diff --git a/.github/workflows/submit.yml b/.github/workflows/submit.yml index 9d19715a9862a7aed3803170feef90cd35ba527e..93dd4e4b9f08333a89f8e5a36a63ff4dc1afb9b4 100644 --- a/.github/workflows/submit.yml +++ b/.github/workflows/submit.yml @@ -12,6 +12,10 @@ on: required: true default: "Linux additional (hotspot only), Linux x64, Linux x86, Windows aarch64, Windows x64, macOS x64" +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: prerequisites: name: Prerequisites @@ -19,6 +23,7 @@ jobs: outputs: should_run: ${{ steps.check_submit.outputs.should_run }} bundle_id: ${{ steps.check_bundle_id.outputs.bundle_id }} + jdk_version: ${{ steps.check_jdk_versions.outputs.jdk_version }} platform_linux_additional: ${{ steps.check_platforms.outputs.platform_linux_additional }} platform_linux_x64: ${{ steps.check_platforms.outputs.platform_linux_x64 }} platform_linux_x86: ${{ steps.check_platforms.outputs.platform_linux_x86 }} @@ -66,6 +71,23 @@ jobs: run: "echo '${{ steps.check_deps.outputs.dependencies }}'" if: steps.check_submit.outputs.should_run != 'false' + - name: Determine full JDK versions + id: check_jdk_versions + shell: bash + run: | + FEATURE=${{ fromJson(steps.check_deps.outputs.dependencies).DEFAULT_VERSION_FEATURE }} + INTERIM=${{ fromJson(steps.check_deps.outputs.dependencies).DEFAULT_VERSION_INTERIM }} + UPDATE=${{ fromJson(steps.check_deps.outputs.dependencies).DEFAULT_VERSION_UPDATE }} + if [ "x${UPDATE}" != "x0" ]; then + V=${FEATURE}.${INTERIM}.${UPDATE} + elif [ "x${INTERIM}" != "x0" ]; then + V={FEATURE}.${INTERIM} + else + V=${FEATURE} + fi + echo "::set-output name=jdk_version::${V}" + if: steps.check_submit.outputs.should_run != 'false' + - name: Determine the jtreg ref to checkout run: "echo JTREG_REF=jtreg-${{ fromJson(steps.check_deps.outputs.dependencies).JTREG_VERSION }}+${{ fromJson(steps.check_deps.outputs.dependencies).JTREG_BUILD }} >> $GITHUB_ENV" if: steps.check_submit.outputs.should_run != 'false' @@ -121,7 +143,7 @@ jobs: artifact: -debug env: - JDK_VERSION: "${{ fromJson(needs.prerequisites.outputs.dependencies).DEFAULT_VERSION_FEATURE }}" + JDK_VERSION: "${{ needs.prerequisites.outputs.jdk_version }}" BOOT_JDK_VERSION: "${{ fromJson(needs.prerequisites.outputs.dependencies).BOOT_JDK_VERSION }}" BOOT_JDK_FILENAME: "${{ fromJson(needs.prerequisites.outputs.dependencies).LINUX_X64_BOOT_JDK_FILENAME }}" BOOT_JDK_URL: "${{ fromJson(needs.prerequisites.outputs.dependencies).LINUX_X64_BOOT_JDK_URL }}" @@ -183,7 +205,6 @@ jobs: --with-conf-name=linux-x64 ${{ matrix.flags }} --with-version-opt=${GITHUB_ACTOR}-${GITHUB_SHA} - --with-version-build=0 --with-boot-jdk=${HOME}/bootjdk/${BOOT_JDK_VERSION} --with-jtreg=${HOME}/jtreg --with-gtest=${GITHUB_WORKSPACE}/gtest @@ -201,8 +222,8 @@ jobs: with: name: transient_jdk-linux-x64${{ matrix.artifact }}_${{ needs.prerequisites.outputs.bundle_id }} path: | - jdk/build/linux-x64/bundles/jdk-${{ env.JDK_VERSION }}-internal+0_linux-x64_bin${{ matrix.artifact }}.tar.gz - jdk/build/linux-x64/bundles/jdk-${{ env.JDK_VERSION }}-internal+0_linux-x64_bin-tests${{ matrix.artifact }}.tar.gz + jdk/build/linux-x64/bundles/jdk-${{ env.JDK_VERSION }}-internal_linux-x64_bin${{ matrix.artifact }}.tar.gz + jdk/build/linux-x64/bundles/jdk-${{ env.JDK_VERSION }}-internal_linux-x64_bin-tests${{ matrix.artifact }}.tar.gz linux_x64_test: name: Linux x64 @@ -250,7 +271,7 @@ jobs: artifact: -debug env: - JDK_VERSION: "${{ fromJson(needs.prerequisites.outputs.dependencies).DEFAULT_VERSION_FEATURE }}" + JDK_VERSION: "${{ needs.prerequisites.outputs.jdk_version }}" BOOT_JDK_VERSION: "${{ fromJson(needs.prerequisites.outputs.dependencies).BOOT_JDK_VERSION }}" BOOT_JDK_FILENAME: "${{ fromJson(needs.prerequisites.outputs.dependencies).LINUX_X64_BOOT_JDK_FILENAME }}" BOOT_JDK_URL: "${{ fromJson(needs.prerequisites.outputs.dependencies).LINUX_X64_BOOT_JDK_URL }}" @@ -308,23 +329,23 @@ jobs: - name: Unpack jdk run: | - mkdir -p "${HOME}/jdk-linux-x64${{ matrix.artifact }}/jdk-${{ env.JDK_VERSION }}-internal+0_linux-x64_bin${{ matrix.artifact }}" - tar -xf "${HOME}/jdk-linux-x64${{ matrix.artifact }}/jdk-${{ env.JDK_VERSION }}-internal+0_linux-x64_bin${{ matrix.artifact }}.tar.gz" -C "${HOME}/jdk-linux-x64${{ matrix.artifact }}/jdk-${{ env.JDK_VERSION }}-internal+0_linux-x64_bin${{ matrix.artifact }}" + mkdir -p "${HOME}/jdk-linux-x64${{ matrix.artifact }}/jdk-${{ env.JDK_VERSION }}-internal_linux-x64_bin${{ matrix.artifact }}" + tar -xf "${HOME}/jdk-linux-x64${{ matrix.artifact }}/jdk-${{ env.JDK_VERSION }}-internal_linux-x64_bin${{ matrix.artifact }}.tar.gz" -C "${HOME}/jdk-linux-x64${{ matrix.artifact }}/jdk-${{ env.JDK_VERSION }}-internal_linux-x64_bin${{ matrix.artifact }}" - name: Unpack tests run: | - mkdir -p "${HOME}/jdk-linux-x64${{ matrix.artifact }}/jdk-${{ env.JDK_VERSION }}-internal+0_linux-x64_bin-tests${{ matrix.artifact }}" - tar -xf "${HOME}/jdk-linux-x64${{ matrix.artifact }}/jdk-${{ env.JDK_VERSION }}-internal+0_linux-x64_bin-tests${{ matrix.artifact }}.tar.gz" -C "${HOME}/jdk-linux-x64${{ matrix.artifact }}/jdk-${{ env.JDK_VERSION }}-internal+0_linux-x64_bin-tests${{ matrix.artifact }}" + mkdir -p "${HOME}/jdk-linux-x64${{ matrix.artifact }}/jdk-${{ env.JDK_VERSION }}-internal_linux-x64_bin-tests${{ matrix.artifact }}" + tar -xf "${HOME}/jdk-linux-x64${{ matrix.artifact }}/jdk-${{ env.JDK_VERSION }}-internal_linux-x64_bin-tests${{ matrix.artifact }}.tar.gz" -C "${HOME}/jdk-linux-x64${{ matrix.artifact }}/jdk-${{ env.JDK_VERSION }}-internal_linux-x64_bin-tests${{ matrix.artifact }}" - name: Find root of jdk image dir run: | - imageroot=`find ${HOME}/jdk-linux-x64${{ matrix.artifact }}/jdk-${{ env.JDK_VERSION }}-internal+0_linux-x64_bin${{ matrix.artifact }} -name release -type f` + imageroot=`find ${HOME}/jdk-linux-x64${{ matrix.artifact }}/jdk-${{ env.JDK_VERSION }}-internal_linux-x64_bin${{ matrix.artifact }} -name release -type f` echo "imageroot=`dirname ${imageroot}`" >> $GITHUB_ENV - name: Run tests run: > JDK_IMAGE_DIR=${{ env.imageroot }} - TEST_IMAGE_DIR=${HOME}/jdk-linux-x64${{ matrix.artifact }}/jdk-${{ env.JDK_VERSION }}-internal+0_linux-x64_bin-tests${{ matrix.artifact }} + TEST_IMAGE_DIR=${HOME}/jdk-linux-x64${{ matrix.artifact }}/jdk-${{ env.JDK_VERSION }}-internal_linux-x64_bin-tests${{ matrix.artifact }} BOOT_JDK=${HOME}/bootjdk/${BOOT_JDK_VERSION} JT_HOME=${HOME}/jtreg make test-prebuilt @@ -341,6 +362,7 @@ jobs: run: > if ! grep --include=test-summary.txt -lqr build/*/test-results -e "TEST SUCCESS" ; then cat build/*/test-results/*/text/newfailures.txt ; + cat build/*/test-results/*/text/other_errors.txt ; exit 1 ; fi @@ -431,7 +453,7 @@ jobs: gnu-arch: powerpc64le env: - JDK_VERSION: "${{ fromJson(needs.prerequisites.outputs.dependencies).DEFAULT_VERSION_FEATURE }}" + JDK_VERSION: "${{ needs.prerequisites.outputs.jdk_version }}" BOOT_JDK_VERSION: "${{ fromJson(needs.prerequisites.outputs.dependencies).BOOT_JDK_VERSION }}" BOOT_JDK_FILENAME: "${{ fromJson(needs.prerequisites.outputs.dependencies).LINUX_X64_BOOT_JDK_FILENAME }}" BOOT_JDK_URL: "${{ fromJson(needs.prerequisites.outputs.dependencies).LINUX_X64_BOOT_JDK_URL }}" @@ -476,12 +498,12 @@ jobs: - name: Unpack build JDK run: | - mkdir -p "${HOME}/jdk-linux-x64/jdk-${{ env.JDK_VERSION }}-internal+0_linux-x64_bin" - tar -xf "${HOME}/jdk-linux-x64/jdk-${{ env.JDK_VERSION }}-internal+0_linux-x64_bin.tar.gz" -C "${HOME}/jdk-linux-x64/jdk-${{ env.JDK_VERSION }}-internal+0_linux-x64_bin" + mkdir -p "${HOME}/jdk-linux-x64/jdk-${{ env.JDK_VERSION }}-internal_linux-x64_bin" + tar -xf "${HOME}/jdk-linux-x64/jdk-${{ env.JDK_VERSION }}-internal_linux-x64_bin.tar.gz" -C "${HOME}/jdk-linux-x64/jdk-${{ env.JDK_VERSION }}-internal_linux-x64_bin" - name: Find root of build JDK image dir run: | - build_jdk_root=`find ${HOME}/jdk-linux-x64/jdk-${{ env.JDK_VERSION }}-internal+0_linux-x64_bin -name release -type f` + build_jdk_root=`find ${HOME}/jdk-linux-x64/jdk-${{ env.JDK_VERSION }}-internal_linux-x64_bin -name release -type f` echo "build_jdk_root=`dirname ${build_jdk_root}`" >> $GITHUB_ENV - name: Update apt @@ -549,7 +571,6 @@ jobs: ${{ matrix.flags }} ${{ env.cross_flags }} --with-version-opt=${GITHUB_ACTOR}-${GITHUB_SHA} - --with-version-build=0 --with-boot-jdk=${HOME}/bootjdk/${BOOT_JDK_VERSION} --with-build-jdk=${{ env.build_jdk_root }} --with-default-make-target="hotspot" @@ -579,7 +600,7 @@ jobs: # Reduced 32-bit build uses the same boot JDK as 64-bit build env: - JDK_VERSION: "${{ fromJson(needs.prerequisites.outputs.dependencies).DEFAULT_VERSION_FEATURE }}" + JDK_VERSION: "${{ needs.prerequisites.outputs.jdk_version }}" BOOT_JDK_VERSION: "${{ fromJson(needs.prerequisites.outputs.dependencies).BOOT_JDK_VERSION }}" BOOT_JDK_FILENAME: "${{ fromJson(needs.prerequisites.outputs.dependencies).LINUX_X64_BOOT_JDK_FILENAME }}" BOOT_JDK_URL: "${{ fromJson(needs.prerequisites.outputs.dependencies).LINUX_X64_BOOT_JDK_URL }}" @@ -648,7 +669,6 @@ jobs: --with-target-bits=32 ${{ matrix.flags }} --with-version-opt=${GITHUB_ACTOR}-${GITHUB_SHA} - --with-version-build=0 --with-boot-jdk=${HOME}/bootjdk/${BOOT_JDK_VERSION} --with-jtreg=${HOME}/jtreg --with-gtest=${GITHUB_WORKSPACE}/gtest @@ -666,8 +686,8 @@ jobs: with: name: transient_jdk-linux-x86${{ matrix.artifact }}_${{ needs.prerequisites.outputs.bundle_id }} path: | - jdk/build/linux-x86/bundles/jdk-${{ env.JDK_VERSION }}-internal+0_linux-x86_bin${{ matrix.artifact }}.tar.gz - jdk/build/linux-x86/bundles/jdk-${{ env.JDK_VERSION }}-internal+0_linux-x86_bin-tests${{ matrix.artifact }}.tar.gz + jdk/build/linux-x86/bundles/jdk-${{ env.JDK_VERSION }}-internal_linux-x86_bin${{ matrix.artifact }}.tar.gz + jdk/build/linux-x86/bundles/jdk-${{ env.JDK_VERSION }}-internal_linux-x86_bin-tests${{ matrix.artifact }}.tar.gz linux_x86_test: name: Linux x86 @@ -716,7 +736,7 @@ jobs: # Reduced 32-bit build uses the same boot JDK as 64-bit build env: - JDK_VERSION: "${{ fromJson(needs.prerequisites.outputs.dependencies).DEFAULT_VERSION_FEATURE }}" + JDK_VERSION: "${{ needs.prerequisites.outputs.jdk_version }}" BOOT_JDK_VERSION: "${{ fromJson(needs.prerequisites.outputs.dependencies).BOOT_JDK_VERSION }}" BOOT_JDK_FILENAME: "${{ fromJson(needs.prerequisites.outputs.dependencies).LINUX_X64_BOOT_JDK_FILENAME }}" BOOT_JDK_URL: "${{ fromJson(needs.prerequisites.outputs.dependencies).LINUX_X64_BOOT_JDK_URL }}" @@ -774,23 +794,23 @@ jobs: - name: Unpack jdk run: | - mkdir -p "${HOME}/jdk-linux-x86${{ matrix.artifact }}/jdk-${{ env.JDK_VERSION }}-internal+0_linux-x86_bin${{ matrix.artifact }}" - tar -xf "${HOME}/jdk-linux-x86${{ matrix.artifact }}/jdk-${{ env.JDK_VERSION }}-internal+0_linux-x86_bin${{ matrix.artifact }}.tar.gz" -C "${HOME}/jdk-linux-x86${{ matrix.artifact }}/jdk-${{ env.JDK_VERSION }}-internal+0_linux-x86_bin${{ matrix.artifact }}" + mkdir -p "${HOME}/jdk-linux-x86${{ matrix.artifact }}/jdk-${{ env.JDK_VERSION }}-internal_linux-x86_bin${{ matrix.artifact }}" + tar -xf "${HOME}/jdk-linux-x86${{ matrix.artifact }}/jdk-${{ env.JDK_VERSION }}-internal_linux-x86_bin${{ matrix.artifact }}.tar.gz" -C "${HOME}/jdk-linux-x86${{ matrix.artifact }}/jdk-${{ env.JDK_VERSION }}-internal_linux-x86_bin${{ matrix.artifact }}" - name: Unpack tests run: | - mkdir -p "${HOME}/jdk-linux-x86${{ matrix.artifact }}/jdk-${{ env.JDK_VERSION }}-internal+0_linux-x86_bin-tests${{ matrix.artifact }}" - tar -xf "${HOME}/jdk-linux-x86${{ matrix.artifact }}/jdk-${{ env.JDK_VERSION }}-internal+0_linux-x86_bin-tests${{ matrix.artifact }}.tar.gz" -C "${HOME}/jdk-linux-x86${{ matrix.artifact }}/jdk-${{ env.JDK_VERSION }}-internal+0_linux-x86_bin-tests${{ matrix.artifact }}" + mkdir -p "${HOME}/jdk-linux-x86${{ matrix.artifact }}/jdk-${{ env.JDK_VERSION }}-internal_linux-x86_bin-tests${{ matrix.artifact }}" + tar -xf "${HOME}/jdk-linux-x86${{ matrix.artifact }}/jdk-${{ env.JDK_VERSION }}-internal_linux-x86_bin-tests${{ matrix.artifact }}.tar.gz" -C "${HOME}/jdk-linux-x86${{ matrix.artifact }}/jdk-${{ env.JDK_VERSION }}-internal_linux-x86_bin-tests${{ matrix.artifact }}" - name: Find root of jdk image dir run: | - imageroot=`find ${HOME}/jdk-linux-x86${{ matrix.artifact }}/jdk-${{ env.JDK_VERSION }}-internal+0_linux-x86_bin${{ matrix.artifact }} -name release -type f` + imageroot=`find ${HOME}/jdk-linux-x86${{ matrix.artifact }}/jdk-${{ env.JDK_VERSION }}-internal_linux-x86_bin${{ matrix.artifact }} -name release -type f` echo "imageroot=`dirname ${imageroot}`" >> $GITHUB_ENV - name: Run tests run: > JDK_IMAGE_DIR=${{ env.imageroot }} - TEST_IMAGE_DIR=${HOME}/jdk-linux-x86${{ matrix.artifact }}/jdk-${{ env.JDK_VERSION }}-internal+0_linux-x86_bin-tests${{ matrix.artifact }} + TEST_IMAGE_DIR=${HOME}/jdk-linux-x86${{ matrix.artifact }}/jdk-${{ env.JDK_VERSION }}-internal_linux-x86_bin-tests${{ matrix.artifact }} BOOT_JDK=${HOME}/bootjdk/${BOOT_JDK_VERSION} JT_HOME=${HOME}/jtreg make test-prebuilt @@ -807,6 +827,7 @@ jobs: run: > if ! grep --include=test-summary.txt -lqr build/*/test-results -e "TEST SUCCESS" ; then cat build/*/test-results/*/text/newfailures.txt ; + cat build/*/test-results/*/text/other_errors.txt ; exit 1 ; fi @@ -866,7 +887,7 @@ jobs: artifact: -debug env: - JDK_VERSION: "${{ fromJson(needs.prerequisites.outputs.dependencies).DEFAULT_VERSION_FEATURE }}" + JDK_VERSION: "${{ needs.prerequisites.outputs.jdk_version }}" BOOT_JDK_VERSION: "${{ fromJson(needs.prerequisites.outputs.dependencies).BOOT_JDK_VERSION }}" BOOT_JDK_FILENAME: "${{ fromJson(needs.prerequisites.outputs.dependencies).WINDOWS_X64_BOOT_JDK_FILENAME }}" BOOT_JDK_URL: "${{ fromJson(needs.prerequisites.outputs.dependencies).WINDOWS_X64_BOOT_JDK_URL }}" @@ -925,7 +946,6 @@ jobs: --openjdk-target=aarch64-unknown-cygwin ${{ matrix.flags }} --with-version-opt="$env:GITHUB_ACTOR-$env:GITHUB_SHA" - --with-version-build=0 --with-boot-jdk="$env:BOOT_JDK" --with-default-make-target="hotspot" working-directory: jdk @@ -955,7 +975,7 @@ jobs: artifact: -debug env: - JDK_VERSION: "${{ fromJson(needs.prerequisites.outputs.dependencies).DEFAULT_VERSION_FEATURE }}" + JDK_VERSION: "${{ needs.prerequisites.outputs.jdk_version }}" BOOT_JDK_VERSION: "${{ fromJson(needs.prerequisites.outputs.dependencies).BOOT_JDK_VERSION }}" BOOT_JDK_FILENAME: "${{ fromJson(needs.prerequisites.outputs.dependencies).WINDOWS_X64_BOOT_JDK_FILENAME }}" BOOT_JDK_URL: "${{ fromJson(needs.prerequisites.outputs.dependencies).WINDOWS_X64_BOOT_JDK_URL }}" @@ -1037,7 +1057,6 @@ jobs: --with-msvc-toolset-version=14.28 ${{ matrix.flags }} --with-version-opt="$env:GITHUB_ACTOR-$env:GITHUB_SHA" - --with-version-build=0 --with-boot-jdk="$env:BOOT_JDK" --with-jtreg="$env:JT_HOME" --with-gtest="$env:GTEST" @@ -1057,9 +1076,9 @@ jobs: with: name: transient_jdk-windows-x64${{ matrix.artifact }}_${{ needs.prerequisites.outputs.bundle_id }} path: | - jdk/build/windows-x64/bundles/jdk-${{ env.JDK_VERSION }}-internal+0_windows-x64_bin${{ matrix.artifact }}.zip - jdk/build/windows-x64/bundles/jdk-${{ env.JDK_VERSION }}-internal+0_windows-x64_bin-tests${{ matrix.artifact }}.tar.gz - jdk/build/windows-x64/bundles/jdk-${{ env.JDK_VERSION }}-internal+0_windows-x64_bin${{ matrix.artifact }}-symbols.tar.gz + jdk/build/windows-x64/bundles/jdk-${{ env.JDK_VERSION }}-internal_windows-x64_bin${{ matrix.artifact }}.zip + jdk/build/windows-x64/bundles/jdk-${{ env.JDK_VERSION }}-internal_windows-x64_bin-tests${{ matrix.artifact }}.tar.gz + jdk/build/windows-x64/bundles/jdk-${{ env.JDK_VERSION }}-internal_windows-x64_bin${{ matrix.artifact }}-symbols.tar.gz windows_x64_test: name: Windows x64 @@ -1107,7 +1126,7 @@ jobs: artifact: -debug env: - JDK_VERSION: "${{ fromJson(needs.prerequisites.outputs.dependencies).DEFAULT_VERSION_FEATURE }}" + JDK_VERSION: "${{ needs.prerequisites.outputs.jdk_version }}" BOOT_JDK_VERSION: "${{ fromJson(needs.prerequisites.outputs.dependencies).BOOT_JDK_VERSION }}" BOOT_JDK_FILENAME: "${{ fromJson(needs.prerequisites.outputs.dependencies).WINDOWS_X64_BOOT_JDK_FILENAME }}" BOOT_JDK_URL: "${{ fromJson(needs.prerequisites.outputs.dependencies).WINDOWS_X64_BOOT_JDK_URL }}" @@ -1179,21 +1198,21 @@ jobs: - name: Unpack jdk run: | - mkdir -p "${HOME}/jdk-windows-x64${{ matrix.artifact }}/jdk-${{ env.JDK_VERSION }}-internal+0_windows-x64_bin${{ matrix.artifact }}" - tar -xf "${HOME}/jdk-windows-x64${{ matrix.artifact }}/jdk-${{ env.JDK_VERSION }}-internal+0_windows-x64_bin${{ matrix.artifact }}.zip" -C "${HOME}/jdk-windows-x64${{ matrix.artifact }}/jdk-${{ env.JDK_VERSION }}-internal+0_windows-x64_bin${{ matrix.artifact }}" + mkdir -p "${HOME}/jdk-windows-x64${{ matrix.artifact }}/jdk-${{ env.JDK_VERSION }}-internal_windows-x64_bin${{ matrix.artifact }}" + tar -xf "${HOME}/jdk-windows-x64${{ matrix.artifact }}/jdk-${{ env.JDK_VERSION }}-internal_windows-x64_bin${{ matrix.artifact }}.zip" -C "${HOME}/jdk-windows-x64${{ matrix.artifact }}/jdk-${{ env.JDK_VERSION }}-internal_windows-x64_bin${{ matrix.artifact }}" - name: Unpack symbols run: | - mkdir -p "${HOME}/jdk-windows-x64${{ matrix.artifact }}/jdk-${{ env.JDK_VERSION }}-internal+0_windows-x64_bin${{ matrix.artifact }}-symbols" - tar -xf "${HOME}/jdk-windows-x64${{ matrix.artifact }}/jdk-${{ env.JDK_VERSION }}-internal+0_windows-x64_bin${{ matrix.artifact }}-symbols.tar.gz" -C "${HOME}/jdk-windows-x64${{ matrix.artifact }}/jdk-${{ env.JDK_VERSION }}-internal+0_windows-x64_bin${{ matrix.artifact }}-symbols" + mkdir -p "${HOME}/jdk-windows-x64${{ matrix.artifact }}/jdk-${{ env.JDK_VERSION }}-internal_windows-x64_bin${{ matrix.artifact }}-symbols" + tar -xf "${HOME}/jdk-windows-x64${{ matrix.artifact }}/jdk-${{ env.JDK_VERSION }}-internal_windows-x64_bin${{ matrix.artifact }}-symbols.tar.gz" -C "${HOME}/jdk-windows-x64${{ matrix.artifact }}/jdk-${{ env.JDK_VERSION }}-internal_windows-x64_bin${{ matrix.artifact }}-symbols" - name: Unpack tests run: | - mkdir -p "${HOME}/jdk-windows-x64${{ matrix.artifact }}/jdk-${{ env.JDK_VERSION }}-internal+0_windows-x64_bin-tests${{ matrix.artifact }}" - tar -xf "${HOME}/jdk-windows-x64${{ matrix.artifact }}/jdk-${{ env.JDK_VERSION }}-internal+0_windows-x64_bin-tests${{ matrix.artifact }}.tar.gz" -C "${HOME}/jdk-windows-x64${{ matrix.artifact }}/jdk-${{ env.JDK_VERSION }}-internal+0_windows-x64_bin-tests${{ matrix.artifact }}" + mkdir -p "${HOME}/jdk-windows-x64${{ matrix.artifact }}/jdk-${{ env.JDK_VERSION }}-internal_windows-x64_bin-tests${{ matrix.artifact }}" + tar -xf "${HOME}/jdk-windows-x64${{ matrix.artifact }}/jdk-${{ env.JDK_VERSION }}-internal_windows-x64_bin-tests${{ matrix.artifact }}.tar.gz" -C "${HOME}/jdk-windows-x64${{ matrix.artifact }}/jdk-${{ env.JDK_VERSION }}-internal_windows-x64_bin-tests${{ matrix.artifact }}" - name: Find root of jdk image dir - run: echo ("imageroot=" + (Get-ChildItem -Path $HOME/jdk-windows-x64${{ matrix.artifact }}/jdk-${{ env.JDK_VERSION }}-internal+0_windows-x64_bin${{ matrix.artifact }} -Filter release -Recurse -ErrorAction SilentlyContinue -Force).DirectoryName) | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 + run: echo ("imageroot=" + (Get-ChildItem -Path $HOME/jdk-windows-x64${{ matrix.artifact }}/jdk-${{ env.JDK_VERSION }}-internal_windows-x64_bin${{ matrix.artifact }} -Filter release -Recurse -ErrorAction SilentlyContinue -Force).DirectoryName) | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 - name: Run tests run: > @@ -1201,7 +1220,7 @@ jobs: $env:Path = $env:Path -split ";" -match "C:\\Windows|PowerShell|cygwin" -join ";" ; $env:JDK_IMAGE_DIR = cygpath "${{ env.imageroot }}" ; $env:SYMBOLS_IMAGE_DIR = cygpath "${{ env.imageroot }}" ; - $env:TEST_IMAGE_DIR = cygpath "$HOME/jdk-windows-x64${{ matrix.artifact }}/jdk-${{ env.JDK_VERSION }}-internal+0_windows-x64_bin-tests${{ matrix.artifact }}" ; + $env:TEST_IMAGE_DIR = cygpath "$HOME/jdk-windows-x64${{ matrix.artifact }}/jdk-${{ env.JDK_VERSION }}-internal_windows-x64_bin-tests${{ matrix.artifact }}" ; $env:BOOT_JDK = cygpath "$HOME/bootjdk/$env:BOOT_JDK_VERSION" ; $env:JT_HOME = cygpath "$HOME/jtreg" ; & make test-prebuilt @@ -1218,6 +1237,7 @@ jobs: run: > if ((Get-ChildItem -Path build\*\test-results\test-summary.txt -Recurse | Select-String -Pattern "TEST SUCCESS" ).Count -eq 0) { Get-Content -Path build\*\test-results\*\*\newfailures.txt ; + Get-Content -Path build\*\test-results\*\*\other_errors.txt ; exit 1 } @@ -1281,7 +1301,7 @@ jobs: artifact: -debug env: - JDK_VERSION: "${{ fromJson(needs.prerequisites.outputs.dependencies).DEFAULT_VERSION_FEATURE }}" + JDK_VERSION: "${{ needs.prerequisites.outputs.jdk_version }}" BOOT_JDK_VERSION: "${{ fromJson(needs.prerequisites.outputs.dependencies).BOOT_JDK_VERSION }}" BOOT_JDK_FILENAME: "${{ fromJson(needs.prerequisites.outputs.dependencies).MACOS_X64_BOOT_JDK_FILENAME }}" BOOT_JDK_URL: "${{ fromJson(needs.prerequisites.outputs.dependencies).MACOS_X64_BOOT_JDK_URL }}" @@ -1343,7 +1363,6 @@ jobs: --with-conf-name=macos-x64 ${{ matrix.flags }} --with-version-opt=${GITHUB_ACTOR}-${GITHUB_SHA} - --with-version-build=0 --with-boot-jdk=${HOME}/bootjdk/${BOOT_JDK_VERSION}/Contents/Home --with-jtreg=${HOME}/jtreg --with-gtest=${GITHUB_WORKSPACE}/gtest @@ -1361,8 +1380,8 @@ jobs: with: name: transient_jdk-macos-x64${{ matrix.artifact }}_${{ needs.prerequisites.outputs.bundle_id }} path: | - jdk/build/macos-x64/bundles/jdk-${{ env.JDK_VERSION }}-internal+0_macos-x64_bin${{ matrix.artifact }}.tar.gz - jdk/build/macos-x64/bundles/jdk-${{ env.JDK_VERSION }}-internal+0_macos-x64_bin-tests${{ matrix.artifact }}.tar.gz + jdk/build/macos-x64/bundles/jdk-${{ env.JDK_VERSION }}-internal_macos-x64_bin${{ matrix.artifact }}.tar.gz + jdk/build/macos-x64/bundles/jdk-${{ env.JDK_VERSION }}-internal_macos-x64_bin-tests${{ matrix.artifact }}.tar.gz macos_aarch64_build: name: macOS aarch64 @@ -1383,7 +1402,7 @@ jobs: artifact: -debug env: - JDK_VERSION: "${{ fromJson(needs.prerequisites.outputs.dependencies).DEFAULT_VERSION_FEATURE }}" + JDK_VERSION: "${{ needs.prerequisites.outputs.jdk_version }}" BOOT_JDK_VERSION: "${{ fromJson(needs.prerequisites.outputs.dependencies).BOOT_JDK_VERSION }}" BOOT_JDK_FILENAME: "${{ fromJson(needs.prerequisites.outputs.dependencies).MACOS_X64_BOOT_JDK_FILENAME }}" BOOT_JDK_URL: "${{ fromJson(needs.prerequisites.outputs.dependencies).MACOS_X64_BOOT_JDK_URL }}" @@ -1446,7 +1465,6 @@ jobs: --openjdk-target=aarch64-apple-darwin ${{ matrix.flags }} --with-version-opt=${GITHUB_ACTOR}-${GITHUB_SHA} - --with-version-build=0 --with-boot-jdk=${HOME}/bootjdk/${BOOT_JDK_VERSION}/Contents/Home --with-jtreg=${HOME}/jtreg --with-gtest=${GITHUB_WORKSPACE}/gtest @@ -1464,8 +1482,8 @@ jobs: with: name: transient_jdk-macos-aarch64${{ matrix.artifact }}_${{ needs.prerequisites.outputs.bundle_id }} path: | - jdk/build/macos-aarch64/bundles/jdk-${{ env.JDK_VERSION }}-internal+0_macos-aarch64_bin${{ matrix.artifact }}.tar.gz - jdk/build/macos-aarch64/bundles/jdk-${{ env.JDK_VERSION }}-internal+0_macos-aarch64_bin-tests${{ matrix.artifact }}.tar.gz + jdk/build/macos-aarch64/bundles/jdk-${{ env.JDK_VERSION }}-internal_macos-aarch64_bin${{ matrix.artifact }}.tar.gz + jdk/build/macos-aarch64/bundles/jdk-${{ env.JDK_VERSION }}-internal_macos-aarch64_bin-tests${{ matrix.artifact }}.tar.gz macos_x64_test: @@ -1514,7 +1532,7 @@ jobs: artifact: -debug env: - JDK_VERSION: "${{ fromJson(needs.prerequisites.outputs.dependencies).DEFAULT_VERSION_FEATURE }}" + JDK_VERSION: "${{ needs.prerequisites.outputs.jdk_version }}" BOOT_JDK_VERSION: "${{ fromJson(needs.prerequisites.outputs.dependencies).BOOT_JDK_VERSION }}" BOOT_JDK_FILENAME: "${{ fromJson(needs.prerequisites.outputs.dependencies).MACOS_X64_BOOT_JDK_FILENAME }}" BOOT_JDK_URL: "${{ fromJson(needs.prerequisites.outputs.dependencies).MACOS_X64_BOOT_JDK_URL }}" @@ -1572,13 +1590,13 @@ jobs: - name: Unpack jdk run: | - mkdir -p "${HOME}/jdk-macos-x64${{ matrix.artifact }}/jdk-${{ env.JDK_VERSION }}-internal+0_macos-x64_bin${{ matrix.artifact }}" - tar -xf "${HOME}/jdk-macos-x64${{ matrix.artifact }}/jdk-${{ env.JDK_VERSION }}-internal+0_macos-x64_bin${{ matrix.artifact }}.tar.gz" -C "${HOME}/jdk-macos-x64${{ matrix.artifact }}/jdk-${{ env.JDK_VERSION }}-internal+0_macos-x64_bin${{ matrix.artifact }}" + mkdir -p "${HOME}/jdk-macos-x64${{ matrix.artifact }}/jdk-${{ env.JDK_VERSION }}-internal_macos-x64_bin${{ matrix.artifact }}" + tar -xf "${HOME}/jdk-macos-x64${{ matrix.artifact }}/jdk-${{ env.JDK_VERSION }}-internal_macos-x64_bin${{ matrix.artifact }}.tar.gz" -C "${HOME}/jdk-macos-x64${{ matrix.artifact }}/jdk-${{ env.JDK_VERSION }}-internal_macos-x64_bin${{ matrix.artifact }}" - name: Unpack tests run: | - mkdir -p "${HOME}/jdk-macos-x64${{ matrix.artifact }}/jdk-${{ env.JDK_VERSION }}-internal+0_macos-x64_bin-tests${{ matrix.artifact }}" - tar -xf "${HOME}/jdk-macos-x64${{ matrix.artifact }}/jdk-${{ env.JDK_VERSION }}-internal+0_macos-x64_bin-tests${{ matrix.artifact }}.tar.gz" -C "${HOME}/jdk-macos-x64${{ matrix.artifact }}/jdk-${{ env.JDK_VERSION }}-internal+0_macos-x64_bin-tests${{ matrix.artifact }}" + mkdir -p "${HOME}/jdk-macos-x64${{ matrix.artifact }}/jdk-${{ env.JDK_VERSION }}-internal_macos-x64_bin-tests${{ matrix.artifact }}" + tar -xf "${HOME}/jdk-macos-x64${{ matrix.artifact }}/jdk-${{ env.JDK_VERSION }}-internal_macos-x64_bin-tests${{ matrix.artifact }}.tar.gz" -C "${HOME}/jdk-macos-x64${{ matrix.artifact }}/jdk-${{ env.JDK_VERSION }}-internal_macos-x64_bin-tests${{ matrix.artifact }}" - name: Install dependencies run: brew install make @@ -1588,13 +1606,13 @@ jobs: - name: Find root of jdk image dir run: | - imageroot=`find ${HOME}/jdk-macos-x64${{ matrix.artifact }}/jdk-${{ env.JDK_VERSION }}-internal+0_macos-x64_bin${{ matrix.artifact }} -name release -type f` + imageroot=`find ${HOME}/jdk-macos-x64${{ matrix.artifact }}/jdk-${{ env.JDK_VERSION }}-internal_macos-x64_bin${{ matrix.artifact }} -name release -type f` echo "imageroot=`dirname ${imageroot}`" >> $GITHUB_ENV - name: Run tests run: > JDK_IMAGE_DIR=${{ env.imageroot }} - TEST_IMAGE_DIR=${HOME}/jdk-macos-x64${{ matrix.artifact }}/jdk-${{ env.JDK_VERSION }}-internal+0_macos-x64_bin-tests${{ matrix.artifact }} + TEST_IMAGE_DIR=${HOME}/jdk-macos-x64${{ matrix.artifact }}/jdk-${{ env.JDK_VERSION }}-internal_macos-x64_bin-tests${{ matrix.artifact }} BOOT_JDK=${HOME}/bootjdk/${BOOT_JDK_VERSION}/Contents/Home JT_HOME=${HOME}/jtreg gmake test-prebuilt @@ -1611,6 +1629,7 @@ jobs: run: > if ! grep --include=test-summary.txt -lqr build/*/test-results -e "TEST SUCCESS" ; then cat build/*/test-results/*/text/newfailures.txt ; + cat build/*/test-results/*/text/other_errors.txt ; exit 1 ; fi diff --git a/.hgtags b/.hgtags deleted file mode 100644 index ef4ec35e2f27ed951ce5306b393547235e25a97f..0000000000000000000000000000000000000000 --- a/.hgtags +++ /dev/null @@ -1,664 +0,0 @@ -3cc80be736f24704e505ad8ddaa598dec3fa2ed3 jdk-9+181 -e2b70be325bd10dae4c06f74c46d70d480854916 jdk-9+179 -5b16a1c3ccffff2a82c88bb7ea894c4ff1c9ebde jdk-9+180 -43bf6f30fcba031ecf0cc7e511efe3a8179d0f77 jdk-9+176 -d9f6bc6ba599d0487dc18b2fbdb6c34eedf6f958 jdk-9+177 -bc9df7dd63ec76f50fafeb4acc44465044662f0a jdk-9+178 -994036e74ab805bcc09afa0646be17a725bec42f jdk-9+175 -94680c6d60ecd9ed3ffd1847706efde7eb947afc jdk-9+174 -6dd7fda42bab7ecf648cafb0a4e9b4ca11b3094f jdk-9+173 -dad6746278facbbea57dd462cb56fb743dc0a5f0 jdk-9+172 -643b5f18c2656fe91b69fea85b07b98d5fad394d jdk-9+171 -898cbe31fbdae2d25d141384fac746cc244a730c jdk-9+170 -c7efde2b60fc1ec04630be769d9ad60efb39c39c jdk-9+169 -8fd0a4569191f33c98ee90c2709174a342fefb0d jdk-9+167 -fcabc74bd44e56c7419d111d59b95669ecb33c55 jdk-9+168 -d3e973f1809606c67412361041ad197e50fe8cec jdk-9+166 -3965b747cfe1e6cbd66b8739da5a1ea6ec6985e9 jdk-9+165 -d16aebbb56d37f12e0c0b0a4fb427db65e1fb1a8 jdk-9+162 -18c41483a082e097ac2f5f983c1226ed94aa4215 jdk-9+163 -32db52c675e7d5bc413605d2e89b68b608b19be0 jdk-9+164 -fd1497902bbe3aa24b21f270ecdcb8de5f7aa9ac jdk-9+159 -6aa8be0c4e054fe8b3ab016ae00d16d680f92145 jdk-9+160 -f6883b1a5a6478437cd4181c4bd45328ab24feaf jdk-9+161 -fa3e76b477829afc4476f0b725cfaa440a6fd917 jdk-9+157 -b5015f742ba648184bb7fc547197bd33ebfde30d jdk-9+158 -1cc8dd79fd1cd13d36b385196271a29632c67c3b jdk7-b24 -bf2517e15f0c0f950e5b3143c4ca11e2df73dcc1 jdk7-b25 -5ae7db536e3fcf6be78e45b240a9058095e0ed38 jdk7-b26 -67052ac87fc927d048e62ec54ff42adb230d3f7c jdk7-b27 -18dc4ba4739a537fd146f77da51db16efce28da2 jdk7-b28 -bfe4572fd301a6fcd120373cdb2eff5d2da0c72c jdk7-b29 -bee4731164a06ddece1297ae58db24aca6a1c626 jdk7-b30 -cd8b8f500face60d1566d850857a7fccadbd383a jdk7-b31 -a9f1805e3ba9ca520cad199d522c84af5433e85a jdk7-b32 -6838c1a3296aaa3572364d2ce7d70826cee96286 jdk7-b33 -90cf935adb353bb0af4b46fb0677e841fd24c000 jdk7-b34 -6d909d5803e3a22850e6c4e5a75b888742ee7e20 jdk7-b35 -d718a441936196b93d8bc9f084933af9a4c2a350 jdk7-b36 -c2036bf76829c03b99108fffab52e20910a9be4f jdk7-b37 -a2879b2837f5a4c87e9542efe69ef138194af8ff jdk7-b38 -126f365cec6c3c2c72de934fa1c64b5f082b55b5 jdk7-b39 -3c53424bbe3bb77e01b468b4b0140deec33e11fc jdk7-b40 -3cb2a607c347934f8e7e86f840a094c28b08d9ea jdk7-b41 -caf58ffa084568990cbb3441f9ae188e36b31770 jdk7-b42 -41bd0a702bc8ec6feebd725a63e7c3227f82ab11 jdk7-b43 -5843778bda89b1d5ac8e1aa05e26930ac90b3145 jdk7-b44 -54dffad0bf066791a2793305875250c395011d5f jdk7-b45 -04b2620edc72de93671646e4720c5992c74ac8b5 jdk7-b46 -0c4657194eec95c08ba478aee9cfc3c295e41657 jdk7-b47 -1bf51a4c2627c2f0e0cbcc2cf0421bdb37f1f2b2 jdk7-b48 -6b84b04a80afe23262377c60913eebfc898f14c4 jdk7-b49 -5da0e6b9f4f18ef483c977337214b12ee0e1fc8f jdk7-b50 -a25c5ec5e40e07733d1ff9898a0abe36159288ff jdk7-b51 -7a90e89e36d103038f8667f6a7daae34ecfa1ad8 jdk7-b52 -d52186ee770dac57950536cd00ccbfdef360b04c jdk7-b53 -15096652c4d48dfb9fc0b2cb135304db94c65ba0 jdk7-b54 -c8b275d62d6b0a980c510e839b70292245863e85 jdk7-b55 -a8134c4ee2cf451cf9b5e1609f39d83ecd53acc5 jdk7-b56 -b44f05654c26fcd1f995e712992f9b07ffd7c0c6 jdk7-b57 -d60a9ce3c3eabf28f5d50ae839d18be04a551bc2 jdk7-b58 -c33e7d38c9210741dbc285507403a4b20bd802a0 jdk7-b59 -5a10e4d0b14d7beac53a7b2213ae6864afe1fd3e jdk7-b60 -dbb955b1ee59b876dd1f133952b557b48b1d7732 jdk7-b61 -6107cbff3130c747d243c25a7874cd59db5744a8 jdk7-b62 -dfd8506f74c3731bb169ce93c72612d78ee0413b jdk7-b63 -d22867c5f1b295a0a2b3b4bc8999a2676f6e20c3 jdk7-b64 -7d3bf00f3cc4f8125de1842521e7567f37dc84b8 jdk7-b65 -62109d1b9e7310f29ab51ca6f1d71b899c0ce6b0 jdk7-b66 -eb24af1404aec8aa140c4cd4d13d2839b150dd41 jdk7-b67 -bca2225b66d78c4bf4d9801f54cac7715a598650 jdk7-b68 -1b662b1ed14eb4ae31d5138a36c433b13d941dc5 jdk7-b69 -207f694795c448c17753eff1a2f50363106960c2 jdk7-b70 -c5d39b6be65cba0effb5f466ea48fe43764d0e0c jdk7-b71 -df4bcd06e1d0ab306efa5a44f24a409dc0c0c742 jdk7-b72 -ce74bd35ce948d629a356e168797f44b593b1578 jdk7-b73 -4e7661eaa211e186674f6cbefec4aef1144ac2a0 jdk7-b74 -946518568340c4e511549318f19f47f06b7f5f9b jdk7-b75 -09e0b33177af2b98a03c9ca19eedf61440bd1cf6 jdk7-b76 -1d0121b741f029dc4b828e4b36ba6fda92907dd7 jdk7-b77 -4061c66ba1af1a2e27c2c839ba887407dd3ce050 jdk7-b78 -e9c98378f6b9256c0595ef2985ca5899f0c0e274 jdk7-b79 -e6abd38682d237306d6c147c17538ec9e7f8e3a7 jdk7-b80 -dcc938ac40cc45f1ef454d76020b5db5d943001c jdk7-b81 -a30062be6d9ca1d48579826f870f85974300004e jdk7-b82 -34c8199936a1682aa8587857f44cfaf37c2b6381 jdk7-b83 -b1e55627a6980b9508854ed0c0f21d4f981b4494 jdk7-b84 -b6f633a93ae0ec4555ff4bf756f5e2150c9bdede jdk7-b85 -c94d9cc81f495d97817eba9d71b84fc45f7661a5 jdk7-b86 -b7456c473862048fa70ed8092313a4ef0a55d403 jdk7-b87 -7077b95d42f6b3942a8751bba033801ff50e5889 jdk7-b88 -44158f6d3b94c0fa020e33632532473d92d1ea96 jdk7-b89 -1d1927f9ec097b62c913921e2dfa5dbaf5dc325b jdk7-b90 -308ad8f68b8dd68e22d73dd490e110059b732422 jdk7-b91 -ff9031a745d9cc52318f2148e43ca3b07ee08098 jdk7-b92 -b5dab6a313fdff4c043250e4d9c8f66fd624d27e jdk7-b93 -8bb281f0f91582104d65d032be22522bfd2d8110 jdk7-b94 -654298d26561b76dfe3cfcffbbd7078080837300 jdk7-b95 -d260f892491e040ae385a8e6df59557a7d721abf jdk7-b96 -7e406ebed9a5968b584f3c3e6b60893b5d6d9741 jdk7-b97 -db6e660120446c407e2d908d52ec046592b21726 jdk7-b98 -c4c8a5bc54f66abc68cd185d9294042121922154 jdk7-b99 -2d6ba7a221915bdf0311acc5641c7f3875cb793e jdk7-b100 -2548ac036b8fca3326d058d758e6df8355a42469 jdk7-b101 -88db80c8e49cea352c2900f689600dc410761c1f jdk7-b102 -64770970865839b0443066370e7d476ef47e90cd jdk7-b103 -10bc903a228d3a8efdf46fb8c3fcf82a59b88bc5 jdk7-b104 -1ce7938efb03224ccc8b3cdd7803eb39e889539c jdk7-b105 -6bdae472f77205046703b685eff2ac4f7a0ecf4e jdk7-b106 -439de530aac531a360beedba6e2fe51e17292cc0 jdk7-b107 -044d31b99ef5609389fc771c422e722e5e224228 jdk7-b108 -e02b4d709e177d08d56130a4bc68061e4bbacc7d jdk7-b109 -a6442d6bc38a44152e0662688213ce4d2701f42a jdk7-b110 -69f3edf083477955b5bd2f754252c7504167d8e1 jdk7-b111 -f960f117f1623629f64203e2b09a92a8f6f14ff5 jdk7-b112 -1fee41c7ed2b3388970a756a85aa693c0de8407a jdk7-b113 -750c1ccb2f2d1ddfa95ab6c7f897fdab2f87f7e9 jdk7-b114 -9cb24917216bc68997154f6e9566c3de62acb2f4 jdk7-b115 -a4e6aa1f45ad23a6f083ed98d970b5006ea4d292 jdk7-b116 -228e73f288c543a8c34e2a54227103ae5649e6af jdk7-b117 -2e876e59938a853934aa738c811b26c452bd9fe8 jdk7-b118 -4951967a61b4dbbf514828879f57bd1a0d4b420b jdk7-b119 -8c840d3ab24f8d0f422b991638acb44b6ab1d98c jdk7-b120 -0ce0a2c3a6926677dc507839a820ab6625541e5a jdk7-b121 -6f09ea1c034f087916d2a8cf0d22be768400118f jdk7-b122 -142129d8599d1f56b29387e7f9a5fad53b6d61df jdk7-b123 -aa894c225b1a517b665ac2a58295217ea2245134 jdk7-b124 -f658ec2730fa29323c36d23c27e54c7219ef5e16 jdk7-b125 -f1df068076986679ea1105532a65529d63a89060 jdk7-b126 -f83cd8bd35c678f94e526990e03dc838d0ec2717 jdk7-b127 -7da3f5f30855dec6bf3a86529e87dee883b90c72 jdk7-b128 -6823ea7eb8eb6fab405d7edb7a5c2f690887a2fa jdk7-b129 -a36beda9b9de91231d92a2c529f21cc218fcf8d5 jdk7-b130 -d8af56da89bc0fc02a6b6ad78f51157a46d665ab jdk7-b131 -d61280d36755d1941fb487f554e8b7a6d0bca6a1 jdk7-b132 -fd444c61e7ed3d92b2a730da7c737b02191b682f jdk7-b133 -def8e16dd237a47fc067d66d4c616d7baaec6001 jdk7-b134 -f75a1efb141210901aabe00a834e0fc32bb8b337 jdk7-b135 -46acf76a533954cfd594bb88fdea79938abfbe20 jdk7-b136 -d1cf7d4ee16c341f5b8c7e7f1d68a8c412b6c693 jdk7-b137 -62b8e328f8c8c66c14b0713222116f2add473f3f jdk7-b138 -955488f34ca418f6cdab843d61c20d2c615637d9 jdk7-b139 -f4298bc3f4b6baa315643be06966f09684290068 jdk7-b140 -5d86d0c7692e8f4a58d430d68c03594e2d3403b3 jdk7-b141 -92bf0655022d4187e9b49c1400f98fb3392a4630 jdk7-b142 -4a05062d8c4dfa3edec3faf1052af28baba5adff jdk7-b143 -07a8728ad49ef6dfa469c3a8bf5ab1e9c80bed5c jdk7-b144 -8294c99e685a1f6d1d37c45cd97854cf74be771e jdk7-b145 -dca1e8a87e8f756f95b99bac8fe795750d42e1b0 jdk7-b146 -a2a589fc29543ed32919c78a1810ad93a6fcf5bc jdk7-b147 -de9223c94f9c710b3eebb599cd3586f36c8b94a9 jdk8-b01 -1b9d19620eb4606a25b1e28f86d66c8bfa867e06 jdk8-b02 -6815e85bf96d6d3875954f9777660372cd70d065 jdk8-b03 -31f5c34d78081572ad9a2401c0bb0c6b9711dd65 jdk8-b04 -c4f9ea1ecb55ff44e0dd21d2888ead308c86a3aa jdk8-b05 -429da7734bf491bccde2a752fae97e9f225896dc jdk8-b06 -bc5710332b294676661103bb20d47d2ea3ba8def jdk8-b07 -24ee504f80412770c6874836cd9e55b536427b1d jdk8-b08 -fbf3cabc9e3bb1fcf710941d777cb0400505fbe6 jdk8-b09 -f651ce87127980c58e3599daba964eba2f3b4026 jdk8-b10 -cc1f5ce8e504d350e0b0c28c5f84333f8d540132 jdk8-b11 -86db042b3385c338e17f7664447fdc7d406dd19e jdk8-b12 -4cc0ef72c812943743ef4765f1100e2fbe2b1a08 jdk8-b13 -9ffaa48dbfb0f5936c2b789867d0785faec7071d jdk8-b14 -b5060eae3b32fd9f884a09774338cd8186d7fafa jdk8-b15 -736a63b854f321c7824b7e47890135f80aee05e3 jdk8-b16 -f0eccb2946986fb9626efde7d8ed9c8192623f5c jdk8-b17 -885050364691ac1ac978305c63f3368a197fb04d jdk8-b18 -0ff7113a0882ec82d642cb9f0297b4e497807ced jdk8-b19 -6561530ea757c3f3a6fb171c9cc7b3885cdeca85 jdk8-b20 -b3a426170188f52981cf4573a2f14d487fddab0d jdk8-b21 -e8f03541af27e38aafb619b96863e17f65ffe53b jdk8-b22 -498124337041ad53cbaa7eb110f3d7acd6d4eac4 jdk8-b23 -7d3720d8c595d1519c31e9ff7366203fc2c61350 jdk8-b24 -0071a6d64113a35ba345bb1580c256de5ce17d3e jdk8-b25 -6c805d8ed4e5449ea5e4d158c7bdbd7b0b70efd1 jdk8-b26 -c51754cddc037b9609e202b9ed38363d8683e7a8 jdk8-b27 -16ba58282d117247f480aae7a79b88141ade52a3 jdk8-b28 -e070119aa56ee4dc5506c19d2c4d2eecab8ad429 jdk8-b29 -23da7804aca0c9c4e6e86532a1453125a76d95ee jdk8-b30 -bac81e9f7d57b75fba5ab31b571f3fe0dc08af69 jdk8-b31 -2c5208ccb863db936eab523f49450b3fcd230348 jdk8-b32 -a6e6d42203e6d35f9e8b31eac25b0021b4dd58ad jdk8-b33 -0ae89825c75c9492e44efb3aca3d9ee3d8a209df jdk8-b34 -f151d5833912a82cd4f203944da0305c3be83ecc jdk8-b35 -98ce9816ae089c959ba1e70fba98423a31c4e9fa jdk8-b36 -b3a91113026c99b0da010d41055719ab0d8938f0 jdk8-b37 -4cc5610a6dd6227da766ebf9742eb11ff5ded6c0 jdk8-b38 -35a5397278779a2f8f3013f81586dc8f30cb149d jdk8-b39 -6e4e654931b976304bf6e7b4d0d6db8f75bac5d9 jdk8-b40 -c029c972396cea042a0dc67c0f7ccf2fe68007d4 jdk8-b41 -5c5a64ec0839df5affe9394b99ff338c363acbca jdk8-b42 -69d8a827cdf9236be9694a46d75c710d71dac7d7 jdk8-b43 -7e981cb0ad6a194f1fa859f9ad47586db461f269 jdk8-b44 -9b19b2302c28f4da6d4078f66234abecfed5688a jdk8-b45 -600c9a1feb01633cbcf2341a43d1d21e6497ecd0 jdk8-b46 -b820143a6f1ce993c6e6f31db4d64de990f42654 jdk8-b47 -086271e35b0a419b38e8bda9bebd70693811df0a jdk8-b48 -cecd7026f30cbd83b0601925a7a5e059aec98138 jdk8-b49 -38fe5ab028908cf64dd73a43336ba3211577bfc3 jdk8-b50 -382651d28f2502d371eca751962232c0e535e57a jdk8-b51 -b67041a6cb508da18d2f5c7687e6a31e08bea4fc jdk8-b52 -c7aa5cca1c01689a7b1a92411daf83684af05a33 jdk8-b53 -7c6aa31ff1b2ae48c1c686ebe1aadf0c3da5be15 jdk8-b54 -319f583f66db47395fa86127dd3ddb729eb7c64f jdk8-b55 -ffe6bce5a521be40146af2ac03c509b7bac30595 jdk8-b56 -2c21c080b11b93efb3851e39e1363e45da805943 jdk8-b57 -479d3302a26d7607ba271d66973e59ebf58825b6 jdk8-b58 -3bd874584fc01aae92fbc8827e2bd04d8b6ace04 jdk8-b59 -5e3adc681779037a2d33b7be6f75680619085492 jdk8-b60 -cdaa6122185f9bf512dcd6600f56bfccc4824e8c jdk8-b61 -8d9d430b4244b95f5cf1ebe719f834a1ac5d6cd5 jdk8-b62 -21ee1dd7b809639284900a128b9b656a592ebc7a jdk8-b63 -70fa4b11f26522e69b51fd652215f60ce350bac3 jdk8-b64 -a2cf4d4a484378caea2e827ed604b2bbae58bdba jdk8-b65 -17820b958ae84f7c1cc6719319c8e2232f7a4f1d jdk8-b66 -76cc9bd3ece407d3a15d3bea537b57927973c5e7 jdk8-b67 -cb33628d4e8f11e879c371959e5948b66a53376f jdk8-b68 -adb5171c554e14cd86f618b5584f6e3d693d5889 jdk8-b69 -0d625373c69e2ad6f546fd88ab50c6c9aad01271 jdk8-b70 -a41ada2ed4ef735449531c6ebe6cec593d890a1c jdk8-b71 -6725b3961f987cf40f446d1c11cd324a3bec545f jdk8-b72 -fe94b40ffd9390f6cffcdf51c0389b0e6dde0c13 jdk8-b73 -f627eff819628822a0777af8062244352f2a29cf jdk8-b74 -f1478a6d25fddd311a84dcbfac50824cc1858bdd jdk8-b75 -f407160c280d1c5b00d314c535441ac26f195fee jdk8-b76 -d17eb2e13e362085e866d46235314c50cc4661cc jdk8-b77 -6d3dcd34b5b962ea1ef9eed0dafdee9e812401bc jdk8-b78 -a1313a8d90d17d363a3b2a645dc4030ec204b168 jdk8-b79 -3fa21fbf9be7e6b482af43aacb6a09acfa30bdb6 jdk8-b80 -e41d716405b209d3eddef8bd4240cec2bd34dcca jdk8-b81 -5e8c55025644730385a6f8fa029ecdb2d2c98a07 jdk8-b82 -bcebd3fdefc91abb9d7fa0c5af6211b3f8720da6 jdk8-b83 -d7ad0dfaa41151bd3a9ae46725b0aec3730a9cd0 jdk8-b84 -1872c12529090e1c1dbf567f02ad7ae6231b8f0c jdk8-b85 -da9a4c9312816451884aa6db6f18be51a07bff13 jdk8-b86 -5ebf6c63714de2c9dcf831074086d31daec819df jdk8-b87 -e517701a4d0e25ae9c7945bca6e1762a8c5d8aa6 jdk8-b88 -4dec41b3c5e3bb616f0c6f15830d940905aa5d16 jdk8-b89 -f09ab0c416185e3cba371e81bcb6a16060c90f44 jdk8-b90 -80b6c3172dc2cfceb022411292d290a967f9c728 jdk8-b91 -2fd6acba737b01e705e1f7c33588c922a3787f13 jdk8-b92 -b72ae39e1329fefae50d4690db4fde43f3841a95 jdk8-b93 -0d804e3b955dce406af6a79ac1cc35c696aff7fb jdk8-b94 -49fe9c8049132647ad38837a877dd473e6c9b0e5 jdk8-b95 -ea73f01b9053e7165e7ba80f242bafecbc6af712 jdk8-b96 -0a85476a0b9cb876d5666d45097dac68bef3fce1 jdk8-b97 -711eb4aa87de68de78250e0549980936bab53d54 jdk8-b98 -2d3875b0d18b3ad1c2bebf385a697e309e4005a4 jdk8-b99 -3d34036aae4ea90b2ca59712d5a69db3221f0875 jdk8-b100 -edb01c460d4cab21ff0ff13512df7b746efaa0e7 jdk8-b101 -bbe43d712fe08e650808d774861b256ccb34e500 jdk8-b102 -30a1d677a20c6a95f98043d8f20ce570304e3818 jdk8-b103 -b5ed503c26ad38869c247c5e32debec217fd056b jdk8-b104 -589f4fdc584e373a47cde0162e9eceec9165c381 jdk8-b105 -514b0b69fb9683ef52062fd962a3e0644431f64d jdk8-b106 -892889f445755790ae90e61775bfb59ddc6182b5 jdk8-b107 -74049f7a28b48c14910106a75d9f2504169c352e jdk8-b108 -af9a674e12a16da1a4bd53e4990ddb1121a21ef1 jdk8-b109 -b5d2bf482a3ea1cca08c994512804ffbc73de0a1 jdk8-b110 -b9a0f6c693f347a6f4b9bb994957f4eaa05bdedd jdk8-b111 -ad67c34f79c28a8e755f4a49f313868619d6702c jdk8-b112 -4a4dbcf7cb7d3e1a81beaa3b11cd909f69ebc79a jdk8-b113 -dfa34ab293faad9b543a24646dbb381bc3ab5586 jdk8-b114 -3dd9732b17034f45d111996d1d50287b05a3998c jdk8-b115 -aaf663f591aba43ec942263b15ba62759ce26a1e jdk8-b116 -31b0e03fcad73d7886b306b4c2e57ad270780d0d jdk8-b117 -f5b521ade7a35cea18df78ee86322207729f5611 jdk8-b118 -87b743b2263cc53955266411b7797b365a0fb050 jdk8-b119 -a1ee9743f4ee165eae59389a020f2552f895dac8 jdk8-b120 -13b877757b0b1c0d5813298df85364f41d7ba6fe jdk9-b00 -f130ca87de6637acae7d99fcd7a8573eea1cbaed jdk9-b01 -b32e2219736e42baaf45daf0ad67ed34f6033799 jdk9-b02 -7f655f31f9bcee618cf832f08176ad8c1ed3fdd3 jdk9-b03 -099891b1d86f3719e116ac717ffdafc90d037fb7 jdk9-b04 -dd311791ad6895a3989020dd6c6c46db87972ab8 jdk9-b05 -85dbdc227c5e11429b4fc4a8ba763f50107edd6e jdk9-b06 -c826d05f1fb0773f6a28caa763307dd30d90d36e jdk9-b07 -b47e021195757f8f45582124ea7cad48ccf5f872 jdk9-b08 -efe7dbc6088691757404e0c8745f894e3ca9c022 jdk9-b09 -8c0bdeecd7c0f9ce3f3762a51991f755cb3a972c jdk9-b10 -0809c9a4d36e6291f1c4384604c4bbf29e975722 jdk9-b11 -0d1f816217dce5e72187f167cc1816080cbeb453 jdk9-b12 -1a30593dcb9802faec3b6edb24d86ca088594e4e jdk9-b13 -97932f6ad950ae5a73a9da5c96e6e58503ff646b jdk9-b14 -74eb0778e4f2dbff6628e718378449fba27c4265 jdk9-b15 -4a09f5d30be844ac6f714bdb0f63d8c3c08b9a98 jdk9-b16 -410bccbded9e9cce80f1e13ad221e37ae97a3986 jdk9-b17 -c5495e25c7258ab5f96a1ae14610887d76d2be63 jdk9-b18 -2dcf544eb7ed5ac6a3f7813a32e33acea7442405 jdk9-b19 -89731ae72a761afdf4262e8b9513f302f6563f89 jdk9-b20 -28dd0c7beb3cad9cf95f17b4b5ad87eb447a4084 jdk9-b21 -9678e0db8ff6ed845d4c2ee4a3baf7f386a777e5 jdk9-b22 -39cfdc2dcaf3f195c55398e4e677ab053b07e3d2 jdk9-b23 -d9ce05f36ffec3e5e8af62a92455c1c66a63c320 jdk9-b24 -13a5c76976fe48e55c9727c25fae2d2ce7c05da0 jdk9-b25 -cd6f4557e7fea5799ff3762ed7a80a743e75d5fd jdk9-b26 -d06a6d3c66c08293b2a9650f3cc01fd55c620e65 jdk9-b27 -f4269e8f454eb77763ecee228a88ae102a9aef6e jdk9-b28 -c36c0092693707a8255561433647e8c3cd724ccd jdk9-b29 -b2287cac7813c70ed7f679d9a46fe774bd4005f8 jdk9-b30 -9d0e6639a4d71b63507dd94b1a028e963b27e798 jdk9-b31 -1b1ec4291abc0ba6da7bf79b754f08dd759a4a0c jdk9-b32 -f0c5e4b732da823bdaa4184133675f384e7cd68d jdk9-b33 -9618201c5df28a460631577fad1f61e96f775c34 jdk9-b34 -a137992d750c72f6f944f341aa19b0d0d96afe0c jdk9-b35 -41df50e7303daf73c0d661ef601c4fe250915de5 jdk9-b36 -b409bc51bc23cfd51f2bd04ea919ec83535af9d0 jdk9-b37 -948cceef81ba4cb34bc233e7cc5952951ff04e88 jdk9-b38 -4e7c4d692e934cb9023af8201e7c2b510e9c4ee1 jdk9-b39 -82f4cb44b2d7af2352f48568a64b7b6a5ae960cd jdk9-b40 -9fffb959eb4197ff806e4ac12244761815b4deee jdk9-b41 -3107be2ba9c6e208a0b86bc7100a141abbc5b5fb jdk9-b42 -6494b13f88a867026ee316b444d9a4fa589dd6bd jdk9-b43 -abbfccd659b91a7bb815d5e36fed635dcdd40f31 jdk9-b44 -bfc24ae2b900187585079bb11e66e459d1e525fe jdk9-b45 -722378bc599e38d9a1dd484de30f10dfd7b21438 jdk9-b46 -8327024a99559982b848e9c2191da9c0bf8838fd jdk9-b47 -b2f9702efbe95527ea3a991474fda23987ff1c5c jdk9-b48 -5b8db585a33c3cc48e70e688ceee57dd9271dc5d jdk9-b49 -1550b2f6b63d1411fa84dc7bbc6f04809aedb43f jdk9-b50 -6efe265424e3f1ea596408a1f71baf2de316c772 jdk9-b51 -d6224d6021459ac8b3832e822f5acc849fa944af jdk9-b52 -874d76e4699dfcd61ae1826c9fe0ddc1610ad598 jdk9-b53 -82cd31c5d6ca8d4c1653f4eb1c09eb2d9a3b2813 jdk9-b54 -c97e2d1bad9708d379793ba2a4c848eda14c741e jdk9-b55 -47544495db2d3d2edf0f85862d8715592fdb919f jdk9-b56 -ddb95d8f169b09544cc17e72a6baaff2400092f5 jdk9-b57 -f40752db7773ca0c737f2ad88371e35c57fdfed7 jdk9-b58 -da950f343762a856d69751570a4c07cfa68a415b jdk9-b59 -38f98cb6b33562a926ec3b79c7b34128be37647d jdk9-b60 -ac3f5a39d4ff14d70c365e12cf5ec8f2abd52a04 jdk9-b61 -e7dbbef69d12b6a74dfad331b7188e7f893e8d29 jdk9-b62 -989253a902c34dcb7564695161c9200a5fbb7412 jdk9-b63 -8ffdeabc7c2b9a8280bf46cae026ac46b4d31c26 jdk9-b64 -4915246064b2f89d5f00c96e758686b7fdad36a6 jdk9-b65 -ff3fc75f3214ad7e03595be1b0d0f38d887b6f0e jdk9-b66 -56166ce66037952fa21e9f680b31bf8eb47312c0 jdk9-b67 -5b500c93ce4822d47061cd518ff3f72d9d8cb5b5 jdk9-b68 -d69c968463f0ae5d0b45de3fc14fe65171b23948 jdk9-b69 -43d0179ee9de3bfffae3417f09e07eb6d8efc963 jdk9-b70 -f66c185284727f6e6ffd27e9c45ed2dd9da0a691 jdk9-b71 -61d2d0629b6dbf4c091dc86151ade1b3ef34fffe jdk9-b72 -9b3a9d72f07b40c648de79961679f42283af1bb5 jdk9-b73 -7c577fda1855d03c04546694d514678f596508c9 jdk9-b74 -f55df5cfe11c97e4b58998b76f5bd00a73cde12d jdk9-b75 -eeea9adfd1e3d075ef82148c00a4847a1aab4d26 jdk9-b76 -c25e882cee9622ec75c4e9d60633539a2f0a8809 jdk9-b77 -c8753d0be1778944dc512ec86a459941ea1ad2c3 jdk9-b78 -3966bd3b8167419aa05c6718a4af1cf54b1e3c58 jdk9-b79 -3c9f5bd909ae7187f24622ee4b69f8a5756a9271 jdk9-b80 -2050b3a0aadcb0e024bf798197421d58e54ec8bf jdk9-b81 -6521875cb63e1d0121b30af56ebbc36db078c4c6 jdk9-b82 -f61a63b7d1e52e307abc0bfc751203155d362ec4 jdk9-b83 -51b2db2fa04c16d767b66113dbf08c5349ce382a jdk9-b84 -8392405ab038b22e69a3728e17dbdd9e3d3a22ed jdk9-b85 -7db0663a5e968059fa7c772172187ebd60b6492d jdk9-b86 -1a52a30674cd28c24d4d388150336121f2e9ddf9 jdk9-b87 -16b4968f9bb8f34371b42c0ba483d76e91ba84d8 jdk9-b88 -4a0312f2894bcbe1fd20266c8fda8d983bd2fcf6 jdk9-b89 -d131f4b8433a79408f935eff9bf92a0664229b60 jdk9-b90 -8077fd2f055d31e50b46fcf62d9c035bc385a215 jdk9-b91 -f242d4332f563648426a1b0fa02d8741beba19ef jdk9-b92 -09206c6513b300e1ac8541f3be012e1a49312104 jdk9-b93 -25a2cab05cfbe6034b71d9e72d64c65b0572ce63 jdk9-b94 -5ac6287ec71aafe021cc839d8bc828108d23aaba jdk-9+95 -139f19d70350238e15e107945cea75082b6380b3 jdk-9+96 -4edcff1b9a8875eb6380a2165dfec599e8e3f7c0 jdk-9+97 -d00ad2d9049ac60815f70bff445e95df85648bd2 jdk-9+98 -f9bcdce2df26678c3fe468130b535c0342c69b89 jdk-9+99 -4379223f8806626852c46c52d4e7a27a584b406e jdk-9+100 -80f67512daa15cf37b4825c1c62a675d524d7c49 jdk-9+101 -2dc4c11fe48831854916d53c3913bdb7d49023ea jdk-9+102 -4a652e4ca9523422149958673033e0ac740d5e1e jdk-9+103 -086c682bd8c5f195c324f61e2c61fbcd0226d63b jdk-9+104 -db483b34fa7148d257a429acddbde9c13687dcae jdk-9+105 -6c644cca3f3fc2763e2ff7d669849a75d34543ba jdk-9+106 -1c076468bf7dad5b8f2ee5dcf66e2279caa3e208 jdk-9+107 -257b579d813201682931d6b42f0445ffe5b4210d jdk-9+108 -c870cb782aca71093d2584376f27f0cfbfec0e3a jdk-9+109 -4a95f4b1bd8bfce85dc02a593896749feab96c34 jdk-9+110 -a6614ff7bf09da74be1d0ef3d9755090d244697a jdk-9+111 -7359994942f8d8e723b584d66a3a92c2e9e95e5c jdk-9+112 -6072af7a98be3922f26bdce71b53bb3646cb2ac9 jdk-9+113 -c84d0cce090e161d736de69e941830adf8c2f87a jdk-9+114 -8d78fb40648dd221ce4ef19f9d5aa41ee1a3a884 jdk-9+115 -84aba7335005a3a47751dcf1f37935f97df9f99a jdk-9+116 -82b8d12a553f5617737c238cec060281d52e351c jdk-9+117 -7c04fcb12bd4a31570a238e663fa846dfa5ec3b8 jdk-9+118 -caf97b37ebec84288c112d21d3a60cb628cba1e8 jdk-9+119 -9330543436402b8f3bd070524846a464d8143557 jdk-9+120 -18e5cdecb37a2f03ba74f6c8f022858bcbaacf56 jdk-9+121 -7693aa00e131493ceb42b93305e2f014c9922a3b jdk-9+122 -d53037a90c441cb528dc41c30827985de0e67c62 jdk-9+123 -2a5697a98620c4f40e4a1a71478464399b8878de jdk-9+124 -3aa52182b3ad7c5b3a61cf05a59dd07e4c5884e5 jdk-9+125 -03e7b2c5ae345be3caf981d76ceb3efe5ff447f8 jdk-9+126 -8e45018bde9de4ad15b972ae62874bba52dba2d5 jdk-9+127 -5bf88dce615f6804f9e101a96ffa7c9dfb4fbbbe jdk-9+128 -e8373543a3f0f60589b7d72b1f9b172721124caf jdk-9+129 -e613affb88d178dc7c589f1679db113d589bddb4 jdk-9+130 -4d2a15091124488080d65848b704e25599b2aaeb jdk-9+131 -2e83d21d78cd9c1d52e6cd2599e9c8aa36ea1f52 jdk-9+132 -e17429a7e843c4a4ed3651458d0f950970edcbcc jdk-9+133 -a71210c0d9800eb6925b61ecd6198abd554f90ee jdk-9+134 -e384420383a5b79fa0012ebcb25d8f83cff7f777 jdk-9+135 -1b4b5d01aa11edf24b6fadbe3d2f3e411e3b02cd jdk-9+136 -9cb87c88ed851c0575b8ead753ea238ed5b544e9 jdk-9+137 -d273dfe9a126d3bffe92072547fef2cd1361b0eb jdk-9+138 -65477538bec32963dc41153d89c4417eb46c45fc jdk-9+139 -0875007901f7d364a08220b052f0c81003e9c8c5 jdk-9+140 -9aadd2163b568d76f8969ad2fb404a63733da359 jdk-9+141 -df0e03e3ca0ed1307793017dfc1a054c8726131c jdk-9+142 -d62173b931bf5b6bffc6e80a9060bb2e8b8efc75 jdk-9+143 -31f5023200d42185b70c4c00ba5672391e4642d0 jdk-9+144 -3ee4e7827413fa5c5c4fca58597b0ad89e921bfb jdk-9+145 -581331db696a62dd411926ba7fd437252252a71d jdk-9+146 -f4e854a77aa38749bd90f722b06974a56e7233d5 jdk-9+147 -5c71ea43933b6c7e8a85eb1a4eb2213011b95d82 jdk-9+148 -cf139f925da04c8bd7efd33270a0315d72b338d3 jdk-9+149 -17469f16fbb406ec9f0dd262ce776ab6efbc38f1 jdk-9+150 -37b95df0042ae0687324e1f7dc4a2519e230e704 jdk-9+151 -ab2c8b03c3284fcbdd157551a66f807e3a182d9b jdk-9+152 -d7034ff7f8e257e81c9f95c7785dd4eaaa3c2afc jdk-9+153 -8c70d170e62c0c58b5bc3ba666bd140399b98c9c jdk-10+0 -45b751afd11e6c05991cf4913c5a0ac3304fcc4e jdk-9+154 -f4aff695ffe05cfdb69d8af25a4ddc6a029754ea jdk-9+155 -06bce0388880b5ff8e040e4a9d72a3ea11dac321 jdk-9+156 -74116beae88a8f17a80301aa6c83865c82f10ece jdk-10+1 -4a79ad46e578112fce68f1af9dd931025cc235cb jdk-10+2 -d1cab6c7e608479be4ebfad48a25b0ed48600f62 jdk-10+3 -02253db2ace1422f576f58502fc7831ead77424b jdk-10+4 -f113ce12fe24fbd24acf02711372d9f1e1c12426 jdk-10+5 -1407b19a2ddf6baae162f5a1a5b96af473f4d7d1 jdk-10+6 -30e75693ae99fd8e47fd2f5116527aff1b59aff9 jdk-10+7 -c42dc7b58b4d4301ea676a76326fd9bbd403d595 jdk-10+8 -aa5b01f5e5620438fd39efdb2e2f6365a2c7d898 jdk-10+9 -b0f2b8ff25a2209b2c807785d75f20e5086bbfc2 jdk-10+10 -036dbf8b381798e5d31065109714d04d97bf98a4 jdk-10+11 -e6d70017f5b9adbb2ec82d826973d0251800a3c3 jdk-10+12 -9927a9f16738e240ab7014f0118f41e314ef8f99 jdk-10+13 -9ef5029b247b4d940080417a287440bbdbab995b jdk-10+14 -878e216039322cb3f0ecbd0944642a2b4e2593f3 jdk-10+15 -4bbea012e5676e8025ade2bcfab4d6581e6e9f4b jdk-10+16 -7db699468b4f84abbcc01647e5a964409737411a jdk-10+17 -3739654290616e533fc6f51bf9ad69ed47a6abba jdk-10+18 -14df107500cc3b8ab238c3e4ad2c74e12bfe6067 jdk-10+19 -4586bc5d28d13d3147b993e6237eaf29a7073bbb jdk-10+20 -a85884d55ce32799f5c7382b7ea4839052b362a2 jdk-10+21 -e5357aa85dadacc6562175ff74714fecfb4470cf jdk-10+22 -22850b3a55240253841b9a425ad60a7fcdb22d47 jdk-10+23 -3b201865d5c1f244f555cad58da599c9261286d8 jdk-10+24 -8eb5e3ccee560c28ac9b1df2670adac2b3d36fad jdk-10+25 -1129253d3bc728a2963ba411ab9dd1adf358fb6b jdk-10+26 -b87d7b5d5dedc1185e5929470f945b7378cdb3ad jdk-10+27 -92f08900cb3c0d694e5c529a676c1c9e5909193f jdk-10+28 -a6e591e12f122768f675428e1e5a838fd0e9c7ec jdk-10+29 -8fee80b92e65149f7414250fd5e34b6f35d417b4 jdk-10+30 -e6278add9ff28fab70fe1cc4c1d65f7363dc9445 jdk-10+31 -a2008587c13fa05fa2dbfcb09fe987576fbedfd1 jdk-10+32 -bbd692ad4fa300ecca7939ffbe3b1d5e52a28cc6 jdk-10+33 -89deac44e51517841491ba86ff44aa82a5ca96b3 jdk-10+34 -d8c634b016c628622c9abbdc6bf50509e5dedbec jdk-10+35 -0ee20aad71c4f33c426372b4c8bcc1235ce2ec08 jdk-11+0 -959f2f7cbaa6d2ee45d50029744efb219721576c jdk-10+36 -4f830b447edf04fb4a52151a5ad44d9bb60723cd jdk-10+37 -e569e83139fdfbecfeb3cd9014d560917787f158 jdk-10+38 -5b834ec962366e00d4445352a999a3ac14e26f64 jdk-10+39 -860326263d1f6a83996d7da0f4c66806ae4aa1eb jdk-10+40 -3eae36c6baa5f916a3024cf1513e22357e00185d jdk-10+41 -4b62b815b4f49970b91a952929cf50115c263cb3 jdk-10+42 -107413b070b92c88bde6230ceb4a19b579781068 jdk-10+43 -dfa46cfe56346884a61efdc30dc50f7505d66761 jdk-11+1 -03ae177c26b016353e5ea1cab6ffd051dfa086ca jdk-11+2 -663f20fc51091bd7f95d18448850ba091207b7bd jdk-10+44 -4f96cf952e71cb8a127334494faf28880c26181b jdk-10+45 -1fd4d6068f54561cfc67d54fc9ca84af7212c4f8 jdk-11+3 -e59941f7247d451fa7df9eaef3fce0f492f8420c jdk-11+4 -d5c43e9f08fb9a7c74aae0d48daf17f2ad2afaef jdk-11+5 -3acb379b86725c47e7f33358cb22efa8752ae532 jdk-11+6 -f7363de371c9a1f668bd0a01b7df3d1ddb9cc58b jdk-11+7 -755e1b55a4dff510f9639cdb5c5e82549a7e09b3 jdk-11+8 -0c3e252cea44f06aef570ef464950ab97c669970 jdk-11+9 -6fa770f9f8ab296e1ce255ec17ccf6d4e1051886 jdk-10+46 -69d7398038c54774d9395b6810e0cca335edc02c jdk-11+10 -e1e60f75cd39312a7f59d2a4f91d624e5aecc95e jdk-11+11 -3ab6ba9f94a9045a526d645af26c933235371d6f jdk-11+12 -758deedaae8406ae60147486107a54e9864aa7b0 jdk-11+13 -3595bd343b65f8c37818ebe6a4c343ddeb1a5f88 jdk-11+14 -a11c1cb542bbd1671d25b85efe7d09b983c48525 jdk-11+15 -02934b0d661b82b7fe1052a04998d2091352e08d jdk-11+16 -64e4b1686141e57a681936a8283983341484676e jdk-11+17 -e1b3def126240d5433902f3cb0e91a4c27f6db50 jdk-11+18 -36ca515343e00b021dcfc902e986d26ec994a2e5 jdk-11+19 -95aad0c785e497f1bade3955c4e4a677b629fa9d jdk-12+0 -9816d7cc655e53ba081f938b656e31971b8f097a jdk-11+20 -14708e1acdc3974f4539027cbbcfa6d69f83cf51 jdk-11+21 -00b16d0457e43d23f6ca5ade6b243edce62750a0 jdk-12+1 -9937ef7499dcd7673714517fd5e450410c14ba4e jdk-11+22 -69b438908512d3dfef5852c6a843a5778333a309 jdk-12+2 -1edcf36fe15f79d6228d1a63eb680878e2386480 jdk-11+23 -990db216e7199b2ba9989d8fa20b657e0ca7d969 jdk-12+3 -ea900a7dc7d77dee30865c60eabd87fc24b1037c jdk-11+24 -499b873761d8e8a1cc4aa649daf04cbe98cbce77 jdk-12+4 -331888ea4a788df801b1edf8836646cd25fc758b jdk-11+25 -f8696e0ab9b795030429fc3374ec03e378fd9ed7 jdk-12+5 -945ba9278a272a5477ffb1b3ea1b04174fed8036 jdk-11+26 -7939b3c4e4088bf4f70ec5bbd8030393b653372f jdk-12+6 -9d7d74c6f2cbe522e39fa22dc557fdd3f79b32ad jdk-11+27 -ef57958c7c511162da8d9a75f0b977f0f7ac464e jdk-12+7 -76072a077ee1d815152d45d1692c4b36c53c5c49 jdk-11+28 -492b366f8e5784cc4927c2c98f9b8a3f16c067eb jdk-12+8 -31b159f30fb281016c5f0c103552809aeda84063 jdk-12+9 -8f594f75e0547d4ca16649cb3501659e3155e81b jdk-12+10 -f0f5d23449d31f1b3580c8a73313918cafeaefd7 jdk-12+11 -15094d12a632f452a2064318a4e416d0c7a9ce0c jdk-12+12 -511a9946f83e3e3c7b9dbe1840367063fb39b4e1 jdk-12+13 -8897e41b327c0a5601c6ba2bba5d07f15a3ffc91 jdk-12+14 -8897e41b327c0a5601c6ba2bba5d07f15a3ffc91 jdk-12+14 -6f04692c7d5137ee34a6bd94c0c8a6c9219cb127 jdk-12+14 -f8626bcc169813a4b2a15880386b952719d1d6d1 jdk-12+15 -199658d1ef860cdc17055b4fd3e94b057f292fe9 jdk-12+16 -eefa65e142af305923d2adcd596fab9c639723a1 jdk-12+17 -e38473506688e0995e701fc7f77d5a91b438ef93 jdk-12+18 -dc1f9dec2018a37fedba47d8a2aedef99faaec64 jdk-12+19 -40098289d5804c3b5e7074bc75501a81e70d9b0d jdk-12+20 -f8fb0c86f2b3d24294d39c5685a628e1beb14ba7 jdk-12+21 -732bec44c89e8b93a38296bf690f97b7230c5b6d jdk-12+22 -eef755718cb24813031a842bbfc716a6cea18e9a jdk-12+23 -cc4098b3bc10d1c390384289025fea7b0d4b9e93 jdk-13+0 -7d4397b43fa305806160785a4c7210600d59581a jdk-12+24 -11033c4ada542f9c9a873314b6ecf60af19e8256 jdk-13+1 -7496df94b3b79f3da53925d2d137317715f11d97 jdk-12+25 -50677f43ac3df9a8684222b8893543c60f3aa0bd jdk-13+2 -de9fd809bb475401aad188eab2264226788aad81 jdk-12+26 -642346a11059b9f283110dc301a24ed43b76a94e jdk-13+3 -f15d443f97318e9b40e6f451e327ff69ed4ec361 jdk-12+27 -a47b8125b7cc9ef59619745c163975fe935b57ed jdk-13+4 -659b004b6a1bd8c31e766cbdf328d8f8473fd4d7 jdk-12+28 -e3ed960609927b5fdfd0a797159835cd83a81a31 jdk-13+5 -44f41693631f9b5ac78ff4d2bfabd6734fe46df2 jdk-12+29 -b5f05fe4a6f8b3996a000c20078b356d991ca8ec jdk-13+6 -6c377af36a5c4203f16aed8a5e4c2ecc08fcd8bd jdk-12+30 -021917019cda1c0c5853255322274f37693a2431 jdk-13+7 -b5f7bb57de2f797be34f6c75d45c3245ad37ab97 jdk-12+31 -a535ba736cabc6886acdff36de3a096c46e5ddc5 jdk-13+8 -4ce47bc1fb92cf94c6e3d1f49d582f02dcb851ab jdk-12+32 -c081f3ea6b9300265a4a34e38f970b1e3ddaae9f jdk-13+9 -b67884871b5fff79c5ef3eb8ac74dd48d71ea9b1 jdk-12+33 -8e069f7b4fabfe05d9f500783e6d56cb0196d25c jdk-13+10 -21ea4076a275a0f498afa517e9ee1b94a9cf0255 jdk-13+11 -1d7aec80147a6d92b101a76aef92f3ddc88bedf4 jdk-13+12 -b67884871b5fff79c5ef3eb8ac74dd48d71ea9b1 jdk-12-ga -83cace4142c8563b6a921787db02388e1bc48d01 jdk-13+13 -46cf212cdccaf4fb064d913b12004007d3322b67 jdk-13+14 -f855ec13aa2501ae184c8b3e0626a8cec9966116 jdk-13+15 -9d0ae9508d5337b0dc7cc4684be42888c4023755 jdk-13+16 -93b702d2a0cb9e32160208f6700aede1f8492773 jdk-13+17 -bebb82ef3434a25f8142edafec20165f07ac562d jdk-13+18 -a43d6467317d8f1e160f67aadec37919c9d64443 jdk-13+19 -6ccc7cd7931e34129f6b7e04988fc9a63958dde0 jdk-13+20 -f2f11d7f7f4e7128f8aba6ffa576cfa76fbf7d1a jdk-13+21 -181986c5476468bc2dd4532af49599003ee8af37 jdk-13+22 -b034d2dee5fc93d42a81b65e58ce3f91e42586ff jdk-13+23 -7e2238451585029680f126ccbb46d01f2ff5607f jdk-13+24 -22b3b7983adab54e318f75aeb94471f7a4429c1e jdk-14+0 -22b3b7983adab54e318f75aeb94471f7a4429c1e jdk-13+25 -2f4e214781a1d597ed36bf5a36f20928c6c82996 jdk-14+1 -0692b67f54621991ba7afbf23e55b788f3555e69 jdk-13+26 -43627549a488b7d0b4df8fad436e36233df89877 jdk-14+2 -b7f68ddec66f996ae3aad03291d129ca9f02482d jdk-13+27 -e64383344f144217c36196c3c8a2df8f588a2af3 jdk-14+3 -1e95931e7d8fa7e3899340a9c7cb28dbea50c10c jdk-13+28 -19d0b382f0869f72d4381b54fa129f1c74b6e766 jdk-14+4 -3081f39a3d30d63b112098386ac2bb027c2b7223 jdk-13+29 -0f1e29c77e50c7da11d83df410026392c4d1a28c jdk-14+5 -2e63fb0a885fa908a97bbb0da8d7c3de11536aca jdk-13+30 -443f7359b34d60e7821216ffc60f88b6ffe0ccdd jdk-14+6 -6a159c6c23ccd0029140ab91653442e412305ce5 jdk-13+31 -28ab01c067551ef158abaef08e154e1051ca0893 jdk-14+7 -929f37a9c35d530d4e866f6e832001aeb4cfb371 jdk-13+32 -c0023e364b6f130cb1e93747b796d8718d544db1 jdk-14+8 -9c250a7600e12bdb1e611835250af3204d4aa152 jdk-13+33 -18f189e69b29f8215a3500b875127ed4fb2d977a jdk-14+9 -ececb6dae777e622abda42c705fd984a42f46b5a jdk-14+10 -bf4c808a4488025a415f867e54c8b088417e08a0 jdk-14+11 -8570f22b9b6ac6bec673899b582150865696e425 jdk-14+12 -fbbe6672ae15deaf350a9e935290a36f57ba9c25 jdk-14+13 -cddef3bde924f3ff4f17f3d369280cf69d0450e5 jdk-14+14 -9c250a7600e12bdb1e611835250af3204d4aa152 jdk-13-ga -778fc2dcbdaa8981e07e929a2cacef979c72261e jdk-14+15 -d29f0181ba424a95d881aba5eabf2e393abcc70f jdk-14+16 -5c83830390baafb76a1fbe33443c57620bd45fb9 jdk-14+17 -e84d8379815ba0d3e50fb096d28c25894cb50b8c jdk-14+18 -9b67dd88a9313e982ec5f710a7747161bc8f0c23 jdk-14+19 -54ffb15c48399dd59922ee22bb592d815307e77c jdk-14+20 -c16ac7a2eba4e73cb4f7ee9294dd647860eebff0 jdk-14+21 -83810b7d12e7ff761ad3dd91f323a22dad96f108 jdk-14+22 -15936b142f86731afa4b1a2c0fe4a01e806c4944 jdk-14+23 -438337c846fb071900ddb6922bddf8b3e895a514 jdk-14+24 -17d242844fc9e7d18b3eac97426490a9c246119e jdk-14+25 -288777cf0702914e5266bc1e5d380eed9032ca41 jdk-14+26 -2c724dba4c3cf9516b2152e151c9aea66b21b30b jdk-15+0 -91a3f092682fc715d991a87eb6ec6f28886d2035 jdk-14+27 -63e17cf29bed191ea21020b4648c9cdf893f80f5 jdk-15+1 -2069b4bfd23b56b6fc659fba8b75aaaa23debbe0 jdk-14+28 -f33197adda9ad82fdef46ac0f7dc0126204f35b2 jdk-15+2 -563fa900fa17c290ae516c7a3a69e8c069dde304 jdk-14+29 -d05fcdf25717d85e80a3a39a6b719458b22be5fe jdk-15+3 -d54ce919da90dab361995bb4d87be9851f00537a jdk-14+30 -bb0a7975b31ded63d594ee8dbfc4d4ead587f79b jdk-15+4 -decd3d2953b640f1043ee76953ff89238bff92e8 jdk-14+31 -b97c1773ccafae4a8c16cc6aedb10b2a4f9a07ed jdk-15+5 -2776da28515e087cc8849acf1e131a65ea7e77b6 jdk-14+32 -ef7d53b4fccd4a0501b17d974e84f37aa99fa813 jdk-15+6 -f728b6c7f4910d6bd6070cb4dde8393f4ba95113 jdk-14+33 -e2bc57500c1b785837982f7ce8af6751387ed73b jdk-15+7 -a96bc204e3b31ddbf909b20088964112f052927e jdk-14+34 -c7d4f2849dbfb755fc5860b362a4044ea0c9e082 jdk-15+8 -4a87bb7ebfd7f6a25ec59a5982fe3607242777f8 jdk-14+35 -62b5bfef8d618e08e6f3a56cf1fb0e67e89e9cc2 jdk-15+9 -bc54620a3848c26cff9766e5e2a6e5ddab98ed18 jdk-14+36 -1bee69801aeea1a34261c93f35bc9de072a98704 jdk-15+10 -b2dd4028a6de4e40dda8b76109e4b5c6b294f980 jdk-15+11 -2ec0ff3042630ddbd3587e340fe0dd40391cb6c4 jdk-15+12 -1c06a8ee8acad4d93c782626a233693a73de0add jdk-15+13 -1d6ceb13e142665ea833fca01c8c8598e0ddd211 jdk-15+14 -bc54620a3848c26cff9766e5e2a6e5ddab98ed18 jdk-14-ga -82b7c62cf4cc56828a8fb724f57087967232a2a7 jdk-15+15 -5c7ec21f5d13f6eb5cd32288c69b8be2f9cac256 jdk-15+16 -dd5198db2e5b1ebcafe065d987c03ba9fcb50fc3 jdk-15+17 -44aef192b488a48cce12422394691a6b1d16b98e jdk-15+18 -7cc27caabe6e342151e8baf549beb07a9c755ec2 jdk-15+19 -46bca5e5e6fb26efd07245d26fe96a9c3260f51e jdk-15+20 -12b55fad80f30d24b1f8fdb3b947ea6465ef9518 jdk-15+21 -7223c6d610343fd8323af9d07d501e01fa1a7696 jdk-15+22 -f143729ca00ec14a98ea5c7f73acba88da97746e jdk-15+23 -497fd9f9129c4928fd5a876dd55e0daf6298b511 jdk-15+24 -90b266a84c06f1b3dc0ed8767856793e8c1c357e jdk-15+25 -0a32396f7a690015d22ca3328ac441a358295d90 jdk-15+26 -93813843680bbe1b7efbca56c03fd137f20a2c31 jdk-16+0 -93813843680bbe1b7efbca56c03fd137f20a2c31 jdk-15+27 -4a485c89d5a08b495961835f5308a96038678aeb jdk-16+1 -06c9f89459daba98395fad726100feb44f89ba71 jdk-15+28 -bcbe7b8a77b8971bc221c0be1bd2abb6fb68c2d0 jdk-16+2 -b58fc60580550a4a587cab729d8fd87223ad6932 jdk-15+29 -76810b3a88c8c641ae3850a8dfd7c40c984aea9d jdk-16+3 -6909e4a1f25bfe9a2727026f5845fc1fc44a36aa jdk-15+30 -e2622818f0bd30e736252eba101fe7d2c27f400b jdk-16+4 -a32f58c6b8be81877411767de7ba9c4cf087c1b5 jdk-15+31 -143e258f64af490010eb7e0bacc1cfaeceff0993 jdk-16+5 -2dad000726b8d5db9f3df647fb4949d88f269dd4 jdk-15+32 -4a8fd81d64bafa523cddb45f82805536edace106 jdk-16+6 -6b65f4e7a975628df51ef755b02642075390041d jdk-15+33 -c3a4a7ea7c304cabdacdc31741eb94c51351668d jdk-16+7 -b0817631d2f4395508cb10e81c3858a94d9ae4de jdk-15+34 -0a73d6f3aab48ff6d7e61e47f0bc2d87a054f217 jdk-16+8 -fd60c3146a024037cdd9be34c645bb793995a7cc jdk-15+35 -c075a286cc7df767cce28e8057d6ec5051786490 jdk-16+9 -b01985b4f88f554f97901e53e1ba314681dd9c19 jdk-16+10 -e3f940bd3c8fcdf4ca704c6eb1ac745d155859d5 jdk-15+36 -5c18d696c7ce724ca36df13933aa53f50e12b9e0 jdk-16+11 -fc8e62b399bd93d06e8d13dc3b384c450e853dcd jdk-16+12 -fd07cdb26fc70243ef23d688b545514f4ddf1c2b jdk-16+13 -36b29df125dc88f11657ce93b4998aa9ff5f5d41 jdk-16+14 diff --git a/.jcheck/conf b/.jcheck/conf index 42c3716369ea45aef1693b447d60146073e3b9bc..58d09d2b614a8f24f7802cdd4369ac85556380a9 100644 --- a/.jcheck/conf +++ b/.jcheck/conf @@ -1,6 +1,7 @@ [general] project=jdk jbs=JDK +version=19 [checks] error=author,committer,reviewers,merge,issues,executable,symlink,message,hg-tag,whitespace,problemlists diff --git a/doc/building.html b/doc/building.html index 1333a36771ab4c33577e093c6b289ff2848d51f6..66e07f07b9d7dfd77115a01fb6dd5e490a634f70 100644 --- a/doc/building.html +++ b/doc/building.html @@ -163,6 +163,8 @@

Building on aarch64

At a minimum, a machine with 8 cores is advisable, as well as 8 GB of RAM. (The more cores to use, the more memory you need.) At least 6 GB of free disk space is required.

If you do not have access to sufficiently powerful hardware, it is also possible to use cross-compiling.

+

Branch Protection

+

In order to use Branch Protection features in the VM, --enable-branch-protection must be used. This option requires C++ compiler support (GCC 9.1.0+ or Clang 10+). The resulting build can be run on both machines with and without support for branch protection in hardware. Branch Protection is only supported for Linux targets.

Building on 32-bit arm

This is not recommended. Instead, see the section on Cross-compiling.

Operating System Requirements

@@ -196,7 +198,7 @@

Windows

Windows XP is not a supported platform, but all newer Windows should be able to build the JDK.

On Windows, it is important that you pay attention to the instructions in the Special Considerations.

-

Windows is the only non-POSIX OS supported by the JDK, and as such, requires some extra care. A POSIX support layer is required to build on Windows. Currently, the only supported such layers are Cygwin and Windows Subsystem for Linux (WSL). (Msys is no longer supported due to a too old bash; msys2 would likely be possible to support in a future version but that would require effort to implement.)

+

Windows is the only non-POSIX OS supported by the JDK, and as such, requires some extra care. A POSIX support layer is required to build on Windows. Currently, the only supported such layers are Cygwin, Windows Subsystem for Linux (WSL), and MSYS2. (MSYS is no longer supported due to an outdated bash; While OpenJDK can be built with MSYS2, support for it is still experimental, so build failures and unusual errors are not uncommon.)

Internally in the build system, all paths are represented as Unix-style paths, e.g. /cygdrive/c/git/jdk/Makefile rather than C:\git\jdk\Makefile. This rule also applies to input to the build system, e.g. in arguments to configure. So, use --with-msvcr-dll=/cygdrive/c/msvcr100.dll rather than --with-msvcr-dll=c:\msvcr100.dll. For details on this conversion, see the section on Fixpath.

Cygwin

A functioning Cygwin environment is required for building the JDK on Windows. If you have a 64-bit OS, we strongly recommend using the 64-bit version of Cygwin.

@@ -214,7 +216,7 @@

Unfortunately, Cygwin can be unreliable in certain circumstances. If you experience build tool crashes or strange issues when building on Windows, please check the Cygwin FAQ on the "BLODA" list and the section on fork() failures.

Windows Subsystem for Linux (WSL)

Windows 10 1809 or newer is supported due to a dependency on the wslpath utility and support for environment variable sharing through WSLENV. Version 1803 can work but intermittent build failures have been observed.

-

It's possible to build both Windows and Linux binaries from WSL. To build Windows binaries, you must use a Windows boot JDK (located in a Windows-accessible directory). To build Linux binaries, you must use a Linux boot JDK. The default behavior is to build for Windows. To build for Linux, pass --build=x86_64-unknown-linux-gnu --host=x86_64-unknown-linux-gnu to configure.

+

It's possible to build both Windows and Linux binaries from WSL. To build Windows binaries, you must use a Windows boot JDK (located in a Windows-accessible directory). To build Linux binaries, you must use a Linux boot JDK. The default behavior is to build for Windows. To build for Linux, pass --build=x86_64-unknown-linux-gnu --openjdk-target=x86_64-unknown-linux-gnu to configure.

If building Windows binaries, the source code must be located in a Windows- accessible directory. This is because Windows executables (such as Visual Studio and the boot JDK) must be able to access the source code. Also, the drive where the source is stored must be mounted as case-insensitive by changing either /etc/fstab or /etc/wsl.conf in WSL. Individual directories may be corrected using the fsutil tool in case the source was cloned before changing the mount options.

Note that while it's possible to build on WSL, testing is still not fully supported.

macOS

@@ -271,7 +273,7 @@ Linux -gcc 10.2.0 +gcc 11.2.0 macOS @@ -286,7 +288,7 @@

All compilers are expected to be able to compile to the C99 language standard, as some C99 features are used in the source code. Microsoft Visual Studio doesn't fully support C99 so in practice shared code is limited to using C99 features that it does support.

gcc

The minimum accepted version of gcc is 5.0. Older versions will generate a warning by configure and are unlikely to work.

-

The JDK is currently known to be able to compile with at least version 10.2 of gcc.

+

The JDK is currently known to be able to compile with at least version 11.2 of gcc.

In general, any version between these two should be usable.

clang

The minimum accepted version of clang is 3.5. Older versions will not be accepted by configure.

@@ -298,7 +300,7 @@

It is advisable to keep an older version of Xcode for building the JDK when updating Xcode. This blog page has good suggestions on managing multiple Xcode versions. To use a specific version of Xcode, use xcode-select -s before running configure, or use --with-toolchain-path to point to the version of Xcode to use, e.g. configure --with-toolchain-path=/Applications/Xcode8.app/Contents/Developer/usr/bin

If you have recently (inadvertently) updated your OS and/or Xcode version, and the JDK can no longer be built, please see the section on Problems with the Build Environment, and Getting Help to find out if there are any recent, non-merged patches available for this update.

Microsoft Visual Studio

-

The minimum accepted version of Visual Studio is 2017. Older versions will not be accepted by configure and will not work. The maximum accepted version of Visual Studio is 2019.

+

For aarch64 machines running Windows the minimum accepted version is Visual Studio 2019 (16.8 or higher). For all other platforms the minimum accepted version of Visual Studio is 2017. Older versions will not be accepted by configure and will not work. For all platforms the maximum accepted version of Visual Studio is 2022.

If you have multiple versions of Visual Studio installed, configure will by default pick the latest. You can request a specific version to be used by setting --with-toolchain-version, e.g. --with-toolchain-version=2017.

If you have Visual Studio installed but configure fails to detect it, it may be because of spaces in path.

IBM XL C/C++

@@ -568,7 +570,8 @@ x86_64-linux-gnu-to-ppc64le-linux-gnu

To be able to build, we need a "Build JDK", which is a JDK built from the current sources (that is, the same as the end result of the entire build process), but able to run on the build system, and not the target system. (In contrast, the Boot JDK should be from an older release, e.g. JDK 8 when building JDK 9.)

The build process will create a minimal Build JDK for you, as part of building. To speed up the build, you can use --with-build-jdk to configure to point to a pre-built Build JDK. Please note that the build result is unpredictable, and can possibly break in subtle ways, if the Build JDK does not exactly match the current sources.

Specifying the Target Platform

-

You must specify the target platform when cross-compiling. Doing so will also automatically turn the build into a cross-compiling mode. The simplest way to do this is to use the --openjdk-target argument, e.g. --openjdk-target=arm-linux-gnueabihf. or --openjdk-target=aarch64-oe-linux. This will automatically set the --build, --host and --target options for autoconf, which can otherwise be confusing. (In autoconf terminology, the "target" is known as "host", and "target" is used for building a Canadian cross-compiler.)

+

You must specify the target platform when cross-compiling. Doing so will also automatically turn the build into a cross-compiling mode. The simplest way to do this is to use the --openjdk-target argument, e.g. --openjdk-target=arm-linux-gnueabihf. or --openjdk-target=aarch64-oe-linux. This will automatically set the --host and --target options for autoconf, which can otherwise be confusing. (In autoconf terminology, the "target" is known as "host", and "target" is used for building a Canadian cross-compiler.)

+

If --build has not been explicitly passed to configure, --openjdk-target will autodetect the build platform and internally set the flag automatically, otherwise the platform that was explicitly passed to --build will be used instead.

Toolchain Considerations

You will need two copies of your toolchain, one which generates output that can run on the target system (the normal, or target, toolchain), and one that generates output that can run on the build system (the build toolchain). Note that cross-compiling is only supported for gcc at the time being. The gcc standard is to prefix cross-compiling toolchains with the target denominator. If you follow this standard, configure is likely to pick up the toolchain correctly.

The build toolchain will be autodetected just the same way the normal build/target toolchain will be autodetected when not cross-compiling. If this is not what you want, or if the autodetection fails, you can specify a devkit containing the build toolchain using --with-build-devkit to configure, or by giving BUILD_CC and BUILD_CXX arguments.

@@ -887,30 +890,28 @@ spawn failed

If you need general help or advice about developing for the JDK, you can also contact the Adoption Group. See the section on Contributing to OpenJDK for more information.

Reproducible Builds

Build reproducibility is the property of getting exactly the same bits out when building, every time, independent on who builds the product, or where. This is for many reasons a harder goal than it initially appears, but it is an important goal, for security reasons and others. Please see Reproducible Builds for more information about the background and reasons for reproducible builds.

-

Currently, it is not possible to build OpenJDK fully reproducibly, but getting there is an ongoing effort. There are some things you can do to minimize non-determinism and make a larger part of the build reproducible:

+

Currently, it is not possible to build OpenJDK fully reproducibly, but getting there is an ongoing effort.

+

An absolute prerequisite for building reproducible is to speficy a fixed build time, since time stamps are embedded in many file formats. This is done by setting the SOURCE_DATE_EPOCH environment variable, which is an industry standard, that many tools, such as gcc, recognize, and use in place of the current time when generating output.

+

To generate reproducible builds, you must set SOURCE_DATE_EPOCH before running configure. The value in SOURCE_DATE_EPOCH will be stored in the configuration, and used by make. Setting SOURCE_DATE_EPOCH before running make will have no effect on the build.

+

You must also make sure your build does not rely on configure's default adhoc version strings. Default adhoc version strings OPT segment include user name and source directory. You can either override just the OPT segment using --with-version-opt=<any fixed string>, or you can specify the entire version string using --with-version-string=<your version>.

+

This is a typical example of how to build the JDK in a reproducible way:

+
export SOURCE_DATE_EPOCH=946684800
+bash configure --with-version-opt=adhoc
+make
+

Note that regardless if you specify a source date for configure or not, the JDK build system will set SOURCE_DATE_EPOCH for all build tools when building. If --with-source-date has the value updated (which is the default unless SOURCE_DATE_EPOCH is found by in the environment by configure), the source date value will be determined at build time.

+

There are several aspects of reproducible builds that can be individually adjusted by configure arguments. If any of these are given, they will override the value derived from SOURCE_DATE_EPOCH. These arguments are:

-

Add the flag --enable-reproducible-builds to your configure command line. This will turn on support for reproducible builds where it could otherwise be lacking.

- -

Default adhoc version strings OPT segment include user name, source directory and timestamp. You can either override just the OPT segment using --with-version-opt=<any fixed string>, or you can specify the entire version string using --with-version-string=<your version>.

- -

The JDK build system will set the SOURCE_DATE_EPOCH environment variable during building, depending on the value of the --with-source-date option for configure. The default value is updated, which means that SOURCE_DATE_EPOCH will be set to the current time each time you are running make.

-

The SOURCE_DATE_EPOCH environment variable is an industry standard, that many tools, such as gcc, recognize, and use in place of the current time when generating output.

-

For reproducible builds, you need to set this to a fixed value. You can use the special value version which will use the nominal release date for the current JDK version, or a value describing a date, either an epoch based timestamp as an integer, or a valid ISO-8601 date.

-

Hint: If your build environment already sets SOURCE_DATE_EPOCH, you can propagate this using --with-source-date=$SOURCE_DATE_EPOCH.

- -

Set a fixed hotspot build time. This will be included in the hotspot library (libjvm.so or jvm.dll) and defaults to the current time when building hotspot. Use --with-hotspot-build-time=<any fixed string> for reproducible builds. It's a string so you don't need to format it specifically, so e.g. n/a will do. Another solution is to use the SOURCE_DATE_EPOCH variable, e.g. --with-hotspot-build-time=$(date --date=@$SOURCE_DATE_EPOCH).

- -

The copyright year in some generated text files are normally set to the current year. This can be overridden by --with-copyright-year=<year>. For fully reproducible builds, this needs to be set to a fixed value.

Hints and Suggestions for Advanced Users

Bash Completion

The configure and make commands tries to play nice with bash command-line completion (using <tab> or <tab><tab>). To use this functionality, make sure you enable completion in your ~/.bashrc (see instructions for bash in your operating system).

diff --git a/doc/building.md b/doc/building.md index ac694ef84049b35238eb9494e54911cd55c302ae..6bc5857811e763b10fe423b82f7cf9eb4c2b7868 100644 --- a/doc/building.md +++ b/doc/building.md @@ -135,6 +135,14 @@ space is required. If you do not have access to sufficiently powerful hardware, it is also possible to use [cross-compiling](#cross-compiling). +#### Branch Protection + +In order to use Branch Protection features in the VM, `--enable-branch-protection` +must be used. This option requires C++ compiler support (GCC 9.1.0+ or Clang +10+). The resulting build can be run on both machines with and without support +for branch protection in hardware. Branch Protection is only supported for +Linux targets. + ### Building on 32-bit arm This is not recommended. Instead, see the section on [Cross-compiling]( @@ -179,10 +187,10 @@ On Windows, it is important that you pay attention to the instructions in the Windows is the only non-POSIX OS supported by the JDK, and as such, requires some extra care. A POSIX support layer is required to build on Windows. -Currently, the only supported such layers are Cygwin and Windows Subsystem for -Linux (WSL). (Msys is no longer supported due to a too old bash; msys2 would -likely be possible to support in a future version but that would require effort -to implement.) +Currently, the only supported such layers are Cygwin, Windows Subsystem for +Linux (WSL), and MSYS2. (MSYS is no longer supported due to an outdated bash; +While OpenJDK can be built with MSYS2, support for it is still experimental, so +build failures and unusual errors are not uncommon.) Internally in the build system, all paths are represented as Unix-style paths, e.g. `/cygdrive/c/git/jdk/Makefile` rather than `C:\git\jdk\Makefile`. This @@ -236,8 +244,8 @@ It's possible to build both Windows and Linux binaries from WSL. To build Windows binaries, you must use a Windows boot JDK (located in a Windows-accessible directory). To build Linux binaries, you must use a Linux boot JDK. The default behavior is to build for Windows. To build for Linux, pass -`--build=x86_64-unknown-linux-gnu --host=x86_64-unknown-linux-gnu` to -`configure`. +`--build=x86_64-unknown-linux-gnu --openjdk-target=x86_64-unknown-linux-gnu` +to `configure`. If building Windows binaries, the source code must be located in a Windows- accessible directory. This is because Windows executables (such as Visual Studio @@ -321,7 +329,7 @@ issues. Operating system Toolchain version ------------------ ------------------------------------------------------- - Linux gcc 10.2.0 + Linux gcc 11.2.0 macOS Apple Xcode 10.1 (using clang 10.0.0) Windows Microsoft Visual Studio 2019 update 16.7.2 @@ -335,7 +343,7 @@ features that it does support. The minimum accepted version of gcc is 5.0. Older versions will generate a warning by `configure` and are unlikely to work. -The JDK is currently known to be able to compile with at least version 10.2 of +The JDK is currently known to be able to compile with at least version 11.2 of gcc. In general, any version between these two should be usable. @@ -374,9 +382,10 @@ available for this update. ### Microsoft Visual Studio -The minimum accepted version of Visual Studio is 2017. Older versions will not -be accepted by `configure` and will not work. The maximum accepted -version of Visual Studio is 2019. +For aarch64 machines running Windows the minimum accepted version is Visual Studio 2019 +(16.8 or higher). For all other platforms the minimum accepted version of +Visual Studio is 2017. Older versions will not be accepted by `configure` and will +not work. For all platforms the maximum accepted version of Visual Studio is 2022. If you have multiple versions of Visual Studio installed, `configure` will by default pick the latest. You can request a specific version to be used by @@ -977,11 +986,16 @@ You *must* specify the target platform when cross-compiling. Doing so will also automatically turn the build into a cross-compiling mode. The simplest way to do this is to use the `--openjdk-target` argument, e.g. `--openjdk-target=arm-linux-gnueabihf`. or `--openjdk-target=aarch64-oe-linux`. -This will automatically set the `--build`, `--host` and `--target` options for +This will automatically set the `--host` and `--target` options for autoconf, which can otherwise be confusing. (In autoconf terminology, the "target" is known as "host", and "target" is used for building a Canadian cross-compiler.) +If `--build` has not been explicitly passed to configure, `--openjdk-target` +will autodetect the build platform and internally set the flag automatically, +otherwise the platform that was explicitly passed to `--build` will be used +instead. + ### Toolchain Considerations You will need two copies of your toolchain, one which generates output that can @@ -1513,57 +1527,85 @@ https://reproducible-builds.org) for more information about the background and reasons for reproducible builds. Currently, it is not possible to build OpenJDK fully reproducibly, but getting -there is an ongoing effort. There are some things you can do to minimize -non-determinism and make a larger part of the build reproducible: +there is an ongoing effort. + +An absolute prerequisite for building reproducible is to speficy a fixed build +time, since time stamps are embedded in many file formats. This is done by +setting the `SOURCE_DATE_EPOCH` environment variable, which is an [industry +standard]( https://reproducible-builds.org/docs/source-date-epoch/), that many +tools, such as gcc, recognize, and use in place of the current time when +generating output. + +To generate reproducible builds, you must set `SOURCE_DATE_EPOCH` before running +`configure`. The value in `SOURCE_DATE_EPOCH` will be stored in the +configuration, and used by `make`. Setting `SOURCE_DATE_EPOCH` before running +`make` will have no effect on the build. + +You must also make sure your build does not rely on `configure`'s default adhoc +version strings. Default adhoc version strings `OPT` segment include user name +and source directory. You can either override just the `OPT` segment using +`--with-version-opt=`, or you can specify the entire version +string using `--with-version-string=`. - * Turn on build system support for reproducible builds +This is a typical example of how to build the JDK in a reproducible way: -Add the flag `--enable-reproducible-builds` to your `configure` command line. -This will turn on support for reproducible builds where it could otherwise be -lacking. +``` +export SOURCE_DATE_EPOCH=946684800 +bash configure --with-version-opt=adhoc +make +``` - * Do not rely on `configure`'s default adhoc version strings +Note that regardless if you specify a source date for `configure` or not, the +JDK build system will set `SOURCE_DATE_EPOCH` for all build tools when building. +If `--with-source-date` has the value `updated` (which is the default unless +`SOURCE_DATE_EPOCH` is found by in the environment by `configure`), the source +date value will be determined at build time. -Default adhoc version strings OPT segment include user name, source directory -and timestamp. You can either override just the OPT segment using -`--with-version-opt=`, or you can specify the entire version -string using `--with-version-string=`. +There are several aspects of reproducible builds that can be individually +adjusted by `configure` arguments. If any of these are given, they will override +the value derived from `SOURCE_DATE_EPOCH`. These arguments are: - * Specify how the build sets `SOURCE_DATE_EPOCH` + * `--with-source-date` -The JDK build system will set the `SOURCE_DATE_EPOCH` environment variable -during building, depending on the value of the `--with-source-date` option for -`configure`. The default value is `updated`, which means that -`SOURCE_DATE_EPOCH` will be set to the current time each time you are running -`make`. + This option controls how the JDK build sets `SOURCE_DATE_EPOCH` when + building. It can be set to a value describing a date, either an epoch based + timestamp as an integer, or a valid ISO-8601 date. -The [`SOURCE_DATE_EPOCH` environment variable]( -https://reproducible-builds.org/docs/source-date-epoch/) is an industry -standard, that many tools, such as gcc, recognize, and use in place of the -current time when generating output. + It can also be set to one of the special values `current`, `updated` or + `version`. `current` means that the time of running `configure` will be + used. `version` will use the nominal release date for the current JDK + version. `updated`, which means that `SOURCE_DATE_EPOCH` will be set to the + current time each time you are running `make`. All choices, except for + `updated`, will set a fixed value for the source date timestamp. -For reproducible builds, you need to set this to a fixed value. You can use the -special value `version` which will use the nominal release date for the current -JDK version, or a value describing a date, either an epoch based timestamp as an -integer, or a valid ISO-8601 date. + When `SOURCE_DATE_EPOCH` is set, the default value for `--with-source-date` + will be the value given by `SOURCE_DATE_EPOCH`. Otherwise, the default value + is `updated`. -**Hint:** If your build environment already sets `SOURCE_DATE_EPOCH`, you can -propagate this using `--with-source-date=$SOURCE_DATE_EPOCH`. + * `--with-hotspot-build-time` + + This option controls the build time string that will be included in the + hotspot library (`libjvm.so` or `jvm.dll`). When the source date is fixed + (e.g. by setting `SOURCE_DATE_EPOCH`), the default value for + `--with-hotspot-build-time` will be an ISO 8601 representation of that time + stamp. Otherwise the default value will be the current time when building + hotspot. - * Specify a hotspot build time + * `--with-copyright-year` -Set a fixed hotspot build time. This will be included in the hotspot library -(`libjvm.so` or `jvm.dll`) and defaults to the current time when building -hotspot. Use `--with-hotspot-build-time=` for reproducible -builds. It's a string so you don't need to format it specifically, so e.g. `n/a` -will do. Another solution is to use the `SOURCE_DATE_EPOCH` variable, e.g. -`--with-hotspot-build-time=$(date --date=@$SOURCE_DATE_EPOCH)`. + This option controls the copyright year in some generated text files. When + the source date is fixed (e.g. by setting `SOURCE_DATE_EPOCH`), the default + value for `--with-copyright-year` will be the year of that time stamp. + Otherwise the default is the current year at the time of running configure. + This can be overridden by `--with-copyright-year=`. - * Copyright year + * `--enable-reproducible-build` -The copyright year in some generated text files are normally set to the current -year. This can be overridden by `--with-copyright-year=`. For fully -reproducible builds, this needs to be set to a fixed value. + This option controls some additional behavior needed to make the build + reproducible. When the source date is fixed (e.g. by setting + `SOURCE_DATE_EPOCH`), this flag will be turned on by default. Otherwise, the + value is determined by heuristics. If it is explicitly turned off, the build + might not be reproducible. ## Hints and Suggestions for Advanced Users diff --git a/doc/hotspot-style.html b/doc/hotspot-style.html index fe72cbbdf80c1cca160571c8e4b9cd51e122c9f1..c93b941c9885fbfc640175f2cfeb82f711cce3cc 100644 --- a/doc/hotspot-style.html +++ b/doc/hotspot-style.html @@ -67,7 +67,9 @@

Counterexamples and Updates

Many of the guidelines mentioned here have (sometimes widespread) counterexamples in the HotSpot code base. Finding a counterexample is not sufficient justification for new code to follow the counterexample as a precedent, since readers of your code will rightfully expect your code to follow the greater bulk of precedents documented here.

Occasionally a guideline mentioned here may be just out of synch with the actual HotSpot code base. If you find that a guideline is consistently contradicted by a large number of counterexamples, please bring it up for discussion and possible change. The architectural rule, of course, is "When in Rome do as the Romans". Sometimes in the suburbs of Rome the rules are a little different; these differences can be pointed out here.

-

Proposed changes should be discussed on the HotSpot Developers mailing list, and approved by rough consensus of the HotSpot Group Members. The Group Lead determines whether consensus has been reached. Changes are likely to be cautious and incremental, since HotSpot coders have been using these guidelines for years.

+

Proposed changes should be discussed on the HotSpot Developers mailing list. Changes are likely to be cautious and incremental, since HotSpot coders have been using these guidelines for years.

+

Substantive changes are approved by rough consensus of the HotSpot Group Members. The Group Lead determines whether consensus has been reached.

+

Editorial changes (changes that only affect the description of HotSpot style, not its substance) do not require the full consensus gathering process. The normal HotSpot pull request process may be used for editorial changes, with the additional requirement that the requisite reviewers are also HotSpot Group Members.

Structure and Formatting

Factoring and Class Design

    @@ -151,7 +153,7 @@

    Whitespace

    • In general, don't change whitespace unless it improves readability or consistency. Gratuitous whitespace changes will make integrations and backports more difficult.

    • -
    • Use One-True-Brace-Style. The opening brace for a function or class is normally at the end of the line; it is sometimes moved to the beginning of the next line for emphasis. Substatements are enclosed in braces, even if there is only a single statement. Extremely simple one-line statements may drop braces around a substatement.

    • +
    • Use One-True-Brace-Style. The opening brace for a function or class is normally at the end of the line; it is sometimes moved to the beginning of the next line for emphasis. Substatements are enclosed in braces, even if there is only a single statement. Extremely simple one-line statements may drop braces around a substatement.

    • Indentation levels are two columns.

    • There is no hard line length limit. That said, bear in mind that excessively long lines can cause difficulties. Some people like to have multiple side-by-side windows in their editors, and long lines may force them to choose among unpleasant options. They can use wide windows, reducing the number that can fit across the screen, and wasting a lot of screen real estate because most lines are not that long. Alternatively, they can have more windows across the screen, with long lines wrapping (or worse, requiring scrolling to see in their entirety), which is harder to read. Similar issues exist for side-by-side code reviews.

    • Tabs are not allowed in code. Set your editor accordingly.
      (Emacs: (setq-default indent-tabs-mode nil).)

    • @@ -195,7 +197,7 @@ while ( test_foo(args...) ) { // No, excess spaces around controlSimilar discussions for some other projects:

      @@ -208,7 +210,7 @@ while ( test_foo(args...) ) { // No, excess spaces around controlRationale: Other than to implement exceptions (which HotSpot doesn't use), most potential uses of RTTI are better done via virtual functions. Some of the remainder can be replaced by bespoke mechanisms. The cost of the additional runtime data structures needed to support RTTI are deemed not worthwhile, given the alternatives.

      Memory Allocation

      Do not use the standard global allocation and deallocation functions (operator new and related functions). Use of these functions by HotSpot code is disabled for some platforms.

      -

      Rationale: HotSpot often uses "resource" or "arena" allocation. Even where heap allocation is used, the standard global functions are avoided in favor of wrappers around malloc and free that support the VM's Native Memory Tracking (NMT) feature.

      +

      Rationale: HotSpot often uses "resource" or "arena" allocation. Even where heap allocation is used, the standard global functions are avoided in favor of wrappers around malloc and free that support the VM's Native Memory Tracking (NMT) feature. Typically, uses of the global operator new are inadvertent and therefore often associated with memory leaks.

      Native memory allocation failures are often treated as non-recoverable. The place where "out of memory" is (first) detected may be an innocent bystander, unrelated to the actual culprit.

      Class Inheritance

      Use public single inheritance.

      @@ -268,8 +270,8 @@ while ( test_foo(args...) ) { // No, excess spaces around controlThe underlying type of a scoped-enum should also be specified explicitly if conversions may be applied to values of that type.

      Due to bugs in certain (very old) compilers, there is widespread use of enums and avoidance of in-class initialization of static integral constant members. Compilers having such bugs are no longer supported. Except where an enum is semantically appropriate, new code should use integral constants.

      thread_local

      -

      Do not use thread_local (n2659); instead, use the HotSpot macro THREAD_LOCAL. The initializer must be a constant expression.

      -

      As was discussed in the review for JDK-8230877, thread_local allows dynamic initialization and destruction semantics. However, that support requires a run-time penalty for references to non-function-local thread_local variables defined in a different translation unit, even if they don't need dynamic initialization. Dynamic initialization and destruction of namespace-scoped thread local variables also has the same ordering problems as for ordinary namespace-scoped variables.

      +

      Avoid use of thread_local (n2659); and instead, use the HotSpot macro THREAD_LOCAL, for which the initializer must be a constant expression. When thread_local must be used, use the Hotspot macro APPROVED_CPP_THREAD_LOCAL to indicate that the use has been given appropriate consideration.

      +

      As was discussed in the review for JDK-8230877, thread_local allows dynamic initialization and destruction semantics. However, that support requires a run-time penalty for references to non-function-local thread_local variables defined in a different translation unit, even if they don't need dynamic initialization. Dynamic initialization and destruction of non-local thread_local variables also has the same ordering problems as for ordinary non-local variables. So we avoid use of thread_local in general, limiting its use to only those cases where dynamic initialization or destruction are essential. See JDK-8282469 for further discussion.

      nullptr

      Prefer nullptr (n2431) to NULL. Don't use (constexpr or literal) 0 for pointers.

      For historical reasons there are widespread uses of both NULL and of integer 0 as a pointer value.

      @@ -436,7 +438,7 @@ while ( test_foo(args...) ) { // No, excess spaces around control

      Inline namespaces (n2535) — HotSpot makes very limited use of namespaces.

    • using namespace directives. In particular, don't use using namespace std; to avoid needing to qualify Standard Library names.

    • Propagating exceptions (n2179) — HotSpot does not permit the use of exceptions, so this feature isn't useful.

    • -
    • Avoid namespace-scoped variables with non-constexpr initialization. In particular, avoid variables with types requiring non-trivial initialization or destruction. Initialization order problems can be difficult to deal with and lead to surprises, as can destruction ordering. HotSpot doesn't generally try to cleanup on exit, and running destructors at exit can also lead to problems.

    • +
    • Avoid non-local variables with non-constexpr initialization. In particular, avoid variables with types requiring non-trivial initialization or destruction. Initialization order problems can be difficult to deal with and lead to surprises, as can destruction ordering. HotSpot doesn't generally try to cleanup on exit, and running destructors at exit can also lead to problems.

    • [[deprecated]] attribute (n3760) — Not relevant in HotSpot code.

    • Avoid most operator overloading, preferring named functions. When operator overloading is used, ensure the semantics conform to the normal expected behavior of the operation.

    • Avoid most implicit conversion constructors and (implicit or explicit) conversion operators. (Note that conversion to bool isn't needed in HotSpot code because of the "no implicit boolean" guideline.)

    • diff --git a/doc/hotspot-style.md b/doc/hotspot-style.md index 6d167cad9d6c20a2c7e6713aca40994de6da9a3f..89d9684672db0ea1960f789e3aa39bc40ccb4bee 100644 --- a/doc/hotspot-style.md +++ b/doc/hotspot-style.md @@ -56,12 +56,19 @@ can be pointed out here. Proposed changes should be discussed on the [HotSpot Developers](mailto:hotspot-dev@openjdk.java.net) mailing -list, and approved by -[rough consensus](https://en.wikipedia.org/wiki/Rough_consensus) of +list. Changes are likely to be cautious and incremental, since HotSpot +coders have been using these guidelines for years. + +Substantive changes are approved by +[rough consensus](https://www.rfc-editor.org/rfc/rfc7282.html) of the [HotSpot Group](https://openjdk.java.net/census#hotspot) Members. The Group Lead determines whether consensus has been reached. -Changes are likely to be cautious and incremental, since HotSpot -coders have been using these guidelines for years. + +Editorial changes (changes that only affect the description of HotSpot +style, not its substance) do not require the full consensus gathering +process. The normal HotSpot pull request process may be used for +editorial changes, with the additional requirement that the requisite +reviewers are also HotSpot Group Members. ## Structure and Formatting @@ -287,7 +294,9 @@ well. or consistency. Gratuitous whitespace changes will make integrations and backports more difficult. -* Use One-True-Brace-Style. The opening brace for a function or class +* Use [One-True-Brace-Style]( +https://en.wikipedia.org/wiki/Indentation_style#Variant:_1TBS_(OTBS)). +The opening brace for a function or class is normally at the end of the line; it is sometimes moved to the beginning of the next line for emphasis. Substatements are enclosed in braces, even if there is only a single statement. Extremely simple @@ -409,7 +418,7 @@ Similar discussions for some other projects: * [Google C++ Style Guide](https://google.github.io/styleguide/cppguide.html) — Currently (2020) targeting C++17. -* [C++11 and C++14 use in Chromium](https://chromium.googlesource.com/chromium/src/+/main/styleguide/c++/c++11.md) — +* [C++11 and C++14 use in Chromium](https://chromium.googlesource.com/chromium/src/+/main/styleguide/c++/c++-features.md) — Categorizes features as allowed, banned, or to be discussed. * [llvm Coding Standards](https://llvm.org/docs/CodingStandards.html) — @@ -462,7 +471,9 @@ code is disabled for some platforms. Rationale: HotSpot often uses "resource" or "arena" allocation. Even where heap allocation is used, the standard global functions are avoided in favor of wrappers around malloc and free that support the -VM's Native Memory Tracking (NMT) feature. +VM's Native Memory Tracking (NMT) feature. Typically, uses of the global +operator new are inadvertent and therefore often associated with memory +leaks. Native memory allocation failures are often treated as non-recoverable. The place where "out of memory" is (first) detected may be an innocent @@ -622,7 +633,7 @@ Here are a few closely related example bugs:
      ### enum Where appropriate, _scoped-enums_ should be used. -([n2347](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2347.pdf)) +([n2347](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2347.pdf)) Use of _unscoped-enums_ is permitted, though ordinary constants may be preferable when the automatic initializer feature isn't used. @@ -642,10 +653,12 @@ integral constants. ### thread_local -Do not use `thread_local` +Avoid use of `thread_local` ([n2659](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2659.htm)); -instead, use the HotSpot macro `THREAD_LOCAL`. The initializer must -be a constant expression. +and instead, use the HotSpot macro `THREAD_LOCAL`, for which the initializer must +be a constant expression. When `thread_local` must be used, use the Hotspot macro +`APPROVED_CPP_THREAD_LOCAL` to indicate that the use has been given appropriate +consideration. As was discussed in the review for [JDK-8230877](https://mail.openjdk.java.net/pipermail/hotspot-dev/2019-September/039487.html), @@ -654,14 +667,18 @@ semantics. However, that support requires a run-time penalty for references to non-function-local `thread_local` variables defined in a different translation unit, even if they don't need dynamic initialization. Dynamic initialization and destruction of -namespace-scoped thread local variables also has the same ordering -problems as for ordinary namespace-scoped variables. +non-local `thread_local` variables also has the same ordering +problems as for ordinary non-local variables. So we avoid use of +`thread_local` in general, limiting its use to only those cases where dynamic +initialization or destruction are essential. See +[JDK-8282469](https://bugs.openjdk.java.net/browse/JDK-8282469) +for further discussion. ### nullptr Prefer `nullptr` ([n2431](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2431.pdf)) -to `NULL`. Don't use (constexpr or literal) 0 for pointers. +to `NULL`. Don't use (constexpr or literal) 0 for pointers. For historical reasons there are widespread uses of both `NULL` and of integer 0 as a pointer value. @@ -930,7 +947,7 @@ References: * Generalized lambda capture (init-capture) ([N3648]) * Generic (polymorphic) lambda expressions ([N3649]) -[n2657]: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2657.htm +[n2657]: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2657.htm [n2927]: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2927.pdf [N3648]: https://isocpp.org/files/papers/N3648.html [N3649]: https://isocpp.org/files/papers/N3649.html @@ -971,7 +988,7 @@ References from C++23 ### Additional Permitted Features * `constexpr` -([n2235](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2235.pdf)) +([n2235](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2235.pdf)) ([n3652](https://isocpp.org/files/papers/N3652.html)) * Sized deallocation @@ -1057,7 +1074,7 @@ namespace std;` to avoid needing to qualify Standard Library names. ([n2179](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2179.html)) — HotSpot does not permit the use of exceptions, so this feature isn't useful. -* Avoid namespace-scoped variables with non-constexpr initialization. +* Avoid non-local variables with non-constexpr initialization. In particular, avoid variables with types requiring non-trivial initialization or destruction. Initialization order problems can be difficult to deal with and lead to surprises, as can destruction @@ -1078,14 +1095,14 @@ in HotSpot code because of the "no implicit boolean" guideline.) * Avoid covariant return types. -* Avoid `goto` statements. +* Avoid `goto` statements. ### Undecided Features This list is incomplete; it serves to explicitly call out some features that have not yet been discussed. -* Trailing return type syntax for functions +* Trailing return type syntax for functions ([n2541](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2541.htm)) * Variable templates @@ -1099,7 +1116,7 @@ features that have not yet been discussed. * Rvalue references and move semantics -[ADL]: https://en.cppreference.com/w/cpp/language/adl +[ADL]: https://en.cppreference.com/w/cpp/language/adl "Argument Dependent Lookup" [ODR]: https://en.cppreference.com/w/cpp/language/definition diff --git a/doc/ide.html b/doc/ide.html index 1730eb0bef5b5bb1e6d18aed43b61ee4155a5aaa..288a477e538f80f3c3f7c01cfcafa2e32b18b627 100644 --- a/doc/ide.html +++ b/doc/ide.html @@ -41,14 +41,20 @@
      make vscode-project-clangd

      Additional instructions for configuring the given indexer will be displayed after the workspace has been generated.

      Visual Studio

      -

      This section is a work in progress.

      -
      make ide-project
      +

      The make system can generate a Visual Studio project for the Hotspot native source. After configuring, the project is generated using:

      +
      make hotspot-ide-project
      +

      This creates a file named jvm.vcxproj in ide\hotspot-visualstudio subfolder of the build output folder. The file can be opened in Visual Studio via File -> Open -> Project/Solution.

      Compilation Database

      The make system can generate generic native code indexing support in the form of a Compilation Database that can be used by many different IDEs and source code indexers.

      make compile-commands

      It's also possible to generate the Compilation Database for the HotSpot source code only, which is a bit faster as it includes less information.

      make compile-commands-hotspot

      IDE support for Java code

      -

      This section is a work in progress.

      +

      IntelliJ IDEA

      +

      The JDK project has a script that can be used for indexing the project with IntelliJ. After configuring and building the JDK, an IntelliJ workspace can be generated by running the following command in the top-level folder of the cloned repository:

      +
      bash bin/idea.sh
      +

      To use it, choose File -> Open... in IntelliJ and select the folder where you ran the above script.

      +

      Next, configure the project SDK in IntelliJ. Open File -> Project Structure -> Project and select build/<config>/images/jdk as the SDK to use.

      +

      In order to run the tests from the IDE, you can use the JTReg plugin. Instructions for building and using the plugin can be found here.

      diff --git a/doc/ide.md b/doc/ide.md index 4a692efd22f03f9dd6f14eec95387002598c4d19..f0a419c948ba98683f00d43c890f07375a2debf9 100644 --- a/doc/ide.md +++ b/doc/ide.md @@ -45,12 +45,17 @@ after the workspace has been generated. #### Visual Studio -This section is a work in progress. +The make system can generate a Visual Studio project for the Hotspot +native source. After configuring, the project is generated using: ```shell -make ide-project +make hotspot-ide-project ``` +This creates a file named `jvm.vcxproj` in `ide\hotspot-visualstudio` +subfolder of the build output folder. The file can be opened in Visual Studio +via `File -> Open -> Project/Solution`. + #### Compilation Database The make system can generate generic native code indexing support in the form of @@ -70,4 +75,24 @@ make compile-commands-hotspot ### IDE support for Java code -This section is a work in progress. \ No newline at end of file +#### IntelliJ IDEA + +The JDK project has a script that can be used for indexing the project +with IntelliJ. After configuring and building the JDK, an IntelliJ workspace +can be generated by running the following command in the top-level folder +of the cloned repository: + +```shell +bash bin/idea.sh +``` + +To use it, choose `File -> Open...` in IntelliJ and select the folder where +you ran the above script. + +Next, configure the project SDK in IntelliJ. Open +`File -> Project Structure -> Project` and select `build//images/jdk` +as the SDK to use. + +In order to run the tests from the IDE, you can use the JTReg plugin. +Instructions for building and using the plugin can be found +[here](https://github.com/openjdk/jtreg/tree/master/plugins/idea). diff --git a/doc/testing.html b/doc/testing.html index 1146400df805f5d5cc84536ea96b8b484c7dcf09..213e23664c37c9afadfd3be808e8d5388a9d9a57 100644 --- a/doc/testing.html +++ b/doc/testing.html @@ -193,7 +193,9 @@ TEST FAILURE

      AOT_MODULES

      Generate AOT modules before testing for the specified module, or set of modules. If multiple modules are specified, they should be separated by space (or, to help avoid quoting issues, the special value %20).

      RETRY_COUNT

      -

      Retry failed tests up to a set number of times. Defaults to 0.

      +

      Retry failed tests up to a set number of times, until they pass. This allows to pass the tests with intermittent failures. Defaults to 0.

      +

      REPEAT_COUNT

      +

      Repeat the tests up to a set number of times, stopping at first failure. This helps to reproduce intermittent test failures. Defaults to 0.

      Gtest keywords

      REPEAT

      The number of times to repeat the tests (--gtest_repeat).

      diff --git a/doc/testing.md b/doc/testing.md index 5dde4d11804d67a4450c7c2a1beb9227ccb8a221..3ab7079ea07f7a681354cafea7a593a67dbe0e06 100644 --- a/doc/testing.md +++ b/doc/testing.md @@ -419,7 +419,15 @@ modules. If multiple modules are specified, they should be separated by space #### RETRY_COUNT -Retry failed tests up to a set number of times. Defaults to 0. +Retry failed tests up to a set number of times, until they pass. +This allows to pass the tests with intermittent failures. +Defaults to 0. + +#### REPEAT_COUNT + +Repeat the tests up to a set number of times, stopping at first failure. +This helps to reproduce intermittent test failures. +Defaults to 0. ### Gtest keywords diff --git a/make/CompileInterimLangtools.gmk b/make/CompileInterimLangtools.gmk index a6a42f6a9cd3c72e9b66c443d45ee27571bcde80..3fff64db1f81a4c26fe4988f58f2e0bf6acfc421 100644 --- a/make/CompileInterimLangtools.gmk +++ b/make/CompileInterimLangtools.gmk @@ -71,7 +71,7 @@ define SetupInterimModule SRC := $(BUILDTOOLS_OUTPUTDIR)/gensrc/$1.interim \ $$(wildcard $(SUPPORT_OUTPUTDIR)/gensrc/$1) \ $(TOPDIR)/src/$1/share/classes, \ - EXCLUDES := sun, \ + EXCLUDES := sun javax/tools/snippet-files, \ EXCLUDE_FILES := $(TOPDIR)/src/$1/share/classes/module-info.java \ Standard.java, \ EXTRA_FILES := $(BUILDTOOLS_OUTPUTDIR)/gensrc/$1.interim/module-info.java, \ diff --git a/make/CreateJmods.gmk b/make/CreateJmods.gmk index d9e5f415fe787c5d0b7721464f15a339b6d15ead..ec1e377bc078428fcb0544715cb1cbde27474e0e 100644 --- a/make/CreateJmods.gmk +++ b/make/CreateJmods.gmk @@ -226,6 +226,13 @@ else JMOD_FLAGS += --exclude '**{_the.*,_*.marker*,*.diz,*.debuginfo,*.dSYM/**,*.dSYM}' endif +# For reproducible builds specify the jmod --date using SOURCE_DATE in ISO-8601 +ifeq ($(ENABLE_REPRODUCIBLE_BUILD), true) + JMOD_SOURCE_DATE := --date $(SOURCE_DATE_ISO_8601) +else + JMOD_SOURCE_DATE := +endif + # Create jmods in the support dir and then move them into place to keep the # module path in $(IMAGES_OUTPUTDIR)/jmods valid at all times. $(eval $(call SetupExecute, create_$(JMOD_FILE), \ @@ -237,6 +244,7 @@ $(eval $(call SetupExecute, create_$(JMOD_FILE), \ COMMAND := $(JMOD) create --module-version $(VERSION_SHORT) \ --target-platform '$(OPENJDK_MODULE_TARGET_PLATFORM)' \ --module-path $(JMODS_DIR) $(JMOD_FLAGS) \ + $(JMOD_SOURCE_DATE) \ $(JMODS_SUPPORT_DIR)/$(JMOD_FILE), \ POST_COMMAND := $(MV) $(JMODS_SUPPORT_DIR)/$(JMOD_FILE) $(JMODS_DIR)/$(JMOD_FILE), \ )) diff --git a/make/Docs.gmk b/make/Docs.gmk index ef1651eaf4ee0aa8014aac1c25d8f7d210335e82..6ea5c7fb638565192b832ab33725211d43439c71 100644 --- a/make/Docs.gmk +++ b/make/Docs.gmk @@ -131,7 +131,7 @@ JAVA_PLATFORM := Java Platform ifeq ($(IS_DRAFT), true) DRAFT_MARKER_STR :=
      DRAFT $(VERSION_STRING) - ifeq ($(VERSION_BUILD), 0) + ifeq ($(VERSION_BUILD), ) DRAFT_MARKER_TITLE := $(SPACE)[ad-hoc build] else DRAFT_MARKER_TITLE := $(SPACE)[build $(VERSION_BUILD)] diff --git a/make/Hsdis.gmk b/make/Hsdis.gmk index 02f09b320f095522d29e0e7d7e73438a10f2ee72..ec06a89aaab1f3c714a9213cefc9790b4d07fdd1 100644 --- a/make/Hsdis.gmk +++ b/make/Hsdis.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. +# 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 @@ -35,107 +35,165 @@ include JdkNativeCompilation.gmk ################################################################################ HSDIS_OUTPUT_DIR := $(SUPPORT_OUTPUTDIR)/hsdis +REAL_HSDIS_NAME := hsdis-$(OPENJDK_TARGET_CPU_LEGACY_LIB)$(SHARED_LIBRARY_SUFFIX) +BUILT_HSDIS_LIB := $(HSDIS_OUTPUT_DIR)/$(REAL_HSDIS_NAME) + +HSDIS_TOOLCHAIN := TOOLCHAIN_DEFAULT +HSDIS_TOOLCHAIN_CFLAGS := $(CFLAGS_JDKLIB) +HSDIS_TOOLCHAIN_LDFLAGS := $(LDFLAGS_JDKLIB) + +ifeq ($(HSDIS_BACKEND), capstone) + ifeq ($(call isTargetCpuArch, x86), true) + CAPSTONE_ARCH := CS_ARCH_X86 + CAPSTONE_MODE := CS_MODE_$(OPENJDK_TARGET_CPU_BITS) + else ifeq ($(call isTargetCpuArch, aarch64), true) + CAPSTONE_ARCH := CS_ARCH_ARM64 + CAPSTONE_MODE := CS_MODE_ARM + else + $(error No support for Capstone on this platform) + endif -ifeq ($(call isTargetOs, windows), true) - INSTALLED_HSDIS_DIR := $(JDK_OUTPUTDIR)/bin + HSDIS_CFLAGS += -DCAPSTONE_ARCH=$(CAPSTONE_ARCH) \ + -DCAPSTONE_MODE=$(CAPSTONE_MODE) +endif - # On windows, we need to "fake" a completely different toolchain using gcc - # instead of the normal microsoft toolchain. This is quite hacky... +ifeq ($(HSDIS_BACKEND), llvm) + # Use C++ instead of C + HSDIS_TOOLCHAIN_CFLAGS := $(CXXFLAGS_JDKLIB) + HSDIS_TOOLCHAIN := TOOLCHAIN_LINK_CXX + + ifeq ($(call isTargetOs, linux), true) + LLVM_OS := pc-linux-gnu + else ifeq ($(call isTargetOs, macosx), true) + LLVM_OS := apple-darwin + else ifeq ($(call isTargetOs, windows), true) + LLVM_OS := pc-windows-msvc + else + $(error No support for LLVM on this platform) + endif - MINGW_BASE := x86_64-w64-mingw32 + HSDIS_CFLAGS += -DLLVM_DEFAULT_TRIPLET='"$(OPENJDK_TARGET_CPU)-$(LLVM_OS)"' +endif - MINGW_SYSROOT = $(shell $(MINGW_BASE)-gcc -print-sysroot) - ifeq ($(wildcard $(MINGW_SYSROOT)), ) - # Use fallback path - MINGW_SYSROOT := /usr/$(MINGW_BASE) +ifeq ($(HSDIS_BACKEND), binutils) + ifeq ($(call isTargetOs, windows), true) + # On windows, we need to "fake" a completely different toolchain using gcc + # instead of the normal microsoft toolchain. This is quite hacky... + + MINGW_BASE := x86_64-w64-mingw32 + + MINGW_SYSROOT = $(shell $(MINGW_BASE)-gcc -print-sysroot) ifeq ($(wildcard $(MINGW_SYSROOT)), ) - $(error mingw sysroot not found) + # Use fallback path + MINGW_SYSROOT := /usr/$(MINGW_BASE) + ifeq ($(wildcard $(MINGW_SYSROOT)), ) + $(error mingw sysroot not found) + endif endif - endif - $(eval $(call DefineNativeToolchain, TOOLCHAIN_MINGW, \ - CC := $(MINGW_BASE)-gcc, \ - LD := $(MINGW_BASE)-ld, \ - OBJCOPY := $(MINGW_BASE)-objcopy, \ - RC := $(RC), \ - SYSROOT_CFLAGS := --sysroot=$(MINGW_SYSROOT), \ - SYSROOT_LDFLAGS := --sysroot=$(MINGW_SYSROOT), \ - )) - - MINGW_SYSROOT_LIB_PATH := $(MINGW_SYSROOT)/mingw/lib - ifeq ($(wildcard $(MINGW_SYSROOT_LIB_PATH)), ) - # Try without mingw - MINGW_SYSROOT_LIB_PATH := $(MINGW_SYSROOT)/lib + $(eval $(call DefineNativeToolchain, TOOLCHAIN_MINGW, \ + CC := $(MINGW_BASE)-gcc, \ + LD := $(MINGW_BASE)-ld, \ + OBJCOPY := $(MINGW_BASE)-objcopy, \ + RC := $(RC), \ + SYSROOT_CFLAGS := --sysroot=$(MINGW_SYSROOT), \ + SYSROOT_LDFLAGS := --sysroot=$(MINGW_SYSROOT), \ + )) + + MINGW_SYSROOT_LIB_PATH := $(MINGW_SYSROOT)/mingw/lib ifeq ($(wildcard $(MINGW_SYSROOT_LIB_PATH)), ) - $(error mingw sysroot lib path not found) + # Try without mingw + MINGW_SYSROOT_LIB_PATH := $(MINGW_SYSROOT)/lib + ifeq ($(wildcard $(MINGW_SYSROOT_LIB_PATH)), ) + $(error mingw sysroot lib path not found) + endif endif - endif - MINGW_VERSION = $(shell $(MINGW_BASE)-gcc -v 2>&1 | $(GREP) "gcc version" | $(CUT) -d " " -f 3) - MINGW_GCC_LIB_PATH := /usr/lib/gcc/$(MINGW_BASE)/$(MINGW_VERSION) - ifeq ($(wildcard $(MINGW_GCC_LIB_PATH)), ) - # Try using only major version number - MINGW_VERSION_MAJOR := $(firstword $(subst ., , $(MINGW_VERSION))) - MINGW_GCC_LIB_PATH := /usr/lib/gcc/$(MINGW_BASE)/$(MINGW_VERSION_MAJOR) + MINGW_VERSION = $(shell $(MINGW_BASE)-gcc -v 2>&1 | $(GREP) "gcc version" | $(CUT) -d " " -f 3) + MINGW_GCC_LIB_PATH := /usr/lib/gcc/$(MINGW_BASE)/$(MINGW_VERSION) ifeq ($(wildcard $(MINGW_GCC_LIB_PATH)), ) - $(error mingw gcc lib path not found) + # Try using only major version number + MINGW_VERSION_MAJOR := $(firstword $(subst ., , $(MINGW_VERSION))) + MINGW_GCC_LIB_PATH := /usr/lib/gcc/$(MINGW_BASE)/$(MINGW_VERSION_MAJOR) + ifeq ($(wildcard $(MINGW_GCC_LIB_PATH)), ) + $(error mingw gcc lib path not found) + endif endif - endif - TOOLCHAIN_TYPE := gcc - OPENJDK_TARGET_OS := linux - CC_OUT_OPTION := -o$(SPACE) - LD_OUT_OPTION := -o$(SPACE) - GENDEPS_FLAGS := -MMD -MF - CFLAGS_DEBUG_SYMBOLS := -g - DISABLED_WARNINGS := - DISABLE_WARNING_PREFIX := -Wno- - CFLAGS_WARNINGS_ARE_ERRORS := -Werror - SHARED_LIBRARY_FLAGS := -shared - - HSDIS_TOOLCHAIN := TOOLCHAIN_MINGW - HSDIS_TOOLCHAIN_CFLAGS := - HSDIS_TOOLCHAIN_LDFLAGS := -L$(MINGW_GCC_LIB_PATH) -L$(MINGW_SYSROOT_LIB_PATH) - MINGW_DLLCRT := $(MINGW_SYSROOT_LIB_PATH)/dllcrt2.o - HSDIS_TOOLCHAIN_LIBS := $(MINGW_DLLCRT) -lmingw32 -lgcc -lgcc_eh -lmoldname \ - -lmingwex -lmsvcrt -lpthread -ladvapi32 -lshell32 -luser32 -lkernel32 -else - INSTALLED_HSDIS_DIR := $(JDK_OUTPUTDIR)/lib - - HSDIS_TOOLCHAIN := TOOLCHAIN_DEFAULT - HSDIS_TOOLCHAIN_CFLAGS := $(CFLAGS_JDKLIB) - HSDIS_TOOLCHAIN_LDFLAGS := $(LDFLAGS_JDKLIB) - HSDIS_TOOLCHAIN_LIBS := -ldl + TOOLCHAIN_TYPE := gcc + OPENJDK_TARGET_OS := linux + CC_OUT_OPTION := -o$(SPACE) + LD_OUT_OPTION := -o$(SPACE) + GENDEPS_FLAGS := -MMD -MF + CFLAGS_DEBUG_SYMBOLS := -g + DISABLED_WARNINGS := + DISABLE_WARNING_PREFIX := -Wno- + CFLAGS_WARNINGS_ARE_ERRORS := -Werror + SHARED_LIBRARY_FLAGS := -shared + + HSDIS_TOOLCHAIN := TOOLCHAIN_MINGW + HSDIS_TOOLCHAIN_CFLAGS := + HSDIS_TOOLCHAIN_LDFLAGS := -L$(MINGW_GCC_LIB_PATH) -L$(MINGW_SYSROOT_LIB_PATH) + MINGW_DLLCRT := $(MINGW_SYSROOT_LIB_PATH)/dllcrt2.o + HSDIS_TOOLCHAIN_LIBS := $(MINGW_DLLCRT) -lmingw32 -lgcc -lgcc_eh -lmoldname \ + -lmingwex -lmsvcrt -lpthread -ladvapi32 -lshell32 -luser32 -lkernel32 + else + HSDIS_TOOLCHAIN_LIBS := -ldl + endif endif - $(eval $(call SetupJdkLibrary, BUILD_HSDIS, \ NAME := hsdis, \ - SRC := $(TOPDIR)/src/utils/hsdis, \ + SRC := $(TOPDIR)/src/utils/hsdis/$(HSDIS_BACKEND), \ + EXTRA_HEADER_DIRS := $(TOPDIR)/src/utils/hsdis, \ TOOLCHAIN := $(HSDIS_TOOLCHAIN), \ OUTPUT_DIR := $(HSDIS_OUTPUT_DIR), \ OBJECT_DIR := $(HSDIS_OUTPUT_DIR), \ DISABLED_WARNINGS_gcc := undef format-nonliteral sign-compare, \ DISABLED_WARNINGS_clang := undef format-nonliteral, \ CFLAGS := $(HSDIS_TOOLCHAIN_CFLAGS) $(HSDIS_CFLAGS), \ - LDFLAGS := $(HSDIS_TOOLCHAIN_LDFLAGS) $(SHARED_LIBRARY_FLAGS), \ + LDFLAGS := $(HSDIS_TOOLCHAIN_LDFLAGS) $(HSDIS_LDFLAGS) $(SHARED_LIBRARY_FLAGS), \ LIBS := $(HSDIS_LIBS) $(HSDIS_TOOLCHAIN_LIBS), \ )) -build: $(BUILD_HSDIS) +$(BUILT_HSDIS_LIB): $(BUILD_HSDIS_TARGET) + $(install-file) + +build: $(BUILD_HSDIS) $(BUILT_HSDIS_LIB) TARGETS += build -INSTALLED_HSDIS_NAME := hsdis-$(OPENJDK_TARGET_CPU_LEGACY_LIB)$(SHARED_LIBRARY_SUFFIX) +ifeq ($(ENABLE_HSDIS_BUNDLING), false) + + ifeq ($(call isTargetOs, windows), true) + JDK_HSDIS_DIR := $(JDK_OUTPUTDIR)/bin + IMAGE_HSDIS_DIR := $(JDK_IMAGE_DIR)/bin + else + JDK_HSDIS_DIR := $(JDK_OUTPUTDIR)/lib + IMAGE_HSDIS_DIR := $(JDK_IMAGE_DIR)/lib + endif + -INSTALLED_HSDIS := $(INSTALLED_HSDIS_DIR)/$(INSTALLED_HSDIS_NAME) + INSTALLED_HSDIS_JDK := $(JDK_HSDIS_DIR)/$(REAL_HSDIS_NAME) + INSTALLED_HSDIS_IMAGE := $(IMAGE_HSDIS_DIR)/$(REAL_HSDIS_NAME) -$(INSTALLED_HSDIS): $(BUILD_HSDIS_TARGET) - $(call LogWarn, NOTE: The resulting build might not be redistributable. Seek legal advice before distibuting.) + $(INSTALLED_HSDIS_JDK): $(BUILT_HSDIS_LIB) + ifeq ($(HSDIS_BACKEND), binutils) + $(call LogWarn, NOTE: The resulting build might not be redistributable. Seek legal advice before distributing.) + endif $(install-file) + $(INSTALLED_HSDIS_IMAGE): $(BUILT_HSDIS_LIB) + $(install-file) + + install: $(INSTALLED_HSDIS_JDK) $(INSTALLED_HSDIS_IMAGE) + +else + + install: + $(ECHO) NOTE: make install-hsdis is a no-op with --enable-hsdis-bundling -install: $(INSTALLED_HSDIS) +endif TARGETS += install diff --git a/make/InitSupport.gmk b/make/InitSupport.gmk index 8ee2e9098babc0e49c06cf8e6584344e5a2ba0bf..62fdc438c8a68e2e6c09717ab8d7472368bdb2e0 100644 --- a/make/InitSupport.gmk +++ b/make/InitSupport.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 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 @@ -310,9 +310,17 @@ else # $(HAS_SPEC)=true # level of reproducible builds define SetupReproducibleBuild ifeq ($$(SOURCE_DATE), updated) - SOURCE_DATE := $$(shell $$(DATE) +"%s") + # For static values of SOURCE_DATE (not "updated"), these are set in spec.gmk + export SOURCE_DATE_EPOCH := $$(shell $$(DATE) +"%s") + ifeq ($$(IS_GNU_DATE), yes) + export SOURCE_DATE_ISO_8601 := $$(shell $$(DATE) --utc \ + --date="@$$(SOURCE_DATE_EPOCH)" +"$$(ISO_8601_FORMAT_STRING)" \ + 2> /dev/null) + else + export SOURCE_DATE_ISO_8601 := $$(shell $$(DATE) -u -j -f "%s" \ + "$$(SOURCE_DATE_EPOCH)" +"$$(ISO_8601_FORMAT_STRING)" 2> /dev/null) + endif endif - export SOURCE_DATE_EPOCH := $$(SOURCE_DATE) endef # Parse COMPARE_BUILD into COMPARE_BUILD_* diff --git a/make/Main.gmk b/make/Main.gmk index 75eee65ba84afddd1f787ddbac7d13c2fd205fd8..26e470f9c40a2e8bbb620e0cf963fa73bd196f13 100644 --- a/make/Main.gmk +++ b/make/Main.gmk @@ -324,7 +324,7 @@ $(eval $(call SetupTarget, vscode-project-ccls, \ # aren't built until after libjava and libjvm are available to link to. $(eval $(call SetupTarget, demos-jdk, \ MAKEFILE := CompileDemos, \ - DEPS := java.base-libs exploded-image, \ + DEPS := java.base-libs exploded-image buildtools-jdk, \ )) $(eval $(call SetupTarget, test-image-demos-jdk, \ @@ -383,12 +383,12 @@ bootcycle-images: $(eval $(call SetupTarget, zip-security, \ MAKEFILE := ZipSecurity, \ - DEPS := java.base-java java.security.jgss-java java.security.jgss-libs, \ + DEPS := buildtools-jdk java.base-java java.security.jgss-java java.security.jgss-libs, \ )) $(eval $(call SetupTarget, zip-source, \ MAKEFILE := ZipSource, \ - DEPS := gensrc, \ + DEPS := buildtools-jdk gensrc, \ )) $(eval $(call SetupTarget, jrtfs-jar, \ @@ -508,13 +508,13 @@ $(eval $(call SetupTarget, docs-jdk-index, \ $(eval $(call SetupTarget, docs-zip, \ MAKEFILE := Docs, \ TARGET := docs-zip, \ - DEPS := docs-jdk, \ + DEPS := docs-jdk buildtools-jdk, \ )) $(eval $(call SetupTarget, docs-specs-zip, \ MAKEFILE := Docs, \ TARGET := docs-specs-zip, \ - DEPS := docs-jdk-specs, \ + DEPS := docs-jdk-specs buildtools-jdk, \ )) $(eval $(call SetupTarget, update-build-docs, \ @@ -535,6 +535,7 @@ ifneq ($(HSDIS_BACKEND), none) $(eval $(call SetupTarget, install-hsdis, \ MAKEFILE := Hsdis, \ TARGET := install, \ + DEPS := jdk-image, \ )) endif @@ -861,6 +862,10 @@ else $(foreach t, $(filter-out java.base-libs, $(LIBS_TARGETS)), \ $(eval $t: java.base-libs)) + ifeq ($(ENABLE_HSDIS_BUNDLING), true) + java.base-copy: build-hsdis + endif + # jdk.accessibility depends on java.desktop jdk.accessibility-libs: java.desktop-libs diff --git a/make/ModuleWrapper.gmk b/make/ModuleWrapper.gmk index e4a8db24aa3c988a7c2885f97140de61be9f3ab7..d83af819a9bc46d053e71cfdac2311b46ea97531 100644 --- a/make/ModuleWrapper.gmk +++ b/make/ModuleWrapper.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2014, 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 @@ -35,6 +35,8 @@ default: all include $(SPEC) include MakeBase.gmk +MODULE_SRC := $(TOPDIR)/src/$(MODULE) + # All makefiles should add the targets to be built to this variable. TARGETS := diff --git a/make/RunTests.gmk b/make/RunTests.gmk index a2c8ea8101eac3fbdca236ec0a3f087acae94cc0..81540266ec0c68d8fd3f416dcc5a5fe9480cbf28 100644 --- a/make/RunTests.gmk +++ b/make/RunTests.gmk @@ -200,7 +200,7 @@ $(eval $(call SetTestOpt,FAILURE_HANDLER_TIMEOUT,JTREG)) $(eval $(call ParseKeywordVariable, JTREG, \ SINGLE_KEYWORDS := JOBS TIMEOUT_FACTOR FAILURE_HANDLER_TIMEOUT \ TEST_MODE ASSERT VERBOSE RETAIN MAX_MEM RUN_PROBLEM_LISTS \ - RETRY_COUNT MAX_OUTPUT $(CUSTOM_JTREG_SINGLE_KEYWORDS), \ + RETRY_COUNT REPEAT_COUNT MAX_OUTPUT $(CUSTOM_JTREG_SINGLE_KEYWORDS), \ STRING_KEYWORDS := OPTIONS JAVA_OPTIONS VM_OPTIONS KEYWORDS \ EXTRA_PROBLEM_LISTS LAUNCHER_OPTIONS \ $(CUSTOM_JTREG_STRING_KEYWORDS), \ @@ -745,6 +745,15 @@ define SetupRunJtregTestBody JTREG_RETAIN ?= fail,error JTREG_RUN_PROBLEM_LISTS ?= false JTREG_RETRY_COUNT ?= 0 + JTREG_REPEAT_COUNT ?= 0 + + ifneq ($$(JTREG_RETRY_COUNT), 0) + ifneq ($$(JTREG_REPEAT_COUNT), 0) + $$(info Error: Cannot use both JTREG_RETRY_COUNT and JTREG_REPEAT_COUNT together.) + $$(info Please choose one or the other.) + $$(error Cannot continue) + endif + endif ifneq ($$(JTREG_LAUNCHER_OPTIONS), ) $1_JTREG_LAUNCHER_OPTIONS += $$(JTREG_LAUNCHER_OPTIONS) @@ -869,6 +878,18 @@ define SetupRunJtregTestBody done endif + ifneq ($$(JTREG_REPEAT_COUNT), 0) + $1_COMMAND_LINE := \ + for i in {1..$$(JTREG_REPEAT_COUNT)}; do \ + $$(PRINTF) "\nRepeating Jtreg run: $$$$i out of $$(JTREG_REPEAT_COUNT)\n"; \ + $$($1_COMMAND_LINE); \ + if [ "`$$(CAT) $$($1_EXITCODE)`" != "0" ]; then \ + $$(PRINTF) "\nFailures detected, no more repeats.\n"; \ + break; \ + fi; \ + done + endif + run-test-$1: pre-run-test clean-workdir-$1 $$(call LogWarn) $$(call LogWarn, Running test '$$($1_TEST)') diff --git a/make/TestImage.gmk b/make/TestImage.gmk index 26d10f95d3bc00ae229a9321ce2c7ae04cc76733..b719d6824da3028ddfd78bb2e0e87f0c0dacfd72 100644 --- a/make/TestImage.gmk +++ b/make/TestImage.gmk @@ -35,8 +35,8 @@ BUILD_INFO_PROPERTIES := $(TEST_IMAGE_DIR)/build-info.properties $(BUILD_INFO_PROPERTIES): $(call MakeTargetDir) $(ECHO) "# Build info properties for JDK tests" > $@ - $(ECHO) "build.workspace.root=$(call FixPath, $(WORKSPACE_ROOT))" >> $@ - $(ECHO) "build.output.root=$(call FixPath, $(OUTPUTDIR))" >> $@ + $(ECHO) 'build.workspace.root=$(call FixPath, $(WORKSPACE_ROOT))' >> $@ + $(ECHO) 'build.output.root=$(call FixPath, $(OUTPUTDIR))' >> $@ README := $(TEST_IMAGE_DIR)/Readme.txt diff --git a/make/ToolsJdk.gmk b/make/ToolsJdk.gmk index 395a78602f626a83e7ecdd2fb45e980e6caf7119..9eef6969125a289dfa13760034f6e042bde304e4 100644 --- a/make/ToolsJdk.gmk +++ b/make/ToolsJdk.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 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 @@ -53,7 +53,7 @@ TOOL_GENERATECHARACTER = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_cla TOOL_CHARACTERNAME = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \ build.tools.generatecharacter.CharacterName -TOOL_DTDBUILDER = $(JAVA_SMALL) -Ddtd_home=$(TOPDIR)/make/data/dtdbuilder \ +TOOL_DTDBUILDER = $(JAVA_SMALL) -Ddtd_home=$(TOPDIR)/src/java.desktop/share/data/dtdbuilder \ -Djava.awt.headless=true \ -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes build.tools.dtdbuilder.DTDBuilder @@ -82,6 +82,8 @@ TOOL_GENERATECACERTS = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_class TOOL_GENERATEEMOJIDATA = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \ build.tools.generateemojidata.GenerateEmojiData +TOOL_MAKEZIPREPRODUCIBLE = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \ + build.tools.makezipreproducible.MakeZipReproducible # TODO: There are references to the jdwpgen.jar in jdk/make/netbeans/jdwpgen/build.xml # and nbproject/project.properties in the same dir. Needs to be looked at. diff --git a/make/UpdateX11Wrappers.gmk b/make/UpdateX11Wrappers.gmk index ad67966ec8a7b32f47bbb86d9016e7e70dc3bf0a..3201b5f883f7130d6b874a1fd99bb8038ffb9290 100644 --- a/make/UpdateX11Wrappers.gmk +++ b/make/UpdateX11Wrappers.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2012, 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 @@ -50,7 +50,7 @@ endif X11WRAPPERS_OUTPUT := $(SUPPORT_OUTPUTDIR)/x11wrappers GENERATOR_SOURCE_FILE := $(X11WRAPPERS_OUTPUT)/src/data_generator.c -GENSRC_X11WRAPPERS_DATADIR := $(TOPDIR)/make/data/x11wrappergen +GENSRC_X11WRAPPERS_DATADIR := $(TOPDIR)/src/java.desktop/unix/data/x11wrappergen WRAPPER_OUTPUT_FILE := $(GENSRC_X11WRAPPERS_DATADIR)/sizes-$(BITS).txt BITS := $(OPENJDK_TARGET_CPU_BITS) diff --git a/make/autoconf/basic.m4 b/make/autoconf/basic.m4 index 60b4097cba90e04cfb268a8367aab1acff26671a..65558e83c7209feefbce5914b468a897044c3137 100644 --- a/make/autoconf/basic.m4 +++ b/make/autoconf/basic.m4 @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 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 @@ -94,11 +94,6 @@ AC_DEFUN_ONCE([BASIC_SETUP_PATHS], # Locate the directory of this script. AUTOCONF_DIR=$TOPDIR/make/autoconf - - # Setup username (for use in adhoc version strings etc) - # Outer [ ] to quote m4. - [ USERNAME=`$ECHO "$USER" | $TR -d -c '[a-z][A-Z][0-9]'` ] - AC_SUBST(USERNAME) ]) ############################################################################### @@ -443,7 +438,9 @@ AC_DEFUN([BASIC_CHECK_DIR_ON_LOCAL_DISK], AC_DEFUN_ONCE([BASIC_CHECK_SRC_PERMS], [ if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then - file_to_test="$TOPDIR/LICENSE" + # The choice of file here is somewhat arbitrary, it just needs to be there + # in the source tree when configure runs + file_to_test="$TOPDIR/Makefile" if test `$STAT -c '%a' "$file_to_test"` -lt 400; then AC_MSG_ERROR([Bad file permissions on src files. This is usually caused by cloning the repositories with a non cygwin hg in a directory not created in cygwin.]) fi diff --git a/make/autoconf/basic_tools.m4 b/make/autoconf/basic_tools.m4 index 820d2f4924d9bdc80ec09185fd6b085e02228248..1611e9fd5312ee8ceb46f1a35cdaf926700daf70 100644 --- a/make/autoconf/basic_tools.m4 +++ b/make/autoconf/basic_tools.m4 @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 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 @@ -80,6 +80,7 @@ AC_DEFUN_ONCE([BASIC_SETUP_FUNDAMENTAL_TOOLS], # Optional tools, we can do without them UTIL_LOOKUP_PROGS(DF, df) + UTIL_LOOKUP_PROGS(GIT, git) UTIL_LOOKUP_PROGS(NICE, nice) UTIL_LOOKUP_PROGS(READLINK, greadlink readlink) @@ -339,7 +340,6 @@ AC_DEFUN_ONCE([BASIC_SETUP_COMPLEX_TOOLS], UTIL_LOOKUP_PROGS(READELF, greadelf readelf) UTIL_LOOKUP_PROGS(DOT, dot) UTIL_LOOKUP_PROGS(HG, hg) - UTIL_LOOKUP_PROGS(GIT, git) UTIL_LOOKUP_PROGS(STAT, stat) UTIL_LOOKUP_PROGS(TIME, time) UTIL_LOOKUP_PROGS(FLOCK, flock) @@ -356,6 +356,18 @@ AC_DEFUN_ONCE([BASIC_SETUP_COMPLEX_TOOLS], fi AC_SUBST(IS_GNU_TIME) + # Check if it's a GNU date compatible version + AC_MSG_CHECKING([if date is a GNU compatible version]) + check_date=`$DATE --version 2>&1 | $GREP "GNU\|BusyBox"` + if test "x$check_date" != x; then + AC_MSG_RESULT([yes]) + IS_GNU_DATE=yes + else + AC_MSG_RESULT([no]) + IS_GNU_DATE=no + fi + AC_SUBST(IS_GNU_DATE) + if test "x$OPENJDK_TARGET_OS" = "xmacosx"; then UTIL_REQUIRE_PROGS(DSYMUTIL, dsymutil) UTIL_REQUIRE_PROGS(MIG, mig) diff --git a/make/autoconf/basic_windows.m4 b/make/autoconf/basic_windows.m4 index a8686e45d8919ec59f6a374dcaee0ba11fc1b290..fb6fc526bfa219d361aae8783dfbc47c98d3bcc6 100644 --- a/make/autoconf/basic_windows.m4 +++ b/make/autoconf/basic_windows.m4 @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 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 @@ -34,9 +34,10 @@ AC_DEFUN([BASIC_SETUP_PATHS_WINDOWS], OPENJDK_BUILD_OS_ENV=windows.wsl1 else # This test is not guaranteed, but there is no documented way of - # distinguishing between WSL1 and WSL2. Assume only WSL2 has WSL_INTEROP - # in /run/WSL - if test -d "/run/WSL" ; then + # distinguishing between WSL1 and WSL2. + # Check whether "Hyper-V" appears in /proc/interrupts because WSL2 runs on Hyper-V. + $GREP -q Hyper-V /proc/interrupts + if test $? -eq 0; then OPENJDK_BUILD_OS_ENV=windows.wsl2 else OPENJDK_BUILD_OS_ENV=windows.wsl1 @@ -184,6 +185,16 @@ AC_DEFUN([BASIC_SETUP_PATHS_WINDOWS], AC_MSG_RESULT([unknown]) AC_MSG_WARN([It seems that your find utility is non-standard.]) fi + + if test "x$GIT" != x && test -e $TOPDIR/.git; then + git_autocrlf=`$GIT config core.autocrlf` + if test "x$git_autocrlf" != x && test "x$git_autocrlf" != "xfalse"; then + AC_MSG_NOTICE([Your git configuration does not set core.autocrlf to false.]) + AC_MSG_NOTICE([If you checked out this code using that setting, the build WILL fail.]) + AC_MSG_NOTICE([To correct, run "git config --global core.autocrlf false" and re-clone the repo.]) + AC_MSG_WARN([Code is potentially incorrectly cloned. HIGH RISK of build failure!]) + fi + fi ]) # Verify that the directory is usable on Windows diff --git a/make/autoconf/boot-jdk.m4 b/make/autoconf/boot-jdk.m4 index 9c0f9018bfcc10e4b47e96f17edf39edcc284dd6..7b82cdb2543ab918693bc7b6c4496432e537f71f 100644 --- a/make/autoconf/boot-jdk.m4 +++ b/make/autoconf/boot-jdk.m4 @@ -379,6 +379,16 @@ AC_DEFUN_ONCE([BOOTJDK_SETUP_BOOT_JDK], # Finally, set some other options... + # Determine if the boot jdk jar supports the --date option + if $JAR --help 2>&1 | $GREP -q "\-\-date=TIMESTAMP"; then + BOOT_JDK_JAR_SUPPORTS_DATE=true + else + BOOT_JDK_JAR_SUPPORTS_DATE=false + fi + AC_MSG_CHECKING([if Boot JDK jar supports --date=TIMESTAMP]) + AC_MSG_RESULT([$BOOT_JDK_JAR_SUPPORTS_DATE]) + AC_SUBST(BOOT_JDK_JAR_SUPPORTS_DATE) + # When compiling code to be executed by the Boot JDK, force compatibility with the # oldest supported bootjdk. OLDEST_BOOT_JDK=`$ECHO $DEFAULT_ACCEPTABLE_BOOT_VERSIONS \ diff --git a/make/autoconf/compare.sh.in b/make/autoconf/compare.sh.in index 1c48f800c8a3430cca9137c19ddb74815505b791..542a516ebc4475cc05d3be52c54e8aedece4b5d0 100644 --- a/make/autoconf/compare.sh.in +++ b/make/autoconf/compare.sh.in @@ -53,7 +53,7 @@ export LDD="@LDD@" export LN="@LN@" export MKDIR="@MKDIR@" export MV="@MV@" -export NM="@GNM@" +export NM="@NM@" export OBJDUMP="@OBJDUMP@" export OTOOL="@OTOOL@" export PRINTF="@PRINTF@" diff --git a/make/autoconf/configure b/make/autoconf/configure index 7e0ece129f4dfb2f9354c7406df590e199c01140..4b26e3d706147fdb04158f5dd3133f130d0c0246 100644 --- a/make/autoconf/configure +++ b/make/autoconf/configure @@ -274,11 +274,11 @@ do # Check for certain autoconf options that require extra action case $conf_option in -build | --build | --buil | --bui | --bu |-build=* | --build=* | --buil=* | --bui=* | --bu=*) - conf_legacy_crosscompile="$conf_legacy_crosscompile $conf_option" ;; + conf_build_set=true ;; -target | --target | --targe | --targ | --tar | --ta | --t | -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) - conf_legacy_crosscompile="$conf_legacy_crosscompile $conf_option" ;; + conf_incompatible_crosscompile="$conf_incompatible_crosscompile $conf_option" ;; -host | --host | --hos | --ho | -host=* | --host=* | --hos=* | --ho=*) - conf_legacy_crosscompile="$conf_legacy_crosscompile $conf_option" ;; + conf_incompatible_crosscompile="$conf_incompatible_crosscompile $conf_option" ;; -help | --help | --hel | --he | -h) conf_print_help=true ;; esac @@ -287,23 +287,30 @@ done # Save the quoted command line CONFIGURE_COMMAND_LINE="${conf_quoted_arguments[@]}" -if test "x$conf_legacy_crosscompile" != "x"; then +if test "x$conf_incompatible_crosscompile" != "x"; then if test "x$conf_openjdk_target" != "x"; then - echo "Error: Specifying --openjdk-target together with autoconf" - echo "legacy cross-compilation flags is not supported." - echo "You specified: --openjdk-target=$conf_openjdk_target and $conf_legacy_crosscompile." - echo "The recommended use is just --openjdk-target." + echo "Error: --openjdk-target was specified together with" + echo "incompatible autoconf cross-compilation flags." + echo "You specified: --openjdk-target=$conf_openjdk_target and $conf_incompatible_crosscompile." + echo "It is recommended that you only use --openjdk-target." exit 1 else - echo "Warning: You are using legacy autoconf cross-compilation flags." - echo "It is recommended that you use --openjdk-target instead." + echo "Warning: You are using misleading autoconf cross-compilation flag(s)." + echo "This is not encouraged as use of such flags during building can" + echo "quickly become confusing." + echo "It is highly recommended that you use --openjdk-target instead." echo "" fi fi if test "x$conf_openjdk_target" != "x"; then - conf_build_platform=`sh $conf_script_dir/build-aux/config.guess` - conf_processed_arguments=("--build=$conf_build_platform" "--host=$conf_openjdk_target" "--target=$conf_openjdk_target" "${conf_processed_arguments[@]}") + conf_processed_arguments=("--host=$conf_openjdk_target" "--target=$conf_openjdk_target" "${conf_processed_arguments[@]}") + + # If --build has been explicitly set don't override that flag with our own + if test "x$conf_build_set" != xtrue; then + conf_build_platform=`sh $conf_script_dir/build-aux/config.guess` + conf_processed_arguments=("--build=$conf_build_platform" "${conf_processed_arguments[@]}") + fi fi # Make configure exit with error on invalid options as default. @@ -341,7 +348,9 @@ Additional (non-autoconf) OpenJDK Options: --openjdk-target=TARGET cross-compile with TARGET as target platform (i.e. the one you will run the resulting binary on). Equivalent to --host=TARGET --target=TARGET - --build= + --build=, or the platform you + have provided if you have explicitly passed + --build to configure --debug-configure Run the configure script with additional debug logging enabled. diff --git a/make/autoconf/configure.ac b/make/autoconf/configure.ac index 29ed3f206aa46722b6b50bbb8d3ed047c764a214..5e58696e34d38a2742c1c75dbd39d9d9bb904189 100644 --- a/make/autoconf/configure.ac +++ b/make/autoconf/configure.ac @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 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 @@ -152,6 +152,7 @@ BOOTJDK_SETUP_DOCS_REFERENCE_JDK # ############################################################################### +JDKOPT_SETUP_REPRODUCIBLE_BUILD JDKOPT_SETUP_JDK_OPTIONS ############################################################################### @@ -207,7 +208,6 @@ PLATFORM_SETUP_OPENJDK_TARGET_BITS PLATFORM_SETUP_OPENJDK_TARGET_ENDIANNESS # Configure flags for the tools. Need to know if we should build reproducible. -JDKOPT_SETUP_REPRODUCIBLE_BUILD FLAGS_SETUP_FLAGS # Setup debug symbols (need objcopy from the toolchain for that) @@ -249,7 +249,6 @@ JDKOPT_EXCLUDE_TRANSLATIONS JDKOPT_ENABLE_DISABLE_MANPAGES JDKOPT_ENABLE_DISABLE_CDS_ARCHIVE JDKOPT_ENABLE_DISABLE_COMPATIBLE_CDS_ALIGNMENT -JDKOPT_SETUP_HSDIS ############################################################################### # diff --git a/make/autoconf/flags-cflags.m4 b/make/autoconf/flags-cflags.m4 index ba4cb3e9ac7314ef19cc399e13f7b42fd5f836bb..2d7732e6c66b668cfd90bc611c4a0d90bb868634 100644 --- a/make/autoconf/flags-cflags.m4 +++ b/make/autoconf/flags-cflags.m4 @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 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 @@ -496,8 +496,8 @@ AC_DEFUN([FLAGS_SETUP_CFLAGS_HELPER], TOOLCHAIN_CFLAGS_JVM="-qtbtable=full -qtune=balanced \ -qalias=noansi -qstrict -qtls=default -qnortti -qnoeh -qignerrno -qstackprotect" elif test "x$TOOLCHAIN_TYPE" = xmicrosoft; then - TOOLCHAIN_CFLAGS_JVM="-nologo -MD -MP" - TOOLCHAIN_CFLAGS_JDK="-nologo -MD -Zc:wchar_t-" + TOOLCHAIN_CFLAGS_JVM="-nologo -MD -Zc:strictStrings -MP" + TOOLCHAIN_CFLAGS_JDK="-nologo -MD -Zc:strictStrings -Zc:wchar_t-" fi # CFLAGS C language level for JDK sources (hotspot only uses C++) @@ -782,10 +782,8 @@ AC_DEFUN([FLAGS_SETUP_CFLAGS_CPU_DEP], test "x$ENABLE_REPRODUCIBLE_BUILD" = xtrue; then # There is a known issue with the pathmap if the mapping is made to the # empty string. Add a minimal string "s" as prefix to work around this. - workspace_root_win=`$FIXPATH_BASE print "${WORKSPACE_ROOT%/}"` # PATHMAP_FLAGS is also added to LDFLAGS in flags-ldflags.m4. - PATHMAP_FLAGS="-pathmap:${workspace_root_win//\//\\\\}=s \ - -pathmap:${workspace_root_win}=s" + PATHMAP_FLAGS="-pathmap:${WORKSPACE_ROOT}=s" FILE_MACRO_CFLAGS="$PATHMAP_FLAGS" FLAGS_COMPILER_CHECK_ARGUMENTS(ARGUMENT: [${FILE_MACRO_CFLAGS}], PREFIX: $3, @@ -805,17 +803,19 @@ AC_DEFUN([FLAGS_SETUP_CFLAGS_CPU_DEP], fi AC_SUBST(FILE_MACRO_CFLAGS) + FLAGS_SETUP_BRANCH_PROTECTION + # EXPORT to API CFLAGS_JVM_COMMON="$ALWAYS_CFLAGS_JVM $ALWAYS_DEFINES_JVM \ $TOOLCHAIN_CFLAGS_JVM ${$1_TOOLCHAIN_CFLAGS_JVM} \ $OS_CFLAGS $OS_CFLAGS_JVM $CFLAGS_OS_DEF_JVM $DEBUG_CFLAGS_JVM \ $WARNING_CFLAGS $WARNING_CFLAGS_JVM $JVM_PICFLAG $FILE_MACRO_CFLAGS \ - $REPRODUCIBLE_CFLAGS" + $REPRODUCIBLE_CFLAGS $BRANCH_PROTECTION_CFLAGS" CFLAGS_JDK_COMMON="$ALWAYS_CFLAGS_JDK $ALWAYS_DEFINES_JDK $TOOLCHAIN_CFLAGS_JDK \ $OS_CFLAGS $CFLAGS_OS_DEF_JDK $DEBUG_CFLAGS_JDK $DEBUG_OPTIONS_FLAGS_JDK \ $WARNING_CFLAGS $WARNING_CFLAGS_JDK $DEBUG_SYMBOLS_CFLAGS_JDK \ - $FILE_MACRO_CFLAGS $REPRODUCIBLE_CFLAGS" + $FILE_MACRO_CFLAGS $REPRODUCIBLE_CFLAGS $BRANCH_PROTECTION_CFLAGS" # Use ${$2EXTRA_CFLAGS} to block EXTRA_CFLAGS to be added to build flags. # (Currently we don't have any OPENJDK_BUILD_EXTRA_CFLAGS, but that might @@ -881,3 +881,24 @@ AC_DEFUN([FLAGS_SETUP_GCC6_COMPILER_FLAGS], PREFIX: $2, IF_FALSE: [NO_LIFETIME_DSE_CFLAG=""]) $1_GCC6_CFLAGS="${NO_DELETE_NULL_POINTER_CHECKS_CFLAG} ${NO_LIFETIME_DSE_CFLAG}" ]) + +AC_DEFUN_ONCE([FLAGS_SETUP_BRANCH_PROTECTION], +[ + # Is branch protection available? + BRANCH_PROTECTION_AVAILABLE=false + BRANCH_PROTECTION_FLAG="-mbranch-protection=standard" + + 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}], + 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, + DESC: [enable branch protection when compiling C/C++], + IF_ENABLED: [ BRANCH_PROTECTION_CFLAGS=${BRANCH_PROTECTION_FLAG}]) + AC_SUBST(BRANCH_PROTECTION_CFLAGS) +]) diff --git a/make/autoconf/flags-ldflags.m4 b/make/autoconf/flags-ldflags.m4 index e9d4557f8665ed879976b5ba04791ec106a54b13..457690ac39165621d505458530cf7c8741319e5a 100644 --- a/make/autoconf/flags-ldflags.m4 +++ b/make/autoconf/flags-ldflags.m4 @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 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 @@ -77,7 +77,7 @@ AC_DEFUN([FLAGS_SETUP_LDFLAGS_HELPER], -fPIC" elif test "x$TOOLCHAIN_TYPE" = xxlc; then - BASIC_LDFLAGS="-b64 -brtl -bnorwexec -bnolibpath -bexpall -bernotok -btextpsize:64K \ + BASIC_LDFLAGS="-b64 -brtl -bnorwexec -bnolibpath -bnoexpall -bernotok -btextpsize:64K \ -bdatapsize:64K -bstackpsize:64K" # libjvm.so has gotten too large for normal TOC size; compile with qpic=large and link with bigtoc BASIC_LDFLAGS_JVM_ONLY="-Wl,-lC_r -bbigtoc" @@ -95,13 +95,10 @@ AC_DEFUN([FLAGS_SETUP_LDFLAGS_HELPER], fi # Setup OS-dependent LDFLAGS - if test "x$TOOLCHAIN_TYPE" = xclang || test "x$TOOLCHAIN_TYPE" = xgcc; then - if test "x$OPENJDK_TARGET_OS" = xmacosx; then - # Assume clang or gcc. - # FIXME: We should really generalize SET_SHARED_LIBRARY_ORIGIN instead. - OS_LDFLAGS_JVM_ONLY="-Wl,-rpath,@loader_path/. -Wl,-rpath,@loader_path/.." - OS_LDFLAGS="-mmacosx-version-min=$MACOSX_VERSION_MIN" - fi + if test "x$OPENJDK_TARGET_OS" = xmacosx && test "x$TOOLCHAIN_TYPE" = xclang; then + # FIXME: We should really generalize SET_SHARED_LIBRARY_ORIGIN instead. + OS_LDFLAGS_JVM_ONLY="-Wl,-rpath,@loader_path/. -Wl,-rpath,@loader_path/.." + OS_LDFLAGS="-mmacosx-version-min=$MACOSX_VERSION_MIN" fi # Setup debug level-dependent LDFLAGS diff --git a/make/autoconf/flags.m4 b/make/autoconf/flags.m4 index 2171ca10ba238cea1e8a8610048348754513309d..0f05c9edac4052a0f1cb49e6ef5e11f958153544 100644 --- a/make/autoconf/flags.m4 +++ b/make/autoconf/flags.m4 @@ -215,8 +215,21 @@ AC_DEFUN([FLAGS_SETUP_SYSROOT_FLAGS], $1SYSROOT_CFLAGS="--sysroot=[$]$1SYSROOT" $1SYSROOT_LDFLAGS="--sysroot=[$]$1SYSROOT" elif test "x$TOOLCHAIN_TYPE" = xclang; then - $1SYSROOT_CFLAGS="-isysroot [$]$1SYSROOT" - $1SYSROOT_LDFLAGS="-isysroot [$]$1SYSROOT" + if test "x$OPENJDK_TARGET_OS" = "xlinux"; then + # -isysroot has no effect on linux + # https://bugs.llvm.org/show_bug.cgi?id=11503 + $1SYSROOT_CFLAGS="--sysroot=[$]$1SYSROOT" + $1SYSROOT_LDFLAGS="--sysroot=[$]$1SYSROOT" + if test -d "$DEVKIT_TOOLCHAIN_PATH"; then + # In devkits, gcc is not located in the sysroot. + # use --gcc-toolchain to let clang find the gcc installation. + $1SYSROOT_CFLAGS="[$]$1SYSROOT_CFLAGS --gcc-toolchain=$DEVKIT_TOOLCHAIN_PATH/.." + $1SYSROOT_LDFLAGS="[$]$1SYSROOT_LDFLAGS --gcc-toolchain=$DEVKIT_TOOLCHAIN_PATH/.." + fi + else + $1SYSROOT_CFLAGS="-isysroot [$]$1SYSROOT" + $1SYSROOT_LDFLAGS="-isysroot [$]$1SYSROOT" + fi fi fi diff --git a/make/autoconf/help.m4 b/make/autoconf/help.m4 index f36aa2819dfcc943e80509ec32113bf14eb7908a..3d6963c7d4d09553d115d335161a6aae76bb0894 100644 --- a/make/autoconf/help.m4 +++ b/make/autoconf/help.m4 @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 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 @@ -25,7 +25,7 @@ AC_DEFUN_ONCE([HELP_SETUP_DEPENDENCY_HELP], [ - UTIL_LOOKUP_PROGS(PKGHANDLER, zypper apt-get yum brew port pkgutil pkgadd pacman) + UTIL_LOOKUP_PROGS(PKGHANDLER, zypper apt-get yum brew port pkgutil pkgadd pacman apk) ]) AC_DEFUN([HELP_MSG_MISSING_DEPENDENCY], @@ -58,6 +58,8 @@ AC_DEFUN([HELP_MSG_MISSING_DEPENDENCY], zypper_help $MISSING_DEPENDENCY ;; *pacman) pacman_help $MISSING_DEPENDENCY ;; + *apk) + apk_help $MISSING_DEPENDENCY ;; esac if test "x$PKGHANDLER_COMMAND" != x; then @@ -115,6 +117,8 @@ apt_help() { PKGHANDLER_COMMAND="sudo apt-get install ccache" ;; dtrace) PKGHANDLER_COMMAND="sudo apt-get install systemtap-sdt-dev" ;; + capstone) + PKGHANDLER_COMMAND="sudo apt-get install libcapstone-dev" ;; esac } @@ -166,6 +170,8 @@ brew_help() { PKGHANDLER_COMMAND="brew install freetype" ;; ccache) PKGHANDLER_COMMAND="brew install ccache" ;; + capstone) + PKGHANDLER_COMMAND="brew install capstone" ;; esac } @@ -192,6 +198,27 @@ pkgadd_help() { PKGHANDLER_COMMAND="" } +apk_help() { + case $1 in + devkit) + PKGHANDLER_COMMAND="sudo apk add alpine-sdk linux-headers" ;; + alsa) + PKGHANDLER_COMMAND="sudo apk add alsa-lib-dev" ;; + cups) + PKGHANDLER_COMMAND="sudo apk add cups-dev" ;; + fontconfig) + PKGHANDLER_COMMAND="sudo apk add fontconfig-dev" ;; + freetype) + PKGHANDLER_COMMAND="sudo apk add freetype-dev" ;; + harfbuzz) + PKGHANDLER_COMMAND="sudo apk add harfbuzz-dev" ;; + x11) + PKGHANDLER_COMMAND="sudo apk add libxtst-dev libxt-dev libxrender-dev libxrandr-dev" ;; + ccache) + PKGHANDLER_COMMAND="sudo apk add ccache" ;; + esac +} + # This function will check if we're called from the "configure" wrapper while # printing --help. If so, we will print out additional information that can # only be extracted within the autoconf script, and then exit. This must be @@ -269,6 +296,13 @@ AC_DEFUN_ONCE([HELP_PRINT_SUMMARY_AND_WARNINGS], printf "* OpenJDK target: OS: $OPENJDK_TARGET_OS, CPU architecture: $OPENJDK_TARGET_CPU_ARCH, address length: $OPENJDK_TARGET_CPU_BITS\n" printf "* Version string: $VERSION_STRING ($VERSION_SHORT)\n" + if test "x$SOURCE_DATE" != xupdated; then + source_date_info="$SOURCE_DATE ($SOURCE_DATE_ISO_8601)" + else + source_date_info="Determined at build time" + fi + printf "* Source date: $source_date_info\n" + printf "\n" printf "Tools summary:\n" if test "x$OPENJDK_BUILD_OS" = "xwindows"; then diff --git a/make/autoconf/hotspot.m4 b/make/autoconf/hotspot.m4 index 1cac6bb00c666e814d2e8cfd557661d0327d1d06..18f46036fe5243f940e2f6d2884ed9cdd211791b 100644 --- a/make/autoconf/hotspot.m4 +++ b/make/autoconf/hotspot.m4 @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 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 @@ -114,12 +114,26 @@ AC_DEFUN_ONCE([HOTSPOT_SETUP_MISC], HOTSPOT_TARGET_CPU_ARCH=zero fi + AC_ARG_WITH([hotspot-build-time], [AS_HELP_STRING([--with-hotspot-build-time], - [timestamp to use in hotspot version string, empty for on-the-fly @<:@empty@:>@])]) + [timestamp to use in hotspot version string, empty means determined at build time @<:@source-date/empty@:>@])]) + + AC_MSG_CHECKING([what hotspot build time to use]) if test "x$with_hotspot_build_time" != x; then HOTSPOT_BUILD_TIME="$with_hotspot_build_time" + AC_MSG_RESULT([$HOTSPOT_BUILD_TIME (from --with-hotspot-build-time)]) + else + if test "x$SOURCE_DATE" = xupdated; then + HOTSPOT_BUILD_TIME="" + AC_MSG_RESULT([determined at build time (default)]) + else + # If we have a fixed value for SOURCE_DATE, use it as default + HOTSPOT_BUILD_TIME="$SOURCE_DATE_ISO_8601" + AC_MSG_RESULT([$HOTSPOT_BUILD_TIME (from --with-source-date)]) + fi fi + AC_SUBST(HOTSPOT_BUILD_TIME) diff --git a/make/autoconf/jdk-options.m4 b/make/autoconf/jdk-options.m4 index c937101c2c71af49c93377beb8cf4f7e35e50d6a..2034934cd733241d48ce87044269cb6fc0c06c75 100644 --- a/make/autoconf/jdk-options.m4 +++ b/make/autoconf/jdk-options.m4 @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 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 @@ -169,6 +169,23 @@ AC_DEFUN_ONCE([JDKOPT_SETUP_JDK_OPTIONS], fi AC_SUBST(CACERTS_FILE) + # Choose cacerts source folder for user provided PEM files + AC_ARG_WITH(cacerts-src, [AS_HELP_STRING([--with-cacerts-src], + [specify alternative cacerts source folder containing certificates])]) + CACERTS_SRC="" + AC_MSG_CHECKING([for cacerts source]) + if test "x$with_cacerts_src" == x; then + AC_MSG_RESULT([default]) + else + CACERTS_SRC=$with_cacerts_src + if test ! -d "$CACERTS_SRC"; then + AC_MSG_RESULT([fail]) + AC_MSG_ERROR([Specified cacerts source folder "$CACERTS_SRC" does not exist]) + fi + AC_MSG_RESULT([$CACERTS_SRC]) + fi + AC_SUBST(CACERTS_SRC) + # Enable or disable unlimited crypto UTIL_ARG_ENABLE(NAME: unlimited-crypto, DEFAULT: true, RESULT: UNLIMITED_CRYPTO, DESC: [enable unlimited crypto policy]) @@ -194,11 +211,17 @@ AC_DEFUN_ONCE([JDKOPT_SETUP_JDK_OPTIONS], # Setup default copyright year. Mostly overridden when building close to a new year. AC_ARG_WITH(copyright-year, [AS_HELP_STRING([--with-copyright-year], - [Set copyright year value for build @<:@current year@:>@])]) + [Set copyright year value for build @<:@current year/source-date@:>@])]) if test "x$with_copyright_year" = xyes; then AC_MSG_ERROR([Copyright year must have a value]) elif test "x$with_copyright_year" != x; then COPYRIGHT_YEAR="$with_copyright_year" + elif test "x$SOURCE_DATE" != xupdated; then + if test "x$IS_GNU_DATE" = xyes; then + COPYRIGHT_YEAR=`$DATE --date=@$SOURCE_DATE +%Y` + else + COPYRIGHT_YEAR=`$DATE -j -f %s $SOURCE_DATE +%Y` + fi else COPYRIGHT_YEAR=`$DATE +'%Y'` fi @@ -639,15 +662,28 @@ AC_DEFUN([JDKOPT_ALLOW_ABSOLUTE_PATHS_IN_OUTPUT], AC_DEFUN_ONCE([JDKOPT_SETUP_REPRODUCIBLE_BUILD], [ AC_ARG_WITH([source-date], [AS_HELP_STRING([--with-source-date], - [how to set SOURCE_DATE_EPOCH ('updated', 'current', 'version' a timestamp or an ISO-8601 date) @<:@updated@:>@])], + [how to set SOURCE_DATE_EPOCH ('updated', 'current', 'version' a timestamp or an ISO-8601 date) @<:@updated/value of SOURCE_DATE_EPOCH@:>@])], [with_source_date_present=true], [with_source_date_present=false]) + if test "x$SOURCE_DATE_EPOCH" != x && test "x$with_source_date" != x; then + AC_MSG_WARN([--with-source-date will override SOURCE_DATE_EPOCH]) + fi + AC_MSG_CHECKING([what source date to use]) if test "x$with_source_date" = xyes; then AC_MSG_ERROR([--with-source-date must have a value]) - elif test "x$with_source_date" = xupdated || test "x$with_source_date" = x; then - # Tell the makefiles to update at each build + elif test "x$with_source_date" = x; then + if test "x$SOURCE_DATE_EPOCH" != x; then + SOURCE_DATE=$SOURCE_DATE_EPOCH + with_source_date_present=true + AC_MSG_RESULT([$SOURCE_DATE, from SOURCE_DATE_EPOCH]) + else + # Tell the makefiles to update at each build + SOURCE_DATE=updated + AC_MSG_RESULT([determined at build time (default)]) + fi + elif test "x$with_source_date" = xupdated; then SOURCE_DATE=updated AC_MSG_RESULT([determined at build time, from 'updated']) elif test "x$with_source_date" = xcurrent; then @@ -679,6 +715,18 @@ AC_DEFUN_ONCE([JDKOPT_SETUP_REPRODUCIBLE_BUILD], fi fi + ISO_8601_FORMAT_STRING="%Y-%m-%dT%H:%M:%SZ" + if test "x$SOURCE_DATE" != xupdated; then + # If we have a fixed value for SOURCE_DATE, we need to set SOURCE_DATE_EPOCH + # for the rest of configure. + SOURCE_DATE_EPOCH="$SOURCE_DATE" + if test "x$IS_GNU_DATE" = xyes; then + SOURCE_DATE_ISO_8601=`$DATE --utc --date="@$SOURCE_DATE" +"$ISO_8601_FORMAT_STRING" 2> /dev/null` + else + SOURCE_DATE_ISO_8601=`$DATE -u -j -f "%s" "$SOURCE_DATE" +"$ISO_8601_FORMAT_STRING" 2> /dev/null` + fi + fi + REPRODUCIBLE_BUILD_DEFAULT=$with_source_date_present if test "x$OPENJDK_BUILD_OS" = xwindows && \ @@ -696,153 +744,13 @@ AC_DEFUN_ONCE([JDKOPT_SETUP_REPRODUCIBLE_BUILD], if test "x$OPENJDK_BUILD_OS" = xwindows && \ test "x$ALLOW_ABSOLUTE_PATHS_IN_OUTPUT" = xfalse && \ test "x$ENABLE_REPRODUCIBLE_BUILD" = xfalse; then - AC_MSG_NOTICE([On Windows it is not possible to combine --disable-reproducible-builds]) + AC_MSG_NOTICE([On Windows it is not possible to combine --disable-reproducible-build]) AC_MSG_NOTICE([with --disable-absolute-paths-in-output.]) AC_MSG_ERROR([Cannot continue]) fi AC_SUBST(SOURCE_DATE) AC_SUBST(ENABLE_REPRODUCIBLE_BUILD) -]) - -################################################################################ -# -# Helper function to build binutils from source. -# -AC_DEFUN([JDKOPT_BUILD_BINUTILS], -[ - BINUTILS_SRC="$with_binutils_src" - UTIL_FIXUP_PATH(BINUTILS_SRC) - - if ! test -d $BINUTILS_SRC; then - AC_MSG_ERROR([--with-binutils-src is not pointing to a directory]) - fi - if ! test -x $BINUTILS_SRC/configure; then - AC_MSG_ERROR([--with-binutils-src does not look like a binutils source directory]) - fi - - if test -e $BINUTILS_SRC/bfd/libbfd.a && \ - test -e $BINUTILS_SRC/opcodes/libopcodes.a && \ - test -e $BINUTILS_SRC/libiberty/libiberty.a && \ - test -e $BINUTILS_SRC/zlib/libz.a; then - AC_MSG_NOTICE([Found binutils binaries in binutils source directory -- not building]) - else - # On Windows, we cannot build with the normal Microsoft CL, but must instead use - # a separate mingw toolchain. - if test "x$OPENJDK_BUILD_OS" = xwindows; then - if test "x$OPENJDK_TARGET_CPU" = "xx86"; then - target_base="i686-w64-mingw32" - else - target_base="$OPENJDK_TARGET_CPU-w64-mingw32" - fi - binutils_cc="$target_base-gcc" - binutils_target="--host=$target_base --target=$target_base" - # Somehow the uint typedef is not included when building with mingw - binutils_cflags="-Duint=unsigned" - compiler_version=`$binutils_cc --version 2>&1` - if ! [ [[ "$compiler_version" =~ GCC ]] ]; then - AC_MSG_NOTICE([Could not find correct mingw compiler $binutils_cc.]) - HELP_MSG_MISSING_DEPENDENCY([$binutils_cc]) - AC_MSG_ERROR([Cannot continue. $HELP_MSG]) - else - AC_MSG_NOTICE([Using compiler $binutils_cc with version $compiler_version]) - fi - elif test "x$OPENJDK_BUILD_OS" = xmacosx; then - if test "x$OPENJDK_TARGET_CPU" = "xaarch64"; then - binutils_target="--enable-targets=aarch64-darwin" - else - binutils_target="" - fi - else - binutils_cc="$CC $SYSROOT_CFLAGS" - binutils_target="" - fi - binutils_cflags="$binutils_cflags $MACHINE_FLAG $JVM_PICFLAG $C_O_FLAG_NORM" - - AC_MSG_NOTICE([Running binutils configure]) - AC_MSG_NOTICE([configure command line: ./configure --disable-nls CFLAGS="$binutils_cflags" CC="$binutils_cc" $binutils_target]) - saved_dir=`pwd` - cd "$BINUTILS_SRC" - ./configure --disable-nls CFLAGS="$binutils_cflags" CC="$binutils_cc" $binutils_target - if test $? -ne 0 || ! test -e $BINUTILS_SRC/Makefile; then - AC_MSG_NOTICE([Automatic building of binutils failed on configure. Try building it manually]) - AC_MSG_ERROR([Cannot continue]) - fi - AC_MSG_NOTICE([Running binutils make]) - $MAKE all-opcodes - if test $? -ne 0; then - AC_MSG_NOTICE([Automatic building of binutils failed on make. Try building it manually]) - AC_MSG_ERROR([Cannot continue]) - fi - cd $saved_dir - AC_MSG_NOTICE([Building of binutils done]) - fi - - BINUTILS_DIR="$BINUTILS_SRC" -]) - -################################################################################ -# -# Determine if hsdis should be built, and if so, with which backend. -# -AC_DEFUN_ONCE([JDKOPT_SETUP_HSDIS], -[ - AC_ARG_WITH([hsdis], [AS_HELP_STRING([--with-hsdis], - [what hsdis backend to use ('none', 'binutils') @<:@none@:>@])]) - - AC_ARG_WITH([binutils], [AS_HELP_STRING([--with-binutils], - [where to find the binutils files needed for hsdis/binutils])]) - - AC_ARG_WITH([binutils-src], [AS_HELP_STRING([--with-binutils-src], - [where to find the binutils source for building])]) - - AC_MSG_CHECKING([what hsdis backend to use]) - - if test "x$with_hsdis" = xyes; then - AC_MSG_ERROR([--with-hsdis must have a value]) - elif test "x$with_hsdis" = xnone || test "x$with_hsdis" = xno || test "x$with_hsdis" = x; then - HSDIS_BACKEND=none - AC_MSG_RESULT(['none', hsdis will not be built]) - elif test "x$with_hsdis" = xbinutils; then - HSDIS_BACKEND=binutils - AC_MSG_RESULT(['binutils']) - - # We need the binutils static libs and includes. - if test "x$with_binutils_src" != x; then - # Try building the source first. If it succeeds, it sets $BINUTILS_DIR. - JDKOPT_BUILD_BINUTILS - fi - - if test "x$with_binutils" != x; then - BINUTILS_DIR="$with_binutils" - fi - - AC_MSG_CHECKING([for binutils to use with hsdis]) - if test "x$BINUTILS_DIR" != x; then - if test -e $BINUTILS_DIR/bfd/libbfd.a && \ - test -e $BINUTILS_DIR/opcodes/libopcodes.a && \ - test -e $BINUTILS_DIR/libiberty/libiberty.a; then - AC_MSG_RESULT([$BINUTILS_DIR]) - HSDIS_CFLAGS="-I$BINUTILS_DIR/include -I$BINUTILS_DIR/bfd -DLIBARCH_$OPENJDK_TARGET_CPU_LEGACY_LIB" - HSDIS_LIBS="$BINUTILS_DIR/bfd/libbfd.a $BINUTILS_DIR/opcodes/libopcodes.a $BINUTILS_DIR/libiberty/libiberty.a $BINUTILS_DIR/zlib/libz.a" - else - AC_MSG_RESULT([invalid]) - AC_MSG_ERROR([$BINUTILS_DIR does not contain a proper binutils installation]) - fi - else - AC_MSG_RESULT([missing]) - AC_MSG_NOTICE([--with-hsdis=binutils requires specifying a binutils installation.]) - AC_MSG_NOTICE([Download binutils from https://www.gnu.org/software/binutils and unpack it,]) - AC_MSG_NOTICE([and point --with-binutils-src to the resulting directory, or use]) - AC_MSG_NOTICE([--with-binutils to point to a pre-built binutils installation.]) - AC_MSG_ERROR([Cannot continue]) - fi - else - AC_MSG_RESULT([invalid]) - AC_MSG_ERROR([Incorrect hsdis backend "$with_hsdis"]) - fi - - AC_SUBST(HSDIS_BACKEND) - AC_SUBST(HSDIS_CFLAGS) - AC_SUBST(HSDIS_LIBS) + AC_SUBST(ISO_8601_FORMAT_STRING) + AC_SUBST(SOURCE_DATE_ISO_8601) ]) diff --git a/make/autoconf/jdk-version.m4 b/make/autoconf/jdk-version.m4 index 60405d67bcb078779b7abacd6d69393fbd1dcb75..41f4b1fb1211f77b68b4b1f17c3893d94abc0d89 100644 --- a/make/autoconf/jdk-version.m4 +++ b/make/autoconf/jdk-version.m4 @@ -69,11 +69,24 @@ AC_DEFUN_ONCE([JDKVER_SETUP_JDK_VERSION_NUMBERS], AC_SUBST(JDK_RC_PLATFORM_NAME) AC_SUBST(HOTSPOT_VM_DISTRO) + # Setup username (for use in adhoc version strings etc) + AC_ARG_WITH([build-user], [AS_HELP_STRING([--with-build-user], + [build username to use in version strings])]) + if test "x$with_build_user" = xyes || test "x$with_build_user" = xno; then + AC_MSG_ERROR([--with-build-user must have a value]) + elif test "x$with_build_user" != x; then + USERNAME="$with_build_user" + else + # Outer [ ] to quote m4. + [ USERNAME=`$ECHO "$USER" | $TR -d -c '[a-z][A-Z][0-9]'` ] + fi + AC_SUBST(USERNAME) + # Set the JDK RC name AC_ARG_WITH(jdk-rc-name, [AS_HELP_STRING([--with-jdk-rc-name], [Set JDK RC name. This is used for FileDescription and ProductName properties of MS Windows binaries. @<:@not specified@:>@])]) - if test "x$with_jdk_rc_name" = xyes; then + if test "x$with_jdk_rc_name" = xyes || test "x$with_jdk_rc_name" = xno; then AC_MSG_ERROR([--with-jdk-rc-name must have a value]) elif [ ! [[ $with_jdk_rc_name =~ ^[[:print:]]*$ ]] ]; then AC_MSG_ERROR([--with-jdk-rc-name contains non-printing characters: $with_jdk_rc_name]) @@ -90,7 +103,7 @@ AC_DEFUN_ONCE([JDKVER_SETUP_JDK_VERSION_NUMBERS], AC_ARG_WITH(vendor-name, [AS_HELP_STRING([--with-vendor-name], [Set vendor name. Among others, used to set the 'java.vendor' and 'java.vm.vendor' system properties. @<:@not specified@:>@])]) - if test "x$with_vendor_name" = xyes; then + if test "x$with_vendor_name" = xyes || test "x$with_vendor_name" = xno; then AC_MSG_ERROR([--with-vendor-name must have a value]) elif [ ! [[ $with_vendor_name =~ ^[[:print:]]*$ ]] ]; then AC_MSG_ERROR([--with-vendor-name contains non-printing characters: $with_vendor_name]) @@ -104,7 +117,7 @@ AC_DEFUN_ONCE([JDKVER_SETUP_JDK_VERSION_NUMBERS], # The vendor URL, if any AC_ARG_WITH(vendor-url, [AS_HELP_STRING([--with-vendor-url], [Set the 'java.vendor.url' system property @<:@not specified@:>@])]) - if test "x$with_vendor_url" = xyes; then + if test "x$with_vendor_url" = xyes || test "x$with_vendor_url" = xno; then AC_MSG_ERROR([--with-vendor-url must have a value]) elif [ ! [[ $with_vendor_url =~ ^[[:print:]]*$ ]] ]; then AC_MSG_ERROR([--with-vendor-url contains non-printing characters: $with_vendor_url]) @@ -118,7 +131,7 @@ AC_DEFUN_ONCE([JDKVER_SETUP_JDK_VERSION_NUMBERS], # The vendor bug URL, if any AC_ARG_WITH(vendor-bug-url, [AS_HELP_STRING([--with-vendor-bug-url], [Set the 'java.vendor.url.bug' system property @<:@not specified@:>@])]) - if test "x$with_vendor_bug_url" = xyes; then + if test "x$with_vendor_bug_url" = xyes || test "x$with_vendor_bug_url" = xno; then AC_MSG_ERROR([--with-vendor-bug-url must have a value]) elif [ ! [[ $with_vendor_bug_url =~ ^[[:print:]]*$ ]] ]; then AC_MSG_ERROR([--with-vendor-bug-url contains non-printing characters: $with_vendor_bug_url]) @@ -132,7 +145,7 @@ AC_DEFUN_ONCE([JDKVER_SETUP_JDK_VERSION_NUMBERS], # The vendor VM bug URL, if any AC_ARG_WITH(vendor-vm-bug-url, [AS_HELP_STRING([--with-vendor-vm-bug-url], [Sets the bug URL which will be displayed when the VM crashes @<:@not specified@:>@])]) - if test "x$with_vendor_vm_bug_url" = xyes; then + if test "x$with_vendor_vm_bug_url" = xyes || test "x$with_vendor_vm_bug_url" = xno; then AC_MSG_ERROR([--with-vendor-vm-bug-url must have a value]) elif [ ! [[ $with_vendor_vm_bug_url =~ ^[[:print:]]*$ ]] ]; then AC_MSG_ERROR([--with-vendor-vm-bug-url contains non-printing characters: $with_vendor_vm_bug_url]) @@ -149,7 +162,7 @@ AC_DEFUN_ONCE([JDKVER_SETUP_JDK_VERSION_NUMBERS], # override parts with more specific flags, since these are processed later. AC_ARG_WITH(version-string, [AS_HELP_STRING([--with-version-string], [Set version string @<:@calculated@:>@])]) - if test "x$with_version_string" = xyes; then + if test "x$with_version_string" = xyes || test "x$with_version_string" = xno; then AC_MSG_ERROR([--with-version-string must have a value]) elif test "x$with_version_string" != x; then # Additional [] needed to keep m4 from mangling shell constructs. @@ -188,6 +201,10 @@ AC_DEFUN_ONCE([JDKVER_SETUP_JDK_VERSION_NUMBERS], && test "x$VERSION_BUILD$VERSION_OPT" = x; then AC_MSG_ERROR([Version string contains + but both 'BUILD' and 'OPT' are missing]) fi + if test "x$VERSION_BUILD" = x0; then + AC_MSG_WARN([Version build 0 is interpreted as no build number]) + VERSION_BUILD= + fi # Stop the version part process from setting default values. # We still allow them to explicitly override though. NO_DEFAULT_VERSION_PARTS=true @@ -239,9 +256,10 @@ AC_DEFUN_ONCE([JDKVER_SETUP_JDK_VERSION_NUMBERS], fi else if test "x$NO_DEFAULT_VERSION_PARTS" != xtrue; then - # Default is to calculate a string like this 'adhoc..' + # Default is to calculate a string like this: + # 'adhoc..' # Outer [ ] to quote m4. - [ basedirname=`$BASENAME "$TOPDIR" | $TR -d -c '[a-z][A-Z][0-9].-'` ] + [ basedirname=`$BASENAME "$WORKSPACE_ROOT" | $TR -d -c '[a-z][A-Z][0-9].-'` ] VERSION_OPT="adhoc.$USERNAME.$basedirname" fi fi @@ -260,13 +278,15 @@ AC_DEFUN_ONCE([JDKVER_SETUP_JDK_VERSION_NUMBERS], VERSION_BUILD= else JDKVER_CHECK_AND_SET_NUMBER(VERSION_BUILD, $with_version_build) + if test "x$VERSION_BUILD" = "x0"; then + AC_MSG_WARN([--with-version-build=0 is interpreted as --without-version-build]) + VERSION_BUILD= + fi fi else if test "x$NO_DEFAULT_VERSION_PARTS" != xtrue; then # Default is to not have a build number. VERSION_BUILD="" - # FIXME: Until all code can cope with an empty VERSION_BUILD, set it to 0. - VERSION_BUILD=0 fi fi @@ -275,7 +295,7 @@ AC_DEFUN_ONCE([JDKVER_SETUP_JDK_VERSION_NUMBERS], [with_version_feature_present=true], [with_version_feature_present=false]) if test "x$with_version_feature_present" = xtrue; then - if test "x$with_version_feature" = xyes; then + if test "x$with_version_feature" = xyes || test "x$with_version_feature" = xno; then AC_MSG_ERROR([--with-version-feature must have a value]) else JDKVER_CHECK_AND_SET_NUMBER(VERSION_FEATURE, $with_version_feature) @@ -439,13 +459,22 @@ AC_DEFUN_ONCE([JDKVER_SETUP_JDK_VERSION_NUMBERS], for i in 1 2 3 4 5 6 ; do stripped_version_number=${stripped_version_number%.0} ; done VERSION_NUMBER=$stripped_version_number - # The complete version string, with additional build information - if test "x$VERSION_BUILD$VERSION_OPT" = x; then - VERSION_STRING=$VERSION_NUMBER${VERSION_PRE:+-$VERSION_PRE} + # A build number of "0" is interpreted as "no build number". + if test "x$VERSION_BUILD" = x0; then + VERSION_BUILD= + fi + + # Compute the complete version string, with additional build information + version_with_pre=$VERSION_NUMBER${VERSION_PRE:+-$VERSION_PRE} + if test "x$VERSION_BUILD" != x || \ + ( test "x$VERSION_OPT" != x && test "x$VERSION_PRE" = x ); then + # As per JEP 223, if build is set, or if opt is set but not pre, + # we need a + separator + version_with_build=$version_with_pre+$VERSION_BUILD else - # If either build or opt is set, we need a + separator - VERSION_STRING=$VERSION_NUMBER${VERSION_PRE:+-$VERSION_PRE}+$VERSION_BUILD${VERSION_OPT:+-$VERSION_OPT} + version_with_build=$version_with_pre fi + VERSION_STRING=$version_with_build${VERSION_OPT:+-$VERSION_OPT} # The short version string, just VERSION_NUMBER and PRE, if present. VERSION_SHORT=$VERSION_NUMBER${VERSION_PRE:+-$VERSION_PRE} @@ -453,7 +482,7 @@ AC_DEFUN_ONCE([JDKVER_SETUP_JDK_VERSION_NUMBERS], # The version date AC_ARG_WITH(version-date, [AS_HELP_STRING([--with-version-date], [Set version date @<:@current source value@:>@])]) - if test "x$with_version_date" = xyes; then + if test "x$with_version_date" = xyes || test "x$with_version_date" = xno; then AC_MSG_ERROR([--with-version-date must have a value]) elif test "x$with_version_date" != x; then if [ ! [[ $with_version_date =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}$ ]] ]; then @@ -472,7 +501,10 @@ AC_DEFUN_ONCE([JDKVER_SETUP_JDK_VERSION_NUMBERS], AC_MSG_ERROR([--with-vendor-version-string must have a value]) elif [ ! [[ $with_vendor_version_string =~ ^[[:graph:]]*$ ]] ]; then AC_MSG_ERROR([--with--vendor-version-string contains non-graphical characters: $with_vendor_version_string]) - else + elif test "x$with_vendor_version_string" != xno; then + # Set vendor version string if --without is not passed + # Check not required if an empty value is passed, since VENDOR_VERSION_STRING + # would then be set to "" VENDOR_VERSION_STRING="$with_vendor_version_string" fi @@ -480,7 +512,7 @@ AC_DEFUN_ONCE([JDKVER_SETUP_JDK_VERSION_NUMBERS], AC_ARG_WITH(macosx-bundle-name-base, [AS_HELP_STRING([--with-macosx-bundle-name-base], [Set the MacOSX Bundle Name base. This is the base name for calculating MacOSX Bundle Names. @<:@not specified@:>@])]) - if test "x$with_macosx_bundle_name_base" = xyes; then + if test "x$with_macosx_bundle_name_base" = xyes || test "x$with_macosx_bundle_name_base" = xno; then AC_MSG_ERROR([--with-macosx-bundle-name-base must have a value]) elif [ ! [[ $with_macosx_bundle_name_base =~ ^[[:print:]]*$ ]] ]; then AC_MSG_ERROR([--with-macosx-bundle-name-base contains non-printing characters: $with_macosx_bundle_name_base]) @@ -494,7 +526,7 @@ AC_DEFUN_ONCE([JDKVER_SETUP_JDK_VERSION_NUMBERS], AC_ARG_WITH(macosx-bundle-id-base, [AS_HELP_STRING([--with-macosx-bundle-id-base], [Set the MacOSX Bundle ID base. This is the base ID for calculating MacOSX Bundle IDs. @<:@not specified@:>@])]) - if test "x$with_macosx_bundle_id_base" = xyes; then + if test "x$with_macosx_bundle_id_base" = xyes || test "x$with_macosx_bundle_id_base" = xno; then AC_MSG_ERROR([--with-macosx-bundle-id-base must have a value]) elif [ ! [[ $with_macosx_bundle_id_base =~ ^[[:print:]]*$ ]] ]; then AC_MSG_ERROR([--with-macosx-bundle-id-base contains non-printing characters: $with_macosx_bundle_id_base]) @@ -515,14 +547,19 @@ AC_DEFUN_ONCE([JDKVER_SETUP_JDK_VERSION_NUMBERS], [Set the MacOSX Bundle CFBundleVersion field. This key is a machine-readable string composed of one to three period-separated integers and should represent the build version. Defaults to the build number.])]) - if test "x$with_macosx_bundle_build_version" = xyes; then + if test "x$with_macosx_bundle_build_version" = xyes || test "x$with_macosx_bundle_build_version" = xno; then AC_MSG_ERROR([--with-macosx-bundle-build-version must have a value]) elif [ ! [[ $with_macosx_bundle_build_version =~ ^[0-9\.]*$ ]] ]; then AC_MSG_ERROR([--with-macosx-bundle-build-version contains non numbers and periods: $with_macosx_bundle_build_version]) elif test "x$with_macosx_bundle_build_version" != x; then MACOSX_BUNDLE_BUILD_VERSION="$with_macosx_bundle_build_version" else - MACOSX_BUNDLE_BUILD_VERSION="$VERSION_BUILD" + if test "x$VERSION_BUILD" != x; then + MACOSX_BUNDLE_BUILD_VERSION="$VERSION_BUILD" + else + MACOSX_BUNDLE_BUILD_VERSION=0 + fi + # If VERSION_OPT consists of only numbers and periods, add it. if [ [[ $VERSION_OPT =~ ^[0-9\.]+$ ]] ]; then MACOSX_BUNDLE_BUILD_VERSION="$MACOSX_BUNDLE_BUILD_VERSION.$VERSION_OPT" diff --git a/make/autoconf/jvm-features.m4 b/make/autoconf/jvm-features.m4 index 1f76c323129fd366a358b72f1e67c6a0a63b7568..8dfc0d362b9d385649d16d291e0e18d683c8af0e 100644 --- a/make/autoconf/jvm-features.m4 +++ b/make/autoconf/jvm-features.m4 @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 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 @@ -45,7 +45,7 @@ m4_define(jvm_features_valid, m4_normalize( \ ifdef([custom_jvm_features_valid], custom_jvm_features_valid) \ \ cds compiler1 compiler2 dtrace epsilongc g1gc jfr jni-check \ - jvmci jvmti link-time-opt management minimal nmt opt-size parallelgc \ + jvmci jvmti link-time-opt management minimal opt-size parallelgc \ serialgc services shenandoahgc static-build vm-structs zero zgc \ )) @@ -68,7 +68,6 @@ m4_define(jvm_feature_desc_jvmti, [enable Java Virtual Machine Tool Interface (J m4_define(jvm_feature_desc_link_time_opt, [enable link time optimization]) m4_define(jvm_feature_desc_management, [enable java.lang.management API support]) m4_define(jvm_feature_desc_minimal, [support building variant 'minimal']) -m4_define(jvm_feature_desc_nmt, [include native memory tracking (NMT)]) m4_define(jvm_feature_desc_opt_size, [optimize the JVM library for size]) m4_define(jvm_feature_desc_parallelgc, [include the parallel garbage collector]) m4_define(jvm_feature_desc_serialgc, [include the serial garbage collector]) @@ -265,22 +264,6 @@ AC_DEFUN_ONCE([JVM_FEATURES_CHECK_DTRACE], ]) ]) -############################################################################### -# Check if the feature 'jfr' is available on this platform. -# -AC_DEFUN_ONCE([JVM_FEATURES_CHECK_JFR], -[ - JVM_FEATURES_CHECK_AVAILABILITY(jfr, [ - AC_MSG_CHECKING([if platform is supported by JFR]) - if test "x$OPENJDK_TARGET_OS" = xaix; then - AC_MSG_RESULT([no, $OPENJDK_TARGET_OS-$OPENJDK_TARGET_CPU]) - AVAILABLE=false - else - AC_MSG_RESULT([yes]) - fi - ]) -]) - ############################################################################### # Check if the feature 'jvmci' is available on this platform. # @@ -307,7 +290,8 @@ AC_DEFUN_ONCE([JVM_FEATURES_CHECK_SHENANDOAHGC], JVM_FEATURES_CHECK_AVAILABILITY(shenandoahgc, [ AC_MSG_CHECKING([if platform is supported by Shenandoah]) if test "x$OPENJDK_TARGET_CPU_ARCH" = "xx86" || \ - test "x$OPENJDK_TARGET_CPU" = "xaarch64" ; then + test "x$OPENJDK_TARGET_CPU" = "xaarch64" || \ + test "x$OPENJDK_TARGET_CPU" = "xppc64le"; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no, $OPENJDK_TARGET_CPU]) @@ -399,18 +383,11 @@ AC_DEFUN_ONCE([JVM_FEATURES_PREPARE_PLATFORM], JVM_FEATURES_CHECK_CDS JVM_FEATURES_CHECK_DTRACE - JVM_FEATURES_CHECK_JFR JVM_FEATURES_CHECK_JVMCI JVM_FEATURES_CHECK_SHENANDOAHGC JVM_FEATURES_CHECK_STATIC_BUILD JVM_FEATURES_CHECK_ZGC - # Filter out features by default for all variants on certain platforms. - # Make sure to just add to JVM_FEATURES_PLATFORM_FILTER, since it could - # have a value already from custom extensions. - if test "x$OPENJDK_TARGET_OS" = xaix; then - JVM_FEATURES_PLATFORM_FILTER="$JVM_FEATURES_PLATFORM_FILTER jfr" - fi ]) ############################################################################### @@ -442,7 +419,7 @@ AC_DEFUN([JVM_FEATURES_PREPARE_VARIANT], JVM_FEATURES_VARIANT_FILTER="compiler2 jvmci link-time-opt opt-size" elif test "x$variant" = "xminimal"; then JVM_FEATURES_VARIANT_FILTER="cds compiler2 dtrace epsilongc g1gc \ - jfr jni-check jvmci jvmti management nmt parallelgc services \ + jfr jni-check jvmci jvmti management parallelgc services \ shenandoahgc vm-structs zgc" if test "x$OPENJDK_TARGET_CPU" = xarm ; then JVM_FEATURES_VARIANT_FILTER="$JVM_FEATURES_VARIANT_FILTER opt-size" @@ -537,10 +514,6 @@ AC_DEFUN([JVM_FEATURES_VERIFY], AC_MSG_ERROR([Specified JVM feature 'jvmti' requires feature 'services' for variant '$variant']) fi - if JVM_FEATURES_IS_ACTIVE(management) && ! JVM_FEATURES_IS_ACTIVE(nmt); then - AC_MSG_ERROR([Specified JVM feature 'management' requires feature 'nmt' for variant '$variant']) - fi - # For backwards compatibility, disable a feature "globally" if one variant # is missing the feature. if ! JVM_FEATURES_IS_ACTIVE(cds); then diff --git a/make/autoconf/lib-hsdis.m4 b/make/autoconf/lib-hsdis.m4 new file mode 100644 index 0000000000000000000000000000000000000000..f3e5da5f8690199cb86b1e4412e7e7ce19fc917c --- /dev/null +++ b/make/autoconf/lib-hsdis.m4 @@ -0,0 +1,336 @@ +# +# 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. 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. +# + +################################################################################ +# +# Helper function to setup hsdis using Capstone +# +AC_DEFUN([LIB_SETUP_HSDIS_CAPSTONE], +[ + AC_ARG_WITH(capstone, [AS_HELP_STRING([--with-capstone], + [where to find the Capstone files needed for hsdis/capstone])]) + + if test "x$with_capstone" != x; then + AC_MSG_CHECKING([for capstone]) + CAPSTONE="$with_capstone" + AC_MSG_RESULT([$CAPSTONE]) + + HSDIS_CFLAGS="-I${CAPSTONE}/include/capstone" + if test "x$OPENJDK_TARGET_OS" != xwindows; then + HSDIS_LDFLAGS="-L${CAPSTONE}/lib" + HSDIS_LIBS="-lcapstone" + else + HSDIS_LDFLAGS="-nodefaultlib:libcmt.lib" + HSDIS_LIBS="${CAPSTONE}/capstone.lib" + fi + else + if test "x$OPENJDK_TARGET_OS" = xwindows; then + # There is no way to auto-detect capstone on Windowos + AC_MSG_NOTICE([You must specify capstone location using --with-capstone=]) + AC_MSG_ERROR([Cannot continue]) + fi + + PKG_CHECK_MODULES(CAPSTONE, capstone, [CAPSTONE_FOUND=yes], [CAPSTONE_FOUND=no]) + if test "x$CAPSTONE_FOUND" = xyes; then + HSDIS_CFLAGS="$CAPSTONE_CFLAGS" + HSDIS_LDFLAGS="$CAPSTONE_LDFLAGS" + HSDIS_LIBS="$CAPSTONE_LIBS" + else + HELP_MSG_MISSING_DEPENDENCY([capstone]) + AC_MSG_NOTICE([Cannot locate capstone which is needed for hsdis/capstone. Try using --with-capstone=. $HELP_MSG]) + AC_MSG_ERROR([Cannot continue]) + fi + fi +]) + +################################################################################ +# +# Helper function to setup hsdis using LLVM +# +AC_DEFUN([LIB_SETUP_HSDIS_LLVM], +[ + AC_ARG_WITH([llvm], [AS_HELP_STRING([--with-llvm], + [where to find the LLVM files needed for hsdis/llvm])]) + + if test "x$with_llvm" != x; then + LLVM_DIR="$with_llvm" + fi + + if test "x$OPENJDK_TARGET_OS" != xwindows; then + if test "x$LLVM_DIR" = x; then + # Macs with homebrew can have llvm in different places + UTIL_LOOKUP_PROGS(LLVM_CONFIG, llvm-config, [$PATH:/usr/local/opt/llvm/bin:/opt/homebrew/opt/llvm/bin]) + if test "x$LLVM_CONFIG" = x; then + AC_MSG_NOTICE([Cannot locate llvm-config which is needed for hsdis/llvm. Try using --with-llvm=.]) + AC_MSG_ERROR([Cannot continue]) + fi + else + UTIL_LOOKUP_PROGS(LLVM_CONFIG, llvm-config, [$LLVM_DIR/bin]) + if test "x$LLVM_CONFIG" = x; then + AC_MSG_NOTICE([Cannot locate llvm-config in $LLVM_DIR. Check your --with-llvm argument.]) + AC_MSG_ERROR([Cannot continue]) + fi + fi + + # We need the LLVM flags and libs, and llvm-config provides them for us. + HSDIS_CFLAGS=`$LLVM_CONFIG --cflags` + HSDIS_LDFLAGS=`$LLVM_CONFIG --ldflags` + HSDIS_LIBS=`$LLVM_CONFIG --libs $OPENJDK_TARGET_CPU_ARCH ${OPENJDK_TARGET_CPU_ARCH}disassembler` + else + if test "x$LLVM_DIR" = x; then + AC_MSG_NOTICE([--with-llvm is needed on Windows to point out the LLVM home]) + AC_MSG_ERROR([Cannot continue]) + fi + + # Official Windows installation of LLVM do not ship llvm-config, and self-built llvm-config + # produced unusable output, so just ignore it on Windows. + if ! test -e $LLVM_DIR/include/llvm-c/lto.h; then + AC_MSG_NOTICE([$LLVM_DIR does not seem like a valid LLVM home; include dir is missing]) + AC_MSG_ERROR([Cannot continue]) + fi + if ! test -e $LLVM_DIR/include/llvm-c/Disassembler.h; then + AC_MSG_NOTICE([$LLVM_DIR does not point to a complete LLVM installation. ]) + AC_MSG_NOTICE([The official LLVM distribution is missing crucical files; you need to build LLVM yourself or get all include files elsewhere]) + AC_MSG_ERROR([Cannot continue]) + fi + if ! test -e $LLVM_DIR/lib/llvm-c.lib; then + AC_MSG_NOTICE([$LLVM_DIR does not seem like a valid LLVM home; lib dir is missing]) + AC_MSG_ERROR([Cannot continue]) + fi + HSDIS_CFLAGS="-I$LLVM_DIR/include" + HSDIS_LDFLAGS="-libpath:$LLVM_DIR/lib" + HSDIS_LIBS="llvm-c.lib" + fi +]) + +################################################################################ +# +# Helper function to build binutils from source. +# +AC_DEFUN([LIB_BUILD_BINUTILS], +[ + BINUTILS_SRC="$with_binutils_src" + UTIL_FIXUP_PATH(BINUTILS_SRC) + + if ! test -d $BINUTILS_SRC; then + AC_MSG_ERROR([--with-binutils-src is not pointing to a directory]) + fi + if ! test -x $BINUTILS_SRC/configure; then + AC_MSG_ERROR([--with-binutils-src does not look like a binutils source directory]) + fi + + if test -e $BINUTILS_SRC/bfd/libbfd.a && \ + test -e $BINUTILS_SRC/opcodes/libopcodes.a && \ + test -e $BINUTILS_SRC/libiberty/libiberty.a && \ + test -e $BINUTILS_SRC/zlib/libz.a; then + AC_MSG_NOTICE([Found binutils binaries in binutils source directory -- not building]) + else + # On Windows, we cannot build with the normal Microsoft CL, but must instead use + # a separate mingw toolchain. + if test "x$OPENJDK_BUILD_OS" = xwindows; then + if test "x$OPENJDK_TARGET_CPU" = "xx86"; then + target_base="i686-w64-mingw32" + else + target_base="$OPENJDK_TARGET_CPU-w64-mingw32" + fi + binutils_cc="$target_base-gcc" + binutils_target="--host=$target_base --target=$target_base" + # Somehow the uint typedef is not included when building with mingw + binutils_cflags="-Duint=unsigned" + compiler_version=`$binutils_cc --version 2>&1` + if ! [ [[ "$compiler_version" =~ GCC ]] ]; then + AC_MSG_NOTICE([Could not find correct mingw compiler $binutils_cc.]) + HELP_MSG_MISSING_DEPENDENCY([$binutils_cc]) + AC_MSG_ERROR([Cannot continue. $HELP_MSG]) + else + AC_MSG_NOTICE([Using compiler $binutils_cc with version $compiler_version]) + fi + elif test "x$OPENJDK_BUILD_OS" = xmacosx; then + if test "x$OPENJDK_TARGET_CPU" = "xaarch64"; then + binutils_target="--enable-targets=aarch64-darwin" + else + binutils_target="" + fi + else + binutils_cc="$CC $SYSROOT_CFLAGS" + binutils_target="" + fi + binutils_cflags="$binutils_cflags $MACHINE_FLAG $JVM_PICFLAG $C_O_FLAG_NORM" + + AC_MSG_NOTICE([Running binutils configure]) + AC_MSG_NOTICE([configure command line: ./configure --disable-nls CFLAGS="$binutils_cflags" CC="$binutils_cc" $binutils_target]) + saved_dir=`pwd` + cd "$BINUTILS_SRC" + ./configure --disable-nls CFLAGS="$binutils_cflags" CC="$binutils_cc" $binutils_target + if test $? -ne 0 || ! test -e $BINUTILS_SRC/Makefile; then + AC_MSG_NOTICE([Automatic building of binutils failed on configure. Try building it manually]) + AC_MSG_ERROR([Cannot continue]) + fi + AC_MSG_NOTICE([Running binutils make]) + $MAKE all-opcodes + if test $? -ne 0; then + AC_MSG_NOTICE([Automatic building of binutils failed on make. Try building it manually]) + AC_MSG_ERROR([Cannot continue]) + fi + cd $saved_dir + AC_MSG_NOTICE([Building of binutils done]) + fi + + BINUTILS_DIR="$BINUTILS_SRC" +]) + +################################################################################ +# +# Helper function to setup hsdis using binutils +# +AC_DEFUN([LIB_SETUP_HSDIS_BINUTILS], +[ + AC_ARG_WITH([binutils], [AS_HELP_STRING([--with-binutils], + [where to find the binutils files needed for hsdis/binutils])]) + + AC_ARG_WITH([binutils-src], [AS_HELP_STRING([--with-binutils-src], + [where to find the binutils source for building])]) + + # We need the binutils static libs and includes. + if test "x$with_binutils_src" != x; then + # Try building the source first. If it succeeds, it sets $BINUTILS_DIR. + LIB_BUILD_BINUTILS + fi + + if test "x$with_binutils" != x; then + BINUTILS_DIR="$with_binutils" + fi + + binutils_system_error="" + HSDIS_LIBS="" + if test "x$BINUTILS_DIR" = xsystem; then + AC_CHECK_LIB(bfd, bfd_openr, [ HSDIS_LIBS="-lbfd" ], [ binutils_system_error="libbfd not found" ]) + AC_CHECK_LIB(opcodes, disassembler, [ HSDIS_LIBS="$HSDIS_LIBS -lopcodes" ], [ binutils_system_error="libopcodes not found" ]) + AC_CHECK_LIB(iberty, xmalloc, [ HSDIS_LIBS="$HSDIS_LIBS -liberty" ], [ binutils_system_error="libiberty not found" ]) + AC_CHECK_LIB(z, deflate, [ HSDIS_LIBS="$HSDIS_LIBS -lz" ], [ binutils_system_error="libz not found" ]) + HSDIS_CFLAGS="-DLIBARCH_$OPENJDK_TARGET_CPU_LEGACY_LIB" + elif test "x$BINUTILS_DIR" != x; then + if test -e $BINUTILS_DIR/bfd/libbfd.a && \ + test -e $BINUTILS_DIR/opcodes/libopcodes.a && \ + test -e $BINUTILS_DIR/libiberty/libiberty.a; then + HSDIS_CFLAGS="-I$BINUTILS_DIR/include -I$BINUTILS_DIR/bfd -DLIBARCH_$OPENJDK_TARGET_CPU_LEGACY_LIB" + HSDIS_LDFLAGS="" + HSDIS_LIBS="$BINUTILS_DIR/bfd/libbfd.a $BINUTILS_DIR/opcodes/libopcodes.a $BINUTILS_DIR/libiberty/libiberty.a $BINUTILS_DIR/zlib/libz.a" + fi + fi + + AC_MSG_CHECKING([for binutils to use with hsdis]) + case "x$BINUTILS_DIR" in + xsystem) + if test "x$OPENJDK_TARGET_OS" != xlinux; then + AC_MSG_RESULT([invalid]) + AC_MSG_ERROR([binutils on system is supported for Linux only]) + elif test "x$binutils_system_error" = x; then + AC_MSG_RESULT([system]) + HSDIS_CFLAGS="$HSDIS_CFLAGS -DSYSTEM_BINUTILS" + else + AC_MSG_RESULT([invalid]) + AC_MSG_ERROR([$binutils_system_error]) + fi + ;; + x) + AC_MSG_RESULT([missing]) + AC_MSG_NOTICE([--with-hsdis=binutils requires specifying a binutils installation.]) + AC_MSG_NOTICE([Download binutils from https://www.gnu.org/software/binutils and unpack it,]) + AC_MSG_NOTICE([and point --with-binutils-src to the resulting directory, or use]) + AC_MSG_NOTICE([--with-binutils to point to a pre-built binutils installation.]) + AC_MSG_ERROR([Cannot continue]) + ;; + *) + if test "x$HSDIS_LIBS" != x; then + AC_MSG_RESULT([$BINUTILS_DIR]) + else + AC_MSG_RESULT([invalid]) + AC_MSG_ERROR([$BINUTILS_DIR does not contain a proper binutils installation]) + fi + ;; + esac +]) + +################################################################################ +# +# Determine if hsdis should be built, and if so, with which backend. +# +AC_DEFUN_ONCE([LIB_SETUP_HSDIS], +[ + AC_ARG_WITH([hsdis], [AS_HELP_STRING([--with-hsdis], + [what hsdis backend to use ('none', 'capstone', 'llvm', 'binutils') @<:@none@:>@])]) + + UTIL_ARG_ENABLE(NAME: hsdis-bundling, DEFAULT: false, + RESULT: ENABLE_HSDIS_BUNDLING, + DESC: [enable bundling of hsdis to allow HotSpot disassembly out-of-the-box]) + + AC_MSG_CHECKING([what hsdis backend to use]) + + if test "x$with_hsdis" = xyes; then + AC_MSG_ERROR([--with-hsdis must have a value]) + elif test "x$with_hsdis" = xnone || test "x$with_hsdis" = xno || test "x$with_hsdis" = x; then + HSDIS_BACKEND=none + AC_MSG_RESULT(['none', hsdis will not be built]) + elif test "x$with_hsdis" = xcapstone; then + HSDIS_BACKEND=capstone + AC_MSG_RESULT(['capstone']) + + LIB_SETUP_HSDIS_CAPSTONE + elif test "x$with_hsdis" = xllvm; then + HSDIS_BACKEND=llvm + AC_MSG_RESULT(['llvm']) + + LIB_SETUP_HSDIS_LLVM + elif test "x$with_hsdis" = xbinutils; then + HSDIS_BACKEND=binutils + AC_MSG_RESULT(['binutils']) + + LIB_SETUP_HSDIS_BINUTILS + else + AC_MSG_RESULT([invalid]) + AC_MSG_ERROR([Incorrect hsdis backend "$with_hsdis"]) + fi + + AC_SUBST(HSDIS_BACKEND) + AC_SUBST(HSDIS_CFLAGS) + AC_SUBST(HSDIS_LDFLAGS) + AC_SUBST(HSDIS_LIBS) + + AC_MSG_CHECKING([if hsdis should be bundled]) + if test "x$ENABLE_HSDIS_BUNDLING" = "xtrue"; then + if test "x$HSDIS_BACKEND" = xnone; then + AC_MSG_RESULT([no, backend missing]) + AC_MSG_ERROR([hsdis-bundling requires a hsdis backend. Please set --with-hsdis=]); + fi + AC_MSG_RESULT([yes]) + if test "x$HSDIS_BACKEND" = xbinutils; then + AC_MSG_WARN([The resulting build might not be redistributable. Seek legal advice before distributing.]) + fi + else + AC_MSG_RESULT([no]) + fi + AC_SUBST(ENABLE_HSDIS_BUNDLING) +]) diff --git a/make/autoconf/libraries.m4 b/make/autoconf/libraries.m4 index 8e4012910d890774acb9a2769c147e1b14f9951e..fbc8ee7b9c8638fd639e3c34076a25bbce04dc4c 100644 --- a/make/autoconf/libraries.m4 +++ b/make/autoconf/libraries.m4 @@ -28,10 +28,12 @@ m4_include([lib-alsa.m4]) m4_include([lib-bundled.m4]) m4_include([lib-cups.m4]) m4_include([lib-ffi.m4]) +m4_include([lib-fontconfig.m4]) m4_include([lib-freetype.m4]) +m4_include([lib-hsdis.m4]) m4_include([lib-std.m4]) m4_include([lib-x11.m4]) -m4_include([lib-fontconfig.m4]) + m4_include([lib-tests.m4]) ################################################################################ @@ -93,14 +95,17 @@ AC_DEFUN_ONCE([LIB_DETERMINE_DEPENDENCIES], AC_DEFUN_ONCE([LIB_SETUP_LIBRARIES], [ LIB_SETUP_STD_LIBS - LIB_SETUP_X11 + + LIB_SETUP_ALSA + LIB_SETUP_BUNDLED_LIBS LIB_SETUP_CUPS LIB_SETUP_FONTCONFIG LIB_SETUP_FREETYPE - LIB_SETUP_ALSA + LIB_SETUP_HSDIS LIB_SETUP_LIBFFI - LIB_SETUP_BUNDLED_LIBS LIB_SETUP_MISC_LIBS + LIB_SETUP_X11 + LIB_TESTS_SETUP_GTEST BASIC_JDKLIB_LIBS="" diff --git a/make/autoconf/spec.gmk.in b/make/autoconf/spec.gmk.in index 72be922f1036f0b31ad6fc4ccd347f1e5eb69871..5671d4a9f3e5aa1a485ca38f6232598e29e61363 100644 --- a/make/autoconf/spec.gmk.in +++ b/make/autoconf/spec.gmk.in @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 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 @@ -130,6 +130,13 @@ RELEASE_FILE_LIBC:=@RELEASE_FILE_LIBC@ SOURCE_DATE := @SOURCE_DATE@ ENABLE_REPRODUCIBLE_BUILD := @ENABLE_REPRODUCIBLE_BUILD@ +ISO_8601_FORMAT_STRING := @ISO_8601_FORMAT_STRING@ + +ifneq ($(SOURCE_DATE), updated) + # For "updated" source date value, these are set in InitSupport.gmk + export SOURCE_DATE_EPOCH := $(SOURCE_DATE) + SOURCE_DATE_ISO_8601 := @SOURCE_DATE_ISO_8601@ +endif LIBM:=@LIBM@ LIBDL:=@LIBDL@ @@ -239,7 +246,7 @@ VERSION_DOCS_API_SINCE := @VERSION_DOCS_API_SINCE@ JDK_SOURCE_TARGET_VERSION := @JDK_SOURCE_TARGET_VERSION@ # Convenience CFLAGS settings for passing version information into native programs. -VERSION_CFLAGS := \ +VERSION_CFLAGS = \ -DVERSION_FEATURE=$(VERSION_FEATURE) \ -DVERSION_INTERIM=$(VERSION_INTERIM) \ -DVERSION_UPDATE=$(VERSION_UPDATE) \ @@ -360,7 +367,9 @@ ENABLE_COMPATIBLE_CDS_ALIGNMENT := @ENABLE_COMPATIBLE_CDS_ALIGNMENT@ ALLOW_ABSOLUTE_PATHS_IN_OUTPUT := @ALLOW_ABSOLUTE_PATHS_IN_OUTPUT@ HSDIS_BACKEND := @HSDIS_BACKEND@ +ENABLE_HSDIS_BUNDLING := @ENABLE_HSDIS_BUNDLING@ HSDIS_CFLAGS := @HSDIS_CFLAGS@ +HSDIS_LDFLAGS := @HSDIS_LDFLAGS@ HSDIS_LIBS := @HSDIS_LIBS@ # The boot jdk to use. This is overridden in bootcycle-spec.gmk. Make sure to keep @@ -371,6 +380,9 @@ BUILD_JDK:=@BUILD_JDK@ CREATE_BUILDJDK:=@CREATE_BUILDJDK@ EXTERNAL_BUILDJDK:=@EXTERNAL_BUILDJDK@ +# Whether the boot jdk jar supports --date=TIMESTAMP +BOOT_JDK_JAR_SUPPORTS_DATE:=@BOOT_JDK_JAR_SUPPORTS_DATE@ + # When compiling Java source to be run by the boot jdk # use these extra flags, eg -source 6 -target 6 BOOT_JDK_SOURCETARGET:=@BOOT_JDK_SOURCETARGET@ @@ -403,6 +415,7 @@ LIBFFI_CFLAGS:=@LIBFFI_CFLAGS@ ENABLE_LIBFFI_BUNDLING:=@ENABLE_LIBFFI_BUNDLING@ LIBFFI_LIB_FILE:=@LIBFFI_LIB_FILE@ FILE_MACRO_CFLAGS := @FILE_MACRO_CFLAGS@ +BRANCH_PROTECTION_CFLAGS := @BRANCH_PROTECTION_CFLAGS@ STATIC_LIBS_CFLAGS := @STATIC_LIBS_CFLAGS@ @@ -416,6 +429,8 @@ GTEST_FRAMEWORK_SRC := @GTEST_FRAMEWORK_SRC@ # Source file for cacerts CACERTS_FILE=@CACERTS_FILE@ +# Source folder for user provided cacerts PEM files +CACERTS_SRC=@CACERTS_SRC@ # Enable unlimited crypto policy UNLIMITED_CRYPTO=@UNLIMITED_CRYPTO@ @@ -576,7 +591,6 @@ AR := @AR@ ARFLAGS:=@ARFLAGS@ NM:=@NM@ -GNM:=@GNM@ STRIP:=@STRIP@ OBJDUMP:=@OBJDUMP@ CXXFILT:=@CXXFILT@ @@ -705,6 +719,7 @@ CODESIGN:=@CODESIGN@ CP:=@CP@ CUT:=@CUT@ DATE:=@DATE@ +IS_GNU_DATE:=@IS_GNU_DATE@ DIFF:=@DIFF@ DIRNAME:=@DIRNAME@ DSYMUTIL:=@DSYMUTIL@ @@ -923,7 +938,12 @@ JDK_MACOSX_CONTENTS_DIR=$(JDK_MACOSX_BUNDLE_DIR)/$(JDK_MACOSX_CONTENTS_SUBDIR) JRE_MACOSX_CONTENTS_DIR=$(JRE_MACOSX_BUNDLE_DIR)/$(JRE_MACOSX_CONTENTS_SUBDIR) # Bundle names -BASE_NAME := $(VERSION_SHORT)+$(VERSION_BUILD)_$(OPENJDK_TARGET_BUNDLE_PLATFORM) +ifneq ($(VERSION_BUILD), ) + BASE_NAME := $(VERSION_SHORT)+$(VERSION_BUILD)_$(OPENJDK_TARGET_BUNDLE_PLATFORM) +else + BASE_NAME := $(VERSION_SHORT)_$(OPENJDK_TARGET_BUNDLE_PLATFORM) +endif + ifeq ($(DEBUG_LEVEL), fastdebug) DEBUG_PART := -debug else ifneq ($(DEBUG_LEVEL), release) diff --git a/make/autoconf/toolchain.m4 b/make/autoconf/toolchain.m4 index 9666d9a6d9dd6c0d360fc89f5a89a25d7e011e93..b79d161331d273c5bd456c004ad39ea79cc5f5a6 100644 --- a/make/autoconf/toolchain.m4 +++ b/make/autoconf/toolchain.m4 @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 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 @@ -39,7 +39,7 @@ VALID_TOOLCHAINS_all="gcc clang xlc microsoft" # These toolchains are valid on different platforms VALID_TOOLCHAINS_linux="gcc clang" -VALID_TOOLCHAINS_macosx="gcc clang" +VALID_TOOLCHAINS_macosx="clang" VALID_TOOLCHAINS_aix="xlc" VALID_TOOLCHAINS_windows="microsoft" @@ -234,7 +234,7 @@ AC_DEFUN_ONCE([TOOLCHAIN_DETERMINE_TOOLCHAIN_TYPE], if test "x$OPENJDK_TARGET_OS" = xmacosx; then if test -n "$XCODEBUILD"; then # On Mac OS X, default toolchain to clang after Xcode 5 - XCODE_VERSION_OUTPUT=`"$XCODEBUILD" -version 2>&1 | $HEAD -n 1` + XCODE_VERSION_OUTPUT=`"$XCODEBUILD" -version | $HEAD -n 1` $ECHO "$XCODE_VERSION_OUTPUT" | $GREP "Xcode " > /dev/null if test $? -ne 0; then AC_MSG_NOTICE([xcodebuild output: $XCODE_VERSION_OUTPUT]) @@ -772,8 +772,6 @@ AC_DEFUN_ONCE([TOOLCHAIN_DETECT_TOOLCHAIN_EXTRA], else UTIL_LOOKUP_TOOLCHAIN_PROGS(NM, nm) fi - GNM="$NM" - AC_SUBST(GNM) fi # objcopy is used for moving debug symbols to separate files when @@ -903,8 +901,8 @@ AC_DEFUN_ONCE([TOOLCHAIN_SETUP_BUILD_COMPILERS], BUILD_LDCXX="$BUILD_LD" else if test "x$OPENJDK_BUILD_OS" = xmacosx; then - UTIL_REQUIRE_PROGS(BUILD_CC, clang cc gcc) - UTIL_REQUIRE_PROGS(BUILD_CXX, clang++ CC g++) + UTIL_REQUIRE_PROGS(BUILD_CC, clang) + UTIL_REQUIRE_PROGS(BUILD_CXX, clang++) else UTIL_REQUIRE_PROGS(BUILD_CC, cc gcc) UTIL_REQUIRE_PROGS(BUILD_CXX, CC g++) diff --git a/make/autoconf/toolchain_microsoft.m4 b/make/autoconf/toolchain_microsoft.m4 index 2600b431cfb79143b00c2cd6b24f4009e2d1942a..03d4ae50dfb0165d49e28289a4f62b46658ba484 100644 --- a/make/autoconf/toolchain_microsoft.m4 +++ b/make/autoconf/toolchain_microsoft.m4 @@ -103,6 +103,7 @@ AC_DEFUN([TOOLCHAIN_CHECK_POSSIBLE_VISUAL_STUDIO_ROOT], vc/auxiliary/build/vcvarsx86_amd64.bat vc/auxiliary/build/vcvars64.bat" elif test "x$TARGET_CPU" = xaarch64; then # for host x86-64, target aarch64 + # aarch64 requires Visual Studio 16.8 or higher VCVARSFILES="vc/auxiliary/build/vcvarsamd64_arm64.bat \ vc/auxiliary/build/vcvarsx86_arm64.bat" fi @@ -480,6 +481,7 @@ AC_DEFUN([TOOLCHAIN_CHECK_POSSIBLE_MSVC_DLL], AC_DEFUN([TOOLCHAIN_SETUP_MSVC_DLL], [ DLL_NAME="$1" + DLL_HELP="$2" MSVC_DLL= if test "x$OPENJDK_TARGET_CPU" = xx86; then @@ -564,7 +566,7 @@ AC_DEFUN([TOOLCHAIN_SETUP_MSVC_DLL], if test "x$MSVC_DLL" = x; then AC_MSG_CHECKING([for $DLL_NAME]) AC_MSG_RESULT([no]) - AC_MSG_ERROR([Could not find $DLL_NAME. Please specify using --with-msvcr-dll.]) + AC_MSG_ERROR([Could not find $DLL_NAME. Please specify using ${DLL_HELP}.]) fi ]) @@ -587,7 +589,7 @@ AC_DEFUN([TOOLCHAIN_SETUP_VS_RUNTIME_DLLS], fi MSVCR_DLL="$MSVC_DLL" else - TOOLCHAIN_SETUP_MSVC_DLL([${MSVCR_NAME}]) + TOOLCHAIN_SETUP_MSVC_DLL([${MSVCR_NAME}], [--with-msvcr-dll]) MSVCR_DLL="$MSVC_DLL" fi AC_SUBST(MSVCR_DLL) @@ -610,7 +612,7 @@ AC_DEFUN([TOOLCHAIN_SETUP_VS_RUNTIME_DLLS], fi MSVCP_DLL="$MSVC_DLL" else - TOOLCHAIN_SETUP_MSVC_DLL([${MSVCP_NAME}]) + TOOLCHAIN_SETUP_MSVC_DLL([${MSVCP_NAME}], [--with-msvcp-dll]) MSVCP_DLL="$MSVC_DLL" fi AC_SUBST(MSVCP_DLL) @@ -635,7 +637,7 @@ AC_DEFUN([TOOLCHAIN_SETUP_VS_RUNTIME_DLLS], fi VCRUNTIME_1_DLL="$MSVC_DLL" else - TOOLCHAIN_SETUP_MSVC_DLL([${VCRUNTIME_1_NAME}]) + TOOLCHAIN_SETUP_MSVC_DLL([${VCRUNTIME_1_NAME}], [--with-vcruntime-1-dll]) VCRUNTIME_1_DLL="$MSVC_DLL" fi fi diff --git a/make/autoconf/util.m4 b/make/autoconf/util.m4 index 9ececc55e5ee8a420e7a9030e4374ed065b51a3f..15f41abafda9b492c112836b28e304c683e55c32 100644 --- a/make/autoconf/util.m4 +++ b/make/autoconf/util.m4 @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 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 @@ -230,20 +230,20 @@ AC_DEFUN([UTIL_GET_MATCHING_VALUES], # Converts an ISO-8601 date/time string to a unix epoch timestamp. If no # suitable conversion method was found, an empty string is returned. # -# Sets the specified variable to the resulting list. -# # $1: result variable name # $2: input date/time string AC_DEFUN([UTIL_GET_EPOCH_TIMESTAMP], [ - timestamp=$($DATE --utc --date=$2 +"%s" 2> /dev/null) - if test "x$timestamp" = x; then - # GNU date format did not work, try BSD date options - timestamp=$($DATE -j -f "%F %T" "$2" "+%s" 2> /dev/null) + if test "x$IS_GNU_DATE" = xyes; then + # GNU date + timestamp=$($DATE --utc --date=$2 +"%s" 2> /dev/null) + else + # BSD date + timestamp=$($DATE -u -j -f "%FZ %TZ" "$2" "+%s" 2> /dev/null) if test "x$timestamp" = x; then - # Perhaps the time was missing - timestamp=$($DATE -j -f "%F %T" "$2 00:00:00" "+%s" 2> /dev/null) - # If this did not work, we give up and return the empty string + # BSD date cannot handle trailing milliseconds. + # Try again ignoring characters at end + timestamp=$($DATE -u -j -f "%Y-%m-%dT%H:%M:%S" "$2" "+%s" 2> /dev/null) fi fi $1=$timestamp diff --git a/make/common/JarArchive.gmk b/make/common/JarArchive.gmk index d2a4ec103c455c62b98cfccd10cf79e72f20a0d0..26b08fc1509017fd18f138bbc8468a46f308c305 100644 --- a/make/common/JarArchive.gmk +++ b/make/common/JarArchive.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 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 @@ -193,7 +193,8 @@ define SetupJarArchiveBody $1_UPDATE_CONTENTS=\ if [ "`$(WC) -l $$($1_BIN)/_the.$$($1_JARNAME)_contents | $(AWK) '{ print $$$$1 }'`" -gt "0" ]; then \ $(ECHO) " updating" `$(WC) -l $$($1_BIN)/_the.$$($1_JARNAME)_contents | $(AWK) '{ print $$$$1 }'` files && \ - $$($1_JAR_CMD) $$($1_JAR_UPDATE_OPTIONS) $$@ @$$($1_BIN)/_the.$$($1_JARNAME)_contents; \ + $(SORT) $$($1_BIN)/_the.$$($1_JARNAME)_contents > $$($1_BIN)/_the.$$($1_JARNAME)_contents_sorted && \ + $$($1_JAR_CMD) --update $$($1_JAR_OPTIONS) --file $$@ @$$($1_BIN)/_the.$$($1_JARNAME)_contents_sorted; \ fi $$(NEWLINE) # The s-variants of the above macros are used when the jar is created from scratch. # NOTICE: please leave the parentheses space separated otherwise the AIX build will break! @@ -212,25 +213,29 @@ define SetupJarArchiveBody | $(SED) 's|$$(src)/|-C $$(src) |g' >> \ $$($1_BIN)/_the.$$($1_JARNAME)_contents) $$(NEWLINE) ) endif - $1_SUPDATE_CONTENTS=$$($1_JAR_CMD) $$($1_JAR_UPDATE_OPTIONS) $$@ @$$($1_BIN)/_the.$$($1_JARNAME)_contents $$(NEWLINE) + $1_SUPDATE_CONTENTS=\ + $(SORT) $$($1_BIN)/_the.$$($1_JARNAME)_contents > $$($1_BIN)/_the.$$($1_JARNAME)_contents_sorted && \ + $$($1_JAR_CMD) --update $$($1_JAR_OPTIONS) --file $$@ @$$($1_BIN)/_the.$$($1_JARNAME)_contents_sorted $$(NEWLINE) # Use a slightly shorter name for logging, but with enough path to identify this jar. $1_NAME:=$$(subst $$(OUTPUTDIR)/,,$$($1_JAR)) + # If reproducible build and the boot jdk jar supports --date option + # then specify the --date using SOURCE_DATE in ISO-8601 + $1_JAR_OPTIONS := + ifeq ($$(ENABLE_REPRODUCIBLE_BUILD), true) + ifeq ($$(BOOT_JDK_JAR_SUPPORTS_DATE), true) + $1_JAR_OPTIONS += --date $(SOURCE_DATE_ISO_8601) + endif + endif ifneq (,$$($1_CHECK_COMPRESS_JAR)) - $1_JAR_CREATE_OPTIONS := c0fm - $1_JAR_UPDATE_OPTIONS := u0f - ifeq ($(COMPRESS_JARS), true) - $1_JAR_CREATE_OPTIONS := cfm - $1_JAR_UPDATE_OPTIONS := uf + ifneq ($(COMPRESS_JARS), true) + $1_JAR_OPTIONS += --no-compress endif - else - $1_JAR_CREATE_OPTIONS := cfm - $1_JAR_UPDATE_OPTIONS := uf endif # Include all variables of significance in the vardeps file - $1_VARDEPS := $$($1_JAR_CMD) $$($1_JAR_CREATE_OPTIONS) $$($1_MANIFEST) \ + $1_VARDEPS := $$($1_JAR_CMD) $$($1_JAR_OPTIONS) $$($1_MANIFEST) \ $$($1_JARMAIN) $$($1_EXTRA_MANIFEST_ATTR) $$($1_ORIG_DEPS) $$($1_SRCS) \ $$($1_INCLUDES) $$($1_EXCLUDES) $$($1_EXCLUDE_FILES) $$($1_EXTRA_FILES) $1_VARDEPS_FILE := $$(call DependOnVariable, $1_VARDEPS, $$($1_BIN)/_the.$$($1_JARNAME).vardeps) @@ -255,7 +260,7 @@ define SetupJarArchiveBody $$(if $$($1_EXTRA_MANIFEST_ATTR), \ $(PRINTF) "$$($1_EXTRA_MANIFEST_ATTR)\n" >> $$($1_MANIFEST_FILE) $$(NEWLINE)) \ $(ECHO) Creating $$($1_NAME) $$(NEWLINE) \ - $$($1_JAR_CMD) $$($1_JAR_CREATE_OPTIONS) $$@ $$($1_MANIFEST_FILE) $$(NEWLINE) \ + $$($1_JAR_CMD) --create $$($1_JAR_OPTIONS) --file $$@ --manifest $$($1_MANIFEST_FILE) $$(NEWLINE) \ $$($1_SCAPTURE_CONTENTS) \ $$($1_SCAPTURE_METAINF) \ $$($1_SUPDATE_CONTENTS) \ diff --git a/make/common/TestFilesCompilation.gmk b/make/common/TestFilesCompilation.gmk index 01dc181d2c2ab2e3d89c93e18588b62c0cca929e..bb807ebf6b1761cd0bc94c0b517da4f8ca17ec26 100644 --- a/make/common/TestFilesCompilation.gmk +++ b/make/common/TestFilesCompilation.gmk @@ -62,11 +62,7 @@ define SetupTestFilesCompilationBody $1_OUTPUT_SUBDIR := lib $1_BASE_CFLAGS := $(CFLAGS_JDKLIB) $1_BASE_CXXFLAGS := $(CXXFLAGS_JDKLIB) - ifeq ($(call isTargetOs, windows), false) - $1_LDFLAGS := $(LDFLAGS_JDKLIB) $$(call SET_SHARED_LIBRARY_ORIGIN) -pthread - else - $1_LDFLAGS := $(LDFLAGS_JDKLIB) $$(call SET_SHARED_LIBRARY_ORIGIN) - endif + $1_LDFLAGS := $(LDFLAGS_JDKLIB) $$(call SET_SHARED_LIBRARY_ORIGIN) $1_COMPILATION_TYPE := LIBRARY else ifeq ($$($1_TYPE), PROGRAM) $1_PREFIX = exe diff --git a/make/common/ZipArchive.gmk b/make/common/ZipArchive.gmk index efa013f501ecf612c1f9bdf7c78476582471ad3d..592d1a60aa0f5c50cd63d1b3fa45afb4ee3e5db2 100644 --- a/make/common/ZipArchive.gmk +++ b/make/common/ZipArchive.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 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 @@ -26,6 +26,9 @@ ifndef _ZIP_ARCHIVE_GMK _ZIP_ARCHIVE_GMK := 1 +# Depends on build tools for MakeZipReproducible +include ../ToolsJdk.gmk + ifeq (,$(_MAKEBASE_GMK)) $(error You must include MakeBase.gmk prior to including ZipArchive.gmk) endif @@ -51,6 +54,8 @@ endif # FOLLOW_SYMLINKS - Set to explicitly follow symlinks. Affects performance of # finding files. # ZIP_OPTIONS extra options to pass to zip +# REPRODUCIBLE override ENABLE_REPRODUCIBLE_BUILD (to make zip reproducible or not) + SetupZipArchive = $(NamedParamsMacroTemplate) define SetupZipArchiveBody @@ -124,6 +129,10 @@ define SetupZipArchiveBody ) \ ) + ifeq ($$($1_REPRODUCIBLE), ) + $1_REPRODUCIBLE := $$(ENABLE_REPRODUCIBLE_BUILD) + endif + # Use a slightly shorter name for logging, but with enough path to identify this zip. $1_NAME:=$$(subst $$(OUTPUTDIR)/,,$$($1_ZIP)) @@ -134,6 +143,8 @@ define SetupZipArchiveBody # dir is very small. # If zip has nothing to do, it returns 12 and would fail the build. Check for 12 # and only fail if it's not. + # For reproducible builds set the zip access & modify times to SOURCE_DATE_EPOCH + # by using a ziptmp folder to generate final zip from using MakeZipReproducible. $$($1_ZIP) : $$($1_ALL_SRCS) $$($1_EXTRA_DEPS) $$(call LogWarn, Updating $$($1_NAME)) $$(call MakeTargetDir) @@ -163,7 +174,18 @@ define SetupZipArchiveBody $$($1_ZIP_EXCLUDES_$$s) \ || test "$$$$?" = "12" \ ))$$(NEWLINE) \ - ) true \ + ) true + ifeq ($$($1_REPRODUCIBLE), true) + $$(call ExecuteWithLog, \ + $$(SUPPORT_OUTPUTDIR)/makezipreproducible/$$(patsubst $$(OUTPUTDIR)/%,%, $$@), \ + ($(RM) $$(SUPPORT_OUTPUTDIR)/ziptmp/$1/tmp.zip && \ + $(MKDIR) -p $$(SUPPORT_OUTPUTDIR)/ziptmp/$1 && \ + $(TOOL_MAKEZIPREPRODUCIBLE) -f $$(SUPPORT_OUTPUTDIR)/ziptmp/$1/tmp.zip \ + -t $(SOURCE_DATE_EPOCH) $$@ && \ + $(RM) $$@ && \ + $(MV) $$(SUPPORT_OUTPUTDIR)/ziptmp/$1/tmp.zip $$@ \ + )) + endif $(TOUCH) $$@ # Add zip to target list diff --git a/make/common/modules/LauncherCommon.gmk b/make/common/modules/LauncherCommon.gmk index 7ad0375e2e38ff31419eb47d028a652c2dead647..85056bbe40f0c076ba7d2c9738b1c7a0be776a85 100644 --- a/make/common/modules/LauncherCommon.gmk +++ b/make/common/modules/LauncherCommon.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 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 @@ -33,13 +33,14 @@ include ToolsJdk.gmk # On Mac, we have always exported all symbols, probably due to oversight # and/or misunderstanding. To emulate this, don't hide any symbols # by default. -# On AIX/xlc we need at least xlc 13.1 for the symbol hiding (see JDK-8214063) # Also provide an override for non-conformant libraries. ifeq ($(TOOLCHAIN_TYPE), gcc) LAUNCHER_CFLAGS += -fvisibility=hidden LDFLAGS_JDKEXE += -Wl,--exclude-libs,ALL else ifeq ($(TOOLCHAIN_TYPE), clang) LAUNCHER_CFLAGS += -fvisibility=hidden +else ifeq ($(TOOLCHAIN_TYPE), xlc) + LAUNCHER_CFLAGS += -qvisibility=hidden endif LAUNCHER_SRC := $(TOPDIR)/src/java.base/share/native/launcher diff --git a/make/common/modules/LibCommon.gmk b/make/common/modules/LibCommon.gmk index 8ca3ddfffe9a606186ad0103fb4928330a390085..aa5c9f0a5c6b87415f853d88915335e5e9ad314a 100644 --- a/make/common/modules/LibCommon.gmk +++ b/make/common/modules/LibCommon.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 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 @@ -36,7 +36,6 @@ WIN_JAVA_LIB := $(SUPPORT_OUTPUTDIR)/native/java.base/libjava/java.lib # On Mac, we have always exported all symbols, probably due to oversight # and/or misunderstanding. To emulate this, don't hide any symbols # by default. -# On AIX/xlc we need at least xlc 13.1 for the symbol hiding (see JDK-8214063) # Also provide an override for non-conformant libraries. ifeq ($(TOOLCHAIN_TYPE), gcc) CFLAGS_JDKLIB += -fvisibility=hidden @@ -47,6 +46,10 @@ else ifeq ($(TOOLCHAIN_TYPE), clang) CFLAGS_JDKLIB += -fvisibility=hidden CXXFLAGS_JDKLIB += -fvisibility=hidden EXPORT_ALL_SYMBOLS := -fvisibility=default +else ifeq ($(TOOLCHAIN_TYPE), xlc) + CFLAGS_JDKLIB += -qvisibility=hidden + CXXFLAGS_JDKLIB += -qvisibility=hidden + EXPORT_ALL_SYMBOLS := -qvisibility=default endif # Put the libraries here. diff --git a/make/conf/jib-profiles.js b/make/conf/jib-profiles.js index 5fc212aa45223aef983b978641bc97864184255f..f16d7fd12e717f31831a949c7f3aafc2f3b6f0a2 100644 --- a/make/conf/jib-profiles.js +++ b/make/conf/jib-profiles.js @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -258,7 +258,6 @@ var getJibProfilesCommon = function (input, data) { common.release_profile_base = { configure_args: [ "--enable-reproducible-build", - "--with-source-date=current", ], }; // Extra settings for debug profiles @@ -450,7 +449,7 @@ var getJibProfilesProfiles = function (input, common, data) { "macosx-aarch64": { target_os: "macosx", target_cpu: "aarch64", - dependencies: ["devkit", "gtest"], + dependencies: ["devkit", "gtest", "pandoc"], configure_args: concat(common.configure_args_64bit, "--with-zlib=system", "--with-macosx-version-max=11.00.00"), }, @@ -1053,10 +1052,10 @@ var getJibProfilesProfiles = function (input, common, data) { var getJibProfilesDependencies = function (input, common) { var devkit_platform_revisions = { - linux_x64: "gcc10.3.0-OL6.4+1.0", + linux_x64: "gcc11.2.0-OL6.4+1.0", macosx: "Xcode12.4+1.0", windows_x64: "VS2019-16.9.3+1.0", - linux_aarch64: "gcc10.3.0-OL7.6+1.0", + linux_aarch64: "gcc11.2.0-OL7.6+1.0", linux_arm: "gcc8.2.0-Fedora27+1.0", linux_ppc64le: "gcc8.2.0-Fedora27+1.0", linux_s390x: "gcc8.2.0-Fedora27+1.0" @@ -1100,6 +1099,17 @@ var getJibProfilesDependencies = function (input, common) { environment_path: common.boot_jdk_home + "/bin" } + var pandoc_version; + if (input.build_cpu == "aarch64") { + if (input.build_os == "macosx") { + pandoc_version = "2.14.0.2+1.0"; + } else { + pandoc_version = "2.5+1.0"; + } + } else { + pandoc_version = "2.3.1+1.0"; + } + var makeBinDir = (input.build_os == "windows" ? input.get("gnumake", "install_path") + "/cygwin/bin" : input.get("gnumake", "install_path") + "/bin"); @@ -1154,19 +1164,12 @@ var getJibProfilesDependencies = function (input, common) { jmh: { organization: common.organization, ext: "tar.gz", - revision: "1.28+1.0" + revision: "1.34+1.0" }, jcov: { - // Use custom build of JCov - // See CODETOOLS-7902734 for more info. - // server: "jpg", - // product: "jcov", - // version: "3.0", - // build_number: "b07", - // file: "bundles/jcov-3_0.zip", organization: common.organization, - revision: "3.0-9-jdk-asm+1.0", + revision: "3.0-12-jdk-asm+1.0", ext: "zip", environment_name: "JCOV_HOME", }, @@ -1212,7 +1215,7 @@ var getJibProfilesDependencies = function (input, common) { pandoc: { organization: common.organization, ext: "tar.gz", - revision: (input.build_cpu == 'aarch64' ? "2.5+1.0" : "2.3.1+1.0"), + revision: pandoc_version, module: "pandoc-" + input.build_platform, configure_args: "PANDOC=" + input.get("pandoc", "install_path") + "/pandoc/pandoc", environment_path: input.get("pandoc", "install_path") + "/pandoc" @@ -1420,7 +1423,10 @@ var getVersion = function (feature, interim, update, patch, extra1, extra2, extr * other version inputs */ var versionArgs = function(input, common) { - var args = ["--with-version-build=" + common.build_number]; + var args = []; + if (common.build_number != 0) { + args = concat(args, "--with-version-build=" + common.build_number); + } if (input.build_type == "promoted") { args = concat(args, "--with-version-pre=" + version_numbers.get("DEFAULT_PROMOTED_VERSION_PRE"), @@ -1440,6 +1446,14 @@ var versionArgs = function(input, common) { } else { args = concat(args, "--with-version-opt=" + common.build_id); } + var sourceDate + if (input.build_id_data && input.build_id_data.creationTime) { + sourceDate = Math.floor(Date.parse(input.build_id_data.creationTime)/1000); + } else { + sourceDate = "current"; + } + args = concat(args, "--with-source-date=" + sourceDate); + return args; } diff --git a/make/conf/version-numbers.conf b/make/conf/version-numbers.conf index 2d12d668a71051fad460bebc8a7a6027a2706e9f..3cb6b4341b52b0117a47495f6af8161df8a7c076 100644 --- a/make/conf/version-numbers.conf +++ b/make/conf/version-numbers.conf @@ -26,17 +26,17 @@ # Default version, product, and vendor information to use, # unless overridden by configure -DEFAULT_VERSION_FEATURE=18 +DEFAULT_VERSION_FEATURE=19 DEFAULT_VERSION_INTERIM=0 DEFAULT_VERSION_UPDATE=0 DEFAULT_VERSION_PATCH=0 DEFAULT_VERSION_EXTRA1=0 DEFAULT_VERSION_EXTRA2=0 DEFAULT_VERSION_EXTRA3=0 -DEFAULT_VERSION_DATE=2022-03-15 -DEFAULT_VERSION_CLASSFILE_MAJOR=62 # "`$EXPR $DEFAULT_VERSION_FEATURE + 44`" +DEFAULT_VERSION_DATE=2022-09-20 +DEFAULT_VERSION_CLASSFILE_MAJOR=63 # "`$EXPR $DEFAULT_VERSION_FEATURE + 44`" DEFAULT_VERSION_CLASSFILE_MINOR=0 DEFAULT_VERSION_DOCS_API_SINCE=11 -DEFAULT_ACCEPTABLE_BOOT_VERSIONS="17 18" -DEFAULT_JDK_SOURCE_TARGET_VERSION=18 +DEFAULT_ACCEPTABLE_BOOT_VERSIONS="17 18 19" +DEFAULT_JDK_SOURCE_TARGET_VERSION=19 DEFAULT_PROMOTED_VERSION_PRE=ea diff --git a/make/data/hotspot-symbols/symbols-unix b/make/data/hotspot-symbols/symbols-unix index d735f61b3a456bc9878949861043ebb995eceed7..d51fcb3727d2b97601d790d1a2d52eb559348c14 100644 --- a/make/data/hotspot-symbols/symbols-unix +++ b/make/data/hotspot-symbols/symbols-unix @@ -1,5 +1,5 @@ # -# Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. +# 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 @@ -147,6 +147,7 @@ JVM_IsArrayClass JVM_IsCDSDumpingEnabled JVM_IsConstructorIx JVM_IsDumpingClassList +JVM_IsFinalizationEnabled JVM_IsHiddenClass JVM_IsInterface JVM_IsPrimitiveClass @@ -157,6 +158,7 @@ JVM_IsSupportedJNIVersion JVM_IsThreadAlive JVM_IsVMGeneratedMethodIx JVM_LatestUserDefinedLoader +JVM_LoadZipLibrary JVM_LoadLibrary JVM_LookupDefineClass JVM_LookupLambdaProxyClassFromArchive diff --git a/make/data/publicsuffixlist/VERSION b/make/data/publicsuffixlist/VERSION deleted file mode 100644 index 3367b24a0be6ffa9c2c00af11c65423987ebb9a0..0000000000000000000000000000000000000000 --- a/make/data/publicsuffixlist/VERSION +++ /dev/null @@ -1,2 +0,0 @@ -Github: https://raw.githubusercontent.com/publicsuffix/list/cbbba1d234670453df9c930dfbf510c0474d4301/public_suffix_list.dat -Date: 2020-04-24 diff --git a/make/data/symbols/jdk.incubator.vector-H.sym.txt b/make/data/symbols/jdk.incubator.vector-H.sym.txt deleted file mode 100644 index a815726e54b3835248f19404d7ebd8971772591a..0000000000000000000000000000000000000000 --- a/make/data/symbols/jdk.incubator.vector-H.sym.txt +++ /dev/null @@ -1,54 +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. Oracle designates this -# particular file as subject to the "Classpath" exception as provided -# by Oracle in the LICENSE file that accompanied this code. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# -# ########################################################## -# ### THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. ### -# ########################################################## -# -class name jdk/incubator/vector/ByteVector -method name fromBooleanArray descriptor (Ljdk/incubator/vector/VectorSpecies;[ZI)Ljdk/incubator/vector/ByteVector; flags 9 signature (Ljdk/incubator/vector/VectorSpecies;[ZI)Ljdk/incubator/vector/ByteVector; runtimeAnnotations @Ljdk/internal/vm/annotation/ForceInline; -method name fromBooleanArray descriptor (Ljdk/incubator/vector/VectorSpecies;[ZILjdk/incubator/vector/VectorMask;)Ljdk/incubator/vector/ByteVector; flags 9 signature (Ljdk/incubator/vector/VectorSpecies;[ZILjdk/incubator/vector/VectorMask;)Ljdk/incubator/vector/ByteVector; runtimeAnnotations @Ljdk/internal/vm/annotation/ForceInline; -method name fromBooleanArray descriptor (Ljdk/incubator/vector/VectorSpecies;[ZI[II)Ljdk/incubator/vector/ByteVector; flags 9 signature (Ljdk/incubator/vector/VectorSpecies;[ZI[II)Ljdk/incubator/vector/ByteVector; runtimeAnnotations @Ljdk/internal/vm/annotation/ForceInline; -method name fromBooleanArray descriptor (Ljdk/incubator/vector/VectorSpecies;[ZI[IILjdk/incubator/vector/VectorMask;)Ljdk/incubator/vector/ByteVector; flags 9 signature (Ljdk/incubator/vector/VectorSpecies;[ZI[IILjdk/incubator/vector/VectorMask;)Ljdk/incubator/vector/ByteVector; runtimeAnnotations @Ljdk/internal/vm/annotation/ForceInline; -method name intoBooleanArray descriptor ([ZI)V flags 11 runtimeAnnotations @Ljdk/internal/vm/annotation/ForceInline; -method name intoBooleanArray descriptor ([ZILjdk/incubator/vector/VectorMask;)V flags 11 signature ([ZILjdk/incubator/vector/VectorMask;)V runtimeAnnotations @Ljdk/internal/vm/annotation/ForceInline; -method name intoBooleanArray descriptor ([ZI[II)V flags 11 runtimeAnnotations @Ljdk/internal/vm/annotation/ForceInline; -method name intoBooleanArray descriptor ([ZI[IILjdk/incubator/vector/VectorMask;)V flags 11 signature ([ZI[IILjdk/incubator/vector/VectorMask;)V runtimeAnnotations @Ljdk/internal/vm/annotation/ForceInline; - -class name jdk/incubator/vector/ShortVector -method name fromCharArray descriptor (Ljdk/incubator/vector/VectorSpecies;[CI)Ljdk/incubator/vector/ShortVector; flags 9 signature (Ljdk/incubator/vector/VectorSpecies;[CI)Ljdk/incubator/vector/ShortVector; runtimeAnnotations @Ljdk/internal/vm/annotation/ForceInline; -method name fromCharArray descriptor (Ljdk/incubator/vector/VectorSpecies;[CILjdk/incubator/vector/VectorMask;)Ljdk/incubator/vector/ShortVector; flags 9 signature (Ljdk/incubator/vector/VectorSpecies;[CILjdk/incubator/vector/VectorMask;)Ljdk/incubator/vector/ShortVector; runtimeAnnotations @Ljdk/internal/vm/annotation/ForceInline; -method name fromCharArray descriptor (Ljdk/incubator/vector/VectorSpecies;[CI[II)Ljdk/incubator/vector/ShortVector; flags 9 signature (Ljdk/incubator/vector/VectorSpecies;[CI[II)Ljdk/incubator/vector/ShortVector; runtimeAnnotations @Ljdk/internal/vm/annotation/ForceInline; -method name fromCharArray descriptor (Ljdk/incubator/vector/VectorSpecies;[CI[IILjdk/incubator/vector/VectorMask;)Ljdk/incubator/vector/ShortVector; flags 9 signature (Ljdk/incubator/vector/VectorSpecies;[CI[IILjdk/incubator/vector/VectorMask;)Ljdk/incubator/vector/ShortVector; runtimeAnnotations @Ljdk/internal/vm/annotation/ForceInline; -method name intoCharArray descriptor ([CI)V flags 11 runtimeAnnotations @Ljdk/internal/vm/annotation/ForceInline; -method name intoCharArray descriptor ([CILjdk/incubator/vector/VectorMask;)V flags 11 signature ([CILjdk/incubator/vector/VectorMask;)V runtimeAnnotations @Ljdk/internal/vm/annotation/ForceInline; -method name intoCharArray descriptor ([CI[II)V flags 11 runtimeAnnotations @Ljdk/internal/vm/annotation/ForceInline; -method name intoCharArray descriptor ([CI[IILjdk/incubator/vector/VectorMask;)V flags 11 signature ([CI[IILjdk/incubator/vector/VectorMask;)V runtimeAnnotations @Ljdk/internal/vm/annotation/ForceInline; - -class name jdk/incubator/vector/VectorOperators -field name UNSIGNED_LT descriptor Ljdk/incubator/vector/VectorOperators$Comparison; flags 19 -field name UNSIGNED_LE descriptor Ljdk/incubator/vector/VectorOperators$Comparison; flags 19 -field name UNSIGNED_GT descriptor Ljdk/incubator/vector/VectorOperators$Comparison; flags 19 -field name UNSIGNED_GE descriptor Ljdk/incubator/vector/VectorOperators$Comparison; flags 19 - diff --git a/make/data/unicodedata/VERSION b/make/data/unicodedata/VERSION deleted file mode 100644 index 02161ca86e5e8ecad11b9b69fbb8b4564dae144f..0000000000000000000000000000000000000000 --- a/make/data/unicodedata/VERSION +++ /dev/null @@ -1 +0,0 @@ -13.0.0 diff --git a/make/devkit/Tools.gmk b/make/devkit/Tools.gmk index 19eccf89be2ac185f32d6dd7432671e22f80206a..e94a74d0063e1a254f7e92d8be720bcc7b0a5d92 100644 --- a/make/devkit/Tools.gmk +++ b/make/devkit/Tools.gmk @@ -87,8 +87,17 @@ endif # Define external dependencies # Latest that could be made to work. -GCC_VER := 10.3.0 -ifeq ($(GCC_VER), 10.3.0) +GCC_VER := 11.2.0 +ifeq ($(GCC_VER), 11.2.0) + gcc_ver := gcc-11.2.0 + binutils_ver := binutils-2.37 + ccache_ver := ccache-3.7.12 + mpfr_ver := mpfr-4.1.0 + gmp_ver := gmp-6.2.1 + mpc_ver := mpc-1.2.1 + gdb_ver := gdb-11.1 + REQUIRED_MIN_MAKE_MAJOR_VERSION := 4 +else ifeq ($(GCC_VER), 10.3.0) gcc_ver := gcc-10.3.0 binutils_ver := binutils-2.36.1 ccache_ver := ccache-3.7.11 diff --git a/make/devkit/createJMHBundle.sh b/make/devkit/createJMHBundle.sh index d34c9939ff07b58d90dcd6f50dee1ef9d733c3fc..059fb7acb6fb9fdb5722b6b288bee40d8421169a 100644 --- a/make/devkit/createJMHBundle.sh +++ b/make/devkit/createJMHBundle.sh @@ -26,7 +26,7 @@ # Create a bundle in the build directory, containing what's needed to # build and run JMH microbenchmarks from the OpenJDK build. -JMH_VERSION=1.33 +JMH_VERSION=1.34 COMMONS_MATH3_VERSION=3.2 JOPT_SIMPLE_VERSION=4.6 diff --git a/make/hotspot/gensrc/GensrcAdlc.gmk b/make/hotspot/gensrc/GensrcAdlc.gmk index f9f1bb3868879e9fe5a95fa551e142ca7a6f4416..25c132729142e426262022a700f1e925edd09972 100644 --- a/make/hotspot/gensrc/GensrcAdlc.gmk +++ b/make/hotspot/gensrc/GensrcAdlc.gmk @@ -149,6 +149,7 @@ ifeq ($(call check-jvm-feature, compiler2), true) ifeq ($(call check-jvm-feature, shenandoahgc), true) AD_SRC_FILES += $(call uniq, $(wildcard $(foreach d, $(AD_SRC_ROOTS), \ $d/cpu/$(HOTSPOT_TARGET_CPU_ARCH)/gc/shenandoah/shenandoah_$(HOTSPOT_TARGET_CPU).ad \ + $d/cpu/$(HOTSPOT_TARGET_CPU_ARCH)/gc/shenandoah/shenandoah_$(HOTSPOT_TARGET_CPU_ARCH).ad \ ))) endif diff --git a/make/hotspot/lib/CompileGtest.gmk b/make/hotspot/lib/CompileGtest.gmk index cb2bbccc1686aa4a28a8f8557523eee75d0b80ca..f16b9a747bcc435320386cf394b0e183a8bac6d2 100644 --- a/make/hotspot/lib/CompileGtest.gmk +++ b/make/hotspot/lib/CompileGtest.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. +# 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 @@ -49,7 +49,7 @@ $(eval $(call SetupJdkLibrary, BUILD_GTEST_LIBGTEST, \ $(GTEST_FRAMEWORK_SRC)/googletest/src \ $(GTEST_FRAMEWORK_SRC)/googlemock/src, \ INCLUDE_FILES := gtest-all.cc gmock-all.cc, \ - DISABLED_WARNINGS_gcc := undef unused-result format-nonliteral, \ + DISABLED_WARNINGS_gcc := undef unused-result format-nonliteral maybe-uninitialized, \ DISABLED_WARNINGS_clang := undef unused-result format-nonliteral, \ CFLAGS := $(JVM_CFLAGS) \ -I$(GTEST_FRAMEWORK_SRC)/googletest \ diff --git a/make/hotspot/lib/CompileJvm.gmk b/make/hotspot/lib/CompileJvm.gmk index 65edd047571c3318d3d838df1682977298a7de13..7c702d853d07014254d77ec41dc1a76a0dd80779 100644 --- a/make/hotspot/lib/CompileJvm.gmk +++ b/make/hotspot/lib/CompileJvm.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2013, 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 @@ -61,6 +61,11 @@ else OPENJDK_TARGET_CPU_VM_VERSION := $(OPENJDK_TARGET_CPU) endif +ifeq ($(VERSION_BUILD), ) + # Hotspot cannot handle an empty build number + VERSION_BUILD := 0 +endif + CFLAGS_VM_VERSION := \ $(VERSION_CFLAGS) \ -DHOTSPOT_VERSION_STRING='"$(VERSION_STRING)"' \ diff --git a/make/hotspot/lib/JvmFeatures.gmk b/make/hotspot/lib/JvmFeatures.gmk index ab555f9d82d4e7cb01e271fa0807c7673a544293..07ce6feaf6f692cbfcc70c7a903f04b73e9b066a 100644 --- a/make/hotspot/lib/JvmFeatures.gmk +++ b/make/hotspot/lib/JvmFeatures.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2013, 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 @@ -130,13 +130,6 @@ ifneq ($(call check-jvm-feature, cds), true) JVM_EXCLUDE_PATTERNS += cds/ endif -ifneq ($(call check-jvm-feature, nmt), true) - JVM_CFLAGS_FEATURES += -DINCLUDE_NMT=0 - JVM_EXCLUDE_FILES += \ - memBaseline.cpp memReporter.cpp mallocTracker.cpp virtualMemoryTracker.cpp nmtCommon.cpp \ - memTracker.cpp nmtDCmd.cpp mallocSiteTable.cpp threadStackTracker.cpp -endif - ifneq ($(call check-jvm-feature, g1gc), true) JVM_CFLAGS_FEATURES += -DINCLUDE_G1GC=0 JVM_EXCLUDE_PATTERNS += gc/g1 diff --git a/make/ide/vscode/hotspot/CreateVSCodeProject.gmk b/make/ide/vscode/hotspot/CreateVSCodeProject.gmk index 8b82c38a7518e2ef866e50cb81ce65d27d63a310..bc56e878de6f34add01103c1e0570d136fa85fba 100644 --- a/make/ide/vscode/hotspot/CreateVSCodeProject.gmk +++ b/make/ide/vscode/hotspot/CreateVSCodeProject.gmk @@ -29,6 +29,13 @@ default: all include $(SPEC) include MakeBase.gmk +################################################################################ +# SedEscape +# +# Escape special characters for use in SED replacement string +################################################################################ +SedEscape = $(subst !,\!,$(subst \,\\,$1)) + ################################################################################ # Return the full path to an indexer-specific file fragment. # @@ -78,15 +85,15 @@ define CreateFromTemplate $(SED) -e '/{{INDEXER_EXTENSIONS}}/r $(call GetIndexerFragment,extensions)' \ -e '/{{INDEXER_SETTINGS}}/r $(call GetIndexerFragment,settings)' \ -e '/{{EXTRA_WORKSPACE_ROOT}}/r $(call GetExtraWorkspaceRoot)' $1 | \ - $(SED) -e 's!{{TOPDIR}}!$(call FixPath,$(TOPDIR))!g' \ - -e 's!{{TOPDIR_RELATIVE}}!$(call FixPath,$(strip \ - $(call RelativePath,$(OUTPUTDIR),$(TOPDIR))))!g' \ - -e 's!{{WORKSPACE_ROOT}}!$(call FixPath,$(WORKSPACE_ROOT))!g' \ - -e 's!{{OUTPUTDIR}}!$(call FixPath,$(OUTPUTDIR))!g' \ + $(SED) -e 's!{{TOPDIR}}!$(call SedEscape,$(call FixPath,$(TOPDIR)))!g' \ + -e 's!{{TOPDIR_RELATIVE}}!$(call SedEscape,$(call FixPath,$(strip \ + $(call RelativePath,$(OUTPUTDIR),$(TOPDIR)))))!g' \ + -e 's!{{WORKSPACE_ROOT}}!$(call SedEscape,$(call FixPath,$(WORKSPACE_ROOT)))!g' \ + -e 's!{{OUTPUTDIR}}!$(call SedEscape,$(call FixPath,$(OUTPUTDIR)))!g' \ -e 's!{{CONF_NAME}}!$(CONF_NAME)!g' \ - -e 's!{{COMPILER}}!$(call FixPath,$(CXX)) $(SYSROOT_CFLAGS)!g' \ - -e 's!{{MAKE}}!$(call FixPath,$(MAKE))!g' \ - -e 's!{{PATH}}!$(call FixPath,$(PATH))!g' \ + -e 's!{{COMPILER}}!$(call SedEscape,$(call FixPath,$(CXX))) $(SYSROOT_CFLAGS)!g' \ + -e 's!{{MAKE}}!$(call SedEscape,$(call FixPath,$(MAKE)))!g' \ + -e 's!{{PATH}}!$(call SedEscape,$(call FixPath,$(PATH)))!g' \ -e 's!{{DEBUGENGINENAME}}!$(call DebugEngineName)!g' \ -e '/{{INDEXER_EXTENSIONS}}/d' \ -e '/{{INDEXER_SETTINGS}}/d' \ diff --git a/make/jdk/src/classes/build/tools/cldrconverter/Bundle.java b/make/jdk/src/classes/build/tools/cldrconverter/Bundle.java index 9f262fa010608157d8bbcfb417cfd1b1cb7d5392..952e28fd43bbbf4193347c7db6e1f79e75756ee1 100644 --- a/make/jdk/src/classes/build/tools/cldrconverter/Bundle.java +++ b/make/jdk/src/classes/build/tools/cldrconverter/Bundle.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -25,6 +25,9 @@ package build.tools.cldrconverter; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.ArrayList; import java.util.Arrays; import java.util.EnumSet; @@ -34,6 +37,7 @@ import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Optional; +import java.util.stream.Collectors; import java.util.stream.IntStream; class Bundle { @@ -47,21 +51,21 @@ class Bundle { FORMATDATA); } - private final static Map bundles = new HashMap<>(); + private static final Map bundles = new HashMap<>(); - private final static String[] NUMBER_PATTERN_KEYS = { + private static final String[] NUMBER_PATTERN_KEYS = { "NumberPatterns/decimal", "NumberPatterns/currency", "NumberPatterns/percent", "NumberPatterns/accounting" }; - private final static String[] COMPACT_NUMBER_PATTERN_KEYS = { - "short.CompactNumberPatterns", - "long.CompactNumberPatterns" + private static final String[] COMPACT_NUMBER_PATTERN_KEYS = { + "short.CompactNumberPatterns", + "long.CompactNumberPatterns" }; - private final static String[] NUMBER_ELEMENT_KEYS = { + private static final String[] NUMBER_ELEMENT_KEYS = { "NumberElements/decimal", "NumberElements/group", "NumberElements/list", @@ -77,41 +81,45 @@ class Bundle { "NumberElements/currencyGroup", }; - private final static String[] TIME_PATTERN_KEYS = { + private static final String[] TIME_PATTERN_KEYS = { "DateTimePatterns/full-time", "DateTimePatterns/long-time", "DateTimePatterns/medium-time", "DateTimePatterns/short-time", }; - private final static String[] DATE_PATTERN_KEYS = { + private static final String[] DATE_PATTERN_KEYS = { "DateTimePatterns/full-date", "DateTimePatterns/long-date", "DateTimePatterns/medium-date", "DateTimePatterns/short-date", }; - private final static String[] DATETIME_PATTERN_KEYS = { + private static final String[] DATETIME_PATTERN_KEYS = { "DateTimePatterns/full-dateTime", "DateTimePatterns/long-dateTime", "DateTimePatterns/medium-dateTime", "DateTimePatterns/short-dateTime", }; - private final static String[] ERA_KEYS = { + private static final String[] ERA_KEYS = { "long.Eras", "Eras", "narrow.Eras" }; + // DateFormatItem prefix + static final String DATEFORMATITEM_KEY_PREFIX = "DateFormatItem."; + static final String DATEFORMATITEM_INPUT_REGIONS_PREFIX = "DateFormatItemInputRegions."; + // Keys for individual time zone names - private final static String TZ_GEN_LONG_KEY = "timezone.displayname.generic.long"; - private final static String TZ_GEN_SHORT_KEY = "timezone.displayname.generic.short"; - private final static String TZ_STD_LONG_KEY = "timezone.displayname.standard.long"; - private final static String TZ_STD_SHORT_KEY = "timezone.displayname.standard.short"; - private final static String TZ_DST_LONG_KEY = "timezone.displayname.daylight.long"; - private final static String TZ_DST_SHORT_KEY = "timezone.displayname.daylight.short"; - private final static String[] ZONE_NAME_KEYS = { + private static final String TZ_GEN_LONG_KEY = "timezone.displayname.generic.long"; + private static final String TZ_GEN_SHORT_KEY = "timezone.displayname.generic.short"; + private static final String TZ_STD_LONG_KEY = "timezone.displayname.standard.long"; + private static final String TZ_STD_SHORT_KEY = "timezone.displayname.standard.short"; + private static final String TZ_DST_LONG_KEY = "timezone.displayname.daylight.long"; + private static final String TZ_DST_SHORT_KEY = "timezone.displayname.daylight.short"; + private static final String[] ZONE_NAME_KEYS = { TZ_STD_LONG_KEY, TZ_STD_SHORT_KEY, TZ_DST_LONG_KEY, @@ -262,7 +270,7 @@ class Bundle { CLDRConverter.handleAliases(myMap); // another hack: parentsMap is not used for date-time resources. - if ("root".equals(id)) { + if (isRoot()) { parentsMap = null; } @@ -287,6 +295,14 @@ class Bundle { handleDateTimeFormatPatterns(TIME_PATTERN_KEYS, myMap, parentsMap, calendarType, "TimePatterns"); handleDateTimeFormatPatterns(DATE_PATTERN_KEYS, myMap, parentsMap, calendarType, "DatePatterns"); handleDateTimeFormatPatterns(DATETIME_PATTERN_KEYS, myMap, parentsMap, calendarType, "DateTimePatterns"); + + // Skeleton + handleSkeletonPatterns(myMap, calendarType); + } + + // Skeleton input regions + if (isRoot()) { + skeletonInputRegions(myMap); } // First, weed out any empty timezone or metazone names from myMap. @@ -647,8 +663,9 @@ class Bundle { private void convertDateTimePatternLetter(CalendarType calendarType, char cldrLetter, int count, StringBuilder sb) { switch (cldrLetter) { case 'u': - // Change cldr letter 'u' to 'y', as 'u' is interpreted as - // "Extended year (numeric)" in CLDR/LDML, + case 'U': + // Change cldr letter 'u'/'U' to 'y', as 'u' is interpreted as + // "Extended year (numeric)", and 'U' as "Cyclic year" in CLDR/LDML, // which is not supported in SimpleDateFormat and // j.t.f.DateTimeFormatter, so it is replaced with 'y' // as the best approximation @@ -742,6 +759,19 @@ class Bundle { return false; } + private void handleSkeletonPatterns(Map myMap, CalendarType calendarType) { + String calendarPrefix = calendarType.keyElementName(); + myMap.putAll(myMap.entrySet().stream() + .filter(e -> e.getKey().startsWith(Bundle.DATEFORMATITEM_KEY_PREFIX)) + .collect(Collectors.toMap( + e -> calendarPrefix + e.getKey(), + e -> translateDateFormatLetters(calendarType, + (String)e.getValue(), + this::convertDateTimePatternLetter) + )) + ); + } + @FunctionalInterface private interface ConvertDateTimeLetters { void convert(CalendarType calendarType, char cldrLetter, int count, StringBuilder sb); @@ -790,4 +820,14 @@ class Bundle { } return numArray; } + + private static void skeletonInputRegions(Map myMap) { + myMap.putAll(myMap.entrySet().stream() + .filter(e -> e.getKey().startsWith(Bundle.DATEFORMATITEM_INPUT_REGIONS_PREFIX)) + .collect(Collectors.toMap( + e -> e.getKey(), + e -> ((String)e.getValue()).trim() + )) + ); + } } diff --git a/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java b/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java index 5fd7a583a422fe1754c131122c83dd27f1aa1d6a..abf1be6430630ba5e737c508f992a1e31ad8eece 100644 --- a/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java +++ b/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -114,6 +114,7 @@ public class CLDRConverter { ResourceBundle.Control.getControl(ResourceBundle.Control.FORMAT_DEFAULT); private static Set AVAILABLE_TZIDS; + static int copyrightYear; private static String zoneNameTempFile; private static String tzDataDir; private static final Map canonicalTZMap = new HashMap<>(); @@ -217,6 +218,10 @@ public class CLDRConverter { verbose = true; break; + case "-year": + copyrightYear = Integer.parseInt(args[++i]); + break; + case "-zntempfile": zoneNameTempFile = args[++i]; break; @@ -235,7 +240,7 @@ public class CLDRConverter { } } } catch (RuntimeException e) { - severe("unknown or imcomplete arg(s): " + currentArg); + severe("unknown or incomplete arg(s): " + currentArg); usage(); System.exit(1); } @@ -260,6 +265,10 @@ public class CLDRConverter { setupBaseLocales("en-US"); } + if (copyrightYear == 0) { + copyrightYear = ZonedDateTime.now(ZoneId.of("America/Los_Angeles")).getYear(); + } + bundleGenerator = new ResourceBundleGenerator(); // Parse data independent of locales @@ -292,6 +301,7 @@ public class CLDRConverter { + "\t-basemodule generates bundles that go into java.base module%n" + "\t-baselocales loc(,loc)* locales that go into the base module%n" + "\t-o dir output directory (default: ./build/gensrc)%n" + + "\t-year year copyright year in output%n" + "\t-zntempfile template file for java.time.format.ZoneName.java%n" + "\t-tzdatadir tzdata directory for java.time.format.ZoneName.java%n" + "\t-utf8 use UTF-8 rather than \\uxxxx (for debug)%n"); @@ -837,20 +847,19 @@ public class CLDRConverter { "DateTimePatternChars", "PluralRules", "DayPeriodRules", + "DateFormatItem", }; private static Map extractFormatData(Map map, String id) { Map formatData = new LinkedHashMap<>(); for (CalendarType calendarType : CalendarType.values()) { - if (calendarType == CalendarType.GENERIC) { - continue; - } String prefix = calendarType.keyElementName(); - for (String element : FORMAT_DATA_ELEMENTS) { - String key = prefix + element; - copyIfPresent(map, "java.time." + key, formatData); - copyIfPresent(map, key, formatData); - } + Arrays.stream(FORMAT_DATA_ELEMENTS) + .flatMap(elem -> map.keySet().stream().filter(k -> k.startsWith(prefix + elem))) + .forEach(key -> { + copyIfPresent(map, "java.time." + key, formatData); + copyIfPresent(map, key, formatData); + }); } for (String key : map.keySet()) { @@ -858,9 +867,6 @@ public class CLDRConverter { if (key.startsWith(CLDRConverter.LOCALE_TYPE_PREFIX_CA)) { String type = key.substring(CLDRConverter.LOCALE_TYPE_PREFIX_CA.length()); for (CalendarType calendarType : CalendarType.values()) { - if (calendarType == CalendarType.GENERIC) { - continue; - } if (type.equals(calendarType.lname())) { Object value = map.get(key); String dataKey = key.replace(LOCALE_TYPE_PREFIX_CA, diff --git a/make/jdk/src/classes/build/tools/cldrconverter/CopyrightHeaders.java b/make/jdk/src/classes/build/tools/cldrconverter/CopyrightHeaders.java index 16062de116fc15d8c52d1dda255f4c7b33cc0e84..d1ea90a54c6dcb6f10d725ecedcdafd78ca2315e 100644 --- a/make/jdk/src/classes/build/tools/cldrconverter/CopyrightHeaders.java +++ b/make/jdk/src/classes/build/tools/cldrconverter/CopyrightHeaders.java @@ -26,6 +26,7 @@ package build.tools.cldrconverter; import java.util.Calendar; +import java.util.Date; import java.util.GregorianCalendar; import java.util.Locale; import java.util.TimeZone; @@ -131,8 +132,7 @@ class CopyrightHeaders { " * questions.\n" + " */\n"; - static String getOracleCopyright() { - int year = getYear(); + static String getOracleCopyright(int year) { return String.format(year > 2012 ? ORACLE_AFTER2012 : ORACLE2012, year); } @@ -140,16 +140,10 @@ class CopyrightHeaders { return UNICODE; } - static String getOpenJDKCopyright() { - int year = getYear(); + static String getOpenJDKCopyright(int year) { return String.format(year > 2012 ? OPENJDK_AFTER2012 : OPENJDK2012, year); } - private static int getYear() { - return new GregorianCalendar(TimeZone.getTimeZone("America/Los_Angeles"), - Locale.US).get(Calendar.YEAR); - } - // no instantiation private CopyrightHeaders() { } diff --git a/make/jdk/src/classes/build/tools/cldrconverter/LDMLParseHandler.java b/make/jdk/src/classes/build/tools/cldrconverter/LDMLParseHandler.java index 745796d96cf500932577db0f9f84d9569270b99a..668c187c383c128fecd61e5cccf7a7f8996774cf 100644 --- a/make/jdk/src/classes/build/tools/cldrconverter/LDMLParseHandler.java +++ b/make/jdk/src/classes/build/tools/cldrconverter/LDMLParseHandler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -756,6 +756,14 @@ class LDMLParseHandler extends AbstractLDMLHandler { pushStringEntry(qName, attributes, prefix + "DateTimePatterns/" + attributes.getValue("type") + "-dateTime"); } break; + case "dateFormatItem": + { + // for FormatData + String prefix = (currentCalendarType == null) ? "" : currentCalendarType.keyElementName(); + pushStringEntry(qName, attributes, + prefix + Bundle.DATEFORMATITEM_KEY_PREFIX + attributes.getValue("id")); + } + break; case "localizedPatternChars": { // for FormatData @@ -1113,7 +1121,7 @@ class LDMLParseHandler extends AbstractLDMLHandler { if (id.equals("root") && key.startsWith("MonthNames")) { value = new DateFormatSymbols(Locale.US).getShortMonths(); } - return put(entry.getKey(), value); + return put(key, value); } } return null; diff --git a/make/jdk/src/classes/build/tools/cldrconverter/ResourceBundleGenerator.java b/make/jdk/src/classes/build/tools/cldrconverter/ResourceBundleGenerator.java index 9c95717edb2855b6df4aea62ce13ee31bc2aacd4..34ce822ab649c83f0bf446d768c94ff6f7631b02 100644 --- a/make/jdk/src/classes/build/tools/cldrconverter/ResourceBundleGenerator.java +++ b/make/jdk/src/classes/build/tools/cldrconverter/ResourceBundleGenerator.java @@ -198,7 +198,7 @@ class ResourceBundleGenerator implements BundleGenerator { try (PrintWriter out = new PrintWriter(file, encoding)) { // Output copyright headers - out.println(CopyrightHeaders.getOpenJDKCopyright()); + out.println(CopyrightHeaders.getOpenJDKCopyright(CLDRConverter.copyrightYear)); out.println(CopyrightHeaders.getUnicodeCopyright()); if (useJava) { @@ -266,7 +266,7 @@ class ResourceBundleGenerator implements BundleGenerator { CLDRConverter.info("Generating file " + file); try (PrintWriter out = new PrintWriter(file, "us-ascii")) { - out.printf(CopyrightHeaders.getOpenJDKCopyright()); + out.printf(CopyrightHeaders.getOpenJDKCopyright(CLDRConverter.copyrightYear)); out.printf((CLDRConverter.isBaseModule ? "package sun.util.cldr;\n\n" : "package sun.util.resources.cldr.provider;\n\n") diff --git a/make/jdk/src/classes/build/tools/cldrconverter/SupplementDataParseHandler.java b/make/jdk/src/classes/build/tools/cldrconverter/SupplementDataParseHandler.java index fdc8a97776615fa227613f63ed54acb0990578af..11547ccb38e3f9da0e1c710ac47360ddd9802819 100644 --- a/make/jdk/src/classes/build/tools/cldrconverter/SupplementDataParseHandler.java +++ b/make/jdk/src/classes/build/tools/cldrconverter/SupplementDataParseHandler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -27,8 +27,12 @@ package build.tools.cldrconverter; import java.io.File; import java.io.IOException; +import java.util.Arrays; import java.util.HashMap; import java.util.Map; +import java.util.SortedSet; +import java.util.TreeSet; +import java.util.stream.Collectors; import org.xml.sax.Attributes; import org.xml.sax.InputSource; import org.xml.sax.SAXException; @@ -62,10 +66,15 @@ class SupplementDataParseHandler extends AbstractLDMLHandler { // parentLocale.=(" ")+ private final Map parentLocalesMap; + // Input Skeleton map for "preferred" and "allowed" + // Map<"preferred"/"allowed", Map<"skeleton", SortedSet<"regions">>> + private final Map>> inputSkeletonMap; + SupplementDataParseHandler() { firstDayMap = new HashMap<>(); minDaysMap = new HashMap<>(); parentLocalesMap = new HashMap<>(); + inputSkeletonMap = new HashMap<>(); } /** @@ -76,22 +85,25 @@ class SupplementDataParseHandler extends AbstractLDMLHandler { * It returns null when there is no firstDay and minDays for the country * although this should not happen because supplementalData.xml includes * default value for the world ("001") for firstDay and minDays. + * + * This method also returns Maps for "preferred" and "allowed" skeletons, + * which are grouped by regions. E.g, "h:XX YY ZZ;" which means 'h' pattern + * is "preferred"/"allowed" in "XX", "YY", and "ZZ" regions. */ Map getData(String id) { Map values = new HashMap<>(); if ("root".equals(id)) { - parentLocalesMap.keySet().forEach(key -> { - values.put(CLDRConverter.PARENT_LOCALE_PREFIX+key, - parentLocalesMap.get(key)); - }); - firstDayMap.keySet().forEach(key -> { - values.put(CLDRConverter.CALENDAR_FIRSTDAY_PREFIX+firstDayMap.get(key), - key); - }); - minDaysMap.keySet().forEach(key -> { - values.put(CLDRConverter.CALENDAR_MINDAYS_PREFIX+minDaysMap.get(key), - key); - }); + parentLocalesMap.forEach((k, v) -> values.put(CLDRConverter.PARENT_LOCALE_PREFIX + k, v)); + firstDayMap.forEach((k, v) -> values.put(CLDRConverter.CALENDAR_FIRSTDAY_PREFIX + v, k)); + minDaysMap.forEach((k, v) -> values.put(CLDRConverter.CALENDAR_MINDAYS_PREFIX + v, k)); + inputSkeletonMap.get("preferred").forEach((k, v) -> + values.merge(Bundle.DATEFORMATITEM_INPUT_REGIONS_PREFIX + "preferred", + k + ":" + v.stream().collect(Collectors.joining(" ")) + ";", + (old, newVal) -> old + (String)newVal)); + inputSkeletonMap.get("allowed").forEach((k, v) -> + values.merge(Bundle.DATEFORMATITEM_INPUT_REGIONS_PREFIX + "allowed", + k + ":" + v.stream().collect(Collectors.joining(" ")) + ";", + (old, newVal) -> old + (String)newVal)); } return values.isEmpty() ? null : values; } @@ -158,11 +170,23 @@ class SupplementDataParseHandler extends AbstractLDMLHandler { attributes.getValue("locales").replaceAll("_", "-")); } break; + case "hours": + if (!isIgnored(attributes)) { + var preferred = attributes.getValue("preferred"); + var allowed = attributes.getValue("allowed").replaceFirst(" .*", "").replaceFirst("b", "B"); // take only the first one, "b" -> "B" + var regions = Arrays.stream(attributes.getValue("regions").split(" ")) + .map(r -> r.replaceAll("_", "-")) + .collect(Collectors.toSet()); + var pmap = inputSkeletonMap.computeIfAbsent("preferred", k -> new HashMap<>()); + var amap = inputSkeletonMap.computeIfAbsent("allowed", k -> new HashMap<>()); + pmap.computeIfAbsent(preferred, k -> new TreeSet<>()).addAll(regions); + amap.computeIfAbsent(allowed, k -> new TreeSet<>()).addAll(regions); + } + break; default: // treat anything else as a container pushContainer(qName, attributes); break; } } - } diff --git a/make/jdk/src/classes/build/tools/depend/Depend.java b/make/jdk/src/classes/build/tools/depend/Depend.java index 74df2af2d575f14551c57f7ceb3d7d1b449b2f16..71d1b378879b8ba5f17a9f9fb6349df78a2ad17f 100644 --- a/make/jdk/src/classes/build/tools/depend/Depend.java +++ b/make/jdk/src/classes/build/tools/depend/Depend.java @@ -37,6 +37,7 @@ import java.security.NoSuchAlgorithmException; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; +import java.util.HexFormat; import java.util.List; import java.util.Map; import java.util.Objects; @@ -156,13 +157,7 @@ public class Depend implements Plugin { } private String toString(byte[] digest) { - StringBuilder result = new StringBuilder(); - - for (byte b : digest) { - result.append(String.format("%X", b)); - } - - return result.toString(); + return HexFormat.of().withUpperCase().formatHex(digest); } private static final class APIVisitor implements ElementVisitor, diff --git a/make/jdk/src/classes/build/tools/generatecharacter/CharacterScript.java b/make/jdk/src/classes/build/tools/generatecharacter/CharacterScript.java index fda7a561e87f92f2ecb58b1ca625dbda618dfcc0..d242cb8ed42912d8bf01680a28db13b7a53562fb 100644 --- a/make/jdk/src/classes/build/tools/generatecharacter/CharacterScript.java +++ b/make/jdk/src/classes/build/tools/generatecharacter/CharacterScript.java @@ -115,7 +115,7 @@ public class CharacterScript { for (j = 0; j < scriptSize; j++) { for (int cp = scripts[j][0]; cp <= scripts[j][1]; cp++) { - String name = names[scripts[j][2]].toUpperCase(Locale.ENGLISH);; + String name = names[scripts[j][2]].toUpperCase(Locale.ENGLISH); if (cp > 0xffff) System.out.printf("%05X %s%n", cp, name); else diff --git a/make/jdk/src/classes/build/tools/generatelsrequivmaps/EquivMapsGenerator.java b/make/jdk/src/classes/build/tools/generatelsrequivmaps/EquivMapsGenerator.java index af2844b29e7efd5950923da616d686cda039347a..d196230bfbe46e20cad5c18b6f2f21270707d600 100644 --- a/make/jdk/src/classes/build/tools/generatelsrequivmaps/EquivMapsGenerator.java +++ b/make/jdk/src/classes/build/tools/generatelsrequivmaps/EquivMapsGenerator.java @@ -29,13 +29,15 @@ import java.io.BufferedWriter; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Paths; -import java.time.ZoneId; -import java.time.ZonedDateTime; import java.util.ArrayList; import java.util.Arrays; +import java.util.Calendar; +import java.util.Date; +import java.util.GregorianCalendar; import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.TimeZone; import java.util.TreeMap; import java.util.stream.Collectors; @@ -51,17 +53,19 @@ import java.util.stream.Collectors; public class EquivMapsGenerator { public static void main(String[] args) throws Exception { - if (args.length != 2) { + if (args.length != 3) { System.err.println("Usage: java EquivMapsGenerator" - + " language-subtag-registry.txt LocaleEquivalentMaps.java"); + + " language-subtag-registry.txt LocaleEquivalentMaps.java copyrightYear"); System.exit(1); } + copyrightYear = Integer.parseInt(args[2]); readLSRfile(args[0]); generateEquivalentMap(); generateSourceCode(args[1]); } private static String LSRrevisionDate; + private static int copyrightYear; private static Map initialLanguageMap = new TreeMap<>(); private static Map initialRegionVariantMap = @@ -244,9 +248,7 @@ public class EquivMapsGenerator { + "}"; private static String getOpenJDKCopyright() { - int year = ZonedDateTime.now(ZoneId - .of("America/Los_Angeles")).getYear(); - return String.format(Locale.US, COPYRIGHT, year); + return String.format(Locale.US, COPYRIGHT, copyrightYear); } /** diff --git a/make/jdk/src/classes/build/tools/makezipreproducible/MakeZipReproducible.java b/make/jdk/src/classes/build/tools/makezipreproducible/MakeZipReproducible.java new file mode 100644 index 0000000000000000000000000000000000000000..4ea976a8cc50df07b8e8026aa0db0c56f1f746f0 --- /dev/null +++ b/make/jdk/src/classes/build/tools/makezipreproducible/MakeZipReproducible.java @@ -0,0 +1,237 @@ +/* + * 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. + */ + +package build.tools.makezipreproducible; + +import java.io.*; +import java.nio.file.*; +import java.nio.file.attribute.BasicFileAttributes; +import java.nio.channels.Channels; +import java.nio.channels.FileChannel; +import java.util.*; +import java.util.zip.ZipEntry; +import java.util.zip.ZipException; +import java.util.zip.ZipFile; +import java.util.zip.ZipInputStream; +import java.util.zip.ZipOutputStream; +import java.time.Instant; +import java.time.ZoneOffset; +import java.time.LocalDateTime; + +/** + * Generate a zip file in a "reproducible" manner from the input zip file. + * Standard zip tools rely on OS file list querying whose ordering can vary + * by platform architecture, this class ensures the zip entries are ordered + * and also supports SOURCE_DATE_EPOCH timestamps which will set the ZipEntry + * local time in UTC. + */ +public class MakeZipReproducible { + String input_file = null; + String fname = null; + String zname = ""; + LocalDateTime timestamp = null; + boolean verbose = false; + + // Keep a sorted Set of ZipEntrys to be processed, so that the zip is reproducible + SortedMap entries = new TreeMap(); + + private boolean ok; + + public MakeZipReproducible() { + } + + public synchronized boolean run(String args[]) { + ok = true; + if (!parseArgs(args)) { + return false; + } + try { + zname = fname.replace(File.separatorChar, '/'); + if (zname.startsWith("./")) { + zname = zname.substring(2); + } + + if (verbose) System.out.println("Input zip file: " + input_file); + + File inFile = new File(input_file); + if (!inFile.exists()) { + error("Input zip file does not exist"); + ok = false; + } else { + File zipFile = new File(fname); + // Check archive to create does not exist + if (!zipFile.exists()) { + // Process input ZipEntries + ok = processInputEntries(inFile); + if (ok) { + try (FileOutputStream out = new FileOutputStream(fname)) { + ok = create(inFile, new BufferedOutputStream(out, 4096)); + } + } else { + } + } else { + error("Target zip file "+fname+" already exists."); + ok = false; + } + } + } catch (IOException e) { + fatalError(e); + ok = false; + } catch (Error ee) { + ee.printStackTrace(); + ok = false; + } catch (Throwable t) { + t.printStackTrace(); + ok = false; + } + return ok; + } + + boolean parseArgs(String args[]) { + try { + boolean parsingIncludes = false; + boolean parsingExcludes = false; + int count = 0; + while(count < args.length) { + if (args[count].startsWith("-")) { + String flag = args[count].substring(1); + switch (flag.charAt(0)) { + case 'f': + fname = args[++count]; + break; + case 't': + // SOURCE_DATE_EPOCH timestamp specified + long epochSeconds = Long.parseLong(args[++count]); + Instant instant = Instant.ofEpochSecond(epochSeconds); + timestamp = LocalDateTime.ofInstant(instant, ZoneOffset.UTC); + break; + case 'v': + verbose = true; + break; + default: + error(String.format("Illegal option -%s", String.valueOf(flag.charAt(0)))); + usageError(); + return false; + } + } else { + // input zip file + if (input_file != null) { + error("Input zip file already specified"); + usageError(); + return false; + } + input_file = args[count]; + } + count++; + } + } catch (ArrayIndexOutOfBoundsException e) { + usageError(); + return false; + } catch (NumberFormatException e) { + usageError(); + return false; + } + if (fname == null) { + error("-f must be specified"); + usageError(); + return false; + } + // If no files specified then default to current directory + if (input_file == null) { + error("No input zip file specified"); + usageError(); + return false; + } + + return true; + } + + // Process input zip file and add to sorted entries set + boolean processInputEntries(File inFile) throws IOException { + ZipFile zipFile = new ZipFile(inFile); + zipFile.stream().forEach(entry -> entries.put(entry.getName(), entry)); + + return true; + } + + // Create new zip from entries + boolean create(File inFile, OutputStream out) throws IOException + { + try (ZipFile zipFile = new ZipFile(inFile); + ZipOutputStream zos = new ZipOutputStream(out)) { + for (Map.Entry entry : entries.entrySet()) { + ZipEntry zipEntry = entry.getValue(); + if (zipEntry.getSize() > 0) { + try (InputStream eis = zipFile.getInputStream(zipEntry)) { + addEntry(zos, zipEntry, eis); + } + } else { + addEntry(zos, zipEntry, null); + } + } + } + return true; + } + + // Add Entry and data to Zip + void addEntry(ZipOutputStream zos, ZipEntry entry, InputStream entryInputStream) throws IOException { + if (verbose) { + System.out.println("Adding: "+entry.getName()); + } + + // Set to specified timestamp if set otherwise leave as original lastModified time + if (timestamp != null) { + entry.setTimeLocal(timestamp); + } + + zos.putNextEntry(entry); + if (entry.getSize() > 0 && entryInputStream != null) { + entryInputStream.transferTo(zos); + } + zos.closeEntry(); + } + + void usageError() { + error( + "Usage: MakeZipReproducible [-v] [-t ] -f \n" + + "Options:\n" + + " -v verbose output\n" + + " -f specify archive file name to create\n" + + " -t specific SOURCE_DATE_EPOCH value to use for timestamps\n" + + " input_zip_file re-written as a reproducible zip output_zip_file.\n"); + } + + void fatalError(Exception e) { + e.printStackTrace(); + } + + protected void error(String s) { + System.err.println(s); + } + + public static void main(String args[]) { + MakeZipReproducible z = new MakeZipReproducible(); + System.exit(z.run(args) ? 0 : 1); + } +} + diff --git a/make/jdk/src/classes/build/tools/taglet/ToolGuide.java b/make/jdk/src/classes/build/tools/taglet/ToolGuide.java index ae70d424222fda7099f8392b46939df041662268..f3ce80cf241da4c3465810a4887f832d3a69329b 100644 --- a/make/jdk/src/classes/build/tools/taglet/ToolGuide.java +++ b/make/jdk/src/classes/build/tools/taglet/ToolGuide.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -31,8 +31,8 @@ import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.lang.model.element.Element; -import javax.lang.model.element.ModuleElement; import javax.lang.model.element.PackageElement; +import javax.lang.model.element.TypeElement; import com.sun.source.doctree.DocTree; import com.sun.source.doctree.UnknownBlockTagTree; @@ -75,7 +75,7 @@ public class ToolGuide implements Taglet { */ @Override public Set getAllowedLocations() { - return EnumSet.of(MODULE, PACKAGE); + return EnumSet.of(MODULE, PACKAGE, TYPE); } @Override @@ -151,6 +151,12 @@ public class ToolGuide implements Taglet { return pe.getEnclosingElement() != null ? "../" + pkgPart : pkgPart; + case CLASS: + TypeElement te = (TypeElement)elem; + return te.getQualifiedName() + .toString() + .replace('.', '/') + .replaceAll("[^/]+", ".."); default: throw new IllegalArgumentException(elem.getKind().toString()); diff --git a/make/langtools/src/classes/build/tools/symbolgenerator/CreateSymbols.java b/make/langtools/src/classes/build/tools/symbolgenerator/CreateSymbols.java index 1f439e1c29e081bd23174c1a44f6cebb10c56841..41f600a817e0df7102fa856228814ba20689935a 100644 --- a/make/langtools/src/classes/build/tools/symbolgenerator/CreateSymbols.java +++ b/make/langtools/src/classes/build/tools/symbolgenerator/CreateSymbols.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 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 @@ -25,6 +25,7 @@ package build.tools.symbolgenerator; +import build.tools.symbolgenerator.CreateSymbols.ModuleHeaderDescription.ExportsDescription; import build.tools.symbolgenerator.CreateSymbols .ModuleHeaderDescription .ProvidesDescription; @@ -122,6 +123,7 @@ import com.sun.tools.classfile.Field; import com.sun.tools.classfile.InnerClasses_attribute; import com.sun.tools.classfile.InnerClasses_attribute.Info; import com.sun.tools.classfile.Method; +import com.sun.tools.classfile.ModulePackages_attribute; import com.sun.tools.classfile.MethodParameters_attribute; import com.sun.tools.classfile.ModuleMainClass_attribute; import com.sun.tools.classfile.ModuleResolution_attribute; @@ -154,7 +156,7 @@ import java.util.Optional; * A tool for processing the .sym.txt files. * * To add historical data for JDK N, N >= 11, do the following: - * * cd /make/data/symbols + * * cd /src/jdk.compiler/share/data/symbols * * /bin/java --add-exports jdk.jdeps/com.sun.tools.classfile=ALL-UNNAMED \ * --add-exports jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED \ * --add-exports jdk.compiler/com.sun.tools.javac.jvm=ALL-UNNAMED \ @@ -162,7 +164,7 @@ import java.util.Optional; * --add-modules jdk.jdeps \ * ../../../make/langtools/src/classes/build/tools/symbolgenerator/CreateSymbols.java \ * build-description-incremental symbols include.list - * * sanity-check the new and updates files in make/data/symbols and commit them + * * sanity-check the new and updates files in src/jdk.compiler/share/data/symbols and commit them * * The tools allows to: * * convert the .sym.txt into class/sig files for ct.sym @@ -210,7 +212,8 @@ import java.util.Optional; * To generate the .sym.txt files for OpenJDK 7 and 8: * /bin/java build.tools.symbolgenerator.Probe OpenJDK7.classes * /bin/java build.tools.symbolgenerator.Probe OpenJDK8.classes - * java build.tools.symbolgenerator.CreateSymbols build-description make/data/symbols $TOPDIR make/data/symbols/include.list + * java build.tools.symbolgenerator.CreateSymbols build-description src/jdk.compiler/share/data/symbols + * $TOPDIR src/jdk.compiler/share/data/symbols/include.list * 8 OpenJDK8.classes '' * 7 OpenJDK7.classes 8 * @@ -244,7 +247,14 @@ public class CreateSymbols { md, mhd, versionsList); - mhd.exports.stream().forEach(pkg -> { + List packages = new ArrayList<>(); + mhd.exports.stream() + .map(ExportsDescription::packageName) + .forEach(packages::add); + if (mhd.extraModulePackages != null) { + packages.addAll(mhd.extraModulePackages); + } + packages.stream().forEach(pkg -> { for (char v : mhd.versions.toCharArray()) { package2Version2Module.computeIfAbsent(pkg, dummy -> new HashMap<>()).put(v, md.name); } @@ -974,13 +984,21 @@ public class CreateSymbols { return new RequiresEntry(idx, r.flags, r.version != null - ? addInt(cp, r.version) + ? addString(cp, r.version) : 0); } private static ExportsEntry createExportsEntry(List cp, - String e) { - return new ExportsEntry(addPackageName(cp, e), 0, new int[0]); + ExportsDescription export) { + int[] to; + if (export.isQualified()) { + to = export.to.stream() + .mapToInt(module -> addModuleName(cp, module)) + .toArray(); + } else { + to = new int[0]; + } + return new ExportsEntry(addPackageName(cp, export.packageName()), 0, to); } private static OpensEntry createOpensEntry(List cp, String e) { @@ -1405,7 +1423,7 @@ public class CreateSymbols { dumpDescriptions(classes, modules, platforms, Set.of(), descDest.resolve("symbols"), args); } //where: - private static final String DO_NO_MODIFY = + public static String DO_NOT_MODIFY = "#\n" + "# Copyright (c) {YEAR}, Oracle and/or its affiliates. All rights reserved.\n" + "# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n" + @@ -1477,14 +1495,19 @@ public class CreateSymbols { ExcludeIncludeList currentEIList = excludesIncludes; if (!currentVersionModules.isEmpty()) { + Set privateIncludes = + enhancedIncludesListBasedOnClassHeaders(classes, classData); Set includes = new HashSet<>(); for (ModuleDescription md : currentVersionModules.values()) { - md.header.get(0).exports.stream().map(e -> e + '/') + md.header.get(0).exports.stream() + .filter(e -> !e.isQualified()) + .map(e -> e.packageName + '/') .forEach(includes::add); } currentEIList = new ExcludeIncludeList(includes, + privateIncludes, Collections.emptySet()); } @@ -1507,7 +1530,9 @@ public class CreateSymbols { if (unsupported.header .get(0) .exports - .contains(cd.packge().replace('.', '/'))) { + .stream() + .map(ed -> ed.packageName) + .anyMatch(pack -> pack.equals(cd.packge().replace('.', '/')))) { ClassHeaderDescription ch = cd.header.get(0); if (ch.classAnnotations == null) { ch.classAnnotations = new ArrayList<>(); @@ -1529,7 +1554,7 @@ public class CreateSymbols { for (ClassDescription clazz : currentVersionClasses) { ClassHeaderDescription header = clazz.header.get(0); - if (includeEffectiveAccess(currentVersionClasses, clazz)) { + if (includeEffectiveAccess(currentVersionClasses, clazz) && currentEIList.accepts(clazz.name, false)) { modified |= include(includedClasses, currentVersionClasses, clazz.name); } @@ -1555,6 +1580,8 @@ public class CreateSymbols { } } while (modified); + Set allIncludedPackages = new HashSet<>(); + for (ClassDescription clazz : currentVersionClasses) { if (!includedClasses.contains(clazz.name)) { continue; @@ -1595,6 +1622,8 @@ public class CreateSymbols { } else { classes.add(clazz); } + + allIncludedPackages.add(clazz.packge().replace('.', '/')); } for (ModuleDescription module : currentVersionModules.values()) { @@ -1611,6 +1640,13 @@ public class CreateSymbols { } } + header.exports.removeIf(ed -> ed.isQualified() && + !allIncludedPackages.contains(ed.packageName())); + + if (header.extraModulePackages != null) { + header.extraModulePackages.retainAll(allIncludedPackages); + } + ModuleDescription existing = modules.get(module.name); if (existing != null) { @@ -1642,7 +1678,16 @@ public class CreateSymbols { md.header .stream() .filter(h -> h.versions.contains(v.version)) - .flatMap(h -> h.exports.stream()) + .flatMap(h -> { + List packages = new ArrayList<>(); + h.exports.stream() + .map(ExportsDescription::packageName) + .forEach(packages::add); + if (h.extraModulePackages != null) { + packages.addAll(h.extraModulePackages); + } + return packages.stream(); + }) .map(p -> p.replace('/', '.')) .forEach(p -> package2Modules.putIfAbsent(p, md.name)); } @@ -1718,11 +1763,11 @@ public class CreateSymbols { boolean hasChange = true; if (Files.isReadable(f)) { String oldContent = Files.readString(f, StandardCharsets.UTF_8); - int yearPos = DO_NO_MODIFY.indexOf("{YEAR}"); + int yearPos = DO_NOT_MODIFY.indexOf("{YEAR}"); String headerPattern = - Pattern.quote(DO_NO_MODIFY.substring(0, yearPos)) + + Pattern.quote(DO_NOT_MODIFY.substring(0, yearPos)) + "([0-9]+)(, [0-9]+)?" + - Pattern.quote(DO_NO_MODIFY.substring(yearPos + "{YEAR}".length())); + Pattern.quote(DO_NOT_MODIFY.substring(yearPos + "{YEAR}".length())); String pattern = headerPattern + Pattern.quote(dataString); Matcher m = Pattern.compile(pattern, Pattern.MULTILINE).matcher(oldContent); @@ -1739,7 +1784,7 @@ public class CreateSymbols { try (Writer out = Files.newBufferedWriter(f, StandardCharsets.UTF_8)) { String currentYear = String.valueOf(year); String yearSpec = (existingYear != null && !currentYear.equals(existingYear) ? existingYear + ", " : "") + currentYear; - out.append(DO_NO_MODIFY.replace("{YEAR}", yearSpec)); + out.append(DO_NOT_MODIFY.replace("{YEAR}", yearSpec)); out.write(dataString); } } @@ -1750,7 +1795,7 @@ public class CreateSymbols { outputFiles.put(desc, files); } - symbolsOut.append(DO_NO_MODIFY.replace("{YEAR}", "2015, " + year)); + symbolsOut.append(DO_NOT_MODIFY.replace("{YEAR}", "2015, " + year)); symbolsOut.append("#command used to generate this file:\n"); symbolsOut.append("#") .append(CreateSymbols.class.getName()) @@ -1923,7 +1968,7 @@ public class CreateSymbols { return ; } - if (!excludesIncludes.accepts(cf.getName())) { + if (!excludesIncludes.accepts(cf.getName(), true)) { return ; } @@ -2019,6 +2064,45 @@ public class CreateSymbols { addModuleHeader(moduleDesc, headerDesc, version); } + private Set enhancedIncludesListBasedOnClassHeaders(ClassList classes, + Iterable classData) { + Set additionalIncludes = new HashSet<>(); + + for (byte[] classFileData : classData) { + try (InputStream in = new ByteArrayInputStream(classFileData)) { + ClassFile cf = ClassFile.read(in); + + if (cf.access_flags.is(AccessFlags.ACC_MODULE)) { + continue; + } + + Set additionalClasses = new HashSet<>(); + + if (cf.super_class != 0) { + additionalClasses.add(cf.getSuperclassName()); + } + for (int i = 0; i < cf.interfaces.length; i++) { + additionalClasses.add(cf.getInterfaceName(i)); + } + + for (String additional : additionalClasses) { + int dollar; + + additionalIncludes.add(additional); + + while ((dollar = additional.lastIndexOf('$')) != (-1)) { + additional = additional.substring(0, dollar); + additionalIncludes.add(additional); + } + } + } catch (IOException | ConstantPoolException ex) { + throw new IllegalStateException(ex); + } + } + + return additionalIncludes; + } + private void addModuleHeader(ModuleDescription moduleDesc, ModuleHeaderDescription headerDesc, String version) { @@ -2204,9 +2288,11 @@ public class CreateSymbols { header.exports = Arrays.stream(mod.exports) - .filter(ee -> ee.exports_to_count == 0) - .map(ee -> getPackageName(cf, ee.exports_index)) + .map(ee -> ExportsDescription.create(cf, ee)) .collect(Collectors.toList()); + if (header.extraModulePackages != null) { + header.exports.forEach(ed -> header.extraModulePackages.remove(ed.packageName())); + } header.requires = Arrays.stream(mod.requires) .map(r -> RequiresDescription.create(cf, r)) @@ -2242,6 +2328,20 @@ public class CreateSymbols { break; } case Attribute.ModulePackages: + assert feature instanceof ModuleHeaderDescription; + ModuleHeaderDescription header = + (ModuleHeaderDescription) feature; + ModulePackages_attribute mod = + (ModulePackages_attribute) attr; + header.extraModulePackages = new ArrayList<>(); + for (int i = 0; i < mod.packages_count; i++) { + String packageName = getPackageName(cf, mod.packages_index[i]); + if (header.exports == null || + header.exports.stream().noneMatch(ed -> ed.packageName().equals(packageName))) { + header.extraModulePackages.add(packageName); + } + } + break; case Attribute.ModuleHashes: break; case Attribute.NestHost: { @@ -2352,11 +2452,16 @@ public class CreateSymbols { } } - private static Integer getVersion(ClassFile cf, int idx) { + public static String INJECTED_VERSION = null; + + private static String getVersion(ClassFile cf, int idx) { + if (INJECTED_VERSION != null) { + return INJECTED_VERSION; + } if (idx == 0) return null; try { - return ((CONSTANT_Integer_info) cf.constant_pool.get(idx)).value; + return ((CONSTANT_Utf8_info) cf.constant_pool.get(idx)).value; } catch (InvalidIndex ex) { throw new IllegalStateException(ex); } @@ -2470,9 +2575,15 @@ public class CreateSymbols { if (clazzName == null) return false; + ClassDescription desc = classes.find(clazzName, true); + + if (desc == null) { + return false; + } + boolean modified = includedClasses.add(clazzName); - for (ClassDescription outer : classes.enclosingClasses(classes.find(clazzName, true))) { + for (ClassDescription outer : classes.enclosingClasses(desc)) { modified |= includedClasses.add(outer.name); } @@ -2514,10 +2625,17 @@ public class CreateSymbols { public static class ExcludeIncludeList { public final Set includeList; + public final Set privateIncludeList; public final Set excludeList; protected ExcludeIncludeList(Set includeList, Set excludeList) { + this(includeList, Set.of(), excludeList); + } + + protected ExcludeIncludeList(Set includeList, Set privateIncludeList, + Set excludeList) { this.includeList = includeList; + this.privateIncludeList = privateIncludeList; this.excludeList = excludeList; } @@ -2537,8 +2655,10 @@ public class CreateSymbols { return new ExcludeIncludeList(includeList, excludeList); } - public boolean accepts(String className) { - return matches(includeList, className) && !matches(excludeList, className); + public boolean accepts(String className, boolean includePrivateClasses) { + return (matches(includeList, className) || + (includePrivateClasses && matches(privateIncludeList, className))) && + !matches(excludeList, className); } private static boolean matches(Set list, String className) { @@ -2738,8 +2858,9 @@ public class CreateSymbols { static class ModuleHeaderDescription extends HeaderDescription { String name; - List exports = new ArrayList<>(); + List exports = new ArrayList<>(); List opens = new ArrayList<>(); + List extraModulePackages = new ArrayList<>(); List requires = new ArrayList<>(); List uses = new ArrayList<>(); List provides = new ArrayList<>(); @@ -2753,6 +2874,7 @@ public class CreateSymbols { hash = 83 * hash + Objects.hashCode(this.name); hash = 83 * hash + Objects.hashCode(this.exports); hash = 83 * hash + Objects.hashCode(this.opens); + hash = 83 * hash + Objects.hashCode(this.extraModulePackages); hash = 83 * hash + Objects.hashCode(this.requires); hash = 83 * hash + Objects.hashCode(this.uses); hash = 83 * hash + Objects.hashCode(this.provides); @@ -2781,6 +2903,9 @@ public class CreateSymbols { if (!listEquals(this.opens, other.opens)) { return false; } + if (!listEquals(this.extraModulePackages, other.extraModulePackages)) { + return false; + } if (!listEquals(this.requires, other.requires)) { return false; } @@ -2812,10 +2937,17 @@ public class CreateSymbols { && versions.contains(version))) return ; output.append("header"); - if (exports != null && !exports.isEmpty()) - output.append(" exports " + serializeList(exports)); + if (exports != null && !exports.isEmpty()) { + List exportsList = + exports.stream() + .map(exp -> exp.serialize()) + .collect(Collectors.toList()); + output.append(" exports " + serializeList(exportsList)); + } if (opens != null && !opens.isEmpty()) output.append(" opens " + serializeList(opens)); + if (extraModulePackages != null && !extraModulePackages.isEmpty()) + output.append(" extraModulePackages " + serializeList(extraModulePackages)); if (requires != null && !requires.isEmpty()) { List requiresList = requires.stream() @@ -2862,8 +2994,12 @@ public class CreateSymbols { if (!"header".equals(reader.lineKey)) return false; - exports = deserializeList(reader.attributes.get("exports")); + List exportsList = deserializeList(reader.attributes.get("exports"), false); + exports = exportsList.stream() + .map(ExportsDescription::deserialize) + .collect(Collectors.toList()); opens = deserializeList(reader.attributes.get("opens")); + extraModulePackages = deserializeList(reader.attributes.get("extraModulePackages")); List requiresList = deserializeList(reader.attributes.get("requires")); requires = requiresList.stream() @@ -2893,13 +3029,53 @@ public class CreateSymbols { return true; } + record ExportsDescription(String packageName, List to) { + public String serialize() { + return packageName + + (isQualified() ? "[" + quote(serializeList(to), true, true) + "]" + : ""); + } + + public static ExportsDescription deserialize(String data) { + int bracket = data.indexOf("["); + String packageName; + List to; + if (bracket != (-1)) { + packageName = data.substring(0, bracket); + to = deserializeList(unquote(data.substring(bracket + 1, data.length() - 1))); + } else { + packageName = data; + to = null; + } + + return new ExportsDescription(packageName, to); + } + + public static ExportsDescription create(ClassFile cf, + ExportsEntry ee) { + String packageName = getPackageName(cf, ee.exports_index); + List to = null; + if (ee.exports_to_count > 0) { + to = new ArrayList<>(); + for (int moduleIndex : ee.exports_to_index) { + to.add(getModuleName(cf, moduleIndex)); + } + } + return new ExportsDescription(packageName, to); + } + + public boolean isQualified() { + return to != null && !to.isEmpty(); + } + } + static class RequiresDescription { final String moduleName; final int flags; - final Integer version; + final String version; public RequiresDescription(String moduleName, int flags, - Integer version) { + String version) { this.moduleName = moduleName; this.flags = flags; this.version = version; @@ -2907,7 +3083,7 @@ public class CreateSymbols { public String serialize() { String versionKeyValue = version != null - ? " version " + quote(String.valueOf(version), true) + ? " version " + quote(version, true) : ""; return "name " + quote(moduleName, true) + " flags " + quote(Integer.toHexString(flags), true) + @@ -2917,8 +3093,8 @@ public class CreateSymbols { public static RequiresDescription deserialize(String data) { Map attributes = splitAttributes(data); - Integer ver = attributes.containsKey("version") - ? Integer.parseInt(attributes.get("version")) + String ver = attributes.containsKey("version") + ? attributes.get("version") : null; int flags = Integer.parseInt(attributes.get("flags"), 16); return new RequiresDescription(attributes.get("name"), @@ -2929,7 +3105,7 @@ public class CreateSymbols { public static RequiresDescription create(ClassFile cf, RequiresEntry req) { String mod = getModuleName(cf, req.requires_index); - Integer ver = getVersion(cf, req.requires_version_index); + String ver = getVersion(cf, req.requires_version_index); return new RequiresDescription(mod, req.requires_flags, ver); @@ -3071,10 +3247,24 @@ public class CreateSymbols { header.write(output, baselineVersion, version); } for (FieldDescription field : fields) { - field.write(output, baselineVersion, version); + if (!field.versions.contains(version)) { + field.write(output, baselineVersion, version); + } + } + for (MethodDescription method : methods) { + if (!method.versions.contains(version)) { + method.write(output, baselineVersion, version); + } + } + for (FieldDescription field : fields) { + if (field.versions.contains(version)) { + field.write(output, baselineVersion, version); + } } for (MethodDescription method : methods) { - method.write(output, baselineVersion, version); + if (method.versions.contains(version)) { + method.write(output, baselineVersion, version); + } } output.append("\n"); } @@ -3157,6 +3347,12 @@ public class CreateSymbols { return pack; } + + @Override + public String toString() { + return name; + } + } static class ClassHeaderDescription extends HeaderDescription { @@ -3265,12 +3461,12 @@ public class CreateSymbols { readRecordComponents(reader); } readInnerClasses(reader); + isSealed = reader.attributes.containsKey("permittedSubclasses"); if (isSealed) { String subclassesList = reader.attributes.get("permittedSubclasses"); permittedSubclasses = deserializeList(subclassesList); } - return true; } @@ -4120,8 +4316,11 @@ public class CreateSymbols { } w.write("module:" + module.name); w.write("\n"); - for (String pack : header.get().exports) { - w.write(pack.replace('/', '.')); + for (ExportsDescription export : header.get().exports) { + if (export.isQualified()) { + continue; + } + w.write(export.packageName.replace('/', '.')); w.write("\n"); } } diff --git a/make/langtools/tools/compileproperties/CompileProperties.java b/make/langtools/tools/compileproperties/CompileProperties.java index 49cfc8a4a4b1445cd15a32d784c8204fe95587e0..7d69f9b47b2e9d37e06f2424054d85385d1571f7 100644 --- a/make/langtools/tools/compileproperties/CompileProperties.java +++ b/make/langtools/tools/compileproperties/CompileProperties.java @@ -183,7 +183,8 @@ public class CompileProperties { log.error("cannot close " + filename, e); } } - if ( ok = true && contents != null ) { + ok = true; + if ( contents != null ) { String tokens[] = (new String(contents)).split("\\s+"); if ( tokens.length > 0 ) { ok = parseOptions(tokens); diff --git a/make/langtools/tools/genstubs/GenStubs.java b/make/langtools/tools/genstubs/GenStubs.java index 9f8fc7a7a596132f2d8dc77246141ce62d10729a..bcf73fc5f71c89795b9b112ea72a5abdbd40c84f 100644 --- a/make/langtools/tools/genstubs/GenStubs.java +++ b/make/langtools/tools/genstubs/GenStubs.java @@ -213,7 +213,7 @@ public class GenStubs { long prevClassMods = currClassMods; currClassMods = tree.mods.flags; try { - super.visitClassDef(tree);; + super.visitClassDef(tree); } finally { currClassMods = prevClassMods; } diff --git a/make/modules/java.base/Copy.gmk b/make/modules/java.base/Copy.gmk index d61a274317296b60c32e75458a9b921a8a78ef34..16d1b8d910cfe521a266bc23c9215c0cf2aca38f 100644 --- a/make/modules/java.base/Copy.gmk +++ b/make/modules/java.base/Copy.gmk @@ -246,6 +246,23 @@ ifeq ($(ENABLE_LIBFFI_BUNDLING), true) TARGETS += $(COPY_LIBFFI) endif +################################################################################ +# Optionally copy hsdis into the the image + +ifeq ($(ENABLE_HSDIS_BUNDLING), true) + HSDIS_NAME := hsdis-$(OPENJDK_TARGET_CPU_LEGACY_LIB)$(SHARED_LIBRARY_SUFFIX) + HSDIS_PATH := $(SUPPORT_OUTPUTDIR)/hsdis/$(HSDIS_NAME) + + $(eval $(call SetupCopyFiles, COPY_HSDIS, \ + FILES := $(HSDIS_PATH), \ + DEST := $(call FindLibDirForModule, $(MODULE)), \ + FLATTEN := true, \ + MACRO := install-file-nolink, \ + )) + + TARGETS += $(COPY_HSDIS) +endif + ################################################################################ # Generate classfile_constants.h diff --git a/make/modules/java.base/Gendata.gmk b/make/modules/java.base/Gendata.gmk index f9c25c8c53fcea1ffd4b490b7e27f3fbb3fad28e..9e5cfe2d0fc40e10ff9c66e8e225ea154102a008 100644 --- a/make/modules/java.base/Gendata.gmk +++ b/make/modules/java.base/Gendata.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 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 @@ -39,7 +39,7 @@ include gendata/GendataPublicSuffixList.gmk GENDATA_UNINAME := $(JDK_OUTPUTDIR)/modules/java.base/java/lang/uniName.dat -$(GENDATA_UNINAME): $(TOPDIR)/make/data/unicodedata/UnicodeData.txt $(BUILD_TOOLS_JDK) +$(GENDATA_UNINAME): $(MODULE_SRC)/share/data/unicodedata/UnicodeData.txt $(BUILD_TOOLS_JDK) $(call MakeDir, $(@D)) $(TOOL_CHARACTERNAME) $< $@ @@ -49,7 +49,7 @@ TARGETS += $(GENDATA_UNINAME) GENDATA_CURDATA := $(JDK_OUTPUTDIR)/modules/java.base/java/util/currency.data -$(GENDATA_CURDATA): $(TOPDIR)/make/data/currency/CurrencyData.properties $(BUILD_TOOLS_JDK) +$(GENDATA_CURDATA): $(MODULE_SRC)/share/data/currency/CurrencyData.properties $(BUILD_TOOLS_JDK) $(call MakeDir, $(@D)) $(RM) $@ $(TOOL_GENERATECURRENCYDATA) -o $@.tmp -i $< @@ -60,7 +60,11 @@ TARGETS += $(GENDATA_CURDATA) ################################################################################ -GENDATA_CACERTS_SRC := $(TOPDIR)/make/data/cacerts/ +ifneq ($(CACERTS_SRC), ) + GENDATA_CACERTS_SRC := $(CACERTS_SRC) +else + GENDATA_CACERTS_SRC := $(MODULE_SRC)/share/data/cacerts/ +endif GENDATA_CACERTS := $(SUPPORT_OUTPUTDIR)/modules_libs/java.base/security/cacerts $(GENDATA_CACERTS): $(BUILD_TOOLS_JDK) $(wildcard $(GENDATA_CACERTS_SRC)/*) @@ -74,7 +78,7 @@ endif ################################################################################ -GENDATA_JAVA_SECURITY_SRC := $(TOPDIR)/src/java.base/share/conf/security/java.security +GENDATA_JAVA_SECURITY_SRC := $(MODULE_SRC)/share/conf/security/java.security GENDATA_JAVA_SECURITY := $(SUPPORT_OUTPUTDIR)/modules_conf/java.base/security/java.security ifeq ($(UNLIMITED_CRYPTO), true) diff --git a/make/modules/java.base/Gensrc.gmk b/make/modules/java.base/Gensrc.gmk index f1eb5ff7e8000e7a605798cd1f8e855eb447dc1a..9c9576bdd4a3290acc5518cd09a6e3abe0b00535 100644 --- a/make/modules/java.base/Gensrc.gmk +++ b/make/modules/java.base/Gensrc.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 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 @@ -46,8 +46,8 @@ TARGETS += $(GENSRC_BASELOCALEDATA) CLDR_DATA_DIR := $(TOPDIR)/make/data/cldr/common GENSRC_DIR := $(SUPPORT_OUTPUTDIR)/gensrc/java.base CLDR_GEN_DONE := $(GENSRC_DIR)/_cldr-gensrc.marker -TZ_DATA_DIR := $(TOPDIR)/make/data/tzdata -ZONENAME_TEMPLATE := $(TOPDIR)/src/java.base/share/classes/java/time/format/ZoneName.java.template +TZ_DATA_DIR := $(MODULE_SRC)/share/data/tzdata +ZONENAME_TEMPLATE := $(MODULE_SRC)/share/classes/java/time/format/ZoneName.java.template $(CLDR_GEN_DONE): $(wildcard $(CLDR_DATA_DIR)/dtd/*.dtd) \ $(wildcard $(CLDR_DATA_DIR)/main/en*.xml) \ @@ -62,6 +62,7 @@ $(CLDR_GEN_DONE): $(wildcard $(CLDR_DATA_DIR)/dtd/*.dtd) \ -baselocales "en-US" \ -o $(GENSRC_DIR) \ -basemodule \ + -year $(COPYRIGHT_YEAR) \ -zntempfile $(ZONENAME_TEMPLATE) \ -tzdatadir $(TZ_DATA_DIR)) $(TOUCH) $@ @@ -73,12 +74,12 @@ TARGETS += $(CLDR_GEN_DONE) include GensrcProperties.gmk $(eval $(call SetupCompileProperties, LIST_RESOURCE_BUNDLE, \ - SRC_DIRS := $(TOPDIR)/src/java.base/share/classes/sun/launcher/resources, \ + SRC_DIRS := $(MODULE_SRC)/share/classes/sun/launcher/resources, \ CLASS := ListResourceBundle, \ )) $(eval $(call SetupCompileProperties, SUN_UTIL, \ - SRC_DIRS := $(TOPDIR)/src/java.base/share/classes/sun/util/resources, \ + SRC_DIRS := $(MODULE_SRC)/share/classes/sun/util/resources, \ CLASS := sun.util.resources.LocaleNamesBundle, \ )) @@ -97,9 +98,9 @@ TARGETS += $(COPY_ZH_HK) GENSRC_LSREQUIVMAPS := $(SUPPORT_OUTPUTDIR)/gensrc/java.base/sun/util/locale/LocaleEquivalentMaps.java -$(GENSRC_LSREQUIVMAPS): $(TOPDIR)/make/data/lsrdata/language-subtag-registry.txt $(BUILD_TOOLS_JDK) +$(GENSRC_LSREQUIVMAPS): $(MODULE_SRC)/share/data/lsrdata/language-subtag-registry.txt $(BUILD_TOOLS_JDK) $(call MakeDir, $(@D)) - $(TOOL_GENERATELSREQUIVMAPS) $< $@ + $(TOOL_GENERATELSREQUIVMAPS) $< $@ $(COPYRIGHT_YEAR) TARGETS += $(GENSRC_LSREQUIVMAPS) diff --git a/make/modules/java.base/Java.gmk b/make/modules/java.base/Java.gmk index 58d707e6148c55de800dd90b67d106de40ad6257..25c14d2b1d265cc93268275b9e22690f30a18f2c 100644 --- a/make/modules/java.base/Java.gmk +++ b/make/modules/java.base/Java.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. +# 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 @@ -23,7 +23,7 @@ # questions. # -DOCLINT += -Xdoclint:all/protected,-reference,-accessibility \ +DOCLINT += -Xdoclint:all/protected \ '-Xdoclint/package:java.*,javax.*' JAVAC_FLAGS += -XDstringConcat=inline COPY += .icu .dat .spp .nrm content-types.properties \ diff --git a/make/modules/java.base/gendata/GendataBlockedCerts.gmk b/make/modules/java.base/gendata/GendataBlockedCerts.gmk index 65f75012a33d5648b3e6a3d1a7cc3b6612a3964d..b6149b457cd5093b9fcd1b73d9bedc2478d3f25c 100644 --- a/make/modules/java.base/gendata/GendataBlockedCerts.gmk +++ b/make/modules/java.base/gendata/GendataBlockedCerts.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2014, 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 @@ -23,7 +23,7 @@ # questions. # -GENDATA_BLOCKED_CERTS_SRC += $(TOPDIR)/make/data/blockedcertsconverter/blocked.certs.pem +GENDATA_BLOCKED_CERTS_SRC += $(MODULE_SRC)/share/data/blockedcertsconverter/blocked.certs.pem GENDATA_BLOCKED_CERTS := $(SUPPORT_OUTPUTDIR)/modules_libs/$(MODULE)/security/blocked.certs $(GENDATA_BLOCKED_CERTS): $(BUILD_TOOLS_JDK) $(GENDATA_BLOCKED_CERTS_SRC) diff --git a/make/modules/java.base/gendata/GendataBreakIterator.gmk b/make/modules/java.base/gendata/GendataBreakIterator.gmk index d314253b4fe31bc1e3d849e53176375858e90f49..857ce2b7c34fc94fc82be091de65d211bb385740 100644 --- a/make/modules/java.base/gendata/GendataBreakIterator.gmk +++ b/make/modules/java.base/gendata/GendataBreakIterator.gmk @@ -1,5 +1,5 @@ -# Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 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 @@ -74,7 +74,7 @@ BREAK_ITERATOR_BOOTCLASSPATH := \ # Generate data resource files. # input -UNICODEDATA := $(TOPDIR)/make/data/unicodedata/UnicodeData.txt +UNICODEDATA := $(MODULE_SRC)/share/data/unicodedata/UnicodeData.txt # output BASE_DATA_PKG_DIR := $(JDK_OUTPUTDIR)/modules/java.base/sun/text/resources diff --git a/make/modules/java.base/gendata/GendataPublicSuffixList.gmk b/make/modules/java.base/gendata/GendataPublicSuffixList.gmk index 757098a619fc2c89d9c4dedc6219cb7f838dbd2f..189fccf0c0da535a2ceebfbe036f1331b7d0f0df 100644 --- a/make/modules/java.base/gendata/GendataPublicSuffixList.gmk +++ b/make/modules/java.base/gendata/GendataPublicSuffixList.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved. +# 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 @@ -25,7 +25,7 @@ include $(SPEC) -GENDATA_PUBLICSUFFIXLIST_SRC += $(TOPDIR)/make/data/publicsuffixlist/public_suffix_list.dat +GENDATA_PUBLICSUFFIXLIST_SRC += $(MODULE_SRC)/share/data/publicsuffixlist/public_suffix_list.dat GENDATA_PUBLICSUFFIXLIST := $(SUPPORT_OUTPUTDIR)/modules_libs/$(MODULE)/security/public_suffix_list.dat $(GENDATA_PUBLICSUFFIXLIST): $(GENDATA_PUBLICSUFFIXLIST_SRC) $(BUILD_TOOLS_JDK) diff --git a/make/modules/java.base/gendata/GendataTZDB.gmk b/make/modules/java.base/gendata/GendataTZDB.gmk index 1352178694fe357c96bc4b9fa525560534ec3e54..593ed8a8f115879016afae95621de59080b0d705 100644 --- a/make/modules/java.base/gendata/GendataTZDB.gmk +++ b/make/modules/java.base/gendata/GendataTZDB.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2012, 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 @@ -28,7 +28,7 @@ GENDATA_TZDB := # # Time zone data file creation # -TZDATA_DIR := $(TOPDIR)/make/data/tzdata +TZDATA_DIR := $(MODULE_SRC)/share/data/tzdata TZDATA_TZFILE := africa antarctica asia australasia europe northamerica southamerica backward etcetera gmt jdk11_backward TZDATA_TZFILES := $(addprefix $(TZDATA_DIR)/,$(TZDATA_TZFILE)) diff --git a/make/modules/java.base/gensrc/GensrcBuffer.gmk b/make/modules/java.base/gensrc/GensrcBuffer.gmk index 6ad432fb86678b4bc14bcc8fab711e47b2d23939..ce22230a8e18444ccd597555c71c4a3225f44f75 100644 --- a/make/modules/java.base/gensrc/GensrcBuffer.gmk +++ b/make/modules/java.base/gensrc/GensrcBuffer.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 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 @@ -27,7 +27,7 @@ GENSRC_BUFFER := GENSRC_BUFFER_DST := $(SUPPORT_OUTPUTDIR)/gensrc/java.base/java/nio -GENSRC_BUFFER_SRC := $(TOPDIR)/src/java.base/share/classes/java/nio +GENSRC_BUFFER_SRC := $(MODULE_SRC)/share/classes/java/nio ### diff --git a/make/modules/java.base/gensrc/GensrcCharacterData.gmk b/make/modules/java.base/gensrc/GensrcCharacterData.gmk index eb9380165061cc750cb54d5faaffd3f34cc5052f..115a28309a2374a70e8ed4147dd259f27357e65d 100644 --- a/make/modules/java.base/gensrc/GensrcCharacterData.gmk +++ b/make/modules/java.base/gensrc/GensrcCharacterData.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 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 @@ -29,8 +29,8 @@ GENSRC_CHARACTERDATA := -CHARACTERDATA = $(TOPDIR)/make/data/characterdata -UNICODEDATA = $(TOPDIR)/make/data/unicodedata +CHARACTERDATA_TEMPLATES = $(MODULE_SRC)/share/classes/java/lang +UNICODEDATA = $(MODULE_SRC)/share/data/unicodedata ifneq ($(DEBUG_LEVEL), release) ifeq ($(ALLOW_ABSOLUTE_PATHS_IN_OUTPUT), true) @@ -40,11 +40,11 @@ endif define SetupCharacterData $(SUPPORT_OUTPUTDIR)/gensrc/java.base/java/lang/$1.java: \ - $(CHARACTERDATA)/$1.java.template + $(CHARACTERDATA_TEMPLATES)/$1.java.template $$(call LogInfo, Generating $1.java) $$(call MakeDir, $$(@D)) $(TOOL_GENERATECHARACTER) $2 $(DEBUG_OPTION) \ - -template $(CHARACTERDATA)/$1.java.template \ + -template $(CHARACTERDATA_TEMPLATES)/$1.java.template \ -spec $(UNICODEDATA)/UnicodeData.txt \ -specialcasing $(UNICODEDATA)/SpecialCasing.txt \ -proplist $(UNICODEDATA)/PropList.txt \ diff --git a/make/modules/java.base/gensrc/GensrcCharsetCoder.gmk b/make/modules/java.base/gensrc/GensrcCharsetCoder.gmk index 79fa54b19cc0072af4840be05fbaae9b11257e18..2940ba4231931a797d68972fdd92daeda42c9993 100644 --- a/make/modules/java.base/gensrc/GensrcCharsetCoder.gmk +++ b/make/modules/java.base/gensrc/GensrcCharsetCoder.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 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 @@ -27,7 +27,7 @@ GENSRC_CHARSETCODER := GENSRC_CHARSETCODER_DST := $(SUPPORT_OUTPUTDIR)/gensrc/java.base/java/nio/charset -GENSRC_CHARSETCODER_SRC := $(TOPDIR)/src/java.base/share/classes/java/nio +GENSRC_CHARSETCODER_SRC := $(MODULE_SRC)/share/classes/java/nio GENSRC_CHARSETCODER_TEMPLATE := $(GENSRC_CHARSETCODER_SRC)/charset/Charset-X-Coder.java.template diff --git a/make/modules/java.base/gensrc/GensrcEmojiData.gmk b/make/modules/java.base/gensrc/GensrcEmojiData.gmk index d92cb9354a3fd3e4f6f0606df9d07728b144f27d..1af03bcafe92523c6fbd9d08953ccd247d1ebead 100644 --- a/make/modules/java.base/gensrc/GensrcEmojiData.gmk +++ b/make/modules/java.base/gensrc/GensrcEmojiData.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. +# 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 @@ -29,8 +29,8 @@ GENSRC_EMOJIDATA := $(SUPPORT_OUTPUTDIR)/gensrc/java.base/java/util/regex/EmojiData.java -EMOJIDATATEMP = $(TOPDIR)/src/java.base/share/classes/java/util/regex/EmojiData.java.template -UNICODEDATA = $(TOPDIR)/make/data/unicodedata +EMOJIDATATEMP = $(MODULE_SRC)/share/classes/java/util/regex/EmojiData.java.template +UNICODEDATA = $(MODULE_SRC)/share/data/unicodedata $(GENSRC_EMOJIDATA): $(BUILD_TOOLS_JDK) $(EMOJIDATATEMP) $(UNICODEDATA)/emoji/emoji-data.txt $(call LogInfo, Generating $@) diff --git a/make/modules/java.base/gensrc/GensrcExceptions.gmk b/make/modules/java.base/gensrc/GensrcExceptions.gmk index 37fed896560b7217e2c45e9a4da5598244d3959c..1c4974b4a28c6f01ad8f9d8713895b99f9e43682 100644 --- a/make/modules/java.base/gensrc/GensrcExceptions.gmk +++ b/make/modules/java.base/gensrc/GensrcExceptions.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 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 @@ -27,7 +27,7 @@ GENSRC_EXCEPTIONS := GENSRC_EXCEPTIONS_DST := $(SUPPORT_OUTPUTDIR)/gensrc/java.base/java/nio -GENSRC_EXCEPTIONS_SRC := $(TOPDIR)/src/java.base/share/classes/java/nio +GENSRC_EXCEPTIONS_SRC := $(MODULE_SRC)/share/classes/java/nio GENSRC_EXCEPTIONS_CMD := $(TOPDIR)/make/scripts/genExceptions.sh GENSRC_EXCEPTIONS_SRC_DIRS := . charset channels diff --git a/make/modules/java.base/gensrc/GensrcLocaleData.gmk b/make/modules/java.base/gensrc/GensrcLocaleData.gmk index 1e28d91ab684eb9941da504b0915e997b7f69800..c04bab5317570eb830f44316a61ac6cdd1c58ae7 100644 --- a/make/modules/java.base/gensrc/GensrcLocaleData.gmk +++ b/make/modules/java.base/gensrc/GensrcLocaleData.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 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 @@ -29,8 +29,8 @@ # First go look for all locale files LOCALE_FILES := $(call FindFiles, \ - $(TOPDIR)/src/$(MODULE)/share/classes/sun/text/resources \ - $(TOPDIR)/src/$(MODULE)/share/classes/sun/util/resources, \ + $(MODULE_SRC)/share/classes/sun/text/resources \ + $(MODULE_SRC)/share/classes/sun/util/resources, \ FormatData_*.java FormatData_*.properties \ CollationData_*.java CollationData_*.properties \ TimeZoneNames_*.java TimeZoneNames_*.properties \ diff --git a/make/modules/java.base/gensrc/GensrcScopedMemoryAccess.gmk b/make/modules/java.base/gensrc/GensrcScopedMemoryAccess.gmk index b431acc14e1183e577b15200cb393d04d6d9cc13..54fea77571e90209b635811a9348c5732c900d25 100644 --- a/make/modules/java.base/gensrc/GensrcScopedMemoryAccess.gmk +++ b/make/modules/java.base/gensrc/GensrcScopedMemoryAccess.gmk @@ -24,7 +24,7 @@ # SCOPED_MEMORY_ACCESS_GENSRC_DIR := $(SUPPORT_OUTPUTDIR)/gensrc/java.base/jdk/internal/misc -SCOPED_MEMORY_ACCESS_SRC_DIR := $(TOPDIR)/src/java.base/share/classes/jdk/internal/misc +SCOPED_MEMORY_ACCESS_SRC_DIR := $(MODULE_SRC)/share/classes/jdk/internal/misc SCOPED_MEMORY_ACCESS_TEMPLATE := $(SCOPED_MEMORY_ACCESS_SRC_DIR)/X-ScopedMemoryAccess.java.template SCOPED_MEMORY_ACCESS_BIN_TEMPLATE := $(SCOPED_MEMORY_ACCESS_SRC_DIR)/X-ScopedMemoryAccess-bin.java.template SCOPED_MEMORY_ACCESS_DEST := $(SCOPED_MEMORY_ACCESS_GENSRC_DIR)/ScopedMemoryAccess.java @@ -139,7 +139,7 @@ endef SCOPE_MEMORY_ACCESS_TYPES := Byte Short Char Int Long Float Double $(foreach t, $(SCOPE_MEMORY_ACCESS_TYPES), \ $(eval $(call GenerateScopedOp,BIN_$t,$t))) - + $(SCOPED_MEMORY_ACCESS_DEST): $(BUILD_TOOLS_JDK) $(SCOPED_MEMORY_ACCESS_TEMPLATE) $(SCOPED_MEMORY_ACCESS_BIN_TEMPLATE) $(call MakeDir, $(SCOPED_MEMORY_ACCESS_GENSRC_DIR)) $(CAT) $(SCOPED_MEMORY_ACCESS_TEMPLATE) > $(SCOPED_MEMORY_ACCESS_DEST) @@ -147,5 +147,5 @@ $(SCOPED_MEMORY_ACCESS_DEST): $(BUILD_TOOLS_JDK) $(SCOPED_MEMORY_ACCESS_TEMPLATE $(TOOL_SPP) -nel -K$(BIN_$t_type) -Dtype=$(BIN_$t_type) -DType=$(BIN_$t_Type) $(BIN_$t_ARGS) \ -i$(SCOPED_MEMORY_ACCESS_BIN_TEMPLATE) -o$(SCOPED_MEMORY_ACCESS_DEST) ;) $(PRINTF) "}\n" >> $(SCOPED_MEMORY_ACCESS_DEST) - + TARGETS += $(SCOPED_MEMORY_ACCESS_DEST) diff --git a/make/modules/java.base/gensrc/GensrcVarHandles.gmk b/make/modules/java.base/gensrc/GensrcVarHandles.gmk index 579488379c333d853223de5c5a949d30dc55f3b2..e1686834bf5e908dd8d64676c23408ede400b9a1 100644 --- a/make/modules/java.base/gensrc/GensrcVarHandles.gmk +++ b/make/modules/java.base/gensrc/GensrcVarHandles.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. +# 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 @@ -26,7 +26,7 @@ GENSRC_VARHANDLES := VARHANDLES_GENSRC_DIR := $(SUPPORT_OUTPUTDIR)/gensrc/java.base/java/lang/invoke -VARHANDLES_SRC_DIR := $(TOPDIR)/src/java.base/share/classes/java/lang/invoke +VARHANDLES_SRC_DIR := $(MODULE_SRC)/share/classes/java/lang/invoke ################################################################################ # Setup a rule for generating a VarHandle java class diff --git a/make/modules/java.compiler/Java.gmk b/make/modules/java.compiler/Java.gmk index e124e8844d3b39179d97b509f66430fd05c9029f..e2d5ac264b8b6406cf5c928d40d9c018cf103d9e 100644 --- a/make/modules/java.compiler/Java.gmk +++ b/make/modules/java.compiler/Java.gmk @@ -25,3 +25,5 @@ DOCLINT += -Xdoclint:all/protected \ '-Xdoclint/package:java.*,javax.*' + +EXCLUDES += javax/tools/snippet-files diff --git a/make/modules/java.datatransfer/Java.gmk b/make/modules/java.datatransfer/Java.gmk index a9f7c8f4f0af9aee4b8f5decbc2af7e42c9d7c59..29feb6df9f55283dce03fa03f4ab659a3c6b56f5 100644 --- a/make/modules/java.datatransfer/Java.gmk +++ b/make/modules/java.datatransfer/Java.gmk @@ -23,6 +23,6 @@ # questions. # -DOCLINT += -Xdoclint:all/protected,-reference \ +DOCLINT += -Xdoclint:all/protected \ '-Xdoclint/package:java.*,javax.*' COPY += flavormap.properties diff --git a/make/modules/java.desktop/Java.gmk b/make/modules/java.desktop/Java.gmk index e9f0d1fa3184ef08fa19f64851534655cbdddb73..a6d6cf80c1d86b4ebbfaf292f196ad43ec0d7ff7 100644 --- a/make/modules/java.desktop/Java.gmk +++ b/make/modules/java.desktop/Java.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. +# 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 @@ -23,7 +23,7 @@ # questions. # -DOCLINT += -Xdoclint:all/protected,-reference,-missing \ +DOCLINT += -Xdoclint:all/protected \ '-Xdoclint/package:java.*,javax.*' COPY += .gif .png .wav .txt .xml .css .pf CLEAN += iio-plugin.properties cursors.properties diff --git a/make/modules/java.desktop/gendata/GendataFontConfig.gmk b/make/modules/java.desktop/gendata/GendataFontConfig.gmk index 42e3f4b485f14c3c6ca126825fc9748ecf5a32bc..92a64b986e189c4c6a6c98a841607989814a0769 100644 --- a/make/modules/java.desktop/gendata/GendataFontConfig.gmk +++ b/make/modules/java.desktop/gendata/GendataFontConfig.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 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 @@ -23,30 +23,35 @@ # questions. # -GENDATA_FONT_CONFIG_DST := $(SUPPORT_OUTPUTDIR)/modules_libs/$(MODULE) +FONTCONFIG_DATA_DIR := $(MODULE_SRC)/$(OPENJDK_TARGET_OS)/data/fontconfig +FONTCONFIG_SRC_FILE := $(FONTCONFIG_DATA_DIR)/fontconfig.properties -GENDATA_FONT_CONFIG_DATA_DIR ?= $(TOPDIR)/make/data/fontconfig +FONTCONFIG_DEST_DIR := $(SUPPORT_OUTPUTDIR)/modules_libs/$(MODULE) +FONTCONFIG_OUT_FILE := $(FONTCONFIG_DEST_DIR)/fontconfig.properties.src +FONTCONFIG_OUT_BIN_FILE := $(FONTCONFIG_DEST_DIR)/fontconfig.bfc -GENDATA_FONT_CONFIG_SRC_FILES := \ - $(wildcard $(GENDATA_FONT_CONFIG_DATA_DIR)/$(OPENJDK_TARGET_OS).*) +ifneq ($(findstring $(LOG_LEVEL), debug trace), ) + FONTCONFIG_VERBOSE_FLAG := -verbose +endif +# Not all OSes have a fontconfig file +ifneq ($(wildcard $(FONTCONFIG_SRC_FILE)), ) -$(GENDATA_FONT_CONFIG_DST)/%.src: \ - $(GENDATA_FONT_CONFIG_DATA_DIR)/$(OPENJDK_TARGET_OS).% + # Copy properties file as-is + $(FONTCONFIG_OUT_FILE): $(FONTCONFIG_SRC_FILE) + $(call LogInfo, Copying fontconfig.properties) $(call install-file) -$(GENDATA_FONT_CONFIG_DST)/%.bfc: \ - $(GENDATA_FONT_CONFIG_DATA_DIR)/$(OPENJDK_TARGET_OS).%.properties \ - $(BUILD_TOOLS_JDK) + TARGETS += $(FONTCONFIG_OUT_FILE) + + # Generate binary representation + $(FONTCONFIG_OUT_BIN_FILE): $(FONTCONFIG_SRC_FILE) $(BUILD_TOOLS_JDK) + $(call LogInfo, Compiling fontconfig.properties to binary) $(call MakeTargetDir) $(RM) $@ - $(TOOL_COMPILEFONTCONFIG) $< $@ + $(TOOL_COMPILEFONTCONFIG) $(FONTCONFIG_VERBOSE_FLAG) $< $@ $(CHMOD) 444 $@ + TARGETS += $(FONTCONFIG_OUT_BIN_FILE) -GENDATA_FONT_CONFIGS := $(patsubst $(GENDATA_FONT_CONFIG_DATA_DIR)/$(OPENJDK_TARGET_OS).%, \ - $(GENDATA_FONT_CONFIG_DST)/%.src, $(GENDATA_FONT_CONFIG_SRC_FILES)) -GENDATA_BFONT_CONFIGS := $(patsubst $(GENDATA_FONT_CONFIG_DATA_DIR)/$(OPENJDK_TARGET_OS).%.properties, \ - $(GENDATA_FONT_CONFIG_DST)/%.bfc, $(GENDATA_FONT_CONFIG_SRC_FILES)) - -TARGETS := $(GENDATA_FONT_CONFIGS) $(GENDATA_BFONT_CONFIGS) +endif diff --git a/make/modules/java.desktop/gensrc/GensrcIcons.gmk b/make/modules/java.desktop/gensrc/GensrcIcons.gmk index e0a6c107eccfe2dc1b1f7bafe64431e7b117590f..28434d3f4c1be48a8f541e01fabb472c20164a54 100644 --- a/make/modules/java.desktop/gensrc/GensrcIcons.gmk +++ b/make/modules/java.desktop/gensrc/GensrcIcons.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 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 @@ -29,7 +29,7 @@ GENSRC_AWT_ICONS_TMP := $(SUPPORT_OUTPUTDIR)/gensrc/java.desktop GENSRC_AWT_ICONS_DST := $(GENSRC_AWT_ICONS_TMP)/sun/awt/ # Allow this to be overridden from a custom makefile -X11_ICONS_PATH_PREFIX ?= $(TOPDIR)/src/java.desktop/$(OPENJDK_TARGET_OS_TYPE) +X11_ICONS_PATH_PREFIX ?= $(MODULE_SRC)/$(OPENJDK_TARGET_OS_TYPE) GENSRC_AWT_ICONS_SRC += \ $(X11_ICONS_PATH_PREFIX)/classes/sun/awt/X11/java-icon16.png \ @@ -38,7 +38,7 @@ GENSRC_AWT_ICONS_SRC += \ $(X11_ICONS_PATH_PREFIX)/classes/sun/awt/X11/java-icon48.png -AWT_ICONPATH := $(TOPDIR)/src/java.desktop/share/classes/sun/awt/resources +AWT_ICONPATH := $(MODULE_SRC)/share/classes/sun/awt/resources GENSRC_AWT_ICONS_SRC += \ $(AWT_ICONPATH)/security-icon-bw16.png \ @@ -111,7 +111,7 @@ ifeq ($(call isTargetOs, macosx), true) GENSRC_OSX_ICONS_DST := $(SUPPORT_OUTPUTDIR)/headers/java.desktop GENSRC_OSX_ICONS := $(GENSRC_OSX_ICONS_DST)/AWTIconData.h - GENSRC_OSX_ICONS_SRC ?= $(TOPDIR)/make/data/macosxicons/JavaApp.icns + GENSRC_OSX_ICONS_SRC ?= $(MODULE_SRC)/macosx/data/macosxicons/JavaApp.icns $(GENSRC_OSX_ICONS): $(GENSRC_OSX_ICONS_SRC) $(BUILD_TOOLS_JDK) diff --git a/make/modules/java.desktop/gensrc/GensrcSwing.gmk b/make/modules/java.desktop/gensrc/GensrcSwing.gmk index cfb50831d1bcc7d7464bb3ec2f31a702c85a16db..abd428f3641987eb687ab7d46d87402663c34228 100644 --- a/make/modules/java.desktop/gensrc/GensrcSwing.gmk +++ b/make/modules/java.desktop/gensrc/GensrcSwing.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 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 @@ -28,7 +28,7 @@ # NIMBUS_PACKAGE = javax.swing.plaf NIMBUS_GENSRC_DIR = $(SUPPORT_OUTPUTDIR)/gensrc/java.desktop/javax/swing/plaf/nimbus -NIMBUS_SKIN_FILE = $(TOPDIR)/src/java.desktop/share/classes/javax/swing/plaf/nimbus/skin.laf +NIMBUS_SKIN_FILE = $(MODULE_SRC)/share/classes/javax/swing/plaf/nimbus/skin.laf $(SUPPORT_OUTPUTDIR)/gensrc/java.desktop/_the.generated_nimbus: $(NIMBUS_SKIN_FILE) $(BUILD_TOOLS_JDK) $(call LogInfo, Generating Nimbus source files) diff --git a/make/modules/java.desktop/gensrc/GensrcX11Wrappers.gmk b/make/modules/java.desktop/gensrc/GensrcX11Wrappers.gmk index d46328f8607984f61186a67bce64e0c89ae41ea1..25402ad035a5b6d0f4729bf360c30f62bc04f58a 100644 --- a/make/modules/java.desktop/gensrc/GensrcX11Wrappers.gmk +++ b/make/modules/java.desktop/gensrc/GensrcX11Wrappers.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2012, 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 @@ -24,13 +24,13 @@ # # Generate java sources using the X11 offsets that are precalculated in files -# make/data/x11wrappergen/sizes-
      .txt. +# src/java.desktop/unix/data/x11wrappergen/sizes-
      .txt. # Put the generated Java classes used to interface X11 from awt here. GENSRC_X11WRAPPERS_OUTPUTDIR := $(SUPPORT_OUTPUTDIR)/gensrc/java.desktop/sun/awt/X11 # The pre-calculated offset file are stored here: -GENSRC_X11WRAPPERS_DATADIR := $(TOPDIR)/make/data/x11wrappergen +GENSRC_X11WRAPPERS_DATADIR := $(MODULE_SRC)/unix/data/x11wrappergen GENSRC_X11WRAPPERS_DATA := $(GENSRC_X11WRAPPERS_DATADIR)/sizes-$(OPENJDK_TARGET_CPU_BITS).txt # Run the tool on the offset files to generate several Java classes used in awt. diff --git a/make/modules/java.desktop/lib/Awt2dLibraries.gmk b/make/modules/java.desktop/lib/Awt2dLibraries.gmk index ef7eadae20672fe31d0e94be54b46807322fe862..3cf8ca8a820e8439ab1582b3d2d01a1ea69442b9 100644 --- a/make/modules/java.desktop/lib/Awt2dLibraries.gmk +++ b/make/modules/java.desktop/lib/Awt2dLibraries.gmk @@ -742,7 +742,7 @@ ifeq ($(ENABLE_HEADLESS_ONLY), false) maybe-uninitialized shift-negative-value implicit-fallthrough \ unused-function, \ DISABLED_WARNINGS_clang := incompatible-pointer-types sign-compare \ - deprecated-declarations, \ + deprecated-declarations null-pointer-subtraction, \ DISABLED_WARNINGS_microsoft := 4018 4244 4267, \ LDFLAGS := $(LDFLAGS_JDKLIB) \ $(call SET_SHARED_LIBRARY_ORIGIN), \ @@ -834,6 +834,19 @@ endif ################################################################################ +# MACOSX_METAL_VERSION_MIN specifies the lowest version of Macosx +# that should be used to compile Metal shaders. We support Metal +# pipeline only on Macosx >=10.14. For Macosx versions <10.14 even if +# we enable Metal pipeline using -Dsun.java2d.metal=true, at +# runtime we force it to use OpenGL pipeline. And MACOSX_VERSION_MIN +# for aarch64 has always been >10.14 so we use continue to use +# MACOSX_VERSION_MIN for aarch64. +ifeq ($(OPENJDK_TARGET_CPU_ARCH), xaarch64) + MACOSX_METAL_VERSION_MIN=$(MACOSX_VERSION_MIN) +else + MACOSX_METAL_VERSION_MIN=10.14.0 +endif + ifeq ($(call isTargetOs, macosx), true) SHADERS_SRC := $(TOPDIR)/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/shaders.metal SHADERS_SUPPORT_DIR := $(SUPPORT_OUTPUTDIR)/native/java.desktop/libosxui @@ -845,7 +858,9 @@ ifeq ($(call isTargetOs, macosx), true) DEPS := $(SHADERS_SRC), \ OUTPUT_FILE := $(SHADERS_AIR), \ SUPPORT_DIR := $(SHADERS_SUPPORT_DIR), \ - COMMAND := $(METAL) -c -std=osx-metal2.0 -o $(SHADERS_AIR) $(SHADERS_SRC), \ + COMMAND := $(METAL) -c -std=osx-metal2.0 \ + -mmacosx-version-min=$(MACOSX_METAL_VERSION_MIN) \ + -o $(SHADERS_AIR) $(SHADERS_SRC), \ )) $(eval $(call SetupExecute, metallib_shaders, \ diff --git a/make/modules/java.instrument/Java.gmk b/make/modules/java.instrument/Java.gmk index 5f46b155e0cc22c61f8f9f898e81a8c681af14ee..f49e425718e7fc45c52e1f55c81e221145a781cf 100644 --- a/make/modules/java.instrument/Java.gmk +++ b/make/modules/java.instrument/Java.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. +# 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 @@ -23,5 +23,5 @@ # questions. # -DOCLINT += -Xdoclint:all/protected,-accessibility \ +DOCLINT += -Xdoclint:all/protected \ '-Xdoclint/package:java.*,javax.*' diff --git a/make/modules/java.logging/Java.gmk b/make/modules/java.logging/Java.gmk index 40da53d432b1692f18278d1895fcdb705b38e30e..f49e425718e7fc45c52e1f55c81e221145a781cf 100644 --- a/make/modules/java.logging/Java.gmk +++ b/make/modules/java.logging/Java.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. +# 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 @@ -23,5 +23,5 @@ # questions. # -DOCLINT += -Xdoclint:all/protected,-reference,-accessibility \ +DOCLINT += -Xdoclint:all/protected \ '-Xdoclint/package:java.*,javax.*' diff --git a/make/modules/java.management/Java.gmk b/make/modules/java.management/Java.gmk index 40da53d432b1692f18278d1895fcdb705b38e30e..f49e425718e7fc45c52e1f55c81e221145a781cf 100644 --- a/make/modules/java.management/Java.gmk +++ b/make/modules/java.management/Java.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. +# 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 @@ -23,5 +23,5 @@ # questions. # -DOCLINT += -Xdoclint:all/protected,-reference,-accessibility \ +DOCLINT += -Xdoclint:all/protected \ '-Xdoclint/package:java.*,javax.*' diff --git a/make/modules/java.naming/Java.gmk b/make/modules/java.naming/Java.gmk index 32bb474385f2a86a12d5bbab4946cf98250d68fd..648853d6f532c204b61eb9f41e6c2ea314582356 100644 --- a/make/modules/java.naming/Java.gmk +++ b/make/modules/java.naming/Java.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. +# 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 @@ -23,6 +23,6 @@ # questions. # -DOCLINT += -Xdoclint:all/protected,-accessibility \ +DOCLINT += -Xdoclint:all/protected \ '-Xdoclint/package:java.*,javax.*' CLEAN += jndiprovider.properties diff --git a/make/modules/java.rmi/Launcher.gmk b/make/modules/java.rmi/Launcher.gmk index 8a540da898b953e9b267f2eed4de9bf5da355531..001bc204c942db623bcdaee1bde03f99fbd7a199 100644 --- a/make/modules/java.rmi/Launcher.gmk +++ b/make/modules/java.rmi/Launcher.gmk @@ -27,4 +27,5 @@ include LauncherCommon.gmk $(eval $(call SetupBuildLauncher, rmiregistry, \ MAIN_CLASS := sun.rmi.registry.RegistryImpl, \ + JAVA_ARGS := -Djava.security.manager=allow, \ )) diff --git a/make/modules/java.smartcardio/Java.gmk b/make/modules/java.smartcardio/Java.gmk index 5f46b155e0cc22c61f8f9f898e81a8c681af14ee..f49e425718e7fc45c52e1f55c81e221145a781cf 100644 --- a/make/modules/java.smartcardio/Java.gmk +++ b/make/modules/java.smartcardio/Java.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. +# 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 @@ -23,5 +23,5 @@ # questions. # -DOCLINT += -Xdoclint:all/protected,-accessibility \ +DOCLINT += -Xdoclint:all/protected \ '-Xdoclint/package:java.*,javax.*' diff --git a/make/modules/java.sql.rowset/Java.gmk b/make/modules/java.sql.rowset/Java.gmk index 2ea5be28ed17dece0db11134a408d0cd8ddb68ff..63437c6113f5ea153c6d599ed8467b75040aa1ee 100644 --- a/make/modules/java.sql.rowset/Java.gmk +++ b/make/modules/java.sql.rowset/Java.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. +# 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 @@ -23,7 +23,7 @@ # questions. # -DOCLINT += -Xdoclint:all/protected,-accessibility \ +DOCLINT += -Xdoclint:all/protected \ '-Xdoclint/package:java.*,javax.*' CLEAN_FILES += $(wildcard \ $(TOPDIR)/src/java.sql.rowset/share/classes/com/sun/rowset/*.properties \ diff --git a/make/modules/java.xml/Java.gmk b/make/modules/java.xml/Java.gmk index b7bf8b701650124702baf8e85d38ea2517a4e3aa..aa4b786020fea5a4c39bdba74e63636042a6eda9 100644 --- a/make/modules/java.xml/Java.gmk +++ b/make/modules/java.xml/Java.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. +# 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 @@ -23,7 +23,7 @@ # questions. # -DOCLINT += -Xdoclint:all/protected,-accessibility \ +DOCLINT += -Xdoclint:all/protected \ '-Xdoclint/package:$(call CommaList, javax.xml.catalog javax.xml.datatype \ javax.xml.transform javax.xml.validation javax.xml.xpath)' CLEAN += .properties diff --git a/make/modules/jdk.charsets/Gensrc.gmk b/make/modules/jdk.charsets/Gensrc.gmk index ca9c19409411ee21d325c89ac588567ea2b2a690..1fac37b2c4b99fa1268cc96241b4f7dc6fb5ee2c 100644 --- a/make/modules/jdk.charsets/Gensrc.gmk +++ b/make/modules/jdk.charsets/Gensrc.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 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 @@ -38,8 +38,8 @@ CHARSET_TEMPLATES := \ $(CHARSET_DATA_DIR)/SingleByte-X.java.template \ $(CHARSET_DATA_DIR)/DoubleByte-X.java.template CHARSET_EXTENDED_JAVA_TEMPLATES := \ - $(TOPDIR)/src/jdk.charsets/share/classes/sun/nio/cs/ext/ExtendedCharsets.java.template -CHARSET_EXTENDED_JAVA_DIR := $(TOPDIR)/src/jdk.charsets/share/classes/sun/nio/cs/ext + $(MODULE_SRC)/share/classes/sun/nio/cs/ext/ExtendedCharsets.java.template +CHARSET_EXTENDED_JAVA_DIR := $(MODULE_SRC)/share/classes/sun/nio/cs/ext CHARSET_STANDARD_OS := stdcs-$(OPENJDK_TARGET_OS) $(CHARSET_DONE_CS)-extcs: $(CHARSET_DATA_DIR)/charsets \ diff --git a/make/modules/jdk.compiler/Gendata.gmk b/make/modules/jdk.compiler/Gendata.gmk index 85815e5524b1edeb7423a5199a328fa053e70c49..5471fa1127c1c664aeac5613fc4f3a65a2c83e80 100644 --- a/make/modules/jdk.compiler/Gendata.gmk +++ b/make/modules/jdk.compiler/Gendata.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. +# 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 @@ -41,7 +41,7 @@ CT_MODULES := $(DOCS_MODULES) # Get the complete module source path: CT_MODULESOURCEPATH := $(call GetModuleSrcPath) -CT_DATA_DESCRIPTION += $(TOPDIR)/make/data/symbols/symbols +CT_DATA_DESCRIPTION += $(MODULE_SRC)/share/data/symbols/symbols COMPILECREATESYMBOLS_ADD_EXPORTS := \ --add-exports java.base/jdk.internal.javac=java.compiler.interim,jdk.compiler.interim \ @@ -65,7 +65,7 @@ $(eval $(call SetupJavaCompilation, COMPILE_CREATE_SYMBOLS, \ $(SUPPORT_OUTPUTDIR)/symbols/ct.sym: \ $(COMPILE_CREATE_SYMBOLS) \ - $(wildcard $(TOPDIR)/make/data/symbols/*) \ + $(wildcard $(MODULE_SRC)/share/data/symbols/*) \ $(MODULE_INFOS) $(RM) -r $(@D) $(MKDIR) -p $(@D) diff --git a/make/modules/jdk.unsupported.desktop/Java.gmk b/make/modules/jdk.httpserver/Launcher.gmk similarity index 84% rename from make/modules/jdk.unsupported.desktop/Java.gmk rename to make/modules/jdk.httpserver/Launcher.gmk index f892ebeb84c171d99d372a9203ace9abdbc16e5a..ead28ba1ca5ee7bdb460ded024029f487785eaeb 100644 --- a/make/modules/jdk.unsupported.desktop/Java.gmk +++ b/make/modules/jdk.httpserver/Launcher.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. +# 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 @@ -23,4 +23,8 @@ # questions. # -DISABLED_WARNINGS_java += missing-explicit-ctor +include LauncherCommon.gmk + +$(eval $(call SetupBuildLauncher, jwebserver, \ + MAIN_CLASS := sun.net.httpserver.simpleserver.JWebServer, \ +)) diff --git a/make/modules/jdk.javadoc/Gendata.gmk b/make/modules/jdk.javadoc/Gendata.gmk index 50ef87545a4cdf360d52e3de65973777dac21bab..69c93c29468b890b3888f25c65fd75e3a6277fa7 100644 --- a/make/modules/jdk.javadoc/Gendata.gmk +++ b/make/modules/jdk.javadoc/Gendata.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. +# 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 @@ -39,7 +39,7 @@ JAVADOC_MODULES := $(DOCS_MODULES) # Get the complete module source path: JAVADOC_MODULESOURCEPATH := $(call GetModuleSrcPath) -CT_DATA_DESCRIPTION += $(TOPDIR)/make/data/symbols/symbols +CT_DATA_DESCRIPTION += $(TOPDIR)/src/jdk.compiler/share/data/symbols/symbols COMPILECREATESYMBOLS_ADD_EXPORTS := \ --add-exports java.base/jdk.internal=java.compiler.interim,jdk.compiler.interim \ @@ -68,7 +68,7 @@ ELEMENT_LISTS_DIR := $(JDK_JAVADOC_DIR)/$(ELEMENT_LISTS_PKG) $(JDK_JAVADOC_DIR)/_element_lists.marker: \ $(COMPILE_CREATE_SYMBOLS) \ - $(wildcard $(TOPDIR)/make/data/symbols/*) \ + $(wildcard $(TOPDIR)/src/jdk.compiler/share/data/symbols/*) \ $(MODULE_INFOS) $(call MakeTargetDir) $(call LogInfo, Creating javadoc element lists) diff --git a/make/modules/jdk.jdi/Gensrc.gmk b/make/modules/jdk.jdi/Gensrc.gmk index 5487e950921ea59c36051566daa702791c9174c7..7db06b5c95873a3e0b5258124b82dcc095286bff 100644 --- a/make/modules/jdk.jdi/Gensrc.gmk +++ b/make/modules/jdk.jdi/Gensrc.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 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 @@ -26,10 +26,11 @@ include GensrcCommonJdk.gmk ################################################################################ -# Translate the Java debugger wire protocol (jdwp.spec) file into a JDWP.java file -# and a JDWPCommands.h C-header file. +# Translate the Java debugger wire protocol (jdwp.spec) file into a front-end +# Java implementation (JDWP.java), a back-end C header file (JDWPCommands.h) and +# an HTML documentation file (jdwp-protocol.html). -JDWP_SPEC_FILE := $(TOPDIR)/make/data/jdwp/jdwp.spec +JDWP_SPEC_FILE := $(TOPDIR)/src/java.se/share/data/jdwp/jdwp.spec HEADER_FILE := $(SUPPORT_OUTPUTDIR)/headers/jdk.jdwp.agent/JDWPCommands.h JAVA_FILE := $(SUPPORT_OUTPUTDIR)/gensrc/jdk.jdi/com/sun/tools/jdi/JDWP.java HTML_FILE := $(SUPPORT_OUTPUTDIR)/gensrc/jdk.jdi/jdwp-protocol.html diff --git a/make/modules/jdk.jpackage/Lib.gmk b/make/modules/jdk.jpackage/Lib.gmk index aa955b97bee330a6045e51b4ba448b87883d221a..9d118d950f5efe72baa8c3a793a0b77c06374ede 100644 --- a/make/modules/jdk.jpackage/Lib.gmk +++ b/make/modules/jdk.jpackage/Lib.gmk @@ -92,9 +92,9 @@ ifeq ($(call isTargetOs, linux), true) JPACKAGE_LIBAPPLAUNCHER_INCLUDES := $(addprefix -I, $(JPACKAGE_LIBAPPLAUNCHER_SRC)) $(eval $(call SetupJdkLibrary, BUILD_JPACKAGE_LIBAPPLAUNCHER, \ - NAME := jpackageapplauncher, \ + NAME := jpackageapplauncheraux, \ OUTPUT_DIR := $(JPACKAGE_OUTPUT_DIR), \ - SYMBOLS_DIR := $(SUPPORT_OUTPUTDIR)/native/$(MODULE)/libjpackageapplauncher, \ + SYMBOLS_DIR := $(SUPPORT_OUTPUTDIR)/native/$(MODULE)/libjpackageapplauncheraux, \ SRC := $(JPACKAGE_LIBAPPLAUNCHER_SRC), \ EXCLUDE_FILES := LinuxLauncher.c LinuxPackage.c, \ TOOLCHAIN := TOOLCHAIN_LINK_CXX, \ diff --git a/make/modules/jdk.jstatd/Launcher.gmk b/make/modules/jdk.jstatd/Launcher.gmk index de481b78b6c71e687f03544df59195984a336284..2137fddd9a01011215b73bd8fc6b6cb577f334a7 100644 --- a/make/modules/jdk.jstatd/Launcher.gmk +++ b/make/modules/jdk.jstatd/Launcher.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 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 diff --git a/make/modules/jdk.localedata/Gensrc.gmk b/make/modules/jdk.localedata/Gensrc.gmk index ce746e8973231f39068280fda5b52cf62cf5dc97..233572c8a544bde9338cd01146636658dd0b6bb6 100644 --- a/make/modules/jdk.localedata/Gensrc.gmk +++ b/make/modules/jdk.localedata/Gensrc.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2014, 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 @@ -46,6 +46,7 @@ $(CLDR_GEN_DONE): $(wildcard $(CLDR_DATA_DIR)/dtd/*.dtd) \ $(call ExecuteWithLog, $@, \ $(TOOL_CLDRCONVERTER) -base $(CLDR_DATA_DIR) \ -baselocales "en-US" \ + -year $(COPYRIGHT_YEAR) \ -o $(GENSRC_DIR)) $(TOUCH) $@ @@ -56,7 +57,7 @@ TARGETS += $(CLDR_GEN_DONE) include GensrcProperties.gmk $(eval $(call SetupCompileProperties, COMPILE_PROPERTIES, \ - SRC_DIRS := $(TOPDIR)/src/jdk.localedata/share/classes/sun/util/resources, \ + SRC_DIRS := $(MODULE_SRC)/share/classes/sun/util/resources, \ CLASS := sun.util.resources.LocaleNamesBundle, \ KEEP_ALL_TRANSLATIONS := true, \ )) diff --git a/make/scripts/compare.sh b/make/scripts/compare.sh index cc05476c997e5090c860882fe72e241b1bf89531..a0006fa4ceee104ccc9948cf7bd3a27a45993615 100644 --- a/make/scripts/compare.sh +++ b/make/scripts/compare.sh @@ -1,6 +1,6 @@ #!/bin/bash # -# Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2012, 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 @@ -324,7 +324,7 @@ compare_general_files() { ! -name "*.cpl" ! -name "*.pdb" ! -name "*.exp" ! -name "*.ilk" \ ! -name "*.lib" ! -name "*.jmod" ! -name "*.exe" \ ! -name "*.obj" ! -name "*.o" ! -name "jspawnhelper" ! -name "*.a" \ - ! -name "*.tar.gz" ! -name "*.jsa" ! -name "gtestLauncher" \ + ! -name "*.tar.gz" ! -name "classes_nocoops.jsa" ! -name "gtestLauncher" \ ! -name "*.map" \ | $GREP -v "./bin/" | $SORT | $FILTER) diff --git a/make/scripts/generate-symbol-data.sh b/make/scripts/generate-symbol-data.sh index 56aa8016dd6a8a55730682e0484eb034a1cb51fa..ee1d540715fd3905021269dcc6c4ae48cc57e1d8 100644 --- a/make/scripts/generate-symbol-data.sh +++ b/make/scripts/generate-symbol-data.sh @@ -34,19 +34,19 @@ # - have a checkout the JDK to which the data should be added (or in which the data should be updated). # The checkout directory will be denoted as "${JDK_CHECKOUT}" in the further text. # The checkout must not have any local changes that could interfere with the new data. In particular, -# there must be absolutely no changed, new or removed files under the ${JDK_CHECKOUT}/make/data/symbols +# there must be absolutely no changed, new or removed files under the ${JDK_CHECKOUT}/src/jdk.compiler/share/data/symbols # directory. # - open a terminal program and run these commands: -# cd "${JDK_CHECKOUT}"/make/data/symbols +# cd "${JDK_CHECKOUT}"/src/jdk.compiler/share/data/symbols # bash ../../scripts/generate-symbol-data.sh "${JDK_N_INSTALL}" -# - this command will generate or update data for "--release N" into the ${JDK_CHECKOUT}/make/data/symbols +# - this command will generate or update data for "--release N" into the ${JDK_CHECKOUT}/src/jdk.compiler/share/data/symbols # directory, updating all registration necessary. If the goal was to update the data, and there are no -# new or changed files in the ${JDK_CHECKOUT}/make/data/symbols directory after running this script, +# new or changed files in the ${JDK_CHECKOUT}/src/jdk.compiler/share/data/symbols directory after running this script, # there were no relevant changes and no further action is necessary. Note that version for N > 9 are encoded # using capital letters, i.e. A represents version 10, B represents 11, and so on. The version numbers are in -# the names of the files in the ${JDK_CHECKOUT}/make/data/symbols directory, as well as in -# the ${JDK_CHECKOUT}/make/data/symbols/symbols file. -# - if there are any changed/new files in the ${JDK_CHECKOUT}/make/data/symbols directory after running this script, +# the names of the files in the ${JDK_CHECKOUT}/src/jdk.compiler/share/data/symbols directory, as well as in +# the ${JDK_CHECKOUT}/src/jdk.compiler/share/data/symbols/symbols file. +# - if there are any changed/new files in the ${JDK_CHECKOUT}/src/jdk.compiler/share/data/symbols directory after running this script, # then all the changes in this directory, including any new files, need to be sent for review and eventually pushed. # The commit message should specify which binary build was installed in the ${JDK_N_INSTALL} directory and also # include the SCM state that was used to build it, which can be found in ${JDK_N_INSTALL}/release, @@ -59,12 +59,12 @@ if [ "$1x" = "x" ] ; then fi; if [ ! -f symbols ] ; then - echo "Must run inside the make/data/symbols directory" >&2 + echo "Must run inside the src/jdk.compiler/share/data/symbols directory" >&2 exit 1 fi; if [ "`git status --porcelain=v1 .`x" != "x" ] ; then - echo "The make/data/symbols directory contains local changes!" >&2 + echo "The src/jdk.compiler/share/data/symbols directory contains local changes!" >&2 exit 1 fi; diff --git a/make/scripts/update_copyright_year.sh b/make/scripts/update_copyright_year.sh index 0f9ba80fc5af9f9d66ac23895135c9515d85f769..a825486a94179e1ddc10e8f4ecf53d0b893f1e2f 100644 --- a/make/scripts/update_copyright_year.sh +++ b/make/scripts/update_copyright_year.sh @@ -1,7 +1,7 @@ #!/bin/bash -f # -# Copyright (c) 2010, 2020, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2010, 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 @@ -23,27 +23,87 @@ # questions. # -# Script to update the Copyright YEAR range in Mercurial sources. +# Script to update the Copyright YEAR range in Mercurial & Git sources. # (Originally from xdono, Thanks!) -awk=awk +#------------------------------------------------------------ +copyright="Copyright (c)" +company="Oracle" +#------------------------------------------------------------ + +awk="awk" # Stop on any error set -e +# To allow total changes counting +shopt -s lastpipe + +# Get an absolute path to this script, since that determines the top-level directory. +this_script_dir=`dirname $0` +this_script_dir=`cd $this_script_dir > /dev/null && pwd` + # Temp area tmp=/tmp/`basename $0`.${USER}.$$ rm -f -r ${tmp} mkdir -p ${tmp} total=0 +# Default or supplied company name +if [ "$3" != "" ] ; then + company="$3" +fi + # This year or supplied year -if [ "$1" != "" ] ; then - year="$1" +if [ "$2" != "" ] ; then + year="$2" else year=`date +%Y` fi +# VCS select +vcs="$1" + +if [ -z "$vcs" ] ; then + git_found=false + hg_found=false + + [ -d "${this_script_dir}/../../.git" ] && git_found=true + [ -d "${this_script_dir}/../../.hg" ] && hg_found=true + + if [ "$git_found" == "true" ] && [ "$hg_found" == "false" ] ; then + vcs="git" + elif [ "$hg_found" == "true" ] && [ "$git_found" == "false" ] ; then + vcs="hg" + else + echo "Error: could not auto-detect version control system" + vcs="" + fi +fi + +case "$vcs" in + "git") + echo "Using Git version control system" + vcs_status=(git ls-files -m) + vcs_list_changesets=(git log --no-merges --since="${year}-01-01T00:00:00Z" --until="${year}-12-31T23:59:59Z" --pretty=tformat:"%H") + vcs_changeset_message=(git log -1 --pretty=tformat:"%B") # followed by ${changeset} + vcs_changeset_files=(git diff-tree --no-commit-id --name-only -r) # followed by ${changeset} + ;; + + "hg") + echo "Using Mercurial version control system" + vcs_status=(hg status) + vcs_list_changesets=(hg log --no-merges -v -d "${year}-01-01 to ${year}-12-31" --template '{node}\n') + vcs_changeset_message=(hg log -l1 --template '{desc}\n' --rev) # followed by ${changeset} + vcs_changeset_files=(hg log -l1 -v --template '{files}\n' --rev) # followed by ${changeset} + ;; + + *) + echo "Usage: `basename "$0"` [year [company]]" + exit 1 + ;; +esac + # Return true if it makes sense to edit this file saneFileToCheck() { @@ -68,8 +128,6 @@ updateFile() # file { changed="false" if [ `saneFileToCheck "$1"` = "true" ] ; then - copyright="Copyright (c)" - company="Oracle" rm -f $1.OLD mv $1 $1.OLD cat $1.OLD | \ @@ -94,12 +152,10 @@ updateChangesetFiles() # changeset count=0 files=${tmp}/files.$1 rm -f ${files} - hg log -l1 --rev $1 -v --template '{files}\n' | expand \ + "${vcs_changeset_files[@]}" "$1" | expand \ | ${awk} -F' ' '{for(i=1;i<=NF;i++)print $i}' \ > ${files} if [ -f "${files}" -a -s "${files}" ] ; then - copyright="Copyright (c)" - company="Oracle" fcount=`cat ${files}| wc -l` for i in `cat ${files}` ; do if [ `updateFile "${i}"` = "true" ] ; then @@ -116,8 +172,8 @@ updateChangesetFiles() # changeset printf " ERROR: No files changed in the changeset? Must be a mistake.\n" set -x ls -al ${files} - hg log -l1 --rev $1 -v --template '{files}\n' - hg log -l1 --rev $1 -v --template '{files}\n' | expand \ + "${vcs_changeset_files[@]}" "$1" + "${vcs_changeset_files[@]}" "$1" | expand \ | ${awk} -F' ' '{for(i=1;i<=NF;i++)print $i}' set +x exit 1 @@ -126,16 +182,16 @@ updateChangesetFiles() # changeset } # Check if repository is clean -previous=`hg status|wc -l` +previous=`"${vcs_status[@]}"|wc -l` if [ ${previous} -ne 0 ] ; then echo "WARNING: This repository contains previously edited working set files." - echo " hg status | wc -l = `hg status | wc -l`" + echo " ${vcs_status[*]} | wc -l = `"${vcs_status[@]}" | wc -l`" fi # Get all changesets this year all_changesets=${tmp}/all_changesets rm -f ${all_changesets} -hg log --no-merges -v -d "${year}-01-01 to ${year}-12-31" --template '{node}\n' > ${all_changesets} +"${vcs_list_changesets[@]}" > ${all_changesets} # Check changeset to see if it is Copyright only changes, filter changesets if [ -s ${all_changesets} ] ; then @@ -146,7 +202,7 @@ if [ -s ${all_changesets} ] ; then desc=${tmp}/desc.${changeset} rm -f ${desc} echo "------------------------------------------------" - hg log -l1 --rev ${changeset} --template '{desc}\n' > ${desc} + "${vcs_changeset_message[@]}" "${changeset}" > ${desc} printf "%d: %s\n%s\n" ${index} "${changeset}" "`cat ${desc}|head -1`" if [ "${year}" = "2010" ] ; then if cat ${desc} | fgrep -i "Added tag" > /dev/null ; then @@ -175,18 +231,18 @@ if [ ${total} -gt 0 ] ; then echo "---------------------------------------------" echo "Updated the copyright year on a total of ${total} files." if [ ${previous} -eq 0 ] ; then - echo "This count should match the count of modified files in the repository: hg status -m" + echo "This count should match the count of modified files in the repository: ${vcs_status[*]}" else echo "WARNING: This repository contained previously edited working set files." fi - echo " hg status -m | wc -l = `hg status -m | wc -l`" + echo " ${vcs_status[*]} | wc -l = `"${vcs_status[@]}" | wc -l`" else echo "---------------------------------------------" echo "No files were changed" if [ ${previous} -ne 0 ] ; then echo "WARNING: This repository contained previously edited working set files." fi - echo " hg status -m | wc -l = `hg status -m | wc -l`" + echo " ${vcs_status[*]} | wc -l = `"${vcs_status[@]}" | wc -l`" fi # Cleanup diff --git a/make/src/classes/build/tools/jfr/GenerateJfrFiles.java b/make/src/classes/build/tools/jfr/GenerateJfrFiles.java index dbaa8db7f653df27eef191994f3e81d3e73972ac..a3b17cf8c3f5a8b76ccec07a5feda31624cea0b7 100644 --- a/make/src/classes/build/tools/jfr/GenerateJfrFiles.java +++ b/make/src/classes/build/tools/jfr/GenerateJfrFiles.java @@ -174,6 +174,7 @@ public class GenerateJfrFiles { boolean cutoff; boolean throttle; boolean experimental; + boolean internal; long id; boolean isEvent; boolean isRelation; @@ -197,6 +198,7 @@ public class GenerateJfrFiles { pos.writeBoolean(cutoff); pos.writeBoolean(throttle); pos.writeBoolean(experimental); + pos.writeBoolean(internal); pos.writeLong(id); pos.writeBoolean(isEvent); pos.writeBoolean(isRelation); @@ -487,6 +489,7 @@ public class GenerateJfrFiles { currentType.description = getString(attributes, "description"); currentType.category = getString(attributes, "category"); currentType.experimental = getBoolean(attributes, "experimental", false); + currentType.internal = getBoolean(attributes, "internal", false); currentType.thread = getBoolean(attributes, "thread", false); currentType.stackTrace = getBoolean(attributes, "stackTrace", false); currentType.startTime = getBoolean(attributes, "startTime", true); @@ -863,6 +866,9 @@ public class GenerateJfrFiles { private static void printWriteData(Printer out, TypeElement type) { out.write(" template "); out.write(" void writeData(Writer& w) {"); + if (type.isEvent && type.internal) { + out.write(" JfrEventSetting::unhide_internal_types();"); + } if (("_thread_in_native").equals(type.commitState)) { out.write(" // explicit epoch synchronization check"); out.write(" JfrEpochSynchronization sync;"); diff --git a/make/test/JtregNativeJdk.gmk b/make/test/JtregNativeJdk.gmk index 270ff93d1475da508de1968f3db4779d23f930b7..89cc94f90bf02e9b4eb8bd8fc1700253fd2115fb 100644 --- a/make/test/JtregNativeJdk.gmk +++ b/make/test/JtregNativeJdk.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. +# 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 @@ -53,8 +53,6 @@ BUILD_JDK_JTREG_EXECUTABLES_CFLAGS_exeJliLaunchTest := \ -I$(TOPDIR)/src/java.base/$(OPENJDK_TARGET_OS_TYPE)/native/libjli \ -I$(TOPDIR)/src/java.base/$(OPENJDK_TARGET_OS)/native/libjli -BUILD_JDK_JTREG_LIBRARIES_LDFLAGS_libAsyncStackWalk := $(LIBCXX) - # Platform specific setup ifeq ($(call isTargetOs, windows), true) BUILD_JDK_JTREG_EXCLUDE += libDirectIO.c libInheritedChannel.c exelauncher.c @@ -64,11 +62,20 @@ ifeq ($(call isTargetOs, windows), true) WIN_LIB_JLI := $(SUPPORT_OUTPUTDIR)/native/java.base/libjli/jli.lib BUILD_JDK_JTREG_EXECUTABLES_LIBS_exeJliLaunchTest := $(WIN_LIB_JLI) BUILD_JDK_JTREG_EXECUTABLES_LIBS_exeCallerAccessTest := jvm.lib + BUILD_JDK_JTREG_EXECUTABLES_LIBS_exeNullCallerClassLoaderTest := jvm.lib + BUILD_JDK_JTREG_EXECUTABLES_LIBS_exeNullCallerLookupTest := jvm.lib + BUILD_JDK_JTREG_EXECUTABLES_LIBS_exeNullCallerResourceBundle := jvm.lib BUILD_JDK_JTREG_EXECUTABLES_LIBS_exerevokeall := advapi32.lib BUILD_JDK_JTREG_LIBRARIES_CFLAGS_libAsyncStackWalk := /EHsc + BUILD_JDK_JTREG_LIBRARIES_CFLAGS_libAsyncInvokers := /EHsc + BUILD_JDK_JTREG_LIBRARIES_LDFLAGS_libAsyncStackWalk := $(LIBCXX) + BUILD_JDK_JTREG_LIBRARIES_LDFLAGS_libAsyncInvokers := $(LIBCXX) else BUILD_JDK_JTREG_LIBRARIES_LIBS_libstringPlatformChars := -ljava BUILD_JDK_JTREG_LIBRARIES_LIBS_libDirectIO := -ljava + BUILD_JDK_JTREG_LIBRARIES_LDFLAGS_libNativeThread := -pthread + BUILD_JDK_JTREG_LIBRARIES_LDFLAGS_libAsyncStackWalk := $(LIBCXX) -pthread + BUILD_JDK_JTREG_LIBRARIES_LDFLAGS_libAsyncInvokers := $(LIBCXX) -pthread BUILD_JDK_JTREG_EXCLUDE += exerevokeall.c ifeq ($(call isTargetOs, linux), true) BUILD_JDK_JTREG_LIBRARIES_LIBS_libInheritedChannel := -ljava @@ -76,6 +83,9 @@ else endif BUILD_JDK_JTREG_EXECUTABLES_LIBS_exeJliLaunchTest := -ljli BUILD_JDK_JTREG_EXECUTABLES_LIBS_exeCallerAccessTest := -ljvm + BUILD_JDK_JTREG_EXECUTABLES_LIBS_exeNullCallerClassLoaderTest := -ljvm + BUILD_JDK_JTREG_EXECUTABLES_LIBS_exeNullCallerLookupTest := -ljvm + BUILD_JDK_JTREG_EXECUTABLES_LIBS_exeNullCallerResourceBundle := -ljvm endif ifeq ($(call isTargetOs, macosx), true) diff --git a/src/demo/share/jfc/SwingSet2/TableDemo.java b/src/demo/share/jfc/SwingSet2/TableDemo.java index 350fb6efd675e2221eec0fa97a6cbab5cc89b9e4..f136de28df962bf535a4b538fb5f08c77e8b455f 100644 --- a/src/demo/share/jfc/SwingSet2/TableDemo.java +++ b/src/demo/share/jfc/SwingSet2/TableDemo.java @@ -768,4 +768,13 @@ public class TableDemo extends DemoModule { footerTextField.setDragEnabled(dragEnabled); } + @Override + public ImageIcon createImageIcon(String filename, String description) { + ImageIcon imageIcon = super.createImageIcon(filename, description); + AccessibleContext context = imageIcon.getAccessibleContext(); + if (context!= null) { + context.setAccessibleName(description); + } + return imageIcon; + } } diff --git a/src/hotspot/cpu/aarch64/aarch64.ad b/src/hotspot/cpu/aarch64/aarch64.ad index 612ed63751b696ca9416cf6cc2ba1aa63c8a7c75..68fd336aa33b6f6ce3c685279ae5cd8e110bc777 100644 --- a/src/hotspot/cpu/aarch64/aarch64.ad +++ b/src/hotspot/cpu/aarch64/aarch64.ad @@ -1,5 +1,5 @@ // -// Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. +// Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved. // Copyright (c) 2014, 2021, Red Hat, Inc. All rights reserved. // DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. // @@ -1311,6 +1311,9 @@ public: // predicate controlling translation of CompareAndSwapX bool needs_acquiring_load_exclusive(const Node *load); + // Assert that the given node is not a variable shift. + bool assert_not_var_shift(const Node* n); + // predicate controlling addressing modes bool size_fits_all_mem_uses(AddPNode* addp, int shift); %} @@ -1725,6 +1728,12 @@ bool needs_acquiring_load_exclusive(const Node *n) return true; } +// Assert that the given node is not a variable shift. +bool assert_not_var_shift(const Node* n) { + assert(!n->as_ShiftV()->is_var_shift(), "illegal variable shift"); + return true; +} + #define __ _masm. // advance declarations for helper functions to convert register @@ -1853,6 +1862,10 @@ void MachPrologNode::format(PhaseRegAlloc *ra_, outputStream *st) const { if (C->output()->need_stack_bang(framesize)) st->print("# stack bang size=%d\n\t", framesize); + if (VM_Version::use_rop_protection()) { + st->print("ldr zr, [lr]\n\t"); + st->print("pacia lr, rfp\n\t"); + } if (framesize < ((1 << 9) + 2 * wordSize)) { st->print("sub sp, sp, #%d\n\t", framesize); st->print("stp rfp, lr, [sp, #%d]", framesize - 2 * wordSize); @@ -1961,6 +1974,10 @@ void MachEpilogNode::format(PhaseRegAlloc *ra_, outputStream *st) const { st->print("add sp, sp, rscratch1\n\t"); st->print("ldp lr, rfp, [sp],#%d\n\t", (2 * wordSize)); } + if (VM_Version::use_rop_protection()) { + st->print("autia lr, rfp\n\t"); + st->print("ldr zr, [lr]\n\t"); + } if (do_polling() && C->is_method_compilation()) { st->print("# test polling word\n\t"); @@ -2478,7 +2495,7 @@ const RegMask* Matcher::predicate_reg_mask(void) { return &_PR_REG_mask; } -const TypeVect* Matcher::predicate_reg_type(const Type* elemTy, int length) { +const TypeVectMask* Matcher::predicate_reg_type(const Type* elemTy, int length) { return new TypeVectMask(elemTy, length); } @@ -2685,12 +2702,52 @@ bool size_fits_all_mem_uses(AddPNode* addp, int shift) { return true; } +bool can_combine_with_imm(Node* binary_node, Node* replicate_node) { + if (UseSVE == 0 || !VectorNode::is_invariant_vector(replicate_node)){ + return false; + } + Node* imm_node = replicate_node->in(1); + if (!imm_node->is_Con()) { + return false; + } + + const Type* t = imm_node->bottom_type(); + if (!(t->isa_int() || t->isa_long())) { + return false; + } + + switch (binary_node->Opcode()) { + case Op_AndV: + case Op_OrV: + case Op_XorV: { + Assembler::SIMD_RegVariant T = Assembler::elemType_to_regVariant(Matcher::vector_element_basic_type(binary_node)); + uint64_t value = t->isa_long() ? (uint64_t)imm_node->get_long() : (uint64_t)imm_node->get_int(); + return Assembler::operand_valid_for_sve_logical_immediate(Assembler::regVariant_to_elemBits(T), value); + } + case Op_AddVB: + return (imm_node->get_int() <= 255 && imm_node->get_int() >= -255); + case Op_AddVS: + case Op_AddVI: + return Assembler::operand_valid_for_sve_add_sub_immediate((int64_t)imm_node->get_int()); + case Op_AddVL: + return Assembler::operand_valid_for_sve_add_sub_immediate(imm_node->get_long()); + default: + return false; + } +} + +bool is_vector_arith_imm_pattern(Node* n, Node* m) { + if (n != NULL && m != NULL) { + return can_combine_with_imm(n, m); + } + return false; +} + // Should the matcher clone input 'm' of node 'n'? bool Matcher::pd_clone_node(Node* n, Node* m, Matcher::MStack& mstack) { // ShiftV src (ShiftCntV con) - // StoreVector (VectorStoreMask src) - if (is_vshift_con_pattern(n, m) || - (UseSVE > 0 && m->Opcode() == Op_VectorStoreMask && n->Opcode() == Op_StoreVector)) { + // Binary src (Replicate con) + if (is_vshift_con_pattern(n, m) || is_vector_arith_imm_pattern(n, m)) { mstack.push(m, Visit); return true; } @@ -3161,16 +3218,30 @@ encode %{ rscratch1, stlrb); %} + enc_class aarch64_enc_stlrb0(memory mem) %{ + MOV_VOLATILE(zr, $mem$$base, $mem$$index, $mem$$scale, $mem$$disp, + rscratch1, stlrb); + %} + enc_class aarch64_enc_stlrh(iRegI src, memory mem) %{ MOV_VOLATILE(as_Register($src$$reg), $mem$$base, $mem$$index, $mem$$scale, $mem$$disp, rscratch1, stlrh); %} + enc_class aarch64_enc_stlrh0(memory mem) %{ + MOV_VOLATILE(zr, $mem$$base, $mem$$index, $mem$$scale, $mem$$disp, + rscratch1, stlrh); + %} + enc_class aarch64_enc_stlrw(iRegI src, memory mem) %{ MOV_VOLATILE(as_Register($src$$reg), $mem$$base, $mem$$index, $mem$$scale, $mem$$disp, rscratch1, stlrw); %} + enc_class aarch64_enc_stlrw0(memory mem) %{ + MOV_VOLATILE(zr, $mem$$base, $mem$$index, $mem$$scale, $mem$$disp, + rscratch1, stlrw); + %} enc_class aarch64_enc_ldarsbw(iRegI dst, memory mem) %{ Register dst_reg = as_Register($dst$$reg); @@ -3261,6 +3332,11 @@ encode %{ rscratch1, stlr); %} + enc_class aarch64_enc_stlr0(memory mem) %{ + MOV_VOLATILE(zr, $mem$$base, $mem$$index, $mem$$scale, $mem$$disp, + rscratch1, stlr); + %} + enc_class aarch64_enc_fstlrs(vRegF src, memory mem) %{ { C2_MacroAssembler _masm(&cbuf); @@ -3860,37 +3936,40 @@ encode %{ // Check for existing monitor __ tbnz(disp_hdr, exact_log2(markWord::monitor_value), object_has_monitor); - // Set tmp to be (markWord of object | UNLOCK_VALUE). - __ orr(tmp, disp_hdr, markWord::unlocked_value); - - // Initialize the box. (Must happen before we update the object mark!) - __ str(tmp, Address(box, BasicLock::displaced_header_offset_in_bytes())); - - // Compare object markWord with an unlocked value (tmp) and if - // equal exchange the stack address of our box with object markWord. - // On failure disp_hdr contains the possibly locked markWord. - __ cmpxchg(oop, tmp, box, Assembler::xword, /*acquire*/ true, - /*release*/ true, /*weak*/ false, disp_hdr); - __ br(Assembler::EQ, cont); - - assert(oopDesc::mark_offset_in_bytes() == 0, "offset of _mark is not 0"); - - // If the compare-and-exchange succeeded, then we found an unlocked - // object, will have now locked it will continue at label cont - - __ bind(cas_failed); - // We did not see an unlocked object so try the fast recursive case. - - // Check if the owner is self by comparing the value in the - // markWord of object (disp_hdr) with the stack pointer. - __ mov(rscratch1, sp); - __ sub(disp_hdr, disp_hdr, rscratch1); - __ mov(tmp, (address) (~(os::vm_page_size()-1) | markWord::lock_mask_in_place)); - // If condition is true we are cont and hence we can store 0 as the - // displaced header in the box, which indicates that it is a recursive lock. - __ ands(tmp/*==0?*/, disp_hdr, tmp); // Sets flags for result - __ str(tmp/*==0, perhaps*/, Address(box, BasicLock::displaced_header_offset_in_bytes())); - + if (!UseHeavyMonitors) { + // Set tmp to be (markWord of object | UNLOCK_VALUE). + __ orr(tmp, disp_hdr, markWord::unlocked_value); + + // Initialize the box. (Must happen before we update the object mark!) + __ str(tmp, Address(box, BasicLock::displaced_header_offset_in_bytes())); + + // Compare object markWord with an unlocked value (tmp) and if + // equal exchange the stack address of our box with object markWord. + // On failure disp_hdr contains the possibly locked markWord. + __ cmpxchg(oop, tmp, box, Assembler::xword, /*acquire*/ true, + /*release*/ true, /*weak*/ false, disp_hdr); + __ br(Assembler::EQ, cont); + + assert(oopDesc::mark_offset_in_bytes() == 0, "offset of _mark is not 0"); + + // If the compare-and-exchange succeeded, then we found an unlocked + // object, will have now locked it will continue at label cont + + __ bind(cas_failed); + // We did not see an unlocked object so try the fast recursive case. + + // Check if the owner is self by comparing the value in the + // markWord of object (disp_hdr) with the stack pointer. + __ mov(rscratch1, sp); + __ sub(disp_hdr, disp_hdr, rscratch1); + __ mov(tmp, (address) (~(os::vm_page_size()-1) | markWord::lock_mask_in_place)); + // If condition is true we are cont and hence we can store 0 as the + // displaced header in the box, which indicates that it is a recursive lock. + __ ands(tmp/*==0?*/, disp_hdr, tmp); // Sets flags for result + __ str(tmp/*==0, perhaps*/, Address(box, BasicLock::displaced_header_offset_in_bytes())); + } else { + __ tst(oop, oop); // Set NE to indicate 'failure' -> take slow-path. We know that oop != 0. + } __ b(cont); // Handle existing monitor. @@ -3902,7 +3981,7 @@ encode %{ // Try to CAS m->owner from NULL to current thread. __ add(tmp, disp_hdr, (ObjectMonitor::owner_offset_in_bytes()-markWord::monitor_value)); __ cmpxchg(tmp, zr, rthread, Assembler::xword, /*acquire*/ true, - /*release*/ true, /*weak*/ false, noreg); // Sets flags for result + /*release*/ true, /*weak*/ false, rscratch1); // Sets flags for result // Store a non-null value into the box to avoid looking like a re-entrant // lock. The fast-path monitor unlock code checks for @@ -3911,6 +3990,15 @@ encode %{ __ mov(tmp, (address)markWord::unused_mark().value()); __ str(tmp, Address(box, BasicLock::displaced_header_offset_in_bytes())); + __ br(Assembler::EQ, cont); // CAS success means locking succeeded + + __ cmp(rscratch1, rthread); + __ br(Assembler::NE, cont); // Check for recursive locking + + // Recursive lock case + __ increment(Address(disp_hdr, ObjectMonitor::recursions_offset_in_bytes() - markWord::monitor_value), 1); + // flag == EQ still from the cmp above, checking if this is a reentrant lock + __ bind(cont); // flag == EQ indicates success // flag == NE indicates failure @@ -3927,23 +4015,29 @@ encode %{ assert_different_registers(oop, box, tmp, disp_hdr); - // Find the lock address and load the displaced header from the stack. - __ ldr(disp_hdr, Address(box, BasicLock::displaced_header_offset_in_bytes())); + if (!UseHeavyMonitors) { + // Find the lock address and load the displaced header from the stack. + __ ldr(disp_hdr, Address(box, BasicLock::displaced_header_offset_in_bytes())); - // If the displaced header is 0, we have a recursive unlock. - __ cmp(disp_hdr, zr); - __ br(Assembler::EQ, cont); + // If the displaced header is 0, we have a recursive unlock. + __ cmp(disp_hdr, zr); + __ br(Assembler::EQ, cont); + } // Handle existing monitor. __ ldr(tmp, Address(oop, oopDesc::mark_offset_in_bytes())); __ tbnz(disp_hdr, exact_log2(markWord::monitor_value), object_has_monitor); - // Check if it is still a light weight lock, this is is true if we - // see the stack address of the basicLock in the markWord of the - // object. + if (!UseHeavyMonitors) { + // Check if it is still a light weight lock, this is is true if we + // see the stack address of the basicLock in the markWord of the + // object. - __ cmpxchg(oop, box, disp_hdr, Assembler::xword, /*acquire*/ false, - /*release*/ true, /*weak*/ false, tmp); + __ cmpxchg(oop, box, disp_hdr, Assembler::xword, /*acquire*/ false, + /*release*/ true, /*weak*/ false, tmp); + } else { + __ tst(oop, oop); // Set NE to indicate 'failure' -> take slow-path. We know that oop != 0. + } __ b(cont); assert(oopDesc::mark_offset_in_bytes() == 0, "offset of _mark is not 0"); @@ -3952,13 +4046,18 @@ encode %{ __ bind(object_has_monitor); STATIC_ASSERT(markWord::monitor_value <= INT_MAX); __ add(tmp, tmp, -(int)markWord::monitor_value); // monitor - __ ldr(rscratch1, Address(tmp, ObjectMonitor::owner_offset_in_bytes())); __ ldr(disp_hdr, Address(tmp, ObjectMonitor::recursions_offset_in_bytes())); - __ eor(rscratch1, rscratch1, rthread); // Will be 0 if we are the owner. - __ orr(rscratch1, rscratch1, disp_hdr); // Will be 0 if there are 0 recursions - __ cmp(rscratch1, zr); // Sets flags for result - __ br(Assembler::NE, cont); + Label notRecursive; + __ cbz(disp_hdr, notRecursive); + + // Recursive lock + __ sub(disp_hdr, disp_hdr, 1u); + __ str(disp_hdr, Address(tmp, ObjectMonitor::recursions_offset_in_bytes())); + __ cmp(disp_hdr, disp_hdr); // Sets flags for result + __ b(cont); + + __ bind(notRecursive); __ ldr(rscratch1, Address(tmp, ObjectMonitor::EntryList_offset_in_bytes())); __ ldr(disp_hdr, Address(tmp, ObjectMonitor::cxq_offset_in_bytes())); __ orr(rscratch1, rscratch1, disp_hdr); // Will be 0 if both are 0. @@ -4611,6 +4710,17 @@ operand immL8_shift8() interface(CONST_INTER); %} +// 8 bit integer valid for vector add sub immediate +operand immBAddSubV() +%{ + predicate(n->get_int() <= 255 && n->get_int() >= -255); + match(ConI); + + op_cost(0); + format %{ %} + interface(CONST_INTER); +%} + // 32 bit integer valid for add sub immediate operand immIAddSub() %{ @@ -4621,8 +4731,39 @@ operand immIAddSub() interface(CONST_INTER); %} +// 32 bit integer valid for vector add sub immediate +operand immIAddSubV() +%{ + predicate(Assembler::operand_valid_for_sve_add_sub_immediate((int64_t)n->get_int())); + match(ConI); + + op_cost(0); + format %{ %} + interface(CONST_INTER); +%} + // 32 bit unsigned integer valid for logical immediate -// TODO -- check this is right when e.g the mask is 0x80000000 + +operand immBLog() +%{ + predicate(Assembler::operand_valid_for_sve_logical_immediate(BitsPerByte, (uint64_t)n->get_int())); + match(ConI); + + op_cost(0); + format %{ %} + interface(CONST_INTER); +%} + +operand immSLog() +%{ + predicate(Assembler::operand_valid_for_sve_logical_immediate(BitsPerShort, (uint64_t)n->get_int())); + match(ConI); + + op_cost(0); + format %{ %} + interface(CONST_INTER); +%} + operand immILog() %{ predicate(Assembler::operand_valid_for_logical_immediate(/*is32*/true, (uint64_t)n->get_int())); @@ -4700,6 +4841,17 @@ operand immLAddSub() interface(CONST_INTER); %} +// 64 bit integer valid for addv subv immediate +operand immLAddSubV() +%{ + predicate(Assembler::operand_valid_for_sve_add_sub_immediate(n->get_long())); + match(ConL); + + op_cost(0); + format %{ %} + interface(CONST_INTER); +%} + // 64 bit integer valid for logical immediate operand immLLog() %{ @@ -8159,6 +8311,18 @@ instruct storeB_volatile(iRegIorL2I src, /* sync_memory*/indirect mem) ins_pipe(pipe_class_memory); %} +instruct storeimmB0_volatile(immI0 zero, /* sync_memory*/indirect mem) +%{ + match(Set mem (StoreB mem zero)); + + ins_cost(VOLATILE_REF_COST); + format %{ "stlrb zr, $mem\t# byte" %} + + ins_encode(aarch64_enc_stlrb0(mem)); + + ins_pipe(pipe_class_memory); +%} + // Store Char/Short instruct storeC_volatile(iRegIorL2I src, /* sync_memory*/indirect mem) %{ @@ -8172,6 +8336,18 @@ instruct storeC_volatile(iRegIorL2I src, /* sync_memory*/indirect mem) ins_pipe(pipe_class_memory); %} +instruct storeimmC0_volatile(immI0 zero, /* sync_memory*/indirect mem) +%{ + match(Set mem (StoreC mem zero)); + + ins_cost(VOLATILE_REF_COST); + format %{ "stlrh zr, $mem\t# short" %} + + ins_encode(aarch64_enc_stlrh0(mem)); + + ins_pipe(pipe_class_memory); +%} + // Store Integer instruct storeI_volatile(iRegIorL2I src, /* sync_memory*/indirect mem) @@ -8186,6 +8362,18 @@ instruct storeI_volatile(iRegIorL2I src, /* sync_memory*/indirect mem) ins_pipe(pipe_class_memory); %} +instruct storeimmI0_volatile(immI0 zero, /* sync_memory*/indirect mem) +%{ + match(Set mem(StoreI mem zero)); + + ins_cost(VOLATILE_REF_COST); + format %{ "stlrw zr, $mem\t# int" %} + + ins_encode(aarch64_enc_stlrw0(mem)); + + ins_pipe(pipe_class_memory); +%} + // Store Long (64 bit signed) instruct storeL_volatile(iRegL src, /* sync_memory*/indirect mem) %{ @@ -8199,6 +8387,18 @@ instruct storeL_volatile(iRegL src, /* sync_memory*/indirect mem) ins_pipe(pipe_class_memory); %} +instruct storeimmL0_volatile(immL0 zero, /* sync_memory*/indirect mem) +%{ + match(Set mem (StoreL mem zero)); + + ins_cost(VOLATILE_REF_COST); + format %{ "stlr zr, $mem\t# int" %} + + ins_encode(aarch64_enc_stlr0(mem)); + + ins_pipe(pipe_class_memory); +%} + // Store Pointer instruct storeP_volatile(iRegP src, /* sync_memory*/indirect mem) %{ @@ -8212,6 +8412,18 @@ instruct storeP_volatile(iRegP src, /* sync_memory*/indirect mem) ins_pipe(pipe_class_memory); %} +instruct storeimmP0_volatile(immP0 zero, /* sync_memory*/indirect mem) +%{ + match(Set mem (StoreP mem zero)); + + ins_cost(VOLATILE_REF_COST); + format %{ "stlr zr, $mem\t# ptr" %} + + ins_encode(aarch64_enc_stlr0(mem)); + + ins_pipe(pipe_class_memory); +%} + // Store Compressed Pointer instruct storeN_volatile(iRegN src, /* sync_memory*/indirect mem) %{ @@ -8225,6 +8437,18 @@ instruct storeN_volatile(iRegN src, /* sync_memory*/indirect mem) ins_pipe(pipe_class_memory); %} +instruct storeimmN0_volatile(immN0 zero, /* sync_memory*/indirect mem) +%{ + match(Set mem (StoreN mem zero)); + + ins_cost(VOLATILE_REF_COST); + format %{ "stlrw zr, $mem\t# compressed ptr" %} + + ins_encode(aarch64_enc_stlrw0(mem)); + + ins_pipe(pipe_class_memory); +%} + // Store Float instruct storeF_volatile(vRegF src, /* sync_memory*/indirect mem) %{ @@ -8425,10 +8649,10 @@ instruct popCountI(iRegINoSp dst, iRegIorL2I src, vRegF tmp) %{ "mov $dst, $tmp\t# vector (1D)" %} ins_encode %{ __ movw($src$$Register, $src$$Register); // ensure top 32 bits 0 - __ mov($tmp$$FloatRegister, __ T1D, 0, $src$$Register); + __ mov($tmp$$FloatRegister, __ D, 0, $src$$Register); __ cnt($tmp$$FloatRegister, __ T8B, $tmp$$FloatRegister); __ addv($tmp$$FloatRegister, __ T8B, $tmp$$FloatRegister); - __ mov($dst$$Register, $tmp$$FloatRegister, __ T1D, 0); + __ mov($dst$$Register, $tmp$$FloatRegister, __ D, 0); %} ins_pipe(pipe_class_default); @@ -8450,7 +8674,7 @@ instruct popCountI_mem(iRegINoSp dst, memory4 mem, vRegF tmp) %{ as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 4); __ cnt($tmp$$FloatRegister, __ T8B, $tmp$$FloatRegister); __ addv($tmp$$FloatRegister, __ T8B, $tmp$$FloatRegister); - __ mov($dst$$Register, $tmp$$FloatRegister, __ T1D, 0); + __ mov($dst$$Register, $tmp$$FloatRegister, __ D, 0); %} ins_pipe(pipe_class_default); @@ -8468,10 +8692,10 @@ instruct popCountL(iRegINoSp dst, iRegL src, vRegD tmp) %{ "addv $tmp, $tmp\t# vector (8B)\n\t" "mov $dst, $tmp\t# vector (1D)" %} ins_encode %{ - __ mov($tmp$$FloatRegister, __ T1D, 0, $src$$Register); + __ mov($tmp$$FloatRegister, __ D, 0, $src$$Register); __ cnt($tmp$$FloatRegister, __ T8B, $tmp$$FloatRegister); __ addv($tmp$$FloatRegister, __ T8B, $tmp$$FloatRegister); - __ mov($dst$$Register, $tmp$$FloatRegister, __ T1D, 0); + __ mov($dst$$Register, $tmp$$FloatRegister, __ D, 0); %} ins_pipe(pipe_class_default); @@ -8493,7 +8717,7 @@ instruct popCountL_mem(iRegINoSp dst, memory8 mem, vRegD tmp) %{ as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 8); __ cnt($tmp$$FloatRegister, __ T8B, $tmp$$FloatRegister); __ addv($tmp$$FloatRegister, __ T8B, $tmp$$FloatRegister); - __ mov($dst$$Register, $tmp$$FloatRegister, __ T1D, 0); + __ mov($dst$$Register, $tmp$$FloatRegister, __ D, 0); %} ins_pipe(pipe_class_default); @@ -16856,13 +17080,13 @@ instruct array_equalsC(iRegP_R1 ary1, iRegP_R2 ary2, iRegI_R0 result, ins_pipe(pipe_class_memory); %} -instruct has_negatives(iRegP_R1 ary1, iRegI_R2 len, iRegI_R0 result, rFlagsReg cr) +instruct count_positives(iRegP_R1 ary1, iRegI_R2 len, iRegI_R0 result, rFlagsReg cr) %{ - match(Set result (HasNegatives ary1 len)); + match(Set result (CountPositives ary1 len)); effect(USE_KILL ary1, USE_KILL len, KILL cr); - format %{ "has negatives byte[] $ary1,$len -> $result" %} + format %{ "count positives byte[] $ary1,$len -> $result" %} ins_encode %{ - address tpc = __ has_negatives($ary1$$Register, $len$$Register, $result$$Register); + address tpc = __ count_positives($ary1$$Register, $len$$Register, $result$$Register); if (tpc == NULL) { ciEnv::current()->record_failure("CodeCache is full"); return; @@ -16878,16 +17102,17 @@ instruct string_compress(iRegP_R2 src, iRegP_R1 dst, iRegI_R3 len, iRegI_R0 result, rFlagsReg cr) %{ match(Set result (StrCompressedCopy src (Binary dst len))); - effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, USE_KILL src, USE_KILL dst, USE_KILL len, KILL cr); + effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, + USE_KILL src, USE_KILL dst, USE len, KILL cr); - format %{ "String Compress $src,$dst -> $result // KILL R1, R2, R3, R4" %} + format %{ "String Compress $src,$dst,$len -> $result // KILL $src,$dst" %} ins_encode %{ __ char_array_compress($src$$Register, $dst$$Register, $len$$Register, + $result$$Register, $tmp1$$FloatRegister, $tmp2$$FloatRegister, - $tmp3$$FloatRegister, $tmp4$$FloatRegister, - $result$$Register); + $tmp3$$FloatRegister, $tmp4$$FloatRegister); %} - ins_pipe( pipe_slow ); + ins_pipe(pipe_slow); %} // fast byte[] to char[] inflation @@ -16912,22 +17137,43 @@ instruct string_inflate(Universe dummy, iRegP_R0 src, iRegP_R1 dst, iRegI_R2 len // encode char[] to byte[] in ISO_8859_1 instruct encode_iso_array(iRegP_R2 src, iRegP_R1 dst, iRegI_R3 len, - vRegD_V0 Vtmp1, vRegD_V1 Vtmp2, - vRegD_V2 Vtmp3, vRegD_V3 Vtmp4, + vRegD_V0 vtmp0, vRegD_V1 vtmp1, + vRegD_V2 vtmp2, vRegD_V3 vtmp3, iRegI_R0 result, rFlagsReg cr) %{ predicate(!((EncodeISOArrayNode*)n)->is_ascii()); match(Set result (EncodeISOArray src (Binary dst len))); - effect(USE_KILL src, USE_KILL dst, USE_KILL len, - KILL Vtmp1, KILL Vtmp2, KILL Vtmp3, KILL Vtmp4, KILL cr); + effect(USE_KILL src, USE_KILL dst, USE len, + KILL vtmp0, KILL vtmp1, KILL vtmp2, KILL vtmp3, KILL cr); - format %{ "Encode array $src,$dst,$len -> $result" %} + format %{ "Encode ISO array $src,$dst,$len -> $result" %} ins_encode %{ __ encode_iso_array($src$$Register, $dst$$Register, $len$$Register, - $result$$Register, $Vtmp1$$FloatRegister, $Vtmp2$$FloatRegister, - $Vtmp3$$FloatRegister, $Vtmp4$$FloatRegister); + $result$$Register, false, + $vtmp0$$FloatRegister, $vtmp1$$FloatRegister, + $vtmp2$$FloatRegister, $vtmp3$$FloatRegister); %} - ins_pipe( pipe_class_memory ); + ins_pipe(pipe_class_memory); +%} + +instruct encode_ascii_array(iRegP_R2 src, iRegP_R1 dst, iRegI_R3 len, + vRegD_V0 vtmp0, vRegD_V1 vtmp1, + vRegD_V2 vtmp2, vRegD_V3 vtmp3, + iRegI_R0 result, rFlagsReg cr) +%{ + predicate(((EncodeISOArrayNode*)n)->is_ascii()); + match(Set result (EncodeISOArray src (Binary dst len))); + effect(USE_KILL src, USE_KILL dst, USE len, + KILL vtmp0, KILL vtmp1, KILL vtmp2, KILL vtmp3, KILL cr); + + format %{ "Encode ASCII array $src,$dst,$len -> $result" %} + ins_encode %{ + __ encode_iso_array($src$$Register, $dst$$Register, $len$$Register, + $result$$Register, true, + $vtmp0$$FloatRegister, $vtmp1$$FloatRegister, + $vtmp2$$FloatRegister, $vtmp3$$FloatRegister); + %} + ins_pipe(pipe_class_memory); %} // ============================================================================ diff --git a/src/hotspot/cpu/aarch64/aarch64_neon.ad b/src/hotspot/cpu/aarch64/aarch64_neon.ad index b3cb6f5f25516bfbcf6db920ce603b7df6baab69..feecd8ab90add28181a2c7b2bd615432703389b9 100644 --- a/src/hotspot/cpu/aarch64/aarch64_neon.ad +++ b/src/hotspot/cpu/aarch64/aarch64_neon.ad @@ -1,5 +1,5 @@ -// Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. -// Copyright (c) 2020, 2021, Arm Limited. All rights reserved. +// Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. +// Copyright (c) 2020, 2022, 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 @@ -511,7 +511,7 @@ instruct vcvt2Dto2I(vecD dst, vecX src) "fcvtzdw rscratch1, $src\n\t" "fcvtzdw rscratch2, $dst\n\t" "fmovs $dst, rscratch1\n\t" - "mov $dst, T2S, 1, rscratch2\t#convert 2D to 2I vector" + "mov $dst, S, 1, rscratch2\t#convert 2D to 2I vector" %} ins_encode %{ __ ins(as_FloatRegister($dst$$reg), __ D, as_FloatRegister($src$$reg), 0, 1); @@ -520,7 +520,7 @@ instruct vcvt2Dto2I(vecD dst, vecX src) __ fcvtzdw(rscratch1, as_FloatRegister($src$$reg)); __ fcvtzdw(rscratch2, as_FloatRegister($dst$$reg)); __ fmovs(as_FloatRegister($dst$$reg), rscratch1); - __ mov(as_FloatRegister($dst$$reg), __ T2S, 1, rscratch2); + __ mov(as_FloatRegister($dst$$reg), __ S, 1, rscratch2); %} ins_pipe(pipe_slow); %} @@ -1703,13 +1703,13 @@ instruct insert8B(vecD dst, vecD src, iRegIorL2I val, immI idx) match(Set dst (VectorInsert (Binary src val) idx)); ins_cost(INSN_COST); format %{ "orr $dst, T8B, $src, $src\n\t" - "mov $dst, T8B, $idx, $val\t# insert into vector(8B)" %} + "mov $dst, B, $idx, $val\t# insert into vector(8B)" %} ins_encode %{ if (as_FloatRegister($dst$$reg) != as_FloatRegister($src$$reg)) { __ orr(as_FloatRegister($dst$$reg), __ T8B, as_FloatRegister($src$$reg), as_FloatRegister($src$$reg)); } - __ mov(as_FloatRegister($dst$$reg), __ T8B, $idx$$constant, $val$$Register); + __ mov(as_FloatRegister($dst$$reg), __ B, $idx$$constant, $val$$Register); %} ins_pipe(pipe_slow); %} @@ -1720,13 +1720,13 @@ instruct insert16B(vecX dst, vecX src, iRegIorL2I val, immI idx) match(Set dst (VectorInsert (Binary src val) idx)); ins_cost(INSN_COST); format %{ "orr $dst, T16B, $src, $src\n\t" - "mov $dst, T16B, $idx, $val\t# insert into vector(16B)" %} + "mov $dst, B, $idx, $val\t# insert into vector(16B)" %} ins_encode %{ if (as_FloatRegister($dst$$reg) != as_FloatRegister($src$$reg)) { __ orr(as_FloatRegister($dst$$reg), __ T16B, as_FloatRegister($src$$reg), as_FloatRegister($src$$reg)); } - __ mov(as_FloatRegister($dst$$reg), __ T16B, $idx$$constant, $val$$Register); + __ mov(as_FloatRegister($dst$$reg), __ B, $idx$$constant, $val$$Register); %} ins_pipe(pipe_slow); %} @@ -1737,13 +1737,13 @@ instruct insert4S(vecD dst, vecD src, iRegIorL2I val, immI idx) match(Set dst (VectorInsert (Binary src val) idx)); ins_cost(INSN_COST); format %{ "orr $dst, T8B, $src, $src\n\t" - "mov $dst, T4H, $idx, $val\t# insert into vector(4S)" %} + "mov $dst, H, $idx, $val\t# insert into vector(4S)" %} ins_encode %{ if (as_FloatRegister($dst$$reg) != as_FloatRegister($src$$reg)) { __ orr(as_FloatRegister($dst$$reg), __ T8B, as_FloatRegister($src$$reg), as_FloatRegister($src$$reg)); } - __ mov(as_FloatRegister($dst$$reg), __ T4H, $idx$$constant, $val$$Register); + __ mov(as_FloatRegister($dst$$reg), __ H, $idx$$constant, $val$$Register); %} ins_pipe(pipe_slow); %} @@ -1754,13 +1754,13 @@ instruct insert8S(vecX dst, vecX src, iRegIorL2I val, immI idx) match(Set dst (VectorInsert (Binary src val) idx)); ins_cost(INSN_COST); format %{ "orr $dst, T16B, $src, $src\n\t" - "mov $dst, T8H, $idx, $val\t# insert into vector(8S)" %} + "mov $dst, H, $idx, $val\t# insert into vector(8S)" %} ins_encode %{ if (as_FloatRegister($dst$$reg) != as_FloatRegister($src$$reg)) { __ orr(as_FloatRegister($dst$$reg), __ T16B, as_FloatRegister($src$$reg), as_FloatRegister($src$$reg)); } - __ mov(as_FloatRegister($dst$$reg), __ T8H, $idx$$constant, $val$$Register); + __ mov(as_FloatRegister($dst$$reg), __ H, $idx$$constant, $val$$Register); %} ins_pipe(pipe_slow); %} @@ -1771,13 +1771,13 @@ instruct insert2I(vecD dst, vecD src, iRegIorL2I val, immI idx) match(Set dst (VectorInsert (Binary src val) idx)); ins_cost(INSN_COST); format %{ "orr $dst, T8B, $src, $src\n\t" - "mov $dst, T2S, $idx, $val\t# insert into vector(2I)" %} + "mov $dst, S, $idx, $val\t# insert into vector(2I)" %} ins_encode %{ if (as_FloatRegister($dst$$reg) != as_FloatRegister($src$$reg)) { __ orr(as_FloatRegister($dst$$reg), __ T8B, as_FloatRegister($src$$reg), as_FloatRegister($src$$reg)); } - __ mov(as_FloatRegister($dst$$reg), __ T2S, $idx$$constant, $val$$Register); + __ mov(as_FloatRegister($dst$$reg), __ S, $idx$$constant, $val$$Register); %} ins_pipe(pipe_slow); %} @@ -1788,13 +1788,13 @@ instruct insert4I(vecX dst, vecX src, iRegIorL2I val, immI idx) match(Set dst (VectorInsert (Binary src val) idx)); ins_cost(INSN_COST); format %{ "orr $dst, T16B, $src, $src\n\t" - "mov $dst, T4S, $idx, $val\t# insert into vector(4I)" %} + "mov $dst, S, $idx, $val\t# insert into vector(4I)" %} ins_encode %{ if (as_FloatRegister($dst$$reg) != as_FloatRegister($src$$reg)) { __ orr(as_FloatRegister($dst$$reg), __ T16B, as_FloatRegister($src$$reg), as_FloatRegister($src$$reg)); } - __ mov(as_FloatRegister($dst$$reg), __ T4S, $idx$$constant, $val$$Register); + __ mov(as_FloatRegister($dst$$reg), __ S, $idx$$constant, $val$$Register); %} ins_pipe(pipe_slow); %} @@ -1805,13 +1805,13 @@ instruct insert2L(vecX dst, vecX src, iRegL val, immI idx) match(Set dst (VectorInsert (Binary src val) idx)); ins_cost(INSN_COST); format %{ "orr $dst, T16B, $src, $src\n\t" - "mov $dst, T2D, $idx, $val\t# insert into vector(2L)" %} + "mov $dst, D, $idx, $val\t# insert into vector(2L)" %} ins_encode %{ if (as_FloatRegister($dst$$reg) != as_FloatRegister($src$$reg)) { __ orr(as_FloatRegister($dst$$reg), __ T16B, as_FloatRegister($src$$reg), as_FloatRegister($src$$reg)); } - __ mov(as_FloatRegister($dst$$reg), __ T2D, $idx$$constant, $val$$Register); + __ mov(as_FloatRegister($dst$$reg), __ D, $idx$$constant, $val$$Register); %} ins_pipe(pipe_slow); %} @@ -2044,11 +2044,11 @@ instruct vmul2L(vecX dst, vecX src1, vecX src2, iRegLNoSp tmp1, iRegLNoSp tmp2) __ umov($tmp1$$Register, as_FloatRegister($src1$$reg), __ D, 0); __ umov($tmp2$$Register, as_FloatRegister($src2$$reg), __ D, 0); __ mul(as_Register($tmp2$$reg), as_Register($tmp2$$reg), as_Register($tmp1$$reg)); - __ mov(as_FloatRegister($dst$$reg), __ T2D, 0, $tmp2$$Register); + __ mov(as_FloatRegister($dst$$reg), __ D, 0, $tmp2$$Register); __ umov($tmp1$$Register, as_FloatRegister($src1$$reg), __ D, 1); __ umov($tmp2$$Register, as_FloatRegister($src2$$reg), __ D, 1); __ mul(as_Register($tmp2$$reg), as_Register($tmp2$$reg), as_Register($tmp1$$reg)); - __ mov(as_FloatRegister($dst$$reg), __ T2D, 1, $tmp2$$Register); + __ mov(as_FloatRegister($dst$$reg), __ D, 1, $tmp2$$Register); %} ins_pipe(pipe_slow); %} @@ -4400,11 +4400,17 @@ instruct vxor16B(vecX dst, vecX src1, vecX src2) // ------------------------------ Shift --------------------------------------- -instruct vshiftcnt8B(vecD dst, iRegIorL2I cnt) %{ +// Vector shift count +// Note-1: Low 8 bits of each element are used, so it doesn't matter if we +// treat it as ints or bytes here. +// Note-2: Shift value is negated for RShiftCntV additionally. See the comments +// on vsra8B rule for more details. + +instruct vslcnt8B(vecD dst, iRegIorL2I cnt) %{ predicate(UseSVE == 0 && (n->as_Vector()->length_in_bytes() == 4 || - n->as_Vector()->length_in_bytes() == 8)); + n->as_Vector()->length_in_bytes() == 8)); match(Set dst (LShiftCntV cnt)); - match(Set dst (RShiftCntV cnt)); + ins_cost(INSN_COST); format %{ "dup $dst, $cnt\t# shift count vector (8B)" %} ins_encode %{ __ dup(as_FloatRegister($dst$$reg), __ T8B, as_Register($cnt$$reg)); @@ -4412,10 +4418,10 @@ instruct vshiftcnt8B(vecD dst, iRegIorL2I cnt) %{ ins_pipe(vdup_reg_reg64); %} -instruct vshiftcnt16B(vecX dst, iRegIorL2I cnt) %{ - predicate(UseSVE == 0 && (n->as_Vector()->length_in_bytes() == 16)); +instruct vslcnt16B(vecX dst, iRegIorL2I cnt) %{ + predicate(UseSVE == 0 && n->as_Vector()->length_in_bytes() == 16); match(Set dst (LShiftCntV cnt)); - match(Set dst (RShiftCntV cnt)); + ins_cost(INSN_COST); format %{ "dup $dst, $cnt\t# shift count vector (16B)" %} ins_encode %{ __ dup(as_FloatRegister($dst$$reg), __ T16B, as_Register($cnt$$reg)); @@ -4423,9 +4429,35 @@ instruct vshiftcnt16B(vecX dst, iRegIorL2I cnt) %{ ins_pipe(vdup_reg_reg128); %} +instruct vsrcnt8B(vecD dst, iRegIorL2I cnt) %{ + predicate(UseSVE == 0 && (n->as_Vector()->length_in_bytes() == 4 || + n->as_Vector()->length_in_bytes() == 8)); + match(Set dst (RShiftCntV cnt)); + ins_cost(INSN_COST * 2); + format %{ "negw rscratch1, $cnt\t" + "dup $dst, rscratch1\t# shift count vector (8B)" %} + ins_encode %{ + __ negw(rscratch1, as_Register($cnt$$reg)); + __ dup(as_FloatRegister($dst$$reg), __ T8B, rscratch1); + %} + ins_pipe(vdup_reg_reg64); +%} + +instruct vsrcnt16B(vecX dst, iRegIorL2I cnt) %{ + predicate(UseSVE == 0 && n->as_Vector()->length_in_bytes() == 16); + match(Set dst (RShiftCntV cnt)); + ins_cost(INSN_COST * 2); + format %{ "negw rscratch1, $cnt\t" + "dup $dst, rscratch1\t# shift count vector (16B)" %} + ins_encode %{ + __ negw(rscratch1, as_Register($cnt$$reg)); + __ dup(as_FloatRegister($dst$$reg), __ T16B, rscratch1); + %} + ins_pipe(vdup_reg_reg128); +%} + instruct vsll8B(vecD dst, vecD src, vecD shift) %{ - predicate(n->as_Vector()->length() == 4 || - n->as_Vector()->length() == 8); + predicate(n->as_Vector()->length() == 4 || n->as_Vector()->length() == 8); match(Set dst (LShiftVB src shift)); ins_cost(INSN_COST); format %{ "sshl $dst,$src,$shift\t# vector (8B)" %} @@ -4459,8 +4491,6 @@ instruct vsll16B(vecX dst, vecX src, vecX shift) %{ // LoadVector RShiftCntV // | / // RShiftVI -// Note: In inner loop, multiple neg instructions are used, which can be -// moved to outer loop and merge into one neg instruction. // // Case 2: The vector shift count is from loading. // This case isn't supported by middle-end now. But it's supported by @@ -4470,83 +4500,145 @@ instruct vsll16B(vecX dst, vecX src, vecX shift) %{ // | / // RShiftVI // +// The negate is conducted in RShiftCntV rule for case 1, whereas it's done in +// RShiftV* rules for case 2. Because there exists an optimization opportunity +// for case 1, that is, multiple neg instructions in inner loop can be hoisted +// to outer loop and merged into one neg instruction. +// +// Note that ShiftVNode::is_var_shift() indicates whether the vector shift +// count is a variable vector(case 2) or not(a vector generated by RShiftCntV, +// i.e. case 1). -instruct vsra8B(vecD dst, vecD src, vecD shift, vecD tmp) %{ - predicate(n->as_Vector()->length() == 4 || - n->as_Vector()->length() == 8); +instruct vsra8B(vecD dst, vecD src, vecD shift) %{ + predicate((n->as_Vector()->length() == 4 || n->as_Vector()->length() == 8) && + !n->as_ShiftV()->is_var_shift()); match(Set dst (RShiftVB src shift)); ins_cost(INSN_COST); - effect(TEMP tmp); - format %{ "negr $tmp,$shift\t" - "sshl $dst,$src,$tmp\t# vector (8B)" %} + format %{ "sshl $dst,$src,$shift\t# vector (8B)" %} + ins_encode %{ + __ sshl(as_FloatRegister($dst$$reg), __ T8B, + as_FloatRegister($src$$reg), + as_FloatRegister($shift$$reg)); + %} + ins_pipe(vshift64); +%} + +instruct vsra8B_var(vecD dst, vecD src, vecD shift) %{ + predicate((n->as_Vector()->length() == 4 || n->as_Vector()->length() == 8) && + n->as_ShiftV()->is_var_shift()); + match(Set dst (RShiftVB src shift)); + ins_cost(INSN_COST * 2); + effect(TEMP_DEF dst); + format %{ "negr $dst,$shift\t" + "sshl $dst,$src,$dst\t# vector (8B)" %} ins_encode %{ - __ negr(as_FloatRegister($tmp$$reg), __ T8B, + __ negr(as_FloatRegister($dst$$reg), __ T8B, as_FloatRegister($shift$$reg)); __ sshl(as_FloatRegister($dst$$reg), __ T8B, as_FloatRegister($src$$reg), - as_FloatRegister($tmp$$reg)); + as_FloatRegister($dst$$reg)); %} ins_pipe(vshift64); %} -instruct vsra16B(vecX dst, vecX src, vecX shift, vecX tmp) %{ - predicate(n->as_Vector()->length() == 16); +instruct vsra16B(vecX dst, vecX src, vecX shift) %{ + predicate(n->as_Vector()->length() == 16 && !n->as_ShiftV()->is_var_shift()); match(Set dst (RShiftVB src shift)); ins_cost(INSN_COST); - effect(TEMP tmp); - format %{ "negr $tmp,$shift\t" - "sshl $dst,$src,$tmp\t# vector (16B)" %} + format %{ "sshl $dst,$src,$shift\t# vector (16B)" %} ins_encode %{ - __ negr(as_FloatRegister($tmp$$reg), __ T16B, + __ sshl(as_FloatRegister($dst$$reg), __ T16B, + as_FloatRegister($src$$reg), + as_FloatRegister($shift$$reg)); + %} + ins_pipe(vshift128); +%} + +instruct vsra16B_var(vecX dst, vecX src, vecX shift) %{ + predicate(n->as_Vector()->length() == 16 && n->as_ShiftV()->is_var_shift()); + match(Set dst (RShiftVB src shift)); + ins_cost(INSN_COST * 2); + effect(TEMP_DEF dst); + format %{ "negr $dst,$shift\t" + "sshl $dst,$src,$dst\t# vector (16B)" %} + ins_encode %{ + __ negr(as_FloatRegister($dst$$reg), __ T16B, as_FloatRegister($shift$$reg)); __ sshl(as_FloatRegister($dst$$reg), __ T16B, as_FloatRegister($src$$reg), - as_FloatRegister($tmp$$reg)); + as_FloatRegister($dst$$reg)); %} ins_pipe(vshift128); %} -instruct vsrl8B(vecD dst, vecD src, vecD shift, vecD tmp) %{ - predicate(n->as_Vector()->length() == 4 || - n->as_Vector()->length() == 8); +instruct vsrl8B(vecD dst, vecD src, vecD shift) %{ + predicate((n->as_Vector()->length() == 4 || n->as_Vector()->length() == 8) && + !n->as_ShiftV()->is_var_shift()); match(Set dst (URShiftVB src shift)); ins_cost(INSN_COST); - effect(TEMP tmp); - format %{ "negr $tmp,$shift\t" - "ushl $dst,$src,$tmp\t# vector (8B)" %} + format %{ "ushl $dst,$src,$shift\t# vector (8B)" %} + ins_encode %{ + __ ushl(as_FloatRegister($dst$$reg), __ T8B, + as_FloatRegister($src$$reg), + as_FloatRegister($shift$$reg)); + %} + ins_pipe(vshift64); +%} + +instruct vsrl8B_var(vecD dst, vecD src, vecD shift) %{ + predicate((n->as_Vector()->length() == 4 || n->as_Vector()->length() == 8) && + n->as_ShiftV()->is_var_shift()); + match(Set dst (URShiftVB src shift)); + ins_cost(INSN_COST * 2); + effect(TEMP_DEF dst); + format %{ "negr $dst,$shift\t" + "ushl $dst,$src,$dst\t# vector (8B)" %} ins_encode %{ - __ negr(as_FloatRegister($tmp$$reg), __ T8B, + __ negr(as_FloatRegister($dst$$reg), __ T8B, as_FloatRegister($shift$$reg)); __ ushl(as_FloatRegister($dst$$reg), __ T8B, as_FloatRegister($src$$reg), - as_FloatRegister($tmp$$reg)); + as_FloatRegister($dst$$reg)); %} ins_pipe(vshift64); %} -instruct vsrl16B(vecX dst, vecX src, vecX shift, vecX tmp) %{ - predicate(n->as_Vector()->length() == 16); +instruct vsrl16B(vecX dst, vecX src, vecX shift) %{ + predicate(n->as_Vector()->length() == 16 && !n->as_ShiftV()->is_var_shift()); match(Set dst (URShiftVB src shift)); ins_cost(INSN_COST); - effect(TEMP tmp); - format %{ "negr $tmp,$shift\t" - "ushl $dst,$src,$tmp\t# vector (16B)" %} + format %{ "ushl $dst,$src,$shift\t# vector (16B)" %} ins_encode %{ - __ negr(as_FloatRegister($tmp$$reg), __ T16B, + __ ushl(as_FloatRegister($dst$$reg), __ T16B, + as_FloatRegister($src$$reg), + as_FloatRegister($shift$$reg)); + %} + ins_pipe(vshift128); +%} + +instruct vsrl16B_var(vecX dst, vecX src, vecX shift) %{ + predicate(n->as_Vector()->length() == 16 && n->as_ShiftV()->is_var_shift()); + match(Set dst (URShiftVB src shift)); + ins_cost(INSN_COST * 2); + effect(TEMP_DEF dst); + format %{ "negr $dst,$shift\t" + "ushl $dst,$src,$dst\t# vector (16B)" %} + ins_encode %{ + __ negr(as_FloatRegister($dst$$reg), __ T16B, as_FloatRegister($shift$$reg)); __ ushl(as_FloatRegister($dst$$reg), __ T16B, as_FloatRegister($src$$reg), - as_FloatRegister($tmp$$reg)); + as_FloatRegister($dst$$reg)); %} ins_pipe(vshift128); %} instruct vsll8B_imm(vecD dst, vecD src, immI shift) %{ - predicate(n->as_Vector()->length() == 4 || - n->as_Vector()->length() == 8); + predicate((n->as_Vector()->length() == 4 || n->as_Vector()->length() == 8) && + assert_not_var_shift(n)); match(Set dst (LShiftVB src (LShiftCntV shift))); ins_cost(INSN_COST); - format %{ "shl $dst, $src, $shift\t# vector (8B)" %} + format %{ "shl $dst, $src, $shift\t# vector (8B)" %} ins_encode %{ int sh = (int)$shift$$constant; if (sh >= 8) { @@ -4562,10 +4654,10 @@ instruct vsll8B_imm(vecD dst, vecD src, immI shift) %{ %} instruct vsll16B_imm(vecX dst, vecX src, immI shift) %{ - predicate(n->as_Vector()->length() == 16); + predicate(n->as_Vector()->length() == 16 && assert_not_var_shift(n)); match(Set dst (LShiftVB src (LShiftCntV shift))); ins_cost(INSN_COST); - format %{ "shl $dst, $src, $shift\t# vector (16B)" %} + format %{ "shl $dst, $src, $shift\t# vector (16B)" %} ins_encode %{ int sh = (int)$shift$$constant; if (sh >= 8) { @@ -4581,40 +4673,40 @@ instruct vsll16B_imm(vecX dst, vecX src, immI shift) %{ %} instruct vsra8B_imm(vecD dst, vecD src, immI shift) %{ - predicate(n->as_Vector()->length() == 4 || - n->as_Vector()->length() == 8); + predicate((n->as_Vector()->length() == 4 || n->as_Vector()->length() == 8) && + assert_not_var_shift(n)); match(Set dst (RShiftVB src (RShiftCntV shift))); ins_cost(INSN_COST); - format %{ "sshr $dst, $src, $shift\t# vector (8B)" %} + format %{ "sshr $dst, $src, $shift\t# vector (8B)" %} ins_encode %{ int sh = (int)$shift$$constant; if (sh >= 8) sh = 7; __ sshr(as_FloatRegister($dst$$reg), __ T8B, - as_FloatRegister($src$$reg), sh); + as_FloatRegister($src$$reg), sh); %} ins_pipe(vshift64_imm); %} instruct vsra16B_imm(vecX dst, vecX src, immI shift) %{ - predicate(n->as_Vector()->length() == 16); + predicate(n->as_Vector()->length() == 16 && assert_not_var_shift(n)); match(Set dst (RShiftVB src (RShiftCntV shift))); ins_cost(INSN_COST); - format %{ "sshr $dst, $src, $shift\t# vector (16B)" %} + format %{ "sshr $dst, $src, $shift\t# vector (16B)" %} ins_encode %{ int sh = (int)$shift$$constant; if (sh >= 8) sh = 7; __ sshr(as_FloatRegister($dst$$reg), __ T16B, - as_FloatRegister($src$$reg), sh); + as_FloatRegister($src$$reg), sh); %} ins_pipe(vshift128_imm); %} instruct vsrl8B_imm(vecD dst, vecD src, immI shift) %{ - predicate(n->as_Vector()->length() == 4 || - n->as_Vector()->length() == 8); + predicate((n->as_Vector()->length() == 4 || n->as_Vector()->length() == 8) && + assert_not_var_shift(n)); match(Set dst (URShiftVB src (RShiftCntV shift))); ins_cost(INSN_COST); - format %{ "ushr $dst, $src, $shift\t# vector (8B)" %} + format %{ "ushr $dst, $src, $shift\t# vector (8B)" %} ins_encode %{ int sh = (int)$shift$$constant; if (sh >= 8) { @@ -4623,17 +4715,17 @@ instruct vsrl8B_imm(vecD dst, vecD src, immI shift) %{ as_FloatRegister($src$$reg)); } else { __ ushr(as_FloatRegister($dst$$reg), __ T8B, - as_FloatRegister($src$$reg), sh); + as_FloatRegister($src$$reg), sh); } %} ins_pipe(vshift64_imm); %} instruct vsrl16B_imm(vecX dst, vecX src, immI shift) %{ - predicate(n->as_Vector()->length() == 16); + predicate(n->as_Vector()->length() == 16 && assert_not_var_shift(n)); match(Set dst (URShiftVB src (RShiftCntV shift))); ins_cost(INSN_COST); - format %{ "ushr $dst, $src, $shift\t# vector (16B)" %} + format %{ "ushr $dst, $src, $shift\t# vector (16B)" %} ins_encode %{ int sh = (int)$shift$$constant; if (sh >= 8) { @@ -4642,15 +4734,14 @@ instruct vsrl16B_imm(vecX dst, vecX src, immI shift) %{ as_FloatRegister($src$$reg)); } else { __ ushr(as_FloatRegister($dst$$reg), __ T16B, - as_FloatRegister($src$$reg), sh); + as_FloatRegister($src$$reg), sh); } %} ins_pipe(vshift128_imm); %} instruct vsll4S(vecD dst, vecD src, vecD shift) %{ - predicate(n->as_Vector()->length() == 2 || - n->as_Vector()->length() == 4); + predicate(n->as_Vector()->length() == 2 || n->as_Vector()->length() == 4); match(Set dst (LShiftVS src shift)); ins_cost(INSN_COST); format %{ "sshl $dst,$src,$shift\t# vector (4H)" %} @@ -4675,82 +4766,136 @@ instruct vsll8S(vecX dst, vecX src, vecX shift) %{ ins_pipe(vshift128); %} -instruct vsra4S(vecD dst, vecD src, vecD shift, vecD tmp) %{ - predicate(n->as_Vector()->length() == 2 || - n->as_Vector()->length() == 4); +instruct vsra4S(vecD dst, vecD src, vecD shift) %{ + predicate((n->as_Vector()->length() == 2 || n->as_Vector()->length() == 4) && + !n->as_ShiftV()->is_var_shift()); match(Set dst (RShiftVS src shift)); ins_cost(INSN_COST); - effect(TEMP tmp); - format %{ "negr $tmp,$shift\t" - "sshl $dst,$src,$tmp\t# vector (4H)" %} + format %{ "sshl $dst,$src,$shift\t# vector (4H)" %} ins_encode %{ - __ negr(as_FloatRegister($tmp$$reg), __ T8B, + __ sshl(as_FloatRegister($dst$$reg), __ T4H, + as_FloatRegister($src$$reg), + as_FloatRegister($shift$$reg)); + %} + ins_pipe(vshift64); +%} + +instruct vsra4S_var(vecD dst, vecD src, vecD shift) %{ + predicate((n->as_Vector()->length() == 2 || n->as_Vector()->length() == 4) && + n->as_ShiftV()->is_var_shift()); + match(Set dst (RShiftVS src shift)); + ins_cost(INSN_COST * 2); + effect(TEMP_DEF dst); + format %{ "negr $dst,$shift\t" + "sshl $dst,$src,$dst\t# vector (4H)" %} + ins_encode %{ + __ negr(as_FloatRegister($dst$$reg), __ T8B, as_FloatRegister($shift$$reg)); __ sshl(as_FloatRegister($dst$$reg), __ T4H, as_FloatRegister($src$$reg), - as_FloatRegister($tmp$$reg)); + as_FloatRegister($dst$$reg)); %} ins_pipe(vshift64); %} -instruct vsra8S(vecX dst, vecX src, vecX shift, vecX tmp) %{ - predicate(n->as_Vector()->length() == 8); +instruct vsra8S(vecX dst, vecX src, vecX shift) %{ + predicate(n->as_Vector()->length() == 8 && !n->as_ShiftV()->is_var_shift()); match(Set dst (RShiftVS src shift)); ins_cost(INSN_COST); - effect(TEMP tmp); - format %{ "negr $tmp,$shift\t" - "sshl $dst,$src,$tmp\t# vector (8H)" %} + format %{ "sshl $dst,$src,$shift\t# vector (8H)" %} + ins_encode %{ + __ sshl(as_FloatRegister($dst$$reg), __ T8H, + as_FloatRegister($src$$reg), + as_FloatRegister($shift$$reg)); + %} + ins_pipe(vshift128); +%} + +instruct vsra8S_var(vecX dst, vecX src, vecX shift) %{ + predicate(n->as_Vector()->length() == 8 && n->as_ShiftV()->is_var_shift()); + match(Set dst (RShiftVS src shift)); + ins_cost(INSN_COST * 2); + effect(TEMP_DEF dst); + format %{ "negr $dst,$shift\t" + "sshl $dst,$src,$dst\t# vector (8H)" %} ins_encode %{ - __ negr(as_FloatRegister($tmp$$reg), __ T16B, + __ negr(as_FloatRegister($dst$$reg), __ T16B, as_FloatRegister($shift$$reg)); __ sshl(as_FloatRegister($dst$$reg), __ T8H, as_FloatRegister($src$$reg), - as_FloatRegister($tmp$$reg)); + as_FloatRegister($dst$$reg)); %} ins_pipe(vshift128); %} -instruct vsrl4S(vecD dst, vecD src, vecD shift, vecD tmp) %{ - predicate(n->as_Vector()->length() == 2 || - n->as_Vector()->length() == 4); +instruct vsrl4S(vecD dst, vecD src, vecD shift) %{ + predicate((n->as_Vector()->length() == 2 || n->as_Vector()->length() == 4) && + !n->as_ShiftV()->is_var_shift()); match(Set dst (URShiftVS src shift)); ins_cost(INSN_COST); - effect(TEMP tmp); - format %{ "negr $tmp,$shift\t" - "ushl $dst,$src,$tmp\t# vector (4H)" %} + format %{ "ushl $dst,$src,$shift\t# vector (4H)" %} + ins_encode %{ + __ ushl(as_FloatRegister($dst$$reg), __ T4H, + as_FloatRegister($src$$reg), + as_FloatRegister($shift$$reg)); + %} + ins_pipe(vshift64); +%} + +instruct vsrl4S_var(vecD dst, vecD src, vecD shift) %{ + predicate((n->as_Vector()->length() == 2 || n->as_Vector()->length() == 4) && + n->as_ShiftV()->is_var_shift()); + match(Set dst (URShiftVS src shift)); + ins_cost(INSN_COST * 2); + effect(TEMP_DEF dst); + format %{ "negr $dst,$shift\t" + "ushl $dst,$src,$dst\t# vector (4H)" %} ins_encode %{ - __ negr(as_FloatRegister($tmp$$reg), __ T8B, + __ negr(as_FloatRegister($dst$$reg), __ T8B, as_FloatRegister($shift$$reg)); __ ushl(as_FloatRegister($dst$$reg), __ T4H, as_FloatRegister($src$$reg), - as_FloatRegister($tmp$$reg)); + as_FloatRegister($dst$$reg)); %} ins_pipe(vshift64); %} -instruct vsrl8S(vecX dst, vecX src, vecX shift, vecX tmp) %{ - predicate(n->as_Vector()->length() == 8); +instruct vsrl8S(vecX dst, vecX src, vecX shift) %{ + predicate(n->as_Vector()->length() == 8 && !n->as_ShiftV()->is_var_shift()); match(Set dst (URShiftVS src shift)); ins_cost(INSN_COST); - effect(TEMP tmp); - format %{ "negr $tmp,$shift\t" - "ushl $dst,$src,$tmp\t# vector (8H)" %} + format %{ "ushl $dst,$src,$shift\t# vector (8H)" %} ins_encode %{ - __ negr(as_FloatRegister($tmp$$reg), __ T16B, + __ ushl(as_FloatRegister($dst$$reg), __ T8H, + as_FloatRegister($src$$reg), + as_FloatRegister($shift$$reg)); + %} + ins_pipe(vshift128); +%} + +instruct vsrl8S_var(vecX dst, vecX src, vecX shift) %{ + predicate(n->as_Vector()->length() == 8 && n->as_ShiftV()->is_var_shift()); + match(Set dst (URShiftVS src shift)); + ins_cost(INSN_COST * 2); + effect(TEMP_DEF dst); + format %{ "negr $dst,$shift\t" + "ushl $dst,$src,$dst\t# vector (8H)" %} + ins_encode %{ + __ negr(as_FloatRegister($dst$$reg), __ T16B, as_FloatRegister($shift$$reg)); __ ushl(as_FloatRegister($dst$$reg), __ T8H, as_FloatRegister($src$$reg), - as_FloatRegister($tmp$$reg)); + as_FloatRegister($dst$$reg)); %} ins_pipe(vshift128); %} instruct vsll4S_imm(vecD dst, vecD src, immI shift) %{ - predicate(n->as_Vector()->length() == 2 || - n->as_Vector()->length() == 4); + predicate((n->as_Vector()->length() == 2 || n->as_Vector()->length() == 4) && + assert_not_var_shift(n)); match(Set dst (LShiftVS src (LShiftCntV shift))); ins_cost(INSN_COST); - format %{ "shl $dst, $src, $shift\t# vector (4H)" %} + format %{ "shl $dst, $src, $shift\t# vector (4H)" %} ins_encode %{ int sh = (int)$shift$$constant; if (sh >= 16) { @@ -4766,10 +4911,10 @@ instruct vsll4S_imm(vecD dst, vecD src, immI shift) %{ %} instruct vsll8S_imm(vecX dst, vecX src, immI shift) %{ - predicate(n->as_Vector()->length() == 8); + predicate(n->as_Vector()->length() == 8 && assert_not_var_shift(n)); match(Set dst (LShiftVS src (LShiftCntV shift))); ins_cost(INSN_COST); - format %{ "shl $dst, $src, $shift\t# vector (8H)" %} + format %{ "shl $dst, $src, $shift\t# vector (8H)" %} ins_encode %{ int sh = (int)$shift$$constant; if (sh >= 16) { @@ -4785,40 +4930,40 @@ instruct vsll8S_imm(vecX dst, vecX src, immI shift) %{ %} instruct vsra4S_imm(vecD dst, vecD src, immI shift) %{ - predicate(n->as_Vector()->length() == 2 || - n->as_Vector()->length() == 4); + predicate((n->as_Vector()->length() == 2 || n->as_Vector()->length() == 4) && + assert_not_var_shift(n)); match(Set dst (RShiftVS src (RShiftCntV shift))); ins_cost(INSN_COST); - format %{ "sshr $dst, $src, $shift\t# vector (4H)" %} + format %{ "sshr $dst, $src, $shift\t# vector (4H)" %} ins_encode %{ int sh = (int)$shift$$constant; if (sh >= 16) sh = 15; __ sshr(as_FloatRegister($dst$$reg), __ T4H, - as_FloatRegister($src$$reg), sh); + as_FloatRegister($src$$reg), sh); %} ins_pipe(vshift64_imm); %} instruct vsra8S_imm(vecX dst, vecX src, immI shift) %{ - predicate(n->as_Vector()->length() == 8); + predicate(n->as_Vector()->length() == 8 && assert_not_var_shift(n)); match(Set dst (RShiftVS src (RShiftCntV shift))); ins_cost(INSN_COST); - format %{ "sshr $dst, $src, $shift\t# vector (8H)" %} + format %{ "sshr $dst, $src, $shift\t# vector (8H)" %} ins_encode %{ int sh = (int)$shift$$constant; if (sh >= 16) sh = 15; __ sshr(as_FloatRegister($dst$$reg), __ T8H, - as_FloatRegister($src$$reg), sh); + as_FloatRegister($src$$reg), sh); %} ins_pipe(vshift128_imm); %} instruct vsrl4S_imm(vecD dst, vecD src, immI shift) %{ - predicate(n->as_Vector()->length() == 2 || - n->as_Vector()->length() == 4); + predicate((n->as_Vector()->length() == 2 || n->as_Vector()->length() == 4) && + assert_not_var_shift(n)); match(Set dst (URShiftVS src (RShiftCntV shift))); ins_cost(INSN_COST); - format %{ "ushr $dst, $src, $shift\t# vector (4H)" %} + format %{ "ushr $dst, $src, $shift\t# vector (4H)" %} ins_encode %{ int sh = (int)$shift$$constant; if (sh >= 16) { @@ -4827,17 +4972,17 @@ instruct vsrl4S_imm(vecD dst, vecD src, immI shift) %{ as_FloatRegister($src$$reg)); } else { __ ushr(as_FloatRegister($dst$$reg), __ T4H, - as_FloatRegister($src$$reg), sh); + as_FloatRegister($src$$reg), sh); } %} ins_pipe(vshift64_imm); %} instruct vsrl8S_imm(vecX dst, vecX src, immI shift) %{ - predicate(n->as_Vector()->length() == 8); + predicate(n->as_Vector()->length() == 8 && assert_not_var_shift(n)); match(Set dst (URShiftVS src (RShiftCntV shift))); ins_cost(INSN_COST); - format %{ "ushr $dst, $src, $shift\t# vector (8H)" %} + format %{ "ushr $dst, $src, $shift\t# vector (8H)" %} ins_encode %{ int sh = (int)$shift$$constant; if (sh >= 16) { @@ -4846,7 +4991,7 @@ instruct vsrl8S_imm(vecX dst, vecX src, immI shift) %{ as_FloatRegister($src$$reg)); } else { __ ushr(as_FloatRegister($dst$$reg), __ T8H, - as_FloatRegister($src$$reg), sh); + as_FloatRegister($src$$reg), sh); } %} ins_pipe(vshift128_imm); @@ -4878,79 +5023,131 @@ instruct vsll4I(vecX dst, vecX src, vecX shift) %{ ins_pipe(vshift128); %} -instruct vsra2I(vecD dst, vecD src, vecD shift, vecD tmp) %{ - predicate(n->as_Vector()->length() == 2); +instruct vsra2I(vecD dst, vecD src, vecD shift) %{ + predicate(n->as_Vector()->length() == 2 && !n->as_ShiftV()->is_var_shift()); match(Set dst (RShiftVI src shift)); ins_cost(INSN_COST); - effect(TEMP tmp); - format %{ "negr $tmp,$shift\t" - "sshl $dst,$src,$tmp\t# vector (2S)" %} + format %{ "sshl $dst,$src,$shift\t# vector (2S)" %} + ins_encode %{ + __ sshl(as_FloatRegister($dst$$reg), __ T2S, + as_FloatRegister($src$$reg), + as_FloatRegister($shift$$reg)); + %} + ins_pipe(vshift64); +%} + +instruct vsra2I_var(vecD dst, vecD src, vecD shift) %{ + predicate(n->as_Vector()->length() == 2 && n->as_ShiftV()->is_var_shift()); + match(Set dst (RShiftVI src shift)); + ins_cost(INSN_COST * 2); + effect(TEMP_DEF dst); + format %{ "negr $dst,$shift\t" + "sshl $dst,$src,$dst\t# vector (2S)" %} ins_encode %{ - __ negr(as_FloatRegister($tmp$$reg), __ T8B, + __ negr(as_FloatRegister($dst$$reg), __ T8B, as_FloatRegister($shift$$reg)); __ sshl(as_FloatRegister($dst$$reg), __ T2S, as_FloatRegister($src$$reg), - as_FloatRegister($tmp$$reg)); + as_FloatRegister($dst$$reg)); %} ins_pipe(vshift64); %} -instruct vsra4I(vecX dst, vecX src, vecX shift, vecX tmp) %{ - predicate(n->as_Vector()->length() == 4); +instruct vsra4I(vecX dst, vecX src, vecX shift) %{ + predicate(n->as_Vector()->length() == 4 && !n->as_ShiftV()->is_var_shift()); match(Set dst (RShiftVI src shift)); ins_cost(INSN_COST); - effect(TEMP tmp); - format %{ "negr $tmp,$shift\t" - "sshl $dst,$src,$tmp\t# vector (4S)" %} + format %{ "sshl $dst,$src,$shift\t# vector (4S)" %} ins_encode %{ - __ negr(as_FloatRegister($tmp$$reg), __ T16B, + __ sshl(as_FloatRegister($dst$$reg), __ T4S, + as_FloatRegister($src$$reg), + as_FloatRegister($shift$$reg)); + %} + ins_pipe(vshift128); +%} + +instruct vsra4I_var(vecX dst, vecX src, vecX shift) %{ + predicate(n->as_Vector()->length() == 4 && n->as_ShiftV()->is_var_shift()); + match(Set dst (RShiftVI src shift)); + ins_cost(INSN_COST * 2); + effect(TEMP_DEF dst); + format %{ "negr $dst,$shift\t" + "sshl $dst,$src,$dst\t# vector (4S)" %} + ins_encode %{ + __ negr(as_FloatRegister($dst$$reg), __ T16B, as_FloatRegister($shift$$reg)); __ sshl(as_FloatRegister($dst$$reg), __ T4S, as_FloatRegister($src$$reg), - as_FloatRegister($tmp$$reg)); + as_FloatRegister($dst$$reg)); %} ins_pipe(vshift128); %} -instruct vsrl2I(vecD dst, vecD src, vecD shift, vecD tmp) %{ - predicate(n->as_Vector()->length() == 2); +instruct vsrl2I(vecD dst, vecD src, vecD shift) %{ + predicate(n->as_Vector()->length() == 2 && !n->as_ShiftV()->is_var_shift()); match(Set dst (URShiftVI src shift)); ins_cost(INSN_COST); - effect(TEMP tmp); - format %{ "negr $tmp,$shift\t" - "ushl $dst,$src,$tmp\t# vector (2S)" %} + format %{ "ushl $dst,$src,$shift\t# vector (2S)" %} + ins_encode %{ + __ ushl(as_FloatRegister($dst$$reg), __ T2S, + as_FloatRegister($src$$reg), + as_FloatRegister($shift$$reg)); + %} + ins_pipe(vshift64); +%} + +instruct vsrl2I_var(vecD dst, vecD src, vecD shift) %{ + predicate(n->as_Vector()->length() == 2 && n->as_ShiftV()->is_var_shift()); + match(Set dst (URShiftVI src shift)); + ins_cost(INSN_COST * 2); + effect(TEMP_DEF dst); + format %{ "negr $dst,$shift\t" + "ushl $dst,$src,$dst\t# vector (2S)" %} ins_encode %{ - __ negr(as_FloatRegister($tmp$$reg), __ T8B, + __ negr(as_FloatRegister($dst$$reg), __ T8B, as_FloatRegister($shift$$reg)); __ ushl(as_FloatRegister($dst$$reg), __ T2S, as_FloatRegister($src$$reg), - as_FloatRegister($tmp$$reg)); + as_FloatRegister($dst$$reg)); %} ins_pipe(vshift64); %} -instruct vsrl4I(vecX dst, vecX src, vecX shift, vecX tmp) %{ - predicate(n->as_Vector()->length() == 4); +instruct vsrl4I(vecX dst, vecX src, vecX shift) %{ + predicate(n->as_Vector()->length() == 4 && !n->as_ShiftV()->is_var_shift()); match(Set dst (URShiftVI src shift)); ins_cost(INSN_COST); - effect(TEMP tmp); - format %{ "negr $tmp,$shift\t" - "ushl $dst,$src,$tmp\t# vector (4S)" %} + format %{ "ushl $dst,$src,$shift\t# vector (4S)" %} ins_encode %{ - __ negr(as_FloatRegister($tmp$$reg), __ T16B, + __ ushl(as_FloatRegister($dst$$reg), __ T4S, + as_FloatRegister($src$$reg), + as_FloatRegister($shift$$reg)); + %} + ins_pipe(vshift128); +%} + +instruct vsrl4I_var(vecX dst, vecX src, vecX shift) %{ + predicate(n->as_Vector()->length() == 4 && n->as_ShiftV()->is_var_shift()); + match(Set dst (URShiftVI src shift)); + ins_cost(INSN_COST * 2); + effect(TEMP_DEF dst); + format %{ "negr $dst,$shift\t" + "ushl $dst,$src,$dst\t# vector (4S)" %} + ins_encode %{ + __ negr(as_FloatRegister($dst$$reg), __ T16B, as_FloatRegister($shift$$reg)); __ ushl(as_FloatRegister($dst$$reg), __ T4S, as_FloatRegister($src$$reg), - as_FloatRegister($tmp$$reg)); + as_FloatRegister($dst$$reg)); %} ins_pipe(vshift128); %} instruct vsll2I_imm(vecD dst, vecD src, immI shift) %{ - predicate(n->as_Vector()->length() == 2); + predicate(n->as_Vector()->length() == 2 && assert_not_var_shift(n)); match(Set dst (LShiftVI src (LShiftCntV shift))); ins_cost(INSN_COST); - format %{ "shl $dst, $src, $shift\t# vector (2S)" %} + format %{ "shl $dst, $src, $shift\t# vector (2S)" %} ins_encode %{ __ shl(as_FloatRegister($dst$$reg), __ T2S, as_FloatRegister($src$$reg), @@ -4960,10 +5157,10 @@ instruct vsll2I_imm(vecD dst, vecD src, immI shift) %{ %} instruct vsll4I_imm(vecX dst, vecX src, immI shift) %{ - predicate(n->as_Vector()->length() == 4); + predicate(n->as_Vector()->length() == 4 && assert_not_var_shift(n)); match(Set dst (LShiftVI src (LShiftCntV shift))); ins_cost(INSN_COST); - format %{ "shl $dst, $src, $shift\t# vector (4S)" %} + format %{ "shl $dst, $src, $shift\t# vector (4S)" %} ins_encode %{ __ shl(as_FloatRegister($dst$$reg), __ T4S, as_FloatRegister($src$$reg), @@ -4973,10 +5170,10 @@ instruct vsll4I_imm(vecX dst, vecX src, immI shift) %{ %} instruct vsra2I_imm(vecD dst, vecD src, immI shift) %{ - predicate(n->as_Vector()->length() == 2); + predicate(n->as_Vector()->length() == 2 && assert_not_var_shift(n)); match(Set dst (RShiftVI src (RShiftCntV shift))); ins_cost(INSN_COST); - format %{ "sshr $dst, $src, $shift\t# vector (2S)" %} + format %{ "sshr $dst, $src, $shift\t# vector (2S)" %} ins_encode %{ __ sshr(as_FloatRegister($dst$$reg), __ T2S, as_FloatRegister($src$$reg), @@ -4986,10 +5183,10 @@ instruct vsra2I_imm(vecD dst, vecD src, immI shift) %{ %} instruct vsra4I_imm(vecX dst, vecX src, immI shift) %{ - predicate(n->as_Vector()->length() == 4); + predicate(n->as_Vector()->length() == 4 && assert_not_var_shift(n)); match(Set dst (RShiftVI src (RShiftCntV shift))); ins_cost(INSN_COST); - format %{ "sshr $dst, $src, $shift\t# vector (4S)" %} + format %{ "sshr $dst, $src, $shift\t# vector (4S)" %} ins_encode %{ __ sshr(as_FloatRegister($dst$$reg), __ T4S, as_FloatRegister($src$$reg), @@ -4999,10 +5196,10 @@ instruct vsra4I_imm(vecX dst, vecX src, immI shift) %{ %} instruct vsrl2I_imm(vecD dst, vecD src, immI shift) %{ - predicate(n->as_Vector()->length() == 2); + predicate(n->as_Vector()->length() == 2 && assert_not_var_shift(n)); match(Set dst (URShiftVI src (RShiftCntV shift))); ins_cost(INSN_COST); - format %{ "ushr $dst, $src, $shift\t# vector (2S)" %} + format %{ "ushr $dst, $src, $shift\t# vector (2S)" %} ins_encode %{ __ ushr(as_FloatRegister($dst$$reg), __ T2S, as_FloatRegister($src$$reg), @@ -5012,10 +5209,10 @@ instruct vsrl2I_imm(vecD dst, vecD src, immI shift) %{ %} instruct vsrl4I_imm(vecX dst, vecX src, immI shift) %{ - predicate(n->as_Vector()->length() == 4); + predicate(n->as_Vector()->length() == 4 && assert_not_var_shift(n)); match(Set dst (URShiftVI src (RShiftCntV shift))); ins_cost(INSN_COST); - format %{ "ushr $dst, $src, $shift\t# vector (4S)" %} + format %{ "ushr $dst, $src, $shift\t# vector (4S)" %} ins_encode %{ __ ushr(as_FloatRegister($dst$$reg), __ T4S, as_FloatRegister($src$$reg), @@ -5037,45 +5234,71 @@ instruct vsll2L(vecX dst, vecX src, vecX shift) %{ ins_pipe(vshift128); %} -instruct vsra2L(vecX dst, vecX src, vecX shift, vecX tmp) %{ - predicate(n->as_Vector()->length() == 2); +instruct vsra2L(vecX dst, vecX src, vecX shift) %{ + predicate(n->as_Vector()->length() == 2 && !n->as_ShiftV()->is_var_shift()); match(Set dst (RShiftVL src shift)); ins_cost(INSN_COST); - effect(TEMP tmp); - format %{ "negr $tmp,$shift\t" - "sshl $dst,$src,$tmp\t# vector (2D)" %} + format %{ "sshl $dst,$src,$shift\t# vector (2D)" %} + ins_encode %{ + __ sshl(as_FloatRegister($dst$$reg), __ T2D, + as_FloatRegister($src$$reg), + as_FloatRegister($shift$$reg)); + %} + ins_pipe(vshift128); +%} + +instruct vsra2L_var(vecX dst, vecX src, vecX shift) %{ + predicate(n->as_Vector()->length() == 2 && n->as_ShiftV()->is_var_shift()); + match(Set dst (RShiftVL src shift)); + ins_cost(INSN_COST * 2); + effect(TEMP_DEF dst); + format %{ "negr $dst,$shift\t" + "sshl $dst,$src,$dst\t# vector (2D)" %} ins_encode %{ - __ negr(as_FloatRegister($tmp$$reg), __ T16B, + __ negr(as_FloatRegister($dst$$reg), __ T16B, as_FloatRegister($shift$$reg)); __ sshl(as_FloatRegister($dst$$reg), __ T2D, as_FloatRegister($src$$reg), - as_FloatRegister($tmp$$reg)); + as_FloatRegister($dst$$reg)); %} ins_pipe(vshift128); %} -instruct vsrl2L(vecX dst, vecX src, vecX shift, vecX tmp) %{ - predicate(n->as_Vector()->length() == 2); +instruct vsrl2L(vecX dst, vecX src, vecX shift) %{ + predicate(n->as_Vector()->length() == 2 && !n->as_ShiftV()->is_var_shift()); match(Set dst (URShiftVL src shift)); ins_cost(INSN_COST); - effect(TEMP tmp); - format %{ "negr $tmp,$shift\t" - "ushl $dst,$src,$tmp\t# vector (2D)" %} + format %{ "ushl $dst,$src,$shift\t# vector (2D)" %} ins_encode %{ - __ negr(as_FloatRegister($tmp$$reg), __ T16B, + __ ushl(as_FloatRegister($dst$$reg), __ T2D, + as_FloatRegister($src$$reg), + as_FloatRegister($shift$$reg)); + %} + ins_pipe(vshift128); +%} + +instruct vsrl2L_var(vecX dst, vecX src, vecX shift) %{ + predicate(n->as_Vector()->length() == 2 && n->as_ShiftV()->is_var_shift()); + match(Set dst (URShiftVL src shift)); + ins_cost(INSN_COST * 2); + effect(TEMP_DEF dst); + format %{ "negr $dst,$shift\t" + "ushl $dst,$src,$dst\t# vector (2D)" %} + ins_encode %{ + __ negr(as_FloatRegister($dst$$reg), __ T16B, as_FloatRegister($shift$$reg)); __ ushl(as_FloatRegister($dst$$reg), __ T2D, as_FloatRegister($src$$reg), - as_FloatRegister($tmp$$reg)); + as_FloatRegister($dst$$reg)); %} ins_pipe(vshift128); %} instruct vsll2L_imm(vecX dst, vecX src, immI shift) %{ - predicate(n->as_Vector()->length() == 2); + predicate(n->as_Vector()->length() == 2 && assert_not_var_shift(n)); match(Set dst (LShiftVL src (LShiftCntV shift))); ins_cost(INSN_COST); - format %{ "shl $dst, $src, $shift\t# vector (2D)" %} + format %{ "shl $dst, $src, $shift\t# vector (2D)" %} ins_encode %{ __ shl(as_FloatRegister($dst$$reg), __ T2D, as_FloatRegister($src$$reg), @@ -5085,10 +5308,10 @@ instruct vsll2L_imm(vecX dst, vecX src, immI shift) %{ %} instruct vsra2L_imm(vecX dst, vecX src, immI shift) %{ - predicate(n->as_Vector()->length() == 2); + predicate(n->as_Vector()->length() == 2 && assert_not_var_shift(n)); match(Set dst (RShiftVL src (RShiftCntV shift))); ins_cost(INSN_COST); - format %{ "sshr $dst, $src, $shift\t# vector (2D)" %} + format %{ "sshr $dst, $src, $shift\t# vector (2D)" %} ins_encode %{ __ sshr(as_FloatRegister($dst$$reg), __ T2D, as_FloatRegister($src$$reg), @@ -5098,10 +5321,10 @@ instruct vsra2L_imm(vecX dst, vecX src, immI shift) %{ %} instruct vsrl2L_imm(vecX dst, vecX src, immI shift) %{ - predicate(n->as_Vector()->length() == 2); + predicate(n->as_Vector()->length() == 2 && assert_not_var_shift(n)); match(Set dst (URShiftVL src (RShiftCntV shift))); ins_cost(INSN_COST); - format %{ "ushr $dst, $src, $shift\t# vector (2D)" %} + format %{ "ushr $dst, $src, $shift\t# vector (2D)" %} ins_encode %{ __ ushr(as_FloatRegister($dst$$reg), __ T2D, as_FloatRegister($src$$reg), @@ -5114,12 +5337,12 @@ instruct vsraa8B_imm(vecD dst, vecD src, immI shift) %{ predicate(n->as_Vector()->length() == 8); match(Set dst (AddVB dst (RShiftVB src (RShiftCntV shift)))); ins_cost(INSN_COST); - format %{ "ssra $dst, $src, $shift\t# vector (8B)" %} + format %{ "ssra $dst, $src, $shift\t# vector (8B)" %} ins_encode %{ int sh = (int)$shift$$constant; if (sh >= 8) sh = 7; __ ssra(as_FloatRegister($dst$$reg), __ T8B, - as_FloatRegister($src$$reg), sh); + as_FloatRegister($src$$reg), sh); %} ins_pipe(vshift64_imm); %} @@ -5128,12 +5351,12 @@ instruct vsraa16B_imm(vecX dst, vecX src, immI shift) %{ predicate(n->as_Vector()->length() == 16); match(Set dst (AddVB dst (RShiftVB src (RShiftCntV shift)))); ins_cost(INSN_COST); - format %{ "ssra $dst, $src, $shift\t# vector (16B)" %} + format %{ "ssra $dst, $src, $shift\t# vector (16B)" %} ins_encode %{ int sh = (int)$shift$$constant; if (sh >= 8) sh = 7; __ ssra(as_FloatRegister($dst$$reg), __ T16B, - as_FloatRegister($src$$reg), sh); + as_FloatRegister($src$$reg), sh); %} ins_pipe(vshift128_imm); %} @@ -5142,12 +5365,12 @@ instruct vsraa4S_imm(vecD dst, vecD src, immI shift) %{ predicate(n->as_Vector()->length() == 4); match(Set dst (AddVS dst (RShiftVS src (RShiftCntV shift)))); ins_cost(INSN_COST); - format %{ "ssra $dst, $src, $shift\t# vector (4H)" %} + format %{ "ssra $dst, $src, $shift\t# vector (4H)" %} ins_encode %{ int sh = (int)$shift$$constant; if (sh >= 16) sh = 15; __ ssra(as_FloatRegister($dst$$reg), __ T4H, - as_FloatRegister($src$$reg), sh); + as_FloatRegister($src$$reg), sh); %} ins_pipe(vshift64_imm); %} @@ -5156,12 +5379,12 @@ instruct vsraa8S_imm(vecX dst, vecX src, immI shift) %{ predicate(n->as_Vector()->length() == 8); match(Set dst (AddVS dst (RShiftVS src (RShiftCntV shift)))); ins_cost(INSN_COST); - format %{ "ssra $dst, $src, $shift\t# vector (8H)" %} + format %{ "ssra $dst, $src, $shift\t# vector (8H)" %} ins_encode %{ int sh = (int)$shift$$constant; if (sh >= 16) sh = 15; __ ssra(as_FloatRegister($dst$$reg), __ T8H, - as_FloatRegister($src$$reg), sh); + as_FloatRegister($src$$reg), sh); %} ins_pipe(vshift128_imm); %} @@ -5170,7 +5393,7 @@ instruct vsraa2I_imm(vecD dst, vecD src, immI shift) %{ predicate(n->as_Vector()->length() == 2); match(Set dst (AddVI dst (RShiftVI src (RShiftCntV shift)))); ins_cost(INSN_COST); - format %{ "ssra $dst, $src, $shift\t# vector (2S)" %} + format %{ "ssra $dst, $src, $shift\t# vector (2S)" %} ins_encode %{ __ ssra(as_FloatRegister($dst$$reg), __ T2S, as_FloatRegister($src$$reg), @@ -5183,7 +5406,7 @@ instruct vsraa4I_imm(vecX dst, vecX src, immI shift) %{ predicate(n->as_Vector()->length() == 4); match(Set dst (AddVI dst (RShiftVI src (RShiftCntV shift)))); ins_cost(INSN_COST); - format %{ "ssra $dst, $src, $shift\t# vector (4S)" %} + format %{ "ssra $dst, $src, $shift\t# vector (4S)" %} ins_encode %{ __ ssra(as_FloatRegister($dst$$reg), __ T4S, as_FloatRegister($src$$reg), @@ -5196,7 +5419,7 @@ instruct vsraa2L_imm(vecX dst, vecX src, immI shift) %{ predicate(n->as_Vector()->length() == 2); match(Set dst (AddVL dst (RShiftVL src (RShiftCntV shift)))); ins_cost(INSN_COST); - format %{ "ssra $dst, $src, $shift\t# vector (2D)" %} + format %{ "ssra $dst, $src, $shift\t# vector (2D)" %} ins_encode %{ __ ssra(as_FloatRegister($dst$$reg), __ T2D, as_FloatRegister($src$$reg), @@ -5209,12 +5432,12 @@ instruct vsrla8B_imm(vecD dst, vecD src, immI shift) %{ predicate(n->as_Vector()->length() == 8); match(Set dst (AddVB dst (URShiftVB src (RShiftCntV shift)))); ins_cost(INSN_COST); - format %{ "usra $dst, $src, $shift\t# vector (8B)" %} + format %{ "usra $dst, $src, $shift\t# vector (8B)" %} ins_encode %{ int sh = (int)$shift$$constant; if (sh < 8) { __ usra(as_FloatRegister($dst$$reg), __ T8B, - as_FloatRegister($src$$reg), sh); + as_FloatRegister($src$$reg), sh); } %} ins_pipe(vshift64_imm); @@ -5224,12 +5447,12 @@ instruct vsrla16B_imm(vecX dst, vecX src, immI shift) %{ predicate(n->as_Vector()->length() == 16); match(Set dst (AddVB dst (URShiftVB src (RShiftCntV shift)))); ins_cost(INSN_COST); - format %{ "usra $dst, $src, $shift\t# vector (16B)" %} + format %{ "usra $dst, $src, $shift\t# vector (16B)" %} ins_encode %{ int sh = (int)$shift$$constant; if (sh < 8) { __ usra(as_FloatRegister($dst$$reg), __ T16B, - as_FloatRegister($src$$reg), sh); + as_FloatRegister($src$$reg), sh); } %} ins_pipe(vshift128_imm); @@ -5239,12 +5462,12 @@ instruct vsrla4S_imm(vecD dst, vecD src, immI shift) %{ predicate(n->as_Vector()->length() == 4); match(Set dst (AddVS dst (URShiftVS src (RShiftCntV shift)))); ins_cost(INSN_COST); - format %{ "usra $dst, $src, $shift\t# vector (4H)" %} + format %{ "usra $dst, $src, $shift\t# vector (4H)" %} ins_encode %{ int sh = (int)$shift$$constant; if (sh < 16) { __ usra(as_FloatRegister($dst$$reg), __ T4H, - as_FloatRegister($src$$reg), sh); + as_FloatRegister($src$$reg), sh); } %} ins_pipe(vshift64_imm); @@ -5254,12 +5477,12 @@ instruct vsrla8S_imm(vecX dst, vecX src, immI shift) %{ predicate(n->as_Vector()->length() == 8); match(Set dst (AddVS dst (URShiftVS src (RShiftCntV shift)))); ins_cost(INSN_COST); - format %{ "usra $dst, $src, $shift\t# vector (8H)" %} + format %{ "usra $dst, $src, $shift\t# vector (8H)" %} ins_encode %{ int sh = (int)$shift$$constant; if (sh < 16) { __ usra(as_FloatRegister($dst$$reg), __ T8H, - as_FloatRegister($src$$reg), sh); + as_FloatRegister($src$$reg), sh); } %} ins_pipe(vshift128_imm); @@ -5269,7 +5492,7 @@ instruct vsrla2I_imm(vecD dst, vecD src, immI shift) %{ predicate(n->as_Vector()->length() == 2); match(Set dst (AddVI dst (URShiftVI src (RShiftCntV shift)))); ins_cost(INSN_COST); - format %{ "usra $dst, $src, $shift\t# vector (2S)" %} + format %{ "usra $dst, $src, $shift\t# vector (2S)" %} ins_encode %{ __ usra(as_FloatRegister($dst$$reg), __ T2S, as_FloatRegister($src$$reg), @@ -5282,7 +5505,7 @@ instruct vsrla4I_imm(vecX dst, vecX src, immI shift) %{ predicate(n->as_Vector()->length() == 4); match(Set dst (AddVI dst (URShiftVI src (RShiftCntV shift)))); ins_cost(INSN_COST); - format %{ "usra $dst, $src, $shift\t# vector (4S)" %} + format %{ "usra $dst, $src, $shift\t# vector (4S)" %} ins_encode %{ __ usra(as_FloatRegister($dst$$reg), __ T4S, as_FloatRegister($src$$reg), @@ -5295,7 +5518,7 @@ instruct vsrla2L_imm(vecX dst, vecX src, immI shift) %{ predicate(n->as_Vector()->length() == 2); match(Set dst (AddVL dst (URShiftVL src (RShiftCntV shift)))); ins_cost(INSN_COST); - format %{ "usra $dst, $src, $shift\t# vector (2D)" %} + format %{ "usra $dst, $src, $shift\t# vector (2D)" %} ins_encode %{ __ usra(as_FloatRegister($dst$$reg), __ T2D, as_FloatRegister($src$$reg), @@ -5617,3 +5840,35 @@ instruct vmask_lasttrue16B(iRegINoSp dst, vecX src) %{ %} ins_pipe(pipe_slow); %} + +instruct vmask_tolong8B(iRegLNoSp dst, vecD src) %{ + match(Set dst (VectorMaskToLong src)); + ins_cost(5 * INSN_COST); + format %{ "vmask_tolong $dst, $src\t# convert mask to long (8B)" %} + ins_encode %{ + // Input "src" is a vector of boolean represented as + // bytes with 0x00/0x01 as element values. + + __ fmovd(as_Register($dst$$reg), as_FloatRegister($src$$reg)); + __ bytemask_compress(as_Register($dst$$reg)); + %} + ins_pipe(pipe_slow); +%} + +instruct vmask_tolong16B(iRegLNoSp dst, vecX src) %{ + match(Set dst (VectorMaskToLong src)); + ins_cost(11 * INSN_COST); + format %{ "vmask_tolong $dst, $src\t# convert mask to long (16B)" %} + ins_encode %{ + // Input "src" is a vector of boolean represented as + // bytes with 0x00/0x01 as element values. + + __ umov(as_Register($dst$$reg), as_FloatRegister($src$$reg), __ D, 0); + __ umov(rscratch1, as_FloatRegister($src$$reg), __ D, 1); + __ bytemask_compress(as_Register($dst$$reg)); + __ bytemask_compress(rscratch1); + __ orr(as_Register($dst$$reg), as_Register($dst$$reg), + rscratch1, Assembler::LSL, 8); + %} + ins_pipe(pipe_slow); +%} diff --git a/src/hotspot/cpu/aarch64/aarch64_neon_ad.m4 b/src/hotspot/cpu/aarch64/aarch64_neon_ad.m4 index ded6d0fd6d2eb961c88579e204d9cf2abec4d1b1..f98ddf4ee3655f91d45b07f2227b28ed8ae214eb 100644 --- a/src/hotspot/cpu/aarch64/aarch64_neon_ad.m4 +++ b/src/hotspot/cpu/aarch64/aarch64_neon_ad.m4 @@ -1,5 +1,5 @@ -// Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. -// Copyright (c) 2020, 2021, Arm Limited. All rights reserved. +// Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. +// Copyright (c) 2020, 2022, 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 @@ -296,7 +296,7 @@ instruct vcvt2Dto2I(vecD dst, vecX src) "fcvtzdw rscratch1, $src\n\t" "fcvtzdw rscratch2, $dst\n\t" "fmovs $dst, rscratch1\n\t" - "mov $dst, T2S, 1, rscratch2\t#convert 2D to 2I vector" + "mov $dst, S, 1, rscratch2\t#convert 2D to 2I vector" %} ins_encode %{ __ ins(as_FloatRegister($dst$$reg), __ D, as_FloatRegister($src$$reg), 0, 1); @@ -305,7 +305,7 @@ instruct vcvt2Dto2I(vecD dst, vecX src) __ fcvtzdw(rscratch1, as_FloatRegister($src$$reg)); __ fcvtzdw(rscratch2, as_FloatRegister($dst$$reg)); __ fmovs(as_FloatRegister($dst$$reg), rscratch1); - __ mov(as_FloatRegister($dst$$reg), __ T2S, 1, rscratch2); + __ mov(as_FloatRegister($dst$$reg), __ S, 1, rscratch2); %} ins_pipe(pipe_slow); %} @@ -868,13 +868,13 @@ instruct insert$1$2`'(vec$3 dst, vec$3 src, iReg$4`'ORL2I($4) val, immI idx) match(Set dst (VectorInsert (Binary src val) idx)); ins_cost(INSN_COST); format %{ "orr $dst, T$5, $src, $src\n\t" - "mov $dst, T$1`'iTYPE2SIMD($2), $idx, $val\t# insert into vector($1$2)" %} + "mov $dst, iTYPE2SIMD($2), $idx, $val\t# insert into vector($1$2)" %} ins_encode %{ if (as_FloatRegister($dst$$reg) != as_FloatRegister($src$$reg)) { __ orr(as_FloatRegister($dst$$reg), __ T$5, as_FloatRegister($src$$reg), as_FloatRegister($src$$reg)); } - __ mov(as_FloatRegister($dst$$reg), __ T$1`'iTYPE2SIMD($2), $idx$$constant, $val$$Register); + __ mov(as_FloatRegister($dst$$reg), __ iTYPE2SIMD($2), $idx$$constant, $val$$Register); %} ins_pipe(pipe_slow); %}')dnl @@ -1003,11 +1003,11 @@ instruct vmul2L(vecX dst, vecX src1, vecX src2, iRegLNoSp tmp1, iRegLNoSp tmp2) __ umov($tmp1$$Register, as_FloatRegister($src1$$reg), __ D, 0); __ umov($tmp2$$Register, as_FloatRegister($src2$$reg), __ D, 0); __ mul(as_Register($tmp2$$reg), as_Register($tmp2$$reg), as_Register($tmp1$$reg)); - __ mov(as_FloatRegister($dst$$reg), __ T2D, 0, $tmp2$$Register); + __ mov(as_FloatRegister($dst$$reg), __ D, 0, $tmp2$$Register); __ umov($tmp1$$Register, as_FloatRegister($src1$$reg), __ D, 1); __ umov($tmp2$$Register, as_FloatRegister($src2$$reg), __ D, 1); __ mul(as_Register($tmp2$$reg), as_Register($tmp2$$reg), as_Register($tmp1$$reg)); - __ mov(as_FloatRegister($dst$$reg), __ T2D, 1, $tmp2$$Register); + __ mov(as_FloatRegister($dst$$reg), __ D, 1, $tmp2$$Register); %} ins_pipe(pipe_slow); %} @@ -1972,223 +1972,277 @@ VLOGICAL(xor, eor, xor, Xor, 16, B, X) // ------------------------------ Shift --------------------------------------- dnl -define(`VSHIFTCNT', ` -instruct vshiftcnt$3$4`'(vec$5 dst, iRegIorL2I cnt) %{ - predicate(UseSVE == 0 && (ifelse($3, 8, n->as_Vector()->length_in_bytes() == 4 ||` - ')n->as_Vector()->length_in_bytes() == $3)); +define(`VSLCNT', ` +instruct vslcnt$1$2`'(vec$3 dst, iRegIorL2I cnt) %{ + predicate(UseSVE == 0 && ifelse($1, 8, + (n->as_Vector()->length_in_bytes() == 4 ||` + 'n->as_Vector()->length_in_bytes() == $1), + n->as_Vector()->length_in_bytes() == $1)); match(Set dst (LShiftCntV cnt)); - match(Set dst (RShiftCntV cnt)); - format %{ "$1 $dst, $cnt\t# shift count vector ($3$4)" %} + ins_cost(INSN_COST); + format %{ "dup $dst, $cnt\t# shift count vector ($1$2)" %} ins_encode %{ - __ $2(as_FloatRegister($dst$$reg), __ T$3$4, as_Register($cnt$$reg)); + __ dup(as_FloatRegister($dst$$reg), __ T$1$2, as_Register($cnt$$reg)); %} - ins_pipe(vdup_reg_reg`'ifelse($5, D, 64, 128)); + ins_pipe(vdup_reg_reg`'ifelse($3, D, 64, 128)); %}')dnl -dnl $1 $2 $3 $4 $5 -VSHIFTCNT(dup, dup, 8, B, D) -VSHIFTCNT(dup, dup, 16, B, X) +dnl +define(`VSRCNT', ` +instruct vsrcnt$1$2`'(vec$3 dst, iRegIorL2I cnt) %{ + predicate(UseSVE == 0 && ifelse($1, 8, + (n->as_Vector()->length_in_bytes() == 4 ||` + 'n->as_Vector()->length_in_bytes() == $1), + n->as_Vector()->length_in_bytes() == $1)); + match(Set dst (RShiftCntV cnt)); + ins_cost(INSN_COST * 2); + format %{ "negw rscratch1, $cnt\t" + "dup $dst, rscratch1\t# shift count vector ($1$2)" %} + ins_encode %{ + __ negw(rscratch1, as_Register($cnt$$reg)); + __ dup(as_FloatRegister($dst$$reg), __ T$1$2, rscratch1); + %} + ins_pipe(vdup_reg_reg`'ifelse($3, D, 64, 128)); +%}')dnl +dnl + +// Vector shift count +// Note-1: Low 8 bits of each element are used, so it doesn't matter if we +// treat it as ints or bytes here. +// Note-2: Shift value is negated for RShiftCntV additionally. See the comments +// on vsra8B rule for more details. +dnl $1 $2 $3 +VSLCNT(8, B, D) +VSLCNT(16, B, X) +VSRCNT(8, B, D) +VSRCNT(16, B, X) +dnl +define(`PREDICATE', +`ifelse($1, 8B, + ifelse($3, `', `predicate(n->as_Vector()->length() == 4 || n->as_Vector()->length() == 8);', + `predicate((n->as_Vector()->length() == 4 || n->as_Vector()->length() == 8) &&` + '$3);'), + $1, 4S, + ifelse($3, `', `predicate(n->as_Vector()->length() == 2 || n->as_Vector()->length() == 4);', + `predicate((n->as_Vector()->length() == 2 || n->as_Vector()->length() == 4) &&` + '$3);'), + ifelse($3, `', `predicate(n->as_Vector()->length() == $2);', + `predicate(n->as_Vector()->length() == $2 && $3);'))')dnl dnl define(`VSLL', ` -instruct vsll$3$4`'(vec$6 dst, vec$6 src, vec$6 shift) %{ - predicate(ifelse($3$4, 8B, n->as_Vector()->length() == 4 ||` - ', - $3$4, 4S, n->as_Vector()->length() == 2 ||` - ')n->as_Vector()->length() == $3); - match(Set dst (LShiftV$4 src shift)); +instruct vsll$1$2`'(vec$4 dst, vec$4 src, vec$4 shift) %{ + PREDICATE(`$1$2', $1, ) + match(Set dst (LShiftV$2 src shift)); ins_cost(INSN_COST); - format %{ "$1 $dst,$src,$shift\t# vector ($3$5)" %} + format %{ "sshl $dst,$src,$shift\t# vector ($1$3)" %} ins_encode %{ - __ $2(as_FloatRegister($dst$$reg), __ T$3$5, + __ sshl(as_FloatRegister($dst$$reg), __ T$1$3, as_FloatRegister($src$$reg), as_FloatRegister($shift$$reg)); %} - ins_pipe(vshift`'ifelse($6, D, 64, 128)); + ins_pipe(vshift`'ifelse($4, D, 64, 128)); %}')dnl dnl define(`VSRA', ` -instruct vsra$3$4`'(vec$6 dst, vec$6 src, vec$6 shift, vec$6 tmp) %{ - predicate(ifelse($3$4, 8B, n->as_Vector()->length() == 4 ||` - ', - $3$4, 4S, n->as_Vector()->length() == 2 ||` - ')n->as_Vector()->length() == $3); - match(Set dst (RShiftV$4 src shift)); +instruct vsra$1$2`'(vec$4 dst, vec$4 src, vec$4 shift) %{ + PREDICATE(`$1$2', $1, !n->as_ShiftV()->is_var_shift()) + match(Set dst (RShiftV$2 src shift)); ins_cost(INSN_COST); - effect(TEMP tmp); - format %{ "$1 $tmp,$shift\t" - "$2 $dst,$src,$tmp\t# vector ($3$5)" %} + format %{ "sshl $dst,$src,$shift\t# vector ($1$3)" %} ins_encode %{ - __ $1(as_FloatRegister($tmp$$reg), __ T`'ifelse($6, D, 8B, 16B), + __ sshl(as_FloatRegister($dst$$reg), __ T$1$3, + as_FloatRegister($src$$reg), as_FloatRegister($shift$$reg)); - __ $2(as_FloatRegister($dst$$reg), __ T$3$5, + %} + ins_pipe(vshift`'ifelse($4, D, 64, 128)); +%}')dnl +dnl +define(`VSRA_VAR', ` +instruct vsra$1$2_var`'(vec$4 dst, vec$4 src, vec$4 shift) %{ + PREDICATE(`$1$2', $1, n->as_ShiftV()->is_var_shift()) + match(Set dst (RShiftV$2 src shift)); + ins_cost(INSN_COST * 2); + effect(TEMP_DEF dst); + format %{ "negr $dst,$shift\t" + "sshl $dst,$src,$dst\t# vector ($1$3)" %} + ins_encode %{ + __ negr(as_FloatRegister($dst$$reg), __ T`'ifelse($4, D, 8B, 16B), + as_FloatRegister($shift$$reg)); + __ sshl(as_FloatRegister($dst$$reg), __ T$1$3, as_FloatRegister($src$$reg), - as_FloatRegister($tmp$$reg)); + as_FloatRegister($dst$$reg)); %} - ins_pipe(vshift`'ifelse($6, D, 64, 128)); + ins_pipe(vshift`'ifelse($4, D, 64, 128)); %}')dnl dnl define(`VSRL', ` -instruct vsrl$3$4`'(vec$6 dst, vec$6 src, vec$6 shift, vec$6 tmp) %{ - predicate(ifelse($3$4, 8B, n->as_Vector()->length() == 4 ||` - ', - $3$4, 4S, n->as_Vector()->length() == 2 ||` - ')n->as_Vector()->length() == $3); - match(Set dst (URShiftV$4 src shift)); +instruct vsrl$1$2`'(vec$4 dst, vec$4 src, vec$4 shift) %{ + PREDICATE(`$1$2', $1, !n->as_ShiftV()->is_var_shift()) + match(Set dst (URShiftV$2 src shift)); ins_cost(INSN_COST); - effect(TEMP tmp); - format %{ "$1 $tmp,$shift\t" - "$2 $dst,$src,$tmp\t# vector ($3$5)" %} + format %{ "ushl $dst,$src,$shift\t# vector ($1$3)" %} ins_encode %{ - __ $1(as_FloatRegister($tmp$$reg), __ T`'ifelse($6, D, 8B, 16B), + __ ushl(as_FloatRegister($dst$$reg), __ T$1$3, + as_FloatRegister($src$$reg), + as_FloatRegister($shift$$reg)); + %} + ins_pipe(vshift`'ifelse($4, D, 64, 128)); +%}')dnl +dnl +define(`VSRL_VAR', ` +instruct vsrl$1$2_var`'(vec$4 dst, vec$4 src, vec$4 shift) %{ + PREDICATE(`$1$2', $1, n->as_ShiftV()->is_var_shift()) + match(Set dst (URShiftV$2 src shift)); + ins_cost(INSN_COST * 2); + effect(TEMP_DEF dst); + format %{ "negr $dst,$shift\t" + "ushl $dst,$src,$dst\t# vector ($1$3)" %} + ins_encode %{ + __ negr(as_FloatRegister($dst$$reg), __ T`'ifelse($4, D, 8B, 16B), as_FloatRegister($shift$$reg)); - __ $2(as_FloatRegister($dst$$reg), __ T$3$5, + __ ushl(as_FloatRegister($dst$$reg), __ T$1$3, as_FloatRegister($src$$reg), - as_FloatRegister($tmp$$reg)); + as_FloatRegister($dst$$reg)); %} - ins_pipe(vshift`'ifelse($6, D, 64, 128)); + ins_pipe(vshift`'ifelse($4, D, 64, 128)); %}')dnl dnl define(`VSLL_IMM', ` -instruct vsll$3$4_imm`'(vec$6 dst, vec$6 src, immI shift) %{ - predicate(ifelse($3$4, 8B, n->as_Vector()->length() == 4 ||` - ', - $3$4, 4S, n->as_Vector()->length() == 2 ||` - ')n->as_Vector()->length() == $3); - match(Set dst (LShiftV$4 src (LShiftCntV shift))); - ins_cost(INSN_COST); - format %{ "$1 $dst, $src, $shift\t# vector ($3$5)" %} - ins_encode %{ifelse($4, B,` +instruct vsll$1$2_imm`'(vec$4 dst, vec$4 src, immI shift) %{ + PREDICATE(`$1$2', $1, assert_not_var_shift(n)) + match(Set dst (LShiftV$2 src (LShiftCntV shift))); + ins_cost(INSN_COST); + format %{ "shl $dst, $src, $shift\t# vector ($1$3)" %} + ins_encode %{ifelse($2, B,` int sh = (int)$shift$$constant; if (sh >= 8) { - __ eor(as_FloatRegister($dst$$reg), __ ifelse($6, D, T8B, T16B), + __ eor(as_FloatRegister($dst$$reg), __ ifelse($4, D, T8B, T16B), as_FloatRegister($src$$reg), as_FloatRegister($src$$reg)); } else { - __ $2(as_FloatRegister($dst$$reg), __ T$3$5, + __ shl(as_FloatRegister($dst$$reg), __ T$1$3, as_FloatRegister($src$$reg), sh); - }', $4, S,` + }', $2, S,` int sh = (int)$shift$$constant; if (sh >= 16) { - __ eor(as_FloatRegister($dst$$reg), __ ifelse($6, D, T8B, T16B), + __ eor(as_FloatRegister($dst$$reg), __ ifelse($4, D, T8B, T16B), as_FloatRegister($src$$reg), as_FloatRegister($src$$reg)); } else { - __ $2(as_FloatRegister($dst$$reg), __ T$3$5, + __ shl(as_FloatRegister($dst$$reg), __ T$1$3, as_FloatRegister($src$$reg), sh); }', ` - __ $2(as_FloatRegister($dst$$reg), __ T$3$5, + __ shl(as_FloatRegister($dst$$reg), __ T$1$3, as_FloatRegister($src$$reg), (int)$shift$$constant);') %} - ins_pipe(vshift`'ifelse($6, D, 64, 128)_imm); + ins_pipe(vshift`'ifelse($4, D, 64, 128)_imm); %}')dnl +dnl define(`VSRA_IMM', ` -instruct vsra$3$4_imm`'(vec$6 dst, vec$6 src, immI shift) %{ - predicate(ifelse($3$4, 8B, n->as_Vector()->length() == 4 ||` - ', - $3$4, 4S, n->as_Vector()->length() == 2 ||` - ')n->as_Vector()->length() == $3); - match(Set dst (RShiftV$4 src (RShiftCntV shift))); - ins_cost(INSN_COST); - format %{ "$1 $dst, $src, $shift\t# vector ($3$5)" %} - ins_encode %{ifelse($4, B,` +instruct vsra$1$2_imm`'(vec$4 dst, vec$4 src, immI shift) %{ + PREDICATE(`$1$2', $1, assert_not_var_shift(n)) + match(Set dst (RShiftV$2 src (RShiftCntV shift))); + ins_cost(INSN_COST); + format %{ "sshr $dst, $src, $shift\t# vector ($1$3)" %} + ins_encode %{ifelse($2, B,` int sh = (int)$shift$$constant; if (sh >= 8) sh = 7; - __ $2(as_FloatRegister($dst$$reg), __ T$3$5, - as_FloatRegister($src$$reg), sh);', $4, S,` + __ sshr(as_FloatRegister($dst$$reg), __ T$1$3, + as_FloatRegister($src$$reg), sh);', $2, S,` int sh = (int)$shift$$constant; if (sh >= 16) sh = 15; - __ $2(as_FloatRegister($dst$$reg), __ T$3$5, - as_FloatRegister($src$$reg), sh);', ` - __ $2(as_FloatRegister($dst$$reg), __ T$3$5, + __ sshr(as_FloatRegister($dst$$reg), __ T$1$3, + as_FloatRegister($src$$reg), sh);', ` + __ sshr(as_FloatRegister($dst$$reg), __ T$1$3, as_FloatRegister($src$$reg), (int)$shift$$constant);') %} - ins_pipe(vshift`'ifelse($6, D, 64, 128)_imm); + ins_pipe(vshift`'ifelse($4, D, 64, 128)_imm); %}')dnl dnl define(`VSRL_IMM', ` -instruct vsrl$3$4_imm`'(vec$6 dst, vec$6 src, immI shift) %{ - predicate(ifelse($3$4, 8B, n->as_Vector()->length() == 4 ||` - ', - $3$4, 4S, n->as_Vector()->length() == 2 ||` - ')n->as_Vector()->length() == $3); - match(Set dst (URShiftV$4 src (RShiftCntV shift))); - ins_cost(INSN_COST); - format %{ "$1 $dst, $src, $shift\t# vector ($3$5)" %} - ins_encode %{ifelse($4, B,` +instruct vsrl$1$2_imm`'(vec$4 dst, vec$4 src, immI shift) %{ + PREDICATE(`$1$2', $1, assert_not_var_shift(n)) + match(Set dst (URShiftV$2 src (RShiftCntV shift))); + ins_cost(INSN_COST); + format %{ "ushr $dst, $src, $shift\t# vector ($1$3)" %} + ins_encode %{ifelse($2, B,` int sh = (int)$shift$$constant; if (sh >= 8) { - __ eor(as_FloatRegister($dst$$reg), __ ifelse($6, D, T8B, T16B), + __ eor(as_FloatRegister($dst$$reg), __ ifelse($4, D, T8B, T16B), as_FloatRegister($src$$reg), as_FloatRegister($src$$reg)); } else { - __ $2(as_FloatRegister($dst$$reg), __ T$3$5, - as_FloatRegister($src$$reg), sh); - }', $4, S,` + __ ushr(as_FloatRegister($dst$$reg), __ T$1$3, + as_FloatRegister($src$$reg), sh); + }', $2, S,` int sh = (int)$shift$$constant; if (sh >= 16) { - __ eor(as_FloatRegister($dst$$reg), __ ifelse($6, D, T8B, T16B), + __ eor(as_FloatRegister($dst$$reg), __ ifelse($4, D, T8B, T16B), as_FloatRegister($src$$reg), as_FloatRegister($src$$reg)); } else { - __ $2(as_FloatRegister($dst$$reg), __ T$3$5, - as_FloatRegister($src$$reg), sh); + __ ushr(as_FloatRegister($dst$$reg), __ T$1$3, + as_FloatRegister($src$$reg), sh); }', ` - __ $2(as_FloatRegister($dst$$reg), __ T$3$5, + __ ushr(as_FloatRegister($dst$$reg), __ T$1$3, as_FloatRegister($src$$reg), (int)$shift$$constant);') %} - ins_pipe(vshift`'ifelse($6, D, 64, 128)_imm); + ins_pipe(vshift`'ifelse($4, D, 64, 128)_imm); %}')dnl dnl define(`VSRLA_IMM', ` -instruct vsrla$3$4_imm`'(vec$6 dst, vec$6 src, immI shift) %{ - predicate(n->as_Vector()->length() == $3); - match(Set dst (AddV$4 dst (URShiftV$4 src (RShiftCntV shift)))); +instruct vsrla$1$2_imm`'(vec$4 dst, vec$4 src, immI shift) %{ + predicate(n->as_Vector()->length() == $1); + match(Set dst (AddV$2 dst (URShiftV$2 src (RShiftCntV shift)))); ins_cost(INSN_COST); - format %{ "$1 $dst, $src, $shift\t# vector ($3$5)" %} - ins_encode %{ifelse($4, B,` + format %{ "usra $dst, $src, $shift\t# vector ($1$3)" %} + ins_encode %{ifelse($2, B,` int sh = (int)$shift$$constant; if (sh < 8) { - __ $2(as_FloatRegister($dst$$reg), __ T$3$5, - as_FloatRegister($src$$reg), sh); - }', $4, S,` + __ usra(as_FloatRegister($dst$$reg), __ T$1$3, + as_FloatRegister($src$$reg), sh); + }', $2, S,` int sh = (int)$shift$$constant; if (sh < 16) { - __ $2(as_FloatRegister($dst$$reg), __ T$3$5, - as_FloatRegister($src$$reg), sh); + __ usra(as_FloatRegister($dst$$reg), __ T$1$3, + as_FloatRegister($src$$reg), sh); }', ` - __ $2(as_FloatRegister($dst$$reg), __ T$3$5, + __ usra(as_FloatRegister($dst$$reg), __ T$1$3, as_FloatRegister($src$$reg), (int)$shift$$constant);') %} - ins_pipe(vshift`'ifelse($6, D, 64, 128)_imm); + ins_pipe(vshift`'ifelse($4, D, 64, 128)_imm); %}')dnl dnl define(`VSRAA_IMM', ` -instruct vsraa$3$4_imm`'(vec$6 dst, vec$6 src, immI shift) %{ - predicate(n->as_Vector()->length() == $3); - match(Set dst (AddV$4 dst (RShiftV$4 src (RShiftCntV shift)))); +instruct vsraa$1$2_imm`'(vec$4 dst, vec$4 src, immI shift) %{ + predicate(n->as_Vector()->length() == $1); + match(Set dst (AddV$2 dst (RShiftV$2 src (RShiftCntV shift)))); ins_cost(INSN_COST); - format %{ "$1 $dst, $src, $shift\t# vector ($3$5)" %} - ins_encode %{ifelse($4, B,` + format %{ "ssra $dst, $src, $shift\t# vector ($1$3)" %} + ins_encode %{ifelse($2, B,` int sh = (int)$shift$$constant; if (sh >= 8) sh = 7; - __ $2(as_FloatRegister($dst$$reg), __ T$3$5, - as_FloatRegister($src$$reg), sh);', $4, S,` + __ ssra(as_FloatRegister($dst$$reg), __ T$1$3, + as_FloatRegister($src$$reg), sh);', $2, S,` int sh = (int)$shift$$constant; if (sh >= 16) sh = 15; - __ $2(as_FloatRegister($dst$$reg), __ T$3$5, - as_FloatRegister($src$$reg), sh);', ` - __ $2(as_FloatRegister($dst$$reg), __ T$3$5, + __ ssra(as_FloatRegister($dst$$reg), __ T$1$3, + as_FloatRegister($src$$reg), sh);', ` + __ ssra(as_FloatRegister($dst$$reg), __ T$1$3, as_FloatRegister($src$$reg), (int)$shift$$constant);') %} - ins_pipe(vshift`'ifelse($6, D, 64, 128)_imm); + ins_pipe(vshift`'ifelse($4, D, 64, 128)_imm); %}')dnl -dnl $1 $2 $3 $4 $5 $6 -VSLL(sshl, sshl, 8, B, B, D) -VSLL(sshl, sshl, 16, B, B, X) +dnl +undefine(PREDICATE)dnl +dnl +dnl $1 $2 $3 $4 +VSLL(8, B, B, D) +VSLL(16, B, B, X) // Right shifts with vector shift count on aarch64 SIMD are implemented // as left shift by negative shift count. @@ -2199,8 +2253,6 @@ VSLL(sshl, sshl, 16, B, B, X) // LoadVector RShiftCntV // | / // RShiftVI -// Note: In inner loop, multiple neg instructions are used, which can be -// moved to outer loop and merge into one neg instruction. // // Case 2: The vector shift count is from loading. // This case isn't supported by middle-end now. But it's supported by @@ -2210,61 +2262,83 @@ VSLL(sshl, sshl, 16, B, B, X) // | / // RShiftVI // -dnl $1 $2 $3 $4 $5 $6 -VSRA(negr, sshl, 8, B, B, D) -VSRA(negr, sshl, 16, B, B, X) -VSRL(negr, ushl, 8, B, B, D) -VSRL(negr, ushl, 16, B, B, X) -VSLL_IMM(shl, shl, 8, B, B, D) -VSLL_IMM(shl, shl, 16, B, B, X) -VSRA_IMM(sshr, sshr, 8, B, B, D) -VSRA_IMM(sshr, sshr, 16, B, B, X) -VSRL_IMM(ushr, ushr, 8, B, B, D) -VSRL_IMM(ushr, ushr, 16, B, B, X) -VSLL(sshl, sshl, 4, S, H, D) -VSLL(sshl, sshl, 8, S, H, X) -VSRA(negr, sshl, 4, S, H, D) -VSRA(negr, sshl, 8, S, H, X) -VSRL(negr, ushl, 4, S, H, D) -VSRL(negr, ushl, 8, S, H, X) -VSLL_IMM(shl, shl, 4, S, H, D) -VSLL_IMM(shl, shl, 8, S, H, X) -VSRA_IMM(sshr, sshr, 4, S, H, D) -VSRA_IMM(sshr, sshr, 8, S, H, X) -VSRL_IMM(ushr, ushr, 4, S, H, D) -VSRL_IMM(ushr, ushr, 8, S, H, X) -VSLL(sshl, sshl, 2, I, S, D) -VSLL(sshl, sshl, 4, I, S, X) -VSRA(negr, sshl, 2, I, S, D) -VSRA(negr, sshl, 4, I, S, X) -VSRL(negr, ushl, 2, I, S, D) -VSRL(negr, ushl, 4, I, S, X) -VSLL_IMM(shl, shl, 2, I, S, D) -VSLL_IMM(shl, shl, 4, I, S, X) -VSRA_IMM(sshr, sshr, 2, I, S, D) -VSRA_IMM(sshr, sshr, 4, I, S, X) -VSRL_IMM(ushr, ushr, 2, I, S, D) -VSRL_IMM(ushr, ushr, 4, I, S, X) -VSLL(sshl, sshl, 2, L, D, X) -VSRA(negr, sshl, 2, L, D, X) -VSRL(negr, ushl, 2, L, D, X) -VSLL_IMM(shl, shl, 2, L, D, X) -VSRA_IMM(sshr, sshr, 2, L, D, X) -VSRL_IMM(ushr, ushr, 2, L, D, X) -VSRAA_IMM(ssra, ssra, 8, B, B, D) -VSRAA_IMM(ssra, ssra, 16, B, B, X) -VSRAA_IMM(ssra, ssra, 4, S, H, D) -VSRAA_IMM(ssra, ssra, 8, S, H, X) -VSRAA_IMM(ssra, ssra, 2, I, S, D) -VSRAA_IMM(ssra, ssra, 4, I, S, X) -VSRAA_IMM(ssra, ssra, 2, L, D, X) -VSRLA_IMM(usra, usra, 8, B, B, D) -VSRLA_IMM(usra, usra, 16, B, B, X) -VSRLA_IMM(usra, usra, 4, S, H, D) -VSRLA_IMM(usra, usra, 8, S, H, X) -VSRLA_IMM(usra, usra, 2, I, S, D) -VSRLA_IMM(usra, usra, 4, I, S, X) -VSRLA_IMM(usra, usra, 2, L, D, X) +// The negate is conducted in RShiftCntV rule for case 1, whereas it's done in +// RShiftV* rules for case 2. Because there exists an optimization opportunity +// for case 1, that is, multiple neg instructions in inner loop can be hoisted +// to outer loop and merged into one neg instruction. +// +// Note that ShiftVNode::is_var_shift() indicates whether the vector shift +// count is a variable vector(case 2) or not(a vector generated by RShiftCntV, +// i.e. case 1). +dnl $1 $2 $3 $4 +VSRA(8, B, B, D) +VSRA_VAR(8, B, B, D) +VSRA(16, B, B, X) +VSRA_VAR(16, B, B, X) +VSRL(8, B, B, D) +VSRL_VAR(8, B, B, D) +VSRL(16, B, B, X) +VSRL_VAR(16, B, B, X) +VSLL_IMM(8, B, B, D) +VSLL_IMM(16, B, B, X) +VSRA_IMM(8, B, B, D) +VSRA_IMM(16, B, B, X) +VSRL_IMM(8, B, B, D) +VSRL_IMM(16, B, B, X) +VSLL(4, S, H, D) +VSLL(8, S, H, X) +VSRA(4, S, H, D) +VSRA_VAR(4, S, H, D) +VSRA(8, S, H, X) +VSRA_VAR(8, S, H, X) +VSRL(4, S, H, D) +VSRL_VAR(4, S, H, D) +VSRL(8, S, H, X) +VSRL_VAR(8, S, H, X) +VSLL_IMM(4, S, H, D) +VSLL_IMM(8, S, H, X) +VSRA_IMM(4, S, H, D) +VSRA_IMM(8, S, H, X) +VSRL_IMM(4, S, H, D) +VSRL_IMM(8, S, H, X) +VSLL(2, I, S, D) +VSLL(4, I, S, X) +VSRA(2, I, S, D) +VSRA_VAR(2, I, S, D) +VSRA(4, I, S, X) +VSRA_VAR(4, I, S, X) +VSRL(2, I, S, D) +VSRL_VAR(2, I, S, D) +VSRL(4, I, S, X) +VSRL_VAR(4, I, S, X) +VSLL_IMM(2, I, S, D) +VSLL_IMM(4, I, S, X) +VSRA_IMM(2, I, S, D) +VSRA_IMM(4, I, S, X) +VSRL_IMM(2, I, S, D) +VSRL_IMM(4, I, S, X) +VSLL(2, L, D, X) +VSRA(2, L, D, X) +VSRA_VAR(2, L, D, X) +VSRL(2, L, D, X) +VSRL_VAR(2, L, D, X) +VSLL_IMM(2, L, D, X) +VSRA_IMM(2, L, D, X) +VSRL_IMM(2, L, D, X) +VSRAA_IMM(8, B, B, D) +VSRAA_IMM(16, B, B, X) +VSRAA_IMM(4, S, H, D) +VSRAA_IMM(8, S, H, X) +VSRAA_IMM(2, I, S, D) +VSRAA_IMM(4, I, S, X) +VSRAA_IMM(2, L, D, X) +VSRLA_IMM(8, B, B, D) +VSRLA_IMM(16, B, B, X) +VSRLA_IMM(4, S, H, D) +VSRLA_IMM(8, S, H, X) +VSRLA_IMM(2, I, S, D) +VSRLA_IMM(4, I, S, X) +VSRLA_IMM(2, L, D, X) dnl define(`VMINMAX', ` instruct v$1$3`'ifelse($5, S, F, D)`'(vec$6 dst, vec$6 src1, vec$6 src2) @@ -2481,3 +2555,35 @@ instruct vmask_lasttrue16B(iRegINoSp dst, vecX src) %{ %} ins_pipe(pipe_slow); %} + +instruct vmask_tolong8B(iRegLNoSp dst, vecD src) %{ + match(Set dst (VectorMaskToLong src)); + ins_cost(5 * INSN_COST); + format %{ "vmask_tolong $dst, $src\t# convert mask to long (8B)" %} + ins_encode %{ + // Input "src" is a vector of boolean represented as + // bytes with 0x00/0x01 as element values. + + __ fmovd(as_Register($dst$$reg), as_FloatRegister($src$$reg)); + __ bytemask_compress(as_Register($dst$$reg)); + %} + ins_pipe(pipe_slow); +%} + +instruct vmask_tolong16B(iRegLNoSp dst, vecX src) %{ + match(Set dst (VectorMaskToLong src)); + ins_cost(11 * INSN_COST); + format %{ "vmask_tolong $dst, $src\t# convert mask to long (16B)" %} + ins_encode %{ + // Input "src" is a vector of boolean represented as + // bytes with 0x00/0x01 as element values. + + __ umov(as_Register($dst$$reg), as_FloatRegister($src$$reg), __ D, 0); + __ umov(rscratch1, as_FloatRegister($src$$reg), __ D, 1); + __ bytemask_compress(as_Register($dst$$reg)); + __ bytemask_compress(rscratch1); + __ orr(as_Register($dst$$reg), as_Register($dst$$reg), + rscratch1, Assembler::LSL, 8); + %} + ins_pipe(pipe_slow); +%} diff --git a/src/hotspot/cpu/aarch64/aarch64_sve.ad b/src/hotspot/cpu/aarch64/aarch64_sve.ad index 78c09b65708b2abdce8771fb1626e4ec2ae5264b..c048a463c1a4ffeded90e57911c23ffecaeab080 100644 --- a/src/hotspot/cpu/aarch64/aarch64_sve.ad +++ b/src/hotspot/cpu/aarch64/aarch64_sve.ad @@ -1,6 +1,6 @@ // -// Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. -// Copyright (c) 2020, 2021, Arm Limited. All rights reserved. +// Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. +// Copyright (c) 2020, 2022, 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 @@ -411,13 +411,13 @@ instruct storeV_masked_partial(vReg src, vmemA mem, pRegGov pg, pRegGov pgtmp, r ins_pipe(pipe_slow); %} -// maskAll +// maskAll (full or partial predicate size) instruct vmaskAll_immI(pRegGov dst, immI src) %{ predicate(UseSVE > 0); match(Set dst (MaskAll src)); ins_cost(SVE_COST); - format %{ "sve_ptrue/sve_pfalse $dst\t# mask all (sve) (B/H/S)" %} + format %{ "sve_ptrue_lanecnt/sve_pfalse $dst\t# mask all (sve) (B/H/S)" %} ins_encode %{ int con = (int)$src$$constant; if (con == 0) { @@ -425,7 +425,8 @@ instruct vmaskAll_immI(pRegGov dst, immI src) %{ } else { assert(con == -1, "invalid constant value for mask"); BasicType bt = Matcher::vector_element_basic_type(this); - __ sve_ptrue(as_PRegister($dst$$reg), __ elemType_to_regVariant(bt)); + __ sve_ptrue_lanecnt(as_PRegister($dst$$reg), __ elemType_to_regVariant(bt), + Matcher::vector_length(this)); } %} ins_pipe(pipe_slow); @@ -435,14 +436,22 @@ instruct vmaskAllI(pRegGov dst, iRegIorL2I src, vReg tmp, rFlagsReg cr) %{ predicate(UseSVE > 0); match(Set dst (MaskAll src)); effect(TEMP tmp, KILL cr); - ins_cost(2 * SVE_COST); + ins_cost(3 * SVE_COST); format %{ "sve_dup $tmp, $src\n\t" - "sve_cmpne $dst, $tmp, 0\t# mask all (sve) (B/H/S)" %} + "sve_ptrue_lanecnt $dst\n\t" + "sve_cmpne $dst, $dst, $tmp, 0\t# mask all (sve) (B/H/S)" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); Assembler::SIMD_RegVariant size = __ elemType_to_regVariant(bt); + uint length_in_bytes = Matcher::vector_length_in_bytes(this); __ sve_dup(as_FloatRegister($tmp$$reg), size, as_Register($src$$reg)); - __ sve_cmp(Assembler::NE, as_PRegister($dst$$reg), size, ptrue, as_FloatRegister($tmp$$reg), 0); + if (length_in_bytes < MaxVectorSize) { + __ sve_ptrue_lanecnt(as_PRegister($dst$$reg), size, Matcher::vector_length(this)); + __ sve_cmp(Assembler::NE, as_PRegister($dst$$reg), size, + as_PRegister($dst$$reg), as_FloatRegister($tmp$$reg), 0); + } else { + __ sve_cmp(Assembler::NE, as_PRegister($dst$$reg), size, ptrue, as_FloatRegister($tmp$$reg), 0); + } %} ins_pipe(pipe_slow); %} @@ -451,7 +460,7 @@ instruct vmaskAll_immL(pRegGov dst, immL src) %{ predicate(UseSVE > 0); match(Set dst (MaskAll src)); ins_cost(SVE_COST); - format %{ "sve_ptrue/sve_pfalse $dst\t# mask all (sve) (D)" %} + format %{ "sve_ptrue_lanecnt/sve_pfalse $dst\t# mask all (sve) (D)" %} ins_encode %{ long con = (long)$src$$constant; if (con == 0) { @@ -459,7 +468,8 @@ instruct vmaskAll_immL(pRegGov dst, immL src) %{ } else { assert(con == -1, "invalid constant value for mask"); BasicType bt = Matcher::vector_element_basic_type(this); - __ sve_ptrue(as_PRegister($dst$$reg), __ elemType_to_regVariant(bt)); + __ sve_ptrue_lanecnt(as_PRegister($dst$$reg), __ elemType_to_regVariant(bt), + Matcher::vector_length(this)); } %} ins_pipe(pipe_slow); @@ -469,14 +479,22 @@ instruct vmaskAllL(pRegGov dst, iRegL src, vReg tmp, rFlagsReg cr) %{ predicate(UseSVE > 0); match(Set dst (MaskAll src)); effect(TEMP tmp, KILL cr); - ins_cost(2 * SVE_COST); + ins_cost(3 * SVE_COST); format %{ "sve_dup $tmp, $src\n\t" - "sve_cmpne $dst, $tmp, 0\t# mask all (sve) (D)" %} + "sve_ptrue_lanecnt $dst\n\t" + "sve_cmpne $dst, $dst, $tmp, 0\t# mask all (sve) (D)" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); Assembler::SIMD_RegVariant size = __ elemType_to_regVariant(bt); + uint length_in_bytes = Matcher::vector_length_in_bytes(this); __ sve_dup(as_FloatRegister($tmp$$reg), size, as_Register($src$$reg)); - __ sve_cmp(Assembler::NE, as_PRegister($dst$$reg), size, ptrue, as_FloatRegister($tmp$$reg), 0); + if (length_in_bytes < MaxVectorSize) { + __ sve_ptrue_lanecnt(as_PRegister($dst$$reg), size, Matcher::vector_length(this)); + __ sve_cmp(Assembler::NE, as_PRegister($dst$$reg), size, + as_PRegister($dst$$reg), as_FloatRegister($tmp$$reg), 0); + } else { + __ sve_cmp(Assembler::NE, as_PRegister($dst$$reg), size, ptrue, as_FloatRegister($tmp$$reg), 0); + } %} ins_pipe(pipe_slow); %} @@ -935,6 +953,217 @@ instruct vaddD_masked(vReg dst_src1, vReg src2, pRegGov pg) %{ ins_pipe(pipe_slow); %} +// vector add reg imm (unpredicated) + +instruct vaddImmB(vReg dst_src, immBAddSubV con) %{ + predicate(UseSVE > 0); + match(Set dst_src (AddVB dst_src (ReplicateB con))); + ins_cost(SVE_COST); + format %{ "sve_add $dst_src, $dst_src, $con\t # vector (sve) (B)" %} + ins_encode %{ + int32_t val = $con$$constant; + if (val > 0){ + __ sve_add(as_FloatRegister($dst_src$$reg), __ B, val); + } else if (val < 0){ + __ sve_sub(as_FloatRegister($dst_src$$reg), __ B, -val); + } + %} + ins_pipe(pipe_slow); +%} + +instruct vaddImmS(vReg dst_src, immIAddSubV con) %{ + predicate(UseSVE > 0); + match(Set dst_src (AddVS dst_src (ReplicateS con))); + ins_cost(SVE_COST); + format %{ "sve_add $dst_src, $dst_src, $con\t # vector (sve) (H)" %} + ins_encode %{ + int32_t val = $con$$constant; + if (val > 0){ + __ sve_add(as_FloatRegister($dst_src$$reg), __ H, val); + } else if (val < 0){ + __ sve_sub(as_FloatRegister($dst_src$$reg), __ H, -val); + } + %} + ins_pipe(pipe_slow); +%} + +instruct vaddImmI(vReg dst_src, immIAddSubV con) %{ + predicate(UseSVE > 0); + match(Set dst_src (AddVI dst_src (ReplicateI con))); + ins_cost(SVE_COST); + format %{ "sve_add $dst_src, $dst_src, $con\t # vector (sve) (S)" %} + ins_encode %{ + int32_t val = $con$$constant; + if (val > 0){ + __ sve_add(as_FloatRegister($dst_src$$reg), __ S, val); + } else if (val < 0){ + __ sve_sub(as_FloatRegister($dst_src$$reg), __ S, -val); + } + %} + ins_pipe(pipe_slow); +%} + +instruct vaddImmL(vReg dst_src, immLAddSubV con) %{ + predicate(UseSVE > 0); + match(Set dst_src (AddVL dst_src (ReplicateL con))); + ins_cost(SVE_COST); + format %{ "sve_add $dst_src, $dst_src, $con\t # vector (sve) (D)" %} + ins_encode %{ + int32_t val = $con$$constant; + if (val > 0){ + __ sve_add(as_FloatRegister($dst_src$$reg), __ D, val); + } else if (val < 0){ + __ sve_sub(as_FloatRegister($dst_src$$reg), __ D, -val); + } + %} + ins_pipe(pipe_slow); +%} + +// vector binary op reg imm (unpredicated) + +instruct vandB(vReg dst_src, immBLog con) %{ + predicate(UseSVE > 0); + match(Set dst_src (AndV dst_src (ReplicateB con))); + ins_cost(SVE_COST); + format %{ "sve_and $dst_src, $dst_src, $con\t # vector (sve) (B)" %} + ins_encode %{ + __ sve_and(as_FloatRegister($dst_src$$reg), __ B, + (uint64_t)($con$$constant)); + %} + ins_pipe(pipe_slow); +%} + +instruct vandH(vReg dst_src, immSLog con) %{ + predicate(UseSVE > 0); + match(Set dst_src (AndV dst_src (ReplicateS con))); + ins_cost(SVE_COST); + format %{ "sve_and $dst_src, $dst_src, $con\t # vector (sve) (H)" %} + ins_encode %{ + __ sve_and(as_FloatRegister($dst_src$$reg), __ H, + (uint64_t)($con$$constant)); + %} + ins_pipe(pipe_slow); +%} + +instruct vandS(vReg dst_src, immILog con) %{ + predicate(UseSVE > 0); + match(Set dst_src (AndV dst_src (ReplicateI con))); + ins_cost(SVE_COST); + format %{ "sve_and $dst_src, $dst_src, $con\t # vector (sve) (S)" %} + ins_encode %{ + __ sve_and(as_FloatRegister($dst_src$$reg), __ S, + (uint64_t)($con$$constant)); + %} + ins_pipe(pipe_slow); +%} + +instruct vandD(vReg dst_src, immLLog con) %{ + predicate(UseSVE > 0); + match(Set dst_src (AndV dst_src (ReplicateL con))); + ins_cost(SVE_COST); + format %{ "sve_and $dst_src, $dst_src, $con\t # vector (sve) (D)" %} + ins_encode %{ + __ sve_and(as_FloatRegister($dst_src$$reg), __ D, + (uint64_t)($con$$constant)); + %} + ins_pipe(pipe_slow); +%} + +instruct vorB(vReg dst_src, immBLog con) %{ + predicate(UseSVE > 0); + match(Set dst_src (OrV dst_src (ReplicateB con))); + ins_cost(SVE_COST); + format %{ "sve_orr $dst_src, $dst_src, $con\t # vector (sve) (B)" %} + ins_encode %{ + __ sve_orr(as_FloatRegister($dst_src$$reg), __ B, + (uint64_t)($con$$constant)); + %} + ins_pipe(pipe_slow); +%} + +instruct vorH(vReg dst_src, immSLog con) %{ + predicate(UseSVE > 0); + match(Set dst_src (OrV dst_src (ReplicateS con))); + ins_cost(SVE_COST); + format %{ "sve_orr $dst_src, $dst_src, $con\t # vector (sve) (H)" %} + ins_encode %{ + __ sve_orr(as_FloatRegister($dst_src$$reg), __ H, + (uint64_t)($con$$constant)); + %} + ins_pipe(pipe_slow); +%} + +instruct vorS(vReg dst_src, immILog con) %{ + predicate(UseSVE > 0); + match(Set dst_src (OrV dst_src (ReplicateI con))); + ins_cost(SVE_COST); + format %{ "sve_orr $dst_src, $dst_src, $con\t # vector (sve) (S)" %} + ins_encode %{ + __ sve_orr(as_FloatRegister($dst_src$$reg), __ S, + (uint64_t)($con$$constant)); + %} + ins_pipe(pipe_slow); +%} + +instruct vorD(vReg dst_src, immLLog con) %{ + predicate(UseSVE > 0); + match(Set dst_src (OrV dst_src (ReplicateL con))); + ins_cost(SVE_COST); + format %{ "sve_orr $dst_src, $dst_src, $con\t # vector (sve) (D)" %} + ins_encode %{ + __ sve_orr(as_FloatRegister($dst_src$$reg), __ D, + (uint64_t)($con$$constant)); + %} + ins_pipe(pipe_slow); +%} + +instruct vxorB(vReg dst_src, immBLog con) %{ + predicate(UseSVE > 0); + match(Set dst_src (XorV dst_src (ReplicateB con))); + ins_cost(SVE_COST); + format %{ "sve_eor $dst_src, $dst_src, $con\t # vector (sve) (B)" %} + ins_encode %{ + __ sve_eor(as_FloatRegister($dst_src$$reg), __ B, + (uint64_t)($con$$constant)); + %} + ins_pipe(pipe_slow); +%} + +instruct vxorH(vReg dst_src, immSLog con) %{ + predicate(UseSVE > 0); + match(Set dst_src (XorV dst_src (ReplicateS con))); + ins_cost(SVE_COST); + format %{ "sve_eor $dst_src, $dst_src, $con\t # vector (sve) (H)" %} + ins_encode %{ + __ sve_eor(as_FloatRegister($dst_src$$reg), __ H, + (uint64_t)($con$$constant)); + %} + ins_pipe(pipe_slow); +%} + +instruct vxorS(vReg dst_src, immILog con) %{ + predicate(UseSVE > 0); + match(Set dst_src (XorV dst_src (ReplicateI con))); + ins_cost(SVE_COST); + format %{ "sve_eor $dst_src, $dst_src, $con\t # vector (sve) (S)" %} + ins_encode %{ + __ sve_eor(as_FloatRegister($dst_src$$reg), __ S, + (uint64_t)($con$$constant)); + %} + ins_pipe(pipe_slow); +%} + +instruct vxorD(vReg dst_src, immLLog con) %{ + predicate(UseSVE > 0); + match(Set dst_src (XorV dst_src (ReplicateL con))); + ins_cost(SVE_COST); + format %{ "sve_eor $dst_src, $dst_src, $con\t # vector (sve) (D)" %} + ins_encode %{ + __ sve_eor(as_FloatRegister($dst_src$$reg), __ D, + (uint64_t)($con$$constant)); + %} + ins_pipe(pipe_slow); +%} // vector and instruct vand(vReg dst, vReg src1, vReg src2) %{ @@ -1059,6 +1288,36 @@ instruct vnotL(vReg dst, vReg src, immL_M1 m1) %{ ins_pipe(pipe_slow); %} +// vector not - predicated + +instruct vnotI_masked(vReg dst, vReg src, immI_M1 m1, pRegGov pg) %{ + predicate(UseSVE > 0); + match(Set dst (XorV (Binary src (ReplicateB m1)) pg)); + match(Set dst (XorV (Binary src (ReplicateS m1)) pg)); + match(Set dst (XorV (Binary src (ReplicateI m1)) pg)); + ins_cost(SVE_COST); + format %{ "sve_not $dst, $pg, $src\t# vector (sve) B/H/S" %} + ins_encode %{ + BasicType bt = Matcher::vector_element_basic_type(this); + __ sve_not(as_FloatRegister($dst$$reg), __ elemType_to_regVariant(bt), + as_PRegister($pg$$reg), as_FloatRegister($src$$reg)); + %} + ins_pipe(pipe_slow); +%} + +instruct vnotL_masked(vReg dst, vReg src, immL_M1 m1, pRegGov pg) %{ + predicate(UseSVE > 0); + match(Set dst (XorV (Binary src (ReplicateL m1)) pg)); + ins_cost(SVE_COST); + format %{ "sve_not $dst, $pg, $src\t# vector (sve) D" %} + ins_encode %{ + BasicType bt = Matcher::vector_element_basic_type(this); + __ sve_not(as_FloatRegister($dst$$reg), __ elemType_to_regVariant(bt), + as_PRegister($pg$$reg), as_FloatRegister($src$$reg)); + %} + ins_pipe(pipe_slow); +%} + // vector and_not instruct vand_notI(vReg dst, vReg src1, vReg src2, immI_M1 m1) %{ @@ -1089,6 +1348,36 @@ instruct vand_notL(vReg dst, vReg src1, vReg src2, immL_M1 m1) %{ ins_pipe(pipe_slow); %} +// vector and_not - predicated + +instruct vand_notI_masked(vReg dst_src1, vReg src2, immI_M1 m1, pRegGov pg) %{ + predicate(UseSVE > 0); + match(Set dst_src1 (AndV (Binary dst_src1 (XorV src2 (ReplicateB m1))) pg)); + match(Set dst_src1 (AndV (Binary dst_src1 (XorV src2 (ReplicateS m1))) pg)); + match(Set dst_src1 (AndV (Binary dst_src1 (XorV src2 (ReplicateI m1))) pg)); + ins_cost(SVE_COST); + format %{ "sve_bic $dst_src1, $pg, $dst_src1, $src2\t# vector (sve) B/H/S" %} + ins_encode %{ + BasicType bt = Matcher::vector_element_basic_type(this); + __ sve_bic(as_FloatRegister($dst_src1$$reg), __ elemType_to_regVariant(bt), + as_PRegister($pg$$reg), as_FloatRegister($src2$$reg)); + %} + ins_pipe(pipe_slow); +%} + +instruct vand_notL_masked(vReg dst_src1, vReg src2, immL_M1 m1, pRegGov pg) %{ + predicate(UseSVE > 0); + match(Set dst_src1 (AndV (Binary dst_src1 (XorV src2 (ReplicateL m1))) pg)); + ins_cost(SVE_COST); + format %{ "sve_bic $dst_src1, $pg, $dst_src1, $src2\t# vector (sve) D" %} + ins_encode %{ + BasicType bt = Matcher::vector_element_basic_type(this); + __ sve_bic(as_FloatRegister($dst_src1$$reg), __ elemType_to_regVariant(bt), + as_PRegister($pg$$reg), as_FloatRegister($src2$$reg)); + %} + ins_pipe(pipe_slow); +%} + // vector float div instruct vdivF(vReg dst_src1, vReg src2) %{ @@ -2873,6 +3162,7 @@ instruct reduce_maxF_masked(vRegF dst, vRegF src1, vReg src2, pRegGov pg) %{ n->in(1)->in(2)->bottom_type()->is_vect()->length_in_bytes() == MaxVectorSize); match(Set dst (MaxReductionV (Binary src1 src2) pg)); ins_cost(SVE_COST); + effect(TEMP_DEF dst); format %{ "sve_reduce_maxF $dst, $src1, $pg, $src2\t# maxF reduction predicated (sve)" %} ins_encode %{ __ sve_fmaxv(as_FloatRegister($dst$$reg), __ S, as_PRegister($pg$$reg), as_FloatRegister($src2$$reg)); @@ -2887,6 +3177,7 @@ instruct reduce_maxD_masked(vRegD dst, vRegD src1, vReg src2, pRegGov pg) %{ n->in(1)->in(2)->bottom_type()->is_vect()->length_in_bytes() == MaxVectorSize); match(Set dst (MaxReductionV (Binary src1 src2) pg)); ins_cost(SVE_COST); + effect(TEMP_DEF dst); format %{ "sve_reduce_maxD $dst, $src1, $pg, $src2\t# maxD reduction predicated (sve)" %} ins_encode %{ __ sve_fmaxv(as_FloatRegister($dst$$reg), __ D, as_PRegister($pg$$reg), as_FloatRegister($src2$$reg)); @@ -3169,6 +3460,7 @@ instruct reduce_minF_masked(vRegF dst, vRegF src1, vReg src2, pRegGov pg) %{ n->in(1)->in(2)->bottom_type()->is_vect()->length_in_bytes() == MaxVectorSize); match(Set dst (MinReductionV (Binary src1 src2) pg)); ins_cost(SVE_COST); + effect(TEMP_DEF dst); format %{ "sve_reduce_minF $dst, $src1, $pg, $src2\t# minF reduction predicated (sve)" %} ins_encode %{ __ sve_fminv(as_FloatRegister($dst$$reg), __ S, as_PRegister($pg$$reg), as_FloatRegister($src2$$reg)); @@ -3183,6 +3475,7 @@ instruct reduce_minD_masked(vRegD dst, vRegD src1, vReg src2, pRegGov pg) %{ n->in(1)->in(2)->bottom_type()->is_vect()->length_in_bytes() == MaxVectorSize); match(Set dst (MinReductionV (Binary src1 src2) pg)); ins_cost(SVE_COST); + effect(TEMP_DEF dst); format %{ "sve_reduce_minD $dst, $src1, $pg, $src2\t# minD reduction predicated (sve)" %} ins_encode %{ __ sve_fminv(as_FloatRegister($dst$$reg), __ D, as_PRegister($pg$$reg), as_FloatRegister($src2$$reg)); @@ -5434,4 +5727,35 @@ instruct vmask_lasttrue_partial(iRegINoSp dst, pReg src, pReg ptmp, rFlagsReg cr __ sve_vmask_lasttrue($dst$$Register, bt, as_PRegister($ptmp$$reg), as_PRegister($ptmp$$reg)); %} ins_pipe(pipe_slow); -%} \ No newline at end of file +%} + +instruct vmask_tolong(iRegLNoSp dst, pReg src, vReg vtmp1, vReg vtmp2, pRegGov pgtmp, rFlagsReg cr) %{ + predicate(UseSVE > 0 && + n->in(1)->bottom_type()->is_vect()->length() <= 64); + match(Set dst (VectorMaskToLong src)); + effect(TEMP vtmp1, TEMP vtmp2, TEMP pgtmp, KILL cr); + ins_cost(13 * SVE_COST); + format %{ "vmask_tolong $dst, $src\t# vector mask tolong (sve)" %} + ins_encode %{ + __ sve_vmask_tolong(as_Register($dst$$reg), as_PRegister($src$$reg), + Matcher::vector_element_basic_type(this, $src), + Matcher::vector_length(this, $src), + as_FloatRegister($vtmp1$$reg), as_FloatRegister($vtmp2$$reg), + as_PRegister($pgtmp$$reg)); + %} + ins_pipe(pipe_slow); +%} +// ---------------------------- Vector mask generation --------------------------- +instruct vmask_gen(pRegGov pg, iRegL len, rFlagsReg cr) %{ + predicate(UseSVE > 0); + match(Set pg (VectorMaskGen len)); + effect(KILL cr); + ins_cost(SVE_COST); + format %{ "sve_whilelo $pg, zr, $len\t # sve" %} + ins_encode %{ + BasicType bt = Matcher::vector_element_basic_type(this); + Assembler::SIMD_RegVariant size = __ elemType_to_regVariant(bt); + __ sve_whilelo(as_PRegister($pg$$reg), size, zr, as_Register($len$$reg)); + %} + ins_pipe(pipe_slow); +%} diff --git a/src/hotspot/cpu/aarch64/aarch64_sve_ad.m4 b/src/hotspot/cpu/aarch64/aarch64_sve_ad.m4 index 91a7a8b21d5b0f518ab7ab8c5dfb8cde924e2cf1..874cdf6e4e0c9a36fae4156762f487a1ba657e71 100644 --- a/src/hotspot/cpu/aarch64/aarch64_sve_ad.m4 +++ b/src/hotspot/cpu/aarch64/aarch64_sve_ad.m4 @@ -1,6 +1,6 @@ // -// Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. -// Copyright (c) 2020, 2021, Arm Limited. All rights reserved. +// Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. +// Copyright (c) 2020, 2022, 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 @@ -356,7 +356,7 @@ instruct vmaskAll_imm$1(pRegGov dst, imm$1 src) %{ predicate(UseSVE > 0); match(Set dst (MaskAll src)); ins_cost(SVE_COST); - format %{ "sve_ptrue/sve_pfalse $dst\t# mask all (sve) ($2)" %} + format %{ "sve_ptrue_lanecnt/sve_pfalse $dst\t# mask all (sve) ($2)" %} ins_encode %{ ifelse($1, `I', int, long) con = (ifelse($1, `I', int, long))$src$$constant; if (con == 0) { @@ -364,7 +364,8 @@ instruct vmaskAll_imm$1(pRegGov dst, imm$1 src) %{ } else { assert(con == -1, "invalid constant value for mask"); BasicType bt = Matcher::vector_element_basic_type(this); - __ sve_ptrue(as_PRegister($dst$$reg), __ elemType_to_regVariant(bt)); + __ sve_ptrue_lanecnt(as_PRegister($dst$$reg), __ elemType_to_regVariant(bt), + Matcher::vector_length(this)); } %} ins_pipe(pipe_slow); @@ -377,19 +378,27 @@ instruct vmaskAll$1(pRegGov dst, ifelse($1, `I', iRegIorL2I, iRegL) src, vReg tm predicate(UseSVE > 0); match(Set dst (MaskAll src)); effect(TEMP tmp, KILL cr); - ins_cost(2 * SVE_COST); + ins_cost(3 * SVE_COST); format %{ "sve_dup $tmp, $src\n\t" - "sve_cmpne $dst, $tmp, 0\t# mask all (sve) ($2)" %} + "sve_ptrue_lanecnt $dst\n\t" + "sve_cmpne $dst, $dst, $tmp, 0\t# mask all (sve) ($2)" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); Assembler::SIMD_RegVariant size = __ elemType_to_regVariant(bt); + uint length_in_bytes = Matcher::vector_length_in_bytes(this); __ sve_dup(as_FloatRegister($tmp$$reg), size, as_Register($src$$reg)); - __ sve_cmp(Assembler::NE, as_PRegister($dst$$reg), size, ptrue, as_FloatRegister($tmp$$reg), 0); + if (length_in_bytes < MaxVectorSize) { + __ sve_ptrue_lanecnt(as_PRegister($dst$$reg), size, Matcher::vector_length(this)); + __ sve_cmp(Assembler::NE, as_PRegister($dst$$reg), size, + as_PRegister($dst$$reg), as_FloatRegister($tmp$$reg), 0); + } else { + __ sve_cmp(Assembler::NE, as_PRegister($dst$$reg), size, ptrue, as_FloatRegister($tmp$$reg), 0); + } %} ins_pipe(pipe_slow); %}')dnl dnl -// maskAll +// maskAll (full or partial predicate size) MASKALL_IMM(I, B/H/S) MASKALL(I, B/H/S) MASKALL_IMM(L, D) @@ -603,7 +612,61 @@ BINARY_OP_PREDICATE(vaddI, AddVI, S, sve_add) BINARY_OP_PREDICATE(vaddL, AddVL, D, sve_add) BINARY_OP_PREDICATE(vaddF, AddVF, S, sve_fadd) BINARY_OP_PREDICATE(vaddD, AddVD, D, sve_fadd) +dnl +dnl ADD_IMM($1, $2, $3 ) +dnl ADD_IMM(name_suffix, size, imm_type) +define(`ADD_IMM', ` +instruct vaddImm$1(vReg dst_src, $3 con) %{ + predicate(UseSVE > 0); + match(Set dst_src (AddV$1 dst_src (Replicate$1 con))); + ins_cost(SVE_COST); + format %{ "sve_add $dst_src, $dst_src, $con\t # vector (sve) ($2)" %} + ins_encode %{ + int32_t val = $con$$constant; + if (val > 0){ + __ sve_add(as_FloatRegister($dst_src$$reg), __ $2, val); + } else if (val < 0){ + __ sve_sub(as_FloatRegister($dst_src$$reg), __ $2, -val); + } + %} + ins_pipe(pipe_slow); +%}')dnl +// vector add reg imm (unpredicated) +ADD_IMM(B, B, immBAddSubV) +ADD_IMM(S, H, immIAddSubV) +ADD_IMM(I, S, immIAddSubV) +ADD_IMM(L, D, immLAddSubV) +dnl +dnl BITWISE_OP_IMM($1, $2 $3, $4 $5 ) +dnl BITWISE_OP_IMM(insn_name, op_name1, size, type, op_name2) +define(`BITWISE_OP_IMM', ` +instruct $1(vReg dst_src, imm$4Log con) %{ + predicate(UseSVE > 0); + match(Set dst_src ($2 dst_src (Replicate$4 con))); + ins_cost(SVE_COST); + format %{ "$5 $dst_src, $dst_src, $con\t # vector (sve) ($3)" %} + ins_encode %{ + __ $5(as_FloatRegister($dst_src$$reg), __ $3, + (uint64_t)($con$$constant)); + %} + ins_pipe(pipe_slow); +%}')dnl + +// vector binary op reg imm (unpredicated) +BITWISE_OP_IMM(vandB, AndV, B, B, sve_and) +BITWISE_OP_IMM(vandH, AndV, H, S, sve_and) +BITWISE_OP_IMM(vandS, AndV, S, I, sve_and) +BITWISE_OP_IMM(vandD, AndV, D, L, sve_and) +BITWISE_OP_IMM(vorB, OrV, B, B, sve_orr) +BITWISE_OP_IMM(vorH, OrV, H, S, sve_orr) +BITWISE_OP_IMM(vorS, OrV, S, I, sve_orr) +BITWISE_OP_IMM(vorD, OrV, D, L, sve_orr) +BITWISE_OP_IMM(vxorB, XorV, B, B, sve_eor) +BITWISE_OP_IMM(vxorH, XorV, H, S, sve_eor) +BITWISE_OP_IMM(vxorS, XorV, S, I, sve_eor) +BITWISE_OP_IMM(vxorD, XorV, D, L, sve_eor) +dnl dnl dnl BINARY_OP_UNSIZED($1, $2, $3 ) dnl BINARY_OP_UNSIZED(insn_name, op_name, insn) @@ -682,6 +745,32 @@ VECTOR_NOT(I, B/H/S) VECTOR_NOT(L, D) undefine(MATCH_RULE) dnl +// vector not - predicated +dnl +define(`MATCH_RULE', `ifelse($1, I, +`match(Set dst (XorV (Binary src (ReplicateB m1)) pg)); + match(Set dst (XorV (Binary src (ReplicateS m1)) pg)); + match(Set dst (XorV (Binary src (ReplicateI m1)) pg));', +`match(Set dst (XorV (Binary src (ReplicateL m1)) pg));')')dnl +dnl +define(`VECTOR_NOT_PREDICATE', ` +instruct vnot$1_masked`'(vReg dst, vReg src, imm$1_M1 m1, pRegGov pg) %{ + predicate(UseSVE > 0); + MATCH_RULE($1) + ins_cost(SVE_COST); + format %{ "sve_not $dst, $pg, $src\t# vector (sve) $2" %} + ins_encode %{ + BasicType bt = Matcher::vector_element_basic_type(this); + __ sve_not(as_FloatRegister($dst$$reg), __ elemType_to_regVariant(bt), + as_PRegister($pg$$reg), as_FloatRegister($src$$reg)); + %} + ins_pipe(pipe_slow); +%}')dnl +dnl $1, $2 +VECTOR_NOT_PREDICATE(I, B/H/S) +VECTOR_NOT_PREDICATE(L, D) +undefine(MATCH_RULE) +dnl // vector and_not dnl define(`MATCH_RULE', `ifelse($1, I, @@ -708,6 +797,32 @@ VECTOR_AND_NOT(I, B/H/S) VECTOR_AND_NOT(L, D) undefine(MATCH_RULE) dnl +// vector and_not - predicated +dnl +define(`MATCH_RULE', `ifelse($1, I, +`match(Set dst_src1 (AndV (Binary dst_src1 (XorV src2 (ReplicateB m1))) pg)); + match(Set dst_src1 (AndV (Binary dst_src1 (XorV src2 (ReplicateS m1))) pg)); + match(Set dst_src1 (AndV (Binary dst_src1 (XorV src2 (ReplicateI m1))) pg));', +`match(Set dst_src1 (AndV (Binary dst_src1 (XorV src2 (ReplicateL m1))) pg));')')dnl +dnl +define(`VECTOR_AND_NOT_PREDICATE', ` +instruct vand_not$1_masked`'(vReg dst_src1, vReg src2, imm$1_M1 m1, pRegGov pg) %{ + predicate(UseSVE > 0); + MATCH_RULE($1) + ins_cost(SVE_COST); + format %{ "sve_bic $dst_src1, $pg, $dst_src1, $src2\t# vector (sve) $2" %} + ins_encode %{ + BasicType bt = Matcher::vector_element_basic_type(this); + __ sve_bic(as_FloatRegister($dst_src1$$reg), __ elemType_to_regVariant(bt), + as_PRegister($pg$$reg), as_FloatRegister($src2$$reg)); + %} + ins_pipe(pipe_slow); +%}')dnl +dnl $1, $2 +VECTOR_AND_NOT_PREDICATE(I, B/H/S) +VECTOR_AND_NOT_PREDICATE(L, D) +undefine(MATCH_RULE) +dnl dnl VDIVF($1, $2 , $3 ) dnl VDIVF(name_suffix, size, min_vec_len) define(`VDIVF', ` @@ -1753,6 +1868,7 @@ instruct reduce_$1$2_masked($5 dst, $5 src1, vReg src2, pRegGov pg) %{ n->in(1)->in(2)->bottom_type()->is_vect()->length_in_bytes() == MaxVectorSize); match(Set dst (translit($1, `m', `M')ReductionV (Binary src1 src2) pg)); ins_cost(SVE_COST); + effect(TEMP_DEF dst); format %{ "sve_reduce_$1$2 $dst, $src1, $pg, $src2\t# $1$2 reduction predicated (sve)" %} ins_encode %{ __ sve_f$1v(as_FloatRegister($dst$$reg), __ $4, as_PRegister($pg$$reg), as_FloatRegister($src2$$reg)); @@ -3084,4 +3200,36 @@ instruct vmask_lasttrue_partial(iRegINoSp dst, pReg src, pReg ptmp, rFlagsReg cr __ sve_vmask_lasttrue($dst$$Register, bt, as_PRegister($ptmp$$reg), as_PRegister($ptmp$$reg)); %} ins_pipe(pipe_slow); +%} + +instruct vmask_tolong(iRegLNoSp dst, pReg src, vReg vtmp1, vReg vtmp2, pRegGov pgtmp, rFlagsReg cr) %{ + predicate(UseSVE > 0 && + n->in(1)->bottom_type()->is_vect()->length() <= 64); + match(Set dst (VectorMaskToLong src)); + effect(TEMP vtmp1, TEMP vtmp2, TEMP pgtmp, KILL cr); + ins_cost(13 * SVE_COST); + format %{ "vmask_tolong $dst, $src\t# vector mask tolong (sve)" %} + ins_encode %{ + __ sve_vmask_tolong(as_Register($dst$$reg), as_PRegister($src$$reg), + Matcher::vector_element_basic_type(this, $src), + Matcher::vector_length(this, $src), + as_FloatRegister($vtmp1$$reg), as_FloatRegister($vtmp2$$reg), + as_PRegister($pgtmp$$reg)); + %} + ins_pipe(pipe_slow); %}dnl + +// ---------------------------- Vector mask generation --------------------------- +instruct vmask_gen(pRegGov pg, iRegL len, rFlagsReg cr) %{ + predicate(UseSVE > 0); + match(Set pg (VectorMaskGen len)); + effect(KILL cr); + ins_cost(SVE_COST); + format %{ "sve_whilelo $pg, zr, $len\t # sve" %} + ins_encode %{ + BasicType bt = Matcher::vector_element_basic_type(this); + Assembler::SIMD_RegVariant size = __ elemType_to_regVariant(bt); + __ sve_whilelo(as_PRegister($pg$$reg), size, zr, as_Register($len$$reg)); + %} + ins_pipe(pipe_slow); +%} diff --git a/src/hotspot/cpu/aarch64/assembler_aarch64.cpp b/src/hotspot/cpu/aarch64/assembler_aarch64.cpp index 4e883838a6610ba34d7f737526f7e39b2aead592..943ca002c7ad998f1d7d1f406a832cd194a9dd5c 100644 --- a/src/hotspot/cpu/aarch64/assembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/assembler_aarch64.cpp @@ -82,6 +82,11 @@ Assembler::SIMD_RegVariant Assembler::elemType_to_regVariant(BasicType bt) { return elemBytes_to_regVariant(type2aelembytes(bt)); } +unsigned Assembler::regVariant_to_elemBits(Assembler::SIMD_RegVariant T){ + guarantee(T != Q, "Invalid register variant"); + return 1 << (T + 3); +} + void Assembler::emit_data64(jlong data, relocInfo::relocType rtype, int format) { @@ -339,21 +344,21 @@ void Assembler::wrap_label(Label &L, prfop op, prefetch_insn insn) { } bool Assembler::operand_valid_for_add_sub_immediate(int64_t imm) { - bool shift = false; - uint64_t uimm = (uint64_t)uabs((jlong)imm); - if (uimm < (1 << 12)) - return true; - if (uimm < (1 << 24) - && ((uimm >> 12) << 12 == uimm)) { - return true; - } - return false; + return operand_valid_for_immediate_bits(imm, 12); +} + +bool Assembler::operand_valid_for_sve_add_sub_immediate(int64_t imm) { + return operand_valid_for_immediate_bits(imm, 8); } bool Assembler::operand_valid_for_logical_immediate(bool is32, uint64_t imm) { return encode_logical_immediate(is32, imm) != 0xffffffff; } +bool Assembler::operand_valid_for_sve_logical_immediate(unsigned elembits, uint64_t imm) { + return encode_sve_logical_immediate(elembits, imm) != 0xffffffff; +} + static uint64_t doubleTo64Bits(jdouble d) { union { jdouble double_value; @@ -383,6 +388,17 @@ int AbstractAssembler::code_fill_byte() { // n.b. this is implemented in subclass MacroAssembler void Assembler::bang_stack_with_offset(int offset) { Unimplemented(); } +bool asm_util::operand_valid_for_immediate_bits(int64_t imm, unsigned nbits) { + guarantee(nbits == 8 || nbits == 12, "invalid nbits value"); + uint64_t uimm = (uint64_t)uabs((jlong)imm); + if (uimm < (UCONST64(1) << nbits)) + return true; + if (uimm < (UCONST64(1) << (2 * nbits)) + && ((uimm >> nbits) << nbits == uimm)) { + return true; + } + return false; +} // and now the routines called by the assembler which encapsulate the // above encode and decode functions @@ -403,6 +419,25 @@ asm_util::encode_logical_immediate(bool is32, uint64_t imm) return encoding_for_logical_immediate(imm); } +uint32_t +asm_util::encode_sve_logical_immediate(unsigned elembits, uint64_t imm) { + guarantee(elembits == 8 || elembits == 16 || + elembits == 32 || elembits == 64, "unsupported element size"); + uint64_t upper = UCONST64(-1) << (elembits/2) << (elembits/2); + /* Allow all zeros or all ones in top bits, so that + * constant expressions like ~1 are permitted. */ + if ((imm & ~upper) != imm && (imm | upper) != imm) + return 0xffffffff; + + // Replicate the immediate in different element sizes to 64 bits. + imm &= ~upper; + for (unsigned i = elembits; i < 64; i *= 2) { + imm |= (imm << i); + } + + return encoding_for_logical_immediate(imm); +} + unsigned Assembler::pack(double value) { float val = (float)value; unsigned result = encoding_for_fp_immediate(val); diff --git a/src/hotspot/cpu/aarch64/assembler_aarch64.hpp b/src/hotspot/cpu/aarch64/assembler_aarch64.hpp index 9858eccb8a787f5fc0d60c64756db46983049fb5..10fcdaa243c006afdb3e5ebc9e21a51f6970c2b4 100644 --- a/src/hotspot/cpu/aarch64/assembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/assembler_aarch64.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2021, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -27,6 +27,7 @@ #define CPU_AARCH64_ASSEMBLER_AARCH64_HPP #include "asm/register.hpp" +#include "metaprogramming/enableIf.hpp" #ifdef __GNUC__ @@ -159,6 +160,8 @@ REGISTER_DECLARATION(PRegister, ptrue, p7); namespace asm_util { uint32_t encode_logical_immediate(bool is32, uint64_t imm); + uint32_t encode_sve_logical_immediate(unsigned elembits, uint64_t imm); + bool operand_valid_for_immediate_bits(int64_t imm, unsigned nbits); }; using namespace asm_util; @@ -402,18 +405,11 @@ class Address { : _mode(no_mode) { } Address(Register r) : _base(r), _index(noreg), _offset(0), _mode(base_plus_offset), _target(0) { } - Address(Register r, int o) - : _base(r), _index(noreg), _offset(o), _mode(base_plus_offset), _target(0) { } - Address(Register r, long o) - : _base(r), _index(noreg), _offset(o), _mode(base_plus_offset), _target(0) { } - Address(Register r, long long o) - : _base(r), _index(noreg), _offset(o), _mode(base_plus_offset), _target(0) { } - Address(Register r, unsigned int o) - : _base(r), _index(noreg), _offset(o), _mode(base_plus_offset), _target(0) { } - Address(Register r, unsigned long o) - : _base(r), _index(noreg), _offset(o), _mode(base_plus_offset), _target(0) { } - Address(Register r, unsigned long long o) - : _base(r), _index(noreg), _offset(o), _mode(base_plus_offset), _target(0) { } + + template::value)> + Address(Register r, T o) + : _base(r), _index(noreg), _offset(o), _mode(base_plus_offset), _target(0) {} + Address(Register r, ByteSize disp) : Address(r, in_bytes(disp)) { } Address(Register r, Register r1, extend ext = lsl()) @@ -476,16 +472,17 @@ class Address { assert(size == 0, "bad size"); size = 0b100; } + assert(offset_ok_for_immed(_offset, size), + "must be, was: " INT64_FORMAT ", %d", _offset, size); unsigned mask = (1 << size) - 1; - if (_offset < 0 || _offset & mask) - { - i->f(0b00, 25, 24); - i->f(0, 21), i->f(0b00, 11, 10); - i->sf(_offset, 20, 12); - } else { - i->f(0b01, 25, 24); - i->f(_offset >> size, 21, 10); - } + if (_offset < 0 || _offset & mask) { + i->f(0b00, 25, 24); + i->f(0, 21), i->f(0b00, 11, 10); + i->sf(_offset, 20, 12); + } else { + i->f(0b01, 25, 24); + i->f(_offset >> size, 21, 10); + } } break; @@ -990,33 +987,35 @@ public: rf(rt, 0); } - void hint(int imm) { - system(0b00, 0b011, 0b0010, 0b0000, imm); - } + // Hint instructions - void nop() { - hint(0); +#define INSN(NAME, crm, op2) \ + void NAME() { \ + system(0b00, 0b011, 0b0010, crm, op2); \ } - void yield() { - hint(1); - } + INSN(nop, 0b000, 0b0000); + INSN(yield, 0b000, 0b0001); + INSN(wfe, 0b000, 0b0010); + INSN(wfi, 0b000, 0b0011); + INSN(sev, 0b000, 0b0100); + INSN(sevl, 0b000, 0b0101); - void wfe() { - hint(2); - } + INSN(autia1716, 0b0001, 0b100); + INSN(autiasp, 0b0011, 0b101); + INSN(autiaz, 0b0011, 0b100); + INSN(autib1716, 0b0001, 0b110); + INSN(autibsp, 0b0011, 0b111); + INSN(autibz, 0b0011, 0b110); + INSN(pacia1716, 0b0001, 0b000); + INSN(paciasp, 0b0011, 0b001); + INSN(paciaz, 0b0011, 0b000); + INSN(pacib1716, 0b0001, 0b010); + INSN(pacibsp, 0b0011, 0b011); + INSN(pacibz, 0b0011, 0b010); + INSN(xpaclri, 0b0000, 0b111); - void wfi() { - hint(3); - } - - void sev() { - hint(4); - } - - void sevl() { - hint(5); - } +#undef INSN // we only provide mrs and msr for the special purpose system // registers where op1 (instr[20:19]) == 11 and, (currently) only @@ -1102,18 +1101,21 @@ public: } // Unconditional branch (register) - void branch_reg(Register R, int opc) { + + void branch_reg(int OP, int A, int M, Register RN, Register RM) { starti; f(0b1101011, 31, 25); - f(opc, 24, 21); - f(0b11111000000, 20, 10); - rf(R, 5); - f(0b00000, 4, 0); + f(OP, 24, 21); + f(0b111110000, 20, 12); + f(A, 11, 11); + f(M, 10, 10); + rf(RN, 5); + rf(RM, 0); } -#define INSN(NAME, opc) \ - void NAME(Register R) { \ - branch_reg(R, opc); \ +#define INSN(NAME, opc) \ + void NAME(Register RN) { \ + branch_reg(opc, 0, 0, RN, r0); \ } INSN(br, 0b0000); @@ -1124,14 +1126,48 @@ public: #undef INSN -#define INSN(NAME, opc) \ - void NAME() { \ - branch_reg(dummy_reg, opc); \ +#define INSN(NAME, opc) \ + void NAME() { \ + branch_reg(opc, 0, 0, dummy_reg, r0); \ } INSN(eret, 0b0100); INSN(drps, 0b0101); +#undef INSN + +#define INSN(NAME, M) \ + void NAME() { \ + branch_reg(0b0010, 1, M, dummy_reg, dummy_reg); \ + } + + INSN(retaa, 0); + INSN(retab, 1); + +#undef INSN + +#define INSN(NAME, OP, M) \ + void NAME(Register rn) { \ + branch_reg(OP, 1, M, rn, dummy_reg); \ + } + + INSN(braaz, 0b0000, 0); + INSN(brabz, 0b0000, 1); + INSN(blraaz, 0b0001, 0); + INSN(blrabz, 0b0001, 1); + +#undef INSN + +#define INSN(NAME, OP, M) \ + void NAME(Register rn, Register rm) { \ + branch_reg(OP, 1, M, rn, rm); \ + } + + INSN(braa, 0b1000, 0); + INSN(brab, 0b1000, 1); + INSN(blraa, 0b1001, 0); + INSN(blrab, 0b1001, 1); + #undef INSN // Load/store exclusive @@ -1516,6 +1552,8 @@ public: static SIMD_Arrangement esize2arrangement(unsigned esize, bool isQ); static SIMD_RegVariant elemType_to_regVariant(BasicType bt); static SIMD_RegVariant elemBytes_to_regVariant(unsigned esize); + // Return the corresponding bits for different SIMD_RegVariant value. + static unsigned regVariant_to_elemBits(SIMD_RegVariant T); enum shift_kind { LSL, LSR, ASR, ROR }; @@ -1721,7 +1759,7 @@ void mvnw(Register Rd, Register Rm, #define INSN(NAME, op) \ void NAME(Register Rn, Register Rm, int imm, Condition cond) { \ - int regNumber = (Rm == zr ? 31 : (uintptr_t)Rm); \ + int regNumber = (Rm == zr ? 31 : Rm->encoding()); \ conditional_compare(op, 0, 0, 0, Rn, regNumber, imm, cond); \ } \ \ @@ -1793,6 +1831,37 @@ void mvnw(Register Rd, Register Rm, INSN(clz, 0b110, 0b00000, 0b00100); INSN(cls, 0b110, 0b00000, 0b00101); + // PAC instructions + INSN(pacia, 0b110, 0b00001, 0b00000); + INSN(pacib, 0b110, 0b00001, 0b00001); + INSN(pacda, 0b110, 0b00001, 0b00010); + INSN(pacdb, 0b110, 0b00001, 0b00011); + INSN(autia, 0b110, 0b00001, 0b00100); + INSN(autib, 0b110, 0b00001, 0b00101); + INSN(autda, 0b110, 0b00001, 0b00110); + INSN(autdb, 0b110, 0b00001, 0b00111); + +#undef INSN + +#define INSN(NAME, op29, opcode2, opcode) \ + void NAME(Register Rd) { \ + starti; \ + f(opcode2, 20, 16); \ + data_processing(current_insn, op29, opcode, Rd, dummy_reg); \ + } + + // PAC instructions (with zero modifier) + INSN(paciza, 0b110, 0b00001, 0b01000); + INSN(pacizb, 0b110, 0b00001, 0b01001); + INSN(pacdza, 0b110, 0b00001, 0b01010); + INSN(pacdzb, 0b110, 0b00001, 0b01011); + INSN(autiza, 0b110, 0b00001, 0b01100); + INSN(autizb, 0b110, 0b00001, 0b01101); + INSN(autdza, 0b110, 0b00001, 0b01110); + INSN(autdzb, 0b110, 0b00001, 0b01111); + INSN(xpaci, 0b110, 0b00001, 0b10000); + INSN(xpacd, 0b110, 0b00001, 0b10001); + #undef INSN // (2 sources) @@ -2419,6 +2488,12 @@ public: INSN(cnt, 0, 0b100000010110, 0); // accepted arrangements: T8B, T16B INSN(uaddlp, 1, 0b100000001010, 2); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S INSN(uaddlv, 1, 0b110000001110, 1); // accepted arrangements: T8B, T16B, T4H, T8H, T4S + // Zero compare. + INSN(cmeq, 0, 0b100000100110, 3); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S, T2D + INSN(cmge, 1, 0b100000100010, 3); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S, T2D + INSN(cmgt, 0, 0b100000100010, 3); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S, T2D + INSN(cmle, 1, 0b100000100110, 3); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S, T2D + INSN(cmlt, 0, 0b100000101010, 3); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S, T2D #undef INSN @@ -2751,20 +2826,18 @@ public: // Move from general purpose register // mov Vd.T[index], Rn - void mov(FloatRegister Vd, SIMD_Arrangement T, int index, Register Xn) { + void mov(FloatRegister Vd, SIMD_RegVariant T, int index, Register Xn) { + guarantee(T != Q, "invalid register variant"); starti; - f(0b01001110000, 31, 21), f(((1 << (T >> 1)) | (index << ((T >> 1) + 1))), 20, 16); + f(0b01001110000, 31, 21), f(((1 << T) | (index << (T + 1))), 20, 16); f(0b000111, 15, 10), zrf(Xn, 5), rf(Vd, 0); } // Move to general purpose register // mov Rd, Vn.T[index] - void mov(Register Xd, FloatRegister Vn, SIMD_Arrangement T, int index) { - guarantee(T >= T2S && T < T1Q, "only D and S arrangements are supported"); - starti; - f(0, 31), f((T >= T1D) ? 1:0, 30), f(0b001110000, 29, 21); - f(((1 << (T >> 1)) | (index << ((T >> 1) + 1))), 20, 16); - f(0b001111, 15, 10), rf(Vn, 5), rf(Xd, 0); + void mov(Register Xd, FloatRegister Vn, SIMD_RegVariant T, int index) { + guarantee(T == S || T == D, "invalid register variant"); + umov(Xd, Vn, T, index); } private: @@ -2953,6 +3026,32 @@ public: INSN(sve_sub, 0b001); #undef INSN +// SVE integer add/subtract immediate (unpredicated) +#define INSN(NAME, op) \ + void NAME(FloatRegister Zd, SIMD_RegVariant T, unsigned imm8) { \ + starti; \ + /* The immediate is an unsigned value in the range 0 to 255, and \ + * for element width of 16 bits or higher it may also be a \ + * positive multiple of 256 in the range 256 to 65280. \ + */ \ + assert(T != Q, "invalid size"); \ + int sh = 0; \ + if (imm8 <= 0xff) { \ + sh = 0; \ + } else if (T != B && imm8 <= 0xff00 && (imm8 & 0xff) == 0) { \ + sh = 1; \ + imm8 = (imm8 >> 8); \ + } else { \ + guarantee(false, "invalid immediate"); \ + } \ + f(0b00100101, 31, 24), f(T, 23, 22), f(0b10000, 21, 17); \ + f(op, 16, 14), f(sh, 13), f(imm8, 12, 5), rf(Zd, 0); \ + } + + INSN(sve_add, 0b011); + INSN(sve_sub, 0b111); +#undef INSN + // SVE floating-point arithmetic - unpredicated #define INSN(NAME, opcode) \ void NAME(FloatRegister Zd, SIMD_RegVariant T, FloatRegister Zn, FloatRegister Zm) { \ @@ -3016,6 +3115,7 @@ public: INSN(sve_and, 0b00000100, 0b011010000); // vector and INSN(sve_andv, 0b00000100, 0b011010001); // bitwise and reduction to scalar INSN(sve_asr, 0b00000100, 0b010000100); // vector arithmetic shift right + INSN(sve_bic, 0b00000100, 0b011011000); // vector bitwise clear INSN(sve_cnt, 0b00000100, 0b011010101); // count non-zero bits INSN(sve_cpy, 0b00000101, 0b100000100); // copy scalar to each active vector element INSN(sve_eor, 0b00000100, 0b011001000); // vector eor @@ -3090,6 +3190,20 @@ public: INSN(sve_bic, 0b11); #undef INSN +// SVE bitwise logical with immediate (unpredicated) +#define INSN(NAME, opc) \ + void NAME(FloatRegister Zd, SIMD_RegVariant T, uint64_t imm) { \ + starti; \ + unsigned elembits = regVariant_to_elemBits(T); \ + uint32_t val = encode_sve_logical_immediate(elembits, imm); \ + f(0b00000101, 31, 24), f(opc, 23, 22), f(0b0000, 21, 18); \ + f(val, 17, 5), rf(Zd, 0); \ + } + INSN(sve_and, 0b10); + INSN(sve_eor, 0b01); + INSN(sve_orr, 0b00); +#undef INSN + // SVE shift immediate - unpredicated #define INSN(NAME, opc, isSHR) \ void NAME(FloatRegister Zd, SIMD_RegVariant T, FloatRegister Zn, int shift) { \ @@ -3639,7 +3753,9 @@ void sve_cmp(Condition cond, PRegister Pd, SIMD_RegVariant T, virtual void bang_stack_with_offset(int offset); static bool operand_valid_for_logical_immediate(bool is32, uint64_t imm); + static bool operand_valid_for_sve_logical_immediate(unsigned elembits, uint64_t imm); static bool operand_valid_for_add_sub_immediate(int64_t imm); + static bool operand_valid_for_sve_add_sub_immediate(int64_t imm); static bool operand_valid_for_float_immediate(double imm); void emit_data64(jlong data, relocInfo::relocType rtype, int format = 0); diff --git a/src/hotspot/cpu/aarch64/assembler_aarch64.inline.hpp b/src/hotspot/cpu/aarch64/assembler_aarch64.inline.hpp index 9fabf1699c53121e63eeadf79f5de7a45b85b24c..e7efe472b829047a09ae79d63fc84a72ac76452c 100644 --- a/src/hotspot/cpu/aarch64/assembler_aarch64.inline.hpp +++ b/src/hotspot/cpu/aarch64/assembler_aarch64.inline.hpp @@ -30,8 +30,14 @@ #include "asm/codeBuffer.hpp" #include "code/codeCache.hpp" - +// Check if an offset is within the encoding range for LDR/STR instructions +// with an immediate offset, either using unscaled signed 9-bits or, scaled +// unsigned 12-bits. We favour the scaled unsigned encoding for all aligned +// offsets (only using the signed 9-bit encoding for negative and unaligned +// offsets). As a precondition, 0 <= shift <= 4 is the log2(size), for the +// supported data widths, {1, 2, 4, 8, 16} bytes. inline bool Address::offset_ok_for_immed(int64_t offset, uint shift) { + precond(shift < 5); uint mask = (1 << shift) - 1; if (offset < 0 || (offset & mask) != 0) { // Unscaled signed offset, encoded in a signed imm9 field. diff --git a/src/hotspot/cpu/aarch64/bytes_aarch64.hpp b/src/hotspot/cpu/aarch64/bytes_aarch64.hpp index acb2e493a9a6bfcdccfccae5e4d043b2da85e7ba..672f03b93a961ccdecffbe31f8b9bc925adec141 100644 --- a/src/hotspot/cpu/aarch64/bytes_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/bytes_aarch64.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2022, 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. * @@ -26,7 +26,7 @@ #ifndef CPU_AARCH64_BYTES_AARCH64_HPP #define CPU_AARCH64_BYTES_AARCH64_HPP -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" class Bytes: AllStatic { public: diff --git a/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp index 7582444a1db7a3140a63cf1e462cef9c322b41aa..6f91b1539a6df7e336f455970a23db93db446711 100644 --- a/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp @@ -187,14 +187,13 @@ Address LIR_Assembler::as_Address(LIR_Address* addr, Register tmp) { default: ShouldNotReachHere(); } - } else { - intptr_t addr_offset = intptr_t(addr->disp()); - if (Address::offset_ok_for_immed(addr_offset, addr->scale())) - return Address(base, addr_offset, Address::lsl(addr->scale())); - else { - __ mov(tmp, addr_offset); - return Address(base, tmp, Address::lsl(addr->scale())); - } + } else { + assert(addr->scale() == 0, + "expected for immediate operand, was: %d", addr->scale()); + ptrdiff_t offset = ptrdiff_t(addr->disp()); + // NOTE: Does not handle any 16 byte vector access. + const uint type_size = type2aelembytes(addr->type(), true); + return __ legitimize_address(Address(base, offset), type_size, tmp); } return Address(); } @@ -439,7 +438,11 @@ int LIR_Assembler::emit_unwind_handler() { if (method()->is_synchronized()) { monitor_address(0, FrameMap::r0_opr); stub = new MonitorExitStub(FrameMap::r0_opr, true, 0); - __ unlock_object(r5, r4, r0, *stub->entry()); + if (UseHeavyMonitors) { + __ b(*stub->entry()); + } else { + __ unlock_object(r5, r4, r0, *stub->entry()); + } __ bind(*stub->continuation()); } @@ -986,14 +989,7 @@ void LIR_Assembler::mem2reg(LIR_Opr src, LIR_Opr dest, BasicType type, LIR_Patch __ ldr(dest->as_register(), as_Address(from_addr)); break; case T_ADDRESS: - // FIXME: OMG this is a horrible kludge. Any offset from an - // address that matches klass_offset_in_bytes() will be loaded - // as a word, not a long. - if (UseCompressedClassPointers && addr->disp() == oopDesc::klass_offset_in_bytes()) { - __ ldrw(dest->as_register(), as_Address(from_addr)); - } else { - __ ldr(dest->as_register(), as_Address(from_addr)); - } + __ ldr(dest->as_register(), as_Address(from_addr)); break; case T_INT: __ ldrw(dest->as_register(), as_Address(from_addr)); @@ -1032,10 +1028,6 @@ void LIR_Assembler::mem2reg(LIR_Opr src, LIR_Opr dest, BasicType type, LIR_Patch // Load barrier has not yet been applied, so ZGC can't verify the oop here __ verify_oop(dest->as_register()); } - } else if (type == T_ADDRESS && addr->disp() == oopDesc::klass_offset_in_bytes()) { - if (UseCompressedClassPointers) { - __ decode_klass_not_null(dest->as_register()); - } } } @@ -1564,7 +1556,7 @@ void LIR_Assembler::emit_compare_and_swap(LIR_OpCompareAndSwap* op) { assert(op->addr()->is_address(), "what else?"); LIR_Address* addr_ptr = op->addr()->as_address_ptr(); assert(addr_ptr->disp() == 0, "need 0 disp"); - assert(addr_ptr->index() == LIR_OprDesc::illegalOpr(), "need 0 index"); + assert(addr_ptr->index() == LIR_Opr::illegalOpr(), "need 0 index"); addr = as_reg(addr_ptr->base()); } Register newval = as_reg(op->new_value()); @@ -2574,7 +2566,7 @@ void LIR_Assembler::emit_lock(LIR_OpLock* op) { Register obj = op->obj_opr()->as_register(); // may not be an oop Register hdr = op->hdr_opr()->as_register(); Register lock = op->lock_opr()->as_register(); - if (!UseFastLocking) { + if (UseHeavyMonitors) { __ b(*op->stub()->entry()); } else if (op->code() == lir_lock) { assert(BasicLock::displaced_header_offset_in_bytes() == 0, "lock_reg must point to the displaced header"); @@ -2593,6 +2585,22 @@ void LIR_Assembler::emit_lock(LIR_OpLock* op) { __ bind(*op->stub()->continuation()); } +void LIR_Assembler::emit_load_klass(LIR_OpLoadKlass* op) { + Register obj = op->obj()->as_pointer_register(); + Register result = op->result_opr()->as_pointer_register(); + + CodeEmitInfo* info = op->info(); + if (info != NULL) { + add_debug_info_for_null_check_here(info); + } + + if (UseCompressedClassPointers) { + __ ldrw(result, Address (obj, oopDesc::klass_offset_in_bytes())); + __ decode_klass_not_null(result); + } else { + __ ldr(result, Address (obj, oopDesc::klass_offset_in_bytes())); + } +} void LIR_Assembler::emit_profile_call(LIR_OpProfileCall* op) { ciMethod* method = op->profiled_method(); diff --git a/src/hotspot/cpu/aarch64/c1_LIRGenerator_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_LIRGenerator_aarch64.cpp index 0a97872900e8940e33d80f7ce23fffcb0e8ee0f1..9f60e493d6acfe2c37a8d8abb96708f815342a26 100644 --- a/src/hotspot/cpu/aarch64/c1_LIRGenerator_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c1_LIRGenerator_aarch64.cpp @@ -148,7 +148,7 @@ LIR_Address* LIRGenerator::generate_address(LIR_Opr base, LIR_Opr index, if (index->is_constant()) { LIR_Const *constant = index->as_constant_ptr(); if (constant->type() == T_INT) { - large_disp += index->as_jint() << shift; + large_disp += ((intx)index->as_jint()) << shift; } else { assert(constant->type() == T_LONG, "should be"); jlong c = index->as_jlong() << shift; @@ -194,7 +194,7 @@ LIR_Address* LIRGenerator::generate_address(LIR_Opr base, LIR_Opr index, if (large_disp == 0 && index->is_register()) { return new LIR_Address(base, index, type); } else { - assert(Address::offset_ok_for_immed(large_disp, 0), "must be"); + assert(Address::offset_ok_for_immed(large_disp, shift), "failed for large_disp: " INTPTR_FORMAT " and shift %d", large_disp, shift); return new LIR_Address(base, large_disp, type); } } @@ -204,24 +204,7 @@ LIR_Address* LIRGenerator::emit_array_address(LIR_Opr array_opr, LIR_Opr index_o int offset_in_bytes = arrayOopDesc::base_offset_in_bytes(type); int elem_size = type2aelembytes(type); int shift = exact_log2(elem_size); - - LIR_Address* addr; - if (index_opr->is_constant()) { - addr = new LIR_Address(array_opr, - offset_in_bytes + (intx)(index_opr->as_jint()) * elem_size, type); - } else { - if (offset_in_bytes) { - LIR_Opr tmp = new_pointer_register(); - __ add(array_opr, LIR_OprFact::intConst(offset_in_bytes), tmp); - array_opr = tmp; - offset_in_bytes = 0; - } - addr = new LIR_Address(array_opr, - index_opr, - LIR_Address::scale(type), - offset_in_bytes, type); - } - return addr; + return generate_address(array_opr, index_opr, shift, offset_in_bytes, type); } LIR_Opr LIRGenerator::load_immediate(int x, BasicType type) { diff --git a/src/hotspot/cpu/aarch64/c1_LIR_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_LIR_aarch64.cpp index 58e1cf5ae63a70b0bc1f09acf1d3e9f0ebf053ca..0dd1a2156e89e5d3fadb1f8faf162bc6bae89fa0 100644 --- a/src/hotspot/cpu/aarch64/c1_LIR_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c1_LIR_aarch64.cpp @@ -26,22 +26,22 @@ #include "asm/register.hpp" #include "c1/c1_LIR.hpp" -FloatRegister LIR_OprDesc::as_float_reg() const { +FloatRegister LIR_Opr::as_float_reg() const { return as_FloatRegister(fpu_regnr()); } -FloatRegister LIR_OprDesc::as_double_reg() const { +FloatRegister LIR_Opr::as_double_reg() const { return as_FloatRegister(fpu_regnrLo()); } // Reg2 unused. LIR_Opr LIR_OprFact::double_fpu(int reg1, int reg2) { assert(as_FloatRegister(reg2) == fnoreg, "Not used on this platform"); - return (LIR_Opr)(intptr_t)((reg1 << LIR_OprDesc::reg1_shift) | - (reg1 << LIR_OprDesc::reg2_shift) | - LIR_OprDesc::double_type | - LIR_OprDesc::fpu_register | - LIR_OprDesc::double_size); + return (LIR_Opr)(intptr_t)((reg1 << LIR_Opr::reg1_shift) | + (reg1 << LIR_Opr::reg2_shift) | + LIR_Opr::double_type | + LIR_Opr::fpu_register | + LIR_Opr::double_size); } #ifndef PRODUCT diff --git a/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.cpp index 661fad89e47edf1289274d09d6929915b60d7b53..54821ea4b0a9184c73fac1a7f618d24aea7dd644 100644 --- a/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.cpp @@ -304,7 +304,7 @@ void C1_MacroAssembler::remove_frame(int framesize) { } -void C1_MacroAssembler::verified_entry() { +void C1_MacroAssembler::verified_entry(bool breakAtEntry) { // If we have to make this method not-entrant we'll overwrite its // first instruction with a jump. For this action to be legal we // must ensure that this first instruction is a B, BL, NOP, BKPT, diff --git a/src/hotspot/cpu/aarch64/c1_Runtime1_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_Runtime1_aarch64.cpp index 005f739f0aa0566a83bda8adff7d2cc0106ff3b7..342aa87a6208d9b3059be01e910635f8ada97509 100644 --- a/src/hotspot/cpu/aarch64/c1_Runtime1_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c1_Runtime1_aarch64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2022, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2021, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -385,6 +385,7 @@ OopMapSet* Runtime1::generate_handle_exception(StubID id, StubAssembler *sasm) { // load issuing PC (the return address for this stub) into r3 __ ldr(exception_pc, Address(rfp, 1*BytesPerWord)); + __ authenticate_return_address(exception_pc, rscratch1); // make sure that the vm_results are cleared (may be unnecessary) __ str(zr, Address(rthread, JavaThread::vm_result_offset())); @@ -433,6 +434,7 @@ OopMapSet* Runtime1::generate_handle_exception(StubID id, StubAssembler *sasm) { __ str(exception_pc, Address(rthread, JavaThread::exception_pc_offset())); // patch throwing pc into return address (has bci & oop map) + __ protect_return_address(exception_pc, rscratch1); __ str(exception_pc, Address(rfp, 1*BytesPerWord)); // compute the exception handler. @@ -448,6 +450,7 @@ OopMapSet* Runtime1::generate_handle_exception(StubID id, StubAssembler *sasm) { __ invalidate_registers(false, true, true, true, true, true); // patch the return address, this stub will directly return to the exception handler + __ protect_return_address(r0, rscratch1); __ str(r0, Address(rfp, 1*BytesPerWord)); switch (id) { @@ -496,10 +499,12 @@ void Runtime1::generate_unwind_exception(StubAssembler *sasm) { // Save our return address because // exception_handler_for_return_address will destroy it. We also // save exception_oop + __ mov(r3, lr); + __ protect_return_address(); __ stp(lr, exception_oop, Address(__ pre(sp, -2 * wordSize))); // search the exception handler address of the caller (using the return address) - __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address), rthread, lr); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address), rthread, r3); // r0: exception handler address of the caller // Only R0 is valid at this time; all other registers have been @@ -512,6 +517,7 @@ void Runtime1::generate_unwind_exception(StubAssembler *sasm) { // get throwing pc (= return address). // lr has been destroyed by the call __ ldp(lr, exception_oop, Address(__ post(sp, 2 * wordSize))); + __ authenticate_return_address(); __ mov(r3, lr); __ verify_not_null_oop(exception_oop); diff --git a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp index 5ba1026415f617ec50ee70e438c2310884ec38c6..53ee3d71bc769e3975a2139ac1cca06293acdf64 100644 --- a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp @@ -945,6 +945,48 @@ void C2_MacroAssembler::neon_compare(FloatRegister dst, BasicType bt, FloatRegis } } +// Compress the least significant bit of each byte to the rightmost and clear +// the higher garbage bits. +void C2_MacroAssembler::bytemask_compress(Register dst) { + // Example input, dst = 0x01 00 00 00 01 01 00 01 + // The "??" bytes are garbage. + orr(dst, dst, dst, Assembler::LSR, 7); // dst = 0x?? 02 ?? 00 ?? 03 ?? 01 + orr(dst, dst, dst, Assembler::LSR, 14); // dst = 0x????????08 ??????0D + orr(dst, dst, dst, Assembler::LSR, 28); // dst = 0x????????????????8D + andr(dst, dst, 0xff); // dst = 0x8D +} + +// Pack the lowest-numbered bit of each mask element in src into a long value +// in dst, at most the first 64 lane elements. +// Clobbers: rscratch1 +void C2_MacroAssembler::sve_vmask_tolong(Register dst, PRegister src, BasicType bt, int lane_cnt, + FloatRegister vtmp1, FloatRegister vtmp2, PRegister pgtmp) { + assert(pgtmp->is_governing(), "This register has to be a governing predicate register."); + assert(lane_cnt <= 64 && is_power_of_2(lane_cnt), "Unsupported lane count"); + assert_different_registers(dst, rscratch1); + + Assembler::SIMD_RegVariant size = elemType_to_regVariant(bt); + + // Pack the mask into vector with sequential bytes. + sve_cpy(vtmp1, size, src, 1, false); + if (bt != T_BYTE) { + sve_vector_narrow(vtmp1, B, vtmp1, size, vtmp2); + } + + // Compress the lowest 8 bytes. + fmovd(dst, vtmp1); + bytemask_compress(dst); + if (lane_cnt <= 8) return; + + // Repeat on higher bytes and join the results. + // Compress 8 bytes in each iteration. + for (int idx = 1; idx < (lane_cnt / 8); idx++) { + idx == 1 ? fmovhid(rscratch1, vtmp1) : sve_extract(rscratch1, D, pgtmp, vtmp1, idx); + bytemask_compress(rscratch1); + orr(dst, dst, rscratch1, Assembler::LSL, idx << 3); + } +} + void C2_MacroAssembler::sve_compare(PRegister pd, BasicType bt, PRegister pg, FloatRegister zn, FloatRegister zm, int cond) { assert(pg->is_governing(), "This register has to be a governing predicate register"); @@ -1020,6 +1062,7 @@ void C2_MacroAssembler::sve_vector_narrow(FloatRegister dst, SIMD_RegVariant dst FloatRegister src, SIMD_RegVariant src_size, FloatRegister tmp) { assert(dst_size < src_size && dst_size <= S && src_size <= D, "invalid element size"); + assert_different_registers(src, tmp); sve_dup(tmp, src_size, 0); if (src_size == D) { switch (dst_size) { @@ -1188,3 +1231,39 @@ void C2_MacroAssembler::sve_reduce_integral(int opc, Register dst, BasicType bt, } } } + +// Set elements of the dst predicate to true if the element number is +// in the range of [0, lane_cnt), or to false otherwise. +void C2_MacroAssembler::sve_ptrue_lanecnt(PRegister dst, SIMD_RegVariant size, int lane_cnt) { + assert(size != Q, "invalid size"); + switch(lane_cnt) { + case 1: /* VL1 */ + case 2: /* VL2 */ + case 3: /* VL3 */ + case 4: /* VL4 */ + case 5: /* VL5 */ + case 6: /* VL6 */ + case 7: /* VL7 */ + case 8: /* VL8 */ + sve_ptrue(dst, size, lane_cnt); + break; + case 16: + sve_ptrue(dst, size, /* VL16 */ 0b01001); + break; + case 32: + sve_ptrue(dst, size, /* VL32 */ 0b01010); + break; + case 64: + sve_ptrue(dst, size, /* VL64 */ 0b01011); + break; + case 128: + sve_ptrue(dst, size, /* VL128 */ 0b01100); + break; + case 256: + sve_ptrue(dst, size, /* VL256 */ 0b01101); + break; + default: + assert(false, "unsupported"); + ShouldNotReachHere(); + } +} diff --git a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.hpp index 81d9799f5adbc06f85424339cc4e84d13e87700b..e31fa7df08047065a3e6f028efd91908ef547713 100644 --- a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.hpp @@ -54,6 +54,15 @@ FloatRegister ztmp1, FloatRegister ztmp2, PRegister pgtmp, PRegister ptmp, bool isL); + // Compress the least significant bit of each byte to the rightmost and clear + // the higher garbage bits. + void bytemask_compress(Register dst); + + // Pack the lowest-numbered bit of each mask element in src into a long value + // in dst, at most the first 64 lane elements. + void sve_vmask_tolong(Register dst, PRegister src, BasicType bt, int lane_cnt, + FloatRegister vtmp1, FloatRegister vtmp2, PRegister pgtmp); + // SIMD&FP comparison void neon_compare(FloatRegister dst, BasicType bt, FloatRegister src1, FloatRegister src2, int cond, bool isQ); @@ -78,6 +87,10 @@ void sve_reduce_integral(int opc, Register dst, BasicType bt, Register src1, FloatRegister src2, PRegister pg, FloatRegister tmp); + // Set elements of the dst predicate to true if the element number is + // in the range of [0, lane_cnt), or to false otherwise. + void sve_ptrue_lanecnt(PRegister dst, SIMD_RegVariant size, int lane_cnt); + // Generate predicate through whilelo, by comparing ZR with an unsigned // immediate. rscratch1 will be clobbered. inline void sve_whilelo_zr_imm(PRegister pd, SIMD_RegVariant size, uint imm) { diff --git a/src/hotspot/cpu/aarch64/copy_aarch64.hpp b/src/hotspot/cpu/aarch64/copy_aarch64.hpp index 3912ee086cf0c4a093094f59da801c8863fb6736..0ff9ace59cc2f3761c7aed3f433dc77b32d7e2e3 100644 --- a/src/hotspot/cpu/aarch64/copy_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/copy_aarch64.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2022, 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. * @@ -52,4 +52,166 @@ static void pd_zero_to_bytes(void* to, size_t count) { (void)memset(to, 0, count); } +#ifndef _WINDOWS + +#define COPY_SMALL(from, to, count) \ +{ \ + long tmp0, tmp1, tmp2, tmp3; \ + long tmp4, tmp5, tmp6, tmp7; \ + __asm volatile( \ +" adr %[t0], 0f;\n" \ +" add %[t0], %[t0], %[cnt], lsl #5;\n" \ +" br %[t0];\n" \ +" .align 5;\n" \ +"0:" \ +" b 1f;\n" \ +" .align 5;\n" \ +" ldr %[t0], [%[s], #0];\n" \ +" str %[t0], [%[d], #0];\n" \ +" b 1f;\n" \ +" .align 5;\n" \ +" ldp %[t0], %[t1], [%[s], #0];\n" \ +" stp %[t0], %[t1], [%[d], #0];\n" \ +" b 1f;\n" \ +" .align 5;\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" \ +" 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" \ +" ldp %[t0], %[t1], [%[s], #0];\n" \ +" ldp %[t2], %[t3], [%[s], #16];\n" \ +" ldr %[t4], [%[s], #32];\n" \ +" stp %[t0], %[t1], [%[d], #0];\n" \ +" stp %[t2], %[t3], [%[d], #16];\n" \ +" str %[t4], [%[d], #32];\n" \ +" b 1f;\n" \ +" .align 5;\n" \ +" ldp %[t0], %[t1], [%[s], #0];\n" \ +" ldp %[t2], %[t3], [%[s], #16];\n" \ +" ldp %[t4], %[t5], [%[s], #32];\n" \ +"2:" \ +" stp %[t0], %[t1], [%[d], #0];\n" \ +" stp %[t2], %[t3], [%[d], #16];\n" \ +" stp %[t4], %[t5], [%[d], #32];\n" \ +" b 1f;\n" \ +" .align 5;\n" \ +" ldr %[t6], [%[s], #0];\n" \ +" ldp %[t0], %[t1], [%[s], #8];\n" \ +" ldp %[t2], %[t3], [%[s], #24];\n" \ +" ldp %[t4], %[t5], [%[s], #40];\n" \ +" str %[t6], [%[d]], #8;\n" \ +" b 2b;\n" \ +" .align 5;\n" \ +" ldp %[t0], %[t1], [%[s], #0];\n" \ +" ldp %[t2], %[t3], [%[s], #16];\n" \ +" ldp %[t4], %[t5], [%[s], #32];\n" \ +" ldp %[t6], %[t7], [%[s], #48];\n" \ +" stp %[t0], %[t1], [%[d], #0];\n" \ +" stp %[t2], %[t3], [%[d], #16];\n" \ +" stp %[t4], %[t5], [%[d], #32];\n" \ +" stp %[t6], %[t7], [%[d], #48];\n" \ +"1:" \ + \ + : [s]"+r"(from), [d]"+r"(to), [cnt]"+r"(count), \ + [t0]"=&r"(tmp0), [t1]"=&r"(tmp1), [t2]"=&r"(tmp2), [t3]"=&r"(tmp3), \ + [t4]"=&r"(tmp4), [t5]"=&r"(tmp5), [t6]"=&r"(tmp6), [t7]"=&r"(tmp7) \ + : \ + : "memory", "cc"); \ +} + +static void pd_conjoint_words(const HeapWord* from, HeapWord* to, size_t count) { + __asm volatile( "prfm pldl1strm, [%[s], #0];" :: [s]"r"(from) : "memory"); + if (__builtin_expect(count <= 8, 1)) { + COPY_SMALL(from, to, count); + return; + } + _Copy_conjoint_words(from, to, count); +} + +static void pd_disjoint_words(const HeapWord* from, HeapWord* to, size_t count) { + if (__builtin_constant_p(count)) { + memcpy(to, from, count * sizeof(HeapWord)); + return; + } + __asm volatile( "prfm pldl1strm, [%[s], #0];" :: [s]"r"(from) : "memory"); + if (__builtin_expect(count <= 8, 1)) { + COPY_SMALL(from, to, count); + return; + } + _Copy_disjoint_words(from, to, count); +} + +static void pd_disjoint_words_atomic(const HeapWord* from, HeapWord* to, size_t count) { + __asm volatile( "prfm pldl1strm, [%[s], #0];" :: [s]"r"(from) : "memory"); + if (__builtin_expect(count <= 8, 1)) { + COPY_SMALL(from, to, count); + return; + } + _Copy_disjoint_words(from, to, count); +} + +static void pd_aligned_conjoint_words(const HeapWord* from, HeapWord* to, size_t count) { + pd_conjoint_words(from, to, count); +} + +static void pd_aligned_disjoint_words(const HeapWord* from, HeapWord* to, size_t count) { + pd_disjoint_words(from, to, count); +} + +static void pd_conjoint_bytes(const void* from, void* to, size_t count) { + (void)memmove(to, from, count); +} + +static void pd_conjoint_bytes_atomic(const void* from, void* to, size_t count) { + pd_conjoint_bytes(from, to, count); +} + +static void pd_conjoint_jshorts_atomic(const jshort* from, jshort* to, size_t count) { + _Copy_conjoint_jshorts_atomic(from, to, count); +} + +static void pd_conjoint_jints_atomic(const jint* from, jint* to, size_t count) { + _Copy_conjoint_jints_atomic(from, to, count); +} + +static void pd_conjoint_jlongs_atomic(const jlong* from, jlong* to, size_t count) { + _Copy_conjoint_jlongs_atomic(from, to, count); +} + +static void pd_conjoint_oops_atomic(const oop* from, oop* to, size_t count) { + assert(BytesPerLong == BytesPerOop, "jlongs and oops must be the same size"); + _Copy_conjoint_jlongs_atomic((const jlong*)from, (jlong*)to, count); +} + +static void pd_arrayof_conjoint_bytes(const HeapWord* from, HeapWord* to, size_t count) { + _Copy_arrayof_conjoint_bytes(from, to, count); +} + +static void pd_arrayof_conjoint_jshorts(const HeapWord* from, HeapWord* to, size_t count) { + _Copy_arrayof_conjoint_jshorts(from, to, count); +} + +static void pd_arrayof_conjoint_jints(const HeapWord* from, HeapWord* to, size_t count) { + _Copy_arrayof_conjoint_jints(from, to, count); +} + +static void pd_arrayof_conjoint_jlongs(const HeapWord* from, HeapWord* to, size_t count) { + _Copy_arrayof_conjoint_jlongs(from, to, count); +} + +static void pd_arrayof_conjoint_oops(const HeapWord* from, HeapWord* to, size_t count) { + assert(!UseCompressedOops, "foo!"); + assert(BytesPerLong == BytesPerOop, "jlongs and oops must be the same size"); + _Copy_arrayof_conjoint_jlongs(from, to, count); +} +#endif // _WINDOWS + #endif // CPU_AARCH64_COPY_AARCH64_HPP diff --git a/src/hotspot/cpu/aarch64/foreign_globals_aarch64.cpp b/src/hotspot/cpu/aarch64/foreign_globals_aarch64.cpp index d08afc79a52451ed082ce5dafb7e2c24e8c4ec20..4334a395571a0b215ded547cbdd9d0e114b2d7ea 100644 --- a/src/hotspot/cpu/aarch64/foreign_globals_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/foreign_globals_aarch64.cpp @@ -45,7 +45,7 @@ bool ABIDescriptor::is_volatile_reg(FloatRegister reg) const { const ABIDescriptor ForeignGlobals::parse_abi_descriptor_impl(jobject jabi) const { oop abi_oop = JNIHandles::resolve_non_null(jabi); ABIDescriptor abi; - const Register (*to_Register)(int) = as_Register; + constexpr Register (*to_Register)(int) = as_Register; objArrayOop inputStorage = cast(abi_oop->obj_field(ABI.inputStorage_offset)); loadArray(inputStorage, INTEGER_TYPE, abi._integer_argument_registers, to_Register); diff --git a/src/hotspot/cpu/aarch64/frame_aarch64.cpp b/src/hotspot/cpu/aarch64/frame_aarch64.cpp index 35cc1ee1f8402e4c52ed8dfe3af2a9686aa9db5e..3363e53690e474bf5dbde3ef92c4f87601b96e08 100644 --- a/src/hotspot/cpu/aarch64/frame_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/frame_aarch64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -128,13 +128,13 @@ bool frame::safe_for_sender(JavaThread *thread) { return false; } - sender_pc = (address) this->fp()[return_addr_offset]; // for interpreted frames, the value below is the sender "raw" sp, // which can be different from the sender unextended sp (the sp seen // by the sender) because of current frame local variables sender_sp = (intptr_t*) addr_at(sender_sp_offset); sender_unextended_sp = (intptr_t*) this->fp()[interpreter_frame_sender_sp_offset]; saved_fp = (intptr_t*) this->fp()[link_offset]; + sender_pc = pauth_strip_verifiable((address) this->fp()[return_addr_offset], (address)saved_fp); } else { // must be some sort of compiled/runtime frame @@ -151,9 +151,9 @@ bool frame::safe_for_sender(JavaThread *thread) { return false; } sender_unextended_sp = sender_sp; - sender_pc = (address) *(sender_sp-1); // Note: frame::sender_sp_offset is only valid for compiled frame saved_fp = (intptr_t*) *(sender_sp - frame::sender_sp_offset); + sender_pc = pauth_strip_verifiable((address) *(sender_sp-1), (address)saved_fp); } @@ -268,17 +268,22 @@ bool frame::safe_for_sender(JavaThread *thread) { void frame::patch_pc(Thread* thread, address pc) { assert(_cb == CodeCache::find_blob(pc), "unexpected pc"); address* pc_addr = &(((address*) sp())[-1]); + address signing_sp = (((address*) sp())[-2]); + address signed_pc = pauth_sign_return_address(pc, (address)signing_sp); + address pc_old = pauth_strip_verifiable(*pc_addr, (address)signing_sp); if (TracePcPatching) { - tty->print_cr("patch_pc at address " INTPTR_FORMAT " [" INTPTR_FORMAT " -> " INTPTR_FORMAT "]", - p2i(pc_addr), p2i(*pc_addr), p2i(pc)); + tty->print("patch_pc at address " INTPTR_FORMAT " [" INTPTR_FORMAT " -> " INTPTR_FORMAT "]", + p2i(pc_addr), p2i(pc_old), p2i(pc)); + if (VM_Version::use_rop_protection()) { + tty->print(" [signed " INTPTR_FORMAT " -> " INTPTR_FORMAT "]", p2i(*pc_addr), p2i(signed_pc)); + } + tty->print_cr(""); } - // Only generated code frames should be patched, therefore the return address will not be signed. - assert(pauth_ptr_is_raw(*pc_addr), "cannot be signed"); // Either the return address is the original one or we are going to // patch in the same address that's already there. - assert(_pc == *pc_addr || pc == *pc_addr, "must be"); - *pc_addr = pc; + assert(_pc == pc_old || pc == pc_old, "must be"); + *pc_addr = signed_pc; address original_pc = CompiledMethod::get_deopt_original_pc(this); if (original_pc != NULL) { assert(original_pc == _pc, "expected original PC to be stored before patching"); @@ -358,6 +363,7 @@ frame frame::sender_for_entry_frame(RegisterMap* map) const { assert(map->include_argument_oops(), "should be set by clear"); vmassert(jfa->last_Java_pc() != NULL, "not walkable"); frame fr(jfa->last_Java_sp(), jfa->last_Java_fp(), jfa->last_Java_pc()); + fr.set_sp_is_trusted(); return fr; } @@ -454,25 +460,36 @@ frame frame::sender_for_interpreter_frame(RegisterMap* map) const { } #endif // COMPILER2_OR_JVMCI - // Use the raw version of pc - the interpreter should not have signed it. + // For ROP protection, Interpreter will have signed the sender_pc, but there is no requirement to authenticate it here. + address sender_pc = pauth_strip_verifiable(sender_pc_maybe_signed(), (address)link()); - return frame(sender_sp, unextended_sp, link(), sender_pc_maybe_signed()); + return frame(sender_sp, unextended_sp, link(), sender_pc); } - //------------------------------------------------------------------------------ // frame::sender_for_compiled_frame frame frame::sender_for_compiled_frame(RegisterMap* map) const { - // we cannot rely upon the last fp having been saved to the thread - // in C2 code but it will have been pushed onto the stack. so we - // have to find it relative to the unextended sp + // When the sp of a compiled frame is correct, we can get the correct sender sp + // by unextended sp + frame size. + // For the following two scenarios, the sp of a compiled frame is correct: + // a) This compiled frame is built from the anchor. + // b) This compiled frame is built from a callee frame, and the callee frame can + // calculate its sp correctly. + // + // For b), if the callee frame is a native code frame (such as leaf call), the sp of + // the compiled frame cannot be calculated correctly. There is currently no suitable + // solution to solve this problem perfectly. But when PreserveFramePointer is enabled, + // we can get the correct sender sp by fp + 2 (that is sender_sp()). assert(_cb->frame_size() >= 0, "must have non-zero frame size"); - intptr_t* l_sender_sp = unextended_sp() + _cb->frame_size(); + intptr_t* l_sender_sp = (!PreserveFramePointer || _sp_is_trusted) ? unextended_sp() + _cb->frame_size() + : sender_sp(); intptr_t* unextended_sp = l_sender_sp; // the return_address is always the word on the stack - address sender_pc = (address) *(l_sender_sp-1); + + // For ROP protection, C1/C2 will have signed the sender_pc, but there is no requirement to authenticate it here. + address sender_pc = pauth_strip_verifiable((address) *(l_sender_sp-1), (address) *(l_sender_sp-2)); intptr_t** saved_fp_addr = (intptr_t**) (l_sender_sp - frame::sender_sp_offset); @@ -520,6 +537,9 @@ frame frame::sender_raw(RegisterMap* map) const { // Must be native-compiled frame, i.e. the marshaling code for native // methods that exists in the core system. + // Native code may or may not have signed the return address, we have no way to be sure or what + // signing methods they used. Instead, just ensure the stripped value is used. + return frame(sender_sp(), link(), sender_pc()); } diff --git a/src/hotspot/cpu/aarch64/frame_aarch64.hpp b/src/hotspot/cpu/aarch64/frame_aarch64.hpp index 716c0ff9f1a59ee88bb2f045fc82d6589c96e021..95f470befa021ab433baf524045ece4c55d17786 100644 --- a/src/hotspot/cpu/aarch64/frame_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/frame_aarch64.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2022, 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. * @@ -124,6 +124,11 @@ intptr_t* _unextended_sp; void adjust_unextended_sp(); + // true means _sp value is correct and we can use it to get the sender's sp + // of the compiled frame, otherwise, _sp value may be invalid and we can use + // _fp to get the sender's sp if PreserveFramePointer is enabled. + bool _sp_is_trusted; + intptr_t* ptr_at_addr(int offset) const { return (intptr_t*) addr_at(offset); } @@ -165,4 +170,6 @@ // returns the sending frame, without applying any barriers frame sender_raw(RegisterMap* map) const; + void set_sp_is_trusted() { _sp_is_trusted = true; } + #endif // CPU_AARCH64_FRAME_AARCH64_HPP diff --git a/src/hotspot/cpu/aarch64/frame_aarch64.inline.hpp b/src/hotspot/cpu/aarch64/frame_aarch64.inline.hpp index 5be02aa57e7a3c8c56c21c19fe79c46060b08f92..20b5b8e8662484d0f3319416f3ce79f373b6f959 100644 --- a/src/hotspot/cpu/aarch64/frame_aarch64.inline.hpp +++ b/src/hotspot/cpu/aarch64/frame_aarch64.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2022, 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. * @@ -41,6 +41,7 @@ inline frame::frame() { _fp = NULL; _cb = NULL; _deopt_state = unknown; + _sp_is_trusted = false; } static int spin; @@ -64,6 +65,7 @@ inline void frame::init(intptr_t* sp, intptr_t* fp, address pc) { } else { _deopt_state = not_deoptimized; } + _sp_is_trusted = false; } inline frame::frame(intptr_t* sp, intptr_t* fp, address pc) { @@ -91,6 +93,7 @@ inline frame::frame(intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, address } else { _deopt_state = not_deoptimized; } + _sp_is_trusted = false; } inline frame::frame(intptr_t* sp, intptr_t* fp) { @@ -122,6 +125,7 @@ inline frame::frame(intptr_t* sp, intptr_t* fp) { } else { _deopt_state = not_deoptimized; } + _sp_is_trusted = false; } // Accessors @@ -144,10 +148,12 @@ inline intptr_t* frame::id(void) const { return unextended_sp(); } inline bool frame::is_older(intptr_t* id) const { assert(this->id() != NULL && id != NULL, "NULL frame id"); return this->id() > id ; } - - inline intptr_t* frame::link() const { return (intptr_t*) *(intptr_t **)addr_at(link_offset); } +inline intptr_t* frame::link_or_null() const { + intptr_t** ptr = (intptr_t **)addr_at(link_offset); + return os::is_readable_pointer(ptr) ? *ptr : NULL; +} inline intptr_t* frame::unextended_sp() const { return _unextended_sp; } diff --git a/src/hotspot/cpu/aarch64/gc/g1/g1BarrierSetAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/gc/g1/g1BarrierSetAssembler_aarch64.cpp index 77a6dc8b7396ff06d5524435c7a9c3c0b217f5e9..01aff54c96d5582e65dec49346fc993b507d2abd 100644 --- a/src/hotspot/cpu/aarch64/gc/g1/g1BarrierSetAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/gc/g1/g1BarrierSetAssembler_aarch64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -222,7 +222,7 @@ void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm, const Register card_addr = tmp; - __ lsr(card_addr, store_addr, CardTable::card_shift); + __ lsr(card_addr, store_addr, CardTable::card_shift()); // get the address of the card __ load_byte_map_base(tmp2); @@ -271,7 +271,7 @@ void G1BarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorator ModRefBarrierSetAssembler::load_at(masm, decorators, type, dst, src, tmp1, tmp_thread); if (on_oop && on_reference) { // LR is live. It must be saved around calls. - __ enter(); // barrier may call runtime + __ enter(/*strip_ret_addr*/true); // barrier may call runtime // Generate the G1 pre-barrier code to log the value of // the referent field in an SATB buffer. g1_write_barrier_pre(masm /* masm */, @@ -444,7 +444,7 @@ void G1BarrierSetAssembler::generate_c1_post_barrier_runtime_stub(StubAssembler* assert_different_registers(card_offset, byte_map_base, rscratch1); __ load_parameter(0, card_offset); - __ lsr(card_offset, card_offset, CardTable::card_shift); + __ lsr(card_offset, card_offset, CardTable::card_shift()); __ load_byte_map_base(byte_map_base); __ ldrb(rscratch1, Address(byte_map_base, card_offset)); __ cmpw(rscratch1, (int)G1CardTable::g1_young_card_val()); diff --git a/src/hotspot/cpu/aarch64/gc/shared/cardTableBarrierSetAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/gc/shared/cardTableBarrierSetAssembler_aarch64.cpp index fb677828e20e640df27cc874e6183f7a59036eed..f94f2b9c902a018c583f0fe79e68ba988d3ec448 100644 --- a/src/hotspot/cpu/aarch64/gc/shared/cardTableBarrierSetAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/gc/shared/cardTableBarrierSetAssembler_aarch64.cpp @@ -38,7 +38,7 @@ void CardTableBarrierSetAssembler::store_check(MacroAssembler* masm, Register ob BarrierSet* bs = BarrierSet::barrier_set(); assert(bs->kind() == BarrierSet::CardTableBarrierSet, "Wrong barrier set kind"); - __ lsr(obj, obj, CardTable::card_shift); + __ lsr(obj, obj, CardTable::card_shift()); assert(CardTable::dirty_card_val() == 0, "must be"); @@ -64,8 +64,8 @@ void CardTableBarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembl __ lea(end, Address(start, count, Address::lsl(LogBytesPerHeapOop))); // end = start + count << LogBytesPerHeapOop __ sub(end, end, BytesPerHeapOop); // last element address to make inclusive - __ lsr(start, start, CardTable::card_shift); - __ lsr(end, end, CardTable::card_shift); + __ lsr(start, start, CardTable::card_shift()); + __ lsr(end, end, CardTable::card_shift()); __ sub(count, end, start); // number of bytes to copy __ load_byte_map_base(scratch); diff --git a/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.cpp index 53de1d921fca33dc4213bbdfb1574c48d9a901eb..bcabb40e63cbea92dfe2ec363c7206908ce7c2a6 100644 --- a/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Red Hat, Inc. All rights reserved. + * Copyright (c) 2018, 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 @@ -237,7 +237,7 @@ void ShenandoahBarrierSetAssembler::load_reference_barrier(MacroAssembler* masm, bool is_narrow = UseCompressedOops && !is_native; Label heap_stable, not_cset; - __ enter(); + __ enter(/*strip_ret_addr*/true); Address gc_state(rthread, in_bytes(ShenandoahThreadLocalData::gc_state_offset())); __ ldrb(rscratch2, gc_state); @@ -359,7 +359,7 @@ void ShenandoahBarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet d // 3: apply keep-alive barrier if needed if (ShenandoahBarrierSet::need_keep_alive_barrier(decorators, type)) { - __ enter(); + __ enter(/*strip_ret_addr*/true); __ push_call_clobbered_registers(); satb_write_barrier_pre(masm /* masm */, noreg /* obj */, diff --git a/src/hotspot/cpu/aarch64/gc/z/zBarrierSetAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/gc/z/zBarrierSetAssembler_aarch64.cpp index 10b1cf20ef910240b4988db7d611a1b778d71ca4..6820be15950ec50f975ee6c870b52c2024317882 100644 --- a/src/hotspot/cpu/aarch64/gc/z/zBarrierSetAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/gc/z/zBarrierSetAssembler_aarch64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -78,7 +78,7 @@ void ZBarrierSetAssembler::load_at(MacroAssembler* masm, __ tst(dst, rscratch1); __ br(Assembler::EQ, done); - __ enter(); + __ enter(/*strip_ret_addr*/true); __ push_call_clobbered_registers_except(RegSet::of(dst)); diff --git a/src/hotspot/cpu/aarch64/globalDefinitions_aarch64.hpp b/src/hotspot/cpu/aarch64/globalDefinitions_aarch64.hpp index 3c779bb11b15cfe961ccad89c6d4d78abe586269..fe88f7b887c1958e1368ed5eb6e0da74729feb39 100644 --- a/src/hotspot/cpu/aarch64/globalDefinitions_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/globalDefinitions_aarch64.hpp @@ -67,4 +67,6 @@ const bool CCallingConventionRequiresIntsAsLongs = false; #define NOT_R18_RESERVED(code) code #endif +#define USE_POINTERS_TO_REGISTER_IMPL_ARRAY + #endif // CPU_AARCH64_GLOBALDEFINITIONS_AARCH64_HPP diff --git a/src/hotspot/cpu/aarch64/globals_aarch64.hpp b/src/hotspot/cpu/aarch64/globals_aarch64.hpp index 82760cc3bcf066becfedc9c5fb279c2a14cd1c89..443eb46b720ab97ad5381f40c8fffa701ddd6f53 100644 --- a/src/hotspot/cpu/aarch64/globals_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/globals_aarch64.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2022, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2015, 2019, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -118,7 +118,9 @@ define_pd_global(intx, InlineSmallCode, 1000); product(uint, OnSpinWaitInstCount, 1, DIAGNOSTIC, \ "The number of OnSpinWaitInst instructions to generate." \ "It cannot be used with OnSpinWaitInst=none.") \ - range(1, 99) + range(1, 99) \ + product(ccstr, UseBranchProtection, "none", \ + "Branch Protection to use: none, standard, pac-ret") \ // end of ARCH_FLAGS diff --git a/src/hotspot/cpu/aarch64/immediate_aarch64.cpp b/src/hotspot/cpu/aarch64/immediate_aarch64.cpp index 3e38b7cca0484a4990baf7b274f9d14cbd2f0781..916494605bc12bba7b63fea589950a02d7a642b9 100644 --- a/src/hotspot/cpu/aarch64/immediate_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/immediate_aarch64.cpp @@ -129,8 +129,17 @@ static inline uint32_t uimm(uint32_t val, int hi, int lo) uint64_t replicate(uint64_t bits, int nbits, int count) { + assert(count > 0, "must be"); + assert(nbits > 0, "must be"); + assert(count * nbits <= 64, "must be"); + + // Special case nbits == 64 since the shift below with that nbits value + // would result in undefined behavior. + if (nbits == 64) { + return bits; + } + uint64_t result = 0; - // nbits may be 64 in which case we want mask to be -1 uint64_t mask = ones(nbits); for (int i = 0; i < count ; i++) { result <<= nbits; diff --git a/src/hotspot/cpu/aarch64/jniTypes_aarch64.hpp b/src/hotspot/cpu/aarch64/jniTypes_aarch64.hpp index 4254cdf4cfd575a0c57756ae6ca8f4cb59cbccc3..8d20a6a170152042c346d148347907b1c115c4f1 100644 --- a/src/hotspot/cpu/aarch64/jniTypes_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/jniTypes_aarch64.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2022, 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,7 +27,7 @@ #define CPU_AARCH64_JNITYPES_AARCH64_HPP #include "jni.h" -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" #include "oops/oop.hpp" // This file holds platform-dependent routines used to write primitive jni diff --git a/src/hotspot/cpu/aarch64/jvmciCodeInstaller_aarch64.cpp b/src/hotspot/cpu/aarch64/jvmciCodeInstaller_aarch64.cpp index 17b9780129db00d13f169645e305c7ffba0c52a0..aacca26a36c8843b80244dc4c9cdf00651767ca4 100644 --- a/src/hotspot/cpu/aarch64/jvmciCodeInstaller_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/jvmciCodeInstaller_aarch64.cpp @@ -186,7 +186,7 @@ VMReg CodeInstaller::get_hotspot_reg(jint jvmci_reg, JVMCI_TRAPS) { if (jvmci_reg < RegisterImpl::number_of_registers) { return as_Register(jvmci_reg)->as_VMReg(); } else { - jint floatRegisterNumber = jvmci_reg - RegisterImpl::number_of_registers_for_jvmci; + jint floatRegisterNumber = jvmci_reg - RegisterImpl::number_of_declared_registers; if (floatRegisterNumber >= 0 && floatRegisterNumber < FloatRegisterImpl::number_of_registers) { return as_FloatRegister(floatRegisterNumber)->as_VMReg(); } diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp index 07e3fdad17b16ac2c7b0614358884651e92a2386..ad1a6d58596ff0e08ca6f1f9b188007fad252227 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2021, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -29,6 +29,7 @@ #include "jvm.h" #include "asm/assembler.hpp" #include "asm/assembler.inline.hpp" +#include "ci/ciEnv.hpp" #include "gc/shared/barrierSet.hpp" #include "gc/shared/barrierSetAssembler.hpp" #include "gc/shared/cardTableBarrierSet.hpp" @@ -159,8 +160,7 @@ int MacroAssembler::pd_patch_instruction_size(address branch, address target) { Instruction_aarch64::patch(branch+8, 20, 5, (dest >>= 16) & 0xffff); assert(target_addr_for_insn(branch) == target, "should be"); instructions = 3; - } else if (Instruction_aarch64::extract(insn, 31, 22) == 0b1011100101 && - Instruction_aarch64::extract(insn, 4, 0) == 0b11111) { + } else if (NativeInstruction::is_ldrw_to_zr(address(&insn))) { // nothing to do assert(target == 0, "did not expect to relocate target for polling page load"); } else { @@ -283,15 +283,19 @@ address MacroAssembler::target_addr_for_insn(address insn_addr, unsigned insn) { return address(uint64_t(Instruction_aarch64::extract(insns[0], 20, 5)) + (uint64_t(Instruction_aarch64::extract(insns[1], 20, 5)) << 16) + (uint64_t(Instruction_aarch64::extract(insns[2], 20, 5)) << 32)); - } else if (Instruction_aarch64::extract(insn, 31, 22) == 0b1011100101 && - Instruction_aarch64::extract(insn, 4, 0) == 0b11111) { - return 0; } else { ShouldNotReachHere(); } return address(((uint64_t)insn_addr + (offset << 2))); } +address MacroAssembler::target_addr_for_insn_or_null(address insn_addr, unsigned insn) { + if (NativeInstruction::is_ldrw_to_zr(address(&insn))) { + return 0; + } + return MacroAssembler::target_addr_for_insn(insn_addr, insn); +} + void MacroAssembler::safepoint_poll(Label& slow_path, bool at_return, bool acquire, bool in_nmethod) { if (acquire) { lea(rscratch1, Address(rthread, JavaThread::polling_word_offset())); @@ -1133,6 +1137,8 @@ void MacroAssembler::verify_oop(Register reg, const char* s) { } BLOCK_COMMENT("verify_oop {"); + strip_return_address(); // This might happen within a stack frame. + protect_return_address(); stp(r0, rscratch1, Address(pre(sp, -2 * wordSize))); stp(rscratch2, lr, Address(pre(sp, -2 * wordSize))); @@ -1146,6 +1152,7 @@ void MacroAssembler::verify_oop(Register reg, const char* s) { ldp(rscratch2, lr, Address(post(sp, 2 * wordSize))); ldp(r0, rscratch1, Address(post(sp, 2 * wordSize))); + authenticate_return_address(); BLOCK_COMMENT("} verify_oop"); } @@ -1162,6 +1169,8 @@ void MacroAssembler::verify_oop_addr(Address addr, const char* s) { } BLOCK_COMMENT("verify_oop_addr {"); + strip_return_address(); // This might happen within a stack frame. + protect_return_address(); stp(r0, rscratch1, Address(pre(sp, -2 * wordSize))); stp(rscratch2, lr, Address(pre(sp, -2 * wordSize))); @@ -1182,6 +1191,7 @@ void MacroAssembler::verify_oop_addr(Address addr, const char* s) { ldp(rscratch2, lr, Address(post(sp, 2 * wordSize))); ldp(r0, rscratch1, Address(post(sp, 2 * wordSize))); + authenticate_return_address(); BLOCK_COMMENT("} verify_oop_addr"); } @@ -2533,7 +2543,7 @@ void MacroAssembler::debug64(char* msg, int64_t pc, int64_t regs[]) fatal("DEBUG MESSAGE: %s", msg); } -RegSet MacroAssembler::call_clobbered_registers() { +RegSet MacroAssembler::call_clobbered_gp_registers() { RegSet regs = RegSet::range(r0, r17) - RegSet::of(rscratch1, rscratch2); #ifndef R18_RESERVED regs += r18_tls; @@ -2543,7 +2553,7 @@ RegSet MacroAssembler::call_clobbered_registers() { void MacroAssembler::push_call_clobbered_registers_except(RegSet exclude) { int step = 4 * wordSize; - push(call_clobbered_registers() - exclude, sp); + push(call_clobbered_gp_registers() - exclude, sp); sub(sp, sp, step); mov(rscratch1, -step); // Push v0-v7, v16-v31. @@ -2565,7 +2575,7 @@ void MacroAssembler::pop_call_clobbered_registers_except(RegSet exclude) { reinitialize_ptrue(); - pop(call_clobbered_registers() - exclude, sp); + pop(call_clobbered_gp_registers() - exclude, sp); } void MacroAssembler::push_CPU_state(bool save_vectors, bool use_sve, @@ -3367,7 +3377,7 @@ void MacroAssembler::kernel_crc32(Register crc, Register buf, Register len, ld1r(v5, T2D, post(tmp, 8)); ld1r(v6, T2D, post(tmp, 8)); ld1r(v7, T2D, post(tmp, 8)); - mov(v16, T4S, 0, crc); + mov(v16, S, 0, crc); eor(v0, T16B, v0, v16); sub(len, len, 64); @@ -3471,16 +3481,16 @@ void MacroAssembler::kernel_crc32(Register crc, Register buf, Register len, br(Assembler::GE, L_fold); mov(crc, 0); - mov(tmp, v0, T1D, 0); + mov(tmp, v0, D, 0); update_word_crc32(crc, tmp, tmp2, table0, table1, table2, table3, false); update_word_crc32(crc, tmp, tmp2, table0, table1, table2, table3, true); - mov(tmp, v0, T1D, 1); + mov(tmp, v0, D, 1); update_word_crc32(crc, tmp, tmp2, table0, table1, table2, table3, false); update_word_crc32(crc, tmp, tmp2, table0, table1, table2, table3, true); - mov(tmp, v1, T1D, 0); + mov(tmp, v1, D, 0); update_word_crc32(crc, tmp, tmp2, table0, table1, table2, table3, false); update_word_crc32(crc, tmp, tmp2, table0, table1, table2, table3, true); - mov(tmp, v1, T1D, 1); + mov(tmp, v1, D, 1); update_word_crc32(crc, tmp, tmp2, table0, table1, table2, table3, false); update_word_crc32(crc, tmp, tmp2, table0, table1, table2, table3, true); @@ -4292,6 +4302,7 @@ void MacroAssembler::load_byte_map_base(Register reg) { void MacroAssembler::build_frame(int framesize) { assert(framesize >= 2 * wordSize, "framesize must include space for FP/LR"); assert(framesize % (2*wordSize) == 0, "must preserve 2*wordSize alignment"); + protect_return_address(); if (framesize < ((1 << 9) + 2 * wordSize)) { sub(sp, sp, framesize); stp(rfp, lr, Address(sp, framesize - 2 * wordSize)); @@ -4324,19 +4335,21 @@ void MacroAssembler::remove_frame(int framesize) { } ldp(rfp, lr, Address(post(sp, 2 * wordSize))); } + authenticate_return_address(); } -// This method checks if provided byte array contains byte with highest bit set. -address MacroAssembler::has_negatives(Register ary1, Register len, Register result) { +// This method counts leading positive bytes (highest bit not set) in provided byte array +address MacroAssembler::count_positives(Register ary1, Register len, Register result) { // Simple and most common case of aligned small array which is not at the // end of memory page is placed here. All other cases are in stub. Label LOOP, END, STUB, STUB_LONG, SET_RESULT, DONE; const uint64_t UPPER_BIT_MASK=0x8080808080808080; assert_different_registers(ary1, len, result); + mov(result, len); cmpw(len, 0); - br(LE, SET_RESULT); + br(LE, DONE); cmpw(len, 4 * wordSize); br(GE, STUB_LONG); // size > 32 then go to stub @@ -4355,19 +4368,20 @@ address MacroAssembler::has_negatives(Register ary1, Register len, Register resu subs(len, len, wordSize); br(GE, LOOP); cmpw(len, -wordSize); - br(EQ, SET_RESULT); + br(EQ, DONE); BIND(END); - ldr(result, Address(ary1)); - sub(len, zr, len, LSL, 3); // LSL 3 is to get bits from bytes - lslv(result, result, len); - tst(result, UPPER_BIT_MASK); - b(SET_RESULT); + ldr(rscratch1, Address(ary1)); + sub(rscratch2, zr, len, LSL, 3); // LSL 3 is to get bits from bytes + lslv(rscratch1, rscratch1, rscratch2); + tst(rscratch1, UPPER_BIT_MASK); + br(NE, SET_RESULT); + b(DONE); BIND(STUB); - RuntimeAddress has_neg = RuntimeAddress(StubRoutines::aarch64::has_negatives()); - assert(has_neg.target() != NULL, "has_negatives stub has not been generated"); - address tpc1 = trampoline_call(has_neg); + RuntimeAddress count_pos = RuntimeAddress(StubRoutines::aarch64::count_positives()); + assert(count_pos.target() != NULL, "count_positives stub has not been generated"); + address tpc1 = trampoline_call(count_pos); if (tpc1 == NULL) { DEBUG_ONLY(reset_labels(STUB_LONG, SET_RESULT, DONE)); postcond(pc() == badAddress); @@ -4376,9 +4390,9 @@ address MacroAssembler::has_negatives(Register ary1, Register len, Register resu b(DONE); BIND(STUB_LONG); - RuntimeAddress has_neg_long = RuntimeAddress(StubRoutines::aarch64::has_negatives_long()); - assert(has_neg_long.target() != NULL, "has_negatives stub has not been generated"); - address tpc2 = trampoline_call(has_neg_long); + RuntimeAddress count_pos_long = RuntimeAddress(StubRoutines::aarch64::count_positives_long()); + assert(count_pos_long.target() != NULL, "count_positives_long stub has not been generated"); + address tpc2 = trampoline_call(count_pos_long); if (tpc2 == NULL) { DEBUG_ONLY(reset_labels(SET_RESULT, DONE)); postcond(pc() == badAddress); @@ -4387,7 +4401,9 @@ address MacroAssembler::has_negatives(Register ary1, Register len, Register resu b(DONE); BIND(SET_RESULT); - cset(result, NE); // set true or false + + add(len, len, wordSize); + sub(result, result, len); BIND(DONE); postcond(pc() != badAddress); @@ -4923,111 +4939,118 @@ void MacroAssembler::fill_words(Register base, Register cnt, Register value) bind(fini); } -// Intrinsic for sun/nio/cs/ISO_8859_1$Encoder.implEncodeISOArray and -// java/lang/StringUTF16.compress. +// Intrinsic for +// +// - sun/nio/cs/ISO_8859_1$Encoder.implEncodeISOArray +// return the number of characters copied. +// - java/lang/StringUTF16.compress +// return zero (0) if copy fails, otherwise 'len'. +// +// This version always returns the number of characters copied, and does not +// clobber the 'len' register. A successful copy will complete with the post- +// condition: 'res' == 'len', while an unsuccessful copy will exit with the +// post-condition: 0 <= 'res' < 'len'. +// +// NOTE: Attempts to use 'ld2' (and 'umaxv' in the ISO part) has proven to +// degrade performance (on Ampere Altra - Neoverse N1), to an extent +// beyond the acceptable, even though the footprint would be smaller. +// Using 'umaxv' in the ASCII-case comes with a small penalty but does +// avoid additional bloat. +// void MacroAssembler::encode_iso_array(Register src, Register dst, - Register len, Register result, - FloatRegister Vtmp1, FloatRegister Vtmp2, - FloatRegister Vtmp3, FloatRegister Vtmp4) + Register len, Register res, bool ascii, + FloatRegister vtmp0, FloatRegister vtmp1, + FloatRegister vtmp2, FloatRegister vtmp3) { - Label DONE, SET_RESULT, NEXT_32, NEXT_32_PRFM, LOOP_8, NEXT_8, LOOP_1, NEXT_1, - NEXT_32_START, NEXT_32_PRFM_START; - Register tmp1 = rscratch1, tmp2 = rscratch2; - - mov(result, len); // Save initial len - - cmp(len, (u1)8); // handle shortest strings first - br(LT, LOOP_1); - cmp(len, (u1)32); - br(LT, NEXT_8); - // The following code uses the SIMD 'uzp1' and 'uzp2' instructions - // to convert chars to bytes - if (SoftwarePrefetchHintDistance >= 0) { - ld1(Vtmp1, Vtmp2, Vtmp3, Vtmp4, T8H, src); - subs(tmp2, len, SoftwarePrefetchHintDistance/2 + 16); - br(LE, NEXT_32_START); - b(NEXT_32_PRFM_START); - BIND(NEXT_32_PRFM); - ld1(Vtmp1, Vtmp2, Vtmp3, Vtmp4, T8H, src); - BIND(NEXT_32_PRFM_START); - prfm(Address(src, SoftwarePrefetchHintDistance)); - orr(v4, T16B, Vtmp1, Vtmp2); - orr(v5, T16B, Vtmp3, Vtmp4); - uzp1(Vtmp1, T16B, Vtmp1, Vtmp2); - uzp1(Vtmp3, T16B, Vtmp3, Vtmp4); - uzp2(v5, T16B, v4, v5); // high bytes - umov(tmp2, v5, D, 1); - fmovd(tmp1, v5); - orr(tmp1, tmp1, tmp2); - cbnz(tmp1, LOOP_8); - stpq(Vtmp1, Vtmp3, dst); - sub(len, len, 32); - add(dst, dst, 32); - add(src, src, 64); - subs(tmp2, len, SoftwarePrefetchHintDistance/2 + 16); - br(GE, NEXT_32_PRFM); - cmp(len, (u1)32); - br(LT, LOOP_8); - BIND(NEXT_32); - ld1(Vtmp1, Vtmp2, Vtmp3, Vtmp4, T8H, src); - BIND(NEXT_32_START); - } else { - BIND(NEXT_32); - ld1(Vtmp1, Vtmp2, Vtmp3, Vtmp4, T8H, src); - } - prfm(Address(src, SoftwarePrefetchHintDistance)); - uzp1(v4, T16B, Vtmp1, Vtmp2); - uzp1(v5, T16B, Vtmp3, Vtmp4); - orr(Vtmp1, T16B, Vtmp1, Vtmp2); - orr(Vtmp3, T16B, Vtmp3, Vtmp4); - uzp2(Vtmp1, T16B, Vtmp1, Vtmp3); // high bytes - umov(tmp2, Vtmp1, D, 1); - fmovd(tmp1, Vtmp1); - orr(tmp1, tmp1, tmp2); - cbnz(tmp1, LOOP_8); - stpq(v4, v5, dst); - sub(len, len, 32); - add(dst, dst, 32); - add(src, src, 64); - cmp(len, (u1)32); - br(GE, NEXT_32); - cbz(len, DONE); - - BIND(LOOP_8); - cmp(len, (u1)8); - br(LT, LOOP_1); - BIND(NEXT_8); - ld1(Vtmp1, T8H, src); - uzp1(Vtmp2, T16B, Vtmp1, Vtmp1); // low bytes - uzp2(Vtmp3, T16B, Vtmp1, Vtmp1); // high bytes - fmovd(tmp1, Vtmp3); - cbnz(tmp1, NEXT_1); - strd(Vtmp2, dst); - - sub(len, len, 8); - add(dst, dst, 8); - add(src, src, 16); - cmp(len, (u1)8); - br(GE, NEXT_8); - - BIND(LOOP_1); - - cbz(len, DONE); - BIND(NEXT_1); - ldrh(tmp1, Address(post(src, 2))); - tst(tmp1, 0xff00); - br(NE, SET_RESULT); - strb(tmp1, Address(post(dst, 1))); - subs(len, len, 1); - br(GT, NEXT_1); - - BIND(SET_RESULT); - sub(result, result, len); // Return index where we stopped - // Return len == 0 if we processed all - // characters - BIND(DONE); -} + Register cnt = res; + Register max = rscratch1; + Register chk = rscratch2; + + prfm(Address(src), PLDL1STRM); + movw(cnt, len); +#define ASCII(insn) do { if (ascii) { insn; } } while (0) + + Label LOOP_32, DONE_32, FAIL_32; + + BIND(LOOP_32); + { + cmpw(cnt, 32); + br(LT, DONE_32); + ld1(vtmp0, vtmp1, vtmp2, vtmp3, T8H, Address(post(src, 64))); + // Extract lower bytes. + FloatRegister vlo0 = v4; + FloatRegister vlo1 = v5; + uzp1(vlo0, T16B, vtmp0, vtmp1); + uzp1(vlo1, T16B, vtmp2, vtmp3); + // Merge bits... + orr(vtmp0, T16B, vtmp0, vtmp1); + orr(vtmp2, T16B, vtmp2, vtmp3); + // Extract merged upper bytes. + FloatRegister vhix = vtmp0; + uzp2(vhix, T16B, vtmp0, vtmp2); + // ISO-check on hi-parts (all zero). + // ASCII-check on lo-parts (no sign). + FloatRegister vlox = vtmp1; // Merge lower bytes. + ASCII(orr(vlox, T16B, vlo0, vlo1)); + umov(chk, vhix, D, 1); ASCII(cmlt(vlox, T16B, vlox)); + fmovd(max, vhix); ASCII(umaxv(vlox, T16B, vlox)); + orr(chk, chk, max); ASCII(umov(max, vlox, B, 0)); + ASCII(orr(chk, chk, max)); + cbnz(chk, FAIL_32); + subw(cnt, cnt, 32); + st1(vlo0, vlo1, T16B, Address(post(dst, 32))); + b(LOOP_32); + } + BIND(FAIL_32); + sub(src, src, 64); + BIND(DONE_32); + + Label LOOP_8, SKIP_8; + + BIND(LOOP_8); + { + cmpw(cnt, 8); + br(LT, SKIP_8); + FloatRegister vhi = vtmp0; + FloatRegister vlo = vtmp1; + ld1(vtmp3, T8H, src); + uzp1(vlo, T16B, vtmp3, vtmp3); + uzp2(vhi, T16B, vtmp3, vtmp3); + // ISO-check on hi-parts (all zero). + // ASCII-check on lo-parts (no sign). + ASCII(cmlt(vtmp2, T16B, vlo)); + fmovd(chk, vhi); ASCII(umaxv(vtmp2, T16B, vtmp2)); + ASCII(umov(max, vtmp2, B, 0)); + ASCII(orr(chk, chk, max)); + cbnz(chk, SKIP_8); + + strd(vlo, Address(post(dst, 8))); + subw(cnt, cnt, 8); + add(src, src, 16); + b(LOOP_8); + } + BIND(SKIP_8); + +#undef ASCII + + Label LOOP, DONE; + + cbz(cnt, DONE); + BIND(LOOP); + { + Register chr = rscratch1; + ldrh(chr, Address(post(src, 2))); + tst(chr, ascii ? 0xff80 : 0xff00); + br(NE, DONE); + strb(chr, Address(post(dst, 1))); + subs(cnt, cnt, 1); + br(GT, LOOP); + } + BIND(DONE); + // Return index where we stopped. + subw(res, len, cnt); +} // Inflate byte[] array to char[]. address MacroAssembler::byte_array_inflate(Register src, Register dst, Register len, @@ -5136,13 +5159,13 @@ address MacroAssembler::byte_array_inflate(Register src, Register dst, Register // Compress char[] array to byte[]. void MacroAssembler::char_array_compress(Register src, Register dst, Register len, - FloatRegister tmp1Reg, FloatRegister tmp2Reg, - FloatRegister tmp3Reg, FloatRegister tmp4Reg, - Register result) { - encode_iso_array(src, dst, len, result, - tmp1Reg, tmp2Reg, tmp3Reg, tmp4Reg); - cmp(len, zr); - csel(result, result, zr, EQ); + Register res, + FloatRegister tmp0, FloatRegister tmp1, + FloatRegister tmp2, FloatRegister tmp3) { + encode_iso_array(src, dst, len, res, false, tmp0, tmp1, tmp2, tmp3); + // Adjust result: res == len ? len : 0 + cmp(len, res); + csel(res, res, zr, EQ); } // get_thread() can be called anywhere inside generated code so we @@ -5158,6 +5181,7 @@ void MacroAssembler::get_thread(Register dst) { LINUX_ONLY(RegSet::range(r0, r1) + lr - dst) NOT_LINUX (RegSet::range(r0, r17) + lr - dst); + protect_return_address(); push(saved_regs, sp); mov(lr, CAST_FROM_FN_PTR(address, JavaThread::aarch64_get_thread_helper)); @@ -5167,6 +5191,7 @@ void MacroAssembler::get_thread(Register dst) { } pop(saved_regs, sp); + authenticate_return_address(); } void MacroAssembler::cache_wb(Address line) { @@ -5258,3 +5283,102 @@ void MacroAssembler::spin_wait() { } } } + +// Stack frame creation/removal + +void MacroAssembler::enter(bool strip_ret_addr) { + if (strip_ret_addr) { + // Addresses can only be signed once. If there are multiple nested frames being created + // in the same function, then the return address needs stripping first. + strip_return_address(); + } + protect_return_address(); + stp(rfp, lr, Address(pre(sp, -2 * wordSize))); + mov(rfp, sp); +} + +void MacroAssembler::leave() { + mov(sp, rfp); + ldp(rfp, lr, Address(post(sp, 2 * wordSize))); + authenticate_return_address(); +} + +// ROP Protection +// Use the AArch64 PAC feature to add ROP protection for generated code. Use whenever creating/ +// destroying stack frames or whenever directly loading/storing the LR to memory. +// If ROP protection is not set then these functions are no-ops. +// For more details on PAC see pauth_aarch64.hpp. + +// Sign the LR. Use during construction of a stack frame, before storing the LR to memory. +// Uses the FP as the modifier. +// +void MacroAssembler::protect_return_address() { + if (VM_Version::use_rop_protection()) { + check_return_address(); + // The standard convention for C code is to use paciasp, which uses SP as the modifier. This + // works because in C code, FP and SP match on function entry. In the JDK, SP and FP may not + // match, so instead explicitly use the FP. + pacia(lr, rfp); + } +} + +// Sign the return value in the given register. Use before updating the LR in the exisiting stack +// frame for the current function. +// Uses the FP from the start of the function as the modifier - which is stored at the address of +// the current FP. +// +void MacroAssembler::protect_return_address(Register return_reg, Register temp_reg) { + if (VM_Version::use_rop_protection()) { + assert(PreserveFramePointer, "PreserveFramePointer must be set for ROP protection"); + check_return_address(return_reg); + ldr(temp_reg, Address(rfp)); + pacia(return_reg, temp_reg); + } +} + +// Authenticate the LR. Use before function return, after restoring FP and loading LR from memory. +// +void MacroAssembler::authenticate_return_address(Register return_reg) { + if (VM_Version::use_rop_protection()) { + autia(return_reg, rfp); + check_return_address(return_reg); + } +} + +// Authenticate the return value in the given register. Use before updating the LR in the exisiting +// stack frame for the current function. +// Uses the FP from the start of the function as the modifier - which is stored at the address of +// the current FP. +// +void MacroAssembler::authenticate_return_address(Register return_reg, Register temp_reg) { + if (VM_Version::use_rop_protection()) { + assert(PreserveFramePointer, "PreserveFramePointer must be set for ROP protection"); + ldr(temp_reg, Address(rfp)); + autia(return_reg, temp_reg); + check_return_address(return_reg); + } +} + +// Strip any PAC data from LR without performing any authentication. Use with caution - only if +// there is no guaranteed way of authenticating the LR. +// +void MacroAssembler::strip_return_address() { + if (VM_Version::use_rop_protection()) { + xpaclri(); + } +} + +#ifndef PRODUCT +// PAC failures can be difficult to debug. After an authentication failure, a segfault will only +// occur when the pointer is used - ie when the program returns to the invalid LR. At this point +// it is difficult to debug back to the callee function. +// This function simply loads from the address in the given register. +// Use directly after authentication to catch authentication failures. +// Also use before signing to check that the pointer is valid and hasn't already been signed. +// +void MacroAssembler::check_return_address(Register return_reg) { + if (VM_Version::use_rop_protection()) { + ldr(zr, Address(return_reg)); + } +} +#endif diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp index a9ebc8bdc69196fe97229633737f99992c20701f..d5bfc42e784d43070918d936f30c042d2b259a19 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2021, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -27,6 +27,7 @@ #define CPU_AARCH64_MACROASSEMBLER_AARCH64_HPP #include "asm/assembler.inline.hpp" +#include "metaprogramming/enableIf.hpp" #include "oops/compressedOops.hpp" #include "runtime/vm_version.hpp" #include "utilities/powerOfTwo.hpp" @@ -467,7 +468,7 @@ public: void push_fp(FloatRegSet regs, Register stack) { if (regs.bits()) push_fp(regs.bits(), stack); } void pop_fp(FloatRegSet regs, Register stack) { if (regs.bits()) pop_fp(regs.bits(), stack); } - static RegSet call_clobbered_registers(); + static RegSet call_clobbered_gp_registers(); void push_p(PRegSet regs, Register stack) { if (regs.bits()) push_p(regs.bits(), stack); } void pop_p(PRegSet regs, Register stack) { if (regs.bits()) pop_p(regs.bits(), stack); } @@ -493,17 +494,10 @@ public: inline void mov(Register dst, address addr) { mov_immediate64(dst, (uint64_t)addr); } - inline void mov(Register dst, int imm64) { mov_immediate64(dst, (uint64_t)imm64); } - inline void mov(Register dst, long imm64) { mov_immediate64(dst, (uint64_t)imm64); } - inline void mov(Register dst, long long imm64) { mov_immediate64(dst, (uint64_t)imm64); } - inline void mov(Register dst, unsigned int imm64) { mov_immediate64(dst, (uint64_t)imm64); } - inline void mov(Register dst, unsigned long imm64) { mov_immediate64(dst, (uint64_t)imm64); } - inline void mov(Register dst, unsigned long long imm64) { mov_immediate64(dst, (uint64_t)imm64); } + template::value)> + inline void mov(Register dst, T o) { mov_immediate64(dst, (uint64_t)o); } - inline void movw(Register dst, uint32_t imm32) - { - mov_immediate32(dst, imm32); - } + inline void movw(Register dst, uint32_t imm32) { mov_immediate32(dst, imm32); } void mov(Register dst, RegisterOrConstant src) { if (src.is_register()) @@ -606,10 +600,15 @@ public: static bool uses_implicit_null_check(void* address); static address target_addr_for_insn(address insn_addr, unsigned insn); + static address target_addr_for_insn_or_null(address insn_addr, unsigned insn); static address target_addr_for_insn(address insn_addr) { unsigned insn = *(unsigned*)insn_addr; return target_addr_for_insn(insn_addr, insn); } + static address target_addr_for_insn_or_null(address insn_addr) { + unsigned insn = *(unsigned*)insn_addr; + return target_addr_for_insn_or_null(insn_addr, insn); + } // Required platform-specific helpers for Label::patch_instructions. // They _shadow_ the declarations in AbstractAssembler, which are undefined. @@ -689,16 +688,16 @@ public: void align(int modulus); // Stack frame creation/removal - void enter() - { - stp(rfp, lr, Address(pre(sp, -2 * wordSize))); - mov(rfp, sp); - } - void leave() - { - mov(sp, rfp); - ldp(rfp, lr, Address(post(sp, 2 * wordSize))); - } + void enter(bool strip_ret_addr = false); + void leave(); + + // ROP Protection + void protect_return_address(); + void protect_return_address(Register return_reg, Register temp_reg); + void authenticate_return_address(Register return_reg = lr); + void authenticate_return_address(Register return_reg, Register temp_reg); + void strip_return_address(); + void check_return_address(Register return_reg=lr) PRODUCT_RETURN; // Support for getting the JavaThread pointer (i.e.; a reference to thread-local information) // The pointer will be loaded into the thread register. @@ -1235,7 +1234,7 @@ public: Register table0, Register table1, Register table2, Register table3, bool upper = false); - address has_negatives(Register ary1, Register len, Register result); + address count_positives(Register ary1, Register len, Register result); address arrays_equals(Register a1, Register a2, Register result, Register cnt1, Register tmp1, Register tmp2, Register tmp3, int elem_size); @@ -1255,14 +1254,15 @@ public: FloatRegister vtmp3, Register tmp4); void char_array_compress(Register src, Register dst, Register len, - FloatRegister tmp1Reg, FloatRegister tmp2Reg, - FloatRegister tmp3Reg, FloatRegister tmp4Reg, - Register result); + Register res, + FloatRegister vtmp0, FloatRegister vtmp1, + FloatRegister vtmp2, FloatRegister vtmp3); void encode_iso_array(Register src, Register dst, - Register len, Register result, - FloatRegister Vtmp1, FloatRegister Vtmp2, - FloatRegister Vtmp3, FloatRegister Vtmp4); + Register len, Register res, bool ascii, + FloatRegister vtmp0, FloatRegister vtmp1, + FloatRegister vtmp2, FloatRegister vtmp3); + void fast_log(FloatRegister vtmp0, FloatRegister vtmp1, FloatRegister vtmp2, FloatRegister vtmp3, FloatRegister vtmp4, FloatRegister vtmp5, FloatRegister tmpC1, FloatRegister tmpC2, FloatRegister tmpC3, diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64_log.cpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64_log.cpp index d65c3df226d7d4270d33bc03eb21778f8ce6cdc7..45772ff1afd63a2d1f14482bf05bbc9f8f536055 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64_log.cpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64_log.cpp @@ -297,7 +297,8 @@ void MacroAssembler::fast_log(FloatRegister vtmp0, FloatRegister vtmp1, bind(MAIN); fmovs(tmp3, vtmp5); // int intB0 = AS_INT_BITS(B); mov(tmp5, 0x3FE0); - mov(rscratch1, 0xffffe00000000000); + uint64_t mask = UCONST64(0xffffe00000000000); + mov(rscratch1, mask); andr(tmp2, tmp2, tmp1, LSR, 48); // hiWord & 0x7FF0 sub(tmp2, tmp2, tmp5); // tmp2 = hiWord & 0x7FF0 - 0x3FE0 scvtfwd(vtmp5, tmp2); // vtmp5 = (double)tmp2; diff --git a/src/hotspot/cpu/aarch64/matcher_aarch64.hpp b/src/hotspot/cpu/aarch64/matcher_aarch64.hpp index e0bb39f9e5ffcf61690572f368aa84dc39796cff..c2f801f408ade3700e79d217b418504a08d5fb7e 100644 --- a/src/hotspot/cpu/aarch64/matcher_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/matcher_aarch64.hpp @@ -55,9 +55,6 @@ // No support for generic vector operands. static const bool supports_generic_vector_operands = false; - // No support for 48 extra htbl entries in aes-gcm intrinsic - static const int htbl_entries = 0; - static constexpr bool isSimpleConstant64(jlong value) { // Will one (StoreL ConL) be cheaper than two (StoreI ConI)?. // Probably always true, even if a temp register is required. @@ -164,6 +161,12 @@ } // Implements a variant of EncodeISOArrayNode that encode ASCII only - static const bool supports_encode_ascii_array = false; + static const bool supports_encode_ascii_array = true; + + // Returns pre-selection estimated size of a vector operation. + static int vector_op_pre_select_sz_estimate(int vopc, BasicType ety, int vlen) { + return 0; + } + #endif // CPU_AARCH64_MATCHER_AARCH64_HPP diff --git a/src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp b/src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp index d808e4b5b53de9eb13da164cca7dc24871a72dbd..7599c21c2fcaa88e107b457f5963e19ba9f6d48d 100644 --- a/src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -315,7 +315,7 @@ void NativeMovRegMem::set_offset(int x) { void NativeMovRegMem::verify() { #ifdef ASSERT - address dest = MacroAssembler::target_addr_for_insn(instruction_address()); + address dest = MacroAssembler::target_addr_for_insn_or_null(instruction_address()); #endif } @@ -329,7 +329,7 @@ void NativeJump::check_verified_entry_alignment(address entry, address verified_ address NativeJump::jump_destination() const { - address dest = MacroAssembler::target_addr_for_insn(instruction_address()); + address dest = MacroAssembler::target_addr_for_insn_or_null(instruction_address()); // We use jump to self as the unresolved address which the inline // cache code (and relocs) know about diff --git a/src/hotspot/cpu/aarch64/pauth_aarch64.hpp b/src/hotspot/cpu/aarch64/pauth_aarch64.hpp index e12a671daf1e2552cab87b3ac3344bb9a5d61b65..fe5fbbce9f05f22aea98bfee586123c113764023 100644 --- a/src/hotspot/cpu/aarch64/pauth_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/pauth_aarch64.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Arm Limited. All rights reserved. + * Copyright (c) 2021, 2022, 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 @@ -27,9 +27,58 @@ #include OS_CPU_HEADER_INLINE(pauth) +// Support for ROP Protection in VM code. +// This is provided via the AArch64 PAC feature. +// For more details on PAC see The Arm ARM, section "Pointer authentication in AArch64 state". +// +// PAC provides a method to sign and authenticate pointer values. Signing combines the register +// being signed, an additional modifier and a per-process secret key, writing the result to unused +// high bits of the signed register. Once signed a register must be authenticated or stripped +// before it can be used. +// Authentication reverses the signing operation, clearing the high bits. If the signed register +// or modifier has changed then authentication will fail and invalid data will be written to the +// high bits and the next time the pointer is used a segfault will be raised. +// +// Assume a malicious attacker is able to edit the stack via an exploit. Control flow can be +// changed by re-writing the return values stored on the stack. ROP protection prevents this by +// signing return addresses before saving them on the stack, then authenticating when they are +// loaded back. The scope of this protection is per function (a value is signed and authenticated +// by the same function), therefore it is possible for different functions within the same +// program to use different signing methods. +// +// The VM and native code is protected by compiling with the GCC AArch64 branch protection flag. +// +// All generated code is protected via the ROP functions provided in macroAssembler. +// +// In addition, the VM needs to be aware of PAC whenever viewing or editing the stack. Functions +// are provided here and in the OS specific files. We should assume all stack frames for generated +// code have signed return values. Rewriting the stack should ensure new values are correctly +// signed. However, we cannot make any assumptions about how (or if) native code uses PAC - here +// we should limit access to viewing via stripping. +// + + +// Confirm the given pointer has not been signed - ie none of the high bits are set. +// +// Note this can give false positives. The PAC signing can generate a signature with all signing +// bits as zeros, causing this function to return true. Therefore this should only be used for +// assert style checking. In addition, this function should never be used with a "not" to confirm +// a pointer is signed, as it will fail the above case. The only safe way to do this is to instead +// authenticate the pointer. +// inline bool pauth_ptr_is_raw(address ptr) { - // Confirm none of the high bits are set in the pointer. return ptr == pauth_strip_pointer(ptr); } +// Strip a return value (same as pauth_strip_pointer). When debug is enabled then authenticate +// instead. +// +inline address pauth_strip_verifiable(address ret_addr, address modifier) { + if (VM_Version::use_rop_protection()) { + DEBUG_ONLY(ret_addr = pauth_authenticate_return_address(ret_addr, modifier);) + NOT_DEBUG(ret_addr = pauth_strip_pointer(ret_addr)); + } + return ret_addr; +} + #endif // CPU_AARCH64_PAUTH_AARCH64_HPP diff --git a/src/hotspot/cpu/aarch64/register_aarch64.cpp b/src/hotspot/cpu/aarch64/register_aarch64.cpp index b785457ae29ccdc206d839ca0121912366af5a3e..096e480a824cc21c6e250aa057e7bba2497fca4d 100644 --- a/src/hotspot/cpu/aarch64/register_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/register_aarch64.cpp @@ -26,6 +26,10 @@ #include "precompiled.hpp" #include "register_aarch64.hpp" +REGISTER_IMPL_DEFINITION(Register, RegisterImpl, RegisterImpl::number_of_declared_registers); +REGISTER_IMPL_DEFINITION(FloatRegister, FloatRegisterImpl, FloatRegisterImpl::number_of_registers); +REGISTER_IMPL_DEFINITION(PRegister, PRegisterImpl, PRegisterImpl::number_of_registers); + const int ConcreteRegisterImpl::max_gpr = RegisterImpl::number_of_registers * RegisterImpl::max_slots_per_register; @@ -38,7 +42,7 @@ const int ConcreteRegisterImpl::max_pr PRegisterImpl::number_of_registers * PRegisterImpl::max_slots_per_register; const char* RegisterImpl::name() const { - const char* names[number_of_registers] = { + static const char *const names[number_of_registers] = { "c_rarg0", "c_rarg1", "c_rarg2", "c_rarg3", "c_rarg4", "c_rarg5", "c_rarg6", "c_rarg7", "rscratch1", "rscratch2", "r10", "r11", "r12", "r13", "r14", "r15", "r16", @@ -50,7 +54,7 @@ const char* RegisterImpl::name() const { } const char* FloatRegisterImpl::name() const { - const char* names[number_of_registers] = { + static const char *const names[number_of_registers] = { "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15", "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", @@ -60,7 +64,7 @@ const char* FloatRegisterImpl::name() const { } const char* PRegisterImpl::name() const { - const char* names[number_of_registers] = { + static const char *const names[number_of_registers] = { "p0", "p1", "p2", "p3", "p4", "p5", "p6", "p7", "p8", "p9", "p10", "p11", "p12", "p13", "p14", "p15" }; diff --git a/src/hotspot/cpu/aarch64/register_aarch64.hpp b/src/hotspot/cpu/aarch64/register_aarch64.hpp index 69a0a7eb535de7b546e76610c1209dac70d37c85..3fe2fae42a16c3ac24c8f320c45a5029f10854f2 100644 --- a/src/hotspot/cpu/aarch64/register_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/register_aarch64.hpp @@ -34,42 +34,42 @@ typedef VMRegImpl* VMReg; // Use Register as shortcut class RegisterImpl; -typedef RegisterImpl* Register; +typedef const RegisterImpl* Register; -inline const Register as_Register(int encoding) { - return (Register)(intptr_t) encoding; -} +inline constexpr Register as_Register(int encoding); class RegisterImpl: public AbstractRegisterImpl { - public: + static constexpr Register first(); + +public: enum { number_of_registers = 32, - number_of_byte_registers = 32, - number_of_registers_for_jvmci = 34, // Including SP and ZR. + number_of_declared_registers = 34, // Including SP and ZR. max_slots_per_register = 2 }; // derived registers, offsets, and addresses - Register successor() const { return as_Register(encoding() + 1); } + const Register successor() const { return this + 1; } // construction - inline friend const Register as_Register(int encoding); + inline friend constexpr Register as_Register(int encoding); - VMReg as_VMReg(); + VMReg as_VMReg() const; // accessors - int encoding() const { assert(is_valid(), "invalid register"); return (intptr_t)this; } - bool is_valid() const { return 0 <= (intptr_t)this && (intptr_t)this < number_of_registers; } - bool has_byte_register() const { return 0 <= (intptr_t)this && (intptr_t)this < number_of_byte_registers; } + int encoding() const { assert(is_valid(), "invalid register"); return encoding_nocheck(); } + bool is_valid() const { return (unsigned)encoding_nocheck() < number_of_registers; } const char* name() const; - int encoding_nocheck() const { return (intptr_t)this; } + int encoding_nocheck() const { return this - first(); } }; + +REGISTER_IMPL_DECLARATION(Register, RegisterImpl, RegisterImpl::number_of_declared_registers); + // The integer registers of the aarch64 architecture CONSTANT_REGISTER_DECLARATION(Register, noreg, (-1)); - CONSTANT_REGISTER_DECLARATION(Register, r0, (0)); CONSTANT_REGISTER_DECLARATION(Register, r1, (1)); CONSTANT_REGISTER_DECLARATION(Register, r2, (2)); @@ -126,15 +126,15 @@ const Register dummy_reg = r31_sp; // Use FloatRegister as shortcut class FloatRegisterImpl; -typedef FloatRegisterImpl* FloatRegister; +typedef const FloatRegisterImpl* FloatRegister; -inline FloatRegister as_FloatRegister(int encoding) { - return (FloatRegister)(intptr_t) encoding; -} +inline constexpr FloatRegister as_FloatRegister(int encoding); // The implementation of floating point registers for the architecture class FloatRegisterImpl: public AbstractRegisterImpl { - public: + static constexpr FloatRegister first(); + +public: enum { number_of_registers = 32, max_slots_per_register = 8, @@ -144,21 +144,25 @@ class FloatRegisterImpl: public AbstractRegisterImpl { }; // construction - inline friend FloatRegister as_FloatRegister(int encoding); + inline friend constexpr FloatRegister as_FloatRegister(int encoding); - VMReg as_VMReg(); + VMReg as_VMReg() const; // derived registers, offsets, and addresses - FloatRegister successor() const { return as_FloatRegister((encoding() + 1) % 32); } + FloatRegister successor() const { + return as_FloatRegister((encoding() + 1) % (unsigned)number_of_registers); + } // accessors - int encoding() const { assert(is_valid(), "invalid register"); return (intptr_t)this; } - int encoding_nocheck() const { return (intptr_t)this; } - bool is_valid() const { return 0 <= (intptr_t)this && (intptr_t)this < number_of_registers; } + int encoding() const { assert(is_valid(), "invalid register"); return encoding_nocheck(); } + bool is_valid() const { return (unsigned)encoding_nocheck() < number_of_registers; } const char* name() const; - + int encoding_nocheck() const { return this - first(); } }; +REGISTER_IMPL_DECLARATION(FloatRegister, FloatRegisterImpl, FloatRegisterImpl::number_of_registers); + + // The float registers of the AARCH64 architecture CONSTANT_REGISTER_DECLARATION(FloatRegister, fnoreg , (-1)); @@ -232,13 +236,13 @@ CONSTANT_REGISTER_DECLARATION(FloatRegister, z31 , (31)); class PRegisterImpl; -typedef PRegisterImpl* PRegister; -inline PRegister as_PRegister(int encoding) { - return (PRegister)(intptr_t)encoding; -} +typedef const PRegisterImpl* PRegister; +inline constexpr PRegister as_PRegister(int encoding); // The implementation of predicate registers for the architecture class PRegisterImpl: public AbstractRegisterImpl { + static constexpr PRegister first(); + public: enum { number_of_registers = 16, @@ -252,21 +256,24 @@ class PRegisterImpl: public AbstractRegisterImpl { }; // construction - inline friend PRegister as_PRegister(int encoding); + inline friend constexpr PRegister as_PRegister(int encoding); - VMReg as_VMReg(); + VMReg as_VMReg() const; // derived registers, offsets, and addresses - PRegister successor() const { return as_PRegister(encoding() + 1); } + PRegister successor() const { return this + 1; } // accessors - int encoding() const { assert(is_valid(), "invalid register"); return (intptr_t)this; } - int encoding_nocheck() const { return (intptr_t)this; } - bool is_valid() const { return 0 <= (intptr_t)this && (intptr_t)this < number_of_registers; } - bool is_governing() const { return 0 <= (intptr_t)this && (intptr_t)this < number_of_governing_registers; } + int encoding() const { assert(is_valid(), "invalid register"); return encoding_nocheck(); } + int encoding_nocheck() const { return this - first(); } + bool is_valid() const { return (unsigned)encoding_nocheck() < number_of_registers; } + bool is_governing() const { return first() <= this && this - first() < number_of_governing_registers; } const char* name() const; }; + +REGISTER_IMPL_DECLARATION(PRegister, PRegisterImpl, PRegisterImpl::number_of_registers); + // The predicate registers of SVE. CONSTANT_REGISTER_DECLARATION(PRegister, p0, ( 0)); CONSTANT_REGISTER_DECLARATION(PRegister, p1, ( 1)); @@ -307,115 +314,10 @@ class ConcreteRegisterImpl : public AbstractRegisterImpl { static const int max_pr; }; -template class RegSetIterator; - -// A set of registers -template -class AbstractRegSet { - uint32_t _bitset; - - AbstractRegSet(uint32_t bitset) : _bitset(bitset) { } - -public: - - AbstractRegSet() : _bitset(0) { } - - AbstractRegSet(RegImpl r1) : _bitset(1 << r1->encoding()) { } - - AbstractRegSet operator+(const AbstractRegSet aSet) const { - AbstractRegSet result(_bitset | aSet._bitset); - return result; - } - - AbstractRegSet operator-(const AbstractRegSet aSet) const { - AbstractRegSet result(_bitset & ~aSet._bitset); - return result; - } - - AbstractRegSet &operator+=(const AbstractRegSet aSet) { - *this = *this + aSet; - return *this; - } - - AbstractRegSet &operator-=(const AbstractRegSet aSet) { - *this = *this - aSet; - return *this; - } - - static AbstractRegSet of(RegImpl r1) { - return AbstractRegSet(r1); - } - - static AbstractRegSet of(RegImpl r1, RegImpl r2) { - return of(r1) + r2; - } - - static AbstractRegSet of(RegImpl r1, RegImpl r2, RegImpl r3) { - return of(r1, r2) + r3; - } - - static AbstractRegSet of(RegImpl r1, RegImpl r2, RegImpl r3, RegImpl r4) { - return of(r1, r2, r3) + r4; - } - - static AbstractRegSet range(RegImpl start, RegImpl end) { - uint32_t bits = ~0; - bits <<= start->encoding(); - bits <<= 31 - end->encoding(); - bits >>= 31 - end->encoding(); - - return AbstractRegSet(bits); - } - - uint32_t bits() const { return _bitset; } - -private: - - RegImpl first(); - -public: - - friend class RegSetIterator; - - RegSetIterator begin(); -}; - typedef AbstractRegSet RegSet; typedef AbstractRegSet FloatRegSet; typedef AbstractRegSet PRegSet; -template -class RegSetIterator { - AbstractRegSet _regs; - -public: - RegSetIterator(AbstractRegSet x): _regs(x) {} - RegSetIterator(const RegSetIterator& mit) : _regs(mit._regs) {} - - RegSetIterator& operator++() { - RegImpl r = _regs.first(); - if (r->is_valid()) - _regs -= r; - return *this; - } - - bool operator==(const RegSetIterator& rhs) const { - return _regs.bits() == rhs._regs.bits(); - } - bool operator!=(const RegSetIterator& rhs) const { - return ! (rhs == *this); - } - - RegImpl operator*() { - return _regs.first(); - } -}; - -template -inline RegSetIterator AbstractRegSet::begin() { - return RegSetIterator(*this); -} - template <> inline Register AbstractRegSet::first() { uint32_t first = _bitset & -_bitset; diff --git a/src/hotspot/cpu/aarch64/register_definitions_aarch64.cpp b/src/hotspot/cpu/aarch64/register_definitions_aarch64.cpp deleted file mode 100644 index f48c70d09e6707bbd58aa75674cdf668c912ec68..0000000000000000000000000000000000000000 --- a/src/hotspot/cpu/aarch64/register_definitions_aarch64.cpp +++ /dev/null @@ -1,208 +0,0 @@ -/* - * Copyright (c) 2002, 2020, 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. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please 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/macroAssembler.inline.hpp" -#include "asm/register.hpp" -#include "register_aarch64.hpp" -# include "interp_masm_aarch64.hpp" - -REGISTER_DEFINITION(Register, noreg); - -REGISTER_DEFINITION(Register, r0); -REGISTER_DEFINITION(Register, r1); -REGISTER_DEFINITION(Register, r2); -REGISTER_DEFINITION(Register, r3); -REGISTER_DEFINITION(Register, r4); -REGISTER_DEFINITION(Register, r5); -REGISTER_DEFINITION(Register, r6); -REGISTER_DEFINITION(Register, r7); -REGISTER_DEFINITION(Register, r8); -REGISTER_DEFINITION(Register, r9); -REGISTER_DEFINITION(Register, r10); -REGISTER_DEFINITION(Register, r11); -REGISTER_DEFINITION(Register, r12); -REGISTER_DEFINITION(Register, r13); -REGISTER_DEFINITION(Register, r14); -REGISTER_DEFINITION(Register, r15); -REGISTER_DEFINITION(Register, r16); -REGISTER_DEFINITION(Register, r17); -REGISTER_DEFINITION(Register, r18_tls); // see comment in register_aarch64.hpp -REGISTER_DEFINITION(Register, r19); -REGISTER_DEFINITION(Register, r20); -REGISTER_DEFINITION(Register, r21); -REGISTER_DEFINITION(Register, r22); -REGISTER_DEFINITION(Register, r23); -REGISTER_DEFINITION(Register, r24); -REGISTER_DEFINITION(Register, r25); -REGISTER_DEFINITION(Register, r26); -REGISTER_DEFINITION(Register, r27); -REGISTER_DEFINITION(Register, r28); -REGISTER_DEFINITION(Register, r29); -REGISTER_DEFINITION(Register, r30); -REGISTER_DEFINITION(Register, sp); - -REGISTER_DEFINITION(FloatRegister, fnoreg); - -REGISTER_DEFINITION(FloatRegister, v0); -REGISTER_DEFINITION(FloatRegister, v1); -REGISTER_DEFINITION(FloatRegister, v2); -REGISTER_DEFINITION(FloatRegister, v3); -REGISTER_DEFINITION(FloatRegister, v4); -REGISTER_DEFINITION(FloatRegister, v5); -REGISTER_DEFINITION(FloatRegister, v6); -REGISTER_DEFINITION(FloatRegister, v7); -REGISTER_DEFINITION(FloatRegister, v8); -REGISTER_DEFINITION(FloatRegister, v9); -REGISTER_DEFINITION(FloatRegister, v10); -REGISTER_DEFINITION(FloatRegister, v11); -REGISTER_DEFINITION(FloatRegister, v12); -REGISTER_DEFINITION(FloatRegister, v13); -REGISTER_DEFINITION(FloatRegister, v14); -REGISTER_DEFINITION(FloatRegister, v15); -REGISTER_DEFINITION(FloatRegister, v16); -REGISTER_DEFINITION(FloatRegister, v17); -REGISTER_DEFINITION(FloatRegister, v18); -REGISTER_DEFINITION(FloatRegister, v19); -REGISTER_DEFINITION(FloatRegister, v20); -REGISTER_DEFINITION(FloatRegister, v21); -REGISTER_DEFINITION(FloatRegister, v22); -REGISTER_DEFINITION(FloatRegister, v23); -REGISTER_DEFINITION(FloatRegister, v24); -REGISTER_DEFINITION(FloatRegister, v25); -REGISTER_DEFINITION(FloatRegister, v26); -REGISTER_DEFINITION(FloatRegister, v27); -REGISTER_DEFINITION(FloatRegister, v28); -REGISTER_DEFINITION(FloatRegister, v29); -REGISTER_DEFINITION(FloatRegister, v30); -REGISTER_DEFINITION(FloatRegister, v31); - -REGISTER_DEFINITION(Register, zr); - -REGISTER_DEFINITION(Register, c_rarg0); -REGISTER_DEFINITION(Register, c_rarg1); -REGISTER_DEFINITION(Register, c_rarg2); -REGISTER_DEFINITION(Register, c_rarg3); -REGISTER_DEFINITION(Register, c_rarg4); -REGISTER_DEFINITION(Register, c_rarg5); -REGISTER_DEFINITION(Register, c_rarg6); -REGISTER_DEFINITION(Register, c_rarg7); - -REGISTER_DEFINITION(FloatRegister, c_farg0); -REGISTER_DEFINITION(FloatRegister, c_farg1); -REGISTER_DEFINITION(FloatRegister, c_farg2); -REGISTER_DEFINITION(FloatRegister, c_farg3); -REGISTER_DEFINITION(FloatRegister, c_farg4); -REGISTER_DEFINITION(FloatRegister, c_farg5); -REGISTER_DEFINITION(FloatRegister, c_farg6); -REGISTER_DEFINITION(FloatRegister, c_farg7); - -REGISTER_DEFINITION(Register, j_rarg0); -REGISTER_DEFINITION(Register, j_rarg1); -REGISTER_DEFINITION(Register, j_rarg2); -REGISTER_DEFINITION(Register, j_rarg3); -REGISTER_DEFINITION(Register, j_rarg4); -REGISTER_DEFINITION(Register, j_rarg5); -REGISTER_DEFINITION(Register, j_rarg6); -REGISTER_DEFINITION(Register, j_rarg7); - -REGISTER_DEFINITION(FloatRegister, j_farg0); -REGISTER_DEFINITION(FloatRegister, j_farg1); -REGISTER_DEFINITION(FloatRegister, j_farg2); -REGISTER_DEFINITION(FloatRegister, j_farg3); -REGISTER_DEFINITION(FloatRegister, j_farg4); -REGISTER_DEFINITION(FloatRegister, j_farg5); -REGISTER_DEFINITION(FloatRegister, j_farg6); -REGISTER_DEFINITION(FloatRegister, j_farg7); - -REGISTER_DEFINITION(Register, rscratch1); -REGISTER_DEFINITION(Register, rscratch2); -REGISTER_DEFINITION(Register, esp); -REGISTER_DEFINITION(Register, rdispatch); -REGISTER_DEFINITION(Register, rcpool); -REGISTER_DEFINITION(Register, rmonitors); -REGISTER_DEFINITION(Register, rlocals); -REGISTER_DEFINITION(Register, rmethod); -REGISTER_DEFINITION(Register, rbcp); - -REGISTER_DEFINITION(Register, lr); -REGISTER_DEFINITION(Register, rfp); -REGISTER_DEFINITION(Register, rthread); -REGISTER_DEFINITION(Register, rheapbase); - -REGISTER_DEFINITION(Register, r31_sp); - -REGISTER_DEFINITION(FloatRegister, z0); -REGISTER_DEFINITION(FloatRegister, z1); -REGISTER_DEFINITION(FloatRegister, z2); -REGISTER_DEFINITION(FloatRegister, z3); -REGISTER_DEFINITION(FloatRegister, z4); -REGISTER_DEFINITION(FloatRegister, z5); -REGISTER_DEFINITION(FloatRegister, z6); -REGISTER_DEFINITION(FloatRegister, z7); -REGISTER_DEFINITION(FloatRegister, z8); -REGISTER_DEFINITION(FloatRegister, z9); -REGISTER_DEFINITION(FloatRegister, z10); -REGISTER_DEFINITION(FloatRegister, z11); -REGISTER_DEFINITION(FloatRegister, z12); -REGISTER_DEFINITION(FloatRegister, z13); -REGISTER_DEFINITION(FloatRegister, z14); -REGISTER_DEFINITION(FloatRegister, z15); -REGISTER_DEFINITION(FloatRegister, z16); -REGISTER_DEFINITION(FloatRegister, z17); -REGISTER_DEFINITION(FloatRegister, z18); -REGISTER_DEFINITION(FloatRegister, z19); -REGISTER_DEFINITION(FloatRegister, z20); -REGISTER_DEFINITION(FloatRegister, z21); -REGISTER_DEFINITION(FloatRegister, z22); -REGISTER_DEFINITION(FloatRegister, z23); -REGISTER_DEFINITION(FloatRegister, z24); -REGISTER_DEFINITION(FloatRegister, z25); -REGISTER_DEFINITION(FloatRegister, z26); -REGISTER_DEFINITION(FloatRegister, z27); -REGISTER_DEFINITION(FloatRegister, z28); -REGISTER_DEFINITION(FloatRegister, z29); -REGISTER_DEFINITION(FloatRegister, z30); -REGISTER_DEFINITION(FloatRegister, z31); - -REGISTER_DEFINITION(PRegister, p0); -REGISTER_DEFINITION(PRegister, p1); -REGISTER_DEFINITION(PRegister, p2); -REGISTER_DEFINITION(PRegister, p3); -REGISTER_DEFINITION(PRegister, p4); -REGISTER_DEFINITION(PRegister, p5); -REGISTER_DEFINITION(PRegister, p6); -REGISTER_DEFINITION(PRegister, p7); -REGISTER_DEFINITION(PRegister, p8); -REGISTER_DEFINITION(PRegister, p9); -REGISTER_DEFINITION(PRegister, p10); -REGISTER_DEFINITION(PRegister, p11); -REGISTER_DEFINITION(PRegister, p12); -REGISTER_DEFINITION(PRegister, p13); -REGISTER_DEFINITION(PRegister, p14); -REGISTER_DEFINITION(PRegister, p15); - -REGISTER_DEFINITION(PRegister, ptrue); diff --git a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp index 5c80566aeadd7d3425a82cde23b7c51d558bfc10..18c6d227823075bcf802fde79cec599eb387c952 100644 --- a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2021, Red Hat Inc. All rights reserved. * Copyright (c) 2021, Azul Systems, Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -410,6 +410,7 @@ static void patch_callers_callsite(MacroAssembler *masm) { __ mov(c_rarg0, rmethod); __ mov(c_rarg1, lr); + __ authenticate_return_address(c_rarg1, rscratch1); __ lea(rscratch1, RuntimeAddress(CAST_FROM_FN_PTR(address, SharedRuntime::fixup_callers_callsite))); __ blr(rscratch1); @@ -1642,39 +1643,42 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, // Load the oop from the handle __ ldr(obj_reg, Address(oop_handle_reg, 0)); - // Load (object->mark() | 1) into swap_reg %r0 - __ ldr(rscratch1, Address(obj_reg, oopDesc::mark_offset_in_bytes())); - __ orr(swap_reg, rscratch1, 1); + if (!UseHeavyMonitors) { + // Load (object->mark() | 1) into swap_reg %r0 + __ ldr(rscratch1, Address(obj_reg, oopDesc::mark_offset_in_bytes())); + __ orr(swap_reg, rscratch1, 1); - // Save (object->mark() | 1) into BasicLock's displaced header - __ str(swap_reg, Address(lock_reg, mark_word_offset)); + // Save (object->mark() | 1) into BasicLock's displaced header + __ str(swap_reg, Address(lock_reg, mark_word_offset)); - // src -> dest iff dest == r0 else r0 <- dest - { Label here; - __ cmpxchg_obj_header(r0, lock_reg, obj_reg, rscratch1, lock_done, /*fallthrough*/NULL); - } + // src -> dest iff dest == r0 else r0 <- dest + { Label here; + __ cmpxchg_obj_header(r0, lock_reg, obj_reg, rscratch1, lock_done, /*fallthrough*/NULL); + } - // Hmm should this move to the slow path code area??? + // Hmm should this move to the slow path code area??? - // Test if the oopMark is an obvious stack pointer, i.e., - // 1) (mark & 3) == 0, and - // 2) sp <= mark < mark + os::pagesize() - // These 3 tests can be done by evaluating the following - // expression: ((mark - sp) & (3 - os::vm_page_size())), - // assuming both stack pointer and pagesize have their - // least significant 2 bits clear. - // NOTE: the oopMark is in swap_reg %r0 as the result of cmpxchg + // Test if the oopMark is an obvious stack pointer, i.e., + // 1) (mark & 3) == 0, and + // 2) sp <= mark < mark + os::pagesize() + // These 3 tests can be done by evaluating the following + // expression: ((mark - sp) & (3 - os::vm_page_size())), + // assuming both stack pointer and pagesize have their + // least significant 2 bits clear. + // NOTE: the oopMark is in swap_reg %r0 as the result of cmpxchg - __ sub(swap_reg, sp, swap_reg); - __ neg(swap_reg, swap_reg); - __ ands(swap_reg, swap_reg, 3 - os::vm_page_size()); + __ sub(swap_reg, sp, swap_reg); + __ neg(swap_reg, swap_reg); + __ ands(swap_reg, swap_reg, 3 - os::vm_page_size()); - // Save the test result, for recursive case, the result is zero - __ str(swap_reg, Address(lock_reg, mark_word_offset)); - __ br(Assembler::NE, slow_path_lock); + // Save the test result, for recursive case, the result is zero + __ str(swap_reg, Address(lock_reg, mark_word_offset)); + __ br(Assembler::NE, slow_path_lock); + } else { + __ b(slow_path_lock); + } // Slow path will re-enter here - __ bind(lock_done); } @@ -1775,26 +1779,31 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, __ ldr(obj_reg, Address(oop_handle_reg, 0)); Label done; - // Simple recursive lock? - __ ldr(rscratch1, Address(sp, lock_slot_offset * VMRegImpl::stack_slot_size)); - __ cbz(rscratch1, done); + if (!UseHeavyMonitors) { + // Simple recursive lock? + __ ldr(rscratch1, Address(sp, lock_slot_offset * VMRegImpl::stack_slot_size)); + __ cbz(rscratch1, done); + } // Must save r0 if if it is live now because cmpxchg must use it if (ret_type != T_FLOAT && ret_type != T_DOUBLE && ret_type != T_VOID) { save_native_result(masm, ret_type, stack_slots); } + if (!UseHeavyMonitors) { + // get address of the stack lock + __ lea(r0, Address(sp, lock_slot_offset * VMRegImpl::stack_slot_size)); + // get old displaced header + __ ldr(old_hdr, Address(r0, 0)); - // get address of the stack lock - __ lea(r0, Address(sp, lock_slot_offset * VMRegImpl::stack_slot_size)); - // get old displaced header - __ ldr(old_hdr, Address(r0, 0)); - - // Atomic swap old header if oop still contains the stack lock - Label succeed; - __ cmpxchg_obj_header(r0, old_hdr, obj_reg, rscratch1, succeed, &slow_path_unlock); - __ bind(succeed); + // Atomic swap old header if oop still contains the stack lock + Label succeed; + __ cmpxchg_obj_header(r0, old_hdr, obj_reg, rscratch1, succeed, &slow_path_unlock); + __ bind(succeed); + } else { + __ b(slow_path_unlock); + } // slow path re-enters here __ bind(unlock_done); @@ -2170,8 +2179,8 @@ void SharedRuntime::generate_deopt_blob() { // load throwing pc from JavaThread and patch it as the return address // of the current frame. Then clear the field in JavaThread - __ ldr(r3, Address(rthread, JavaThread::exception_pc_offset())); + __ protect_return_address(r3, rscratch1); __ str(r3, Address(rfp, wordSize)); __ str(zr, Address(rthread, JavaThread::exception_pc_offset())); @@ -2279,6 +2288,7 @@ void SharedRuntime::generate_deopt_blob() { __ sub(r2, r2, 2 * wordSize); __ add(sp, sp, r2); __ ldp(rfp, lr, __ post(sp, 2 * wordSize)); + __ authenticate_return_address(); // LR should now be the return address to the caller (3) #ifdef ASSERT @@ -2420,6 +2430,7 @@ void SharedRuntime::generate_uncommon_trap_blob() { // Push self-frame. We get here with a return address in LR // and sp should be 16 byte aligned // push rfp and retaddr by hand + __ protect_return_address(); __ stp(rfp, lr, Address(__ pre(sp, -2 * wordSize))); // we don't expect an arg reg save area #ifndef PRODUCT @@ -2494,6 +2505,7 @@ void SharedRuntime::generate_uncommon_trap_blob() { __ sub(r2, r2, 2 * wordSize); __ add(sp, sp, r2); __ ldp(rfp, lr, __ post(sp, 2 * wordSize)); + __ authenticate_return_address(); // LR should now be the return address to the caller (3) frame #ifdef ASSERT @@ -2616,6 +2628,11 @@ SafepointBlob* SharedRuntime::generate_handler_blob(address call_ptr, int poll_t bool cause_return = (poll_type == POLL_AT_RETURN); RegisterSaver reg_save(poll_type == POLL_AT_VECTOR_LOOP /* save_vectors */); + // When the signal occured, the LR was either signed and stored on the stack (in which + // case it will be restored from the stack before being used) or unsigned and not stored + // on the stack. Stipping ensures we get the right value. + __ strip_return_address(); + // Save Integer and Float registers. map = reg_save.save_live_registers(masm, 0, &frame_size_in_words); @@ -2635,6 +2652,7 @@ SafepointBlob* SharedRuntime::generate_handler_blob(address call_ptr, int poll_t // it later to determine if someone changed the return address for // us! __ ldr(r20, Address(rthread, JavaThread::saved_exception_pc_offset())); + __ protect_return_address(r20, rscratch1); __ str(r20, Address(rfp, wordSize)); } @@ -2675,6 +2693,7 @@ SafepointBlob* SharedRuntime::generate_handler_blob(address call_ptr, int poll_t __ ldr(rscratch1, Address(rfp, wordSize)); __ cmp(r20, rscratch1); __ br(Assembler::NE, no_adjust); + __ authenticate_return_address(r20, rscratch1); #ifdef ASSERT // Verify the correct encoding of the poll we're about to skip. @@ -2689,6 +2708,7 @@ SafepointBlob* SharedRuntime::generate_handler_blob(address call_ptr, int poll_t #endif // Adjust return pc forward to step over the safepoint poll instruction __ add(r20, r20, NativeInstruction::instruction_size); + __ protect_return_address(r20, rscratch1); __ str(r20, Address(rfp, wordSize)); } @@ -2849,6 +2869,7 @@ void OptoRuntime::generate_exception_blob() { // push rfp and retaddr by hand // Exception pc is 'return address' for stack walker + __ protect_return_address(); __ stp(rfp, lr, Address(__ pre(sp, -2 * wordSize))); // there are no callee save registers and we don't expect an // arg reg save area @@ -2902,6 +2923,7 @@ void OptoRuntime::generate_exception_blob() { // there are no callee save registers now that adapter frames are gone. // and we dont' expect an arg reg save area __ ldp(rfp, r3, Address(__ post(sp, 2 * wordSize))); + __ authenticate_return_address(r3); // r0: exception handler diff --git a/src/hotspot/cpu/aarch64/spin_wait_aarch64.hpp b/src/hotspot/cpu/aarch64/spin_wait_aarch64.hpp index 4edce2642e9ff3e48eee910e7b9bc8f84cb52005..28ffeafda487755d8c0126b0a58277d0d7027a89 100644 --- a/src/hotspot/cpu/aarch64/spin_wait_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/spin_wait_aarch64.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Amazon.com Inc. 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 diff --git a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp index fff6cd8cf9967b770a27cfcbb1e365c0a149eed7..1b41f09d97221799ac92ee3e430b10298193c663 100644 --- a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2014, 2021, Red Hat Inc. All rights reserved. + * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -26,6 +26,7 @@ #include "precompiled.hpp" #include "asm/macroAssembler.hpp" #include "asm/macroAssembler.inline.hpp" +#include "asm/register.hpp" #include "atomic_aarch64.hpp" #include "compiler/oopMap.hpp" #include "gc/shared/barrierSet.hpp" @@ -1320,10 +1321,10 @@ class StubGenerator: public StubCodeGenerator { void clobber_registers() { #ifdef ASSERT RegSet clobbered - = MacroAssembler::call_clobbered_registers() - rscratch1; + = MacroAssembler::call_clobbered_gp_registers() - rscratch1; __ mov(rscratch1, (uint64_t)0xdeadbeef); __ orr(rscratch1, rscratch1, rscratch1, Assembler::LSL, 32); - for (RegSetIterator<> it = clobbered.begin(); *it != noreg; ++it) { + for (RegSetIterator it = clobbered.begin(); *it != noreg; ++it) { __ mov(*it, rscratch1); } #endif @@ -3094,8 +3095,7 @@ class StubGenerator: public StubCodeGenerator { // key = c_rarg4 // state = c_rarg5 - GHASH.state // subkeyHtbl = c_rarg6 - powers of H - // subkeyHtbl_48_entries = c_rarg7 (not used) - // counter = [sp, #0] pointer to 16 bytes of CTR + // counter = c_rarg7 - 16 bytes of CTR // return - number of processed bytes address generate_galoisCounterMode_AESCrypt() { address ghash_polynomial = __ pc(); @@ -3121,10 +3121,7 @@ class StubGenerator: public StubCodeGenerator { const Register subkeyHtbl = c_rarg6; - // Pointer to CTR is passed on the stack before the (fp, lr) pair. - const Address counter_mem(sp, 2 * wordSize); const Register counter = c_rarg7; - __ ldr(counter, counter_mem); const Register keylen = r10; // Save state before entering routine @@ -3210,6 +3207,194 @@ class StubGenerator: public StubCodeGenerator { return start; } + // Arguments: + // + // Inputs: + // c_rarg0 - byte[] source+offset + // c_rarg1 - int[] SHA.state + // c_rarg2 - int offset + // c_rarg3 - int limit + // + address generate_md5_implCompress(bool multi_block, const char *name) { + __ align(CodeEntryAlignment); + StubCodeMark mark(this, "StubRoutines", name); + address start = __ pc(); + + Register buf = c_rarg0; + Register state = c_rarg1; + Register ofs = c_rarg2; + Register limit = c_rarg3; + Register a = r4; + Register b = r5; + Register c = r6; + Register d = r7; + Register rscratch3 = r10; + Register rscratch4 = r11; + + Label keys; + Label md5_loop; + + __ BIND(md5_loop); + + // Save hash values for addition after rounds + __ ldrw(a, Address(state, 0)); + __ ldrw(b, Address(state, 4)); + __ ldrw(c, Address(state, 8)); + __ ldrw(d, Address(state, 12)); + +#define FF(r1, r2, r3, r4, k, s, t) \ + __ eorw(rscratch3, r3, r4); \ + __ movw(rscratch2, t); \ + __ andw(rscratch3, rscratch3, r2); \ + __ addw(rscratch4, r1, rscratch2); \ + __ ldrw(rscratch1, Address(buf, k*4)); \ + __ eorw(rscratch3, rscratch3, r4); \ + __ addw(rscratch3, rscratch3, rscratch1); \ + __ addw(rscratch3, rscratch3, rscratch4); \ + __ rorw(rscratch2, rscratch3, 32 - s); \ + __ addw(r1, rscratch2, r2); + +#define GG(r1, r2, r3, r4, k, s, t) \ + __ eorw(rscratch2, r2, r3); \ + __ ldrw(rscratch1, Address(buf, k*4)); \ + __ andw(rscratch3, rscratch2, r4); \ + __ movw(rscratch2, t); \ + __ eorw(rscratch3, rscratch3, r3); \ + __ addw(rscratch4, r1, rscratch2); \ + __ addw(rscratch3, rscratch3, rscratch1); \ + __ addw(rscratch3, rscratch3, rscratch4); \ + __ rorw(rscratch2, rscratch3, 32 - s); \ + __ addw(r1, rscratch2, r2); + +#define HH(r1, r2, r3, r4, k, s, t) \ + __ eorw(rscratch3, r3, r4); \ + __ movw(rscratch2, t); \ + __ addw(rscratch4, r1, rscratch2); \ + __ ldrw(rscratch1, Address(buf, k*4)); \ + __ eorw(rscratch3, rscratch3, r2); \ + __ addw(rscratch3, rscratch3, rscratch1); \ + __ addw(rscratch3, rscratch3, rscratch4); \ + __ rorw(rscratch2, rscratch3, 32 - s); \ + __ addw(r1, rscratch2, r2); + +#define II(r1, r2, r3, r4, k, s, t) \ + __ movw(rscratch3, t); \ + __ ornw(rscratch2, r2, r4); \ + __ addw(rscratch4, r1, rscratch3); \ + __ ldrw(rscratch1, Address(buf, k*4)); \ + __ eorw(rscratch3, rscratch2, r3); \ + __ addw(rscratch3, rscratch3, rscratch1); \ + __ addw(rscratch3, rscratch3, rscratch4); \ + __ rorw(rscratch2, rscratch3, 32 - s); \ + __ addw(r1, rscratch2, r2); + + // Round 1 + FF(a, b, c, d, 0, 7, 0xd76aa478) + FF(d, a, b, c, 1, 12, 0xe8c7b756) + FF(c, d, a, b, 2, 17, 0x242070db) + FF(b, c, d, a, 3, 22, 0xc1bdceee) + FF(a, b, c, d, 4, 7, 0xf57c0faf) + FF(d, a, b, c, 5, 12, 0x4787c62a) + FF(c, d, a, b, 6, 17, 0xa8304613) + FF(b, c, d, a, 7, 22, 0xfd469501) + FF(a, b, c, d, 8, 7, 0x698098d8) + FF(d, a, b, c, 9, 12, 0x8b44f7af) + FF(c, d, a, b, 10, 17, 0xffff5bb1) + FF(b, c, d, a, 11, 22, 0x895cd7be) + FF(a, b, c, d, 12, 7, 0x6b901122) + FF(d, a, b, c, 13, 12, 0xfd987193) + FF(c, d, a, b, 14, 17, 0xa679438e) + FF(b, c, d, a, 15, 22, 0x49b40821) + + // Round 2 + GG(a, b, c, d, 1, 5, 0xf61e2562) + GG(d, a, b, c, 6, 9, 0xc040b340) + GG(c, d, a, b, 11, 14, 0x265e5a51) + GG(b, c, d, a, 0, 20, 0xe9b6c7aa) + GG(a, b, c, d, 5, 5, 0xd62f105d) + GG(d, a, b, c, 10, 9, 0x02441453) + GG(c, d, a, b, 15, 14, 0xd8a1e681) + GG(b, c, d, a, 4, 20, 0xe7d3fbc8) + GG(a, b, c, d, 9, 5, 0x21e1cde6) + GG(d, a, b, c, 14, 9, 0xc33707d6) + GG(c, d, a, b, 3, 14, 0xf4d50d87) + GG(b, c, d, a, 8, 20, 0x455a14ed) + GG(a, b, c, d, 13, 5, 0xa9e3e905) + GG(d, a, b, c, 2, 9, 0xfcefa3f8) + GG(c, d, a, b, 7, 14, 0x676f02d9) + GG(b, c, d, a, 12, 20, 0x8d2a4c8a) + + // Round 3 + HH(a, b, c, d, 5, 4, 0xfffa3942) + HH(d, a, b, c, 8, 11, 0x8771f681) + HH(c, d, a, b, 11, 16, 0x6d9d6122) + HH(b, c, d, a, 14, 23, 0xfde5380c) + HH(a, b, c, d, 1, 4, 0xa4beea44) + HH(d, a, b, c, 4, 11, 0x4bdecfa9) + HH(c, d, a, b, 7, 16, 0xf6bb4b60) + HH(b, c, d, a, 10, 23, 0xbebfbc70) + HH(a, b, c, d, 13, 4, 0x289b7ec6) + HH(d, a, b, c, 0, 11, 0xeaa127fa) + HH(c, d, a, b, 3, 16, 0xd4ef3085) + HH(b, c, d, a, 6, 23, 0x04881d05) + HH(a, b, c, d, 9, 4, 0xd9d4d039) + HH(d, a, b, c, 12, 11, 0xe6db99e5) + HH(c, d, a, b, 15, 16, 0x1fa27cf8) + HH(b, c, d, a, 2, 23, 0xc4ac5665) + + // Round 4 + II(a, b, c, d, 0, 6, 0xf4292244) + II(d, a, b, c, 7, 10, 0x432aff97) + II(c, d, a, b, 14, 15, 0xab9423a7) + II(b, c, d, a, 5, 21, 0xfc93a039) + II(a, b, c, d, 12, 6, 0x655b59c3) + II(d, a, b, c, 3, 10, 0x8f0ccc92) + II(c, d, a, b, 10, 15, 0xffeff47d) + II(b, c, d, a, 1, 21, 0x85845dd1) + II(a, b, c, d, 8, 6, 0x6fa87e4f) + II(d, a, b, c, 15, 10, 0xfe2ce6e0) + II(c, d, a, b, 6, 15, 0xa3014314) + II(b, c, d, a, 13, 21, 0x4e0811a1) + II(a, b, c, d, 4, 6, 0xf7537e82) + II(d, a, b, c, 11, 10, 0xbd3af235) + II(c, d, a, b, 2, 15, 0x2ad7d2bb) + II(b, c, d, a, 9, 21, 0xeb86d391) + +#undef FF +#undef GG +#undef HH +#undef II + + // write hash values back in the correct order + __ ldrw(rscratch1, Address(state, 0)); + __ addw(rscratch1, rscratch1, a); + __ strw(rscratch1, Address(state, 0)); + + __ ldrw(rscratch2, Address(state, 4)); + __ addw(rscratch2, rscratch2, b); + __ strw(rscratch2, Address(state, 4)); + + __ ldrw(rscratch3, Address(state, 8)); + __ addw(rscratch3, rscratch3, c); + __ strw(rscratch3, Address(state, 8)); + + __ ldrw(rscratch4, Address(state, 12)); + __ addw(rscratch4, rscratch4, d); + __ strw(rscratch4, Address(state, 12)); + + if (multi_block) { + __ add(buf, buf, 64); + __ add(ofs, ofs, 64); + __ cmp(ofs, limit); + __ br(Assembler::LE, md5_loop); + __ mov(c_rarg0, ofs); // return ofs + } + + __ ret(lr); + + return start; + } + // Arguments: // // Inputs: @@ -4473,7 +4658,7 @@ class StubGenerator: public StubCodeGenerator { return start; } - address generate_has_negatives(address &has_negatives_long) { + address generate_count_positives(address &count_positives_long) { const u1 large_loop_size = 64; const uint64_t UPPER_BIT_MASK=0x8080808080808080; int dcache_line = VM_Version::dcache_line_size(); @@ -4482,13 +4667,15 @@ class StubGenerator: public StubCodeGenerator { __ align(CodeEntryAlignment); - StubCodeMark mark(this, "StubRoutines", "has_negatives"); + StubCodeMark mark(this, "StubRoutines", "count_positives"); address entry = __ pc(); __ enter(); + // precondition: a copy of len is already in result + // __ mov(result, len); - Label RET_TRUE, RET_TRUE_NO_POP, RET_FALSE, ALIGNED, LOOP16, CHECK_16, DONE, + Label RET_ADJUST, RET_ADJUST_16, RET_ADJUST_LONG, RET_NO_POP, RET_LEN, ALIGNED, LOOP16, CHECK_16, LARGE_LOOP, POST_LOOP16, LEN_OVER_15, LEN_OVER_8, POST_LOOP16_LOAD_TAIL; __ cmp(len, (u1)15); @@ -4502,25 +4689,26 @@ class StubGenerator: public StubCodeGenerator { __ sub(rscratch1, zr, len, __ LSL, 3); // LSL 3 is to get bits from bytes. __ lsrv(rscratch2, rscratch2, rscratch1); __ tst(rscratch2, UPPER_BIT_MASK); - __ cset(result, Assembler::NE); + __ csel(result, zr, result, Assembler::NE); __ leave(); __ ret(lr); __ bind(LEN_OVER_8); __ ldp(rscratch1, rscratch2, Address(ary1, -16)); __ sub(len, len, 8); // no data dep., then sub can be executed while loading __ tst(rscratch2, UPPER_BIT_MASK); - __ br(Assembler::NE, RET_TRUE_NO_POP); + __ br(Assembler::NE, RET_NO_POP); __ sub(rscratch2, zr, len, __ LSL, 3); // LSL 3 is to get bits from bytes __ lsrv(rscratch1, rscratch1, rscratch2); __ tst(rscratch1, UPPER_BIT_MASK); - __ cset(result, Assembler::NE); + __ bind(RET_NO_POP); + __ csel(result, zr, result, Assembler::NE); __ leave(); __ ret(lr); Register tmp1 = r3, tmp2 = r4, tmp3 = r5, tmp4 = r6, tmp5 = r7, tmp6 = r10; const RegSet spilled_regs = RegSet::range(tmp1, tmp5) + tmp6; - has_negatives_long = __ pc(); // 2nd entry point + count_positives_long = __ pc(); // 2nd entry point __ enter(); @@ -4532,10 +4720,10 @@ class StubGenerator: public StubCodeGenerator { __ mov(tmp5, 16); __ sub(rscratch1, tmp5, rscratch2); // amount of bytes until aligned address __ add(ary1, ary1, rscratch1); - __ sub(len, len, rscratch1); __ orr(tmp6, tmp6, tmp1); __ tst(tmp6, UPPER_BIT_MASK); - __ br(Assembler::NE, RET_TRUE); + __ br(Assembler::NE, RET_ADJUST); + __ sub(len, len, rscratch1); __ bind(ALIGNED); __ cmp(len, large_loop_size); @@ -4550,7 +4738,7 @@ class StubGenerator: public StubCodeGenerator { __ sub(len, len, 16); __ orr(tmp6, tmp6, tmp1); __ tst(tmp6, UPPER_BIT_MASK); - __ br(Assembler::NE, RET_TRUE); + __ br(Assembler::NE, RET_ADJUST_16); __ cmp(len, large_loop_size); __ br(Assembler::LT, CHECK_16); @@ -4582,7 +4770,7 @@ class StubGenerator: public StubCodeGenerator { __ orr(rscratch1, rscratch1, tmp6); __ orr(tmp2, tmp2, rscratch1); __ tst(tmp2, UPPER_BIT_MASK); - __ br(Assembler::NE, RET_TRUE); + __ br(Assembler::NE, RET_ADJUST_LONG); __ cmp(len, large_loop_size); __ br(Assembler::GE, LARGE_LOOP); @@ -4595,7 +4783,7 @@ class StubGenerator: public StubCodeGenerator { __ sub(len, len, 16); __ orr(tmp2, tmp2, tmp3); __ tst(tmp2, UPPER_BIT_MASK); - __ br(Assembler::NE, RET_TRUE); + __ br(Assembler::NE, RET_ADJUST_16); __ cmp(len, (u1)16); __ br(Assembler::GE, LOOP16); // 16-byte load loop end @@ -4603,37 +4791,38 @@ class StubGenerator: public StubCodeGenerator { __ cmp(len, (u1)8); __ br(Assembler::LE, POST_LOOP16_LOAD_TAIL); __ ldr(tmp3, Address(__ post(ary1, 8))); - __ sub(len, len, 8); __ tst(tmp3, UPPER_BIT_MASK); - __ br(Assembler::NE, RET_TRUE); + __ br(Assembler::NE, RET_ADJUST); + __ sub(len, len, 8); __ bind(POST_LOOP16_LOAD_TAIL); - __ cbz(len, RET_FALSE); // Can't shift left by 64 when len==0 + __ cbz(len, RET_LEN); // Can't shift left by 64 when len==0 __ ldr(tmp1, Address(ary1)); __ mov(tmp2, 64); __ sub(tmp4, tmp2, len, __ LSL, 3); __ lslv(tmp1, tmp1, tmp4); __ tst(tmp1, UPPER_BIT_MASK); - __ br(Assembler::NE, RET_TRUE); + __ br(Assembler::NE, RET_ADJUST); // Fallthrough - __ bind(RET_FALSE); + __ bind(RET_LEN); __ pop(spilled_regs, sp); __ leave(); - __ mov(result, zr); __ ret(lr); - __ bind(RET_TRUE); - __ pop(spilled_regs, sp); - __ bind(RET_TRUE_NO_POP); - __ leave(); - __ mov(result, 1); - __ ret(lr); + // difference result - len is the count of guaranteed to be + // positive bytes - __ bind(DONE); + __ bind(RET_ADJUST_LONG); + __ add(len, len, (u1)(large_loop_size - 16)); + __ bind(RET_ADJUST_16); + __ add(len, len, 16); + __ bind(RET_ADJUST); __ pop(spilled_regs, sp); __ leave(); + __ sub(result, result, len); __ ret(lr); + return entry; } @@ -5062,11 +5251,11 @@ class StubGenerator: public StubCodeGenerator { __ add(str1, str1, wordSize); __ add(str2, str2, wordSize); if (SoftwarePrefetchHintDistance >= 0) { + __ align(OptoLoopAlignment); __ bind(LARGE_LOOP_PREFETCH); __ prfm(Address(str1, SoftwarePrefetchHintDistance)); __ prfm(Address(str2, SoftwarePrefetchHintDistance)); - __ align(OptoLoopAlignment); for (int i = 0; i < 4; i++) { __ ldp(tmp1, tmp1h, Address(str1, i * 16)); __ ldp(tmp2, tmp2h, Address(str2, i * 16)); @@ -6107,6 +6296,18 @@ class StubGenerator: public StubCodeGenerator { return start; } + // Support for spin waits. + address generate_spin_wait() { + __ align(CodeEntryAlignment); + StubCodeMark mark(this, "StubRoutines", "spin_wait"); + address start = __ pc(); + + __ spin_wait(); + __ ret(lr); + + return start; + } + #ifdef LINUX // ARMv8.1 LSE versions of the atomic stubs used by Atomic::PlatformXX. @@ -6429,7 +6630,7 @@ class StubGenerator: public StubCodeGenerator { // Register allocation - RegSetIterator<> regs = (RegSet::range(r0, r26) - r18_tls).begin(); + RegSetIterator regs = (RegSet::range(r0, r26) - r18_tls).begin(); Pa_base = *regs; // Argument registers if (squaring) Pb_base = Pa_base; @@ -7323,8 +7524,8 @@ class StubGenerator: public StubCodeGenerator { // arraycopy stubs used by compilers generate_arraycopy_stubs(); - // has negatives stub for large arrays. - StubRoutines::aarch64::_has_negatives = generate_has_negatives(StubRoutines::aarch64::_has_negatives_long); + // countPositives stub for large arrays. + StubRoutines::aarch64::_count_positives = generate_count_positives(StubRoutines::aarch64::_count_positives_long); // array equals stub for large arrays. if (!UseSimpleArrayEquals) { @@ -7399,6 +7600,10 @@ class StubGenerator: public StubCodeGenerator { StubRoutines::_galoisCounterMode_AESCrypt = generate_galoisCounterMode_AESCrypt(); } + if (UseMD5Intrinsics) { + StubRoutines::_md5_implCompress = generate_md5_implCompress(false, "md5_implCompress"); + StubRoutines::_md5_implCompressMB = generate_md5_implCompress(true, "md5_implCompressMB"); + } if (UseSHA1Intrinsics) { StubRoutines::_sha1_implCompress = generate_sha1_implCompress(false, "sha1_implCompress"); StubRoutines::_sha1_implCompressMB = generate_sha1_implCompress(true, "sha1_implCompressMB"); @@ -7421,6 +7626,8 @@ class StubGenerator: public StubCodeGenerator { StubRoutines::_updateBytesAdler32 = generate_updateBytesAdler32(); } + StubRoutines::aarch64::_spin_wait = generate_spin_wait(); + #ifdef LINUX generate_atomic_entry_points(); diff --git a/src/hotspot/cpu/aarch64/stubRoutines_aarch64.cpp b/src/hotspot/cpu/aarch64/stubRoutines_aarch64.cpp index 1cbc3ed21d16f29037d4a2e0ec391f06a148e5e3..2e1c4b695425274c4f41223cf36e1ded7507dfa2 100644 --- a/src/hotspot/cpu/aarch64/stubRoutines_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/stubRoutines_aarch64.cpp @@ -45,8 +45,8 @@ address StubRoutines::aarch64::_float_sign_flip = NULL; address StubRoutines::aarch64::_double_sign_mask = NULL; address StubRoutines::aarch64::_double_sign_flip = NULL; address StubRoutines::aarch64::_zero_blocks = NULL; -address StubRoutines::aarch64::_has_negatives = NULL; -address StubRoutines::aarch64::_has_negatives_long = NULL; +address StubRoutines::aarch64::_count_positives = NULL; +address StubRoutines::aarch64::_count_positives_long = NULL; address StubRoutines::aarch64::_large_array_equals = NULL; address StubRoutines::aarch64::_compare_long_string_LL = NULL; address StubRoutines::aarch64::_compare_long_string_UU = NULL; @@ -57,6 +57,10 @@ address StubRoutines::aarch64::_string_indexof_linear_uu = NULL; address StubRoutines::aarch64::_string_indexof_linear_ul = NULL; address StubRoutines::aarch64::_large_byte_array_inflate = NULL; address StubRoutines::aarch64::_method_entry_barrier = NULL; + +static void empty_spin_wait() { } +address StubRoutines::aarch64::_spin_wait = CAST_FROM_FN_PTR(address, empty_spin_wait); + bool StubRoutines::aarch64::_completed = false; /** diff --git a/src/hotspot/cpu/aarch64/stubRoutines_aarch64.hpp b/src/hotspot/cpu/aarch64/stubRoutines_aarch64.hpp index e3ebc4484470120a4c445054414a638b326e9e92..a17e7540e42d24eac8f2db642c7d1f0c407b75ba 100644 --- a/src/hotspot/cpu/aarch64/stubRoutines_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/stubRoutines_aarch64.hpp @@ -36,7 +36,7 @@ static bool returns_to_call_stub(address return_pc) { enum platform_dependent_constants { code_size1 = 19000, // simply increase if too small (assembler will crash if too small) - code_size2 = 38000 // simply increase if too small (assembler will crash if too small) + code_size2 = 45000 // simply increase if too small (assembler will crash if too small) }; class aarch64 { @@ -58,8 +58,6 @@ class aarch64 { static address _zero_blocks; - static address _has_negatives; - static address _has_negatives_long; static address _large_array_equals; static address _compare_long_string_LL; static address _compare_long_string_LU; @@ -72,10 +70,15 @@ class aarch64 { static address _method_entry_barrier; + static address _spin_wait; + static bool _completed; public: + static address _count_positives; + static address _count_positives_long; + static address get_previous_sp_entry() { return _get_previous_sp_entry; @@ -129,12 +132,12 @@ class aarch64 { return _zero_blocks; } - static address has_negatives() { - return _has_negatives; + static address count_positives() { + return _count_positives; } - static address has_negatives_long() { - return _has_negatives_long; + static address count_positives_long() { + return _count_positives_long; } static address large_array_equals() { @@ -177,6 +180,10 @@ class aarch64 { return _method_entry_barrier; } + static address spin_wait() { + return _spin_wait; + } + static bool complete() { return _completed; } diff --git a/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp b/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp index e20cffd57670b49e7ee7372a5432f1a0c1249e2b..bf0a4e4472927e33b12b18c2ea8a310b665c3758 100644 --- a/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -832,6 +832,7 @@ void TemplateInterpreterGenerator::generate_fixed_frame(bool native_call) { __ ldr(rcpool, Address(rcpool, ConstantPool::cache_offset_in_bytes())); __ stp(rlocals, rcpool, Address(sp, 2 * wordSize)); + __ protect_return_address(); __ stp(rfp, lr, Address(sp, 10 * wordSize)); __ lea(rfp, Address(sp, 10 * wordSize)); @@ -1748,6 +1749,8 @@ void TemplateInterpreterGenerator::generate_throw_exception() { // adapter frames in C2. Label caller_not_deoptimized; __ ldr(c_rarg1, Address(rfp, frame::return_addr_offset * wordSize)); + // This is a return address, so requires authenticating for PAC. + __ authenticate_return_address(c_rarg1, rscratch1); __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::interpreter_contains), c_rarg1); __ cbnz(r0, caller_not_deoptimized); @@ -1937,6 +1940,7 @@ void TemplateInterpreterGenerator::set_vtos_entry_points(Template* t, address TemplateInterpreterGenerator::generate_trace_code(TosState state) { address entry = __ pc(); + __ protect_return_address(); __ push(lr); __ push(state); __ push(RegSet::range(r0, r15), sp); @@ -1947,6 +1951,7 @@ address TemplateInterpreterGenerator::generate_trace_code(TosState state) { __ pop(RegSet::range(r0, r15), sp); __ pop(state); __ pop(lr); + __ authenticate_return_address(); __ ret(lr); // return from result handler return entry; diff --git a/src/hotspot/cpu/aarch64/universalUpcallHandler_aarch64.cpp b/src/hotspot/cpu/aarch64/universalUpcallHandler_aarch64.cpp index 41bb34e40abe5f2b84db77c9f10ed2b5a986198a..e3287652891a40b2642c87167feee49999504fa0 100644 --- a/src/hotspot/cpu/aarch64/universalUpcallHandler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/universalUpcallHandler_aarch64.cpp @@ -71,7 +71,8 @@ address ProgrammableUpcallHandler::generate_upcall_stub(jobject rec, jobject jab // Capture prev stack pointer (stack arguments base) __ add(rscratch1, rfp, 16); // Skip saved FP and LR - __ str(rscratch1, Address(sp, layout.stack_args)); + Address slot = __ legitimize_address(Address(sp, layout.stack_args), wordSize, rscratch2); + __ str(rscratch1, slot); // Call upcall helper __ ldr(c_rarg0, rec_adr); diff --git a/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp b/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp index 48b74e7e50e250898469a1b37cd210c966b49a1b..d2a573ac63bd6880060d33f45cd095e084061b4b 100644 --- a/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2015, 2020, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -45,6 +45,7 @@ int VM_Version::_zva_length; int VM_Version::_dcache_line_size; int VM_Version::_icache_line_size; int VM_Version::_initial_sve_vector_length; +bool VM_Version::_rop_protection; SpinWait VM_Version::_spin_wait; @@ -197,11 +198,21 @@ void VM_Version::initialize() { } } - // Neoverse N1 - if (_cpu == CPU_ARM && (_model == 0xd0c || _model2 == 0xd0c)) { + // Neoverse N1, N2 and V1 + if (_cpu == CPU_ARM && ((_model == 0xd0c || _model2 == 0xd0c) + || (_model == 0xd49 || _model2 == 0xd49) + || (_model == 0xd40 || _model2 == 0xd40))) { if (FLAG_IS_DEFAULT(UseSIMDForMemoryOps)) { FLAG_SET_DEFAULT(UseSIMDForMemoryOps, true); } + + if (FLAG_IS_DEFAULT(OnSpinWaitInst)) { + FLAG_SET_DEFAULT(OnSpinWaitInst, "isb"); + } + + if (FLAG_IS_DEFAULT(OnSpinWaitInstCount)) { + FLAG_SET_DEFAULT(OnSpinWaitInstCount, 1); + } } if (_cpu == CPU_ARM) { @@ -293,9 +304,8 @@ void VM_Version::initialize() { FLAG_SET_DEFAULT(UseFMA, true); } - if (UseMD5Intrinsics) { - warning("MD5 intrinsics are not available on this CPU"); - FLAG_SET_DEFAULT(UseMD5Intrinsics, false); + if (FLAG_IS_DEFAULT(UseMD5Intrinsics)) { + UseMD5Intrinsics = true; } if (_features & (CPU_SHA1 | CPU_SHA2 | CPU_SHA3 | CPU_SHA512)) { @@ -400,6 +410,39 @@ void VM_Version::initialize() { UsePopCountInstruction = true; } + if (UseBranchProtection == nullptr || strcmp(UseBranchProtection, "none") == 0) { + _rop_protection = false; + } else if (strcmp(UseBranchProtection, "standard") == 0) { + _rop_protection = false; + // Enable PAC if this code has been built with branch-protection and the CPU/OS supports it. +#ifdef __ARM_FEATURE_PAC_DEFAULT + if ((_features & CPU_PACA) != 0) { + _rop_protection = true; + } +#endif + } else if (strcmp(UseBranchProtection, "pac-ret") == 0) { + _rop_protection = true; +#ifdef __ARM_FEATURE_PAC_DEFAULT + if ((_features & CPU_PACA) == 0) { + warning("ROP-protection specified, but not supported on this CPU."); + // Disable PAC to prevent illegal instruction crashes. + _rop_protection = false; + } +#else + warning("ROP-protection specified, but this VM was built without ROP-protection support."); +#endif + } else { + vm_exit_during_initialization(err_msg("Unsupported UseBranchProtection: %s", UseBranchProtection)); + } + + // The frame pointer must be preserved for ROP protection. + if (_rop_protection == true) { + if (FLAG_IS_DEFAULT(PreserveFramePointer) == false && PreserveFramePointer == false ) { + vm_exit_during_initialization(err_msg("PreserveFramePointer cannot be disabled for ROP-protection")); + } + PreserveFramePointer = true; + } + #ifdef COMPILER2 if (FLAG_IS_DEFAULT(UseMultiplyToLenIntrinsic)) { UseMultiplyToLenIntrinsic = true; @@ -462,6 +505,14 @@ void VM_Version::initialize() { } } + int inline_size = (UseSVE > 0 && MaxVectorSize >= 16) ? MaxVectorSize : 0; + if (FLAG_IS_DEFAULT(ArrayOperationPartialInlineSize)) { + FLAG_SET_DEFAULT(ArrayOperationPartialInlineSize, inline_size); + } else if (ArrayOperationPartialInlineSize != 0 && ArrayOperationPartialInlineSize != inline_size) { + warning("Setting ArrayOperationPartialInlineSize to %d", inline_size); + ArrayOperationPartialInlineSize = inline_size; + } + if (FLAG_IS_DEFAULT(OptoScheduling)) { OptoScheduling = true; } @@ -473,3 +524,22 @@ void VM_Version::initialize() { _spin_wait = get_spin_wait_desc(); } + +void VM_Version::initialize_cpu_information(void) { + // do nothing if cpu info has been initialized + if (_initialized) { + return; + } + + _no_of_cores = os::processor_count(); + _no_of_threads = _no_of_cores; + _no_of_sockets = _no_of_cores; + snprintf(_cpu_name, CPU_TYPE_DESC_BUF_SIZE - 1, "AArch64"); + + int desc_len = snprintf(_cpu_desc, CPU_DETAILED_DESC_BUF_SIZE, "AArch64 "); + get_compatible_board(_cpu_desc + desc_len, CPU_DETAILED_DESC_BUF_SIZE - desc_len); + desc_len = (int)strlen(_cpu_desc); + snprintf(_cpu_desc + desc_len, CPU_DETAILED_DESC_BUF_SIZE - desc_len, " %s", _features_string); + + _initialized = true; +} diff --git a/src/hotspot/cpu/aarch64/vm_version_aarch64.hpp b/src/hotspot/cpu/aarch64/vm_version_aarch64.hpp index 61f422bd2d38b3348f0294c1a741c8ba059b95a5..e979f62b926c78c927f59b716c4d8fcff1f380a1 100644 --- a/src/hotspot/cpu/aarch64/vm_version_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/vm_version_aarch64.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -45,6 +45,7 @@ protected: static int _dcache_line_size; static int _icache_line_size; static int _initial_sve_vector_length; + static bool _rop_protection; static SpinWait _spin_wait; @@ -114,10 +115,11 @@ public: decl(SHA3, "sha3", 17) \ decl(SHA512, "sha512", 21) \ decl(SVE, "sve", 22) \ + decl(PACA, "paca", 30) \ /* flags above must follow Linux HWCAP */ \ decl(SVE2, "sve2", 28) \ decl(STXR_PREFETCH, "stxr_prefetch", 29) \ - decl(A53MAC, "a53mac", 30) + decl(A53MAC, "a53mac", 31) #define DECLARE_CPU_FEATURE_FLAG(id, name, bit) CPU_##id = (1 << bit), CPU_FEATURE_FLAGS(DECLARE_CPU_FEATURE_FLAG) @@ -153,6 +155,10 @@ public: // Is the CPU running emulated (for example macOS Rosetta running x86_64 code on M1 ARM (aarch64) static bool is_cpu_emulated(); #endif + + static void initialize_cpu_information(void); + + static bool use_rop_protection() { return _rop_protection; } }; #endif // CPU_AARCH64_VM_VERSION_AARCH64_HPP diff --git a/src/hotspot/cpu/aarch64/vm_version_ext_aarch64.cpp b/src/hotspot/cpu/aarch64/vm_version_ext_aarch64.cpp deleted file mode 100644 index a95171173e9318615c439ea1b31c7bd2648e9677..0000000000000000000000000000000000000000 --- a/src/hotspot/cpu/aarch64/vm_version_ext_aarch64.cpp +++ /dev/null @@ -1,96 +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. - * - */ - -#include "precompiled.hpp" -#include "memory/allocation.hpp" -#include "memory/allocation.inline.hpp" -#include "runtime/os.inline.hpp" -#include "vm_version_ext_aarch64.hpp" - -// VM_Version_Ext statics -int VM_Version_Ext::_no_of_threads = 0; -int VM_Version_Ext::_no_of_cores = 0; -int VM_Version_Ext::_no_of_sockets = 0; -bool VM_Version_Ext::_initialized = false; -char VM_Version_Ext::_cpu_name[CPU_TYPE_DESC_BUF_SIZE] = {0}; -char VM_Version_Ext::_cpu_desc[CPU_DETAILED_DESC_BUF_SIZE] = {0}; - -void VM_Version_Ext::initialize_cpu_information(void) { - // do nothing if cpu info has been initialized - if (_initialized) { - return; - } - - int core_id = -1; - int chip_id = -1; - int len = 0; - char* src_string = NULL; - - _no_of_cores = os::processor_count(); - _no_of_threads = _no_of_cores; - _no_of_sockets = _no_of_cores; - snprintf(_cpu_name, CPU_TYPE_DESC_BUF_SIZE - 1, "AArch64"); - - int desc_len = snprintf(_cpu_desc, CPU_DETAILED_DESC_BUF_SIZE, "AArch64 "); - VM_Version::get_compatible_board(_cpu_desc + desc_len, CPU_DETAILED_DESC_BUF_SIZE - desc_len); - desc_len = (int)strlen(_cpu_desc); - snprintf(_cpu_desc + desc_len, CPU_DETAILED_DESC_BUF_SIZE - desc_len, " %s", _features_string); - - _initialized = true; -} - -int VM_Version_Ext::number_of_threads(void) { - initialize_cpu_information(); - return _no_of_threads; -} - -int VM_Version_Ext::number_of_cores(void) { - initialize_cpu_information(); - return _no_of_cores; -} - -int VM_Version_Ext::number_of_sockets(void) { - initialize_cpu_information(); - return _no_of_sockets; -} - -const char* VM_Version_Ext::cpu_name(void) { - initialize_cpu_information(); - char* tmp = NEW_C_HEAP_ARRAY_RETURN_NULL(char, CPU_TYPE_DESC_BUF_SIZE, mtTracing); - if (NULL == tmp) { - return NULL; - } - strncpy(tmp, _cpu_name, CPU_TYPE_DESC_BUF_SIZE); - return tmp; -} - -const char* VM_Version_Ext::cpu_description(void) { - initialize_cpu_information(); - char* tmp = NEW_C_HEAP_ARRAY_RETURN_NULL(char, CPU_DETAILED_DESC_BUF_SIZE, mtTracing); - if (NULL == tmp) { - return NULL; - } - strncpy(tmp, _cpu_desc, CPU_DETAILED_DESC_BUF_SIZE); - return tmp; -} diff --git a/src/hotspot/cpu/aarch64/vm_version_ext_aarch64.hpp b/src/hotspot/cpu/aarch64/vm_version_ext_aarch64.hpp deleted file mode 100644 index 0eced8e65575af258c3783b71bd1479d68d9cb99..0000000000000000000000000000000000000000 --- a/src/hotspot/cpu/aarch64/vm_version_ext_aarch64.hpp +++ /dev/null @@ -1,54 +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 CPU_AARCH64_VM_VERSION_EXT_AARCH64_HPP -#define CPU_AARCH64_VM_VERSION_EXT_AARCH64_HPP - -#include "runtime/vm_version.hpp" -#include "utilities/macros.hpp" - -class VM_Version_Ext : public VM_Version { - private: - static const size_t CPU_TYPE_DESC_BUF_SIZE = 256; - static const size_t CPU_DETAILED_DESC_BUF_SIZE = 4096; - - static int _no_of_threads; - static int _no_of_cores; - static int _no_of_sockets; - static bool _initialized; - static char _cpu_name[CPU_TYPE_DESC_BUF_SIZE]; - static char _cpu_desc[CPU_DETAILED_DESC_BUF_SIZE]; - - public: - static int number_of_threads(void); - static int number_of_cores(void); - static int number_of_sockets(void); - - static const char* cpu_name(void); - static const char* cpu_description(void); - static void initialize_cpu_information(void); - -}; - -#endif // CPU_AARCH64_VM_VERSION_EXT_AARCH64_HPP diff --git a/src/hotspot/cpu/aarch64/vmreg_aarch64.inline.hpp b/src/hotspot/cpu/aarch64/vmreg_aarch64.inline.hpp index 8452417b6cf188d4d90341271c23b3c2cc95519c..aa750104896f104e23d4541c9cd81cd37a62bf4d 100644 --- a/src/hotspot/cpu/aarch64/vmreg_aarch64.inline.hpp +++ b/src/hotspot/cpu/aarch64/vmreg_aarch64.inline.hpp @@ -26,17 +26,17 @@ #ifndef CPU_AARCH64_VMREG_AARCH64_INLINE_HPP #define CPU_AARCH64_VMREG_AARCH64_INLINE_HPP -inline VMReg RegisterImpl::as_VMReg() { +inline VMReg RegisterImpl::as_VMReg() const { if( this==noreg ) return VMRegImpl::Bad(); return VMRegImpl::as_VMReg(encoding() * RegisterImpl::max_slots_per_register); } -inline VMReg FloatRegisterImpl::as_VMReg() { +inline VMReg FloatRegisterImpl::as_VMReg() const { return VMRegImpl::as_VMReg((encoding() * FloatRegisterImpl::max_slots_per_register) + ConcreteRegisterImpl::max_gpr); } -inline VMReg PRegisterImpl::as_VMReg() { +inline VMReg PRegisterImpl::as_VMReg() const { return VMRegImpl::as_VMReg(encoding() + ConcreteRegisterImpl::max_fpr); } diff --git a/src/hotspot/cpu/arm/arm.ad b/src/hotspot/cpu/arm/arm.ad index 9e76f430054ac8a1ccbe3a6324b77812d638d52c..f2ac7b58e7336b859ee494318270823ed9107d16 100644 --- a/src/hotspot/cpu/arm/arm.ad +++ b/src/hotspot/cpu/arm/arm.ad @@ -1,5 +1,5 @@ // -// Copyright (c) 2008, 2021, Oracle and/or its affiliates. All rights reserved. +// Copyright (c) 2008, 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 @@ -123,9 +123,18 @@ public: }; }; +// Assert that the given node is not a var shift. +bool assert_not_var_shift(const Node *n); %} source %{ + +// Assert that the given node is not a var shift. +bool assert_not_var_shift(const Node *n) { + assert(!n->as_ShiftV()->is_var_shift(), "illegal var shift"); + return true; +} + #define __ _masm. static FloatRegister reg_to_FloatRegister_object(int register_encoding); @@ -991,7 +1000,7 @@ const RegMask* Matcher::predicate_reg_mask(void) { return NULL; } -const TypeVect* Matcher::predicate_reg_type(const Type* elemTy, int length) { +const TypeVectMask* Matcher::predicate_reg_type(const Type* elemTy, int length) { return NULL; } @@ -8385,7 +8394,7 @@ instruct cmpL3_reg_reg(iRegI dst, iRegL src1, iRegL src2, flagsReg ccr ) %{ // Conditional move instruct cmovLL_reg_LTGE(cmpOpL cmp, flagsRegL_LTGE xcc, iRegL dst, iRegL src) %{ match(Set dst (CMoveL (Binary cmp xcc) (Binary dst src))); - predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge ); + predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge); ins_cost(150); size(8); @@ -8398,9 +8407,9 @@ instruct cmovLL_reg_LTGE(cmpOpL cmp, flagsRegL_LTGE xcc, iRegL dst, iRegL src) % ins_pipe(ialu_reg); %} -instruct cmovLL_reg_LTGE_U(cmpOpL cmp, flagsRegUL_LTGE xcc, iRegL dst, iRegL src) %{ +instruct cmovLL_reg_LTGE_U(cmpOpUL cmp, flagsRegUL_LTGE xcc, iRegL dst, iRegL src) %{ match(Set dst (CMoveL (Binary cmp xcc) (Binary dst src))); - predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge ); + predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge); ins_cost(150); size(8); @@ -8415,7 +8424,7 @@ instruct cmovLL_reg_LTGE_U(cmpOpL cmp, flagsRegUL_LTGE xcc, iRegL dst, iRegL src instruct cmovLL_reg_EQNE(cmpOpL cmp, flagsRegL_EQNE xcc, iRegL dst, iRegL src) %{ match(Set dst (CMoveL (Binary cmp xcc) (Binary dst src))); - predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne ); + predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne); ins_cost(150); size(8); @@ -8430,7 +8439,7 @@ instruct cmovLL_reg_EQNE(cmpOpL cmp, flagsRegL_EQNE xcc, iRegL dst, iRegL src) % instruct cmovLL_reg_LEGT(cmpOpL_commute cmp, flagsRegL_LEGT xcc, iRegL dst, iRegL src) %{ match(Set dst (CMoveL (Binary cmp xcc) (Binary dst src))); - predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::le || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::gt ); + predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::le || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::gt); ins_cost(150); size(8); @@ -8443,9 +8452,9 @@ instruct cmovLL_reg_LEGT(cmpOpL_commute cmp, flagsRegL_LEGT xcc, iRegL dst, iReg ins_pipe(ialu_reg); %} -instruct cmovLL_reg_LEGT_U(cmpOpL_commute cmp, flagsRegUL_LEGT xcc, iRegL dst, iRegL src) %{ +instruct cmovLL_reg_LEGT_U(cmpOpUL_commute cmp, flagsRegUL_LEGT xcc, iRegL dst, iRegL src) %{ match(Set dst (CMoveL (Binary cmp xcc) (Binary dst src))); - predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::le || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::gt ); + predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::le || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::gt); ins_cost(150); size(8); @@ -8460,7 +8469,7 @@ instruct cmovLL_reg_LEGT_U(cmpOpL_commute cmp, flagsRegUL_LEGT xcc, iRegL dst, i instruct cmovLL_imm_LTGE(cmpOpL cmp, flagsRegL_LTGE xcc, iRegL dst, immL0 src) %{ match(Set dst (CMoveL (Binary cmp xcc) (Binary dst src))); - predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge ); + predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge); ins_cost(140); size(8); format %{ "MOV$cmp $dst.lo,0\t! long\n\t" @@ -8472,9 +8481,9 @@ instruct cmovLL_imm_LTGE(cmpOpL cmp, flagsRegL_LTGE xcc, iRegL dst, immL0 src) % ins_pipe(ialu_imm); %} -instruct cmovLL_imm_LTGE_U(cmpOpL cmp, flagsRegUL_LTGE xcc, iRegL dst, immL0 src) %{ +instruct cmovLL_imm_LTGE_U(cmpOpUL cmp, flagsRegUL_LTGE xcc, iRegL dst, immL0 src) %{ match(Set dst (CMoveL (Binary cmp xcc) (Binary dst src))); - predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge ); + predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge); ins_cost(140); size(8); format %{ "MOV$cmp $dst.lo,0\t! long\n\t" @@ -8488,7 +8497,7 @@ instruct cmovLL_imm_LTGE_U(cmpOpL cmp, flagsRegUL_LTGE xcc, iRegL dst, immL0 src instruct cmovLL_imm_EQNE(cmpOpL cmp, flagsRegL_EQNE xcc, iRegL dst, immL0 src) %{ match(Set dst (CMoveL (Binary cmp xcc) (Binary dst src))); - predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne ); + predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne); ins_cost(140); size(8); format %{ "MOV$cmp $dst.lo,0\t! long\n\t" @@ -8502,7 +8511,7 @@ instruct cmovLL_imm_EQNE(cmpOpL cmp, flagsRegL_EQNE xcc, iRegL dst, immL0 src) % instruct cmovLL_imm_LEGT(cmpOpL_commute cmp, flagsRegL_LEGT xcc, iRegL dst, immL0 src) %{ match(Set dst (CMoveL (Binary cmp xcc) (Binary dst src))); - predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::le || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::gt ); + predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::le || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::gt); ins_cost(140); size(8); format %{ "MOV$cmp $dst.lo,0\t! long\n\t" @@ -8516,7 +8525,20 @@ instruct cmovLL_imm_LEGT(cmpOpL_commute cmp, flagsRegL_LEGT xcc, iRegL dst, immL instruct cmovIL_reg_LTGE(cmpOpL cmp, flagsRegL_LTGE xcc, iRegI dst, iRegI src) %{ match(Set dst (CMoveI (Binary cmp xcc) (Binary dst src))); - predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge ); + predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge); + + ins_cost(150); + size(4); + format %{ "MOV$cmp $dst,$src" %} + ins_encode %{ + __ mov($dst$$Register, $src$$Register, (AsmCondition)($cmp$$cmpcode)); + %} + ins_pipe(ialu_reg); +%} + +instruct cmovIL_reg_LTGE_U(cmpOpUL cmp, flagsRegUL_LTGE xcc, iRegI dst, iRegI src) %{ + match(Set dst (CMoveI (Binary cmp xcc) (Binary dst src))); + predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge); ins_cost(150); size(4); @@ -8529,7 +8551,7 @@ instruct cmovIL_reg_LTGE(cmpOpL cmp, flagsRegL_LTGE xcc, iRegI dst, iRegI src) % instruct cmovIL_reg_EQNE(cmpOpL cmp, flagsRegL_EQNE xcc, iRegI dst, iRegI src) %{ match(Set dst (CMoveI (Binary cmp xcc) (Binary dst src))); - predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne ); + predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne); ins_cost(150); size(4); @@ -8540,9 +8562,22 @@ instruct cmovIL_reg_EQNE(cmpOpL cmp, flagsRegL_EQNE xcc, iRegI dst, iRegI src) % ins_pipe(ialu_reg); %} +instruct cmovIL_reg_EQNE_U(cmpOpUL cmp, flagsRegUL_EQNE xcc, iRegI dst, iRegI src) %{ + match(Set dst (CMoveI (Binary cmp xcc) (Binary dst src))); + predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne); + + ins_cost(150); + size(4); + format %{ "MOV$cmp $dst,$src" %} + ins_encode %{ + __ mov($dst$$Register, $src$$Register, (AsmCondition)($cmp$$cmpcode)); + %} + ins_pipe(ialu_reg); +%} + instruct cmovIL_reg_LEGT(cmpOpL_commute cmp, flagsRegL_LEGT xcc, iRegI dst, iRegI src) %{ match(Set dst (CMoveI (Binary cmp xcc) (Binary dst src))); - predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::le || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::gt ); + predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::le || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::gt); ins_cost(150); size(4); @@ -8553,11 +8588,51 @@ instruct cmovIL_reg_LEGT(cmpOpL_commute cmp, flagsRegL_LEGT xcc, iRegI dst, iReg ins_pipe(ialu_reg); %} -instruct cmovIL_imm_LTGE(cmpOpL cmp, flagsRegL_LTGE xcc, iRegI dst, immI16 src) %{ +instruct cmovIL_reg_LEGT_U(cmpOpUL_commute cmp, flagsRegUL_LEGT xcc, iRegI dst, iRegI src) %{ + match(Set dst (CMoveI (Binary cmp xcc) (Binary dst src))); + predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::le || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::gt); + + ins_cost(150); + size(4); + format %{ "MOV$cmp $dst,$src" %} + ins_encode %{ + __ mov($dst$$Register, $src$$Register, (AsmCondition)($cmp$$cmpcode)); + %} + ins_pipe(ialu_reg); +%} + +instruct cmovIL_imm16_LTGE(cmpOpL cmp, flagsRegL_LTGE xcc, iRegI dst, immI16 src) %{ + match(Set dst (CMoveI (Binary cmp xcc) (Binary dst src))); + predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge); + + ins_cost(140); + size(4); + format %{ "MOVW$cmp $dst,$src" %} + ins_encode %{ + __ movw($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode)); + %} + ins_pipe(ialu_imm); +%} + +instruct cmovIL_imm16_LTGE_U(cmpOpUL cmp, flagsRegUL_LTGE xcc, iRegI dst, immI16 src) %{ + match(Set dst (CMoveI (Binary cmp xcc) (Binary dst src))); + predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge); + + ins_cost(140); + size(4); + format %{ "MOVW$cmp $dst,$src" %} + ins_encode %{ + __ movw($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode)); + %} + ins_pipe(ialu_imm); +%} + +instruct cmovIL_imm16_EQNE(cmpOpL cmp, flagsRegL_EQNE xcc, iRegI dst, immI16 src) %{ match(Set dst (CMoveI (Binary cmp xcc) (Binary dst src))); - predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge ); + predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne); ins_cost(140); + size(4); format %{ "MOVW$cmp $dst,$src" %} ins_encode %{ __ movw($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode)); @@ -8565,11 +8640,12 @@ instruct cmovIL_imm_LTGE(cmpOpL cmp, flagsRegL_LTGE xcc, iRegI dst, immI16 src) ins_pipe(ialu_imm); %} -instruct cmovIL_imm_EQNE(cmpOpL cmp, flagsRegL_EQNE xcc, iRegI dst, immI16 src) %{ +instruct cmovIL_imm16_EQNE_U(cmpOpUL cmp, flagsRegUL_EQNE xcc, iRegI dst, immI16 src) %{ match(Set dst (CMoveI (Binary cmp xcc) (Binary dst src))); - predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne ); + predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne); ins_cost(140); + size(4); format %{ "MOVW$cmp $dst,$src" %} ins_encode %{ __ movw($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode)); @@ -8577,11 +8653,12 @@ instruct cmovIL_imm_EQNE(cmpOpL cmp, flagsRegL_EQNE xcc, iRegI dst, immI16 src) ins_pipe(ialu_imm); %} -instruct cmovIL_imm_LEGT(cmpOpL_commute cmp, flagsRegL_LEGT xcc, iRegI dst, immI16 src) %{ +instruct cmovIL_imm16_LEGT(cmpOpL_commute cmp, flagsRegL_LEGT xcc, iRegI dst, immI16 src) %{ match(Set dst (CMoveI (Binary cmp xcc) (Binary dst src))); - predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::le || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::gt ); + predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::le || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::gt); ins_cost(140); + size(4); format %{ "MOVW$cmp $dst,$src" %} ins_encode %{ __ movw($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode)); @@ -8589,9 +8666,113 @@ instruct cmovIL_imm_LEGT(cmpOpL_commute cmp, flagsRegL_LEGT xcc, iRegI dst, immI ins_pipe(ialu_imm); %} +instruct cmovIL_imm16_LEGT_U(cmpOpUL_commute cmp, flagsRegUL_LEGT xcc, iRegI dst, immI16 src) %{ + match(Set dst (CMoveI (Binary cmp xcc) (Binary dst src))); + predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::le || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::gt); + + ins_cost(140); + size(4); + format %{ "MOVW$cmp $dst,$src" %} + ins_encode %{ + __ movw($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode)); + %} + ins_pipe(ialu_imm); +%} + +instruct cmovIL_immMov_LTGE(cmpOpL cmp, flagsRegL_LTGE xcc, iRegI dst, immIMov src) %{ + match(Set dst (CMoveI (Binary cmp xcc) (Binary dst src))); + predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge); + + ins_cost(140); + size(4); + format %{ "MOV$cmp $dst,$src" %} + ins_encode %{ + __ mov($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode)); + %} + ins_pipe(ialu_imm); +%} + +instruct cmovIL_immMov_LTGE_U(cmpOpUL cmp, flagsRegUL_LTGE xcc, iRegI dst, immIMov src) %{ + match(Set dst (CMoveI (Binary cmp xcc) (Binary dst src))); + predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge); + + ins_cost(140); + size(4); + format %{ "MOV$cmp $dst,$src" %} + ins_encode %{ + __ mov($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode)); + %} + ins_pipe(ialu_imm); +%} + +instruct cmovIL_immMov_EQNE(cmpOpL cmp, flagsRegL_EQNE xcc, iRegI dst, immIMov src) %{ + match(Set dst (CMoveI (Binary cmp xcc) (Binary dst src))); + predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne); + + ins_cost(140); + size(4); + format %{ "MOV$cmp $dst,$src" %} + ins_encode %{ + __ mov($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode)); + %} + ins_pipe(ialu_imm); +%} + +instruct cmovIL_immMov_EQNE_U(cmpOpUL cmp, flagsRegUL_EQNE xcc, iRegI dst, immIMov src) %{ + match(Set dst (CMoveI (Binary cmp xcc) (Binary dst src))); + predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne); + + ins_cost(140); + size(4); + format %{ "MOV$cmp $dst,$src" %} + ins_encode %{ + __ mov($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode)); + %} + ins_pipe(ialu_imm); +%} + +instruct cmovIL_immMov_LEGT(cmpOpL_commute cmp, flagsRegL_LEGT xcc, iRegI dst, immIMov src) %{ + match(Set dst (CMoveI (Binary cmp xcc) (Binary dst src))); + predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::le || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::gt); + + ins_cost(140); + size(4); + format %{ "MOV$cmp $dst,$src" %} + ins_encode %{ + __ mov($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode)); + %} + ins_pipe(ialu_imm); +%} + +instruct cmovIL_immMov_LEGT_U(cmpOpUL_commute cmp, flagsRegUL_LEGT xcc, iRegI dst, immIMov src) %{ + match(Set dst (CMoveI (Binary cmp xcc) (Binary dst src))); + predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::le || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::gt); + + ins_cost(140); + size(4); + format %{ "MOV$cmp $dst,$src" %} + ins_encode %{ + __ mov($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode)); + %} + ins_pipe(ialu_imm); +%} + instruct cmovPL_reg_LTGE(cmpOpL cmp, flagsRegL_LTGE xcc, iRegP dst, iRegP src) %{ match(Set dst (CMoveP (Binary cmp xcc) (Binary dst src))); - predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge ); + predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge); + + ins_cost(150); + size(4); + format %{ "MOV$cmp $dst,$src" %} + ins_encode %{ + __ mov($dst$$Register, $src$$Register, (AsmCondition)($cmp$$cmpcode)); + %} + ins_pipe(ialu_reg); +%} + +instruct cmovPL_reg_LTGE_U(cmpOpUL cmp, flagsRegUL_LTGE xcc, iRegP dst, iRegP src) %{ + match(Set dst (CMoveP (Binary cmp xcc) (Binary dst src))); + predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge); ins_cost(150); size(4); @@ -8604,7 +8785,20 @@ instruct cmovPL_reg_LTGE(cmpOpL cmp, flagsRegL_LTGE xcc, iRegP dst, iRegP src) % instruct cmovPL_reg_EQNE(cmpOpL cmp, flagsRegL_EQNE xcc, iRegP dst, iRegP src) %{ match(Set dst (CMoveP (Binary cmp xcc) (Binary dst src))); - predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne ); + predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne); + + ins_cost(150); + size(4); + format %{ "MOV$cmp $dst,$src" %} + ins_encode %{ + __ mov($dst$$Register, $src$$Register, (AsmCondition)($cmp$$cmpcode)); + %} + ins_pipe(ialu_reg); +%} + +instruct cmovPL_reg_EQNE_U(cmpOpUL cmp, flagsRegUL_EQNE xcc, iRegP dst, iRegP src) %{ + match(Set dst (CMoveP (Binary cmp xcc) (Binary dst src))); + predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne); ins_cost(150); size(4); @@ -8617,7 +8811,20 @@ instruct cmovPL_reg_EQNE(cmpOpL cmp, flagsRegL_EQNE xcc, iRegP dst, iRegP src) % instruct cmovPL_reg_LEGT(cmpOpL_commute cmp, flagsRegL_LEGT xcc, iRegP dst, iRegP src) %{ match(Set dst (CMoveP (Binary cmp xcc) (Binary dst src))); - predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::le || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::gt ); + predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::le || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::gt); + + ins_cost(150); + size(4); + format %{ "MOV$cmp $dst,$src" %} + ins_encode %{ + __ mov($dst$$Register, $src$$Register, (AsmCondition)($cmp$$cmpcode)); + %} + ins_pipe(ialu_reg); +%} + +instruct cmovPL_reg_LEGT_U(cmpOpUL_commute cmp, flagsRegUL_LEGT xcc, iRegP dst, iRegP src) %{ + match(Set dst (CMoveP (Binary cmp xcc) (Binary dst src))); + predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::le || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::gt); ins_cost(150); size(4); @@ -8630,9 +8837,23 @@ instruct cmovPL_reg_LEGT(cmpOpL_commute cmp, flagsRegL_LEGT xcc, iRegP dst, iReg instruct cmovPL_imm_LTGE(cmpOpL cmp, flagsRegL_LTGE xcc, iRegP dst, immP0 src) %{ match(Set dst (CMoveP (Binary cmp xcc) (Binary dst src))); - predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge ); + predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge); ins_cost(140); + size(4); + format %{ "MOVW$cmp $dst,$src" %} + ins_encode %{ + __ movw($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode)); + %} + ins_pipe(ialu_imm); +%} + +instruct cmovPL_imm_LTGE_U(cmpOpUL cmp, flagsRegUL_LTGE xcc, iRegP dst, immP0 src) %{ + match(Set dst (CMoveP (Binary cmp xcc) (Binary dst src))); + predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge); + + ins_cost(140); + size(4); format %{ "MOVW$cmp $dst,$src" %} ins_encode %{ __ movw($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode)); @@ -8642,9 +8863,23 @@ instruct cmovPL_imm_LTGE(cmpOpL cmp, flagsRegL_LTGE xcc, iRegP dst, immP0 src) % instruct cmovPL_imm_EQNE(cmpOpL cmp, flagsRegL_EQNE xcc, iRegP dst, immP0 src) %{ match(Set dst (CMoveP (Binary cmp xcc) (Binary dst src))); - predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne ); + predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne); + + ins_cost(140); + size(4); + format %{ "MOVW$cmp $dst,$src" %} + ins_encode %{ + __ movw($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode)); + %} + ins_pipe(ialu_imm); +%} + +instruct cmovPL_imm_EQNE_U(cmpOpUL cmp, flagsRegUL_EQNE xcc, iRegP dst, immP0 src) %{ + match(Set dst (CMoveP (Binary cmp xcc) (Binary dst src))); + predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne); ins_cost(140); + size(4); format %{ "MOVW$cmp $dst,$src" %} ins_encode %{ __ movw($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode)); @@ -8654,9 +8889,23 @@ instruct cmovPL_imm_EQNE(cmpOpL cmp, flagsRegL_EQNE xcc, iRegP dst, immP0 src) % instruct cmovPL_imm_LEGT(cmpOpL_commute cmp, flagsRegL_LEGT xcc, iRegP dst, immP0 src) %{ match(Set dst (CMoveP (Binary cmp xcc) (Binary dst src))); - predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::le || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::gt ); + predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::le || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::gt); + + ins_cost(140); + size(4); + format %{ "MOVW$cmp $dst,$src" %} + ins_encode %{ + __ movw($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode)); + %} + ins_pipe(ialu_imm); +%} + +instruct cmovPL_imm_LEGT_U(cmpOpUL_commute cmp, flagsRegUL_LEGT xcc, iRegP dst, immP0 src) %{ + match(Set dst (CMoveP (Binary cmp xcc) (Binary dst src))); + predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::le || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::gt); ins_cost(140); + size(4); format %{ "MOVW$cmp $dst,$src" %} ins_encode %{ __ movw($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode)); @@ -8666,7 +8915,7 @@ instruct cmovPL_imm_LEGT(cmpOpL_commute cmp, flagsRegL_LEGT xcc, iRegP dst, immP instruct cmovFL_reg_LTGE(cmpOpL cmp, flagsRegL_LTGE xcc, regF dst, regF src) %{ match(Set dst (CMoveF (Binary cmp xcc) (Binary dst src))); - predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge ); + predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge); ins_cost(150); size(4); format %{ "FCPYS$cmp $dst,$src" %} @@ -8678,7 +8927,7 @@ instruct cmovFL_reg_LTGE(cmpOpL cmp, flagsRegL_LTGE xcc, regF dst, regF src) %{ instruct cmovFL_reg_EQNE(cmpOpL cmp, flagsRegL_EQNE xcc, regF dst, regF src) %{ match(Set dst (CMoveF (Binary cmp xcc) (Binary dst src))); - predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne ); + predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne); ins_cost(150); size(4); format %{ "FCPYS$cmp $dst,$src" %} @@ -8690,7 +8939,7 @@ instruct cmovFL_reg_EQNE(cmpOpL cmp, flagsRegL_EQNE xcc, regF dst, regF src) %{ instruct cmovFL_reg_LEGT(cmpOpL_commute cmp, flagsRegL_LEGT xcc, regF dst, regF src) %{ match(Set dst (CMoveF (Binary cmp xcc) (Binary dst src))); - predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::le || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::gt ); + predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::le || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::gt); ins_cost(150); size(4); format %{ "FCPYS$cmp $dst,$src" %} @@ -8702,7 +8951,7 @@ instruct cmovFL_reg_LEGT(cmpOpL_commute cmp, flagsRegL_LEGT xcc, regF dst, regF instruct cmovDL_reg_LTGE(cmpOpL cmp, flagsRegL_LTGE xcc, regD dst, regD src) %{ match(Set dst (CMoveD (Binary cmp xcc) (Binary dst src))); - predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge ); + predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge); ins_cost(150); size(4); @@ -8715,7 +8964,7 @@ instruct cmovDL_reg_LTGE(cmpOpL cmp, flagsRegL_LTGE xcc, regD dst, regD src) %{ instruct cmovDL_reg_EQNE(cmpOpL cmp, flagsRegL_EQNE xcc, regD dst, regD src) %{ match(Set dst (CMoveD (Binary cmp xcc) (Binary dst src))); - predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne ); + predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne); ins_cost(150); size(4); @@ -8728,7 +8977,7 @@ instruct cmovDL_reg_EQNE(cmpOpL cmp, flagsRegL_EQNE xcc, regD dst, regD src) %{ instruct cmovDL_reg_LEGT(cmpOpL_commute cmp, flagsRegL_LEGT xcc, regD dst, regD src) %{ match(Set dst (CMoveD (Binary cmp xcc) (Binary dst src))); - predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::le || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::gt ); + predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::le || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::gt); ins_cost(150); size(4); @@ -10351,7 +10600,7 @@ instruct vneg16B_reg(vecX dst, vecX src) %{ ins_pipe( ialu_reg_reg ); // FIXME %} -// ------------------------------ Shift --------------------------------------- +// ------------------------------ ShiftCount ---------------------------------- instruct vslcntD(vecD dst, iRegI cnt) %{ predicate(n->as_Vector()->length_in_bytes() == 8 && VM_Version::has_simd()); @@ -10410,6 +10659,8 @@ instruct vsrcntX(vecX dst, iRegI cnt) %{ ins_pipe( ialu_reg_reg ); // FIXME %} +// ------------------------------ LogicalShift -------------------------------- + // Byte vector logical left/right shift based on sign instruct vsh8B_reg(vecD dst, vecD src, vecD shift) %{ predicate(n->as_Vector()->length() == 8); @@ -10526,9 +10777,9 @@ instruct vsh2L_reg(vecX dst, vecX src, vecX shift) %{ ins_pipe( ialu_reg_reg ); // FIXME %} -// ------------------------------ LeftShift ----------------------------------- +// ------------------------------ LogicalLeftShift ---------------------------- -// Byte vector left shift +// Byte vector logical left shift instruct vsl8B_reg(vecD dst, vecD src, vecD shift) %{ predicate(n->as_Vector()->length() == 8); match(Set dst (LShiftVB src shift)); @@ -10550,7 +10801,7 @@ instruct vsl16B_reg(vecX dst, vecX src, vecX shift) %{ %} instruct vsl8B_immI(vecD dst, vecD src, immI shift) %{ - predicate(n->as_Vector()->length() == 8); + predicate(n->as_Vector()->length() == 8 && assert_not_var_shift(n)); match(Set dst (LShiftVB src (LShiftCntV shift))); size(4); ins_cost(DEFAULT_COST); // FIXME @@ -10566,7 +10817,7 @@ instruct vsl8B_immI(vecD dst, vecD src, immI shift) %{ %} instruct vsl16B_immI(vecX dst, vecX src, immI shift) %{ - predicate(n->as_Vector()->length() == 16); + predicate(n->as_Vector()->length() == 16 && assert_not_var_shift(n)); match(Set dst (LShiftVB src (LShiftCntV shift))); size(4); ins_cost(DEFAULT_COST); // FIXME @@ -10581,11 +10832,10 @@ instruct vsl16B_immI(vecX dst, vecX src, immI shift) %{ ins_pipe( ialu_reg_reg ); // FIXME %} -// Shorts/Chars vector logical left/right shift +// Shorts/Chars vector logical left shift instruct vsl4S_reg(vecD dst, vecD src, vecD shift) %{ predicate(n->as_Vector()->length() == 4); match(Set dst (LShiftVS src shift)); - match(Set dst (URShiftVS src shift)); size(4*1); ins_cost(DEFAULT_COST*1); // FIXME expand %{ @@ -10596,7 +10846,6 @@ instruct vsl4S_reg(vecD dst, vecD src, vecD shift) %{ instruct vsl8S_reg(vecX dst, vecX src, vecX shift) %{ predicate(n->as_Vector()->length() == 8); match(Set dst (LShiftVS src shift)); - match(Set dst (URShiftVS src shift)); size(4*1); ins_cost(DEFAULT_COST*1); // FIXME expand %{ @@ -10605,7 +10854,7 @@ instruct vsl8S_reg(vecX dst, vecX src, vecX shift) %{ %} instruct vsl4S_immI(vecD dst, vecD src, immI shift) %{ - predicate(n->as_Vector()->length() == 4); + predicate(n->as_Vector()->length() == 4 && assert_not_var_shift(n)); match(Set dst (LShiftVS src (LShiftCntV shift))); size(4); ins_cost(DEFAULT_COST); // FIXME @@ -10621,7 +10870,7 @@ instruct vsl4S_immI(vecD dst, vecD src, immI shift) %{ %} instruct vsl8S_immI(vecX dst, vecX src, immI shift) %{ - predicate(n->as_Vector()->length() == 8); + predicate(n->as_Vector()->length() == 8 && assert_not_var_shift(n)); match(Set dst (LShiftVS src shift)); size(4); ins_cost(DEFAULT_COST); // FIXME @@ -10636,11 +10885,10 @@ instruct vsl8S_immI(vecX dst, vecX src, immI shift) %{ ins_pipe( ialu_reg_reg ); // FIXME %} -// Integers vector logical left/right shift +// Integers vector logical left shift instruct vsl2I_reg(vecD dst, vecD src, vecD shift) %{ predicate(n->as_Vector()->length() == 2 && VM_Version::has_simd()); match(Set dst (LShiftVI src shift)); - match(Set dst (URShiftVI src shift)); size(4*1); ins_cost(DEFAULT_COST*1); // FIXME expand %{ @@ -10651,7 +10899,6 @@ instruct vsl2I_reg(vecD dst, vecD src, vecD shift) %{ instruct vsl4I_reg(vecX dst, vecX src, vecX shift) %{ predicate(n->as_Vector()->length() == 4 && VM_Version::has_simd()); match(Set dst (LShiftVI src shift)); - match(Set dst (URShiftVI src shift)); size(4*1); ins_cost(DEFAULT_COST*1); // FIXME expand %{ @@ -10660,7 +10907,9 @@ instruct vsl4I_reg(vecX dst, vecX src, vecX shift) %{ %} instruct vsl2I_immI(vecD dst, vecD src, immI shift) %{ - predicate(n->as_Vector()->length() == 2 && VM_Version::has_simd()); + predicate(n->as_Vector()->length() == 2 && + VM_Version::has_simd() && + assert_not_var_shift(n)); match(Set dst (LShiftVI src (LShiftCntV shift))); size(4); ins_cost(DEFAULT_COST); // FIXME @@ -10676,7 +10925,9 @@ instruct vsl2I_immI(vecD dst, vecD src, immI shift) %{ %} instruct vsl4I_immI(vecX dst, vecX src, immI shift) %{ - predicate(n->as_Vector()->length() == 4 && VM_Version::has_simd()); + predicate(n->as_Vector()->length() == 4 && + VM_Version::has_simd() && + assert_not_var_shift(n)); match(Set dst (LShiftVI src (LShiftCntV shift))); size(4); ins_cost(DEFAULT_COST); // FIXME @@ -10691,11 +10942,10 @@ instruct vsl4I_immI(vecX dst, vecX src, immI shift) %{ ins_pipe( ialu_reg_reg ); // FIXME %} -// Longs vector logical left/right shift +// Longs vector logical left shift instruct vsl2L_reg(vecX dst, vecX src, vecX shift) %{ predicate(n->as_Vector()->length() == 2); match(Set dst (LShiftVL src shift)); - match(Set dst (URShiftVL src shift)); size(4*1); ins_cost(DEFAULT_COST*1); // FIXME expand %{ @@ -10704,7 +10954,7 @@ instruct vsl2L_reg(vecX dst, vecX src, vecX shift) %{ %} instruct vsl2L_immI(vecX dst, vecX src, immI shift) %{ - predicate(n->as_Vector()->length() == 2); + predicate(n->as_Vector()->length() == 2 && assert_not_var_shift(n)); match(Set dst (LShiftVL src (LShiftCntV shift))); size(4); ins_cost(DEFAULT_COST); // FIXME @@ -10725,9 +10975,79 @@ instruct vsl2L_immI(vecX dst, vecX src, immI shift) %{ // for negative data because java code convert short value into int with // sign extension before a shift. +// Right shift with vector shift count on aarch32 SIMD is implemented as left +// shift by negative shift count value. +// +// Method is_var_shift() denotes that vector shift count is a variable shift: +// 1) for this case, vector shift count should be negated before conducting +// right shifts. E.g., vsrl4S_reg_var rule. +// 2) for the opposite case, vector shift count is generated via RShiftCntV +// rules and is already negated there. Hence, no negation is needed. +// E.g., vsrl4S_reg rule. + // Chars vector logical right shift +instruct vsrl4S_reg(vecD dst, vecD src, vecD shift) %{ + predicate(n->as_Vector()->length() == 4 && !n->as_ShiftV()->is_var_shift()); + match(Set dst (URShiftVS src shift)); + size(4); + ins_cost(DEFAULT_COST); + expand %{ + vsh4S_reg(dst, src, shift); + %} +%} + +instruct vsrl4S_reg_var(vecD dst, vecD src, vecD shift, vecD tmp) %{ + predicate(n->as_Vector()->length() == 4 && n->as_ShiftV()->is_var_shift()); + match(Set dst (URShiftVS src shift)); + effect(TEMP tmp); + size(4*2); + ins_cost(DEFAULT_COST*2); + format %{ + "VNEG.S8 $tmp.D,$shift.D\n\t! neg packed8B" + "VSHL.U16 $dst.D,$src.D,$tmp.D\t! logical right shift packed4S" + %} + ins_encode %{ + bool quad = false; + __ vnegI($tmp$$FloatRegister, $shift$$FloatRegister, + MacroAssembler::VELEM_SIZE_8, quad); + __ vshlUI($dst$$FloatRegister, $tmp$$FloatRegister, $src$$FloatRegister, + MacroAssembler::VELEM_SIZE_16, quad); + %} + ins_pipe(ialu_reg_reg); +%} + +instruct vsrl8S_reg(vecX dst, vecX src, vecX shift) %{ + predicate(n->as_Vector()->length() == 8 && !n->as_ShiftV()->is_var_shift()); + match(Set dst (URShiftVS src shift)); + size(4); + ins_cost(DEFAULT_COST); + expand %{ + vsh8S_reg(dst, src, shift); + %} +%} + +instruct vsrl8S_reg_var(vecX dst, vecX src, vecX shift, vecX tmp) %{ + predicate(n->as_Vector()->length() == 8 && n->as_ShiftV()->is_var_shift()); + match(Set dst (URShiftVS src shift)); + effect(TEMP tmp); + size(4*2); + ins_cost(DEFAULT_COST*2); + format %{ + "VNEG.S8 $tmp.Q,$shift.Q\n\t! neg packed16B" + "VSHL.U16 $dst.Q,$src.Q,$tmp.Q\t! logical right shift packed8S" + %} + ins_encode %{ + bool quad = true; + __ vnegI($tmp$$FloatRegister, $shift$$FloatRegister, + MacroAssembler::VELEM_SIZE_8, quad); + __ vshlUI($dst$$FloatRegister, $tmp$$FloatRegister, $src$$FloatRegister, + MacroAssembler::VELEM_SIZE_16, quad); + %} + ins_pipe(ialu_reg_reg); +%} + instruct vsrl4S_immI(vecD dst, vecD src, immI shift) %{ - predicate(n->as_Vector()->length() == 4); + predicate(n->as_Vector()->length() == 4 && assert_not_var_shift(n)); match(Set dst (URShiftVS src (RShiftCntV shift))); size(4); ins_cost(DEFAULT_COST); // FIXME @@ -10743,7 +11063,7 @@ instruct vsrl4S_immI(vecD dst, vecD src, immI shift) %{ %} instruct vsrl8S_immI(vecX dst, vecX src, immI shift) %{ - predicate(n->as_Vector()->length() == 8); + predicate(n->as_Vector()->length() == 8 && assert_not_var_shift(n)); match(Set dst (URShiftVS src (RShiftCntV shift))); size(4); ins_cost(DEFAULT_COST); // FIXME @@ -10759,8 +11079,78 @@ instruct vsrl8S_immI(vecX dst, vecX src, immI shift) %{ %} // Integers vector logical right shift +instruct vsrl2I_reg(vecD dst, vecD src, vecD shift) %{ + predicate(n->as_Vector()->length() == 2 && + VM_Version::has_simd() && + !n->as_ShiftV()->is_var_shift()); + match(Set dst (URShiftVI src shift)); + size(4); + ins_cost(DEFAULT_COST); + expand %{ + vsh2I_reg(dst, src, shift); + %} +%} + +instruct vsrl2I_reg_var(vecD dst, vecD src, vecD shift, vecD tmp) %{ + predicate(n->as_Vector()->length() == 2 && + VM_Version::has_simd() && + n->as_ShiftV()->is_var_shift()); + match(Set dst (URShiftVI src shift)); + effect(TEMP tmp); + size(4*2); + ins_cost(DEFAULT_COST*2); + format %{ + "VNEG.S8 $tmp.D,$shift.D\n\t! neg packed8B" + "VSHL.U32 $dst.D,$src.D,$tmp.D\t! logical right shift packed2I" + %} + ins_encode %{ + bool quad = false; + __ vnegI($tmp$$FloatRegister, $shift$$FloatRegister, + MacroAssembler::VELEM_SIZE_8, quad); + __ vshlUI($dst$$FloatRegister, $tmp$$FloatRegister, $src$$FloatRegister, + MacroAssembler::VELEM_SIZE_32, quad); + %} + ins_pipe(ialu_reg_reg); +%} + +instruct vsrl4I_reg(vecX dst, vecX src, vecX shift) %{ + predicate(n->as_Vector()->length() == 4 && + VM_Version::has_simd() && + !n->as_ShiftV()->is_var_shift()); + match(Set dst (URShiftVI src shift)); + size(4); + ins_cost(DEFAULT_COST); + expand %{ + vsh4I_reg(dst, src, shift); + %} +%} + +instruct vsrl4I_reg_var(vecX dst, vecX src, vecX shift, vecX tmp) %{ + predicate(n->as_Vector()->length() == 4 && + VM_Version::has_simd() && + n->as_ShiftV()->is_var_shift()); + match(Set dst (URShiftVI src shift)); + effect(TEMP tmp); + size(4*2); + ins_cost(DEFAULT_COST*2); + format %{ + "VNEG.S8 $tmp.Q,$shift.Q\n\t! neg packed16B" + "VSHL.U32 $dst.Q,$src.Q,$tmp.Q\t! logical right shift packed4I" + %} + ins_encode %{ + bool quad = true; + __ vnegI($tmp$$FloatRegister, $shift$$FloatRegister, + MacroAssembler::VELEM_SIZE_8, quad); + __ vshlUI($dst$$FloatRegister, $tmp$$FloatRegister, $src$$FloatRegister, + MacroAssembler::VELEM_SIZE_32, quad); + %} + ins_pipe(ialu_reg_reg); +%} + instruct vsrl2I_immI(vecD dst, vecD src, immI shift) %{ - predicate(n->as_Vector()->length() == 2 && VM_Version::has_simd()); + predicate(n->as_Vector()->length() == 2 && + VM_Version::has_simd() && + assert_not_var_shift(n)); match(Set dst (URShiftVI src (RShiftCntV shift))); size(4); ins_cost(DEFAULT_COST); // FIXME @@ -10776,7 +11166,9 @@ instruct vsrl2I_immI(vecD dst, vecD src, immI shift) %{ %} instruct vsrl4I_immI(vecX dst, vecX src, immI shift) %{ - predicate(n->as_Vector()->length() == 4 && VM_Version::has_simd()); + predicate(n->as_Vector()->length() == 4 && + VM_Version::has_simd() && + assert_not_var_shift(n)); match(Set dst (URShiftVI src (RShiftCntV shift))); size(4); ins_cost(DEFAULT_COST); // FIXME @@ -10792,8 +11184,38 @@ instruct vsrl4I_immI(vecX dst, vecX src, immI shift) %{ %} // Longs vector logical right shift +instruct vsrl2L_reg(vecX dst, vecX src, vecX shift) %{ + predicate(n->as_Vector()->length() == 2 && !n->as_ShiftV()->is_var_shift()); + match(Set dst (URShiftVL src shift)); + size(4); + ins_cost(DEFAULT_COST); + expand %{ + vsh2L_reg(dst, src, shift); + %} +%} + +instruct vsrl2L_reg_var(vecX dst, vecX src, vecX shift, vecX tmp) %{ + predicate(n->as_Vector()->length() == 2 && n->as_ShiftV()->is_var_shift()); + match(Set dst (URShiftVL src shift)); + effect(TEMP tmp, DEF dst, USE src, USE shift); + size(4*2); + ins_cost(DEFAULT_COST*2); + format %{ + "VNEG.S8 $tmp.Q,$shift.Q\n\t! neg packed16B" + "VSHL.U64 $dst.Q,$src.Q,$tmp.Q\t! logical right shift packed2L" + %} + ins_encode %{ + bool quad = true; + __ vnegI($tmp$$FloatRegister, $shift$$FloatRegister, + MacroAssembler::VELEM_SIZE_8, quad); + __ vshlUI($dst$$FloatRegister, $tmp$$FloatRegister, $src$$FloatRegister, + MacroAssembler::VELEM_SIZE_64, quad); + %} + ins_pipe(ialu_reg_reg); +%} + instruct vsrl2L_immI(vecX dst, vecX src, immI shift) %{ - predicate(n->as_Vector()->length() == 2); + predicate(n->as_Vector()->length() == 2 && assert_not_var_shift(n)); match(Set dst (URShiftVL src (RShiftCntV shift))); size(4); ins_cost(DEFAULT_COST); // FIXME @@ -10927,9 +11349,8 @@ instruct vsha2L_reg(vecX dst, vecX src, vecX shift) %{ %} // Byte vector arithmetic right shift - instruct vsra8B_reg(vecD dst, vecD src, vecD shift) %{ - predicate(n->as_Vector()->length() == 8); + predicate(n->as_Vector()->length() == 8 && !n->as_ShiftV()->is_var_shift()); match(Set dst (RShiftVB src shift)); size(4); ins_cost(DEFAULT_COST); // FIXME @@ -10938,8 +11359,28 @@ instruct vsra8B_reg(vecD dst, vecD src, vecD shift) %{ %} %} -instruct vsrl16B_reg(vecX dst, vecX src, vecX shift) %{ - predicate(n->as_Vector()->length() == 16); +instruct vsra8B_reg_var(vecD dst, vecD src, vecD shift, vecD tmp) %{ + predicate(n->as_Vector()->length() == 8 && n->as_ShiftV()->is_var_shift()); + match(Set dst (RShiftVB src shift)); + effect(TEMP tmp); + size(4*2); + ins_cost(DEFAULT_COST*2); + format %{ + "VNEG.S8 $tmp.D,$shift.D\n\t! neg packed8B" + "VSHL.S8 $dst.D,$src.D,$tmp.D\t! arithmetic right shift packed8B" + %} + ins_encode %{ + bool quad = false; + __ vnegI($tmp$$FloatRegister, $shift$$FloatRegister, + MacroAssembler::VELEM_SIZE_8, quad); + __ vshlSI($dst$$FloatRegister, $tmp$$FloatRegister, $src$$FloatRegister, + MacroAssembler::VELEM_SIZE_8, quad); + %} + ins_pipe(ialu_reg_reg); +%} + +instruct vsra16B_reg(vecX dst, vecX src, vecX shift) %{ + predicate(n->as_Vector()->length() == 16 && !n->as_ShiftV()->is_var_shift()); match(Set dst (RShiftVB src shift)); size(4); ins_cost(DEFAULT_COST); // FIXME @@ -10948,13 +11389,33 @@ instruct vsrl16B_reg(vecX dst, vecX src, vecX shift) %{ %} %} -instruct vsrl8B_immI(vecD dst, vecD src, immI shift) %{ - predicate(n->as_Vector()->length() == 8); +instruct vsra16B_reg_var(vecX dst, vecX src, vecX shift, vecX tmp) %{ + predicate(n->as_Vector()->length() == 16 && n->as_ShiftV()->is_var_shift()); match(Set dst (RShiftVB src shift)); + effect(TEMP tmp); + size(4*2); + ins_cost(DEFAULT_COST*2); + format %{ + "VNEG.S8 $tmp.Q,$shift.Q\n\t! neg packed16B" + "VSHL.S8 $dst.Q,$src.Q,$tmp.Q\t! arithmetic right shift packed16B" + %} + ins_encode %{ + bool quad = true; + __ vnegI($tmp$$FloatRegister, $shift$$FloatRegister, + MacroAssembler::VELEM_SIZE_8, quad); + __ vshlSI($dst$$FloatRegister, $tmp$$FloatRegister, $src$$FloatRegister, + MacroAssembler::VELEM_SIZE_8, quad); + %} + ins_pipe(ialu_reg_reg); +%} + +instruct vsra8B_immI(vecD dst, vecD src, immI shift) %{ + predicate(n->as_Vector()->length() == 8 && assert_not_var_shift(n)); + match(Set dst (RShiftVB src (RShiftCntV shift))); size(4); ins_cost(DEFAULT_COST); // FIXME format %{ - "VSHR.S8 $dst.D,$src.D,$shift\t! logical right shift packed8B" + "VSHR.S8 $dst.D,$src.D,$shift\t! arithmetic right shift packed8B" %} ins_encode %{ bool quad = false; @@ -10964,13 +11425,13 @@ instruct vsrl8B_immI(vecD dst, vecD src, immI shift) %{ ins_pipe( ialu_reg_reg ); // FIXME %} -instruct vsrl16B_immI(vecX dst, vecX src, immI shift) %{ - predicate(n->as_Vector()->length() == 16); - match(Set dst (RShiftVB src shift)); +instruct vsra16B_immI(vecX dst, vecX src, immI shift) %{ + predicate(n->as_Vector()->length() == 16 && assert_not_var_shift(n)); + match(Set dst (RShiftVB src (RShiftCntV shift))); size(4); ins_cost(DEFAULT_COST); // FIXME format %{ - "VSHR.S8 $dst.Q,$src.Q,$shift\t! logical right shift packed16B" + "VSHR.S8 $dst.Q,$src.Q,$shift\t! arithmetic right shift packed16B" %} ins_encode %{ bool quad = true; @@ -10982,7 +11443,7 @@ instruct vsrl16B_immI(vecX dst, vecX src, immI shift) %{ // Shorts vector arithmetic right shift instruct vsra4S_reg(vecD dst, vecD src, vecD shift) %{ - predicate(n->as_Vector()->length() == 4); + predicate(n->as_Vector()->length() == 4 && !n->as_ShiftV()->is_var_shift()); match(Set dst (RShiftVS src shift)); size(4); ins_cost(DEFAULT_COST); // FIXME @@ -10991,8 +11452,28 @@ instruct vsra4S_reg(vecD dst, vecD src, vecD shift) %{ %} %} +instruct vsra4S_reg_var(vecD dst, vecD src, vecD shift, vecD tmp) %{ + predicate(n->as_Vector()->length() == 4 && n->as_ShiftV()->is_var_shift()); + match(Set dst (RShiftVS src shift)); + effect(TEMP tmp); + size(4*2); + ins_cost(DEFAULT_COST*2); + format %{ + "VNEG.S8 $tmp.D,$shift.D\n\t! neg packed8B" + "VSHL.S16 $dst.D,$src.D,$tmp.D\t! arithmetic right shift packed4S" + %} + ins_encode %{ + bool quad = false; + __ vnegI($tmp$$FloatRegister, $shift$$FloatRegister, + MacroAssembler::VELEM_SIZE_8, quad); + __ vshlSI($dst$$FloatRegister, $tmp$$FloatRegister, $src$$FloatRegister, + MacroAssembler::VELEM_SIZE_16, quad); + %} + ins_pipe(ialu_reg_reg); +%} + instruct vsra8S_reg(vecX dst, vecX src, vecX shift) %{ - predicate(n->as_Vector()->length() == 8); + predicate(n->as_Vector()->length() == 8 && !n->as_ShiftV()->is_var_shift()); match(Set dst (RShiftVS src shift)); size(4); ins_cost(DEFAULT_COST); // FIXME @@ -11001,13 +11482,33 @@ instruct vsra8S_reg(vecX dst, vecX src, vecX shift) %{ %} %} -instruct vsra4S_immI(vecD dst, vecD src, immI shift) %{ - predicate(n->as_Vector()->length() == 4); +instruct vsra8S_reg_var(vecX dst, vecX src, vecX shift, vecX tmp) %{ + predicate(n->as_Vector()->length() == 8 && n->as_ShiftV()->is_var_shift()); match(Set dst (RShiftVS src shift)); + effect(TEMP tmp); + size(4*2); + ins_cost(DEFAULT_COST*2); + format %{ + "VNEG.S8 $tmp.Q,$shift.Q\n\t! neg packed16B" + "VSHL.S16 $dst.Q,$src.Q,$tmp.Q\t! arithmetic right shift packed8S" + %} + ins_encode %{ + bool quad = true; + __ vnegI($tmp$$FloatRegister, $shift$$FloatRegister, + MacroAssembler::VELEM_SIZE_8, quad); + __ vshlSI($dst$$FloatRegister, $tmp$$FloatRegister, $src$$FloatRegister, + MacroAssembler::VELEM_SIZE_16, quad); + %} + ins_pipe(ialu_reg_reg); +%} + +instruct vsra4S_immI(vecD dst, vecD src, immI shift) %{ + predicate(n->as_Vector()->length() == 4 && assert_not_var_shift(n)); + match(Set dst (RShiftVS src (RShiftCntV shift))); size(4); ins_cost(DEFAULT_COST); // FIXME format %{ - "VSHR.S16 $dst.D,$src.D,$shift\t! logical right shift packed4S" + "VSHR.S16 $dst.D,$src.D,$shift\t! arithmetic right shift packed4S" %} ins_encode %{ bool quad = false; @@ -11018,12 +11519,12 @@ instruct vsra4S_immI(vecD dst, vecD src, immI shift) %{ %} instruct vsra8S_immI(vecX dst, vecX src, immI shift) %{ - predicate(n->as_Vector()->length() == 8); - match(Set dst (RShiftVS src shift)); + predicate(n->as_Vector()->length() == 8 && assert_not_var_shift(n)); + match(Set dst (RShiftVS src (RShiftCntV shift))); size(4); ins_cost(DEFAULT_COST); // FIXME format %{ - "VSHR.S16 $dst.Q,$src.Q,$shift\t! logical right shift packed8S" + "VSHR.S16 $dst.Q,$src.Q,$shift\t! arithmetic right shift packed8S" %} ins_encode %{ bool quad = true; @@ -11035,7 +11536,7 @@ instruct vsra8S_immI(vecX dst, vecX src, immI shift) %{ // Integers vector arithmetic right shift instruct vsra2I_reg(vecD dst, vecD src, vecD shift) %{ - predicate(n->as_Vector()->length() == 2); + predicate(n->as_Vector()->length() == 2 && !n->as_ShiftV()->is_var_shift()); match(Set dst (RShiftVI src shift)); size(4); ins_cost(DEFAULT_COST); // FIXME @@ -11044,8 +11545,28 @@ instruct vsra2I_reg(vecD dst, vecD src, vecD shift) %{ %} %} +instruct vsra2I_reg_var(vecD dst, vecD src, vecD shift, vecD tmp) %{ + predicate(n->as_Vector()->length() == 2 && n->as_ShiftV()->is_var_shift()); + match(Set dst (RShiftVI src shift)); + effect(TEMP tmp); + size(4*2); + ins_cost(DEFAULT_COST*2); + format %{ + "VNEG.S8 $tmp.D,$shift.D\n\t! neg packed8B" + "VSHL.S32 $dst.D,$src.D,$tmp.D\t! arithmetic right shift packed2I" + %} + ins_encode %{ + bool quad = false; + __ vnegI($tmp$$FloatRegister, $shift$$FloatRegister, + MacroAssembler::VELEM_SIZE_8, quad); + __ vshlSI($dst$$FloatRegister, $tmp$$FloatRegister, $src$$FloatRegister, + MacroAssembler::VELEM_SIZE_32, quad); + %} + ins_pipe(ialu_reg_reg); +%} + instruct vsra4I_reg(vecX dst, vecX src, vecX shift) %{ - predicate(n->as_Vector()->length() == 4); + predicate(n->as_Vector()->length() == 4 && !n->as_ShiftV()->is_var_shift()); match(Set dst (RShiftVI src shift)); size(4); ins_cost(DEFAULT_COST); // FIXME @@ -11054,13 +11575,33 @@ instruct vsra4I_reg(vecX dst, vecX src, vecX shift) %{ %} %} -instruct vsra2I_immI(vecD dst, vecD src, immI shift) %{ - predicate(n->as_Vector()->length() == 2); +instruct vsra4I_reg_var(vecX dst, vecX src, vecX shift, vecX tmp) %{ + predicate(n->as_Vector()->length() == 4 && n->as_ShiftV()->is_var_shift()); match(Set dst (RShiftVI src shift)); + effect(TEMP tmp); + size(4*2); + ins_cost(DEFAULT_COST*2); + format %{ + "VNEG.S8 $tmp.Q,$shift.Q\n\t! neg packed16B" + "VSHL.S32 $dst.Q,$src.Q,$tmp.Q\t! arithmetic right shift packed4I" + %} + ins_encode %{ + bool quad = true; + __ vnegI($tmp$$FloatRegister, $shift$$FloatRegister, + MacroAssembler::VELEM_SIZE_8, quad); + __ vshlSI($dst$$FloatRegister, $tmp$$FloatRegister, $src$$FloatRegister, + MacroAssembler::VELEM_SIZE_32, quad); + %} + ins_pipe(ialu_reg_reg); +%} + +instruct vsra2I_immI(vecD dst, vecD src, immI shift) %{ + predicate(n->as_Vector()->length() == 2 && assert_not_var_shift(n)); + match(Set dst (RShiftVI src (RShiftCntV shift))); size(4); ins_cost(DEFAULT_COST); // FIXME format %{ - "VSHR.S32 $dst.D,$src.D,$shift\t! logical right shift packed2I" + "VSHR.S32 $dst.D,$src.D,$shift\t! arithmetic right shift packed2I" %} ins_encode %{ bool quad = false; @@ -11071,12 +11612,12 @@ instruct vsra2I_immI(vecD dst, vecD src, immI shift) %{ %} instruct vsra4I_immI(vecX dst, vecX src, immI shift) %{ - predicate(n->as_Vector()->length() == 4); - match(Set dst (RShiftVI src shift)); + predicate(n->as_Vector()->length() == 4 && assert_not_var_shift(n)); + match(Set dst (RShiftVI src (RShiftCntV shift))); size(4); ins_cost(DEFAULT_COST); // FIXME format %{ - "VSHR.S32 $dst.Q,$src.Q,$shift\t! logical right shift packed4I" + "VSHR.S32 $dst.Q,$src.Q,$shift\t! arithmetic right shift packed4I" %} ins_encode %{ bool quad = true; @@ -11088,7 +11629,7 @@ instruct vsra4I_immI(vecX dst, vecX src, immI shift) %{ // Longs vector arithmetic right shift instruct vsra2L_reg(vecX dst, vecX src, vecX shift) %{ - predicate(n->as_Vector()->length() == 2); + predicate(n->as_Vector()->length() == 2 && !n->as_ShiftV()->is_var_shift()); match(Set dst (RShiftVL src shift)); size(4); ins_cost(DEFAULT_COST); // FIXME @@ -11097,13 +11638,33 @@ instruct vsra2L_reg(vecX dst, vecX src, vecX shift) %{ %} %} -instruct vsra2L_immI(vecX dst, vecX src, immI shift) %{ - predicate(n->as_Vector()->length() == 2); +instruct vsra2L_reg_var(vecX dst, vecX src, vecX shift, vecX tmp) %{ + predicate(n->as_Vector()->length() == 2 && n->as_ShiftV()->is_var_shift()); match(Set dst (RShiftVL src shift)); + effect(TEMP tmp); + size(4*2); + ins_cost(DEFAULT_COST*2); + format %{ + "VNEG.S8 $tmp.Q,$shift.Q\n\t! neg packed16B" + "VSHL.S64 $dst.Q,$src.Q,$tmp.Q\t! arithmetic right shift packed2L" + %} + ins_encode %{ + bool quad = true; + __ vnegI($tmp$$FloatRegister, $shift$$FloatRegister, + MacroAssembler::VELEM_SIZE_8, quad); + __ vshlSI($dst$$FloatRegister, $tmp$$FloatRegister, $src$$FloatRegister, + MacroAssembler::VELEM_SIZE_64, quad); + %} + ins_pipe(ialu_reg_reg); +%} + +instruct vsra2L_immI(vecX dst, vecX src, immI shift) %{ + predicate(n->as_Vector()->length() == 2 && assert_not_var_shift(n)); + match(Set dst (RShiftVL src (RShiftCntV shift))); size(4); ins_cost(DEFAULT_COST); // FIXME format %{ - "VSHR.S64 $dst.Q,$src.Q,$shift\t! logical right shift packed2L" + "VSHR.S64 $dst.Q,$src.Q,$shift\t! arithmetic right shift packed2L" %} ins_encode %{ bool quad = true; diff --git a/src/hotspot/cpu/arm/assembler_arm_32.cpp b/src/hotspot/cpu/arm/assembler_arm_32.cpp index 5dd9d39392a0e7d595e779c65af863d8eec0a3bf..6cb6e19cbd5b88d3ee9430496dcbded16ae06969 100644 --- a/src/hotspot/cpu/arm/assembler_arm_32.cpp +++ b/src/hotspot/cpu/arm/assembler_arm_32.cpp @@ -46,7 +46,7 @@ // Convert the raw encoding form into the form expected by the // constructor for Address. Address Address::make_raw(int base, int index, int scale, int disp, relocInfo::relocType disp_reloc) { - RelocationHolder rspec; + RelocationHolder rspec = RelocationHolder::none; if (disp_reloc != relocInfo::none) { rspec = Relocation::spec_simple(disp_reloc); } diff --git a/src/hotspot/cpu/arm/bytes_arm.hpp b/src/hotspot/cpu/arm/bytes_arm.hpp index b0d481f314d13ca05e1495c35bd8cecd53dc79fb..34af43edcac0b4656e277b00cf17bca360b29fb6 100644 --- a/src/hotspot/cpu/arm/bytes_arm.hpp +++ b/src/hotspot/cpu/arm/bytes_arm.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 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 @@ -25,7 +25,7 @@ #ifndef CPU_ARM_BYTES_ARM_HPP #define CPU_ARM_BYTES_ARM_HPP -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" #include "utilities/macros.hpp" #ifndef VM_LITTLE_ENDIAN diff --git a/src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp b/src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp index 2ee7b68f72037323500dfa5883b02dd9e6e361c6..f7ffe84618d1c59c6646a753047f27c29740392c 100644 --- a/src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp +++ b/src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp @@ -720,11 +720,7 @@ void LIR_Assembler::mem2reg(LIR_Opr src, LIR_Opr dest, BasicType type, break; case T_ADDRESS: - if (UseCompressedClassPointers && addr->disp() == oopDesc::klass_offset_in_bytes()) { - __ ldr_u32(dest->as_pointer_register(), as_Address(addr)); - } else { - __ ldr(dest->as_pointer_register(), as_Address(addr)); - } + __ ldr(dest->as_pointer_register(), as_Address(addr)); break; case T_INT: @@ -1381,7 +1377,7 @@ void LIR_Assembler::emit_compare_and_swap(LIR_OpCompareAndSwap* op) { op->addr()->as_pointer_register() : op->addr()->as_address_ptr()->base()->as_pointer_register(); assert(op->addr()->is_register() || op->addr()->as_address_ptr()->disp() == 0, "unexpected disp"); - assert(op->addr()->is_register() || op->addr()->as_address_ptr()->index() == LIR_OprDesc::illegalOpr(), "unexpected index"); + assert(op->addr()->is_register() || op->addr()->as_address_ptr()->index() == LIR_Opr::illegalOpr(), "unexpected index"); if (op->code() == lir_cas_int || op->code() == lir_cas_obj) { Register cmpval = op->cmp_value()->as_register(); Register newval = op->new_value()->as_register(); @@ -1684,6 +1680,9 @@ void LIR_Assembler::logic_op(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Opr } else { assert(right->is_constant(), "must be"); const uint c = (uint)right->as_constant_ptr()->as_jint(); + if (!Assembler::is_arith_imm_in_range(c)) { + BAILOUT("illegal arithmetic operand"); + } switch (code) { case lir_logic_and: __ and_32(res, lreg, c); break; case lir_logic_or: __ orr_32(res, lreg, c); break; @@ -1824,8 +1823,8 @@ void LIR_Assembler::comp_op(LIR_Condition condition, LIR_Opr opr1, LIR_Opr opr2, __ teq(xhi, yhi); __ teq(xlo, ylo, eq); } else { - __ subs(xlo, xlo, ylo); - __ sbcs(xhi, xhi, yhi); + __ subs(Rtemp, xlo, ylo); + __ sbcs(Rtemp, xhi, yhi); } } else { ShouldNotReachHere(); @@ -2429,7 +2428,7 @@ void LIR_Assembler::emit_lock(LIR_OpLock* op) { Register hdr = op->hdr_opr()->as_pointer_register(); Register lock = op->lock_opr()->as_pointer_register(); - if (!UseFastLocking) { + if (UseHeavyMonitors) { __ b(*op->stub()->entry()); } else if (op->code() == lir_lock) { assert(BasicLock::displaced_header_offset_in_bytes() == 0, "lock_reg must point to the displaced header"); @@ -2445,6 +2444,21 @@ void LIR_Assembler::emit_lock(LIR_OpLock* op) { __ bind(*op->stub()->continuation()); } +void LIR_Assembler::emit_load_klass(LIR_OpLoadKlass* op) { + Register obj = op->obj()->as_pointer_register(); + Register result = op->result_opr()->as_pointer_register(); + + CodeEmitInfo* info = op->info(); + if (info != NULL) { + add_debug_info_for_null_check_here(info); + } + + if (UseCompressedClassPointers) { // On 32 bit arm?? + __ ldr_u32(result, Address(obj, oopDesc::klass_offset_in_bytes())); + } else { + __ ldr(result, Address(obj, oopDesc::klass_offset_in_bytes())); + } +} void LIR_Assembler::emit_profile_call(LIR_OpProfileCall* op) { ciMethod* method = op->profiled_method(); diff --git a/src/hotspot/cpu/arm/c1_LIRGenerator_arm.cpp b/src/hotspot/cpu/arm/c1_LIRGenerator_arm.cpp index 0a5b80b23b7659ac35ad4c2cd2fbed4335379503..69a76f4beb0d32882437d4a6227b66840e0fa227 100644 --- a/src/hotspot/cpu/arm/c1_LIRGenerator_arm.cpp +++ b/src/hotspot/cpu/arm/c1_LIRGenerator_arm.cpp @@ -377,7 +377,7 @@ void LIRGenerator::CardTableBarrierSet_post_barrier_helper(LIR_Opr addr, LIR_Con // Use unsigned type T_BOOLEAN here rather than (signed) T_BYTE since signed load // byte instruction does not support the addressing mode we need. - LIR_Address* card_addr = new LIR_Address(tmp, addr, (LIR_Address::Scale) -CardTable::card_shift, 0, T_BOOLEAN); + LIR_Address* card_addr = new LIR_Address(tmp, addr, (LIR_Address::Scale) -CardTable::card_shift(), 0, T_BOOLEAN); if (UseCondCardMark) { LIR_Opr cur_value = new_register(T_INT); __ move(card_addr, cur_value); diff --git a/src/hotspot/cpu/arm/c1_LIR_arm.cpp b/src/hotspot/cpu/arm/c1_LIR_arm.cpp index 60bd5265bfb3339d6d581f01dd98eb107117e309..9d70fd12f3558e3a0bcae40ecbfb923a39dbe986 100644 --- a/src/hotspot/cpu/arm/c1_LIR_arm.cpp +++ b/src/hotspot/cpu/arm/c1_LIR_arm.cpp @@ -25,21 +25,21 @@ #include "precompiled.hpp" #include "c1/c1_LIR.hpp" -FloatRegister LIR_OprDesc::as_float_reg() const { +FloatRegister LIR_Opr::as_float_reg() const { return as_FloatRegister(fpu_regnr()); } -FloatRegister LIR_OprDesc::as_double_reg() const { +FloatRegister LIR_Opr::as_double_reg() const { return as_FloatRegister(fpu_regnrLo()); } LIR_Opr LIR_OprFact::double_fpu(int reg1, int reg2) { assert(as_FloatRegister(reg2) != fnoreg, "Arm32 holds double in two regs."); - return (LIR_Opr)(intptr_t)((reg1 << LIR_OprDesc::reg1_shift) | - (reg2 << LIR_OprDesc::reg2_shift) | - LIR_OprDesc::double_type | - LIR_OprDesc::fpu_register | - LIR_OprDesc::double_size); + return (LIR_Opr)(intptr_t)((reg1 << LIR_Opr::reg1_shift) | + (reg2 << LIR_Opr::reg2_shift) | + LIR_Opr::double_type | + LIR_Opr::fpu_register | + LIR_Opr::double_size); } #ifndef PRODUCT diff --git a/src/hotspot/cpu/arm/c1_MacroAssembler_arm.cpp b/src/hotspot/cpu/arm/c1_MacroAssembler_arm.cpp index 7f1d4341872c2dc36af92b4f011a9d6c64cf73a8..1bf3ce5c23d6494bd01581cfc892567626d041bd 100644 --- a/src/hotspot/cpu/arm/c1_MacroAssembler_arm.cpp +++ b/src/hotspot/cpu/arm/c1_MacroAssembler_arm.cpp @@ -69,8 +69,8 @@ void C1_MacroAssembler::remove_frame(int frame_size_in_bytes) { raw_pop(FP, LR); } -void C1_MacroAssembler::verified_entry() { - if (C1Breakpoint) { +void C1_MacroAssembler::verified_entry(bool breakAtEntry) { + if (breakAtEntry) { breakpoint(); } } diff --git a/src/hotspot/cpu/arm/frame_arm.inline.hpp b/src/hotspot/cpu/arm/frame_arm.inline.hpp index 835edd68493e66e82345eb848d304c0202e27b79..773b6d06f7b4c426052eb7b2d357730c78bc3f20 100644 --- a/src/hotspot/cpu/arm/frame_arm.inline.hpp +++ b/src/hotspot/cpu/arm/frame_arm.inline.hpp @@ -124,9 +124,13 @@ inline intptr_t* frame::id(void) const { return unextended_sp(); } inline bool frame::is_older(intptr_t* id) const { assert(this->id() != NULL && id != NULL, "NULL frame id"); return this->id() > id ; } - inline intptr_t* frame::link() const { return (intptr_t*) *(intptr_t **)addr_at(link_offset); } +inline intptr_t* frame::link_or_null() const { + intptr_t** ptr = (intptr_t **)addr_at(link_offset); + return os::is_readable_pointer(ptr) ? *ptr : NULL; +} + inline intptr_t* frame::unextended_sp() const { return _unextended_sp; } // Return address: diff --git a/src/hotspot/cpu/arm/gc/g1/g1BarrierSetAssembler_arm.cpp b/src/hotspot/cpu/arm/gc/g1/g1BarrierSetAssembler_arm.cpp index 63bf45b8db5d38e4e84f0028c4dcce73108032f9..765b05e779b9e5e2164b297884ace283f6a12c90 100644 --- a/src/hotspot/cpu/arm/gc/g1/g1BarrierSetAssembler_arm.cpp +++ b/src/hotspot/cpu/arm/gc/g1/g1BarrierSetAssembler_arm.cpp @@ -218,7 +218,7 @@ void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm, const Register card_addr = tmp1; __ mov_address(tmp2, (address)ct->byte_map_base()); - __ add(card_addr, tmp2, AsmOperand(store_addr, lsr, CardTable::card_shift)); + __ add(card_addr, tmp2, AsmOperand(store_addr, lsr, CardTable::card_shift())); __ ldrb(tmp2, Address(card_addr)); __ cmp(tmp2, (int)G1CardTable::g1_young_card_val()); @@ -452,7 +452,7 @@ void G1BarrierSetAssembler::generate_c1_post_barrier_runtime_stub(StubAssembler* // explicitly specify that 'cardtable' has a relocInfo::none // type. __ lea(r_card_base_1, cardtable); - __ add(r_card_addr_0, r_card_base_1, AsmOperand(r_obj_0, lsr, CardTable::card_shift)); + __ add(r_card_addr_0, r_card_base_1, AsmOperand(r_obj_0, lsr, CardTable::card_shift())); // first quick check without barrier __ ldrb(r_tmp2, Address(r_card_addr_0)); diff --git a/src/hotspot/cpu/arm/gc/shared/cardTableBarrierSetAssembler_arm.cpp b/src/hotspot/cpu/arm/gc/shared/cardTableBarrierSetAssembler_arm.cpp index 86f43597e220bb1b7f302dc59422cf0320e36de1..11b2ca2ef1d8c4a7dbbac6396c0903d3ac2d131c 100644 --- a/src/hotspot/cpu/arm/gc/shared/cardTableBarrierSetAssembler_arm.cpp +++ b/src/hotspot/cpu/arm/gc/shared/cardTableBarrierSetAssembler_arm.cpp @@ -55,8 +55,8 @@ void CardTableBarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembl __ add_ptr_scaled_int32(count, addr, count, LogBytesPerHeapOop); __ sub(count, count, BytesPerHeapOop); // last addr - __ logical_shift_right(addr, addr, CardTable::card_shift); - __ logical_shift_right(count, count, CardTable::card_shift); + __ logical_shift_right(addr, addr, CardTable::card_shift()); + __ logical_shift_right(count, count, CardTable::card_shift()); __ sub(count, count, addr); // nb of cards // warning: Rthread has not been preserved @@ -129,7 +129,7 @@ void CardTableBarrierSetAssembler::store_check_part2(MacroAssembler* masm, Regis "Wrong barrier set kind"); assert(CardTable::dirty_card_val() == 0, "Dirty card value must be 0 due to optimizations."); - Address card_table_addr(card_table_base, obj, lsr, CardTable::card_shift); + Address card_table_addr(card_table_base, obj, lsr, CardTable::card_shift()); if (UseCondCardMark) { Label already_dirty; diff --git a/src/hotspot/cpu/arm/jniTypes_arm.hpp b/src/hotspot/cpu/arm/jniTypes_arm.hpp index 66596eac1a0346b7135d56946e9458afe00e5145..660e58110f886fac0583f0cbef71e5d8085189ff 100644 --- a/src/hotspot/cpu/arm/jniTypes_arm.hpp +++ b/src/hotspot/cpu/arm/jniTypes_arm.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 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 @@ -26,7 +26,7 @@ #define CPU_ARM_JNITYPES_ARM_HPP #include "jni.h" -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" #include "oops/oop.hpp" // This file holds platform-dependent routines used to write primitive jni diff --git a/src/hotspot/cpu/arm/matcher_arm.hpp b/src/hotspot/cpu/arm/matcher_arm.hpp index 6254f4b33991d66069d47cf02aee04e1e7ed4e7d..496ea27c0861b0d1a8ae1ca2dbc712bc40e48467 100644 --- a/src/hotspot/cpu/arm/matcher_arm.hpp +++ b/src/hotspot/cpu/arm/matcher_arm.hpp @@ -56,9 +56,6 @@ // No support for generic vector operands. static const bool supports_generic_vector_operands = false; - // No support for 48 extra htbl entries in aes-gcm intrinsic - static const int htbl_entries = -1; - static constexpr bool isSimpleConstant64(jlong value) { // Will one (StoreL ConL) be cheaper than two (StoreI ConI)?. return false; @@ -158,4 +155,9 @@ // Implements a variant of EncodeISOArrayNode that encode ASCII only static const bool supports_encode_ascii_array = false; + // Returns pre-selection estimated cost of a vector operation. + static int vector_op_pre_select_sz_estimate(int vopc, BasicType ety, int vlen) { + return 0; + } + #endif // CPU_ARM_MATCHER_ARM_HPP diff --git a/src/hotspot/cpu/arm/register_definitions_arm.cpp b/src/hotspot/cpu/arm/register_definitions_arm.cpp deleted file mode 100644 index 4aa7714970cbb1e0ebe4ed38983c56cf4a7bff72..0000000000000000000000000000000000000000 --- a/src/hotspot/cpu/arm/register_definitions_arm.cpp +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright (c) 2008, 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 "asm/assembler.hpp" -#include "asm/register.hpp" -#include "interp_masm_arm.hpp" -#include "register_arm.hpp" - -REGISTER_DEFINITION(Register, noreg); -REGISTER_DEFINITION(FloatRegister, fnoreg); - - -REGISTER_DEFINITION(FloatRegister, S0); -REGISTER_DEFINITION(FloatRegister, S1_reg); -REGISTER_DEFINITION(FloatRegister, S2_reg); -REGISTER_DEFINITION(FloatRegister, S3_reg); -REGISTER_DEFINITION(FloatRegister, S4_reg); -REGISTER_DEFINITION(FloatRegister, S5_reg); -REGISTER_DEFINITION(FloatRegister, S6_reg); -REGISTER_DEFINITION(FloatRegister, S7); -REGISTER_DEFINITION(FloatRegister, S8); -REGISTER_DEFINITION(FloatRegister, S9); -REGISTER_DEFINITION(FloatRegister, S10); -REGISTER_DEFINITION(FloatRegister, S11); -REGISTER_DEFINITION(FloatRegister, S12); -REGISTER_DEFINITION(FloatRegister, S13); -REGISTER_DEFINITION(FloatRegister, S14); -REGISTER_DEFINITION(FloatRegister, S15); -REGISTER_DEFINITION(FloatRegister, S16); -REGISTER_DEFINITION(FloatRegister, S17); -REGISTER_DEFINITION(FloatRegister, S18); -REGISTER_DEFINITION(FloatRegister, S19); -REGISTER_DEFINITION(FloatRegister, S20); -REGISTER_DEFINITION(FloatRegister, S21); -REGISTER_DEFINITION(FloatRegister, S22); -REGISTER_DEFINITION(FloatRegister, S23); -REGISTER_DEFINITION(FloatRegister, S24); -REGISTER_DEFINITION(FloatRegister, S25); -REGISTER_DEFINITION(FloatRegister, S26); -REGISTER_DEFINITION(FloatRegister, S27); -REGISTER_DEFINITION(FloatRegister, S28); -REGISTER_DEFINITION(FloatRegister, S29); -REGISTER_DEFINITION(FloatRegister, S30); -REGISTER_DEFINITION(FloatRegister, S31); -REGISTER_DEFINITION(FloatRegister, Stemp); -REGISTER_DEFINITION(FloatRegister, D0); -REGISTER_DEFINITION(FloatRegister, D1); -REGISTER_DEFINITION(FloatRegister, D2); -REGISTER_DEFINITION(FloatRegister, D3); -REGISTER_DEFINITION(FloatRegister, D4); -REGISTER_DEFINITION(FloatRegister, D5); -REGISTER_DEFINITION(FloatRegister, D6); -REGISTER_DEFINITION(FloatRegister, D7); -REGISTER_DEFINITION(FloatRegister, D8); -REGISTER_DEFINITION(FloatRegister, D9); -REGISTER_DEFINITION(FloatRegister, D10); -REGISTER_DEFINITION(FloatRegister, D11); -REGISTER_DEFINITION(FloatRegister, D12); -REGISTER_DEFINITION(FloatRegister, D13); -REGISTER_DEFINITION(FloatRegister, D14); -REGISTER_DEFINITION(FloatRegister, D15); -REGISTER_DEFINITION(FloatRegister, D16); -REGISTER_DEFINITION(FloatRegister, D17); -REGISTER_DEFINITION(FloatRegister, D18); -REGISTER_DEFINITION(FloatRegister, D19); -REGISTER_DEFINITION(FloatRegister, D20); -REGISTER_DEFINITION(FloatRegister, D21); -REGISTER_DEFINITION(FloatRegister, D22); -REGISTER_DEFINITION(FloatRegister, D23); -REGISTER_DEFINITION(FloatRegister, D24); -REGISTER_DEFINITION(FloatRegister, D25); -REGISTER_DEFINITION(FloatRegister, D26); -REGISTER_DEFINITION(FloatRegister, D27); -REGISTER_DEFINITION(FloatRegister, D28); -REGISTER_DEFINITION(FloatRegister, D29); -REGISTER_DEFINITION(FloatRegister, D30); -REGISTER_DEFINITION(FloatRegister, D31); - diff --git a/src/hotspot/cpu/arm/vm_version_arm.hpp b/src/hotspot/cpu/arm/vm_version_arm.hpp index a6e2dc8b442198115b3f4ad62fa36aefa16c4053..bdc3df12eb9f4d0b7fc4166583ccab5639efac70 100644 --- a/src/hotspot/cpu/arm/vm_version_arm.hpp +++ b/src/hotspot/cpu/arm/vm_version_arm.hpp @@ -106,6 +106,7 @@ class VM_Version: public Abstract_VM_Version { friend class VM_Version_StubGenerator; + static void initialize_cpu_information(void); }; #endif // CPU_ARM_VM_VERSION_ARM_HPP diff --git a/src/hotspot/cpu/arm/vm_version_arm_32.cpp b/src/hotspot/cpu/arm/vm_version_arm_32.cpp index a31857d9a47227a228f9bd65e3e0e37fdee59d8a..9e228b3d75191f84870891dde5021cf0a0618ec7 100644 --- a/src/hotspot/cpu/arm/vm_version_arm_32.cpp +++ b/src/hotspot/cpu/arm/vm_version_arm_32.cpp @@ -347,3 +347,17 @@ void VM_Version::initialize() { _is_initialized = true; } + +void VM_Version::initialize_cpu_information(void) { + // do nothing if cpu info has been initialized + if (_initialized) { + return; + } + + _no_of_cores = os::processor_count(); + _no_of_threads = _no_of_cores; + _no_of_sockets = _no_of_cores; + snprintf(_cpu_name, CPU_TYPE_DESC_BUF_SIZE - 1, "ARM%d", _arm_arch); + snprintf(_cpu_desc, CPU_DETAILED_DESC_BUF_SIZE, "%s", _features_string); + _initialized = true; +} diff --git a/src/hotspot/cpu/arm/vm_version_ext_arm.cpp b/src/hotspot/cpu/arm/vm_version_ext_arm.cpp deleted file mode 100644 index 0e2a1ffa1369f9e13e66b0cfaa3811aeff6e0830..0000000000000000000000000000000000000000 --- a/src/hotspot/cpu/arm/vm_version_ext_arm.cpp +++ /dev/null @@ -1,90 +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. - * - */ - -#include "memory/allocation.hpp" -#include "memory/allocation.inline.hpp" -#include "runtime/os.inline.hpp" -#include "vm_version_ext_arm.hpp" - -// VM_Version_Ext statics -int VM_Version_Ext::_no_of_threads = 0; -int VM_Version_Ext::_no_of_cores = 0; -int VM_Version_Ext::_no_of_sockets = 0; -bool VM_Version_Ext::_initialized = false; -char VM_Version_Ext::_cpu_name[CPU_TYPE_DESC_BUF_SIZE] = {0}; -char VM_Version_Ext::_cpu_desc[CPU_DETAILED_DESC_BUF_SIZE] = {0}; - -void VM_Version_Ext::initialize_cpu_information(void) { - // do nothing if cpu info has been initialized - if (_initialized) { - return; - } - - int core_id = -1; - int chip_id = -1; - int len = 0; - char* src_string = NULL; - - _no_of_cores = os::processor_count(); - _no_of_threads = _no_of_cores; - _no_of_sockets = _no_of_cores; - snprintf(_cpu_name, CPU_TYPE_DESC_BUF_SIZE - 1, "ARM%d", _arm_arch); - snprintf(_cpu_desc, CPU_DETAILED_DESC_BUF_SIZE, "%s", _features_string); - _initialized = true; -} - -int VM_Version_Ext::number_of_threads(void) { - initialize_cpu_information(); - return _no_of_threads; -} - -int VM_Version_Ext::number_of_cores(void) { - initialize_cpu_information(); - return _no_of_cores; -} - -int VM_Version_Ext::number_of_sockets(void) { - initialize_cpu_information(); - return _no_of_sockets; -} - -const char* VM_Version_Ext::cpu_name(void) { - initialize_cpu_information(); - char* tmp = NEW_C_HEAP_ARRAY_RETURN_NULL(char, CPU_TYPE_DESC_BUF_SIZE, mtTracing); - if (NULL == tmp) { - return NULL; - } - strncpy(tmp, _cpu_name, CPU_TYPE_DESC_BUF_SIZE); - return tmp; -} - -const char* VM_Version_Ext::cpu_description(void) { - initialize_cpu_information(); - char* tmp = NEW_C_HEAP_ARRAY_RETURN_NULL(char, CPU_DETAILED_DESC_BUF_SIZE, mtTracing); - if (NULL == tmp) { - return NULL; - } - strncpy(tmp, _cpu_desc, CPU_DETAILED_DESC_BUF_SIZE); - return tmp; -} diff --git a/src/hotspot/cpu/arm/vm_version_ext_arm.hpp b/src/hotspot/cpu/arm/vm_version_ext_arm.hpp deleted file mode 100644 index 77fc4615e1b4450b02d42ebd0a6b80fd8c8d81f0..0000000000000000000000000000000000000000 --- a/src/hotspot/cpu/arm/vm_version_ext_arm.hpp +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2013, 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_ARM_VM_VERSION_EXT_ARM_HPP -#define CPU_ARM_VM_VERSION_EXT_ARM_HPP - -#include "runtime/vm_version.hpp" -#include "utilities/macros.hpp" - -class VM_Version_Ext : public VM_Version { - private: - static const size_t CPU_TYPE_DESC_BUF_SIZE = 256; - static const size_t CPU_DETAILED_DESC_BUF_SIZE = 4096; - - static int _no_of_threads; - static int _no_of_cores; - static int _no_of_sockets; - static bool _initialized; - static char _cpu_name[CPU_TYPE_DESC_BUF_SIZE]; - static char _cpu_desc[CPU_DETAILED_DESC_BUF_SIZE]; - - public: - static int number_of_threads(void); - static int number_of_cores(void); - static int number_of_sockets(void); - - static const char* cpu_name(void); - static const char* cpu_description(void); - static void initialize_cpu_information(void); - -}; - -#endif // CPU_ARM_VM_VERSION_EXT_ARM_HPP diff --git a/src/hotspot/cpu/ppc/bytes_ppc.hpp b/src/hotspot/cpu/ppc/bytes_ppc.hpp index 8249068ecd6f0d71e211faa956772ff30435da1a..a4d061e9b732fa8f2613a64d0e86853ff53e40a6 100644 --- a/src/hotspot/cpu/ppc/bytes_ppc.hpp +++ b/src/hotspot/cpu/ppc/bytes_ppc.hpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2016 SAP SE. All rights reserved. + * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -26,7 +26,7 @@ #ifndef CPU_PPC_BYTES_PPC_HPP #define CPU_PPC_BYTES_PPC_HPP -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" class Bytes: AllStatic { public: diff --git a/src/hotspot/cpu/ppc/c1_CodeStubs_ppc.cpp b/src/hotspot/cpu/ppc/c1_CodeStubs_ppc.cpp index 4f329d2e63333accbc0d53651f2bc3367e0f7310..109372bb1a4b155daebdfb5e64f03ecda14f3aaf 100644 --- a/src/hotspot/cpu/ppc/c1_CodeStubs_ppc.cpp +++ b/src/hotspot/cpu/ppc/c1_CodeStubs_ppc.cpp @@ -81,8 +81,6 @@ void RangeCheckStub::emit_code(LIR_Assembler* ce) { if (_info->deoptimize_on_exception()) { address a = Runtime1::entry_for(Runtime1::predicate_failed_trap_id); - // May be used by optimizations like LoopInvariantCodeMotion or RangeCheckEliminator. - DEBUG_ONLY( __ untested("RangeCheckStub: predicate_failed_trap_id"); ) //__ load_const_optimized(R0, a); __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(a)); __ mtctr(R0); diff --git a/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp b/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp index 831e2bdfe930df2de90bf2fdba5905dd9854780f..b04c49152f3fb81e72a721c61d6592549f208669 100644 --- a/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp @@ -812,12 +812,7 @@ int LIR_Assembler::load(Register base, int offset, LIR_Opr to_reg, BasicType typ case T_LONG : __ ld(to_reg->as_register_lo(), offset, base); break; case T_METADATA: __ ld(to_reg->as_register(), offset, base); break; case T_ADDRESS: - if (offset == oopDesc::klass_offset_in_bytes() && UseCompressedClassPointers) { - __ lwz(to_reg->as_register(), offset, base); - __ decode_klass_not_null(to_reg->as_register()); - } else { - __ ld(to_reg->as_register(), offset, base); - } + __ ld(to_reg->as_register(), offset, base); break; case T_ARRAY : // fall through case T_OBJECT: @@ -947,9 +942,10 @@ void LIR_Assembler::const2mem(LIR_Opr src, LIR_Opr dest, BasicType type, CodeEmi tmp = FrameMap::R0_opr; if (UseCompressedOops && !wide && c->as_jobject() != NULL) { AddressLiteral oop_addr = __ constant_oop_address(c->as_jobject()); - __ lis(R0, oop_addr.value() >> 16); // Don't care about sign extend (will use stw). + // Don't care about sign extend (will use stw). + __ lis(R0, 0); // Will get patched. __ relocate(oop_addr.rspec(), /*compressed format*/ 1); - __ ori(R0, R0, oop_addr.value() & 0xffff); + __ ori(R0, R0, 0); // Will get patched. } else { jobject2reg(c->as_jobject(), R0); } @@ -2694,7 +2690,7 @@ void LIR_Assembler::emit_lock(LIR_OpLock* op) { // Obj may not be an oop. if (op->code() == lir_lock) { MonitorEnterStub* stub = (MonitorEnterStub*)op->stub(); - if (UseFastLocking) { + if (!UseHeavyMonitors) { assert(BasicLock::displaced_header_offset_in_bytes() == 0, "lock_reg must point to the displaced header"); // Add debug info for NullPointerException only if one is possible. if (op->info() != NULL) { @@ -2716,7 +2712,7 @@ void LIR_Assembler::emit_lock(LIR_OpLock* op) { } } else { assert (op->code() == lir_unlock, "Invalid code, expected lir_unlock"); - if (UseFastLocking) { + if (!UseHeavyMonitors) { assert(BasicLock::displaced_header_offset_in_bytes() == 0, "lock_reg must point to the displaced header"); __ unlock_object(hdr, obj, lock, *op->stub()->entry()); } else { @@ -2732,6 +2728,26 @@ void LIR_Assembler::emit_lock(LIR_OpLock* op) { __ bind(*op->stub()->continuation()); } +void LIR_Assembler::emit_load_klass(LIR_OpLoadKlass* op) { + Register obj = op->obj()->as_pointer_register(); + Register result = op->result_opr()->as_pointer_register(); + + CodeEmitInfo* info = op->info(); + if (info != NULL) { + if (!os::zero_page_read_protected() || !ImplicitNullChecks) { + explicit_null_check(obj, info); + } else { + add_debug_info_for_null_check_here(info); + } + } + + if (UseCompressedClassPointers) { + __ lwz(result, oopDesc::klass_offset_in_bytes(), obj); + __ decode_klass_not_null(result); + } else { + __ ld(result, oopDesc::klass_offset_in_bytes(), obj); + } +} void LIR_Assembler::emit_profile_call(LIR_OpProfileCall* op) { ciMethod* method = op->profiled_method(); diff --git a/src/hotspot/cpu/ppc/c1_LIR_ppc.cpp b/src/hotspot/cpu/ppc/c1_LIR_ppc.cpp index fb234e8298502c3a60998f8051439077ac4fee9a..d031aaa1e40614f03f3d68d898c041b5e5a64684 100644 --- a/src/hotspot/cpu/ppc/c1_LIR_ppc.cpp +++ b/src/hotspot/cpu/ppc/c1_LIR_ppc.cpp @@ -27,22 +27,22 @@ #include "asm/register.hpp" #include "c1/c1_LIR.hpp" -FloatRegister LIR_OprDesc::as_float_reg() const { +FloatRegister LIR_Opr::as_float_reg() const { return as_FloatRegister(fpu_regnr()); } -FloatRegister LIR_OprDesc::as_double_reg() const { +FloatRegister LIR_Opr::as_double_reg() const { return as_FloatRegister(fpu_regnrLo()); } // Reg2 unused. LIR_Opr LIR_OprFact::double_fpu(int reg1, int reg2) { assert(!as_FloatRegister(reg2)->is_valid(), "Not used on this platform"); - return (LIR_Opr)(intptr_t)((reg1 << LIR_OprDesc::reg1_shift) | - (reg1 << LIR_OprDesc::reg2_shift) | - LIR_OprDesc::double_type | - LIR_OprDesc::fpu_register | - LIR_OprDesc::double_size); + return (LIR_Opr)(intptr_t)((reg1 << LIR_Opr::reg1_shift) | + (reg1 << LIR_Opr::reg2_shift) | + LIR_Opr::double_type | + LIR_Opr::fpu_register | + LIR_Opr::double_size); } #ifndef PRODUCT diff --git a/src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.cpp b/src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.cpp index 2e7fb125eb3b6640ddb7587c8654a5bdae14e22c..fba889385ba6a5ba712db642ec301c659f414561 100644 --- a/src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.cpp @@ -86,8 +86,8 @@ void C1_MacroAssembler::build_frame(int frame_size_in_bytes, int bang_size_in_by } -void C1_MacroAssembler::verified_entry() { - if (C1Breakpoint) illtrap(); +void C1_MacroAssembler::verified_entry(bool breakAtEntry) { + if (breakAtEntry) illtrap(); // build frame } diff --git a/src/hotspot/cpu/ppc/c2_MacroAssembler_ppc.cpp b/src/hotspot/cpu/ppc/c2_MacroAssembler_ppc.cpp index 69a29c02654e484e2d2fe9357f923c0b7f5bcd3c..30104094983b579eb68c5a959958fdd9ae0af5ba 100644 --- a/src/hotspot/cpu/ppc/c2_MacroAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/c2_MacroAssembler_ppc.cpp @@ -41,17 +41,18 @@ // Compress char[] to byte[] by compressing 16 bytes at once. void C2_MacroAssembler::string_compress_16(Register src, Register dst, Register cnt, Register tmp1, Register tmp2, Register tmp3, Register tmp4, Register tmp5, - Label& Lfailure) { + Label& Lfailure, bool ascii) { const Register tmp0 = R0; + const int byte_mask = ascii ? 0x7F : 0xFF; assert_different_registers(src, dst, cnt, tmp0, tmp1, tmp2, tmp3, tmp4, tmp5); Label Lloop, Lslow; // Check if cnt >= 8 (= 16 bytes) - lis(tmp1, 0xFF); // tmp1 = 0x00FF00FF00FF00FF + lis(tmp1, byte_mask); // tmp1 = 0x00FF00FF00FF00FF (non ascii case) srwi_(tmp2, cnt, 3); beq(CCR0, Lslow); - ori(tmp1, tmp1, 0xFF); + ori(tmp1, tmp1, byte_mask); rldimi(tmp1, tmp1, 32, 0); mtctr(tmp2); @@ -67,7 +68,7 @@ void C2_MacroAssembler::string_compress_16(Register src, Register dst, Register rldimi(tmp4, tmp4, 2*8, 2*8); // _4_6_7_7 andc_(tmp0, tmp0, tmp1); - bne(CCR0, Lfailure); // Not latin1. + bne(CCR0, Lfailure); // Not latin1/ascii. addi(src, src, 16); rlwimi(tmp3, tmp2, 0*8, 24, 31);// _____1_3 @@ -87,20 +88,49 @@ void C2_MacroAssembler::string_compress_16(Register src, Register dst, Register } // Compress char[] to byte[]. cnt must be positive int. -void C2_MacroAssembler::string_compress(Register src, Register dst, Register cnt, Register tmp, Label& Lfailure) { +void C2_MacroAssembler::string_compress(Register src, Register dst, Register cnt, Register tmp, + Label& Lfailure, bool ascii) { + const int byte_mask = ascii ? 0x7F : 0xFF; Label Lloop; mtctr(cnt); bind(Lloop); lhz(tmp, 0, src); - cmplwi(CCR0, tmp, 0xff); - bgt(CCR0, Lfailure); // Not latin1. + cmplwi(CCR0, tmp, byte_mask); + bgt(CCR0, Lfailure); // Not latin1/ascii. addi(src, src, 2); stb(tmp, 0, dst); addi(dst, dst, 1); bdnz(Lloop); } +void C2_MacroAssembler::encode_iso_array(Register src, Register dst, Register len, + Register tmp1, Register tmp2, Register tmp3, Register tmp4, Register tmp5, + Register result, bool ascii) { + Label Lslow, Lfailure1, Lfailure2, Ldone; + + string_compress_16(src, dst, len, tmp1, tmp2, tmp3, tmp4, tmp5, Lfailure1, ascii); + rldicl_(result, len, 0, 64-3); // Remaining characters. + beq(CCR0, Ldone); + bind(Lslow); + string_compress(src, dst, result, tmp2, Lfailure2, ascii); + li(result, 0); + b(Ldone); + + bind(Lfailure1); + mr(result, len); + mfctr(tmp1); + rldimi_(result, tmp1, 3, 0); // Remaining characters. + beq(CCR0, Ldone); + b(Lslow); + + bind(Lfailure2); + mfctr(result); // Remaining characters. + + bind(Ldone); + subf(result, result, len); +} + // Inflate byte[] to char[] by inflating 16 bytes at once. void C2_MacroAssembler::string_inflate_16(Register src, Register dst, Register cnt, Register tmp1, Register tmp2, Register tmp3, Register tmp4, Register tmp5) { @@ -535,16 +565,16 @@ void C2_MacroAssembler::string_indexof_char(Register result, Register haystack, } // string_indexof_char -void C2_MacroAssembler::has_negatives(Register src, Register cnt, Register result, - Register tmp1, Register tmp2) { +void C2_MacroAssembler::count_positives(Register src, Register cnt, Register result, + Register tmp1, Register tmp2) { const Register tmp0 = R0; assert_different_registers(src, result, cnt, tmp0, tmp1, tmp2); - Label Lfastloop, Lslow, Lloop, Lnoneg, Ldone; + Label Lfastloop, Lslow, Lloop, Ldone; // Check if cnt >= 8 (= 16 bytes) lis(tmp1, (int)(short)0x8080); // tmp1 = 0x8080808080808080 srwi_(tmp2, cnt, 4); - li(result, 1); // Assume there's a negative byte. + mr(result, src); // Use result reg to point to the current position. beq(CCR0, Lslow); ori(tmp1, tmp1, 0x8080); rldimi(tmp1, tmp1, 32, 0); @@ -552,30 +582,28 @@ void C2_MacroAssembler::has_negatives(Register src, Register cnt, Register resul // 2x unrolled loop bind(Lfastloop); - ld(tmp2, 0, src); - ld(tmp0, 8, src); + ld(tmp2, 0, result); + ld(tmp0, 8, result); orr(tmp0, tmp2, tmp0); and_(tmp0, tmp0, tmp1); - bne(CCR0, Ldone); // Found negative byte. - addi(src, src, 16); - + bne(CCR0, Lslow); // Found negative byte. + addi(result, result, 16); bdnz(Lfastloop); - bind(Lslow); // Fallback to slow version - rldicl_(tmp0, cnt, 0, 64-4); - beq(CCR0, Lnoneg); + bind(Lslow); // Fallback to slow version. + subf(tmp0, src, result); // Bytes known positive. + subf_(tmp0, tmp0, cnt); // Remaining Bytes. + beq(CCR0, Ldone); mtctr(tmp0); bind(Lloop); - lbz(tmp0, 0, src); - addi(src, src, 1); + lbz(tmp0, 0, result); andi_(tmp0, tmp0, 0x80); bne(CCR0, Ldone); // Found negative byte. + addi(result, result, 1); bdnz(Lloop); - bind(Lnoneg); - li(result, 0); bind(Ldone); + subf(result, src, result); // Result is offset from src. } - diff --git a/src/hotspot/cpu/ppc/c2_MacroAssembler_ppc.hpp b/src/hotspot/cpu/ppc/c2_MacroAssembler_ppc.hpp index 9f363f2b962170c6d3c43a84fe2851d036668696..ef4840b08a256c61d1add926f43eb255c9551e8c 100644 --- a/src/hotspot/cpu/ppc/c2_MacroAssembler_ppc.hpp +++ b/src/hotspot/cpu/ppc/c2_MacroAssembler_ppc.hpp @@ -32,10 +32,16 @@ // Compress char[] to byte[] by compressing 16 bytes at once. void string_compress_16(Register src, Register dst, Register cnt, Register tmp1, Register tmp2, Register tmp3, Register tmp4, Register tmp5, - Label& Lfailure); + Label& Lfailure, bool ascii = false); // Compress char[] to byte[]. cnt must be positive int. - void string_compress(Register src, Register dst, Register cnt, Register tmp, Label& Lfailure); + void string_compress(Register src, Register dst, Register cnt, Register tmp, + Label& Lfailure, bool ascii = false); + + // Encode UTF16 to ISO_8859_1 or ASCII. Return len on success or position of first mismatch. + void encode_iso_array(Register src, Register dst, Register len, + Register tmp1, Register tmp2, Register tmp3, Register tmp4, Register tmp5, + Register result, bool ascii); // Inflate byte[] to char[] by inflating 16 bytes at once. void string_inflate_16(Register src, Register dst, Register cnt, @@ -57,6 +63,6 @@ void string_indexof_char(Register result, Register haystack, Register haycnt, Register needle, jchar needleChar, Register tmp1, Register tmp2, bool is_byte); - void has_negatives(Register src, Register cnt, Register result, Register tmp1, Register tmp2); + void count_positives(Register src, Register cnt, Register result, Register tmp1, Register tmp2); #endif // CPU_PPC_C2_MACROASSEMBLER_PPC_HPP diff --git a/src/hotspot/cpu/ppc/copy_ppc.hpp b/src/hotspot/cpu/ppc/copy_ppc.hpp index 06eae3c3f098054ecfae68a12ef6b1944aa21f13..0ae84b4e5959553042defa0ab7e203703831752d 100644 --- a/src/hotspot/cpu/ppc/copy_ppc.hpp +++ b/src/hotspot/cpu/ppc/copy_ppc.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2022, 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. * @@ -53,21 +53,7 @@ static void pd_disjoint_words(const HeapWord* from, HeapWord* to, size_t count) } static void pd_disjoint_words_atomic(const HeapWord* from, HeapWord* to, size_t count) { - switch (count) { - case 8: to[7] = from[7]; - case 7: to[6] = from[6]; - case 6: to[5] = from[5]; - case 5: to[4] = from[4]; - case 4: to[3] = from[3]; - case 3: to[2] = from[2]; - case 2: to[1] = from[1]; - case 1: to[0] = from[0]; - case 0: break; - default: while (count-- > 0) { - *to++ = *from++; - } - break; - } + shared_disjoint_words_atomic(from, to, count); } static void pd_aligned_conjoint_words(const HeapWord* from, HeapWord* to, size_t count) { diff --git a/src/hotspot/cpu/ppc/frame_ppc.cpp b/src/hotspot/cpu/ppc/frame_ppc.cpp index 870345789d6112339549d9964ebe4e7c9da3b531..b8e6433913b80a0956d720c745c41a9e2c33fbd7 100644 --- a/src/hotspot/cpu/ppc/frame_ppc.cpp +++ b/src/hotspot/cpu/ppc/frame_ppc.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2021 SAP SE. All rights reserved. + * Copyright (c) 2000, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -294,9 +294,57 @@ void frame::patch_pc(Thread* thread, address pc) { } bool frame::is_interpreted_frame_valid(JavaThread* thread) const { - // Is there anything to do? assert(is_interpreted_frame(), "Not an interpreted frame"); - return true; + // These are reasonable sanity checks + if (fp() == 0 || (intptr_t(fp()) & (wordSize-1)) != 0) { + return false; + } + if (sp() == 0 || (intptr_t(sp()) & (wordSize-1)) != 0) { + return false; + } + int min_frame_slots = (abi_minframe_size + ijava_state_size) / sizeof(intptr_t); + if (fp() - min_frame_slots < sp()) { + return false; + } + // These are hacks to keep us out of trouble. + // The problem with these is that they mask other problems + if (fp() <= sp()) { // this attempts to deal with unsigned comparison above + return false; + } + + // do some validation of frame elements + + // first the method + + Method* m = *interpreter_frame_method_addr(); + + // validate the method we'd find in this potential sender + if (!Method::is_valid_method(m)) return false; + + // stack frames shouldn't be much larger than max_stack elements + // this test requires the use of unextended_sp which is the sp as seen by + // the current frame, and not sp which is the "raw" pc which could point + // further because of local variables of the callee method inserted after + // method arguments + if (fp() - unextended_sp() > 1024 + m->max_stack()*Interpreter::stackElementSize) { + return false; + } + + // validate bci/bcx + + address bcp = interpreter_frame_bcp(); + if (m->validate_bci_from_bcp(bcp) < 0) { + return false; + } + + // validate constantPoolCache* + ConstantPoolCache* cp = *interpreter_frame_cache_addr(); + if (MetaspaceObj::is_valid(cp) == false) return false; + + // validate locals + + address locals = (address) *interpreter_frame_locals_addr(); + return thread->is_in_stack_range_incl(locals, (address)fp()); } BasicType frame::interpreter_frame_result(oop* oop_result, jvalue* value_result) { diff --git a/src/hotspot/cpu/ppc/frame_ppc.inline.hpp b/src/hotspot/cpu/ppc/frame_ppc.inline.hpp index 705b4abefdbd77ead3ef07ee0aca064df1d8aeaa..239db8224c0c38f811ca717d08e09316b0c7fce3 100644 --- a/src/hotspot/cpu/ppc/frame_ppc.inline.hpp +++ b/src/hotspot/cpu/ppc/frame_ppc.inline.hpp @@ -117,6 +117,10 @@ inline intptr_t* frame::link() const { return (intptr_t*)callers_abi()->callers_sp; } +inline intptr_t* frame::link_or_null() const { + return link(); +} + inline intptr_t* frame::real_fp() const { return fp(); } diff --git a/src/hotspot/cpu/ppc/gc/g1/g1BarrierSetAssembler_ppc.cpp b/src/hotspot/cpu/ppc/gc/g1/g1BarrierSetAssembler_ppc.cpp index a9328e8d616705b0e2caa8e40c254b5e46816a10..05c8374cfa4c8ca55d0c064308af9a4d45eb622c 100644 --- a/src/hotspot/cpu/ppc/gc/g1/g1BarrierSetAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/gc/g1/g1BarrierSetAssembler_ppc.cpp @@ -245,7 +245,7 @@ void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm, Decorato Register Rbase = tmp2; __ load_const_optimized(Rbase, (address)(ct->card_table()->byte_map_base()), /*temp*/ tmp3); - __ srdi(Rcard_addr, store_addr, CardTable::card_shift); + __ srdi(Rcard_addr, store_addr, CardTable::card_shift()); // Get the address of the card. __ lbzx(/*card value*/ tmp3, Rbase, Rcard_addr); @@ -516,7 +516,7 @@ void G1BarrierSetAssembler::generate_c1_post_barrier_runtime_stub(StubAssembler* __ std(addr, -8, R1_SP); __ std(tmp2, -16, R1_SP); - __ srdi(addr, R0, CardTable::card_shift); // Addr is passed in R0. + __ srdi(addr, R0, CardTable::card_shift()); // Addr is passed in R0. __ load_const_optimized(/*cardtable*/ tmp2, byte_map_base, tmp); __ add(addr, tmp2, addr); __ lbz(tmp, 0, addr); // tmp := [addr + cardtable] diff --git a/src/hotspot/cpu/ppc/gc/shared/barrierSetAssembler_ppc.cpp b/src/hotspot/cpu/ppc/gc/shared/barrierSetAssembler_ppc.cpp index 3758cc2fcf7627a618571efeb88589494092d0e5..c4b152a6db390401b0277eee08da2a14f1314f3d 100644 --- a/src/hotspot/cpu/ppc/gc/shared/barrierSetAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/gc/shared/barrierSetAssembler_ppc.cpp @@ -151,6 +151,8 @@ void BarrierSetAssembler::nmethod_entry_barrier(MacroAssembler* masm, Register t assert_different_registers(tmp, R0); + __ block_comment("nmethod_entry_barrier (nmethod_entry_barrier) {"); + // Load stub address using toc (fixed instruction size, unlike load_const_optimized) __ calculate_address_from_global_toc(tmp, StubRoutines::ppc::nmethod_entry_barrier(), true, true, false); // 2 instructions @@ -167,6 +169,8 @@ void BarrierSetAssembler::nmethod_entry_barrier(MacroAssembler* masm, Register t // Oops may have been changed; exploiting isync semantics (used as acquire) to make those updates observable. __ isync(); + + __ block_comment("} nmethod_entry_barrier (nmethod_entry_barrier)"); } void BarrierSetAssembler::c2i_entry_barrier(MacroAssembler *masm, Register tmp1, Register tmp2, Register tmp3) { @@ -177,6 +181,8 @@ void BarrierSetAssembler::c2i_entry_barrier(MacroAssembler *masm, Register tmp1, assert_different_registers(tmp1, tmp2, tmp3); + __ block_comment("c2i_entry_barrier (c2i_entry_barrier) {"); + Register tmp1_class_loader_data = tmp1; Label bad_call, skip_barrier; @@ -207,4 +213,6 @@ void BarrierSetAssembler::c2i_entry_barrier(MacroAssembler *masm, Register tmp1, __ bctr(); __ bind(skip_barrier); + + __ block_comment("} c2i_entry_barrier (c2i_entry_barrier)"); } diff --git a/src/hotspot/cpu/ppc/gc/shared/cardTableBarrierSetAssembler_ppc.cpp b/src/hotspot/cpu/ppc/gc/shared/cardTableBarrierSetAssembler_ppc.cpp index 8337317e3f2cc1a431aa8832d87005a72c222381..0d80f2fd95484922d76476d7fdcbe2c0c5c2d9cf 100644 --- a/src/hotspot/cpu/ppc/gc/shared/cardTableBarrierSetAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/gc/shared/cardTableBarrierSetAssembler_ppc.cpp @@ -54,8 +54,8 @@ void CardTableBarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembl __ addi(count, count, -BytesPerHeapOop); __ add(count, addr, count); // Use two shifts to clear out those low order two bits! (Cannot opt. into 1.) - __ srdi(addr, addr, CardTable::card_shift); - __ srdi(count, count, CardTable::card_shift); + __ srdi(addr, addr, CardTable::card_shift()); + __ srdi(count, count, CardTable::card_shift()); __ subf(count, addr, count); __ add_const_optimized(addr, addr, (address)ct->byte_map_base(), R0); __ addi(count, count, 1); @@ -74,7 +74,7 @@ void CardTableBarrierSetAssembler::card_table_write(MacroAssembler* masm, Register tmp, Register obj) { assert_different_registers(obj, tmp, R0); __ load_const_optimized(tmp, (address)byte_map_base, R0); - __ srdi(obj, obj, CardTable::card_shift); + __ srdi(obj, obj, CardTable::card_shift()); __ li(R0, CardTable::dirty_card_val()); __ stbx(R0, tmp, obj); } diff --git a/src/hotspot/cpu/ppc/gc/shenandoah/c1/shenandoahBarrierSetC1_ppc.cpp b/src/hotspot/cpu/ppc/gc/shenandoah/c1/shenandoahBarrierSetC1_ppc.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fc06e1b71e0b8fac8c899ec2a09594fe9d07aa18 --- /dev/null +++ b/src/hotspot/cpu/ppc/gc/shenandoah/c1/shenandoahBarrierSetC1_ppc.cpp @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2018, 2021, Red Hat, Inc. All rights reserved. + * Copyright (c) 2012, 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 "asm/macroAssembler.inline.hpp" +#include "c1/c1_LIRAssembler.hpp" +#include "c1/c1_MacroAssembler.hpp" +#include "gc/shenandoah/shenandoahBarrierSet.hpp" +#include "gc/shenandoah/shenandoahBarrierSetAssembler.hpp" +#include "gc/shenandoah/c1/shenandoahBarrierSetC1.hpp" + +#define __ masm->masm()-> + +void LIR_OpShenandoahCompareAndSwap::emit_code(LIR_Assembler *masm) { + __ block_comment("LIR_OpShenandoahCompareAndSwap (shenandaohgc) {"); + + Register addr = _addr->as_register_lo(); + Register new_val = _new_value->as_register(); + Register cmp_val = _cmp_value->as_register(); + Register tmp1 = _tmp1->as_register(); + Register tmp2 = _tmp2->as_register(); + Register result = result_opr()->as_register(); + + if (ShenandoahIUBarrier) { + ShenandoahBarrierSet::assembler()->iu_barrier(masm->masm(), new_val, tmp1, tmp2, + MacroAssembler::PRESERVATION_FRAME_LR_GP_FP_REGS); + } + + if (UseCompressedOops) { + __ encode_heap_oop(cmp_val, cmp_val); + __ encode_heap_oop(new_val, new_val); + } + + // Due to the memory barriers emitted in ShenandoahBarrierSetC1::atomic_cmpxchg_at_resolved, + // there is no need to specify stronger memory semantics. + ShenandoahBarrierSet::assembler()->cmpxchg_oop(masm->masm(), addr, cmp_val, new_val, tmp1, tmp2, + false, result); + + if (UseCompressedOops) { + __ decode_heap_oop(cmp_val); + __ decode_heap_oop(new_val); + } + + __ block_comment("} LIR_OpShenandoahCompareAndSwap (shenandaohgc)"); +} + +#undef __ + +#ifdef ASSERT +#define __ gen->lir(__FILE__, __LINE__)-> +#else +#define __ gen->lir()-> +#endif + +LIR_Opr ShenandoahBarrierSetC1::atomic_cmpxchg_at_resolved(LIRAccess &access, LIRItem &cmp_value, LIRItem &new_value) { + BasicType bt = access.type(); + + if (access.is_oop()) { + LIRGenerator* gen = access.gen(); + + if (ShenandoahCASBarrier) { + if (support_IRIW_for_not_multiple_copy_atomic_cpu) { + __ membar(); + } else { + __ membar_release(); + } + } + + if (ShenandoahSATBBarrier) { + pre_barrier(gen, access.access_emit_info(), access.decorators(), access.resolved_addr(), + LIR_OprFact::illegalOpr); + } + + if (ShenandoahCASBarrier) { + cmp_value.load_item(); + new_value.load_item(); + + LIR_Opr t1 = gen->new_register(T_OBJECT); + LIR_Opr t2 = gen->new_register(T_OBJECT); + LIR_Opr addr = access.resolved_addr()->as_address_ptr()->base(); + LIR_Opr result = gen->new_register(T_INT); + + __ append(new LIR_OpShenandoahCompareAndSwap(addr, cmp_value.result(), new_value.result(), t1, t2, result)); + + if (support_IRIW_for_not_multiple_copy_atomic_cpu) { + __ membar_acquire(); + } else { + __ membar(); + } + + return result; + } + } + + return BarrierSetC1::atomic_cmpxchg_at_resolved(access, cmp_value, new_value); +} + +LIR_Opr ShenandoahBarrierSetC1::atomic_xchg_at_resolved(LIRAccess &access, LIRItem &value) { + LIRGenerator* gen = access.gen(); + BasicType type = access.type(); + + LIR_Opr result = gen->new_register(type); + value.load_item(); + LIR_Opr value_opr = value.result(); + + if (support_IRIW_for_not_multiple_copy_atomic_cpu) { + __ membar(); + } else { + __ membar_release(); + } + + if (access.is_oop()) { + value_opr = iu_barrier(access.gen(), value_opr, access.access_emit_info(), access.decorators()); + } + + assert(type == T_INT || is_reference_type(type) LP64_ONLY( || type == T_LONG ), "unexpected type"); + LIR_Opr tmp_xchg = gen->new_register(T_INT); + __ xchg(access.resolved_addr(), value_opr, result, tmp_xchg); + + if (access.is_oop()) { + result = load_reference_barrier_impl(access.gen(), result, LIR_OprFact::addressConst(0), + access.decorators()); + + LIR_Opr tmp_barrier = gen->new_register(type); + __ move(result, tmp_barrier); + result = tmp_barrier; + + if (ShenandoahSATBBarrier) { + pre_barrier(access.gen(), access.access_emit_info(), access.decorators(), LIR_OprFact::illegalOpr, result); + } + } + + if (support_IRIW_for_not_multiple_copy_atomic_cpu) { + __ membar_acquire(); + } else { + __ membar(); + } + + return result; +} diff --git a/src/hotspot/cpu/ppc/gc/shenandoah/shenandoahBarrierSetAssembler_ppc.cpp b/src/hotspot/cpu/ppc/gc/shenandoah/shenandoahBarrierSetAssembler_ppc.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8c9955078ffad25eee3cd1110db324355e00d020 --- /dev/null +++ b/src/hotspot/cpu/ppc/gc/shenandoah/shenandoahBarrierSetAssembler_ppc.cpp @@ -0,0 +1,1012 @@ +/* + * Copyright (c) 2018, 2021, Red Hat, Inc. All rights reserved. + * Copyright (c) 2012, 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 "gc/shared/gcArguments.hpp" +#include "gc/shared/gc_globals.hpp" +#include "macroAssembler_ppc.hpp" +#include "precompiled.hpp" +#include "asm/macroAssembler.inline.hpp" +#include "gc/shenandoah/shenandoahBarrierSet.hpp" +#include "gc/shenandoah/shenandoahBarrierSetAssembler.hpp" +#include "gc/shenandoah/shenandoahForwarding.hpp" +#include "gc/shenandoah/shenandoahHeap.hpp" +#include "gc/shenandoah/shenandoahHeap.inline.hpp" +#include "gc/shenandoah/shenandoahHeapRegion.hpp" +#include "gc/shenandoah/shenandoahRuntime.hpp" +#include "gc/shenandoah/shenandoahThreadLocalData.hpp" +#include "gc/shenandoah/heuristics/shenandoahHeuristics.hpp" +#include "interpreter/interpreter.hpp" +#include "runtime/sharedRuntime.hpp" +#include "runtime/thread.hpp" +#include "utilities/globalDefinitions.hpp" +#include "vm_version_ppc.hpp" + +#ifdef COMPILER1 + +#include "c1/c1_LIRAssembler.hpp" +#include "c1/c1_MacroAssembler.hpp" +#include "gc/shenandoah/c1/shenandoahBarrierSetC1.hpp" + +#endif + +#define __ masm-> + +void ShenandoahBarrierSetAssembler::satb_write_barrier(MacroAssembler *masm, + Register base, RegisterOrConstant ind_or_offs, + Register tmp1, Register tmp2, Register tmp3, + MacroAssembler::PreservationLevel preservation_level) { + if (ShenandoahSATBBarrier) { + __ block_comment("satb_write_barrier (shenandoahgc) {"); + satb_write_barrier_impl(masm, 0, base, ind_or_offs, tmp1, tmp2, tmp3, preservation_level); + __ block_comment("} satb_write_barrier (shenandoahgc)"); + } +} + +void ShenandoahBarrierSetAssembler::iu_barrier(MacroAssembler *masm, + Register val, + Register tmp1, Register tmp2, + MacroAssembler::PreservationLevel preservation_level, + DecoratorSet decorators) { + // IU barriers are also employed to avoid resurrection of weak references, + // even if Shenandoah does not operate in incremental update mode. + if (ShenandoahIUBarrier || ShenandoahSATBBarrier) { + __ block_comment("iu_barrier (shenandoahgc) {"); + satb_write_barrier_impl(masm, decorators, noreg, noreg, val, tmp1, tmp2, preservation_level); + __ block_comment("} iu_barrier (shenandoahgc)"); + } +} + +void ShenandoahBarrierSetAssembler::load_reference_barrier(MacroAssembler *masm, DecoratorSet decorators, + Register base, RegisterOrConstant ind_or_offs, + Register dst, + Register tmp1, Register tmp2, + MacroAssembler::PreservationLevel preservation_level) { + if (ShenandoahLoadRefBarrier) { + __ block_comment("load_reference_barrier (shenandoahgc) {"); + load_reference_barrier_impl(masm, decorators, base, ind_or_offs, dst, tmp1, tmp2, preservation_level); + __ block_comment("} load_reference_barrier (shenandoahgc)"); + } +} + +void ShenandoahBarrierSetAssembler::arraycopy_prologue(MacroAssembler *masm, DecoratorSet decorators, BasicType type, + Register src, Register dst, Register count, + Register preserve1, Register preserve2) { + __ block_comment("arraycopy_prologue (shenandoahgc) {"); + + Register R11_tmp = R11_scratch1; + + assert_different_registers(src, dst, count, R11_tmp, noreg); + if (preserve1 != noreg) { + // Technically not required, but likely to indicate an error. + assert_different_registers(preserve1, preserve2); + } + + /* ==== Check whether barrier is required (optimizations) ==== */ + // Fast path: Component type of array is not a reference type. + if (!is_reference_type(type)) { + return; + } + + bool dest_uninitialized = (decorators & IS_DEST_UNINITIALIZED) != 0; + + // Fast path: No barrier required if for every barrier type, it is either disabled or would not store + // any useful information. + if ((!ShenandoahSATBBarrier || dest_uninitialized) && !ShenandoahIUBarrier && !ShenandoahLoadRefBarrier) { + return; + } + + Label skip_prologue; + + // Fast path: Array is of length zero. + __ cmpdi(CCR0, count, 0); + __ beq(CCR0, skip_prologue); + + /* ==== Check whether barrier is required (gc state) ==== */ + __ lbz(R11_tmp, in_bytes(ShenandoahThreadLocalData::gc_state_offset()), + R16_thread); + + // The set of garbage collection states requiring barriers depends on the available barrier types and the + // type of the reference in question. + // For instance, satb barriers may be skipped if it is certain that the overridden values are not relevant + // for the garbage collector. + const int required_states = ShenandoahSATBBarrier && dest_uninitialized + ? ShenandoahHeap::HAS_FORWARDED + : ShenandoahHeap::HAS_FORWARDED | ShenandoahHeap::MARKING; + + __ andi_(R11_tmp, R11_tmp, required_states); + __ beq(CCR0, skip_prologue); + + /* ==== Invoke runtime ==== */ + // Save to-be-preserved registers. + int highest_preserve_register_index = 0; + { + if (preserve1 != noreg && preserve1->is_volatile()) { + __ std(preserve1, -BytesPerWord * ++highest_preserve_register_index, R1_SP); + } + if (preserve2 != noreg && preserve2 != preserve1 && preserve2->is_volatile()) { + __ std(preserve2, -BytesPerWord * ++highest_preserve_register_index, R1_SP); + } + + __ std(src, -BytesPerWord * ++highest_preserve_register_index, R1_SP); + __ std(dst, -BytesPerWord * ++highest_preserve_register_index, R1_SP); + __ std(count, -BytesPerWord * ++highest_preserve_register_index, R1_SP); + + __ save_LR_CR(R11_tmp); + __ push_frame_reg_args(-BytesPerWord * highest_preserve_register_index, + R11_tmp); + } + + // Invoke runtime. + address jrt_address = NULL; + if (UseCompressedOops) { + jrt_address = CAST_FROM_FN_PTR(address, ShenandoahRuntime::arraycopy_barrier_narrow_oop_entry); + } else { + jrt_address = CAST_FROM_FN_PTR(address, ShenandoahRuntime::arraycopy_barrier_oop_entry); + } + assert(jrt_address != nullptr, "jrt routine cannot be found"); + + __ call_VM_leaf(jrt_address, src, dst, count); + + // Restore to-be-preserved registers. + { + __ pop_frame(); + __ restore_LR_CR(R11_tmp); + + __ ld(count, -BytesPerWord * highest_preserve_register_index--, R1_SP); + __ ld(dst, -BytesPerWord * highest_preserve_register_index--, R1_SP); + __ ld(src, -BytesPerWord * highest_preserve_register_index--, R1_SP); + + if (preserve2 != noreg && preserve2 != preserve1 && preserve2->is_volatile()) { + __ ld(preserve2, -BytesPerWord * highest_preserve_register_index--, R1_SP); + } + if (preserve1 != noreg && preserve1->is_volatile()) { + __ ld(preserve1, -BytesPerWord * highest_preserve_register_index--, R1_SP); + } + } + + __ bind(skip_prologue); + __ block_comment("} arraycopy_prologue (shenandoahgc)"); +} + +// The to-be-enqueued value can either be determined +// - dynamically by passing the reference's address information (load mode) or +// - statically by passing a register the value is stored in (preloaded mode) +// - for performance optimizations in cases where the previous value is known (currently not implemented) and +// - for incremental-update barriers. +// +// decorators: The previous value's decorator set. +// In "load mode", the value must equal '0'. +// base: Base register of the reference's address (load mode). +// In "preloaded mode", the register must equal 'noreg'. +// ind_or_offs: Index or offset of the reference's address (load mode). +// If 'base' equals 'noreg' (preloaded mode), the passed value is ignored. +// pre_val: Register holding the to-be-stored value (preloaded mode). +// In "load mode", this register acts as a temporary register and must +// thus not be 'noreg'. In "preloaded mode", its content will be sustained. +// tmp1/tmp2: Temporary registers, one of which must be non-volatile in "preloaded mode". +void ShenandoahBarrierSetAssembler::satb_write_barrier_impl(MacroAssembler *masm, DecoratorSet decorators, + Register base, RegisterOrConstant ind_or_offs, + Register pre_val, + Register tmp1, Register tmp2, + MacroAssembler::PreservationLevel preservation_level) { + assert_different_registers(tmp1, tmp2, pre_val, noreg); + + Label skip_barrier; + + /* ==== 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; + + // Check whether marking is active. + __ lbz(tmp1, in_bytes(ShenandoahThreadLocalData::gc_state_offset()), R16_thread); + + __ andi_(tmp1, tmp1, ShenandoahHeap::MARKING); + __ beq(CCR0, skip_barrier); + + /* ==== Determine the reference's previous value ==== */ + bool preloaded_mode = base == noreg; + Register pre_val_save = noreg; + + if (preloaded_mode) { + // Previous value has been passed to the method, so it must not be determined manually. + // In case 'pre_val' is a volatile register, it must be saved across the C-call + // as callers may depend on its value. + // Unless the general purposes registers are saved anyway, one of the temporary registers + // (i.e., 'tmp1' and 'tmp2') is used to the preserve 'pre_val'. + if (!preserve_gp_registers && pre_val->is_volatile()) { + pre_val_save = !tmp1->is_volatile() ? tmp1 : tmp2; + assert(!pre_val_save->is_volatile(), "at least one of the temporary registers must be non-volatile"); + } + + if ((decorators & IS_NOT_NULL) != 0) { +#ifdef ASSERT + __ cmpdi(CCR0, pre_val, 0); + __ asm_assert_ne("null oop is not allowed"); +#endif // ASSERT + } else { + __ cmpdi(CCR0, pre_val, 0); + __ beq(CCR0, skip_barrier); + } + } else { + // Load from the reference address to determine the reference's current value (before the store is being performed). + // Contrary to the given value in "preloaded mode", it is not necessary to preserve it. + assert(decorators == 0, "decorator set must be empty"); + assert(base != noreg, "base must be a register"); + assert(!ind_or_offs.is_register() || ind_or_offs.as_register() != noreg, "ind_or_offs must be a register"); + if (UseCompressedOops) { + __ lwz(pre_val, ind_or_offs, base); + } else { + __ ld(pre_val, ind_or_offs, base); + } + + __ cmpdi(CCR0, pre_val, 0); + __ beq(CCR0, skip_barrier); + + if (UseCompressedOops) { + __ decode_heap_oop_not_null(pre_val); + } + } + + /* ==== Try to enqueue the to-be-stored value directly into thread's local SATB mark queue ==== */ + { + Label runtime; + Register Rbuffer = tmp1, Rindex = tmp2; + + // Check whether the queue has enough capacity to store another oop. + // If not, jump to the runtime to commit the buffer and to allocate a new one. + // (The buffer's index corresponds to the amount of remaining free space.) + __ ld(Rindex, in_bytes(ShenandoahThreadLocalData::satb_mark_queue_index_offset()), R16_thread); + __ cmpdi(CCR0, Rindex, 0); + __ beq(CCR0, runtime); // If index == 0 (buffer is full), goto runtime. + + // Capacity suffices. Decrement the queue's size by the size of one oop. + // (The buffer is filled contrary to the heap's growing direction, i.e., it is filled downwards.) + __ addi(Rindex, Rindex, -wordSize); + __ std(Rindex, in_bytes(ShenandoahThreadLocalData::satb_mark_queue_index_offset()), R16_thread); + + // Enqueue the previous value and skip the invocation of the runtime. + __ ld(Rbuffer, in_bytes(ShenandoahThreadLocalData::satb_mark_queue_buffer_offset()), R16_thread); + __ stdx(pre_val, Rbuffer, Rindex); + __ b(skip_barrier); + + __ bind(runtime); + } + + /* ==== Invoke runtime to commit SATB mark queue to gc and allocate a new buffer ==== */ + // Save to-be-preserved registers. + int nbytes_save = 0; + + 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; + __ save_volatile_gprs(R1_SP, -nbytes_save, preserve_fp_registers); + } + + __ save_LR_CR(tmp1); + __ push_frame_reg_args(nbytes_save, tmp2); + } + + if (!preserve_gp_registers && preloaded_mode && pre_val->is_volatile()) { + assert(pre_val_save != noreg, "nv_save must not be noreg"); + + // 'pre_val' register must be saved manually unless general-purpose are preserved in general. + __ mr(pre_val_save, pre_val); + } + + // Invoke runtime. + __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre_entry), pre_val, R16_thread); + + // Restore to-be-preserved registers. + if (!preserve_gp_registers && preloaded_mode && pre_val->is_volatile()) { + __ mr(pre_val, pre_val_save); + } + + if (needs_frame) { + __ pop_frame(); + __ restore_LR_CR(tmp1); + + if (preserve_gp_registers) { + __ restore_volatile_gprs(R1_SP, -nbytes_save, preserve_fp_registers); + } + } + + __ bind(skip_barrier); +} + +void ShenandoahBarrierSetAssembler::resolve_forward_pointer_not_null(MacroAssembler *masm, Register dst, Register tmp) { + __ block_comment("resolve_forward_pointer_not_null (shenandoahgc) {"); + + Register tmp1 = tmp, + R0_tmp2 = R0; + assert_different_registers(dst, tmp1, R0_tmp2, noreg); + + // If the object has been evacuated, the mark word layout is as follows: + // | forwarding pointer (62-bit) | '11' (2-bit) | + + // The invariant that stack/thread pointers have the lowest two bits cleared permits retrieving + // the forwarding pointer solely by inversing the lowest two bits. + // This invariant follows inevitably from hotspot's minimal alignment. + assert(markWord::marked_value <= (unsigned long) MinObjAlignmentInBytes, + "marked value must not be higher than hotspot's minimal alignment"); + + Label done; + + // Load the object's mark word. + __ ld(tmp1, oopDesc::mark_offset_in_bytes(), dst); + + // Load the bit mask for the lock bits. + __ li(R0_tmp2, markWord::lock_mask_in_place); + + // Check whether all bits matching the bit mask are set. + // If that is the case, the object has been evacuated and the most significant bits form the forward pointer. + __ andc_(R0_tmp2, R0_tmp2, tmp1); + + assert(markWord::lock_mask_in_place == markWord::marked_value, + "marked value must equal the value obtained when all lock bits are being set"); + if (VM_Version::has_isel()) { + __ xori(tmp1, tmp1, markWord::lock_mask_in_place); + __ isel(dst, CCR0, Assembler::equal, false, tmp1); + } else { + __ bne(CCR0, done); + __ xori(dst, tmp1, markWord::lock_mask_in_place); + } + + __ bind(done); + __ block_comment("} resolve_forward_pointer_not_null (shenandoahgc)"); +} + +// base: Base register of the reference's address. +// ind_or_offs: Index or offset of the reference's address (load mode). +// dst: Reference's address. In case the object has been evacuated, this is the to-space version +// of that object. +void ShenandoahBarrierSetAssembler::load_reference_barrier_impl( + MacroAssembler *masm, DecoratorSet decorators, + Register base, RegisterOrConstant ind_or_offs, + Register dst, + Register tmp1, Register tmp2, + MacroAssembler::PreservationLevel preservation_level) { + if (ind_or_offs.is_register()) { + assert_different_registers(tmp1, tmp2, base, ind_or_offs.as_register(), dst, noreg); + } else { + assert_different_registers(tmp1, tmp2, base, dst, noreg); + } + + Label skip_barrier; + + bool is_strong = ShenandoahBarrierSet::is_strong_access(decorators); + bool is_weak = ShenandoahBarrierSet::is_weak_access(decorators); + bool is_phantom = ShenandoahBarrierSet::is_phantom_access(decorators); + bool is_native = ShenandoahBarrierSet::is_native_access(decorators); + bool is_narrow = UseCompressedOops && !is_native; + + /* ==== Check whether heap is stable ==== */ + __ lbz(tmp2, in_bytes(ShenandoahThreadLocalData::gc_state_offset()), R16_thread); + + if (is_strong) { + // For strong references, the heap is considered stable if "has forwarded" is not active. + __ andi_(tmp1, tmp2, ShenandoahHeap::HAS_FORWARDED | ShenandoahHeap::EVACUATION); + __ beq(CCR0, skip_barrier); +#ifdef ASSERT + // "evacuation" -> (implies) "has forwarded". If we reach this code, "has forwarded" must thus be set. + __ andi_(tmp1, tmp1, ShenandoahHeap::HAS_FORWARDED); + __ asm_assert_ne("'has forwarded' is missing"); +#endif // ASSERT + } else { + // For all non-strong references, the heap is considered stable if not any of "has forwarded", + // "root set processing", and "weak reference processing" is active. + // The additional phase conditions are in place to avoid the resurrection of weak references (see JDK-8266440). + Label skip_fastpath; + __ andi_(tmp1, tmp2, ShenandoahHeap::WEAK_ROOTS); + __ bne(CCR0, skip_fastpath); + + __ andi_(tmp1, tmp2, ShenandoahHeap::HAS_FORWARDED | ShenandoahHeap::EVACUATION); + __ beq(CCR0, skip_barrier); +#ifdef ASSERT + // "evacuation" -> (implies) "has forwarded". If we reach this code, "has forwarded" must thus be set. + __ andi_(tmp1, tmp1, ShenandoahHeap::HAS_FORWARDED); + __ asm_assert_ne("'has forwarded' is missing"); +#endif // ASSERT + + __ bind(skip_fastpath); + } + + /* ==== Check whether region is in collection set ==== */ + if (is_strong) { + // Shenandoah stores metadata on regions in a continuous area of memory in which a single byte corresponds to + // an entire region of the shenandoah heap. At present, only the least significant bit is of significance + // and indicates whether the region is part of the collection set. + // + // All regions are of the same size and are always aligned by a power of two. + // Any address can thus be shifted by a fixed number of bits to retrieve the address prefix shared by + // all objects within that region (region identification bits). + // + // | unused bits | region identification bits | object identification bits | + // (Region size depends on a couple of criteria, such as page size, user-provided arguments and the max heap size. + // The number of object identification bits can thus not be determined at compile time.) + // + // ------------------------------------------------------- <--- cs (collection set) base address + // | lost space due to heap space base address -> 'ShenandoahHeap::in_cset_fast_test_addr()' + // | (region identification bits contain heap base offset) + // |------------------------------------------------------ <--- cs base address + (heap_base >> region size shift) + // | collection set in the proper -> shift: 'region_size_bytes_shift_jint()' + // | + // |------------------------------------------------------ <--- cs base address + (heap_base >> region size shift) + // + number of regions + __ load_const_optimized(tmp2, ShenandoahHeap::in_cset_fast_test_addr(), tmp1); + __ srdi(tmp1, dst, ShenandoahHeapRegion::region_size_bytes_shift_jint()); + __ lbzx(tmp2, tmp1, tmp2); + __ andi_(tmp2, tmp2, 1); + __ beq(CCR0, skip_barrier); + } + + /* ==== Invoke runtime ==== */ + // Save to-be-preserved registers. + 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; + + 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; + __ save_volatile_gprs(R1_SP, -nbytes_save, preserve_fp_registers); + } + + __ save_LR_CR(tmp1); + __ push_frame_reg_args(nbytes_save, tmp1); + } + + // Calculate the reference's absolute address. + __ add(R4_ARG2, ind_or_offs, base); + + // Invoke runtime. + address jrt_address = nullptr; + + if (is_strong) { + if (is_narrow) { + jrt_address = CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_strong_narrow); + } else { + jrt_address = CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_strong); + } + } else if (is_weak) { + if (is_narrow) { + jrt_address = CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_weak_narrow); + } else { + jrt_address = CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_weak); + } + } else { + assert(is_phantom, "only remaining strength"); + assert(!is_narrow, "phantom access cannot be narrow"); + jrt_address = CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_phantom); + } + assert(jrt_address != nullptr, "jrt routine cannot be found"); + + __ call_VM_leaf(jrt_address, dst /* reference */, R4_ARG2 /* reference address */); + + // Restore to-be-preserved registers. + if (preserve_gp_registers) { + __ mr(R0, R3_RET); + } else { + __ mr_if_needed(dst, R3_RET); + } + + if (needs_frame) { + __ pop_frame(); + __ restore_LR_CR(tmp1); + + if (preserve_gp_registers) { + __ restore_volatile_gprs(R1_SP, -nbytes_save, preserve_fp_registers); + __ mr(dst, R0); + } + } + + __ bind(skip_barrier); +} + +// base: Base register of the reference's address. +// ind_or_offs: Index or offset of the reference's address. +// L_handle_null: An optional label that will be jumped to if the reference is null. +void ShenandoahBarrierSetAssembler::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) { + // Register must not clash, except 'base' and 'dst'. + if (ind_or_offs.is_register()) { + if (base != noreg) { + assert_different_registers(tmp1, tmp2, base, ind_or_offs.register_or_noreg(), R0, noreg); + } + assert_different_registers(tmp1, tmp2, dst, ind_or_offs.register_or_noreg(), R0, noreg); + } else { + if (base == noreg) { + assert_different_registers(tmp1, tmp2, base, R0, noreg); + } + assert_different_registers(tmp1, tmp2, dst, R0, noreg); + } + + /* ==== Apply load barrier, if required ==== */ + if (ShenandoahBarrierSet::need_load_reference_barrier(decorators, type)) { + assert(is_reference_type(type), "need_load_reference_barrier must check whether type is a reference type"); + + // If 'dst' clashes with either 'base' or 'ind_or_offs', use an intermediate result register + // to keep the values of those alive until the load reference barrier is applied. + Register intermediate_dst = (dst == base || (ind_or_offs.is_register() && dst == ind_or_offs.as_register())) + ? tmp2 + : dst; + + BarrierSetAssembler::load_at(masm, decorators, type, + base, ind_or_offs, + intermediate_dst, + tmp1, noreg, + preservation_level, L_handle_null); + + load_reference_barrier(masm, decorators, + base, ind_or_offs, + intermediate_dst, + tmp1, R0, + preservation_level); + + __ mr_if_needed(dst, intermediate_dst); + } else { + BarrierSetAssembler::load_at(masm, decorators, type, + base, ind_or_offs, + dst, + tmp1, tmp2, + preservation_level, L_handle_null); + } + + /* ==== Apply keep-alive barrier, if required (e.g., to inhibit weak reference resurrection) ==== */ + if (ShenandoahBarrierSet::need_keep_alive_barrier(decorators, type)) { + iu_barrier(masm, dst, tmp1, tmp2, preservation_level); + } +} + +// base: Base register of the reference's address. +// ind_or_offs: Index or offset of the reference's address. +// val: To-be-stored value/reference's new value. +void ShenandoahBarrierSetAssembler::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) { + if (is_reference_type(type)) { + if (ShenandoahSATBBarrier) { + satb_write_barrier(masm, base, ind_or_offs, tmp1, tmp2, tmp3, preservation_level); + } + + if (ShenandoahIUBarrier && val != noreg) { + iu_barrier(masm, val, tmp1, tmp2, preservation_level, decorators); + } + } + + BarrierSetAssembler::store_at(masm, decorators, type, + base, ind_or_offs, + val, + tmp1, tmp2, tmp3, + preservation_level); +} + +void ShenandoahBarrierSetAssembler::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 (shenandoahgc) {"); + + assert_different_registers(jni_env, obj, tmp); + + Label done; + + // Fast path: Reference is null (JNI tags are zero for null pointers). + __ cmpdi(CCR0, obj, 0); + __ beq(CCR0, done); + + // Resolve jobject using standard implementation. + BarrierSetAssembler::try_resolve_jobject_in_native(masm, dst, jni_env, obj, tmp, slowpath); + + // Check whether heap is stable. + __ lbz(tmp, + in_bytes(ShenandoahThreadLocalData::gc_state_offset() - JavaThread::jni_environment_offset()), + jni_env); + + __ andi_(tmp, tmp, ShenandoahHeap::EVACUATION | ShenandoahHeap::HAS_FORWARDED); + __ bne(CCR0, slowpath); + + __ bind(done); + __ block_comment("} try_resolve_jobject_in_native (shenandoahgc)"); +} + +// Special shenandoah CAS implementation that handles false negatives due +// to concurrent evacuation. That is, the CAS operation is intended to succeed in +// the following scenarios (success criteria): +// s1) The reference pointer ('base_addr') equals the expected ('expected') pointer. +// s2) The reference pointer refers to the from-space version of an already-evacuated +// object, whereas the expected pointer refers to the to-space version of the same object. +// Situations in which the reference pointer refers to the to-space version of an object +// and the expected pointer refers to the from-space version of the same object can not occur due to +// shenandoah's strong to-space invariant. This also implies that the reference stored in 'new_val' +// can not refer to the from-space version of an already-evacuated object. +// +// To guarantee correct behavior in concurrent environments, two races must be addressed: +// r1) A concurrent thread may heal the reference pointer (i.e., it is no longer referring to the +// from-space version but to the to-space version of the object in question). +// In this case, the CAS operation should succeed. +// r2) A concurrent thread may mutate the reference (i.e., the reference pointer refers to an entirely different object). +// In this case, the CAS operation should fail. +// +// By default, the value held in the 'result' register is zero to indicate failure of CAS, +// non-zero to indicate success. If 'is_cae' is set, the result is the most recently fetched +// value from 'base_addr' rather than a boolean success indicator. +void ShenandoahBarrierSetAssembler::cmpxchg_oop(MacroAssembler *masm, Register base_addr, + Register expected, Register new_val, Register tmp1, Register tmp2, + bool is_cae, Register result) { + __ block_comment("cmpxchg_oop (shenandoahgc) {"); + + assert_different_registers(base_addr, new_val, tmp1, tmp2, result, R0); + assert_different_registers(base_addr, expected, tmp1, tmp2, result, R0); + + // Potential clash of 'success_flag' and 'tmp' is being accounted for. + Register success_flag = is_cae ? noreg : result, + current_value = is_cae ? result : tmp1, + tmp = is_cae ? tmp1 : result, + initial_value = tmp2; + + Label done, step_four; + + __ bind(step_four); + + /* ==== Step 1 ("Standard" CAS) ==== */ + // Fast path: The values stored in 'expected' and 'base_addr' are equal. + // Given that 'expected' must refer to the to-space object of an evacuated object (strong to-space invariant), + // no special processing is required. + if (UseCompressedOops) { + __ cmpxchgw(CCR0, current_value, expected, new_val, base_addr, MacroAssembler::MemBarNone, + false, success_flag, true); + } else { + __ cmpxchgd(CCR0, current_value, expected, new_val, base_addr, MacroAssembler::MemBarNone, + false, success_flag, NULL, true); + } + + // Skip the rest of the barrier if the CAS operation succeeds immediately. + // If it does not, the value stored at the address is either the from-space pointer of the + // referenced object (success criteria s2)) or simply another object. + __ beq(CCR0, done); + + /* ==== Step 2 (Null check) ==== */ + // The success criteria s2) cannot be matched with a null pointer + // (null pointers cannot be subject to concurrent evacuation). The failure of the CAS operation is thus legitimate. + __ cmpdi(CCR0, current_value, 0); + __ beq(CCR0, done); + + /* ==== Step 3 (reference pointer refers to from-space version; success criteria s2)) ==== */ + // To check whether the reference pointer refers to the from-space version, the forward + // pointer of the object referred to by the reference is resolved and compared against the expected pointer. + // If this check succeed, another CAS operation is issued with the from-space pointer being the expected pointer. + // + // Save the potential from-space pointer. + __ mr(initial_value, current_value); + + // Resolve forward pointer. + if (UseCompressedOops) { __ decode_heap_oop_not_null(current_value); } + resolve_forward_pointer_not_null(masm, current_value, tmp); + if (UseCompressedOops) { __ encode_heap_oop_not_null(current_value); } + + if (!is_cae) { + // 'success_flag' was overwritten by call to 'resovle_forward_pointer_not_null'. + // Load zero into register for the potential failure case. + __ li(success_flag, 0); + } + __ cmpd(CCR0, current_value, expected); + __ bne(CCR0, done); + + // Discard fetched value as it might be a reference to the from-space version of an object. + if (UseCompressedOops) { + __ cmpxchgw(CCR0, R0, initial_value, new_val, base_addr, MacroAssembler::MemBarNone, + false, success_flag); + } else { + __ cmpxchgd(CCR0, R0, initial_value, new_val, base_addr, MacroAssembler::MemBarNone, + false, success_flag); + } + + /* ==== Step 4 (Retry CAS with to-space pointer (success criteria s2) under race r1)) ==== */ + // The reference pointer could have been healed whilst the previous CAS operation was being performed. + // Another CAS operation must thus be issued with the to-space pointer being the expected pointer. + // If that CAS operation fails as well, race r2) must have occurred, indicating that + // the operation failure is legitimate. + // + // To keep the code's size small and thus improving cache (icache) performance, this highly + // unlikely case should be handled by the smallest possible code. Instead of emitting a third, + // explicit CAS operation, the code jumps back and reuses the first CAS operation (step 1) + // (passed arguments are identical). + // + // A failure of the CAS operation in step 1 would imply that the overall CAS operation is supposed + // to fail. Jumping back to step 1 requires, however, that step 2 and step 3 are re-executed as well. + // It is thus important to ensure that a re-execution of those steps does not put program correctness + // at risk: + // - Step 2: Either terminates in failure (desired result) or falls through to step 3. + // - Step 3: Terminates if the comparison between the forwarded, fetched pointer and the expected value + // fails. Unless the reference has been updated in the meanwhile once again, this is + // guaranteed to be the case. + // In case of a concurrent update, the CAS would be retried again. This is legitimate + // in terms of program correctness (even though it is not desired). + __ bne(CCR0, step_four); + + __ bind(done); + __ block_comment("} cmpxchg_oop (shenandoahgc)"); +} + +#undef __ + +#ifdef COMPILER1 + +#define __ ce->masm()-> + +void ShenandoahBarrierSetAssembler::gen_pre_barrier_stub(LIR_Assembler *ce, ShenandoahPreBarrierStub *stub) { + __ block_comment("gen_pre_barrier_stub (shenandoahgc) {"); + + ShenandoahBarrierSetC1 *bs = (ShenandoahBarrierSetC1*) BarrierSet::barrier_set()->barrier_set_c1(); + __ bind(*stub->entry()); + + // GC status has already been verified by 'ShenandoahBarrierSetC1::pre_barrier'. + // This stub is the slowpath of that function. + + assert(stub->pre_val()->is_register(), "pre_val must be a register"); + Register pre_val = stub->pre_val()->as_register(); + + // If 'do_load()' returns false, the to-be-stored value is already available in 'stub->pre_val()' + // ("preloaded mode" of the store barrier). + if (stub->do_load()) { + ce->mem2reg(stub->addr(), stub->pre_val(), T_OBJECT, stub->patch_code(), stub->info(), false); + } + + // Fast path: Reference is null. + __ cmpdi(CCR0, pre_val, 0); + __ bc_far_optimized(Assembler::bcondCRbiIs1_bhintNoHint, __ bi0(CCR0, Assembler::equal), *stub->continuation()); + + // Argument passing via the stack. + __ std(pre_val, -8, R1_SP); + + __ load_const_optimized(R0, bs->pre_barrier_c1_runtime_code_blob()->code_begin()); + __ call_stub(R0); + + __ b(*stub->continuation()); + __ block_comment("} gen_pre_barrier_stub (shenandoahgc)"); +} + +void ShenandoahBarrierSetAssembler::gen_load_reference_barrier_stub(LIR_Assembler *ce, + ShenandoahLoadReferenceBarrierStub *stub) { + __ block_comment("gen_load_reference_barrier_stub (shenandoahgc) {"); + + ShenandoahBarrierSetC1 *bs = (ShenandoahBarrierSetC1*) BarrierSet::barrier_set()->barrier_set_c1(); + __ bind(*stub->entry()); + + Register obj = stub->obj()->as_register(); + Register res = stub->result()->as_register(); + Register addr = stub->addr()->as_pointer_register(); + Register tmp1 = stub->tmp1()->as_register(); + Register tmp2 = stub->tmp2()->as_register(); + assert_different_registers(addr, res, tmp1, tmp2); + +#ifdef ASSERT + // Ensure that 'res' is 'R3_ARG1' and contains the same value as 'obj' to reduce the number of required + // copy instructions. + assert(R3_RET == res, "res must be r3"); + __ cmpd(CCR0, res, obj); + __ asm_assert_eq("result register must contain the reference stored in obj"); +#endif + + DecoratorSet decorators = stub->decorators(); + + /* ==== Check whether region is in collection set ==== */ + // GC status (unstable) has already been verified by 'ShenandoahBarrierSetC1::load_reference_barrier_impl'. + // This stub is the slowpath of that function. + + bool is_strong = ShenandoahBarrierSet::is_strong_access(decorators); + bool is_weak = ShenandoahBarrierSet::is_weak_access(decorators); + bool is_phantom = ShenandoahBarrierSet::is_phantom_access(decorators); + bool is_native = ShenandoahBarrierSet::is_native_access(decorators); + + if (is_strong) { + // Check whether object is in collection set. + __ load_const_optimized(tmp2, ShenandoahHeap::in_cset_fast_test_addr(), tmp1); + __ srdi(tmp1, obj, ShenandoahHeapRegion::region_size_bytes_shift_jint()); + __ lbzx(tmp2, tmp1, tmp2); + + __ andi_(tmp2, tmp2, 1); + __ bc_far_optimized(Assembler::bcondCRbiIs1_bhintNoHint, __ bi0(CCR0, Assembler::equal), *stub->continuation()); + } + + address blob_addr = nullptr; + + if (is_strong) { + if (is_native) { + blob_addr = bs->load_reference_barrier_strong_native_rt_code_blob()->code_begin(); + } else { + blob_addr = bs->load_reference_barrier_strong_rt_code_blob()->code_begin(); + } + } else if (is_weak) { + blob_addr = bs->load_reference_barrier_weak_rt_code_blob()->code_begin(); + } else { + assert(is_phantom, "only remaining strength"); + blob_addr = bs->load_reference_barrier_phantom_rt_code_blob()->code_begin(); + } + + assert(blob_addr != nullptr, "code blob cannot be found"); + + // Argument passing via the stack. 'obj' is passed implicitly (as asserted above). + __ std(addr, -8, R1_SP); + + __ load_const_optimized(tmp1, blob_addr, tmp2); + __ call_stub(tmp1); + + // 'res' is 'R3_RET'. The result is thus already in the correct register. + + __ b(*stub->continuation()); + __ block_comment("} gen_load_reference_barrier_stub (shenandoahgc)"); +} + +#undef __ + +#define __ sasm-> + +void ShenandoahBarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAssembler *sasm) { + __ block_comment("generate_c1_pre_barrier_runtime_stub (shenandoahgc) {"); + + Label runtime, skip_barrier; + BarrierSet *bs = BarrierSet::barrier_set(); + + // Argument passing via the stack. + const int caller_stack_slots = 3; + + Register R0_pre_val = R0; + __ ld(R0, -8, R1_SP); + Register R11_tmp1 = R11_scratch1; + __ std(R11_tmp1, -16, R1_SP); + Register R12_tmp2 = R12_scratch2; + __ std(R12_tmp2, -24, R1_SP); + + /* ==== Check whether marking is active ==== */ + // Even though gc status was checked in 'ShenandoahBarrierSetAssembler::gen_pre_barrier_stub', + // another check is required as a safepoint might have been reached in the meantime (JDK-8140588). + __ lbz(R12_tmp2, in_bytes(ShenandoahThreadLocalData::gc_state_offset()), R16_thread); + + __ andi_(R12_tmp2, R12_tmp2, ShenandoahHeap::MARKING); + __ beq(CCR0, skip_barrier); + + /* ==== Add previous value directly to thread-local SATB mark queue ==== */ + // Check queue's capacity. Jump to runtime if no free slot is available. + __ ld(R12_tmp2, in_bytes(ShenandoahThreadLocalData::satb_mark_queue_index_offset()), R16_thread); + __ cmpdi(CCR0, R12_tmp2, 0); + __ beq(CCR0, runtime); + + // Capacity suffices. Decrement the queue's size by one slot (size of one oop). + __ addi(R12_tmp2, R12_tmp2, -wordSize); + __ std(R12_tmp2, in_bytes(ShenandoahThreadLocalData::satb_mark_queue_index_offset()), R16_thread); + + // Enqueue the previous value and skip the runtime invocation. + __ ld(R11_tmp1, in_bytes(ShenandoahThreadLocalData::satb_mark_queue_buffer_offset()), R16_thread); + __ stdx(R0_pre_val, R11_tmp1, R12_tmp2); + __ b(skip_barrier); + + __ bind(runtime); + + /* ==== Invoke runtime to commit SATB mark queue to gc and allocate a new buffer ==== */ + // Save to-be-preserved registers. + const int nbytes_save = (MacroAssembler::num_volatile_regs + caller_stack_slots) * BytesPerWord; + __ save_volatile_gprs(R1_SP, -nbytes_save); + __ save_LR_CR(R11_tmp1); + __ push_frame_reg_args(nbytes_save, R11_tmp1); + + // Invoke runtime. + __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre_entry), R0_pre_val, R16_thread); + + // Restore to-be-preserved registers. + __ pop_frame(); + __ restore_LR_CR(R11_tmp1); + __ restore_volatile_gprs(R1_SP, -nbytes_save); + + __ bind(skip_barrier); + + // Restore spilled registers. + __ ld(R11_tmp1, -16, R1_SP); + __ ld(R12_tmp2, -24, R1_SP); + + __ blr(); + __ block_comment("} generate_c1_pre_barrier_runtime_stub (shenandoahgc)"); +} + +void ShenandoahBarrierSetAssembler::generate_c1_load_reference_barrier_runtime_stub(StubAssembler *sasm, + DecoratorSet decorators) { + __ block_comment("generate_c1_load_reference_barrier_runtime_stub (shenandoahgc) {"); + + // Argument passing via the stack. + const int caller_stack_slots = 1; + + // Save to-be-preserved registers. + const int nbytes_save = (MacroAssembler::num_volatile_regs - 1 // 'R3_ARG1' is skipped + + caller_stack_slots) * BytesPerWord; + __ save_volatile_gprs(R1_SP, -nbytes_save, true, false); + + // Load arguments from stack. + // No load required, as assured by assertions in 'ShenandoahBarrierSetAssembler::gen_load_reference_barrier_stub'. + Register R3_obj = R3_ARG1; + Register R4_load_addr = R4_ARG2; + __ ld(R4_load_addr, -8, R1_SP); + + Register R11_tmp = R11_scratch1; + + /* ==== Invoke runtime ==== */ + bool is_strong = ShenandoahBarrierSet::is_strong_access(decorators); + bool is_weak = ShenandoahBarrierSet::is_weak_access(decorators); + bool is_phantom = ShenandoahBarrierSet::is_phantom_access(decorators); + bool is_native = ShenandoahBarrierSet::is_native_access(decorators); + + address jrt_address = NULL; + + if (is_strong) { + if (is_native) { + jrt_address = CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_strong); + } else { + if (UseCompressedOops) { + jrt_address = CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_strong_narrow); + } else { + jrt_address = CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_strong); + } + } + } else if (is_weak) { + assert(!is_native, "weak load reference barrier must not be called off-heap"); + if (UseCompressedOops) { + jrt_address = CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_weak_narrow); + } else { + jrt_address = CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_weak); + } + } else { + assert(is_phantom, "reference type must be phantom"); + assert(is_native, "phantom load reference barrier must be called off-heap"); + jrt_address = CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_phantom); + } + assert(jrt_address != NULL, "load reference barrier runtime routine cannot be found"); + + __ save_LR_CR(R11_tmp); + __ push_frame_reg_args(nbytes_save, R11_tmp); + + // Invoke runtime. Arguments are already stored in the corresponding registers. + __ call_VM_leaf(jrt_address, R3_obj, R4_load_addr); + + // Restore to-be-preserved registers. + __ pop_frame(); + __ restore_LR_CR(R11_tmp); + __ restore_volatile_gprs(R1_SP, -nbytes_save, true, false); // Skip 'R3_RET' register. + + __ blr(); + __ block_comment("} generate_c1_load_reference_barrier_runtime_stub (shenandoahgc)"); +} + +#undef __ + +#endif // COMPILER1 diff --git a/src/hotspot/cpu/ppc/gc/shenandoah/shenandoahBarrierSetAssembler_ppc.hpp b/src/hotspot/cpu/ppc/gc/shenandoah/shenandoahBarrierSetAssembler_ppc.hpp new file mode 100644 index 0000000000000000000000000000000000000000..cf55f505b22070712b9c2b4f77bfc78000896d76 --- /dev/null +++ b/src/hotspot/cpu/ppc/gc/shenandoah/shenandoahBarrierSetAssembler_ppc.hpp @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2018, 2021, Red Hat, Inc. All rights reserved. + * Copyright (c) 2012, 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_SHENANDOAH_SHENANDOAHBARRIERSETASSEMBLER_PPC_HPP +#define CPU_PPC_GC_SHENANDOAH_SHENANDOAHBARRIERSETASSEMBLER_PPC_HPP + +#include "asm/macroAssembler.hpp" +#include "gc/shared/barrierSetAssembler.hpp" +#include "gc/shenandoah/shenandoahBarrierSet.hpp" + +#ifdef COMPILER1 + +class LIR_Assembler; +class ShenandoahPreBarrierStub; +class ShenandoahLoadReferenceBarrierStub; +class StubAssembler; + +#endif + +class StubCodeGenerator; + +class ShenandoahBarrierSetAssembler: public BarrierSetAssembler { +private: + + /* ==== Actual barrier implementations ==== */ + void satb_write_barrier_impl(MacroAssembler* masm, DecoratorSet decorators, + Register base, RegisterOrConstant ind_or_offs, + Register pre_val, + Register tmp1, Register tmp2, + MacroAssembler::PreservationLevel preservation_level); + + void load_reference_barrier_impl(MacroAssembler* masm, DecoratorSet decorators, + Register base, RegisterOrConstant ind_or_offs, + Register dst, + Register tmp1, Register tmp2, + MacroAssembler::PreservationLevel preservation_level); + + /* ==== Helper methods for barrier implementations ==== */ + void resolve_forward_pointer_not_null(MacroAssembler* masm, Register dst, Register tmp); + +public: + + /* ==== C1 stubs ==== */ +#ifdef COMPILER1 + + void gen_pre_barrier_stub(LIR_Assembler* ce, ShenandoahPreBarrierStub* stub); + + void gen_load_reference_barrier_stub(LIR_Assembler* ce, ShenandoahLoadReferenceBarrierStub* stub); + + void generate_c1_pre_barrier_runtime_stub(StubAssembler* sasm); + + void generate_c1_load_reference_barrier_runtime_stub(StubAssembler* sasm, DecoratorSet decorators); + +#endif + + /* ==== Available barriers (facades of the actual implementations) ==== */ + void satb_write_barrier(MacroAssembler* masm, + Register base, RegisterOrConstant ind_or_offs, + Register tmp1, Register tmp2, Register tmp3, + MacroAssembler::PreservationLevel preservation_level); + + void iu_barrier(MacroAssembler* masm, + Register val, + Register tmp1, Register tmp2, + MacroAssembler::PreservationLevel preservation_level, DecoratorSet decorators = 0); + + void load_reference_barrier(MacroAssembler* masm, DecoratorSet decorators, + Register base, RegisterOrConstant ind_or_offs, + Register dst, + Register tmp1, Register tmp2, + MacroAssembler::PreservationLevel preservation_level); + + /* ==== Helper methods used by C1 and C2 ==== */ + void cmpxchg_oop(MacroAssembler* masm, Register base_addr, Register expected, Register new_val, + Register tmp1, Register tmp2, + bool is_cae, Register result); + + /* ==== Access api ==== */ + virtual void arraycopy_prologue(MacroAssembler* masm, DecoratorSet decorators, BasicType type, + Register src, Register dst, Register count, Register preserve1, Register preserve2); + + 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); + + 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 = NULL); + + virtual void try_resolve_jobject_in_native(MacroAssembler* masm, Register dst, Register jni_env, + Register obj, Register tmp, Label& slowpath); +}; + +#endif // CPU_PPC_GC_SHENANDOAH_SHENANDOAHBARRIERSETASSEMBLER_PPC_HPP diff --git a/src/hotspot/cpu/ppc/gc/shenandoah/shenandoah_ppc.ad b/src/hotspot/cpu/ppc/gc/shenandoah/shenandoah_ppc.ad new file mode 100644 index 0000000000000000000000000000000000000000..4825ca9cf81cdf4bfb1aaf4ffbe6ab87ddcc2d9b --- /dev/null +++ b/src/hotspot/cpu/ppc/gc/shenandoah/shenandoah_ppc.ad @@ -0,0 +1,217 @@ +// +// Copyright (c) 2018, 2021, Red Hat, Inc. All rights reserved. +// Copyright (c) 2012, 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/shenandoah/shenandoahBarrierSet.hpp" +#include "gc/shenandoah/shenandoahBarrierSetAssembler.hpp" +%} + +// Weak compareAndSwap operations are treated as strong compareAndSwap operations. +// This is motivated by the retry logic of ShenandoahBarrierSetAssembler::cmpxchg_oop which is hard to realise +// using weak CAS operations. + +instruct compareAndSwapP_shenandoah(iRegIdst res, indirect mem, iRegPsrc oldval, iRegPsrc newval, + iRegPdst tmp1, iRegPdst tmp2, flagsRegCR0 cr) %{ + match(Set res (ShenandoahCompareAndSwapP mem (Binary oldval newval))); + match(Set res (ShenandoahWeakCompareAndSwapP mem (Binary oldval newval))); + effect(TEMP_DEF res, TEMP tmp1, TEMP tmp2, KILL cr); + + predicate(((CompareAndSwapNode*)n)->order() != MemNode::acquire + && ((CompareAndSwapNode*)n)->order() != MemNode::seqcst); + + format %{ "CMPXCHG $res, $mem, $oldval, $newval; as bool; ptr" %} + ins_encode %{ + ShenandoahBarrierSet::assembler()->cmpxchg_oop( + &_masm, + $mem$$Register, $oldval$$Register, $newval$$Register, + $tmp1$$Register, $tmp2$$Register, + false, $res$$Register + ); + %} + ins_pipe(pipe_class_default); +%} + +instruct compareAndSwapN_shenandoah(iRegIdst res, indirect mem, iRegNsrc oldval, iRegNsrc newval, + iRegNdst tmp1, iRegNdst tmp2, flagsRegCR0 cr) %{ + match(Set res (ShenandoahCompareAndSwapN mem (Binary oldval newval))); + match(Set res (ShenandoahWeakCompareAndSwapN mem (Binary oldval newval))); + effect(TEMP_DEF res, TEMP tmp1, TEMP tmp2, KILL cr); + + predicate(((CompareAndSwapNode*)n)->order() != MemNode::acquire + && ((CompareAndSwapNode*)n)->order() != MemNode::seqcst); + + format %{ "CMPXCHG $res, $mem, $oldval, $newval; as bool; ptr" %} + ins_encode %{ + ShenandoahBarrierSet::assembler()->cmpxchg_oop( + &_masm, + $mem$$Register, $oldval$$Register, $newval$$Register, + $tmp1$$Register, $tmp2$$Register, + false, $res$$Register + ); + %} + ins_pipe(pipe_class_default); +%} + +instruct compareAndSwapP_acq_shenandoah(iRegIdst res, indirect mem, iRegPsrc oldval, iRegPsrc newval, + iRegPdst tmp1, iRegPdst tmp2, flagsRegCR0 cr) %{ + match(Set res (ShenandoahCompareAndSwapP mem (Binary oldval newval))); + match(Set res (ShenandoahWeakCompareAndSwapP mem (Binary oldval newval))); + effect(TEMP_DEF res, TEMP tmp1, TEMP tmp2, KILL cr); + + predicate(((CompareAndSwapNode*)n)->order() == MemNode::acquire + || ((CompareAndSwapNode*)n)->order() == MemNode::seqcst); + + format %{ "CMPXCHGD acq $res, $mem, $oldval, $newval; as bool; ptr" %} + ins_encode %{ + ShenandoahBarrierSet::assembler()->cmpxchg_oop( + &_masm, + $mem$$Register, $oldval$$Register, $newval$$Register, + $tmp1$$Register, $tmp2$$Register, + false, $res$$Register + ); + if (support_IRIW_for_not_multiple_copy_atomic_cpu) { + __ isync(); + } else { + __ sync(); + } + %} + ins_pipe(pipe_class_default); +%} + +instruct compareAndSwapN_acq_shenandoah(iRegIdst res, indirect mem, iRegNsrc oldval, iRegNsrc newval, + iRegNdst tmp1, iRegNdst tmp2, flagsRegCR0 cr) %{ + match(Set res (ShenandoahCompareAndSwapN mem (Binary oldval newval))); + match(Set res (ShenandoahWeakCompareAndSwapN mem (Binary oldval newval))); + effect(TEMP_DEF res, TEMP tmp1, TEMP tmp2, KILL cr); + + predicate(((CompareAndSwapNode*)n)->order() == MemNode::acquire + || ((CompareAndSwapNode*)n)->order() == MemNode::seqcst); + + format %{ "CMPXCHGD acq $res, $mem, $oldval, $newval; as bool; ptr" %} + ins_encode %{ + ShenandoahBarrierSet::assembler()->cmpxchg_oop( + &_masm, + $mem$$Register, $oldval$$Register, $newval$$Register, + $tmp1$$Register, $tmp2$$Register, + false, $res$$Register + ); + if (support_IRIW_for_not_multiple_copy_atomic_cpu) { + __ isync(); + } else { + __ sync(); + } + %} + ins_pipe(pipe_class_default); +%} + +instruct compareAndExchangeP_shenandoah(iRegPdst res, indirect mem, iRegPsrc oldval, iRegPsrc newval, + iRegPdst tmp1, iRegPdst tmp2, flagsRegCR0 cr) %{ + match(Set res (ShenandoahCompareAndExchangeP mem (Binary oldval newval))); + effect(TEMP_DEF res, TEMP tmp1, TEMP tmp2, KILL cr); + + predicate(((CompareAndSwapNode*)n)->order() != MemNode::acquire + && ((CompareAndSwapNode*)n)->order() != MemNode::seqcst); + + format %{ "CMPXCHGD $res, $mem, $oldval, $newval; as ptr; ptr" %} + ins_encode %{ + ShenandoahBarrierSet::assembler()->cmpxchg_oop( + &_masm, + $mem$$Register, $oldval$$Register, $newval$$Register, + $tmp1$$Register, $tmp2$$Register, + true, $res$$Register + ); + %} + ins_pipe(pipe_class_default); +%} + +instruct compareAndExchangeN_shenandoah(iRegNdst res, indirect mem, iRegNsrc oldval, iRegNsrc newval, + iRegNdst tmp1, iRegNdst tmp2, flagsRegCR0 cr) %{ + match(Set res (ShenandoahCompareAndExchangeN mem (Binary oldval newval))); + effect(TEMP_DEF res, TEMP tmp1, TEMP tmp2, KILL cr); + + predicate(((CompareAndSwapNode*)n)->order() != MemNode::acquire + && ((CompareAndSwapNode*)n)->order() != MemNode::seqcst); + + format %{ "CMPXCHGD $res, $mem, $oldval, $newval; as ptr; ptr" %} + ins_encode %{ + ShenandoahBarrierSet::assembler()->cmpxchg_oop( + &_masm, + $mem$$Register, $oldval$$Register, $newval$$Register, + $tmp1$$Register, $tmp2$$Register, + true, $res$$Register + ); + %} + ins_pipe(pipe_class_default); +%} + +instruct compareAndExchangePAcq_shenandoah(iRegPdst res, indirect mem, iRegPsrc oldval, iRegPsrc newval, + iRegPdst tmp1, iRegPdst tmp2, flagsRegCR0 cr) %{ + match(Set res (ShenandoahCompareAndExchangeP mem (Binary oldval newval))); + effect(TEMP_DEF res, TEMP tmp1, TEMP tmp2, KILL cr); + + predicate(((CompareAndSwapNode*)n)->order() == MemNode::acquire + || ((CompareAndSwapNode*)n)->order() == MemNode::seqcst); + + format %{ "CMPXCHGD acq $res, $mem, $oldval, $newval; as ptr; ptr" %} + ins_encode %{ + ShenandoahBarrierSet::assembler()->cmpxchg_oop( + &_masm, + $mem$$Register, $oldval$$Register, $newval$$Register, + $tmp1$$Register, $tmp2$$Register, + true, $res$$Register + ); + if (support_IRIW_for_not_multiple_copy_atomic_cpu) { + __ isync(); + } else { + __ sync(); + } + %} + ins_pipe(pipe_class_default); +%} + +instruct compareAndExchangeNAcq_shenandoah(iRegNdst res, indirect mem, iRegNsrc oldval, iRegNsrc newval, + iRegNdst tmp1, iRegNdst tmp2, flagsRegCR0 cr) %{ + match(Set res (ShenandoahCompareAndExchangeN mem (Binary oldval newval))); + effect(TEMP_DEF res, TEMP tmp1, TEMP tmp2, KILL cr); + + predicate(((CompareAndSwapNode*)n)->order() == MemNode::acquire + || ((CompareAndSwapNode*)n)->order() == MemNode::seqcst); + + format %{ "CMPXCHGD acq $res, $mem, $oldval, $newval; as ptr; ptr" %} + ins_encode %{ + ShenandoahBarrierSet::assembler()->cmpxchg_oop( + &_masm, + $mem$$Register, $oldval$$Register, $newval$$Register, + $tmp1$$Register, $tmp2$$Register, + true, $res$$Register + ); + if (support_IRIW_for_not_multiple_copy_atomic_cpu) { + __ isync(); + } else { + __ sync(); + } + %} + ins_pipe(pipe_class_default); +%} diff --git a/src/hotspot/cpu/ppc/jniTypes_ppc.hpp b/src/hotspot/cpu/ppc/jniTypes_ppc.hpp index ef1fe4acfdf4bd8562e44e584d237473f2c18426..13ccaf408e9686f47fa29a6bd9c0a941f17576fd 100644 --- a/src/hotspot/cpu/ppc/jniTypes_ppc.hpp +++ b/src/hotspot/cpu/ppc/jniTypes_ppc.hpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2013 SAP SE. All rights reserved. + * Copyright (c) 2002, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -27,7 +27,7 @@ #define CPU_PPC_JNITYPES_PPC_HPP #include "jni.h" -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" #include "oops/oop.hpp" // This file holds platform-dependent routines used to write primitive diff --git a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp index 98565003691a45fd9c35ea0609d3c8ec2717cd60..d8397ed6fa5382e12e5981854a46a50997b26fc0 100644 --- a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2021 SAP SE. All rights reserved. + * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -233,7 +233,7 @@ address MacroAssembler::patch_set_narrow_oop(address a, address bound, narrowOop return inst1_addr; } -// Get compressed oop or klass constant. +// Get compressed oop constant. narrowOop MacroAssembler::get_narrow_oop(address a, address bound) { assert(UseCompressedOops, "Should only patch compressed oops"); @@ -2660,27 +2660,32 @@ void MacroAssembler::compiler_fast_lock_object(ConditionRegister flag, Register andi_(temp, displaced_header, markWord::monitor_value); bne(CCR0, object_has_monitor); - // Set displaced_header to be (markWord of object | UNLOCK_VALUE). - ori(displaced_header, displaced_header, markWord::unlocked_value); - - // Load Compare Value application register. - - // Initialize the box. (Must happen before we update the object mark!) - std(displaced_header, BasicLock::displaced_header_offset_in_bytes(), box); - - // Must fence, otherwise, preceding store(s) may float below cmpxchg. - // Compare object markWord with mark and if equal exchange scratch1 with object markWord. - cmpxchgd(/*flag=*/flag, - /*current_value=*/current_header, - /*compare_value=*/displaced_header, - /*exchange_value=*/box, - /*where=*/oop, - MacroAssembler::MemBarRel | MacroAssembler::MemBarAcq, - MacroAssembler::cmpxchgx_hint_acquire_lock(), - noreg, - &cas_failed, - /*check without membar and ldarx first*/true); - assert(oopDesc::mark_offset_in_bytes() == 0, "offset of _mark is not 0"); + if (!UseHeavyMonitors) { + // Set displaced_header to be (markWord of object | UNLOCK_VALUE). + ori(displaced_header, displaced_header, markWord::unlocked_value); + + // Load Compare Value application register. + + // Initialize the box. (Must happen before we update the object mark!) + std(displaced_header, BasicLock::displaced_header_offset_in_bytes(), box); + + // Must fence, otherwise, preceding store(s) may float below cmpxchg. + // Compare object markWord with mark and if equal exchange scratch1 with object markWord. + cmpxchgd(/*flag=*/flag, + /*current_value=*/current_header, + /*compare_value=*/displaced_header, + /*exchange_value=*/box, + /*where=*/oop, + MacroAssembler::MemBarRel | MacroAssembler::MemBarAcq, + MacroAssembler::cmpxchgx_hint_acquire_lock(), + noreg, + &cas_failed, + /*check without membar and ldarx first*/true); + assert(oopDesc::mark_offset_in_bytes() == 0, "offset of _mark is not 0"); + } else { + // Set NE to indicate 'failure' -> take slow-path. + crandc(flag, Assembler::equal, flag, Assembler::equal); + } // If the compare-and-exchange succeeded, then we found an unlocked // object and we have now locked it. @@ -2727,16 +2732,17 @@ void MacroAssembler::compiler_fast_lock_object(ConditionRegister flag, Register // Store a non-null value into the box. std(box, BasicLock::displaced_header_offset_in_bytes(), box); + beq(flag, cont); -# ifdef ASSERT + // Check for recursive locking. + cmpd(flag, current_header, R16_thread); bne(flag, cont); - // We have acquired the monitor, check some invariants. - addi(/*monitor=*/temp, temp, -ObjectMonitor::owner_offset_in_bytes()); - // Invariant 1: _recursions should be 0. - //assert(ObjectMonitor::recursions_size_in_bytes() == 8, "unexpected size"); - asm_assert_mem8_is_zero(ObjectMonitor::recursions_offset_in_bytes(), temp, - "monitor->_recursions should be 0"); -# endif + + // Current thread already owns the lock. Just increment recursions. + Register recursions = displaced_header; + ld(recursions, ObjectMonitor::recursions_offset_in_bytes()-ObjectMonitor::owner_offset_in_bytes(), temp); + addi(recursions, recursions, 1); + std(recursions, ObjectMonitor::recursions_offset_in_bytes()-ObjectMonitor::owner_offset_in_bytes(), temp); #if INCLUDE_RTM_OPT } // use_rtm() @@ -2752,8 +2758,7 @@ void MacroAssembler::compiler_fast_unlock_object(ConditionRegister flag, Registe bool use_rtm) { assert_different_registers(oop, box, temp, displaced_header, current_header); assert(flag != CCR0, "bad condition register"); - Label cont; - Label object_has_monitor; + Label cont, object_has_monitor, notRecursive; #if INCLUDE_RTM_OPT if (UseRTMForStackLocks && use_rtm) { @@ -2768,12 +2773,14 @@ void MacroAssembler::compiler_fast_unlock_object(ConditionRegister flag, Registe } #endif - // Find the lock address and load the displaced header from the stack. - ld(displaced_header, BasicLock::displaced_header_offset_in_bytes(), box); + if (!UseHeavyMonitors) { + // Find the lock address and load the displaced header from the stack. + ld(displaced_header, BasicLock::displaced_header_offset_in_bytes(), box); - // If the displaced header is 0, we have a recursive unlock. - cmpdi(flag, displaced_header, 0); - beq(flag, cont); + // If the displaced header is 0, we have a recursive unlock. + cmpdi(flag, displaced_header, 0); + beq(flag, cont); + } // Handle existing monitor. // The object has an existing monitor iff (mark & monitor_value) != 0. @@ -2782,20 +2789,24 @@ void MacroAssembler::compiler_fast_unlock_object(ConditionRegister flag, Registe andi_(R0, current_header, markWord::monitor_value); bne(CCR0, object_has_monitor); - // Check if it is still a light weight lock, this is is true if we see - // the stack address of the basicLock in the markWord of the object. - // Cmpxchg sets flag to cmpd(current_header, box). - cmpxchgd(/*flag=*/flag, - /*current_value=*/current_header, - /*compare_value=*/box, - /*exchange_value=*/displaced_header, - /*where=*/oop, - MacroAssembler::MemBarRel, - MacroAssembler::cmpxchgx_hint_release_lock(), - noreg, - &cont); - - assert(oopDesc::mark_offset_in_bytes() == 0, "offset of _mark is not 0"); + if (!UseHeavyMonitors) { + // Check if it is still a light weight lock, this is is true if we see + // the stack address of the basicLock in the markWord of the object. + // Cmpxchg sets flag to cmpd(current_header, box). + cmpxchgd(/*flag=*/flag, + /*current_value=*/current_header, + /*compare_value=*/box, + /*exchange_value=*/displaced_header, + /*where=*/oop, + MacroAssembler::MemBarRel, + MacroAssembler::cmpxchgx_hint_release_lock(), + noreg, + &cont); + assert(oopDesc::mark_offset_in_bytes() == 0, "offset of _mark is not 0"); + } else { + // Set NE to indicate 'failure' -> take slow-path. + crandc(flag, Assembler::equal, flag, Assembler::equal); + } // Handle existing monitor. b(cont); @@ -2819,11 +2830,16 @@ void MacroAssembler::compiler_fast_unlock_object(ConditionRegister flag, Registe #endif ld(displaced_header, ObjectMonitor::recursions_offset_in_bytes(), current_header); - xorr(temp, R16_thread, temp); // Will be 0 if we are the owner. - orr(temp, temp, displaced_header); // Will be 0 if there are 0 recursions. - cmpdi(flag, temp, 0); + + cmpd(flag, temp, R16_thread); bne(flag, cont); + addic_(displaced_header, displaced_header, -1); + blt(CCR0, notRecursive); // Not recursive if negative after decrement. + std(displaced_header, ObjectMonitor::recursions_offset_in_bytes(), current_header); + b(cont); // flag is already EQ here. + + bind(notRecursive); ld(temp, ObjectMonitor::EntryList_offset_in_bytes(), current_header); ld(displaced_header, ObjectMonitor::cxq_offset_in_bytes(), current_header); orr(temp, temp, displaced_header); // Will be 0 if both are 0. diff --git a/src/hotspot/cpu/ppc/matcher_ppc.hpp b/src/hotspot/cpu/ppc/matcher_ppc.hpp index 877f0be33c4413b644f76aef049c5707d6c0ec04..069c40485fea5adbc64851b83a62dd2a9cca1b50 100644 --- a/src/hotspot/cpu/ppc/matcher_ppc.hpp +++ b/src/hotspot/cpu/ppc/matcher_ppc.hpp @@ -57,9 +57,6 @@ // No support for generic vector operands. static const bool supports_generic_vector_operands = false; - // No support for 48 extra htbl entries in aes-gcm intrinsic - static const int htbl_entries = -1; - static constexpr bool isSimpleConstant64(jlong value) { // Probably always true, even if a temp register is required. return true; @@ -165,6 +162,12 @@ } // Implements a variant of EncodeISOArrayNode that encode ASCII only - static const bool supports_encode_ascii_array = false; + static const bool supports_encode_ascii_array = true; + + // Returns pre-selection estimated cost of a vector operation. + static int vector_op_pre_select_sz_estimate(int vopc, BasicType ety, int vlen) { + return 0; + } + #endif // CPU_PPC_MATCHER_PPC_HPP diff --git a/src/hotspot/cpu/ppc/nativeInst_ppc.hpp b/src/hotspot/cpu/ppc/nativeInst_ppc.hpp index 03b03238b025bdbef7110f7bfc88ace304532e6b..e9cc46e868112e82c505c5029c289b32818c0c3a 100644 --- a/src/hotspot/cpu/ppc/nativeInst_ppc.hpp +++ b/src/hotspot/cpu/ppc/nativeInst_ppc.hpp @@ -257,7 +257,7 @@ class NativeMovConstReg: public NativeInstruction { // Patch the code stream and oop pool. void set_data(intptr_t x); - // Patch narrow oop constants. Use this also for narrow klass. + // Patch narrow oop constants. void set_narrow_oop(narrowOop data, CodeBlob *code = NULL); void verify() NOT_DEBUG_RETURN; diff --git a/src/hotspot/cpu/ppc/ppc.ad b/src/hotspot/cpu/ppc/ppc.ad index 958059e1ca254ad9218d7134b81eb6e517cf7c77..b41c72ab449589687e5e1aed564ab56685f5aef4 100644 --- a/src/hotspot/cpu/ppc/ppc.ad +++ b/src/hotspot/cpu/ppc/ppc.ad @@ -2185,7 +2185,7 @@ const RegMask* Matcher::predicate_reg_mask(void) { return NULL; } -const TypeVect* Matcher::predicate_reg_type(const Type* elemTy, int length) { +const TypeVectMask* Matcher::predicate_reg_type(const Type* elemTy, int length) { return NULL; } @@ -5953,7 +5953,7 @@ instruct loadConN_hi(iRegNdst dst, immN src) %{ format %{ "LIS $dst, $src \t// narrow oop hi" %} size(4); ins_encode %{ - __ lis($dst$$Register, (int)(short)(($src$$constant >> 16) & 0xffff)); + __ lis($dst$$Register, 0); // Will get patched. %} ins_pipe(pipe_class_default); %} @@ -5966,11 +5966,9 @@ instruct loadConN_lo(iRegNdst dst, iRegNsrc src1, immN src2) %{ format %{ "ORI $dst, $src1, $src2 \t// narrow oop lo" %} size(4); ins_encode %{ - assert(__ oop_recorder() != NULL, "this assembler needs an OopRecorder"); - int oop_index = __ oop_recorder()->find_index((jobject)$src2$$constant); - RelocationHolder rspec = oop_Relocation::spec(oop_index); - __ relocate(rspec, 1); - __ ori($dst$$Register, $src1$$Register, $src2$$constant & 0xffff); + AddressLiteral addrlit = __ constant_oop_address((jobject)$src2$$constant); + __ relocate(addrlit.rspec(), /*compressed format*/ 1); + __ ori($dst$$Register, $src1$$Register, 0); // Will get patched. %} ins_pipe(pipe_class_default); %} @@ -6085,12 +6083,9 @@ instruct loadConNKlass_lo(iRegNdst dst, immNKlass_NM src1, iRegNsrc src2) %{ format %{ "ORI $dst, $src1, $src2 \t// narrow klass lo" %} size(4); ins_encode %{ - intptr_t Csrc = CompressedKlassPointers::encode((Klass *)$src1$$constant); - assert(__ oop_recorder() != NULL, "this assembler needs an OopRecorder"); - int klass_index = __ oop_recorder()->find_index((Klass *)$src1$$constant); - RelocationHolder rspec = metadata_Relocation::spec(klass_index); - - __ relocate(rspec, 1); + // Notify OOP recorder (don't need the relocation) + AddressLiteral md = __ constant_metadata_address((Klass*)$src1$$constant); + intptr_t Csrc = CompressedKlassPointers::encode((Klass*)md.value()); __ ori($dst$$Register, $src2$$Register, Csrc & 0xffff); %} ins_pipe(pipe_class_default); @@ -12784,16 +12779,16 @@ instruct string_inflate(Universe dummy, rarg1RegP src, rarg2RegP dst, iRegIsrc l %} // StringCoding.java intrinsics -instruct has_negatives(rarg1RegP ary1, iRegIsrc len, iRegIdst result, iRegLdst tmp1, iRegLdst tmp2, - regCTR ctr, flagsRegCR0 cr0) +instruct count_positives(iRegPsrc ary1, iRegIsrc len, iRegIdst result, iRegLdst tmp1, iRegLdst tmp2, + regCTR ctr, flagsRegCR0 cr0) %{ - match(Set result (HasNegatives ary1 len)); - effect(TEMP_DEF result, USE_KILL ary1, TEMP tmp1, TEMP tmp2, KILL ctr, KILL cr0); + match(Set result (CountPositives ary1 len)); + effect(TEMP_DEF result, TEMP tmp1, TEMP tmp2, KILL ctr, KILL cr0); ins_cost(300); - format %{ "has negatives byte[] $ary1,$len -> $result \t// KILL $tmp1, $tmp2" %} + format %{ "count positives byte[] $ary1,$len -> $result \t// KILL $tmp1, $tmp2" %} ins_encode %{ - __ has_negatives($ary1$$Register, $len$$Register, $result$$Register, - $tmp1$$Register, $tmp2$$Register); + __ count_positives($ary1$$Register, $len$$Register, $result$$Register, + $tmp1$$Register, $tmp2$$Register); %} ins_pipe(pipe_class_default); %} @@ -12806,30 +12801,26 @@ instruct encode_iso_array(rarg1RegP src, rarg2RegP dst, iRegIsrc len, iRegIdst r effect(TEMP_DEF result, TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, TEMP tmp5, USE_KILL src, USE_KILL dst, KILL ctr, KILL cr0); ins_cost(300); - format %{ "Encode array $src,$dst,$len -> $result \t// KILL $tmp1, $tmp2, $tmp3, $tmp4, $tmp5" %} + format %{ "Encode iso array $src,$dst,$len -> $result \t// KILL $tmp1, $tmp2, $tmp3, $tmp4, $tmp5" %} ins_encode %{ - Label Lslow, Lfailure1, Lfailure2, Ldone; - __ string_compress_16($src$$Register, $dst$$Register, $len$$Register, $tmp1$$Register, - $tmp2$$Register, $tmp3$$Register, $tmp4$$Register, $tmp5$$Register, Lfailure1); - __ rldicl_($result$$Register, $len$$Register, 0, 64-3); // Remaining characters. - __ beq(CCR0, Ldone); - __ bind(Lslow); - __ string_compress($src$$Register, $dst$$Register, $result$$Register, $tmp2$$Register, Lfailure2); - __ li($result$$Register, 0); - __ b(Ldone); - - __ bind(Lfailure1); - __ mr($result$$Register, $len$$Register); - __ mfctr($tmp1$$Register); - __ rldimi_($result$$Register, $tmp1$$Register, 3, 0); // Remaining characters. - __ beq(CCR0, Ldone); - __ b(Lslow); - - __ bind(Lfailure2); - __ mfctr($result$$Register); // Remaining characters. + __ encode_iso_array($src$$Register, $dst$$Register, $len$$Register, $tmp1$$Register, $tmp2$$Register, + $tmp3$$Register, $tmp4$$Register, $tmp5$$Register, $result$$Register, false); + %} + ins_pipe(pipe_class_default); +%} - __ bind(Ldone); - __ subf($result$$Register, $result$$Register, $len$$Register); +// encode char[] to byte[] in ASCII +instruct encode_ascii_array(rarg1RegP src, rarg2RegP dst, iRegIsrc len, iRegIdst result, iRegLdst tmp1, + iRegLdst tmp2, iRegLdst tmp3, iRegLdst tmp4, iRegLdst tmp5, regCTR ctr, flagsRegCR0 cr0) %{ + predicate(((EncodeISOArrayNode*)n)->is_ascii()); + match(Set result (EncodeISOArray src (Binary dst len))); + effect(TEMP_DEF result, TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, TEMP tmp5, + USE_KILL src, USE_KILL dst, KILL ctr, KILL cr0); + ins_cost(300); + format %{ "Encode ascii array $src,$dst,$len -> $result \t// KILL $tmp1, $tmp2, $tmp3, $tmp4, $tmp5" %} + ins_encode %{ + __ encode_iso_array($src$$Register, $dst$$Register, $len$$Register, $tmp1$$Register, $tmp2$$Register, + $tmp3$$Register, $tmp4$$Register, $tmp5$$Register, $result$$Register, true); %} ins_pipe(pipe_class_default); %} diff --git a/src/hotspot/cpu/ppc/relocInfo_ppc.cpp b/src/hotspot/cpu/ppc/relocInfo_ppc.cpp index 71ced03459f9e5914223e748f91b37746dae80bf..a3a63c6283faf1f0d554bd4df2056cefcb591192 100644 --- a/src/hotspot/cpu/ppc/relocInfo_ppc.cpp +++ b/src/hotspot/cpu/ppc/relocInfo_ppc.cpp @@ -33,34 +33,15 @@ #include "runtime/safepoint.hpp" void Relocation::pd_set_data_value(address x, intptr_t o, bool verify_only) { - // The following comment is from the declaration of DataRelocation: - // - // "The "o" (displacement) argument is relevant only to split relocations - // on RISC machines. In some CPUs (SPARC), the set-hi and set-lo ins'ns - // can encode more than 32 bits between them. This allows compilers to - // share set-hi instructions between addresses that differ by a small - // offset (e.g., different static variables in the same class). - // On such machines, the "x" argument to set_value on all set-lo - // instructions must be the same as the "x" argument for the - // corresponding set-hi instructions. The "o" arguments for the - // set-hi instructions are ignored, and must not affect the high-half - // immediate constant. The "o" arguments for the set-lo instructions are - // added into the low-half immediate constant, and must not overflow it." - // - // Currently we don't support splitting of relocations, so o must be - // zero: + // Currently we don't support splitting of relocations. assert(o == 0, "tried to split relocations"); if (!verify_only) { if (format() != 1) { nativeMovConstReg_at(addr())->set_data_plain(((intptr_t)x), code()); } else { - assert(type() == relocInfo::oop_type || type() == relocInfo::metadata_type, - "how to encode else?"); - narrowOop no = (type() == relocInfo::oop_type) ? - CompressedOops::encode(cast_to_oop(x)) : - // Type punning compressed klass pointer as narrowOop. - CompressedOops::narrow_oop_cast(CompressedKlassPointers::encode((Klass*)x)); + assert(type() == relocInfo::oop_type, "how to encode else?"); + narrowOop no = CompressedOops::encode(cast_to_oop(x)); nativeMovConstReg_at(addr())->set_narrow_oop(no, code()); } } else { diff --git a/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp b/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp index a834fa1af36f2fc617c29b1fafc939ea1295bc85..315ca3f706282f15b0777cae86a4d4583354eb12 100644 --- a/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp +++ b/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, 2021 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -3216,8 +3216,9 @@ void SharedRuntime::montgomery_multiply(jint *a_ints, jint *b_ints, jint *n_ints // Make very sure we don't use so much space that the stack might // overflow. 512 jints corresponds to an 16384-bit integer and // will use here a total of 8k bytes of stack space. + int divisor = sizeof(unsigned long) * 4; + guarantee(longwords <= 8192 / divisor, "must be"); int total_allocation = longwords * sizeof (unsigned long) * 4; - guarantee(total_allocation <= 8192, "must be"); unsigned long *scratch = (unsigned long *)alloca(total_allocation); // Local scratch arrays @@ -3246,8 +3247,9 @@ void SharedRuntime::montgomery_square(jint *a_ints, jint *n_ints, // Make very sure we don't use so much space that the stack might // overflow. 512 jints corresponds to an 16384-bit integer and // will use here a total of 6k bytes of stack space. + int divisor = sizeof(unsigned long) * 3; + guarantee(longwords <= (8192 / divisor), "must be"); int total_allocation = longwords * sizeof (unsigned long) * 3; - guarantee(total_allocation <= 8192, "must be"); unsigned long *scratch = (unsigned long *)alloca(total_allocation); // Local scratch arrays diff --git a/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp b/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp index 0e68a38dbaf9a453e6ff197e21bb5dd3fb74b9bb..901918f7b37f5684079edac3a085d4f36b923e3c 100644 --- a/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp +++ b/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2021 SAP SE. All rights reserved. + * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -4656,8 +4656,6 @@ class StubGenerator: public StubCodeGenerator { public: StubGenerator(CodeBuffer* code, bool all) : StubCodeGenerator(code) { - // replace the standard masm with a special one: - _masm = new MacroAssembler(code); if (all) { generate_all(); } else { diff --git a/src/hotspot/cpu/ppc/vm_version_ext_ppc.cpp b/src/hotspot/cpu/ppc/vm_version_ext_ppc.cpp deleted file mode 100644 index 8840a762840338cb176361576afef18648814ae7..0000000000000000000000000000000000000000 --- a/src/hotspot/cpu/ppc/vm_version_ext_ppc.cpp +++ /dev/null @@ -1,87 +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. - * - */ - -#include "jvm.h" -#include "memory/allocation.hpp" -#include "memory/allocation.inline.hpp" -#include "runtime/vm_version.hpp" -#include "vm_version_ext_ppc.hpp" - -// VM_Version_Ext statics -int VM_Version_Ext::_no_of_threads = 0; -int VM_Version_Ext::_no_of_cores = 0; -int VM_Version_Ext::_no_of_sockets = 0; -bool VM_Version_Ext::_initialized = false; -char VM_Version_Ext::_cpu_name[CPU_TYPE_DESC_BUF_SIZE] = {0}; -char VM_Version_Ext::_cpu_desc[CPU_DETAILED_DESC_BUF_SIZE] = {0}; - -// get cpu information. -void VM_Version_Ext::initialize_cpu_information(void) { - // do nothing if cpu info has been initialized - if (_initialized) { - return; - } - - _no_of_cores = os::processor_count(); - _no_of_threads = _no_of_cores; - _no_of_sockets = _no_of_cores; - snprintf(_cpu_name, CPU_TYPE_DESC_BUF_SIZE, "PowerPC POWER%lu", PowerArchitecturePPC64); - snprintf(_cpu_desc, CPU_DETAILED_DESC_BUF_SIZE, "PPC %s", features_string()); - _initialized = true; -} - -int VM_Version_Ext::number_of_threads(void) { - initialize_cpu_information(); - return _no_of_threads; -} - -int VM_Version_Ext::number_of_cores(void) { - initialize_cpu_information(); - return _no_of_cores; -} - -int VM_Version_Ext::number_of_sockets(void) { - initialize_cpu_information(); - return _no_of_sockets; -} - -const char* VM_Version_Ext::cpu_name(void) { - initialize_cpu_information(); - char* tmp = NEW_C_HEAP_ARRAY_RETURN_NULL(char, CPU_TYPE_DESC_BUF_SIZE, mtTracing); - if (NULL == tmp) { - return NULL; - } - strncpy(tmp, _cpu_name, CPU_TYPE_DESC_BUF_SIZE); - return tmp; -} - -const char* VM_Version_Ext::cpu_description(void) { - initialize_cpu_information(); - char* tmp = NEW_C_HEAP_ARRAY_RETURN_NULL(char, CPU_DETAILED_DESC_BUF_SIZE, mtTracing); - if (NULL == tmp) { - return NULL; - } - strncpy(tmp, _cpu_desc, CPU_DETAILED_DESC_BUF_SIZE); - return tmp; -} diff --git a/src/hotspot/cpu/ppc/vm_version_ext_ppc.hpp b/src/hotspot/cpu/ppc/vm_version_ext_ppc.hpp deleted file mode 100644 index 36df6f19fd3739523891ce835aff201af87b5f24..0000000000000000000000000000000000000000 --- a/src/hotspot/cpu/ppc/vm_version_ext_ppc.hpp +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2013, 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_PPC_VM_VERSION_EXT_PPC_HPP -#define CPU_PPC_VM_VERSION_EXT_PPC_HPP - -#include "runtime/vm_version.hpp" -#include "utilities/macros.hpp" - -#define CPU_INFO "cpu_info" -#define CPU_TYPE "fpu_type" -#define CPU_DESCRIPTION "implementation" -#define CHIP_ID "chip_id" -#define CORE_ID "core_id" - -class VM_Version_Ext : public VM_Version { - private: - - static const size_t CPU_TYPE_DESC_BUF_SIZE = 256; - static const size_t CPU_DETAILED_DESC_BUF_SIZE = 4096; - - static int _no_of_threads; - static int _no_of_cores; - static int _no_of_sockets; - static bool _initialized; - static char _cpu_name[CPU_TYPE_DESC_BUF_SIZE]; - static char _cpu_desc[CPU_DETAILED_DESC_BUF_SIZE]; - - static void initialize_cpu_information(void); - - public: - - static int number_of_threads(void); - static int number_of_cores(void); - static int number_of_sockets(void); - - static const char* cpu_name(void); - static const char* cpu_description(void); -}; - -#endif // CPU_PPC_VM_VERSION_EXT_PPC_HPP diff --git a/src/hotspot/cpu/ppc/vm_version_ppc.cpp b/src/hotspot/cpu/ppc/vm_version_ppc.cpp index 0b2aa63bceadcd833d1d992d53ceceba323ad683..e8138643a1f1a442ee7ecc0552d19b125c1cd8ed 100644 --- a/src/hotspot/cpu/ppc/vm_version_ppc.cpp +++ b/src/hotspot/cpu/ppc/vm_version_ppc.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, 2020 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -435,7 +435,7 @@ void VM_Version::check_virtualizations() { // system_type=...qemu indicates PowerKVM // e.g. system_type=IBM pSeries (emulated by qemu) char line[500]; - FILE* fp = fopen(info_file, "r"); + FILE* fp = os::fopen(info_file, "r"); if (fp == NULL) { return; } @@ -767,3 +767,18 @@ void VM_Version::allow_all() { void VM_Version::revert() { _features = saved_features; } + +// get cpu information. +void VM_Version::initialize_cpu_information(void) { + // do nothing if cpu info has been initialized + if (_initialized) { + return; + } + + _no_of_cores = os::processor_count(); + _no_of_threads = _no_of_cores; + _no_of_sockets = _no_of_cores; + snprintf(_cpu_name, CPU_TYPE_DESC_BUF_SIZE, "PowerPC POWER%lu", PowerArchitecturePPC64); + snprintf(_cpu_desc, CPU_DETAILED_DESC_BUF_SIZE, "PPC %s", features_string()); + _initialized = true; +} diff --git a/src/hotspot/cpu/ppc/vm_version_ppc.hpp b/src/hotspot/cpu/ppc/vm_version_ppc.hpp index 89352192615c53b082d94802832ce213f35eeb3b..0a9d5ce081045d5e61aa91ded0457283640e85fd 100644 --- a/src/hotspot/cpu/ppc/vm_version_ppc.hpp +++ b/src/hotspot/cpu/ppc/vm_version_ppc.hpp @@ -128,6 +128,8 @@ public: // POWER 8: DSCR current value. static uint64_t _dscr_val; + + static void initialize_cpu_information(void); }; #endif // CPU_PPC_VM_VERSION_PPC_HPP diff --git a/src/hotspot/cpu/s390/bytes_s390.hpp b/src/hotspot/cpu/s390/bytes_s390.hpp index f6882f980abface44aed4169f259389bdce1b1e6..9b4d7b0422148e1a71efe21d4a02176bc25d8cd4 100644 --- a/src/hotspot/cpu/s390/bytes_s390.hpp +++ b/src/hotspot/cpu/s390/bytes_s390.hpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2016, 2018 SAP SE. All rights reserved. + * Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 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 @@ -26,7 +26,7 @@ #ifndef CPU_S390_BYTES_S390_HPP #define CPU_S390_BYTES_S390_HPP -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" class Bytes: AllStatic { public: diff --git a/src/hotspot/cpu/s390/c1_LIRAssembler_s390.cpp b/src/hotspot/cpu/s390/c1_LIRAssembler_s390.cpp index 6971490e0681cacf8ae196ae7079ad3bbd5328da..1d1f163826e243de60c85a19890b5191a1140bee 100644 --- a/src/hotspot/cpu/s390/c1_LIRAssembler_s390.cpp +++ b/src/hotspot/cpu/s390/c1_LIRAssembler_s390.cpp @@ -950,12 +950,7 @@ void LIR_Assembler::mem2reg(LIR_Opr src_opr, LIR_Opr dest, BasicType type, LIR_P } break; case T_ADDRESS: - if (UseCompressedClassPointers && addr->disp() == oopDesc::klass_offset_in_bytes()) { - __ z_llgf(dest->as_register(), disp_value, disp_reg, src); - __ decode_klass_not_null(dest->as_register()); - } else { - __ z_lg(dest->as_register(), disp_value, disp_reg, src); - } + __ z_lg(dest->as_register(), disp_value, disp_reg, src); break; case T_ARRAY : // fall through case T_OBJECT: @@ -2735,7 +2730,7 @@ void LIR_Assembler::emit_lock(LIR_OpLock* op) { Register obj = op->obj_opr()->as_register(); // May not be an oop. Register hdr = op->hdr_opr()->as_register(); Register lock = op->lock_opr()->as_register(); - if (!UseFastLocking) { + if (UseHeavyMonitors) { __ branch_optimized(Assembler::bcondAlways, *op->stub()->entry()); } else if (op->code() == lir_lock) { assert(BasicLock::displaced_header_offset_in_bytes() == 0, "lock_reg must point to the displaced header"); @@ -2754,6 +2749,22 @@ void LIR_Assembler::emit_lock(LIR_OpLock* op) { __ bind(*op->stub()->continuation()); } +void LIR_Assembler::emit_load_klass(LIR_OpLoadKlass* op) { + Register obj = op->obj()->as_pointer_register(); + Register result = op->result_opr()->as_pointer_register(); + + CodeEmitInfo* info = op->info(); + if (info != NULL) { + add_debug_info_for_null_check_here(info); + } + + if (UseCompressedClassPointers) { + __ z_llgf(result, Address(obj, oopDesc::klass_offset_in_bytes())); + __ decode_klass_not_null(result); + } else { + __ z_lg(result, Address(obj, oopDesc::klass_offset_in_bytes())); + } +} void LIR_Assembler::emit_profile_call(LIR_OpProfileCall* op) { ciMethod* method = op->profiled_method(); int bci = op->profiled_bci(); diff --git a/src/hotspot/cpu/s390/c1_LIR_s390.cpp b/src/hotspot/cpu/s390/c1_LIR_s390.cpp index 3c46915e47538109e844821879613a1f0453c6cc..4788a398de8ab6a5af956aaf0158e7fac7b05f69 100644 --- a/src/hotspot/cpu/s390/c1_LIR_s390.cpp +++ b/src/hotspot/cpu/s390/c1_LIR_s390.cpp @@ -29,22 +29,22 @@ #include "c1/c1_LIR.hpp" -FloatRegister LIR_OprDesc::as_float_reg() const { +FloatRegister LIR_Opr::as_float_reg() const { return FrameMap::nr2floatreg(fpu_regnr()); } -FloatRegister LIR_OprDesc::as_double_reg() const { +FloatRegister LIR_Opr::as_double_reg() const { return FrameMap::nr2floatreg(fpu_regnrHi()); } // Reg2 unused. LIR_Opr LIR_OprFact::double_fpu(int reg1, int reg2) { assert(!as_FloatRegister(reg2)->is_valid(), "Not used on this platform"); - return (LIR_Opr)(intptr_t)((reg1 << LIR_OprDesc::reg1_shift) | - (reg1 << LIR_OprDesc::reg2_shift) | - LIR_OprDesc::double_type | - LIR_OprDesc::fpu_register | - LIR_OprDesc::double_size); + return (LIR_Opr)(intptr_t)((reg1 << LIR_Opr::reg1_shift) | + (reg1 << LIR_Opr::reg2_shift) | + LIR_Opr::double_type | + LIR_Opr::fpu_register | + LIR_Opr::double_size); } #ifndef PRODUCT diff --git a/src/hotspot/cpu/s390/c1_MacroAssembler_s390.cpp b/src/hotspot/cpu/s390/c1_MacroAssembler_s390.cpp index aaad1575a82a345e23ff33b528f1e90178b51711..5eac4ae149b34756351005d43fc81f56071e6023 100644 --- a/src/hotspot/cpu/s390/c1_MacroAssembler_s390.cpp +++ b/src/hotspot/cpu/s390/c1_MacroAssembler_s390.cpp @@ -73,8 +73,8 @@ void C1_MacroAssembler::build_frame(int frame_size_in_bytes, int bang_size_in_by push_frame(frame_size_in_bytes); } -void C1_MacroAssembler::verified_entry() { - if (C1Breakpoint) z_illtrap(0xC1); +void C1_MacroAssembler::verified_entry(bool breakAtEntry) { + if (breakAtEntry) z_illtrap(0xC1); } void C1_MacroAssembler::lock_object(Register hdr, Register obj, Register disp_hdr, Label& slow_case) { diff --git a/src/hotspot/cpu/s390/c2_MacroAssembler_s390.cpp b/src/hotspot/cpu/s390/c2_MacroAssembler_s390.cpp index 83040fb6b7f41a0a88a09459f7a93b5443fada2d..6fac285f738ace567bf016f244d59e68031db260 100644 --- a/src/hotspot/cpu/s390/c2_MacroAssembler_s390.cpp +++ b/src/hotspot/cpu/s390/c2_MacroAssembler_s390.cpp @@ -1,5 +1,6 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 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 @@ -46,22 +47,44 @@ // Note: // cnt is signed int. Do not rely on high word! // counts # characters, not bytes. -// The result is the number of characters copied before the first incompatible character was found. -// If precise is true, the processing stops exactly at this point. Otherwise, the result may be off -// by a few bytes. The result always indicates the number of copied characters. -// When used as a character index, the returned value points to the first incompatible character. // -// Note: Does not behave exactly like package private StringUTF16 compress java implementation in case of failure: -// - Different number of characters may have been written to dead array (if precise is false). -// - Returns a number --- - // Strings with 4 and 8 characters were fond to occur very frequently. + // Strings with 4 and 8 characters were found to occur very frequently. // Therefore, we handle them right away with minimal overhead. Label skipShortcut, skip4Shortcut, skip8Shortcut; Register Rout = Z_R0; @@ -133,7 +156,8 @@ unsigned int C2_MacroAssembler::string_compress(Register result, Register src, R if (VM_Version::has_VectorFacility()) { const int min_vcnt = 32; // Minimum #characters required to use vector instructions. // Otherwise just do nothing in vector mode. - // Must be multiple of 2*(vector register length in chars (8 HW = 128 bits)). + // Must correspond to # vector registers used by implementation, + // and must be a power of 2. const int log_min_vcnt = exact_log2(min_vcnt); Label VectorLoop, VectorDone, VectorBreak; @@ -150,7 +174,7 @@ unsigned int C2_MacroAssembler::string_compress(Register result, Register src, R z_brz(VectorDone); // not enough data for vector loop z_vzero(Vzero); // all zeroes - z_vgmh(Vmask, 0, 7); // generate 0xff00 mask for all 2-byte elements + z_vgmh(Vmask, mask_ix_l, mask_ix_r); // generate 0xff00/0xff80 mask for all 2-byte elements z_sllg(Z_R0, Rix, log_min_vcnt); // remember #chars that will be processed by vector loop bind(VectorLoop); @@ -162,7 +186,7 @@ unsigned int C2_MacroAssembler::string_compress(Register result, Register src, R z_vo(Vtmp2, Z_V22, Z_V23); z_vo(Vtmp1, Vtmp1, Vtmp2); z_vn(Vtmp1, Vtmp1, Vmask); - z_vceqhs(Vtmp1, Vtmp1, Vzero); // high half of all chars must be zero for successful compress. + z_vceqhs(Vtmp1, Vtmp1, Vzero); // all bits selected by mask must be zero for successful compress. z_bvnt(VectorBreak); // break vector loop if not all vector elements compare eq -> incompatible character found. // re-process data from current iteration in break handler. @@ -187,7 +211,8 @@ unsigned int C2_MacroAssembler::string_compress(Register result, Register src, R { const int min_cnt = 8; // Minimum #characters required to use unrolled loop. // Otherwise just do nothing in unrolled loop. - // Must be multiple of 8. + // Must correspond to # registers used by implementation, + // and must be a power of 2. const int log_min_cnt = exact_log2(min_cnt); Label UnrolledLoop, UnrolledDone, UnrolledBreak; @@ -197,7 +222,7 @@ unsigned int C2_MacroAssembler::string_compress(Register result, Register src, R z_lr(Rix, Rcnt); z_sr(Rix, Z_R0); } - z_sra(Rix, log_min_cnt); // unrolled loop count + z_sra(Rix, log_min_cnt); // unrolled loop count z_brz(UnrolledDone); bind(UnrolledLoop); @@ -244,6 +269,8 @@ unsigned int C2_MacroAssembler::string_compress(Register result, Register src, R z_sll(Rix, log_min_cnt); // # chars not yet processed in UnrolledLoop (due to break), broken iteration not included. z_sr(Z_R0, Rix); // fix # chars processed OK so far. if (!precise) { + // Because we don't need to be precise, we just return the # of characters which have been written. + // The first illegal character is in the index range [result-min_cnt/2, result+min_cnt/2). z_lgfr(result, Z_R0); z_sllg(Z_R1, Z_R0, 1); // # src bytes already processed. Only lower 32 bits are valid! // Z_R1 contents must be treated as unsigned operand! For huge strings, @@ -274,7 +301,7 @@ unsigned int C2_MacroAssembler::string_compress(Register result, Register src, R z_brh(ScalarDoit); z_llh(Z_R1, 0, Z_R0, Rsrc); z_bre(Scalar2Char); - z_tmll(Z_R1, 0xff00); + z_tmll(Z_R1, char_mask); z_lghi(result, 0); // cnt == 1, first char invalid, no chars successfully processed z_brnaz(AllDone); z_stc(Z_R1, 0, Z_R0, Rdst); @@ -283,11 +310,11 @@ unsigned int C2_MacroAssembler::string_compress(Register result, Register src, R bind(Scalar2Char); z_llh(Z_R0, 2, Z_R0, Rsrc); - z_tmll(Z_R1, 0xff00); + z_tmll(Z_R1, char_mask); z_lghi(result, 0); // cnt == 2, first char invalid, no chars successfully processed z_brnaz(AllDone); z_stc(Z_R1, 0, Z_R0, Rdst); - z_tmll(Z_R0, 0xff00); + z_tmll(Z_R0, char_mask); z_lghi(result, 1); // cnt == 2, second char invalid, one char successfully processed z_brnaz(AllDone); z_stc(Z_R0, 1, Z_R0, Rdst); @@ -299,17 +326,17 @@ unsigned int C2_MacroAssembler::string_compress(Register result, Register src, R #endif if (VM_Version::has_DistinctOpnds()) { - z_srk(Rix, Rcnt, Z_R0); // remaining # chars to compress in unrolled loop + z_srk(Rix, Rcnt, Z_R0); // remaining # chars to compress in scalar loop } else { z_lr(Rix, Rcnt); z_sr(Rix, Z_R0); } - z_lgfr(result, Rcnt); // # processed characters (if all runs ok). - z_brz(ScalarDone); // uses CC from Rix calculation + z_lgfr(result, Rcnt); // # processed characters (if all encodes ok). + z_brz(ScalarDone); // anything left to do? (uses CC from Rix calculation) bind(ScalarLoop); z_llh(Z_R1, 0, Z_R0, Rsrc); - z_tmll(Z_R1, 0xff00); + z_tmll(Z_R1, char_mask); z_brnaz(ScalarBreak); z_stc(Z_R1, 0, Z_R0, Rdst); add2reg(Rsrc, 2); @@ -329,7 +356,11 @@ unsigned int C2_MacroAssembler::string_compress(Register result, Register src, R bind(AllDone); if (precise) { - BLOCK_COMMENT("} encode_iso_array"); + if (toASCII) { + BLOCK_COMMENT("} encode_ascii_array"); + } else { + BLOCK_COMMENT("} encode_iso_array"); + } } else { BLOCK_COMMENT("} string_compress"); } @@ -792,52 +823,64 @@ unsigned int C2_MacroAssembler::string_inflate_const(Register src, Register dst, return offset() - block_start; } -// Kills src. -unsigned int C2_MacroAssembler::has_negatives(Register result, Register src, Register cnt, - Register odd_reg, Register even_reg, Register tmp) { - int block_start = offset(); - Label Lloop1, Lloop2, Lslow, Lnotfound, Ldone; - const Register addr = src, mask = tmp; - - BLOCK_COMMENT("has_negatives {"); - - z_llgfr(Z_R1, cnt); // Number of bytes to read. (Must be a positive simm32.) - z_llilf(mask, 0x80808080); - z_lhi(result, 1); // Assume true. - // Last possible addr for fast loop. - z_lay(odd_reg, -16, Z_R1, src); - z_chi(cnt, 16); - z_brl(Lslow); - - // ind1: index, even_reg: index increment, odd_reg: index limit - z_iihf(mask, 0x80808080); - z_lghi(even_reg, 16); - - bind(Lloop1); // 16 bytes per iteration. - z_lg(Z_R0, Address(addr)); - z_lg(Z_R1, Address(addr, 8)); - z_ogr(Z_R0, Z_R1); - z_ngr(Z_R0, mask); - z_brne(Ldone); // If found return 1. - z_brxlg(addr, even_reg, Lloop1); - - bind(Lslow); - z_aghi(odd_reg, 16-1); // Last possible addr for slow loop. - z_lghi(even_reg, 1); - z_cgr(addr, odd_reg); - z_brh(Lnotfound); - - bind(Lloop2); // 1 byte per iteration. - z_cli(Address(addr), 0x80); - z_brnl(Ldone); // If found return 1. - z_brxlg(addr, even_reg, Lloop2); - - bind(Lnotfound); - z_lhi(result, 0); - - bind(Ldone); - - BLOCK_COMMENT("} has_negatives"); +// Returns the number of non-negative bytes (aka US-ASCII characters) found +// before the first negative byte is encountered. +unsigned int C2_MacroAssembler::count_positives(Register result, Register src, Register cnt, Register tmp) { + const unsigned int block_start = offset(); + const unsigned int byte_mask = 0x80; + const unsigned int twobyte_mask = byte_mask<<8 | byte_mask; + const unsigned int unroll_factor = 16; + const unsigned int log_unroll_factor = exact_log2(unroll_factor); + Register pos = src; // current position in src array, restored at end + Register ctr = result; // loop counter, result value + Register mask = tmp; // holds the sign detection mask + Label unrolledLoop, unrolledDone, byteLoop, allDone; + + assert_different_registers(result, src, cnt, tmp); + + BLOCK_COMMENT("count_positives {"); + + lgr_if_needed(pos, src); // current position in src array + z_srak(ctr, cnt, log_unroll_factor); // # iterations of unrolled loop + z_brnh(unrolledDone); // array too short for unrolled loop + + z_iilf(mask, twobyte_mask<<16 | twobyte_mask); + z_iihf(mask, twobyte_mask<<16 | twobyte_mask); + + bind(unrolledLoop); + z_lmg(Z_R0, Z_R1, 0, pos); + z_ogr(Z_R0, Z_R1); + z_ngr(Z_R0, mask); + z_brne(unrolledDone); // There is a negative byte somewhere. + // ctr and pos are not updated yet -> + // delegate finding correct pos to byteLoop. + add2reg(pos, unroll_factor); + z_brct(ctr, unrolledLoop); + + // Once we arrive here, we have to examine at most (unroll_factor - 1) bytes more. + // We then either have reached the end of the array or we hit a negative byte. + bind(unrolledDone); + z_sll(ctr, log_unroll_factor); // calculate # bytes not processed by unrolled loop + // > 0 only if a negative byte was found + z_lr(Z_R0, cnt); // calculate remainder bytes + z_nilf(Z_R0, unroll_factor - 1); + z_ar(ctr, Z_R0); // remaining bytes + z_brnh(allDone); // shortcut if nothing left to do + + bind(byteLoop); + z_cli(0, pos, byte_mask); // unsigned comparison! byte@pos must be smaller that byte_mask + z_brnl(allDone); // negative byte found. + + add2reg(pos, 1); + z_brct(ctr, byteLoop); + + bind(allDone); + + z_srk(ctr, cnt, ctr); // # bytes actually processed (= cnt or index of first negative byte) + z_sgfr(pos, ctr); // restore src + z_lgfr(result, ctr); // unnecessary. Only there to be sure the high word has a defined state. + + BLOCK_COMMENT("} count_positives"); return offset() - block_start; } diff --git a/src/hotspot/cpu/s390/c2_MacroAssembler_s390.hpp b/src/hotspot/cpu/s390/c2_MacroAssembler_s390.hpp index 08112a482d05cd4618d3504e5fc31adce444c402..a502e41ee08ee12ca3f4af48dbfe7b37a59a5b4f 100644 --- a/src/hotspot/cpu/s390/c2_MacroAssembler_s390.hpp +++ b/src/hotspot/cpu/s390/c2_MacroAssembler_s390.hpp @@ -1,5 +1,6 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 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 @@ -38,7 +39,7 @@ // Early clobber: result. // Boolean precise controls accuracy of result value. unsigned int string_compress(Register result, Register src, Register dst, Register cnt, - Register tmp, bool precise); + Register tmp, bool precise, bool toASCII); // Inflate byte[] to char[]. unsigned int string_inflate_trot(Register src, Register dst, Register cnt, Register tmp); @@ -56,9 +57,7 @@ // len is signed int. Counts # characters, not bytes. unsigned int string_inflate_const(Register src, Register dst, Register tmp, int len); - // Kills src. - unsigned int has_negatives(Register result, Register src, Register cnt, - Register odd_reg, Register even_reg, Register tmp); + unsigned int count_positives(Register result, Register src, Register cnt, Register tmp); unsigned int string_compare(Register str1, Register str2, Register cnt1, Register cnt2, Register odd_reg, Register even_reg, Register result, int ae); diff --git a/src/hotspot/cpu/s390/frame_s390.cpp b/src/hotspot/cpu/s390/frame_s390.cpp index d29227bb32effd34af833a9dbbd128fee57ac2eb..3588915f79d867490215b9f66b631d1a5b501dca 100644 --- a/src/hotspot/cpu/s390/frame_s390.cpp +++ b/src/hotspot/cpu/s390/frame_s390.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2016, 2019 SAP SE. All rights reserved. + * Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 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 @@ -117,8 +117,8 @@ bool frame::safe_for_sender(JavaThread *thread) { return false; } - z_abi_160* sender_abi = (z_abi_160*) fp; - intptr_t* sender_sp = (intptr_t*) sender_abi->callers_sp; + z_abi_16* sender_abi = (z_abi_16*)fp; + intptr_t* sender_sp = (intptr_t*) fp; address sender_pc = (address) sender_abi->return_pc; // We must always be able to find a recognizable pc. @@ -142,7 +142,7 @@ bool frame::safe_for_sender(JavaThread *thread) { // sender_fp must be within the stack and above (but not // equal) current frame's fp. if (!thread->is_in_stack_range_excl(sender_fp, fp)) { - return false; + return false; } // If the potential sender is the interpreter then we can do some more checking. @@ -298,9 +298,55 @@ void frame::patch_pc(Thread* thread, address pc) { } bool frame::is_interpreted_frame_valid(JavaThread* thread) const { - // Is there anything to do? assert(is_interpreted_frame(), "Not an interpreted frame"); - return true; + // These are reasonable sanity checks + if (fp() == 0 || (intptr_t(fp()) & (wordSize-1)) != 0) { + return false; + } + if (sp() == 0 || (intptr_t(sp()) & (wordSize-1)) != 0) { + return false; + } + int min_frame_slots = (z_abi_16_size + z_ijava_state_size) / sizeof(intptr_t); + if (fp() - min_frame_slots < sp()) { + return false; + } + // These are hacks to keep us out of trouble. + // The problem with these is that they mask other problems + if (fp() <= sp()) { // this attempts to deal with unsigned comparison above + return false; + } + + // do some validation of frame elements + + // first the method + // Need to use "unchecked" versions to avoid "z_istate_magic_number" assertion. + Method* m = (Method*)(ijava_state_unchecked()->method); + + // validate the method we'd find in this potential sender + if (!Method::is_valid_method(m)) return false; + + // stack frames shouldn't be much larger than max_stack elements + // this test requires the use of unextended_sp which is the sp as seen by + // the current frame, and not sp which is the "raw" pc which could point + // further because of local variables of the callee method inserted after + // method arguments + if (fp() - unextended_sp() > 1024 + m->max_stack()*Interpreter::stackElementSize) { + return false; + } + + // validate bci/bcx + address bcp = (address)(ijava_state_unchecked()->bcp); + if (m->validate_bci_from_bcp(bcp) < 0) { + return false; + } + + // validate constantPoolCache* + ConstantPoolCache* cp = (ConstantPoolCache*)(ijava_state_unchecked()->cpoolCache); + if (MetaspaceObj::is_valid(cp) == false) return false; + + // validate locals + address locals = (address)(ijava_state_unchecked()->locals); + return thread->is_in_stack_range_incl(locals, (address)fp()); } BasicType frame::interpreter_frame_result(oop* oop_result, jvalue* value_result) { diff --git a/src/hotspot/cpu/s390/frame_s390.inline.hpp b/src/hotspot/cpu/s390/frame_s390.inline.hpp index d8a4395d8cad82800bda84422c6621b6c339c3f3..5574e6384e2218d99dfc7d26a6b6f303e193230c 100644 --- a/src/hotspot/cpu/s390/frame_s390.inline.hpp +++ b/src/hotspot/cpu/s390/frame_s390.inline.hpp @@ -155,6 +155,10 @@ inline intptr_t* frame::link() const { return (intptr_t*) callers_abi()->callers_sp; } +inline intptr_t* frame::link_or_null() const { + return link(); +} + inline intptr_t** frame::interpreter_frame_locals_addr() const { return (intptr_t**) &(ijava_state()->locals); } diff --git a/src/hotspot/cpu/s390/gc/g1/g1BarrierSetAssembler_s390.cpp b/src/hotspot/cpu/s390/gc/g1/g1BarrierSetAssembler_s390.cpp index 7258630bb0b9d30dfbd4691d675ddd7c27449733..b6e3d9eb2c7b5ab59ed1a4a3a95356a2b8edac76 100644 --- a/src/hotspot/cpu/s390/gc/g1/g1BarrierSetAssembler_s390.cpp +++ b/src/hotspot/cpu/s390/gc/g1/g1BarrierSetAssembler_s390.cpp @@ -305,7 +305,7 @@ void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm, Decorato // calculate address of card __ load_const_optimized(Rbase, (address)ct->card_table()->byte_map_base()); // Card table base. - __ z_srlg(Rcard_addr, Rstore_addr, CardTable::card_shift); // Index into card table. + __ z_srlg(Rcard_addr, Rstore_addr, CardTable::card_shift()); // Index into card table. __ z_algr(Rcard_addr, Rbase); // Explicit calculation needed for cli. Rbase = noreg; // end of lifetime @@ -548,7 +548,7 @@ void G1BarrierSetAssembler::generate_c1_post_barrier_runtime_stub(StubAssembler* // Calculate address of card corresponding to the updated oop slot. AddressLiteral rs(byte_map_base); - __ z_srlg(addr_card, addr_oop, CardTable::card_shift); + __ z_srlg(addr_card, addr_oop, CardTable::card_shift()); addr_oop = noreg; // dead now __ load_const_optimized(cardtable, rs); // cardtable := __ z_agr(addr_card, cardtable); // addr_card := addr_oop>>card_shift + cardtable diff --git a/src/hotspot/cpu/s390/gc/shared/cardTableBarrierSetAssembler_s390.cpp b/src/hotspot/cpu/s390/gc/shared/cardTableBarrierSetAssembler_s390.cpp index d3f7bafd33ea3a82a2a0857e6605cecefffb79a9..0124868e46a6fe0b9b49115c146d646b56f59011 100644 --- a/src/hotspot/cpu/s390/gc/shared/cardTableBarrierSetAssembler_s390.cpp +++ b/src/hotspot/cpu/s390/gc/shared/cardTableBarrierSetAssembler_s390.cpp @@ -70,8 +70,8 @@ void CardTableBarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembl __ load_const_optimized(Z_R1, (address)ct->byte_map_base()); // count = (count>>shift) - (addr>>shift) - __ z_srlg(addr, addr, CardTable::card_shift); - __ z_srlg(count, count, CardTable::card_shift); + __ z_srlg(addr, addr, CardTable::card_shift()); + __ z_srlg(count, count, CardTable::card_shift()); // Prefetch first elements of card table for update. if (VM_Version::has_Prefetch()) { @@ -146,7 +146,7 @@ void CardTableBarrierSetAssembler::store_check(MacroAssembler* masm, Register st assert_different_registers(store_addr, tmp); - __ z_srlg(store_addr, store_addr, CardTable::card_shift); + __ z_srlg(store_addr, store_addr, CardTable::card_shift()); __ load_absolute_address(tmp, (address)ct->byte_map_base()); __ z_agr(store_addr, tmp); __ z_mvi(0, store_addr, CardTable::dirty_card_val()); diff --git a/src/hotspot/cpu/s390/jniTypes_s390.hpp b/src/hotspot/cpu/s390/jniTypes_s390.hpp index 56f4a05c6d4bfb5bbc0775f80b6e48279f51f898..951e7f5f6d28e8a9de2df73038bbb1465f14bb6a 100644 --- a/src/hotspot/cpu/s390/jniTypes_s390.hpp +++ b/src/hotspot/cpu/s390/jniTypes_s390.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2016 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -30,7 +30,7 @@ // jni types to the array of arguments passed into JavaCalls::call. #include "jni.h" -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" #include "oops/oop.hpp" class JNITypes : AllStatic { diff --git a/src/hotspot/cpu/s390/matcher_s390.hpp b/src/hotspot/cpu/s390/matcher_s390.hpp index 09cb819a6414ab29b5f1a8c540767858ed27603a..5c56ec5373b7d751e98c614ac6c3b192eb34fecd 100644 --- a/src/hotspot/cpu/s390/matcher_s390.hpp +++ b/src/hotspot/cpu/s390/matcher_s390.hpp @@ -1,5 +1,6 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 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 @@ -57,9 +58,6 @@ // No support for generic vector operands. static const bool supports_generic_vector_operands = false; - // No support for 48 extra htbl entries in aes-gcm intrinsic - static const int htbl_entries = -1; - static constexpr bool isSimpleConstant64(jlong value) { // Probably always true, even if a temp register is required. return true; @@ -153,6 +151,11 @@ } // Implements a variant of EncodeISOArrayNode that encode ASCII only - static const bool supports_encode_ascii_array = false; + static const bool supports_encode_ascii_array = true; + + // Returns pre-selection estimated cost of a vector operation. + static int vector_op_pre_select_sz_estimate(int vopc, BasicType ety, int vlen) { + return 0; + } #endif // CPU_S390_MATCHER_S390_HPP diff --git a/src/hotspot/cpu/s390/s390.ad b/src/hotspot/cpu/s390/s390.ad index 60c27c61a514c4cdcb190b661dab10f4d27e4b5c..d13afd1c8b4f95db6904005ef5af208dacfde00a 100644 --- a/src/hotspot/cpu/s390/s390.ad +++ b/src/hotspot/cpu/s390/s390.ad @@ -1,6 +1,6 @@ // -// Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. -// Copyright (c) 2017, 2020 SAP SE. All rights reserved. +// Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. +// Copyright (c) 2017, 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 @@ -1544,7 +1544,7 @@ const RegMask* Matcher::predicate_reg_mask(void) { return NULL; } -const TypeVect* Matcher::predicate_reg_type(const Type* elemTy, int length) { +const TypeVectMask* Matcher::predicate_reg_type(const Type* elemTy, int length) { return NULL; } @@ -10230,7 +10230,7 @@ instruct string_compress(iRegP src, iRegP dst, iRegI result, iRegI len, iRegI tm format %{ "String Compress $src->$dst($len) -> $result" %} ins_encode %{ __ string_compress($result$$Register, $src$$Register, $dst$$Register, $len$$Register, - $tmp$$Register, false); + $tmp$$Register, false, false); %} ins_pipe(pipe_class_dummy); %} @@ -10273,14 +10273,13 @@ instruct string_inflate_const(Universe dummy, iRegP src, iRegP dst, iRegI tmp, i %} // StringCoding.java intrinsics -instruct has_negatives(rarg5RegP ary1, iRegI len, iRegI result, roddRegI oddReg, revenRegI evenReg, iRegI tmp, flagsReg cr) %{ - match(Set result (HasNegatives ary1 len)); - effect(TEMP_DEF result, USE_KILL ary1, TEMP oddReg, TEMP evenReg, TEMP tmp, KILL cr); // R0, R1 are killed, too. +instruct count_positives(iRegP ary1, iRegI len, iRegI result, iRegI tmp, flagsReg cr) %{ + match(Set result (CountPositives ary1 len)); + effect(TEMP_DEF result, TEMP tmp, KILL cr); // R0, R1 are killed, too. ins_cost(300); - format %{ "has negatives byte[] $ary1($len) -> $result" %} + format %{ "count positives byte[] $ary1($len) -> $result" %} ins_encode %{ - __ has_negatives($result$$Register, $ary1$$Register, $len$$Register, - $oddReg$$Register, $evenReg$$Register, $tmp$$Register); + __ count_positives($result$$Register, $ary1$$Register, $len$$Register, $tmp$$Register); %} ins_pipe(pipe_class_dummy); %} @@ -10291,10 +10290,24 @@ instruct encode_iso_array(iRegP src, iRegP dst, iRegI result, iRegI len, iRegI t match(Set result (EncodeISOArray src (Binary dst len))); effect(TEMP_DEF result, TEMP tmp, KILL cr); // R0, R1 are killed, too. ins_cost(300); - format %{ "Encode array $src->$dst($len) -> $result" %} + format %{ "Encode iso array $src->$dst($len) -> $result" %} + ins_encode %{ + __ string_compress($result$$Register, $src$$Register, $dst$$Register, $len$$Register, + $tmp$$Register, true, false); + %} + ins_pipe(pipe_class_dummy); +%} + +// encode char[] to byte[] in ASCII +instruct encode_ascii_array(iRegP src, iRegP dst, iRegI result, iRegI len, iRegI tmp, flagsReg cr) %{ + predicate(((EncodeISOArrayNode*)n)->is_ascii()); + match(Set result (EncodeISOArray src (Binary dst len))); + effect(TEMP_DEF result, TEMP tmp, KILL cr); // R0, R1 are killed, too. + ins_cost(300); + format %{ "Encode ascii array $src->$dst($len) -> $result" %} ins_encode %{ __ string_compress($result$$Register, $src$$Register, $dst$$Register, $len$$Register, - $tmp$$Register, true); + $tmp$$Register, true, true); %} ins_pipe(pipe_class_dummy); %} diff --git a/src/hotspot/cpu/s390/sharedRuntime_s390.cpp b/src/hotspot/cpu/s390/sharedRuntime_s390.cpp index 2b310f6e44f75921f50ac022201587ca855096e5..107ec979ffd22df2e82c7b97489128308b639b46 100644 --- a/src/hotspot/cpu/s390/sharedRuntime_s390.cpp +++ b/src/hotspot/cpu/s390/sharedRuntime_s390.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2016, 2019 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -3219,8 +3219,9 @@ void SharedRuntime::montgomery_multiply(jint *a_ints, jint *b_ints, jint *n_ints // Make very sure we don't use so much space that the stack might // overflow. 512 jints corresponds to an 16384-bit integer and // will use here a total of 8k bytes of stack space. + int divisor = sizeof(unsigned long) * 4; + guarantee(longwords <= 8192 / divisor, "must be"); int total_allocation = longwords * sizeof (unsigned long) * 4; - guarantee(total_allocation <= 8192, "must be"); unsigned long *scratch = (unsigned long *)alloca(total_allocation); // Local scratch arrays @@ -3249,8 +3250,9 @@ void SharedRuntime::montgomery_square(jint *a_ints, jint *n_ints, // Make very sure we don't use so much space that the stack might // overflow. 512 jints corresponds to an 16384-bit integer and // will use here a total of 6k bytes of stack space. + int divisor = sizeof(unsigned long) * 3; + guarantee(longwords <= (8192 / divisor), "must be"); int total_allocation = longwords * sizeof (unsigned long) * 3; - guarantee(total_allocation <= 8192, "must be"); unsigned long *scratch = (unsigned long *)alloca(total_allocation); // Local scratch arrays diff --git a/src/hotspot/cpu/s390/stubGenerator_s390.cpp b/src/hotspot/cpu/s390/stubGenerator_s390.cpp index 218b0b378b91041d3b4288d153949b0b96da0874..102200fc08f3537c894a88e91b20b0a2d511e9b3 100644 --- a/src/hotspot/cpu/s390/stubGenerator_s390.cpp +++ b/src/hotspot/cpu/s390/stubGenerator_s390.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2016, 2019 SAP SE. All rights reserved. + * Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 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 @@ -2404,9 +2404,6 @@ class StubGenerator: public StubCodeGenerator { public: StubGenerator(CodeBuffer* code, bool all) : StubCodeGenerator(code) { - // Replace the standard masm with a special one: - _masm = new MacroAssembler(code); - _stub_count = !all ? 0x100 : 0x200; if (all) { generate_all(); diff --git a/src/hotspot/cpu/s390/vm_version_ext_s390.cpp b/src/hotspot/cpu/s390/vm_version_ext_s390.cpp deleted file mode 100644 index 2be9d1c5ede1937922dab2152a0f441b05e04d0d..0000000000000000000000000000000000000000 --- a/src/hotspot/cpu/s390/vm_version_ext_s390.cpp +++ /dev/null @@ -1,86 +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. - * - */ - -#include "jvm.h" -#include "memory/allocation.hpp" -#include "memory/allocation.inline.hpp" -#include "vm_version_ext_s390.hpp" - -// VM_Version_Ext statics -int VM_Version_Ext::_no_of_threads = 0; -int VM_Version_Ext::_no_of_cores = 0; -int VM_Version_Ext::_no_of_sockets = 0; -bool VM_Version_Ext::_initialized = false; -char VM_Version_Ext::_cpu_name[CPU_TYPE_DESC_BUF_SIZE] = {0}; -char VM_Version_Ext::_cpu_desc[CPU_DETAILED_DESC_BUF_SIZE] = {0}; - -// get cpu information. -void VM_Version_Ext::initialize_cpu_information(void) { - // do nothing if cpu info has been initialized - if (_initialized) { - return; - } - - _no_of_cores = os::processor_count(); - _no_of_threads = _no_of_cores; - _no_of_sockets = _no_of_cores; - snprintf(_cpu_name, CPU_TYPE_DESC_BUF_SIZE, "s390 %s", VM_Version::get_model_string()); - snprintf(_cpu_desc, CPU_DETAILED_DESC_BUF_SIZE, "s390 %s", features_string()); - _initialized = true; -} - -int VM_Version_Ext::number_of_threads(void) { - initialize_cpu_information(); - return _no_of_threads; -} - -int VM_Version_Ext::number_of_cores(void) { - initialize_cpu_information(); - return _no_of_cores; -} - -int VM_Version_Ext::number_of_sockets(void) { - initialize_cpu_information(); - return _no_of_sockets; -} - -const char* VM_Version_Ext::cpu_name(void) { - initialize_cpu_information(); - char* tmp = NEW_C_HEAP_ARRAY_RETURN_NULL(char, CPU_TYPE_DESC_BUF_SIZE, mtTracing); - if (NULL == tmp) { - return NULL; - } - strncpy(tmp, _cpu_name, CPU_TYPE_DESC_BUF_SIZE); - return tmp; -} - -const char* VM_Version_Ext::cpu_description(void) { - initialize_cpu_information(); - char* tmp = NEW_C_HEAP_ARRAY_RETURN_NULL(char, CPU_DETAILED_DESC_BUF_SIZE, mtTracing); - if (NULL == tmp) { - return NULL; - } - strncpy(tmp, _cpu_desc, CPU_DETAILED_DESC_BUF_SIZE); - return tmp; -} diff --git a/src/hotspot/cpu/s390/vm_version_ext_s390.hpp b/src/hotspot/cpu/s390/vm_version_ext_s390.hpp deleted file mode 100644 index 8e6bc62e52df835cf8c40c8100be60b5e11f95cb..0000000000000000000000000000000000000000 --- a/src/hotspot/cpu/s390/vm_version_ext_s390.hpp +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2013, 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_S390_VM_VERSION_EXT_S390_HPP -#define CPU_S390_VM_VERSION_EXT_S390_HPP - -#include "runtime/vm_version.hpp" -#include "utilities/macros.hpp" - -#define CPU_INFO "cpu_info" -#define CPU_TYPE "fpu_type" -#define CPU_DESCRIPTION "implementation" -#define CHIP_ID "chip_id" -#define CORE_ID "core_id" - -class VM_Version_Ext : public VM_Version { - private: - - static const size_t CPU_TYPE_DESC_BUF_SIZE = 256; - static const size_t CPU_DETAILED_DESC_BUF_SIZE = 4096; - - static int _no_of_threads; - static int _no_of_cores; - static int _no_of_sockets; - static bool _initialized; - static char _cpu_name[CPU_TYPE_DESC_BUF_SIZE]; - static char _cpu_desc[CPU_DETAILED_DESC_BUF_SIZE]; - - static void initialize_cpu_information(void); - - public: - - static int number_of_threads(void); - static int number_of_cores(void); - static int number_of_sockets(void); - - static const char* cpu_name(void); - static const char* cpu_description(void); -}; - -#endif // CPU_S390_VM_VERSION_EXT_S390_HPP diff --git a/src/hotspot/cpu/s390/vm_version_s390.cpp b/src/hotspot/cpu/s390/vm_version_s390.cpp index d7b68f907c7e370aeb5c405a7c01fc4548f1b069..6c077943d3a5a8b128010e0dc42f2497b21297bb 100644 --- a/src/hotspot/cpu/s390/vm_version_s390.cpp +++ b/src/hotspot/cpu/s390/vm_version_s390.cpp @@ -1490,3 +1490,19 @@ unsigned long VM_Version::z_SIGSEGV() { ); return ZeroBuffer; } + + +// get cpu information. +void VM_Version::initialize_cpu_information(void) { + // do nothing if cpu info has been initialized + if (_initialized) { + return; + } + + _no_of_cores = os::processor_count(); + _no_of_threads = _no_of_cores; + _no_of_sockets = _no_of_cores; + snprintf(_cpu_name, CPU_TYPE_DESC_BUF_SIZE, "s390 %s", VM_Version::get_model_string()); + snprintf(_cpu_desc, CPU_DETAILED_DESC_BUF_SIZE, "s390 %s", features_string()); + _initialized = true; +} diff --git a/src/hotspot/cpu/s390/vm_version_s390.hpp b/src/hotspot/cpu/s390/vm_version_s390.hpp index 176aa7549c0c807cd73d83d9233d160e536d6522..a2fb7dd8e9a3fafe578dd8cd9468ff90436b4b07 100644 --- a/src/hotspot/cpu/s390/vm_version_s390.hpp +++ b/src/hotspot/cpu/s390/vm_version_s390.hpp @@ -533,6 +533,8 @@ class VM_Version: public Abstract_VM_Version { // Sometimes helpful for debugging. static unsigned long z_SIGILL(); static unsigned long z_SIGSEGV(); + + static void initialize_cpu_information(void); }; #endif // CPU_S390_VM_VERSION_S390_HPP diff --git a/src/hotspot/cpu/x86/assembler_x86.cpp b/src/hotspot/cpu/x86/assembler_x86.cpp index 2119c0797a63ea49f4ae85e93c3ce841b3c9a6ff..3505e081d38f2484c2fd915ae39d003dbd8c6278 100644 --- a/src/hotspot/cpu/x86/assembler_x86.cpp +++ b/src/hotspot/cpu/x86/assembler_x86.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -186,7 +186,7 @@ Address::Address(address loc, RelocationHolder spec) { // Address. An index of 4 (rsp) corresponds to having no index, so convert // that to noreg for the Address constructor. Address Address::make_raw(int base, int index, int scale, int disp, relocInfo::relocType disp_reloc) { - RelocationHolder rspec; + RelocationHolder rspec = RelocationHolder::none; if (disp_reloc != relocInfo::none) { rspec = Relocation::spec_simple(disp_reloc); } @@ -300,12 +300,24 @@ void Assembler::emit_arith_b(int op1, int op2, Register dst, int imm8) { void Assembler::emit_arith(int op1, int op2, Register dst, int32_t imm32) { assert(isByte(op1) && isByte(op2), "wrong opcode"); - assert((op1 & 0x01) == 1, "should be 32bit operation"); - assert((op1 & 0x02) == 0, "sign-extension bit should not be set"); + assert(op1 == 0x81, "Unexpected opcode"); if (is8bit(imm32)) { emit_int24(op1 | 0x02, // set sign bit op2 | encode(dst), imm32 & 0xFF); + } else if (dst == rax) { + switch (op2) { + case 0xD0: emit_int8(0x15); break; // adc + case 0xC0: emit_int8(0x05); break; // add + case 0xE0: emit_int8(0x25); break; // and + case 0xF8: emit_int8(0x3D); break; // cmp + case 0xC8: emit_int8(0x0D); break; // or + case 0xD8: emit_int8(0x1D); break; // sbb + case 0xE8: emit_int8(0x2D); break; // sub + case 0xF0: emit_int8(0x35); break; // xor + default: ShouldNotReachHere(); + } + emit_int32(imm32); } else { emit_int16(op1, (op2 | encode(dst))); emit_int32(imm32); @@ -929,6 +941,16 @@ address Assembler::locate_operand(address inst, WhichOperand which) { tail_size = 1; break; + case 0x15: // adc rax, #32 + case 0x05: // add rax, #32 + case 0x25: // and rax, #32 + case 0x3D: // cmp rax, #32 + case 0x0D: // or rax, #32 + case 0x1D: // sbb rax, #32 + case 0x2D: // sub rax, #32 + case 0x35: // xor rax, #32 + return which == end_pc_operand ? ip + 4 : ip; + case 0x9B: switch (0xFF & *ip++) { case 0xD9: // fnstcw a @@ -954,6 +976,11 @@ address Assembler::locate_operand(address inst, WhichOperand which) { debug_only(has_disp32 = true); // has both kinds of operands! break; + case 0xA8: // testb rax, #8 + return which == end_pc_operand ? ip + 1 : ip; + case 0xA9: // testl/testq rax, #32 + return which == end_pc_operand ? ip + 4 : ip; + case 0xC1: // sal a, #8; sar a, #8; shl a, #8; shr a, #8 case 0xC6: // movb a, #8 case 0x80: // cmpb a, #8 @@ -1683,12 +1710,6 @@ void Assembler::cmpl(Address dst, int32_t imm32) { emit_int32(imm32); } -void Assembler::cmp(Register dst, int32_t imm32) { - prefix(dst); - emit_int8((unsigned char)0x3D); - emit_int32(imm32); -} - void Assembler::cmpl(Register dst, int32_t imm32) { prefix(dst); emit_arith(0x81, 0xF8, dst, imm32); @@ -2060,6 +2081,13 @@ void Assembler::vcvtpd2ps(XMMRegister dst, XMMRegister src, int vector_len) { emit_int16(0x5A, (0xC0 | encode)); } +void Assembler::vcvttps2dq(XMMRegister dst, XMMRegister src, int vector_len) { + assert(vector_len <= AVX_256bit ? VM_Version::supports_avx() : VM_Version::supports_evex(), ""); + InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F, &attributes); + emit_int16(0x5B, (0xC0 | encode)); +} + void Assembler::evcvtqq2ps(XMMRegister dst, XMMRegister src, int vector_len) { assert(UseAVX > 2 && VM_Version::supports_avx512dq(), ""); InstructionAttr attributes(vector_len, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); @@ -2068,6 +2096,14 @@ void Assembler::evcvtqq2ps(XMMRegister dst, XMMRegister src, int vector_len) { emit_int16(0x5B, (0xC0 | encode)); } +void Assembler::evcvttpd2qq(XMMRegister dst, XMMRegister src, int vector_len) { + assert(UseAVX > 2 && VM_Version::supports_avx512dq(), ""); + InstructionAttr attributes(vector_len, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_is_evex_instruction(); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int16(0x7A, (0xC0 | encode)); +} + void Assembler::evcvtqq2pd(XMMRegister dst, XMMRegister src, int vector_len) { assert(UseAVX > 2 && VM_Version::supports_avx512dq(), ""); InstructionAttr attributes(vector_len, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); @@ -2374,10 +2410,7 @@ void Assembler::ldmxcsr( Address src) { void Assembler::leal(Register dst, Address src) { InstructionMark im(this); -#ifdef _LP64 - emit_int8(0x67); // addr32 prefix(src, dst); -#endif // LP64 emit_int8((unsigned char)0x8D); emit_operand(dst, src); } @@ -2458,6 +2491,16 @@ void Assembler::movddup(XMMRegister dst, XMMRegister src) { emit_int16(0x12, 0xC0 | encode); } +void Assembler::vmovddup(XMMRegister dst, Address src, int vector_len) { + assert(VM_Version::supports_avx(), ""); + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* rex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_rex_vex_w_reverted(); + simd_prefix(dst, xnoreg, src, VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); + emit_int8(0x12); + emit_operand(dst, src); +} + void Assembler::kmovbl(KRegister dst, KRegister src) { assert(VM_Version::supports_avx512dq(), ""); InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); @@ -2773,6 +2816,15 @@ void Assembler::kshiftlbl(KRegister dst, KRegister src, int imm8) { emit_int8(imm8); } +void Assembler::kshiftlql(KRegister dst, KRegister src, int imm8) { + assert(VM_Version::supports_avx512bw(), ""); + InstructionAttr attributes(AVX_128bit, /* rex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = vex_prefix_and_encode(dst->encoding(), 0 , src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); + emit_int16(0x33, (0xC0 | encode)); + emit_int8(imm8); +} + + void Assembler::kshiftrbl(KRegister dst, KRegister src, int imm8) { assert(VM_Version::supports_avx512dq(), ""); InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); @@ -2804,6 +2856,13 @@ void Assembler::kshiftrql(KRegister dst, KRegister src, int imm8) { emit_int8(imm8); } +void Assembler::kunpckdql(KRegister dst, KRegister src1, KRegister src2) { + assert(VM_Version::supports_avx512bw(), ""); + InstructionAttr attributes(AVX_256bit, /* rex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = vex_prefix_and_encode(dst->encoding(), src1->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); + emit_int16(0x4B, (0xC0 | encode)); +} + void Assembler::movb(Address dst, int imm8) { InstructionMark im(this); prefix(dst); @@ -4306,6 +4365,20 @@ void Assembler::vpmovmskb(Register dst, XMMRegister src, int vec_enc) { emit_int16((unsigned char)0xD7, (0xC0 | encode)); } +void Assembler::vmovmskps(Register dst, XMMRegister src, int vec_enc) { + assert(VM_Version::supports_avx(), ""); + InstructionAttr attributes(vec_enc, /* rex_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_NONE, VEX_OPCODE_0F, &attributes); + emit_int16(0x50, (0xC0 | encode)); +} + +void Assembler::vmovmskpd(Register dst, XMMRegister src, int vec_enc) { + assert(VM_Version::supports_avx(), ""); + InstructionAttr attributes(vec_enc, /* rex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int16(0x50, (0xC0 | encode)); +} + void Assembler::vpmaskmovd(XMMRegister dst, XMMRegister nds, Address src, int vector_len) { assert((VM_Version::supports_avx2() && vector_len == AVX_256bit), ""); InstructionMark im(this); @@ -4715,11 +4788,20 @@ void Assembler::vpmovzxwd(XMMRegister dst, XMMRegister src, int vector_len) { assert(vector_len == AVX_128bit? VM_Version::supports_avx() : vector_len == AVX_256bit? VM_Version::supports_avx2() : vector_len == AVX_512bit? VM_Version::supports_evex() : 0, " "); - InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); + InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); emit_int16(0x33, (0xC0 | encode)); } +void Assembler::vpmovzxwq(XMMRegister dst, XMMRegister src, int vector_len) { + assert(vector_len == AVX_128bit? VM_Version::supports_avx() : + vector_len == AVX_256bit? VM_Version::supports_avx2() : + vector_len == AVX_512bit? VM_Version::supports_evex() : 0, " "); + InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); + emit_int16(0x34, (0xC0 | encode)); +} + void Assembler::pmaddwd(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); @@ -4784,6 +4866,14 @@ void Assembler::vpopcntd(XMMRegister dst, XMMRegister src, int vector_len) { emit_int16(0x55, (0xC0 | encode)); } +void Assembler::vpopcntq(XMMRegister dst, XMMRegister src, int vector_len) { + assert(VM_Version::supports_avx512_vpopcntdq(), "must support vpopcntdq feature"); + 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(), 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); + emit_int16(0x55, (0xC0 | encode)); +} + void Assembler::popf() { emit_int8((unsigned char)0x9D); } @@ -5703,8 +5793,13 @@ void Assembler::subss(XMMRegister dst, Address src) { void Assembler::testb(Register dst, int imm8) { NOT_LP64(assert(dst->has_byte_register(), "must have byte register")); - (void) prefix_and_encode(dst->encoding(), true); - emit_arith_b(0xF6, 0xC0, dst, imm8); + if (dst == rax) { + emit_int8((unsigned char)0xA8); + emit_int8(imm8); + } else { + (void) prefix_and_encode(dst->encoding(), true); + emit_arith_b(0xF6, 0xC0, dst, imm8); + } } void Assembler::testb(Address dst, int imm8) { @@ -5715,14 +5810,34 @@ void Assembler::testb(Address dst, int imm8) { emit_int8(imm8); } +void Assembler::testl(Address dst, int32_t imm32) { + if (imm32 >= 0 && is8bit(imm32)) { + testb(dst, imm32); + return; + } + InstructionMark im(this); + emit_int8((unsigned char)0xF7); + emit_operand(as_Register(0), dst); + emit_int32(imm32); +} + void Assembler::testl(Register dst, int32_t imm32) { + if (imm32 >= 0 && is8bit(imm32) && dst->has_byte_register()) { + testb(dst, imm32); + return; + } // not using emit_arith because test // doesn't support sign-extension of // 8bit operands - int encode = dst->encoding(); - encode = prefix_and_encode(encode); - emit_int16((unsigned char)0xF7, (0xC0 | encode)); - emit_int32(imm32); + if (dst == rax) { + emit_int8((unsigned char)0xA9); + emit_int32(imm32); + } else { + int encode = dst->encoding(); + encode = prefix_and_encode(encode); + emit_int16((unsigned char)0xF7, (0xC0 | encode)); + emit_int32(imm32); + } } void Assembler::testl(Register dst, Register src) { @@ -7549,6 +7664,9 @@ void Assembler::pxor(XMMRegister dst, XMMRegister src) { void Assembler::vpxor(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { assert(UseAVX > 0, "requires some form of AVX"); + assert(vector_len == AVX_128bit ? VM_Version::supports_avx() : + vector_len == AVX_256bit ? VM_Version::supports_avx2() : + vector_len == AVX_512bit ? VM_Version::supports_evex() : 0, ""); 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)0xEF, (0xC0 | encode)); @@ -7556,6 +7674,9 @@ void Assembler::vpxor(XMMRegister dst, XMMRegister nds, XMMRegister src, int vec void Assembler::vpxor(XMMRegister dst, XMMRegister nds, Address src, int vector_len) { assert(UseAVX > 0, "requires some form of AVX"); + assert(vector_len == AVX_128bit ? VM_Version::supports_avx() : + vector_len == AVX_256bit ? VM_Version::supports_avx2() : + vector_len == AVX_512bit ? VM_Version::supports_evex() : 0, ""); InstructionMark im(this); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_32bit); @@ -8239,8 +8360,28 @@ void Assembler::vpbroadcastw(XMMRegister dst, Address src, int vector_len) { emit_operand(dst, src); } -// xmm/mem sourced byte/word/dword/qword replicate +void Assembler::vpsadbw(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)0xF6, (0xC0 | encode)); +} +void Assembler::vpunpckhdq(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { + assert(UseAVX > 0, "requires some form of AVX"); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int16(0x6A, (0xC0 | encode)); +} + +void Assembler::vpunpckldq(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { + assert(UseAVX > 0, "requires some form of AVX"); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int16(0x62, (0xC0 | encode)); +} + +// xmm/mem sourced byte/word/dword/qword replicate void Assembler::evpaddb(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len) { assert(VM_Version::supports_avx512bw() && (vector_len == AVX_512bit || VM_Version::supports_avx512vl()), ""); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true); @@ -9232,7 +9373,7 @@ void Assembler::evpsraq(XMMRegister dst, KRegister mask, XMMRegister src, int sh attributes.reset_is_clear_context(); } int encode = vex_prefix_and_encode(xmm4->encoding(), dst->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); - emit_int24(0x73, (0xC0 | encode), shift & 0xFF); + emit_int24(0x72, (0xC0 | encode), shift & 0xFF); } void Assembler::evpsllw(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len) { @@ -9680,6 +9821,68 @@ void Assembler::evpmaxsq(XMMRegister dst, KRegister mask, XMMRegister nds, Addre emit_operand(dst, src); } +void Assembler::evpternlogd(XMMRegister dst, int imm8, KRegister mask, XMMRegister src2, XMMRegister src3, bool merge, int vector_len) { + assert(VM_Version::supports_evex(), "requires EVEX support"); + assert(vector_len == Assembler::AVX_512bit || VM_Version::supports_avx512vl(), "requires VL support"); + 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(), src2->encoding(), src3->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); + emit_int24(0x25, (unsigned char)(0xC0 | encode), imm8); +} + +void Assembler::evpternlogd(XMMRegister dst, int imm8, KRegister mask, XMMRegister src2, Address src3, bool merge, int vector_len) { + assert(VM_Version::supports_evex(), "requires EVEX support"); + assert(vector_len == Assembler::AVX_512bit || VM_Version::supports_avx512vl(), "requires VL support"); + assert(dst != xnoreg, "sanity"); + 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_embedded_opmask_register_specifier(mask); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_64bit); + if (merge) { + attributes.reset_is_clear_context(); + } + vex_prefix(src3, src2->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); + emit_int8(0x25); + emit_operand(dst, src3); + emit_int8(imm8); +} + +void Assembler::evpternlogq(XMMRegister dst, int imm8, KRegister mask, XMMRegister src2, XMMRegister src3, bool merge, int vector_len) { + assert(VM_Version::supports_evex(), "requires EVEX support"); + assert(vector_len == Assembler::AVX_512bit || VM_Version::supports_avx512vl(), "requires VL support"); + 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(), src2->encoding(), src3->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); + emit_int24(0x25, (unsigned char)(0xC0 | encode), imm8); +} + +void Assembler::evpternlogq(XMMRegister dst, int imm8, KRegister mask, XMMRegister src2, Address src3, bool merge, int vector_len) { + assert(VM_Version::supports_evex(), "requires EVEX support"); + assert(vector_len == Assembler::AVX_512bit || VM_Version::supports_avx512vl(), "requires VL support"); + assert(dst != xnoreg, "sanity"); + 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_embedded_opmask_register_specifier(mask); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_64bit); + if (merge) { + attributes.reset_is_clear_context(); + } + vex_prefix(src3, src2->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); + emit_int8(0x25); + emit_operand(dst, src3); + emit_int8(imm8); +} + // duplicate 4-byte integer data from src into programmed locations in dest : requires AVX512VL void Assembler::vpbroadcastd(XMMRegister dst, XMMRegister src, int vector_len) { assert(UseAVX >= 2, ""); @@ -9724,12 +9927,12 @@ void Assembler::vpbroadcastq(XMMRegister dst, Address src, int vector_len) { void Assembler::evbroadcasti32x4(XMMRegister dst, Address src, int vector_len) { assert(vector_len != Assembler::AVX_128bit, ""); - assert(VM_Version::supports_avx512dq(), ""); + assert(VM_Version::supports_evex(), ""); 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_rex_vex_w_reverted(); - attributes.set_address_attributes(/* tuple_type */ EVEX_T2, /* input_size_in_bits */ EVEX_64bit); + 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); @@ -11072,6 +11275,10 @@ void Assembler::evpcmpw(KRegister kdst, KRegister mask, XMMRegister nds, Address emit_int8((unsigned char)comparison); } +// Register is a class, but it would be assigned numerical value. +// "0" is assigned for xmm0. Thus we need to ignore -Wnonnull. +PRAGMA_DIAG_PUSH +PRAGMA_NONNULL_IGNORED void Assembler::evprord(XMMRegister dst, KRegister mask, XMMRegister src, int shift, bool merge, int vector_len) { 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); @@ -11095,6 +11302,7 @@ void Assembler::evprorq(XMMRegister dst, KRegister mask, XMMRegister src, int sh int encode = vex_prefix_and_encode(xmm0->encoding(), dst->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int24(0x72, (0xC0 | encode), shift & 0xFF); } +PRAGMA_DIAG_POP void Assembler::evprorvd(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len) { assert(vector_len == AVX_512bit || VM_Version::supports_avx512vl(), ""); @@ -11263,6 +11471,20 @@ void Assembler::bzhiq(Register dst, Register src1, Register src2) { emit_int16((unsigned char)0xF5, (0xC0 | encode)); } +void Assembler::pext(Register dst, Register src1, Register src2) { + assert(VM_Version::supports_bmi2(), "bit manipulation instructions not supported"); + InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = vex_prefix_and_encode(dst->encoding(), src1->encoding(), src2->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F_38, &attributes); + emit_int16((unsigned char)0xF5, (0xC0 | encode)); +} + +void Assembler::pdep(Register dst, Register src1, Register src2) { + assert(VM_Version::supports_bmi2(), "bit manipulation instructions not supported"); + InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = vex_prefix_and_encode(dst->encoding(), src1->encoding(), src2->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F_38, &attributes); + emit_int16((unsigned char)0xF5, (0xC0 | encode)); +} + void Assembler::shlxl(Register dst, Register src1, Register src2) { assert(VM_Version::supports_bmi2(), ""); InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ true); @@ -12834,6 +13056,10 @@ void Assembler::subq(Register dst, Register src) { } void Assembler::testq(Address dst, int32_t imm32) { + if (imm32 >= 0) { + testl(dst, imm32); + return; + } InstructionMark im(this); emit_int16(get_prefixq(dst), (unsigned char)0xF7); emit_operand(as_Register(0), dst); @@ -12841,13 +13067,23 @@ void Assembler::testq(Address dst, int32_t imm32) { } void Assembler::testq(Register dst, int32_t imm32) { + if (imm32 >= 0) { + testl(dst, imm32); + return; + } // not using emit_arith because test // doesn't support sign-extension of // 8bit operands - int encode = dst->encoding(); - encode = prefixq_and_encode(encode); - emit_int16((unsigned char)0xF7, (0xC0 | encode)); - emit_int32(imm32); + if (dst == rax) { + prefix(REX_W); + emit_int8((unsigned char)0xA9); + emit_int32(imm32); + } else { + int encode = dst->encoding(); + encode = prefixq_and_encode(encode); + emit_int16((unsigned char)0xF7, (0xC0 | encode)); + emit_int32(imm32); + } } void Assembler::testq(Register dst, Register src) { diff --git a/src/hotspot/cpu/x86/assembler_x86.hpp b/src/hotspot/cpu/x86/assembler_x86.hpp index 09b2a392d305801f990beb003460ae9e311accf0..7141e4b96c4141f2184cab62bbff2428313bf649 100644 --- a/src/hotspot/cpu/x86/assembler_x86.hpp +++ b/src/hotspot/cpu/x86/assembler_x86.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -377,7 +377,7 @@ class AddressLiteral { private: address target() { return _target; } - bool is_lval() { return _is_lval; } + bool is_lval() const { return _is_lval; } relocInfo::relocType reloc() const { return _rspec.type(); } const RelocationHolder& rspec() const { return _rspec; } @@ -1081,15 +1081,12 @@ private: void cmpb(Address dst, int imm8); void cmpl(Address dst, int32_t imm32); - - void cmp(Register dst, int32_t imm32); void cmpl(Register dst, int32_t imm32); void cmpl(Register dst, Register src); void cmpl(Register dst, Address src); void cmpq(Address dst, int32_t imm32); void cmpq(Address dst, Register src); - void cmpq(Register dst, int32_t imm32); void cmpq(Register dst, Register src); void cmpq(Register dst, Address src); @@ -1168,10 +1165,16 @@ private: void vcvtps2pd(XMMRegister dst, XMMRegister src, int vector_len); void vcvtpd2ps(XMMRegister dst, XMMRegister src, int vector_len); + // Convert vector float and int + void vcvttps2dq(XMMRegister dst, XMMRegister src, int vector_len); + // Convert vector long to vector FP void evcvtqq2ps(XMMRegister dst, XMMRegister src, int vector_len); void evcvtqq2pd(XMMRegister dst, XMMRegister src, int vector_len); + // Convert vector double to long + void evcvttpd2qq(XMMRegister dst, XMMRegister src, int vector_len); + // Evex casts with truncation void evpmovwb(XMMRegister dst, XMMRegister src, int vector_len); void evpmovdw(XMMRegister dst, XMMRegister src, int vector_len); @@ -1461,6 +1464,7 @@ private: void movb(Register dst, Address src); void movddup(XMMRegister dst, XMMRegister src); + void vmovddup(XMMRegister dst, Address src, int vector_len); void kandbl(KRegister dst, KRegister src1, KRegister src2); void kandwl(KRegister dst, KRegister src1, KRegister src2); @@ -1504,12 +1508,15 @@ private: void kxnorbl(KRegister dst, KRegister src1, KRegister src2); void kshiftlbl(KRegister dst, KRegister src, int imm8); + void kshiftlql(KRegister dst, KRegister src, int imm8); void kshiftrbl(KRegister dst, KRegister src, int imm8); void kshiftrwl(KRegister dst, KRegister src, int imm8); void kshiftrdl(KRegister dst, KRegister src, int imm8); void kshiftrql(KRegister dst, KRegister src, int imm8); void ktestq(KRegister src1, KRegister src2); void ktestd(KRegister src1, KRegister src2); + void kunpckdql(KRegister dst, KRegister src1, KRegister src2); + void ktestql(KRegister dst, KRegister src); void ktestdl(KRegister dst, KRegister src); @@ -1774,6 +1781,8 @@ private: void pmovmskb(Register dst, XMMRegister src); void vpmovmskb(Register dst, XMMRegister src, int vec_enc); + void vmovmskps(Register dst, XMMRegister src, int vec_enc); + void vmovmskpd(Register dst, XMMRegister src, int vec_enc); void vpmaskmovd(XMMRegister dst, XMMRegister nds, Address src, int vector_len); // SSE 4.1 extract @@ -1810,12 +1819,14 @@ private: void pmovzxbw(XMMRegister dst, XMMRegister src); void pmovzxbw(XMMRegister dst, Address src); void pmovzxbd(XMMRegister dst, XMMRegister src); - void vpmovzxbw( XMMRegister dst, Address src, int vector_len); - void pmovzxdq(XMMRegister dst, XMMRegister src); + void vpmovzxbw(XMMRegister dst, Address src, int vector_len); void vpmovzxbw(XMMRegister dst, XMMRegister src, int vector_len); - void vpmovzxdq(XMMRegister dst, XMMRegister src, int vector_len); void vpmovzxbd(XMMRegister dst, XMMRegister src, int vector_len); void vpmovzxbq(XMMRegister dst, XMMRegister src, int vector_len); + void vpmovzxwd(XMMRegister dst, XMMRegister src, int vector_len); + void vpmovzxwq(XMMRegister dst, XMMRegister src, int vector_len); + void pmovzxdq(XMMRegister dst, XMMRegister src); + void vpmovzxdq(XMMRegister dst, XMMRegister src, int vector_len); void evpmovzxbw(XMMRegister dst, KRegister mask, Address src, int vector_len); // Sign extend moves @@ -1832,9 +1843,6 @@ private: void evpmovwb(Address dst, XMMRegister src, int vector_len); void evpmovwb(Address dst, KRegister mask, XMMRegister src, int vector_len); - - void vpmovzxwd(XMMRegister dst, XMMRegister src, int vector_len); - void evpmovdb(Address dst, XMMRegister src, int vector_len); // Multiply add @@ -1858,6 +1866,7 @@ private: void popcntl(Register dst, Register src); void vpopcntd(XMMRegister dst, XMMRegister src, int vector_len); + void vpopcntq(XMMRegister dst, XMMRegister src, int vector_len); #ifdef _LP64 void popcntq(Register dst, Address src); @@ -1921,10 +1930,17 @@ private: // Interleave Low Doublewords void punpckldq(XMMRegister dst, XMMRegister src); void punpckldq(XMMRegister dst, Address src); + void vpunpckldq(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); + + // Interleave High Doublewords + void vpunpckhdq(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); // Interleave Low Quadwords void punpcklqdq(XMMRegister dst, XMMRegister src); + // Vector sum of absolute difference. + void vpsadbw(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); + #ifndef _LP64 // no 32bit push/pop on amd64 void pushl(Address src); #endif @@ -2080,9 +2096,10 @@ private: void subss(XMMRegister dst, Address src); void subss(XMMRegister dst, XMMRegister src); - void testb(Register dst, int imm8); void testb(Address dst, int imm8); + void testb(Register dst, int imm8); + void testl(Address dst, int32_t imm32); void testl(Register dst, int32_t imm32); void testl(Register dst, Register src); void testl(Register dst, Address src); @@ -2176,6 +2193,9 @@ private: void shrxq(Register dst, Register src1, Register src2); void bzhiq(Register dst, Register src1, Register src2); + void pdep(Register dst, Register src1, Register src2); + void pext(Register dst, Register src1, Register src2); + //====================VECTOR ARITHMETIC===================================== // Add Packed Floating-Point Values @@ -2399,6 +2419,12 @@ private: void evprorvd(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len); void evprorvq(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len); + void evpternlogd(XMMRegister dst, int imm8, KRegister mask, XMMRegister src2, XMMRegister src3, bool merge, int vector_len); + void evpternlogd(XMMRegister dst, int imm8, KRegister mask, XMMRegister src2, Address src3, bool merge, int vector_len); + void evpternlogq(XMMRegister dst, int imm8, KRegister mask, XMMRegister src2, XMMRegister src3, bool merge, int vector_len); + void evpternlogq(XMMRegister dst, int imm8, KRegister mask, XMMRegister src2, Address src3, bool merge, int vector_len); + + // Sub packed integers void psubb(XMMRegister dst, XMMRegister src); void psubw(XMMRegister dst, XMMRegister src); diff --git a/src/hotspot/cpu/x86/bytes_x86.hpp b/src/hotspot/cpu/x86/bytes_x86.hpp index 4ce19a473b49a1b054b79b1addb72084464fa7ce..cb5987d2c8262ba3f77d5d4eb216e416ad027576 100644 --- a/src/hotspot/cpu/x86/bytes_x86.hpp +++ b/src/hotspot/cpu/x86/bytes_x86.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -25,7 +25,7 @@ #ifndef CPU_X86_BYTES_X86_HPP #define CPU_X86_BYTES_X86_HPP -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" #include "utilities/align.hpp" #include "utilities/macros.hpp" diff --git a/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp b/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp index 971c2515017df2c9d49d55713802729eb5037a33..eaeeae235f0d2be6ff8f2adface509258fa9e777 100644 --- a/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp @@ -461,7 +461,11 @@ int LIR_Assembler::emit_unwind_handler() { if (method()->is_synchronized()) { monitor_address(0, FrameMap::rax_opr); stub = new MonitorExitStub(FrameMap::rax_opr, true, 0); - __ unlock_object(rdi, rsi, rax, *stub->entry()); + if (UseHeavyMonitors) { + __ jmp(*stub->entry()); + } else { + __ unlock_object(rdi, rsi, rax, *stub->entry()); + } __ bind(*stub->continuation()); } @@ -1184,7 +1188,6 @@ void LIR_Assembler::mem2reg(LIR_Opr src, LIR_Opr dest, BasicType type, LIR_Patch LIR_Address* addr = src->as_address_ptr(); Address from_addr = as_Address(addr); - Register tmp_load_klass = LP64_ONLY(rscratch1) NOT_LP64(noreg); if (addr->base()->type() == T_OBJECT) { __ verify_oop(addr->base()->as_pointer_register()); @@ -1257,11 +1260,7 @@ void LIR_Assembler::mem2reg(LIR_Opr src, LIR_Opr dest, BasicType type, LIR_Patch break; case T_ADDRESS: - if (UseCompressedClassPointers && addr->disp() == oopDesc::klass_offset_in_bytes()) { - __ movl(dest->as_register(), from_addr); - } else { - __ movptr(dest->as_register(), from_addr); - } + __ movptr(dest->as_register(), from_addr); break; case T_INT: __ movl(dest->as_register(), from_addr); @@ -1367,12 +1366,6 @@ void LIR_Assembler::mem2reg(LIR_Opr src, LIR_Opr dest, BasicType type, LIR_Patch if (!UseZGC) { __ verify_oop(dest->as_register()); } - } else if (type == T_ADDRESS && addr->disp() == oopDesc::klass_offset_in_bytes()) { -#ifdef _LP64 - if (UseCompressedClassPointers) { - __ decode_klass_not_null(dest->as_register(), tmp_load_klass); - } -#endif } } @@ -3509,7 +3502,7 @@ void LIR_Assembler::emit_lock(LIR_OpLock* op) { Register obj = op->obj_opr()->as_register(); // may not be an oop Register hdr = op->hdr_opr()->as_register(); Register lock = op->lock_opr()->as_register(); - if (!UseFastLocking) { + if (UseHeavyMonitors) { __ jmp(*op->stub()->entry()); } else if (op->code() == lir_lock) { assert(BasicLock::displaced_header_offset_in_bytes() == 0, "lock_reg must point to the displaced header"); @@ -3528,6 +3521,23 @@ void LIR_Assembler::emit_lock(LIR_OpLock* op) { __ bind(*op->stub()->continuation()); } +void LIR_Assembler::emit_load_klass(LIR_OpLoadKlass* op) { + Register obj = op->obj()->as_pointer_register(); + Register result = op->result_opr()->as_pointer_register(); + + CodeEmitInfo* info = op->info(); + if (info != NULL) { + add_debug_info_for_null_check_here(info); + } + +#ifdef _LP64 + if (UseCompressedClassPointers) { + __ movl(result, Address(obj, oopDesc::klass_offset_in_bytes())); + __ decode_klass_not_null(result, rscratch1); + } else +#endif + __ movptr(result, Address(obj, oopDesc::klass_offset_in_bytes())); +} void LIR_Assembler::emit_profile_call(LIR_OpProfileCall* op) { ciMethod* method = op->profiled_method(); diff --git a/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp b/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp index 0b62108c79fa266265fd50aff85b9b57798440b5..819c36957b35a0f48d43c291902583c5adc09f07 100644 --- a/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp +++ b/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp @@ -192,8 +192,32 @@ LIR_Address* LIRGenerator::emit_array_address(LIR_Opr array_opr, LIR_Opr index_o LIR_Address* addr; if (index_opr->is_constant()) { int elem_size = type2aelembytes(type); - addr = new LIR_Address(array_opr, - offset_in_bytes + (intx)(index_opr->as_jint()) * elem_size, type); +#ifdef _LP64 + jint index = index_opr->as_jint(); + jlong disp = offset_in_bytes + (jlong)(index) * elem_size; + if (disp > max_jint) { + // Displacement overflow. Cannot directly use instruction with 32-bit displacement for 64-bit addresses. + // Convert array index to long to do array offset computation with 64-bit values. + index_opr = new_register(T_LONG); + __ move(LIR_OprFact::longConst(index), index_opr); + addr = new LIR_Address(array_opr, index_opr, LIR_Address::scale(type), offset_in_bytes, type); + } else { + addr = new LIR_Address(array_opr, (intx)disp, type); + } +#else + // A displacement overflow can also occur for x86 but that is not a problem due to the 32-bit address range! + // Let's assume an array 'a' and an access with displacement 'disp'. When disp overflows, then "a + disp" will + // always be negative (i.e. underflows the 32-bit address range): + // Let N = 2^32: a + signed_overflow(disp) = a + disp - N. + // "a + disp" is always smaller than N. If an index was chosen which would point to an address beyond N, then + // range checks would catch that and throw an exception. Thus, a + disp < 0 holds which means that it always + // underflows the 32-bit address range: + // unsigned_underflow(a + signed_overflow(disp)) = unsigned_underflow(a + disp - N) + // = (a + disp - N) + N = a + disp + // This shows that we still end up at the correct address with a displacement overflow due to the 32-bit address + // range limitation. This overflow only needs to be handled if addresses can be larger as on 64-bit platforms. + addr = new LIR_Address(array_opr, offset_in_bytes + (intx)(index_opr->as_jint()) * elem_size, type); +#endif // _LP64 } else { #ifdef _LP64 if (index_opr->type() == T_INT) { diff --git a/src/hotspot/cpu/x86/c1_LIR_x86.cpp b/src/hotspot/cpu/x86/c1_LIR_x86.cpp index f7e3392d2e5c6b0fe8c7e9f895402f5d354b7d95..6bdbfd1824caacc026ecfe64630c737267dc7c52 100644 --- a/src/hotspot/cpu/x86/c1_LIR_x86.cpp +++ b/src/hotspot/cpu/x86/c1_LIR_x86.cpp @@ -28,21 +28,21 @@ #include "c1/c1_LIR.hpp" -FloatRegister LIR_OprDesc::as_float_reg() const { +FloatRegister LIR_Opr::as_float_reg() const { ShouldNotReachHere(); return fnoreg; } -FloatRegister LIR_OprDesc::as_double_reg() const { +FloatRegister LIR_Opr::as_double_reg() const { ShouldNotReachHere(); return fnoreg; } -XMMRegister LIR_OprDesc::as_xmm_float_reg() const { +XMMRegister LIR_Opr::as_xmm_float_reg() const { return FrameMap::nr2xmmreg(xmm_regnr()); } -XMMRegister LIR_OprDesc::as_xmm_double_reg() const { +XMMRegister LIR_Opr::as_xmm_double_reg() const { assert(xmm_regnrLo() == xmm_regnrHi(), "assumed in calculation"); return FrameMap::nr2xmmreg(xmm_regnrLo()); } @@ -50,11 +50,11 @@ XMMRegister LIR_OprDesc::as_xmm_double_reg() const { // Reg2 unused. LIR_Opr LIR_OprFact::double_fpu(int reg1, int reg2) { assert(as_FloatRegister(reg2) == fnoreg, "Not used on this platform"); - return (LIR_Opr)(intptr_t)((reg1 << LIR_OprDesc::reg1_shift) | - (reg1 << LIR_OprDesc::reg2_shift) | - LIR_OprDesc::double_type | - LIR_OprDesc::fpu_register | - LIR_OprDesc::double_size); + return (LIR_Opr)(intptr_t)((reg1 << LIR_Opr::reg1_shift) | + (reg1 << LIR_Opr::reg2_shift) | + LIR_Opr::double_type | + LIR_Opr::fpu_register | + LIR_Opr::double_size); } #ifndef PRODUCT diff --git a/src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp b/src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp index 80d0ca4dd181d338720e5a3d9b8b80a93527e580..26a1f36c94d02a8b4f3464b7895bdf6cddaf919b 100644 --- a/src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp @@ -331,18 +331,18 @@ void C1_MacroAssembler::remove_frame(int frame_size_in_bytes) { } -void C1_MacroAssembler::verified_entry() { - if (C1Breakpoint || VerifyFPU) { +void C1_MacroAssembler::verified_entry(bool breakAtEntry) { + if (breakAtEntry || VerifyFPU) { // Verified Entry first instruction should be 5 bytes long for correct // patching by patch_verified_entry(). // - // C1Breakpoint and VerifyFPU have one byte first instruction. + // Breakpoint and VerifyFPU have one byte first instruction. // Also first instruction will be one byte "push(rbp)" if stack banging // code is not generated (see build_frame() above). // For all these cases generate long instruction first. fat_nop(); } - if (C1Breakpoint)int3(); + if (breakAtEntry) int3(); // build frame IA32_ONLY( verify_FPU(0, "method_entry"); ) } diff --git a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp index df3501974c4b8e07ec96393bf25f45ce8d6cf31c..6d8b9101303508409fa4a8b2b01770670ed69fea 100644 --- a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -485,6 +485,7 @@ void C2_MacroAssembler::fast_lock(Register objReg, Register boxReg, Register tmp #if INCLUDE_RTM_OPT if (UseRTMForStackLocks && use_rtm) { + assert(!UseHeavyMonitors, "+UseHeavyMonitors and +UseRTMForStackLocks are mutually exclusive"); rtm_stack_locking(objReg, tmpReg, scrReg, cx2Reg, stack_rtm_counters, method_data, profile_rtm, DONE_LABEL, IsInflated); @@ -495,20 +496,25 @@ void C2_MacroAssembler::fast_lock(Register objReg, Register boxReg, Register tmp testptr(tmpReg, markWord::monitor_value); // inflated vs stack-locked|neutral jccb(Assembler::notZero, IsInflated); - // Attempt stack-locking ... - orptr (tmpReg, markWord::unlocked_value); - movptr(Address(boxReg, 0), tmpReg); // Anticipate successful CAS - lock(); - cmpxchgptr(boxReg, Address(objReg, oopDesc::mark_offset_in_bytes())); // Updates tmpReg - jcc(Assembler::equal, DONE_LABEL); // Success - - // Recursive locking. - // The object is stack-locked: markword contains stack pointer to BasicLock. - // Locked by current thread if difference with current SP is less than one page. - subptr(tmpReg, rsp); - // Next instruction set ZFlag == 1 (Success) if difference is less then one page. - andptr(tmpReg, (int32_t) (NOT_LP64(0xFFFFF003) LP64_ONLY(7 - os::vm_page_size())) ); - movptr(Address(boxReg, 0), tmpReg); + if (!UseHeavyMonitors) { + // Attempt stack-locking ... + orptr (tmpReg, markWord::unlocked_value); + movptr(Address(boxReg, 0), tmpReg); // Anticipate successful CAS + lock(); + cmpxchgptr(boxReg, Address(objReg, oopDesc::mark_offset_in_bytes())); // Updates tmpReg + jcc(Assembler::equal, DONE_LABEL); // Success + + // Recursive locking. + // The object is stack-locked: markword contains stack pointer to BasicLock. + // Locked by current thread if difference with current SP is less than one page. + subptr(tmpReg, rsp); + // Next instruction set ZFlag == 1 (Success) if difference is less then one page. + andptr(tmpReg, (int32_t) (NOT_LP64(0xFFFFF003) LP64_ONLY(7 - os::vm_page_size())) ); + movptr(Address(boxReg, 0), tmpReg); + } else { + // Clear ZF so that we take the slow path at the DONE label. objReg is known to be not 0. + testptr(objReg, objReg); + } jmp(DONE_LABEL); bind(IsInflated); @@ -574,8 +580,13 @@ void C2_MacroAssembler::fast_lock(Register objReg, Register boxReg, Register tmp // Unconditionally set box->_displaced_header = markWord::unused_mark(). // Without cast to int32_t this style of movptr will destroy r10 which is typically obj. movptr(Address(boxReg, 0), (int32_t)intptr_t(markWord::unused_mark().value())); - // Intentional fall-through into DONE_LABEL ... // Propagate ICC.ZF from CAS above into DONE_LABEL. + jcc(Assembler::equal, DONE_LABEL); // CAS above succeeded; propagate ZF = 1 (success) + + cmpptr(r15_thread, rax); // Check if we are already the owner (recursive lock) + jcc(Assembler::notEqual, DONE_LABEL); // If not recursive, ZF = 0 at this point (fail) + incq(Address(scrReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions))); + xorq(rax, rax); // Set ZF = 1 (success) for recursive lock, denoting locking success #endif // _LP64 #if INCLUDE_RTM_OPT } // use_rtm() @@ -633,6 +644,7 @@ void C2_MacroAssembler::fast_unlock(Register objReg, Register boxReg, Register t #if INCLUDE_RTM_OPT if (UseRTMForStackLocks && use_rtm) { + assert(!UseHeavyMonitors, "+UseHeavyMonitors and +UseRTMForStackLocks are mutually exclusive"); Label L_regular_unlock; movptr(tmpReg, Address(objReg, oopDesc::mark_offset_in_bytes())); // fetch markword andptr(tmpReg, markWord::lock_mask_in_place); // look at 2 lock bits @@ -644,11 +656,15 @@ void C2_MacroAssembler::fast_unlock(Register objReg, Register boxReg, Register t } #endif - cmpptr(Address(boxReg, 0), (int32_t)NULL_WORD); // Examine the displaced header - jcc (Assembler::zero, DONE_LABEL); // 0 indicates recursive stack-lock + if (!UseHeavyMonitors) { + cmpptr(Address(boxReg, 0), (int32_t)NULL_WORD); // Examine the displaced header + jcc (Assembler::zero, DONE_LABEL); // 0 indicates recursive stack-lock + } movptr(tmpReg, Address(objReg, oopDesc::mark_offset_in_bytes())); // Examine the object's markword - testptr(tmpReg, markWord::monitor_value); // Inflated? - jccb (Assembler::zero, Stacked); + if (!UseHeavyMonitors) { + testptr(tmpReg, markWord::monitor_value); // Inflated? + jccb (Assembler::zero, Stacked); + } // It's inflated. #if INCLUDE_RTM_OPT @@ -670,10 +686,6 @@ void C2_MacroAssembler::fast_unlock(Register objReg, Register boxReg, Register t // Refer to the comments in synchronizer.cpp for how we might encode extra // state in _succ so we can avoid fetching EntryList|cxq. // - // I'd like to add more cases in fast_lock() and fast_unlock() -- - // such as recursive enter and exit -- but we have to be wary of - // I$ bloat, T$ effects and BP$ effects. - // // If there's no contention try a 1-0 exit. That is, exit without // a costly MEMBAR or CAS. See synchronizer.cpp for details on how // we detect and recover from the race that the 1-0 exit admits. @@ -721,9 +733,16 @@ void C2_MacroAssembler::fast_unlock(Register objReg, Register boxReg, Register t bind (CheckSucc); #else // _LP64 // It's inflated - xorptr(boxReg, boxReg); - orptr(boxReg, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions))); - jccb (Assembler::notZero, DONE_LABEL); + Label LNotRecursive, LSuccess, LGoSlowPath; + + cmpptr(Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions)), 0); + jccb(Assembler::equal, LNotRecursive); + + // Recursive inflated unlock + decq(Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions))); + jmpb(LSuccess); + + bind(LNotRecursive); movptr(boxReg, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(cxq))); orptr(boxReg, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(EntryList))); jccb (Assembler::notZero, CheckSucc); @@ -732,7 +751,6 @@ void C2_MacroAssembler::fast_unlock(Register objReg, Register boxReg, Register t jmpb (DONE_LABEL); // Try to avoid passing control into the slow_path ... - Label LSuccess, LGoSlowPath ; bind (CheckSucc); // The following optional optimization can be elided if necessary @@ -788,11 +806,12 @@ void C2_MacroAssembler::fast_unlock(Register objReg, Register boxReg, Register t testl (boxReg, 0); // set ICC.ZF=1 to indicate success jmpb (DONE_LABEL); - bind (Stacked); - movptr(tmpReg, Address (boxReg, 0)); // re-fetch - lock(); - cmpxchgptr(tmpReg, Address(objReg, oopDesc::mark_offset_in_bytes())); // Uses RAX which is box - + if (!UseHeavyMonitors) { + bind (Stacked); + movptr(tmpReg, Address (boxReg, 0)); // re-fetch + lock(); + cmpxchgptr(tmpReg, Address(objReg, oopDesc::mark_offset_in_bytes())); // Uses RAX which is box + } #endif bind(DONE_LABEL); } @@ -1474,6 +1493,26 @@ void C2_MacroAssembler::load_vector_mask(KRegister dst, XMMRegister src, XMMRegi } } +void C2_MacroAssembler::load_vector(XMMRegister dst, Address src, int vlen_in_bytes) { + switch (vlen_in_bytes) { + case 4: movdl(dst, src); break; + case 8: movq(dst, src); break; + case 16: movdqu(dst, src); break; + case 32: vmovdqu(dst, src); break; + case 64: evmovdquq(dst, src, Assembler::AVX_512bit); break; + default: ShouldNotReachHere(); + } +} + +void C2_MacroAssembler::load_vector(XMMRegister dst, AddressLiteral src, int vlen_in_bytes, Register rscratch) { + if (reachable(src)) { + load_vector(dst, as_Address(src), vlen_in_bytes); + } else { + lea(rscratch, src); + load_vector(dst, Address(rscratch, 0), vlen_in_bytes); + } +} + void C2_MacroAssembler::load_iota_indices(XMMRegister dst, Register scratch, int vlen_in_bytes) { ExternalAddress addr(StubRoutines::x86::vector_iota_indices()); if (vlen_in_bytes == 4) { @@ -2173,84 +2212,6 @@ void C2_MacroAssembler::evpcmp(BasicType typ, KRegister kdmask, KRegister ksmask } } -void C2_MacroAssembler::vpcmpu(BasicType typ, XMMRegister dst, XMMRegister src1, XMMRegister src2, ComparisonPredicate comparison, - int vlen_in_bytes, XMMRegister vtmp1, XMMRegister vtmp2, Register scratch) { - int vlen_enc = vector_length_encoding(vlen_in_bytes*2); - switch (typ) { - case T_BYTE: - vpmovzxbw(vtmp1, src1, vlen_enc); - vpmovzxbw(vtmp2, src2, vlen_enc); - vpcmpCCW(dst, vtmp1, vtmp2, comparison, Assembler::W, vlen_enc, scratch); - vpacksswb(dst, dst, dst, vlen_enc); - break; - case T_SHORT: - vpmovzxwd(vtmp1, src1, vlen_enc); - vpmovzxwd(vtmp2, src2, vlen_enc); - vpcmpCCW(dst, vtmp1, vtmp2, comparison, Assembler::D, vlen_enc, scratch); - vpackssdw(dst, dst, dst, vlen_enc); - break; - case T_INT: - vpmovzxdq(vtmp1, src1, vlen_enc); - vpmovzxdq(vtmp2, src2, vlen_enc); - vpcmpCCW(dst, vtmp1, vtmp2, comparison, Assembler::Q, vlen_enc, scratch); - vpermilps(dst, dst, 8, vlen_enc); - break; - default: - assert(false, "Should not reach here"); - } - if (vlen_in_bytes == 16) { - vpermpd(dst, dst, 0x8, vlen_enc); - } -} - -void C2_MacroAssembler::vpcmpu32(BasicType typ, XMMRegister dst, XMMRegister src1, XMMRegister src2, ComparisonPredicate comparison, int vlen_in_bytes, - XMMRegister vtmp1, XMMRegister vtmp2, XMMRegister vtmp3, Register scratch) { - int vlen_enc = vector_length_encoding(vlen_in_bytes); - switch (typ) { - case T_BYTE: - vpmovzxbw(vtmp1, src1, vlen_enc); - vpmovzxbw(vtmp2, src2, vlen_enc); - vpcmpCCW(dst, vtmp1, vtmp2, comparison, Assembler::W, vlen_enc, scratch); - vextracti128(vtmp1, src1, 1); - vextracti128(vtmp2, src2, 1); - vpmovzxbw(vtmp1, vtmp1, vlen_enc); - vpmovzxbw(vtmp2, vtmp2, vlen_enc); - vpcmpCCW(vtmp3, vtmp1, vtmp2, comparison, Assembler::W, vlen_enc, scratch); - vpacksswb(dst, dst, vtmp3, vlen_enc); - vpermpd(dst, dst, 0xd8, vlen_enc); - break; - case T_SHORT: - vpmovzxwd(vtmp1, src1, vlen_enc); - vpmovzxwd(vtmp2, src2, vlen_enc); - vpcmpCCW(dst, vtmp1, vtmp2, comparison, Assembler::D, vlen_enc, scratch); - vextracti128(vtmp1, src1, 1); - vextracti128(vtmp2, src2, 1); - vpmovzxwd(vtmp1, vtmp1, vlen_enc); - vpmovzxwd(vtmp2, vtmp2, vlen_enc); - vpcmpCCW(vtmp3, vtmp1, vtmp2, comparison, Assembler::D, vlen_enc, scratch); - vpackssdw(dst, dst, vtmp3, vlen_enc); - vpermpd(dst, dst, 0xd8, vlen_enc); - break; - case T_INT: - vpmovzxdq(vtmp1, src1, vlen_enc); - vpmovzxdq(vtmp2, src2, vlen_enc); - vpcmpCCW(dst, vtmp1, vtmp2, comparison, Assembler::Q, vlen_enc, scratch); - vpshufd(dst, dst, 8, vlen_enc); - vpermq(dst, dst, 8, vlen_enc); - vextracti128(vtmp1, src1, 1); - vextracti128(vtmp2, src2, 1); - vpmovzxdq(vtmp1, vtmp1, vlen_enc); - vpmovzxdq(vtmp2, vtmp2, vlen_enc); - vpcmpCCW(vtmp3, vtmp1, vtmp2, comparison, Assembler::Q, vlen_enc, scratch); - vpshufd(vtmp3, vtmp3, 8, vlen_enc); - vpermq(vtmp3, vtmp3, 0x80, vlen_enc); - vpblendd(dst, dst, vtmp3, 0xf0, vlen_enc); - break; - default: - assert(false, "Should not reach here"); - } -} - void C2_MacroAssembler::evpblend(BasicType typ, XMMRegister dst, KRegister kmask, XMMRegister src1, XMMRegister src2, bool merge, int vector_len) { switch(typ) { case T_BYTE: @@ -3413,18 +3374,19 @@ void C2_MacroAssembler::string_compare(Register str1, Register str2, } // Search for Non-ASCII character (Negative byte value) in a byte array, -// return true if it has any and false otherwise. +// return the index of the first such character, otherwise the length +// of the array segment searched. // ..\jdk\src\java.base\share\classes\java\lang\StringCoding.java // @IntrinsicCandidate -// private static boolean hasNegatives(byte[] ba, int off, int len) { +// public static int countPositives(byte[] ba, int off, int len) { // for (int i = off; i < off + len; i++) { // if (ba[i] < 0) { -// return true; +// return i - off; // } // } -// return false; +// return len; // } -void C2_MacroAssembler::has_negatives(Register ary1, Register len, +void C2_MacroAssembler::count_positives(Register ary1, Register len, Register result, Register tmp1, XMMRegister vec1, XMMRegister vec2, KRegister mask1, KRegister mask2) { // rsi: byte array @@ -3433,17 +3395,18 @@ void C2_MacroAssembler::has_negatives(Register ary1, Register len, ShortBranchVerifier sbv(this); assert_different_registers(ary1, len, result, tmp1); assert_different_registers(vec1, vec2); - Label TRUE_LABEL, FALSE_LABEL, DONE, COMPARE_CHAR, COMPARE_VECTORS, COMPARE_BYTE; + Label ADJUST, TAIL_ADJUST, DONE, TAIL_START, CHAR_ADJUST, COMPARE_CHAR, COMPARE_VECTORS, COMPARE_BYTE; + movl(result, len); // copy // len == 0 testl(len, len); - jcc(Assembler::zero, FALSE_LABEL); + jcc(Assembler::zero, DONE); if ((AVX3Threshold == 0) && (UseAVX > 2) && // AVX512 VM_Version::supports_avx512vlbw() && VM_Version::supports_bmi2()) { - Label test_64_loop, test_tail; + Label test_64_loop, test_tail, BREAK_LOOP; Register tmp3_aliased = len; movl(tmp1, len); @@ -3460,16 +3423,15 @@ void C2_MacroAssembler::has_negatives(Register ary1, Register len, // Check whether our 64 elements of size byte contain negatives evpcmpgtb(mask1, vec2, Address(ary1, len, Address::times_1), Assembler::AVX_512bit); kortestql(mask1, mask1); - jcc(Assembler::notZero, TRUE_LABEL); + jcc(Assembler::notZero, BREAK_LOOP); addptr(len, 64); jccb(Assembler::notZero, test_64_loop); - bind(test_tail); // bail out when there is nothing to be done testl(tmp1, -1); - jcc(Assembler::zero, FALSE_LABEL); + jcc(Assembler::zero, DONE); // ~(~0 << len) applied up to two times (for 32-bit scenario) #ifdef _LP64 @@ -3506,21 +3468,30 @@ void C2_MacroAssembler::has_negatives(Register ary1, Register len, #endif evpcmpgtb(mask1, mask2, vec2, Address(ary1, 0), Assembler::AVX_512bit); ktestq(mask1, mask2); - jcc(Assembler::notZero, TRUE_LABEL); + jcc(Assembler::zero, DONE); - jmp(FALSE_LABEL); + bind(BREAK_LOOP); + // At least one byte in the last 64 bytes is negative. + // Set up to look at the last 64 bytes as if they were a tail + lea(ary1, Address(ary1, len, Address::times_1)); + addptr(result, len); + // Ignore the very last byte: if all others are positive, + // it must be negative, so we can skip right to the 2+1 byte + // end comparison at this point + orl(result, 63); + movl(len, 63); + // Fallthru to tail compare } else { - movl(result, len); // copy if (UseAVX >= 2 && UseSSE >= 2) { // With AVX2, use 32-byte vector compare - Label COMPARE_WIDE_VECTORS, COMPARE_TAIL; + Label COMPARE_WIDE_VECTORS, BREAK_LOOP; // Compare 32-byte vectors - andl(result, 0x0000001f); // tail count (in bytes) - andl(len, 0xffffffe0); // vector count (in bytes) - jccb(Assembler::zero, COMPARE_TAIL); + testl(len, 0xffffffe0); // vector count (in bytes) + jccb(Assembler::zero, TAIL_START); + andl(len, 0xffffffe0); lea(ary1, Address(ary1, len, Address::times_1)); negptr(len); @@ -3531,30 +3502,42 @@ void C2_MacroAssembler::has_negatives(Register ary1, Register len, bind(COMPARE_WIDE_VECTORS); vmovdqu(vec1, Address(ary1, len, Address::times_1)); vptest(vec1, vec2); - jccb(Assembler::notZero, TRUE_LABEL); + jccb(Assembler::notZero, BREAK_LOOP); addptr(len, 32); - jcc(Assembler::notZero, COMPARE_WIDE_VECTORS); + jccb(Assembler::notZero, COMPARE_WIDE_VECTORS); - testl(result, result); - jccb(Assembler::zero, FALSE_LABEL); + testl(result, 0x0000001f); // any bytes remaining? + jcc(Assembler::zero, DONE); - vmovdqu(vec1, Address(ary1, result, Address::times_1, -32)); + // Quick test using the already prepared vector mask + movl(len, result); + andl(len, 0x0000001f); + vmovdqu(vec1, Address(ary1, len, Address::times_1, -32)); vptest(vec1, vec2); - jccb(Assembler::notZero, TRUE_LABEL); - jmpb(FALSE_LABEL); + jcc(Assembler::zero, DONE); + // There are zeros, jump to the tail to determine exactly where + jmpb(TAIL_START); - bind(COMPARE_TAIL); // len is zero - movl(len, result); + bind(BREAK_LOOP); + // At least one byte in the last 32-byte vector is negative. + // Set up to look at the last 32 bytes as if they were a tail + lea(ary1, Address(ary1, len, Address::times_1)); + addptr(result, len); + // Ignore the very last byte: if all others are positive, + // it must be negative, so we can skip right to the 2+1 byte + // end comparison at this point + orl(result, 31); + movl(len, 31); // Fallthru to tail compare } else if (UseSSE42Intrinsics) { // With SSE4.2, use double quad vector compare - Label COMPARE_WIDE_VECTORS, COMPARE_TAIL; + Label COMPARE_WIDE_VECTORS, BREAK_LOOP; // Compare 16-byte vectors - andl(result, 0x0000000f); // tail count (in bytes) - andl(len, 0xfffffff0); // vector count (in bytes) - jcc(Assembler::zero, COMPARE_TAIL); + testl(len, 0xfffffff0); // vector count (in bytes) + jcc(Assembler::zero, TAIL_START); + andl(len, 0xfffffff0); lea(ary1, Address(ary1, len, Address::times_1)); negptr(len); @@ -3565,23 +3548,36 @@ void C2_MacroAssembler::has_negatives(Register ary1, Register len, bind(COMPARE_WIDE_VECTORS); movdqu(vec1, Address(ary1, len, Address::times_1)); ptest(vec1, vec2); - jcc(Assembler::notZero, TRUE_LABEL); + jccb(Assembler::notZero, BREAK_LOOP); addptr(len, 16); - jcc(Assembler::notZero, COMPARE_WIDE_VECTORS); + jccb(Assembler::notZero, COMPARE_WIDE_VECTORS); - testl(result, result); - jcc(Assembler::zero, FALSE_LABEL); + testl(result, 0x0000000f); // len is zero, any bytes remaining? + jcc(Assembler::zero, DONE); - movdqu(vec1, Address(ary1, result, Address::times_1, -16)); + // Quick test using the already prepared vector mask + movl(len, result); + andl(len, 0x0000000f); // tail count (in bytes) + movdqu(vec1, Address(ary1, len, Address::times_1, -16)); ptest(vec1, vec2); - jccb(Assembler::notZero, TRUE_LABEL); - jmpb(FALSE_LABEL); + jcc(Assembler::zero, DONE); + jmpb(TAIL_START); - bind(COMPARE_TAIL); // len is zero - movl(len, result); + bind(BREAK_LOOP); + // At least one byte in the last 16-byte vector is negative. + // Set up and look at the last 16 bytes as if they were a tail + lea(ary1, Address(ary1, len, Address::times_1)); + addptr(result, len); + // Ignore the very last byte: if all others are positive, + // it must be negative, so we can skip right to the 2+1 byte + // end comparison at this point + orl(result, 15); + movl(len, 15); // Fallthru to tail compare } } + + bind(TAIL_START); // Compare 4-byte vectors andl(len, 0xfffffffc); // vector count (in bytes) jccb(Assembler::zero, COMPARE_CHAR); @@ -3592,34 +3588,45 @@ void C2_MacroAssembler::has_negatives(Register ary1, Register len, bind(COMPARE_VECTORS); movl(tmp1, Address(ary1, len, Address::times_1)); andl(tmp1, 0x80808080); - jccb(Assembler::notZero, TRUE_LABEL); + jccb(Assembler::notZero, TAIL_ADJUST); addptr(len, 4); - jcc(Assembler::notZero, COMPARE_VECTORS); + jccb(Assembler::notZero, COMPARE_VECTORS); - // Compare trailing char (final 2 bytes), if any + // Compare trailing char (final 2-3 bytes), if any bind(COMPARE_CHAR); + testl(result, 0x2); // tail char jccb(Assembler::zero, COMPARE_BYTE); load_unsigned_short(tmp1, Address(ary1, 0)); andl(tmp1, 0x00008080); - jccb(Assembler::notZero, TRUE_LABEL); - subptr(result, 2); + jccb(Assembler::notZero, CHAR_ADJUST); lea(ary1, Address(ary1, 2)); bind(COMPARE_BYTE); testl(result, 0x1); // tail byte - jccb(Assembler::zero, FALSE_LABEL); + jccb(Assembler::zero, DONE); load_unsigned_byte(tmp1, Address(ary1, 0)); - andl(tmp1, 0x00000080); - jccb(Assembler::notEqual, TRUE_LABEL); - jmpb(FALSE_LABEL); - - bind(TRUE_LABEL); - movl(result, 1); // return true + testl(tmp1, 0x00000080); + jccb(Assembler::zero, DONE); + subptr(result, 1); jmpb(DONE); - bind(FALSE_LABEL); - xorl(result, result); // return false + bind(TAIL_ADJUST); + // there are negative bits in the last 4 byte block. + // Adjust result and check the next three bytes + addptr(result, len); + orl(result, 3); + lea(ary1, Address(ary1, len, Address::times_1)); + jmpb(COMPARE_CHAR); + + bind(CHAR_ADJUST); + // We are looking at a char + optional byte tail, and found that one + // of the bytes in the char is negative. Adjust the result, check the + // first byte and readjust if needed. + andl(result, 0xfffffffc); + testl(tmp1, 0x00000080); // little-endian, so lowest byte comes first + jccb(Assembler::notZero, DONE); + addptr(result, 1); // That's it bind(DONE); @@ -3629,6 +3636,7 @@ void C2_MacroAssembler::has_negatives(Register ary1, Register len, vpxor(vec2, vec2); } } + // Compare char[] or byte[] arrays aligned to 4 bytes or substrings. void C2_MacroAssembler::arrays_equals(bool is_array_equ, Register ary1, Register ary2, Register limit, Register result, Register chr, @@ -4052,62 +4060,406 @@ void C2_MacroAssembler::masked_op(int ideal_opc, int mask_len, KRegister dst, } } -#ifdef _LP64 -void C2_MacroAssembler::vector_mask_operation(int opc, Register dst, KRegister mask, - Register tmp, int masklen, int masksize, - int vec_enc) { - if(VM_Version::supports_avx512bw()) { - kmovql(tmp, mask); +/* + * Algorithm for vector D2L and F2I conversions:- + * a) Perform vector D2L/F2I cast. + * b) Choose fast path if none of the result vector lane contains 0x80000000 value. + * It signifies that source value could be any of the special floating point + * values(NaN,-Inf,Inf,Max,-Min). + * c) Set destination to zero if source is NaN value. + * d) Replace 0x80000000 with MaxInt if source lane contains a +ve value. + */ + +void C2_MacroAssembler::vector_castD2L_evex(XMMRegister dst, XMMRegister src, XMMRegister xtmp1, XMMRegister xtmp2, + KRegister ktmp1, KRegister ktmp2, AddressLiteral double_sign_flip, + Register scratch, int vec_enc) { + Label done; + evcvttpd2qq(dst, src, vec_enc); + evmovdqul(xtmp1, k0, double_sign_flip, false, vec_enc, scratch); + evpcmpeqq(ktmp1, xtmp1, dst, vec_enc); + kortestwl(ktmp1, ktmp1); + jccb(Assembler::equal, done); + + vpxor(xtmp2, xtmp2, xtmp2, vec_enc); + evcmppd(ktmp2, k0, src, src, Assembler::UNORD_Q, vec_enc); + evmovdquq(dst, ktmp2, xtmp2, true, vec_enc); + + kxorwl(ktmp1, ktmp1, ktmp2); + evcmppd(ktmp1, ktmp1, src, xtmp2, Assembler::NLT_UQ, vec_enc); + vpternlogq(xtmp2, 0x11, xtmp1, xtmp1, vec_enc); + evmovdquq(dst, ktmp1, xtmp2, true, vec_enc); + bind(done); +} + +void C2_MacroAssembler::vector_castF2I_avx(XMMRegister dst, XMMRegister src, XMMRegister xtmp1, + XMMRegister xtmp2, XMMRegister xtmp3, XMMRegister xtmp4, + AddressLiteral float_sign_flip, Register scratch, int vec_enc) { + Label done; + vcvttps2dq(dst, src, vec_enc); + vmovdqu(xtmp1, float_sign_flip, scratch, vec_enc); + vpcmpeqd(xtmp2, dst, xtmp1, vec_enc); + vptest(xtmp2, xtmp2, vec_enc); + jccb(Assembler::equal, done); + + vpcmpeqd(xtmp4, xtmp4, xtmp4, vec_enc); + vpxor(xtmp1, xtmp1, xtmp4, vec_enc); + + vpxor(xtmp4, xtmp4, xtmp4, vec_enc); + vcmpps(xtmp3, src, src, Assembler::UNORD_Q, vec_enc); + vblendvps(dst, dst, xtmp4, xtmp3, vec_enc); + + // Recompute the mask for remaining special value. + vpxor(xtmp2, xtmp2, xtmp3, vec_enc); + // Extract SRC values corresponding to TRUE mask lanes. + vpand(xtmp4, xtmp2, src, vec_enc); + // Flip mask bits so that MSB bit of MASK lanes corresponding to +ve special + // values are set. + vpxor(xtmp3, xtmp2, xtmp4, vec_enc); + + vblendvps(dst, dst, xtmp1, xtmp3, vec_enc); + bind(done); +} + +void C2_MacroAssembler::vector_castF2I_evex(XMMRegister dst, XMMRegister src, XMMRegister xtmp1, XMMRegister xtmp2, + KRegister ktmp1, KRegister ktmp2, AddressLiteral float_sign_flip, + Register scratch, int vec_enc) { + Label done; + vcvttps2dq(dst, src, vec_enc); + evmovdqul(xtmp1, k0, float_sign_flip, false, vec_enc, scratch); + Assembler::evpcmpeqd(ktmp1, k0, xtmp1, dst, vec_enc); + kortestwl(ktmp1, ktmp1); + jccb(Assembler::equal, done); + + vpxor(xtmp2, xtmp2, xtmp2, vec_enc); + evcmpps(ktmp2, k0, src, src, Assembler::UNORD_Q, vec_enc); + evmovdqul(dst, ktmp2, xtmp2, true, vec_enc); + + kxorwl(ktmp1, ktmp1, ktmp2); + evcmpps(ktmp1, ktmp1, src, xtmp2, Assembler::NLT_UQ, vec_enc); + vpternlogd(xtmp2, 0x11, xtmp1, xtmp1, vec_enc); + evmovdqul(dst, ktmp1, xtmp2, true, vec_enc); + bind(done); +} + +void C2_MacroAssembler::vector_unsigned_cast(XMMRegister dst, XMMRegister src, int vlen_enc, + BasicType from_elem_bt, BasicType to_elem_bt) { + switch (from_elem_bt) { + case T_BYTE: + switch (to_elem_bt) { + case T_SHORT: vpmovzxbw(dst, src, vlen_enc); break; + case T_INT: vpmovzxbd(dst, src, vlen_enc); break; + case T_LONG: vpmovzxbq(dst, src, vlen_enc); break; + default: ShouldNotReachHere(); + } + break; + case T_SHORT: + switch (to_elem_bt) { + case T_INT: vpmovzxwd(dst, src, vlen_enc); break; + case T_LONG: vpmovzxwq(dst, src, vlen_enc); break; + default: ShouldNotReachHere(); + } + break; + case T_INT: + assert(to_elem_bt == T_LONG, ""); + vpmovzxdq(dst, src, vlen_enc); + break; + default: + ShouldNotReachHere(); + } +} + +void C2_MacroAssembler::evpternlog(XMMRegister dst, int func, KRegister mask, XMMRegister src2, XMMRegister src3, + bool merge, BasicType bt, int vlen_enc) { + if (bt == T_INT) { + evpternlogd(dst, func, mask, src2, src3, merge, vlen_enc); } else { - assert(masklen <= 16, ""); - kmovwl(tmp, mask); + assert(bt == T_LONG, ""); + evpternlogq(dst, func, mask, src2, src3, merge, vlen_enc); } - if (masksize < 16) { - andq(tmp, (((jlong)1 << masklen) - 1)); +} + +void C2_MacroAssembler::evpternlog(XMMRegister dst, int func, KRegister mask, XMMRegister src2, Address src3, + bool merge, BasicType bt, int vlen_enc) { + if (bt == T_INT) { + evpternlogd(dst, func, mask, src2, src3, merge, vlen_enc); + } else { + assert(bt == T_LONG, ""); + evpternlogq(dst, func, mask, src2, src3, merge, vlen_enc); } +} + +#ifdef _LP64 +void C2_MacroAssembler::vector_long_to_maskvec(XMMRegister dst, Register src, Register rtmp1, + Register rtmp2, XMMRegister xtmp, int mask_len, + int vec_enc) { + int index = 0; + int vindex = 0; + mov64(rtmp1, 0x0101010101010101L); + pdep(rtmp1, src, rtmp1); + if (mask_len > 8) { + movq(rtmp2, src); + vpxor(xtmp, xtmp, xtmp, vec_enc); + movq(xtmp, rtmp1); + } + movq(dst, rtmp1); + + mask_len -= 8; + while (mask_len > 0) { + assert ((mask_len & 0x7) == 0, "mask must be multiple of 8"); + index++; + if ((index % 2) == 0) { + pxor(xtmp, xtmp); + } + mov64(rtmp1, 0x0101010101010101L); + shrq(rtmp2, 8); + pdep(rtmp1, rtmp2, rtmp1); + pinsrq(xtmp, rtmp1, index % 2); + vindex = index / 2; + if (vindex) { + // Write entire 16 byte vector when both 64 bit + // lanes are update to save redundant instructions. + if (index % 2) { + vinsertf128(dst, dst, xtmp, vindex); + } + } else { + vmovdqu(dst, xtmp); + } + mask_len -= 8; + } +} + +void C2_MacroAssembler::vector_mask_operation_helper(int opc, Register dst, Register tmp, int masklen) { switch(opc) { case Op_VectorMaskTrueCount: popcntq(dst, tmp); break; case Op_VectorMaskLastTrue: - mov64(dst, -1); - bsrq(tmp, tmp); - cmov(Assembler::notZero, dst, tmp); + if (VM_Version::supports_lzcnt()) { + lzcntq(tmp, tmp); + movl(dst, 63); + subl(dst, tmp); + } else { + movl(dst, -1); + bsrq(tmp, tmp); + cmov32(Assembler::notZero, dst, tmp); + } break; case Op_VectorMaskFirstTrue: - mov64(dst, masklen); - bsfq(tmp, tmp); - cmov(Assembler::notZero, dst, tmp); + if (VM_Version::supports_bmi1()) { + if (masklen < 32) { + orl(tmp, 1 << masklen); + tzcntl(dst, tmp); + } else if (masklen == 32) { + tzcntl(dst, tmp); + } else { + assert(masklen == 64, ""); + tzcntq(dst, tmp); + } + } else { + if (masklen < 32) { + orl(tmp, 1 << masklen); + bsfl(dst, tmp); + } else { + assert(masklen == 32 || masklen == 64, ""); + movl(dst, masklen); + if (masklen == 32) { + bsfl(tmp, tmp); + } else { + bsfq(tmp, tmp); + } + cmov32(Assembler::notZero, dst, tmp); + } + } + break; + case Op_VectorMaskToLong: + assert(dst == tmp, "Dst and tmp should be the same for toLong operations"); break; default: assert(false, "Unhandled mask operation"); } } -void C2_MacroAssembler::vector_mask_operation(int opc, Register dst, XMMRegister mask, XMMRegister xtmp, - XMMRegister xtmp1, Register tmp, int masklen, int masksize, - int vec_enc) { - assert(VM_Version::supports_avx(), ""); - vpxor(xtmp, xtmp, xtmp, vec_enc); - vpsubb(xtmp, xtmp, mask, vec_enc); - vpmovmskb(tmp, xtmp, vec_enc); - if (masksize < 16) { - andq(tmp, (((jlong)1 << masklen) - 1)); +void C2_MacroAssembler::vector_mask_operation(int opc, Register dst, KRegister mask, Register tmp, + int masklen, int masksize, int vec_enc) { + assert(VM_Version::supports_popcnt(), ""); + + if(VM_Version::supports_avx512bw()) { + kmovql(tmp, mask); + } else { + assert(masklen <= 16, ""); + kmovwl(tmp, mask); } - switch(opc) { - case Op_VectorMaskTrueCount: - popcntq(dst, tmp); + + // Mask generated out of partial vector comparisons/replicate/mask manipulation + // operations needs to be clipped. + if (masksize < 16 && opc != Op_VectorMaskFirstTrue) { + andq(tmp, (1 << masklen) - 1); + } + + vector_mask_operation_helper(opc, dst, tmp, masklen); +} + +void C2_MacroAssembler::vector_mask_operation(int opc, Register dst, XMMRegister mask, XMMRegister xtmp, + Register tmp, int masklen, BasicType bt, int vec_enc) { + assert(vec_enc == AVX_128bit && VM_Version::supports_avx() || + vec_enc == AVX_256bit && (VM_Version::supports_avx2() || type2aelembytes(bt) >= 4), ""); + assert(VM_Version::supports_popcnt(), ""); + + bool need_clip = false; + switch(bt) { + case T_BOOLEAN: + // While masks of other types contain 0, -1; boolean masks contain lane values of 0, 1 + vpxor(xtmp, xtmp, xtmp, vec_enc); + vpsubb(xtmp, xtmp, mask, vec_enc); + vpmovmskb(tmp, xtmp, vec_enc); + need_clip = masklen < 16; break; - case Op_VectorMaskLastTrue: - mov64(dst, -1); - bsrq(tmp, tmp); - cmov(Assembler::notZero, dst, tmp); + case T_BYTE: + vpmovmskb(tmp, mask, vec_enc); + need_clip = masklen < 16; break; - case Op_VectorMaskFirstTrue: - mov64(dst, masklen); - bsfq(tmp, tmp); - cmov(Assembler::notZero, dst, tmp); + case T_SHORT: + vpacksswb(xtmp, mask, mask, vec_enc); + if (masklen >= 16) { + vpermpd(xtmp, xtmp, 8, vec_enc); + } + vpmovmskb(tmp, xtmp, Assembler::AVX_128bit); + need_clip = masklen < 16; break; - default: assert(false, "Unhandled mask operation"); + case T_INT: + case T_FLOAT: + vmovmskps(tmp, mask, vec_enc); + need_clip = masklen < 4; + break; + case T_LONG: + case T_DOUBLE: + vmovmskpd(tmp, mask, vec_enc); + need_clip = masklen < 2; + break; + default: assert(false, "Unhandled type, %s", type2name(bt)); + } + + // Mask generated out of partial vector comparisons/replicate/mask manipulation + // operations needs to be clipped. + if (need_clip && opc != Op_VectorMaskFirstTrue) { + // need_clip implies masklen < 32 + andq(tmp, (1 << masklen) - 1); + } + + vector_mask_operation_helper(opc, dst, tmp, masklen); +} +#endif + +void C2_MacroAssembler::vector_maskall_operation(KRegister dst, Register src, int mask_len) { + if (VM_Version::supports_avx512bw()) { + if (mask_len > 32) { + kmovql(dst, src); + } else { + kmovdl(dst, src); + if (mask_len != 32) { + kshiftrdl(dst, dst, 32 - mask_len); + } + } + } else { + assert(mask_len <= 16, ""); + kmovwl(dst, src); + if (mask_len != 16) { + kshiftrwl(dst, dst, 16 - mask_len); + } + } +} + + +// +// Following is lookup table based popcount computation algorithm:- +// Index Bit set count +// [ 0000 -> 0, +// 0001 -> 1, +// 0010 -> 1, +// 0011 -> 2, +// 0100 -> 1, +// 0101 -> 2, +// 0110 -> 2, +// 0111 -> 3, +// 1000 -> 1, +// 1001 -> 2, +// 1010 -> 3, +// 1011 -> 3, +// 1100 -> 2, +// 1101 -> 3, +// 1111 -> 4 ] +// a. Count the number of 1s in 4 LSB bits of each byte. These bits are used as +// shuffle indices for lookup table access. +// b. Right shift each byte of vector lane by 4 positions. +// c. Count the number of 1s in 4 MSB bits each byte. These bits are used as +// shuffle indices for lookup table access. +// d. Add the bitset count of upper and lower 4 bits of each byte. +// e. Unpack double words to quad words and compute sum of absolute difference of bitset +// count of all the bytes of a quadword. +// f. Perform step e. for upper 128bit vector lane. +// g. Pack the bitset count of quadwords back to double word. +// h. Unpacking and packing operations are not needed for 64bit vector lane. +void C2_MacroAssembler::vector_popcount_int(XMMRegister dst, XMMRegister src, XMMRegister xtmp1, + XMMRegister xtmp2, XMMRegister xtmp3, Register rtmp, + int vec_enc) { + if (VM_Version::supports_avx512_vpopcntdq()) { + vpopcntd(dst, src, vec_enc); + } else { + assert((vec_enc == Assembler::AVX_512bit && VM_Version::supports_avx512bw()) || VM_Version::supports_avx2(), ""); + movl(rtmp, 0x0F0F0F0F); + movdl(xtmp1, rtmp); + vpbroadcastd(xtmp1, xtmp1, vec_enc); + if (Assembler::AVX_512bit == vec_enc) { + evmovdqul(xtmp2, k0, ExternalAddress(StubRoutines::x86::vector_popcount_lut()), false, vec_enc, rtmp); + } else { + vmovdqu(xtmp2, ExternalAddress(StubRoutines::x86::vector_popcount_lut()), rtmp); + } + vpand(xtmp3, src, xtmp1, vec_enc); + vpshufb(xtmp3, xtmp2, xtmp3, vec_enc); + vpsrlw(dst, src, 4, vec_enc); + vpand(dst, dst, xtmp1, vec_enc); + vpshufb(dst, xtmp2, dst, vec_enc); + vpaddb(xtmp3, dst, xtmp3, vec_enc); + vpxor(xtmp1, xtmp1, xtmp1, vec_enc); + vpunpckhdq(dst, xtmp3, xtmp1, vec_enc); + vpsadbw(dst, dst, xtmp1, vec_enc); + vpunpckldq(xtmp2, xtmp3, xtmp1, vec_enc); + vpsadbw(xtmp2, xtmp2, xtmp1, vec_enc); + vpackuswb(dst, xtmp2, dst, vec_enc); + } +} + +void C2_MacroAssembler::vector_popcount_long(XMMRegister dst, XMMRegister src, XMMRegister xtmp1, + XMMRegister xtmp2, XMMRegister xtmp3, Register rtmp, + int vec_enc) { + if (VM_Version::supports_avx512_vpopcntdq()) { + vpopcntq(dst, src, vec_enc); + } else if (vec_enc == Assembler::AVX_512bit) { + assert(VM_Version::supports_avx512bw(), ""); + movl(rtmp, 0x0F0F0F0F); + movdl(xtmp1, rtmp); + vpbroadcastd(xtmp1, xtmp1, vec_enc); + evmovdqul(xtmp2, k0, ExternalAddress(StubRoutines::x86::vector_popcount_lut()), true, vec_enc, rtmp); + vpandq(xtmp3, src, xtmp1, vec_enc); + vpshufb(xtmp3, xtmp2, xtmp3, vec_enc); + vpsrlw(dst, src, 4, vec_enc); + vpandq(dst, dst, xtmp1, vec_enc); + vpshufb(dst, xtmp2, dst, vec_enc); + vpaddb(xtmp3, dst, xtmp3, vec_enc); + vpxorq(xtmp1, xtmp1, xtmp1, vec_enc); + vpsadbw(dst, xtmp3, xtmp1, vec_enc); + } else { + // We do not see any performance benefit of running + // above instruction sequence on 256 bit vector which + // can operate over maximum 4 long elements. + ShouldNotReachHere(); } + evpmovqd(dst, dst, vec_enc); +} + +#ifndef _LP64 +void C2_MacroAssembler::vector_maskall_operation32(KRegister dst, Register src, KRegister tmp, int mask_len) { + assert(VM_Version::supports_avx512bw(), ""); + kmovdl(tmp, src); + kunpckdql(dst, tmp, tmp); } #endif diff --git a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp index 8efa36a8101db5843323e66a00ffbbe1cf18433a..5ecdf20700dfb11c584898481acdf48dbd2dfd49 100644 --- a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -144,14 +144,10 @@ public: void load_vector_mask(XMMRegister dst, XMMRegister src, int vlen_in_bytes, BasicType elem_bt, bool is_legacy); void load_vector_mask(KRegister dst, XMMRegister src, XMMRegister xtmp, Register tmp, bool novlbwdq, int vlen_enc); + void load_vector(XMMRegister dst, Address src, int vlen_in_bytes); + void load_vector(XMMRegister dst, AddressLiteral src, int vlen_in_bytes, Register rscratch = rscratch1); void load_iota_indices(XMMRegister dst, Register scratch, int vlen_in_bytes); - // vector compare - void vpcmpu(BasicType typ, XMMRegister dst, XMMRegister src1, XMMRegister src2, ComparisonPredicate comparison, int vlen_in_bytes, - XMMRegister vtmp1, XMMRegister vtmp2, Register scratch); - void vpcmpu32(BasicType typ, XMMRegister dst, XMMRegister src1, XMMRegister src2, ComparisonPredicate comparison, int vlen_in_bytes, - XMMRegister vtmp1, XMMRegister vtmp2, XMMRegister vtmp3, Register scratch); - // Reductions for vectors of bytes, shorts, ints, longs, floats, and doubles. // dst = src1 reduce(op, src2) using vtmp as temps @@ -224,11 +220,22 @@ public: public: #ifdef _LP64 + void vector_mask_operation_helper(int opc, Register dst, Register tmp, int masklen); + void vector_mask_operation(int opc, Register dst, KRegister mask, Register tmp, int masklen, int masksize, int vec_enc); - void vector_mask_operation(int opc, Register dst, XMMRegister mask, XMMRegister xtmp, XMMRegister xtmp1, - Register tmp, int masklen, int masksize, int vec_enc); + void vector_mask_operation(int opc, Register dst, XMMRegister mask, XMMRegister xtmp, + Register tmp, int masklen, BasicType bt, int vec_enc); + void vector_long_to_maskvec(XMMRegister dst, Register src, Register rtmp1, + Register rtmp2, XMMRegister xtmp, int mask_len, int vec_enc); +#endif + + void vector_maskall_operation(KRegister dst, Register src, int mask_len); + +#ifndef _LP64 + void vector_maskall_operation32(KRegister dst, Register src, KRegister ktmp, int mask_len); #endif + void string_indexof_char(Register str1, Register cnt1, Register ch, Register result, XMMRegister vec1, XMMRegister vec2, XMMRegister vec3, Register tmp); @@ -264,11 +271,10 @@ public: XMMRegister vec1, int ae, KRegister mask = knoreg); // Search for Non-ASCII character (Negative byte value) in a byte array, - // return true if it has any and false otherwise. - void has_negatives(Register ary1, Register len, - Register result, Register tmp1, - XMMRegister vec1, XMMRegister vec2, KRegister mask1 = knoreg, KRegister mask2 = knoreg); - + // return index of the first such character, otherwise len. + void count_positives(Register ary1, Register len, + Register result, Register tmp1, + XMMRegister vec1, XMMRegister vec2, KRegister mask1 = knoreg, KRegister mask2 = knoreg); // Compare char[] or byte[] arrays. void arrays_equals(bool is_array_equ, Register ary1, Register ary2, Register limit, Register result, Register chr, @@ -288,4 +294,34 @@ public: void masked_op(int ideal_opc, int mask_len, KRegister dst, KRegister src1, KRegister src2); + + void vector_castF2I_avx(XMMRegister dst, XMMRegister src, XMMRegister xtmp1, + XMMRegister xtmp2, XMMRegister xtmp3, XMMRegister xtmp4, + AddressLiteral float_sign_flip, Register scratch, int vec_enc); + + void vector_castF2I_evex(XMMRegister dst, XMMRegister src, XMMRegister xtmp1, XMMRegister xtmp2, + KRegister ktmp1, KRegister ktmp2, AddressLiteral float_sign_flip, + Register scratch, int vec_enc); + + void vector_castD2L_evex(XMMRegister dst, XMMRegister src, XMMRegister xtmp1, XMMRegister xtmp2, + KRegister ktmp1, KRegister ktmp2, AddressLiteral double_sign_flip, + Register scratch, int vec_enc); + + void vector_unsigned_cast(XMMRegister dst, XMMRegister src, int vlen_enc, + BasicType from_elem_bt, BasicType to_elem_bt); + + void evpternlog(XMMRegister dst, int func, KRegister mask, XMMRegister src2, XMMRegister src3, + bool merge, BasicType bt, int vlen_enc); + + void evpternlog(XMMRegister dst, int func, KRegister mask, XMMRegister src2, Address src3, + bool merge, BasicType bt, int vlen_enc); + + void vector_popcount_int(XMMRegister dst, XMMRegister src, XMMRegister xtmp1, + XMMRegister xtmp2, XMMRegister xtmp3, Register rtmp, + int vec_enc); + + void vector_popcount_long(XMMRegister dst, XMMRegister src, XMMRegister xtmp1, + XMMRegister xtmp2, XMMRegister xtmp3, Register rtmp, + int vec_enc); + #endif // CPU_X86_C2_MACROASSEMBLER_X86_HPP diff --git a/src/hotspot/cpu/x86/c2_intelJccErratum_x86.hpp b/src/hotspot/cpu/x86/c2_intelJccErratum_x86.hpp index f3f66f3d7bc15f6d00aee1ef61a3a92df4538049..415d8a99933e2159f9ba2c9aa576a284c6595e9f 100644 --- a/src/hotspot/cpu/x86/c2_intelJccErratum_x86.hpp +++ b/src/hotspot/cpu/x86/c2_intelJccErratum_x86.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -25,7 +25,7 @@ #ifndef CPU_X86_INTELJCCERRATUM_X86_HPP #define CPU_X86_INTELJCCERRATUM_X86_HPP -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" #include "utilities/globalDefinitions.hpp" class Block; diff --git a/src/hotspot/cpu/x86/copy_x86.hpp b/src/hotspot/cpu/x86/copy_x86.hpp index dc150a568afc76bfa0c313cb33745b3d2f18f318..1798e74eb0636f9b16b53beaee83397241f379d8 100644 --- a/src/hotspot/cpu/x86/copy_x86.hpp +++ b/src/hotspot/cpu/x86/copy_x86.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -59,4 +59,278 @@ static void pd_zero_to_bytes(void* to, size_t count) { (void)memset(to, 0, count); } +static void pd_conjoint_words(const HeapWord* from, HeapWord* to, size_t count) { +#if defined AMD64 || defined _WINDOWS + (void)memmove(to, from, count * HeapWordSize); +#else + // Includes a zero-count check. + intx temp = 0; + __asm__ volatile(" testl %6,%6 ;" + " jz 7f ;" + " cmpl %4,%5 ;" + " leal -4(%4,%6,4),%3;" + " jbe 1f ;" + " cmpl %7,%5 ;" + " jbe 4f ;" + "1: cmpl $32,%6 ;" + " ja 3f ;" + " subl %4,%1 ;" + "2: movl (%4),%3 ;" + " movl %7,(%5,%4,1) ;" + " addl $4,%0 ;" + " subl $1,%2 ;" + " jnz 2b ;" + " jmp 7f ;" + "3: rep; smovl ;" + " jmp 7f ;" + "4: cmpl $32,%2 ;" + " movl %7,%0 ;" + " leal -4(%5,%6,4),%1;" + " ja 6f ;" + " subl %4,%1 ;" + "5: movl (%4),%3 ;" + " movl %7,(%5,%4,1) ;" + " subl $4,%0 ;" + " subl $1,%2 ;" + " jnz 5b ;" + " jmp 7f ;" + "6: std ;" + " rep; smovl ;" + " cld ;" + "7: nop " + : "=S" (from), "=D" (to), "=c" (count), "=r" (temp) + : "0" (from), "1" (to), "2" (count), "3" (temp) + : "memory", "flags"); +#endif // AMD64 +} + +static void pd_disjoint_words(const HeapWord* from, HeapWord* to, size_t count) { +#ifdef AMD64 + switch (count) { + case 8: to[7] = from[7]; + case 7: to[6] = from[6]; + case 6: to[5] = from[5]; + case 5: to[4] = from[4]; + case 4: to[3] = from[3]; + case 3: to[2] = from[2]; + case 2: to[1] = from[1]; + case 1: to[0] = from[0]; + case 0: break; + default: + (void)memcpy(to, from, count * HeapWordSize); + break; + } +#else +#if defined _WINDOWS + (void)memcpy(to, from, count * HeapWordSize); +#else + // Includes a zero-count check. + intx temp = 0; + __asm__ volatile(" testl %6,%6 ;" + " jz 3f ;" + " cmpl $32,%6 ;" + " ja 2f ;" + " subl %4,%1 ;" + "1: movl (%4),%3 ;" + " movl %7,(%5,%4,1);" + " addl $4,%0 ;" + " subl $1,%2 ;" + " jnz 1b ;" + " jmp 3f ;" + "2: rep; smovl ;" + "3: nop " + : "=S" (from), "=D" (to), "=c" (count), "=r" (temp) + : "0" (from), "1" (to), "2" (count), "3" (temp) + : "memory", "cc"); +#endif // _WINDOWS +#endif // AMD64 +} + +static void pd_disjoint_words_atomic(const HeapWord* from, HeapWord* to, size_t count) { +#ifdef AMD64 + shared_disjoint_words_atomic(from, to, count); +#else + // pd_disjoint_words is word-atomic in this implementation. + pd_disjoint_words(from, to, count); +#endif // AMD64 +} + +static void pd_aligned_conjoint_words(const HeapWord* from, HeapWord* to, size_t count) { + pd_conjoint_words(from, to, count); +} + +static void pd_aligned_disjoint_words(const HeapWord* from, HeapWord* to, size_t count) { + pd_disjoint_words(from, to, count); +} + +static void pd_conjoint_bytes(const void* from, void* to, size_t count) { +#if defined AMD64 || defined _WINDOWS + (void)memmove(to, from, count); +#else + // Includes a zero-count check. + intx temp = 0; + __asm__ volatile(" testl %6,%6 ;" + " jz 13f ;" + " cmpl %4,%5 ;" + " leal -1(%4,%6),%3 ;" + " jbe 1f ;" + " cmpl %7,%5 ;" + " jbe 8f ;" + "1: cmpl $3,%6 ;" + " jbe 6f ;" + " movl %6,%3 ;" + " movl $4,%2 ;" + " subl %4,%2 ;" + " andl $3,%2 ;" + " jz 2f ;" + " subl %6,%3 ;" + " rep; smovb ;" + "2: movl %7,%2 ;" + " shrl $2,%2 ;" + " jz 5f ;" + " cmpl $32,%2 ;" + " ja 4f ;" + " subl %4,%1 ;" + "3: movl (%4),%%edx ;" + " movl %%edx,(%5,%4,1);" + " addl $4,%0 ;" + " subl $1,%2 ;" + " jnz 3b ;" + " addl %4,%1 ;" + " jmp 5f ;" + "4: rep; smovl ;" + "5: movl %7,%2 ;" + " andl $3,%2 ;" + " jz 13f ;" + "6: xorl %7,%3 ;" + "7: movb (%4,%7,1),%%dl ;" + " movb %%dl,(%5,%7,1) ;" + " addl $1,%3 ;" + " subl $1,%2 ;" + " jnz 7b ;" + " jmp 13f ;" + "8: std ;" + " cmpl $12,%2 ;" + " ja 9f ;" + " movl %7,%0 ;" + " leal -1(%6,%5),%1 ;" + " jmp 11f ;" + "9: xchgl %3,%2 ;" + " movl %6,%0 ;" + " addl $1,%2 ;" + " leal -1(%7,%5),%1 ;" + " andl $3,%2 ;" + " jz 10f ;" + " subl %6,%3 ;" + " rep; smovb ;" + "10: movl %7,%2 ;" + " subl $3,%0 ;" + " shrl $2,%2 ;" + " subl $3,%1 ;" + " rep; smovl ;" + " andl $3,%3 ;" + " jz 12f ;" + " movl %7,%2 ;" + " addl $3,%0 ;" + " addl $3,%1 ;" + "11: rep; smovb ;" + "12: cld ;" + "13: nop ;" + : "=S" (from), "=D" (to), "=c" (count), "=r" (temp) + : "0" (from), "1" (to), "2" (count), "3" (temp) + : "memory", "flags", "%edx"); +#endif // AMD64 +} + +static void pd_conjoint_bytes_atomic(const void* from, void* to, size_t count) { + pd_conjoint_bytes(from, to, count); +} + +// Windows has a different implementation +#ifndef _WINDOWS +static void pd_conjoint_jshorts_atomic(const jshort* from, jshort* to, size_t count) { + _Copy_conjoint_jshorts_atomic(from, to, count); +} + +static void pd_conjoint_jints_atomic(const jint* from, jint* to, size_t count) { +#ifdef AMD64 + _Copy_conjoint_jints_atomic(from, to, count); +#else + assert(HeapWordSize == BytesPerInt, "heapwords and jints must be the same size"); + // pd_conjoint_words is word-atomic in this implementation. + pd_conjoint_words((const HeapWord*)from, (HeapWord*)to, count); +#endif // AMD64 +} + +static void pd_conjoint_jlongs_atomic(const jlong* from, jlong* to, size_t count) { +#ifdef AMD64 + _Copy_conjoint_jlongs_atomic(from, to, count); +#else + // Guarantee use of fild/fistp or xmm regs via some asm code, because compilers won't. + if (from > to) { + while (count-- > 0) { + __asm__ volatile("fildll (%0); fistpll (%1)" + : + : "r" (from), "r" (to) + : "memory" ); + ++from; + ++to; + } + } else { + while (count-- > 0) { + __asm__ volatile("fildll (%0,%2,8); fistpll (%1,%2,8)" + : + : "r" (from), "r" (to), "r" (count) + : "memory" ); + } + } +#endif // AMD64 +} + +static void pd_conjoint_oops_atomic(const oop* from, oop* to, size_t count) { +#ifdef AMD64 + assert(BytesPerLong == BytesPerOop, "jlongs and oops must be the same size"); + _Copy_conjoint_jlongs_atomic((const jlong*)from, (jlong*)to, count); +#else + assert(HeapWordSize == BytesPerOop, "heapwords and oops must be the same size"); + // pd_conjoint_words is word-atomic in this implementation. + pd_conjoint_words((const HeapWord*)from, (HeapWord*)to, count); +#endif // AMD64 +} + +static void pd_arrayof_conjoint_bytes(const HeapWord* from, HeapWord* to, size_t count) { + _Copy_arrayof_conjoint_bytes(from, to, count); +} + +static void pd_arrayof_conjoint_jshorts(const HeapWord* from, HeapWord* to, size_t count) { + _Copy_arrayof_conjoint_jshorts(from, to, count); +} + +static void pd_arrayof_conjoint_jints(const HeapWord* from, HeapWord* to, size_t count) { +#ifdef AMD64 + _Copy_arrayof_conjoint_jints(from, to, count); +#else + pd_conjoint_jints_atomic((const jint*)from, (jint*)to, count); +#endif // AMD64 +} + +static void pd_arrayof_conjoint_jlongs(const HeapWord* from, HeapWord* to, size_t count) { +#ifdef AMD64 + _Copy_arrayof_conjoint_jlongs(from, to, count); +#else + pd_conjoint_jlongs_atomic((const jlong*)from, (jlong*)to, count); +#endif // AMD64 +} + +static void pd_arrayof_conjoint_oops(const HeapWord* from, HeapWord* to, size_t count) { +#ifdef AMD64 + assert(BytesPerLong == BytesPerOop, "jlongs and oops must be the same size"); + _Copy_arrayof_conjoint_jlongs(from, to, count); +#else + pd_conjoint_oops_atomic((const oop*)from, (oop*)to, count); +#endif // AMD64 +} + +#endif // _WINDOWS + #endif // CPU_X86_COPY_X86_HPP diff --git a/src/hotspot/cpu/x86/frame_x86.inline.hpp b/src/hotspot/cpu/x86/frame_x86.inline.hpp index 733a357d5fe3e7fe9a9e445b64b1ebd4b7c381ea..23072238e16aa3caf798e6f0690f3e5f4ca9ccaf 100644 --- a/src/hotspot/cpu/x86/frame_x86.inline.hpp +++ b/src/hotspot/cpu/x86/frame_x86.inline.hpp @@ -138,10 +138,13 @@ inline intptr_t* frame::id(void) const { return unextended_sp(); } inline bool frame::is_older(intptr_t* id) const { assert(this->id() != NULL && id != NULL, "NULL frame id"); return this->id() > id ; } - - inline intptr_t* frame::link() const { return (intptr_t*) *(intptr_t **)addr_at(link_offset); } +inline intptr_t* frame::link_or_null() const { + intptr_t** ptr = (intptr_t **)addr_at(link_offset); + return os::is_readable_pointer(ptr) ? *ptr : NULL; +} + inline intptr_t* frame::unextended_sp() const { return _unextended_sp; } // Return address: diff --git a/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.cpp b/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.cpp index 645c2fec8bd9e9a49c7ae77293cf680ddf1ac8cd..475a92d0f43a5264b37765917bb07f7c764f8c1e 100644 --- a/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.cpp @@ -67,7 +67,7 @@ void G1BarrierSetAssembler::gen_write_ref_array_pre_barrier(MacroAssembler* masm __ jcc(Assembler::equal, filtered); - __ pusha(); // push registers + __ push_call_clobbered_registers(false /* save_fpu */); #ifdef _LP64 if (count == c_rarg0) { if (addr == c_rarg1) { @@ -90,7 +90,7 @@ void G1BarrierSetAssembler::gen_write_ref_array_pre_barrier(MacroAssembler* masm __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_array_pre_oop_entry), addr, count); #endif - __ popa(); + __ pop_call_clobbered_registers(false /* save_fpu */); __ bind(filtered); } @@ -98,7 +98,7 @@ void G1BarrierSetAssembler::gen_write_ref_array_pre_barrier(MacroAssembler* masm void G1BarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators, Register addr, Register count, Register tmp) { - __ pusha(); // push registers (overkill) + __ push_call_clobbered_registers(false /* save_fpu */); #ifdef _LP64 if (c_rarg0 == count) { // On win64 c_rarg0 == rcx assert_different_registers(c_rarg1, addr); @@ -114,7 +114,7 @@ void G1BarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembler* mas __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_array_post_entry), addr, count); #endif - __ popa(); + __ pop_call_clobbered_registers(false /* save_fpu */); } void G1BarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, @@ -204,14 +204,15 @@ void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm, __ jmp(done); __ bind(runtime); - // save the live input values - if(tosca_live) __ push(rax); - if (obj != noreg && obj != rax) - __ push(obj); + // Determine and save the live input values + RegSet saved; + if (tosca_live) saved += RegSet::of(rax); + if (obj != noreg && obj != rax) saved += RegSet::of(obj); + if (pre_val != rax) saved += RegSet::of(pre_val); + NOT_LP64( saved += RegSet::of(thread); ) - if (pre_val != rax) - __ push(pre_val); + __ push_set(saved); // Calling the runtime using the regular call_VM_leaf mechanism generates // code (generated by InterpreterMacroAssember::call_VM_leaf_base) @@ -225,8 +226,6 @@ void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm, // So when we do not have have a full interpreter frame on the stack // expand_call should be passed true. - NOT_LP64( __ push(thread); ) - if (expand_call) { LP64_ONLY( assert(pre_val != c_rarg1, "smashed arg"); ) #ifdef _LP64 @@ -244,17 +243,7 @@ void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm, } else { __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_pre_entry), pre_val, thread); } - - NOT_LP64( __ pop(thread); ) - - // save the live input values - if (pre_val != rax) - __ pop(pre_val); - - if (obj != noreg && obj != rax) - __ pop(obj); - - if(tosca_live) __ pop(rax); + __ pop_set(saved); __ bind(done); } @@ -298,7 +287,7 @@ void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm, const Register cardtable = tmp2; __ movptr(card_addr, store_addr); - __ shrptr(card_addr, CardTable::card_shift); + __ 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()); @@ -328,21 +317,16 @@ void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm, __ bind(runtime); // save the live input values - __ push(store_addr); -#ifdef _LP64 - __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry), card_addr, r15_thread); -#else - __ push(thread); + 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(thread); -#endif - __ pop(store_addr); + __ pop_set(saved); __ bind(done); } void G1BarrierSetAssembler::oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, - Address dst, Register val, Register tmp1, Register tmp2) { + Address dst, Register val, Register tmp1, Register tmp2, Register tmp3) { bool in_heap = (decorators & IN_HEAP) != 0; bool as_normal = (decorators & AS_NORMAL) != 0; assert((decorators & IS_DEST_UNINITIALIZED) == 0, "unsupported"); @@ -350,7 +334,6 @@ void G1BarrierSetAssembler::oop_store_at(MacroAssembler* masm, DecoratorSet deco bool needs_pre_barrier = as_normal; bool needs_post_barrier = val != noreg && in_heap; - Register tmp3 = LP64_ONLY(r8) NOT_LP64(rsi); Register rthread = LP64_ONLY(r15_thread) NOT_LP64(rcx); // flatten object address if needed // We do it regardless of precise because we need the registers @@ -379,7 +362,7 @@ void G1BarrierSetAssembler::oop_store_at(MacroAssembler* masm, DecoratorSet deco false /* expand_call */); } if (val == noreg) { - BarrierSetAssembler::store_at(masm, decorators, type, Address(tmp1, 0), val, noreg, noreg); + BarrierSetAssembler::store_at(masm, decorators, type, Address(tmp1, 0), val, noreg, noreg, noreg); } else { Register new_val = val; if (needs_post_barrier) { @@ -389,7 +372,7 @@ void G1BarrierSetAssembler::oop_store_at(MacroAssembler* masm, DecoratorSet deco __ movptr(new_val, val); } } - BarrierSetAssembler::store_at(masm, decorators, type, Address(tmp1, 0), val, noreg, noreg); + BarrierSetAssembler::store_at(masm, decorators, type, Address(tmp1, 0), val, noreg, noreg, noreg); if (needs_post_barrier) { g1_write_barrier_post(masm /*masm*/, tmp1 /* store_adr */, @@ -496,13 +479,13 @@ void G1BarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAssembler* __ bind(runtime); - __ save_live_registers_no_oop_map(true); + __ push_call_clobbered_registers(); // load the pre-value __ load_parameter(0, rcx); __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_pre_entry), rcx, thread); - __ restore_live_registers(true); + __ pop_call_clobbered_registers(); __ bind(done); @@ -515,9 +498,6 @@ void G1BarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAssembler* void G1BarrierSetAssembler::generate_c1_post_barrier_runtime_stub(StubAssembler* sasm) { __ prologue("g1_post_barrier", false); - // arg0: store_address - Address store_addr(rbp, 2*BytesPerWord); - CardTableBarrierSet* ct = barrier_set_cast(BarrierSet::barrier_set()); @@ -540,7 +520,7 @@ void G1BarrierSetAssembler::generate_c1_post_barrier_runtime_stub(StubAssembler* const Register card_addr = rcx; __ load_parameter(0, card_addr); - __ shrptr(card_addr, CardTable::card_shift); + __ 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()); @@ -573,12 +553,11 @@ void G1BarrierSetAssembler::generate_c1_post_barrier_runtime_stub(StubAssembler* __ jmp(enqueued); __ bind(runtime); - - __ save_live_registers_no_oop_map(true); + __ push_call_clobbered_registers(); __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry), card_addr, thread); - __ restore_live_registers(true); + __ pop_call_clobbered_registers(); __ bind(enqueued); __ pop(rdx); diff --git a/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.hpp b/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.hpp index 94bbadc7b2b14622e7a168a6641d6615200bfe2f..a5695f5657a4ad6a10ed8fc1687959f6b55f2ecb 100644 --- a/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.hpp @@ -54,7 +54,7 @@ class G1BarrierSetAssembler: public ModRefBarrierSetAssembler { Register tmp2); virtual void oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, - Address dst, Register val, Register tmp1, Register tmp2); + Address dst, Register val, Register tmp1, Register tmp2, Register tmp3); public: void gen_pre_barrier_stub(LIR_Assembler* ce, G1PreBarrierStub* stub); diff --git a/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.cpp b/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.cpp index 55823bdf217c33b059b7066d38e310fd61056d2d..930926bbb17652308db427ae09242dba1db94451 100644 --- a/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.cpp @@ -103,7 +103,7 @@ void BarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorators, } void BarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, - Address dst, Register val, Register tmp1, Register tmp2) { + Address dst, Register val, Register tmp1, Register tmp2, Register tmp3) { bool in_heap = (decorators & IN_HEAP) != 0; bool in_native = (decorators & IN_NATIVE) != 0; bool is_not_null = (decorators & IS_NOT_NULL) != 0; diff --git a/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.hpp b/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.hpp index 3c63c00e4dbcb8b4fe1fa1c5e34b84684d9691e7..085238d60b55f2caa4dde806b5409cd5864d8a35 100644 --- a/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.hpp @@ -47,7 +47,7 @@ public: virtual void load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, Register dst, Address src, Register tmp1, Register tmp_thread); virtual void store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, - Address dst, Register val, Register tmp1, Register tmp2); + Address dst, Register val, Register tmp1, Register tmp2, Register tmp3); // Support for jniFastGetField to try resolving a jobject/jweak in native virtual void try_resolve_jobject_in_native(MacroAssembler* masm, Register jni_env, diff --git a/src/hotspot/cpu/x86/gc/shared/cardTableBarrierSetAssembler_x86.cpp b/src/hotspot/cpu/x86/gc/shared/cardTableBarrierSetAssembler_x86.cpp index 9b2d2c5efedcee2eba8c4a90adfe02b7e054dd7c..f314cac5980b7f3c9e44ad888383a1139ab1c58d 100644 --- a/src/hotspot/cpu/x86/gc/shared/cardTableBarrierSetAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/gc/shared/cardTableBarrierSetAssembler_x86.cpp @@ -60,8 +60,8 @@ void CardTableBarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembl #ifdef _LP64 __ leaq(end, Address(addr, count, TIMES_OOP, 0)); // end == addr+count*oop_size __ subptr(end, BytesPerHeapOop); // end - 1 to make inclusive - __ shrptr(addr, CardTable::card_shift); - __ shrptr(end, CardTable::card_shift); + __ shrptr(addr, CardTable::card_shift()); + __ shrptr(end, CardTable::card_shift()); __ subptr(end, addr); // end --> cards count __ mov64(tmp, disp); @@ -72,8 +72,8 @@ __ BIND(L_loop); __ jcc(Assembler::greaterEqual, L_loop); #else __ lea(end, Address(addr, count, Address::times_ptr, -wordSize)); - __ shrptr(addr, CardTable::card_shift); - __ shrptr(end, CardTable::card_shift); + __ shrptr(addr, CardTable::card_shift()); + __ shrptr(end, CardTable::card_shift()); __ subptr(end, addr); // end --> count __ BIND(L_loop); Address cardtable(addr, count, Address::times_1, disp); @@ -93,7 +93,7 @@ void CardTableBarrierSetAssembler::store_check(MacroAssembler* masm, Register ob CardTableBarrierSet* ctbs = barrier_set_cast(bs); CardTable* ct = ctbs->card_table(); - __ shrptr(obj, CardTable::card_shift); + __ shrptr(obj, CardTable::card_shift()); Address card_addr; @@ -128,7 +128,7 @@ void CardTableBarrierSetAssembler::store_check(MacroAssembler* masm, Register ob } void CardTableBarrierSetAssembler::oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, - Address dst, Register val, Register tmp1, Register tmp2) { + Address dst, Register val, Register tmp1, Register tmp2, Register tmp3) { bool in_heap = (decorators & IN_HEAP) != 0; bool is_array = (decorators & IS_ARRAY) != 0; @@ -137,7 +137,7 @@ void CardTableBarrierSetAssembler::oop_store_at(MacroAssembler* masm, DecoratorS bool needs_post_barrier = val != noreg && in_heap; - BarrierSetAssembler::store_at(masm, decorators, type, dst, val, noreg, noreg); + BarrierSetAssembler::store_at(masm, decorators, type, dst, val, noreg, noreg, noreg); if (needs_post_barrier) { // flatten object address if needed if (!precise || (dst.index() == noreg && dst.disp() == 0)) { diff --git a/src/hotspot/cpu/x86/gc/shared/cardTableBarrierSetAssembler_x86.hpp b/src/hotspot/cpu/x86/gc/shared/cardTableBarrierSetAssembler_x86.hpp index a65286bd5996734f49e47f0f2137f27676d3c2f6..4760b222977a81b9e8febd93701786409860835d 100644 --- a/src/hotspot/cpu/x86/gc/shared/cardTableBarrierSetAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/gc/shared/cardTableBarrierSetAssembler_x86.hpp @@ -35,7 +35,7 @@ protected: virtual void gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators, Register addr, Register count, Register tmp); virtual void oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, - Address dst, Register val, Register tmp1, Register tmp2); + Address dst, Register val, Register tmp1, Register tmp2, Register tmp3); }; #endif // CPU_X86_GC_SHARED_CARDTABLEBARRIERSETASSEMBLER_X86_HPP diff --git a/src/hotspot/cpu/x86/gc/shared/modRefBarrierSetAssembler_x86.cpp b/src/hotspot/cpu/x86/gc/shared/modRefBarrierSetAssembler_x86.cpp index 9325ab7ecf9c711605f1fe75d637782d2fecdcca..618095bdfa634b8c3a7cdccab5e280ae96668c1b 100644 --- a/src/hotspot/cpu/x86/gc/shared/modRefBarrierSetAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/gc/shared/modRefBarrierSetAssembler_x86.cpp @@ -84,10 +84,10 @@ void ModRefBarrierSetAssembler::arraycopy_epilogue(MacroAssembler* masm, Decorat } void ModRefBarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, - Address dst, Register val, Register tmp1, Register tmp2) { + Address dst, Register val, Register tmp1, Register tmp2, Register tmp3) { if (is_reference_type(type)) { - oop_store_at(masm, decorators, type, dst, val, tmp1, tmp2); + oop_store_at(masm, decorators, type, dst, val, tmp1, tmp2, tmp3); } else { - BarrierSetAssembler::store_at(masm, decorators, type, dst, val, tmp1, tmp2); + BarrierSetAssembler::store_at(masm, decorators, type, dst, val, tmp1, tmp2, tmp3); } } diff --git a/src/hotspot/cpu/x86/gc/shared/modRefBarrierSetAssembler_x86.hpp b/src/hotspot/cpu/x86/gc/shared/modRefBarrierSetAssembler_x86.hpp index 39950225bfe736a71f7b6dc34a021e78357b110e..c8b5043256ad203bed7d16f7ead5e188c91cbb45 100644 --- a/src/hotspot/cpu/x86/gc/shared/modRefBarrierSetAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/gc/shared/modRefBarrierSetAssembler_x86.hpp @@ -39,7 +39,7 @@ protected: virtual void gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators, Register addr, Register count, Register tmp) {} virtual void oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, - Address dst, Register val, Register tmp1, Register tmp2) = 0; + Address dst, Register val, Register tmp1, Register tmp2, Register tmp3) = 0; public: virtual void arraycopy_prologue(MacroAssembler* masm, DecoratorSet decorators, BasicType type, Register src, Register dst, Register count); @@ -47,7 +47,7 @@ public: Register src, Register dst, Register count); virtual void store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, - Address dst, Register val, Register tmp1, Register tmp2); + Address dst, Register val, Register tmp1, Register tmp2, Register tmp3); }; #endif // CPU_X86_GC_SHARED_MODREFBARRIERSETASSEMBLER_X86_HPP diff --git a/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.cpp b/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.cpp index 28c295d6139cf69dd5c4fdf0f194ae460759c202..d213e6fda394e6796bddf81a2a22aef405026b66 100644 --- a/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.cpp @@ -420,9 +420,9 @@ void ShenandoahBarrierSetAssembler::load_reference_barrier(MacroAssembler* masm, if (is_strong) { if (is_narrow) { - __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_strong_narrow), arg0, arg1); + __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_strong_narrow), arg0, arg1); } else { - __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_strong), arg0, arg1); + __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_strong), arg0, arg1); } } else if (is_weak) { if (is_narrow) { @@ -433,7 +433,7 @@ void ShenandoahBarrierSetAssembler::load_reference_barrier(MacroAssembler* masm, } else { assert(is_phantom, "only remaining strength"); assert(!is_narrow, "phantom access cannot be narrow"); - __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_phantom), arg0, arg1); + __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_phantom), arg0, arg1); } #ifdef _LP64 @@ -591,7 +591,7 @@ void ShenandoahBarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet d } void ShenandoahBarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, - Address dst, Register val, Register tmp1, Register tmp2) { + Address dst, Register val, Register tmp1, Register tmp2, Register tmp3) { bool on_oop = is_reference_type(type); bool in_heap = (decorators & IN_HEAP) != 0; @@ -599,7 +599,6 @@ void ShenandoahBarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet if (on_oop && in_heap) { bool needs_pre_barrier = as_normal; - Register tmp3 = LP64_ONLY(r8) NOT_LP64(rsi); Register rthread = LP64_ONLY(r15_thread) NOT_LP64(rcx); // flatten object address if needed // We do it regardless of precise because we need the registers @@ -629,14 +628,14 @@ void ShenandoahBarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet false /* expand_call */); } if (val == noreg) { - BarrierSetAssembler::store_at(masm, decorators, type, Address(tmp1, 0), val, noreg, noreg); + BarrierSetAssembler::store_at(masm, decorators, type, Address(tmp1, 0), val, noreg, noreg, noreg); } else { iu_barrier(masm, val, tmp3); - BarrierSetAssembler::store_at(masm, decorators, type, Address(tmp1, 0), val, noreg, noreg); + BarrierSetAssembler::store_at(masm, decorators, type, Address(tmp1, 0), val, noreg, noreg, noreg); } NOT_LP64(imasm->restore_bcp()); } else { - BarrierSetAssembler::store_at(masm, decorators, type, dst, val, tmp1, tmp2); + BarrierSetAssembler::store_at(masm, decorators, type, dst, val, tmp1, tmp2, tmp3); } } diff --git a/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.hpp b/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.hpp index 2a8c0862b9e6380c85c18570693e8e3d483fc655..47dfe1449280259f524318b1adf4fc4b573787c8 100644 --- a/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.hpp @@ -77,7 +77,7 @@ public: virtual void load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, Register dst, Address src, Register tmp1, Register tmp_thread); virtual void store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, - Address dst, Register val, Register tmp1, Register tmp2); + Address dst, Register val, Register tmp1, Register tmp2, Register tmp3); virtual void try_resolve_jobject_in_native(MacroAssembler* masm, Register jni_env, Register obj, Register tmp, Label& slowpath); }; diff --git a/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.cpp b/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.cpp index 3ffd3a2a85f4062164a413b982774574c81a46e5..00071d66da34166365cd8e10f56d832988295377 100644 --- a/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.cpp @@ -193,7 +193,8 @@ void ZBarrierSetAssembler::store_at(MacroAssembler* masm, Address dst, Register src, Register tmp1, - Register tmp2) { + Register tmp2, + Register tmp3) { BLOCK_COMMENT("ZBarrierSetAssembler::store_at {"); // Verify oop store @@ -211,7 +212,7 @@ void ZBarrierSetAssembler::store_at(MacroAssembler* masm, } // Store value - BarrierSetAssembler::store_at(masm, decorators, type, dst, src, tmp1, tmp2); + BarrierSetAssembler::store_at(masm, decorators, type, dst, src, tmp1, tmp2, tmp3); BLOCK_COMMENT("} ZBarrierSetAssembler::store_at"); } @@ -452,7 +453,7 @@ private: void opmask_register_save(KRegister reg) { _spill_offset -= 8; - __ kmovql(Address(rsp, _spill_offset), reg); + __ kmov(Address(rsp, _spill_offset), reg); } void gp_register_restore(Register reg) { @@ -461,7 +462,7 @@ private: } void opmask_register_restore(KRegister reg) { - __ kmovql(reg, Address(rsp, _spill_offset)); + __ kmov(reg, Address(rsp, _spill_offset)); _spill_offset += 8; } diff --git a/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.hpp b/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.hpp index 134f7e6c9e2e5951a63a8a816c3d1ddd311332df..2446bd1e46a73357d47f9fda7a95828d9a13df8a 100644 --- a/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.hpp @@ -61,7 +61,8 @@ public: Address dst, Register src, Register tmp1, - Register tmp2); + Register tmp2, + Register tmp3); #endif // ASSERT virtual void arraycopy_prologue(MacroAssembler* masm, diff --git a/src/hotspot/cpu/x86/interp_masm_x86.cpp b/src/hotspot/cpu/x86/interp_masm_x86.cpp index bf8b94a6319dbacfe7a14d0228fb3fb50689a3f8..34d4178b8da4c39e4412428ddb1cb222098532ce 100644 --- a/src/hotspot/cpu/x86/interp_masm_x86.cpp +++ b/src/hotspot/cpu/x86/interp_masm_x86.cpp @@ -1972,19 +1972,18 @@ void InterpreterMacroAssembler::verify_FPU(int stack_depth, TosState state) { #endif } -// Jump if ((*counter_addr += increment) & mask) satisfies the condition. -void InterpreterMacroAssembler::increment_mask_and_jump(Address counter_addr, - int increment, Address mask, - Register scratch, bool preloaded, - Condition cond, Label* where) { - if (!preloaded) { - movl(scratch, counter_addr); - } - incrementl(scratch, increment); +// Jump if ((*counter_addr += increment) & mask) == 0 +void InterpreterMacroAssembler::increment_mask_and_jump(Address counter_addr, Address mask, + Register scratch, Label* where) { + // This update is actually not atomic and can lose a number of updates + // under heavy contention, but the alternative of using the (contended) + // atomic update here penalizes profiling paths too much. + movl(scratch, counter_addr); + incrementl(scratch, InvocationCounter::count_increment); movl(counter_addr, scratch); andl(scratch, mask); if (where != NULL) { - jcc(cond, *where); + jcc(Assembler::zero, *where); } } diff --git a/src/hotspot/cpu/x86/interp_masm_x86.hpp b/src/hotspot/cpu/x86/interp_masm_x86.hpp index 0aecb6b4a25e6bf47d3876060c7940e7bb276003..a94f35426b8bcaa186f7e3b54c8c8314fc4e59d5 100644 --- a/src/hotspot/cpu/x86/interp_masm_x86.hpp +++ b/src/hotspot/cpu/x86/interp_masm_x86.hpp @@ -248,10 +248,8 @@ class InterpreterMacroAssembler: public MacroAssembler { bool decrement = false); void increment_mdp_data_at(Register mdp_in, Register reg, int constant, bool decrement = false); - void increment_mask_and_jump(Address counter_addr, - int increment, Address mask, - Register scratch, bool preloaded, - Condition cond, Label* where); + void increment_mask_and_jump(Address counter_addr, Address mask, + Register scratch, Label* where); void set_mdp_flag_at(Register mdp_in, int flag_constant); void test_mdp_data_at(Register mdp_in, int offset, Register value, Register test_value_out, diff --git a/src/hotspot/cpu/x86/jniTypes_x86.hpp b/src/hotspot/cpu/x86/jniTypes_x86.hpp index 403a0b63e2be74c8853298b646351e81085a8d9f..5c925474796d4373d43008c00d7feca2b17090de 100644 --- a/src/hotspot/cpu/x86/jniTypes_x86.hpp +++ b/src/hotspot/cpu/x86/jniTypes_x86.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -26,7 +26,7 @@ #define CPU_X86_JNITYPES_X86_HPP #include "jni.h" -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" #include "oops/oop.hpp" // This file holds platform-dependent routines used to write primitive jni diff --git a/src/hotspot/cpu/x86/jvmciCodeInstaller_x86.cpp b/src/hotspot/cpu/x86/jvmciCodeInstaller_x86.cpp index 38f696b50c2f833bc1141534ef6de87ff4190343..7d93ed522ba0146fe31e434716cd2afe900670a5 100644 --- a/src/hotspot/cpu/x86/jvmciCodeInstaller_x86.cpp +++ b/src/hotspot/cpu/x86/jvmciCodeInstaller_x86.cpp @@ -155,14 +155,15 @@ void CodeInstaller::pd_relocate_JavaMethod(CodeBuffer &, JVMCIObject hotspot_met method = JVMCIENV->asMethod(hotspot_method); } #endif + NativeCall* call = NULL; switch (_next_call_type) { case INLINE_INVOKE: - break; + return; case INVOKEVIRTUAL: case INVOKEINTERFACE: { assert(method == NULL || !method->is_static(), "cannot call static method with invokeinterface"); - NativeCall* call = nativeCall_at(_instructions->start() + pc_offset); + call = nativeCall_at(_instructions->start() + pc_offset); call->set_destination(SharedRuntime::get_resolve_virtual_call_stub()); _instructions->relocate(call->instruction_address(), virtual_call_Relocation::spec(_invoke_mark_pc), @@ -172,7 +173,7 @@ void CodeInstaller::pd_relocate_JavaMethod(CodeBuffer &, JVMCIObject hotspot_met case INVOKESTATIC: { assert(method == NULL || method->is_static(), "cannot call non-static method with invokestatic"); - NativeCall* call = nativeCall_at(_instructions->start() + pc_offset); + call = nativeCall_at(_instructions->start() + pc_offset); call->set_destination(SharedRuntime::get_resolve_static_call_stub()); _instructions->relocate(call->instruction_address(), relocInfo::static_call_type, Assembler::call32_operand); @@ -180,15 +181,18 @@ void CodeInstaller::pd_relocate_JavaMethod(CodeBuffer &, JVMCIObject hotspot_met } case INVOKESPECIAL: { assert(method == NULL || !method->is_static(), "cannot call static method with invokespecial"); - NativeCall* call = nativeCall_at(_instructions->start() + pc_offset); + call = nativeCall_at(_instructions->start() + pc_offset); call->set_destination(SharedRuntime::get_resolve_opt_virtual_call_stub()); _instructions->relocate(call->instruction_address(), relocInfo::opt_virtual_call_type, Assembler::call32_operand); break; } default: - JVMCI_ERROR("invalid _next_call_type value"); - break; + JVMCI_ERROR("invalid _next_call_type value: %d", _next_call_type); + return; + } + if (!call->is_displacement_aligned()) { + JVMCI_ERROR("unaligned displacement for call at offset %d", pc_offset); } } diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.cpp b/src/hotspot/cpu/x86/macroAssembler_x86.cpp index 6a7f671c3516cc8de5240746abbc20498ed3ba20..e9285b11e42b6facfbb87cb7588691c3e13d7146 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -26,6 +26,7 @@ #include "jvm.h" #include "asm/assembler.hpp" #include "asm/assembler.inline.hpp" +#include "c1/c1_FrameMap.hpp" #include "compiler/compiler_globals.hpp" #include "compiler/disassembler.hpp" #include "gc/shared/barrierSet.hpp" @@ -332,21 +333,6 @@ void MacroAssembler::movptr(Address dst, intptr_t src) { movl(dst, src); } - -void MacroAssembler::pop_callee_saved_registers() { - pop(rcx); - pop(rdx); - pop(rdi); - pop(rsi); -} - -void MacroAssembler::push_callee_saved_registers() { - push(rsi); - push(rdi); - push(rdx); - push(rcx); -} - void MacroAssembler::pushoop(jobject obj) { push_literal32((int32_t)obj, oop_Relocation::spec_for_immediate()); } @@ -2546,6 +2532,15 @@ void MacroAssembler::vmovdqu(XMMRegister dst, AddressLiteral src, Register scrat } } +void MacroAssembler::vmovdqu(XMMRegister dst, AddressLiteral src, Register scratch_reg, int vector_len) { + assert(vector_len <= AVX_256bit, "AVX2 vector length"); + if (vector_len == AVX_256bit) { + vmovdqu(dst, src, scratch_reg); + } else { + movdqu(dst, src, scratch_reg); + } +} + void MacroAssembler::kmov(KRegister dst, Address src) { if (VM_Version::supports_avx512bw()) { kmovql(dst, src); @@ -2693,6 +2688,15 @@ void MacroAssembler::movss(XMMRegister dst, AddressLiteral src) { } } +void MacroAssembler::vmovddup(XMMRegister dst, AddressLiteral src, int vector_len, Register rscratch) { + if (reachable(src)) { + Assembler::vmovddup(dst, as_Address(src), vector_len); + } else { + lea(rscratch, src); + Assembler::vmovddup(dst, Address(rscratch, 0), vector_len); + } +} + void MacroAssembler::mulsd(XMMRegister dst, AddressLiteral src) { if (reachable(src)) { Assembler::mulsd(dst, as_Address(src)); @@ -3142,6 +3146,15 @@ void MacroAssembler::vpbroadcastw(XMMRegister dst, XMMRegister src, int vector_l Assembler::vpbroadcastw(dst, src, vector_len); } +void MacroAssembler::vbroadcastsd(XMMRegister dst, AddressLiteral src, int vector_len, Register rscratch) { + if (reachable(src)) { + Assembler::vbroadcastsd(dst, as_Address(src), vector_len); + } else { + lea(rscratch, src); + Assembler::vbroadcastsd(dst, Address(rscratch, 0), vector_len); + } +} + void MacroAssembler::vpcmpeqb(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { assert(((dst->encoding() < 16 && src->encoding() < 16 && nds->encoding() < 16) || VM_Version::supports_avx512vlbw()),"XMM register should be 0-15"); Assembler::vpcmpeqb(dst, nds, src, vector_len); @@ -3210,7 +3223,7 @@ void MacroAssembler::vpcmpCC(XMMRegister dst, XMMRegister nds, XMMRegister src, } } -void MacroAssembler::vpcmpCCW(XMMRegister dst, XMMRegister nds, XMMRegister src, ComparisonPredicate cond, Width width, int vector_len, Register scratch_reg) { +void MacroAssembler::vpcmpCCW(XMMRegister dst, XMMRegister nds, XMMRegister src, XMMRegister xtmp, ComparisonPredicate cond, Width width, int vector_len) { int eq_cond_enc = 0x29; int gt_cond_enc = 0x37; if (width != Assembler::Q) { @@ -3223,15 +3236,18 @@ void MacroAssembler::vpcmpCCW(XMMRegister dst, XMMRegister nds, XMMRegister src, break; case neq: vpcmpCC(dst, nds, src, eq_cond_enc, width, vector_len); - vpxor(dst, dst, ExternalAddress(StubRoutines::x86::vector_all_bits_set()), vector_len, scratch_reg); + vallones(xtmp, vector_len); + vpxor(dst, xtmp, dst, vector_len); break; case le: vpcmpCC(dst, nds, src, gt_cond_enc, width, vector_len); - vpxor(dst, dst, ExternalAddress(StubRoutines::x86::vector_all_bits_set()), vector_len, scratch_reg); + vallones(xtmp, vector_len); + vpxor(dst, xtmp, dst, vector_len); break; case nlt: vpcmpCC(dst, src, nds, gt_cond_enc, width, vector_len); - vpxor(dst, dst, ExternalAddress(StubRoutines::x86::vector_all_bits_set()), vector_len, scratch_reg); + vallones(xtmp, vector_len); + vpxor(dst, xtmp, dst, vector_len); break; case lt: vpcmpCC(dst, src, nds, gt_cond_enc, width, vector_len); @@ -3563,6 +3579,190 @@ void MacroAssembler::tlab_allocate(Register thread, Register obj, bs->tlab_allocate(this, thread, obj, var_size_in_bytes, con_size_in_bytes, t1, t2, slow_case); } +RegSet MacroAssembler::call_clobbered_gp_registers() { + RegSet regs; +#ifdef _LP64 + regs += RegSet::of(rax, rcx, rdx); +#ifndef WINDOWS + regs += RegSet::of(rsi, rdi); +#endif + regs += RegSet::range(r8, r11); +#else + regs += RegSet::of(rax, rcx, rdx); +#endif + return regs; +} + +XMMRegSet MacroAssembler::call_clobbered_xmm_registers() { +#if defined(WINDOWS) && defined(_LP64) + XMMRegSet result = XMMRegSet::range(xmm0, xmm5); + if (FrameMap::get_num_caller_save_xmms() > 16) { + result += XMMRegSet::range(xmm16, as_XMMRegister(FrameMap::get_num_caller_save_xmms() - 1)); + } + return result; +#else + return XMMRegSet::range(xmm0, as_XMMRegister(FrameMap::get_num_caller_save_xmms() - 1)); +#endif +} + +static int FPUSaveAreaSize = align_up(108, StackAlignmentInBytes); // 108 bytes needed for FPU state by fsave/frstor + +#ifndef _LP64 +static bool use_x87_registers() { return UseSSE < 2; } +#endif +static bool use_xmm_registers() { return UseSSE >= 1; } + +// C1 only ever uses the first double/float of the XMM register. +static int xmm_save_size() { return UseSSE >= 2 ? sizeof(double) : sizeof(float); } + +static void save_xmm_register(MacroAssembler* masm, int offset, XMMRegister reg) { + if (UseSSE == 1) { + masm->movflt(Address(rsp, offset), reg); + } else { + masm->movdbl(Address(rsp, offset), reg); + } +} + +static void restore_xmm_register(MacroAssembler* masm, int offset, XMMRegister reg) { + if (UseSSE == 1) { + masm->movflt(reg, Address(rsp, offset)); + } else { + masm->movdbl(reg, Address(rsp, offset)); + } +} + +int register_section_sizes(RegSet gp_registers, XMMRegSet xmm_registers, bool save_fpu, + int& gp_area_size, int& fp_area_size, int& xmm_area_size) { + + gp_area_size = align_up(gp_registers.size() * RegisterImpl::max_slots_per_register * VMRegImpl::stack_slot_size, + StackAlignmentInBytes); +#ifdef _LP64 + fp_area_size = 0; +#else + fp_area_size = (save_fpu && use_x87_registers()) ? FPUSaveAreaSize : 0; +#endif + xmm_area_size = (save_fpu && use_xmm_registers()) ? xmm_registers.size() * xmm_save_size() : 0; + + return gp_area_size + fp_area_size + xmm_area_size; +} + +void MacroAssembler::push_call_clobbered_registers_except(RegSet exclude, bool save_fpu) { + block_comment("push_call_clobbered_registers start"); + // Regular registers + RegSet gp_registers_to_push = call_clobbered_gp_registers() - exclude; + + int gp_area_size; + int fp_area_size; + int xmm_area_size; + int total_save_size = register_section_sizes(gp_registers_to_push, call_clobbered_xmm_registers(), save_fpu, + gp_area_size, fp_area_size, xmm_area_size); + subptr(rsp, total_save_size); + + push_set(gp_registers_to_push, 0); + +#ifndef _LP64 + if (save_fpu && use_x87_registers()) { + fnsave(Address(rsp, gp_area_size)); + fwait(); + } +#endif + if (save_fpu && use_xmm_registers()) { + push_set(call_clobbered_xmm_registers(), gp_area_size + fp_area_size); + } + + block_comment("push_call_clobbered_registers end"); +} + +void MacroAssembler::pop_call_clobbered_registers_except(RegSet exclude, bool restore_fpu) { + block_comment("pop_call_clobbered_registers start"); + + RegSet gp_registers_to_pop = call_clobbered_gp_registers() - exclude; + + int gp_area_size; + int fp_area_size; + int xmm_area_size; + int total_save_size = register_section_sizes(gp_registers_to_pop, call_clobbered_xmm_registers(), restore_fpu, + gp_area_size, fp_area_size, xmm_area_size); + + if (restore_fpu && use_xmm_registers()) { + pop_set(call_clobbered_xmm_registers(), gp_area_size + fp_area_size); + } +#ifndef _LP64 + if (restore_fpu && use_x87_registers()) { + frstor(Address(rsp, gp_area_size)); + } +#endif + + pop_set(gp_registers_to_pop, 0); + + addptr(rsp, total_save_size); + + vzeroupper(); + + block_comment("pop_call_clobbered_registers end"); +} + +void MacroAssembler::push_set(XMMRegSet set, int offset) { + assert(is_aligned(set.size() * xmm_save_size(), StackAlignmentInBytes), "must be"); + int spill_offset = offset; + + for (RegSetIterator it = set.begin(); *it != xnoreg; ++it) { + save_xmm_register(this, spill_offset, *it); + spill_offset += xmm_save_size(); + } +} + +void MacroAssembler::pop_set(XMMRegSet set, int offset) { + int restore_size = set.size() * xmm_save_size(); + assert(is_aligned(restore_size, StackAlignmentInBytes), "must be"); + + int restore_offset = offset + restore_size - xmm_save_size(); + + for (ReverseRegSetIterator it = set.rbegin(); *it != xnoreg; ++it) { + restore_xmm_register(this, restore_offset, *it); + restore_offset -= xmm_save_size(); + } +} + +void MacroAssembler::push_set(RegSet set, int offset) { + int spill_offset; + if (offset == -1) { + int register_push_size = set.size() * RegisterImpl::max_slots_per_register * VMRegImpl::stack_slot_size; + int aligned_size = align_up(register_push_size, StackAlignmentInBytes); + subptr(rsp, aligned_size); + spill_offset = 0; + } else { + spill_offset = offset; + } + + for (RegSetIterator it = set.begin(); *it != noreg; ++it) { + movptr(Address(rsp, spill_offset), *it); + spill_offset += RegisterImpl::max_slots_per_register * VMRegImpl::stack_slot_size; + } +} + +void MacroAssembler::pop_set(RegSet set, int offset) { + + int gp_reg_size = RegisterImpl::max_slots_per_register * VMRegImpl::stack_slot_size; + int restore_size = set.size() * gp_reg_size; + int aligned_size = align_up(restore_size, StackAlignmentInBytes); + + int restore_offset; + if (offset == -1) { + restore_offset = restore_size - gp_reg_size; + } else { + restore_offset = offset + restore_size - gp_reg_size; + } + for (ReverseRegSetIterator it = set.rbegin(); *it != noreg; ++it) { + movptr(*it, Address(rsp, restore_offset)); + restore_offset -= gp_reg_size; + } + + if (offset == -1) { + addptr(rsp, aligned_size); + } +} + // Defines obj, preserves var_size_in_bytes void MacroAssembler::eden_allocate(Register thread, Register obj, Register var_size_in_bytes, @@ -4575,14 +4775,14 @@ void MacroAssembler::access_load_at(BasicType type, DecoratorSet decorators, Reg } void MacroAssembler::access_store_at(BasicType type, DecoratorSet decorators, Address dst, Register src, - Register tmp1, Register tmp2) { + Register tmp1, Register tmp2, Register tmp3) { BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler(); decorators = AccessInternal::decorator_fixup(decorators); bool as_raw = (decorators & AS_RAW) != 0; if (as_raw) { - bs->BarrierSetAssembler::store_at(this, decorators, type, dst, src, tmp1, tmp2); + bs->BarrierSetAssembler::store_at(this, decorators, type, dst, src, tmp1, tmp2, tmp3); } else { - bs->store_at(this, decorators, type, dst, src, tmp1, tmp2); + bs->store_at(this, decorators, type, dst, src, tmp1, tmp2, tmp3); } } @@ -4598,13 +4798,13 @@ void MacroAssembler::load_heap_oop_not_null(Register dst, Address src, Register } void MacroAssembler::store_heap_oop(Address dst, Register src, Register tmp1, - Register tmp2, DecoratorSet decorators) { - access_store_at(T_OBJECT, IN_HEAP | decorators, dst, src, tmp1, tmp2); + Register tmp2, Register tmp3, DecoratorSet decorators) { + access_store_at(T_OBJECT, IN_HEAP | decorators, dst, src, tmp1, tmp2, tmp3); } // Used for storing NULLs. void MacroAssembler::store_heap_oop_null(Address dst) { - access_store_at(T_OBJECT, IN_HEAP, dst, noreg, noreg, noreg); + access_store_at(T_OBJECT, IN_HEAP, dst, noreg, noreg, noreg, noreg); } #ifdef _LP64 @@ -4621,12 +4821,19 @@ void MacroAssembler::verify_heapbase(const char* msg) { assert (Universe::heap() != NULL, "java heap should be initialized"); if (CheckCompressedOops) { Label ok; - push(rscratch1); // cmpptr trashes rscratch1 - cmpptr(r12_heapbase, ExternalAddress((address)CompressedOops::ptrs_base_addr())); + const auto src2 = ExternalAddress((address)CompressedOops::ptrs_base_addr()); + assert(!src2.is_lval(), "should not be lval"); + const bool is_src2_reachable = reachable(src2); + if (!is_src2_reachable) { + push(rscratch1); // cmpptr trashes rscratch1 + } + cmpptr(r12_heapbase, src2); jcc(Assembler::equal, ok); STOP(msg); bind(ok); - pop(rscratch1); + if (!is_src2_reachable) { + pop(rscratch1); + } } } #endif @@ -4786,8 +4993,6 @@ void MacroAssembler::encode_and_move_klass_not_null(Register dst, Register src) } } -// !!! If the instructions that get generated here change then function -// instr_size_for_decode_klass_not_null() needs to get updated. void MacroAssembler::decode_klass_not_null(Register r, Register tmp) { assert_different_registers(r, tmp); // Note: it will change flags @@ -5014,7 +5219,7 @@ void MacroAssembler::xmm_clear_mem(Register base, Register cnt, Register rtmp, X // cnt - number of qwords (8-byte words). // base - start address, qword aligned. Label L_zero_64_bytes, L_loop, L_sloop, L_tail, L_end; - bool use64byteVector = MaxVectorSize == 64 && AVX3Threshold == 0; + bool use64byteVector = (MaxVectorSize == 64) && (VM_Version::avx3_threshold() == 0); if (use64byteVector) { vpxor(xtmp, xtmp, xtmp, AVX_512bit); } else if (MaxVectorSize >= 32) { @@ -5078,7 +5283,7 @@ void MacroAssembler::xmm_clear_mem(Register base, Register cnt, Register rtmp, X // Clearing constant sized memory using YMM/ZMM registers. void MacroAssembler::clear_mem(Register base, int cnt, Register rtmp, XMMRegister xtmp, KRegister mask) { assert(UseAVX > 2 && VM_Version::supports_avx512vlbw(), ""); - bool use64byteVector = MaxVectorSize > 32 && AVX3Threshold == 0; + bool use64byteVector = (MaxVectorSize > 32) && (VM_Version::avx3_threshold() == 0); int vector64_count = (cnt & (~0x7)) >> 3; cnt = cnt & 0x7; @@ -5321,8 +5526,8 @@ void MacroAssembler::generate_fill(BasicType t, bool aligned, // Fill 64-byte chunks Label L_fill_64_bytes_loop_avx3, L_check_fill_64_bytes_avx2; - // If number of bytes to fill < AVX3Threshold, perform fill using AVX2 - cmpl(count, AVX3Threshold); + // If number of bytes to fill < VM_Version::avx3_threshold(), perform fill using AVX2 + cmpl(count, VM_Version::avx3_threshold()); jccb(Assembler::below, L_check_fill_64_bytes_avx2); vpbroadcastd(xtmp, xtmp, Assembler::AVX_512bit); @@ -7032,7 +7237,7 @@ void MacroAssembler::fold512bit_crc32_avx512(XMMRegister xcrc, XMMRegister xK, X // Helper function for AVX 512 CRC32 // Compute CRC32 for < 256B buffers -void MacroAssembler::kernel_crc32_avx512_256B(Register crc, Register buf, Register len, Register key, Register pos, +void MacroAssembler::kernel_crc32_avx512_256B(Register crc, Register buf, Register len, Register table, Register pos, Register tmp1, Register tmp2, Label& L_barrett, Label& L_16B_reduction_loop, Label& L_get_last_two_xmms, Label& L_128_done, Label& L_cleanup) { @@ -7045,7 +7250,7 @@ void MacroAssembler::kernel_crc32_avx512_256B(Register crc, Register buf, Regist jcc(Assembler::less, L_less_than_32); // if there is, load the constants - movdqu(xmm10, Address(key, 1 * 16)); //rk1 and rk2 in xmm10 + movdqu(xmm10, Address(table, 1 * 16)); //rk1 and rk2 in xmm10 movdl(xmm0, crc); // get the initial crc value movdqu(xmm7, Address(buf, pos, Address::times_1, 0 * 16)); //load the plaintext pxor(xmm7, xmm0); @@ -7072,7 +7277,7 @@ void MacroAssembler::kernel_crc32_avx512_256B(Register crc, Register buf, Regist pxor(xmm7, xmm0); //xor the initial crc value addl(pos, 16); subl(len, 16); - movdqu(xmm10, Address(key, 1 * 16)); // rk1 and rk2 in xmm10 + movdqu(xmm10, Address(table, 1 * 16)); // rk1 and rk2 in xmm10 jmp(L_get_last_two_xmms); bind(L_less_than_16_left); @@ -7192,12 +7397,17 @@ void MacroAssembler::kernel_crc32_avx512_256B(Register crc, Register buf, Regist * param crc register containing existing CRC (32-bit) * param buf register pointing to input byte buffer (byte*) * param len register containing number of bytes +* param table address of crc or crc32c table * param tmp1 scratch register * param tmp2 scratch register * return rax result register +* +* This routine is identical for crc32c with the exception of the precomputed constant +* table which will be passed as the table argument. The calculation steps are +* the same for both variants. */ -void MacroAssembler::kernel_crc32_avx512(Register crc, Register buf, Register len, Register key, Register tmp1, Register tmp2) { - assert_different_registers(crc, buf, len, key, tmp1, tmp2, rax); +void MacroAssembler::kernel_crc32_avx512(Register crc, Register buf, Register len, Register table, Register tmp1, Register tmp2) { + assert_different_registers(crc, buf, len, table, tmp1, tmp2, rax, r12); Label L_tail, L_tail_restore, L_tail_loop, L_exit, L_align_loop, L_aligned; Label L_fold_tail, L_fold_128b, L_fold_512b, L_fold_512b_loop, L_fold_tail_loop; @@ -7212,8 +7422,6 @@ void MacroAssembler::kernel_crc32_avx512(Register crc, Register buf, Register le // For EVEX with VL and BW, provide a standard mask, VL = 128 will guide the merge // context for the registers used, where all instructions below are using 128-bit mode // On EVEX without VL and BW, these instructions will all be AVX. - lea(key, ExternalAddress(StubRoutines::x86::crc_table_avx512_addr())); - notl(crc); movl(pos, 0); // check if smaller than 256B @@ -7227,7 +7435,7 @@ void MacroAssembler::kernel_crc32_avx512(Register crc, Register buf, Register le evmovdquq(xmm0, Address(buf, pos, Address::times_1, 0 * 64), Assembler::AVX_512bit); evmovdquq(xmm4, Address(buf, pos, Address::times_1, 1 * 64), Assembler::AVX_512bit); evpxorq(xmm0, xmm0, xmm10, Assembler::AVX_512bit); - evbroadcasti32x4(xmm10, Address(key, 2 * 16), Assembler::AVX_512bit); //zmm10 has rk3 and rk4 + evbroadcasti32x4(xmm10, Address(table, 2 * 16), Assembler::AVX_512bit); //zmm10 has rk3 and rk4 subl(len, 256); cmpl(len, 256); @@ -7235,7 +7443,7 @@ void MacroAssembler::kernel_crc32_avx512(Register crc, Register buf, Register le evmovdquq(xmm7, Address(buf, pos, Address::times_1, 2 * 64), Assembler::AVX_512bit); evmovdquq(xmm8, Address(buf, pos, Address::times_1, 3 * 64), Assembler::AVX_512bit); - evbroadcasti32x4(xmm16, Address(key, 0 * 16), Assembler::AVX_512bit); //zmm16 has rk-1 and rk-2 + evbroadcasti32x4(xmm16, Address(table, 0 * 16), Assembler::AVX_512bit); //zmm16 has rk-1 and rk-2 subl(len, 256); bind(L_fold_256_B_loop); @@ -7281,8 +7489,8 @@ void MacroAssembler::kernel_crc32_avx512(Register crc, Register buf, Register le // at this point, the buffer pointer is pointing at the last y Bytes of the buffer, where 0 <= y < 128 // the 128B of folded data is in 8 of the xmm registers : xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7 bind(L_fold_128_B_register); - evmovdquq(xmm16, Address(key, 5 * 16), Assembler::AVX_512bit); // multiply by rk9-rk16 - evmovdquq(xmm11, Address(key, 9 * 16), Assembler::AVX_512bit); // multiply by rk17-rk20, rk1,rk2, 0,0 + evmovdquq(xmm16, Address(table, 5 * 16), Assembler::AVX_512bit); // multiply by rk9-rk16 + evmovdquq(xmm11, Address(table, 9 * 16), Assembler::AVX_512bit); // multiply by rk17-rk20, rk1,rk2, 0,0 evpclmulqdq(xmm1, xmm0, xmm16, 0x01, Assembler::AVX_512bit); evpclmulqdq(xmm2, xmm0, xmm16, 0x10, Assembler::AVX_512bit); // save last that has no multiplicand @@ -7291,7 +7499,7 @@ void MacroAssembler::kernel_crc32_avx512(Register crc, Register buf, Register le evpclmulqdq(xmm5, xmm4, xmm11, 0x01, Assembler::AVX_512bit); evpclmulqdq(xmm6, xmm4, xmm11, 0x10, Assembler::AVX_512bit); // Needed later in reduction loop - movdqu(xmm10, Address(key, 1 * 16)); + movdqu(xmm10, Address(table, 1 * 16)); vpternlogq(xmm1, 0x96, xmm2, xmm5, Assembler::AVX_512bit); // xor ABC vpternlogq(xmm1, 0x96, xmm6, xmm7, Assembler::AVX_512bit); // xor ABC @@ -7307,7 +7515,7 @@ void MacroAssembler::kernel_crc32_avx512(Register crc, Register buf, Register le jcc(Assembler::less, L_final_reduction_for_128); bind(L_16B_reduction_loop); - vpclmulqdq(xmm8, xmm7, xmm10, 0x1); + vpclmulqdq(xmm8, xmm7, xmm10, 0x01); vpclmulqdq(xmm7, xmm7, xmm10, 0x10); vpxor(xmm7, xmm7, xmm8, Assembler::AVX_128bit); movdqu(xmm0, Address(buf, pos, Address::times_1, 0 * 16)); @@ -7338,14 +7546,14 @@ void MacroAssembler::kernel_crc32_avx512(Register crc, Register buf, Register le vpshufb(xmm2, xmm2, xmm0, Assembler::AVX_128bit); blendvpb(xmm2, xmm2, xmm1, xmm0, Assembler::AVX_128bit); - vpclmulqdq(xmm8, xmm7, xmm10, 0x1); + vpclmulqdq(xmm8, xmm7, xmm10, 0x01); vpclmulqdq(xmm7, xmm7, xmm10, 0x10); vpxor(xmm7, xmm7, xmm8, Assembler::AVX_128bit); vpxor(xmm7, xmm7, xmm2, Assembler::AVX_128bit); bind(L_128_done); // compute crc of a 128-bit value - movdqu(xmm10, Address(key, 3 * 16)); + movdqu(xmm10, Address(table, 3 * 16)); movdqu(xmm0, xmm7); // 64b fold @@ -7361,14 +7569,14 @@ void MacroAssembler::kernel_crc32_avx512(Register crc, Register buf, Register le jmp(L_barrett); bind(L_less_than_256); - kernel_crc32_avx512_256B(crc, buf, len, key, pos, tmp1, tmp2, L_barrett, L_16B_reduction_loop, L_get_last_two_xmms, L_128_done, L_cleanup); + kernel_crc32_avx512_256B(crc, buf, len, table, pos, tmp1, tmp2, L_barrett, L_16B_reduction_loop, L_get_last_two_xmms, L_128_done, L_cleanup); //barrett reduction bind(L_barrett); vpand(xmm7, xmm7, ExternalAddress(StubRoutines::x86::crc_by128_masks_avx512_addr() + 1 * 16), Assembler::AVX_128bit, tmp2); movdqu(xmm1, xmm7); movdqu(xmm2, xmm7); - movdqu(xmm10, Address(key, 4 * 16)); + movdqu(xmm10, Address(table, 4 * 16)); pclmulqdq(xmm7, xmm10, 0x0); pxor(xmm7, xmm2); @@ -7380,7 +7588,6 @@ void MacroAssembler::kernel_crc32_avx512(Register crc, Register buf, Register le pextrd(crc, xmm7, 2); bind(L_cleanup); - notl(crc); // ~c addptr(rsp, 16 * 2 + 8); pop(r12); } @@ -8708,6 +8915,7 @@ void MacroAssembler::generate_fill_avx3(BasicType type, Register to, Register va Label L_fill_zmm_sequence; int shift = -1; + int avx3threshold = VM_Version::avx3_threshold(); switch(type) { case T_BYTE: shift = 0; break; @@ -8723,10 +8931,10 @@ void MacroAssembler::generate_fill_avx3(BasicType type, Register to, Register va fatal("Unhandled type: %s\n", type2name(type)); } - if (AVX3Threshold != 0 || MaxVectorSize == 32) { + if ((avx3threshold != 0) || (MaxVectorSize == 32)) { if (MaxVectorSize == 64) { - cmpq(count, AVX3Threshold >> shift); + cmpq(count, avx3threshold >> shift); jcc(Assembler::greater, L_fill_zmm_sequence); } @@ -9037,4 +9245,5 @@ void MacroAssembler::get_thread(Register thread) { } } + #endif // !WIN32 || _LP64 diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.hpp b/src/hotspot/cpu/x86/macroAssembler_x86.hpp index 392ff61d87fd4351f90a300d16aca5fcc45cd762..9b3da9d5de15cce9a36f1ac9438c47f715701f44 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -26,6 +26,7 @@ #define CPU_X86_MACROASSEMBLER_X86_HPP #include "asm/assembler.hpp" +#include "asm/register.hpp" #include "code/vmreg.inline.hpp" #include "compiler/oopMap.hpp" #include "utilities/macros.hpp" @@ -345,14 +346,14 @@ class MacroAssembler: public Assembler { void access_load_at(BasicType type, DecoratorSet decorators, Register dst, Address src, Register tmp1, Register thread_tmp); void access_store_at(BasicType type, DecoratorSet decorators, Address dst, Register src, - Register tmp1, Register tmp2); + Register tmp1, Register tmp2, Register tmp3); void load_heap_oop(Register dst, Address src, Register tmp1 = noreg, Register thread_tmp = noreg, DecoratorSet decorators = 0); void load_heap_oop_not_null(Register dst, Address src, Register tmp1 = noreg, Register thread_tmp = noreg, DecoratorSet decorators = 0); void store_heap_oop(Address dst, Register src, Register tmp1 = noreg, - Register tmp2 = noreg, DecoratorSet decorators = 0); + Register tmp2 = noreg, Register tmp3 = noreg, DecoratorSet decorators = 0); // Used for storing NULL. All other oop constants should be // stored using routines that take a jobject. @@ -521,9 +522,34 @@ class MacroAssembler: public Assembler { // Round up to a power of two void round_to(Register reg, int modulus); - // Callee saved registers handling - void push_callee_saved_registers(); - void pop_callee_saved_registers(); +private: + // General purpose and XMM registers potentially clobbered by native code; there + // is no need for FPU or AVX opmask related methods because C1/interpreter + // - we save/restore FPU state as a whole always + // - do not care about AVX-512 opmask + static RegSet call_clobbered_gp_registers(); + static XMMRegSet call_clobbered_xmm_registers(); + + void push_set(XMMRegSet set, int offset); + void pop_set(XMMRegSet set, int offset); + +public: + void push_set(RegSet set, int offset = -1); + void pop_set(RegSet set, int offset = -1); + + // Push and pop everything that might be clobbered by a native + // runtime call. + // Only save the lower 64 bits of each vector register. + // Additonal registers can be excluded in a passed RegSet. + void push_call_clobbered_registers_except(RegSet exclude, bool save_fpu = true); + void pop_call_clobbered_registers_except(RegSet exclude, bool restore_fpu = true); + + void push_call_clobbered_registers(bool save_fpu = true) { + push_call_clobbered_registers_except(RegSet(), save_fpu); + } + void pop_call_clobbered_registers(bool restore_fpu = true) { + pop_call_clobbered_registers_except(RegSet(), restore_fpu); + } // allocation void eden_allocate( @@ -1117,6 +1143,8 @@ public: void vmovdqu(XMMRegister dst, Address src); void vmovdqu(XMMRegister dst, XMMRegister src); void vmovdqu(XMMRegister dst, AddressLiteral src, Register scratch_reg = rscratch1); + void vmovdqu(XMMRegister dst, AddressLiteral src, Register scratch_reg, int vector_len); + // AVX512 Unaligned void evmovdqu(BasicType type, KRegister kmask, Address dst, XMMRegister src, int vector_len); @@ -1174,6 +1202,9 @@ public: void movsd(XMMRegister dst, Address src) { Assembler::movsd(dst, src); } void movsd(XMMRegister dst, AddressLiteral src); + using Assembler::vmovddup; + void vmovddup(XMMRegister dst, AddressLiteral src, int vector_len, Register rscratch = rscratch1); + void mulpd(XMMRegister dst, XMMRegister src) { Assembler::mulpd(dst, src); } void mulpd(XMMRegister dst, Address src) { Assembler::mulpd(dst, src); } void mulpd(XMMRegister dst, AddressLiteral src); @@ -1282,6 +1313,9 @@ public: void vpbroadcastw(XMMRegister dst, XMMRegister src, int vector_len); void vpbroadcastw(XMMRegister dst, Address src, int vector_len) { Assembler::vpbroadcastw(dst, src, vector_len); } + using Assembler::vbroadcastsd; + void vbroadcastsd(XMMRegister dst, AddressLiteral src, int vector_len, Register rscratch = rscratch1); + void vpcmpeqb(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); void vpcmpeqw(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); @@ -1308,7 +1342,7 @@ public: void evpbroadcast(BasicType type, XMMRegister dst, Register src, int vector_len); // Emit comparison instruction for the specified comparison predicate. - void vpcmpCCW(XMMRegister dst, XMMRegister nds, XMMRegister src, ComparisonPredicate cond, Width width, int vector_len, Register scratch_reg); + void vpcmpCCW(XMMRegister dst, XMMRegister nds, XMMRegister src, XMMRegister xtmp, ComparisonPredicate cond, Width width, int vector_len); void vpcmpCC(XMMRegister dst, XMMRegister nds, XMMRegister src, int cond_encoding, Width width, int vector_len); void vpmovzxbw(XMMRegister dst, Address src, int vector_len); @@ -1487,8 +1521,14 @@ public: void vpxor(XMMRegister dst, XMMRegister nds, AddressLiteral src, int vector_len, Register scratch_reg = rscratch1); // Simple version for AVX2 256bit vectors - void vpxor(XMMRegister dst, XMMRegister src) { Assembler::vpxor(dst, dst, src, true); } - void vpxor(XMMRegister dst, Address src) { Assembler::vpxor(dst, dst, src, true); } + void vpxor(XMMRegister dst, XMMRegister src) { + assert(UseAVX >= 2, "Should be at least AVX2"); + Assembler::vpxor(dst, dst, src, AVX_256bit); + } + void vpxor(XMMRegister dst, Address src) { + assert(UseAVX >= 2, "Should be at least AVX2"); + Assembler::vpxor(dst, dst, src, AVX_256bit); + } void vpermd(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { Assembler::vpermd(dst, nds, src, vector_len); } void vpermd(XMMRegister dst, XMMRegister nds, AddressLiteral src, int vector_len, Register scratch_reg); diff --git a/src/hotspot/cpu/x86/macroAssembler_x86_arrayCopy_avx3.cpp b/src/hotspot/cpu/x86/macroAssembler_x86_arrayCopy_avx3.cpp index cbf4db8966b643afea4d6881bdd54168eddcd9c4..79ff020a54d0ab7e559e5b8c7326d6d7ae3e0e99 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86_arrayCopy_avx3.cpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86_arrayCopy_avx3.cpp @@ -114,7 +114,7 @@ void MacroAssembler::arraycopy_avx3_special_cases_conjoint(XMMRegister xmm, KReg bool use64byteVector, Label& L_entry, Label& L_exit) { Label L_entry_64, L_entry_96, L_entry_128; Label L_entry_160, L_entry_192; - bool avx3 = MaxVectorSize > 32 && AVX3Threshold == 0; + bool avx3 = (MaxVectorSize > 32) && (VM_Version::avx3_threshold() == 0); int size_mat[][6] = { /* T_BYTE */ {32 , 64, 96 , 128 , 160 , 192 }, diff --git a/src/hotspot/cpu/x86/matcher_x86.hpp b/src/hotspot/cpu/x86/matcher_x86.hpp index 2dcd1e6e7a94adacf4494dfa848dd884ef2e10a4..9711bc8c2c4368d36d616aacb13c54511ac67fe7 100644 --- a/src/hotspot/cpu/x86/matcher_x86.hpp +++ b/src/hotspot/cpu/x86/matcher_x86.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -148,8 +148,6 @@ static const bool int_in_long = false; #endif - // Number of htbl entries for aes-gcm intrinsic - static const int htbl_entries = 96; // Does the CPU supports vector variable shift instructions? static bool supports_vector_variable_shifts(void) { @@ -168,20 +166,7 @@ // Does the CPU supports vector unsigned comparison instructions? static const bool supports_vector_comparison_unsigned(int vlen, BasicType bt) { - int vlen_in_bytes = vlen * type2aelembytes(bt); - if ((UseAVX > 2) && (VM_Version::supports_avx512vl() || vlen_in_bytes == 64)) - return true; - else { - // instruction set supports only signed comparison - // so need to zero extend to higher integral type and perform comparison - // cannot cast long to higher integral type - // and on avx1 cannot cast 128 bit integral vectors to higher size - - if ((bt != T_LONG) && - ((UseAVX >= 2) || (vlen_in_bytes <= 8))) - return true; - } - return false; + return true; } // Some microarchitectures have mask registers used on vectors @@ -198,4 +183,13 @@ // Implements a variant of EncodeISOArrayNode that encode ASCII only static const bool supports_encode_ascii_array = true; + // Returns pre-selection estimated cost of a vector operation. + static int vector_op_pre_select_sz_estimate(int vopc, BasicType ety, int vlen) { + switch(vopc) { + default: return 0; + case Op_PopCountVI: return VM_Version::supports_avx512_vpopcntdq() ? 0 : 50; + case Op_PopCountVL: return VM_Version::supports_avx512_vpopcntdq() ? 0 : 40; + } + } + #endif // CPU_X86_MATCHER_X86_HPP diff --git a/src/hotspot/cpu/x86/nativeInst_x86.cpp b/src/hotspot/cpu/x86/nativeInst_x86.cpp index fb00defc99e61e672f569e9ecc019183e16d53ee..0374a9cadeaaa06b3fb7234c1c8682569b553d12 100644 --- a/src/hotspot/cpu/x86/nativeInst_x86.cpp +++ b/src/hotspot/cpu/x86/nativeInst_x86.cpp @@ -260,6 +260,9 @@ void NativeCall::replace_mt_safe(address instr_addr, address code_buffer) { } +bool NativeCall::is_displacement_aligned() { + return (uintptr_t) displacement_address() % 4 == 0; +} // Similar to replace_mt_safe, but just changes the destination. The // important thing is that free-running threads are able to execute this @@ -282,8 +285,7 @@ void NativeCall::set_destination_mt_safe(address dest) { 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. - bool is_aligned = ((uintptr_t)displacement_address() + 0) / cache_line_size == - ((uintptr_t)displacement_address() + 3) / cache_line_size; + bool is_aligned = is_displacement_aligned(); guarantee(is_aligned, "destination must be aligned"); diff --git a/src/hotspot/cpu/x86/nativeInst_x86.hpp b/src/hotspot/cpu/x86/nativeInst_x86.hpp index 94f8b5e637c958af88a1852971dd8602fb60e9c0..a86128e7e4c02523327948b44884edc444f860e3 100644 --- a/src/hotspot/cpu/x86/nativeInst_x86.hpp +++ b/src/hotspot/cpu/x86/nativeInst_x86.hpp @@ -160,8 +160,6 @@ class NativeCall: public NativeInstruction { return_address_offset = 5 }; - enum { cache_line_size = BytesPerWord }; // conservative estimate! - address instruction_address() const { return addr_at(instruction_offset); } address next_instruction_address() const { return addr_at(return_address_offset); } int displacement() const { return (jint) int_at(displacement_offset); } @@ -175,9 +173,11 @@ class NativeCall: public NativeInstruction { #endif // AMD64 set_int_at(displacement_offset, dest - return_address()); } + // Returns whether the 4-byte displacement operand is 4-byte aligned. + bool is_displacement_aligned(); void set_destination_mt_safe(address dest); - void verify_alignment() { assert((intptr_t)addr_at(displacement_offset) % BytesPerInt == 0, "must be aligned"); } + void verify_alignment() { assert(is_displacement_aligned(), "displacement of call is not aligned"); } void verify(); void print(); diff --git a/src/hotspot/cpu/x86/rdtsc_x86.cpp b/src/hotspot/cpu/x86/rdtsc_x86.cpp index a4e743cc2dfbfaf9ca2ebda349cbd2cad6d61091..c6109ccdefec75be712e06f15345e74cf4a3890b 100644 --- a/src/hotspot/cpu/x86/rdtsc_x86.cpp +++ b/src/hotspot/cpu/x86/rdtsc_x86.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -27,7 +27,7 @@ #include "runtime/globals_extension.hpp" #include "runtime/orderAccess.hpp" #include "runtime/thread.inline.hpp" -#include "vm_version_ext_x86.hpp" +#include "vm_version_x86.hpp" // The following header contains the implementations of rdtsc() #include OS_CPU_HEADER_INLINE(os) @@ -101,9 +101,9 @@ static jlong initialize_frequency() { // if platform supports invariant tsc, // apply higher resolution and granularity for conversion calculations - if (VM_Version_Ext::supports_tscinv_ext()) { + if (VM_Version::supports_tscinv_ext()) { // for invariant tsc platforms, take the maximum qualified cpu frequency - tsc_freq = (double)VM_Version_Ext::maximum_qualified_cpu_frequency(); + tsc_freq = (double)VM_Version::maximum_qualified_cpu_frequency(); os_to_tsc_conv_factor = tsc_freq / os_freq; } else { // use measurements to estimate @@ -171,7 +171,7 @@ static bool ergonomics() { } bool Rdtsc::is_supported() { - return VM_Version_Ext::supports_tscinv_ext(); + return VM_Version::supports_tscinv_ext(); } bool Rdtsc::is_elapsed_counter_enabled() { @@ -198,7 +198,7 @@ bool Rdtsc::initialize() { static bool initialized = false; if (!initialized) { assert(!rdtsc_elapsed_counter_enabled, "invariant"); - VM_Version_Ext::initialize(); + VM_Version::initialize_tsc(); assert(0 == tsc_frequency, "invariant"); assert(0 == _epoch, "invariant"); bool result = initialize_elapsed_counter(); // init hw diff --git a/src/hotspot/cpu/x86/rdtsc_x86.hpp b/src/hotspot/cpu/x86/rdtsc_x86.hpp index f66997c9cfedfeae8cd1650931b79a656bbd9022..d9e77a0ae6bcf32d6d79711255d7fbc9b2b0b47f 100644 --- a/src/hotspot/cpu/x86/rdtsc_x86.hpp +++ b/src/hotspot/cpu/x86/rdtsc_x86.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -25,7 +25,8 @@ #ifndef CPU_X86_RDTSC_X86_HPP #define CPU_X86_RDTSC_X86_HPP -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" +#include "utilities/globalDefinitions.hpp" #include "utilities/macros.hpp" // Interface to the x86 rdtsc() time counter, if available. diff --git a/src/hotspot/cpu/x86/register_definitions_x86.cpp b/src/hotspot/cpu/x86/register_definitions_x86.cpp deleted file mode 100644 index 07466930ffac0df7d3b0e60474e26948613c71e7..0000000000000000000000000000000000000000 --- a/src/hotspot/cpu/x86/register_definitions_x86.cpp +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright (c) 2002, 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 "asm/assembler.hpp" -#include "asm/register.hpp" -#include "register_x86.hpp" -#include "interp_masm_x86.hpp" - -REGISTER_DEFINITION(Register, noreg); -REGISTER_DEFINITION(Register, rax); -REGISTER_DEFINITION(Register, rcx); -REGISTER_DEFINITION(Register, rdx); -REGISTER_DEFINITION(Register, rbx); -REGISTER_DEFINITION(Register, rsp); -REGISTER_DEFINITION(Register, rbp); -REGISTER_DEFINITION(Register, rsi); -REGISTER_DEFINITION(Register, rdi); -#ifdef AMD64 -REGISTER_DEFINITION(Register, r8); -REGISTER_DEFINITION(Register, r9); -REGISTER_DEFINITION(Register, r10); -REGISTER_DEFINITION(Register, r11); -REGISTER_DEFINITION(Register, r12); -REGISTER_DEFINITION(Register, r13); -REGISTER_DEFINITION(Register, r14); -REGISTER_DEFINITION(Register, r15); -#endif // AMD64 - -REGISTER_DEFINITION(FloatRegister, fnoreg); - -REGISTER_DEFINITION(XMMRegister, xnoreg); -REGISTER_DEFINITION(XMMRegister, xmm0 ); -REGISTER_DEFINITION(XMMRegister, xmm1 ); -REGISTER_DEFINITION(XMMRegister, xmm2 ); -REGISTER_DEFINITION(XMMRegister, xmm3 ); -REGISTER_DEFINITION(XMMRegister, xmm4 ); -REGISTER_DEFINITION(XMMRegister, xmm5 ); -REGISTER_DEFINITION(XMMRegister, xmm6 ); -REGISTER_DEFINITION(XMMRegister, xmm7 ); -#ifdef AMD64 -REGISTER_DEFINITION(XMMRegister, xmm8); -REGISTER_DEFINITION(XMMRegister, xmm9); -REGISTER_DEFINITION(XMMRegister, xmm10); -REGISTER_DEFINITION(XMMRegister, xmm11); -REGISTER_DEFINITION(XMMRegister, xmm12); -REGISTER_DEFINITION(XMMRegister, xmm13); -REGISTER_DEFINITION(XMMRegister, xmm14); -REGISTER_DEFINITION(XMMRegister, xmm15); -REGISTER_DEFINITION(XMMRegister, xmm16); -REGISTER_DEFINITION(XMMRegister, xmm17); -REGISTER_DEFINITION(XMMRegister, xmm18); -REGISTER_DEFINITION(XMMRegister, xmm19); -REGISTER_DEFINITION(XMMRegister, xmm20); -REGISTER_DEFINITION(XMMRegister, xmm21); -REGISTER_DEFINITION(XMMRegister, xmm22); -REGISTER_DEFINITION(XMMRegister, xmm23); -REGISTER_DEFINITION(XMMRegister, xmm24); -REGISTER_DEFINITION(XMMRegister, xmm25); -REGISTER_DEFINITION(XMMRegister, xmm26); -REGISTER_DEFINITION(XMMRegister, xmm27); -REGISTER_DEFINITION(XMMRegister, xmm28); -REGISTER_DEFINITION(XMMRegister, xmm29); -REGISTER_DEFINITION(XMMRegister, xmm30); -REGISTER_DEFINITION(XMMRegister, xmm31); - -REGISTER_DEFINITION(Register, c_rarg0); -REGISTER_DEFINITION(Register, c_rarg1); -REGISTER_DEFINITION(Register, c_rarg2); -REGISTER_DEFINITION(Register, c_rarg3); - -REGISTER_DEFINITION(XMMRegister, c_farg0); -REGISTER_DEFINITION(XMMRegister, c_farg1); -REGISTER_DEFINITION(XMMRegister, c_farg2); -REGISTER_DEFINITION(XMMRegister, c_farg3); - -// Non windows OS's have a few more argument registers -#ifndef _WIN64 -REGISTER_DEFINITION(Register, c_rarg4); -REGISTER_DEFINITION(Register, c_rarg5); - -REGISTER_DEFINITION(XMMRegister, c_farg4); -REGISTER_DEFINITION(XMMRegister, c_farg5); -REGISTER_DEFINITION(XMMRegister, c_farg6); -REGISTER_DEFINITION(XMMRegister, c_farg7); -#endif /* _WIN64 */ - -REGISTER_DEFINITION(Register, j_rarg0); -REGISTER_DEFINITION(Register, j_rarg1); -REGISTER_DEFINITION(Register, j_rarg2); -REGISTER_DEFINITION(Register, j_rarg3); -REGISTER_DEFINITION(Register, j_rarg4); -REGISTER_DEFINITION(Register, j_rarg5); - -REGISTER_DEFINITION(XMMRegister, j_farg0); -REGISTER_DEFINITION(XMMRegister, j_farg1); -REGISTER_DEFINITION(XMMRegister, j_farg2); -REGISTER_DEFINITION(XMMRegister, j_farg3); -REGISTER_DEFINITION(XMMRegister, j_farg4); -REGISTER_DEFINITION(XMMRegister, j_farg5); -REGISTER_DEFINITION(XMMRegister, j_farg6); -REGISTER_DEFINITION(XMMRegister, j_farg7); - -REGISTER_DEFINITION(Register, rscratch1); -REGISTER_DEFINITION(Register, rscratch2); - -REGISTER_DEFINITION(Register, r12_heapbase); -REGISTER_DEFINITION(Register, r15_thread); -#endif // AMD64 - -REGISTER_DEFINITION(KRegister, knoreg); -REGISTER_DEFINITION(KRegister, k0); -REGISTER_DEFINITION(KRegister, k1); -REGISTER_DEFINITION(KRegister, k2); -REGISTER_DEFINITION(KRegister, k3); -REGISTER_DEFINITION(KRegister, k4); -REGISTER_DEFINITION(KRegister, k5); -REGISTER_DEFINITION(KRegister, k6); -REGISTER_DEFINITION(KRegister, k7); - -// JSR 292 -REGISTER_DEFINITION(Register, rbp_mh_SP_save); diff --git a/src/hotspot/cpu/x86/register_x86.hpp b/src/hotspot/cpu/x86/register_x86.hpp index b9ac28902407560b1d03df290b731b4f407ede7c..f57b1db48c838e86ddddacca263f8d2662f244c8 100644 --- a/src/hotspot/cpu/x86/register_x86.hpp +++ b/src/hotspot/cpu/x86/register_x86.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -26,6 +26,8 @@ #define CPU_X86_REGISTER_X86_HPP #include "asm/register.hpp" +#include "utilities/count_leading_zeros.hpp" +#include "utilities/powerOfTwo.hpp" class VMRegImpl; typedef VMRegImpl* VMReg; @@ -135,7 +137,7 @@ inline XMMRegister as_XMMRegister(int encoding) { } -// The implementation of XMM registers for the IA32 architecture +// The implementation of XMM registers. class XMMRegisterImpl: public AbstractRegisterImpl { public: enum { @@ -201,11 +203,7 @@ CONSTANT_REGISTER_DECLARATION(XMMRegister, xmm30, (30)); CONSTANT_REGISTER_DECLARATION(XMMRegister, xmm31, (31)); #endif // AMD64 -// Only used by the 32bit stubGenerator. These can't be described by vmreg and hence -// can't be described in oopMaps and therefore can't be used by the compilers (at least -// were deopt might wan't to see them). - -// Use XMMRegister as shortcut +// Use KRegister as shortcut class KRegisterImpl; typedef KRegisterImpl* KRegister; @@ -213,7 +211,7 @@ inline KRegister as_KRegister(int encoding) { return (KRegister)(intptr_t)encoding; } -// The implementation of XMM registers for the IA32 architecture +// The implementation of AVX-3 (AVX-512) opmask registers. class KRegisterImpl : public AbstractRegisterImpl { public: enum { @@ -276,4 +274,33 @@ class ConcreteRegisterImpl : public AbstractRegisterImpl { }; +template <> +inline Register AbstractRegSet::first() { + uint32_t first = _bitset & -_bitset; + return first ? as_Register(exact_log2(first)) : noreg; +} + +template <> +inline Register AbstractRegSet::last() { + if (_bitset == 0) { return noreg; } + uint32_t last = 31 - count_leading_zeros(_bitset); + return as_Register(last); +} + +template <> +inline XMMRegister AbstractRegSet::first() { + uint32_t first = _bitset & -_bitset; + return first ? as_XMMRegister(exact_log2(first)) : xnoreg; +} + +template <> +inline XMMRegister AbstractRegSet::last() { + if (_bitset == 0) { return xnoreg; } + uint32_t last = 31 - count_leading_zeros(_bitset); + return as_XMMRegister(last); +} + +typedef AbstractRegSet RegSet; +typedef AbstractRegSet XMMRegSet; + #endif // CPU_X86_REGISTER_X86_HPP diff --git a/src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp b/src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp index a00af0e4af0d61c1ccf64598a5ef314a3a2e2930..e5a46138473dff074e7032b7943842e0489d7c0a 100644 --- a/src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp +++ b/src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp @@ -1705,36 +1705,41 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, // Load the oop from the handle __ movptr(obj_reg, Address(oop_handle_reg, 0)); - // Load immediate 1 into swap_reg %rax, - __ movptr(swap_reg, 1); - - // Load (object->mark() | 1) into swap_reg %rax, - __ orptr(swap_reg, Address(obj_reg, oopDesc::mark_offset_in_bytes())); - - // Save (object->mark() | 1) into BasicLock's displaced header - __ movptr(Address(lock_reg, mark_word_offset), swap_reg); - - // src -> dest iff dest == rax, else rax, <- dest - // *obj_reg = lock_reg iff *obj_reg == rax, else rax, = *(obj_reg) - __ lock(); - __ cmpxchgptr(lock_reg, Address(obj_reg, oopDesc::mark_offset_in_bytes())); - __ jcc(Assembler::equal, lock_done); - - // Test if the oopMark is an obvious stack pointer, i.e., - // 1) (mark & 3) == 0, and - // 2) rsp <= mark < mark + os::pagesize() - // These 3 tests can be done by evaluating the following - // expression: ((mark - rsp) & (3 - os::vm_page_size())), - // assuming both stack pointer and pagesize have their - // least significant 2 bits clear. - // NOTE: the oopMark is in swap_reg %rax, as the result of cmpxchg - - __ subptr(swap_reg, rsp); - __ andptr(swap_reg, 3 - os::vm_page_size()); - - // Save the test result, for recursive case, the result is zero - __ movptr(Address(lock_reg, mark_word_offset), swap_reg); - __ jcc(Assembler::notEqual, slow_path_lock); + if (!UseHeavyMonitors) { + // Load immediate 1 into swap_reg %rax, + __ movptr(swap_reg, 1); + + // Load (object->mark() | 1) into swap_reg %rax, + __ orptr(swap_reg, Address(obj_reg, oopDesc::mark_offset_in_bytes())); + + // Save (object->mark() | 1) into BasicLock's displaced header + __ movptr(Address(lock_reg, mark_word_offset), swap_reg); + + // src -> dest iff dest == rax, else rax, <- dest + // *obj_reg = lock_reg iff *obj_reg == rax, else rax, = *(obj_reg) + __ lock(); + __ cmpxchgptr(lock_reg, Address(obj_reg, oopDesc::mark_offset_in_bytes())); + __ jcc(Assembler::equal, lock_done); + + // Test if the oopMark is an obvious stack pointer, i.e., + // 1) (mark & 3) == 0, and + // 2) rsp <= mark < mark + os::pagesize() + // These 3 tests can be done by evaluating the following + // expression: ((mark - rsp) & (3 - os::vm_page_size())), + // assuming both stack pointer and pagesize have their + // least significant 2 bits clear. + // NOTE: the oopMark is in swap_reg %rax, as the result of cmpxchg + + __ subptr(swap_reg, rsp); + __ andptr(swap_reg, 3 - os::vm_page_size()); + + // Save the test result, for recursive case, the result is zero + __ movptr(Address(lock_reg, mark_word_offset), swap_reg); + __ jcc(Assembler::notEqual, slow_path_lock); + } else { + __ jmp(slow_path_lock); + } + // Slow path will re-enter here __ bind(lock_done); } @@ -1852,28 +1857,34 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, // Get locked oop from the handle we passed to jni __ movptr(obj_reg, Address(oop_handle_reg, 0)); - // Simple recursive lock? + if (!UseHeavyMonitors) { + // Simple recursive lock? - __ cmpptr(Address(rbp, lock_slot_rbp_offset), (int32_t)NULL_WORD); - __ jcc(Assembler::equal, done); + __ cmpptr(Address(rbp, lock_slot_rbp_offset), (int32_t)NULL_WORD); + __ jcc(Assembler::equal, done); + } - // Must save rax, if if it is live now because cmpxchg must use it + // Must save rax, if it is live now because cmpxchg must use it if (ret_type != T_FLOAT && ret_type != T_DOUBLE && ret_type != T_VOID) { save_native_result(masm, ret_type, stack_slots); } - // get old displaced header - __ movptr(rbx, Address(rbp, lock_slot_rbp_offset)); + if (!UseHeavyMonitors) { + // get old displaced header + __ movptr(rbx, Address(rbp, lock_slot_rbp_offset)); - // get address of the stack lock - __ lea(rax, Address(rbp, lock_slot_rbp_offset)); + // get address of the stack lock + __ lea(rax, Address(rbp, lock_slot_rbp_offset)); - // Atomic swap old header if oop still contains the stack lock - // src -> dest iff dest == rax, else rax, <- dest - // *obj_reg = rbx, iff *obj_reg == rax, else rax, = *(obj_reg) - __ lock(); - __ cmpxchgptr(rbx, Address(obj_reg, oopDesc::mark_offset_in_bytes())); - __ jcc(Assembler::notEqual, slow_path_unlock); + // Atomic swap old header if oop still contains the stack lock + // src -> dest iff dest == rax, else rax, <- dest + // *obj_reg = rbx, iff *obj_reg == rax, else rax, = *(obj_reg) + __ lock(); + __ cmpxchgptr(rbx, Address(obj_reg, oopDesc::mark_offset_in_bytes())); + __ jcc(Assembler::notEqual, slow_path_unlock); + } else { + __ jmp(slow_path_unlock); + } // slow path re-enters here __ bind(unlock_done); diff --git a/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp b/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp index f78ec39c25e42c7dc8a3c3d55e776546cec92091..8bfbe3303da9e9a8f1dc0604cdbaaf6329d780c5 100644 --- a/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp +++ b/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -1918,37 +1918,41 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, // Load the oop from the handle __ movptr(obj_reg, Address(oop_handle_reg, 0)); - // Load immediate 1 into swap_reg %rax - __ movl(swap_reg, 1); + if (!UseHeavyMonitors) { + // Load immediate 1 into swap_reg %rax + __ movl(swap_reg, 1); - // Load (object->mark() | 1) into swap_reg %rax - __ orptr(swap_reg, Address(obj_reg, oopDesc::mark_offset_in_bytes())); + // Load (object->mark() | 1) into swap_reg %rax + __ orptr(swap_reg, Address(obj_reg, oopDesc::mark_offset_in_bytes())); - // Save (object->mark() | 1) into BasicLock's displaced header - __ movptr(Address(lock_reg, mark_word_offset), swap_reg); + // Save (object->mark() | 1) into BasicLock's displaced header + __ movptr(Address(lock_reg, mark_word_offset), swap_reg); - // src -> dest iff dest == rax else rax <- dest - __ lock(); - __ cmpxchgptr(lock_reg, Address(obj_reg, oopDesc::mark_offset_in_bytes())); - __ jcc(Assembler::equal, lock_done); + // src -> dest iff dest == rax else rax <- dest + __ lock(); + __ cmpxchgptr(lock_reg, Address(obj_reg, oopDesc::mark_offset_in_bytes())); + __ jcc(Assembler::equal, lock_done); - // Hmm should this move to the slow path code area??? + // Hmm should this move to the slow path code area??? - // Test if the oopMark is an obvious stack pointer, i.e., - // 1) (mark & 3) == 0, and - // 2) rsp <= mark < mark + os::pagesize() - // These 3 tests can be done by evaluating the following - // expression: ((mark - rsp) & (3 - os::vm_page_size())), - // assuming both stack pointer and pagesize have their - // least significant 2 bits clear. - // NOTE: the oopMark is in swap_reg %rax as the result of cmpxchg + // Test if the oopMark is an obvious stack pointer, i.e., + // 1) (mark & 3) == 0, and + // 2) rsp <= mark < mark + os::pagesize() + // These 3 tests can be done by evaluating the following + // expression: ((mark - rsp) & (3 - os::vm_page_size())), + // assuming both stack pointer and pagesize have their + // least significant 2 bits clear. + // NOTE: the oopMark is in swap_reg %rax as the result of cmpxchg - __ subptr(swap_reg, rsp); - __ andptr(swap_reg, 3 - os::vm_page_size()); + __ subptr(swap_reg, rsp); + __ andptr(swap_reg, 3 - os::vm_page_size()); - // Save the test result, for recursive case, the result is zero - __ movptr(Address(lock_reg, mark_word_offset), swap_reg); - __ jcc(Assembler::notEqual, slow_path_lock); + // Save the test result, for recursive case, the result is zero + __ movptr(Address(lock_reg, mark_word_offset), swap_reg); + __ jcc(Assembler::notEqual, slow_path_lock); + } else { + __ jmp(slow_path_lock); + } // Slow path will re-enter here @@ -2055,26 +2059,32 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, __ movptr(obj_reg, Address(oop_handle_reg, 0)); Label done; - // Simple recursive lock? - __ cmpptr(Address(rsp, lock_slot_offset * VMRegImpl::stack_slot_size), (int32_t)NULL_WORD); - __ jcc(Assembler::equal, done); + if (!UseHeavyMonitors) { + // Simple recursive lock? + __ cmpptr(Address(rsp, lock_slot_offset * VMRegImpl::stack_slot_size), (int32_t)NULL_WORD); + __ jcc(Assembler::equal, done); + } - // Must save rax if if it is live now because cmpxchg must use it + // Must save rax if it is live now because cmpxchg must use it if (ret_type != T_FLOAT && ret_type != T_DOUBLE && ret_type != T_VOID) { save_native_result(masm, ret_type, stack_slots); } - // get address of the stack lock - __ lea(rax, Address(rsp, lock_slot_offset * VMRegImpl::stack_slot_size)); - // get old displaced header - __ movptr(old_hdr, Address(rax, 0)); + if (!UseHeavyMonitors) { + // get address of the stack lock + __ lea(rax, Address(rsp, lock_slot_offset * VMRegImpl::stack_slot_size)); + // get old displaced header + __ movptr(old_hdr, Address(rax, 0)); - // Atomic swap old header if oop still contains the stack lock - __ lock(); - __ cmpxchgptr(old_hdr, Address(obj_reg, oopDesc::mark_offset_in_bytes())); - __ jcc(Assembler::notEqual, slow_path_unlock); + // Atomic swap old header if oop still contains the stack lock + __ lock(); + __ cmpxchgptr(old_hdr, Address(obj_reg, oopDesc::mark_offset_in_bytes())); + __ jcc(Assembler::notEqual, slow_path_unlock); + } else { + __ jmp(slow_path_unlock); + } // slow path re-enters here __ bind(unlock_done); @@ -2992,7 +3002,7 @@ RuntimeStub* SharedRuntime::generate_resolve_blob(address destination, const cha // allocate space for the code ResourceMark rm; - CodeBuffer buffer(name, 1000, 512); + CodeBuffer buffer(name, 1200, 512); MacroAssembler* masm = new MacroAssembler(&buffer); int frame_size_in_words; @@ -3532,8 +3542,9 @@ void SharedRuntime::montgomery_multiply(jint *a_ints, jint *b_ints, jint *n_ints // Make very sure we don't use so much space that the stack might // overflow. 512 jints corresponds to an 16384-bit integer and // will use here a total of 8k bytes of stack space. + int divisor = sizeof(julong) * 4; + guarantee(longwords <= 8192 / divisor, "must be"); int total_allocation = longwords * sizeof (julong) * 4; - guarantee(total_allocation <= 8192, "must be"); julong *scratch = (julong *)alloca(total_allocation); // Local scratch arrays @@ -3561,8 +3572,9 @@ void SharedRuntime::montgomery_square(jint *a_ints, jint *n_ints, // Make very sure we don't use so much space that the stack might // overflow. 512 jints corresponds to an 16384-bit integer and // will use here a total of 6k bytes of stack space. + int divisor = sizeof(julong) * 3; + guarantee(longwords <= (8192 / divisor), "must be"); int total_allocation = longwords * sizeof (julong) * 3; - guarantee(total_allocation <= 8192, "must be"); julong *scratch = (julong *)alloca(total_allocation); // Local scratch arrays diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_32.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_32.cpp index 1525d10e5b5f3dea743318ca097dd1b3098dd6f5..24cfc237b23591e90d3633e26529c4c1b5051d09 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_32.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_32.cpp @@ -588,6 +588,30 @@ class StubGenerator: public StubCodeGenerator { return start; } + address generate_popcount_avx_lut(const char *stub_name) { + __ align64(); + StubCodeMark mark(this, "StubRoutines", stub_name); + address start = __ pc(); + __ emit_data(0x02010100, relocInfo::none, 0); + __ emit_data(0x03020201, relocInfo::none, 0); + __ emit_data(0x03020201, relocInfo::none, 0); + __ emit_data(0x04030302, relocInfo::none, 0); + __ emit_data(0x02010100, relocInfo::none, 0); + __ emit_data(0x03020201, relocInfo::none, 0); + __ emit_data(0x03020201, relocInfo::none, 0); + __ emit_data(0x04030302, relocInfo::none, 0); + __ emit_data(0x02010100, relocInfo::none, 0); + __ emit_data(0x03020201, relocInfo::none, 0); + __ emit_data(0x03020201, relocInfo::none, 0); + __ emit_data(0x04030302, relocInfo::none, 0); + __ emit_data(0x02010100, relocInfo::none, 0); + __ emit_data(0x03020201, relocInfo::none, 0); + __ emit_data(0x03020201, relocInfo::none, 0); + __ emit_data(0x04030302, relocInfo::none, 0); + return start; + } + + address generate_iota_indices(const char *stub_name) { __ align(CodeEntryAlignment); StubCodeMark mark(this, "StubRoutines", stub_name); @@ -4004,6 +4028,11 @@ class StubGenerator: public StubCodeGenerator { StubRoutines::x86::_vector_int_mask_cmp_bits = generate_vector_mask("vector_int_mask_cmp_bits", 0x00000001); StubRoutines::x86::_vector_iota_indices = generate_iota_indices("iota_indices"); + if (UsePopCountInstruction && VM_Version::supports_avx2() && !VM_Version::supports_avx512_vpopcntdq()) { + // lut implementation influenced by counting 1s algorithm from section 5-1 of Hackers' Delight. + StubRoutines::x86::_vector_popcount_lut = generate_popcount_avx_lut("popcount_lut"); + } + // support for verify_oop (must happen after universe_init) StubRoutines::_verify_oop_subroutine_entry = generate_verify_oop(); diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp index f5ef24ddf4cecfc19794c57155364d4aa2a32cac..39d5cbe2fb4638c4e5104bc53c86a13848e85b4c 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp @@ -795,6 +795,21 @@ class StubGenerator: public StubCodeGenerator { return start; } + address generate_popcount_avx_lut(const char *stub_name) { + __ align64(); + StubCodeMark mark(this, "StubRoutines", stub_name); + address start = __ pc(); + __ emit_data64(0x0302020102010100, relocInfo::none); + __ emit_data64(0x0403030203020201, relocInfo::none); + __ emit_data64(0x0302020102010100, relocInfo::none); + __ emit_data64(0x0403030203020201, relocInfo::none); + __ emit_data64(0x0302020102010100, relocInfo::none); + __ emit_data64(0x0403030203020201, relocInfo::none); + __ emit_data64(0x0302020102010100, relocInfo::none); + __ emit_data64(0x0403030203020201, relocInfo::none); + return start; + } + address generate_iota_indices(const char *stub_name) { __ align(CodeEntryAlignment); StubCodeMark mark(this, "StubRoutines", stub_name); @@ -1221,11 +1236,6 @@ class StubGenerator: public StubCodeGenerator { } __ addptr(qword_count, 4); __ BIND(L_end); - if (UseAVX >= 2) { - // clean upper bits of YMM registers - __ vpxor(xmm0, xmm0); - __ vpxor(xmm1, xmm1); - } } else { // Copy 32-bytes per iteration __ BIND(L_loop); @@ -1299,11 +1309,6 @@ class StubGenerator: public StubCodeGenerator { } __ subptr(qword_count, 4); __ BIND(L_end); - if (UseAVX >= 2) { - // clean upper bits of YMM registers - __ vpxor(xmm0, xmm0); - __ vpxor(xmm1, xmm1); - } } else { // Copy 32-bytes per iteration __ BIND(L_loop); @@ -1384,8 +1389,8 @@ class StubGenerator: public StubCodeGenerator { __ align(CodeEntryAlignment); StubCodeMark mark(this, "StubRoutines", name); address start = __ pc(); - - bool use64byteVector = MaxVectorSize > 32 && AVX3Threshold == 0; + int avx3threshold = VM_Version::avx3_threshold(); + bool use64byteVector = (MaxVectorSize > 32) && (avx3threshold == 0); Label L_main_loop, L_main_loop_64bytes, L_tail, L_tail64, L_exit, L_entry; Label L_repmovs, L_main_pre_loop, L_main_pre_loop_64bytes, L_pre_main_post_64; const Register from = rdi; // source array address @@ -1448,7 +1453,7 @@ class StubGenerator: public StubCodeGenerator { // PRE-MAIN-POST loop for aligned copy. __ BIND(L_entry); - if (AVX3Threshold != 0) { + if (avx3threshold != 0) { __ cmpq(count, threshold[shift]); if (MaxVectorSize == 64) { // Copy using 64 byte vectors. @@ -1460,7 +1465,7 @@ class StubGenerator: public StubCodeGenerator { } } - if (MaxVectorSize < 64 || AVX3Threshold != 0) { + if ((MaxVectorSize < 64) || (avx3threshold != 0)) { // Partial copy to make dst address 32 byte aligned. __ movq(temp2, to); __ andq(temp2, 31); @@ -1603,7 +1608,8 @@ class StubGenerator: public StubCodeGenerator { StubCodeMark mark(this, "StubRoutines", name); address start = __ pc(); - bool use64byteVector = MaxVectorSize > 32 && AVX3Threshold == 0; + int avx3threshold = VM_Version::avx3_threshold(); + bool use64byteVector = (MaxVectorSize > 32) && (avx3threshold == 0); Label L_main_pre_loop, L_main_pre_loop_64bytes, L_pre_main_post_64; Label L_main_loop, L_main_loop_64bytes, L_tail, L_tail64, L_exit, L_entry; @@ -1668,12 +1674,12 @@ class StubGenerator: public StubCodeGenerator { // PRE-MAIN-POST loop for aligned copy. __ BIND(L_entry); - if (MaxVectorSize > 32 && AVX3Threshold != 0) { + if ((MaxVectorSize > 32) && (avx3threshold != 0)) { __ cmpq(temp1, threshold[shift]); __ jcc(Assembler::greaterEqual, L_pre_main_post_64); } - if (MaxVectorSize < 64 || AVX3Threshold != 0) { + if ((MaxVectorSize < 64) || (avx3threshold != 0)) { // Partial copy to make dst address 32 byte aligned. __ leaq(temp2, Address(to, temp1, (Address::ScaleFactor)(shift), 0)); __ andq(temp2, 31); @@ -2842,7 +2848,7 @@ class StubGenerator: public StubCodeGenerator { __ align(OptoLoopAlignment); __ BIND(L_store_element); - __ store_heap_oop(to_element_addr, rax_oop, noreg, noreg, AS_RAW); // store the oop + __ store_heap_oop(to_element_addr, rax_oop, noreg, noreg, noreg, AS_RAW); // store the oop __ increment(count); // increment the count toward zero __ jcc(Assembler::zero, L_do_card_marks); @@ -4137,6 +4143,7 @@ class StubGenerator: public StubCodeGenerator { const Register len = c_rarg3; // src len (must be multiple of blocksize 16) __ enter(); // required for proper stackwalking of RuntimeStub frame __ aesecb_encrypt(from, to, key, len); + __ vzeroupper(); __ leave(); // required for proper stackwalking of RuntimeStub frame __ ret(0); return start; @@ -4152,6 +4159,7 @@ class StubGenerator: public StubCodeGenerator { const Register len = c_rarg3; // src len (must be multiple of blocksize 16) __ enter(); // required for proper stackwalking of RuntimeStub frame __ aesecb_decrypt(from, to, key, len); + __ vzeroupper(); __ leave(); // required for proper stackwalking of RuntimeStub frame __ ret(0); return start; @@ -4413,9 +4421,8 @@ class StubGenerator: public StubCodeGenerator { const Register state = c_rarg5; const Address subkeyH_mem(rbp, 2 * wordSize); const Register subkeyHtbl = r11; - const Address avx512_subkeyH_mem(rbp, 3 * wordSize); const Register avx512_subkeyHtbl = r13; - const Address counter_mem(rbp, 4 * wordSize); + const Address counter_mem(rbp, 3 * wordSize); const Register counter = r12; #else const Address key_mem(rbp, 6 * wordSize); @@ -4424,9 +4431,8 @@ class StubGenerator: public StubCodeGenerator { const Register state = r13; const Address subkeyH_mem(rbp, 8 * wordSize); const Register subkeyHtbl = r14; - const Address avx512_subkeyH_mem(rbp, 9 * wordSize); const Register avx512_subkeyHtbl = r12; - const Address counter_mem(rbp, 10 * wordSize); + const Address counter_mem(rbp, 9 * wordSize); const Register counter = rsi; #endif __ enter(); @@ -4443,10 +4449,20 @@ class StubGenerator: public StubCodeGenerator { __ movptr(state, state_mem); #endif __ movptr(subkeyHtbl, subkeyH_mem); - __ movptr(avx512_subkeyHtbl, avx512_subkeyH_mem); __ movptr(counter, counter_mem); +// Save rbp and rsp + __ push(rbp); + __ movq(rbp, rsp); +// Align stack + __ andq(rsp, -64); + __ subptr(rsp, 96 * longSize); // Create space on the stack for htbl entries + __ movptr(avx512_subkeyHtbl, rsp); __ aesgcm_encrypt(in, len, ct, out, key, state, subkeyHtbl, avx512_subkeyHtbl, counter); + __ vzeroupper(); + + __ movq(rsp, rbp); + __ pop(rbp); // Restore state before leaving routine #ifdef _WIN64 @@ -4563,6 +4579,7 @@ class StubGenerator: public StubCodeGenerator { #endif __ push(rbx); __ aesctr_encrypt(from, to, key, counter, len_reg, used, used_addr, saved_encCounter_start); + __ vzeroupper(); // Restore state before leaving routine __ pop(rbx); #ifdef _WIN64 @@ -5183,6 +5200,7 @@ address generate_cipherBlockChaining_decryptVectorAESCrypt() { __ evpxorq(RK14, RK14, RK14, Assembler::AVX_512bit); __ BIND(Lcbc_exit); + __ vzeroupper(); __ pop(rbx); #ifdef _WIN64 __ movl(rax, len_mem); @@ -6260,6 +6278,9 @@ address generate_avx_ghash_processBlocks() { __ cmpl(length, 63); __ jcc(Assembler::lessEqual, L_finalBit); + __ mov64(rax, 0x0000ffffffffffff); + __ kmovql(k2, rax); + __ align32(); __ BIND(L_process64Loop); @@ -6281,7 +6302,7 @@ address generate_avx_ghash_processBlocks() { __ vpmaddwd(merged0, merge_ab_bc0, pack32_op, Assembler::AVX_512bit); __ vpermb(merged0, pack24bits, merged0, Assembler::AVX_512bit); - __ evmovdquq(Address(dest, dp), merged0, Assembler::AVX_512bit); + __ evmovdqub(Address(dest, dp), k2, merged0, true, Assembler::AVX_512bit); __ subl(length, 64); __ addptr(source, 64); @@ -6528,7 +6549,13 @@ address generate_avx_ghash_processBlocks() { if (VM_Version::supports_sse4_1() && VM_Version::supports_avx512_vpclmulqdq() && VM_Version::supports_avx512bw() && VM_Version::supports_avx512vl()) { + // The constants used in the CRC32 algorithm requires the 1's compliment of the initial crc value. + // However, the constant table for CRC32-C assumes the original crc value. Account for this + // difference before calling and after returning. + __ lea(table, ExternalAddress(StubRoutines::x86::crc_table_avx512_addr())); + __ notl(crc); __ kernel_crc32_avx512(crc, buf, len, table, tmp1, tmp2); + __ notl(crc); } else { __ kernel_crc32(crc, buf, len, table, tmp1); } @@ -6580,20 +6607,27 @@ address generate_avx_ghash_processBlocks() { BLOCK_COMMENT("Entry:"); __ enter(); // required for proper stackwalking of RuntimeStub frame + if (VM_Version::supports_sse4_1() && VM_Version::supports_avx512_vpclmulqdq() && + VM_Version::supports_avx512bw() && + VM_Version::supports_avx512vl()) { + __ lea(j, ExternalAddress(StubRoutines::x86::crc32c_table_avx512_addr())); + __ kernel_crc32_avx512(crc, buf, len, j, l, k); + } else { #ifdef _WIN64 - __ push(y); - __ push(z); + __ push(y); + __ push(z); #endif - __ crc32c_ipl_alg2_alt2(crc, buf, len, - a, j, k, - l, y, z, - c_farg0, c_farg1, c_farg2, - is_pclmulqdq_supported); - __ movl(rax, crc); + __ crc32c_ipl_alg2_alt2(crc, buf, len, + a, j, k, + l, y, z, + c_farg0, c_farg1, c_farg2, + is_pclmulqdq_supported); #ifdef _WIN64 - __ pop(z); - __ pop(y); + __ pop(z); + __ pop(y); #endif + } + __ movl(rax, crc); __ vzeroupper(); __ leave(); // required for proper stackwalking of RuntimeStub frame __ ret(0); @@ -7042,6 +7076,7 @@ address generate_avx_ghash_processBlocks() { __ shrdl(tmp4, tmp3); __ movl(Address(newArr, nIdx, Address::times_4), tmp4); __ BIND(Exit); + __ vzeroupper(); // Restore callee save registers. __ pop(tmp5); #ifdef _WINDOWS @@ -7163,6 +7198,7 @@ address generate_avx_ghash_processBlocks() { __ movl(Address(newArr, idx, Address::times_4), tmp3); __ BIND(Exit); + __ vzeroupper(); // Restore callee save registers. __ pop(tmp5); #ifdef _WINDOWS @@ -7692,6 +7728,11 @@ address generate_avx_ghash_processBlocks() { StubRoutines::x86::_vector_long_sign_mask = generate_vector_mask("vector_long_sign_mask", 0x8000000000000000); StubRoutines::x86::_vector_iota_indices = generate_iota_indices("iota_indices"); + if (UsePopCountInstruction && VM_Version::supports_avx2() && !VM_Version::supports_avx512_vpopcntdq()) { + // lut implementation influenced by counting 1s algorithm from section 5-1 of Hackers' Delight. + StubRoutines::x86::_vector_popcount_lut = generate_popcount_avx_lut("popcount_lut"); + } + // support for verify_oop (must happen after universe_init) if (VerifyOops) { StubRoutines::_verify_oop_subroutine_entry = generate_verify_oop(); diff --git a/src/hotspot/cpu/x86/stubRoutines_x86.cpp b/src/hotspot/cpu/x86/stubRoutines_x86.cpp index ec5a5d0f1433b7fd3a395b40414e31cd15051d6f..f5a0eb623d0d269c89bd905fee044ff47435a5e1 100644 --- a/src/hotspot/cpu/x86/stubRoutines_x86.cpp +++ b/src/hotspot/cpu/x86/stubRoutines_x86.cpp @@ -59,6 +59,7 @@ address StubRoutines::x86::_vector_double_sign_flip = NULL; address StubRoutines::x86::_vector_byte_perm_mask = NULL; address StubRoutines::x86::_vector_long_sign_mask = NULL; address StubRoutines::x86::_vector_iota_indices = NULL; +address StubRoutines::x86::_vector_popcount_lut = NULL; address StubRoutines::x86::_vector_32_bit_mask = NULL; address StubRoutines::x86::_vector_64_bit_mask = NULL; #ifdef _LP64 @@ -221,6 +222,23 @@ juint StubRoutines::x86::_crc_table_avx512[] = 0x00000000UL, 0x00000000UL, 0x00000000UL, 0x00000000UL }; +juint StubRoutines::x86::_crc32c_table_avx512[] = +{ + 0xb9e02b86UL, 0x00000000UL, 0xdcb17aa4UL, 0x00000000UL, + 0x493c7d27UL, 0x00000000UL, 0xc1068c50UL, 0x0000000eUL, + 0x06e38d70UL, 0x00000002UL, 0x6992cea2UL, 0x00000000UL, + 0x493c7d27UL, 0x00000000UL, 0xdd45aab8UL, 0x00000000UL, + 0xdea713f0UL, 0x00000000UL, 0x05ec76f0UL, 0x00000001UL, + 0x47db8317UL, 0x00000000UL, 0x2ad91c30UL, 0x00000000UL, + 0x0715ce53UL, 0x00000000UL, 0xc49f4f67UL, 0x00000000UL, + 0x39d3b296UL, 0x00000000UL, 0x083a6eecUL, 0x00000000UL, + 0x9e4addf8UL, 0x00000000UL, 0x740eef02UL, 0x00000000UL, + 0xddc0152bUL, 0x00000000UL, 0x1c291d04UL, 0x00000000UL, + 0xba4fc28eUL, 0x00000000UL, 0x3da6d0cbUL, 0x00000000UL, + 0x493c7d27UL, 0x00000000UL, 0xc1068c50UL, 0x0000000eUL, + 0x00000000UL, 0x00000000UL, 0x00000000UL, 0x00000000UL +}; + juint StubRoutines::x86::_crc_by128_masks_avx512[] = { 0xffffffffUL, 0xffffffffUL, 0x00000000UL, 0x00000000UL, diff --git a/src/hotspot/cpu/x86/stubRoutines_x86.hpp b/src/hotspot/cpu/x86/stubRoutines_x86.hpp index 1ef8377dfc2376b7f52901831673d44b2b8a39ee..5119dde4fd5427a866036ba95425c4116805ce15 100644 --- a/src/hotspot/cpu/x86/stubRoutines_x86.hpp +++ b/src/hotspot/cpu/x86/stubRoutines_x86.hpp @@ -137,6 +137,7 @@ class x86 { #ifdef _LP64 static juint _crc_by128_masks_avx512[]; static juint _crc_table_avx512[]; + static juint _crc32c_table_avx512[]; static juint _shuf_table_crc32_avx512[]; static juint _adler32_shuf0_table[]; static juint _adler32_shuf1_table[]; @@ -176,6 +177,7 @@ class x86 { static address _vector_short_shuffle_mask; static address _vector_long_shuffle_mask; static address _vector_iota_indices; + static address _vector_popcount_lut; #ifdef _LP64 static juint _k256_W[]; static address _k256_W_adr; @@ -256,6 +258,7 @@ class x86 { static address crc_by128_masks_avx512_addr() { return (address)_crc_by128_masks_avx512; } static address shuf_table_crc32_avx512_addr() { return (address)_shuf_table_crc32_avx512; } static address crc_table_avx512_addr() { return (address)_crc_table_avx512; } + static address crc32c_table_avx512_addr() { return (address)_crc32c_table_avx512; } static address ghash_polynomial512_addr() { return _ghash_poly512_addr; } #endif // _LP64 static address ghash_long_swap_mask_addr() { return _ghash_long_swap_mask_addr; } @@ -338,6 +341,9 @@ class x86 { return _vector_iota_indices; } + static address vector_popcount_lut() { + return _vector_popcount_lut; + } #ifdef _LP64 static address k256_W_addr() { return _k256_W_adr; } static address k512_W_addr() { return _k512_W_addr; } diff --git a/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp b/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp index a4e86ff42023efaa70c6e1554c11b359f0167032..7b14aff6f1f6e2f7c71b8cd18e9576262a47e20c 100644 --- a/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp +++ b/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -388,7 +388,6 @@ address TemplateInterpreterGenerator::generate_safept_entry_for( void TemplateInterpreterGenerator::generate_counter_incr(Label* overflow) { Label done; // Note: In tiered we increment either counters in Method* or in MDO depending if we're profiling or not. - int increment = InvocationCounter::count_increment; Label no_mdo; if (ProfileInterpreter) { // Are we profiling? @@ -399,7 +398,7 @@ void TemplateInterpreterGenerator::generate_counter_incr(Label* overflow) { const Address mdo_invocation_counter(rax, in_bytes(MethodData::invocation_counter_offset()) + in_bytes(InvocationCounter::counter_offset())); const Address mask(rax, in_bytes(MethodData::invoke_mask_offset())); - __ increment_mask_and_jump(mdo_invocation_counter, increment, mask, rcx, false, Assembler::zero, overflow); + __ increment_mask_and_jump(mdo_invocation_counter, mask, rcx, overflow); __ jmp(done); } __ bind(no_mdo); @@ -409,8 +408,7 @@ void TemplateInterpreterGenerator::generate_counter_incr(Label* overflow) { InvocationCounter::counter_offset()); __ get_method_counters(rbx, rax, done); const Address mask(rax, in_bytes(MethodCounters::invoke_mask_offset())); - __ increment_mask_and_jump(invocation_counter, increment, mask, rcx, - false, Assembler::zero, overflow); + __ increment_mask_and_jump(invocation_counter, mask, rcx, overflow); __ bind(done); } @@ -713,23 +711,59 @@ address TemplateInterpreterGenerator::generate_Reference_get_entry(void) { } void TemplateInterpreterGenerator::bang_stack_shadow_pages(bool native_call) { - // Quick & dirty stack overflow checking: bang the stack & handle trap. + // See more discussion in stackOverflow.hpp. + // Note that we do the banging after the frame is setup, since the exception // handling code expects to find a valid interpreter frame on the stack. // Doing the banging earlier fails if the caller frame is not an interpreter // frame. // (Also, the exception throwing code expects to unlock any synchronized - // method receiever, so do the banging after locking the receiver.) + // method receiver, so do the banging after locking the receiver.) - // Bang each page in the shadow zone. We can't assume it's been done for - // an interpreter frame with greater than a page of locals, so each page - // needs to be checked. Only true for non-native. + const int shadow_zone_size = checked_cast(StackOverflow::stack_shadow_zone_size()); const int page_size = os::vm_page_size(); - const int n_shadow_pages = ((int)StackOverflow::stack_shadow_zone_size()) / page_size; - const int start_page = native_call ? n_shadow_pages : 1; - for (int pages = start_page; pages <= n_shadow_pages; pages++) { - __ bang_stack_with_offset(pages*page_size); + const int n_shadow_pages = shadow_zone_size / page_size; + + const Register thread = NOT_LP64(rsi) LP64_ONLY(r15_thread); +#ifndef _LP64 + __ push(thread); + __ get_thread(thread); +#endif + +#ifdef ASSERT + Label L_good_limit; + __ cmpptr(Address(thread, JavaThread::shadow_zone_safe_limit()), (int32_t)NULL_WORD); + __ jcc(Assembler::notEqual, L_good_limit); + __ stop("shadow zone safe limit is not initialized"); + __ bind(L_good_limit); + + Label L_good_watermark; + __ cmpptr(Address(thread, JavaThread::shadow_zone_growth_watermark()), (int32_t)NULL_WORD); + __ jcc(Assembler::notEqual, L_good_watermark); + __ stop("shadow zone growth watermark is not initialized"); + __ bind(L_good_watermark); +#endif + + Label L_done; + + __ cmpptr(rsp, Address(thread, JavaThread::shadow_zone_growth_watermark())); + __ jcc(Assembler::above, L_done); + + for (int p = 1; p <= n_shadow_pages; p++) { + __ bang_stack_with_offset(p*page_size); } + + // Record the new watermark, but only if update is above the safe limit. + // Otherwise, the next time around the check above would pass the safe limit. + __ cmpptr(rsp, Address(thread, JavaThread::shadow_zone_safe_limit())); + __ jccb(Assembler::belowEqual, L_done); + __ movptr(Address(thread, JavaThread::shadow_zone_growth_watermark()), rsp); + + __ bind(L_done); + +#ifndef _LP64 + __ pop(thread); +#endif } // Interpreter stub for calling a native method. (asm interpreter) @@ -1702,21 +1736,21 @@ void TemplateInterpreterGenerator::set_vtos_entry_points(Template* t, #ifndef _LP64 fep = __ pc(); // ftos entry point __ push(ftos); - __ jmp(L); + __ jmpb(L); dep = __ pc(); // dtos entry point __ push(dtos); - __ jmp(L); + __ jmpb(L); #else fep = __ pc(); // ftos entry point __ push_f(xmm0); - __ jmp(L); + __ jmpb(L); dep = __ pc(); // dtos entry point __ push_d(xmm0); - __ jmp(L); + __ jmpb(L); #endif // _LP64 lep = __ pc(); // ltos entry point __ push_l(); - __ jmp(L); + __ jmpb(L); aep = bep = cep = sep = iep = __ pc(); // [abcsi]tos entry point __ push_i_or_ptr(); vep = __ pc(); // vtos entry point diff --git a/src/hotspot/cpu/x86/templateInterpreterGenerator_x86_64.cpp b/src/hotspot/cpu/x86/templateInterpreterGenerator_x86_64.cpp index 75dc0535d2a5506fe9cbd1bd73776706d0bc3352..1a1dad0cea317543dda0b0604f8e614097c2233f 100644 --- a/src/hotspot/cpu/x86/templateInterpreterGenerator_x86_64.cpp +++ b/src/hotspot/cpu/x86/templateInterpreterGenerator_x86_64.cpp @@ -69,7 +69,7 @@ address TemplateInterpreterGenerator::generate_slow_signature_handler() { Label isfloatordouble, isdouble, next; __ testl(c_rarg3, 1 << (i*2)); // Float or Double? - __ jcc(Assembler::notZero, isfloatordouble); + __ jccb(Assembler::notZero, isfloatordouble); // Do Int register here switch ( i ) { @@ -88,15 +88,15 @@ address TemplateInterpreterGenerator::generate_slow_signature_handler() { break; } - __ jmp (next); + __ jmpb(next); __ bind(isfloatordouble); __ testl(c_rarg3, 1 << ((i*2)+1)); // Double? - __ jcc(Assembler::notZero, isdouble); + __ jccb(Assembler::notZero, isdouble); // Do Float Here __ movflt(floatreg, Address(rsp, i * wordSize)); - __ jmp(next); + __ jmpb(next); // Do Double here __ bind(isdouble); @@ -150,9 +150,9 @@ address TemplateInterpreterGenerator::generate_slow_signature_handler() { Label d, done; __ testl(c_rarg3, 1 << i); - __ jcc(Assembler::notZero, d); + __ jccb(Assembler::notZero, d); __ movflt(r, Address(rsp, (6 + i) * wordSize)); - __ jmp(done); + __ jmpb(done); __ bind(d); __ movdbl(r, Address(rsp, (6 + i) * wordSize)); __ bind(done); @@ -445,3 +445,18 @@ address TemplateInterpreterGenerator::generate_math_entry(AbstractInterpreter::M return entry_point; } +address TemplateInterpreterGenerator::generate_currentThread() { + + address entry_point = __ pc(); + + __ movptr(rax, Address(r15_thread, JavaThread::threadObj_offset())); + + __ resolve_oop_handle(rax, rscratch1); + + __ pop(rcx); + __ mov(rsp, r13); + __ jmp(rcx); + + return entry_point; +} + diff --git a/src/hotspot/cpu/x86/templateTable_x86.cpp b/src/hotspot/cpu/x86/templateTable_x86.cpp index 19530b7c57cccfc6287a415516b4b3c91bb06956..531ff7956b4bc86007977c5a8c4148f88dde12ef 100644 --- a/src/hotspot/cpu/x86/templateTable_x86.cpp +++ b/src/hotspot/cpu/x86/templateTable_x86.cpp @@ -152,7 +152,7 @@ static void do_oop_store(InterpreterMacroAssembler* _masm, Register val, DecoratorSet decorators = 0) { assert(val == noreg || val == rax, "parameter is just for looks"); - __ store_heap_oop(dst, val, rdx, rbx, decorators); + __ store_heap_oop(dst, val, rdx, rbx, LP64_ONLY(r8) NOT_LP64(rsi), decorators); } static void do_oop_load(InterpreterMacroAssembler* _masm, @@ -525,7 +525,7 @@ void TemplateTable::condy_helper(Label& Done) { // tos in (itos, ftos, stos, btos, ctos, ztos) Label notInt, notFloat, notShort, notByte, notChar, notBool; __ cmpl(flags, itos); - __ jcc(Assembler::notEqual, notInt); + __ jccb(Assembler::notEqual, notInt); // itos __ movl(rax, field); __ push(itos); @@ -533,7 +533,7 @@ void TemplateTable::condy_helper(Label& Done) { __ bind(notInt); __ cmpl(flags, ftos); - __ jcc(Assembler::notEqual, notFloat); + __ jccb(Assembler::notEqual, notFloat); // ftos __ load_float(field); __ push(ftos); @@ -541,7 +541,7 @@ void TemplateTable::condy_helper(Label& Done) { __ bind(notFloat); __ cmpl(flags, stos); - __ jcc(Assembler::notEqual, notShort); + __ jccb(Assembler::notEqual, notShort); // stos __ load_signed_short(rax, field); __ push(stos); @@ -549,7 +549,7 @@ void TemplateTable::condy_helper(Label& Done) { __ bind(notShort); __ cmpl(flags, btos); - __ jcc(Assembler::notEqual, notByte); + __ jccb(Assembler::notEqual, notByte); // btos __ load_signed_byte(rax, field); __ push(btos); @@ -557,7 +557,7 @@ void TemplateTable::condy_helper(Label& Done) { __ bind(notByte); __ cmpl(flags, ctos); - __ jcc(Assembler::notEqual, notChar); + __ jccb(Assembler::notEqual, notChar); // ctos __ load_unsigned_short(rax, field); __ push(ctos); @@ -565,7 +565,7 @@ void TemplateTable::condy_helper(Label& Done) { __ bind(notChar); __ cmpl(flags, ztos); - __ jcc(Assembler::notEqual, notBool); + __ jccb(Assembler::notEqual, notBool); // ztos __ load_signed_byte(rax, field); __ push(ztos); @@ -579,7 +579,7 @@ void TemplateTable::condy_helper(Label& Done) { { Label notLong, notDouble; __ cmpl(flags, ltos); - __ jcc(Assembler::notEqual, notLong); + __ jccb(Assembler::notEqual, notLong); // ltos // Loading high word first because movptr clobbers rax NOT_LP64(__ movptr(rdx, field.plus_disp(4))); @@ -589,7 +589,7 @@ void TemplateTable::condy_helper(Label& Done) { __ bind(notLong); __ cmpl(flags, dtos); - __ jcc(Assembler::notEqual, notDouble); + __ jccb(Assembler::notEqual, notDouble); // dtos __ load_double(field); __ push(dtos); @@ -1067,7 +1067,7 @@ void TemplateTable::iastore() { __ access_store_at(T_INT, IN_HEAP | IS_ARRAY, Address(rdx, rbx, Address::times_4, arrayOopDesc::base_offset_in_bytes(T_INT)), - rax, noreg, noreg); + rax, noreg, noreg, noreg); } void TemplateTable::lastore() { @@ -1081,7 +1081,7 @@ void TemplateTable::lastore() { __ access_store_at(T_LONG, IN_HEAP | IS_ARRAY, Address(rcx, rbx, Address::times_8, arrayOopDesc::base_offset_in_bytes(T_LONG)), - noreg /* ltos */, noreg, noreg); + noreg /* ltos */, noreg, noreg, noreg); } @@ -1095,7 +1095,7 @@ void TemplateTable::fastore() { __ access_store_at(T_FLOAT, IN_HEAP | IS_ARRAY, Address(rdx, rbx, Address::times_4, arrayOopDesc::base_offset_in_bytes(T_FLOAT)), - noreg /* ftos */, noreg, noreg); + noreg /* ftos */, noreg, noreg, noreg); } void TemplateTable::dastore() { @@ -1108,7 +1108,7 @@ void TemplateTable::dastore() { __ access_store_at(T_DOUBLE, IN_HEAP | IS_ARRAY, Address(rdx, rbx, Address::times_8, arrayOopDesc::base_offset_in_bytes(T_DOUBLE)), - noreg /* dtos */, noreg, noreg); + noreg /* dtos */, noreg, noreg, noreg); } void TemplateTable::aastore() { @@ -1186,7 +1186,7 @@ void TemplateTable::bastore() { __ access_store_at(T_BYTE, IN_HEAP | IS_ARRAY, Address(rdx, rbx,Address::times_1, arrayOopDesc::base_offset_in_bytes(T_BYTE)), - rax, noreg, noreg); + rax, noreg, noreg, noreg); } void TemplateTable::castore() { @@ -1199,7 +1199,7 @@ void TemplateTable::castore() { __ access_store_at(T_CHAR, IN_HEAP | IS_ARRAY, Address(rdx, rbx, Address::times_2, arrayOopDesc::base_offset_in_bytes(T_CHAR)), - rax, noreg, noreg); + rax, noreg, noreg, noreg); } @@ -2197,7 +2197,6 @@ void TemplateTable::branch(bool is_jsr, bool is_wide) { __ bind(has_counters); Label no_mdo; - int increment = InvocationCounter::count_increment; if (ProfileInterpreter) { // Are we profiling? __ movptr(rbx, Address(rcx, in_bytes(Method::method_data_offset()))); @@ -2207,7 +2206,7 @@ void TemplateTable::branch(bool is_jsr, bool is_wide) { const Address mdo_backedge_counter(rbx, in_bytes(MethodData::backedge_counter_offset()) + in_bytes(InvocationCounter::counter_offset())); const Address mask(rbx, in_bytes(MethodData::backedge_mask_offset())); - __ increment_mask_and_jump(mdo_backedge_counter, increment, mask, rax, false, Assembler::zero, + __ increment_mask_and_jump(mdo_backedge_counter, mask, rax, UseOnStackReplacement ? &backedge_counter_overflow : NULL); __ jmp(dispatch); } @@ -2215,8 +2214,8 @@ void TemplateTable::branch(bool is_jsr, bool is_wide) { // Increment backedge counter in MethodCounters* __ movptr(rcx, Address(rcx, Method::method_counters_offset())); const Address mask(rcx, in_bytes(MethodCounters::backedge_mask_offset())); - __ increment_mask_and_jump(Address(rcx, be_offset), increment, mask, - rax, false, Assembler::zero, UseOnStackReplacement ? &backedge_counter_overflow : NULL); + __ increment_mask_and_jump(Address(rcx, be_offset), mask, rax, + UseOnStackReplacement ? &backedge_counter_overflow : NULL); __ bind(dispatch); } @@ -3102,7 +3101,7 @@ void TemplateTable::putfield_or_static_helper(int byte_no, bool is_static, Rewri { __ pop(btos); if (!is_static) pop_and_check_object(obj); - __ access_store_at(T_BYTE, IN_HEAP, field, rax, noreg, noreg); + __ access_store_at(T_BYTE, IN_HEAP, field, rax, noreg, noreg, noreg); if (!is_static && rc == may_rewrite) { patch_bytecode(Bytecodes::_fast_bputfield, bc, rbx, true, byte_no); } @@ -3117,7 +3116,7 @@ void TemplateTable::putfield_or_static_helper(int byte_no, bool is_static, Rewri { __ pop(ztos); if (!is_static) pop_and_check_object(obj); - __ access_store_at(T_BOOLEAN, IN_HEAP, field, rax, noreg, noreg); + __ access_store_at(T_BOOLEAN, IN_HEAP, field, rax, noreg, noreg, noreg); if (!is_static && rc == may_rewrite) { patch_bytecode(Bytecodes::_fast_zputfield, bc, rbx, true, byte_no); } @@ -3148,7 +3147,7 @@ void TemplateTable::putfield_or_static_helper(int byte_no, bool is_static, Rewri { __ pop(itos); if (!is_static) pop_and_check_object(obj); - __ access_store_at(T_INT, IN_HEAP, field, rax, noreg, noreg); + __ access_store_at(T_INT, IN_HEAP, field, rax, noreg, noreg, noreg); if (!is_static && rc == may_rewrite) { patch_bytecode(Bytecodes::_fast_iputfield, bc, rbx, true, byte_no); } @@ -3163,7 +3162,7 @@ void TemplateTable::putfield_or_static_helper(int byte_no, bool is_static, Rewri { __ pop(ctos); if (!is_static) pop_and_check_object(obj); - __ access_store_at(T_CHAR, IN_HEAP, field, rax, noreg, noreg); + __ access_store_at(T_CHAR, IN_HEAP, field, rax, noreg, noreg, noreg); if (!is_static && rc == may_rewrite) { patch_bytecode(Bytecodes::_fast_cputfield, bc, rbx, true, byte_no); } @@ -3178,7 +3177,7 @@ void TemplateTable::putfield_or_static_helper(int byte_no, bool is_static, Rewri { __ pop(stos); if (!is_static) pop_and_check_object(obj); - __ access_store_at(T_SHORT, IN_HEAP, field, rax, noreg, noreg); + __ access_store_at(T_SHORT, IN_HEAP, field, rax, noreg, noreg, noreg); if (!is_static && rc == may_rewrite) { patch_bytecode(Bytecodes::_fast_sputfield, bc, rbx, true, byte_no); } @@ -3194,7 +3193,7 @@ void TemplateTable::putfield_or_static_helper(int byte_no, bool is_static, Rewri __ pop(ltos); if (!is_static) pop_and_check_object(obj); // MO_RELAXED: generate atomic store for the case of volatile field (important for x86_32) - __ access_store_at(T_LONG, IN_HEAP | MO_RELAXED, field, noreg /* ltos*/, noreg, noreg); + __ access_store_at(T_LONG, IN_HEAP | MO_RELAXED, field, noreg /* ltos*/, noreg, noreg, noreg); #ifdef _LP64 if (!is_static && rc == may_rewrite) { patch_bytecode(Bytecodes::_fast_lputfield, bc, rbx, true, byte_no); @@ -3211,7 +3210,7 @@ void TemplateTable::putfield_or_static_helper(int byte_no, bool is_static, Rewri { __ pop(ftos); if (!is_static) pop_and_check_object(obj); - __ access_store_at(T_FLOAT, IN_HEAP, field, noreg /* ftos */, noreg, noreg); + __ access_store_at(T_FLOAT, IN_HEAP, field, noreg /* ftos */, noreg, noreg, noreg); if (!is_static && rc == may_rewrite) { patch_bytecode(Bytecodes::_fast_fputfield, bc, rbx, true, byte_no); } @@ -3230,7 +3229,7 @@ void TemplateTable::putfield_or_static_helper(int byte_no, bool is_static, Rewri __ pop(dtos); if (!is_static) pop_and_check_object(obj); // MO_RELAXED: for the case of volatile field, in fact it adds no extra work for the underlying implementation - __ access_store_at(T_DOUBLE, IN_HEAP | MO_RELAXED, field, noreg /* dtos */, noreg, noreg); + __ access_store_at(T_DOUBLE, IN_HEAP | MO_RELAXED, field, noreg /* dtos */, noreg, noreg, noreg); if (!is_static && rc == may_rewrite) { patch_bytecode(Bytecodes::_fast_dputfield, bc, rbx, true, byte_no); } @@ -3373,31 +3372,31 @@ void TemplateTable::fast_storefield_helper(Address field, Register rax) { break; case Bytecodes::_fast_lputfield: #ifdef _LP64 - __ access_store_at(T_LONG, IN_HEAP, field, noreg /* ltos */, noreg, noreg); + __ access_store_at(T_LONG, IN_HEAP, field, noreg /* ltos */, noreg, noreg, noreg); #else __ stop("should not be rewritten"); #endif break; case Bytecodes::_fast_iputfield: - __ access_store_at(T_INT, IN_HEAP, field, rax, noreg, noreg); + __ access_store_at(T_INT, IN_HEAP, field, rax, noreg, noreg, noreg); break; case Bytecodes::_fast_zputfield: - __ access_store_at(T_BOOLEAN, IN_HEAP, field, rax, noreg, noreg); + __ access_store_at(T_BOOLEAN, IN_HEAP, field, rax, noreg, noreg, noreg); break; case Bytecodes::_fast_bputfield: - __ access_store_at(T_BYTE, IN_HEAP, field, rax, noreg, noreg); + __ access_store_at(T_BYTE, IN_HEAP, field, rax, noreg, noreg, noreg); break; case Bytecodes::_fast_sputfield: - __ access_store_at(T_SHORT, IN_HEAP, field, rax, noreg, noreg); + __ access_store_at(T_SHORT, IN_HEAP, field, rax, noreg, noreg, noreg); break; case Bytecodes::_fast_cputfield: - __ access_store_at(T_CHAR, IN_HEAP, field, rax, noreg, noreg); + __ access_store_at(T_CHAR, IN_HEAP, field, rax, noreg, noreg, noreg); break; case Bytecodes::_fast_fputfield: - __ access_store_at(T_FLOAT, IN_HEAP, field, noreg /* ftos*/, noreg, noreg); + __ access_store_at(T_FLOAT, IN_HEAP, field, noreg /* ftos*/, noreg, noreg, noreg); break; case Bytecodes::_fast_dputfield: - __ access_store_at(T_DOUBLE, IN_HEAP, field, noreg /* dtos*/, noreg, noreg); + __ access_store_at(T_DOUBLE, IN_HEAP, field, noreg /* dtos*/, noreg, noreg, noreg); break; default: ShouldNotReachHere(); diff --git a/src/hotspot/cpu/x86/universalUpcallHandler_x86_64.cpp b/src/hotspot/cpu/x86/universalUpcallHandler_x86_64.cpp index c54b907f9b5c5f0bb3713532c66b4f27039bca9f..da675bf0aa6484761b8abce99ee5879045f9c616 100644 --- a/src/hotspot/cpu/x86/universalUpcallHandler_x86_64.cpp +++ b/src/hotspot/cpu/x86/universalUpcallHandler_x86_64.cpp @@ -616,12 +616,9 @@ address ProgrammableUpcallHandler::generate_optimized_upcall_stub(jobject receiv int reg_save_area_size = compute_reg_save_area_size(abi); int arg_save_area_size = compute_arg_save_area_size(conv); int res_save_area_size = compute_res_save_area_size(conv); - // To spill receiver during deopt - int deopt_spill_size = 1 * BytesPerWord; int shuffle_area_offset = 0; - int deopt_spill_offset = shuffle_area_offset + out_arg_area; - int res_save_area_offset = deopt_spill_offset + deopt_spill_size; + int res_save_area_offset = shuffle_area_offset + out_arg_area; int arg_save_area_offset = res_save_area_offset + res_save_area_size; int reg_save_area_offset = arg_save_area_offset + arg_save_area_size; int frame_data_offset = reg_save_area_offset + reg_save_area_size; @@ -648,9 +645,6 @@ address ProgrammableUpcallHandler::generate_optimized_upcall_stub(jobject receiv // | res_save_area | // |---------------------| = res_save_are_offset // | | - // | deopt_spill | - // |---------------------| = deopt_spill_offset - // | | // SP-> | out_arg_area | needs to be at end for shadow space // // diff --git a/src/hotspot/cpu/x86/vm_version_ext_x86.cpp b/src/hotspot/cpu/x86/vm_version_ext_x86.cpp deleted file mode 100644 index 84e8c9fa819a87c9ca8ad779c671961b9a2e9b9c..0000000000000000000000000000000000000000 --- a/src/hotspot/cpu/x86/vm_version_ext_x86.cpp +++ /dev/null @@ -1,982 +0,0 @@ -/* - * Copyright (c) 2013, 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 "jvm.h" -#include "utilities/macros.hpp" -#include "asm/macroAssembler.hpp" -#include "asm/macroAssembler.inline.hpp" -#include "code/codeBlob.hpp" -#include "memory/allocation.inline.hpp" -#include "memory/resourceArea.hpp" -#include "runtime/java.hpp" -#include "runtime/stubCodeGenerator.hpp" -#include "vm_version_ext_x86.hpp" - -typedef enum { - CPU_FAMILY_8086_8088 = 0, - CPU_FAMILY_INTEL_286 = 2, - CPU_FAMILY_INTEL_386 = 3, - CPU_FAMILY_INTEL_486 = 4, - CPU_FAMILY_PENTIUM = 5, - CPU_FAMILY_PENTIUMPRO = 6, // Same family several models - CPU_FAMILY_PENTIUM_4 = 0xF -} FamilyFlag; - -typedef enum { - RDTSCP_FLAG = 0x08000000, // bit 27 - INTEL64_FLAG = 0x20000000 // bit 29 -} _featureExtendedEdxFlag; - -#define CPUID_STANDARD_FN 0x0 -#define CPUID_STANDARD_FN_1 0x1 -#define CPUID_STANDARD_FN_4 0x4 -#define CPUID_STANDARD_FN_B 0xb - -#define CPUID_EXTENDED_FN 0x80000000 -#define CPUID_EXTENDED_FN_1 0x80000001 -#define CPUID_EXTENDED_FN_2 0x80000002 -#define CPUID_EXTENDED_FN_3 0x80000003 -#define CPUID_EXTENDED_FN_4 0x80000004 -#define CPUID_EXTENDED_FN_7 0x80000007 -#define CPUID_EXTENDED_FN_8 0x80000008 - -typedef enum { - FPU_FLAG = 0x00000001, - VME_FLAG = 0x00000002, - DE_FLAG = 0x00000004, - PSE_FLAG = 0x00000008, - TSC_FLAG = 0x00000010, - MSR_FLAG = 0x00000020, - PAE_FLAG = 0x00000040, - MCE_FLAG = 0x00000080, - CX8_FLAG = 0x00000100, - APIC_FLAG = 0x00000200, - SEP_FLAG = 0x00000800, - MTRR_FLAG = 0x00001000, - PGE_FLAG = 0x00002000, - MCA_FLAG = 0x00004000, - CMOV_FLAG = 0x00008000, - PAT_FLAG = 0x00010000, - PSE36_FLAG = 0x00020000, - PSNUM_FLAG = 0x00040000, - CLFLUSH_FLAG = 0x00080000, - DTS_FLAG = 0x00200000, - ACPI_FLAG = 0x00400000, - MMX_FLAG = 0x00800000, - FXSR_FLAG = 0x01000000, - SSE_FLAG = 0x02000000, - SSE2_FLAG = 0x04000000, - SS_FLAG = 0x08000000, - HTT_FLAG = 0x10000000, - TM_FLAG = 0x20000000 -} FeatureEdxFlag; - -static BufferBlob* cpuid_brand_string_stub_blob; -static const int cpuid_brand_string_stub_size = 550; - -extern "C" { - typedef void (*getCPUIDBrandString_stub_t)(void*); -} - -static getCPUIDBrandString_stub_t getCPUIDBrandString_stub = NULL; - -class VM_Version_Ext_StubGenerator: public StubCodeGenerator { - public: - - VM_Version_Ext_StubGenerator(CodeBuffer *c) : StubCodeGenerator(c) {} - - address generate_getCPUIDBrandString(void) { - // Flags to test CPU type. - const uint32_t HS_EFL_AC = 0x40000; - const uint32_t HS_EFL_ID = 0x200000; - // Values for when we don't have a CPUID instruction. - const int CPU_FAMILY_SHIFT = 8; - const uint32_t CPU_FAMILY_386 = (3 << CPU_FAMILY_SHIFT); - const uint32_t CPU_FAMILY_486 = (4 << CPU_FAMILY_SHIFT); - - Label detect_486, cpu486, detect_586, done, ext_cpuid; - - StubCodeMark mark(this, "VM_Version_Ext", "getCPUIDNameInfo_stub"); -# define __ _masm-> - - address start = __ pc(); - - // - // void getCPUIDBrandString(VM_Version::CpuidInfo* cpuid_info); - // - // LP64: rcx and rdx are first and second argument registers on windows - - __ push(rbp); -#ifdef _LP64 - __ mov(rbp, c_rarg0); // cpuid_info address -#else - __ movptr(rbp, Address(rsp, 8)); // cpuid_info address -#endif - __ push(rbx); - __ push(rsi); - __ pushf(); // preserve rbx, and flags - __ pop(rax); - __ push(rax); - __ mov(rcx, rax); - // - // if we are unable to change the AC flag, we have a 386 - // - __ xorl(rax, HS_EFL_AC); - __ push(rax); - __ popf(); - __ pushf(); - __ pop(rax); - __ cmpptr(rax, rcx); - __ jccb(Assembler::notEqual, detect_486); - - __ movl(rax, CPU_FAMILY_386); - __ jmp(done); - - // - // If we are unable to change the ID flag, we have a 486 which does - // not support the "cpuid" instruction. - // - __ bind(detect_486); - __ mov(rax, rcx); - __ xorl(rax, HS_EFL_ID); - __ push(rax); - __ popf(); - __ pushf(); - __ pop(rax); - __ cmpptr(rcx, rax); - __ jccb(Assembler::notEqual, detect_586); - - __ bind(cpu486); - __ movl(rax, CPU_FAMILY_486); - __ jmp(done); - - // - // At this point, we have a chip which supports the "cpuid" instruction - // - __ bind(detect_586); - __ xorl(rax, rax); - __ cpuid(); - __ orl(rax, rax); - __ jcc(Assembler::equal, cpu486); // if cpuid doesn't support an input - // value of at least 1, we give up and - // assume a 486 - - // - // Extended cpuid(0x80000000) for processor brand string detection - // - __ bind(ext_cpuid); - __ movl(rax, CPUID_EXTENDED_FN); - __ cpuid(); - __ cmpl(rax, CPUID_EXTENDED_FN_4); - __ jcc(Assembler::below, done); - - // - // Extended cpuid(0x80000002) // first 16 bytes in brand string - // - __ movl(rax, CPUID_EXTENDED_FN_2); - __ cpuid(); - __ lea(rsi, Address(rbp, in_bytes(VM_Version_Ext::proc_name_0_offset()))); - __ movl(Address(rsi, 0), rax); - __ lea(rsi, Address(rbp, in_bytes(VM_Version_Ext::proc_name_1_offset()))); - __ movl(Address(rsi, 0), rbx); - __ lea(rsi, Address(rbp, in_bytes(VM_Version_Ext::proc_name_2_offset()))); - __ movl(Address(rsi, 0), rcx); - __ lea(rsi, Address(rbp, in_bytes(VM_Version_Ext::proc_name_3_offset()))); - __ movl(Address(rsi,0), rdx); - - // - // Extended cpuid(0x80000003) // next 16 bytes in brand string - // - __ movl(rax, CPUID_EXTENDED_FN_3); - __ cpuid(); - __ lea(rsi, Address(rbp, in_bytes(VM_Version_Ext::proc_name_4_offset()))); - __ movl(Address(rsi, 0), rax); - __ lea(rsi, Address(rbp, in_bytes(VM_Version_Ext::proc_name_5_offset()))); - __ movl(Address(rsi, 0), rbx); - __ lea(rsi, Address(rbp, in_bytes(VM_Version_Ext::proc_name_6_offset()))); - __ movl(Address(rsi, 0), rcx); - __ lea(rsi, Address(rbp, in_bytes(VM_Version_Ext::proc_name_7_offset()))); - __ movl(Address(rsi,0), rdx); - - // - // Extended cpuid(0x80000004) // last 16 bytes in brand string - // - __ movl(rax, CPUID_EXTENDED_FN_4); - __ cpuid(); - __ lea(rsi, Address(rbp, in_bytes(VM_Version_Ext::proc_name_8_offset()))); - __ movl(Address(rsi, 0), rax); - __ lea(rsi, Address(rbp, in_bytes(VM_Version_Ext::proc_name_9_offset()))); - __ movl(Address(rsi, 0), rbx); - __ lea(rsi, Address(rbp, in_bytes(VM_Version_Ext::proc_name_10_offset()))); - __ movl(Address(rsi, 0), rcx); - __ lea(rsi, Address(rbp, in_bytes(VM_Version_Ext::proc_name_11_offset()))); - __ movl(Address(rsi,0), rdx); - - // - // return - // - __ bind(done); - __ popf(); - __ pop(rsi); - __ pop(rbx); - __ pop(rbp); - __ ret(0); - -# undef __ - - return start; - }; -}; - - -// VM_Version_Ext statics -const size_t VM_Version_Ext::VENDOR_LENGTH = 13; -const size_t VM_Version_Ext::CPU_EBS_MAX_LENGTH = (3 * 4 * 4 + 1); -const size_t VM_Version_Ext::CPU_TYPE_DESC_BUF_SIZE = 256; -const size_t VM_Version_Ext::CPU_DETAILED_DESC_BUF_SIZE = 4096; -char* VM_Version_Ext::_cpu_brand_string = NULL; -int64_t VM_Version_Ext::_max_qualified_cpu_frequency = 0; - -int VM_Version_Ext::_no_of_threads = 0; -int VM_Version_Ext::_no_of_cores = 0; -int VM_Version_Ext::_no_of_packages = 0; - -void VM_Version_Ext::initialize(void) { - ResourceMark rm; - - cpuid_brand_string_stub_blob = BufferBlob::create("getCPUIDBrandString_stub", cpuid_brand_string_stub_size); - if (cpuid_brand_string_stub_blob == NULL) { - vm_exit_during_initialization("Unable to allocate getCPUIDBrandString_stub"); - } - CodeBuffer c(cpuid_brand_string_stub_blob); - VM_Version_Ext_StubGenerator g(&c); - getCPUIDBrandString_stub = CAST_TO_FN_PTR(getCPUIDBrandString_stub_t, - g.generate_getCPUIDBrandString()); -} - -const char* VM_Version_Ext::cpu_model_description(void) { - uint32_t cpu_family = extended_cpu_family(); - uint32_t cpu_model = extended_cpu_model(); - const char* model = NULL; - - if (cpu_family == CPU_FAMILY_PENTIUMPRO) { - for (uint32_t i = 0; i <= cpu_model; i++) { - model = _model_id_pentium_pro[i]; - if (model == NULL) { - break; - } - } - } - return model; -} - -const char* VM_Version_Ext::cpu_brand_string(void) { - if (_cpu_brand_string == NULL) { - _cpu_brand_string = NEW_C_HEAP_ARRAY_RETURN_NULL(char, CPU_EBS_MAX_LENGTH, mtInternal); - if (NULL == _cpu_brand_string) { - return NULL; - } - int ret_val = cpu_extended_brand_string(_cpu_brand_string, CPU_EBS_MAX_LENGTH); - if (ret_val != OS_OK) { - FREE_C_HEAP_ARRAY(char, _cpu_brand_string); - _cpu_brand_string = NULL; - } - } - return _cpu_brand_string; -} - -const char* VM_Version_Ext::cpu_brand(void) { - const char* brand = NULL; - - if ((_cpuid_info.std_cpuid1_ebx.value & 0xFF) > 0) { - int brand_num = _cpuid_info.std_cpuid1_ebx.value & 0xFF; - brand = _brand_id[0]; - for (int i = 0; brand != NULL && i <= brand_num; i += 1) { - brand = _brand_id[i]; - } - } - return brand; -} - -bool VM_Version_Ext::cpu_is_em64t(void) { - return ((_cpuid_info.ext_cpuid1_edx.value & INTEL64_FLAG) == INTEL64_FLAG); -} - -bool VM_Version_Ext::is_netburst(void) { - return (is_intel() && (extended_cpu_family() == CPU_FAMILY_PENTIUM_4)); -} - -bool VM_Version_Ext::supports_tscinv_ext(void) { - if (!supports_tscinv_bit()) { - return false; - } - - if (is_intel()) { - return true; - } - - if (is_amd()) { - return !is_amd_Barcelona(); - } - - if (is_hygon()) { - return true; - } - - return false; -} - -void VM_Version_Ext::resolve_cpu_information_details(void) { - - // in future we want to base this information on proper cpu - // and cache topology enumeration such as: - // Intel 64 Architecture Processor Topology Enumeration - // which supports system cpu and cache topology enumeration - // either using 2xAPICIDs or initial APICIDs - - // currently only rough cpu information estimates - // which will not necessarily reflect the exact configuration of the system - - // this is the number of logical hardware threads - // visible to the operating system - _no_of_threads = os::processor_count(); - - // find out number of threads per cpu package - int threads_per_package = threads_per_core() * cores_per_cpu(); - - // use amount of threads visible to the process in order to guess number of sockets - _no_of_packages = _no_of_threads / threads_per_package; - - // process might only see a subset of the total number of threads - // from a single processor package. Virtualization/resource management for example. - // If so then just write a hard 1 as num of pkgs. - if (0 == _no_of_packages) { - _no_of_packages = 1; - } - - // estimate the number of cores - _no_of_cores = cores_per_cpu() * _no_of_packages; -} - -int VM_Version_Ext::number_of_threads(void) { - if (_no_of_threads == 0) { - resolve_cpu_information_details(); - } - return _no_of_threads; -} - -int VM_Version_Ext::number_of_cores(void) { - if (_no_of_cores == 0) { - resolve_cpu_information_details(); - } - return _no_of_cores; -} - -int VM_Version_Ext::number_of_sockets(void) { - if (_no_of_packages == 0) { - resolve_cpu_information_details(); - } - return _no_of_packages; -} - -const char* VM_Version_Ext::cpu_family_description(void) { - int cpu_family_id = extended_cpu_family(); - if (is_amd()) { - if (cpu_family_id < ExtendedFamilyIdLength_AMD) { - return _family_id_amd[cpu_family_id]; - } - } - if (is_intel()) { - if (cpu_family_id == CPU_FAMILY_PENTIUMPRO) { - return cpu_model_description(); - } - if (cpu_family_id < ExtendedFamilyIdLength_INTEL) { - return _family_id_intel[cpu_family_id]; - } - } - if (is_hygon()) { - return "Dhyana"; - } - return "Unknown x86"; -} - -int VM_Version_Ext::cpu_type_description(char* const buf, size_t buf_len) { - assert(buf != NULL, "buffer is NULL!"); - assert(buf_len >= CPU_TYPE_DESC_BUF_SIZE, "buffer len should at least be == CPU_TYPE_DESC_BUF_SIZE!"); - - const char* cpu_type = NULL; - const char* x64 = NULL; - - if (is_intel()) { - cpu_type = "Intel"; - x64 = cpu_is_em64t() ? " Intel64" : ""; - } else if (is_amd()) { - cpu_type = "AMD"; - x64 = cpu_is_em64t() ? " AMD64" : ""; - } else if (is_hygon()) { - cpu_type = "Hygon"; - x64 = cpu_is_em64t() ? " AMD64" : ""; - } else { - cpu_type = "Unknown x86"; - x64 = cpu_is_em64t() ? " x86_64" : ""; - } - - jio_snprintf(buf, buf_len, "%s %s%s SSE SSE2%s%s%s%s%s%s%s%s", - cpu_type, - cpu_family_description(), - supports_ht() ? " (HT)" : "", - supports_sse3() ? " SSE3" : "", - supports_ssse3() ? " SSSE3" : "", - supports_sse4_1() ? " SSE4.1" : "", - supports_sse4_2() ? " SSE4.2" : "", - supports_sse4a() ? " SSE4A" : "", - is_netburst() ? " Netburst" : "", - is_intel_family_core() ? " Core" : "", - x64); - - return OS_OK; -} - -int VM_Version_Ext::cpu_extended_brand_string(char* const buf, size_t buf_len) { - assert(buf != NULL, "buffer is NULL!"); - assert(buf_len >= CPU_EBS_MAX_LENGTH, "buffer len should at least be == CPU_EBS_MAX_LENGTH!"); - assert(getCPUIDBrandString_stub != NULL, "not initialized"); - - // invoke newly generated asm code to fetch CPU Brand String - getCPUIDBrandString_stub(&_cpuid_info); - - // fetch results into buffer - *((uint32_t*) &buf[0]) = _cpuid_info.proc_name_0; - *((uint32_t*) &buf[4]) = _cpuid_info.proc_name_1; - *((uint32_t*) &buf[8]) = _cpuid_info.proc_name_2; - *((uint32_t*) &buf[12]) = _cpuid_info.proc_name_3; - *((uint32_t*) &buf[16]) = _cpuid_info.proc_name_4; - *((uint32_t*) &buf[20]) = _cpuid_info.proc_name_5; - *((uint32_t*) &buf[24]) = _cpuid_info.proc_name_6; - *((uint32_t*) &buf[28]) = _cpuid_info.proc_name_7; - *((uint32_t*) &buf[32]) = _cpuid_info.proc_name_8; - *((uint32_t*) &buf[36]) = _cpuid_info.proc_name_9; - *((uint32_t*) &buf[40]) = _cpuid_info.proc_name_10; - *((uint32_t*) &buf[44]) = _cpuid_info.proc_name_11; - - return OS_OK; -} - -size_t VM_Version_Ext::cpu_write_support_string(char* const buf, size_t buf_len) { - guarantee(buf != NULL, "buffer is NULL!"); - guarantee(buf_len > 0, "buffer len not enough!"); - - unsigned int flag = 0; - unsigned int fi = 0; - size_t written = 0; - const char* prefix = ""; - -#define WRITE_TO_BUF(string) \ - { \ - int res = jio_snprintf(&buf[written], buf_len - written, "%s%s", prefix, string); \ - if (res < 0) { \ - return buf_len - 1; \ - } \ - written += res; \ - if (prefix[0] == '\0') { \ - prefix = ", "; \ - } \ - } - - for (flag = 1, fi = 0; flag <= 0x20000000 ; flag <<= 1, fi++) { - if (flag == HTT_FLAG && (((_cpuid_info.std_cpuid1_ebx.value >> 16) & 0xff) <= 1)) { - continue; /* no hyperthreading */ - } else if (flag == SEP_FLAG && (cpu_family() == CPU_FAMILY_PENTIUMPRO && ((_cpuid_info.std_cpuid1_eax.value & 0xff) < 0x33))) { - continue; /* no fast system call */ - } - if ((_cpuid_info.std_cpuid1_edx.value & flag) && strlen(_feature_edx_id[fi]) > 0) { - WRITE_TO_BUF(_feature_edx_id[fi]); - } - } - - for (flag = 1, fi = 0; flag <= 0x20000000; flag <<= 1, fi++) { - if ((_cpuid_info.std_cpuid1_ecx.value & flag) && strlen(_feature_ecx_id[fi]) > 0) { - WRITE_TO_BUF(_feature_ecx_id[fi]); - } - } - - for (flag = 1, fi = 0; flag <= 0x20000000 ; flag <<= 1, fi++) { - if ((_cpuid_info.ext_cpuid1_ecx.value & flag) && strlen(_feature_extended_ecx_id[fi]) > 0) { - WRITE_TO_BUF(_feature_extended_ecx_id[fi]); - } - } - - for (flag = 1, fi = 0; flag <= 0x20000000; flag <<= 1, fi++) { - if ((_cpuid_info.ext_cpuid1_edx.value & flag) && strlen(_feature_extended_edx_id[fi]) > 0) { - WRITE_TO_BUF(_feature_extended_edx_id[fi]); - } - } - - if (supports_tscinv_bit()) { - WRITE_TO_BUF("Invariant TSC"); - } - - return written; -} - -/** - * Write a detailed description of the cpu to a given buffer, including - * feature set. - */ -int VM_Version_Ext::cpu_detailed_description(char* const buf, size_t buf_len) { - assert(buf != NULL, "buffer is NULL!"); - assert(buf_len >= CPU_DETAILED_DESC_BUF_SIZE, "buffer len should at least be == CPU_DETAILED_DESC_BUF_SIZE!"); - - static const char* unknown = ""; - char vendor_id[VENDOR_LENGTH]; - const char* family = NULL; - const char* model = NULL; - const char* brand = NULL; - int outputLen = 0; - - family = cpu_family_description(); - if (family == NULL) { - family = unknown; - } - - model = cpu_model_description(); - if (model == NULL) { - model = unknown; - } - - brand = cpu_brand_string(); - - if (brand == NULL) { - brand = cpu_brand(); - if (brand == NULL) { - brand = unknown; - } - } - - *((uint32_t*) &vendor_id[0]) = _cpuid_info.std_vendor_name_0; - *((uint32_t*) &vendor_id[4]) = _cpuid_info.std_vendor_name_2; - *((uint32_t*) &vendor_id[8]) = _cpuid_info.std_vendor_name_1; - vendor_id[VENDOR_LENGTH-1] = '\0'; - - outputLen = jio_snprintf(buf, buf_len, "Brand: %s, Vendor: %s\n" - "Family: %s (0x%x), Model: %s (0x%x), Stepping: 0x%x\n" - "Ext. family: 0x%x, Ext. model: 0x%x, Type: 0x%x, Signature: 0x%8.8x\n" - "Features: ebx: 0x%8.8x, ecx: 0x%8.8x, edx: 0x%8.8x\n" - "Ext. features: eax: 0x%8.8x, ebx: 0x%8.8x, ecx: 0x%8.8x, edx: 0x%8.8x\n" - "Supports: ", - brand, - vendor_id, - family, - extended_cpu_family(), - model, - extended_cpu_model(), - cpu_stepping(), - _cpuid_info.std_cpuid1_eax.bits.ext_family, - _cpuid_info.std_cpuid1_eax.bits.ext_model, - _cpuid_info.std_cpuid1_eax.bits.proc_type, - _cpuid_info.std_cpuid1_eax.value, - _cpuid_info.std_cpuid1_ebx.value, - _cpuid_info.std_cpuid1_ecx.value, - _cpuid_info.std_cpuid1_edx.value, - _cpuid_info.ext_cpuid1_eax, - _cpuid_info.ext_cpuid1_ebx, - _cpuid_info.ext_cpuid1_ecx, - _cpuid_info.ext_cpuid1_edx); - - if (outputLen < 0 || (size_t) outputLen >= buf_len - 1) { - if (buf_len > 0) { buf[buf_len-1] = '\0'; } - return OS_ERR; - } - - cpu_write_support_string(&buf[outputLen], buf_len - outputLen); - - return OS_OK; -} - -const char* VM_Version_Ext::cpu_name(void) { - char cpu_type_desc[CPU_TYPE_DESC_BUF_SIZE]; - size_t cpu_desc_len = sizeof(cpu_type_desc); - - cpu_type_description(cpu_type_desc, cpu_desc_len); - char* tmp = NEW_C_HEAP_ARRAY_RETURN_NULL(char, cpu_desc_len, mtTracing); - if (NULL == tmp) { - return NULL; - } - strncpy(tmp, cpu_type_desc, cpu_desc_len); - return tmp; -} - -const char* VM_Version_Ext::cpu_description(void) { - char cpu_detailed_desc_buffer[CPU_DETAILED_DESC_BUF_SIZE]; - size_t cpu_detailed_desc_len = sizeof(cpu_detailed_desc_buffer); - - cpu_detailed_description(cpu_detailed_desc_buffer, cpu_detailed_desc_len); - - char* tmp = NEW_C_HEAP_ARRAY_RETURN_NULL(char, cpu_detailed_desc_len, mtTracing); - - if (NULL == tmp) { - return NULL; - } - - strncpy(tmp, cpu_detailed_desc_buffer, cpu_detailed_desc_len); - return tmp; -} - -/** - * For information about extracting the frequency from the cpu brand string, please see: - * - * Intel Processor Identification and the CPUID Instruction - * Application Note 485 - * May 2012 - * - * The return value is the frequency in Hz. - */ -int64_t VM_Version_Ext::max_qualified_cpu_freq_from_brand_string(void) { - const char* const brand_string = cpu_brand_string(); - if (brand_string == NULL) { - return 0; - } - const int64_t MEGA = 1000000; - int64_t multiplier = 0; - int64_t frequency = 0; - uint8_t idx = 0; - // The brand string buffer is at most 48 bytes. - // -2 is to prevent buffer overrun when looking for y in yHz, as z is +2 from y. - for (; idx < 48-2; ++idx) { - // Format is either "x.xxyHz" or "xxxxyHz", where y=M, G, T and x are digits. - // Search brand string for "yHz" where y is M, G, or T. - if (brand_string[idx+1] == 'H' && brand_string[idx+2] == 'z') { - if (brand_string[idx] == 'M') { - multiplier = MEGA; - } else if (brand_string[idx] == 'G') { - multiplier = MEGA * 1000; - } else if (brand_string[idx] == 'T') { - multiplier = MEGA * MEGA; - } - break; - } - } - if (multiplier > 0) { - // Compute freqency (in Hz) from brand string. - if (brand_string[idx-3] == '.') { // if format is "x.xx" - frequency = (brand_string[idx-4] - '0') * multiplier; - frequency += (brand_string[idx-2] - '0') * multiplier / 10; - frequency += (brand_string[idx-1] - '0') * multiplier / 100; - } else { // format is "xxxx" - frequency = (brand_string[idx-4] - '0') * 1000; - frequency += (brand_string[idx-3] - '0') * 100; - frequency += (brand_string[idx-2] - '0') * 10; - frequency += (brand_string[idx-1] - '0'); - frequency *= multiplier; - } - } - return frequency; -} - - -int64_t VM_Version_Ext::maximum_qualified_cpu_frequency(void) { - if (_max_qualified_cpu_frequency == 0) { - _max_qualified_cpu_frequency = max_qualified_cpu_freq_from_brand_string(); - } - return _max_qualified_cpu_frequency; -} - -const char* const VM_Version_Ext::_family_id_intel[ExtendedFamilyIdLength_INTEL] = { - "8086/8088", - "", - "286", - "386", - "486", - "Pentium", - "Pentium Pro", //or Pentium-M/Woodcrest depeding on model - "", - "", - "", - "", - "", - "", - "", - "", - "Pentium 4" -}; - -const char* const VM_Version_Ext::_family_id_amd[ExtendedFamilyIdLength_AMD] = { - "", - "", - "", - "", - "5x86", - "K5/K6", - "Athlon/AthlonXP", - "", - "", - "", - "", - "", - "", - "", - "", - "Opteron/Athlon64", - "Opteron QC/Phenom", // Barcelona et.al. - "", - "", - "", - "", - "", - "", - "Zen" -}; -// Partially from Intel 64 and IA-32 Architecture Software Developer's Manual, -// September 2013, Vol 3C Table 35-1 -const char* const VM_Version_Ext::_model_id_pentium_pro[] = { - "", - "Pentium Pro", - "", - "Pentium II model 3", - "", - "Pentium II model 5/Xeon/Celeron", - "Celeron", - "Pentium III/Pentium III Xeon", - "Pentium III/Pentium III Xeon", - "Pentium M model 9", // Yonah - "Pentium III, model A", - "Pentium III, model B", - "", - "Pentium M model D", // Dothan - "", - "Core 2", // 0xf Woodcrest/Conroe/Merom/Kentsfield/Clovertown - "", - "", - "", - "", - "", - "", - "Celeron", // 0x16 Celeron 65nm - "Core 2", // 0x17 Penryn / Harpertown - "", - "", - "Core i7", // 0x1A CPU_MODEL_NEHALEM_EP - "Atom", // 0x1B Z5xx series Silverthorn - "", - "Core 2", // 0x1D Dunnington (6-core) - "Nehalem", // 0x1E CPU_MODEL_NEHALEM - "", - "", - "", - "", - "", - "", - "Westmere", // 0x25 CPU_MODEL_WESTMERE - "", - "", - "", // 0x28 - "", - "Sandy Bridge", // 0x2a "2nd Generation Intel Core i7, i5, i3" - "", - "Westmere-EP", // 0x2c CPU_MODEL_WESTMERE_EP - "Sandy Bridge-EP", // 0x2d CPU_MODEL_SANDYBRIDGE_EP - "Nehalem-EX", // 0x2e CPU_MODEL_NEHALEM_EX - "Westmere-EX", // 0x2f CPU_MODEL_WESTMERE_EX - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "Ivy Bridge", // 0x3a - "", - "Haswell", // 0x3c "4th Generation Intel Core Processor" - "", // 0x3d "Next Generation Intel Core Processor" - "Ivy Bridge-EP", // 0x3e "Next Generation Intel Xeon Processor E7 Family" - "", // 0x3f "Future Generation Intel Xeon Processor" - "", - "", - "", - "", - "", - "Haswell", // 0x45 "4th Generation Intel Core Processor" - "Haswell", // 0x46 "4th Generation Intel Core Processor" - NULL -}; - -/* Brand ID is for back compability - * Newer CPUs uses the extended brand string */ -const char* const VM_Version_Ext::_brand_id[] = { - "", - "Celeron processor", - "Pentium III processor", - "Intel Pentium III Xeon processor", - "", - "", - "", - "", - "Intel Pentium 4 processor", - NULL -}; - - -const char* const VM_Version_Ext::_feature_edx_id[] = { - "On-Chip FPU", - "Virtual Mode Extensions", - "Debugging Extensions", - "Page Size Extensions", - "Time Stamp Counter", - "Model Specific Registers", - "Physical Address Extension", - "Machine Check Exceptions", - "CMPXCHG8B Instruction", - "On-Chip APIC", - "", - "Fast System Call", - "Memory Type Range Registers", - "Page Global Enable", - "Machine Check Architecture", - "Conditional Mov Instruction", - "Page Attribute Table", - "36-bit Page Size Extension", - "Processor Serial Number", - "CLFLUSH Instruction", - "", - "Debug Trace Store feature", - "ACPI registers in MSR space", - "Intel Architecture MMX Technology", - "Fast Float Point Save and Restore", - "Streaming SIMD extensions", - "Streaming SIMD extensions 2", - "Self-Snoop", - "Hyper Threading", - "Thermal Monitor", - "", - "Pending Break Enable" -}; - -const char* const VM_Version_Ext::_feature_extended_edx_id[] = { - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "SYSCALL/SYSRET", - "", - "", - "", - "", - "", - "", - "", - "", - "Execute Disable Bit", - "", - "", - "", - "", - "", - "", - "RDTSCP", - "", - "Intel 64 Architecture", - "", - "" -}; - -const char* const VM_Version_Ext::_feature_ecx_id[] = { - "Streaming SIMD Extensions 3", - "PCLMULQDQ", - "64-bit DS Area", - "MONITOR/MWAIT instructions", - "CPL Qualified Debug Store", - "Virtual Machine Extensions", - "Safer Mode Extensions", - "Enhanced Intel SpeedStep technology", - "Thermal Monitor 2", - "Supplemental Streaming SIMD Extensions 3", - "L1 Context ID", - "", - "Fused Multiply-Add", - "CMPXCHG16B", - "xTPR Update Control", - "Perfmon and Debug Capability", - "", - "Process-context identifiers", - "Direct Cache Access", - "Streaming SIMD extensions 4.1", - "Streaming SIMD extensions 4.2", - "x2APIC", - "MOVBE", - "Popcount instruction", - "TSC-Deadline", - "AESNI", - "XSAVE", - "OSXSAVE", - "AVX", - "F16C", - "RDRAND", - "" -}; - -const char* const VM_Version_Ext::_feature_extended_ecx_id[] = { - "LAHF/SAHF instruction support", - "Core multi-processor legacy mode", - "", - "", - "", - "Advanced Bit Manipulations: LZCNT", - "SSE4A: MOVNTSS, MOVNTSD, EXTRQ, INSERTQ", - "Misaligned SSE mode", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "" -}; diff --git a/src/hotspot/cpu/x86/vm_version_ext_x86.hpp b/src/hotspot/cpu/x86/vm_version_ext_x86.hpp deleted file mode 100644 index c81ebead23ca52d0a4691529cccc898292fa4358..0000000000000000000000000000000000000000 --- a/src/hotspot/cpu/x86/vm_version_ext_x86.hpp +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (c) 2013, 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_VM_VERSION_EXT_X86_HPP -#define CPU_X86_VM_VERSION_EXT_X86_HPP - -#include "runtime/vm_version.hpp" -#include "utilities/macros.hpp" -#include "utilities/sizes.hpp" - -class VM_Version_Ext : public VM_Version { - - enum { - ExtendedFamilyIdLength_INTEL = 16, - ExtendedFamilyIdLength_AMD = 24 - }; - - private: - static const size_t VENDOR_LENGTH; - static const size_t CPU_EBS_MAX_LENGTH; - static const size_t CPU_TYPE_DESC_BUF_SIZE; - static const size_t CPU_DETAILED_DESC_BUF_SIZE; - - static const char* const _family_id_intel[ExtendedFamilyIdLength_INTEL]; - static const char* const _family_id_amd[ExtendedFamilyIdLength_AMD]; - static const char* const _brand_id[]; - static const char* const _model_id_pentium_pro[]; - - static const char* const _feature_edx_id[]; - static const char* const _feature_extended_edx_id[]; - static const char* const _feature_ecx_id[]; - static const char* const _feature_extended_ecx_id[]; - - static int _no_of_threads; - static int _no_of_cores; - static int _no_of_packages; - static char* _cpu_brand_string; - static int64_t _max_qualified_cpu_frequency; - - static const char* cpu_family_description(void); - static const char* cpu_model_description(void); - static const char* cpu_brand(void); - static const char* cpu_brand_string(void); - - static int cpu_type_description(char* const buf, size_t buf_len); - static int cpu_detailed_description(char* const buf, size_t buf_len); - static int cpu_extended_brand_string(char* const buf, size_t buf_len); - - static bool cpu_is_em64t(void); - static bool is_netburst(void); - - // Returns bytes written excluding termninating null byte. - static size_t cpu_write_support_string(char* const buf, size_t buf_len); - static void resolve_cpu_information_details(void); - static int64_t max_qualified_cpu_freq_from_brand_string(void); - - public: - // Offsets for cpuid asm stub brand string - static ByteSize proc_name_0_offset() { return byte_offset_of(CpuidInfo, proc_name_0); } - static ByteSize proc_name_1_offset() { return byte_offset_of(CpuidInfo, proc_name_1); } - static ByteSize proc_name_2_offset() { return byte_offset_of(CpuidInfo, proc_name_2); } - static ByteSize proc_name_3_offset() { return byte_offset_of(CpuidInfo, proc_name_3); } - static ByteSize proc_name_4_offset() { return byte_offset_of(CpuidInfo, proc_name_4); } - static ByteSize proc_name_5_offset() { return byte_offset_of(CpuidInfo, proc_name_5); } - static ByteSize proc_name_6_offset() { return byte_offset_of(CpuidInfo, proc_name_6); } - static ByteSize proc_name_7_offset() { return byte_offset_of(CpuidInfo, proc_name_7); } - static ByteSize proc_name_8_offset() { return byte_offset_of(CpuidInfo, proc_name_8); } - static ByteSize proc_name_9_offset() { return byte_offset_of(CpuidInfo, proc_name_9); } - static ByteSize proc_name_10_offset() { return byte_offset_of(CpuidInfo, proc_name_10); } - static ByteSize proc_name_11_offset() { return byte_offset_of(CpuidInfo, proc_name_11); } - - static int number_of_threads(void); - static int number_of_cores(void); - static int number_of_sockets(void); - - static int64_t maximum_qualified_cpu_frequency(void); - - static bool supports_tscinv_ext(void); - - static const char* cpu_name(void); - static const char* cpu_description(void); - - static void initialize(); -}; - -#endif // CPU_X86_VM_VERSION_EXT_X86_HPP diff --git a/src/hotspot/cpu/x86/vm_version_x86.cpp b/src/hotspot/cpu/x86/vm_version_x86.cpp index 605faf89f196ab96362c3395ef84a695f5b2405d..c09785b969aa9d3bd9a4909e1b03925e4e58e756 100644 --- a/src/hotspot/cpu/x86/vm_version_x86.cpp +++ b/src/hotspot/cpu/x86/vm_version_x86.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -83,6 +83,19 @@ bool VM_Version::supports_clflush() { } #endif +#define CPUID_STANDARD_FN 0x0 +#define CPUID_STANDARD_FN_1 0x1 +#define CPUID_STANDARD_FN_4 0x4 +#define CPUID_STANDARD_FN_B 0xb + +#define CPUID_EXTENDED_FN 0x80000000 +#define CPUID_EXTENDED_FN_1 0x80000001 +#define CPUID_EXTENDED_FN_2 0x80000002 +#define CPUID_EXTENDED_FN_3 0x80000003 +#define CPUID_EXTENDED_FN_4 0x80000004 +#define CPUID_EXTENDED_FN_7 0x80000007 +#define CPUID_EXTENDED_FN_8 0x80000008 + class VM_Version_StubGenerator: public StubCodeGenerator { public: @@ -626,6 +639,149 @@ class VM_Version_StubGenerator: public StubCodeGenerator { __ pop(rbp); __ ret(0); +# undef __ + + return start; + }; + + + address generate_getCPUIDBrandString(void) { + // Flags to test CPU type. + const uint32_t HS_EFL_AC = 0x40000; + const uint32_t HS_EFL_ID = 0x200000; + // Values for when we don't have a CPUID instruction. + const int CPU_FAMILY_SHIFT = 8; + const uint32_t CPU_FAMILY_386 = (3 << CPU_FAMILY_SHIFT); + const uint32_t CPU_FAMILY_486 = (4 << CPU_FAMILY_SHIFT); + + Label detect_486, cpu486, detect_586, done, ext_cpuid; + + StubCodeMark mark(this, "VM_Version", "getCPUIDNameInfo_stub"); +# define __ _masm-> + + address start = __ pc(); + + // + // void getCPUIDBrandString(VM_Version::CpuidInfo* cpuid_info); + // + // LP64: rcx and rdx are first and second argument registers on windows + + __ push(rbp); +#ifdef _LP64 + __ mov(rbp, c_rarg0); // cpuid_info address +#else + __ movptr(rbp, Address(rsp, 8)); // cpuid_info address +#endif + __ push(rbx); + __ push(rsi); + __ pushf(); // preserve rbx, and flags + __ pop(rax); + __ push(rax); + __ mov(rcx, rax); + // + // if we are unable to change the AC flag, we have a 386 + // + __ xorl(rax, HS_EFL_AC); + __ push(rax); + __ popf(); + __ pushf(); + __ pop(rax); + __ cmpptr(rax, rcx); + __ jccb(Assembler::notEqual, detect_486); + + __ movl(rax, CPU_FAMILY_386); + __ jmp(done); + + // + // If we are unable to change the ID flag, we have a 486 which does + // not support the "cpuid" instruction. + // + __ bind(detect_486); + __ mov(rax, rcx); + __ xorl(rax, HS_EFL_ID); + __ push(rax); + __ popf(); + __ pushf(); + __ pop(rax); + __ cmpptr(rcx, rax); + __ jccb(Assembler::notEqual, detect_586); + + __ bind(cpu486); + __ movl(rax, CPU_FAMILY_486); + __ jmp(done); + + // + // At this point, we have a chip which supports the "cpuid" instruction + // + __ bind(detect_586); + __ xorl(rax, rax); + __ cpuid(); + __ orl(rax, rax); + __ jcc(Assembler::equal, cpu486); // if cpuid doesn't support an input + // value of at least 1, we give up and + // assume a 486 + + // + // Extended cpuid(0x80000000) for processor brand string detection + // + __ bind(ext_cpuid); + __ movl(rax, CPUID_EXTENDED_FN); + __ cpuid(); + __ cmpl(rax, CPUID_EXTENDED_FN_4); + __ jcc(Assembler::below, done); + + // + // Extended cpuid(0x80000002) // first 16 bytes in brand string + // + __ movl(rax, CPUID_EXTENDED_FN_2); + __ cpuid(); + __ lea(rsi, Address(rbp, in_bytes(VM_Version::proc_name_0_offset()))); + __ movl(Address(rsi, 0), rax); + __ lea(rsi, Address(rbp, in_bytes(VM_Version::proc_name_1_offset()))); + __ movl(Address(rsi, 0), rbx); + __ lea(rsi, Address(rbp, in_bytes(VM_Version::proc_name_2_offset()))); + __ movl(Address(rsi, 0), rcx); + __ lea(rsi, Address(rbp, in_bytes(VM_Version::proc_name_3_offset()))); + __ movl(Address(rsi,0), rdx); + + // + // Extended cpuid(0x80000003) // next 16 bytes in brand string + // + __ movl(rax, CPUID_EXTENDED_FN_3); + __ cpuid(); + __ lea(rsi, Address(rbp, in_bytes(VM_Version::proc_name_4_offset()))); + __ movl(Address(rsi, 0), rax); + __ lea(rsi, Address(rbp, in_bytes(VM_Version::proc_name_5_offset()))); + __ movl(Address(rsi, 0), rbx); + __ lea(rsi, Address(rbp, in_bytes(VM_Version::proc_name_6_offset()))); + __ movl(Address(rsi, 0), rcx); + __ lea(rsi, Address(rbp, in_bytes(VM_Version::proc_name_7_offset()))); + __ movl(Address(rsi,0), rdx); + + // + // Extended cpuid(0x80000004) // last 16 bytes in brand string + // + __ movl(rax, CPUID_EXTENDED_FN_4); + __ cpuid(); + __ lea(rsi, Address(rbp, in_bytes(VM_Version::proc_name_8_offset()))); + __ movl(Address(rsi, 0), rax); + __ lea(rsi, Address(rbp, in_bytes(VM_Version::proc_name_9_offset()))); + __ movl(Address(rsi, 0), rbx); + __ lea(rsi, Address(rbp, in_bytes(VM_Version::proc_name_10_offset()))); + __ movl(Address(rsi, 0), rcx); + __ lea(rsi, Address(rbp, in_bytes(VM_Version::proc_name_11_offset()))); + __ movl(Address(rsi,0), rdx); + + // + // return + // + __ bind(done); + __ popf(); + __ pop(rsi); + __ pop(rbx); + __ pop(rbp); + __ ret(0); + # undef __ return start; @@ -1662,9 +1818,6 @@ void VM_Version::get_processor_features() { if (FLAG_IS_DEFAULT(PrefetchScanIntervalInBytes)) { FLAG_SET_DEFAULT(PrefetchScanIntervalInBytes, 576); } - if (FLAG_IS_DEFAULT(PrefetchFieldsAhead)) { - FLAG_SET_DEFAULT(PrefetchFieldsAhead, 1); - } #endif if (FLAG_IS_DEFAULT(ContendedPaddingWidth) && @@ -1727,9 +1880,6 @@ void VM_Version::get_processor_features() { if (PrefetchScanIntervalInBytes > 0) { log->print_cr("PrefetchScanIntervalInBytes %d", (int) PrefetchScanIntervalInBytes); } - if (PrefetchFieldsAhead > 0) { - log->print_cr("PrefetchFieldsAhead %d", (int) PrefetchFieldsAhead); - } if (ContendedPaddingWidth > 0) { log->print_cr("ContendedPaddingWidth %d", (int) ContendedPaddingWidth); } @@ -1878,6 +2028,19 @@ void VM_Version::check_virtualizations() { } } +// avx3_threshold() sets the threshold at which 64-byte instructions are used +// for implementing the array copy and clear operations. +// The Intel platforms that supports the serialize instruction +// has improved implementation of 64-byte load/stores and so the default +// threshold is set to 0 for these platforms. +int VM_Version::avx3_threshold() { + return (is_intel_family_core() && + supports_serialize() && + FLAG_IS_DEFAULT(AVX3Threshold)) ? 0 : AVX3Threshold; +} + +static bool _vm_version_initialized = false; + void VM_Version::initialize() { ResourceMark rm; // Making this stub must be FIRST use of assembler @@ -1900,4 +2063,757 @@ void VM_Version::initialize() { if (VM_Version::supports_hv()) { // Supports hypervisor check_virtualizations(); } + _vm_version_initialized = true; } + +typedef enum { + CPU_FAMILY_8086_8088 = 0, + CPU_FAMILY_INTEL_286 = 2, + CPU_FAMILY_INTEL_386 = 3, + CPU_FAMILY_INTEL_486 = 4, + CPU_FAMILY_PENTIUM = 5, + CPU_FAMILY_PENTIUMPRO = 6, // Same family several models + CPU_FAMILY_PENTIUM_4 = 0xF +} FamilyFlag; + +typedef enum { + RDTSCP_FLAG = 0x08000000, // bit 27 + INTEL64_FLAG = 0x20000000 // bit 29 +} _featureExtendedEdxFlag; + +typedef enum { + FPU_FLAG = 0x00000001, + VME_FLAG = 0x00000002, + DE_FLAG = 0x00000004, + PSE_FLAG = 0x00000008, + TSC_FLAG = 0x00000010, + MSR_FLAG = 0x00000020, + PAE_FLAG = 0x00000040, + MCE_FLAG = 0x00000080, + CX8_FLAG = 0x00000100, + APIC_FLAG = 0x00000200, + SEP_FLAG = 0x00000800, + MTRR_FLAG = 0x00001000, + PGE_FLAG = 0x00002000, + MCA_FLAG = 0x00004000, + CMOV_FLAG = 0x00008000, + PAT_FLAG = 0x00010000, + PSE36_FLAG = 0x00020000, + PSNUM_FLAG = 0x00040000, + CLFLUSH_FLAG = 0x00080000, + DTS_FLAG = 0x00200000, + ACPI_FLAG = 0x00400000, + MMX_FLAG = 0x00800000, + FXSR_FLAG = 0x01000000, + SSE_FLAG = 0x02000000, + SSE2_FLAG = 0x04000000, + SS_FLAG = 0x08000000, + HTT_FLAG = 0x10000000, + TM_FLAG = 0x20000000 +} FeatureEdxFlag; + +static BufferBlob* cpuid_brand_string_stub_blob; +static const int cpuid_brand_string_stub_size = 550; + +extern "C" { + typedef void (*getCPUIDBrandString_stub_t)(void*); +} + +static getCPUIDBrandString_stub_t getCPUIDBrandString_stub = NULL; + +// VM_Version statics +enum { + ExtendedFamilyIdLength_INTEL = 16, + ExtendedFamilyIdLength_AMD = 24 +}; + +const size_t VENDOR_LENGTH = 13; +const size_t CPU_EBS_MAX_LENGTH = (3 * 4 * 4 + 1); +static char* _cpu_brand_string = NULL; +static int64_t _max_qualified_cpu_frequency = 0; + +static int _no_of_threads = 0; +static int _no_of_cores = 0; + +const char* const _family_id_intel[ExtendedFamilyIdLength_INTEL] = { + "8086/8088", + "", + "286", + "386", + "486", + "Pentium", + "Pentium Pro", //or Pentium-M/Woodcrest depeding on model + "", + "", + "", + "", + "", + "", + "", + "", + "Pentium 4" +}; + +const char* const _family_id_amd[ExtendedFamilyIdLength_AMD] = { + "", + "", + "", + "", + "5x86", + "K5/K6", + "Athlon/AthlonXP", + "", + "", + "", + "", + "", + "", + "", + "", + "Opteron/Athlon64", + "Opteron QC/Phenom", // Barcelona et.al. + "", + "", + "", + "", + "", + "", + "Zen" +}; +// Partially from Intel 64 and IA-32 Architecture Software Developer's Manual, +// September 2013, Vol 3C Table 35-1 +const char* const _model_id_pentium_pro[] = { + "", + "Pentium Pro", + "", + "Pentium II model 3", + "", + "Pentium II model 5/Xeon/Celeron", + "Celeron", + "Pentium III/Pentium III Xeon", + "Pentium III/Pentium III Xeon", + "Pentium M model 9", // Yonah + "Pentium III, model A", + "Pentium III, model B", + "", + "Pentium M model D", // Dothan + "", + "Core 2", // 0xf Woodcrest/Conroe/Merom/Kentsfield/Clovertown + "", + "", + "", + "", + "", + "", + "Celeron", // 0x16 Celeron 65nm + "Core 2", // 0x17 Penryn / Harpertown + "", + "", + "Core i7", // 0x1A CPU_MODEL_NEHALEM_EP + "Atom", // 0x1B Z5xx series Silverthorn + "", + "Core 2", // 0x1D Dunnington (6-core) + "Nehalem", // 0x1E CPU_MODEL_NEHALEM + "", + "", + "", + "", + "", + "", + "Westmere", // 0x25 CPU_MODEL_WESTMERE + "", + "", + "", // 0x28 + "", + "Sandy Bridge", // 0x2a "2nd Generation Intel Core i7, i5, i3" + "", + "Westmere-EP", // 0x2c CPU_MODEL_WESTMERE_EP + "Sandy Bridge-EP", // 0x2d CPU_MODEL_SANDYBRIDGE_EP + "Nehalem-EX", // 0x2e CPU_MODEL_NEHALEM_EX + "Westmere-EX", // 0x2f CPU_MODEL_WESTMERE_EX + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "Ivy Bridge", // 0x3a + "", + "Haswell", // 0x3c "4th Generation Intel Core Processor" + "", // 0x3d "Next Generation Intel Core Processor" + "Ivy Bridge-EP", // 0x3e "Next Generation Intel Xeon Processor E7 Family" + "", // 0x3f "Future Generation Intel Xeon Processor" + "", + "", + "", + "", + "", + "Haswell", // 0x45 "4th Generation Intel Core Processor" + "Haswell", // 0x46 "4th Generation Intel Core Processor" + NULL +}; + +/* Brand ID is for back compability + * Newer CPUs uses the extended brand string */ +const char* const _brand_id[] = { + "", + "Celeron processor", + "Pentium III processor", + "Intel Pentium III Xeon processor", + "", + "", + "", + "", + "Intel Pentium 4 processor", + NULL +}; + + +const char* const _feature_edx_id[] = { + "On-Chip FPU", + "Virtual Mode Extensions", + "Debugging Extensions", + "Page Size Extensions", + "Time Stamp Counter", + "Model Specific Registers", + "Physical Address Extension", + "Machine Check Exceptions", + "CMPXCHG8B Instruction", + "On-Chip APIC", + "", + "Fast System Call", + "Memory Type Range Registers", + "Page Global Enable", + "Machine Check Architecture", + "Conditional Mov Instruction", + "Page Attribute Table", + "36-bit Page Size Extension", + "Processor Serial Number", + "CLFLUSH Instruction", + "", + "Debug Trace Store feature", + "ACPI registers in MSR space", + "Intel Architecture MMX Technology", + "Fast Float Point Save and Restore", + "Streaming SIMD extensions", + "Streaming SIMD extensions 2", + "Self-Snoop", + "Hyper Threading", + "Thermal Monitor", + "", + "Pending Break Enable" +}; + +const char* const _feature_extended_edx_id[] = { + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "SYSCALL/SYSRET", + "", + "", + "", + "", + "", + "", + "", + "", + "Execute Disable Bit", + "", + "", + "", + "", + "", + "", + "RDTSCP", + "", + "Intel 64 Architecture", + "", + "" +}; + +const char* const _feature_ecx_id[] = { + "Streaming SIMD Extensions 3", + "PCLMULQDQ", + "64-bit DS Area", + "MONITOR/MWAIT instructions", + "CPL Qualified Debug Store", + "Virtual Machine Extensions", + "Safer Mode Extensions", + "Enhanced Intel SpeedStep technology", + "Thermal Monitor 2", + "Supplemental Streaming SIMD Extensions 3", + "L1 Context ID", + "", + "Fused Multiply-Add", + "CMPXCHG16B", + "xTPR Update Control", + "Perfmon and Debug Capability", + "", + "Process-context identifiers", + "Direct Cache Access", + "Streaming SIMD extensions 4.1", + "Streaming SIMD extensions 4.2", + "x2APIC", + "MOVBE", + "Popcount instruction", + "TSC-Deadline", + "AESNI", + "XSAVE", + "OSXSAVE", + "AVX", + "F16C", + "RDRAND", + "" +}; + +const char* const _feature_extended_ecx_id[] = { + "LAHF/SAHF instruction support", + "Core multi-processor legacy mode", + "", + "", + "", + "Advanced Bit Manipulations: LZCNT", + "SSE4A: MOVNTSS, MOVNTSD, EXTRQ, INSERTQ", + "Misaligned SSE mode", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" +}; + +void VM_Version::initialize_tsc(void) { + ResourceMark rm; + + cpuid_brand_string_stub_blob = BufferBlob::create("getCPUIDBrandString_stub", cpuid_brand_string_stub_size); + if (cpuid_brand_string_stub_blob == NULL) { + vm_exit_during_initialization("Unable to allocate getCPUIDBrandString_stub"); + } + CodeBuffer c(cpuid_brand_string_stub_blob); + VM_Version_StubGenerator g(&c); + getCPUIDBrandString_stub = CAST_TO_FN_PTR(getCPUIDBrandString_stub_t, + g.generate_getCPUIDBrandString()); +} + +const char* VM_Version::cpu_model_description(void) { + uint32_t cpu_family = extended_cpu_family(); + uint32_t cpu_model = extended_cpu_model(); + const char* model = NULL; + + if (cpu_family == CPU_FAMILY_PENTIUMPRO) { + for (uint32_t i = 0; i <= cpu_model; i++) { + model = _model_id_pentium_pro[i]; + if (model == NULL) { + break; + } + } + } + return model; +} + +const char* VM_Version::cpu_brand_string(void) { + if (_cpu_brand_string == NULL) { + _cpu_brand_string = NEW_C_HEAP_ARRAY_RETURN_NULL(char, CPU_EBS_MAX_LENGTH, mtInternal); + if (NULL == _cpu_brand_string) { + return NULL; + } + int ret_val = cpu_extended_brand_string(_cpu_brand_string, CPU_EBS_MAX_LENGTH); + if (ret_val != OS_OK) { + FREE_C_HEAP_ARRAY(char, _cpu_brand_string); + _cpu_brand_string = NULL; + } + } + return _cpu_brand_string; +} + +const char* VM_Version::cpu_brand(void) { + const char* brand = NULL; + + if ((_cpuid_info.std_cpuid1_ebx.value & 0xFF) > 0) { + int brand_num = _cpuid_info.std_cpuid1_ebx.value & 0xFF; + brand = _brand_id[0]; + for (int i = 0; brand != NULL && i <= brand_num; i += 1) { + brand = _brand_id[i]; + } + } + return brand; +} + +bool VM_Version::cpu_is_em64t(void) { + return ((_cpuid_info.ext_cpuid1_edx.value & INTEL64_FLAG) == INTEL64_FLAG); +} + +bool VM_Version::is_netburst(void) { + return (is_intel() && (extended_cpu_family() == CPU_FAMILY_PENTIUM_4)); +} + +bool VM_Version::supports_tscinv_ext(void) { + if (!supports_tscinv_bit()) { + return false; + } + + if (is_intel()) { + return true; + } + + if (is_amd()) { + return !is_amd_Barcelona(); + } + + if (is_hygon()) { + return true; + } + + return false; +} + +void VM_Version::resolve_cpu_information_details(void) { + + // in future we want to base this information on proper cpu + // and cache topology enumeration such as: + // Intel 64 Architecture Processor Topology Enumeration + // which supports system cpu and cache topology enumeration + // either using 2xAPICIDs or initial APICIDs + + // currently only rough cpu information estimates + // which will not necessarily reflect the exact configuration of the system + + // this is the number of logical hardware threads + // visible to the operating system + _no_of_threads = os::processor_count(); + + // find out number of threads per cpu package + int threads_per_package = threads_per_core() * cores_per_cpu(); + + // use amount of threads visible to the process in order to guess number of sockets + _no_of_sockets = _no_of_threads / threads_per_package; + + // process might only see a subset of the total number of threads + // from a single processor package. Virtualization/resource management for example. + // If so then just write a hard 1 as num of pkgs. + if (0 == _no_of_sockets) { + _no_of_sockets = 1; + } + + // estimate the number of cores + _no_of_cores = cores_per_cpu() * _no_of_sockets; +} + + +const char* VM_Version::cpu_family_description(void) { + int cpu_family_id = extended_cpu_family(); + if (is_amd()) { + if (cpu_family_id < ExtendedFamilyIdLength_AMD) { + return _family_id_amd[cpu_family_id]; + } + } + if (is_intel()) { + if (cpu_family_id == CPU_FAMILY_PENTIUMPRO) { + return cpu_model_description(); + } + if (cpu_family_id < ExtendedFamilyIdLength_INTEL) { + return _family_id_intel[cpu_family_id]; + } + } + if (is_hygon()) { + return "Dhyana"; + } + return "Unknown x86"; +} + +int VM_Version::cpu_type_description(char* const buf, size_t buf_len) { + assert(buf != NULL, "buffer is NULL!"); + assert(buf_len >= CPU_TYPE_DESC_BUF_SIZE, "buffer len should at least be == CPU_TYPE_DESC_BUF_SIZE!"); + + const char* cpu_type = NULL; + const char* x64 = NULL; + + if (is_intel()) { + cpu_type = "Intel"; + x64 = cpu_is_em64t() ? " Intel64" : ""; + } else if (is_amd()) { + cpu_type = "AMD"; + x64 = cpu_is_em64t() ? " AMD64" : ""; + } else if (is_hygon()) { + cpu_type = "Hygon"; + x64 = cpu_is_em64t() ? " AMD64" : ""; + } else { + cpu_type = "Unknown x86"; + x64 = cpu_is_em64t() ? " x86_64" : ""; + } + + jio_snprintf(buf, buf_len, "%s %s%s SSE SSE2%s%s%s%s%s%s%s%s", + cpu_type, + cpu_family_description(), + supports_ht() ? " (HT)" : "", + supports_sse3() ? " SSE3" : "", + supports_ssse3() ? " SSSE3" : "", + supports_sse4_1() ? " SSE4.1" : "", + supports_sse4_2() ? " SSE4.2" : "", + supports_sse4a() ? " SSE4A" : "", + is_netburst() ? " Netburst" : "", + is_intel_family_core() ? " Core" : "", + x64); + + return OS_OK; +} + +int VM_Version::cpu_extended_brand_string(char* const buf, size_t buf_len) { + assert(buf != NULL, "buffer is NULL!"); + assert(buf_len >= CPU_EBS_MAX_LENGTH, "buffer len should at least be == CPU_EBS_MAX_LENGTH!"); + assert(getCPUIDBrandString_stub != NULL, "not initialized"); + + // invoke newly generated asm code to fetch CPU Brand String + getCPUIDBrandString_stub(&_cpuid_info); + + // fetch results into buffer + *((uint32_t*) &buf[0]) = _cpuid_info.proc_name_0; + *((uint32_t*) &buf[4]) = _cpuid_info.proc_name_1; + *((uint32_t*) &buf[8]) = _cpuid_info.proc_name_2; + *((uint32_t*) &buf[12]) = _cpuid_info.proc_name_3; + *((uint32_t*) &buf[16]) = _cpuid_info.proc_name_4; + *((uint32_t*) &buf[20]) = _cpuid_info.proc_name_5; + *((uint32_t*) &buf[24]) = _cpuid_info.proc_name_6; + *((uint32_t*) &buf[28]) = _cpuid_info.proc_name_7; + *((uint32_t*) &buf[32]) = _cpuid_info.proc_name_8; + *((uint32_t*) &buf[36]) = _cpuid_info.proc_name_9; + *((uint32_t*) &buf[40]) = _cpuid_info.proc_name_10; + *((uint32_t*) &buf[44]) = _cpuid_info.proc_name_11; + + return OS_OK; +} + +size_t VM_Version::cpu_write_support_string(char* const buf, size_t buf_len) { + guarantee(buf != NULL, "buffer is NULL!"); + guarantee(buf_len > 0, "buffer len not enough!"); + + unsigned int flag = 0; + unsigned int fi = 0; + size_t written = 0; + const char* prefix = ""; + +#define WRITE_TO_BUF(string) \ + { \ + int res = jio_snprintf(&buf[written], buf_len - written, "%s%s", prefix, string); \ + if (res < 0) { \ + return buf_len - 1; \ + } \ + written += res; \ + if (prefix[0] == '\0') { \ + prefix = ", "; \ + } \ + } + + for (flag = 1, fi = 0; flag <= 0x20000000 ; flag <<= 1, fi++) { + if (flag == HTT_FLAG && (((_cpuid_info.std_cpuid1_ebx.value >> 16) & 0xff) <= 1)) { + continue; /* no hyperthreading */ + } else if (flag == SEP_FLAG && (cpu_family() == CPU_FAMILY_PENTIUMPRO && ((_cpuid_info.std_cpuid1_eax.value & 0xff) < 0x33))) { + continue; /* no fast system call */ + } + if ((_cpuid_info.std_cpuid1_edx.value & flag) && strlen(_feature_edx_id[fi]) > 0) { + WRITE_TO_BUF(_feature_edx_id[fi]); + } + } + + for (flag = 1, fi = 0; flag <= 0x20000000; flag <<= 1, fi++) { + if ((_cpuid_info.std_cpuid1_ecx.value & flag) && strlen(_feature_ecx_id[fi]) > 0) { + WRITE_TO_BUF(_feature_ecx_id[fi]); + } + } + + for (flag = 1, fi = 0; flag <= 0x20000000 ; flag <<= 1, fi++) { + if ((_cpuid_info.ext_cpuid1_ecx.value & flag) && strlen(_feature_extended_ecx_id[fi]) > 0) { + WRITE_TO_BUF(_feature_extended_ecx_id[fi]); + } + } + + for (flag = 1, fi = 0; flag <= 0x20000000; flag <<= 1, fi++) { + if ((_cpuid_info.ext_cpuid1_edx.value & flag) && strlen(_feature_extended_edx_id[fi]) > 0) { + WRITE_TO_BUF(_feature_extended_edx_id[fi]); + } + } + + if (supports_tscinv_bit()) { + WRITE_TO_BUF("Invariant TSC"); + } + + return written; +} + +/** + * Write a detailed description of the cpu to a given buffer, including + * feature set. + */ +int VM_Version::cpu_detailed_description(char* const buf, size_t buf_len) { + assert(buf != NULL, "buffer is NULL!"); + assert(buf_len >= CPU_DETAILED_DESC_BUF_SIZE, "buffer len should at least be == CPU_DETAILED_DESC_BUF_SIZE!"); + + static const char* unknown = ""; + char vendor_id[VENDOR_LENGTH]; + const char* family = NULL; + const char* model = NULL; + const char* brand = NULL; + int outputLen = 0; + + family = cpu_family_description(); + if (family == NULL) { + family = unknown; + } + + model = cpu_model_description(); + if (model == NULL) { + model = unknown; + } + + brand = cpu_brand_string(); + + if (brand == NULL) { + brand = cpu_brand(); + if (brand == NULL) { + brand = unknown; + } + } + + *((uint32_t*) &vendor_id[0]) = _cpuid_info.std_vendor_name_0; + *((uint32_t*) &vendor_id[4]) = _cpuid_info.std_vendor_name_2; + *((uint32_t*) &vendor_id[8]) = _cpuid_info.std_vendor_name_1; + vendor_id[VENDOR_LENGTH-1] = '\0'; + + outputLen = jio_snprintf(buf, buf_len, "Brand: %s, Vendor: %s\n" + "Family: %s (0x%x), Model: %s (0x%x), Stepping: 0x%x\n" + "Ext. family: 0x%x, Ext. model: 0x%x, Type: 0x%x, Signature: 0x%8.8x\n" + "Features: ebx: 0x%8.8x, ecx: 0x%8.8x, edx: 0x%8.8x\n" + "Ext. features: eax: 0x%8.8x, ebx: 0x%8.8x, ecx: 0x%8.8x, edx: 0x%8.8x\n" + "Supports: ", + brand, + vendor_id, + family, + extended_cpu_family(), + model, + extended_cpu_model(), + cpu_stepping(), + _cpuid_info.std_cpuid1_eax.bits.ext_family, + _cpuid_info.std_cpuid1_eax.bits.ext_model, + _cpuid_info.std_cpuid1_eax.bits.proc_type, + _cpuid_info.std_cpuid1_eax.value, + _cpuid_info.std_cpuid1_ebx.value, + _cpuid_info.std_cpuid1_ecx.value, + _cpuid_info.std_cpuid1_edx.value, + _cpuid_info.ext_cpuid1_eax, + _cpuid_info.ext_cpuid1_ebx, + _cpuid_info.ext_cpuid1_ecx, + _cpuid_info.ext_cpuid1_edx); + + if (outputLen < 0 || (size_t) outputLen >= buf_len - 1) { + if (buf_len > 0) { buf[buf_len-1] = '\0'; } + return OS_ERR; + } + + cpu_write_support_string(&buf[outputLen], buf_len - outputLen); + + return OS_OK; +} + + +// Fill in Abstract_VM_Version statics +void VM_Version::initialize_cpu_information() { + assert(_vm_version_initialized, "should have initialized VM_Version long ago"); + assert(!_initialized, "shouldn't be initialized yet"); + resolve_cpu_information_details(); + + // initialize cpu_name and cpu_desc + cpu_type_description(_cpu_name, CPU_TYPE_DESC_BUF_SIZE); + cpu_detailed_description(_cpu_desc, CPU_DETAILED_DESC_BUF_SIZE); + _initialized = true; +} + +/** + * For information about extracting the frequency from the cpu brand string, please see: + * + * Intel Processor Identification and the CPUID Instruction + * Application Note 485 + * May 2012 + * + * The return value is the frequency in Hz. + */ +int64_t VM_Version::max_qualified_cpu_freq_from_brand_string(void) { + const char* const brand_string = cpu_brand_string(); + if (brand_string == NULL) { + return 0; + } + const int64_t MEGA = 1000000; + int64_t multiplier = 0; + int64_t frequency = 0; + uint8_t idx = 0; + // The brand string buffer is at most 48 bytes. + // -2 is to prevent buffer overrun when looking for y in yHz, as z is +2 from y. + for (; idx < 48-2; ++idx) { + // Format is either "x.xxyHz" or "xxxxyHz", where y=M, G, T and x are digits. + // Search brand string for "yHz" where y is M, G, or T. + if (brand_string[idx+1] == 'H' && brand_string[idx+2] == 'z') { + if (brand_string[idx] == 'M') { + multiplier = MEGA; + } else if (brand_string[idx] == 'G') { + multiplier = MEGA * 1000; + } else if (brand_string[idx] == 'T') { + multiplier = MEGA * MEGA; + } + break; + } + } + if (multiplier > 0) { + // Compute freqency (in Hz) from brand string. + if (brand_string[idx-3] == '.') { // if format is "x.xx" + frequency = (brand_string[idx-4] - '0') * multiplier; + frequency += (brand_string[idx-2] - '0') * multiplier / 10; + frequency += (brand_string[idx-1] - '0') * multiplier / 100; + } else { // format is "xxxx" + frequency = (brand_string[idx-4] - '0') * 1000; + frequency += (brand_string[idx-3] - '0') * 100; + frequency += (brand_string[idx-2] - '0') * 10; + frequency += (brand_string[idx-1] - '0'); + frequency *= multiplier; + } + } + return frequency; +} + + +int64_t VM_Version::maximum_qualified_cpu_frequency(void) { + if (_max_qualified_cpu_frequency == 0) { + _max_qualified_cpu_frequency = max_qualified_cpu_freq_from_brand_string(); + } + return _max_qualified_cpu_frequency; +} + diff --git a/src/hotspot/cpu/x86/vm_version_x86.hpp b/src/hotspot/cpu/x86/vm_version_x86.hpp index 6feb3b8c1a0a6ec18ce98ecb47d7f05250cd65e0..2f4e31b4708ec8e9c777584dd5e1e5ea65111133 100644 --- a/src/hotspot/cpu/x86/vm_version_x86.hpp +++ b/src/hotspot/cpu/x86/vm_version_x86.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -148,12 +148,11 @@ class VM_Version : public Abstract_VM_Version { uint32_t LahfSahf : 1, CmpLegacy : 1, : 3, - lzcnt_intel : 1, lzcnt : 1, sse4a : 1, misalignsse : 1, prefetchw : 1, - : 22; + : 23; } bits; }; @@ -371,7 +370,7 @@ protected: static const char* _features_names[]; -enum Extended_Family { + enum Extended_Family { // AMD CPU_FAMILY_AMD_11H = 0x11, // ZX @@ -640,10 +639,10 @@ enum Extended_Family { // Intel features. if (is_intel()) { - if (_cpuid_info.ext_cpuid1_ecx.bits.lzcnt_intel != 0) + if (_cpuid_info.ext_cpuid1_ecx.bits.lzcnt != 0) { result |= CPU_LZCNT; - // for Intel, ecx.bits.misalignsse bit (bit 8) indicates support for prefetchw - if (_cpuid_info.ext_cpuid1_ecx.bits.misalignsse != 0) { + } + if (_cpuid_info.ext_cpuid1_ecx.bits.prefetchw != 0) { result |= CPU_3DNOW_PREFETCH; } if (_cpuid_info.sef_cpuid7_ebx.bits.clwb != 0) { @@ -655,10 +654,10 @@ enum Extended_Family { // ZX features. if (is_zx()) { - if (_cpuid_info.ext_cpuid1_ecx.bits.lzcnt_intel != 0) + if (_cpuid_info.ext_cpuid1_ecx.bits.lzcnt != 0) { result |= CPU_LZCNT; - // for ZX, ecx.bits.misalignsse bit (bit 8) indicates support for prefetchw - if (_cpuid_info.ext_cpuid1_ecx.bits.misalignsse != 0) { + } + if (_cpuid_info.ext_cpuid1_ecx.bits.prefetchw != 0) { result |= CPU_3DNOW_PREFETCH; } } @@ -911,6 +910,8 @@ public: static bool is_intel_skylake() { return is_intel_family_core() && extended_cpu_model() == CPU_MODEL_SKYLAKE; } + static int avx3_threshold(); + static bool is_intel_tsc_synched_at_init() { if (is_intel_family_core()) { uint32_t ext_model = extended_cpu_model(); @@ -1043,6 +1044,25 @@ public: static bool supports_clflushopt() { return ((_features & CPU_FLUSHOPT) != 0); } static bool supports_clwb() { return ((_features & CPU_CLWB) != 0); } + // Old CPUs perform lea on AGU which causes additional latency transfering the + // value from/to ALU for other operations + static bool supports_fast_2op_lea() { + return (is_intel() && supports_avx()) || // Sandy Bridge and above + (is_amd() && supports_avx()); // Jaguar and Bulldozer and above + } + + // Pre Icelake Intels suffer inefficiency regarding 3-operand lea, which contains + // all of base register, index register and displacement immediate, with 3 latency. + // Note that when the address contains no displacement but the base register is + // rbp or r13, the machine code must contain a zero displacement immediate, + // effectively transform a 2-operand lea into a 3-operand lea. This can be + // replaced by add-add or lea-add + static bool supports_fast_3op_lea() { + return supports_fast_2op_lea() && + ((is_intel() && supports_clwb() && !is_intel_skylake()) || // Icelake and above + is_amd()); + } + #ifdef __APPLE__ // Is the CPU running emulated (for example macOS Rosetta running x86_64 code on M1 ARM (aarch64) static bool is_cpu_emulated(); @@ -1051,6 +1071,45 @@ public: // support functions for virtualization detection private: static void check_virtualizations(); + + static const char* cpu_family_description(void); + static const char* cpu_model_description(void); + static const char* cpu_brand(void); + static const char* cpu_brand_string(void); + + static int cpu_type_description(char* const buf, size_t buf_len); + static int cpu_detailed_description(char* const buf, size_t buf_len); + static int cpu_extended_brand_string(char* const buf, size_t buf_len); + + static bool cpu_is_em64t(void); + static bool is_netburst(void); + + // Returns bytes written excluding termninating null byte. + static size_t cpu_write_support_string(char* const buf, size_t buf_len); + static void resolve_cpu_information_details(void); + static int64_t max_qualified_cpu_freq_from_brand_string(void); + + public: + // Offsets for cpuid asm stub brand string + static ByteSize proc_name_0_offset() { return byte_offset_of(CpuidInfo, proc_name_0); } + static ByteSize proc_name_1_offset() { return byte_offset_of(CpuidInfo, proc_name_1); } + static ByteSize proc_name_2_offset() { return byte_offset_of(CpuidInfo, proc_name_2); } + static ByteSize proc_name_3_offset() { return byte_offset_of(CpuidInfo, proc_name_3); } + static ByteSize proc_name_4_offset() { return byte_offset_of(CpuidInfo, proc_name_4); } + static ByteSize proc_name_5_offset() { return byte_offset_of(CpuidInfo, proc_name_5); } + static ByteSize proc_name_6_offset() { return byte_offset_of(CpuidInfo, proc_name_6); } + static ByteSize proc_name_7_offset() { return byte_offset_of(CpuidInfo, proc_name_7); } + static ByteSize proc_name_8_offset() { return byte_offset_of(CpuidInfo, proc_name_8); } + static ByteSize proc_name_9_offset() { return byte_offset_of(CpuidInfo, proc_name_9); } + static ByteSize proc_name_10_offset() { return byte_offset_of(CpuidInfo, proc_name_10); } + static ByteSize proc_name_11_offset() { return byte_offset_of(CpuidInfo, proc_name_11); } + + static int64_t maximum_qualified_cpu_frequency(void); + + static bool supports_tscinv_ext(void); + + static void initialize_tsc(); + static void initialize_cpu_information(void); }; #endif // CPU_X86_VM_VERSION_X86_HPP diff --git a/src/hotspot/cpu/x86/x86.ad b/src/hotspot/cpu/x86/x86.ad index 5a8569dc6e0f290eb7d68b850bdd60636fad16df..ab28ebd5ca5e1da187a41fd625a5a5350aefea5b 100644 --- a/src/hotspot/cpu/x86/x86.ad +++ b/src/hotspot/cpu/x86/x86.ad @@ -1,5 +1,5 @@ // -// Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved. +// Copyright (c) 2011, 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 @@ -1382,6 +1382,8 @@ Assembler::Width widthForType(BasicType bt) { static address vector_long_shufflemask() { return StubRoutines::x86::vector_long_shuffle_mask(); } static address vector_32_bit_mask() { return StubRoutines::x86::vector_32_bit_mask(); } static address vector_64_bit_mask() { return StubRoutines::x86::vector_64_bit_mask(); } + static address vector_float_signflip() { return StubRoutines::x86::vector_float_sign_flip();} + static address vector_double_signflip() { return StubRoutines::x86::vector_double_sign_flip();} //============================================================================= const bool Matcher::match_rule_supported(int opcode) { @@ -1403,7 +1405,12 @@ const bool Matcher::match_rule_supported(int opcode) { } break; case Op_PopCountVI: - if (!UsePopCountInstruction || !VM_Version::supports_avx512_vpopcntdq()) { + if (!UsePopCountInstruction || (UseAVX < 2)) { + return false; + } + break; + case Op_PopCountVL: + if (!UsePopCountInstruction || (UseAVX <= 2)) { return false; } break; @@ -1454,6 +1461,9 @@ const bool Matcher::match_rule_supported(int opcode) { case Op_VectorCastL2X: case Op_VectorCastF2X: case Op_VectorCastD2X: + case Op_VectorUCastB2X: + case Op_VectorUCastS2X: + case Op_VectorUCastI2X: if (UseAVX < 1) { // enabled for AVX only return false; } @@ -1599,6 +1609,21 @@ const bool Matcher::match_rule_supported(int opcode) { return false; } break; + case Op_SqrtF: + if (UseSSE < 1) { + return false; + } + break; + case Op_SqrtD: +#ifdef _LP64 + if (UseSSE < 2) { + return false; + } +#else + // x86_32.ad has a special match rule for SqrtD. + // Together with common x86 rules, this handles all UseSSE cases. +#endif + break; } return true; // Match rules are supported by default. } @@ -1771,17 +1796,9 @@ const bool Matcher::match_rule_supported_vector(int opcode, int vlen, BasicType } break; case Op_VectorCastB2X: - if (size_in_bits == 256 && UseAVX < 2) { - return false; // Implementation limitation - } - break; case Op_VectorCastS2X: - if (is_integral_type(bt) && size_in_bits == 256 && UseAVX < 2) { - return false; - } - break; case Op_VectorCastI2X: - if (is_integral_type(bt) && size_in_bits == 256 && UseAVX < 2) { + if (bt != T_DOUBLE && size_in_bits == 256 && UseAVX < 2) { return false; } break; @@ -1792,13 +1809,19 @@ const bool Matcher::match_rule_supported_vector(int opcode, int vlen, BasicType return false; } break; - case Op_VectorCastF2X: case Op_VectorCastD2X: - if (is_integral_type(bt)) { - // Casts from FP to integral types require special fixup logic not easily - // implementable with vectors. - return false; // Implementation limitation + if (is_subword_type(bt) || bt == T_INT) { + return false; } + if (bt == T_LONG && !VM_Version::supports_avx512dq()) { + return false; + } + break; + case Op_VectorCastF2X: + if (is_subword_type(bt) || bt == T_LONG) { + return false; + } + break; case Op_MulReductionVI: if (bt == T_BYTE && size_in_bits == 512 && !VM_Version::supports_avx512bw()) { return false; @@ -1819,7 +1842,7 @@ const bool Matcher::match_rule_supported_vector(int opcode, int vlen, BasicType } break; case Op_MaskAll: - if (!is_LP64 || !VM_Version::supports_evex()) { + if (!VM_Version::supports_evex()) { return false; } if ((vlen > 16 || is_subword_type(bt)) && !VM_Version::supports_avx512bw()) { @@ -1834,6 +1857,26 @@ const bool Matcher::match_rule_supported_vector(int opcode, int vlen, BasicType return false; } break; + case Op_VectorLongToMask: + if (UseAVX < 1 || !is_LP64) { + return false; + } + if (UseAVX < 3 && !VM_Version::supports_bmi2()) { + return false; + } + break; + case Op_PopCountVI: + if (!VM_Version::supports_avx512_vpopcntdq() && + (vlen == 16) && !VM_Version::supports_avx512bw()) { + return false; + } + break; + case Op_PopCountVL: + if (!VM_Version::supports_avx512_vpopcntdq() && + ((vlen <= 4) || ((vlen == 8) && !VM_Version::supports_avx512bw()))) { + return false; + } + break; } return true; // Per default match rules are supported. } @@ -1870,6 +1913,12 @@ const bool Matcher::match_rule_supported_vector_masked(int opcode, int vlen, Bas case Op_FmaVD: return true; + case Op_MacroLogicV: + if(bt != T_INT && bt != T_LONG) { + return false; + } + return true; + // Binary masked operations case Op_AddVB: case Op_AddVS: @@ -2043,7 +2092,7 @@ const RegMask* Matcher::predicate_reg_mask(void) { return &_VECTMASK_REG_mask; } -const TypeVect* Matcher::predicate_reg_type(const Type* elemTy, int length) { +const TypeVectMask* Matcher::predicate_reg_type(const Type* elemTy, int length) { return new TypeVectMask(elemTy, length); } @@ -2522,19 +2571,37 @@ void vec_spill_helper(CodeBuffer *cbuf, bool is_load, } } -static inline jlong replicate8_imm(int con, int width) { - // Load a constant of "width" (in bytes) and replicate it to fill 64bit. - assert(width == 1 || width == 2 || width == 4, "only byte, short or int types here"); - int bit_width = width * 8; - jlong val = con; - val &= (((jlong) 1) << bit_width) - 1; // mask off sign bits - while(bit_width < 64) { - val |= (val << bit_width); - bit_width <<= 1; +template +static inline GrowableArray* vreplicate_imm(BasicType bt, T con, int len) { + GrowableArray* val = new GrowableArray(len); + jvalue ele; + switch (bt) { + case T_BYTE: ele.b = con; break; + case T_SHORT: ele.s = con; break; + case T_INT: ele.i = con; break; + case T_LONG: ele.j = con; break; + case T_FLOAT: ele.f = con; break; + case T_DOUBLE: ele.d = con; break; + default: ShouldNotReachHere(); + } + for (int i = 0; i < len; i++) { + val->append(ele); } return val; } +static inline jlong high_bit_set(BasicType bt) { + switch (bt) { + case T_BYTE: return 0x8080808080808080; + case T_SHORT: return 0x8000800080008000; + case T_INT: return 0x8000000080000000; + case T_LONG: return 0x8000000000000000; + default: + ShouldNotReachHere(); + return 0; + } +} + #ifndef PRODUCT void MachNopNode::format(PhaseRegAlloc*, outputStream* st) const { st->print("nop \t# %d bytes pad for loops and calls", _count); @@ -3782,14 +3849,7 @@ instruct loadV(vec dst, memory mem) %{ ins_cost(125); format %{ "load_vector $dst,$mem" %} ins_encode %{ - switch (Matcher::vector_length_in_bytes(this)) { - case 4: __ movdl ($dst$$XMMRegister, $mem$$Address); break; - case 8: __ movq ($dst$$XMMRegister, $mem$$Address); break; - case 16: __ movdqu ($dst$$XMMRegister, $mem$$Address); break; - case 32: __ vmovdqu ($dst$$XMMRegister, $mem$$Address); break; - case 64: __ evmovdqul($dst$$XMMRegister, $mem$$Address, Assembler::AVX_512bit); break; - default: ShouldNotReachHere(); - } + __ load_vector($dst$$XMMRegister, $mem$$Address, Matcher::vector_length_in_bytes(this)); %} ins_pipe( pipe_slow ); %} @@ -3967,43 +4027,12 @@ instruct ReplB_imm(vec dst, immI con) %{ match(Set dst (ReplicateB con)); format %{ "replicateB $dst,$con" %} ins_encode %{ - uint vlen = Matcher::vector_length(this); - InternalAddress const_addr = $constantaddress(replicate8_imm($con$$constant, 1)); - if (vlen == 4) { - __ movdl($dst$$XMMRegister, const_addr); - } else { - __ movq($dst$$XMMRegister, const_addr); - if (vlen >= 16) { - if (VM_Version::supports_avx2()) { - int vlen_enc = vector_length_encoding(this); - __ vpbroadcastq($dst$$XMMRegister, $dst$$XMMRegister, vlen_enc); - } else { - assert(vlen == 16, "sanity"); - __ punpcklqdq($dst$$XMMRegister, $dst$$XMMRegister); - } - } - } + InternalAddress addr = $constantaddress(T_BYTE, vreplicate_imm(T_BYTE, $con$$constant, Matcher::vector_length(this))); + __ load_vector($dst$$XMMRegister, addr, Matcher::vector_length_in_bytes(this)); %} ins_pipe( pipe_slow ); %} -// Replicate byte scalar zero to be vector -instruct ReplB_zero(vec dst, immI_0 zero) %{ - match(Set dst (ReplicateB zero)); - format %{ "replicateB $dst,$zero" %} - ins_encode %{ - uint vlen = Matcher::vector_length(this); - if (vlen <= 16) { - __ pxor($dst$$XMMRegister, $dst$$XMMRegister); - } else { - // Use vpxor since AVX512F does not have 512bit vxorpd (requires AVX512DQ). - int vlen_enc = vector_length_encoding(this); - __ vpxor($dst$$XMMRegister, $dst$$XMMRegister, $dst$$XMMRegister, vlen_enc); - } - %} - ins_pipe( fpu_reg_reg ); -%} - // ====================ReplicateS======================================= instruct ReplS_reg(vec dst, rRegI src) %{ @@ -4049,39 +4078,10 @@ instruct ReplS_imm(vec dst, immI con) %{ match(Set dst (ReplicateS con)); format %{ "replicateS $dst,$con" %} ins_encode %{ - uint vlen = Matcher::vector_length(this); - InternalAddress const_addr = $constantaddress(replicate8_imm($con$$constant, 2)); - if (vlen == 2) { - __ movdl($dst$$XMMRegister, const_addr); - } else { - __ movq($dst$$XMMRegister, const_addr); - if (vlen >= 8) { - if (VM_Version::supports_avx2()) { - int vlen_enc = vector_length_encoding(this); - __ vpbroadcastw($dst$$XMMRegister, $dst$$XMMRegister, vlen_enc); - } else { - assert(vlen == 8, "sanity"); - __ punpcklqdq($dst$$XMMRegister, $dst$$XMMRegister); - } - } - } - %} - ins_pipe( fpu_reg_reg ); -%} - -instruct ReplS_zero(vec dst, immI_0 zero) %{ - match(Set dst (ReplicateS zero)); - format %{ "replicateS $dst,$zero" %} - ins_encode %{ - uint vlen = Matcher::vector_length(this); - if (vlen <= 8) { - __ pxor($dst$$XMMRegister, $dst$$XMMRegister); - } else { - int vlen_enc = vector_length_encoding(this); - __ vpxor($dst$$XMMRegister, $dst$$XMMRegister, $dst$$XMMRegister, vlen_enc); - } + InternalAddress addr = $constantaddress(T_SHORT, vreplicate_imm(T_SHORT, $con$$constant, Matcher::vector_length(this))); + __ load_vector($dst$$XMMRegister, addr, Matcher::vector_length_in_bytes(this)); %} - ins_pipe( fpu_reg_reg ); + ins_pipe( pipe_slow ); %} // ====================ReplicateI======================================= @@ -4131,30 +4131,21 @@ instruct ReplI_imm(vec dst, immI con) %{ match(Set dst (ReplicateI con)); format %{ "replicateI $dst,$con" %} ins_encode %{ - uint vlen = Matcher::vector_length(this); - InternalAddress const_addr = $constantaddress(replicate8_imm($con$$constant, 4)); - if (vlen <= 4) { - __ movq($dst$$XMMRegister, const_addr); - if (vlen == 4) { - __ punpcklqdq($dst$$XMMRegister, $dst$$XMMRegister); - } - } else { - assert(VM_Version::supports_avx2(), "sanity"); - int vlen_enc = vector_length_encoding(this); - __ movq($dst$$XMMRegister, const_addr); - __ vpbroadcastd($dst$$XMMRegister, $dst$$XMMRegister, vlen_enc); - } + InternalAddress addr = $constantaddress(T_INT, vreplicate_imm(T_INT, $con$$constant, Matcher::vector_length(this))); + __ load_vector($dst$$XMMRegister, addr, Matcher::vector_length_in_bytes(this)); %} ins_pipe( pipe_slow ); %} -// Replicate integer (4 byte) scalar zero to be vector +// Replicate scalar zero to be vector instruct ReplI_zero(vec dst, immI_0 zero) %{ + match(Set dst (ReplicateB zero)); + match(Set dst (ReplicateS zero)); match(Set dst (ReplicateI zero)); format %{ "replicateI $dst,$zero" %} ins_encode %{ - uint vlen = Matcher::vector_length(this); - if (vlen <= 4) { + uint vsize = Matcher::vector_length_in_bytes(this); + if (vsize <= 16) { __ pxor($dst$$XMMRegister, $dst$$XMMRegister); } else { int vlen_enc = vector_length_encoding(this); @@ -4285,17 +4276,8 @@ instruct ReplL_imm(vec dst, immL con) %{ match(Set dst (ReplicateL con)); format %{ "replicateL $dst,$con" %} ins_encode %{ - uint vlen = Matcher::vector_length(this); - InternalAddress const_addr = $constantaddress($con); - if (vlen == 2) { - __ movq($dst$$XMMRegister, const_addr); - __ punpcklqdq($dst$$XMMRegister, $dst$$XMMRegister); - } else { - assert(VM_Version::supports_avx2(), "sanity"); - int vlen_enc = vector_length_encoding(this); - __ movq($dst$$XMMRegister, const_addr); - __ vpbroadcastq($dst$$XMMRegister, $dst$$XMMRegister, vlen_enc); - } + InternalAddress addr = $constantaddress(T_LONG, vreplicate_imm(T_LONG, $con$$constant, Matcher::vector_length(this))); + __ load_vector($dst$$XMMRegister, addr, Matcher::vector_length_in_bytes(this)); %} ins_pipe( pipe_slow ); %} @@ -4365,6 +4347,17 @@ instruct ReplF_mem(vec dst, memory mem) %{ ins_pipe( pipe_slow ); %} +// Replicate float scalar immediate to be vector by loading from const table. +instruct ReplF_imm(vec dst, immF con) %{ + match(Set dst (ReplicateF con)); + format %{ "replicateF $dst,$con" %} + ins_encode %{ + InternalAddress addr = $constantaddress(T_FLOAT, vreplicate_imm(T_FLOAT, $con$$constant, Matcher::vector_length(this))); + __ load_vector($dst$$XMMRegister, addr, Matcher::vector_length_in_bytes(this)); + %} + ins_pipe( pipe_slow ); +%} + instruct ReplF_zero(vec dst, immF0 zero) %{ match(Set dst (ReplicateF zero)); format %{ "replicateF $dst,$zero" %} @@ -4419,6 +4412,17 @@ instruct ReplD_mem(vec dst, memory mem) %{ ins_pipe( pipe_slow ); %} +// Replicate double (8 byte) scalar immediate to be vector by loading from const table. +instruct ReplD_imm(vec dst, immD con) %{ + match(Set dst (ReplicateD con)); + format %{ "replicateD $dst,$con" %} + ins_encode %{ + InternalAddress addr = $constantaddress(T_DOUBLE, vreplicate_imm(T_DOUBLE, $con$$constant, Matcher::vector_length(this))); + __ load_vector($dst$$XMMRegister, addr, Matcher::vector_length_in_bytes(this)); + %} + ins_pipe( pipe_slow ); +%} + instruct ReplD_zero(vec dst, immD0 zero) %{ match(Set dst (ReplicateD zero)); format %{ "replicateD $dst,$zero" %} @@ -4564,7 +4568,8 @@ instruct insertF(vec dst, regF val, immU8 idx) %{ assert(Matcher::vector_element_basic_type(this) == T_FLOAT, "sanity"); assert($idx$$constant < (int)Matcher::vector_length(this), "out of bounds"); - __ insertps($dst$$XMMRegister, $val$$XMMRegister, $idx$$constant); + uint x_idx = $idx$$constant & right_n_bits(2); + __ insertps($dst$$XMMRegister, $val$$XMMRegister, x_idx << 4); %} ins_pipe( pipe_slow ); %} @@ -4584,13 +4589,13 @@ instruct vinsertF(vec dst, vec src, regF val, immU8 idx, vec vtmp) %{ uint y_idx = ($idx$$constant >> 2) & 1; int vlen_enc = Assembler::AVX_256bit; __ vextracti128($vtmp$$XMMRegister, $src$$XMMRegister, y_idx); - __ vinsertps($vtmp$$XMMRegister, $vtmp$$XMMRegister, $val$$XMMRegister, x_idx); + __ vinsertps($vtmp$$XMMRegister, $vtmp$$XMMRegister, $val$$XMMRegister, x_idx << 4); __ vinserti128($dst$$XMMRegister, $src$$XMMRegister, $vtmp$$XMMRegister, y_idx); } else { assert(vlen == 16, "sanity"); uint y_idx = ($idx$$constant >> 2) & 3; __ vextracti32x4($vtmp$$XMMRegister, $src$$XMMRegister, y_idx); - __ vinsertps($vtmp$$XMMRegister, $vtmp$$XMMRegister, $val$$XMMRegister, x_idx); + __ vinsertps($vtmp$$XMMRegister, $vtmp$$XMMRegister, $val$$XMMRegister, x_idx << 4); __ vinserti32x4($dst$$XMMRegister, $src$$XMMRegister, $vtmp$$XMMRegister, y_idx); } %} @@ -6196,7 +6201,7 @@ instruct vshiftcnt(vec dst, rRegI cnt) %{ // Byte vector shift instruct vshiftB(vec dst, vec src, vec shift, vec tmp, rRegI scratch) %{ - predicate(Matcher::vector_length(n) <= 8 && VectorNode::is_vshift_cnt(n->in(2))); + predicate(Matcher::vector_length(n) <= 8 && !n->as_ShiftV()->is_var_shift()); match(Set dst ( LShiftVB src shift)); match(Set dst ( RShiftVB src shift)); match(Set dst (URShiftVB src shift)); @@ -6216,7 +6221,7 @@ instruct vshiftB(vec dst, vec src, vec shift, vec tmp, rRegI scratch) %{ %} instruct vshift16B(vec dst, vec src, vec shift, vec tmp1, vec tmp2, rRegI scratch) %{ - predicate(Matcher::vector_length(n) == 16 && VectorNode::is_vshift_cnt(n->in(2)) && + predicate(Matcher::vector_length(n) == 16 && !n->as_ShiftV()->is_var_shift() && UseAVX <= 1); match(Set dst ( LShiftVB src shift)); match(Set dst ( RShiftVB src shift)); @@ -6241,7 +6246,7 @@ instruct vshift16B(vec dst, vec src, vec shift, vec tmp1, vec tmp2, rRegI scratc %} instruct vshift16B_avx(vec dst, vec src, vec shift, vec tmp, rRegI scratch) %{ - predicate(Matcher::vector_length(n) == 16 && VectorNode::is_vshift_cnt(n->in(2)) && + predicate(Matcher::vector_length(n) == 16 && !n->as_ShiftV()->is_var_shift() && UseAVX > 1); match(Set dst ( LShiftVB src shift)); match(Set dst ( RShiftVB src shift)); @@ -6262,7 +6267,7 @@ instruct vshift16B_avx(vec dst, vec src, vec shift, vec tmp, rRegI scratch) %{ %} instruct vshift32B_avx(vec dst, vec src, vec shift, vec tmp, rRegI scratch) %{ - predicate(Matcher::vector_length(n) == 32 && VectorNode::is_vshift_cnt(n->in(2))); + predicate(Matcher::vector_length(n) == 32 && !n->as_ShiftV()->is_var_shift()); match(Set dst ( LShiftVB src shift)); match(Set dst ( RShiftVB src shift)); match(Set dst (URShiftVB src shift)); @@ -6287,7 +6292,7 @@ instruct vshift32B_avx(vec dst, vec src, vec shift, vec tmp, rRegI scratch) %{ %} instruct vshift64B_avx(vec dst, vec src, vec shift, vec tmp1, vec tmp2, rRegI scratch) %{ - predicate(Matcher::vector_length(n) == 64 && VectorNode::is_vshift_cnt(n->in(2))); + predicate(Matcher::vector_length(n) == 64 && !n->as_ShiftV()->is_var_shift()); match(Set dst ( LShiftVB src shift)); match(Set dst (RShiftVB src shift)); match(Set dst (URShiftVB src shift)); @@ -6320,7 +6325,7 @@ instruct vshift64B_avx(vec dst, vec src, vec shift, vec tmp1, vec tmp2, rRegI sc // unsigned values. // Shorts/Chars vector left shift instruct vshiftS(vec dst, vec src, vec shift) %{ - predicate(VectorNode::is_vshift_cnt(n->in(2))); + predicate(!n->as_ShiftV()->is_var_shift()); match(Set dst ( LShiftVS src shift)); match(Set dst ( RShiftVS src shift)); match(Set dst (URShiftVS src shift)); @@ -6351,7 +6356,7 @@ instruct vshiftS(vec dst, vec src, vec shift) %{ // Integers vector left shift instruct vshiftI(vec dst, vec src, vec shift) %{ - predicate(VectorNode::is_vshift_cnt(n->in(2))); + predicate(!n->as_ShiftV()->is_var_shift()); match(Set dst ( LShiftVI src shift)); match(Set dst ( RShiftVI src shift)); match(Set dst (URShiftVI src shift)); @@ -6405,7 +6410,7 @@ instruct vshiftI_imm(vec dst, vec src, immI8 shift) %{ // Longs vector shift instruct vshiftL(vec dst, vec src, vec shift) %{ - predicate(VectorNode::is_vshift_cnt(n->in(2))); + predicate(!n->as_ShiftV()->is_var_shift()); match(Set dst ( LShiftVL src shift)); match(Set dst (URShiftVL src shift)); effect(TEMP dst, USE src, USE shift); @@ -6446,7 +6451,7 @@ instruct vshiftL_imm(vec dst, vec src, immI8 shift) %{ // -------------------ArithmeticRightShift ----------------------------------- // Long vector arithmetic right shift instruct vshiftL_arith_reg(vec dst, vec src, vec shift, vec tmp, rRegI scratch) %{ - predicate(VectorNode::is_vshift_cnt(n->in(2)) && UseAVX <= 2); + predicate(!n->as_ShiftV()->is_var_shift() && UseAVX <= 2); match(Set dst (RShiftVL src shift)); effect(TEMP dst, TEMP tmp, TEMP scratch); format %{ "vshiftq $dst,$src,$shift" %} @@ -6475,7 +6480,7 @@ instruct vshiftL_arith_reg(vec dst, vec src, vec shift, vec tmp, rRegI scratch) %} instruct vshiftL_arith_reg_evex(vec dst, vec src, vec shift) %{ - predicate(VectorNode::is_vshift_cnt(n->in(2)) && UseAVX > 2); + predicate(!n->as_ShiftV()->is_var_shift() && UseAVX > 2); match(Set dst (RShiftVL src shift)); format %{ "vshiftq $dst,$src,$shift" %} ins_encode %{ @@ -6489,7 +6494,7 @@ instruct vshiftL_arith_reg_evex(vec dst, vec src, vec shift) %{ // Byte variable shift instruct vshift8B_var_nobw(vec dst, vec src, vec shift, vec vtmp, rRegP scratch) %{ predicate(Matcher::vector_length(n) <= 8 && - !VectorNode::is_vshift_cnt(n->in(2)) && + n->as_ShiftV()->is_var_shift() && !VM_Version::supports_avx512bw()); match(Set dst ( LShiftVB src shift)); match(Set dst ( RShiftVB src shift)); @@ -6509,7 +6514,7 @@ instruct vshift8B_var_nobw(vec dst, vec src, vec shift, vec vtmp, rRegP scratch) instruct vshift16B_var_nobw(vec dst, vec src, vec shift, vec vtmp1, vec vtmp2, rRegP scratch) %{ predicate(Matcher::vector_length(n) == 16 && - !VectorNode::is_vshift_cnt(n->in(2)) && + n->as_ShiftV()->is_var_shift() && !VM_Version::supports_avx512bw()); match(Set dst ( LShiftVB src shift)); match(Set dst ( RShiftVB src shift)); @@ -6537,7 +6542,7 @@ instruct vshift16B_var_nobw(vec dst, vec src, vec shift, vec vtmp1, vec vtmp2, r instruct vshift32B_var_nobw(vec dst, vec src, vec shift, vec vtmp1, vec vtmp2, vec vtmp3, vec vtmp4, rRegP scratch) %{ predicate(Matcher::vector_length(n) == 32 && - !VectorNode::is_vshift_cnt(n->in(2)) && + n->as_ShiftV()->is_var_shift() && !VM_Version::supports_avx512bw()); match(Set dst ( LShiftVB src shift)); match(Set dst ( RShiftVB src shift)); @@ -6573,7 +6578,7 @@ instruct vshift32B_var_nobw(vec dst, vec src, vec shift, vec vtmp1, vec vtmp2, v instruct vshiftB_var_evex_bw(vec dst, vec src, vec shift, vec vtmp, rRegP scratch) %{ predicate(Matcher::vector_length(n) <= 32 && - !VectorNode::is_vshift_cnt(n->in(2)) && + n->as_ShiftV()->is_var_shift() && VM_Version::supports_avx512bw()); match(Set dst ( LShiftVB src shift)); match(Set dst ( RShiftVB src shift)); @@ -6592,7 +6597,7 @@ instruct vshiftB_var_evex_bw(vec dst, vec src, vec shift, vec vtmp, rRegP scratc instruct vshift64B_var_evex_bw(vec dst, vec src, vec shift, vec vtmp1, vec vtmp2, rRegP scratch) %{ predicate(Matcher::vector_length(n) == 64 && - !VectorNode::is_vshift_cnt(n->in(2)) && + n->as_ShiftV()->is_var_shift() && VM_Version::supports_avx512bw()); match(Set dst ( LShiftVB src shift)); match(Set dst ( RShiftVB src shift)); @@ -6616,7 +6621,7 @@ instruct vshift64B_var_evex_bw(vec dst, vec src, vec shift, vec vtmp1, vec vtmp2 // Short variable shift instruct vshift8S_var_nobw(vec dst, vec src, vec shift, vec vtmp, rRegP scratch) %{ predicate(Matcher::vector_length(n) <= 8 && - !VectorNode::is_vshift_cnt(n->in(2)) && + n->as_ShiftV()->is_var_shift() && !VM_Version::supports_avx512bw()); match(Set dst ( LShiftVS src shift)); match(Set dst ( RShiftVS src shift)); @@ -6641,7 +6646,7 @@ instruct vshift8S_var_nobw(vec dst, vec src, vec shift, vec vtmp, rRegP scratch) instruct vshift16S_var_nobw(vec dst, vec src, vec shift, vec vtmp1, vec vtmp2, rRegP scratch) %{ predicate(Matcher::vector_length(n) == 16 && - !VectorNode::is_vshift_cnt(n->in(2)) && + n->as_ShiftV()->is_var_shift() && !VM_Version::supports_avx512bw()); match(Set dst ( LShiftVS src shift)); match(Set dst ( RShiftVS src shift)); @@ -6676,7 +6681,7 @@ instruct vshift16S_var_nobw(vec dst, vec src, vec shift, vec vtmp1, vec vtmp2, r %} instruct vshift16S_var_evex_bw(vec dst, vec src, vec shift) %{ - predicate(!VectorNode::is_vshift_cnt(n->in(2)) && + predicate(n->as_ShiftV()->is_var_shift() && VM_Version::supports_avx512bw()); match(Set dst ( LShiftVS src shift)); match(Set dst ( RShiftVS src shift)); @@ -6697,7 +6702,7 @@ instruct vshift16S_var_evex_bw(vec dst, vec src, vec shift) %{ //Integer variable shift instruct vshiftI_var(vec dst, vec src, vec shift) %{ - predicate(!VectorNode::is_vshift_cnt(n->in(2))); + predicate(n->as_ShiftV()->is_var_shift()); match(Set dst ( LShiftVI src shift)); match(Set dst ( RShiftVI src shift)); match(Set dst (URShiftVI src shift)); @@ -6714,7 +6719,7 @@ instruct vshiftI_var(vec dst, vec src, vec shift) %{ //Long variable shift instruct vshiftL_var(vec dst, vec src, vec shift) %{ - predicate(!VectorNode::is_vshift_cnt(n->in(2))); + predicate(n->as_ShiftV()->is_var_shift()); match(Set dst ( LShiftVL src shift)); match(Set dst (URShiftVL src shift)); format %{ "vector_varshift_long $dst,$src,$shift\t!" %} @@ -6731,7 +6736,7 @@ instruct vshiftL_var(vec dst, vec src, vec shift) %{ //Long variable right shift arithmetic instruct vshiftL_arith_var(vec dst, vec src, vec shift, vec vtmp) %{ predicate(Matcher::vector_length(n) <= 4 && - !VectorNode::is_vshift_cnt(n->in(2)) && + n->as_ShiftV()->is_var_shift() && UseAVX == 2); match(Set dst (RShiftVL src shift)); effect(TEMP dst, TEMP vtmp); @@ -6746,7 +6751,7 @@ instruct vshiftL_arith_var(vec dst, vec src, vec shift, vec vtmp) %{ %} instruct vshiftL_arith_var_evex(vec dst, vec src, vec shift) %{ - predicate(!VectorNode::is_vshift_cnt(n->in(2)) && + predicate(n->as_ShiftV()->is_var_shift() && UseAVX > 2); match(Set dst (RShiftVL src shift)); format %{ "vector_varfshift_long $dst,$src,$shift\t!" %} @@ -6887,11 +6892,12 @@ instruct vcastBtoX(vec dst, vec src) %{ case T_LONG: __ vpmovsxbq($dst$$XMMRegister, $src$$XMMRegister, vlen_enc); break; - case T_DOUBLE: - __ vpmovsxbd($dst$$XMMRegister, $src$$XMMRegister, vlen_enc); + case T_DOUBLE: { + int mid_vlen_enc = (vlen_enc == Assembler::AVX_512bit) ? Assembler::AVX_256bit : Assembler::AVX_128bit; + __ vpmovsxbd($dst$$XMMRegister, $src$$XMMRegister, mid_vlen_enc); __ vcvtdq2pd($dst$$XMMRegister, $dst$$XMMRegister, vlen_enc); break; - + } default: assert(false, "%s", type2name(to_elem_bt)); } %} @@ -6958,10 +6964,12 @@ instruct vcastStoX_evex(vec dst, vec src) %{ case T_LONG: __ vpmovsxwq($dst$$XMMRegister, $src$$XMMRegister, vlen_enc); break; - case T_DOUBLE: - __ vpmovsxwd($dst$$XMMRegister, $src$$XMMRegister, vlen_enc); + case T_DOUBLE: { + int mid_vlen_enc = (vlen_enc == Assembler::AVX_512bit) ? Assembler::AVX_256bit : Assembler::AVX_128bit; + __ vpmovsxwd($dst$$XMMRegister, $src$$XMMRegister, mid_vlen_enc); __ vcvtdq2pd($dst$$XMMRegister, $dst$$XMMRegister, vlen_enc); break; + } default: ShouldNotReachHere(); } @@ -7157,7 +7165,7 @@ instruct vcastLtoX_evex(vec dst, vec src) %{ instruct vcastFtoD_reg(vec dst, vec src) %{ predicate(Matcher::vector_element_basic_type(n) == T_DOUBLE); match(Set dst (VectorCastF2X src)); - format %{ "vector_cast_f2x $dst,$src\t!" %} + format %{ "vector_cast_f2d $dst,$src\t!" %} ins_encode %{ int vlen_enc = vector_length_encoding(this); __ vcvtps2pd($dst$$XMMRegister, $src$$XMMRegister, vlen_enc); @@ -7165,6 +7173,38 @@ instruct vcastFtoD_reg(vec dst, vec src) %{ ins_pipe( pipe_slow ); %} +instruct vcastFtoI_reg_avx(vec dst, vec src, vec xtmp1, vec xtmp2, vec xtmp3, vec xtmp4, rRegP scratch, rFlagsReg cr) %{ + predicate(!VM_Version::supports_avx512vl() && + Matcher::vector_length_in_bytes(n) < 64 && + Matcher::vector_element_basic_type(n) == T_INT); + match(Set dst (VectorCastF2X src)); + effect(TEMP dst, TEMP xtmp1, TEMP xtmp2, TEMP xtmp3, TEMP xtmp4, TEMP scratch, KILL cr); + format %{ "vector_cast_f2i $dst,$src\t! using $xtmp1, $xtmp2, $xtmp3 and $xtmp4 as TEMP" %} + ins_encode %{ + int vlen_enc = vector_length_encoding(this); + __ vector_castF2I_avx($dst$$XMMRegister, $src$$XMMRegister, $xtmp1$$XMMRegister, + $xtmp2$$XMMRegister, $xtmp3$$XMMRegister, $xtmp4$$XMMRegister, + ExternalAddress(vector_float_signflip()), $scratch$$Register, vlen_enc); + %} + ins_pipe( pipe_slow ); +%} + +instruct vcastFtoI_reg_evex(vec dst, vec src, vec xtmp1, vec xtmp2, kReg ktmp1, kReg ktmp2, rRegP scratch, rFlagsReg cr) %{ + predicate((VM_Version::supports_avx512vl() || + Matcher::vector_length_in_bytes(n) == 64) && + Matcher::vector_element_basic_type(n) == T_INT); + match(Set dst (VectorCastF2X src)); + effect(TEMP dst, TEMP xtmp1, TEMP xtmp2, TEMP ktmp1, TEMP ktmp2, TEMP scratch, KILL cr); + format %{ "vector_cast_f2i $dst,$src\t! using $xtmp1, $xtmp2, $ktmp1 and $ktmp2 as TEMP" %} + ins_encode %{ + int vlen_enc = vector_length_encoding(this); + __ vector_castF2I_evex($dst$$XMMRegister, $src$$XMMRegister, $xtmp1$$XMMRegister, + $xtmp2$$XMMRegister, $ktmp1$$KRegister, $ktmp2$$KRegister, + ExternalAddress(vector_float_signflip()), $scratch$$Register, vlen_enc); + %} + ins_pipe( pipe_slow ); +%} + instruct vcastDtoF_reg(vec dst, vec src) %{ predicate(Matcher::vector_element_basic_type(n) == T_FLOAT); match(Set dst (VectorCastD2X src)); @@ -7176,6 +7216,36 @@ instruct vcastDtoF_reg(vec dst, vec src) %{ ins_pipe( pipe_slow ); %} +instruct vcastDtoL_reg_evex(vec dst, vec src, vec xtmp1, vec xtmp2, kReg ktmp1, kReg ktmp2, rRegP scratch, rFlagsReg cr) %{ + predicate(Matcher::vector_element_basic_type(n) == T_LONG); + match(Set dst (VectorCastD2X src)); + effect(TEMP dst, TEMP xtmp1, TEMP xtmp2, TEMP ktmp1, TEMP ktmp2, TEMP scratch, KILL cr); + format %{ "vector_cast_d2l $dst,$src\t! using $xtmp1, $xtmp2, $ktmp1 and $ktmp2 as TEMP" %} + ins_encode %{ + int vlen_enc = vector_length_encoding(this); + __ vector_castD2L_evex($dst$$XMMRegister, $src$$XMMRegister, $xtmp1$$XMMRegister, + $xtmp2$$XMMRegister, $ktmp1$$KRegister, $ktmp2$$KRegister, + ExternalAddress(vector_double_signflip()), $scratch$$Register, vlen_enc); + %} + ins_pipe( pipe_slow ); +%} + +instruct vucast(vec dst, vec src) %{ + match(Set dst (VectorUCastB2X src)); + match(Set dst (VectorUCastS2X src)); + match(Set dst (VectorUCastI2X src)); + format %{ "vector_ucast $dst,$src\t!" %} + ins_encode %{ + assert(UseAVX > 0, "required"); + + BasicType from_elem_bt = Matcher::vector_element_basic_type(this, $src); + BasicType to_elem_bt = Matcher::vector_element_basic_type(this); + int vlen_enc = vector_length_encoding(this); + __ vector_unsigned_cast($dst$$XMMRegister, $src$$XMMRegister, vlen_enc, from_elem_bt, to_elem_bt); + %} + ins_pipe( pipe_slow ); +%} + // --------------------------------- VectorMaskCmp -------------------------------------- instruct vcmpFD(legVec dst, legVec src1, legVec src2, immI8 cond) %{ @@ -7238,62 +7308,75 @@ instruct evcmpFD(kReg dst, vec src1, vec src2, immI8 cond) %{ ins_pipe( pipe_slow ); %} -instruct vcmp(legVec dst, legVec src1, legVec src2, immI8 cond, rRegP scratch) %{ +instruct vcmp_direct(legVec dst, legVec src1, legVec src2, immI8 cond) %{ predicate(n->bottom_type()->isa_vectmask() == NULL && !is_unsigned_booltest_pred(n->in(2)->get_int()) && Matcher::vector_length_in_bytes(n->in(1)->in(1)) >= 4 && // src1 Matcher::vector_length_in_bytes(n->in(1)->in(1)) <= 32 && // src1 - is_integral_type(Matcher::vector_element_basic_type(n->in(1)->in(1)))); // src1 + is_integral_type(Matcher::vector_element_basic_type(n->in(1)->in(1))) && + (n->in(2)->get_int() == BoolTest::eq || + n->in(2)->get_int() == BoolTest::lt || + n->in(2)->get_int() == BoolTest::gt)); // cond match(Set dst (VectorMaskCmp (Binary src1 src2) cond)); - effect(TEMP scratch); - format %{ "vector_compare $dst,$src1,$src2,$cond\t! using $scratch as TEMP" %} + format %{ "vector_compare $dst,$src1,$src2,$cond\t!" %} ins_encode %{ int vlen_enc = vector_length_encoding(this, $src1); Assembler::ComparisonPredicate cmp = booltest_pred_to_comparison_pred($cond$$constant); Assembler::Width ww = widthForType(Matcher::vector_element_basic_type(this, $src1)); - __ vpcmpCCW($dst$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister, cmp, ww, vlen_enc, $scratch$$Register); + __ vpcmpCCW($dst$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister, xnoreg, cmp, ww, vlen_enc); %} ins_pipe( pipe_slow ); %} -instruct vcmpu(legVec dst, legVec src1, legVec src2, immI8 cond, legVec vtmp1, legVec vtmp2, rRegP scratch) %{ +instruct vcmp_negate(legVec dst, legVec src1, legVec src2, immI8 cond, legVec xtmp) %{ predicate(n->bottom_type()->isa_vectmask() == NULL && - is_unsigned_booltest_pred(n->in(2)->get_int()) && - Matcher::vector_length_in_bytes(n->in(1)->in(1)) >= 8 && // src1 - Matcher::vector_length_in_bytes(n->in(1)->in(1)) <= 16 && // src1 - is_integral_type(Matcher::vector_element_basic_type(n->in(1)->in(1)))); // src1 + !is_unsigned_booltest_pred(n->in(2)->get_int()) && + Matcher::vector_length_in_bytes(n->in(1)->in(1)) >= 4 && // src1 + Matcher::vector_length_in_bytes(n->in(1)->in(1)) <= 32 && // src1 + is_integral_type(Matcher::vector_element_basic_type(n->in(1)->in(1))) && + (n->in(2)->get_int() == BoolTest::ne || + n->in(2)->get_int() == BoolTest::le || + n->in(2)->get_int() == BoolTest::ge)); // cond match(Set dst (VectorMaskCmp (Binary src1 src2) cond)); - effect(TEMP vtmp1, TEMP vtmp2, TEMP scratch); - format %{ "vector_compareu $dst,$src1,$src2,$cond\t! using $scratch as TEMP" %} + effect(TEMP dst, TEMP xtmp); + format %{ "vector_compare $dst,$src1,$src2,$cond\t! using $xtmp as TEMP" %} ins_encode %{ - int vlen = Matcher::vector_length_in_bytes(this, $src1); + int vlen_enc = vector_length_encoding(this, $src1); Assembler::ComparisonPredicate cmp = booltest_pred_to_comparison_pred($cond$$constant); - BasicType bt = Matcher::vector_element_basic_type(this, $src1); - __ vpcmpu(bt, $dst$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister, cmp, vlen, $vtmp1$$XMMRegister, - $vtmp2$$XMMRegister, $scratch$$Register); + Assembler::Width ww = widthForType(Matcher::vector_element_basic_type(this, $src1)); + __ vpcmpCCW($dst$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister, $xtmp$$XMMRegister, cmp, ww, vlen_enc); %} ins_pipe( pipe_slow ); %} -instruct vcmpu32(legVec dst, legVec src1, legVec src2, immI8 cond, legVec vtmp1, legVec vtmp2, legVec vtmp3, rRegP scratch) %{ +instruct vcmpu(legVec dst, legVec src1, legVec src2, immI8 cond, legVec xtmp) %{ predicate(n->bottom_type()->isa_vectmask() == NULL && is_unsigned_booltest_pred(n->in(2)->get_int()) && - Matcher::vector_length_in_bytes(n->in(1)->in(1)) == 32 && // src1 + Matcher::vector_length_in_bytes(n->in(1)->in(1)) >= 4 && // src1 + Matcher::vector_length_in_bytes(n->in(1)->in(1)) <= 32 && // src1 is_integral_type(Matcher::vector_element_basic_type(n->in(1)->in(1)))); // src1 match(Set dst (VectorMaskCmp (Binary src1 src2) cond)); - effect(TEMP dst, TEMP vtmp1, TEMP vtmp2, TEMP vtmp3, TEMP scratch); - format %{ "vector_compareu $dst,$src1,$src2,$cond\t! using $scratch as TEMP" %} + effect(TEMP dst, TEMP xtmp); + format %{ "vector_compareu $dst,$src1,$src2,$cond\t! using $xtmp as TEMP" %} ins_encode %{ - int vlen = Matcher::vector_length_in_bytes(this, $src1); + InternalAddress flip_bit = $constantaddress(high_bit_set(Matcher::vector_element_basic_type(this, $src1))); + int vlen_enc = vector_length_encoding(this, $src1); Assembler::ComparisonPredicate cmp = booltest_pred_to_comparison_pred($cond$$constant); - BasicType bt = Matcher::vector_element_basic_type(this, $src1); - __ vpcmpu32(bt, $dst$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister, cmp, vlen, $vtmp1$$XMMRegister, - $vtmp2$$XMMRegister, $vtmp3$$XMMRegister, $scratch$$Register); + Assembler::Width ww = widthForType(Matcher::vector_element_basic_type(this, $src1)); + + if (vlen_enc == Assembler::AVX_128bit) { + __ vmovddup($xtmp$$XMMRegister, flip_bit, vlen_enc, noreg); + } else { + __ vbroadcastsd($xtmp$$XMMRegister, flip_bit, vlen_enc, noreg); + } + __ vpxor($dst$$XMMRegister, $xtmp$$XMMRegister, $src1$$XMMRegister, vlen_enc); + __ vpxor($xtmp$$XMMRegister, $xtmp$$XMMRegister, $src2$$XMMRegister, vlen_enc); + __ vpcmpCCW($dst$$XMMRegister, $dst$$XMMRegister, $xtmp$$XMMRegister, $xtmp$$XMMRegister, cmp, ww, vlen_enc); %} ins_pipe( pipe_slow ); %} -instruct vcmpu64(vec dst, vec src1, vec src2, immI8 cond, rRegP scratch, kReg ktmp) %{ +instruct vcmp64(vec dst, vec src1, vec src2, immI8 cond, rRegP scratch, kReg ktmp) %{ predicate((n->bottom_type()->isa_vectmask() == NULL && Matcher::vector_length_in_bytes(n->in(1)->in(1)) == 64) && // src1 is_integral_type(Matcher::vector_element_basic_type(n->in(1)->in(1)))); // src1 @@ -8504,14 +8587,54 @@ instruct vmuladdaddS2I_reg(vec dst, vec src1, vec src2) %{ // --------------------------------- PopCount -------------------------------------- -instruct vpopcountI(vec dst, vec src) %{ +instruct vpopcountI_popcntd(vec dst, vec src) %{ + predicate(VM_Version::supports_avx512_vpopcntdq()); match(Set dst (PopCountVI src)); - format %{ "vpopcntd $dst,$src\t! vector popcount packedI" %} + format %{ "vector_popcount_int $dst, $src\t! vector popcount packedI" %} ins_encode %{ assert(UsePopCountInstruction, "not enabled"); + int vlen_enc = vector_length_encoding(this); + __ vector_popcount_int($dst$$XMMRegister, $src$$XMMRegister, xnoreg, xnoreg, xnoreg, noreg, vlen_enc); + %} + ins_pipe( pipe_slow ); +%} +instruct vpopcountI(vec dst, vec src, vec xtmp1, vec xtmp2, vec xtmp3, rRegP rtmp, rFlagsReg cc) %{ + predicate(!VM_Version::supports_avx512_vpopcntdq()); + match(Set dst (PopCountVI src)); + effect(TEMP dst, TEMP xtmp1, TEMP xtmp2, TEMP xtmp3, TEMP rtmp, KILL cc); + format %{ "vector_popcount_int $dst, $src\t! using $xtmp1, $xtmp2, $xtmp3, and $rtmp as TEMP" %} + ins_encode %{ + assert(UsePopCountInstruction, "not enabled"); int vlen_enc = vector_length_encoding(this); - __ vpopcntd($dst$$XMMRegister, $src$$XMMRegister, vlen_enc); + __ vector_popcount_int($dst$$XMMRegister, $src$$XMMRegister, $xtmp1$$XMMRegister, $xtmp2$$XMMRegister, + $xtmp3$$XMMRegister, $rtmp$$Register, vlen_enc); + %} + ins_pipe( pipe_slow ); +%} + +instruct vpopcountL_popcntd(vec dst, vec src) %{ + predicate(VM_Version::supports_avx512_vpopcntdq()); + match(Set dst (PopCountVL src)); + format %{ "vector_popcount_long $dst, $src\t! vector popcount packedL" %} + ins_encode %{ + assert(UsePopCountInstruction, "not enabled"); + int vlen_enc = vector_length_encoding(this, $src); + __ vector_popcount_long($dst$$XMMRegister, $src$$XMMRegister, xnoreg, xnoreg, xnoreg, noreg, vlen_enc); + %} + ins_pipe( pipe_slow ); +%} + +instruct vpopcountL(vec dst, vec src, vec xtmp1, vec xtmp2, vec xtmp3, rRegP rtmp, rFlagsReg cc) %{ + predicate(!VM_Version::supports_avx512_vpopcntdq()); + match(Set dst (PopCountVL src)); + effect(TEMP dst, TEMP xtmp1, TEMP xtmp2, TEMP xtmp3, TEMP rtmp, KILL cc); + format %{ "vector_popcount_long $dst, $src\t! using $xtmp1, $xtmp2, $xtmp3, and $rtmp as TEMP" %} + ins_encode %{ + assert(UsePopCountInstruction, "not enabled"); + int vlen_enc = vector_length_encoding(this, $src); + __ vector_popcount_long($dst$$XMMRegister, $src$$XMMRegister, $xtmp1$$XMMRegister, $xtmp2$$XMMRegister, + $xtmp3$$XMMRegister, $rtmp$$Register, vlen_enc); %} ins_pipe( pipe_slow ); %} @@ -8647,43 +8770,45 @@ instruct vmask_tolong_evex(rRegL dst, kReg mask, rFlagsReg cr) %{ effect(TEMP dst, KILL cr); format %{ "vector_tolong_evex $dst, $mask \t! vector mask tolong" %} ins_encode %{ - int mask_len = Matcher::vector_length(this, $mask); + int opcode = this->ideal_Opcode(); BasicType mbt = Matcher::vector_element_basic_type(this, $mask); - if (VM_Version::supports_avx512vlbw()) { - __ kmovql($dst$$Register, $mask$$KRegister); - } else { - assert(mask_len <= 16, ""); - __ kmovwl($dst$$Register, $mask$$KRegister); - } - // Mask generated out of partial vector comparisons/replicate/mask manipulation - // operations needs to be clipped. + int mask_len = Matcher::vector_length(this, $mask); int mask_size = mask_len * type2aelembytes(mbt); - if (mask_size < 16) { - __ andq($dst$$Register, (((jlong)1 << mask_len) - 1)); - } + int vlen_enc = vector_length_encoding(this, $mask); + __ vector_mask_operation(opcode, $dst$$Register, $mask$$KRegister, + $dst$$Register, mask_len, mask_size, vlen_enc); %} ins_pipe( pipe_slow ); %} -instruct vmask_tolong_avx(rRegL dst, vec mask, vec xtmp, rFlagsReg cr) %{ - predicate(n->in(1)->bottom_type()->isa_vectmask() == NULL && - n->in(1)->bottom_type()->is_vect()->element_basic_type() == T_BOOLEAN); +instruct vmask_tolong_bool(rRegL dst, vec mask, vec xtmp, rFlagsReg cr) %{ + predicate(n->in(1)->bottom_type()->isa_vectmask() == NULL); match(Set dst (VectorMaskToLong mask)); - format %{ "vector_tolong_avx $dst, $mask \t! using $xtmp as TEMP" %} + format %{ "vector_tolong_bool $dst, $mask \t! using $xtmp as TEMP" %} effect(TEMP_DEF dst, TEMP xtmp, KILL cr); ins_encode %{ + int opcode = this->ideal_Opcode(); + BasicType mbt = Matcher::vector_element_basic_type(this, $mask); int mask_len = Matcher::vector_length(this, $mask); + int vlen_enc = vector_length_encoding(this, $mask); + __ vector_mask_operation(opcode, $dst$$Register, $mask$$XMMRegister, $xtmp$$XMMRegister, + $dst$$Register, mask_len, mbt, vlen_enc); + %} + ins_pipe( pipe_slow ); +%} + +instruct vmask_tolong_avx(rRegL dst, vec mask, immI size, vec xtmp, rFlagsReg cr) %{ + predicate(n->in(1)->in(1)->bottom_type()->isa_vectmask() == NULL); + match(Set dst (VectorMaskToLong (VectorStoreMask mask size))); + format %{ "vector_tolong_avx $dst, $mask \t! using $xtmp as TEMP" %} + effect(TEMP_DEF dst, TEMP xtmp, KILL cr); + ins_encode %{ + int opcode = this->ideal_Opcode(); BasicType mbt = Matcher::vector_element_basic_type(this, $mask); + int mask_len = Matcher::vector_length(this, $mask); int vlen_enc = vector_length_encoding(this, $mask); - __ vpxor($xtmp$$XMMRegister, $xtmp$$XMMRegister, $xtmp$$XMMRegister, vlen_enc); - __ vpsubb($xtmp$$XMMRegister, $xtmp$$XMMRegister, $mask$$XMMRegister, vlen_enc); - __ vpmovmskb($dst$$Register, $xtmp$$XMMRegister, vlen_enc); - // Mask generated out of partial vector comparisons/replicate/mask manipulation - // operations needs to be clipped. - int mask_size = mask_len * type2aelembytes(mbt); - if (mask_size < 16) { - __ andq($dst$$Register, (((jlong)1 << mask_len) - 1)); - } + __ vector_mask_operation(opcode, $dst$$Register, $mask$$XMMRegister, $xtmp$$XMMRegister, + $dst$$Register, mask_len, mbt, vlen_enc); %} ins_pipe( pipe_slow ); %} @@ -8699,25 +8824,40 @@ instruct vmask_truecount_evex(rRegI dst, kReg mask, rRegL tmp, rFlagsReg cr) %{ int mask_len = Matcher::vector_length(this, $mask); int mask_size = mask_len * type2aelembytes(mbt); int vlen_enc = vector_length_encoding(this, $mask); - __ vector_mask_operation(opcode, $dst$$Register, $mask$$KRegister, $tmp$$Register, - mask_len, mask_size, vlen_enc); + __ vector_mask_operation(opcode, $dst$$Register, $mask$$KRegister, + $tmp$$Register, mask_len, mask_size, vlen_enc); %} ins_pipe( pipe_slow ); %} -instruct vmask_truecount_avx(rRegI dst, vec mask, rRegL tmp, vec xtmp, vec xtmp1, rFlagsReg cr) %{ +instruct vmask_truecount_bool(rRegI dst, vec mask, rRegL tmp, vec xtmp, rFlagsReg cr) %{ predicate(n->in(1)->bottom_type()->isa_vectmask() == NULL); match(Set dst (VectorMaskTrueCount mask)); - effect(TEMP_DEF dst, TEMP tmp, TEMP xtmp, TEMP xtmp1, KILL cr); - format %{ "vector_truecount_avx $dst, $mask \t! using $tmp, $xtmp and $xtmp1 as TEMP" %} + effect(TEMP_DEF dst, TEMP tmp, TEMP xtmp, KILL cr); + format %{ "vector_truecount_bool $dst, $mask \t! using $tmp, $xtmp as TEMP" %} + ins_encode %{ + int opcode = this->ideal_Opcode(); + BasicType mbt = Matcher::vector_element_basic_type(this, $mask); + int mask_len = Matcher::vector_length(this, $mask); + int vlen_enc = vector_length_encoding(this, $mask); + __ vector_mask_operation(opcode, $dst$$Register, $mask$$XMMRegister, $xtmp$$XMMRegister, + $tmp$$Register, mask_len, mbt, vlen_enc); + %} + ins_pipe( pipe_slow ); +%} + +instruct vmask_truecount_avx(rRegI dst, vec mask, immI size, rRegL tmp, vec xtmp, rFlagsReg cr) %{ + predicate(n->in(1)->in(1)->bottom_type()->isa_vectmask() == NULL); + match(Set dst (VectorMaskTrueCount (VectorStoreMask mask size))); + effect(TEMP_DEF dst, TEMP tmp, TEMP xtmp, KILL cr); + format %{ "vector_truecount_avx $dst, $mask \t! using $tmp, $xtmp as TEMP" %} ins_encode %{ int opcode = this->ideal_Opcode(); BasicType mbt = Matcher::vector_element_basic_type(this, $mask); int mask_len = Matcher::vector_length(this, $mask); - int mask_size = mask_len * type2aelembytes(mbt); int vlen_enc = vector_length_encoding(this, $mask); __ vector_mask_operation(opcode, $dst$$Register, $mask$$XMMRegister, $xtmp$$XMMRegister, - $xtmp1$$XMMRegister, $tmp$$Register, mask_len, mask_size, vlen_enc); + $tmp$$Register, mask_len, mbt, vlen_enc); %} ins_pipe( pipe_slow ); %} @@ -8734,26 +8874,42 @@ instruct vmask_first_or_last_true_evex(rRegI dst, kReg mask, rRegL tmp, rFlagsRe int mask_len = Matcher::vector_length(this, $mask); int mask_size = mask_len * type2aelembytes(mbt); int vlen_enc = vector_length_encoding(this, $mask); - __ vector_mask_operation(opcode, $dst$$Register, $mask$$KRegister, $tmp$$Register, mask_len, - mask_size, vlen_enc); + __ vector_mask_operation(opcode, $dst$$Register, $mask$$KRegister, + $tmp$$Register, mask_len, mask_size, vlen_enc); %} ins_pipe( pipe_slow ); %} -instruct vmask_first_or_last_true_avx(rRegI dst, vec mask, rRegL tmp, vec xtmp, vec xtmp1, rFlagsReg cr) %{ +instruct vmask_first_or_last_true_bool(rRegI dst, vec mask, rRegL tmp, vec xtmp, rFlagsReg cr) %{ predicate(n->in(1)->bottom_type()->isa_vectmask() == NULL); match(Set dst (VectorMaskFirstTrue mask)); match(Set dst (VectorMaskLastTrue mask)); - effect(TEMP_DEF dst, TEMP tmp, TEMP xtmp, TEMP xtmp1, KILL cr); - format %{ "vector_mask_first_or_last_true_avx $dst, $mask \t! using $tmp, $xtmp and $xtmp1 as TEMP" %} + effect(TEMP_DEF dst, TEMP tmp, TEMP xtmp, KILL cr); + format %{ "vector_mask_first_or_last_true_bool $dst, $mask \t! using $tmp, $xtmp as TEMP" %} + ins_encode %{ + int opcode = this->ideal_Opcode(); + BasicType mbt = Matcher::vector_element_basic_type(this, $mask); + int mask_len = Matcher::vector_length(this, $mask); + int vlen_enc = vector_length_encoding(this, $mask); + __ vector_mask_operation(opcode, $dst$$Register, $mask$$XMMRegister, $xtmp$$XMMRegister, + $tmp$$Register, mask_len, mbt, vlen_enc); + %} + ins_pipe( pipe_slow ); +%} + +instruct vmask_first_or_last_true_avx(rRegI dst, vec mask, immI size, rRegL tmp, vec xtmp, rFlagsReg cr) %{ + predicate(n->in(1)->in(1)->bottom_type()->isa_vectmask() == NULL); + match(Set dst (VectorMaskFirstTrue (VectorStoreMask mask size))); + match(Set dst (VectorMaskLastTrue (VectorStoreMask mask size))); + effect(TEMP_DEF dst, TEMP tmp, TEMP xtmp, KILL cr); + format %{ "vector_mask_first_or_last_true_avx $dst, $mask \t! using $tmp, $xtmp as TEMP" %} ins_encode %{ int opcode = this->ideal_Opcode(); BasicType mbt = Matcher::vector_element_basic_type(this, $mask); int mask_len = Matcher::vector_length(this, $mask); - int mask_size = mask_len * type2aelembytes(mbt); int vlen_enc = vector_length_encoding(this, $mask); __ vector_mask_operation(opcode, $dst$$Register, $mask$$XMMRegister, $xtmp$$XMMRegister, - $xtmp1$$XMMRegister, $tmp$$Register, mask_len, mask_size, vlen_enc); + $tmp$$Register, mask_len, mbt, vlen_enc); %} ins_pipe( pipe_slow ); %} @@ -9033,6 +9189,7 @@ instruct vlshift_imm_masked(vec dst, immI8 shift, kReg mask) %{ %} instruct vlshift_reg_masked(vec dst, vec src2, kReg mask) %{ + predicate(!n->as_ShiftV()->is_var_shift()); match(Set dst (LShiftVS (Binary dst src2) mask)); match(Set dst (LShiftVI (Binary dst src2) mask)); match(Set dst (LShiftVL (Binary dst src2) mask)); @@ -9041,9 +9198,24 @@ instruct vlshift_reg_masked(vec dst, vec src2, kReg mask) %{ int vlen_enc = vector_length_encoding(this); BasicType bt = Matcher::vector_element_basic_type(this); int opc = this->ideal_Opcode(); - bool is_varshift = !VectorNode::is_vshift_cnt_opcode(in(2)->isa_Mach()->ideal_Opcode()); __ evmasked_op(opc, bt, $mask$$KRegister, $dst$$XMMRegister, - $dst$$XMMRegister, $src2$$XMMRegister, true, vlen_enc, is_varshift); + $dst$$XMMRegister, $src2$$XMMRegister, true, vlen_enc, false); + %} + ins_pipe( pipe_slow ); +%} + +instruct vlshiftv_reg_masked(vec dst, vec src2, kReg mask) %{ + predicate(n->as_ShiftV()->is_var_shift()); + match(Set dst (LShiftVS (Binary dst src2) mask)); + match(Set dst (LShiftVI (Binary dst src2) mask)); + match(Set dst (LShiftVL (Binary dst src2) mask)); + format %{ "vplshiftv_masked $dst, $dst, $src2, $mask\t! lshift 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, true); %} ins_pipe( pipe_slow ); %} @@ -9079,6 +9251,7 @@ instruct vrshift_imm_masked(vec dst, immI8 shift, kReg mask) %{ %} instruct vrshift_reg_masked(vec dst, vec src2, kReg mask) %{ + predicate(!n->as_ShiftV()->is_var_shift()); match(Set dst (RShiftVS (Binary dst src2) mask)); match(Set dst (RShiftVI (Binary dst src2) mask)); match(Set dst (RShiftVL (Binary dst src2) mask)); @@ -9087,9 +9260,24 @@ instruct vrshift_reg_masked(vec dst, vec src2, kReg mask) %{ int vlen_enc = vector_length_encoding(this); BasicType bt = Matcher::vector_element_basic_type(this); int opc = this->ideal_Opcode(); - bool is_varshift = !VectorNode::is_vshift_cnt_opcode(in(2)->isa_Mach()->ideal_Opcode()); __ evmasked_op(opc, bt, $mask$$KRegister, $dst$$XMMRegister, - $dst$$XMMRegister, $src2$$XMMRegister, true, vlen_enc, is_varshift); + $dst$$XMMRegister, $src2$$XMMRegister, true, vlen_enc, false); + %} + ins_pipe( pipe_slow ); +%} + +instruct vrshiftv_reg_masked(vec dst, vec src2, kReg mask) %{ + predicate(n->as_ShiftV()->is_var_shift()); + match(Set dst (RShiftVS (Binary dst src2) mask)); + match(Set dst (RShiftVI (Binary dst src2) mask)); + match(Set dst (RShiftVL (Binary dst src2) mask)); + format %{ "vprshiftv_masked $dst, $dst, $src2, $mask\t! rshift 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, true); %} ins_pipe( pipe_slow ); %} @@ -9125,6 +9313,7 @@ instruct vurshift_imm_masked(vec dst, immI8 shift, kReg mask) %{ %} instruct vurshift_reg_masked(vec dst, vec src2, kReg mask) %{ + predicate(!n->as_ShiftV()->is_var_shift()); match(Set dst (URShiftVS (Binary dst src2) mask)); match(Set dst (URShiftVI (Binary dst src2) mask)); match(Set dst (URShiftVL (Binary dst src2) mask)); @@ -9133,9 +9322,24 @@ instruct vurshift_reg_masked(vec dst, vec src2, kReg mask) %{ int vlen_enc = vector_length_encoding(this); BasicType bt = Matcher::vector_element_basic_type(this); int opc = this->ideal_Opcode(); - bool is_varshift = !VectorNode::is_vshift_cnt_opcode(in(2)->isa_Mach()->ideal_Opcode()); __ evmasked_op(opc, bt, $mask$$KRegister, $dst$$XMMRegister, - $dst$$XMMRegister, $src2$$XMMRegister, true, vlen_enc, is_varshift); + $dst$$XMMRegister, $src2$$XMMRegister, true, vlen_enc, false); + %} + ins_pipe( pipe_slow ); +%} + +instruct vurshiftv_reg_masked(vec dst, vec src2, kReg mask) %{ + predicate(n->as_ShiftV()->is_var_shift()); + match(Set dst (URShiftVS (Binary dst src2) mask)); + match(Set dst (URShiftVI (Binary dst src2) mask)); + match(Set dst (URShiftVL (Binary dst src2) mask)); + format %{ "vpurshiftv_masked $dst, $dst, $src2, $mask\t! urshift 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, true); %} ins_pipe( pipe_slow ); %} @@ -9316,64 +9520,18 @@ instruct evcmp_masked(kReg dst, vec src1, vec src2, immI8 cond, kReg mask, rRegP ins_pipe( pipe_slow ); %} -#ifdef _LP64 -instruct mask_all_evexI_imm(kReg dst, immI cnt, rRegL tmp) %{ - match(Set dst (MaskAll cnt)); - effect(TEMP_DEF dst, TEMP tmp); - format %{ "mask_all_evexI $dst, $cnt \t! using $tmp as TEMP" %} - ins_encode %{ - int vec_len = Matcher::vector_length(this); - if (VM_Version::supports_avx512bw()) { - __ movq($tmp$$Register, $cnt$$constant); - __ kmovql($dst$$KRegister, $tmp$$Register); - __ kshiftrql($dst$$KRegister, $dst$$KRegister, 64 - vec_len); - } else { - assert(vec_len <= 16, ""); - __ movq($tmp$$Register, $cnt$$constant); - __ kmovwl($dst$$KRegister, $tmp$$Register); - __ kshiftrwl($dst$$KRegister, $dst$$KRegister, 16 - vec_len); - } - %} - ins_pipe( pipe_slow ); -%} - -instruct mask_all_evexI(kReg dst, rRegI src, rRegL tmp) %{ +instruct mask_all_evexI_LE32(kReg dst, rRegI src) %{ + predicate(Matcher::vector_length(n) <= 32); match(Set dst (MaskAll src)); - effect(TEMP_DEF dst, TEMP tmp); - format %{ "mask_all_evexI $dst, $src \t! using $tmp as TEMP" %} - ins_encode %{ - int vec_len = Matcher::vector_length(this); - if (VM_Version::supports_avx512bw()) { - __ movslq($tmp$$Register, $src$$Register); - __ kmovql($dst$$KRegister, $tmp$$Register); - __ kshiftrql($dst$$KRegister, $dst$$KRegister, 64 - vec_len); - } else { - assert(vec_len <= 16, ""); - __ kmovwl($dst$$KRegister, $src$$Register); - __ kshiftrwl($dst$$KRegister, $dst$$KRegister, 16 - vec_len); - } - %} - ins_pipe( pipe_slow ); -%} - -instruct mask_all_evexL(kReg dst, rRegL src) %{ - match(Set dst (MaskAll src)); - effect(TEMP_DEF dst); - format %{ "mask_all_evexL $dst, $src \t! mask all operation" %} + format %{ "mask_all_evexI_LE32 $dst, $src \t" %} ins_encode %{ - int vec_len = Matcher::vector_length(this); - if (VM_Version::supports_avx512bw()) { - __ kmovql($dst$$KRegister, $src$$Register); - __ kshiftrql($dst$$KRegister, $dst$$KRegister, 64 - vec_len); - } else { - assert(vec_len <= 16, ""); - __ kmovwl($dst$$KRegister, $src$$Register); - __ kshiftrwl($dst$$KRegister, $dst$$KRegister, 16 - vec_len); - } + int mask_len = Matcher::vector_length(this); + __ vector_maskall_operation($dst$$KRegister, $src$$Register, mask_len); %} ins_pipe( pipe_slow ); %} +#ifdef _LP64 instruct mask_not_immLT8(kReg dst, kReg src, rRegI rtmp, kReg ktmp, immI_M1 cnt) %{ predicate(Matcher::vector_length(n) < 8 && VM_Version::supports_avx512dq()); match(Set dst (XorVMask src (MaskAll cnt))); @@ -9398,6 +9556,46 @@ instruct mask_not_imm(kReg dst, kReg src, immI_M1 cnt) %{ %} ins_pipe( pipe_slow ); %} + +instruct long_to_maskLE8_avx(vec dst, rRegL src, rRegL rtmp1, rRegL rtmp2, vec xtmp) %{ + predicate(n->bottom_type()->isa_vectmask() == NULL && Matcher::vector_length(n) <= 8); + match(Set dst (VectorLongToMask src)); + effect(TEMP dst, TEMP rtmp1, TEMP rtmp2, TEMP xtmp); + format %{ "long_to_mask_avx $dst, $src\t! using $rtmp1, $rtmp2, $xtmp as TEMP" %} + ins_encode %{ + int mask_len = Matcher::vector_length(this); + int vec_enc = vector_length_encoding(mask_len); + __ vector_long_to_maskvec($dst$$XMMRegister, $src$$Register, $rtmp1$$Register, + $rtmp2$$Register, xnoreg, mask_len, vec_enc); + %} + ins_pipe( pipe_slow ); +%} + + +instruct long_to_maskGT8_avx(vec dst, rRegL src, rRegL rtmp1, rRegL rtmp2, vec xtmp1, rFlagsReg cr) %{ + predicate(n->bottom_type()->isa_vectmask() == NULL && Matcher::vector_length(n) > 8); + match(Set dst (VectorLongToMask src)); + effect(TEMP dst, TEMP rtmp1, TEMP rtmp2, TEMP xtmp1, KILL cr); + format %{ "long_to_mask_avx $dst, $src\t! using $rtmp1, $rtmp2, $xtmp1, as TEMP" %} + ins_encode %{ + int mask_len = Matcher::vector_length(this); + assert(mask_len <= 32, "invalid mask length"); + int vec_enc = vector_length_encoding(mask_len); + __ vector_long_to_maskvec($dst$$XMMRegister, $src$$Register, $rtmp1$$Register, + $rtmp2$$Register, $xtmp1$$XMMRegister, mask_len, vec_enc); + %} + ins_pipe( pipe_slow ); +%} + +instruct long_to_mask_evex(kReg dst, rRegL src) %{ + predicate(n->bottom_type()->isa_vectmask()); + match(Set dst (VectorLongToMask src)); + format %{ "long_to_mask_evex $dst, $src\t!" %} + ins_encode %{ + __ kmov($dst$$KRegister, $src$$Register); + %} + ins_pipe( pipe_slow ); +%} #endif instruct mask_opers_evex(kReg dst, kReg src1, kReg src2, kReg kscratch) %{ @@ -9417,6 +9615,30 @@ instruct mask_opers_evex(kReg dst, kReg src1, kReg src2, kReg kscratch) %{ ins_pipe( pipe_slow ); %} +instruct vternlog_reg_masked(vec dst, vec src2, vec src3, immU8 func, kReg mask) %{ + match(Set dst (MacroLogicV dst (Binary src2 (Binary src3 (Binary func mask))))); + format %{ "vternlog_masked $dst,$src2,$src3,$func,$mask\t! vternlog masked operation" %} + ins_encode %{ + int vlen_enc = vector_length_encoding(this); + BasicType bt = Matcher::vector_element_basic_type(this); + __ evpternlog($dst$$XMMRegister, $func$$constant, $mask$$KRegister, + $src2$$XMMRegister, $src3$$XMMRegister, true, bt, vlen_enc); + %} + ins_pipe( pipe_slow ); +%} + +instruct vternlogd_mem_masked(vec dst, vec src2, memory src3, immU8 func, kReg mask) %{ + match(Set dst (MacroLogicV dst (Binary src2 (Binary src3 (Binary func mask))))); + format %{ "vternlog_masked $dst,$src2,$src3,$func,$mask\t! vternlog masked operation" %} + ins_encode %{ + int vlen_enc = vector_length_encoding(this); + BasicType bt = Matcher::vector_element_basic_type(this); + __ evpternlog($dst$$XMMRegister, $func$$constant, $mask$$KRegister, + $src2$$XMMRegister, $src3$$Address, true, bt, vlen_enc); + %} + ins_pipe( pipe_slow ); +%} + instruct castMM(kReg dst) %{ match(Set dst (CastVV dst)); diff --git a/src/hotspot/cpu/x86/x86_32.ad b/src/hotspot/cpu/x86/x86_32.ad index 4475f053fd035e310e174f48af42bace2b2fd212..9bba150516ed134ae16e34b52cf97242f2ef22e7 100644 --- a/src/hotspot/cpu/x86/x86_32.ad +++ b/src/hotspot/cpu/x86/x86_32.ad @@ -1,5 +1,5 @@ // -// Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. +// 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 @@ -755,6 +755,7 @@ static enum RC rc_class( OptoReg::Name reg ) { assert(UseSSE < 2, "shouldn't be used in SSE2+ mode"); return rc_float; } + if (r->is_KRegister()) return rc_kreg; assert(r->is_XMMRegister(), "must be"); return rc_xmm; } @@ -1249,26 +1250,6 @@ uint MachSpillCopyNode::implementation( CodeBuffer *cbuf, PhaseRegAlloc *ra_, bo return size; } - assert( size > 0, "missed a case" ); - - // -------------------------------------------------------------------- - // Check for second bits still needing moving. - if( src_second == dst_second ) - return size; // Self copy; no move - assert( src_second_rc != rc_bad && dst_second_rc != rc_bad, "src_second & dst_second cannot be Bad" ); - - // Check for second word int-int move - if( src_second_rc == rc_int && dst_second_rc == rc_int ) - return impl_mov_helper(cbuf,do_size,src_second,dst_second,size, st); - - // Check for second word integer store - if( src_second_rc == rc_int && dst_second_rc == rc_stack ) - return impl_helper(cbuf,do_size,false,ra_->reg2offset(dst_second),src_second,0x89,"MOV ",size, st); - - // Check for second word integer load - if( dst_second_rc == rc_int && src_second_rc == rc_stack ) - return impl_helper(cbuf,do_size,true ,ra_->reg2offset(src_second),dst_second,0x8B,"MOV ",size, st); - // AVX-512 opmask specific spilling. if (src_first_rc == rc_stack && dst_first_rc == rc_kreg) { assert((src_first & 1) == 0 && src_first + 1 == src_second, "invalid register pair"); @@ -1306,6 +1287,26 @@ uint MachSpillCopyNode::implementation( CodeBuffer *cbuf, PhaseRegAlloc *ra_, bo return 0; } + assert( size > 0, "missed a case" ); + + // -------------------------------------------------------------------- + // Check for second bits still needing moving. + if( src_second == dst_second ) + return size; // Self copy; no move + assert( src_second_rc != rc_bad && dst_second_rc != rc_bad, "src_second & dst_second cannot be Bad" ); + + // Check for second word int-int move + if( src_second_rc == rc_int && dst_second_rc == rc_int ) + return impl_mov_helper(cbuf,do_size,src_second,dst_second,size, st); + + // Check for second word integer store + if( src_second_rc == rc_int && dst_second_rc == rc_stack ) + return impl_helper(cbuf,do_size,false,ra_->reg2offset(dst_second),src_second,0x89,"MOV ",size, st); + + // Check for second word integer load + if( dst_second_rc == rc_int && src_second_rc == rc_stack ) + return impl_helper(cbuf,do_size,true ,ra_->reg2offset(src_second),dst_second,0x8B,"MOV ",size, st); + Unimplemented(); return 0; // Mute compiler } @@ -7824,9 +7825,9 @@ instruct divI_eReg(eAXRegI rax, eDXRegI rdx, eCXRegI div, eFlagsReg cr) %{ %} // Divide Register Long -instruct divL_eReg( eADXRegL dst, eRegL src1, eRegL src2, eFlagsReg cr, eCXRegI cx, eBXRegI bx ) %{ +instruct divL_eReg(eADXRegL dst, eRegL src1, eRegL src2) %{ match(Set dst (DivL src1 src2)); - effect( KILL cr, KILL cx, KILL bx ); + effect(CALL); ins_cost(10000); format %{ "PUSH $src1.hi\n\t" "PUSH $src1.lo\n\t" @@ -7872,9 +7873,9 @@ instruct modI_eReg(eDXRegI rdx, eAXRegI rax, eCXRegI div, eFlagsReg cr) %{ %} // Remainder Register Long -instruct modL_eReg( eADXRegL dst, eRegL src1, eRegL src2, eFlagsReg cr, eCXRegI cx, eBXRegI bx ) %{ +instruct modL_eReg(eADXRegL dst, eRegL src1, eRegL src2) %{ match(Set dst (ModL src1 src2)); - effect( KILL cr, KILL cx, KILL bx ); + effect(CALL); ins_cost(10000); format %{ "PUSH $src1.hi\n\t" "PUSH $src1.lo\n\t" @@ -12121,34 +12122,34 @@ instruct array_equalsC_evex(eDIRegP ary1, eSIRegP ary2, eAXRegI result, ins_pipe( pipe_slow ); %} -instruct has_negatives(eSIRegP ary1, eCXRegI len, eAXRegI result, - regD tmp1, regD tmp2, eBXRegI tmp3, eFlagsReg cr) +instruct count_positives(eSIRegP ary1, eCXRegI len, eAXRegI result, + regD tmp1, regD tmp2, eBXRegI tmp3, eFlagsReg cr) %{ predicate(!VM_Version::supports_avx512vlbw() || !VM_Version::supports_bmi2()); - match(Set result (HasNegatives ary1 len)); + match(Set result (CountPositives ary1 len)); effect(TEMP tmp1, TEMP tmp2, USE_KILL ary1, USE_KILL len, KILL tmp3, KILL cr); - format %{ "has negatives byte[] $ary1,$len -> $result // KILL $tmp1, $tmp2, $tmp3" %} + format %{ "countPositives byte[] $ary1,$len -> $result // KILL $tmp1, $tmp2, $tmp3" %} ins_encode %{ - __ has_negatives($ary1$$Register, $len$$Register, - $result$$Register, $tmp3$$Register, - $tmp1$$XMMRegister, $tmp2$$XMMRegister, knoreg, knoreg); + __ count_positives($ary1$$Register, $len$$Register, + $result$$Register, $tmp3$$Register, + $tmp1$$XMMRegister, $tmp2$$XMMRegister, knoreg, knoreg); %} ins_pipe( pipe_slow ); %} -instruct has_negatives_evex(eSIRegP ary1, eCXRegI len, eAXRegI result, - regD tmp1, regD tmp2, kReg ktmp1, kReg ktmp2, eBXRegI tmp3, eFlagsReg cr) +instruct count_positives_evex(eSIRegP ary1, eCXRegI len, eAXRegI result, + regD tmp1, regD tmp2, kReg ktmp1, kReg ktmp2, eBXRegI tmp3, eFlagsReg cr) %{ predicate(VM_Version::supports_avx512vlbw() && VM_Version::supports_bmi2()); - match(Set result (HasNegatives ary1 len)); + match(Set result (CountPositives ary1 len)); effect(TEMP tmp1, TEMP tmp2, TEMP ktmp1, TEMP ktmp2, USE_KILL ary1, USE_KILL len, KILL tmp3, KILL cr); - format %{ "has negatives byte[] $ary1,$len -> $result // KILL $tmp1, $tmp2, $tmp3" %} + format %{ "countPositives byte[] $ary1,$len -> $result // KILL $tmp1, $tmp2, $tmp3" %} ins_encode %{ - __ has_negatives($ary1$$Register, $len$$Register, - $result$$Register, $tmp3$$Register, - $tmp1$$XMMRegister, $tmp2$$XMMRegister, $ktmp1$$KRegister, $ktmp2$$KRegister); + __ count_positives($ary1$$Register, $len$$Register, + $result$$Register, $tmp3$$Register, + $tmp1$$XMMRegister, $tmp2$$XMMRegister, $ktmp1$$KRegister, $ktmp2$$KRegister); %} ins_pipe( pipe_slow ); %} @@ -13129,6 +13130,24 @@ instruct cmovLL_mem_LTGE(cmpOp cmp, flagsReg_long_LTGE flags, eRegL dst, load_lo ins_pipe( pipe_cmov_reg_long ); %} +instruct cmovLL_reg_LTGE_U(cmpOpU cmp, flagsReg_ulong_LTGE flags, eRegL dst, eRegL src) %{ + match(Set dst (CMoveL (Binary cmp flags) (Binary dst src))); + predicate(VM_Version::supports_cmov() && ( _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge )); + ins_cost(400); + expand %{ + cmovLL_reg_LTGE(cmp, flags, dst, src); + %} +%} + +instruct cmovLL_mem_LTGE_U(cmpOpU cmp, flagsReg_ulong_LTGE flags, eRegL dst, load_long_memory src) %{ + match(Set dst (CMoveL (Binary cmp flags) (Binary dst (LoadL src)))); + predicate(VM_Version::supports_cmov() && ( _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge )); + ins_cost(500); + expand %{ + cmovLL_mem_LTGE(cmp, flags, dst, src); + %} +%} + // Compare 2 longs and CMOVE ints. instruct cmovII_reg_LTGE(cmpOp cmp, flagsReg_long_LTGE flags, rRegI dst, rRegI src) %{ predicate(VM_Version::supports_cmov() && ( _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge )); @@ -13150,7 +13169,25 @@ instruct cmovII_mem_LTGE(cmpOp cmp, flagsReg_long_LTGE flags, rRegI dst, memory ins_pipe( pipe_cmov_mem ); %} -// Compare 2 longs and CMOVE ints. +instruct cmovII_reg_LTGE_U(cmpOpU cmp, flagsReg_ulong_LTGE flags, rRegI dst, rRegI src) %{ + predicate(VM_Version::supports_cmov() && ( _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge )); + match(Set dst (CMoveI (Binary cmp flags) (Binary dst src))); + ins_cost(200); + expand %{ + cmovII_reg_LTGE(cmp, flags, dst, src); + %} +%} + +instruct cmovII_mem_LTGE_U(cmpOpU cmp, flagsReg_ulong_LTGE flags, rRegI dst, memory src) %{ + predicate(VM_Version::supports_cmov() && ( _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge )); + match(Set dst (CMoveI (Binary cmp flags) (Binary dst (LoadI src)))); + ins_cost(250); + expand %{ + cmovII_mem_LTGE(cmp, flags, dst, src); + %} +%} + +// Compare 2 longs and CMOVE ptrs. instruct cmovPP_reg_LTGE(cmpOp cmp, flagsReg_long_LTGE flags, eRegP dst, eRegP src) %{ predicate(VM_Version::supports_cmov() && ( _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge )); match(Set dst (CMoveP (Binary cmp flags) (Binary dst src))); @@ -13161,6 +13198,16 @@ instruct cmovPP_reg_LTGE(cmpOp cmp, flagsReg_long_LTGE flags, eRegP dst, eRegP s ins_pipe( pipe_cmov_reg ); %} +// Compare 2 unsigned longs and CMOVE ptrs. +instruct cmovPP_reg_LTGE_U(cmpOpU cmp, flagsReg_ulong_LTGE flags, eRegP dst, eRegP src) %{ + predicate(VM_Version::supports_cmov() && ( _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge )); + match(Set dst (CMoveP (Binary cmp flags) (Binary dst src))); + ins_cost(200); + expand %{ + cmovPP_reg_LTGE(cmp,flags,dst,src); + %} +%} + // Compare 2 longs and CMOVE doubles instruct cmovDDPR_reg_LTGE(cmpOp cmp, flagsReg_long_LTGE flags, regDPR dst, regDPR src) %{ predicate( UseSSE<=1 && _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge ); @@ -13313,7 +13360,25 @@ instruct cmovII_mem_EQNE(cmpOp cmp, flagsReg_long_EQNE flags, rRegI dst, memory ins_pipe( pipe_cmov_mem ); %} -// Compare 2 longs and CMOVE ints. +instruct cmovII_reg_EQNE_U(cmpOpU cmp, flagsReg_ulong_EQNE flags, rRegI dst, rRegI src) %{ + predicate(VM_Version::supports_cmov() && ( _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne )); + match(Set dst (CMoveI (Binary cmp flags) (Binary dst src))); + ins_cost(200); + expand %{ + cmovII_reg_EQNE(cmp, flags, dst, src); + %} +%} + +instruct cmovII_mem_EQNE_U(cmpOpU cmp, flagsReg_ulong_EQNE flags, rRegI dst, memory src) %{ + predicate(VM_Version::supports_cmov() && ( _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne )); + match(Set dst (CMoveI (Binary cmp flags) (Binary dst (LoadI src)))); + ins_cost(250); + expand %{ + cmovII_mem_EQNE(cmp, flags, dst, src); + %} +%} + +// Compare 2 longs and CMOVE ptrs. instruct cmovPP_reg_EQNE(cmpOp cmp, flagsReg_long_EQNE flags, eRegP dst, eRegP src) %{ predicate(VM_Version::supports_cmov() && ( _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne )); match(Set dst (CMoveP (Binary cmp flags) (Binary dst src))); @@ -13324,6 +13389,16 @@ instruct cmovPP_reg_EQNE(cmpOp cmp, flagsReg_long_EQNE flags, eRegP dst, eRegP s ins_pipe( pipe_cmov_reg ); %} +// Compare 2 unsigned longs and CMOVE ptrs. +instruct cmovPP_reg_EQNE_U(cmpOpU cmp, flagsReg_ulong_EQNE flags, eRegP dst, eRegP src) %{ + predicate(VM_Version::supports_cmov() && ( _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne )); + match(Set dst (CMoveP (Binary cmp flags) (Binary dst src))); + ins_cost(200); + expand %{ + cmovPP_reg_EQNE(cmp,flags,dst,src); + %} +%} + // Compare 2 longs and CMOVE doubles instruct cmovDDPR_reg_EQNE(cmpOp cmp, flagsReg_long_EQNE flags, regDPR dst, regDPR src) %{ predicate( UseSSE<=1 && _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne ); @@ -13469,22 +13544,18 @@ instruct cmovLL_reg_LEGT_U(cmpOpU_commute cmp, flagsReg_ulong_LEGT flags, eRegL match(Set dst (CMoveL (Binary cmp flags) (Binary dst src))); predicate(VM_Version::supports_cmov() && ( _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::le || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::gt )); ins_cost(400); - format %{ "CMOV$cmp $dst.lo,$src.lo\n\t" - "CMOV$cmp $dst.hi,$src.hi" %} - opcode(0x0F,0x40); - ins_encode( enc_cmov(cmp), RegReg_Lo2( dst, src ), enc_cmov(cmp), RegReg_Hi2( dst, src ) ); - ins_pipe( pipe_cmov_reg_long ); + expand %{ + cmovLL_reg_LEGT(cmp, flags, dst, src); + %} %} instruct cmovLL_mem_LEGT_U(cmpOpU_commute cmp, flagsReg_ulong_LEGT flags, eRegL dst, load_long_memory src) %{ match(Set dst (CMoveL (Binary cmp flags) (Binary dst (LoadL src)))); predicate(VM_Version::supports_cmov() && ( _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::le || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::gt )); ins_cost(500); - format %{ "CMOV$cmp $dst.lo,$src.lo\n\t" - "CMOV$cmp $dst.hi,$src.hi+4" %} - opcode(0x0F,0x40); - ins_encode( enc_cmov(cmp), RegMem(dst, src), enc_cmov(cmp), RegMem_Hi(dst, src) ); - ins_pipe( pipe_cmov_reg_long ); + expand %{ + cmovLL_mem_LEGT(cmp, flags, dst, src); + %} %} // Compare 2 longs and CMOVE ints. @@ -13508,6 +13579,24 @@ instruct cmovII_mem_LEGT(cmpOp_commute cmp, flagsReg_long_LEGT flags, rRegI dst, ins_pipe( pipe_cmov_mem ); %} +instruct cmovII_reg_LEGT_U(cmpOpU_commute cmp, flagsReg_ulong_LEGT flags, rRegI dst, rRegI src) %{ + predicate(VM_Version::supports_cmov() && ( _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::le || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::gt )); + match(Set dst (CMoveI (Binary cmp flags) (Binary dst src))); + ins_cost(200); + expand %{ + cmovII_reg_LEGT(cmp, flags, dst, src); + %} +%} + +instruct cmovII_mem_LEGT_U(cmpOpU_commute cmp, flagsReg_ulong_LEGT flags, rRegI dst, memory src) %{ + predicate(VM_Version::supports_cmov() && ( _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::le || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::gt )); + match(Set dst (CMoveI (Binary cmp flags) (Binary dst (LoadI src)))); + ins_cost(250); + expand %{ + cmovII_mem_LEGT(cmp, flags, dst, src); + %} +%} + // Compare 2 longs and CMOVE ptrs. instruct cmovPP_reg_LEGT(cmpOp_commute cmp, flagsReg_long_LEGT flags, eRegP dst, eRegP src) %{ predicate(VM_Version::supports_cmov() && ( _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::le || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::gt )); @@ -13519,6 +13608,16 @@ instruct cmovPP_reg_LEGT(cmpOp_commute cmp, flagsReg_long_LEGT flags, eRegP dst, ins_pipe( pipe_cmov_reg ); %} +// Compare 2 unsigned longs and CMOVE ptrs. +instruct cmovPP_reg_LEGT_U(cmpOpU_commute cmp, flagsReg_ulong_LEGT flags, eRegP dst, eRegP src) %{ + predicate(VM_Version::supports_cmov() && ( _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::le || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::gt )); + match(Set dst (CMoveP (Binary cmp flags) (Binary dst src))); + ins_cost(200); + expand %{ + cmovPP_reg_LEGT(cmp,flags,dst,src); + %} +%} + // Compare 2 longs and CMOVE doubles instruct cmovDDPR_reg_LEGT(cmpOp_commute cmp, flagsReg_long_LEGT flags, regDPR dst, regDPR src) %{ predicate( UseSSE<=1 && _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::le || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::gt ); @@ -13748,7 +13847,40 @@ instruct cmpFastUnlock(eFlagsReg cr, eRegP object, eAXRegP box, eRegP tmp ) %{ ins_pipe(pipe_slow); %} +instruct mask_all_evexL_LT32(kReg dst, eRegL src) %{ + predicate(Matcher::vector_length(n) <= 32); + match(Set dst (MaskAll src)); + format %{ "mask_all_evexL_LE32 $dst, $src \t" %} + ins_encode %{ + int mask_len = Matcher::vector_length(this); + __ vector_maskall_operation($dst$$KRegister, $src$$Register, mask_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct mask_all_evexL_GT32(kReg dst, eRegL src, kReg ktmp) %{ + predicate(Matcher::vector_length(n) > 32); + match(Set dst (MaskAll src)); + effect(TEMP ktmp); + format %{ "mask_all_evexL_GT32 $dst, $src \t! using $ktmp as TEMP " %} + ins_encode %{ + int mask_len = Matcher::vector_length(this); + __ vector_maskall_operation32($dst$$KRegister, $src$$Register, $ktmp$$KRegister, mask_len); + %} + ins_pipe( pipe_slow ); +%} +instruct mask_all_evexI_GT32(kReg dst, rRegI src, kReg ktmp) %{ + predicate(Matcher::vector_length(n) > 32); + match(Set dst (MaskAll src)); + effect(TEMP ktmp); + format %{ "mask_all_evexI_GT32 $dst, $src \t! using $ktmp as TEMP" %} + ins_encode %{ + int mask_len = Matcher::vector_length(this); + __ vector_maskall_operation32($dst$$KRegister, $src$$Register, $ktmp$$KRegister, mask_len); + %} + ins_pipe( pipe_slow ); +%} // ============================================================================ // Safepoint Instruction diff --git a/src/hotspot/cpu/x86/x86_64.ad b/src/hotspot/cpu/x86/x86_64.ad index 6a764fd62a19b4403350b6e6f986937eb4b35690..09ff707599472eb57dbf77fa9fe21dc12d744b6b 100644 --- a/src/hotspot/cpu/x86/x86_64.ad +++ b/src/hotspot/cpu/x86/x86_64.ad @@ -1,5 +1,5 @@ // -// Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. +// Copyright (c) 2003, 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 @@ -241,6 +241,11 @@ reg_class long_no_rcx_reg %{ return _LONG_NO_RCX_REG_mask; %} +// Class for all long registers (excluding RBP and R13) +reg_class long_no_rbp_r13_reg %{ + return _LONG_NO_RBP_R13_REG_mask; +%} + // Class for all int registers (excluding RSP) reg_class int_reg %{ return _INT_REG_mask; @@ -256,6 +261,11 @@ reg_class int_no_rcx_reg %{ return _INT_NO_RCX_REG_mask; %} +// Class for all int registers (excluding RBP and R13) +reg_class int_no_rbp_r13_reg %{ + return _INT_NO_RBP_R13_REG_mask; +%} + // Singleton class for RAX pointer register reg_class ptr_rax_reg(RAX, RAX_H); @@ -319,9 +329,11 @@ extern RegMask _PTR_NO_RAX_RBX_REG_mask; extern RegMask _LONG_REG_mask; extern RegMask _LONG_NO_RAX_RDX_REG_mask; extern RegMask _LONG_NO_RCX_REG_mask; +extern RegMask _LONG_NO_RBP_R13_REG_mask; extern RegMask _INT_REG_mask; extern RegMask _INT_NO_RAX_RDX_REG_mask; extern RegMask _INT_NO_RCX_REG_mask; +extern RegMask _INT_NO_RBP_R13_REG_mask; extern RegMask _FLOAT_REG_mask; extern RegMask _STACK_OR_PTR_REG_mask; @@ -348,9 +360,11 @@ RegMask _PTR_NO_RAX_RBX_REG_mask; RegMask _LONG_REG_mask; RegMask _LONG_NO_RAX_RDX_REG_mask; RegMask _LONG_NO_RCX_REG_mask; +RegMask _LONG_NO_RBP_R13_REG_mask; RegMask _INT_REG_mask; RegMask _INT_NO_RAX_RDX_REG_mask; RegMask _INT_NO_RCX_REG_mask; +RegMask _INT_NO_RBP_R13_REG_mask; RegMask _FLOAT_REG_mask; RegMask _STACK_OR_PTR_REG_mask; RegMask _STACK_OR_LONG_REG_mask; @@ -409,6 +423,12 @@ void reg_mask_init() { _LONG_NO_RCX_REG_mask.Remove(OptoReg::as_OptoReg(rcx->as_VMReg())); _LONG_NO_RCX_REG_mask.Remove(OptoReg::as_OptoReg(rcx->as_VMReg()->next())); + _LONG_NO_RBP_R13_REG_mask = _LONG_REG_mask; + _LONG_NO_RBP_R13_REG_mask.Remove(OptoReg::as_OptoReg(rbp->as_VMReg())); + _LONG_NO_RBP_R13_REG_mask.Remove(OptoReg::as_OptoReg(rbp->as_VMReg()->next())); + _LONG_NO_RBP_R13_REG_mask.Remove(OptoReg::as_OptoReg(r13->as_VMReg())); + _LONG_NO_RBP_R13_REG_mask.Remove(OptoReg::as_OptoReg(r13->as_VMReg()->next())); + _INT_REG_mask = _ALL_INT_REG_mask; if (PreserveFramePointer) { _INT_REG_mask.Remove(OptoReg::as_OptoReg(rbp->as_VMReg())); @@ -427,6 +447,10 @@ void reg_mask_init() { _INT_NO_RCX_REG_mask = _INT_REG_mask; _INT_NO_RCX_REG_mask.Remove(OptoReg::as_OptoReg(rcx->as_VMReg())); + _INT_NO_RBP_R13_REG_mask = _INT_REG_mask; + _INT_NO_RBP_R13_REG_mask.Remove(OptoReg::as_OptoReg(rbp->as_VMReg())); + _INT_NO_RBP_R13_REG_mask.Remove(OptoReg::as_OptoReg(r13->as_VMReg())); + // _FLOAT_REG_LEGACY_mask/_FLOAT_REG_EVEX_mask is generated by adlc // from the float_reg_legacy/float_reg_evex register class. _FLOAT_REG_mask = VM_Version::supports_evex() ? _FLOAT_REG_EVEX_mask : _FLOAT_REG_LEGACY_mask; @@ -1926,7 +1950,7 @@ encode %{ Label done; // cmp $0x80000000,%eax - __ cmp(as_Register(RAX_enc), 0x80000000); + __ cmpl(as_Register(RAX_enc), 0x80000000); // jne e __ jccb(Assembler::notEqual, normal); @@ -3491,6 +3515,21 @@ operand no_rax_rdx_RegI() interface(REG_INTER); %} +operand no_rbp_r13_RegI() +%{ + constraint(ALLOC_IN_RC(int_no_rbp_r13_reg)); + match(RegI); + match(rRegI); + match(rax_RegI); + match(rbx_RegI); + match(rcx_RegI); + match(rdx_RegI); + match(rdi_RegI); + + format %{ %} + interface(REG_INTER); +%} + // Pointer Register operand any_RegP() %{ @@ -3718,6 +3757,19 @@ operand rdx_RegL() interface(REG_INTER); %} +operand no_rbp_r13_RegL() +%{ + constraint(ALLOC_IN_RC(long_no_rbp_r13_reg)); + match(RegL); + match(rRegL); + match(rax_RegL); + match(rcx_RegL); + match(rdx_RegL); + + format %{ %} + interface(REG_INTER); +%} + // Flags register, used as output of compare instructions operand rFlagsReg() %{ @@ -7443,14 +7495,53 @@ instruct decI_mem(memory dst, immI_M1 src, rFlagsReg cr) ins_pipe(ialu_mem_imm); %} -instruct leaI_rReg_immI(rRegI dst, rRegI src0, immI src1) +instruct leaI_rReg_immI2_immI(rRegI dst, rRegI index, immI2 scale, immI disp) %{ - match(Set dst (AddI src0 src1)); + predicate(VM_Version::supports_fast_2op_lea()); + match(Set dst (AddI (LShiftI index scale) disp)); - ins_cost(110); - format %{ "addr32 leal $dst, [$src0 + $src1]\t# int" %} + format %{ "leal $dst, [$index << $scale + $disp]\t# int" %} ins_encode %{ - __ leal($dst$$Register, Address($src0$$Register, $src1$$constant)); + Address::ScaleFactor scale = static_cast($scale$$constant); + __ leal($dst$$Register, Address(noreg, $index$$Register, scale, $disp$$constant)); + %} + ins_pipe(ialu_reg_reg); +%} + +instruct leaI_rReg_rReg_immI(rRegI dst, rRegI base, rRegI index, immI disp) +%{ + predicate(VM_Version::supports_fast_3op_lea()); + match(Set dst (AddI (AddI base index) disp)); + + format %{ "leal $dst, [$base + $index + $disp]\t# int" %} + ins_encode %{ + __ leal($dst$$Register, Address($base$$Register, $index$$Register, Address::times_1, $disp$$constant)); + %} + ins_pipe(ialu_reg_reg); +%} + +instruct leaI_rReg_rReg_immI2(rRegI dst, no_rbp_r13_RegI base, rRegI index, immI2 scale) +%{ + predicate(VM_Version::supports_fast_2op_lea()); + match(Set dst (AddI base (LShiftI index scale))); + + format %{ "leal $dst, [$base + $index << $scale]\t# int" %} + ins_encode %{ + Address::ScaleFactor scale = static_cast($scale$$constant); + __ leal($dst$$Register, Address($base$$Register, $index$$Register, scale)); + %} + ins_pipe(ialu_reg_reg); +%} + +instruct leaI_rReg_rReg_immI2_immI(rRegI dst, rRegI base, rRegI index, immI2 scale, immI disp) +%{ + predicate(VM_Version::supports_fast_3op_lea()); + match(Set dst (AddI (AddI base (LShiftI index scale)) disp)); + + format %{ "leal $dst, [$base + $index << $scale + $disp]\t# int" %} + ins_encode %{ + Address::ScaleFactor scale = static_cast($scale$$constant); + __ leal($dst$$Register, Address($base$$Register, $index$$Register, scale, $disp$$constant)); %} ins_pipe(ialu_reg_reg); %} @@ -7574,14 +7665,53 @@ instruct decL_mem(memory dst, immL_M1 src, rFlagsReg cr) ins_pipe(ialu_mem_imm); %} -instruct leaL_rReg_immL(rRegL dst, rRegL src0, immL32 src1) +instruct leaL_rReg_immI2_immL32(rRegL dst, rRegL index, immI2 scale, immL32 disp) %{ - match(Set dst (AddL src0 src1)); + predicate(VM_Version::supports_fast_2op_lea()); + match(Set dst (AddL (LShiftL index scale) disp)); - ins_cost(110); - format %{ "leaq $dst, [$src0 + $src1]\t# long" %} + format %{ "leaq $dst, [$index << $scale + $disp]\t# long" %} ins_encode %{ - __ leaq($dst$$Register, Address($src0$$Register, $src1$$constant)); + Address::ScaleFactor scale = static_cast($scale$$constant); + __ leaq($dst$$Register, Address(noreg, $index$$Register, scale, $disp$$constant)); + %} + ins_pipe(ialu_reg_reg); +%} + +instruct leaL_rReg_rReg_immL32(rRegL dst, rRegL base, rRegL index, immL32 disp) +%{ + predicate(VM_Version::supports_fast_3op_lea()); + match(Set dst (AddL (AddL base index) disp)); + + format %{ "leaq $dst, [$base + $index + $disp]\t# long" %} + ins_encode %{ + __ leaq($dst$$Register, Address($base$$Register, $index$$Register, Address::times_1, $disp$$constant)); + %} + ins_pipe(ialu_reg_reg); +%} + +instruct leaL_rReg_rReg_immI2(rRegL dst, no_rbp_r13_RegL base, rRegL index, immI2 scale) +%{ + predicate(VM_Version::supports_fast_2op_lea()); + match(Set dst (AddL base (LShiftL index scale))); + + format %{ "leaq $dst, [$base + $index << $scale]\t# long" %} + ins_encode %{ + Address::ScaleFactor scale = static_cast($scale$$constant); + __ leaq($dst$$Register, Address($base$$Register, $index$$Register, scale)); + %} + ins_pipe(ialu_reg_reg); +%} + +instruct leaL_rReg_rReg_immI2_immL32(rRegL dst, rRegL base, rRegL index, immI2 scale, immL32 disp) +%{ + predicate(VM_Version::supports_fast_3op_lea()); + match(Set dst (AddL (AddL base (LShiftL index scale)) disp)); + + format %{ "leaq $dst, [$base + $index << $scale + $disp]\t# long" %} + ins_encode %{ + Address::ScaleFactor scale = static_cast($scale$$constant); + __ leaq($dst$$Register, Address($base$$Register, $index$$Register, scale, $disp$$constant)); %} ins_pipe(ialu_reg_reg); %} @@ -7612,18 +7742,6 @@ instruct addP_rReg_imm(rRegP dst, immL32 src, rFlagsReg cr) // XXX addP mem ops ???? -instruct leaP_rReg_imm(rRegP dst, rRegP src0, immL32 src1) -%{ - match(Set dst (AddP src0 src1)); - - ins_cost(110); - format %{ "leaq $dst, [$src0 + $src1]\t# ptr" %} - ins_encode %{ - __ leaq($dst$$Register, Address($src0$$Register, $src1$$constant)); - %} - ins_pipe(ialu_reg_reg); -%} - instruct checkCastPP(rRegP dst) %{ match(Set dst (CheckCastPP dst)); @@ -11685,34 +11803,34 @@ instruct array_equalsC_evex(rdi_RegP ary1, rsi_RegP ary2, rax_RegI result, ins_pipe( pipe_slow ); %} -instruct has_negatives(rsi_RegP ary1, rcx_RegI len, rax_RegI result, - legRegD tmp1, legRegD tmp2, rbx_RegI tmp3, rFlagsReg cr,) +instruct count_positives(rsi_RegP ary1, rcx_RegI len, rax_RegI result, + legRegD tmp1, legRegD tmp2, rbx_RegI tmp3, rFlagsReg cr,) %{ predicate(!VM_Version::supports_avx512vlbw() || !VM_Version::supports_bmi2()); - match(Set result (HasNegatives ary1 len)); + match(Set result (CountPositives ary1 len)); effect(TEMP tmp1, TEMP tmp2, USE_KILL ary1, USE_KILL len, KILL tmp3, KILL cr); - format %{ "has negatives byte[] $ary1,$len -> $result // KILL $tmp1, $tmp2, $tmp3" %} + format %{ "countPositives byte[] $ary1,$len -> $result // KILL $tmp1, $tmp2, $tmp3" %} ins_encode %{ - __ has_negatives($ary1$$Register, $len$$Register, - $result$$Register, $tmp3$$Register, - $tmp1$$XMMRegister, $tmp2$$XMMRegister, knoreg, knoreg); + __ count_positives($ary1$$Register, $len$$Register, + $result$$Register, $tmp3$$Register, + $tmp1$$XMMRegister, $tmp2$$XMMRegister, knoreg, knoreg); %} ins_pipe( pipe_slow ); %} -instruct has_negatives_evex(rsi_RegP ary1, rcx_RegI len, rax_RegI result, - legRegD tmp1, legRegD tmp2, kReg ktmp1, kReg ktmp2, rbx_RegI tmp3, rFlagsReg cr,) +instruct count_positives_evex(rsi_RegP ary1, rcx_RegI len, rax_RegI result, + legRegD tmp1, legRegD tmp2, kReg ktmp1, kReg ktmp2, rbx_RegI tmp3, rFlagsReg cr,) %{ predicate(VM_Version::supports_avx512vlbw() && VM_Version::supports_bmi2()); - match(Set result (HasNegatives ary1 len)); + match(Set result (CountPositives ary1 len)); effect(TEMP tmp1, TEMP tmp2, TEMP ktmp1, TEMP ktmp2, USE_KILL ary1, USE_KILL len, KILL tmp3, KILL cr); - format %{ "has negatives byte[] $ary1,$len -> $result // KILL $tmp1, $tmp2, $tmp3" %} + format %{ "countPositives byte[] $ary1,$len -> $result // KILL $tmp1, $tmp2, $tmp3" %} ins_encode %{ - __ has_negatives($ary1$$Register, $len$$Register, - $result$$Register, $tmp3$$Register, - $tmp1$$XMMRegister, $tmp2$$XMMRegister, $ktmp1$$KRegister, $ktmp2$$KRegister); + __ count_positives($ary1$$Register, $len$$Register, + $result$$Register, $tmp3$$Register, + $tmp1$$XMMRegister, $tmp2$$XMMRegister, $ktmp1$$KRegister, $ktmp2$$KRegister); %} ins_pipe( pipe_slow ); %} @@ -13011,6 +13129,29 @@ instruct safePoint_poll_tls(rFlagsReg cr, rRegP poll) ins_pipe(ialu_reg_mem); %} +instruct mask_all_evexL(kReg dst, rRegL src) %{ + match(Set dst (MaskAll src)); + format %{ "mask_all_evexL $dst, $src \t! mask all operation" %} + ins_encode %{ + int mask_len = Matcher::vector_length(this); + __ vector_maskall_operation($dst$$KRegister, $src$$Register, mask_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct mask_all_evexI_GT32(kReg dst, rRegI src, rRegL tmp) %{ + predicate(Matcher::vector_length(n) > 32); + match(Set dst (MaskAll src)); + effect(TEMP tmp); + format %{ "mask_all_evexI_GT32 $dst, $src \t! using $tmp as TEMP" %} + ins_encode %{ + int mask_len = Matcher::vector_length(this); + __ movslq($tmp$$Register, $src$$Register); + __ vector_maskall_operation($dst$$KRegister, $tmp$$Register, mask_len); + %} + ins_pipe( pipe_slow ); +%} + // ============================================================================ // Procedure Call/Return Instructions // Call Java Static Instruction diff --git a/src/hotspot/cpu/zero/bytes_zero.hpp b/src/hotspot/cpu/zero/bytes_zero.hpp index 9acd9dd2430e2782d8744fc2e11a04333119b06b..93d49b8a28d06fe2ce475aee078065f08f037247 100644 --- a/src/hotspot/cpu/zero/bytes_zero.hpp +++ b/src/hotspot/cpu/zero/bytes_zero.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. * Copyright 2007, 2008, 2009 Red Hat, Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -26,7 +26,7 @@ #ifndef CPU_ZERO_BYTES_ZERO_HPP #define CPU_ZERO_BYTES_ZERO_HPP -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" typedef union unaligned { u4 u; diff --git a/src/hotspot/cpu/zero/copy_zero.hpp b/src/hotspot/cpu/zero/copy_zero.hpp index e45e598f74c92494cd8f8ff04763585ec19524c5..1594e861535f850371403be20c9516f3a828e151 100644 --- a/src/hotspot/cpu/zero/copy_zero.hpp +++ b/src/hotspot/cpu/zero/copy_zero.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved. * Copyright 2007 Red Hat, Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -52,22 +52,7 @@ static void pd_disjoint_words(const HeapWord* from, HeapWord* to, size_t count) static void pd_disjoint_words_atomic(const HeapWord* from, HeapWord* to, size_t count) { - switch (count) { - case 8: to[7] = from[7]; - case 7: to[6] = from[6]; - case 6: to[5] = from[5]; - case 5: to[4] = from[4]; - case 4: to[3] = from[3]; - case 3: to[2] = from[2]; - case 2: to[1] = from[1]; - case 1: to[0] = from[0]; - case 0: break; - default: - while (count-- > 0) { - *to++ = *from++; - } - break; - } + shared_disjoint_words_atomic(from, to, count); } static void pd_aligned_conjoint_words(const HeapWord* from, diff --git a/src/hotspot/cpu/zero/frame_zero.cpp b/src/hotspot/cpu/zero/frame_zero.cpp index 19970cfb82bc20cc2e4b6729e080aaaa2f7d29e3..2e00d703377cc89597762cc9d5bd36c11f4d4edb 100644 --- a/src/hotspot/cpu/zero/frame_zero.cpp +++ b/src/hotspot/cpu/zero/frame_zero.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. - * Copyright 2007, 2008, 2009, 2010, 2011 Red Hat, Inc. + * Copyright (c) 2007, 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 @@ -116,13 +116,67 @@ void frame::patch_pc(Thread* thread, address pc) { } bool frame::safe_for_sender(JavaThread *thread) { - ShouldNotCallThis(); - return false; + address sp = (address)_sp; + + // consider stack guards when trying to determine "safe" stack pointers + // sp must be within the usable part of the stack (not in guards) + if (!thread->is_in_usable_stack(sp)) { + return false; + } + + // an fp must be within the stack and above (but not equal) sp + if (!thread->is_in_stack_range_excl((address)fp(), sp)) { + return false; + } + + // All good. + return true; } bool frame::is_interpreted_frame_valid(JavaThread *thread) const { - ShouldNotCallThis(); - return false; + assert(is_interpreted_frame(), "Not an interpreted frame"); + // These are reasonable sanity checks + if (fp() == 0 || (intptr_t(fp()) & (wordSize-1)) != 0) { + return false; + } + if (sp() == 0 || (intptr_t(sp()) & (wordSize-1)) != 0) { + return false; + } + // These are hacks to keep us out of trouble. + // The problem with these is that they mask other problems + if (fp() <= sp()) { // this attempts to deal with unsigned comparison above + return false; + } + + // do some validation of frame elements + // first the method + + Method* m = *interpreter_frame_method_addr(); + + // validate the method we'd find in this potential sender + if (!Method::is_valid_method(m)) { + return false; + } + + // validate bci/bcp + address bcp = interpreter_frame_bcp(); + if (m->validate_bci_from_bcp(bcp) < 0) { + return false; + } + + // validate ConstantPoolCache* + ConstantPoolCache* cp = *interpreter_frame_cache_addr(); + if (MetaspaceObj::is_valid(cp) == false) { + return false; + } + + // validate locals + address locals = (address) *interpreter_frame_locals_addr(); + if (!thread->is_in_stack_range_incl(locals, (address)fp())) { + return false; + } + + return true; } BasicType frame::interpreter_frame_result(oop* oop_result, diff --git a/src/hotspot/cpu/zero/frame_zero.inline.hpp b/src/hotspot/cpu/zero/frame_zero.inline.hpp index 396e189a5db4039fbf03ca242a56919e524d4354..dfca0e4bcb11c4f9bbc08d09a6d791f566430ae5 100644 --- a/src/hotspot/cpu/zero/frame_zero.inline.hpp +++ b/src/hotspot/cpu/zero/frame_zero.inline.hpp @@ -82,6 +82,11 @@ inline intptr_t* frame::link() const { return NULL; } +inline intptr_t* frame::link_or_null() const { + ShouldNotCallThis(); + return NULL; +} + inline interpreterState frame::get_interpreterState() const { return zero_interpreterframe()->interpreter_state(); } diff --git a/src/hotspot/cpu/zero/globals_zero.hpp b/src/hotspot/cpu/zero/globals_zero.hpp index aa330925c5a184f211751154afd16481aa6fca00..208fc32940f09e21cb9e98955db58778c015e708 100644 --- a/src/hotspot/cpu/zero/globals_zero.hpp +++ b/src/hotspot/cpu/zero/globals_zero.hpp @@ -69,8 +69,7 @@ define_pd_global(uintx, TypeProfileLevel, 0); define_pd_global(bool, PreserveFramePointer, false); -// No performance work done here yet. -define_pd_global(bool, CompactStrings, false); +define_pd_global(bool, CompactStrings, true); #define ARCH_FLAGS(develop, \ product, \ diff --git a/src/hotspot/cpu/zero/jniTypes_zero.hpp b/src/hotspot/cpu/zero/jniTypes_zero.hpp index 8d5a6bee7fa32059d8b49e985019693bae35182a..9f6fe78005b9efb63d909bb43881930525192d2c 100644 --- a/src/hotspot/cpu/zero/jniTypes_zero.hpp +++ b/src/hotspot/cpu/zero/jniTypes_zero.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -26,7 +26,7 @@ #define CPU_ZERO_JNITYPES_ZERO_HPP #include "jni.h" -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" #include "oops/oop.hpp" // This file holds platform-dependent routines used to write primitive jni diff --git a/src/hotspot/cpu/zero/vm_version_ext_zero.cpp b/src/hotspot/cpu/zero/vm_version_ext_zero.cpp deleted file mode 100644 index 9e4f45fd679e49d89520be4da442eece8e254e4a..0000000000000000000000000000000000000000 --- a/src/hotspot/cpu/zero/vm_version_ext_zero.cpp +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (c) 2013, 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 "memory/allocation.hpp" -#include "memory/allocation.inline.hpp" -#include "runtime/os.hpp" -#include "vm_version_ext_zero.hpp" - -// VM_Version_Ext statics -int VM_Version_Ext::_no_of_threads = 0; -int VM_Version_Ext::_no_of_cores = 0; -int VM_Version_Ext::_no_of_sockets = 0; -bool VM_Version_Ext::_initialized = false; -char VM_Version_Ext::_cpu_name[CPU_TYPE_DESC_BUF_SIZE] = {0}; -char VM_Version_Ext::_cpu_desc[CPU_DETAILED_DESC_BUF_SIZE] = {0}; - -void VM_Version_Ext::initialize_cpu_information(void) { - // do nothing if cpu info has been initialized - if (_initialized) { - return; - } - - int core_id = -1; - int chip_id = -1; - int len = 0; - char* src_string = NULL; - - _no_of_cores = os::processor_count(); - _no_of_threads = _no_of_cores; - _no_of_sockets = _no_of_cores; - snprintf(_cpu_name, CPU_TYPE_DESC_BUF_SIZE - 1, "Zero VM"); - snprintf(_cpu_desc, CPU_DETAILED_DESC_BUF_SIZE, "%s", _features_string); - _initialized = true; -} - -int VM_Version_Ext::number_of_threads(void) { - initialize_cpu_information(); - return _no_of_threads; -} - -int VM_Version_Ext::number_of_cores(void) { - initialize_cpu_information(); - return _no_of_cores; -} - -int VM_Version_Ext::number_of_sockets(void) { - initialize_cpu_information(); - return _no_of_sockets; -} - -const char* VM_Version_Ext::cpu_name(void) { - initialize_cpu_information(); - char* tmp = NEW_C_HEAP_ARRAY_RETURN_NULL(char, CPU_TYPE_DESC_BUF_SIZE, mtTracing); - if (NULL == tmp) { - return NULL; - } - strncpy(tmp, _cpu_name, CPU_TYPE_DESC_BUF_SIZE); - return tmp; -} - -const char* VM_Version_Ext::cpu_description(void) { - initialize_cpu_information(); - char* tmp = NEW_C_HEAP_ARRAY_RETURN_NULL(char, CPU_DETAILED_DESC_BUF_SIZE, mtTracing); - if (NULL == tmp) { - return NULL; - } - strncpy(tmp, _cpu_desc, CPU_DETAILED_DESC_BUF_SIZE); - return tmp; -} diff --git a/src/hotspot/cpu/zero/vm_version_ext_zero.hpp b/src/hotspot/cpu/zero/vm_version_ext_zero.hpp deleted file mode 100644 index 2c6580d5f1f20cd60598ec2af7871b869410b3be..0000000000000000000000000000000000000000 --- a/src/hotspot/cpu/zero/vm_version_ext_zero.hpp +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2013, 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_ZERO_VM_VERSION_EXT_ZERO_HPP -#define CPU_ZERO_VM_VERSION_EXT_ZERO_HPP - -#include "runtime/vm_version.hpp" -#include "utilities/macros.hpp" - -class VM_Version_Ext : public VM_Version { - private: - static const size_t CPU_TYPE_DESC_BUF_SIZE = 256; - static const size_t CPU_DETAILED_DESC_BUF_SIZE = 4096; - - static int _no_of_threads; - static int _no_of_cores; - static int _no_of_sockets; - static bool _initialized; - static char _cpu_name[CPU_TYPE_DESC_BUF_SIZE]; - static char _cpu_desc[CPU_DETAILED_DESC_BUF_SIZE]; - - public: - static int number_of_threads(void); - static int number_of_cores(void); - static int number_of_sockets(void); - - static const char* cpu_name(void); - static const char* cpu_description(void); - static void initialize_cpu_information(void); - -}; - -#endif // CPU_ZERO_VM_VERSION_EXT_ZERO_HPP diff --git a/src/hotspot/cpu/zero/vm_version_zero.cpp b/src/hotspot/cpu/zero/vm_version_zero.cpp index 6fa56c24cce14c265ab5324e97f3f00c1536d781..5c2a0a3d5d2304b798d992ab5ae03138c4d899a9 100644 --- a/src/hotspot/cpu/zero/vm_version_zero.cpp +++ b/src/hotspot/cpu/zero/vm_version_zero.cpp @@ -121,3 +121,17 @@ void VM_Version::initialize() { UNSUPPORTED_OPTION(CountCompiledCalls); #endif } + +void VM_Version::initialize_cpu_information(void) { + // do nothing if cpu info has been initialized + if (_initialized) { + return; + } + + _no_of_cores = os::processor_count(); + _no_of_threads = _no_of_cores; + _no_of_sockets = _no_of_cores; + snprintf(_cpu_name, CPU_TYPE_DESC_BUF_SIZE - 1, "Zero VM"); + snprintf(_cpu_desc, CPU_DETAILED_DESC_BUF_SIZE, "%s", _features_string); + _initialized = true; +} diff --git a/src/hotspot/cpu/zero/vm_version_zero.hpp b/src/hotspot/cpu/zero/vm_version_zero.hpp index c63a47719e50d592d7db088fa0f9c04a77e901d4..1cfe57b11c2463b45ad9507affadd6a203b9a4f6 100644 --- a/src/hotspot/cpu/zero/vm_version_zero.hpp +++ b/src/hotspot/cpu/zero/vm_version_zero.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. * Copyright 2007 Red Hat, Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -34,6 +34,8 @@ class VM_Version : public Abstract_VM_Version { static void initialize(); constexpr static bool supports_stack_watermark_barrier() { return true; } + + static void initialize_cpu_information(void); }; #endif // CPU_ZERO_VM_VERSION_ZERO_HPP diff --git a/src/hotspot/cpu/zero/zeroInterpreter_zero.cpp b/src/hotspot/cpu/zero/zeroInterpreter_zero.cpp index f2e8dc2fe2322566bf20fa34ea0c70f90ac44153..f3f1327a62969a264f8c58697d4d6e67b1adb899 100644 --- a/src/hotspot/cpu/zero/zeroInterpreter_zero.cpp +++ b/src/hotspot/cpu/zero/zeroInterpreter_zero.cpp @@ -186,9 +186,17 @@ void ZeroInterpreter::main_loop(int recurse, TRAPS) { // Call the interpreter if (JvmtiExport::can_post_interpreter_events()) { - BytecodeInterpreter::run(istate); + if (RewriteBytecodes) { + BytecodeInterpreter::run(istate); + } else { + BytecodeInterpreter::run(istate); + } } else { - BytecodeInterpreter::run(istate); + if (RewriteBytecodes) { + BytecodeInterpreter::run(istate); + } else { + BytecodeInterpreter::run(istate); + } } fixup_after_potential_safepoint(); diff --git a/src/hotspot/os/aix/attachListener_aix.cpp b/src/hotspot/os/aix/attachListener_aix.cpp index 25dfe8d816b609cff331213d80d7c892cad32716..461b7fc874f46dc20985019192355b3709aeee5e 100644 --- a/src/hotspot/os/aix/attachListener_aix.cpp +++ b/src/hotspot/os/aix/attachListener_aix.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2022, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, 2018 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -28,7 +28,6 @@ #include "runtime/interfaceSupport.inline.hpp" #include "runtime/os.inline.hpp" #include "services/attachListener.hpp" -#include "services/dtraceAttacher.hpp" #include #include diff --git a/src/hotspot/os/aix/libperfstat_aix.cpp b/src/hotspot/os/aix/libperfstat_aix.cpp index 65a937ef261cc3c651e0e776654e113e959cd714..cec0ac1d28769cabd451c2d258922e5597dc3efa 100644 --- a/src/hotspot/os/aix/libperfstat_aix.cpp +++ b/src/hotspot/os/aix/libperfstat_aix.cpp @@ -1,5 +1,7 @@ /* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, 2018 SAP SE. All rights reserved. + * Copyright (c) 2022, IBM Corp. * 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 +32,22 @@ // Handle to the libperfstat. static void* g_libhandle = NULL; +typedef int (*fun_perfstat_cpu_t) (perfstat_id_t *name, PERFSTAT_CPU_T_LATEST* userbuff, + int sizeof_userbuff, int desired_number); + typedef int (*fun_perfstat_cpu_total_t) (perfstat_id_t *name, PERFSTAT_CPU_TOTAL_T_LATEST* userbuff, int sizeof_userbuff, int desired_number); typedef int (*fun_perfstat_memory_total_t) (perfstat_id_t *name, perfstat_memory_total_t* userbuff, int sizeof_userbuff, int desired_number); +typedef int (*fun_perfstat_netinterface_t) (perfstat_id_t *name, perfstat_netinterface_t* userbuff, + int sizeof_userbuff, int desired_number); + +typedef int (*fun_perfstat_process_t) (perfstat_id_t *name, + PERFSTAT_PROCESS_T_LATEST* userbuff, int sizeof_userbuff, + int desired_number); + typedef int (*fun_perfstat_partition_total_t) (perfstat_id_t *name, PERFSTAT_PARTITON_TOTAL_T_LATEST* userbuff, int sizeof_userbuff, int desired_number); @@ -48,12 +60,15 @@ typedef void (*fun_perfstat_reset_t) (); typedef cid_t (*fun_wpar_getcid_t) (); -static fun_perfstat_cpu_total_t g_fun_perfstat_cpu_total = NULL; -static fun_perfstat_memory_total_t g_fun_perfstat_memory_total = NULL; +static fun_perfstat_cpu_total_t g_fun_perfstat_cpu_total = NULL; +static fun_perfstat_cpu_t g_fun_perfstat_cpu = NULL; +static fun_perfstat_memory_total_t g_fun_perfstat_memory_total = NULL; +static fun_perfstat_netinterface_t g_fun_perfstat_netinterface = NULL; static fun_perfstat_partition_total_t g_fun_perfstat_partition_total = NULL; -static fun_perfstat_wpar_total_t g_fun_perfstat_wpar_total = NULL; -static fun_perfstat_reset_t g_fun_perfstat_reset = NULL; -static fun_wpar_getcid_t g_fun_wpar_getcid = NULL; +static fun_perfstat_process_t g_fun_perfstat_process = NULL; +static fun_perfstat_wpar_total_t g_fun_perfstat_wpar_total = NULL; +static fun_perfstat_reset_t g_fun_perfstat_reset = NULL; +static fun_wpar_getcid_t g_fun_wpar_getcid = NULL; bool libperfstat::init() { @@ -84,7 +99,10 @@ bool libperfstat::init() { // These functions are required for every release. RESOLVE_FUN(perfstat_cpu_total); + RESOLVE_FUN(perfstat_cpu); RESOLVE_FUN(perfstat_memory_total); + RESOLVE_FUN(perfstat_netinterface); + RESOLVE_FUN(perfstat_process); RESOLVE_FUN(perfstat_reset); trcVerbose("libperfstat loaded."); @@ -108,6 +126,22 @@ void libperfstat::cleanup() { } +int libperfstat::perfstat_cpu_total(perfstat_id_t *name, PERFSTAT_CPU_TOTAL_T_LATEST* userbuff, + int sizeof_userbuff, int desired_number) { + if (g_fun_perfstat_cpu_total == NULL) { + return -1; + } + return g_fun_perfstat_cpu_total(name, userbuff, sizeof_userbuff, desired_number); +} + +int libperfstat::perfstat_cpu(perfstat_id_t *name, PERFSTAT_CPU_T_LATEST* userbuff, + int sizeof_userbuff, int desired_number) { + if (g_fun_perfstat_cpu == NULL) { + return -1; + } + return g_fun_perfstat_cpu(name, userbuff, sizeof_userbuff, desired_number); +} + int libperfstat::perfstat_memory_total(perfstat_id_t *name, perfstat_memory_total_t* userbuff, int sizeof_userbuff, int desired_number) { @@ -117,12 +151,13 @@ int libperfstat::perfstat_memory_total(perfstat_id_t *name, return g_fun_perfstat_memory_total(name, userbuff, sizeof_userbuff, desired_number); } -int libperfstat::perfstat_cpu_total(perfstat_id_t *name, PERFSTAT_CPU_TOTAL_T_LATEST* userbuff, - int sizeof_userbuff, int desired_number) { - if (g_fun_perfstat_cpu_total == NULL) { +int libperfstat::perfstat_netinterface(perfstat_id_t *name, + perfstat_netinterface_t* userbuff, + int sizeof_userbuff, int desired_number) { + if (g_fun_perfstat_netinterface == NULL) { return -1; } - return g_fun_perfstat_cpu_total(name, userbuff, sizeof_userbuff, desired_number); + return g_fun_perfstat_netinterface(name, userbuff, sizeof_userbuff, desired_number); } int libperfstat::perfstat_partition_total(perfstat_id_t *name, PERFSTAT_PARTITON_TOTAL_T_LATEST* userbuff, @@ -133,6 +168,14 @@ int libperfstat::perfstat_partition_total(perfstat_id_t *name, PERFSTAT_PARTITON return g_fun_perfstat_partition_total(name, userbuff, sizeof_userbuff, desired_number); } +int libperfstat::perfstat_process(perfstat_id_t *name, perfstat_process_t* userbuff, + int sizeof_userbuff, int desired_number) { + if (g_fun_perfstat_process == NULL) { + return -1; + } + return g_fun_perfstat_process(name, userbuff, sizeof_userbuff, desired_number); +} + int libperfstat::perfstat_wpar_total(perfstat_id_wpar_t *name, PERFSTAT_WPAR_TOTAL_T_LATEST* userbuff, int sizeof_userbuff, int desired_number) { if (g_fun_perfstat_wpar_total == NULL) { diff --git a/src/hotspot/os/aix/libperfstat_aix.hpp b/src/hotspot/os/aix/libperfstat_aix.hpp index d323b8e8bbcfa816415a003e57eb9e06d2d45fba..30f08c57a033bf438c0ffc4e90d29f3ca3265315 100644 --- a/src/hotspot/os/aix/libperfstat_aix.hpp +++ b/src/hotspot/os/aix/libperfstat_aix.hpp @@ -1,5 +1,7 @@ /* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, 2018 SAP SE. All rights reserved. + * Copyright (c) 2022, IBM Corp. * 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 +49,9 @@ // work without recompilation on all newer AIX versions. // -#define IDENTIFIER_LENGTH 64 /* length of strings included in the structures */ +#define IDENTIFIER_LENGTH 64 /* length of strings included in the structures */ +#define FIRST_CPU "" /* pseudo-name for fist CPU */ +#define FIRST_NETINTERFACE "" /* pseudo-name for first NETINTERFACE */ typedef struct { /* structure element identifier */ @@ -439,6 +443,102 @@ typedef struct { /* global cpu information AIX 7.2 / 6.1 TL6 (see oslevel -r) * * of perfstat_cpu_total_t data structure */ } perfstat_cpu_total_t_72; +typedef struct { /* component perfstat_cpu_t from AIX 7.2 documentation */ + char name [IDENTIFIER_LENGTH]; /* Logical processor name (processor0, processor1,.). */ + ulong_t state; /* Specifies whether the CPU is offline or online. + * (NOTE: The type of 'state' is not specified in the documentation, but + * ulong_t is the correct length) */ + u_longlong_t user; /* Raw number of clock ticks spent in user mode. */ + u_longlong_t sys; /* Raw number of clock ticks spent in system mode. */ + u_longlong_t idle; /* Raw number of clock ticks spent idle. */ + u_longlong_t wait; /* Raw number of clock ticks spent waiting for I/O. */ + u_longlong_t pswitch; /* Number of context switches (changes of currently running process). */ + u_longlong_t syscall; /* Number of system calls executed. */ + u_longlong_t sysread; /* Number of read system calls executed. */ + u_longlong_t syswrite; /* Number of write system calls executed. */ + u_longlong_t sysfork; /* Number of fork system call executed. */ + u_longlong_t sysexec; /* Number of exec system call executed. */ + u_longlong_t readch; /* Number of characters transferred with read system call. */ + u_longlong_t writech; /* Number of characters transferred with write system call. */ + u_longlong_t bread; /* Number of block reads. */ + u_longlong_t bwrite; /* Number of block writes. */ + u_longlong_t lread; /* Number of logical read requests. */ + u_longlong_t lwrite; /* Number of logical write requests. */ + u_longlong_t phread; /* Number of physical reads (reads on raw device). */ + u_longlong_t phwrite; /* Number of physical writes (writes on raw device). */ + u_longlong_t iget; /* Number of inode lookups. */ + u_longlong_t namei; /* Number of vnode lookup from a path name. */ + u_longlong_t dirblk; /* Number of 512-byte blocks reads by the directory search routine to locate an entry for a file. */ + u_longlong_t msg; /* Number of interprocess communication (IPC) message operations. */ + u_longlong_t sema; /* Number of IPC semaphore operations. */ + u_longlong_t minfaults; /* Number of page faults with no I/O. */ + u_longlong_t majfaults; /* Number of page faults with disk I/O. */ + u_longlong_t puser; /* Raw number of physical processor ticks in user mode. */ + u_longlong_t psys; /* Raw number of physical processor ticks in system mode. */ + u_longlong_t pidle; /* Raw number of physical processor ticks idle. */ + u_longlong_t pwait; /* Raw number of physical processor ticks waiting for I/O. */ + u_longlong_t redisp_sd0; /* Number of thread redispatches within the scheduler affinity domain 0. */ + u_longlong_t redisp_sd1; /* Number of thread redispatches within the scheduler affinity domain 1. */ + u_longlong_t redisp_sd2; /* Number of thread redispatches within the scheduler affinity domain 2. */ + u_longlong_t redisp_sd3; /* Number of thread redispatches within the scheduler affinity domain 3. */ + u_longlong_t redisp_sd4; /* Number of thread redispatches within the scheduler affinity domain 4. */ + u_longlong_t redisp_sd5; /* Number of thread redispatches within the scheduler affinity domain 5. */ + u_longlong_t migration_push; /* Number of thread migrations from the local runque to another queue due to starvation load balancing. */ + u_longlong_t migration_S3grq; /* Number of thread migrations from the global runque to the local runque resulting in a move across scheduling domain 3. */ + u_longlong_t migration_S3pull; /* Number of thread migrations from another processor's runque resulting in a move across scheduling domain 3. */ + u_longlong_t invol_cswitch; /* Number of involuntary thread context switches. */ + u_longlong_t vol_cswitch; /* Number of voluntary thread context switches. */ + u_longlong_t runque; /* Number of threads on the runque. */ + u_longlong_t bound; /* Number of bound threads. */ + u_longlong_t decrintrs; /* Number of decrementer interrupts. */ + u_longlong_t mpcrintrs; /* Number of received interrupts for MPC. */ + u_longlong_t mpcsintrs; /* Number of sent interrupts for MPC. */ + u_longlong_t devintrs; /* Number of device interrupts. */ + u_longlong_t softintrs; /* Number of offlevel handlers called. */ + u_longlong_t phantintrs; /* Number of phantom interrupts. */ + u_longlong_t idle_donated_purr; /* Number of idle cycles donated by a dedicated partition enabled for donation. */ + u_longlong_t idle_donated_spurr; /* Number of idle spurr cycles donated by a dedicated partition enabled for donation. */ + u_longlong_t busy_donated_purr; /* Number of busy cycles donated by a dedicated partition enabled for donation. */ + u_longlong_t busy_donated_spurr; /* Number of busy spurr cycles donated by a dedicated partition enabled for donation. */ + u_longlong_t idle_stolen_purr; /* Number of idle cycles stolen by the hypervisor from a dedicated partition. */ + u_longlong_t idle_stolen_spurr; /* Number of idle spurr cycles stolen by the hypervisor from a dedicated partition. */ + u_longlong_t busy_stolen_purr; /* Number of busy cycles stolen by the hypervisor from a dedicated partition. */ + u_longlong_t busy_stolen_spurr; /* Number of busy spurr cycles stolen by the hypervisor from a dedicated partition.*/ + u_longlong_t shcpus_in_sys; /* Number of physical processors allocated for shared processor use, across all shared processors pools. */ + u_longlong_t entitled_pool_capacity; /* Entitled processor capacity of partition’s pool. */ + u_longlong_t pool_max_time; /* Summation of maximum time that can be consumed by the pool (nanoseconds). */ + u_longlong_t pool_busy_time; /* Summation of busy (nonidle) time accumulated across all partitions in the pool (nanoseconds). */ + u_longlong_t pool_scaled_busy_time; /* Scaled summation of busy (nonidle) time accumulated across all partitions in the pool (nanoseconds). */ + u_longlong_t shcpu_tot_time; /* Summation of total time across all physical processors allocated for shared processor use (nanoseconds). */ + u_longlong_t shcpu_busy_time; /* Summation of busy (nonidle) time accumulated across all shared processor partitions (nanoseconds). */ + u_longlong_t shcpu_scaled_busy_time; /* Scaled summation of busy time accumulated across all shared processor partitions (nanoseconds). */ + int ams_pool_id; /* AMS pool ID of the pool the LPAR belongs to. */ + int var_mem_weight; /* Variable memory capacity weight. */ + u_longlong_t iome; /* I/O memory entitlement of the partition in bytes. */ + u_longlong_t pmem; /* Physical memory currently backing the partition's logical memory in bytes. */ + u_longlong_t hpi; /* Number of hypervisor page-ins. */ + u_longlong_t hpit; /* Time spent in hypervisor page-ins (in nanoseconds). */ + u_longlong_t hypv_pagesize; /* Hypervisor page size in KB. */ + uint online_lcpus; /* Number of online logical processors. */ + uint smt_thrds; /* Number of SMT threads. */ +} perfstat_cpu_t; + +typedef struct { + char name[IDENTIFIER_LENGTH]; /* Name of the interface. */ + char description[IDENTIFIER_LENGTH]; /* Interface description (from ODM, similar to lscfg output). */ + uchar type; /* Ethernet, token ring, and so on. Interpretation can be done using the /usr/include/net/if_types.h file. */ + u_longlong_t mtu; /* Network frame size. */ + u_longlong_t ipacets; /* Number of packets received on interface. */ + u_longlong_t ibytes; /* Number of bytes received on interface. */ + u_longlong_t ierrors; /* Number of input errors on interface. */ + u_longlong_t opackets; /* Number of packets sent on interface. */ + u_longlong_t obytes; /* Number of bytes sent on interface. */ + u_longlong_t oerrors; /* Number of output errors on interface. */ + u_longlong_t collisions; /* Number of collisions on csma interface. */ + u_longlong_t bitrate; /* Adapter rating in bit per second. */ + u_longlong_t if_iqdrops; /* Dropped on input, this interface. */ + u_longlong_t if_arpdrops; /* Dropped because no arp response. */ +} perfstat_netinterface_t; typedef union { uint w; @@ -797,6 +897,38 @@ typedef struct { /* partition total information AIX 7.1 >= TL1*/ * of perfstat_partition_total_t data structure */ } perfstat_partition_total_t_71_1; +typedef struct { + u_longlong_t version; /* Version number of the data structure. */ + u_longlong_t pid; /* Process ID. */ + char proc_name[64]; /* Name of the process. */ + int proc_priority; /* Process priority. */ + u_longlong_t num_threads; /* Thread count. */ + u_longlong_t proc_uid; /* Owner information. */ + u_longlong_t proc_classid; /* WLM class name. */ + u_longlong_t proc_size; /* Virtual size of the process (exclusive usage, leaving all shared library text & shared file pages, shared memory, and memory mapped). */ + u_longlong_t proc_real_mem_data; /* Real memory used for data in KB. */ + u_longlong_t proc_real_mem_text; /* Real memory used for text in KB. */ + u_longlong_t proc_virt_mem_data; /* Virtual memory used for data in KB. */ + u_longlong_t proc_virt_mem_text; /* Virtual memory used for text in KB. */ + u_longlong_t shared_lib_data_size; /* Data size from shared library in KB. */ + u_longlong_t heap_size; /* Heap size in KB. */ + u_longlong_t real_inuse; /* The Real memory (in KB) in use by the process including all kind of segments (excluding system segments). This includes text, data, shared library text, shared library data, file pages, shared memory, and memory mapped. */ + u_longlong_t virt_inuse; /* The virtual memory (in KB) in use by the process including all kind of segments (excluding system segments). This includes text, data, shared library text, shared library data, file pages, shared memory, and memory mapped. */ + u_longlong_t pinned; /* Pinned memory (in KB) for this process inclusive of all segments. */ + u_longlong_t pgsp_inuse; /* Paging space used (in KB) inclusive of all segments. */ + u_longlong_t filepages; /* File pages used (in KB) including shared pages. */ + u_longlong_t real_inuse_map; /* Real memory used (in KB) for shared memory and memory mapped regions */ + u_longlong_t virt_inuse_map; /* Virtual memory used (in KB) for shared memory and memory mapped regions. */ + u_longlong_t pinned_inuse_map; /* Pinned memory used (in KB) for shared memory and memory mapped regions. */ + double ucpu_time; /* User mode CPU time is in percentage or milliseconds, which is based on, whether it is filled by perfstat_process_util or perfstat_process respectively. */ + double scpu_time; /* System mode CPU time is in percentage or milliseconds, which is based on whether it is filled by perfstat_process_util or perfstat_process respectively. */ + u_longlong_t last_timebase; /* Timebase counter. */ + u_longlong_t inBytes; /* Bytes written to disk. */ + u_longlong_t outBytes; /* Bytes read from disk. */ + u_longlong_t inOps; /* In operations from disk. */ + u_longlong_t outOps; /* Out operations from disk */ +} perfstat_process_t; + typedef union { /* WPAR Type & Flags */ uint w; struct { @@ -854,9 +986,14 @@ typedef struct { /* WPAR identifier */ // end: libperfstat.h (AIX 5.2, 5.3, 6.1, 7.1) ////////////////////////////////////////////////////////////////////////////////////////////////////////////// -#define PERFSTAT_PARTITON_TOTAL_T_LATEST perfstat_partition_total_t_71_1/* latest perfstat_partition_total_t structure */ -#define PERFSTAT_CPU_TOTAL_T_LATEST perfstat_cpu_total_t_72 /* latest perfstat_cpu_total_t structure */ -#define PERFSTAT_WPAR_TOTAL_T_LATEST perfstat_wpar_total_t_71 /* latest perfstat_wpar_total_t structure */ +#define PERFSTAT_PARTITON_TOTAL_T_LATEST perfstat_partition_total_t_71_1 /* latest perfstat_partition_total_t structure */ +#define PERFSTAT_PROCESS_T_LATEST perfstat_process_t /* latest perfstat_process_t structure */ +#define PERFSTAT_CPU_TOTAL_T_LATEST perfstat_cpu_total_t_72 /* latest perfstat_cpu_total_t structure */ +#define PERFSTAT_CPU_T_LATEST perfstat_cpu_t /* latest perfstat_cpu_t structure */ +#define PERFSTAT_NETINTERFACE_T_LATEST perfstat_netinterface_t /* latest perfstat_netinterface_t structure */ +#define PERFSTAT_WPAR_TOTAL_T_LATEST perfstat_wpar_total_t_71 /* latest perfstat_wpar_total_t structure */ + +typedef PERFSTAT_CPU_TOTAL_T_LATEST perfstat_cpu_total_t; class libperfstat { @@ -886,6 +1023,14 @@ public: static cid_t wpar_getcid(); + static int perfstat_cpu(perfstat_id_t *name, PERFSTAT_CPU_T_LATEST* userbuff, + int sizeof_userbuff, int desired_number); + + static int perfstat_process(perfstat_id_t *name, PERFSTAT_PROCESS_T_LATEST* userbuff, + int sizeof_userbuff, int desired_number); + + static int perfstat_netinterface(perfstat_id_t *name, PERFSTAT_NETINTERFACE_T_LATEST* userbuff, + int sizeof_userbuff, int desired_number); //////////////////////////////////////////////////////////////// // The convenience functions get_partitioninfo(), get_cpuinfo(), get_wparinfo() return diff --git a/src/hotspot/os/aix/loadlib_aix.cpp b/src/hotspot/os/aix/loadlib_aix.cpp index 9ac761f62124ca252dfb5a8a34d074c2d0b26f53..a111e0199fa69568e9135c0f577aa2dce5b17858 100644 --- a/src/hotspot/os/aix/loadlib_aix.cpp +++ b/src/hotspot/os/aix/loadlib_aix.cpp @@ -1,6 +1,7 @@ /* - * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, 2019 SAP SE. All rights reserved. + * Copyright (c) 2022, IBM Corp. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -110,13 +111,7 @@ static StringList g_stringlist; // eternal - this list is rebuilt on every reload. // Note that we do not hand out those entries, but copies of them. -struct entry_t { - entry_t* next; - loaded_module_t info; -}; - -static void print_entry(const entry_t* e, outputStream* os) { - const loaded_module_t* const lm = &(e->info); +static void print_entry(const loaded_module_t* lm, outputStream* os) { os->print(" %c text: " INTPTR_FORMAT " - " INTPTR_FORMAT ", data: " INTPTR_FORMAT " - " INTPTR_FORMAT " " "%s", @@ -129,50 +124,50 @@ static void print_entry(const entry_t* e, outputStream* os) { } } -static entry_t* g_first = NULL; +static loaded_module_t* g_first = NULL; -static entry_t* find_entry_for_text_address(const void* p) { - for (entry_t* e = g_first; e; e = e->next) { - if ((uintptr_t)p >= (uintptr_t)e->info.text && - (uintptr_t)p < ((uintptr_t)e->info.text + e->info.text_len)) { - return e; +static loaded_module_t* find_entry_for_text_address(const void* p) { + for (loaded_module_t* lm = g_first; lm; lm = lm->next) { + if ((uintptr_t)p >= (uintptr_t)lm->text && + (uintptr_t)p < ((uintptr_t)lm->text + lm->text_len)) { + return lm; } } return NULL; } -static entry_t* find_entry_for_data_address(const void* p) { - for (entry_t* e = g_first; e; e = e->next) { - if ((uintptr_t)p >= (uintptr_t)e->info.data && - (uintptr_t)p < ((uintptr_t)e->info.data + e->info.data_len)) { - return e; +static loaded_module_t* find_entry_for_data_address(const void* p) { + for (loaded_module_t* lm = g_first; lm; lm = lm->next) { + if ((uintptr_t)p >= (uintptr_t)lm->data && + (uintptr_t)p < ((uintptr_t)lm->data + lm->data_len)) { + return lm; } } return NULL; } // Adds a new entry to the list (ordered by text address ascending). -static void add_entry_to_list(entry_t* e, entry_t** start) { - entry_t* last = NULL; - entry_t* e2 = *start; - while (e2 && e2->info.text < e->info.text) { - last = e2; - e2 = e2->next; +static void add_entry_to_list(loaded_module_t* lm, loaded_module_t** start) { + loaded_module_t* last = NULL; + loaded_module_t* lm2 = *start; + while (lm2 && lm2->text < lm->text) { + last = lm2; + lm2 = lm2->next; } if (last) { - last->next = e; + last->next = lm; } else { - *start = e; + *start = lm; } - e->next = e2; + lm->next = lm2; } -static void free_entry_list(entry_t** start) { - entry_t* e = *start; - while (e) { - entry_t* const e2 = e->next; - ::free(e); - e = e2; +static void free_entry_list(loaded_module_t** start) { + loaded_module_t* lm = *start; + while (lm) { + loaded_module_t* const lm2 = lm->next; + ::free(lm); + lm = lm2; } *start = NULL; } @@ -186,7 +181,7 @@ static bool reload_table() { trcVerbose("reload module table..."); - entry_t* new_list = NULL; + loaded_module_t* new_list = NULL; const struct ld_info* ldi = NULL; // Call loadquery(L_GETINFO..) to get a list of all loaded Dlls from AIX. loadquery @@ -214,33 +209,33 @@ static bool reload_table() { for (;;) { - entry_t* e = (entry_t*) ::malloc(sizeof(entry_t)); - if (!e) { + loaded_module_t* lm = (loaded_module_t*) ::malloc(sizeof(loaded_module_t)); + if (!lm) { trcVerbose("OOM."); goto cleanup; } - memset(e, 0, sizeof(entry_t)); + memset(lm, 0, sizeof(loaded_module_t)); - e->info.text = ldi->ldinfo_textorg; - e->info.text_len = ldi->ldinfo_textsize; - e->info.data = ldi->ldinfo_dataorg; - e->info.data_len = ldi->ldinfo_datasize; + lm->text = ldi->ldinfo_textorg; + lm->text_len = ldi->ldinfo_textsize; + lm->data = ldi->ldinfo_dataorg; + lm->data_len = ldi->ldinfo_datasize; - e->info.path = g_stringlist.add(ldi->ldinfo_filename); - if (!e->info.path) { + lm->path = g_stringlist.add(ldi->ldinfo_filename); + if (!lm->path) { trcVerbose("OOM."); goto cleanup; } // Extract short name { - const char* p = strrchr(e->info.path, '/'); + const char* p = strrchr(lm->path, '/'); if (p) { p ++; - e->info.shortname = p; + lm->shortname = p; } else { - e->info.shortname = e->info.path; + lm->shortname = lm->path; } } @@ -248,32 +243,32 @@ static bool reload_table() { const char* p_mbr_name = ldi->ldinfo_filename + strlen(ldi->ldinfo_filename) + 1; if (*p_mbr_name) { - e->info.member = g_stringlist.add(p_mbr_name); - if (!e->info.member) { + lm->member = g_stringlist.add(p_mbr_name); + if (!lm->member) { trcVerbose("OOM."); goto cleanup; } } else { - e->info.member = NULL; + lm->member = NULL; } - if (strcmp(e->info.shortname, "libjvm.so") == 0) { + if (strcmp(lm->shortname, "libjvm.so") == 0) { // Note that this, theoretically, is fuzzy. We may accidentally contain // more than one libjvm.so. But that is improbable, so lets go with this // solution. - e->info.is_in_vm = true; + lm->is_in_vm = true; } trcVerbose("entry: %p " SIZE_FORMAT ", %p " SIZE_FORMAT ", %s %s %s, %d", - e->info.text, e->info.text_len, - e->info.data, e->info.data_len, - e->info.path, e->info.shortname, - (e->info.member ? e->info.member : "NULL"), - e->info.is_in_vm + lm->text, lm->text_len, + lm->data, lm->data_len, + lm->path, lm->shortname, + (lm->member ? lm->member : "NULL"), + lm->is_in_vm ); // Add to list. - add_entry_to_list(e, &new_list); + add_entry_to_list(lm, &new_list); // Next entry... if (ldi->ldinfo_next) { @@ -304,6 +299,23 @@ cleanup: } // end LoadedLibraries::reload() +// Callback for loaded module information (from os.hpp) +// Input parameters: +// char* module_file_name, +// address module_base_addr, +// address module_top_addr, +// void* param +static bool for_each_internal(os::LoadedModulesCallbackFunc cb, void* param) { + + for (const loaded_module_t* lm = g_first; lm; lm = lm->next) { + (*cb)(lm->shortname, + (address) lm->text, + (address) lm->text + lm->text_len, + param); + } + + return true; +} /////////////////////////////////////////////////////////////////////////////// // Externals @@ -322,8 +334,8 @@ void LoadedLibraries::print(outputStream* os) { if (!g_first) { reload_table(); } - for (entry_t* e = g_first; e; e = e->next) { - print_entry(e, os); + for (loaded_module_t* lm = g_first; lm; lm = lm->next) { + print_entry(lm, os); os->cr(); } } @@ -334,14 +346,17 @@ bool LoadedLibraries::find_for_text_address(const void* p, if (!g_first) { reload_table(); } - const entry_t* const e = find_entry_for_text_address(p); - if (e) { - if (info) { - *info = e->info; - } - return true; + + const loaded_module_t* const lm = find_entry_for_text_address(p); + if (!lm) { + return false; } - return false; + + if (info) { + memcpy(info, lm, sizeof(loaded_module_t)); + info->next = nullptr; + } + return true; } @@ -353,13 +368,30 @@ bool LoadedLibraries::find_for_data_address ( if (!g_first) { reload_table(); } - const entry_t* const e = find_entry_for_data_address(p); - if (e) { - if (info) { - *info = e->info; + + const loaded_module_t* const lm = find_entry_for_data_address(p); + if (!lm) { + return false; + } + + if (info) { + memcpy(info, lm, sizeof(loaded_module_t)); + info->next = nullptr; + } + return true; +} + +bool LoadedLibraries::for_each(os::LoadedModulesCallbackFunc cb, void* param) { + MiscUtils::AutoCritSect lck(&g_cs); + + if (!g_first) { + if (!reload_table()) { + // If the table is not loaded and cannot be initialized, + // then we must quit. + return false; } - return true; } - return false; + + return for_each_internal(cb, param); } diff --git a/src/hotspot/os/aix/loadlib_aix.hpp b/src/hotspot/os/aix/loadlib_aix.hpp index 354dccf4c7b651fd745bb5884931a4308e7430e2..18cd6e59864f88f1961070f31ae9bb565d4042ab 100644 --- a/src/hotspot/os/aix/loadlib_aix.hpp +++ b/src/hotspot/os/aix/loadlib_aix.hpp @@ -1,4 +1,5 @@ /* + * Copyright (c) 2022, 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. * @@ -32,6 +33,9 @@ #ifndef OS_AIX_LOADLIB_AIX_HPP #define OS_AIX_LOADLIB_AIX_HPP +#include "misc_aix.hpp" +#include "runtime/os.hpp" + #include class outputStream; @@ -66,6 +70,9 @@ struct loaded_module_t { // True if this module is part of the vm. bool is_in_vm; + // Next item in the list, or NULL if no such item exits + loaded_module_t* next; + }; // This class is a singleton holding a map of all loaded binaries @@ -99,6 +106,11 @@ class LoadedLibraries // Output debug info static void print(outputStream* os); + // Apply the callback to each loaded_module_t in the list + // Return false if module table is empty and cannot be loaded. + static bool for_each(os::LoadedModulesCallbackFunc cb, void* param); + }; + #endif // OS_AIX_LOADLIB_AIX_HPP diff --git a/src/hotspot/os/aix/osThread_aix.hpp b/src/hotspot/os/aix/osThread_aix.hpp index 0c8706d4add55aa6c4c5dfda0e30141bf675cb24..79e60b82e4cf6df2d3be7080426414cca3944714 100644 --- a/src/hotspot/os/aix/osThread_aix.hpp +++ b/src/hotspot/os/aix/osThread_aix.hpp @@ -63,13 +63,6 @@ // Used for debugging, return a unique integer for each thread. int thread_identifier() const { return _thread_id; } #endif -#ifdef ASSERT - // We expect no reposition failures so kill vm if we get one. - // - bool valid_reposition_failure() { - return false; - } -#endif // ASSERT tid_t kernel_thread_id() const { return _kernel_thread_id; } diff --git a/src/hotspot/os/aix/os_aix.cpp b/src/hotspot/os/aix/os_aix.cpp index df8563067e43e7d103d52a64e581b23e9e8bbec0..b586da9a78d43759ed172f0040d30c896ac6af69 100644 --- a/src/hotspot/os/aix/os_aix.cpp +++ b/src/hotspot/os/aix/os_aix.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2022, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, 2021 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -741,7 +741,7 @@ bool os::create_thread(Thread* thread, ThreadType thr_type, assert(thread->osthread() == NULL, "caller responsible"); // Allocate the OSThread object. - OSThread* osthread = new OSThread(NULL, NULL); + OSThread* osthread = new OSThread(); if (osthread == NULL) { return false; } @@ -855,7 +855,7 @@ bool os::create_attached_thread(JavaThread* thread) { #endif // Allocate the OSThread object - OSThread* osthread = new OSThread(NULL, NULL); + OSThread* osthread = new OSThread(); if (osthread == NULL) { return false; @@ -1131,7 +1131,11 @@ void os::get_summary_os_info(char* buf, size_t buflen) { } int os::get_loaded_modules_info(os::LoadedModulesCallbackFunc callback, void *param) { - // Not yet implemented. + + if (!LoadedLibraries::for_each(callback, param)) { + return -1; + } + return 0; } diff --git a/src/hotspot/os/aix/os_perf_aix.cpp b/src/hotspot/os/aix/os_perf_aix.cpp index 15eca737fdf9ae8044cd7619f30c73c52bb41f43..ad031de3cdc8f2d4e137ba8ca87107969162dcab 100644 --- a/src/hotspot/os/aix/os_perf_aix.cpp +++ b/src/hotspot/os/aix/os_perf_aix.cpp @@ -1,5 +1,6 @@ /* - * Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, IBM Corp. * 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,198 +25,42 @@ #include "precompiled.hpp" #include "jvm.h" +#include "libperfstat_aix.hpp" #include "memory/allocation.inline.hpp" +#include "memory/resourceArea.hpp" #include "os_aix.inline.hpp" #include "runtime/os.hpp" #include "runtime/os_perf.hpp" +#include "runtime/vm_version.hpp" +#include "utilities/debug.hpp" #include "utilities/globalDefinitions.hpp" -#include CPU_HEADER(vm_version_ext) - -#include -#include -#include +#include +#include #include +#include +#include +#include +#include #include +#include #include -#include #include -#include +#include #include -#include -#include -#include - -/** - /proc/[number]/stat - Status information about the process. This is used by ps(1). It is defined in /usr/src/linux/fs/proc/array.c. - - The fields, in order, with their proper scanf(3) format specifiers, are: - - 1. pid %d The process id. - - 2. comm %s - The filename of the executable, in parentheses. This is visible whether or not the executable is swapped out. - - 3. state %c - One character from the string "RSDZTW" where R is running, S is sleeping in an interruptible wait, D is waiting in uninterruptible disk - sleep, Z is zombie, T is traced or stopped (on a signal), and W is paging. - - 4. ppid %d - The PID of the parent. - - 5. pgrp %d - The process group ID of the process. - - 6. session %d - The session ID of the process. - - 7. tty_nr %d - The tty the process uses. - - 8. tpgid %d - The process group ID of the process which currently owns the tty that the process is connected to. - - 9. flags %lu - The flags of the process. The math bit is decimal 4, and the traced bit is decimal 10. - - 10. minflt %lu - The number of minor faults the process has made which have not required loading a memory page from disk. - - 11. cminflt %lu - The number of minor faults that the process's waited-for children have made. - - 12. majflt %lu - The number of major faults the process has made which have required loading a memory page from disk. - - 13. cmajflt %lu - The number of major faults that the process's waited-for children have made. - - 14. utime %lu - The number of jiffies that this process has been scheduled in user mode. - - 15. stime %lu - The number of jiffies that this process has been scheduled in kernel mode. - - 16. cutime %ld - The number of jiffies that this process's waited-for children have been scheduled in user mode. (See also times(2).) - - 17. cstime %ld - The number of jiffies that this process' waited-for children have been scheduled in kernel mode. - - 18. priority %ld - The standard nice value, plus fifteen. The value is never negative in the kernel. - - 19. nice %ld - The nice value ranges from 19 (nicest) to -19 (not nice to others). - - 20. 0 %ld This value is hard coded to 0 as a placeholder for a removed field. - - 21. itrealvalue %ld - The time in jiffies before the next SIGALRM is sent to the process due to an interval timer. - - 22. starttime %lu - The time in jiffies the process started after system boot. - - 23. vsize %lu - Virtual memory size in bytes. - - 24. rss %ld - Resident Set Size: number of pages the process has in real memory, minus 3 for administrative purposes. This is just the pages which count - towards text, data, or stack space. This does not include pages which have not been demand-loaded in, or which are swapped out. - - 25. rlim %lu - Current limit in bytes on the rss of the process (usually 4294967295 on i386). - - 26. startcode %lu - The address above which program text can run. - - 27. endcode %lu - The address below which program text can run. - - 28. startstack %lu - The address of the start of the stack. - - 29. kstkesp %lu - The current value of esp (stack pointer), as found in the kernel stack page for the process. - - 30. kstkeip %lu - The current EIP (instruction pointer). - - 31. signal %lu - The bitmap of pending signals (usually 0). - - 32. blocked %lu - The bitmap of blocked signals (usually 0, 2 for shells). - - 33. sigignore %lu - The bitmap of ignored signals. - - 34. sigcatch %lu - The bitmap of catched signals. - - 35. wchan %lu - This is the "channel" in which the process is waiting. It is the address of a system call, and can be looked up in a namelist if you need - a textual name. (If you have an up-to-date /etc/psdatabase, then try ps -l to see the WCHAN field in action.) - - 36. nswap %lu - Number of pages swapped - not maintained. - - 37. cnswap %lu - Cumulative nswap for child processes. - - 38. exit_signal %d - Signal to be sent to parent when we die. - - 39. processor %d - CPU number last executed on. - - - - ///// SSCANF FORMAT STRING. Copy and use. - -field: 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 -format: %d %s %c %d %d %d %d %d %lu %lu %lu %lu %lu %lu %lu %ld %ld %ld %ld %ld %ld %lu %lu %ld %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %d %d - - -*/ - -/** - * For platforms that have them, when declaring - * a printf-style function, - * formatSpec is the parameter number (starting at 1) - * that is the format argument ("%d pid %s") - * params is the parameter number where the actual args to - * the format starts. If the args are in a va_list, this - * should be 0. - */ -#ifndef PRINTF_ARGS -# define PRINTF_ARGS(formatSpec, params) ATTRIBUTE_PRINTF(formatSpec, params) -#endif - -#ifndef SCANF_ARGS -# define SCANF_ARGS(formatSpec, params) ATTRIBUTE_SCANF(formatSpec, params) -#endif - -#ifndef _PRINTFMT_ -# define _PRINTFMT_ -#endif - -#ifndef _SCANFMT_ -# define _SCANFMT_ -#endif - +#include -struct CPUPerfTicks { - uint64_t used; - uint64_t usedKernel; - uint64_t total; -}; +typedef struct { + u_longlong_t user; + u_longlong_t sys; + u_longlong_t idle; + u_longlong_t wait; +} cpu_tick_store_t; -typedef enum { - CPU_LOAD_VM_ONLY, - CPU_LOAD_GLOBAL, -} CpuLoadTarget; +typedef struct { + double utime; + double stime; +} jvm_time_store_t; enum { UNDETECTED, @@ -224,318 +69,299 @@ enum { BAREMETAL }; -struct CPUPerfCounters { - int nProcs; - CPUPerfTicks jvmTicks; - CPUPerfTicks* cpus; -}; - -static double get_cpu_load(int which_logical_cpu, CPUPerfCounters* counters, double* pkernelLoad, CpuLoadTarget target); - -/** reads /proc//stat data, with some checks and some skips. - * Ensure that 'fmt' does _NOT_ contain the first two "%d %s" +/** + * Get info for requested PID from /proc//psinfo file */ -static int SCANF_ARGS(2, 0) vread_statdata(const char* procfile, _SCANFMT_ const char* fmt, va_list args) { - FILE*f; - int n; - char buf[2048]; - - if ((f = fopen(procfile, "r")) == NULL) { - return -1; - } - - if ((n = fread(buf, 1, sizeof(buf), f)) != -1) { - char *tmp; - - buf[n-1] = '\0'; - /** skip through pid and exec name. */ - if ((tmp = strrchr(buf, ')')) != NULL) { - // skip the ')' and the following space - // but check that buffer is long enough - tmp += 2; - if (tmp < buf + n) { - n = vsscanf(tmp, fmt, args); - } - } - } +static bool read_psinfo(const u_longlong_t& pid, psinfo_t& psinfo) { + static size_t BUF_LENGTH = 32 + sizeof(u_longlong_t); - fclose(f); + FILE* fp; + char buf[BUF_LENGTH]; + int len; - return n; -} + jio_snprintf(buf, BUF_LENGTH, "/proc/%llu/psinfo", pid); + fp = fopen(buf, "r"); -static int SCANF_ARGS(2, 3) read_statdata(const char* procfile, _SCANFMT_ const char* fmt, ...) { - int n; - va_list args; + if (!fp) { + return false; + } - va_start(args, fmt); - n = vread_statdata(procfile, fmt, args); - va_end(args); - return n; + len = fread(&psinfo, 1, sizeof(psinfo_t), fp); + return len == sizeof(psinfo_t); } /** - * on Linux we got the ticks related information from /proc/stat - * this does not work on AIX, libperfstat might be an alternative + * Get and set ticks for the specified lcpu */ -static OSReturn get_total_ticks(int which_logical_cpu, CPUPerfTicks* pticks) { - return OS_ERR; -} +static OSReturn get_lcpu_ticks(perfstat_id_t* lcpu_name, cpu_tick_store_t* pticks) { + perfstat_cpu_t lcpu_stats; -/** read user and system ticks from a named procfile, assumed to be in 'stat' format then. */ -static int read_ticks(const char* procfile, uint64_t* userTicks, uint64_t* systemTicks) { - return read_statdata(procfile, "%*c %*d %*d %*d %*d %*d %*u %*u %*u %*u %*u " UINT64_FORMAT " " UINT64_FORMAT, - userTicks, systemTicks); -} + if (!pticks) { + return OS_ERR; + } -/** - * Return the number of ticks spent in any of the processes belonging - * to the JVM on any CPU. - */ -static OSReturn get_jvm_ticks(CPUPerfTicks* pticks) { - return OS_ERR; + // populate cpu_stats + if (libperfstat::perfstat_cpu(lcpu_name, &lcpu_stats, sizeof(perfstat_cpu_t), 1) < 1) { + memset(pticks, 0, sizeof(cpu_tick_store_t)); + return OS_ERR; + } + + pticks->user = lcpu_stats.user; + pticks->sys = lcpu_stats.sys; + pticks->idle = lcpu_stats.idle; + pticks->wait = lcpu_stats.wait; + + return OS_OK; } /** - * Return the load of the CPU as a double. 1.0 means the CPU process uses all - * available time for user or system processes, 0.0 means the CPU uses all time - * being idle. - * - * Returns a negative value if there is a problem in determining the CPU load. + * Return CPU load caused by the currently executing process (the jvm). */ -static double get_cpu_load(int which_logical_cpu, CPUPerfCounters* counters, double* pkernelLoad, CpuLoadTarget target) { - uint64_t udiff, kdiff, tdiff; - CPUPerfTicks* pticks; - CPUPerfTicks tmp; - double user_load; +static OSReturn get_jvm_load(double* jvm_uload, double* jvm_sload) { + static clock_t ticks_per_sec = sysconf(_SC_CLK_TCK); + static u_longlong_t last_timebase = 0; - *pkernelLoad = 0.0; + perfstat_process_t jvm_stats; + perfstat_id_t name_holder; + u_longlong_t timebase_diff; - if (target == CPU_LOAD_VM_ONLY) { - pticks = &counters->jvmTicks; - } else if (-1 == which_logical_cpu) { - pticks = &counters->cpus[counters->nProcs]; - } else { - pticks = &counters->cpus[which_logical_cpu]; + jio_snprintf(name_holder.name, IDENTIFIER_LENGTH, "%d", getpid()); + if (libperfstat::perfstat_process(&name_holder, &jvm_stats, sizeof(perfstat_process_t), 1) < 1) { + return OS_ERR; } - tmp = *pticks; + // Update timebase + timebase_diff = jvm_stats.last_timebase - last_timebase; + last_timebase = jvm_stats.last_timebase; - if (target == CPU_LOAD_VM_ONLY) { - if (get_jvm_ticks(pticks) != OS_OK) { - return -1.0; - } - } else if (get_total_ticks(which_logical_cpu, pticks) != OS_OK) { - return -1.0; + if (jvm_uload) { + *jvm_uload = jvm_stats.ucpu_time / timebase_diff; + } + if (jvm_sload) { + *jvm_sload = jvm_stats.scpu_time / timebase_diff; } - // seems like we sometimes end up with less kernel ticks when - // reading /proc/self/stat a second time, timing issue between cpus? - if (pticks->usedKernel < tmp.usedKernel) { - kdiff = 0; - } else { - kdiff = pticks->usedKernel - tmp.usedKernel; + return OS_OK; +} + +static void update_prev_time(jvm_time_store_t* from, jvm_time_store_t* to) { + if (from && to) { + memcpy(to, from, sizeof(jvm_time_store_t)); } - tdiff = pticks->total - tmp.total; - udiff = pticks->used - tmp.used; +} - if (tdiff == 0) { - return 0.0; - } else if (tdiff < (udiff + kdiff)) { - tdiff = udiff + kdiff; +static void update_prev_ticks(cpu_tick_store_t* from, cpu_tick_store_t* to) { + if (from && to) { + memcpy(to, from, sizeof(cpu_tick_store_t)); } - *pkernelLoad = (kdiff / (double)tdiff); - // BUG9044876, normalize return values to sane values - *pkernelLoad = MAX2(*pkernelLoad, 0.0); - *pkernelLoad = MIN2(*pkernelLoad, 1.0); +} - user_load = (udiff / (double)tdiff); - user_load = MAX2(user_load, 0.0); - user_load = MIN2(user_load, 1.0); +/** + * Calculate the current system load from current ticks using previous ticks as a starting point. + */ +static void calculate_updated_load(cpu_tick_store_t* update, cpu_tick_store_t* prev, double* load) { + cpu_tick_store_t diff; - return user_load; -} + if (update && prev && load) { + diff.user = update->user - prev->user; + diff.sys = update->sys - prev->sys; + diff.idle = update->idle - prev->idle; + diff.wait = update->wait - prev->wait; -static int SCANF_ARGS(1, 2) parse_stat(_SCANFMT_ const char* fmt, ...) { - return OS_ERR; + *load = 1.0 - diff.idle/(diff.sys + diff.user + diff.idle + diff.wait); + } } -static int get_noof_context_switches(uint64_t* switches) { - return parse_stat("ctxt " UINT64_FORMAT "\n", switches); -} +/** + * Look up lcpu names for later re-use. + */ +static bool populate_lcpu_names(int ncpus, perfstat_id_t* lcpu_names) { + ResourceMark rm; + perfstat_cpu_t* all_lcpu_stats; + perfstat_cpu_t* lcpu_stats; + perfstat_id_t name_holder; -/** returns boot time in _seconds_ since epoch */ -static int get_boot_time(uint64_t* time) { - return parse_stat("btime " UINT64_FORMAT "\n", time); -} + assert(lcpu_names, "Names pointer NULL"); -static int perf_context_switch_rate(double* rate) { - static pthread_mutex_t contextSwitchLock = PTHREAD_MUTEX_INITIALIZER; - static uint64_t bootTime; - static uint64_t lastTimeNanos; - static uint64_t lastSwitches; - static double lastRate; + strncpy(name_holder.name, FIRST_CPU, IDENTIFIER_LENGTH); - uint64_t bt = 0; - int res = 0; + all_lcpu_stats = NEW_RESOURCE_ARRAY(perfstat_cpu_t, ncpus); - // First time through bootTime will be zero. - if (bootTime == 0) { - uint64_t tmp; - if (get_boot_time(&tmp) < 0) { - return OS_ERR; - } - bt = tmp * 1000; + // If perfstat_cpu does not return the expected number of names, signal error to caller + if (ncpus != libperfstat::perfstat_cpu(&name_holder, all_lcpu_stats, sizeof(perfstat_cpu_t), ncpus)) { + return false; } - res = OS_OK; + for (int n = 0; n < ncpus; n++) { + strncpy(lcpu_names[n].name, all_lcpu_stats[n].name, IDENTIFIER_LENGTH); + } - pthread_mutex_lock(&contextSwitchLock); - { + return true; +} - uint64_t sw; - s8 t, d; +/** + * Calculates the context switch rate. + * (Context Switches / Tick) * (Tick / s) = Context Switches per second + */ +static OSReturn perf_context_switch_rate(double* rate) { + static clock_t ticks_per_sec = sysconf(_SC_CLK_TCK); - if (bootTime == 0) { - // First interval is measured from boot time which is - // seconds since the epoch. Thereafter we measure the - // elapsed time using javaTimeNanos as it is monotonic- - // non-decreasing. - lastTimeNanos = os::javaTimeNanos(); - t = os::javaTimeMillis(); - d = t - bt; - // keep bootTime zero for now to use as a first-time-through flag - } else { - t = os::javaTimeNanos(); - d = nanos_to_millis(t - lastTimeNanos); - } + u_longlong_t ticks; + perfstat_cpu_total_t cpu_stats; - if (d == 0) { - *rate = lastRate; - } else if (get_noof_context_switches(&sw) == 0) { - *rate = ( (double)(sw - lastSwitches) / d ) * 1000; - lastRate = *rate; - lastSwitches = sw; - if (bootTime != 0) { - lastTimeNanos = t; - } - } else { - *rate = 0; - res = OS_ERR; - } - if (*rate <= 0) { - *rate = 0; - lastRate = 0; - } + if (libperfstat::perfstat_cpu_total(NULL, &cpu_stats, sizeof(perfstat_cpu_total_t), 1) < 0) { + return OS_ERR; + } - if (bootTime == 0) { - bootTime = bt; - } - } - pthread_mutex_unlock(&contextSwitchLock); + ticks = cpu_stats.user + cpu_stats.sys + cpu_stats.idle + cpu_stats.wait; + *rate = (cpu_stats.pswitch / ticks) * ticks_per_sec; - return res; + return OS_OK; } class CPUPerformanceInterface::CPUPerformance : public CHeapObj { - friend class CPUPerformanceInterface; private: - CPUPerfCounters _counters; - - int cpu_load(int which_logical_cpu, double* cpu_load); - int context_switch_rate(double* rate); - int cpu_load_total_process(double* cpu_load); - int cpu_loads_process(double* pjvmUserLoad, double* pjvmKernelLoad, double* psystemTotalLoad); + int _ncpus; + perfstat_id_t* _lcpu_names; + cpu_tick_store_t* _prev_ticks; public: CPUPerformance(); bool initialize(); ~CPUPerformance(); + + int cpu_load(int which_logical_cpu, double* cpu_load); + int context_switch_rate(double* rate); + int cpu_load_total_process(double* cpu_load); + int cpu_loads_process(double* pjvmUserLoad, double* pjvmKernelLoad, double* psystemTotalLoad); }; -CPUPerformanceInterface::CPUPerformance::CPUPerformance() { - _counters.nProcs = os::active_processor_count(); - _counters.cpus = NULL; -} +CPUPerformanceInterface::CPUPerformance::CPUPerformance(): + _ncpus(0), + _lcpu_names(NULL), + _prev_ticks(NULL) {} bool CPUPerformanceInterface::CPUPerformance::initialize() { - size_t array_entry_count = _counters.nProcs + 1; - _counters.cpus = NEW_C_HEAP_ARRAY(CPUPerfTicks, array_entry_count, mtInternal); - memset(_counters.cpus, 0, array_entry_count * sizeof(*_counters.cpus)); + perfstat_cpu_total_t cpu_stats; - // For the CPU load total - get_total_ticks(-1, &_counters.cpus[_counters.nProcs]); - - // For each CPU - for (int i = 0; i < _counters.nProcs; i++) { - get_total_ticks(i, &_counters.cpus[i]); + if (libperfstat::perfstat_cpu_total(NULL, &cpu_stats, sizeof(perfstat_cpu_total_t), 1) < 0) { + return false; + } + if (cpu_stats.ncpus <= 0) { + return false; } - // For JVM load - get_jvm_ticks(&_counters.jvmTicks); - // initialize context switch system - // the double is only for init - double init_ctx_switch_rate; - perf_context_switch_rate(&init_ctx_switch_rate); + _ncpus = cpu_stats.ncpus; + _lcpu_names = NEW_C_HEAP_ARRAY(perfstat_id_t, _ncpus, mtInternal); + + _prev_ticks = NEW_C_HEAP_ARRAY(cpu_tick_store_t, _ncpus, mtInternal); + // Set all prev-tick values to 0 + memset(_prev_ticks, 0, _ncpus*sizeof(cpu_tick_store_t)); + + if (!populate_lcpu_names(_ncpus, _lcpu_names)) { + return false; + } return true; } CPUPerformanceInterface::CPUPerformance::~CPUPerformance() { - if (_counters.cpus != NULL) { - FREE_C_HEAP_ARRAY(char, _counters.cpus); + if (_lcpu_names) { + FREE_C_HEAP_ARRAY(perfstat_id_t, _lcpu_names); + } + if (_prev_ticks) { + FREE_C_HEAP_ARRAY(cpu_tick_store_t, _prev_ticks); } } -int CPUPerformanceInterface::CPUPerformance::cpu_load(int which_logical_cpu, double* cpu_load) { - double u, s; - u = get_cpu_load(which_logical_cpu, &_counters, &s, CPU_LOAD_GLOBAL); - if (u < 0) { - *cpu_load = 0.0; +/** + * Get CPU load for all processes on specified logical CPU. + */ +int CPUPerformanceInterface::CPUPerformance::cpu_load(int lcpu_number, double* lcpu_load) { + cpu_tick_store_t ticks; + + assert(lcpu_load != NULL, "NULL pointer passed to cpu_load"); + assert(lcpu_number < _ncpus, "Invalid lcpu passed to cpu_load"); + + if (get_lcpu_ticks(&_lcpu_names[lcpu_number], &ticks) == OS_ERR) { + *lcpu_load = -1.0; return OS_ERR; } - // Cap total systemload to 1.0 - *cpu_load = MIN2((u + s), 1.0); + + calculate_updated_load(&ticks, &_prev_ticks[lcpu_number], lcpu_load); + update_prev_ticks(&ticks, &_prev_ticks[lcpu_number]); + return OS_OK; } -int CPUPerformanceInterface::CPUPerformance::cpu_load_total_process(double* cpu_load) { - double u, s; - u = get_cpu_load(-1, &_counters, &s, CPU_LOAD_VM_ONLY); - if (u < 0) { - *cpu_load = 0.0; - return OS_ERR; +/** + * Get CPU load for all processes on all CPUs. + */ +int CPUPerformanceInterface::CPUPerformance::cpu_load_total_process(double* total_load) { + cpu_tick_store_t total_ticks; + cpu_tick_store_t prev_total_ticks; + + assert(total_load != NULL, "NULL pointer passed to cpu_load_total_process"); + + memset(&total_ticks, 0, sizeof(cpu_tick_store_t)); + memset(&prev_total_ticks, 0, sizeof(cpu_tick_store_t)); + + for (int lcpu = 0; lcpu < _ncpus; lcpu++) { + cpu_tick_store_t lcpu_ticks; + + if (get_lcpu_ticks(&_lcpu_names[lcpu], &lcpu_ticks) == OS_ERR) { + *total_load = -1.0; + return OS_ERR; + } + + total_ticks.user = lcpu_ticks.user; + total_ticks.sys = lcpu_ticks.sys; + total_ticks.idle = lcpu_ticks.idle; + total_ticks.wait = lcpu_ticks.wait; + + prev_total_ticks.user += _prev_ticks[lcpu].user; + prev_total_ticks.sys += _prev_ticks[lcpu].sys; + prev_total_ticks.idle += _prev_ticks[lcpu].idle; + prev_total_ticks.wait += _prev_ticks[lcpu].wait; + + update_prev_ticks(&lcpu_ticks, &_prev_ticks[lcpu]); } - *cpu_load = u + s; + + calculate_updated_load(&total_ticks, &prev_total_ticks, total_load); + return OS_OK; } +/** + * Get CPU load for all CPUs. + * + * Set values for: + * - pjvmUserLoad: CPU load due to jvm process in user mode. Jvm process assumed to be self process + * - pjvmKernelLoad: CPU load due to jvm process in kernel mode. Jvm process assumed to be self process + * - psystemTotalLoad: Total CPU load from all process on all logical CPUs + * + * Note: If any of the above loads cannot be calculated, this procedure returns OS_ERR and any load that could not be calculated is set to -1 + * + */ int CPUPerformanceInterface::CPUPerformance::cpu_loads_process(double* pjvmUserLoad, double* pjvmKernelLoad, double* psystemTotalLoad) { - double u, s, t; + double u, k, t; - assert(pjvmUserLoad != NULL, "pjvmUserLoad not inited"); - assert(pjvmKernelLoad != NULL, "pjvmKernelLoad not inited"); - assert(psystemTotalLoad != NULL, "psystemTotalLoad not inited"); - - u = get_cpu_load(-1, &_counters, &s, CPU_LOAD_VM_ONLY); - if (u < 0) { - *pjvmUserLoad = 0.0; - *pjvmKernelLoad = 0.0; - *psystemTotalLoad = 0.0; - return OS_ERR; + int retval = OS_OK; + if (get_jvm_load(&u, &k) == OS_ERR || cpu_load_total_process(&t) == OS_ERR) { + retval = OS_ERR; } - cpu_load(-1, &t); - // clamp at user+system and 1.0 - if (u + s > t) { - t = MIN2(u + s, 1.0); + if (pjvmUserLoad) { + *pjvmUserLoad = u; + } + if (pjvmKernelLoad) { + *pjvmKernelLoad = k; + } + if (psystemTotalLoad) { + *psystemTotalLoad = t; } - *pjvmUserLoad = u; - *pjvmKernelLoad = s; - *psystemTotalLoad = t; - - return OS_OK; + return retval; } int CPUPerformanceInterface::CPUPerformance::context_switch_rate(double* rate) { @@ -574,267 +400,85 @@ int CPUPerformanceInterface::context_switch_rate(double* rate) const { } class SystemProcessInterface::SystemProcesses : public CHeapObj { - friend class SystemProcessInterface; - private: - class ProcessIterator : public CHeapObj { - friend class SystemProcessInterface::SystemProcesses; - private: - DIR* _dir; - struct dirent* _entry; - bool _valid; - char _exeName[PATH_MAX]; - char _exePath[PATH_MAX]; - - ProcessIterator(); - ~ProcessIterator(); - bool initialize(); - - bool is_valid() const { return _valid; } - bool is_valid_entry(struct dirent* entry) const; - bool is_dir(const char* name) const; - int fsize(const char* name, uint64_t& size) const; - - char* allocate_string(const char* str) const; - void get_exe_name(); - char* get_exe_path(); - char* get_cmdline(); - - int current(SystemProcess* process_info); - int next_process(); - }; - - ProcessIterator* _iterator; + private: + char* allocate_string(const char* str) const; + + public: SystemProcesses(); bool initialize(); ~SystemProcesses(); - - //information about system processes int system_processes(SystemProcess** system_processes, int* no_of_sys_processes) const; }; -bool SystemProcessInterface::SystemProcesses::ProcessIterator::is_dir(const char* name) const { - struct stat mystat; - int ret_val = 0; - - ret_val = stat(name, &mystat); - if (ret_val < 0) { - return false; - } - ret_val = S_ISDIR(mystat.st_mode); - return ret_val > 0; -} - -int SystemProcessInterface::SystemProcesses::ProcessIterator::fsize(const char* name, uint64_t& size) const { - assert(name != NULL, "name pointer is NULL!"); - size = 0; - struct stat fbuf; - - if (stat(name, &fbuf) < 0) { - return OS_ERR; - } - size = fbuf.st_size; - return OS_OK; -} - -// if it has a numeric name, is a directory and has a 'stat' file in it -bool SystemProcessInterface::SystemProcesses::ProcessIterator::is_valid_entry(struct dirent* entry) const { - char buffer[PATH_MAX]; - uint64_t size = 0; - - if (atoi(entry->d_name) != 0) { - jio_snprintf(buffer, PATH_MAX, "/proc/%s", entry->d_name); - buffer[PATH_MAX - 1] = '\0'; - - if (is_dir(buffer)) { - jio_snprintf(buffer, PATH_MAX, "/proc/%s/stat", entry->d_name); - buffer[PATH_MAX - 1] = '\0'; - if (fsize(buffer, size) != OS_ERR) { - return true; - } - } - } - return false; -} - -// get exe-name from /proc//stat -void SystemProcessInterface::SystemProcesses::ProcessIterator::get_exe_name() { - FILE* fp; - char buffer[PATH_MAX]; - - jio_snprintf(buffer, PATH_MAX, "/proc/%s/stat", _entry->d_name); - buffer[PATH_MAX - 1] = '\0'; - if ((fp = fopen(buffer, "r")) != NULL) { - if (fgets(buffer, PATH_MAX, fp) != NULL) { - char* start, *end; - // exe-name is between the first pair of ( and ) - start = strchr(buffer, '('); - if (start != NULL && start[1] != '\0') { - start++; - end = strrchr(start, ')'); - if (end != NULL) { - size_t len; - len = MIN2(end - start, sizeof(_exeName) - 1); - memcpy(_exeName, start, len); - _exeName[len] = '\0'; - } - } - } - fclose(fp); - } +SystemProcessInterface::SystemProcesses::SystemProcesses() { } -// get command line from /proc//cmdline -char* SystemProcessInterface::SystemProcesses::ProcessIterator::get_cmdline() { - FILE* fp; - char buffer[PATH_MAX]; - char* cmdline = NULL; - - jio_snprintf(buffer, PATH_MAX, "/proc/%s/cmdline", _entry->d_name); - buffer[PATH_MAX - 1] = '\0'; - if ((fp = fopen(buffer, "r")) != NULL) { - size_t size = 0; - char dummy; - - // find out how long the file is (stat always returns 0) - while (fread(&dummy, 1, 1, fp) == 1) { - size++; - } - if (size > 0) { - cmdline = NEW_C_HEAP_ARRAY(char, size + 1, mtInternal); - cmdline[0] = '\0'; - if (fseek(fp, 0, SEEK_SET) == 0) { - if (fread(cmdline, 1, size, fp) == size) { - // the file has the arguments separated by '\0', - // so we translate '\0' to ' ' - for (size_t i = 0; i < size; i++) { - if (cmdline[i] == '\0') { - cmdline[i] = ' '; - } - } - cmdline[size] = '\0'; - } - } - } - fclose(fp); - } - return cmdline; +bool SystemProcessInterface::SystemProcesses::initialize() { + return true; } -// get full path to exe from /proc//exe symlink -char* SystemProcessInterface::SystemProcesses::ProcessIterator::get_exe_path() { - char buffer[PATH_MAX]; - - jio_snprintf(buffer, PATH_MAX, "/proc/%s/exe", _entry->d_name); - buffer[PATH_MAX - 1] = '\0'; - return realpath(buffer, _exePath); +SystemProcessInterface::SystemProcesses::~SystemProcesses() { } -char* SystemProcessInterface::SystemProcesses::ProcessIterator::allocate_string(const char* str) const { +char* SystemProcessInterface::SystemProcesses::allocate_string(const char* str) const { if (str != NULL) { return os::strdup_check_oom(str, mtInternal); } return NULL; } -int SystemProcessInterface::SystemProcesses::ProcessIterator::current(SystemProcess* process_info) { - if (!is_valid()) { - return OS_ERR; - } - - process_info->set_pid(atoi(_entry->d_name)); - - get_exe_name(); - process_info->set_name(allocate_string(_exeName)); +int SystemProcessInterface::SystemProcesses::system_processes(SystemProcess** system_processes, int* nprocs) const { + ResourceMark rm; + perfstat_process_t* proc_stats; + SystemProcess* head; + perfstat_id_t name_holder; + int records_allocated = 0; - if (get_exe_path() != NULL) { - process_info->set_path(allocate_string(_exePath)); - } - - char* cmdline = NULL; - cmdline = get_cmdline(); - if (cmdline != NULL) { - process_info->set_command_line(allocate_string(cmdline)); - FREE_C_HEAP_ARRAY(char, cmdline); - } + assert(nprocs != NULL, "system_processes counter pointers is NULL!"); - return OS_OK; -} + head = NULL; + *nprocs = 0; + strncpy(name_holder.name, "", IDENTIFIER_LENGTH); -int SystemProcessInterface::SystemProcesses::ProcessIterator::next_process() { - if (!is_valid()) { + // calling perfstat_(NULL, NULL, _, 0) returns number of available records + *nprocs = libperfstat::perfstat_process(NULL, NULL, sizeof(perfstat_process_t), 0); + if(*nprocs < 1) { + // expect at least 1 process return OS_ERR; } - do { - _entry = os::readdir(_dir); - if (_entry == NULL) { - // Error or reached end. Could use errno to distinguish those cases. - _valid = false; - return OS_ERR; - } - } while(!is_valid_entry(_entry)); - - _valid = true; - return OS_OK; -} - -SystemProcessInterface::SystemProcesses::ProcessIterator::ProcessIterator() { - _dir = NULL; - _entry = NULL; - _valid = false; -} + records_allocated = *nprocs; + proc_stats = NEW_RESOURCE_ARRAY(perfstat_process_t, records_allocated); -bool SystemProcessInterface::SystemProcesses::ProcessIterator::initialize() { - // Not yet implemented. - return false; -} + // populate stats && set the actual number of procs that have been populated + // should never be higher than requested, but may be lower due to process death + *nprocs = libperfstat::perfstat_process(&name_holder, proc_stats, sizeof(perfstat_process_t), records_allocated); -SystemProcessInterface::SystemProcesses::ProcessIterator::~ProcessIterator() { - if (_dir != NULL) { - os::closedir(_dir); - } -} + for (int n = 0; n < *nprocs; n++) { + psinfo_t psinfo; + // Note: SystemProcess with free these in its dtor. + char* name = NEW_C_HEAP_ARRAY(char, IDENTIFIER_LENGTH, mtInternal); + char* exe_name = NEW_C_HEAP_ARRAY(char, PRFNSZ, mtInternal); + char* cmd_line = NEW_C_HEAP_ARRAY(char, PRARGSZ, mtInternal); -SystemProcessInterface::SystemProcesses::SystemProcesses() { - _iterator = NULL; -} + strncpy(name, proc_stats[n].proc_name, IDENTIFIER_LENGTH); -bool SystemProcessInterface::SystemProcesses::initialize() { - _iterator = new SystemProcessInterface::SystemProcesses::ProcessIterator(); - return _iterator->initialize(); -} + if (read_psinfo(proc_stats[n].pid, psinfo)) { + strncpy(exe_name, psinfo.pr_fname, PRFNSZ); + strncpy(cmd_line, psinfo.pr_psargs, PRARGSZ); + } -SystemProcessInterface::SystemProcesses::~SystemProcesses() { - if (_iterator != NULL) { - delete _iterator; + // create a new SystemProcess with next pointing to current head. + SystemProcess* sp = new SystemProcess(proc_stats[n].pid, + name, + exe_name, + cmd_line, + head); + // update head. + head = sp; } -} - -int SystemProcessInterface::SystemProcesses::system_processes(SystemProcess** system_processes, int* no_of_sys_processes) const { - assert(system_processes != NULL, "system_processes pointer is NULL!"); - assert(no_of_sys_processes != NULL, "system_processes counter pointers is NULL!"); - assert(_iterator != NULL, "iterator is NULL!"); - - // initialize pointers - *no_of_sys_processes = 0; - *system_processes = NULL; - while (_iterator->is_valid()) { - SystemProcess* tmp = new SystemProcess(); - _iterator->current(tmp); - - //if already existing head - if (*system_processes != NULL) { - //move "first to second" - tmp->set_next(*system_processes); - } - // new head - *system_processes = tmp; - // increment - (*no_of_sys_processes)++; - // step forward - _iterator->next_process(); - } + *system_processes = head; return OS_OK; } @@ -863,11 +507,12 @@ CPUInformationInterface::CPUInformationInterface() { bool CPUInformationInterface::initialize() { _cpu_info = new CPUInformation(); - _cpu_info->set_number_of_hardware_threads(VM_Version_Ext::number_of_threads()); - _cpu_info->set_number_of_cores(VM_Version_Ext::number_of_cores()); - _cpu_info->set_number_of_sockets(VM_Version_Ext::number_of_sockets()); - _cpu_info->set_cpu_name(VM_Version_Ext::cpu_name()); - _cpu_info->set_cpu_description(VM_Version_Ext::cpu_description()); + VM_Version::initialize_cpu_information(); + _cpu_info->set_number_of_hardware_threads(VM_Version::number_of_threads()); + _cpu_info->set_number_of_cores(VM_Version::number_of_cores()); + _cpu_info->set_number_of_sockets(VM_Version::number_of_sockets()); + _cpu_info->set_cpu_name(VM_Version::cpu_name()); + _cpu_info->set_cpu_description(VM_Version::cpu_description()); return true; } @@ -897,29 +542,68 @@ int CPUInformationInterface::cpu_information(CPUInformation& cpu_info) { } class NetworkPerformanceInterface::NetworkPerformance : public CHeapObj { - friend class NetworkPerformanceInterface; + NONCOPYABLE(NetworkPerformance); + private: + char* allocate_string(const char* str) const; + + public: NetworkPerformance(); - NONCOPYABLE(NetworkPerformance); bool initialize(); ~NetworkPerformance(); int network_utilization(NetworkInterface** network_interfaces) const; }; -NetworkPerformanceInterface::NetworkPerformance::NetworkPerformance() { - -} +NetworkPerformanceInterface::NetworkPerformance::NetworkPerformance() {} bool NetworkPerformanceInterface::NetworkPerformance::initialize() { return true; } -NetworkPerformanceInterface::NetworkPerformance::~NetworkPerformance() { -} +NetworkPerformanceInterface::NetworkPerformance::~NetworkPerformance() {} + +int NetworkPerformanceInterface::NetworkPerformance::network_utilization(NetworkInterface** network_interfaces) const { + int n_records = 0; + perfstat_netinterface_t* net_stats; + perfstat_id_t name_holder; + int records_allocated = 0; + + assert(network_interfaces != NULL, "network_interfaces is NULL"); + + *network_interfaces = NULL; + strncpy(name_holder.name , FIRST_NETINTERFACE, IDENTIFIER_LENGTH); + + // calling perfstat_(NULL, NULL, _, 0) returns number of available records + if ((n_records = libperfstat::perfstat_netinterface(NULL, NULL, sizeof(perfstat_netinterface_t), 0)) < 0) { + return OS_ERR; + } -int NetworkPerformanceInterface::NetworkPerformance::network_utilization(NetworkInterface** network_interfaces) const -{ - return FUNCTIONALITY_NOT_IMPLEMENTED; + records_allocated = n_records; + net_stats = NEW_C_HEAP_ARRAY(perfstat_netinterface_t, records_allocated, mtInternal); + + n_records = libperfstat::perfstat_netinterface(&name_holder, net_stats, sizeof(perfstat_netinterface_t), n_records); + + // check for error + if (n_records < 0) { + FREE_C_HEAP_ARRAY(perfstat_netinterface_t, net_stats); + return OS_ERR; + } + + for (int i = 0; i < n_records; i++) { + // Create new Network interface *with current head as next node* + // Note: NetworkInterface makes copies of these string values into RA memory + // this means: + // (1) we are free to clean our values upon exiting this proc + // (2) we avoid using RA-alloced memory here (ie. do not use NEW_RESOURCE_ARRAY) + NetworkInterface* new_interface = new NetworkInterface(net_stats[i].name, + net_stats[i].ibytes, + net_stats[i].obytes, + *network_interfaces); + *network_interfaces = new_interface; + } + + FREE_C_HEAP_ARRAY(perfstat_netinterface_t, net_stats); + return OS_OK; } NetworkPerformanceInterface::NetworkPerformanceInterface() { diff --git a/src/hotspot/os/bsd/attachListener_bsd.cpp b/src/hotspot/os/bsd/attachListener_bsd.cpp index 9daad43dc7ad567dd87c9ce44b1363d18c4f5931..b8702c5aa763ef87658db1c1a77b898620d42459 100644 --- a/src/hotspot/os/bsd/attachListener_bsd.cpp +++ b/src/hotspot/os/bsd/attachListener_bsd.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -27,7 +27,6 @@ #include "runtime/interfaceSupport.inline.hpp" #include "runtime/os.inline.hpp" #include "services/attachListener.hpp" -#include "services/dtraceAttacher.hpp" #include #include diff --git a/src/hotspot/os/bsd/gc/z/zNUMA_bsd.cpp b/src/hotspot/os/bsd/gc/z/zNUMA_bsd.cpp index a0fe34c65041e9c60cdb14fadbdf0d66805a9477..e5b3895c44e6df677f612889573ff869abc2c66a 100644 --- a/src/hotspot/os/bsd/gc/z/zNUMA_bsd.cpp +++ b/src/hotspot/os/bsd/gc/z/zNUMA_bsd.cpp @@ -23,6 +23,7 @@ #include "precompiled.hpp" #include "gc/z/zNUMA.hpp" +#include "utilities/globalDefinitions.hpp" void ZNUMA::pd_initialize() { _enabled = false; diff --git a/src/hotspot/os/bsd/osThread_bsd.hpp b/src/hotspot/os/bsd/osThread_bsd.hpp index 8e7375d714566628a9c813d5c941d20a97a51790..731e046e529917743ff2f8f45d6e3e0b772b825c 100644 --- a/src/hotspot/os/bsd/osThread_bsd.hpp +++ b/src/hotspot/os/bsd/osThread_bsd.hpp @@ -67,14 +67,6 @@ intptr_t thread_identifier() const { return (intptr_t)_pthread_id; } #endif -#ifdef ASSERT - // We expect no reposition failures so kill vm if we get one. - // - bool valid_reposition_failure() { - return false; - } -#endif // ASSERT - pthread_t pthread_id() const { return _pthread_id; } diff --git a/src/hotspot/os/bsd/os_bsd.cpp b/src/hotspot/os/bsd/os_bsd.cpp index ef7e6e3e3a1c24076b90200b1475424feba95915..89e6aed8ec828c49f319389b26bca239ada199c8 100644 --- a/src/hotspot/os/bsd/os_bsd.cpp +++ b/src/hotspot/os/bsd/os_bsd.cpp @@ -589,7 +589,7 @@ bool os::create_thread(Thread* thread, ThreadType thr_type, assert(thread->osthread() == NULL, "caller responsible"); // Allocate the OSThread object - OSThread* osthread = new OSThread(NULL, NULL); + OSThread* osthread = new OSThread(); if (osthread == NULL) { return false; } @@ -682,7 +682,7 @@ bool os::create_attached_thread(JavaThread* thread) { #endif // Allocate the OSThread object - OSThread* osthread = new OSThread(NULL, NULL); + OSThread* osthread = new OSThread(); if (osthread == NULL) { return false; diff --git a/src/hotspot/os/bsd/os_perf_bsd.cpp b/src/hotspot/os/bsd/os_perf_bsd.cpp index e69bfc79558c3fb5cebf3a8451b98f1fd0ecad80..9b80e74954284ab602e538e9d6cfb1a812ab85f7 100644 --- a/src/hotspot/os/bsd/os_perf_bsd.cpp +++ b/src/hotspot/os/bsd/os_perf_bsd.cpp @@ -26,8 +26,8 @@ #include "memory/resourceArea.hpp" #include "runtime/os.hpp" #include "runtime/os_perf.hpp" +#include "runtime/vm_version.hpp" #include "utilities/globalDefinitions.hpp" -#include CPU_HEADER(vm_version_ext) #ifdef __APPLE__ #import @@ -371,11 +371,12 @@ CPUInformationInterface::CPUInformationInterface() { bool CPUInformationInterface::initialize() { _cpu_info = new CPUInformation(); - _cpu_info->set_number_of_hardware_threads(VM_Version_Ext::number_of_threads()); - _cpu_info->set_number_of_cores(VM_Version_Ext::number_of_cores()); - _cpu_info->set_number_of_sockets(VM_Version_Ext::number_of_sockets()); - _cpu_info->set_cpu_name(VM_Version_Ext::cpu_name()); - _cpu_info->set_cpu_description(VM_Version_Ext::cpu_description()); + VM_Version::initialize_cpu_information(); + _cpu_info->set_number_of_hardware_threads(VM_Version::number_of_threads()); + _cpu_info->set_number_of_cores(VM_Version::number_of_cores()); + _cpu_info->set_number_of_sockets(VM_Version::number_of_sockets()); + _cpu_info->set_cpu_name(VM_Version::cpu_name()); + _cpu_info->set_cpu_description(VM_Version::cpu_description()); return true; } diff --git a/src/hotspot/os/bsd/threadCritical_bsd.cpp b/src/hotspot/os/bsd/threadCritical_bsd.cpp deleted file mode 100644 index 71c51df599d7bcf7c6592f9bfa44a2bb1f245fc0..0000000000000000000000000000000000000000 --- a/src/hotspot/os/bsd/threadCritical_bsd.cpp +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#include "precompiled.hpp" -#include "runtime/thread.inline.hpp" -#include "runtime/threadCritical.hpp" - -// put OS-includes here -# include - -// -// See threadCritical.hpp for details of this class. -// - -static pthread_t tc_owner = 0; -static pthread_mutex_t tc_mutex = PTHREAD_MUTEX_INITIALIZER; -static int tc_count = 0; - -ThreadCritical::ThreadCritical() { - pthread_t self = pthread_self(); - if (self != tc_owner) { - int ret = pthread_mutex_lock(&tc_mutex); - guarantee(ret == 0, "fatal error with pthread_mutex_lock()"); - assert(tc_count == 0, "Lock acquired with illegal reentry count."); - tc_owner = self; - } - tc_count++; -} - -ThreadCritical::~ThreadCritical() { - assert(tc_owner == pthread_self(), "must have correct owner"); - assert(tc_count > 0, "must have correct count"); - - tc_count--; - if (tc_count == 0) { - tc_owner = 0; - int ret = pthread_mutex_unlock(&tc_mutex); - guarantee(ret == 0, "fatal error with pthread_mutex_unlock()"); - } -} diff --git a/src/hotspot/os/linux/attachListener_linux.cpp b/src/hotspot/os/linux/attachListener_linux.cpp index 628c3f1c462b158362502077c7f14f4330149cf9..a6ab0ae8c943d64643a757cf07a0ecf914e61e15 100644 --- a/src/hotspot/os/linux/attachListener_linux.cpp +++ b/src/hotspot/os/linux/attachListener_linux.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -28,7 +28,6 @@ #include "runtime/interfaceSupport.inline.hpp" #include "runtime/os.inline.hpp" #include "services/attachListener.hpp" -#include "services/dtraceAttacher.hpp" #include #include @@ -385,7 +384,7 @@ LinuxAttachOperation* LinuxAttachListener::dequeue() { // write the given buffer to the socket int LinuxAttachListener::write_fully(int s, char* buf, int len) { do { - int n = ::write(s, buf, len); + ssize_t n = ::write(s, buf, len); if (n == -1) { if (errno != EINTR) return -1; } else { diff --git a/src/hotspot/os/linux/cgroupSubsystem_linux.cpp b/src/hotspot/os/linux/cgroupSubsystem_linux.cpp index 1593a701e67991e41b8a4d010b4a44b86803cd75..1346cf8915f111729f9aa7f99d06bac705fba7da 100644 --- a/src/hotspot/os/linux/cgroupSubsystem_linux.cpp +++ b/src/hotspot/os/linux/cgroupSubsystem_linux.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -146,7 +146,7 @@ bool CgroupSubsystemFactory::determine_type(CgroupInfo* cg_infos, * Conversely, for cgroups v2 (unified hierarchy), cpu, cpuacct, cpuset, memory * controllers must have hierarchy ID 0 and the unified controller mounted. */ - cgroups = fopen(proc_cgroups, "r"); + cgroups = os::fopen(proc_cgroups, "r"); if (cgroups == NULL) { log_debug(os, container)("Can't open %s, %s", proc_cgroups, os::strerror(errno)); *flags = INVALID_CGROUPS_GENERIC; @@ -214,7 +214,7 @@ bool CgroupSubsystemFactory::determine_type(CgroupInfo* cg_infos, * - on a cgroups v1 system, collect info for mapping * the host mount point to the local one via /proc/self/mountinfo below. */ - cgroup = fopen(proc_self_cgroup, "r"); + cgroup = os::fopen(proc_self_cgroup, "r"); if (cgroup == NULL) { log_debug(os, container)("Can't open %s, %s", proc_self_cgroup, os::strerror(errno)); @@ -269,7 +269,7 @@ bool CgroupSubsystemFactory::determine_type(CgroupInfo* cg_infos, // Find various mount points by reading /proc/self/mountinfo // mountinfo format is documented at https://www.kernel.org/doc/Documentation/filesystems/proc.txt - mntinfo = fopen(proc_self_mountinfo, "r"); + mntinfo = os::fopen(proc_self_mountinfo, "r"); if (mntinfo == NULL) { log_debug(os, container)("Can't open %s, %s", proc_self_mountinfo, os::strerror(errno)); @@ -495,7 +495,12 @@ int CgroupSubsystem::active_processor_count() { cpu_count = limit_count = os::Linux::active_processor_count(); int quota = cpu_quota(); int period = cpu_period(); - int share = cpu_shares(); + + // It's not a good idea to use cpu_shares() to limit the number + // of CPUs used by the JVM. See JDK-8281181. + // UseContainerCpuShares and PreferContainerQuotaForCPUCount are + // deprecated and will be removed in the next JDK release. + int share = UseContainerCpuShares ? cpu_shares() : -1; if (quota > -1 && period > 0) { quota_count = ceilf((float)quota / (float)period); diff --git a/src/hotspot/os/linux/cgroupSubsystem_linux.hpp b/src/hotspot/os/linux/cgroupSubsystem_linux.hpp index 754629714492911a7a20601a49fcad10873b31b1..5fc376a304e65d2b96c6083204a4f936ae62883b 100644 --- a/src/hotspot/os/linux/cgroupSubsystem_linux.hpp +++ b/src/hotspot/os/linux/cgroupSubsystem_linux.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -108,7 +108,7 @@ template int subsystem_file_line_contents(CgroupController* c, } strncat(file, filename, MAXPATHLEN-filelen); log_trace(os, container)("Path to %s is %s", filename, file); - fp = fopen(file, "r"); + fp = os::fopen(file, "r"); if (fp != NULL) { int err = 0; while ((p = fgets(buf, MAXPATHLEN, fp)) != NULL) { @@ -157,8 +157,10 @@ PRAGMA_DIAG_POP NULL, \ scan_fmt, \ &variable); \ - if (err != 0) \ + if (err != 0) { \ + log_trace(os, container)(logstring, (return_type) OSCONTAINER_ERROR); \ return (return_type) OSCONTAINER_ERROR; \ + } \ \ log_trace(os, container)(logstring, variable); \ } diff --git a/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp b/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp index 25146373532c6b13b641c973025c97320b503128..0b1bc9c6cddd83e9704215a5bb09e2aada28ca9a 100644 --- a/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp +++ b/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2021, Red Hat Inc. + * Copyright (c) 2020, 2022, Red Hat Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,7 +36,7 @@ */ int CgroupV2Subsystem::cpu_shares() { GET_CONTAINER_INFO(int, _unified, "/cpu.weight", - "Raw value for CPU shares is: %d", "%d", shares); + "Raw value for CPU Shares is: %d", "%d", shares); // Convert default value of 100 to no shares setup if (shares == 100) { log_debug(os, container)("CPU Shares is: %d", -1); diff --git a/src/hotspot/os/linux/decoder_linux.cpp b/src/hotspot/os/linux/decoder_linux.cpp index daa12ec6f6d7caa2331c188fc9503334eef3c99c..0fc0daf98e7b9ee89a635e9317905bb865142caa 100644 --- a/src/hotspot/os/linux/decoder_linux.cpp +++ b/src/hotspot/os/linux/decoder_linux.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -58,7 +58,7 @@ bool ElfDecoder::demangle(const char* symbol, char *buf, int buflen) { bool ElfFile::specifies_noexecstack(const char* filepath) { if (filepath == NULL) return true; - FILE* file = fopen(filepath, "r"); + FILE* file = os::fopen(filepath, "r"); if (file == NULL) return true; // AARCH64 defaults to noexecstack. All others default to execstack. diff --git a/src/hotspot/os/linux/gc/z/zMountPoint_linux.cpp b/src/hotspot/os/linux/gc/z/zMountPoint_linux.cpp index d3c5ef3fd7d7d831b1a06e0e0c1dbb9b18bd3fd2..b0fa227ef7c05cd30d3a34fedabc422246061889 100644 --- a/src/hotspot/os/linux/gc/z/zMountPoint_linux.cpp +++ b/src/hotspot/os/linux/gc/z/zMountPoint_linux.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -27,6 +27,7 @@ #include "gc/z/zErrno.hpp" #include "gc/z/zMountPoint_linux.hpp" #include "runtime/globals.hpp" +#include "runtime/os.hpp" #include #include @@ -70,7 +71,7 @@ char* ZMountPoint::get_mountpoint(const char* line, const char* filesystem) cons } void ZMountPoint::get_mountpoints(const char* filesystem, ZArray* mountpoints) const { - FILE* fd = fopen(PROC_SELF_MOUNTINFO, "r"); + FILE* fd = os::fopen(PROC_SELF_MOUNTINFO, "r"); if (fd == NULL) { ZErrno err; log_error_p(gc)("Failed to open %s: %s", PROC_SELF_MOUNTINFO, err.to_string()); diff --git a/src/hotspot/os/linux/gc/z/zPhysicalMemoryBacking_linux.cpp b/src/hotspot/os/linux/gc/z/zPhysicalMemoryBacking_linux.cpp index 951b98d6cce40ba9d751cc3cc9ce3bba7f65c88c..b434acc3215eb3548c160491d0839bb52f99271c 100644 --- a/src/hotspot/os/linux/gc/z/zPhysicalMemoryBacking_linux.cpp +++ b/src/hotspot/os/linux/gc/z/zPhysicalMemoryBacking_linux.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -329,7 +329,7 @@ void ZPhysicalMemoryBacking::warn_available_space(size_t max_capacity) const { void ZPhysicalMemoryBacking::warn_max_map_count(size_t max_capacity) const { const char* const filename = ZFILENAME_PROC_MAX_MAP_COUNT; - FILE* const file = fopen(filename, "r"); + FILE* const file = os::fopen(filename, "r"); if (file == NULL) { // Failed to open file, skip check log_debug_p(gc, init)("Failed to open %s", filename); diff --git a/src/hotspot/os/linux/gc/z/zSyscall_linux.hpp b/src/hotspot/os/linux/gc/z/zSyscall_linux.hpp index 95b13841b2a8f244ef7badeea45749f01f0d223d..1e1becf5a140f5db0666e659b764f2a254b25e90 100644 --- a/src/hotspot/os/linux/gc/z/zSyscall_linux.hpp +++ b/src/hotspot/os/linux/gc/z/zSyscall_linux.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -24,7 +24,8 @@ #ifndef OS_LINUX_GC_Z_ZSYSCALL_LINUX_HPP #define OS_LINUX_GC_Z_ZSYSCALL_LINUX_HPP -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" +#include "utilities/globalDefinitions.hpp" // Flags for get_mempolicy() #ifndef MPOL_F_NODE diff --git a/src/hotspot/os/linux/globals_linux.hpp b/src/hotspot/os/linux/globals_linux.hpp index 72915b5afbbbe38d25dc624a48685cb09d7fe2f5..2fc4a404b3411244e8acb26c8f767d264fed4d91 100644 --- a/src/hotspot/os/linux/globals_linux.hpp +++ b/src/hotspot/os/linux/globals_linux.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -59,10 +59,14 @@ product(bool, UseContainerSupport, true, \ "Enable detection and runtime container configuration support") \ \ + product(bool, UseContainerCpuShares, false, \ + "(Deprecated) Include CPU shares in the CPU availability" \ + " calculation.") \ + \ product(bool, PreferContainerQuotaForCPUCount, true, \ - "Calculate the container CPU availability based on the value" \ - " of quotas (if set), when true. Otherwise, use the CPU" \ - " shares value, provided it is less than quota.") \ + "(Deprecated) Calculate the container CPU availability based" \ + " on the value of quotas (if set), when true. Otherwise, use" \ + " the CPU shares value, provided it is less than quota.") \ \ product(bool, AdjustStackSizeForTLS, false, \ "Increase the thread stack size to include space for glibc " \ diff --git a/src/hotspot/os/linux/osContainer_linux.hpp b/src/hotspot/os/linux/osContainer_linux.hpp index 940bc0e3874bf00048722622e99e3defee97a211..1ba4a9dabdc88eecd613920db168b6968f0d86b7 100644 --- a/src/hotspot/os/linux/osContainer_linux.hpp +++ b/src/hotspot/os/linux/osContainer_linux.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -27,7 +27,7 @@ #include "utilities/globalDefinitions.hpp" #include "utilities/macros.hpp" -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" #define OSCONTAINER_ERROR (-2) diff --git a/src/hotspot/os/linux/osThread_linux.hpp b/src/hotspot/os/linux/osThread_linux.hpp index 01c93f6eb9a8df29443b35ea8e41c36129fe23e4..7dbe92b415eae840f2cc7b1139a46b25e565ff74 100644 --- a/src/hotspot/os/linux/osThread_linux.hpp +++ b/src/hotspot/os/linux/osThread_linux.hpp @@ -55,13 +55,7 @@ // Used for debugging, return a unique integer for each thread. int thread_identifier() const { return _thread_id; } #endif -#ifdef ASSERT - // We expect no reposition failures so kill vm if we get one. - // - bool valid_reposition_failure() { - return false; - } -#endif // ASSERT + pthread_t pthread_id() const { return _pthread_id; } diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp index e75e2e51b0e467b99b16e4904e551185b933a22b..f2ecca92c82834f5a455e003bd3e429134e75067 100644 --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp @@ -1,5 +1,6 @@ /* - * Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 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 @@ -258,7 +259,7 @@ bool os::Linux::get_tick_information(CPUPerfTicks* pticks, int which_logical_cpu memset(pticks, 0, sizeof(CPUPerfTicks)); - if ((fh = fopen("/proc/stat", "r")) == NULL) { + if ((fh = os::fopen("/proc/stat", "r")) == NULL) { return false; } @@ -352,7 +353,7 @@ void os::Linux::initialize_system_info() { pid_t pid = os::Linux::gettid(); char fname[32]; jio_snprintf(fname, sizeof(fname), "/proc/%d", pid); - FILE *fp = fopen(fname, "r"); + FILE *fp = os::fopen(fname, "r"); if (fp == NULL) { unsafe_chroot_detected = true; } else { @@ -786,7 +787,7 @@ bool os::create_thread(Thread* thread, ThreadType thr_type, assert(thread->osthread() == NULL, "caller responsible"); // Allocate the OSThread object - OSThread* osthread = new OSThread(NULL, NULL); + OSThread* osthread = new OSThread(); if (osthread == NULL) { return false; } @@ -806,7 +807,7 @@ bool os::create_thread(Thread* thread, ThreadType thr_type, // Calculate stack size if it's not specified by caller. size_t stack_size = os::Posix::get_initial_stack_size(thr_type, req_stack_size); - // In glibc versions prior to 2.7 the guard size mechanism + // In glibc versions prior to 2.27 the guard size mechanism // is not implemented properly. The posix standard requires adding // the size of the guard pages to the stack size, instead Linux // takes the space out of 'stacksize'. Thus we adapt the requested @@ -915,7 +916,7 @@ bool os::create_attached_thread(JavaThread* thread) { #endif // Allocate the OSThread object - OSThread* osthread = new OSThread(NULL, NULL); + OSThread* osthread = new OSThread(); if (osthread == NULL) { return false; @@ -1027,7 +1028,7 @@ bool os::is_primordial_thread(void) { // Find the virtual memory area that contains addr static bool find_vma(address addr, address* vma_low, address* vma_high) { - FILE *fp = fopen("/proc/self/maps", "r"); + FILE *fp = os::fopen("/proc/self/maps", "r"); if (fp) { address low, high; while (!feof(fp)) { @@ -1139,7 +1140,7 @@ void os::Linux::capture_initial_stack(size_t max_size) { char stat[2048]; int statlen; - fp = fopen("/proc/self/stat", "r"); + fp = os::fopen("/proc/self/stat", "r"); if (fp) { statlen = fread(stat, 1, 2047, fp); stat[statlen] = '\0'; @@ -2004,7 +2005,7 @@ static void parse_os_info_helper(FILE* fp, char* distro, size_t length, bool get } static void parse_os_info(char* distro, size_t length, const char* file) { - FILE* fp = fopen(file, "r"); + FILE* fp = os::fopen(file, "r"); if (fp != NULL) { // if suse format, print out first line bool get_first_line = (strcmp(file, "/etc/SuSE-release") == 0); @@ -2065,7 +2066,7 @@ void os::Linux::print_system_memory_info(outputStream* st) { } bool os::Linux::query_process_memory_info(os::Linux::meminfo_t* info) { - FILE* f = ::fopen("/proc/self/status", "r"); + FILE* f = os::fopen("/proc/self/status", "r"); const int num_values = sizeof(os::Linux::meminfo_t) / sizeof(size_t); int num_found = 0; char buf[256]; @@ -2092,6 +2093,34 @@ bool os::Linux::query_process_memory_info(os::Linux::meminfo_t* info) { return false; } +#ifdef __GLIBC__ +// For Glibc, print a one-liner with the malloc tunables. +// Most important and popular is MALLOC_ARENA_MAX, but we are +// thorough and print them all. +static void print_glibc_malloc_tunables(outputStream* st) { + static const char* var[] = { + // the new variant + "GLIBC_TUNABLES", + // legacy variants + "MALLOC_CHECK_", "MALLOC_TOP_PAD_", "MALLOC_PERTURB_", + "MALLOC_MMAP_THRESHOLD_", "MALLOC_TRIM_THRESHOLD_", + "MALLOC_MMAP_MAX_", "MALLOC_ARENA_TEST", "MALLOC_ARENA_MAX", + NULL}; + st->print("glibc malloc tunables: "); + bool printed = false; + for (int i = 0; var[i] != NULL; i ++) { + const char* const val = ::getenv(var[i]); + if (val != NULL) { + st->print("%s%s=%s", (printed ? ", " : ""), var[i], val); + printed = true; + } + } + if (!printed) { + st->print("(default)"); + } +} +#endif // __GLIBC__ + void os::Linux::print_process_memory_info(outputStream* st) { st->print_cr("Process Memory:"); @@ -2114,8 +2143,9 @@ void os::Linux::print_process_memory_info(outputStream* st) { st->print_cr("Could not open /proc/self/status to get process memory related information"); } - // Print glibc outstanding allocations. - // (note: there is no implementation of mallinfo for muslc) + // glibc only: + // - Print outstanding allocations using mallinfo + // - Print glibc tunables #ifdef __GLIBC__ size_t total_allocated = 0; bool might_have_wrapped = false; @@ -2123,9 +2153,10 @@ void os::Linux::print_process_memory_info(outputStream* st) { struct glibc_mallinfo2 mi = _mallinfo2(); total_allocated = mi.uordblks; } else if (_mallinfo != NULL) { - // mallinfo is an old API. Member names mean next to nothing and, beyond that, are int. - // So values may have wrapped around. Still useful enough to see how much glibc thinks - // we allocated. + // mallinfo is an old API. Member names mean next to nothing and, beyond that, are 32-bit signed. + // So for larger footprints the values may have wrapped around. We try to detect this here: if the + // process whole resident set size is smaller than 4G, malloc footprint has to be less than that + // and the numbers are reliable. struct glibc_mallinfo mi = _mallinfo(); total_allocated = (size_t)(unsigned)mi.uordblks; // Since mallinfo members are int, glibc values may have wrapped. Warn about this. @@ -2136,8 +2167,10 @@ void os::Linux::print_process_memory_info(outputStream* st) { total_allocated / K, might_have_wrapped ? " (may have wrapped)" : ""); } -#endif // __GLIBC__ - + // Tunables + print_glibc_malloc_tunables(st); + st->cr(); +#endif } bool os::Linux::print_ld_preload_file(outputStream* st) { @@ -2174,7 +2207,11 @@ bool os::Linux::print_container_info(outputStream* st) { int i = OSContainer::active_processor_count(); st->print("active_processor_count: "); if (i > 0) { - st->print_cr("%d", i); + if (ActiveProcessorCount > 0) { + st->print_cr("%d, but overridden by -XX:ActiveProcessorCount %d", i, ActiveProcessorCount); + } else { + st->print_cr("%d", i); + } } else { st->print_cr("not supported"); } @@ -2312,7 +2349,7 @@ void os::print_memory_info(outputStream* st) { static bool print_model_name_and_flags(outputStream* st, char* buf, size_t buflen) { #if defined(IA32) || defined(AMD64) // Other platforms have less repetitive cpuinfo files - FILE *fp = fopen("/proc/cpuinfo", "r"); + FILE *fp = os::fopen("/proc/cpuinfo", "r"); if (fp) { bool model_name_printed = false; while (!feof(fp)) { @@ -2416,7 +2453,7 @@ const char* search_string = "Processor"; // Parses the cpuinfo file for string representing the model name. void os::get_summary_cpu_info(char* cpuinfo, size_t length) { - FILE* fp = fopen("/proc/cpuinfo", "r"); + FILE* fp = os::fopen("/proc/cpuinfo", "r"); if (fp != NULL) { while (!feof(fp)) { char buf[256]; @@ -3551,7 +3588,7 @@ static void set_coredump_filter(CoredumpFilterBit bit) { FILE *f; long cdm; - if ((f = fopen("/proc/self/coredump_filter", "r+")) == NULL) { + if ((f = os::fopen("/proc/self/coredump_filter", "r+")) == NULL) { return; } @@ -3590,7 +3627,7 @@ static size_t scan_default_large_page_size() { // If we can't determine the value (e.g. /proc is not mounted, or the text // format has been changed), we'll set largest page size to 0 - FILE *fp = fopen("/proc/meminfo", "r"); + FILE *fp = os::fopen("/proc/meminfo", "r"); if (fp) { while (!feof(fp)) { int x = 0; @@ -3935,23 +3972,14 @@ char* os::Linux::reserve_memory_special_shm(size_t bytes, size_t alignment, return addr; } -static void warn_on_commit_special_failure(char* req_addr, size_t bytes, +static void log_on_commit_special_failure(char* req_addr, size_t bytes, size_t page_size, int error) { assert(error == ENOMEM, "Only expect to fail if no memory is available"); - bool warn_on_failure = UseLargePages && - (!FLAG_IS_DEFAULT(UseLargePages) || - !FLAG_IS_DEFAULT(UseHugeTLBFS) || - !FLAG_IS_DEFAULT(LargePageSizeInBytes)); - - if (warn_on_failure) { - char msg[128]; - jio_snprintf(msg, sizeof(msg), "Failed to reserve and commit memory. req_addr: " - PTR_FORMAT " bytes: " SIZE_FORMAT " page size: " - SIZE_FORMAT " (errno = %d).", - req_addr, bytes, page_size, error); - warning("%s", msg); - } + log_info(pagesize)("Failed to reserve and commit memory with given page size. req_addr: " PTR_FORMAT + " size: " SIZE_FORMAT "%s, page size: " SIZE_FORMAT "%s, (errno = %d)", + p2i(req_addr), byte_size_in_exact_unit(bytes), exact_unit_for_byte_size(bytes), + byte_size_in_exact_unit(page_size), exact_unit_for_byte_size(page_size), error); } bool os::Linux::commit_memory_special(size_t bytes, @@ -3973,7 +4001,7 @@ bool os::Linux::commit_memory_special(size_t bytes, char* addr = (char*)::mmap(req_addr, bytes, prot, flags, -1, 0); if (addr == MAP_FAILED) { - warn_on_commit_special_failure(req_addr, bytes, page_size, errno); + log_on_commit_special_failure(req_addr, bytes, page_size, errno); return false; } @@ -4268,7 +4296,7 @@ int os::Linux::get_namespace_pid(int vmid) { int retpid = -1; snprintf(fname, sizeof(fname), "/proc/%d/status", vmid); - FILE *fp = fopen(fname, "r"); + FILE *fp = os::fopen(fname, "r"); if (fp) { int pid, nspid; @@ -5077,7 +5105,7 @@ static jlong slow_thread_cpu_time(Thread *thread, bool user_sys_cpu_time) { FILE *fp; snprintf(proc_name, 64, "/proc/self/task/%d/stat", tid); - fp = fopen(proc_name, "r"); + fp = os::fopen(proc_name, "r"); if (fp == NULL) return -1; statlen = fread(stat, 1, 2047, fp); stat[statlen] = '\0'; @@ -5380,21 +5408,20 @@ bool os::supports_map_sync() { } void os::print_memory_mappings(char* addr, size_t bytes, outputStream* st) { + // Note: all ranges are "[..)" unsigned long long start = (unsigned long long)addr; unsigned long long end = start + bytes; - FILE* f = ::fopen("/proc/self/maps", "r"); + FILE* f = os::fopen("/proc/self/maps", "r"); int num_found = 0; if (f != NULL) { - st->print("Range [%llx-%llx) contains: ", start, end); + st->print_cr("Range [%llx-%llx) contains: ", start, end); char line[512]; while(fgets(line, sizeof(line), f) == line) { - unsigned long long a1 = 0; - unsigned long long a2 = 0; - if (::sscanf(line, "%llx-%llx", &a1, &a2) == 2) { + unsigned long long segment_start = 0; + unsigned long long segment_end = 0; + if (::sscanf(line, "%llx-%llx", &segment_start, &segment_end) == 2) { // Lets print out every range which touches ours. - if ((a1 >= start && a1 < end) || // left leg in - (a2 >= start && a2 < end) || // right leg in - (a1 < start && a2 >= end)) { // superimposition + if (segment_start < end && segment_end > start) { num_found ++; st->print("%s", line); // line includes \n } @@ -5402,7 +5429,7 @@ void os::print_memory_mappings(char* addr, size_t bytes, outputStream* st) { } ::fclose(f); if (num_found == 0) { - st->print("nothing."); + st->print_cr("nothing."); } st->cr(); } diff --git a/src/hotspot/os/linux/os_perf_linux.cpp b/src/hotspot/os/linux/os_perf_linux.cpp index 7c42379a0a710de20b2f2f53c82d2fab45434d85..8d244887d4bdb8bd35cea8134c3941ddcb59b34a 100644 --- a/src/hotspot/os/linux/os_perf_linux.cpp +++ b/src/hotspot/os/linux/os_perf_linux.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -28,10 +28,9 @@ #include "os_linux.inline.hpp" #include "runtime/os.hpp" #include "runtime/os_perf.hpp" +#include "runtime/vm_version.hpp" #include "utilities/globalDefinitions.hpp" -#include CPU_HEADER(vm_version_ext) - #include #include #include @@ -235,7 +234,7 @@ static int SCANF_ARGS(2, 0) vread_statdata(const char* procfile, _SCANFMT_ const int n; char buf[2048]; - if ((f = fopen(procfile, "r")) == NULL) { + if ((f = os::fopen(procfile, "r")) == NULL) { return -1; } @@ -272,7 +271,7 @@ static int SCANF_ARGS(2, 3) read_statdata(const char* procfile, _SCANFMT_ const static FILE* open_statfile(void) { FILE *f; - if ((f = fopen("/proc/stat", "r")) == NULL) { + if ((f = os::fopen("/proc/stat", "r")) == NULL) { static int haveWarned = 0; if (!haveWarned) { haveWarned = 1; @@ -723,7 +722,7 @@ void SystemProcessInterface::SystemProcesses::ProcessIterator::get_exe_name() { jio_snprintf(buffer, PATH_MAX, "/proc/%s/stat", _entry->d_name); buffer[PATH_MAX - 1] = '\0'; - if ((fp = fopen(buffer, "r")) != NULL) { + if ((fp = os::fopen(buffer, "r")) != NULL) { if (fgets(buffer, PATH_MAX, fp) != NULL) { char* start, *end; // exe-name is between the first pair of ( and ) @@ -751,7 +750,7 @@ char* SystemProcessInterface::SystemProcesses::ProcessIterator::get_cmdline() { jio_snprintf(buffer, PATH_MAX, "/proc/%s/cmdline", _entry->d_name); buffer[PATH_MAX - 1] = '\0'; - if ((fp = fopen(buffer, "r")) != NULL) { + if ((fp = os::fopen(buffer, "r")) != NULL) { size_t size = 0; char dummy; @@ -927,11 +926,12 @@ CPUInformationInterface::CPUInformationInterface() { bool CPUInformationInterface::initialize() { _cpu_info = new CPUInformation(); - _cpu_info->set_number_of_hardware_threads(VM_Version_Ext::number_of_threads()); - _cpu_info->set_number_of_cores(VM_Version_Ext::number_of_cores()); - _cpu_info->set_number_of_sockets(VM_Version_Ext::number_of_sockets()); - _cpu_info->set_cpu_name(VM_Version_Ext::cpu_name()); - _cpu_info->set_cpu_description(VM_Version_Ext::cpu_description()); + VM_Version::initialize_cpu_information(); + _cpu_info->set_number_of_hardware_threads(VM_Version::number_of_threads()); + _cpu_info->set_number_of_cores(VM_Version::number_of_cores()); + _cpu_info->set_number_of_sockets(VM_Version::number_of_sockets()); + _cpu_info->set_cpu_name(VM_Version::cpu_name()); + _cpu_info->set_cpu_description(VM_Version::cpu_description()); return true; } diff --git a/src/hotspot/os/linux/threadCritical_linux.cpp b/src/hotspot/os/linux/threadCritical_linux.cpp deleted file mode 100644 index 71c51df599d7bcf7c6592f9bfa44a2bb1f245fc0..0000000000000000000000000000000000000000 --- a/src/hotspot/os/linux/threadCritical_linux.cpp +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#include "precompiled.hpp" -#include "runtime/thread.inline.hpp" -#include "runtime/threadCritical.hpp" - -// put OS-includes here -# include - -// -// See threadCritical.hpp for details of this class. -// - -static pthread_t tc_owner = 0; -static pthread_mutex_t tc_mutex = PTHREAD_MUTEX_INITIALIZER; -static int tc_count = 0; - -ThreadCritical::ThreadCritical() { - pthread_t self = pthread_self(); - if (self != tc_owner) { - int ret = pthread_mutex_lock(&tc_mutex); - guarantee(ret == 0, "fatal error with pthread_mutex_lock()"); - assert(tc_count == 0, "Lock acquired with illegal reentry count."); - tc_owner = self; - } - tc_count++; -} - -ThreadCritical::~ThreadCritical() { - assert(tc_owner == pthread_self(), "must have correct owner"); - assert(tc_count > 0, "must have correct count"); - - tc_count--; - if (tc_count == 0) { - tc_owner = 0; - int ret = pthread_mutex_unlock(&tc_mutex); - guarantee(ret == 0, "fatal error with pthread_mutex_unlock()"); - } -} diff --git a/src/hotspot/os/posix/os_posix.cpp b/src/hotspot/os/posix/os_posix.cpp index 8ec5b152d34d26871aba02f6c90be03484e42080..31c1cbc3d4faacffa7e051ac4b7f415b9bafc2af 100644 --- a/src/hotspot/os/posix/os_posix.cpp +++ b/src/hotspot/os/posix/os_posix.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -675,13 +675,13 @@ const char* os::get_current_directory(char *buf, size_t buflen) { return getcwd(buf, buflen); } -FILE* os::open(int fd, const char* mode) { +FILE* os::fdopen(int fd, const char* mode) { return ::fdopen(fd, mode); } -size_t os::write(int fd, const void *buf, unsigned int nBytes) { - size_t res; - RESTARTABLE((size_t) ::write(fd, buf, (size_t) nBytes), res); +ssize_t os::write(int fd, const void *buf, unsigned int nBytes) { + ssize_t res; + RESTARTABLE(::write(fd, buf, (size_t) nBytes), res); return res; } @@ -689,10 +689,6 @@ ssize_t os::read_at(int fd, void *buf, unsigned int nBytes, jlong offset) { return ::pread(fd, buf, nBytes, offset); } -int os::close(int fd) { - return ::close(fd); -} - void os::flockfile(FILE* fp) { ::flockfile(fp); } @@ -720,10 +716,6 @@ int os::socket_close(int fd) { return ::close(fd); } -int os::socket(int domain, int type, int protocol) { - return ::socket(domain, type, protocol); -} - int os::recv(int fd, char* buf, size_t nBytes, uint flags) { RESTARTABLE_RETURN_INT(::recv(fd, buf, nBytes, flags)); } @@ -1610,9 +1602,7 @@ int os::PlatformEvent::park(jlong millis) { status = pthread_cond_timedwait(_cond, _mutex, &abst); assert_status(status == 0 || status == ETIMEDOUT, status, "cond_timedwait"); - // OS-level "spurious wakeups" are ignored unless the archaic - // FilterSpuriousWakeups is set false. That flag should be obsoleted. - if (!FilterSpuriousWakeups) break; + // OS-level "spurious wakeups" are ignored if (status == ETIMEDOUT) break; } --_nParked; diff --git a/src/hotspot/os/posix/perfMemory_posix.cpp b/src/hotspot/os/posix/perfMemory_posix.cpp index a89947f32edc1da75a7d9622b8163ae7b5151757..7fcf867b3f86a6cdae6bb9a49bce15a8f9baf3c0 100644 --- a/src/hotspot/os/posix/perfMemory_posix.cpp +++ b/src/hotspot/os/posix/perfMemory_posix.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2022, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, 2021 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -98,21 +98,20 @@ static void save_memory_to_file(char* addr, size_t size) { const char* destfile = PerfMemory::get_perfdata_file_path(); assert(destfile[0] != '\0', "invalid PerfData file path"); - int result; + int fd; - RESTARTABLE(os::open(destfile, O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR|S_IWUSR), - result); - if (result == OS_ERR) { + RESTARTABLE(os::open(destfile, O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR|S_IWUSR), fd); + if (fd == OS_ERR) { if (PrintMiscellaneous && Verbose) { warning("Could not create Perfdata save file: %s: %s\n", destfile, os::strerror(errno)); } } else { - int fd = result; + ssize_t result; for (size_t remaining = size; remaining > 0;) { - RESTARTABLE(::write(fd, addr, remaining), result); + result = os::write(fd, addr, remaining); if (result == OS_ERR) { if (PrintMiscellaneous && Verbose) { warning("Could not write Perfdata save file: %s: %s\n", @@ -331,7 +330,7 @@ static DIR *open_directory_secure(const char* dirname) { // Determine if the open directory is secure. if (!is_dirfd_secure(fd)) { // The directory is not a secure directory. - os::close(fd); + ::close(fd); return dirp; } @@ -339,21 +338,21 @@ static DIR *open_directory_secure(const char* dirname) { dirp = ::opendir(dirname); if (dirp == NULL) { // The directory doesn't exist, close fd and return. - os::close(fd); + ::close(fd); return dirp; } // Check to make sure fd and dirp are referencing the same file system object. if (!is_same_fsobject(fd, AIX_ONLY(dirp->dd_fd) NOT_AIX(dirfd(dirp)))) { // The directory is not secure. - os::close(fd); + ::close(fd); os::closedir(dirp); dirp = NULL; return dirp; } // Close initial open now that we know directory is secure - os::close(fd); + ::close(fd); return dirp; } @@ -842,9 +841,9 @@ static int create_sharedmem_resources(const char* dirname, const char* filename, // Open the filename in the current directory. // Cannot use O_TRUNC here; truncation of an existing file has to happen // after the is_file_secure() check below. - int result; - RESTARTABLE(os::open(filename, O_RDWR|O_CREAT|O_NOFOLLOW, S_IRUSR|S_IWUSR), result); - if (result == OS_ERR) { + int fd; + RESTARTABLE(os::open(filename, O_RDWR|O_CREAT|O_NOFOLLOW, S_IRUSR|S_IWUSR), fd); + if (fd == OS_ERR) { if (PrintMiscellaneous && Verbose) { if (errno == ELOOP) { warning("file %s is a symlink and is not secure\n", filename); @@ -860,15 +859,14 @@ static int create_sharedmem_resources(const char* dirname, const char* filename, // close the directory and reset the current working directory close_directory_secure_cwd(dirp, saved_cwd_fd); - // save the file descriptor - int fd = result; - // check to see if the file is secure if (!is_file_secure(fd, filename)) { ::close(fd); return -1; } + ssize_t result; + // truncate the file to get rid of any existing data RESTARTABLE(::ftruncate(fd, (off_t)0), result); if (result == OS_ERR) { @@ -895,7 +893,7 @@ static int create_sharedmem_resources(const char* dirname, const char* filename, int zero_int = 0; result = (int)os::seek_to_file_offset(fd, (jlong)(seekpos)); if (result == -1 ) break; - RESTARTABLE(::write(fd, &zero_int, 1), result); + result = os::write(fd, &zero_int, 1); if (result != 1) { if (errno == ENOSPC) { warning("Insufficient space for shared memory file:\n %s\nTry using the -Djava.io.tmpdir= option to select an alternate temp location.\n", filename); @@ -1028,7 +1026,7 @@ static char* mmap_create_shared(size_t size) { // static void unmap_shared(char* addr, size_t bytes) { int res; - if (MemTracker::tracking_level() > NMT_minimal) { + if (MemTracker::enabled()) { // Note: Tracker contains a ThreadCritical. Tracker tkr(Tracker::release); res = ::munmap(addr, bytes); diff --git a/src/hotspot/os/posix/signals_posix.cpp b/src/hotspot/os/posix/signals_posix.cpp index 2c020a79408049797d5c2f1fcc1e5de8d968323e..6e94b47712f95f9194a3d4a3a138eec629b9535e 100644 --- a/src/hotspot/os/posix/signals_posix.cpp +++ b/src/hotspot/os/posix/signals_posix.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -562,6 +562,11 @@ int JVM_HANDLE_XXX_SIGNAL(int sig, siginfo_t* info, { assert(info != NULL && ucVoid != NULL, "sanity"); + if (sig == BREAK_SIGNAL) { + assert(!ReduceSignalUsage, "Should not happen with -Xrs/-XX:+ReduceSignalUsage"); + return true; // ignore it + } + // Note: it's not uncommon that JNI code uses signal/sigset to install, // then restore certain signal handler (e.g. to temporarily block SIGPIPE, // or have a SIGILL handler when detecting CPU type). When that happens, @@ -1197,7 +1202,7 @@ int os::get_signal_number(const char* signal_name) { return -1; } -void set_signal_handler(int sig) { +void set_signal_handler(int sig, bool do_check = true) { // Check for overwrite. struct sigaction oldAct; sigaction(sig, (struct sigaction*)NULL, &oldAct); @@ -1241,7 +1246,7 @@ void set_signal_handler(int sig) { // Save handler setup for later checking vm_handlers.set(sig, &sigAct); - do_check_signal_periodically[sig] = true; + do_check_signal_periodically[sig] = do_check; int ret = sigaction(sig, &sigAct, &oldAct); assert(ret == 0, "check"); @@ -1279,7 +1284,12 @@ void install_signal_handlers() { set_signal_handler(SIGFPE); PPC64_ONLY(set_signal_handler(SIGTRAP);) set_signal_handler(SIGXFSZ); - + if (!ReduceSignalUsage) { + // This is just for early initialization phase. Intercepting the signal here reduces the risk + // that an attach client accidentally forces HotSpot to quit prematurely. We skip the periodic + // check because late initialization will overwrite it to UserHandler. + set_signal_handler(BREAK_SIGNAL, false); + } #if defined(__APPLE__) // lldb (gdb) installs both standard BSD signal handlers, and mach exception // handlers. By replacing the existing task exception handler, we disable lldb's mach @@ -1546,8 +1556,6 @@ void PosixSignals::hotspot_sigmask(Thread* thread) { // - Forte Analyzer: AsyncGetCallTrace() // - StackBanging: get_frame_at_stack_banging_point() -sigset_t SR_sigset; - static void resume_clear_context(OSThread *osthread) { osthread->set_ucontext(NULL); osthread->set_siginfo(NULL); @@ -1663,14 +1671,11 @@ int SR_initialize() { assert(PosixSignals::SR_signum > SIGSEGV && PosixSignals::SR_signum > SIGBUS, "SR_signum must be greater than max(SIGSEGV, SIGBUS), see 4355769"); - sigemptyset(&SR_sigset); - sigaddset(&SR_sigset, PosixSignals::SR_signum); - // Set up signal handler for suspend/resume act.sa_flags = SA_RESTART|SA_SIGINFO; act.sa_handler = (void (*)(int)) SR_handler; - // SR_signum is blocked by default. + // SR_signum is blocked when the handler runs. pthread_sigmask(SIG_BLOCK, NULL, &act.sa_mask); remove_error_signals_from_set(&(act.sa_mask)); diff --git a/src/hotspot/os/posix/signals_posix.hpp b/src/hotspot/os/posix/signals_posix.hpp index 373a02ff3a31475e9ca05865b9651ce001b01263..2efdb374c4eb2e1ed9750882831f144b6de070f2 100644 --- a/src/hotspot/os/posix/signals_posix.hpp +++ b/src/hotspot/os/posix/signals_posix.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -25,7 +25,7 @@ #ifndef OS_POSIX_SIGNALS_POSIX_HPP #define OS_POSIX_SIGNALS_POSIX_HPP -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" #include "utilities/globalDefinitions.hpp" class outputStream; diff --git a/src/hotspot/os/aix/threadCritical_aix.cpp b/src/hotspot/os/posix/threadCritical_posix.cpp similarity index 96% rename from src/hotspot/os/aix/threadCritical_aix.cpp rename to src/hotspot/os/posix/threadCritical_posix.cpp index cd25cb68dc4646e54a6ff89b01afc73377dcfbe6..ee57352cb0cbef007055a2cc25148f3794dba055 100644 --- a/src/hotspot/os/aix/threadCritical_aix.cpp +++ b/src/hotspot/os/posix/threadCritical_posix.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2022, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, 2014 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -24,8 +24,8 @@ */ #include "precompiled.hpp" -#include "runtime/threadCritical.hpp" #include "runtime/thread.inline.hpp" +#include "runtime/threadCritical.hpp" // put OS-includes here # include diff --git a/src/hotspot/os/posix/threadLocalStorage_posix.cpp b/src/hotspot/os/posix/threadLocalStorage_posix.cpp index cc703ef811f94fe140bece77f8da533ddb0f9f71..25bbbe2244f788d6302235e1517c367b45906712 100644 --- a/src/hotspot/os/posix/threadLocalStorage_posix.cpp +++ b/src/hotspot/os/posix/threadLocalStorage_posix.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -23,6 +23,7 @@ */ #include "runtime/threadLocalStorage.hpp" +#include "utilities/debug.hpp" #include static pthread_key_t _thread_key; diff --git a/src/hotspot/os/windows/attachListener_windows.cpp b/src/hotspot/os/windows/attachListener_windows.cpp index 8b5a2cb7ab4fb8e1bc9f9f209a9e4f8028c6cff1..710afc410051f627ff45807be7454e948e263a8b 100644 --- a/src/hotspot/os/windows/attachListener_windows.cpp +++ b/src/hotspot/os/windows/attachListener_windows.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -27,7 +27,6 @@ #include "runtime/interfaceSupport.inline.hpp" #include "runtime/os.hpp" #include "services/attachListener.hpp" -#include "services/dtraceAttacher.hpp" #include #include // SIGBREAK diff --git a/src/hotspot/os/windows/gc/z/zMapper_windows.hpp b/src/hotspot/os/windows/gc/z/zMapper_windows.hpp index 4db80c899561d51cb1227cbd76b5e7b80c52bb4d..3e47b470f5f28445f5dbe56e83ab447a971ceb6c 100644 --- a/src/hotspot/os/windows/gc/z/zMapper_windows.hpp +++ b/src/hotspot/os/windows/gc/z/zMapper_windows.hpp @@ -24,7 +24,7 @@ #ifndef OS_WINDOWS_GC_Z_ZMAPPER_WINDOWS_HPP #define OS_WINDOWS_GC_Z_ZMAPPER_WINDOWS_HPP -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" #include "utilities/globalDefinitions.hpp" #include diff --git a/src/hotspot/os/windows/iphlp_interface.hpp b/src/hotspot/os/windows/iphlp_interface.hpp index 0ebe971a5f17947ca346a49aea0f517f880b00de..3e7e0adef6500d7f25716127f81e8cc4df99eb91 100644 --- a/src/hotspot/os/windows/iphlp_interface.hpp +++ b/src/hotspot/os/windows/iphlp_interface.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -25,7 +25,7 @@ #ifndef OS_WINDOWS_IPHLP_INTERFACE_HPP #define OS_WINDOWS_IPHLP_INTERFACE_HPP -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" #include "utilities/macros.hpp" #include #include diff --git a/src/hotspot/os/windows/osThread_windows.hpp b/src/hotspot/os/windows/osThread_windows.hpp index 74b50100663396c3a9b3b981914241617a48ef0b..5bd07646b1718b51e3f201c7ad938493d4cf33e8 100644 --- a/src/hotspot/os/windows/osThread_windows.hpp +++ b/src/hotspot/os/windows/osThread_windows.hpp @@ -49,13 +49,6 @@ // Used for debugging, return a unique integer for each thread. int thread_identifier() const { return _thread_id; } #endif -#ifdef ASSERT - // We expect no reposition failures so kill vm if we get one - // - bool valid_reposition_failure() { - return false; - } -#endif // ASSERT private: void pd_initialize(); diff --git a/src/hotspot/os/windows/os_perf_windows.cpp b/src/hotspot/os/windows/os_perf_windows.cpp index 3ce1137f37d780dab850841bef7de849bcd6acca..fc2a5631b706ec96ae25b2c729d13c01d5be9a09 100644 --- a/src/hotspot/os/windows/os_perf_windows.cpp +++ b/src/hotspot/os/windows/os_perf_windows.cpp @@ -32,9 +32,9 @@ #include "runtime/os_perf.hpp" #include "runtime/os.hpp" #include "runtime/semaphore.inline.hpp" +#include "runtime/vm_version.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/macros.hpp" -#include CPU_HEADER(vm_version_ext) #include #include #include @@ -1434,11 +1434,12 @@ CPUInformationInterface::CPUInformationInterface() : _cpu_info(NULL) {} bool CPUInformationInterface::initialize() { _cpu_info = new CPUInformation(); - _cpu_info->set_number_of_hardware_threads(VM_Version_Ext::number_of_threads()); - _cpu_info->set_number_of_cores(VM_Version_Ext::number_of_cores()); - _cpu_info->set_number_of_sockets(VM_Version_Ext::number_of_sockets()); - _cpu_info->set_cpu_name(VM_Version_Ext::cpu_name()); - _cpu_info->set_cpu_description(VM_Version_Ext::cpu_description()); + VM_Version::initialize_cpu_information(); + _cpu_info->set_number_of_hardware_threads(VM_Version::number_of_threads()); + _cpu_info->set_number_of_cores(VM_Version::number_of_cores()); + _cpu_info->set_number_of_sockets(VM_Version::number_of_sockets()); + _cpu_info->set_cpu_name(VM_Version::cpu_name()); + _cpu_info->set_cpu_description(VM_Version::cpu_description()); return true; } diff --git a/src/hotspot/os/windows/os_windows.cpp b/src/hotspot/os/windows/os_windows.cpp index 6f8c88d764da645dda82dcec3df6867efbcf4fcd..fd64008ab48e2851eeced4cfa203d0c05ba983d2 100644 --- a/src/hotspot/os/windows/os_windows.cpp +++ b/src/hotspot/os/windows/os_windows.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -529,7 +529,7 @@ static unsigned __stdcall thread_native_entry(Thread* thread) { res = 20115; // java thread } - log_info(os, thread)("Thread is alive (tid: " UINTX_FORMAT ").", os::current_thread_id()); + log_info(os, thread)("Thread is alive (tid: " UINTX_FORMAT ", stacksize: " SIZE_FORMAT "k).", os::current_thread_id(), thread->stack_size() / 1024); #ifdef USE_VECTORED_EXCEPTION_HANDLING // Any exception is caught by the Vectored Exception Handler, so VM can @@ -568,7 +568,7 @@ static unsigned __stdcall thread_native_entry(Thread* thread) { static OSThread* create_os_thread(Thread* thread, HANDLE thread_handle, int thread_id) { // Allocate the OSThread object - OSThread* osthread = new OSThread(NULL, NULL); + OSThread* osthread = new OSThread(); if (osthread == NULL) return NULL; // Initialize the JDK library's interrupt event. @@ -671,11 +671,14 @@ bool os::create_thread(Thread* thread, ThreadType thr_type, unsigned thread_id; // Allocate the OSThread object - OSThread* osthread = new OSThread(NULL, NULL); + OSThread* osthread = new OSThread(); if (osthread == NULL) { return false; } + // Initial state is ALLOCATED but not INITIALIZED + osthread->set_state(ALLOCATED); + // Initialize the JDK library's interrupt event. // This should really be done when OSThread is constructed, // but there is no way for a constructor to report failure to @@ -777,7 +780,7 @@ bool os::create_thread(Thread* thread, ThreadType thr_type, osthread->set_thread_handle(thread_handle); osthread->set_thread_id(thread_id); - // Initial thread state is INITIALIZED, not SUSPENDED + // Thread state now is INITIALIZED, not SUSPENDED osthread->set_state(INITIALIZED); // The thread is returned suspended (in state INITIALIZED), and is started higher up in the call chain @@ -1550,7 +1553,7 @@ void * os::dll_load(const char *name, char *ebuf, int ebuflen) { || // Read location of signature (sizeof(signature_offset) != - (os::read(fd, (void*)&signature_offset, sizeof(signature_offset)))) + (::read(fd, (void*)&signature_offset, sizeof(signature_offset)))) || // Go to COFF File Header in dll // that is located after "signature" (4 bytes long) @@ -1559,7 +1562,7 @@ void * os::dll_load(const char *name, char *ebuf, int ebuflen) { || // Read field that contains code of architecture // that dll was built for - (sizeof(lib_arch) != (os::read(fd, (void*)&lib_arch, sizeof(lib_arch)))) + (sizeof(lib_arch) != (::read(fd, (void*)&lib_arch, sizeof(lib_arch)))) ); ::close(fd); @@ -4455,7 +4458,7 @@ static errno_t get_full_path(LPCWSTR unicode_path, LPWSTR* full_path) { return ERROR_SUCCESS; } -static void set_path_prefix(char* buf, LPWSTR* prefix, int* prefix_off, bool* needs_fullpath) { +static void set_path_prefix(char* buf, LPCWSTR* prefix, int* prefix_off, bool* needs_fullpath) { *prefix_off = 0; *needs_fullpath = true; @@ -4491,7 +4494,7 @@ static wchar_t* wide_abs_unc_path(char const* path, errno_t & err, int additiona strncpy(buf, path, buf_len); os::native_path(buf); - LPWSTR prefix = NULL; + LPCWSTR prefix = NULL; int prefix_off = 0; bool needs_fullpath = true; set_path_prefix(buf, &prefix, &prefix_off, &needs_fullpath); @@ -4751,18 +4754,14 @@ int os::open(const char *path, int oflag, int mode) { return fd; } -FILE* os::open(int fd, const char* mode) { +FILE* os::fdopen(int fd, const char* mode) { return ::_fdopen(fd, mode); } -size_t os::write(int fd, const void *buf, unsigned int nBytes) { +ssize_t os::write(int fd, const void *buf, unsigned int nBytes) { return ::write(fd, buf, nBytes); } -int os::close(int fd) { - return ::close(fd); -} - void os::exit(int num) { win32::exit_process_or_thread(win32::EPT_PROCESS, num); } @@ -5722,10 +5721,6 @@ int os::socket_close(int fd) { return ::closesocket(fd); } -int os::socket(int domain, int type, int protocol) { - return ::socket(domain, type, protocol); -} - int os::connect(int fd, struct sockaddr* him, socklen_t len) { return ::connect(fd, him, len); } diff --git a/src/hotspot/os/windows/pdh_interface.hpp b/src/hotspot/os/windows/pdh_interface.hpp index 743c737d9982c6f1fca37eac2637ff4a37c6da72..151f9edd0e94906b1e56473a69337b7e3e8b9231 100644 --- a/src/hotspot/os/windows/pdh_interface.hpp +++ b/src/hotspot/os/windows/pdh_interface.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -25,7 +25,7 @@ #ifndef OS_WINDOWS_PDH_INTERFACE_HPP #define OS_WINDOWS_PDH_INTERFACE_HPP -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" #include #include diff --git a/src/hotspot/os/windows/perfMemory_windows.cpp b/src/hotspot/os/windows/perfMemory_windows.cpp index 600eb8882f9e4a51be91aa440713f0ff3dd29f36..0a53a94957c3d6d98db7dbe76637ed526be759ff 100644 --- a/src/hotspot/os/windows/perfMemory_windows.cpp +++ b/src/hotspot/os/windows/perfMemory_windows.cpp @@ -1834,7 +1834,7 @@ void PerfMemory::detach(char* addr, size_t bytes) { return; } - if (MemTracker::tracking_level() > NMT_minimal) { + if (MemTracker::enabled()) { // it does not go through os api, the operation has to record from here Tracker tkr(Tracker::release); remove_file_mapping(addr); diff --git a/src/hotspot/os/windows/threadLocalStorage_windows.cpp b/src/hotspot/os/windows/threadLocalStorage_windows.cpp index 5648a672d71667ec946e491c2de6f1f7cf03d37c..7d809518aab33f3d958465de61be07b39d49a491 100644 --- a/src/hotspot/os/windows/threadLocalStorage_windows.cpp +++ b/src/hotspot/os/windows/threadLocalStorage_windows.cpp @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "runtime/threadLocalStorage.hpp" +#include "utilities/debug.hpp" #include static DWORD _thread_key; diff --git a/src/hotspot/os_cpu/aix_ppc/thread_aix_ppc.cpp b/src/hotspot/os_cpu/aix_ppc/thread_aix_ppc.cpp index 6b810bd39185580ec524026ddac4d12ed546be84..44c7baebd7900f8a46587f41cd8097a7c4a071eb 100644 --- a/src/hotspot/os_cpu/aix_ppc/thread_aix_ppc.cpp +++ b/src/hotspot/os_cpu/aix_ppc/thread_aix_ppc.cpp @@ -1,6 +1,7 @@ /* * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, 2014 SAP SE. All rights reserved. + * Copyright (c) 2022, IBM Corp. * 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 +25,7 @@ */ #include "precompiled.hpp" +#include "memory/metaspace.hpp" #include "runtime/frame.inline.hpp" #include "runtime/thread.hpp" @@ -34,6 +36,8 @@ frame JavaThread::pd_last_frame() { address pc = _anchor.last_Java_pc(); // Last_Java_pc ist not set, if we come here from compiled code. + // Assume spill slot for link register contains a suitable pc. + // Should have been filled by method entry code. if (pc == NULL) pc = (address) *(sp + 2); @@ -41,16 +45,71 @@ frame JavaThread::pd_last_frame() { } bool JavaThread::pd_get_top_frame_for_profiling(frame* fr_addr, void* ucontext, bool isInJava) { - ucontext_t* uc = (ucontext_t*) ucontext; - *fr_addr = frame((intptr_t*)uc->uc_mcontext.jmp_context.gpr[1/*REG_SP*/], - (address)uc->uc_mcontext.jmp_context.iar); - return true; + + // If we have a last_Java_frame, then we should use it even if + // isInJava == true. It should be more reliable than ucontext info. + if (has_last_Java_frame() && frame_anchor()->walkable()) { + *fr_addr = pd_last_frame(); + return true; + } + + // At this point, we don't have a last_Java_frame, so + // we try to glean some information out of the ucontext + // if we were running Java code when SIGPROF came in. + if (isInJava) { + ucontext_t* uc = (ucontext_t*) ucontext; + address pc = (address)uc->uc_mcontext.jmp_context.iar; + + if (pc == NULL) { + // ucontext wasn't useful + return false; + } + + frame ret_frame((intptr_t*)uc->uc_mcontext.jmp_context.gpr[1/*REG_SP*/], pc); + + if (ret_frame.fp() == NULL) { + // The found frame does not have a valid frame pointer. + // Bail out because this will create big trouble later on, either + // - when using istate, calculated as (NULL - ijava_state_size) or + // - when using fp() directly in safe_for_sender() + // + // There is no conclusive description (yet) how this could happen, but it does. + // For more details on what was observed, see thread_linux_s390.cpp + return false; + } + + if (ret_frame.is_interpreted_frame()) { + frame::ijava_state *istate = ret_frame.get_ijava_state(); + const Method *m = (const Method*)(istate->method); + if (!Method::is_valid_method(m)) return false; + if (!Metaspace::contains(m->constMethod())) return false; + + uint64_t reg_bcp = uc->uc_mcontext.jmp_context.gpr[14/*R14_bcp*/]; + uint64_t istate_bcp = istate->bcp; + uint64_t code_start = (uint64_t)(m->code_base()); + uint64_t code_end = (uint64_t)(m->code_base() + m->code_size()); + if (istate_bcp >= code_start && istate_bcp < code_end) { + // we have a valid bcp, don't touch it, do nothing + } else if (reg_bcp >= code_start && reg_bcp < code_end) { + istate->bcp = reg_bcp; + } else { + return false; + } + } + if (!ret_frame.safe_for_sender(this)) { + // nothing else to try if the frame isn't good + return false; + } + *fr_addr = ret_frame; + return true; + } + // nothing else to try + return false; } -// Forte Analyzer AsyncGetCallTrace profiling support is not implemented on Aix/PPC. +// Forte Analyzer AsyncGetCallTrace profiling support. bool JavaThread::pd_get_top_frame_for_signal_handler(frame* fr_addr, void* ucontext, bool isInJava) { - Unimplemented(); - return false; + return pd_get_top_frame_for_profiling(fr_addr, ucontext, isInJava); } void JavaThread::cache_global_variables() { } diff --git a/src/hotspot/os_cpu/bsd_aarch64/copy_bsd_aarch64.hpp b/src/hotspot/os_cpu/bsd_aarch64/copy_bsd_aarch64.hpp index 6f08cb351252dbc92dd240104e45f119020de8ae..580daec9ebf2ecce47736a166e180d0440a9e547 100644 --- a/src/hotspot/os_cpu/bsd_aarch64/copy_bsd_aarch64.hpp +++ b/src/hotspot/os_cpu/bsd_aarch64/copy_bsd_aarch64.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, Red Hat Inc. All rights reserved. * Copyright (c) 2021, Azul Systems, Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -27,163 +27,6 @@ #ifndef OS_CPU_BSD_AARCH64_COPY_BSD_AARCH64_HPP #define OS_CPU_BSD_AARCH64_COPY_BSD_AARCH64_HPP -#define COPY_SMALL(from, to, count) \ -{ \ - long tmp0, tmp1, tmp2, tmp3; \ - long tmp4, tmp5, tmp6, tmp7; \ - __asm volatile( \ -" adr %[t0], 0f;\n" \ -" add %[t0], %[t0], %[cnt], lsl #5;\n" \ -" br %[t0];\n" \ -" .align 5;\n" \ -"0:" \ -" b 1f;\n" \ -" .align 5;\n" \ -" ldr %[t0], [%[s], #0];\n" \ -" str %[t0], [%[d], #0];\n" \ -" b 1f;\n" \ -" .align 5;\n" \ -" ldp %[t0], %[t1], [%[s], #0];\n" \ -" stp %[t0], %[t1], [%[d], #0];\n" \ -" b 1f;\n" \ -" .align 5;\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" \ -" 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" \ -" ldp %[t0], %[t1], [%[s], #0];\n" \ -" ldp %[t2], %[t3], [%[s], #16];\n" \ -" ldr %[t4], [%[s], #32];\n" \ -" stp %[t0], %[t1], [%[d], #0];\n" \ -" stp %[t2], %[t3], [%[d], #16];\n" \ -" str %[t4], [%[d], #32];\n" \ -" b 1f;\n" \ -" .align 5;\n" \ -" ldp %[t0], %[t1], [%[s], #0];\n" \ -" ldp %[t2], %[t3], [%[s], #16];\n" \ -" ldp %[t4], %[t5], [%[s], #32];\n" \ -"2:" \ -" stp %[t0], %[t1], [%[d], #0];\n" \ -" stp %[t2], %[t3], [%[d], #16];\n" \ -" stp %[t4], %[t5], [%[d], #32];\n" \ -" b 1f;\n" \ -" .align 5;\n" \ -" ldr %[t6], [%[s], #0];\n" \ -" ldp %[t0], %[t1], [%[s], #8];\n" \ -" ldp %[t2], %[t3], [%[s], #24];\n" \ -" ldp %[t4], %[t5], [%[s], #40];\n" \ -" str %[t6], [%[d]], #8;\n" \ -" b 2b;\n" \ -" .align 5;\n" \ -" ldp %[t0], %[t1], [%[s], #0];\n" \ -" ldp %[t2], %[t3], [%[s], #16];\n" \ -" ldp %[t4], %[t5], [%[s], #32];\n" \ -" ldp %[t6], %[t7], [%[s], #48];\n" \ -" stp %[t0], %[t1], [%[d], #0];\n" \ -" stp %[t2], %[t3], [%[d], #16];\n" \ -" stp %[t4], %[t5], [%[d], #32];\n" \ -" stp %[t6], %[t7], [%[d], #48];\n" \ -"1:" \ - \ - : [s]"+r"(from), [d]"+r"(to), [cnt]"+r"(count), \ - [t0]"=&r"(tmp0), [t1]"=&r"(tmp1), [t2]"=&r"(tmp2), [t3]"=&r"(tmp3), \ - [t4]"=&r"(tmp4), [t5]"=&r"(tmp5), [t6]"=&r"(tmp6), [t7]"=&r"(tmp7) \ - : \ - : "memory", "cc"); \ -} - -static void pd_conjoint_words(const HeapWord* from, HeapWord* to, size_t count) { - __asm volatile( "prfm pldl1strm, [%[s], #0];" :: [s]"r"(from) : "memory"); - if (__builtin_expect(count <= 8, 1)) { - COPY_SMALL(from, to, count); - return; - } - _Copy_conjoint_words(from, to, count); -} - -static void pd_disjoint_words(const HeapWord* from, HeapWord* to, size_t count) { - if (__builtin_constant_p(count)) { - memcpy(to, from, count * sizeof(HeapWord)); - return; - } - __asm volatile( "prfm pldl1strm, [%[s], #0];" :: [s]"r"(from) : "memory"); - if (__builtin_expect(count <= 8, 1)) { - COPY_SMALL(from, to, count); - return; - } - _Copy_disjoint_words(from, to, count); -} - -static void pd_disjoint_words_atomic(const HeapWord* from, HeapWord* to, size_t count) { - __asm volatile( "prfm pldl1strm, [%[s], #0];" :: [s]"r"(from) : "memory"); - if (__builtin_expect(count <= 8, 1)) { - COPY_SMALL(from, to, count); - return; - } - _Copy_disjoint_words(from, to, count); -} - -static void pd_aligned_conjoint_words(const HeapWord* from, HeapWord* to, size_t count) { - pd_conjoint_words(from, to, count); -} - -static void pd_aligned_disjoint_words(const HeapWord* from, HeapWord* to, size_t count) { - pd_disjoint_words(from, to, count); -} - -static void pd_conjoint_bytes(const void* from, void* to, size_t count) { - (void)memmove(to, from, count); -} - -static void pd_conjoint_bytes_atomic(const void* from, void* to, size_t count) { - pd_conjoint_bytes(from, to, count); -} - -static void pd_conjoint_jshorts_atomic(const jshort* from, jshort* to, size_t count) { - _Copy_conjoint_jshorts_atomic(from, to, count); -} - -static void pd_conjoint_jints_atomic(const jint* from, jint* to, size_t count) { - _Copy_conjoint_jints_atomic(from, to, count); -} - -static void pd_conjoint_jlongs_atomic(const jlong* from, jlong* to, size_t count) { - _Copy_conjoint_jlongs_atomic(from, to, count); -} - -static void pd_conjoint_oops_atomic(const oop* from, oop* to, size_t count) { - assert(BytesPerLong == BytesPerOop, "jlongs and oops must be the same size"); - _Copy_conjoint_jlongs_atomic((const jlong*)from, (jlong*)to, count); -} - -static void pd_arrayof_conjoint_bytes(const HeapWord* from, HeapWord* to, size_t count) { - _Copy_arrayof_conjoint_bytes(from, to, count); -} - -static void pd_arrayof_conjoint_jshorts(const HeapWord* from, HeapWord* to, size_t count) { - _Copy_arrayof_conjoint_jshorts(from, to, count); -} - -static void pd_arrayof_conjoint_jints(const HeapWord* from, HeapWord* to, size_t count) { - _Copy_arrayof_conjoint_jints(from, to, count); -} - -static void pd_arrayof_conjoint_jlongs(const HeapWord* from, HeapWord* to, size_t count) { - _Copy_arrayof_conjoint_jlongs(from, to, count); -} - -static void pd_arrayof_conjoint_oops(const HeapWord* from, HeapWord* to, size_t count) { - assert(!UseCompressedOops, "foo!"); - assert(BytesPerLong == BytesPerOop, "jlongs and oops must be the same size"); - _Copy_arrayof_conjoint_jlongs(from, to, count); -} +// Empty for build system #endif // OS_CPU_BSD_AARCH64_COPY_BSD_AARCH64_HPP diff --git a/src/hotspot/os_cpu/bsd_aarch64/pauth_bsd_aarch64.inline.hpp b/src/hotspot/os_cpu/bsd_aarch64/pauth_bsd_aarch64.inline.hpp index a4d416d384e29f2d5daedd76611ce78cfc456e54..4d07bbef3033240d42775dd24ac0db729a7ba46d 100644 --- a/src/hotspot/os_cpu/bsd_aarch64/pauth_bsd_aarch64.inline.hpp +++ b/src/hotspot/os_cpu/bsd_aarch64/pauth_bsd_aarch64.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Arm Limited. All rights reserved. + * Copyright (c) 2021, 2022, 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 @@ -25,29 +25,23 @@ #ifndef OS_CPU_BSD_AARCH64_PAUTH_BSD_AARCH64_INLINE_HPP #define OS_CPU_BSD_AARCH64_PAUTH_BSD_AARCH64_INLINE_HPP -#ifdef __APPLE__ -#include -#endif - -// Only the PAC instructions in the NOP space can be used. This ensures the -// binaries work on systems without PAC. Write these instructions using their -// alternate "hint" instructions to ensure older compilers can still be used. -// For Apple, use the provided interface as this may provide additional -// optimization. - -#define XPACLRI "hint #0x7;" +// OS specific Support for ROP Protection in VM code. +// For more details on PAC see pauth_aarch64.hpp. inline address pauth_strip_pointer(address ptr) { -#ifdef __APPLE__ - return ptrauth_strip(ptr, ptrauth_key_asib); -#else - register address result __asm__("x30") = ptr; - asm (XPACLRI : "+r"(result)); - return result; -#endif + // No PAC support in BSD as of yet. + return ptr; } -#undef XPACLRI +inline address pauth_sign_return_address(address ret_addr, address sp) { + // No PAC support in BSD as of yet. + return ret_addr; +} + +inline address pauth_authenticate_return_address(address ret_addr, address sp) { + // No PAC support in BSD as of yet. + return ret_addr; +} #endif // OS_CPU_BSD_AARCH64_PAUTH_BSD_AARCH64_INLINE_HPP diff --git a/src/hotspot/os_cpu/bsd_aarch64/thread_bsd_aarch64.cpp b/src/hotspot/os_cpu/bsd_aarch64/thread_bsd_aarch64.cpp index d8b1a0b20ef3287cb65acb47686f17b9c1a07e70..f07f22bc0cd7a3e8977883bc62f214f4e3ad942f 100644 --- a/src/hotspot/os_cpu/bsd_aarch64/thread_bsd_aarch64.cpp +++ b/src/hotspot/os_cpu/bsd_aarch64/thread_bsd_aarch64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, Red Hat Inc. All rights reserved. * Copyright (c) 2021, Azul Systems, Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -32,7 +32,9 @@ frame JavaThread::pd_last_frame() { assert(has_last_Java_frame(), "must have last_Java_sp() when suspended"); vmassert(_anchor.last_Java_pc() != NULL, "not walkable"); - return frame(_anchor.last_Java_sp(), _anchor.last_Java_fp(), _anchor.last_Java_pc()); + frame f = frame(_anchor.last_Java_sp(), _anchor.last_Java_fp(), _anchor.last_Java_pc()); + f.set_sp_is_trusted(); + return f; } // For Forte Analyzer AsyncGetCallTrace profiling support - thread is diff --git a/src/hotspot/os_cpu/bsd_x86/bsd_x86_32.S b/src/hotspot/os_cpu/bsd_x86/bsd_x86_32.S index 0d22a6a6790237637484b70ac27dad913ae0de50..02231040e15bda886acc2c0024f404c458b1b1d6 100644 --- a/src/hotspot/os_cpu/bsd_x86/bsd_x86_32.S +++ b/src/hotspot/os_cpu/bsd_x86/bsd_x86_32.S @@ -1,5 +1,5 @@ # -# Copyright (c) 2004, 2017, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2004, 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 @@ -39,7 +39,6 @@ # point or use it in the same manner as does the server # compiler. - .globl SYMBOL(_Copy_conjoint_bytes) .globl SYMBOL(_Copy_arrayof_conjoint_bytes) .globl SYMBOL(_Copy_conjoint_jshorts_atomic) .globl SYMBOL(_Copy_arrayof_conjoint_jshorts) @@ -72,117 +71,10 @@ SYMBOL(SpinPause): movl $1, %eax ret - # Support for void Copy::conjoint_bytes(void* from, - # void* to, - # size_t count) - .p2align 4,,15 - ELF_TYPE(_Copy_conjoint_bytes,@function) -SYMBOL(_Copy_conjoint_bytes): - pushl %esi - movl 4+12(%esp),%ecx # count - pushl %edi - movl 8+ 4(%esp),%esi # from - movl 8+ 8(%esp),%edi # to - cmpl %esi,%edi - leal -1(%esi,%ecx),%eax # from + count - 1 - jbe cb_CopyRight - cmpl %eax,%edi - jbe cb_CopyLeft - # copy from low to high -cb_CopyRight: - cmpl $3,%ecx - jbe 5f # <= 3 bytes - # align source address at dword address boundary - movl %ecx,%eax # original count - movl $4,%ecx - subl %esi,%ecx - andl $3,%ecx # prefix byte count - jz 1f # no prefix - subl %ecx,%eax # byte count less prefix - # copy prefix - subl %esi,%edi -0: movb (%esi),%dl - movb %dl,(%edi,%esi,1) - addl $1,%esi - subl $1,%ecx - jnz 0b - addl %esi,%edi -1: movl %eax,%ecx # byte count less prefix - shrl $2,%ecx # dword count - jz 4f # no dwords to move - cmpl $32,%ecx - jbe 2f # <= 32 dwords - # copy aligned dwords - rep; smovl - jmp 4f - # copy aligned dwords -2: subl %esi,%edi - .p2align 4,,15 -3: movl (%esi),%edx - movl %edx,(%edi,%esi,1) - addl $4,%esi - subl $1,%ecx - jnz 3b - addl %esi,%edi -4: movl %eax,%ecx # byte count less prefix -5: andl $3,%ecx # suffix byte count - jz 7f # no suffix - # copy suffix - xorl %eax,%eax -6: movb (%esi,%eax,1),%dl - movb %dl,(%edi,%eax,1) - addl $1,%eax - subl $1,%ecx - jnz 6b -7: popl %edi - popl %esi - ret - # copy from high to low -cb_CopyLeft: - std - leal -4(%edi,%ecx),%edi # to + count - 4 - movl %eax,%esi # from + count - 1 - movl %ecx,%eax - subl $3,%esi # from + count - 4 - cmpl $3,%ecx - jbe 5f # <= 3 bytes -1: shrl $2,%ecx # dword count - jz 4f # no dwords to move - cmpl $32,%ecx - ja 3f # > 32 dwords - # copy dwords, aligned or not - subl %esi,%edi - .p2align 4,,15 -2: movl (%esi),%edx - movl %edx,(%edi,%esi,1) - subl $4,%esi - subl $1,%ecx - jnz 2b - addl %esi,%edi - jmp 4f - # copy dwords, aligned or not -3: rep; smovl -4: movl %eax,%ecx # byte count -5: andl $3,%ecx # suffix byte count - jz 7f # no suffix - # copy suffix - subl %esi,%edi - addl $3,%esi -6: movb (%esi),%dl - movb %dl,(%edi,%esi,1) - subl $1,%esi - subl $1,%ecx - jnz 6b -7: cld - popl %edi - popl %esi - ret - # Support for void Copy::arrayof_conjoint_bytes(void* from, # void* to, # size_t count) # - # Same as _Copy_conjoint_bytes, except no source alignment check. .p2align 4,,15 ELF_TYPE(_Copy_arrayof_conjoint_bytes,@function) SYMBOL(_Copy_arrayof_conjoint_bytes): diff --git a/src/hotspot/os_cpu/bsd_x86/copy_bsd_x86.hpp b/src/hotspot/os_cpu/bsd_x86/copy_bsd_x86.hpp index 2a5498d8541aae88922896e8c2c6343616924fd4..e95c18c48a24632de6d2a337f4b5fa238a2e9b43 100644 --- a/src/hotspot/os_cpu/bsd_x86/copy_bsd_x86.hpp +++ b/src/hotspot/os_cpu/bsd_x86/copy_bsd_x86.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -25,285 +25,6 @@ #ifndef OS_CPU_BSD_X86_COPY_BSD_X86_HPP #define OS_CPU_BSD_X86_COPY_BSD_X86_HPP -static void pd_conjoint_words(const HeapWord* from, HeapWord* to, size_t count) { -#ifdef AMD64 - (void)memmove(to, from, count * HeapWordSize); -#else - // Includes a zero-count check. - intx temp; - __asm__ volatile(" testl %6,%6 ;" - " jz 7f ;" - " cmpl %4,%5 ;" - " leal -4(%4,%6,4),%3;" - " jbe 1f ;" - " cmpl %7,%5 ;" - " jbe 4f ;" - "1: cmpl $32,%6 ;" - " ja 3f ;" - " subl %4,%1 ;" - "2: movl (%4),%3 ;" - " movl %7,(%5,%4,1) ;" - " addl $4,%0 ;" - " subl $1,%2 ;" - " jnz 2b ;" - " jmp 7f ;" - "3: rep; smovl ;" - " jmp 7f ;" - "4: cmpl $32,%2 ;" - " movl %7,%0 ;" - " leal -4(%5,%6,4),%1;" - " ja 6f ;" - " subl %4,%1 ;" - "5: movl (%4),%3 ;" - " movl %7,(%5,%4,1) ;" - " subl $4,%0 ;" - " subl $1,%2 ;" - " jnz 5b ;" - " jmp 7f ;" - "6: std ;" - " rep; smovl ;" - " cld ;" - "7: nop " - : "=S" (from), "=D" (to), "=c" (count), "=r" (temp) - : "0" (from), "1" (to), "2" (count), "3" (temp) - : "memory", "flags"); -#endif // AMD64 -} - -static void pd_disjoint_words(const HeapWord* from, HeapWord* to, size_t count) { -#ifdef AMD64 - switch (count) { - case 8: to[7] = from[7]; - case 7: to[6] = from[6]; - case 6: to[5] = from[5]; - case 5: to[4] = from[4]; - case 4: to[3] = from[3]; - case 3: to[2] = from[2]; - case 2: to[1] = from[1]; - case 1: to[0] = from[0]; - case 0: break; - default: - (void)memcpy(to, from, count * HeapWordSize); - break; - } -#else - // Includes a zero-count check. - intx temp; - __asm__ volatile(" testl %6,%6 ;" - " jz 3f ;" - " cmpl $32,%6 ;" - " ja 2f ;" - " subl %4,%1 ;" - "1: movl (%4),%3 ;" - " movl %7,(%5,%4,1);" - " addl $4,%0 ;" - " subl $1,%2 ;" - " jnz 1b ;" - " jmp 3f ;" - "2: rep; smovl ;" - "3: nop " - : "=S" (from), "=D" (to), "=c" (count), "=r" (temp) - : "0" (from), "1" (to), "2" (count), "3" (temp) - : "memory", "cc"); -#endif // AMD64 -} - -static void pd_disjoint_words_atomic(const HeapWord* from, HeapWord* to, size_t count) { -#ifdef AMD64 - switch (count) { - case 8: to[7] = from[7]; - case 7: to[6] = from[6]; - case 6: to[5] = from[5]; - case 5: to[4] = from[4]; - case 4: to[3] = from[3]; - case 3: to[2] = from[2]; - case 2: to[1] = from[1]; - case 1: to[0] = from[0]; - case 0: break; - default: - while (count-- > 0) { - *to++ = *from++; - } - break; - } -#else - // pd_disjoint_words is word-atomic in this implementation. - pd_disjoint_words(from, to, count); -#endif // AMD64 -} - -static void pd_aligned_conjoint_words(const HeapWord* from, HeapWord* to, size_t count) { - pd_conjoint_words(from, to, count); -} - -static void pd_aligned_disjoint_words(const HeapWord* from, HeapWord* to, size_t count) { - pd_disjoint_words(from, to, count); -} - -static void pd_conjoint_bytes(const void* from, void* to, size_t count) { -#ifdef AMD64 - (void)memmove(to, from, count); -#else - // Includes a zero-count check. - intx temp; - __asm__ volatile(" testl %6,%6 ;" - " jz 13f ;" - " cmpl %4,%5 ;" - " leal -1(%4,%6),%3 ;" - " jbe 1f ;" - " cmpl %7,%5 ;" - " jbe 8f ;" - "1: cmpl $3,%6 ;" - " jbe 6f ;" - " movl %6,%3 ;" - " movl $4,%2 ;" - " subl %4,%2 ;" - " andl $3,%2 ;" - " jz 2f ;" - " subl %6,%3 ;" - " rep; smovb ;" - "2: movl %7,%2 ;" - " shrl $2,%2 ;" - " jz 5f ;" - " cmpl $32,%2 ;" - " ja 4f ;" - " subl %4,%1 ;" - "3: movl (%4),%%edx ;" - " movl %%edx,(%5,%4,1);" - " addl $4,%0 ;" - " subl $1,%2 ;" - " jnz 3b ;" - " addl %4,%1 ;" - " jmp 5f ;" - "4: rep; smovl ;" - "5: movl %7,%2 ;" - " andl $3,%2 ;" - " jz 13f ;" - "6: xorl %7,%3 ;" - "7: movb (%4,%7,1),%%dl ;" - " movb %%dl,(%5,%7,1) ;" - " addl $1,%3 ;" - " subl $1,%2 ;" - " jnz 7b ;" - " jmp 13f ;" - "8: std ;" - " cmpl $12,%2 ;" - " ja 9f ;" - " movl %7,%0 ;" - " leal -1(%6,%5),%1 ;" - " jmp 11f ;" - "9: xchgl %3,%2 ;" - " movl %6,%0 ;" - " addl $1,%2 ;" - " leal -1(%7,%5),%1 ;" - " andl $3,%2 ;" - " jz 10f ;" - " subl %6,%3 ;" - " rep; smovb ;" - "10: movl %7,%2 ;" - " subl $3,%0 ;" - " shrl $2,%2 ;" - " subl $3,%1 ;" - " rep; smovl ;" - " andl $3,%3 ;" - " jz 12f ;" - " movl %7,%2 ;" - " addl $3,%0 ;" - " addl $3,%1 ;" - "11: rep; smovb ;" - "12: cld ;" - "13: nop ;" - : "=S" (from), "=D" (to), "=c" (count), "=r" (temp) - : "0" (from), "1" (to), "2" (count), "3" (temp) - : "memory", "flags", "%edx"); -#endif // AMD64 -} - -static void pd_conjoint_bytes_atomic(const void* from, void* to, size_t count) { - pd_conjoint_bytes(from, to, count); -} - -static void pd_conjoint_jshorts_atomic(const jshort* from, jshort* to, size_t count) { - _Copy_conjoint_jshorts_atomic(from, to, count); -} - -static void pd_conjoint_jints_atomic(const jint* from, jint* to, size_t count) { -#ifdef AMD64 - _Copy_conjoint_jints_atomic(from, to, count); -#else - assert(HeapWordSize == BytesPerInt, "heapwords and jints must be the same size"); - // pd_conjoint_words is word-atomic in this implementation. - pd_conjoint_words((const HeapWord*)from, (HeapWord*)to, count); -#endif // AMD64 -} - -static void pd_conjoint_jlongs_atomic(const jlong* from, jlong* to, size_t count) { -#ifdef AMD64 - _Copy_conjoint_jlongs_atomic(from, to, count); -#else - // Guarantee use of fild/fistp or xmm regs via some asm code, because compilers won't. - if (from > to) { - while (count-- > 0) { - __asm__ volatile("fildll (%0); fistpll (%1)" - : - : "r" (from), "r" (to) - : "memory" ); - ++from; - ++to; - } - } else { - while (count-- > 0) { - __asm__ volatile("fildll (%0,%2,8); fistpll (%1,%2,8)" - : - : "r" (from), "r" (to), "r" (count) - : "memory" ); - } - } -#endif // AMD64 -} - -static void pd_conjoint_oops_atomic(const oop* from, oop* to, size_t count) { -#ifdef AMD64 - assert(BytesPerLong == BytesPerOop, "jlongs and oops must be the same size"); - _Copy_conjoint_jlongs_atomic((const jlong*)from, (jlong*)to, count); -#else - assert(HeapWordSize == BytesPerOop, "heapwords and oops must be the same size"); - // pd_conjoint_words is word-atomic in this implementation. - pd_conjoint_words((const HeapWord*)from, (HeapWord*)to, count); -#endif // AMD64 -} - -static void pd_arrayof_conjoint_bytes(const HeapWord* from, HeapWord* to, size_t count) { - _Copy_arrayof_conjoint_bytes(from, to, count); -} - -static void pd_arrayof_conjoint_jshorts(const HeapWord* from, HeapWord* to, size_t count) { - _Copy_arrayof_conjoint_jshorts(from, to, count); -} - -static void pd_arrayof_conjoint_jints(const HeapWord* from, HeapWord* to, size_t count) { -#ifdef AMD64 - _Copy_arrayof_conjoint_jints(from, to, count); -#else - pd_conjoint_jints_atomic((const jint*)from, (jint*)to, count); -#endif // AMD64 -} - -static void pd_arrayof_conjoint_jlongs(const HeapWord* from, HeapWord* to, size_t count) { -#ifdef AMD64 - _Copy_arrayof_conjoint_jlongs(from, to, count); -#else - pd_conjoint_jlongs_atomic((const jlong*)from, (jlong*)to, count); -#endif // AMD64 -} - -static void pd_arrayof_conjoint_oops(const HeapWord* from, HeapWord* to, size_t count) { -#ifdef AMD64 - assert(BytesPerLong == BytesPerOop, "jlongs and oops must be the same size"); - _Copy_arrayof_conjoint_jlongs(from, to, count); -#else - pd_conjoint_oops_atomic((const oop*)from, (oop*)to, count); -#endif // AMD64 -} +// Empty for build system #endif // OS_CPU_BSD_X86_COPY_BSD_X86_HPP diff --git a/src/hotspot/os_cpu/linux_aarch64/copy_linux_aarch64.hpp b/src/hotspot/os_cpu/linux_aarch64/copy_linux_aarch64.hpp index f50d80022ae16db558d5c706039457028cc3e9ef..302929d85750daccd1dc099d510331cdcac72d4a 100644 --- a/src/hotspot/os_cpu/linux_aarch64/copy_linux_aarch64.hpp +++ b/src/hotspot/os_cpu/linux_aarch64/copy_linux_aarch64.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2022, 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. * @@ -26,163 +26,6 @@ #ifndef OS_CPU_LINUX_AARCH64_COPY_LINUX_AARCH64_HPP #define OS_CPU_LINUX_AARCH64_COPY_LINUX_AARCH64_HPP -#define COPY_SMALL(from, to, count) \ -{ \ - long tmp0, tmp1, tmp2, tmp3; \ - long tmp4, tmp5, tmp6, tmp7; \ - __asm volatile( \ -" adr %[t0], 0f;" \ -" add %[t0], %[t0], %[cnt], lsl #5;" \ -" br %[t0];" \ -" .align 5;" \ -"0:" \ -" b 1f;" \ -" .align 5;" \ -" ldr %[t0], [%[s], #0];" \ -" str %[t0], [%[d], #0];" \ -" b 1f;" \ -" .align 5;" \ -" ldp %[t0], %[t1], [%[s], #0];" \ -" stp %[t0], %[t1], [%[d], #0];" \ -" b 1f;" \ -" .align 5;" \ -" ldp %[t0], %[t1], [%[s], #0];" \ -" ldr %[t2], [%[s], #16];" \ -" stp %[t0], %[t1], [%[d], #0];" \ -" str %[t2], [%[d], #16];" \ -" b 1f;" \ -" .align 5;" \ -" ldp %[t0], %[t1], [%[s], #0];" \ -" ldp %[t2], %[t3], [%[s], #16];" \ -" stp %[t0], %[t1], [%[d], #0];" \ -" stp %[t2], %[t3], [%[d], #16];" \ -" b 1f;" \ -" .align 5;" \ -" ldp %[t0], %[t1], [%[s], #0];" \ -" ldp %[t2], %[t3], [%[s], #16];" \ -" ldr %[t4], [%[s], #32];" \ -" stp %[t0], %[t1], [%[d], #0];" \ -" stp %[t2], %[t3], [%[d], #16];" \ -" str %[t4], [%[d], #32];" \ -" b 1f;" \ -" .align 5;" \ -" ldp %[t0], %[t1], [%[s], #0];" \ -" ldp %[t2], %[t3], [%[s], #16];" \ -" ldp %[t4], %[t5], [%[s], #32];" \ -"2:" \ -" stp %[t0], %[t1], [%[d], #0];" \ -" stp %[t2], %[t3], [%[d], #16];" \ -" stp %[t4], %[t5], [%[d], #32];" \ -" b 1f;" \ -" .align 5;" \ -" ldr %[t6], [%[s], #0];" \ -" ldp %[t0], %[t1], [%[s], #8];" \ -" ldp %[t2], %[t3], [%[s], #24];" \ -" ldp %[t4], %[t5], [%[s], #40];" \ -" str %[t6], [%[d]], #8;" \ -" b 2b;" \ -" .align 5;" \ -" ldp %[t0], %[t1], [%[s], #0];" \ -" ldp %[t2], %[t3], [%[s], #16];" \ -" ldp %[t4], %[t5], [%[s], #32];" \ -" ldp %[t6], %[t7], [%[s], #48];" \ -" stp %[t0], %[t1], [%[d], #0];" \ -" stp %[t2], %[t3], [%[d], #16];" \ -" stp %[t4], %[t5], [%[d], #32];" \ -" stp %[t6], %[t7], [%[d], #48];" \ -"1:" \ - \ - : [s]"+r"(from), [d]"+r"(to), [cnt]"+r"(count), \ - [t0]"=&r"(tmp0), [t1]"=&r"(tmp1), [t2]"=&r"(tmp2), [t3]"=&r"(tmp3), \ - [t4]"=&r"(tmp4), [t5]"=&r"(tmp5), [t6]"=&r"(tmp6), [t7]"=&r"(tmp7) \ - : \ - : "memory", "cc"); \ -} - -static void pd_conjoint_words(const HeapWord* from, HeapWord* to, size_t count) { - __asm volatile( "prfm pldl1strm, [%[s], #0];" :: [s]"r"(from) : "memory"); - if (__builtin_expect(count <= 8, 1)) { - COPY_SMALL(from, to, count); - return; - } - _Copy_conjoint_words(from, to, count); -} - -static void pd_disjoint_words(const HeapWord* from, HeapWord* to, size_t count) { - if (__builtin_constant_p(count)) { - memcpy(to, from, count * sizeof(HeapWord)); - return; - } - __asm volatile( "prfm pldl1strm, [%[s], #0];" :: [s]"r"(from) : "memory"); - if (__builtin_expect(count <= 8, 1)) { - COPY_SMALL(from, to, count); - return; - } - _Copy_disjoint_words(from, to, count); -} - -static void pd_disjoint_words_atomic(const HeapWord* from, HeapWord* to, size_t count) { - __asm volatile( "prfm pldl1strm, [%[s], #0];" :: [s]"r"(from) : "memory"); - if (__builtin_expect(count <= 8, 1)) { - COPY_SMALL(from, to, count); - return; - } - _Copy_disjoint_words(from, to, count); -} - -static void pd_aligned_conjoint_words(const HeapWord* from, HeapWord* to, size_t count) { - pd_conjoint_words(from, to, count); -} - -static void pd_aligned_disjoint_words(const HeapWord* from, HeapWord* to, size_t count) { - pd_disjoint_words(from, to, count); -} - -static void pd_conjoint_bytes(const void* from, void* to, size_t count) { - (void)memmove(to, from, count); -} - -static void pd_conjoint_bytes_atomic(const void* from, void* to, size_t count) { - pd_conjoint_bytes(from, to, count); -} - -static void pd_conjoint_jshorts_atomic(const jshort* from, jshort* to, size_t count) { - _Copy_conjoint_jshorts_atomic(from, to, count); -} - -static void pd_conjoint_jints_atomic(const jint* from, jint* to, size_t count) { - _Copy_conjoint_jints_atomic(from, to, count); -} - -static void pd_conjoint_jlongs_atomic(const jlong* from, jlong* to, size_t count) { - _Copy_conjoint_jlongs_atomic(from, to, count); -} - -static void pd_conjoint_oops_atomic(const oop* from, oop* to, size_t count) { - assert(BytesPerLong == BytesPerOop, "jlongs and oops must be the same size"); - _Copy_conjoint_jlongs_atomic((const jlong*)from, (jlong*)to, count); -} - -static void pd_arrayof_conjoint_bytes(const HeapWord* from, HeapWord* to, size_t count) { - _Copy_arrayof_conjoint_bytes(from, to, count); -} - -static void pd_arrayof_conjoint_jshorts(const HeapWord* from, HeapWord* to, size_t count) { - _Copy_arrayof_conjoint_jshorts(from, to, count); -} - -static void pd_arrayof_conjoint_jints(const HeapWord* from, HeapWord* to, size_t count) { - _Copy_arrayof_conjoint_jints(from, to, count); -} - -static void pd_arrayof_conjoint_jlongs(const HeapWord* from, HeapWord* to, size_t count) { - _Copy_arrayof_conjoint_jlongs(from, to, count); -} - -static void pd_arrayof_conjoint_oops(const HeapWord* from, HeapWord* to, size_t count) { - assert(!UseCompressedOops, "foo!"); - assert(BytesPerLong == BytesPerOop, "jlongs and oops must be the same size"); - _Copy_arrayof_conjoint_jlongs(from, to, count); -} +// Empty for build system #endif // OS_CPU_LINUX_AARCH64_COPY_LINUX_AARCH64_HPP diff --git a/src/hotspot/os_cpu/linux_aarch64/os_linux_aarch64.cpp b/src/hotspot/os_cpu/linux_aarch64/os_linux_aarch64.cpp index b3c60b6e6248241b6321b3090ce4fe03622842d0..6b09069e09dd71a03002722f5a285d2f62ae1dbd 100644 --- a/src/hotspot/os_cpu/linux_aarch64/os_linux_aarch64.cpp +++ b/src/hotspot/os_cpu/linux_aarch64/os_linux_aarch64.cpp @@ -382,7 +382,20 @@ int os::extra_bang_size_in_bytes() { extern "C" { int SpinPause() { - return 0; + using spin_wait_func_ptr_t = void (*)(); + spin_wait_func_ptr_t func = CAST_TO_FN_PTR(spin_wait_func_ptr_t, StubRoutines::aarch64::spin_wait()); + assert(func != nullptr, "StubRoutines::aarch64::spin_wait must not be null."); + (*func)(); + // If StubRoutines::aarch64::spin_wait consists of only a RET, + // SpinPause can be considered as implemented. There will be a sequence + // of instructions for: + // - call of SpinPause + // - load of StubRoutines::aarch64::spin_wait stub pointer + // - indirect call of the stub + // - return from the stub + // - return from SpinPause + // So '1' always is returned. + return 1; } void _Copy_conjoint_jshorts_atomic(const jshort* from, jshort* to, size_t count) { diff --git a/src/hotspot/os_cpu/linux_aarch64/pauth_linux_aarch64.inline.hpp b/src/hotspot/os_cpu/linux_aarch64/pauth_linux_aarch64.inline.hpp index 6f3fd41539c62d430633af1e464fdb058bd9f090..1eb1b92b9365ce23a16dc69351ae9e8815c64851 100644 --- a/src/hotspot/os_cpu/linux_aarch64/pauth_linux_aarch64.inline.hpp +++ b/src/hotspot/os_cpu/linux_aarch64/pauth_linux_aarch64.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Arm Limited. All rights reserved. + * Copyright (c) 2021, 2022, 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 @@ -25,18 +25,57 @@ #ifndef OS_CPU_LINUX_AARCH64_PAUTH_LINUX_AARCH64_INLINE_HPP #define OS_CPU_LINUX_AARCH64_PAUTH_LINUX_AARCH64_INLINE_HPP -// Only the PAC instructions in the NOP space can be used. This ensures the -// binaries work on systems without PAC. Write these instructions using their -// alternate "hint" instructions to ensure older compilers can still be used. +// OS specific Support for ROP Protection in VM code. +// For more details on PAC see pauth_aarch64.hpp. -#define XPACLRI "hint #0x7;" +inline bool pauth_ptr_is_raw(address ptr); +// Use only the PAC instructions in the NOP space. This ensures the binaries work on systems +// without PAC. Write these instructions using their alternate "hint" instructions to ensure older +// compilers can still be used. +#define XPACLRI "hint #0x7;" +#define PACIA1716 "hint #0x8;" +#define AUTIA1716 "hint #0xc;" + +// Strip an address. Use with caution - only if there is no guaranteed way of authenticating the +// value. +// inline address pauth_strip_pointer(address ptr) { register address result __asm__("x30") = ptr; asm (XPACLRI : "+r"(result)); return result; } +// Sign a return value, using the given modifier. +// +inline address pauth_sign_return_address(address ret_addr, address sp) { + if (VM_Version::use_rop_protection()) { + // A pointer cannot be double signed. + guarantee(pauth_ptr_is_raw(ret_addr), "Return address is already signed"); + register address r17 __asm("r17") = ret_addr; + register address r16 __asm("r16") = sp; + asm (PACIA1716 : "+r"(r17) : "r"(r16)); + ret_addr = r17; + } + return ret_addr; +} + +// Authenticate a return value, using the given modifier. +// +inline address pauth_authenticate_return_address(address ret_addr, address sp) { + if (VM_Version::use_rop_protection()) { + register address r17 __asm("r17") = ret_addr; + register address r16 __asm("r16") = sp; + asm (AUTIA1716 : "+r"(r17) : "r"(r16)); + ret_addr = r17; + // Ensure that the pointer authenticated. + guarantee(pauth_ptr_is_raw(ret_addr), "Return address did not authenticate"); + } + return ret_addr; +} + #undef XPACLRI +#undef PACIA1716 +#undef AUTIA1716 #endif // OS_CPU_LINUX_AARCH64_PAUTH_LINUX_AARCH64_INLINE_HPP 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 f541844b9d6dfd9d230ad73d0f19184731139af6..ac60d6aa941689c1b74a9fa6758cf11dded26df7 100644 --- a/src/hotspot/os_cpu/linux_aarch64/threadLS_linux_aarch64.S +++ b/src/hotspot/os_cpu/linux_aarch64/threadLS_linux_aarch64.S @@ -1,4 +1,4 @@ -// Copyright (c) 2015, Red Hat Inc. All rights reserved. +// 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 @@ -29,6 +29,7 @@ .type _ZN10JavaThread25aarch64_get_thread_helperEv, %function _ZN10JavaThread25aarch64_get_thread_helperEv: + hint #0x19 // paciasp stp x29, x30, [sp, -16]! adrp x0, :tlsdesc:_ZN6Thread12_thr_currentE ldr x1, [x0, #:tlsdesc_lo12:_ZN6Thread12_thr_currentE] @@ -39,6 +40,7 @@ _ZN10JavaThread25aarch64_get_thread_helperEv: add x0, x1, x0 ldr x0, [x0] ldp x29, x30, [sp], 16 + hint #0x1d // autiasp ret .size _ZN10JavaThread25aarch64_get_thread_helperEv, .-_ZN10JavaThread25aarch64_get_thread_helperEv diff --git a/src/hotspot/os_cpu/linux_aarch64/thread_linux_aarch64.cpp b/src/hotspot/os_cpu/linux_aarch64/thread_linux_aarch64.cpp index fca22629bc5651dfb40e4e59f5a0453aa8611552..f584da5814a684ecec06ef93ba4cccb9a0b3ff71 100644 --- a/src/hotspot/os_cpu/linux_aarch64/thread_linux_aarch64.cpp +++ b/src/hotspot/os_cpu/linux_aarch64/thread_linux_aarch64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2022, 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. * @@ -29,7 +29,9 @@ frame JavaThread::pd_last_frame() { assert(has_last_Java_frame(), "must have last_Java_sp() when suspended"); - return frame(_anchor.last_Java_sp(), _anchor.last_Java_fp(), _anchor.last_Java_pc()); + frame f = frame(_anchor.last_Java_sp(), _anchor.last_Java_fp(), _anchor.last_Java_pc()); + f.set_sp_is_trusted(); + return f; } // For Forte Analyzer AsyncGetCallTrace profiling support - thread is diff --git a/src/hotspot/os_cpu/linux_aarch64/vm_version_linux_aarch64.cpp b/src/hotspot/os_cpu/linux_aarch64/vm_version_linux_aarch64.cpp index 3497ae2ce73a59c4c3a74e85d2686a580fb131f0..b1080e77c908cf0bfdc63a77a42016e6d1a0de32 100644 --- a/src/hotspot/os_cpu/linux_aarch64/vm_version_linux_aarch64.cpp +++ b/src/hotspot/os_cpu/linux_aarch64/vm_version_linux_aarch64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2022, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -72,6 +72,10 @@ #define HWCAP_SVE (1 << 22) #endif +#ifndef HWCAP_PACA +#define HWCAP_PACA (1 << 30) +#endif + #ifndef HWCAP2_SVE2 #define HWCAP2_SVE2 (1 << 1) #endif @@ -111,6 +115,7 @@ void VM_Version::get_os_cpu_info() { static_assert(CPU_SHA3 == HWCAP_SHA3, "Flag CPU_SHA3 must follow Linux HWCAP"); static_assert(CPU_SHA512 == HWCAP_SHA512, "Flag CPU_SHA512 must follow Linux HWCAP"); static_assert(CPU_SVE == HWCAP_SVE, "Flag CPU_SVE must follow Linux HWCAP"); + static_assert(CPU_PACA == HWCAP_PACA, "Flag CPU_PACA must follow Linux HWCAP"); _features = auxv & ( HWCAP_FP | HWCAP_ASIMD | @@ -124,7 +129,8 @@ void VM_Version::get_os_cpu_info() { HWCAP_DCPOP | HWCAP_SHA3 | HWCAP_SHA512 | - HWCAP_SVE); + HWCAP_SVE | + HWCAP_PACA); if (auxv2 & HWCAP2_SVE2) _features |= CPU_SVE2; @@ -143,7 +149,7 @@ void VM_Version::get_os_cpu_info() { _zva_length = 4 << (dczid_el0 & 0xf); } - if (FILE *f = fopen("/proc/cpuinfo", "r")) { + if (FILE *f = os::fopen("/proc/cpuinfo", "r")) { // need a large buffer as the flags line may include lots of text char buf[1024], *p; while (fgets(buf, sizeof (buf), f) != NULL) { @@ -174,8 +180,8 @@ static bool read_fully(const char *fname, char *buf, size_t buflen) { assert(buflen >= 1, "invalid argument"); int fd = os::open(fname, O_RDONLY, 0); if (fd != -1) { - ssize_t read_sz = os::read(fd, buf, buflen); - os::close(fd); + ssize_t read_sz = ::read(fd, buf, buflen); + ::close(fd); // Skip if the contents is just "\n" because some machine only sets // '\n' to the board name. diff --git a/src/hotspot/os_cpu/linux_arm/linux_arm_32.S b/src/hotspot/os_cpu/linux_arm/linux_arm_32.S index c1c8fd428154ea929b1b58916b6d6aa65b6a87de..eb560d8f0c78b7bb904d77c28900ecb5e3836912 100644 --- a/src/hotspot/os_cpu/linux_arm/linux_arm_32.S +++ b/src/hotspot/os_cpu/linux_arm/linux_arm_32.S @@ -1,5 +1,5 @@ # -# Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2008, 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 @@ -58,12 +58,6 @@ to .req r1 SpinPause: bx LR - # Support for void Copy::conjoint_bytes(void* from, - # void* to, - # size_t count) -_Copy_conjoint_bytes: - swi 0x9f0001 - # Support for void Copy::arrayof_conjoint_bytes(void* from, # void* to, # size_t count) diff --git a/src/hotspot/os_cpu/linux_ppc/thread_linux_ppc.cpp b/src/hotspot/os_cpu/linux_ppc/thread_linux_ppc.cpp index d09608c6aa763ff7f0b9cefea44f7871c5e95660..15f6220fc81dc37ed8cf177e2c829d278d8a2737 100644 --- a/src/hotspot/os_cpu/linux_ppc/thread_linux_ppc.cpp +++ b/src/hotspot/os_cpu/linux_ppc/thread_linux_ppc.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2019 SAP SE. All rights reserved. + * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -58,14 +58,15 @@ bool JavaThread::pd_get_top_frame_for_profiling(frame* fr_addr, void* ucontext, // if we were running Java code when SIGPROF came in. if (isInJava) { ucontext_t* uc = (ucontext_t*) ucontext; - frame ret_frame((intptr_t*)uc->uc_mcontext.regs->gpr[1/*REG_SP*/], - (address)uc->uc_mcontext.regs->nip); + address pc = (address)uc->uc_mcontext.regs->nip; - if (ret_frame.pc() == NULL) { + if (pc == NULL) { // ucontext wasn't useful return false; } + frame ret_frame((intptr_t*)uc->uc_mcontext.regs->gpr[1/*REG_SP*/], pc); + if (ret_frame.fp() == NULL) { // The found frame does not have a valid frame pointer. // Bail out because this will create big trouble later on, either diff --git a/src/hotspot/os_cpu/linux_s390/thread_linux_s390.cpp b/src/hotspot/os_cpu/linux_s390/thread_linux_s390.cpp index d06b851a99f67dad72fc2ef554c33f15f0c8335e..3b16096784f224054b1ec866a092cc322467d1f1 100644 --- a/src/hotspot/os_cpu/linux_s390/thread_linux_s390.cpp +++ b/src/hotspot/os_cpu/linux_s390/thread_linux_s390.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2016, 2019 SAP SE. All rights reserved. + * Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 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 @@ -58,14 +58,15 @@ bool JavaThread::pd_get_top_frame_for_profiling(frame* fr_addr, void* ucontext, // if we were running Java code when SIGPROF came in. if (isInJava) { ucontext_t* uc = (ucontext_t*) ucontext; - frame ret_frame((intptr_t*)uc->uc_mcontext.gregs[15/*Z_SP*/], - (address)uc->uc_mcontext.psw.addr); + address pc = (address)uc->uc_mcontext.psw.addr; - if (ret_frame.pc() == NULL) { + if (pc == NULL) { // ucontext wasn't useful return false; } + frame ret_frame((intptr_t*)uc->uc_mcontext.gregs[15/*Z_SP*/], pc); + if (ret_frame.fp() == NULL) { // The found frame does not have a valid frame pointer. // Bail out because this will create big trouble later on, either @@ -100,7 +101,7 @@ bool JavaThread::pd_get_top_frame_for_profiling(frame* fr_addr, void* ucontext, if (ret_frame.is_interpreted_frame()) { frame::z_ijava_state* istate = ret_frame.ijava_state_unchecked(); - if (is_in_full_stack((address)istate)) { + if (!is_in_full_stack((address)istate)) { return false; } const Method *m = (const Method*)(istate->method); diff --git a/src/hotspot/os_cpu/linux_x86/copy_linux_x86.hpp b/src/hotspot/os_cpu/linux_x86/copy_linux_x86.hpp index de43d12f4a76f62013d4cddba377bfc0ad68ccd8..ed25d38cbffa07f7cb330117e66d9a2ee8343f56 100644 --- a/src/hotspot/os_cpu/linux_x86/copy_linux_x86.hpp +++ b/src/hotspot/os_cpu/linux_x86/copy_linux_x86.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -25,285 +25,6 @@ #ifndef OS_CPU_LINUX_X86_COPY_LINUX_X86_HPP #define OS_CPU_LINUX_X86_COPY_LINUX_X86_HPP -static void pd_conjoint_words(const HeapWord* from, HeapWord* to, size_t count) { -#ifdef AMD64 - (void)memmove(to, from, count * HeapWordSize); -#else - // Includes a zero-count check. - intx temp = 0; - __asm__ volatile(" testl %6,%6 ;" - " jz 7f ;" - " cmpl %4,%5 ;" - " leal -4(%4,%6,4),%3;" - " jbe 1f ;" - " cmpl %7,%5 ;" - " jbe 4f ;" - "1: cmpl $32,%6 ;" - " ja 3f ;" - " subl %4,%1 ;" - "2: movl (%4),%3 ;" - " movl %7,(%5,%4,1) ;" - " addl $4,%0 ;" - " subl $1,%2 ;" - " jnz 2b ;" - " jmp 7f ;" - "3: rep; smovl ;" - " jmp 7f ;" - "4: cmpl $32,%2 ;" - " movl %7,%0 ;" - " leal -4(%5,%6,4),%1;" - " ja 6f ;" - " subl %4,%1 ;" - "5: movl (%4),%3 ;" - " movl %7,(%5,%4,1) ;" - " subl $4,%0 ;" - " subl $1,%2 ;" - " jnz 5b ;" - " jmp 7f ;" - "6: std ;" - " rep; smovl ;" - " cld ;" - "7: nop " - : "=S" (from), "=D" (to), "=c" (count), "=r" (temp) - : "0" (from), "1" (to), "2" (count), "3" (temp) - : "memory", "flags"); -#endif // AMD64 -} - -static void pd_disjoint_words(const HeapWord* from, HeapWord* to, size_t count) { -#ifdef AMD64 - switch (count) { - case 8: to[7] = from[7]; - case 7: to[6] = from[6]; - case 6: to[5] = from[5]; - case 5: to[4] = from[4]; - case 4: to[3] = from[3]; - case 3: to[2] = from[2]; - case 2: to[1] = from[1]; - case 1: to[0] = from[0]; - case 0: break; - default: - (void)memcpy(to, from, count * HeapWordSize); - break; - } -#else - // Includes a zero-count check. - intx temp = 0; - __asm__ volatile(" testl %6,%6 ;" - " jz 3f ;" - " cmpl $32,%6 ;" - " ja 2f ;" - " subl %4,%1 ;" - "1: movl (%4),%3 ;" - " movl %7,(%5,%4,1);" - " addl $4,%0 ;" - " subl $1,%2 ;" - " jnz 1b ;" - " jmp 3f ;" - "2: rep; smovl ;" - "3: nop " - : "=S" (from), "=D" (to), "=c" (count), "=r" (temp) - : "0" (from), "1" (to), "2" (count), "3" (temp) - : "memory", "cc"); -#endif // AMD64 -} - -static void pd_disjoint_words_atomic(const HeapWord* from, HeapWord* to, size_t count) { -#ifdef AMD64 - switch (count) { - case 8: to[7] = from[7]; - case 7: to[6] = from[6]; - case 6: to[5] = from[5]; - case 5: to[4] = from[4]; - case 4: to[3] = from[3]; - case 3: to[2] = from[2]; - case 2: to[1] = from[1]; - case 1: to[0] = from[0]; - case 0: break; - default: - while (count-- > 0) { - *to++ = *from++; - } - break; - } -#else - // pd_disjoint_words is word-atomic in this implementation. - pd_disjoint_words(from, to, count); -#endif // AMD64 -} - -static void pd_aligned_conjoint_words(const HeapWord* from, HeapWord* to, size_t count) { - pd_conjoint_words(from, to, count); -} - -static void pd_aligned_disjoint_words(const HeapWord* from, HeapWord* to, size_t count) { - pd_disjoint_words(from, to, count); -} - -static void pd_conjoint_bytes(const void* from, void* to, size_t count) { -#ifdef AMD64 - (void)memmove(to, from, count); -#else - // Includes a zero-count check. - intx temp = 0; - __asm__ volatile(" testl %6,%6 ;" - " jz 13f ;" - " cmpl %4,%5 ;" - " leal -1(%4,%6),%3 ;" - " jbe 1f ;" - " cmpl %7,%5 ;" - " jbe 8f ;" - "1: cmpl $3,%6 ;" - " jbe 6f ;" - " movl %6,%3 ;" - " movl $4,%2 ;" - " subl %4,%2 ;" - " andl $3,%2 ;" - " jz 2f ;" - " subl %6,%3 ;" - " rep; smovb ;" - "2: movl %7,%2 ;" - " shrl $2,%2 ;" - " jz 5f ;" - " cmpl $32,%2 ;" - " ja 4f ;" - " subl %4,%1 ;" - "3: movl (%4),%%edx ;" - " movl %%edx,(%5,%4,1);" - " addl $4,%0 ;" - " subl $1,%2 ;" - " jnz 3b ;" - " addl %4,%1 ;" - " jmp 5f ;" - "4: rep; smovl ;" - "5: movl %7,%2 ;" - " andl $3,%2 ;" - " jz 13f ;" - "6: xorl %7,%3 ;" - "7: movb (%4,%7,1),%%dl ;" - " movb %%dl,(%5,%7,1) ;" - " addl $1,%3 ;" - " subl $1,%2 ;" - " jnz 7b ;" - " jmp 13f ;" - "8: std ;" - " cmpl $12,%2 ;" - " ja 9f ;" - " movl %7,%0 ;" - " leal -1(%6,%5),%1 ;" - " jmp 11f ;" - "9: xchgl %3,%2 ;" - " movl %6,%0 ;" - " addl $1,%2 ;" - " leal -1(%7,%5),%1 ;" - " andl $3,%2 ;" - " jz 10f ;" - " subl %6,%3 ;" - " rep; smovb ;" - "10: movl %7,%2 ;" - " subl $3,%0 ;" - " shrl $2,%2 ;" - " subl $3,%1 ;" - " rep; smovl ;" - " andl $3,%3 ;" - " jz 12f ;" - " movl %7,%2 ;" - " addl $3,%0 ;" - " addl $3,%1 ;" - "11: rep; smovb ;" - "12: cld ;" - "13: nop ;" - : "=S" (from), "=D" (to), "=c" (count), "=r" (temp) - : "0" (from), "1" (to), "2" (count), "3" (temp) - : "memory", "flags", "%edx"); -#endif // AMD64 -} - -static void pd_conjoint_bytes_atomic(const void* from, void* to, size_t count) { - pd_conjoint_bytes(from, to, count); -} - -static void pd_conjoint_jshorts_atomic(const jshort* from, jshort* to, size_t count) { - _Copy_conjoint_jshorts_atomic(from, to, count); -} - -static void pd_conjoint_jints_atomic(const jint* from, jint* to, size_t count) { -#ifdef AMD64 - _Copy_conjoint_jints_atomic(from, to, count); -#else - assert(HeapWordSize == BytesPerInt, "heapwords and jints must be the same size"); - // pd_conjoint_words is word-atomic in this implementation. - pd_conjoint_words((const HeapWord*)from, (HeapWord*)to, count); -#endif // AMD64 -} - -static void pd_conjoint_jlongs_atomic(const jlong* from, jlong* to, size_t count) { -#ifdef AMD64 - _Copy_conjoint_jlongs_atomic(from, to, count); -#else - // Guarantee use of fild/fistp or xmm regs via some asm code, because compilers won't. - if (from > to) { - while (count-- > 0) { - __asm__ volatile("fildll (%0); fistpll (%1)" - : - : "r" (from), "r" (to) - : "memory" ); - ++from; - ++to; - } - } else { - while (count-- > 0) { - __asm__ volatile("fildll (%0,%2,8); fistpll (%1,%2,8)" - : - : "r" (from), "r" (to), "r" (count) - : "memory" ); - } - } -#endif // AMD64 -} - -static void pd_conjoint_oops_atomic(const oop* from, oop* to, size_t count) { -#ifdef AMD64 - assert(BytesPerLong == BytesPerOop, "jlongs and oops must be the same size"); - _Copy_conjoint_jlongs_atomic((const jlong*)from, (jlong*)to, count); -#else - assert(HeapWordSize == BytesPerOop, "heapwords and oops must be the same size"); - // pd_conjoint_words is word-atomic in this implementation. - pd_conjoint_words((const HeapWord*)from, (HeapWord*)to, count); -#endif // AMD64 -} - -static void pd_arrayof_conjoint_bytes(const HeapWord* from, HeapWord* to, size_t count) { - _Copy_arrayof_conjoint_bytes(from, to, count); -} - -static void pd_arrayof_conjoint_jshorts(const HeapWord* from, HeapWord* to, size_t count) { - _Copy_arrayof_conjoint_jshorts(from, to, count); -} - -static void pd_arrayof_conjoint_jints(const HeapWord* from, HeapWord* to, size_t count) { -#ifdef AMD64 - _Copy_arrayof_conjoint_jints(from, to, count); -#else - pd_conjoint_jints_atomic((const jint*)from, (jint*)to, count); -#endif // AMD64 -} - -static void pd_arrayof_conjoint_jlongs(const HeapWord* from, HeapWord* to, size_t count) { -#ifdef AMD64 - _Copy_arrayof_conjoint_jlongs(from, to, count); -#else - pd_conjoint_jlongs_atomic((const jlong*)from, (jlong*)to, count); -#endif // AMD64 -} - -static void pd_arrayof_conjoint_oops(const HeapWord* from, HeapWord* to, size_t count) { -#ifdef AMD64 - assert(BytesPerLong == BytesPerOop, "jlongs and oops must be the same size"); - _Copy_arrayof_conjoint_jlongs(from, to, count); -#else - pd_conjoint_oops_atomic((const oop*)from, (oop*)to, count); -#endif // AMD64 -} +// Empty for build system #endif // OS_CPU_LINUX_X86_COPY_LINUX_X86_HPP diff --git a/src/hotspot/os_cpu/linux_x86/linux_x86_32.S b/src/hotspot/os_cpu/linux_x86/linux_x86_32.S index 620179d99dda4848920b4855f04732c2df7fd8db..344358172defdc26ff1c27ff8d98cd3f45008796 100644 --- a/src/hotspot/os_cpu/linux_x86/linux_x86_32.S +++ b/src/hotspot/os_cpu/linux_x86/linux_x86_32.S @@ -1,5 +1,5 @@ # -# Copyright (c) 2004, 2017, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2004, 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 @@ -28,7 +28,6 @@ # point or use it in the same manner as does the server # compiler. - .globl _Copy_conjoint_bytes .globl _Copy_arrayof_conjoint_bytes .globl _Copy_conjoint_jshorts_atomic .globl _Copy_arrayof_conjoint_jshorts @@ -51,117 +50,10 @@ SpinPause: movl $1, %eax ret - # Support for void Copy::conjoint_bytes(void* from, - # void* to, - # size_t count) - .p2align 4,,15 - .type _Copy_conjoint_bytes,@function -_Copy_conjoint_bytes: - pushl %esi - movl 4+12(%esp),%ecx # count - pushl %edi - movl 8+ 4(%esp),%esi # from - movl 8+ 8(%esp),%edi # to - cmpl %esi,%edi - leal -1(%esi,%ecx),%eax # from + count - 1 - jbe cb_CopyRight - cmpl %eax,%edi - jbe cb_CopyLeft - # copy from low to high -cb_CopyRight: - cmpl $3,%ecx - jbe 5f # <= 3 bytes - # align source address at dword address boundary - movl %ecx,%eax # original count - movl $4,%ecx - subl %esi,%ecx - andl $3,%ecx # prefix byte count - jz 1f # no prefix - subl %ecx,%eax # byte count less prefix - # copy prefix - subl %esi,%edi -0: movb (%esi),%dl - movb %dl,(%edi,%esi,1) - addl $1,%esi - subl $1,%ecx - jnz 0b - addl %esi,%edi -1: movl %eax,%ecx # byte count less prefix - shrl $2,%ecx # dword count - jz 4f # no dwords to move - cmpl $32,%ecx - jbe 2f # <= 32 dwords - # copy aligned dwords - rep; smovl - jmp 4f - # copy aligned dwords -2: subl %esi,%edi - .p2align 4,,15 -3: movl (%esi),%edx - movl %edx,(%edi,%esi,1) - addl $4,%esi - subl $1,%ecx - jnz 3b - addl %esi,%edi -4: movl %eax,%ecx # byte count less prefix -5: andl $3,%ecx # suffix byte count - jz 7f # no suffix - # copy suffix - xorl %eax,%eax -6: movb (%esi,%eax,1),%dl - movb %dl,(%edi,%eax,1) - addl $1,%eax - subl $1,%ecx - jnz 6b -7: popl %edi - popl %esi - ret - # copy from high to low -cb_CopyLeft: - std - leal -4(%edi,%ecx),%edi # to + count - 4 - movl %eax,%esi # from + count - 1 - movl %ecx,%eax - subl $3,%esi # from + count - 4 - cmpl $3,%ecx - jbe 5f # <= 3 bytes -1: shrl $2,%ecx # dword count - jz 4f # no dwords to move - cmpl $32,%ecx - ja 3f # > 32 dwords - # copy dwords, aligned or not - subl %esi,%edi - .p2align 4,,15 -2: movl (%esi),%edx - movl %edx,(%edi,%esi,1) - subl $4,%esi - subl $1,%ecx - jnz 2b - addl %esi,%edi - jmp 4f - # copy dwords, aligned or not -3: rep; smovl -4: movl %eax,%ecx # byte count -5: andl $3,%ecx # suffix byte count - jz 7f # no suffix - # copy suffix - subl %esi,%edi - addl $3,%esi -6: movb (%esi),%dl - movb %dl,(%edi,%esi,1) - subl $1,%esi - subl $1,%ecx - jnz 6b -7: cld - popl %edi - popl %esi - ret - # Support for void Copy::arrayof_conjoint_bytes(void* from, # void* to, # size_t count) # - # Same as _Copy_conjoint_bytes, except no source alignment check. .p2align 4,,15 .type _Copy_arrayof_conjoint_bytes,@function _Copy_arrayof_conjoint_bytes: 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 cc71b0d278019bf95142c995b2ac504a9e41c473..c6b945fdd7903e69ed661f5ca1778a511bbc253f 100644 --- a/src/hotspot/os_cpu/linux_x86/os_linux_x86.cpp +++ b/src/hotspot/os_cpu/linux_x86/os_linux_x86.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -459,11 +459,26 @@ bool os::supports_sse() { } juint os::cpu_microcode_revision() { + // Note: this code runs on startup, and therefore should not be slow, + // see JDK-8283200. + juint result = 0; - char data[2048] = {0}; // lines should fit in 2K buf - size_t len = sizeof(data); - FILE *fp = fopen("/proc/cpuinfo", "r"); + + // Attempt 1 (faster): Read the microcode version off the sysfs. + FILE *fp = os::fopen("/sys/devices/system/cpu/cpu0/microcode/version", "r"); + if (fp) { + int read = fscanf(fp, "%x", &result); + fclose(fp); + if (read > 0) { + return result; + } + } + + // Attempt 2 (slower): Read the microcode version off the procfs. + fp = os::fopen("/proc/cpuinfo", "r"); if (fp) { + char data[2048] = {0}; // lines should fit in 2K buf + size_t len = sizeof(data); while (!feof(fp)) { if (fgets(data, len, fp)) { if (strstr(data, "microcode") != NULL) { @@ -475,6 +490,7 @@ juint os::cpu_microcode_revision() { } fclose(fp); } + return result; } diff --git a/src/hotspot/os_cpu/linux_zero/thread_linux_zero.cpp b/src/hotspot/os_cpu/linux_zero/thread_linux_zero.cpp index 816ca411430cc609615825747f055c2ac0b82935..e4313782613ddab3ed94a56b66553f5089051fa0 100644 --- a/src/hotspot/os_cpu/linux_zero/thread_linux_zero.cpp +++ b/src/hotspot/os_cpu/linux_zero/thread_linux_zero.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved. - * Copyright 2009, 2010 Red Hat, Inc. + * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 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 @@ -35,3 +35,40 @@ frame JavaThread::pd_last_frame() { void JavaThread::cache_global_variables() { // nothing to do } + +bool JavaThread::pd_get_top_frame_for_signal_handler(frame* fr_addr, + void* ucontext, + bool isInJava) { + if (has_last_Java_frame()) { + *fr_addr = pd_last_frame(); + return true; + } + + if (isInJava) { + // We know we are in Java, but there is no frame? + // Try to find the top-most Java frame on Zero stack then. + intptr_t* sp = zero_stack()->sp(); + ZeroFrame* zf = top_zero_frame(); + while (zf != NULL) { + if (zf->is_interpreter_frame()) { + interpreterState istate = zf->as_interpreter_frame()->interpreter_state(); + if (istate->self_link() == istate) { + // Valid interpreter state found, this is our frame. + *fr_addr = frame(zf, sp); + return true; + } + } + sp = ((intptr_t *) zf) + 1; + zf = zf->next(); + } + } + + // No dice. + return false; +} + +bool JavaThread::pd_get_top_frame_for_profiling(frame* fr_addr, + void* ucontext, + bool isInJava) { + return pd_get_top_frame_for_signal_handler(fr_addr, ucontext, isInJava); +} diff --git a/src/hotspot/os_cpu/linux_zero/thread_linux_zero.hpp b/src/hotspot/os_cpu/linux_zero/thread_linux_zero.hpp index b180611b2f9e2fcf7fdae9d721a2debe566af203..b915c40c04987a5c303a9ef5eeceeab8dd6542d6 100644 --- a/src/hotspot/os_cpu/linux_zero/thread_linux_zero.hpp +++ b/src/hotspot/os_cpu/linux_zero/thread_linux_zero.hpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved. - * Copyright 2007, 2008, 2009, 2010 Red Hat, Inc. + * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 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 @@ -96,16 +96,10 @@ public: bool pd_get_top_frame_for_signal_handler(frame* fr_addr, void* ucontext, - bool isInJava) { - ShouldNotCallThis(); - return false; // silence compile warning - } + bool isInJava); bool pd_get_top_frame_for_profiling(frame* fr_addr, void* ucontext, - bool isInJava) { - ShouldNotCallThis(); - return false; // silence compile warning - } + bool isInJava); #endif // OS_CPU_LINUX_ZERO_THREAD_LINUX_ZERO_HPP diff --git a/src/hotspot/os_cpu/windows_aarch64/copy_windows_aarch64.hpp b/src/hotspot/os_cpu/windows_aarch64/copy_windows_aarch64.hpp index 2d3c55cea39130770c733dfed20df332433af61f..ce2ad2d046f88ff6b65c4768eecd4e531a974114 100644 --- a/src/hotspot/os_cpu/windows_aarch64/copy_windows_aarch64.hpp +++ b/src/hotspot/os_cpu/windows_aarch64/copy_windows_aarch64.hpp @@ -1,5 +1,6 @@ /* * Copyright (c) 2020, Microsoft Corporation. All rights reserved. + * 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 @@ -49,21 +50,7 @@ static void pd_disjoint_words(const HeapWord* from, HeapWord* to, size_t count) } static void pd_disjoint_words_atomic(const HeapWord* from, HeapWord* to, size_t count) { - switch (count) { - case 8: to[7] = from[7]; - case 7: to[6] = from[6]; - case 6: to[5] = from[5]; - case 5: to[4] = from[4]; - case 4: to[3] = from[3]; - case 3: to[2] = from[2]; - case 2: to[1] = from[1]; - case 1: to[0] = from[0]; - case 0: break; - default: while (count-- > 0) { - *to++ = *from++; - } - break; - } + shared_disjoint_words_atomic(from, to, count); } static void pd_aligned_conjoint_words(const HeapWord* from, HeapWord* to, size_t count) { diff --git a/src/hotspot/os_cpu/windows_aarch64/pauth_windows_aarch64.inline.hpp b/src/hotspot/os_cpu/windows_aarch64/pauth_windows_aarch64.inline.hpp index 844291ee1e41231818704e1a9321632e26f98b50..6b5c9eecb72a49d8caafc4f5c186c47ff0caecc4 100644 --- a/src/hotspot/os_cpu/windows_aarch64/pauth_windows_aarch64.inline.hpp +++ b/src/hotspot/os_cpu/windows_aarch64/pauth_windows_aarch64.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Arm Limited. All rights reserved. + * Copyright (c) 2021, 2022, 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 @@ -25,10 +25,22 @@ #ifndef OS_CPU_WINDOWS_AARCH64_PAUTH_WINDOWS_AARCH64_INLINE_HPP #define OS_CPU_WINDOWS_AARCH64_PAUTH_WINDOWS_AARCH64_INLINE_HPP +// OS specific Support for ROP Protection in VM code. +// For more details on PAC see pauth_aarch64.hpp. + inline address pauth_strip_pointer(address ptr) { // No PAC support in windows as of yet. return ptr; } -#endif // OS_CPU_WINDOWS_AARCH64_PAUTH_WINDOWS_AARCH64_INLINE_HPP +inline address pauth_sign_return_address(address ret_addr, address sp) { + // No PAC support in windows as of yet. + return ret_addr; +} +inline address pauth_authenticate_return_address(address ret_addr, address sp) { + // No PAC support in windows as of yet. + return ret_addr; +} + +#endif // OS_CPU_WINDOWS_AARCH64_PAUTH_WINDOWS_AARCH64_INLINE_HPP diff --git a/src/hotspot/os_cpu/windows_aarch64/thread_windows_aarch64.cpp b/src/hotspot/os_cpu/windows_aarch64/thread_windows_aarch64.cpp index 6512df3e7b9188d76dce3f3260c12bd8828a7a69..c5267d85d377d20f6683d4eb0e271be9dc103249 100644 --- a/src/hotspot/os_cpu/windows_aarch64/thread_windows_aarch64.cpp +++ b/src/hotspot/os_cpu/windows_aarch64/thread_windows_aarch64.cpp @@ -1,5 +1,6 @@ /* * Copyright (c) 2020, Microsoft Corporation. All rights reserved. + * Copyright (c) 2022, 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 @@ -29,7 +30,9 @@ frame JavaThread::pd_last_frame() { assert(has_last_Java_frame(), "must have last_Java_sp() when suspended"); vmassert(_anchor.last_Java_pc() != NULL, "not walkable"); - return frame(_anchor.last_Java_sp(), _anchor.last_Java_fp(), _anchor.last_Java_pc()); + frame f = frame(_anchor.last_Java_sp(), _anchor.last_Java_fp(), _anchor.last_Java_pc()); + f.set_sp_is_trusted(); + return f; } // For Forte Analyzer AsyncGetCallTrace profiling support - thread is diff --git a/src/hotspot/os_cpu/windows_x86/copy_windows_x86.hpp b/src/hotspot/os_cpu/windows_x86/copy_windows_x86.hpp index 2f0560d89878d0148dd15af6d1493e03ef13f5dd..820ca46cb25d16bb9f34702168d120e87e750163 100644 --- a/src/hotspot/os_cpu/windows_x86/copy_windows_x86.hpp +++ b/src/hotspot/os_cpu/windows_x86/copy_windows_x86.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -25,64 +25,6 @@ #ifndef OS_CPU_WINDOWS_X86_COPY_WINDOWS_X86_HPP #define OS_CPU_WINDOWS_X86_COPY_WINDOWS_X86_HPP -static void pd_conjoint_words(const HeapWord* from, HeapWord* to, size_t count) { - (void)memmove(to, from, count * HeapWordSize); -} - -static void pd_disjoint_words(const HeapWord* from, HeapWord* to, size_t count) { -#ifdef AMD64 - switch (count) { - case 8: to[7] = from[7]; - case 7: to[6] = from[6]; - case 6: to[5] = from[5]; - case 5: to[4] = from[4]; - case 4: to[3] = from[3]; - case 3: to[2] = from[2]; - case 2: to[1] = from[1]; - case 1: to[0] = from[0]; - case 0: break; - default: - (void)memcpy(to, from, count * HeapWordSize); - break; - } -#else - (void)memcpy(to, from, count * HeapWordSize); -#endif // AMD64 -} - -static void pd_disjoint_words_atomic(const HeapWord* from, HeapWord* to, size_t count) { - switch (count) { - case 8: to[7] = from[7]; - case 7: to[6] = from[6]; - case 6: to[5] = from[5]; - case 5: to[4] = from[4]; - case 4: to[3] = from[3]; - case 3: to[2] = from[2]; - case 2: to[1] = from[1]; - case 1: to[0] = from[0]; - case 0: break; - default: while (count-- > 0) { - *to++ = *from++; - } - break; - } -} - -static void pd_aligned_conjoint_words(const HeapWord* from, HeapWord* to, size_t count) { - (void)memmove(to, from, count * HeapWordSize); -} - -static void pd_aligned_disjoint_words(const HeapWord* from, HeapWord* to, size_t count) { - pd_disjoint_words(from, to, count); -} - -static void pd_conjoint_bytes(const void* from, void* to, size_t count) { - (void)memmove(to, from, count); -} - -static void pd_conjoint_bytes_atomic(const void* from, void* to, size_t count) { - pd_conjoint_bytes(from, to, count); -} static void pd_conjoint_jshorts_atomic(const jshort* from, jshort* to, size_t count) { if (from > to) { diff --git a/src/hotspot/share/adlc/arena.cpp b/src/hotspot/share/adlc/adlArena.cpp similarity index 66% rename from src/hotspot/share/adlc/arena.cpp rename to src/hotspot/share/adlc/adlArena.cpp index 60a546e796168b8b7f65fef8b683ff602c0d8761..7c6e9419d4f506cc1c18a4f0b2e16de135a97bfc 100644 --- a/src/hotspot/share/adlc/arena.cpp +++ b/src/hotspot/share/adlc/adlArena.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -24,7 +24,7 @@ #include "adlc.hpp" -void* AllocateHeap(size_t size) { +void* AdlAllocateHeap(size_t size) { unsigned char* ptr = (unsigned char*) malloc(size); if (ptr == NULL && size != 0) { fprintf(stderr, "Error: Out of memory in ADLC\n"); // logging can cause crash! @@ -34,7 +34,7 @@ void* AllocateHeap(size_t size) { return ptr; } -void* ReAllocateHeap(void* old_ptr, size_t size) { +void* AdlReAllocateHeap(void* old_ptr, size_t size) { unsigned char* ptr = (unsigned char*) realloc(old_ptr, size); if (ptr == NULL && size != 0) { fprintf(stderr, "Error: Out of memory in ADLC\n"); // logging can cause crash! @@ -44,24 +44,24 @@ void* ReAllocateHeap(void* old_ptr, size_t size) { return ptr; } -void* Chunk::operator new(size_t requested_size, size_t length) throw() { - return CHeapObj::operator new(requested_size + length); +void* AdlChunk::operator new(size_t requested_size, size_t length) throw() { + return AdlCHeapObj::operator new(requested_size + length); } -void Chunk::operator delete(void* p, size_t length) { - CHeapObj::operator delete(p); +void AdlChunk::operator delete(void* p, size_t length) { + AdlCHeapObj::operator delete(p); } -Chunk::Chunk(size_t length) { +AdlChunk::AdlChunk(size_t length) { _next = NULL; // Chain on the linked list _len = length; // Save actual size } //------------------------------chop------------------------------------------- -void Chunk::chop() { - Chunk *k = this; +void AdlChunk::chop() { + AdlChunk *k = this; while( k ) { - Chunk *tmp = k->_next; + AdlChunk *tmp = k->_next; // clear out this chunk (to detect allocation bugs) memset(k, 0xBE, k->_len); free(k); // Free chunk (was malloc'd) @@ -69,52 +69,52 @@ void Chunk::chop() { } } -void Chunk::next_chop() { +void AdlChunk::next_chop() { _next->chop(); _next = NULL; } -//------------------------------Arena------------------------------------------ -Arena::Arena( size_t init_size ) { +//------------------------------AdlArena------------------------------------------ +AdlArena::AdlArena( size_t init_size ) { init_size = (init_size+3) & ~3; - _first = _chunk = new (init_size) Chunk(init_size); + _first = _chunk = new (init_size) AdlChunk(init_size); _hwm = _chunk->bottom(); // Save the cached hwm, max _max = _chunk->top(); set_size_in_bytes(init_size); } -Arena::Arena() { - _first = _chunk = new (Chunk::init_size) Chunk(Chunk::init_size); +AdlArena::AdlArena() { + _first = _chunk = new (AdlChunk::init_size) AdlChunk(AdlChunk::init_size); _hwm = _chunk->bottom(); // Save the cached hwm, max _max = _chunk->top(); - set_size_in_bytes(Chunk::init_size); + set_size_in_bytes(AdlChunk::init_size); } -Arena::Arena( Arena *a ) +AdlArena::AdlArena( AdlArena *a ) : _chunk(a->_chunk), _hwm(a->_hwm), _max(a->_max), _first(a->_first) { set_size_in_bytes(a->size_in_bytes()); } //------------------------------used------------------------------------------- -// Total of all Chunks in arena -size_t Arena::used() const { - size_t sum = _chunk->_len - (_max-_hwm); // Size leftover in this Chunk - Chunk *k = _first; - while( k != _chunk) { // Whilst have Chunks in a row - sum += k->_len; // Total size of this Chunk - k = k->_next; // Bump along to next Chunk +// Total of all AdlChunks in arena +size_t AdlArena::used() const { + size_t sum = _chunk->_len - (_max-_hwm); // Size leftover in this AdlChunk + AdlChunk *k = _first; + while( k != _chunk) { // Whilst have AdlChunks in a row + sum += k->_len; // Total size of this AdlChunk + k = k->_next; // Bump along to next AdlChunk } return sum; // Return total consumed space. } //------------------------------grow------------------------------------------- -// Grow a new Chunk -void* Arena::grow( size_t x ) { +// Grow a new AdlChunk +void* AdlArena::grow( size_t x ) { // Get minimal required size. Either real big, or even bigger for giant objs - size_t len = max(x, Chunk::size); + size_t len = max(x, AdlChunk::size); - Chunk *k = _chunk; // Get filled-up chunk address - _chunk = new (len) Chunk(len); + AdlChunk *k = _chunk; // Get filled-up chunk address + _chunk = new (len) AdlChunk(len); if( k ) k->_next = _chunk; // Append new chunk to end of linked list else _first = _chunk; @@ -127,8 +127,8 @@ void* Arena::grow( size_t x ) { } //------------------------------calloc----------------------------------------- -// Allocate zeroed storage in Arena -void *Arena::Acalloc( size_t items, size_t x ) { +// Allocate zeroed storage in AdlArena +void *AdlArena::Acalloc( size_t items, size_t x ) { size_t z = items*x; // Total size needed void *ptr = Amalloc(z); // Get space memset( ptr, 0, z ); // Zap space @@ -136,8 +136,8 @@ void *Arena::Acalloc( size_t items, size_t x ) { } //------------------------------realloc---------------------------------------- -// Reallocate storage in Arena. -void *Arena::Arealloc( void *old_ptr, size_t old_size, size_t new_size ) { +// Reallocate storage in AdlArena. +void *AdlArena::Arealloc( void *old_ptr, size_t old_size, size_t new_size ) { char *c_old = (char*)old_ptr; // Handy name // Stupid fast special case if( new_size <= old_size ) { // Shrink in-place @@ -161,32 +161,32 @@ void *Arena::Arealloc( void *old_ptr, size_t old_size, size_t new_size ) { } //------------------------------reset------------------------------------------ -// Reset this Arena to empty, and return this Arenas guts in a new Arena. -Arena *Arena::reset(void) { - Arena *a = new Arena(this); // New empty arena +// Reset this AdlArena to empty, and return this AdlArenas guts in a new AdlArena. +AdlArena *AdlArena::reset(void) { + AdlArena *a = new AdlArena(this); // New empty arena _first = _chunk = NULL; // Normal, new-arena initialization _hwm = _max = NULL; - return a; // Return Arena with guts + return a; // Return AdlArena with guts } //------------------------------contains--------------------------------------- -// Determine if pointer belongs to this Arena or not. -bool Arena::contains( const void *ptr ) const { +// Determine if pointer belongs to this AdlArena or not. +bool AdlArena::contains( const void *ptr ) const { if( (void*)_chunk->bottom() <= ptr && ptr < (void*)_hwm ) return true; // Check for in this chunk - for( Chunk *c = _first; c; c = c->_next ) + for( AdlChunk *c = _first; c; c = c->_next ) if( (void*)c->bottom() <= ptr && ptr < (void*)c->top()) - return true; // Check for every chunk in Arena - return false; // Not in any Chunk, so not in Arena + return true; // Check for every chunk in AdlArena + return false; // Not in any AdlChunk, so not in AdlArena } //----------------------------------------------------------------------------- // CHeapObj -void* CHeapObj::operator new(size_t size) throw() { - return (void *) AllocateHeap(size); +void* AdlCHeapObj::operator new(size_t size) throw() { + return (void *) AdlAllocateHeap(size); } -void CHeapObj::operator delete(void* p){ +void AdlCHeapObj::operator delete(void* p){ free(p); } diff --git a/src/hotspot/share/adlc/arena.hpp b/src/hotspot/share/adlc/adlArena.hpp similarity index 73% rename from src/hotspot/share/adlc/arena.hpp rename to src/hotspot/share/adlc/adlArena.hpp index 1fa99ed0e24bf7b9d840016e2adb16e22155c974..254f414f707c253643ca161429f21c527c3a2e40 100644 --- a/src/hotspot/share/adlc/arena.hpp +++ b/src/hotspot/share/adlc/adlArena.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -22,11 +22,11 @@ * */ -#ifndef SHARE_ADLC_ARENA_HPP -#define SHARE_ADLC_ARENA_HPP +#ifndef SHARE_ADLC_ADLARENA_HPP +#define SHARE_ADLC_ADLARENA_HPP -void* AllocateHeap(size_t size); -void* ReAllocateHeap(void* old_ptr, size_t size); +void* AdlAllocateHeap(size_t size); +void* AdlReAllocateHeap(void* old_ptr, size_t size); // All classes in adlc may be derived // from one of the following allocation classes: @@ -35,10 +35,10 @@ void* ReAllocateHeap(void* old_ptr, size_t size); // - CHeapObj // // For classes used as name spaces. -// - AllStatic +// - AdlAllStatic // -class CHeapObj { +class AdlCHeapObj { public: void* operator new(size_t size) throw(); void operator delete(void* p); @@ -47,16 +47,16 @@ class CHeapObj { // Base class for classes that constitute name spaces. -class AllStatic { +class AdlAllStatic { public: void* operator new(size_t size) throw(); void operator delete(void* p); }; -//------------------------------Chunk------------------------------------------ +//------------------------------AdlChunk------------------------------------------ // Linked list of raw memory chunks -class Chunk: public CHeapObj { +class AdlChunk: public AdlCHeapObj { private: // This ordinary operator delete is needed even though not used, so the // below two-argument operator delete will be treated as a placement @@ -65,41 +65,41 @@ class Chunk: public CHeapObj { public: void* operator new(size_t size, size_t length) throw(); void operator delete(void* p, size_t length); - Chunk(size_t length); + AdlChunk(size_t length); enum { init_size = 1*1024, // Size of first chunk - size = 32*1024 // Default size of an Arena chunk (following the first) + size = 32*1024 // Default size of an AdlArena chunk (following the first) }; - Chunk* _next; // Next Chunk in list - size_t _len; // Size of this Chunk + AdlChunk* _next; // Next AdlChunk in list + size_t _len; // Size of this AdlChunk void chop(); // Chop this chunk void next_chop(); // Chop next chunk // Boundaries of data area (possibly unused) - char* bottom() const { return ((char*) this) + sizeof(Chunk); } + char* bottom() const { return ((char*) this) + sizeof(AdlChunk); } char* top() const { return bottom() + _len; } }; -//------------------------------Arena------------------------------------------ +//------------------------------AdlArena------------------------------------------ // Fast allocation of memory -class Arena: public CHeapObj { +class AdlArena: public AdlCHeapObj { protected: friend class ResourceMark; friend class HandleMark; friend class NoHandleMark; - Chunk *_first; // First chunk - Chunk *_chunk; // current chunk + AdlChunk *_first; // First chunk + AdlChunk *_chunk; // current chunk char *_hwm, *_max; // High water mark and max in current chunk - void* grow(size_t x); // Get a new Chunk of at least size x + void* grow(size_t x); // Get a new AdlChunk of at least size x size_t _size_in_bytes; // Size of arena (used for memory usage tracing) public: - Arena(); - Arena(size_t init_size); - Arena(Arena *old); - ~Arena() { _first->chop(); } + AdlArena(); + AdlArena(size_t init_size); + AdlArena(AdlArena *old); + ~AdlArena() { _first->chop(); } char* hwm() const { return _hwm; } // Fast allocate in the arena. Common case is: pointer test + increment. @@ -137,10 +137,10 @@ public: void *Acalloc( size_t items, size_t x ); void *Arealloc( void *old_ptr, size_t old_size, size_t new_size ); - // Reset this Arena to empty, and return this Arenas guts in a new Arena. - Arena *reset(void); + // Reset this AdlArena to empty, and return this AdlArenas guts in a new AdlArena. + AdlArena *reset(void); - // Determine if pointer belongs to this Arena or not. + // Determine if pointer belongs to this AdlArena or not. bool contains( const void *ptr ) const; // Total of all chunks in use (not thread-safe) @@ -151,4 +151,4 @@ public: void set_size_in_bytes(size_t size) { _size_in_bytes = size; } }; -#endif // SHARE_ADLC_ARENA_HPP +#endif // SHARE_ADLC_ADLARENA_HPP diff --git a/src/hotspot/share/adlc/adlc.hpp b/src/hotspot/share/adlc/adlc.hpp index 297d5cb0133e0a7c76d2beaf3685d751f4a6d1c5..19567f05d4049889e0643b2e569378ec00ff77ee 100644 --- a/src/hotspot/share/adlc/adlc.hpp +++ b/src/hotspot/share/adlc/adlc.hpp @@ -93,7 +93,7 @@ typedef unsigned int uintptr_t; #define max(a, b) (((a)>(b)) ? (a) : (b)) // ADLC components -#include "arena.hpp" +#include "adlArena.hpp" #include "opto/adlcVMDeps.hpp" #include "filebuff.hpp" #include "dict2.hpp" diff --git a/src/hotspot/share/adlc/adlparse.cpp b/src/hotspot/share/adlc/adlparse.cpp index ecb722c56b2327e84ea3e265b99481f2c45c7bc0..283713bb1f838614622e304432394aa37c01c210 100644 --- a/src/hotspot/share/adlc/adlparse.cpp +++ b/src/hotspot/share/adlc/adlparse.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -211,7 +211,7 @@ void ADLParser::instr_parse(void) { return; } assert(match_rules_cnt < 100," too many match rule clones"); - char* buf = (char*) AllocateHeap(strlen(instr->_ident) + 4); + char* buf = (char*) AdlAllocateHeap(strlen(instr->_ident) + 4); sprintf(buf, "%s_%d", instr->_ident, match_rules_cnt++); rule->_result = buf; // Check for commutative operations with tree operands. @@ -2805,7 +2805,7 @@ void ADLParser::ins_encode_parse_block(InstructForm& inst) { // Create a new encoding name based on the name of the instruction // definition, which should be unique. const char* prefix = "__ins_encode_"; - char* ec_name = (char*) AllocateHeap(strlen(inst._ident) + strlen(prefix) + 1); + char* ec_name = (char*) AdlAllocateHeap(strlen(inst._ident) + strlen(prefix) + 1); sprintf(ec_name, "%s%s", prefix, inst._ident); assert(_AD._encode->encClass(ec_name) == NULL, "shouldn't already exist"); @@ -3276,7 +3276,7 @@ void ADLParser::constant_parse(InstructForm& inst) { // Create a new encoding name based on the name of the instruction // definition, which should be unique. const char* prefix = "__constant_"; - char* ec_name = (char*) AllocateHeap(strlen(inst._ident) + strlen(prefix) + 1); + char* ec_name = (char*) AdlAllocateHeap(strlen(inst._ident) + strlen(prefix) + 1); sprintf(ec_name, "%s%s", prefix, inst._ident); assert(_AD._encode->encClass(ec_name) == NULL, "shouldn't already exist"); @@ -4409,7 +4409,7 @@ char* ADLParser::find_cpp_block(const char* description) { if (_AD._adlocation_debug) { char* location = get_line_string(line); char* end_loc = end_line_marker(); - char* result = (char *)AllocateHeap(strlen(location) + strlen(cppBlock) + strlen(end_loc) + 1); + char* result = (char *)AdlAllocateHeap(strlen(location) + strlen(cppBlock) + strlen(end_loc) + 1); strcpy(result, location); strcat(result, cppBlock); strcat(result, end_loc); @@ -4498,7 +4498,7 @@ char *ADLParser::get_paren_expr(const char *description, bool include_location) // Prepend location descriptor, for debugging. char* location = get_line_string(line); char* end_loc = end_line_marker(); - char* result = (char *)AllocateHeap(strlen(location) + strlen(token2) + strlen(end_loc) + 1); + char* result = (char *)AdlAllocateHeap(strlen(location) + strlen(token2) + strlen(end_loc) + 1); strcpy(result, location); strcat(result, token2); strcat(result, end_loc); @@ -4596,7 +4596,7 @@ char *ADLParser::get_ident_or_literal_constant(const char* description) { // Grab a constant expression. param = get_paren_expr(description); if (param[0] != '(') { - char* buf = (char*) AllocateHeap(strlen(param) + 3); + char* buf = (char*) AdlAllocateHeap(strlen(param) + 3); sprintf(buf, "(%s)", param); param = buf; } @@ -5204,7 +5204,7 @@ void ADLParser::next_line() { char* ADLParser::get_line_string(int linenum) { const char* file = _AD._ADL_file._name; int line = linenum ? linenum : this->linenum(); - char* location = (char *)AllocateHeap(strlen(file) + 100); + char* location = (char *)AdlAllocateHeap(strlen(file) + 100); sprintf(location, "\n#line %d \"%s\"\n", line, file); return location; } diff --git a/src/hotspot/share/adlc/dfa.cpp b/src/hotspot/share/adlc/dfa.cpp index b1556ab5f5eea4474b09d7de472bad6cf46afd16..5abc43652973a500c8dfc1af9dc550b2f914cfe8 100644 --- a/src/hotspot/share/adlc/dfa.cpp +++ b/src/hotspot/share/adlc/dfa.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -72,7 +72,7 @@ private: public: // cmpstr does string comparisions. hashstr computes a key. - ProductionState(Arena *arena) : _production(cmpstr, hashstr, arena) { initialize(); }; + ProductionState(AdlArena *arena) : _production(cmpstr, hashstr, arena) { initialize(); }; ~ProductionState() { }; void initialize(); // reset local and dictionary state @@ -817,7 +817,7 @@ bool Expr::check_buffers() { //------------------------------ExprDict--------------------------------------- // Constructor -ExprDict::ExprDict( CmpKey cmp, Hash hash, Arena *arena ) +ExprDict::ExprDict( CmpKey cmp, Hash hash, AdlArena *arena ) : _expr(cmp, hash, arena), _defines() { } ExprDict::~ExprDict() { diff --git a/src/hotspot/share/adlc/dict2.cpp b/src/hotspot/share/adlc/dict2.cpp index 4f3e33dd626b467324d69a6f8605c09531612ab3..9fd22572855e362a15d1cf0c0f05fbfb1c9d06e0 100644 --- a/src/hotspot/share/adlc/dict2.cpp +++ b/src/hotspot/share/adlc/dict2.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -56,7 +56,7 @@ Dict::Dict(CmpKey initcmp, Hash inithash) : _hash(inithash), _cmp(initcmp), _are init(); } -Dict::Dict(CmpKey initcmp, Hash inithash, Arena *arena) : _hash(inithash), _cmp(initcmp), _arena(arena) { +Dict::Dict(CmpKey initcmp, Hash inithash, AdlArena *arena) : _hash(inithash), _cmp(initcmp), _arena(arena) { init(); } diff --git a/src/hotspot/share/adlc/dict2.hpp b/src/hotspot/share/adlc/dict2.hpp index a9790088dfb2ea725ca77b69e31217509e22887f..c6b7da3368a637cc3ffb5c9f9a69f721a117f199 100644 --- a/src/hotspot/share/adlc/dict2.hpp +++ b/src/hotspot/share/adlc/dict2.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -43,7 +43,7 @@ typedef void (*FuncDict)(const void *key, const void *val, Dict *d); class Dict { // Dictionary structure private: - class Arena *_arena; // Where to draw storage from + class AdlArena *_arena; // Where to draw storage from class bucket *_bin; // Hash table is array of buckets int _size; // Size (# of slots) in hash table int _cnt; // Number of key-value pairs in hash table @@ -56,7 +56,7 @@ class Dict { // Dictionary structure // cmp is a key comparision routine. hash is a routine to hash a key. Dict( CmpKey cmp, Hash hash ); - Dict( CmpKey cmp, Hash hash, Arena *arena ); + Dict( CmpKey cmp, Hash hash, AdlArena *arena ); void init(); ~Dict(); diff --git a/src/hotspot/share/adlc/forms.cpp b/src/hotspot/share/adlc/forms.cpp index 3a246285b3a6975d28de7cd5804cf695bda54761..9580d81484dee647fc1e04dc5a552d5c8925ce2c 100644 --- a/src/hotspot/share/adlc/forms.cpp +++ b/src/hotspot/share/adlc/forms.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -27,9 +27,9 @@ //------------------------------Static Initializers---------------------------- // allocate arena used by forms -Arena *Form::arena = Form::generate_arena(); // = Form::generate_arena(); -Arena *Form::generate_arena() { - return (new Arena); +AdlArena *Form::arena = Form::generate_arena(); // = Form::generate_arena(); +AdlArena *Form::generate_arena() { + return (new AdlArena); } //------------------------------NameList--------------------------------------- @@ -40,7 +40,7 @@ const char *NameList::_signal3 = "$$SIGNAL3$$"; // Constructor and Destructor NameList::NameList() : _cur(0), _max(4), _iter(0), _justReset(true) { - _names = (const char**) AllocateHeap(_max*sizeof(char*)); + _names = (const char**) AdlAllocateHeap(_max*sizeof(char*)); } NameList::~NameList() { // The following free is a double-free, and crashes the program: @@ -49,7 +49,7 @@ NameList::~NameList() { void NameList::addName(const char *name) { if (_cur == _max) { - _names = (const char**) ReAllocateHeap(_names, (_max *=2)*sizeof(char*)); + _names = (const char**) AdlReAllocateHeap(_names, (_max *=2)*sizeof(char*)); } _names[_cur++] = name; } @@ -312,7 +312,7 @@ FormList::~FormList() { //------------------------------FormDict--------------------------------------- // Constructor -FormDict::FormDict( CmpKey cmp, Hash hash, Arena *arena ) +FormDict::FormDict( CmpKey cmp, Hash hash, AdlArena *arena ) : _form(cmp, hash, arena) { } FormDict::~FormDict() { diff --git a/src/hotspot/share/adlc/forms.hpp b/src/hotspot/share/adlc/forms.hpp index b4e115229c31de2153bf7991dc11c459ea0bfdba..6586ea88311d96ddec8b7bbbb6aacc82641d334a 100644 --- a/src/hotspot/share/adlc/forms.hpp +++ b/src/hotspot/share/adlc/forms.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -97,7 +97,7 @@ private: public: // cmp is a key comparision routine. hash is a routine to hash a key. // FormDict( CmpKey cmp, Hash hash ); - FormDict( CmpKey cmp, Hash hash, Arena *arena ); + FormDict( CmpKey cmp, Hash hash, AdlArena *arena ); FormDict( const FormDict & fd ); // Deep-copy guts ~FormDict(); @@ -119,9 +119,9 @@ public: //------------------------------Form------------------------------------------- class Form { public: - static Arena *arena; // arena used by forms + static AdlArena *arena; // arena used by forms private: - static Arena *generate_arena(); // allocate arena used by forms + static AdlArena *generate_arena(); // allocate arena used by forms protected: int _ftype; // Indicator for derived class type @@ -573,7 +573,7 @@ private: public: // cmp is a key comparision routine. hash is a routine to hash a key. - ExprDict( CmpKey cmp, Hash hash, Arena *arena ); + ExprDict( CmpKey cmp, Hash hash, AdlArena *arena ); ~ExprDict(); // Return # of key-value pairs in dict diff --git a/src/hotspot/share/adlc/formsopt.cpp b/src/hotspot/share/adlc/formsopt.cpp index 351904bbb291a04b2f770b70caee1f062e05077d..6f1a5997511e2234fe213699627943515d5a9cd0 100644 --- a/src/hotspot/share/adlc/formsopt.cpp +++ b/src/hotspot/share/adlc/formsopt.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -206,7 +206,7 @@ RegDef::RegDef(char *regname, char *callconv, char *c_conv, char * idealtype, ch _concrete(concrete), _register_num(0) { - // Chunk and register mask are determined by the register number + // AdlChunk and register mask are determined by the register number // _register_num is set when registers are added to an allocation class } RegDef::~RegDef() { // Destructor diff --git a/src/hotspot/share/adlc/formssel.cpp b/src/hotspot/share/adlc/formssel.cpp index 651511f375185feff85a4d5b0aee0bb25e2b12ef..0ae7b07507436bf982dd2b3fc65ec151d1e5824c 100644 --- a/src/hotspot/share/adlc/formssel.cpp +++ b/src/hotspot/share/adlc/formssel.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -612,7 +612,7 @@ bool InstructForm::needs_anti_dependence_check(FormDict &globals) const { strcmp(_matrule->_rChild->_opType,"StrEquals" )==0 || strcmp(_matrule->_rChild->_opType,"StrIndexOf" )==0 || strcmp(_matrule->_rChild->_opType,"StrIndexOfChar" )==0 || - strcmp(_matrule->_rChild->_opType,"HasNegatives" )==0 || + strcmp(_matrule->_rChild->_opType,"CountPositives" )==0 || strcmp(_matrule->_rChild->_opType,"AryEq" )==0 )) return true; @@ -902,7 +902,7 @@ uint InstructForm::oper_input_base(FormDict &globals) { strcmp(_matrule->_rChild->_opType,"StrCompressedCopy" )==0 || strcmp(_matrule->_rChild->_opType,"StrIndexOf")==0 || strcmp(_matrule->_rChild->_opType,"StrIndexOfChar")==0 || - strcmp(_matrule->_rChild->_opType,"HasNegatives")==0 || + strcmp(_matrule->_rChild->_opType,"CountPositives")==0 || strcmp(_matrule->_rChild->_opType,"EncodeISOArray")==0)) { // String.(compareTo/equals/indexOf) and Arrays.equals // and sun.nio.cs.iso8859_1$Encoder.EncodeISOArray @@ -1366,7 +1366,7 @@ void InstructForm::set_unique_opnds() { // component back to an index and any DEF always goes at 0 so the // length of the array has to be the number of components + 1. _uniq_idx_length = _components.count() + 1; - uniq_idx = (uint*) AllocateHeap(sizeof(uint) * _uniq_idx_length); + uniq_idx = (uint*) AdlAllocateHeap(sizeof(uint) * _uniq_idx_length); for (i = 0; i < _uniq_idx_length; i++) { uniq_idx[i] = i; } @@ -3476,7 +3476,7 @@ void MatchNode::build_internalop( ) { rstr = (_rChild) ? ((_rChild->_internalop) ? _rChild->_internalop : _rChild->_opType) : ""; len += (int)strlen(lstr) + (int)strlen(rstr); - subtree = (char *)AllocateHeap(len); + subtree = (char *)AdlAllocateHeap(len); sprintf(subtree,"_%s_%s_%s", _opType, lstr, rstr); // Hash the subtree string in _internalOps; if a name exists, use it iop = (char *)_AD._internalOps[subtree]; @@ -3926,7 +3926,7 @@ void MatchRule::matchrule_swap_commutative_op(const char* instr_ident, int count MatchRule* clone = new MatchRule(_AD, this); // Swap operands of commutative operation ((MatchNode*)clone)->swap_commutative_op(true, count); - char* buf = (char*) AllocateHeap(strlen(instr_ident) + 4); + char* buf = (char*) AdlAllocateHeap(strlen(instr_ident) + 4); sprintf(buf, "%s_%d", instr_ident, match_rules_cnt++); clone->_result = buf; @@ -4234,8 +4234,9 @@ bool MatchRule::is_vector() const { "VectorRearrange","VectorLoadShuffle", "VectorLoadConst", "VectorCastB2X", "VectorCastS2X", "VectorCastI2X", "VectorCastL2X", "VectorCastF2X", "VectorCastD2X", - "VectorMaskWrapper", "VectorMaskCmp", "VectorReinterpret","LoadVectorMasked","StoreVectorMasked", - "FmaVD", "FmaVF","PopCountVI", + "VectorUCastB2X", "VectorUCastS2X", "VectorUCastI2X", + "VectorMaskWrapper","VectorMaskCmp","VectorReinterpret","LoadVectorMasked","StoreVectorMasked", + "FmaVD","FmaVF","PopCountVI", "PopCountVL", "VectorLongToMask", // Next are vector mask ops. "MaskAll", "AndVMask", "OrVMask", "XorVMask", "VectorMaskCast", // Next are not supported currently. diff --git a/src/hotspot/share/asm/assembler.hpp b/src/hotspot/share/asm/assembler.hpp index 10fa79eb30a121756564c94ad634d97de79023e1..dc38a53b031080ed0771232a9faa3e93ed65b01c 100644 --- a/src/hotspot/share/asm/assembler.hpp +++ b/src/hotspot/share/asm/assembler.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -429,6 +429,31 @@ class AbstractAssembler : public ResourceObj { } return ptr; } + address array_constant(BasicType bt, GrowableArray* c) { + CodeSection* c1 = _code_section; + int len = c->length(); + int size = type2aelembytes(bt) * len; + address ptr = start_a_const(size, MIN2(round_up_power_of_2(size), 8)); + if (ptr != NULL) { + for (int i = 0; i < len; i++) { + jvalue e = c->at(i); + switch(bt) { + case T_BOOLEAN: emit_int8(e.z); break; + case T_BYTE: emit_int8(e.b); break; + case T_CHAR: emit_int16(e.c); break; + case T_SHORT: emit_int16(e.s); break; + case T_INT: emit_int32(e.i); break; + case T_LONG: emit_int64(e.j); break; + case T_FLOAT: emit_float(e.f); break; + case T_DOUBLE: emit_double(e.d); break; + default: + ShouldNotReachHere(); + } + } + end_a_const(c1); + } + return ptr; + } // Bang stack to trigger StackOverflowError at a safe location // implementation delegates to machine-specific bang_stack_with_offset diff --git a/src/hotspot/share/asm/register.hpp b/src/hotspot/share/asm/register.hpp index 861c43b2c84128e12b7fa465aadaa6fa73358739..b8538e4df6810330e02f798b8baa4404f4d80c87 100644 --- a/src/hotspot/share/asm/register.hpp +++ b/src/hotspot/share/asm/register.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -28,6 +28,7 @@ #include "utilities/debug.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/macros.hpp" +#include "utilities/population_count.hpp" // Use AbstractRegister as shortcut class AbstractRegisterImpl; @@ -36,7 +37,7 @@ typedef AbstractRegisterImpl* AbstractRegister; // The super class for platform specific registers. Instead of using value objects, // registers are implemented as pointers. Subclassing is used so all registers can -// use the debugging suport below. No virtual functions are used for efficiency. +// use the debugging support below. No virtual functions are used for efficiency. // They are canonicalized; i.e., registers are equal if their pointers are equal, // and vice versa. A concrete implementation may just map the register onto 'this'. @@ -45,16 +46,190 @@ class AbstractRegisterImpl { int value() const { return (int)(intx)this; } }; + +// Macros to help define all kinds of registers + +#ifndef USE_POINTERS_TO_REGISTER_IMPL_ARRAY + #define AS_REGISTER(type,name) ((type)name##_##type##EnumValue) -#define CONSTANT_REGISTER_DECLARATION(type, name, value) \ -const type name = ((type)value); \ +#define CONSTANT_REGISTER_DECLARATION(type, name, value) \ +const type name = ((type)value); \ enum { name##_##type##EnumValue = (value) } -#define REGISTER_DECLARATION(type, name, value) \ +#else // USE_POINTERS_TO_REGISTER_IMPL_ARRAY + +#define REGISTER_IMPL_DECLARATION(type, impl_type, reg_count) \ +inline constexpr type as_ ## type(int encoding) { \ + return impl_type::first() + encoding; \ +} \ +extern impl_type all_ ## type ## s[reg_count + 1] INTERNAL_VISIBILITY; \ +inline constexpr type impl_type::first() { return all_ ## type ## s + 1; } + +#define REGISTER_IMPL_DEFINITION(type, impl_type, reg_count) \ +impl_type all_ ## type ## s[reg_count + 1]; + +#define CONSTANT_REGISTER_DECLARATION(type, name, value) \ +constexpr type name = as_ ## type(value); + +#endif // USE_POINTERS_TO_REGISTER_IMPL_ARRAY + + +#define REGISTER_DECLARATION(type, name, value) \ const type name = ((type)value) -#define REGISTER_DEFINITION(type, name) + +// For definitions of RegisterImpl* instances. To be redefined in an +// OS-specific way. +#ifdef __GNUC__ +#define INTERNAL_VISIBILITY __attribute__ ((visibility ("internal"))) +#else +#define INTERNAL_VISIBILITY +#endif + +template class RegSetIterator; +template class ReverseRegSetIterator; + +// A set of registers +template +class AbstractRegSet { + uint32_t _bitset; + + AbstractRegSet(uint32_t bitset) : _bitset(bitset) { } + +public: + + AbstractRegSet() : _bitset(0) { } + + AbstractRegSet(RegImpl r1) : _bitset(1 << r1->encoding()) { } + + AbstractRegSet operator+(const AbstractRegSet aSet) const { + AbstractRegSet result(_bitset | aSet._bitset); + return result; + } + + AbstractRegSet operator-(const AbstractRegSet aSet) const { + AbstractRegSet result(_bitset & ~aSet._bitset); + return result; + } + + AbstractRegSet &operator+=(const AbstractRegSet aSet) { + *this = *this + aSet; + return *this; + } + + AbstractRegSet &operator-=(const AbstractRegSet aSet) { + *this = *this - aSet; + return *this; + } + + static AbstractRegSet of(RegImpl r1) { + return AbstractRegSet(r1); + } + + static AbstractRegSet of(RegImpl r1, RegImpl r2) { + return of(r1) + r2; + } + + static AbstractRegSet of(RegImpl r1, RegImpl r2, RegImpl r3) { + return of(r1, r2) + r3; + } + + static AbstractRegSet of(RegImpl r1, RegImpl r2, RegImpl r3, RegImpl r4) { + return of(r1, r2, r3) + r4; + } + + static AbstractRegSet range(RegImpl start, RegImpl end) { + assert(start <= end, "must be"); + uint32_t bits = ~0; + bits <<= start->encoding(); + bits <<= 31 - end->encoding(); + bits >>= 31 - end->encoding(); + + return AbstractRegSet(bits); + } + + uint size() const { return population_count(_bitset); } + + uint32_t bits() const { return _bitset; } + +private: + + RegImpl first(); + RegImpl last(); + +public: + + friend class RegSetIterator; + friend class ReverseRegSetIterator; + + RegSetIterator begin(); + ReverseRegSetIterator rbegin(); +}; + +template +class RegSetIterator { + AbstractRegSet _regs; + +public: + RegSetIterator(AbstractRegSet x): _regs(x) {} + RegSetIterator(const RegSetIterator& mit) : _regs(mit._regs) {} + + RegSetIterator& operator++() { + RegImpl r = _regs.first(); + if (r->is_valid()) + _regs -= r; + return *this; + } + + bool operator==(const RegSetIterator& rhs) const { + return _regs.bits() == rhs._regs.bits(); + } + bool operator!=(const RegSetIterator& rhs) const { + return ! (rhs == *this); + } + + RegImpl operator*() { + return _regs.first(); + } +}; + +template +inline RegSetIterator AbstractRegSet::begin() { + return RegSetIterator(*this); +} + +template +class ReverseRegSetIterator { + AbstractRegSet _regs; + +public: + ReverseRegSetIterator(AbstractRegSet x): _regs(x) {} + ReverseRegSetIterator(const ReverseRegSetIterator& mit) : _regs(mit._regs) {} + + ReverseRegSetIterator& operator++() { + RegImpl r = _regs.last(); + if (r->is_valid()) + _regs -= r; + return *this; + } + + bool operator==(const ReverseRegSetIterator& rhs) const { + return _regs.bits() == rhs._regs.bits(); + } + bool operator!=(const ReverseRegSetIterator& rhs) const { + return ! (rhs == *this); + } + + RegImpl operator*() { + return _regs.last(); + } +}; + +template +inline ReverseRegSetIterator AbstractRegSet::rbegin() { + return ReverseRegSetIterator(*this); +} #include CPU_HEADER(register) diff --git a/src/hotspot/share/c1/c1_CFGPrinter.cpp b/src/hotspot/share/c1/c1_CFGPrinter.cpp index 9cd617d542812194c1e46cee42f20dc153020557..73a1d2d649e8686330a3a4f7bab3b3d48c867f14 100644 --- a/src/hotspot/share/c1/c1_CFGPrinter.cpp +++ b/src/hotspot/share/c1/c1_CFGPrinter.cpp @@ -231,9 +231,7 @@ void CFGPrinterOutput::print_LIR(BlockBegin* block) { void CFGPrinterOutput::print_block(BlockBegin* block) { print_begin("block"); - print("name \"B%d\"", block->block_id()); - print("from_bci %d", block->bci()); print("to_bci %d", (block->end() == NULL ? -1 : block->end()->printable_bci())); @@ -246,9 +244,13 @@ void CFGPrinterOutput::print_block(BlockBegin* block) { output()->cr(); output()->indent(); - output()->print("successors "); - for (i = 0; i < block->number_of_sux(); i++) { - output()->print("\"B%d\" ", block->sux_at(i)->block_id()); + if (block->end() != NULL) { + output()->print("successors "); + for (i = 0; i < block->number_of_sux(); i++) { + output()->print("\"B%d\" ", block->sux_at(i)->block_id()); + } + } else { + output()->print("(block has no end, cannot print successors)"); } output()->cr(); diff --git a/src/hotspot/share/c1/c1_Compilation.cpp b/src/hotspot/share/c1/c1_Compilation.cpp index df4b6bbed54660b578b96d90b5e2c7e4c0780598..baabbbd147bb82b696435f03fd50bcb114c03833 100644 --- a/src/hotspot/share/c1/c1_Compilation.cpp +++ b/src/hotspot/share/c1/c1_Compilation.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -77,7 +77,6 @@ static int totalInstructionNodes = 0; class PhaseTraceTime: public TraceTime { private: - JavaThread* _thread; CompileLog* _log; TimerName _timer; @@ -560,6 +559,7 @@ Compilation::Compilation(AbstractCompiler* compiler, ciEnv* env, ciMethod* metho , _has_exception_handlers(false) , _has_fpu_code(true) // pessimistic assumption , _has_unsafe_access(false) +, _has_irreducible_loops(false) , _would_profile(false) , _has_method_handle_invokes(false) , _has_reserved_stack_access(method->has_reserved_stack_access()) @@ -703,7 +703,7 @@ void Compilation::print_timers() { #ifndef PRODUCT void Compilation::compile_only_this_method() { ResourceMark rm; - fileStream stream(fopen("c1_compile_only", "wt")); + fileStream stream(os::fopen("c1_compile_only", "wt")); stream.print_cr("# c1 compile only directives"); compile_only_this_scope(&stream, hir()->top_scope()); } @@ -717,7 +717,7 @@ void Compilation::compile_only_this_scope(outputStream* st, IRScope* scope) { } void Compilation::exclude_this_method() { - fileStream stream(fopen(".hotspot_compiler", "at")); + fileStream stream(os::fopen(".hotspot_compiler", "at")); stream.print("exclude "); method()->holder()->name()->print_symbol_on(&stream); stream.print(" "); diff --git a/src/hotspot/share/c1/c1_Compilation.hpp b/src/hotspot/share/c1/c1_Compilation.hpp index f3be9ed7cee295410cfbc521dd1a415f3e899757..02a2f367df37a5930c4efa3df1d1cf954843fc70 100644 --- a/src/hotspot/share/c1/c1_Compilation.hpp +++ b/src/hotspot/share/c1/c1_Compilation.hpp @@ -77,6 +77,7 @@ class Compilation: public StackObj { bool _has_exception_handlers; bool _has_fpu_code; bool _has_unsafe_access; + bool _has_irreducible_loops; bool _would_profile; bool _has_method_handle_invokes; // True if this method has MethodHandle invokes. bool _has_reserved_stack_access; @@ -135,6 +136,7 @@ class Compilation: public StackObj { bool has_exception_handlers() const { return _has_exception_handlers; } bool has_fpu_code() const { return _has_fpu_code; } bool has_unsafe_access() const { return _has_unsafe_access; } + bool has_irreducible_loops() const { return _has_irreducible_loops; } int max_vector_size() const { return 0; } ciMethod* method() const { return _method; } int osr_bci() const { return _osr_bci; } @@ -162,6 +164,7 @@ class Compilation: public StackObj { void set_has_exception_handlers(bool f) { _has_exception_handlers = f; } void set_has_fpu_code(bool f) { _has_fpu_code = f; } void set_has_unsafe_access(bool f) { _has_unsafe_access = f; } + void set_has_irreducible_loops(bool f) { _has_irreducible_loops = f; } void set_would_profile(bool f) { _would_profile = f; } void set_has_access_indexed(bool f) { _has_access_indexed = f; } // Add a set of exception handlers covering the given PC offset diff --git a/src/hotspot/share/c1/c1_FrameMap.hpp b/src/hotspot/share/c1/c1_FrameMap.hpp index 5cbb37422dcbbee4b7c5f95f31b21af259853ad9..480a1082f686e7c9ca66e15eb536dff07b646fab 100644 --- a/src/hotspot/share/c1/c1_FrameMap.hpp +++ b/src/hotspot/share/c1/c1_FrameMap.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -43,7 +43,7 @@ class CallingConvention; //-------------------------------------------------------- // This class is responsible of mapping items (locals, monitors, spill -// slots and registers to their frame location +// slots and registers) to their frame location // // The monitors are specified by a consecutive index, although each monitor entry // occupies two words. The monitor_index is 0.._num_monitors diff --git a/src/hotspot/share/c1/c1_GraphBuilder.cpp b/src/hotspot/share/c1/c1_GraphBuilder.cpp index 9afabb75060bd17cc3e7970c731f464fffc65e62..6bb39e38f6920bc8b3544ee407301ba634e8158c 100644 --- a/src/hotspot/share/c1/c1_GraphBuilder.cpp +++ b/src/hotspot/share/c1/c1_GraphBuilder.cpp @@ -34,6 +34,7 @@ #include "ci/ciMemberName.hpp" #include "ci/ciSymbols.hpp" #include "ci/ciUtilities.inline.hpp" +#include "classfile/javaClasses.hpp" #include "compiler/compilationPolicy.hpp" #include "compiler/compileBroker.hpp" #include "compiler/compilerEvent.hpp" @@ -53,11 +54,12 @@ class BlockListBuilder { BlockList _blocks; // internal list of all blocks BlockList* _bci2block; // mapping from bci to blocks for GraphBuilder + GrowableArray _bci2block_successors; // Mapping bcis to their blocks successors while we dont have a blockend // fields used by mark_loops ResourceBitMap _active; // for iteration of control flow graph ResourceBitMap _visited; // for iteration of control flow graph - intArray _loop_map; // caches the information if a block is contained in a loop + GrowableArray _loop_map; // caches the information if a block is contained in a loop int _next_loop_index; // next free loop number int _next_block_number; // for reverse postorder numbering of blocks @@ -82,13 +84,18 @@ class BlockListBuilder { void make_loop_header(BlockBegin* block); void mark_loops(); - int mark_loops(BlockBegin* b, bool in_subroutine); + BitMap& mark_loops(BlockBegin* b, bool in_subroutine); // debugging #ifndef PRODUCT void print(); #endif + int number_of_successors(BlockBegin* block); + BlockBegin* successor_at(BlockBegin* block, int i); + void add_successor(BlockBegin* block, BlockBegin* sux); + bool is_successor(BlockBegin* block, BlockBegin* sux); + public: // creation BlockListBuilder(Compilation* compilation, IRScope* scope, int osr_bci); @@ -105,6 +112,7 @@ BlockListBuilder::BlockListBuilder(Compilation* compilation, IRScope* scope, int , _scope(scope) , _blocks(16) , _bci2block(new BlockList(scope->method()->code_size(), NULL)) + , _bci2block_successors(scope->method()->code_size()) , _active() // size not known yet , _visited() // size not known yet , _loop_map() // size not known yet @@ -118,6 +126,8 @@ BlockListBuilder::BlockListBuilder(Compilation* compilation, IRScope* scope, int mark_loops(); NOT_PRODUCT(if (PrintInitialBlockList) print()); + // _bci2block still contains blocks with _end == null and > 0 sux in _bci2block_successors. + #ifndef PRODUCT if (PrintCFGToFile) { stringStream title; @@ -160,6 +170,7 @@ BlockBegin* BlockListBuilder::make_block_at(int cur_bci, BlockBegin* predecessor block = new BlockBegin(cur_bci); block->init_stores_to_locals(method()->max_locals()); _bci2block->at_put(cur_bci, block); + _bci2block_successors.at_put_grow(cur_bci, BlockList()); _blocks.append(block); assert(predecessor == NULL || predecessor->bci() < cur_bci, "targets for backward branches must already exist"); @@ -170,7 +181,7 @@ BlockBegin* BlockListBuilder::make_block_at(int cur_bci, BlockBegin* predecessor BAILOUT_("Exception handler can be reached by both normal and exceptional control flow", block); } - predecessor->add_successor(block); + add_successor(predecessor, block); block->increment_total_preds(); } @@ -201,8 +212,8 @@ void BlockListBuilder::handle_exceptions(BlockBegin* current, int cur_bci) { assert(entry->is_set(BlockBegin::exception_entry_flag), "flag must be set"); // add each exception handler only once - if (!current->is_successor(entry)) { - current->add_successor(entry); + if(!is_successor(current, entry)) { + add_successor(current, entry); entry->increment_total_preds(); } @@ -365,17 +376,36 @@ void BlockListBuilder::mark_loops() { _active.initialize(BlockBegin::number_of_blocks()); _visited.initialize(BlockBegin::number_of_blocks()); - _loop_map = intArray(BlockBegin::number_of_blocks(), BlockBegin::number_of_blocks(), 0); + _loop_map = GrowableArray(BlockBegin::number_of_blocks(), BlockBegin::number_of_blocks(), ResourceBitMap()); + for (int i = 0; i < BlockBegin::number_of_blocks(); i++) { + _loop_map.at(i).initialize(BlockBegin::number_of_blocks()); + } _next_loop_index = 0; _next_block_number = _blocks.length(); - // recursively iterate the control flow graph - mark_loops(_bci2block->at(0), false); + // The loop detection algorithm works as follows: + // - We maintain the _loop_map, where for each block we have a bitmap indicating which loops contain this block. + // - The CFG is recursively traversed (depth-first) and if we detect a loop, we assign the loop a unique number that is stored + // in the bitmap associated with the loop header block. Until we return back through that loop header the bitmap contains + // only a single bit corresponding to the loop number. + // - The bit is then propagated for all the blocks in the loop after we exit them (post-order). There could be multiple bits + // of course in case of nested loops. + // - When we exit the loop header we remove that single bit and assign the real loop state for it. + // - Now, the tricky part here is how we detect irriducible loops. In the algorithm above the loop state bits + // are propagated to the predecessors. If we encounter an irreducible loop (a loop with multiple heads) we would see + // a node with some loop bit set that would then propagate back and be never cleared because we would + // never go back through the original loop header. Therefore if there are any irreducible loops the bits in the states + // for these loops are going to propagate back to the root. + BitMap& loop_state = mark_loops(_bci2block->at(0), false); + if (!loop_state.is_empty()) { + compilation()->set_has_irreducible_loops(true); + } assert(_next_block_number >= 0, "invalid block numbers"); // Remove dangling Resource pointers before the ResourceMark goes out-of-scope. _active.resize(0); _visited.resize(0); + _loop_map.clear(); } void BlockListBuilder::make_loop_header(BlockBegin* block) { @@ -387,19 +417,17 @@ void BlockListBuilder::make_loop_header(BlockBegin* block) { if (!block->is_set(BlockBegin::parser_loop_header_flag)) { block->set(BlockBegin::parser_loop_header_flag); - assert(_loop_map.at(block->block_id()) == 0, "must not be set yet"); - assert(0 <= _next_loop_index && _next_loop_index < BitsPerInt, "_next_loop_index is used as a bit-index in integer"); - _loop_map.at_put(block->block_id(), 1 << _next_loop_index); - if (_next_loop_index < 31) _next_loop_index++; + assert(_loop_map.at(block->block_id()).is_empty(), "must not be set yet"); + assert(0 <= _next_loop_index && _next_loop_index < BlockBegin::number_of_blocks(), "_next_loop_index is too large"); + _loop_map.at(block->block_id()).set_bit(_next_loop_index++); } else { // block already marked as loop header - assert(is_power_of_2((unsigned int)_loop_map.at(block->block_id())), "exactly one bit must be set"); + assert(_loop_map.at(block->block_id()).count_one_bits() == 1, "exactly one bit must be set"); } } -int BlockListBuilder::mark_loops(BlockBegin* block, bool in_subroutine) { +BitMap& BlockListBuilder::mark_loops(BlockBegin* block, bool in_subroutine) { int block_id = block->block_id(); - if (_visited.at(block_id)) { if (_active.at(block_id)) { // reached block via backward branch @@ -417,10 +445,11 @@ int BlockListBuilder::mark_loops(BlockBegin* block, bool in_subroutine) { _visited.set_bit(block_id); _active.set_bit(block_id); - intptr_t loop_state = 0; - for (int i = block->number_of_sux() - 1; i >= 0; i--) { + ResourceMark rm; + ResourceBitMap loop_state(BlockBegin::number_of_blocks()); + for (int i = number_of_successors(block) - 1; i >= 0; i--) { // recursively process all successors - loop_state |= mark_loops(block->sux_at(i), in_subroutine); + loop_state.set_union(mark_loops(successor_at(block, i), in_subroutine)); } // clear active-bit after all successors are processed @@ -430,28 +459,46 @@ int BlockListBuilder::mark_loops(BlockBegin* block, bool in_subroutine) { block->set_depth_first_number(_next_block_number); _next_block_number--; - if (loop_state != 0 || in_subroutine ) { + if (!loop_state.is_empty() || in_subroutine ) { // block is contained at least in one loop, so phi functions are necessary // phi functions are also necessary for all locals stored in a subroutine scope()->requires_phi_function().set_union(block->stores_to_locals()); } if (block->is_set(BlockBegin::parser_loop_header_flag)) { - int header_loop_state = _loop_map.at(block_id); - assert(is_power_of_2((unsigned)header_loop_state), "exactly one bit must be set"); - - // If the highest bit is set (i.e. when integer value is negative), the method - // has 32 or more loops. This bit is never cleared because it is used for multiple loops - if (header_loop_state >= 0) { - clear_bits(loop_state, header_loop_state); - } + BitMap& header_loop_state = _loop_map.at(block_id); + assert(header_loop_state.count_one_bits() == 1, "exactly one bit must be set"); + // remove the bit with the loop number for the state (header is outside of the loop) + loop_state.set_difference(header_loop_state); } // cache and return loop information for this block - _loop_map.at_put(block_id, loop_state); - return loop_state; + _loop_map.at(block_id).set_from(loop_state); + return _loop_map.at(block_id); +} + +inline int BlockListBuilder::number_of_successors(BlockBegin* block) +{ + assert(_bci2block_successors.length() > block->bci(), "sux must exist"); + return _bci2block_successors.at(block->bci()).length(); +} + +inline BlockBegin* BlockListBuilder::successor_at(BlockBegin* block, int i) +{ + assert(_bci2block_successors.length() > block->bci(), "sux must exist"); + return _bci2block_successors.at(block->bci()).at(i); +} + +inline void BlockListBuilder::add_successor(BlockBegin* block, BlockBegin* sux) +{ + assert(_bci2block_successors.length() > block->bci(), "sux must exist"); + _bci2block_successors.at(block->bci()).append(sux); } +inline bool BlockListBuilder::is_successor(BlockBegin* block, BlockBegin* sux) { + assert(_bci2block_successors.length() > block->bci(), "sux must exist"); + return _bci2block_successors.at(block->bci()).contains(sux); +} #ifndef PRODUCT @@ -477,10 +524,10 @@ void BlockListBuilder::print() { tty->print(cur->is_set(BlockBegin::subroutine_entry_flag) ? " sr" : " "); tty->print(cur->is_set(BlockBegin::parser_loop_header_flag) ? " lh" : " "); - if (cur->number_of_sux() > 0) { + if (number_of_successors(cur) > 0) { tty->print(" sux: "); - for (int j = 0; j < cur->number_of_sux(); j++) { - BlockBegin* sux = cur->sux_at(j); + for (int j = 0; j < number_of_successors(cur); j++) { + BlockBegin* sux = successor_at(cur, j); tty->print("B%d ", sux->block_id()); } } @@ -884,53 +931,68 @@ void GraphBuilder::ScopeData::incr_num_returns() { void GraphBuilder::load_constant() { ciConstant con = stream()->get_constant(); - if (con.basic_type() == T_ILLEGAL) { - // FIXME: an unresolved Dynamic constant can get here, - // and that should not terminate the whole compilation. - BAILOUT("could not resolve a constant"); - } else { + if (con.is_valid()) { ValueType* t = illegalType; ValueStack* patch_state = NULL; switch (con.basic_type()) { - case T_BOOLEAN: t = new IntConstant (con.as_boolean()); break; - case T_BYTE : t = new IntConstant (con.as_byte ()); break; - case T_CHAR : t = new IntConstant (con.as_char ()); break; - case T_SHORT : t = new IntConstant (con.as_short ()); break; - case T_INT : t = new IntConstant (con.as_int ()); break; - case T_LONG : t = new LongConstant (con.as_long ()); break; - case T_FLOAT : t = new FloatConstant (con.as_float ()); break; - case T_DOUBLE : t = new DoubleConstant (con.as_double ()); break; - case T_ARRAY : t = new ArrayConstant (con.as_object ()->as_array ()); break; - case T_OBJECT : - { + case T_BOOLEAN: t = new IntConstant (con.as_boolean()); break; + case T_BYTE : t = new IntConstant (con.as_byte ()); break; + case T_CHAR : t = new IntConstant (con.as_char ()); break; + case T_SHORT : t = new IntConstant (con.as_short ()); break; + case T_INT : t = new IntConstant (con.as_int ()); break; + case T_LONG : t = new LongConstant (con.as_long ()); break; + case T_FLOAT : t = new FloatConstant (con.as_float ()); break; + case T_DOUBLE : t = new DoubleConstant(con.as_double ()); break; + case T_ARRAY : // fall-through + case T_OBJECT : { ciObject* obj = con.as_object(); - if (!obj->is_loaded() - || (PatchALot && obj->klass() != ciEnv::current()->String_klass())) { - // A Class, MethodType, MethodHandle, or String. - // Unloaded condy nodes show up as T_ILLEGAL, above. + if (!obj->is_loaded() || (PatchALot && (obj->is_null_object() || obj->klass() != ciEnv::current()->String_klass()))) { + // A Class, MethodType, MethodHandle, Dynamic, or String. patch_state = copy_state_before(); t = new ObjectConstant(obj); } else { // Might be a Class, MethodType, MethodHandle, or Dynamic constant // result, which might turn out to be an array. - if (obj->is_null_object()) + if (obj->is_null_object()) { t = objectNull; - else if (obj->is_array()) + } else if (obj->is_array()) { t = new ArrayConstant(obj->as_array()); - else + } else { t = new InstanceConstant(obj->as_instance()); + } } break; - } - default : ShouldNotReachHere(); + } + default: ShouldNotReachHere(); } Value x; if (patch_state != NULL) { - x = new Constant(t, patch_state); + bool kills_memory = stream()->is_dynamic_constant(); // arbitrary memory effects from running BSM during linkage + x = new Constant(t, patch_state, kills_memory); } else { x = new Constant(t); } + + // Unbox the value at runtime, if needed. + // ConstantDynamic entry can be of a primitive type, but it is cached in boxed form. + if (patch_state != NULL) { + int index = stream()->get_constant_pool_index(); + BasicType type = stream()->get_basic_type_for_constant_at(index); + if (is_java_primitive(type)) { + ciInstanceKlass* box_klass = ciEnv::current()->get_box_klass_for_primitive_type(type); + assert(box_klass->is_loaded(), "sanity"); + int offset = java_lang_boxing_object::value_offset(type); + ciField* value_field = box_klass->get_field_by_offset(offset, false /*is_static*/); + x = new LoadField(append(x), offset, value_field, false /*is_static*/, patch_state, false /*needs_patching*/); + t = as_ValueType(type); + } else { + assert(is_reference_type(type), "not a reference: %s", type2name(type)); + } + } + push(t, append(x)); + } else { + BAILOUT("could not resolve a constant"); } } @@ -1865,22 +1927,17 @@ void GraphBuilder::invoke(Bytecodes::Code code) { log->identify(target), Bytecodes::name(code)); - // invoke-special-super - if (bc_raw == Bytecodes::_invokespecial && !target->is_object_initializer()) { - ciInstanceKlass* sender_klass = calling_klass; - if (sender_klass->is_interface()) { - int index = state()->stack_size() - (target->arg_size_no_receiver() + 1); - Value receiver = state()->stack_at(index); - CheckCast* c = new CheckCast(sender_klass, receiver, copy_state_before()); - c->set_invokespecial_receiver_check(); - state()->stack_at_put(index, append_split(c)); - } - } - // Some methods are obviously bindable without any type checks so // convert them directly to an invokespecial or invokestatic. if (target->is_loaded() && !target->is_abstract() && target->can_be_statically_bound()) { switch (bc_raw) { + case Bytecodes::_invokeinterface: + // convert to invokespecial if the target is the private interface method. + if (target->is_private()) { + assert(holder->is_interface(), "How did we get a non-interface method here!"); + code = Bytecodes::_invokespecial; + } + break; case Bytecodes::_invokevirtual: code = Bytecodes::_invokespecial; break; @@ -1897,6 +1954,26 @@ void GraphBuilder::invoke(Bytecodes::Code code) { } } + if (code == Bytecodes::_invokespecial) { + // Additional receiver subtype checks for interface calls via invokespecial or invokeinterface. + ciKlass* receiver_constraint = nullptr; + + if (bc_raw == Bytecodes::_invokeinterface) { + receiver_constraint = holder; + } else if (bc_raw == Bytecodes::_invokespecial && !target->is_object_initializer() && calling_klass->is_interface()) { + receiver_constraint = calling_klass; + } + + if (receiver_constraint != nullptr) { + int index = state()->stack_size() - (target->arg_size_no_receiver() + 1); + Value receiver = state()->stack_at(index); + CheckCast* c = new CheckCast(receiver_constraint, receiver, copy_state_before()); + // go to uncommon_trap when checkcast fails + c->set_invokespecial_receiver_check(); + state()->stack_at_put(index, append_split(c)); + } + } + // Push appendix argument (MethodType, CallSite, etc.), if one. bool patch_for_appendix = false; int patching_appendix_arg = 0; @@ -1989,19 +2066,19 @@ void GraphBuilder::invoke(Bytecodes::Code code) { cha_monomorphic_target = target->find_monomorphic_target(calling_klass, declared_interface, singleton); if (cha_monomorphic_target != NULL) { if (cha_monomorphic_target->holder() != compilation()->env()->Object_klass()) { - // If CHA is able to bind this invoke then update the class - // to match that class, otherwise klass will refer to the - // interface. - klass = cha_monomorphic_target->holder(); + ciInstanceKlass* holder = cha_monomorphic_target->holder(); + ciInstanceKlass* constraint = (holder->is_subtype_of(singleton) ? holder : singleton); // avoid upcasts actual_recv = declared_interface; // insert a check it's really the expected class. - CheckCast* c = new CheckCast(klass, receiver, copy_state_for_exception()); + CheckCast* c = new CheckCast(constraint, receiver, copy_state_for_exception()); c->set_incompatible_class_change_check(); - c->set_direct_compare(klass->is_final()); + c->set_direct_compare(constraint->is_final()); // pass the result of the checkcast so that the compiler has // more accurate type info in the inlinee better_receiver = append_split(c); + + dependency_recorder()->assert_unique_implementor(declared_interface, singleton); } else { cha_monomorphic_target = NULL; // subtype check against Object is useless } @@ -2025,9 +2102,11 @@ void GraphBuilder::invoke(Bytecodes::Code code) { } // check if we could do inlining - if (!PatchALot && Inline && target->is_loaded() && callee_holder->is_linked() && !patch_for_appendix) { + if (!PatchALot && Inline && target->is_loaded() && !patch_for_appendix && + callee_holder->is_loaded()) { // the effect of symbolic reference resolution + // callee is known => check if we have static binding - if ((code == Bytecodes::_invokestatic && callee_holder->is_initialized()) || // invokestatic involves an initialization barrier on resolved klass + if ((code == Bytecodes::_invokestatic && klass->is_initialized()) || // invokestatic involves an initialization barrier on declaring class code == Bytecodes::_invokespecial || (code == Bytecodes::_invokevirtual && target->is_final_method()) || code == Bytecodes::_invokedynamic) { @@ -2431,7 +2510,7 @@ XHandlers* GraphBuilder::handle_exception(Instruction* instruction) { // The only test case we've seen so far which exhibits this // problem is caught by the infinite recursion test in // GraphBuilder::jsr() if the join doesn't work. - if (!entry->try_merge(cur_state)) { + if (!entry->try_merge(cur_state, compilation()->has_irreducible_loops())) { BAILOUT_("error while joining with exception handler, prob. due to complicated jsr/rets", exception_handlers); } @@ -2917,7 +2996,7 @@ BlockEnd* GraphBuilder::iterate_bytecodes_for_block(int bci) { BlockBegin* sux = end->sux_at(i); assert(sux->is_predecessor(block()), "predecessor missing"); // be careful, bailout if bytecodes are strange - if (!sux->try_merge(end->state())) BAILOUT_("block join failed", NULL); + if (!sux->try_merge(end->state(), compilation()->has_irreducible_loops())) BAILOUT_("block join failed", NULL); scope_data()->add_to_work_list(end->sux_at(i)); } @@ -3044,7 +3123,7 @@ BlockBegin* GraphBuilder::setup_start_block(int osr_bci, BlockBegin* std_entry, // each method. Previously, each method started with the // start-block created below, and this block was followed by the // header block that was always empty. This header block is only - // necesary if std_entry is also a backward branch target because + // necessary if std_entry is also a backward branch target because // then phi functions may be necessary in the header block. It's // also necessary when profiling so that there's a single block that // can increment the the counters. @@ -3071,7 +3150,7 @@ BlockBegin* GraphBuilder::setup_start_block(int osr_bci, BlockBegin* std_entry, if (base->std_entry()->state() == NULL) { // setup states for header blocks - base->std_entry()->merge(state); + base->std_entry()->merge(state, compilation()->has_irreducible_loops()); } assert(base->std_entry()->state() != NULL, ""); @@ -3154,7 +3233,7 @@ void GraphBuilder::setup_osr_entry_block() { Goto* g = new Goto(target, false); append(g); _osr_entry->set_end(g); - target->merge(_osr_entry->end()->state()); + target->merge(_osr_entry->end()->state(), compilation()->has_irreducible_loops()); scope_data()->set_stream(NULL); } @@ -3213,7 +3292,9 @@ GraphBuilder::GraphBuilder(Compilation* compilation, IRScope* scope) // setup state for std entry _initial_state = state_at_entry(); - start_block->merge(_initial_state); + start_block->merge(_initial_state, compilation->has_irreducible_loops()); + + // End nulls still exist here // complete graph _vmap = new ValueMap(); @@ -3318,6 +3399,27 @@ GraphBuilder::GraphBuilder(Compilation* compilation, IRScope* scope) } CHECK_BAILOUT(); +# ifdef ASSERT + //All blocks reachable from start_block have _end != NULL + { + BlockList processed; + BlockList to_go; + to_go.append(start_block); + while(to_go.length() > 0) { + BlockBegin* current = to_go.pop(); + assert(current != NULL, "Should not happen."); + assert(current->end() != NULL, "All blocks reachable from start_block should have end() != NULL."); + processed.append(current); + for(int i = 0; i < current->number_of_sux(); i++) { + BlockBegin* s = current->sux_at(i); + if (!processed.contains(s)) { + to_go.append(s); + } + } + } + } +#endif // ASSERT + _start = setup_start_block(osr_bci, start_block, _osr_entry, _initial_state); eliminate_redundant_phis(_start); @@ -3941,7 +4043,7 @@ bool GraphBuilder::try_inline_full(ciMethod* callee, bool holder_known, bool ign // the entry bci for the callee instead of the call site bci. append_with_bci(goto_callee, 0); _block->set_end(goto_callee); - callee_start_block->merge(callee_state); + callee_start_block->merge(callee_state, compilation()->has_irreducible_loops()); _last = _block = callee_start_block; diff --git a/src/hotspot/share/c1/c1_IR.cpp b/src/hotspot/share/c1/c1_IR.cpp index e4b9d86dcc300b54334a478b1e7578a1a1d29d88..78aef07b4cf0c013d869d4e8b51f6ff359ccc597 100644 --- a/src/hotspot/share/c1/c1_IR.cpp +++ b/src/hotspot/share/c1/c1_IR.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -191,7 +191,8 @@ CodeEmitInfo::CodeEmitInfo(ValueStack* stack, XHandlers* exception_handlers, boo , _oop_map(NULL) , _stack(stack) , _is_method_handle_invoke(false) - , _deoptimize_on_exception(deoptimize_on_exception) { + , _deoptimize_on_exception(deoptimize_on_exception) + , _force_reexecute(false) { assert(_stack != NULL, "must be non null"); } @@ -203,7 +204,8 @@ CodeEmitInfo::CodeEmitInfo(CodeEmitInfo* info, ValueStack* stack) , _oop_map(NULL) , _stack(stack == NULL ? info->_stack : stack) , _is_method_handle_invoke(info->_is_method_handle_invoke) - , _deoptimize_on_exception(info->_deoptimize_on_exception) { + , _deoptimize_on_exception(info->_deoptimize_on_exception) + , _force_reexecute(info->_force_reexecute) { // deep copy of exception handlers if (info->_exception_handlers != NULL) { @@ -215,7 +217,8 @@ CodeEmitInfo::CodeEmitInfo(CodeEmitInfo* info, ValueStack* stack) void CodeEmitInfo::record_debug_info(DebugInformationRecorder* recorder, int pc_offset) { // record the safepoint before recording the debug info for enclosing scopes recorder->add_safepoint(pc_offset, _oop_map->deep_copy()); - _scope_debug_info->record_debug_info(recorder, pc_offset, true/*topmost*/, _is_method_handle_invoke); + bool reexecute = _force_reexecute || _scope_debug_info->should_reexecute(); + _scope_debug_info->record_debug_info(recorder, pc_offset, reexecute, _is_method_handle_invoke); recorder->end_safepoint(pc_offset); } @@ -1260,13 +1263,38 @@ void IR::print(bool cfg_only, bool live_only) { tty->print_cr("invalid IR"); } } +#endif // PRODUCT +#ifdef ASSERT +class EndNotNullValidator : public BlockClosure { + public: + virtual void block_do(BlockBegin* block) { + assert(block->end() != NULL, "Expect block end to exist."); + } +}; + +class XentryFlagValidator : public BlockClosure { + public: + virtual void block_do(BlockBegin* block) { + for (int i = 0; i < block->end()->number_of_sux(); i++) { + assert(!block->end()->sux_at(i)->is_set(BlockBegin::exception_entry_flag), "must not be xhandler"); + } + for (int i = 0; i < block->number_of_exception_handlers(); i++) { + assert(block->exception_handler_at(i)->is_set(BlockBegin::exception_entry_flag), "must be xhandler"); + } + } +}; typedef GrowableArray BlockListList; -class PredecessorValidator : public BlockClosure { +// Validation goals: +// - code() length == blocks length +// - code() contents == blocks content +// - Each block's computed predecessors match sux lists (length) +// - Each block's computed predecessors match sux lists (set content) +class PredecessorAndCodeValidator : public BlockClosure { private: - BlockListList* _predecessors; + BlockListList* _predecessors; // Each index i will hold predecessors of block with id i BlockList* _blocks; static int cmp(BlockBegin** a, BlockBegin** b) { @@ -1274,98 +1302,153 @@ class PredecessorValidator : public BlockClosure { } public: - PredecessorValidator(IR* hir) { + PredecessorAndCodeValidator(IR* hir) { ResourceMark rm; _predecessors = new BlockListList(BlockBegin::number_of_blocks(), BlockBegin::number_of_blocks(), NULL); - _blocks = new BlockList(); + _blocks = new BlockList(BlockBegin::number_of_blocks()); - int i; hir->start()->iterate_preorder(this); if (hir->code() != NULL) { assert(hir->code()->length() == _blocks->length(), "must match"); - for (i = 0; i < _blocks->length(); i++) { + for (int i = 0; i < _blocks->length(); i++) { assert(hir->code()->contains(_blocks->at(i)), "should be in both lists"); } } - for (i = 0; i < _blocks->length(); i++) { + for (int i = 0; i < _blocks->length(); i++) { BlockBegin* block = _blocks->at(i); - BlockList* preds = _predecessors->at(block->block_id()); - if (preds == NULL) { - assert(block->number_of_preds() == 0, "should be the same"); - continue; - } - - // clone the pred list so we can mutate it - BlockList* pred_copy = new BlockList(); - int j; - for (j = 0; j < block->number_of_preds(); j++) { - pred_copy->append(block->pred_at(j)); - } - // sort them in the same order - preds->sort(cmp); - pred_copy->sort(cmp); - int length = MIN2(preds->length(), block->number_of_preds()); - for (j = 0; j < block->number_of_preds(); j++) { - assert(preds->at(j) == pred_copy->at(j), "must match"); - } - - assert(preds->length() == block->number_of_preds(), "should be the same"); + verify_block_preds_against_collected_preds(block); } } virtual void block_do(BlockBegin* block) { _blocks->append(block); - BlockEnd* be = block->end(); - int n = be->number_of_sux(); - int i; - for (i = 0; i < n; i++) { - BlockBegin* sux = be->sux_at(i); - assert(!sux->is_set(BlockBegin::exception_entry_flag), "must not be xhandler"); - - BlockList* preds = _predecessors->at_grow(sux->block_id(), NULL); - if (preds == NULL) { - preds = new BlockList(); - _predecessors->at_put(sux->block_id(), preds); - } - preds->append(block); + collect_predecessors(block); + } + + private: + void collect_predecessors(BlockBegin* block) { + for (int i = 0; i < block->end()->number_of_sux(); i++) { + collect_predecessor(block, block->end()->sux_at(i)); + } + for (int i = 0; i < block->number_of_exception_handlers(); i++) { + collect_predecessor(block, block->exception_handler_at(i)); + } + } + + void collect_predecessor(BlockBegin* const pred, const BlockBegin* sux) { + BlockList* preds = _predecessors->at_grow(sux->block_id(), NULL); + if (preds == NULL) { + preds = new BlockList(); + _predecessors->at_put(sux->block_id(), preds); } + preds->append(pred); + } - n = block->number_of_exception_handlers(); - for (i = 0; i < n; i++) { - BlockBegin* sux = block->exception_handler_at(i); - assert(sux->is_set(BlockBegin::exception_entry_flag), "must be xhandler"); + void verify_block_preds_against_collected_preds(const BlockBegin* block) const { + BlockList* preds = _predecessors->at(block->block_id()); + if (preds == NULL) { + assert(block->number_of_preds() == 0, "should be the same"); + return; + } + assert(preds->length() == block->number_of_preds(), "should be the same"); - BlockList* preds = _predecessors->at_grow(sux->block_id(), NULL); - if (preds == NULL) { - preds = new BlockList(); - _predecessors->at_put(sux->block_id(), preds); - } - preds->append(block); + // clone the pred list so we can mutate it + BlockList* pred_copy = new BlockList(); + for (int j = 0; j < block->number_of_preds(); j++) { + pred_copy->append(block->pred_at(j)); + } + // sort them in the same order + preds->sort(cmp); + pred_copy->sort(cmp); + for (int j = 0; j < block->number_of_preds(); j++) { + assert(preds->at(j) == pred_copy->at(j), "must match"); } } }; class VerifyBlockBeginField : public BlockClosure { - public: - - virtual void block_do(BlockBegin *block) { - for ( Instruction *cur = block; cur != NULL; cur = cur->next()) { + virtual void block_do(BlockBegin* block) { + for (Instruction* cur = block; cur != NULL; cur = cur->next()) { assert(cur->block() == block, "Block begin is not correct"); } } }; -void IR::verify() { -#ifdef ASSERT - PredecessorValidator pv(this); +class ValidateEdgeMutuality : public BlockClosure { + public: + virtual void block_do(BlockBegin* block) { + for (int i = 0; i < block->end()->number_of_sux(); i++) { + assert(block->end()->sux_at(i)->is_predecessor(block), "Block's successor should have it as predecessor"); + } + + for (int i = 0; i < block->number_of_exception_handlers(); i++) { + assert(block->exception_handler_at(i)->is_predecessor(block), "Block's exception handler should have it as predecessor"); + } + + for (int i = 0; i < block->number_of_preds(); i++) { + assert(block->pred_at(i) != NULL, "Predecessor must exist"); + assert(block->pred_at(i)->end() != NULL, "Predecessor end must exist"); + bool is_sux = block->pred_at(i)->end()->is_sux(block); + bool is_xhandler = block->pred_at(i)->is_exception_handler(block); + assert(is_sux || is_xhandler, "Block's predecessor should have it as successor or xhandler"); + } + } +}; + +void IR::expand_with_neighborhood(BlockList& blocks) { + int original_size = blocks.length(); + for (int h = 0; h < original_size; h++) { + BlockBegin* block = blocks.at(h); + + for (int i = 0; i < block->end()->number_of_sux(); i++) { + if (!blocks.contains(block->end()->sux_at(i))) { + blocks.append(block->end()->sux_at(i)); + } + } + + for (int i = 0; i < block->number_of_preds(); i++) { + if (!blocks.contains(block->pred_at(i))) { + blocks.append(block->pred_at(i)); + } + } + + for (int i = 0; i < block->number_of_exception_handlers(); i++) { + if (!blocks.contains(block->exception_handler_at(i))) { + blocks.append(block->exception_handler_at(i)); + } + } + } +} + +void IR::verify_local(BlockList& blocks) { + EndNotNullValidator ennv; + blocks.iterate_forward(&ennv); + + ValidateEdgeMutuality vem; + blocks.iterate_forward(&vem); + VerifyBlockBeginField verifier; - this->iterate_postorder(&verifier); -#endif + blocks.iterate_forward(&verifier); } -#endif // PRODUCT +void IR::verify() { + XentryFlagValidator xe; + iterate_postorder(&xe); + + PredecessorAndCodeValidator pv(this); + + EndNotNullValidator ennv; + iterate_postorder(&ennv); + + ValidateEdgeMutuality vem; + iterate_postorder(&vem); + + VerifyBlockBeginField verifier; + iterate_postorder(&verifier); +} +#endif // ASSERT void SubstitutionResolver::visit(Value* v) { Value v0 = *v; diff --git a/src/hotspot/share/c1/c1_IR.hpp b/src/hotspot/share/c1/c1_IR.hpp index f7155c464137d5bafdb78d311a32a84c06a20fdb..1c759a8bee2408b7f3f2663643da4f5158e2cb9c 100644 --- a/src/hotspot/share/c1/c1_IR.hpp +++ b/src/hotspot/share/c1/c1_IR.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -232,16 +232,15 @@ class IRScopeDebugInfo: public CompilationResourceObj { //Whether we should reexecute this bytecode for deopt bool should_reexecute(); - void record_debug_info(DebugInformationRecorder* recorder, int pc_offset, bool topmost, bool is_method_handle_invoke = false) { + void record_debug_info(DebugInformationRecorder* recorder, int pc_offset, bool reexecute, bool is_method_handle_invoke = false) { if (caller() != NULL) { // Order is significant: Must record caller first. - caller()->record_debug_info(recorder, pc_offset, false/*topmost*/); + caller()->record_debug_info(recorder, pc_offset, false/*reexecute*/); } DebugToken* locvals = recorder->create_scope_values(locals()); DebugToken* expvals = recorder->create_scope_values(expressions()); DebugToken* monvals = recorder->create_monitor_values(monitors()); // reexecute allowed only for the topmost frame - bool reexecute = topmost ? should_reexecute() : false; bool return_oop = false; // This flag will be ignored since it used only for C2 with escape analysis. bool rethrow_exception = false; bool is_opt_native = false; @@ -264,6 +263,7 @@ class CodeEmitInfo: public CompilationResourceObj { ValueStack* _stack; // used by deoptimization (contains also monitors bool _is_method_handle_invoke; // true if the associated call site is a MethodHandle call site. bool _deoptimize_on_exception; + bool _force_reexecute; // force the reexecute flag on, used for patching stub FrameMap* frame_map() const { return scope()->compilation()->frame_map(); } Compilation* compilation() const { return scope()->compilation(); } @@ -290,7 +290,11 @@ class CodeEmitInfo: public CompilationResourceObj { bool is_method_handle_invoke() const { return _is_method_handle_invoke; } void set_is_method_handle_invoke(bool x) { _is_method_handle_invoke = x; } + bool force_reexecute() const { return _force_reexecute; } + void set_force_reexecute() { _force_reexecute = true; } + int interpreter_frame_size() const; + }; @@ -338,7 +342,10 @@ class IR: public CompilationResourceObj { // debugging static void print(BlockBegin* start, bool cfg_only, bool live_only = false) PRODUCT_RETURN; void print(bool cfg_only, bool live_only = false) PRODUCT_RETURN; - void verify() PRODUCT_RETURN; + + void expand_with_neighborhood(BlockList& blocks) NOT_DEBUG_RETURN; + void verify_local(BlockList&) NOT_DEBUG_RETURN; + void verify() NOT_DEBUG_RETURN; }; diff --git a/src/hotspot/share/c1/c1_Instruction.cpp b/src/hotspot/share/c1/c1_Instruction.cpp index 687d2dae707be2a50dce11a29416b8f31bd0a6e3..75cb0c2ccd65ed4e96175ea53335a4f418442f6e 100644 --- a/src/hotspot/share/c1/c1_Instruction.cpp +++ b/src/hotspot/share/c1/c1_Instruction.cpp @@ -524,39 +524,22 @@ Constant::CompareResult Constant::compare(Instruction::Condition cond, Value rig // Implementation of BlockBegin -void BlockBegin::set_end(BlockEnd* end) { - assert(end != NULL, "should not reset block end to NULL"); - if (end == _end) { - return; - } - clear_end(); - - // Set the new end - _end = end; +void BlockBegin::set_end(BlockEnd* new_end) { // Assumes that no predecessor of new_end still has it as its successor + assert(new_end != NULL, "Should not reset block new_end to NULL"); + if (new_end == _end) return; - _successors.clear(); - // Now reset successors list based on BlockEnd - for (int i = 0; i < end->number_of_sux(); i++) { - BlockBegin* sux = end->sux_at(i); - _successors.append(sux); - sux->_predecessors.append(this); + // Remove this block as predecessor of its current successors + if (_end != NULL) { + for (int i = 0; i < number_of_sux(); i++) { + sux_at(i)->remove_predecessor(this); + } } - _end->set_begin(this); -} - -void BlockBegin::clear_end() { - // Must make the predecessors/successors match up with the - // BlockEnd's notion. - if (_end != NULL) { - // disconnect from the old end - _end->set_begin(NULL); + _end = new_end; - // disconnect this block from it's current successors - for (int i = 0; i < _successors.length(); i++) { - _successors.at(i)->remove_predecessor(this); - } - _end = NULL; + // Add this block as predecessor of its new successors + for (int i = 0; i < number_of_sux(); i++) { + sux_at(i)->add_predecessor(this); } } @@ -575,7 +558,7 @@ void BlockBegin::disconnect_edge(BlockBegin* from, BlockBegin* to) { if (index >= 0) { sux->_predecessors.remove_at(index); } - from->_successors.remove_at(s); + from->end()->remove_sux_at(s); } else { s++; } @@ -583,16 +566,6 @@ void BlockBegin::disconnect_edge(BlockBegin* from, BlockBegin* to) { } -void BlockBegin::disconnect_from_graph() { - // disconnect this block from all other blocks - for (int p = 0; p < number_of_preds(); p++) { - pred_at(p)->remove_successor(this); - } - for (int s = 0; s < number_of_sux(); s++) { - sux_at(s)->remove_predecessor(this); - } -} - void BlockBegin::substitute_sux(BlockBegin* old_sux, BlockBegin* new_sux) { // modify predecessors before substituting successors for (int i = 0; i < number_of_sux(); i++) { @@ -669,14 +642,6 @@ BlockBegin* BlockBegin::insert_block_between(BlockBegin* sux) { } -void BlockBegin::remove_successor(BlockBegin* pred) { - int idx; - while ((idx = _successors.find(pred)) >= 0) { - _successors.remove_at(idx); - } -} - - void BlockBegin::add_predecessor(BlockBegin* pred) { _predecessors.append(pred); } @@ -754,7 +719,7 @@ void BlockBegin::block_values_do(ValueVisitor* f) { #endif -bool BlockBegin::try_merge(ValueStack* new_state) { +bool BlockBegin::try_merge(ValueStack* new_state, bool has_irreducible_loops) { TRACE_PHI(tty->print_cr("********** try_merge for block B%d", block_id())); // local variables used for state iteration @@ -795,10 +760,9 @@ bool BlockBegin::try_merge(ValueStack* new_state) { } BitMap& requires_phi_function = new_state->scope()->requires_phi_function(); - for_each_local_value(new_state, index, new_value) { bool requires_phi = requires_phi_function.at(index) || (new_value->type()->is_double_word() && requires_phi_function.at(index + 1)); - if (requires_phi || !SelectivePhiFunctions) { + if (requires_phi || !SelectivePhiFunctions || has_irreducible_loops) { new_state->setup_phi_for_local(this, index); TRACE_PHI(tty->print_cr("creating phi-function %c%d for local %d", new_state->local_at(index)->type()->tchar(), new_state->local_at(index)->id(), index)); } @@ -837,6 +801,11 @@ bool BlockBegin::try_merge(ValueStack* new_state) { existing_state->invalidate_local(index); TRACE_PHI(tty->print_cr("invalidating local %d because of type mismatch", index)); } + + if (existing_value != new_state->local_at(index) && existing_value->as_Phi() == NULL) { + TRACE_PHI(tty->print_cr("required phi for local %d is missing, irreducible loop?", index)); + return false; // BAILOUT in caller + } } #ifdef ASSERT @@ -926,11 +895,6 @@ void BlockList::iterate_backward(BlockClosure* closure) { } -void BlockList::blocks_do(void f(BlockBegin*)) { - for (int i = length() - 1; i >= 0; i--) f(at(i)); -} - - void BlockList::values_do(ValueVisitor* f) { for (int i = length() - 1; i >= 0; i--) at(i)->block_values_do(f); } @@ -953,26 +917,10 @@ void BlockList::print(bool cfg_only, bool live_only) { // Implementation of BlockEnd -void BlockEnd::set_begin(BlockBegin* begin) { - BlockList* sux = NULL; - if (begin != NULL) { - sux = begin->successors(); - } else if (this->begin() != NULL) { - // copy our sux list - BlockList* sux = new BlockList(this->begin()->number_of_sux()); - for (int i = 0; i < this->begin()->number_of_sux(); i++) { - sux->append(this->begin()->sux_at(i)); - } - } - _sux = sux; -} - - void BlockEnd::substitute_sux(BlockBegin* old_sux, BlockBegin* new_sux) { substitute(*_sux, old_sux, new_sux); } - // Implementation of Phi // Normal phi functions take their operands from the last instruction of the diff --git a/src/hotspot/share/c1/c1_Instruction.hpp b/src/hotspot/share/c1/c1_Instruction.hpp index 6adaae6f30f6869a7737166f9aa5a463e2635e5a..10bc7eb4fdf09ec4027d366ad58326b5af11e847 100644 --- a/src/hotspot/share/c1/c1_Instruction.hpp +++ b/src/hotspot/share/c1/c1_Instruction.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -137,7 +137,6 @@ class BlockList: public GrowableArray { void iterate_forward(BlockClosure* closure); void iterate_backward(BlockClosure* closure); - void blocks_do(void f(BlockBegin*)); void values_do(ValueVisitor* f); void print(bool cfg_only = false, bool live_only = false) PRODUCT_RETURN; }; @@ -364,6 +363,7 @@ class Instruction: public CompilationResourceObj { NeedsRangeCheckFlag, InWorkListFlag, DeoptimizeOnException, + KillsMemoryFlag, InstructionLastFlag }; @@ -719,13 +719,13 @@ LEAF(Constant, Instruction) assert(type->is_constant(), "must be a constant"); } - Constant(ValueType* type, ValueStack* state_before): + Constant(ValueType* type, ValueStack* state_before, bool kills_memory = false): Instruction(type, state_before, /*type_is_constant*/ true) { assert(state_before != NULL, "only used for constants which need patching"); assert(type->is_constant(), "must be a constant"); - // since it's patching it needs to be pinned - pin(); + set_flag(KillsMemoryFlag, kills_memory); + pin(); // since it's patching it needs to be pinned } // generic @@ -737,6 +737,8 @@ LEAF(Constant, Instruction) virtual ciType* exact_type() const; + bool kills_memory() const { return check_flag(KillsMemoryFlag); } + enum CompareResult { not_comparable = -1, cond_false, cond_true }; virtual CompareResult compare(Instruction::Condition condition, Value right) const; @@ -1595,7 +1597,6 @@ LEAF(BlockBegin, StateSplit) ResourceBitMap _stores_to_locals; // bit is set when a local variable is stored in the block // SSA specific fields: (factor out later) - BlockList _successors; // the successors of this block BlockList _predecessors; // the predecessors of this block BlockList _dominates; // list of blocks that are dominated by this block BlockBegin* _dominator; // the dominator of this block @@ -1649,7 +1650,6 @@ LEAF(BlockBegin, StateSplit) , _flags(0) , _total_preds(0) , _stores_to_locals() - , _successors(2) , _predecessors(2) , _dominates(2) , _dominator(NULL) @@ -1676,7 +1676,6 @@ LEAF(BlockBegin, StateSplit) // accessors int block_id() const { return _block_id; } int bci() const { return _bci; } - BlockList* successors() { return &_successors; } BlockList* dominates() { return &_dominates; } BlockBegin* dominator() const { return _dominator; } int loop_depth() const { return _loop_depth; } @@ -1704,9 +1703,7 @@ LEAF(BlockBegin, StateSplit) void set_dominator_depth(int d) { _dominator_depth = d; } void set_depth_first_number(int dfn) { _depth_first_number = dfn; } void set_linear_scan_number(int lsn) { _linear_scan_number = lsn; } - void set_end(BlockEnd* end); - void clear_end(); - void disconnect_from_graph(); + void set_end(BlockEnd* new_end); static void disconnect_edge(BlockBegin* from, BlockBegin* to); BlockBegin* insert_block_between(BlockBegin* sux); void substitute_sux(BlockBegin* old_sux, BlockBegin* new_sux); @@ -1729,10 +1726,6 @@ LEAF(BlockBegin, StateSplit) // successors and predecessors int number_of_sux() const; BlockBegin* sux_at(int i) const; - void add_successor(BlockBegin* sux); - void remove_successor(BlockBegin* pred); - bool is_successor(BlockBegin* sux) const { return _successors.contains(sux); } - void add_predecessor(BlockBegin* pred); void remove_predecessor(BlockBegin* pred); bool is_predecessor(BlockBegin* pred) const { return _predecessors.contains(pred); } @@ -1786,12 +1779,16 @@ LEAF(BlockBegin, StateSplit) int loop_index() const { return _loop_index; } // merging - bool try_merge(ValueStack* state); // try to merge states at block begin - void merge(ValueStack* state) { bool b = try_merge(state); assert(b, "merge failed"); } + bool try_merge(ValueStack* state, bool has_irreducible_loops); // try to merge states at block begin + void merge(ValueStack* state, bool has_irreducible_loops) { + bool b = try_merge(state, has_irreducible_loops); + assert(b, "merge failed"); + } // debugging void print_block() PRODUCT_RETURN; void print_block(InstructionPrinter& ip, bool live_only = false) PRODUCT_RETURN; + }; @@ -1825,14 +1822,14 @@ BASE(BlockEnd, StateSplit) BlockBegin* begin() const { return _block; } // manipulation - void set_begin(BlockBegin* begin); + inline void remove_sux_at(int i) { _sux->remove_at(i);} + inline int find_sux(BlockBegin* sux) {return _sux->find(sux);} // successors int number_of_sux() const { return _sux != NULL ? _sux->length() : 0; } BlockBegin* sux_at(int i) const { return _sux->at(i); } + bool is_sux(BlockBegin* sux) const { return _sux == NULL ? false : _sux->contains(sux); } BlockBegin* default_sux() const { return sux_at(number_of_sux() - 1); } - BlockBegin** addr_sux_at(int i) const { return _sux->adr_at(i); } - int sux_index(BlockBegin* sux) const { return _sux->find(sux); } void substitute_sux(BlockBegin* old_sux, BlockBegin* new_sux); }; @@ -1998,14 +1995,6 @@ LEAF(If, BlockEnd) _cond = mirror(_cond); } - void swap_sux() { - assert(number_of_sux() == 2, "wrong number of successors"); - BlockList* s = sux(); - BlockBegin* t = s->at(0); s->at_put(0, s->at(1)); s->at_put(1, t); - _cond = negate(_cond); - set_flag(UnorderedIsTrueFlag, !check_flag(UnorderedIsTrueFlag)); - } - void set_should_profile(bool value) { set_flag(ProfileMDOFlag, value); } void set_profiled_method(ciMethod* method) { _profiled_method = method; } void set_profiled_bci(int bci) { _profiled_bci = bci; } @@ -2447,9 +2436,8 @@ class BlockPair: public CompilationResourceObj { typedef GrowableArray BlockPairList; -inline int BlockBegin::number_of_sux() const { assert(_end == NULL || _end->number_of_sux() == _successors.length(), "mismatch"); return _successors.length(); } -inline BlockBegin* BlockBegin::sux_at(int i) const { assert(_end == NULL || _end->sux_at(i) == _successors.at(i), "mismatch"); return _successors.at(i); } -inline void BlockBegin::add_successor(BlockBegin* sux) { assert(_end == NULL, "Would create mismatch with successors of BlockEnd"); _successors.append(sux); } +inline int BlockBegin::number_of_sux() const { assert(_end != NULL, "need end"); return _end->number_of_sux(); } +inline BlockBegin* BlockBegin::sux_at(int i) const { assert(_end != NULL , "need end"); return _end->sux_at(i); } #undef ASSERT_VALUES diff --git a/src/hotspot/share/c1/c1_InstructionPrinter.cpp b/src/hotspot/share/c1/c1_InstructionPrinter.cpp index 3e0708351a6cbfd65653700b97995dbb7a3f0f35..f1757d0dbb0bfa074cb7b9f685d24de53c920807 100644 --- a/src/hotspot/share/c1/c1_InstructionPrinter.cpp +++ b/src/hotspot/share/c1/c1_InstructionPrinter.cpp @@ -262,7 +262,7 @@ void InstructionPrinter::print_inline_level(BlockBegin* block) { void InstructionPrinter::print_unsafe_op(UnsafeOp* op, const char* name) { - output()->print("%s", name); + output()->print("%s(", name); print_value(op->object()); output()->print(", "); print_value(op->offset()); @@ -612,14 +612,7 @@ void InstructionPrinter::do_BlockBegin(BlockBegin* x) { output()->print(" dom B%d", x->dominator()->block_id()); } - // print predecessors and successors - if (x->successors()->length() > 0) { - output()->print(" sux:"); - for (int i = 0; i < x->successors()->length(); i ++) { - output()->print(" B%d", x->successors()->at(i)->block_id()); - } - } - + // print predecessors if (x->number_of_preds() > 0) { output()->print(" pred:"); for (int i = 0; i < x->number_of_preds(); i ++) { diff --git a/src/hotspot/share/c1/c1_LIR.cpp b/src/hotspot/share/c1/c1_LIR.cpp index 6b1310dfd83192a0a39058446196c3e89f0b63ec..d27b9175c9da514cfceffa758b7ded5d894188c9 100644 --- a/src/hotspot/share/c1/c1_LIR.cpp +++ b/src/hotspot/share/c1/c1_LIR.cpp @@ -33,15 +33,15 @@ #include "runtime/sharedRuntime.hpp" #include "runtime/vm_version.hpp" -Register LIR_OprDesc::as_register() const { +Register LIR_Opr::as_register() const { return FrameMap::cpu_rnr2reg(cpu_regnr()); } -Register LIR_OprDesc::as_register_lo() const { +Register LIR_Opr::as_register_lo() const { return FrameMap::cpu_rnr2reg(cpu_regnrLo()); } -Register LIR_OprDesc::as_register_hi() const { +Register LIR_Opr::as_register_hi() const { return FrameMap::cpu_rnr2reg(cpu_regnrHi()); } @@ -93,7 +93,7 @@ LIR_Address::Scale LIR_Address::scale(BasicType type) { //--------------------------------------------------- -char LIR_OprDesc::type_char(BasicType t) { +char LIR_Opr::type_char(BasicType t) { switch (t) { case T_ARRAY: t = T_OBJECT; @@ -121,7 +121,7 @@ char LIR_OprDesc::type_char(BasicType t) { } #ifndef PRODUCT -void LIR_OprDesc::validate_type() const { +void LIR_Opr::validate_type() const { #ifdef ASSERT if (!is_pointer() && !is_illegal()) { @@ -132,17 +132,15 @@ void LIR_OprDesc::validate_type() const { size_field() == double_size, "must match"); break; case T_FLOAT: - // FP return values can be also in CPU registers on ARM and PPC32 (softfp ABI) + // FP return values can be also in CPU registers on ARM (softfp ABI) assert((kindfield == fpu_register || kindfield == stack_value - ARM_ONLY(|| kindfield == cpu_register) - PPC32_ONLY(|| kindfield == cpu_register) ) && + ARM_ONLY(|| kindfield == cpu_register) ) && size_field() == single_size, "must match"); break; case T_DOUBLE: - // FP return values can be also in CPU registers on ARM and PPC32 (softfp ABI) + // FP return values can be also in CPU registers on ARM (softfp ABI) assert((kindfield == fpu_register || kindfield == stack_value - ARM_ONLY(|| kindfield == cpu_register) - PPC32_ONLY(|| kindfield == cpu_register) ) && + ARM_ONLY(|| kindfield == cpu_register) ) && size_field() == double_size, "must match"); break; case T_BOOLEAN: @@ -173,7 +171,7 @@ void LIR_OprDesc::validate_type() const { #endif // PRODUCT -bool LIR_OprDesc::is_oop() const { +bool LIR_Opr::is_oop() const { if (is_pointer()) { return pointer()->is_oop_pointer(); } else { @@ -497,10 +495,6 @@ void LIR_OpVisitState::visit(LIR_Op* op) { assert(opConvert->_info == NULL, "must be"); if (opConvert->_opr->is_valid()) do_input(opConvert->_opr); if (opConvert->_result->is_valid()) do_output(opConvert->_result); -#ifdef PPC32 - if (opConvert->_tmp1->is_valid()) do_temp(opConvert->_tmp1); - if (opConvert->_tmp2->is_valid()) do_temp(opConvert->_tmp2); -#endif do_stub(opConvert->_stub); break; @@ -880,6 +874,19 @@ void LIR_OpVisitState::visit(LIR_Op* op) { break; } +// LIR_OpLoadKlass + case lir_load_klass: + { + LIR_OpLoadKlass* opLoadKlass = op->as_OpLoadKlass(); + assert(opLoadKlass != NULL, "must be"); + + do_input(opLoadKlass->_obj); + do_output(opLoadKlass->_result); + if (opLoadKlass->_info) do_info(opLoadKlass->_info); + break; + } + + // LIR_OpProfileCall: case lir_profile_call: { assert(op->as_OpProfileCall() != NULL, "must be"); @@ -1049,6 +1056,10 @@ void LIR_OpLock::emit_code(LIR_Assembler* masm) { } } +void LIR_OpLoadKlass::emit_code(LIR_Assembler* masm) { + masm->emit_load_klass(this); +} + #ifdef ASSERT void LIR_OpAssert::emit_code(LIR_Assembler* masm) { masm->emit_assert(this); @@ -1373,7 +1384,7 @@ void LIR_List::unlock_object(LIR_Opr hdr, LIR_Opr obj, LIR_Opr lock, LIR_Opr scr void check_LIR() { // cannot do the proper checking as PRODUCT and other modes return different results - // guarantee(sizeof(LIR_OprDesc) == wordSize, "may not have a v-table"); + // guarantee(sizeof(LIR_Opr) == wordSize, "may not have a v-table"); } @@ -1448,12 +1459,12 @@ void print_LIR(BlockList* blocks) { } #else -// LIR_OprDesc -void LIR_OprDesc::print() const { +// LIR_Opr +void LIR_Opr::print() const { print(tty); } -void LIR_OprDesc::print(outputStream* out) const { +void LIR_Opr::print(outputStream* out) const { if (is_illegal()) { return; } @@ -1569,7 +1580,7 @@ static void print_block(BlockBegin* x) { } } - if (x->number_of_sux() > 0) { + if (end != NULL && x->number_of_sux() > 0) { tty->print("sux: "); for (int i = 0; i < x->number_of_sux(); i ++) { tty->print("B%d ", x->sux_at(i)->block_id()); @@ -1857,12 +1868,6 @@ void LIR_OpConvert::print_instr(outputStream* out) const { print_bytecode(out, bytecode()); in_opr()->print(out); out->print(" "); result_opr()->print(out); out->print(" "); -#ifdef PPC32 - if(tmp1()->is_valid()) { - tmp1()->print(out); out->print(" "); - tmp2()->print(out); out->print(" "); - } -#endif } void LIR_OpConvert::print_bytecode(outputStream* out, Bytecodes::Code code) { @@ -1970,6 +1975,11 @@ void LIR_OpLock::print_instr(outputStream* out) const { out->print("[lbl:" INTPTR_FORMAT "]", p2i(stub()->entry())); } +void LIR_OpLoadKlass::print_instr(outputStream* out) const { + obj()->print(out); out->print(" "); + result_opr()->print(out); out->print(" "); +} + #ifdef ASSERT void LIR_OpAssert::print_instr(outputStream* out) const { print_condition(out, condition()); out->print(" "); diff --git a/src/hotspot/share/c1/c1_LIR.hpp b/src/hotspot/share/c1/c1_LIR.hpp index 6a6f33b775519506db88b182b5ed96f5ab691f2f..c4504b7b8b5cc39d18f37279eff13859faeabb87 100644 --- a/src/hotspot/share/c1/c1_LIR.hpp +++ b/src/hotspot/share/c1/c1_LIR.hpp @@ -478,40 +478,31 @@ class LIR_Opr { void print(outputStream* out) const PRODUCT_RETURN; }; -// TODO: Remove this hack. -// UGLY HACK: add a type alias. `LIR_Opr` is not actually equivalent to the -// previous `LIR_OprDesc` (`LIR_Opr` is like more similar to previous -// `LIR_OprDesc*`). The only purpose of this typedef is so that the various -// `LIR_OprDesc::enum_value` scattered everywhere don't need to be -// modified. This should be removed, and a textual replacement of -// `LIR_OprDesc::` to `LIR_Opr::` done throughout the code. -typedef LIR_Opr LIR_OprDesc; - -inline LIR_OprDesc::OprType as_OprType(BasicType type) { +inline LIR_Opr::OprType as_OprType(BasicType type) { switch (type) { - case T_INT: return LIR_OprDesc::int_type; - case T_LONG: return LIR_OprDesc::long_type; - case T_FLOAT: return LIR_OprDesc::float_type; - case T_DOUBLE: return LIR_OprDesc::double_type; + case T_INT: return LIR_Opr::int_type; + case T_LONG: return LIR_Opr::long_type; + case T_FLOAT: return LIR_Opr::float_type; + case T_DOUBLE: return LIR_Opr::double_type; case T_OBJECT: - case T_ARRAY: return LIR_OprDesc::object_type; - case T_ADDRESS: return LIR_OprDesc::address_type; - case T_METADATA: return LIR_OprDesc::metadata_type; + case T_ARRAY: return LIR_Opr::object_type; + case T_ADDRESS: return LIR_Opr::address_type; + case T_METADATA: return LIR_Opr::metadata_type; case T_ILLEGAL: // fall through - default: ShouldNotReachHere(); return LIR_OprDesc::unknown_type; + default: ShouldNotReachHere(); return LIR_Opr::unknown_type; } } -inline BasicType as_BasicType(LIR_OprDesc::OprType t) { +inline BasicType as_BasicType(LIR_Opr::OprType t) { switch (t) { - case LIR_OprDesc::int_type: return T_INT; - case LIR_OprDesc::long_type: return T_LONG; - case LIR_OprDesc::float_type: return T_FLOAT; - case LIR_OprDesc::double_type: return T_DOUBLE; - case LIR_OprDesc::object_type: return T_OBJECT; - case LIR_OprDesc::address_type: return T_ADDRESS; - case LIR_OprDesc::metadata_type:return T_METADATA; - case LIR_OprDesc::unknown_type: // fall through + case LIR_Opr::int_type: return T_INT; + case LIR_Opr::long_type: return T_LONG; + case LIR_Opr::float_type: return T_FLOAT; + case LIR_Opr::double_type: return T_DOUBLE; + case LIR_Opr::object_type: return T_OBJECT; + case LIR_Opr::address_type: return T_ADDRESS; + case LIR_Opr::metadata_type:return T_METADATA; + case LIR_Opr::unknown_type: // fall through default: ShouldNotReachHere(); return T_ILLEGAL; } } @@ -549,14 +540,14 @@ class LIR_Address: public LIR_OprPtr { LIR_Address(LIR_Opr base, intx disp, BasicType type): _base(base) - , _index(LIR_OprDesc::illegalOpr()) + , _index(LIR_Opr::illegalOpr()) , _scale(times_1) , _disp(disp) , _type(type) { verify(); } LIR_Address(LIR_Opr base, BasicType type): _base(base) - , _index(LIR_OprDesc::illegalOpr()) + , _index(LIR_Opr::illegalOpr()) , _scale(times_1) , _disp(0) , _type(type) { verify(); } @@ -600,43 +591,43 @@ class LIR_OprFact: public AllStatic { static LIR_Opr nullOpr; static LIR_Opr single_cpu(int reg) { - return (LIR_Opr)(intptr_t)((reg << LIR_OprDesc::reg1_shift) | - LIR_OprDesc::int_type | - LIR_OprDesc::cpu_register | - LIR_OprDesc::single_size); + return (LIR_Opr)(intptr_t)((reg << LIR_Opr::reg1_shift) | + LIR_Opr::int_type | + LIR_Opr::cpu_register | + LIR_Opr::single_size); } static LIR_Opr single_cpu_oop(int reg) { - return (LIR_Opr)(intptr_t)((reg << LIR_OprDesc::reg1_shift) | - LIR_OprDesc::object_type | - LIR_OprDesc::cpu_register | - LIR_OprDesc::single_size); + return (LIR_Opr)(intptr_t)((reg << LIR_Opr::reg1_shift) | + LIR_Opr::object_type | + LIR_Opr::cpu_register | + LIR_Opr::single_size); } static LIR_Opr single_cpu_address(int reg) { - return (LIR_Opr)(intptr_t)((reg << LIR_OprDesc::reg1_shift) | - LIR_OprDesc::address_type | - LIR_OprDesc::cpu_register | - LIR_OprDesc::single_size); + return (LIR_Opr)(intptr_t)((reg << LIR_Opr::reg1_shift) | + LIR_Opr::address_type | + LIR_Opr::cpu_register | + LIR_Opr::single_size); } static LIR_Opr single_cpu_metadata(int reg) { - return (LIR_Opr)(intptr_t)((reg << LIR_OprDesc::reg1_shift) | - LIR_OprDesc::metadata_type | - LIR_OprDesc::cpu_register | - LIR_OprDesc::single_size); + return (LIR_Opr)(intptr_t)((reg << LIR_Opr::reg1_shift) | + LIR_Opr::metadata_type | + LIR_Opr::cpu_register | + LIR_Opr::single_size); } static LIR_Opr double_cpu(int reg1, int reg2) { LP64_ONLY(assert(reg1 == reg2, "must be identical")); - return (LIR_Opr)(intptr_t)((reg1 << LIR_OprDesc::reg1_shift) | - (reg2 << LIR_OprDesc::reg2_shift) | - LIR_OprDesc::long_type | - LIR_OprDesc::cpu_register | - LIR_OprDesc::double_size); + return (LIR_Opr)(intptr_t)((reg1 << LIR_Opr::reg1_shift) | + (reg2 << LIR_Opr::reg2_shift) | + LIR_Opr::long_type | + LIR_Opr::cpu_register | + LIR_Opr::double_size); } static LIR_Opr single_fpu(int reg) { - return (LIR_Opr)(intptr_t)((reg << LIR_OprDesc::reg1_shift) | - LIR_OprDesc::float_type | - LIR_OprDesc::fpu_register | - LIR_OprDesc::single_size); + return (LIR_Opr)(intptr_t)((reg << LIR_Opr::reg1_shift) | + LIR_Opr::float_type | + LIR_Opr::fpu_register | + LIR_Opr::single_size); } // Platform dependant. @@ -644,40 +635,40 @@ class LIR_OprFact: public AllStatic { #ifdef ARM32 static LIR_Opr single_softfp(int reg) { - return (LIR_Opr)(intptr_t)((reg << LIR_OprDesc::reg1_shift) | - LIR_OprDesc::float_type | - LIR_OprDesc::cpu_register | - LIR_OprDesc::single_size); + return (LIR_Opr)(intptr_t)((reg << LIR_Opr::reg1_shift) | + LIR_Opr::float_type | + LIR_Opr::cpu_register | + LIR_Opr::single_size); } static LIR_Opr double_softfp(int reg1, int reg2) { - return (LIR_Opr)(intptr_t)((reg1 << LIR_OprDesc::reg1_shift) | - (reg2 << LIR_OprDesc::reg2_shift) | - LIR_OprDesc::double_type | - LIR_OprDesc::cpu_register | - LIR_OprDesc::double_size); + return (LIR_Opr)(intptr_t)((reg1 << LIR_Opr::reg1_shift) | + (reg2 << LIR_Opr::reg2_shift) | + LIR_Opr::double_type | + LIR_Opr::cpu_register | + LIR_Opr::double_size); } #endif // ARM32 #if defined(X86) static LIR_Opr single_xmm(int reg) { - return (LIR_Opr)(intptr_t)((reg << LIR_OprDesc::reg1_shift) | - LIR_OprDesc::float_type | - LIR_OprDesc::fpu_register | - LIR_OprDesc::single_size | - LIR_OprDesc::is_xmm_mask); + return (LIR_Opr)(intptr_t)((reg << LIR_Opr::reg1_shift) | + LIR_Opr::float_type | + LIR_Opr::fpu_register | + LIR_Opr::single_size | + LIR_Opr::is_xmm_mask); } static LIR_Opr double_xmm(int reg) { - return (LIR_Opr)(intptr_t)((reg << LIR_OprDesc::reg1_shift) | - (reg << LIR_OprDesc::reg2_shift) | - LIR_OprDesc::double_type | - LIR_OprDesc::fpu_register | - LIR_OprDesc::double_size | - LIR_OprDesc::is_xmm_mask); + return (LIR_Opr)(intptr_t)((reg << LIR_Opr::reg1_shift) | + (reg << LIR_Opr::reg2_shift) | + LIR_Opr::double_type | + LIR_Opr::fpu_register | + LIR_Opr::double_size | + LIR_Opr::is_xmm_mask); } #endif // X86 static LIR_Opr virtual_register(int index, BasicType type) { - if (index > LIR_OprDesc::vreg_max) { + if (index > LIR_Opr::vreg_max) { // Running out of virtual registers. Caller should bailout. return illegalOpr; } @@ -686,75 +677,75 @@ class LIR_OprFact: public AllStatic { switch (type) { case T_OBJECT: // fall through case T_ARRAY: - res = (LIR_Opr)(intptr_t)((index << LIR_OprDesc::data_shift) | - LIR_OprDesc::object_type | - LIR_OprDesc::cpu_register | - LIR_OprDesc::single_size | - LIR_OprDesc::virtual_mask); + res = (LIR_Opr)(intptr_t)((index << LIR_Opr::data_shift) | + LIR_Opr::object_type | + LIR_Opr::cpu_register | + LIR_Opr::single_size | + LIR_Opr::virtual_mask); break; case T_METADATA: - res = (LIR_Opr)(intptr_t)((index << LIR_OprDesc::data_shift) | - LIR_OprDesc::metadata_type| - LIR_OprDesc::cpu_register | - LIR_OprDesc::single_size | - LIR_OprDesc::virtual_mask); + res = (LIR_Opr)(intptr_t)((index << LIR_Opr::data_shift) | + LIR_Opr::metadata_type| + LIR_Opr::cpu_register | + LIR_Opr::single_size | + LIR_Opr::virtual_mask); break; case T_INT: - res = (LIR_Opr)(intptr_t)((index << LIR_OprDesc::data_shift) | - LIR_OprDesc::int_type | - LIR_OprDesc::cpu_register | - LIR_OprDesc::single_size | - LIR_OprDesc::virtual_mask); + res = (LIR_Opr)(intptr_t)((index << LIR_Opr::data_shift) | + LIR_Opr::int_type | + LIR_Opr::cpu_register | + LIR_Opr::single_size | + LIR_Opr::virtual_mask); break; case T_ADDRESS: - res = (LIR_Opr)(intptr_t)((index << LIR_OprDesc::data_shift) | - LIR_OprDesc::address_type | - LIR_OprDesc::cpu_register | - LIR_OprDesc::single_size | - LIR_OprDesc::virtual_mask); + res = (LIR_Opr)(intptr_t)((index << LIR_Opr::data_shift) | + LIR_Opr::address_type | + LIR_Opr::cpu_register | + LIR_Opr::single_size | + LIR_Opr::virtual_mask); break; case T_LONG: - res = (LIR_Opr)(intptr_t)((index << LIR_OprDesc::data_shift) | - LIR_OprDesc::long_type | - LIR_OprDesc::cpu_register | - LIR_OprDesc::double_size | - LIR_OprDesc::virtual_mask); + res = (LIR_Opr)(intptr_t)((index << LIR_Opr::data_shift) | + LIR_Opr::long_type | + LIR_Opr::cpu_register | + LIR_Opr::double_size | + LIR_Opr::virtual_mask); break; #ifdef __SOFTFP__ case T_FLOAT: - res = (LIR_Opr)(intptr_t)((index << LIR_OprDesc::data_shift) | - LIR_OprDesc::float_type | - LIR_OprDesc::cpu_register | - LIR_OprDesc::single_size | - LIR_OprDesc::virtual_mask); + res = (LIR_Opr)(intptr_t)((index << LIR_Opr::data_shift) | + LIR_Opr::float_type | + LIR_Opr::cpu_register | + LIR_Opr::single_size | + LIR_Opr::virtual_mask); break; case T_DOUBLE: - res = (LIR_Opr)(intptr_t)((index << LIR_OprDesc::data_shift) | - LIR_OprDesc::double_type | - LIR_OprDesc::cpu_register | - LIR_OprDesc::double_size | - LIR_OprDesc::virtual_mask); + res = (LIR_Opr)(intptr_t)((index << LIR_Opr::data_shift) | + LIR_Opr::double_type | + LIR_Opr::cpu_register | + LIR_Opr::double_size | + LIR_Opr::virtual_mask); break; #else // __SOFTFP__ case T_FLOAT: - res = (LIR_Opr)(intptr_t)((index << LIR_OprDesc::data_shift) | - LIR_OprDesc::float_type | - LIR_OprDesc::fpu_register | - LIR_OprDesc::single_size | - LIR_OprDesc::virtual_mask); + res = (LIR_Opr)(intptr_t)((index << LIR_Opr::data_shift) | + LIR_Opr::float_type | + LIR_Opr::fpu_register | + LIR_Opr::single_size | + LIR_Opr::virtual_mask); break; case - T_DOUBLE: res = (LIR_Opr)(intptr_t)((index << LIR_OprDesc::data_shift) | - LIR_OprDesc::double_type | - LIR_OprDesc::fpu_register | - LIR_OprDesc::double_size | - LIR_OprDesc::virtual_mask); + T_DOUBLE: res = (LIR_Opr)(intptr_t)((index << LIR_Opr::data_shift) | + LIR_Opr::double_type | + LIR_Opr::fpu_register | + LIR_Opr::double_size | + LIR_Opr::virtual_mask); break; #endif // __SOFTFP__ default: ShouldNotReachHere(); res = illegalOpr; @@ -763,20 +754,20 @@ class LIR_OprFact: public AllStatic { #ifdef ASSERT res->validate_type(); assert(res->vreg_number() == index, "conversion check"); - assert(index >= LIR_OprDesc::vreg_base, "must start at vreg_base"); - assert(index <= (max_jint >> LIR_OprDesc::data_shift), "index is too big"); + assert(index >= LIR_Opr::vreg_base, "must start at vreg_base"); + assert(index <= (max_jint >> LIR_Opr::data_shift), "index is too big"); // old-style calculation; check if old and new method are equal - LIR_OprDesc::OprType t = as_OprType(type); + LIR_Opr::OprType t = as_OprType(type); #ifdef __SOFTFP__ - LIR_Opr old_res = (LIR_Opr)(intptr_t)((index << LIR_OprDesc::data_shift) | + LIR_Opr old_res = (LIR_Opr)(intptr_t)((index << LIR_Opr::data_shift) | t | - LIR_OprDesc::cpu_register | - LIR_OprDesc::size_for(type) | LIR_OprDesc::virtual_mask); + LIR_Opr::cpu_register | + LIR_Opr::size_for(type) | LIR_Opr::virtual_mask); #else // __SOFTFP__ - LIR_Opr old_res = (LIR_Opr)(intptr_t)((index << LIR_OprDesc::data_shift) | t | - ((type == T_FLOAT || type == T_DOUBLE) ? LIR_OprDesc::fpu_register : LIR_OprDesc::cpu_register) | - LIR_OprDesc::size_for(type) | LIR_OprDesc::virtual_mask); + LIR_Opr old_res = (LIR_Opr)(intptr_t)((index << LIR_Opr::data_shift) | t | + ((type == T_FLOAT || type == T_DOUBLE) ? LIR_Opr::fpu_register : LIR_Opr::cpu_register) | + LIR_Opr::size_for(type) | LIR_Opr::virtual_mask); assert(res == old_res, "old and new method not equal"); #endif // __SOFTFP__ #endif // ASSERT @@ -792,50 +783,50 @@ class LIR_OprFact: public AllStatic { switch (type) { case T_OBJECT: // fall through case T_ARRAY: - res = (LIR_Opr)(intptr_t)((index << LIR_OprDesc::data_shift) | - LIR_OprDesc::object_type | - LIR_OprDesc::stack_value | - LIR_OprDesc::single_size); + res = (LIR_Opr)(intptr_t)((index << LIR_Opr::data_shift) | + LIR_Opr::object_type | + LIR_Opr::stack_value | + LIR_Opr::single_size); break; case T_METADATA: - res = (LIR_Opr)(intptr_t)((index << LIR_OprDesc::data_shift) | - LIR_OprDesc::metadata_type | - LIR_OprDesc::stack_value | - LIR_OprDesc::single_size); + res = (LIR_Opr)(intptr_t)((index << LIR_Opr::data_shift) | + LIR_Opr::metadata_type | + LIR_Opr::stack_value | + LIR_Opr::single_size); break; case T_INT: - res = (LIR_Opr)(intptr_t)((index << LIR_OprDesc::data_shift) | - LIR_OprDesc::int_type | - LIR_OprDesc::stack_value | - LIR_OprDesc::single_size); + res = (LIR_Opr)(intptr_t)((index << LIR_Opr::data_shift) | + LIR_Opr::int_type | + LIR_Opr::stack_value | + LIR_Opr::single_size); break; case T_ADDRESS: - res = (LIR_Opr)(intptr_t)((index << LIR_OprDesc::data_shift) | - LIR_OprDesc::address_type | - LIR_OprDesc::stack_value | - LIR_OprDesc::single_size); + res = (LIR_Opr)(intptr_t)((index << LIR_Opr::data_shift) | + LIR_Opr::address_type | + LIR_Opr::stack_value | + LIR_Opr::single_size); break; case T_LONG: - res = (LIR_Opr)(intptr_t)((index << LIR_OprDesc::data_shift) | - LIR_OprDesc::long_type | - LIR_OprDesc::stack_value | - LIR_OprDesc::double_size); + res = (LIR_Opr)(intptr_t)((index << LIR_Opr::data_shift) | + LIR_Opr::long_type | + LIR_Opr::stack_value | + LIR_Opr::double_size); break; case T_FLOAT: - res = (LIR_Opr)(intptr_t)((index << LIR_OprDesc::data_shift) | - LIR_OprDesc::float_type | - LIR_OprDesc::stack_value | - LIR_OprDesc::single_size); + res = (LIR_Opr)(intptr_t)((index << LIR_Opr::data_shift) | + LIR_Opr::float_type | + LIR_Opr::stack_value | + LIR_Opr::single_size); break; case T_DOUBLE: - res = (LIR_Opr)(intptr_t)((index << LIR_OprDesc::data_shift) | - LIR_OprDesc::double_type | - LIR_OprDesc::stack_value | - LIR_OprDesc::double_size); + res = (LIR_Opr)(intptr_t)((index << LIR_Opr::data_shift) | + LIR_Opr::double_type | + LIR_Opr::stack_value | + LIR_Opr::double_size); break; default: ShouldNotReachHere(); res = illegalOpr; @@ -843,12 +834,12 @@ class LIR_OprFact: public AllStatic { #ifdef ASSERT assert(index >= 0, "index must be positive"); - assert(index <= (max_jint >> LIR_OprDesc::data_shift), "index is too big"); + assert(index <= (max_jint >> LIR_Opr::data_shift), "index is too big"); - LIR_Opr old_res = (LIR_Opr)(intptr_t)((index << LIR_OprDesc::data_shift) | - LIR_OprDesc::stack_value | + LIR_Opr old_res = (LIR_Opr)(intptr_t)((index << LIR_Opr::data_shift) | + LIR_Opr::stack_value | as_OprType(type) | - LIR_OprDesc::size_for(type)); + LIR_Opr::size_for(type)); assert(res == old_res, "old and new method not equal"); #endif @@ -904,6 +895,7 @@ class LIR_OpUpdateCRC32; class LIR_OpLock; class LIR_OpTypeCheck; class LIR_OpCompareAndSwap; +class LIR_OpLoadKlass; class LIR_OpProfileCall; class LIR_OpProfileType; #ifdef ASSERT @@ -948,6 +940,7 @@ enum LIR_Code { , lir_roundfp , lir_safepoint , lir_unwind + , lir_load_klass , end_op1 , begin_op2 , lir_cmp @@ -1157,6 +1150,7 @@ class LIR_Op: public CompilationResourceObj { virtual LIR_OpUpdateCRC32* as_OpUpdateCRC32() { return NULL; } virtual LIR_OpTypeCheck* as_OpTypeCheck() { return NULL; } virtual LIR_OpCompareAndSwap* as_OpCompareAndSwap() { return NULL; } + virtual LIR_OpLoadKlass* as_OpLoadKlass() { return NULL; } virtual LIR_OpProfileCall* as_OpProfileCall() { return NULL; } virtual LIR_OpProfileType* as_OpProfileType() { return NULL; } #ifdef ASSERT @@ -1829,6 +1823,23 @@ class LIR_OpLock: public LIR_Op { void print_instr(outputStream* out) const PRODUCT_RETURN; }; +class LIR_OpLoadKlass: public LIR_Op { + friend class LIR_OpVisitState; + + private: + LIR_Opr _obj; + public: + LIR_OpLoadKlass(LIR_Opr obj, LIR_Opr result, CodeEmitInfo* info) + : LIR_Op(lir_load_klass, result, info) + , _obj(obj) + {} + + LIR_Opr obj() const { return _obj; } + + virtual LIR_OpLoadKlass* as_OpLoadKlass() { return this; } + virtual void emit_code(LIR_Assembler* masm); + void print_instr(outputStream* out) const PRODUCT_RETURN; +}; class LIR_OpDelay: public LIR_Op { friend class LIR_OpVisitState; @@ -2271,6 +2282,9 @@ class LIR_List: public CompilationResourceObj { void xadd(LIR_Opr src, LIR_Opr add, LIR_Opr res, LIR_Opr tmp) { append(new LIR_Op2(lir_xadd, src, add, res, tmp)); } void xchg(LIR_Opr src, LIR_Opr set, LIR_Opr res, LIR_Opr tmp) { append(new LIR_Op2(lir_xchg, src, set, res, tmp)); } + + void load_klass(LIR_Opr obj, LIR_Opr result, CodeEmitInfo* info) { append(new LIR_OpLoadKlass(obj, result, info)); } + #ifdef ASSERT void lir_assert(LIR_Condition condition, LIR_Opr opr1, LIR_Opr opr2, const char* msg, bool halt) { append(new LIR_OpAssert(condition, opr1, opr2, msg, halt)); } #endif @@ -2474,8 +2488,8 @@ class LIR_OpVisitState: public StackObj { }; -inline LIR_Opr LIR_OprDesc::illegalOpr() { return LIR_OprFact::illegalOpr; }; +inline LIR_Opr LIR_Opr::illegalOpr() { return LIR_OprFact::illegalOpr; }; -inline LIR_Opr LIR_OprDesc::nullOpr() { return LIR_OprFact::nullOpr; }; +inline LIR_Opr LIR_Opr::nullOpr() { return LIR_OprFact::nullOpr; }; #endif // SHARE_C1_C1_LIR_HPP diff --git a/src/hotspot/share/c1/c1_LIRAssembler.cpp b/src/hotspot/share/c1/c1_LIRAssembler.cpp index 1dc3981ceaf073f0b816a0abb702d03c203bedbe..1c4e0d09306b52906385e1f16b44be4399f8bd99 100644 --- a/src/hotspot/share/c1/c1_LIRAssembler.cpp +++ b/src/hotspot/share/c1/c1_LIRAssembler.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -32,7 +32,6 @@ #include "c1/c1_ValueStack.hpp" #include "ci/ciInstance.hpp" #include "compiler/oopMap.hpp" -#include "gc/shared/barrierSet.hpp" #include "runtime/os.hpp" #include "runtime/vm_version.hpp" @@ -43,6 +42,7 @@ void LIR_Assembler::patching_epilog(PatchingStub* patch, LIR_PatchCode patch_cod while ((intx) _masm->pc() - (intx) patch->pc_start() < NativeGeneralJump::instruction_size) { _masm->nop(); } + info->set_force_reexecute(); patch->install(_masm, patch_code, obj, info); append_code_stub(patch); @@ -75,6 +75,7 @@ void LIR_Assembler::patching_epilog(PatchingStub* patch, LIR_PatchCode patch_cod case Bytecodes::_getstatic: case Bytecodes::_ldc: case Bytecodes::_ldc_w: + case Bytecodes::_ldc2_w: break; default: ShouldNotReachHere(); @@ -102,7 +103,6 @@ PatchingStub::PatchID LIR_Assembler::patching_id(CodeEmitInfo* info) { LIR_Assembler::LIR_Assembler(Compilation* c): _masm(c->masm()) - , _bs(BarrierSet::barrier_set()) , _compilation(c) , _frame_map(c->frame_map()) , _current_block(NULL) @@ -606,7 +606,7 @@ void LIR_Assembler::emit_op0(LIR_Op0* op) { check_icache(); } offsets()->set_value(CodeOffsets::Verified_Entry, _masm->offset()); - _masm->verified_entry(); + _masm->verified_entry(compilation()->directive()->BreakAtExecuteOption); if (needs_clinit_barrier_on_entry(compilation()->method())) { clinit_barrier(compilation()->method()); } diff --git a/src/hotspot/share/c1/c1_LIRAssembler.hpp b/src/hotspot/share/c1/c1_LIRAssembler.hpp index 683e921846242bb97a488334cabdf782fe3b97b1..1d873b9638da08d1493264b3620b006468b32e2f 100644 --- a/src/hotspot/share/c1/c1_LIRAssembler.hpp +++ b/src/hotspot/share/c1/c1_LIRAssembler.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -32,13 +32,11 @@ class Compilation; class ScopeValue; -class BarrierSet; class LIR_Assembler: public CompilationResourceObj { private: C1_MacroAssembler* _masm; CodeStubList* _slow_case_stubs; - BarrierSet* _bs; Compilation* _compilation; FrameMap* _frame_map; @@ -197,6 +195,7 @@ class LIR_Assembler: public CompilationResourceObj { void emit_typecheck_helper(LIR_OpTypeCheck *op, Label* success, Label* failure, Label* obj_is_null); void emit_compare_and_swap(LIR_OpCompareAndSwap* op); void emit_lock(LIR_OpLock* op); + void emit_load_klass(LIR_OpLoadKlass* op); void emit_call(LIR_OpJavaCall* op); void emit_rtcall(LIR_OpRTCall* op); void emit_profile_call(LIR_OpProfileCall* op); diff --git a/src/hotspot/share/c1/c1_LIRGenerator.cpp b/src/hotspot/share/c1/c1_LIRGenerator.cpp index ff8f08a5bbdaac67fcf441cc5857ddf0cc14f3b9..b386b541f89c6d24b0377b9dbd05af4ade3d79ea 100644 --- a/src/hotspot/share/c1/c1_LIRGenerator.cpp +++ b/src/hotspot/share/c1/c1_LIRGenerator.cpp @@ -620,7 +620,7 @@ void LIRGenerator::monitor_exit(LIR_Opr object, LIR_Opr lock, LIR_Opr new_hdr, L // setup registers LIR_Opr hdr = lock; lock = new_hdr; - CodeStub* slow_path = new MonitorExitStub(lock, UseFastLocking, monitor_no); + CodeStub* slow_path = new MonitorExitStub(lock, !UseHeavyMonitors, monitor_no); __ load_stack_address_monitor(monitor_no, lock); __ unlock_object(hdr, object, lock, scratch, slow_path); } @@ -963,6 +963,14 @@ void LIRGenerator::move_to_phi(PhiResolver* resolver, Value cur_val, Value sux_v Phi* phi = sux_val->as_Phi(); // cur_val can be null without phi being null in conjunction with inlining if (phi != NULL && cur_val != NULL && cur_val != phi && !phi->is_illegal()) { + if (phi->is_local()) { + for (int i = 0; i < phi->operand_count(); i++) { + Value op = phi->operand_at(i); + if (op != NULL && op->type()->is_illegal()) { + bailout("illegal phi operand"); + } + } + } Phi* cur_phi = cur_val->as_Phi(); if (cur_phi != NULL && cur_phi->is_illegal()) { // Phi and local would need to get invalidated @@ -1019,12 +1027,12 @@ LIR_Opr LIRGenerator::new_register(BasicType type) { int vreg_num = _virtual_register_number; // Add a little fudge factor for the bailout since the bailout is only checked periodically. This allows us to hand out // a few extra registers before we really run out which helps to avoid to trip over assertions. - if (vreg_num + 20 >= LIR_OprDesc::vreg_max) { + if (vreg_num + 20 >= LIR_Opr::vreg_max) { bailout("out of virtual registers in LIR generator"); - if (vreg_num + 2 >= LIR_OprDesc::vreg_max) { + if (vreg_num + 2 >= LIR_Opr::vreg_max) { // Wrap it around and continue until bailout really happens to avoid hitting assertions. - _virtual_register_number = LIR_OprDesc::vreg_base; - vreg_num = LIR_OprDesc::vreg_base; + _virtual_register_number = LIR_Opr::vreg_base; + vreg_num = LIR_Opr::vreg_base; } } _virtual_register_number += 1; @@ -1231,13 +1239,17 @@ void LIRGenerator::do_isInstance(Intrinsic* x) { __ move(call_result, result); } +void LIRGenerator::load_klass(LIR_Opr obj, LIR_Opr klass, CodeEmitInfo* null_check_info) { + __ load_klass(obj, klass, null_check_info); +} + // Example: object.getClass () void LIRGenerator::do_getClass(Intrinsic* x) { assert(x->number_of_arguments() == 1, "wrong type"); LIRItem rcvr(x->argument_at(0), this); rcvr.load_item(); - LIR_Opr temp = new_register(T_METADATA); + LIR_Opr temp = new_register(T_ADDRESS); LIR_Opr result = rlock_result(x); // need to perform the null check on the rcvr @@ -1246,10 +1258,9 @@ void LIRGenerator::do_getClass(Intrinsic* x) { info = state_for(x); } - // FIXME T_ADDRESS should actually be T_METADATA but it can't because the - // meaning of these two is mixed up (see JDK-8026837). - __ move(new LIR_Address(rcvr.result(), oopDesc::klass_offset_in_bytes(), T_ADDRESS), temp, info); - __ move_wide(new LIR_Address(temp, in_bytes(Klass::java_mirror_offset()), T_ADDRESS), temp); + LIR_Opr klass = new_register(T_METADATA); + load_klass(rcvr.result(), klass, info); + __ move_wide(new LIR_Address(klass, in_bytes(Klass::java_mirror_offset()), T_ADDRESS), temp); // mirror = ((OopHandle)mirror)->resolve(); access_load(IN_NATIVE, T_OBJECT, LIR_OprFact::address(new LIR_Address(temp, T_OBJECT)), result); @@ -1322,7 +1333,7 @@ void LIRGenerator::do_getObjectSize(Intrinsic* x) { value.load_item(); LIR_Opr klass = new_register(T_METADATA); - __ move(new LIR_Address(value.result(), oopDesc::klass_offset_in_bytes(), T_ADDRESS), klass, NULL); + load_klass(value.result(), klass, NULL); LIR_Opr layout = new_register(T_INT); __ move(new LIR_Address(klass, in_bytes(Klass::layout_helper_offset()), T_INT), layout); @@ -3572,7 +3583,7 @@ LIR_Opr LIRGenerator::mask_boolean(LIR_Opr array, LIR_Opr value, CodeEmitInfo*& __ logical_and(value, LIR_OprFact::intConst(1), value_fixed); } LIR_Opr klass = new_register(T_METADATA); - __ move(new LIR_Address(array, oopDesc::klass_offset_in_bytes(), T_ADDRESS), klass, null_check_info); + load_klass(array, klass, null_check_info); null_check_info = NULL; LIR_Opr layout = new_register(T_INT); __ move(new LIR_Address(klass, in_bytes(Klass::layout_helper_offset()), T_INT), layout); diff --git a/src/hotspot/share/c1/c1_LIRGenerator.hpp b/src/hotspot/share/c1/c1_LIRGenerator.hpp index f7c47e653fda680becf926c85b58b8c95f70aecf..2c26e7714fdafc60719598c79ad2ff4fa07c34f9 100644 --- a/src/hotspot/share/c1/c1_LIRGenerator.hpp +++ b/src/hotspot/share/c1/c1_LIRGenerator.hpp @@ -239,6 +239,8 @@ class LIRGenerator: public InstructionVisitor, public BlockClosure { void move_to_phi(PhiResolver* resolver, Value cur_val, Value sux_val); void move_to_phi(ValueStack* cur_state); + void load_klass(LIR_Opr obj, LIR_Opr klass, CodeEmitInfo* null_check_info); + // platform dependent LIR_Opr getThreadPointer(); @@ -502,7 +504,7 @@ class LIRGenerator: public InstructionVisitor, public BlockClosure { LIRGenerator(Compilation* compilation, ciMethod* method) : _compilation(compilation) , _method(method) - , _virtual_register_number(LIR_OprDesc::vreg_base) + , _virtual_register_number(LIR_Opr::vreg_base) , _vreg_flags(num_vreg_flags) , _barrier_set(BarrierSet::barrier_set()->barrier_set_c1()) { } diff --git a/src/hotspot/share/c1/c1_LinearScan.cpp b/src/hotspot/share/c1/c1_LinearScan.cpp index 84846e8e43d54a7b140b8b8a6c9b7e37ae3412fd..d2386d7cbb6234a9587c432a300f397922751e42 100644 --- a/src/hotspot/share/c1/c1_LinearScan.cpp +++ b/src/hotspot/share/c1/c1_LinearScan.cpp @@ -173,7 +173,7 @@ bool LinearScan::is_precolored_interval(const Interval* i) { } bool LinearScan::is_virtual_interval(const Interval* i) { - return i->reg_num() >= LIR_OprDesc::vreg_base; + return i->reg_num() >= LIR_Opr::vreg_base; } bool LinearScan::is_precolored_cpu_interval(const Interval* i) { @@ -182,9 +182,9 @@ bool LinearScan::is_precolored_cpu_interval(const Interval* i) { bool LinearScan::is_virtual_cpu_interval(const Interval* i) { #if defined(__SOFTFP__) || defined(E500V2) - return i->reg_num() >= LIR_OprDesc::vreg_base; + return i->reg_num() >= LIR_Opr::vreg_base; #else - return i->reg_num() >= LIR_OprDesc::vreg_base && (i->type() != T_FLOAT && i->type() != T_DOUBLE); + return i->reg_num() >= LIR_Opr::vreg_base && (i->type() != T_FLOAT && i->type() != T_DOUBLE); #endif // __SOFTFP__ or E500V2 } @@ -196,7 +196,7 @@ bool LinearScan::is_virtual_fpu_interval(const Interval* i) { #if defined(__SOFTFP__) || defined(E500V2) return false; #else - return i->reg_num() >= LIR_OprDesc::vreg_base && (i->type() == T_FLOAT || i->type() == T_DOUBLE); + return i->reg_num() >= LIR_Opr::vreg_base && (i->type() == T_FLOAT || i->type() == T_DOUBLE); #endif // __SOFTFP__ or E500V2 } @@ -274,7 +274,7 @@ Interval* LinearScan::create_interval(int reg_num) { _intervals.at_put(reg_num, interval); // assign register number for precolored intervals - if (reg_num < LIR_OprDesc::vreg_base) { + if (reg_num < LIR_Opr::vreg_base) { interval->assign_reg(reg_num); } return interval; @@ -819,7 +819,7 @@ void LinearScan::compute_global_live_sets() { // (live set must be empty at fixed intervals) for (int i = 0; i < num_blocks; i++) { BlockBegin* block = block_at(i); - for (int j = 0; j < LIR_OprDesc::vreg_base; j++) { + for (int j = 0; j < LIR_Opr::vreg_base; j++) { assert(block->live_in().at(j) == false, "live_in set of fixed register must be empty"); assert(block->live_out().at(j) == false, "live_out set of fixed register must be empty"); assert(block->live_gen().at(j) == false, "live_gen set of fixed register must be empty"); @@ -1333,7 +1333,7 @@ void LinearScan::build_intervals() { int size = (int)live.size(); for (int number = (int)live.get_next_one_offset(0, size); number < size; number = (int)live.get_next_one_offset(number + 1, size)) { assert(live.at(number), "should not stop here otherwise"); - assert(number >= LIR_OprDesc::vreg_base, "fixed intervals must not be live on block bounds"); + assert(number >= LIR_Opr::vreg_base, "fixed intervals must not be live on block bounds"); TRACE_LINEAR_SCAN(2, tty->print_cr("live in %d to %d", number, block_to + 2)); add_use(number, block_from, block_to + 2, noUse, T_ILLEGAL); @@ -1706,7 +1706,7 @@ Interval* LinearScan::split_child_at_op_id(Interval* interval, int op_id, LIR_Op } assert(false, "must find an interval, but do a clean bailout in product mode"); - result = new Interval(LIR_OprDesc::vreg_base); + result = new Interval(LIR_Opr::vreg_base); result->assign_reg(0); result->set_type(T_INT); BAILOUT_("LinearScan: interval is NULL", result); @@ -2141,12 +2141,8 @@ LIR_Opr LinearScan::calc_operand_for_interval(const Interval* interval) { #ifdef _LP64 return LIR_OprFact::double_cpu(assigned_reg, assigned_reg); -#else -#if defined(PPC32) - return LIR_OprFact::double_cpu(assigned_regHi, assigned_reg); #else return LIR_OprFact::double_cpu(assigned_reg, assigned_regHi); -#endif // PPC32 #endif // LP64 } @@ -2435,7 +2431,7 @@ OopMap* LinearScan::compute_oop_map(IntervalWalker* iw, LIR_Op* op, CodeEmitInfo assert(interval->current_from() <= op->id() && op->id() <= interval->current_to(), "interval should not be active otherwise"); assert(interval->assigned_regHi() == any_reg, "oop must be single word"); - assert(interval->reg_num() >= LIR_OprDesc::vreg_base, "fixed interval found"); + assert(interval->reg_num() >= LIR_Opr::vreg_base, "fixed interval found"); // Check if this range covers the instruction. Intervals that // start or end at the current operation are not included in the @@ -2789,9 +2785,6 @@ int LinearScan::append_scope_value_for_operand(LIR_Opr opr, GrowableArrayfpu_regnrHi() == opr->fpu_regnrLo() + 1, "assumed in calculation (only fpu_regnrLo is used)"); #endif -#ifdef PPC32 - assert(opr->fpu_regnrLo() == opr->fpu_regnrHi(), "assumed in calculation (only fpu_regnrHi is used)"); -#endif #ifdef VM_LITTLE_ENDIAN VMReg rname_first = frame_map()->fpu_regname(opr->fpu_regnrLo()); @@ -3218,7 +3211,7 @@ void LinearScan::print_reg_num(outputStream* out, int reg_num) { if (reg_num == -1) { out->print("[ANY]"); return; - } else if (reg_num >= LIR_OprDesc::vreg_base) { + } else if (reg_num >= LIR_Opr::vreg_base) { out->print("[VREG %d]", reg_num); return; } @@ -3298,7 +3291,7 @@ void LinearScan::verify_intervals() { has_error = true; } - if (i1->reg_num() >= LIR_OprDesc::vreg_base && i1->type() == T_ILLEGAL) { + if (i1->reg_num() >= LIR_Opr::vreg_base && i1->type() == T_ILLEGAL) { tty->print_cr("Interval %d has no type assigned", i1->reg_num()); i1->print(); tty->cr(); has_error = true; } @@ -3969,11 +3962,11 @@ LIR_Opr MoveResolver::get_virtual_register(Interval* interval) { // Add a little fudge factor for the bailout since the bailout is only checked periodically. This allows us to hand out // a few extra registers before we really run out which helps to avoid to trip over assertions. int reg_num = interval->reg_num(); - if (reg_num + 20 >= LIR_OprDesc::vreg_max) { + if (reg_num + 20 >= LIR_Opr::vreg_max) { _allocator->bailout("out of virtual registers in linear scan"); - if (reg_num + 2 >= LIR_OprDesc::vreg_max) { + if (reg_num + 2 >= LIR_Opr::vreg_max) { // Wrap it around and continue until bailout really happens to avoid hitting assertions. - reg_num = LIR_OprDesc::vreg_base; + reg_num = LIR_Opr::vreg_base; } } LIR_Opr vreg = LIR_OprFact::virtual_register(reg_num, interval->type()); @@ -4405,7 +4398,7 @@ void Interval::add_use_pos(int pos, IntervalUseKind use_kind) { // do not add use positions for precolored intervals because // they are never used - if (use_kind != noUse && reg_num() >= LIR_OprDesc::vreg_base) { + if (use_kind != noUse && reg_num() >= LIR_Opr::vreg_base) { #ifdef ASSERT assert(_use_pos_and_kinds.length() % 2 == 0, "must be"); for (int i = 0; i < _use_pos_and_kinds.length(); i += 2) { @@ -4635,7 +4628,7 @@ void Interval::print_on(outputStream* out, bool is_cfg_printer) const { const char* UseKind2Name[] = { "N", "L", "S", "M" }; const char* type_name; - if (reg_num() < LIR_OprDesc::vreg_base) { + if (reg_num() < LIR_Opr::vreg_base) { type_name = "fixed"; } else { type_name = type2name(type()); @@ -4652,7 +4645,7 @@ void Interval::print_on(outputStream* out, bool is_cfg_printer) const { } } else { // Improved output for normal debugging. - if (reg_num() < LIR_OprDesc::vreg_base) { + if (reg_num() < LIR_Opr::vreg_base) { LinearScan::print_reg_num(out, assigned_reg()); } else if (assigned_reg() != -1 && (LinearScan::num_physical_regs(type()) == 1 || assigned_regHi() != -1)) { LinearScan::calc_operand_for_interval(this)->print(out); diff --git a/src/hotspot/share/c1/c1_LinearScan.hpp b/src/hotspot/share/c1/c1_LinearScan.hpp index 20c1a66f40febbba561c04ae2b227c1577189742..5808675a5436943da367a4306c27804994d62c0d 100644 --- a/src/hotspot/share/c1/c1_LinearScan.hpp +++ b/src/hotspot/share/c1/c1_LinearScan.hpp @@ -547,8 +547,8 @@ class Interval : public CompilationResourceObj { // accessors int reg_num() const { return _reg_num; } void set_reg_num(int r) { assert(_reg_num == -1, "cannot change reg_num"); _reg_num = r; } - BasicType type() const { assert(_reg_num == -1 || _reg_num >= LIR_OprDesc::vreg_base, "cannot access type for fixed interval"); return _type; } - void set_type(BasicType type) { assert(_reg_num < LIR_OprDesc::vreg_base || _type == T_ILLEGAL || _type == type, "overwriting existing type"); _type = type; } + BasicType type() const { assert(_reg_num == -1 || _reg_num >= LIR_Opr::vreg_base, "cannot access type for fixed interval"); return _type; } + void set_type(BasicType type) { assert(_reg_num < LIR_Opr::vreg_base || _type == T_ILLEGAL || _type == type, "overwriting existing type"); _type = type; } Range* first() const { return _first; } int from() const { return _first->from(); } diff --git a/src/hotspot/share/c1/c1_MacroAssembler.hpp b/src/hotspot/share/c1/c1_MacroAssembler.hpp index 206eda91e2abfe643ee5d8c8bd4a2b383bd61d33..6a8304bd405fac11a598bf23f21557e276887eca 100644 --- a/src/hotspot/share/c1/c1_MacroAssembler.hpp +++ b/src/hotspot/share/c1/c1_MacroAssembler.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -42,7 +42,7 @@ class C1_MacroAssembler: public MacroAssembler { void build_frame(int frame_size_in_bytes, int bang_size_in_bytes); void remove_frame(int frame_size_in_bytes); - void verified_entry(); + void verified_entry(bool breakAtEntry); void verify_stack_oop(int offset) PRODUCT_RETURN; void verify_not_null_oop(Register r) PRODUCT_RETURN; diff --git a/src/hotspot/share/c1/c1_Optimizer.cpp b/src/hotspot/share/c1/c1_Optimizer.cpp index e5c5061e334a7a21f7dc55bb36dca9d393e98021..e741cf90f9210f604c8f3335cb1e15505eed73a9 100644 --- a/src/hotspot/share/c1/c1_Optimizer.cpp +++ b/src/hotspot/share/c1/c1_Optimizer.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -180,6 +180,25 @@ void CE_Eliminator::block_do(BlockBegin* block) { return; } +#ifdef ASSERT +#define DO_DELAYED_VERIFICATION + /* + * We need to verify the internal representation after modifying it. + * Verifying only the blocks that have been tampered with is cheaper than verifying the whole graph, but we must + * capture blocks_to_verify_later before making the changes, since they might not be reachable afterwards. + * DO_DELAYED_VERIFICATION ensures that the code for this is either enabled in full, or not at all. + */ +#endif // ASSERT + +#ifdef DO_DELAYED_VERIFICATION + BlockList blocks_to_verify_later; + blocks_to_verify_later.append(block); + blocks_to_verify_later.append(t_block); + blocks_to_verify_later.append(f_block); + blocks_to_verify_later.append(sux); + _hir->expand_with_neighborhood(blocks_to_verify_later); +#endif // DO_DELAYED_VERIFICATION + // 2) substitute conditional expression // with an IfOp followed by a Goto // cut if_ away and get node before @@ -248,7 +267,10 @@ void CE_Eliminator::block_do(BlockBegin* block) { tty->print_cr("%d. IfOp in B%d", ifop_count(), block->block_id()); } - _hir->verify(); +#ifdef DO_DELAYED_VERIFICATION + _hir->verify_local(blocks_to_verify_later); +#endif // DO_DELAYED_VERIFICATION + } Value CE_Eliminator::make_ifop(Value x, Instruction::Condition cond, Value y, Value tval, Value fval) { @@ -312,6 +334,20 @@ void Optimizer::eliminate_conditional_expressions() { CE_Eliminator ce(ir()); } +// This removes others' relation to block, but doesnt empty block's lists +void disconnect_from_graph(BlockBegin* block) { + for (int p = 0; p < block->number_of_preds(); p++) { + BlockBegin* pred = block->pred_at(p); + int idx; + while ((idx = pred->end()->find_sux(block)) >= 0) { + pred->end()->remove_sux_at(idx); + } + } + for (int s = 0; s < block->number_of_sux(); s++) { + block->sux_at(s)->remove_predecessor(block); + } +} + class BlockMerger: public BlockClosure { private: IR* _hir; @@ -336,143 +372,159 @@ class BlockMerger: public BlockClosure { bool try_merge(BlockBegin* block) { BlockEnd* end = block->end(); - if (end->as_Goto() != NULL) { - assert(end->number_of_sux() == 1, "end must have exactly one successor"); - // Note: It would be sufficient to check for the number of successors (= 1) - // in order to decide if this block can be merged potentially. That - // would then also include switch statements w/ only a default case. - // However, in that case we would need to make sure the switch tag - // expression is executed if it can produce observable side effects. - // We should probably have the canonicalizer simplifying such switch - // statements and then we are sure we don't miss these merge opportunities - // here (was bug - gri 7/7/99). - BlockBegin* sux = end->default_sux(); - if (sux->number_of_preds() == 1 && !sux->is_entry_block() && !end->is_safepoint()) { - // merge the two blocks + if (end->as_Goto() == NULL) return false; + + assert(end->number_of_sux() == 1, "end must have exactly one successor"); + // Note: It would be sufficient to check for the number of successors (= 1) + // in order to decide if this block can be merged potentially. That + // would then also include switch statements w/ only a default case. + // However, in that case we would need to make sure the switch tag + // expression is executed if it can produce observable side effects. + // We should probably have the canonicalizer simplifying such switch + // statements and then we are sure we don't miss these merge opportunities + // here (was bug - gri 7/7/99). + BlockBegin* sux = end->default_sux(); + if (sux->number_of_preds() != 1 || sux->is_entry_block() || end->is_safepoint()) return false; + // merge the two blocks #ifdef ASSERT - // verify that state at the end of block and at the beginning of sux are equal - // no phi functions must be present at beginning of sux - ValueStack* sux_state = sux->state(); - ValueStack* end_state = end->state(); - - assert(end_state->scope() == sux_state->scope(), "scopes must match"); - assert(end_state->stack_size() == sux_state->stack_size(), "stack not equal"); - assert(end_state->locals_size() == sux_state->locals_size(), "locals not equal"); - - int index; - Value sux_value; - for_each_stack_value(sux_state, index, sux_value) { - assert(sux_value == end_state->stack_at(index), "stack not equal"); - } - for_each_local_value(sux_state, index, sux_value) { - Phi* sux_phi = sux_value->as_Phi(); - if (sux_phi != NULL && sux_phi->is_illegal()) continue; - assert(sux_value == end_state->local_at(index), "locals not equal"); - } - assert(sux_state->caller_state() == end_state->caller_state(), "caller not equal"); + // verify that state at the end of block and at the beginning of sux are equal + // no phi functions must be present at beginning of sux + ValueStack* sux_state = sux->state(); + ValueStack* end_state = end->state(); + + assert(end_state->scope() == sux_state->scope(), "scopes must match"); + assert(end_state->stack_size() == sux_state->stack_size(), "stack not equal"); + assert(end_state->locals_size() == sux_state->locals_size(), "locals not equal"); + + int index; + Value sux_value; + for_each_stack_value(sux_state, index, sux_value) { + assert(sux_value == end_state->stack_at(index), "stack not equal"); + } + for_each_local_value(sux_state, index, sux_value) { + Phi* sux_phi = sux_value->as_Phi(); + if (sux_phi != NULL && sux_phi->is_illegal()) continue; + assert(sux_value == end_state->local_at(index), "locals not equal"); + } + assert(sux_state->caller_state() == end_state->caller_state(), "caller not equal"); #endif - // find instruction before end & append first instruction of sux block - Instruction* prev = end->prev(); - Instruction* next = sux->next(); - assert(prev->as_BlockEnd() == NULL, "must not be a BlockEnd"); - prev->set_next(next); - prev->fixup_block_pointers(); - sux->disconnect_from_graph(); - block->set_end(sux->end()); - // add exception handlers of deleted block, if any - for (int k = 0; k < sux->number_of_exception_handlers(); k++) { - BlockBegin* xhandler = sux->exception_handler_at(k); - block->add_exception_handler(xhandler); - - // also substitute predecessor of exception handler - assert(xhandler->is_predecessor(sux), "missing predecessor"); - xhandler->remove_predecessor(sux); - if (!xhandler->is_predecessor(block)) { - xhandler->add_predecessor(block); - } - } +#ifdef DO_DELAYED_VERIFICATION + BlockList blocks_to_verify_later; + blocks_to_verify_later.append(block); + _hir->expand_with_neighborhood(blocks_to_verify_later); +#endif // DO_DELAYED_VERIFICATION + + // find instruction before end & append first instruction of sux block + Instruction* prev = end->prev(); + Instruction* next = sux->next(); + assert(prev->as_BlockEnd() == NULL, "must not be a BlockEnd"); + prev->set_next(next); + prev->fixup_block_pointers(); + + // disconnect this block from all other blocks + disconnect_from_graph(sux); +#ifdef DO_DELAYED_VERIFICATION + blocks_to_verify_later.remove(sux); // Sux is not part of graph anymore +#endif // DO_DELAYED_VERIFICATION + block->set_end(sux->end()); + + // TODO Should this be done in set_end universally? + // add exception handlers of deleted block, if any + for (int k = 0; k < sux->number_of_exception_handlers(); k++) { + BlockBegin* xhandler = sux->exception_handler_at(k); + block->add_exception_handler(xhandler); - // debugging output - _merge_count++; - if (PrintBlockElimination) { - tty->print_cr("%d. merged B%d & B%d (stack size = %d)", - _merge_count, block->block_id(), sux->block_id(), sux->state()->stack_size()); - } + // TODO This should be in disconnect from graph... + // also substitute predecessor of exception handler + assert(xhandler->is_predecessor(sux), "missing predecessor"); + xhandler->remove_predecessor(sux); + if (!xhandler->is_predecessor(block)) { + xhandler->add_predecessor(block); + } + } - _hir->verify(); - - If* if_ = block->end()->as_If(); - if (if_) { - IfOp* ifop = if_->x()->as_IfOp(); - Constant* con = if_->y()->as_Constant(); - bool swapped = false; - if (!con || !ifop) { - ifop = if_->y()->as_IfOp(); - con = if_->x()->as_Constant(); - swapped = true; + // debugging output + _merge_count++; + if (PrintBlockElimination) { + tty->print_cr("%d. merged B%d & B%d (stack size = %d)", + _merge_count, block->block_id(), sux->block_id(), sux->state()->stack_size()); + } + +#ifdef DO_DELAYED_VERIFICATION + _hir->verify_local(blocks_to_verify_later); +#endif // DO_DELAYED_VERIFICATION + + If* if_ = block->end()->as_If(); + if (if_) { + IfOp* ifop = if_->x()->as_IfOp(); + Constant* con = if_->y()->as_Constant(); + bool swapped = false; + if (!con || !ifop) { + ifop = if_->y()->as_IfOp(); + con = if_->x()->as_Constant(); + swapped = true; + } + if (con && ifop) { + Constant* tval = ifop->tval()->as_Constant(); + Constant* fval = ifop->fval()->as_Constant(); + if (tval && fval) { + // Find the instruction before if_, starting with ifop. + // When if_ and ifop are not in the same block, prev + // becomes NULL In such (rare) cases it is not + // profitable to perform the optimization. + Value prev = ifop; + while (prev != NULL && prev->next() != if_) { + prev = prev->next(); } - if (con && ifop) { - Constant* tval = ifop->tval()->as_Constant(); - Constant* fval = ifop->fval()->as_Constant(); - if (tval && fval) { - // Find the instruction before if_, starting with ifop. - // When if_ and ifop are not in the same block, prev - // becomes NULL In such (rare) cases it is not - // profitable to perform the optimization. - Value prev = ifop; - while (prev != NULL && prev->next() != if_) { - prev = prev->next(); - } - if (prev != NULL) { - Instruction::Condition cond = if_->cond(); - BlockBegin* tsux = if_->tsux(); - BlockBegin* fsux = if_->fsux(); - if (swapped) { - cond = Instruction::mirror(cond); - } - - BlockBegin* tblock = tval->compare(cond, con, tsux, fsux); - BlockBegin* fblock = fval->compare(cond, con, tsux, fsux); - if (tblock != fblock && !if_->is_safepoint()) { - If* newif = new If(ifop->x(), ifop->cond(), false, ifop->y(), - tblock, fblock, if_->state_before(), if_->is_safepoint()); - newif->set_state(if_->state()->copy()); - - assert(prev->next() == if_, "must be guaranteed by above search"); - NOT_PRODUCT(newif->set_printable_bci(if_->printable_bci())); - prev->set_next(newif); - block->set_end(newif); - - _merge_count++; - if (PrintBlockElimination) { - tty->print_cr("%d. replaced If and IfOp at end of B%d with single If", _merge_count, block->block_id()); - } - - _hir->verify(); - } + if (prev != NULL) { + Instruction::Condition cond = if_->cond(); + BlockBegin* tsux = if_->tsux(); + BlockBegin* fsux = if_->fsux(); + if (swapped) { + cond = Instruction::mirror(cond); + } + + BlockBegin* tblock = tval->compare(cond, con, tsux, fsux); + BlockBegin* fblock = fval->compare(cond, con, tsux, fsux); + if (tblock != fblock && !if_->is_safepoint()) { + If* newif = new If(ifop->x(), ifop->cond(), false, ifop->y(), + tblock, fblock, if_->state_before(), if_->is_safepoint()); + newif->set_state(if_->state()->copy()); + + assert(prev->next() == if_, "must be guaranteed by above search"); + NOT_PRODUCT(newif->set_printable_bci(if_->printable_bci())); + prev->set_next(newif); + block->set_end(newif); + + _merge_count++; + if (PrintBlockElimination) { + tty->print_cr("%d. replaced If and IfOp at end of B%d with single If", _merge_count, block->block_id()); } + +#ifdef DO_DELAYED_VERIFICATION + _hir->verify_local(blocks_to_verify_later); +#endif // DO_DELAYED_VERIFICATION } } } - - return true; } } - return false; + + return true; } virtual void block_do(BlockBegin* block) { - _hir->verify(); // repeat since the same block may merge again - while (try_merge(block)) { - _hir->verify(); - } + while (try_merge(block)) ; } }; +#ifdef ASSERT +#undef DO_DELAYED_VERIFICATION +#endif // ASSERT void Optimizer::eliminate_blocks() { // merge blocks if possible diff --git a/src/hotspot/share/c1/c1_RangeCheckElimination.cpp b/src/hotspot/share/c1/c1_RangeCheckElimination.cpp index fc5df4a420133f139b97ba55a0a7d425fb0ea59e..f5275eb9d5c5341a3ecf4ef18ec979d12d5306c8 100644 --- a/src/hotspot/share/c1/c1_RangeCheckElimination.cpp +++ b/src/hotspot/share/c1/c1_RangeCheckElimination.cpp @@ -365,7 +365,12 @@ void RangeCheckEliminator::update_bound(IntegerStack &pushed, Value v, Instructi bool RangeCheckEliminator::loop_invariant(BlockBegin *loop_header, Instruction *instruction) { assert(loop_header, "Loop header must not be null!"); if (!instruction) return true; - return instruction->dominator_depth() < loop_header->dominator_depth(); + for (BlockBegin *d = loop_header->dominator(); d != NULL; d = d->dominator()) { + if (d == instruction->block()) { + return true; + } + } + return false; } // Update bound. Pushes a new bound onto the stack. Tries to do a conjunction with the current bound. diff --git a/src/hotspot/share/c1/c1_Runtime1.cpp b/src/hotspot/share/c1/c1_Runtime1.cpp index 072b3d3900a72b4b55252d782ccebf2a0c00697f..03cb4a961f40f6190b6c9ab9d640fc58afdf6317 100644 --- a/src/hotspot/share/c1/c1_Runtime1.cpp +++ b/src/hotspot/share/c1/c1_Runtime1.cpp @@ -243,9 +243,6 @@ void Runtime1::generate_blob_for(BufferBlob* buffer_blob, StubID id) { case fpu2long_stub_id: case unwind_exception_id: case counter_overflow_id: -#if defined(PPC32) - case handle_exception_nofpu_id: -#endif expect_oop_map = false; break; default: @@ -739,7 +736,7 @@ JRT_BLOCK_ENTRY(void, Runtime1::monitorenter(JavaThread* current, oopDesc* obj, _monitorenter_slowcase_cnt++; } #endif - if (!UseFastLocking) { + if (UseHeavyMonitors) { lock->set_obj(obj); } assert(obj == lock->obj(), "must match"); @@ -1012,6 +1009,7 @@ JRT_ENTRY(void, Runtime1::patch_code(JavaThread* current, Runtime1::StubID stub_ break; case Bytecodes::_ldc: case Bytecodes::_ldc_w: + case Bytecodes::_ldc2_w: { Bytecode_loadconstant cc(caller_method, bci); oop m = cc.resolve_constant(CHECK); @@ -1156,7 +1154,6 @@ JRT_ENTRY(void, Runtime1::patch_code(JavaThread* current, Runtime1::StubID stub_ assert(load_klass != NULL, "klass not set"); n_copy->set_data((intx) (load_klass)); } else { - assert(mirror() != NULL, "klass not set"); // Don't need a G1 pre-barrier here since we assert above that data isn't an oop. n_copy->set_data(cast_from_oop(mirror())); } @@ -1179,40 +1176,6 @@ JRT_ENTRY(void, Runtime1::patch_code(JavaThread* current, Runtime1::StubID stub_ ShouldNotReachHere(); } -#if defined(PPC32) - if (load_klass_or_mirror_patch_id || - stub_id == Runtime1::load_appendix_patching_id) { - // Update the location in the nmethod with the proper - // metadata. When the code was generated, a NULL was stuffed - // in the metadata table and that table needs to be update to - // have the right value. On intel the value is kept - // directly in the instruction instead of in the metadata - // table, so set_data above effectively updated the value. - nmethod* nm = CodeCache::find_nmethod(instr_pc); - assert(nm != NULL, "invalid nmethod_pc"); - RelocIterator mds(nm, copy_buff, copy_buff + 1); - bool found = false; - while (mds.next() && !found) { - if (mds.type() == relocInfo::oop_type) { - assert(stub_id == Runtime1::load_mirror_patching_id || - stub_id == Runtime1::load_appendix_patching_id, "wrong stub id"); - oop_Relocation* r = mds.oop_reloc(); - oop* oop_adr = r->oop_addr(); - *oop_adr = stub_id == Runtime1::load_mirror_patching_id ? mirror() : appendix(); - r->fix_oop_relocation(); - found = true; - } else if (mds.type() == relocInfo::metadata_type) { - assert(stub_id == Runtime1::load_klass_patching_id, "wrong stub id"); - metadata_Relocation* r = mds.metadata_reloc(); - Metadata** metadata_adr = r->metadata_addr(); - *metadata_adr = load_klass; - r->fix_metadata_relocation(); - found = true; - } - } - assert(found, "the metadata must exist!"); - } -#endif if (do_patch) { // replace instructions // first replace the tail, then the call @@ -1270,13 +1233,6 @@ JRT_ENTRY(void, Runtime1::patch_code(JavaThread* current, Runtime1::StubID stub_ RelocIterator iter(nm, (address)instr_pc, (address)(instr_pc + 1)); relocInfo::change_reloc_info_for_address(&iter, (address) instr_pc, relocInfo::none, rtype); -#ifdef PPC32 - { address instr_pc2 = instr_pc + NativeMovConstReg::lo_offset; - RelocIterator iter2(nm, instr_pc2, instr_pc2 + 1); - relocInfo::change_reloc_info_for_address(&iter2, (address) instr_pc2, - relocInfo::none, rtype); - } -#endif } } else { diff --git a/src/hotspot/share/c1/c1_Runtime1.hpp b/src/hotspot/share/c1/c1_Runtime1.hpp index 9212a4fb2498eac533e638611a185e33aa670151..3dcb27476a6f9b8d342461d2032248d94ab9c8fe 100644 --- a/src/hotspot/share/c1/c1_Runtime1.hpp +++ b/src/hotspot/share/c1/c1_Runtime1.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -28,7 +28,7 @@ #include "c1/c1_FrameMap.hpp" #include "code/stubs.hpp" #include "interpreter/interpreter.hpp" -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" #include "runtime/deoptimization.hpp" class StubAssembler; diff --git a/src/hotspot/share/c1/c1_ValueMap.cpp b/src/hotspot/share/c1/c1_ValueMap.cpp index f1961663179b547211a2b6389a36f7fe826d1624..2e2f883bae5a9b5491ddc6dde3bccbad2819ddaf 100644 --- a/src/hotspot/share/c1/c1_ValueMap.cpp +++ b/src/hotspot/share/c1/c1_ValueMap.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -505,7 +505,7 @@ GlobalValueNumbering::GlobalValueNumbering(IR* ir) assert(start_block == ir->start() && start_block->number_of_preds() == 0 && start_block->dominator() == NULL, "must be start block"); assert(start_block->next()->as_Base() != NULL && start_block->next()->next() == NULL, "start block must not have instructions"); - // method parameters are not linked in instructions list, so process them separateley + // method parameters are not linked in instructions list, so process them separately for_each_state_value(start_block->state(), value, assert(value->as_Local() != NULL, "only method parameters allowed"); set_processed(value); diff --git a/src/hotspot/share/c1/c1_ValueMap.hpp b/src/hotspot/share/c1/c1_ValueMap.hpp index 00034c24ed16aa5c2886d6a596ca0866c873a95a..303ebba6c9d8a1bd5e0aec75ecc691fab9aa3d75 100644 --- a/src/hotspot/share/c1/c1_ValueMap.hpp +++ b/src/hotspot/share/c1/c1_ValueMap.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -116,7 +116,6 @@ class ValueMap: public CompilationResourceObj { void kill_memory(); void kill_field(ciField* field, bool all_offsets); void kill_array(ValueType* type); - void kill_exception(); void kill_map(ValueMap* map); void kill_all(); @@ -165,7 +164,12 @@ class ValueNumberingVisitor: public InstructionVisitor { void do_Phi (Phi* x) { /* nothing to do */ } void do_Local (Local* x) { /* nothing to do */ } - void do_Constant (Constant* x) { /* nothing to do */ } + void do_Constant (Constant* x) { + if (x->kills_memory()) { + assert(x->can_trap(), "already linked"); + kill_memory(); + } + } void do_LoadField (LoadField* x) { if (x->is_init_point() || // getstatic is an initialization point so treat it as a wide kill x->field()->is_volatile()) { // the JMM requires this diff --git a/src/hotspot/share/c1/c1_globals.hpp b/src/hotspot/share/c1/c1_globals.hpp index 2b5de079a0c9410e490dafb9d2bb9d60ad21c056..e90aaf6536d4470fb51b6422454ebcc51f03f1be 100644 --- a/src/hotspot/share/c1/c1_globals.hpp +++ b/src/hotspot/share/c1/c1_globals.hpp @@ -242,9 +242,6 @@ develop(bool, UseFastNewObjectArray, true, \ "Use fast inlined object array allocation") \ \ - develop(bool, UseFastLocking, true, \ - "Use fast inlined locking code") \ - \ develop(bool, UseSlowPath, false, \ "For debugging: test slow cases by always using them") \ \ diff --git a/src/hotspot/share/cds/archiveBuilder.cpp b/src/hotspot/share/cds/archiveBuilder.cpp index cb5c0aeb8c78008f044e0d009bddbd102fa38bbb..89529b2cf595de49207ec999afc316bdd68b2e3f 100644 --- a/src/hotspot/share/cds/archiveBuilder.cpp +++ b/src/hotspot/share/cds/archiveBuilder.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -522,7 +522,8 @@ ArchiveBuilder::FollowMode ArchiveBuilder::get_follow_mode(MetaspaceClosure::Ref if (MetaspaceShared::is_in_shared_metaspace(obj)) { // Don't dump existing shared metadata again. return point_to_it; - } else if (ref->msotype() == MetaspaceObj::MethodDataType) { + } else if (ref->msotype() == MetaspaceObj::MethodDataType || + ref->msotype() == MetaspaceObj::MethodCountersType) { return set_to_null; } else { if (ref->msotype() == MetaspaceObj::ClassType) { diff --git a/src/hotspot/share/cds/archiveBuilder.hpp b/src/hotspot/share/cds/archiveBuilder.hpp index 1057d05b0836647cd1410df9996efc95d233e6fa..484f7271a7c70b271c1214a680c58fcdae4504ab 100644 --- a/src/hotspot/share/cds/archiveBuilder.hpp +++ b/src/hotspot/share/cds/archiveBuilder.hpp @@ -312,14 +312,14 @@ public: template u4 buffer_to_offset_u4(T p) const { uintx offset = buffer_to_offset((address)p); - guarantee(offset <= MAX_SHARED_DELTA, "must be 32-bit offset"); + guarantee(offset <= MAX_SHARED_DELTA, "must be 32-bit offset " INTPTR_FORMAT, offset); return (u4)offset; } template u4 any_to_offset_u4(T p) const { uintx offset = any_to_offset((address)p); - guarantee(offset <= MAX_SHARED_DELTA, "must be 32-bit offset"); + guarantee(offset <= MAX_SHARED_DELTA, "must be 32-bit offset " INTPTR_FORMAT, offset); return (u4)offset; } diff --git a/src/hotspot/share/cds/archiveUtils.cpp b/src/hotspot/share/cds/archiveUtils.cpp index 8c273c06a8d0b431a9591420c0577bb18808a371..073c5f829d2f8743137018c2395b6c92c3121dba 100644 --- a/src/hotspot/share/cds/archiveUtils.cpp +++ b/src/hotspot/share/cds/archiveUtils.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -39,7 +39,9 @@ #include "oops/compressedOops.inline.hpp" #include "runtime/arguments.hpp" #include "utilities/bitMap.inline.hpp" +#include "utilities/debug.hpp" #include "utilities/formatBuffer.hpp" +#include "utilities/globalDefinitions.hpp" CHeapBitMap* ArchivePtrMarker::_ptrmap = NULL; VirtualSpace* ArchivePtrMarker::_vs; @@ -264,7 +266,7 @@ void WriteClosure::do_oop(oop* o) { } else { assert(HeapShared::can_write(), "sanity"); _dump_region->append_intptr_t( - (intptr_t)CompressedOops::encode_not_null(*o)); + UseCompressedOops ? (intptr_t)CompressedOops::encode_not_null(*o) : (intptr_t)((void*)(*o))); } } @@ -306,13 +308,23 @@ void ReadClosure::do_tag(int tag) { } void ReadClosure::do_oop(oop *p) { - narrowOop o = CompressedOops::narrow_oop_cast(nextPtr()); - if (CompressedOops::is_null(o) || !HeapShared::is_fully_available()) { - *p = NULL; + if (UseCompressedOops) { + narrowOop o = CompressedOops::narrow_oop_cast(nextPtr()); + if (CompressedOops::is_null(o) || !HeapShared::is_fully_available()) { + *p = NULL; + } else { + assert(HeapShared::can_use(), "sanity"); + assert(HeapShared::is_fully_available(), "must be"); + *p = HeapShared::decode_from_archive(o); + } } else { - assert(HeapShared::can_use(), "sanity"); - assert(HeapShared::is_fully_available(), "must be"); - *p = HeapShared::decode_from_archive(o); + intptr_t dumptime_oop = nextPtr(); + if (dumptime_oop == 0 || !HeapShared::is_fully_available()) { + *p = NULL; + } else { + intptr_t runtime_oop = dumptime_oop + HeapShared::runtime_delta(); + *p = cast_to_oop(runtime_oop); + } } } diff --git a/src/hotspot/share/cds/archiveUtils.hpp b/src/hotspot/share/cds/archiveUtils.hpp index 588ad1b6da921152f1caaf4827504286d2e969ba..be8d8a0e84ed5add863781a91217db12e9fce2ee 100644 --- a/src/hotspot/share/cds/archiveUtils.hpp +++ b/src/hotspot/share/cds/archiveUtils.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -30,6 +30,7 @@ #include "memory/virtualspace.hpp" #include "utilities/bitMap.hpp" #include "utilities/exceptions.hpp" +#include "utilities/macros.hpp" class BootstrapInfo; class ReservedSpace; @@ -147,7 +148,7 @@ public: char* expand_top_to(char* newtop); char* allocate(size_t num_bytes); - void append_intptr_t(intptr_t n, bool need_to_mark = false); + void append_intptr_t(intptr_t n, bool need_to_mark = false) NOT_CDS_RETURN; char* base() const { return _base; } char* top() const { return _top; } diff --git a/src/hotspot/share/cds/cdsHeapVerifier.cpp b/src/hotspot/share/cds/cdsHeapVerifier.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1eff911690110f9d8e0f1a59ab9f1fce92b82c9c --- /dev/null +++ b/src/hotspot/share/cds/cdsHeapVerifier.cpp @@ -0,0 +1,305 @@ +/* + * 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 "cds/archiveBuilder.hpp" +#include "cds/cdsHeapVerifier.hpp" +#include "classfile/classLoaderDataGraph.hpp" +#include "classfile/javaClasses.inline.hpp" +#include "logging/log.hpp" +#include "logging/logStream.hpp" +#include "memory/resourceArea.hpp" +#include "oops/fieldStreams.inline.hpp" +#include "oops/klass.inline.hpp" +#include "oops/oop.inline.hpp" +#include "runtime/fieldDescriptor.inline.hpp" + +#if INCLUDE_CDS_JAVA_HEAP + +// CDSHeapVerifier is used to check for problems where an archived object references a +// static field that may be reinitialized at runtime. In the following example, +// Foo.get.test() +// correctly returns true when CDS disabled, but incorrectly returns false when CDS is enabled. +// +// class Foo { +// final Foo archivedFoo; // this field is archived by CDS +// Bar bar; +// static { +// CDS.initializeFromArchive(Foo.class); +// if (archivedFoo == null) { +// archivedFoo = new Foo(); +// archivedFoo.bar = Bar.bar; +// } +// } +// static Foo get() { return archivedFoo; } +// boolean test() { +// return bar == Bar.bar; +// } +// } +// +// class Bar { +// // this field is initialized in both CDS dump time and runtime. +// static final Bar bar = new Bar(); +// } +// +// The check itself is simple: +// [1] CDSHeapVerifier::do_klass() collects all static fields +// [2] CDSHeapVerifier::do_entry() checks all the archived objects. None of them +// should be in [1] +// +// However, it's legal for *some* static fields to be references. This leads to the +// table of ADD_EXCL below. +// +// [A] In most of the cases, the module bootstrap code will update the static field +// to point to part of the archived module graph. E.g., +// - java/lang/System::bootLayer +// - jdk/internal/loader/ClassLoaders::BOOT_LOADER +// [B] A final static String that's explicitly initialized inside , but +// its value is deterministic and is always the same string literal. +// [C] A non-final static string that is assigned a string literal during class +// initialization; this string is never changed during -Xshare:dump. +// [D] Simple caches whose value doesn't matter. +// [E] Other cases (see comments in-line below). + +CDSHeapVerifier::CDSHeapVerifier() : _archived_objs(0), _problems(0) +{ +# define ADD_EXCL(...) { static const char* e[] = {__VA_ARGS__, NULL}; add_exclusion(e); } + + // Unfortunately this needs to be manually maintained. If + // test/hotspot/jtreg/runtime/cds/appcds/cacheObject/ArchivedEnumTest.java fails, + // you might need to fix the core library code, or fix the ADD_EXCL entries below. + // + // class field type + ADD_EXCL("java/lang/ClassLoader", "scl"); // A + ADD_EXCL("java/lang/invoke/InvokerBytecodeGenerator", "DONTINLINE_SIG", // B + "FORCEINLINE_SIG", // B + "HIDDEN_SIG", // B + "INJECTEDPROFILE_SIG", // B + "LF_COMPILED_SIG"); // B + ADD_EXCL("java/lang/Module", "ALL_UNNAMED_MODULE", // A + "ALL_UNNAMED_MODULE_SET", // A + "EVERYONE_MODULE", // A + "EVERYONE_SET"); // A + ADD_EXCL("java/lang/System", "bootLayer"); // A + ADD_EXCL("java/lang/VersionProps", "VENDOR_URL_BUG", // C + "VENDOR_URL_VM_BUG", // C + "VENDOR_VERSION"); // C + ADD_EXCL("java/net/URL$DefaultFactory", "PREFIX"); // B FIXME: JDK-8276561 + + // A dummy object used by HashSet. The value doesn't matter and it's never + // tested for equality. + ADD_EXCL("java/util/HashSet", "PRESENT"); // E + ADD_EXCL("jdk/internal/loader/BuiltinClassLoader", "packageToModule"); // A + ADD_EXCL("jdk/internal/loader/ClassLoaders", "BOOT_LOADER", // A + "APP_LOADER", // A + "PLATFORM_LOADER"); // A + ADD_EXCL("jdk/internal/loader/URLClassPath", "JAVA_VERSION"); // B + ADD_EXCL("jdk/internal/module/Builder", "cachedVersion"); // D + ADD_EXCL("jdk/internal/module/ModuleLoaderMap$Mapper", "APP_CLASSLOADER", // A + "APP_LOADER_INDEX", // A + "PLATFORM_CLASSLOADER", // A + "PLATFORM_LOADER_INDEX"); // A + ADD_EXCL("jdk/internal/module/ServicesCatalog", "CLV"); // A + + // This just points to an empty Map + ADD_EXCL("jdk/internal/reflect/Reflection", "methodFilterMap"); // E + ADD_EXCL("jdk/internal/util/StaticProperty", "FILE_ENCODING"); // C + + // Integer for 0 and 1 are in java/lang/Integer$IntegerCache and are archived + ADD_EXCL("sun/invoke/util/ValueConversions", "ONE_INT", // E + "ZERO_INT"); // E + ADD_EXCL("sun/security/util/SecurityConstants", "PROVIDER_VER"); // C + + +# undef ADD_EXCL + + ClassLoaderDataGraph::classes_do(this); +} + +CDSHeapVerifier::~CDSHeapVerifier() { + if (_problems > 0) { + log_warning(cds, heap)("Scanned %d objects. Found %d case(s) where " + "an object points to a static field that may be " + "reinitialized at runtime.", _archived_objs, _problems); + } +} + +class CDSHeapVerifier::CheckStaticFields : public FieldClosure { + CDSHeapVerifier* _verifier; + InstanceKlass* _ik; + const char** _exclusions; +public: + CheckStaticFields(CDSHeapVerifier* verifier, InstanceKlass* ik) + : _verifier(verifier), _ik(ik) { + _exclusions = _verifier->find_exclusion(_ik); + } + + void do_field(fieldDescriptor* fd) { + if (fd->field_type() != T_OBJECT) { + return; + } + + oop static_obj_field = _ik->java_mirror()->obj_field(fd->offset()); + if (static_obj_field != NULL) { + Klass* klass = static_obj_field->klass(); + if (_exclusions != NULL) { + for (const char** p = _exclusions; *p != NULL; p++) { + if (fd->name()->equals(*p)) { + return; + } + } + } + + if (fd->is_final() && java_lang_String::is_instance(static_obj_field) && fd->has_initial_value()) { + // This field looks like like this in the Java source: + // static final SOME_STRING = "a string literal"; + // This string literal has been stored in the shared string table, so it's OK + // for the archived objects to refer to it. + return; + } + if (fd->is_final() && java_lang_Class::is_instance(static_obj_field)) { + // This field points to an archived mirror. + return; + } + if (klass->has_archived_enum_objs()) { + // This klass is a subclass of java.lang.Enum. If any instance of this klass + // has been archived, we will archive all static fields of this klass. + // See HeapShared::initialize_enum_klass(). + return; + } + + // This field *may* be initialized to a different value at runtime. Remember it + // and check later if it appears in the archived object graph. + _verifier->add_static_obj_field(_ik, static_obj_field, fd->name()); + } + } +}; + +// Remember all the static object fields of every class that are currently +// loaded. +void CDSHeapVerifier::do_klass(Klass* k) { + if (k->is_instance_klass()) { + InstanceKlass* ik = InstanceKlass::cast(k); + + if (HeapShared::is_subgraph_root_class(ik)) { + // ik is inside one of the ArchivableStaticFieldInfo tables + // in heapShared.cpp. We assume such classes are programmed to + // update their static fields correctly at runtime. + return; + } + + CheckStaticFields csf(this, ik); + ik->do_local_static_fields(&csf); + } +} + +void CDSHeapVerifier::add_static_obj_field(InstanceKlass* ik, oop field, Symbol* name) { + StaticFieldInfo info = {ik, name}; + _table.put(field, info); +} + +inline bool CDSHeapVerifier::do_entry(oop& orig_obj, HeapShared::CachedOopInfo& value) { + _archived_objs++; + + StaticFieldInfo* info = _table.get(orig_obj); + if (info != NULL) { + ResourceMark rm; + LogStream ls(Log(cds, heap)::warning()); + ls.print_cr("Archive heap points to a static field that may be reinitialized at runtime:"); + ls.print_cr("Field: %s::%s", info->_holder->name()->as_C_string(), info->_name->as_C_string()); + ls.print("Value: "); + orig_obj->print_on(&ls); + ls.print_cr("--- trace begin ---"); + trace_to_root(orig_obj, NULL, &value); + ls.print_cr("--- trace end ---"); + ls.cr(); + _problems ++; + } + + return true; /* keep on iterating */ +} + +class CDSHeapVerifier::TraceFields : public FieldClosure { + oop _orig_obj; + oop _orig_field; + LogStream* _ls; + +public: + TraceFields(oop orig_obj, oop orig_field, LogStream* ls) + : _orig_obj(orig_obj), _orig_field(orig_field), _ls(ls) {} + + void do_field(fieldDescriptor* fd) { + if (fd->field_type() == T_OBJECT || fd->field_type() == T_ARRAY) { + oop obj_field = _orig_obj->obj_field(fd->offset()); + if (obj_field == _orig_field) { + _ls->print("::%s (offset = %d)", fd->name()->as_C_string(), fd->offset()); + } + } + } +}; + +// Hint: to exercise this function, uncomment out one of the ADD_EXCL lines above. +int CDSHeapVerifier::trace_to_root(oop orig_obj, oop orig_field, HeapShared::CachedOopInfo* p) { + int level = 0; + LogStream ls(Log(cds, heap)::warning()); + if (p->_referrer != NULL) { + HeapShared::CachedOopInfo* ref = HeapShared::archived_object_cache()->get(p->_referrer); + assert(ref != NULL, "sanity"); + level = trace_to_root(p->_referrer, orig_obj, ref) + 1; + } else if (java_lang_String::is_instance(orig_obj)) { + ls.print_cr("[%2d] (shared string table)", level++); + } + Klass* k = orig_obj->klass(); + ResourceMark rm; + ls.print("[%2d] ", level); + orig_obj->print_address_on(&ls); + ls.print(" %s", k->internal_name()); + if (orig_field != NULL) { + if (k->is_instance_klass()) { + TraceFields clo(orig_obj, orig_field, &ls);; + InstanceKlass::cast(k)->do_nonstatic_fields(&clo); + } else { + assert(orig_obj->is_objArray(), "must be"); + objArrayOop array = (objArrayOop)orig_obj; + for (int i = 0; i < array->length(); i++) { + if (array->obj_at(i) == orig_field) { + ls.print(" @[%d]", i); + break; + } + } + } + } + ls.cr(); + + return level; +} + +#ifdef ASSERT +void CDSHeapVerifier::verify() { + CDSHeapVerifier verf; + HeapShared::archived_object_cache()->iterate(&verf); +} +#endif + +#endif // INCLUDE_CDS_JAVA_HEAP diff --git a/src/hotspot/share/cds/cdsHeapVerifier.hpp b/src/hotspot/share/cds/cdsHeapVerifier.hpp new file mode 100644 index 0000000000000000000000000000000000000000..830e41ae03db77b1e1d4472c778b7125801308d3 --- /dev/null +++ b/src/hotspot/share/cds/cdsHeapVerifier.hpp @@ -0,0 +1,89 @@ +/* + * 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 SHARED_CDS_CDSHEAPVERIFIER_HPP +#define SHARED_CDS_CDSHEAPVERIFIER_HPP + +#include "cds/heapShared.hpp" +#include "memory/iterator.hpp" +#include "utilities/growableArray.hpp" +#include "utilities/resourceHash.hpp" + +class InstanceKlass; +class Symbol; + +#if INCLUDE_CDS_JAVA_HEAP + +class CDSHeapVerifier : public KlassClosure { + class CheckStaticFields; + class TraceFields; + + int _archived_objs; + int _problems; + + struct StaticFieldInfo { + InstanceKlass* _holder; + Symbol* _name; + }; + + ResourceHashtable _table; + + GrowableArray _exclusions; + + void add_exclusion(const char** excl) { + _exclusions.append(excl); + } + void add_static_obj_field(InstanceKlass* ik, oop field, Symbol* name); + + const char** find_exclusion(InstanceKlass* ik) { + for (int i = 0; i < _exclusions.length(); i++) { + const char** excl = _exclusions.at(i); + if (ik->name()->equals(excl[0])) { + return &excl[1]; + } + } + return NULL; + } + int trace_to_root(oop orig_obj, oop orig_field, HeapShared::CachedOopInfo* p); + + CDSHeapVerifier(); + ~CDSHeapVerifier(); + +public: + + // Overrides KlassClosure::do_klass() + virtual void do_klass(Klass* k); + + // For ResourceHashtable::iterate() + inline bool do_entry(oop& orig_obj, HeapShared::CachedOopInfo& value); + + static void verify() NOT_DEBUG_RETURN; +}; + +#endif // INCLUDE_CDS_JAVA_HEAP +#endif // SHARED_CDS_CDSHEAPVERIFIER_HPP diff --git a/src/hotspot/share/cds/classListParser.cpp b/src/hotspot/share/cds/classListParser.cpp index 66e346b19442470807b7906255213f2267248a5b..1da5e79377bf01d25d266ba7d337f43aa3935ff5 100644 --- a/src/hotspot/share/cds/classListParser.cpp +++ b/src/hotspot/share/cds/classListParser.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -64,7 +64,7 @@ ClassListParser::ClassListParser(const char* file) : _id2klass_table(INITIAL_TAB if (fd != -1) { // Obtain a File* from the file descriptor so that fgets() // can be used in parse_one_line() - _file = os::open(fd, "r"); + _file = os::fdopen(fd, "r"); } if (_file == NULL) { char errmsg[JVM_MAXPATHLEN]; diff --git a/src/hotspot/share/cds/classListWriter.cpp b/src/hotspot/share/cds/classListWriter.cpp index 6750a5d4cac09c113ae466ff631929b29149afbc..2ff647559c35a37645a2bc86af47fd2239ee4d38 100644 --- a/src/hotspot/share/cds/classListWriter.cpp +++ b/src/hotspot/share/cds/classListWriter.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -59,11 +59,6 @@ void ClassListWriter::write(const InstanceKlass* k, const ClassFileStream* cfs) return; } - // filter out java/lang/invoke/BoundMethodHandle$Species.... - if (cfs != NULL && strcmp(cfs->source(), "_ClassSpecializer_generateConcreteSpeciesCode") == 0) { - return; - } - ClassListWriter w; write_to_stream(k, w.stream(), cfs); } @@ -107,10 +102,21 @@ void ClassListWriter::handle_class_unloading(const InstanceKlass* klass) { void ClassListWriter::write_to_stream(const InstanceKlass* k, outputStream* stream, const ClassFileStream* cfs) { assert_locked(); - ClassLoaderData* loader_data = k->class_loader_data(); - if (!SystemDictionaryShared::is_builtin_loader(loader_data)) { - if (cfs == NULL || strncmp(cfs->source(), "file:", 5) != 0) { + ClassLoaderData* loader_data = k->class_loader_data(); + bool is_builtin_loader = SystemDictionaryShared::is_builtin_loader(loader_data); + if (!is_builtin_loader) { + // class may be loaded from shared archive + if (!k->is_shared()) { + if (cfs == nullptr || cfs->source() == nullptr) { + // CDS static dump only handles unregistered class with known source. + return; + } + if (strncmp(cfs->source(), "file:", 5) != 0) { + return; + } + } else { + // Shared unregistered classes are skipped since their real source are not recorded in shared space. return; } if (!SystemDictionaryShared::add_unregistered_class(Thread::current(), (InstanceKlass*)k)) { @@ -118,6 +124,10 @@ void ClassListWriter::write_to_stream(const InstanceKlass* k, outputStream* stre } } + // filter out java/lang/invoke/BoundMethodHandle$Species... + if (cfs != nullptr && cfs->source() != nullptr && strcmp(cfs->source(), "_ClassSpecializer_generateConcreteSpeciesCode") == 0) { + return; + } { InstanceKlass* super = k->java_super(); @@ -145,7 +155,7 @@ void ClassListWriter::write_to_stream(const InstanceKlass* k, outputStream* stre ResourceMark rm; stream->print("%s id: %d", k->name()->as_C_string(), get_id(k)); - if (!SystemDictionaryShared::is_builtin_loader(loader_data)) { + if (!is_builtin_loader) { InstanceKlass* super = k->java_super(); assert(super != NULL, "must be"); stream->print(" super: %d", get_id(super)); diff --git a/src/hotspot/share/cds/dumpTimeClassInfo.cpp b/src/hotspot/share/cds/dumpTimeClassInfo.cpp index 5a9028d32255a740a74cf32f7795f10923a6e633..ac35e6583b4c4cfb2295b3c9fa7066f17dfe6d20 100644 --- a/src/hotspot/share/cds/dumpTimeClassInfo.cpp +++ b/src/hotspot/share/cds/dumpTimeClassInfo.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -24,7 +24,8 @@ #include "precompiled.hpp" #include "cds/archiveBuilder.hpp" -#include "cds/dumpTimeClassInfo.hpp" +#include "cds/dumpTimeClassInfo.inline.hpp" +#include "cds/runTimeClassInfo.hpp" #include "classfile/classLoader.hpp" #include "classfile/classLoaderData.inline.hpp" #include "classfile/systemDictionaryShared.hpp" @@ -45,6 +46,7 @@ DumpTimeClassInfo DumpTimeClassInfo::clone() { clone._verifier_constraints = NULL; clone._verifier_constraint_flags = NULL; clone._loader_constraints = NULL; + clone._enum_klass_static_fields = NULL; int clone_num_verifier_constraints = num_verifier_constraints(); if (clone_num_verifier_constraints > 0) { clone._verifier_constraints = new (ResourceObj::C_HEAP, mtClass) GrowableArray(clone_num_verifier_constraints, mtClass); @@ -61,9 +63,16 @@ DumpTimeClassInfo DumpTimeClassInfo::clone() { clone._loader_constraints->append(_loader_constraints->at(i)); } } + assert(_enum_klass_static_fields == NULL, "This should not happen with jcmd VM.cds dumping"); return clone; } +size_t DumpTimeClassInfo::runtime_info_bytesize() const { + return RunTimeClassInfo::byte_size(_klass, num_verifier_constraints(), + num_loader_constraints(), + num_enum_klass_static_fields()); +} + void DumpTimeClassInfo::add_verification_constraint(InstanceKlass* k, Symbol* name, Symbol* from_name, bool from_field_is_protected, bool from_is_array, bool from_is_object) { if (_verifier_constraints == NULL) { @@ -144,6 +153,18 @@ void DumpTimeClassInfo::record_linking_constraint(Symbol* name, Handle loader1, } } +void DumpTimeClassInfo::add_enum_klass_static_field(int archived_heap_root_index) { + if (_enum_klass_static_fields == NULL) { + _enum_klass_static_fields = new (ResourceObj::C_HEAP, mtClass) GrowableArray(20, mtClass); + } + _enum_klass_static_fields->append(archived_heap_root_index); +} + +int DumpTimeClassInfo::enum_klass_static_field(int which_field) { + assert(_enum_klass_static_fields != NULL, "must be"); + return _enum_klass_static_fields->at(which_field); +} + bool DumpTimeClassInfo::is_builtin() { return SystemDictionaryShared::is_builtin(_klass); } diff --git a/src/hotspot/share/cds/dumpTimeClassInfo.hpp b/src/hotspot/share/cds/dumpTimeClassInfo.hpp index 722849954fa47868728e665225cf91e3914759d0..5b4f5cd9b9beb1f494c5a2a68b8fba2aae757657 100644 --- a/src/hotspot/share/cds/dumpTimeClassInfo.hpp +++ b/src/hotspot/share/cds/dumpTimeClassInfo.hpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -77,6 +77,7 @@ public: GrowableArray* _verifier_constraints; GrowableArray* _verifier_constraint_flags; GrowableArray* _loader_constraints; + GrowableArray* _enum_klass_static_fields; DumpTimeClassInfo() { _klass = NULL; @@ -92,28 +93,38 @@ public: _verifier_constraints = NULL; _verifier_constraint_flags = NULL; _loader_constraints = NULL; + _enum_klass_static_fields = NULL; } void add_verification_constraint(InstanceKlass* k, Symbol* name, Symbol* from_name, bool from_field_is_protected, bool from_is_array, bool from_is_object); void record_linking_constraint(Symbol* name, Handle loader1, Handle loader2); - + void add_enum_klass_static_field(int archived_heap_root_index); + int enum_klass_static_field(int which_field); bool is_builtin(); - int num_verifier_constraints() { - if (_verifier_constraint_flags != NULL) { - return _verifier_constraint_flags->length(); - } else { +private: + template + static int array_length_or_zero(GrowableArray* array) { + if (array == NULL) { return 0; + } else { + return array->length(); } } - int num_loader_constraints() { - if (_loader_constraints != NULL) { - return _loader_constraints->length(); - } else { - return 0; - } +public: + + int num_verifier_constraints() const { + return array_length_or_zero(_verifier_constraint_flags); + } + + int num_loader_constraints() const { + return array_length_or_zero(_loader_constraints); + } + + int num_enum_klass_static_fields() const { + return array_length_or_zero(_enum_klass_static_fields); } void metaspace_pointers_do(MetaspaceClosure* it) { @@ -135,8 +146,7 @@ public: } bool is_excluded() { - // _klass may become NULL due to DynamicArchiveBuilder::set_to_null - return _excluded || _failed_verification || _klass == NULL; + return _excluded || _failed_verification; } // Was this class loaded while JvmtiExport::is_early_phase()==true @@ -152,11 +162,13 @@ public: void set_failed_verification() { _failed_verification = true; } InstanceKlass* nest_host() const { return _nest_host; } void set_nest_host(InstanceKlass* nest_host) { _nest_host = nest_host; } + DumpTimeClassInfo clone(); + size_t runtime_info_bytesize() const; }; - -inline unsigned DumpTimeSharedClassTable_hash(InstanceKlass* const& k) { +template +inline unsigned DumpTimeSharedClassTable_hash(T* const& k) { if (DumpSharedSpaces) { // Deterministic archive contents uintx delta = k->name() - MetaspaceShared::symbol_rs_base(); @@ -164,17 +176,19 @@ inline unsigned DumpTimeSharedClassTable_hash(InstanceKlass* const& k) { } else { // Deterministic archive is not possible because classes can be loaded // in multiple threads. - return primitive_hash(k); + return primitive_hash(k); } } -class DumpTimeSharedClassTable: public ResourceHashtable< +using DumpTimeSharedClassTableBaseType = ResourceHashtable< InstanceKlass*, DumpTimeClassInfo, 15889, // prime number ResourceObj::C_HEAP, mtClassShared, - &DumpTimeSharedClassTable_hash> + &DumpTimeSharedClassTable_hash>; + +class DumpTimeSharedClassTable: public DumpTimeSharedClassTableBaseType { int _builtin_count; int _unregistered_count; @@ -194,6 +208,11 @@ public: return _unregistered_count; } } + + // Overrides ResourceHashtable<>::iterate(ITER*) + template void iterate(ITER* iter) const; +private: + template class IterationHelper; }; #endif // SHARED_CDS_DUMPTIMESHAREDCLASSINFO_HPP diff --git a/src/hotspot/share/cds/dumpTimeClassInfo.inline.hpp b/src/hotspot/share/cds/dumpTimeClassInfo.inline.hpp new file mode 100644 index 0000000000000000000000000000000000000000..f9dbfc7f816c14f90dc67fb1e19baf3bcb99ccb0 --- /dev/null +++ b/src/hotspot/share/cds/dumpTimeClassInfo.inline.hpp @@ -0,0 +1,74 @@ + +/* + * 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 SHARED_CDS_DUMPTIMESHAREDCLASSINFO_INLINE_HPP +#define SHARED_CDS_DUMPTIMESHAREDCLASSINFO_INLINE_HPP + +#include "cds/dumpTimeClassInfo.hpp" +#include "classfile/systemDictionaryShared.hpp" +#include "classfile/classLoaderData.inline.hpp" +#include "oops/instanceKlass.hpp" +#include "oops/klass.inline.hpp" +#include "runtime/safepoint.hpp" + +#if INCLUDE_CDS + +// For safety, only iterate over a class if it loader is alive. +// IterationHelper and DumpTimeSharedClassTable::iterate +// must be used only inside a safepoint, where the value of +// k->is_loader_alive() will not change. +template +class DumpTimeSharedClassTable::IterationHelper { + ITER* _iter; +public: + IterationHelper(ITER* iter) { + _iter = iter; + } + bool do_entry(InstanceKlass* k, DumpTimeClassInfo& info) { + assert(SafepointSynchronize::is_at_safepoint(), "invariant"); + assert_lock_strong(DumpTimeTable_lock); + if (k->is_loader_alive()) { + bool result = _iter->do_entry(k, info); + assert(k->is_loader_alive(), "must not change"); + return result; + } else { + if (!SystemDictionaryShared::is_excluded_class(k)) { + SystemDictionaryShared::warn_excluded(k, "Class loader not alive"); + SystemDictionaryShared::set_excluded_locked(k); + } + return true; + } + } +}; + +template +void DumpTimeSharedClassTable::iterate(ITER* iter) const { + IterationHelper helper(iter); + DumpTimeSharedClassTableBaseType::iterate(&helper); +} + +#endif // INCLUDE_CDS + +#endif // SHARED_CDS_DUMPTIMESHAREDCLASSINFO_INLINE_HPP diff --git a/src/hotspot/share/cds/dynamicArchive.cpp b/src/hotspot/share/cds/dynamicArchive.cpp index b3c18e318a85058ecd403885281010bd69dcfcc0..00d586ffc4f4ef9f5da9423c990ce47bccf6f626 100644 --- a/src/hotspot/share/cds/dynamicArchive.cpp +++ b/src/hotspot/share/cds/dynamicArchive.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -50,7 +50,9 @@ class DynamicArchiveBuilder : public ArchiveBuilder { + const char* _archive_name; public: + DynamicArchiveBuilder(const char* archive_name) : _archive_name(archive_name) {} void mark_pointer(address* ptr_loc) { ArchivePtrMarker::mark_pointer(ptr_loc); } @@ -113,6 +115,12 @@ public: MutexLocker ml(DumpTimeTable_lock, Mutex::_no_safepoint_check_flag); SystemDictionaryShared::check_excluded_classes(); + if (SystemDictionaryShared::is_dumptime_table_empty()) { + log_warning(cds, dynamic)("There is no class to be included in the dynamic archive."); + SystemDictionaryShared::stop_dumping(); + return; + } + // save dumptime tables SystemDictionaryShared::clone_dumptime_tables(); @@ -169,6 +177,7 @@ public: assert(_num_dump_regions_used == _total_dump_regions, "must be"); verify_universe("After CDS dynamic dump"); + SystemDictionaryShared::stop_dumping(); } virtual void iterate_roots(MetaspaceClosure* it, bool is_relocating_pointers) { @@ -178,7 +187,7 @@ public: }; void DynamicArchiveBuilder::init_header() { - FileMapInfo* mapinfo = new FileMapInfo(false); + FileMapInfo* mapinfo = new FileMapInfo(_archive_name, false); assert(FileMapInfo::dynamic_info() == mapinfo, "must be"); FileMapInfo* base_info = FileMapInfo::current_info(); // header only be available after populate_header @@ -318,7 +327,7 @@ void DynamicArchiveBuilder::write_archive(char* serialized_data) { FileMapInfo* dynamic_info = FileMapInfo::dynamic_info(); assert(dynamic_info != NULL, "Sanity"); - dynamic_info->open_for_write(Arguments::GetSharedDynamicArchivePath()); + dynamic_info->open_for_write(); ArchiveBuilder::write_archive(dynamic_info, NULL, NULL, NULL, NULL); address base = _requested_dynamic_archive_bottom; @@ -333,30 +342,50 @@ void DynamicArchiveBuilder::write_archive(char* serialized_data) { } class VM_PopulateDynamicDumpSharedSpace: public VM_GC_Sync_Operation { - DynamicArchiveBuilder builder; + DynamicArchiveBuilder _builder; public: - VM_PopulateDynamicDumpSharedSpace() : VM_GC_Sync_Operation() {} + VM_PopulateDynamicDumpSharedSpace(const char* archive_name) + : VM_GC_Sync_Operation(), _builder(archive_name) {} VMOp_Type type() const { return VMOp_PopulateDumpSharedSpace; } void doit() { ResourceMark rm; - if (SystemDictionaryShared::is_dumptime_table_empty()) { - log_warning(cds, dynamic)("There is no class to be included in the dynamic archive."); - return; - } if (AllowArchivingWithJavaAgent) { warning("This archive was created with AllowArchivingWithJavaAgent. It should be used " "for testing purposes only and should not be used in a production environment"); } FileMapInfo::check_nonempty_dir_in_shared_path_table(); - builder.doit(); + _builder.doit(); + } + ~VM_PopulateDynamicDumpSharedSpace() { + LambdaFormInvokers::cleanup_regenerated_classes(); } }; -void DynamicArchive::prepare_for_dynamic_dumping() { +void DynamicArchive::check_for_dynamic_dump() { + if (DynamicDumpSharedSpaces && !UseSharedSpaces) { + // This could happen if SharedArchiveFile has failed to load: + // - -Xshare:off was specified + // - SharedArchiveFile points to an non-existent file. + // - SharedArchiveFile points to an archive that has failed CRC check + // - SharedArchiveFile is not specified and the VM doesn't have a compatible default archive + +#define __THEMSG " is unsupported when base CDS archive is not loaded. Run with -Xlog:cds for more info." + if (RecordDynamicDumpInfo) { + vm_exit_during_initialization("-XX:+RecordDynamicDumpInfo" __THEMSG, NULL); + } else { + assert(ArchiveClassesAtExit != nullptr, "sanity"); + warning("-XX:ArchiveClassesAtExit" __THEMSG); + } +#undef __THEMSG + DynamicDumpSharedSpaces = false; + } +} + +void DynamicArchive::prepare_for_dump_at_exit() { EXCEPTION_MARK; ResourceMark rm(THREAD); - MetaspaceShared::link_shared_classes(THREAD); + MetaspaceShared::link_shared_classes(false/*not from jcmd*/, THREAD); if (HAS_PENDING_EXCEPTION) { log_error(cds)("Dynamic dump has failed"); log_error(cds)("%s: %s", PENDING_EXCEPTION->klass()->external_name(), @@ -367,41 +396,27 @@ void DynamicArchive::prepare_for_dynamic_dumping() { } } -void DynamicArchive::dump(const char* archive_name, TRAPS) { - assert(UseSharedSpaces && RecordDynamicDumpInfo, "already checked in arguments.cpp?"); - assert(ArchiveClassesAtExit == nullptr, "already checked in arguments.cpp?"); - ArchiveClassesAtExit = archive_name; - if (Arguments::init_shared_archive_paths()) { - prepare_for_dynamic_dumping(); - if (DynamicDumpSharedSpaces) { - dump(CHECK); - } - } else { - ArchiveClassesAtExit = nullptr; - THROW_MSG(vmSymbols::java_lang_RuntimeException(), - "Could not setup SharedDynamicArchivePath"); - } - // prevent do dynamic dump at exit. - ArchiveClassesAtExit = nullptr; - if (!Arguments::init_shared_archive_paths()) { - THROW_MSG(vmSymbols::java_lang_RuntimeException(), - "Could not restore SharedDynamicArchivePath"); - } +// This is called by "jcmd VM.cds dynamic_dump" +void DynamicArchive::dump_for_jcmd(const char* archive_name, TRAPS) { + assert(UseSharedSpaces && RecordDynamicDumpInfo, "already checked in arguments.cpp"); + assert(ArchiveClassesAtExit == nullptr, "already checked in arguments.cpp"); + assert(DynamicDumpSharedSpaces, "already checked by check_for_dynamic_dump() during VM startup"); + MetaspaceShared::link_shared_classes(true/*from jcmd*/, CHECK); + dump(archive_name, THREAD); } -void DynamicArchive::dump(TRAPS) { - if (Arguments::GetSharedDynamicArchivePath() == NULL) { - log_warning(cds, dynamic)("SharedDynamicArchivePath is not specified"); - return; - } - +void DynamicArchive::dump(const char* archive_name, TRAPS) { // copy shared path table to saved. FileMapInfo::clone_shared_path_table(CHECK); - VM_PopulateDynamicDumpSharedSpace op; + VM_PopulateDynamicDumpSharedSpace op(archive_name); VMThread::execute(&op); } +bool DynamicArchive::should_dump_at_vm_exit() { + return DynamicDumpSharedSpaces && (ArchiveClassesAtExit != nullptr); +} + bool DynamicArchive::validate(FileMapInfo* dynamic_info) { assert(!dynamic_info->is_static(), "must be"); // Check if the recorded base archive matches with the current one diff --git a/src/hotspot/share/cds/dynamicArchive.hpp b/src/hotspot/share/cds/dynamicArchive.hpp index 0371b94849752aad06eaf08d38333b7291637113..ec8a505978b9450ceead4846f0c1515b0a02f1fb 100644 --- a/src/hotspot/share/cds/dynamicArchive.hpp +++ b/src/hotspot/share/cds/dynamicArchive.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -27,7 +27,7 @@ #include "cds/filemap.hpp" #include "classfile/compactHashtable.hpp" -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" #include "memory/memRegion.hpp" #include "memory/virtualspace.hpp" #include "oops/oop.hpp" @@ -59,9 +59,11 @@ public: class DynamicArchive : AllStatic { public: - static void prepare_for_dynamic_dumping(); + static void check_for_dynamic_dump(); + static bool should_dump_at_vm_exit(); + static void prepare_for_dump_at_exit(); + static void dump_for_jcmd(const char* archive_name, TRAPS); static void dump(const char* archive_name, TRAPS); - static void dump(TRAPS); static bool is_mapped() { return FileMapInfo::dynamic_info() != NULL; } static bool validate(FileMapInfo* dynamic_info); }; diff --git a/src/hotspot/share/cds/filemap.cpp b/src/hotspot/share/cds/filemap.cpp index 14eaa8a6abbfe3ae05bde33234feb15c5347750d..b8e28f30b72bf21aa8c25194fa887da73e99194f 100644 --- a/src/hotspot/share/cds/filemap.cpp +++ b/src/hotspot/share/cds/filemap.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -121,7 +121,6 @@ void FileMapInfo::fail_continue(const char *msg, ...) { fail_exit(msg, ap); } else { if (log_is_enabled(Info, cds)) { - ResourceMark rm; LogStream ls(Log(cds)::info()); ls.print("UseSharedSpaces: "); ls.vprint_cr(msg, ap); @@ -167,8 +166,9 @@ template static void get_header_version(char (&header_version) [N]) { assert(header_version[JVM_IDENT_MAX-1] == 0, "must be"); } -FileMapInfo::FileMapInfo(bool is_static) { +FileMapInfo::FileMapInfo(const char* full_path, bool is_static) { memset((void*)this, 0, sizeof(FileMapInfo)); + _full_path = full_path; _is_static = is_static; if (_is_static) { assert(_current_info == NULL, "must be singleton"); // not thread safe @@ -189,6 +189,9 @@ FileMapInfo::~FileMapInfo() { assert(_dynamic_archive_info == this, "must be singleton"); // not thread safe _dynamic_archive_info = NULL; } + if (_file_open) { + ::close(_fd); + } } void FileMapInfo::populate_header(size_t core_region_alignment) { @@ -242,8 +245,13 @@ void FileMapHeader::populate(FileMapInfo *info, size_t core_region_alignment, _narrow_oop_mode = CompressedOops::mode(); _narrow_oop_base = CompressedOops::base(); _narrow_oop_shift = CompressedOops::shift(); - _heap_begin = CompressedOops::begin(); - _heap_end = CompressedOops::end(); + if (UseCompressedOops) { + _heap_begin = CompressedOops::begin(); + _heap_end = CompressedOops::end(); + } else { + _heap_begin = (address)G1CollectedHeap::heap()->reserved().start(); + _heap_end = (address)G1CollectedHeap::heap()->reserved().end(); + } } _compressed_oops = UseCompressedOops; _compressed_class_ptrs = UseCompressedClassPointers; @@ -274,7 +282,6 @@ void FileMapHeader::populate(FileMapInfo *info, size_t core_region_alignment, if (!DynamicDumpSharedSpaces) { set_shared_path_table(info->_shared_path_table); - CDS_JAVA_HEAP_ONLY(_heap_obj_roots = CompressedOops::encode(HeapShared::roots());) } } @@ -314,6 +321,7 @@ void FileMapHeader::print(outputStream* st) { st->print_cr("- compressed_class_ptrs: %d", _compressed_class_ptrs); st->print_cr("- cloned_vtables_offset: " SIZE_FORMAT_HEX, _cloned_vtables_offset); st->print_cr("- serialized_data_offset: " SIZE_FORMAT_HEX, _serialized_data_offset); + st->print_cr("- heap_begin: " INTPTR_FORMAT, p2i(_heap_begin)); st->print_cr("- heap_end: " INTPTR_FORMAT, p2i(_heap_end)); st->print_cr("- jvm_ident: %s", _jvm_ident); st->print_cr("- shared_path_table_offset: " SIZE_FORMAT_HEX, _shared_path_table_offset); @@ -765,6 +773,21 @@ int FileMapInfo::num_paths(const char* path) { return npaths; } +// Returns true if a path within the paths exists and has non-zero size. +bool FileMapInfo::check_paths_existence(const char* paths) { + ClasspathStream cp_stream(paths); + bool exist = false; + struct stat st; + while (cp_stream.has_next()) { + const char* path = cp_stream.get_next(); + if (os::stat(path, &st) == 0 && st.st_size > 0) { + exist = true; + break; + } + } + return exist; +} + GrowableArray* FileMapInfo::create_path_array(const char* paths) { GrowableArray* path_array = new GrowableArray(10); JavaThread* current = JavaThread::current(); @@ -848,7 +871,12 @@ bool FileMapInfo::validate_boot_class_paths() { if (relaxed_check) { return true; // ok, relaxed check, runtime has extra boot append path entries } else { - mismatch = true; + ResourceMark rm; + 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; + } } } else if (dp_len > 0 && rp != NULL) { int num; @@ -935,6 +963,17 @@ void FileMapInfo::log_paths(const char* msg, int start_idx, int end_idx) { } } +bool FileMapInfo::check_module_paths() { + const char* rp = Arguments::get_property("jdk.module.path"); + int num_paths = Arguments::num_archives(rp); + if (num_paths != header()->num_module_paths()) { + return false; + } + ResourceMark rm; + GrowableArray* rp_array = create_path_array(rp); + return check_paths(header()->app_module_paths_start_index(), num_paths, rp_array); +} + bool FileMapInfo::validate_shared_path_table() { assert(UseSharedSpaces, "runtime only"); @@ -957,9 +996,11 @@ bool FileMapInfo::validate_shared_path_table() { "Dynamic archiving is disabled because base layer archive has appended boot classpath"); } if (header()->num_module_paths() > 0) { - DynamicDumpSharedSpaces = false; - warning( - "Dynamic archiving is disabled because base layer archive has module path"); + if (!check_module_paths()) { + DynamicDumpSharedSpaces = false; + warning( + "Dynamic archiving is disabled because base layer archive has a different module path"); + } } } @@ -1042,25 +1083,44 @@ void FileMapInfo::validate_non_existent_class_paths() { } } -// a utility class for checking file header +// A utility class for reading/validating the GenericCDSFileMapHeader portion of +// a CDS archive's header. The file header of all CDS archives with versions from +// CDS_GENERIC_HEADER_SUPPORTED_MIN_VERSION (12) are guaranteed to always start +// with GenericCDSFileMapHeader. This makes it possible to read important information +// from a CDS archive created by a different version of HotSpot, so that we can +// automatically regenerate the archive as necessary (JDK-8261455). class FileHeaderHelper { int _fd; - GenericCDSFileMapHeader _header; + bool _is_valid; + bool _is_static; + GenericCDSFileMapHeader* _header; + const char* _archive_name; + const char* _base_archive_name; public: - FileHeaderHelper() { + FileHeaderHelper(const char* archive_name, bool is_static) { _fd = -1; + _is_valid = false; + _header = nullptr; + _base_archive_name = nullptr; + _archive_name = archive_name; + _is_static = is_static; } ~FileHeaderHelper() { + if (_header != nullptr) { + FREE_C_HEAP_ARRAY(char, _header); + } if (_fd != -1) { - os::close(_fd); + ::close(_fd); } } - bool initialize(const char* archive_name) { - _fd = os::open(archive_name, O_RDONLY | O_BINARY, 0); + bool initialize() { + assert(_archive_name != nullptr, "Archive name is NULL"); + _fd = os::open(_archive_name, O_RDONLY | O_BINARY, 0); if (_fd < 0) { + FileMapInfo::fail_continue("Specified shared archive not found (%s)", _archive_name); return false; } return initialize(_fd); @@ -1068,143 +1128,200 @@ public: // for an already opened file, do not set _fd bool initialize(int fd) { - assert(fd != -1, "Archive should be opened"); + assert(_archive_name != nullptr, "Archive name is NULL"); + assert(fd != -1, "Archive must be opened already"); + // First read the generic header so we know the exact size of the actual header. + GenericCDSFileMapHeader gen_header; size_t size = sizeof(GenericCDSFileMapHeader); - lseek(fd, 0, SEEK_SET); - size_t n = os::read(fd, (void*)&_header, (unsigned int)size); + os::lseek(fd, 0, SEEK_SET); + size_t n = ::read(fd, (void*)&gen_header, (unsigned int)size); if (n != size) { - vm_exit_during_initialization("Unable to read generic CDS file map header from shared archive"); + FileMapInfo::fail_continue("Unable to read generic CDS file map header from shared archive"); return false; } - return true; - } - - GenericCDSFileMapHeader* get_generic_file_header() { - return &_header; - } - char* read_base_archive_name() { - assert(_fd != -1, "Archive should be open"); - size_t name_size = _header._base_archive_name_size; - assert(name_size != 0, "For non-default base archive, name size should be non-zero!"); - char* base_name = NEW_C_HEAP_ARRAY(char, name_size, mtInternal); - lseek(_fd, _header._base_archive_name_offset, SEEK_SET); // position to correct offset. - size_t n = os::read(_fd, base_name, (unsigned int)name_size); - if (n != name_size) { - log_info(cds)("Unable to read base archive name from archive"); - FREE_C_HEAP_ARRAY(char, base_name); - return nullptr; - } - if (base_name[name_size - 1] != '\0' || strlen(base_name) != name_size - 1) { - log_info(cds)("Base archive name is damaged"); - FREE_C_HEAP_ARRAY(char, base_name); - return nullptr; + if (gen_header._magic != CDS_ARCHIVE_MAGIC && + gen_header._magic != CDS_DYNAMIC_ARCHIVE_MAGIC) { + FileMapInfo::fail_continue("The shared archive file has a bad magic number: %#x", gen_header._magic); + return false; } - if (!os::file_exists(base_name)) { - log_info(cds)("Base archive %s does not exist", base_name); - FREE_C_HEAP_ARRAY(char, base_name); - return nullptr; + + if (gen_header._version < CDS_GENERIC_HEADER_SUPPORTED_MIN_VERSION) { + FileMapInfo::fail_continue("Cannot handle shared archive file version %d. Must be at least %d", + gen_header._version, CDS_GENERIC_HEADER_SUPPORTED_MIN_VERSION); + return false; } - return base_name; - } -}; -bool FileMapInfo::check_archive(const char* archive_name, bool is_static) { - FileHeaderHelper file_helper; - if (!file_helper.initialize(archive_name)) { - // do not vm_exit_during_initialization here because Arguments::init_shared_archive_paths() - // requires a shared archive name. The open_for_read() function will log a message regarding - // failure in opening a shared archive. - return false; - } + if (gen_header._version != CURRENT_CDS_ARCHIVE_VERSION) { + FileMapInfo::fail_continue("The shared archive file version %d does not match the required version %d", + gen_header._version, CURRENT_CDS_ARCHIVE_VERSION); + } - GenericCDSFileMapHeader* header = file_helper.get_generic_file_header(); - if (is_static) { - if (header->_magic != CDS_ARCHIVE_MAGIC) { - vm_exit_during_initialization("Not a base shared archive", archive_name); + size_t filelen = os::lseek(fd, 0, SEEK_END); + if (gen_header._header_size >= filelen) { + FileMapInfo::fail_continue("Archive file header larger than archive file"); return false; } - if (header->_base_archive_name_offset != 0) { - log_info(cds)("_base_archive_name_offset should be 0"); - log_info(cds)("_base_archive_name_offset = " UINT32_FORMAT, header->_base_archive_name_offset); + + // Read the actual header and perform more checks + size = gen_header._header_size; + _header = (GenericCDSFileMapHeader*)NEW_C_HEAP_ARRAY(char, size, mtInternal); + os::lseek(fd, 0, SEEK_SET); + n = ::read(fd, (void*)_header, (unsigned int)size); + if (n != size) { + FileMapInfo::fail_continue("Unable to read actual CDS file map header from shared archive"); return false; } - } else { - if (header->_magic != CDS_DYNAMIC_ARCHIVE_MAGIC) { - vm_exit_during_initialization("Not a top shared archive", archive_name); + + if (!check_crc()) { return false; } - unsigned int name_size = header->_base_archive_name_size; - unsigned int name_offset = header->_base_archive_name_offset; - unsigned int header_size = header->_header_size; - if (name_offset + name_size != header_size) { - log_info(cds)("_header_size should be equal to _base_archive_name_offset plus _base_archive_name_size"); - log_info(cds)(" _base_archive_name_size = " UINT32_FORMAT, name_size); - log_info(cds)(" _base_archive_name_offset = " UINT32_FORMAT, name_offset); - log_info(cds)(" _header_size = " UINT32_FORMAT, header_size); + + if (!check_and_init_base_archive_name()) { return false; } - char* base_name = file_helper.read_base_archive_name(); - if (base_name == nullptr) { + + // All fields in the GenericCDSFileMapHeader has been validated. + _is_valid = true; + return true; + } + + GenericCDSFileMapHeader* get_generic_file_header() { + assert(_header != nullptr && _is_valid, "must be a valid archive file"); + return _header; + } + + const char* base_archive_name() { + assert(_header != nullptr && _is_valid, "must be a valid archive file"); + return _base_archive_name; + } + + private: + bool check_crc() { + if (VerifySharedSpaces) { + FileMapHeader* header = (FileMapHeader*)_header; + int actual_crc = header->compute_crc(); + if (actual_crc != header->crc()) { + log_info(cds)("_crc expected: %d", header->crc()); + log_info(cds)(" actual: %d", actual_crc); + FileMapInfo::fail_continue("Header checksum verification failed."); + return false; + } + } + return true; + } + + bool check_and_init_base_archive_name() { + unsigned int name_offset = _header->_base_archive_name_offset; + unsigned int name_size = _header->_base_archive_name_size; + unsigned int header_size = _header->_header_size; + + if (name_offset + name_size < name_offset) { + FileMapInfo::fail_continue("base_archive_name offset/size overflow: " UINT32_FORMAT "/" UINT32_FORMAT, + name_offset, name_size); return false; } - FREE_C_HEAP_ARRAY(char, base_name); + if (_header->_magic == CDS_ARCHIVE_MAGIC) { + if (name_offset != 0) { + FileMapInfo::fail_continue("static shared archive must have zero _base_archive_name_offset"); + return false; + } + if (name_size != 0) { + FileMapInfo::fail_continue("static shared archive must have zero _base_archive_name_size"); + return false; + } + } else { + assert(_header->_magic == CDS_DYNAMIC_ARCHIVE_MAGIC, "must be"); + if ((name_size == 0 && name_offset != 0) || + (name_size != 0 && name_offset == 0)) { + // If either is zero, both must be zero. This indicates that we are using the default base archive. + FileMapInfo::fail_continue("Invalid base_archive_name offset/size: " UINT32_FORMAT "/" UINT32_FORMAT, + name_offset, name_size); + return false; + } + if (name_size > 0) { + if (name_offset + name_size > header_size) { + FileMapInfo::fail_continue("Invalid base_archive_name offset/size (out of range): " + UINT32_FORMAT " + " UINT32_FORMAT " > " UINT32_FORMAT , + name_offset, name_size, header_size); + return false; + } + const char* name = ((const char*)_header) + _header->_base_archive_name_offset; + if (name[name_size - 1] != '\0' || strlen(name) != name_size - 1) { + FileMapInfo::fail_continue("Base archive name is damaged"); + return false; + } + if (!os::file_exists(name)) { + FileMapInfo::fail_continue("Base archive %s does not exist", name); + return false; + } + _base_archive_name = name; + } + } + return true; } - return true; -} +}; +// Return value: +// false: +// is not a valid archive. *base_archive_name is set to null. +// true && (*base_archive_name) == NULL: +// is a valid static archive. +// true && (*base_archive_name) != NULL: +// is a valid dynamic archive. bool FileMapInfo::get_base_archive_name_from_header(const char* archive_name, char** base_archive_name) { - FileHeaderHelper file_helper; - if (!file_helper.initialize(archive_name)) { + FileHeaderHelper file_helper(archive_name, false); + *base_archive_name = NULL; + + if (!file_helper.initialize()) { return false; } GenericCDSFileMapHeader* header = file_helper.get_generic_file_header(); if (header->_magic != CDS_DYNAMIC_ARCHIVE_MAGIC) { - // Not a dynamic header, no need to proceed further. - return false; + assert(header->_magic == CDS_ARCHIVE_MAGIC, "must be"); + if (AutoCreateSharedArchive) { + log_warning(cds)("AutoCreateSharedArchive is ignored because %s is a static archive", archive_name); + } + return true; } - if ((header->_base_archive_name_size == 0 && header->_base_archive_name_offset != 0) || - (header->_base_archive_name_size != 0 && header->_base_archive_name_offset == 0)) { - fail_continue("Default base archive not set correct"); - return false; - } - if (header->_base_archive_name_size == 0 && - header->_base_archive_name_offset == 0) { + const char* base = file_helper.base_archive_name(); + if (base == nullptr) { *base_archive_name = Arguments::get_default_shared_archive_path(); } else { - // read the base archive name - *base_archive_name = file_helper.read_base_archive_name(); - if (*base_archive_name == nullptr) { - return false; - } + *base_archive_name = os::strdup_check_oom(base); } + return true; } // Read the FileMapInfo information from the file. bool FileMapInfo::init_from_file(int fd) { - FileHeaderHelper file_helper; + FileHeaderHelper file_helper(_full_path, _is_static); if (!file_helper.initialize(fd)) { fail_continue("Unable to read the file header."); return false; } GenericCDSFileMapHeader* gen_header = file_helper.get_generic_file_header(); - unsigned int expected_magic = is_static() ? CDS_ARCHIVE_MAGIC : CDS_DYNAMIC_ARCHIVE_MAGIC; - if (gen_header->_magic != expected_magic) { - log_info(cds)("_magic expected: 0x%08x", expected_magic); - log_info(cds)(" actual: 0x%08x", gen_header->_magic); - FileMapInfo::fail_continue("The shared archive file has a bad magic number."); - return false; + if (_is_static) { + if (gen_header->_magic != CDS_ARCHIVE_MAGIC) { + FileMapInfo::fail_continue("Not a base shared archive: %s", _full_path); + return false; + } + } else { + if (gen_header->_magic != CDS_DYNAMIC_ARCHIVE_MAGIC) { + FileMapInfo::fail_continue("Not a top shared archive: %s", _full_path); + return false; + } } _header = (FileMapHeader*)os::malloc(gen_header->_header_size, mtInternal); - lseek(fd, 0, SEEK_SET); // reset to begin of the archive + os::lseek(fd, 0, SEEK_SET); // reset to begin of the archive size_t size = gen_header->_header_size; - size_t n = os::read(fd, (void*)_header, (unsigned int)size); + size_t n = ::read(fd, (void*)_header, (unsigned int)size); if (n != size) { fail_continue("Failed to read file header from the top archive file\n"); return false; @@ -1247,22 +1364,12 @@ bool FileMapInfo::init_from_file(int fd) { return false; } - if (VerifySharedSpaces) { - int expected_crc = header()->compute_crc(); - if (expected_crc != header()->crc()) { - log_info(cds)("_crc expected: %d", expected_crc); - log_info(cds)(" actual: %d", header()->crc()); - FileMapInfo::fail_continue("Header checksum verification failed."); - return false; - } - } - _file_offset = header()->header_size(); // accounts for the size of _base_archive_name if (is_static()) { // just checking the last region is sufficient since the archive is written // in sequential order - size_t len = lseek(fd, 0, SEEK_END); + size_t len = os::lseek(fd, 0, SEEK_END); FileMapRegion* si = space_at(MetaspaceShared::last_valid_region); // The last space might be empty if (si->file_offset() > len || len - si->file_offset() < si->used()) { @@ -1275,7 +1382,7 @@ bool FileMapInfo::init_from_file(int fd) { } void FileMapInfo::seek_to_position(size_t pos) { - if (lseek(_fd, (long)pos, SEEK_SET) < 0) { + if (os::lseek(_fd, (long)pos, SEEK_SET) < 0) { fail_stop("Unable to seek to position " SIZE_FORMAT, pos); } } @@ -1285,18 +1392,13 @@ bool FileMapInfo::open_for_read() { if (_file_open) { return true; } - if (is_static()) { - _full_path = Arguments::GetSharedArchivePath(); - } else { - _full_path = Arguments::GetSharedDynamicArchivePath(); - } log_info(cds)("trying to map %s", _full_path); int fd = os::open(_full_path, O_RDONLY | O_BINARY, 0); if (fd < 0) { if (errno == ENOENT) { - fail_continue("Specified shared archive not found (%s).", _full_path); + fail_continue("Specified shared archive not found (%s)", _full_path); } else { - fail_continue("Failed to open shared archive file (%s).", + fail_continue("Failed to open shared archive file (%s)", os::strerror(errno)); } return false; @@ -1311,12 +1413,7 @@ bool FileMapInfo::open_for_read() { // Write the FileMapInfo information to the file. -void FileMapInfo::open_for_write(const char* path) { - if (path == NULL) { - _full_path = Arguments::GetSharedArchivePath(); - } else { - _full_path = path; - } +void FileMapInfo::open_for_write() { LogMessage(cds) msg; if (msg.is_info()) { msg.info("Dumping shared data to file: "); @@ -1416,7 +1513,11 @@ void FileMapInfo::write_region(int region, char* base, size_t size, } else if (HeapShared::is_heap_region(region)) { assert(!DynamicDumpSharedSpaces, "must be"); requested_base = base; - mapping_offset = (size_t)CompressedOops::encode_not_null(cast_to_oop(base)); + if (UseCompressedOops) { + mapping_offset = (size_t)CompressedOops::encode_not_null(cast_to_oop(base)); + } else { + mapping_offset = requested_base - (char*)G1CollectedHeap::heap()->reserved().start(); + } assert(mapping_offset == (size_t)(uint32_t)mapping_offset, "must be 32-bit only"); } else { char* requested_SharedBaseAddress = (char*)MetaspaceShared::requested_base_address(); @@ -1550,8 +1651,8 @@ size_t FileMapInfo::write_heap_regions(GrowableArray* regions, void FileMapInfo::write_bytes(const void* buffer, size_t nbytes) { assert(_file_open, "must be"); - size_t n = os::write(_fd, buffer, (unsigned int)nbytes); - if (n != nbytes) { + ssize_t n = os::write(_fd, buffer, (unsigned int)nbytes); + if (n < 0 || (size_t)n != nbytes) { // If the shared archive is corrupted, close it and remove it. close(); remove(_full_path); @@ -1686,7 +1787,7 @@ bool FileMapInfo::read_region(int i, char* base, size_t size, bool do_commit) { return false; } } - if (lseek(_fd, (long)si->file_offset(), SEEK_SET) != (int)si->file_offset() || + if (os::lseek(_fd, (long)si->file_offset(), SEEK_SET) != (int)si->file_offset() || read_bytes(base, size) != size) { return false; } @@ -1723,7 +1824,7 @@ MapArchiveResult FileMapInfo::map_region(int i, intx addr_delta, char* mapped_ba if (MetaspaceShared::use_windows_memory_mapping() && rs.is_reserved()) { // This is the second time we try to map the archive(s). We have already created a ReservedSpace // that covers all the FileMapRegions to ensure all regions can be mapped. However, Windows - // can't mmap into a ReservedSpace, so we just os::read() the data. We're going to patch all the + // can't mmap into a ReservedSpace, so we just ::read() the data. We're going to patch all the // regions anyway, so there's no benefit for mmap anyway. if (!read_region(i, requested_addr, size, /* do_commit = */ true)) { log_info(cds)("Failed to read %s shared space into reserved space at " INTPTR_FORMAT, @@ -1829,7 +1930,7 @@ bool FileMapInfo::relocate_pointers_in_core_regions(intx addr_delta) { size_t FileMapInfo::read_bytes(void* buffer, size_t count) { assert(_file_open, "Archive file is not open"); - size_t n = os::read(_fd, buffer, (unsigned int)count); + size_t n = ::read(_fd, buffer, (unsigned int)count); if (n != count) { // Close the file if there's a problem reading it. close(); @@ -1896,7 +1997,7 @@ void FileMapInfo::map_or_load_heap_regions() { } else if (HeapShared::can_load()) { success = HeapShared::load_heap_regions(this); } else { - log_info(cds)("Cannot use CDS heap data. UseEpsilonGC, UseG1GC or UseSerialGC are required."); + log_info(cds)("Cannot use CDS heap data. UseEpsilonGC, UseG1GC, UseSerialGC or UseParallelGC are required."); } } @@ -1938,7 +2039,10 @@ bool FileMapInfo::can_use_heap_regions() { log_info(cds)(" narrow_oop_mode = %d, narrow_oop_base = " PTR_FORMAT ", narrow_oop_shift = %d", CompressedOops::mode(), p2i(CompressedOops::base()), CompressedOops::shift()); log_info(cds)(" heap range = [" PTR_FORMAT " - " PTR_FORMAT "]", - p2i(CompressedOops::begin()), p2i(CompressedOops::end())); + UseCompressedOops ? p2i(CompressedOops::begin()) : + UseG1GC ? p2i((address)G1CollectedHeap::heap()->reserved().start()) : 0L, + UseCompressedOops ? p2i(CompressedOops::end()) : + UseG1GC ? p2i((address)G1CollectedHeap::heap()->reserved().end()) : 0L); if (narrow_klass_base() != CompressedKlassPointers::base() || narrow_klass_shift() != CompressedKlassPointers::shift()) { @@ -1948,6 +2052,26 @@ bool FileMapInfo::can_use_heap_regions() { return true; } +// The address where the bottom of this shared heap region should be mapped +// at runtime +address FileMapInfo::heap_region_runtime_start_address(FileMapRegion* spc) { + assert(UseSharedSpaces, "runtime only"); + spc->assert_is_heap_region(); + if (UseCompressedOops) { + return start_address_as_decoded_from_archive(spc); + } else { + assert(is_aligned(spc->mapping_offset(), sizeof(HeapWord)), "must be"); + return header()->heap_begin() + spc->mapping_offset() + HeapShared::runtime_delta(); + } +} + +void FileMapInfo::set_shared_heap_runtime_delta(ptrdiff_t delta) { + if (UseCompressedOops) { + HeapShared::init_narrow_oop_decoding(narrow_oop_base() + delta, narrow_oop_shift()); + } else { + HeapShared::set_runtime_delta(delta); + } +} // // Map the closed and open archive heap objects to the runtime java heap. @@ -1970,39 +2094,66 @@ void FileMapInfo::map_heap_regions_impl() { log_info(cds)("CDS heap data needs to be relocated because the archive was created with an incompatible oop encoding mode."); _heap_pointers_need_patching = true; } else { - MemRegion range = get_heap_regions_range_with_current_oop_encoding_mode(); - if (!CompressedOops::is_in(range)) { - log_info(cds)("CDS heap data needs to be relocated because"); - log_info(cds)("the desired range " PTR_FORMAT " - " PTR_FORMAT, p2i(range.start()), p2i(range.end())); - log_info(cds)("is outside of the heap " PTR_FORMAT " - " PTR_FORMAT, p2i(CompressedOops::begin()), p2i(CompressedOops::end())); - _heap_pointers_need_patching = true; - } else if (header()->heap_end() != CompressedOops::end()) { - log_info(cds)("CDS heap data needs to be relocated to the end of the runtime heap to reduce fragmentation"); - _heap_pointers_need_patching = true; + if (UseCompressedOops) { + MemRegion range = get_heap_regions_range_with_current_oop_encoding_mode(); + if (!CompressedOops::is_in(range)) { + log_info(cds)("CDS heap data needs to be relocated because"); + log_info(cds)("the desired range " PTR_FORMAT " - " PTR_FORMAT, p2i(range.start()), p2i(range.end())); + log_info(cds)("is outside of the heap " PTR_FORMAT " - " PTR_FORMAT, p2i(CompressedOops::begin()), p2i(CompressedOops::end())); + _heap_pointers_need_patching = true; + } else if (header()->heap_end() != CompressedOops::end()) { + log_info(cds)("CDS heap data needs to be relocated to the end of the runtime heap to reduce fragmentation"); + _heap_pointers_need_patching = true; + } + } else { + MemRegion range((HeapWord*)header()->heap_begin(), (HeapWord*)header()->heap_end()); + if (!G1CollectedHeap::heap()->reserved().contains(range)) { + log_info(cds)("CDS heap data needs to be relocated because"); + log_info(cds)("the desired range " PTR_FORMAT " - " PTR_FORMAT, p2i(range.start()), p2i(range.end())); + log_info(cds)("is outside of the heap " PTR_FORMAT " - " PTR_FORMAT, + p2i((address)G1CollectedHeap::heap()->reserved().start()), p2i((address)G1CollectedHeap::heap()->reserved().end())); + _heap_pointers_need_patching = true; + } else if (header()->heap_end() != (address)G1CollectedHeap::heap()->reserved().end()) { + log_info(cds)("CDS heap data needs to be relocated to the end of the runtime heap to reduce fragmentation"); + _heap_pointers_need_patching = true; + } } } ptrdiff_t delta = 0; if (_heap_pointers_need_patching) { // dumptime heap end ------------v - // [ |archived heap regions| ] runtime heap end ------v + // [ |archived heap regions| ] run time heap end -----v // [ |archived heap regions| ] + // ^ + // D ^ + // R // |<-----delta-------------------->| // // At dump time, the archived heap regions were near the top of the heap. - // At run time, they may not be inside the heap, so we move them so - // that they are now near the top of the runtime time. This can be done by + // At run time, if the heap ends at a different address, we need to + // move them near to top of the run time heap. This can be done by // the simple math of adding the delta as shown above. + // + // Also: D = bottom of a heap region at dump time + // R = bottom of a heap region at run time + // + // FileMapRegion* spc = ...; + // address D = header()->heap_begin() + spc->mapping_offset(); + // address R = D + delta; address dumptime_heap_end = header()->heap_end(); - address runtime_heap_end = CompressedOops::end(); + address runtime_heap_end = UseCompressedOops ? CompressedOops::end() : + (address)G1CollectedHeap::heap()->reserved().end(); delta = runtime_heap_end - dumptime_heap_end; } log_info(cds)("CDS heap data relocation delta = " INTX_FORMAT " bytes", delta); - HeapShared::init_narrow_oop_decoding(narrow_oop_base() + delta, narrow_oop_shift()); + + set_shared_heap_runtime_delta(delta); FileMapRegion* si = space_at(MetaspaceShared::first_closed_heap_region); - address relocated_closed_heap_region_bottom = start_address_as_decoded_from_archive(si); + address relocated_closed_heap_region_bottom = heap_region_runtime_start_address(si); + if (!is_aligned(relocated_closed_heap_region_bottom, HeapRegion::GrainBytes)) { // Align the bottom of the closed archive heap regions at G1 region boundary. // This will avoid the situation where the highest open region and the lowest @@ -2013,13 +2164,22 @@ void FileMapInfo::map_heap_regions_impl() { log_info(cds)("CDS heap data needs to be relocated lower by a further " SIZE_FORMAT " bytes to " INTX_FORMAT " to be aligned with HeapRegion::GrainBytes", align, delta); - HeapShared::init_narrow_oop_decoding(narrow_oop_base() + delta, narrow_oop_shift()); + set_shared_heap_runtime_delta(delta); + relocated_closed_heap_region_bottom = heap_region_runtime_start_address(si); _heap_pointers_need_patching = true; - relocated_closed_heap_region_bottom = start_address_as_decoded_from_archive(si); } assert(is_aligned(relocated_closed_heap_region_bottom, HeapRegion::GrainBytes), "must be"); + if (_heap_pointers_need_patching) { + char* bitmap_base = map_bitmap_region(); + if (bitmap_base == NULL) { + log_info(cds)("CDS heap cannot be used because bitmap region cannot be mapped"); + _heap_pointers_need_patching = false; + return; + } + } + // Map the closed heap regions: GC does not write into these regions. if (map_heap_regions(MetaspaceShared::first_closed_heap_region, MetaspaceShared::max_num_closed_heap_regions, @@ -2033,7 +2193,6 @@ void FileMapInfo::map_heap_regions_impl() { /*is_open_archive=*/ true, &open_heap_regions, &num_open_heap_regions)) { HeapShared::set_open_regions_mapped(); - HeapShared::set_roots(header()->heap_obj_roots()); } } } @@ -2074,7 +2233,7 @@ bool FileMapInfo::map_heap_regions(int first, int max, bool is_open_archive, si = space_at(i); size_t size = si->used(); if (size > 0) { - HeapWord* start = (HeapWord*)start_address_as_decoded_from_archive(si); + HeapWord* start = (HeapWord*)heap_region_runtime_start_address(si); regions[num_regions] = MemRegion(start, size / HeapWordSize); num_regions ++; log_info(cds)("Trying to map heap data: region[%d] at " INTPTR_FORMAT ", size = " SIZE_FORMAT_W(8) " bytes", @@ -2150,9 +2309,7 @@ void FileMapInfo::patch_heap_embedded_pointers() { void FileMapInfo::patch_heap_embedded_pointers(MemRegion* regions, int num_regions, int first_region_idx) { char* bitmap_base = map_bitmap_region(); - if (bitmap_base == NULL) { - return; - } + assert(bitmap_base != NULL, "must have already been mapped"); for (int i=0; iis_jar(), "must be"); // other types of scpe will not produce archived classes + + const char* path = scpe->name(); + struct stat st; + if (os::stat(path, &st) != 0) { + char *msg = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, strlen(path) + 128); + jio_snprintf(msg, strlen(path) + 127, "error in finding JAR file %s", path); + THROW_MSG_(vmSymbols::java_io_IOException(), msg, NULL); } else { - SharedClassPathEntry* scpe = shared_path(i); - assert(scpe->is_jar(), "must be"); // other types of scpe will not produce archived classes - - const char* path = scpe->name(); - struct stat st; - if (os::stat(path, &st) != 0) { + ent = ClassLoader::create_class_path_entry(THREAD, path, &st, false, false); + if (ent == NULL) { char *msg = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, strlen(path) + 128); - jio_snprintf(msg, strlen(path) + 127, "error in finding JAR file %s", path); + jio_snprintf(msg, strlen(path) + 127, "error in opening JAR file %s", path); THROW_MSG_(vmSymbols::java_io_IOException(), msg, NULL); - } else { - ent = ClassLoader::create_class_path_entry(THREAD, path, &st, false, false); - if (ent == NULL) { - char *msg = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, strlen(path) + 128); - jio_snprintf(msg, strlen(path) + 127, "error in opening JAR file %s", path); - THROW_MSG_(vmSymbols::java_io_IOException(), msg, NULL); - } } } diff --git a/src/hotspot/share/cds/filemap.hpp b/src/hotspot/share/cds/filemap.hpp index 816ac5469dc5d7d548ddd3671f8256e4062ede9e..f34fb4d72117efb3b3b1bae01ffa0b5f8f632f47 100644 --- a/src/hotspot/share/cds/filemap.hpp +++ b/src/hotspot/share/cds/filemap.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -232,7 +232,6 @@ private: // some expensive operations. bool _use_full_module_graph; // Can we use the full archived module graph? size_t _ptrmap_size_in_bits; // Size of pointer relocation bitmap - narrowOop _heap_obj_roots; // An objArray that stores all the roots of archived heap objects char* from_mapped_offset(size_t offset) const { return mapped_base_address() + offset; } @@ -279,14 +278,12 @@ public: jshort app_module_paths_start_index() const { return _app_module_paths_start_index; } jshort app_class_paths_start_index() const { return _app_class_paths_start_index; } jshort num_module_paths() const { return _num_module_paths; } - narrowOop heap_obj_roots() const { return _heap_obj_roots; } void set_has_platform_or_app_classes(bool v) { _has_platform_or_app_classes = v; } void set_cloned_vtables(char* p) { set_as_offset(p, &_cloned_vtables_offset); } void set_serialized_data(char* p) { set_as_offset(p, &_serialized_data_offset); } void set_ptrmap_size_in_bits(size_t s) { _ptrmap_size_in_bits = s; } void set_mapped_base_address(char* p) { _mapped_base_address = p; } - void set_heap_obj_roots(narrowOop r) { _heap_obj_roots = r; } void copy_base_archive_name(const char* name); void set_shared_path_table(SharedPathTable table) { @@ -354,12 +351,10 @@ private: static bool _memory_mapping_failed; static GrowableArray* _non_existent_class_paths; - FileMapHeader *header() const { return _header; } - public: + FileMapHeader *header() const { return _header; } static bool get_base_archive_name_from_header(const char* archive_name, char** base_archive_name); - static bool check_archive(const char* archive_name, bool is_static); static SharedPathTable shared_path_table() { return _shared_path_table; } @@ -373,7 +368,7 @@ public: void log_paths(const char* msg, int start_idx, int end_idx); - FileMapInfo(bool is_static); + FileMapInfo(const char* full_apth, bool is_static); ~FileMapInfo(); // Accessors @@ -413,8 +408,6 @@ public: void set_requested_base(char* b) { header()->set_requested_base(b); } char* requested_base_address() const { return header()->requested_base_address(); } - narrowOop heap_obj_roots() const { return header()->heap_obj_roots(); } - class DynamicArchiveHeader* dynamic_header() const { assert(!is_static(), "must be"); return (DynamicArchiveHeader*)header(); @@ -446,7 +439,7 @@ public: // File manipulation. bool initialize() NOT_CDS_RETURN_(false); bool open_for_read(); - void open_for_write(const char* path = NULL); + void open_for_write(); void write_header(); void write_region(int region, char* base, size_t size, bool read_only, bool allow_exec); @@ -498,6 +491,7 @@ public: static void clone_shared_path_table(TRAPS); static int add_shared_classpaths(int i, const char* which, ClassPathEntry *cpe, TRAPS); static void check_nonempty_dir_in_shared_path_table(); + bool check_module_paths(); bool validate_shared_path_table(); void validate_non_existent_class_paths(); static void set_shared_path_table(FileMapInfo* info) { @@ -560,6 +554,7 @@ public: void seek_to_position(size_t pos); char* skip_first_path_entry(const char* path) NOT_CDS_RETURN_(NULL); int num_paths(const char* path) NOT_CDS_RETURN_(0); + bool check_paths_existence(const char* paths) NOT_CDS_RETURN_(false); GrowableArray* create_path_array(const char* path) NOT_CDS_RETURN_(NULL); bool classpath_failure(const char* msg, const char* name) NOT_CDS_RETURN_(false); bool check_paths(int shared_path_start_idx, int num_paths, @@ -573,6 +568,8 @@ public: bool can_use_heap_regions(); bool load_heap_regions() NOT_CDS_JAVA_HEAP_RETURN_(false); bool map_heap_regions() NOT_CDS_JAVA_HEAP_RETURN_(false); + address heap_region_runtime_start_address(FileMapRegion* spc) NOT_CDS_JAVA_HEAP_RETURN_(NULL); + void set_shared_heap_runtime_delta(ptrdiff_t delta) NOT_CDS_JAVA_HEAP_RETURN; void map_heap_regions_impl() NOT_CDS_JAVA_HEAP_RETURN; MapArchiveResult map_region(int i, intx addr_delta, char* mapped_base_address, ReservedSpace rs); bool relocate_pointers_in_core_regions(intx addr_delta); diff --git a/src/hotspot/share/cds/heapShared.cpp b/src/hotspot/share/cds/heapShared.cpp index aa4694168c12e4ec25ce164670b5bf8d8be4d6a0..14bca5d74b62bce1074da9f76694faaa04a7bfb2 100644 --- a/src/hotspot/share/cds/heapShared.cpp +++ b/src/hotspot/share/cds/heapShared.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -25,6 +25,7 @@ #include "precompiled.hpp" #include "cds/archiveBuilder.hpp" #include "cds/archiveUtils.hpp" +#include "cds/cdsHeapVerifier.hpp" #include "cds/filemap.hpp" #include "cds/heapShared.inline.hpp" #include "cds/metaspaceShared.hpp" @@ -42,7 +43,6 @@ #include "gc/shared/gcLocker.hpp" #include "gc/shared/gcVMOperations.hpp" #include "logging/log.hpp" -#include "logging/logMessage.hpp" #include "logging/logStream.hpp" #include "memory/iterator.inline.hpp" #include "memory/metadataFactory.hpp" @@ -71,10 +71,12 @@ bool HeapShared::_closed_regions_mapped = false; bool HeapShared::_open_regions_mapped = false; bool HeapShared::_is_loaded = false; +bool HeapShared::_disable_writing = false; address HeapShared::_narrow_oop_base; int HeapShared::_narrow_oop_shift; DumpedInternedStrings *HeapShared::_dumped_interned_strings = NULL; +// Support for loaded heap. uintptr_t HeapShared::_loaded_heap_bottom = 0; uintptr_t HeapShared::_loaded_heap_top = 0; uintptr_t HeapShared::_dumptime_base_0 = UINTPTR_MAX; @@ -87,6 +89,10 @@ intx HeapShared::_runtime_offset_1 = 0; intx HeapShared::_runtime_offset_2 = 0; intx HeapShared::_runtime_offset_3 = 0; bool HeapShared::_loading_failed = false; + +// Suport for mapped heap (!UseCompressedOops only) +ptrdiff_t HeapShared::_runtime_delta = 0; + // // If you add new entries to the following tables, you should know what you're doing! // @@ -127,7 +133,6 @@ const static int num_fmg_open_archive_subgraph_entry_fields = sizeof(fmg_open_archive_subgraph_entry_fields) / sizeof(ArchivableStaticFieldInfo); GrowableArrayCHeap* HeapShared::_pending_roots = NULL; -narrowOop HeapShared::_roots_narrow; OopHandle HeapShared::_roots; #ifdef ASSERT @@ -138,11 +143,24 @@ bool HeapShared::is_archived_object_during_dumptime(oop p) { } #endif -//////////////////////////////////////////////////////////////// -// -// Java heap object archiving support -// -//////////////////////////////////////////////////////////////// +static bool is_subgraph_root_class_of(ArchivableStaticFieldInfo fields[], int num, InstanceKlass* ik) { + for (int i = 0; i < num; i++) { + if (fields[i].klass == ik) { + return true; + } + } + return false; +} + +bool HeapShared::is_subgraph_root_class(InstanceKlass* ik) { + return is_subgraph_root_class_of(closed_archive_subgraph_entry_fields, + num_closed_archive_subgraph_entry_fields, ik) || + is_subgraph_root_class_of(open_archive_subgraph_entry_fields, + num_open_archive_subgraph_entry_fields, ik) || + is_subgraph_root_class_of(fmg_open_archive_subgraph_entry_fields, + num_fmg_open_archive_subgraph_entry_fields, ik); +} + void HeapShared::fixup_regions() { FileMapInfo* mapinfo = FileMapInfo::current_info(); if (is_mapped()) { @@ -151,7 +169,6 @@ void HeapShared::fixup_regions() { fill_failed_loaded_region(); } if (is_fully_available()) { - _roots = OopHandle(Universe::vm_global(), decode_from_archive(_roots_narrow)); if (!MetaspaceShared::use_full_module_graph()) { // Need to remove all the archived java.lang.Module objects from HeapShared::roots(). ClassLoaderDataShared::clear_archived_oops(); @@ -199,9 +216,9 @@ HeapShared::ArchivedObjectCache* HeapShared::_archived_object_cache = NULL; oop HeapShared::find_archived_heap_object(oop obj) { assert(DumpSharedSpaces, "dump-time only"); ArchivedObjectCache* cache = archived_object_cache(); - oop* p = cache->get(obj); + CachedOopInfo* p = cache->get(obj); if (p != NULL) { - return *p; + return p->_obj; } else { return NULL; } @@ -235,12 +252,6 @@ objArrayOop HeapShared::roots() { return roots; } -void HeapShared::set_roots(narrowOop roots) { - assert(UseSharedSpaces, "runtime only"); - assert(is_fully_available(), "must be"); - _roots_narrow = roots; -} - // Returns an objArray that contains all the roots of the archived objects oop HeapShared::get_root(int index, bool clear) { assert(index >= 0, "sanity"); @@ -304,7 +315,8 @@ oop HeapShared::archive_object(oop obj) { assert(hash_original == hash_archived, "Different hash codes: original %x, archived %x", hash_original, hash_archived); ArchivedObjectCache* cache = archived_object_cache(); - cache->put(obj, archived_oop); + CachedOopInfo info = make_cached_oop_info(archived_oop); + cache->put(obj, info); if (log_is_enabled(Debug, cds, heap)) { ResourceMark rm; log_debug(cds, heap)("Archived heap object " PTR_FORMAT " ==> " PTR_FORMAT " : %s", @@ -338,6 +350,94 @@ void HeapShared::archive_klass_objects() { } } +// -- Handling of Enum objects +// Java Enum classes have synthetic methods that look like this +// enum MyEnum {FOO, BAR} +// MyEnum:: { +// /*static final MyEnum*/ MyEnum::FOO = new MyEnum("FOO"); +// /*static final MyEnum*/ MyEnum::BAR = new MyEnum("BAR"); +// } +// +// If MyEnum::FOO object is referenced by any of the archived subgraphs, we must +// ensure the archived value equals (in object address) to the runtime value of +// MyEnum::FOO. +// +// However, since MyEnum:: is synthetically generated by javac, there's +// no way of programatically handling this inside the Java code (as you would handle +// ModuleLayer::EMPTY_LAYER, for example). +// +// Instead, we archive all static field of such Enum classes. At runtime, +// HeapShared::initialize_enum_klass() will skip the method and pull +// the static fields out of the archived heap. +void HeapShared::check_enum_obj(int level, + KlassSubGraphInfo* subgraph_info, + oop orig_obj, + bool is_closed_archive) { + Klass* k = orig_obj->klass(); + Klass* relocated_k = ArchiveBuilder::get_relocated_klass(k); + if (!k->is_instance_klass()) { + return; + } + InstanceKlass* ik = InstanceKlass::cast(k); + if (ik->java_super() == vmClasses::Enum_klass() && !ik->has_archived_enum_objs()) { + ResourceMark rm; + ik->set_has_archived_enum_objs(); + relocated_k->set_has_archived_enum_objs(); + oop mirror = ik->java_mirror(); + + for (JavaFieldStream fs(ik); !fs.done(); fs.next()) { + if (fs.access_flags().is_static()) { + fieldDescriptor& fd = fs.field_descriptor(); + if (fd.field_type() != T_OBJECT && fd.field_type() != T_ARRAY) { + guarantee(false, "static field %s::%s must be T_OBJECT or T_ARRAY", + ik->external_name(), fd.name()->as_C_string()); + } + oop oop_field = mirror->obj_field(fd.offset()); + if (oop_field == NULL) { + guarantee(false, "static field %s::%s must not be null", + ik->external_name(), fd.name()->as_C_string()); + } else if (oop_field->klass() != ik && oop_field->klass() != ik->array_klass_or_null()) { + guarantee(false, "static field %s::%s is of the wrong type", + ik->external_name(), fd.name()->as_C_string()); + } + oop archived_oop_field = archive_reachable_objects_from(level, subgraph_info, oop_field, is_closed_archive); + int root_index = append_root(archived_oop_field); + log_info(cds, heap)("Archived enum obj @%d %s::%s (" INTPTR_FORMAT " -> " INTPTR_FORMAT ")", + root_index, ik->external_name(), fd.name()->as_C_string(), + p2i((oopDesc*)oop_field), p2i((oopDesc*)archived_oop_field)); + SystemDictionaryShared::add_enum_klass_static_field(ik, root_index); + } + } + } +} + +// See comments in HeapShared::check_enum_obj() +bool HeapShared::initialize_enum_klass(InstanceKlass* k, TRAPS) { + if (!is_fully_available()) { + return false; + } + + RunTimeClassInfo* info = RunTimeClassInfo::get_for(k); + assert(info != NULL, "sanity"); + + if (log_is_enabled(Info, cds, heap)) { + ResourceMark rm; + log_info(cds, heap)("Initializing Enum class: %s", k->external_name()); + } + + oop mirror = k->java_mirror(); + int i = 0; + for (JavaFieldStream fs(k); !fs.done(); fs.next()) { + if (fs.access_flags().is_static()) { + int root_index = info->enum_klass_static_field_root_index_at(i++); + fieldDescriptor& fd = fs.field_descriptor(); + assert(fd.field_type() == T_OBJECT || fd.field_type() == T_ARRAY, "must be"); + mirror->obj_field_put(fd.offset(), get_root(root_index, /*clear=*/true)); + } + } + return true; +} + void HeapShared::run_full_gc_in_vm_thread() { if (HeapShared::can_write()) { // Avoid fragmentation while archiving heap objects. @@ -369,13 +469,17 @@ void HeapShared::archive_objects(GrowableArray* closed_regions, create_archived_object_cache(); log_info(cds)("Heap range = [" PTR_FORMAT " - " PTR_FORMAT "]", - p2i(CompressedOops::begin()), p2i(CompressedOops::end())); + UseCompressedOops ? p2i(CompressedOops::begin()) : + p2i((address)G1CollectedHeap::heap()->reserved().start()), + UseCompressedOops ? p2i(CompressedOops::end()) : + p2i((address)G1CollectedHeap::heap()->reserved().end())); log_info(cds)("Dumping objects to closed archive heap region ..."); copy_closed_objects(closed_regions); log_info(cds)("Dumping objects to open archive heap region ..."); copy_open_objects(open_regions); + CDSHeapVerifier::verify(); destroy_archived_object_cache(); } @@ -470,7 +574,7 @@ KlassSubGraphInfo* HeapShared::init_subgraph_info(Klass* k, bool is_full_module_ bool created; Klass* relocated_k = ArchiveBuilder::get_relocated_klass(k); KlassSubGraphInfo* info = - _dump_time_subgraph_info_table->put_if_absent(relocated_k, KlassSubGraphInfo(relocated_k, is_full_module_graph), + _dump_time_subgraph_info_table->put_if_absent(k, KlassSubGraphInfo(relocated_k, is_full_module_graph), &created); assert(created, "must not initialize twice"); return info; @@ -478,8 +582,7 @@ KlassSubGraphInfo* HeapShared::init_subgraph_info(Klass* k, bool is_full_module_ KlassSubGraphInfo* HeapShared::get_subgraph_info(Klass* k) { assert(DumpSharedSpaces, "dump time only"); - Klass* relocated_k = ArchiveBuilder::get_relocated_klass(k); - KlassSubGraphInfo* info = _dump_time_subgraph_info_table->get(relocated_k); + KlassSubGraphInfo* info = _dump_time_subgraph_info_table->get(k); assert(info != NULL, "must have been initialized"); return info; } @@ -640,7 +743,8 @@ struct CopyKlassSubGraphInfoToArchive : StackObj { (ArchivedKlassSubGraphInfoRecord*)ArchiveBuilder::ro_region_alloc(sizeof(ArchivedKlassSubGraphInfoRecord)); record->init(&info); - unsigned int hash = SystemDictionaryShared::hash_for_shared_dictionary((address)klass); + Klass* relocated_k = ArchiveBuilder::get_relocated_klass(klass); + unsigned int hash = SystemDictionaryShared::hash_for_shared_dictionary((address)relocated_k); u4 delta = ArchiveBuilder::current()->any_to_offset_u4(record); _writer->add(hash, delta); } @@ -665,11 +769,26 @@ void HeapShared::write_subgraph_info_table() { CompactHashtableWriter writer(d_table->_count, &stats); CopyKlassSubGraphInfoToArchive copy(&writer); d_table->iterate(©); - writer.dump(&_run_time_subgraph_info_table, "subgraphs"); } -void HeapShared::serialize_subgraph_info_table_header(SerializeClosure* soc) { +void HeapShared::serialize(SerializeClosure* soc) { + oop roots_oop = NULL; + + if (soc->reading()) { + soc->do_oop(&roots_oop); // read from archive + assert(oopDesc::is_oop_or_null(roots_oop), "is oop"); + // Create an OopHandle only if we have actually mapped or loaded the roots + if (roots_oop != NULL) { + assert(HeapShared::is_fully_available(), "must be"); + _roots = OopHandle(Universe::vm_global(), roots_oop); + } + } else { + // writing + roots_oop = roots(); + soc->do_oop(&roots_oop); // write to archive + } + _run_time_subgraph_info_table.serialize_header(soc); } @@ -887,6 +1006,11 @@ class WalkOopAndArchiveClosure: public BasicOopIterateClosure { KlassSubGraphInfo* _subgraph_info; oop _orig_referencing_obj; oop _archived_referencing_obj; + + // The following are for maintaining a stack for determining + // CachedOopInfo::_referrer + static WalkOopAndArchiveClosure* _current; + WalkOopAndArchiveClosure* _last; public: WalkOopAndArchiveClosure(int level, bool is_closed_archive, @@ -896,7 +1020,13 @@ class WalkOopAndArchiveClosure: public BasicOopIterateClosure { _level(level), _is_closed_archive(is_closed_archive), _record_klasses_only(record_klasses_only), _subgraph_info(subgraph_info), - _orig_referencing_obj(orig), _archived_referencing_obj(archived) {} + _orig_referencing_obj(orig), _archived_referencing_obj(archived) { + _last = _current; + _current = this; + } + ~WalkOopAndArchiveClosure() { + _current = _last; + } void do_oop(narrowOop *p) { WalkOopAndArchiveClosure::do_oop_work(p); } void do_oop( oop *p) { WalkOopAndArchiveClosure::do_oop_work(p); } @@ -933,8 +1063,26 @@ class WalkOopAndArchiveClosure: public BasicOopIterateClosure { } } } + + public: + static WalkOopAndArchiveClosure* current() { return _current; } + oop orig_referencing_obj() { return _orig_referencing_obj; } + KlassSubGraphInfo* subgraph_info() { return _subgraph_info; } }; +WalkOopAndArchiveClosure* WalkOopAndArchiveClosure::_current = NULL; + +HeapShared::CachedOopInfo HeapShared::make_cached_oop_info(oop orig_obj) { + CachedOopInfo info; + WalkOopAndArchiveClosure* walker = WalkOopAndArchiveClosure::current(); + + info._subgraph_info = (walker == NULL) ? NULL : walker->subgraph_info(); + info._referrer = (walker == NULL) ? NULL : walker->orig_referencing_obj(); + info._obj = orig_obj; + + return info; +} + void HeapShared::check_closed_region_object(InstanceKlass* k) { // Check fields in the object for (JavaFieldStream fs(k); !fs.done(); fs.next()) { @@ -1060,6 +1208,8 @@ oop HeapShared::archive_reachable_objects_from(int level, if (is_closed_archive && orig_k->is_instance_klass()) { check_closed_region_object(InstanceKlass::cast(orig_k)); } + + check_enum_obj(level + 1, subgraph_info, orig_obj, is_closed_archive); return archived_obj; } @@ -1391,39 +1541,44 @@ void HeapShared::add_to_dumped_interned_strings(oop string) { // region. This way we can quickly relocate all the pointers without using // BasicOopIterateClosure at runtime. class FindEmbeddedNonNullPointers: public BasicOopIterateClosure { - narrowOop* _start; + void* _start; BitMap *_oopmap; int _num_total_oops; int _num_null_oops; public: - FindEmbeddedNonNullPointers(narrowOop* start, BitMap* oopmap) + FindEmbeddedNonNullPointers(void* start, BitMap* oopmap) : _start(start), _oopmap(oopmap), _num_total_oops(0), _num_null_oops(0) {} virtual void do_oop(narrowOop* p) { _num_total_oops ++; narrowOop v = *p; if (!CompressedOops::is_null(v)) { - size_t idx = p - _start; + size_t idx = p - (narrowOop*)_start; _oopmap->set_bit(idx); } else { _num_null_oops ++; } } - virtual void do_oop(oop *p) { - ShouldNotReachHere(); + virtual void do_oop(oop* p) { + _num_total_oops ++; + if ((*p) != NULL) { + size_t idx = p - (oop*)_start; + _oopmap->set_bit(idx); + } else { + _num_null_oops ++; + } } int num_total_oops() const { return _num_total_oops; } int num_null_oops() const { return _num_null_oops; } }; ResourceBitMap HeapShared::calculate_oopmap(MemRegion region) { - assert(UseCompressedOops, "must be"); - size_t num_bits = region.byte_size() / sizeof(narrowOop); + size_t num_bits = region.byte_size() / (UseCompressedOops ? sizeof(narrowOop) : sizeof(oop)); ResourceBitMap oopmap(num_bits); HeapWord* p = region.start(); HeapWord* end = region.end(); - FindEmbeddedNonNullPointers finder((narrowOop*)p, &oopmap); + FindEmbeddedNonNullPointers finder((void*)p, &oopmap); ArchiveBuilder* builder = DumpSharedSpaces ? ArchiveBuilder::current() : NULL; int num_objs = 0; @@ -1444,11 +1599,11 @@ ResourceBitMap HeapShared::calculate_oopmap(MemRegion region) { // Patch all the embedded oop pointers inside an archived heap region, // to be consistent with the runtime oop encoding. -class PatchEmbeddedPointers: public BitMapClosure { +class PatchCompressedEmbeddedPointers: public BitMapClosure { narrowOop* _start; public: - PatchEmbeddedPointers(narrowOop* start) : _start(start) {} + PatchCompressedEmbeddedPointers(narrowOop* start) : _start(start) {} bool do_bit(size_t offset) { narrowOop* p = _start + offset; @@ -1460,6 +1615,22 @@ class PatchEmbeddedPointers: public BitMapClosure { } }; +class PatchUncompressedEmbeddedPointers: public BitMapClosure { + oop* _start; + + public: + PatchUncompressedEmbeddedPointers(oop* start) : _start(start) {} + + 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 + HeapShared::runtime_delta(); + RawAccess::oop_store(p, cast_to_oop(runtime_oop)); + return true; + } +}; + // Patch all the non-null pointers that are embedded in the archived heap objects // in this region void HeapShared::patch_embedded_pointers(MemRegion region, address oopmap, @@ -1472,8 +1643,13 @@ void HeapShared::patch_embedded_pointers(MemRegion region, address oopmap, assert(bm.is_same(checkBm), "sanity"); #endif - PatchEmbeddedPointers patcher((narrowOop*)region.start()); - bm.iterate(&patcher); + if (UseCompressedOops) { + PatchCompressedEmbeddedPointers patcher((narrowOop*)region.start()); + bm.iterate(&patcher); + } else { + PatchUncompressedEmbeddedPointers patcher((oop*)region.start()); + bm.iterate(&patcher); + } } // The CDS archive remembers each heap object by its address at dump time, but @@ -1637,6 +1813,10 @@ void HeapShared::sort_loaded_regions(LoadedArchiveHeapRegion* loaded_regions, in bool HeapShared::load_regions(FileMapInfo* mapinfo, LoadedArchiveHeapRegion* loaded_regions, int num_loaded_regions, uintptr_t buffer) { uintptr_t bitmap_base = (uintptr_t)mapinfo->map_bitmap_region(); + if (bitmap_base == 0) { + _loading_failed = true; + return false; // OOM or CRC error + } uintptr_t load_address = buffer; for (int i = 0; i < num_loaded_regions; i++) { LoadedArchiveHeapRegion* ri = &loaded_regions[i]; @@ -1694,7 +1874,6 @@ bool HeapShared::load_heap_regions(FileMapInfo* mapinfo) { init_loaded_heap_relocation(loaded_regions, num_loaded_regions); _is_loaded = true; - set_roots(mapinfo->heap_obj_roots()); return true; } diff --git a/src/hotspot/share/cds/heapShared.hpp b/src/hotspot/share/cds/heapShared.hpp index 0a673c51e864f7cd3d668f6e65d4f8d154848a17..d8fc71fc76e9ba1279401c392363a6cb8f7fcfc4 100644 --- a/src/hotspot/share/cds/heapShared.hpp +++ b/src/hotspot/share/cds/heapShared.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -25,6 +25,7 @@ #ifndef SHARE_CDS_HEAPSHARED_HPP #define SHARE_CDS_HEAPSHARED_HPP +#include "cds/dumpTimeClassInfo.hpp" #include "cds/metaspaceShared.hpp" #include "classfile/compactHashtable.hpp" #include "classfile/javaClasses.hpp" @@ -43,6 +44,7 @@ #if INCLUDE_CDS_JAVA_HEAP class DumpedInternedStrings; class FileMapInfo; +class KlassSubGraphInfo; struct ArchivableStaticFieldInfo { const char* klass_name; @@ -155,13 +157,21 @@ public: // Can this VM write heap regions into the CDS archive? Currently only G1+compressed{oops,cp} static bool can_write() { - CDS_JAVA_HEAP_ONLY(return (UseG1GC && UseCompressedOops && UseCompressedClassPointers);) + CDS_JAVA_HEAP_ONLY( + if (_disable_writing) { + return false; + } + return (UseG1GC && UseCompressedClassPointers); + ) NOT_CDS_JAVA_HEAP(return false;) } + static void disable_writing() { + CDS_JAVA_HEAP_ONLY(_disable_writing = true;) + } // Can this VM map archived heap regions? Currently only G1+compressed{oops,cp} static bool can_map() { - CDS_JAVA_HEAP_ONLY(return (UseG1GC && UseCompressedOops && UseCompressedClassPointers);) + CDS_JAVA_HEAP_ONLY(return (UseG1GC && UseCompressedClassPointers);) NOT_CDS_JAVA_HEAP(return false;) } static bool is_mapped() { @@ -185,9 +195,10 @@ public: static bool is_fully_available() { return is_loaded() || is_mapped(); } - + static bool is_subgraph_root_class(InstanceKlass* ik); private: #if INCLUDE_CDS_JAVA_HEAP + static bool _disable_writing; static bool _closed_regions_mapped; static bool _open_regions_mapped; static bool _is_loaded; @@ -219,29 +230,35 @@ public: assert(is_in_loaded_heap(o), "must be"); } + struct CachedOopInfo { + KlassSubGraphInfo* _subgraph_info; + oop _referrer; + oop _obj; + CachedOopInfo() :_subgraph_info(), _referrer(), _obj() {} + }; + private: + static void check_enum_obj(int level, + KlassSubGraphInfo* subgraph_info, + oop orig_obj, + bool is_closed_archive); static bool is_in_loaded_heap(uintptr_t o) { return (_loaded_heap_bottom <= o && o < _loaded_heap_top); } - typedef ResourceHashtable ArchivedObjectCache; static ArchivedObjectCache* _archived_object_cache; - static unsigned klass_hash(Klass* const& klass) { - // Generate deterministic hashcode even if SharedBaseAddress is changed due to ASLR. - return primitive_hash
      (address(klass) - SharedBaseAddress); - } - class DumpTimeKlassSubGraphInfoTable : public ResourceHashtable { + DumpTimeSharedClassTable_hash> { public: int _count; }; @@ -263,7 +280,7 @@ private: static RunTimeKlassSubGraphInfoTable _run_time_subgraph_info_table; static void check_closed_region_object(InstanceKlass* k); - + static CachedOopInfo make_cached_oop_info(oop orig_obj); static void archive_object_subgraphs(ArchivableStaticFieldInfo fields[], int num, bool is_closed_archive, @@ -288,10 +305,13 @@ private: static void init_subgraph_entry_fields(ArchivableStaticFieldInfo fields[], int num, TRAPS); - // Used by decode_from_archive + // UseCompressedOops only: Used by decode_from_archive static address _narrow_oop_base; static int _narrow_oop_shift; + // !UseCompressedOops only: used to relocate pointers to the archived objects + static ptrdiff_t _runtime_delta; + typedef ResourceHashtable* _pending_roots; - static narrowOop _roots_narrow; static OopHandle _roots; static void init_seen_objects_table() { @@ -409,11 +428,22 @@ private: static oop get_root(int index, bool clear=false); // Run-time only - static void set_roots(narrowOop roots); static void clear_root(int index); + + static void set_runtime_delta(ptrdiff_t delta) { + assert(!UseCompressedOops, "must be"); + _runtime_delta = delta; + } + #endif // INCLUDE_CDS_JAVA_HEAP public: + static ptrdiff_t runtime_delta() { + assert(!UseCompressedOops, "must be"); + CDS_JAVA_HEAP_ONLY(return _runtime_delta;) + NOT_CDS_JAVA_HEAP_RETURN_(0L); + } + static void run_full_gc_in_vm_thread() NOT_CDS_JAVA_HEAP_RETURN; static bool is_heap_region(int idx) { @@ -459,7 +489,8 @@ private: static void init_for_dumping(TRAPS) NOT_CDS_JAVA_HEAP_RETURN; static void write_subgraph_info_table() NOT_CDS_JAVA_HEAP_RETURN; - static void serialize_subgraph_info_table_header(SerializeClosure* soc) NOT_CDS_JAVA_HEAP_RETURN; + static void serialize(SerializeClosure* soc) NOT_CDS_JAVA_HEAP_RETURN; + static bool initialize_enum_klass(InstanceKlass* k, TRAPS) NOT_CDS_JAVA_HEAP_RETURN_(false); }; #if INCLUDE_CDS_JAVA_HEAP diff --git a/src/hotspot/share/cds/lambdaFormInvokers.cpp b/src/hotspot/share/cds/lambdaFormInvokers.cpp index 5c058dc43ac131746c1ccb919189b51a94f56776..bf49f94b6820c4f689fbc2f8b9d110ed146d2df7 100644 --- a/src/hotspot/share/cds/lambdaFormInvokers.cpp +++ b/src/hotspot/share/cds/lambdaFormInvokers.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -39,10 +39,11 @@ #include "memory/oopFactory.hpp" #include "memory/resourceArea.hpp" #include "oops/instanceKlass.hpp" -#include "oops/klass.hpp" +#include "oops/klass.inline.hpp" #include "oops/objArrayKlass.hpp" #include "oops/objArrayOop.hpp" #include "oops/oop.inline.hpp" +#include "oops/oopHandle.inline.hpp" #include "oops/typeArrayOop.inline.hpp" #include "runtime/handles.inline.hpp" #include "runtime/javaCalls.hpp" @@ -50,6 +51,7 @@ GrowableArrayCHeap* LambdaFormInvokers::_lambdaform_lines = nullptr; Array*>* LambdaFormInvokers::_static_archive_invokers = nullptr; +GrowableArrayCHeap* LambdaFormInvokers::_regenerated_mirrors = nullptr; #define NUM_FILTER 4 static const char* filter[NUM_FILTER] = {"java.lang.invoke.Invokers$Holder", @@ -65,12 +67,6 @@ static bool should_be_archived(char* line) { } return false; } - -void LambdaFormInvokers::append_filtered(char* line) { - if (should_be_archived(line)) { - append(line); - } -} #undef NUM_FILTER void LambdaFormInvokers::append(char* line) { @@ -81,6 +77,25 @@ void LambdaFormInvokers::append(char* line) { _lambdaform_lines->append(line); } +// The regenerated Klass is not added to any class loader, so we need +// to keep its java_mirror alive to avoid class unloading. +void LambdaFormInvokers::add_regenerated_class(oop regenerated_class) { + if (_regenerated_mirrors == nullptr) { + _regenerated_mirrors = new GrowableArrayCHeap(150); + } + _regenerated_mirrors->append(OopHandle(Universe::vm_global(), regenerated_class)); +} + +void LambdaFormInvokers::cleanup_regenerated_classes() { + if (_regenerated_mirrors == nullptr) return; + + for (int i = 0; i < _regenerated_mirrors->length(); i++) { + _regenerated_mirrors->at(i).release(Universe::vm_global()); + } + delete _regenerated_mirrors; + _regenerated_mirrors = nullptr; +} + // convenient output class PrintLambdaFormMessage { public: @@ -155,12 +170,20 @@ void LambdaFormInvokers::regenerate_holder_classes(TRAPS) { char *buf = NEW_RESOURCE_ARRAY(char, len); memcpy(buf, (char*)h_bytes->byte_at_addr(0), len); ClassFileStream st((u1*)buf, len, NULL, ClassFileStream::verify); - reload_class(class_name, st, CHECK); + regenerate_class(class_name, st, CHECK); } } -// class_handle - the class name, bytes_handle - the class bytes -void LambdaFormInvokers::reload_class(char* name, ClassFileStream& st, TRAPS) { +// check if a class name is a species +bool is_a_species(const char* species_name) { + log_info(cds)("Checking class %s", species_name); + if (strstr(species_name, "java/lang/invoke/BoundMethodHandle$Species_") != nullptr) { + return true; + } + return false; +} + +void LambdaFormInvokers::regenerate_class(char* name, ClassFileStream& st, TRAPS) { Symbol* class_name = SymbolTable::new_symbol((const char*)name); // the class must exist Klass* klass = SystemDictionary::resolve_or_null(class_name, THREAD); @@ -168,6 +191,12 @@ void LambdaFormInvokers::reload_class(char* name, ClassFileStream& st, TRAPS) { log_info(cds)("Class %s not present, skip", name); return; } + // the species is shared in base archive, skip it. + if (klass->is_regenerated() && is_a_species(name)) { + log_info(cds)("Skip regenerating for shared %s", name); + return; + } + assert(klass->is_instance_klass(), "Should be"); ClassLoaderData* cld = ClassLoaderData::the_null_class_loader_data(); @@ -180,6 +209,9 @@ void LambdaFormInvokers::reload_class(char* name, ClassFileStream& st, TRAPS) { cl_info, CHECK); + assert(result->java_mirror() != nullptr, "must be"); + add_regenerated_class(result->java_mirror()); + { MutexLocker mu_r(THREAD, Compile_lock); // add_to_hierarchy asserts this. SystemDictionary::add_to_hierarchy(result); @@ -188,10 +220,10 @@ void LambdaFormInvokers::reload_class(char* name, ClassFileStream& st, TRAPS) { MetaspaceShared::try_link_class(THREAD, result); assert(!HAS_PENDING_EXCEPTION, "Invariant"); - // exclude the existing class from dump - SystemDictionaryShared::set_excluded(InstanceKlass::cast(klass)); + result->set_regenerated(); // mark for regenerated + SystemDictionaryShared::set_excluded(InstanceKlass::cast(klass)); // exclude the existing class from dump SystemDictionaryShared::init_dumptime_info(result); - log_info(cds, lambda)("Replaced class %s, old: " INTPTR_FORMAT " new: " INTPTR_FORMAT, + log_info(cds, lambda)("Regenerated class %s, old: " INTPTR_FORMAT " new: " INTPTR_FORMAT, name, p2i(klass), p2i(result)); } diff --git a/src/hotspot/share/cds/lambdaFormInvokers.hpp b/src/hotspot/share/cds/lambdaFormInvokers.hpp index acb5eab4d8adeb989c5314e0b72672f71dc390a3..9463427eeca4d0c39bd7091f319f3b9ea5d8c302 100644 --- a/src/hotspot/share/cds/lambdaFormInvokers.hpp +++ b/src/hotspot/share/cds/lambdaFormInvokers.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -25,6 +25,7 @@ #ifndef SHARE_CDS_LAMBDAFORMINVOKERS_HPP #define SHARE_CDS_LAMBDAFORMINVOKERS_HPP #include "memory/allStatic.hpp" +#include "oops/oopHandle.hpp" #include "runtime/handles.hpp" #include "utilities/growableArray.hpp" @@ -37,13 +38,15 @@ class LambdaFormInvokers : public AllStatic { static GrowableArrayCHeap* _lambdaform_lines; // For storing LF form lines (LF_RESOLVE only) in read only table. static Array*>* _static_archive_invokers; - static void reload_class(char* name, ClassFileStream& st, TRAPS); + static GrowableArrayCHeap* _regenerated_mirrors; + static void regenerate_class(char* name, ClassFileStream& st, TRAPS); + static void add_regenerated_class(oop regenerated_class); public: static void append(char* line); - static void append_filtered(char* line); static void dump_static_archive_invokers(); static void read_static_archive_invokers(); static void regenerate_holder_classes(TRAPS); static void serialize(SerializeClosure* soc); + static void cleanup_regenerated_classes(); }; #endif // SHARE_CDS_LAMBDAFORMINVOKERS_HPP diff --git a/src/hotspot/share/cds/metaspaceShared.cpp b/src/hotspot/share/cds/metaspaceShared.cpp index 17e27a5372f6a65fced5c0f6a7af3a94c1c486af..10e96df575b3f84e166b6f0ca4178f320ad0ca09 100644 --- a/src/hotspot/share/cds/metaspaceShared.cpp +++ b/src/hotspot/share/cds/metaspaceShared.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -65,6 +65,7 @@ #include "oops/oopHandle.hpp" #include "prims/jvmtiExport.hpp" #include "runtime/arguments.hpp" +#include "runtime/globals_extension.hpp" #include "runtime/handles.inline.hpp" #include "runtime/os.hpp" #include "runtime/safepointVerifiers.hpp" @@ -384,7 +385,7 @@ void MetaspaceShared::serialize(SerializeClosure* soc) { // Dump/restore the symbol/string/subgraph_info tables SymbolTable::serialize_shared_table_header(soc); StringTable::serialize_shared_table_header(soc); - HeapShared::serialize_subgraph_info_table_header(soc); + HeapShared::serialize(soc); SystemDictionaryShared::serialize_dictionary_headers(soc); InstanceMirrorKlass::serialize_offsets(soc); @@ -556,7 +557,9 @@ void VM_PopulateDumpSharedSpace::doit() { builder.relocate_to_requested(); // Write the archive file - FileMapInfo* mapinfo = new FileMapInfo(true); + const char* static_archive = Arguments::GetSharedArchivePath(); + assert(static_archive != nullptr, "SharedArchiveFile not set?"); + FileMapInfo* mapinfo = new FileMapInfo(static_archive, true); mapinfo->populate_header(MetaspaceShared::core_region_alignment()); mapinfo->set_serialized_data(serialized_data); mapinfo->set_cloned_vtables(cloned_vtables); @@ -596,7 +599,7 @@ public: void do_cld(ClassLoaderData* cld) { assert(cld->is_alive(), "must be"); _loaded_cld.append(cld); - _loaded_cld_handles.append(OopHandle(Universe::vm_global(), cld->holder_phantom())); + _loaded_cld_handles.append(OopHandle(Universe::vm_global(), cld->holder())); } int nof_cld() const { return _loaded_cld.length(); } @@ -640,8 +643,10 @@ bool MetaspaceShared::link_class_for_cds(InstanceKlass* ik, TRAPS) { return res; } -void MetaspaceShared::link_shared_classes(TRAPS) { - LambdaFormInvokers::regenerate_holder_classes(CHECK); +void MetaspaceShared::link_shared_classes(bool jcmd_request, TRAPS) { + if (!jcmd_request) { + LambdaFormInvokers::regenerate_holder_classes(CHECK); + } // Collect all loaded ClassLoaderData. CollectCLDClosure collect_cld(THREAD); @@ -705,6 +710,30 @@ void MetaspaceShared::preload_and_dump() { } } +#if INCLUDE_CDS_JAVA_HEAP && defined(_LP64) +void MetaspaceShared::adjust_heap_sizes_for_dumping() { + if (!DumpSharedSpaces || UseCompressedOops) { + return; + } + // CDS heap dumping requires all string oops to have an offset + // from the heap bottom that can be encoded in 32-bit. + julong max_heap_size = (julong)(4 * G); + + if (MinHeapSize > max_heap_size) { + log_debug(cds)("Setting MinHeapSize to 4G for CDS dumping, original size = " SIZE_FORMAT "M", MinHeapSize/M); + FLAG_SET_ERGO(MinHeapSize, max_heap_size); + } + if (InitialHeapSize > max_heap_size) { + log_debug(cds)("Setting InitialHeapSize to 4G for CDS dumping, original size = " SIZE_FORMAT "M", InitialHeapSize/M); + FLAG_SET_ERGO(InitialHeapSize, max_heap_size); + } + if (MaxHeapSize > max_heap_size) { + log_debug(cds)("Setting MaxHeapSize to 4G for CDS dumping, original size = " SIZE_FORMAT "M", MaxHeapSize/M); + FLAG_SET_ERGO(MaxHeapSize, max_heap_size); + } +} +#endif // INCLUDE_CDS_JAVA_HEAP && _LP64 + void MetaspaceShared::preload_classes(TRAPS) { char default_classlist[JVM_MAXPATHLEN]; const char* classlist_path; @@ -773,7 +802,7 @@ void MetaspaceShared::preload_and_dump_impl(TRAPS) { // were not explicitly specified in the classlist. E.g., if an interface implemented by class K // fails verification, all other interfaces that were not specified in the classlist but // are implemented by K are not verified. - link_shared_classes(CHECK); + link_shared_classes(false/*not from jcmd*/, CHECK); log_info(cds)("Rewriting and linking classes: done"); #if INCLUDE_CDS_JAVA_HEAP @@ -830,11 +859,10 @@ bool MetaspaceShared::try_link_class(JavaThread* current, InstanceKlass* ik) { void VM_PopulateDumpSharedSpace::dump_java_heap_objects(GrowableArray* klasses) { if(!HeapShared::can_write()) { log_info(cds)( - "Archived java heap is not supported as UseG1GC, " - "UseCompressedOops and UseCompressedClassPointers are required." - "Current settings: UseG1GC=%s, UseCompressedOops=%s, UseCompressedClassPointers=%s.", - BOOL_TO_STR(UseG1GC), BOOL_TO_STR(UseCompressedOops), - BOOL_TO_STR(UseCompressedClassPointers)); + "Archived java heap is not supported as UseG1GC " + "and UseCompressedClassPointers are required." + "Current settings: UseG1GC=%s, UseCompressedClassPointers=%s.", + BOOL_TO_STR(UseG1GC), BOOL_TO_STR(UseCompressedClassPointers)); return; } // Find all the interned strings that should be dumped. @@ -946,12 +974,20 @@ void MetaspaceShared::initialize_runtime_shared_and_meta_spaces() { _requested_base_address = static_mapinfo->requested_base_address(); if (dynamic_mapped) { FileMapInfo::set_shared_path_table(dynamic_mapinfo); + // turn AutoCreateSharedArchive off if successfully mapped + AutoCreateSharedArchive = false; } else { FileMapInfo::set_shared_path_table(static_mapinfo); } } else { set_shared_metaspace_range(NULL, NULL, NULL); + if (DynamicDumpSharedSpaces) { + warning("-XX:ArchiveClassesAtExit is unsupported when base CDS archive is not loaded. Run with -Xlog:cds for more info."); + } UseSharedSpaces = false; + // The base archive cannot be mapped. We cannot dump the dynamic shared archive. + AutoCreateSharedArchive = false; + DynamicDumpSharedSpaces = false; FileMapInfo::fail_continue("Unable to map shared spaces"); if (PrintSharedArchiveAndExit) { vm_exit_during_initialization("Unable to use shared archive."); @@ -967,7 +1003,9 @@ void MetaspaceShared::initialize_runtime_shared_and_meta_spaces() { } FileMapInfo* MetaspaceShared::open_static_archive() { - FileMapInfo* mapinfo = new FileMapInfo(true); + const char* static_archive = Arguments::GetSharedArchivePath(); + assert(static_archive != nullptr, "SharedArchivePath is NULL"); + FileMapInfo* mapinfo = new FileMapInfo(static_archive, true); if (!mapinfo->initialize()) { delete(mapinfo); return NULL; @@ -979,11 +1017,12 @@ FileMapInfo* MetaspaceShared::open_dynamic_archive() { if (DynamicDumpSharedSpaces) { return NULL; } - if (Arguments::GetSharedDynamicArchivePath() == NULL) { + const char* dynamic_archive = Arguments::GetSharedDynamicArchivePath(); + if (dynamic_archive == nullptr) { return NULL; } - FileMapInfo* mapinfo = new FileMapInfo(false); + FileMapInfo* mapinfo = new FileMapInfo(dynamic_archive, false); if (!mapinfo->initialize()) { delete(mapinfo); return NULL; diff --git a/src/hotspot/share/cds/metaspaceShared.hpp b/src/hotspot/share/cds/metaspaceShared.hpp index 74077d0fff05b582fca74a1d1c46e8760298de18..63c1089bd27a68c50d97fcdf8ccb0607cb0cbe65 100644 --- a/src/hotspot/share/cds/metaspaceShared.hpp +++ b/src/hotspot/share/cds/metaspaceShared.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -82,6 +82,9 @@ class MetaspaceShared : AllStatic { static void prepare_for_dumping() NOT_CDS_RETURN; static void preload_and_dump() NOT_CDS_RETURN; +#ifdef _LP64 + static void adjust_heap_sizes_for_dumping() NOT_CDS_JAVA_HEAP_RETURN; +#endif private: static void preload_and_dump_impl(TRAPS) NOT_CDS_RETURN; @@ -133,7 +136,7 @@ public: } static bool try_link_class(JavaThread* current, InstanceKlass* ik); - static void link_shared_classes(TRAPS) NOT_CDS_RETURN; + static void link_shared_classes(bool jcmd_request, TRAPS) NOT_CDS_RETURN; static bool link_class_for_cds(InstanceKlass* ik, TRAPS) NOT_CDS_RETURN_(false); static bool may_be_eagerly_linked(InstanceKlass* ik) NOT_CDS_RETURN_(false); diff --git a/src/hotspot/share/cds/runTimeClassInfo.cpp b/src/hotspot/share/cds/runTimeClassInfo.cpp index 52fa94c119d9c12a05ccd9f02e9b577f6845d157..77ec5de8c3b1e4df55e79a52cabbe1329239b932 100644 --- a/src/hotspot/share/cds/runTimeClassInfo.cpp +++ b/src/hotspot/share/cds/runTimeClassInfo.cpp @@ -1,6 +1,5 @@ - /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -64,6 +63,15 @@ void RunTimeClassInfo::init(DumpTimeClassInfo& info) { InstanceKlass* n_h = info.nest_host(); set_nest_host(n_h); } + if (_klass->has_archived_enum_objs()) { + int num = info.num_enum_klass_static_fields(); + set_num_enum_klass_static_fields(num); + for (int i = 0; i < num; i++) { + int root_index = info.enum_klass_static_field(i); + set_enum_klass_static_field_root_index_at(i, root_index); + } + } + ArchivePtrMarker::mark_pointer(&_klass); } diff --git a/src/hotspot/share/cds/runTimeClassInfo.hpp b/src/hotspot/share/cds/runTimeClassInfo.hpp index adc828c4f88c28a9b3962913ef6e6d4d91a85713..74fdf92ebafa9ae70432bca1c8d656bb52299c8a 100644 --- a/src/hotspot/share/cds/runTimeClassInfo.hpp +++ b/src/hotspot/share/cds/runTimeClassInfo.hpp @@ -1,6 +1,5 @@ - /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -64,30 +63,40 @@ public: return (Symbol*)(SharedBaseAddress + _name); } }; + struct RTEnumKlassStaticFields { + int _num; + int _root_indices[1]; + }; InstanceKlass* _klass; int _num_verifier_constraints; int _num_loader_constraints; - // optional CrcInfo _crc; (only for UNREGISTERED classes) - // optional InstanceKlass* _nest_host - // optional RTLoaderConstraint _loader_constraint_types[_num_loader_constraints] - // optional RTVerifierConstraint _verifier_constraints[_num_verifier_constraints] - // optional char _verifier_constraint_flags[_num_verifier_constraints] + // optional CrcInfo _crc; (only for UNREGISTERED classes) + // optional InstanceKlass* _nest_host + // optional RTLoaderConstraint _loader_constraint_types[_num_loader_constraints] + // optional RTVerifierConstraint _verifier_constraints[_num_verifier_constraints] + // optional char _verifier_constraint_flags[_num_verifier_constraints] + // optional RTEnumKlassStaticFields _enum_klass_static_fields; private: static size_t header_size_size() { - return sizeof(RunTimeClassInfo); + return align_up(sizeof(RunTimeClassInfo), wordSize); } static size_t verifier_constraints_size(int num_verifier_constraints) { - return sizeof(RTVerifierConstraint) * num_verifier_constraints; + return align_up(sizeof(RTVerifierConstraint) * num_verifier_constraints, wordSize); } static size_t verifier_constraint_flags_size(int num_verifier_constraints) { - return sizeof(char) * num_verifier_constraints; + return align_up(sizeof(char) * num_verifier_constraints, wordSize); } static size_t loader_constraints_size(int num_loader_constraints) { - return sizeof(RTLoaderConstraint) * num_loader_constraints; + return align_up(sizeof(RTLoaderConstraint) * num_loader_constraints, wordSize); } + static size_t enum_klass_static_fields_size(int num_fields) { + size_t size = num_fields <= 0 ? 0 : sizeof(RTEnumKlassStaticFields) + (num_fields - 1) * sizeof(int); + return align_up(size, wordSize); + } + static size_t nest_host_size(InstanceKlass* klass) { if (klass->is_hidden()) { return sizeof(InstanceKlass*); @@ -98,13 +107,15 @@ private: static size_t crc_size(InstanceKlass* klass); public: - static size_t byte_size(InstanceKlass* klass, int num_verifier_constraints, int num_loader_constraints) { + static size_t byte_size(InstanceKlass* klass, int num_verifier_constraints, int num_loader_constraints, + int num_enum_klass_static_fields) { return header_size_size() + crc_size(klass) + nest_host_size(klass) + loader_constraints_size(num_loader_constraints) + verifier_constraints_size(num_verifier_constraints) + - verifier_constraint_flags_size(num_verifier_constraints); + verifier_constraint_flags_size(num_verifier_constraints) + + enum_klass_static_fields_size(num_enum_klass_static_fields); } private: @@ -113,7 +124,7 @@ private: } size_t nest_host_offset() const { - return crc_offset() + crc_size(_klass); + return crc_offset() + crc_size(_klass); } size_t loader_constraints_offset() const { @@ -125,6 +136,9 @@ private: size_t verifier_constraint_flags_offset() const { return verifier_constraints_offset() + verifier_constraints_size(_num_verifier_constraints); } + size_t enum_klass_static_fields_offset() const { + return verifier_constraint_flags_offset() + verifier_constraint_flags_size(_num_verifier_constraints); + } void check_verifier_constraint_offset(int i) const { assert(0 <= i && i < _num_verifier_constraints, "sanity"); @@ -134,6 +148,11 @@ private: assert(0 <= i && i < _num_loader_constraints, "sanity"); } + RTEnumKlassStaticFields* enum_klass_static_fields_addr() const { + assert(_klass->has_archived_enum_objs(), "sanity"); + return (RTEnumKlassStaticFields*)(address(this) + enum_klass_static_fields_offset()); + } + public: CrcInfo* crc() const { assert(crc_size(_klass) > 0, "must be"); @@ -187,6 +206,23 @@ public: return verifier_constraint_flags()[i]; } + int num_enum_klass_static_fields(int i) const { + return enum_klass_static_fields_addr()->_num; + } + + void set_num_enum_klass_static_fields(int num) { + enum_klass_static_fields_addr()->_num = num; + } + + int enum_klass_static_field_root_index_at(int i) const { + assert(0 <= i && i < enum_klass_static_fields_addr()->_num, "must be"); + return enum_klass_static_fields_addr()->_root_indices[i]; + } + + void set_enum_klass_static_field_root_index_at(int i, int root_index) { + assert(0 <= i && i < enum_klass_static_fields_addr()->_num, "must be"); + enum_klass_static_fields_addr()->_root_indices[i] = root_index; + } private: // ArchiveBuilder::make_shallow_copy() has reserved a pointer immediately // before archived InstanceKlasses. We can use this slot to do a quick diff --git a/src/hotspot/share/ci/bcEscapeAnalyzer.cpp b/src/hotspot/share/ci/bcEscapeAnalyzer.cpp index a10a9d3d551f3ec0af51290f4ec32d42de9e3822..7fd8b5c04f338d048b60985fc81f3712a9200cc2 100644 --- a/src/hotspot/share/ci/bcEscapeAnalyzer.cpp +++ b/src/hotspot/share/ci/bcEscapeAnalyzer.cpp @@ -416,11 +416,11 @@ void BCEscapeAnalyzer::iterate_one_block(ciBlock *blk, StateInfo &state, Growabl // Avoid calling get_constant() which will try to allocate // unloaded constant. We need only constant's type. int index = s.get_constant_pool_index(); - constantTag tag = s.get_constant_pool_tag(index); - if (tag.is_long() || tag.is_double()) { + BasicType con_bt = s.get_basic_type_for_constant_at(index); + if (con_bt == T_LONG || con_bt == T_DOUBLE) { // Only longs and doubles use 2 stack slots. state.lpush(); - } else if (tag.basic_type() == T_OBJECT) { + } else if (con_bt == T_OBJECT) { state.apush(unknown_obj); } else { state.spush(); diff --git a/src/hotspot/share/ci/ciConstant.hpp b/src/hotspot/share/ci/ciConstant.hpp index c9351771d173b31057f237250c61ca55a3dec631..255916990459a14b63d9d456d6efbb7e552dae4a 100644 --- a/src/hotspot/share/ci/ciConstant.hpp +++ b/src/hotspot/share/ci/ciConstant.hpp @@ -127,6 +127,17 @@ public: bool is_valid() const { return basic_type() != T_ILLEGAL; } + + bool is_loaded() const { + if (is_valid()) { + if (is_reference_type(basic_type())) { + return as_object()->is_loaded(); + } else { + return true; + } + } + return false; + } // Debugging output void print(); }; diff --git a/src/hotspot/share/ci/ciEnv.cpp b/src/hotspot/share/ci/ciEnv.cpp index 9b8d118196b7cbd962c2dbbeea2f7608a770d4d3..ff70023d3cfdfc9b0237dbabeb5cb958bc5effaa 100644 --- a/src/hotspot/share/ci/ciEnv.cpp +++ b/src/hotspot/share/ci/ciEnv.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -392,6 +392,23 @@ ciInstance* ciEnv::get_or_create_exception(jobject& handle, Symbol* name) { return obj == NULL? NULL: get_object(obj)->as_instance(); } +ciInstanceKlass* ciEnv::get_box_klass_for_primitive_type(BasicType type) { + switch (type) { + case T_BOOLEAN: return Boolean_klass(); + case T_BYTE : return Byte_klass(); + case T_CHAR : return Character_klass(); + case T_SHORT : return Short_klass(); + case T_INT : return Integer_klass(); + case T_LONG : return Long_klass(); + case T_FLOAT : return Float_klass(); + case T_DOUBLE : return Double_klass(); + + default: + assert(false, "not a primitive: %s", type2name(type)); + return NULL; + } +} + ciInstance* ciEnv::ArrayIndexOutOfBoundsException_instance() { if (_ArrayIndexOutOfBoundsException_instance == NULL) { _ArrayIndexOutOfBoundsException_instance @@ -503,13 +520,6 @@ ciKlass* ciEnv::get_klass_by_name_impl(ciKlass* accessing_klass, domain = Handle(current, accessing_klass->protection_domain()); } - // setup up the proper type to return on OOM - ciKlass* fail_type; - if (sym->char_at(0) == JVM_SIGNATURE_ARRAY) { - fail_type = _unloaded_ciobjarrayklass; - } else { - fail_type = _unloaded_ciinstance_klass; - } Klass* found_klass; { ttyUnlocker ttyul; // release tty lock to avoid ordering problems @@ -591,7 +601,6 @@ ciKlass* ciEnv::get_klass_by_index_impl(const constantPoolHandle& cpool, int index, bool& is_accessible, ciInstanceKlass* accessor) { - EXCEPTION_CONTEXT; Klass* klass = NULL; Symbol* klass_name = NULL; @@ -599,7 +608,7 @@ ciKlass* ciEnv::get_klass_by_index_impl(const constantPoolHandle& cpool, klass_name = cpool->symbol_at(index); } else { // Check if it's resolved if it's not a symbol constant pool entry. - klass = ConstantPool::klass_at_if_loaded(cpool, index); + klass = ConstantPool::klass_at_if_loaded(cpool, index); // Try to look it up by name. if (klass == NULL) { klass_name = cpool->klass_name_at(index); @@ -658,53 +667,75 @@ ciKlass* ciEnv::get_klass_by_index(const constantPoolHandle& cpool, GUARDED_VM_ENTRY(return get_klass_by_index_impl(cpool, index, is_accessible, accessor);) } +// ------------------------------------------------------------------ +// ciEnv::unbox_primitive_value +// +// Unbox a primitive and return it as a ciConstant. +ciConstant ciEnv::unbox_primitive_value(ciObject* cibox, BasicType expected_bt) { + jvalue value; + BasicType bt = java_lang_boxing_object::get_value(cibox->get_oop(), &value); + if (bt != expected_bt && expected_bt != T_ILLEGAL) { + assert(false, "type mismatch: %s vs %s", type2name(expected_bt), cibox->klass()->name()->as_klass_external_name()); + return ciConstant(); + } + switch (bt) { + case T_BOOLEAN: return ciConstant(bt, value.z); + case T_BYTE: return ciConstant(bt, value.b); + case T_SHORT: return ciConstant(bt, value.s); + case T_CHAR: return ciConstant(bt, value.c); + case T_INT: return ciConstant(bt, value.i); + case T_LONG: return ciConstant(value.j); + case T_FLOAT: return ciConstant(value.f); + case T_DOUBLE: return ciConstant(value.d); + + default: + assert(false, "not a primitive type: %s", type2name(bt)); + return ciConstant(); + } +} + +// ------------------------------------------------------------------ +// ciEnv::get_resolved_constant +// +ciConstant ciEnv::get_resolved_constant(const constantPoolHandle& cpool, int obj_index) { + assert(obj_index >= 0, ""); + oop obj = cpool->resolved_references()->obj_at(obj_index); + if (obj == NULL) { + // Unresolved constant. It is resolved when the corresponding slot contains a non-null reference. + // Null constant is represented as a sentinel (non-null) value. + return ciConstant(); + } else if (obj == Universe::the_null_sentinel()) { + return ciConstant(T_OBJECT, get_object(NULL)); + } else { + ciObject* ciobj = get_object(obj); + if (ciobj->is_array()) { + return ciConstant(T_ARRAY, ciobj); + } else { + int cp_index = cpool->object_to_cp_index(obj_index); + BasicType bt = cpool->basic_type_for_constant_at(cp_index); + if (is_java_primitive(bt)) { + assert(cpool->tag_at(cp_index).is_dynamic_constant(), "sanity"); + return unbox_primitive_value(ciobj, bt); + } else { + assert(ciobj->is_instance(), "should be an instance"); + return ciConstant(T_OBJECT, ciobj); + } + } + } +} + // ------------------------------------------------------------------ // ciEnv::get_constant_by_index_impl // // Implementation of get_constant_by_index(). ciConstant ciEnv::get_constant_by_index_impl(const constantPoolHandle& cpool, - int pool_index, int cache_index, + int index, int obj_index, ciInstanceKlass* accessor) { bool ignore_will_link; - EXCEPTION_CONTEXT; - int index = pool_index; - if (cache_index >= 0) { - assert(index < 0, "only one kind of index at a time"); - index = cpool->object_to_cp_index(cache_index); - oop obj = cpool->resolved_references()->obj_at(cache_index); - if (obj != NULL) { - if (obj == Universe::the_null_sentinel()) { - return ciConstant(T_OBJECT, get_object(NULL)); - } - BasicType bt = T_OBJECT; - if (cpool->tag_at(index).is_dynamic_constant()) - bt = Signature::basic_type(cpool->uncached_signature_ref_at(index)); - if (is_reference_type(bt)) { - } else { - // we have to unbox the primitive value - if (!is_java_primitive(bt)) return ciConstant(); - jvalue value; - BasicType bt2 = java_lang_boxing_object::get_value(obj, &value); - assert(bt2 == bt, ""); - switch (bt2) { - case T_DOUBLE: return ciConstant(value.d); - case T_FLOAT: return ciConstant(value.f); - case T_LONG: return ciConstant(value.j); - case T_INT: return ciConstant(bt2, value.i); - case T_SHORT: return ciConstant(bt2, value.s); - case T_BYTE: return ciConstant(bt2, value.b); - case T_CHAR: return ciConstant(bt2, value.c); - case T_BOOLEAN: return ciConstant(bt2, value.z); - default: return ciConstant(); - } - } - ciObject* ciobj = get_object(obj); - if (ciobj->is_array()) { - return ciConstant(T_ARRAY, ciobj); - } else { - assert(ciobj->is_instance(), "should be an instance"); - return ciConstant(T_OBJECT, ciobj); - } + if (obj_index >= 0) { + ciConstant con = get_resolved_constant(cpool, obj_index); + if (con.is_valid()) { + return con; } } constantTag tag = cpool->tag_at(index); @@ -717,41 +748,30 @@ ciConstant ciEnv::get_constant_by_index_impl(const constantPoolHandle& cpool, } else if (tag.is_double()) { return ciConstant((jdouble)cpool->double_at(index)); } else if (tag.is_string()) { - oop string = NULL; - assert(cache_index >= 0, "should have a cache index"); - string = cpool->string_at(index, cache_index, THREAD); + EXCEPTION_CONTEXT; + assert(obj_index >= 0, "should have an object index"); + oop string = cpool->string_at(index, obj_index, THREAD); if (HAS_PENDING_EXCEPTION) { CLEAR_PENDING_EXCEPTION; record_out_of_memory_failure(); return ciConstant(); } - ciObject* constant = get_object(string); - if (constant->is_array()) { - return ciConstant(T_ARRAY, constant); - } else { - assert (constant->is_instance(), "must be an instance, or not? "); - return ciConstant(T_OBJECT, constant); - } + ciInstance* constant = get_object(string)->as_instance(); + return ciConstant(T_OBJECT, constant); } else if (tag.is_unresolved_klass_in_error()) { - return ciConstant(); + return ciConstant(T_OBJECT, get_unloaded_klass_mirror(NULL)); } else if (tag.is_klass() || tag.is_unresolved_klass()) { - // 4881222: allow ldc to take a class type ciKlass* klass = get_klass_by_index_impl(cpool, index, ignore_will_link, accessor); - if (HAS_PENDING_EXCEPTION) { - CLEAR_PENDING_EXCEPTION; - record_out_of_memory_failure(); - return ciConstant(); - } - assert (klass->is_instance_klass() || klass->is_array_klass(), - "must be an instance or array klass "); return ciConstant(T_OBJECT, klass->java_mirror()); - } else if (tag.is_method_type()) { + } else if (tag.is_method_type() || tag.is_method_type_in_error()) { // must execute Java code to link this CP entry into cache[i].f1 + assert(obj_index >= 0, "should have an object index"); ciSymbol* signature = get_symbol(cpool->method_type_signature_at(index)); ciObject* ciobj = get_unloaded_method_type_constant(signature); return ciConstant(T_OBJECT, ciobj); - } else if (tag.is_method_handle()) { + } else if (tag.is_method_handle() || tag.is_method_handle_in_error()) { // must execute Java code to link this CP entry into cache[i].f1 + assert(obj_index >= 0, "should have an object index"); int ref_kind = cpool->method_handle_ref_kind_at(index); int callee_index = cpool->method_handle_klass_index_at(index); ciKlass* callee = get_klass_by_index_impl(cpool, callee_index, ignore_will_link, accessor); @@ -759,10 +779,11 @@ ciConstant ciEnv::get_constant_by_index_impl(const constantPoolHandle& cpool, ciSymbol* signature = get_symbol(cpool->method_handle_signature_ref_at(index)); ciObject* ciobj = get_unloaded_method_handle_constant(callee, name, signature, ref_kind); return ciConstant(T_OBJECT, ciobj); - } else if (tag.is_dynamic_constant()) { - return ciConstant(); + } else if (tag.is_dynamic_constant() || tag.is_dynamic_constant_in_error()) { + assert(obj_index >= 0, "should have an object index"); + return ciConstant(T_OBJECT, unloaded_ciinstance()); // unresolved dynamic constant } else { - ShouldNotReachHere(); + assert(false, "unknown tag: %d (%s)", tag.value(), tag.internal_name()); return ciConstant(); } } @@ -1654,9 +1675,11 @@ void ciEnv::dump_replay_data_helper(outputStream* out) { GrowableArray* objects = _factory->get_ci_metadata(); out->print_cr("# %d ciObject found", objects->length()); + // The very first entry is the InstanceKlass of the root method of the current compilation in order to get the right // protection domain to load subsequent classes during replay compilation. - out->print_cr("instanceKlass %s", CURRENT_ENV->replay_name(task()->method()->method_holder())); + ciInstanceKlass::dump_replay_instanceKlass(out, task()->method()->method_holder()); + for (int i = 0; i < objects->length(); i++) { objects->at(i)->dump_replay_data(out); } @@ -1681,12 +1704,12 @@ void ciEnv::dump_replay_data(outputStream* out) { } void ciEnv::dump_replay_data(int compile_id) { - static char buffer[O_BUFLEN]; - int ret = jio_snprintf(buffer, O_BUFLEN, "replay_pid%p_compid%d.log", os::current_process_id(), compile_id); + char buffer[64]; + int ret = jio_snprintf(buffer, sizeof(buffer), "replay_pid%d_compid%d.log", os::current_process_id(), compile_id); if (ret > 0) { int fd = os::open(buffer, O_RDWR | O_CREAT | O_TRUNC, 0666); if (fd != -1) { - FILE* replay_data_file = os::open(fd, "w"); + FILE* replay_data_file = os::fdopen(fd, "w"); if (replay_data_file != NULL) { fileStream replay_data_stream(replay_data_file, /*need_close=*/true); dump_replay_data(&replay_data_stream); @@ -1699,12 +1722,12 @@ void ciEnv::dump_replay_data(int compile_id) { } void ciEnv::dump_inline_data(int compile_id) { - static char buffer[O_BUFLEN]; - int ret = jio_snprintf(buffer, O_BUFLEN, "inline_pid%p_compid%d.log", os::current_process_id(), compile_id); + char buffer[64]; + int ret = jio_snprintf(buffer, sizeof(buffer), "inline_pid%d_compid%d.log", os::current_process_id(), compile_id); if (ret > 0) { int fd = os::open(buffer, O_RDWR | O_CREAT | O_TRUNC, 0666); if (fd != -1) { - FILE* inline_data_file = os::open(fd, "w"); + FILE* inline_data_file = os::fdopen(fd, "w"); if (inline_data_file != NULL) { fileStream replay_data_stream(inline_data_file, /*need_close=*/true); GUARDED_VM_ENTRY( diff --git a/src/hotspot/share/ci/ciEnv.hpp b/src/hotspot/share/ci/ciEnv.hpp index 52bcc9bddcf7e1bd3b6936c7d2ecf4c550a32d2f..b2e98f1dce877190d30f87ba1c40b2789d09960b 100644 --- a/src/hotspot/share/ci/ciEnv.hpp +++ b/src/hotspot/share/ci/ciEnv.hpp @@ -165,6 +165,9 @@ private: Bytecodes::Code bc, constantTag tag); + ciConstant unbox_primitive_value(ciObject* cibox, BasicType expected_bt = T_ILLEGAL); + ciConstant get_resolved_constant(const constantPoolHandle& cpool, int obj_index); + // Get a ciObject from the object factory. Ensures uniqueness // of ciObjects. ciObject* get_object(oop o) { @@ -429,6 +432,8 @@ public: } ciInstance* unloaded_ciinstance(); + ciInstanceKlass* get_box_klass_for_primitive_type(BasicType type); + // Note: To find a class from its name string, use ciSymbol::make, // but consider adding to vmSymbols.hpp instead. diff --git a/src/hotspot/share/ci/ciInstanceKlass.cpp b/src/hotspot/share/ci/ciInstanceKlass.cpp index 88c475d93d8127fb142fb894402533c9d4e3cfad..8b2806dbf9ed4be261488e5080c2bfd116b70a91 100644 --- a/src/hotspot/share/ci/ciInstanceKlass.cpp +++ b/src/hotspot/share/ci/ciInstanceKlass.cpp @@ -732,6 +732,19 @@ const char *ciInstanceKlass::replay_name() const { return CURRENT_ENV->replay_name(get_instanceKlass()); } +void ciInstanceKlass::dump_replay_instanceKlass(outputStream* out, InstanceKlass* ik) { + if (ik->is_hidden()) { + const char *name = CURRENT_ENV->dyno_name(ik); + if (name != NULL) { + out->print_cr("instanceKlass %s # %s", name, ik->name()->as_quoted_ascii()); + } else { + out->print_cr("# instanceKlass %s", ik->name()->as_quoted_ascii()); + } + } else { + out->print_cr("instanceKlass %s", ik->name()->as_quoted_ascii()); + } +} + void ciInstanceKlass::dump_replay_data(outputStream* out) { ResourceMark rm; @@ -743,16 +756,7 @@ void ciInstanceKlass::dump_replay_data(outputStream* out) { while (sub != NULL) { if (sub->is_instance_klass()) { InstanceKlass *isub = InstanceKlass::cast(sub); - if (isub->is_hidden()) { - const char *name = CURRENT_ENV->dyno_name(isub); - if (name != NULL) { - out->print_cr("instanceKlass %s # %s", name, sub->name()->as_quoted_ascii()); - } else { - out->print_cr("# instanceKlass %s", sub->name()->as_quoted_ascii()); - } - } else { - out->print_cr("instanceKlass %s", sub->name()->as_quoted_ascii()); - } + dump_replay_instanceKlass(out, isub); } sub = sub->next_sibling(); } diff --git a/src/hotspot/share/ci/ciInstanceKlass.hpp b/src/hotspot/share/ci/ciInstanceKlass.hpp index 3e79198eddbe1a5a1e4136b36d1b14fb9661d862..9afee115488e723c2a74e5597d03b15f87aa0de1 100644 --- a/src/hotspot/share/ci/ciInstanceKlass.hpp +++ b/src/hotspot/share/ci/ciInstanceKlass.hpp @@ -293,6 +293,9 @@ public: // Dump the current state of this klass for compilation replay. virtual void dump_replay_data(outputStream* out); + static void dump_replay_instanceKlass(outputStream* out, InstanceKlass* ik); + + // Return stable class name suitable for replay file. const char *replay_name() const; diff --git a/src/hotspot/share/ci/ciMethod.cpp b/src/hotspot/share/ci/ciMethod.cpp index 862824c5b72f9bc75b0d42c01195c21fbf50780e..b2d9e14208dd57d826e8c30bf1548cfca47b8187 100644 --- a/src/hotspot/share/ci/ciMethod.cpp +++ b/src/hotspot/share/ci/ciMethod.cpp @@ -117,9 +117,11 @@ ciMethod::ciMethod(const methodHandle& h_m, ciInstanceKlass* holder) : if (h_m->method_holder()->is_linked()) { _can_be_statically_bound = h_m->can_be_statically_bound(); + _can_omit_stack_trace = h_m->can_omit_stack_trace(); } else { // Have to use a conservative value in this case. _can_be_statically_bound = false; + _can_omit_stack_trace = true; } // Adjust the definition of this condition to be more useful: @@ -176,6 +178,7 @@ ciMethod::ciMethod(ciInstanceKlass* holder, _intrinsic_id( vmIntrinsics::_none), _instructions_size(-1), _can_be_statically_bound(false), + _can_omit_stack_trace(true), _liveness( NULL) #if defined(COMPILER2) , @@ -766,6 +769,20 @@ bool ciMethod::can_be_statically_bound(ciInstanceKlass* context) const { return (holder() == context) && can_be_statically_bound(); } +// ------------------------------------------------------------------ +// ciMethod::can_omit_stack_trace +// +// Tries to determine whether a method can omit stack trace in throw in compiled code. +bool ciMethod::can_omit_stack_trace() const { + if (!StackTraceInThrowable) { + return true; // stack trace is switched off. + } + if (!OmitStackTraceInFastThrow) { + return false; // Have to provide stack trace. + } + return _can_omit_stack_trace; +} + // ------------------------------------------------------------------ // ciMethod::resolve_invoke // diff --git a/src/hotspot/share/ci/ciMethod.hpp b/src/hotspot/share/ci/ciMethod.hpp index 926badd2f381f44c041ac40da8ca6fe591c59e9d..5e0732dfeb72bf2d1f89ede4aa36321e1871082a 100644 --- a/src/hotspot/share/ci/ciMethod.hpp +++ b/src/hotspot/share/ci/ciMethod.hpp @@ -92,6 +92,7 @@ class ciMethod : public ciMetadata { bool _is_c2_compilable; bool _can_be_parsed; bool _can_be_statically_bound; + bool _can_omit_stack_trace; bool _has_reserved_stack_access; bool _is_overpass; @@ -364,6 +365,8 @@ class ciMethod : public ciMetadata { bool can_be_statically_bound(ciInstanceKlass* context) const; + bool can_omit_stack_trace() const; + // Replay data methods static void dump_name_as_ascii(outputStream* st, Method* method); void dump_name_as_ascii(outputStream* st); diff --git a/src/hotspot/share/ci/ciObjectFactory.cpp b/src/hotspot/share/ci/ciObjectFactory.cpp index 0f53c9957ce66bcec084643479a05ca583450f5c..bc438cf1d815ca1ae25f15dd89b93f3c27b937f3 100644 --- a/src/hotspot/share/ci/ciObjectFactory.cpp +++ b/src/hotspot/share/ci/ciObjectFactory.cpp @@ -555,7 +555,7 @@ ciInstance* ciObjectFactory::get_unloaded_instance(ciInstanceKlass* instance_kla // Get a ciInstance representing an unresolved klass mirror. // // Currently, this ignores the parameters and returns a unique unloaded instance. -ciInstance* ciObjectFactory::get_unloaded_klass_mirror(ciKlass* type) { +ciInstance* ciObjectFactory::get_unloaded_klass_mirror(ciKlass* type) { assert(ciEnv::_Class_klass != NULL, ""); return get_unloaded_instance(ciEnv::_Class_klass->as_instance_klass()); } @@ -570,7 +570,7 @@ ciInstance* ciObjectFactory::get_unloaded_method_handle_constant(ciKlass* holde ciSymbol* name, ciSymbol* signature, int ref_kind) { - if (ciEnv::_MethodHandle_klass == NULL) return NULL; + assert(ciEnv::_MethodHandle_klass != NULL, ""); return get_unloaded_instance(ciEnv::_MethodHandle_klass->as_instance_klass()); } @@ -581,12 +581,12 @@ ciInstance* ciObjectFactory::get_unloaded_method_handle_constant(ciKlass* holde // // Currently, this ignores the parameters and returns a unique unloaded instance. ciInstance* ciObjectFactory::get_unloaded_method_type_constant(ciSymbol* signature) { - if (ciEnv::_MethodType_klass == NULL) return NULL; + assert(ciEnv::_MethodType_klass != NULL, ""); return get_unloaded_instance(ciEnv::_MethodType_klass->as_instance_klass()); } ciInstance* ciObjectFactory::get_unloaded_object_constant() { - if (ciEnv::_Object_klass == NULL) return NULL; + assert(ciEnv::_Object_klass != NULL, ""); return get_unloaded_instance(ciEnv::_Object_klass->as_instance_klass()); } diff --git a/src/hotspot/share/ci/ciReplay.cpp b/src/hotspot/share/ci/ciReplay.cpp index 20f33cc4909ddf9d47e0749108dc2eff228d0c77..a2a249f157ac4e8cdbdd8a8eed68f62ce7d3c989 100644 --- a/src/hotspot/share/ci/ciReplay.cpp +++ b/src/hotspot/share/ci/ciReplay.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -103,6 +103,7 @@ typedef struct _ciInlineRecord { int _inline_depth; int _inline_bci; + bool _inline_late; } ciInlineRecord; class CompileReplay; @@ -144,7 +145,7 @@ class CompileReplay : public StackObj { _protection_domain = Handle(); _protection_domain_initialized = false; - _stream = fopen(filename, "rt"); + _stream = os::fopen(filename, "rt"); if (_stream == NULL) { fprintf(stderr, "ERROR: Can't open replay file %s\n", filename); } @@ -436,7 +437,7 @@ class CompileReplay : public StackObj { } else if (strcmp(dyno_ref, "") == 0) { int pool_index = cp_cache_entry->constant_pool_index(); BootstrapInfo bootstrap_specifier(cp, pool_index, index); - obj = cp->resolve_possibly_cached_constant_at(bootstrap_specifier.bsm_index(), thread); + obj = cp->resolve_possibly_cached_constant_at(bootstrap_specifier.bsm_index(), CHECK_NULL); } else { report_error("unrecognized token"); return NULL; @@ -465,57 +466,57 @@ class CompileReplay : public StackObj { report_error("no method handle found at cpi"); return NULL; } - { - bool found_it; - obj = cp->find_cached_constant_at(cpi, found_it, thread); - } + ik->link_class(CHECK_NULL); + obj = cp->resolve_possibly_cached_constant_at(cpi, CHECK_NULL); + } + if (obj == NULL) { + report_error("null cp object found"); + return NULL; } Klass* k = NULL; - if (obj != NULL) { - skip_ws(); - // loop: read fields - char* field = NULL; - do { - field = parse_string(); - if (field == NULL) { - report_error("no field found"); + skip_ws(); + // loop: read fields + char* field = NULL; + do { + field = parse_string(); + if (field == NULL) { + report_error("no field found"); + return NULL; + } + if (strcmp(field, ";") == 0) { + break; + } + // raw Method* + if (strcmp(field, "") == 0) { + Method* vmtarget = java_lang_invoke_MemberName::vmtarget(obj); + k = (vmtarget == NULL) ? NULL : vmtarget->method_holder(); + if (k == NULL) { + report_error("null vmtarget found"); return NULL; } - if (strcmp(field, ";") == 0) { - break; - } - // raw Method* - if (strcmp(field, "") == 0) { - Method* vmtarget = java_lang_invoke_MemberName::vmtarget(obj); - k = (vmtarget == NULL) ? NULL : vmtarget->method_holder(); - if (k == NULL) { - report_error("null vmtarget found"); - return NULL; - } - if (!parse_terminator()) { - report_error("missing terminator"); - return NULL; - } - return k; + if (!parse_terminator()) { + report_error("missing terminator"); + return NULL; } - obj = ciReplay::obj_field(obj, field); - // array - if (obj != NULL && obj->is_objArray()) { - objArrayOop arr = (objArrayOop)obj; - int index = parse_int("index"); - if (index >= arr->length()) { - report_error("bad array index"); - return NULL; - } - obj = arr->obj_at(index); + return k; + } + obj = ciReplay::obj_field(obj, field); + // array + if (obj != NULL && obj->is_objArray()) { + objArrayOop arr = (objArrayOop)obj; + int index = parse_int("index"); + if (index >= arr->length()) { + report_error("bad array index"); + return NULL; } - } while (obj != NULL); - if (obj == NULL) { - report_error("null field found"); - return NULL; + obj = arr->obj_at(index); } - k = obj->klass(); + } while (obj != NULL); + if (obj == NULL) { + report_error("null field found"); + return NULL; } + k = obj->klass(); return k; } @@ -720,7 +721,7 @@ class CompileReplay : public StackObj { return NULL; } - // compile inline ( )* + // compile inline ( )* void process_compile(TRAPS) { Method* method = parse_method(CHECK); if (had_error()) return; @@ -762,11 +763,19 @@ class CompileReplay : public StackObj { if (had_error()) { break; } + int inline_late = 0; + if (_version >= 2) { + inline_late = parse_int("inline_late"); + if (had_error()) { + break; + } + } + Method* inl_method = parse_method(CHECK); if (had_error()) { break; } - new_ciInlineRecord(inl_method, bci, depth); + new_ciInlineRecord(inl_method, bci, depth, inline_late); } } if (_imethod != NULL) { @@ -927,6 +936,7 @@ class CompileReplay : public StackObj { void process_ciInstanceKlass(TRAPS) { InstanceKlass* k = (InstanceKlass*)parse_klass(CHECK); if (k == NULL) { + skip_remaining(); return; } int is_linked = parse_int("is_linked"); @@ -1226,13 +1236,14 @@ class CompileReplay : public StackObj { } // Create and initialize a record for a ciInlineRecord - ciInlineRecord* new_ciInlineRecord(Method* method, int bci, int depth) { + ciInlineRecord* new_ciInlineRecord(Method* method, int bci, int depth, int inline_late) { ciInlineRecord* rec = NEW_RESOURCE_OBJ(ciInlineRecord); rec->_klass_name = method->method_holder()->name()->as_utf8(); rec->_method_name = method->name()->as_utf8(); rec->_signature = method->signature()->as_utf8(); rec->_inline_bci = bci; rec->_inline_depth = depth; + rec->_inline_late = inline_late; _ci_inline_records->append(rec); return rec; } @@ -1469,23 +1480,33 @@ bool ciReplay::should_not_inline(ciMethod* method) { return replay_state->find_ciMethodRecord(method->get_Method()) == NULL; } -bool ciReplay::should_inline(void* data, ciMethod* method, int bci, int inline_depth) { +bool ciReplay::should_inline(void* data, ciMethod* method, int bci, int inline_depth, bool& should_delay) { if (data != NULL) { - GrowableArray* records = (GrowableArray*)data; + GrowableArray* records = (GrowableArray*)data; VM_ENTRY_MARK; // Inline record are ordered by bci and depth. - return CompileReplay::find_ciInlineRecord(records, method->get_Method(), bci, inline_depth) != NULL; + ciInlineRecord* record = CompileReplay::find_ciInlineRecord(records, method->get_Method(), bci, inline_depth); + if (record == NULL) { + return false; + } + should_delay = record->_inline_late; + return true; } else if (replay_state != NULL) { VM_ENTRY_MARK; // Inline record are ordered by bci and depth. - return replay_state->find_ciInlineRecord(method->get_Method(), bci, inline_depth) != NULL; + ciInlineRecord* record = replay_state->find_ciInlineRecord(method->get_Method(), bci, inline_depth); + if (record == NULL) { + return false; + } + should_delay = record->_inline_late; + return true; } return false; } bool ciReplay::should_not_inline(void* data, ciMethod* method, int bci, int inline_depth) { if (data != NULL) { - GrowableArray* records = (GrowableArray*)data; + GrowableArray* records = (GrowableArray*)data; VM_ENTRY_MARK; // Inline record are ordered by bci and depth. return CompileReplay::find_ciInlineRecord(records, method->get_Method(), bci, inline_depth) == NULL; diff --git a/src/hotspot/share/ci/ciReplay.hpp b/src/hotspot/share/ci/ciReplay.hpp index 187f47497bdda827474d207c2a14f9a6c88bd3a2..e835bb907ba9b90596a31f4a5eecefaa3ae337fa 100644 --- a/src/hotspot/share/ci/ciReplay.hpp +++ b/src/hotspot/share/ci/ciReplay.hpp @@ -121,7 +121,7 @@ class ciReplay { static bool is_loaded(Method* method); static bool should_not_inline(ciMethod* method); - static bool should_inline(void* data, ciMethod* method, int bci, int inline_depth); + static bool should_inline(void* data, ciMethod* method, int bci, int inline_depth, bool& should_delay); static bool should_not_inline(void* data, ciMethod* method, int bci, int inline_depth); #endif @@ -135,6 +135,7 @@ class ciReplay { // 0: legacy (no version number) // 1: first instanceKlass sets protection domain (8275868) // replace current_mileage with invocation_count (8276095) -#define REPLAY_VERSION 1 // current version, bump up for incompatible changes +// 2: incremental inlining support (8254108) +#define REPLAY_VERSION 2 // current version, bump up for incompatible changes #endif // SHARE_CI_CIREPLAY_HPP diff --git a/src/hotspot/share/ci/ciStreams.cpp b/src/hotspot/share/ci/ciStreams.cpp index 4e9895bfaed8ad30b814f48cdd8efe88d10c4424..6c7e9b6ee4171585bed3be470077722a2c77af27 100644 --- a/src/hotspot/share/ci/ciStreams.cpp +++ b/src/hotspot/share/ci/ciStreams.cpp @@ -230,14 +230,19 @@ int ciBytecodeStream::get_constant_pool_index() const { // If this bytecode is one of the ldc variants, get the referenced // constant. ciConstant ciBytecodeStream::get_constant() { + VM_ENTRY_MARK; + constantPoolHandle cpool(THREAD, _method->get_Method()->constants()); int pool_index = get_constant_raw_index(); int cache_index = -1; if (has_cache_index()) { cache_index = pool_index; - pool_index = -1; + pool_index = cpool->object_to_cp_index(cache_index); + } else if (cpool->tag_at(pool_index).is_dynamic_constant() || + cpool->tag_at(pool_index).is_dynamic_constant_in_error()) { + // Condy with primitive type is not quickened, so the index into resolved reference cache should be reconstructed. + assert(is_java_primitive(cpool->basic_type_for_constant_at(pool_index)), "not quickened"); + cache_index = cpool->cp_to_object_index(pool_index); } - VM_ENTRY_MARK; - constantPoolHandle cpool(THREAD, _method->get_Method()->constants()); return CURRENT_ENV->get_constant_by_index(cpool, pool_index, cache_index, _holder); } @@ -251,6 +256,22 @@ constantTag ciBytecodeStream::get_constant_pool_tag(int index) const { return _method->get_Method()->constants()->constant_tag_at(index); } +// ------------------------------------------------------------------ +// ciBytecodeStream::get_raw_pool_tag +// +constantTag ciBytecodeStream::get_raw_pool_tag(int index) const { + VM_ENTRY_MARK; + return _method->get_Method()->constants()->tag_at(index); +} + +// ------------------------------------------------------------------ +// ciBytecodeStream::get_basic_type_for_constant_at +// +BasicType ciBytecodeStream::get_basic_type_for_constant_at(int index) const { + VM_ENTRY_MARK; + return _method->get_Method()->constants()->basic_type_for_constant_at(index); +} + // ------------------------------------------------------------------ // ciBytecodeStream::get_field_index // @@ -476,8 +497,9 @@ ciKlass* ciBytecodeStream::get_declared_method_holder() { constantPoolHandle cpool(THREAD, _method->get_Method()->constants()); bool ignore; // report as MethodHandle for invokedynamic, which is syntactically classless - if (cur_bc() == Bytecodes::_invokedynamic) - return CURRENT_ENV->get_klass_by_name(_holder, ciSymbols::java_lang_invoke_MethodHandle(), false); + if (cur_bc() == Bytecodes::_invokedynamic) { + return CURRENT_ENV->MethodHandle_klass(); + } return CURRENT_ENV->get_klass_by_index(cpool, get_method_holder_index(), ignore, _holder); } diff --git a/src/hotspot/share/ci/ciStreams.hpp b/src/hotspot/share/ci/ciStreams.hpp index 8f46510a0d288182e813e9961d4f83c315b495b8..faf3e87cee64f405315777e37c114a0bf9b792e5 100644 --- a/src/hotspot/share/ci/ciStreams.hpp +++ b/src/hotspot/share/ci/ciStreams.hpp @@ -140,7 +140,7 @@ public: bool is_wide() const { return ( _pc == _was_wide ); } - // Does this instruction contain an index which refes into the CP cache? + // Does this instruction contain an index which refers into the CP cache? bool has_cache_index() const { return Bytecodes::uses_cp_cache(cur_bc_raw()); } int get_index_u1() const { @@ -226,8 +226,11 @@ public: // constant. Do not attempt to resolve it, since that would require // execution of Java code. If it is not resolved, return an unloaded // object (ciConstant.as_object()->is_loaded() == false). - ciConstant get_constant(); + ciConstant get_constant(); constantTag get_constant_pool_tag(int index) const; + BasicType get_basic_type_for_constant_at(int index) const; + + constantTag get_raw_pool_tag(int index) const; // True if the klass-using bytecode points to an unresolved klass bool is_unresolved_klass() const { @@ -235,9 +238,28 @@ public: return tag.is_unresolved_klass(); } - bool is_unresolved_klass_in_error() const { - constantTag tag = get_constant_pool_tag(get_klass_index()); - return tag.is_unresolved_klass_in_error(); + bool is_dynamic_constant() const { + assert(cur_bc() == Bytecodes::_ldc || + cur_bc() == Bytecodes::_ldc_w || + cur_bc() == Bytecodes::_ldc2_w, "not supported: %s", Bytecodes::name(cur_bc())); + + int index = get_constant_pool_index(); + constantTag tag = get_raw_pool_tag(index); + return tag.is_dynamic_constant() || + tag.is_dynamic_constant_in_error(); + } + + bool is_in_error() const { + assert(cur_bc() == Bytecodes::_ldc || + cur_bc() == Bytecodes::_ldc_w || + cur_bc() == Bytecodes::_ldc2_w, "not supported: %s", Bytecodes::name(cur_bc())); + + int index = get_constant_pool_index(); + constantTag tag = get_constant_pool_tag(index); + return tag.is_unresolved_klass_in_error() || + tag.is_method_handle_in_error() || + tag.is_method_type_in_error() || + tag.is_dynamic_constant_in_error(); } // If this bytecode is one of get_field, get_static, put_field, diff --git a/src/hotspot/share/ci/ciTypeFlow.cpp b/src/hotspot/share/ci/ciTypeFlow.cpp index 802ba97db2e7b2569cc0068348b276a47078f5d8..6ce6325cf91ff371aa4f643a3e84caf77f6e2328 100644 --- a/src/hotspot/share/ci/ciTypeFlow.cpp +++ b/src/hotspot/share/ci/ciTypeFlow.cpp @@ -720,9 +720,15 @@ void ciTypeFlow::StateVector::do_jsr(ciBytecodeStream* str) { // ------------------------------------------------------------------ // ciTypeFlow::StateVector::do_ldc void ciTypeFlow::StateVector::do_ldc(ciBytecodeStream* str) { + if (str->is_in_error()) { + trap(str, NULL, Deoptimization::make_trap_request(Deoptimization::Reason_unhandled, + Deoptimization::Action_none)); + return; + } ciConstant con = str->get_constant(); if (con.is_valid()) { - BasicType basic_type = con.basic_type(); + int index = str->get_constant_pool_index(); + BasicType basic_type = str->get_basic_type_for_constant_at(index); if (is_reference_type(basic_type)) { ciObject* obj = con.as_object(); if (obj->is_null_object()) { @@ -732,17 +738,14 @@ void ciTypeFlow::StateVector::do_ldc(ciBytecodeStream* str) { push_object(obj->klass()); } } else { + assert(basic_type == con.basic_type() || con.basic_type() == T_OBJECT, + "not a boxed form: %s vs %s", type2name(basic_type), type2name(con.basic_type())); push_translate(ciType::make(basic_type)); } } else { - if (str->is_unresolved_klass_in_error()) { - trap(str, NULL, Deoptimization::make_trap_request(Deoptimization::Reason_unhandled, - Deoptimization::Action_none)); - } else { - // OutOfMemoryError in the CI while loading constant - push_null(); - outer()->record_failure("ldc did not link"); - } + // OutOfMemoryError in the CI while loading a String constant. + push_null(); + outer()->record_failure("ldc did not link"); } } @@ -2173,7 +2176,7 @@ bool ciTypeFlow::can_trap(ciBytecodeStream& str) { case Bytecodes::_ldc: case Bytecodes::_ldc_w: case Bytecodes::_ldc2_w: - return str.is_unresolved_klass_in_error(); + return str.is_in_error(); case Bytecodes::_aload_0: // These bytecodes can trap for rewriting. We need to assume that @@ -2202,10 +2205,10 @@ bool ciTypeFlow::can_trap(ciBytecodeStream& str) { // ciTypeFlow::clone_loop_heads // // Clone the loop heads -bool ciTypeFlow::clone_loop_heads(Loop* lp, StateVector* temp_vector, JsrSet* temp_set) { +bool ciTypeFlow::clone_loop_heads(StateVector* temp_vector, JsrSet* temp_set) { bool rslt = false; for (PreorderLoops iter(loop_tree_root()); !iter.done(); iter.next()) { - lp = iter.current(); + Loop* lp = iter.current(); Block* head = lp->head(); if (lp == loop_tree_root() || lp->is_irreducible() || @@ -2450,6 +2453,102 @@ void ciTypeFlow::PreorderLoops::next() { } } +// If the tail is a branch to the head, retrieve how many times that path was taken from profiling +int ciTypeFlow::profiled_count(ciTypeFlow::Loop* loop) { + ciMethodData* methodData = method()->method_data(); + if (!methodData->is_mature()) { + return 0; + } + ciTypeFlow::Block* tail = loop->tail(); + if (tail->control() == -1) { + return 0; + } + + ciProfileData* data = methodData->bci_to_data(tail->control()); + + if (data == NULL || !data->is_JumpData()) { + return 0; + } + + ciBytecodeStream iter(method()); + iter.reset_to_bci(tail->control()); + + bool is_an_if = false; + bool wide = false; + Bytecodes::Code bc = iter.next(); + switch (bc) { + case Bytecodes::_ifeq: + case Bytecodes::_ifne: + case Bytecodes::_iflt: + case Bytecodes::_ifge: + case Bytecodes::_ifgt: + case Bytecodes::_ifle: + case Bytecodes::_if_icmpeq: + case Bytecodes::_if_icmpne: + case Bytecodes::_if_icmplt: + case Bytecodes::_if_icmpge: + case Bytecodes::_if_icmpgt: + case Bytecodes::_if_icmple: + case Bytecodes::_if_acmpeq: + case Bytecodes::_if_acmpne: + case Bytecodes::_ifnull: + case Bytecodes::_ifnonnull: + is_an_if = true; + break; + case Bytecodes::_goto_w: + case Bytecodes::_jsr_w: + wide = true; + break; + case Bytecodes::_goto: + case Bytecodes::_jsr: + break; + default: + fatal(" invalid bytecode: %s", Bytecodes::name(iter.cur_bc())); + } + + GrowableArray* succs = tail->successors(); + + if (!is_an_if) { + assert(((wide ? iter.get_far_dest() : iter.get_dest()) == loop->head()->start()) == (succs->at(ciTypeFlow::GOTO_TARGET) == loop->head()), "branch should lead to loop head"); + if (succs->at(ciTypeFlow::GOTO_TARGET) == loop->head()) { + return method()->scale_count(data->as_JumpData()->taken()); + } + } else { + assert((iter.get_dest() == loop->head()->start()) == (succs->at(ciTypeFlow::IF_TAKEN) == loop->head()), "bytecode and CFG not consistent"); + assert((tail->limit() == loop->head()->start()) == (succs->at(ciTypeFlow::IF_NOT_TAKEN) == loop->head()), "bytecode and CFG not consistent"); + if (succs->at(ciTypeFlow::IF_TAKEN) == loop->head()) { + return method()->scale_count(data->as_JumpData()->taken()); + } else if (succs->at(ciTypeFlow::IF_NOT_TAKEN) == loop->head()) { + return method()->scale_count(data->as_BranchData()->not_taken()); + } + } + + return 0; +} + +bool ciTypeFlow::Loop::at_insertion_point(Loop* lp, Loop* current) { + int lp_pre_order = lp->head()->pre_order(); + if (current->head()->pre_order() < lp_pre_order) { + return true; + } else if (current->head()->pre_order() > lp_pre_order) { + return false; + } + // In the case of a shared head, make the most frequent head/tail (as reported by profiling) the inner loop + if (current->head() == lp->head()) { + int lp_count = outer()->profiled_count(lp); + int current_count = outer()->profiled_count(current); + if (current_count < lp_count) { + return true; + } else if (current_count > lp_count) { + return false; + } + } + if (current->tail()->pre_order() > lp->tail()->pre_order()) { + return true; + } + return false; +} + // ------------------------------------------------------------------ // ciTypeFlow::Loop::sorted_merge // @@ -2467,12 +2566,10 @@ ciTypeFlow::Loop* ciTypeFlow::Loop::sorted_merge(Loop* lp) { int lp_pre_order = lp->head()->pre_order(); // Find insertion point for "lp" while (current != NULL) { - if (current == lp) + if (current == lp) { return leaf; // Already in list - if (current->head()->pre_order() < lp_pre_order) - break; - if (current->head()->pre_order() == lp_pre_order && - current->tail()->pre_order() > lp->tail()->pre_order()) { + } + if (at_insertion_point(lp, current)) { break; } prev = current; @@ -2732,7 +2829,7 @@ void ciTypeFlow::flow_types() { env()->comp_level() >= CompLevel_full_optimization) { // Loop optimizations are not performed on Tier1 compiles. - bool changed = clone_loop_heads(loop_tree_root(), temp_vector, temp_set); + bool changed = clone_loop_heads(temp_vector, temp_set); // If some loop heads were cloned, recompute postorder and loop tree if (changed) { diff --git a/src/hotspot/share/ci/ciTypeFlow.hpp b/src/hotspot/share/ci/ciTypeFlow.hpp index 907897fe310000835410711617a2355756fdc109..b733a694f380073a8c5549fc9a4bc855bc383984 100644 --- a/src/hotspot/share/ci/ciTypeFlow.hpp +++ b/src/hotspot/share/ci/ciTypeFlow.hpp @@ -717,6 +717,9 @@ public: bool _irreducible; LocalSet _def_locals; + ciTypeFlow* outer() const { return head()->outer(); } + bool at_insertion_point(Loop* lp, Loop* current); + public: Loop(Block* head, Block* tail) : _parent(NULL), _sibling(NULL), _child(NULL), @@ -795,7 +798,7 @@ private: bool can_trap(ciBytecodeStream& str); // Clone the loop heads. Returns true if any cloning occurred. - bool clone_loop_heads(Loop* lp, StateVector* temp_vector, JsrSet* temp_set); + bool clone_loop_heads(StateVector* temp_vector, JsrSet* temp_set); // Clone lp's head and replace tail's successors with clone. Block* clone_loop_head(Loop* lp, StateVector* temp_vector, JsrSet* temp_set); @@ -913,6 +916,8 @@ private: // Create the block map, which indexes blocks in pre_order. void map_blocks(); + int profiled_count(ciTypeFlow::Loop* loop); + public: // Perform type inference flow analysis. void do_flow(); diff --git a/src/hotspot/share/classfile/altHashing.cpp b/src/hotspot/share/classfile/altHashing.cpp index d0672138668f9d51672b10eed8610a0be8611716..98c5502fc1fddb21768aa49d0141390476affd29 100644 --- a/src/hotspot/share/classfile/altHashing.cpp +++ b/src/hotspot/share/classfile/altHashing.cpp @@ -26,18 +26,23 @@ * halfsiphash code adapted from reference implementation * (https://github.com/veorq/SipHash/blob/master/halfsiphash.c) * which is distributed with the following copyright: - * - * SipHash reference C implementation - * - * Copyright (c) 2016 Jean-Philippe Aumasson - * - * To the extent possible under law, the author(s) have dedicated all copyright - * and related and neighboring rights to this software to the public domain - * worldwide. This software is distributed without any warranty. - * - * You should have received a copy of the CC0 Public Domain Dedication along - * with this software. If not, see - * . + */ + +/* + SipHash reference C implementation + + Copyright (c) 2012-2021 Jean-Philippe Aumasson + + Copyright (c) 2012-2014 Daniel J. Bernstein + + To the extent possible under law, the author(s) have dedicated all copyright + and related and neighboring rights to this software to the public domain + worldwide. This software is distributed without any warranty. + + You should have received a copy of the CC0 Public Domain Dedication along + with + this software. If not, see + . */ #include "precompiled.hpp" @@ -135,7 +140,9 @@ static uint64_t halfsiphash_finish64(uint32_t v[4], int rounds) { } // HalfSipHash-2-4 (32-bit output) for Symbols -uint32_t AltHashing::halfsiphash_32(uint64_t seed, const uint8_t* data, int len) { +uint32_t AltHashing::halfsiphash_32(uint64_t seed, const void* in, int len) { + + const unsigned char* data = (const unsigned char*)in; uint32_t v[4]; uint32_t newdata; int off = 0; diff --git a/src/hotspot/share/classfile/altHashing.hpp b/src/hotspot/share/classfile/altHashing.hpp index e1726ae5152b7bd048467a418fc0dcd8a85bfd64..555720c0666d9152e5e31b4707cb6cf35ad53c69 100644 --- a/src/hotspot/share/classfile/altHashing.hpp +++ b/src/hotspot/share/classfile/altHashing.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -26,7 +26,8 @@ #define SHARE_CLASSFILE_ALTHASHING_HPP #include "jni.h" -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" +#include "utilities/globalDefinitions.hpp" /** * Implementation of alternate more secure hashing. @@ -43,7 +44,7 @@ class AltHashing : AllStatic { static uint64_t compute_seed(); // For Symbols - static uint32_t halfsiphash_32(uint64_t seed, const uint8_t* data, int len); + static uint32_t halfsiphash_32(uint64_t seed, const void* in, int len); // For Strings static uint32_t halfsiphash_32(uint64_t seed, const uint16_t* data, int len); }; diff --git a/src/hotspot/share/classfile/classFileParser.cpp b/src/hotspot/share/classfile/classFileParser.cpp index a7ae7bef5c3d5e5dcbf6c3189846e0dc497db0ef..182ed43bedf91a25aa7734f1d87e0f0fc2e41da4 100644 --- a/src/hotspot/share/classfile/classFileParser.cpp +++ b/src/hotspot/share/classfile/classFileParser.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -139,6 +139,8 @@ #define JAVA_18_VERSION 62 +#define JAVA_19_VERSION 63 + void ClassFileParser::set_class_bad_constant_seen(short bad_constant) { assert((bad_constant == JVM_CONSTANT_Module || bad_constant == JVM_CONSTANT_Package) && _major_version >= JAVA_9_VERSION, @@ -2739,6 +2741,7 @@ Method* ClassFileParser::parse_method(const ClassFileStream* const cfs, access_flags, &sizes, ConstMethod::NORMAL, + _cp->symbol_at(name_index), CHECK_NULL); ClassLoadingService::add_class_method_size(m->size()*wordSize); @@ -2835,7 +2838,8 @@ Method* ClassFileParser::parse_method(const ClassFileStream* const cfs, annotation_default_length, CHECK_NULL); - if (name == vmSymbols::finalize_method_name() && + if (InstanceKlass::is_finalization_enabled() && + name == vmSymbols::finalize_method_name() && signature == vmSymbols::void_method_signature()) { if (m->is_empty_method()) { _has_empty_finalizer = true; @@ -3050,6 +3054,7 @@ static int inner_classes_jump_to_outer(const Array* inner_classes, int inner static bool inner_classes_check_loop_through_outer(const Array* inner_classes, int idx, const ConstantPool* cp, int length) { int slow = inner_classes->at(idx + InstanceKlass::inner_class_inner_class_info_offset); int fast = inner_classes->at(idx + InstanceKlass::inner_class_outer_class_info_offset); + while (fast != -1 && fast != 0) { if (slow != 0 && (cp->klass_name_at(slow) == cp->klass_name_at(fast))) { return true; // found a circularity @@ -3079,14 +3084,15 @@ bool ClassFileParser::check_inner_classes_circularity(const ConstantPool* cp, in for (int y = idx + InstanceKlass::inner_class_next_offset; y < length; y += InstanceKlass::inner_class_next_offset) { - // To maintain compatibility, throw an exception if duplicate inner classes - // entries are found. - guarantee_property((_inner_classes->at(idx) != _inner_classes->at(y) || - _inner_classes->at(idx+1) != _inner_classes->at(y+1) || - _inner_classes->at(idx+2) != _inner_classes->at(y+2) || - _inner_classes->at(idx+3) != _inner_classes->at(y+3)), - "Duplicate entry in InnerClasses attribute in class file %s", - CHECK_(true)); + // 4347400: make sure there's no duplicate entry in the classes array + if (_major_version >= JAVA_1_5_VERSION) { + guarantee_property((_inner_classes->at(idx) != _inner_classes->at(y) || + _inner_classes->at(idx+1) != _inner_classes->at(y+1) || + _inner_classes->at(idx+2) != _inner_classes->at(y+2) || + _inner_classes->at(idx+3) != _inner_classes->at(y+3)), + "Duplicate entry in InnerClasses attribute in class file %s", + CHECK_(true)); + } // Return true if there are two entries with the same inner_class_info_index. if (_inner_classes->at(y) == _inner_classes->at(idx)) { return true; @@ -3179,10 +3185,9 @@ u2 ClassFileParser::parse_classfile_inner_classes_attribute(const ClassFileStrea inner_classes->at_put(index++, inner_access_flags.as_short()); } - // 4347400: make sure there's no duplicate entry in the classes array - // Also, check for circular entries. + // Check for circular and duplicate entries. bool has_circularity = false; - if (_need_verify && _major_version >= JAVA_1_5_VERSION) { + if (_need_verify) { has_circularity = check_inner_classes_circularity(cp, length * 4, CHECK_0); if (has_circularity) { // If circularity check failed then ignore InnerClasses attribute. @@ -4171,7 +4176,8 @@ void ClassFileParser::set_precomputed_flags(InstanceKlass* ik) { bool f = false; const Method* const m = ik->lookup_method(vmSymbols::finalize_method_name(), vmSymbols::void_method_signature()); - if (m != NULL && !m->is_empty_method()) { + if (InstanceKlass::is_finalization_enabled() && + (m != NULL) && !m->is_empty_method()) { f = true; } @@ -4525,7 +4531,6 @@ void ClassFileParser::verify_legal_class_modifiers(jint flags, TRAPS) const { const bool is_enum = (flags & JVM_ACC_ENUM) != 0; const bool is_annotation = (flags & JVM_ACC_ANNOTATION) != 0; const bool major_gte_1_5 = _major_version >= JAVA_1_5_VERSION; - const bool major_gte_14 = _major_version >= JAVA_14_VERSION; if ((is_abstract && is_final) || (is_interface && !is_abstract) || @@ -4781,7 +4786,7 @@ bool ClassFileParser::verify_unqualified_name(const char* name, // Take pointer to a UTF8 byte string (not NUL-terminated). // Skip over the longest part of the string that could -// be taken as a fieldname. Allow '/' if slash_ok is true. +// be taken as a fieldname. Allow non-trailing '/'s if slash_ok is true. // Return a pointer to just past the fieldname. // Return NULL if no fieldname at all was found, or in the case of slash_ok // being true, we saw consecutive slashes (meaning we were looking for a @@ -4855,7 +4860,7 @@ static const char* skip_over_field_name(const char* const name, } return (not_first_ch) ? old_p : NULL; } - return (not_first_ch) ? p : NULL; + return (not_first_ch && !last_is_slash) ? p : NULL; } // Take pointer to a UTF8 byte string (not NUL-terminated). diff --git a/src/hotspot/share/classfile/classLoader.cpp b/src/hotspot/share/classfile/classLoader.cpp index cf5ede2415fbcb41bd25eb3b188fdd2c7b914606..bf450cbf407414851acea8b0e074f393e94ce997 100644 --- a/src/hotspot/share/classfile/classLoader.cpp +++ b/src/hotspot/share/classfile/classLoader.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -99,7 +99,8 @@ static FindEntry_t FindEntry = NULL; static ReadEntry_t ReadEntry = NULL; static GetNextEntry_t GetNextEntry = NULL; static Crc32_t Crc32 = NULL; -int ClassLoader::_libzip_loaded = 0; +int ClassLoader::_libzip_loaded = 0; +void* ClassLoader::_zip_handle = NULL; // Entry points for jimage.dll for loading jimage file entries @@ -253,9 +254,9 @@ ClassFileStream* ClassPathDirEntry::open_stream(JavaThread* current, const char* if (file_handle != -1) { // read contents into resource array u1* buffer = NEW_RESOURCE_ARRAY(u1, st.st_size); - size_t num_read = os::read(file_handle, (char*) buffer, st.st_size); + size_t num_read = ::read(file_handle, (char*) buffer, st.st_size); // close file - os::close(file_handle); + ::close(file_handle); // construct ClassFileStream if (num_read == (size_t)st.st_size) { if (UsePerfData) { @@ -303,13 +304,19 @@ u1* ClassPathZipEntry::open_entry(JavaThread* current, const char* name, jint* f } // read contents into resource array - int size = (*filesize) + ((nul_terminate) ? 1 : 0); + size_t size = (uint32_t)(*filesize); + if (nul_terminate) { + if (sizeof(size) == sizeof(uint32_t) && size == UINT_MAX) { + return NULL; // 32-bit integer overflow will occur. + } + size++; + } buffer = NEW_RESOURCE_ARRAY(u1, size); if (!(*ReadEntry)(_zip, entry, buffer, filename)) return NULL; // return result if (nul_terminate) { - buffer[*filesize] = 0; + buffer[size - 1] = 0; } return buffer; } @@ -936,20 +943,19 @@ void ClassLoader::load_zip_library() { assert(ZipOpen == NULL, "should not load zip library twice"); char path[JVM_MAXPATHLEN]; char ebuf[1024]; - void* handle = NULL; if (os::dll_locate_lib(path, sizeof(path), Arguments::get_dll_dir(), "zip")) { - handle = os::dll_load(path, ebuf, sizeof ebuf); + _zip_handle = os::dll_load(path, ebuf, sizeof ebuf); } - if (handle == NULL) { + if (_zip_handle == NULL) { vm_exit_during_initialization("Unable to load zip library", path); } - ZipOpen = CAST_TO_FN_PTR(ZipOpen_t, dll_lookup(handle, "ZIP_Open", path)); - ZipClose = CAST_TO_FN_PTR(ZipClose_t, dll_lookup(handle, "ZIP_Close", path)); - FindEntry = CAST_TO_FN_PTR(FindEntry_t, dll_lookup(handle, "ZIP_FindEntry", path)); - ReadEntry = CAST_TO_FN_PTR(ReadEntry_t, dll_lookup(handle, "ZIP_ReadEntry", path)); - GetNextEntry = CAST_TO_FN_PTR(GetNextEntry_t, dll_lookup(handle, "ZIP_GetNextEntry", path)); - Crc32 = CAST_TO_FN_PTR(Crc32_t, dll_lookup(handle, "ZIP_CRC32", path)); + ZipOpen = CAST_TO_FN_PTR(ZipOpen_t, dll_lookup(_zip_handle, "ZIP_Open", path)); + ZipClose = CAST_TO_FN_PTR(ZipClose_t, dll_lookup(_zip_handle, "ZIP_Close", path)); + FindEntry = CAST_TO_FN_PTR(FindEntry_t, dll_lookup(_zip_handle, "ZIP_FindEntry", path)); + ReadEntry = CAST_TO_FN_PTR(ReadEntry_t, dll_lookup(_zip_handle, "ZIP_ReadEntry", path)); + GetNextEntry = CAST_TO_FN_PTR(GetNextEntry_t, dll_lookup(_zip_handle, "ZIP_GetNextEntry", path)); + Crc32 = CAST_TO_FN_PTR(Crc32_t, dll_lookup(_zip_handle, "ZIP_CRC32", path)); } void ClassLoader::load_jimage_library() { @@ -1253,7 +1259,8 @@ char* ClassLoader::skip_uri_protocol(char* source) { // Record the shared classpath index and loader type for classes loaded // by the builtin loaders at dump time. -void ClassLoader::record_result(JavaThread* current, InstanceKlass* ik, const ClassFileStream* stream) { +void ClassLoader::record_result(JavaThread* current, InstanceKlass* ik, + const ClassFileStream* stream, bool redefined) { Arguments::assert_is_dumping_archive(); assert(stream != NULL, "sanity"); @@ -1337,10 +1344,10 @@ void ClassLoader::record_result(JavaThread* current, InstanceKlass* ik, const Cl } } - // No path entry found for this class. Must be a shared class loaded by the + // No path entry found for this class: most likely a shared class loaded by the // user defined classloader. - if (classpath_index < 0) { - assert(ik->shared_classpath_index() < 0, "Sanity"); + if (classpath_index < 0 && !SystemDictionaryShared::is_builtin_loader(ik->class_loader_data())) { + assert(ik->shared_classpath_index() < 0, "not assigned yet"); ik->set_shared_classpath_index(UNREGISTERED_INDEX); SystemDictionaryShared::set_shared_class_misc_info(ik, (ClassFileStream*)stream); return; @@ -1359,7 +1366,7 @@ void ClassLoader::record_result(JavaThread* current, InstanceKlass* ik, const Cl ik->name()->utf8_length()); assert(file_name != NULL, "invariant"); - ClassLoaderExt::record_result(classpath_index, ik); + ClassLoaderExt::record_result(classpath_index, ik, redefined); } #endif // INCLUDE_CDS diff --git a/src/hotspot/share/classfile/classLoader.hpp b/src/hotspot/share/classfile/classLoader.hpp index 9cafdd2a83e4f3b09217d26da134eebf23d98392..d2f2c6ccef1926e3c88801c9787af0c66fff0510 100644 --- a/src/hotspot/share/classfile/classLoader.hpp +++ b/src/hotspot/share/classfile/classLoader.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -229,6 +229,9 @@ class ClassLoader: AllStatic { bool check_for_duplicates); CDS_ONLY(static void add_to_module_path_entries(const char* path, ClassPathEntry* entry);) + + // cache the zip library handle + static void* _zip_handle; public: CDS_ONLY(static ClassPathEntry* app_classpath_entries() {return _app_classpath_entries;}) CDS_ONLY(static ClassPathEntry* module_path_entries() {return _module_path_entries;}) @@ -253,9 +256,10 @@ class ClassLoader: AllStatic { private: static int _libzip_loaded; // used to sync loading zip. static void release_load_zip_library(); - static inline void load_zip_library_if_needed(); public: + static inline void load_zip_library_if_needed(); + static void* zip_library_handle() { return _zip_handle; } static jzfile* open_zip_file(const char* canonical_path, char** error_msg, JavaThread* thread); static ClassPathEntry* create_class_path_entry(JavaThread* current, const char *path, const struct stat* st, @@ -365,7 +369,8 @@ class ClassLoader: AllStatic { static int num_module_path_entries(); static void exit_with_path_failure(const char* error, const char* message); static char* skip_uri_protocol(char* source); - static void record_result(JavaThread* current, InstanceKlass* ik, const ClassFileStream* stream); + static void record_result(JavaThread* current, InstanceKlass* ik, + const ClassFileStream* stream, bool redefined); #endif static char* lookup_vm_options(); diff --git a/src/hotspot/share/classfile/classLoaderData.cpp b/src/hotspot/share/classfile/classLoaderData.cpp index 0f1840cc9a6c0f9537f0bb07a41320e99fbf8c20..e3a3ada3e8a9e1d1cc2a57926e0651c892670f75 100644 --- a/src/hotspot/share/classfile/classLoaderData.cpp +++ b/src/hotspot/share/classfile/classLoaderData.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -67,6 +67,7 @@ #include "memory/universe.hpp" #include "oops/access.inline.hpp" #include "oops/klass.inline.hpp" +#include "oops/objArrayKlass.hpp" #include "oops/oop.inline.hpp" #include "oops/oopHandle.inline.hpp" #include "oops/weakHandle.inline.hpp" @@ -358,15 +359,28 @@ void ClassLoaderData::loaded_classes_do(KlassClosure* klass_closure) { // Lock-free access requires load_acquire for (Klass* k = Atomic::load_acquire(&_klasses); k != NULL; k = k->next_link()) { - // Do not filter ArrayKlass oops here... - if (k->is_array_klass() || (k->is_instance_klass() && InstanceKlass::cast(k)->is_loaded())) { + // Filter out InstanceKlasses (or their ObjArrayKlasses) that have not entered the + // loaded state. + if (k->is_instance_klass()) { + if (!InstanceKlass::cast(k)->is_loaded()) { + continue; + } + } else if (k->is_shared() && k->is_objArray_klass()) { + Klass* bottom = ObjArrayKlass::cast(k)->bottom_klass(); + if (bottom->is_instance_klass() && !InstanceKlass::cast(bottom)->is_loaded()) { + // This could happen if is a shared class that has been restored + // but is not yet marked as loaded. All archived array classes of the + // bottom class are already restored and placed in the _klasses list. + continue; + } + } + #ifdef ASSERT - oop m = k->java_mirror(); - assert(m != NULL, "NULL mirror"); - assert(m->is_a(vmClasses::Class_klass()), "invalid mirror"); + oop m = k->java_mirror(); + assert(m != NULL, "NULL mirror"); + assert(m->is_a(vmClasses::Class_klass()), "invalid mirror"); #endif - klass_closure->do_klass(k); - } + klass_closure->do_klass(k); } } @@ -615,8 +629,9 @@ Dictionary* ClassLoaderData::create_dictionary() { return new Dictionary(this, size, resizable); } -// Tell the GC to keep this klass alive while iterating ClassLoaderDataGraph -oop ClassLoaderData::holder_phantom() const { +// Tell the GC to keep this klass alive. Needed while iterating ClassLoaderDataGraph, +// and any runtime code that uses klasses. +oop ClassLoaderData::holder() const { // A klass that was previously considered dead can be looked up in the // CLD/SD, and its _java_mirror or _class_loader can be stored in a root // or a reachable object making it alive again. The SATB part of G1 needs diff --git a/src/hotspot/share/classfile/classLoaderData.hpp b/src/hotspot/share/classfile/classLoaderData.hpp index bb4938750433eed17e860478dfd1f4e199a64393..0d6defae93515c9dd0bda709a59dce638deb0e99 100644 --- a/src/hotspot/share/classfile/classLoaderData.hpp +++ b/src/hotspot/share/classfile/classLoaderData.hpp @@ -174,7 +174,7 @@ class ClassLoaderData : public CHeapObj { bool has_modified_oops() { return _modified_oops; } oop holder_no_keepalive() const; - oop holder_phantom() const; + oop holder() const; private: void unload(); diff --git a/src/hotspot/share/classfile/classLoaderDataGraph.cpp b/src/hotspot/share/classfile/classLoaderDataGraph.cpp index c1e672a0c4343939cc0651f23075db1f842f25ba..4cbee3ec7d8ae6070e98942a6d3f0efee396cd0c 100644 --- a/src/hotspot/share/classfile/classLoaderDataGraph.cpp +++ b/src/hotspot/share/classfile/classLoaderDataGraph.cpp @@ -336,7 +336,7 @@ public: } if (cld != NULL) { // Keep cld that is being returned alive. - _holder = Handle(_thread, cld->holder_phantom()); + _holder = Handle(_thread, cld->holder()); _next = cld->next(); } else { _next = NULL; diff --git a/src/hotspot/share/classfile/classLoaderExt.cpp b/src/hotspot/share/classfile/classLoaderExt.cpp index e571f2deda8a84b1a65681c8235d5b3df976b4b0..b6da1fb52c041830ca91337c4de3e5173fd8da0d 100644 --- a/src/hotspot/share/classfile/classLoaderExt.cpp +++ b/src/hotspot/share/classfile/classLoaderExt.cpp @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "cds/filemap.hpp" +#include "cds/heapShared.hpp" #include "classfile/classFileParser.hpp" #include "classfile/classLoader.inline.hpp" #include "classfile/classLoaderExt.hpp" @@ -227,7 +228,7 @@ void ClassLoaderExt::setup_search_paths(JavaThread* current) { ClassLoaderExt::setup_app_search_path(current); } -void ClassLoaderExt::record_result(const s2 classpath_index, InstanceKlass* result) { +void ClassLoaderExt::record_result(const s2 classpath_index, InstanceKlass* result, bool redefined) { Arguments::assert_is_dumping_archive(); // We need to remember where the class comes from during dumping. @@ -245,4 +246,21 @@ void ClassLoaderExt::record_result(const s2 classpath_index, InstanceKlass* resu } result->set_shared_classpath_index(classpath_index); result->set_shared_class_loader_type(classloader_type); +#if INCLUDE_CDS_JAVA_HEAP + if (DumpSharedSpaces && AllowArchivingWithJavaAgent && classloader_type == ClassLoader::BOOT_LOADER && + classpath_index < 0 && HeapShared::can_write() && redefined) { + // During static dump, classes for the built-in loaders are always loaded from + // known locations (jimage, classpath or modulepath), so classpath_index should + // always be >= 0. + // The only exception is when a java agent is used during dump time (for testing + // purposes only). If a class is transformed by the agent, the CodeSource of + // this class may point to an unknown location. This may break heap object archiving, + // which requires all the boot classes to be from known locations. This is an + // uncommon scenario (even in test cases). Let's simply disable heap object archiving. + ResourceMark rm; + log_warning(cds)("CDS heap objects cannot be written because class %s maybe modified by ClassFileLoadHook.", + result->external_name()); + HeapShared::disable_writing(); + } +#endif // INCLUDE_CDS_JAVA_HEAP } diff --git a/src/hotspot/share/classfile/classLoaderExt.hpp b/src/hotspot/share/classfile/classLoaderExt.hpp index cbc5481db7872079c3b59721ee73d59784327a88..7e58bc6d1e3f70c05c7f17a577e35e017eff8b23 100644 --- a/src/hotspot/share/classfile/classLoaderExt.hpp +++ b/src/hotspot/share/classfile/classLoaderExt.hpp @@ -111,7 +111,7 @@ public: return _has_non_jar_in_classpath; } - static void record_result(const s2 classpath_index, InstanceKlass* result); + static void record_result(const s2 classpath_index, InstanceKlass* result, bool redefined); static void set_has_app_classes() { _has_app_classes = true; } diff --git a/src/hotspot/share/classfile/compactHashtable.cpp b/src/hotspot/share/classfile/compactHashtable.cpp index dc21ee4e7f3913ed4375d59894c69b8483a7570d..4538af56e4b9ebaa6a5cf24bfa492502f650fd88 100644 --- a/src/hotspot/share/classfile/compactHashtable.cpp +++ b/src/hotspot/share/classfile/compactHashtable.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -252,7 +252,7 @@ HashtableTextDump::HashtableTextDump(const char* filename) : _fd(-1) { HashtableTextDump::~HashtableTextDump() { os::unmap_memory((char*)_base, _size); if (_fd >= 0) { - close(_fd); + ::close(_fd); } } diff --git a/src/hotspot/share/classfile/defaultMethods.cpp b/src/hotspot/share/classfile/defaultMethods.cpp index 2ef313982d75037a580e7777b7e7667e121b05e1..4d181bdadf0dd1ad204b51c9566602aa648ad6bf 100644 --- a/src/hotspot/share/classfile/defaultMethods.cpp +++ b/src/hotspot/share/classfile/defaultMethods.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -900,7 +900,7 @@ static Method* new_method( Method* m = Method::allocate(cp->pool_holder()->class_loader_data(), code_length, flags, &sizes, - mt, CHECK_NULL); + mt, name, CHECK_NULL); m->set_constants(NULL); // This will get filled in later m->set_name_index(cp->utf8(name)); diff --git a/src/hotspot/share/classfile/javaClasses.cpp b/src/hotspot/share/classfile/javaClasses.cpp index 9c92c767fd81fbf557e667fadbc3314a252625ad..ae76dea73aa8fb73429e104aa9f0d814ef6bb41e 100644 --- a/src/hotspot/share/classfile/javaClasses.cpp +++ b/src/hotspot/share/classfile/javaClasses.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -4087,11 +4087,20 @@ void java_lang_invoke_MethodType::serialize_offsets(SerializeClosure* f) { void java_lang_invoke_MethodType::print_signature(oop mt, outputStream* st) { st->print("("); objArrayOop pts = ptypes(mt); - for (int i = 0, limit = pts->length(); i < limit; i++) { - java_lang_Class::print_signature(pts->obj_at(i), st); + if (pts != NULL) { + for (int i = 0, limit = pts->length(); i < limit; i++) { + java_lang_Class::print_signature(pts->obj_at(i), st); + } + } else { + st->print("NULL"); } st->print(")"); - java_lang_Class::print_signature(rtype(mt), st); + oop rt = rtype(mt); + if (rt != NULL) { + java_lang_Class::print_signature(rt, st); + } else { + st->print("NULL"); + } } Symbol* java_lang_invoke_MethodType::as_signature(oop mt, bool intern_if_not_found) { diff --git a/src/hotspot/share/classfile/klassFactory.cpp b/src/hotspot/share/classfile/klassFactory.cpp index 7b5960ee36ef6d569f0ab9c34d3626467d8777b1..de3e176a464b75c94902e1fd3123bf5becb32d4f 100644 --- a/src/hotspot/share/classfile/klassFactory.cpp +++ b/src/hotspot/share/classfile/klassFactory.cpp @@ -211,7 +211,7 @@ InstanceKlass* KlassFactory::create_from_stream(ClassFileStream* stream, #if INCLUDE_CDS if (Arguments::is_dumping_archive()) { - ClassLoader::record_result(THREAD, result, stream); + ClassLoader::record_result(THREAD, result, stream, old_stream != stream); } #endif // INCLUDE_CDS diff --git a/src/hotspot/share/classfile/klassFactory.hpp b/src/hotspot/share/classfile/klassFactory.hpp index 2b2ee36dfa35bc3df6786dacccd279ed56e4bd82..b1584b3e2caec64e670927f1e524231834da9a97 100644 --- a/src/hotspot/share/classfile/klassFactory.hpp +++ b/src/hotspot/share/classfile/klassFactory.hpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. +* 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 @@ -25,7 +25,7 @@ #ifndef SHARE_CLASSFILE_KLASSFACTORY_HPP #define SHARE_CLASSFILE_KLASSFACTORY_HPP -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" #include "runtime/handles.hpp" class ClassFileStream; diff --git a/src/hotspot/share/classfile/modules.hpp b/src/hotspot/share/classfile/modules.hpp index 31cab8209fa28a75e1a7d8fac106e2576abe617c..5c52a323b0cfdfd933df02aa6d20c712d3df88a7 100644 --- a/src/hotspot/share/classfile/modules.hpp +++ b/src/hotspot/share/classfile/modules.hpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. +* 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 @@ -25,7 +25,7 @@ #ifndef SHARE_CLASSFILE_MODULES_HPP #define SHARE_CLASSFILE_MODULES_HPP -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" #include "runtime/handles.hpp" class ModuleEntryTable; diff --git a/src/hotspot/share/classfile/stringTable.cpp b/src/hotspot/share/classfile/stringTable.cpp index c43f940b790a49b61f04df02a0fd930f16315cb6..e3015a02eb5a477e7ab197576c7a2138abc6b3de 100644 --- a/src/hotspot/share/classfile/stringTable.cpp +++ b/src/hotspot/share/classfile/stringTable.cpp @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "cds/archiveBuilder.hpp" +#include "cds/filemap.hpp" #include "cds/heapShared.inline.hpp" #include "classfile/altHashing.hpp" #include "classfile/compactHashtable.hpp" @@ -55,6 +56,9 @@ #include "utilities/macros.hpp" #include "utilities/resizeableResourceHash.hpp" #include "utilities/utf8.hpp" +#if INCLUDE_G1GC +#include "gc/g1/g1CollectedHeap.hpp" +#endif // We prefer short chains of avg 2 const double PREF_AVG_LIST_LEN = 2.0; @@ -67,9 +71,18 @@ const double CLEAN_DEAD_HIGH_WATER_MARK = 0.5; #if INCLUDE_CDS_JAVA_HEAP inline oop read_string_from_compact_hashtable(address base_address, u4 offset) { - assert(sizeof(narrowOop) == sizeof(offset), "must be"); - narrowOop v = CompressedOops::narrow_oop_cast(offset); - return HeapShared::decode_from_archive(v); + if (UseCompressedOops) { + assert(sizeof(narrowOop) == sizeof(offset), "must be"); + narrowOop v = CompressedOops::narrow_oop_cast(offset); + return HeapShared::decode_from_archive(v); + } else { + intptr_t dumptime_oop = (uintptr_t)offset; + assert(dumptime_oop != 0, "null strings cannot be interned"); + intptr_t runtime_oop = dumptime_oop + + (intptr_t)FileMapInfo::current_info()->header()->heap_begin() + + (intptr_t)HeapShared::runtime_delta(); + return (oop)cast_to_oop(runtime_oop); + } } typedef CompactHashtable< @@ -746,6 +759,16 @@ oop StringTable::create_archived_string(oop s) { class CopyToArchive : StackObj { CompactHashtableWriter* _writer; +private: + u4 compute_delta(oop s) { + HeapWord* start = G1CollectedHeap::heap()->reserved().start(); + intx offset = ((address)(void*)s) - ((address)(void*)start); + assert(offset >= 0, "must be"); + if (offset > 0xffffffff) { + fatal("too large"); + } + return (u4)offset; + } public: CopyToArchive(CompactHashtableWriter* writer) : _writer(writer) {} bool do_entry(oop s, bool value_ignored) { @@ -757,7 +780,11 @@ public: } // add to the compact table - _writer->add(hash, CompressedOops::narrow_oop_value(new_s)); + if (UseCompressedOops) { + _writer->add(hash, CompressedOops::narrow_oop_value(new_s)); + } else { + _writer->add(hash, compute_delta(new_s)); + } return true; } }; @@ -771,7 +798,6 @@ void StringTable::write_to_archive(const DumpedInternedStrings* dumped_interned_ // Copy the interned strings into the "string space" within the java heap CopyToArchive copier(&writer); dumped_interned_strings->iterate(&copier); - writer.dump(&_shared_table, "string"); } diff --git a/src/hotspot/share/classfile/symbolTable.cpp b/src/hotspot/share/classfile/symbolTable.cpp index fa966fc7b22af71a5941cb924465221ea4d8650a..a321d94bbd2b0261fe0f82299c0ac5ab79cd6830 100644 --- a/src/hotspot/share/classfile/symbolTable.cpp +++ b/src/hotspot/share/classfile/symbolTable.cpp @@ -91,7 +91,14 @@ static volatile bool _has_items_to_clean = false; static volatile bool _alt_hash = false; + +#ifdef USE_LIBRARY_BASED_TLS_ONLY static volatile bool _lookup_shared_first = false; +#else +// "_lookup_shared_first" can get highly contended with many cores if multiple threads +// are updating "lookup success history" in a global shared variable. If built-in TLS is available, use it. +static THREAD_LOCAL bool _lookup_shared_first = false; +#endif // Static arena for symbols that are not deallocated Arena* SymbolTable::_arena = NULL; diff --git a/src/hotspot/share/classfile/systemDictionary.cpp b/src/hotspot/share/classfile/systemDictionary.cpp index 38e07f12be2dc66c5a449c20d37d490be7374b6d..c3b9b0104431970b4fbc6272c40b9a4631b1b296 100644 --- a/src/hotspot/share/classfile/systemDictionary.cpp +++ b/src/hotspot/share/classfile/systemDictionary.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -1559,8 +1559,8 @@ InstanceKlass* SystemDictionary::find_or_define_instance_class(Symbol* class_nam // ---------------------------------------------------------------------------- -// Update hierachy. This is done before the new klass has been added to the SystemDictionary. The Compile_lock -// is held, to ensure that the compiler is not using the class hierachy, and that deoptimization will kick in +// Update hierarchy. This is done before the new klass has been added to the SystemDictionary. The Compile_lock +// is held, to ensure that the compiler is not using the class hierarchy, and that deoptimization will kick in // before a new class is used. void SystemDictionary::add_to_hierarchy(InstanceKlass* k) { @@ -1574,7 +1574,7 @@ void SystemDictionary::add_to_hierarchy(InstanceKlass* k) { // The compiler reads the hierarchy outside of the Compile_lock. // Access ordering is used to add to hierarchy. - // Link into hierachy. + // Link into hierarchy. k->append_to_sibling_list(); // add to superklass/sibling list k->process_interfaces(); // handle all "implements" declarations @@ -1724,7 +1724,7 @@ void SystemDictionary::check_constraints(unsigned int name_hash, } } -// Update class loader data dictionary - done after check_constraint and add_to_hierachy +// Update class loader data dictionary - done after check_constraint and add_to_hierarchy // have been called. void SystemDictionary::update_dictionary(unsigned int hash, InstanceKlass* k, @@ -2014,8 +2014,9 @@ Method* SystemDictionary::find_method_handle_intrinsic(vmIntrinsicID iid, spe = NULL; // Must create lots of stuff here, but outside of the SystemDictionary lock. m = Method::make_method_handle_intrinsic(iid, signature, CHECK_NULL); - if (!Arguments::is_interpreter_only()) { + if (!Arguments::is_interpreter_only() || iid == vmIntrinsics::_linkToNative) { // Generate a compiled form of the MH intrinsic. + // linkToNative doesn't have interpreter-specific implementation, so always has to go through compiled version. AdapterHandlerLibrary::create_native_wrapper(m); // Check if have the compiled code. if (!m->has_compiled_code()) { @@ -2078,9 +2079,9 @@ static Method* unpack_method_and_appendix(Handle mname, Method* SystemDictionary::find_method_handle_invoker(Klass* klass, Symbol* name, Symbol* signature, - Klass* accessing_klass, - Handle *appendix_result, - TRAPS) { + Klass* accessing_klass, + Handle* appendix_result, + TRAPS) { assert(THREAD->can_call_java() ,""); Handle method_type = SystemDictionary::find_method_handle_type(signature, accessing_klass, CHECK_NULL); diff --git a/src/hotspot/share/classfile/systemDictionaryShared.cpp b/src/hotspot/share/classfile/systemDictionaryShared.cpp index 3e4bd3cfb34f455dd3b9b0344392045efbfcd7bd..66f9a433dfc097a23fb8909d9aa80900a6da47d2 100644 --- a/src/hotspot/share/classfile/systemDictionaryShared.cpp +++ b/src/hotspot/share/classfile/systemDictionaryShared.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -31,7 +31,7 @@ #include "cds/filemap.hpp" #include "cds/heapShared.hpp" #include "cds/cdsProtectionDomain.hpp" -#include "cds/dumpTimeClassInfo.hpp" +#include "cds/dumpTimeClassInfo.inline.hpp" #include "cds/metaspaceShared.hpp" #include "cds/runTimeClassInfo.hpp" #include "classfile/classFileStream.hpp" @@ -187,6 +187,11 @@ void SystemDictionaryShared::start_dumping() { _dump_in_progress = true; } +void SystemDictionaryShared::stop_dumping() { + assert_lock_strong(DumpTimeTable_lock); + _dump_in_progress = false; +} + DumpTimeClassInfo* SystemDictionaryShared::find_or_allocate_info_for(InstanceKlass* k) { MutexLocker ml(DumpTimeTable_lock, Mutex::_no_safepoint_check_flag); return find_or_allocate_info_for_locked(k); @@ -788,6 +793,13 @@ bool SystemDictionaryShared::add_verification_constraint(InstanceKlass* k, Symbo } } +void SystemDictionaryShared::add_enum_klass_static_field(InstanceKlass* ik, int root_index) { + assert(DumpSharedSpaces, "static dump only"); + DumpTimeClassInfo* info = SystemDictionaryShared::find_or_allocate_info_for_locked(ik); + assert(info != NULL, "must be"); + info->add_enum_klass_static_field(root_index); +} + void SystemDictionaryShared::add_to_dump_time_lambda_proxy_class_dictionary(LambdaProxyClassKey& key, InstanceKlass* proxy_klass) { assert_lock_strong(DumpTimeTable_lock); @@ -1169,7 +1181,7 @@ public: bool do_entry(InstanceKlass* k, DumpTimeClassInfo& info) { if (!info.is_excluded()) { - size_t byte_size = RunTimeClassInfo::byte_size(info._klass, info.num_verifier_constraints(), info.num_loader_constraints()); + size_t byte_size = info.runtime_info_bytesize(); _shared_class_info_size += align_up(byte_size, SharedSpaceObjectAlignment); } return true; // keep on iterating @@ -1278,7 +1290,7 @@ public: bool do_entry(InstanceKlass* k, DumpTimeClassInfo& info) { if (!info.is_excluded() && info.is_builtin() == _is_builtin) { - size_t byte_size = RunTimeClassInfo::byte_size(info._klass, info.num_verifier_constraints(), info.num_loader_constraints()); + size_t byte_size = info.runtime_info_bytesize(); RunTimeClassInfo* record; record = (RunTimeClassInfo*)ArchiveBuilder::ro_region_alloc(byte_size); record->init(info); @@ -1410,6 +1422,11 @@ InstanceKlass* SystemDictionaryShared::find_builtin_class(Symbol* name) { if (record != NULL) { assert(!record->_klass->is_hidden(), "hidden class cannot be looked up by name"); assert(check_alignment(record->_klass), "Address not aligned"); + // We did not save the classfile data of the regenerated LambdaForm invoker classes, + // so we cannot support CLFH for such classes. + if (record->_klass->is_regenerated() && JvmtiExport::should_post_class_file_load_hook()) { + return NULL; + } return record->_klass; } else { return NULL; @@ -1528,6 +1545,7 @@ void SystemDictionaryShared::print_table_statistics(outputStream* st) { } bool SystemDictionaryShared::is_dumptime_table_empty() { + assert_lock_strong(DumpTimeTable_lock); if (_dumptime_table == NULL) { return true; } diff --git a/src/hotspot/share/classfile/systemDictionaryShared.hpp b/src/hotspot/share/classfile/systemDictionaryShared.hpp index bbd76c8d7b75f429f8a72ebfe2d98e90bb71a6c2..0dbbd486dc37b92c39637f29eb360fc0c9265b7b 100644 --- a/src/hotspot/share/classfile/systemDictionaryShared.hpp +++ b/src/hotspot/share/classfile/systemDictionaryShared.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -193,6 +193,9 @@ private: public: static bool is_hidden_lambda_proxy(InstanceKlass* ik); static bool is_early_klass(InstanceKlass* k); // Was k loaded while JvmtiExport::is_early_phase()==true + static bool has_archived_enum_objs(InstanceKlass* ik); + static void set_has_archived_enum_objs(InstanceKlass* ik); + static InstanceKlass* find_builtin_class(Symbol* class_name); static const RunTimeClassInfo* find_record(RunTimeSharedDictionary* static_dict, @@ -243,6 +246,7 @@ public: bool from_is_array, bool from_is_object) NOT_CDS_RETURN_(false); static void check_verification_constraints(InstanceKlass* klass, TRAPS) NOT_CDS_RETURN; + static void add_enum_klass_static_field(InstanceKlass* ik, int root_index); static void set_class_has_failed_verification(InstanceKlass* ik) NOT_CDS_RETURN; static bool has_class_failed_verification(InstanceKlass* ik) NOT_CDS_RETURN_(false); static void add_lambda_proxy_class(InstanceKlass* caller_ik, @@ -300,6 +304,7 @@ public: static void print_table_statistics(outputStream* st) NOT_CDS_RETURN; static bool is_dumptime_table_empty() NOT_CDS_RETURN_(true); static void start_dumping() NOT_CDS_RETURN; + static void stop_dumping() NOT_CDS_RETURN; static bool is_supported_invokedynamic(BootstrapInfo* bsi) NOT_CDS_RETURN_(false); DEBUG_ONLY(static bool no_class_loading_should_happen() {return _no_class_loading_should_happen;}) diff --git a/src/hotspot/share/classfile/vmClassMacros.hpp b/src/hotspot/share/classfile/vmClassMacros.hpp index 357e5538809fb83c2333608e1596922785a5e6e6..2879076004b5ad7a2d6f20593cf86f683997f3be 100644 --- a/src/hotspot/share/classfile/vmClassMacros.hpp +++ b/src/hotspot/share/classfile/vmClassMacros.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -136,6 +136,7 @@ do_klass(ByteArrayInputStream_klass, java_io_ByteArrayInputStream ) \ do_klass(URL_klass, java_net_URL ) \ do_klass(URLClassLoader_klass, java_net_URLClassLoader ) \ + do_klass(Enum_klass, java_lang_Enum ) \ do_klass(Jar_Manifest_klass, java_util_jar_Manifest ) \ do_klass(jdk_internal_loader_BuiltinClassLoader_klass,jdk_internal_loader_BuiltinClassLoader ) \ do_klass(jdk_internal_loader_ClassLoaders_klass, jdk_internal_loader_ClassLoaders ) \ diff --git a/src/hotspot/share/classfile/vmIntrinsics.cpp b/src/hotspot/share/classfile/vmIntrinsics.cpp index cc3dc1ebdccf58fc689140cfcc02f432ec07dfef..a329669bed3d25b0a9284b4cce4482581faa9754 100644 --- a/src/hotspot/share/classfile/vmIntrinsics.cpp +++ b/src/hotspot/share/classfile/vmIntrinsics.cpp @@ -229,7 +229,7 @@ bool vmIntrinsics::disabled_by_jvm_flags(vmIntrinsics::ID id) { case vmIntrinsics::_loadFence: case vmIntrinsics::_storeFence: case vmIntrinsics::_fullFence: - case vmIntrinsics::_hasNegatives: + case vmIntrinsics::_countPositives: case vmIntrinsics::_Reference_get: break; default: diff --git a/src/hotspot/share/classfile/vmIntrinsics.hpp b/src/hotspot/share/classfile/vmIntrinsics.hpp index 08cc2bec0e697dcb5c767918dd89ce789ea36cfc..5b2c6a9ce5610124d7de545ed690eb57dc9ea087 100644 --- a/src/hotspot/share/classfile/vmIntrinsics.hpp +++ b/src/hotspot/share/classfile/vmIntrinsics.hpp @@ -354,9 +354,9 @@ class methodHandle; do_signature(Preconditions_checkLongIndex_signature, "(JJLjava/util/function/BiFunction;)J") \ \ do_class(java_lang_StringCoding, "java/lang/StringCoding") \ - do_intrinsic(_hasNegatives, java_lang_StringCoding, hasNegatives_name, hasNegatives_signature, F_S) \ - do_name( hasNegatives_name, "hasNegatives") \ - do_signature(hasNegatives_signature, "([BII)Z") \ + do_intrinsic(_countPositives, java_lang_StringCoding, countPositives_name, countPositives_signature, F_S) \ + do_name( countPositives_name, "countPositives") \ + do_signature(countPositives_signature, "([BII)I") \ \ do_class(sun_nio_cs_iso8859_1_Encoder, "sun/nio/cs/ISO_8859_1$Encoder") \ do_intrinsic(_encodeISOArray, sun_nio_cs_iso8859_1_Encoder, encodeISOArray_name, encodeISOArray_signature, F_S) \ @@ -459,9 +459,8 @@ class methodHandle; \ /* support for sun.security.provider.DigestBase */ \ do_class(sun_security_provider_digestbase, "sun/security/provider/DigestBase") \ - do_intrinsic(_digestBase_implCompressMB, sun_security_provider_digestbase, implCompressMB_name, implCompressMB_signature, F_R) \ + do_intrinsic(_digestBase_implCompressMB, sun_security_provider_digestbase, implCompressMB_name, countPositives_signature, F_R) \ do_name( implCompressMB_name, "implCompressMultiBlock0") \ - do_signature(implCompressMB_signature, "([BII)I") \ \ /* support for java.util.Base64.Encoder*/ \ do_class(java_util_Base64_Encoder, "java/util/Base64$Encoder") \ @@ -869,15 +868,16 @@ class methodHandle; "Ljdk/internal/vm/vector/VectorSupport$Vector;") \ do_name(vector_ternary_op_name, "ternaryOp") \ \ - do_intrinsic(_VectorBroadcastCoerced, jdk_internal_vm_vector_VectorSupport, vector_broadcast_coerced_name, vector_broadcast_coerced_sig, F_S)\ - do_signature(vector_broadcast_coerced_sig, "(Ljava/lang/Class;" \ + 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;" \ "I" \ "J" \ + "I" \ "Ljdk/internal/vm/vector/VectorSupport$VectorSpecies;" \ - "Ljdk/internal/vm/vector/VectorSupport$BroadcastOperation;)" \ + "Ljdk/internal/vm/vector/VectorSupport$FromBitsCoercedOperation;)" \ "Ljdk/internal/vm/vector/VectorSupport$VectorPayload;") \ - do_name(vector_broadcast_coerced_name, "broadcastCoerced") \ + do_name(vector_frombits_coerced_name, "fromBitsCoerced") \ \ do_intrinsic(_VectorShuffleIota, jdk_internal_vm_vector_VectorSupport, vector_shuffle_step_iota_name, vector_shuffle_step_iota_sig, F_S) \ do_signature(vector_shuffle_step_iota_sig, "(Ljava/lang/Class;" \ diff --git a/src/hotspot/share/classfile/vmSymbols.hpp b/src/hotspot/share/classfile/vmSymbols.hpp index 6357019adb7757d3d309559d2985bd114d2a2c18..e0402392467e2b9c9a19196798b5d755e569844e 100644 --- a/src/hotspot/share/classfile/vmSymbols.hpp +++ b/src/hotspot/share/classfile/vmSymbols.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -142,6 +142,7 @@ template(java_util_Iterator, "java/util/Iterator") \ template(java_lang_Record, "java/lang/Record") \ template(sun_instrument_InstrumentationImpl, "sun/instrument/InstrumentationImpl") \ + template(sun_invoke_util_ValueConversions, "sun/invoke/util/ValueConversions") \ \ template(jdk_internal_loader_NativeLibraries, "jdk/internal/loader/NativeLibraries") \ template(jdk_internal_loader_BuiltinClassLoader, "jdk/internal/loader/BuiltinClassLoader") \ @@ -351,7 +352,6 @@ /* Foreign API Support */ \ template(jdk_internal_invoke_NativeEntryPoint, "jdk/internal/invoke/NativeEntryPoint") \ template(jdk_internal_invoke_NativeEntryPoint_signature, "Ljdk/internal/invoke/NativeEntryPoint;") \ - template(jdk_incubator_foreign_MemoryAccess, "jdk/incubator/foreign/MemoryAccess") \ \ /* Support for JVMCI */ \ JVMCI_VM_SYMBOLS_DO(template, do_alias) \ @@ -700,6 +700,7 @@ template(dumpSharedArchive_signature, "(ZLjava/lang/String;)Ljava/lang/String;") \ template(generateLambdaFormHolderClasses, "generateLambdaFormHolderClasses") \ template(generateLambdaFormHolderClasses_signature, "([Ljava/lang/String;)[Ljava/lang/Object;") \ + template(java_lang_Enum, "java/lang/Enum") \ template(java_lang_invoke_Invokers_Holder, "java/lang/invoke/Invokers$Holder") \ template(java_lang_invoke_DirectMethodHandle_Holder, "java/lang/invoke/DirectMethodHandle$Holder") \ template(java_lang_invoke_LambdaForm_Holder, "java/lang/invoke/LambdaForm$Holder") \ diff --git a/src/hotspot/share/code/codeCache.cpp b/src/hotspot/share/code/codeCache.cpp index 2b89fa89f32b04c3ac0be4069eb60011dee80a35..0c1a579ea341c0658445dff0623f7290b6e484ec 100644 --- a/src/hotspot/share/code/codeCache.cpp +++ b/src/hotspot/share/code/codeCache.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -101,22 +101,37 @@ class CodeBlob_sizes { scopes_pcs_size = 0; } - int total() { return total_size; } - bool is_empty() { return count == 0; } + int total() const { return total_size; } + bool is_empty() const { return count == 0; } - void print(const char* title) { - tty->print_cr(" #%d %s = %dK (hdr %d%%, loc %d%%, code %d%%, stub %d%%, [oops %d%%, metadata %d%%, data %d%%, pcs %d%%])", - count, - title, - (int)(total() / K), - header_size * 100 / total_size, - relocation_size * 100 / total_size, - code_size * 100 / total_size, - stub_size * 100 / total_size, - scopes_oop_size * 100 / total_size, - scopes_metadata_size * 100 / total_size, - scopes_data_size * 100 / total_size, - scopes_pcs_size * 100 / total_size); + void print(const char* title) const { + if (is_empty()) { + tty->print_cr(" #%d %s = %dK", + count, + title, + total() / (int)K); + } else { + tty->print_cr(" #%d %s = %dK (hdr %dK %d%%, loc %dK %d%%, code %dK %d%%, stub %dK %d%%, [oops %dK %d%%, metadata %dK %d%%, data %dK %d%%, pcs %dK %d%%])", + count, + title, + total() / (int)K, + header_size / (int)K, + header_size * 100 / total_size, + relocation_size / (int)K, + relocation_size * 100 / total_size, + code_size / (int)K, + code_size * 100 / total_size, + stub_size / (int)K, + stub_size * 100 / total_size, + scopes_oop_size / (int)K, + scopes_oop_size * 100 / total_size, + scopes_metadata_size / (int)K, + scopes_metadata_size * 100 / total_size, + scopes_data_size / (int)K, + scopes_data_size * 100 / total_size, + scopes_pcs_size / (int)K, + scopes_pcs_size * 100 / total_size); + } } void add(CodeBlob* cb) { @@ -353,7 +368,7 @@ bool CodeCache::heap_available(int code_blob_type) { if (!SegmentedCodeCache) { // No segmentation: use a single code heap return (code_blob_type == CodeBlobType::All); - } else if (Arguments::is_interpreter_only()) { + } else if (CompilerConfig::is_interpreter_only()) { // Interpreter only: we don't need any method code heaps return (code_blob_type == CodeBlobType::NonNMethod); } else if (CompilerConfig::is_c1_profiling()) { @@ -487,7 +502,7 @@ CodeBlob* CodeCache::next_blob(CodeHeap* heap, CodeBlob* cb) { */ CodeBlob* CodeCache::allocate(int size, int code_blob_type, bool handle_alloc_failure, int orig_code_blob_type) { // Possibly wakes up the sweeper thread. - NMethodSweeper::report_allocation(code_blob_type); + NMethodSweeper::report_allocation(); assert_locked_or_safepoint(CodeCache_lock); assert(size > 0, "Code cache allocation request must be > 0 but is %d", size); if (size <= 0) { @@ -512,7 +527,7 @@ CodeBlob* CodeCache::allocate(int size, int code_blob_type, bool handle_alloc_fa // Fallback solution: Try to store code in another code heap. // NonNMethod -> MethodNonProfiled -> MethodProfiled (-> MethodNonProfiled) // Note that in the sweeper, we check the reverse_free_ratio of the code heap - // and force stack scanning if less than 10% of the code heap are free. + // and force stack scanning if less than 10% of the entire code cache are free. int type = code_blob_type; switch (type) { case CodeBlobType::NonNMethod: @@ -678,7 +693,7 @@ void CodeCache::nmethods_do(void f(nmethod* nm)) { void CodeCache::metadata_do(MetadataClosure* f) { assert_locked_or_safepoint(CodeCache_lock); - NMethodIterator iter(NMethodIterator::only_alive_and_not_unloading); + NMethodIterator iter(NMethodIterator::only_alive); while(iter.next()) { iter.method()->metadata_do(f); } @@ -889,20 +904,17 @@ size_t CodeCache::max_capacity() { return max_cap; } -/** - * Returns the reverse free ratio. E.g., if 25% (1/4) of the code heap - * is free, reverse_free_ratio() returns 4. - */ -double CodeCache::reverse_free_ratio(int code_blob_type) { - CodeHeap* heap = get_code_heap(code_blob_type); - if (heap == NULL) { - return 0; - } - double unallocated_capacity = MAX2((double)heap->unallocated_capacity(), 1.0); // Avoid division by 0; - double max_capacity = (double)heap->max_capacity(); - double result = max_capacity / unallocated_capacity; - assert (max_capacity >= unallocated_capacity, "Must be"); +// Returns the reverse free ratio. E.g., if 25% (1/4) of the code cache +// is free, reverse_free_ratio() returns 4. +// Since code heap for each type of code blobs falls forward to the next +// type of code heap, return the reverse free ratio for the entire +// code cache. +double CodeCache::reverse_free_ratio() { + double unallocated = MAX2((double)unallocated_capacity(), 1.0); // Avoid division by 0; + double max = (double)max_capacity(); + double result = max / unallocated; + assert (max >= unallocated, "Must be"); assert (result >= 1.0, "reverse_free_ratio must be at least 1. It is %f", result); return result; } @@ -1032,7 +1044,7 @@ CompiledMethod* CodeCache::find_compiled(void* start) { } #if INCLUDE_JVMTI -// RedefineClasses support for unloading nmethods that are dependent on "old" methods. +// RedefineClasses support for saving nmethods that are dependent on "old" methods. // We don't really expect this table to grow very large. If it does, it can become a hashtable. static GrowableArray* old_compiled_method_table = NULL; @@ -1085,7 +1097,7 @@ int CodeCache::mark_dependents_for_evol_deoptimization() { reset_old_method_table(); int number_of_marked_CodeBlobs = 0; - CompiledMethodIterator iter(CompiledMethodIterator::only_alive_and_not_unloading); + CompiledMethodIterator iter(CompiledMethodIterator::only_alive); while(iter.next()) { CompiledMethod* nm = iter.method(); // Walk all alive nmethods to check for old Methods. @@ -1105,7 +1117,7 @@ int CodeCache::mark_dependents_for_evol_deoptimization() { void CodeCache::mark_all_nmethods_for_evol_deoptimization() { assert(SafepointSynchronize::is_at_safepoint(), "Can only do this at a safepoint!"); - CompiledMethodIterator iter(CompiledMethodIterator::only_alive_and_not_unloading); + CompiledMethodIterator iter(CompiledMethodIterator::only_alive); while(iter.next()) { CompiledMethod* nm = iter.method(); if (!nm->method()->is_method_handle_intrinsic()) { @@ -1226,9 +1238,9 @@ void CodeCache::report_codemem_full(int code_blob_type, bool print) { CodeHeap* heap = get_code_heap(code_blob_type); assert(heap != NULL, "heap is null"); - heap->report_full(); + int full_count = heap->report_full(); - if ((heap->full_count() == 1) || print) { + if ((full_count == 1) || print) { // Not yet reported for this heap, report if (SegmentedCodeCache) { ResourceMark rm; @@ -1265,7 +1277,7 @@ void CodeCache::report_codemem_full(int code_blob_type, bool print) { tty->print("%s", s.as_string()); } - if (heap->full_count() == 1) { + if (full_count == 1) { if (PrintCodeHeapAnalytics) { CompileBroker::print_heapinfo(tty, "all", 4096); // details, may be a lot! } @@ -1430,27 +1442,73 @@ void CodeCache::print() { #ifndef PRODUCT if (!Verbose) return; - CodeBlob_sizes live; - CodeBlob_sizes dead; + CodeBlob_sizes live[CompLevel_full_optimization + 1]; + CodeBlob_sizes dead[CompLevel_full_optimization + 1]; + CodeBlob_sizes runtimeStub; + CodeBlob_sizes uncommonTrapStub; + CodeBlob_sizes deoptimizationStub; + CodeBlob_sizes adapter; + CodeBlob_sizes bufferBlob; + CodeBlob_sizes other; FOR_ALL_ALLOCABLE_HEAPS(heap) { FOR_ALL_BLOBS(cb, *heap) { - if (!cb->is_alive()) { - dead.add(cb); + if (cb->is_nmethod()) { + const int level = cb->as_nmethod()->comp_level(); + assert(0 <= level && level <= CompLevel_full_optimization, "Invalid compilation level"); + if (!cb->is_alive()) { + dead[level].add(cb); + } else { + live[level].add(cb); + } + } else if (cb->is_runtime_stub()) { + runtimeStub.add(cb); + } else if (cb->is_deoptimization_stub()) { + deoptimizationStub.add(cb); + } else if (cb->is_uncommon_trap_stub()) { + uncommonTrapStub.add(cb); + } else if (cb->is_adapter_blob()) { + adapter.add(cb); + } else if (cb->is_buffer_blob()) { + bufferBlob.add(cb); } else { - live.add(cb); + other.add(cb); } } } - tty->print_cr("CodeCache:"); tty->print_cr("nmethod dependency checking time %fs", dependentCheckTime.seconds()); - if (!live.is_empty()) { - live.print("live"); - } - if (!dead.is_empty()) { - dead.print("dead"); + tty->print_cr("nmethod blobs per compilation level:"); + for (int i = 0; i <= CompLevel_full_optimization; i++) { + const char *level_name; + switch (i) { + case CompLevel_none: level_name = "none"; break; + case CompLevel_simple: level_name = "simple"; break; + case CompLevel_limited_profile: level_name = "limited profile"; break; + case CompLevel_full_profile: level_name = "full profile"; break; + case CompLevel_full_optimization: level_name = "full optimization"; break; + default: assert(false, "invalid compilation level"); + } + tty->print_cr("%s:", level_name); + live[i].print("live"); + dead[i].print("dead"); + } + + struct { + const char* name; + const CodeBlob_sizes* sizes; + } non_nmethod_blobs[] = { + { "runtime", &runtimeStub }, + { "uncommon trap", &uncommonTrapStub }, + { "deoptimization", &deoptimizationStub }, + { "adapter", &adapter }, + { "buffer blob", &bufferBlob }, + { "other", &other }, + }; + tty->print_cr("Non-nmethod blobs:"); + for (auto& blob: non_nmethod_blobs) { + blob.sizes->print(blob.name); } if (WizardMode) { diff --git a/src/hotspot/share/code/codeCache.hpp b/src/hotspot/share/code/codeCache.hpp index 53705aadcbe3639aca98e21beeacb1cd9d2d5e8c..0a0bd9c770402e450dc51330033a0f7dbb840b44 100644 --- a/src/hotspot/share/code/codeCache.hpp +++ b/src/hotspot/share/code/codeCache.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -211,7 +211,7 @@ class CodeCache : AllStatic { static size_t unallocated_capacity(); static size_t max_capacity(); - static double reverse_free_ratio(int code_blob_type); + static double reverse_free_ratio(); static void clear_inline_caches(); // clear all inline caches static void cleanup_inline_caches(); // clean unloaded/zombie nmethods from inline caches diff --git a/src/hotspot/share/code/compiledMethod.cpp b/src/hotspot/share/code/compiledMethod.cpp index 3cc2e1c4ffbdc460906e77b9fc092448f75b2e26..4e42b555d966e34cf65a3e44fe958cf392c39743 100644 --- a/src/hotspot/share/code/compiledMethod.cpp +++ b/src/hotspot/share/code/compiledMethod.cpp @@ -478,6 +478,10 @@ bool CompiledMethod::clean_ic_if_metadata_is_dead(CompiledIC *ic) { } else { ShouldNotReachHere(); } + } else { + // This inline cache is a megamorphic vtable call. Those ICs never hold + // any Metadata and should therefore never be cleaned by this function. + return true; } } diff --git a/src/hotspot/share/code/dependencies.cpp b/src/hotspot/share/code/dependencies.cpp index 8ca9c59fc8270105691f7772366c612adabf57a5..e150b300b7b6519db253c43994ace80ae8d8d90a 100644 --- a/src/hotspot/share/code/dependencies.cpp +++ b/src/hotspot/share/code/dependencies.cpp @@ -116,6 +116,12 @@ void Dependencies::assert_unique_concrete_method(ciKlass* ctxk, ciMethod* uniqm, } } +void Dependencies::assert_unique_implementor(ciInstanceKlass* ctxk, ciInstanceKlass* uniqk) { + check_ctxk(ctxk); + check_unique_implementor(ctxk, uniqk); + assert_common_2(unique_implementor, ctxk, uniqk); +} + void Dependencies::assert_has_no_finalizable_subclasses(ciKlass* ctxk) { check_ctxk(ctxk); assert_common_1(no_finalizable_subclasses, ctxk); @@ -173,6 +179,13 @@ void Dependencies::assert_abstract_with_unique_concrete_subtype(Klass* ctxk, Kla assert_common_2(abstract_with_unique_concrete_subtype, ctxk_dv, conck_dv); } +void Dependencies::assert_unique_implementor(InstanceKlass* ctxk, InstanceKlass* uniqk) { + check_ctxk(ctxk); + assert(ctxk->is_interface(), "not an interface"); + assert(ctxk->implementor() == uniqk, "not a unique implementor"); + assert_common_2(unique_implementor, DepValue(_oop_recorder, ctxk), DepValue(_oop_recorder, uniqk)); +} + void Dependencies::assert_unique_concrete_method(Klass* ctxk, Method* uniqm) { check_ctxk(ctxk); check_unique_method(ctxk, uniqm); @@ -580,6 +593,7 @@ const char* Dependencies::_dep_name[TYPE_LIMIT] = { "abstract_with_unique_concrete_subtype", "unique_concrete_method_2", "unique_concrete_method_4", + "unique_implementor", "no_finalizable_subclasses", "call_site_target_value" }; @@ -591,6 +605,7 @@ int Dependencies::_dep_args[TYPE_LIMIT] = { 2, // abstract_with_unique_concrete_subtype ctxk, k 2, // unique_concrete_method_2 ctxk, m 4, // unique_concrete_method_4 ctxk, m, resolved_klass, resolved_method + 2, // unique_implementor ctxk, implementor 1, // no_finalizable_subclasses ctxk 2 // call_site_target_value call_site, method_handle }; @@ -1813,6 +1828,16 @@ Klass* Dependencies::check_unique_concrete_method(InstanceKlass* ctxk, return NULL; } +Klass* Dependencies::check_unique_implementor(InstanceKlass* ctxk, Klass* uniqk, NewKlassDepChange* changes) { + assert(ctxk->is_interface(), "sanity"); + assert(ctxk->nof_implementors() > 0, "no implementors"); + if (ctxk->nof_implementors() == 1) { + assert(ctxk->implementor() == uniqk, "sanity"); + return NULL; + } + return ctxk; // no unique implementor +} + // Search for AME. // There are two version of checks. // 1) Spot checking version(Classload time). Newly added class is checked for AME. @@ -2062,6 +2087,9 @@ Klass* Dependencies::DepStream::check_new_klass_dependency(NewKlassDepChange* ch case unique_concrete_method_4: witness = check_unique_concrete_method(context_type(), method_argument(1), type_argument(2), method_argument(3), changes); break; + case unique_implementor: + witness = check_unique_implementor(context_type(), type_argument(1), changes); + break; case no_finalizable_subclasses: witness = check_has_no_finalizable_subclasses(context_type(), changes); break; diff --git a/src/hotspot/share/code/dependencies.hpp b/src/hotspot/share/code/dependencies.hpp index 104fc9ee6496bb290485ce6b3c633fdf8f8d2fa5..0d8fa9fa48c71a5743e6543b295836df1305a76d 100644 --- a/src/hotspot/share/code/dependencies.hpp +++ b/src/hotspot/share/code/dependencies.hpp @@ -143,6 +143,9 @@ class Dependencies: public ResourceObj { // of the analysis. unique_concrete_method_4, // one unique concrete method under CX + // This dependency asserts that interface CX has a unique implementor class. + unique_implementor, // one unique implementor under CX + // This dependency asserts that no instances of class or it's // subclasses require finalization registration. no_finalizable_subclasses, @@ -329,7 +332,10 @@ class Dependencies: public ResourceObj { assert(!is_concrete_klass(ctxk->as_instance_klass()), "must be abstract"); } static void check_unique_method(ciKlass* ctxk, ciMethod* m) { - assert(!m->can_be_statically_bound(ctxk->as_instance_klass()), "redundant"); + assert(!m->can_be_statically_bound(ctxk->as_instance_klass()) || ctxk->is_interface(), "redundant"); + } + static void check_unique_implementor(ciInstanceKlass* ctxk, ciInstanceKlass* uniqk) { + assert(ctxk->implementor() == uniqk, "not a unique implementor"); } void assert_common_1(DepType dept, ciBaseObject* x); @@ -343,9 +349,9 @@ class Dependencies: public ResourceObj { void assert_abstract_with_unique_concrete_subtype(ciKlass* ctxk, ciKlass* conck); void assert_unique_concrete_method(ciKlass* ctxk, ciMethod* uniqm); void assert_unique_concrete_method(ciKlass* ctxk, ciMethod* uniqm, ciKlass* resolved_klass, ciMethod* resolved_method); + void assert_unique_implementor(ciInstanceKlass* ctxk, ciInstanceKlass* uniqk); void assert_has_no_finalizable_subclasses(ciKlass* ctxk); void assert_call_site_target_value(ciCallSite* call_site, ciMethodHandle* method_handle); - #if INCLUDE_JVMCI private: static void check_ctxk(Klass* ctxk) { @@ -366,6 +372,7 @@ class Dependencies: public ResourceObj { void assert_evol_method(Method* m); void assert_has_no_finalizable_subclasses(Klass* ctxk); void assert_leaf_type(Klass* ctxk); + void assert_unique_implementor(InstanceKlass* ctxk, InstanceKlass* uniqk); void assert_unique_concrete_method(Klass* ctxk, Method* uniqm); void assert_abstract_with_unique_concrete_subtype(Klass* ctxk, Klass* conck); void assert_call_site_target_value(oop callSite, oop methodHandle); @@ -413,6 +420,7 @@ class Dependencies: public ResourceObj { static Klass* check_evol_method(Method* m); static Klass* check_leaf_type(InstanceKlass* ctxk); static Klass* check_abstract_with_unique_concrete_subtype(InstanceKlass* ctxk, Klass* conck, NewKlassDepChange* changes = NULL); + static Klass* check_unique_implementor(InstanceKlass* ctxk, Klass* uniqk, NewKlassDepChange* changes = NULL); static Klass* check_unique_concrete_method(InstanceKlass* ctxk, Method* uniqm, NewKlassDepChange* changes = NULL); static Klass* check_unique_concrete_method(InstanceKlass* ctxk, Method* uniqm, Klass* resolved_klass, Method* resolved_method, KlassDepChange* changes = NULL); static Klass* check_has_no_finalizable_subclasses(InstanceKlass* ctxk, NewKlassDepChange* changes = NULL); diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index f695f242231209c1c07af21130863cad5ad8a591..543892bc434aa2d2072073579486ea7550e0dbc9 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -924,7 +924,7 @@ void nmethod::print_on(outputStream* st, const char* msg) const { CompileTask::print(st, this, msg, /*short_form:*/ true); st->print_cr(" (" INTPTR_FORMAT ")", p2i(this)); } else { - CompileTask::print(st, this, msg, /*short_form:*/ false, /* cr */ true, /* timestamp */ false); + CompileTask::print(st, this, msg, /*short_form:*/ false); } } } diff --git a/src/hotspot/share/code/nmethod.hpp b/src/hotspot/share/code/nmethod.hpp index d0154bc85a37ad1e0f3221df79147238681d22d1..d31e62f404a63e5f795972fed6fb747448f7c0ab 100644 --- a/src/hotspot/share/code/nmethod.hpp +++ b/src/hotspot/share/code/nmethod.hpp @@ -256,7 +256,7 @@ class nmethod : public CompiledMethod { // stack. An not_entrant method can be removed when there are no // more activations, i.e., when the _stack_traversal_mark is less than // current sweep traversal index. - volatile long _stack_traversal_mark; + volatile int64_t _stack_traversal_mark; // The _hotness_counter indicates the hotness of a method. The higher // the value the hotter the method. The hotness counter of a nmethod is @@ -538,8 +538,8 @@ public: void fix_oop_relocations() { fix_oop_relocations(NULL, NULL, false); } // Sweeper support - long stack_traversal_mark() { return _stack_traversal_mark; } - void set_stack_traversal_mark(long l) { _stack_traversal_mark = l; } + int64_t stack_traversal_mark() { return _stack_traversal_mark; } + void set_stack_traversal_mark(int64_t l) { _stack_traversal_mark = l; } // On-stack replacement support int osr_entry_bci() const { assert(is_osr_method(), "wrong kind of nmethod"); return _entry_bci; } diff --git a/src/hotspot/share/code/vtableStubs.hpp b/src/hotspot/share/code/vtableStubs.hpp index 8fc2bdae94c2042149299637581baaaceaa29d6d..9498ad7d329e6ec3442a6eb9db42f38d373d232a 100644 --- a/src/hotspot/share/code/vtableStubs.hpp +++ b/src/hotspot/share/code/vtableStubs.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -27,7 +27,7 @@ #include "asm/macroAssembler.hpp" #include "code/vmreg.hpp" -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" // A VtableStub holds an individual code stub for a pair (vtable index, #args) for either itables or vtables // There's a one-to-one relationship between a VtableStub and such a pair. diff --git a/src/hotspot/share/compiler/compilationPolicy.cpp b/src/hotspot/share/compiler/compilationPolicy.cpp index 592cb5d65f2f400feb94fd75bced2012a7da7ffd..027b513af695544695ff82d4458bf469abe45ae2 100644 --- a/src/hotspot/share/compiler/compilationPolicy.cpp +++ b/src/hotspot/share/compiler/compilationPolicy.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 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 @@ -315,7 +315,7 @@ double CompilationPolicy::threshold_scale(CompLevel level, int feedback_k) { // The main intention is to keep enough free space for C2 compiled code // to achieve peak performance if the code cache is under stress. if (CompilerConfig::is_tiered() && !CompilationModeFlag::disable_intermediate() && is_c1_compile(level)) { - double current_reverse_free_ratio = CodeCache::reverse_free_ratio(CodeCache::get_code_blob_type(level)); + double current_reverse_free_ratio = CodeCache::reverse_free_ratio(); if (current_reverse_free_ratio > _increase_threshold_at_ratio) { k *= exp(current_reverse_free_ratio - _increase_threshold_at_ratio); } diff --git a/src/hotspot/share/compiler/compileBroker.cpp b/src/hotspot/share/compiler/compileBroker.cpp index fbb295b4c4d9e423c8f4c34f6644a6e0e6615708..6422b719f68de41530e3139ea55b113f510414e8 100644 --- a/src/hotspot/share/compiler/compileBroker.cpp +++ b/src/hotspot/share/compiler/compileBroker.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -186,7 +186,7 @@ int CompileBroker::_sum_standard_bytes_compiled = 0; int CompileBroker::_sum_nmethod_size = 0; int CompileBroker::_sum_nmethod_code_size = 0; -long CompileBroker::_peak_compilation_time = 0; +jlong CompileBroker::_peak_compilation_time = 0; CompilerStatistics CompileBroker::_stats_per_level[CompLevel_full_optimization]; @@ -225,11 +225,13 @@ class CompilationLog : public StringEventLog { } void log_metaspace_failure(const char* reason) { + // Note: This method can be called from non-Java/compiler threads to + // log the global metaspace failure that might affect profiling. ResourceMark rm; StringLogMessage lm; lm.print("%4d COMPILE PROFILING SKIPPED: %s", -1, reason); lm.print("\n"); - log(JavaThread::current(), "%s", (const char*)lm); + log(Thread::current(), "%s", (const char*)lm); } }; @@ -411,6 +413,7 @@ void CompileQueue::free_all() { CompileTask::free(current); } _first = NULL; + _last = NULL; // Wake up all threads that block on the queue. MethodCompileQueue_lock->notify_all(); @@ -613,9 +616,8 @@ void register_jfr_phasetype_serializer(CompilerType compiler_type) { #ifdef COMPILER2 } else if (compiler_type == compiler_c2) { assert(first_registration, "invariant"); // c2 must be registered first. - GrowableArray* c2_phase_names = new GrowableArray(PHASE_NUM_TYPES); for (int i = 0; i < PHASE_NUM_TYPES; i++) { - const char* phase_name = CompilerPhaseTypeHelper::to_string((CompilerPhaseType) i); + const char* phase_name = CompilerPhaseTypeHelper::to_description((CompilerPhaseType) i); CompilerEvent::PhaseEvent::get_phase_id(phase_name, false, false, false); } first_registration = false; @@ -1969,6 +1971,8 @@ void CompileBroker::compiler_thread_loop() { method->clear_queued_for_compilation(); task->set_failure_reason("compilation is disabled"); } + } else { + task->set_failure_reason("breakpoints are present"); } if (UseDynamicNumberOfCompilerThreads) { @@ -2002,7 +2006,7 @@ void CompileBroker::init_compiler_thread_log() { os::file_separator(), thread_id, os::current_process_id()); } - fp = fopen(file_name, "wt"); + fp = os::fopen(file_name, "wt"); if (fp != NULL) { if (LogCompilation && Verbose) { tty->print_cr("Opening compilation log %s", file_name); diff --git a/src/hotspot/share/compiler/compileBroker.hpp b/src/hotspot/share/compiler/compileBroker.hpp index 33fde0dace6cdd7480dd9f5143ebbeb3f13fac4c..be770aac9c242afafccc65afa6c6d12bf9104dad 100644 --- a/src/hotspot/share/compiler/compileBroker.hpp +++ b/src/hotspot/share/compiler/compileBroker.hpp @@ -222,7 +222,7 @@ class CompileBroker: AllStatic { static int _sum_standard_bytes_compiled; static int _sum_nmethod_size; static int _sum_nmethod_code_size; - static long _peak_compilation_time; + static jlong _peak_compilation_time; static CompilerStatistics _stats_per_level[]; @@ -411,8 +411,8 @@ public: static int get_sum_standard_bytes_compiled() { return _sum_standard_bytes_compiled; } static int get_sum_nmethod_size() { return _sum_nmethod_size;} static int get_sum_nmethod_code_size() { return _sum_nmethod_code_size; } - static long get_peak_compilation_time() { return _peak_compilation_time; } - static long get_total_compilation_time() { return _t_total_compilation.milliseconds(); } + static jlong get_peak_compilation_time() { return _peak_compilation_time; } + static jlong get_total_compilation_time() { return _t_total_compilation.milliseconds(); } // Log that compilation profiling is skipped because metaspace is full. static void log_metaspace_failure(); diff --git a/src/hotspot/share/compiler/compileLog.cpp b/src/hotspot/share/compiler/compileLog.cpp index eb52c5f5fb1acd1decd55f1c27768575e4c06295..3dbc71f6075d6ac29a6d8495d050311efef554b0 100644 --- a/src/hotspot/share/compiler/compileLog.cpp +++ b/src/hotspot/share/compiler/compileLog.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 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 @@ -225,7 +225,7 @@ void CompileLog::finish_log_on_error(outputStream* file, char* buf, int buflen) if (to_read < (julong)buflen) nr = (size_t)to_read; else nr = buflen; - bytes_read = read(partial_fd, buf, (int)nr); + bytes_read = ::read(partial_fd, buf, (int)nr); if (bytes_read <= 0) break; nr = bytes_read; to_read -= (julong)nr; @@ -235,7 +235,7 @@ void CompileLog::finish_log_on_error(outputStream* file, char* buf, int buflen) // Copy any remaining data inside a quote: bool saw_slop = false; int end_cdata = 0; // state machine [0..2] watching for too many "]]" - while ((bytes_read = read(partial_fd, buf, buflen-1)) > 0) { + while ((bytes_read = ::read(partial_fd, buf, buflen-1)) > 0) { nr = bytes_read; buf[buflen-1] = '\0'; if (!saw_slop) { @@ -285,7 +285,7 @@ void CompileLog::finish_log_on_error(outputStream* file, char* buf, int buflen) file->print_raw_cr(""); } file->print_raw_cr(""); - close(partial_fd); + ::close(partial_fd); } CompileLog* next_log = log->_next; delete log; // Removes partial file diff --git a/src/hotspot/share/compiler/compileTask.cpp b/src/hotspot/share/compiler/compileTask.cpp index b78806346c5db44ff38163c72172ef9efd23add8..d610d8bdcf814730579233cf65bd9649566b2d25 100644 --- a/src/hotspot/share/compiler/compileTask.cpp +++ b/src/hotspot/share/compiler/compileTask.cpp @@ -236,13 +236,11 @@ void CompileTask::print_tty() { // CompileTask::print_impl void CompileTask::print_impl(outputStream* st, Method* method, int compile_id, int comp_level, bool is_osr_method, int osr_bci, bool is_blocking, - const char* msg, bool short_form, bool cr, bool timestamp, + const char* msg, bool short_form, bool cr, jlong time_queued, jlong time_started) { if (!short_form) { - if (timestamp) { - // Print current time - st->print("%7d ", (int)tty->time_stamp().milliseconds()); - } + // Print current time + st->print("%7d ", (int)tty->time_stamp().milliseconds()); if (Verbose && time_queued != 0) { // Print time in queue and time being processed by compiler thread jlong now = os::elapsed_counter(); diff --git a/src/hotspot/share/compiler/compileTask.hpp b/src/hotspot/share/compiler/compileTask.hpp index a900bfd4f44b29812186dd5e3584817dce2e06b1..23facc90cc5d81d2c8d954ebc7acaea0b65b95af 100644 --- a/src/hotspot/share/compiler/compileTask.hpp +++ b/src/hotspot/share/compiler/compileTask.hpp @@ -104,7 +104,8 @@ class CompileTask : public CHeapObj { public: CompileTask() : _failure_reason(NULL), _failure_reason_on_C_heap(false) { - _lock = new Monitor(Mutex::safepoint, "CompileTask_lock"); + // May hold MethodCompileQueue_lock + _lock = new Monitor(Mutex::safepoint-1, "CompileTask_lock"); } void initialize(int compile_id, const methodHandle& method, int osr_bci, int comp_level, @@ -187,16 +188,16 @@ class CompileTask : public CHeapObj { private: static void print_impl(outputStream* st, Method* method, int compile_id, int comp_level, bool is_osr_method = false, int osr_bci = -1, bool is_blocking = false, - const char* msg = NULL, bool short_form = false, bool cr = true, bool timestamp = true, + const char* msg = NULL, bool short_form = false, bool cr = true, jlong time_queued = 0, jlong time_started = 0); public: void print(outputStream* st = tty, const char* msg = NULL, bool short_form = false, bool cr = true); void print_ul(const char* msg = NULL); - static void print(outputStream* st, const nmethod* nm, const char* msg = NULL, bool short_form = false, bool cr = true, bool timestamp = true) { + static void print(outputStream* st, const nmethod* nm, const char* msg = NULL, bool short_form = false, bool cr = true) { print_impl(st, nm->method(), nm->compile_id(), nm->comp_level(), nm->is_osr_method(), nm->is_osr_method() ? nm->osr_entry_bci() : -1, /*is_blocking*/ false, - msg, short_form, cr, timestamp); + msg, short_form, cr); } static void print_ul(const nmethod* nm, const char* msg = NULL); diff --git a/src/hotspot/share/compiler/compilerDefinitions.cpp b/src/hotspot/share/compiler/compilerDefinitions.cpp index a6445c161b2f3593ae2203f4b62bde89c14d4428..aa8dd0a1be8638c9bc4519177af24624da36744c 100644 --- a/src/hotspot/share/compiler/compilerDefinitions.cpp +++ b/src/hotspot/share/compiler/compilerDefinitions.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -310,7 +310,6 @@ void CompilerConfig::set_compilation_policy_flags() { } } - if (CompileThresholdScaling < 0) { vm_exit_during_initialization("Negative value specified for CompileThresholdScaling", NULL); } @@ -509,6 +508,10 @@ bool CompilerConfig::check_args_consistency(bool status) { } FLAG_SET_CMDLINE(TieredCompilation, false); } + if (SegmentedCodeCache) { + warning("SegmentedCodeCache has no meaningful effect with -Xint"); + FLAG_SET_DEFAULT(SegmentedCodeCache, false); + } #if INCLUDE_JVMCI if (EnableJVMCI) { if (!FLAG_IS_DEFAULT(EnableJVMCI) || !FLAG_IS_DEFAULT(UseJVMCICompiler)) { diff --git a/src/hotspot/share/compiler/compilerDefinitions.hpp b/src/hotspot/share/compiler/compilerDefinitions.hpp index 1c8096918a6a49a9233c55f62800583f56231d91..153dfaad3645cdeea4b5674312f20fb6b8d55dfa 100644 --- a/src/hotspot/share/compiler/compilerDefinitions.hpp +++ b/src/hotspot/share/compiler/compilerDefinitions.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -27,7 +27,7 @@ #include "compiler/compiler_globals.hpp" #include "jvmci/jvmci_globals.hpp" -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" #include "runtime/globals.hpp" // The (closed set) of concrete compiler classes. diff --git a/src/hotspot/share/compiler/compilerDirectives.cpp b/src/hotspot/share/compiler/compilerDirectives.cpp index 0e38b067246aef7641fb59e14a8e078d21ba63a6..5fe8482719525f64905f23d41bfcffbb9137826d 100644 --- a/src/hotspot/share/compiler/compilerDirectives.cpp +++ b/src/hotspot/share/compiler/compilerDirectives.cpp @@ -30,6 +30,7 @@ #include "compiler/compilerOracle.hpp" #include "memory/allocation.inline.hpp" #include "memory/resourceArea.hpp" +#include "opto/phasetype.hpp" #include "runtime/globals_extension.hpp" CompilerDirectives::CompilerDirectives() : _next(NULL), _match(NULL), _ref_count(0) { @@ -262,6 +263,7 @@ void DirectiveSet::init_control_intrinsic() { DirectiveSet::DirectiveSet(CompilerDirectives* d) :_inlinematchers(NULL), _directive(d) { #define init_defaults_definition(name, type, dvalue, compiler) this->name##Option = dvalue; + _ideal_phase_name_mask = 0; compilerdirectives_common_flags(init_defaults_definition) compilerdirectives_c2_flags(init_defaults_definition) compilerdirectives_c1_flags(init_defaults_definition) @@ -334,9 +336,21 @@ DirectiveSet* DirectiveSet::compilecommand_compatibility_init(const methodHandle if (!CompilerDirectivesIgnoreCompileCommandsOption && CompilerOracle::has_any_command_set()) { DirectiveSetPtr set(this); +#ifdef COMPILER1 + if (C1Breakpoint) { + // If the directives didn't have 'BreakAtExecute', + // the command 'C1Breakpoint' would become effective. + if (!_modified[BreakAtExecuteIndex]) { + set.cloned()->BreakAtExecuteOption = true; + } + } +#endif + // All CompileCommands are not equal so this gets a bit verbose // When CompileCommands have been refactored less clutter will remain. if (CompilerOracle::should_break_at(method)) { + // If the directives didn't have 'BreakAtCompile' or 'BreakAtExecute', + // the sub-command 'Break' of the 'CompileCommand' would become effective. if (!_modified[BreakAtCompileIndex]) { set.cloned()->BreakAtCompileOption = true; } @@ -369,6 +383,24 @@ DirectiveSet* DirectiveSet::compilecommand_compatibility_init(const methodHandle compilerdirectives_c2_flags(init_default_cc) compilerdirectives_c1_flags(init_default_cc) + // Parse PrintIdealPhaseName and create an efficient lookup mask +#ifndef PRODUCT +#ifdef COMPILER2 + if (!_modified[PrintIdealPhaseIndex]) { + // Parse ccstr and create mask + ccstrlist option; + if (CompilerOracle::has_option_value(method, CompileCommand::PrintIdealPhase, option)) { + uint64_t mask = 0; + PhaseNameValidator validator(option, mask); + if (validator.is_valid()) { + assert(mask != 0, "Must be set"); + set.cloned()->_ideal_phase_name_mask = mask; + } + } + } +#endif +#endif + // Canonicalize DisableIntrinsic to contain only ',' as a separator. ccstrlist option_value; bool need_reset = true; // if Control/DisableIntrinsic redefined, only need to reset control_words once diff --git a/src/hotspot/share/compiler/compilerDirectives.hpp b/src/hotspot/share/compiler/compilerDirectives.hpp index d51aa28e28cc6026578aada9d7ec23b3b44f6fb8..bab28e2458ae0c5bd4bd120cf006fd617dc856ca 100644 --- a/src/hotspot/share/compiler/compilerDirectives.hpp +++ b/src/hotspot/share/compiler/compilerDirectives.hpp @@ -66,7 +66,9 @@ cflags(PrintIntrinsics, bool, PrintIntrinsics, PrintIntrinsics) \ NOT_PRODUCT(cflags(TraceOptoPipelining, bool, TraceOptoPipelining, TraceOptoPipelining)) \ NOT_PRODUCT(cflags(TraceOptoOutput, bool, TraceOptoOutput, TraceOptoOutput)) \ +NOT_PRODUCT(cflags(TraceEscapeAnalysis, bool, false, TraceEscapeAnalysis)) \ NOT_PRODUCT(cflags(PrintIdeal, bool, PrintIdeal, PrintIdeal)) \ +NOT_PRODUCT(cflags(PrintIdealPhase, ccstrlist, "", PrintIdealPhase)) \ cflags(TraceSpilling, bool, TraceSpilling, TraceSpilling) \ cflags(Vectorize, bool, false, Vectorize) \ cflags(CloneMapDebug, bool, false, CloneMapDebug) \ @@ -107,6 +109,7 @@ private: InlineMatcher* _inlinematchers; CompilerDirectives* _directive; TriBoolArray<(size_t)vmIntrinsics::number_of_intrinsics(), int> _intrinsic_control_words; + uint64_t _ideal_phase_name_mask; public: DirectiveSet(CompilerDirectives* directive); @@ -136,7 +139,6 @@ public: private: bool _modified[number_of_flags]; // Records what options where set by a directive - public: #define flag_store_definition(name, type, dvalue, cc_flag) type name##Option; compilerdirectives_common_flags(flag_store_definition) @@ -149,6 +151,9 @@ public: compilerdirectives_c2_flags(set_function_definition) compilerdirectives_c1_flags(set_function_definition) + void set_ideal_phase_mask(uint64_t mask) { _ideal_phase_name_mask = mask; }; + uint64_t ideal_phase_mask() { return _ideal_phase_name_mask; }; + void print_intx(outputStream* st, ccstr n, intx v, bool mod) { if (mod) { st->print("%s:" INTX_FORMAT " ", n, v); } } void print_uintx(outputStream* st, ccstr n, intx v, bool mod) { if (mod) { st->print("%s:" UINTX_FORMAT " ", n, v); } } void print_bool(outputStream* st, ccstr n, bool v, bool mod) { if (mod) { st->print("%s:%s ", n, v ? "true" : "false"); } } diff --git a/src/hotspot/share/compiler/compilerEvent.hpp b/src/hotspot/share/compiler/compilerEvent.hpp index 65fc296b66b3dab9e5f1dacfa1aed1c8ff2f54de..cf04ce9a4364b8f3fb2904ffe0a867f024197644 100644 --- a/src/hotspot/share/compiler/compilerEvent.hpp +++ b/src/hotspot/share/compiler/compilerEvent.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -26,7 +26,7 @@ #include "jni.h" #include "compiler/compilerDefinitions.hpp" -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" #include "utilities/macros.hpp" #include "utilities/ticks.hpp" diff --git a/src/hotspot/share/compiler/compilerOracle.cpp b/src/hotspot/share/compiler/compilerOracle.cpp index 8464d22ef42d11a111d136941bc01e5492434334..7d8b7179d0c7c5a17cabe2ee00d4e8ef62611f73 100644 --- a/src/hotspot/share/compiler/compilerOracle.cpp +++ b/src/hotspot/share/compiler/compilerOracle.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -34,6 +34,7 @@ #include "oops/klass.hpp" #include "oops/method.inline.hpp" #include "oops/symbol.hpp" +#include "opto/phasetype.hpp" #include "runtime/globals_extension.hpp" #include "runtime/handles.inline.hpp" #include "runtime/jniHandles.hpp" @@ -683,6 +684,21 @@ static void scan_value(enum OptionType type, char* line, int& total_bytes_read, jio_snprintf(errorbuf, buf_size, "Unrecognized intrinsic detected in %s: %s", option2name(option), validator.what()); } } +#ifndef PRODUCT + else if (option == CompileCommand::PrintIdealPhase) { + uint64_t mask = 0; + PhaseNameValidator validator(value, mask); + + if (!validator.is_valid()) { + jio_snprintf(errorbuf, buf_size, "Unrecognized phase name in %s: %s", option2name(option), validator.what()); + } + } else if (option == CompileCommand::TestOptionList) { + // all values are ok + } +#endif + else { + assert(false, "Ccstrlist type option missing validator"); + } register_command(matcher, option, (ccstr) value); return; @@ -932,7 +948,7 @@ bool CompilerOracle::_quiet = false; void CompilerOracle::parse_from_file() { assert(has_command_file(), "command file must be specified"); - FILE* stream = fopen(cc_file(), "rt"); + FILE* stream = os::fopen(cc_file(), "rt"); if (stream == NULL) return; char token[1024]; diff --git a/src/hotspot/share/compiler/compilerOracle.hpp b/src/hotspot/share/compiler/compilerOracle.hpp index 858e5c794060ffbe96c84bc02339ee757881f491..303c52683f543e435b3eab1fbdd03d3d2d05b7a3 100644 --- a/src/hotspot/share/compiler/compilerOracle.hpp +++ b/src/hotspot/share/compiler/compilerOracle.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -25,7 +25,7 @@ #ifndef SHARE_COMPILER_COMPILERORACLE_HPP #define SHARE_COMPILER_COMPILERORACLE_HPP -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" #include "oops/oopsHierarchy.hpp" class methodHandle; @@ -79,8 +79,10 @@ class methodHandle; option(TraceOptoPipelining, "TraceOptoPipelining", Bool) \ option(TraceOptoOutput, "TraceOptoOutput", Bool) \ option(TraceSpilling, "TraceSpilling", Bool) \ - option(PrintIdeal, "PrintIdeal", Bool) \ - option(IGVPrintLevel, "IGVPrintLevel", Intx) \ +NOT_PRODUCT(option(TraceEscapeAnalysis, "TraceEscapeAnalysis", Bool)) \ +NOT_PRODUCT(option(PrintIdeal, "PrintIdeal", Bool)) \ +NOT_PRODUCT(option(PrintIdealPhase, "PrintIdealPhase", Ccstrlist)) \ +NOT_PRODUCT(option(IGVPrintLevel, "IGVPrintLevel", Intx)) \ option(Vectorize, "Vectorize", Bool) \ option(VectorizeDebug, "VectorizeDebug", Uintx) \ option(CloneMapDebug, "CloneMapDebug", Bool) \ diff --git a/src/hotspot/share/compiler/directivesParser.cpp b/src/hotspot/share/compiler/directivesParser.cpp index e88dda3768b810914b417ed4e8d0c3bb4634ef91..e48ac58b31c1f8b622a93ef2fe50dd31201e0394 100644 --- a/src/hotspot/share/compiler/directivesParser.cpp +++ b/src/hotspot/share/compiler/directivesParser.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -27,6 +27,7 @@ #include "compiler/directivesParser.hpp" #include "memory/allocation.inline.hpp" #include "memory/resourceArea.hpp" +#include "opto/phasetype.hpp" #include "runtime/os.hpp" #include @@ -94,11 +95,11 @@ bool DirectivesParser::parse_from_file_inner(const char* filename, outputStream* if (file_handle != -1) { // read contents into resource array char* buffer = NEW_RESOURCE_ARRAY(char, st.st_size+1); - ssize_t num_read = os::read(file_handle, (char*) buffer, st.st_size); + ssize_t num_read = ::read(file_handle, (char*) buffer, st.st_size); if (num_read >= 0) { buffer[num_read] = '\0'; // close file - os::close(file_handle); + ::close(file_handle); return parse_string(buffer, stream) > 0; } } @@ -334,6 +335,15 @@ bool DirectivesParser::set_option_flag(JSON_TYPE t, JSON_VAL* v, const key* opti error(VALUE_ERROR, "Unrecognized intrinsic detected in DisableIntrinsic: %s", validator.what()); return false; } + } else if (strncmp(option_key->name, "PrintIdealPhase", 15) == 0) { + uint64_t mask = 0; + PhaseNameValidator validator(s, mask); + + if (!validator.is_valid()) { + error(VALUE_ERROR, "Unrecognized phase name detected in PrintIdealPhase: %s", validator.what()); + return false; + } + set->set_ideal_phase_mask(mask); } } break; diff --git a/src/hotspot/share/compiler/disassembler.cpp b/src/hotspot/share/compiler/disassembler.cpp index 54cea9cc2811d56e1e1011c6768513b710764528..1beb75441cd429e14d1914fb35eba85bc6240dcc 100644 --- a/src/hotspot/share/compiler/disassembler.cpp +++ b/src/hotspot/share/compiler/disassembler.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 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 @@ -267,7 +267,7 @@ void decode_env::print_hook_comments(address pc, bool newline) { _cached_src_lines = new (ResourceObj::C_HEAP, mtCode)GrowableArray(0, mtCode); } - if ((fp = fopen(file, "r")) == NULL) { + if ((fp = os::fopen(file, "r")) == NULL) { _cached_src = NULL; return; } diff --git a/src/hotspot/share/compiler/methodLiveness.cpp b/src/hotspot/share/compiler/methodLiveness.cpp index 5f83eea6716e65406e2239906f7f724b2fd004f4..6bcabfe4ace5a1ca6aa6aa334acd7ed1e5d32057 100644 --- a/src/hotspot/share/compiler/methodLiveness.cpp +++ b/src/hotspot/share/compiler/methodLiveness.cpp @@ -97,8 +97,6 @@ void MethodLiveness::compute_liveness() { void MethodLiveness::init_basic_blocks() { - bool bailout = false; - int method_len = method()->code_size(); ciMethodBlocks *mblocks = method()->get_method_blocks(); @@ -255,10 +253,6 @@ void MethodLiveness::init_basic_blocks() { // We will patch up jsr/rets in a subsequent pass. ret_list->append(current_block); break; - case Bytecodes::_breakpoint: - // Bail out of there are breakpoints in here. - bailout = true; - break; default: // Do nothing. break; diff --git a/src/hotspot/share/gc/epsilon/epsilonHeap.hpp b/src/hotspot/share/gc/epsilon/epsilonHeap.hpp index 0f929b64bd9f9faa47d1dbbb897bd00e36ec1074..036593c72aef61cc37e9d1f59f7702b5f578292e 100644 --- a/src/hotspot/share/gc/epsilon/epsilonHeap.hpp +++ b/src/hotspot/share/gc/epsilon/epsilonHeap.hpp @@ -132,7 +132,7 @@ public: bool is_in_reserved(const void* addr) const { return _reserved.contains(addr); } // Support for loading objects from CDS archive into the heap - virtual bool can_load_archived_objects() const { return true; } + virtual bool can_load_archived_objects() const { return UseCompressedOops; } virtual HeapWord* allocate_loaded_archive_space(size_t size); virtual void print_on(outputStream* st) const; diff --git a/src/hotspot/share/gc/g1/c1/g1BarrierSetC1.cpp b/src/hotspot/share/gc/g1/c1/g1BarrierSetC1.cpp index 29c0d2689d80d9ae50303581308b5ec3913e0d41..fbed1921182d2d1b00a4b61d581791ecf5ffbe5d 100644 --- a/src/hotspot/share/gc/g1/c1/g1BarrierSetC1.cpp +++ b/src/hotspot/share/gc/g1/c1/g1BarrierSetC1.cpp @@ -152,13 +152,13 @@ void G1BarrierSetC1::post_barrier(LIRAccess& access, LIR_Opr addr, LIR_Opr new_v __ unsigned_shift_right(xor_shift_res, LIR_OprFact::intConst(HeapRegion::LogOfHRGrainBytes), xor_shift_res, - LIR_OprDesc::illegalOpr()); + LIR_Opr::illegalOpr()); } else { __ logical_xor(addr, new_val, xor_res); __ unsigned_shift_right(xor_res, LIR_OprFact::intConst(HeapRegion::LogOfHRGrainBytes), xor_shift_res, - LIR_OprDesc::illegalOpr()); + LIR_Opr::illegalOpr()); } if (!new_val->is_register()) { diff --git a/src/hotspot/share/gc/g1/c2/g1BarrierSetC2.cpp b/src/hotspot/share/gc/g1/c2/g1BarrierSetC2.cpp index d5c4c14f92e3fc168c2f4350b05840ba672e75ff..7d28f26e68edfd3d6fa560e42fa7d945b54173f1 100644 --- a/src/hotspot/share/gc/g1/c2/g1BarrierSetC2.cpp +++ b/src/hotspot/share/gc/g1/c2/g1BarrierSetC2.cpp @@ -442,7 +442,7 @@ void G1BarrierSetC2::post_barrier(GraphKit* kit, Node* cast = __ CastPX(__ ctrl(), adr); // Divide pointer by card size - Node* card_offset = __ URShiftX( cast, __ ConI(CardTable::card_shift) ); + 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 ); diff --git a/src/hotspot/share/gc/g1/g1AllocRegion.cpp b/src/hotspot/share/gc/g1/g1AllocRegion.cpp index 239822d6d1d9fbedef918942a172bacf47326879..915110e3ebb1f5c22bd837384972d7c541896d86 100644 --- a/src/hotspot/share/gc/g1/g1AllocRegion.cpp +++ b/src/hotspot/share/gc/g1/g1AllocRegion.cpp @@ -371,7 +371,7 @@ HeapRegion* OldGCAllocRegion::release() { // Determine how far we are from the next card boundary. If it is smaller than // the minimum object size we can allocate into, expand into the next card. HeapWord* top = cur->top(); - HeapWord* aligned_top = align_up(top, BOTConstants::N_bytes); + HeapWord* aligned_top = align_up(top, BOTConstants::card_size()); size_t to_allocate_words = pointer_delta(aligned_top, top, HeapWordSize); diff --git a/src/hotspot/share/gc/g1/g1Allocator.cpp b/src/hotspot/share/gc/g1/g1Allocator.cpp index 7a6cb0a499dcb0807981d4ec7a3c43b070a92336..f83ae9b52d30d919745911eae7cebef620597539 100644 --- a/src/hotspot/share/gc/g1/g1Allocator.cpp +++ b/src/hotspot/share/gc/g1/g1Allocator.cpp @@ -301,10 +301,7 @@ G1PLABAllocator::G1PLABAllocator(G1Allocator* allocator) : _alloc_buffers[state] = NEW_C_HEAP_ARRAY(PLAB*, length, mtGC); size_t word_sz = _g1h->desired_plab_sz(state); for (uint node_index = 0; node_index < length; node_index++) { - // Specialized PLABs for old that handle BOT updates for object allocations. - _alloc_buffers[state][node_index] = (state == G1HeapRegionAttr::Old) - ? new G1BotUpdatingPLAB(word_sz) - : new PLAB(word_sz); + _alloc_buffers[state][node_index] = new PLAB(word_sz); } } } @@ -364,7 +361,6 @@ HeapWord* G1PLABAllocator::allocate_direct_or_new_plab(G1HeapRegionAttr dest, // Try direct allocation. HeapWord* result = _allocator->par_allocate_during_gc(dest, word_sz, node_index); if (result != NULL) { - update_bot_for_direct_allocation(dest, result, word_sz); _direct_allocated[dest.type()] += word_sz; } return result; diff --git a/src/hotspot/share/gc/g1/g1Allocator.hpp b/src/hotspot/share/gc/g1/g1Allocator.hpp index 8eea1e0f12b43ef2ba3c6ad82d70086134cefcc0..5014442845ab91469cf966e1a450b296660d3200 100644 --- a/src/hotspot/share/gc/g1/g1Allocator.hpp +++ b/src/hotspot/share/gc/g1/g1Allocator.hpp @@ -145,22 +145,6 @@ public: uint node_index); }; -// Specialized PLAB for old generation promotions. For old regions the -// BOT needs to be updated and the relevant data to do this efficiently -// is stored in the PLAB. -class G1BotUpdatingPLAB : public PLAB { - // An object spanning this threshold will cause a BOT update. - HeapWord* _next_bot_threshold; - // The region in which the PLAB resides. - HeapRegion* _region; -public: - G1BotUpdatingPLAB(size_t word_sz) : PLAB(word_sz) { } - // Sets the new PLAB buffer as well as updates the threshold and region. - void set_buf(HeapWord* buf, size_t word_sz) override; - // Updates the BOT if the last allocation crossed the threshold. - inline void update_bot(size_t word_sz); -}; - // Manages the PLABs used during garbage collection. Interface for allocation from PLABs. // Needs to handle multiple contexts, extra alignment in any "survivor" area and some // statistics. @@ -181,18 +165,11 @@ private: inline PLAB* alloc_buffer(G1HeapRegionAttr dest, uint node_index) const; inline PLAB* alloc_buffer(region_type_t dest, uint node_index) const; - // Helpers to do explicit BOT updates for allocations in old generation regions. - void update_bot_for_direct_allocation(G1HeapRegionAttr attr, HeapWord* addr, size_t size); - // Returns the number of allocation buffers for the given dest. // There is only 1 buffer for Old while Young may have multiple buffers depending on // active NUMA nodes. inline uint alloc_buffers_length(region_type_t dest) const; - // Returns if BOT updates are needed for the given destinaion. Currently we only have - // two destinations and BOT updates are only needed for the old generation. - inline bool needs_bot_update(G1HeapRegionAttr dest) const; - bool may_throw_away_buffer(size_t const allocation_word_sz, size_t const buffer_size) const; public: G1PLABAllocator(G1Allocator* allocator); @@ -221,9 +198,6 @@ public: bool* refill_failed, uint node_index); - // Update the BOT for the last PLAB allocation. - inline void update_bot_for_plab_allocation(G1HeapRegionAttr dest, size_t word_sz, uint node_index); - void undo_allocation(G1HeapRegionAttr dest, HeapWord* obj, size_t word_sz, uint node_index); }; diff --git a/src/hotspot/share/gc/g1/g1Allocator.inline.hpp b/src/hotspot/share/gc/g1/g1Allocator.inline.hpp index 82223a75ad454522d090186f03f1d1ffbfae8302..42d6a547257511d2d6a9eb4c669f254f5c84a52b 100644 --- a/src/hotspot/share/gc/g1/g1Allocator.inline.hpp +++ b/src/hotspot/share/gc/g1/g1Allocator.inline.hpp @@ -133,49 +133,4 @@ inline HeapWord* G1PLABAllocator::allocate(G1HeapRegionAttr dest, return allocate_direct_or_new_plab(dest, word_sz, refill_failed, node_index); } -inline bool G1PLABAllocator::needs_bot_update(G1HeapRegionAttr dest) const { - return dest.is_old(); -} - -inline void G1PLABAllocator::update_bot_for_direct_allocation(G1HeapRegionAttr attr, HeapWord* addr, size_t size) { - if (!needs_bot_update(attr)) { - return; - } - - // Out of PLAB allocations in an old generation region. Update BOT. - HeapRegion* region = _g1h->heap_region_containing(addr); - region->update_bot_at(addr, size); -} - -inline void G1PLABAllocator::update_bot_for_plab_allocation(G1HeapRegionAttr dest, size_t word_sz, uint node_index) { - assert(needs_bot_update(dest), "Wrong destination: %s", dest.get_type_str()); - G1BotUpdatingPLAB* plab = static_cast(alloc_buffer(dest, node_index)); - plab->update_bot(word_sz); -} - -inline void G1BotUpdatingPLAB::set_buf(HeapWord* buf, size_t word_sz) { - PLAB::set_buf(buf, word_sz); - // Update the region and threshold to allow efficient BOT updates. - _region = G1CollectedHeap::heap()->heap_region_containing(buf); - _next_bot_threshold = _region->bot_threshold_for_addr(buf); -} - -inline void G1BotUpdatingPLAB::update_bot(size_t word_sz) { - // The last object end is at _top, if it did not cross the - // threshold, there is nothing to do. - if (_top <= _next_bot_threshold) { - return; - } - - HeapWord* obj_start = _top - word_sz; - assert(contains(obj_start), - "Object start outside PLAB. bottom: " PTR_FORMAT " object: " PTR_FORMAT, - p2i(_bottom), p2i(obj_start)); - assert(obj_start <= _next_bot_threshold, - "Object start not below or at threshold. threshold: " PTR_FORMAT " object: " PTR_FORMAT, - p2i(_next_bot_threshold), p2i(obj_start)); - - _region->update_bot_crossing_threshold(&_next_bot_threshold, obj_start, _top); -} - #endif // SHARE_GC_G1_G1ALLOCATOR_INLINE_HPP diff --git a/src/hotspot/share/gc/g1/g1Arguments.cpp b/src/hotspot/share/gc/g1/g1Arguments.cpp index aa1755bc3c650d9c16db92c5140680eeec9927a2..348402cf95785697437d9bd064befb965fd466fe 100644 --- a/src/hotspot/share/gc/g1/g1Arguments.cpp +++ b/src/hotspot/share/gc/g1/g1Arguments.cpp @@ -45,6 +45,9 @@ static size_t calculate_heap_alignment(size_t space_alignment) { } void G1Arguments::initialize_alignments() { + // Initialize card size before initializing alignments + CardTable::initialize_card_size(); + // Set up the region size and associated fields. // // There is a circular dependency here. We base the region size on the heap @@ -132,15 +135,15 @@ void G1Arguments::initialize_card_set_configuration() { uint region_size_log_mb = (uint)MAX2(HeapRegion::LogOfHRGrainBytes - LOG_M, 0); if (FLAG_IS_DEFAULT(G1RemSetArrayOfCardsEntries)) { - uint num_cards_in_inline_ptr = G1CardSetConfiguration::num_cards_in_inline_ptr(HeapRegion::LogOfHRGrainBytes - CardTable::card_shift); - FLAG_SET_ERGO(G1RemSetArrayOfCardsEntries, MAX2(num_cards_in_inline_ptr * 2, + uint max_cards_in_inline_ptr = G1CardSetConfiguration::max_cards_in_inline_ptr(HeapRegion::LogOfHRGrainBytes - CardTable::card_shift()); + FLAG_SET_ERGO(G1RemSetArrayOfCardsEntries, MAX2(max_cards_in_inline_ptr * 2, G1RemSetArrayOfCardsEntriesBase * (1u << (region_size_log_mb + 1)))); } // Round to next 8 byte boundary for array to maximize space usage. size_t const cur_size = G1CardSetArray::size_in_bytes(G1RemSetArrayOfCardsEntries); FLAG_SET_ERGO(G1RemSetArrayOfCardsEntries, - G1RemSetArrayOfCardsEntries + (uint)(align_up(cur_size, G1CardSetAllocOptions::BufferAlignment) - cur_size) / sizeof(G1CardSetArray::EntryDataType)); + G1RemSetArrayOfCardsEntries + (uint)(align_up(cur_size, G1CardSetAllocOptions::SlotAlignment) - cur_size) / sizeof(G1CardSetArray::EntryDataType)); // Howl card set container globals. if (FLAG_IS_DEFAULT(G1RemSetHowlNumBuckets)) { @@ -240,7 +243,7 @@ void G1Arguments::initialize() { // the refcount in G1CardSetContainer. uint max_parallel_refinement_threads = G1ConcRefinementThreads + G1DirtyCardQueueSet::num_par_ids(); uint const divisor = 3; // Safe divisor; we increment by 2 for each claim, but there is a small initial value. - if (max_parallel_refinement_threads > UINTPTR_MAX / divisor) { + if (max_parallel_refinement_threads > UINT_MAX / divisor) { vm_exit_during_initialization("Too large parallelism for remembered sets."); } } diff --git a/src/hotspot/share/gc/g1/g1BlockOffsetTable.cpp b/src/hotspot/share/gc/g1/g1BlockOffsetTable.cpp index fd7ea33ea9291dbc59a087b2f5d7c5d8e04a6e62..d5032957d789b6e1b720b718161b70aaab9b79f7 100644 --- a/src/hotspot/share/gc/g1/g1BlockOffsetTable.cpp +++ b/src/hotspot/share/gc/g1/g1BlockOffsetTable.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -52,14 +52,14 @@ G1BlockOffsetTable::G1BlockOffsetTable(MemRegion heap, G1RegionToSpaceMapper* st bool G1BlockOffsetTable::is_card_boundary(HeapWord* p) const { assert(p >= _reserved.start(), "just checking"); size_t delta = pointer_delta(p, _reserved.start()); - return (delta & right_n_bits((int)BOTConstants::LogN_words)) == (size_t)NoBits; + return (delta & right_n_bits((int)BOTConstants::log_card_size_in_words())) == (size_t)NoBits; } #ifdef ASSERT void G1BlockOffsetTable::check_index(size_t index, const char* msg) const { - assert((index) < (_reserved.word_size() >> BOTConstants::LogN_words), + assert((index) < (_reserved.word_size() >> BOTConstants::log_card_size_in_words()), "%s - index: " SIZE_FORMAT ", _vs.committed_size: " SIZE_FORMAT, - msg, (index), (_reserved.word_size() >> BOTConstants::LogN_words)); + msg, (index), (_reserved.word_size() >> BOTConstants::log_card_size_in_words())); assert(G1CollectedHeap::heap()->is_in(address_for_index_raw(index)), "Index " SIZE_FORMAT " corresponding to " PTR_FORMAT " (%u) is not in committed area.", @@ -74,8 +74,6 @@ void G1BlockOffsetTable::check_index(size_t index, const char* msg) const { ////////////////////////////////////////////////////////////////////// G1BlockOffsetTablePart::G1BlockOffsetTablePart(G1BlockOffsetTable* array, HeapRegion* hr) : - _next_offset_threshold(NULL), - DEBUG_ONLY(_object_can_span(false) COMMA) _bot(array), _hr(hr) { @@ -89,22 +87,15 @@ void G1BlockOffsetTablePart::update() { while (next_addr < limit) { prev_addr = next_addr; next_addr = prev_addr + block_size(prev_addr); - alloc_block(prev_addr, next_addr); + update_for_block(prev_addr, next_addr); } assert(next_addr == limit, "Should stop the scan at the limit."); } // The arguments follow the normal convention of denoting // a right-open interval: [start, end) -void G1BlockOffsetTablePart:: set_remainder_to_point_to_start(HeapWord* start, HeapWord* end) { - - if (start >= end) { - // The start address is equal to the end address (or to - // the right of the end address) so there are not cards - // that need to be updated.. - return; - } - +void G1BlockOffsetTablePart::set_remainder_to_point_to_start(HeapWord* start, HeapWord* end) { + assert(start < end, "precondition"); // Write the backskip value for each region. // // offset @@ -141,7 +132,7 @@ void G1BlockOffsetTablePart:: set_remainder_to_point_to_start(HeapWord* start, H size_t start_card = _bot->index_for(start); size_t end_card = _bot->index_for(end-1); assert(start ==_bot->address_for_index(start_card), "Precondition"); - assert(end ==_bot->address_for_index(end_card)+BOTConstants::N_words, "Precondition"); + assert(end ==_bot->address_for_index(end_card)+BOTConstants::card_size_in_words(), "Precondition"); set_remainder_to_point_to_start_incl(start_card, end_card); // closed interval } @@ -149,11 +140,9 @@ void G1BlockOffsetTablePart:: set_remainder_to_point_to_start(HeapWord* start, H // a closed, inclusive interval: [start_card, end_card], cf set_remainder_to_point_to_start() // above. void G1BlockOffsetTablePart::set_remainder_to_point_to_start_incl(size_t start_card, size_t end_card) { - if (start_card > end_card) { - return; - } + assert(start_card <= end_card, "precondition"); assert(start_card > _bot->index_for(_hr->bottom()), "Cannot be first card"); - assert(_bot->offset_array(start_card-1) <= BOTConstants::N_words, + assert(_bot->offset_array(start_card-1) < BOTConstants::card_size_in_words(), "Offset card has an unexpected value"); size_t start_card_for_region = start_card; u_char offset = max_jubyte; @@ -162,7 +151,7 @@ void G1BlockOffsetTablePart::set_remainder_to_point_to_start_incl(size_t start_c // so that the reach ends in this region and not at the start // of the next. size_t reach = start_card - 1 + (BOTConstants::power_to_cards_back(i+1) - 1); - offset = BOTConstants::N_words + i; + offset = BOTConstants::card_size_in_words() + i; if (reach >= end_card) { _bot->set_offset_array(start_card_for_region, end_card, offset); start_card_for_region = reach + 1; @@ -183,16 +172,16 @@ void G1BlockOffsetTablePart::check_all_cards(size_t start_card, size_t end_card) if (end_card < start_card) { return; } - guarantee(_bot->offset_array(start_card) == BOTConstants::N_words, "Wrong value in second card"); + guarantee(_bot->offset_array(start_card) == BOTConstants::card_size_in_words(), "Wrong value in second card"); for (size_t c = start_card + 1; c <= end_card; c++ /* yeah! */) { u_char entry = _bot->offset_array(c); if (c - start_card > BOTConstants::power_to_cards_back(1)) { - guarantee(entry > BOTConstants::N_words, + guarantee(entry > BOTConstants::card_size_in_words(), "Should be in logarithmic region - " "entry: %u, " "_array->offset_array(c): %u, " "N_words: %u", - (uint)entry, (uint)_bot->offset_array(c), BOTConstants::N_words); + (uint)entry, (uint)_bot->offset_array(c), BOTConstants::card_size_in_words()); } size_t backskip = BOTConstants::entry_to_cards_back(entry); size_t landing_card = c - backskip; @@ -205,130 +194,86 @@ void G1BlockOffsetTablePart::check_all_cards(size_t start_card, size_t end_card) } else { guarantee(landing_card == start_card - 1, "Tautology"); // Note that N_words is the maximum offset value - guarantee(_bot->offset_array(landing_card) <= BOTConstants::N_words, + guarantee(_bot->offset_array(landing_card) < BOTConstants::card_size_in_words(), "landing card offset: %u, " "N_words: %u", - (uint)_bot->offset_array(landing_card), (uint)BOTConstants::N_words); + (uint)_bot->offset_array(landing_card), (uint)BOTConstants::card_size_in_words()); } } } -HeapWord* G1BlockOffsetTablePart::forward_to_block_containing_addr_slow(HeapWord* q, - HeapWord* n, - const void* addr) { - // We're not in the normal case. We need to handle an important subcase - // here: LAB allocation. An allocation previously recorded in the - // offset table was actually a lab allocation, and was divided into - // several objects subsequently. Fix this situation as we answer the - // query, by updating entries as we cross them. - - // If the fist object's end q is at the card boundary. Start refining - // with the corresponding card (the value of the entry will be basically - // set to 0). If the object crosses the boundary -- start from the next card. - size_t n_index = _bot->index_for(n); - size_t next_index = _bot->index_for(n) + !_bot->is_card_boundary(n); - // Calculate a consistent next boundary. If "n" is not at the boundary - // already, step to the boundary. - HeapWord* next_boundary = _bot->address_for_index(n_index) + - (n_index == next_index ? 0 : BOTConstants::N_words); - assert(next_boundary <= _bot->_reserved.end(), - "next_boundary is beyond the end of the covered region " - " next_boundary " PTR_FORMAT " _array->_end " PTR_FORMAT, - p2i(next_boundary), p2i(_bot->_reserved.end())); - while (next_boundary < addr) { - while (n <= next_boundary) { - q = n; - oop obj = cast_to_oop(q); - if (obj->klass_or_null_acquire() == NULL) return q; - n += block_size(q); - } - assert(q <= next_boundary && n > next_boundary, "Consequence of loop"); - // [q, n) is the block that crosses the boundary. - alloc_block_work(&next_boundary, q, n); - } - return forward_to_block_containing_addr_const(q, n, addr); -} - // -// threshold_ +// cur_card_boundary // | _index_ // v v // +-------+-------+-------+-------+-------+ // | i-1 | i | i+1 | i+2 | i+3 | // +-------+-------+-------+-------+-------+ // ( ^ ] -// block-start +// blk_start // -void G1BlockOffsetTablePart::alloc_block_work(HeapWord** threshold_, HeapWord* blk_start, - HeapWord* blk_end) { - // For efficiency, do copy-in/copy-out. - HeapWord* threshold = *threshold_; - size_t index = _bot->index_for_raw(threshold); +void G1BlockOffsetTablePart::update_for_block_work(HeapWord* blk_start, + HeapWord* blk_end) { + HeapWord* const cur_card_boundary = align_up_by_card_size(blk_start); + size_t const index = _bot->index_for_raw(cur_card_boundary); assert(blk_start != NULL && blk_end > blk_start, "phantom block"); - assert(blk_end > threshold, "should be past threshold"); - assert(blk_start <= threshold, "blk_start should be at or before threshold"); - assert(pointer_delta(threshold, blk_start) <= BOTConstants::N_words, - "offset should be <= BlockOffsetSharedArray::N"); + assert(blk_end > cur_card_boundary, "should be past cur_card_boundary"); + assert(blk_start <= cur_card_boundary, "blk_start should be at or before cur_card_boundary"); + assert(pointer_delta(cur_card_boundary, blk_start) < BOTConstants::card_size_in_words(), + "offset should be < BOTConstants::card_size_in_words()"); assert(G1CollectedHeap::heap()->is_in_reserved(blk_start), "reference must be into the heap"); - assert(G1CollectedHeap::heap()->is_in_reserved(blk_end-1), + assert(G1CollectedHeap::heap()->is_in_reserved(blk_end - 1), "limit must be within the heap"); - assert(threshold == _bot->_reserved.start() + index*BOTConstants::N_words, - "index must agree with threshold"); - - DEBUG_ONLY(size_t orig_index = index;) + assert(cur_card_boundary == _bot->_reserved.start() + index*BOTConstants::card_size_in_words(), + "index must agree with cur_card_boundary"); - // Mark the card that holds the offset into the block. Note - // that _next_offset_threshold is not updated until the end - // of this method. - _bot->set_offset_array(index, threshold, blk_start); + // Mark the card that holds the offset into the block. + _bot->set_offset_array(index, cur_card_boundary, blk_start); - // We need to now mark the subsequent cards that this blk spans. + // We need to now mark the subsequent cards that this block spans. - // Index of card on which blk ends. - size_t end_index = _bot->index_for(blk_end - 1); + // Index of card on which the block ends. + size_t end_index = _bot->index_for(blk_end - 1); // Are there more cards left to be updated? if (index + 1 <= end_index) { HeapWord* rem_st = _bot->address_for_index(index + 1); // Calculate rem_end this way because end_index // may be the last valid index in the covered region. - HeapWord* rem_end = _bot->address_for_index(end_index) + BOTConstants::N_words; + HeapWord* rem_end = _bot->address_for_index(end_index) + BOTConstants::card_size_in_words(); set_remainder_to_point_to_start(rem_st, rem_end); } - index = end_index + 1; - // Calculate threshold_ this way because end_index +#ifdef ASSERT + // Calculate new_card_boundary this way because end_index // may be the last valid index in the covered region. - threshold = _bot->address_for_index(end_index) + BOTConstants::N_words; - assert(threshold >= blk_end, "Incorrect offset threshold"); - - *threshold_ = threshold; + HeapWord* new_card_boundary = _bot->address_for_index(end_index) + BOTConstants::card_size_in_words(); + assert(new_card_boundary >= blk_end, "postcondition"); -#ifdef ASSERT // The offset can be 0 if the block starts on a boundary. That // is checked by an assertion above. size_t start_index = _bot->index_for(blk_start); HeapWord* boundary = _bot->address_for_index(start_index); - assert((_bot->offset_array(orig_index) == 0 && blk_start == boundary) || - (_bot->offset_array(orig_index) > 0 && _bot->offset_array(orig_index) <= BOTConstants::N_words), + assert((_bot->offset_array(index) == 0 && blk_start == boundary) || + (_bot->offset_array(index) > 0 && _bot->offset_array(index) < BOTConstants::card_size_in_words()), "offset array should have been set - " - "orig_index offset: %u, " + "index offset: %u, " "blk_start: " PTR_FORMAT ", " "boundary: " PTR_FORMAT, - (uint)_bot->offset_array(orig_index), + (uint)_bot->offset_array(index), p2i(blk_start), p2i(boundary)); - for (size_t j = orig_index + 1; j <= end_index; j++) { + for (size_t j = index + 1; j <= end_index; j++) { assert(_bot->offset_array(j) > 0 && _bot->offset_array(j) <= - (u_char) (BOTConstants::N_words+BOTConstants::N_powers-1), + (u_char) (BOTConstants::card_size_in_words()+BOTConstants::N_powers-1), "offset array should have been set - " "%u not > 0 OR %u not <= %u", (uint) _bot->offset_array(j), (uint) _bot->offset_array(j), - (uint) (BOTConstants::N_words+BOTConstants::N_powers-1)); + (uint) (BOTConstants::card_size_in_words() + BOTConstants::N_powers - 1)); } #endif } @@ -336,13 +281,11 @@ void G1BlockOffsetTablePart::alloc_block_work(HeapWord** threshold_, HeapWord* b void G1BlockOffsetTablePart::verify() const { assert(_hr->bottom() < _hr->top(), "Only non-empty regions should be verified."); size_t start_card = _bot->index_for(_hr->bottom()); - // Do not verify beyond the BOT allocation threshold. - assert(_hr->top() <= _next_offset_threshold, "invariant"); size_t end_card = _bot->index_for(_hr->top() - 1); for (size_t current_card = start_card; current_card < end_card; current_card++) { u_char entry = _bot->offset_array(current_card); - if (entry < BOTConstants::N_words) { + if (entry < BOTConstants::card_size_in_words()) { // The entry should point to an object before the current card. Verify that // it is possible to walk from that object in to the current card by just // iterating over the objects following it. @@ -376,12 +319,6 @@ void G1BlockOffsetTablePart::verify() const { } } -#ifdef ASSERT -void G1BlockOffsetTablePart::set_object_can_span(bool can_span) { - _object_can_span = can_span; -} -#endif - #ifndef PRODUCT void G1BlockOffsetTablePart::print_on(outputStream* out) { size_t from_index = _bot->index_for(_hr->bottom()); @@ -394,26 +331,12 @@ void G1BlockOffsetTablePart::print_on(outputStream* out) { i, p2i(_bot->address_for_index(i)), (uint) _bot->offset_array(i)); } - out->print_cr(" next offset threshold: " PTR_FORMAT, p2i(_next_offset_threshold)); } #endif // !PRODUCT -void G1BlockOffsetTablePart::zero_bottom_entry_raw() { - size_t bottom_index = _bot->index_for_raw(_hr->bottom()); - assert(_bot->address_for_index_raw(bottom_index) == _hr->bottom(), - "Precondition of call"); - _bot->set_offset_array_raw(bottom_index, 0); -} - -void G1BlockOffsetTablePart::initialize_threshold() { - _next_offset_threshold = _hr->bottom() + BOTConstants::N_words; -} - void G1BlockOffsetTablePart::set_for_starts_humongous(HeapWord* obj_top, size_t fill_size) { - // The first BOT entry should have offset 0. - reset_bot(); - alloc_block(_hr->bottom(), obj_top); + update_for_block(_hr->bottom(), obj_top); if (fill_size > 0) { - alloc_block(obj_top, fill_size); + update_for_block(obj_top, fill_size); } } diff --git a/src/hotspot/share/gc/g1/g1BlockOffsetTable.hpp b/src/hotspot/share/gc/g1/g1BlockOffsetTable.hpp index 89a91d5bce2036c8f3e5f5cc2aba301d56f6bdd6..b70435bf21d33dda3b5fadb8414e20dfb297113f 100644 --- a/src/hotspot/share/gc/g1/g1BlockOffsetTable.hpp +++ b/src/hotspot/share/gc/g1/g1BlockOffsetTable.hpp @@ -55,9 +55,9 @@ private: volatile u_char* _offset_array; // byte array keeping backwards offsets void check_offset(size_t offset, const char* msg) const { - assert(offset <= BOTConstants::N_words, + assert(offset < BOTConstants::card_size_in_words(), "%s - offset: " SIZE_FORMAT ", N_words: %u", - msg, offset, BOTConstants::N_words); + msg, offset, BOTConstants::card_size_in_words()); } // Bounds checking accessors: @@ -80,13 +80,13 @@ public: // Return the number of slots needed for an offset array // that covers mem_region_words words. static size_t compute_size(size_t mem_region_words) { - size_t number_of_slots = (mem_region_words / BOTConstants::N_words); + size_t number_of_slots = (mem_region_words / BOTConstants::card_size_in_words()); return ReservedSpace::allocation_align_size_up(number_of_slots); } // Returns how many bytes of the heap a single byte of the BOT corresponds to. static size_t heap_map_factor() { - return BOTConstants::N_bytes; + return BOTConstants::card_size(); } // Initialize the Block Offset Table to cover the memory region passed @@ -102,7 +102,7 @@ public: inline HeapWord* address_for_index(size_t index) const; // Variant of address_for_index that does not check the index for validity. inline HeapWord* address_for_index_raw(size_t index) const { - return _reserved.start() + (index << BOTConstants::LogN_words); + return _reserved.start() + (index << BOTConstants::log_card_size_in_words()); } }; @@ -111,12 +111,6 @@ class G1BlockOffsetTablePart { friend class HeapRegion; friend class VMStructs; private: - // allocation boundary at which offset array must be updated - HeapWord* _next_offset_threshold; - - // Indicates if an object can span into this G1BlockOffsetTablePart. - debug_only(bool _object_can_span;) - // This is the global BlockOffsetTable. G1BlockOffsetTable* _bot; @@ -132,49 +126,34 @@ private: // that is closed: [start_index, end_index] void set_remainder_to_point_to_start_incl(size_t start, size_t end); - // Zero out the entry for _bottom (offset will be zero). Does not check for availability of the - // memory first. - void zero_bottom_entry_raw(); - inline size_t block_size(const HeapWord* p) const; // Returns the address of a block whose start is at most "addr". inline HeapWord* block_at_or_preceding(const void* addr) const; + // Return the address of the beginning of the block that contains "addr". // "q" is a block boundary that is <= "addr"; "n" is the address of the - // next block (or the end of the space.) Return the address of the - // beginning of the block that contains "addr". Does so without side - // effects (see, e.g., spec of block_start.) - inline HeapWord* forward_to_block_containing_addr_const(HeapWord* q, HeapWord* n, - const void* addr) const; - - // "q" is a block boundary that is <= "addr"; return the address of the - // beginning of the block that contains "addr". May have side effects - // on "this", by updating imprecise entries. - inline HeapWord* forward_to_block_containing_addr(HeapWord* q, - const void* addr); + // next block (or the end of the space.) + inline HeapWord* forward_to_block_containing_addr(HeapWord* q, HeapWord* n, + const void* addr) const; - // "q" is a block boundary that is <= "addr"; "n" is the address of the - // next block (or the end of the space.) Return the address of the - // beginning of the block that contains "addr". May have side effects - // on "this", by updating imprecise entries. - HeapWord* forward_to_block_containing_addr_slow(HeapWord* q, - HeapWord* n, - const void* addr); - - // Requires that "*threshold_" be the first array entry boundary at or - // above "blk_start". If the block starts at or crosses "*threshold_", records - // "blk_start" as the appropriate block start for the array index - // starting at "*threshold_", and for any other indices crossed by the - // block. Updates "*threshold_" to correspond to the first index after - // the block end. - void alloc_block_work(HeapWord** threshold_, - HeapWord* blk_start, - HeapWord* blk_end); + // Update BOT entries corresponding to the mem range [blk_start, blk_end). + void update_for_block_work(HeapWord* blk_start, HeapWord* blk_end); void check_all_cards(size_t left_card, size_t right_card) const; public: + static HeapWord* align_up_by_card_size(HeapWord* const addr) { + return align_up(addr, BOTConstants::card_size()); + } + + static bool is_crossing_card_boundary(HeapWord* const obj_start, + HeapWord* const obj_end) { + HeapWord* cur_card_boundary = align_up_by_card_size(obj_start); + // strictly greater-than + return obj_end > cur_card_boundary; + } + // The elements of the array are initialized to zero. G1BlockOffsetTablePart(G1BlockOffsetTable* array, HeapRegion* hr); @@ -182,52 +161,24 @@ public: void verify() const; - // Given an address calculate where the next threshold needing an update is. - inline HeapWord* threshold_for_addr(const void* addr); - // Returns the address of the start of the block containing "addr", or // else "null" if it is covered by no block. (May have side effects, // namely updating of shared array entries that "point" too far // backwards. This can occur, for example, when lab allocation is used // in a space covered by the table.) inline HeapWord* block_start(const void* addr); - // Same as above, but does not have any of the possible side effects - // discussed above. - inline HeapWord* block_start_const(const void* addr) const; - - // Initialize the threshold to reflect the first boundary after the - // bottom of the covered region. - void initialize_threshold(); - void reset_bot() { - zero_bottom_entry_raw(); - initialize_threshold(); - } - - // Return the next threshold, the point at which the table should be - // updated. - HeapWord* threshold() const { return _next_offset_threshold; } - - // Sets the threshold explicitly to keep it consistent with what has been - // updated. This needs to be done when the threshold is not used for updating - // the bot, for example when promoting to old in young collections. - void set_threshold(HeapWord* threshold) { _next_offset_threshold = threshold; } - - // These must be guaranteed to work properly (i.e., do nothing) - // when "blk_start" ("blk" for second version) is "NULL". In this - // implementation, that's true because NULL is represented as 0, and thus - // never exceeds the "_next_offset_threshold". - void alloc_block(HeapWord* blk_start, HeapWord* blk_end) { - if (blk_end > _next_offset_threshold) { - alloc_block_work(&_next_offset_threshold, blk_start, blk_end); + void update_for_block(HeapWord* blk_start, HeapWord* blk_end) { + if (is_crossing_card_boundary(blk_start, blk_end)) { + update_for_block_work(blk_start, blk_end); } } - void alloc_block(HeapWord* blk, size_t size) { - alloc_block(blk, blk+size); + + void update_for_block(HeapWord* blk_start, size_t size) { + update_for_block(blk_start, blk_start + size); } void set_for_starts_humongous(HeapWord* obj_top, size_t fill_size); - void set_object_can_span(bool can_span) NOT_DEBUG_RETURN; void print_on(outputStream* out) PRODUCT_RETURN; }; diff --git a/src/hotspot/share/gc/g1/g1BlockOffsetTable.inline.hpp b/src/hotspot/share/gc/g1/g1BlockOffsetTable.inline.hpp index 104200eeea2111eb4df3cb4769fc34304644d732..058a9f58785dfd978e02ddd5dbab961159e75276 100644 --- a/src/hotspot/share/gc/g1/g1BlockOffsetTable.inline.hpp +++ b/src/hotspot/share/gc/g1/g1BlockOffsetTable.inline.hpp @@ -30,32 +30,13 @@ #include "gc/g1/heapRegion.hpp" #include "gc/shared/memset_with_concurrent_readers.hpp" #include "runtime/atomic.hpp" - -inline HeapWord* G1BlockOffsetTablePart::threshold_for_addr(const void* addr) { - assert(addr >= _hr->bottom() && addr < _hr->top(), "invalid address"); - size_t index = _bot->index_for(addr); - HeapWord* card_boundary = _bot->address_for_index(index); - // Address at card boundary, use as threshold. - if (card_boundary == addr) { - return card_boundary; - } - - // Calculate next threshold. - HeapWord* threshold = card_boundary + BOTConstants::N_words; - return threshold; -} +#include "oops/oop.inline.hpp" inline HeapWord* G1BlockOffsetTablePart::block_start(const void* addr) { - assert(addr >= _hr->bottom() && addr < _hr->top(), "invalid address"); - HeapWord* q = block_at_or_preceding(addr); - return forward_to_block_containing_addr(q, addr); -} - -inline HeapWord* G1BlockOffsetTablePart::block_start_const(const void* addr) const { assert(addr >= _hr->bottom() && addr < _hr->top(), "invalid address"); HeapWord* q = block_at_or_preceding(addr); HeapWord* n = q + block_size(q); - return forward_to_block_containing_addr_const(q, n, addr); + return forward_to_block_containing_addr(q, n, addr); } u_char G1BlockOffsetTable::offset_array(size_t index) const { @@ -90,7 +71,7 @@ void G1BlockOffsetTable::set_offset_array(size_t left, size_t right, u_char offs // Variant of index_for that does not check the index for validity. inline size_t G1BlockOffsetTable::index_for_raw(const void* p) const { - return pointer_delta((char*)p, _reserved.start(), sizeof(char)) >> BOTConstants::LogN; + return pointer_delta((char*)p, _reserved.start(), sizeof(char)) >> BOTConstants::log_card_size(); } inline size_t G1BlockOffsetTable::index_for(const void* p) const { @@ -119,58 +100,49 @@ inline size_t G1BlockOffsetTablePart::block_size(const HeapWord* p) const { } inline HeapWord* G1BlockOffsetTablePart::block_at_or_preceding(const void* addr) const { - assert(_object_can_span || _bot->offset_array(_bot->index_for(_hr->bottom())) == 0, - "Object crossed region boundary, found offset %u instead of 0", - (uint) _bot->offset_array(_bot->index_for(_hr->bottom()))); +#ifdef ASSERT + if (!_hr->is_continues_humongous()) { + // For non-ContinuesHumongous regions, the first obj always starts from bottom. + u_char offset = _bot->offset_array(_bot->index_for(_hr->bottom())); + assert(offset == 0, "Found offset %u instead of 0 for region %u %s", + offset, _hr->hrm_index(), _hr->get_short_type_str()); + } +#endif size_t index = _bot->index_for(addr); - HeapWord* q = _bot->address_for_index(index); - uint offset = _bot->offset_array(index); // Extend u_char to uint. - while (offset >= BOTConstants::N_words) { + while (offset >= BOTConstants::card_size_in_words()) { // The excess of the offset from N_words indicates a power of Base // to go back by. size_t n_cards_back = BOTConstants::entry_to_cards_back(offset); - q -= (BOTConstants::N_words * n_cards_back); index -= n_cards_back; offset = _bot->offset_array(index); } - assert(offset < BOTConstants::N_words, "offset too large"); - q -= offset; - return q; + assert(offset < BOTConstants::card_size_in_words(), "offset too large"); + + HeapWord* q = _bot->address_for_index(index); + return q - offset; } -inline HeapWord* G1BlockOffsetTablePart::forward_to_block_containing_addr_const(HeapWord* q, HeapWord* n, - const void* addr) const { +inline HeapWord* G1BlockOffsetTablePart::forward_to_block_containing_addr(HeapWord* q, HeapWord* n, + const void* addr) const { while (n <= addr) { + // When addr is not covered by the block starting at q we need to + // step forward until we find the correct block. With the BOT + // being precise, we should never have to step through more than + // a single card. + assert(_bot->index_for(n) == _bot->index_for(addr), + "BOT not precise. Index for n: " SIZE_FORMAT " must be equal to the index for addr: " SIZE_FORMAT, + _bot->index_for(n), _bot->index_for(addr)); q = n; - oop obj = cast_to_oop(q); - if (obj->klass_or_null_acquire() == NULL) { - return q; - } + assert(cast_to_oop(q)->klass_or_null() != nullptr, + "start of block must be an initialized object"); n += block_size(q); } - assert(q <= n, "wrong order for q and addr"); + assert(q <= addr, "wrong order for q and addr"); assert(addr < n, "wrong order for addr and n"); return q; } -inline HeapWord* G1BlockOffsetTablePart::forward_to_block_containing_addr(HeapWord* q, - const void* addr) { - if (cast_to_oop(q)->klass_or_null_acquire() == NULL) { - return q; - } - HeapWord* n = q + block_size(q); - // In the normal case, where the query "addr" is a card boundary, and the - // offset table chunks are the same size as cards, the block starting at - // "q" will contain addr, so the test below will fail, and we'll fall - // through quickly. - if (n <= addr) { - q = forward_to_block_containing_addr_slow(q, n, addr); - } - assert(q <= addr, "wrong order for current and arg"); - return q; -} - #endif // SHARE_GC_G1_G1BLOCKOFFSETTABLE_INLINE_HPP diff --git a/src/hotspot/share/gc/g1/g1CardCounts.cpp b/src/hotspot/share/gc/g1/g1CardCounts.cpp index 1607ec40b95b9a96b2f015bd2b2c5979167001d1..6e56eecafb9a2a4afd22974a13e361c0c1c0b87e 100644 --- a/src/hotspot/share/gc/g1/g1CardCounts.cpp +++ b/src/hotspot/share/gc/g1/g1CardCounts.cpp @@ -126,7 +126,7 @@ void G1CardCounts::clear_range(MemRegion mr) { HeapWord* start_addr = _ct->addr_for(from_card_ptr); assert(start_addr == mr.start(), "MemRegion start must be aligned to a card."); HeapWord* last_addr = _ct->addr_for(last_card_ptr); - assert((last_addr + G1CardTable::card_size_in_words) == mr.end(), "MemRegion end must be aligned to a card."); + assert((last_addr + G1CardTable::card_size_in_words()) == mr.end(), "MemRegion end must be aligned to a card."); #endif // ASSERT // Clear the counts for the (exclusive) card range. diff --git a/src/hotspot/share/gc/g1/g1CardSet.cpp b/src/hotspot/share/gc/g1/g1CardSet.cpp index cabe8573f8879a202ad3984f40f4660f495e615b..82092a1d5020c9d17b5af25c947757365ce4e240 100644 --- a/src/hotspot/share/gc/g1/g1CardSet.cpp +++ b/src/hotspot/share/gc/g1/g1CardSet.cpp @@ -26,83 +26,77 @@ #include "gc/g1/g1CardSet.inline.hpp" #include "gc/g1/g1CardSetContainers.inline.hpp" #include "gc/g1/g1CardSetMemory.inline.hpp" -#include "gc/g1/g1FromCardCache.hpp" #include "gc/g1/heapRegion.inline.hpp" +#include "gc/shared/gcLogPrecious.hpp" +#include "gc/shared/gcTraceTime.inline.hpp" #include "memory/allocation.inline.hpp" #include "runtime/atomic.hpp" #include "runtime/globals_extension.hpp" -#include "runtime/mutex.hpp" #include "utilities/bitMap.inline.hpp" #include "utilities/concurrentHashTable.inline.hpp" #include "utilities/globalDefinitions.hpp" -#include "utilities/lockFreeStack.hpp" -#include "utilities/spinYield.hpp" - -#include "gc/shared/gcLogPrecious.hpp" -#include "gc/shared/gcTraceTime.inline.hpp" -#include "runtime/java.hpp" -G1CardSet::CardSetPtr G1CardSet::FullCardSet = (G1CardSet::CardSetPtr)-1; +G1CardSet::ContainerPtr G1CardSet::FullCardSet = (G1CardSet::ContainerPtr)-1; -static uint default_log2_card_region_per_region() { - uint log2_card_region_per_heap_region = 0; +static uint default_log2_card_regions_per_region() { + uint log2_card_regions_per_heap_region = 0; const uint card_container_limit = G1CardSetContainer::LogCardsPerRegionLimit; if (card_container_limit < (uint)HeapRegion::LogCardsPerRegion) { - log2_card_region_per_heap_region = (uint)HeapRegion::LogCardsPerRegion - card_container_limit; + log2_card_regions_per_heap_region = (uint)HeapRegion::LogCardsPerRegion - card_container_limit; } - return log2_card_region_per_heap_region; + return log2_card_regions_per_heap_region; } G1CardSetConfiguration::G1CardSetConfiguration() : G1CardSetConfiguration(HeapRegion::LogCardsPerRegion, /* inline_ptr_bits_per_card */ - G1RemSetArrayOfCardsEntries, /* num_cards_in_array */ + G1RemSetArrayOfCardsEntries, /* max_cards_in_array */ (double)G1RemSetCoarsenHowlBitmapToHowlFullPercent / 100, /* cards_in_bitmap_threshold_percent */ G1RemSetHowlNumBuckets, /* num_buckets_in_howl */ (double)G1RemSetCoarsenHowlToFullPercent / 100, /* cards_in_howl_threshold_percent */ (uint)HeapRegion::CardsPerRegion, /* max_cards_in_cardset */ - default_log2_card_region_per_region()) /* log2_card_region_per_region */ + default_log2_card_regions_per_region()) /* log2_card_regions_per_region */ { - assert((_log2_card_region_per_heap_region + _log2_cards_per_card_region) == (uint)HeapRegion::LogCardsPerRegion, + assert((_log2_card_regions_per_heap_region + _log2_cards_per_card_region) == (uint)HeapRegion::LogCardsPerRegion, "inconsistent heap region virtualization setup"); } -G1CardSetConfiguration::G1CardSetConfiguration(uint num_cards_in_array, +G1CardSetConfiguration::G1CardSetConfiguration(uint max_cards_in_array, double cards_in_bitmap_threshold_percent, uint max_buckets_in_howl, double cards_in_howl_threshold_percent, uint max_cards_in_card_set, - uint log2_card_region_per_region) : + uint log2_card_regions_per_region) : G1CardSetConfiguration(log2i_exact(max_cards_in_card_set), /* inline_ptr_bits_per_card */ - num_cards_in_array, /* num_cards_in_array */ + max_cards_in_array, /* max_cards_in_array */ cards_in_bitmap_threshold_percent, /* cards_in_bitmap_threshold_percent */ G1CardSetHowl::num_buckets(max_cards_in_card_set, /* num_buckets_in_howl */ - num_cards_in_array, + max_cards_in_array, max_buckets_in_howl), cards_in_howl_threshold_percent, /* cards_in_howl_threshold_percent */ max_cards_in_card_set, /* max_cards_in_cardset */ - log2_card_region_per_region) + log2_card_regions_per_region) { } G1CardSetConfiguration::G1CardSetConfiguration(uint inline_ptr_bits_per_card, - uint num_cards_in_array, + uint max_cards_in_array, double cards_in_bitmap_threshold_percent, uint num_buckets_in_howl, double cards_in_howl_threshold_percent, uint max_cards_in_card_set, - uint log2_card_region_per_heap_region) : + uint log2_card_regions_per_heap_region) : _inline_ptr_bits_per_card(inline_ptr_bits_per_card), - _num_cards_in_array(num_cards_in_array), + _max_cards_in_array(max_cards_in_array), _num_buckets_in_howl(num_buckets_in_howl), _max_cards_in_card_set(max_cards_in_card_set), _cards_in_howl_threshold(max_cards_in_card_set * cards_in_howl_threshold_percent), - _num_cards_in_howl_bitmap(G1CardSetHowl::bitmap_size(_max_cards_in_card_set, _num_buckets_in_howl)), - _cards_in_howl_bitmap_threshold(_num_cards_in_howl_bitmap * cards_in_bitmap_threshold_percent), - _log2_num_cards_in_howl_bitmap(log2i_exact(_num_cards_in_howl_bitmap)), - _bitmap_hash_mask(~(~(0) << _log2_num_cards_in_howl_bitmap)), - _log2_card_region_per_heap_region(log2_card_region_per_heap_region), - _log2_cards_per_card_region(log2i_exact(_max_cards_in_card_set) - _log2_card_region_per_heap_region) { + _max_cards_in_howl_bitmap(G1CardSetHowl::bitmap_size(_max_cards_in_card_set, _num_buckets_in_howl)), + _cards_in_howl_bitmap_threshold(_max_cards_in_howl_bitmap * cards_in_bitmap_threshold_percent), + _log2_max_cards_in_howl_bitmap(log2i_exact(_max_cards_in_howl_bitmap)), + _bitmap_hash_mask(~(~(0) << _log2_max_cards_in_howl_bitmap)), + _log2_card_regions_per_heap_region(log2_card_regions_per_heap_region), + _log2_cards_per_card_region(log2i_exact(_max_cards_in_card_set) - _log2_card_regions_per_heap_region) { assert(is_power_of_2(_max_cards_in_card_set), "max_cards_in_card_set must be a power of 2: %u", _max_cards_in_card_set); @@ -118,31 +112,31 @@ G1CardSetConfiguration::~G1CardSetConfiguration() { void G1CardSetConfiguration::init_card_set_alloc_options() { _card_set_alloc_options = NEW_C_HEAP_ARRAY(G1CardSetAllocOptions, num_mem_object_types(), mtGC); new (&_card_set_alloc_options[0]) G1CardSetAllocOptions((uint)CardSetHash::get_node_size()); - new (&_card_set_alloc_options[1]) G1CardSetAllocOptions((uint)G1CardSetArray::size_in_bytes(_num_cards_in_array), 2, 256); - new (&_card_set_alloc_options[2]) G1CardSetAllocOptions((uint)G1CardSetBitMap::size_in_bytes(_num_cards_in_howl_bitmap), 2, 256); + new (&_card_set_alloc_options[1]) G1CardSetAllocOptions((uint)G1CardSetArray::size_in_bytes(_max_cards_in_array), 2, 256); + new (&_card_set_alloc_options[2]) G1CardSetAllocOptions((uint)G1CardSetBitMap::size_in_bytes(_max_cards_in_howl_bitmap), 2, 256); new (&_card_set_alloc_options[3]) G1CardSetAllocOptions((uint)G1CardSetHowl::size_in_bytes(_num_buckets_in_howl), 2, 256); } void G1CardSetConfiguration::log_configuration() { log_debug_p(gc, remset)("Card Set container configuration: " - "InlinePtr #elems %u size %zu " - "Array Of Cards #elems %u size %zu " + "InlinePtr #cards %u size %zu " + "Array Of Cards #cards %u size %zu " "Howl #buckets %u coarsen threshold %u " - "Howl Bitmap #elems %u size %zu coarsen threshold %u " + "Howl Bitmap #cards %u size %zu coarsen threshold %u " "Card regions per heap region %u cards per card region %u", - num_cards_in_inline_ptr(), sizeof(void*), - num_cards_in_array(), G1CardSetArray::size_in_bytes(num_cards_in_array()), + max_cards_in_inline_ptr(), sizeof(void*), + max_cards_in_array(), G1CardSetArray::size_in_bytes(max_cards_in_array()), num_buckets_in_howl(), cards_in_howl_threshold(), - num_cards_in_howl_bitmap(), G1CardSetBitMap::size_in_bytes(num_cards_in_howl_bitmap()), cards_in_howl_bitmap_threshold(), - (uint)1 << log2_card_region_per_heap_region(), + max_cards_in_howl_bitmap(), G1CardSetBitMap::size_in_bytes(max_cards_in_howl_bitmap()), cards_in_howl_bitmap_threshold(), + (uint)1 << log2_card_regions_per_heap_region(), (uint)1 << log2_cards_per_card_region()); } -uint G1CardSetConfiguration::num_cards_in_inline_ptr() const { - return num_cards_in_inline_ptr(_inline_ptr_bits_per_card); +uint G1CardSetConfiguration::max_cards_in_inline_ptr() const { + return max_cards_in_inline_ptr(_inline_ptr_bits_per_card); } -uint G1CardSetConfiguration::num_cards_in_inline_ptr(uint bits_per_card) { +uint G1CardSetConfiguration::max_cards_in_inline_ptr(uint bits_per_card) { return G1CardSetInlinePtr::max_cards_in_inline_ptr(bits_per_card); } @@ -197,10 +191,10 @@ void G1CardSetCoarsenStats::print_on(outputStream* out) { } class G1CardSetHashTable : public CHeapObj { - using CardSetPtr = G1CardSet::CardSetPtr; + using ContainerPtr = G1CardSet::ContainerPtr; - // Did we insert at least one element in the table? - bool volatile _inserted_elem; + // Did we insert at least one card in the table? + bool volatile _inserted_card; G1CardSetMemoryManager* _mm; CardSetHash _table; @@ -231,12 +225,12 @@ class G1CardSetHashTable : public CHeapObj { }; class G1CardSetHashTableScan : public StackObj { - G1CardSet::G1CardSetPtrIterator* _scan_f; + G1CardSet::ContainerPtrClosure* _scan_f; public: - explicit G1CardSetHashTableScan(G1CardSet::G1CardSetPtrIterator* f) : _scan_f(f) { } + explicit G1CardSetHashTableScan(G1CardSet::ContainerPtrClosure* f) : _scan_f(f) { } bool operator()(G1CardSetHashTableValue* value) { - _scan_f->do_cardsetptr(value->_region_idx, value->_num_occupied, value->_card_set); + _scan_f->do_containerptr(value->_region_idx, value->_num_occupied, value->_container); return true; } }; @@ -247,7 +241,7 @@ public: G1CardSetHashTable(G1CardSetMemoryManager* mm, size_t initial_log_table_size = InitialLogTableSize) : - _inserted_elem(false), + _inserted_card(false), _mm(mm), _table(mm, initial_log_table_size) { } @@ -267,10 +261,10 @@ public: G1CardSetHashTableValue value(region_idx, G1CardSetInlinePtr()); bool inserted = _table.insert_get(Thread::current(), lookup, value, found, should_grow); - if (!_inserted_elem && inserted) { + if (!_inserted_card && inserted) { // It does not matter to us who is setting the flag so a regular atomic store // is sufficient. - Atomic::store(&_inserted_elem, true); + Atomic::store(&_inserted_card, true); } return found.value(); @@ -284,20 +278,20 @@ public: return found.value(); } - void iterate_safepoint(G1CardSet::G1CardSetPtrIterator* cl2) { + void iterate_safepoint(G1CardSet::ContainerPtrClosure* cl2) { G1CardSetHashTableScan cl(cl2); _table.do_safepoint_scan(cl); } - void iterate(G1CardSet::G1CardSetPtrIterator* cl2) { + void iterate(G1CardSet::ContainerPtrClosure* cl2) { G1CardSetHashTableScan cl(cl2); _table.do_scan(Thread::current(), cl); } void reset() { - if (Atomic::load(&_inserted_elem)) { - _table.unsafe_reset(InitialLogTableSize); - Atomic::store(&_inserted_elem, false); + if (Atomic::load(&_inserted_card)) { + _table.unsafe_reset(InitialLogTableSize); + Atomic::store(&_inserted_card, false); } } @@ -343,101 +337,93 @@ G1CardSet::~G1CardSet() { _mm->flush(); } -uint G1CardSet::card_set_type_to_mem_object_type(uintptr_t type) const { - assert(type == G1CardSet::CardSetArrayOfCards || - type == G1CardSet::CardSetBitMap || - type == G1CardSet::CardSetHowl, "should not allocate card set type %zu", type); +uint G1CardSet::container_type_to_mem_object_type(uintptr_t type) const { + assert(type == G1CardSet::ContainerArrayOfCards || + type == G1CardSet::ContainerBitMap || + type == G1CardSet::ContainerHowl, "should not allocate container type %zu", type); return (uint)type; } uint8_t* G1CardSet::allocate_mem_object(uintptr_t type) { - return _mm->allocate(card_set_type_to_mem_object_type(type)); + return _mm->allocate(container_type_to_mem_object_type(type)); } -void G1CardSet::free_mem_object(CardSetPtr card_set) { - assert(card_set != G1CardSet::FreeCardSet, "should not free Free card set"); - assert(card_set != G1CardSet::FullCardSet, "should not free Full card set"); +void G1CardSet::free_mem_object(ContainerPtr container) { + assert(container != G1CardSet::FreeCardSet, "should not free container FreeCardSet"); + assert(container != G1CardSet::FullCardSet, "should not free container FullCardSet"); - uintptr_t type = card_set_type(card_set); - void* value = strip_card_set_type(card_set); + uintptr_t type = container_type(container); + void* value = strip_container_type(container); - assert(type == G1CardSet::CardSetArrayOfCards || - type == G1CardSet::CardSetBitMap || - type == G1CardSet::CardSetHowl, "should not free card set type %zu", type); + assert(type == G1CardSet::ContainerArrayOfCards || + type == G1CardSet::ContainerBitMap || + type == G1CardSet::ContainerHowl, "should not free card set type %zu", type); + assert(static_cast(value)->refcount() == 1, "must be"); -#ifdef ASSERT - if (type == G1CardSet::CardSetArrayOfCards || - type == G1CardSet::CardSetBitMap || - type == G1CardSet::CardSetHowl) { - G1CardSetContainer* card_set = (G1CardSetContainer*)value; - assert((card_set->refcount() == 1), "must be"); - } -#endif - - _mm->free(card_set_type_to_mem_object_type(type), value); + _mm->free(container_type_to_mem_object_type(type), value); } -G1CardSet::CardSetPtr G1CardSet::acquire_card_set(CardSetPtr volatile* card_set_addr) { +G1CardSet::ContainerPtr G1CardSet::acquire_container(ContainerPtr volatile* container_addr) { // Update reference counts under RCU critical section to avoid a // use-after-cleapup bug where we increment a reference count for // an object whose memory has already been cleaned up and reused. GlobalCounter::CriticalSection cs(Thread::current()); while (true) { - // Get cardsetptr and increment refcount atomically wrt to memory reuse. - CardSetPtr card_set = Atomic::load_acquire(card_set_addr); - uint cs_type = card_set_type(card_set); - if (card_set == FullCardSet || cs_type == CardSetInlinePtr) { - return card_set; + // Get ContainerPtr and increment refcount atomically wrt to memory reuse. + ContainerPtr container = Atomic::load_acquire(container_addr); + uint cs_type = container_type(container); + if (container == FullCardSet || cs_type == ContainerInlinePtr) { + return container; } - G1CardSetContainer* card_set_on_heap = (G1CardSetContainer*)strip_card_set_type(card_set); + G1CardSetContainer* container_on_heap = (G1CardSetContainer*)strip_container_type(container); - if (card_set_on_heap->try_increment_refcount()) { - assert(card_set_on_heap->refcount() >= 3, "Smallest value is 3"); - return card_set; + if (container_on_heap->try_increment_refcount()) { + assert(container_on_heap->refcount() >= 3, "Smallest value is 3"); + return container; } } } -bool G1CardSet::release_card_set(CardSetPtr card_set) { - uint cs_type = card_set_type(card_set); - if (card_set == FullCardSet || cs_type == CardSetInlinePtr) { +bool G1CardSet::release_container(ContainerPtr container) { + uint cs_type = container_type(container); + if (container == FullCardSet || cs_type == ContainerInlinePtr) { return false; } - G1CardSetContainer* card_set_on_heap = (G1CardSetContainer*)strip_card_set_type(card_set); - return card_set_on_heap->decrement_refcount() == 1; + G1CardSetContainer* container_on_heap = (G1CardSetContainer*)strip_container_type(container); + return container_on_heap->decrement_refcount() == 1; } -void G1CardSet::release_and_maybe_free_card_set(CardSetPtr card_set) { - if (release_card_set(card_set)) { - free_mem_object(card_set); +void G1CardSet::release_and_maybe_free_container(ContainerPtr container) { + if (release_container(container)) { + free_mem_object(container); } } -void G1CardSet::release_and_must_free_card_set(CardSetPtr card_set) { - bool should_free = release_card_set(card_set); +void G1CardSet::release_and_must_free_container(ContainerPtr container) { + bool should_free = release_container(container); assert(should_free, "should have been the only one having a reference"); - free_mem_object(card_set); + free_mem_object(container); } class G1ReleaseCardsets : public StackObj { G1CardSet* _card_set; - using CardSetPtr = G1CardSet::CardSetPtr; + using ContainerPtr = G1CardSet::ContainerPtr; - void coarsen_to_full(CardSetPtr* card_set_addr) { + void coarsen_to_full(ContainerPtr* container_addr) { while (true) { - CardSetPtr cur_card_set = Atomic::load_acquire(card_set_addr); - uint cs_type = G1CardSet::card_set_type(cur_card_set); - if (cur_card_set == G1CardSet::FullCardSet) { + ContainerPtr cur_container = Atomic::load_acquire(container_addr); + uint cs_type = G1CardSet::container_type(cur_container); + if (cur_container == G1CardSet::FullCardSet) { return; } - CardSetPtr old_value = Atomic::cmpxchg(card_set_addr, cur_card_set, G1CardSet::FullCardSet); + ContainerPtr old_value = Atomic::cmpxchg(container_addr, cur_container, G1CardSet::FullCardSet); - if (old_value == cur_card_set) { - _card_set->release_and_maybe_free_card_set(cur_card_set); + if (old_value == cur_container) { + _card_set->release_and_maybe_free_container(cur_container); return; } } @@ -446,51 +432,51 @@ class G1ReleaseCardsets : public StackObj { public: explicit G1ReleaseCardsets(G1CardSet* card_set) : _card_set(card_set) { } - void operator ()(CardSetPtr* card_set_addr) { - coarsen_to_full(card_set_addr); + void operator ()(ContainerPtr* container_addr) { + coarsen_to_full(container_addr); } }; -G1AddCardResult G1CardSet::add_to_array(CardSetPtr card_set, uint card_in_region) { - G1CardSetArray* array = card_set_ptr(card_set); +G1AddCardResult G1CardSet::add_to_array(ContainerPtr container, uint card_in_region) { + G1CardSetArray* array = container_ptr(container); return array->add(card_in_region); } -G1AddCardResult G1CardSet::add_to_howl(CardSetPtr parent_card_set, - uint card_region, - uint card_in_region, - bool increment_total) { - G1CardSetHowl* howl = card_set_ptr(parent_card_set); +G1AddCardResult G1CardSet::add_to_howl(ContainerPtr parent_container, + uint card_region, + uint card_in_region, + bool increment_total) { + G1CardSetHowl* howl = container_ptr(parent_container); G1AddCardResult add_result; - CardSetPtr to_transfer = nullptr; - CardSetPtr card_set; + ContainerPtr to_transfer = nullptr; + ContainerPtr container; uint bucket = _config->howl_bucket_index(card_in_region); - volatile CardSetPtr* bucket_entry = howl->get_card_set_addr(bucket); + ContainerPtr volatile* bucket_entry = howl->get_container_addr(bucket); while (true) { if (Atomic::load(&howl->_num_entries) >= _config->cards_in_howl_threshold()) { return Overflow; } - card_set = acquire_card_set(bucket_entry); - add_result = add_to_card_set(bucket_entry, card_set, card_region, card_in_region); + container = acquire_container(bucket_entry); + add_result = add_to_container(bucket_entry, container, card_region, card_in_region); if (add_result != Overflow) { break; } - // Card set has overflown. Coarsen or retry. - bool coarsened = coarsen_card_set(bucket_entry, card_set, card_in_region, true /* within_howl */); - _coarsen_stats.record_coarsening(card_set_type(card_set) + G1CardSetCoarsenStats::CoarsenHowlOffset, !coarsened); + // Card set container has overflown. Coarsen or retry. + bool coarsened = coarsen_container(bucket_entry, container, card_in_region, true /* within_howl */); + _coarsen_stats.record_coarsening(container_type(container) + G1CardSetCoarsenStats::CoarsenHowlOffset, !coarsened); if (coarsened) { - // We have been the one coarsening this card set (and in the process added that card). + // We successful coarsened this card set container (and in the process added the card). add_result = Added; - to_transfer = card_set; + to_transfer = container; break; } // Somebody else beat us to coarsening. Retry. - release_and_maybe_free_card_set(card_set); + release_and_maybe_free_container(container); } if (increment_total && add_result == Added) { @@ -498,91 +484,91 @@ G1AddCardResult G1CardSet::add_to_howl(CardSetPtr parent_card_set, } if (to_transfer != nullptr) { - transfer_cards_in_howl(parent_card_set, to_transfer, card_region); + transfer_cards_in_howl(parent_container, to_transfer, card_region); } - release_and_maybe_free_card_set(card_set); + release_and_maybe_free_container(container); return add_result; } -G1AddCardResult G1CardSet::add_to_bitmap(CardSetPtr card_set, uint card_in_region) { - G1CardSetBitMap* bitmap = card_set_ptr(card_set); +G1AddCardResult G1CardSet::add_to_bitmap(ContainerPtr container, uint card_in_region) { + G1CardSetBitMap* bitmap = container_ptr(container); uint card_offset = _config->howl_bitmap_offset(card_in_region); - return bitmap->add(card_offset, _config->cards_in_howl_bitmap_threshold(), _config->num_cards_in_howl_bitmap()); + return bitmap->add(card_offset, _config->cards_in_howl_bitmap_threshold(), _config->max_cards_in_howl_bitmap()); } -G1AddCardResult G1CardSet::add_to_inline_ptr(CardSetPtr volatile* card_set_addr, CardSetPtr card_set, uint card_in_region) { - G1CardSetInlinePtr value(card_set_addr, card_set); - return value.add(card_in_region, _config->inline_ptr_bits_per_card(), _config->num_cards_in_inline_ptr()); +G1AddCardResult G1CardSet::add_to_inline_ptr(ContainerPtr volatile* container_addr, ContainerPtr container, uint card_in_region) { + G1CardSetInlinePtr value(container_addr, container); + return value.add(card_in_region, _config->inline_ptr_bits_per_card(), _config->max_cards_in_inline_ptr()); } -G1CardSet::CardSetPtr G1CardSet::create_coarsened_array_of_cards(uint card_in_region, bool within_howl) { +G1CardSet::ContainerPtr G1CardSet::create_coarsened_array_of_cards(uint card_in_region, bool within_howl) { uint8_t* data = nullptr; - CardSetPtr new_card_set; + ContainerPtr new_container; if (within_howl) { - uint const size_in_bits = _config->num_cards_in_howl_bitmap(); - uint card_offset = _config->howl_bitmap_offset(card_in_region); - data = allocate_mem_object(CardSetBitMap); - new (data) G1CardSetBitMap(card_offset, size_in_bits); - new_card_set = make_card_set_ptr(data, CardSetBitMap); + uint const size_in_bits = _config->max_cards_in_howl_bitmap(); + uint container_offset = _config->howl_bitmap_offset(card_in_region); + data = allocate_mem_object(ContainerBitMap); + new (data) G1CardSetBitMap(container_offset, size_in_bits); + new_container = make_container_ptr(data, ContainerBitMap); } else { - data = allocate_mem_object(CardSetHowl); + data = allocate_mem_object(ContainerHowl); new (data) G1CardSetHowl(card_in_region, _config); - new_card_set = make_card_set_ptr(data, CardSetHowl); + new_container = make_container_ptr(data, ContainerHowl); } - return new_card_set; + return new_container; } -bool G1CardSet::coarsen_card_set(volatile CardSetPtr* card_set_addr, - CardSetPtr cur_card_set, - uint card_in_region, - bool within_howl) { - CardSetPtr new_card_set = nullptr; +bool G1CardSet::coarsen_container(ContainerPtr volatile* container_addr, + ContainerPtr cur_container, + uint card_in_region, + bool within_howl) { + ContainerPtr new_container = nullptr; - switch (card_set_type(cur_card_set)) { - case CardSetArrayOfCards : { - new_card_set = create_coarsened_array_of_cards(card_in_region, within_howl); + switch (container_type(cur_container)) { + case ContainerArrayOfCards: { + new_container = create_coarsened_array_of_cards(card_in_region, within_howl); break; } - case CardSetBitMap: { - new_card_set = FullCardSet; + case ContainerBitMap: { + new_container = FullCardSet; break; } - case CardSetInlinePtr: { - uint const size = _config->num_cards_in_array(); - uint8_t* data = allocate_mem_object(CardSetArrayOfCards); + case ContainerInlinePtr: { + uint const size = _config->max_cards_in_array(); + uint8_t* data = allocate_mem_object(ContainerArrayOfCards); new (data) G1CardSetArray(card_in_region, size); - new_card_set = make_card_set_ptr(data, CardSetArrayOfCards); + new_container = make_container_ptr(data, ContainerArrayOfCards); break; } - case CardSetHowl: { - new_card_set = FullCardSet; // anything will do at this point. + case ContainerHowl: { + new_container = FullCardSet; // anything will do at this point. break; } default: ShouldNotReachHere(); } - CardSetPtr old_value = Atomic::cmpxchg(card_set_addr, cur_card_set, new_card_set); // Memory order? - if (old_value == cur_card_set) { + ContainerPtr old_value = Atomic::cmpxchg(container_addr, cur_container, new_container); // Memory order? + if (old_value == cur_container) { // Success. Indicate that the cards from the current card set must be transferred // by this caller. // Release the hash table reference to the card. The caller still holds the // reference to this card set, so it can never be released (and we do not need to // check its result). - bool should_free = release_card_set(cur_card_set); + bool should_free = release_container(cur_container); assert(!should_free, "must have had more than one reference"); - // Free containers if cur_card_set is CardSetHowl - if (card_set_type(cur_card_set) == CardSetHowl) { + // Free containers if cur_container is ContainerHowl + if (container_type(cur_container) == ContainerHowl) { G1ReleaseCardsets rel(this); - card_set_ptr(cur_card_set)->iterate(rel, _config->num_buckets_in_howl()); + container_ptr(cur_container)->iterate(rel, _config->num_buckets_in_howl()); } return true; } else { // Somebody else beat us to coarsening that card set. Exit, but clean up first. - if (new_card_set != FullCardSet) { - assert(new_card_set != nullptr, "must not be"); - release_and_must_free_card_set(new_card_set); + if (new_container != FullCardSet) { + assert(new_container != nullptr, "must not be"); + release_and_must_free_container(new_container); } return false; } @@ -599,46 +585,46 @@ public: } }; -void G1CardSet::transfer_cards(G1CardSetHashTableValue* table_entry, CardSetPtr source_card_set, uint card_region) { - assert(source_card_set != FullCardSet, "Should not need to transfer from full"); - // Need to transfer old entries unless there is a Full card set in place now, i.e. - // the old type has been CardSetBitMap. "Full" contains all elements anyway. - if (card_set_type(source_card_set) != CardSetHowl) { +void G1CardSet::transfer_cards(G1CardSetHashTableValue* table_entry, ContainerPtr source_container, uint card_region) { + assert(source_container != FullCardSet, "Should not need to transfer from FullCardSet"); + // Need to transfer old entries unless there is a Full card set container in place now, i.e. + // the old type has been ContainerBitMap. "Full" contains all elements anyway. + if (container_type(source_container) != ContainerHowl) { G1TransferCard iter(this, card_region); - iterate_cards_during_transfer(source_card_set, iter); + iterate_cards_during_transfer(source_container, iter); } else { - assert(card_set_type(source_card_set) == CardSetHowl, "must be"); + assert(container_type(source_container) == ContainerHowl, "must be"); // Need to correct for that the Full remembered set occupies more cards than the // AoCS before. Atomic::add(&_num_occupied, _config->max_cards_in_region() - table_entry->_num_occupied, memory_order_relaxed); } } -void G1CardSet::transfer_cards_in_howl(CardSetPtr parent_card_set, - CardSetPtr source_card_set, - uint card_region) { - assert(card_set_type(parent_card_set) == CardSetHowl, "must be"); - assert(source_card_set != FullCardSet, "Should not need to transfer from full"); +void G1CardSet::transfer_cards_in_howl(ContainerPtr parent_container, + ContainerPtr source_container, + uint card_region) { + assert(container_type(parent_container) == ContainerHowl, "must be"); + assert(source_container != FullCardSet, "Should not need to transfer from full"); // Need to transfer old entries unless there is a Full card set in place now, i.e. - // the old type has been CardSetBitMap. - if (card_set_type(source_card_set) != CardSetBitMap) { - // We only need to transfer from anything below CardSetBitMap. + // the old type has been ContainerBitMap. + if (container_type(source_container) != ContainerBitMap) { + // We only need to transfer from anything below ContainerBitMap. G1TransferCard iter(this, card_region); - iterate_cards_during_transfer(source_card_set, iter); + iterate_cards_during_transfer(source_container, iter); } else { - uint diff = _config->num_cards_in_howl_bitmap() - card_set_ptr(source_card_set)->num_bits_set(); + uint diff = _config->max_cards_in_howl_bitmap() - container_ptr(source_container)->num_bits_set(); // Need to correct for that the Full remembered set occupies more cards than the // bitmap before. - // We add 1 element less because the values will be incremented + // We add 1 card less because the values will be incremented // in G1CardSet::add_card for the current addition or where already incremented in // G1CardSet::add_to_howl after coarsening. diff -= 1; - G1CardSetHowl* howling_array = card_set_ptr(parent_card_set); + G1CardSetHowl* howling_array = container_ptr(parent_container); Atomic::add(&howling_array->_num_entries, diff, memory_order_relaxed); - G1CardSetHashTableValue* table_entry = get_card_set(card_region); + G1CardSetHashTableValue* table_entry = get_container(card_region); assert(table_entry != nullptr, "Table entry not found for transferred cards"); Atomic::add(&table_entry->_num_occupied, diff, memory_order_relaxed); @@ -647,72 +633,75 @@ void G1CardSet::transfer_cards_in_howl(CardSetPtr parent_card_set, } } -G1AddCardResult G1CardSet::add_to_card_set(volatile CardSetPtr* card_set_addr, CardSetPtr card_set, uint card_region, uint card_in_region, bool increment_total) { - assert(card_set_addr != nullptr, "Cannot add to empty cardset"); +G1AddCardResult G1CardSet::add_to_container(ContainerPtr volatile* container_addr, + ContainerPtr container, + uint card_region, + uint card_in_region, + bool increment_total) { + assert(container_addr != nullptr, "must be"); G1AddCardResult add_result; - switch (card_set_type(card_set)) { - case CardSetInlinePtr: { - add_result = add_to_inline_ptr(card_set_addr, card_set, card_in_region); + switch (container_type(container)) { + case ContainerInlinePtr: { + add_result = add_to_inline_ptr(container_addr, container, card_in_region); break; } - case CardSetArrayOfCards : { - add_result = add_to_array(card_set, card_in_region); + case ContainerArrayOfCards: { + add_result = add_to_array(container, card_in_region); break; } - case CardSetBitMap: { - add_result = add_to_bitmap(card_set, card_in_region); + case ContainerBitMap: { + add_result = add_to_bitmap(container, card_in_region); break; } - case CardSetHowl: { - assert(CardSetHowl == card_set_type(FullCardSet), "must be"); - if (card_set == FullCardSet) { + case ContainerHowl: { + assert(ContainerHowl == container_type(FullCardSet), "must be"); + if (container == FullCardSet) { return Found; } - add_result = add_to_howl(card_set, card_region, card_in_region, increment_total); + add_result = add_to_howl(container, card_region, card_in_region, increment_total); break; } default: ShouldNotReachHere(); } - return add_result; } -G1CardSetHashTableValue* G1CardSet::get_or_add_card_set(uint card_region, bool* should_grow_table) { +G1CardSetHashTableValue* G1CardSet::get_or_add_container(uint card_region, bool* should_grow_table) { return _table->get_or_add(card_region, should_grow_table); } -G1CardSetHashTableValue* G1CardSet::get_card_set(uint card_region) { +G1CardSetHashTableValue* G1CardSet::get_container(uint card_region) { return _table->get(card_region); } G1AddCardResult G1CardSet::add_card(uint card_region, uint card_in_region, bool increment_total) { G1AddCardResult add_result; - CardSetPtr to_transfer = nullptr; - CardSetPtr card_set; + ContainerPtr to_transfer = nullptr; + ContainerPtr container; bool should_grow_table = false; - G1CardSetHashTableValue* table_entry = get_or_add_card_set(card_region, &should_grow_table); + G1CardSetHashTableValue* table_entry = get_or_add_container(card_region, &should_grow_table); while (true) { - card_set = acquire_card_set(&table_entry->_card_set); - add_result = add_to_card_set(&table_entry->_card_set, card_set, card_region, card_in_region, increment_total); + container = acquire_container(&table_entry->_container); + add_result = add_to_container(&table_entry->_container, container, card_region, card_in_region, increment_total); if (add_result != Overflow) { break; } // Card set has overflown. Coarsen or retry. - bool coarsened = coarsen_card_set(&table_entry->_card_set, card_set, card_in_region); - _coarsen_stats.record_coarsening(card_set_type(card_set), !coarsened); + bool coarsened = coarsen_container(&table_entry->_container, container, card_in_region); + _coarsen_stats.record_coarsening(container_type(container), !coarsened); if (coarsened) { - // We have been the one coarsening this card set (and in the process added that card). + // We successful coarsened this card set container (and in the process added the card). add_result = Added; - to_transfer = card_set; + to_transfer = container; break; } // Somebody else beat us to coarsening. Retry. - release_and_maybe_free_card_set(card_set); + release_and_maybe_free_container(container); } if (increment_total && add_result == Added) { @@ -726,7 +715,7 @@ G1AddCardResult G1CardSet::add_card(uint card_region, uint card_in_region, bool transfer_cards(table_entry, to_transfer, card_region); } - release_and_maybe_free_card_set(card_set); + release_and_maybe_free_container(container); return add_result; } @@ -735,29 +724,29 @@ bool G1CardSet::contains_card(uint card_region, uint card_in_region) { assert(card_in_region < _config->max_cards_in_region(), "Card %u is beyond max %u", card_in_region, _config->max_cards_in_region()); - // Protect the card set from reclamation. + // Protect the card set container from reclamation. GlobalCounter::CriticalSection cs(Thread::current()); - G1CardSetHashTableValue* table_entry = get_card_set(card_region); + G1CardSetHashTableValue* table_entry = get_container(card_region); if (table_entry == nullptr) { return false; } - CardSetPtr card_set = table_entry->_card_set; - if (card_set == FullCardSet) { + ContainerPtr container = table_entry->_container; + if (container == FullCardSet) { // contains_card() is not a performance critical method so we do not hide that // case in the switch below. return true; } - switch (card_set_type(card_set)) { - case CardSetInlinePtr: { - G1CardSetInlinePtr ptr(card_set); + switch (container_type(container)) { + case ContainerInlinePtr: { + G1CardSetInlinePtr ptr(container); return ptr.contains(card_in_region, _config->inline_ptr_bits_per_card()); } - case CardSetArrayOfCards : return card_set_ptr(card_set)->contains(card_in_region); - case CardSetBitMap: return card_set_ptr(card_set)->contains(card_in_region, _config->num_cards_in_howl_bitmap()); - case CardSetHowl: { - G1CardSetHowl* howling_array = card_set_ptr(card_set); + case ContainerArrayOfCards: return container_ptr(container)->contains(card_in_region); + case ContainerBitMap: return container_ptr(container)->contains(card_in_region, _config->max_cards_in_howl_bitmap()); + case ContainerHowl: { + G1CardSetHowl* howling_array = container_ptr(container); return howling_array->contains(card_in_region, _config); } @@ -767,53 +756,53 @@ bool G1CardSet::contains_card(uint card_region, uint card_in_region) { } void G1CardSet::print_info(outputStream* st, uint card_region, uint card_in_region) { - G1CardSetHashTableValue* table_entry = get_card_set(card_region); + G1CardSetHashTableValue* table_entry = get_container(card_region); if (table_entry == nullptr) { st->print("NULL card set"); return; } - CardSetPtr card_set = table_entry->_card_set; - if (card_set == FullCardSet) { + ContainerPtr container = table_entry->_container; + if (container == FullCardSet) { st->print("FULL card set)"); return; } - switch (card_set_type(card_set)) { - case CardSetInlinePtr: { + switch (container_type(container)) { + case ContainerInlinePtr: { st->print("InlinePtr not containing %u", card_in_region); break; } - case CardSetArrayOfCards : { + case ContainerArrayOfCards: { st->print("AoC not containing %u", card_in_region); break; } - case CardSetBitMap: { + case ContainerBitMap: { st->print("BitMap not containing %u", card_in_region); break; } - case CardSetHowl: { - st->print("CardSetHowl not containing %u", card_in_region); + case ContainerHowl: { + st->print("ContainerHowl not containing %u", card_in_region); break; } - default: st->print("Unknown card set type %u", card_set_type(card_set)); ShouldNotReachHere(); break; + default: st->print("Unknown card set container type %u", container_type(container)); ShouldNotReachHere(); break; } } template -void G1CardSet::iterate_cards_during_transfer(CardSetPtr const card_set, CardVisitor& found) { - uint type = card_set_type(card_set); - assert(type == CardSetInlinePtr || type == CardSetArrayOfCards, +void G1CardSet::iterate_cards_during_transfer(ContainerPtr const container, CardVisitor& cl) { + uint type = container_type(container); + assert(type == ContainerInlinePtr || type == ContainerArrayOfCards, "invalid card set type %d to transfer from", - card_set_type(card_set)); + container_type(container)); switch (type) { - case CardSetInlinePtr: { - G1CardSetInlinePtr ptr(card_set); - ptr.iterate(found, _config->inline_ptr_bits_per_card()); + case ContainerInlinePtr: { + G1CardSetInlinePtr ptr(container); + ptr.iterate(cl, _config->inline_ptr_bits_per_card()); return; } - case CardSetArrayOfCards : { - card_set_ptr(card_set)->iterate(found); + case ContainerArrayOfCards: { + container_ptr(container)->iterate(cl); return; } default: @@ -821,56 +810,57 @@ void G1CardSet::iterate_cards_during_transfer(CardSetPtr const card_set, CardVis } } -void G1CardSet::iterate_containers(G1CardSetPtrIterator* found, bool at_safepoint) { +void G1CardSet::iterate_containers(ContainerPtrClosure* cl, bool at_safepoint) { if (at_safepoint) { - _table->iterate_safepoint(found); + _table->iterate_safepoint(cl); } else { - _table->iterate(found); + _table->iterate(cl); } } +// Applied to all card (ranges) of the containers. template -class G1ContainerCards { - Closure& _iter; +class G1ContainerCardsClosure { + Closure& _cl; uint _region_idx; public: - G1ContainerCards(Closure& iter, uint region_idx) : _iter(iter), _region_idx(region_idx) { } + G1ContainerCardsClosure(Closure& cl, uint region_idx) : _cl(cl), _region_idx(region_idx) { } bool start_iterate(uint tag) { return true; } void operator()(uint card_idx) { - _iter.do_card(_region_idx, card_idx); + _cl.do_card(_region_idx, card_idx); } void operator()(uint card_idx, uint length) { for (uint i = 0; i < length; i++) { - _iter.do_card(_region_idx, card_idx); + _cl.do_card(_region_idx, card_idx); } } }; template class CardOrRanges> -class G1CardSetIterateCardsIterator : public G1CardSet::G1CardSetPtrIterator { +class G1CardSetContainersClosure : public G1CardSet::ContainerPtrClosure { G1CardSet* _card_set; - Closure& _iter; + Closure& _cl; public: - G1CardSetIterateCardsIterator(G1CardSet* card_set, - Closure& iter) : + G1CardSetContainersClosure(G1CardSet* card_set, + Closure& cl) : _card_set(card_set), - _iter(iter) { } + _cl(cl) { } - void do_cardsetptr(uint region_idx, size_t num_occupied, G1CardSet::CardSetPtr card_set) override { - CardOrRanges cl(_iter, region_idx); - _card_set->iterate_cards_or_ranges_in_container(card_set, cl); + void do_containerptr(uint region_idx, size_t num_occupied, G1CardSet::ContainerPtr container) override { + CardOrRanges cl(_cl, region_idx); + _card_set->iterate_cards_or_ranges_in_container(container, cl); } }; -void G1CardSet::iterate_cards(G1CardSetCardIterator& iter) { - G1CardSetIterateCardsIterator cl(this, iter); - iterate_containers(&cl); +void G1CardSet::iterate_cards(CardClosure& cl) { + G1CardSetContainersClosure cl2(this, cl); + iterate_containers(&cl2); } bool G1CardSet::occupancy_less_or_equal_to(size_t limit) const { @@ -886,13 +876,13 @@ size_t G1CardSet::occupied() const { } size_t G1CardSet::num_containers() { - class GetNumberOfContainers : public G1CardSetPtrIterator { + class GetNumberOfContainers : public ContainerPtrClosure { public: size_t _count; - GetNumberOfContainers() : G1CardSetPtrIterator(), _count(0) { } + GetNumberOfContainers() : ContainerPtrClosure(), _count(0) { } - void do_cardsetptr(uint region_idx, size_t num_occupied, CardSetPtr card_set) override { + void do_containerptr(uint region_idx, size_t num_occupied, ContainerPtr container) override { _count++; } } cl; diff --git a/src/hotspot/share/gc/g1/g1CardSet.hpp b/src/hotspot/share/gc/g1/g1CardSet.hpp index 937bc99a919d6e85cb7caa3c01ebda455bc823f7..946d8cb73382b954ecf23d23124c909edc3e477f 100644 --- a/src/hotspot/share/gc/g1/g1CardSet.hpp +++ b/src/hotspot/share/gc/g1/g1CardSet.hpp @@ -26,10 +26,7 @@ #define SHARE_GC_G1_G1CARDSET_HPP #include "memory/allocation.hpp" -#include "memory/padded.hpp" -#include "oops/oopsHierarchy.hpp" #include "utilities/concurrentHashTable.hpp" -#include "utilities/lockFreeStack.hpp" class G1CardSetAllocOptions; class G1CardSetHashTable; @@ -50,26 +47,26 @@ class G1CardSetConfiguration { // regions covered by this card set. uint _inline_ptr_bits_per_card; - uint _num_cards_in_array; + uint _max_cards_in_array; uint _num_buckets_in_howl; uint _max_cards_in_card_set; uint _cards_in_howl_threshold; - uint _num_cards_in_howl_bitmap; + uint _max_cards_in_howl_bitmap; uint _cards_in_howl_bitmap_threshold; - uint _log2_num_cards_in_howl_bitmap; + uint _log2_max_cards_in_howl_bitmap; size_t _bitmap_hash_mask; - uint _log2_card_region_per_heap_region; + uint _log2_card_regions_per_heap_region; uint _log2_cards_per_card_region; G1CardSetAllocOptions* _card_set_alloc_options; G1CardSetConfiguration(uint inline_ptr_bits_per_card, - uint num_cards_in_array, + uint max_cards_in_array, double cards_in_bitmap_threshold_percent, uint num_buckets_in_howl, double cards_in_howl_threshold_percent, uint max_cards_in_card_set, - uint log2_card_region_per_heap_region); + uint log2_card_regions_per_heap_region); void init_card_set_alloc_options(); void log_configuration(); @@ -79,7 +76,7 @@ public: G1CardSetConfiguration(); // Initialize card set configuration from parameters. // Testing only. - G1CardSetConfiguration(uint num_cards_in_array, + G1CardSetConfiguration(uint max_cards_in_array, double cards_in_bitmap_threshold_percent, uint max_buckets_in_howl, double cards_in_howl_threshold_percent, @@ -90,21 +87,19 @@ public: // Inline pointer configuration uint inline_ptr_bits_per_card() const { return _inline_ptr_bits_per_card; } - uint num_cards_in_inline_ptr() const; - static uint num_cards_in_inline_ptr(uint bits_per_card); + uint max_cards_in_inline_ptr() const; + static uint max_cards_in_inline_ptr(uint bits_per_card); // Array of Cards configuration - bool use_cards_in_array() const { return _num_cards_in_array != 0; } // Unused for now - // Number of cards in "Array of Cards" set; 0 to disable. + // Maximum number of cards in "Array of Cards" set; 0 to disable. // Always coarsen to next level if full, so no specific threshold. - uint num_cards_in_array() const { return _num_cards_in_array; } + uint max_cards_in_array() const { return _max_cards_in_array; } // Bitmap within Howl card set container configuration - bool use_cards_in_howl_bitmap() const { return _num_cards_in_howl_bitmap != 0; } // Unused for now - uint num_cards_in_howl_bitmap() const { return _num_cards_in_howl_bitmap; } + uint max_cards_in_howl_bitmap() const { return _max_cards_in_howl_bitmap; } // (Approximate) Number of cards in bitmap to coarsen Howl Bitmap to Howl Full. uint cards_in_howl_bitmap_threshold() const { return _cards_in_howl_bitmap_threshold; } - uint log2_num_cards_in_howl_bitmap() const {return _log2_num_cards_in_howl_bitmap;} + uint log2_max_cards_in_howl_bitmap() const {return _log2_max_cards_in_howl_bitmap;} // Howl card set container configuration uint num_buckets_in_howl() const { return _num_buckets_in_howl; } @@ -112,7 +107,7 @@ public: uint cards_in_howl_threshold() const { return _cards_in_howl_threshold; } uint howl_bitmap_offset(uint card_idx) const { return card_idx & _bitmap_hash_mask; } // Given a card index, return the bucket in the array of card sets. - uint howl_bucket_index(uint card_idx) { return card_idx >> _log2_num_cards_in_howl_bitmap; } + uint howl_bucket_index(uint card_idx) { return card_idx >> _log2_max_cards_in_howl_bitmap; } // Full card configuration // Maximum number of cards in a non-full card set for a single region. Card sets @@ -127,8 +122,8 @@ public: // The next two members give information about how many card regions are there // per area (heap region) and how many cards each card region has. - // The log2 of the amount of card regions per heap region configured. - uint log2_card_region_per_heap_region() const { return _log2_card_region_per_heap_region; } + // The log2 of the number of card regions per heap region configured. + uint log2_card_regions_per_heap_region() const { return _log2_card_regions_per_heap_region; } // The log2 of the number of cards per card region. This is calculated from max_cards_in_region() // and above. uint log2_cards_per_card_region() const { return _log2_cards_per_card_region; } @@ -149,10 +144,10 @@ public: class G1CardSetCoarsenStats { public: // Number of entries in the statistics tables: since we index with the source - // cardset of the coarsening, this is the total number of combinations of - // card sets - 1. + // container of the coarsening, this is the total number of combinations of + // card set containers - 1. static constexpr size_t NumCoarsenCategories = 7; - // Coarsening statistics for the possible CardSetPtr in the Howl card set + // Coarsening statistics for the possible ContainerPtr in the Howl card set // start from this offset. static constexpr size_t CoarsenHowlOffset = 4; @@ -175,14 +170,14 @@ public: void print_on(outputStream* out); }; -// Sparse set of card indexes comprising a remembered set on the Java heap. Card +// Set of card indexes comprising a remembered set on the Java heap. Card // size is assumed to be card table card size. // // Technically it is implemented using a ConcurrentHashTable that stores a card // set container for every region containing at least one card. // // There are in total five different containers, encoded in the ConcurrentHashTable -// node as CardSetPtr. A CardSetPtr may cover the whole region or just a part of +// node as ContainerPtr. A ContainerPtr may cover the whole region or just a part of // it. // See its description below for more information. class G1CardSet : public CHeapObj { @@ -196,46 +191,46 @@ class G1CardSet : public CHeapObj { static G1CardSetCoarsenStats _coarsen_stats; // Coarsening statistics since VM start. static G1CardSetCoarsenStats _last_coarsen_stats; // Coarsening statistics at last GC. public: - // Two lower bits are used to encode the card storage types - static const uintptr_t CardSetPtrHeaderSize = 2; + // Two lower bits are used to encode the card set container types + static const uintptr_t ContainerPtrHeaderSize = 2; - // CardSetPtr represents the card storage type of a given covered area. It encodes - // a type in the LSBs, in addition to having a few significant values. + // ContainerPtr represents the card set container type of a given covered area. + // It encodes a type in the LSBs, in addition to having a few significant values. // // Possible encodings: // // 0...00000 free (Empty, should never happen) - // 1...11111 full All card indexes in the whole area this CardSetPtr covers are part of this container. - // X...XXX00 inline-ptr-cards A handful of card indexes covered by this CardSetPtr are encoded within the CardSetPtr. + // 1...11111 full All card indexes in the whole area this ContainerPtr covers are part of this container. + // X...XXX00 inline-ptr-cards A handful of card indexes covered by this ContainerPtr are encoded within the ContainerPtr. // X...XXX01 array of cards The container is a contiguous array of card indexes. // X...XXX10 bitmap The container uses a bitmap to determine whether a given index is part of this set. - // X...XXX11 howl This is a card set container containing an array of CardSetPtr, with each CardSetPtr + // X...XXX11 howl This is a card set container containing an array of ContainerPtr, with each ContainerPtr // limited to a sub-range of the original range. Currently only one level of this // container is supported. - typedef void* CardSetPtr; + using ContainerPtr = void*; // Coarsening happens in the order below: - // CardSetInlinePtr -> CardSetArrayOfCards -> CardSetHowl -> Full - // Corsening of containers inside the CardSetHowl happens in the order: - // CardSetInlinePtr -> CardSetArrayOfCards -> CardSetBitMap -> Full - static const uintptr_t CardSetInlinePtr = 0x0; - static const uintptr_t CardSetArrayOfCards = 0x1; - static const uintptr_t CardSetBitMap = 0x2; - static const uintptr_t CardSetHowl = 0x3; + // ContainerInlinePtr -> ContainerArrayOfCards -> ContainerHowl -> Full + // Corsening of containers inside the ContainerHowl happens in the order: + // ContainerInlinePtr -> ContainerArrayOfCards -> ContainerBitMap -> Full + static const uintptr_t ContainerInlinePtr = 0x0; + static const uintptr_t ContainerArrayOfCards = 0x1; + static const uintptr_t ContainerBitMap = 0x2; + static const uintptr_t ContainerHowl = 0x3; // The special sentinel values - static constexpr CardSetPtr FreeCardSet = nullptr; - // Unfortunately we can't make (G1CardSet::CardSetPtr)-1 constexpr because + static constexpr ContainerPtr FreeCardSet = nullptr; + // Unfortunately we can't make (G1CardSet::ContainerPtr)-1 constexpr because // reinterpret_casts are forbidden in constexprs. Use a regular static instead. - static CardSetPtr FullCardSet; + static ContainerPtr FullCardSet; - static const uintptr_t CardSetPtrTypeMask = ((uintptr_t)1 << CardSetPtrHeaderSize) - 1; + static const uintptr_t ContainerPtrTypeMask = ((uintptr_t)1 << ContainerPtrHeaderSize) - 1; - static CardSetPtr strip_card_set_type(CardSetPtr ptr) { return (CardSetPtr)((uintptr_t)ptr & ~CardSetPtrTypeMask); } + static ContainerPtr strip_container_type(ContainerPtr ptr) { return (ContainerPtr)((uintptr_t)ptr & ~ContainerPtrTypeMask); } - static uint card_set_type(CardSetPtr ptr) { return (uintptr_t)ptr & CardSetPtrTypeMask; } + static uint container_type(ContainerPtr ptr) { return (uintptr_t)ptr & ContainerPtrTypeMask; } template - static T* card_set_ptr(CardSetPtr ptr); + static T* container_ptr(ContainerPtr ptr); private: G1CardSetMemoryManager* _mm; @@ -247,42 +242,42 @@ private: // be (slightly) more cards in the card set than this value in reality. size_t _num_occupied; - CardSetPtr make_card_set_ptr(void* value, uintptr_t type); + ContainerPtr make_container_ptr(void* value, uintptr_t type); - CardSetPtr acquire_card_set(CardSetPtr volatile* card_set_addr); - // Returns true if the card set should be released - bool release_card_set(CardSetPtr card_set); + ContainerPtr acquire_container(ContainerPtr volatile* container_addr); + // Returns true if the card set container should be released + bool release_container(ContainerPtr container); // Release card set and free if needed. - void release_and_maybe_free_card_set(CardSetPtr card_set); + void release_and_maybe_free_container(ContainerPtr container); // Release card set and free (and it must be freeable). - void release_and_must_free_card_set(CardSetPtr card_set); + void release_and_must_free_container(ContainerPtr container); - // Coarsens the CardSet cur_card_set to the next level; tries to replace the - // previous CardSet with a new one which includes the given card_in_region. - // coarsen_card_set does not transfer cards from cur_card_set - // to the new card_set. Transfer is achieved by transfer_cards. - // Returns true if this was the thread that coarsened the CardSet (and added the card). - bool coarsen_card_set(CardSetPtr volatile* card_set_addr, - CardSetPtr cur_card_set, - uint card_in_region, bool within_howl = false); + // Coarsens the card set container cur_container to the next level; tries to replace the + // previous ContainerPtr with a new one which includes the given card_in_region. + // coarsen_container does not transfer cards from cur_container + // to the new container. Transfer is achieved by transfer_cards. + // Returns true if this was the thread that coarsened the container (and added the card). + bool coarsen_container(ContainerPtr volatile* container_addr, + ContainerPtr cur_container, + uint card_in_region, bool within_howl = false); - CardSetPtr create_coarsened_array_of_cards(uint card_in_region, bool within_howl); + ContainerPtr create_coarsened_array_of_cards(uint card_in_region, bool within_howl); // Transfer entries from source_card_set to a recently installed coarser storage type - // We only need to transfer anything finer than CardSetBitMap. "Full" contains + // We only need to transfer anything finer than ContainerBitMap. "Full" contains // all elements anyway. - void transfer_cards(G1CardSetHashTableValue* table_entry, CardSetPtr source_card_set, uint card_region); - void transfer_cards_in_howl(CardSetPtr parent_card_set, CardSetPtr source_card_set, uint card_region); + void transfer_cards(G1CardSetHashTableValue* table_entry, ContainerPtr source_container, uint card_region); + void transfer_cards_in_howl(ContainerPtr parent_container, ContainerPtr source_container, uint card_region); - G1AddCardResult add_to_card_set(CardSetPtr volatile* card_set_addr, CardSetPtr card_set, uint card_region, uint card, bool increment_total = true); + G1AddCardResult add_to_container(ContainerPtr volatile* container_addr, ContainerPtr container, uint card_region, uint card, bool increment_total = true); - G1AddCardResult add_to_inline_ptr(CardSetPtr volatile* card_set_addr, CardSetPtr card_set, uint card_in_region); - G1AddCardResult add_to_array(CardSetPtr card_set, uint card_in_region); - G1AddCardResult add_to_bitmap(CardSetPtr card_set, uint card_in_region); - G1AddCardResult add_to_howl(CardSetPtr parent_card_set, uint card_region, uint card_in_region, bool increment_total = true); + G1AddCardResult add_to_inline_ptr(ContainerPtr volatile* container_addr, ContainerPtr container, uint card_in_region); + G1AddCardResult add_to_array(ContainerPtr container, uint card_in_region); + G1AddCardResult add_to_bitmap(ContainerPtr container, uint card_in_region); + G1AddCardResult add_to_howl(ContainerPtr parent_container, uint card_region, uint card_in_region, bool increment_total = true); - G1CardSetHashTableValue* get_or_add_card_set(uint card_region, bool* should_grow_table); - G1CardSetHashTableValue* get_card_set(uint card_region); + G1CardSetHashTableValue* get_or_add_container(uint card_region, bool* should_grow_table); + G1CardSetHashTableValue* get_container(uint card_region); // Iterate over cards of a card set container during transfer of the cards from // one container to another. Executes @@ -291,11 +286,11 @@ private: // // on the given class. template - void iterate_cards_during_transfer(CardSetPtr const card_set, CardVisitor& found); + void iterate_cards_during_transfer(ContainerPtr const container, CardVisitor& vl); - uint card_set_type_to_mem_object_type(uintptr_t type) const; + uint container_type_to_mem_object_type(uintptr_t type) const; uint8_t* allocate_mem_object(uintptr_t type); - void free_mem_object(CardSetPtr card_set); + void free_mem_object(ContainerPtr container); public: G1CardSetConfiguration* config() const { return _config; } @@ -304,8 +299,8 @@ public: G1CardSet(G1CardSetConfiguration* config, G1CardSetMemoryManager* mm); virtual ~G1CardSet(); - // Adds the given card to this set, returning an appropriate result. If added, - // updates the total count. + // Adds the given card to this set, returning an appropriate result. + // If incremental_count is true and the card has been added, updates the total count. G1AddCardResult add_card(uint card_region, uint card_in_region, bool increment_total = true); bool contains_card(uint card_region, uint card_in_region); @@ -353,32 +348,32 @@ public: // start_iterate(). // template - void iterate_cards_or_ranges_in_container(CardSetPtr const card_set, CardOrRangeVisitor& found); + void iterate_cards_or_ranges_in_container(ContainerPtr const container, CardOrRangeVisitor& cl); - class G1CardSetPtrIterator { + class ContainerPtrClosure { public: - virtual void do_cardsetptr(uint region_idx, size_t num_occupied, CardSetPtr card_set) = 0; + virtual void do_containerptr(uint region_idx, size_t num_occupied, ContainerPtr container) = 0; }; - void iterate_containers(G1CardSetPtrIterator* iter, bool safepoint = false); + void iterate_containers(ContainerPtrClosure* cl, bool safepoint = false); - class G1CardSetCardIterator { + class CardClosure { public: virtual void do_card(uint region_idx, uint card_idx) = 0; }; - void iterate_cards(G1CardSetCardIterator& iter); + void iterate_cards(CardClosure& cl); }; class G1CardSetHashTableValue { public: - using CardSetPtr = G1CardSet::CardSetPtr; + using ContainerPtr = G1CardSet::ContainerPtr; const uint _region_idx; uint volatile _num_occupied; - CardSetPtr volatile _card_set; + ContainerPtr volatile _container; - G1CardSetHashTableValue(uint region_idx, CardSetPtr card_set) : _region_idx(region_idx), _num_occupied(0), _card_set(card_set) { } + G1CardSetHashTableValue(uint region_idx, ContainerPtr container) : _region_idx(region_idx), _num_occupied(0), _container(container) { } }; class G1CardSetHashTableConfig : public StackObj { @@ -393,6 +388,6 @@ public: static void free_node(void* context, void* memory, Value const& value); }; -typedef ConcurrentHashTable CardSetHash; +using CardSetHash = ConcurrentHashTable; #endif // SHARE_GC_G1_G1CARDSET_HPP diff --git a/src/hotspot/share/gc/g1/g1CardSet.inline.hpp b/src/hotspot/share/gc/g1/g1CardSet.inline.hpp index 4ebc8f664a92867a6db8e0a31192ec1bcb251403..49d7928735a300f577aa4cdc6c85b30d843de5a5 100644 --- a/src/hotspot/share/gc/g1/g1CardSet.inline.hpp +++ b/src/hotspot/share/gc/g1/g1CardSet.inline.hpp @@ -28,55 +28,54 @@ #include "gc/g1/g1CardSet.hpp" #include "gc/g1/g1CardSetContainers.inline.hpp" #include "gc/g1/g1GCPhaseTimes.hpp" -#include "runtime/atomic.hpp" #include "logging/log.hpp" template -inline T* G1CardSet::card_set_ptr(CardSetPtr ptr) { - return (T*)strip_card_set_type(ptr); +inline T* G1CardSet::container_ptr(ContainerPtr ptr) { + return (T*)strip_container_type(ptr); } -inline G1CardSet::CardSetPtr G1CardSet::make_card_set_ptr(void* value, uintptr_t type) { - assert(card_set_type(value) == 0, "Given ptr " PTR_FORMAT " already has type bits set", p2i(value)); - return (CardSetPtr)((uintptr_t)value | type); +inline G1CardSet::ContainerPtr G1CardSet::make_container_ptr(void* value, uintptr_t type) { + assert(container_type(value) == 0, "Given ptr " PTR_FORMAT " already has type bits set", p2i(value)); + return (ContainerPtr)((uintptr_t)value | type); } template -inline void G1CardSet::iterate_cards_or_ranges_in_container(CardSetPtr const card_set, CardOrRangeVisitor& found) { - switch (card_set_type(card_set)) { - case CardSetInlinePtr: { - if (found.start_iterate(G1GCPhaseTimes::MergeRSMergedInline)) { - G1CardSetInlinePtr ptr(card_set); - ptr.iterate(found, _config->inline_ptr_bits_per_card()); +inline void G1CardSet::iterate_cards_or_ranges_in_container(ContainerPtr const container, CardOrRangeVisitor& cl) { + switch (container_type(container)) { + case ContainerInlinePtr: { + if (cl.start_iterate(G1GCPhaseTimes::MergeRSMergedInline)) { + G1CardSetInlinePtr ptr(container); + ptr.iterate(cl, _config->inline_ptr_bits_per_card()); } return; } - case CardSetArrayOfCards : { - if (found.start_iterate(G1GCPhaseTimes::MergeRSMergedArrayOfCards)) { - card_set_ptr(card_set)->iterate(found); + case ContainerArrayOfCards: { + if (cl.start_iterate(G1GCPhaseTimes::MergeRSMergedArrayOfCards)) { + container_ptr(container)->iterate(cl); } return; } - case CardSetBitMap: { + case ContainerBitMap: { // There is no first-level bitmap spanning the whole area. ShouldNotReachHere(); return; } - case CardSetHowl: { - assert(card_set_type(FullCardSet) == CardSetHowl, "Must be"); - if (card_set == FullCardSet) { - if (found.start_iterate(G1GCPhaseTimes::MergeRSMergedFull)) { - found(0, _config->max_cards_in_region()); + case ContainerHowl: { + assert(container_type(FullCardSet) == ContainerHowl, "Must be"); + if (container == FullCardSet) { + if (cl.start_iterate(G1GCPhaseTimes::MergeRSMergedFull)) { + cl(0, _config->max_cards_in_region()); } return; } - if (found.start_iterate(G1GCPhaseTimes::MergeRSMergedHowl)) { - card_set_ptr(card_set)->iterate(found, _config); + if (cl.start_iterate(G1GCPhaseTimes::MergeRSMergedHowl)) { + container_ptr(container)->iterate(cl, _config); } return; } } - log_error(gc)("Unkown card set type %u", card_set_type(card_set)); + log_error(gc)("Unkown card set container type %u", container_type(container)); ShouldNotReachHere(); } diff --git a/src/hotspot/share/gc/g1/g1CardSetContainers.hpp b/src/hotspot/share/gc/g1/g1CardSetContainers.hpp index c273695aa638ba72c97563158ccd732eb74c5500..453594da3f9e570d0ad7da90999cd5bb544c14e7 100644 --- a/src/hotspot/share/gc/g1/g1CardSetContainers.hpp +++ b/src/hotspot/share/gc/g1/g1CardSetContainers.hpp @@ -28,15 +28,10 @@ #include "gc/g1/g1CardSet.hpp" #include "memory/allocation.hpp" #include "runtime/atomic.hpp" -#include "utilities/bitMap.inline.hpp" +#include "utilities/bitMap.hpp" #include "utilities/globalDefinitions.hpp" -#include "utilities/spinYield.hpp" -#include "logging/log.hpp" - -#include "runtime/thread.inline.hpp" - -// A helper class to encode a few card indexes within a CardSetPtr. +// A helper class to encode a few card indexes within a ContainerPtr. // // The pointer value (either 32 or 64 bits) is split into two areas: // @@ -70,16 +65,16 @@ class G1CardSetInlinePtr : public StackObj { friend class G1CardSetContainersTest; - typedef G1CardSet::CardSetPtr CardSetPtr; + using ContainerPtr = G1CardSet::ContainerPtr; - CardSetPtr volatile * _value_addr; - CardSetPtr _value; + ContainerPtr volatile * _value_addr; + ContainerPtr _value; static const uint SizeFieldLen = 3; static const uint SizeFieldPos = 2; - static const uint HeaderSize = G1CardSet::CardSetPtrHeaderSize + SizeFieldLen; + static const uint HeaderSize = G1CardSet::ContainerPtrHeaderSize + SizeFieldLen; - static const uint BitsInValue = sizeof(CardSetPtr) * BitsPerByte; + static const uint BitsInValue = sizeof(ContainerPtr) * BitsPerByte; static const uintptr_t SizeFieldMask = (((uint)1 << SizeFieldLen) - 1) << SizeFieldPos; @@ -87,25 +82,25 @@ class G1CardSetInlinePtr : public StackObj { return (idx * bits_per_card + HeaderSize); } - static CardSetPtr merge(CardSetPtr orig_value, uint card_in_region, uint idx, uint bits_per_card); + static ContainerPtr merge(ContainerPtr orig_value, uint card_in_region, uint idx, uint bits_per_card); - static uint card_at(CardSetPtr value, uint const idx, uint const bits_per_card) { + static uint card_at(ContainerPtr value, uint const idx, uint const bits_per_card) { uint8_t card_pos = card_pos_for(idx, bits_per_card); uint result = ((uintptr_t)value >> card_pos) & (((uintptr_t)1 << bits_per_card) - 1); return result; } - uint find(uint const card_idx, uint const bits_per_card, uint start_at, uint num_elems); + uint find(uint const card_idx, uint const bits_per_card, uint start_at, uint num_cards); public: - G1CardSetInlinePtr() : _value_addr(nullptr), _value((CardSetPtr)G1CardSet::CardSetInlinePtr) { } + G1CardSetInlinePtr() : _value_addr(nullptr), _value((ContainerPtr)G1CardSet::ContainerInlinePtr) { } - G1CardSetInlinePtr(CardSetPtr value) : _value_addr(nullptr), _value(value) { - assert(G1CardSet::card_set_type(_value) == G1CardSet::CardSetInlinePtr, "Value " PTR_FORMAT " is not a valid G1CardSetInPtr.", p2i(_value)); + G1CardSetInlinePtr(ContainerPtr value) : _value_addr(nullptr), _value(value) { + assert(G1CardSet::container_type(_value) == G1CardSet::ContainerInlinePtr, "Value " PTR_FORMAT " is not a valid G1CardSetInlinePtr.", p2i(_value)); } - G1CardSetInlinePtr(CardSetPtr volatile* value_addr, CardSetPtr value) : _value_addr(value_addr), _value(value) { - assert(G1CardSet::card_set_type(_value) == G1CardSet::CardSetInlinePtr, "Value " PTR_FORMAT " is not a valid G1CardSetInPtr.", p2i(_value)); + G1CardSetInlinePtr(ContainerPtr volatile* value_addr, ContainerPtr value) : _value_addr(value_addr), _value(value) { + assert(G1CardSet::container_type(_value) == G1CardSet::ContainerInlinePtr, "Value " PTR_FORMAT " is not a valid G1CardSetInlinePtr.", p2i(_value)); } G1AddCardResult add(uint const card_idx, uint const bits_per_card, uint const max_cards_in_inline_ptr); @@ -115,13 +110,13 @@ public: template void iterate(CardVisitor& found, uint const bits_per_card); - operator CardSetPtr () { return _value; } + operator ContainerPtr () { return _value; } static uint max_cards_in_inline_ptr(uint bits_per_card) { return (BitsInValue - HeaderSize) / bits_per_card; } - static uint num_cards_in(CardSetPtr value) { + static uint num_cards_in(ContainerPtr value) { return ((uintptr_t)value & SizeFieldMask) >> SizeFieldPos; } }; @@ -143,18 +138,12 @@ public: // To maintain these constraints, live objects should have ((_ref_count & 0x1) == 1), // which requires that we increment the reference counts by 2 starting at _ref_count = 3. // -// When such an object is on a free list, we reuse the same field for linking -// together those free objects. -// // All but inline pointers are of this kind. For those, card entries are stored -// directly in the CardSetPtr of the ConcurrentHashTable node. +// directly in the ContainerPtr of the ConcurrentHashTable node. class G1CardSetContainer { -private: - union { - G1CardSetContainer* _next; - uintptr_t _ref_count; - }; - + uintptr_t _ref_count; +protected: + ~G1CardSetContainer() = default; public: G1CardSetContainer() : _ref_count(3) { } @@ -166,18 +155,6 @@ public: // to check the value after attempting to decrement. uintptr_t decrement_refcount(); - G1CardSetContainer* next() { - return _next; - } - - G1CardSetContainer** next_addr() { - return &_next; - } - - void set_next(G1CardSetContainer* next) { - _next = next; - } - // Log of largest card index that can be stored in any G1CardSetContainer static uint LogCardsPerRegionLimit; }; @@ -186,7 +163,7 @@ class G1CardSetArray : public G1CardSetContainer { public: typedef uint16_t EntryDataType; typedef uint EntryCountType; - using CardSetPtr = G1CardSet::CardSetPtr; + using ContainerPtr = G1CardSet::ContainerPtr; private: EntryCountType _size; EntryCountType volatile _num_entries; @@ -218,7 +195,7 @@ private: } public: - G1CardSetArray(uint const card_in_region, EntryCountType num_elems); + G1CardSetArray(uint const card_in_region, EntryCountType num_cards); G1AddCardResult add(uint card_idx); @@ -228,7 +205,6 @@ public: void iterate(CardVisitor& found); size_t num_entries() const { return _num_entries & EntryMask; } - size_t max_entries() const { return _size; } static size_t header_size_in_bytes() { return header_size_in_bytes_internal(); } @@ -241,7 +217,7 @@ class G1CardSetBitMap : public G1CardSetContainer { size_t _num_bits_set; BitMap::bm_word_t _bits[1]; - using CardSetPtr = G1CardSet::CardSetPtr; + using ContainerPtr = G1CardSet::ContainerPtr; template static size_t header_size_in_bytes_internal() { @@ -276,10 +252,10 @@ public: class G1CardSetHowl : public G1CardSetContainer { public: typedef uint EntryCountType; - using CardSetPtr = G1CardSet::CardSetPtr; + using ContainerPtr = G1CardSet::ContainerPtr; EntryCountType volatile _num_entries; private: - CardSetPtr _buckets[2]; + ContainerPtr _buckets[2]; // Do not add class member variables beyond this point template @@ -287,32 +263,32 @@ private: return offset_of(Derived, _buckets); } - // Iterates over the given CardSetPtr with at index in this Howl card set, + // Iterates over the given ContainerPtr with at index in this Howl card set, // applying a CardOrRangeVisitor on it. template - void iterate_cardset(CardSetPtr const card_set, uint index, CardOrRangeVisitor& found, G1CardSetConfiguration* config); + void iterate_cardset(ContainerPtr const container, uint index, CardOrRangeVisitor& found, G1CardSetConfiguration* config); public: G1CardSetHowl(EntryCountType card_in_region, G1CardSetConfiguration* config); - CardSetPtr* get_card_set_addr(EntryCountType index) { + ContainerPtr* get_container_addr(EntryCountType index) { return &_buckets[index]; } bool contains(uint card_idx, G1CardSetConfiguration* config); - // Iterates over all CardSetPtrs in this Howl card set, applying a CardOrRangeVisitor + // Iterates over all ContainerPtrs in this Howl card set, applying a CardOrRangeVisitor // on it. template void iterate(CardOrRangeVisitor& found, G1CardSetConfiguration* config); - // Iterates over all CardSetPtrs in this Howl card set. Calls + // Iterates over all ContainerPtrs in this Howl card set. Calls // - // void operator ()(CardSetPtr* card_set_addr); + // void operator ()(ContainerPtr* card_set_addr); // // on all of them. - template - void iterate(CardSetPtrVisitor& found, uint num_card_sets); + template + void iterate(ContainerPtrVisitor& found, uint num_card_sets); static EntryCountType num_buckets(size_t size_in_bits, size_t num_cards_in_array, size_t max_buckets); @@ -324,7 +300,7 @@ public: static size_t header_size_in_bytes() { return header_size_in_bytes_internal(); } static size_t size_in_bytes(size_t num_arrays) { - return header_size_in_bytes() + sizeof(CardSetPtr) * num_arrays; + return header_size_in_bytes() + sizeof(ContainerPtr) * num_arrays; } }; diff --git a/src/hotspot/share/gc/g1/g1CardSetContainers.inline.hpp b/src/hotspot/share/gc/g1/g1CardSetContainers.inline.hpp index e23386d4040eb6110bfff3d114089658939e21d0..3949687a97c2fefabd10abefe252d284564844d4 100644 --- a/src/hotspot/share/gc/g1/g1CardSetContainers.inline.hpp +++ b/src/hotspot/share/gc/g1/g1CardSetContainers.inline.hpp @@ -27,9 +27,11 @@ #include "gc/g1/g1CardSetContainers.hpp" #include "gc/g1/g1GCPhaseTimes.hpp" +#include "utilities/bitMap.inline.hpp" #include "utilities/globalDefinitions.hpp" +#include "utilities/spinYield.hpp" -inline G1CardSetInlinePtr::CardSetPtr G1CardSetInlinePtr::merge(CardSetPtr orig_value, uint card_in_region, uint idx, uint bits_per_card) { +inline G1CardSetInlinePtr::ContainerPtr G1CardSetInlinePtr::merge(ContainerPtr orig_value, uint card_in_region, uint idx, uint bits_per_card) { assert((idx & (SizeFieldMask >> SizeFieldPos)) == idx, "Index %u too large to fit into size field", idx); assert(card_in_region < ((uint)1 << bits_per_card), "Card %u too large to fit into card value field", card_in_region); @@ -42,7 +44,7 @@ inline G1CardSetInlinePtr::CardSetPtr G1CardSetInlinePtr::merge(CardSetPtr orig_ uintptr_t value = ((uintptr_t)(idx + 1) << SizeFieldPos) | ((uintptr_t)card_in_region << card_pos); uintptr_t res = (((uintptr_t)orig_value & ~SizeFieldMask) | value); - return (CardSetPtr)res; + return (ContainerPtr)res; } inline G1AddCardResult G1CardSetInlinePtr::add(uint card_idx, uint bits_per_card, uint max_cards_in_inline_ptr) { @@ -50,20 +52,20 @@ inline G1AddCardResult G1CardSetInlinePtr::add(uint card_idx, uint bits_per_card uint cur_idx = 0; while (true) { - uint num_elems = num_cards_in(_value); - if (num_elems > 0) { - cur_idx = find(card_idx, bits_per_card, cur_idx, num_elems); + uint num_cards = num_cards_in(_value); + if (num_cards > 0) { + cur_idx = find(card_idx, bits_per_card, cur_idx, num_cards); } // Check if the card is already stored in the pointer. - if (cur_idx < num_elems) { + if (cur_idx < num_cards) { return Found; } // Check if there is actually enough space. - if (num_elems >= max_cards_in_inline_ptr) { + if (num_cards >= max_cards_in_inline_ptr) { return Overflow; } - CardSetPtr new_value = merge(_value, card_idx, num_elems, bits_per_card); - CardSetPtr old_value = Atomic::cmpxchg(_value_addr, _value, new_value, memory_order_relaxed); + ContainerPtr new_value = merge(_value, card_idx, num_cards, bits_per_card); + ContainerPtr old_value = Atomic::cmpxchg(_value_addr, _value, new_value, memory_order_relaxed); if (_value == old_value) { return Added; } @@ -71,44 +73,44 @@ inline G1AddCardResult G1CardSetInlinePtr::add(uint card_idx, uint bits_per_card _value = old_value; // The value of the pointer may have changed to something different than // an inline card set. Exit then instead of overwriting. - if (G1CardSet::card_set_type(_value) != G1CardSet::CardSetInlinePtr) { + if (G1CardSet::container_type(_value) != G1CardSet::ContainerInlinePtr) { return Overflow; } } } -inline uint G1CardSetInlinePtr::find(uint card_idx, uint bits_per_card, uint start_at, uint num_elems) { - assert(start_at < num_elems, "Precondition!"); +inline uint G1CardSetInlinePtr::find(uint card_idx, uint bits_per_card, uint start_at, uint num_cards) { + assert(start_at < num_cards, "Precondition!"); uintptr_t const card_mask = (1 << bits_per_card) - 1; uintptr_t value = ((uintptr_t)_value) >> card_pos_for(start_at, bits_per_card); // Check if the card is already stored in the pointer. - for (uint cur_idx = start_at; cur_idx < num_elems; cur_idx++) { + for (uint cur_idx = start_at; cur_idx < num_cards; cur_idx++) { if ((value & card_mask) == card_idx) { return cur_idx; } value >>= bits_per_card; } - return num_elems; + return num_cards; } inline bool G1CardSetInlinePtr::contains(uint card_idx, uint bits_per_card) { - uint num_elems = num_cards_in(_value); - if (num_elems == 0) { + uint num_cards = num_cards_in(_value); + if (num_cards == 0) { return false; } - uint cur_idx = find(card_idx, bits_per_card, 0, num_elems); - return cur_idx < num_elems; + uint cur_idx = find(card_idx, bits_per_card, 0, num_cards); + return cur_idx < num_cards; } template inline void G1CardSetInlinePtr::iterate(CardVisitor& found, uint bits_per_card) { - uint const num_elems = num_cards_in(_value); + uint const num_cards = num_cards_in(_value); uintptr_t const card_mask = (1 << bits_per_card) - 1; uintptr_t value = ((uintptr_t)_value) >> card_pos_for(0, bits_per_card); - for (uint cur_idx = 0; cur_idx < num_elems; cur_idx++) { + for (uint cur_idx = 0; cur_idx < num_cards; cur_idx++) { found(value & card_mask); value >>= bits_per_card; } @@ -136,9 +138,9 @@ inline uintptr_t G1CardSetContainer::decrement_refcount() { return Atomic::sub(&_ref_count, 2u); } -inline G1CardSetArray::G1CardSetArray(uint card_in_region, EntryCountType num_elems) : +inline G1CardSetArray::G1CardSetArray(uint card_in_region, EntryCountType num_cards) : G1CardSetContainer(), - _size(num_elems), + _size(num_cards), _num_entries(1) { assert(_size > 0, "CardSetArray of size 0 not supported."); assert(_size < LockBitMask, "Only support CardSetArray of size %u or smaller.", LockBitMask - 1); @@ -166,7 +168,7 @@ inline G1CardSetArray::G1CardSetArrayLocker::G1CardSetArrayLocker(EntryCountType inline G1AddCardResult G1CardSetArray::add(uint card_idx) { assert(card_idx < (1u << (sizeof(_data[0]) * BitsPerByte)), - "Card index %u does not fit card element.", card_idx); + "Card index %u does not fit allowed card value range.", card_idx); EntryCountType num_entries = Atomic::load_acquire(&_num_entries) & EntryMask; EntryCountType idx = 0; for (; idx < num_entries; idx++) { @@ -181,7 +183,7 @@ inline G1AddCardResult G1CardSetArray::add(uint card_idx) { // Reload number of entries from the G1CardSetArrayLocker as it might have changed. // It already read the actual value with the necessary synchronization. num_entries = x.num_entries(); - // Look if the elements added while waiting for the lock are the same as our card. + // Look if the cards added while waiting for the lock are the same as our card. for (; idx < num_entries; idx++) { if (_data[idx] == card_idx) { return Found; @@ -252,37 +254,37 @@ inline void G1CardSetBitMap::iterate(CardVisitor& found, size_t size_in_bits, ui inline G1CardSetHowl::G1CardSetHowl(EntryCountType card_in_region, G1CardSetConfiguration* config) : G1CardSetContainer(), - _num_entries((config->num_cards_in_array() + 1)) /* Card Transfer will not increment _num_entries */ { + _num_entries((config->max_cards_in_array() + 1)) /* Card Transfer will not increment _num_entries */ { EntryCountType num_buckets = config->num_buckets_in_howl(); EntryCountType bucket = config->howl_bucket_index(card_in_region); for (uint i = 0; i < num_buckets; ++i) { _buckets[i] = G1CardSetInlinePtr(); if (i == bucket) { G1CardSetInlinePtr value(&_buckets[i], _buckets[i]); - value.add(card_in_region, config->inline_ptr_bits_per_card(), config->num_cards_in_inline_ptr()); + value.add(card_in_region, config->inline_ptr_bits_per_card(), config->max_cards_in_inline_ptr()); } } } inline bool G1CardSetHowl::contains(uint card_idx, G1CardSetConfiguration* config) { EntryCountType bucket = config->howl_bucket_index(card_idx); - CardSetPtr* array_entry = get_card_set_addr(bucket); - CardSetPtr card_set = Atomic::load_acquire(array_entry); + ContainerPtr* array_entry = get_container_addr(bucket); + ContainerPtr container = Atomic::load_acquire(array_entry); - switch (G1CardSet::card_set_type(card_set)) { - case G1CardSet::CardSetArrayOfCards : { - return G1CardSet::card_set_ptr(card_set)->contains(card_idx); + switch (G1CardSet::container_type(container)) { + case G1CardSet::ContainerArrayOfCards: { + return G1CardSet::container_ptr(container)->contains(card_idx); } - case G1CardSet::CardSetBitMap: { + case G1CardSet::ContainerBitMap: { uint card_offset = config->howl_bitmap_offset(card_idx); - return G1CardSet::card_set_ptr(card_set)->contains(card_offset, config->num_cards_in_howl_bitmap()); + return G1CardSet::container_ptr(container)->contains(card_offset, config->max_cards_in_howl_bitmap()); } - case G1CardSet::CardSetInlinePtr: { - G1CardSetInlinePtr ptr(card_set); + case G1CardSet::ContainerInlinePtr: { + G1CardSetInlinePtr ptr(container); return ptr.contains(card_idx, config->inline_ptr_bits_per_card()); } - case G1CardSet::CardSetHowl: {// Fullcard set entry - assert(card_set == G1CardSet::FullCardSet, "Must be"); + case G1CardSet::ContainerHowl: {// Fullcard set entry + assert(container == G1CardSet::FullCardSet, "Must be"); return true; } } @@ -296,53 +298,53 @@ inline void G1CardSetHowl::iterate(CardOrRangeVisitor& found, G1CardSetConfigura } } -template -inline void G1CardSetHowl::iterate(CardSetPtrVisitor& found, uint num_card_sets) { +template +inline void G1CardSetHowl::iterate(ContainerPtrVisitor& found, uint num_card_sets) { for (uint i = 0; i < num_card_sets; ++i) { found(&_buckets[i]); } } template -inline void G1CardSetHowl::iterate_cardset(CardSetPtr const card_set, uint index, CardOrRangeVisitor& found, G1CardSetConfiguration* config) { - switch (G1CardSet::card_set_type(card_set)) { - case G1CardSet::CardSetInlinePtr: { +inline void G1CardSetHowl::iterate_cardset(ContainerPtr const container, uint index, CardOrRangeVisitor& found, G1CardSetConfiguration* config) { + switch (G1CardSet::container_type(container)) { + case G1CardSet::ContainerInlinePtr: { if (found.start_iterate(G1GCPhaseTimes::MergeRSHowlInline)) { - G1CardSetInlinePtr ptr(card_set); + G1CardSetInlinePtr ptr(container); ptr.iterate(found, config->inline_ptr_bits_per_card()); } return; } - case G1CardSet::CardSetArrayOfCards : { + case G1CardSet::ContainerArrayOfCards: { if (found.start_iterate(G1GCPhaseTimes::MergeRSHowlArrayOfCards)) { - G1CardSet::card_set_ptr(card_set)->iterate(found); + G1CardSet::container_ptr(container)->iterate(found); } return; } - case G1CardSet::CardSetBitMap: { + case G1CardSet::ContainerBitMap: { if (found.start_iterate(G1GCPhaseTimes::MergeRSHowlBitmap)) { - uint offset = index << config->log2_num_cards_in_howl_bitmap(); - G1CardSet::card_set_ptr(card_set)->iterate(found, config->num_cards_in_howl_bitmap(), offset); + uint offset = index << config->log2_max_cards_in_howl_bitmap(); + G1CardSet::container_ptr(container)->iterate(found, config->max_cards_in_howl_bitmap(), offset); } return; } - case G1CardSet::CardSetHowl: { // actually FullCardSet - assert(card_set == G1CardSet::FullCardSet, "Must be"); + case G1CardSet::ContainerHowl: { // actually FullCardSet + assert(container == G1CardSet::FullCardSet, "Must be"); if (found.start_iterate(G1GCPhaseTimes::MergeRSHowlFull)) { - uint offset = index << config->log2_num_cards_in_howl_bitmap(); - found(offset, config->num_cards_in_howl_bitmap()); + uint offset = index << config->log2_max_cards_in_howl_bitmap(); + found(offset, config->max_cards_in_howl_bitmap()); } return; } } } -inline G1CardSetHowl::EntryCountType G1CardSetHowl::num_buckets(size_t size_in_bits, size_t num_cards_in_array, size_t max_num_buckets) { +inline G1CardSetHowl::EntryCountType G1CardSetHowl::num_buckets(size_t size_in_bits, size_t max_cards_in_array, size_t max_num_buckets) { size_t size_bitmap_bytes = BitMap::calc_size_in_words(size_in_bits) * BytesPerWord; // Ensure that in the worst case arrays consume half the memory size // of storing the entire bitmap size_t max_size_arrays_bytes = size_bitmap_bytes / 2; - size_t size_array_bytes = num_cards_in_array * sizeof(G1CardSetArray::EntryDataType); + size_t size_array_bytes = max_cards_in_array * sizeof(G1CardSetArray::EntryDataType); size_t num_arrays = max_size_arrays_bytes / size_array_bytes; // We use shifts and masks for indexing the array. So round down to the next // power of two to not use more than expected memory. diff --git a/src/hotspot/share/gc/g1/g1CardSetMemory.cpp b/src/hotspot/share/gc/g1/g1CardSetMemory.cpp index 988db3a4a8dd2cbaf52f4e5f96c8a4782ef7b9da..b68c50b5cb1b5ff4a6abd68e07e015ac765189ac 100644 --- a/src/hotspot/share/gc/g1/g1CardSetMemory.cpp +++ b/src/hotspot/share/gc/g1/g1CardSetMemory.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -24,294 +24,82 @@ #include "precompiled.hpp" +#include "gc/g1/g1CardSetContainers.inline.hpp" #include "gc/g1/g1CardSetMemory.inline.hpp" #include "gc/g1/g1SegmentedArray.inline.hpp" -#include "logging/log.hpp" #include "runtime/atomic.hpp" -#include "utilities/formatBuffer.hpp" #include "utilities/ostream.hpp" - -template -G1CardSetAllocator::G1CardSetAllocator(const char* name, - const G1CardSetAllocOptions* buffer_options, - G1CardSetBufferList* free_buffer_list) : - _segmented_array(buffer_options, free_buffer_list), - _transfer_lock(false), - _free_nodes_list(), - _pending_nodes_list(), - _num_pending_nodes(0), - _num_free_nodes(0) +G1CardSetAllocator::G1CardSetAllocator(const char* name, + const G1CardSetAllocOptions* alloc_options, + G1CardSetFreeList* free_segment_list) : + _segmented_array(alloc_options, free_segment_list), + _free_slots_list(name, &_segmented_array) { - uint elem_size = _segmented_array.elem_size(); - assert(elem_size >= sizeof(G1CardSetContainer), "Element instance size %u for allocator %s too small", elem_size, name); + uint slot_size = _segmented_array.slot_size(); + assert(slot_size >= sizeof(G1CardSetContainer), "Slot instance size %u for allocator %s too small", slot_size, name); } -template -G1CardSetAllocator::~G1CardSetAllocator() { +G1CardSetAllocator::~G1CardSetAllocator() { drop_all(); } -template -bool G1CardSetAllocator::try_transfer_pending() { - // Attempt to claim the lock. - if (Atomic::load_acquire(&_transfer_lock) || // Skip CAS if likely to fail. - Atomic::cmpxchg(&_transfer_lock, false, true)) { - return false; - } - // Have the lock; perform the transfer. - - // Claim all the pending nodes. - G1CardSetContainer* first = _pending_nodes_list.pop_all(); - - if (first != nullptr) { - // Prepare to add the claimed nodes, and update _num_pending_nodes. - G1CardSetContainer* last = first; - Atomic::load_acquire(&_num_pending_nodes); - - uint count = 1; - for (G1CardSetContainer* next = first->next(); next != nullptr; next = next->next()) { - last = next; - ++count; - } - - Atomic::sub(&_num_pending_nodes, count); - - // Wait for any in-progress pops to avoid ABA for them. - GlobalCounter::write_synchronize(); - // Add synchronized nodes to _free_node_list. - // Update count first so there can be no underflow in allocate(). - Atomic::add(&_num_free_nodes, count); - _free_nodes_list.prepend(*first, *last); - } - Atomic::release_store(&_transfer_lock, false); - return true; +void G1CardSetAllocator::free(void* slot) { + assert(slot != nullptr, "precondition"); + _free_slots_list.release(slot); } -template -void G1CardSetAllocator::free(Elem* elem) { - assert(elem != nullptr, "precondition"); - // Desired minimum transfer batch size. There is relatively little - // importance to the specific number. It shouldn't be too big, else - // we're wasting space when the release rate is low. If the release - // rate is high, we might accumulate more than this before being - // able to start a new transfer, but that's okay. Also note that - // the allocation rate and the release rate are going to be fairly - // similar, due to how the buffers are used. - kbarret - uint const trigger_transfer = 10; - - uint pending_count = Atomic::add(&_num_pending_nodes, 1u, memory_order_relaxed); - - G1CardSetContainer* node = reinterpret_cast(reinterpret_cast(elem)); - - node->set_next(nullptr); - assert(node->next() == nullptr, "precondition"); +void G1CardSetAllocator::drop_all() { + _free_slots_list.reset(); + _segmented_array.drop_all(); +} - _pending_nodes_list.push(*node); +size_t G1CardSetAllocator::mem_size() const { + return sizeof(*this) + + _segmented_array.num_segments() * sizeof(G1CardSetSegment) + + _segmented_array.num_available_slots() * _segmented_array.slot_size(); +} - if (pending_count > trigger_transfer) { - try_transfer_pending(); - } +size_t G1CardSetAllocator::wasted_mem_size() const { + uint num_wasted_slots = _segmented_array.num_available_slots() - + _segmented_array.num_allocated_slots() - + (uint)_free_slots_list.pending_count(); + return num_wasted_slots * _segmented_array.slot_size(); } -template -void G1CardSetAllocator::drop_all() { - _free_nodes_list.pop_all(); - _pending_nodes_list.pop_all(); - _num_pending_nodes = 0; - _num_free_nodes = 0; - _segmented_array.drop_all(); +uint G1CardSetAllocator::num_segments() const { + return _segmented_array.num_segments(); } -template -void G1CardSetAllocator::print(outputStream* os) { - uint num_allocated_nodes = _segmented_array.num_allocated_nodes(); - uint num_available_nodes = _segmented_array.num_available_nodes(); - uint highest = _segmented_array.first_array_buffer() != nullptr - ? _segmented_array.first_array_buffer()->num_elems() +void G1CardSetAllocator::print(outputStream* os) { + uint num_allocated_slots = _segmented_array.num_allocated_slots(); + uint num_available_slots = _segmented_array.num_available_slots(); + uint highest = _segmented_array.first_array_segment() != nullptr + ? _segmented_array.first_array_segment()->num_slots() : 0; - uint num_buffers = _segmented_array.num_buffers(); - os->print("MA " PTR_FORMAT ": %u elems pending (allocated %u available %u) used %.3f highest %u buffers %u size %zu ", + uint num_segments = _segmented_array.num_segments(); + uint num_pending_slots = (uint)_free_slots_list.pending_count(); + os->print("MA " PTR_FORMAT ": %u slots pending (allocated %u available %u) used %.3f highest %u segments %u size %zu ", p2i(this), - _num_pending_nodes, - num_allocated_nodes, - num_available_nodes, - percent_of(num_allocated_nodes - _num_pending_nodes, num_available_nodes), + num_pending_slots, + num_allocated_slots, + num_available_slots, + percent_of(num_allocated_slots - num_pending_slots, num_available_slots), highest, - num_buffers, + num_segments, mem_size()); } -G1CardSetMemoryStats::G1CardSetMemoryStats() { - clear(); -} - -void G1CardSetMemoryStats::clear() { - for (uint i = 0; i < num_pools(); i++) { - _num_mem_sizes[i] = 0; - _num_buffers[i] = 0; - } -} - -void G1CardSetFreePool::update_unlink_processors(G1ReturnMemoryProcessorSet* unlink_processor) { - uint num_free_lists = _freelist_pool.num_free_lists(); - - for (uint i = 0; i < num_free_lists; i++) { - unlink_processor->at(i)->visit_free_list(_freelist_pool.free_list(i)); - } -} - -void G1CardSetFreePool::G1ReturnMemoryProcessor::visit_free_list(G1CardSetBufferList* source) { - assert(_source == nullptr, "already visited"); - if (_return_to_vm_size > 0) { - _source = source; - } else { - assert(_source == nullptr, "must be"); - } - if (source->mem_size() > _return_to_vm_size) { - _first = source->get_all(_num_unlinked, _unlinked_bytes); - } else { - assert(_first == nullptr, "must be"); - } - // Above we were racing with other threads getting the contents of the free list, - // so while we might have been asked to return something to the OS initially, - // the free list might be empty anyway. In this case just reset internal values - // used for checking whether there is work available. - if (_first == nullptr) { - _source = nullptr; - _return_to_vm_size = 0; - } -} - -bool G1CardSetFreePool::G1ReturnMemoryProcessor::return_to_vm(jlong deadline) { - assert(!finished_return_to_vm(), "already returned everything to the VM"); - assert(_first != nullptr, "must have element to return"); - - size_t keep_size = 0; - size_t keep_num = 0; - - G1CardSetBuffer* cur = _first; - G1CardSetBuffer* last = nullptr; - - while (cur != nullptr && _return_to_vm_size > 0) { - size_t cur_size = cur->mem_size(); - _return_to_vm_size -= MIN2(_return_to_vm_size, cur_size); - - keep_size += cur_size; - keep_num++; - - last = cur; - cur = cur->next(); - // To ensure progress, perform the deadline check here. - if (os::elapsed_counter() > deadline) { - break; - } - } - - assert(_first != nullptr, "must be"); - assert(last != nullptr, "must be"); - - last->set_next(nullptr); - - // Wait for any in-progress pops to avoid ABA for them. - GlobalCounter::write_synchronize(); - _source->bulk_add(*_first, *last, keep_num, keep_size); - _first = cur; - - log_trace(gc, task)("Card Set Free Memory: Returned to VM %zu buffers size %zu", keep_num, keep_size); - - // _return_to_vm_size may be larger than what is available in the list at the - // time we actually get the list. I.e. the list and _return_to_vm_size may be - // inconsistent. - // So also check if we actually already at the end of the list for the exit - // condition. - if (_return_to_vm_size == 0 || _first == nullptr) { - _source = nullptr; - _return_to_vm_size = 0; - } - return _source != nullptr; -} - -bool G1CardSetFreePool::G1ReturnMemoryProcessor::return_to_os(jlong deadline) { - assert(finished_return_to_vm(), "not finished returning to VM"); - assert(!finished_return_to_os(), "already returned everything to the OS"); - - // Now delete the rest. - size_t num_delete = 0; - size_t mem_size_deleted = 0; - - while (_first != nullptr) { - G1CardSetBuffer* next = _first->next(); - num_delete++; - mem_size_deleted += _first->mem_size(); - delete _first; - _first = next; - - // To ensure progress, perform the deadline check here. - if (os::elapsed_counter() > deadline) { - break; - } - } - - log_trace(gc, task)("Card Set Free Memory: Return to OS %zu buffers size %zu", num_delete, mem_size_deleted); - - return _first != nullptr; -} - -G1CardSetFreePool G1CardSetFreePool::_freelist_pool(G1CardSetConfiguration::num_mem_object_types()); - -G1CardSetFreePool::G1CardSetFreePool(uint num_free_lists) : - _num_free_lists(num_free_lists) { - - _free_lists = NEW_C_HEAP_ARRAY(G1CardSetBufferList, _num_free_lists, mtGC); - for (uint i = 0; i < _num_free_lists; i++) { - new (&_free_lists[i]) G1CardSetBufferList(); - } -} - -G1CardSetFreePool::~G1CardSetFreePool() { - for (uint i = 0; i < _num_free_lists; i++) { - _free_lists[i].~G1CardSetBufferList(); - } - FREE_C_HEAP_ARRAY(mtGC, _free_lists); -} - -G1CardSetMemoryStats G1CardSetFreePool::memory_sizes() const { - G1CardSetMemoryStats free_list_stats; - assert(free_list_stats.num_pools() == num_free_lists(), "must be"); - for (uint i = 0; i < num_free_lists(); i++) { - free_list_stats._num_mem_sizes[i] = _free_lists[i].mem_size(); - free_list_stats._num_buffers[i] = _free_lists[i].num_buffers(); - } - return free_list_stats; -} - -size_t G1CardSetFreePool::mem_size() const { - size_t result = 0; - for (uint i = 0; i < _num_free_lists; i++) { - result += _free_lists[i].mem_size(); - } - return result; -} - -void G1CardSetFreePool::print_on(outputStream* out) { - out->print_cr(" Free Pool: size %zu", free_list_pool()->mem_size()); - for (uint i = 0; i < _num_free_lists; i++) { - FormatBuffer<> fmt(" %s", G1CardSetConfiguration::mem_object_type_name_str(i)); - _free_lists[i].print_on(out, fmt); - } -} - G1CardSetMemoryManager::G1CardSetMemoryManager(G1CardSetConfiguration* config, G1CardSetFreePool* free_list_pool) : _config(config) { - _allocators = NEW_C_HEAP_ARRAY(G1CardSetAllocator, + _allocators = NEW_C_HEAP_ARRAY(G1CardSetAllocator, _config->num_mem_object_types(), mtGC); for (uint i = 0; i < num_mem_object_types(); i++) { - new (&_allocators[i]) G1CardSetAllocator(_config->mem_object_type_name_str(i), - _config->mem_object_alloc_options(i), - free_list_pool->free_list(i)); + new (&_allocators[i]) G1CardSetAllocator(_config->mem_object_type_name_str(i), + _config->mem_object_alloc_options(i), + free_list_pool->free_list(i)); } } @@ -329,7 +117,7 @@ G1CardSetMemoryManager::~G1CardSetMemoryManager() { void G1CardSetMemoryManager::free(uint type, void* value) { assert(type < num_mem_object_types(), "must be"); - _allocators[type].free((G1CardSetContainer*)value); + _allocators[type].free(value); } void G1CardSetMemoryManager::flush() { @@ -350,9 +138,8 @@ size_t G1CardSetMemoryManager::mem_size() const { for (uint i = 0; i < num_mem_object_types(); i++) { result += _allocators[i].mem_size(); } - return sizeof(*this) - - (sizeof(G1CardSetAllocator) * num_mem_object_types()) + - result; + return sizeof(*this) + result - + (sizeof(G1CardSetAllocator) * num_mem_object_types()); } size_t G1CardSetMemoryManager::wasted_mem_size() const { @@ -363,11 +150,11 @@ size_t G1CardSetMemoryManager::wasted_mem_size() const { return result; } -G1CardSetMemoryStats G1CardSetMemoryManager::memory_stats() const { - G1CardSetMemoryStats result; +G1SegmentedArrayMemoryStats G1CardSetMemoryManager::memory_stats() const { + G1SegmentedArrayMemoryStats result; for (uint i = 0; i < num_mem_object_types(); i++) { result._num_mem_sizes[i] += _allocators[i].mem_size(); - result._num_buffers[i] += _allocators[i].num_buffers(); + result._num_segments[i] += _allocators[i].num_segments(); } return result; } diff --git a/src/hotspot/share/gc/g1/g1CardSetMemory.hpp b/src/hotspot/share/gc/g1/g1CardSetMemory.hpp index 4167576f9bb8952a2123d4bf8f7bffe5c78df03d..c2663b41cf1ab8afb6cd9568426aeb3931930a10 100644 --- a/src/hotspot/share/gc/g1/g1CardSetMemory.hpp +++ b/src/hotspot/share/gc/g1/g1CardSetMemory.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -27,212 +27,77 @@ #include "gc/g1/g1CardSet.hpp" #include "gc/g1/g1CardSetContainers.hpp" -#include "gc/g1/g1CardSetContainers.inline.hpp" #include "gc/g1/g1SegmentedArray.hpp" +#include "gc/g1/g1SegmentedArrayFreePool.hpp" +#include "gc/shared/freeListAllocator.hpp" #include "memory/allocation.hpp" #include "utilities/growableArray.hpp" -#include "utilities/lockFreeStack.hpp" class G1CardSetConfiguration; class outputStream; // Collects G1CardSetAllocator options/heuristics. Called by G1CardSetAllocator -// to determine the next size of the allocated G1CardSetBuffer. +// to determine the next size of the allocated G1CardSetSegment. class G1CardSetAllocOptions : public G1SegmentedArrayAllocOptions { - static const uint MinimumBufferSize = 8; - static const uint MaximumBufferSize = UINT_MAX / 2; + static const uint MinimumNumSlots = 8; + static const uint MaximumNumSlots = UINT_MAX / 2; - uint exponential_expand(uint prev_num_elems) const { - return clamp(prev_num_elems * 2, _initial_num_elems, _max_num_elems); + uint exponential_expand(uint prev_num_slots) const { + return clamp(prev_num_slots * 2, _initial_num_slots, _max_num_slots); } public: - static const uint BufferAlignment = 8; + static const uint SlotAlignment = 8; - G1CardSetAllocOptions(uint elem_size, uint initial_num_elems = MinimumBufferSize, uint max_num_elems = MaximumBufferSize) : - G1SegmentedArrayAllocOptions(align_up(elem_size, BufferAlignment), initial_num_elems, max_num_elems, BufferAlignment) { + G1CardSetAllocOptions(uint slot_size, uint initial_num_slots = MinimumNumSlots, uint max_num_slots = MaximumNumSlots) : + G1SegmentedArrayAllocOptions(align_up(slot_size, SlotAlignment), initial_num_slots, max_num_slots, SlotAlignment) { } - virtual uint next_num_elems(uint prev_num_elems) const override { - return exponential_expand(prev_num_elems); + virtual uint next_num_slots(uint prev_num_slots) const override { + return exponential_expand(prev_num_slots); } }; -typedef G1SegmentedArrayBuffer G1CardSetBuffer; +typedef G1SegmentedArraySegment G1CardSetSegment; -typedef G1SegmentedArrayBufferList G1CardSetBufferList; +typedef G1SegmentedArrayFreeList G1CardSetFreeList; -// Arena-like allocator for (card set) heap memory objects (Elem elements). +// Arena-like allocator for (card set) heap memory objects. // -// Allocation and deallocation in the first phase on G1CardSetContainer basis -// may occur by multiple threads at once. -// -// Allocation occurs from an internal free list of G1CardSetContainers first, -// only then trying to bump-allocate from the current G1CardSetBuffer. If there is -// none, this class allocates a new G1CardSetBuffer (allocated from the C heap, -// asking the G1CardSetAllocOptions instance about sizes etc) and uses that one. -// -// The NodeStack free list is a linked list of G1CardSetContainers -// within all G1CardSetBuffer instances allocated so far. It uses a separate -// pending list and global synchronization to avoid the ABA problem when the -// user frees a memory object. -// -// The class also manages a few counters for statistics using atomic operations. -// Their values are only consistent within each other with extra global -// synchronization. -// -// Since it is expected that every CardSet (and in extension each region) has its -// own set of allocators, there is intentionally no padding between them to save -// memory. -template +// Allocation occurs from an internal free list of objects first. If the free list is +// empty then tries to allocate from the G1SegmentedArray. class G1CardSetAllocator { - // G1CardSetBuffer management. - - typedef G1SegmentedArray SegmentedArray; - // G1CardSetContainer node management within the G1CardSetBuffers allocated - // by this allocator. - static G1CardSetContainer* volatile* next_ptr(G1CardSetContainer& node); - typedef LockFreeStack NodeStack; - - SegmentedArray _segmented_array; - volatile bool _transfer_lock; - NodeStack _free_nodes_list; - NodeStack _pending_nodes_list; - - volatile uint _num_pending_nodes; // Number of nodes in the pending list. - volatile uint _num_free_nodes; // Number of nodes in the free list. - - // Try to transfer nodes from _pending_nodes_list to _free_nodes_list, with a - // synchronization delay for any in-progress pops from the _free_nodes_list - // to solve ABA here. - bool try_transfer_pending(); - - uint num_free_elems() const; + G1SegmentedArray _segmented_array; + FreeListAllocator _free_slots_list; public: G1CardSetAllocator(const char* name, - const G1CardSetAllocOptions* buffer_options, - G1CardSetBufferList* free_buffer_list); + const G1CardSetAllocOptions* alloc_options, + G1CardSetFreeList* free_segment_list); ~G1CardSetAllocator(); - Elem* allocate(); - void free(Elem* elem); + void* allocate(); + void free(void* slot); - // Deallocate all buffers to the free buffer list and reset this allocator. Must + // Deallocate all segments to the free segment list and reset this allocator. Must // be called in a globally synchronized area. void drop_all(); - size_t mem_size() const { - return sizeof(*this) + - _segmented_array.num_buffers() * sizeof(G1CardSetBuffer) + _segmented_array.num_available_nodes() * _segmented_array.elem_size(); - } + size_t mem_size() const; - size_t wasted_mem_size() const { - return (_segmented_array.num_available_nodes() - (_segmented_array.num_allocated_nodes() - _num_pending_nodes)) * _segmented_array.elem_size(); - } + size_t wasted_mem_size() const; - inline uint num_buffers() { return _segmented_array.num_buffers(); } + uint num_segments() const; void print(outputStream* os); }; -// Statistics for a fixed set of buffer lists. Contains the number of buffers and memory -// used for each. Note that statistics are typically not taken atomically so there -// can be inconsistencies. The user must be prepared for them. -class G1CardSetMemoryStats { -public: - - size_t _num_mem_sizes[G1CardSetConfiguration::num_mem_object_types()]; - size_t _num_buffers[G1CardSetConfiguration::num_mem_object_types()]; - - // Returns all-zero statistics. - G1CardSetMemoryStats(); - - void add(G1CardSetMemoryStats const other) { - STATIC_ASSERT(ARRAY_SIZE(_num_buffers) == ARRAY_SIZE(_num_mem_sizes)); - for (uint i = 0; i < ARRAY_SIZE(_num_mem_sizes); i++) { - _num_mem_sizes[i] += other._num_mem_sizes[i]; - _num_buffers[i] += other._num_buffers[i]; - } - } - - void clear(); - - uint num_pools() const { return G1CardSetConfiguration::num_mem_object_types(); } -}; - -// A set of free lists holding memory buffers for use by G1CardSetAllocators. -class G1CardSetFreePool { - // The global free pool. - static G1CardSetFreePool _freelist_pool; - - const uint _num_free_lists; - G1CardSetBufferList* _free_lists; - -public: - static G1CardSetFreePool* free_list_pool() { return &_freelist_pool; } - static G1CardSetMemoryStats free_list_sizes() { return _freelist_pool.memory_sizes(); } - - class G1ReturnMemoryProcessor; - typedef GrowableArrayCHeap G1ReturnMemoryProcessorSet; - - static void update_unlink_processors(G1ReturnMemoryProcessorSet* unlink_processors); - - explicit G1CardSetFreePool(uint num_free_lists); - ~G1CardSetFreePool(); - - G1CardSetBufferList* free_list(uint i) { - assert(i < _num_free_lists, "must be"); - return &_free_lists[i]; - } - - uint num_free_lists() const { return _num_free_lists; } - - G1CardSetMemoryStats memory_sizes() const; - size_t mem_size() const; - - void print_on(outputStream* out); -}; - -// Data structure containing current in-progress state for returning memory to the -// operating system for a single G1CardSetBufferList. -class G1CardSetFreePool::G1ReturnMemoryProcessor : public CHeapObj { - G1CardSetBufferList* _source; - size_t _return_to_vm_size; - - G1CardSetBuffer* _first; - size_t _unlinked_bytes; - size_t _num_unlinked; - -public: - explicit G1ReturnMemoryProcessor(size_t return_to_vm) : - _source(nullptr), _return_to_vm_size(return_to_vm), _first(nullptr), _unlinked_bytes(0), _num_unlinked(0) { - } - - // Updates the instance members about the given card set buffer list for the purpose - // of giving back memory. Only necessary members are updated, e.g. if there is - // nothing to return to the VM, do not set the source list. - void visit_free_list(G1CardSetBufferList* source); - - bool finished_return_to_vm() const { return _return_to_vm_size == 0; } - bool finished_return_to_os() const { return _first == nullptr; } - - // Returns memory to the VM until the given deadline expires. Returns true if - // there is no more work. Guarantees forward progress, i.e. at least one buffer - // has been processed after returning. - // return_to_vm() re-adds buffers to the respective free list. - bool return_to_vm(jlong deadline); - // Returns memory to the VM until the given deadline expires. Returns true if - // there is no more work. Guarantees forward progress, i.e. at least one buffer - // has been processed after returning. - // return_to_os() gives back buffers to the OS. - bool return_to_os(jlong deadline); -}; +typedef G1SegmentedArrayFreePool G1CardSetFreePool; class G1CardSetMemoryManager : public CHeapObj { G1CardSetConfiguration* _config; - G1CardSetAllocator* _allocators; + G1CardSetAllocator* _allocators; uint num_mem_object_types() const; public: @@ -256,7 +121,7 @@ public: size_t mem_size() const; size_t wasted_mem_size() const; - G1CardSetMemoryStats memory_stats() const; + G1SegmentedArrayMemoryStats memory_stats() const; }; #endif // SHARE_GC_G1_G1CARDSETMEMORY_HPP diff --git a/src/hotspot/share/gc/g1/g1CardSetMemory.inline.hpp b/src/hotspot/share/gc/g1/g1CardSetMemory.inline.hpp index 0eaac226b593e62c07f187abb27ab92d19f05df2..bdf69e227dfc661f3af4351ce6c45a6a8218d031 100644 --- a/src/hotspot/share/gc/g1/g1CardSetMemory.inline.hpp +++ b/src/hotspot/share/gc/g1/g1CardSetMemory.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -26,39 +26,15 @@ #define SHARE_GC_G1_G1CARDSETMEMORY_INLINE_HPP #include "gc/g1/g1CardSetMemory.hpp" -#include "gc/g1/g1CardSetContainers.hpp" -#include "gc/g1/g1SegmentedArray.inline.hpp" -#include "utilities/ostream.hpp" - #include "gc/g1/g1CardSetContainers.inline.hpp" +#include "gc/g1/g1SegmentedArray.inline.hpp" #include "utilities/globalCounter.inline.hpp" +#include "utilities/ostream.hpp" -template -G1CardSetContainer* volatile* G1CardSetAllocator::next_ptr(G1CardSetContainer& node) { - return node.next_addr(); -} - -template -Elem* G1CardSetAllocator::allocate() { - assert(_segmented_array.elem_size() > 0, "instance size not set."); - - if (num_free_elems() > 0) { - // Pop under critical section to deal with ABA problem - // Other solutions to the same problem are more complicated (ref counting, HP) - GlobalCounter::CriticalSection cs(Thread::current()); - - G1CardSetContainer* node = _free_nodes_list.pop(); - if (node != nullptr) { - Elem* elem = reinterpret_cast(reinterpret_cast(node)); - Atomic::sub(&_num_free_nodes, 1u); - guarantee(is_aligned(elem, 8), "result " PTR_FORMAT " not aligned", p2i(elem)); - return elem; - } - } - - Elem* elem = _segmented_array.allocate(); - assert(elem != nullptr, "must be"); - return elem; +inline void* G1CardSetAllocator::allocate() { + void* slot = _free_slots_list.allocate(); + assert(slot != nullptr, "must be"); + return slot; } inline uint8_t* G1CardSetMemoryManager::allocate(uint type) { @@ -74,9 +50,4 @@ inline void G1CardSetMemoryManager::free_node(void* value) { free(0, value); } -template -inline uint G1CardSetAllocator::num_free_elems() const { - return Atomic::load(&_num_free_nodes); -} - #endif // SHARE_GC_G1_G1CARDSETMEMORY_INLINE_HPP diff --git a/src/hotspot/share/gc/g1/g1CardTable.cpp b/src/hotspot/share/gc/g1/g1CardTable.cpp index 9e565c1ba64a6b9b26ae09a66053d768f5a74497..4fc6db5bac10ea92d42130abb5808015269bbe77 100644 --- a/src/hotspot/share/gc/g1/g1CardTable.cpp +++ b/src/hotspot/share/gc/g1/g1CardTable.cpp @@ -62,7 +62,7 @@ void G1CardTable::initialize(G1RegionToSpaceMapper* mapper) { _covered[0] = _whole_heap; _byte_map = (CardValue*) mapper->reserved().start(); - _byte_map_base = _byte_map - (uintptr_t(low_bound) >> card_shift); + _byte_map_base = _byte_map - (uintptr_t(low_bound) >> _card_shift); assert(byte_for(low_bound) == &_byte_map[0], "Checking start of map"); assert(byte_for(high_bound-1) <= &_byte_map[_last_valid_index], "Checking end of map"); diff --git a/src/hotspot/share/gc/g1/g1CardTable.hpp b/src/hotspot/share/gc/g1/g1CardTable.hpp index fd150db39f8dfa9102f8a9cd884cf1f7365aeb2c..e73cbfaf86d2f100374198b560ef619eada15465 100644 --- a/src/hotspot/share/gc/g1/g1CardTable.hpp +++ b/src/hotspot/share/gc/g1/g1CardTable.hpp @@ -110,12 +110,12 @@ public: inline uint region_idx_for(CardValue* p); static size_t compute_size(size_t mem_region_size_in_words) { - size_t number_of_slots = (mem_region_size_in_words / card_size_in_words); + size_t number_of_slots = (mem_region_size_in_words / _card_size_in_words); return ReservedSpace::allocation_align_size_up(number_of_slots); } // Returns how many bytes of the heap a single byte of the Card Table corresponds to. - static size_t heap_map_factor() { return card_size; } + static size_t heap_map_factor() { return _card_size; } void initialize() {} void initialize(G1RegionToSpaceMapper* mapper); diff --git a/src/hotspot/share/gc/g1/g1CardTable.inline.hpp b/src/hotspot/share/gc/g1/g1CardTable.inline.hpp index 41ffdf5318e30c1fb37b1ab162fc2cc6102d2737..d2962cbad845526fceb36755fce7f83f9042711b 100644 --- a/src/hotspot/share/gc/g1/g1CardTable.inline.hpp +++ b/src/hotspot/share/gc/g1/g1CardTable.inline.hpp @@ -31,7 +31,7 @@ inline uint G1CardTable::region_idx_for(CardValue* p) { size_t const card_idx = pointer_delta(p, _byte_map, sizeof(CardValue)); - return (uint)(card_idx >> (HeapRegion::LogOfHRGrainBytes - card_shift)); + return (uint)(card_idx >> (HeapRegion::LogOfHRGrainBytes - _card_shift)); } inline bool G1CardTable::mark_clean_as_dirty(CardValue* card) { diff --git a/src/hotspot/share/gc/g1/g1CodeBlobClosure.cpp b/src/hotspot/share/gc/g1/g1CodeBlobClosure.cpp index 725e0130388c069722c80c6838c910b978060bcf..f2dc595ef5369cf9a736afdebaff12c80db529c2 100644 --- a/src/hotspot/share/gc/g1/g1CodeBlobClosure.cpp +++ b/src/hotspot/share/gc/g1/g1CodeBlobClosure.cpp @@ -40,8 +40,8 @@ void G1CodeBlobClosure::HeapRegionGatheringOopClosure::do_oop_work(T* p) { if (!CompressedOops::is_null(oop_or_narrowoop)) { oop o = CompressedOops::decode_not_null(oop_or_narrowoop); HeapRegion* hr = _g1h->heap_region_containing(o); - assert(!_g1h->is_in_cset(o) || hr->rem_set()->strong_code_roots_list_contains(_nm), "if o still in collection set then evacuation failed and nm must already be in the remset"); - hr->add_strong_code_root(_nm); + assert(!_g1h->is_in_cset(o) || hr->rem_set()->code_roots_list_contains(_nm), "if o still in collection set then evacuation failed and nm must already be in the remset"); + hr->add_code_root(_nm); } } diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp index 13fce2dd1264bc821a192e5d0bf1da2cc906635e..3b6458b9f82b81f4131c7b80fb3953b33d0cb81a 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -33,7 +33,6 @@ #include "gc/g1/g1Arguments.hpp" #include "gc/g1/g1BarrierSet.hpp" #include "gc/g1/g1BatchedTask.hpp" -#include "gc/g1/g1CardSetFreeMemoryTask.hpp" #include "gc/g1/g1CollectedHeap.inline.hpp" #include "gc/g1/g1CollectionSet.hpp" #include "gc/g1/g1CollectionSetCandidates.hpp" @@ -65,13 +64,14 @@ #include "gc/g1/g1RootClosures.hpp" #include "gc/g1/g1RootProcessor.hpp" #include "gc/g1/g1SATBMarkQueueSet.hpp" +#include "gc/g1/g1SegmentedArrayFreeMemoryTask.hpp" +#include "gc/g1/g1ServiceThread.hpp" #include "gc/g1/g1ThreadLocalData.hpp" #include "gc/g1/g1Trace.hpp" -#include "gc/g1/g1ServiceThread.hpp" #include "gc/g1/g1UncommitRegionTask.hpp" #include "gc/g1/g1VMOperations.hpp" -#include "gc/g1/g1YoungGCEvacFailureInjector.hpp" #include "gc/g1/g1YoungCollector.hpp" +#include "gc/g1/g1YoungGCEvacFailureInjector.hpp" #include "gc/g1/heapRegion.inline.hpp" #include "gc/g1/heapRegionRemSet.inline.hpp" #include "gc/g1/heapRegionSet.inline.hpp" @@ -87,17 +87,17 @@ #include "gc/shared/locationPrinter.inline.hpp" #include "gc/shared/oopStorageParState.hpp" #include "gc/shared/preservedMarks.inline.hpp" -#include "gc/shared/suspendibleThreadSet.hpp" #include "gc/shared/referenceProcessor.inline.hpp" -#include "gc/shared/taskTerminator.hpp" +#include "gc/shared/suspendibleThreadSet.hpp" #include "gc/shared/taskqueue.inline.hpp" +#include "gc/shared/taskTerminator.hpp" #include "gc/shared/tlab_globals.hpp" -#include "gc/shared/weakProcessor.inline.hpp" #include "gc/shared/workerPolicy.hpp" +#include "gc/shared/weakProcessor.inline.hpp" #include "logging/log.hpp" #include "memory/allocation.hpp" -#include "memory/iterator.hpp" #include "memory/heapInspection.hpp" +#include "memory/iterator.hpp" #include "memory/metaspaceUtils.hpp" #include "memory/resourceArea.hpp" #include "memory/universe.hpp" @@ -1042,8 +1042,8 @@ void G1CollectedHeap::prepare_heap_for_mutators() { resize_heap_if_necessary(); uncommit_regions_if_necessary(); - // Rebuild the strong code root lists for each region - rebuild_strong_code_roots(); + // Rebuild the code root lists for each region + rebuild_code_roots(); // Purge code root memory purge_code_root_memory(); @@ -1098,7 +1098,7 @@ void G1CollectedHeap::verify_after_full_collection() { bool G1CollectedHeap::do_full_collection(bool explicit_gc, bool clear_all_soft_refs, - bool do_maximum_compaction) { + bool do_maximal_compaction) { assert_at_safepoint_on_vm_thread(); if (GCLocker::check_active_before_gc()) { @@ -1111,7 +1111,7 @@ bool G1CollectedHeap::do_full_collection(bool explicit_gc, G1FullGCMark gc_mark; GCTraceTime(Info, gc) tm("Pause Full", NULL, gc_cause(), true); - G1FullCollector collector(this, explicit_gc, do_clear_all_soft_refs, do_maximum_compaction); + G1FullCollector collector(this, explicit_gc, do_clear_all_soft_refs, do_maximal_compaction); collector.prepare_collection(); collector.collect(); @@ -1125,12 +1125,12 @@ void G1CollectedHeap::do_full_collection(bool clear_all_soft_refs) { // Currently, there is no facility in the do_full_collection(bool) API to notify // the caller that the collection did not succeed (e.g., because it was locked // out by the GC locker). So, right now, we'll ignore the return value. - // When clear_all_soft_refs is set we want to do a maximum compaction + // When clear_all_soft_refs is set we want to do a maximal compaction // not leaving any dead wood. - bool do_maximum_compaction = clear_all_soft_refs; + bool do_maximal_compaction = clear_all_soft_refs; bool dummy = do_full_collection(true, /* explicit_gc */ clear_all_soft_refs, - do_maximum_compaction); + do_maximal_compaction); } bool G1CollectedHeap::upgrade_to_full_collection() { @@ -1138,7 +1138,7 @@ bool G1CollectedHeap::upgrade_to_full_collection() { log_info(gc, ergo)("Attempting full compaction clearing soft references"); bool success = do_full_collection(false /* explicit gc */, true /* clear_all_soft_refs */, - false /* do_maximum_compaction */); + false /* do_maximal_compaction */); // do_full_collection only fails if blocked by GC locker and that can't // be the case here since we only call this when already completed one gc. assert(success, "invariant"); @@ -1162,7 +1162,7 @@ void G1CollectedHeap::resize_heap_if_necessary() { HeapWord* G1CollectedHeap::satisfy_failed_allocation_helper(size_t word_size, bool do_gc, - bool maximum_compaction, + bool maximal_compaction, bool expect_null_mutator_alloc_region, bool* gc_succeeded) { *gc_succeeded = true; @@ -1186,16 +1186,16 @@ HeapWord* G1CollectedHeap::satisfy_failed_allocation_helper(size_t word_size, if (do_gc) { GCCauseSetter compaction(this, GCCause::_g1_compaction_pause); // Expansion didn't work, we'll try to do a Full GC. - // If maximum_compaction is set we clear all soft references and don't + // If maximal_compaction is set we clear all soft references and don't // allow any dead wood to be left on the heap. - if (maximum_compaction) { - log_info(gc, ergo)("Attempting maximum full compaction clearing soft references"); + if (maximal_compaction) { + log_info(gc, ergo)("Attempting maximal full compaction clearing soft references"); } else { log_info(gc, ergo)("Attempting full compaction"); } *gc_succeeded = do_full_collection(false, /* explicit_gc */ - maximum_compaction /* clear_all_soft_refs */ , - maximum_compaction /* do_maximum_compaction */); + maximal_compaction /* clear_all_soft_refs */ , + maximal_compaction /* do_maximal_compaction */); } return NULL; @@ -1431,7 +1431,7 @@ G1CollectedHeap::G1CollectedHeap() : CollectedHeap(), _service_thread(NULL), _periodic_gc_task(NULL), - _free_card_set_memory_task(NULL), + _free_segmented_array_memory_task(NULL), _workers(NULL), _card_table(NULL), _collection_pause_end(Ticks::now()), @@ -1660,7 +1660,7 @@ jint G1CollectedHeap::initialize() { // The G1FromCardCache reserves card with value 0 as "invalid", so the heap must not // start within the first card. - guarantee(heap_rs.base() >= (char*)G1CardTable::card_size, "Java heap must not start within the first card."); + guarantee((uintptr_t)(heap_rs.base()) >= G1CardTable::card_size(), "Java heap must not start within the first card."); G1FromCardCache::initialize(max_reserved_regions()); // Also create a G1 rem set. _rem_set = new G1RemSet(this, _card_table, _hot_card_cache); @@ -1723,14 +1723,8 @@ jint G1CollectedHeap::initialize() { _periodic_gc_task = new G1PeriodicGCTask("Periodic GC Task"); _service_thread->register_task(_periodic_gc_task); - _free_card_set_memory_task = new G1CardSetFreeMemoryTask("Card Set Free Memory Task"); - _service_thread->register_task(_free_card_set_memory_task); - - { - G1DirtyCardQueueSet& dcqs = G1BarrierSet::dirty_card_queue_set(); - dcqs.set_process_cards_threshold(concurrent_refine()->yellow_zone()); - dcqs.set_max_cards(concurrent_refine()->red_zone()); - } + _free_segmented_array_memory_task = new G1SegmentedArrayFreeMemoryTask("Card Set Free Memory Task"); + _service_thread->register_task(_free_segmented_array_memory_task); // Here we allocate the dummy HeapRegion that is required by the // G1AllocRegion class. @@ -1828,7 +1822,6 @@ void G1CollectedHeap::ref_processing_init() { ParallelGCThreads, // degree of mt processing // We discover with the gc worker threads during Remark, so both // thread counts must be considered for discovery. - (ParallelGCThreads > 1) || (ConcGCThreads > 1), // mt discovery MAX2(ParallelGCThreads, ConcGCThreads), // degree of mt discovery true, // Reference discovery is concurrent &_is_alive_closure_cm); // is alive closure @@ -1837,7 +1830,6 @@ void G1CollectedHeap::ref_processing_init() { _ref_processor_stw = new ReferenceProcessor(&_is_subject_to_discovery_stw, ParallelGCThreads, // degree of mt processing - (ParallelGCThreads > 1), // mt discovery ParallelGCThreads, // degree of mt discovery false, // Reference discovery is not concurrent &_is_alive_closure_stw); // is alive closure @@ -2262,7 +2254,7 @@ void G1CollectedHeap::object_iterate(ObjectClosure* cl) { heap_region_iterate(&blk); } -class G1ParallelObjectIterator : public ParallelObjectIterator { +class G1ParallelObjectIterator : public ParallelObjectIteratorImpl { private: G1CollectedHeap* _heap; HeapRegionClaimer _claimer; @@ -2277,7 +2269,7 @@ public: } }; -ParallelObjectIterator* G1CollectedHeap::parallel_object_iterator(uint thread_num) { +ParallelObjectIteratorImpl* G1CollectedHeap::parallel_object_iterator(uint thread_num) { return new G1ParallelObjectIterator(thread_num); } @@ -2413,7 +2405,6 @@ bool G1CollectedHeap::is_obj_dead_cond(const oop obj, const VerifyOption vo) const { switch (vo) { case VerifyOption_G1UsePrevMarking: return is_obj_dead(obj, hr); - case VerifyOption_G1UseNextMarking: return is_obj_ill(obj, hr); case VerifyOption_G1UseFullMarking: return is_obj_dead_full(obj, hr); default: ShouldNotReachHere(); } @@ -2424,7 +2415,6 @@ bool G1CollectedHeap::is_obj_dead_cond(const oop obj, const VerifyOption vo) const { switch (vo) { case VerifyOption_G1UsePrevMarking: return is_obj_dead(obj); - case VerifyOption_G1UseNextMarking: return is_obj_ill(obj); case VerifyOption_G1UseFullMarking: return is_obj_dead_full(obj); default: ShouldNotReachHere(); } @@ -2618,8 +2608,8 @@ void G1CollectedHeap::gc_epilogue(bool full) { _collection_pause_end = Ticks::now(); - _free_card_set_memory_task->notify_new_stats(&_young_gen_card_set_stats, - &_collection_set_candidates_card_set_stats); + _free_segmented_array_memory_task->notify_new_stats(&_young_gen_card_set_stats, + &_collection_set_candidates_card_set_stats); } uint G1CollectedHeap::uncommit_regions(uint region_limit) { @@ -2943,11 +2933,11 @@ bool G1CollectedHeap::should_sample_collection_set_candidates() const { return candidates != NULL && candidates->num_remaining() > 0; } -void G1CollectedHeap::set_collection_set_candidates_stats(G1CardSetMemoryStats& stats) { +void G1CollectedHeap::set_collection_set_candidates_stats(G1SegmentedArrayMemoryStats& stats) { _collection_set_candidates_card_set_stats = stats; } -void G1CollectedHeap::set_young_gen_card_set_stats(const G1CardSetMemoryStats& stats) { +void G1CollectedHeap::set_young_gen_card_set_stats(const G1SegmentedArrayMemoryStats& stats) { _young_gen_card_set_stats = stats; } @@ -2959,14 +2949,18 @@ void G1CollectedHeap::record_obj_copy_mem_stats() { create_g1_evac_summary(&_old_evac_stats)); } +void G1CollectedHeap::clear_prev_bitmap_for_region(HeapRegion* hr) { + MemRegion mr(hr->bottom(), hr->end()); + concurrent_mark()->clear_range_in_prev_bitmap(mr); +} + void G1CollectedHeap::free_region(HeapRegion* hr, FreeRegionList* free_list) { assert(!hr->is_free(), "the region should not be free"); assert(!hr->is_empty(), "the region should not be empty"); assert(_hrm.is_available(hr->hrm_index()), "region should be committed"); if (G1VerifyBitmaps) { - MemRegion mr(hr->bottom(), hr->end()); - concurrent_mark()->clear_range_in_prev_bitmap(mr); + clear_prev_bitmap_for_region(hr); } // Clear the card counts for this region. @@ -3293,7 +3287,6 @@ void G1CollectedHeap::retire_gc_alloc_region(HeapRegion* alloc_region, _bytes_used_during_gc += allocated_bytes; if (dest.is_old()) { old_set_add(alloc_region); - alloc_region->update_bot_threshold(); } else { assert(dest.is_young(), "Retiring alloc region should be young (%d)", dest.type()); _survivor.add_used_bytes(allocated_bytes); @@ -3320,6 +3313,13 @@ HeapRegion* G1CollectedHeap::alloc_highest_free_region() { return NULL; } +void G1CollectedHeap::mark_evac_failure_object(const oop obj, uint worker_id) const { + // All objects failing evacuation are live. What we'll do is + // that we'll update the prev marking info so that they are + // all under PTAMS and explicitly marked. + _cm->par_mark_in_prev_bitmap(obj); +} + // Optimized nmethod scanning class RegisterNMethodOopClosure: public OopClosure { @@ -3340,8 +3340,8 @@ public: " starting at " HR_FORMAT, p2i(_nm), HR_FORMAT_PARAMS(hr), HR_FORMAT_PARAMS(hr->humongous_start_region())); - // HeapRegion::add_strong_code_root_locked() avoids adding duplicate entries. - hr->add_strong_code_root_locked(_nm); + // HeapRegion::add_code_root_locked() avoids adding duplicate entries. + hr->add_code_root_locked(_nm); } } @@ -3366,7 +3366,7 @@ public: " starting at " HR_FORMAT, p2i(_nm), HR_FORMAT_PARAMS(hr), HR_FORMAT_PARAMS(hr->humongous_start_region())); - hr->remove_strong_code_root(_nm); + hr->remove_code_root(_nm); } } @@ -3409,11 +3409,11 @@ void G1CollectedHeap::purge_code_root_memory() { G1CodeRootSet::purge(); } -class RebuildStrongCodeRootClosure: public CodeBlobClosure { +class RebuildCodeRootClosure: public CodeBlobClosure { G1CollectedHeap* _g1h; public: - RebuildStrongCodeRootClosure(G1CollectedHeap* g1h) : + RebuildCodeRootClosure(G1CollectedHeap* g1h) : _g1h(g1h) {} void do_code_blob(CodeBlob* cb) { @@ -3426,8 +3426,8 @@ public: } }; -void G1CollectedHeap::rebuild_strong_code_roots() { - RebuildStrongCodeRootClosure blob_cl(this); +void G1CollectedHeap::rebuild_code_roots() { + RebuildCodeRootClosure blob_cl(this); CodeCache::blobs_do(&blob_cl); } diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp index 513c60ed3912e39b6822a1f15eabe04efd9eac33..de2442c7ce57588fa70feccb6129180b7bd3bd2e 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp @@ -27,20 +27,21 @@ #include "gc/g1/g1BarrierSet.hpp" #include "gc/g1/g1BiasedArray.hpp" -#include "gc/g1/g1CardSetFreeMemoryTask.hpp" #include "gc/g1/g1CardTable.hpp" +#include "gc/g1/g1CardSet.hpp" #include "gc/g1/g1CollectionSet.hpp" #include "gc/g1/g1CollectorState.hpp" #include "gc/g1/g1ConcurrentMark.hpp" #include "gc/g1/g1EdenRegions.hpp" #include "gc/g1/g1EvacStats.hpp" #include "gc/g1/g1GCPauseType.hpp" +#include "gc/g1/g1HeapRegionAttr.hpp" #include "gc/g1/g1HeapTransition.hpp" #include "gc/g1/g1HeapVerifier.hpp" #include "gc/g1/g1HRPrinter.hpp" -#include "gc/g1/g1HeapRegionAttr.hpp" #include "gc/g1/g1MonitoringSupport.hpp" #include "gc/g1/g1NUMA.hpp" +#include "gc/g1/g1SegmentedArrayFreeMemoryTask.hpp" #include "gc/g1/g1SurvivorRegions.hpp" #include "gc/g1/g1YoungGCEvacFailureInjector.hpp" #include "gc/g1/heapRegionManager.hpp" @@ -143,7 +144,7 @@ class G1CollectedHeap : public CollectedHeap { private: G1ServiceThread* _service_thread; G1ServiceTask* _periodic_gc_task; - G1CardSetFreeMemoryTask* _free_card_set_memory_task; + G1SegmentedArrayFreeMemoryTask* _free_segmented_array_memory_task; WorkerThreads* _workers; G1CardTable* _card_table; @@ -160,9 +161,9 @@ private: HeapRegionSet _humongous_set; // Young gen memory statistics before GC. - G1CardSetMemoryStats _young_gen_card_set_stats; + G1SegmentedArrayMemoryStats _young_gen_card_set_stats; // Collection set candidates memory statistics after GC. - G1CardSetMemoryStats _collection_set_candidates_card_set_stats; + G1SegmentedArrayMemoryStats _collection_set_candidates_card_set_stats; // The block offset table for the G1 heap. G1BlockOffsetTable* _bot; @@ -259,8 +260,8 @@ public: void set_humongous_stats(uint num_humongous_total, uint num_humongous_candidates); bool should_sample_collection_set_candidates() const; - void set_collection_set_candidates_stats(G1CardSetMemoryStats& stats); - void set_young_gen_card_set_stats(const G1CardSetMemoryStats& stats); + void set_collection_set_candidates_stats(G1SegmentedArrayMemoryStats& stats); + void set_young_gen_card_set_stats(const G1SegmentedArrayMemoryStats& stats); private: @@ -486,13 +487,13 @@ private: // otherwise it's for a failed allocation. // - if clear_all_soft_refs is true, all soft references should be // cleared during the GC. - // - if do_maximum_compaction is true, full gc will do a maximally + // - if do_maximal_compaction is true, full gc will do a maximally // compacting collection, leaving no dead wood. // - it returns false if it is unable to do the collection due to the // GC locker being active, true otherwise. bool do_full_collection(bool explicit_gc, bool clear_all_soft_refs, - bool do_maximum_compaction); + bool do_maximal_compaction); // Callback from VM_G1CollectFull operation, or collect_as_vm_thread. void do_full_collection(bool clear_all_soft_refs) override; @@ -518,7 +519,7 @@ private: // Helper method for satisfy_failed_allocation() HeapWord* satisfy_failed_allocation_helper(size_t word_size, bool do_gc, - bool maximum_compaction, + bool maximal_compaction, bool expect_null_mutator_alloc_region, bool* gc_succeeded); @@ -622,6 +623,8 @@ public: // for all regions. void verify_region_attr_remset_is_tracked() PRODUCT_RETURN; + void clear_prev_bitmap_for_region(HeapRegion* hr); + bool is_user_requested_concurrent_full_gc(GCCause::Cause cause); // This is called at the start of either a concurrent cycle or a Full @@ -777,8 +780,6 @@ public: // Start a concurrent cycle. void start_concurrent_cycle(bool concurrent_operation_is_full_mark); - void wait_for_root_region_scanning(); - void prepare_tlabs_for_mutator(); void retire_tlabs(); @@ -936,9 +937,6 @@ public: void fill_with_dummy_object(HeapWord* start, HeapWord* end, bool zap) override; - // Try to minimize the remembered set. - void scrub_rem_set(); - // Apply the given closure on all cards in the Hot Card Cache, emptying it. void iterate_hcc_closure(G1CardTableEntryClosure* cl, uint worker_id); @@ -1082,7 +1080,7 @@ public: // Iterate over all objects, calling "cl.do_object" on each. void object_iterate(ObjectClosure* cl) override; - ParallelObjectIterator* parallel_object_iterator(uint thread_num) override; + ParallelObjectIteratorImpl* parallel_object_iterator(uint thread_num) override; // Keep alive an object that was loaded with AS_NO_KEEPALIVE. void keep_alive(oop obj) override; @@ -1181,7 +1179,7 @@ public: size_t max_tlab_size() const override; size_t unsafe_max_tlab_alloc(Thread* ignored) const override; - inline bool is_in_young(const oop obj); + inline bool is_in_young(const oop obj) const; // Returns "true" iff the given word_size is "very large". static bool is_humongous(size_t word_size) { @@ -1239,11 +1237,6 @@ public: // the region to which the object belongs. inline bool is_obj_dead(const oop obj, const HeapRegion* hr) const; - // This function returns true when an object has been - // around since the previous marking and hasn't yet - // been marked during this marking, and is not in a closed archive region. - inline bool is_obj_ill(const oop obj, const HeapRegion* hr) const; - // Determine if an object is dead, given only the object itself. // This will find the region to which the object belongs and // then call the region version of the same function. @@ -1252,11 +1245,12 @@ public: inline bool is_obj_dead(const oop obj) const; - inline bool is_obj_ill(const oop obj) const; - inline bool is_obj_dead_full(const oop obj, const HeapRegion* hr) const; inline bool is_obj_dead_full(const oop obj) const; + // Mark the live object that failed evacuation in the prev bitmap. + void mark_evac_failure_object(const oop obj, uint worker_id) const; + G1ConcurrentMark* concurrent_mark() const { return _cm; } // Refinement @@ -1287,9 +1281,9 @@ public: // Free up superfluous code root memory. void purge_code_root_memory(); - // Rebuild the strong code root lists for each region + // Rebuild the code root lists for each region // after a full GC. - void rebuild_strong_code_roots(); + void rebuild_code_roots(); // Performs cleaning of data structures after class unloading. void complete_cleaning(BoolObjectClosure* is_alive, bool class_unloading_occurred); @@ -1302,15 +1296,11 @@ public: // Perform verification. // vo == UsePrevMarking -> use "prev" marking information, - // vo == UseNextMarking -> use "next" marking information // vo == UseFullMarking -> use "next" marking bitmap but no TAMS // // NOTE: Only the "prev" marking information is guaranteed to be // consistent most of the time, so most calls to this should use // vo == UsePrevMarking. - // Currently, there is only one case where this is called with - // vo == UseNextMarking, which is to verify the "next" marking - // information at the end of remark. // Currently there is only one place where this is called with // vo == UseFullMarking, which is to verify the marking during a // full GC. diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.inline.hpp b/src/hotspot/share/gc/g1/g1CollectedHeap.inline.hpp index 2e0f6028a5da781bc7cdf3532e7b110f45ddef1f..0cd8de23e56871578153d4d58547f43def5bdb40 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.inline.hpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.inline.hpp @@ -41,6 +41,12 @@ #include "runtime/atomic.hpp" #include "utilities/bitMap.inline.hpp" +inline bool G1STWIsAliveClosure::do_object_b(oop p) { + // An object is reachable if it is outside the collection set, + // or is inside and copied. + return !_g1h->is_in_cset(p) || p->is_forwarded(); +} + G1GCPhaseTimes* G1CollectedHeap::phase_times() const { return _policy->phase_times(); } @@ -201,7 +207,7 @@ void G1CollectedHeap::register_optional_region_with_region_attr(HeapRegion* r) { _region_attr.set_optional(r->hrm_index(), r->rem_set()->is_tracked()); } -inline bool G1CollectedHeap::is_in_young(const oop obj) { +inline bool G1CollectedHeap::is_in_young(const oop obj) const { if (obj == NULL) { return false; } @@ -219,20 +225,6 @@ inline bool G1CollectedHeap::is_obj_dead(const oop obj) const { return is_obj_dead(obj, heap_region_containing(obj)); } -inline bool G1CollectedHeap::is_obj_ill(const oop obj, const HeapRegion* hr) const { - return - !hr->obj_allocated_since_next_marking(obj) && - !is_marked_next(obj) && - !hr->is_closed_archive(); -} - -inline bool G1CollectedHeap::is_obj_ill(const oop obj) const { - if (obj == NULL) { - return false; - } - return is_obj_ill(obj, heap_region_containing(obj)); -} - inline bool G1CollectedHeap::is_obj_dead_full(const oop obj, const HeapRegion* hr) const { return !is_marked_next(obj) && !hr->is_closed_archive(); } diff --git a/src/hotspot/share/gc/g1/g1CollectionSetChooser.hpp b/src/hotspot/share/gc/g1/g1CollectionSetChooser.hpp index 5692a0c407e273dfa07ab877b03e7a88c0f752cd..e8894323d651837505c767f5512ce8170886162d 100644 --- a/src/hotspot/share/gc/g1/g1CollectionSetChooser.hpp +++ b/src/hotspot/share/gc/g1/g1CollectionSetChooser.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -26,7 +26,7 @@ #define SHARE_GC_G1_G1COLLECTIONSETCHOOSER_HPP #include "gc/g1/heapRegion.hpp" -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" #include "runtime/globals.hpp" class G1CollectionSetCandidates; diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp index 9d533cb89cbd4c4d349012ee942285dc85bf7e3c..5d0c0dd605daa1ae9c4e870a89e2d7b080b45595 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp @@ -770,7 +770,7 @@ public: double worker_cost() const override { // The work done per region is very small, therefore we choose this magic number to cap the number // of threads used when there are few regions. - const uint regions_per_thread = 1000; + const double regions_per_thread = 1000; return _claimer.n_regions() / regions_per_thread; } @@ -1618,10 +1618,6 @@ void G1ConcurrentMark::weak_refs_work() { uint active_workers = (ParallelRefProcEnabled ? _g1h->workers()->active_workers() : 1U); active_workers = clamp(active_workers, 1u, _max_num_tasks); - // Set the concurrency level. The phase was already set prior to - // executing the remark task. - set_concurrency(active_workers); - // Set the degree of MT processing here. If the discovery was done MT, // the number of threads involved during discovery could differ from // the number of active workers. This is OK as long as the discovered @@ -1650,9 +1646,10 @@ void G1ConcurrentMark::weak_refs_work() { if (has_overflown()) { // We can not trust g1_is_alive and the contents of the heap if the marking stack // overflowed while processing references. Exit the VM. - fatal("Overflow during reference processing, can not continue. Please " - "increase MarkStackSizeMax (current value: " SIZE_FORMAT ") and " - "restart.", MarkStackSizeMax); + fatal("Overflow during reference processing, can not continue. Current mark stack depth: " + SIZE_FORMAT ", MarkStackSize: " SIZE_FORMAT ", MarkStackSizeMax: " SIZE_FORMAT ". " + "Please increase MarkStackSize and/or MarkStackSizeMax and restart.", + _global_mark_stack.size(), MarkStackSize, MarkStackSizeMax); return; } @@ -2012,13 +2009,21 @@ void G1ConcurrentMark::print_stats() { } void G1ConcurrentMark::concurrent_cycle_abort() { - if (!cm_thread()->in_progress() || _has_aborted) { - // We haven't started a concurrent cycle or we have already aborted it. No need to do anything. + // We haven't started a concurrent cycle no need to do anything; we might have + // aborted the marking because of shutting down though. In this case the marking + // might have already completed the abort (leading to in_progress() below to + // return false), however this still left marking state particularly in the + // shared marking bitmap that must be cleaned up. + // If there are multiple full gcs during shutdown we do this work repeatedly for + // nothing, but this situation should be extremely rare (a full gc after shutdown + // has been signalled is alredy rare), and this work should be negligible compared + // to actual full gc work. + if (!cm_thread()->in_progress() && !_g1h->concurrent_mark_is_terminating()) { return; } - // Clear all marks in the next bitmap for the next marking cycle. This will allow us to skip the next - // concurrent bitmap clearing. + // Clear all marks in the next bitmap for this full gc as it has been used by the + // marking that is interrupted by this full gc. { GCTraceTime(Debug, gc) debug("Clear Next Bitmap"); clear_next_bitmap(_g1h->workers()); @@ -2032,9 +2037,8 @@ void G1ConcurrentMark::concurrent_cycle_abort() { for (uint i = 0; i < _max_num_tasks; ++i) { _tasks[i]->clear_region_fields(); } - _first_overflow_barrier_sync.abort(); - _second_overflow_barrier_sync.abort(); - _has_aborted = true; + + abort_marking_threads(); SATBMarkQueueSet& satb_mq_set = G1BarrierSet::satb_mark_queue_set(); satb_mq_set.abandon_partial_marking(); @@ -2045,6 +2049,13 @@ void G1ConcurrentMark::concurrent_cycle_abort() { satb_mq_set.is_active() /* expected_active */); } +void G1ConcurrentMark::abort_marking_threads() { + assert(!_root_regions.scan_in_progress(), "still doing root region scan"); + _has_aborted = true; + _first_overflow_barrier_sync.abort(); + _second_overflow_barrier_sync.abort(); +} + static void print_ms_time_info(const char* prefix, const char* name, NumberSeq& ns) { log_trace(gc, marking)("%s%5d %12s: total time = %8.2f s (avg = %8.2f ms).", @@ -2943,7 +2954,7 @@ G1CMTask::G1CMTask(uint worker_id, G1PrintRegionLivenessInfoClosure::G1PrintRegionLivenessInfoClosure(const char* phase_name) : _total_used_bytes(0), _total_capacity_bytes(0), _total_prev_live_bytes(0), _total_next_live_bytes(0), - _total_remset_bytes(0), _total_strong_code_roots_bytes(0) + _total_remset_bytes(0), _total_code_roots_bytes(0) { if (!log_is_enabled(Trace, gc, liveness)) { return; @@ -3003,7 +3014,7 @@ bool G1PrintRegionLivenessInfoClosure::do_heap_region(HeapRegion* r) { size_t next_live_bytes = r->next_live_bytes(); double gc_eff = r->gc_efficiency(); size_t remset_bytes = r->rem_set()->mem_size(); - size_t strong_code_roots_bytes = r->rem_set()->strong_code_roots_mem_size(); + size_t code_roots_bytes = r->rem_set()->code_roots_mem_size(); const char* remset_type = r->rem_set()->get_short_state_str(); FormatBuffer<16> gc_efficiency(""); @@ -3012,7 +3023,7 @@ bool G1PrintRegionLivenessInfoClosure::do_heap_region(HeapRegion* r) { _total_prev_live_bytes += prev_live_bytes; _total_next_live_bytes += next_live_bytes; _total_remset_bytes += remset_bytes; - _total_strong_code_roots_bytes += strong_code_roots_bytes; + _total_code_roots_bytes += code_roots_bytes; if(gc_eff < 0) { gc_efficiency.append("-"); @@ -3033,7 +3044,7 @@ bool G1PrintRegionLivenessInfoClosure::do_heap_region(HeapRegion* r) { G1PPRL_BYTE_FORMAT, type, p2i(bottom), p2i(end), used_bytes, prev_live_bytes, next_live_bytes, gc_efficiency.buffer(), - remset_bytes, remset_type, strong_code_roots_bytes); + remset_bytes, remset_type, code_roots_bytes); return false; } @@ -3063,5 +3074,5 @@ G1PrintRegionLivenessInfoClosure::~G1PrintRegionLivenessInfoClosure() { bytes_to_mb(_total_next_live_bytes), percent_of(_total_next_live_bytes, _total_capacity_bytes), bytes_to_mb(_total_remset_bytes), - bytes_to_mb(_total_strong_code_roots_bytes)); + bytes_to_mb(_total_code_roots_bytes)); } diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp index 28752225f133688726d2731fa676d5c6577076ba..cc603df18c4d650a7f87cbe04364f42b57bf52af 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp @@ -496,6 +496,11 @@ public: void concurrent_cycle_abort(); void concurrent_cycle_end(); + // Notifies marking threads to abort. This is a best-effort notification. Does not + // guarantee or update any state after the call. Root region scan must not be + // running. + void abort_marking_threads(); + void update_accum_task_vtime(int i, double vtime) { _accum_task_vtime[i] += vtime; } @@ -563,7 +568,7 @@ public: void cleanup(); // Mark in the previous bitmap. Caution: the prev bitmap is usually read-only, so use // this carefully. - inline void mark_in_prev_bitmap(oop p); + inline void par_mark_in_prev_bitmap(oop p); // Clears marks for all objects in the given range, for the prev or // next bitmaps. Caution: the previous bitmap is usually @@ -842,8 +847,8 @@ class G1PrintRegionLivenessInfoClosure : public HeapRegionClosure { // Accumulator for the remembered set size size_t _total_remset_bytes; - // Accumulator for strong code roots memory size - size_t _total_strong_code_roots_bytes; + // Accumulator for code roots memory size + size_t _total_code_roots_bytes; static double bytes_to_mb(size_t val) { return (double) val / (double) M; diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.inline.hpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.inline.hpp index 9d45803e2ef9963e2a1f318590dceefc64bfdc01..73575e0f532dbc20c8334f97dfb107eb9a527582 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMark.inline.hpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.inline.hpp @@ -41,7 +41,26 @@ #include "utilities/bitMap.inline.hpp" inline bool G1CMIsAliveClosure::do_object_b(oop obj) { - return !_g1h->is_obj_ill(obj); + // Check whether the passed in object is null. During discovery the referent + // may be cleared between the initial check and being passed in here. + if (obj == NULL) { + // Return true to avoid discovery when the referent is NULL. + return true; + } + + HeapRegion* hr = _g1h->heap_region_containing(cast_from_oop(obj)); + // All objects allocated since the start of marking are considered live. + if (hr->obj_allocated_since_next_marking(obj)) { + return true; + } + + // All objects in closed archive regions are live. + if (hr->is_closed_archive()) { + return true; + } + + // All objects that are marked are live. + return _g1h->is_marked_next(obj); } inline bool G1CMSubjectToDiscoveryClosure::do_object_b(oop obj) { @@ -110,7 +129,6 @@ inline void G1CMTask::push(G1TaskQueueEntry task_entry) { assert(task_entry.is_array_slice() || _g1h->is_in_reserved(task_entry.obj()), "invariant"); assert(task_entry.is_array_slice() || !_g1h->is_on_master_free_list( _g1h->heap_region_containing(task_entry.obj())), "invariant"); - assert(task_entry.is_array_slice() || !_g1h->is_obj_ill(task_entry.obj()), "invariant"); // FIXME!!! assert(task_entry.is_array_slice() || _next_mark_bitmap->is_marked(cast_from_oop(task_entry.obj())), "invariant"); if (!_task_queue->push(task_entry)) { @@ -268,9 +286,8 @@ inline bool G1CMTask::deal_with_reference(T* p) { return make_reference_grey(obj); } -inline void G1ConcurrentMark::mark_in_prev_bitmap(oop p) { - assert(!_prev_mark_bitmap->is_marked(p), "sanity"); - _prev_mark_bitmap->mark(p); +inline void G1ConcurrentMark::par_mark_in_prev_bitmap(oop p) { + _prev_mark_bitmap->par_mark(p); } bool G1ConcurrentMark::is_marked_in_prev_bitmap(oop p) const { diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMarkThread.cpp b/src/hotspot/share/gc/g1/g1ConcurrentMarkThread.cpp index dde620e9398f852b2d326e9776270b532f717e75..d7bdd8ea9a564eee148779de6793e622d4f796ea 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMarkThread.cpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMarkThread.cpp @@ -56,26 +56,6 @@ G1ConcurrentMarkThread::G1ConcurrentMarkThread(G1ConcurrentMark* cm) : create_and_start(); } -class CMRemark : public VoidClosure { - G1ConcurrentMark* _cm; -public: - CMRemark(G1ConcurrentMark* cm) : _cm(cm) {} - - void do_void(){ - _cm->remark(); - } -}; - -class CMCleanup : public VoidClosure { - G1ConcurrentMark* _cm; -public: - CMCleanup(G1ConcurrentMark* cm) : _cm(cm) {} - - void do_void(){ - _cm->cleanup(); - } -}; - double G1ConcurrentMarkThread::mmu_delay_end(G1Policy* policy, bool remark) { // There are 3 reasons to use SuspendibleThreadSetJoiner. // 1. To avoid concurrency problem. @@ -159,6 +139,15 @@ void G1ConcurrentMarkThread::run_service() { } void G1ConcurrentMarkThread::stop_service() { + if (in_progress()) { + // We are not allowed to abort the marking threads during root region scan. + // Needs to be done separately. + _cm->root_regions()->abort(); + _cm->root_regions()->wait_until_scan_finished(); + + _cm->abort_marking_threads(); + } + MutexLocker ml(CGC_lock, Mutex::_no_safepoint_check_flag); CGC_lock->notify_all(); } @@ -239,8 +228,7 @@ bool G1ConcurrentMarkThread::subphase_delay_to_keep_mmu_before_remark() { bool G1ConcurrentMarkThread::subphase_remark() { ConcurrentGCBreakpoints::at("BEFORE MARKING COMPLETED"); - CMRemark cl(_cm); - VM_G1Concurrent op(&cl, "Pause Remark"); + VM_G1PauseRemark op; VMThread::execute(&op); return _cm->has_aborted(); } @@ -257,8 +245,7 @@ bool G1ConcurrentMarkThread::phase_delay_to_keep_mmu_before_cleanup() { } bool G1ConcurrentMarkThread::phase_cleanup() { - CMCleanup cl(_cm); - VM_G1Concurrent op(&cl, "Pause Cleanup"); + VM_G1PauseCleanup op; VMThread::execute(&op); return _cm->has_aborted(); } diff --git a/src/hotspot/share/gc/g1/g1ConcurrentRefine.cpp b/src/hotspot/share/gc/g1/g1ConcurrentRefine.cpp index 7d8076f3cf3c6d80e8d3304de25f4caf86b67acb..d879568e34c08866d49b10c210966cf86600252d 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentRefine.cpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentRefine.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -42,7 +42,7 @@ G1ConcurrentRefineThread* G1ConcurrentRefineThreadControl::create_refinement_thread(uint worker_id, bool initializing) { G1ConcurrentRefineThread* result = NULL; if (initializing || !InjectGCWorkerCreationFailure) { - result = new G1ConcurrentRefineThread(_cr, worker_id); + result = G1ConcurrentRefineThread::create(_cr, worker_id); } if (result == NULL || result->osthread() == NULL) { log_warning(gc)("Failed to create refinement thread %u, no more %s", @@ -53,8 +53,9 @@ G1ConcurrentRefineThread* G1ConcurrentRefineThreadControl::create_refinement_thr } G1ConcurrentRefineThreadControl::G1ConcurrentRefineThreadControl() : - _cr(NULL), - _threads(NULL), + _cr(nullptr), + _primary_thread(nullptr), + _threads(nullptr), _num_max_threads(0) { } @@ -76,22 +77,27 @@ jint G1ConcurrentRefineThreadControl::initialize(G1ConcurrentRefine* cr, uint nu _threads = NEW_C_HEAP_ARRAY(G1ConcurrentRefineThread*, num_max_threads, mtGC); - for (uint i = 0; i < num_max_threads; i++) { - if (UseDynamicNumberOfGCThreads && i != 0 /* Always start first thread. */) { - _threads[i] = NULL; - } else { - _threads[i] = create_refinement_thread(i, true); - if (_threads[i] == NULL) { - vm_shutdown_during_initialization("Could not allocate refinement threads."); - return JNI_ENOMEM; + if (num_max_threads > 0) { + auto primary = G1PrimaryConcurrentRefineThread::create(cr); + if (primary == nullptr) { + vm_shutdown_during_initialization("Could not allocate primary refinement thread"); + return JNI_ENOMEM; + } + _threads[0] = _primary_thread = primary; + + for (uint i = 1; i < num_max_threads; ++i) { + if (UseDynamicNumberOfGCThreads) { + _threads[i] = nullptr; + } else { + _threads[i] = create_refinement_thread(i, true); + if (_threads[i] == nullptr) { + vm_shutdown_during_initialization("Could not allocate refinement threads."); + return JNI_ENOMEM; + } } } } - if (num_max_threads > 0) { - G1BarrierSet::dirty_card_queue_set().set_primary_refinement_thread(_threads[0]); - } - return JNI_OK; } @@ -237,7 +243,18 @@ G1ConcurrentRefine::G1ConcurrentRefine(size_t green_zone, } jint G1ConcurrentRefine::initialize() { - return _thread_control.initialize(this, max_num_threads()); + jint result = _thread_control.initialize(this, max_num_threads()); + if (result != JNI_OK) return result; + + G1DirtyCardQueueSet& dcqs = G1BarrierSet::dirty_card_queue_set(); + dcqs.set_max_cards(red_zone()); + if (max_num_threads() > 0) { + G1PrimaryConcurrentRefineThread* primary_thread = _thread_control.primary_thread(); + primary_thread->update_notify_threshold(primary_activation_threshold()); + dcqs.set_refinement_notification_thread(primary_thread); + } + + return JNI_OK; } static size_t calc_min_yellow_zone_size() { @@ -250,14 +267,21 @@ static size_t calc_min_yellow_zone_size() { } } +// An initial guess at the rate for pause-time card refinement for one +// thread, used when computing the default initial green zone value. +const double InitialPauseTimeCardRefinementRate = 200.0; + static size_t calc_init_green_zone() { - size_t green = G1ConcRefinementGreenZone; - const char* name = "G1ConcRefinementGreenZone"; + size_t green; if (FLAG_IS_DEFAULT(G1ConcRefinementGreenZone)) { - green = ParallelGCThreads; - name = "ParallelGCThreads"; + const double rate = InitialPauseTimeCardRefinementRate * ParallelGCThreads; + // The time budget for pause-time card refinement. + const double ms = MaxGCPauseMillis * (G1RSetUpdatingPauseTimePercent / 100.0); + green = rate * ms; + } else { + green = configuration_buffers_to_cards(G1ConcRefinementGreenZone, + "G1ConcRefinementGreenZone"); } - green = configuration_buffers_to_cards(green, name); return MIN2(green, max_green_zone); } @@ -385,14 +409,9 @@ void G1ConcurrentRefine::adjust(double logged_cards_scan_time, update_zones(logged_cards_scan_time, processed_logged_cards, goal_ms); // Change the barrier params - if (max_num_threads() == 0) { - // Disable dcqs notification when there are no threads to notify. - dcqs.set_process_cards_threshold(G1DirtyCardQueueSet::ProcessCardsThresholdNever); - } else { - // Worker 0 is the primary; wakeup is via dcqs notification. - STATIC_ASSERT(max_yellow_zone <= INT_MAX); - size_t activate = activation_threshold(0); - dcqs.set_process_cards_threshold(activate); + if (max_num_threads() > 0) { + size_t threshold = primary_activation_threshold(); + _thread_control.primary_thread()->update_notify_threshold(threshold); } dcqs.set_max_cards(red_zone()); } @@ -404,7 +423,6 @@ void G1ConcurrentRefine::adjust(double logged_cards_scan_time, } else { dcqs.set_max_cards_padding(0); } - dcqs.notify_if_necessary(); } G1ConcurrentRefineStats G1ConcurrentRefine::get_and_reset_refinement_stats() { @@ -431,6 +449,11 @@ size_t G1ConcurrentRefine::deactivation_threshold(uint worker_id) const { return deactivation_level(thresholds); } +size_t G1ConcurrentRefine::primary_activation_threshold() const { + assert(max_num_threads() > 0, "No primary refinement thread"); + return activation_threshold(0); +} + uint G1ConcurrentRefine::worker_id_offset() { return G1DirtyCardQueueSet::num_par_ids(); } diff --git a/src/hotspot/share/gc/g1/g1ConcurrentRefine.hpp b/src/hotspot/share/gc/g1/g1ConcurrentRefine.hpp index b904e47a76a00749c0a82d6555f5751463d380e3..feb82dd20676e2dfabe55847f5092798a0a02d7d 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentRefine.hpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentRefine.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -27,20 +27,20 @@ #include "gc/g1/g1ConcurrentRefineStats.hpp" #include "memory/allocation.hpp" +#include "utilities/debug.hpp" #include "utilities/globalDefinitions.hpp" -#include "utilities/ticks.hpp" // Forward decl class G1ConcurrentRefine; class G1ConcurrentRefineThread; -class outputStream; +class G1PrimaryConcurrentRefineThread; class ThreadClosure; // Helper class for refinement thread management. Used to start, stop and // iterate over them. class G1ConcurrentRefineThreadControl { G1ConcurrentRefine* _cr; - + G1PrimaryConcurrentRefineThread* _primary_thread; G1ConcurrentRefineThread** _threads; uint _num_max_threads; @@ -53,6 +53,12 @@ public: jint initialize(G1ConcurrentRefine* cr, uint num_max_threads); + G1PrimaryConcurrentRefineThread* primary_thread() const { + assert(_num_max_threads > 0, "precondition"); + assert(_primary_thread != nullptr, "uninitialized"); + return _primary_thread; + } + // If there is a "successor" thread that can be activated given the current id, // activate it. void maybe_activate_next(uint cur_worker_id); @@ -116,6 +122,10 @@ public: void stop(); + // The minimum number of pending cards for activation of the primary + // refinement thread. + size_t primary_activation_threshold() const; + // Adjust refinement thresholds based on work done during the pause and the goal time. void adjust(double logged_cards_scan_time, size_t processed_logged_cards, double goal_ms); diff --git a/src/hotspot/share/gc/g1/g1ConcurrentRefineStats.cpp b/src/hotspot/share/gc/g1/g1ConcurrentRefineStats.cpp index 055fd8b891df2e72dec66d3ed290cb786a5b06c5..3e8f83326b2708bc6252f5d9bd3cc4324cde4016 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentRefineStats.cpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentRefineStats.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -32,6 +32,12 @@ G1ConcurrentRefineStats::G1ConcurrentRefineStats() : _dirtied_cards(0) {} +double G1ConcurrentRefineStats::refinement_rate_ms() const { + // Report 0 when no time recorded because no refinement performed. + double secs = refinement_time().seconds(); + return (secs > 0) ? (refined_cards() / (secs * MILLIUNITS)) : 0.0; +} + G1ConcurrentRefineStats& G1ConcurrentRefineStats::operator+=(const G1ConcurrentRefineStats& other) { _refinement_time += other._refinement_time; diff --git a/src/hotspot/share/gc/g1/g1ConcurrentRefineStats.hpp b/src/hotspot/share/gc/g1/g1ConcurrentRefineStats.hpp index d0e17301a5fa06fc7cc8784a2594a78b265e5bdf..ae576778a070243d3de0f1345b1e456319f85d73 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentRefineStats.hpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentRefineStats.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -47,6 +47,9 @@ public: // Number of refined cards. size_t refined_cards() const { return _refined_cards; } + // Refinement rate, in cards per ms. + double refinement_rate_ms() const; + // Number of cards for which refinement was skipped because some other // thread had already refined them. size_t precleaned_cards() const { return _precleaned_cards; } diff --git a/src/hotspot/share/gc/g1/g1ConcurrentRefineThread.cpp b/src/hotspot/share/gc/g1/g1ConcurrentRefineThread.cpp index e57617114d26761ec82d29040fa949c8fe8923f9..ece63ed805ab30f59f44465f69a62a2bc75a633c 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentRefineThread.cpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentRefineThread.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -31,6 +31,8 @@ #include "gc/shared/suspendibleThreadSet.hpp" #include "logging/log.hpp" #include "runtime/atomic.hpp" +#include "runtime/init.hpp" +#include "runtime/safepoint.hpp" #include "runtime/thread.hpp" G1ConcurrentRefineThread::G1ConcurrentRefineThread(G1ConcurrentRefine* cr, uint worker_id) : @@ -39,75 +41,20 @@ G1ConcurrentRefineThread::G1ConcurrentRefineThread(G1ConcurrentRefine* cr, uint _vtime_accum(0.0), _refinement_stats(new G1ConcurrentRefineStats()), _worker_id(worker_id), - _notifier(new Semaphore(0)), - _should_notify(true), _cr(cr) { // set name set_name("G1 Refine#%d", worker_id); - create_and_start(); } G1ConcurrentRefineThread::~G1ConcurrentRefineThread() { delete _refinement_stats; - delete _notifier; -} - -void G1ConcurrentRefineThread::wait_for_completed_buffers() { - assert(this == Thread::current(), "precondition"); - while (Atomic::load_acquire(&_should_notify)) { - _notifier->wait(); - } -} - -void G1ConcurrentRefineThread::activate() { - assert(this != Thread::current(), "precondition"); - // Notify iff transitioning from needing activation to not. This helps - // keep the semaphore count bounded and minimizes the work done by - // activators when the thread is already active. - if (Atomic::load_acquire(&_should_notify) && - Atomic::cmpxchg(&_should_notify, true, false)) { - _notifier->signal(); - } -} - -bool G1ConcurrentRefineThread::maybe_deactivate(bool more_work) { - assert(this == Thread::current(), "precondition"); - - if (more_work) { - // Suppress unnecessary notifications. - Atomic::release_store(&_should_notify, false); - return false; - } else if (Atomic::load_acquire(&_should_notify)) { - // Deactivate if no notifications since enabled (see below). - return true; - } else { - // Try for more refinement work with notifications enabled, to close - // race; there could be a plethora of suppressed activation attempts - // after we found no work but before we enable notifications here - // (so there could be lots of work for this thread to do), followed - // by a long time without activation after enabling notifications. - // But first, clear any pending signals to prevent accumulation. - while (_notifier->trywait()) {} - Atomic::release_store(&_should_notify, true); - return false; - } } void G1ConcurrentRefineThread::run_service() { _vtime_start = os::elapsedVTime(); - while (!should_terminate()) { - // Wait for work - wait_for_completed_buffers(); - if (should_terminate()) { - break; - } - - log_debug(gc, refine)("Activated worker %d, on threshold: " SIZE_FORMAT ", current: " SIZE_FORMAT, - _worker_id, _cr->activation_threshold(_worker_id), - G1BarrierSet::dirty_card_queue_set().num_cards()); - + while (wait_for_completed_buffers()) { // For logging. G1ConcurrentRefineStats start_stats = *_refinement_stats; G1ConcurrentRefineStats total_stats; // Accumulate over activation. @@ -115,6 +62,10 @@ void G1ConcurrentRefineThread::run_service() { { SuspendibleThreadSetJoiner sts_join; + log_debug(gc, refine)("Activated worker %d, on threshold: %zu, current: %zu", + _worker_id, _cr->activation_threshold(_worker_id), + G1BarrierSet::dirty_card_queue_set().num_cards()); + while (!should_terminate()) { if (sts_join.should_yield()) { // Accumulate changed stats before possible GC that resets stats. @@ -125,18 +76,21 @@ void G1ConcurrentRefineThread::run_service() { continue; // Re-check for termination after yield delay. } - bool more_work = _cr->do_refinement_step(_worker_id, _refinement_stats); - if (maybe_deactivate(more_work)) break; + if (!_cr->do_refinement_step(_worker_id, _refinement_stats)) { + if (maybe_deactivate()) { + break; + } + } } } total_stats += *_refinement_stats - start_stats; - log_debug(gc, refine)("Deactivated worker %d, off threshold: " SIZE_FORMAT - ", current: " SIZE_FORMAT - ", refined cards: " SIZE_FORMAT, + log_debug(gc, refine)("Deactivated worker %d, off threshold: %zu, " + "cards: %zu, refined %zu, rate %1.2fc/ms", _worker_id, _cr->deactivation_threshold(_worker_id), G1BarrierSet::dirty_card_queue_set().num_cards(), - total_stats.refined_cards()); + total_stats.refined_cards(), + total_stats.refinement_rate_ms()); if (os::supports_vtime()) { _vtime_accum = (os::elapsedVTime() - _vtime_start); @@ -151,3 +105,164 @@ void G1ConcurrentRefineThread::run_service() { void G1ConcurrentRefineThread::stop_service() { activate(); } + +G1PrimaryConcurrentRefineThread* +G1PrimaryConcurrentRefineThread::create(G1ConcurrentRefine* cr) { + G1PrimaryConcurrentRefineThread* crt = + new (std::nothrow) G1PrimaryConcurrentRefineThread(cr); + if (crt != nullptr) { + crt->create_and_start(); + } + return crt; +} + +G1PrimaryConcurrentRefineThread::G1PrimaryConcurrentRefineThread(G1ConcurrentRefine* cr) : + G1ConcurrentRefineThread(cr, 0), + _notifier(0), + _threshold(0) +{} + +void G1PrimaryConcurrentRefineThread::stop_service() { + G1DirtyCardQueueSet& dcqs = G1BarrierSet::dirty_card_queue_set(); + dcqs.set_refinement_notification_thread(nullptr); + G1ConcurrentRefineThread::stop_service(); +} + +// The primary refinement thread is notified when buffers/cards are added to +// the dirty card queue. That can happen in fairly arbitrary contexts. +// This means there may be arbitrary other locks held when notifying. We +// also don't want to have to take a lock on the fairly common notification +// path, as contention for that lock can significantly impact performance. +// +// We use a semaphore to implement waiting and unblocking, to avoid +// lock rank checking issues. (We could alternatively use an +// arbitrarily low ranked mutex.) The atomic variable _threshold is +// used to decide when to signal the semaphore. When its value is +// SIZE_MAX then the thread is running. Otherwise, the thread should +// be requested to run when notified that the number of cards has +// exceeded the threshold value. + +bool G1PrimaryConcurrentRefineThread::wait_for_completed_buffers() { + assert(this == Thread::current(), "precondition"); + _notifier.wait(); + assert(Atomic::load(&_threshold) == SIZE_MAX || should_terminate(), "incorrect state"); + return !should_terminate(); +} + +bool G1PrimaryConcurrentRefineThread::maybe_deactivate() { + assert(this == Thread::current(), "precondition"); + assert(Atomic::load(&_threshold) == SIZE_MAX, "incorrect state"); + Atomic::store(&_threshold, cr()->primary_activation_threshold()); + // Always deactivate when no refinement work found. New refinement + // work may have arrived after we tried, but checking for that would + // still be racy. Instead, the next time additional work is made + // available we'll get reactivated. + return true; +} + +void G1PrimaryConcurrentRefineThread::activate() { + assert(this != Thread::current(), "precondition"); + // The thread is running when notifications are disabled, so shouldn't + // signal is this case. But there's a race between stop requests and + // maybe_deactivate, so also signal if stop requested. + size_t threshold = Atomic::load(&_threshold); + if (((threshold != SIZE_MAX) && + (threshold == Atomic::cmpxchg(&_threshold, threshold, SIZE_MAX))) || + should_terminate()) { + _notifier.signal(); + } +} + +void G1PrimaryConcurrentRefineThread::notify(size_t num_cards) { + // Only activate if the number of pending cards exceeds the activation + // threshold. Notification is disabled when the thread is running, by + // setting _threshold to SIZE_MAX. A relaxed load is sufficient; we don't + // need to be precise about this. + if (num_cards > Atomic::load(&_threshold)) { + // Discard notifications occurring during a safepoint. A GC safepoint + // may dirty some cards (such as during reference processing), possibly + // leading to notification. End-of-GC update_notify_threshold activates + // the primary thread if needed. Non-GC safepoints are expected to + // rarely (if ever) dirty cards, so defer activation to a post-safepoint + // notification. + if (!SafepointSynchronize::is_at_safepoint()) { + activate(); + } + } +} + +void G1PrimaryConcurrentRefineThread::update_notify_threshold(size_t threshold) { +#ifdef ASSERT + if (is_init_completed()) { + assert_at_safepoint(); + assert(Thread::current()->is_VM_thread(), "precondition"); + } +#endif // ASSERT + // If _threshold is SIZE_MAX then the thread is active and the value + // of _threshold shouldn't be changed. + if (Atomic::load(&_threshold) != SIZE_MAX) { + Atomic::store(&_threshold, threshold); + if (G1BarrierSet::dirty_card_queue_set().num_cards() > threshold) { + activate(); + } + } +} + +class G1SecondaryConcurrentRefineThread final : public G1ConcurrentRefineThread { + Monitor _notifier; + bool _requested_active; + + bool wait_for_completed_buffers() override; + bool maybe_deactivate() override; + +public: + G1SecondaryConcurrentRefineThread(G1ConcurrentRefine* cr, uint worker_id); + + void activate() override; +}; + +G1SecondaryConcurrentRefineThread::G1SecondaryConcurrentRefineThread(G1ConcurrentRefine* cr, + uint worker_id) : + G1ConcurrentRefineThread(cr, worker_id), + _notifier(Mutex::nosafepoint, this->name(), true), + _requested_active(false) +{ + assert(worker_id > 0, "precondition"); +} + +bool G1SecondaryConcurrentRefineThread::wait_for_completed_buffers() { + assert(this == Thread::current(), "precondition"); + MonitorLocker ml(&_notifier, Mutex::_no_safepoint_check_flag); + while (!_requested_active && !should_terminate()) { + ml.wait(); + } + return !should_terminate(); +} + +void G1SecondaryConcurrentRefineThread::activate() { + assert(this != Thread::current(), "precondition"); + MonitorLocker ml(&_notifier, Mutex::_no_safepoint_check_flag); + if (!_requested_active || should_terminate()) { + _requested_active = true; + ml.notify(); + } +} + +bool G1SecondaryConcurrentRefineThread::maybe_deactivate() { + assert(this == Thread::current(), "precondition"); + MutexLocker ml(&_notifier, Mutex::_no_safepoint_check_flag); + bool requested = _requested_active; + _requested_active = false; + return !requested; // Deactivate if not recently requested active. +} + +G1ConcurrentRefineThread* +G1ConcurrentRefineThread::create(G1ConcurrentRefine* cr, uint worker_id) { + assert(worker_id > 0, "precondition"); + G1ConcurrentRefineThread* crt = + new (std::nothrow) G1SecondaryConcurrentRefineThread(cr, worker_id); + if (crt != nullptr) { + crt->create_and_start(); + } + return crt; +} diff --git a/src/hotspot/share/gc/g1/g1ConcurrentRefineThread.hpp b/src/hotspot/share/gc/g1/g1ConcurrentRefineThread.hpp index cdcab6b22859c664b261aa64b4f5c4d55c974c60..218609dd76c0a7812fd08c7fc47e4026c26e1e54 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentRefineThread.hpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentRefineThread.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -26,7 +26,9 @@ #define SHARE_GC_G1_G1CONCURRENTREFINETHREAD_HPP #include "gc/shared/concurrentGCThread.hpp" -#include "utilities/ticks.hpp" +#include "memory/padded.hpp" +#include "runtime/semaphore.hpp" +#include "utilities/macros.hpp" // Forward Decl. class G1ConcurrentRefine; @@ -45,36 +47,34 @@ class G1ConcurrentRefineThread: public ConcurrentGCThread { uint _worker_id; - // _notifier and _should_notify form a single-reader / multi-writer - // notification mechanism. The owning concurrent refinement thread is the - // single reader. The writers are (other) threads that call activate() on - // the thread. The i-th concurrent refinement thread is responsible for - // activating thread i+1 if the number of buffers in the queue exceeds a - // threshold for that i+1th thread. The 0th (primary) thread is activated - // by threads that add cards to the dirty card queue set when the primary - // thread's threshold is exceeded. activate() is also used to wake up the - // threads during termination, so even the non-primary thread case is - // multi-writer. - Semaphore* _notifier; - volatile bool _should_notify; + G1ConcurrentRefine* _cr; + + NONCOPYABLE(G1ConcurrentRefineThread); + +protected: + G1ConcurrentRefineThread(G1ConcurrentRefine* cr, uint worker_id); + + // Returns !should_terminate(). + // precondition: this is the current thread. + virtual bool wait_for_completed_buffers() = 0; // Called when no refinement work found for this thread. // Returns true if should deactivate. - bool maybe_deactivate(bool more_work); + // precondition: this is the current thread. + virtual bool maybe_deactivate() = 0; - G1ConcurrentRefine* _cr; - - void wait_for_completed_buffers(); + G1ConcurrentRefine* cr() const { return _cr; } - virtual void run_service(); - virtual void stop_service(); + void run_service() override; + void stop_service() override; public: - G1ConcurrentRefineThread(G1ConcurrentRefine* cg1r, uint worker_id); + static G1ConcurrentRefineThread* create(G1ConcurrentRefine* cr, uint worker_id); virtual ~G1ConcurrentRefineThread(); // Activate this thread. - void activate(); + // precondition: this is not the current thread. + virtual void activate() = 0; G1ConcurrentRefineStats* refinement_stats() const { return _refinement_stats; @@ -84,4 +84,37 @@ public: double vtime_accum() { return _vtime_accum; } }; +// Singleton special refinement thread, registered with the dirty card queue. +// This thread supports notification of increases to the number of cards in +// the dirty card queue, which may trigger activation of this thread when it +// is not already running. +class G1PrimaryConcurrentRefineThread final : public G1ConcurrentRefineThread { + // Support for activation. The thread waits on this semaphore when idle. + // Calls to activate signal it to wake the thread. + Semaphore _notifier; + DEFINE_PAD_MINUS_SIZE(0, DEFAULT_CACHE_LINE_SIZE, 0); + // Used as both the activation threshold and also the "is active" state. + // The value is SIZE_MAX when the thread is active, otherwise the threshold + // for signaling the semaphore. + volatile size_t _threshold; + DEFINE_PAD_MINUS_SIZE(1, DEFAULT_CACHE_LINE_SIZE, sizeof(size_t)); + + bool wait_for_completed_buffers() override; + bool maybe_deactivate() override; + + G1PrimaryConcurrentRefineThread(G1ConcurrentRefine* cr); + + void stop_service() override; + +public: + static G1PrimaryConcurrentRefineThread* create(G1ConcurrentRefine* cr); + + void activate() override; + + // Used by the write barrier support to activate the thread if needed when + // there are new refinement buffers. + void notify(size_t num_cards); + void update_notify_threshold(size_t threshold); +}; + #endif // SHARE_GC_G1_G1CONCURRENTREFINETHREAD_HPP diff --git a/src/hotspot/share/gc/g1/g1DirtyCardQueue.cpp b/src/hotspot/share/gc/g1/g1DirtyCardQueue.cpp index 9819328ee669dac107c82efc54d97b77b098bfd2..136f5849dbb60bfd659fbcdfbe6468fd0f37413d 100644 --- a/src/hotspot/share/gc/g1/g1DirtyCardQueue.cpp +++ b/src/hotspot/share/gc/g1/g1DirtyCardQueue.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -24,7 +24,6 @@ #include "precompiled.hpp" #include "gc/g1/g1BarrierSet.inline.hpp" -#include "gc/g1/g1BufferNodeList.hpp" #include "gc/g1/g1CardTableEntryClosure.hpp" #include "gc/g1/g1CollectedHeap.inline.hpp" #include "gc/g1/g1ConcurrentRefineStats.hpp" @@ -35,6 +34,7 @@ #include "gc/g1/g1RemSet.hpp" #include "gc/g1/g1ThreadLocalData.hpp" #include "gc/g1/heapRegionRemSet.inline.hpp" +#include "gc/shared/bufferNodeList.hpp" #include "gc/shared/suspendibleThreadSet.hpp" #include "memory/iterator.hpp" #include "runtime/atomic.hpp" @@ -66,12 +66,11 @@ static uint par_ids_start() { return 0; } G1DirtyCardQueueSet::G1DirtyCardQueueSet(BufferNode::Allocator* allocator) : PtrQueueSet(allocator), - _primary_refinement_thread(NULL), + _refinement_notification_thread(nullptr), _num_cards(0), _completed(), _paused(), _free_ids(par_ids_start(), num_par_ids()), - _process_cards_threshold(ProcessCardsThresholdNever), _max_cards(MaxCardsUnlimited), _padded_max_cards(MaxCardsUnlimited), _detached_refinement_stats() @@ -118,15 +117,24 @@ void G1DirtyCardQueueSet::handle_zero_index_for_thread(Thread* t) { G1BarrierSet::dirty_card_queue_set().handle_zero_index(queue); } +size_t G1DirtyCardQueueSet::num_cards() const { + return Atomic::load(&_num_cards); +} + void G1DirtyCardQueueSet::enqueue_completed_buffer(BufferNode* cbn) { assert(cbn != NULL, "precondition"); // Increment _num_cards before adding to queue, so queue removal doesn't // need to deal with _num_cards possibly going negative. size_t new_num_cards = Atomic::add(&_num_cards, buffer_size() - cbn->index()); - _completed.push(*cbn); - if ((new_num_cards > process_cards_threshold()) && - (_primary_refinement_thread != NULL)) { - _primary_refinement_thread->activate(); + { + // Perform push in CS. The old tail may be popped while the push is + // observing it (attaching it to the new buffer). We need to ensure it + // can't be reused until the push completes, to avoid ABA problems. + GlobalCounter::CriticalSection cs(Thread::current()); + _completed.push(*cbn); + } + if (_refinement_notification_thread != nullptr) { + _refinement_notification_thread->notify(new_num_cards); } } @@ -307,7 +315,7 @@ void G1DirtyCardQueueSet::enqueue_all_paused_buffers() { } void G1DirtyCardQueueSet::abandon_completed_buffers() { - G1BufferNodeList list = take_all_completed_buffers(); + BufferNodeList list = take_all_completed_buffers(); BufferNode* buffers_to_delete = list._head; while (buffers_to_delete != NULL) { BufferNode* bn = buffers_to_delete; @@ -317,31 +325,24 @@ void G1DirtyCardQueueSet::abandon_completed_buffers() { } } -void G1DirtyCardQueueSet::notify_if_necessary() { - if ((_primary_refinement_thread != NULL) && - (num_cards() > process_cards_threshold())) { - _primary_refinement_thread->activate(); - } -} - // Merge lists of buffers. The source queue set is emptied as a // result. The queue sets must share the same allocator. void G1DirtyCardQueueSet::merge_bufferlists(G1RedirtyCardsQueueSet* src) { assert(allocator() == src->allocator(), "precondition"); - const G1BufferNodeList from = src->take_all_completed_buffers(); + const BufferNodeList from = src->take_all_completed_buffers(); if (from._head != NULL) { Atomic::add(&_num_cards, from._entry_count); _completed.append(*from._head, *from._tail); } } -G1BufferNodeList G1DirtyCardQueueSet::take_all_completed_buffers() { +BufferNodeList G1DirtyCardQueueSet::take_all_completed_buffers() { enqueue_all_paused_buffers(); verify_num_cards(); Pair pair = _completed.take_all(); size_t num_cards = Atomic::load(&_num_cards); Atomic::store(&_num_cards, size_t(0)); - return G1BufferNodeList(pair.first, pair.second, num_cards); + return BufferNodeList(pair.first, pair.second, num_cards); } class G1RefineBufferedCards : public StackObj { @@ -495,6 +496,14 @@ void G1DirtyCardQueueSet::handle_completed_buffer(BufferNode* new_node, return; } + // Don't try to process a buffer that will just get immediately paused. + // When going into a safepoint it's just a waste of effort. + // When coming out of a safepoint, Java threads may be running before the + // yield request (for non-Java threads) has been cleared. + if (SuspendibleThreadSet::should_yield()) { + return; + } + // Only Java threads perform mutator refinement. if (!Thread::current()->is_Java_thread()) { return; diff --git a/src/hotspot/share/gc/g1/g1DirtyCardQueue.hpp b/src/hotspot/share/gc/g1/g1DirtyCardQueue.hpp index 9e9ad0ee80cddb67a71c7818bb648108c0ebb9d3..097efe957f7b5d044ffce5c94f883128420b8b14 100644 --- a/src/hotspot/share/gc/g1/g1DirtyCardQueue.hpp +++ b/src/hotspot/share/gc/g1/g1DirtyCardQueue.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -25,16 +25,16 @@ #ifndef SHARE_GC_G1_G1DIRTYCARDQUEUE_HPP #define SHARE_GC_G1_G1DIRTYCARDQUEUE_HPP -#include "gc/g1/g1BufferNodeList.hpp" #include "gc/g1/g1FreeIdSet.hpp" #include "gc/g1/g1CardTable.hpp" #include "gc/g1/g1ConcurrentRefineStats.hpp" +#include "gc/shared/bufferNodeList.hpp" #include "gc/shared/ptrQueue.hpp" #include "memory/allocation.hpp" #include "memory/padded.hpp" #include "utilities/nonblockingQueue.hpp" -class G1ConcurrentRefineThread; +class G1PrimaryConcurrentRefineThread; class G1DirtyCardQueueSet; class G1RedirtyCardsQueueSet; class Thread; @@ -69,7 +69,7 @@ public: class G1DirtyCardQueueSet: public PtrQueueSet { // Head and tail of a list of BufferNodes, linked through their next() - // fields. Similar to G1BufferNodeList, but without the _entry_count. + // fields. Similar to BufferNodeList, but without the _entry_count. struct HeadTail { BufferNode* _head; BufferNode* _tail; @@ -156,10 +156,10 @@ class G1DirtyCardQueueSet: public PtrQueueSet { HeadTail take_all(); }; - // The primary refinement thread, for activation when the processing - // threshold is reached. NULL if there aren't any refinement threads. - G1ConcurrentRefineThread* _primary_refinement_thread; - DEFINE_PAD_MINUS_SIZE(1, DEFAULT_CACHE_LINE_SIZE, sizeof(G1ConcurrentRefineThread*)); + // The refinement notification thread, for activation when the notification + // threshold is reached. nullptr if there aren't any refinement threads. + G1PrimaryConcurrentRefineThread* _refinement_notification_thread; + DEFINE_PAD_MINUS_SIZE(1, DEFAULT_CACHE_LINE_SIZE, sizeof(G1PrimaryConcurrentRefineThread*)); // Upper bound on the number of cards in the completed and paused buffers. volatile size_t _num_cards; DEFINE_PAD_MINUS_SIZE(2, DEFAULT_CACHE_LINE_SIZE, sizeof(size_t)); @@ -174,9 +174,6 @@ class G1DirtyCardQueueSet: public PtrQueueSet { G1FreeIdSet _free_ids; - // Activation threshold for the primary refinement thread. - size_t _process_cards_threshold; - // If the queue contains more cards than configured here, the // mutator must start doing some of the concurrent refinement work. size_t _max_cards; @@ -242,10 +239,6 @@ public: G1DirtyCardQueueSet(BufferNode::Allocator* allocator); ~G1DirtyCardQueueSet(); - void set_primary_refinement_thread(G1ConcurrentRefineThread* thread) { - _primary_refinement_thread = thread; - } - // The number of parallel ids that can be claimed to allow collector or // mutator threads to do card-processing work. static uint num_par_ids(); @@ -254,28 +247,20 @@ public: virtual void enqueue_completed_buffer(BufferNode* node); - // Upper bound on the number of cards currently in in this queue set. + // Upper bound on the number of cards currently in this queue set. // Read without synchronization. The value may be high because there // is a concurrent modification of the set of buffers. - size_t num_cards() const { return _num_cards; } + size_t num_cards() const; - // Get/Set the number of cards that triggers log processing. - // Log processing should be done when the number of cards exceeds the - // threshold. - void set_process_cards_threshold(size_t sz) { - _process_cards_threshold = sz; + // Record the primary concurrent refinement thread. This is the thread to + // be notified when num_cards() exceeds the refinement notification threshold. + void set_refinement_notification_thread(G1PrimaryConcurrentRefineThread* thread) { + _refinement_notification_thread = thread; } - size_t process_cards_threshold() const { - return _process_cards_threshold; - } - static const size_t ProcessCardsThresholdNever = SIZE_MAX; - - // Notify the consumer if the number of buffers crossed the threshold - void notify_if_necessary(); void merge_bufferlists(G1RedirtyCardsQueueSet* src); - G1BufferNodeList take_all_completed_buffers(); + BufferNodeList take_all_completed_buffers(); void flush_queue(G1DirtyCardQueue& queue); diff --git a/src/hotspot/share/gc/g1/g1EvacFailure.cpp b/src/hotspot/share/gc/g1/g1EvacFailure.cpp index e447b0f07763fb9f9c68996c4aaa02de996b989b..9f93239bab022d642deb791ba022176c76d93208 100644 --- a/src/hotspot/share/gc/g1/g1EvacFailure.cpp +++ b/src/hotspot/share/gc/g1/g1EvacFailure.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -28,16 +28,16 @@ #include "gc/g1/g1ConcurrentMark.inline.hpp" #include "gc/g1/g1EvacFailure.hpp" #include "gc/g1/g1EvacFailureRegions.hpp" +#include "gc/g1/g1GCPhaseTimes.hpp" #include "gc/g1/g1HeapVerifier.hpp" #include "gc/g1/g1OopClosures.inline.hpp" #include "gc/g1/heapRegion.hpp" #include "gc/g1/heapRegionRemSet.inline.hpp" -#include "gc/shared/preservedMarks.inline.hpp" #include "oops/access.inline.hpp" #include "oops/compressedOops.inline.hpp" #include "oops/oop.inline.hpp" -class RemoveSelfForwardPtrObjClosure: public ObjectClosure { +class RemoveSelfForwardPtrObjClosure { G1CollectedHeap* _g1h; G1ConcurrentMark* _cm; HeapRegion* _hr; @@ -60,13 +60,13 @@ public: size_t marked_bytes() { return _marked_words * HeapWordSize; } - // Iterate over the live objects in the region to find self-forwarded objects + // Handle the marked objects in the region. These are self-forwarded objects // that need to be kept live. We need to update the remembered sets of these // objects. Further update the BOT and marks. // We can coalesce and overwrite the remaining heap contents with dummy objects // as they have either been dead or evacuated (which are unreferenced now, i.e. // dead too) already. - void do_object(oop obj) { + size_t apply(oop obj) { HeapWord* obj_addr = cast_from_oop(obj); assert(_last_forwarded_object_end <= obj_addr, "should iterate in ascending address order"); assert(_hr->is_in(obj_addr), "sanity"); @@ -75,12 +75,8 @@ public: assert(obj->is_forwarded() && obj->forwardee() == obj, "sanity"); zap_dead_objects(_last_forwarded_object_end, obj_addr); - // We consider all objects that we find self-forwarded to be - // live. What we'll do is that we'll update the prev marking - // info so that they are all under PTAMS and explicitly marked. - if (!_cm->is_marked_in_prev_bitmap(obj)) { - _cm->mark_in_prev_bitmap(obj); - } + + assert(_cm->is_marked_in_prev_bitmap(obj), "should be correctly marked"); if (_during_concurrent_start) { // For the next marking info we'll only mark the // self-forwarded objects explicitly if we are during @@ -92,20 +88,23 @@ public: // explicitly and all objects in the CSet are considered // (implicitly) live. So, we won't mark them explicitly and // we'll leave them over NTAMS. - _cm->mark_in_next_bitmap(_worker_id, _hr, obj); + _cm->mark_in_next_bitmap(_worker_id, obj); } size_t obj_size = obj->size(); _marked_words += obj_size; - PreservedMarks::init_forwarded_mark(obj); + // Reset the markWord + obj->init_mark(); HeapWord* obj_end = obj_addr + obj_size; _last_forwarded_object_end = obj_end; - _hr->alloc_block_in_bot(obj_addr, obj_end); + _hr->update_bot_for_block(obj_addr, obj_end); + return obj_size; } // Fill the memory area from start to end with filler objects, and update the BOT - // and the mark bitmap accordingly. + // accordingly. Since we clear and use the prev bitmap for marking objects that + // failed evacuation, there is no work to be done there. void zap_dead_objects(HeapWord* start, HeapWord* end) { if (start == end) { return; @@ -117,13 +116,13 @@ public: CollectedHeap::fill_with_objects(start, gap_size); HeapWord* end_first_obj = start + cast_to_oop(start)->size(); - _hr->alloc_block_in_bot(start, end_first_obj); + _hr->update_bot_for_block(start, end_first_obj); // Fill_with_objects() may have created multiple (i.e. two) // objects, as the max_fill_size() is half a region. // After updating the BOT for the first object, also update the // BOT for the second object to make the BOT complete. if (end_first_obj != end) { - _hr->alloc_block_in_bot(end_first_obj, end); + _hr->update_bot_for_block(end_first_obj, end); #ifdef ASSERT size_t size_second_obj = cast_to_oop(end_first_obj)->size(); HeapWord* end_of_second_obj = end_first_obj + size_second_obj; @@ -134,7 +133,7 @@ public: #endif } } - _cm->clear_range_in_prev_bitmap(mr); + assert(!_cm->is_marked_in_prev_bitmap(cast_to_oop(start)), "should not be marked in prev bitmap"); } void zap_remainder() { @@ -148,12 +147,15 @@ class RemoveSelfForwardPtrHRClosure: public HeapRegionClosure { G1EvacFailureRegions* _evac_failure_regions; + G1GCPhaseTimes* _phase_times; + public: RemoveSelfForwardPtrHRClosure(uint worker_id, G1EvacFailureRegions* evac_failure_regions) : _g1h(G1CollectedHeap::heap()), _worker_id(worker_id), - _evac_failure_regions(evac_failure_regions) { + _evac_failure_regions(evac_failure_regions), + _phase_times(G1CollectedHeap::heap()->phase_times()) { } size_t remove_self_forward_ptr_by_walking_hr(HeapRegion* hr, @@ -161,8 +163,11 @@ public: RemoveSelfForwardPtrObjClosure rspc(hr, during_concurrent_start, _worker_id); - // Iterates evac failure objs which are recorded during evacuation. - hr->process_and_drop_evac_failure_objs(&rspc); + + // All objects that failed evacuation has been marked in the prev bitmap. + // Use the bitmap to apply the above closure to all failing objects. + G1CMBitMap* bitmap = const_cast(_g1h->concurrent_mark()->prev_mark_bitmap()); + hr->apply_to_marked_objects(bitmap, &rspc); // Need to zap the remainder area of the processed region. rspc.zap_remainder(); @@ -172,26 +177,29 @@ public: bool do_heap_region(HeapRegion *hr) { assert(!hr->is_pinned(), "Unexpected pinned region at index %u", hr->hrm_index()); assert(hr->in_collection_set(), "bad CS"); + assert(_evac_failure_regions->contains(hr->hrm_index()), "precondition"); - if (_evac_failure_regions->contains(hr->hrm_index())) { - hr->clear_index_in_opt_cset(); + hr->clear_index_in_opt_cset(); - bool during_concurrent_start = _g1h->collector_state()->in_concurrent_start_gc(); - bool during_concurrent_mark = _g1h->collector_state()->mark_or_rebuild_in_progress(); + bool during_concurrent_start = _g1h->collector_state()->in_concurrent_start_gc(); + bool during_concurrent_mark = _g1h->collector_state()->mark_or_rebuild_in_progress(); - hr->note_self_forwarding_removal_start(during_concurrent_start, - during_concurrent_mark); - _g1h->verifier()->check_bitmaps("Self-Forwarding Ptr Removal", hr); + hr->note_self_forwarding_removal_start(during_concurrent_start, + during_concurrent_mark); - hr->reset_bot(); + _phase_times->record_or_add_thread_work_item(G1GCPhaseTimes::RestoreRetainedRegions, + _worker_id, + 1, + G1GCPhaseTimes::RestoreRetainedRegionsNum); - size_t live_bytes = remove_self_forward_ptr_by_walking_hr(hr, during_concurrent_start); + size_t live_bytes = remove_self_forward_ptr_by_walking_hr(hr, during_concurrent_start); - hr->rem_set()->clean_strong_code_roots(hr); - hr->rem_set()->clear_locked(true); + hr->rem_set()->clean_code_roots(hr); + hr->rem_set()->clear_locked(true); + + hr->note_self_forwarding_removal_end(live_bytes); + _g1h->verifier()->check_bitmaps("Self-Forwarding Ptr Removal", hr); - hr->note_self_forwarding_removal_end(live_bytes); - } return false; } }; diff --git a/src/hotspot/share/gc/g1/g1EvacFailureObjectsSet.cpp b/src/hotspot/share/gc/g1/g1EvacFailureObjectsSet.cpp deleted file mode 100644 index deabc897ed86371df948b6519d1e0aebf63c3e94..0000000000000000000000000000000000000000 --- a/src/hotspot/share/gc/g1/g1EvacFailureObjectsSet.cpp +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (c) 2021, Huawei and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please 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/g1/g1EvacFailureObjectsSet.hpp" -#include "gc/g1/g1CollectedHeap.hpp" -#include "gc/g1/g1SegmentedArray.inline.hpp" -#include "gc/g1/heapRegion.inline.hpp" -#include "utilities/quickSort.hpp" - - -const G1SegmentedArrayAllocOptions G1EvacFailureObjectsSet::_alloc_options = - G1SegmentedArrayAllocOptions((uint)sizeof(OffsetInRegion), BufferLength, UINT_MAX, Alignment); - -G1SegmentedArrayBufferList G1EvacFailureObjectsSet::_free_buffer_list; - -#ifdef ASSERT -void G1EvacFailureObjectsSet::assert_is_valid_offset(size_t offset) const { - const uint max_offset = 1u << (HeapRegion::LogOfHRGrainBytes - LogHeapWordSize); - assert(offset < max_offset, "must be, but is " SIZE_FORMAT, offset); -} -#endif - -oop G1EvacFailureObjectsSet::from_offset(OffsetInRegion offset) const { - assert_is_valid_offset(offset); - return cast_to_oop(_bottom + offset); -} - -G1EvacFailureObjectsSet::OffsetInRegion G1EvacFailureObjectsSet::to_offset(oop obj) const { - const HeapWord* o = cast_from_oop(obj); - size_t offset = pointer_delta(o, _bottom); - assert(obj == from_offset(static_cast(offset)), "must be"); - return static_cast(offset); -} - -G1EvacFailureObjectsSet::G1EvacFailureObjectsSet(uint region_idx, HeapWord* bottom) : - DEBUG_ONLY(_region_idx(region_idx) COMMA) - _bottom(bottom), - _offsets(&_alloc_options, &_free_buffer_list) { - assert(HeapRegion::LogOfHRGrainBytes < 32, "must be"); -} - -// Helper class to join, sort and iterate over the previously collected segmented -// array of objects that failed evacuation. -class G1EvacFailureObjectsIterationHelper { - typedef G1EvacFailureObjectsSet::OffsetInRegion OffsetInRegion; - - G1EvacFailureObjectsSet* _objects_set; - const G1SegmentedArray* _segments; - OffsetInRegion* _offset_array; - uint _array_length; - - static int order_oop(OffsetInRegion a, OffsetInRegion b) { - return static_cast(a-b); - } - - void join_and_sort() { - _segments->iterate_nodes(*this); - - QuickSort::sort(_offset_array, _array_length, order_oop, true); - } - - void iterate(ObjectClosure* closure) { - for (uint i = 0; i < _array_length; i++) { - oop cur = _objects_set->from_offset(_offset_array[i]); - closure->do_object(cur); - } - } - -public: - G1EvacFailureObjectsIterationHelper(G1EvacFailureObjectsSet* collector) : - _objects_set(collector), - _segments(&_objects_set->_offsets), - _offset_array(nullptr), - _array_length(0) { } - - void process_and_drop(ObjectClosure* closure) { - uint num = _segments->num_allocated_nodes(); - _offset_array = NEW_C_HEAP_ARRAY(OffsetInRegion, num, mtGC); - - join_and_sort(); - assert(_array_length == num, "must be %u, %u", _array_length, num); - iterate(closure); - - FREE_C_HEAP_ARRAY(OffsetInRegion, _offset_array); - } - - // Callback of G1SegmentedArray::iterate_nodes - void do_buffer(G1SegmentedArrayBuffer* node, uint length) { - node->copy_to(&_offset_array[_array_length]); - _array_length += length; - } -}; - -void G1EvacFailureObjectsSet::process_and_drop(ObjectClosure* closure) { - assert_at_safepoint(); - - G1EvacFailureObjectsIterationHelper helper(this); - helper.process_and_drop(closure); - - _offsets.drop_all(); -} diff --git a/src/hotspot/share/gc/g1/g1EvacFailureObjectsSet.hpp b/src/hotspot/share/gc/g1/g1EvacFailureObjectsSet.hpp deleted file mode 100644 index a34e46dc96ce3884b3f1134a0f952641bebfdbbc..0000000000000000000000000000000000000000 --- a/src/hotspot/share/gc/g1/g1EvacFailureObjectsSet.hpp +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (c) 2021, Huawei and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please 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_G1_G1EVACUATIONFAILUREOBJSINHR_HPP -#define SHARE_GC_G1_G1EVACUATIONFAILUREOBJSINHR_HPP - -#include "gc/g1/g1SegmentedArray.hpp" -#include "memory/iterator.hpp" -#include "oops/oop.hpp" - -class G1EvacFailureObjectsIterationHelper; - -// This class collects addresses of objects that failed evacuation in a specific -// heap region. -// Provides sorted iteration of these elements for processing during the remove -// self forwards phase. -class G1EvacFailureObjectsSet { - friend class G1EvacFailureObjectsIterationHelper; - -public: - // Storage type of an object that failed evacuation within a region. Given - // heap region size and possible object locations within a region, it is - // sufficient to use an uint here to save some space instead of full pointers. - typedef uint OffsetInRegion; - -private: - static const uint BufferLength = 256; - static const uint Alignment = 4; - - static const G1SegmentedArrayAllocOptions _alloc_options; - - // This free list is shared among evacuation failure process in all regions. - static G1SegmentedArrayBufferList _free_buffer_list; - - DEBUG_ONLY(const uint _region_idx;) - - // Region bottom - const HeapWord* _bottom; - - // Offsets within region containing objects that failed evacuation. - G1SegmentedArray _offsets; - - void assert_is_valid_offset(size_t offset) const NOT_DEBUG_RETURN; - // Converts between an offset within a region and an oop address. - oop from_offset(OffsetInRegion offset) const; - OffsetInRegion to_offset(oop obj) const; - -public: - G1EvacFailureObjectsSet(uint region_idx, HeapWord* bottom); - - // Record an object that failed evacuation. - inline void record(oop obj); - - // Apply the given ObjectClosure to all objects that failed evacuation and - // empties the list after processing. - // Objects are passed in increasing address order. - void process_and_drop(ObjectClosure* closure); -}; - - -#endif //SHARE_GC_G1_G1EVACUATIONFAILUREOBJSINHR_HPP diff --git a/src/hotspot/share/gc/g1/g1EvacFailureRegions.cpp b/src/hotspot/share/gc/g1/g1EvacFailureRegions.cpp index 855c549cd04800ddac3535568d84bccad96bfeb3..a67fb06a333d68d8774686c82e3742ccf9e188e2 100644 --- a/src/hotspot/share/gc/g1/g1EvacFailureRegions.cpp +++ b/src/hotspot/share/gc/g1/g1EvacFailureRegions.cpp @@ -29,6 +29,7 @@ #include "gc/g1/heapRegion.hpp" #include "memory/allocation.hpp" #include "runtime/atomic.hpp" +#include "utilities/bitMap.inline.hpp" G1EvacFailureRegions::G1EvacFailureRegions() : _regions_failed_evacuation(mtGC), diff --git a/src/hotspot/share/gc/g1/g1FromCardCache.hpp b/src/hotspot/share/gc/g1/g1FromCardCache.hpp index b76d7b1b8633401ed719504a01779096c7a7b7ef..0a01e0102aed3e1b497bd6dbbd55c89018943f1a 100644 --- a/src/hotspot/share/gc/g1/g1FromCardCache.hpp +++ b/src/hotspot/share/gc/g1/g1FromCardCache.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -25,7 +25,7 @@ #ifndef SHARE_GC_G1_G1FROMCARDCACHE_HPP #define SHARE_GC_G1_G1FROMCARDCACHE_HPP -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" #include "utilities/ostream.hpp" // G1FromCardCache remembers the most recently processed card on the heap on diff --git a/src/hotspot/share/gc/g1/g1FullCollector.cpp b/src/hotspot/share/gc/g1/g1FullCollector.cpp index 603b381802903c1ff317cdd062b9f811b68b6e3a..7e07ff4757c503fb4131761cebf8a493814cba62 100644 --- a/src/hotspot/share/gc/g1/g1FullCollector.cpp +++ b/src/hotspot/share/gc/g1/g1FullCollector.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -32,7 +32,7 @@ #include "gc/g1/g1FullGCCompactTask.hpp" #include "gc/g1/g1FullGCMarker.inline.hpp" #include "gc/g1/g1FullGCMarkTask.hpp" -#include "gc/g1/g1FullGCPrepareTask.hpp" +#include "gc/g1/g1FullGCPrepareTask.inline.hpp" #include "gc/g1/g1FullGCScope.hpp" #include "gc/g1/g1OopClosures.hpp" #include "gc/g1/g1Policy.hpp" @@ -111,9 +111,9 @@ uint G1FullCollector::calc_active_workers() { G1FullCollector::G1FullCollector(G1CollectedHeap* heap, bool explicit_gc, bool clear_soft_refs, - bool do_maximum_compaction) : + bool do_maximal_compaction) : _heap(heap), - _scope(heap->monitoring_support(), explicit_gc, clear_soft_refs, do_maximum_compaction), + _scope(heap->monitoring_support(), explicit_gc, clear_soft_refs, do_maximal_compaction), _num_workers(calc_active_workers()), _oop_queue_set(_num_workers), _array_queue_set(_num_workers), @@ -294,17 +294,74 @@ void G1FullCollector::phase1_mark_live_objects() { } scope()->tracer()->report_object_count_after_gc(&_is_alive); +#if TASKQUEUE_STATS + oop_queue_set()->print_and_reset_taskqueue_stats("Oop Queue"); + array_queue_set()->print_and_reset_taskqueue_stats("ObjArrayOop Queue"); +#endif } void G1FullCollector::phase2_prepare_compaction() { - GCTraceTime(Info, gc, phases) info("Phase 2: Prepare for compaction", scope()->timer()); + GCTraceTime(Info, gc, phases) info("Phase 2: Prepare compaction", scope()->timer()); + + phase2a_determine_worklists(); + + bool has_free_compaction_targets = phase2b_forward_oops(); + + // Try to avoid OOM immediately after Full GC in case there are no free regions + // left after determining the result locations (i.e. this phase). Prepare to + // maximally compact the tail regions of the compaction queues serially. + if (!has_free_compaction_targets) { + phase2c_prepare_serial_compaction(); + } +} + +void G1FullCollector::phase2a_determine_worklists() { + GCTraceTime(Debug, gc, phases) debug("Phase 2: Determine work lists", scope()->timer()); + + G1DetermineCompactionQueueClosure cl(this); + _heap->heap_region_iterate(&cl); +} + +bool G1FullCollector::phase2b_forward_oops() { + GCTraceTime(Debug, gc, phases) debug("Phase 2: Prepare parallel compaction", scope()->timer()); + G1FullGCPrepareTask task(this); run_task(&task); - // To avoid OOM when there is memory left. - if (!task.has_freed_regions()) { - task.prepare_serial_compaction(); + return task.has_free_compaction_targets(); +} + +void G1FullCollector::phase2c_prepare_serial_compaction() { + GCTraceTime(Debug, gc, phases) debug("Phase 2: Prepare serial compaction", scope()->timer()); + // At this point we know that after parallel compaction there will be no + // completely free regions. That means that the last region of + // all compaction queues still have data in them. We try to compact + // these regions in serial to avoid a premature OOM when the mutator wants + // to allocate the first eden region after gc. + for (uint i = 0; i < workers(); i++) { + G1FullGCCompactionPoint* cp = compaction_point(i); + if (cp->has_regions()) { + serial_compaction_point()->add(cp->remove_last()); + } + } + + // Update the forwarding information for the regions in the serial + // compaction point. + G1FullGCCompactionPoint* cp = serial_compaction_point(); + for (GrowableArrayIterator it = cp->regions()->begin(); it != cp->regions()->end(); ++it) { + HeapRegion* current = *it; + if (!cp->is_initialized()) { + // Initialize the compaction point. Nothing more is needed for the first heap region + // since it is already prepared for compaction. + cp->initialize(current); + } else { + assert(!current->is_humongous(), "Should be no humongous regions in compaction queue"); + G1SerialRePrepareClosure re_prepare(cp, current); + current->set_compaction_top(current->bottom()); + current->apply_to_marked_objects(mark_bitmap(), &re_prepare); + } } + cp->update(); } void G1FullCollector::phase3_adjust_pointers() { diff --git a/src/hotspot/share/gc/g1/g1FullCollector.hpp b/src/hotspot/share/gc/g1/g1FullCollector.hpp index c4d019629dd89d8738ccd514439aa474f36f9cc6..2d4bfc26feb16638637d556c3297ed2d0ce77289 100644 --- a/src/hotspot/share/gc/g1/g1FullCollector.hpp +++ b/src/hotspot/share/gc/g1/g1FullCollector.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -93,7 +93,7 @@ public: G1FullCollector(G1CollectedHeap* heap, bool explicit_gc, bool clear_soft_refs, - bool do_maximum_compaction); + bool do_maximal_compaction); ~G1FullCollector(); void prepare_collection(); @@ -110,7 +110,7 @@ public: G1FullGCCompactionPoint* serial_compaction_point() { return &_serial_compaction_point; } G1CMBitMap* mark_bitmap(); ReferenceProcessor* reference_processor(); - size_t live_words(uint region_index) { + size_t live_words(uint region_index) const { assert(region_index < _heap->max_regions(), "sanity"); return _live_stats[region_index]._live_words; } @@ -121,6 +121,9 @@ public: inline bool is_skip_compacting(uint region_index) const; inline bool is_skip_marking(oop obj) const; + // Are we (potentially) going to compact into this region? + inline bool is_compaction_target(uint region_index) const; + inline void set_free(uint region_idx); inline bool is_free(uint region_idx) const; inline void update_from_compacting_to_skip_compacting(uint region_idx); @@ -128,6 +131,11 @@ public: private: void phase1_mark_live_objects(); void phase2_prepare_compaction(); + + void phase2a_determine_worklists(); + bool phase2b_forward_oops(); + void phase2c_prepare_serial_compaction(); + void phase3_adjust_pointers(); void phase4_do_compaction(); diff --git a/src/hotspot/share/gc/g1/g1FullCollector.inline.hpp b/src/hotspot/share/gc/g1/g1FullCollector.inline.hpp index 5a0863b202a07a8131091de6bfafd949cb03dcd0..37e16fc6f78b9b0a512c3d5255283ae23f9d391d 100644 --- a/src/hotspot/share/gc/g1/g1FullCollector.inline.hpp +++ b/src/hotspot/share/gc/g1/g1FullCollector.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -43,6 +43,10 @@ bool G1FullCollector::is_skip_marking(oop obj) const { return _region_attr_table.is_skip_marking(cast_from_oop(obj)); } +bool G1FullCollector::is_compaction_target(uint region_index) const { + return _region_attr_table.is_compacting(region_index) || is_free(region_index); +} + void G1FullCollector::set_free(uint region_idx) { _region_attr_table.set_free(region_idx); } diff --git a/src/hotspot/share/gc/g1/g1FullGCCompactTask.cpp b/src/hotspot/share/gc/g1/g1FullGCCompactTask.cpp index d0dc0593d3bbc90bb1fd88923d2d08d8f600422b..f484ee5133c7007f793b74a57e3edc851cbc8356 100644 --- a/src/hotspot/share/gc/g1/g1FullGCCompactTask.cpp +++ b/src/hotspot/share/gc/g1/g1FullGCCompactTask.cpp @@ -46,26 +46,43 @@ public: uint region_index = r->hrm_index(); // Only for skip-compaction regions; early return otherwise. if (!_collector->is_skip_compacting(region_index)) { - return false; } - assert(_collector->live_words(region_index) > _collector->scope()->region_compaction_threshold() || - !r->is_starts_humongous() || - _collector->mark_bitmap()->is_marked(cast_to_oop(r->bottom())), - "must be, otherwise reclaimed earlier"); +#ifdef ASSERT + if (r->is_humongous()) { + oop obj = cast_to_oop(r->humongous_start_region()->bottom()); + assert(_collector->mark_bitmap()->is_marked(obj), "must be live"); + } else if (r->is_open_archive()) { + bool is_empty = (_collector->live_words(r->hrm_index()) == 0); + assert(!is_empty, "should contain at least one live obj"); + } else if (r->is_closed_archive()) { + // should early-return above + ShouldNotReachHere(); + } else { + assert(_collector->live_words(region_index) > _collector->scope()->region_compaction_threshold(), + "should be quite full"); + } +#endif r->reset_skip_compacting_after_full_gc(); return false; } }; +void G1FullGCCompactTask::G1CompactRegionClosure::clear_in_prev_bitmap(oop obj) { + assert(_bitmap->is_marked(obj), "Should only compact marked objects"); + _bitmap->clear(obj); +} + size_t G1FullGCCompactTask::G1CompactRegionClosure::apply(oop obj) { size_t size = obj->size(); - HeapWord* destination = cast_from_oop(obj->forwardee()); - if (destination == NULL) { - // Object not moving + if (!obj->is_forwarded()) { + // Object not moving, but clear the mark to allow reuse of the bitmap. + clear_in_prev_bitmap(obj); return size; } + HeapWord* destination = cast_from_oop(obj->forwardee()); + // copy object and reinit its mark HeapWord* obj_addr = cast_from_oop(obj); assert(obj_addr != destination, "everything in this pass should be moving"); @@ -73,6 +90,9 @@ size_t G1FullGCCompactTask::G1CompactRegionClosure::apply(oop obj) { cast_to_oop(destination)->init_mark(); assert(cast_to_oop(destination)->klass() != NULL, "should have a class"); + // Clear the mark for the compacted object to allow reuse of the + // bitmap without an additional clearing step. + clear_in_prev_bitmap(obj); return size; } @@ -81,13 +101,15 @@ void G1FullGCCompactTask::compact_region(HeapRegion* hr) { assert(!hr->is_humongous(), "Should be no humongous regions in compaction queue"); if (!collector()->is_free(hr->hrm_index())) { + // The compaction closure not only copies the object to the new + // location, but also clears the bitmap for it. This is needed + // for bitmap verification and to be able to use the prev_bitmap + // for evacuation failures in the next young collection. Testing + // showed that it was better overall to clear bit by bit, compared + // to clearing the whole region at the end. This difference was + // clearly seen for regions with few marks. G1CompactRegionClosure compact(collector()->mark_bitmap()); hr->apply_to_marked_objects(collector()->mark_bitmap(), &compact); - // Clear the liveness information for this region if necessary i.e. if we actually look at it - // for bitmap verification. Otherwise it is sufficient that we move the TAMS to bottom(). - if (G1VerifyBitmaps) { - collector()->mark_bitmap()->clear_region(hr); - } } hr->reset_compacted_after_full_gc(); diff --git a/src/hotspot/share/gc/g1/g1FullGCCompactTask.hpp b/src/hotspot/share/gc/g1/g1FullGCCompactTask.hpp index 5f96796accadc4b2fff82bd550cf125f44faf8e6..936980b98056379d4b26e41e0499d79a53fc8d07 100644 --- a/src/hotspot/share/gc/g1/g1FullGCCompactTask.hpp +++ b/src/hotspot/share/gc/g1/g1FullGCCompactTask.hpp @@ -50,7 +50,7 @@ public: class G1CompactRegionClosure : public StackObj { G1CMBitMap* _bitmap; - + void clear_in_prev_bitmap(oop object); public: G1CompactRegionClosure(G1CMBitMap* bitmap) : _bitmap(bitmap) { } size_t apply(oop object); diff --git a/src/hotspot/share/gc/g1/g1FullGCCompactionPoint.cpp b/src/hotspot/share/gc/g1/g1FullGCCompactionPoint.cpp index e14f0ea2569603ec6c4cd1cb60012d02b0e4672b..195707424c30988dea236865c67223209a9cca93 100644 --- a/src/hotspot/share/gc/g1/g1FullGCCompactionPoint.cpp +++ b/src/hotspot/share/gc/g1/g1FullGCCompactionPoint.cpp @@ -45,11 +45,8 @@ void G1FullGCCompactionPoint::update() { } } -void G1FullGCCompactionPoint::initialize_values(bool init_threshold) { +void G1FullGCCompactionPoint::initialize_values() { _compaction_top = _current_region->compaction_top(); - if (init_threshold) { - _current_region->initialize_bot_threshold(); - } } bool G1FullGCCompactionPoint::has_regions() { @@ -60,9 +57,9 @@ bool G1FullGCCompactionPoint::is_initialized() { return _current_region != NULL; } -void G1FullGCCompactionPoint::initialize(HeapRegion* hr, bool init_threshold) { +void G1FullGCCompactionPoint::initialize(HeapRegion* hr) { _current_region = hr; - initialize_values(init_threshold); + initialize_values(); } HeapRegion* G1FullGCCompactionPoint::current_region() { @@ -89,7 +86,7 @@ void G1FullGCCompactionPoint::switch_region() { _current_region->set_compaction_top(_compaction_top); // Get the next region and re-initialize the values. _current_region = next_region(); - initialize_values(true); + initialize_values(); } void G1FullGCCompactionPoint::forward(oop object, size_t size) { @@ -103,26 +100,14 @@ void G1FullGCCompactionPoint::forward(oop object, size_t size) { // Store a forwarding pointer if the object should be moved. if (cast_from_oop(object) != _compaction_top) { object->forward_to(cast_to_oop(_compaction_top)); + assert(object->is_forwarded(), "must be forwarded"); } else { - if (object->forwardee() != NULL) { - // Object should not move but mark-word is used so it looks like the - // object is forwarded. Need to clear the mark and it's no problem - // since it will be restored by preserved marks. - object->init_mark(); - } else { - // Make sure object has the correct mark-word set or that it will be - // fixed when restoring the preserved marks. - assert(object->mark() == markWord::prototype() || // Correct mark - object->mark_must_be_preserved(), // Will be restored by PreservedMarksSet - "should have correct prototype obj: " PTR_FORMAT " mark: " PTR_FORMAT " prototype: " PTR_FORMAT, - p2i(object), object->mark().value(), markWord::prototype().value()); - } - assert(object->forwardee() == NULL, "should be forwarded to NULL"); + assert(!object->is_forwarded(), "must not be forwarded"); } // Update compaction values. _compaction_top += size; - _current_region->alloc_block_in_bot(_compaction_top - size, _compaction_top); + _current_region->update_bot_for_block(_compaction_top - size, _compaction_top); } void G1FullGCCompactionPoint::add(HeapRegion* hr) { diff --git a/src/hotspot/share/gc/g1/g1FullGCCompactionPoint.hpp b/src/hotspot/share/gc/g1/g1FullGCCompactionPoint.hpp index 21bb75ee2e97ad8489eecae20541e1f1a7a3391a..41a9783a07c2a022c87f2815ce38bb1dfeae5364 100644 --- a/src/hotspot/share/gc/g1/g1FullGCCompactionPoint.hpp +++ b/src/hotspot/share/gc/g1/g1FullGCCompactionPoint.hpp @@ -38,7 +38,7 @@ class G1FullGCCompactionPoint : public CHeapObj { GrowableArrayIterator _compaction_region_iterator; bool object_will_fit(size_t size); - void initialize_values(bool init_threshold); + void initialize_values(); void switch_region(); HeapRegion* next_region(); @@ -48,7 +48,7 @@ public: bool has_regions(); bool is_initialized(); - void initialize(HeapRegion* hr, bool init_threshold); + void initialize(HeapRegion* hr); void update(); void forward(oop object, size_t size); void add(HeapRegion* hr); diff --git a/src/hotspot/share/gc/g1/g1FullGCHeapRegionAttr.hpp b/src/hotspot/share/gc/g1/g1FullGCHeapRegionAttr.hpp index ca2f970edde55f0eaf7ff136d89d30343286a454..017877785f41e3dbd9004173697117eff5c87c7a 100644 --- a/src/hotspot/share/gc/g1/g1FullGCHeapRegionAttr.hpp +++ b/src/hotspot/share/gc/g1/g1FullGCHeapRegionAttr.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -70,6 +70,10 @@ public: return get_by_address(obj) == Compacting; } + bool is_compacting(uint idx) const { + return get_by_index(idx) == Compacting; + } + bool is_skip_compacting(uint idx) const { return get_by_index(idx) == SkipCompacting; } diff --git a/src/hotspot/share/gc/g1/g1FullGCMarker.cpp b/src/hotspot/share/gc/g1/g1FullGCMarker.cpp index 2e2773c54dd0f672ef6f36b365ad27902f4e1e4e..398b904fdb2eca27caf4ac9880dc355aed13e2b9 100644 --- a/src/hotspot/share/gc/g1/g1FullGCMarker.cpp +++ b/src/hotspot/share/gc/g1/g1FullGCMarker.cpp @@ -45,7 +45,6 @@ G1FullGCMarker::G1FullGCMarker(G1FullCollector* collector, _stack_closure(this), _cld_closure(mark_closure(), ClassLoaderData::_claim_strong), _mark_stats_cache(mark_stats, G1RegionMarkStatsCache::RegionMarkStatsCacheSize) { - _mark_stats_cache.reset(); } G1FullGCMarker::~G1FullGCMarker() { @@ -56,7 +55,7 @@ void G1FullGCMarker::complete_marking(OopQueueSet* oop_stacks, ObjArrayTaskQueueSet* array_stacks, TaskTerminator* terminator) { do { - drain_stack(); + follow_marking_stacks(); ObjArrayTask steal_array; if (array_stacks->steal(_worker_id, steal_array)) { follow_array_chunk(objArrayOop(steal_array.obj()), steal_array.index()); diff --git a/src/hotspot/share/gc/g1/g1FullGCMarker.hpp b/src/hotspot/share/gc/g1/g1FullGCMarker.hpp index ec7f029b7cee72ae6a4ec460c84197c241bd0618..ee77e5044fc4bdb81b354db37e9f1598254435fe 100644 --- a/src/hotspot/share/gc/g1/g1FullGCMarker.hpp +++ b/src/hotspot/share/gc/g1/g1FullGCMarker.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -71,8 +71,6 @@ class G1FullGCMarker : public CHeapObj { G1RegionMarkStatsCache _mark_stats_cache; inline bool is_empty(); - inline bool pop_object(oop& obj); - inline bool pop_objarray(ObjArrayTask& array); inline void push_objarray(oop obj, size_t index); inline bool mark_object(oop obj); @@ -80,6 +78,14 @@ class G1FullGCMarker : public CHeapObj { inline void follow_object(oop obj); inline void follow_array(objArrayOop array); inline void follow_array_chunk(objArrayOop array, int index); + + inline void publish_and_drain_oop_tasks(); + // Try to publish all contents from the objArray task queue overflow stack to + // the shared objArray stack. + // Returns true and a valid task if there has not been enough space in the shared + // objArray stack, otherwise returns false and the task is invalid. + inline bool publish_or_pop_objarray_tasks(ObjArrayTask& task); + public: G1FullGCMarker(G1FullCollector* collector, uint worker_id, @@ -97,7 +103,7 @@ public: inline void follow_klass(Klass* k); inline void follow_cld(ClassLoaderData* cld); - inline void drain_stack(); + inline void follow_marking_stacks(); void complete_marking(OopQueueSet* oop_stacks, ObjArrayTaskQueueSet* array_stacks, TaskTerminator* terminator); diff --git a/src/hotspot/share/gc/g1/g1FullGCMarker.inline.hpp b/src/hotspot/share/gc/g1/g1FullGCMarker.inline.hpp index 3ef6375c3a4b54816223af5f31d9832c5c2cd949..ce3013138cef1aecb69b70b787fc9d9a3f1dab7c 100644 --- a/src/hotspot/share/gc/g1/g1FullGCMarker.inline.hpp +++ b/src/hotspot/share/gc/g1/g1FullGCMarker.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -54,12 +54,10 @@ inline bool G1FullGCMarker::mark_object(oop obj) { } // Marked by us, preserve if needed. - markWord mark = obj->mark(); - if (obj->mark_must_be_preserved(mark) && - // It is not necessary to preserve marks for objects in regions we do not - // compact because we do not change their headers (i.e. forward them). - _collector->is_compacting(obj)) { - preserved_stack()->push(obj, mark); + if (_collector->is_compacting(obj)) { + // It is not necessary to preserve marks for objects in regions we do not + // compact because we do not change their headers (i.e. forward them). + preserved_stack()->push_if_necessary(obj, obj->mark()); } // Check if deduplicatable string. @@ -93,20 +91,12 @@ inline bool G1FullGCMarker::is_empty() { return _oop_stack.is_empty() && _objarray_stack.is_empty(); } -inline bool G1FullGCMarker::pop_object(oop& oop) { - return _oop_stack.pop_overflow(oop) || _oop_stack.pop_local(oop); -} - inline void G1FullGCMarker::push_objarray(oop obj, size_t index) { ObjArrayTask task(obj, index); assert(task.is_valid(), "bad ObjArrayTask"); _objarray_stack.push(task); } -inline bool G1FullGCMarker::pop_objarray(ObjArrayTask& arr) { - return _objarray_stack.pop_overflow(arr) || _objarray_stack.pop_local(arr); -} - inline void G1FullGCMarker::follow_array(objArrayOop array) { follow_klass(array->klass()); // Don't push empty arrays to avoid unnecessary work. @@ -148,7 +138,7 @@ inline void G1FullGCMarker::follow_object(oop obj) { } else { obj->oop_iterate(mark_closure()); if (VerifyDuringGC) { - if (obj->is_instance() && InstanceKlass::cast(obj->klass())->is_reference_instance_klass()) { + if (obj->is_instanceRef()) { return; } _verify_closure.set_containing_obj(obj); @@ -161,16 +151,40 @@ inline void G1FullGCMarker::follow_object(oop obj) { } } -void G1FullGCMarker::drain_stack() { - do { - oop obj; - while (pop_object(obj)) { +inline void G1FullGCMarker::publish_and_drain_oop_tasks() { + oop obj; + while (_oop_stack.pop_overflow(obj)) { + if (!_oop_stack.try_push_to_taskqueue(obj)) { assert(_bitmap->is_marked(obj), "must be marked"); follow_object(obj); } - // Process ObjArrays one at a time to avoid marking stack bloat. + } + while (_oop_stack.pop_local(obj)) { + assert(_bitmap->is_marked(obj), "must be marked"); + follow_object(obj); + } +} + +inline bool G1FullGCMarker::publish_or_pop_objarray_tasks(ObjArrayTask& task) { + // It is desirable to move as much as possible work from the overflow queue to + // the shared queue as quickly as possible. + while (_objarray_stack.pop_overflow(task)) { + if (!_objarray_stack.try_push_to_taskqueue(task)) { + return true; + } + } + return false; +} + +void G1FullGCMarker::follow_marking_stacks() { + do { + // First, drain regular oop stack. + publish_and_drain_oop_tasks(); + + // Then process ObjArrays one at a time to avoid marking stack bloat. ObjArrayTask task; - if (pop_objarray(task)) { + if (publish_or_pop_objarray_tasks(task) || + _objarray_stack.pop_local(task)) { follow_array_chunk(objArrayOop(task.obj()), task.index()); } } while (!is_empty()); diff --git a/src/hotspot/share/gc/g1/g1FullGCOopClosures.cpp b/src/hotspot/share/gc/g1/g1FullGCOopClosures.cpp index ba3b50e5a963ee126e60b406fe232eb03dd6a8db..eebfa814ae20ae7e7fe70ddea205569db6a01968 100644 --- a/src/hotspot/share/gc/g1/g1FullGCOopClosures.cpp +++ b/src/hotspot/share/gc/g1/g1FullGCOopClosures.cpp @@ -36,7 +36,7 @@ G1IsAliveClosure::G1IsAliveClosure(G1FullCollector* collector) : G1IsAliveClosure(collector, collector->mark_bitmap()) { } -void G1FollowStackClosure::do_void() { _marker->drain_stack(); } +void G1FollowStackClosure::do_void() { _marker->follow_marking_stacks(); } void G1FullKeepAliveClosure::do_oop(oop* p) { do_oop_work(p); } void G1FullKeepAliveClosure::do_oop(narrowOop* p) { do_oop_work(p); } diff --git a/src/hotspot/share/gc/g1/g1FullGCOopClosures.inline.hpp b/src/hotspot/share/gc/g1/g1FullGCOopClosures.inline.hpp index d9a1759b029578ecb40607ca118f0e3845af18ad..f4b9d9e11768364b5309b3d847f7a0a32fcdf60b 100644 --- a/src/hotspot/share/gc/g1/g1FullGCOopClosures.inline.hpp +++ b/src/hotspot/share/gc/g1/g1FullGCOopClosures.inline.hpp @@ -77,19 +77,13 @@ template inline void G1AdjustClosure::adjust_pointer(T* p) { return; } - oop forwardee = obj->forwardee(); - if (forwardee == NULL) { - // Not forwarded, return current reference. - assert(obj->mark() == markWord::prototype() || // Correct mark - obj->mark_must_be_preserved(), // Will be restored by PreservedMarksSet - "Must have correct prototype or be preserved, obj: " PTR_FORMAT ", mark: " PTR_FORMAT ", prototype: " PTR_FORMAT, - p2i(obj), obj->mark().value(), markWord::prototype().value()); - return; + if (obj->is_forwarded()) { + oop forwardee = obj->forwardee(); + // Forwarded, just update. + assert(G1CollectedHeap::heap()->is_in_reserved(forwardee), "should be in object space"); + RawAccess::oop_store(p, forwardee); } - // Forwarded, just update. - assert(G1CollectedHeap::heap()->is_in_reserved(forwardee), "should be in object space"); - RawAccess::oop_store(p, forwardee); } inline void G1AdjustClosure::do_oop(oop* p) { do_oop_work(p); } diff --git a/src/hotspot/share/gc/g1/g1FullGCPrepareTask.cpp b/src/hotspot/share/gc/g1/g1FullGCPrepareTask.cpp index 817966a273bbf31b77a86b7b3671451eb833dbcb..4ffe9329dc754a359281103b452f1b700b8a8c38 100644 --- a/src/hotspot/share/gc/g1/g1FullGCPrepareTask.cpp +++ b/src/hotspot/share/gc/g1/g1FullGCPrepareTask.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -23,13 +23,13 @@ */ #include "precompiled.hpp" -#include "gc/g1/g1CollectedHeap.hpp" +#include "gc/g1/g1CollectedHeap.inline.hpp" #include "gc/g1/g1ConcurrentMarkBitMap.inline.hpp" #include "gc/g1/g1FullCollector.inline.hpp" #include "gc/g1/g1FullGCCompactionPoint.hpp" #include "gc/g1/g1FullGCMarker.hpp" #include "gc/g1/g1FullGCOopClosures.inline.hpp" -#include "gc/g1/g1FullGCPrepareTask.hpp" +#include "gc/g1/g1FullGCPrepareTask.inline.hpp" #include "gc/g1/g1HotCardCache.hpp" #include "gc/g1/heapRegion.inline.hpp" #include "gc/shared/gcTraceTime.inline.hpp" @@ -39,114 +39,84 @@ #include "oops/oop.inline.hpp" #include "utilities/ticks.hpp" -template -void G1FullGCPrepareTask::G1CalculatePointersClosure::free_pinned_region(HeapRegion* hr) { - _regions_freed = true; - if (is_humongous) { - _g1h->free_humongous_region(hr, nullptr); - } else { - _g1h->free_region(hr, nullptr); - } - _collector->set_free(hr->hrm_index()); - prepare_for_compaction(hr); -} +G1DetermineCompactionQueueClosure::G1DetermineCompactionQueueClosure(G1FullCollector* collector) : + _g1h(G1CollectedHeap::heap()), + _collector(collector), + _cur_worker(0) { } bool G1FullGCPrepareTask::G1CalculatePointersClosure::do_heap_region(HeapRegion* hr) { - bool force_not_compacted = false; - if (should_compact(hr)) { - assert(!hr->is_humongous(), "moving humongous objects not supported."); - prepare_for_compaction(hr); - } else { - // There is no need to iterate and forward objects in pinned regions ie. - // prepare them for compaction. The adjust pointers phase will skip - // work for them. - assert(hr->containing_set() == nullptr, "already cleared by PrepareRegionsClosure"); - if (hr->is_humongous()) { - oop obj = cast_to_oop(hr->humongous_start_region()->bottom()); - if (!_bitmap->is_marked(obj)) { - free_pinned_region(hr); - } - } else if (hr->is_open_archive()) { - bool is_empty = _collector->live_words(hr->hrm_index()) == 0; - if (is_empty) { - free_pinned_region(hr); - } - } else if (hr->is_closed_archive()) { - // nothing to do with closed archive region - } else { - assert(MarkSweepDeadRatio > 0, - "only skip compaction for other regions when MarkSweepDeadRatio > 0"); - - // Too many live objects; skip compacting it. - _collector->update_from_compacting_to_skip_compacting(hr->hrm_index()); - if (hr->is_young()) { - // G1 updates the BOT for old region contents incrementally, but young regions - // lack BOT information for performance reasons. - // Recreate BOT information of high live ratio young regions here to keep expected - // performance during scanning their card tables in the collection pauses later. - hr->update_bot(); - } - log_trace(gc, phases)("Phase 2: skip compaction region index: %u, live words: " SIZE_FORMAT, - hr->hrm_index(), _collector->live_words(hr->hrm_index())); - } - } + uint region_idx = hr->hrm_index(); + assert(_collector->is_compaction_target(region_idx), "must be"); - // Reset data structures not valid after Full GC. - reset_region_metadata(hr); + assert(!hr->is_pinned(), "must be"); + assert(!hr->is_closed_archive(), "must be"); + assert(!hr->is_open_archive(), "must be"); + + prepare_for_compaction(hr); return false; } G1FullGCPrepareTask::G1FullGCPrepareTask(G1FullCollector* collector) : G1FullGCTask("G1 Prepare Compact Task", collector), - _freed_regions(false), + _has_free_compaction_targets(false), _hrclaimer(collector->workers()) { } -void G1FullGCPrepareTask::set_freed_regions() { - if (!_freed_regions) { - _freed_regions = true; +void G1FullGCPrepareTask::set_has_free_compaction_targets() { + if (!_has_free_compaction_targets) { + _has_free_compaction_targets = true; } } -bool G1FullGCPrepareTask::has_freed_regions() { - return _freed_regions; +bool G1FullGCPrepareTask::has_free_compaction_targets() { + return _has_free_compaction_targets; } void G1FullGCPrepareTask::work(uint worker_id) { Ticks start = Ticks::now(); - G1FullGCCompactionPoint* compaction_point = collector()->compaction_point(worker_id); - G1CalculatePointersClosure closure(collector(), compaction_point); - G1CollectedHeap::heap()->heap_region_par_iterate_from_start(&closure, &_hrclaimer); - - compaction_point->update(); + // Calculate the target locations for the objects in the non-free regions of + // the compaction queues provided by the associate compaction point. + { + G1FullGCCompactionPoint* compaction_point = collector()->compaction_point(worker_id); + G1CalculatePointersClosure closure(collector(), compaction_point); + + for (GrowableArrayIterator it = compaction_point->regions()->begin(); + it != compaction_point->regions()->end(); + ++it) { + closure.do_heap_region(*it); + } + compaction_point->update(); + // Determine if there are any unused compaction targets. This is only the case if + // there are + // - any regions in queue, so no free ones either. + // - and the current region is not the last one in the list. + if (compaction_point->has_regions() && + compaction_point->current_region() != compaction_point->regions()->last()) { + set_has_free_compaction_targets(); + } + } - // Check if any regions was freed by this worker and store in task. - if (closure.freed_regions()) { - set_freed_regions(); + // Clear region metadata that is invalid after GC for all regions. + { + G1ResetMetadataClosure closure(collector()); + G1CollectedHeap::heap()->heap_region_par_iterate_from_start(&closure, &_hrclaimer); } log_task("Prepare compaction task", worker_id, start); } G1FullGCPrepareTask::G1CalculatePointersClosure::G1CalculatePointersClosure(G1FullCollector* collector, G1FullGCCompactionPoint* cp) : - _g1h(G1CollectedHeap::heap()), - _collector(collector), - _bitmap(collector->mark_bitmap()), - _cp(cp), - _regions_freed(false) { } - -bool G1FullGCPrepareTask::G1CalculatePointersClosure::should_compact(HeapRegion* hr) { - if (hr->is_pinned()) { - return false; - } - size_t live_words = _collector->live_words(hr->hrm_index()); - size_t live_words_threshold = _collector->scope()->region_compaction_threshold(); - // High live ratio region will not be compacted. - return live_words <= live_words_threshold; -} + _g1h(G1CollectedHeap::heap()), + _collector(collector), + _bitmap(collector->mark_bitmap()), + _cp(cp) { } -void G1FullGCPrepareTask::G1CalculatePointersClosure::reset_region_metadata(HeapRegion* hr) { +G1FullGCPrepareTask::G1ResetMetadataClosure::G1ResetMetadataClosure(G1FullCollector* collector) : + _g1h(G1CollectedHeap::heap()), + _collector(collector) { } + +void G1FullGCPrepareTask::G1ResetMetadataClosure::reset_region_metadata(HeapRegion* hr) { hr->rem_set()->clear(); hr->clear_cardtable(); @@ -156,6 +126,26 @@ void G1FullGCPrepareTask::G1CalculatePointersClosure::reset_region_metadata(Heap } } +bool G1FullGCPrepareTask::G1ResetMetadataClosure::do_heap_region(HeapRegion* hr) { + uint const region_idx = hr->hrm_index(); + if (!_collector->is_compaction_target(region_idx)) { + assert(!hr->is_free(), "all free regions should be compaction targets"); + assert(_collector->is_skip_compacting(region_idx) || hr->is_closed_archive(), "must be"); + if (hr->is_young()) { + // G1 updates the BOT for old region contents incrementally, but young regions + // lack BOT information for performance reasons. + // Recreate BOT information of high live ratio young regions here to keep expected + // performance during scanning their card tables in the collection pauses later. + hr->update_bot(); + } + } + + // Reset data structures not valid after Full GC. + reset_region_metadata(hr); + + return false; +} + G1FullGCPrepareTask::G1PrepareCompactLiveClosure::G1PrepareCompactLiveClosure(G1FullGCCompactionPoint* cp) : _cp(cp) { } @@ -165,88 +155,9 @@ size_t G1FullGCPrepareTask::G1PrepareCompactLiveClosure::apply(oop object) { return size; } -size_t G1FullGCPrepareTask::G1RePrepareClosure::apply(oop obj) { - // We only re-prepare objects forwarded within the current region, so - // skip objects that are already forwarded to another region. - oop forwarded_to = obj->forwardee(); - if (forwarded_to != NULL && !_current->is_in(forwarded_to)) { - return obj->size(); - } - - // Get size and forward. - size_t size = obj->size(); - _cp->forward(obj, size); - - return size; -} - -void G1FullGCPrepareTask::G1CalculatePointersClosure::prepare_for_compaction_work(G1FullGCCompactionPoint* cp, - HeapRegion* hr) { - hr->set_compaction_top(hr->bottom()); +void G1FullGCPrepareTask::G1CalculatePointersClosure::prepare_for_compaction(HeapRegion* hr) { if (!_collector->is_free(hr->hrm_index())) { - G1PrepareCompactLiveClosure prepare_compact(cp); + G1PrepareCompactLiveClosure prepare_compact(_cp); hr->apply_to_marked_objects(_bitmap, &prepare_compact); } } - -void G1FullGCPrepareTask::G1CalculatePointersClosure::prepare_for_compaction(HeapRegion* hr) { - if (!_cp->is_initialized()) { - hr->set_compaction_top(hr->bottom()); - _cp->initialize(hr, true); - } - // Add region to the compaction queue and prepare it. - _cp->add(hr); - prepare_for_compaction_work(_cp, hr); -} - -void G1FullGCPrepareTask::prepare_serial_compaction() { - GCTraceTime(Debug, gc, phases) debug("Phase 2: Prepare Serial Compaction", collector()->scope()->timer()); - // At this point we know that no regions were completely freed by - // the parallel compaction. That means that the last region of - // all compaction queues still have data in them. We try to compact - // these regions in serial to avoid a premature OOM. - for (uint i = 0; i < collector()->workers(); i++) { - G1FullGCCompactionPoint* cp = collector()->compaction_point(i); - if (cp->has_regions()) { - collector()->serial_compaction_point()->add(cp->remove_last()); - } - } - - // Update the forwarding information for the regions in the serial - // compaction point. - G1FullGCCompactionPoint* cp = collector()->serial_compaction_point(); - for (GrowableArrayIterator it = cp->regions()->begin(); it != cp->regions()->end(); ++it) { - HeapRegion* current = *it; - if (!cp->is_initialized()) { - // Initialize the compaction point. Nothing more is needed for the first heap region - // since it is already prepared for compaction. - cp->initialize(current, false); - } else { - assert(!current->is_humongous(), "Should be no humongous regions in compaction queue"); - G1RePrepareClosure re_prepare(cp, current); - current->set_compaction_top(current->bottom()); - current->apply_to_marked_objects(collector()->mark_bitmap(), &re_prepare); - } - } - cp->update(); -} - -bool G1FullGCPrepareTask::G1CalculatePointersClosure::freed_regions() { - if (_regions_freed) { - return true; - } - - if (!_cp->has_regions()) { - // No regions in queue, so no free ones either. - return false; - } - - if (_cp->current_region() != _cp->regions()->last()) { - // The current region used for compaction is not the last in the - // queue. That means there is at least one free region in the queue. - return true; - } - - // No free regions in the queue. - return false; -} diff --git a/src/hotspot/share/gc/g1/g1FullGCPrepareTask.hpp b/src/hotspot/share/gc/g1/g1FullGCPrepareTask.hpp index d694fc6ffcaf66fe13536561903eafbb6bfad658..41c0c67d87cf66482933081a88b11775a57c85f3 100644 --- a/src/hotspot/share/gc/g1/g1FullGCPrepareTask.hpp +++ b/src/hotspot/share/gc/g1/g1FullGCPrepareTask.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -25,53 +25,81 @@ #ifndef SHARE_GC_G1_G1FULLGCPREPARETASK_HPP #define SHARE_GC_G1_G1FULLGCPREPARETASK_HPP -#include "gc/g1/g1FullGCCompactionPoint.hpp" -#include "gc/g1/g1FullGCScope.hpp" #include "gc/g1/g1FullGCTask.hpp" -#include "gc/g1/g1RootProcessor.hpp" -#include "gc/g1/heapRegionManager.hpp" -#include "gc/shared/referenceProcessor.hpp" +#include "gc/g1/heapRegion.hpp" +#include "memory/allocation.hpp" +class G1CollectedHeap; class G1CMBitMap; class G1FullCollector; +class G1FullGCCompactionPoint; +class HeapRegion; + +// Determines the regions in the heap that should be part of the compaction and +// distributes them among the compaction queues in round-robin fashion. +class G1DetermineCompactionQueueClosure : public HeapRegionClosure { + G1CollectedHeap* _g1h; + G1FullCollector* _collector; + uint _cur_worker; + + template + inline void free_pinned_region(HeapRegion* hr); + + inline bool should_compact(HeapRegion* hr) const; + + // Returns the current worker id to assign a compaction point to, and selects + // the next one round-robin style. + inline uint next_worker(); + + inline G1FullGCCompactionPoint* next_compaction_point(); + + inline void add_to_compaction_queue(HeapRegion* hr); + +public: + G1DetermineCompactionQueueClosure(G1FullCollector* collector); + + inline bool do_heap_region(HeapRegion* hr) override; +}; class G1FullGCPrepareTask : public G1FullGCTask { -protected: - volatile bool _freed_regions; + volatile bool _has_free_compaction_targets; HeapRegionClaimer _hrclaimer; - void set_freed_regions(); + void set_has_free_compaction_targets(); public: G1FullGCPrepareTask(G1FullCollector* collector); void work(uint worker_id); - void prepare_serial_compaction(); - bool has_freed_regions(); + // After the Prepare phase, are there any unused (empty) regions (compaction + // targets) at the end of any compaction queues? + bool has_free_compaction_targets(); -protected: +private: class G1CalculatePointersClosure : public HeapRegionClosure { - private: - template - void free_pinned_region(HeapRegion* hr); - protected: G1CollectedHeap* _g1h; G1FullCollector* _collector; G1CMBitMap* _bitmap; G1FullGCCompactionPoint* _cp; - bool _regions_freed; - bool should_compact(HeapRegion* hr); void prepare_for_compaction(HeapRegion* hr); - void prepare_for_compaction_work(G1FullGCCompactionPoint* cp, HeapRegion* hr); - - void reset_region_metadata(HeapRegion* hr); public: G1CalculatePointersClosure(G1FullCollector* collector, G1FullGCCompactionPoint* cp); bool do_heap_region(HeapRegion* hr); - bool freed_regions(); + }; + + class G1ResetMetadataClosure : public HeapRegionClosure { + G1CollectedHeap* _g1h; + G1FullCollector* _collector; + + void reset_region_metadata(HeapRegion* hr); + + public: + G1ResetMetadataClosure(G1FullCollector* collector); + + bool do_heap_region(HeapRegion* hr); }; class G1PrepareCompactLiveClosure : public StackObj { @@ -81,19 +109,20 @@ protected: G1PrepareCompactLiveClosure(G1FullGCCompactionPoint* cp); size_t apply(oop object); }; +}; - class G1RePrepareClosure : public StackObj { - G1FullGCCompactionPoint* _cp; - HeapRegion* _current; +// Closure to re-prepare objects in the serial compaction point queue regions for +// serial compaction. +class G1SerialRePrepareClosure : public StackObj { + G1FullGCCompactionPoint* _cp; + HeapRegion* _current; - public: - G1RePrepareClosure(G1FullGCCompactionPoint* hrcp, - HeapRegion* hr) : - _cp(hrcp), - _current(hr) { } +public: + G1SerialRePrepareClosure(G1FullGCCompactionPoint* hrcp, HeapRegion* hr) : + _cp(hrcp), + _current(hr) { } - size_t apply(oop object); - }; + inline size_t apply(oop obj); }; #endif // SHARE_GC_G1_G1FULLGCPREPARETASK_HPP diff --git a/src/hotspot/share/gc/g1/g1FullGCPrepareTask.inline.hpp b/src/hotspot/share/gc/g1/g1FullGCPrepareTask.inline.hpp new file mode 100644 index 0000000000000000000000000000000000000000..a5807c33c37c0b63c293ebe0f2d3185a8958116b --- /dev/null +++ b/src/hotspot/share/gc/g1/g1FullGCPrepareTask.inline.hpp @@ -0,0 +1,126 @@ +/* + * 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_G1_G1FULLGCPREPARETASK_INLINE_HPP +#define SHARE_GC_G1_G1FULLGCPREPARETASK_INLINE_HPP + +#include "gc/g1/g1FullGCPrepareTask.hpp" + +#include "gc/g1/g1CollectedHeap.inline.hpp" +#include "gc/g1/g1FullCollector.hpp" +#include "gc/g1/g1FullGCCompactionPoint.hpp" +#include "gc/g1/g1FullGCScope.hpp" +#include "gc/g1/heapRegion.inline.hpp" + +template +void G1DetermineCompactionQueueClosure::free_pinned_region(HeapRegion* hr) { + if (is_humongous) { + _g1h->free_humongous_region(hr, nullptr); + } else { + _g1h->free_region(hr, nullptr); + } + _collector->set_free(hr->hrm_index()); + add_to_compaction_queue(hr); +} + +inline bool G1DetermineCompactionQueueClosure::should_compact(HeapRegion* hr) const { + // There is no need to iterate and forward objects in pinned regions ie. + // prepare them for compaction. + if (hr->is_pinned()) { + return false; + } + size_t live_words = _collector->live_words(hr->hrm_index()); + size_t live_words_threshold = _collector->scope()->region_compaction_threshold(); + // High live ratio region will not be compacted. + return live_words <= live_words_threshold; +} + +inline uint G1DetermineCompactionQueueClosure::next_worker() { + uint result = _cur_worker; + _cur_worker = (_cur_worker + 1) % _collector->workers(); + return result; +} + +inline G1FullGCCompactionPoint* G1DetermineCompactionQueueClosure::next_compaction_point() { + return _collector->compaction_point(next_worker()); +} + +inline void G1DetermineCompactionQueueClosure::add_to_compaction_queue(HeapRegion* hr) { + hr->set_compaction_top(hr->bottom()); + G1FullGCCompactionPoint* cp = next_compaction_point(); + if (!cp->is_initialized()) { + cp->initialize(hr); + } + // Add region to the compaction queue. + cp->add(hr); +} + +inline bool G1DetermineCompactionQueueClosure::do_heap_region(HeapRegion* hr) { + if (should_compact(hr)) { + assert(!hr->is_humongous(), "moving humongous objects not supported."); + add_to_compaction_queue(hr); + } else { + assert(hr->containing_set() == nullptr, "already cleared by PrepareRegionsClosure"); + if (hr->is_humongous()) { + oop obj = cast_to_oop(hr->humongous_start_region()->bottom()); + bool is_empty = !_collector->mark_bitmap()->is_marked(obj); + if (is_empty) { + free_pinned_region(hr); + } + } else if (hr->is_open_archive()) { + bool is_empty = _collector->live_words(hr->hrm_index()) == 0; + if (is_empty) { + free_pinned_region(hr); + } + } else if (hr->is_closed_archive()) { + // nothing to do with closed archive region + } else { + assert(MarkSweepDeadRatio > 0, + "only skip compaction for other regions when MarkSweepDeadRatio > 0"); + + // Too many live objects in the region; skip compacting it. + _collector->update_from_compacting_to_skip_compacting(hr->hrm_index()); + log_trace(gc, phases)("Phase 2: skip compaction region index: %u, live words: " SIZE_FORMAT, + hr->hrm_index(), _collector->live_words(hr->hrm_index())); + } + } + + return false; +} + +inline size_t G1SerialRePrepareClosure::apply(oop obj) { + // We only re-prepare objects forwarded within the current region, so + // skip objects that are already forwarded to another region. + if (obj->is_forwarded() && !_current->is_in(obj->forwardee())) { + return obj->size(); + } + + // Get size and forward. + size_t size = obj->size(); + _cp->forward(obj, size); + + return size; +} + +#endif // SHARE_GC_G1_G1FULLGCPREPARETASK_INLINE_HPP diff --git a/src/hotspot/share/gc/g1/g1FullGCScope.cpp b/src/hotspot/share/gc/g1/g1FullGCScope.cpp index b4d3b3656034b5bc7cd6b3567494d25bfb9b0191..38752db1bffccc176869b694e67c19d5a2087cc1 100644 --- a/src/hotspot/share/gc/g1/g1FullGCScope.cpp +++ b/src/hotspot/share/gc/g1/g1FullGCScope.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -38,7 +38,7 @@ G1FullGCJFRTracerMark::~G1FullGCJFRTracerMark() { G1FullGCScope::G1FullGCScope(G1MonitoringSupport* monitoring_support, bool explicit_gc, bool clear_soft, - bool do_maximum_compaction) : + bool do_maximal_compaction) : _rm(), _explicit_gc(explicit_gc), _g1h(G1CollectedHeap::heap()), @@ -50,7 +50,7 @@ G1FullGCScope::G1FullGCScope(G1MonitoringSupport* monitoring_support, _soft_refs(clear_soft, _g1h->soft_ref_policy()), _monitoring_scope(monitoring_support, true /* full_gc */, true /* all_memory_pools_affected */), _heap_printer(_g1h), - _region_compaction_threshold(do_maximum_compaction ? + _region_compaction_threshold(do_maximal_compaction ? HeapRegion::GrainWords : (1 - MarkSweepDeadRatio / 100.0) * HeapRegion::GrainWords) { } @@ -70,6 +70,6 @@ G1FullGCTracer* G1FullGCScope::tracer() { return &_tracer; } -size_t G1FullGCScope::region_compaction_threshold() { +size_t G1FullGCScope::region_compaction_threshold() const { return _region_compaction_threshold; } diff --git a/src/hotspot/share/gc/g1/g1FullGCScope.hpp b/src/hotspot/share/gc/g1/g1FullGCScope.hpp index c0035b9052aa7e8136e3ef825f739629e6caeeb1..a6e079f4d63dde8ccc7dbd9207bf2218bf4ac6b4 100644 --- a/src/hotspot/share/gc/g1/g1FullGCScope.hpp +++ b/src/hotspot/share/gc/g1/g1FullGCScope.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -71,7 +71,7 @@ public: STWGCTimer* timer(); G1FullGCTracer* tracer(); G1HeapTransition* heap_transition(); - size_t region_compaction_threshold(); + size_t region_compaction_threshold() const; }; #endif // SHARE_GC_G1_G1FULLGCSCOPE_HPP diff --git a/src/hotspot/share/gc/g1/g1GCParPhaseTimesTracker.hpp b/src/hotspot/share/gc/g1/g1GCParPhaseTimesTracker.hpp index 11a62b03825ee34b9e724287836d95ad6028a514..af626e99fd413566e70c5715b730e6e1842e6017 100644 --- a/src/hotspot/share/gc/g1/g1GCParPhaseTimesTracker.hpp +++ b/src/hotspot/share/gc/g1/g1GCParPhaseTimesTracker.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -36,10 +36,10 @@ protected: G1GCPhaseTimes* _phase_times; uint _worker_id; EventGCPhaseParallel _event; - bool _must_record; + bool _allow_multiple_record; public: - G1GCParPhaseTimesTracker(G1GCPhaseTimes* phase_times, G1GCPhaseTimes::GCParPhases phase, uint worker_id, bool must_record = true); + G1GCParPhaseTimesTracker(G1GCPhaseTimes* phase_times, G1GCPhaseTimes::GCParPhases phase, uint worker_id, bool allow_multiple_record = false); virtual ~G1GCParPhaseTimesTracker(); }; diff --git a/src/hotspot/share/gc/g1/g1GCPhaseTimes.cpp b/src/hotspot/share/gc/g1/g1GCPhaseTimes.cpp index c77dd7196f5409022cc902bb4024496be489484a..4a45a3eca651b5a09e982c4abc5a500b66648fe3 100644 --- a/src/hotspot/share/gc/g1/g1GCPhaseTimes.cpp +++ b/src/hotspot/share/gc/g1/g1GCPhaseTimes.cpp @@ -102,7 +102,7 @@ G1GCPhaseTimes::G1GCPhaseTimes(STWGCTimer* gc_timer, uint max_gc_threads) : _gc_par_phases[GCWorkerEnd] = new WorkerDataArray("GCWorkerEnd", "GC Worker End (ms):", max_gc_threads); _gc_par_phases[Other] = new WorkerDataArray("Other", "GC Worker Other (ms):", max_gc_threads); _gc_par_phases[MergePSS] = new WorkerDataArray("MergePSS", "Merge Per-Thread State (ms):", max_gc_threads); - _gc_par_phases[RemoveSelfForwardingPtr] = new WorkerDataArray("RemoveSelfForwardingPtr", "Remove Self Forwards (ms):", max_gc_threads); + _gc_par_phases[RestoreRetainedRegions] = new WorkerDataArray("RestoreRetainedRegions", "Restore Retained Regions (ms):", max_gc_threads); _gc_par_phases[ClearCardTable] = new WorkerDataArray("ClearLoggedCards", "Clear Logged Cards (ms):", max_gc_threads); _gc_par_phases[RecalculateUsed] = new WorkerDataArray("RecalculateUsed", "Recalculate Used Memory (ms):", max_gc_threads); _gc_par_phases[ResetHotCardCache] = new WorkerDataArray("ResetHotCardCache", "Reset Hot Card Cache (ms):", max_gc_threads); @@ -116,10 +116,12 @@ G1GCPhaseTimes::G1GCPhaseTimes(STWGCTimer* gc_timer, uint max_gc_threads) : _gc_par_phases[ScanHR]->create_thread_work_items("Scanned Cards:", ScanHRScannedCards); _gc_par_phases[ScanHR]->create_thread_work_items("Scanned Blocks:", ScanHRScannedBlocks); _gc_par_phases[ScanHR]->create_thread_work_items("Claimed Chunks:", ScanHRClaimedChunks); + _gc_par_phases[ScanHR]->create_thread_work_items("Found Roots:", ScanHRFoundRoots); _gc_par_phases[OptScanHR]->create_thread_work_items("Scanned Cards:", ScanHRScannedCards); _gc_par_phases[OptScanHR]->create_thread_work_items("Scanned Blocks:", ScanHRScannedBlocks); _gc_par_phases[OptScanHR]->create_thread_work_items("Claimed Chunks:", ScanHRClaimedChunks); + _gc_par_phases[OptScanHR]->create_thread_work_items("Found Roots:", ScanHRFoundRoots); _gc_par_phases[OptScanHR]->create_thread_work_items("Scanned Refs:", ScanHRScannedOptRefs); _gc_par_phases[OptScanHR]->create_thread_work_items("Used Memory:", ScanHRUsedMemory); @@ -130,6 +132,8 @@ G1GCPhaseTimes::G1GCPhaseTimes(STWGCTimer* gc_timer, uint max_gc_threads) : _gc_par_phases[MergePSS]->create_thread_work_items("LAB Waste", MergePSSLABWasteBytes); _gc_par_phases[MergePSS]->create_thread_work_items("LAB Undo Waste", MergePSSLABUndoWasteBytes); + _gc_par_phases[RestoreRetainedRegions]->create_thread_work_items("Evacuation Failure Regions:", RestoreRetainedRegionsNum); + _gc_par_phases[EagerlyReclaimHumongousObjects]->create_thread_work_items("Humongous Total", EagerlyReclaimNumTotal); _gc_par_phases[EagerlyReclaimHumongousObjects]->create_thread_work_items("Humongous Candidates", EagerlyReclaimNumCandidates); _gc_par_phases[EagerlyReclaimHumongousObjects]->create_thread_work_items("Humongous Reclaimed", EagerlyReclaimNumReclaimed); @@ -264,11 +268,7 @@ void G1GCPhaseTimes::add_time_secs(GCParPhases phase, uint worker_id, double sec } void G1GCPhaseTimes::record_or_add_time_secs(GCParPhases phase, uint worker_id, double secs) { - if (_gc_par_phases[phase]->get(worker_id) == _gc_par_phases[phase]->uninitialized()) { - record_time_secs(phase, worker_id, secs); - } else { - add_time_secs(phase, worker_id, secs); - } + _gc_par_phases[phase]->set_or_add(worker_id, secs); } double G1GCPhaseTimes::get_time_secs(GCParPhases phase, uint worker_id) { @@ -482,7 +482,7 @@ double G1GCPhaseTimes::print_post_evacuate_collection_set(bool evacuation_failed debug_phase(_gc_par_phases[ClearCardTable], 1); debug_phase(_gc_par_phases[RecalculateUsed], 1); if (evacuation_failed) { - debug_phase(_gc_par_phases[RemoveSelfForwardingPtr], 1); + debug_phase(_gc_par_phases[RestoreRetainedRegions], 1); } trace_phase(_gc_par_phases[RedirtyCards]); @@ -576,8 +576,8 @@ void G1EvacPhaseWithTrimTimeTracker::stop() { _stopped = true; } -G1GCParPhaseTimesTracker::G1GCParPhaseTimesTracker(G1GCPhaseTimes* phase_times, G1GCPhaseTimes::GCParPhases phase, uint worker_id, bool must_record) : - _start_time(), _phase(phase), _phase_times(phase_times), _worker_id(worker_id), _event(), _must_record(must_record) { +G1GCParPhaseTimesTracker::G1GCParPhaseTimesTracker(G1GCPhaseTimes* phase_times, G1GCPhaseTimes::GCParPhases phase, uint worker_id, bool allow_multiple_record) : + _start_time(), _phase(phase), _phase_times(phase_times), _worker_id(worker_id), _event(), _allow_multiple_record(allow_multiple_record) { if (_phase_times != NULL) { _start_time = Ticks::now(); } @@ -585,10 +585,10 @@ G1GCParPhaseTimesTracker::G1GCParPhaseTimesTracker(G1GCPhaseTimes* phase_times, G1GCParPhaseTimesTracker::~G1GCParPhaseTimesTracker() { if (_phase_times != NULL) { - if (_must_record) { - _phase_times->record_time_secs(_phase, _worker_id, (Ticks::now() - _start_time).seconds()); - } else { + if (_allow_multiple_record) { _phase_times->record_or_add_time_secs(_phase, _worker_id, (Ticks::now() - _start_time).seconds()); + } else { + _phase_times->record_time_secs(_phase, _worker_id, (Ticks::now() - _start_time).seconds()); } _event.commit(GCId::current(), _worker_id, G1GCPhaseTimes::phase_name(_phase)); } diff --git a/src/hotspot/share/gc/g1/g1GCPhaseTimes.hpp b/src/hotspot/share/gc/g1/g1GCPhaseTimes.hpp index 255aab6f96ee98b6501cff361023a02701dac303..0cd6aebc8ccec453d72e39774769f0d7ff8f1c6f 100644 --- a/src/hotspot/share/gc/g1/g1GCPhaseTimes.hpp +++ b/src/hotspot/share/gc/g1/g1GCPhaseTimes.hpp @@ -77,7 +77,7 @@ class G1GCPhaseTimes : public CHeapObj { RebuildFreeList, SampleCollectionSetCandidates, MergePSS, - RemoveSelfForwardingPtr, + RestoreRetainedRegions, ClearCardTable, RecalculateUsed, ResetHotCardCache, @@ -123,6 +123,7 @@ class G1GCPhaseTimes : public CHeapObj { ScanHRScannedCards, ScanHRScannedBlocks, ScanHRClaimedChunks, + ScanHRFoundRoots, ScanHRScannedOptRefs, ScanHRUsedMemory }; @@ -143,6 +144,10 @@ class G1GCPhaseTimes : public CHeapObj { MergePSSLABUndoWasteBytes }; + enum RestoreRetainedRegionsWorkItems { + RestoreRetainedRegionsNum, + }; + enum GCEagerlyReclaimHumongousObjectsItems { EagerlyReclaimNumTotal, EagerlyReclaimNumCandidates, diff --git a/src/hotspot/share/gc/g1/g1HeapRegionAttr.hpp b/src/hotspot/share/gc/g1/g1HeapRegionAttr.hpp index 2b8fb3532ee0ea574a32d4e546ddb21648b8eaa4..d59d7e1c0fbf25c21cce7046838ba32617fa6e08 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegionAttr.hpp +++ b/src/hotspot/share/gc/g1/g1HeapRegionAttr.hpp @@ -32,13 +32,7 @@ // lookups for that information all over the place. struct G1HeapRegionAttr { public: -#if defined(_M_ARM64)&& defined(_MSC_VER) && _MSC_VER <= 1927 - // workaround for MSCV ARM64 bug - // https://developercommunity.visualstudio.com/content/problem/1079221/arm64-bad-code-generation-around-signed-char-arith.html - typedef int32_t region_type_t; -#else typedef int8_t region_type_t; -#endif // remset_is_tracked_t is essentially bool, but we need precise control // on the size, and sizeof(bool) is implementation specific. typedef uint8_t remset_is_tracked_t; diff --git a/src/hotspot/share/gc/g1/g1HeapRegionEventSender.hpp b/src/hotspot/share/gc/g1/g1HeapRegionEventSender.hpp index c8518a5172e2e31a0773e145b7f2d86a13e1be5e..eb3d60656d4a9c0c39d69d49d3a3ca2ad1a24341 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegionEventSender.hpp +++ b/src/hotspot/share/gc/g1/g1HeapRegionEventSender.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -25,7 +25,7 @@ #ifndef SHARE_GC_G1_G1HEAPREGIONEVENTSENDER_HPP #define SHARE_GC_G1_G1HEAPREGIONEVENTSENDER_HPP -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" class G1HeapRegionEventSender : public AllStatic { public: diff --git a/src/hotspot/share/gc/g1/g1HeapRegionTraceType.hpp b/src/hotspot/share/gc/g1/g1HeapRegionTraceType.hpp index ab3ee03137c76a661d859787218b5bed7b10886c..1c5690e566d8a1200e444f65fcab091654134988 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegionTraceType.hpp +++ b/src/hotspot/share/gc/g1/g1HeapRegionTraceType.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -25,7 +25,7 @@ #ifndef SHARE_GC_G1_G1HEAPREGIONTRACETYPE_HPP #define SHARE_GC_G1_G1HEAPREGIONTRACETYPE_HPP -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" #include "utilities/debug.hpp" class G1HeapRegionTraceType : AllStatic { diff --git a/src/hotspot/share/gc/g1/g1HeapVerifier.cpp b/src/hotspot/share/gc/g1/g1HeapVerifier.cpp index 2c18b4a7346ad8f4c52571c1218fff5c568a4a8c..89a90177c8cad795f41bc89696677494667fd232 100644 --- a/src/hotspot/share/gc/g1/g1HeapVerifier.cpp +++ b/src/hotspot/share/gc/g1/g1HeapVerifier.cpp @@ -53,7 +53,6 @@ private: bool _failures; public: // _vo == UsePrevMarking -> use "prev" marking information, - // _vo == UseNextMarking -> use "next" marking information, // _vo == UseFullMarking -> use "next" marking bitmap but no TAMS VerifyRootsClosure(VerifyOption vo) : _g1h(G1CollectedHeap::heap()), @@ -114,9 +113,9 @@ class G1VerifyCodeRootOopClosure: public OopClosure { // Now fetch the region containing the object HeapRegion* hr = _g1h->heap_region_containing(obj); HeapRegionRemSet* hrrs = hr->rem_set(); - // Verify that the strong code root list for this region + // Verify that the code root list for this region // contains the nmethod - if (!hrrs->strong_code_roots_list_contains(_nm)) { + if (!hrrs->code_roots_list_contains(_nm)) { log_error(gc, verify)("Code root location " PTR_FORMAT " " "from nmethod " PTR_FORMAT " not in strong " "code roots for region [" PTR_FORMAT "," PTR_FORMAT ")", @@ -206,7 +205,6 @@ private: VerifyOption _vo; public: // _vo == UsePrevMarking -> use "prev" marking information, - // _vo == UseNextMarking -> use "next" marking information, // _vo == UseFullMarking -> use "next" marking bitmap but no TAMS. VerifyObjsInRegionClosure(HeapRegion *hr, VerifyOption vo) : _live_bytes(0), _hr(hr), _vo(vo) { @@ -359,7 +357,6 @@ private: bool _failures; public: // _vo == UsePrevMarking -> use "prev" marking information, - // _vo == UseNextMarking -> use "next" marking information, // _vo == UseFullMarking -> use "next" marking bitmap but no TAMS VerifyRegionClosure(bool par, VerifyOption vo) : _par(par), @@ -407,16 +404,10 @@ public: } else if (!r->is_starts_humongous()) { VerifyObjsInRegionClosure not_dead_yet_cl(r, _vo); r->object_iterate(¬_dead_yet_cl); - if (_vo != VerifyOption_G1UseNextMarking) { - if (r->max_live_bytes() < not_dead_yet_cl.live_bytes()) { - log_error(gc, verify)("[" PTR_FORMAT "," PTR_FORMAT "] max_live_bytes " SIZE_FORMAT " < calculated " SIZE_FORMAT, + if (r->max_live_bytes() < not_dead_yet_cl.live_bytes()) { + log_error(gc, verify)("[" PTR_FORMAT "," PTR_FORMAT "] max_live_bytes " SIZE_FORMAT " < calculated " SIZE_FORMAT, p2i(r->bottom()), p2i(r->end()), r->max_live_bytes(), not_dead_yet_cl.live_bytes()); - _failures = true; - } - } else { - // When vo == UseNextMarking we cannot currently do a sanity - // check on the live bytes as the calculation has not been - // finalized yet. + _failures = true; } } } @@ -435,7 +426,6 @@ private: public: // _vo == UsePrevMarking -> use "prev" marking information, - // _vo == UseNextMarking -> use "next" marking information, // _vo == UseFullMarking -> use "next" marking bitmap but no TAMS G1ParVerifyTask(G1CollectedHeap* g1h, VerifyOption vo) : WorkerTask("Parallel verify task"), diff --git a/src/hotspot/share/gc/g1/g1HeapVerifier.hpp b/src/hotspot/share/gc/g1/g1HeapVerifier.hpp index 1bcb27f02e3b13b2746c596e647ea00468780302..877742715e5c813a55ab53eb82d5968ac70fc13f 100644 --- a/src/hotspot/share/gc/g1/g1HeapVerifier.hpp +++ b/src/hotspot/share/gc/g1/g1HeapVerifier.hpp @@ -61,15 +61,11 @@ public: // Perform verification. // vo == UsePrevMarking -> use "prev" marking information, - // vo == UseNextMarking -> use "next" marking information // vo == UseFullMarking -> use "next" marking bitmap but no TAMS // // NOTE: Only the "prev" marking information is guaranteed to be // consistent most of the time, so most calls to this should use // vo == UsePrevMarking. - // Currently, there is only one case where this is called with - // vo == UseNextMarking, which is to verify the "next" marking - // information at the end of remark. // Currently there is only one place where this is called with // vo == UseFullMarking, which is to verify the marking during a // full GC. diff --git a/src/hotspot/share/gc/g1/g1OldGenAllocationTracker.cpp b/src/hotspot/share/gc/g1/g1OldGenAllocationTracker.cpp index 6289bc82f243ae043974183f5c09203331d22684..d0a0542152ed51b4cb5e79553afd27d4a09af0cf 100644 --- a/src/hotspot/share/gc/g1/g1OldGenAllocationTracker.cpp +++ b/src/hotspot/share/gc/g1/g1OldGenAllocationTracker.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Amazon.com, Inc. 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 diff --git a/src/hotspot/share/gc/g1/g1OldGenAllocationTracker.hpp b/src/hotspot/share/gc/g1/g1OldGenAllocationTracker.hpp index 0c934f4d31ec77f943acb3a2c52add4b9f35be23..ed55c0f9bed913f61ea764c94d5af575114ea704 100644 --- a/src/hotspot/share/gc/g1/g1OldGenAllocationTracker.hpp +++ b/src/hotspot/share/gc/g1/g1OldGenAllocationTracker.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Amazon.com, Inc. 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 diff --git a/src/hotspot/share/gc/g1/g1OopClosures.hpp b/src/hotspot/share/gc/g1/g1OopClosures.hpp index 9f0c4a23a55d4299863d0e899515481ac52dfe54..0dbaabbf6396de6ad1895cad77a63b1c29306e2d 100644 --- a/src/hotspot/share/gc/g1/g1OopClosures.hpp +++ b/src/hotspot/share/gc/g1/g1OopClosures.hpp @@ -61,10 +61,12 @@ public: // Used to scan cards from the DCQS or the remembered sets during garbage collection. class G1ScanCardClosure : public G1ScanClosureBase { + size_t& _heap_roots_found; public: G1ScanCardClosure(G1CollectedHeap* g1h, - G1ParScanThreadState* pss) : - G1ScanClosureBase(g1h, pss) { } + G1ParScanThreadState* pss, + size_t& heap_roots_found) : + G1ScanClosureBase(g1h, pss), _heap_roots_found(heap_roots_found) { } template void do_oop_work(T* p); virtual void do_oop(narrowOop* p) { do_oop_work(p); } diff --git a/src/hotspot/share/gc/g1/g1OopClosures.inline.hpp b/src/hotspot/share/gc/g1/g1OopClosures.inline.hpp index 74b5c19ff45823ac89499457411199a1c8e1bf5a..c368130bfcae013dc6f8a32c90711fc4876a3740 100644 --- a/src/hotspot/share/gc/g1/g1OopClosures.inline.hpp +++ b/src/hotspot/share/gc/g1/g1OopClosures.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -180,6 +180,7 @@ inline void G1ScanCardClosure::do_oop_work(T* p) { // Since the source is always from outside the collection set, here we implicitly know // that this is a cross-region reference too. prefetch_and_push(p, obj); + _heap_roots_found++; } else if (!HeapRegion::is_in_same_region(p, obj)) { handle_non_cset_obj_common(region_attr, p, obj); _par_scan_state->enqueue_card_if_tracked(region_attr, p, obj); @@ -273,7 +274,9 @@ template void G1RebuildRemSetClosure::do_oop_work(T* p) { HeapRegion* to = _g1h->heap_region_containing(obj); HeapRegionRemSet* rem_set = to->rem_set(); - rem_set->add_reference(p, _worker_id); + if (rem_set->is_tracked()) { + rem_set->add_reference(p, _worker_id); + } } #endif // SHARE_GC_G1_G1OOPCLOSURES_INLINE_HPP diff --git a/src/hotspot/share/gc/g1/g1PageBasedVirtualSpace.cpp b/src/hotspot/share/gc/g1/g1PageBasedVirtualSpace.cpp index 7a164e6461f43dd3176f37b7cc7b3e4e4566033e..94f51c8fdd1bb00d26f816bc7d9f9b25521ae064 100644 --- a/src/hotspot/share/gc/g1/g1PageBasedVirtualSpace.cpp +++ b/src/hotspot/share/gc/g1/g1PageBasedVirtualSpace.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -178,13 +178,6 @@ char* G1PageBasedVirtualSpace::bounded_end_addr(size_t end_page) const { return MIN2(_high_boundary, page_start(end_page)); } -void G1PageBasedVirtualSpace::pretouch_internal(size_t start_page, size_t end_page) { - guarantee(start_page < end_page, - "Given start page " SIZE_FORMAT " is larger or equal to end page " SIZE_FORMAT, start_page, end_page); - - os::pretouch_memory(page_start(start_page), bounded_end_addr(end_page), _page_size); -} - bool G1PageBasedVirtualSpace::commit(size_t start_page, size_t size_in_pages) { // We need to make sure to commit all pages covered by the given area. guarantee(is_area_uncommitted(start_page, size_in_pages), diff --git a/src/hotspot/share/gc/g1/g1PageBasedVirtualSpace.hpp b/src/hotspot/share/gc/g1/g1PageBasedVirtualSpace.hpp index 8b68ad60e560a3e702ea2f4e50fa332f13e1585d..0b97656c883933abf603398c14a01f7727d948e7 100644 --- a/src/hotspot/share/gc/g1/g1PageBasedVirtualSpace.hpp +++ b/src/hotspot/share/gc/g1/g1PageBasedVirtualSpace.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -87,9 +87,6 @@ class G1PageBasedVirtualSpace { // Uncommit the given memory range. void uncommit_internal(size_t start_page, size_t end_page); - // Pretouch the given memory range. - void pretouch_internal(size_t start_page, size_t end_page); - // Returns the index of the page which contains the given address. size_t addr_to_page_index(char* addr) const; diff --git a/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp b/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp index a8ffaa20ed509bcd096e84471a7318784b3ed914..3cc3c5c0120ba15101507cd3d60511d22b4bbb51 100644 --- a/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp +++ b/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp @@ -421,8 +421,8 @@ HeapWord* G1ParScanThreadState::allocate_copy_slow(G1HeapRegionAttr* dest_attr, } #if EVAC_FAILURE_INJECTOR -bool G1ParScanThreadState::inject_evacuation_failure() { - return _g1h->evac_failure_injector()->evacuation_should_fail(_evac_failure_inject_counter); +bool G1ParScanThreadState::inject_evacuation_failure(uint region_idx) { + return _g1h->evac_failure_injector()->evacuation_should_fail(_evac_failure_inject_counter, region_idx); } #endif @@ -434,6 +434,12 @@ void G1ParScanThreadState::undo_allocation(G1HeapRegionAttr dest_attr, _plab_allocator->undo_allocation(dest_attr, obj_ptr, word_sz, node_index); } +void G1ParScanThreadState::update_bot_after_copying(oop obj, size_t word_sz) { + HeapWord* obj_start = cast_from_oop(obj); + HeapRegion* region = _g1h->heap_region_containing(obj_start); + region->update_bot_for_obj(obj_start, word_sz); +} + // Private inline function, for direct internal use and providing the // implementation of the public not-inline function. MAYBE_INLINE_EVACUATION @@ -470,7 +476,7 @@ oop G1ParScanThreadState::do_copy_to_survivor_space(G1HeapRegionAttr const regio assert(_g1h->is_in_reserved(obj_ptr), "Allocated memory should be in the heap"); // Should this evacuation fail? - if (inject_evacuation_failure()) { + if (inject_evacuation_failure(from_region->hrm_index())) { // Doing this after all the allocation attempts also tests the // undo_allocation() method too. undo_allocation(dest_attr, obj_ptr, word_sz, node_index); @@ -482,6 +488,10 @@ oop G1ParScanThreadState::do_copy_to_survivor_space(G1HeapRegionAttr const regio Copy::aligned_disjoint_words(cast_from_oop(old), obj_ptr, word_sz); const oop obj = cast_to_oop(obj_ptr); + // Because the forwarding is done with memory_order_relaxed there is no + // ordering with the above copy. Clients that get the forwardee must not + // examine its contents without other synchronization, since the contents + // may not be up to date for them. const oop forward_ptr = old->forward_to_atomic(obj, old_mark, memory_order_relaxed); if (forward_ptr == NULL) { @@ -499,10 +509,7 @@ oop G1ParScanThreadState::do_copy_to_survivor_space(G1HeapRegionAttr const regio } _age_table.add(age, word_sz); } else { - // Currently we only have two destinations and we only need BOT updates for - // old. If the current allocation was done outside the PLAB this call will - // have no effect since the _top of the PLAB has not changed. - _plab_allocator->update_bot_for_plab_allocation(dest_attr, word_sz, node_index); + update_bot_after_copying(obj, word_sz); } // Most objects are not arrays, so do one array check rather than @@ -612,9 +619,11 @@ oop G1ParScanThreadState::handle_evacuation_failure_par(oop old, markWord m, siz if (forward_ptr == NULL) { // Forward-to-self succeeded. We are the "owner" of the object. HeapRegion* r = _g1h->heap_region_containing(old); - // Records evac failure objs, this will help speed up iteration - // of these objs later in *remove self forward* phase of post evacuation. - r->record_evac_failure_obj(old); + + // Objects failing evacuation will turn into old objects since the regions + // are relabeled as such. We mark the failing objects in the prev bitmap and + // later use it to handle all failed objects. + _g1h->mark_evac_failure_object(old, _worker_id); if (_evac_failure_regions->record(r->hrm_index())) { _g1h->hr_printer()->evac_failure(r); diff --git a/src/hotspot/share/gc/g1/g1ParScanThreadState.hpp b/src/hotspot/share/gc/g1/g1ParScanThreadState.hpp index 478b8745731cadaf1562fe7091ddd2221468b6e2..dab2d718b7cfd0625646e76c4fa867216492d04f 100644 --- a/src/hotspot/share/gc/g1/g1ParScanThreadState.hpp +++ b/src/hotspot/share/gc/g1/g1ParScanThreadState.hpp @@ -107,7 +107,7 @@ class G1ParScanThreadState : public CHeapObj { EvacuationFailedInfo _evacuation_failed_info; G1EvacFailureRegions* _evac_failure_regions; - bool inject_evacuation_failure() EVAC_FAILURE_INJECTOR_RETURN_( return false; ); + bool inject_evacuation_failure(uint region_idx) EVAC_FAILURE_INJECTOR_RETURN_( return false; ); public: G1ParScanThreadState(G1CollectedHeap* g1h, @@ -169,6 +169,8 @@ private: size_t word_sz, uint node_index); + void update_bot_after_copying(oop obj, size_t word_sz); + oop do_copy_to_survivor_space(G1HeapRegionAttr region_attr, oop obj, markWord old_mark); diff --git a/src/hotspot/share/gc/g1/g1ParScanThreadState.inline.hpp b/src/hotspot/share/gc/g1/g1ParScanThreadState.inline.hpp index 46651307bc1c6b160ebcf5db65939abab7f9202b..c37f0f38e51c8cf749510fad0d5798a106ee3b54 100644 --- a/src/hotspot/share/gc/g1/g1ParScanThreadState.inline.hpp +++ b/src/hotspot/share/gc/g1/g1ParScanThreadState.inline.hpp @@ -111,9 +111,9 @@ template void G1ParScanThreadState::write_ref_field_post(T* p, oop obj // References to the current collection set are references to objects that failed // evacuation. Currently these regions are always relabelled as old without // remembered sets, so skip them. - assert(dest_attr.is_in_cset() == (obj->is_forwarded() && obj->forwardee() == obj), - "Only evac-failed objects must be in the collection set here but " PTR_FORMAT " is not", p2i(obj)); if (dest_attr.is_in_cset()) { + assert(obj->is_forwarded(), "evac-failed but not forwarded: " PTR_FORMAT, p2i(obj)); + assert(obj->forwardee() == obj, "evac-failed but not self-forwarded: " PTR_FORMAT, p2i(obj)); return; } enqueue_card_if_tracked(dest_attr, p, obj); diff --git a/src/hotspot/share/gc/g1/g1Policy.cpp b/src/hotspot/share/gc/g1/g1Policy.cpp index d41ffcbee7b2890e5d0d73ab17fa393f07c06953..6de90942ff5a76cc57fa6ae2de616bc6bd57059c 100644 --- a/src/hotspot/share/gc/g1/g1Policy.cpp +++ b/src/hotspot/share/gc/g1/g1Policy.cpp @@ -1313,7 +1313,6 @@ void G1Policy::calculate_old_collection_set_regions(G1CollectionSetCandidates* c num_optional_regions = 0; uint num_expensive_regions = 0; - double predicted_old_time_ms = 0.0; double predicted_initial_time_ms = 0.0; double predicted_optional_time_ms = 0.0; @@ -1344,7 +1343,7 @@ void G1Policy::calculate_old_collection_set_regions(G1CollectionSetCandidates* c time_remaining_ms = MAX2(time_remaining_ms - predicted_time_ms, 0.0); // Add regions to old set until we reach the minimum amount if (num_initial_regions < min_old_cset_length) { - predicted_old_time_ms += predicted_time_ms; + predicted_initial_time_ms += predicted_time_ms; num_initial_regions++; // Record the number of regions added with no time remaining if (time_remaining_ms == 0.0) { @@ -1358,7 +1357,7 @@ void G1Policy::calculate_old_collection_set_regions(G1CollectionSetCandidates* c } else { // Keep adding regions to old set until we reach the optional threshold if (time_remaining_ms > optional_threshold_ms) { - predicted_old_time_ms += predicted_time_ms; + predicted_initial_time_ms += predicted_time_ms; num_initial_regions++; } else if (time_remaining_ms > 0) { // Keep adding optional regions until time is up. @@ -1382,7 +1381,7 @@ void G1Policy::calculate_old_collection_set_regions(G1CollectionSetCandidates* c } log_debug(gc, ergo, cset)("Finish choosing collection set old regions. Initial: %u, optional: %u, " - "predicted old time: %1.2fms, predicted optional time: %1.2fms, time remaining: %1.2f", + "predicted initial time: %1.2fms, predicted optional time: %1.2fms, time remaining: %1.2f", num_initial_regions, num_optional_regions, predicted_initial_time_ms, predicted_optional_time_ms, time_remaining_ms); } diff --git a/src/hotspot/share/gc/g1/g1Policy.hpp b/src/hotspot/share/gc/g1/g1Policy.hpp index 4a4efc0b32b54ae5d0da80a900604a8eabff3026..fb28e8218c5e72da24f6ef3bca508e1f07e5028e 100644 --- a/src/hotspot/share/gc/g1/g1Policy.hpp +++ b/src/hotspot/share/gc/g1/g1Policy.hpp @@ -382,7 +382,7 @@ public: // This must be called at the very beginning of an evacuation pause. void decide_on_concurrent_start_pause(); - size_t young_list_target_length() const { return _young_list_target_length; } + uint young_list_target_length() const { return _young_list_target_length; } bool should_allocate_mutator_region() const; diff --git a/src/hotspot/share/gc/g1/g1RedirtyCardsQueue.cpp b/src/hotspot/share/gc/g1/g1RedirtyCardsQueue.cpp index a1802e01821fe75d5bacc28acdc99fe07922c9cd..d6c2ae148be5adb800b11f2820642e6e4b2ea2f8 100644 --- a/src/hotspot/share/gc/g1/g1RedirtyCardsQueue.cpp +++ b/src/hotspot/share/gc/g1/g1RedirtyCardsQueue.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -67,7 +67,7 @@ void G1RedirtyCardsLocalQueueSet::enqueue(void* value) { void G1RedirtyCardsLocalQueueSet::flush() { flush_queue(_queue); _shared_qset->add_bufferlist(_buffers); - _buffers = G1BufferNodeList(); + _buffers = BufferNodeList(); } // G1RedirtyCardsLocalQueueSet::Queue @@ -109,9 +109,9 @@ BufferNode* G1RedirtyCardsQueueSet::all_completed_buffers() const { return _list.top(); } -G1BufferNodeList G1RedirtyCardsQueueSet::take_all_completed_buffers() { +BufferNodeList G1RedirtyCardsQueueSet::take_all_completed_buffers() { DEBUG_ONLY(_collecting = false;) - G1BufferNodeList result(_list.pop_all(), _tail, _entry_count); + BufferNodeList result(_list.pop_all(), _tail, _entry_count); _tail = NULL; _entry_count = 0; DEBUG_ONLY(_collecting = true;) @@ -135,7 +135,7 @@ void G1RedirtyCardsQueueSet::enqueue_completed_buffer(BufferNode* node) { update_tail(node); } -void G1RedirtyCardsQueueSet::add_bufferlist(const G1BufferNodeList& buffers) { +void G1RedirtyCardsQueueSet::add_bufferlist(const BufferNodeList& buffers) { assert(_collecting, "precondition"); if (buffers._head != NULL) { assert(buffers._tail != NULL, "invariant"); diff --git a/src/hotspot/share/gc/g1/g1RedirtyCardsQueue.hpp b/src/hotspot/share/gc/g1/g1RedirtyCardsQueue.hpp index 26bb78c4096e54a4d9f716256213a48e27ba0e8a..b464d3772985fd7afecd72da81e47d9002824623 100644 --- a/src/hotspot/share/gc/g1/g1RedirtyCardsQueue.hpp +++ b/src/hotspot/share/gc/g1/g1RedirtyCardsQueue.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -25,7 +25,7 @@ #ifndef SHARE_GC_G1_G1REDIRTYCARDSQUEUE_HPP #define SHARE_GC_G1_G1REDIRTYCARDSQUEUE_HPP -#include "gc/g1/g1BufferNodeList.hpp" +#include "gc/shared/bufferNodeList.hpp" #include "gc/shared/ptrQueue.hpp" #include "memory/padded.hpp" #include "utilities/macros.hpp" @@ -42,7 +42,7 @@ class G1RedirtyCardsLocalQueueSet : private PtrQueueSet { }; G1RedirtyCardsQueueSet* _shared_qset; - G1BufferNodeList _buffers; + BufferNodeList _buffers; Queue _queue; // Add the buffer to the local list. @@ -84,12 +84,12 @@ public: // Collect buffers. These functions are thread-safe. // precondition: Must not be concurrent with buffer processing. virtual void enqueue_completed_buffer(BufferNode* node); - void add_bufferlist(const G1BufferNodeList& buffers); + void add_bufferlist(const BufferNodeList& buffers); // Processing phase operations. // precondition: Must not be concurrent with buffer collection. BufferNode* all_completed_buffers() const; - G1BufferNodeList take_all_completed_buffers(); + BufferNodeList take_all_completed_buffers(); }; #endif // SHARE_GC_G1_G1REDIRTYCARDSQUEUE_HPP diff --git a/src/hotspot/share/gc/g1/g1RegionMarkStatsCache.cpp b/src/hotspot/share/gc/g1/g1RegionMarkStatsCache.cpp index f8ce06237c1bcf9dd6915649dc5f99086090745e..6cabe460065314bcdd88bdee1440e18c3c5919f6 100644 --- a/src/hotspot/share/gc/g1/g1RegionMarkStatsCache.cpp +++ b/src/hotspot/share/gc/g1/g1RegionMarkStatsCache.cpp @@ -30,15 +30,13 @@ G1RegionMarkStatsCache::G1RegionMarkStatsCache(G1RegionMarkStats* target, uint num_cache_entries) : _target(target), - _cache(NULL), _num_cache_entries(num_cache_entries), - _cache_hits(0), - _cache_misses(0), _num_cache_entries_mask(_num_cache_entries - 1) { guarantee(is_power_of_2(num_cache_entries), "Number of cache entries must be power of two, but is %u", num_cache_entries); _cache = NEW_C_HEAP_ARRAY(G1RegionMarkStatsCacheEntry, _num_cache_entries, mtGC); + reset(); } G1RegionMarkStatsCache::~G1RegionMarkStatsCache() { diff --git a/src/hotspot/share/gc/g1/g1RemSet.cpp b/src/hotspot/share/gc/g1/g1RemSet.cpp index b689e6497625564f9e1d0d3f8eda2a221fc0e6fa..6496b6eaf64924cc8ca813dc691befc0d22a4b6f 100644 --- a/src/hotspot/share/gc/g1/g1RemSet.cpp +++ b/src/hotspot/share/gc/g1/g1RemSet.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -45,6 +45,7 @@ #include "gc/g1/heapRegion.inline.hpp" #include "gc/g1/heapRegionManager.inline.hpp" #include "gc/g1/heapRegionRemSet.inline.hpp" +#include "gc/shared/bufferNodeList.hpp" #include "gc/shared/gcTraceTime.inline.hpp" #include "gc/shared/ptrQueue.hpp" #include "gc/shared/suspendibleThreadSet.hpp" @@ -106,7 +107,7 @@ class G1RemSetScanState : public CHeapObj { // within a region to claim. Dependent on the region size as proxy for the heap // size, we limit the total number of chunks to limit memory usage and maintenance // effort of that table vs. granularity of distributing scanning work. - // Testing showed that 8 for 1M/2M region, 16 for 4M/8M regions, 32 for 16/32M regions, + // Testing showed that 64 for 1M/2M region, 128 for 4M/8M regions, 256 for 16/32M regions, // and so on seems to be such a good trade-off. static uint get_chunks_per_region(uint log_region_size) { // Limit the expected input values to current known possible values of the @@ -114,7 +115,7 @@ class G1RemSetScanState : public CHeapObj { // values for region size. assert(log_region_size >= 20 && log_region_size <= 29, "expected value in [20,29], but got %u", log_region_size); - return 1u << (log_region_size / 2 - 7); + return 1u << (log_region_size / 2 - 4); } uint _scan_chunks_per_region; // Number of chunks per region. @@ -774,6 +775,7 @@ class G1ScanHRForRegionClosure : public HeapRegionClosure { size_t _cards_scanned; size_t _blocks_scanned; size_t _chunks_claimed; + size_t _heap_roots_found; Tickspan _rem_set_root_scan_time; Tickspan _rem_set_trim_partially_time; @@ -785,7 +787,7 @@ class G1ScanHRForRegionClosure : public HeapRegionClosure { HeapWord* scan_memregion(uint region_idx_for_card, MemRegion mr) { HeapRegion* const card_region = _g1h->region_at(region_idx_for_card); - G1ScanCardClosure card_cl(_g1h, _pss); + G1ScanCardClosure card_cl(_g1h, _pss, _heap_roots_found); HeapWord* const scanned_to = card_region->oops_on_memregion_seq_iterate_careful(mr, &card_cl); assert(scanned_to != NULL, "Should be able to scan range"); @@ -807,7 +809,7 @@ class G1ScanHRForRegionClosure : public HeapRegionClosure { return; } - HeapWord* scan_end = MIN2(card_start + (num_cards << BOTConstants::LogN_words), top); + HeapWord* scan_end = MIN2(card_start + (num_cards << BOTConstants::log_card_size_in_words()), top); if (_scanned_to >= scan_end) { return; } @@ -880,6 +882,7 @@ public: _cards_scanned(0), _blocks_scanned(0), _chunks_claimed(0), + _heap_roots_found(0), _rem_set_root_scan_time(), _rem_set_trim_partially_time(), _scanned_to(NULL), @@ -906,6 +909,7 @@ public: size_t cards_scanned() const { return _cards_scanned; } size_t blocks_scanned() const { return _blocks_scanned; } size_t chunks_claimed() const { return _chunks_claimed; } + size_t heap_roots_found() const { return _heap_roots_found; } }; void G1RemSet::scan_heap_roots(G1ParScanThreadState* pss, @@ -924,6 +928,7 @@ void G1RemSet::scan_heap_roots(G1ParScanThreadState* pss, p->record_or_add_thread_work_item(scan_phase, worker_id, cl.cards_scanned(), G1GCPhaseTimes::ScanHRScannedCards); p->record_or_add_thread_work_item(scan_phase, worker_id, cl.blocks_scanned(), G1GCPhaseTimes::ScanHRScannedBlocks); p->record_or_add_thread_work_item(scan_phase, worker_id, cl.chunks_claimed(), G1GCPhaseTimes::ScanHRClaimedChunks); + p->record_or_add_thread_work_item(scan_phase, worker_id, cl.heap_roots_found(), G1GCPhaseTimes::ScanHRFoundRoots); } // Heap region closure to be applied to all regions in the current collection set @@ -937,11 +942,12 @@ class G1ScanCollectionSetRegionClosure : public HeapRegionClosure { uint _worker_id; + size_t _opt_roots_scanned; size_t _opt_refs_scanned; size_t _opt_refs_memory_used; - Tickspan _strong_code_root_scan_time; - Tickspan _strong_code_trim_partially_time; + Tickspan _code_root_scan_time; + Tickspan _code_trim_partially_time; Tickspan _rem_set_opt_root_scan_time; Tickspan _rem_set_opt_trim_partially_time; @@ -951,7 +957,7 @@ class G1ScanCollectionSetRegionClosure : public HeapRegionClosure { G1OopStarChunkedList* opt_rem_set_list = _pss->oops_into_optional_region(r); - G1ScanCardClosure scan_cl(G1CollectedHeap::heap(), _pss); + G1ScanCardClosure scan_cl(G1CollectedHeap::heap(), _pss, _opt_roots_scanned); G1ScanRSForOptionalClosure cl(G1CollectedHeap::heap(), &scan_cl); _opt_refs_scanned += opt_rem_set_list->oops_do(&cl, _pss->closures()->strong_oops()); _opt_refs_memory_used += opt_rem_set_list->used_memory(); @@ -970,10 +976,11 @@ public: _scan_phase(scan_phase), _code_roots_phase(code_roots_phase), _worker_id(worker_id), + _opt_roots_scanned(0), _opt_refs_scanned(0), _opt_refs_memory_used(0), - _strong_code_root_scan_time(), - _strong_code_trim_partially_time(), + _code_root_scan_time(), + _code_trim_partially_time(), _rem_set_opt_root_scan_time(), _rem_set_opt_trim_partially_time() { } @@ -990,9 +997,9 @@ public: if (_scan_state->claim_collection_set_region(region_idx)) { EventGCPhaseParallel event; - G1EvacPhaseWithTrimTimeTracker timer(_pss, _strong_code_root_scan_time, _strong_code_trim_partially_time); - // Scan the strong code root list attached to the current region - r->strong_code_roots_do(_pss->closures()->weak_codeblobs()); + G1EvacPhaseWithTrimTimeTracker timer(_pss, _code_root_scan_time, _code_trim_partially_time); + // Scan the code root list attached to the current region + r->code_roots_do(_pss->closures()->weak_codeblobs()); event.commit(GCId::current(), _worker_id, G1GCPhaseTimes::phase_name(_code_roots_phase)); } @@ -1000,12 +1007,13 @@ public: return false; } - Tickspan strong_code_root_scan_time() const { return _strong_code_root_scan_time; } - Tickspan strong_code_root_trim_partially_time() const { return _strong_code_trim_partially_time; } + Tickspan code_root_scan_time() const { return _code_root_scan_time; } + Tickspan code_root_trim_partially_time() const { return _code_trim_partially_time; } Tickspan rem_set_opt_root_scan_time() const { return _rem_set_opt_root_scan_time; } Tickspan rem_set_opt_trim_partially_time() const { return _rem_set_opt_trim_partially_time; } + size_t opt_roots_scanned() const { return _opt_roots_scanned; } size_t opt_refs_scanned() const { return _opt_refs_scanned; } size_t opt_refs_memory_used() const { return _opt_refs_memory_used; } }; @@ -1023,11 +1031,12 @@ void G1RemSet::scan_collection_set_regions(G1ParScanThreadState* pss, p->record_or_add_time_secs(scan_phase, worker_id, cl.rem_set_opt_root_scan_time().seconds()); p->record_or_add_time_secs(scan_phase, worker_id, cl.rem_set_opt_trim_partially_time().seconds()); - p->record_or_add_time_secs(coderoots_phase, worker_id, cl.strong_code_root_scan_time().seconds()); - p->add_time_secs(objcopy_phase, worker_id, cl.strong_code_root_trim_partially_time().seconds()); + p->record_or_add_time_secs(coderoots_phase, worker_id, cl.code_root_scan_time().seconds()); + p->add_time_secs(objcopy_phase, worker_id, cl.code_root_trim_partially_time().seconds()); // At this time we record some metrics only for the evacuations after the initial one. if (scan_phase == G1GCPhaseTimes::OptScanHR) { + p->record_or_add_thread_work_item(scan_phase, worker_id, cl.opt_roots_scanned(), G1GCPhaseTimes::ScanHRFoundRoots); p->record_or_add_thread_work_item(scan_phase, worker_id, cl.opt_refs_scanned(), G1GCPhaseTimes::ScanHRScannedOptRefs); p->record_or_add_thread_work_item(scan_phase, worker_id, cl.opt_refs_memory_used(), G1GCPhaseTimes::ScanHRUsedMemory); } @@ -1251,6 +1260,46 @@ class G1MergeHeapRootsTask : public WorkerTask { G1MergeCardSetStats stats() const { return _stats; } }; + // Closure to clear the prev bitmap for any old region in the collection set. + // This is needed to be able to use the bitmap for evacuation failure handling. + class G1ClearBitmapClosure : public HeapRegionClosure { + G1CollectedHeap* _g1h; + void assert_bitmap_clear(HeapRegion* hr, const G1CMBitMap* bitmap) { + assert(bitmap->get_next_marked_addr(hr->bottom(), hr->end()) == hr->end(), + "Bitmap should have no mark for young regions"); + } + public: + G1ClearBitmapClosure(G1CollectedHeap* g1h) : _g1h(g1h) { } + + bool do_heap_region(HeapRegion* hr) { + assert(_g1h->is_in_cset(hr), "Should only be used iterating the collection set"); + // Young regions should always have cleared bitmaps, so only clear old. + if (hr->is_old()) { + _g1h->clear_prev_bitmap_for_region(hr); + } else { + assert(hr->is_young(), "Should only be young and old regions in collection set"); + assert_bitmap_clear(hr, _g1h->concurrent_mark()->prev_mark_bitmap()); + } + return false; + } + }; + + // Helper to allow two closure to be applied when + // iterating through the collection set. + class G1CombinedClosure : public HeapRegionClosure { + HeapRegionClosure* _closure1; + HeapRegionClosure* _closure2; + public: + G1CombinedClosure(HeapRegionClosure* cl1, HeapRegionClosure* cl2) : + _closure1(cl1), + _closure2(cl2) { } + + bool do_heap_region(HeapRegion* hr) { + return _closure1->do_heap_region(hr) || + _closure2->do_heap_region(hr); + } + }; + // Visitor for the remembered sets of humongous candidate regions to merge their // remembered set into the card table. class G1FlushHumongousCandidateRemSets : public HeapRegionClosure { @@ -1381,7 +1430,7 @@ public: { if (initial_evacuation) { G1DirtyCardQueueSet& dcqs = G1BarrierSet::dirty_card_queue_set(); - G1BufferNodeList buffers = dcqs.take_all_completed_buffers(); + BufferNodeList buffers = dcqs.take_all_completed_buffers(); if (buffers._entry_count != 0) { _dirty_card_buffers.prepend(*buffers._head, *buffers._tail); } @@ -1415,12 +1464,15 @@ public: // Merge remembered sets of current candidates. { - G1GCParPhaseTimesTracker x(p, merge_remset_phase, worker_id, _initial_evacuation /* must_record */); + G1GCParPhaseTimesTracker x(p, merge_remset_phase, worker_id, !_initial_evacuation /* allow_multiple_record */); G1MergeCardSetStats stats; { - G1MergeCardSetClosure cl(_scan_state); - g1h->collection_set_iterate_increment_from(&cl, &_hr_claimer, worker_id); - stats = cl.stats(); + G1MergeCardSetClosure merge(_scan_state); + G1ClearBitmapClosure clear(g1h); + G1CombinedClosure combined(&merge, &clear); + + g1h->collection_set_iterate_increment_from(&combined, &_hr_claimer, worker_id); + stats = merge.stats(); } for (uint i = 0; i < G1GCPhaseTimes::MergeRSContainersSentinel; i++) { @@ -1666,7 +1718,7 @@ void G1RemSet::refine_card_concurrently(CardValue* const card_ptr, // Don't use addr_for(card_ptr + 1) which can ask for // a card beyond the heap. - HeapWord* end = start + G1CardTable::card_size_in_words; + HeapWord* end = start + G1CardTable::card_size_in_words(); MemRegion dirty_region(start, MIN2(scan_limit, end)); assert(!dirty_region.is_empty(), "sanity"); @@ -1906,7 +1958,7 @@ public: HeapWord* const top_at_mark_start = hr->prev_top_at_mark_start(); HeapWord* cur = hr->bottom(); - while (cur < hr->end()) { + while (true) { // After every iteration (yield point) we need to check whether the region's // TARS changed due to e.g. eager reclaim. HeapWord* const top_at_rebuild_start = _cm->top_at_rebuild_start(region_idx); diff --git a/src/hotspot/share/gc/g1/g1RemSetSummary.cpp b/src/hotspot/share/gc/g1/g1RemSetSummary.cpp index 473166ad5db699bac8159ee1fc4c3bc8dc1b6bd8..faf09063bc05f232bf47b220814260d00ea05c24 100644 --- a/src/hotspot/share/gc/g1/g1RemSetSummary.cpp +++ b/src/hotspot/share/gc/g1/g1RemSetSummary.cpp @@ -233,7 +233,7 @@ public: HeapRegionRemSet* hrrs = r->rem_set(); // HeapRegionRemSet::mem_size() includes the - // size of the strong code roots + // size of the code roots size_t rs_wasted_mem_sz = hrrs->wasted_mem_size(); size_t rs_mem_sz = hrrs->mem_size(); if (rs_mem_sz > _max_rs_mem_sz) { @@ -241,12 +241,12 @@ public: _max_rs_mem_sz_region = r; } size_t occupied_cards = hrrs->occupied(); - size_t code_root_mem_sz = hrrs->strong_code_roots_mem_size(); + size_t code_root_mem_sz = hrrs->code_roots_mem_size(); if (code_root_mem_sz > max_code_root_mem_sz()) { _max_code_root_mem_sz = code_root_mem_sz; _max_code_root_mem_sz_region = r; } - size_t code_root_elems = hrrs->strong_code_roots_list_length(); + size_t code_root_elems = hrrs->code_roots_list_length(); RegionTypeCounter* current = NULL; if (r->is_free()) { @@ -300,14 +300,14 @@ public: HeapRegionRemSet::print_static_mem_size(out); G1CardSetFreePool::free_list_pool()->print_on(out); - // Strong code root statistics + // Code root statistics HeapRegionRemSet* max_code_root_rem_set = max_code_root_mem_sz_region()->rem_set(); out->print_cr(" Total heap region code root sets sizes = " SIZE_FORMAT "%s." " Max = " SIZE_FORMAT "%s.", byte_size_in_proper_unit(total_code_root_mem_sz()), proper_unit_for_byte_size(total_code_root_mem_sz()), - byte_size_in_proper_unit(max_code_root_rem_set->strong_code_roots_mem_size()), - proper_unit_for_byte_size(max_code_root_rem_set->strong_code_roots_mem_size())); + byte_size_in_proper_unit(max_code_root_rem_set->code_roots_mem_size()), + proper_unit_for_byte_size(max_code_root_rem_set->code_roots_mem_size())); for (RegionTypeCounter** current = &counters[0]; *current != NULL; current++) { (*current)->print_code_root_mem_info_on(out, total_code_root_mem_sz()); } @@ -319,11 +319,11 @@ public: } out->print_cr(" Region with largest amount of code roots = " HR_FORMAT ", " - "size = " SIZE_FORMAT "%s, num_elems = " SIZE_FORMAT ".", + "size = " SIZE_FORMAT "%s, num_slots = " SIZE_FORMAT ".", HR_FORMAT_PARAMS(max_code_root_mem_sz_region()), - byte_size_in_proper_unit(max_code_root_rem_set->strong_code_roots_mem_size()), - proper_unit_for_byte_size(max_code_root_rem_set->strong_code_roots_mem_size()), - max_code_root_rem_set->strong_code_roots_list_length()); + byte_size_in_proper_unit(max_code_root_rem_set->code_roots_mem_size()), + proper_unit_for_byte_size(max_code_root_rem_set->code_roots_mem_size()), + max_code_root_rem_set->code_roots_list_length()); } }; diff --git a/src/hotspot/share/gc/g1/g1SegmentedArray.hpp b/src/hotspot/share/gc/g1/g1SegmentedArray.hpp index b1522ae68c1430d9c3cf9d01b6346c3de25edc52..6c73e9855cc4ec7097e05a341e3a63f604664ebc 100644 --- a/src/hotspot/share/gc/g1/g1SegmentedArray.hpp +++ b/src/hotspot/share/gc/g1/g1SegmentedArray.hpp @@ -26,150 +26,151 @@ #ifndef SHARE_GC_G1_G1SEGMENTEDARRAY_HPP #define SHARE_GC_G1_G1SEGMENTEDARRAY_HPP +#include "gc/shared/freeListAllocator.hpp" #include "memory/allocation.hpp" #include "utilities/lockFreeStack.hpp" -// A single buffer/arena containing _num_elems blocks of memory of _elem_size. -// G1SegmentedArrayBuffers can be linked together using a singly linked list. +// A single segment/arena containing _num_slots blocks of memory of _slot_size. +// G1SegmentedArraySegments can be linked together using a singly linked list. template -class G1SegmentedArrayBuffer : public CHeapObj { - const uint _elem_size; - const uint _num_elems; +class G1SegmentedArraySegment : public CHeapObj { + const uint _slot_size; + const uint _num_slots; - G1SegmentedArrayBuffer* volatile _next; + G1SegmentedArraySegment* volatile _next; - char* _buffer; // Actual data. + char* _segment; // Actual data. - // Index into the next free block to allocate into. Full if equal (or larger) - // to _num_elems (can be larger because we atomically increment this value and + // Index into the next free slot to allocate into. Full if equal (or larger) + // to _num_slots (can be larger because we atomically increment this value and // check only afterwards if the allocation has been successful). uint volatile _next_allocate; public: - G1SegmentedArrayBuffer(uint elem_size, uint num_elems, G1SegmentedArrayBuffer* next); - ~G1SegmentedArrayBuffer(); + G1SegmentedArraySegment(uint slot_size, uint num_slots, G1SegmentedArraySegment* next); + ~G1SegmentedArraySegment(); - G1SegmentedArrayBuffer* volatile* next_addr() { return &_next; } + G1SegmentedArraySegment* volatile* next_addr() { return &_next; } - void* get_new_buffer_elem(); + void* get_new_slot(); - uint num_elems() const { return _num_elems; } + uint num_slots() const { return _num_slots; } - G1SegmentedArrayBuffer* next() const { return _next; } + G1SegmentedArraySegment* next() const { return _next; } - void set_next(G1SegmentedArrayBuffer* next) { + void set_next(G1SegmentedArraySegment* next) { assert(next != this, " loop condition"); _next = next; } - void reset(G1SegmentedArrayBuffer* next) { + void reset(G1SegmentedArraySegment* next) { _next_allocate = 0; assert(next != this, " loop condition"); set_next(next); - memset((void*)_buffer, 0, (size_t)_num_elems * _elem_size); + memset((void*)_segment, 0, (size_t)_num_slots * _slot_size); } - uint elem_size() const { return _elem_size; } + uint slot_size() const { return _slot_size; } - size_t mem_size() const { return sizeof(*this) + (size_t)_num_elems * _elem_size; } + size_t mem_size() const { return sizeof(*this) + (size_t)_num_slots * _slot_size; } uint length() const { - // _next_allocate might grow larger than _num_elems in multi-thread environments + // _next_allocate might grow larger than _num_slots in multi-thread environments // due to races. - return MIN2(_next_allocate, _num_elems); + return MIN2(_next_allocate, _num_slots); } - // Copies the (valid) contents of this buffer into the destination. + // Copies the (valid) contents of this segment into the destination. void copy_to(void* dest) const { - ::memcpy(dest, _buffer, length() * _elem_size); + ::memcpy(dest, _segment, length() * _slot_size); } - bool is_full() const { return _next_allocate >= _num_elems; } + bool is_full() const { return _next_allocate >= _num_slots; } }; -// Set of (free) G1SegmentedArrayBuffers. The assumed usage is that allocation -// to it and removal of elements is strictly separate, but every action may be +// Set of (free) G1SegmentedArraySegments. The assumed usage is that allocation +// to it and removal of segments is strictly separate, but every action may be // performed by multiple threads at the same time. // Counts and memory usage are current on a best-effort basis if accessed concurrently. template -class G1SegmentedArrayBufferList { - static G1SegmentedArrayBuffer* volatile* next_ptr(G1SegmentedArrayBuffer& node) { - return node.next_addr(); +class G1SegmentedArrayFreeList { + static G1SegmentedArraySegment* volatile* next_ptr(G1SegmentedArraySegment& segment) { + return segment.next_addr(); } - typedef LockFreeStack, &G1SegmentedArrayBufferList::next_ptr> NodeStack; + typedef LockFreeStack, &G1SegmentedArrayFreeList::next_ptr> SegmentStack; - NodeStack _list; + SegmentStack _list; - volatile size_t _num_buffers; + volatile size_t _num_segments; volatile size_t _mem_size; public: - G1SegmentedArrayBufferList() : _list(), _num_buffers(0), _mem_size(0) { } - ~G1SegmentedArrayBufferList() { free_all(); } + G1SegmentedArrayFreeList() : _list(), _num_segments(0), _mem_size(0) { } + ~G1SegmentedArrayFreeList() { free_all(); } - void bulk_add(G1SegmentedArrayBuffer& first, G1SegmentedArrayBuffer& last, size_t num, size_t mem_size); + void bulk_add(G1SegmentedArraySegment& first, G1SegmentedArraySegment& last, size_t num, size_t mem_size); - G1SegmentedArrayBuffer* get(); - G1SegmentedArrayBuffer* get_all(size_t& num_buffers, size_t& mem_size); + G1SegmentedArraySegment* get(); + G1SegmentedArraySegment* get_all(size_t& num_segments, size_t& mem_size); // Give back all memory to the OS. void free_all(); void print_on(outputStream* out, const char* prefix = ""); - size_t num_buffers() const { return Atomic::load(&_num_buffers); } + size_t num_segments() const { return Atomic::load(&_num_segments); } size_t mem_size() const { return Atomic::load(&_mem_size); } }; -// Configuration for G1SegmentedArray, e.g element size, element number of next G1SegmentedArrayBuffer. +// Configuration for G1SegmentedArray, e.g slot size, slot number of next G1SegmentedArraySegment. class G1SegmentedArrayAllocOptions { protected: - const uint _elem_size; - const uint _initial_num_elems; - // Defines a limit to the number of elements in the buffer - const uint _max_num_elems; - const uint _alignment; + const uint _slot_size; + const uint _initial_num_slots; + // Defines a limit to the number of slots in the segment + const uint _max_num_slots; + const uint _slot_alignment; public: - G1SegmentedArrayAllocOptions(uint elem_size, uint initial_num_elems, uint max_num_elems, uint alignment) : - _elem_size(elem_size), - _initial_num_elems(initial_num_elems), - _max_num_elems(max_num_elems), - _alignment(alignment) { - assert(_elem_size > 0, "Must be"); - assert(_initial_num_elems > 0, "Must be"); - assert(_max_num_elems > 0, "Must be"); - assert(_alignment > 0, "Must be"); + G1SegmentedArrayAllocOptions(uint slot_size, uint initial_num_slots, uint max_num_slots, uint alignment) : + _slot_size(slot_size), + _initial_num_slots(initial_num_slots), + _max_num_slots(max_num_slots), + _slot_alignment(alignment) { + assert(_slot_size > 0, "Must be"); + assert(_initial_num_slots > 0, "Must be"); + assert(_max_num_slots > 0, "Must be"); + assert(_slot_alignment > 0, "Must be"); } - virtual uint next_num_elems(uint prev_num_elems) const { - return _initial_num_elems; + virtual uint next_num_slots(uint prev_num_slots) const { + return _initial_num_slots; } - uint elem_size() const { return _elem_size; } + uint slot_size() const { return _slot_size; } - uint alignment() const { return _alignment; } + uint slot_alignment() const { return _slot_alignment; } }; -// A segmented array where G1SegmentedArrayBuffer is the segment, and -// G1SegmentedArrayBufferList is the free list to cache G1SegmentedArrayBuffer, +// A segmented array where G1SegmentedArraySegment is the segment, and +// G1SegmentedArrayFreeList is the free list to cache G1SegmentedArraySegments, // and G1SegmentedArrayAllocOptions is the configuration for G1SegmentedArray // attributes. // // Implementation details as below: // -// Arena-like allocator for (card set, or ...) heap memory objects (Elem elements). +// Arena-like allocator for (card set, or ...) heap memory objects (Slot slots). // -// Actual allocation from the C heap occurs on G1SegmentedArrayBuffer basis, i.e. segments -// of elements. The assumed allocation pattern for these G1SegmentedArrayBuffer elements +// Actual allocation from the C heap occurs on G1SegmentedArraySegment basis, i.e. segments +// of slots. The assumed allocation pattern for these G1SegmentedArraySegment slots // is assumed to be strictly two-phased: // -// - in the first phase, G1SegmentedArrayBuffers are allocated from the C heap (or a free +// - in the first phase, G1SegmentedArraySegments are allocated from the C heap (or a free // list given at initialization time). This allocation may occur in parallel. This // typically corresponds to a single mutator phase, but may extend over multiple. // -// - in the second phase, G1SegmentedArrayBuffers are given back in bulk to the free list. +// - in the second phase, G1SegmentedArraySegments are given back in bulk to the free list. // This is typically done during a GC pause. // // Some third party is responsible for giving back memory from the free list to @@ -180,54 +181,57 @@ public: // The class also manages a few counters for statistics using atomic operations. // Their values are only consistent within each other with extra global // synchronization. -template -class G1SegmentedArray { - // G1SegmentedArrayAllocOptions provides parameters for allocation buffer +template +class G1SegmentedArray : public FreeListConfig { + // G1SegmentedArrayAllocOptions provides parameters for allocation segment // sizing and expansion. const G1SegmentedArrayAllocOptions* _alloc_options; - G1SegmentedArrayBuffer* volatile _first; // The (start of the) list of all buffers. - G1SegmentedArrayBuffer* _last; // The last element of the list of all buffers. - volatile uint _num_buffers; // Number of assigned buffers to this allocator. - volatile size_t _mem_size; // Memory used by all buffers. + G1SegmentedArraySegment* volatile _first; // The (start of the) list of all segments. + G1SegmentedArraySegment* _last; // The last segment of the list of all segments. + volatile uint _num_segments; // Number of assigned segments to this allocator. + volatile size_t _mem_size; // Memory used by all segments. - G1SegmentedArrayBufferList* _free_buffer_list; // The global free buffer list to - // preferentially get new buffers from. + G1SegmentedArrayFreeList* _free_segment_list; // The global free segment list to + // preferentially get new segments from. - volatile uint _num_available_nodes; // Number of nodes available in all buffers (allocated + free + pending + not yet used). - volatile uint _num_allocated_nodes; // Number of total nodes allocated and in use. + volatile uint _num_available_slots; // Number of slots available in all segments (allocated + free + pending + not yet used). + volatile uint _num_allocated_slots; // Number of total slots allocated and in use. private: - inline G1SegmentedArrayBuffer* create_new_buffer(G1SegmentedArrayBuffer* const prev); + inline G1SegmentedArraySegment* create_new_segment(G1SegmentedArraySegment* const prev); DEBUG_ONLY(uint calculate_length() const;) public: - const G1SegmentedArrayBuffer* first_array_buffer() const { return Atomic::load(&_first); } + const G1SegmentedArraySegment* first_array_segment() const { return Atomic::load(&_first); } - uint num_available_nodes() const { return Atomic::load(&_num_available_nodes); } - uint num_allocated_nodes() const { - uint allocated = Atomic::load(&_num_allocated_nodes); + uint num_available_slots() const { return Atomic::load(&_num_available_slots); } + uint num_allocated_slots() const { + uint allocated = Atomic::load(&_num_allocated_slots); assert(calculate_length() == allocated, "Must be"); return allocated; } - inline uint elem_size() const; + inline uint slot_size() const; - G1SegmentedArray(const G1SegmentedArrayAllocOptions* buffer_options, - G1SegmentedArrayBufferList* free_buffer_list); + G1SegmentedArray(const G1SegmentedArrayAllocOptions* alloc_options, + G1SegmentedArrayFreeList* free_segment_list); ~G1SegmentedArray(); - // Deallocate all buffers to the free buffer list and reset this allocator. Must + // Deallocate all segments to the free segment list and reset this allocator. Must // be called in a globally synchronized area. void drop_all(); - inline Elem* allocate(); + inline void* allocate() override; - inline uint num_buffers() const; + // We do not deallocate individual slots + inline void deallocate(void* node) override { ShouldNotReachHere(); } - template - void iterate_nodes(BufferClosure& closure) const; + inline uint num_segments() const; + + template + void iterate_segments(SegmentClosure& closure) const; }; #endif //SHARE_GC_G1_G1SEGMENTEDARRAY_HPP diff --git a/src/hotspot/share/gc/g1/g1SegmentedArray.inline.hpp b/src/hotspot/share/gc/g1/g1SegmentedArray.inline.hpp index 463085602be80df592ff60f92063c66e60fc9245..69c3526e58d81686cd18d91495a7b4d1dc7bc95a 100644 --- a/src/hotspot/share/gc/g1/g1SegmentedArray.inline.hpp +++ b/src/hotspot/share/gc/g1/g1SegmentedArray.inline.hpp @@ -31,79 +31,79 @@ #include "utilities/globalCounter.inline.hpp" template -G1SegmentedArrayBuffer::G1SegmentedArrayBuffer(uint elem_size, uint num_instances, G1SegmentedArrayBuffer* next) : - _elem_size(elem_size), _num_elems(num_instances), _next(next), _next_allocate(0) { +G1SegmentedArraySegment::G1SegmentedArraySegment(uint slot_size, uint num_slots, G1SegmentedArraySegment* next) : + _slot_size(slot_size), _num_slots(num_slots), _next(next), _next_allocate(0) { - _buffer = NEW_C_HEAP_ARRAY(char, (size_t)_num_elems * elem_size, mtGCCardSet); + _segment = NEW_C_HEAP_ARRAY(char, (size_t)_num_slots * slot_size, flag); } template -G1SegmentedArrayBuffer::~G1SegmentedArrayBuffer() { - FREE_C_HEAP_ARRAY(mtGCCardSet, _buffer); +G1SegmentedArraySegment::~G1SegmentedArraySegment() { + FREE_C_HEAP_ARRAY(flag, _segment); } template -void* G1SegmentedArrayBuffer::get_new_buffer_elem() { - if (_next_allocate >= _num_elems) { +void* G1SegmentedArraySegment::get_new_slot() { + if (_next_allocate >= _num_slots) { return nullptr; } uint result = Atomic::fetch_and_add(&_next_allocate, 1u, memory_order_relaxed); - if (result >= _num_elems) { + if (result >= _num_slots) { return nullptr; } - void* r = _buffer + (uint)result * _elem_size; + void* r = _segment + (uint)result * _slot_size; return r; } template -void G1SegmentedArrayBufferList::bulk_add(G1SegmentedArrayBuffer& first, - G1SegmentedArrayBuffer& last, - size_t num, - size_t mem_size) { +void G1SegmentedArrayFreeList::bulk_add(G1SegmentedArraySegment& first, + G1SegmentedArraySegment& last, + size_t num, + size_t mem_size) { _list.prepend(first, last); - Atomic::add(&_num_buffers, num, memory_order_relaxed); + Atomic::add(&_num_segments, num, memory_order_relaxed); Atomic::add(&_mem_size, mem_size, memory_order_relaxed); } template -void G1SegmentedArrayBufferList::print_on(outputStream* out, const char* prefix) { - out->print_cr("%s: buffers %zu size %zu", - prefix, Atomic::load(&_num_buffers), Atomic::load(&_mem_size)); +void G1SegmentedArrayFreeList::print_on(outputStream* out, const char* prefix) { + out->print_cr("%s: segments %zu size %zu", + prefix, Atomic::load(&_num_segments), Atomic::load(&_mem_size)); } template -G1SegmentedArrayBuffer* G1SegmentedArrayBufferList::get() { +G1SegmentedArraySegment* G1SegmentedArrayFreeList::get() { GlobalCounter::CriticalSection cs(Thread::current()); - G1SegmentedArrayBuffer* result = _list.pop(); + G1SegmentedArraySegment* result = _list.pop(); if (result != nullptr) { - Atomic::dec(&_num_buffers, memory_order_relaxed); + Atomic::dec(&_num_segments, memory_order_relaxed); Atomic::sub(&_mem_size, result->mem_size(), memory_order_relaxed); } return result; } template -G1SegmentedArrayBuffer* G1SegmentedArrayBufferList::get_all(size_t& num_buffers, - size_t& mem_size) { +G1SegmentedArraySegment* G1SegmentedArrayFreeList::get_all(size_t& num_segments, + size_t& mem_size) { GlobalCounter::CriticalSection cs(Thread::current()); - G1SegmentedArrayBuffer* result = _list.pop_all(); - num_buffers = Atomic::load(&_num_buffers); + G1SegmentedArraySegment* result = _list.pop_all(); + num_segments = Atomic::load(&_num_segments); mem_size = Atomic::load(&_mem_size); if (result != nullptr) { - Atomic::sub(&_num_buffers, num_buffers, memory_order_relaxed); + Atomic::sub(&_num_segments, num_segments, memory_order_relaxed); Atomic::sub(&_mem_size, mem_size, memory_order_relaxed); } return result; } template -void G1SegmentedArrayBufferList::free_all() { +void G1SegmentedArrayFreeList::free_all() { size_t num_freed = 0; size_t mem_size_freed = 0; - G1SegmentedArrayBuffer* cur; + G1SegmentedArraySegment* cur; while ((cur = _list.pop()) != nullptr) { mem_size_freed += cur->mem_size(); @@ -111,130 +111,130 @@ void G1SegmentedArrayBufferList::free_all() { delete cur; } - Atomic::sub(&_num_buffers, num_freed, memory_order_relaxed); + Atomic::sub(&_num_segments, num_freed, memory_order_relaxed); Atomic::sub(&_mem_size, mem_size_freed, memory_order_relaxed); } -template -G1SegmentedArrayBuffer* G1SegmentedArray::create_new_buffer(G1SegmentedArrayBuffer* const prev) { - // Take an existing buffer if available. - G1SegmentedArrayBuffer* next = _free_buffer_list->get(); +template +G1SegmentedArraySegment* G1SegmentedArray::create_new_segment(G1SegmentedArraySegment* const prev) { + // Take an existing segment if available. + G1SegmentedArraySegment* next = _free_segment_list->get(); if (next == nullptr) { - uint prev_num_elems = (prev != nullptr) ? prev->num_elems() : 0; - uint num_elems = _alloc_options->next_num_elems(prev_num_elems); - next = new G1SegmentedArrayBuffer(elem_size(), num_elems, prev); + uint prev_num_slots = (prev != nullptr) ? prev->num_slots() : 0; + uint num_slots = _alloc_options->next_num_slots(prev_num_slots); + next = new G1SegmentedArraySegment(slot_size(), num_slots, prev); } else { - assert(elem_size() == next->elem_size() , - "Mismatch %d != %d Elem %zu", elem_size(), next->elem_size(), sizeof(Elem)); + assert(slot_size() == next->slot_size() , + "Mismatch %d != %d", slot_size(), next->slot_size()); next->reset(prev); } - // Install it as current allocation buffer. - G1SegmentedArrayBuffer* old = Atomic::cmpxchg(&_first, prev, next); + // Install it as current allocation segment. + G1SegmentedArraySegment* old = Atomic::cmpxchg(&_first, prev, next); if (old != prev) { - // Somebody else installed the buffer, use that one. + // Somebody else installed the segment, use that one. delete next; return old; } else { - // Did we install the first element in the list? If so, this is also the last. + // Did we install the first segment in the list? If so, this is also the last. if (prev == nullptr) { _last = next; } - // Successfully installed the buffer into the list. - Atomic::inc(&_num_buffers, memory_order_relaxed); + // Successfully installed the segment into the list. + Atomic::inc(&_num_segments, memory_order_relaxed); Atomic::add(&_mem_size, next->mem_size(), memory_order_relaxed); - Atomic::add(&_num_available_nodes, next->num_elems(), memory_order_relaxed); + Atomic::add(&_num_available_slots, next->num_slots(), memory_order_relaxed); return next; } } -template -uint G1SegmentedArray::elem_size() const { - return _alloc_options->elem_size(); +template +uint G1SegmentedArray::slot_size() const { + return _alloc_options->slot_size(); } -template -G1SegmentedArray::G1SegmentedArray(const G1SegmentedArrayAllocOptions* buffer_options, - G1SegmentedArrayBufferList* free_buffer_list) : - _alloc_options(buffer_options), +template +G1SegmentedArray::G1SegmentedArray(const G1SegmentedArrayAllocOptions* alloc_options, + G1SegmentedArrayFreeList* free_segment_list) : + _alloc_options(alloc_options), _first(nullptr), _last(nullptr), - _num_buffers(0), + _num_segments(0), _mem_size(0), - _free_buffer_list(free_buffer_list), - _num_available_nodes(0), - _num_allocated_nodes(0) { - assert(_free_buffer_list != nullptr, "precondition!"); + _free_segment_list(free_segment_list), + _num_available_slots(0), + _num_allocated_slots(0) { + assert(_free_segment_list != nullptr, "precondition!"); } -template -G1SegmentedArray::~G1SegmentedArray() { +template +G1SegmentedArray::~G1SegmentedArray() { drop_all(); } -template -void G1SegmentedArray::drop_all() { - G1SegmentedArrayBuffer* cur = Atomic::load_acquire(&_first); +template +void G1SegmentedArray::drop_all() { + G1SegmentedArraySegment* cur = Atomic::load_acquire(&_first); if (cur != nullptr) { - assert(_last != nullptr, "If there is at least one element, there must be a last one."); + assert(_last != nullptr, "If there is at least one segment, there must be a last one."); - G1SegmentedArrayBuffer* first = cur; + G1SegmentedArraySegment* first = cur; #ifdef ASSERT // Check list consistency. - G1SegmentedArrayBuffer* last = cur; - uint num_buffers = 0; + G1SegmentedArraySegment* last = cur; + uint num_segments = 0; size_t mem_size = 0; while (cur != nullptr) { mem_size += cur->mem_size(); - num_buffers++; + num_segments++; - G1SegmentedArrayBuffer* next = cur->next(); + G1SegmentedArraySegment* next = cur->next(); last = cur; cur = next; } #endif - assert(num_buffers == _num_buffers, "Buffer count inconsistent %u %u", num_buffers, _num_buffers); + assert(num_segments == _num_segments, "Segment count inconsistent %u %u", num_segments, _num_segments); assert(mem_size == _mem_size, "Memory size inconsistent"); - assert(last == _last, "Inconsistent last element"); + assert(last == _last, "Inconsistent last segment"); - _free_buffer_list->bulk_add(*first, *_last, _num_buffers, _mem_size); + _free_segment_list->bulk_add(*first, *_last, _num_segments, _mem_size); } _first = nullptr; _last = nullptr; - _num_buffers = 0; + _num_segments = 0; _mem_size = 0; - _num_available_nodes = 0; - _num_allocated_nodes = 0; + _num_available_slots = 0; + _num_allocated_slots = 0; } -template -Elem* G1SegmentedArray::allocate() { - assert(elem_size() > 0, "instance size not set."); +template +void* G1SegmentedArray::allocate() { + assert(slot_size() > 0, "instance size not set."); - G1SegmentedArrayBuffer* cur = Atomic::load_acquire(&_first); + G1SegmentedArraySegment* cur = Atomic::load_acquire(&_first); if (cur == nullptr) { - cur = create_new_buffer(cur); + cur = create_new_segment(cur); } while (true) { - Elem* elem = (Elem*)cur->get_new_buffer_elem(); - if (elem != nullptr) { - Atomic::inc(&_num_allocated_nodes, memory_order_relaxed); - guarantee(is_aligned(elem, _alloc_options->alignment()), - "result " PTR_FORMAT " not aligned at %u", p2i(elem), _alloc_options->alignment()); - return elem; + void* slot = cur->get_new_slot(); + if (slot != nullptr) { + Atomic::inc(&_num_allocated_slots, memory_order_relaxed); + guarantee(is_aligned(slot, _alloc_options->slot_alignment()), + "result " PTR_FORMAT " not aligned at %u", p2i(slot), _alloc_options->slot_alignment()); + return slot; } - // The buffer is full. Next round. + // The segment is full. Next round. assert(cur->is_full(), "must be"); - cur = create_new_buffer(cur); + cur = create_new_segment(cur); } } -template -inline uint G1SegmentedArray::num_buffers() const { - return Atomic::load(&_num_buffers); +template +inline uint G1SegmentedArray::num_segments() const { + return Atomic::load(&_num_segments); } #ifdef ASSERT @@ -243,7 +243,7 @@ class LengthClosure { uint _total; public: LengthClosure() : _total(0) {} - void do_buffer(G1SegmentedArrayBuffer* node, uint limit) { + void do_segment(G1SegmentedArraySegment* segment, uint limit) { _total += limit; } uint length() const { @@ -251,24 +251,24 @@ public: } }; -template -uint G1SegmentedArray::calculate_length() const { +template +uint G1SegmentedArray::calculate_length() const { LengthClosure closure; - iterate_nodes(closure); + iterate_segments(closure); return closure.length(); } #endif -template -template -void G1SegmentedArray::iterate_nodes(BufferClosure& closure) const { - G1SegmentedArrayBuffer* cur = Atomic::load_acquire(&_first); +template +template +void G1SegmentedArray::iterate_segments(SegmentClosure& closure) const { + G1SegmentedArraySegment* cur = Atomic::load_acquire(&_first); assert((cur != nullptr) == (_last != nullptr), - "If there is at least one element, there must be a last one"); + "If there is at least one segment, there must be a last one"); while (cur != nullptr) { - closure.do_buffer(cur, cur->length()); + closure.do_segment(cur, cur->length()); cur = cur->next(); } } diff --git a/src/hotspot/share/gc/g1/g1CardSetFreeMemoryTask.cpp b/src/hotspot/share/gc/g1/g1SegmentedArrayFreeMemoryTask.cpp similarity index 70% rename from src/hotspot/share/gc/g1/g1CardSetFreeMemoryTask.cpp rename to src/hotspot/share/gc/g1/g1SegmentedArrayFreeMemoryTask.cpp index 09a22728a89471c0d4145a858bb376eb19e58fff..4752adde74d2d3be284b9c951f64033b0d45dbb4 100644 --- a/src/hotspot/share/gc/g1/g1CardSetFreeMemoryTask.cpp +++ b/src/hotspot/share/gc/g1/g1SegmentedArrayFreeMemoryTask.cpp @@ -23,22 +23,23 @@ */ #include "precompiled.hpp" -#include "gc/g1/g1CardSetFreeMemoryTask.hpp" +#include "ci/ciUtilities.hpp" #include "gc/g1/g1CardSetMemory.inline.hpp" #include "gc/g1/g1CollectedHeap.hpp" +#include "gc/g1/g1SegmentedArrayFreeMemoryTask.hpp" #include "gc/g1/g1_globals.hpp" +#include "gc/g1/heapRegionRemSet.hpp" #include "gc/shared/gcTraceTime.inline.hpp" #include "gc/shared/suspendibleThreadSet.hpp" -#include "heapRegionRemSet.hpp" -#include "ci/ciUtilities.hpp" +#include "runtime/os.hpp" -constexpr const char* G1CardSetFreeMemoryTask::_state_names[]; +constexpr const char* G1SegmentedArrayFreeMemoryTask::_state_names[]; -const char* G1CardSetFreeMemoryTask::get_state_name(State value) const { +const char* G1SegmentedArrayFreeMemoryTask::get_state_name(State value) const { return _state_names[static_cast>(value)]; } -bool G1CardSetFreeMemoryTask::deadline_exceeded(jlong deadline) { +bool G1SegmentedArrayFreeMemoryTask::deadline_exceeded(jlong deadline) { return os::elapsed_counter() >= deadline; } @@ -47,31 +48,31 @@ static size_t keep_size(size_t free, size_t used, double percent) { return MIN2(free, to_keep); } -bool G1CardSetFreeMemoryTask::calculate_return_infos(jlong deadline) { +bool G1SegmentedArrayFreeMemoryTask::calculate_return_infos(jlong deadline) { // Ignore the deadline in this step as it is very short. - G1CardSetMemoryStats used = _total_used; - G1CardSetMemoryStats free = G1CardSetFreePool::free_list_sizes(); + G1SegmentedArrayMemoryStats used = _total_used; + G1SegmentedArrayMemoryStats free = G1SegmentedArrayFreePool::free_list_sizes(); _return_info = new G1ReturnMemoryProcessorSet(used.num_pools()); for (uint i = 0; i < used.num_pools(); i++) { size_t return_to_vm_size = keep_size(free._num_mem_sizes[i], used._num_mem_sizes[i], G1RemSetFreeMemoryKeepExcessRatio); - log_trace(gc, task)("Card Set Free Memory: Type %s: Free: %zu (%zu) " + log_trace(gc, task)("Segmented Array Free Memory: Type %s: Free: %zu (%zu) " "Used: %zu Keep: %zu", G1CardSetConfiguration::mem_object_type_name_str(i), - free._num_mem_sizes[i], free._num_buffers[i], + free._num_mem_sizes[i], free._num_segments[i], used._num_mem_sizes[i], return_to_vm_size); _return_info->append(new G1ReturnMemoryProcessor(return_to_vm_size)); } - G1CardSetFreePool::update_unlink_processors(_return_info); + G1SegmentedArrayFreePool::update_unlink_processors(_return_info); return false; } -bool G1CardSetFreeMemoryTask::return_memory_to_vm(jlong deadline) { +bool G1SegmentedArrayFreeMemoryTask::return_memory_to_vm(jlong deadline) { for (int i = 0; i < _return_info->length(); i++) { G1ReturnMemoryProcessor* info = _return_info->at(i); if (!info->finished_return_to_vm()) { @@ -83,7 +84,7 @@ bool G1CardSetFreeMemoryTask::return_memory_to_vm(jlong deadline) { return false; } -bool G1CardSetFreeMemoryTask::return_memory_to_os(jlong deadline) { +bool G1SegmentedArrayFreeMemoryTask::return_memory_to_os(jlong deadline) { for (int i = 0; i < _return_info->length(); i++) { G1ReturnMemoryProcessor* info = _return_info->at(i); if (!info->finished_return_to_os()) { @@ -95,7 +96,7 @@ bool G1CardSetFreeMemoryTask::return_memory_to_os(jlong deadline) { return false; } -bool G1CardSetFreeMemoryTask::cleanup_return_infos() { +bool G1SegmentedArrayFreeMemoryTask::cleanup_return_infos() { for (int i = 0; i < _return_info->length(); i++) { G1ReturnMemoryProcessor* info = _return_info->at(i); delete info; @@ -106,12 +107,12 @@ bool G1CardSetFreeMemoryTask::cleanup_return_infos() { return false; } -bool G1CardSetFreeMemoryTask::free_excess_card_set_memory() { +bool G1SegmentedArrayFreeMemoryTask::free_excess_segmented_array_memory() { jlong start = os::elapsed_counter(); jlong end = start + (os::elapsed_frequency() / 1000) * G1RemSetFreeMemoryStepDurationMillis; - log_trace(gc, task)("Card Set Free Memory: Step start %1.3f end %1.3f", + log_trace(gc, task)("Segmented Array Free Memory: Step start %1.3f end %1.3f", TimeHelper::counter_to_millis(start), TimeHelper::counter_to_millis(end)); State next_state; @@ -148,7 +149,7 @@ bool G1CardSetFreeMemoryTask::free_excess_card_set_memory() { break; } default: - log_error(gc, task)("Should not try to free excess card set memory in %s state", get_state_name(_state)); + log_error(gc, task)("Should not try to free excess segmented array memory in %s state", get_state_name(_state)); ShouldNotReachHere(); break; } @@ -156,41 +157,41 @@ bool G1CardSetFreeMemoryTask::free_excess_card_set_memory() { set_state(next_state); } while (_state != State::Inactive && !deadline_exceeded(end)); - log_trace(gc, task)("Card Set Free Memory: Step took %1.3fms, done %s", + log_trace(gc, task)("Segmented Array Free Memory: Step took %1.3fms, done %s", TimeHelper::counter_to_millis(os::elapsed_counter() - start), bool_to_str(_state == State::CalculateUsed)); return is_active(); } -void G1CardSetFreeMemoryTask::set_state(State new_state) { - log_trace(gc, task)("Card Set Free Memory: State change from %s to %s", +void G1SegmentedArrayFreeMemoryTask::set_state(State new_state) { + log_trace(gc, task)("Segmented Array Free Memory: State change from %s to %s", get_state_name(_state), get_state_name(new_state)); _state = new_state; } -bool G1CardSetFreeMemoryTask::is_active() const { +bool G1SegmentedArrayFreeMemoryTask::is_active() const { return _state != State::Inactive; } -jlong G1CardSetFreeMemoryTask::reschedule_delay_ms() const { +jlong G1SegmentedArrayFreeMemoryTask::reschedule_delay_ms() const { return G1RemSetFreeMemoryRescheduleDelayMillis; } -G1CardSetFreeMemoryTask::G1CardSetFreeMemoryTask(const char* name) : +G1SegmentedArrayFreeMemoryTask::G1SegmentedArrayFreeMemoryTask(const char* name) : G1ServiceTask(name), _state(State::CalculateUsed), _return_info(nullptr) { } -void G1CardSetFreeMemoryTask::execute() { +void G1SegmentedArrayFreeMemoryTask::execute() { SuspendibleThreadSetJoiner sts; - if (free_excess_card_set_memory()) { + if (free_excess_segmented_array_memory()) { schedule(reschedule_delay_ms()); } } -void G1CardSetFreeMemoryTask::notify_new_stats(G1CardSetMemoryStats* young_gen_stats, - G1CardSetMemoryStats* collection_set_candidate_stats) { +void G1SegmentedArrayFreeMemoryTask::notify_new_stats(G1SegmentedArrayMemoryStats* young_gen_stats, + G1SegmentedArrayMemoryStats* collection_set_candidate_stats) { assert_at_safepoint_on_vm_thread(); _total_used = *young_gen_stats; diff --git a/src/hotspot/share/gc/g1/g1CardSetFreeMemoryTask.hpp b/src/hotspot/share/gc/g1/g1SegmentedArrayFreeMemoryTask.hpp similarity index 72% rename from src/hotspot/share/gc/g1/g1CardSetFreeMemoryTask.hpp rename to src/hotspot/share/gc/g1/g1SegmentedArrayFreeMemoryTask.hpp index 3d617243aa4c3fbd5f0186ace6484e81157d4b4b..a4195cd424c669ef414237868b4a644313de9190 100644 --- a/src/hotspot/share/gc/g1/g1CardSetFreeMemoryTask.hpp +++ b/src/hotspot/share/gc/g1/g1SegmentedArrayFreeMemoryTask.hpp @@ -22,17 +22,18 @@ * */ -#ifndef SHARE_GC_G1_G1CARDSETFREEMEMORYTASK_HPP -#define SHARE_GC_G1_G1CARDSETFREEMEMORYTASK_HPP +#ifndef SHARE_GC_G1_G1SEGMENTEDARRAYFREEMEMORYTASK_HPP +#define SHARE_GC_G1_G1SEGMENTEDARRAYFREEMEMORYTASK_HPP -#include "gc/g1/g1ServiceThread.hpp" #include "gc/g1/g1CardSetMemory.hpp" +#include "gc/g1/g1SegmentedArrayFreePool.hpp" +#include "gc/g1/g1ServiceThread.hpp" #include "gc/g1/heapRegionRemSet.hpp" #include "utilities/growableArray.hpp" #include "utilities/ticks.hpp" -// Task handling deallocation of free card set memory. -class G1CardSetFreeMemoryTask : public G1ServiceTask { +// Task handling deallocation of free segmented array memory. +class G1SegmentedArrayFreeMemoryTask : public G1ServiceTask { enum class State : uint { Inactive, @@ -52,11 +53,11 @@ class G1CardSetFreeMemoryTask : public G1ServiceTask { State _state; - // Current total card set memory usage. - G1CardSetMemoryStats _total_used; + // Current total segmented array memory usage. + G1SegmentedArrayMemoryStats _total_used; - typedef G1CardSetFreePool::G1ReturnMemoryProcessor G1ReturnMemoryProcessor; - typedef G1CardSetFreePool::G1ReturnMemoryProcessorSet G1ReturnMemoryProcessorSet; + typedef G1SegmentedArrayFreePool::G1ReturnMemoryProcessor G1ReturnMemoryProcessor; + typedef G1SegmentedArrayFreePool::G1ReturnMemoryProcessorSet G1ReturnMemoryProcessorSet; G1ReturnMemoryProcessorSet* _return_info; @@ -70,9 +71,9 @@ class G1CardSetFreeMemoryTask : public G1ServiceTask { bool return_memory_to_os(jlong deadline); bool cleanup_return_infos(); - // Free excess card set memory, main method. Returns true if there is more work + // Free excess segmented array memory, main method. Returns true if there is more work // to do. - bool free_excess_card_set_memory(); + bool free_excess_segmented_array_memory(); void set_state(State new_state); // Returns whether we are currently processing a recent request. @@ -82,14 +83,14 @@ class G1CardSetFreeMemoryTask : public G1ServiceTask { jlong reschedule_delay_ms() const; public: - explicit G1CardSetFreeMemoryTask(const char* name); + explicit G1SegmentedArrayFreeMemoryTask(const char* name); void execute() override; // Notify the task of new used remembered set memory statistics for the young // generation and the collection set candidate sets. - void notify_new_stats(G1CardSetMemoryStats* young_gen_stats, - G1CardSetMemoryStats* collection_set_candidate_stats); + void notify_new_stats(G1SegmentedArrayMemoryStats* young_gen_stats, + G1SegmentedArrayMemoryStats* collection_set_candidate_stats); }; -#endif // SHARE_GC_G1_G1CARDSETFREEMEMORYTASK_HPP +#endif // SHARE_GC_G1_G1SEGMENTEDARRAYFREEMEMORYTASK_HPP diff --git a/src/hotspot/share/gc/g1/g1SegmentedArrayFreePool.cpp b/src/hotspot/share/gc/g1/g1SegmentedArrayFreePool.cpp new file mode 100644 index 0000000000000000000000000000000000000000..118638da75bee9887a455926039223e41b7c67a5 --- /dev/null +++ b/src/hotspot/share/gc/g1/g1SegmentedArrayFreePool.cpp @@ -0,0 +1,205 @@ +/* + * 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/g1/g1SegmentedArrayFreePool.hpp" +#include "gc/g1/g1SegmentedArray.inline.hpp" +#include "logging/log.hpp" +#include "memory/allocation.hpp" +#include "runtime/os.hpp" +#include "utilities/formatBuffer.hpp" +#include "utilities/ostream.hpp" + +G1SegmentedArrayMemoryStats::G1SegmentedArrayMemoryStats() { + clear(); +} + +void G1SegmentedArrayMemoryStats::clear() { + for (uint i = 0; i < num_pools(); i++) { + _num_mem_sizes[i] = 0; + _num_segments[i] = 0; + } +} + +template +void G1SegmentedArrayFreePool::update_unlink_processors(G1ReturnMemoryProcessorSet* unlink_processor) { + uint num_free_lists = _freelist_pool.num_free_lists(); + + for (uint i = 0; i < num_free_lists; i++) { + unlink_processor->at(i)->visit_free_list(_freelist_pool.free_list(i)); + } +} + +template +void G1SegmentedArrayFreePool::G1ReturnMemoryProcessor::visit_free_list(G1SegmentedArrayFreeList* source) { + assert(_source == nullptr, "already visited"); + if (_return_to_vm_size > 0) { + _source = source; + } else { + assert(_source == nullptr, "must be"); + } + if (source->mem_size() > _return_to_vm_size) { + _first = source->get_all(_num_unlinked, _unlinked_bytes); + } else { + assert(_first == nullptr, "must be"); + } + // Above we were racing with other threads getting the contents of the free list, + // so while we might have been asked to return something to the OS initially, + // the free list might be empty anyway. In this case just reset internal values + // used for checking whether there is work available. + if (_first == nullptr) { + _source = nullptr; + _return_to_vm_size = 0; + } +} + +template +bool G1SegmentedArrayFreePool::G1ReturnMemoryProcessor::return_to_vm(jlong deadline) { + assert(!finished_return_to_vm(), "already returned everything to the VM"); + assert(_first != nullptr, "must have segment to return"); + + size_t keep_size = 0; + size_t keep_num = 0; + + G1SegmentedArraySegment* cur = _first; + G1SegmentedArraySegment* last = nullptr; + + while (cur != nullptr && _return_to_vm_size > 0) { + size_t cur_size = cur->mem_size(); + _return_to_vm_size -= MIN2(_return_to_vm_size, cur_size); + + keep_size += cur_size; + keep_num++; + + last = cur; + cur = cur->next(); + // To ensure progress, perform the deadline check here. + if (os::elapsed_counter() > deadline) { + break; + } + } + + assert(_first != nullptr, "must be"); + assert(last != nullptr, "must be"); + + last->set_next(nullptr); + + // Wait for any in-progress pops to avoid ABA for them. + GlobalCounter::write_synchronize(); + _source->bulk_add(*_first, *last, keep_num, keep_size); + _first = cur; + + log_trace(gc, task)("Segmented Array Free Memory: Returned to VM %zu segments size %zu", keep_num, keep_size); + + // _return_to_vm_size may be larger than what is available in the list at the + // time we actually get the list. I.e. the list and _return_to_vm_size may be + // inconsistent. + // So also check if we actually already at the end of the list for the exit + // condition. + if (_return_to_vm_size == 0 || _first == nullptr) { + _source = nullptr; + _return_to_vm_size = 0; + } + return _source != nullptr; +} + +template +bool G1SegmentedArrayFreePool::G1ReturnMemoryProcessor::return_to_os(jlong deadline) { + assert(finished_return_to_vm(), "not finished returning to VM"); + assert(!finished_return_to_os(), "already returned everything to the OS"); + + // Now delete the rest. + size_t num_delete = 0; + size_t mem_size_deleted = 0; + + while (_first != nullptr) { + G1SegmentedArraySegment* next = _first->next(); + num_delete++; + mem_size_deleted += _first->mem_size(); + delete _first; + _first = next; + + // To ensure progress, perform the deadline check here. + if (os::elapsed_counter() > deadline) { + break; + } + } + + log_trace(gc, task)("Segmented Array Free Memory: Return to OS %zu segments size %zu", num_delete, mem_size_deleted); + + return _first != nullptr; +} + +template +G1SegmentedArrayFreePool G1SegmentedArrayFreePool::_freelist_pool(G1CardSetConfiguration::num_mem_object_types()); + +template +G1SegmentedArrayFreePool::G1SegmentedArrayFreePool(uint num_free_lists) : + _num_free_lists(num_free_lists) { + + _free_lists = NEW_C_HEAP_ARRAY(G1SegmentedArrayFreeList < flag >, _num_free_lists, mtGC); + for (uint i = 0; i < _num_free_lists; i++) { + new (&_free_lists[i]) G1SegmentedArrayFreeList(); + } +} + +template +G1SegmentedArrayFreePool::~G1SegmentedArrayFreePool() { + for (uint i = 0; i < _num_free_lists; i++) { + _free_lists[i].~G1SegmentedArrayFreeList(); + } + FREE_C_HEAP_ARRAY(mtGC, _free_lists); +} + +template +G1SegmentedArrayMemoryStats G1SegmentedArrayFreePool::memory_sizes() const { + G1SegmentedArrayMemoryStats free_list_stats; + assert(free_list_stats.num_pools() == num_free_lists(), "must be"); + for (uint i = 0; i < num_free_lists(); i++) { + free_list_stats._num_mem_sizes[i] = _free_lists[i].mem_size(); + free_list_stats._num_segments[i] = _free_lists[i].num_segments(); + } + return free_list_stats; +} + +template +size_t G1SegmentedArrayFreePool::mem_size() const { + size_t result = 0; + for (uint i = 0; i < _num_free_lists; i++) { + result += _free_lists[i].mem_size(); + } + return result; +} + +template +void G1SegmentedArrayFreePool::print_on(outputStream* out) { + out->print_cr(" Free Pool: size %zu", free_list_pool()->mem_size()); + for (uint i = 0; i < _num_free_lists; i++) { + FormatBuffer<> fmt(" %s", G1CardSetConfiguration::mem_object_type_name_str(i)); + _free_lists[i].print_on(out, fmt); + } +} + +template class G1SegmentedArrayFreePool; diff --git a/src/hotspot/share/gc/g1/g1SegmentedArrayFreePool.hpp b/src/hotspot/share/gc/g1/g1SegmentedArrayFreePool.hpp new file mode 100644 index 0000000000000000000000000000000000000000..ba1b952875c5f3c6470c8c338570f29ffc1262d1 --- /dev/null +++ b/src/hotspot/share/gc/g1/g1SegmentedArrayFreePool.hpp @@ -0,0 +1,128 @@ +/* + * 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_G1_G1SEGMENTEDARRAYFREEPOOL_HPP +#define SHARE_GC_G1_G1SEGMENTEDARRAYFREEPOOL_HPP + +#include "gc/g1/g1CardSet.hpp" +#include "gc/g1/g1SegmentedArray.hpp" +#include "utilities/growableArray.hpp" + +// Statistics for a segmented array. Contains the number of segments and memory +// used for each. Note that statistics are typically not taken atomically so there +// can be inconsistencies. The user must be prepared for them. +class G1SegmentedArrayMemoryStats { +public: + + size_t _num_mem_sizes[G1CardSetConfiguration::num_mem_object_types()]; + size_t _num_segments[G1CardSetConfiguration::num_mem_object_types()]; + + // Returns all-zero statistics. + G1SegmentedArrayMemoryStats(); + + void add(G1SegmentedArrayMemoryStats const other) { + STATIC_ASSERT(ARRAY_SIZE(_num_segments) == ARRAY_SIZE(_num_mem_sizes)); + for (uint i = 0; i < ARRAY_SIZE(_num_mem_sizes); i++) { + _num_mem_sizes[i] += other._num_mem_sizes[i]; + _num_segments[i] += other._num_segments[i]; + } + } + + void clear(); + + uint num_pools() const { return G1CardSetConfiguration::num_mem_object_types(); } +}; + +// A set of free lists holding freed segments for use by G1SegmentedArray, +// e.g. G1CardSetAllocators::SegmentedArray +template +class G1SegmentedArrayFreePool { + // The global free pool. + static G1SegmentedArrayFreePool _freelist_pool; + + const uint _num_free_lists; + G1SegmentedArrayFreeList* _free_lists; + +public: + static G1SegmentedArrayFreePool* free_list_pool() { return &_freelist_pool; } + static G1SegmentedArrayMemoryStats free_list_sizes() { return _freelist_pool.memory_sizes(); } + + class G1ReturnMemoryProcessor; + typedef GrowableArrayCHeap G1ReturnMemoryProcessorSet; + + static void update_unlink_processors(G1ReturnMemoryProcessorSet* unlink_processors); + + explicit G1SegmentedArrayFreePool(uint num_free_lists); + ~G1SegmentedArrayFreePool(); + + G1SegmentedArrayFreeList* free_list(uint i) { + assert(i < _num_free_lists, "must be"); + return &_free_lists[i]; + } + + uint num_free_lists() const { return _num_free_lists; } + + G1SegmentedArrayMemoryStats memory_sizes() const; + size_t mem_size() const; + + void print_on(outputStream* out); +}; + +// Data structure containing current in-progress state for returning memory to the +// operating system for a single G1SegmentedArrayFreeList. +template +class G1SegmentedArrayFreePool::G1ReturnMemoryProcessor : public CHeapObj { + G1SegmentedArrayFreeList* _source; + size_t _return_to_vm_size; + + G1SegmentedArraySegment* _first; + size_t _unlinked_bytes; + size_t _num_unlinked; + +public: + explicit G1ReturnMemoryProcessor(size_t return_to_vm) : + _source(nullptr), _return_to_vm_size(return_to_vm), _first(nullptr), _unlinked_bytes(0), _num_unlinked(0) { + } + + // Updates the instance members about the given free list for + // the purpose of giving back memory. Only necessary members are updated, + // e.g. if there is nothing to return to the VM, do not set the source list. + void visit_free_list(G1SegmentedArrayFreeList* source); + + bool finished_return_to_vm() const { return _return_to_vm_size == 0; } + bool finished_return_to_os() const { return _first == nullptr; } + + // Returns memory to the VM until the given deadline expires. Returns true if + // there is no more work. Guarantees forward progress, i.e. at least one segment + // has been processed after returning. + // return_to_vm() re-adds segments to the respective free list. + bool return_to_vm(jlong deadline); + // Returns memory to the VM until the given deadline expires. Returns true if + // there is no more work. Guarantees forward progress, i.e. at least one segment + // has been processed after returning. + // return_to_os() gives back segments to the OS. + bool return_to_os(jlong deadline); +}; + +#endif //SHARE_GC_G1_G1SEGMENTEDARRAYFREEPOOL_HPP diff --git a/src/hotspot/share/gc/g1/g1SharedClosures.hpp b/src/hotspot/share/gc/g1/g1SharedClosures.hpp index 55b9a1e62c53a543b0719774dd2c1c5a40b4a731..4808f0ae84f6c128813ef494377cd877581819a7 100644 --- a/src/hotspot/share/gc/g1/g1SharedClosures.hpp +++ b/src/hotspot/share/gc/g1/g1SharedClosures.hpp @@ -37,7 +37,7 @@ public: G1ParCopyClosure _oops_in_cld; // We do not need (and actually should not) collect oops from nmethods into the // optional collection set as we already automatically collect the corresponding - // nmethods in the region's strong code roots set. So set G1BarrierNoOptRoots in + // nmethods in the region's code roots set. So set G1BarrierNoOptRoots in // this closure. // If these were present there would be opportunity for multiple threads to try // to change this oop* at the same time. Since embedded oops are not necessarily diff --git a/src/hotspot/share/gc/g1/g1VMOperations.cpp b/src/hotspot/share/gc/g1/g1VMOperations.cpp index 75d209b94a5717f72c56f27703ef4715f5aecde6..a4633f9c2b9f2b05dae78fd7301380dd884ceb57 100644 --- a/src/hotspot/share/gc/g1/g1VMOperations.cpp +++ b/src/hotspot/share/gc/g1/g1VMOperations.cpp @@ -52,7 +52,7 @@ void VM_G1CollectFull::doit() { GCCauseSetter x(g1h, _gc_cause); _gc_succeeded = g1h->do_full_collection(true /* explicit_gc */, false /* clear_all_soft_refs */, - false /* do_maximum_compaction */); + false /* do_maximal_compaction */); } VM_G1TryInitiateConcMark::VM_G1TryInitiateConcMark(uint gc_count_before, @@ -170,7 +170,7 @@ void VM_G1CollectForAllocation::doit() { } } -void VM_G1Concurrent::doit() { +void VM_G1PauseConcurrent::doit() { GCIdMark gc_id_mark(_gc_id); GCTraceCPUTime tcpu; G1CollectedHeap* g1h = G1CollectedHeap::heap(); @@ -184,17 +184,28 @@ void VM_G1Concurrent::doit() { TraceCollectorStats tcs(g1h->monitoring_support()->conc_collection_counters()); SvcGCMarker sgcm(SvcGCMarker::CONCURRENT); IsGCActiveMark x; - _cl->do_void(); + + work(); } -bool VM_G1Concurrent::doit_prologue() { +bool VM_G1PauseConcurrent::doit_prologue() { Heap_lock->lock(); return true; } -void VM_G1Concurrent::doit_epilogue() { +void VM_G1PauseConcurrent::doit_epilogue() { if (Universe::has_reference_pending_list()) { Heap_lock->notify_all(); } Heap_lock->unlock(); } + +void VM_G1PauseRemark::work() { + G1CollectedHeap* g1h = G1CollectedHeap::heap(); + g1h->concurrent_mark()->remark(); +} + +void VM_G1PauseCleanup::work() { + G1CollectedHeap* g1h = G1CollectedHeap::heap(); + g1h->concurrent_mark()->cleanup(); +} diff --git a/src/hotspot/share/gc/g1/g1VMOperations.hpp b/src/hotspot/share/gc/g1/g1VMOperations.hpp index b5f36a51b789c5661d946601c40f29badcc95b71..72f450ad3bc2de66c86c356b8a05ddbfbdc3a6cc 100644 --- a/src/hotspot/share/gc/g1/g1VMOperations.hpp +++ b/src/hotspot/share/gc/g1/g1VMOperations.hpp @@ -87,18 +87,33 @@ private: }; // Concurrent G1 stop-the-world operations such as remark and cleanup. -class VM_G1Concurrent : public VM_Operation { - VoidClosure* _cl; - const char* _message; +class VM_G1PauseConcurrent : public VM_Operation { uint _gc_id; + const char* _message; + +protected: + VM_G1PauseConcurrent(const char* message) : + _gc_id(GCId::current()), _message(message) { } + virtual void work() = 0; public: - VM_G1Concurrent(VoidClosure* cl, const char* message) : - _cl(cl), _message(message), _gc_id(GCId::current()) { } - virtual VMOp_Type type() const { return VMOp_G1Concurrent; } - virtual void doit(); - virtual bool doit_prologue(); - virtual void doit_epilogue(); + bool doit_prologue() override; + void doit_epilogue() override; + void doit() override; +}; + +class VM_G1PauseRemark : public VM_G1PauseConcurrent { +public: + VM_G1PauseRemark() : VM_G1PauseConcurrent("Pause Remark") { } + VMOp_Type type() const override { return VMOp_G1PauseRemark; } + void work() override; +}; + +class VM_G1PauseCleanup : public VM_G1PauseConcurrent { +public: + VM_G1PauseCleanup() : VM_G1PauseConcurrent("Pause Cleanup") { } + VMOp_Type type() const override { return VMOp_G1PauseCleanup; } + void work() override; }; #endif // SHARE_GC_G1_G1VMOPERATIONS_HPP diff --git a/src/hotspot/share/gc/g1/g1YoungCollector.cpp b/src/hotspot/share/gc/g1/g1YoungCollector.cpp index c900c1ce2488ca7cad6878e108ab9c23a40eb6c5..d5e1774a8bd208596fcfb557c995c0cd31a4ac44 100644 --- a/src/hotspot/share/gc/g1/g1YoungCollector.cpp +++ b/src/hotspot/share/gc/g1/g1YoungCollector.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -29,7 +29,7 @@ #include "compiler/oopMap.hpp" #include "gc/g1/g1Allocator.hpp" #include "gc/g1/g1CardSetMemory.hpp" -#include "gc/g1/g1CollectedHeap.hpp" +#include "gc/g1/g1CollectedHeap.inline.hpp" #include "gc/g1/g1CollectorState.hpp" #include "gc/g1/g1ConcurrentMark.hpp" #include "gc/g1/g1GCPhaseTimes.hpp" @@ -59,47 +59,6 @@ #include "memory/resourceArea.hpp" #include "utilities/ticks.hpp" -#if TASKQUEUE_STATS -uint G1YoungCollector::num_task_queues() const { - return task_queues()->size(); -} - -void G1YoungCollector::print_taskqueue_stats_hdr(outputStream* const st) { - st->print_raw_cr("GC Task Stats"); - st->print_raw("thr "); TaskQueueStats::print_header(1, st); st->cr(); - st->print_raw("--- "); TaskQueueStats::print_header(2, st); st->cr(); -} - -void G1YoungCollector::print_taskqueue_stats() const { - if (!log_is_enabled(Trace, gc, task, stats)) { - return; - } - Log(gc, task, stats) log; - ResourceMark rm; - LogStream ls(log.trace()); - outputStream* st = &ls; - - print_taskqueue_stats_hdr(st); - - TaskQueueStats totals; - const uint n = num_task_queues(); - for (uint i = 0; i < n; ++i) { - st->print("%3u ", i); _g1h->task_queue(i)->stats.print(st); st->cr(); - totals += _g1h->task_queue(i)->stats; - } - st->print_raw("tot "); totals.print(st); st->cr(); - - DEBUG_ONLY(totals.verify()); -} - -void G1YoungCollector::reset_taskqueue_stats() { - const uint n = num_task_queues(); - for (uint i = 0; i < n; ++i) { - _g1h->task_queue(i)->stats.reset(); - } -} -#endif // TASKQUEUE_STATS - // GCTraceTime wrapper that constructs the message according to GC pause type and // GC cause. // The code relies on the fact that GCTraceTimeWrapper stores the string passed @@ -330,7 +289,7 @@ class G1PrepareEvacuationTask : public WorkerTask { uint _worker_humongous_total; uint _worker_humongous_candidates; - G1CardSetMemoryStats _card_set_stats; + G1SegmentedArrayMemoryStats _card_set_stats; void sample_card_set_size(HeapRegion* hr) { // Sample card set sizes for young gen and humongous before GC: this makes @@ -436,7 +395,7 @@ class G1PrepareEvacuationTask : public WorkerTask { cast_to_oop(hr->bottom())->size() * HeapWordSize, p2i(hr->bottom()), hr->rem_set()->occupied(), - hr->rem_set()->strong_code_roots_list_length(), + hr->rem_set()->code_roots_list_length(), _g1h->concurrent_mark()->next_mark_bitmap()->is_marked(hr->bottom()), _g1h->is_humongous_reclaim_candidate(index), cast_to_oop(hr->bottom())->is_typeArray() @@ -446,7 +405,7 @@ class G1PrepareEvacuationTask : public WorkerTask { return false; } - G1CardSetMemoryStats card_set_stats() const { + G1SegmentedArrayMemoryStats card_set_stats() const { return _card_set_stats; } }; @@ -456,7 +415,7 @@ class G1PrepareEvacuationTask : public WorkerTask { volatile uint _humongous_total; volatile uint _humongous_candidates; - G1CardSetMemoryStats _all_card_set_stats; + G1SegmentedArrayMemoryStats _all_card_set_stats; public: G1PrepareEvacuationTask(G1CollectedHeap* g1h) : @@ -490,7 +449,7 @@ public: return _humongous_total; } - const G1CardSetMemoryStats all_card_set_stats() const { + const G1SegmentedArrayMemoryStats all_card_set_stats() const { return _all_card_set_stats; } }; @@ -856,7 +815,7 @@ public: return; } if (region_attr.is_in_cset()) { - assert( obj->is_forwarded(), "invariant" ); + assert(obj->is_forwarded(), "invariant" ); *p = obj->forwardee(); } else { assert(!obj->is_forwarded(), "invariant" ); @@ -987,12 +946,6 @@ void G1YoungCollector::process_discovered_references(G1ParScanThreadStateSet* pe phase_times()->record_ref_proc_time((Ticks::now() - start).seconds() * MILLIUNITS); } -bool G1STWIsAliveClosure::do_object_b(oop p) { - // An object is reachable if it is outside the collection set, - // or is inside and copied. - return !_g1h->is_in_cset(p) || p->is_forwarded(); -} - void G1YoungCollector::post_evacuate_cleanup_1(G1ParScanThreadStateSet* per_thread_states) { Ticks start = Ticks::now(); { @@ -1153,6 +1106,5 @@ void G1YoungCollector::collect() { policy()->record_young_collection_end(_concurrent_operation_is_full_mark, evacuation_failed()); } - TASKQUEUE_STATS_ONLY(print_taskqueue_stats()); - TASKQUEUE_STATS_ONLY(reset_taskqueue_stats()); + TASKQUEUE_STATS_ONLY(_g1h->task_queues()->print_and_reset_taskqueue_stats("Oop Queue");) } diff --git a/src/hotspot/share/gc/g1/g1YoungCollector.hpp b/src/hotspot/share/gc/g1/g1YoungCollector.hpp index 4bc1eaf19421c90612613ba96a167ada2f2a6134..c5ad5c452358ad2dec096d1d3bd3c79340647a40 100644 --- a/src/hotspot/share/gc/g1/g1YoungCollector.hpp +++ b/src/hotspot/share/gc/g1/g1YoungCollector.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -33,7 +33,6 @@ class WorkerTask; class G1Allocator; class G1BatchedTask; -class G1CardSetMemoryStats; class G1CollectedHeap; class G1CollectionSet; class G1CollectorState; @@ -49,6 +48,7 @@ class G1ParScanThreadStateSet; class G1Policy; class G1RedirtyCardsQueueSet; class G1RemSet; +class G1SegmentedArrayMemoryStats; class G1SurvivorRegions; class G1YoungGCEvacFailureInjector; class STWGCTimer; @@ -134,13 +134,6 @@ class G1YoungCollector { // True iff an evacuation has failed in the most-recent collection. bool evacuation_failed() const; -#if TASKQUEUE_STATS - uint num_task_queues() const; - static void print_taskqueue_stats_hdr(outputStream* const st); - void print_taskqueue_stats() const; - void reset_taskqueue_stats(); -#endif // TASKQUEUE_STATS - public: G1YoungCollector(GCCause::Cause gc_cause, double target_pause_time_ms); diff --git a/src/hotspot/share/gc/g1/g1YoungGCEvacFailureInjector.cpp b/src/hotspot/share/gc/g1/g1YoungGCEvacFailureInjector.cpp index 67b44263004d691654af6a62def2a390a4bfc8ac..c534d6f29c8e85cf10bdf6656a0945d36ea10cfb 100644 --- a/src/hotspot/share/gc/g1/g1YoungGCEvacFailureInjector.cpp +++ b/src/hotspot/share/gc/g1/g1YoungGCEvacFailureInjector.cpp @@ -30,6 +30,33 @@ #if EVAC_FAILURE_INJECTOR +class SelectEvacFailureRegionClosure : public HeapRegionClosure { + CHeapBitMap& _evac_failure_regions; + size_t _evac_failure_regions_num; + +public: + SelectEvacFailureRegionClosure(CHeapBitMap& evac_failure_regions, size_t cset_length) : + _evac_failure_regions(evac_failure_regions), + _evac_failure_regions_num(cset_length * G1EvacuationFailureALotCSetPercent / 100) { } + + bool do_heap_region(HeapRegion* r) override { + assert(r->in_collection_set(), "must be"); + if (_evac_failure_regions_num > 0) { + _evac_failure_regions.set_bit(r->hrm_index()); + --_evac_failure_regions_num; + return false; + } + return true; + } +}; + +void G1YoungGCEvacFailureInjector::select_evac_failure_regions() { + G1CollectedHeap* g1h = G1CollectedHeap::heap(); + _evac_failure_regions.reinitialize(g1h->max_reserved_regions()); + SelectEvacFailureRegionClosure closure(_evac_failure_regions, g1h->collection_set()->cur_length()); + g1h->collection_set_iterate_all(&closure); +} + bool G1YoungGCEvacFailureInjector::arm_if_needed_for_gc_type(bool for_young_gc, bool during_concurrent_start, bool mark_or_rebuild_in_progress) { @@ -68,6 +95,10 @@ void G1YoungGCEvacFailureInjector::arm_if_needed() { arm_if_needed_for_gc_type(in_young_only_phase, in_concurrent_start_gc, mark_or_rebuild_in_progress); + + if (_inject_evacuation_failure_for_current_gc) { + select_evac_failure_regions(); + } } } diff --git a/src/hotspot/share/gc/g1/g1YoungGCEvacFailureInjector.hpp b/src/hotspot/share/gc/g1/g1YoungGCEvacFailureInjector.hpp index eb0d4598c14fe49e3b401abcd048eab44bb11de4..aff61c4035d3e766f485718fe6bf51578e93fa86 100644 --- a/src/hotspot/share/gc/g1/g1YoungGCEvacFailureInjector.hpp +++ b/src/hotspot/share/gc/g1/g1YoungGCEvacFailureInjector.hpp @@ -56,11 +56,17 @@ class G1YoungGCEvacFailureInjector { // Used to determine whether evacuation failure injection should be in effect // for the current GC. size_t _last_collection_with_evacuation_failure; + + // Records the regions that will fail evacuation. + CHeapBitMap _evac_failure_regions; #endif bool arm_if_needed_for_gc_type(bool for_young_gc, bool during_concurrent_start, bool mark_or_rebuild_in_progress) EVAC_FAILURE_INJECTOR_RETURN_( return false; ); + + // Selects the regions that will fail evacuation by G1EvacuationFailureALotCSetPercent. + void select_evac_failure_regions() EVAC_FAILURE_INJECTOR_RETURN; public: // Arm the evacuation failure injector if needed for the current @@ -69,7 +75,7 @@ public: // Return true if it's time to cause an evacuation failure; the caller // provides the (preferably thread-local) counter to minimize performance impact. - bool evacuation_should_fail(size_t& counter) EVAC_FAILURE_INJECTOR_RETURN_( return false; ); + bool evacuation_should_fail(size_t& counter, uint region_idx) EVAC_FAILURE_INJECTOR_RETURN_( return false; ); // Reset the evacuation failure injection counters. Should be called at // the end of an evacuation pause in which an evacuation failure occurred. diff --git a/src/hotspot/share/gc/g1/g1YoungGCEvacFailureInjector.inline.hpp b/src/hotspot/share/gc/g1/g1YoungGCEvacFailureInjector.inline.hpp index e259fc6137650408729634b8b373ebeca9a80a60..90d64056b83e25f9e3549676765797a6eb144a5b 100644 --- a/src/hotspot/share/gc/g1/g1YoungGCEvacFailureInjector.inline.hpp +++ b/src/hotspot/share/gc/g1/g1YoungGCEvacFailureInjector.inline.hpp @@ -32,10 +32,13 @@ #if EVAC_FAILURE_INJECTOR -inline bool G1YoungGCEvacFailureInjector::evacuation_should_fail(size_t& counter) { +inline bool G1YoungGCEvacFailureInjector::evacuation_should_fail(size_t& counter, uint region_idx) { if (!_inject_evacuation_failure_for_current_gc) { return false; } + if (!_evac_failure_regions.at(region_idx)) { + return false; + } if (++counter < G1EvacuationFailureALotCount) { return false; } diff --git a/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp b/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp index 2df06a5e3246f5fe940f11b4f0058d8d931287f9..669b3a8ae761ec207724f24fd1f2cb81cb442792 100644 --- a/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp +++ b/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp @@ -82,7 +82,7 @@ public: class G1SampleCollectionSetCandidatesClosure : public HeapRegionClosure { public: - G1CardSetMemoryStats _total; + G1SegmentedArrayMemoryStats _total; bool do_heap_region(HeapRegion* r) override { _total.add(r->rem_set()->card_set_memory_stats()); @@ -103,7 +103,7 @@ class G1PostEvacuateCollectionSetCleanupTask1::RemoveSelfForwardPtrsTask : publi public: RemoveSelfForwardPtrsTask(G1EvacFailureRegions* evac_failure_regions) : - G1AbstractSubTask(G1GCPhaseTimes::RemoveSelfForwardingPtr), + G1AbstractSubTask(G1GCPhaseTimes::RestoreRetainedRegions), _task(evac_failure_regions), _evac_failure_regions(evac_failure_regions) { } diff --git a/src/hotspot/share/gc/g1/g1_globals.hpp b/src/hotspot/share/gc/g1/g1_globals.hpp index ed71b6d45b2802d8ef89105de103cb3d474cc812..40334fc5f1054be48ea70e6f51f588841fc97d1a 100644 --- a/src/hotspot/share/gc/g1/g1_globals.hpp +++ b/src/hotspot/share/gc/g1/g1_globals.hpp @@ -73,7 +73,13 @@ \ product(bool, G1EvacuationFailureALotDuringMixedGC, true, \ "Force use of evacuation failure handling during mixed " \ - "evacuation pauses") + "evacuation pauses") \ + \ + product(uint, G1EvacuationFailureALotCSetPercent, 100, \ + "The percentage of regions in the collection set starting " \ + "from the beginning where the forced evacuation failure " \ + "injection will be applied.") \ + range(1, 100) #else #define GC_G1_EVACUATION_FAILURE_FLAGS(develop, \ develop_pd, \ diff --git a/src/hotspot/share/gc/g1/heapRegion.cpp b/src/hotspot/share/gc/g1/heapRegion.cpp index 78ca4ad8bf97fcdea9536075b6bdb198539ba49f..044e8f527cf811d0d1f54fbc2995698c76051c39 100644 --- a/src/hotspot/share/gc/g1/heapRegion.cpp +++ b/src/hotspot/share/gc/g1/heapRegion.cpp @@ -91,7 +91,7 @@ void HeapRegion::setup_heap_region_size(size_t max_heap_size) { GrainWords = GrainBytes >> LogHeapWordSize; guarantee(CardsPerRegion == 0, "we should only set it once"); - CardsPerRegion = GrainBytes >> G1CardTable::card_shift; + CardsPerRegion = GrainBytes >> G1CardTable::card_shift(); LogCardsPerRegion = log2i(CardsPerRegion); @@ -107,10 +107,6 @@ void HeapRegion::handle_evacuation_failure() { _next_marked_bytes = 0; } -void HeapRegion::process_and_drop_evac_failure_objs(ObjectClosure* closure) { - _evac_failure_objs.process_and_drop(closure); -} - void HeapRegion::unlink_from_list() { set_next(NULL); set_prev(NULL); @@ -214,8 +210,6 @@ void HeapRegion::set_continues_humongous(HeapRegion* first_hr) { report_region_type_change(G1HeapRegionTraceType::ContinuesHumongous); _type.set_continues_humongous(); _humongous_start_region = first_hr; - - _bot_part.set_object_can_span(true); } void HeapRegion::clear_humongous() { @@ -223,8 +217,6 @@ void HeapRegion::clear_humongous() { assert(capacity() == HeapRegion::GrainBytes, "pre-condition"); _humongous_start_region = NULL; - - _bot_part.set_object_can_span(false); } HeapRegion::HeapRegion(uint hrm_index, @@ -250,8 +242,7 @@ HeapRegion::HeapRegion(uint hrm_index, _prev_marked_bytes(0), _next_marked_bytes(0), _young_index_in_cset(-1), _surv_rate_group(NULL), _age_index(G1SurvRateGroup::InvalidAgeIndex), _gc_efficiency(-1.0), - _node_index(G1NUMA::UnknownNodeIndex), - _evac_failure_objs(hrm_index, _bottom) + _node_index(G1NUMA::UnknownNodeIndex) { assert(Universe::on_page_boundary(mr.start()) && Universe::on_page_boundary(mr.end()), "invalid space boundaries"); @@ -269,7 +260,6 @@ void HeapRegion::initialize(bool clear_space, bool mangle_space) { set_top(bottom()); set_compaction_top(bottom()); - reset_bot(); hr_clear(false /*clear_space*/); } @@ -313,28 +303,28 @@ void HeapRegion::note_self_forwarding_removal_end(size_t marked_bytes) { // Code roots support -void HeapRegion::add_strong_code_root(nmethod* nm) { +void HeapRegion::add_code_root(nmethod* nm) { HeapRegionRemSet* hrrs = rem_set(); - hrrs->add_strong_code_root(nm); + hrrs->add_code_root(nm); } -void HeapRegion::add_strong_code_root_locked(nmethod* nm) { +void HeapRegion::add_code_root_locked(nmethod* nm) { assert_locked_or_safepoint(CodeCache_lock); HeapRegionRemSet* hrrs = rem_set(); - hrrs->add_strong_code_root_locked(nm); + hrrs->add_code_root_locked(nm); } -void HeapRegion::remove_strong_code_root(nmethod* nm) { +void HeapRegion::remove_code_root(nmethod* nm) { HeapRegionRemSet* hrrs = rem_set(); - hrrs->remove_strong_code_root(nm); + hrrs->remove_code_root(nm); } -void HeapRegion::strong_code_roots_do(CodeBlobClosure* blk) const { +void HeapRegion::code_roots_do(CodeBlobClosure* blk) const { HeapRegionRemSet* hrrs = rem_set(); - hrrs->strong_code_roots_do(blk); + hrrs->code_roots_do(blk); } -class VerifyStrongCodeRootOopClosure: public OopClosure { +class VerifyCodeRootOopClosure: public OopClosure { const HeapRegion* _hr; bool _failures; bool _has_oops_in_region; @@ -362,7 +352,7 @@ class VerifyStrongCodeRootOopClosure: public OopClosure { } public: - VerifyStrongCodeRootOopClosure(const HeapRegion* hr): + VerifyCodeRootOopClosure(const HeapRegion* hr): _hr(hr), _failures(false), _has_oops_in_region(false) {} void do_oop(narrowOop* p) { do_oop_work(p); } @@ -372,11 +362,11 @@ public: bool has_oops_in_region() { return _has_oops_in_region; } }; -class VerifyStrongCodeRootCodeBlobClosure: public CodeBlobClosure { +class VerifyCodeRootCodeBlobClosure: public CodeBlobClosure { const HeapRegion* _hr; bool _failures; public: - VerifyStrongCodeRootCodeBlobClosure(const HeapRegion* hr) : + VerifyCodeRootCodeBlobClosure(const HeapRegion* hr) : _hr(hr), _failures(false) {} void do_code_blob(CodeBlob* cb) { @@ -384,14 +374,14 @@ public: if (nm != NULL) { // Verify that the nemthod is live if (!nm->is_alive()) { - log_error(gc, verify)("region [" PTR_FORMAT "," PTR_FORMAT "] has dead nmethod " PTR_FORMAT " in its strong code roots", + log_error(gc, verify)("region [" PTR_FORMAT "," PTR_FORMAT "] has dead nmethod " PTR_FORMAT " in its code roots", p2i(_hr->bottom()), p2i(_hr->end()), p2i(nm)); _failures = true; } else { - VerifyStrongCodeRootOopClosure oop_cl(_hr); + VerifyCodeRootOopClosure oop_cl(_hr); nm->oops_do(&oop_cl); if (!oop_cl.has_oops_in_region()) { - log_error(gc, verify)("region [" PTR_FORMAT "," PTR_FORMAT "] has nmethod " PTR_FORMAT " in its strong code roots with no pointers into region", + log_error(gc, verify)("region [" PTR_FORMAT "," PTR_FORMAT "] has nmethod " PTR_FORMAT " in its code roots with no pointers into region", p2i(_hr->bottom()), p2i(_hr->end()), p2i(nm)); _failures = true; } else if (oop_cl.failures()) { @@ -406,47 +396,47 @@ public: bool failures() { return _failures; } }; -void HeapRegion::verify_strong_code_roots(VerifyOption vo, bool* failures) const { +void HeapRegion::verify_code_roots(VerifyOption vo, bool* failures) const { if (!G1VerifyHeapRegionCodeRoots) { // We're not verifying code roots. return; } if (vo == VerifyOption_G1UseFullMarking) { // Marking verification during a full GC is performed after class - // unloading, code cache unloading, etc so the strong code roots + // unloading, code cache unloading, etc so the code roots // attached to each heap region are in an inconsistent state. They won't - // be consistent until the strong code roots are rebuilt after the - // actual GC. Skip verifying the strong code roots in this particular + // be consistent until the code roots are rebuilt after the + // actual GC. Skip verifying the code roots in this particular // time. assert(VerifyDuringGC, "only way to get here"); return; } HeapRegionRemSet* hrrs = rem_set(); - size_t strong_code_roots_length = hrrs->strong_code_roots_list_length(); + size_t code_roots_length = hrrs->code_roots_list_length(); // if this region is empty then there should be no entries - // on its strong code root list + // on its code root list if (is_empty()) { - if (strong_code_roots_length > 0) { + if (code_roots_length > 0) { log_error(gc, verify)("region " HR_FORMAT " is empty but has " SIZE_FORMAT " code root entries", - HR_FORMAT_PARAMS(this), strong_code_roots_length); + HR_FORMAT_PARAMS(this), code_roots_length); *failures = true; } return; } if (is_continues_humongous()) { - if (strong_code_roots_length > 0) { + if (code_roots_length > 0) { log_error(gc, verify)("region " HR_FORMAT " is a continuation of a humongous region but has " SIZE_FORMAT " code root entries", - HR_FORMAT_PARAMS(this), strong_code_roots_length); + HR_FORMAT_PARAMS(this), code_roots_length); *failures = true; } return; } - VerifyStrongCodeRootCodeBlobClosure cb_cl(this); - strong_code_roots_do(&cb_cl); + VerifyCodeRootCodeBlobClosure cb_cl(this); + code_roots_do(&cb_cl); if (cb_cl.failures()) { *failures = true; @@ -489,7 +479,6 @@ protected: VerifyOption _vo; public: // _vo == UsePrevMarking -> use "prev" marking information, - // _vo == UseNextMarking -> use "next" marking information, // _vo == UseFullMarking -> use "next" marking bitmap but no TAMS. G1VerificationClosure(G1CollectedHeap* g1h, VerifyOption vo) : _g1h(g1h), _ct(g1h->card_table()), @@ -659,6 +648,8 @@ void HeapRegion::verify(VerifyOption vo, VerifyLiveClosure vl_cl(g1h, vo); VerifyRemSetClosure vr_cl(g1h, vo); bool is_region_humongous = is_humongous(); + // We cast p to an oop, so region-bottom must be an obj-start. + assert(!is_region_humongous || is_starts_humongous(), "invariant"); size_t object_num = 0; while (p < top()) { oop obj = cast_to_oop(p); @@ -737,12 +728,7 @@ void HeapRegion::verify(VerifyOption vo, return; } - verify_strong_code_roots(vo, failures); -} - -void HeapRegion::verify() const { - bool dummy = false; - verify(VerifyOption_G1UsePrevMarking, /* failures */ &dummy); + verify_code_roots(vo, failures); } void HeapRegion::verify_rem_set(VerifyOption vo, bool* failures) const { @@ -792,7 +778,6 @@ void HeapRegion::clear(bool mangle_space) { if (ZapUnusedHeapArea && mangle_space) { mangle_unused_area(); } - reset_bot(); } #ifndef PRODUCT @@ -801,12 +786,8 @@ void HeapRegion::mangle_unused_area() { } #endif -void HeapRegion::initialize_bot_threshold() { - _bot_part.initialize_threshold(); -} - -void HeapRegion::alloc_block_in_bot(HeapWord* start, HeapWord* end) { - _bot_part.alloc_block(start, end); +void HeapRegion::update_bot_for_block(HeapWord* start, HeapWord* end) { + _bot_part.update_for_block(start, end); } void HeapRegion::object_iterate(ObjectClosure* blk) { @@ -822,7 +803,7 @@ void HeapRegion::object_iterate(ObjectClosure* blk) { void HeapRegion::fill_with_dummy_object(HeapWord* address, size_t word_size, bool zap) { // Keep the BOT in sync for old generation regions. if (is_old()) { - update_bot_at(address, word_size); + update_bot_for_obj(address, word_size); } // Fill in the object. CollectedHeap::fill_with_object(address, word_size, zap); diff --git a/src/hotspot/share/gc/g1/heapRegion.hpp b/src/hotspot/share/gc/g1/heapRegion.hpp index 2317861388a7f9e95333a38e4ebd2c865df88386..2e9851963ac21b689eec6260efcd1848708ce345 100644 --- a/src/hotspot/share/gc/g1/heapRegion.hpp +++ b/src/hotspot/share/gc/g1/heapRegion.hpp @@ -26,7 +26,6 @@ #define SHARE_GC_G1_HEAPREGION_HPP #include "gc/g1/g1BlockOffsetTable.hpp" -#include "gc/g1/g1EvacFailureObjectsSet.hpp" #include "gc/g1/g1HeapRegionTraceType.hpp" #include "gc/g1/g1SurvRateGroup.hpp" #include "gc/g1/heapRegionTracer.hpp" @@ -38,7 +37,6 @@ #include "utilities/macros.hpp" class G1CardSetConfiguration; -class G1CardSetMemoryManager; class G1CollectedHeap; class G1CMBitMap; class G1Predictions; @@ -164,18 +162,12 @@ public: inline HeapWord* allocate(size_t word_size); inline HeapWord* allocate(size_t min_word_size, size_t desired_word_size, size_t* actual_size); - // Update the BOT for the given address if it crosses the next - // BOT threshold at or after obj_start. - inline void update_bot_at(HeapWord* obj_start, size_t obj_size); - // Update BOT at the given threshold for the given object. The - // given object must cross the threshold. - inline void update_bot_crossing_threshold(HeapWord** threshold, HeapWord* obj_start, HeapWord* obj_end); - inline HeapWord* bot_threshold_for_addr(const void* addr); + // Update BOT if this obj is the first entering a new card (i.e. crossing the card boundary). + inline void update_bot_for_obj(HeapWord* obj_start, size_t obj_size); // Full GC support methods. - void initialize_bot_threshold(); - void alloc_block_in_bot(HeapWord* start, HeapWord* end); + void update_bot_for_block(HeapWord* start, HeapWord* end); // Update heap region that has been compacted to be consistent after Full GC. void reset_compacted_after_full_gc(); @@ -199,18 +191,10 @@ public: template inline void apply_to_marked_objects(G1CMBitMap* bitmap, ApplyToMarkedClosure* closure); - void reset_bot() { - _bot_part.reset_bot(); - } - void update_bot() { _bot_part.update(); } - void update_bot_threshold() { - _bot_part.set_threshold(top()); - } - private: // The remembered set for this region. HeapRegionRemSet* _rem_set; @@ -269,8 +253,6 @@ private: uint _node_index; - G1EvacFailureObjectsSet _evac_failure_objs; - void report_region_type_change(G1HeapRegionTraceType::Type to); // Returns whether the given object address refers to a dead object, and either the @@ -567,11 +549,6 @@ public: // Update the region state after a failed evacuation. void handle_evacuation_failure(); - // Record an object that failed evacuation within this region. - void record_evac_failure_obj(oop obj); - // Applies the given closure to all previously recorded objects - // that failed evacuation in ascending address order. - void process_and_drop_evac_failure_objs(ObjectClosure* closure); // Iterate over the objects overlapping the given memory region, applying cl // to all references in the region. This is a helper for @@ -586,42 +563,35 @@ public: // Routines for managing a list of code roots (attached to the // this region's RSet) that point into this heap region. - void add_strong_code_root(nmethod* nm); - void add_strong_code_root_locked(nmethod* nm); - void remove_strong_code_root(nmethod* nm); + void add_code_root(nmethod* nm); + void add_code_root_locked(nmethod* nm); + void remove_code_root(nmethod* nm); // Applies blk->do_code_blob() to each of the entries in - // the strong code roots list for this region - void strong_code_roots_do(CodeBlobClosure* blk) const; + // the code roots list for this region + void code_roots_do(CodeBlobClosure* blk) const; uint node_index() const { return _node_index; } void set_node_index(uint node_index) { _node_index = node_index; } - // Verify that the entries on the strong code root list for this + // Verify that the entries on the code root list for this // region are live and include at least one pointer into this region. - void verify_strong_code_roots(VerifyOption vo, bool* failures) const; + void verify_code_roots(VerifyOption vo, bool* failures) const; void print() const; void print_on(outputStream* st) const; // vo == UsePrevMarking -> use "prev" marking information, - // vo == UseNextMarking -> use "next" marking information // vo == UseFullMarking -> use "next" marking bitmap but no TAMS // // NOTE: Only the "prev" marking information is guaranteed to be // consistent most of the time, so most calls to this should use // vo == UsePrevMarking. - // Currently, there is only one case where this is called with - // vo == UseNextMarking, which is to verify the "next" marking - // information at the end of remark. // Currently there is only one place where this is called with // vo == UseFullMarking, which is to verify the marking during a // full GC. void verify(VerifyOption vo, bool *failures) const; - // Verify using the "prev" marking information - void verify() const; - void verify_rem_set(VerifyOption vo, bool *failures) const; void verify_rem_set() const; }; diff --git a/src/hotspot/share/gc/g1/heapRegion.inline.hpp b/src/hotspot/share/gc/g1/heapRegion.inline.hpp index 3d07d61fe24464b1d54b02f1e7128a177bc1f8b2..e94320fbdb496d7dc6ac53da0bb05e823e08c8c8 100644 --- a/src/hotspot/share/gc/g1/heapRegion.inline.hpp +++ b/src/hotspot/share/gc/g1/heapRegion.inline.hpp @@ -30,7 +30,6 @@ #include "gc/g1/g1BlockOffsetTable.inline.hpp" #include "gc/g1/g1CollectedHeap.inline.hpp" #include "gc/g1/g1ConcurrentMarkBitMap.inline.hpp" -#include "gc/g1/g1EvacFailureObjectsSet.inline.hpp" #include "gc/g1/g1Predictions.hpp" #include "gc/g1/g1SegmentedArray.inline.hpp" #include "oops/oop.inline.hpp" @@ -84,10 +83,6 @@ inline HeapWord* HeapRegion::block_start(const void* p) { return _bot_part.block_start(p); } -inline HeapWord* HeapRegion::block_start_const(const void* p) const { - return _bot_part.block_start_const(p); -} - inline bool HeapRegion::is_obj_dead_with_size(const oop obj, const G1CMBitMap* const prev_bitmap, size_t* size) const { HeapWord* addr = cast_from_oop(obj); @@ -108,12 +103,8 @@ inline bool HeapRegion::is_obj_dead_with_size(const oop obj, const G1CMBitMap* c } inline bool HeapRegion::block_is_obj(const HeapWord* p) const { - G1CollectedHeap* g1h = G1CollectedHeap::heap(); - - if (!this->is_in(p)) { - assert(is_continues_humongous(), "This case can only happen for humongous regions"); - return (p == humongous_start_region()->bottom()); - } + assert(p >= bottom() && p < top(), "precondition"); + assert(!is_continues_humongous(), "p must point to block-start"); // When class unloading is enabled it is not safe to only consider top() to conclude if the // given pointer is a valid object. The situation can occur both for class unloading in a // Full GC and during a concurrent cycle. @@ -122,9 +113,9 @@ inline bool HeapRegion::block_is_obj(const HeapWord* p) const { // During a concurrent cycle class unloading is done after marking is complete and objects // for the unloaded classes will be stale until the regions are collected. if (ClassUnloading) { - return !g1h->is_obj_dead(cast_to_oop(p), this); + return !G1CollectedHeap::heap()->is_obj_dead(cast_to_oop(p), this); } - return p < top(); + return true; } inline size_t HeapRegion::block_size_using_bitmap(const HeapWord* addr, const G1CMBitMap* const prev_bitmap) const { @@ -192,10 +183,6 @@ inline void HeapRegion::reset_skip_compacting_after_full_gc() { } inline void HeapRegion::reset_after_full_gc_common() { - if (is_empty()) { - reset_bot(); - } - // Clear unused heap memory in debug builds. if (ZapUnusedHeapArea) { mangle_unused_area(); @@ -240,33 +227,17 @@ inline HeapWord* HeapRegion::allocate(size_t min_word_size, return allocate_impl(min_word_size, desired_word_size, actual_word_size); } -inline HeapWord* HeapRegion::bot_threshold_for_addr(const void* addr) { - HeapWord* threshold = _bot_part.threshold_for_addr(addr); - assert(threshold >= addr, - "threshold must be at or after given address. " PTR_FORMAT " >= " PTR_FORMAT, - p2i(threshold), p2i(addr)); - assert(is_old(), - "Should only calculate BOT threshold for old regions. addr: " PTR_FORMAT " region:" HR_FORMAT, - p2i(addr), HR_FORMAT_PARAMS(this)); - return threshold; -} - -inline void HeapRegion::update_bot_crossing_threshold(HeapWord** threshold, HeapWord* obj_start, HeapWord* obj_end) { +inline void HeapRegion::update_bot_for_obj(HeapWord* obj_start, size_t obj_size) { assert(is_old(), "should only do BOT updates for old regions"); - assert(is_in(obj_start), "obj_start must be in this region: " HR_FORMAT - " obj_start " PTR_FORMAT " obj_end " PTR_FORMAT " threshold " PTR_FORMAT, - HR_FORMAT_PARAMS(this), - p2i(obj_start), p2i(obj_end), p2i(*threshold)); - _bot_part.alloc_block_work(threshold, obj_start, obj_end); -} -inline void HeapRegion::update_bot_at(HeapWord* obj_start, size_t obj_size) { - HeapWord* threshold = bot_threshold_for_addr(obj_start); HeapWord* obj_end = obj_start + obj_size; - if (obj_end > threshold) { - update_bot_crossing_threshold(&threshold, obj_start, obj_end); - } + assert(is_in(obj_start), "obj_start must be in this region: " HR_FORMAT + " obj_start " PTR_FORMAT " obj_end " PTR_FORMAT, + HR_FORMAT_PARAMS(this), + p2i(obj_start), p2i(obj_end)); + + _bot_part.update_for_block(obj_start, obj_end); } inline void HeapRegion::note_start_of_marking() { @@ -356,20 +327,8 @@ HeapWord* HeapRegion::oops_on_memregion_seq_iterate_careful(MemRegion mr, HeapWord* const end = mr.end(); // Find the obj that extends onto mr.start(). - // Update BOT as needed while finding start of (possibly dead) - // object containing the start of the region. HeapWord* cur = block_start(start); -#ifdef ASSERT - { - assert(cur <= start, - "cur: " PTR_FORMAT ", start: " PTR_FORMAT, p2i(cur), p2i(start)); - HeapWord* next = cur + block_size(cur); - assert(start < next, - "start: " PTR_FORMAT ", next: " PTR_FORMAT, p2i(start), p2i(next)); - } -#endif - const G1CMBitMap* const bitmap = g1h->concurrent_mark()->prev_mark_bitmap(); while (true) { oop obj = cast_to_oop(cur); @@ -449,8 +408,4 @@ inline void HeapRegion::record_surv_words_in_group(size_t words_survived) { _surv_rate_group->record_surviving_words(age_in_group, words_survived); } -inline void HeapRegion::record_evac_failure_obj(oop obj) { - _evac_failure_objs.record(obj); -} - #endif // SHARE_GC_G1_HEAPREGION_INLINE_HPP diff --git a/src/hotspot/share/gc/g1/heapRegionBounds.hpp b/src/hotspot/share/gc/g1/heapRegionBounds.hpp index 5e748de59286b814d0c9fdc6aca41535f8b42144..5a6db9fac3b145a9706ce805d37ea0629e6dff41 100644 --- a/src/hotspot/share/gc/g1/heapRegionBounds.hpp +++ b/src/hotspot/share/gc/g1/heapRegionBounds.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -25,7 +25,8 @@ #ifndef SHARE_GC_G1_HEAPREGIONBOUNDS_HPP #define SHARE_GC_G1_HEAPREGIONBOUNDS_HPP -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" +#include "utilities/globalDefinitions.hpp" class HeapRegionBounds : public AllStatic { private: diff --git a/src/hotspot/share/gc/g1/heapRegionRemSet.cpp b/src/hotspot/share/gc/g1/heapRegionRemSet.cpp index a0e740ad26790864477f942051f232bb20df36d6..9e6c31ffdc11aa55a49b52de10325ce9c2b4c38f 100644 --- a/src/hotspot/share/gc/g1/heapRegionRemSet.cpp +++ b/src/hotspot/share/gc/g1/heapRegionRemSet.cpp @@ -60,7 +60,7 @@ void HeapRegionRemSet::initialize(MemRegion reserved) { vm_exit_during_initialization("Can not represent all cards in a card region within uint."); } - _split_card_shift = CardBitsWithinCardRegion + CardTable::card_shift; + _split_card_shift = CardBitsWithinCardRegion + CardTable::card_shift(); _split_card_mask = ((size_t)1 << _split_card_shift) - 1; // Check if the card region/region within cards combination can cover the heap. @@ -81,7 +81,7 @@ HeapRegionRemSet::HeapRegionRemSet(HeapRegion* hr, G1CardSetConfiguration* config) : _m(Mutex::service - 1, FormatBuffer<128>("HeapRegionRemSet#%u_lock", hr->hrm_index())), _code_roots(), - _card_set_mm(config, G1CardSetFreePool::free_list_pool()), + _card_set_mm(config, G1SegmentedArrayFreePool::free_list_pool()), _card_set(config, &_card_set_mm), _hr(hr), _state(Untracked) { } @@ -105,6 +105,10 @@ void HeapRegionRemSet::clear_locked(bool only_cardset) { assert(occupied() == 0, "Should be clear."); } +G1SegmentedArrayMemoryStats HeapRegionRemSet::card_set_memory_stats() const { + return _card_set_mm.memory_stats(); +} + void HeapRegionRemSet::print_static_mem_size(outputStream* out) { out->print_cr(" Static structures = " SIZE_FORMAT, HeapRegionRemSet::static_mem_size()); } @@ -118,19 +122,19 @@ void HeapRegionRemSet::print_static_mem_size(outputStream* out) { // When concurrent readers access the contains() function // (during the evacuation phase) no removals are allowed. -void HeapRegionRemSet::add_strong_code_root(nmethod* nm) { +void HeapRegionRemSet::add_code_root(nmethod* nm) { assert(nm != NULL, "sanity"); assert((!CodeCache_lock->owned_by_self() || SafepointSynchronize::is_at_safepoint()), - "should call add_strong_code_root_locked instead. CodeCache_lock->owned_by_self(): %s, is_at_safepoint(): %s", + "should call add_code_root_locked instead. CodeCache_lock->owned_by_self(): %s, is_at_safepoint(): %s", BOOL_TO_STR(CodeCache_lock->owned_by_self()), BOOL_TO_STR(SafepointSynchronize::is_at_safepoint())); // Optimistic unlocked contains-check if (!_code_roots.contains(nm)) { MutexLocker ml(&_m, Mutex::_no_safepoint_check_flag); - add_strong_code_root_locked(nm); + add_code_root_locked(nm); } } -void HeapRegionRemSet::add_strong_code_root_locked(nmethod* nm) { +void HeapRegionRemSet::add_code_root_locked(nmethod* nm) { assert(nm != NULL, "sanity"); assert((CodeCache_lock->owned_by_self() || (SafepointSynchronize::is_at_safepoint() && @@ -141,7 +145,7 @@ void HeapRegionRemSet::add_strong_code_root_locked(nmethod* nm) { _code_roots.add(nm); } -void HeapRegionRemSet::remove_strong_code_root(nmethod* nm) { +void HeapRegionRemSet::remove_code_root(nmethod* nm) { assert(nm != NULL, "sanity"); assert_locked_or_safepoint(CodeCache_lock); @@ -152,14 +156,14 @@ void HeapRegionRemSet::remove_strong_code_root(nmethod* nm) { guarantee(!_code_roots.contains(nm), "duplicate entry found"); } -void HeapRegionRemSet::strong_code_roots_do(CodeBlobClosure* blk) const { +void HeapRegionRemSet::code_roots_do(CodeBlobClosure* blk) const { _code_roots.nmethods_do(blk); } -void HeapRegionRemSet::clean_strong_code_roots(HeapRegion* hr) { +void HeapRegionRemSet::clean_code_roots(HeapRegion* hr) { _code_roots.clean(hr); } -size_t HeapRegionRemSet::strong_code_roots_mem_size() { +size_t HeapRegionRemSet::code_roots_mem_size() { return _code_roots.mem_size(); } diff --git a/src/hotspot/share/gc/g1/heapRegionRemSet.hpp b/src/hotspot/share/gc/g1/heapRegionRemSet.hpp index 958d6fceaf18920700779d30429f1c62df79b4d5..04b585661f837b5b03c616420827415484ac8f75 100644 --- a/src/hotspot/share/gc/g1/heapRegionRemSet.hpp +++ b/src/hotspot/share/gc/g1/heapRegionRemSet.hpp @@ -33,6 +33,7 @@ #include "runtime/safepoint.hpp" #include "utilities/bitMap.hpp" +class G1CardSetMemoryManager; class outputStream; class HeapRegionRemSet : public CHeapObj { @@ -72,11 +73,11 @@ public: } bool is_empty() const { - return (strong_code_roots_list_length() == 0) && cardset_is_empty(); + return (code_roots_list_length() == 0) && cardset_is_empty(); } bool occupancy_less_or_equal_than(size_t occ) const { - return (strong_code_roots_list_length() == 0) && _card_set.occupancy_less_or_equal_to(occ); + return (code_roots_list_length() == 0) && _card_set.occupancy_less_or_equal_to(occ); } // Iterate the card based remembered set for merging them into the card table. @@ -125,14 +126,14 @@ public: void clear(bool only_cardset = false); void clear_locked(bool only_cardset = false); - G1CardSetMemoryStats card_set_memory_stats() const { return _card_set_mm.memory_stats(); } + G1SegmentedArrayMemoryStats card_set_memory_stats() const; - // The actual # of bytes this hr_remset takes up. Also includes the strong code + // The actual # of bytes this hr_remset takes up. Also includes the code // root set. size_t mem_size() { return _card_set.mem_size() - + (sizeof(HeapRegionRemSet) - sizeof(G1CardSet)) // Avoid double-counting G1CardSet. - + strong_code_roots_mem_size(); + + (sizeof(HeapRegionRemSet) - sizeof(G1CardSet)) // Avoid double-counting G1CardSet. + + code_roots_mem_size(); } size_t wasted_mem_size() { @@ -153,30 +154,29 @@ public: // Routines for managing the list of code roots that point into // the heap region that owns this RSet. - void add_strong_code_root(nmethod* nm); - void add_strong_code_root_locked(nmethod* nm); - void remove_strong_code_root(nmethod* nm); + void add_code_root(nmethod* nm); + void add_code_root_locked(nmethod* nm); + void remove_code_root(nmethod* nm); - // Applies blk->do_code_blob() to each of the entries in - // the strong code roots list - void strong_code_roots_do(CodeBlobClosure* blk) const; + // Applies blk->do_code_blob() to each of the entries in _code_roots + void code_roots_do(CodeBlobClosure* blk) const; - void clean_strong_code_roots(HeapRegion* hr); + void clean_code_roots(HeapRegion* hr); - // Returns the number of elements in the strong code roots list - size_t strong_code_roots_list_length() const { + // Returns the number of elements in _code_roots + size_t code_roots_list_length() const { return _code_roots.length(); } - // Returns true if the strong code roots contains the given + // Returns true if the code roots contains the given // nmethod. - bool strong_code_roots_list_contains(nmethod* nm) { + bool code_roots_list_contains(nmethod* nm) { return _code_roots.contains(nm); } // Returns the amount of memory, in bytes, currently - // consumed by the strong code roots. - size_t strong_code_roots_mem_size(); + // consumed by the code roots. + size_t code_roots_mem_size(); static void invalidate_from_card_cache(uint start_idx, size_t num_regions) { G1FromCardCache::invalidate(start_idx, num_regions); diff --git a/src/hotspot/share/gc/g1/heapRegionRemSet.inline.hpp b/src/hotspot/share/gc/g1/heapRegionRemSet.inline.hpp index ff1f75df6028fc09133caeab3aa7793d55d8b601..a0e920175e1509688e00a37e5a0c4149dde7b40d 100644 --- a/src/hotspot/share/gc/g1/heapRegionRemSet.inline.hpp +++ b/src/hotspot/share/gc/g1/heapRegionRemSet.inline.hpp @@ -57,79 +57,76 @@ void HeapRegionRemSet::set_state_complete() { template class G1ContainerCardsOrRanges { - Closure& _iter; + Closure& _cl; uint _region_idx; uint _offset; public: - G1ContainerCardsOrRanges(Closure& iter, uint region_idx, uint offset) : _iter(iter), _region_idx(region_idx), _offset(offset) { } + G1ContainerCardsOrRanges(Closure& cl, uint region_idx, uint offset) : _cl(cl), _region_idx(region_idx), _offset(offset) { } bool start_iterate(uint tag) { - return _iter.start_iterate(tag, _region_idx); + return _cl.start_iterate(tag, _region_idx); } void operator()(uint card_idx) { - _iter.do_card(card_idx + _offset); + _cl.do_card(card_idx + _offset); } void operator()(uint card_idx, uint length) { - _iter.do_card_range(card_idx + _offset, length); + _cl.do_card_range(card_idx + _offset, length); } }; template class CardOrRanges> -class G1HeapRegionRemSetMergeCardIterator : public G1CardSet::G1CardSetPtrIterator { +class G1HeapRegionRemSetMergeCardClosure : public G1CardSet::ContainerPtrClosure { G1CardSet* _card_set; - Closure& _iter; + Closure& _cl; uint _log_card_regions_per_region; uint _card_regions_per_region_mask; uint _log_card_region_size; public: - G1HeapRegionRemSetMergeCardIterator(G1CardSet* card_set, - Closure& iter, + G1HeapRegionRemSetMergeCardClosure(G1CardSet* card_set, + Closure& cl, uint log_card_regions_per_region, uint log_card_region_size) : _card_set(card_set), - _iter(iter), + _cl(cl), _log_card_regions_per_region(log_card_regions_per_region), _card_regions_per_region_mask((1 << log_card_regions_per_region) - 1), _log_card_region_size(log_card_region_size) { } - void do_cardsetptr(uint card_region_idx, size_t num_occupied, G1CardSet::CardSetPtr card_set) override { - CardOrRanges cl(_iter, + void do_containerptr(uint card_region_idx, size_t num_occupied, G1CardSet::ContainerPtr container) override { + CardOrRanges cl(_cl, card_region_idx >> _log_card_regions_per_region, (card_region_idx & _card_regions_per_region_mask) << _log_card_region_size); - _card_set->iterate_cards_or_ranges_in_container(card_set, cl); + _card_set->iterate_cards_or_ranges_in_container(container, cl); } }; template inline void HeapRegionRemSet::iterate_for_merge(CardOrRangeVisitor& cl) { - G1HeapRegionRemSetMergeCardIterator cl2(&_card_set, - cl, - _card_set.config()->log2_card_region_per_heap_region(), - _card_set.config()->log2_cards_per_card_region()); + G1HeapRegionRemSetMergeCardClosure cl2(&_card_set, + cl, + _card_set.config()->log2_card_regions_per_heap_region(), + _card_set.config()->log2_cards_per_card_region()); _card_set.iterate_containers(&cl2, true /* at_safepoint */); } void HeapRegionRemSet::split_card(OopOrNarrowOopStar from, uint& card_region, uint& card_within_region) const { size_t offset = pointer_delta(from, _heap_base_address, 1); card_region = (uint)(offset >> _split_card_shift); - card_within_region = (uint)((offset & _split_card_mask) >> CardTable::card_shift); + card_within_region = (uint)((offset & _split_card_mask) >> CardTable::card_shift()); assert(card_within_region < ((uint)1 << G1CardSetContainer::LogCardsPerRegionLimit), "must be"); } void HeapRegionRemSet::add_reference(OopOrNarrowOopStar from, uint tid) { - RemSetState state = _state; - if (state == Untracked) { - return; - } + assert(_state != Untracked, "must be"); uint cur_idx = _hr->hrm_index(); - uintptr_t from_card = uintptr_t(from) >> CardTable::card_shift; + uintptr_t from_card = uintptr_t(from) >> CardTable::card_shift(); if (G1FromCardCache::contains_or_replace(tid, cur_idx, from_card)) { // We can't check whether the card is in the remembered set - the card container diff --git a/src/hotspot/share/gc/g1/heapRegionTracer.hpp b/src/hotspot/share/gc/g1/heapRegionTracer.hpp index bdfcd1cfd8e2599016e0d79daeb25d0b3ed1a4a7..647744d0d5e2362029e285109e57a3d1216db05b 100644 --- a/src/hotspot/share/gc/g1/heapRegionTracer.hpp +++ b/src/hotspot/share/gc/g1/heapRegionTracer.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -26,7 +26,8 @@ #define SHARE_GC_G1_HEAPREGIONTRACER_HPP #include "gc/g1/g1HeapRegionTraceType.hpp" -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" +#include "utilities/globalDefinitions.hpp" class HeapRegionTracer : AllStatic { public: diff --git a/src/hotspot/share/gc/g1/heapRegionType.hpp b/src/hotspot/share/gc/g1/heapRegionType.hpp index 74807c37746598eda34e1c32c53a8a87c1528333..9e1c79ea0d052433a7993249a89cfa97797cdf1b 100644 --- a/src/hotspot/share/gc/g1/heapRegionType.hpp +++ b/src/hotspot/share/gc/g1/heapRegionType.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -26,6 +26,7 @@ #define SHARE_GC_G1_HEAPREGIONTYPE_HPP #include "gc/g1/g1HeapRegionTraceType.hpp" +#include "utilities/globalDefinitions.hpp" #define hrt_assert_is_valid(tag) \ assert(is_valid((tag)), "invalid HR type: %u", (uint) (tag)) diff --git a/src/hotspot/share/gc/parallel/mutableSpace.cpp b/src/hotspot/share/gc/parallel/mutableSpace.cpp index e28a71e5691255ea275e8128de254043b4bac0f7..95bd979bcf1435ef90aa809510433492948fa15a 100644 --- a/src/hotspot/share/gc/parallel/mutableSpace.cpp +++ b/src/hotspot/share/gc/parallel/mutableSpace.cpp @@ -217,7 +217,7 @@ bool MutableSpace::cas_deallocate(HeapWord *obj, size_t size) { // Only used by oldgen allocation. bool MutableSpace::needs_expand(size_t word_size) const { - assert_lock_strong(ExpandHeap_lock); + assert_lock_strong(PSOldGenExpand_lock); // Holding the lock means end is stable. So while top may be advancing // via concurrent allocations, there is no need to order the reads of top // and end here, unlike in cas_allocate. diff --git a/src/hotspot/share/gc/parallel/mutableSpace.hpp b/src/hotspot/share/gc/parallel/mutableSpace.hpp index 548b6a4949ee7cb0d5189e36e18b1ff7d45216a5..289d8997f39749b5d091b0e022d97397697d81c1 100644 --- a/src/hotspot/share/gc/parallel/mutableSpace.hpp +++ b/src/hotspot/share/gc/parallel/mutableSpace.hpp @@ -145,7 +145,7 @@ class MutableSpace: public CHeapObj { // Return true if this space needs to be expanded in order to satisfy an // allocation request of the indicated size. Concurrent allocations and // resizes may change the result of a later call. Used by oldgen allocator. - // precondition: holding ExpandHeap_lock + // precondition: holding PSOldGenExpand_lock bool needs_expand(size_t word_size) const; // Iteration. diff --git a/src/hotspot/share/gc/parallel/objectStartArray.cpp b/src/hotspot/share/gc/parallel/objectStartArray.cpp index d2d98bc24a9cde39a743613886be1572bcdbcda2..3e4820aa9414f8b3e21d3af6fb6847928453d752 100644 --- a/src/hotspot/share/gc/parallel/objectStartArray.cpp +++ b/src/hotspot/share/gc/parallel/objectStartArray.cpp @@ -31,16 +31,26 @@ #include "services/memTracker.hpp" #include "utilities/align.hpp" +uint ObjectStartArray::_card_shift = 0; +uint ObjectStartArray::_card_size = 0; +uint ObjectStartArray::_card_size_in_words = 0; + +void ObjectStartArray::initialize_block_size(uint card_shift) { + _card_shift = card_shift; + _card_size = 1 << _card_shift; + _card_size_in_words = _card_size / sizeof(HeapWord); +} + void ObjectStartArray::initialize(MemRegion reserved_region) { // We're based on the assumption that we use the same // size blocks as the card table. - assert((int)block_size == (int)CardTable::card_size, "Sanity"); - assert((int)block_size <= 512, "block_size must be less than or equal to 512"); + assert(_card_size == CardTable::card_size(), "Sanity"); + assert(_card_size <= MaxBlockSize, "block_size must be less than or equal to " UINT32_FORMAT, MaxBlockSize); // Calculate how much space must be reserved _reserved_region = reserved_region; - size_t bytes_to_reserve = reserved_region.word_size() / block_size_in_words; + size_t bytes_to_reserve = reserved_region.word_size() / _card_size_in_words; assert(bytes_to_reserve > 0, "Sanity"); bytes_to_reserve = @@ -55,20 +65,12 @@ void ObjectStartArray::initialize(MemRegion reserved_region) { MemTracker::record_virtual_memory_type((address)backing_store.base(), mtGC); // We do not commit any memory initially - if (!_virtual_space.initialize(backing_store, 0)) { - vm_exit_during_initialization("Could not commit space for ObjectStartArray"); - } + _virtual_space.initialize(backing_store); _raw_base = (jbyte*)_virtual_space.low_boundary(); + assert(_raw_base != nullptr, "set from the backing_store"); - if (_raw_base == NULL) { - vm_exit_during_initialization("Could not get raw_base address"); - } - - MemTracker::record_virtual_memory_type((address)_raw_base, mtGC); - - - _offset_base = _raw_base - (size_t(reserved_region.start()) >> block_shift); + _offset_base = _raw_base - (size_t(reserved_region.start()) >> _card_shift); _covered_region.set_start(reserved_region.start()); _covered_region.set_word_size(0); @@ -83,10 +85,10 @@ void ObjectStartArray::set_covered_region(MemRegion mr) { HeapWord* low_bound = mr.start(); HeapWord* high_bound = mr.end(); - assert((uintptr_t(low_bound) & (block_size - 1)) == 0, "heap must start at block boundary"); - assert((uintptr_t(high_bound) & (block_size - 1)) == 0, "heap must end at block boundary"); + assert((uintptr_t(low_bound) & (_card_size - 1)) == 0, "heap must start at block boundary"); + assert((uintptr_t(high_bound) & (_card_size - 1)) == 0, "heap must end at block boundary"); - size_t requested_blocks_size_in_bytes = mr.word_size() / block_size_in_words; + size_t requested_blocks_size_in_bytes = mr.word_size() / _card_size_in_words; // Only commit memory in page sized chunks requested_blocks_size_in_bytes = @@ -130,8 +132,15 @@ bool ObjectStartArray::object_starts_in_range(HeapWord* start_addr, "Range is wrong. start_addr (" PTR_FORMAT ") is after end_addr (" PTR_FORMAT ")", p2i(start_addr), p2i(end_addr)); + assert(is_aligned(start_addr, _card_size), "precondition"); + + if (start_addr == end_addr) { + // No objects in empty range. + return false; + } + jbyte* start_block = block_for_addr(start_addr); - jbyte* end_block = block_for_addr(end_addr); + jbyte* end_block = block_for_addr(end_addr - 1); for (jbyte* block = start_block; block <= end_block; block++) { if (*block != clean_block) { diff --git a/src/hotspot/share/gc/parallel/objectStartArray.hpp b/src/hotspot/share/gc/parallel/objectStartArray.hpp index 45b4a53b16c5a959cf0ee10ad34c4b5d61882997..06005fc0075616cb5a7b4cfd790ff0f9336bc75b 100644 --- a/src/hotspot/share/gc/parallel/objectStartArray.hpp +++ b/src/hotspot/share/gc/parallel/objectStartArray.hpp @@ -41,22 +41,40 @@ class ObjectStartArray : public CHeapObj { private: PSVirtualSpace _virtual_space; MemRegion _reserved_region; + // The committed (old-gen heap) virtual space this object-start-array covers. MemRegion _covered_region; MemRegion _blocks_region; jbyte* _raw_base; jbyte* _offset_base; + static uint _card_shift; + static uint _card_size; + static uint _card_size_in_words; + public: enum BlockValueConstants { clean_block = -1 }; - enum BlockSizeConstants { - block_shift = 9, - block_size = 1 << block_shift, - block_size_in_words = block_size / sizeof(HeapWord) - }; + // Maximum size an offset table entry can cover. This maximum is derived from that + // we need an extra bit for possible offsets in the byte for backskip values, leaving 2^7 possible offsets. + // Minimum object alignment is 8 bytes (2^3), so we can at most represent 2^10 offsets within a BOT value. + static const uint MaxBlockSize = 1024; + + // Initialize block size based on card size + static void initialize_block_size(uint card_shift); + + static uint card_shift() { + return _card_shift; + } + + static uint card_size() { + return _card_size; + } + static uint card_size_in_words() { + return _card_size_in_words; + } protected: @@ -64,7 +82,7 @@ class ObjectStartArray : public CHeapObj { jbyte* block_for_addr(void* p) const { assert(_covered_region.contains(p), "out of bounds access to object start array"); - jbyte* result = &_offset_base[uintptr_t(p) >> block_shift]; + jbyte* result = &_offset_base[uintptr_t(p) >> _card_shift]; assert(_blocks_region.contains(result), "out of bounds result in byte_for"); return result; @@ -75,7 +93,7 @@ class ObjectStartArray : public CHeapObj { assert(_blocks_region.contains(p), "out of bounds access to object start array"); size_t delta = pointer_delta(p, _offset_base, sizeof(jbyte)); - HeapWord* result = (HeapWord*) (delta << block_shift); + HeapWord* result = (HeapWord*) (delta << _card_shift); assert(_covered_region.contains(result), "out of bounds accessor from card marking array"); return result; @@ -98,7 +116,7 @@ class ObjectStartArray : public CHeapObj { } size_t delta = pointer_delta(p, _offset_base, sizeof(jbyte)); - HeapWord* result = (HeapWord*) (delta << block_shift); + HeapWord* result = (HeapWord*) (delta << _card_shift); result += *p; assert(_covered_region.contains(result), @@ -147,9 +165,11 @@ class ObjectStartArray : public CHeapObj { return *block != clean_block; } - // Return true if an object starts in the range of heap addresses. - // If an object starts at an address corresponding to - // "start", the method will return true. + // Return true iff an object starts in + // [start_addr, end_addr_aligned_up) + // where + // end_addr_aligned_up = align_up(end_addr, _card_size) + // Precondition: start_addr is card-size aligned bool object_starts_in_range(HeapWord* start_addr, HeapWord* end_addr) const; }; diff --git a/src/hotspot/share/gc/parallel/parallelArguments.cpp b/src/hotspot/share/gc/parallel/parallelArguments.cpp index 2ffffdf145532d2e141161e6690e36fc2cc22e7f..468dc7bdfaf8ca2da50b53ee8106c68f887becb3 100644 --- a/src/hotspot/share/gc/parallel/parallelArguments.cpp +++ b/src/hotspot/share/gc/parallel/parallelArguments.cpp @@ -97,6 +97,8 @@ static size_t default_gen_alignment() { } void ParallelArguments::initialize_alignments() { + // Initialize card size before initializing alignments + CardTable::initialize_card_size(); SpaceAlignment = GenAlignment = default_gen_alignment(); HeapAlignment = compute_heap_alignment(); } diff --git a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp index 0013007a923c4f1fddc026d1388a29c7bf93a247..e47730d47e1fe714ef634a0ad9bf90d50e502b08 100644 --- a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp +++ b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp @@ -600,7 +600,7 @@ void ParallelScavengeHeap::object_iterate_parallel(ObjectClosure* cl, } } -class PSScavengeParallelObjectIterator : public ParallelObjectIterator { +class PSScavengeParallelObjectIterator : public ParallelObjectIteratorImpl { private: ParallelScavengeHeap* _heap; HeapBlockClaimer _claimer; @@ -615,7 +615,7 @@ public: } }; -ParallelObjectIterator* ParallelScavengeHeap::parallel_object_iterator(uint thread_num) { +ParallelObjectIteratorImpl* ParallelScavengeHeap::parallel_object_iterator(uint thread_num) { return new PSScavengeParallelObjectIterator(); } @@ -645,8 +645,10 @@ void ParallelScavengeHeap::prepare_for_verify() { PSHeapSummary ParallelScavengeHeap::create_ps_heap_summary() { PSOldGen* old = old_gen(); HeapWord* old_committed_end = (HeapWord*)old->virtual_space()->committed_high_addr(); - VirtualSpaceSummary old_summary(old->reserved().start(), old_committed_end, old->reserved().end()); - SpaceSummary old_space(old->reserved().start(), old_committed_end, old->used_in_bytes()); + HeapWord* old_reserved_start = old->reserved().start(); + HeapWord* old_reserved_end = old->reserved().end(); + VirtualSpaceSummary old_summary(old_reserved_start, old_committed_end, old_reserved_end); + SpaceSummary old_space(old_reserved_start, old_committed_end, old->used_in_bytes()); PSYoungGen* young = young_gen(); VirtualSpaceSummary young_summary(young->reserved().start(), @@ -796,6 +798,16 @@ void ParallelScavengeHeap::resize_old_gen(size_t desired_free_space) { _old_gen->resize(desired_free_space); } +HeapWord* ParallelScavengeHeap::allocate_loaded_archive_space(size_t size) { + return _old_gen->allocate(size); +} + +void ParallelScavengeHeap::complete_loaded_archive_space(MemRegion archive_space) { + assert(_old_gen->object_space()->used_region().contains(archive_space), + "Archive space not contained in old gen"); + _old_gen->complete_loaded_archive_space(archive_space); +} + #ifndef PRODUCT void ParallelScavengeHeap::record_gen_tops_before_GC() { if (ZapUnusedHeapArea) { diff --git a/src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp b/src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp index 9d8368fc3a4b86f4005a1a40efc4fc050aecb1dc..3ee16e5d8b9840851d01916a5dc526c98d001d39 100644 --- a/src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp +++ b/src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp @@ -184,8 +184,7 @@ class ParallelScavengeHeap : public CollectedHeap { bool is_in_reserved(const void* p) const; - bool is_in_young(oop p); // reserved part - bool is_in_old(oop p); // reserved part + bool is_in_young(const oop p) const; MemRegion reserved_region() const { return _reserved; } HeapWord* base() const { return _reserved.start(); } @@ -231,7 +230,7 @@ class ParallelScavengeHeap : public CollectedHeap { void object_iterate(ObjectClosure* cl); void object_iterate_parallel(ObjectClosure* cl, HeapBlockClaimer* claimer); - virtual ParallelObjectIterator* parallel_object_iterator(uint thread_num); + virtual ParallelObjectIteratorImpl* parallel_object_iterator(uint thread_num); HeapWord* block_start(const void* addr) const; bool block_is_obj(const HeapWord* addr) const; @@ -273,6 +272,11 @@ class ParallelScavengeHeap : public CollectedHeap { WorkerThreads& workers() { return _workers; } + + // Support for loading objects from CDS archive into the heap + bool can_load_archived_objects() const { return UseCompressedOops; } + HeapWord* allocate_loaded_archive_space(size_t size); + void complete_loaded_archive_space(MemRegion archive_space); }; // Class that can be used to print information about the diff --git a/src/hotspot/share/gc/parallel/parallelScavengeHeap.inline.hpp b/src/hotspot/share/gc/parallel/parallelScavengeHeap.inline.hpp index a867c689c984023bab102da76319aef4706003d4..80efa1b8fc6f6e5d6e74b7ecede99973cf03f5d7 100644 --- a/src/hotspot/share/gc/parallel/parallelScavengeHeap.inline.hpp +++ b/src/hotspot/share/gc/parallel/parallelScavengeHeap.inline.hpp @@ -43,7 +43,7 @@ inline void ParallelScavengeHeap::invoke_scavenge() { PSScavenge::invoke(); } -inline bool ParallelScavengeHeap::is_in_young(oop p) { +inline bool ParallelScavengeHeap::is_in_young(const oop p) const { // Assumes the the old gen address range is lower than that of the young gen. bool result = cast_from_oop(p) >= young_gen()->reserved().start(); assert(result == young_gen()->is_in_reserved(p), diff --git a/src/hotspot/share/gc/parallel/parallel_globals.hpp b/src/hotspot/share/gc/parallel/parallel_globals.hpp index 19953ca0b618cac9bc833a09315d86c7b011188b..b9202ce7cda81b21fecebdb4cbc9e3bde324f480 100644 --- a/src/hotspot/share/gc/parallel/parallel_globals.hpp +++ b/src/hotspot/share/gc/parallel/parallel_globals.hpp @@ -55,9 +55,6 @@ "limiter (a number between 0-100)") \ range(0, 100) \ \ - develop(uintx, GCWorkerDelayMillis, 0, \ - "Delay in scheduling GC workers (in milliseconds)") \ - \ product(bool, PSChunkLargeArrays, true, \ "Process large arrays in chunks") diff --git a/src/hotspot/share/gc/parallel/psCardTable.cpp b/src/hotspot/share/gc/parallel/psCardTable.cpp index ec186aec83f0151c9c8702afcfb46f5593813260..bdad1707ca13925e228eea1d752fbb06219f7fe8 100644 --- a/src/hotspot/share/gc/parallel/psCardTable.cpp +++ b/src/hotspot/share/gc/parallel/psCardTable.cpp @@ -117,18 +117,88 @@ class CheckForPreciseMarks : public BasicOopIterateClosure { virtual void do_oop(narrowOop* p) { CheckForPreciseMarks::do_oop_work(p); } }; +static void prefetch_write(void *p) { + if (PrefetchScanIntervalInBytes >= 0) { + Prefetch::write(p, PrefetchScanIntervalInBytes); + } +} + +// postcondition: ret is a dirty card or end_card +CardTable::CardValue* PSCardTable::find_first_dirty_card(CardValue* const start_card, + CardValue* const end_card) { + for (CardValue* i_card = start_card; i_card < end_card; ++i_card) { + if (*i_card != PSCardTable::clean_card_val()) { + return i_card; + } + } + return end_card; +} + +// postcondition: ret is a clean card or end_card +// Note: if a part of an object is on a dirty card, all cards this object +// resides on are considered dirty. +CardTable::CardValue* PSCardTable::find_first_clean_card(ObjectStartArray* const start_array, + CardValue* const start_card, + CardValue* const end_card) { + assert(start_card == end_card || + *start_card != PSCardTable::clean_card_val(), "precondition"); + // Skip the first dirty card. + CardValue* i_card = start_card + 1; + while (i_card < end_card) { + if (*i_card != PSCardTable::clean_card_val()) { + i_card++; + continue; + } + assert(i_card - 1 >= start_card, "inv"); + assert(*(i_card - 1) != PSCardTable::clean_card_val(), "prev card must be dirty"); + // Find the final obj on the prev dirty card. + HeapWord* obj_addr = start_array->object_start(addr_for(i_card)-1); + HeapWord* obj_end_addr = obj_addr + cast_to_oop(obj_addr)->size(); + CardValue* final_card_by_obj = byte_for(obj_end_addr - 1); + assert(final_card_by_obj < end_card, "inv"); + if (final_card_by_obj <= i_card) { + return i_card; + } + // This final obj extends beyond i_card, check if this new card is dirty. + if (*final_card_by_obj == PSCardTable::clean_card_val()) { + return final_card_by_obj; + } + // This new card is dirty, continuing the search... + i_card = final_card_by_obj + 1; + } + return end_card; +} + +void PSCardTable::clear_cards(CardValue* const start, CardValue* const end) { + for (CardValue* i_card = start; i_card < end; ++i_card) { + *i_card = clean_card; + } +} + +void PSCardTable::scan_objects_in_range(PSPromotionManager* pm, + HeapWord* start, + HeapWord* end) { + HeapWord* obj_addr = start; + while (obj_addr < end) { + oop obj = cast_to_oop(obj_addr); + assert(oopDesc::is_oop(obj), "inv"); + prefetch_write(obj_addr); + pm->push_contents(obj); + obj_addr += obj->size(); + } + pm->drain_stacks_cond_depth(); +} + // We get passed the space_top value to prevent us from traversing into // the old_gen promotion labs, which cannot be safely parsed. // Do not call this method if the space is empty. // It is a waste to start tasks and get here only to -// do no work. If this method needs to be called -// when the space is empty, fix the calculation of -// end_card to allow sp_top == sp->bottom(). +// do no work. This method is just a no-op if space_top == sp->bottom(). // The generation (old gen) is divided into slices, which are further // subdivided into stripes, with one stripe per GC thread. The size of -// a stripe is a constant, ssize. +// a stripe is a constant, num_cards_in_stripe. // // +===============+ slice 0 // | stripe 0 | @@ -152,199 +222,107 @@ class CheckForPreciseMarks : public BasicOopIterateClosure { // In this case there are 4 threads, so 4 stripes. A GC thread first works on // its stripe within slice 0 and then moves to its stripe in the next slice // until it has exceeded the top of the generation. The distance to stripe in -// the next slice is calculated based on the number of stripes. The next -// stripe is at ssize * number_of_stripes (= slice_stride).. So after -// finishing stripe 0 in slice 0, the thread finds the stripe 0 in slice1 by -// adding slice_stride to the start of stripe 0 in slice 0 to get to the start -// of stride 0 in slice 1. +// the next slice is calculated based on the number of stripes. After finishing +// stripe 0 in slice 0, the thread finds the stripe 0 in slice 1 by adding +// slice_size_in_words to the start of stripe 0 in slice 0 to get to the start +// of stripe 0 in slice 1. void PSCardTable::scavenge_contents_parallel(ObjectStartArray* start_array, MutableSpace* sp, HeapWord* space_top, PSPromotionManager* pm, - uint stripe_number, - uint stripe_total) { - int ssize = 128; // Naked constant! Work unit = 64k. - int dirty_card_count = 0; - - // It is a waste to get here if empty. - assert(sp->bottom() < sp->top(), "Should not be called if empty"); - oop* sp_top = (oop*)space_top; - CardValue* start_card = byte_for(sp->bottom()); - CardValue* end_card = byte_for(sp_top - 1) + 1; - oop* last_scanned = NULL; // Prevent scanning objects more than once - // The width of the stripe ssize*stripe_total must be - // consistent with the number of stripes so that the complete slice - // is covered. - size_t slice_width = ssize * stripe_total; - for (CardValue* slice = start_card; slice < end_card; slice += slice_width) { - CardValue* worker_start_card = slice + stripe_number * ssize; - if (worker_start_card >= end_card) - return; // We're done. - - CardValue* worker_end_card = worker_start_card + ssize; - if (worker_end_card > end_card) - worker_end_card = end_card; - - // We do not want to scan objects more than once. In order to accomplish - // this, we assert that any object with an object head inside our 'slice' - // belongs to us. We may need to extend the range of scanned cards if the - // last object continues into the next 'slice'. - // - // Note! ending cards are exclusive! - HeapWord* slice_start = addr_for(worker_start_card); - HeapWord* slice_end = MIN2((HeapWord*) sp_top, addr_for(worker_end_card)); - -#ifdef ASSERT - if (GCWorkerDelayMillis > 0) { - // Delay 1 worker so that it proceeds after all the work - // has been completed. - if (stripe_number < 2) { - os::naked_sleep(GCWorkerDelayMillis); - } - } -#endif + uint stripe_index, + uint n_stripes) { + const size_t num_cards_in_stripe = 128; + const size_t stripe_size_in_words = num_cards_in_stripe * _card_size_in_words; + const size_t slice_size_in_words = stripe_size_in_words * n_stripes; + + HeapWord* cur_stripe_addr = sp->bottom() + stripe_index * stripe_size_in_words; - // If there are not objects starting within the chunk, skip it. - if (!start_array->object_starts_in_range(slice_start, slice_end)) { + for (/* empty */; cur_stripe_addr < space_top; cur_stripe_addr += slice_size_in_words) { + // exclusive + HeapWord* const cur_stripe_end_addr = MIN2(cur_stripe_addr + stripe_size_in_words, + space_top); + + // Process a stripe iff it contains any obj-start + if (!start_array->object_starts_in_range(cur_stripe_addr, cur_stripe_end_addr)) { continue; } - // Update our beginning addr - HeapWord* first_object = start_array->object_start(slice_start); - debug_only(oop* first_object_within_slice = (oop*) first_object;) - if (first_object < slice_start) { - last_scanned = (oop*)(first_object + cast_to_oop(first_object)->size()); - debug_only(first_object_within_slice = last_scanned;) - worker_start_card = byte_for(last_scanned); + + // Constraints: + // 1. range of cards checked for being dirty or clean: [iter_limit_l, iter_limit_r) + // 2. range of cards can be cleared: [clear_limit_l, clear_limit_r) + // 3. range of objs (obj-start) can be scanned: [first_obj_addr, cur_stripe_end_addr) + + CardValue* iter_limit_l; + CardValue* iter_limit_r; + CardValue* clear_limit_l; + CardValue* clear_limit_r; + + // Identify left ends and the first obj-start inside this stripe. + HeapWord* first_obj_addr = start_array->object_start(cur_stripe_addr); + if (first_obj_addr < cur_stripe_addr) { + // this obj belongs to previous stripe; can't clear any cards it occupies + first_obj_addr += cast_to_oop(first_obj_addr)->size(); + clear_limit_l = byte_for(first_obj_addr - 1) + 1; + iter_limit_l = byte_for(first_obj_addr); + } else { + assert(first_obj_addr == cur_stripe_addr, "inv"); + iter_limit_l = clear_limit_l = byte_for(cur_stripe_addr); } - // Update the ending addr - if (slice_end < (HeapWord*)sp_top) { - // The subtraction is important! An object may start precisely at slice_end. - HeapWord* last_object = start_array->object_start(slice_end - 1); - slice_end = last_object + cast_to_oop(last_object)->size(); - // worker_end_card is exclusive, so bump it one past the end of last_object's - // covered span. - worker_end_card = byte_for(slice_end) + 1; - - if (worker_end_card > end_card) - worker_end_card = end_card; + assert(cur_stripe_addr <= first_obj_addr, "inside this stripe"); + assert(first_obj_addr <= cur_stripe_end_addr, "can be empty"); + + { + // Identify right ends. + HeapWord* obj_addr = start_array->object_start(cur_stripe_end_addr - 1); + HeapWord* obj_end_addr = obj_addr + cast_to_oop(obj_addr)->size(); + assert(obj_end_addr >= cur_stripe_end_addr, "inv"); + clear_limit_r = byte_for(obj_end_addr); + iter_limit_r = byte_for(obj_end_addr - 1) + 1; } - assert(slice_end <= (HeapWord*)sp_top, "Last object in slice crosses space boundary"); - assert(is_valid_card_address(worker_start_card), "Invalid worker start card"); - assert(is_valid_card_address(worker_end_card), "Invalid worker end card"); - // Note that worker_start_card >= worker_end_card is legal, and happens when - // an object spans an entire slice. - assert(worker_start_card <= end_card, "worker start card beyond end card"); - assert(worker_end_card <= end_card, "worker end card beyond end card"); - - CardValue* current_card = worker_start_card; - while (current_card < worker_end_card) { - // Find an unclean card. - while (current_card < worker_end_card && card_is_clean(*current_card)) { - current_card++; + assert(iter_limit_l <= clear_limit_l && + clear_limit_r <= iter_limit_r, "clear cards only if we iterate over them"); + + // Process dirty chunks, i.e. consecutive dirty cards [dirty_l, dirty_r), + // chunk by chunk inside [iter_limit_l, iter_limit_r). + CardValue* dirty_l; + CardValue* dirty_r; + + for (CardValue* cur_card = iter_limit_l; cur_card < iter_limit_r; cur_card = dirty_r + 1) { + dirty_l = find_first_dirty_card(cur_card, iter_limit_r); + dirty_r = find_first_clean_card(start_array, dirty_l, iter_limit_r); + assert(dirty_l <= dirty_r, "inv"); + + // empty + if (dirty_l == dirty_r) { + assert(dirty_r == iter_limit_r, "no more dirty cards in this stripe"); + break; } - CardValue* first_unclean_card = current_card; - - // Find the end of a run of contiguous unclean cards - while (current_card < worker_end_card && !card_is_clean(*current_card)) { - while (current_card < worker_end_card && !card_is_clean(*current_card)) { - current_card++; - } - - if (current_card < worker_end_card) { - // Some objects may be large enough to span several cards. If such - // an object has more than one dirty card, separated by a clean card, - // we will attempt to scan it twice. The test against "last_scanned" - // prevents the redundant object scan, but it does not prevent newly - // marked cards from being cleaned. - HeapWord* last_object_in_dirty_region = start_array->object_start(addr_for(current_card)-1); - size_t size_of_last_object = cast_to_oop(last_object_in_dirty_region)->size(); - HeapWord* end_of_last_object = last_object_in_dirty_region + size_of_last_object; - CardValue* ending_card_of_last_object = byte_for(end_of_last_object); - assert(ending_card_of_last_object <= worker_end_card, "ending_card_of_last_object is greater than worker_end_card"); - if (ending_card_of_last_object > current_card) { - // This means the object spans the next complete card. - // We need to bump the current_card to ending_card_of_last_object - current_card = ending_card_of_last_object; - } - } + + assert(*dirty_l != clean_card, "inv"); + assert(*dirty_r == clean_card || dirty_r >= clear_limit_r, + "clean card or belonging to next stripe"); + + // Process this non-empty dirty chunk in two steps: + { + // 1. Clear card in [dirty_l, dirty_r) subject to [clear_limit_l, clear_limit_r) constraint + clear_cards(MAX2(dirty_l, clear_limit_l), + MIN2(dirty_r, clear_limit_r)); } - CardValue* following_clean_card = current_card; - - if (first_unclean_card < worker_end_card) { - oop* p = (oop*) start_array->object_start(addr_for(first_unclean_card)); - assert((HeapWord*)p <= addr_for(first_unclean_card), "checking"); - // "p" should always be >= "last_scanned" because newly GC dirtied - // cards are no longer scanned again (see comment at end - // of loop on the increment of "current_card"). Test that - // hypothesis before removing this code. - // If this code is removed, deal with the first time through - // the loop when the last_scanned is the object starting in - // the previous slice. - assert((p >= last_scanned) || - (last_scanned == first_object_within_slice), - "Should no longer be possible"); - if (p < last_scanned) { - // Avoid scanning more than once; this can happen because - // newgen cards set by GC may a different set than the - // originally dirty set - p = last_scanned; - } - oop* to = (oop*)addr_for(following_clean_card); - - // Test slice_end first! - if ((HeapWord*)to > slice_end) { - to = (oop*)slice_end; - } else if (to > sp_top) { - to = sp_top; - } - - // we know which cards to scan, now clear them - if (first_unclean_card <= worker_start_card+1) - first_unclean_card = worker_start_card+1; - if (following_clean_card >= worker_end_card-1) - following_clean_card = worker_end_card-1; - - while (first_unclean_card < following_clean_card) { - *first_unclean_card++ = clean_card; - } - - const int interval = PrefetchScanIntervalInBytes; - // scan all objects in the range - if (interval != 0) { - while (p < to) { - Prefetch::write(p, interval); - oop m = cast_to_oop(p); - assert(oopDesc::is_oop_or_null(m), "Expected an oop or NULL for header field at " PTR_FORMAT, p2i(m)); - pm->push_contents(m); - p += m->size(); - } - pm->drain_stacks_cond_depth(); - } else { - while (p < to) { - oop m = cast_to_oop(p); - assert(oopDesc::is_oop_or_null(m), "Expected an oop or NULL for header field at " PTR_FORMAT, p2i(m)); - pm->push_contents(m); - p += m->size(); - } - pm->drain_stacks_cond_depth(); - } - last_scanned = p; + + { + // 2. Scan objs in [dirty_l, dirty_r) subject to [first_obj_addr, cur_stripe_end_addr) constraint + HeapWord* obj_l = MAX2(start_array->object_start(addr_for(dirty_l)), + first_obj_addr); + + HeapWord* obj_r = MIN2(addr_for(dirty_r), + cur_stripe_end_addr); + + scan_objects_in_range(pm, obj_l, obj_r); } - // "current_card" is still the "following_clean_card" or - // the current_card is >= the worker_end_card so the - // loop will not execute again. - assert((current_card == following_clean_card) || - (current_card >= worker_end_card), - "current_card should only be incremented if it still equals " - "following_clean_card"); - // Increment current_card so that it is not processed again. - // It may now be dirty because a old-to-young pointer was - // found on it an updated. If it is now dirty, it cannot be - // be safely cleaned in the next iteration. - current_card++; } } } @@ -422,284 +400,6 @@ bool PSCardTable::addr_is_marked_precise(void *addr) { return false; } -// Assumes that only the base or the end changes. This allows indentification -// of the region that is being resized. The -// CardTable::resize_covered_region() is used for the normal case -// where the covered regions are growing or shrinking at the high end. -// The method resize_covered_region_by_end() is analogous to -// CardTable::resize_covered_region() but -// for regions that grow or shrink at the low end. -void PSCardTable::resize_covered_region(MemRegion new_region) { - for (int i = 0; i < _cur_covered_regions; i++) { - if (_covered[i].start() == new_region.start()) { - // Found a covered region with the same start as the - // new region. The region is growing or shrinking - // from the start of the region. - resize_covered_region_by_start(new_region); - return; - } - if (_covered[i].start() > new_region.start()) { - break; - } - } - - int changed_region = -1; - for (int j = 0; j < _cur_covered_regions; j++) { - if (_covered[j].end() == new_region.end()) { - changed_region = j; - // This is a case where the covered region is growing or shrinking - // at the start of the region. - assert(changed_region != -1, "Don't expect to add a covered region"); - assert(_covered[changed_region].byte_size() != new_region.byte_size(), - "The sizes should be different here"); - resize_covered_region_by_end(changed_region, new_region); - return; - } - } - // This should only be a new covered region (where no existing - // covered region matches at the start or the end). - assert(_cur_covered_regions < _max_covered_regions, - "An existing region should have been found"); - resize_covered_region_by_start(new_region); -} - -void PSCardTable::resize_covered_region_by_start(MemRegion new_region) { - CardTable::resize_covered_region(new_region); - debug_only(verify_guard();) -} - -void PSCardTable::resize_covered_region_by_end(int changed_region, - MemRegion new_region) { - assert(SafepointSynchronize::is_at_safepoint(), - "Only expect an expansion at the low end at a GC"); - debug_only(verify_guard();) -#ifdef ASSERT - for (int k = 0; k < _cur_covered_regions; k++) { - if (_covered[k].end() == new_region.end()) { - assert(changed_region == k, "Changed region is incorrect"); - break; - } - } -#endif - - // Commit new or uncommit old pages, if necessary. - if (resize_commit_uncommit(changed_region, new_region)) { - // Set the new start of the committed region - resize_update_committed_table(changed_region, new_region); - } - - // Update card table entries - resize_update_card_table_entries(changed_region, new_region); - - // Update the covered region - resize_update_covered_table(changed_region, new_region); - - int ind = changed_region; - log_trace(gc, barrier)("CardTable::resize_covered_region: "); - log_trace(gc, barrier)(" _covered[%d].start(): " INTPTR_FORMAT " _covered[%d].last(): " INTPTR_FORMAT, - ind, p2i(_covered[ind].start()), ind, p2i(_covered[ind].last())); - log_trace(gc, barrier)(" _committed[%d].start(): " INTPTR_FORMAT " _committed[%d].last(): " INTPTR_FORMAT, - ind, p2i(_committed[ind].start()), ind, p2i(_committed[ind].last())); - log_trace(gc, barrier)(" byte_for(start): " INTPTR_FORMAT " byte_for(last): " INTPTR_FORMAT, - p2i(byte_for(_covered[ind].start())), p2i(byte_for(_covered[ind].last()))); - log_trace(gc, barrier)(" addr_for(start): " INTPTR_FORMAT " addr_for(last): " INTPTR_FORMAT, - p2i(addr_for((CardValue*) _committed[ind].start())), p2i(addr_for((CardValue*) _committed[ind].last()))); - - debug_only(verify_guard();) -} - -bool PSCardTable::resize_commit_uncommit(int changed_region, - MemRegion new_region) { - bool result = false; - // Commit new or uncommit old pages, if necessary. - MemRegion cur_committed = _committed[changed_region]; - assert(_covered[changed_region].end() == new_region.end(), - "The ends of the regions are expected to match"); - // Extend the start of this _committed region to - // to cover the start of any previous _committed region. - // This forms overlapping regions, but never interior regions. - HeapWord* min_prev_start = lowest_prev_committed_start(changed_region); - if (min_prev_start < cur_committed.start()) { - // Only really need to set start of "cur_committed" to - // the new start (min_prev_start) but assertion checking code - // below use cur_committed.end() so make it correct. - MemRegion new_committed = - MemRegion(min_prev_start, cur_committed.end()); - cur_committed = new_committed; - } -#ifdef ASSERT - ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); - assert(cur_committed.start() == align_up(cur_committed.start(), os::vm_page_size()), - "Starts should have proper alignment"); -#endif - - CardValue* new_start = byte_for(new_region.start()); - // Round down because this is for the start address - HeapWord* new_start_aligned = align_down((HeapWord*)new_start, os::vm_page_size()); - // The guard page is always committed and should not be committed over. - // This method is used in cases where the generation is growing toward - // lower addresses but the guard region is still at the end of the - // card table. That still makes sense when looking for writes - // off the end of the card table. - if (new_start_aligned < cur_committed.start()) { - // Expand the committed region - // - // Case A - // |+ guard +| - // |+ cur committed +++++++++| - // |+ new committed +++++++++++++++++| - // - // Case B - // |+ guard +| - // |+ cur committed +| - // |+ new committed +++++++| - // - // These are not expected because the calculation of the - // cur committed region and the new committed region - // share the same end for the covered region. - // Case C - // |+ guard +| - // |+ cur committed +| - // |+ new committed +++++++++++++++++| - // Case D - // |+ guard +| - // |+ cur committed +++++++++++| - // |+ new committed +++++++| - - HeapWord* new_end_for_commit = - MIN2(cur_committed.end(), _guard_region.start()); - if(new_start_aligned < new_end_for_commit) { - MemRegion new_committed = - MemRegion(new_start_aligned, new_end_for_commit); - os::commit_memory_or_exit((char*)new_committed.start(), - new_committed.byte_size(), !ExecMem, - "card table expansion"); - } - result = true; - } else if (new_start_aligned > cur_committed.start()) { - // Shrink the committed region -#if 0 // uncommitting space is currently unsafe because of the interactions - // of growing and shrinking regions. One region A can uncommit space - // that it owns but which is being used by another region B (maybe). - // Region B has not committed the space because it was already - // committed by region A. - MemRegion uncommit_region = committed_unique_to_self(changed_region, - MemRegion(cur_committed.start(), new_start_aligned)); - if (!uncommit_region.is_empty()) { - if (!os::uncommit_memory((char*)uncommit_region.start(), - uncommit_region.byte_size())) { - // If the uncommit fails, ignore it. Let the - // committed table resizing go even though the committed - // table will over state the committed space. - } - } -#else - assert(!result, "Should be false with current workaround"); -#endif - } - assert(_committed[changed_region].end() == cur_committed.end(), - "end should not change"); - return result; -} - -void PSCardTable::resize_update_committed_table(int changed_region, - MemRegion new_region) { - - CardValue* new_start = byte_for(new_region.start()); - // Set the new start of the committed region - HeapWord* new_start_aligned = align_down((HeapWord*)new_start, os::vm_page_size()); - MemRegion new_committed = MemRegion(new_start_aligned, - _committed[changed_region].end()); - _committed[changed_region] = new_committed; - _committed[changed_region].set_start(new_start_aligned); -} - -void PSCardTable::resize_update_card_table_entries(int changed_region, - MemRegion new_region) { - debug_only(verify_guard();) - MemRegion original_covered = _covered[changed_region]; - // Initialize the card entries. Only consider the - // region covered by the card table (_whole_heap) - CardValue* entry; - if (new_region.start() < _whole_heap.start()) { - entry = byte_for(_whole_heap.start()); - } else { - entry = byte_for(new_region.start()); - } - CardValue* end = byte_for(original_covered.start()); - // If _whole_heap starts at the original covered regions start, - // this loop will not execute. - while (entry < end) { *entry++ = clean_card; } -} - -void PSCardTable::resize_update_covered_table(int changed_region, - MemRegion new_region) { - // Update the covered region - _covered[changed_region].set_start(new_region.start()); - _covered[changed_region].set_word_size(new_region.word_size()); - - // reorder regions. There should only be at most 1 out - // of order. - for (int i = _cur_covered_regions-1 ; i > 0; i--) { - if (_covered[i].start() < _covered[i-1].start()) { - MemRegion covered_mr = _covered[i-1]; - _covered[i-1] = _covered[i]; - _covered[i] = covered_mr; - MemRegion committed_mr = _committed[i-1]; - _committed[i-1] = _committed[i]; - _committed[i] = committed_mr; - break; - } - } -#ifdef ASSERT - for (int m = 0; m < _cur_covered_regions-1; m++) { - assert(_covered[m].start() <= _covered[m+1].start(), - "Covered regions out of order"); - assert(_committed[m].start() <= _committed[m+1].start(), - "Committed regions out of order"); - } -#endif -} - -// Returns the start of any committed region that is lower than -// the target committed region (index ind) and that intersects the -// target region. If none, return start of target region. -// -// ------------- -// | | -// ------------- -// ------------ -// | target | -// ------------ -// ------------- -// | | -// ------------- -// ^ returns this -// -// ------------- -// | | -// ------------- -// ------------ -// | target | -// ------------ -// ------------- -// | | -// ------------- -// ^ returns this - -HeapWord* PSCardTable::lowest_prev_committed_start(int ind) const { - assert(_cur_covered_regions >= 0, "Expecting at least on region"); - HeapWord* min_start = _committed[ind].start(); - for (int j = 0; j < ind; j++) { - HeapWord* this_start = _committed[j].start(); - if ((this_start < min_start) && - !(_committed[j].intersection(_committed[ind])).is_empty()) { - min_start = this_start; - } - } - return min_start; -} - bool PSCardTable::is_in_young(oop obj) const { return ParallelScavengeHeap::heap()->is_in_young(obj); } diff --git a/src/hotspot/share/gc/parallel/psCardTable.hpp b/src/hotspot/share/gc/parallel/psCardTable.hpp index d912c6567412503e1c08ced94824b24d4b41c401..eb8f3ddbb2b3eba15d5a3686dba19a35b9888b54 100644 --- a/src/hotspot/share/gc/parallel/psCardTable.hpp +++ b/src/hotspot/share/gc/parallel/psCardTable.hpp @@ -34,14 +34,6 @@ class PSPromotionManager; class PSCardTable: public CardTable { private: - // Support methods for resizing the card table. - // resize_commit_uncommit() returns true if the pages were committed or - // uncommitted - bool resize_commit_uncommit(int changed_region, MemRegion new_region); - void resize_update_card_table_entries(int changed_region, - MemRegion new_region); - void resize_update_committed_table(int changed_region, MemRegion new_region); - void resize_update_covered_table(int changed_region, MemRegion new_region); void verify_all_young_refs_precise_helper(MemRegion mr); @@ -50,6 +42,19 @@ class PSCardTable: public CardTable { verify_card = CT_MR_BS_last_reserved + 5 }; + CardValue* find_first_dirty_card(CardValue* const start_card, + CardValue* const end_card); + + CardValue* find_first_clean_card(ObjectStartArray* start_array, + CardValue* const start_card, + CardValue* const end_card); + + void clear_cards(CardValue* const start, CardValue* const end); + + void scan_objects_in_range(PSPromotionManager* pm, + HeapWord* start, + HeapWord* end); + public: PSCardTable(MemRegion whole_heap) : CardTable(whole_heap) {} @@ -61,8 +66,8 @@ class PSCardTable: public CardTable { MutableSpace* sp, HeapWord* space_top, PSPromotionManager* pm, - uint stripe_number, - uint stripe_total); + uint stripe_index, + uint n_stripes); bool addr_is_marked_imprecise(void *addr); bool addr_is_marked_precise(void *addr); @@ -84,19 +89,6 @@ class PSCardTable: public CardTable { // ReduceInitialCardMarks support bool is_in_young(oop obj) const; - // Adaptive size policy support - // Allows adjustment of the base and size of the covered regions - void resize_covered_region(MemRegion new_region); - // Finds the covered region to resize based on the start address - // of the covered regions. - void resize_covered_region_by_start(MemRegion new_region); - // Finds the covered region to resize based on the end address - // of the covered regions. - void resize_covered_region_by_end(int changed_region, MemRegion new_region); - // Finds the lowest start address of a covered region that is - // previous (i.e., lower index) to the covered region with index "ind". - HeapWord* lowest_prev_committed_start(int ind) const; - #ifdef ASSERT bool is_valid_card_address(CardValue* addr) { return (addr >= _byte_map) && (addr < _byte_map + _byte_map_size); diff --git a/src/hotspot/share/gc/parallel/psClosure.inline.hpp b/src/hotspot/share/gc/parallel/psClosure.inline.hpp index cd78583bb80c74e0347423976bd73013d7f18d21..3499b179f46688da825d16af50b85eb73c613042 100644 --- a/src/hotspot/share/gc/parallel/psClosure.inline.hpp +++ b/src/hotspot/share/gc/parallel/psClosure.inline.hpp @@ -60,9 +60,12 @@ private: PSPromotionManager* _promotion_manager; template void do_oop_work(T *p) { - if (PSScavenge::should_scavenge(p)) { - // We never card mark roots, maybe call a func without test? - _promotion_manager->copy_and_push_safe_barrier(p); + assert(!ParallelScavengeHeap::heap()->is_in_reserved(p), "roots should be outside of heap"); + oop o = RawAccess<>::oop_load(p); + if (PSScavenge::is_obj_in_young(o)) { + assert(!PSScavenge::is_obj_in_to_space(o), "Revisiting roots?"); + oop new_obj = _promotion_manager->copy_to_survivor_space(o); + RawAccess::oop_store(p, new_obj); } } public: diff --git a/src/hotspot/share/gc/parallel/psCompactionManager.cpp b/src/hotspot/share/gc/parallel/psCompactionManager.cpp index 0a71ec80e3bd5fc5ed035649b179597f1ef67a40..dc68d999b271fd07cf77f3166e8b3b42b59ecfd8 100644 --- a/src/hotspot/share/gc/parallel/psCompactionManager.cpp +++ b/src/hotspot/share/gc/parallel/psCompactionManager.cpp @@ -70,7 +70,7 @@ void ParCompactionManager::initialize(ParMarkBitMap* mbm) { uint parallel_gc_threads = ParallelScavengeHeap::heap()->workers().max_workers(); assert(_manager_array == NULL, "Attempt to initialize twice"); - _manager_array = NEW_C_HEAP_ARRAY(ParCompactionManager*, parallel_gc_threads+1, mtGC); + _manager_array = NEW_C_HEAP_ARRAY(ParCompactionManager*, parallel_gc_threads, mtGC); _oop_task_queues = new OopTaskQueueSet(parallel_gc_threads); _objarray_task_queues = new ObjArrayTaskQueueSet(parallel_gc_threads); @@ -84,9 +84,6 @@ void ParCompactionManager::initialize(ParMarkBitMap* mbm) { region_task_queues()->register_queue(i, _manager_array[i]->region_stack()); } - // The VMThread gets its own ParCompactionManager, which is not available - // for work stealing. - _manager_array[parallel_gc_threads] = new ParCompactionManager(); assert(ParallelScavengeHeap::heap()->workers().max_workers() != 0, "Not initialized?"); @@ -97,14 +94,14 @@ void ParCompactionManager::initialize(ParMarkBitMap* mbm) { void ParCompactionManager::reset_all_bitmap_query_caches() { uint parallel_gc_threads = ParallelScavengeHeap::heap()->workers().max_workers(); - for (uint i=0; i<=parallel_gc_threads; i++) { + for (uint i=0; ireset_bitmap_query_cache(); } } void ParCompactionManager::flush_all_string_dedup_requests() { uint parallel_gc_threads = ParallelScavengeHeap::heap()->workers().max_workers(); - for (uint i=0; i<=parallel_gc_threads; i++) { + for (uint i=0; iflush_string_dedup_requests(); } } @@ -116,20 +113,37 @@ ParCompactionManager::gc_thread_compaction_manager(uint index) { return _manager_array[index]; } -void ParCompactionManager::follow_marking_stacks() { - do { - // Drain the overflow stack first, to allow stealing from the marking stack. - oop obj; - while (marking_stack()->pop_overflow(obj)) { +inline void ParCompactionManager::publish_and_drain_oop_tasks() { + oop obj; + while (marking_stack()->pop_overflow(obj)) { + if (!marking_stack()->try_push_to_taskqueue(obj)) { follow_contents(obj); } - while (marking_stack()->pop_local(obj)) { - follow_contents(obj); + } + while (marking_stack()->pop_local(obj)) { + follow_contents(obj); + } +} + +bool ParCompactionManager::publish_or_pop_objarray_tasks(ObjArrayTask& task) { + while (_objarray_stack.pop_overflow(task)) { + if (!_objarray_stack.try_push_to_taskqueue(task)) { + return true; } + } + return false; +} + +void ParCompactionManager::follow_marking_stacks() { + do { + // First, try to move tasks from the overflow stack into the shared buffer, so + // that other threads can steal. Otherwise process the overflow stack first. + publish_and_drain_oop_tasks(); // Process ObjArrays one at a time to avoid marking stack bloat. ObjArrayTask task; - if (_objarray_stack.pop_overflow(task) || _objarray_stack.pop_local(task)) { + if (publish_or_pop_objarray_tasks(task) || + _objarray_stack.pop_local(task)) { follow_array((objArrayOop)task.obj(), task.index()); } } while (!marking_stacks_empty()); @@ -184,14 +198,14 @@ void ParCompactionManager::remove_all_shadow_regions() { #ifdef ASSERT void ParCompactionManager::verify_all_marking_stack_empty() { uint parallel_gc_threads = ParallelGCThreads; - for (uint i = 0; i <= parallel_gc_threads; i++) { + for (uint i = 0; i < parallel_gc_threads; i++) { assert(_manager_array[i]->marking_stacks_empty(), "Marking stack should be empty"); } } void ParCompactionManager::verify_all_region_stack_empty() { uint parallel_gc_threads = ParallelGCThreads; - for (uint i = 0; i <= parallel_gc_threads; i++) { + for (uint i = 0; i < parallel_gc_threads; i++) { assert(_manager_array[i]->region_stack()->is_empty(), "Region stack should be empty"); } } diff --git a/src/hotspot/share/gc/parallel/psCompactionManager.hpp b/src/hotspot/share/gc/parallel/psCompactionManager.hpp index 2e73da920b5f0f8bc16da9b21d16cdc10e6ed5ce..18f8a459434079c353c1f40b8b4b1ce432d09738 100644 --- a/src/hotspot/share/gc/parallel/psCompactionManager.hpp +++ b/src/hotspot/share/gc/parallel/psCompactionManager.hpp @@ -97,6 +97,12 @@ class ParCompactionManager : public CHeapObj { static void initialize(ParMarkBitMap* mbm); + void publish_and_drain_oop_tasks(); + // Try to publish all contents from the objArray task queue overflow stack to + // the shared objArray stack. + // Returns true and a valid task if there has not been enough space in the shared + // objArray stack, otherwise returns false and the task is invalid. + bool publish_or_pop_objarray_tasks(ObjArrayTask& task); protected: // Array of task queues. Needed by the task terminator. static RegionTaskQueueSet* region_task_queues() { return _region_task_queues; } @@ -147,7 +153,9 @@ class ParCompactionManager : public CHeapObj { RegionTaskQueue* region_stack() { return &_region_stack; } - static ParCompactionManager* get_vmthread_cm() { return _manager_array[ParallelGCThreads]; } + // Get the compaction manager when doing evacuation work from the VM thread. + // Simply use the first compaction manager here. + static ParCompactionManager* get_vmthread_cm() { return _manager_array[0]; } ParCompactionManager(); diff --git a/src/hotspot/share/gc/parallel/psOldGen.cpp b/src/hotspot/share/gc/parallel/psOldGen.cpp index 4f689ec72518bc156cbb9e8f3051cb6b80cda26f..7599025657bf4446e765e041baa7e8497c5a9463 100644 --- a/src/hotspot/share/gc/parallel/psOldGen.cpp +++ b/src/hotspot/share/gc/parallel/psOldGen.cpp @@ -50,10 +50,6 @@ void PSOldGen::initialize(ReservedSpace rs, size_t initial_size, size_t alignmen initialize_virtual_space(rs, initial_size, alignment); initialize_work(perf_data_name, level); - // The old gen can grow to max_gen_size(). _reserve reflects only - // the current maximum that can be committed. - assert(_reserved.byte_size() <= max_gen_size(), "Consistency check"); - initialize_performance_counters(perf_data_name, level); } @@ -69,66 +65,51 @@ void PSOldGen::initialize_virtual_space(ReservedSpace rs, } void PSOldGen::initialize_work(const char* perf_data_name, int level) { - // - // Basic memory initialization - // + MemRegion const reserved_mr = reserved(); + assert(reserved_mr.byte_size() == max_gen_size(), "invariant"); - MemRegion limit_reserved((HeapWord*)virtual_space()->low_boundary(), - heap_word_size(max_gen_size())); - assert(limit_reserved.byte_size() == max_gen_size(), - "word vs bytes confusion"); - // - // Object start stuff - // - - start_array()->initialize(limit_reserved); + // Object start stuff: for all reserved memory + start_array()->initialize(reserved_mr); - _reserved = MemRegion((HeapWord*)virtual_space()->low_boundary(), - (HeapWord*)virtual_space()->high_boundary()); + // Card table stuff: for all committed memory + MemRegion committed_mr((HeapWord*)virtual_space()->low(), + (HeapWord*)virtual_space()->high()); - // - // Card table stuff - // - - MemRegion cmr((HeapWord*)virtual_space()->low(), - (HeapWord*)virtual_space()->high()); if (ZapUnusedHeapArea) { // Mangle newly committed space immediately rather than // waiting for the initialization of the space even though // mangling is related to spaces. Doing it here eliminates // the need to carry along information that a complete mangling // (bottom to end) needs to be done. - SpaceMangler::mangle_region(cmr); + SpaceMangler::mangle_region(committed_mr); } ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); PSCardTable* ct = heap->card_table(); - ct->resize_covered_region(cmr); + ct->resize_covered_region(committed_mr); // Verify that the start and end of this generation is the start of a card. // If this wasn't true, a single card could span more than one generation, // which would cause problems when we commit/uncommit memory, and when we // clear and dirty cards. - guarantee(ct->is_card_aligned(_reserved.start()), "generation must be card aligned"); - if (_reserved.end() != heap->reserved_region().end()) { - // Don't check at the very end of the heap as we'll assert that we're probing off - // the end if we try. - guarantee(ct->is_card_aligned(_reserved.end()), "generation must be card aligned"); - } + guarantee(ct->is_card_aligned(reserved_mr.start()), "generation must be card aligned"); + // Check the heap layout documented at `class ParallelScavengeHeap`. + assert(reserved_mr.end() != heap->reserved_region().end(), "invariant"); + guarantee(ct->is_card_aligned(reserved_mr.end()), "generation must be card aligned"); // // ObjectSpace stuff // _object_space = new MutableSpace(virtual_space()->alignment()); - object_space()->initialize(cmr, + object_space()->initialize(committed_mr, SpaceDecorator::Clear, SpaceDecorator::Mangle, MutableSpace::SetupPages, &ParallelScavengeHeap::heap()->workers()); // Update the start_array - start_array()->set_covered_region(cmr); + start_array()->set_covered_region(committed_mr); } void PSOldGen::initialize_performance_counters(const char* perf_data_name, int level) { @@ -152,7 +133,7 @@ size_t PSOldGen::num_iterable_blocks() const { void PSOldGen::object_iterate_block(ObjectClosure* cl, size_t block_index) { size_t block_word_size = IterateBlockSize / HeapWordSize; - assert((block_word_size % (ObjectStartArray::block_size)) == 0, + assert((block_word_size % (ObjectStartArray::card_size())) == 0, "Block size not a multiple of start_array block"); MutableSpace *space = object_space(); @@ -182,7 +163,7 @@ bool PSOldGen::expand_for_allocate(size_t word_size) { assert(word_size > 0, "allocating zero words?"); bool result = true; { - MutexLocker x(ExpandHeap_lock); + MutexLocker x(PSOldGenExpand_lock); // Avoid "expand storms" by rechecking available space after obtaining // the lock, because another thread may have already made sufficient // space available. If insufficient space available, that will remain @@ -200,7 +181,7 @@ bool PSOldGen::expand_for_allocate(size_t word_size) { } bool PSOldGen::expand(size_t bytes) { - assert_lock_strong(ExpandHeap_lock); + assert_lock_strong(PSOldGenExpand_lock); assert_locked_or_safepoint(Heap_lock); assert(bytes > 0, "precondition"); const size_t alignment = virtual_space()->alignment(); @@ -238,7 +219,7 @@ bool PSOldGen::expand(size_t bytes) { } bool PSOldGen::expand_by(size_t bytes) { - assert_lock_strong(ExpandHeap_lock); + assert_lock_strong(PSOldGenExpand_lock); assert_locked_or_safepoint(Heap_lock); assert(bytes > 0, "precondition"); bool result = virtual_space()->expand_by(bytes); @@ -274,7 +255,7 @@ bool PSOldGen::expand_by(size_t bytes) { } bool PSOldGen::expand_to_reserved() { - assert_lock_strong(ExpandHeap_lock); + assert_lock_strong(PSOldGenExpand_lock); assert_locked_or_safepoint(Heap_lock); bool result = false; @@ -287,12 +268,11 @@ bool PSOldGen::expand_to_reserved() { } void PSOldGen::shrink(size_t bytes) { - assert_lock_strong(ExpandHeap_lock); + assert_lock_strong(PSOldGenExpand_lock); assert_locked_or_safepoint(Heap_lock); size_t size = align_down(bytes, virtual_space()->alignment()); if (size > 0) { - assert_lock_strong(ExpandHeap_lock); virtual_space()->shrink_by(bytes); post_resize(); @@ -303,6 +283,15 @@ void PSOldGen::shrink(size_t bytes) { } } +void PSOldGen::complete_loaded_archive_space(MemRegion archive_space) { + HeapWord* cur = archive_space.start(); + while (cur < archive_space.end()) { + _start_array.allocate_block(cur); + size_t word_size = cast_to_oop(cur)->size(); + cur += word_size; + } +} + void PSOldGen::resize(size_t desired_free_space) { const size_t alignment = virtual_space()->alignment(); const size_t size_before = virtual_space()->committed_size(); @@ -314,7 +303,6 @@ void PSOldGen::resize(size_t desired_free_space) { // Adjust according to our min and max new_size = clamp(new_size, min_gen_size(), max_gen_size()); - assert(max_gen_size() >= reserved().byte_size(), "max new size problem?"); new_size = align_up(new_size, alignment); const size_t current_size = capacity_in_bytes(); @@ -332,11 +320,11 @@ void PSOldGen::resize(size_t desired_free_space) { } if (new_size > current_size) { size_t change_bytes = new_size - current_size; - MutexLocker x(ExpandHeap_lock); + MutexLocker x(PSOldGenExpand_lock); expand(change_bytes); } else { size_t change_bytes = current_size - new_size; - MutexLocker x(ExpandHeap_lock); + MutexLocker x(PSOldGenExpand_lock); shrink(change_bytes); } @@ -400,12 +388,11 @@ void PSOldGen::verify() { } class VerifyObjectStartArrayClosure : public ObjectClosure { - PSOldGen* _old_gen; ObjectStartArray* _start_array; public: - VerifyObjectStartArrayClosure(PSOldGen* old_gen, ObjectStartArray* start_array) : - _old_gen(old_gen), _start_array(start_array) { } + VerifyObjectStartArrayClosure(ObjectStartArray* start_array) : + _start_array(start_array) { } virtual void do_object(oop obj) { HeapWord* test_addr = cast_from_oop(obj) + 1; @@ -415,7 +402,7 @@ class VerifyObjectStartArrayClosure : public ObjectClosure { }; void PSOldGen::verify_object_start_array() { - VerifyObjectStartArrayClosure check( this, &_start_array ); + VerifyObjectStartArrayClosure check(&_start_array); object_iterate(&check); } diff --git a/src/hotspot/share/gc/parallel/psOldGen.hpp b/src/hotspot/share/gc/parallel/psOldGen.hpp index 53947a948984caffa548ba7dfb3880599dc96d5f..d5f6f90a80cce904b60982f64ccf1f1e2e3d5d94 100644 --- a/src/hotspot/share/gc/parallel/psOldGen.hpp +++ b/src/hotspot/share/gc/parallel/psOldGen.hpp @@ -34,9 +34,7 @@ class PSOldGen : public CHeapObj { friend class VMStructs; - private: - MemRegion _reserved; // Used for simple containment tests PSVirtualSpace* _virtual_space; // Controls mapping and unmapping of virtual mem ObjectStartArray _start_array; // Keeps track of where objects start in a 512b block MutableSpace* _object_space; // Where all the objects live @@ -99,16 +97,20 @@ class PSOldGen : public CHeapObj { PSOldGen(ReservedSpace rs, size_t initial_size, size_t min_size, size_t max_size, const char* perf_data_name, int level); - MemRegion reserved() const { return _reserved; } + MemRegion reserved() const { + return MemRegion((HeapWord*)(_virtual_space->low_boundary()), + (HeapWord*)(_virtual_space->high_boundary())); + } + size_t max_gen_size() const { return _max_gen_size; } size_t min_gen_size() const { return _min_gen_size; } bool is_in(const void* p) const { - return _virtual_space->contains((void *)p); + return _virtual_space->is_in_committed((void *)p); } bool is_in_reserved(const void* p) const { - return reserved().contains(p); + return _virtual_space->is_in_reserved(p); } MutableSpace* object_space() const { return _object_space; } @@ -131,6 +133,8 @@ class PSOldGen : public CHeapObj { return virtual_space()->uncommitted_size() == 0; } + void complete_loaded_archive_space(MemRegion archive_space); + // Calculating new sizes void resize(size_t desired_free_space); diff --git a/src/hotspot/share/gc/parallel/psParallelCompact.cpp b/src/hotspot/share/gc/parallel/psParallelCompact.cpp index 212bd424e63ce0e07347d3dbf1895fb771e39ac1..22b5bc41f343fd2d3bce7e560323cb401c7b9286 100644 --- a/src/hotspot/share/gc/parallel/psParallelCompact.cpp +++ b/src/hotspot/share/gc/parallel/psParallelCompact.cpp @@ -845,41 +845,15 @@ PSParallelCompact::IsAliveClosure PSParallelCompact::_is_alive_closure; bool PSParallelCompact::IsAliveClosure::do_object_b(oop p) { return mark_bitmap()->is_marked(p); } -class PCReferenceProcessor: public ReferenceProcessor { -public: - PCReferenceProcessor( - BoolObjectClosure* is_subject_to_discovery, - BoolObjectClosure* is_alive_non_header) : - ReferenceProcessor(is_subject_to_discovery, - ParallelGCThreads, // mt processing degree - true, // mt discovery - ParallelGCThreads, // mt discovery degree - true, // atomic_discovery - is_alive_non_header) { - } - - template bool discover(oop obj, ReferenceType type) { - T* referent_addr = (T*) java_lang_ref_Reference::referent_addr_raw(obj); - T heap_oop = RawAccess<>::oop_load(referent_addr); - oop referent = CompressedOops::decode_not_null(heap_oop); - return PSParallelCompact::mark_bitmap()->is_unmarked(referent) - && ReferenceProcessor::discover_reference(obj, type); - } - virtual bool discover_reference(oop obj, ReferenceType type) { - if (UseCompressedOops) { - return discover(obj, type); - } else { - return discover(obj, type); - } - } -}; - void PSParallelCompact::post_initialize() { ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); _span_based_discoverer.set_span(heap->reserved_region()); _ref_processor = - new PCReferenceProcessor(&_span_based_discoverer, - &_is_alive_closure); // non-header is alive closure + new ReferenceProcessor(&_span_based_discoverer, + ParallelGCThreads, // mt processing degree + ParallelGCThreads, // mt discovery degree + false, // concurrent_discovery + &_is_alive_closure); // non-header is alive closure _counters = new CollectorCounters("Parallel full collection pauses", 1); @@ -1042,9 +1016,9 @@ void PSParallelCompact::post_compact() PSCardTable* ct = heap->card_table(); MemRegion old_mr = heap->old_gen()->reserved(); if (young_gen_empty) { - ct->clear(MemRegion(old_mr.start(), old_mr.end())); + ct->clear(old_mr); } else { - ct->invalidate(MemRegion(old_mr.start(), old_mr.end())); + ct->invalidate(old_mr); } // Delete metaspaces for unloaded class loaders and clean up loader_data graph @@ -1596,8 +1570,7 @@ void PSParallelCompact::summary_phase_msg(SpaceId dst_space_id, } #endif // #ifndef PRODUCT -void PSParallelCompact::summary_phase(ParCompactionManager* cm, - bool maximum_compaction) +void PSParallelCompact::summary_phase(bool maximum_compaction) { GCTraceTime(Info, gc, phases) tm("Summary Phase", &_gc_timer); @@ -1736,10 +1709,6 @@ bool PSParallelCompact::invoke_no_policy(bool maximum_heap_compaction) { _gc_timer.register_gc_start(); _gc_tracer.report_gc_start(heap->gc_cause(), _gc_timer.gc_start()); - TimeStamp marking_start; - TimeStamp compaction_start; - TimeStamp collection_exit; - GCCause::Cause gc_cause = heap->gc_cause(); PSYoungGen* young_gen = heap->young_gen(); PSOldGen* old_gen = heap->old_gen(); @@ -1761,9 +1730,6 @@ bool PSParallelCompact::invoke_no_policy(bool maximum_heap_compaction) { const PreGenGCValues pre_gc_values = heap->get_pre_gc_values(); - // Get the compaction manager reserved for the VM thread. - ParCompactionManager* const vmthread_cm = ParCompactionManager::get_vmthread_cm(); - { const uint active_workers = WorkerPolicy::calc_active_workers(ParallelScavengeHeap::heap()->workers().max_workers(), @@ -1792,12 +1758,11 @@ bool PSParallelCompact::invoke_no_policy(bool maximum_heap_compaction) { ref_processor()->start_discovery(maximum_heap_compaction); - marking_start.update(); - marking_phase(vmthread_cm, &_gc_tracer); + marking_phase(&_gc_tracer); bool max_on_system_gc = UseMaximumCompactionOnSystemGC && GCCause::is_user_requested_gc(gc_cause); - summary_phase(vmthread_cm, maximum_heap_compaction || max_on_system_gc); + summary_phase(maximum_heap_compaction || max_on_system_gc); #if COMPILER2_OR_JVMCI assert(DerivedPointerTable::is_active(), "Sanity"); @@ -1808,7 +1773,6 @@ bool PSParallelCompact::invoke_no_policy(bool maximum_heap_compaction) { // needed by the compaction for filling holes in the dense prefix. adjust_roots(); - compaction_start.update(); compact(); ParCompactionManager::verify_all_region_stack_empty(); @@ -1923,15 +1887,9 @@ bool PSParallelCompact::invoke_no_policy(bool maximum_heap_compaction) { old_gen->object_space()->check_mangled_unused_area_complete(); } - collection_exit.update(); - heap->print_heap_after_gc(); heap->trace_heap_after_gc(&_gc_tracer); - log_debug(gc, task, time)("VM-Thread " JLONG_FORMAT " " JLONG_FORMAT " " JLONG_FORMAT, - marking_start.ticks(), compaction_start.ticks(), - collection_exit.ticks()); - AdaptiveSizePolicyOutput::print(size_policy, heap->total_collections()); _gc_timer.register_gc_end(); @@ -1965,60 +1923,27 @@ public: } }; -static void mark_from_roots_work(ParallelRootType::Value root_type, uint worker_id) { - assert(ParallelScavengeHeap::heap()->is_gc_active(), "called outside gc"); - - ParCompactionManager* cm = - ParCompactionManager::gc_thread_compaction_manager(worker_id); - PCMarkAndPushClosure mark_and_push_closure(cm); - - switch (root_type) { - case ParallelRootType::class_loader_data: - { - CLDToOopClosure cld_closure(&mark_and_push_closure, ClassLoaderData::_claim_strong); - ClassLoaderDataGraph::always_strong_cld_do(&cld_closure); - } - break; - - case ParallelRootType::code_cache: - // Do not treat nmethods as strong roots for mark/sweep, since we can unload them. - //ScavengableNMethods::scavengable_nmethods_do(CodeBlobToOopClosure(&mark_and_push_closure)); - break; - - case ParallelRootType::sentinel: - DEBUG_ONLY(default:) // DEBUG_ONLY hack will create compile error on release builds (-Wswitch) and runtime check on debug builds - fatal("Bad enumeration value: %u", root_type); - break; - } - - // Do the real work - cm->follow_marking_stacks(); -} - void steal_marking_work(TaskTerminator& terminator, uint worker_id) { assert(ParallelScavengeHeap::heap()->is_gc_active(), "called outside gc"); ParCompactionManager* cm = ParCompactionManager::gc_thread_compaction_manager(worker_id); - oop obj = NULL; - ObjArrayTask task; do { - while (ParCompactionManager::steal_objarray(worker_id, task)) { + oop obj = NULL; + ObjArrayTask task; + if (ParCompactionManager::steal_objarray(worker_id, task)) { cm->follow_array((objArrayOop)task.obj(), task.index()); - cm->follow_marking_stacks(); - } - while (ParCompactionManager::steal(worker_id, obj)) { + } else if (ParCompactionManager::steal(worker_id, obj)) { cm->follow_contents(obj); - cm->follow_marking_stacks(); } + cm->follow_marking_stacks(); } while (!terminator.offer_termination()); } class MarkFromRootsTask : public WorkerTask { StrongRootsScope _strong_roots_scope; // needed for Threads::possibly_parallel_threads_do OopStorageSetStrongParState _oop_storage_set_par_state; - SequentialSubTasksDone _subtasks; TaskTerminator _terminator; uint _active_workers; @@ -2026,14 +1951,19 @@ public: MarkFromRootsTask(uint active_workers) : WorkerTask("MarkFromRootsTask"), _strong_roots_scope(active_workers), - _subtasks(ParallelRootType::sentinel), _terminator(active_workers, ParCompactionManager::oop_task_queues()), - _active_workers(active_workers) { - } + _active_workers(active_workers) {} virtual void work(uint worker_id) { - for (uint task = 0; _subtasks.try_claim_task(task); /*empty*/ ) { - mark_from_roots_work(static_cast(task), worker_id); + ParCompactionManager* cm = ParCompactionManager::gc_thread_compaction_manager(worker_id); + PCMarkAndPushClosure mark_and_push_closure(cm); + + { + CLDToOopClosure cld_closure(&mark_and_push_closure, ClassLoaderData::_claim_strong); + ClassLoaderDataGraph::always_strong_cld_do(&cld_closure); + + // Do the real work + cm->follow_marking_stacks(); } PCAddThreadRootsMarkingTaskClosure closure(worker_id); @@ -2041,9 +1971,7 @@ public: // Mark from OopStorages { - ParCompactionManager* cm = ParCompactionManager::gc_thread_compaction_manager(worker_id); - PCMarkAndPushClosure closure(cm); - _oop_storage_set_par_state.oops_do(&closure); + _oop_storage_set_par_state.oops_do(&mark_and_push_closure); // Do the real work cm->follow_marking_stacks(); } @@ -2076,8 +2004,7 @@ public: } }; -void PSParallelCompact::marking_phase(ParCompactionManager* cm, - ParallelOldTracer *gc_tracer) { +void PSParallelCompact::marking_phase(ParallelOldTracer *gc_tracer) { // Recursively traverse all live objects and mark them GCTraceTime(Info, gc, phases) tm("Marking Phase", &_gc_timer); @@ -2136,20 +2063,11 @@ void PSParallelCompact::marking_phase(ParCompactionManager* cm, } _gc_tracer.report_object_count_after_gc(is_alive_closure()); -} - -#ifdef ASSERT -void PCAdjustPointerClosure::verify_cm(ParCompactionManager* cm) { - assert(cm != NULL, "associate ParCompactionManage should not be NULL"); - auto vmthread_cm = ParCompactionManager::get_vmthread_cm(); - if (Thread::current()->is_VM_thread()) { - assert(cm == vmthread_cm, "VM threads should use ParCompactionManager from get_vmthread_cm()"); - } else { - assert(Thread::current()->is_Worker_thread(), "Must be a GC thread"); - assert(cm != vmthread_cm, "GC threads should use ParCompactionManager from gc_thread_compaction_manager()"); - } -} +#if TASKQUEUE_STATS + ParCompactionManager::oop_task_queues()->print_and_reset_taskqueue_stats("Oop Queue"); + ParCompactionManager::_objarray_task_queues->print_and_reset_taskqueue_stats("ObjArrayOop Queue"); #endif +} class PSAdjustTask final : public WorkerTask { SubTasksDone _sub_tasks; @@ -2541,9 +2459,7 @@ void PSParallelCompact::compact() { { GCTraceTime(Trace, gc, phases) tm("Deferred Updates", &_gc_timer); - // Update the deferred objects, if any. In principle, any compaction - // manager can be used. However, since the current thread is VM thread, we - // use the rightful one to keep the verification logic happy. + // Update the deferred objects, if any. ParCompactionManager* cm = ParCompactionManager::get_vmthread_cm(); for (unsigned int id = old_space_id; id < last_space_id; ++id) { update_deferred_objects(cm, SpaceId(id)); diff --git a/src/hotspot/share/gc/parallel/psParallelCompact.hpp b/src/hotspot/share/gc/parallel/psParallelCompact.hpp index 0b8eb6b01167513baf942aabe5e58a13b3915df8..77a9d44f9b6b44045c3cf41814c4a55369d03a5c 100644 --- a/src/hotspot/share/gc/parallel/psParallelCompact.hpp +++ b/src/hotspot/share/gc/parallel/psParallelCompact.hpp @@ -1062,8 +1062,7 @@ class PSParallelCompact : AllStatic { static void post_compact(); // Mark live objects - static void marking_phase(ParCompactionManager* cm, - ParallelOldTracer *gc_tracer); + static void marking_phase(ParallelOldTracer *gc_tracer); // Compute the dense prefix for the designated space. This is an experimental // implementation currently not used in production. @@ -1123,7 +1122,7 @@ class PSParallelCompact : AllStatic { static void summarize_spaces_quick(); static void summarize_space(SpaceId id, bool maximum_compaction); - static void summary_phase(ParCompactionManager* cm, bool maximum_compaction); + static void summary_phase(bool maximum_compaction); // Adjust addresses in roots. Does not adjust addresses in heap. static void adjust_roots(); diff --git a/src/hotspot/share/gc/parallel/psParallelCompact.inline.hpp b/src/hotspot/share/gc/parallel/psParallelCompact.inline.hpp index 001f55c076a9f72ee5fc0109f5c4ed9f2a176600..48c5a98fd1a6447e0a8196876a3231f6872f248b 100644 --- a/src/hotspot/share/gc/parallel/psParallelCompact.inline.hpp +++ b/src/hotspot/share/gc/parallel/psParallelCompact.inline.hpp @@ -126,9 +126,7 @@ inline void PSParallelCompact::adjust_pointer(T* p, ParCompactionManager* cm) { class PCAdjustPointerClosure: public BasicOopIterateClosure { public: - PCAdjustPointerClosure(ParCompactionManager* cm) { - verify_cm(cm); - _cm = cm; + PCAdjustPointerClosure(ParCompactionManager* cm) : _cm(cm) { } template void do_oop_nv(T* p) { PSParallelCompact::adjust_pointer(p, _cm); } virtual void do_oop(oop* p) { do_oop_nv(p); } @@ -137,8 +135,6 @@ public: virtual ReferenceIterationMode reference_iteration_mode() { return DO_FIELDS; } private: ParCompactionManager* _cm; - - static void verify_cm(ParCompactionManager* cm) NOT_DEBUG_RETURN; }; #endif // SHARE_GC_PARALLEL_PSPARALLELCOMPACT_INLINE_HPP diff --git a/src/hotspot/share/gc/parallel/psPromotionLAB.cpp b/src/hotspot/share/gc/parallel/psPromotionLAB.cpp index 53fac0e98a58f9d70b249ca464224ff5460d602d..bab79b25a13ebc1d19c44475a50d182406b7fabe 100644 --- a/src/hotspot/share/gc/parallel/psPromotionLAB.cpp +++ b/src/hotspot/share/gc/parallel/psPromotionLAB.cpp @@ -29,8 +29,6 @@ #include "memory/universe.hpp" #include "oops/oop.inline.hpp" -size_t PSPromotionLAB::filler_header_size; - // This is the shared initialization code. It sets up the basic pointers, // and allows enough extra space for a filler object. We call a virtual // method, "lab_is_valid()" to handle the different asserts the old/young @@ -45,10 +43,6 @@ void PSPromotionLAB::initialize(MemRegion lab) { set_end(end); set_top(bottom); - // Initialize after VM starts up because header_size depends on compressed - // oops. - filler_header_size = align_object_size(typeArrayOopDesc::header_size(T_INT)); - // We can be initialized to a zero size! if (free() > 0) { if (ZapUnusedHeapArea) { @@ -56,8 +50,8 @@ void PSPromotionLAB::initialize(MemRegion lab) { } // NOTE! We need to allow space for a filler object. - assert(lab.word_size() >= filler_header_size, "lab is too small"); - end = end - filler_header_size; + assert(lab.word_size() >= CollectedHeap::min_dummy_object_size(), "lab is too small"); + end = end - CollectedHeap::min_dummy_object_size(); set_end(end); _state = needs_flush; @@ -81,20 +75,8 @@ void PSPromotionLAB::flush() { // PLAB's never allocate the last aligned_header_size // so they can always fill with an array. - HeapWord* tlab_end = end() + filler_header_size; - typeArrayOop filler_oop = (typeArrayOop) cast_to_oop(top()); - filler_oop->set_mark(markWord::prototype()); - filler_oop->set_klass(Universe::intArrayKlassObj()); - const size_t array_length = - pointer_delta(tlab_end, top()) - typeArrayOopDesc::header_size(T_INT); - assert( (array_length * (HeapWordSize/sizeof(jint))) < (size_t)max_jint, "array too big in PSPromotionLAB"); - filler_oop->set_length((int)(array_length * (HeapWordSize/sizeof(jint)))); - -#ifdef ASSERT - // Note that we actually DO NOT want to use the aligned header size! - HeapWord* elt_words = cast_from_oop(filler_oop) + typeArrayOopDesc::header_size(T_INT); - Copy::fill_to_words(elt_words, array_length, 0xDEAABABE); -#endif + HeapWord* tlab_end = end() + CollectedHeap::min_dummy_object_size(); + CollectedHeap::fill_with_object(top(), tlab_end, trueInDebug); set_bottom(NULL); set_end(NULL); @@ -103,18 +85,19 @@ void PSPromotionLAB::flush() { _state = flushed; } -bool PSPromotionLAB::unallocate_object(HeapWord* obj, size_t obj_size) { +void PSPromotionLAB::unallocate_object(HeapWord* obj, size_t obj_size) { assert(ParallelScavengeHeap::heap()->is_in(obj), "Object outside heap"); + // If the object is inside this LAB, we just bump-down the `top` pointer. + // Otherwise, we overwrite it with a filler object. if (contains(obj)) { HeapWord* object_end = obj + obj_size; assert(object_end == top(), "Not matching last allocation"); set_top(obj); - return true; + } else { + CollectedHeap::fill_with_object(obj, obj_size); } - - return false; } // Fill all remaining lab space with an unreachable object. diff --git a/src/hotspot/share/gc/parallel/psPromotionLAB.hpp b/src/hotspot/share/gc/parallel/psPromotionLAB.hpp index e51852f8a6e962f10d7fc659625e4ea1300aba9e..7e8f8857dcd4b13161b1c8de31ded479db1293a5 100644 --- a/src/hotspot/share/gc/parallel/psPromotionLAB.hpp +++ b/src/hotspot/share/gc/parallel/psPromotionLAB.hpp @@ -39,8 +39,6 @@ class ObjectStartArray; class PSPromotionLAB : public CHeapObj { protected: - static size_t filler_header_size; - enum LabState { needs_flush, flushed, @@ -74,7 +72,7 @@ class PSPromotionLAB : public CHeapObj { bool is_flushed() { return _state == flushed; } - bool unallocate_object(HeapWord* obj, size_t obj_size); + void unallocate_object(HeapWord* obj, size_t obj_size); // Returns a subregion containing all objects in this space. MemRegion used_region() { return MemRegion(bottom(), top()); } @@ -106,7 +104,6 @@ class PSOldPromotionLAB : public PSPromotionLAB { public: PSOldPromotionLAB() : _start_array(NULL) { } - PSOldPromotionLAB(ObjectStartArray* start_array) : _start_array(start_array) { } void set_start_array(ObjectStartArray* start_array) { _start_array = start_array; } diff --git a/src/hotspot/share/gc/parallel/psPromotionManager.cpp b/src/hotspot/share/gc/parallel/psPromotionManager.cpp index 7ef706aba936b3fc251dc97b4e653fdb5b0640ec..652342ae31f5e1240f91d9bdcaed2c5ef468480d 100644 --- a/src/hotspot/share/gc/parallel/psPromotionManager.cpp +++ b/src/hotspot/share/gc/parallel/psPromotionManager.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 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 @@ -54,7 +54,7 @@ void PSPromotionManager::initialize() { _old_gen = heap->old_gen(); _young_space = heap->young_gen()->to_space(); - const uint promotion_manager_num = ParallelGCThreads + 1; + const uint promotion_manager_num = ParallelGCThreads; // To prevent false sharing, we pad the PSPromotionManagers // and make sure that the first instance starts at a cache line. @@ -95,7 +95,7 @@ PSPromotionManager* PSPromotionManager::gc_thread_promotion_manager(uint index) PSPromotionManager* PSPromotionManager::vm_thread_promotion_manager() { assert(_manager_array != NULL, "Sanity"); - return &_manager_array[ParallelGCThreads]; + return &_manager_array[0]; } void PSPromotionManager::pre_scavenge() { @@ -104,7 +104,7 @@ void PSPromotionManager::pre_scavenge() { _preserved_marks_set->assert_empty(); _young_space = heap->young_gen()->to_space(); - for(uint i=0; ireset(); } } @@ -113,7 +113,7 @@ bool PSPromotionManager::post_scavenge(YoungGCTracer& gc_tracer) { bool promotion_failure_occurred = false; TASKQUEUE_STATS_ONLY(print_taskqueue_stats()); - for (uint i = 0; i < ParallelGCThreads + 1; i++) { + for (uint i = 0; i < ParallelGCThreads; i++) { PSPromotionManager* manager = manager_array(i); assert(manager->claimed_stack_depth()->is_empty(), "should be empty"); if (manager->_promotion_failed_info.has_failed()) { @@ -147,37 +147,24 @@ static const char* const pm_stats_hdr[] = { "--- ---------- ---------- ---------- ----------" }; -void -PSPromotionManager::print_taskqueue_stats() { +void PSPromotionManager::print_taskqueue_stats() { if (!log_is_enabled(Trace, gc, task, stats)) { return; } Log(gc, task, stats) log; ResourceMark rm; LogStream ls(log.trace()); - outputStream* out = &ls; - out->print_cr("== GC Tasks Stats, GC %3d", - ParallelScavengeHeap::heap()->total_collections()); - - TaskQueueStats totals; - out->print("thr "); TaskQueueStats::print_header(1, out); out->cr(); - out->print("--- "); TaskQueueStats::print_header(2, out); out->cr(); - for (uint i = 0; i < ParallelGCThreads + 1; ++i) { - TaskQueueStats& next = manager_array(i)->_claimed_stack_depth.stats; - out->print("%3d ", i); next.print(out); out->cr(); - totals += next; - } - out->print("tot "); totals.print(out); out->cr(); + + stack_array_depth()->print_taskqueue_stats(&ls, "Oop Queue"); const uint hlines = sizeof(pm_stats_hdr) / sizeof(pm_stats_hdr[0]); - for (uint i = 0; i < hlines; ++i) out->print_cr("%s", pm_stats_hdr[i]); - for (uint i = 0; i < ParallelGCThreads + 1; ++i) { - manager_array(i)->print_local_stats(out, i); + for (uint i = 0; i < hlines; ++i) ls.print_cr("%s", pm_stats_hdr[i]); + for (uint i = 0; i < ParallelGCThreads; ++i) { + manager_array(i)->print_local_stats(&ls, i); } } -void -PSPromotionManager::reset_stats() { +void PSPromotionManager::reset_stats() { claimed_stack_depth()->stats.reset(); _array_chunk_pushes = _array_chunk_steals = 0; _arrays_chunked = _array_chunks_processed = 0; @@ -193,8 +180,7 @@ PSPromotionManager::PSPromotionManager() { uint queue_size; queue_size = claimed_stack_depth()->max_elems(); - _totally_drain = (ParallelGCThreads == 1) || (GCDrainStackTargetSize == 0); - if (_totally_drain) { + if (ParallelGCThreads == 1) { _target_stack_size = 0; } else { // don't let the target stack size to be more than 1/4 of the entries @@ -216,8 +202,6 @@ void PSPromotionManager::reset() { // We need to get an assert in here to make sure the labs are always flushed. - ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); - // Do not prefill the LAB's, save heap wastage! HeapWord* lab_base = young_space()->top(); _young_lab.initialize(MemRegion(lab_base, (size_t)0)); @@ -242,13 +226,7 @@ void PSPromotionManager::restore_preserved_marks() { } void PSPromotionManager::drain_stacks_depth(bool totally_drain) { - totally_drain = totally_drain || _totally_drain; - -#ifdef ASSERT - ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); - MutableSpace* to_space = heap->young_gen()->to_space(); - MutableSpace* old_space = heap->old_gen()->object_space(); -#endif /* ASSERT */ + totally_drain = totally_drain || (_target_stack_size == 0); PSScannerTasksQueue* const tq = claimed_stack_depth(); do { @@ -360,7 +338,10 @@ oop PSPromotionManager::oop_promotion_failed(oop obj, markWord obj_mark) { push_contents(obj); - _preserved_marks->push_if_necessary(obj, obj_mark); + // Save the markWord of promotion-failed objs in _preserved_marks for later + // restoration. This way we don't have to walk the young-gen to locate + // these promotion-failed objs. + _preserved_marks->push_always(obj, obj_mark); } else { // We lost, someone else "owns" this object guarantee(obj->is_forwarded(), "Object must be forwarded if the cas failed."); diff --git a/src/hotspot/share/gc/parallel/psPromotionManager.hpp b/src/hotspot/share/gc/parallel/psPromotionManager.hpp index bd48135f1346718806ee806076e4ca9d91ba0aa0..a1d2b38db31fa17a32aa255187f21ed063f72fa4 100644 --- a/src/hotspot/share/gc/parallel/psPromotionManager.hpp +++ b/src/hotspot/share/gc/parallel/psPromotionManager.hpp @@ -83,7 +83,6 @@ class PSPromotionManager { PSScannerTasksQueue _claimed_stack_depth; - bool _totally_drain; uint _target_stack_size; uint _array_chunk_size; diff --git a/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp b/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp index f752901594908bdd2a74136902b76c0eb384ea02..64ee5f286b5317c23a361d71b2896fc30529436e 100644 --- a/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp +++ b/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp @@ -44,7 +44,7 @@ inline PSPromotionManager* PSPromotionManager::manager_array(uint index) { assert(_manager_array != NULL, "access of NULL manager_array"); - assert(index <= ParallelGCThreads, "out of range manager_array access"); + assert(index < ParallelGCThreads, "out of range manager_array access"); return &_manager_array[index]; } @@ -219,13 +219,6 @@ inline oop PSPromotionManager::copy_unmarked_to_survivor_space(oop o, HeapWord* lab_base = old_gen()->allocate(OldPLABSize); if(lab_base != NULL) { -#ifdef ASSERT - // Delay the initialization of the promotion lab (plab). - // This exposes uninitialized plabs to card table processing. - if (GCWorkerDelayMillis > 0) { - os::naked_sleep(GCWorkerDelayMillis); - } -#endif _old_lab.initialize(MemRegion(lab_base, OldPLABSize)); // Try the old lab allocation again. new_obj = cast_to_oop(_old_lab.allocate(new_obj_size)); @@ -297,39 +290,28 @@ inline oop PSPromotionManager::copy_unmarked_to_survivor_space(oop o, assert(o->is_forwarded(), "Object must be forwarded if the cas failed."); assert(o->forwardee() == forwardee, "invariant"); - // Try to deallocate the space. If it was directly allocated we cannot - // deallocate it, so we have to test. If the deallocation fails, - // overwrite with a filler object. if (new_obj_is_tenured) { - if (!_old_lab.unallocate_object(cast_from_oop(new_obj), new_obj_size)) { - CollectedHeap::fill_with_object(cast_from_oop(new_obj), new_obj_size); - } - } else if (!_young_lab.unallocate_object(cast_from_oop(new_obj), new_obj_size)) { - CollectedHeap::fill_with_object(cast_from_oop(new_obj), new_obj_size); + _old_lab.unallocate_object(cast_from_oop(new_obj), new_obj_size); + } else { + _young_lab.unallocate_object(cast_from_oop(new_obj), new_obj_size); } return forwardee; } } // Attempt to "claim" oop at p via CAS, push the new obj if successful -// This version tests the oop* to make sure it is within the heap before -// attempting marking. template inline void PSPromotionManager::copy_and_push_safe_barrier(T* p) { + assert(ParallelScavengeHeap::heap()->is_in_reserved(p), "precondition"); assert(should_scavenge(p, true), "revisiting object?"); oop o = RawAccess::oop_load(p); oop new_obj = copy_to_survivor_space(o); RawAccess::oop_store(p, new_obj); - // We cannot mark without test, as some code passes us pointers - // that are outside the heap. These pointers are either from roots - // or from metadata. - if ((!PSScavenge::is_obj_in_young((HeapWord*)p)) && - ParallelScavengeHeap::heap()->is_in_reserved(p)) { - if (PSScavenge::is_obj_in_young(new_obj)) { - PSScavenge::card_table()->inline_write_ref_field_gc(p, new_obj); - } + if (!PSScavenge::is_obj_in_young((HeapWord*)p) && + PSScavenge::is_obj_in_young(new_obj)) { + PSScavenge::card_table()->inline_write_ref_field_gc(p, new_obj); } } diff --git a/src/hotspot/share/gc/parallel/psRootType.hpp b/src/hotspot/share/gc/parallel/psRootType.hpp index 921bbfdd2b0f12b174da13ae090bd0e2023870a9..cbdc94dc9abe6fcc0b7c727497988545734d3861 100644 --- a/src/hotspot/share/gc/parallel/psRootType.hpp +++ b/src/hotspot/share/gc/parallel/psRootType.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -25,7 +25,7 @@ #ifndef SHARE_GC_PARALLEL_PSROOTTYPE_HPP #define SHARE_GC_PARALLEL_PSROOTTYPE_HPP -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" #include "utilities/macros.hpp" class ParallelRootType : public AllStatic { diff --git a/src/hotspot/share/gc/parallel/psScavenge.cpp b/src/hotspot/share/gc/parallel/psScavenge.cpp index f4a2fce76ec8b6cd950fdac02672c49bca3089a2..b6ca29adefcae194895d2b08217fb7f4a4056ac8 100644 --- a/src/hotspot/share/gc/parallel/psScavenge.cpp +++ b/src/hotspot/share/gc/parallel/psScavenge.cpp @@ -70,8 +70,6 @@ #include "services/memoryService.hpp" #include "utilities/stack.inline.hpp" -HeapWord* PSScavenge::_to_space_top_before_gc = NULL; -int PSScavenge::_consecutive_skipped_scavenges = 0; SpanSubjectToDiscoveryClosure PSScavenge::_span_based_discoverer; ReferenceProcessor* PSScavenge::_ref_processor = NULL; PSCardTable* PSScavenge::_card_table = NULL; @@ -285,37 +283,30 @@ class ScavengeRootsTask : public WorkerTask { PSOldGen* _old_gen; HeapWord* _gen_top; uint _active_workers; - bool _is_empty; + bool _is_old_gen_empty; TaskTerminator _terminator; public: ScavengeRootsTask(PSOldGen* old_gen, - HeapWord* gen_top, - uint active_workers, - bool is_empty) : + uint active_workers) : WorkerTask("ScavengeRootsTask"), _strong_roots_scope(active_workers), _subtasks(ParallelRootType::sentinel), _old_gen(old_gen), - _gen_top(gen_top), + _gen_top(old_gen->object_space()->top()), _active_workers(active_workers), - _is_empty(is_empty), + _is_old_gen_empty(old_gen->object_space()->is_empty()), _terminator(active_workers, PSPromotionManager::vm_thread_promotion_manager()->stack_array_depth()) { + assert(_old_gen != NULL, "Sanity"); } virtual void work(uint worker_id) { + assert(worker_id < _active_workers, "Sanity"); ResourceMark rm; - if (!_is_empty) { + if (!_is_old_gen_empty) { // There are only old-to-young pointers if there are objects // in the old gen. - - assert(_old_gen != NULL, "Sanity"); - // There are no old-to-young pointers if the old gen is empty. - assert(!_old_gen->object_space()->is_empty(), "Should not be called is there is no work"); - assert(_old_gen->object_space()->contains(_gen_top) || _gen_top == _old_gen->object_space()->top(), "Sanity"); - assert(worker_id < ParallelGCThreads, "Sanity"); - { PSPromotionManager* pm = PSPromotionManager::gc_thread_promotion_manager(worker_id); PSCardTable* card_table = ParallelScavengeHeap::heap()->card_table(); @@ -367,12 +358,6 @@ bool PSScavenge::invoke_no_policy() { _gc_timer.register_gc_start(); - TimeStamp scavenge_entry; - TimeStamp scavenge_midpoint; - TimeStamp scavenge_exit; - - scavenge_entry.update(); - if (GCLocker::check_active_before_gc()) { return false; } @@ -444,8 +429,6 @@ bool PSScavenge::invoke_no_policy() { "Attempt to scavenge with live objects in to_space"); young_gen->to_space()->clear(SpaceDecorator::Mangle); - save_to_space_top_before_gc(); - #if COMPILER2_OR_JVMCI DerivedPointerTable::clear(); #endif @@ -457,12 +440,6 @@ bool PSScavenge::invoke_no_policy() { // Reset our survivor overflow. set_survivor_overflow(false); - // We need to save the old top values before - // creating the promotion_manager. We pass the top - // values to the card_table, to prevent it from - // straying into the promotion labs. - HeapWord* old_top = old_gen->object_space()->top(); - const uint active_workers = WorkerPolicy::calc_active_workers(ParallelScavengeHeap::heap()->workers().max_workers(), ParallelScavengeHeap::heap()->workers().active_workers(), @@ -476,12 +453,10 @@ bool PSScavenge::invoke_no_policy() { { GCTraceTime(Debug, gc, phases) tm("Scavenge", &_gc_timer); - ScavengeRootsTask task(old_gen, old_top, active_workers, old_gen->object_space()->is_empty()); + ScavengeRootsTask task(old_gen, active_workers); ParallelScavengeHeap::heap()->workers().run_task(&task); } - scavenge_midpoint.update(); - // Process reference objects discovered during scavenge { GCTraceTime(Debug, gc, phases) tm("Reference Processing", &_gc_timer); @@ -686,12 +661,6 @@ bool PSScavenge::invoke_no_policy() { heap->print_heap_after_gc(); heap->trace_heap_after_gc(&_gc_tracer); - scavenge_exit.update(); - - log_debug(gc, task, time)("VM-Thread " JLONG_FORMAT " " JLONG_FORMAT " " JLONG_FORMAT, - scavenge_entry.ticks(), scavenge_midpoint.ticks(), - scavenge_exit.ticks()); - AdaptiveSizePolicyOutput::print(size_policy, heap->total_collections()); _gc_timer.register_gc_end(); @@ -701,19 +670,11 @@ bool PSScavenge::invoke_no_policy() { return !promotion_failure_occurred; } -// This method iterates over all objects in the young generation, -// removing all forwarding references. It then restores any preserved marks. void PSScavenge::clean_up_failed_promotion() { - ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); - PSYoungGen* young_gen = heap->young_gen(); - - RemoveForwardedPointerClosure remove_fwd_ptr_closure; - young_gen->object_iterate(&remove_fwd_ptr_closure); - PSPromotionManager::restore_preserved_marks(); // Reset the PromotionFailureALot counters. - NOT_PRODUCT(heap->reset_promotion_should_fail();) + NOT_PRODUCT(ParallelScavengeHeap::heap()->reset_promotion_should_fail();) } bool PSScavenge::should_attempt_scavenge() { @@ -729,7 +690,6 @@ bool PSScavenge::should_attempt_scavenge() { // Do not attempt to promote unless to_space is empty if (!young_gen->to_space()->is_empty()) { - _consecutive_skipped_scavenges++; if (UsePerfData) { counters->update_scavenge_skipped(to_space_not_empty); } @@ -753,10 +713,7 @@ bool PSScavenge::should_attempt_scavenge() { log_trace(ergo)(" padded_promoted_average is greater than maximum promotion = " SIZE_FORMAT, young_gen->used_in_bytes()); } - if (result) { - _consecutive_skipped_scavenges = 0; - } else { - _consecutive_skipped_scavenges++; + if (!result) { if (UsePerfData) { counters->update_scavenge_skipped(promoted_too_large); } @@ -799,7 +756,6 @@ void PSScavenge::initialize() { _ref_processor = new ReferenceProcessor(&_span_based_discoverer, ParallelGCThreads, // mt processing degree - true, // mt discovery ParallelGCThreads, // mt discovery degree false, // concurrent_discovery NULL); // header provides liveness info diff --git a/src/hotspot/share/gc/parallel/psScavenge.hpp b/src/hotspot/share/gc/parallel/psScavenge.hpp index 440519ff7076df79e823661980538135b6584195..01bc154e55291dae3bd9690d99af4978a4d846b9 100644 --- a/src/hotspot/share/gc/parallel/psScavenge.hpp +++ b/src/hotspot/share/gc/parallel/psScavenge.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 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 @@ -29,7 +29,7 @@ #include "gc/parallel/psVirtualspace.hpp" #include "gc/shared/collectorCounters.hpp" #include "gc/shared/gcTrace.hpp" -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" #include "oops/oop.hpp" #include "utilities/stack.hpp" @@ -53,14 +53,6 @@ class PSScavenge: AllStatic { full_follows_scavenge }; - // Saved value of to_space->top(), used to prevent objects in to_space from - // being rescanned. - static HeapWord* _to_space_top_before_gc; - - // Number of consecutive attempts to scavenge that were skipped - static int _consecutive_skipped_scavenges; - - protected: // Flags/counters static SpanSubjectToDiscoveryClosure _span_based_discoverer; @@ -84,9 +76,6 @@ class PSScavenge: AllStatic { static bool should_attempt_scavenge(); - static HeapWord* to_space_top_before_gc() { return _to_space_top_before_gc; } - static inline void save_to_space_top_before_gc(); - // Private accessors static PSCardTable* const card_table() { assert(_card_table != NULL, "Sanity"); return _card_table; } static const ParallelScavengeTracer* gc_tracer() { return &_gc_tracer; } @@ -95,8 +84,6 @@ class PSScavenge: AllStatic { // Accessors static uint tenuring_threshold() { return _tenuring_threshold; } static elapsedTimer* accumulated_time() { return &_accumulated_time; } - static int consecutive_skipped_scavenges() - { return _consecutive_skipped_scavenges; } // Performance Counters static CollectorCounters* counters() { return _counters; } @@ -148,6 +135,10 @@ class PSScavenge: AllStatic { inline static bool is_obj_in_young(HeapWord* o) { return o >= _young_generation_boundary; } + + static bool is_obj_in_to_space(oop o) { + return ParallelScavengeHeap::young_gen()->to_space()->contains(o); + } }; #endif // SHARE_GC_PARALLEL_PSSCAVENGE_HPP diff --git a/src/hotspot/share/gc/parallel/psScavenge.inline.hpp b/src/hotspot/share/gc/parallel/psScavenge.inline.hpp index 1fee9f08339ed8c5bf947e6c69b9be323f6ed310..af3ff4c616513e18bcfdedb2a28b5c58b8abb5f2 100644 --- a/src/hotspot/share/gc/parallel/psScavenge.inline.hpp +++ b/src/hotspot/share/gc/parallel/psScavenge.inline.hpp @@ -35,11 +35,6 @@ #include "oops/oop.inline.hpp" #include "utilities/globalDefinitions.hpp" -inline void PSScavenge::save_to_space_top_before_gc() { - ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); - _to_space_top_before_gc = heap->young_gen()->to_space()->top(); -} - template inline bool PSScavenge::should_scavenge(T* p) { T heap_oop = RawAccess<>::oop_load(p); return PSScavenge::is_obj_in_young(heap_oop); @@ -51,7 +46,7 @@ inline bool PSScavenge::should_scavenge(T* p, MutableSpace* to_space) { oop obj = RawAccess::oop_load(p); // Skip objects copied to to_space since the scavenge started. HeapWord* const addr = cast_from_oop(obj); - return addr < to_space_top_before_gc() || addr >= to_space->end(); + return addr < to_space->bottom() || addr >= to_space->end(); } return false; } diff --git a/src/hotspot/share/gc/parallel/psVirtualspace.cpp b/src/hotspot/share/gc/parallel/psVirtualspace.cpp index 473a1f268545196e82bfb64128ba6cd39b3fb9f4..4c5733f24d940b6bce0f38c20883b3aa7fcacc92 100644 --- a/src/hotspot/share/gc/parallel/psVirtualspace.cpp +++ b/src/hotspot/share/gc/parallel/psVirtualspace.cpp @@ -37,14 +37,6 @@ PSVirtualSpace::PSVirtualSpace(ReservedSpace rs, size_t alignment) : DEBUG_ONLY(verify()); } -PSVirtualSpace::PSVirtualSpace(ReservedSpace rs) : - _alignment(os::vm_page_size()) -{ - set_reserved(rs); - set_committed(reserved_low_addr(), reserved_low_addr()); - DEBUG_ONLY(verify()); -} - // Deprecated. PSVirtualSpace::PSVirtualSpace(): _alignment(os::vm_page_size()), @@ -56,27 +48,16 @@ PSVirtualSpace::PSVirtualSpace(): } // Deprecated. -bool PSVirtualSpace::initialize(ReservedSpace rs, - size_t commit_size) { +void PSVirtualSpace::initialize(ReservedSpace rs) { set_reserved(rs); set_committed(reserved_low_addr(), reserved_low_addr()); - - // Commit to initial size. - assert(commit_size <= rs.size(), "commit_size too big"); - bool result = commit_size > 0 ? expand_by(commit_size) : true; DEBUG_ONLY(verify()); - return result; } PSVirtualSpace::~PSVirtualSpace() { release(); } -bool PSVirtualSpace::contains(void* p) const { - char* const cp = (char*)p; - return cp >= committed_low_addr() && cp < committed_high_addr(); -} - void PSVirtualSpace::release() { DEBUG_ONLY(PSVirtualSpaceVerifier this_verifier(this)); // This may not release memory it didn't reserve. @@ -121,67 +102,6 @@ bool PSVirtualSpace::shrink_by(size_t bytes) { return result; } -size_t -PSVirtualSpace::expand_into(PSVirtualSpace* other_space, size_t bytes) { - assert(is_aligned(bytes), "arg not aligned"); - assert(grows_up(), "this space must grow up"); - assert(other_space->grows_down(), "other space must grow down"); - assert(reserved_high_addr() == other_space->reserved_low_addr(), - "spaces not contiguous"); - assert(special() == other_space->special(), "one space is special, the other is not"); - DEBUG_ONLY(PSVirtualSpaceVerifier this_verifier(this)); - DEBUG_ONLY(PSVirtualSpaceVerifier other_verifier(other_space)); - - size_t bytes_needed = bytes; - - // First use the uncommitted region in this space. - size_t tmp_bytes = MIN2(uncommitted_size(), bytes_needed); - if (tmp_bytes > 0) { - if (expand_by(tmp_bytes)) { - bytes_needed -= tmp_bytes; - } else { - return 0; - } - } - - // Next take from the uncommitted region in the other space, and commit it. - tmp_bytes = MIN2(other_space->uncommitted_size(), bytes_needed); - if (tmp_bytes > 0) { - char* const commit_base = committed_high_addr(); - if (other_space->special() || - os::commit_memory(commit_base, tmp_bytes, alignment(), !ExecMem)) { - // Reduce the reserved region in the other space. - other_space->set_reserved(other_space->reserved_low_addr() + tmp_bytes, - other_space->reserved_high_addr(), - other_space->special()); - - // Grow both reserved and committed in this space. - _reserved_high_addr += tmp_bytes; - _committed_high_addr += tmp_bytes; - bytes_needed -= tmp_bytes; - } else { - return bytes - bytes_needed; - } - } - - // Finally take from the already committed region in the other space. - tmp_bytes = bytes_needed; - if (tmp_bytes > 0) { - // Reduce both committed and reserved in the other space. - other_space->set_committed(other_space->committed_low_addr() + tmp_bytes, - other_space->committed_high_addr()); - other_space->set_reserved(other_space->reserved_low_addr() + tmp_bytes, - other_space->reserved_high_addr(), - other_space->special()); - - // Grow both reserved and committed in this space. - _reserved_high_addr += tmp_bytes; - _committed_high_addr += tmp_bytes; - } - - return bytes; -} - #ifndef PRODUCT bool PSVirtualSpace::is_aligned(size_t value, size_t align) { const size_t tmp_value = value + align - 1; @@ -210,13 +130,9 @@ void PSVirtualSpace::verify() const { "bad reserved addrs"); assert(committed_low_addr() <= committed_high_addr(), "bad committed addrs"); - if (grows_up()) { - assert(reserved_low_addr() == committed_low_addr(), "bad low addrs"); - assert(reserved_high_addr() >= committed_high_addr(), "bad high addrs"); - } else { - assert(reserved_high_addr() == committed_high_addr(), "bad high addrs"); - assert(reserved_low_addr() <= committed_low_addr(), "bad low addrs"); - } + // committed addr grows up + assert(reserved_low_addr() == committed_low_addr(), "bad low addrs"); + assert(reserved_high_addr() >= committed_high_addr(), "bad high addrs"); } #endif // #ifndef PRODUCT diff --git a/src/hotspot/share/gc/parallel/psVirtualspace.hpp b/src/hotspot/share/gc/parallel/psVirtualspace.hpp index 853264ed62d7a23b702cb853ca5df88af7f329f2..48150293a9ee154ffee78e6c44de9e6b6d4ac7b5 100644 --- a/src/hotspot/share/gc/parallel/psVirtualspace.hpp +++ b/src/hotspot/share/gc/parallel/psVirtualspace.hpp @@ -57,25 +57,19 @@ class PSVirtualSpace : public CHeapObj { public: PSVirtualSpace(ReservedSpace rs, size_t alignment); - PSVirtualSpace(ReservedSpace rs); ~PSVirtualSpace(); - // Eventually all instances should be created with the above 1- or 2-arg - // constructors. Then the 1st constructor below should become protected and - // the 2nd ctor and initialize() removed. - PSVirtualSpace(size_t alignment): - _alignment(alignment), - _reserved_low_addr(NULL), - _reserved_high_addr(NULL), - _committed_low_addr(NULL), - _committed_high_addr(NULL), - _special(false) { - } PSVirtualSpace(); - bool initialize(ReservedSpace rs, size_t commit_size); + void initialize(ReservedSpace rs); + + bool is_in_committed(const void* p) const { + return (p >= committed_low_addr()) && (p < committed_high_addr()); + } - bool contains(void* p) const; + bool is_in_reserved(const void* p) const { + return (p >= reserved_low_addr()) && (p < reserved_high_addr()); + } // Accessors (all sizes are bytes). size_t alignment() const { return _alignment; } @@ -85,6 +79,7 @@ class PSVirtualSpace : public CHeapObj { char* committed_high_addr() const { return _committed_high_addr; } bool special() const { return _special; } + // Return size in bytes inline size_t committed_size() const; inline size_t reserved_size() const; inline size_t uncommitted_size() const; @@ -95,7 +90,6 @@ class PSVirtualSpace : public CHeapObj { inline void set_committed(char* low_addr, char* high_addr); virtual bool expand_by(size_t bytes); virtual bool shrink_by(size_t bytes); - virtual size_t expand_into(PSVirtualSpace* space, size_t bytes); void release(); #ifndef PRODUCT @@ -104,8 +98,6 @@ class PSVirtualSpace : public CHeapObj { bool is_aligned(size_t val) const; bool is_aligned(char* val) const; void verify() const; - virtual bool grows_up() const { return true; } - bool grows_down() const { return !grows_up(); } // Helper class to verify a space when entering/leaving a block. class PSVirtualSpaceVerifier: public StackObj { diff --git a/src/hotspot/share/gc/parallel/psYoungGen.hpp b/src/hotspot/share/gc/parallel/psYoungGen.hpp index 0da0592a98616c252cc09ee83cadfd59e45bbc8e..3babc311e95500622f95b74259e7e5ab6c7df7aa 100644 --- a/src/hotspot/share/gc/parallel/psYoungGen.hpp +++ b/src/hotspot/share/gc/parallel/psYoungGen.hpp @@ -90,7 +90,7 @@ class PSYoungGen : public CHeapObj { MemRegion reserved() const { return _reserved; } bool is_in(const void* p) const { - return _virtual_space->contains((void *)p); + return _virtual_space->is_in_committed(p); } bool is_in_reserved(const void* p) const { diff --git a/src/hotspot/share/gc/parallel/vmStructs_parallelgc.hpp b/src/hotspot/share/gc/parallel/vmStructs_parallelgc.hpp index 0f131687f5b18b92b14f74c88f78ffbcaef8c537..fa019aa5b429517615a58bb85385d157b826f0ef 100644 --- a/src/hotspot/share/gc/parallel/vmStructs_parallelgc.hpp +++ b/src/hotspot/share/gc/parallel/vmStructs_parallelgc.hpp @@ -57,7 +57,6 @@ nonstatic_field(PSYoungGen, _min_gen_size, const size_t) \ nonstatic_field(PSYoungGen, _max_gen_size, const size_t) \ \ - nonstatic_field(PSOldGen, _reserved, MemRegion) \ nonstatic_field(PSOldGen, _virtual_space, PSVirtualSpace*) \ nonstatic_field(PSOldGen, _object_space, MutableSpace*) \ nonstatic_field(PSOldGen, _min_gen_size, const size_t) \ diff --git a/src/hotspot/share/gc/serial/defNewGeneration.cpp b/src/hotspot/share/gc/serial/defNewGeneration.cpp index cd5e679cd074b6a3927f3502d524b52209df91a5..faec1096cfd05821c4de8251406453ea5dafe088 100644 --- a/src/hotspot/share/gc/serial/defNewGeneration.cpp +++ b/src/hotspot/share/gc/serial/defNewGeneration.cpp @@ -288,7 +288,6 @@ void DefNewGeneration::swap_spaces() { } bool DefNewGeneration::expand(size_t bytes) { - MutexLocker x(ExpandHeap_lock); HeapWord* prev_high = (HeapWord*) _virtual_space.high(); bool success = _virtual_space.expand_by(bytes); if (success && ZapUnusedHeapArea) { @@ -669,9 +668,21 @@ void DefNewGeneration::init_assuming_no_promotion_failure() { } void DefNewGeneration::remove_forwarding_pointers() { - RemoveForwardedPointerClosure rspc; - eden()->object_iterate(&rspc); - from()->object_iterate(&rspc); + assert(_promotion_failed, "precondition"); + + // Will enter Full GC soon due to failed promotion. Must reset the mark word + // of objs in young-gen so that no objs are marked (forwarded) when Full GC + // starts. (The mark word is overloaded: `is_marked()` == `is_forwarded()`.) + struct ResetForwardedMarkWord : ObjectClosure { + void do_object(oop obj) override { + if (obj->is_forwarded()) { + obj->init_mark(); + } + } + } cl; + eden()->object_iterate(&cl); + from()->object_iterate(&cl); + restore_preserved_marks(); } @@ -878,11 +889,6 @@ void DefNewGeneration::record_spaces_top() { from()->set_top_for_allocations(); } -void DefNewGeneration::ref_processor_init() { - Generation::ref_processor_init(); -} - - void DefNewGeneration::update_counters() { if (UsePerfData) { _eden_counters->update_all(); diff --git a/src/hotspot/share/gc/serial/defNewGeneration.hpp b/src/hotspot/share/gc/serial/defNewGeneration.hpp index 5ea7785256654bc2c6470595faee814c4e9b2b02..f060a5ea8ac99ca9fee27376cfa552bd38b8baef 100644 --- a/src/hotspot/share/gc/serial/defNewGeneration.hpp +++ b/src/hotspot/share/gc/serial/defNewGeneration.hpp @@ -202,8 +202,6 @@ protected: size_t max_byte_size, const char* policy="Serial young collection pauses"); - virtual void ref_processor_init(); - virtual Generation::Name kind() { return Generation::DefNew; } // Accessing spaces diff --git a/src/hotspot/share/gc/serial/markSweep.inline.hpp b/src/hotspot/share/gc/serial/markSweep.inline.hpp index ee0ef1e0b1bb1284d4e1e4dcd8be561d908c1dce..27fb8bb2f29d76b44e23b369970e8773b059e2df 100644 --- a/src/hotspot/share/gc/serial/markSweep.inline.hpp +++ b/src/hotspot/share/gc/serial/markSweep.inline.hpp @@ -88,13 +88,8 @@ template inline void MarkSweep::adjust_pointer(T* p) { oop obj = CompressedOops::decode_not_null(heap_oop); assert(Universe::heap()->is_in(obj), "should be in heap"); - oop new_obj = cast_to_oop(obj->mark().decode_pointer()); - - assert(new_obj != NULL || // is forwarding ptr? - obj->mark() == markWord::prototype(), // not gc marked? - "should be forwarded"); - - if (new_obj != NULL) { + if (obj->is_forwarded()) { + oop new_obj = obj->forwardee(); assert(is_object_aligned(new_obj), "oop must be aligned"); RawAccess::oop_store(p, new_obj); } diff --git a/src/hotspot/share/gc/serial/serialHeap.hpp b/src/hotspot/share/gc/serial/serialHeap.hpp index 208a997ad5fc85ce91cfc695892754a4b11dd721..f71b4a6740cffeb4cf478e08c5340fc92c4f9794 100644 --- a/src/hotspot/share/gc/serial/serialHeap.hpp +++ b/src/hotspot/share/gc/serial/serialHeap.hpp @@ -35,6 +35,26 @@ class MemoryPool; class OopIterateClosure; class TenuredGeneration; +// SerialHeap is the implementation of CollectedHeap for Serial GC. +// +// The heap is reserved up-front in a single contiguous block, split into two +// parts, the young and old generation. The young generation resides at lower +// addresses, the old generation at higher addresses. The boundary address +// between the generations is fixed. Within a generation, committed memory +// grows towards higher addresses. +// +// +// low high +// +// +-- generation boundary (fixed after startup) +// | +// |<- young gen (reserved MaxNewSize) ->|<- old gen (reserved MaxOldSize) ->| +// +-----------------+--------+--------+--------+---------------+-------------------+ +// | eden | from | to | | old | | +// | | (to) | (from) | | | | +// +-----------------+--------+--------+--------+---------------+-------------------+ +// |<- committed ->| |<- committed ->| +// class SerialHeap : public GenCollectedHeap { private: MemoryPool* _eden_pool; @@ -85,7 +105,7 @@ public: virtual void safepoint_synchronize_end(); // Support for loading objects from CDS archive into the heap - bool can_load_archived_objects() const { return true; } + bool can_load_archived_objects() const { return UseCompressedOops; } HeapWord* allocate_loaded_archive_space(size_t size); void complete_loaded_archive_space(MemRegion archive_space); }; diff --git a/src/hotspot/share/gc/serial/tenuredGeneration.cpp b/src/hotspot/share/gc/serial/tenuredGeneration.cpp index 1aec978b3820724b488cb725932773a618c3cbb6..08aede2880f2acdda741f3b0cb1ba6c169c299f3 100644 --- a/src/hotspot/share/gc/serial/tenuredGeneration.cpp +++ b/src/hotspot/share/gc/serial/tenuredGeneration.cpp @@ -26,8 +26,8 @@ #include "gc/serial/genMarkSweep.hpp" #include "gc/serial/tenuredGeneration.inline.hpp" #include "gc/shared/blockOffsetTable.inline.hpp" -#include "gc/shared/cardGeneration.inline.hpp" #include "gc/shared/collectorCounters.hpp" +#include "gc/shared/gcLocker.hpp" #include "gc/shared/gcTimer.hpp" #include "gc/shared/gcTrace.hpp" #include "gc/shared/genCollectedHeap.hpp" @@ -40,13 +40,286 @@ #include "runtime/java.hpp" #include "utilities/macros.hpp" +bool TenuredGeneration::grow_by(size_t bytes) { + assert_correct_size_change_locking(); + bool result = _virtual_space.expand_by(bytes); + if (result) { + size_t new_word_size = + heap_word_size(_virtual_space.committed_size()); + MemRegion mr(space()->bottom(), new_word_size); + // Expand card table + GenCollectedHeap::heap()->rem_set()->resize_covered_region(mr); + // Expand shared block offset array + _bts->resize(new_word_size); + + // Fix for bug #4668531 + if (ZapUnusedHeapArea) { + MemRegion mangle_region(space()->end(), + (HeapWord*)_virtual_space.high()); + SpaceMangler::mangle_region(mangle_region); + } + + // Expand space -- also expands space's BOT + // (which uses (part of) shared array above) + space()->set_end((HeapWord*)_virtual_space.high()); + + // update the space and generation capacity counters + update_counters(); + + size_t new_mem_size = _virtual_space.committed_size(); + size_t old_mem_size = new_mem_size - bytes; + log_trace(gc, heap)("Expanding %s from " SIZE_FORMAT "K by " SIZE_FORMAT "K to " SIZE_FORMAT "K", + name(), old_mem_size/K, bytes/K, new_mem_size/K); + } + return result; +} + +bool TenuredGeneration::expand(size_t bytes, size_t expand_bytes) { + assert_locked_or_safepoint(Heap_lock); + if (bytes == 0) { + return true; // That's what grow_by(0) would return + } + size_t aligned_bytes = ReservedSpace::page_align_size_up(bytes); + if (aligned_bytes == 0){ + // The alignment caused the number of bytes to wrap. An expand_by(0) will + // return true with the implication that an expansion was done when it + // was not. A call to expand implies a best effort to expand by "bytes" + // but not a guarantee. Align down to give a best effort. This is likely + // the most that the generation can expand since it has some capacity to + // start with. + aligned_bytes = ReservedSpace::page_align_size_down(bytes); + } + size_t aligned_expand_bytes = ReservedSpace::page_align_size_up(expand_bytes); + bool success = false; + if (aligned_expand_bytes > aligned_bytes) { + success = grow_by(aligned_expand_bytes); + } + if (!success) { + success = grow_by(aligned_bytes); + } + if (!success) { + success = grow_to_reserved(); + } + if (success && GCLocker::is_active_and_needs_gc()) { + log_trace(gc, heap)("Garbage collection disabled, expanded heap instead"); + } + + return success; +} + +bool TenuredGeneration::grow_to_reserved() { + assert_correct_size_change_locking(); + bool success = true; + const size_t remaining_bytes = _virtual_space.uncommitted_size(); + if (remaining_bytes > 0) { + success = grow_by(remaining_bytes); + DEBUG_ONLY(if (!success) log_warning(gc)("grow to reserved failed");) + } + return success; +} + +void TenuredGeneration::shrink(size_t bytes) { + assert_correct_size_change_locking(); + + size_t size = ReservedSpace::page_align_size_down(bytes); + if (size == 0) { + return; + } + + // Shrink committed space + _virtual_space.shrink_by(size); + // Shrink space; this also shrinks the space's BOT + space()->set_end((HeapWord*) _virtual_space.high()); + size_t new_word_size = heap_word_size(space()->capacity()); + // Shrink the shared block offset array + _bts->resize(new_word_size); + MemRegion mr(space()->bottom(), new_word_size); + // Shrink the card table + GenCollectedHeap::heap()->rem_set()->resize_covered_region(mr); + + size_t new_mem_size = _virtual_space.committed_size(); + size_t old_mem_size = new_mem_size + size; + log_trace(gc, heap)("Shrinking %s from " SIZE_FORMAT "K to " SIZE_FORMAT "K", + name(), old_mem_size/K, new_mem_size/K); +} + +// Objects in this generation may have moved, invalidate this +// generation's cards. +void TenuredGeneration::invalidate_remembered_set() { + _rs->invalidate(used_region()); +} + +void TenuredGeneration::compute_new_size_inner() { + assert(_shrink_factor <= 100, "invalid shrink factor"); + size_t current_shrink_factor = _shrink_factor; + if (ShrinkHeapInSteps) { + // Always reset '_shrink_factor' if the heap is shrunk in steps. + // If we shrink the heap in this iteration, '_shrink_factor' will + // be recomputed based on the old value further down in this fuction. + _shrink_factor = 0; + } + + // We don't have floating point command-line arguments + // Note: argument processing ensures that MinHeapFreeRatio < 100. + const double minimum_free_percentage = MinHeapFreeRatio / 100.0; + const double maximum_used_percentage = 1.0 - minimum_free_percentage; + + // Compute some numbers about the state of the heap. + const size_t used_after_gc = used(); + const size_t capacity_after_gc = capacity(); + + const double min_tmp = used_after_gc / maximum_used_percentage; + size_t minimum_desired_capacity = (size_t)MIN2(min_tmp, double(max_uintx)); + // Don't shrink less than the initial generation size + minimum_desired_capacity = MAX2(minimum_desired_capacity, initial_size()); + assert(used_after_gc <= minimum_desired_capacity, "sanity check"); + + const size_t free_after_gc = free(); + const double free_percentage = ((double)free_after_gc) / capacity_after_gc; + log_trace(gc, heap)("TenuredGeneration::compute_new_size:"); + log_trace(gc, heap)(" minimum_free_percentage: %6.2f maximum_used_percentage: %6.2f", + minimum_free_percentage, + maximum_used_percentage); + log_trace(gc, heap)(" free_after_gc : %6.1fK used_after_gc : %6.1fK capacity_after_gc : %6.1fK", + free_after_gc / (double) K, + used_after_gc / (double) K, + capacity_after_gc / (double) K); + log_trace(gc, heap)(" free_percentage: %6.2f", free_percentage); + + if (capacity_after_gc < minimum_desired_capacity) { + // If we have less free space than we want then expand + size_t expand_bytes = minimum_desired_capacity - capacity_after_gc; + // Don't expand unless it's significant + if (expand_bytes >= _min_heap_delta_bytes) { + expand(expand_bytes, 0); // safe if expansion fails + } + log_trace(gc, heap)(" expanding: minimum_desired_capacity: %6.1fK expand_bytes: %6.1fK _min_heap_delta_bytes: %6.1fK", + minimum_desired_capacity / (double) K, + expand_bytes / (double) K, + _min_heap_delta_bytes / (double) K); + return; + } + + // No expansion, now see if we want to shrink + size_t shrink_bytes = 0; + // We would never want to shrink more than this + size_t max_shrink_bytes = capacity_after_gc - minimum_desired_capacity; + + if (MaxHeapFreeRatio < 100) { + const double maximum_free_percentage = MaxHeapFreeRatio / 100.0; + const double minimum_used_percentage = 1.0 - maximum_free_percentage; + const double max_tmp = used_after_gc / minimum_used_percentage; + size_t maximum_desired_capacity = (size_t)MIN2(max_tmp, double(max_uintx)); + maximum_desired_capacity = MAX2(maximum_desired_capacity, initial_size()); + log_trace(gc, heap)(" maximum_free_percentage: %6.2f minimum_used_percentage: %6.2f", + maximum_free_percentage, minimum_used_percentage); + log_trace(gc, heap)(" _capacity_at_prologue: %6.1fK minimum_desired_capacity: %6.1fK maximum_desired_capacity: %6.1fK", + _capacity_at_prologue / (double) K, + minimum_desired_capacity / (double) K, + maximum_desired_capacity / (double) K); + assert(minimum_desired_capacity <= maximum_desired_capacity, + "sanity check"); + + if (capacity_after_gc > maximum_desired_capacity) { + // Capacity too large, compute shrinking size + shrink_bytes = capacity_after_gc - maximum_desired_capacity; + if (ShrinkHeapInSteps) { + // If ShrinkHeapInSteps is true (the default), + // we don't want to shrink all the way back to initSize if people call + // System.gc(), because some programs do that between "phases" and then + // we'd just have to grow the heap up again for the next phase. So we + // damp the shrinking: 0% on the first call, 10% on the second call, 40% + // on the third call, and 100% by the fourth call. But if we recompute + // size without shrinking, it goes back to 0%. + shrink_bytes = shrink_bytes / 100 * current_shrink_factor; + if (current_shrink_factor == 0) { + _shrink_factor = 10; + } else { + _shrink_factor = MIN2(current_shrink_factor * 4, (size_t) 100); + } + } + assert(shrink_bytes <= max_shrink_bytes, "invalid shrink size"); + log_trace(gc, heap)(" shrinking: initSize: %.1fK maximum_desired_capacity: %.1fK", + initial_size() / (double) K, maximum_desired_capacity / (double) K); + log_trace(gc, heap)(" shrink_bytes: %.1fK current_shrink_factor: " SIZE_FORMAT " new shrink factor: " SIZE_FORMAT " _min_heap_delta_bytes: %.1fK", + shrink_bytes / (double) K, + current_shrink_factor, + _shrink_factor, + _min_heap_delta_bytes / (double) K); + } + } + + if (capacity_after_gc > _capacity_at_prologue) { + // We might have expanded for promotions, in which case we might want to + // take back that expansion if there's room after GC. That keeps us from + // stretching the heap with promotions when there's plenty of room. + size_t expansion_for_promotion = capacity_after_gc - _capacity_at_prologue; + expansion_for_promotion = MIN2(expansion_for_promotion, max_shrink_bytes); + // We have two shrinking computations, take the largest + shrink_bytes = MAX2(shrink_bytes, expansion_for_promotion); + assert(shrink_bytes <= max_shrink_bytes, "invalid shrink size"); + log_trace(gc, heap)(" aggressive shrinking: _capacity_at_prologue: %.1fK capacity_after_gc: %.1fK expansion_for_promotion: %.1fK shrink_bytes: %.1fK", + capacity_after_gc / (double) K, + _capacity_at_prologue / (double) K, + expansion_for_promotion / (double) K, + shrink_bytes / (double) K); + } + // Don't shrink unless it's significant + if (shrink_bytes >= _min_heap_delta_bytes) { + shrink(shrink_bytes); + } +} + +void TenuredGeneration::space_iterate(SpaceClosure* blk, + bool usedOnly) { + blk->do_space(space()); +} + +void TenuredGeneration::younger_refs_iterate(OopIterateClosure* blk) { + // Apply "cl->do_oop" to (the address of) (exactly) all the ref fields in + // "sp" that point into the young generation. + // The iteration is only over objects allocated at the start of the + // iterations; objects allocated as a result of applying the closure are + // not included. + + HeapWord* gen_boundary = reserved().start(); + _rs->younger_refs_in_space_iterate(space(), gen_boundary, blk); +} + TenuredGeneration::TenuredGeneration(ReservedSpace rs, size_t initial_byte_size, size_t min_byte_size, size_t max_byte_size, CardTableRS* remset) : - CardGeneration(rs, initial_byte_size, remset) + Generation(rs, initial_byte_size), _rs(remset), + _min_heap_delta_bytes(), _capacity_at_prologue(), + _used_at_prologue() { + // If we don't shrink the heap in steps, '_shrink_factor' is always 100%. + _shrink_factor = ShrinkHeapInSteps ? 0 : 100; + HeapWord* start = (HeapWord*)rs.base(); + size_t reserved_byte_size = rs.size(); + assert((uintptr_t(start) & 3) == 0, "bad alignment"); + assert((reserved_byte_size & 3) == 0, "bad alignment"); + MemRegion reserved_mr(start, heap_word_size(reserved_byte_size)); + _bts = new BlockOffsetSharedArray(reserved_mr, + heap_word_size(initial_byte_size)); + MemRegion committed_mr(start, heap_word_size(initial_byte_size)); + _rs->resize_covered_region(committed_mr); + + // Verify that the start and end of this generation is the start of a card. + // If this wasn't true, a single card could span more than on generation, + // which would cause problems when we commit/uncommit memory, and when we + // clear and dirty cards. + guarantee(_rs->is_aligned(reserved_mr.start()), "generation must be card aligned"); + if (reserved_mr.end() != GenCollectedHeap::heap()->reserved_region().end()) { + // Don't check at the very end of the heap as we'll assert that we're probing off + // the end if we try. + guarantee(_rs->is_aligned(reserved_mr.end()), "generation must be card aligned"); + } + _min_heap_delta_bytes = MinHeapDeltaBytes; + _capacity_at_prologue = initial_byte_size; + _used_at_prologue = 0; HeapWord* bottom = (HeapWord*) _virtual_space.low(); HeapWord* end = (HeapWord*) _virtual_space.high(); _the_space = new TenuredSpace(_bts, MemRegion(bottom, end)); @@ -114,7 +387,7 @@ void TenuredGeneration::compute_new_size() { const size_t used_after_gc = used(); const size_t capacity_after_gc = capacity(); - CardGeneration::compute_new_size(); + compute_new_size_inner(); assert(used() == used_after_gc && used_after_gc <= capacity(), "used: " SIZE_FORMAT " used_after_gc: " SIZE_FORMAT @@ -195,11 +468,6 @@ TenuredGeneration::expand_and_allocate(size_t word_size, bool is_tlab) { return _the_space->allocate(word_size); } -bool TenuredGeneration::expand(size_t bytes, size_t expand_bytes) { - GCMutexLocker x(ExpandHeap_lock); - return CardGeneration::expand(bytes, expand_bytes); -} - size_t TenuredGeneration::unsafe_max_alloc_nogc() const { return _the_space->free(); } @@ -209,12 +477,9 @@ size_t TenuredGeneration::contiguous_available() const { } void TenuredGeneration::assert_correct_size_change_locking() { - assert_locked_or_safepoint(ExpandHeap_lock); + assert_locked_or_safepoint(Heap_lock); } -// Currently nothing to do. -void TenuredGeneration::prepare_for_verify() {} - void TenuredGeneration::object_iterate(ObjectClosure* blk) { _the_space->object_iterate(blk); } diff --git a/src/hotspot/share/gc/serial/tenuredGeneration.hpp b/src/hotspot/share/gc/serial/tenuredGeneration.hpp index 44153320f6c1fbd66251a0a6976e5a0ded107a6a..6f364a38f446f196779effe84533a2275f5493ca 100644 --- a/src/hotspot/share/gc/serial/tenuredGeneration.hpp +++ b/src/hotspot/share/gc/serial/tenuredGeneration.hpp @@ -26,36 +26,85 @@ #define SHARE_GC_SERIAL_TENUREDGENERATION_HPP #include "gc/serial/cSpaceCounters.hpp" -#include "gc/shared/cardGeneration.hpp" +#include "gc/shared/generation.hpp" #include "gc/shared/gcStats.hpp" #include "gc/shared/generationCounters.hpp" #include "utilities/macros.hpp" +class BlockOffsetSharedArray; +class CardTableRS; +class CompactibleSpace; + // TenuredGeneration models the heap containing old (promoted/tenured) objects -// contained in a single contiguous space. -// +// contained in a single contiguous space. This generation is covered by a card +// table, and uses a card-size block-offset array to implement block_start. // Garbage collection is performed using mark-compact. -class TenuredGeneration: public CardGeneration { +class TenuredGeneration: public Generation { friend class VMStructs; // Abstractly, this is a subtype that gets access to protected fields. friend class VM_PopulateDumpSharedSpace; protected: + + // This is shared with other generations. + CardTableRS* _rs; + // This is local to this generation. + BlockOffsetSharedArray* _bts; + + // Current shrinking effect: this damps shrinking when the heap gets empty. + size_t _shrink_factor; + + size_t _min_heap_delta_bytes; // Minimum amount to expand. + + // Some statistics from before gc started. + // These are gathered in the gc_prologue (and should_collect) + // to control growing/shrinking policy in spite of promotions. + size_t _capacity_at_prologue; + size_t _used_at_prologue; + + void assert_correct_size_change_locking(); + ContiguousSpace* _the_space; // Actual space holding objects GenerationCounters* _gen_counters; CSpaceCounters* _space_counters; - // Allocation failure - virtual bool expand(size_t bytes, size_t expand_bytes); - // Accessing spaces ContiguousSpace* space() const { return _the_space; } - void assert_correct_size_change_locking(); + // Attempt to expand the generation by "bytes". Expand by at a + // minimum "expand_bytes". Return true if some amount (not + // necessarily the full "bytes") was done. + bool expand(size_t bytes, size_t expand_bytes); + + // Shrink generation with specified size + void shrink(size_t bytes); + void compute_new_size_inner(); public: + virtual void compute_new_size(); + + virtual void invalidate_remembered_set(); + + // Grow generation with specified size (returns false if unable to grow) + bool grow_by(size_t bytes); + // Grow generation to reserved size. + bool grow_to_reserved(); + + size_t capacity() const; + size_t used() const; + size_t free() const; + MemRegion used_region() const; + + void space_iterate(SpaceClosure* blk, bool usedOnly = false); + + void younger_refs_iterate(OopIterateClosure* blk); + + bool is_in(const void* p) const; + + CompactibleSpace* first_compaction_space() const; + TenuredGeneration(ReservedSpace rs, size_t initial_byte_size, size_t min_byte_size, @@ -97,8 +146,6 @@ class TenuredGeneration: public CardGeneration { HeapWord* expand_and_allocate(size_t size, bool is_tlab); - virtual void prepare_for_verify(); - virtual void gc_prologue(bool full); virtual void gc_epilogue(bool full); @@ -106,8 +153,6 @@ class TenuredGeneration: public CardGeneration { size_t word_size, bool is_tlab); - virtual void compute_new_size(); - // Performance Counter support void update_counters(); diff --git a/src/hotspot/share/gc/serial/tenuredGeneration.inline.hpp b/src/hotspot/share/gc/serial/tenuredGeneration.inline.hpp index f79d31786e2d1ad9f67338d4f6edf0246c145049..2e6a4ca56dfcc1d8d156ef24d527df32e553e95b 100644 --- a/src/hotspot/share/gc/serial/tenuredGeneration.inline.hpp +++ b/src/hotspot/share/gc/serial/tenuredGeneration.inline.hpp @@ -29,6 +29,30 @@ #include "gc/shared/space.inline.hpp" +inline size_t TenuredGeneration::capacity() const { + return space()->capacity(); +} + +inline size_t TenuredGeneration::used() const { + return space()->used(); +} + +inline size_t TenuredGeneration::free() const { + return space()->free(); +} + +inline MemRegion TenuredGeneration::used_region() const { + return space()->used_region(); +} + +inline bool TenuredGeneration::is_in(const void* p) const { + return space()->is_in(p); +} + +inline CompactibleSpace* TenuredGeneration::first_compaction_space() const { + return space(); +} + HeapWord* TenuredGeneration::allocate(size_t word_size, bool is_tlab) { assert(!is_tlab, "TenuredGeneration does not support TLAB allocation"); diff --git a/src/hotspot/share/gc/serial/vmStructs_serial.hpp b/src/hotspot/share/gc/serial/vmStructs_serial.hpp index 39905458d4c129f4e751d8a11f9f40ff78138e6c..0ba676706ab88e93ce9902742df251361bfaa2f1 100644 --- a/src/hotspot/share/gc/serial/vmStructs_serial.hpp +++ b/src/hotspot/share/gc/serial/vmStructs_serial.hpp @@ -45,7 +45,7 @@ declare_toplevel_type, \ declare_integer_type) \ declare_type(SerialHeap, GenCollectedHeap) \ - declare_type(TenuredGeneration, CardGeneration) \ + declare_type(TenuredGeneration, Generation) \ declare_type(TenuredSpace, OffsetTableContigSpace) \ \ declare_type(DefNewGeneration, Generation) \ diff --git a/src/hotspot/share/gc/shared/accessBarrierSupport.hpp b/src/hotspot/share/gc/shared/accessBarrierSupport.hpp index 58bc562d988a8551efd3e127da497033f2c4ef04..ca3b4589224bf2233335d96fcebcf08311da183a 100644 --- a/src/hotspot/share/gc/shared/accessBarrierSupport.hpp +++ b/src/hotspot/share/gc/shared/accessBarrierSupport.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -25,7 +25,7 @@ #ifndef SHARE_GC_SHARED_ACCESSBARRIERSUPPORT_HPP #define SHARE_GC_SHARED_ACCESSBARRIERSUPPORT_HPP -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" #include "oops/access.hpp" class AccessBarrierSupport: AllStatic { diff --git a/src/hotspot/share/gc/shared/ageTableTracer.hpp b/src/hotspot/share/gc/shared/ageTableTracer.hpp index cca3f125bfd730f0ec0a74ca0b8ccad7d88a4e0c..02e1fe3338db210b82ed283646e3e3173da022d2 100644 --- a/src/hotspot/share/gc/shared/ageTableTracer.hpp +++ b/src/hotspot/share/gc/shared/ageTableTracer.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -25,7 +25,8 @@ #ifndef SHARE_GC_SHARED_AGETABLETRACER_HPP #define SHARE_GC_SHARED_AGETABLETRACER_HPP -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" +#include "utilities/globalDefinitions.hpp" class AgeTableTracer : AllStatic { public: diff --git a/src/hotspot/share/gc/shared/allocTracer.hpp b/src/hotspot/share/gc/shared/allocTracer.hpp index c30628b2889705f37795fb0b7443891807c8fd68..273f20d70ea44d5e1161ff6ec1877c97d9d0f99b 100644 --- a/src/hotspot/share/gc/shared/allocTracer.hpp +++ b/src/hotspot/share/gc/shared/allocTracer.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -25,7 +25,7 @@ #ifndef SHARE_GC_SHARED_ALLOCTRACER_HPP #define SHARE_GC_SHARED_ALLOCTRACER_HPP -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" #include "runtime/handles.hpp" class AllocTracer : AllStatic { diff --git a/src/hotspot/share/gc/shared/barrierSetNMethod.cpp b/src/hotspot/share/gc/shared/barrierSetNMethod.cpp index f98675d0b23d22bb685428697fae6dfa83fa4c05..efe2ff7b9e309e4a8c07a5de3b844466e2afe2ad 100644 --- a/src/hotspot/share/gc/shared/barrierSetNMethod.cpp +++ b/src/hotspot/share/gc/shared/barrierSetNMethod.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -28,6 +28,7 @@ #include "gc/shared/barrierSet.hpp" #include "gc/shared/barrierSetNMethod.hpp" #include "logging/log.hpp" +#include "runtime/frame.inline.hpp" #include "runtime/thread.hpp" #include "runtime/threadWXSetters.inline.hpp" #include "utilities/debug.hpp" @@ -54,6 +55,7 @@ int BarrierSetNMethod::nmethod_stub_entry_barrier(address* return_address_ptr) { MACOS_AARCH64_ONLY(ThreadWXEnable wx(WXWrite, Thread::current())); address return_address = *return_address_ptr; + AARCH64_PORT_ONLY(return_address = pauth_strip_pointer(return_address)); CodeBlob* cb = CodeCache::find_blob(return_address); assert(cb != NULL, "invariant"); diff --git a/src/hotspot/share/gc/shared/blockOffsetTable.cpp b/src/hotspot/share/gc/shared/blockOffsetTable.cpp index fb569a6b0a2fd69cb00232018cb496ec0f611848..2a4f3a48fa37158700ae00d13e66cf8e74bf3b4a 100644 --- a/src/hotspot/share/gc/shared/blockOffsetTable.cpp +++ b/src/hotspot/share/gc/shared/blockOffsetTable.cpp @@ -33,6 +33,18 @@ #include "runtime/java.hpp" #include "services/memTracker.hpp" +uint BOTConstants::_log_card_size = 0; +uint BOTConstants::_log_card_size_in_words = 0; +uint BOTConstants::_card_size = 0; +uint BOTConstants::_card_size_in_words = 0; + +void BOTConstants::initialize_bot_size(uint card_shift) { + _log_card_size = card_shift; + _log_card_size_in_words = _log_card_size - LogHeapWordSize; + _card_size = 1 << _log_card_size; + _card_size_in_words = 1 << _log_card_size_in_words; +} + ////////////////////////////////////////////////////////////////////// // BlockOffsetSharedArray ////////////////////////////////////////////////////////////////////// @@ -87,7 +99,7 @@ void BlockOffsetSharedArray::resize(size_t new_word_size) { bool BlockOffsetSharedArray::is_card_boundary(HeapWord* p) const { assert(p >= _reserved.start(), "just checking"); size_t delta = pointer_delta(p, _reserved.start()); - return (delta & right_n_bits((int)BOTConstants::LogN_words)) == (size_t)NoBits; + return (delta & right_n_bits((int)BOTConstants::log_card_size_in_words())) == (size_t)NoBits; } @@ -104,7 +116,7 @@ BlockOffsetArray::BlockOffsetArray(BlockOffsetSharedArray* array, set_init_to_zero(init_to_zero_); if (!init_to_zero_) { // initialize cards to point back to mr.start() - set_remainder_to_point_to_start(mr.start() + BOTConstants::N_words, mr.end()); + set_remainder_to_point_to_start(mr.start() + BOTConstants::card_size_in_words(), mr.end()); _array->set_offset_array(0, 0); // set first card to 0 } } @@ -160,7 +172,7 @@ set_remainder_to_point_to_start(HeapWord* start, HeapWord* end, bool reducing) { size_t start_card = _array->index_for(start); size_t end_card = _array->index_for(end-1); assert(start ==_array->address_for_index(start_card), "Precondition"); - assert(end ==_array->address_for_index(end_card)+BOTConstants::N_words, "Precondition"); + assert(end ==_array->address_for_index(end_card)+BOTConstants::card_size_in_words(), "Precondition"); set_remainder_to_point_to_start_incl(start_card, end_card, reducing); // closed interval } @@ -176,7 +188,7 @@ BlockOffsetArray::set_remainder_to_point_to_start_incl(size_t start_card, size_t return; } assert(start_card > _array->index_for(_bottom), "Cannot be first card"); - assert(_array->offset_array(start_card-1) <= BOTConstants::N_words, + assert(_array->offset_array(start_card-1) <= BOTConstants::card_size_in_words(), "Offset card has an unexpected value"); size_t start_card_for_region = start_card; u_char offset = max_jubyte; @@ -185,7 +197,7 @@ BlockOffsetArray::set_remainder_to_point_to_start_incl(size_t start_card, size_t // so that the reach ends in this region and not at the start // of the next. size_t reach = start_card - 1 + (BOTConstants::power_to_cards_back(i+1) - 1); - offset = BOTConstants::N_words + i; + offset = BOTConstants::card_size_in_words() + i; if (reach >= end_card) { _array->set_offset_array(start_card_for_region, end_card, offset, reducing); start_card_for_region = reach + 1; @@ -206,13 +218,13 @@ void BlockOffsetArray::check_all_cards(size_t start_card, size_t end_card) const if (end_card < start_card) { return; } - guarantee(_array->offset_array(start_card) == BOTConstants::N_words, "Wrong value in second card"); - u_char last_entry = BOTConstants::N_words; + guarantee(_array->offset_array(start_card) == BOTConstants::card_size_in_words(), "Wrong value in second card"); + u_char last_entry = BOTConstants::card_size_in_words(); for (size_t c = start_card + 1; c <= end_card; c++ /* yeah! */) { u_char entry = _array->offset_array(c); guarantee(entry >= last_entry, "Monotonicity"); if (c - start_card > BOTConstants::power_to_cards_back(1)) { - guarantee(entry > BOTConstants::N_words, "Should be in logarithmic region"); + guarantee(entry > BOTConstants::card_size_in_words(), "Should be in logarithmic region"); } size_t backskip = BOTConstants::entry_to_cards_back(entry); size_t landing_card = c - backskip; @@ -222,7 +234,7 @@ void BlockOffsetArray::check_all_cards(size_t start_card, size_t end_card) const } else { guarantee(landing_card == (start_card - 1), "Tautology"); // Note that N_words is the maximum offset value - guarantee(_array->offset_array(landing_card) <= BOTConstants::N_words, "Offset value"); + guarantee(_array->offset_array(landing_card) <= BOTConstants::card_size_in_words(), "Offset value"); } last_entry = entry; // remember for monotonicity test } @@ -236,14 +248,10 @@ BlockOffsetArray::alloc_block(HeapWord* blk_start, HeapWord* blk_end) { single_block(blk_start, blk_end); } -// Action_mark - update the BOT for the block [blk_start, blk_end). -// Current typical use is for splitting a block. -// Action_single - udpate the BOT for an allocation. -// Action_verify - BOT verification. void BlockOffsetArray::do_block_internal(HeapWord* blk_start, HeapWord* blk_end, - Action action, bool reducing) { + bool reducing) { assert(_sp->is_in_reserved(blk_start), "reference must be into the space"); assert(_sp->is_in_reserved(blk_end-1), @@ -254,7 +262,7 @@ BlockOffsetArray::do_block_internal(HeapWord* blk_start, uintptr_t start_ui = (uintptr_t)blk_start; // Calculate the last card boundary preceding end of blk intptr_t boundary_before_end = (intptr_t)end_ui; - clear_bits(boundary_before_end, right_n_bits((int)BOTConstants::LogN)); + clear_bits(boundary_before_end, right_n_bits((int)BOTConstants::log_card_size())); if (start_ui <= (uintptr_t)boundary_before_end) { // blk starts at or crosses a boundary // Calculate index of card on which blk begins @@ -267,38 +275,18 @@ BlockOffsetArray::do_block_internal(HeapWord* blk_start, if (blk_start != boundary) { // blk starts strictly after boundary // adjust card boundary and start_index forward to next card - boundary += BOTConstants::N_words; + boundary += BOTConstants::card_size_in_words(); start_index++; } assert(start_index <= end_index, "monotonicity of index_for()"); assert(boundary <= (HeapWord*)boundary_before_end, "tautology"); - switch (action) { - case Action_mark: { - if (init_to_zero()) { - _array->set_offset_array(start_index, boundary, blk_start, reducing); - break; - } // Else fall through to the next case - } - case Action_single: { - _array->set_offset_array(start_index, boundary, blk_start, reducing); - // We have finished marking the "offset card". We need to now - // mark the subsequent cards that this blk spans. - if (start_index < end_index) { - HeapWord* rem_st = _array->address_for_index(start_index) + BOTConstants::N_words; - HeapWord* rem_end = _array->address_for_index(end_index) + BOTConstants::N_words; - set_remainder_to_point_to_start(rem_st, rem_end, reducing); - } - break; - } - case Action_check: { - _array->check_offset_array(start_index, boundary, blk_start); - // We have finished checking the "offset card". We need to now - // check the subsequent cards that this blk spans. - check_all_cards(start_index + 1, end_index); - break; - } - default: - ShouldNotReachHere(); + _array->set_offset_array(start_index, boundary, blk_start, reducing); + // We have finished marking the "offset card". We need to now + // mark the subsequent cards that this blk spans. + if (start_index < end_index) { + HeapWord* rem_st = _array->address_for_index(start_index) + BOTConstants::card_size_in_words(); + HeapWord* rem_end = _array->address_for_index(end_index) + BOTConstants::card_size_in_words(); + set_remainder_to_point_to_start(rem_st, rem_end, reducing); } } } @@ -310,7 +298,7 @@ BlockOffsetArray::do_block_internal(HeapWord* blk_start, void BlockOffsetArray::single_block(HeapWord* blk_start, HeapWord* blk_end) { - do_block_internal(blk_start, blk_end, Action_single); + do_block_internal(blk_start, blk_end); } void BlockOffsetArray::verify() const { @@ -368,22 +356,22 @@ HeapWord* BlockOffsetArrayContigSpace::block_start_unsafe(const void* addr) cons HeapWord* q = _array->address_for_index(index); uint offset = _array->offset_array(index); // Extend u_char to uint. - while (offset > BOTConstants::N_words) { + while (offset > BOTConstants::card_size_in_words()) { // The excess of the offset from N_words indicates a power of Base // to go back by. size_t n_cards_back = BOTConstants::entry_to_cards_back(offset); - q -= (BOTConstants::N_words * n_cards_back); + q -= (BOTConstants::card_size_in_words() * n_cards_back); assert(q >= _sp->bottom(), "Went below bottom!"); index -= n_cards_back; offset = _array->offset_array(index); } - while (offset == BOTConstants::N_words) { + while (offset == BOTConstants::card_size_in_words()) { assert(q >= _sp->bottom(), "Went below bottom!"); - q -= BOTConstants::N_words; + q -= BOTConstants::card_size_in_words(); index--; offset = _array->offset_array(index); } - assert(offset < BOTConstants::N_words, "offset too large"); + assert(offset < BOTConstants::card_size_in_words(), "offset too large"); q -= offset; HeapWord* n = q; @@ -416,14 +404,14 @@ void BlockOffsetArrayContigSpace::alloc_block_work(HeapWord* blk_start, "should be past threshold"); assert(blk_start <= _next_offset_threshold, "blk_start should be at or before threshold"); - assert(pointer_delta(_next_offset_threshold, blk_start) <= BOTConstants::N_words, + assert(pointer_delta(_next_offset_threshold, blk_start) <= BOTConstants::card_size_in_words(), "offset should be <= BlockOffsetSharedArray::N"); assert(_sp->is_in_reserved(blk_start), "reference must be into the space"); assert(_sp->is_in_reserved(blk_end-1), "limit must be within the space"); assert(_next_offset_threshold == - _array->_reserved.start() + _next_offset_index*BOTConstants::N_words, + _array->_reserved.start() + _next_offset_index*BOTConstants::card_size_in_words(), "index must agree with threshold"); debug_only(size_t orig_next_offset_index = _next_offset_index;) @@ -445,7 +433,7 @@ void BlockOffsetArrayContigSpace::alloc_block_work(HeapWord* blk_start, HeapWord* rem_st = _array->address_for_index(_next_offset_index + 1); // Calculate rem_end this way because end_index // may be the last valid index in the covered region. - HeapWord* rem_end = _array->address_for_index(end_index) + BOTConstants::N_words; + HeapWord* rem_end = _array->address_for_index(end_index) + BOTConstants::card_size_in_words(); set_remainder_to_point_to_start(rem_st, rem_end); } @@ -453,7 +441,7 @@ void BlockOffsetArrayContigSpace::alloc_block_work(HeapWord* blk_start, _next_offset_index = end_index + 1; // Calculate _next_offset_threshold this way because end_index // may be the last valid index in the covered region. - _next_offset_threshold = _array->address_for_index(end_index) + BOTConstants::N_words; + _next_offset_threshold = _array->address_for_index(end_index) + BOTConstants::card_size_in_words(); assert(_next_offset_threshold >= blk_end, "Incorrect offset threshold"); #ifdef ASSERT @@ -464,11 +452,11 @@ void BlockOffsetArrayContigSpace::alloc_block_work(HeapWord* blk_start, assert((_array->offset_array(orig_next_offset_index) == 0 && blk_start == boundary) || (_array->offset_array(orig_next_offset_index) > 0 && - _array->offset_array(orig_next_offset_index) <= BOTConstants::N_words), + _array->offset_array(orig_next_offset_index) <= BOTConstants::card_size_in_words()), "offset array should have been set"); for (size_t j = orig_next_offset_index + 1; j <= end_index; j++) { assert(_array->offset_array(j) > 0 && - _array->offset_array(j) <= (u_char) (BOTConstants::N_words+BOTConstants::N_powers-1), + _array->offset_array(j) <= (u_char) (BOTConstants::card_size_in_words()+BOTConstants::N_powers-1), "offset array should have been set"); } #endif diff --git a/src/hotspot/share/gc/shared/blockOffsetTable.hpp b/src/hotspot/share/gc/shared/blockOffsetTable.hpp index 5e60bfe63a43e945ab2f8d83d3198beafa8a903f..6adc224876da21e137de1390020adcc93e17d2fb 100644 --- a/src/hotspot/share/gc/shared/blockOffsetTable.hpp +++ b/src/hotspot/share/gc/shared/blockOffsetTable.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -27,7 +27,8 @@ #include "gc/shared/gc_globals.hpp" #include "gc/shared/memset_with_concurrent_readers.hpp" -#include "memory/allocation.hpp" +#include "gc/shared/cardTable.hpp" +#include "memory/allStatic.hpp" #include "memory/memRegion.hpp" #include "memory/virtualspace.hpp" #include "runtime/globals.hpp" @@ -48,30 +49,40 @@ class ContiguousSpace; class BOTConstants : public AllStatic { + static uint _log_card_size; + static uint _log_card_size_in_words; + static uint _card_size; + static uint _card_size_in_words; + public: - static const uint LogN = 9; - static const uint LogN_words = LogN - LogHeapWordSize; - static const uint N_bytes = 1 << LogN; - static const uint N_words = 1 << LogN_words; // entries "e" of at least N_words mean "go back by Base^(e-N_words)." // All entries are less than "N_words + N_powers". static const uint LogBase = 4; static const uint Base = (1 << LogBase); static const uint N_powers = 14; + // Initialize bot size based on card size + static void initialize_bot_size(uint card_shift); + static size_t power_to_cards_back(uint i) { return (size_t)1 << (LogBase * i); } - static size_t power_to_words_back(uint i) { - return power_to_cards_back(i) * N_words; - } + static size_t entry_to_cards_back(u_char entry) { - assert(entry >= N_words, "Precondition"); - return power_to_cards_back(entry - N_words); + assert(entry >= _card_size_in_words, "Precondition"); + return power_to_cards_back(entry - _card_size_in_words); } - static size_t entry_to_words_back(u_char entry) { - assert(entry >= N_words, "Precondition"); - return power_to_words_back(entry - N_words); + static uint log_card_size() { + return _log_card_size; + } + static uint log_card_size_in_words() { + return _log_card_size_in_words; + } + static uint card_size() { + return _card_size; + } + static uint card_size_in_words() { + return _card_size_in_words; } }; @@ -93,6 +104,7 @@ public: BlockOffsetTable(HeapWord* bottom, HeapWord* end): _bottom(bottom), _end(end) { assert(_bottom <= _end, "arguments out of order"); + assert(BOTConstants::card_size() == CardTable::card_size(), "sanity"); } // Note that the committed size of the covered space may have changed, @@ -179,7 +191,7 @@ class BlockOffsetSharedArray: public CHeapObj { check_reducing_assertion(reducing); assert(index < _vs.committed_size(), "index out of range"); assert(high >= low, "addresses out of order"); - assert(pointer_delta(high, low) <= BOTConstants::N_words, "offset too large"); + assert(pointer_delta(high, low) <= BOTConstants::card_size_in_words(), "offset too large"); assert(!reducing || _offset_array[index] >= (u_char)pointer_delta(high, low), "Not reducing"); _offset_array[index] = (u_char)pointer_delta(high, low); @@ -190,7 +202,7 @@ class BlockOffsetSharedArray: public CHeapObj { assert(index_for(right - 1) < _vs.committed_size(), "right address out of range"); assert(left < right, "Heap addresses out of order"); - size_t num_cards = pointer_delta(right, left) >> BOTConstants::LogN_words; + size_t num_cards = pointer_delta(right, left) >> BOTConstants::log_card_size_in_words(); fill_range(index_for(left), num_cards, offset); } @@ -207,7 +219,7 @@ class BlockOffsetSharedArray: public CHeapObj { void check_offset_array(size_t index, HeapWord* high, HeapWord* low) const { assert(index < _vs.committed_size(), "index out of range"); assert(high >= low, "addresses out of order"); - assert(pointer_delta(high, low) <= BOTConstants::N_words, "offset too large"); + assert(pointer_delta(high, low) <= BOTConstants::card_size_in_words(), "offset too large"); assert(_offset_array[index] == pointer_delta(high, low), "Wrong offset"); } @@ -222,7 +234,7 @@ class BlockOffsetSharedArray: public CHeapObj { // to be reserved. size_t compute_size(size_t mem_region_words) { - size_t number_of_slots = (mem_region_words / BOTConstants::N_words) + 1; + size_t number_of_slots = (mem_region_words / BOTConstants::card_size_in_words()) + 1; return ReservedSpace::allocation_align_size_up(number_of_slots); } @@ -267,14 +279,6 @@ class Space; class BlockOffsetArray: public BlockOffsetTable { friend class VMStructs; protected: - // The following enums are used by do_block_internal() below - enum Action { - Action_single, // BOT records a single block (see single_block()) - Action_mark, // BOT marks the start of a block (see mark_block()) - Action_check // Check that BOT records block correctly - // (see verify_single_block()). - }; - // The shared array, which is shared with other BlockOffsetArray's // corresponding to different spaces within a generation or span of // memory. @@ -303,7 +307,7 @@ class BlockOffsetArray: public BlockOffsetTable { void set_remainder_to_point_to_start_incl(size_t start, size_t end, bool reducing = false); // A helper function for BOT adjustment/verification work - void do_block_internal(HeapWord* blk_start, HeapWord* blk_end, Action action, bool reducing = false); + void do_block_internal(HeapWord* blk_start, HeapWord* blk_end, bool reducing = false); public: // The space may not have its bottom and top set yet, which is why the @@ -336,7 +340,7 @@ class BlockOffsetArray: public BlockOffsetTable { assert(_array->is_card_boundary(new_end), "new _end would not be a card boundary"); // set all the newly added cards - _array->set_offset_array(_end, new_end, BOTConstants::N_words); + _array->set_offset_array(_end, new_end, BOTConstants::card_size_in_words()); } _end = new_end; // update _end } diff --git a/src/hotspot/share/gc/shared/blockOffsetTable.inline.hpp b/src/hotspot/share/gc/shared/blockOffsetTable.inline.hpp index ceb852b4ffc4a5b21eb9e07e8a90dc450d908475..abaa0dade46e127723d4e3b2a916a7ab0c1ce0ef 100644 --- a/src/hotspot/share/gc/shared/blockOffsetTable.inline.hpp +++ b/src/hotspot/share/gc/shared/blockOffsetTable.inline.hpp @@ -50,14 +50,14 @@ inline size_t BlockOffsetSharedArray::index_for(const void* p) const { pc < (char*)_reserved.end(), "p not in range."); size_t delta = pointer_delta(pc, _reserved.start(), sizeof(char)); - size_t result = delta >> BOTConstants::LogN; + size_t result = delta >> BOTConstants::log_card_size(); assert(result < _vs.committed_size(), "bad index from address"); return result; } inline HeapWord* BlockOffsetSharedArray::address_for_index(size_t index) const { assert(index < _vs.committed_size(), "bad index"); - HeapWord* result = _reserved.start() + (index << BOTConstants::LogN_words); + HeapWord* result = _reserved.start() + (index << BOTConstants::log_card_size_in_words()); assert(result >= _reserved.start() && result < _reserved.end(), "bad address from index"); return result; diff --git a/src/hotspot/share/gc/g1/g1BufferNodeList.cpp b/src/hotspot/share/gc/shared/bufferNodeList.cpp similarity index 80% rename from src/hotspot/share/gc/g1/g1BufferNodeList.cpp rename to src/hotspot/share/gc/shared/bufferNodeList.cpp index 3b89b0c7cd7a72c7ecd5a4c6688b476706fb62a2..bcf4b42ec967bdb3cdc334dd8cebc69ff608d854 100644 --- a/src/hotspot/share/gc/g1/g1BufferNodeList.cpp +++ b/src/hotspot/share/gc/shared/bufferNodeList.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -23,15 +23,15 @@ */ #include "precompiled.hpp" -#include "gc/g1/g1BufferNodeList.hpp" +#include "gc/shared/bufferNodeList.hpp" #include "utilities/debug.hpp" -G1BufferNodeList::G1BufferNodeList() : +BufferNodeList::BufferNodeList() : _head(NULL), _tail(NULL), _entry_count(0) {} -G1BufferNodeList::G1BufferNodeList(BufferNode* head, - BufferNode* tail, - size_t entry_count) : +BufferNodeList::BufferNodeList(BufferNode* head, + BufferNode* tail, + size_t entry_count) : _head(head), _tail(tail), _entry_count(entry_count) { assert((_head == NULL) == (_tail == NULL), "invariant"); diff --git a/src/hotspot/share/gc/g1/g1BufferNodeList.hpp b/src/hotspot/share/gc/shared/bufferNodeList.hpp similarity index 79% rename from src/hotspot/share/gc/g1/g1BufferNodeList.hpp rename to src/hotspot/share/gc/shared/bufferNodeList.hpp index 785c3118f9b8897420401d90fb2e79486c066d3b..ae66a1fcc7142f45e0f14f4452fb4f5131b467cf 100644 --- a/src/hotspot/share/gc/g1/g1BufferNodeList.hpp +++ b/src/hotspot/share/gc/shared/bufferNodeList.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -22,21 +22,20 @@ * */ -#ifndef SHARE_GC_G1_G1BUFFERNODELIST_HPP -#define SHARE_GC_G1_G1BUFFERNODELIST_HPP +#ifndef SHARE_GC_SHARED_BUFFERNODELIST_HPP +#define SHARE_GC_SHARED_BUFFERNODELIST_HPP #include "utilities/globalDefinitions.hpp" class BufferNode; -struct G1BufferNodeList { +struct BufferNodeList { BufferNode* _head; // First node in list or NULL if empty. BufferNode* _tail; // Last node in list or NULL if empty. size_t _entry_count; // Sum of entries in nodes in list. - G1BufferNodeList(); - G1BufferNodeList(BufferNode* head, BufferNode* tail, size_t entry_count); + BufferNodeList(); + BufferNodeList(BufferNode* head, BufferNode* tail, size_t entry_count); }; -#endif // SHARE_GC_G1_G1BUFFERNODELIST_HPP - +#endif // SHARE_GC_SHARED_BUFFERNODELIST_HPP diff --git a/src/hotspot/share/gc/shared/c1/barrierSetC1.cpp b/src/hotspot/share/gc/shared/c1/barrierSetC1.cpp index 663ff91372b5879c85ac8a326a32d6d23b934f57..b1828fcdb178a69e0187eb407e911ffcf7bc3582 100644 --- a/src/hotspot/share/gc/shared/c1/barrierSetC1.cpp +++ b/src/hotspot/share/gc/shared/c1/barrierSetC1.cpp @@ -334,7 +334,7 @@ void BarrierSetC1::generate_referent_check(LIRAccess& access, LabelObj* cont) { if (gen_type_check) { // We have determined that offset == referent_offset && src != null. // if (src->_klass->_reference_type == REF_NONE) -> continue - __ move(new LIR_Address(base_reg, oopDesc::klass_offset_in_bytes(), T_ADDRESS), src_klass); + gen->load_klass(base_reg, src_klass, NULL); LIR_Address* reference_type_addr = new LIR_Address(src_klass, in_bytes(InstanceKlass::reference_type_offset()), T_BYTE); LIR_Opr reference_type = gen->new_register(T_INT); __ move(reference_type_addr, reference_type); diff --git a/src/hotspot/share/gc/shared/c1/cardTableBarrierSetC1.cpp b/src/hotspot/share/gc/shared/c1/cardTableBarrierSetC1.cpp index b66e94836ed43bf661ccd6ff87425f5c2692d7a5..660c324aa99b3dcf70620387ec1c7693bed98b70 100644 --- a/src/hotspot/share/gc/shared/c1/cardTableBarrierSetC1.cpp +++ b/src/hotspot/share/gc/shared/c1/cardTableBarrierSetC1.cpp @@ -69,9 +69,9 @@ void CardTableBarrierSetC1::post_barrier(LIRAccess& access, LIR_Opr addr, LIR_Op if (TwoOperandLIRForm) { LIR_Opr addr_opr = LIR_OprFact::address(new LIR_Address(addr, addr->type())); __ leal(addr_opr, tmp); - __ unsigned_shift_right(tmp, CardTable::card_shift, tmp); + __ unsigned_shift_right(tmp, CardTable::card_shift(), tmp); } else { - __ unsigned_shift_right(addr, CardTable::card_shift, tmp); + __ unsigned_shift_right(addr, CardTable::card_shift(), tmp); } LIR_Address* card_addr; diff --git a/src/hotspot/share/gc/shared/c2/barrierSetC2.cpp b/src/hotspot/share/gc/shared/c2/barrierSetC2.cpp index c89643a78811d2d228cad39bc5a966032e61be25..a90565ef705ee4360d5d1ff07f4d50026ecf00dd 100644 --- a/src/hotspot/share/gc/shared/c2/barrierSetC2.cpp +++ b/src/hotspot/share/gc/shared/c2/barrierSetC2.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -96,7 +96,7 @@ Node* BarrierSetC2::store_at_resolved(C2Access& access, C2AccessValue& val) cons GraphKit* kit = parse_access.kit(); if (access.type() == T_DOUBLE) { - Node* new_val = kit->dstore_rounding(val.node()); + Node* new_val = kit->dprecision_rounding(val.node()); val.set_node(new_val); } diff --git a/src/hotspot/share/gc/shared/c2/cardTableBarrierSetC2.cpp b/src/hotspot/share/gc/shared/c2/cardTableBarrierSetC2.cpp index 73ea620041b8672930cc13e98f555b8e36c971ea..0a7a032c117edb81203c33e777ce7f3690fe68b0 100644 --- a/src/hotspot/share/gc/shared/c2/cardTableBarrierSetC2.cpp +++ b/src/hotspot/share/gc/shared/c2/cardTableBarrierSetC2.cpp @@ -91,7 +91,7 @@ void CardTableBarrierSetC2::post_barrier(GraphKit* kit, Node* cast = __ CastPX(__ ctrl(), adr); // Divide by card size - Node* card_offset = __ URShiftX(cast, __ ConI(CardTable::card_shift)); + Node* card_offset = __ URShiftX(cast, __ ConI(CardTable::card_shift())); // Combine card table base and card offset Node* card_adr = __ AddP(__ top(), byte_map_base_node(kit), card_offset); diff --git a/src/hotspot/share/gc/shared/cardGeneration.cpp b/src/hotspot/share/gc/shared/cardGeneration.cpp deleted file mode 100644 index 8f691c3c46cec80a7188b4fb6886f553b90fe8db..0000000000000000000000000000000000000000 --- a/src/hotspot/share/gc/shared/cardGeneration.cpp +++ /dev/null @@ -1,326 +0,0 @@ -/* - * Copyright (c) 2014, 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/blockOffsetTable.inline.hpp" -#include "gc/shared/cardGeneration.inline.hpp" -#include "gc/shared/cardTableRS.hpp" -#include "gc/shared/gcLocker.hpp" -#include "gc/shared/genCollectedHeap.hpp" -#include "gc/shared/genOopClosures.inline.hpp" -#include "gc/shared/generationSpec.hpp" -#include "gc/shared/space.inline.hpp" -#include "memory/iterator.hpp" -#include "memory/memRegion.hpp" -#include "logging/log.hpp" -#include "runtime/java.hpp" - -CardGeneration::CardGeneration(ReservedSpace rs, - size_t initial_byte_size, - CardTableRS* remset) : - Generation(rs, initial_byte_size), _rs(remset), - _min_heap_delta_bytes(), _capacity_at_prologue(), - _used_at_prologue() -{ - // If we don't shrink the heap in steps, '_shrink_factor' is always 100%. - _shrink_factor = ShrinkHeapInSteps ? 0 : 100; - HeapWord* start = (HeapWord*)rs.base(); - size_t reserved_byte_size = rs.size(); - assert((uintptr_t(start) & 3) == 0, "bad alignment"); - assert((reserved_byte_size & 3) == 0, "bad alignment"); - MemRegion reserved_mr(start, heap_word_size(reserved_byte_size)); - _bts = new BlockOffsetSharedArray(reserved_mr, - heap_word_size(initial_byte_size)); - MemRegion committed_mr(start, heap_word_size(initial_byte_size)); - _rs->resize_covered_region(committed_mr); - - // Verify that the start and end of this generation is the start of a card. - // If this wasn't true, a single card could span more than on generation, - // which would cause problems when we commit/uncommit memory, and when we - // clear and dirty cards. - guarantee(_rs->is_aligned(reserved_mr.start()), "generation must be card aligned"); - if (reserved_mr.end() != GenCollectedHeap::heap()->reserved_region().end()) { - // Don't check at the very end of the heap as we'll assert that we're probing off - // the end if we try. - guarantee(_rs->is_aligned(reserved_mr.end()), "generation must be card aligned"); - } - _min_heap_delta_bytes = MinHeapDeltaBytes; - _capacity_at_prologue = initial_byte_size; - _used_at_prologue = 0; -} - -bool CardGeneration::grow_by(size_t bytes) { - assert_correct_size_change_locking(); - bool result = _virtual_space.expand_by(bytes); - if (result) { - size_t new_word_size = - heap_word_size(_virtual_space.committed_size()); - MemRegion mr(space()->bottom(), new_word_size); - // Expand card table - GenCollectedHeap::heap()->rem_set()->resize_covered_region(mr); - // Expand shared block offset array - _bts->resize(new_word_size); - - // Fix for bug #4668531 - if (ZapUnusedHeapArea) { - MemRegion mangle_region(space()->end(), - (HeapWord*)_virtual_space.high()); - SpaceMangler::mangle_region(mangle_region); - } - - // Expand space -- also expands space's BOT - // (which uses (part of) shared array above) - space()->set_end((HeapWord*)_virtual_space.high()); - - // update the space and generation capacity counters - update_counters(); - - size_t new_mem_size = _virtual_space.committed_size(); - size_t old_mem_size = new_mem_size - bytes; - log_trace(gc, heap)("Expanding %s from " SIZE_FORMAT "K by " SIZE_FORMAT "K to " SIZE_FORMAT "K", - name(), old_mem_size/K, bytes/K, new_mem_size/K); - } - return result; -} - -bool CardGeneration::expand(size_t bytes, size_t expand_bytes) { - assert_locked_or_safepoint(Heap_lock); - if (bytes == 0) { - return true; // That's what grow_by(0) would return - } - size_t aligned_bytes = ReservedSpace::page_align_size_up(bytes); - if (aligned_bytes == 0){ - // The alignment caused the number of bytes to wrap. An expand_by(0) will - // return true with the implication that an expansion was done when it - // was not. A call to expand implies a best effort to expand by "bytes" - // but not a guarantee. Align down to give a best effort. This is likely - // the most that the generation can expand since it has some capacity to - // start with. - aligned_bytes = ReservedSpace::page_align_size_down(bytes); - } - size_t aligned_expand_bytes = ReservedSpace::page_align_size_up(expand_bytes); - bool success = false; - if (aligned_expand_bytes > aligned_bytes) { - success = grow_by(aligned_expand_bytes); - } - if (!success) { - success = grow_by(aligned_bytes); - } - if (!success) { - success = grow_to_reserved(); - } - if (success && GCLocker::is_active_and_needs_gc()) { - log_trace(gc, heap)("Garbage collection disabled, expanded heap instead"); - } - - return success; -} - -bool CardGeneration::grow_to_reserved() { - assert_correct_size_change_locking(); - bool success = true; - const size_t remaining_bytes = _virtual_space.uncommitted_size(); - if (remaining_bytes > 0) { - success = grow_by(remaining_bytes); - DEBUG_ONLY(if (!success) log_warning(gc)("grow to reserved failed");) - } - return success; -} - -void CardGeneration::shrink(size_t bytes) { - assert_correct_size_change_locking(); - - size_t size = ReservedSpace::page_align_size_down(bytes); - if (size == 0) { - return; - } - - // Shrink committed space - _virtual_space.shrink_by(size); - // Shrink space; this also shrinks the space's BOT - space()->set_end((HeapWord*) _virtual_space.high()); - size_t new_word_size = heap_word_size(space()->capacity()); - // Shrink the shared block offset array - _bts->resize(new_word_size); - MemRegion mr(space()->bottom(), new_word_size); - // Shrink the card table - GenCollectedHeap::heap()->rem_set()->resize_covered_region(mr); - - size_t new_mem_size = _virtual_space.committed_size(); - size_t old_mem_size = new_mem_size + size; - log_trace(gc, heap)("Shrinking %s from " SIZE_FORMAT "K to " SIZE_FORMAT "K", - name(), old_mem_size/K, new_mem_size/K); -} - -// No young generation references, clear this generation's cards. -void CardGeneration::clear_remembered_set() { - _rs->clear(reserved()); -} - -// Objects in this generation may have moved, invalidate this -// generation's cards. -void CardGeneration::invalidate_remembered_set() { - _rs->invalidate(used_region()); -} - -void CardGeneration::compute_new_size() { - assert(_shrink_factor <= 100, "invalid shrink factor"); - size_t current_shrink_factor = _shrink_factor; - if (ShrinkHeapInSteps) { - // Always reset '_shrink_factor' if the heap is shrunk in steps. - // If we shrink the heap in this iteration, '_shrink_factor' will - // be recomputed based on the old value further down in this fuction. - _shrink_factor = 0; - } - - // We don't have floating point command-line arguments - // Note: argument processing ensures that MinHeapFreeRatio < 100. - const double minimum_free_percentage = MinHeapFreeRatio / 100.0; - const double maximum_used_percentage = 1.0 - minimum_free_percentage; - - // Compute some numbers about the state of the heap. - const size_t used_after_gc = used(); - const size_t capacity_after_gc = capacity(); - - const double min_tmp = used_after_gc / maximum_used_percentage; - size_t minimum_desired_capacity = (size_t)MIN2(min_tmp, double(max_uintx)); - // Don't shrink less than the initial generation size - minimum_desired_capacity = MAX2(minimum_desired_capacity, initial_size()); - assert(used_after_gc <= minimum_desired_capacity, "sanity check"); - - const size_t free_after_gc = free(); - const double free_percentage = ((double)free_after_gc) / capacity_after_gc; - log_trace(gc, heap)("CardGeneration::compute_new_size:"); - log_trace(gc, heap)(" minimum_free_percentage: %6.2f maximum_used_percentage: %6.2f", - minimum_free_percentage, - maximum_used_percentage); - log_trace(gc, heap)(" free_after_gc : %6.1fK used_after_gc : %6.1fK capacity_after_gc : %6.1fK", - free_after_gc / (double) K, - used_after_gc / (double) K, - capacity_after_gc / (double) K); - log_trace(gc, heap)(" free_percentage: %6.2f", free_percentage); - - if (capacity_after_gc < minimum_desired_capacity) { - // If we have less free space than we want then expand - size_t expand_bytes = minimum_desired_capacity - capacity_after_gc; - // Don't expand unless it's significant - if (expand_bytes >= _min_heap_delta_bytes) { - expand(expand_bytes, 0); // safe if expansion fails - } - log_trace(gc, heap)(" expanding: minimum_desired_capacity: %6.1fK expand_bytes: %6.1fK _min_heap_delta_bytes: %6.1fK", - minimum_desired_capacity / (double) K, - expand_bytes / (double) K, - _min_heap_delta_bytes / (double) K); - return; - } - - // No expansion, now see if we want to shrink - size_t shrink_bytes = 0; - // We would never want to shrink more than this - size_t max_shrink_bytes = capacity_after_gc - minimum_desired_capacity; - - if (MaxHeapFreeRatio < 100) { - const double maximum_free_percentage = MaxHeapFreeRatio / 100.0; - const double minimum_used_percentage = 1.0 - maximum_free_percentage; - const double max_tmp = used_after_gc / minimum_used_percentage; - size_t maximum_desired_capacity = (size_t)MIN2(max_tmp, double(max_uintx)); - maximum_desired_capacity = MAX2(maximum_desired_capacity, initial_size()); - log_trace(gc, heap)(" maximum_free_percentage: %6.2f minimum_used_percentage: %6.2f", - maximum_free_percentage, minimum_used_percentage); - log_trace(gc, heap)(" _capacity_at_prologue: %6.1fK minimum_desired_capacity: %6.1fK maximum_desired_capacity: %6.1fK", - _capacity_at_prologue / (double) K, - minimum_desired_capacity / (double) K, - maximum_desired_capacity / (double) K); - assert(minimum_desired_capacity <= maximum_desired_capacity, - "sanity check"); - - if (capacity_after_gc > maximum_desired_capacity) { - // Capacity too large, compute shrinking size - shrink_bytes = capacity_after_gc - maximum_desired_capacity; - if (ShrinkHeapInSteps) { - // If ShrinkHeapInSteps is true (the default), - // we don't want to shrink all the way back to initSize if people call - // System.gc(), because some programs do that between "phases" and then - // we'd just have to grow the heap up again for the next phase. So we - // damp the shrinking: 0% on the first call, 10% on the second call, 40% - // on the third call, and 100% by the fourth call. But if we recompute - // size without shrinking, it goes back to 0%. - shrink_bytes = shrink_bytes / 100 * current_shrink_factor; - if (current_shrink_factor == 0) { - _shrink_factor = 10; - } else { - _shrink_factor = MIN2(current_shrink_factor * 4, (size_t) 100); - } - } - assert(shrink_bytes <= max_shrink_bytes, "invalid shrink size"); - log_trace(gc, heap)(" shrinking: initSize: %.1fK maximum_desired_capacity: %.1fK", - initial_size() / (double) K, maximum_desired_capacity / (double) K); - log_trace(gc, heap)(" shrink_bytes: %.1fK current_shrink_factor: " SIZE_FORMAT " new shrink factor: " SIZE_FORMAT " _min_heap_delta_bytes: %.1fK", - shrink_bytes / (double) K, - current_shrink_factor, - _shrink_factor, - _min_heap_delta_bytes / (double) K); - } - } - - if (capacity_after_gc > _capacity_at_prologue) { - // We might have expanded for promotions, in which case we might want to - // take back that expansion if there's room after GC. That keeps us from - // stretching the heap with promotions when there's plenty of room. - size_t expansion_for_promotion = capacity_after_gc - _capacity_at_prologue; - expansion_for_promotion = MIN2(expansion_for_promotion, max_shrink_bytes); - // We have two shrinking computations, take the largest - shrink_bytes = MAX2(shrink_bytes, expansion_for_promotion); - assert(shrink_bytes <= max_shrink_bytes, "invalid shrink size"); - log_trace(gc, heap)(" aggressive shrinking: _capacity_at_prologue: %.1fK capacity_after_gc: %.1fK expansion_for_promotion: %.1fK shrink_bytes: %.1fK", - capacity_after_gc / (double) K, - _capacity_at_prologue / (double) K, - expansion_for_promotion / (double) K, - shrink_bytes / (double) K); - } - // Don't shrink unless it's significant - if (shrink_bytes >= _min_heap_delta_bytes) { - shrink(shrink_bytes); - } -} - -// Currently nothing to do. -void CardGeneration::prepare_for_verify() {} - -void CardGeneration::space_iterate(SpaceClosure* blk, - bool usedOnly) { - blk->do_space(space()); -} - -void CardGeneration::younger_refs_iterate(OopIterateClosure* blk) { - // Apply "cl->do_oop" to (the address of) (exactly) all the ref fields in - // "sp" that point into the young generation. - // The iteration is only over objects allocated at the start of the - // iterations; objects allocated as a result of applying the closure are - // not included. - - HeapWord* gen_boundary = reserved().start(); - _rs->younger_refs_in_space_iterate(space(), gen_boundary, blk); -} diff --git a/src/hotspot/share/gc/shared/cardGeneration.hpp b/src/hotspot/share/gc/shared/cardGeneration.hpp deleted file mode 100644 index 7ad58cf2b699c120ce4bb6832e453e06a29c3165..0000000000000000000000000000000000000000 --- a/src/hotspot/share/gc/shared/cardGeneration.hpp +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (c) 2014, 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_SHARED_CARDGENERATION_HPP -#define SHARE_GC_SHARED_CARDGENERATION_HPP - -// Class CardGeneration is a generation that is covered by a card table, -// and uses a card-size block-offset array to implement block_start. - -#include "gc/shared/generation.hpp" - -class BlockOffsetSharedArray; -class CardTableRS; -class CompactibleSpace; - -class CardGeneration: public Generation { - friend class VMStructs; - protected: - // This is shared with other generations. - CardTableRS* _rs; - // This is local to this generation. - BlockOffsetSharedArray* _bts; - - // Current shrinking effect: this damps shrinking when the heap gets empty. - size_t _shrink_factor; - - size_t _min_heap_delta_bytes; // Minimum amount to expand. - - // Some statistics from before gc started. - // These are gathered in the gc_prologue (and should_collect) - // to control growing/shrinking policy in spite of promotions. - size_t _capacity_at_prologue; - size_t _used_at_prologue; - - CardGeneration(ReservedSpace rs, size_t initial_byte_size, CardTableRS* remset); - - virtual void assert_correct_size_change_locking() = 0; - - virtual CompactibleSpace* space() const = 0; - - public: - - // Attempt to expand the generation by "bytes". Expand by at a - // minimum "expand_bytes". Return true if some amount (not - // necessarily the full "bytes") was done. - virtual bool expand(size_t bytes, size_t expand_bytes); - - // Shrink generation with specified size - virtual void shrink(size_t bytes); - - virtual void compute_new_size(); - - virtual void clear_remembered_set(); - - virtual void invalidate_remembered_set(); - - virtual void prepare_for_verify(); - - // Grow generation with specified size (returns false if unable to grow) - bool grow_by(size_t bytes); - // Grow generation to reserved size. - bool grow_to_reserved(); - - size_t capacity() const; - size_t used() const; - size_t free() const; - MemRegion used_region() const; - - void space_iterate(SpaceClosure* blk, bool usedOnly = false); - - void younger_refs_iterate(OopIterateClosure* blk); - - bool is_in(const void* p) const; - - CompactibleSpace* first_compaction_space() const; -}; - -#endif // SHARE_GC_SHARED_CARDGENERATION_HPP diff --git a/src/hotspot/share/gc/shared/cardTable.cpp b/src/hotspot/share/gc/shared/cardTable.cpp index 2728e27828642cf0ee4fd65bf12871ed415688d3..cd991af6211b6a100aa13f38e1af14d60974540f 100644 --- a/src/hotspot/share/gc/shared/cardTable.cpp +++ b/src/hotspot/share/gc/shared/cardTable.cpp @@ -25,6 +25,8 @@ #include "precompiled.hpp" #include "gc/shared/cardTable.hpp" #include "gc/shared/collectedHeap.hpp" +#include "gc/shared/gcLogPrecious.hpp" +#include "gc/shared/gc_globals.hpp" #include "gc/shared/space.inline.hpp" #include "logging/log.hpp" #include "memory/virtualspace.hpp" @@ -32,6 +34,32 @@ #include "runtime/os.hpp" #include "services/memTracker.hpp" #include "utilities/align.hpp" +#if INCLUDE_PARALLELGC +#include "gc/parallel/objectStartArray.hpp" +#endif + +uint CardTable::_card_shift = 0; +uint CardTable::_card_size = 0; +uint CardTable::_card_size_in_words = 0; + +void CardTable::initialize_card_size() { + assert(UseG1GC || UseParallelGC || UseSerialGC, + "Initialize card size should only be called by card based collectors."); + + _card_size = GCCardSizeInBytes; + _card_shift = log2i_exact(_card_size); + _card_size_in_words = _card_size / sizeof(HeapWord); + + // Set blockOffsetTable size based on card table entry size + BOTConstants::initialize_bot_size(_card_shift); + +#if INCLUDE_PARALLELGC + // Set ObjectStartArray block size based on card table entry size + ObjectStartArray::initialize_block_size(_card_shift); +#endif + + log_info_p(gc, init)("CardTable entry size: " UINT32_FORMAT, _card_size); +} size_t CardTable::compute_byte_map_size() { assert(_guard_index == cards_required(_whole_heap.word_size()) - 1, @@ -54,10 +82,8 @@ CardTable::CardTable(MemRegion whole_heap) : _committed(MemRegion::create_array(_max_covered_regions, mtGC)), _guard_region() { - assert((uintptr_t(_whole_heap.start()) & (card_size - 1)) == 0, "heap must start at card boundary"); - assert((uintptr_t(_whole_heap.end()) & (card_size - 1)) == 0, "heap must end at card boundary"); - - assert(card_size <= 512, "card_size must be less than 512"); // why? + assert((uintptr_t(_whole_heap.start()) & (_card_size - 1)) == 0, "heap must start at card boundary"); + assert((uintptr_t(_whole_heap.end()) & (_card_size - 1)) == 0, "heap must end at card boundary"); } CardTable::~CardTable() { @@ -94,7 +120,7 @@ void CardTable::initialize() { // // _byte_map = _byte_map_base + (uintptr_t(low_bound) >> card_shift) _byte_map = (CardValue*) heap_rs.base(); - _byte_map_base = _byte_map - (uintptr_t(low_bound) >> card_shift); + _byte_map_base = _byte_map - (uintptr_t(low_bound) >> _card_shift); assert(byte_for(low_bound) == &_byte_map[0], "Checking start of map"); assert(byte_for(high_bound-1) <= &_byte_map[_last_valid_index], "Checking end of map"); @@ -136,16 +162,6 @@ int CardTable::find_covering_region_by_base(HeapWord* base) { return res; } -int CardTable::find_covering_region_containing(HeapWord* addr) { - for (int i = 0; i < _cur_covered_regions; i++) { - if (_covered[i].contains(addr)) { - return i; - } - } - assert(0, "address outside of heap?"); - return -1; -} - HeapWord* CardTable::largest_prev_committed_end(int ind) const { HeapWord* max_end = NULL; for (int j = 0; j < ind; j++) { @@ -369,32 +385,6 @@ void CardTable::dirty(MemRegion mr) { memset(first, dirty_card, last-first); } -// Unlike several other card table methods, dirty_card_iterate() -// iterates over dirty cards ranges in increasing address order. -void CardTable::dirty_card_iterate(MemRegion mr, MemRegionClosure* cl) { - for (int i = 0; i < _cur_covered_regions; i++) { - MemRegion mri = mr.intersection(_covered[i]); - if (!mri.is_empty()) { - CardValue *cur_entry, *next_entry, *limit; - for (cur_entry = byte_for(mri.start()), limit = byte_for(mri.last()); - cur_entry <= limit; - cur_entry = next_entry) { - next_entry = cur_entry + 1; - if (*cur_entry == dirty_card) { - size_t dirty_cards; - // Accumulate maximal dirty card range, starting at cur_entry - for (dirty_cards = 1; - next_entry <= limit && *next_entry == dirty_card; - dirty_cards++, next_entry++); - MemRegion cur_cards(addr_for(cur_entry), - dirty_cards*card_size_in_words); - cl->do_MemRegion(cur_cards); - } - } - } - } -} - MemRegion CardTable::dirty_card_range_after_reset(MemRegion mr, bool reset, int reset_val) { @@ -413,7 +403,7 @@ MemRegion CardTable::dirty_card_range_after_reset(MemRegion mr, next_entry <= limit && *next_entry == dirty_card; dirty_cards++, next_entry++); MemRegion cur_cards(addr_for(cur_entry), - dirty_cards*card_size_in_words); + dirty_cards * _card_size_in_words); if (reset) { for (size_t i = 0; i < dirty_cards; i++) { cur_entry[i] = reset_val; @@ -428,7 +418,8 @@ MemRegion CardTable::dirty_card_range_after_reset(MemRegion mr, } uintx CardTable::ct_max_alignment_constraint() { - return card_size * os::vm_page_size(); + // Calculate maximum alignment using GCCardSizeInBytes as card_size hasn't been set yet + return GCCardSizeInBytes * os::vm_page_size(); } void CardTable::verify_guard() { @@ -466,7 +457,7 @@ void CardTable::verify_region(MemRegion mr, CardValue val, bool val_equals) { } log_error(gc, verify)("== card " PTR_FORMAT " [" PTR_FORMAT "," PTR_FORMAT "], val: %d", p2i(curr), p2i(addr_for(curr)), - p2i((HeapWord*) (((size_t) addr_for(curr)) + card_size)), + p2i((HeapWord*) (((size_t) addr_for(curr)) + _card_size)), (int) curr_val); } } diff --git a/src/hotspot/share/gc/shared/cardTable.hpp b/src/hotspot/share/gc/shared/cardTable.hpp index 94f5265112596371c9c9acedbd3ac2f95b3468d7..7b74e74d82be44fee9feac25714a271a8a8a330c 100644 --- a/src/hotspot/share/gc/shared/cardTable.hpp +++ b/src/hotspot/share/gc/shared/cardTable.hpp @@ -78,10 +78,6 @@ protected: // covered regions defined in the constructor are ever in use. int find_covering_region_by_base(HeapWord* base); - // Same as above, but finds the region containing the given address - // instead of starting at a given base address. - int find_covering_region_containing(HeapWord* addr); - // Returns the leftmost end of a committed region corresponding to a // covered region before covered region "ind", or else "NULL" if "ind" is // the first covered region. @@ -111,6 +107,11 @@ protected: // a word's worth (row) of clean card values static const intptr_t clean_card_row = (intptr_t)(-1); + // CardTable entry size + static uint _card_shift; + static uint _card_size; + static uint _card_size_in_words; + public: CardTable(MemRegion whole_heap); virtual ~CardTable(); @@ -133,8 +134,8 @@ public: // in, um, words. inline size_t cards_required(size_t covered_words) { // Add one for a guard card, used to detect errors. - const size_t words = align_up(covered_words, card_size_in_words); - return words / card_size_in_words + 1; + const size_t words = align_up(covered_words, _card_size_in_words); + return words / _card_size_in_words + 1; } // Dirty the bytes corresponding to "mr" (not all of which must be @@ -157,7 +158,7 @@ public: "Attempt to access p = " PTR_FORMAT " out of bounds of " " card marking array's _whole_heap = [" PTR_FORMAT "," PTR_FORMAT ")", p2i(p), p2i(_whole_heap.start()), p2i(_whole_heap.end())); - CardValue* result = &_byte_map_base[uintptr_t(p) >> card_shift]; + CardValue* result = &_byte_map_base[uintptr_t(p) >> _card_shift]; assert(result >= _byte_map && result < _byte_map + _byte_map_size, "out of bounds accessor for card marking array"); return result; @@ -189,7 +190,7 @@ public: " _byte_map: " PTR_FORMAT " _byte_map + _byte_map_size: " PTR_FORMAT, p2i(p), p2i(_byte_map), p2i(_byte_map + _byte_map_size)); size_t delta = pointer_delta(p, _byte_map_base, sizeof(CardValue)); - HeapWord* result = (HeapWord*) (delta << card_shift); + HeapWord* result = (HeapWord*) (delta << _card_shift); assert(_whole_heap.contains(result), "Returning result = " PTR_FORMAT " out of bounds of " " card marking array's _whole_heap = [" PTR_FORMAT "," PTR_FORMAT ")", @@ -217,10 +218,6 @@ public: static uintx ct_max_alignment_constraint(); - // Apply closure "cl" to the dirty cards containing some part of - // MemRegion "mr". - void dirty_card_iterate(MemRegion mr, MemRegionClosure* cl); - // Return the MemRegion corresponding to the first maximal run // of dirty cards lying completely within MemRegion mr. // If reset is "true", then sets those card table entries to the given @@ -228,17 +225,25 @@ public: MemRegion dirty_card_range_after_reset(MemRegion mr, bool reset, int reset_val); - // Constants - enum SomePublicConstants { - card_shift = 9, - card_size = 1 << card_shift, - card_size_in_words = card_size / sizeof(HeapWord) - }; + static uint card_shift() { + return _card_shift; + } + + static uint card_size() { + return _card_size; + } + + static uint card_size_in_words() { + return _card_size_in_words; + } static constexpr CardValue clean_card_val() { return clean_card; } static constexpr CardValue dirty_card_val() { return dirty_card; } static intptr_t clean_card_row_val() { return clean_card_row; } + // Initialize card size + static void initialize_card_size(); + // Card marking array base (adjusted for heap low boundary) // This would be the 0th element of _byte_map, if the heap started at 0x0. // But since the heap starts at some higher address, this points to somewhere diff --git a/src/hotspot/share/gc/shared/collectedHeap.cpp b/src/hotspot/share/gc/shared/collectedHeap.cpp index 96b3eb94681b35449564ba4f7fc44f0e09808ccc..eb3213d12df1b4ea3cd15ef6e62268637673e837 100644 --- a/src/hotspot/share/gc/shared/collectedHeap.cpp +++ b/src/hotspot/share/gc/shared/collectedHeap.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -110,6 +110,18 @@ void GCHeapLog::log_heap(CollectedHeap* heap, bool before) { st.print_cr("}"); } +ParallelObjectIterator::ParallelObjectIterator(uint thread_num) : + _impl(Universe::heap()->parallel_object_iterator(thread_num)) +{} + +ParallelObjectIterator::~ParallelObjectIterator() { + delete _impl; +} + +void ParallelObjectIterator::object_iterate(ObjectClosure* cl, uint worker_id) { + _impl->object_iterate(cl, worker_id); +} + size_t CollectedHeap::unused() const { MutexLocker ml(Heap_lock); return capacity() - used(); @@ -405,6 +417,11 @@ size_t CollectedHeap::filler_array_min_size() { return align_object_size(filler_array_hdr_size()); // align to MinObjAlignment } +void CollectedHeap::zap_filler_array_with(HeapWord* start, size_t words, juint value) { + Copy::fill_to_words(start + filler_array_hdr_size(), + words - filler_array_hdr_size(), value); +} + #ifdef ASSERT void CollectedHeap::fill_args_check(HeapWord* start, size_t words) { @@ -415,8 +432,7 @@ void CollectedHeap::fill_args_check(HeapWord* start, size_t words) void CollectedHeap::zap_filler_array(HeapWord* start, size_t words, bool zap) { if (ZapFillerObjects && zap) { - Copy::fill_to_words(start + filler_array_hdr_size(), - words - filler_array_hdr_size(), 0XDEAFBABE); + zap_filler_array_with(start, words, 0XDEAFBABE); } } #endif // ASSERT @@ -433,7 +449,13 @@ CollectedHeap::fill_with_array(HeapWord* start, size_t words, bool zap) ObjArrayAllocator allocator(Universe::intArrayKlassObj(), words, (int)len, /* do_zero */ false); allocator.initialize(start); - DEBUG_ONLY(zap_filler_array(start, words, zap);) + if (DumpSharedSpaces) { + // This array is written into the CDS archive. Make sure it + // has deterministic contents. + zap_filler_array_with(start, words, 0); + } else { + DEBUG_ONLY(zap_filler_array(start, words, zap);) + } } void @@ -481,10 +503,6 @@ void CollectedHeap::fill_with_dummy_object(HeapWord* start, HeapWord* end, bool CollectedHeap::fill_with_object(start, end, zap); } -size_t CollectedHeap::min_dummy_object_size() const { - return oopDesc::header_size(); -} - size_t CollectedHeap::tlab_alloc_reserve() const { size_t min_size = min_dummy_object_size(); return min_size > (size_t)MinObjAlignment ? align_object_size(min_size) : 0; diff --git a/src/hotspot/share/gc/shared/collectedHeap.hpp b/src/hotspot/share/gc/shared/collectedHeap.hpp index efac5e76c86ac617af01a2382d4fd04cbb3be249..fd6427fee6019cbac528556649d5b5f466e5bb2b 100644 --- a/src/hotspot/share/gc/shared/collectedHeap.hpp +++ b/src/hotspot/share/gc/shared/collectedHeap.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -62,10 +62,23 @@ class VirtualSpaceSummary; class WorkerThreads; class nmethod; -class ParallelObjectIterator : public CHeapObj { +class ParallelObjectIteratorImpl : public CHeapObj { public: + virtual ~ParallelObjectIteratorImpl() {} virtual void object_iterate(ObjectClosure* cl, uint worker_id) = 0; - virtual ~ParallelObjectIterator() {} +}; + +// User facing parallel object iterator. This is a StackObj, which ensures that +// the _impl is allocated and deleted in the scope of this object. This ensures +// the life cycle of the implementation is as required by ThreadsListHandle, +// which is sometimes used by the root iterators. +class ParallelObjectIterator : public StackObj { + ParallelObjectIteratorImpl* _impl; + +public: + ParallelObjectIterator(uint thread_num); + ~ParallelObjectIterator(); + void object_iterate(ObjectClosure* cl, uint worker_id); }; // @@ -77,11 +90,12 @@ public: // ShenandoahHeap // ZCollectedHeap // -class CollectedHeap : public CHeapObj { +class CollectedHeap : public CHeapObj { friend class VMStructs; friend class JVMCIVMStructs; friend class IsGCActiveMark; // Block structured external access to _is_gc_active friend class MemAllocator; + friend class ParallelObjectIterator; private: GCHeapLog* _gc_heap_log; @@ -143,6 +157,7 @@ class CollectedHeap : public CHeapObj { static inline size_t filler_array_hdr_size(); static inline size_t filler_array_min_size(); + static inline void zap_filler_array_with(HeapWord* start, size_t words, juint value); DEBUG_ONLY(static void fill_args_check(HeapWord* start, size_t words);) DEBUG_ONLY(static void zap_filler_array(HeapWord* start, size_t words, bool zap = true);) @@ -275,7 +290,10 @@ class CollectedHeap : public CHeapObj { } virtual void fill_with_dummy_object(HeapWord* start, HeapWord* end, bool zap); - virtual size_t min_dummy_object_size() const; + static constexpr size_t min_dummy_object_size() { + return oopDesc::header_size(); + } + size_t tlab_alloc_reserve() const; // Some heaps may offer a contiguous region for shared non-blocking @@ -384,10 +402,12 @@ class CollectedHeap : public CHeapObj { // Iterate over all objects, calling "cl.do_object" on each. virtual void object_iterate(ObjectClosure* cl) = 0; - virtual ParallelObjectIterator* parallel_object_iterator(uint thread_num) { + protected: + virtual ParallelObjectIteratorImpl* parallel_object_iterator(uint thread_num) { return NULL; } + public: // Keep alive an object that was loaded with AS_NO_KEEPALIVE. virtual void keep_alive(oop obj) {} @@ -461,14 +481,15 @@ class CollectedHeap : public CHeapObj { // this collector. The default implementation returns false. virtual bool supports_concurrent_gc_breakpoints() const; - // Provides a thread pool to SafepointSynchronize to use - // for parallel safepoint cleanup. - // GCs that use a GC worker thread pool may want to share - // it for use during safepoint cleanup. This is only possible - // if the GC can pause and resume concurrent work (e.g. G1 - // concurrent marking) for an intermittent non-GC safepoint. - // If this method returns NULL, SafepointSynchronize will - // perform cleanup tasks serially in the VMThread. + // Workers used in non-GC safepoints for parallel safepoint cleanup. If this + // method returns NULL, cleanup tasks are done serially in the VMThread. See + // `SafepointSynchronize::do_cleanup_tasks` for details. + // GCs using a GC worker thread pool inside GC safepoints may opt to share + // that pool with non-GC safepoints, avoiding creating extraneous threads. + // Such sharing is safe, because GC safepoints and non-GC safepoints never + // overlap. For example, `G1CollectedHeap::workers()` (for GC safepoints) and + // `G1CollectedHeap::safepoint_workers()` (for non-GC safepoints) return the + // same thread-pool. virtual WorkerThreads* safepoint_workers() { return NULL; } // Support for object pinning. This is used by JNI Get*Critical() diff --git a/src/hotspot/share/gc/shared/concurrentGCBreakpoints.hpp b/src/hotspot/share/gc/shared/concurrentGCBreakpoints.hpp index c11c0e116c5886d2befc97a18c7c1552094c45bc..7af1b5746c3444136317ce3b52c531089999a955 100644 --- a/src/hotspot/share/gc/shared/concurrentGCBreakpoints.hpp +++ b/src/hotspot/share/gc/shared/concurrentGCBreakpoints.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -26,7 +26,7 @@ #define SHARE_GC_SHARED_CONCURRENTGCBREAKPOINTS_HPP #include "gc/shared/gcCause.hpp" -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" #include "utilities/globalDefinitions.hpp" class Monitor; diff --git a/src/hotspot/share/gc/shared/freeListAllocator.cpp b/src/hotspot/share/gc/shared/freeListAllocator.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f616e33691cf37f66dc0c9feb42fe7391ec7e332 --- /dev/null +++ b/src/hotspot/share/gc/shared/freeListAllocator.cpp @@ -0,0 +1,213 @@ +/* + * 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/shared/freeListAllocator.hpp" +#include "logging/log.hpp" +#include "utilities/globalCounter.inline.hpp" + +FreeListAllocator::NodeList::NodeList() : + _head(nullptr), _tail(nullptr), _entry_count(0) {} + +FreeListAllocator::NodeList::NodeList(FreeNode* head, FreeNode* tail, size_t entry_count) : + _head(head), _tail(tail), _entry_count(entry_count) +{ + assert((_head == nullptr) == (_tail == nullptr), "invariant"); + assert((_head == nullptr) == (_entry_count == 0), "invariant"); +} + +FreeListAllocator::PendingList::PendingList() : + _tail(nullptr), _head(nullptr), _count(0) {} + +size_t FreeListAllocator::PendingList::add(FreeNode* node) { + assert(node->next() == nullptr, "precondition"); + FreeNode* old_head = Atomic::xchg(&_head, node); + if (old_head != nullptr) { + node->set_next(old_head); + } else { + assert(_tail == nullptr, "invariant"); + _tail = node; + } + return Atomic::add(&_count, size_t(1)); +} + +typename FreeListAllocator::NodeList FreeListAllocator::PendingList::take_all() { + NodeList result{Atomic::load(&_head), _tail, Atomic::load(&_count)}; + Atomic::store(&_head, (FreeNode*)nullptr); + _tail = nullptr; + Atomic::store(&_count, size_t(0)); + return result; +} + +size_t FreeListAllocator::PendingList::count() const { + return Atomic::load(&_count); +} + +FreeListAllocator::FreeListAllocator(const char* name, FreeListConfig* config) : + _config(config), + _free_count(0), + _free_list(), + _transfer_lock(false), + _active_pending_list(0), + _pending_lists() +{ + strncpy(_name, name, sizeof(_name) - 1); + _name[sizeof(_name) - 1] = '\0'; +} + +void FreeListAllocator::delete_list(FreeNode* list) { + while (list != nullptr) { + FreeNode* next = list->next(); + list->~FreeNode(); + _config->deallocate(list); + list = next; + } +} + +FreeListAllocator::~FreeListAllocator() { + uint index = Atomic::load(&_active_pending_list); + NodeList pending_list = _pending_lists[index].take_all(); + delete_list(Atomic::load(&pending_list._head)); + delete_list(_free_list.pop_all()); +} + +// Drop existing nodes and reset all counters +void FreeListAllocator::reset() { + uint index = Atomic::load(&_active_pending_list); + _pending_lists[index].take_all(); + _free_list.pop_all(); + _free_count = 0; +} + +size_t FreeListAllocator::free_count() const { + return Atomic::load(&_free_count); +} + +size_t FreeListAllocator::pending_count() const { + uint index = Atomic::load(&_active_pending_list); + return _pending_lists[index].count();; +} + +// To solve the ABA problem, popping a node from the _free_list is performed within +// a GlobalCounter critical section, and pushing nodes onto the _free_list is done +// after a GlobalCounter synchronization associated with the nodes to be pushed. +void* FreeListAllocator::allocate() { + FreeNode* node = nullptr; + if (free_count() > 0) { + // Protect against ABA; see release(). + GlobalCounter::CriticalSection cs(Thread::current()); + node = _free_list.pop(); + } + + if (node != nullptr) { + node->~FreeNode(); + // Decrement count after getting buffer from free list. This, along + // with incrementing count before adding to free list, ensures count + // never underflows. + size_t count = Atomic::sub(&_free_count, 1u); + assert((count + 1) != 0, "_free_count underflow"); + return node; + } else { + return _config->allocate(); + } +} + +// The release synchronizes on the critical sections before adding to +// the _free_list. But we don't want to make every release have to do a +// synchronize. Instead, we initially place released nodes on the pending list, +// and transfer them to the _free_list in batches. Only one transfer at a time is +// permitted, with a lock bit to control access to that phase. While a transfer +// is in progress, other threads might be adding other nodes to the pending list, +// to be dealt with by some later transfer. +void FreeListAllocator::release(void* free_node) { + assert(free_node != nullptr, "precondition"); + assert(is_aligned(free_node, sizeof(FreeNode)), "Unaligned addr " PTR_FORMAT, p2i(free_node)); + FreeNode* node = ::new (free_node) FreeNode(); + + // The pending list is double-buffered. Add node to the currently active + // pending list, within a critical section so a transfer will wait until + // we're done with what might be the pending list to be transferred. + { + GlobalCounter::CriticalSection cs(Thread::current()); + uint index = Atomic::load_acquire(&_active_pending_list); + size_t count = _pending_lists[index].add(node); + if (count <= _config->transfer_threshold()) return; + } + // Attempt transfer when number pending exceeds the transfer threshold. + try_transfer_pending(); +} + +// Try to transfer nodes from the pending list to _free_list, with a +// synchronization delay for any in-progress pops from the _free_list, +// to solve ABA there. Return true if performed a (possibly empty) +// transfer, false if blocked from doing so by some other thread's +// in-progress transfer. +bool FreeListAllocator::try_transfer_pending() { + // Attempt to claim the lock. + if (Atomic::load(&_transfer_lock) || // Skip CAS if likely to fail. + Atomic::cmpxchg(&_transfer_lock, false, true)) { + return false; + } + // Have the lock; perform the transfer. + + // Change which pending list is active. Don't need an atomic RMW since + // we have the lock and we're the only writer. + uint index = Atomic::load(&_active_pending_list); + uint new_active = (index + 1) % ARRAY_SIZE(_pending_lists); + Atomic::release_store(&_active_pending_list, new_active); + + // Wait for all critical sections in the buffer life-cycle to complete. + // This includes _free_list pops and adding to the now inactive pending + // list. + GlobalCounter::write_synchronize(); + + // Transfer the inactive pending list to _free_list. + NodeList transfer_list = _pending_lists[index].take_all(); + size_t count = transfer_list._entry_count; + if (count > 0) { + // Update count first so no underflow in allocate(). + Atomic::add(&_free_count, count); + _free_list.prepend(*transfer_list._head, *transfer_list._tail); + log_trace(gc, freelist) + ("Transferred %s pending to free: %zu", name(), count); + } + Atomic::release_store(&_transfer_lock, false); + return true; +} + +size_t FreeListAllocator::reduce_free_list(size_t remove_goal) { + try_transfer_pending(); + size_t removed = 0; + for ( ; removed < remove_goal; ++removed) { + FreeNode* node = _free_list.pop(); + if (node == nullptr) break; + node->~FreeNode(); + _config->deallocate(node); + } + size_t new_count = Atomic::sub(&_free_count, removed); + log_debug(gc, freelist) + ("Reduced %s free list by " SIZE_FORMAT " to " SIZE_FORMAT, + name(), removed, new_count); + return removed; +} diff --git a/src/hotspot/share/gc/shared/freeListAllocator.hpp b/src/hotspot/share/gc/shared/freeListAllocator.hpp new file mode 100644 index 0000000000000000000000000000000000000000..8f4aba0ed03ab56196eeb76e7c7fffd51a05a621 --- /dev/null +++ b/src/hotspot/share/gc/shared/freeListAllocator.hpp @@ -0,0 +1,161 @@ +/* + * 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_SHARED_FREELISTALLOCATOR_HPP +#define SHARE_GC_SHARED_FREELISTALLOCATOR_HPP + +#include "memory/allocation.hpp" +#include "memory/padded.hpp" +#include "runtime/atomic.hpp" +#include "utilities/globalDefinitions.hpp" +#include "utilities/lockFreeStack.hpp" + +class FreeListConfig { + // Desired minimum transfer batch size. There is relatively little + // importance to the specific number. It shouldn't be too big, else + // we're wasting space when the release rate is low. If the release + // rate is high, we might accumulate more than this before being + // able to start a new transfer, but that's okay. + const size_t _transfer_threshold; +protected: + ~FreeListConfig() = default; +public: + explicit FreeListConfig(size_t threshold = 10) : _transfer_threshold(threshold) {} + + size_t transfer_threshold() { return _transfer_threshold; } + + virtual void* allocate() = 0; + + virtual void deallocate(void* node) = 0; +}; + +// Allocation is based on a lock-free list of nodes. To reduce synchronization +// overhead on the free list between allocation and release calls, the released +// nodes are first placed on a pending list, then transferred to the free list in +// batches. While on the pending list, the nodes are not available for allocation. +// The allocator uses allocation options specified by an instance of +// FreeListConfig. The FreeListConfig includes an allocation method to use in case +// the free list is empty and a deallocation method used to deallocate nodes in +// the free list. Additionally, the FreeListConfig configures the threshold used +// as a minimum batch size for transferring released nodes from the pending list +// to the free list making them available for re-allocation. +class FreeListAllocator { + struct FreeNode { + FreeNode* volatile _next; + + FreeNode() : _next (nullptr) { } + + FreeNode* next() { return Atomic::load(&_next); } + + FreeNode* volatile* next_addr() { return &_next; } + + void set_next(FreeNode* next) { Atomic::store(&_next, next); } + }; + + struct NodeList { + FreeNode* _head; // First node in list or nullptr if empty. + FreeNode* _tail; // Last node in list or nullptr if empty. + size_t _entry_count; // Sum of entries in nodes in list. + + NodeList(); + + NodeList(FreeNode* head, FreeNode* tail, size_t entry_count); + }; + + class PendingList { + FreeNode* _tail; + FreeNode* volatile _head; + volatile size_t _count; + + NONCOPYABLE(PendingList); + + public: + PendingList(); + ~PendingList() = default; + + // Add node to the list. Returns the number of nodes in the list. + // Thread-safe against concurrent add operations. + size_t add(FreeNode* node); + + size_t count() const; + + // Return the nodes in the list, leaving the list empty. + // Not thread-safe. + NodeList take_all(); + }; + + static FreeNode* volatile* next_ptr(FreeNode& node) { return node.next_addr(); } + typedef LockFreeStack Stack; + + FreeListConfig* _config; + char _name[DEFAULT_CACHE_LINE_SIZE - sizeof(FreeListConfig*)]; // Use name as padding. + +#define DECLARE_PADDED_MEMBER(Id, Type, Name) \ + Type Name; DEFINE_PAD_MINUS_SIZE(Id, DEFAULT_CACHE_LINE_SIZE, sizeof(Type)) + DECLARE_PADDED_MEMBER(1, volatile size_t, _free_count); + DECLARE_PADDED_MEMBER(2, Stack, _free_list); + DECLARE_PADDED_MEMBER(3, volatile bool, _transfer_lock); +#undef DECLARE_PADDED_MEMBER + + volatile uint _active_pending_list; + PendingList _pending_lists[2]; + + void delete_list(FreeNode* list); + + NONCOPYABLE(FreeListAllocator); + +public: + FreeListAllocator(const char* name, FreeListConfig* config); + + const char* name() const { return _name; } + + ~FreeListAllocator(); + + size_t free_count() const; + size_t pending_count() const; + + void* allocate(); + void release(void* node); + + // Free nodes in the allocator could have been allocated out of an arena. + // Therefore, the nodes can be freed at once when entire arena is discarded + // without running destructors for the individual nodes. In such cases, reset + // method should be called before the ~FreeListAllocator(). Calling the reset + // method on nodes not managed by an arena will leak the memory by just dropping + // the nodes to the floor. + void reset(); + bool try_transfer_pending(); + + size_t mem_size() const { + return sizeof(*this); + } + + // Deallocate some of the available nodes in the free_list. + // remove_goal is the target number to remove. Returns the number + // actually deallocated, which may be less than the goal if there + // were fewer available. + size_t reduce_free_list(size_t remove_goal); +}; + +#endif // SHARE_GC_SHARED_FREELISTALLOCATOR_HPP diff --git a/src/hotspot/share/gc/shared/gcCause.hpp b/src/hotspot/share/gc/shared/gcCause.hpp index 75f7dc73a8cbcb3262060dfae1b0270cb46cde6e..a3746fa8745dad097d036a79ba6f20429d2bcb28 100644 --- a/src/hotspot/share/gc/shared/gcCause.hpp +++ b/src/hotspot/share/gc/shared/gcCause.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 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 @@ -25,7 +25,8 @@ #ifndef SHARE_GC_SHARED_GCCAUSE_HPP #define SHARE_GC_SHARED_GCCAUSE_HPP -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" +#include "utilities/debug.hpp" // // This class exposes implementation details of the various diff --git a/src/hotspot/share/gc/shared/gcConfig.hpp b/src/hotspot/share/gc/shared/gcConfig.hpp index 2dfbf186b7fd0bebeb3581fc99217835caa2a1ab..9b0da3ad528a87e41fcfc4f9e5d12cb403b78c47 100644 --- a/src/hotspot/share/gc/shared/gcConfig.hpp +++ b/src/hotspot/share/gc/shared/gcConfig.hpp @@ -26,7 +26,7 @@ #define SHARE_GC_SHARED_GCCONFIG_HPP #include "gc/shared/collectedHeap.hpp" -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" class GCArguments; diff --git a/src/hotspot/share/gc/shared/gcLocker.hpp b/src/hotspot/share/gc/shared/gcLocker.hpp index 91ed84c41a99b6ba7d8cbd5278380461686ca5e8..e567d0c1f1689b61a1ccd44eece5485206141bed 100644 --- a/src/hotspot/share/gc/shared/gcLocker.hpp +++ b/src/hotspot/share/gc/shared/gcLocker.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -26,7 +26,7 @@ #define SHARE_GC_SHARED_GCLOCKER_HPP #include "gc/shared/gcCause.hpp" -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/macros.hpp" diff --git a/src/hotspot/share/gc/shared/gcLogPrecious.hpp b/src/hotspot/share/gc/shared/gcLogPrecious.hpp index 5f1158caca75a5f0115102534eb5aa7afe42a333..ec8b1c670f3216c69bddef99e68f0280a3be4cc6 100644 --- a/src/hotspot/share/gc/shared/gcLogPrecious.hpp +++ b/src/hotspot/share/gc/shared/gcLogPrecious.hpp @@ -26,7 +26,7 @@ #include "utilities/globalDefinitions.hpp" #include "logging/logHandle.hpp" -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" #include "utilities/debug.hpp" class Mutex; diff --git a/src/hotspot/share/gc/shared/gcVMOperations.hpp b/src/hotspot/share/gc/shared/gcVMOperations.hpp index ce071ee16a73e6c00987ee6341d724832b611209..9144300565873b8282b28dbaca959ca1a310c1f1 100644 --- a/src/hotspot/share/gc/shared/gcVMOperations.hpp +++ b/src/hotspot/share/gc/shared/gcVMOperations.hpp @@ -42,7 +42,6 @@ // VM_GC_HeapInspection // VM_PopulateDynamicDumpSharedSpace // VM_GenCollectFull -// VM_GenCollectFullConcurrent // VM_ParallelGCSystemGC // VM_CollectForAllocation // VM_GenCollectForAllocation @@ -71,7 +70,6 @@ // allocate afterwards; // // VM_GenCollectFull -// VM_GenCollectFullConcurrent // VM_ParallelGCSystemGC // - these operations preform full collection of heaps of // different kind diff --git a/src/hotspot/share/gc/shared/gcWhen.hpp b/src/hotspot/share/gc/shared/gcWhen.hpp index ff489226f65b36759f8db765c5ed53347390448f..23e2ef6b229d745e45a5464fc9c4a7b8e4844a91 100644 --- a/src/hotspot/share/gc/shared/gcWhen.hpp +++ b/src/hotspot/share/gc/shared/gcWhen.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -25,7 +25,7 @@ #ifndef SHARE_GC_SHARED_GCWHEN_HPP #define SHARE_GC_SHARED_GCWHEN_HPP -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" #include "utilities/debug.hpp" class GCWhen : AllStatic { diff --git a/src/hotspot/share/gc/shared/gc_globals.hpp b/src/hotspot/share/gc/shared/gc_globals.hpp index 730e5f616bbd1431c2c8f849372fe2f6baa2cf3d..d9380b2af715a78af9ca7df3d5bf6622b869e6bd 100644 --- a/src/hotspot/share/gc/shared/gc_globals.hpp +++ b/src/hotspot/share/gc/shared/gc_globals.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -208,7 +208,7 @@ "Maximum size of marking stack") \ range(1, (max_jint - 1)) \ \ - product(size_t, MarkStackSize, NOT_LP64(32*K) LP64_ONLY(4*M), \ + product(size_t, MarkStackSize, NOT_LP64(64*K) LP64_ONLY(4*M), \ "Size of marking stack") \ constraint(MarkStackSizeConstraintFunc,AfterErgo) \ range(1, (max_jint - 1)) \ @@ -503,10 +503,6 @@ "How far ahead to prefetch scan area (<= 0 means off)") \ range(-1, max_jint) \ \ - product(intx, PrefetchFieldsAhead, -1, \ - "How many fields ahead to prefetch in oop scan (<= 0 means off)") \ - range(-1, max_jint) \ - \ product(bool, VerifyDuringStartup, false, DIAGNOSTIC, \ "Verify memory system before executing any Java code " \ "during VM initialization") \ @@ -692,9 +688,13 @@ product(uintx, GCDrainStackTargetSize, 64, \ "Number of entries we will try to leave on the stack " \ "during parallel gc") \ - range(0, max_juint) - -// end of GC_FLAGS + range(0, max_juint) \ + \ + product(uint, GCCardSizeInBytes, 512, \ + "Card table entry size (in bytes) for card based collectors") \ + range(128, NOT_LP64(512) LP64_ONLY(1024)) \ + constraint(GCCardSizeInBytesConstraintFunc,AtParse) + // end of GC_FLAGS DECLARE_FLAGS(GC_FLAGS) diff --git a/src/hotspot/share/gc/shared/genArguments.cpp b/src/hotspot/share/gc/shared/genArguments.cpp index 805f353576220e108e9198d7e50784b3c3749727..c53fb72c459a05247c579c2064dd729d652e8c4a 100644 --- a/src/hotspot/share/gc/shared/genArguments.cpp +++ b/src/hotspot/share/gc/shared/genArguments.cpp @@ -23,6 +23,7 @@ */ #include "precompiled.hpp" +#include "gc/shared/cardTable.hpp" #include "gc/shared/genArguments.hpp" #include "gc/shared/generation.hpp" #include "logging/log.hpp" @@ -61,6 +62,8 @@ static size_t bound_minus_alignment(size_t desired_size, } void GenArguments::initialize_alignments() { + // Initialize card size before initializing alignments + CardTable::initialize_card_size(); SpaceAlignment = GenAlignment = (size_t)Generation::GenGrain; HeapAlignment = compute_heap_alignment(); } diff --git a/src/hotspot/share/gc/shared/genCollectedHeap.cpp b/src/hotspot/share/gc/shared/genCollectedHeap.cpp index 473e5abc1dff61bf87f1c837ad80e5b8a741da6d..c840e5a666790972d5b8c554b6c64e1b6c6e1fbf 100644 --- a/src/hotspot/share/gc/shared/genCollectedHeap.cpp +++ b/src/hotspot/share/gc/shared/genCollectedHeap.cpp @@ -1045,16 +1045,8 @@ void GenCollectedHeap::release_scratch() { _old_gen->reset_scratch(); } -class GenPrepareForVerifyClosure: public GenCollectedHeap::GenClosure { - void do_generation(Generation* gen) { - gen->prepare_for_verify(); - } -}; - void GenCollectedHeap::prepare_for_verify() { ensure_parsability(false); // no need to retire TLABs - GenPrepareForVerifyClosure blk; - generation_iterate(&blk, false); } void GenCollectedHeap::generation_iterate(GenClosure* cl, diff --git a/src/hotspot/share/gc/shared/genCollectedHeap.hpp b/src/hotspot/share/gc/shared/genCollectedHeap.hpp index 28ed627b80f205349ccc9efe855bbd8ba27aa19d..1cce08f4b0c99cbf4a27beffbad102b55c649f4f 100644 --- a/src/hotspot/share/gc/shared/genCollectedHeap.hpp +++ b/src/hotspot/share/gc/shared/genCollectedHeap.hpp @@ -48,7 +48,6 @@ class GenCollectedHeap : public CollectedHeap { friend class GenMarkSweep; friend class VM_GenCollectForAllocation; friend class VM_GenCollectFull; - friend class VM_GenCollectFullConcurrent; friend class VM_GC_HeapInspection; friend class VM_HeapDumper; friend class HeapInspection; diff --git a/src/hotspot/share/gc/shared/generation.hpp b/src/hotspot/share/gc/shared/generation.hpp index 452212ffd7224d943cf50a55ce6476fce6302916..36740cc4039cb192dbe3aa0c0849fc5384342cf9 100644 --- a/src/hotspot/share/gc/shared/generation.hpp +++ b/src/hotspot/share/gc/shared/generation.hpp @@ -41,8 +41,7 @@ // // Generation - abstract base class // - DefNewGeneration - allocation area (copy collected) -// - CardGeneration - abstract class adding offset array behavior -// - TenuredGeneration - tenured (old object) space (markSweepCompact) +// - TenuredGeneration - tenured (old object) space (markSweepCompact) // // The system configuration currently allowed is: // @@ -118,7 +117,7 @@ class Generation: public CHeapObj { }; // allocate and initialize ("weak") refs processing support - virtual void ref_processor_init(); + void ref_processor_init(); void set_ref_processor(ReferenceProcessor* rp) { assert(_ref_processor == NULL, "clobbering existing _ref_processor"); _ref_processor = rp; @@ -364,10 +363,6 @@ class Generation: public CHeapObj { virtual void post_compact() { ShouldNotReachHere(); } #endif - // Some generations may require some cleanup actions before allowing - // a verification. - virtual void prepare_for_verify() {} - // Accessing "marks". // This function gives a generation a chance to note a point between @@ -422,11 +417,6 @@ class Generation: public CHeapObj { // each. virtual void object_iterate(ObjectClosure* cl); - // Inform a generation that it longer contains references to objects - // in any younger generation. [e.g. Because younger gens are empty, - // clear the card table.] - virtual void clear_remembered_set() { } - // Inform a generation that some of its objects have moved. [e.g. The // generation's spaces were compacted, invalidating the card table.] virtual void invalidate_remembered_set() { } diff --git a/src/hotspot/share/gc/shared/jvmFlagConstraintsGC.cpp b/src/hotspot/share/gc/shared/jvmFlagConstraintsGC.cpp index d7df753298084733c78508f412e1d209d2b00343..82182fbcea8c5f343a36f4859be892ec5673874d 100644 --- a/src/hotspot/share/gc/shared/jvmFlagConstraintsGC.cpp +++ b/src/hotspot/share/gc/shared/jvmFlagConstraintsGC.cpp @@ -424,3 +424,15 @@ JVMFlag::Error MaxMetaspaceSizeConstraintFunc(size_t value, bool verbose) { } } +JVMFlag::Error GCCardSizeInBytesConstraintFunc(uint value, bool verbose) { + if (!is_power_of_2(value)) { + JVMFlag::printError(verbose, + "GCCardSizeInBytes ( %u ) must be " + "a power of 2\n", + value); + return JVMFlag::VIOLATES_CONSTRAINT; + } else { + return JVMFlag::SUCCESS; + } +} + diff --git a/src/hotspot/share/gc/shared/jvmFlagConstraintsGC.hpp b/src/hotspot/share/gc/shared/jvmFlagConstraintsGC.hpp index 205c2391a64901bead236480ebd9fde9daf8a862..da320944b0ef26924659eec79eeae14bd1d6f829 100644 --- a/src/hotspot/share/gc/shared/jvmFlagConstraintsGC.hpp +++ b/src/hotspot/share/gc/shared/jvmFlagConstraintsGC.hpp @@ -66,7 +66,8 @@ f(uintx, TLABWasteIncrementConstraintFunc) \ f(uintx, SurvivorRatioConstraintFunc) \ f(size_t, MetaspaceSizeConstraintFunc) \ - f(size_t, MaxMetaspaceSizeConstraintFunc) + f(size_t, MaxMetaspaceSizeConstraintFunc) \ + f(uint, GCCardSizeInBytesConstraintFunc) SHARED_GC_CONSTRAINTS(DECLARE_CONSTRAINT) diff --git a/src/hotspot/share/gc/shared/locationPrinter.hpp b/src/hotspot/share/gc/shared/locationPrinter.hpp index 2c99e4528453d62a5a46ec7f97b7aecb6222fd8a..2d5d997376d13c4741a134df010bb4e0beceefaf 100644 --- a/src/hotspot/share/gc/shared/locationPrinter.hpp +++ b/src/hotspot/share/gc/shared/locationPrinter.hpp @@ -25,7 +25,7 @@ #ifndef SHARE_GC_SHARED_LOCATIONPRINTER_HPP #define SHARE_GC_SHARED_LOCATIONPRINTER_HPP -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" #include "oops/oopsHierarchy.hpp" #include "utilities/globalDefinitions.hpp" diff --git a/src/hotspot/share/gc/shared/objectCountEventSender.hpp b/src/hotspot/share/gc/shared/objectCountEventSender.hpp index 58e6da016daf8eb1f5e389aa8cd8c4f606761bbf..115fbfdaf7d3a01d40fbd408ead25482cbf863d1 100644 --- a/src/hotspot/share/gc/shared/objectCountEventSender.hpp +++ b/src/hotspot/share/gc/shared/objectCountEventSender.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -26,7 +26,7 @@ #define SHARE_GC_SHARED_OBJECTCOUNTEVENTSENDER_HPP #include "gc/shared/gcTrace.hpp" -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/macros.hpp" #include "utilities/ticks.hpp" diff --git a/src/hotspot/share/gc/shared/plab.hpp b/src/hotspot/share/gc/shared/plab.hpp index b3700a3b9f67bdecbc4d60f1b47820ed72c69036..ebe788122ba4b2d5473044cc162e7832451f24f2 100644 --- a/src/hotspot/share/gc/shared/plab.hpp +++ b/src/hotspot/share/gc/shared/plab.hpp @@ -94,9 +94,6 @@ public: } } - // Allocate the object aligned to "alignment_in_bytes". - inline HeapWord* allocate_aligned(size_t word_sz, unsigned short alignment_in_bytes); - // Undo any allocation in the buffer, which is required to be of the // "obj" of the given "word_sz". void undo_allocation(HeapWord* obj, size_t word_sz); @@ -119,7 +116,7 @@ public: } // Sets the space of the buffer to be [buf, space+word_sz()). - virtual void set_buf(HeapWord* buf, size_t new_word_sz) { + void set_buf(HeapWord* buf, size_t new_word_sz) { assert(new_word_sz > AlignmentReserve, "Too small"); _word_sz = new_word_sz; diff --git a/src/hotspot/share/gc/shared/preservedMarks.cpp b/src/hotspot/share/gc/shared/preservedMarks.cpp index 718f97085f6789748cc4bb11dc37325499d31b89..9003ccb1697375300537cb1816fac5324e8f1a8c 100644 --- a/src/hotspot/share/gc/shared/preservedMarks.cpp +++ b/src/hotspot/share/gc/shared/preservedMarks.cpp @@ -71,12 +71,6 @@ void PreservedMarks::assert_empty() { } #endif // ndef PRODUCT -void RemoveForwardedPointerClosure::do_object(oop obj) { - if (obj->is_forwarded()) { - PreservedMarks::init_forwarded_mark(obj); - } -} - void PreservedMarksSet::init(uint num) { assert(_stacks == nullptr && _num == 0, "do not re-initialize"); assert(num > 0, "pre-condition"); @@ -125,8 +119,10 @@ public: ~RestorePreservedMarksTask() { assert(_total_size == _total_size_before, "total_size = %zu before = %zu", _total_size, _total_size_before); - - log_trace(gc)("Restored %zu marks", _total_size); + size_t mem_size = _total_size * (sizeof(oop) + sizeof(markWord)); + log_trace(gc)("Restored %zu marks, occupying %zu %s", _total_size, + byte_size_in_proper_unit(mem_size), + proper_unit_for_byte_size(mem_size)); } }; diff --git a/src/hotspot/share/gc/shared/preservedMarks.hpp b/src/hotspot/share/gc/shared/preservedMarks.hpp index 21b40903e7fb2bc747b2e34455c1294dbb31f42b..959287ef99db4c9f8fb527fb1e4bee5783d4952f 100644 --- a/src/hotspot/share/gc/shared/preservedMarks.hpp +++ b/src/hotspot/share/gc/shared/preservedMarks.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -56,8 +56,8 @@ private: public: size_t size() const { return _stack.size(); } - inline void push(oop obj, markWord m); inline void push_if_necessary(oop obj, markWord m); + inline void push_always(oop obj, markWord m); // Iterate over the stack, restore all preserved marks, and // reclaim the memory taken up by the stack segments. void restore(); @@ -66,7 +66,6 @@ public: void adjust_during_full_gc(); void restore_and_increment(volatile size_t* const _total_size_addr); - inline static void init_forwarded_mark(oop obj); // Assert the stack is empty and has no cached segments. void assert_empty() PRODUCT_RETURN; @@ -75,11 +74,6 @@ public: ~PreservedMarks() { assert_empty(); } }; -class RemoveForwardedPointerClosure: public ObjectClosure { -public: - virtual void do_object(oop obj); -}; - class PreservedMarksSet : public CHeapObj { private: // true -> _stacks will be allocated in the C heap diff --git a/src/hotspot/share/gc/shared/preservedMarks.inline.hpp b/src/hotspot/share/gc/shared/preservedMarks.inline.hpp index e3f9f513573453a6dd0df2f638004bb2b0d026bb..107acdba510f32cfa8aa5d25f01dbe9d85170dbe 100644 --- a/src/hotspot/share/gc/shared/preservedMarks.inline.hpp +++ b/src/hotspot/share/gc/shared/preservedMarks.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -35,20 +35,17 @@ inline bool PreservedMarks::should_preserve_mark(oop obj, markWord m) const { return obj->mark_must_be_preserved(m); } -inline void PreservedMarks::push(oop obj, markWord m) { - assert(should_preserve_mark(obj, m), "pre-condition"); - OopAndMarkWord elem(obj, m); - _stack.push(elem); -} - inline void PreservedMarks::push_if_necessary(oop obj, markWord m) { if (should_preserve_mark(obj, m)) { - push(obj, m); + OopAndMarkWord elem(obj, m); + _stack.push(elem); } } -inline void PreservedMarks::init_forwarded_mark(oop obj) { - obj->init_mark(); +inline void PreservedMarks::push_always(oop obj, markWord m) { + assert(!m.is_marked(), "precondition"); + OopAndMarkWord elem(obj, m); + _stack.push(elem); } inline PreservedMarks::PreservedMarks() diff --git a/src/hotspot/share/gc/shared/ptrQueue.cpp b/src/hotspot/share/gc/shared/ptrQueue.cpp index 3838b4f37eeb7caa5fb8203c7974e29778e937ca..e6f24df4d2e19127fa839ce9f8888e8953e31905 100644 --- a/src/hotspot/share/gc/shared/ptrQueue.cpp +++ b/src/hotspot/share/gc/shared/ptrQueue.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -24,14 +24,7 @@ #include "precompiled.hpp" #include "gc/shared/ptrQueue.hpp" -#include "logging/log.hpp" -#include "memory/allocation.hpp" #include "memory/allocation.inline.hpp" -#include "runtime/atomic.hpp" -#include "runtime/mutex.hpp" -#include "runtime/mutexLocker.hpp" -#include "runtime/thread.inline.hpp" -#include "utilities/globalCounter.inline.hpp" #include @@ -45,151 +38,42 @@ PtrQueue::~PtrQueue() { assert(_buf == NULL, "queue must be flushed before delete"); } -BufferNode* BufferNode::allocate(size_t size) { - size_t byte_size = size * sizeof(void*); - void* data = NEW_C_HEAP_ARRAY(char, buffer_offset() + byte_size, mtGC); - return new (data) BufferNode; +BufferNode::AllocatorConfig::AllocatorConfig(size_t size) : _buffer_size(size) {} + +void* BufferNode::AllocatorConfig::allocate() { + size_t byte_size = _buffer_size * sizeof(void*); + return NEW_C_HEAP_ARRAY(char, buffer_offset() + byte_size, mtGC); } -void BufferNode::deallocate(BufferNode* node) { - node->~BufferNode(); +void BufferNode::AllocatorConfig::deallocate(void* node) { + assert(node != nullptr, "precondition"); FREE_C_HEAP_ARRAY(char, node); } BufferNode::Allocator::Allocator(const char* name, size_t buffer_size) : - _buffer_size(buffer_size), - _pending_list(), - _free_list(), - _pending_count(0), - _free_count(0), - _transfer_lock(false) + _config(buffer_size), + _free_list(name, &_config) { - strncpy(_name, name, sizeof(_name) - 1); - _name[sizeof(_name) - 1] = '\0'; -} -BufferNode::Allocator::~Allocator() { - delete_list(_free_list.pop_all()); - delete_list(_pending_list.pop_all()); -} - -void BufferNode::Allocator::delete_list(BufferNode* list) { - while (list != NULL) { - BufferNode* next = list->next(); - DEBUG_ONLY(list->set_next(NULL);) - BufferNode::deallocate(list); - list = next; - } } size_t BufferNode::Allocator::free_count() const { - return Atomic::load(&_free_count); + return _free_list.free_count(); } BufferNode* BufferNode::Allocator::allocate() { - BufferNode* node; - { - // Protect against ABA; see release(). - GlobalCounter::CriticalSection cs(Thread::current()); - node = _free_list.pop(); - } - if (node == NULL) { - node = BufferNode::allocate(_buffer_size); - } else { - // Decrement count after getting buffer from free list. This, along - // with incrementing count before adding to free list, ensures count - // never underflows. - size_t count = Atomic::sub(&_free_count, 1u); - assert((count + 1) != 0, "_free_count underflow"); - } - return node; + return ::new (_free_list.allocate()) BufferNode(); } -// To solve the ABA problem for lock-free stack pop, allocate does the -// pop inside a critical section, and release synchronizes on the -// critical sections before adding to the _free_list. But we don't -// want to make every release have to do a synchronize. Instead, we -// initially place released nodes on the _pending_list, and transfer -// them to the _free_list in batches. Only one transfer at a time is -// permitted, with a lock bit to control access to that phase. A -// transfer takes all the nodes from the _pending_list, synchronizes on -// the _free_list pops, and then adds the former pending nodes to the -// _free_list. While that's happening, other threads might be adding -// other nodes to the _pending_list, to be dealt with by some later -// transfer. void BufferNode::Allocator::release(BufferNode* node) { assert(node != NULL, "precondition"); assert(node->next() == NULL, "precondition"); - - // Desired minimum transfer batch size. There is relatively little - // importance to the specific number. It shouldn't be too big, else - // we're wasting space when the release rate is low. If the release - // rate is high, we might accumulate more than this before being - // able to start a new transfer, but that's okay. Also note that - // the allocation rate and the release rate are going to be fairly - // similar, due to how the buffers are used. - const size_t trigger_transfer = 10; - - // Add to pending list. Update count first so no underflow in transfer. - size_t pending_count = Atomic::add(&_pending_count, 1u); - _pending_list.push(*node); - if (pending_count > trigger_transfer) { - try_transfer_pending(); - } -} - -// Try to transfer nodes from _pending_list to _free_list, with a -// synchronization delay for any in-progress pops from the _free_list, -// to solve ABA there. Return true if performed a (possibly empty) -// transfer, false if blocked from doing so by some other thread's -// in-progress transfer. -bool BufferNode::Allocator::try_transfer_pending() { - // Attempt to claim the lock. - if (Atomic::load(&_transfer_lock) || // Skip CAS if likely to fail. - Atomic::cmpxchg(&_transfer_lock, false, true)) { - return false; - } - // Have the lock; perform the transfer. - - // Claim all the pending nodes. - BufferNode* first = _pending_list.pop_all(); - if (first != NULL) { - // Prepare to add the claimed nodes, and update _pending_count. - BufferNode* last = first; - size_t count = 1; - for (BufferNode* next = first->next(); next != NULL; next = next->next()) { - last = next; - ++count; - } - Atomic::sub(&_pending_count, count); - - // Wait for any in-progress pops, to avoid ABA for them. - GlobalCounter::write_synchronize(); - - // Add synchronized nodes to _free_list. - // Update count first so no underflow in allocate(). - Atomic::add(&_free_count, count); - _free_list.prepend(*first, *last); - log_trace(gc, ptrqueue, freelist) - ("Transferred %s pending to free: " SIZE_FORMAT, name(), count); - } - Atomic::release_store(&_transfer_lock, false); - return true; + node->~BufferNode(); + _free_list.release(node); } size_t BufferNode::Allocator::reduce_free_list(size_t remove_goal) { - try_transfer_pending(); - size_t removed = 0; - for ( ; removed < remove_goal; ++removed) { - BufferNode* node = _free_list.pop(); - if (node == NULL) break; - BufferNode::deallocate(node); - } - size_t new_count = Atomic::sub(&_free_count, removed); - log_debug(gc, ptrqueue, freelist) - ("Reduced %s free list by " SIZE_FORMAT " to " SIZE_FORMAT, - name(), removed, new_count); - return removed; + return _free_list.reduce_free_list(remove_goal); } PtrQueueSet::PtrQueueSet(BufferNode::Allocator* allocator) : diff --git a/src/hotspot/share/gc/shared/ptrQueue.hpp b/src/hotspot/share/gc/shared/ptrQueue.hpp index f1533e5128d29685e1bc5365f746d79346c6d122..844f73941cd1d274637d64e86259934f7bbc67f4 100644 --- a/src/hotspot/share/gc/shared/ptrQueue.hpp +++ b/src/hotspot/share/gc/shared/ptrQueue.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -25,6 +25,7 @@ #ifndef SHARE_GC_SHARED_PTRQUEUE_HPP #define SHARE_GC_SHARED_PTRQUEUE_HPP +#include "gc/shared/freeListAllocator.hpp" #include "memory/padded.hpp" #include "utilities/align.hpp" #include "utilities/debug.hpp" @@ -131,12 +132,6 @@ class BufferNode { return offset_of(BufferNode, _buffer); } - // Allocate a new BufferNode with the "buffer" having size elements. - static BufferNode* allocate(size_t size); - - // Free a BufferNode. - static void deallocate(BufferNode* node); - public: static BufferNode* volatile* next_ptr(BufferNode& bn) { return &bn._next; } typedef LockFreeStack Stack; @@ -162,50 +157,48 @@ public: reinterpret_cast(node) + buffer_offset()); } + class AllocatorConfig; class Allocator; // Free-list based allocator. class TestSupport; // Unit test support. }; -// Allocation is based on a lock-free free list of nodes, linked through -// BufferNode::_next (see BufferNode::Stack). To solve the ABA problem, -// popping a node from the free list is performed within a GlobalCounter -// critical section, and pushing nodes onto the free list is done after -// a GlobalCounter synchronization associated with the nodes to be pushed. -// This is documented behavior so that other parts of the node life-cycle -// can depend on and make use of it too. -class BufferNode::Allocator { - friend class TestSupport; +// We use BufferNode::AllocatorConfig to set the allocation options for the +// FreeListAllocator. +class BufferNode::AllocatorConfig : public FreeListConfig { + const size_t _buffer_size; +public: + explicit AllocatorConfig(size_t size); - // Since we don't expect many instances, and measured >15% speedup - // on stress gtest, padding seems like a good tradeoff here. -#define DECLARE_PADDED_MEMBER(Id, Type, Name) \ - Type Name; DEFINE_PAD_MINUS_SIZE(Id, DEFAULT_CACHE_LINE_SIZE, sizeof(Type)) + ~AllocatorConfig() = default; - const size_t _buffer_size; - char _name[DEFAULT_CACHE_LINE_SIZE - sizeof(size_t)]; // Use name as padding. - DECLARE_PADDED_MEMBER(1, Stack, _pending_list); - DECLARE_PADDED_MEMBER(2, Stack, _free_list); - DECLARE_PADDED_MEMBER(3, volatile size_t, _pending_count); - DECLARE_PADDED_MEMBER(4, volatile size_t, _free_count); - DECLARE_PADDED_MEMBER(5, volatile bool, _transfer_lock); + void* allocate() override; -#undef DECLARE_PADDED_MEMBER + void deallocate(void* node) override; - void delete_list(BufferNode* list); - bool try_transfer_pending(); + size_t buffer_size() const { return _buffer_size; } +}; + +class BufferNode::Allocator { + friend class TestSupport; + + AllocatorConfig _config; + FreeListAllocator _free_list; NONCOPYABLE(Allocator); public: Allocator(const char* name, size_t buffer_size); - ~Allocator(); + ~Allocator() = default; - const char* name() const { return _name; } - size_t buffer_size() const { return _buffer_size; } + size_t buffer_size() const { return _config.buffer_size(); } size_t free_count() const; BufferNode* allocate(); void release(BufferNode* node); + // If _free_list has items buffered in the pending list, transfer + // these to make them available for re-allocation. + bool flush_free_list() { return _free_list.try_transfer_pending(); } + // Deallocate some of the available buffers. remove_goal is the target // number to remove. Returns the number actually deallocated, which may // be less than the goal if there were fewer available. diff --git a/src/hotspot/share/gc/shared/referenceProcessor.cpp b/src/hotspot/share/gc/shared/referenceProcessor.cpp index b1b411e411999b8dd57d9199cec17722ceb398bf..21b57621706ceff97280d9278d6766b1fbe30e0f 100644 --- a/src/hotspot/share/gc/shared/referenceProcessor.cpp +++ b/src/hotspot/share/gc/shared/referenceProcessor.cpp @@ -87,7 +87,6 @@ void ReferenceProcessor::enable_discovery(bool check_no_refs) { ReferenceProcessor::ReferenceProcessor(BoolObjectClosure* is_subject_to_discovery, uint mt_processing_degree, - bool mt_discovery, uint mt_discovery_degree, bool concurrent_discovery, BoolObjectClosure* is_alive_non_header) : @@ -99,7 +98,7 @@ ReferenceProcessor::ReferenceProcessor(BoolObjectClosure* is_subject_to_discover assert(is_subject_to_discovery != NULL, "must be set"); _discovery_is_concurrent = concurrent_discovery; - _discovery_is_mt = mt_discovery; + _discovery_is_mt = (mt_discovery_degree > 1); _num_queues = MAX2(1U, mt_processing_degree); _max_num_queues = MAX2(_num_queues, mt_discovery_degree); _discovered_refs = NEW_C_HEAP_ARRAY(DiscoveredList, @@ -192,13 +191,15 @@ ReferenceProcessorStats ReferenceProcessor::process_discovered_references(RefPro // Stop treating discovered references specially. disable_discovery(); - ReferenceProcessorStats stats(total_count(_discoveredSoftRefs), - total_count(_discoveredWeakRefs), - total_count(_discoveredFinalRefs), - total_count(_discoveredPhantomRefs)); + phase_times.set_ref_discovered(REF_SOFT, total_count(_discoveredSoftRefs)); + phase_times.set_ref_discovered(REF_WEAK, total_count(_discoveredWeakRefs)); + phase_times.set_ref_discovered(REF_FINAL, total_count(_discoveredFinalRefs)); + phase_times.set_ref_discovered(REF_PHANTOM, total_count(_discoveredPhantomRefs)); update_soft_ref_master_clock(); + phase_times.set_processing_is_mt(processing_is_mt()); + { RefProcTotalPhaseTimesTracker tt(SoftWeakFinalRefsPhase, &phase_times); process_soft_weak_final_refs(proxy_task, phase_times); @@ -219,6 +220,10 @@ ReferenceProcessorStats ReferenceProcessor::process_discovered_references(RefPro // Elements on discovered lists were pushed to the pending list. verify_no_references_recorded(); + ReferenceProcessorStats stats(phase_times.ref_discovered(REF_SOFT), + phase_times.ref_discovered(REF_WEAK), + phase_times.ref_discovered(REF_FINAL), + phase_times.ref_discovered(REF_PHANTOM)); return stats; } @@ -478,7 +483,7 @@ void RefProcTask::process_discovered_list(uint worker_id, keep_alive, enqueue, do_enqueue_and_clear); - _phase_times->add_ref_cleared(ref_type, removed); + _phase_times->add_ref_dropped(ref_type, removed); } } @@ -724,14 +729,10 @@ void ReferenceProcessor::run_task(RefProcTask& task, RefProcProxyTask& proxy_tas void ReferenceProcessor::process_soft_weak_final_refs(RefProcProxyTask& proxy_task, ReferenceProcessorPhaseTimes& phase_times) { - size_t const num_soft_refs = total_count(_discoveredSoftRefs); - size_t const num_weak_refs = total_count(_discoveredWeakRefs); - size_t const num_final_refs = total_count(_discoveredFinalRefs); + size_t const num_soft_refs = phase_times.ref_discovered(REF_SOFT); + size_t const num_weak_refs = phase_times.ref_discovered(REF_WEAK); + size_t const num_final_refs = phase_times.ref_discovered(REF_FINAL); size_t const num_total_refs = num_soft_refs + num_weak_refs + num_final_refs; - phase_times.set_ref_discovered(REF_WEAK, num_weak_refs); - phase_times.set_ref_discovered(REF_FINAL, num_final_refs); - - phase_times.set_processing_is_mt(processing_is_mt()); if (num_total_refs == 0) { log_debug(gc, ref)("Skipped SoftWeakFinalRefsPhase of Reference Processing: no references"); @@ -747,8 +748,6 @@ void ReferenceProcessor::process_soft_weak_final_refs(RefProcProxyTask& proxy_ta maybe_balance_queues(_discoveredFinalRefs); } - RefProcPhaseTimeTracker tt(SoftWeakFinalRefsPhase, &phase_times); - log_reflist("SoftWeakFinalRefsPhase Soft before", _discoveredSoftRefs, _max_num_queues); log_reflist("SoftWeakFinalRefsPhase Weak before", _discoveredWeakRefs, _max_num_queues); log_reflist("SoftWeakFinalRefsPhase Final before", _discoveredFinalRefs, _max_num_queues); @@ -764,8 +763,7 @@ void ReferenceProcessor::process_soft_weak_final_refs(RefProcProxyTask& proxy_ta void ReferenceProcessor::process_final_keep_alive(RefProcProxyTask& proxy_task, ReferenceProcessorPhaseTimes& phase_times) { - size_t const num_final_refs = total_count(_discoveredFinalRefs); - phase_times.set_processing_is_mt(processing_is_mt()); + size_t const num_final_refs = phase_times.ref_discovered(REF_FINAL); if (num_final_refs == 0) { log_debug(gc, ref)("Skipped KeepAliveFinalRefsPhase of Reference Processing: no references"); @@ -780,7 +778,6 @@ void ReferenceProcessor::process_final_keep_alive(RefProcProxyTask& proxy_task, } // Traverse referents of final references and keep them and followers alive. - RefProcPhaseTimeTracker tt(KeepAliveFinalRefsPhase, &phase_times); RefProcKeepAliveFinalPhaseTask phase_task(*this, &phase_times); run_task(phase_task, proxy_task, true); @@ -790,9 +787,7 @@ void ReferenceProcessor::process_final_keep_alive(RefProcProxyTask& proxy_task, void ReferenceProcessor::process_phantom_refs(RefProcProxyTask& proxy_task, ReferenceProcessorPhaseTimes& phase_times) { - size_t const num_phantom_refs = total_count(_discoveredPhantomRefs); - phase_times.set_ref_discovered(REF_PHANTOM, num_phantom_refs); - phase_times.set_processing_is_mt(processing_is_mt()); + size_t const num_phantom_refs = phase_times.ref_discovered(REF_PHANTOM); if (num_phantom_refs == 0) { log_debug(gc, ref)("Skipped PhantomRefsPhase of Reference Processing: no references"); @@ -806,9 +801,6 @@ void ReferenceProcessor::process_phantom_refs(RefProcProxyTask& proxy_task, maybe_balance_queues(_discoveredPhantomRefs); } - // Walk phantom references appropriately. - RefProcPhaseTimeTracker tt(PhantomRefsPhase, &phase_times); - log_reflist("PhantomRefsPhase Phantom before", _discoveredPhantomRefs, _max_num_queues); RefProcPhantomPhaseTask phase_task(*this, &phase_times); @@ -823,7 +815,7 @@ inline DiscoveredList* ReferenceProcessor::get_discovered_list(ReferenceType rt) if (_discovery_is_mt) { // During a multi-threaded discovery phase, // each thread saves to its "own" list. - id = WorkerThread::current()->id(); + id = WorkerThread::worker_id(); } else { // single-threaded discovery, we save in round-robin // fashion to each of the lists. @@ -1055,15 +1047,6 @@ bool ReferenceProcessor::discover_reference(oop obj, ReferenceType rt) { return true; } -bool ReferenceProcessor::has_discovered_references() { - for (uint i = 0; i < _max_num_queues * number_of_subclasses_of_ref(); i++) { - if (!_discovered_refs[i].is_empty()) { - return true; - } - } - return false; -} - void ReferenceProcessor::preclean_discovered_references(BoolObjectClosure* is_alive, EnqueueDiscoveredFieldClosure* enqueue, YieldClosure* yield, diff --git a/src/hotspot/share/gc/shared/referenceProcessor.hpp b/src/hotspot/share/gc/shared/referenceProcessor.hpp index 2ab68ab29fec4ffce8a9a779fbfc11e54f5fae1a..a8ea98683e8784e94db9400f57e2b728e1a41959 100644 --- a/src/hotspot/share/gc/shared/referenceProcessor.hpp +++ b/src/hotspot/share/gc/shared/referenceProcessor.hpp @@ -374,7 +374,7 @@ public: // Default parameters give you a vanilla reference processor. ReferenceProcessor(BoolObjectClosure* is_subject_to_discovery, uint mt_processing_degree = 1, - bool mt_discovery = false, uint mt_discovery_degree = 1, + uint mt_discovery_degree = 1, bool concurrent_discovery = false, BoolObjectClosure* is_alive_non_header = NULL); @@ -421,9 +421,6 @@ public: // Discover a Reference object, using appropriate discovery criteria virtual bool discover_reference(oop obj, ReferenceType rt); - // Has discovered references that need handling - bool has_discovered_references(); - // Process references found during GC (called by the garbage collector) ReferenceProcessorStats process_discovered_references(RefProcProxyTask& proxy_task, diff --git a/src/hotspot/share/gc/shared/referenceProcessorPhaseTimes.cpp b/src/hotspot/share/gc/shared/referenceProcessorPhaseTimes.cpp index 87d60b1a6c0b75ec7497fa80740ee9cff85f3084..f3bfcc2269289d10c6a2c7ffa181e2c0366d0b62 100644 --- a/src/hotspot/share/gc/shared/referenceProcessorPhaseTimes.cpp +++ b/src/hotspot/share/gc/shared/referenceProcessorPhaseTimes.cpp @@ -101,10 +101,7 @@ RefProcWorkerTimeTracker::~RefProcWorkerTimeTracker() { RefProcSubPhasesWorkerTimeTracker::RefProcSubPhasesWorkerTimeTracker(ReferenceProcessor::RefProcSubPhases phase, ReferenceProcessorPhaseTimes* phase_times, uint worker_id) : - RefProcWorkerTimeTracker(phase_times->sub_phase_worker_time_sec(phase), worker_id) { -} - -RefProcSubPhasesWorkerTimeTracker::~RefProcSubPhasesWorkerTimeTracker() { + _tracker(phase_times->sub_phase_worker_time_sec(phase), worker_id) { } RefProcPhaseTimeBaseTracker::RefProcPhaseTimeBaseTracker(const char* title, @@ -146,16 +143,6 @@ RefProcBalanceQueuesTimeTracker::~RefProcBalanceQueuesTimeTracker() { phase_times()->set_balance_queues_time_ms(_phase_number, elapsed); } -RefProcPhaseTimeTracker::RefProcPhaseTimeTracker(ReferenceProcessor::RefProcPhases phase_number, - ReferenceProcessorPhaseTimes* phase_times) : - RefProcPhaseTimeBaseTracker(phase_enum_2_phase_string(phase_number), phase_number, phase_times) { -} - -RefProcPhaseTimeTracker::~RefProcPhaseTimeTracker() { - double elapsed = elapsed_time(); - phase_times()->set_phase_time_ms(_phase_number, elapsed); -} - RefProcTotalPhaseTimesTracker::RefProcTotalPhaseTimesTracker(ReferenceProcessor::RefProcPhases phase_number, ReferenceProcessorPhaseTimes* phase_times) : RefProcPhaseTimeBaseTracker(phase_enum_2_phase_string(phase_number), phase_number, phase_times) { @@ -200,7 +187,6 @@ void ReferenceProcessorPhaseTimes::set_phase_time_ms(ReferenceProcessor::RefProc void ReferenceProcessorPhaseTimes::reset() { for (int i = 0; i < ReferenceProcessor::RefSubPhaseMax; i++) { _sub_phases_worker_time_sec[i]->reset(); - _sub_phases_total_time_ms[i] = uninitialized(); } for (int i = 0; i < ReferenceProcessor::RefPhaseMax; i++) { @@ -211,7 +197,7 @@ void ReferenceProcessorPhaseTimes::reset() { _soft_weak_final_refs_phase_worker_time_sec->reset(); for (int i = 0; i < number_of_subclasses_of_ref; i++) { - _ref_cleared[i] = 0; + _ref_dropped[i] = 0; _ref_discovered[i] = 0; } @@ -227,20 +213,9 @@ ReferenceProcessorPhaseTimes::~ReferenceProcessorPhaseTimes() { delete _soft_weak_final_refs_phase_worker_time_sec; } -double ReferenceProcessorPhaseTimes::sub_phase_total_time_ms(ReferenceProcessor::RefProcSubPhases sub_phase) const { - ASSERT_SUB_PHASE(sub_phase); - return _sub_phases_total_time_ms[sub_phase]; -} - -void ReferenceProcessorPhaseTimes::set_sub_phase_total_phase_time_ms(ReferenceProcessor::RefProcSubPhases sub_phase, - double time_ms) { - ASSERT_SUB_PHASE(sub_phase); - _sub_phases_total_time_ms[sub_phase] = time_ms; -} - -void ReferenceProcessorPhaseTimes::add_ref_cleared(ReferenceType ref_type, size_t count) { +void ReferenceProcessorPhaseTimes::add_ref_dropped(ReferenceType ref_type, size_t count) { ASSERT_REF_TYPE(ref_type); - Atomic::add(&_ref_cleared[ref_type_2_index(ref_type)], count, memory_order_relaxed); + Atomic::add(&_ref_dropped[ref_type_2_index(ref_type)], count, memory_order_relaxed); } void ReferenceProcessorPhaseTimes::set_ref_discovered(ReferenceType ref_type, size_t count) { @@ -248,6 +223,11 @@ void ReferenceProcessorPhaseTimes::set_ref_discovered(ReferenceType ref_type, si _ref_discovered[ref_type_2_index(ref_type)] = count; } +size_t ReferenceProcessorPhaseTimes::ref_discovered(ReferenceType ref_type) { + ASSERT_REF_TYPE(ref_type); + return _ref_discovered[ref_type_2_index(ref_type)]; +} + double ReferenceProcessorPhaseTimes::balance_queues_time_ms(ReferenceProcessor::RefProcPhases phase) const { ASSERT_PHASE(phase); return _balance_queues_time_ms[phase]; @@ -290,13 +270,16 @@ void ReferenceProcessorPhaseTimes::print_reference(ReferenceType ref_type, uint LogStream ls(lt); ResourceMark rm; - ls.print_cr("%s%s:", Indents[base_indent], ref_type_2_string(ref_type)); - - uint const next_indent = base_indent + 1; int const ref_type_index = ref_type_2_index(ref_type); - ls.print_cr("%sDiscovered: " SIZE_FORMAT, Indents[next_indent], _ref_discovered[ref_type_index]); - ls.print_cr("%sCleared: " SIZE_FORMAT, Indents[next_indent], _ref_cleared[ref_type_index]); + size_t discovered = _ref_discovered[ref_type_index]; + size_t dropped = _ref_dropped[ref_type_index]; + assert(discovered >= dropped, "invariant"); + size_t processed = discovered - dropped; + + ls.print_cr("%s%s Discovered: %zu, Dropped: %zu, Processed: %zu", + Indents[base_indent], ref_type_2_string(ref_type), + discovered, dropped, processed); } } diff --git a/src/hotspot/share/gc/shared/referenceProcessorPhaseTimes.hpp b/src/hotspot/share/gc/shared/referenceProcessorPhaseTimes.hpp index 5d1f2d2eeb7c6ec83797612795caa6720ecfa2ad..26ee4e2a918141816166d749cdee98f3f8c22f00 100644 --- a/src/hotspot/share/gc/shared/referenceProcessorPhaseTimes.hpp +++ b/src/hotspot/share/gc/shared/referenceProcessorPhaseTimes.hpp @@ -41,8 +41,6 @@ class ReferenceProcessorPhaseTimes : public CHeapObj { // Records per thread time information of each sub phase. WorkerDataArray* _sub_phases_worker_time_sec[ReferenceProcessor::RefSubPhaseMax]; - // Total time of each sub phase. - double _sub_phases_total_time_ms[ReferenceProcessor::RefSubPhaseMax]; // Records total elapsed time for each phase. double _phases_time_ms[ReferenceProcessor::RefPhaseMax]; @@ -54,7 +52,7 @@ class ReferenceProcessorPhaseTimes : public CHeapObj { // Total spent time for reference processing. double _total_time_ms; - size_t _ref_cleared[number_of_subclasses_of_ref]; + size_t _ref_dropped[number_of_subclasses_of_ref]; size_t _ref_discovered[number_of_subclasses_of_ref]; bool _processing_is_mt; @@ -62,7 +60,6 @@ class ReferenceProcessorPhaseTimes : public CHeapObj { GCTimer* _gc_timer; double phase_time_ms(ReferenceProcessor::RefProcPhases phase) const; - double sub_phase_total_time_ms(ReferenceProcessor::RefProcSubPhases sub_phase) const; double total_time_ms() const { return _total_time_ms; } @@ -84,12 +81,11 @@ public: WorkerDataArray* sub_phase_worker_time_sec(ReferenceProcessor::RefProcSubPhases phase) const; void set_phase_time_ms(ReferenceProcessor::RefProcPhases phase, double par_phase_time_ms); - void set_sub_phase_total_phase_time_ms(ReferenceProcessor::RefProcSubPhases sub_phase, double ref_proc_time_ms); - void set_total_time_ms(double total_time_ms) { _total_time_ms = total_time_ms; } - void add_ref_cleared(ReferenceType ref_type, size_t count); + void add_ref_dropped(ReferenceType ref_type, size_t count); void set_ref_discovered(ReferenceType ref_type, size_t count); + size_t ref_discovered(ReferenceType ref_type); void set_balance_queues_time_ms(ReferenceProcessor::RefProcPhases phase, double time_ms); @@ -103,23 +99,23 @@ public: void print_all_references(uint base_indent = 0, bool print_total = true) const; }; -class RefProcWorkerTimeTracker : public CHeapObj { +class RefProcWorkerTimeTracker : public StackObj { protected: WorkerDataArray* _worker_time; double _start_time; uint _worker_id; public: RefProcWorkerTimeTracker(WorkerDataArray* worker_time, uint worker_id); - virtual ~RefProcWorkerTimeTracker(); + ~RefProcWorkerTimeTracker(); }; // Updates working time of each worker thread for a given sub phase. -class RefProcSubPhasesWorkerTimeTracker : public RefProcWorkerTimeTracker { +class RefProcSubPhasesWorkerTimeTracker : public StackObj { + RefProcWorkerTimeTracker _tracker; public: RefProcSubPhasesWorkerTimeTracker(ReferenceProcessor::RefProcSubPhases phase, ReferenceProcessorPhaseTimes* phase_times, uint worker_id); - ~RefProcSubPhasesWorkerTimeTracker(); }; class RefProcPhaseTimeBaseTracker : public StackObj { @@ -150,14 +146,6 @@ public: ~RefProcBalanceQueuesTimeTracker(); }; -// Updates phase time at ReferenceProcessorPhaseTimes and save it into GCTimer. -class RefProcPhaseTimeTracker : public RefProcPhaseTimeBaseTracker { -public: - RefProcPhaseTimeTracker(ReferenceProcessor::RefProcPhases phase_number, - ReferenceProcessorPhaseTimes* phase_times); - ~RefProcPhaseTimeTracker(); -}; - // Highest level time tracker. class RefProcTotalPhaseTimesTracker : public RefProcPhaseTimeBaseTracker { public: diff --git a/src/hotspot/share/gc/shared/scavengableNMethods.hpp b/src/hotspot/share/gc/shared/scavengableNMethods.hpp index 276ea9843c0f0b7bd596cfba3511660011c46533..4852e6d32fbf92f81579fa17f20dba5a72056164 100644 --- a/src/hotspot/share/gc/shared/scavengableNMethods.hpp +++ b/src/hotspot/share/gc/shared/scavengableNMethods.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -25,7 +25,7 @@ #ifndef SHARE_GC_SHARED_SCAVENGABLENMETHODS_HPP #define SHARE_GC_SHARED_SCAVENGABLENMETHODS_HPP -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" #include "utilities/macros.hpp" class BoolObjectClosure; diff --git a/src/hotspot/share/gc/shared/space.cpp b/src/hotspot/share/gc/shared/space.cpp index 1638d994e407e4b5a02c2774c30368df3cd4815c..67d76173614347d220263eb3e0a2253185fc60c8 100644 --- a/src/hotspot/share/gc/shared/space.cpp +++ b/src/hotspot/share/gc/shared/space.cpp @@ -376,7 +376,7 @@ HeapWord* CompactibleSpace::forward(oop q, size_t size, // if the object isn't moving we can just set the mark to the default // mark and handle it specially later on. q->init_mark(); - assert(q->forwardee() == NULL, "should be forwarded to NULL"); + assert(!q->is_forwarded(), "should not be forwarded"); } compact_top += size; @@ -536,7 +536,7 @@ void CompactibleSpace::compact() { debug_only(HeapWord* prev_obj = NULL); while (cur_obj < end_of_live) { - if (!cast_to_oop(cur_obj)->is_gc_marked()) { + if (!cast_to_oop(cur_obj)->is_forwarded()) { debug_only(prev_obj = cur_obj); // The first word of the dead object contains a pointer to the next live object or end of space. cur_obj = *(HeapWord**)cur_obj; @@ -730,38 +730,6 @@ HeapWord* ContiguousSpace::par_allocate(size_t size) { return par_allocate_impl(size); } -void ContiguousSpace::allocate_temporary_filler(int factor) { - // allocate temporary type array decreasing free size with factor 'factor' - assert(factor >= 0, "just checking"); - size_t size = pointer_delta(end(), top()); - - // if space is full, return - if (size == 0) return; - - if (factor > 0) { - size -= size/factor; - } - size = align_object_size(size); - - const size_t array_header_size = typeArrayOopDesc::header_size(T_INT); - if (size >= align_object_size(array_header_size)) { - size_t length = (size - array_header_size) * (HeapWordSize / sizeof(jint)); - // allocate uninitialized int array - typeArrayOop t = (typeArrayOop) cast_to_oop(allocate(size)); - assert(t != NULL, "allocation should succeed"); - t->set_mark(markWord::prototype()); - t->set_klass(Universe::intArrayKlassObj()); - t->set_length((int)length); - } else { - assert(size == CollectedHeap::min_fill_size(), - "size for smallest fake object doesn't match"); - instanceOop obj = (instanceOop) cast_to_oop(allocate(size)); - obj->set_mark(markWord::prototype()); - obj->set_klass_gap(0); - obj->set_klass(vmClasses::Object_klass()); - } -} - void OffsetTableContigSpace::initialize_threshold() { _offsets.initialize_threshold(); } diff --git a/src/hotspot/share/gc/shared/space.hpp b/src/hotspot/share/gc/shared/space.hpp index f2a9c24904ed9b6c2897652e6910a1a115b0596f..9c94a24e4254dc8823e84cf417e22df3fe1e6790 100644 --- a/src/hotspot/share/gc/shared/space.hpp +++ b/src/hotspot/share/gc/shared/space.hpp @@ -532,10 +532,6 @@ class ContiguousSpace: public CompactibleSpace { // Debugging virtual void verify() const; - - // Used to increase collection frequency. "factor" of 0 means entire - // space. - void allocate_temporary_filler(int factor); }; diff --git a/src/hotspot/share/gc/shared/spaceDecorator.hpp b/src/hotspot/share/gc/shared/spaceDecorator.hpp index d421a2a40f5ca80e7c6f5292f6572480f4b53fd7..778881f75a1a2ea9bc56ea96e3b0ed37b1a3806c 100644 --- a/src/hotspot/share/gc/shared/spaceDecorator.hpp +++ b/src/hotspot/share/gc/shared/spaceDecorator.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 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 @@ -25,7 +25,7 @@ #ifndef SHARE_GC_SHARED_SPACEDECORATOR_HPP #define SHARE_GC_SHARED_SPACEDECORATOR_HPP -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" #include "memory/memRegion.hpp" #include "utilities/globalDefinitions.hpp" diff --git a/src/hotspot/share/gc/shared/stringdedup/stringDedupConfig.cpp b/src/hotspot/share/gc/shared/stringdedup/stringDedupConfig.cpp index a01548a72b08d3d5c69da9b9cb57abb98dd18beb..3fa3df12891ec84eb9757bd0e80d83704a03c464 100644 --- a/src/hotspot/share/gc/shared/stringdedup/stringDedupConfig.cpp +++ b/src/hotspot/share/gc/shared/stringdedup/stringDedupConfig.cpp @@ -161,6 +161,6 @@ void StringDedup::Config::initialize() { _load_factor_for_shrink = StringDeduplicationShrinkTableLoad; _load_factor_target = StringDeduplicationTargetTableLoad; _minimum_dead_for_cleanup = StringDeduplicationCleanupDeadMinimum; - _dead_factor_for_cleanup = percent_of(StringDeduplicationCleanupDeadPercent, 100); + _dead_factor_for_cleanup = StringDeduplicationCleanupDeadPercent / 100.0; _hash_seed = initial_hash_seed(); } diff --git a/src/hotspot/share/gc/shared/suspendibleThreadSet.cpp b/src/hotspot/share/gc/shared/suspendibleThreadSet.cpp index e91b1b49802094e5a67b656edb6f2750d37a7bae..2636cc920618dc967ff8773c26c5c9cdb21d08ad 100644 --- a/src/hotspot/share/gc/shared/suspendibleThreadSet.cpp +++ b/src/hotspot/share/gc/shared/suspendibleThreadSet.cpp @@ -29,10 +29,10 @@ #include "runtime/semaphore.hpp" #include "runtime/thread.inline.hpp" -uint SuspendibleThreadSet::_nthreads = 0; -uint SuspendibleThreadSet::_nthreads_stopped = 0; -bool SuspendibleThreadSet::_suspend_all = false; -double SuspendibleThreadSet::_suspend_all_start = 0.0; +uint SuspendibleThreadSet::_nthreads = 0; +uint SuspendibleThreadSet::_nthreads_stopped = 0; +volatile bool SuspendibleThreadSet::_suspend_all = false; +double SuspendibleThreadSet::_suspend_all_start = 0.0; static Semaphore* _synchronize_wakeup = NULL; @@ -50,7 +50,7 @@ bool SuspendibleThreadSet::is_synchronized() { void SuspendibleThreadSet::join() { assert(!Thread::current()->is_suspendible_thread(), "Thread already joined"); MonitorLocker ml(STS_lock, Mutex::_no_safepoint_check_flag); - while (_suspend_all) { + while (suspend_all()) { ml.wait(); } _nthreads++; @@ -63,7 +63,7 @@ void SuspendibleThreadSet::leave() { assert(_nthreads > 0, "Invalid"); DEBUG_ONLY(Thread::current()->clear_suspendible_thread();) _nthreads--; - if (_suspend_all && is_synchronized()) { + if (suspend_all() && is_synchronized()) { // This leave completes a request, so inform the requestor. _synchronize_wakeup->signal(); } @@ -72,7 +72,7 @@ void SuspendibleThreadSet::leave() { void SuspendibleThreadSet::yield() { assert(Thread::current()->is_suspendible_thread(), "Must have joined"); MonitorLocker ml(STS_lock, Mutex::_no_safepoint_check_flag); - if (_suspend_all) { + if (suspend_all()) { _nthreads_stopped++; if (is_synchronized()) { if (ConcGCYieldTimeout > 0) { @@ -82,7 +82,7 @@ void SuspendibleThreadSet::yield() { // This yield completes the request, so inform the requestor. _synchronize_wakeup->signal(); } - while (_suspend_all) { + while (suspend_all()) { ml.wait(); } assert(_nthreads_stopped > 0, "Invalid"); @@ -97,8 +97,8 @@ void SuspendibleThreadSet::synchronize() { } { MonitorLocker ml(STS_lock, Mutex::_no_safepoint_check_flag); - assert(!_suspend_all, "Only one at a time"); - _suspend_all = true; + assert(!suspend_all(), "Only one at a time"); + Atomic::store(&_suspend_all, true); if (is_synchronized()) { return; } @@ -120,7 +120,7 @@ void SuspendibleThreadSet::synchronize() { #ifdef ASSERT MonitorLocker ml(STS_lock, Mutex::_no_safepoint_check_flag); - assert(_suspend_all, "STS not synchronizing"); + assert(suspend_all(), "STS not synchronizing"); assert(is_synchronized(), "STS not synchronized"); #endif } @@ -128,8 +128,8 @@ void SuspendibleThreadSet::synchronize() { void SuspendibleThreadSet::desynchronize() { assert(Thread::current()->is_VM_thread(), "Must be the VM thread"); MonitorLocker ml(STS_lock, Mutex::_no_safepoint_check_flag); - assert(_suspend_all, "STS not synchronizing"); + assert(suspend_all(), "STS not synchronizing"); assert(is_synchronized(), "STS not synchronized"); - _suspend_all = false; + Atomic::store(&_suspend_all, false); ml.notify_all(); } diff --git a/src/hotspot/share/gc/shared/suspendibleThreadSet.hpp b/src/hotspot/share/gc/shared/suspendibleThreadSet.hpp index 1e47c3b57a87c49cd18a7a00af75d47ff5e003b4..37d27f3e9ed94b93092a6426c03cc280b217bd1f 100644 --- a/src/hotspot/share/gc/shared/suspendibleThreadSet.hpp +++ b/src/hotspot/share/gc/shared/suspendibleThreadSet.hpp @@ -26,6 +26,7 @@ #define SHARE_GC_SHARED_SUSPENDIBLETHREADSET_HPP #include "memory/allocation.hpp" +#include "runtime/atomic.hpp" // A SuspendibleThreadSet is a set of threads that can be suspended. // A thread can join and later leave the set, and periodically yield. @@ -40,9 +41,10 @@ class SuspendibleThreadSet : public AllStatic { friend class SuspendibleThreadSetLeaver; private: + static volatile bool _suspend_all; + static uint _nthreads; static uint _nthreads_stopped; - static bool _suspend_all; static double _suspend_all_start; static bool is_synchronized(); @@ -53,9 +55,11 @@ private: // Removes the current thread from the set. static void leave(); + static bool suspend_all() { return Atomic::load(&_suspend_all); } + public: // Returns true if an suspension is in progress. - static bool should_yield() { return _suspend_all; } + static bool should_yield() { return suspend_all(); } // Suspends the current thread if a suspension is in progress. static void yield(); diff --git a/src/hotspot/share/gc/shared/taskqueue.cpp b/src/hotspot/share/gc/shared/taskqueue.cpp index 2ed1c613bc83f14de65c8dc439fa5f06cf89b4b3..1a11a536683674abccc9c11757670c728063b08e 100644 --- a/src/hotspot/share/gc/shared/taskqueue.cpp +++ b/src/hotspot/share/gc/shared/taskqueue.cpp @@ -34,7 +34,9 @@ #if TASKQUEUE_STATS const char * const TaskQueueStats::_names[last_stat_id] = { - "qpush", "qpop", "qpop-s", "qattempt", "qsteal", "opush", "omax" + "push", "pop", "pop-slow", + "st-attempt", "st-empty", "st-ctdd", "st-success", "st-ctdd-max", "st-biasdrop", + "ovflw-push", "ovflw-max" }; TaskQueueStats & TaskQueueStats::operator +=(const TaskQueueStats & addend) @@ -86,20 +88,29 @@ void TaskQueueStats::print(outputStream* stream, unsigned int width) const // quiescent; they do not hold at arbitrary times. void TaskQueueStats::verify() const { - assert(get(push) == get(pop) + get(steal), - "push=" SIZE_FORMAT " pop=" SIZE_FORMAT " steal=" SIZE_FORMAT, - get(push), get(pop), get(steal)); + assert(get(push) == get(pop) + get(steal_success), + "push=%zu pop=%zu steal=%zu", + get(push), get(pop), get(steal_success)); assert(get(pop_slow) <= get(pop), - "pop_slow=" SIZE_FORMAT " pop=" SIZE_FORMAT, + "pop_slow=%zu pop=%zu", get(pop_slow), get(pop)); - assert(get(steal) <= get(steal_attempt), - "steal=" SIZE_FORMAT " steal_attempt=" SIZE_FORMAT, - get(steal), get(steal_attempt)); + assert(get(steal_empty) <= get(steal_attempt), + "steal_empty=%zu steal_attempt=%zu", + get(steal_empty), get(steal_attempt)); + assert(get(steal_contended) <= get(steal_attempt), + "steal_contended=%zu steal_attempt=%zu", + get(steal_contended), get(steal_attempt)); + assert(get(steal_success) <= get(steal_attempt), + "steal_success=%zu steal_attempt=%zu", + get(steal_success), get(steal_attempt)); + assert(get(steal_empty) + get(steal_contended) + get(steal_success) == get(steal_attempt), + "steal_empty=%zu steal_contended=%zu steal_success=%zu steal_attempt=%zu", + get(steal_empty), get(steal_contended), get(steal_success), get(steal_attempt)); assert(get(overflow) == 0 || get(push) != 0, - "overflow=" SIZE_FORMAT " push=" SIZE_FORMAT, + "overflow=%zu push=%zu", get(overflow), get(push)); assert(get(overflow_max_len) == 0 || get(overflow) != 0, - "overflow_max_len=" SIZE_FORMAT " overflow=" SIZE_FORMAT, + "overflow_max_len=%zu overflow=%zu", get(overflow_max_len), get(overflow)); } #endif // ASSERT diff --git a/src/hotspot/share/gc/shared/taskqueue.hpp b/src/hotspot/share/gc/shared/taskqueue.hpp index 325ab3529175f5404af98d5888c6b6985aef3490..0c15c38a4d0853281d644de2fed22158c64890c6 100644 --- a/src/hotspot/share/gc/shared/taskqueue.hpp +++ b/src/hotspot/share/gc/shared/taskqueue.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -56,7 +56,11 @@ public: pop, // number of taskqueue pops pop_slow, // subset of taskqueue pops that were done slow-path steal_attempt, // number of taskqueue steal attempts - steal, // number of taskqueue steals + steal_empty, // number of empty taskqueues + steal_contended, // number of contended steals + steal_success, // number of successful steals + steal_max_contended_in_a_row, // maximum number of contended steals in a row + steal_bias_drop, // number of times the bias has been dropped overflow, // number of overflow pushes overflow_max_len, // max length of overflow stack last_stat_id @@ -68,8 +72,16 @@ public: inline void record_push() { ++_stats[push]; } inline void record_pop() { ++_stats[pop]; } inline void record_pop_slow() { record_pop(); ++_stats[pop_slow]; } - inline void record_steal_attempt() { ++_stats[steal_attempt]; } - inline void record_steal() { ++_stats[steal]; } + inline void record_steal_attempt(uint kind) { + ++_stats[steal_attempt]; + ++_stats[steal_empty + kind]; + } + inline void record_contended_in_a_row(uint in_a_row) { + if (_stats[steal_max_contended_in_a_row] < in_a_row) { + _stats[steal_max_contended_in_a_row] = in_a_row; + } + } + inline void record_bias_drop() { ++_stats[steal_bias_drop]; } inline void record_overflow(size_t new_length); TaskQueueStats & operator +=(const TaskQueueStats & addend); @@ -81,9 +93,9 @@ public: // Print the specified line of the header (does not include a line separator). static void print_header(unsigned int line, outputStream* const stream = tty, - unsigned int width = 10); + unsigned int width = 11); // Print the statistics (does not include a line separator). - void print(outputStream* const stream = tty, unsigned int width = 10) const; + void print(outputStream* const stream = tty, unsigned int width = 11) const; DEBUG_ONLY(void verify() const;) @@ -268,6 +280,16 @@ public: // in GenericTaskQueue. uint max_elems() const { return N - 2; } + // The result of a pop_global operation. The value order of this must correspond + // to the order in the corresponding TaskQueueStats StatId. + enum class PopResult : uint { + Empty = 0, // Queue has been empty. t is undefined. + Contended = 1, // Contention prevented successful retrieval, queue most likely contains elements. t is undefined. + Success = 2 // Successfully retrieved an element, t contains it. + }; + + TASKQUEUE_STATS_ONLY(void record_steal_attempt(PopResult kind) { stats.record_steal_attempt((uint)kind); }) + TASKQUEUE_STATS_ONLY(TaskQueueStats stats;) }; @@ -328,6 +350,8 @@ protected: using TaskQueueSuper::assert_not_underflow; public: + typedef typename TaskQueueSuper::PopResult PopResult; + using TaskQueueSuper::max_elems; using TaskQueueSuper::size; @@ -357,7 +381,7 @@ public: // Like pop_local(), but uses the "global" end of the queue (the least // recently pushed). - bool pop_global(E& t); + PopResult pop_global(E& t); // Delete any resource associated with the queue. ~GenericTaskQueue(); @@ -387,7 +411,10 @@ public: void set_last_stolen_queue_id(uint id) { _last_stolen_queue_id = id; } uint last_stolen_queue_id() const { return _last_stolen_queue_id; } bool is_last_stolen_queue_id_valid() const { return _last_stolen_queue_id != InvalidQueueId; } - void invalidate_last_stolen_queue_id() { _last_stolen_queue_id = InvalidQueueId; } + void invalidate_last_stolen_queue_id() { + TASKQUEUE_STATS_ONLY(stats.record_bias_drop();) + _last_stolen_queue_id = InvalidQueueId; + } }; // OverflowTaskQueue is a TaskQueue that also includes an overflow stack for @@ -447,12 +474,16 @@ template class GenericTaskQueueSet: public TaskQueueSetSuperImpl { public: typedef typename T::element_type E; + typedef typename T::PopResult PopResult; private: uint _n; T** _queues; - bool steal_best_of_2(uint queue_num, E& t); + // Attempts to steal an element from a foreign queue (!= queue_num), setting + // the result in t. Validity of this value and the return value is the same + // as for the last pop_global() operation. + PopResult steal_best_of_2(uint queue_num, E& t); public: GenericTaskQueueSet(uint n); @@ -473,6 +504,18 @@ public: virtual uint tasks() const; uint size() const { return _n; } + +#if TASKQUEUE_STATS +private: + static void print_taskqueue_stats_hdr(outputStream* const st, const char* label); +public: + void print_taskqueue_stats(outputStream* const st, const char* label); + void reset_taskqueue_stats(); + + // Prints taskqueue set statistics into gc+task+stats=trace and resets + // its statistics. + void print_and_reset_taskqueue_stats(const char* label); +#endif // TASKQUEUE_STATS }; template void @@ -483,6 +526,7 @@ GenericTaskQueueSet::register_queue(uint i, T* q) { template T* GenericTaskQueueSet::queue(uint i) { + assert(i < _n, "index out of range."); return _queues[i]; } @@ -536,7 +580,6 @@ class PartialArrayScanTask { oop _src; public: - PartialArrayScanTask() : _src() {} explicit PartialArrayScanTask(oop src_array) : _src(src_array) {} // Trivially copyable. diff --git a/src/hotspot/share/gc/shared/taskqueue.inline.hpp b/src/hotspot/share/gc/shared/taskqueue.inline.hpp index b6e8e7a4095c965a13caf9a0508b3fa3a8e96ac0..f544a24d5361526d4771cf64ace29cc0ed645881 100644 --- a/src/hotspot/share/gc/shared/taskqueue.inline.hpp +++ b/src/hotspot/share/gc/shared/taskqueue.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -27,11 +27,15 @@ #include "gc/shared/taskqueue.hpp" +#include "logging/log.hpp" +#include "logging/logStream.hpp" #include "memory/allocation.inline.hpp" +#include "memory/resourceArea.hpp" #include "oops/oop.inline.hpp" #include "runtime/atomic.hpp" #include "runtime/orderAccess.hpp" #include "utilities/debug.hpp" +#include "utilities/ostream.hpp" #include "utilities/stack.inline.hpp" template @@ -48,6 +52,51 @@ inline GenericTaskQueueSet::~GenericTaskQueueSet() { FREE_C_HEAP_ARRAY(T*, _queues); } +#if TASKQUEUE_STATS +template +void GenericTaskQueueSet::print_taskqueue_stats_hdr(outputStream* const st, const char* label) { + st->print_cr("GC Task Stats %s", label); + st->print("thr "); TaskQueueStats::print_header(1, st); st->cr(); + st->print("--- "); TaskQueueStats::print_header(2, st); st->cr(); +} + +template +void GenericTaskQueueSet::print_taskqueue_stats(outputStream* const st, const char* label) { + print_taskqueue_stats_hdr(st, label); + + TaskQueueStats totals; + const uint n = size(); + for (uint i = 0; i < n; ++i) { + st->print("%3u ", i); queue(i)->stats.print(st); st->cr(); + totals += queue(i)->stats; + } + st->print_raw("tot "); totals.print(st); st->cr(); + + DEBUG_ONLY(totals.verify()); +} + +template +void GenericTaskQueueSet::reset_taskqueue_stats() { + const uint n = size(); + for (uint i = 0; i < n; ++i) { + queue(i)->stats.reset(); + } +} + +template +inline void GenericTaskQueueSet::print_and_reset_taskqueue_stats(const char* label) { + if (!log_is_enabled(Trace, gc, task, stats)) { + return; + } + Log(gc, task, stats) log; + ResourceMark rm; + LogStream ls(log.trace()); + + print_taskqueue_stats(&ls, label); + reset_taskqueue_stats(); +} +#endif // TASKQUEUE_STATS + template inline GenericTaskQueue::GenericTaskQueue() : _elems(ArrayAllocator::allocate(N, F)), @@ -205,7 +254,7 @@ bool OverflowTaskQueue::pop_overflow(E& t) // reads elems[oldAge.top]. The owner's bottom == the thief's oldAge.top. // (4) Thief will discard the read value, because its cmpxchg of age will fail. template -bool GenericTaskQueue::pop_global(E& t) { +typename GenericTaskQueue::PopResult GenericTaskQueue::pop_global(E& t) { Age oldAge = age_relaxed(); // Architectures with non-multi-copy-atomic memory model require a @@ -226,7 +275,7 @@ bool GenericTaskQueue::pop_global(E& t) { uint localBot = bottom_acquire(); uint n_elems = clean_size(localBot, oldAge.top()); if (n_elems == 0) { - return false; + return PopResult::Empty; } t = _elems[oldAge.top()]; @@ -240,7 +289,7 @@ bool GenericTaskQueue::pop_global(E& t) { // Note that using "bottom" here might fail, since a pop_local might // have decremented it. assert_not_underflow(localBot, newAge.top()); - return resAge == oldAge; + return resAge == oldAge ? PopResult::Success : PopResult::Contended; } inline int randomParkAndMiller(int *seed0) { @@ -267,10 +316,10 @@ int GenericTaskQueue::next_random_queue_id() { return randomParkAndMiller(&_seed); } -template bool -GenericTaskQueueSet::steal_best_of_2(uint queue_num, E& t) { +template +typename GenericTaskQueueSet::PopResult GenericTaskQueueSet::steal_best_of_2(uint queue_num, E& t) { + T* const local_queue = queue(queue_num); if (_n > 2) { - T* const local_queue = _queues[queue_num]; uint k1 = queue_num; if (local_queue->is_last_stolen_queue_id_valid()) { @@ -287,21 +336,23 @@ GenericTaskQueueSet::steal_best_of_2(uint queue_num, E& t) { k2 = local_queue->next_random_queue_id() % _n; } // Sample both and try the larger. - uint sz1 = _queues[k1]->size(); - uint sz2 = _queues[k2]->size(); + uint sz1 = queue(k1)->size(); + uint sz2 = queue(k2)->size(); uint sel_k = 0; - bool suc = false; + PopResult suc = PopResult::Empty; if (sz2 > sz1) { sel_k = k2; - suc = _queues[k2]->pop_global(t); + suc = queue(k2)->pop_global(t); + TASKQUEUE_STATS_ONLY(local_queue->record_steal_attempt(suc);) } else if (sz1 > 0) { sel_k = k1; - suc = _queues[k1]->pop_global(t); + suc = queue(k1)->pop_global(t); + TASKQUEUE_STATS_ONLY(local_queue->record_steal_attempt(suc);) } - if (suc) { + if (suc == PopResult::Success) { local_queue->set_last_stolen_queue_id(sel_k); } else { local_queue->invalidate_last_stolen_queue_id(); @@ -311,20 +362,33 @@ GenericTaskQueueSet::steal_best_of_2(uint queue_num, E& t) { } else if (_n == 2) { // Just try the other one. uint k = (queue_num + 1) % 2; - return _queues[k]->pop_global(t); + PopResult res = queue(k)->pop_global(t); + TASKQUEUE_STATS_ONLY(local_queue->record_steal_attempt(res);) + return res; } else { assert(_n == 1, "can't be zero."); - return false; + TASKQUEUE_STATS_ONLY(local_queue->record_steal_attempt(PopResult::Empty);) + return PopResult::Empty; } } -template bool -GenericTaskQueueSet::steal(uint queue_num, E& t) { - for (uint i = 0; i < 2 * _n; i++) { - TASKQUEUE_STATS_ONLY(queue(queue_num)->stats.record_steal_attempt()); - if (steal_best_of_2(queue_num, t)) { - TASKQUEUE_STATS_ONLY(queue(queue_num)->stats.record_steal()); +template +bool GenericTaskQueueSet::steal(uint queue_num, E& t) { + uint const num_retries = 2 * _n; + + TASKQUEUE_STATS_ONLY(uint contended_in_a_row = 0;) + for (uint i = 0; i < num_retries; i++) { + PopResult sr = steal_best_of_2(queue_num, t); + if (sr == PopResult::Success) { return true; + } else if (sr == PopResult::Contended) { + TASKQUEUE_STATS_ONLY( + contended_in_a_row++; + queue(queue_num)->stats.record_contended_in_a_row(contended_in_a_row); + ) + } else { + assert(sr == PopResult::Empty, "must be"); + TASKQUEUE_STATS_ONLY(contended_in_a_row = 0;) } } return false; diff --git a/src/hotspot/share/gc/shared/verifyOption.hpp b/src/hotspot/share/gc/shared/verifyOption.hpp index c4c9afccbfba58e4445eb1c5ef44bb21ed3d56ed..00058731b280cdeb1d59663774f96e85f4402b39 100644 --- a/src/hotspot/share/gc/shared/verifyOption.hpp +++ b/src/hotspot/share/gc/shared/verifyOption.hpp @@ -30,8 +30,7 @@ enum VerifyOption { // G1 VerifyOption_G1UsePrevMarking = VerifyOption_Default, - VerifyOption_G1UseNextMarking = VerifyOption_G1UsePrevMarking + 1, - VerifyOption_G1UseFullMarking = VerifyOption_G1UseNextMarking + 1 + VerifyOption_G1UseFullMarking = VerifyOption_G1UsePrevMarking + 1 }; #endif // SHARE_GC_SHARED_VERIFYOPTION_HPP diff --git a/src/hotspot/share/gc/shared/vmStructs_gc.hpp b/src/hotspot/share/gc/shared/vmStructs_gc.hpp index 2de1cc8c57cd279a43bb0b6fa4646099746ae81c..d5cf2c15373e0246198a25d160993920c0d4f9b4 100644 --- a/src/hotspot/share/gc/shared/vmStructs_gc.hpp +++ b/src/hotspot/share/gc/shared/vmStructs_gc.hpp @@ -26,7 +26,6 @@ #define SHARE_GC_SHARED_VMSTRUCTS_GC_HPP #include "gc/shared/ageTable.hpp" -#include "gc/shared/cardGeneration.hpp" #include "gc/shared/cardTable.hpp" #include "gc/shared/cardTableRS.hpp" #include "gc/shared/collectedHeap.hpp" @@ -101,11 +100,11 @@ nonstatic_field(BlockOffsetArrayContigSpace, _next_offset_threshold, HeapWord*) \ nonstatic_field(BlockOffsetArrayContigSpace, _next_offset_index, size_t) \ \ - nonstatic_field(CardGeneration, _rs, CardTableRS*) \ - nonstatic_field(CardGeneration, _bts, BlockOffsetSharedArray*) \ - nonstatic_field(CardGeneration, _shrink_factor, size_t) \ - nonstatic_field(CardGeneration, _capacity_at_prologue, size_t) \ - nonstatic_field(CardGeneration, _used_at_prologue, size_t) \ + nonstatic_field(TenuredGeneration, _rs, CardTableRS*) \ + nonstatic_field(TenuredGeneration, _bts, BlockOffsetSharedArray*) \ + nonstatic_field(TenuredGeneration, _shrink_factor, size_t) \ + nonstatic_field(TenuredGeneration, _capacity_at_prologue, size_t) \ + nonstatic_field(TenuredGeneration, _used_at_prologue, size_t) \ \ nonstatic_field(CardTable, _whole_heap, const MemRegion) \ nonstatic_field(CardTable, _guard_index, const size_t) \ @@ -186,7 +185,6 @@ declare_toplevel_type(CollectedHeap) \ declare_type(GenCollectedHeap, CollectedHeap) \ declare_toplevel_type(Generation) \ - declare_type(CardGeneration, Generation) \ declare_toplevel_type(Space) \ declare_type(CompactibleSpace, Space) \ declare_type(ContiguousSpace, CompactibleSpace) \ @@ -261,10 +259,6 @@ declare_constant(BarrierSet::ModRef) \ declare_constant(BarrierSet::CardTableBarrierSet) \ \ - declare_constant(BOTConstants::LogN) \ - declare_constant(BOTConstants::LogN_words) \ - declare_constant(BOTConstants::N_bytes) \ - declare_constant(BOTConstants::N_words) \ declare_constant(BOTConstants::LogBase) \ declare_constant(BOTConstants::Base) \ declare_constant(BOTConstants::N_powers) \ @@ -274,9 +268,6 @@ declare_constant(CardTable::dirty_card) \ declare_constant(CardTable::Precise) \ declare_constant(CardTable::ObjHeadPreciseArray) \ - declare_constant(CardTable::card_shift) \ - declare_constant(CardTable::card_size) \ - declare_constant(CardTable::card_size_in_words) \ \ declare_constant(CollectedHeap::Serial) \ declare_constant(CollectedHeap::Parallel) \ diff --git a/src/hotspot/share/gc/shared/weakProcessor.hpp b/src/hotspot/share/gc/shared/weakProcessor.hpp index 5eb2c59f3f2da460e757eb2f15e5ac6d240ef25d..b86129c9b93500abe98fbd704605bef90c3160d4 100644 --- a/src/hotspot/share/gc/shared/weakProcessor.hpp +++ b/src/hotspot/share/gc/shared/weakProcessor.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -28,7 +28,7 @@ #include "gc/shared/oopStorageParState.hpp" #include "gc/shared/oopStorageSetParState.hpp" #include "gc/shared/workerThread.hpp" -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" class WeakProcessorTimes; class WorkerThreads; diff --git a/src/hotspot/share/gc/shared/workerDataArray.cpp b/src/hotspot/share/gc/shared/workerDataArray.cpp index b71406622109f3fa14153afae5fa818e80d3f44a..53f337560d35c28a3ddcdf404f2b0b165a6f1152 100644 --- a/src/hotspot/share/gc/shared/workerDataArray.cpp +++ b/src/hotspot/share/gc/shared/workerDataArray.cpp @@ -36,16 +36,6 @@ double WorkerDataArray::uninitialized() { return -1.0; } -template <> -void WorkerDataArray::WDAPrinter::summary(outputStream* out, double time) { - out->print_cr(" %.1lfms", time * MILLIUNITS); -} - -template <> -void WorkerDataArray::WDAPrinter::summary(outputStream* out, size_t value) { - out->print_cr(" " SIZE_FORMAT, value); -} - template <> void WorkerDataArray::WDAPrinter::summary(outputStream* out, double min, double avg, double max, double diff, double sum, bool print_sum) { out->print(" Min: %4.1lf, Avg: %4.1lf, Max: %4.1lf, Diff: %4.1lf", min * MILLIUNITS, avg * MILLIUNITS, max * MILLIUNITS, diff* MILLIUNITS); diff --git a/src/hotspot/share/gc/shared/workerDataArray.hpp b/src/hotspot/share/gc/shared/workerDataArray.hpp index 8908afbc8f9fa9d0b35506981b8d5edc28678676..b2a81bc948240aec422f23ee0165b0efd0ffe859 100644 --- a/src/hotspot/share/gc/shared/workerDataArray.hpp +++ b/src/hotspot/share/gc/shared/workerDataArray.hpp @@ -46,7 +46,7 @@ private: WorkerDataArray* _thread_work_items[MaxThreadWorkItems]; public: - WorkerDataArray(const char* short_name, const char* title, uint length, bool is_serial = false); + WorkerDataArray(const char* short_name, const char* title, uint length); ~WorkerDataArray(); // Create an integer sub-item at the given index to this WorkerDataArray. If length_override @@ -91,9 +91,7 @@ private: private: class WDAPrinter { public: - static void summary(outputStream* out, double time); static void summary(outputStream* out, double min, double avg, double max, double diff, double sum, bool print_sum); - static void summary(outputStream* out, size_t value); static void summary(outputStream* out, size_t min, double avg, size_t max, size_t diff, size_t sum, bool print_sum); static void details(const WorkerDataArray* phase, outputStream* out); diff --git a/src/hotspot/share/gc/shared/workerDataArray.inline.hpp b/src/hotspot/share/gc/shared/workerDataArray.inline.hpp index 3deb734f20d9549fe78bebc3003b9f91d2413f5e..283fb97af8d2f11b13e5ff67d2d01d37e9e02064 100644 --- a/src/hotspot/share/gc/shared/workerDataArray.inline.hpp +++ b/src/hotspot/share/gc/shared/workerDataArray.inline.hpp @@ -31,14 +31,12 @@ #include "utilities/ostream.hpp" template -WorkerDataArray::WorkerDataArray(const char* short_name, const char* title, uint length, bool is_serial) : +WorkerDataArray::WorkerDataArray(const char* short_name, const char* title, uint length) : _data(NULL), _length(length), _short_name(short_name), - _title(title), - _is_serial(is_serial) { + _title(title) { assert(length > 0, "Must have some workers to store data for"); - assert(!is_serial || length == 1, "Serial phase must only have a single entry."); _data = NEW_C_HEAP_ARRAY(T, _length, mtGC); for (uint i = 0; i < MaxThreadWorkItems; i++) { _thread_work_items[i] = NULL; @@ -158,39 +156,31 @@ void WorkerDataArray::set_all(T value) { template void WorkerDataArray::print_summary_on(outputStream* out, bool print_sum) const { - if (_is_serial) { - out->print("%s:", title()); - } else { - out->print("%-30s", title()); - } + out->print("%-30s", title()); uint start = 0; while (start < _length && get(start) == uninitialized()) { start++; } if (start < _length) { - if (_is_serial) { - WDAPrinter::summary(out, get(0)); - } else { - T min = get(start); - T max = min; - T sum = 0; - uint contributing_threads = 0; - for (uint i = start; i < _length; ++i) { - T value = get(i); - if (value != uninitialized()) { - max = MAX2(max, value); - min = MIN2(min, value); - sum += value; - contributing_threads++; - } + T min = get(start); + T max = min; + T sum = 0; + uint contributing_threads = 0; + for (uint i = start; i < _length; ++i) { + T value = get(i); + if (value != uninitialized()) { + max = MAX2(max, value); + min = MIN2(min, value); + sum += value; + contributing_threads++; } - T diff = max - min; - assert(contributing_threads != 0, "Must be since we found a used value for the start index"); - double avg = sum / (double) contributing_threads; - WDAPrinter::summary(out, min, avg, max, diff, sum, print_sum); - out->print_cr(", Workers: %d", contributing_threads); } + T diff = max - min; + assert(contributing_threads != 0, "Must be since we found a used value for the start index"); + double avg = sum / (double) contributing_threads; + WDAPrinter::summary(out, min, avg, max, diff, sum, print_sum); + out->print_cr(", Workers: %d", contributing_threads); } else { // No data for this phase. out->print_cr(" skipped"); diff --git a/src/hotspot/share/gc/shared/workerPolicy.hpp b/src/hotspot/share/gc/shared/workerPolicy.hpp index 377c9135d29c5af619ab67cc525cd13eeb40185c..769b0e0ed8b3103bf56ca65a5d74b532ef0b2f9b 100644 --- a/src/hotspot/share/gc/shared/workerPolicy.hpp +++ b/src/hotspot/share/gc/shared/workerPolicy.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -25,7 +25,7 @@ #ifndef SHARE_GC_SHARED_WORKERPOLICY_HPP #define SHARE_GC_SHARED_WORKERPOLICY_HPP -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" #include "utilities/globalDefinitions.hpp" class WorkerPolicy : public AllStatic { diff --git a/src/hotspot/share/gc/shared/workerThread.cpp b/src/hotspot/share/gc/shared/workerThread.cpp index 183349ef245ef5d61e37a7eef1e6abc36cc10333..9d141464a394be58a10231e93ea890ebaeef2ecb 100644 --- a/src/hotspot/share/gc/shared/workerThread.cpp +++ b/src/hotspot/share/gc/shared/workerThread.cpp @@ -59,8 +59,9 @@ void WorkerTaskDispatcher::worker_run_task() { // Wait for the coordinator to dispatch a task. _start_semaphore.wait(); - // Get worker id. + // Get and set worker id. const uint worker_id = Atomic::fetch_and_add(&_started, 1u); + WorkerThread::set_worker_id(worker_id); // Run task. GCIdMark gc_id_mark(_task->gc_id()); @@ -91,18 +92,20 @@ void WorkerThreads::initialize_workers() { } } -WorkerThread* WorkerThreads::create_worker(uint id) { +WorkerThread* WorkerThreads::create_worker(uint name_suffix) { if (is_init_completed() && InjectGCWorkerCreationFailure) { return NULL; } - WorkerThread* const worker = new WorkerThread(_name, id, &_dispatcher); + WorkerThread* const worker = new WorkerThread(_name, name_suffix, &_dispatcher); if (!os::create_thread(worker, os::gc_thread)) { delete worker; return NULL; } + on_create_worker(worker); + os::start_thread(worker); return worker; @@ -146,10 +149,11 @@ void WorkerThreads::run_task(WorkerTask* task, uint num_workers) { run_task(task); } -WorkerThread::WorkerThread(const char* name_prefix, uint id, WorkerTaskDispatcher* dispatcher) : - _dispatcher(dispatcher), - _id(id) { - set_name("%s#%d", name_prefix, id); +THREAD_LOCAL uint WorkerThread::_worker_id = UINT_MAX; + +WorkerThread::WorkerThread(const char* name_prefix, uint name_suffix, WorkerTaskDispatcher* dispatcher) : + _dispatcher(dispatcher) { + set_name("%s#%u", name_prefix, name_suffix); } void WorkerThread::run() { diff --git a/src/hotspot/share/gc/shared/workerThread.hpp b/src/hotspot/share/gc/shared/workerThread.hpp index d4c16c246f06b52d88ae1ed6d23caace3c248e81..bdb61f34ed9d90163441bae2ae73eecb09fb3111 100644 --- a/src/hotspot/share/gc/shared/workerThread.hpp +++ b/src/hotspot/share/gc/shared/workerThread.hpp @@ -91,8 +91,10 @@ private: uint _active_workers; WorkerTaskDispatcher _dispatcher; + WorkerThread* create_worker(uint name_suffix); + protected: - virtual WorkerThread* create_worker(uint id); + virtual void on_create_worker(WorkerThread* worker) {} public: WorkerThreads(const char* name, uint max_workers); @@ -117,23 +119,19 @@ public: }; class WorkerThread : public NamedThread { + friend class WorkerTaskDispatcher; + private: - WorkerTaskDispatcher* const _dispatcher; - const uint _id; + static THREAD_LOCAL uint _worker_id; -public: - static WorkerThread* current() { - return WorkerThread::cast(Thread::current()); - } + WorkerTaskDispatcher* const _dispatcher; - static WorkerThread* cast(Thread* t) { - assert(t->is_Worker_thread(), "incorrect cast to WorkerThread"); - return static_cast(t); - } + static void set_worker_id(uint worker_id) { _worker_id = worker_id; } - WorkerThread(const char* name_prefix, uint id, WorkerTaskDispatcher* dispatcher); +public: + static uint worker_id() { return _worker_id; } - uint id() const { return _id; } + WorkerThread(const char* name_prefix, uint which, WorkerTaskDispatcher* dispatcher); bool is_Worker_thread() const override { return true; } const char* type_name() const override { return "WorkerThread"; } diff --git a/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp b/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp index 8bd18c1aa662204c8cca4e69714cad43e826a8f0..a9974783c79c28ab514bd419578deb65447ed6a4 100644 --- a/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp +++ b/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp @@ -718,7 +718,7 @@ Node* ShenandoahBarrierSetC2::atomic_xchg_at_resolved(C2AtomicParseAccess& acces // Support for GC barriers emitted during parsing bool ShenandoahBarrierSetC2::is_gc_barrier_node(Node* node) const { - if (node->Opcode() == Op_ShenandoahLoadReferenceBarrier) return true; + if (node->Opcode() == Op_ShenandoahLoadReferenceBarrier || node->Opcode() == Op_ShenandoahIUBarrier) return true; if (node->Opcode() != Op_CallLeaf && node->Opcode() != Op_CallLeafNoFP) { return false; } diff --git a/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp b/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp index 5ba3828b2d3d7a81b1b874530e3592ba7cd920b2..667808f4efd802c054300269bb17364c68bcc6a5 100644 --- a/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp +++ b/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp @@ -1,5 +1,6 @@ /* * Copyright (c) 2015, 2021, Red Hat, Inc. All rights reserved. + * Copyright (C) 2022 THL A29 Limited, a Tencent company. All rights reserved. * 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 +55,6 @@ bool ShenandoahBarrierC2Support::expand(Compile* C, PhaseIterGVN& igvn) { PhaseIdealLoop::optimize(igvn, LoopOptsShenandoahExpand); if (C->failing()) return false; PhaseIdealLoop::verify(igvn); - DEBUG_ONLY(verify_raw_mem(C->root());) if (attempt_more_loopopts) { C->set_major_progress(); if (!C->optimize_loops(igvn, LoopOptsShenandoahPostExpand)) { @@ -567,7 +567,7 @@ void ShenandoahBarrierC2Support::verify(RootNode* root) { { { 2, ShenandoahLoad }, { 3, ShenandoahLoad } }, Op_EncodeISOArray, { { 2, ShenandoahLoad }, { 3, ShenandoahStore } }, - Op_HasNegatives, + Op_CountPositives, { { 2, ShenandoahLoad }, { -1, ShenandoahNone} }, Op_CastP2X, { { 1, ShenandoahLoad }, { -1, ShenandoahNone} }, @@ -707,7 +707,7 @@ Node* ShenandoahBarrierC2Support::no_branches(Node* c, Node* dom, bool allow_one Node* iffproj = NULL; while (c != dom) { Node* next = phase->idom(c); - assert(next->unique_ctrl_out() == c || c->is_Proj() || c->is_Region(), "multiple control flow out but no proj or region?"); + assert(next->unique_ctrl_out_or_null() == c || c->is_Proj() || c->is_Region(), "multiple control flow out but no proj or region?"); if (c->is_Region()) { ResourceMark rm; Unique_Node_List wq; @@ -964,18 +964,11 @@ void ShenandoahBarrierC2Support::test_in_cset(Node*& ctrl, Node*& not_cset_ctrl, phase->register_new_node(cset_bool, old_ctrl); } -void ShenandoahBarrierC2Support::call_lrb_stub(Node*& ctrl, Node*& val, Node* load_addr, Node*& result_mem, Node* raw_mem, +void ShenandoahBarrierC2Support::call_lrb_stub(Node*& ctrl, Node*& val, Node* load_addr, DecoratorSet decorators, PhaseIdealLoop* phase) { IdealLoopTree*loop = phase->get_loop(ctrl); const TypePtr* obj_type = phase->igvn().type(val)->is_oopptr(); - // The slow path stub consumes and produces raw memory in addition - // to the existing memory edges - Node* base = find_bottom_mem(ctrl, phase); - MergeMemNode* mm = MergeMemNode::make(base); - mm->set_memory_at(Compile::AliasIdxRaw, raw_mem); - phase->register_new_node(mm, ctrl); - address calladdr = NULL; const char* name = NULL; bool is_strong = ShenandoahBarrierSet::is_strong_access(decorators); @@ -1013,7 +1006,7 @@ void ShenandoahBarrierC2Support::call_lrb_stub(Node*& ctrl, Node*& val, Node* lo call->init_req(TypeFunc::Control, ctrl); call->init_req(TypeFunc::I_O, phase->C->top()); - call->init_req(TypeFunc::Memory, mm); + call->init_req(TypeFunc::Memory, phase->C->top()); call->init_req(TypeFunc::FramePtr, phase->C->top()); call->init_req(TypeFunc::ReturnAdr, phase->C->top()); call->init_req(TypeFunc::Parms, val); @@ -1021,8 +1014,6 @@ void ShenandoahBarrierC2Support::call_lrb_stub(Node*& ctrl, Node*& val, Node* lo phase->register_control(call, loop, ctrl); ctrl = new ProjNode(call, TypeFunc::Control); phase->register_control(ctrl, loop, call); - result_mem = new ProjNode(call, TypeFunc::Memory); - phase->register_new_node(result_mem, call); val = new ProjNode(call, TypeFunc::Parms); phase->register_new_node(val, call); val = new CheckCastPPNode(ctrl, val, obj_type); @@ -1341,12 +1332,9 @@ void ShenandoahBarrierC2Support::pin_and_expand(PhaseIdealLoop* phase) { Node* ctrl = phase->get_ctrl(lrb); Node* val = lrb->in(ShenandoahLoadReferenceBarrierNode::ValueIn); - Node* orig_ctrl = ctrl; Node* raw_mem = fixer.find_mem(ctrl, lrb); - Node* init_raw_mem = raw_mem; - Node* raw_mem_for_ctrl = fixer.find_mem(ctrl, NULL); IdealLoopTree *loop = phase->get_loop(ctrl); @@ -1359,7 +1347,6 @@ void ShenandoahBarrierC2Support::pin_and_expand(PhaseIdealLoop* phase) { enum { _heap_stable = 1, _evac_path, _not_cset, PATH_LIMIT }; Node* region = new RegionNode(PATH_LIMIT); Node* val_phi = new PhiNode(region, val->bottom_type()->is_oopptr()); - Node* raw_mem_phi = PhiNode::make(region, raw_mem, Type::MEMORY, TypeRawPtr::BOTTOM); // Stable path. int flags = ShenandoahHeap::HAS_FORWARDED; @@ -1372,7 +1359,6 @@ void ShenandoahBarrierC2Support::pin_and_expand(PhaseIdealLoop* phase) { // Heap stable case region->init_req(_heap_stable, heap_stable_ctrl); val_phi->init_req(_heap_stable, val); - raw_mem_phi->init_req(_heap_stable, raw_mem); // Test for in-cset, unless it's a native-LRB. Native LRBs need to return NULL // even for non-cset objects to prevent ressurrection of such objects. @@ -1384,11 +1370,9 @@ void ShenandoahBarrierC2Support::pin_and_expand(PhaseIdealLoop* phase) { if (not_cset_ctrl != NULL) { region->init_req(_not_cset, not_cset_ctrl); val_phi->init_req(_not_cset, val); - raw_mem_phi->init_req(_not_cset, raw_mem); } else { region->del_req(_not_cset); val_phi->del_req(_not_cset); - raw_mem_phi->del_req(_not_cset); } // Resolve object when orig-value is in cset. @@ -1429,15 +1413,13 @@ void ShenandoahBarrierC2Support::pin_and_expand(PhaseIdealLoop* phase) { } } } - call_lrb_stub(ctrl, val, addr, result_mem, raw_mem, lrb->decorators(), phase); + call_lrb_stub(ctrl, val, addr, lrb->decorators(), phase); region->init_req(_evac_path, ctrl); val_phi->init_req(_evac_path, val); - raw_mem_phi->init_req(_evac_path, result_mem); phase->register_control(region, loop, heap_stable_iff); Node* out_val = val_phi; phase->register_new_node(val_phi, region); - phase->register_new_node(raw_mem_phi, region); fix_ctrl(lrb, region, fixer, uses, uses_to_ignore, last, phase); @@ -1450,18 +1432,10 @@ void ShenandoahBarrierC2Support::pin_and_expand(PhaseIdealLoop* phase) { for(uint next = 0; next < uses.size(); next++ ) { Node *n = uses.at(next); assert(phase->get_ctrl(n) == ctrl, "bad control"); - assert(n != init_raw_mem, "should leave input raw mem above the barrier"); + assert(n != raw_mem, "should leave input raw mem above the barrier"); phase->set_ctrl(n, region); follow_barrier_uses(n, ctrl, uses, phase); } - - // The slow path call produces memory: hook the raw memory phi - // from the expanded load reference barrier with the rest of the graph - // which may require adding memory phis at every post dominated - // region and at enclosing loop heads. Use the memory state - // collected in memory_nodes to fix the memory graph. Update that - // memory state as we go. - fixer.fix_mem(ctrl, region, init_raw_mem, raw_mem_for_ctrl, raw_mem_phi, uses); } // Done expanding load-reference-barriers. assert(ShenandoahBarrierSetC2::bsc2()->state()->load_reference_barriers_count() == 0, "all load reference barrier nodes should have been replaced"); @@ -1902,105 +1876,6 @@ void ShenandoahBarrierC2Support::optimize_after_expansion(VectorSet &visited, No } } -#ifdef ASSERT -void ShenandoahBarrierC2Support::verify_raw_mem(RootNode* root) { - const bool trace = false; - ResourceMark rm; - Unique_Node_List nodes; - Unique_Node_List controls; - Unique_Node_List memories; - - nodes.push(root); - for (uint next = 0; next < nodes.size(); next++) { - Node *n = nodes.at(next); - if (ShenandoahBarrierSetC2::is_shenandoah_lrb_call(n)) { - controls.push(n); - if (trace) { tty->print("XXXXXX verifying"); n->dump(); } - for (uint next2 = 0; next2 < controls.size(); next2++) { - Node *m = controls.at(next2); - for (DUIterator_Fast imax, i = m->fast_outs(imax); i < imax; i++) { - Node* u = m->fast_out(i); - if (u->is_CFG() && !u->is_Root() && - !(u->Opcode() == Op_CProj && u->in(0)->Opcode() == Op_NeverBranch && u->as_Proj()->_con == 1) && - !(u->is_Region() && u->unique_ctrl_out()->Opcode() == Op_Halt)) { - if (trace) { tty->print("XXXXXX pushing control"); u->dump(); } - controls.push(u); - } - } - } - memories.push(n->as_Call()->proj_out(TypeFunc::Memory)); - for (uint next2 = 0; next2 < memories.size(); next2++) { - Node *m = memories.at(next2); - assert(m->bottom_type() == Type::MEMORY, ""); - for (DUIterator_Fast imax, i = m->fast_outs(imax); i < imax; i++) { - Node* u = m->fast_out(i); - if (u->bottom_type() == Type::MEMORY && (u->is_Mem() || u->is_ClearArray())) { - if (trace) { tty->print("XXXXXX pushing memory"); u->dump(); } - memories.push(u); - } else if (u->is_LoadStore()) { - if (trace) { tty->print("XXXXXX pushing memory"); u->find_out_with(Op_SCMemProj)->dump(); } - memories.push(u->find_out_with(Op_SCMemProj)); - } else if (u->is_MergeMem() && u->as_MergeMem()->memory_at(Compile::AliasIdxRaw) == m) { - if (trace) { tty->print("XXXXXX pushing memory"); u->dump(); } - memories.push(u); - } else if (u->is_Phi()) { - assert(u->bottom_type() == Type::MEMORY, ""); - if (u->adr_type() == TypeRawPtr::BOTTOM || u->adr_type() == TypePtr::BOTTOM) { - assert(controls.member(u->in(0)), ""); - if (trace) { tty->print("XXXXXX pushing memory"); u->dump(); } - memories.push(u); - } - } else if (u->is_SafePoint() || u->is_MemBar()) { - for (DUIterator_Fast jmax, j = u->fast_outs(jmax); j < jmax; j++) { - Node* uu = u->fast_out(j); - if (uu->bottom_type() == Type::MEMORY) { - if (trace) { tty->print("XXXXXX pushing memory"); uu->dump(); } - memories.push(uu); - } - } - } - } - } - for (uint next2 = 0; next2 < controls.size(); next2++) { - Node *m = controls.at(next2); - if (m->is_Region()) { - bool all_in = true; - for (uint i = 1; i < m->req(); i++) { - if (!controls.member(m->in(i))) { - all_in = false; - break; - } - } - if (trace) { tty->print("XXX verifying %s", all_in ? "all in" : ""); m->dump(); } - bool found_phi = false; - for (DUIterator_Fast jmax, j = m->fast_outs(jmax); j < jmax && !found_phi; j++) { - Node* u = m->fast_out(j); - if (u->is_Phi() && memories.member(u)) { - found_phi = true; - for (uint i = 1; i < u->req() && found_phi; i++) { - Node* k = u->in(i); - if (memories.member(k) != controls.member(m->in(i))) { - found_phi = false; - } - } - } - } - assert(found_phi || all_in, ""); - } - } - controls.clear(); - memories.clear(); - } - for( uint i = 0; i < n->len(); ++i ) { - Node *m = n->in(i); - if (m != NULL) { - nodes.push(m); - } - } - } -} -#endif - ShenandoahIUBarrierNode::ShenandoahIUBarrierNode(Node* val) : Node(NULL, val) { ShenandoahBarrierSetC2::bsc2()->state()->add_iu_barrier(this); } diff --git a/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.hpp b/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.hpp index 6632e42b36f073a561620e9a4d4c87b7956f742d..86a74011f5a56ed2e398bc28e4feec710266e67d 100644 --- a/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.hpp +++ b/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.hpp @@ -50,7 +50,6 @@ private: static bool verify_helper(Node* in, Node_Stack& phis, VectorSet& visited, verify_type t, bool trace, Unique_Node_List& barriers_used); static void report_verify_failure(const char* msg, Node* n1 = NULL, Node* n2 = NULL); - static void verify_raw_mem(RootNode* root); #endif static Node* dom_mem(Node* mem, Node* ctrl, int alias, Node*& mem_ctrl, PhaseIdealLoop* phase); static Node* no_branches(Node* c, Node* dom, bool allow_one_proj, PhaseIdealLoop* phase); @@ -61,7 +60,7 @@ private: static void test_null(Node*& ctrl, Node* val, Node*& null_ctrl, PhaseIdealLoop* phase); static void test_gc_state(Node*& ctrl, Node* raw_mem, Node*& heap_stable_ctrl, PhaseIdealLoop* phase, int flags); - static void call_lrb_stub(Node*& ctrl, Node*& val, Node* load_addr, Node*& result_mem, Node* raw_mem, + static void call_lrb_stub(Node*& ctrl, Node*& val, Node* load_addr, DecoratorSet decorators, PhaseIdealLoop* phase); static void test_in_cset(Node*& ctrl, Node*& not_cset_ctrl, Node* val, Node* raw_mem, PhaseIdealLoop* phase); static void move_gc_state_test_out_of_loop(IfNode* iff, PhaseIdealLoop* phase); diff --git a/src/hotspot/share/gc/shenandoah/mode/shenandoahIUMode.cpp b/src/hotspot/share/gc/shenandoah/mode/shenandoahIUMode.cpp index ef16bfa9376eae26f3c085bd2ed2f80984392e5e..0c42824616997c578d80662fe82067aca95aa1e7 100644 --- a/src/hotspot/share/gc/shenandoah/mode/shenandoahIUMode.cpp +++ b/src/hotspot/share/gc/shenandoah/mode/shenandoahIUMode.cpp @@ -65,19 +65,18 @@ void ShenandoahIUMode::initialize_flags() const { } ShenandoahHeuristics* ShenandoahIUMode::initialize_heuristics() const { - if (ShenandoahGCHeuristics != NULL) { - if (strcmp(ShenandoahGCHeuristics, "aggressive") == 0) { - return new ShenandoahAggressiveHeuristics(); - } else if (strcmp(ShenandoahGCHeuristics, "static") == 0) { - return new ShenandoahStaticHeuristics(); - } else if (strcmp(ShenandoahGCHeuristics, "adaptive") == 0) { - return new ShenandoahAdaptiveHeuristics(); - } else if (strcmp(ShenandoahGCHeuristics, "compact") == 0) { - return new ShenandoahCompactHeuristics(); - } else { - vm_exit_during_initialization("Unknown -XX:ShenandoahGCHeuristics option"); - } + if (ShenandoahGCHeuristics == NULL) { + vm_exit_during_initialization("Unknown -XX:ShenandoahGCHeuristics option (null)"); } - ShouldNotReachHere(); + if (strcmp(ShenandoahGCHeuristics, "aggressive") == 0) { + return new ShenandoahAggressiveHeuristics(); + } else if (strcmp(ShenandoahGCHeuristics, "static") == 0) { + return new ShenandoahStaticHeuristics(); + } else if (strcmp(ShenandoahGCHeuristics, "adaptive") == 0) { + return new ShenandoahAdaptiveHeuristics(); + } else if (strcmp(ShenandoahGCHeuristics, "compact") == 0) { + return new ShenandoahCompactHeuristics(); + } + vm_exit_during_initialization("Unknown -XX:ShenandoahGCHeuristics option"); return NULL; } diff --git a/src/hotspot/share/gc/shenandoah/mode/shenandoahPassiveMode.cpp b/src/hotspot/share/gc/shenandoah/mode/shenandoahPassiveMode.cpp index a864200954464e16a2346f58a1c82b86129e52b8..caa22bbe068f54a000b725a7960dc607fc4df9d5 100644 --- a/src/hotspot/share/gc/shenandoah/mode/shenandoahPassiveMode.cpp +++ b/src/hotspot/share/gc/shenandoah/mode/shenandoahPassiveMode.cpp @@ -28,6 +28,7 @@ #include "logging/log.hpp" #include "logging/logTag.hpp" #include "runtime/globals_extension.hpp" +#include "runtime/java.hpp" void ShenandoahPassiveMode::initialize_flags() const { // Do not allow concurrent cycles. @@ -55,9 +56,8 @@ void ShenandoahPassiveMode::initialize_flags() const { // No barriers are required to run. } ShenandoahHeuristics* ShenandoahPassiveMode::initialize_heuristics() const { - if (ShenandoahGCHeuristics != NULL) { - return new ShenandoahPassiveHeuristics(); + if (ShenandoahGCHeuristics == NULL) { + vm_exit_during_initialization("Unknown -XX:ShenandoahGCHeuristics option (null)"); } - ShouldNotReachHere(); - return NULL; + return new ShenandoahPassiveHeuristics(); } diff --git a/src/hotspot/share/gc/shenandoah/mode/shenandoahSATBMode.cpp b/src/hotspot/share/gc/shenandoah/mode/shenandoahSATBMode.cpp index 7d9ecabc14e3001f67b6a2d29b3c429cb54817a1..06ed25e59c62b0ee7d9cc218d04252de5a7dc825 100644 --- a/src/hotspot/share/gc/shenandoah/mode/shenandoahSATBMode.cpp +++ b/src/hotspot/share/gc/shenandoah/mode/shenandoahSATBMode.cpp @@ -53,19 +53,18 @@ void ShenandoahSATBMode::initialize_flags() const { } ShenandoahHeuristics* ShenandoahSATBMode::initialize_heuristics() const { - if (ShenandoahGCHeuristics != NULL) { - if (strcmp(ShenandoahGCHeuristics, "aggressive") == 0) { - return new ShenandoahAggressiveHeuristics(); - } else if (strcmp(ShenandoahGCHeuristics, "static") == 0) { - return new ShenandoahStaticHeuristics(); - } else if (strcmp(ShenandoahGCHeuristics, "adaptive") == 0) { - return new ShenandoahAdaptiveHeuristics(); - } else if (strcmp(ShenandoahGCHeuristics, "compact") == 0) { - return new ShenandoahCompactHeuristics(); - } else { - vm_exit_during_initialization("Unknown -XX:ShenandoahGCHeuristics option"); - } + if (ShenandoahGCHeuristics == NULL) { + vm_exit_during_initialization("Unknown -XX:ShenandoahGCHeuristics option (null)"); } - ShouldNotReachHere(); + if (strcmp(ShenandoahGCHeuristics, "aggressive") == 0) { + return new ShenandoahAggressiveHeuristics(); + } else if (strcmp(ShenandoahGCHeuristics, "static") == 0) { + return new ShenandoahStaticHeuristics(); + } else if (strcmp(ShenandoahGCHeuristics, "adaptive") == 0) { + return new ShenandoahAdaptiveHeuristics(); + } else if (strcmp(ShenandoahGCHeuristics, "compact") == 0) { + return new ShenandoahCompactHeuristics(); + } + vm_exit_during_initialization("Unknown -XX:ShenandoahGCHeuristics option"); return NULL; } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahArguments.cpp b/src/hotspot/share/gc/shenandoah/shenandoahArguments.cpp index 624f004e3ccd35ec771f9237e9cb9dee57abe033..c7e0c9b0cd9d707baf76c4ef55cfbc0d7edb3450 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahArguments.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahArguments.cpp @@ -35,7 +35,7 @@ #include "utilities/defaultStream.hpp" void ShenandoahArguments::initialize() { -#if !(defined AARCH64 || defined AMD64 || defined IA32) +#if !(defined AARCH64 || defined AMD64 || defined IA32 || defined PPC64) vm_exit_during_initialization("Shenandoah GC is not supported on this platform."); #endif diff --git a/src/hotspot/share/gc/shenandoah/shenandoahBreakpoint.hpp b/src/hotspot/share/gc/shenandoah/shenandoahBreakpoint.hpp index f8b7489a3bbd0e7aedc4d5b1fe599f531629aedc..acc497618c9c5289b68845417464318913705a3a 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahBreakpoint.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahBreakpoint.hpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2021, Red Hat, Inc. All rights reserved. - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2022, Red Hat, Inc. All rights reserved. + * 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 @@ -26,7 +26,7 @@ #ifndef SHARE_GC_SHENANDOAH_SHENANDOAHBREAKPOINT_HPP #define SHARE_GC_SHENANDOAH_SHENANDOAHBREAKPOINT_HPP -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" class ShenandoahBreakpoint : public AllStatic { private: diff --git a/src/hotspot/share/gc/shenandoah/shenandoahClosures.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahClosures.inline.hpp index 4e56b3e5d4f3528cd828b2e0d354169bf4999e03..d03c029a0da44f5f92c1fc1952e71eb326f41868 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahClosures.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahClosures.inline.hpp @@ -227,7 +227,7 @@ ShenandoahCodeBlobAndDisarmClosure::ShenandoahCodeBlobAndDisarmClosure(OopClosur void ShenandoahCodeBlobAndDisarmClosure::do_code_blob(CodeBlob* cb) { nmethod* const nm = cb->as_nmethod_or_null(); - if (nm != NULL && nm->oops_do_try_claim()) { + if (nm != NULL) { assert(!ShenandoahNMethod::gc_data(nm)->is_unregistered(), "Should not be here"); CodeBlobToOopClosure::do_code_blob(cb); _bs->disarm(nm); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.hpp b/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.hpp index 17bc5b78934425b0a9582578a5c9c9f6a1ef249e..377d768833337e2d2bdeae1cf6e9e48239b26dc0 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Red Hat, Inc. All rights reserved. + * Copyright (c) 2017, 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 @@ -29,7 +29,7 @@ #include "gc/shenandoah/shenandoahSharedVariables.hpp" #include "gc/shenandoah/shenandoahLock.hpp" #include "gc/shenandoah/shenandoahPadding.hpp" -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" #include "memory/iterator.hpp" #include "utilities/globalDefinitions.hpp" diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp index 7cd9a61b29f43bc226ee351aa9fabd98a47b3191..f72d31e1f6985453a2abcd2e74571b475727a903 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp @@ -416,7 +416,7 @@ void ShenandoahHeap::initialize_mode() { vm_exit_during_initialization("Unknown -XX:ShenandoahGCMode option"); } } else { - ShouldNotReachHere(); + vm_exit_during_initialization("Unknown -XX:ShenandoahGCMode option (null)"); } _gc_mode->initialize_flags(); if (_gc_mode->is_diagnostic() && !UnlockDiagnosticVMOptions) { @@ -1366,7 +1366,7 @@ public: // parallel marking queues. // Every worker processes it's own marking queue. work-stealing is used // to balance workload. -class ShenandoahParallelObjectIterator : public ParallelObjectIterator { +class ShenandoahParallelObjectIterator : public ParallelObjectIteratorImpl { private: uint _num_workers; bool _init_ready; @@ -1465,7 +1465,7 @@ private: } }; -ParallelObjectIterator* ShenandoahHeap::parallel_object_iterator(uint workers) { +ParallelObjectIteratorImpl* ShenandoahHeap::parallel_object_iterator(uint workers) { return new ShenandoahParallelObjectIterator(workers, &_aux_bit_map); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp index 79afeb37ab59ffacbcf9bf25276e71840794779e..1ec9d7051cfcf3f2bd94c7c82f029d7886851da3 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp @@ -484,7 +484,7 @@ public: // Used for native heap walkers: heap dumpers, mostly void object_iterate(ObjectClosure* cl); // Parallel heap iteration support - virtual ParallelObjectIterator* parallel_object_iterator(uint workers); + virtual ParallelObjectIteratorImpl* parallel_object_iterator(uint workers); // Keep alive an object that was loaded with AS_NO_KEEPALIVE. void keep_alive(oop obj); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahReferenceProcessor.cpp b/src/hotspot/share/gc/shenandoah/shenandoahReferenceProcessor.cpp index 72a87a9d3dee264403b17e373c9dfd08fbb32add..b828582336c47d021d649dfd94b7b7bd564365f4 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahReferenceProcessor.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahReferenceProcessor.cpp @@ -25,6 +25,7 @@ #include "precompiled.hpp" #include "classfile/javaClasses.hpp" +#include "gc/shared/workerThread.hpp" #include "gc/shenandoah/shenandoahOopClosures.inline.hpp" #include "gc/shenandoah/shenandoahReferenceProcessor.hpp" #include "gc/shenandoah/shenandoahThreadLocalData.hpp" @@ -337,7 +338,6 @@ bool ShenandoahReferenceProcessor::discover(oop reference, ReferenceType type, u } // Add reference to discovered list - assert(worker_id != ShenandoahThreadLocalData::INVALID_WORKER_ID, "need valid worker ID"); ShenandoahRefProcThreadLocal& refproc_data = _ref_proc_thread_locals[worker_id]; oop discovered_head = refproc_data.discovered_list_head(); if (discovered_head == NULL) { @@ -361,7 +361,7 @@ bool ShenandoahReferenceProcessor::discover_reference(oop reference, ReferenceTy } log_trace(gc, ref)("Encountered Reference: " PTR_FORMAT " (%s)", p2i(reference), reference_type_name(type)); - uint worker_id = ShenandoahThreadLocalData::worker_id(Thread::current()); + uint worker_id = WorkerThread::worker_id(); _ref_proc_thread_locals->inc_encountered(type); if (UseCompressedOops) { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.cpp b/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.cpp index a87918ce8a1947c0bed8a4d97fbc3a2d1bd07426..21a21053c8973ba7fbc984fe61e38273085fba4b 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.cpp @@ -79,7 +79,6 @@ ShenandoahThreadRoots::~ShenandoahThreadRoots() { } ShenandoahCodeCacheRoots::ShenandoahCodeCacheRoots(ShenandoahPhaseTimings::Phase phase) : _phase(phase) { - nmethod::oops_do_marking_prologue(); } void ShenandoahCodeCacheRoots::code_blobs_do(CodeBlobClosure* blob_cl, uint worker_id) { @@ -87,39 +86,12 @@ void ShenandoahCodeCacheRoots::code_blobs_do(CodeBlobClosure* blob_cl, uint work _coderoots_iterator.possibly_parallel_blobs_do(blob_cl); } -ShenandoahCodeCacheRoots::~ShenandoahCodeCacheRoots() { - nmethod::oops_do_marking_epilogue(); -} - ShenandoahRootProcessor::ShenandoahRootProcessor(ShenandoahPhaseTimings::Phase phase) : _heap(ShenandoahHeap::heap()), _phase(phase), _worker_phase(phase) { } -ShenandoahRootScanner::ShenandoahRootScanner(uint n_workers, ShenandoahPhaseTimings::Phase phase) : - ShenandoahRootProcessor(phase), - _thread_roots(phase, n_workers > 1) { - nmethod::oops_do_marking_prologue(); -} - -ShenandoahRootScanner::~ShenandoahRootScanner() { - nmethod::oops_do_marking_epilogue(); -} - -void ShenandoahRootScanner::roots_do(uint worker_id, OopClosure* oops) { - MarkingCodeBlobClosure blobs_cl(oops, !CodeBlobToOopClosure::FixRelocations); - roots_do(worker_id, oops, &blobs_cl); -} - -void ShenandoahRootScanner::roots_do(uint worker_id, OopClosure* oops, CodeBlobClosure* code, ThreadClosure *tc) { - assert(ShenandoahSafepoint::is_at_shenandoah_safepoint(), "Must be at a safepoint"); - - ShenandoahParallelOopsDoThreadClosure tc_cl(oops, code, tc); - ResourceMark rm; - _thread_roots.threads_do(&tc_cl, worker_id); -} - ShenandoahSTWRootScanner::ShenandoahSTWRootScanner(ShenandoahPhaseTimings::Phase phase) : ShenandoahRootProcessor(phase), _thread_roots(phase, ShenandoahHeap::heap()->workers()->active_workers() > 1), @@ -237,7 +209,6 @@ void ShenandoahRootAdjuster::roots_do(uint worker_id, OopClosure* oops) { static_cast(&blobs_and_disarm_Cl) : static_cast(&code_blob_cl); CLDToOopClosure adjust_cld_closure(oops, ClassLoaderData::_claim_strong); - AlwaysTrueClosure always_true; // Process light-weight/limited parallel roots then _vm_roots.oops_do(oops, worker_id); @@ -250,29 +221,52 @@ void ShenandoahRootAdjuster::roots_do(uint worker_id, OopClosure* oops) { } ShenandoahHeapIterationRootScanner::ShenandoahHeapIterationRootScanner(uint n_workers) : - ShenandoahRootProcessor(ShenandoahPhaseTimings::heap_iteration_roots), - _thread_roots(ShenandoahPhaseTimings::heap_iteration_roots, false /*is par*/), - _vm_roots(ShenandoahPhaseTimings::heap_iteration_roots), - _cld_roots(ShenandoahPhaseTimings::heap_iteration_roots, n_workers, true /*heap iteration*/), - _weak_roots(ShenandoahPhaseTimings::heap_iteration_roots), - _code_roots(ShenandoahPhaseTimings::heap_iteration_roots) { - } - - void ShenandoahHeapIterationRootScanner::roots_do(OopClosure* oops) { - // Must use _claim_other to avoid interfering with concurrent CLDG iteration - CLDToOopClosure clds(oops, ClassLoaderData::_claim_other); - MarkingCodeBlobClosure code(oops, !CodeBlobToOopClosure::FixRelocations); - ShenandoahParallelOopsDoThreadClosure tc_cl(oops, &code, NULL); - AlwaysTrueClosure always_true; - - ResourceMark rm; - - // Process light-weight/limited parallel roots then - _vm_roots.oops_do(oops, 0); - _weak_roots.oops_do(oops, 0); - _cld_roots.cld_do(&clds, 0); - - // Process heavy-weight/fully parallel roots the last - _code_roots.code_blobs_do(&code, 0); - _thread_roots.threads_do(&tc_cl, 0); - } + ShenandoahRootProcessor(ShenandoahPhaseTimings::heap_iteration_roots), + _thread_roots(ShenandoahPhaseTimings::heap_iteration_roots, false /*is par*/), + _vm_roots(ShenandoahPhaseTimings::heap_iteration_roots), + _cld_roots(ShenandoahPhaseTimings::heap_iteration_roots, n_workers, true /*heap iteration*/), + _weak_roots(ShenandoahPhaseTimings::heap_iteration_roots), + _code_roots(ShenandoahPhaseTimings::heap_iteration_roots) { +} + +class ShenandoahMarkCodeBlobClosure : public CodeBlobClosure { +private: + OopClosure* const _oops; + BarrierSetNMethod* const _bs_nm; + +public: + ShenandoahMarkCodeBlobClosure(OopClosure* oops) : + _oops(oops), + _bs_nm(BarrierSet::barrier_set()->barrier_set_nmethod()) {} + + virtual void do_code_blob(CodeBlob* cb) { + nmethod* const nm = cb->as_nmethod_or_null(); + if (nm != nullptr) { + if (_bs_nm != nullptr) { + // Make sure it only sees to-space objects + _bs_nm->nmethod_entry_barrier(nm); + } + ShenandoahNMethod* const snm = ShenandoahNMethod::gc_data(nm); + assert(snm != nullptr, "Sanity"); + snm->oops_do(_oops, false /*fix_relocations*/); + } + } +}; + +void ShenandoahHeapIterationRootScanner::roots_do(OopClosure* oops) { + // Must use _claim_other to avoid interfering with concurrent CLDG iteration + CLDToOopClosure clds(oops, ClassLoaderData::_claim_other); + ShenandoahMarkCodeBlobClosure code(oops); + ShenandoahParallelOopsDoThreadClosure tc_cl(oops, &code, NULL); + + ResourceMark rm; + + // Process light-weight/limited parallel roots then + _vm_roots.oops_do(oops, 0); + _weak_roots.oops_do(oops, 0); + _cld_roots.cld_do(&clds, 0); + + // Process heavy-weight/fully parallel roots the last + _code_roots.code_blobs_do(&code, 0); + _thread_roots.threads_do(&tc_cl, 0); +} diff --git a/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.hpp b/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.hpp index 1ecee9906a547f2cb66c79d811cded242cc4bf9c..75a23aea04534d53d728eb31f6260e43861898fc 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.hpp @@ -102,7 +102,6 @@ private: ShenandoahCodeRootsIterator _coderoots_iterator; public: ShenandoahCodeCacheRoots(ShenandoahPhaseTimings::Phase phase); - ~ShenandoahCodeCacheRoots(); void code_blobs_do(CodeBlobClosure* blob_cl, uint worker_id); }; @@ -143,20 +142,6 @@ public: ShenandoahHeap* heap() const { return _heap; } }; -class ShenandoahRootScanner : public ShenandoahRootProcessor { -private: - ShenandoahThreadRoots _thread_roots; - -public: - ShenandoahRootScanner(uint n_workers, ShenandoahPhaseTimings::Phase phase); - ~ShenandoahRootScanner(); - - void roots_do(uint worker_id, OopClosure* cl); - -private: - void roots_do(uint worker_id, OopClosure* oops, CodeBlobClosure* code, ThreadClosure* tc = NULL); -}; - // STW root scanner class ShenandoahSTWRootScanner : public ShenandoahRootProcessor { private: diff --git a/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.inline.hpp index e499c3543ff0623e7a030f75270e04b36b4ed1fc..5677f3daa60918982b729974110246b35c0a4326 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.inline.hpp @@ -82,7 +82,7 @@ ShenandoahClassLoaderDataRoots::ShenandoahClassLoaderDataRoots(Shena if (heap_iteration) { ClassLoaderDataGraph::clear_claimed_marks(ClassLoaderData::_claim_other); } else { - ClassLoaderDataGraph::clear_claimed_marks(); + ClassLoaderDataGraph::clear_claimed_marks(ClassLoaderData::_claim_strong); } if (CONCURRENT) { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahRuntime.hpp b/src/hotspot/share/gc/shenandoah/shenandoahRuntime.hpp index 788fe3fbeca7ee36ed7cf0dbb1729c25236e0e94..e187e4360b16b7d713149a7ee2fcc5d34753e2c1 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahRuntime.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahRuntime.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2019, Red Hat, Inc. All rights reserved. + * Copyright (c) 2018, 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 @@ -25,7 +25,7 @@ #ifndef SHARE_GC_SHENANDOAH_SHENANDOAHRUNTIME_HPP #define SHARE_GC_SHENANDOAH_SHENANDOAHRUNTIME_HPP -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" #include "oops/oopsHierarchy.hpp" class JavaThread; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahThreadLocalData.hpp b/src/hotspot/share/gc/shenandoah/shenandoahThreadLocalData.hpp index e34073f9b8ee76055d91e9810ee7382b641f0307..8d50bb35ee1d220fccd16b5972298902a218d1be 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahThreadLocalData.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahThreadLocalData.hpp @@ -36,9 +36,6 @@ #include "utilities/sizes.hpp" class ShenandoahThreadLocalData { -public: - static const uint INVALID_WORKER_ID = uint(-1); - private: char _gc_state; // Evacuation OOM state @@ -47,7 +44,6 @@ private: SATBMarkQueue _satb_mark_queue; PLAB* _gclab; size_t _gclab_size; - uint _worker_id; int _disarmed_value; double _paced_time; @@ -58,7 +54,6 @@ private: _satb_mark_queue(&ShenandoahBarrierSet::satb_mark_queue_set()), _gclab(NULL), _gclab_size(0), - _worker_id(INVALID_WORKER_ID), _disarmed_value(0), _paced_time(0) { @@ -103,16 +98,6 @@ public: return data(thread)->_gc_state; } - static void set_worker_id(Thread* thread, uint id) { - assert(thread->is_Worker_thread(), "Must be a worker thread"); - data(thread)->_worker_id = id; - } - - static uint worker_id(Thread* thread) { - assert(thread->is_Worker_thread(), "Must be a worker thread"); - return data(thread)->_worker_id; - } - static void initialize_gclab(Thread* thread) { assert (thread->is_Java_thread() || thread->is_Worker_thread(), "Only Java and GC worker threads are allowed to get GCLABs"); assert(data(thread)->_gclab == NULL, "Only initialize once"); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahUtils.cpp b/src/hotspot/share/gc/shenandoah/shenandoahUtils.cpp index 4881aff0bf1e46df7877ea21163a8ef222b6a7c1..89db25a80aa2a10d6ebf09e4b6a0df52081bae0a 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahUtils.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahUtils.cpp @@ -146,10 +146,8 @@ ShenandoahGCWorkerPhase::~ShenandoahGCWorkerPhase() { _timings->record_workers_end(_phase); } -ShenandoahWorkerSession::ShenandoahWorkerSession(uint worker_id) : _worker_id(worker_id) { - Thread* thr = Thread::current(); - assert(ShenandoahThreadLocalData::worker_id(thr) == ShenandoahThreadLocalData::INVALID_WORKER_ID, "Already set"); - ShenandoahThreadLocalData::set_worker_id(thr, worker_id); +ShenandoahWorkerSession::ShenandoahWorkerSession(uint worker_id) { + assert(worker_id == WorkerThread::worker_id(), "Wrong worker id"); } ShenandoahConcurrentWorkerSession::~ShenandoahConcurrentWorkerSession() { @@ -157,12 +155,5 @@ ShenandoahConcurrentWorkerSession::~ShenandoahConcurrentWorkerSession() { } ShenandoahParallelWorkerSession::~ShenandoahParallelWorkerSession() { - _event.commit(GCId::current(), _worker_id, ShenandoahPhaseTimings::phase_name(ShenandoahGCPhase::current_phase())); -} -ShenandoahWorkerSession::~ShenandoahWorkerSession() { -#ifdef ASSERT - Thread* thr = Thread::current(); - assert(ShenandoahThreadLocalData::worker_id(thr) != ShenandoahThreadLocalData::INVALID_WORKER_ID, "Must be set"); - ShenandoahThreadLocalData::set_worker_id(thr, ShenandoahThreadLocalData::INVALID_WORKER_ID); -#endif + _event.commit(GCId::current(), WorkerThread::worker_id(), ShenandoahPhaseTimings::phase_name(ShenandoahGCPhase::current_phase())); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahUtils.hpp b/src/hotspot/share/gc/shenandoah/shenandoahUtils.hpp index 49ff6ca28649f8b729bc12861ef3ac4a02b6a5f5..5b593dbfd0cc99bc28e2c3297ef4157f7f792606 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahUtils.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahUtils.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2019, Red Hat, Inc. All rights reserved. + * Copyright (c) 2017, 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 @@ -30,6 +30,7 @@ #include "gc/shared/gcVMOperations.hpp" #include "gc/shared/isGCActiveMark.hpp" #include "gc/shared/suspendibleThreadSet.hpp" +#include "gc/shared/workerThread.hpp" #include "gc/shenandoah/shenandoahPhaseTimings.hpp" #include "gc/shenandoah/shenandoahThreadLocalData.hpp" #include "jfr/jfrEvents.hpp" @@ -173,16 +174,10 @@ public: class ShenandoahWorkerSession : public StackObj { protected: - uint _worker_id; - ShenandoahWorkerSession(uint worker_id); - ~ShenandoahWorkerSession(); public: static inline uint worker_id() { - Thread* thr = Thread::current(); - uint id = ShenandoahThreadLocalData::worker_id(thr); - assert(id != ShenandoahThreadLocalData::INVALID_WORKER_ID, "Worker session has not been created"); - return id; + return WorkerThread::worker_id(); } }; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahWorkGroup.cpp b/src/hotspot/share/gc/shenandoah/shenandoahWorkGroup.cpp index 34202dac6574b8345ce61a4d6d081d0d21770714..d842c87e405c4771ee2eb0e2f9cdea7be138eda0 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahWorkGroup.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahWorkGroup.cpp @@ -71,11 +71,9 @@ ShenandoahPushWorkerScope::~ShenandoahPushWorkerScope() { assert(nworkers == _old_workers, "Must be able to restore"); } -WorkerThread* ShenandoahWorkerThreads::create_worker(uint id) { - WorkerThread* worker = WorkerThreads::create_worker(id); +void ShenandoahWorkerThreads::on_create_worker(WorkerThread* worker) { ShenandoahThreadLocalData::create(worker); if (_initialize_gclab) { ShenandoahThreadLocalData::initialize_gclab(worker); } - return worker; } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahWorkGroup.hpp b/src/hotspot/share/gc/shenandoah/shenandoahWorkGroup.hpp index f5bd3ea0e481b760a7a37ec93f3ce7829476ea0d..a428f26216adebe478814066d77e02c08eb6bf93 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahWorkGroup.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahWorkGroup.hpp @@ -60,9 +60,8 @@ public: WorkerThreads(name, workers), _initialize_gclab(false) { } - // Create a GC worker. // We need to initialize gclab for dynamic allocated workers - WorkerThread* create_worker(uint id); + void on_create_worker(WorkerThread* worker); void set_initialize_gclab() { assert(!_initialize_gclab, "Can only enable once"); _initialize_gclab = true; } }; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahWorkerPolicy.hpp b/src/hotspot/share/gc/shenandoah/shenandoahWorkerPolicy.hpp index 10a6fec6535d5b800dec04d07f39dd03d85c6ec6..3f47822f2200b0e9675ed247630eaeea04c5c25b 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahWorkerPolicy.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahWorkerPolicy.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2019, Red Hat, Inc. All rights reserved. + * Copyright (c) 2017, 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 @@ -25,7 +25,7 @@ #ifndef SHARE_GC_SHENANDOAH_SHENANDOAHWORKERPOLICY_HPP #define SHARE_GC_SHENANDOAH_SHENANDOAHWORKERPOLICY_HPP -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" class ShenandoahWorkerPolicy : AllStatic { private: diff --git a/src/hotspot/share/gc/z/c2/zBarrierSetC2.cpp b/src/hotspot/share/gc/z/c2/zBarrierSetC2.cpp index 45d084fe5d116edcfbab9e9adc9895c90d8b1b1d..9c72716464f753affdd5fc5ed0602025ca59a3cd 100644 --- a/src/hotspot/share/gc/z/c2/zBarrierSetC2.cpp +++ b/src/hotspot/share/gc/z/c2/zBarrierSetC2.cpp @@ -135,7 +135,9 @@ address ZLoadBarrierStubC2::slow_path() const { } RegMask& ZLoadBarrierStubC2::live() const { - return *barrier_set_state()->live(_node); + RegMask* mask = barrier_set_state()->live(_node); + assert(mask != NULL, "must be mach-node with barrier"); + return *mask; } Label* ZLoadBarrierStubC2::entry() { diff --git a/src/hotspot/share/gc/z/zAbort.hpp b/src/hotspot/share/gc/z/zAbort.hpp index 1a5bcc15f1971516078644a4c34643e75ec00613..f87bca8c0a389d4b2e0333742d277da41a315b2e 100644 --- a/src/hotspot/share/gc/z/zAbort.hpp +++ b/src/hotspot/share/gc/z/zAbort.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -24,7 +24,7 @@ #ifndef SHARE_GC_Z_ZABORT_HPP #define SHARE_GC_Z_ZABORT_HPP -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" class ZAbort : public AllStatic { private: diff --git a/src/hotspot/share/gc/z/zAddress.hpp b/src/hotspot/share/gc/z/zAddress.hpp index eddd104189e1e224ba9850155239ac233416713e..2908c37bbe6f1783529dbcda9921cd1f02d9dfc0 100644 --- a/src/hotspot/share/gc/z/zAddress.hpp +++ b/src/hotspot/share/gc/z/zAddress.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -24,7 +24,8 @@ #ifndef SHARE_GC_Z_ZADDRESS_HPP #define SHARE_GC_Z_ZADDRESS_HPP -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" +#include "utilities/globalDefinitions.hpp" class ZAddress : public AllStatic { friend class ZAddressTest; diff --git a/src/hotspot/share/gc/z/zAddressSpaceLimit.hpp b/src/hotspot/share/gc/z/zAddressSpaceLimit.hpp index b6a03776f5cffaa52c423906c1836d58cc5dc7f5..ec0faf2c0870add95cb556592a9ee1e63f8c97b1 100644 --- a/src/hotspot/share/gc/z/zAddressSpaceLimit.hpp +++ b/src/hotspot/share/gc/z/zAddressSpaceLimit.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -24,7 +24,8 @@ #ifndef SHARE_GC_Z_ZADDRESSSPACELIMIT_HPP #define SHARE_GC_Z_ZADDRESSSPACELIMIT_HPP -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" +#include "utilities/globalDefinitions.hpp" class ZAddressSpaceLimit : public AllStatic { public: diff --git a/src/hotspot/share/gc/z/zBarrier.hpp b/src/hotspot/share/gc/z/zBarrier.hpp index d57bef74f91737a2ae6b3014eea5c2b5e133d49c..2dfc1591888fa864ec883f0363093a2303256376 100644 --- a/src/hotspot/share/gc/z/zBarrier.hpp +++ b/src/hotspot/share/gc/z/zBarrier.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -24,7 +24,7 @@ #ifndef SHARE_GC_Z_ZBARRIER_HPP #define SHARE_GC_Z_ZBARRIER_HPP -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" #include "memory/iterator.hpp" #include "oops/oop.hpp" diff --git a/src/hotspot/share/gc/z/zBarrierSetRuntime.hpp b/src/hotspot/share/gc/z/zBarrierSetRuntime.hpp index f3d4fb9c6bd84391ea224609ce3a1860cba499ca..b3a143de3e97129b7a18eafaa0d089b220add38e 100644 --- a/src/hotspot/share/gc/z/zBarrierSetRuntime.hpp +++ b/src/hotspot/share/gc/z/zBarrierSetRuntime.hpp @@ -24,7 +24,7 @@ #ifndef SHARE_GC_Z_ZBARRIERSETRUNTIME_HPP #define SHARE_GC_Z_ZBARRIERSETRUNTIME_HPP -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" #include "oops/accessDecorators.hpp" #include "utilities/globalDefinitions.hpp" diff --git a/src/hotspot/share/gc/z/zBitField.hpp b/src/hotspot/share/gc/z/zBitField.hpp index 4d7171c41ac1da525e03f20a1ff5ae2167b730ad..9bec4e05594cf21355d73f99afe1ec2eef5f6e31 100644 --- a/src/hotspot/share/gc/z/zBitField.hpp +++ b/src/hotspot/share/gc/z/zBitField.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -24,8 +24,9 @@ #ifndef SHARE_GC_Z_ZBITFIELD_HPP #define SHARE_GC_Z_ZBITFIELD_HPP -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" #include "utilities/debug.hpp" +#include "utilities/globalDefinitions.hpp" // // Example diff --git a/src/hotspot/share/gc/z/zBreakpoint.hpp b/src/hotspot/share/gc/z/zBreakpoint.hpp index 14ba227e1895b8ae4d5a62aec41d172bb81ac69a..920169fb6a6716abb7db1588313f2691ee011807 100644 --- a/src/hotspot/share/gc/z/zBreakpoint.hpp +++ b/src/hotspot/share/gc/z/zBreakpoint.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -24,7 +24,7 @@ #ifndef SHARE_GC_Z_ZBREAKPOINT_HPP #define SHARE_GC_Z_ZBREAKPOINT_HPP -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" class ZBreakpoint : public AllStatic { private: diff --git a/src/hotspot/share/gc/z/zCPU.hpp b/src/hotspot/share/gc/z/zCPU.hpp index 65e04cc75e3bd5854149bde8a2ea1732da51a239..0acc949e508b8f8cc569fd7acdc160f7126e3e0d 100644 --- a/src/hotspot/share/gc/z/zCPU.hpp +++ b/src/hotspot/share/gc/z/zCPU.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -24,7 +24,7 @@ #ifndef SHARE_GC_Z_ZCPU_HPP #define SHARE_GC_Z_ZCPU_HPP -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" #include "memory/padded.hpp" #include "utilities/globalDefinitions.hpp" diff --git a/src/hotspot/share/gc/z/zCollectedHeap.cpp b/src/hotspot/share/gc/z/zCollectedHeap.cpp index e07ec3e80c775a43db7bcc9398d396b6604300db..ea883450da0846f88e8fa60493ee7fc60fc45553 100644 --- a/src/hotspot/share/gc/z/zCollectedHeap.cpp +++ b/src/hotspot/share/gc/z/zCollectedHeap.cpp @@ -38,6 +38,7 @@ #include "gc/z/zUtils.inline.hpp" #include "memory/classLoaderMetaspace.hpp" #include "memory/iterator.hpp" +#include "memory/metaspaceCriticalAllocation.hpp" #include "memory/universe.hpp" #include "utilities/align.hpp" @@ -153,34 +154,17 @@ HeapWord* ZCollectedHeap::mem_allocate(size_t size, bool* gc_overhead_limit_was_ MetaWord* ZCollectedHeap::satisfy_failed_metadata_allocation(ClassLoaderData* loader_data, size_t size, Metaspace::MetadataType mdtype) { - MetaWord* result; - // Start asynchronous GC collect(GCCause::_metadata_GC_threshold); // Expand and retry allocation - result = loader_data->metaspace_non_null()->expand_and_allocate(size, mdtype); - if (result != NULL) { - return result; - } - - // Start synchronous GC - collect(GCCause::_metadata_GC_clear_soft_refs); - - // Retry allocation - result = loader_data->metaspace_non_null()->allocate(size, mdtype); - if (result != NULL) { - return result; - } - - // Expand and retry allocation - result = loader_data->metaspace_non_null()->expand_and_allocate(size, mdtype); + MetaWord* const result = loader_data->metaspace_non_null()->expand_and_allocate(size, mdtype); if (result != NULL) { return result; } - // Out of memory - return NULL; + // As a last resort, try a critical allocation, riding on a synchronous full GC + return MetaspaceCriticalAllocation::allocate(loader_data, size, mdtype); } void ZCollectedHeap::collect(GCCause::Cause cause) { @@ -242,7 +226,7 @@ void ZCollectedHeap::object_iterate(ObjectClosure* cl) { _heap.object_iterate(cl, true /* visit_weaks */); } -ParallelObjectIterator* ZCollectedHeap::parallel_object_iterator(uint nworkers) { +ParallelObjectIteratorImpl* ZCollectedHeap::parallel_object_iterator(uint nworkers) { return _heap.parallel_object_iterator(nworkers, true /* visit_weaks */); } diff --git a/src/hotspot/share/gc/z/zCollectedHeap.hpp b/src/hotspot/share/gc/z/zCollectedHeap.hpp index 236609361d02d0d9e8601f628e79668b4b1ffe94..12f6902a025a55138f10406b7cd7e8a4aaca7ecc 100644 --- a/src/hotspot/share/gc/z/zCollectedHeap.hpp +++ b/src/hotspot/share/gc/z/zCollectedHeap.hpp @@ -95,7 +95,7 @@ public: virtual GrowableArray memory_pools(); virtual void object_iterate(ObjectClosure* cl); - virtual ParallelObjectIterator* parallel_object_iterator(uint nworkers); + virtual ParallelObjectIteratorImpl* parallel_object_iterator(uint nworkers); virtual void keep_alive(oop obj); diff --git a/src/hotspot/share/gc/z/zHash.hpp b/src/hotspot/share/gc/z/zHash.hpp index 5752d2abee3c9dbb5b741986ccb5e2eb5839273e..e6469698488901a322f6de54665af2a965ff303f 100644 --- a/src/hotspot/share/gc/z/zHash.hpp +++ b/src/hotspot/share/gc/z/zHash.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -24,7 +24,7 @@ #ifndef SHARE_GC_Z_ZHASH_HPP #define SHARE_GC_Z_ZHASH_HPP -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" #include "utilities/globalDefinitions.hpp" class ZHash : public AllStatic { diff --git a/src/hotspot/share/gc/z/zHeap.cpp b/src/hotspot/share/gc/z/zHeap.cpp index 3bf3cf50ed8ee0b777c5ebe3a2345a1525eb9a1c..b937a645f6264d29e7eb72802469031315599a93 100644 --- a/src/hotspot/share/gc/z/zHeap.cpp +++ b/src/hotspot/share/gc/z/zHeap.cpp @@ -439,7 +439,7 @@ void ZHeap::object_iterate(ObjectClosure* cl, bool visit_weaks) { iter.object_iterate(cl, 0 /* worker_id */); } -ParallelObjectIterator* ZHeap::parallel_object_iterator(uint nworkers, bool visit_weaks) { +ParallelObjectIteratorImpl* ZHeap::parallel_object_iterator(uint nworkers, bool visit_weaks) { assert(SafepointSynchronize::is_at_safepoint(), "Should be at safepoint"); return new ZHeapIterator(nworkers, visit_weaks); } diff --git a/src/hotspot/share/gc/z/zHeap.hpp b/src/hotspot/share/gc/z/zHeap.hpp index f4e36ad738e0b447748fc43f42e318523e1c18ee..723ec52d39cd6c14565d8b77ed28c6def5085d02 100644 --- a/src/hotspot/share/gc/z/zHeap.hpp +++ b/src/hotspot/share/gc/z/zHeap.hpp @@ -141,7 +141,7 @@ public: // Iteration void object_iterate(ObjectClosure* cl, bool visit_weaks); - ParallelObjectIterator* parallel_object_iterator(uint nworkers, bool visit_weaks); + ParallelObjectIteratorImpl* parallel_object_iterator(uint nworkers, bool visit_weaks); void pages_do(ZPageClosure* cl); // Serviceability diff --git a/src/hotspot/share/gc/z/zHeapIterator.hpp b/src/hotspot/share/gc/z/zHeapIterator.hpp index bbd3eb203c3745c9ef3b8155b8324e8754480138..5c3a82d8bb7d9351b83c9a863298e278ce053ffa 100644 --- a/src/hotspot/share/gc/z/zHeapIterator.hpp +++ b/src/hotspot/share/gc/z/zHeapIterator.hpp @@ -42,7 +42,7 @@ using ZHeapIteratorQueues = GenericTaskQueueSet; using ZHeapIteratorArrayQueue = OverflowTaskQueue; using ZHeapIteratorArrayQueues = GenericTaskQueueSet; -class ZHeapIterator : public ParallelObjectIterator { +class ZHeapIterator : public ParallelObjectIteratorImpl { friend class ZHeapIteratorContext; private: diff --git a/src/hotspot/share/gc/z/zHeuristics.hpp b/src/hotspot/share/gc/z/zHeuristics.hpp index 5b810a84851cdddd361a78657d026800fd61bfcb..362fd775f0fa31ec0e1c01b41d901e49efe4480b 100644 --- a/src/hotspot/share/gc/z/zHeuristics.hpp +++ b/src/hotspot/share/gc/z/zHeuristics.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -24,7 +24,7 @@ #ifndef SHARE_GC_Z_ZHEURISTICS_HPP #define SHARE_GC_Z_ZHEURISTICS_HPP -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" class ZHeuristics : public AllStatic { public: diff --git a/src/hotspot/share/gc/z/zLargePages.hpp b/src/hotspot/share/gc/z/zLargePages.hpp index 1201b4962661348583eba7b5000c0a4b6ceed3d1..9f7c8310e50f4fc03e1daa8feba81000e858c0ee 100644 --- a/src/hotspot/share/gc/z/zLargePages.hpp +++ b/src/hotspot/share/gc/z/zLargePages.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -24,7 +24,7 @@ #ifndef SHARE_GC_Z_ZLARGEPAGES_HPP #define SHARE_GC_Z_ZLARGEPAGES_HPP -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" class ZLargePages : public AllStatic { private: diff --git a/src/hotspot/share/gc/z/zNMethod.hpp b/src/hotspot/share/gc/z/zNMethod.hpp index 40ac93adb8e12ef0e903014613efa39744b2aabf..117c5e34f4ecb54ff2982f5e45ed6b35a070afd2 100644 --- a/src/hotspot/share/gc/z/zNMethod.hpp +++ b/src/hotspot/share/gc/z/zNMethod.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -24,7 +24,7 @@ #ifndef SHARE_GC_Z_ZNMETHOD_HPP #define SHARE_GC_Z_ZNMETHOD_HPP -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" class nmethod; class NMethodClosure; diff --git a/src/hotspot/share/gc/z/zNMethodTable.hpp b/src/hotspot/share/gc/z/zNMethodTable.hpp index 26ae2d2793332567cf1416801a1e765fb525f1c4..a1af8512f698b7c6a9a06e0899975a003cc1204b 100644 --- a/src/hotspot/share/gc/z/zNMethodTable.hpp +++ b/src/hotspot/share/gc/z/zNMethodTable.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -26,7 +26,7 @@ #include "gc/z/zNMethodTableIteration.hpp" #include "gc/z/zSafeDelete.hpp" -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" class nmethod; class NMethodClosure; diff --git a/src/hotspot/share/gc/z/zNUMA.hpp b/src/hotspot/share/gc/z/zNUMA.hpp index 0dc4390e8b475809cb809260e9d59ab62a65221a..fb29e1faaa733906983e82b62c56f7b2bea94064 100644 --- a/src/hotspot/share/gc/z/zNUMA.hpp +++ b/src/hotspot/share/gc/z/zNUMA.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -24,7 +24,8 @@ #ifndef SHARE_GC_Z_ZNUMA_HPP #define SHARE_GC_Z_ZNUMA_HPP -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" +#include "utilities/globalDefinitions.hpp" class ZNUMA : public AllStatic { private: diff --git a/src/hotspot/share/gc/z/zOop.hpp b/src/hotspot/share/gc/z/zOop.hpp index cf752ba61c3aff076284280c1b016e6f639b338b..4fb0e6499e14a0c394f4074ca68cd6053d235616 100644 --- a/src/hotspot/share/gc/z/zOop.hpp +++ b/src/hotspot/share/gc/z/zOop.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -24,7 +24,7 @@ #ifndef SHARE_GC_Z_ZOOP_HPP #define SHARE_GC_Z_ZOOP_HPP -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" #include "oops/oopsHierarchy.hpp" class ZOop : public AllStatic { diff --git a/src/hotspot/share/gc/z/zPhysicalMemory.cpp b/src/hotspot/share/gc/z/zPhysicalMemory.cpp index abdf7df69b08090e2ab7566e63e4082dc01787e0..eb889f4e4f2c31090124948c368e2f80f03ac1a0 100644 --- a/src/hotspot/share/gc/z/zPhysicalMemory.cpp +++ b/src/hotspot/share/gc/z/zPhysicalMemory.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -282,7 +282,7 @@ void ZPhysicalMemoryManager::nmt_commit(uintptr_t offset, size_t size) const { } void ZPhysicalMemoryManager::nmt_uncommit(uintptr_t offset, size_t size) const { - if (MemTracker::tracking_level() > NMT_minimal) { + if (MemTracker::enabled()) { const uintptr_t addr = ZAddress::marked0(offset); Tracker tracker(Tracker::uncommit); tracker.record((address)addr, size); diff --git a/src/hotspot/share/gc/z/zResurrection.hpp b/src/hotspot/share/gc/z/zResurrection.hpp index a88b93544692307443f18edf81167315fbc4e2cd..3d6a8f95a1cd833893a7435cb88f66136ea45a0d 100644 --- a/src/hotspot/share/gc/z/zResurrection.hpp +++ b/src/hotspot/share/gc/z/zResurrection.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -24,7 +24,7 @@ #ifndef SHARE_GC_Z_ZRESURRECTION_HPP #define SHARE_GC_Z_ZRESURRECTION_HPP -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" class ZResurrection : public AllStatic { private: diff --git a/src/hotspot/share/gc/z/zStat.cpp b/src/hotspot/share/gc/z/zStat.cpp index 0df9d061087c7b2c939f474882205981d53fd2c2..540c171ae9f7fad001dff608bff985bfd045f21d 100644 --- a/src/hotspot/share/gc/z/zStat.cpp +++ b/src/hotspot/share/gc/z/zStat.cpp @@ -31,6 +31,7 @@ #include "gc/z/zPageAllocator.inline.hpp" #include "gc/z/zRelocationSetSelector.inline.hpp" #include "gc/z/zStat.hpp" +#include "gc/z/zThread.inline.hpp" #include "gc/z/zTracer.inline.hpp" #include "gc/z/zUtils.hpp" #include "memory/metaspaceUtils.hpp" @@ -736,8 +737,13 @@ ZStatSubPhase::ZStatSubPhase(const char* name) : ZStatPhase("Subphase", name) {} void ZStatSubPhase::register_start(const Ticks& start) const { - LogTarget(Debug, gc, phases, start) log; - log_start(log, true /* thread */); + if (ZThread::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 ZStatSubPhase::register_end(const Ticks& start, const Ticks& end) const { @@ -750,8 +756,13 @@ void ZStatSubPhase::register_end(const Ticks& start, const Ticks& end) const { const Tickspan duration = end - start; ZStatSample(_sampler, duration.value()); - LogTarget(Debug, gc, phases) log; - log_end(log, duration, true /* thread */); + if (ZThread::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 */); + } } ZStatCriticalPhase::ZStatCriticalPhase(const char* name, bool verbose) : diff --git a/src/hotspot/share/gc/z/zThread.hpp b/src/hotspot/share/gc/z/zThread.hpp index f98b7a05fb611ca9f09d77c5cab5c2cc94d32296..c67807ff96ecdfe07b7d825b336410acd5c7a249 100644 --- a/src/hotspot/share/gc/z/zThread.hpp +++ b/src/hotspot/share/gc/z/zThread.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -24,7 +24,7 @@ #ifndef SHARE_GC_Z_ZTHREAD_HPP #define SHARE_GC_Z_ZTHREAD_HPP -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" #include "utilities/globalDefinitions.hpp" class ZThread : public AllStatic { diff --git a/src/hotspot/share/gc/z/zThreadLocalAllocBuffer.hpp b/src/hotspot/share/gc/z/zThreadLocalAllocBuffer.hpp index d6693fceb0085b296625a70229336858aa11f884..086c8a5c351ce5b8d4ad90dc10b08732bd14bfbf 100644 --- a/src/hotspot/share/gc/z/zThreadLocalAllocBuffer.hpp +++ b/src/hotspot/share/gc/z/zThreadLocalAllocBuffer.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -26,7 +26,7 @@ #include "gc/shared/threadLocalAllocBuffer.hpp" #include "gc/z/zValue.hpp" -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" class JavaThread; diff --git a/src/hotspot/share/gc/z/zTracer.cpp b/src/hotspot/share/gc/z/zTracer.cpp index 2a0d3e11a793778801f4e4df8fdbfbf5f3635cbb..b7d0bc0a697e5c14a0bbf1be1f37523f30d71164 100644 --- a/src/hotspot/share/gc/z/zTracer.cpp +++ b/src/hotspot/share/gc/z/zTracer.cpp @@ -131,3 +131,16 @@ void ZTracer::send_thread_phase(const char* name, const Ticks& start, const Tick e.commit(); } } + +void ZTracer::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/z/zTracer.hpp b/src/hotspot/share/gc/z/zTracer.hpp index c39a193168ba2d9039408a147cb0a3375396ffdc..3ec97dfa4cbcbde8437478b632321ad58c95826e 100644 --- a/src/hotspot/share/gc/z/zTracer.hpp +++ b/src/hotspot/share/gc/z/zTracer.hpp @@ -39,6 +39,7 @@ private: void send_stat_counter(const ZStatCounter& counter, uint64_t increment, uint64_t value); void send_stat_sampler(const ZStatSampler& 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 ZTracer* tracer(); @@ -47,16 +48,18 @@ public: void report_stat_counter(const ZStatCounter& counter, uint64_t increment, uint64_t value); void report_stat_sampler(const ZStatSampler& 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); }; -class ZTraceThreadPhase : public StackObj { +// For temporary latency measurements during development and debugging +class ZTraceThreadDebug : public StackObj { private: const Ticks _start; const char* const _name; public: - ZTraceThreadPhase(const char* name); - ~ZTraceThreadPhase(); + ZTraceThreadDebug(const char* name); + ~ZTraceThreadDebug(); }; #endif // SHARE_GC_Z_ZTRACER_HPP diff --git a/src/hotspot/share/gc/z/zTracer.inline.hpp b/src/hotspot/share/gc/z/zTracer.inline.hpp index 143eebb4d3b6304b2b4a8a71524593effdf4b012..cfaf7b43f0c463f9fb6cd8903fc48d544d04100c 100644 --- a/src/hotspot/share/gc/z/zTracer.inline.hpp +++ b/src/hotspot/share/gc/z/zTracer.inline.hpp @@ -50,12 +50,18 @@ inline void ZTracer::report_thread_phase(const char* name, const Ticks& start, c } } -inline ZTraceThreadPhase::ZTraceThreadPhase(const char* name) : +inline void ZTracer::report_thread_debug(const char* name, const Ticks& start, const Ticks& end) { + if (EventZThreadDebug::is_enabled()) { + send_thread_debug(name, start, end); + } +} + +inline ZTraceThreadDebug::ZTraceThreadDebug(const char* name) : _start(Ticks::now()), _name(name) {} -inline ZTraceThreadPhase::~ZTraceThreadPhase() { - ZTracer::tracer()->report_thread_phase(_name, _start, Ticks::now()); +inline ZTraceThreadDebug::~ZTraceThreadDebug() { + ZTracer::tracer()->report_thread_debug(_name, _start, Ticks::now()); } #endif // SHARE_GC_Z_ZTRACER_INLINE_HPP diff --git a/src/hotspot/share/gc/z/zUtils.hpp b/src/hotspot/share/gc/z/zUtils.hpp index f4abea9c6feeed61f5f3a6a833fd35ad8fbc2d55..470329daf0d393f658315b7960421e34c9ac075f 100644 --- a/src/hotspot/share/gc/z/zUtils.hpp +++ b/src/hotspot/share/gc/z/zUtils.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -24,7 +24,8 @@ #ifndef SHARE_GC_Z_ZUTILS_HPP #define SHARE_GC_Z_ZUTILS_HPP -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" +#include "utilities/globalDefinitions.hpp" class ZUtils : public AllStatic { public: diff --git a/src/hotspot/share/gc/z/zValue.hpp b/src/hotspot/share/gc/z/zValue.hpp index 281a2e48b8cbebb089fd8f8941be65fe3b1e60c5..e2c67e8c48d0f772a71aff833d9751e6d24454b9 100644 --- a/src/hotspot/share/gc/z/zValue.hpp +++ b/src/hotspot/share/gc/z/zValue.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -24,7 +24,7 @@ #ifndef SHARE_GC_Z_ZVALUE_HPP #define SHARE_GC_Z_ZVALUE_HPP -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" #include "utilities/globalDefinitions.hpp" // diff --git a/src/hotspot/share/gc/z/zVerify.hpp b/src/hotspot/share/gc/z/zVerify.hpp index db2d56d00951f5e92ebc3b9f883670385bc2b123..8d7abd4a8d53152ab1ac2e24bf18600f34a48660 100644 --- a/src/hotspot/share/gc/z/zVerify.hpp +++ b/src/hotspot/share/gc/z/zVerify.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -24,7 +24,7 @@ #ifndef SHARE_GC_Z_ZVERIFY_HPP #define SHARE_GC_Z_ZVERIFY_HPP -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" class frame; class ZPageAllocator; diff --git a/src/hotspot/share/include/cds.h b/src/hotspot/share/include/cds.h index eeb45ba34c4d755996d34a081e60893363cc75d3..21a7a43b3af3c8aae189d34b09497a5f85340544 100644 --- a/src/hotspot/share/include/cds.h +++ b/src/hotspot/share/include/cds.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -38,7 +38,8 @@ #define NUM_CDS_REGIONS 7 // this must be the same as MetaspaceShared::n_regions #define CDS_ARCHIVE_MAGIC 0xf00baba2 #define CDS_DYNAMIC_ARCHIVE_MAGIC 0xf00baba8 -#define CURRENT_CDS_ARCHIVE_VERSION 12 +#define CDS_GENERIC_HEADER_SUPPORTED_MIN_VERSION 13 +#define CURRENT_CDS_ARCHIVE_VERSION 14 typedef struct CDSFileMapRegion { int _crc; // CRC checksum of this region. @@ -47,7 +48,7 @@ typedef struct CDSFileMapRegion { int _is_heap_region; // Used by SA and debug build. int _is_bitmap_region; // Relocation bitmap for RO/RW regions (used by SA and debug build). int _mapped_from_file; // Is this region mapped from a file? - // If false, this region was initialized using os::read(). + // If false, this region was initialized using ::read(). size_t _file_offset; // Data for this region starts at this offset in the archive file. size_t _mapping_offset; // This region should be mapped at this offset from the base address // - for non-heap regions, the base address is SharedBaseAddress @@ -59,12 +60,13 @@ typedef struct CDSFileMapRegion { char* _mapped_base; // Actually mapped address (NULL if this region is not mapped). } CDSFileMapRegion; -// This portion of the archive file header must remain unchanged for _version >= 12. +// This portion of the archive file header must remain unchanged for +// _version >= CDS_GENERIC_HEADER_SUPPORTED_MIN_VERSION (12). // This makes it possible to read important information from a CDS archive created by // a different version of HotSpot, so that we can automatically regenerate the archive as necessary. typedef struct GenericCDSFileMapHeader { unsigned int _magic; // identification of file type - int _crc; // header crc checksum + int _crc; // header crc checksum, start from _base_archive_name_offset int _version; // CURRENT_CDS_ARCHIVE_VERSION of the jdk that dumped the this archive unsigned int _header_size; // total size of the header, in bytes unsigned int _base_archive_name_offset; // offset where the base archive name is stored diff --git a/src/hotspot/share/include/jmm.h b/src/hotspot/share/include/jmm.h index d7788e7a4e841adff698d8701178e38075f9fa70..ee1c77e504a424252d4414be3d4cc075e946caf3 100644 --- a/src/hotspot/share/include/jmm.h +++ b/src/hotspot/share/include/jmm.h @@ -333,7 +333,8 @@ typedef struct jmmInterface_1_ { void (JNICALL *GetDiagnosticCommandArgumentsInfo) (JNIEnv *env, jstring commandName, - dcmdArgInfo *infoArray); + dcmdArgInfo *infoArray, + jint count); jstring (JNICALL *ExecuteDiagnosticCommand) (JNIEnv *env, jstring command); diff --git a/src/hotspot/share/include/jvm.h b/src/hotspot/share/include/jvm.h index 7783b00841d58d1a283501fd1208b0d1de8c0022..dfdd2219869aee6aa734ed461af59fa092f9d30d 100644 --- a/src/hotspot/share/include/jvm.h +++ b/src/hotspot/share/include/jvm.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -150,6 +150,9 @@ JVM_ActiveProcessorCount(void); JNIEXPORT jboolean JNICALL JVM_IsUseContainerSupport(void); +JNIEXPORT void * JNICALL +JVM_LoadZipLibrary(); + JNIEXPORT void * JNICALL JVM_LoadLibrary(const char *name, jboolean throwException); @@ -759,6 +762,9 @@ JVM_SupportsCX8(void); JNIEXPORT void JNICALL JVM_ReportFinalizationComplete(JNIEnv *env, jobject finalizee); +JNIEXPORT jboolean JNICALL +JVM_IsFinalizationEnabled(JNIEnv *env); + /************************************************************************* PART 2: Support for the Verifier and Class File Format Checker ************************************************************************/ diff --git a/src/hotspot/share/interpreter/abstractInterpreter.cpp b/src/hotspot/share/interpreter/abstractInterpreter.cpp index 9e327c2d640101c4ffa35b54cb3b14f9388ed8a7..c39790f69f831b4b4f4dfc844b5546147ee8353f 100644 --- a/src/hotspot/share/interpreter/abstractInterpreter.cpp +++ b/src/hotspot/share/interpreter/abstractInterpreter.cpp @@ -134,6 +134,9 @@ AbstractInterpreter::MethodKind AbstractInterpreter::method_kind(const methodHan case vmIntrinsics::_floatToRawIntBits: return java_lang_Float_floatToRawIntBits; case vmIntrinsics::_longBitsToDouble: return java_lang_Double_longBitsToDouble; case vmIntrinsics::_doubleToRawLongBits: return java_lang_Double_doubleToRawLongBits; +#ifdef AMD64 + case vmIntrinsics::_currentThread: return java_lang_Thread_currentThread; +#endif #endif // ZERO case vmIntrinsics::_dsin: return java_lang_math_sin; case vmIntrinsics::_dcos: return java_lang_math_cos; diff --git a/src/hotspot/share/interpreter/abstractInterpreter.hpp b/src/hotspot/share/interpreter/abstractInterpreter.hpp index 06d35ecd01b87ed58dcb00c9b9a8e0487582abf6..26b3fffd2b9cb71d7e3cdcec3213de1eda63b217 100644 --- a/src/hotspot/share/interpreter/abstractInterpreter.hpp +++ b/src/hotspot/share/interpreter/abstractInterpreter.hpp @@ -90,6 +90,7 @@ class AbstractInterpreter: AllStatic { java_lang_Float_floatToRawIntBits, // implementation of java.lang.Float.floatToRawIntBits() java_lang_Double_longBitsToDouble, // implementation of java.lang.Double.longBitsToDouble() java_lang_Double_doubleToRawLongBits, // implementation of java.lang.Double.doubleToRawLongBits() + java_lang_Thread_currentThread, // implementation of java.lang.Thread.currentThread() number_of_method_entries, invalid = -1 }; diff --git a/src/hotspot/share/interpreter/bootstrapInfo.cpp b/src/hotspot/share/interpreter/bootstrapInfo.cpp index 4f52b19fcc639e99acda8176cc7f9369f5084514..830c015cc3920fa59eb0291e5e5fc83aec720fd5 100644 --- a/src/hotspot/share/interpreter/bootstrapInfo.cpp +++ b/src/hotspot/share/interpreter/bootstrapInfo.cpp @@ -67,7 +67,7 @@ bool BootstrapInfo::resolve_previously_linked_invokedynamic(CallInfo& result, TR if (!cpce->is_f1_null()) { methodHandle method( THREAD, cpce->f1_as_method()); Handle appendix( THREAD, cpce->appendix_if_resolved(_pool)); - result.set_handle(method, appendix, THREAD); + result.set_handle(vmClasses::MethodHandle_klass(), method, appendix, THREAD); Exceptions::wrap_dynamic_exception(/* is_indy */ true, CHECK_false); return true; } else if (cpce->indy_resolution_failed()) { @@ -221,7 +221,7 @@ bool BootstrapInfo::save_and_throw_indy_exc(TRAPS) { void BootstrapInfo::resolve_newly_linked_invokedynamic(CallInfo& result, TRAPS) { assert(is_resolved(), ""); - result.set_handle(resolved_method(), resolved_appendix(), CHECK); + result.set_handle(vmClasses::MethodHandle_klass(), resolved_method(), resolved_appendix(), CHECK); } void BootstrapInfo::print_msg_on(outputStream* st, const char* msg) { diff --git a/src/hotspot/share/interpreter/bytecodeHistogram.hpp b/src/hotspot/share/interpreter/bytecodeHistogram.hpp index b919227702f8e7ba5d5c74183fe02b13a47e5c9a..44ddca074d06bbd26470c0d0de78980fd4c136b1 100644 --- a/src/hotspot/share/interpreter/bytecodeHistogram.hpp +++ b/src/hotspot/share/interpreter/bytecodeHistogram.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -26,7 +26,7 @@ #define SHARE_INTERPRETER_BYTECODEHISTOGRAM_HPP #include "interpreter/bytecodes.hpp" -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" // BytecodeCounter counts the number of bytecodes executed diff --git a/src/hotspot/share/interpreter/bytecodeTracer.hpp b/src/hotspot/share/interpreter/bytecodeTracer.hpp index 52e91a0e7128837f754b3d113cc553f3c55c8bf5..38c2b092ce3faa3b8d6155509f1aacb6e12d43ee 100644 --- a/src/hotspot/share/interpreter/bytecodeTracer.hpp +++ b/src/hotspot/share/interpreter/bytecodeTracer.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -25,7 +25,7 @@ #ifndef SHARE_INTERPRETER_BYTECODETRACER_HPP #define SHARE_INTERPRETER_BYTECODETRACER_HPP -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" #include "utilities/ostream.hpp" // The BytecodeTracer is a helper class used by the interpreter for run-time diff --git a/src/hotspot/share/interpreter/bytecodeUtils.cpp b/src/hotspot/share/interpreter/bytecodeUtils.cpp index 9473e87dec14b9822917e737e31166ab5d6c9c60..df5fbbe0e6b110d31042a77a212d20dad8769b41 100644 --- a/src/hotspot/share/interpreter/bytecodeUtils.cpp +++ b/src/hotspot/share/interpreter/bytecodeUtils.cpp @@ -1029,7 +1029,6 @@ int ExceptionMessageBuilder::do_instruction(int bci) { break; case Bytecodes::_arraylength: - // The return type of arraylength is wrong in the bytecodes table (T_VOID). stack->pop(1); stack->push(bci, T_INT); break; diff --git a/src/hotspot/share/interpreter/bytecodeUtils.hpp b/src/hotspot/share/interpreter/bytecodeUtils.hpp index ede99a995b7c92388e58939272a1d6a04ce52388..ff23b9c000f400f349bf79918144bf8d38488d19 100644 --- a/src/hotspot/share/interpreter/bytecodeUtils.hpp +++ b/src/hotspot/share/interpreter/bytecodeUtils.hpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2019 SAP SE. All rights reserved. + * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 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 @@ -26,7 +26,7 @@ #ifndef SHARE_INTERPRETER_BYTECODEUTILS_HPP #define SHARE_INTERPRETER_BYTECODEUTILS_HPP -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" #include "utilities/globalDefinitions.hpp" class Method; diff --git a/src/hotspot/share/interpreter/bytecodes.cpp b/src/hotspot/share/interpreter/bytecodes.cpp index 6711ba735db769e44260f03f08e27e88ac802cec..770934f31d8c7c9678d0dccaca64325e1727013f 100644 --- a/src/hotspot/share/interpreter/bytecodes.cpp +++ b/src/hotspot/share/interpreter/bytecodes.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -471,7 +471,7 @@ void Bytecodes::initialize() { def(_new , "new" , "bkk" , NULL , T_OBJECT , 1, true ); def(_newarray , "newarray" , "bc" , NULL , T_OBJECT , 0, true ); def(_anewarray , "anewarray" , "bkk" , NULL , T_OBJECT , 0, true ); - def(_arraylength , "arraylength" , "b" , NULL , T_VOID , 0, true ); + def(_arraylength , "arraylength" , "b" , NULL , T_INT , 0, true ); def(_athrow , "athrow" , "b" , NULL , T_VOID , -1, true ); def(_checkcast , "checkcast" , "bkk" , NULL , T_OBJECT , 0, true ); def(_instanceof , "instanceof" , "bkk" , NULL , T_INT , 0, true ); diff --git a/src/hotspot/share/interpreter/bytecodes.hpp b/src/hotspot/share/interpreter/bytecodes.hpp index 9a34a227c0472abc3a35eb96d5ab12a323b9a2fc..7c70518d2b155be71846b480bdb6cca795afe8d3 100644 --- a/src/hotspot/share/interpreter/bytecodes.hpp +++ b/src/hotspot/share/interpreter/bytecodes.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -25,7 +25,8 @@ #ifndef SHARE_INTERPRETER_BYTECODES_HPP #define SHARE_INTERPRETER_BYTECODES_HPP -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" +#include "utilities/globalDefinitions.hpp" // Bytecodes specifies all bytecodes used in the VM and // provides utility functions to get bytecode attributes. diff --git a/src/hotspot/share/interpreter/interpreterRuntime.cpp b/src/hotspot/share/interpreter/interpreterRuntime.cpp index 6b178d625602d8db4646967150bd1c292b7361ff..5e61410ddc204637107e30134ac2417f8db73d93 100644 --- a/src/hotspot/share/interpreter/interpreterRuntime.cpp +++ b/src/hotspot/share/interpreter/interpreterRuntime.cpp @@ -407,7 +407,11 @@ JRT_ENTRY(void, InterpreterRuntime::create_klass_exception(JavaThread* current, // lookup exception klass TempNewSymbol s = SymbolTable::new_symbol(name); if (ProfileTraps) { - note_trap(current, Deoptimization::Reason_class_check); + if (s == vmSymbols::java_lang_ArrayStoreException()) { + note_trap(current, Deoptimization::Reason_array_check); + } else { + note_trap(current, Deoptimization::Reason_class_check); + } } // create exception, with klass name as detail message Handle exception = Exceptions::new_exception(current, s, klass_name); @@ -825,7 +829,18 @@ void InterpreterRuntime::resolve_invoke(JavaThread* current, Bytecodes::Code byt JavaThread* THREAD = current; // For exception macros. LinkResolver::resolve_invoke(info, receiver, pool, last_frame.get_index_u2_cpcache(bytecode), bytecode, - CHECK); + THREAD); + + if (HAS_PENDING_EXCEPTION) { + if (ProfileTraps && PENDING_EXCEPTION->klass()->name() == vmSymbols::java_lang_NullPointerException()) { + // Preserve the original exception across the call to note_trap() + PreserveExceptionMark pm(current); + // Recording the trap will help the compiler to potentially recognize this exception as "hot" + note_trap(current, Deoptimization::Reason_null_check); + } + return; + } + if (JvmtiExport::can_hotswap_or_post_breakpoint() && info.resolved_method()->is_old()) { resolved_method = methodHandle(current, info.resolved_method()->get_new_method()); } else { diff --git a/src/hotspot/share/interpreter/linkResolver.cpp b/src/hotspot/share/interpreter/linkResolver.cpp index 84589092397b6bf5f18f78d4be3b86a415416f59..fa8072fb207b44c7badf6b724037726fb73d93a6 100644 --- a/src/hotspot/share/interpreter/linkResolver.cpp +++ b/src/hotspot/share/interpreter/linkResolver.cpp @@ -94,11 +94,6 @@ void CallInfo::set_virtual(Klass* resolved_klass, assert(!resolved_method->is_compiled_lambda_form(), "these must be handled via an invokehandle call"); } -void CallInfo::set_handle(const methodHandle& resolved_method, - Handle resolved_appendix, TRAPS) { - set_handle(vmClasses::MethodHandle_klass(), resolved_method, resolved_appendix, CHECK); -} - void CallInfo::set_handle(Klass* resolved_klass, const methodHandle& resolved_method, Handle resolved_appendix, TRAPS) { @@ -476,14 +471,12 @@ Method* LinkResolver::lookup_polymorphic_method(const LinkInfo& link_info, } Handle appendix; - Handle method_type; - Method* result = SystemDictionary::find_method_handle_invoker( - klass, - name, - full_signature, - link_info.current_klass(), - &appendix, - CHECK_NULL); + Method* result = SystemDictionary::find_method_handle_invoker(klass, + name, + full_signature, + link_info.current_klass(), + &appendix, + CHECK_NULL); if (lt_mh.is_enabled()) { LogStream ls(lt_mh); ls.print("lookup_polymorphic_method => (via Java) "); @@ -621,7 +614,7 @@ Method* LinkResolver::resolve_method_statically(Bytecodes::Code code, Klass* resolved_klass = link_info.resolved_klass(); if (pool->has_preresolution() - || (resolved_klass == vmClasses::MethodHandle_klass() && + || ((resolved_klass == vmClasses::MethodHandle_klass() || resolved_klass == vmClasses::VarHandle_klass()) && MethodHandles::is_signature_polymorphic_name(resolved_klass, link_info.name()))) { Method* result = ConstantPool::method_at_if_loaded(pool, index); if (result != NULL) { @@ -1679,15 +1672,31 @@ void LinkResolver::resolve_invokeinterface(CallInfo& result, Handle recv, const resolve_interface_call(result, recv, recvrKlass, link_info, true, CHECK); } +bool LinkResolver::resolve_previously_linked_invokehandle(CallInfo& result, const LinkInfo& link_info, const constantPoolHandle& pool, int index, TRAPS) { + int cache_index = ConstantPool::decode_cpcache_index(index, true); + ConstantPoolCacheEntry* cpce = pool->cache()->entry_at(cache_index); + if (!cpce->is_f1_null()) { + Klass* resolved_klass = link_info.resolved_klass(); + methodHandle method(THREAD, cpce->f1_as_method()); + Handle appendix(THREAD, cpce->appendix_if_resolved(pool)); + result.set_handle(resolved_klass, method, appendix, CHECK_false); + return true; + } else { + return false; + } +} void LinkResolver::resolve_invokehandle(CallInfo& result, const constantPoolHandle& pool, int index, TRAPS) { - // This guy is reached from InterpreterRuntime::resolve_invokehandle. LinkInfo link_info(pool, index, CHECK); if (log_is_enabled(Info, methodhandles)) { ResourceMark rm(THREAD); log_info(methodhandles)("resolve_invokehandle %s %s", link_info.name()->as_C_string(), link_info.signature()->as_C_string()); } + { // Check if the call site has been bound already, and short circuit: + bool is_done = resolve_previously_linked_invokehandle(result, link_info, pool, index, CHECK); + if (is_done) return; + } resolve_handle_call(result, link_info, CHECK); } @@ -1699,7 +1708,7 @@ void LinkResolver::resolve_handle_call(CallInfo& result, assert(resolved_klass == vmClasses::MethodHandle_klass() || resolved_klass == vmClasses::VarHandle_klass(), ""); assert(MethodHandles::is_signature_polymorphic_name(link_info.name()), ""); - Handle resolved_appendix; + Handle resolved_appendix; Method* resolved_method = lookup_polymorphic_method(link_info, &resolved_appendix, CHECK); result.set_handle(resolved_klass, methodHandle(THREAD, resolved_method), resolved_appendix, CHECK); } diff --git a/src/hotspot/share/interpreter/linkResolver.hpp b/src/hotspot/share/interpreter/linkResolver.hpp index 9eeb10cc6fd3f69a590626fdc2076586f2ddd476..e0b2c0b43788d1f21d5a3fe48ecb376fe6c2567c 100644 --- a/src/hotspot/share/interpreter/linkResolver.hpp +++ b/src/hotspot/share/interpreter/linkResolver.hpp @@ -66,8 +66,6 @@ class CallInfo : public StackObj { const methodHandle& resolved_method, const methodHandle& selected_method, int vtable_index, TRAPS); - void set_handle(const methodHandle& resolved_method, - Handle resolved_appendix, TRAPS); void set_handle(Klass* resolved_klass, const methodHandle& resolved_method, Handle resolved_appendix, TRAPS); @@ -249,6 +247,11 @@ class LinkResolver: AllStatic { Klass* recv_klass, bool check_null_and_abstract, TRAPS); + static bool resolve_previously_linked_invokehandle(CallInfo& result, + const LinkInfo& link_info, + const constantPoolHandle& pool, + int index, TRAPS); + static void check_field_accessability(Klass* ref_klass, Klass* resolved_klass, Klass* sel_klass, @@ -337,7 +340,6 @@ class LinkResolver: AllStatic { const methodHandle& attached_method, Bytecodes::Code byte, TRAPS); - public: // Only resolved method known. static void throw_abstract_method_error(const methodHandle& resolved_method, TRAPS) { throw_abstract_method_error(resolved_method, methodHandle(), NULL, CHECK); diff --git a/src/hotspot/share/interpreter/oopMapCache.cpp b/src/hotspot/share/interpreter/oopMapCache.cpp index 8799275683ae991939910d99a8d902e83e0f7e3f..84bef74bed921064c7c960225156d108952eadd8 100644 --- a/src/hotspot/share/interpreter/oopMapCache.cpp +++ b/src/hotspot/share/interpreter/oopMapCache.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -276,26 +276,26 @@ bool OopMapCacheEntry::verify_mask(CellTypeState* vars, CellTypeState* stack, in // Check if map is generated correctly // (Use ?: operator to make sure all 'true' & 'false' are represented exactly the same so we can use == afterwards) - Log(interpreter, oopmap) logv; - LogStream st(logv.trace()); + const bool log = log_is_enabled(Trace, interpreter, oopmap); + LogStream st(Log(interpreter, oopmap)::trace()); - st.print("Locals (%d): ", max_locals); + if (log) st.print("Locals (%d): ", max_locals); for(int i = 0; i < max_locals; i++) { bool v1 = is_oop(i) ? true : false; bool v2 = vars[i].is_reference() ? true : false; assert(v1 == v2, "locals oop mask generation error"); - st.print("%d", v1 ? 1 : 0); + if (log) st.print("%d", v1 ? 1 : 0); } - st.cr(); + if (log) st.cr(); - st.print("Stack (%d): ", stack_top); + if (log) st.print("Stack (%d): ", stack_top); for(int j = 0; j < stack_top; j++) { bool v1 = is_oop(max_locals + j) ? true : false; bool v2 = stack[j].is_reference() ? true : false; assert(v1 == v2, "stack oop mask generation error"); - st.print("%d", v1 ? 1 : 0); + if (log) st.print("%d", v1 ? 1 : 0); } - st.cr(); + if (log) st.cr(); return true; } diff --git a/src/hotspot/share/interpreter/templateInterpreter.cpp b/src/hotspot/share/interpreter/templateInterpreter.cpp index 732c12532f7f28e8f6a2f226241e35ff1c7f85e2..322a21b6aa7832e27c0ea2f78704b96a89ede8f3 100644 --- a/src/hotspot/share/interpreter/templateInterpreter.cpp +++ b/src/hotspot/share/interpreter/templateInterpreter.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -47,7 +47,11 @@ void TemplateInterpreter::initialize_stub() { // allocate interpreter int code_size = InterpreterCodeSize; NOT_PRODUCT(code_size *= 4;) // debug uses extra interpreter code space - _code = new StubQueue(new InterpreterCodeletInterface, code_size, NULL, + // 270+ interpreter codelets are generated and each of them is required to be aligned to + // CodeEntryAlignment twice. So we need additional size due to alignment. + int max_aligned_codelets = 280; + int max_aligned_bytes = max_aligned_codelets * CodeEntryAlignment * 2; + _code = new StubQueue(new InterpreterCodeletInterface, code_size + max_aligned_bytes, NULL, "Interpreter"); } diff --git a/src/hotspot/share/interpreter/templateInterpreterGenerator.cpp b/src/hotspot/share/interpreter/templateInterpreterGenerator.cpp index 8637da2e32d64500e5231df46ea01d3999c3ea7b..c318882dccaebb297b997c24f00e97a06e6dc8f0 100644 --- a/src/hotspot/share/interpreter/templateInterpreterGenerator.cpp +++ b/src/hotspot/share/interpreter/templateInterpreterGenerator.cpp @@ -201,7 +201,9 @@ void TemplateInterpreterGenerator::generate_all() { method_entry(java_lang_math_fmaF ) method_entry(java_lang_math_fmaD ) method_entry(java_lang_ref_reference_get) - +#ifdef AMD64 + method_entry(java_lang_Thread_currentThread) +#endif AbstractInterpreter::initialize_method_handle_entries(); // all native method kinds (must be one contiguous block) @@ -431,6 +433,11 @@ address TemplateInterpreterGenerator::generate_method_entry( : // fall thru case Interpreter::java_util_zip_CRC32C_updateDirectByteBuffer : entry_point = generate_CRC32C_updateBytes_entry(kind); break; +#ifdef AMD64 + case Interpreter::java_lang_Thread_currentThread + : entry_point = generate_currentThread(); break; +#endif + #ifdef IA32 // On x86_32 platforms, a special entry is generated for the following four methods. // On other platforms the normal entry is used to enter these methods. diff --git a/src/hotspot/share/interpreter/templateInterpreterGenerator.hpp b/src/hotspot/share/interpreter/templateInterpreterGenerator.hpp index fcb50cfbe01a6754bc56b36b91059e566c97215c..a5cfb9bbad0fac86d9e34ab5520014c049509ae4 100644 --- a/src/hotspot/share/interpreter/templateInterpreterGenerator.hpp +++ b/src/hotspot/share/interpreter/templateInterpreterGenerator.hpp @@ -94,6 +94,9 @@ class TemplateInterpreterGenerator: public AbstractInterpreterGenerator { address generate_CRC32_update_entry(); address generate_CRC32_updateBytes_entry(AbstractInterpreter::MethodKind kind); address generate_CRC32C_updateBytes_entry(AbstractInterpreter::MethodKind kind); +#ifdef AMD64 + address generate_currentThread(); +#endif #ifdef IA32 address generate_Float_intBitsToFloat_entry(); address generate_Float_floatToRawIntBits_entry(); diff --git a/src/hotspot/share/interpreter/templateTable.hpp b/src/hotspot/share/interpreter/templateTable.hpp index ff5d2c338803de2011a2589b3d2539b8ad7d63e2..e7575eeb40a7f4dbea87955de8735730dfb8bd8f 100644 --- a/src/hotspot/share/interpreter/templateTable.hpp +++ b/src/hotspot/share/interpreter/templateTable.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -26,7 +26,7 @@ #define SHARE_INTERPRETER_TEMPLATETABLE_HPP #include "interpreter/bytecodes.hpp" -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" #include "runtime/frame.hpp" #include "utilities/macros.hpp" diff --git a/src/hotspot/share/interpreter/zero/bytecodeInterpreter.cpp b/src/hotspot/share/interpreter/zero/bytecodeInterpreter.cpp index d8fac577d5927625c30f71f48a76b39c4dde929a..4682c2b8129201e3ef2da800b3b369627c1bc170 100644 --- a/src/hotspot/share/interpreter/zero/bytecodeInterpreter.cpp +++ b/src/hotspot/share/interpreter/zero/bytecodeInterpreter.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 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 @@ -99,6 +99,9 @@ #undef PREFETCH_OPCCODE #define PREFETCH_OPCCODE +JRT_ENTRY(void, at_safepoint(JavaThread* current)) {} +JRT_END + /* Interpreter safepoint: it is expected that the interpreter will have no live handles of its own creation live at an interpreter safepoint. Therefore we @@ -107,12 +110,10 @@ There really shouldn't be any handles remaining to trash but this is cheap in relation to a safepoint. */ -#define RETURN_SAFEPOINT \ - if (SafepointMechanism::should_process(THREAD)) { \ - HandleMarkCleaner __hmc(THREAD); \ - CALL_VM(SafepointMechanism::process_if_requested_with_exit_check(THREAD, true /* check asyncs */), \ - handle_exception); \ - } \ +#define RETURN_SAFEPOINT \ + if (SafepointMechanism::should_process(THREAD)) { \ + CALL_VM(at_safepoint(THREAD), handle_exception); \ + } /* * VM_JAVA_ERROR - Macro for throwing a java exception from @@ -293,6 +294,8 @@ istate->set_bcp(pc+opsize); \ return; +#define REWRITE_AT_PC(val) \ + *pc = val; #define METHOD istate->method() #define GET_METHOD_COUNTERS(res) @@ -389,6 +392,81 @@ if (THREAD->has_pending_exception()) goto label; \ } +#define MAYBE_POST_FIELD_ACCESS(obj) { \ + if (JVMTI_ENABLED) { \ + int* count_addr; \ + /* Check to see if a field modification watch has been set */ \ + /* before we take the time to call into the VM. */ \ + count_addr = (int*)JvmtiExport::get_field_access_count_addr(); \ + if (*count_addr > 0) { \ + oop target; \ + if ((Bytecodes::Code)opcode == Bytecodes::_getstatic) { \ + target = NULL; \ + } else { \ + target = obj; \ + } \ + CALL_VM(InterpreterRuntime::post_field_access(THREAD, \ + target, cache), \ + handle_exception); \ + } \ + } \ +} + +#define MAYBE_POST_FIELD_MODIFICATION(obj) { \ + if (JVMTI_ENABLED) { \ + int* count_addr; \ + /* Check to see if a field modification watch has been set */ \ + /* before we take the time to call into the VM. */ \ + count_addr = (int*)JvmtiExport::get_field_modification_count_addr(); \ + if (*count_addr > 0) { \ + oop target; \ + if ((Bytecodes::Code)opcode == Bytecodes::_putstatic) { \ + target = NULL; \ + } else { \ + target = obj; \ + } \ + CALL_VM(InterpreterRuntime::post_field_modification(THREAD, \ + target, cache, \ + (jvalue*)STACK_SLOT(-1)), \ + handle_exception); \ + } \ + } \ +} + +static inline int fast_get_type(TosState tos) { + switch (tos) { + case ztos: + case btos: return Bytecodes::_fast_bgetfield; + case ctos: return Bytecodes::_fast_cgetfield; + case stos: return Bytecodes::_fast_sgetfield; + case itos: return Bytecodes::_fast_igetfield; + case ltos: return Bytecodes::_fast_lgetfield; + case ftos: return Bytecodes::_fast_fgetfield; + case dtos: return Bytecodes::_fast_dgetfield; + case atos: return Bytecodes::_fast_agetfield; + default: + ShouldNotReachHere(); + return -1; + } +} + +static inline int fast_put_type(TosState tos) { + switch (tos) { + case ztos: return Bytecodes::_fast_zputfield; + case btos: return Bytecodes::_fast_bputfield; + case ctos: return Bytecodes::_fast_cputfield; + case stos: return Bytecodes::_fast_sputfield; + case itos: return Bytecodes::_fast_iputfield; + case ltos: return Bytecodes::_fast_lputfield; + case ftos: return Bytecodes::_fast_fputfield; + case dtos: return Bytecodes::_fast_dputfield; + case atos: return Bytecodes::_fast_aputfield; + default: + ShouldNotReachHere(); + return -1; + } +} + /* * BytecodeInterpreter::run(interpreterState istate) * @@ -397,11 +475,13 @@ * the method passed in. */ -// Instantiate two variants of the method for future linking. -template void BytecodeInterpreter::run(interpreterState istate); -template void BytecodeInterpreter::run(interpreterState istate); +// Instantiate variants of the method for future linking. +template void BytecodeInterpreter::run(interpreterState istate); +template void BytecodeInterpreter::run(interpreterState istate); +template void BytecodeInterpreter::run< true, false>(interpreterState istate); +template void BytecodeInterpreter::run< true, true>(interpreterState istate); -template +template void BytecodeInterpreter::run(interpreterState istate) { intptr_t* topOfStack = (intptr_t *)istate->stack(); /* access with STACK macros */ address pc = istate->bcp(); @@ -497,15 +577,15 @@ void BytecodeInterpreter::run(interpreterState istate) { /* 0xC0 */ &&opc_checkcast, &&opc_instanceof, &&opc_monitorenter, &&opc_monitorexit, /* 0xC4 */ &&opc_wide, &&opc_multianewarray, &&opc_ifnull, &&opc_ifnonnull, -/* 0xC8 */ &&opc_goto_w, &&opc_jsr_w, &&opc_breakpoint, &&opc_default, -/* 0xCC */ &&opc_default, &&opc_default, &&opc_default, &&opc_default, +/* 0xC8 */ &&opc_goto_w, &&opc_jsr_w, &&opc_breakpoint, &&opc_fast_agetfield, +/* 0xCC */ &&opc_fast_bgetfield,&&opc_fast_cgetfield, &&opc_fast_dgetfield, &&opc_fast_fgetfield, -/* 0xD0 */ &&opc_default, &&opc_default, &&opc_default, &&opc_default, -/* 0xD4 */ &&opc_default, &&opc_default, &&opc_default, &&opc_default, -/* 0xD8 */ &&opc_default, &&opc_default, &&opc_default, &&opc_default, -/* 0xDC */ &&opc_default, &&opc_default, &&opc_default, &&opc_default, +/* 0xD0 */ &&opc_fast_igetfield,&&opc_fast_lgetfield, &&opc_fast_sgetfield, &&opc_fast_aputfield, +/* 0xD4 */ &&opc_fast_bputfield,&&opc_fast_zputfield, &&opc_fast_cputfield, &&opc_fast_dputfield, +/* 0xD8 */ &&opc_fast_fputfield,&&opc_fast_iputfield, &&opc_fast_lputfield, &&opc_fast_sputfield, +/* 0xDC */ &&opc_fast_aload_0, &&opc_fast_iaccess_0, &&opc_fast_aaccess_0, &&opc_fast_faccess_0, -/* 0xE0 */ &&opc_default, &&opc_default, &&opc_default, &&opc_default, +/* 0xE0 */ &&opc_fast_iload, &&opc_fast_iload2, &&opc_fast_icaload, &&opc_fast_invokevfinal, /* 0xE4 */ &&opc_default, &&opc_default, &&opc_fast_aldc, &&opc_fast_aldc_w, /* 0xE8 */ &&opc_return_register_finalizer, &&opc_invokehandle, &&opc_default, &&opc_default, @@ -747,10 +827,41 @@ run: UPDATE_PC_AND_TOS_AND_CONTINUE(2, 1); CASE(_iload): + { + if (REWRITE_BYTECODES) { + // Attempt to rewrite iload, iload -> fast_iload2 + // iload, caload -> fast_icaload + // Normal iloads will be rewritten to fast_iload to avoid checking again. + switch (*(pc + 2)) { + case Bytecodes::_fast_iload: + REWRITE_AT_PC(Bytecodes::_fast_iload2); + break; + case Bytecodes::_caload: + REWRITE_AT_PC(Bytecodes::_fast_icaload); + break; + case Bytecodes::_iload: + // Wait until rewritten to _fast_iload. + break; + default: + // Last iload in a (potential) series, don't check again. + REWRITE_AT_PC(Bytecodes::_fast_iload); + } + } + // Normal iload handling. + SET_STACK_SLOT(LOCALS_SLOT(pc[1]), 0); + UPDATE_PC_AND_TOS_AND_CONTINUE(2, 1); + } + + CASE(_fast_iload): CASE(_fload): SET_STACK_SLOT(LOCALS_SLOT(pc[1]), 0); UPDATE_PC_AND_TOS_AND_CONTINUE(2, 1); + CASE(_fast_iload2): + SET_STACK_SLOT(LOCALS_SLOT(pc[1]), 0); + SET_STACK_SLOT(LOCALS_SLOT(pc[3]), 1); + UPDATE_PC_AND_TOS_AND_CONTINUE(4, 2); + CASE(_lload): SET_STACK_LONG_FROM_ADDR(LOCALS_LONG_AT(pc[1]), 1); UPDATE_PC_AND_TOS_AND_CONTINUE(2, 2); @@ -761,11 +872,6 @@ run: #undef OPC_LOAD_n #define OPC_LOAD_n(num) \ - CASE(_aload_##num): \ - VERIFY_OOP(LOCALS_OBJECT(num)); \ - SET_STACK_OBJECT(LOCALS_OBJECT(num), 0); \ - UPDATE_PC_AND_TOS_AND_CONTINUE(1, 1); \ - \ CASE(_iload_##num): \ CASE(_fload_##num): \ SET_STACK_SLOT(LOCALS_SLOT(num), 0); \ @@ -778,10 +884,53 @@ run: SET_STACK_DOUBLE_FROM_ADDR(LOCALS_DOUBLE_AT(num), 1); \ UPDATE_PC_AND_TOS_AND_CONTINUE(1, 2); - OPC_LOAD_n(0); - OPC_LOAD_n(1); - OPC_LOAD_n(2); - OPC_LOAD_n(3); + OPC_LOAD_n(0); + OPC_LOAD_n(1); + OPC_LOAD_n(2); + OPC_LOAD_n(3); + +#undef OPC_ALOAD_n +#define OPC_ALOAD_n(num) \ + CASE(_aload_##num): { \ + oop obj = LOCALS_OBJECT(num); \ + VERIFY_OOP(obj); \ + SET_STACK_OBJECT(obj, 0); \ + UPDATE_PC_AND_TOS_AND_CONTINUE(1, 1); \ + } + + CASE(_aload_0): + { + /* Maybe rewrite if following bytecode is one of the supported _fast_Xgetfield bytecodes. */ + if (REWRITE_BYTECODES) { + switch (*(pc + 1)) { + case Bytecodes::_fast_agetfield: + REWRITE_AT_PC(Bytecodes::_fast_aaccess_0); + break; + case Bytecodes::_fast_fgetfield: + REWRITE_AT_PC(Bytecodes::_fast_faccess_0); + break; + case Bytecodes::_fast_igetfield: + REWRITE_AT_PC(Bytecodes::_fast_iaccess_0); + break; + case Bytecodes::_getfield: { + /* Otherwise, do nothing here, wait until it gets rewritten to _fast_Xgetfield. + * Unfortunately, this punishes volatile field access, because it never gets + * rewritten. */ + break; + } + default: + REWRITE_AT_PC(Bytecodes::_fast_aload_0); + break; + } + } + VERIFY_OOP(LOCALS_OBJECT(0)); + SET_STACK_OBJECT(LOCALS_OBJECT(0), 0); + UPDATE_PC_AND_TOS_AND_CONTINUE(1, 1); + } + + OPC_ALOAD_n(1); + OPC_ALOAD_n(2); + OPC_ALOAD_n(3); /* store to a local variable */ @@ -1313,11 +1462,7 @@ run: /* Array access byte-codes */ - /* Every array access byte-code starts out like this */ -// arrayOopDesc* arrObj = (arrayOopDesc*)STACK_OBJECT(arrayOff); -#define ARRAY_INTRO(arrayOff) \ - arrayOop arrObj = (arrayOop)STACK_OBJECT(arrayOff); \ - jint index = STACK_INT(arrayOff + 1); \ +#define ARRAY_INDEX_CHECK(arrObj, index) \ /* Two integers, the additional message, and the null-terminator */ \ char message[2 * jintAsStringSize + 33]; \ CHECK_NULL(arrObj); \ @@ -1329,6 +1474,13 @@ run: message); \ } + /* Every array access byte-code starts out like this */ +// arrayOopDesc* arrObj = (arrayOopDesc*)STACK_OBJECT(arrayOff); +#define ARRAY_INTRO(arrayOff) \ + arrayOop arrObj = (arrayOop)STACK_OBJECT(arrayOff); \ + jint index = STACK_INT(arrayOff + 1); \ + ARRAY_INDEX_CHECK(arrObj, index) + /* 32-bit loads. These handle conversion from < 32-bit types */ #define ARRAY_LOADTO32(T, T2, format, stackRes, extra) \ { \ @@ -1368,6 +1520,15 @@ run: CASE(_daload): ARRAY_LOADTO64(T_DOUBLE, jdouble, STACK_DOUBLE, 0); + CASE(_fast_icaload): { + // Custom fast access for iload,caload pair. + arrayOop arrObj = (arrayOop) STACK_OBJECT(-1); + jint index = LOCALS_INT(pc[1]); + ARRAY_INDEX_CHECK(arrObj, index); + SET_STACK_INT(*(jchar *)(((address) arrObj->base(T_CHAR)) + index * sizeof(jchar)), -1); + UPDATE_PC_AND_TOS_AND_CONTINUE(3, 0); + } + /* 32-bit stores. These handle conversion to < 32-bit types */ #define ARRAY_STOREFROM32(T, T2, format, stackSrc, extra) \ { \ @@ -1537,26 +1698,6 @@ run: cache = cp->entry_at(index); } - if (JVMTI_ENABLED) { - int *count_addr; - oop obj; - // Check to see if a field modification watch has been set - // before we take the time to call into the VM. - count_addr = (int *)JvmtiExport::get_field_access_count_addr(); - if ( *count_addr > 0 ) { - if ((Bytecodes::Code)opcode == Bytecodes::_getstatic) { - obj = NULL; - } else { - obj = STACK_OBJECT(-1); - VERIFY_OOP(obj); - } - CALL_VM(InterpreterRuntime::post_field_access(THREAD, - obj, - cache), - handle_exception); - } - } - oop obj; if ((Bytecodes::Code)opcode == Bytecodes::_getstatic) { Klass* k = cache->f1_as_klass(); @@ -1565,8 +1706,15 @@ run: } else { obj = STACK_OBJECT(-1); CHECK_NULL(obj); + // Check if we can rewrite non-volatile _getfield to one of the _fast_Xgetfield. + if (REWRITE_BYTECODES && !cache->is_volatile()) { + // Rewrite current BC to _fast_Xgetfield. + REWRITE_AT_PC(fast_get_type(cache->flag_state())); + } } + MAYBE_POST_FIELD_ACCESS(obj); + // // Now store the result on the stack // @@ -1661,33 +1809,6 @@ run: cache = cp->entry_at(index); } - if (JVMTI_ENABLED) { - int *count_addr; - oop obj; - // Check to see if a field modification watch has been set - // before we take the time to call into the VM. - count_addr = (int *)JvmtiExport::get_field_modification_count_addr(); - if ( *count_addr > 0 ) { - if ((Bytecodes::Code)opcode == Bytecodes::_putstatic) { - obj = NULL; - } - else { - if (cache->is_long() || cache->is_double()) { - obj = STACK_OBJECT(-3); - } else { - obj = STACK_OBJECT(-2); - } - VERIFY_OOP(obj); - } - - CALL_VM(InterpreterRuntime::post_field_modification(THREAD, - obj, - cache, - (jvalue *)STACK_SLOT(-1)), - handle_exception); - } - } - // QQQ Need to make this as inlined as possible. Probably need to split all the bytecode cases // out so c++ compiler has a chance for constant prop to fold everything possible away. @@ -1706,8 +1827,16 @@ run: --count; obj = STACK_OBJECT(count); CHECK_NULL(obj); + + // Check if we can rewrite non-volatile _putfield to one of the _fast_Xputfield. + if (REWRITE_BYTECODES && !cache->is_volatile()) { + // Rewrite current BC to _fast_Xputfield. + REWRITE_AT_PC(fast_put_type(cache->flag_state())); + } } + MAYBE_POST_FIELD_MODIFICATION(obj); + // // Now store the result // @@ -1814,12 +1943,12 @@ run: Copy::fill_to_words(result + hdr_size, obj_size - hdr_size, 0); } - oop obj = cast_to_oop(result); + // Initialize header, mirrors MemAllocator. + oopDesc::set_mark(result, markWord::prototype()); + oopDesc::set_klass_gap(result, 0); + oopDesc::release_set_klass(result, ik); - // Initialize header - obj->set_mark(markWord::prototype()); - obj->set_klass_gap(0); - obj->set_klass(ik); + oop obj = cast_to_oop(result); // Must prevent reordering of stores for object initialization // with stores that publish the new object. @@ -2266,6 +2395,10 @@ run: CHECK_NULL(STACK_OBJECT(-(cache->parameter_size()))); if (cache->is_vfinal()) { callee = cache->f2_as_vfinal_method(); + if (REWRITE_BYTECODES) { + // Rewrite to _fast_invokevfinal. + REWRITE_AT_PC(Bytecodes::_fast_invokevfinal); + } } else { // get receiver int parms = cache->parameter_size(); @@ -2400,6 +2533,329 @@ run: goto opcode_switch; } + CASE(_fast_agetfield): { + u2 index = Bytes::get_native_u2(pc+1); + ConstantPoolCacheEntry* cache = cp->entry_at(index); + int field_offset = cache->f2_as_index(); + + oop obj = STACK_OBJECT(-1); + CHECK_NULL(obj); + + MAYBE_POST_FIELD_ACCESS(obj); + + VERIFY_OOP(obj->obj_field(field_offset)); + SET_STACK_OBJECT(obj->obj_field(field_offset), -1); + UPDATE_PC_AND_CONTINUE(3); + } + + CASE(_fast_bgetfield): { + u2 index = Bytes::get_native_u2(pc+1); + ConstantPoolCacheEntry* cache = cp->entry_at(index); + int field_offset = cache->f2_as_index(); + + oop obj = STACK_OBJECT(-1); + CHECK_NULL(obj); + + MAYBE_POST_FIELD_ACCESS(obj); + + SET_STACK_INT(obj->byte_field(field_offset), -1); + UPDATE_PC_AND_CONTINUE(3); + } + + CASE(_fast_cgetfield): { + u2 index = Bytes::get_native_u2(pc+1); + ConstantPoolCacheEntry* cache = cp->entry_at(index); + int field_offset = cache->f2_as_index(); + + oop obj = STACK_OBJECT(-1); + CHECK_NULL(obj); + + MAYBE_POST_FIELD_ACCESS(obj); + + SET_STACK_INT(obj->char_field(field_offset), -1); + UPDATE_PC_AND_CONTINUE(3); + } + + CASE(_fast_dgetfield): { + u2 index = Bytes::get_native_u2(pc+1); + ConstantPoolCacheEntry* cache = cp->entry_at(index); + int field_offset = cache->f2_as_index(); + + oop obj = STACK_OBJECT(-1); + CHECK_NULL(obj); + + MAYBE_POST_FIELD_ACCESS(obj); + + SET_STACK_DOUBLE(obj->double_field(field_offset), 0); + MORE_STACK(1); + UPDATE_PC_AND_CONTINUE(3); + } + + CASE(_fast_fgetfield): { + u2 index = Bytes::get_native_u2(pc+1); + ConstantPoolCacheEntry* cache = cp->entry_at(index); + int field_offset = cache->f2_as_index(); + + oop obj = STACK_OBJECT(-1); + CHECK_NULL(obj); + + MAYBE_POST_FIELD_ACCESS(obj); + + SET_STACK_FLOAT(obj->float_field(field_offset), -1); + UPDATE_PC_AND_CONTINUE(3); + } + + CASE(_fast_igetfield): { + u2 index = Bytes::get_native_u2(pc+1); + ConstantPoolCacheEntry* cache = cp->entry_at(index); + int field_offset = cache->f2_as_index(); + + oop obj = STACK_OBJECT(-1); + CHECK_NULL(obj); + + MAYBE_POST_FIELD_ACCESS(obj); + + SET_STACK_INT(obj->int_field(field_offset), -1); + UPDATE_PC_AND_CONTINUE(3); + } + + CASE(_fast_lgetfield): { + u2 index = Bytes::get_native_u2(pc+1); + ConstantPoolCacheEntry* cache = cp->entry_at(index); + int field_offset = cache->f2_as_index(); + + oop obj = STACK_OBJECT(-1); + CHECK_NULL(obj); + + MAYBE_POST_FIELD_ACCESS(obj); + + SET_STACK_LONG(obj->long_field(field_offset), 0); + MORE_STACK(1); + UPDATE_PC_AND_CONTINUE(3); + } + + CASE(_fast_sgetfield): { + u2 index = Bytes::get_native_u2(pc+1); + ConstantPoolCacheEntry* cache = cp->entry_at(index); + int field_offset = cache->f2_as_index(); + + oop obj = STACK_OBJECT(-1); + CHECK_NULL(obj); + + MAYBE_POST_FIELD_ACCESS(obj); + + SET_STACK_INT(obj->short_field(field_offset), -1); + UPDATE_PC_AND_CONTINUE(3); + } + + CASE(_fast_aputfield): { + u2 index = Bytes::get_native_u2(pc+1); + ConstantPoolCacheEntry* cache = cp->entry_at(index); + + oop obj = STACK_OBJECT(-2); + CHECK_NULL(obj); + + MAYBE_POST_FIELD_MODIFICATION(obj); + + int field_offset = cache->f2_as_index(); + obj->obj_field_put(field_offset, STACK_OBJECT(-1)); + + UPDATE_PC_AND_TOS_AND_CONTINUE(3, -2); + } + + CASE(_fast_bputfield): { + u2 index = Bytes::get_native_u2(pc+1); + ConstantPoolCacheEntry* cache = cp->entry_at(index); + + oop obj = STACK_OBJECT(-2); + CHECK_NULL(obj); + + MAYBE_POST_FIELD_MODIFICATION(obj); + + int field_offset = cache->f2_as_index(); + obj->byte_field_put(field_offset, STACK_INT(-1)); + + UPDATE_PC_AND_TOS_AND_CONTINUE(3, -2); + } + + CASE(_fast_zputfield): { + u2 index = Bytes::get_native_u2(pc+1); + ConstantPoolCacheEntry* cache = cp->entry_at(index); + + oop obj = STACK_OBJECT(-2); + CHECK_NULL(obj); + + MAYBE_POST_FIELD_MODIFICATION(obj); + + int field_offset = cache->f2_as_index(); + obj->byte_field_put(field_offset, (STACK_INT(-1) & 1)); // only store LSB + + UPDATE_PC_AND_TOS_AND_CONTINUE(3, -2); + } + + CASE(_fast_cputfield): { + u2 index = Bytes::get_native_u2(pc+1); + ConstantPoolCacheEntry* cache = cp->entry_at(index); + + oop obj = STACK_OBJECT(-2); + CHECK_NULL(obj); + + MAYBE_POST_FIELD_MODIFICATION(obj); + + int field_offset = cache->f2_as_index(); + obj->char_field_put(field_offset, STACK_INT(-1)); + + UPDATE_PC_AND_TOS_AND_CONTINUE(3, -2); + } + + CASE(_fast_dputfield): { + u2 index = Bytes::get_native_u2(pc+1); + ConstantPoolCacheEntry* cache = cp->entry_at(index); + + oop obj = STACK_OBJECT(-3); + CHECK_NULL(obj); + + MAYBE_POST_FIELD_MODIFICATION(obj); + + int field_offset = cache->f2_as_index(); + obj->double_field_put(field_offset, STACK_DOUBLE(-1)); + + UPDATE_PC_AND_TOS_AND_CONTINUE(3, -3); + } + + CASE(_fast_fputfield): { + u2 index = Bytes::get_native_u2(pc+1); + ConstantPoolCacheEntry* cache = cp->entry_at(index); + + oop obj = STACK_OBJECT(-2); + CHECK_NULL(obj); + + MAYBE_POST_FIELD_MODIFICATION(obj); + + int field_offset = cache->f2_as_index(); + obj->float_field_put(field_offset, STACK_FLOAT(-1)); + + UPDATE_PC_AND_TOS_AND_CONTINUE(3, -2); + } + + CASE(_fast_iputfield): { + u2 index = Bytes::get_native_u2(pc+1); + ConstantPoolCacheEntry* cache = cp->entry_at(index); + + oop obj = STACK_OBJECT(-2); + CHECK_NULL(obj); + + MAYBE_POST_FIELD_MODIFICATION(obj); + + int field_offset = cache->f2_as_index(); + obj->int_field_put(field_offset, STACK_INT(-1)); + + UPDATE_PC_AND_TOS_AND_CONTINUE(3, -2); + } + + CASE(_fast_lputfield): { + u2 index = Bytes::get_native_u2(pc+1); + ConstantPoolCacheEntry* cache = cp->entry_at(index); + + oop obj = STACK_OBJECT(-3); + CHECK_NULL(obj); + + MAYBE_POST_FIELD_MODIFICATION(obj); + + int field_offset = cache->f2_as_index(); + obj->long_field_put(field_offset, STACK_LONG(-1)); + + UPDATE_PC_AND_TOS_AND_CONTINUE(3, -3); + } + + CASE(_fast_sputfield): { + u2 index = Bytes::get_native_u2(pc+1); + ConstantPoolCacheEntry* cache = cp->entry_at(index); + + oop obj = STACK_OBJECT(-2); + CHECK_NULL(obj); + + MAYBE_POST_FIELD_MODIFICATION(obj); + + int field_offset = cache->f2_as_index(); + obj->short_field_put(field_offset, STACK_INT(-1)); + + UPDATE_PC_AND_TOS_AND_CONTINUE(3, -2); + } + + CASE(_fast_aload_0): { + oop obj = LOCALS_OBJECT(0); + VERIFY_OOP(obj); + SET_STACK_OBJECT(obj, 0); + UPDATE_PC_AND_TOS_AND_CONTINUE(1, 1); + } + + CASE(_fast_aaccess_0): { + u2 index = Bytes::get_native_u2(pc+2); + ConstantPoolCacheEntry* cache = cp->entry_at(index); + int field_offset = cache->f2_as_index(); + + oop obj = LOCALS_OBJECT(0); + CHECK_NULL(obj); + VERIFY_OOP(obj); + + MAYBE_POST_FIELD_ACCESS(obj); + + VERIFY_OOP(obj->obj_field(field_offset)); + SET_STACK_OBJECT(obj->obj_field(field_offset), 0); + UPDATE_PC_AND_TOS_AND_CONTINUE(4, 1); + } + + CASE(_fast_iaccess_0): { + u2 index = Bytes::get_native_u2(pc+2); + ConstantPoolCacheEntry* cache = cp->entry_at(index); + int field_offset = cache->f2_as_index(); + + oop obj = LOCALS_OBJECT(0); + CHECK_NULL(obj); + VERIFY_OOP(obj); + + MAYBE_POST_FIELD_ACCESS(obj); + + SET_STACK_INT(obj->int_field(field_offset), 0); + UPDATE_PC_AND_TOS_AND_CONTINUE(4, 1); + } + + CASE(_fast_faccess_0): { + u2 index = Bytes::get_native_u2(pc+2); + ConstantPoolCacheEntry* cache = cp->entry_at(index); + int field_offset = cache->f2_as_index(); + + oop obj = LOCALS_OBJECT(0); + CHECK_NULL(obj); + VERIFY_OOP(obj); + + MAYBE_POST_FIELD_ACCESS(obj); + + SET_STACK_FLOAT(obj->float_field(field_offset), 0); + UPDATE_PC_AND_TOS_AND_CONTINUE(4, 1); + } + + CASE(_fast_invokevfinal): { + u2 index = Bytes::get_native_u2(pc+1); + ConstantPoolCacheEntry* cache = cp->entry_at(index); + + assert(cache->is_resolved(Bytecodes::_invokevirtual), "Should be resolved before rewriting"); + + istate->set_msg(call_method); + + CHECK_NULL(STACK_OBJECT(-(cache->parameter_size()))); + Method* callee = cache->f2_as_vfinal_method(); + istate->set_callee(callee); + if (JVMTI_ENABLED && THREAD->is_interp_only_mode()) { + istate->set_callee_entry_point(callee->interpreter_entry()); + } else { + istate->set_callee_entry_point(callee->from_interpreted_entry()); + } + istate->set_bcp_advance(3); + UPDATE_PC_AND_RETURN(0); + } + DEFAULT: fatal("Unimplemented opcode %d = %s", opcode, Bytecodes::name((Bytecodes::Code)opcode)); diff --git a/src/hotspot/share/interpreter/zero/bytecodeInterpreter.hpp b/src/hotspot/share/interpreter/zero/bytecodeInterpreter.hpp index e4a09d492bd6852a40528f31c4aa6ae17fff43b8..9941055bfd41838fe6bb9a54a1f42d5fb74d60f7 100644 --- a/src/hotspot/share/interpreter/zero/bytecodeInterpreter.hpp +++ b/src/hotspot/share/interpreter/zero/bytecodeInterpreter.hpp @@ -503,7 +503,7 @@ static void dup2_x1(intptr_t *tos); /* insert top 2 slots three down */ static void dup2_x2(intptr_t *tos); /* insert top 2 slots four down */ static void swap(intptr_t *tos); /* swap top two elements */ -template +template static void run(interpreterState istate); static void astore(intptr_t* topOfStack, int stack_offset, diff --git a/src/hotspot/share/jfr/dcmd/jfrDcmds.cpp b/src/hotspot/share/jfr/dcmd/jfrDcmds.cpp index 9763ed62b76cc3c3e06bc2890b6fc405b9a4c248..9b29553665716b08c51c884baee414a3f20532df 100644 --- a/src/hotspot/share/jfr/dcmd/jfrDcmds.cpp +++ b/src/hotspot/share/jfr/dcmd/jfrDcmds.cpp @@ -388,12 +388,12 @@ void JfrConfigureFlightRecorderDCmd::print_help(const char* name) const { out->print_cr(" been initalized. (STRING, default determined by the value for"); out->print_cr(" memorysize)"); out->print_cr(""); - out->print_cr(" maxchunksize (Optional) Maximum size of an individual data chunk in bytes if"); + out->print_cr(" maxchunksize (Optional) Maximum size of an individual data chunk in bytes if"); out->print_cr(" one of the following suffixes is not used: 'm' or 'M' for"); out->print_cr(" megabytes OR 'g' or 'G' for gigabytes. This value cannot be"); out->print_cr(" changed once JFR has been initialized. (STRING, 12M)"); out->print_cr(""); - out->print_cr(" memorysize (Optional) Overall memory size, in bytes if one of the following"); + out->print_cr(" memorysize (Optional) Overall memory size, in bytes if one of the following"); out->print_cr(" suffixes is not used: 'm' or 'M' for megabytes OR 'g' or 'G' for"); out->print_cr(" gigabytes. This value cannot be changed once JFR has been"); out->print_cr(" initialized. (STRING, 10M)"); @@ -403,7 +403,11 @@ void JfrConfigureFlightRecorderDCmd::print_help(const char* name) const { out->print_cr(" location is the temporary directory for the operating system. On"); out->print_cr(" Linux operating systems, the temporary directory is /tmp. On"); out->print_cr(" Windows, the temporary directory is specified by the TMP"); - out->print_cr(" environment variable.)"); + out->print_cr(" environment variable)"); + out->print_cr(""); + out->print_cr(" dumppath (Optional) Path to the location where a recording file is written"); + out->print_cr(" in case the VM runs into a critical error, such as a system"); + out->print_cr(" crash. (STRING, The default location is the current directory)"); out->print_cr(""); out->print_cr(" stackdepth (Optional) Stack depth for stack traces. Setting this value"); out->print_cr(" greater than the default of 64 may cause a performance"); @@ -416,8 +420,6 @@ void JfrConfigureFlightRecorderDCmd::print_help(const char* name) const { out->print_cr(" performance and is not recommended. This value cannot be changed"); out->print_cr(" once JFR has been initialized. (STRING, 8k)"); out->print_cr(""); - out->print_cr(" samplethreads (Optional) Flag for activating thread sampling. (BOOLEAN, true)"); - out->print_cr(""); out->print_cr("Options must be specified using the or = syntax."); out->print_cr(""); out->print_cr("Example usage:"); @@ -467,45 +469,47 @@ void JfrConfigureFlightRecorderDCmd::execute(DCmdSource source, TRAPS) { } jobject stack_depth = NULL; - if (_stack_depth.is_set()) { - stack_depth = JfrJavaSupport::new_java_lang_Integer((jint)_stack_depth.value(), CHECK); - } - jobject global_buffer_count = NULL; - if (_global_buffer_count.is_set()) { - global_buffer_count = JfrJavaSupport::new_java_lang_Long(_global_buffer_count.value(), CHECK); - } - jobject global_buffer_size = NULL; - if (_global_buffer_size.is_set()) { - global_buffer_size = JfrJavaSupport::new_java_lang_Long(_global_buffer_size.value()._size, CHECK); - } - jobject thread_buffer_size = NULL; - if (_thread_buffer_size.is_set()) { - thread_buffer_size = JfrJavaSupport::new_java_lang_Long(_thread_buffer_size.value()._size, CHECK); - } - jobject max_chunk_size = NULL; - if (_max_chunk_size.is_set()) { - max_chunk_size = JfrJavaSupport::new_java_lang_Long(_max_chunk_size.value()._size, CHECK); - } - jobject memory_size = NULL; - if (_memory_size.is_set()) { - memory_size = JfrJavaSupport::new_java_lang_Long(_memory_size.value()._size, CHECK); - } - jobject sample_threads = NULL; - if (_sample_threads.is_set()) { - sample_threads = JfrJavaSupport::new_java_lang_Boolean(_sample_threads.value(), CHECK); + if (!JfrRecorder::is_created()) { + if (_stack_depth.is_set()) { + stack_depth = JfrJavaSupport::new_java_lang_Integer((jint)_stack_depth.value(), CHECK); + } + if (_global_buffer_count.is_set()) { + global_buffer_count = JfrJavaSupport::new_java_lang_Long(_global_buffer_count.value(), CHECK); + } + if (_global_buffer_size.is_set()) { + global_buffer_size = JfrJavaSupport::new_java_lang_Long(_global_buffer_size.value()._size, CHECK); + } + if (_thread_buffer_size.is_set()) { + thread_buffer_size = JfrJavaSupport::new_java_lang_Long(_thread_buffer_size.value()._size, CHECK); + } + if (_max_chunk_size.is_set()) { + max_chunk_size = JfrJavaSupport::new_java_lang_Long(_max_chunk_size.value()._size, CHECK); + } + if (_memory_size.is_set()) { + memory_size = JfrJavaSupport::new_java_lang_Long(_memory_size.value()._size, CHECK); + } + if (_sample_threads.is_set()) { + bool startup = DCmd_Source_Internal == source; + if (startup) { + log_warning(jfr,startup)("%s", "Option samplethreads is deprecated. Use -XX:StartFlightRecording:method-profiling="); + } else { + output()->print_cr("%s", "Option samplethreads is deprecated. Use JFR.start method-profiling="); + output()->print_cr(""); + } + } } static const char klass[] = "jdk/jfr/internal/dcmd/DCmdConfigure"; static const char method[] = "execute"; static const char signature[] = "(ZLjava/lang/String;Ljava/lang/String;Ljava/lang/Integer;" "Ljava/lang/Long;Ljava/lang/Long;Ljava/lang/Long;Ljava/lang/Long;" - "Ljava/lang/Long;Ljava/lang/Boolean;)[Ljava/lang/String;"; + "Ljava/lang/Long;)[Ljava/lang/String;"; JfrJavaArguments execute_args(&result, klass, method, signature, CHECK); execute_args.set_receiver(h_dcmd_instance); @@ -520,7 +524,6 @@ void JfrConfigureFlightRecorderDCmd::execute(DCmdSource source, TRAPS) { execute_args.push_jobject(thread_buffer_size); execute_args.push_jobject(memory_size); execute_args.push_jobject(max_chunk_size); - execute_args.push_jobject(sample_threads); JfrJavaSupport::call_virtual(&execute_args, THREAD); handle_dcmd_result(output(), result.get_oop(), source, THREAD); diff --git a/src/hotspot/share/jfr/instrumentation/jfrEventClassTransformer.hpp b/src/hotspot/share/jfr/instrumentation/jfrEventClassTransformer.hpp index d34a4e57a78a0306726a54f35cf67f5a35087453..939c02bfdf4c113970d5b37293b01d1ec5dbd3e5 100644 --- a/src/hotspot/share/jfr/instrumentation/jfrEventClassTransformer.hpp +++ b/src/hotspot/share/jfr/instrumentation/jfrEventClassTransformer.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -25,7 +25,7 @@ #ifndef SHARE_JFR_INSTRUMENTATION_JFREVENTCLASSTRANSFORMER_HPP #define SHARE_JFR_INSTRUMENTATION_JFREVENTCLASSTRANSFORMER_HPP -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" #include "utilities/exceptions.hpp" class ClassFileParser; diff --git a/src/hotspot/share/jfr/jfr.hpp b/src/hotspot/share/jfr/jfr.hpp index c97cc807c3b7c2b0719b29874f248f656cf4b356..b4b1ae78adc78cd15ff37d4e8144f96ec833828e 100644 --- a/src/hotspot/share/jfr/jfr.hpp +++ b/src/hotspot/share/jfr/jfr.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -26,11 +26,13 @@ #define SHARE_JFR_JFR_HPP #include "jni.h" -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" +#include "utilities/globalDefinitions.hpp" class JavaThread; class Thread; class Klass; +class outputStream; extern "C" void JNICALL jfr_register_natives(JNIEnv*, jclass); diff --git a/src/hotspot/share/jfr/jni/jfrJavaSupport.cpp b/src/hotspot/share/jfr/jni/jfrJavaSupport.cpp index 5b7891ab45c8ed91077497a656e2cbdd09b6f523..ff15a68753d29a4ccdf01bb2d016ecab785ffc08 100644 --- a/src/hotspot/share/jfr/jni/jfrJavaSupport.cpp +++ b/src/hotspot/share/jfr/jni/jfrJavaSupport.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -554,14 +554,16 @@ void JfrJavaSupport::throw_runtime_exception(const char* message, TRAPS) { void JfrJavaSupport::abort(jstring errorMsg, JavaThread* t) { DEBUG_ONLY(check_java_thread_in_vm(t)); - ResourceMark rm(t); - const char* const error_msg = c_str(errorMsg, t); - if (error_msg != NULL) { - log_error(jfr, system)("%s",error_msg); + abort(c_str(errorMsg, t)); +} + +void JfrJavaSupport::abort(const char* error_msg, bool dump_core /* true */) { + if (error_msg != nullptr) { + log_error(jfr, system)("%s", error_msg); } log_error(jfr, system)("%s", "An irrecoverable error in Jfr. Shutting down VM..."); - vm_abort(); + vm_abort(dump_core); } JfrJavaSupport::CAUSE JfrJavaSupport::_cause = JfrJavaSupport::VM_ERROR; diff --git a/src/hotspot/share/jfr/jni/jfrJavaSupport.hpp b/src/hotspot/share/jfr/jni/jfrJavaSupport.hpp index ca97d90dd78a0ef52d7be251bf6ff6f8ce388d80..ee608387c519ce68de5ab259d800b0a8d9b872e2 100644 --- a/src/hotspot/share/jfr/jni/jfrJavaSupport.hpp +++ b/src/hotspot/share/jfr/jni/jfrJavaSupport.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -101,6 +101,7 @@ class JfrJavaSupport : public AllStatic { // critical static void abort(jstring errorMsg, TRAPS); + static void abort(const char* error_msg, bool dump_core = true); static void uncaught_exception(jthrowable throwable, JavaThread* t); // asserts diff --git a/src/hotspot/share/jfr/jni/jfrJniMethod.cpp b/src/hotspot/share/jfr/jni/jfrJniMethod.cpp index 54a4680ced84b0dbf67d8a4e8f67400f4ebed6ba..afbfaec6a96f5129d97e3037eca2b66ff76192d7 100644 --- a/src/hotspot/share/jfr/jni/jfrJniMethod.cpp +++ b/src/hotspot/share/jfr/jni/jfrJniMethod.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -35,6 +35,7 @@ #include "jfr/recorder/repository/jfrRepository.hpp" #include "jfr/recorder/repository/jfrChunkRotation.hpp" #include "jfr/recorder/repository/jfrChunkWriter.hpp" +#include "jfr/recorder/repository/jfrEmergencyDump.hpp" #include "jfr/recorder/service/jfrEventThrottler.hpp" #include "jfr/recorder/service/jfrOptionSet.hpp" #include "jfr/recorder/stacktrace/jfrStackTraceRepository.hpp" @@ -120,10 +121,6 @@ NO_TRANSITION(void, jfr_set_file_notification(JNIEnv* env, jobject jvm, jlong th JfrChunkRotation::set_threshold(threshold); NO_TRANSITION_END -NO_TRANSITION(void, jfr_set_sample_threads(JNIEnv* env, jobject jvm, jboolean sampleThreads)) - JfrOptionSet::set_sample_threads(sampleThreads); -NO_TRANSITION_END - NO_TRANSITION(void, jfr_set_stack_depth(JNIEnv* env, jobject jvm, jint depth)) JfrOptionSet::set_stackdepth((jlong)depth); NO_TRANSITION_END @@ -315,6 +312,20 @@ JVM_ENTRY_NO_ENV(void, jfr_set_repository_location(JNIEnv* env, jobject repo, js return JfrRepository::set_path(location, thread); JVM_END +NO_TRANSITION(void, jfr_set_dump_path(JNIEnv* env, jobject jvm, jstring dumppath)) + if (dumppath == NULL) { + JfrEmergencyDump::set_dump_path(NULL); + } else { + const char* dump_path = env->GetStringUTFChars(dumppath, NULL); + JfrEmergencyDump::set_dump_path(dump_path); + env->ReleaseStringUTFChars(dumppath, dump_path); + } +NO_TRANSITION_END + +NO_TRANSITION(jstring, jfr_get_dump_path(JNIEnv* env, jobject jvm)) + return env->NewStringUTF(JfrEmergencyDump::get_dump_path()); +NO_TRANSITION_END + JVM_ENTRY_NO_ENV(void, jfr_uncaught_exception(JNIEnv* env, jobject jvm, jobject t, jthrowable throwable)) JfrJavaSupport::uncaught_exception(throwable, thread); JVM_END diff --git a/src/hotspot/share/jfr/jni/jfrJniMethod.hpp b/src/hotspot/share/jfr/jni/jfrJniMethod.hpp index 19a676c4a22b91fd37f701c1a1803b9937cbe7d4..49286eed76f9d8951c52411ea71e39754efd834e 100644 --- a/src/hotspot/share/jfr/jni/jfrJniMethod.hpp +++ b/src/hotspot/share/jfr/jni/jfrJniMethod.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -87,8 +87,6 @@ void JNICALL jfr_set_method_sampling_interval(JNIEnv* env, jobject jvm, jlong ty void JNICALL jfr_set_output(JNIEnv* env, jobject jvm, jstring path); -void JNICALL jfr_set_sample_threads(JNIEnv* env, jobject jvm, jboolean sampleThreads); - void JNICALL jfr_set_stack_depth(JNIEnv* env, jobject jvm, jint depth); void JNICALL jfr_set_stacktrace_enabled(JNIEnv* env, jobject jvm, jlong event_type_id, jboolean enabled); @@ -113,6 +111,10 @@ jlong JNICALL jfr_type_id(JNIEnv* env, jobject jvm, jclass jc); void JNICALL jfr_set_repository_location(JNIEnv* env, jobject repo, jstring location); +void JNICALL jfr_set_dump_path(JNIEnv* env, jobject jvm, jstring dumppath); + +jstring JNICALL jfr_get_dump_path(JNIEnv* env, jobject jvm); + jobject JNICALL jfr_get_event_writer(JNIEnv* env, jclass cls); jobject JNICALL jfr_new_event_writer(JNIEnv* env, jclass cls); diff --git a/src/hotspot/share/jfr/jni/jfrJniMethodRegistration.cpp b/src/hotspot/share/jfr/jni/jfrJniMethodRegistration.cpp index db137776f654429bc06524da936acb0ad0cc6b5c..d71e2b4f25ac924d3568f974af00d4ad9a798c9c 100644 --- a/src/hotspot/share/jfr/jni/jfrJniMethodRegistration.cpp +++ b/src/hotspot/share/jfr/jni/jfrJniMethodRegistration.cpp @@ -59,7 +59,6 @@ JfrJniMethodRegistration::JfrJniMethodRegistration(JNIEnv* env) { (char*)"setGlobalBufferSize", (char*)"(J)V", (void*)jfr_set_global_buffer_size, (char*)"setMethodSamplingInterval", (char*)"(JJ)V", (void*)jfr_set_method_sampling_interval, (char*)"setOutput", (char*)"(Ljava/lang/String;)V", (void*)jfr_set_output, - (char*)"setSampleThreads", (char*)"(Z)V", (void*)jfr_set_sample_threads, (char*)"setStackDepth", (char*)"(I)V", (void*)jfr_set_stack_depth, (char*)"setStackTraceEnabled", (char*)"(JZ)V", (void*)jfr_set_stacktrace_enabled, (char*)"setThreadBufferSize", (char*)"(J)V", (void*)jfr_set_thread_buffer_size, @@ -75,6 +74,8 @@ JfrJniMethodRegistration::JfrJniMethodRegistration(JNIEnv* env) { (char*)"flush", (char*)"(Ljdk/jfr/internal/EventWriter;II)Z", (void*)jfr_event_writer_flush, (char*)"flush", (char*)"()V", (void*)jfr_flush, (char*)"setRepositoryLocation", (char*)"(Ljava/lang/String;)V", (void*)jfr_set_repository_location, + (char*)"setDumpPath", (char*)"(Ljava/lang/String;)V", (void*)jfr_set_dump_path, + (char*)"getDumpPath", (char*)"()Ljava/lang/String;", (void*)jfr_get_dump_path, (char*)"abort", (char*)"(Ljava/lang/String;)V", (void*)jfr_abort, (char*)"addStringConstant", (char*)"(JLjava/lang/String;)Z", (void*)jfr_add_string_constant, (char*)"uncaughtException", (char*)"(Ljava/lang/Thread;Ljava/lang/Throwable;)V", (void*)jfr_uncaught_exception, diff --git a/src/hotspot/share/jfr/jni/jfrUpcalls.cpp b/src/hotspot/share/jfr/jni/jfrUpcalls.cpp index e8b846d6021f25951b4288ba3f12e719fdc15d10..2040a34a6fae3eba707cbdfe0d9dde5cc19f7591 100644 --- a/src/hotspot/share/jfr/jni/jfrUpcalls.cpp +++ b/src/hotspot/share/jfr/jni/jfrUpcalls.cpp @@ -32,6 +32,7 @@ #include "jfr/support/jfrJdkJfrEvent.hpp" #include "logging/log.hpp" #include "memory/oopFactory.hpp" +#include "memory/resourceArea.hpp" #include "oops/oop.inline.hpp" #include "oops/typeArrayKlass.hpp" #include "oops/typeArrayOop.inline.hpp" @@ -45,6 +46,8 @@ static Symbol* on_retransform_method_sym = NULL; static Symbol* on_retransform_signature_sym = NULL; static Symbol* bytes_for_eager_instrumentation_sym = NULL; static Symbol* bytes_for_eager_instrumentation_sig_sym = NULL; +static Symbol* unhide_internal_types_sym = NULL; +static Symbol* unhide_internal_types_sig_sym = NULL; static bool initialize(TRAPS) { static bool initialized = false; @@ -55,7 +58,9 @@ static bool initialize(TRAPS) { on_retransform_signature_sym = SymbolTable::new_permanent_symbol("(JZLjava/lang/Class;[B)[B"); bytes_for_eager_instrumentation_sym = SymbolTable::new_permanent_symbol("bytesForEagerInstrumentation"); bytes_for_eager_instrumentation_sig_sym = SymbolTable::new_permanent_symbol("(JZLjava/lang/Class;[B)[B"); - initialized = bytes_for_eager_instrumentation_sig_sym != NULL; + unhide_internal_types_sym = SymbolTable::new_permanent_symbol("unhideInternalTypes"); + unhide_internal_types_sig_sym = SymbolTable::new_permanent_symbol("()V"); + initialized = unhide_internal_types_sig_sym != NULL; } return initialized; } @@ -82,7 +87,8 @@ static const typeArrayOop invoke(jlong trace_id, args.push_oop(old_byte_array); JfrJavaSupport::call_static(&args, THREAD); if (HAS_PENDING_EXCEPTION) { - log_error(jfr, system)("JfrUpcall failed"); + ResourceMark rm(THREAD); + log_error(jfr, system)("JfrUpcall failed for %s", method_sym->as_C_string()); return NULL; } // The result should be a [B @@ -179,3 +185,19 @@ void JfrUpcalls::new_bytes_eager_instrumentation(jlong trace_id, *new_class_data_len = new_bytes_length; *new_class_data = new_bytes; } + +bool JfrUpcalls::unhide_internal_types(TRAPS) { + DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD)); + JavaValue result(T_VOID); + const Klass* klass = SystemDictionary::resolve_or_fail(jvm_upcalls_class_sym, true, CHECK_false); + assert(klass != NULL, "invariant"); + JfrJavaArguments args(&result, klass, unhide_internal_types_sym, unhide_internal_types_sig_sym); + JfrJavaSupport::call_static(&args, THREAD); + if (HAS_PENDING_EXCEPTION) { + CLEAR_PENDING_EXCEPTION; + ResourceMark rm(THREAD); + log_error(jfr, system)("JfrUpcall failed for %s", unhide_internal_types_sym->as_C_string()); + return false; + } + return true; +} diff --git a/src/hotspot/share/jfr/jni/jfrUpcalls.hpp b/src/hotspot/share/jfr/jni/jfrUpcalls.hpp index 0bfe7074b4c4cdf7abf43d9d6f7a258dabaf2bd2..cefda39bf6b3b324877af713f7192089183a3b72 100644 --- a/src/hotspot/share/jfr/jni/jfrUpcalls.hpp +++ b/src/hotspot/share/jfr/jni/jfrUpcalls.hpp @@ -53,6 +53,8 @@ class JfrUpcalls : AllStatic { jint* new_class_data_len, unsigned char** new_class_data, TRAPS); + + static bool unhide_internal_types(TRAPS); }; #endif // SHARE_JFR_JNI_JFRUPCALLS_HPP diff --git a/src/hotspot/share/jfr/leakprofiler/chains/dfsClosure.cpp b/src/hotspot/share/jfr/leakprofiler/chains/dfsClosure.cpp index 8161e172215f4c591cfb9a19624f6da331f06a5e..c6d368a90204282cc6ba74cc9c92fd0c663aac8d 100644 --- a/src/hotspot/share/jfr/leakprofiler/chains/dfsClosure.cpp +++ b/src/hotspot/share/jfr/leakprofiler/chains/dfsClosure.cpp @@ -80,24 +80,23 @@ void DFSClosure::closure_impl(UnifiedOopRef reference, const oop pointee) { if (GranularTimer::is_finished()) { return; } + if (_depth == 0 && _ignore_root_set) { // Root set is already marked, but we want // to continue, so skip is_marked check. assert(_mark_bits->is_marked(pointee), "invariant"); - } else { + _reference_stack[_depth] = reference; + } else { if (_mark_bits->is_marked(pointee)) { return; } + _mark_bits->mark_obj(pointee); + _reference_stack[_depth] = reference; + // is the pointee a sample object? + if (pointee->mark().is_marked()) { + add_chain(); + } } - _reference_stack[_depth] = reference; - _mark_bits->mark_obj(pointee); - assert(_mark_bits->is_marked(pointee), "invariant"); - - // is the pointee a sample object? - if (pointee->mark().is_marked()) { - add_chain(); - } - assert(_max_depth >= 1, "invariant"); if (_depth < _max_depth - 1) { _depth++; diff --git a/src/hotspot/share/jfr/leakprofiler/chains/edgeStore.cpp b/src/hotspot/share/jfr/leakprofiler/chains/edgeStore.cpp index 8ba9409df56406d6fd923efc23e5d6e6336a4e07..c9bee7d1ab6d5147b4710545454be68821df7779 100644 --- a/src/hotspot/share/jfr/leakprofiler/chains/edgeStore.cpp +++ b/src/hotspot/share/jfr/leakprofiler/chains/edgeStore.cpp @@ -234,7 +234,15 @@ static int leak_context_edge_idx(const ObjectSample* sample) { } bool EdgeStore::has_leak_context(const ObjectSample* sample) const { - return leak_context_edge_idx(sample) != 0; + const int idx = leak_context_edge_idx(sample); + if (idx == 0) { + return false; + } + assert(idx > 0, "invariant"); + assert(_leak_context_edges != nullptr, "invariant"); + assert(idx < _leak_context_edges->length(), "invariant"); + assert(_leak_context_edges->at(idx) != nullptr, "invariant"); + return true; } const StoredEdge* EdgeStore::get(const ObjectSample* sample) const { @@ -243,7 +251,10 @@ const StoredEdge* EdgeStore::get(const ObjectSample* sample) const { assert(SafepointSynchronize::is_at_safepoint(), "invariant"); const int idx = leak_context_edge_idx(sample); if (idx > 0) { - return _leak_context_edges->at(idx); + assert(idx < _leak_context_edges->length(), "invariant"); + const StoredEdge* const edge =_leak_context_edges->at(idx); + assert(edge != nullptr, "invariant"); + return edge; } } return get(UnifiedOopRef::encode_in_native(sample->object_addr())); diff --git a/src/hotspot/share/jfr/leakprofiler/chains/edgeUtils.hpp b/src/hotspot/share/jfr/leakprofiler/chains/edgeUtils.hpp index c9a169e6edb53cc6f8d3567927595fabea62495d..0f107e7c32e2568806e5cc1be7a2f34916feebec 100644 --- a/src/hotspot/share/jfr/leakprofiler/chains/edgeUtils.hpp +++ b/src/hotspot/share/jfr/leakprofiler/chains/edgeUtils.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -25,7 +25,7 @@ #ifndef SHARE_JFR_LEAKPROFILER_CHAINS_EDGEUTILS_HPP #define SHARE_JFR_LEAKPROFILER_CHAINS_EDGEUTILS_HPP -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" class Edge; class Symbol; diff --git a/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleCheckpoint.hpp b/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleCheckpoint.hpp index 0ed82fd55c828ff949e8d76ac784e9a3b5a2452d..f9f928699e226e51ea9b6afff1a1ece6bc84a468 100644 --- a/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleCheckpoint.hpp +++ b/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleCheckpoint.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -25,7 +25,7 @@ #ifndef SHARE_JFR_LEAKPROFILER_CHECKPOINT_OBJECTSAMPLECHECKPOINT_HPP #define SHARE_JFR_LEAKPROFILER_CHECKPOINT_OBJECTSAMPLECHECKPOINT_HPP -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" #include "jfr/utilities/jfrTypes.hpp" class EdgeStore; diff --git a/src/hotspot/share/jfr/leakprofiler/checkpoint/rootResolver.hpp b/src/hotspot/share/jfr/leakprofiler/checkpoint/rootResolver.hpp index 63dca4afc72a1a0e52a3f0d989fac2dc04341080..279cb5032ff626e4ed1580be4e7c305940f39cfc 100644 --- a/src/hotspot/share/jfr/leakprofiler/checkpoint/rootResolver.hpp +++ b/src/hotspot/share/jfr/leakprofiler/checkpoint/rootResolver.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -27,7 +27,7 @@ #include "jfr/leakprofiler/utilities/rootType.hpp" #include "jfr/leakprofiler/utilities/unifiedOopRef.hpp" -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" #include "oops/oopsHierarchy.hpp" struct RootCallbackInfo { diff --git a/src/hotspot/share/jfr/leakprofiler/leakProfiler.hpp b/src/hotspot/share/jfr/leakprofiler/leakProfiler.hpp index c541ff1086db4c519e2ec3de694e5f43a5fcfec9..6290a10ff748b5401436c7c63dec60a6a128870a 100644 --- a/src/hotspot/share/jfr/leakprofiler/leakProfiler.hpp +++ b/src/hotspot/share/jfr/leakprofiler/leakProfiler.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -25,7 +25,8 @@ #ifndef SHARE_JFR_LEAKPROFILER_LEAKPROFILER_HPP #define SHARE_JFR_LEAKPROFILER_LEAKPROFILER_HPP -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" +#include "utilities/globalDefinitions.hpp" class JavaThread; diff --git a/src/hotspot/share/jfr/leakprofiler/utilities/granularTimer.hpp b/src/hotspot/share/jfr/leakprofiler/utilities/granularTimer.hpp index 231c1b26df4764bd1fc5284a1a734f8088cbe36e..e42a815c10d21cd4f023c1e79e6a4f187c306089 100644 --- a/src/hotspot/share/jfr/leakprofiler/utilities/granularTimer.hpp +++ b/src/hotspot/share/jfr/leakprofiler/utilities/granularTimer.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -26,7 +26,7 @@ #define SHARE_JFR_LEAKPROFILER_UTILITIES_GRANULARTIMER_HPP #include "jfr/utilities/jfrTime.hpp" -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" class GranularTimer : public AllStatic { private: diff --git a/src/hotspot/share/jfr/leakprofiler/utilities/rootType.hpp b/src/hotspot/share/jfr/leakprofiler/utilities/rootType.hpp index ffc47c7b83391f80f953eeb9b3b20cc64cac3a33..ce975e9b802a34a0140cea166dad9e0ac10a5808 100644 --- a/src/hotspot/share/jfr/leakprofiler/utilities/rootType.hpp +++ b/src/hotspot/share/jfr/leakprofiler/utilities/rootType.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -26,7 +26,7 @@ #define SHARE_JFR_LEAKPROFILER_UTILITIES_ROOTTYPE_HPP #include "gc/shared/oopStorageSet.hpp" -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" #include "utilities/enumIterator.hpp" class OldObjectRoot : public AllStatic { diff --git a/src/hotspot/share/jfr/metadata/metadata.xml b/src/hotspot/share/jfr/metadata/metadata.xml index 6a1f426785c9d692d132a89d0dc1d4e2e38f6aab..0b17b5da71548b89858225189b7cd57262824d4e 100644 --- a/src/hotspot/share/jfr/metadata/metadata.xml +++ b/src/hotspot/share/jfr/metadata/metadata.xml @@ -26,6 +26,55 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/hotspot/share/jfr/metadata/metadata.xsd b/src/hotspot/share/jfr/metadata/metadata.xsd index 017307e38473087562db1e2f327309adfa03d3f5..95aa2b94e8cc7d731686d23752f8c7f086239dbd 100644 --- a/src/hotspot/share/jfr/metadata/metadata.xsd +++ b/src/hotspot/share/jfr/metadata/metadata.xsd @@ -1,4 +1,4 @@ - + " PTR_FORMAT, size, p2i(ptr)); - breakpoint(); - } - if (paranoid) { - verify_memory(ptr); - } -#endif + void* const inner_ptr = MemTracker::record_malloc((address)outer_ptr, size, memflags, stack); - // we do not track guard memory - return MemTracker::record_malloc((address)ptr, size, memflags, stack, level); + if (DumpSharedSpaces) { + // Need to deterministically fill all the alignment gaps in C++ structures. + ::memset(inner_ptr, 0, size); + } else { + DEBUG_ONLY(::memset(inner_ptr, uninitBlockPad, size);) + } + DEBUG_ONLY(break_if_ptr_caught(inner_ptr);) + return inner_ptr; } void* os::realloc(void *memblock, size_t size, MEMFLAGS flags) { @@ -715,91 +676,62 @@ void* os::realloc(void *memblock, size_t size, MEMFLAGS flags) { void* os::realloc(void *memblock, size_t size, MEMFLAGS memflags, const NativeCallStack& stack) { -#if INCLUDE_NMT - { - void* rc = NULL; - if (NMTPreInit::handle_realloc(&rc, memblock, size)) { - return rc; - } + // Special handling for NMT preinit phase before arguments are parsed + void* rc = NULL; + if (NMTPreInit::handle_realloc(&rc, memblock, size)) { + return rc; } -#endif + + if (memblock == NULL) { + return os::malloc(size, memflags, stack); + } + + DEBUG_ONLY(check_crash_protection()); + + // On realloc(p, 0), implementators of realloc(3) have the choice to return either + // NULL or a unique non-NULL pointer. To unify libc behavior across our platforms + // we chose the latter. + size = MAX2((size_t)1, size); // For the test flag -XX:MallocMaxTestWords if (has_reached_max_malloc_test_peak(size)) { return NULL; } - if (size == 0) { - // return a valid pointer if size is zero - // if NULL is returned the calling functions assume out of memory. - size = 1; - } + const size_t new_outer_size = size + MemTracker::overhead_per_malloc(); -#ifndef ASSERT - NOT_PRODUCT(inc_stat_counter(&num_mallocs, 1)); - NOT_PRODUCT(inc_stat_counter(&alloc_bytes, size)); - // NMT support - NMT_TrackingLevel level = MemTracker::tracking_level(); - void* membase = MemTracker::record_free(memblock, level); - size_t nmt_header_size = MemTracker::malloc_header_size(level); - void* ptr = ::realloc(membase, size + nmt_header_size); - return MemTracker::record_malloc(ptr, size, memflags, stack, level); -#else - if (memblock == NULL) { - return os::malloc(size, memflags, stack); - } - if ((intptr_t)memblock == (intptr_t)MallocCatchPtr) { - log_warning(malloc, free)("os::realloc caught " PTR_FORMAT, p2i(memblock)); - breakpoint(); - } - // NMT support - void* membase = MemTracker::malloc_base(memblock); - verify_memory(membase); - // always move the block - void* ptr = os::malloc(size, memflags, stack); - // Copy to new memory if malloc didn't fail - if (ptr != NULL ) { - GuardedMemory guarded(MemTracker::malloc_base(memblock)); - // Guard's user data contains NMT header - size_t memblock_size = guarded.get_user_size() - MemTracker::malloc_header_size(memblock); - memcpy(ptr, memblock, MIN2(size, memblock_size)); - if (paranoid) { - verify_memory(MemTracker::malloc_base(ptr)); - } - os::free(memblock); + // If NMT is enabled, this checks for heap overwrites, then de-accounts the old block. + void* const old_outer_ptr = MemTracker::record_free(memblock); + + void* const new_outer_ptr = ::realloc(old_outer_ptr, new_outer_size); + if (new_outer_ptr == NULL) { + return NULL; } - return ptr; -#endif + + void* const new_inner_ptr = MemTracker::record_malloc(new_outer_ptr, size, memflags, stack); + + DEBUG_ONLY(break_if_ptr_caught(new_inner_ptr);) + + return new_inner_ptr; } -// handles NULL pointers void os::free(void *memblock) { -#if INCLUDE_NMT + // Special handling for NMT preinit phase before arguments are parsed if (NMTPreInit::handle_free(memblock)) { return; } -#endif - NOT_PRODUCT(inc_stat_counter(&num_frees, 1)); -#ifdef ASSERT - if (memblock == NULL) return; - if ((intptr_t)memblock == (intptr_t)MallocCatchPtr) { - log_warning(malloc, free)("os::free caught " PTR_FORMAT, p2i(memblock)); - breakpoint(); + if (memblock == NULL) { + return; } - void* membase = MemTracker::record_free(memblock, MemTracker::tracking_level()); - verify_memory(membase); - GuardedMemory guarded(membase); - size_t size = guarded.get_user_size(); - inc_stat_counter(&free_bytes, size); - membase = guarded.release_for_freeing(); - ::free(membase); -#else - void* membase = MemTracker::record_free(memblock, MemTracker::tracking_level()); - ::free(membase); -#endif + DEBUG_ONLY(break_if_ptr_caught(memblock);) + + // If NMT is enabled, this checks for heap overwrites, then de-accounts the old block. + void* const old_outer_ptr = MemTracker::record_free(memblock); + + ::free(old_outer_ptr); } void os::init_random(unsigned int initval) { @@ -1241,34 +1173,34 @@ void os::print_location(outputStream* st, intptr_t x, bool verbose) { st->print_cr(INTPTR_FORMAT " is an unknown value", p2i(addr)); } +bool is_pointer_bad(intptr_t* ptr) { + return !is_aligned(ptr, sizeof(uintptr_t)) || !os::is_readable_pointer(ptr); +} + // Looks like all platforms can use the same function to check if C // stack is walkable beyond current frame. +// Returns true if this is not the case, i.e. the frame is possibly +// the first C frame on the stack. bool os::is_first_C_frame(frame* fr) { #ifdef _WINDOWS return true; // native stack isn't walkable on windows this way. #endif - // Load up sp, fp, sender sp and sender fp, check for reasonable values. // Check usp first, because if that's bad the other accessors may fault // on some architectures. Ditto ufp second, etc. - uintptr_t fp_align_mask = (uintptr_t)(sizeof(address)-1); - // sp on amd can be 32 bit aligned. - uintptr_t sp_align_mask = (uintptr_t)(sizeof(int)-1); - uintptr_t usp = (uintptr_t)fr->sp(); - if ((usp & sp_align_mask) != 0) return true; + if (is_pointer_bad(fr->sp())) return true; uintptr_t ufp = (uintptr_t)fr->fp(); - if ((ufp & fp_align_mask) != 0) return true; + if (is_pointer_bad(fr->fp())) return true; uintptr_t old_sp = (uintptr_t)fr->sender_sp(); - if ((old_sp & sp_align_mask) != 0) return true; - if (old_sp == 0 || old_sp == (uintptr_t)-1) return true; + if ((uintptr_t)fr->sender_sp() == (uintptr_t)-1 || is_pointer_bad(fr->sender_sp())) return true; - uintptr_t old_fp = (uintptr_t)fr->link(); - if ((old_fp & fp_align_mask) != 0) return true; - if (old_fp == 0 || old_fp == (uintptr_t)-1 || old_fp == ufp) return true; + uintptr_t old_fp = (uintptr_t)fr->link_or_null(); + if (old_fp == 0 || old_fp == (uintptr_t)-1 || old_fp == ufp || + is_pointer_bad(fr->link_or_null())) return true; // stack grows downwards; if old_fp is below current fp or if the stack // frame is too large, either the stack is corrupted or fp is not saved @@ -1280,7 +1212,6 @@ bool os::is_first_C_frame(frame* fr) { return false; } - // Set up the boot classpath. char* os::format_boot_path(const char* format_string, @@ -1354,10 +1285,6 @@ FILE* os::fopen(const char* path, const char* mode) { return file; } -ssize_t os::read(int fd, void *buf, unsigned int nBytes) { - return ::read(fd, buf, nBytes); -} - bool os::set_boot_path(char fileSep, char pathSep) { const char* home = Arguments::get_java_home(); int home_len = (int)strlen(home); @@ -1455,7 +1382,7 @@ char** os::split_path(const char* path, size_t* elements, size_t file_name_lengt // pages, false otherwise. bool os::stack_shadow_pages_available(Thread *thread, const methodHandle& method, address sp) { if (!thread->is_Java_thread()) return false; - // Check if we have StackShadowPages above the yellow zone. This parameter + // Check if we have StackShadowPages above the guard zone. This parameter // is dependent on the depth of the maximum VM call stack possible from // the handler for stack overflow. 'instanceof' in the stack overflow // handler or a println uses at least 8k stack of VM and native code @@ -1463,9 +1390,7 @@ bool os::stack_shadow_pages_available(Thread *thread, const methodHandle& method const int framesize_in_bytes = Interpreter::size_top_interpreter_activation(method()) * wordSize; - address limit = JavaThread::cast(thread)->stack_end() + - (StackOverflow::stack_guard_zone_size() + StackOverflow::stack_shadow_zone_size()); - + address limit = JavaThread::cast(thread)->stack_overflow_state()->shadow_zone_safe_limit(); return sp > (limit + framesize_in_bytes); } @@ -1781,7 +1706,7 @@ void os::commit_memory_or_exit(char* addr, size_t size, size_t alignment_hint, bool os::uncommit_memory(char* addr, size_t bytes, bool executable) { bool res; - if (MemTracker::tracking_level() > NMT_minimal) { + if (MemTracker::enabled()) { Tracker tkr(Tracker::uncommit); res = pd_uncommit_memory(addr, bytes, executable); if (res) { @@ -1795,7 +1720,7 @@ bool os::uncommit_memory(char* addr, size_t bytes, bool executable) { bool os::release_memory(char* addr, size_t bytes) { bool res; - if (MemTracker::tracking_level() > NMT_minimal) { + if (MemTracker::enabled()) { // Note: Tracker contains a ThreadCritical. Tracker tkr(Tracker::release); res = pd_release_memory(addr, bytes); @@ -1816,13 +1741,31 @@ void os::print_memory_mappings(outputStream* st) { os::print_memory_mappings(nullptr, (size_t)-1, st); } +// Pretouching must use a store, not just a load. On many OSes loads from +// fresh memory would be satisfied from a single mapped page containing all +// zeros. We need to store something to each page to get them backed by +// their own memory, which is the effect we want here. An atomic add of +// zero is used instead of a simple store, allowing the memory to be used +// while pretouch is in progress, rather than requiring users of the memory +// to wait until the entire range has been touched. This is technically +// a UB data race, but doesn't cause any problems for us. void os::pretouch_memory(void* start, void* end, size_t page_size) { - for (volatile char *p = (char*)start; p < (char*)end; p += page_size) { - // Note: this must be a store, not a load. On many OSes loads from fresh - // memory would be satisfied from a single mapped page containing all zeros. - // We need to store something to each page to get them backed by their own - // memory, which is the effect we want here. - *p = 0; + assert(start <= end, "invalid range: " PTR_FORMAT " -> " PTR_FORMAT, p2i(start), p2i(end)); + assert(is_power_of_2(page_size), "page size misaligned: %zu", page_size); + assert(page_size >= sizeof(int), "page size too small: %zu", page_size); + if (start < end) { + // We're doing concurrent-safe touch and memory state has page + // granularity, so we can touch anywhere in a page. Touch at the + // beginning of each page to simplify iteration. + char* cur = static_cast(align_down(start, page_size)); + void* last = align_down(static_cast(end) - 1, page_size); + assert(cur <= last, "invariant"); + // Iterate from first page through last (inclusive), being careful to + // avoid overflow if the last page abuts the end of the address range. + for ( ; true; cur += page_size) { + Atomic::add(reinterpret_cast(cur), 0, memory_order_relaxed); + if (cur >= last) break; + } } } @@ -1864,7 +1807,7 @@ char* os::remap_memory(int fd, const char* file_name, size_t file_offset, bool os::unmap_memory(char *addr, size_t bytes) { bool result; - if (MemTracker::tracking_level() > NMT_minimal) { + if (MemTracker::enabled()) { Tracker tkr(Tracker::release); result = pd_unmap_memory(addr, bytes); if (result) { @@ -1900,7 +1843,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::tracking_level() > NMT_minimal) { + if (MemTracker::enabled()) { // Note: Tracker contains a ThreadCritical. Tracker tkr(Tracker::release); res = pd_release_memory_special(addr, bytes); diff --git a/src/hotspot/share/runtime/os.hpp b/src/hotspot/share/runtime/os.hpp index 45ed150ec7a80a67a651bba8c3c097ca3fac8f12..1ad15f0d8eaa7c39502bdc2526b88628f027e8dd 100644 --- a/src/hotspot/share/runtime/os.hpp +++ b/src/hotspot/share/runtime/os.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -365,10 +365,9 @@ class os: AllStatic { // Prints all mappings static void print_memory_mappings(outputStream* st); - // Touch memory pages that cover the memory range from start to end (exclusive) - // to make the OS back the memory range with actual memory. - // Current implementation may not touch the last page if unaligned addresses - // are passed. + // Touch memory pages that cover the memory range from start to end + // (exclusive) to make the OS back the memory range with actual memory. + // Other threads may use the memory range concurrently with pretouch. static void pretouch_memory(void* start, void* end, size_t page_size = vm_page_size()); enum ProtType { MEM_PROT_NONE, MEM_PROT_READ, MEM_PROT_RW, MEM_PROT_RWX }; @@ -541,9 +540,8 @@ class os: AllStatic { // File i/o operations static int open(const char *path, int oflag, int mode); - static FILE* open(int fd, const char* mode); + static FILE* fdopen(int fd, const char* mode); static FILE* fopen(const char* path, const char* mode); - static int close(int fd); static jlong lseek(int fd, jlong offset, int whence); static bool file_exists(const char* file); // This function, on Windows, canonicalizes a given path (see os_windows.cpp for details). @@ -563,9 +561,8 @@ class os: AllStatic { //File i/o operations - static ssize_t read(int fd, void *buf, unsigned int nBytes); static ssize_t read_at(int fd, void *buf, unsigned int nBytes, jlong offset); - static size_t write(int fd, const void *buf, unsigned int nBytes); + static ssize_t write(int fd, const void *buf, unsigned int nBytes); // Reading directories. static DIR* opendir(const char* dirname); @@ -784,15 +781,7 @@ class os: AllStatic { // Like strdup, but exit VM when strdup() returns NULL static char* strdup_check_oom(const char*, MEMFLAGS flags = mtInternal); -#ifndef PRODUCT - static julong num_mallocs; // # of calls to malloc/realloc - static julong alloc_bytes; // # of bytes allocated - static julong num_frees; // # of calls to free - static julong free_bytes; // # of bytes freed -#endif - // SocketInterface (ex HPI SocketInterface ) - static int socket(int domain, int type, int protocol); static int socket_close(int fd); static int recv(int fd, char* buf, size_t nBytes, uint flags); static int send(int fd, char* buf, size_t nBytes, uint flags); diff --git a/src/hotspot/share/runtime/osThread.cpp b/src/hotspot/share/runtime/osThread.cpp index dadb33fe014c3765bcc3122612bdd12d7d301d20..edaefaa1070d2f9806a2387cb54441cc6855ea5a 100644 --- a/src/hotspot/share/runtime/osThread.cpp +++ b/src/hotspot/share/runtime/osThread.cpp @@ -26,10 +26,8 @@ #include "oops/oop.inline.hpp" #include "runtime/osThread.hpp" -OSThread::OSThread(OSThreadStartFunc start_proc, void* start_parm) { +OSThread::OSThread() { pd_initialize(); - set_start_proc(start_proc); - set_start_parm(start_parm); } OSThread::~OSThread() { diff --git a/src/hotspot/share/runtime/osThread.hpp b/src/hotspot/share/runtime/osThread.hpp index 9c4c5e12735240df8a4f82493fdefb240c4bfd42..445ac097bf8f436324a964b4a557293674014c9a 100644 --- a/src/hotspot/share/runtime/osThread.hpp +++ b/src/hotspot/share/runtime/osThread.hpp @@ -61,8 +61,6 @@ class OSThread: public CHeapObj { friend class VMStructs; friend class JVMCIVMStructs; private: - OSThreadStartFunc _start_proc; // Thread start routine - void* _start_parm; // Thread start routine parameter volatile ThreadState _state; // Thread state *hint* // Methods @@ -70,18 +68,9 @@ class OSThread: public CHeapObj { void set_state(ThreadState state) { _state = state; } ThreadState get_state() { return _state; } - OSThread(OSThreadStartFunc start_proc, void* start_parm); + OSThread(); ~OSThread(); - // Accessors - OSThreadStartFunc start_proc() const { return _start_proc; } - void set_start_proc(OSThreadStartFunc start_proc) { _start_proc = start_proc; } - void* start_parm() const { return _start_parm; } - void set_start_parm(void* start_parm) { _start_parm = start_parm; } - // This is specialized on Windows. -#ifndef _WINDOWS - void set_interrupted(bool z) { /* nothing to do */ } -#endif // Printing void print_on(outputStream* st) const; void print() const; @@ -90,8 +79,6 @@ class OSThread: public CHeapObj { #include OS_HEADER(osThread) public: - static ByteSize thread_id_offset() { return byte_offset_of(OSThread, _thread_id); } - static size_t thread_id_size() { return sizeof(thread_id_t); } thread_id_t thread_id() const { return _thread_id; } diff --git a/src/hotspot/share/runtime/prefetch.hpp b/src/hotspot/share/runtime/prefetch.hpp index dac34f6cd26634a93b0ed6c19fb5e5a4cea546c3..d949899813c77ef7be07fb3c316c7e8a7f6d6a72 100644 --- a/src/hotspot/share/runtime/prefetch.hpp +++ b/src/hotspot/share/runtime/prefetch.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -25,7 +25,7 @@ #ifndef SHARE_RUNTIME_PREFETCH_HPP #define SHARE_RUNTIME_PREFETCH_HPP -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" // If calls to prefetch methods are in a loop, the loop should be cloned // such that if Prefetch{Scan,Copy}Interval and/or PrefetchFieldInterval diff --git a/src/hotspot/share/runtime/reflectionUtils.hpp b/src/hotspot/share/runtime/reflectionUtils.hpp index a928c50596e82ef298a2ea045f26cdf77b0ee0fc..ef9f8bbd62e7de5fd70fcf0e995d4010f8def361 100644 --- a/src/hotspot/share/runtime/reflectionUtils.hpp +++ b/src/hotspot/share/runtime/reflectionUtils.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -25,7 +25,7 @@ #ifndef SHARE_RUNTIME_REFLECTIONUTILS_HPP #define SHARE_RUNTIME_REFLECTIONUTILS_HPP -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" #include "oops/instanceKlass.hpp" #include "oops/objArrayOop.hpp" #include "oops/oopsHierarchy.hpp" diff --git a/src/hotspot/share/runtime/safefetch.inline.hpp b/src/hotspot/share/runtime/safefetch.inline.hpp index 79c833e4db6b086c58e9903bf39a9509aa2c0f44..cee0853573cf5a323ce26a59e73f5b6de4cf2246 100644 --- a/src/hotspot/share/runtime/safefetch.inline.hpp +++ b/src/hotspot/share/runtime/safefetch.inline.hpp @@ -54,10 +54,20 @@ inline intptr_t SafeFetchN(intptr_t* adr, intptr_t errValue) { // returns true if SafeFetch32 and SafeFetchN can be used safely (stubroutines are already generated) inline bool CanUseSafeFetch32() { +#if defined (__APPLE__) && defined(AARCH64) + if (Thread::current_or_null_safe() == NULL) { // workaround for JDK-8282475 + return false; + } +#endif // __APPLE__ && AARCH64 return StubRoutines::SafeFetch32_stub() ? true : false; } inline bool CanUseSafeFetchN() { +#if defined (__APPLE__) && defined(AARCH64) + if (Thread::current_or_null_safe() == NULL) { + return false; + } +#endif // __APPLE__ && AARCH64 return StubRoutines::SafeFetchN_stub() ? true : false; } diff --git a/src/hotspot/share/runtime/safepoint.cpp b/src/hotspot/share/runtime/safepoint.cpp index 039f8b495b0c6700755d7c484700888e82fe6c5a..44240f85b71cc92bb20d9b26e9651c1e3313303d 100644 --- a/src/hotspot/share/runtime/safepoint.cpp +++ b/src/hotspot/share/runtime/safepoint.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -168,6 +168,14 @@ void SafepointSynchronize::decrement_waiting_to_block() { bool SafepointSynchronize::thread_not_running(ThreadSafepointState *cur_state) { if (!cur_state->is_running()) { + // Robustness: asserted in the caller, but handle/tolerate it for release bits. + LogTarget(Error, safepoint) lt; + if (lt.is_enabled()) { + ResourceMark rm; + LogStream ls(lt); + ls.print("Illegal initial state detected: "); + cur_state->print_on(&ls); + } return true; } cur_state->examine_state_of_thread(SafepointSynchronize::safepoint_counter()); @@ -746,6 +754,7 @@ void SafepointSynchronize::block(JavaThread *thread) { void SafepointSynchronize::handle_polling_page_exception(JavaThread *thread) { assert(thread->thread_state() == _thread_in_Java, "should come from Java code"); + thread->set_thread_state(_thread_in_vm); // Enable WXWrite: the function is called implicitly from java code. MACOS_AARCH64_ONLY(ThreadWXEnable wx(WXWrite, thread)); @@ -757,6 +766,8 @@ void SafepointSynchronize::handle_polling_page_exception(JavaThread *thread) { ThreadSafepointState* state = thread->safepoint_state(); state->handle_polling_page_exception(); + + thread->set_thread_state(_thread_in_Java); } @@ -962,7 +973,6 @@ void ThreadSafepointState::handle_polling_page_exception() { // If we have a pending async exception deoptimize the frame // as otherwise we may never deliver it. if (self->has_async_exception_condition()) { - ThreadInVMfromJava __tiv(self, false /* check asyncs */); Deoptimization::deoptimize_frame(self, caller_fr.id()); } diff --git a/src/hotspot/share/runtime/safepoint.hpp b/src/hotspot/share/runtime/safepoint.hpp index 268a315dd7bf0adf7f65c0bb63e2fd45da838475..e67c960626ba3d9ace17807fa5b66b48544358ff 100644 --- a/src/hotspot/share/runtime/safepoint.hpp +++ b/src/hotspot/share/runtime/safepoint.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -25,7 +25,7 @@ #ifndef SHARE_RUNTIME_SAFEPOINT_HPP #define SHARE_RUNTIME_SAFEPOINT_HPP -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" #include "runtime/os.hpp" #include "runtime/thread.hpp" #include "runtime/vmOperation.hpp" @@ -126,10 +126,6 @@ class SafepointSynchronize : AllStatic { JavaThread *thread, uint64_t safepoint_count); - static bool is_a_block_safe_state(JavaThreadState state) { - // Check that we have a valid thread_state before blocking for safepoints - return state == _thread_in_vm || state == _thread_in_Java; - } // Called when a thread voluntarily blocks static void block(JavaThread *thread); diff --git a/src/hotspot/share/runtime/safepointMechanism.cpp b/src/hotspot/share/runtime/safepointMechanism.cpp index b092f050539bc3cbd3d87d2eed8a7caaa49b4ac6..0a4d9a436c05871182d1686109ebfc90bdd7036e 100644 --- a/src/hotspot/share/runtime/safepointMechanism.cpp +++ b/src/hotspot/share/runtime/safepointMechanism.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -119,7 +119,7 @@ void SafepointMechanism::process(JavaThread *thread, bool allow_suspend) { bool need_rechecking; do { JavaThreadState state = thread->thread_state(); - guarantee(SafepointSynchronize::is_a_block_safe_state(state), "Illegal threadstate encountered: %d", state); + guarantee(state == _thread_in_vm, "Illegal threadstate encountered: %d", state); if (global_poll()) { // Any load in ::block() must not pass the global poll load. // Otherwise we might load an old safepoint counter (for example). diff --git a/src/hotspot/share/runtime/sharedRuntime.cpp b/src/hotspot/share/runtime/sharedRuntime.cpp index 5ac0c3bdf6b31fbe4fdb1432cb5aa975d2800112..ce9a06265a9fc88e593603bdca1bd07ba3bfe4cd 100644 --- a/src/hotspot/share/runtime/sharedRuntime.cpp +++ b/src/hotspot/share/runtime/sharedRuntime.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -497,7 +497,7 @@ address SharedRuntime::raw_exception_handler_for_return_address(JavaThread* curr return SharedRuntime::deopt_blob()->unpack_with_exception(); } else { // The deferred StackWatermarkSet::after_unwind check will be performed in - // * OptoRuntime::rethrow_C for C2 code + // * OptoRuntime::handle_exception_C_helper for C2 code // * exception_handler_for_pc_helper via Runtime1::handle_exception_from_callee_id for C1 code return nm->exception_begin(); } @@ -1947,6 +1947,8 @@ bool SharedRuntime::should_fixup_call_destination(address destination, address e JRT_LEAF(void, SharedRuntime::fixup_callers_callsite(Method* method, address caller_pc)) Method* moop(method); + AARCH64_PORT_ONLY(assert(pauth_ptr_is_raw(caller_pc), "should be raw")); + address entry_point = moop->from_compiled_entry_no_trampoline(); // It's possible that deoptimization can occur at a call site which hasn't diff --git a/src/hotspot/share/runtime/sharedRuntime.hpp b/src/hotspot/share/runtime/sharedRuntime.hpp index ec816928ac79c0cdfd9ebf374b6eb1e66b6333e1..10e4b0ec0af8cad5796a8bfbca8f4576b642bde4 100644 --- a/src/hotspot/share/runtime/sharedRuntime.hpp +++ b/src/hotspot/share/runtime/sharedRuntime.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -29,7 +29,7 @@ #include "code/vmreg.hpp" #include "interpreter/bytecodeTracer.hpp" #include "interpreter/linkResolver.hpp" -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" #include "memory/resourceArea.hpp" #include "utilities/hashtable.hpp" #include "utilities/macros.hpp" @@ -384,8 +384,6 @@ class SharedRuntime: AllStatic { uint num_bits, uint total_args_passed); - static size_t trampoline_size(); - // Generate I2C and C2I adapters. These adapters are simple argument marshalling // blobs. Unlike adapters in the tiger and earlier releases the code in these // blobs does not create a new frame and are therefore virtually invisible diff --git a/src/hotspot/share/runtime/stackOverflow.cpp b/src/hotspot/share/runtime/stackOverflow.cpp index 942f3a29e3fdae86e8fc1fb452f9be35b2be015e..1004ca265d3c153fd3432ed46be11c32eb55b863 100644 --- a/src/hotspot/share/runtime/stackOverflow.cpp +++ b/src/hotspot/share/runtime/stackOverflow.cpp @@ -39,19 +39,20 @@ void StackOverflow::initialize_stack_zone_sizes() { // Stack zone sizes must be page aligned. size_t page_size = os::vm_page_size(); - // We need to adapt the configured number of stack protection pages given - // in 4K pages to the actual os page size. We must do this before setting - // up minimal stack sizes etc. in os::init_2(). - size_t alignment = 4*K; + // We need to adapt the configured number of stack protection pages to the + // actual OS page size. We must do this before setting up minimal stack + // sizes etc. in os::init_2(). The option values are given in 4K units, + // matching the smallest page size in supported platforms. + size_t unit = 4*K; assert(_stack_red_zone_size == 0, "This should be called only once."); - _stack_red_zone_size = align_up(StackRedPages * alignment, page_size); + _stack_red_zone_size = align_up(StackRedPages * unit, page_size); assert(_stack_yellow_zone_size == 0, "This should be called only once."); - _stack_yellow_zone_size = align_up(StackYellowPages * alignment, page_size); + _stack_yellow_zone_size = align_up(StackYellowPages * unit, page_size); assert(_stack_reserved_zone_size == 0, "This should be called only once."); - _stack_reserved_zone_size = align_up(StackReservedPages * alignment, page_size); + _stack_reserved_zone_size = align_up(StackReservedPages * unit, page_size); // The shadow area is not allocated or protected, so // it needs not be page aligned. @@ -63,7 +64,7 @@ void StackOverflow::initialize_stack_zone_sizes() { // suffices to touch all pages. (Some pages are banged // several times, though.) assert(_stack_shadow_zone_size == 0, "This should be called only once."); - _stack_shadow_zone_size = align_up(StackShadowPages * alignment, page_size); + _stack_shadow_zone_size = align_up(StackShadowPages * unit, page_size); } bool StackOverflow::stack_guards_enabled() const { diff --git a/src/hotspot/share/runtime/stackOverflow.hpp b/src/hotspot/share/runtime/stackOverflow.hpp index c8e4249ab257418ee6e8cbda812cee16f6a75aea..5a8a88c4fcd9ed9a85028d4029d7c5ea640776fc 100644 --- a/src/hotspot/share/runtime/stackOverflow.hpp +++ b/src/hotspot/share/runtime/stackOverflow.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -51,6 +51,8 @@ class StackOverflow { _stack_guard_state(stack_guard_unused), _stack_overflow_limit(nullptr), _reserved_stack_activation(nullptr), // stack base not known yet + _shadow_zone_safe_limit(nullptr), + _shadow_zone_growth_watermark(nullptr), _stack_base(nullptr), _stack_end(nullptr) {} // Initialization after thread is started. @@ -58,6 +60,7 @@ class StackOverflow { _stack_base = base; _stack_end = end; set_stack_overflow_limit(); + set_shadow_zone_limits(); set_reserved_stack_activation(base); } private: @@ -68,6 +71,8 @@ class StackOverflow { // We load it from here to simplify the stack overflow check in assembly. address _stack_overflow_limit; address _reserved_stack_activation; + address _shadow_zone_safe_limit; + address _shadow_zone_growth_watermark; // Support for stack overflow handling, copied down from thread. address _stack_base; @@ -77,6 +82,9 @@ class StackOverflow { address stack_base() const { assert(_stack_base != nullptr, "Sanity check"); return _stack_base; } // Stack overflow support + // -------------------------------------------------------------------------------- + // + // The Java thread stack is structured as follows: // // (low addresses) // @@ -95,11 +103,24 @@ class StackOverflow { // | | // | reserved zone | // | | - // -- <-- stack_reserved_zone_base() --- --- - // /|\ shadow <-- stack_overflow_limit() (somewhere in here) - // | zone - // \|/ size - // some untouched memory --- + // -- <-- stack_reserved_zone_base() --- --- + // ^ + // | <-- stack_overflow_limit() [somewhere in here] + // | shadow + // | zone + // | size + // v + // --- <-- shadow_zone_safe_limit() + // (Here and below: not yet touched stack) + // + // + // (Here and below: touched at least once) --- + // ^ + // | shadow + // | zone + // | size + // v + // --- <-- shadow_zone_growth_watermark() // // // -- @@ -120,6 +141,84 @@ class StackOverflow { // // (high addresses) // + // + // The stack overflow mechanism detects overflows by touching ("banging") the stack + // ahead of current stack pointer (SP). The entirety of guard zone is memory protected, + // therefore such access would trap when touching the guard zone, and one of the following + // things would happen. + // + // Access in the red zone: unrecoverable stack overflow. Crash the VM, generate a report, + // crash dump, and other diagnostics. + // + // Access in the yellow zone: recoverable, reportable stack overflow. Create and throw + // a StackOverflowError, remove the protection of yellow zone temporarily to let exception + // handlers run. If exception handlers themselves run out of stack, they will crash VM due + // to access to red zone. + // + // Access in the reserved zone: recoverable, reportable, transparent for privileged methods + // stack overflow. Perform a stack walk to check if there's a method annotated with + // @ReservedStackAccess on the call stack. If such method is found, remove the protection of + // reserved zone temporarily, and let the method run. If not, handle the access like a yellow + // zone trap. + // + // The banging itself happens within the "shadow zone" that extends from the current SP. + // + // The goals for properly implemented shadow zone banging are: + // + // a) Allow native/VM methods to run without stack overflow checks within some reasonable + // headroom. Default shadow zone size should accommodate the largest normally expected + // native/VM stack use. + // b) Guarantee the stack overflow checks work even if SP is dangerously close to guard zone. + // If SP is very low, banging at the edge of shadow zone (SP+shadow-zone-size) can slip + // into adjacent thread stack, or even into other readable memory. This would potentially + // pass the check by accident. + // c) Allow for incremental stack growth on some OSes. This is enabled by handling traps + // from not yet committed thread stacks, even outside the guard zone. The banging should + // not allow uncommitted "gaps" on thread stack. See for example the uses of + // os::map_stack_shadow_pages(). + // d) Make sure the stack overflow trap happens in the code that is known to runtime, so + // the traps can be reasonably handled: handling a spurious trap from executing Java code + // is hard, while properly handling the trap from VM/native code is nearly impossible. + // + // The simplest code that satisfies all these requirements is banging the shadow zone + // page by page at every Java/native method entry. + // + // While that code is sufficient, it comes with the large performance cost. This performance + // cost can be reduced by several *optional* techniques: + // + // 1. Guarantee that stack would not take another page. If so, the current bang was + // enough to verify we are not near the guard zone. This kind of insight is usually only + // available for compilers that can know the size of the frame exactly. + // + // Examples: PhaseOutput::need_stack_bang. + // + // 2. Check the current SP in relation to shadow zone safe limit. + // + // Define "safe limit" as the highest SP where banging would not touch the guard zone. + // Then, do the page-by-page bang only if current SP is above that safe limit, OR some + // OS-es need it to get the stack mapped. + // + // Examples: AbstractAssembler::generate_stack_overflow_check, JavaCalls::call_helper, + // os::stack_shadow_pages_available, os::map_stack_shadow_pages and their uses. + // + // 3. Check the current SP in relation to the shadow zone growth watermark. + // + // Define "shadow zone growth watermark" as the highest SP where we banged already. + // Invariant: growth watermark is always above the safe limit, which allows testing + // for watermark and safe limit at the same time in the most frequent case. + // + // Easy and overwhelmingly frequent case: SP is above the growth watermark, and + // by extension above the safe limit. In this case, we know that the guard zone is far away + // (safe limit), and that the stack was banged before for stack growth (growth watermark). + // Therefore, we can skip the banging altogether. + // + // Harder cases: SP is below the growth watermark. In might be due to two things: + // we have not banged the stack for growth (below growth watermark only), or we are + // close to guard zone (also below safe limit). Do the full banging. Once done, we + // can adjust the growth watermark, thus recording the bang for stack growth had + // happened. + // + // Examples: TemplateInterpreterGenerator::bang_stack_shadow_pages on x86 and others. private: // These values are derived from flags StackRedPages, StackYellowPages, @@ -189,6 +288,11 @@ class StackOverflow { return _stack_shadow_zone_size; } + address shadow_zone_safe_limit() const { + assert(_shadow_zone_safe_limit != nullptr, "Don't call this before the field is initialized."); + return _shadow_zone_safe_limit; + } + void create_stack_guard_pages(); void remove_stack_guard_pages(); @@ -242,6 +346,13 @@ class StackOverflow { _stack_overflow_limit = stack_end() + MAX2(stack_guard_zone_size(), stack_shadow_zone_size()); } + + void set_shadow_zone_limits() { + _shadow_zone_safe_limit = + stack_end() + stack_guard_zone_size() + stack_shadow_zone_size(); + _shadow_zone_growth_watermark = + stack_base(); + } }; #endif // SHARE_RUNTIME_STACKOVERFLOW_HPP diff --git a/src/hotspot/share/runtime/stackWatermark.hpp b/src/hotspot/share/runtime/stackWatermark.hpp index 3cf7ce59cd98e1c7c0f3c946859fda743c3bc732..6210a0bc2bf3a79491dcfb447e18fcdc52e1b47e 100644 --- a/src/hotspot/share/runtime/stackWatermark.hpp +++ b/src/hotspot/share/runtime/stackWatermark.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -25,7 +25,7 @@ #ifndef SHARE_RUNTIME_STACKWATERMARK_HPP #define SHARE_RUNTIME_STACKWATERMARK_HPP -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" #include "runtime/mutex.hpp" #include "runtime/stackWatermarkKind.hpp" diff --git a/src/hotspot/share/runtime/stubCodeGenerator.cpp b/src/hotspot/share/runtime/stubCodeGenerator.cpp index 68a82d78326fe69230094b1edb07192fb6196d83..fb546bc8ebee7fb7ac6ccfb57b8915fe3754c368 100644 --- a/src/hotspot/share/runtime/stubCodeGenerator.cpp +++ b/src/hotspot/share/runtime/stubCodeGenerator.cpp @@ -69,7 +69,7 @@ void StubCodeDesc::print() const { print_on(tty); } // Implementation of StubCodeGenerator StubCodeGenerator::StubCodeGenerator(CodeBuffer* code, bool print_code) { - _masm = new MacroAssembler(code ); + _masm = new MacroAssembler(code); _print_code = PrintStubCode || print_code; } diff --git a/src/hotspot/share/runtime/stubRoutines.cpp b/src/hotspot/share/runtime/stubRoutines.cpp index 591950fa213f0b5bc8430b666044e400ba09943e..c378ab09dc8d76bc50f2629e224561ab6aba0b14 100644 --- a/src/hotspot/share/runtime/stubRoutines.cpp +++ b/src/hotspot/share/runtime/stubRoutines.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -215,7 +215,10 @@ void StubRoutines::initialize1() { if (_code1 == NULL) { ResourceMark rm; TraceTime timer("StubRoutines generation 1", TRACETIME_LOG(Info, startuptime)); - _code1 = BufferBlob::create("StubRoutines (1)", code_size1); + // Add extra space for large CodeEntryAlignment + int max_aligned_stubs = 10; + int size = code_size1 + CodeEntryAlignment * max_aligned_stubs; + _code1 = BufferBlob::create("StubRoutines (1)", size); if (_code1 == NULL) { vm_exit_out_of_memory(code_size1, OOM_MALLOC_ERROR, "CodeCache: no room for StubRoutines (1)"); } @@ -269,7 +272,10 @@ void StubRoutines::initialize2() { if (_code2 == NULL) { ResourceMark rm; TraceTime timer("StubRoutines generation 2", TRACETIME_LOG(Info, startuptime)); - _code2 = BufferBlob::create("StubRoutines (2)", code_size2); + // Add extra space for large CodeEntryAlignment + int max_aligned_stubs = 100; + int size = code_size2 + CodeEntryAlignment * max_aligned_stubs; + _code2 = BufferBlob::create("StubRoutines (2)", size); if (_code2 == NULL) { vm_exit_out_of_memory(code_size2, OOM_MALLOC_ERROR, "CodeCache: no room for StubRoutines (2)"); } diff --git a/src/hotspot/share/runtime/sweeper.cpp b/src/hotspot/share/runtime/sweeper.cpp index 31c9220ea784ee68eac6696ace2307703e38c39f..988d6ccfac95199f75c49cc932cbcb647eea9f7c 100644 --- a/src/hotspot/share/runtime/sweeper.cpp +++ b/src/hotspot/share/runtime/sweeper.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -55,9 +55,9 @@ // Sweeper logging code class SweeperRecord { public: - int traversal; + int64_t traversal; int compile_id; - long traversal_mark; + int64_t traversal_mark; int state; const char* kind; address vep; @@ -65,8 +65,8 @@ class SweeperRecord { int line; void print() { - tty->print_cr("traversal = %d compile_id = %d %s uep = " PTR_FORMAT " vep = " - PTR_FORMAT " state = %d traversal_mark %ld line = %d", + tty->print_cr("traversal = " INT64_FORMAT " compile_id = %d %s uep = " PTR_FORMAT " vep = " + PTR_FORMAT " state = %d traversal_mark " INT64_FORMAT " line = %d", traversal, compile_id, kind == NULL ? "" : kind, @@ -107,8 +107,8 @@ void NMethodSweeper::init_sweeper_log() { #endif CompiledMethodIterator NMethodSweeper::_current(CompiledMethodIterator::all_blobs); // Current compiled method -long NMethodSweeper::_traversals = 0; // Stack scan count, also sweep ID. -long NMethodSweeper::_total_nof_code_cache_sweeps = 0; // Total number of full sweeps of the code cache +int64_t NMethodSweeper::_traversals = 0; // Stack scan count, also sweep ID. +int64_t NMethodSweeper::_total_nof_code_cache_sweeps = 0; // Total number of full sweeps of the code cache int NMethodSweeper::_seen = 0; // Nof. nmethod we have currently processed in current pass of CodeCache size_t NMethodSweeper::_sweep_threshold_bytes = 0; // Threshold for when to sweep. Updated after ergonomics @@ -119,8 +119,8 @@ volatile size_t NMethodSweeper::_bytes_changed = 0; // Counts the tot // 2) not_entrant -> zombie int NMethodSweeper::_hotness_counter_reset_val = 0; -long NMethodSweeper::_total_nof_methods_reclaimed = 0; // Accumulated nof methods flushed -long NMethodSweeper::_total_nof_c2_methods_reclaimed = 0; // Accumulated nof methods flushed +int64_t NMethodSweeper::_total_nof_methods_reclaimed = 0; // Accumulated nof methods flushed +int64_t NMethodSweeper::_total_nof_c2_methods_reclaimed = 0; // Accumulated nof methods flushed size_t NMethodSweeper::_total_flushed_size = 0; // Total number of bytes flushed from the code cache Tickspan NMethodSweeper::_total_time_sweeping; // Accumulated time sweeping Tickspan NMethodSweeper::_total_time_this_sweep; // Total time this sweep @@ -187,7 +187,7 @@ CodeBlobClosure* NMethodSweeper::prepare_mark_active_nmethods() { _total_time_this_sweep = Tickspan(); if (PrintMethodFlushing) { - tty->print_cr("### Sweep: stack traversal %ld", _traversals); + tty->print_cr("### Sweep: stack traversal " INT64_FORMAT, _traversals); } return &mark_activation_closure; } @@ -217,7 +217,7 @@ void NMethodSweeper::sweeper_loop() { { ThreadBlockInVM tbivm(JavaThread::current()); MonitorLocker waiter(CodeSweeper_lock, Mutex::_no_safepoint_check_flag); - const long wait_time = 60*60*24 * 1000; + const int64_t wait_time = 60*60*24 * 1000; timeout = waiter.wait(wait_time); } if (!timeout && (_should_sweep || _force_sweep)) { @@ -229,19 +229,19 @@ void NMethodSweeper::sweeper_loop() { /** * Wakes up the sweeper thread to sweep if code cache space runs low */ -void NMethodSweeper::report_allocation(int code_blob_type) { - if (should_start_aggressive_sweep(code_blob_type)) { +void NMethodSweeper::report_allocation() { + if (should_start_aggressive_sweep()) { MonitorLocker waiter(CodeSweeper_lock, Mutex::_no_safepoint_check_flag); _should_sweep = true; CodeSweeper_lock->notify(); } } -bool NMethodSweeper::should_start_aggressive_sweep(int code_blob_type) { +bool NMethodSweeper::should_start_aggressive_sweep() { // Makes sure that we do not invoke the sweeper too often during startup. double start_threshold = 100.0 / (double)StartAggressiveSweepingAt; double aggressive_sweep_threshold = MAX2(start_threshold, 1.1); - return (CodeCache::reverse_free_ratio(code_blob_type) >= aggressive_sweep_threshold); + return (CodeCache::reverse_free_ratio() >= aggressive_sweep_threshold); } /** @@ -546,8 +546,7 @@ void NMethodSweeper::possibly_flush(nmethod* nm) { // ReservedCodeCacheSize int reset_val = hotness_counter_reset_val(); int time_since_reset = reset_val - nm->hotness_counter(); - int code_blob_type = CodeCache::get_code_blob_type(nm); - double threshold = -reset_val + (CodeCache::reverse_free_ratio(code_blob_type) * NmethodSweepActivity); + double threshold = -reset_val + (CodeCache::reverse_free_ratio() * NmethodSweepActivity); // The less free space in the code cache we have - the bigger reverse_free_ratio() is. // I.e., 'threshold' increases with lower available space in the code cache and a higher // NmethodSweepActivity. If the current hotness counter - which decreases from its initial @@ -646,7 +645,7 @@ void NMethodSweeper::log_sweep(const char* msg, const char* format, ...) { CodeCache::log_state(&s); ttyLocker ttyl; - xtty->begin_elem("sweeper state='%s' traversals='" INTX_FORMAT "' ", msg, (intx)traversal_count()); + xtty->begin_elem("sweeper state='%s' traversals='" INT64_FORMAT "' ", msg, traversal_count()); if (format != NULL) { va_list ap; va_start(ap, format); @@ -664,8 +663,9 @@ void NMethodSweeper::print(outputStream* out) { out = (out == NULL) ? tty : out; out->print_cr("Code cache sweeper statistics:"); out->print_cr(" Total sweep time: %1.0lf ms", (double)_total_time_sweeping.value()/1000000); - out->print_cr(" Total number of full sweeps: %ld", _total_nof_code_cache_sweeps); - out->print_cr(" Total number of flushed methods: %ld (thereof %ld C2 methods)", _total_nof_methods_reclaimed, + out->print_cr(" Total number of full sweeps: " INT64_FORMAT, _total_nof_code_cache_sweeps); + out->print_cr(" Total number of flushed methods: " INT64_FORMAT " (thereof " INT64_FORMAT " C2 methods)", + _total_nof_methods_reclaimed, _total_nof_c2_methods_reclaimed); out->print_cr(" Total size of flushed methods: " SIZE_FORMAT " kB", _total_flushed_size/K); } diff --git a/src/hotspot/share/runtime/sweeper.hpp b/src/hotspot/share/runtime/sweeper.hpp index 9ba2298e9efbf7c030ea6ec10655ce15bd1f386f..06daf37ee3a7e5757a0b6000c140bcfabf2f0e5e 100644 --- a/src/hotspot/share/runtime/sweeper.hpp +++ b/src/hotspot/share/runtime/sweeper.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -66,8 +66,8 @@ class NMethodSweeper : public AllStatic { MadeZombie, Flushed }; - static long _traversals; // Stack scan count, also sweep ID. - static long _total_nof_code_cache_sweeps; // Total number of full sweeps of the code cache + static int64_t _traversals; // Stack scan count, also sweep ID. + static int64_t _total_nof_code_cache_sweeps; // Total number of full sweeps of the code cache static CompiledMethodIterator _current; // Current compiled method static int _seen; // Nof. nmethod we have currently processed in current pass of CodeCache static size_t _sweep_threshold_bytes; // The threshold for when to invoke sweeps @@ -78,8 +78,8 @@ class NMethodSweeper : public AllStatic { // 1) alive -> not_entrant // 2) not_entrant -> zombie // Stat counters - static long _total_nof_methods_reclaimed; // Accumulated nof methods flushed - static long _total_nof_c2_methods_reclaimed; // Accumulated nof C2-compiled methods flushed + static int64_t _total_nof_methods_reclaimed; // Accumulated nof methods flushed + static int64_t _total_nof_c2_methods_reclaimed; // Accumulated nof C2-compiled methods flushed static size_t _total_flushed_size; // Total size of flushed methods static int _hotness_counter_reset_val; @@ -97,10 +97,10 @@ class NMethodSweeper : public AllStatic { static void do_stack_scanning(); static void sweep(); public: - static long traversal_count() { return _traversals; } + static int64_t traversal_count() { return _traversals; } static size_t sweep_threshold_bytes() { return _sweep_threshold_bytes; } static void set_sweep_threshold_bytes(size_t threshold) { _sweep_threshold_bytes = threshold; } - static int total_nof_methods_reclaimed() { return _total_nof_methods_reclaimed; } + static int64_t total_nof_methods_reclaimed() { return _total_nof_methods_reclaimed; } static const Tickspan total_time_sweeping() { return _total_time_sweeping; } static const Tickspan peak_sweep_time() { return _peak_sweep_time; } static const Tickspan peak_sweep_fraction_time() { return _peak_sweep_fraction_time; } @@ -113,11 +113,11 @@ class NMethodSweeper : public AllStatic { static CodeBlobClosure* prepare_mark_active_nmethods(); static void sweeper_loop(); - static bool should_start_aggressive_sweep(int code_blob_type); + static bool should_start_aggressive_sweep(); static void force_sweep(); static int hotness_counter_reset_val(); static void report_state_change(nmethod* nm); - static void report_allocation(int code_blob_type); // Possibly start the sweeper thread. + static void report_allocation(); // Possibly start the sweeper thread. static void possibly_flush(nmethod* nm); static void print(outputStream* out); // Printing/debugging static void print() { print(tty); } diff --git a/src/hotspot/share/runtime/synchronizer.cpp b/src/hotspot/share/runtime/synchronizer.cpp index 87f2880650846f2be13084ba51809ee65e3d1699..d4234575fc0332b4e71fe54e48dc324d7cea42ab 100644 --- a/src/hotspot/share/runtime/synchronizer.cpp +++ b/src/hotspot/share/runtime/synchronizer.cpp @@ -57,6 +57,40 @@ #include "utilities/events.hpp" #include "utilities/preserveException.hpp" +class CleanupObjectMonitorsHashtable: StackObj { + public: + bool do_entry(void*& key, ObjectMonitorsHashtable::PtrList*& list) { + list->clear(); // clear the LinkListNodes + delete list; // then delete the LinkedList + return true; + } +}; + +ObjectMonitorsHashtable::~ObjectMonitorsHashtable() { + CleanupObjectMonitorsHashtable cleanup; + _ptrs->unlink(&cleanup); // cleanup the LinkedLists + delete _ptrs; // then delete the hash table +} + +void ObjectMonitorsHashtable::add_entry(void* key, ObjectMonitor* om) { + ObjectMonitorsHashtable::PtrList* list = get_entry(key); + if (list == nullptr) { + // Create new list and add it to the hash table: + list = new (ResourceObj::C_HEAP, mtThread) ObjectMonitorsHashtable::PtrList(); + add_entry(key, list); + } + list->add(om); // Add the ObjectMonitor to the list. + _om_count++; +} + +bool ObjectMonitorsHashtable::has_entry(void* key, ObjectMonitor* om) { + ObjectMonitorsHashtable::PtrList* list = get_entry(key); + if (list == nullptr || list->find(om) == nullptr) { + return false; + } + return true; +} + void MonitorList::add(ObjectMonitor* m) { ObjectMonitor* head; do { @@ -417,6 +451,14 @@ void ObjectSynchronizer::handle_sync_on_value_based_class(Handle obj, JavaThread } } +static bool useHeavyMonitors() { +#if defined(X86) || defined(AARCH64) || defined(PPC64) + return UseHeavyMonitors; +#else + return false; +#endif +} + // ----------------------------------------------------------------------------- // Monitor Enter/Exit // The interpreter and compiler assembly code tries to lock using the fast path @@ -428,28 +470,33 @@ void ObjectSynchronizer::enter(Handle obj, BasicLock* lock, JavaThread* current) handle_sync_on_value_based_class(obj, current); } - markWord mark = obj->mark(); - if (mark.is_neutral()) { - // Anticipate successful CAS -- the ST of the displaced mark must - // be visible <= the ST performed by the CAS. - lock->set_displaced_header(mark); - if (mark == obj()->cas_set_mark(markWord::from_pointer(lock), mark)) { + if (!useHeavyMonitors()) { + markWord mark = obj->mark(); + if (mark.is_neutral()) { + // Anticipate successful CAS -- the ST of the displaced mark must + // be visible <= the ST performed by the CAS. + lock->set_displaced_header(mark); + if (mark == obj()->cas_set_mark(markWord::from_pointer(lock), mark)) { + return; + } + // Fall through to inflate() ... + } else if (mark.has_locker() && + current->is_lock_owned((address)mark.locker())) { + assert(lock != mark.locker(), "must not re-lock the same lock"); + assert(lock != (BasicLock*)obj->mark().value(), "don't relock with same BasicLock"); + lock->set_displaced_header(markWord::from_pointer(NULL)); return; } - // Fall through to inflate() ... - } else if (mark.has_locker() && - current->is_lock_owned((address)mark.locker())) { - assert(lock != mark.locker(), "must not re-lock the same lock"); - assert(lock != (BasicLock*)obj->mark().value(), "don't relock with same BasicLock"); - lock->set_displaced_header(markWord::from_pointer(NULL)); - return; + + // The object header will never be displaced to this lock, + // so it does not matter what the value is, except that it + // must be non-zero to avoid looking like a re-entrant lock, + // and must not look locked either. + lock->set_displaced_header(markWord::unused_mark()); + } else if (VerifyHeavyMonitors) { + guarantee(!obj->mark().has_locker(), "must not be stack-locked"); } - // The object header will never be displaced to this lock, - // so it does not matter what the value is, except that it - // must be non-zero to avoid looking like a re-entrant lock, - // and must not look locked either. - lock->set_displaced_header(markWord::unused_mark()); // An async deflation can race after the inflate() call and before // enter() can make the ObjectMonitor busy. enter() returns false if // we have lost the race to async deflation and we simply try again. @@ -462,45 +509,49 @@ void ObjectSynchronizer::enter(Handle obj, BasicLock* lock, JavaThread* current) } void ObjectSynchronizer::exit(oop object, BasicLock* lock, JavaThread* current) { - markWord mark = object->mark(); + if (!useHeavyMonitors()) { + markWord mark = object->mark(); - markWord dhw = lock->displaced_header(); - if (dhw.value() == 0) { - // If the displaced header is NULL, then this exit matches up with - // a recursive enter. No real work to do here except for diagnostics. + markWord dhw = lock->displaced_header(); + if (dhw.value() == 0) { + // If the displaced header is NULL, then this exit matches up with + // a recursive enter. No real work to do here except for diagnostics. #ifndef PRODUCT - if (mark != markWord::INFLATING()) { - // Only do diagnostics if we are not racing an inflation. Simply - // exiting a recursive enter of a Java Monitor that is being - // inflated is safe; see the has_monitor() comment below. - assert(!mark.is_neutral(), "invariant"); - assert(!mark.has_locker() || - current->is_lock_owned((address)mark.locker()), "invariant"); - if (mark.has_monitor()) { - // The BasicLock's displaced_header is marked as a recursive - // enter and we have an inflated Java Monitor (ObjectMonitor). - // This is a special case where the Java Monitor was inflated - // after this thread entered the stack-lock recursively. When a - // Java Monitor is inflated, we cannot safely walk the Java - // Monitor owner's stack and update the BasicLocks because a - // Java Monitor can be asynchronously inflated by a thread that - // does not own the Java Monitor. - ObjectMonitor* m = mark.monitor(); - assert(m->object()->mark() == mark, "invariant"); - assert(m->is_entered(current), "invariant"); + if (mark != markWord::INFLATING()) { + // Only do diagnostics if we are not racing an inflation. Simply + // exiting a recursive enter of a Java Monitor that is being + // inflated is safe; see the has_monitor() comment below. + assert(!mark.is_neutral(), "invariant"); + assert(!mark.has_locker() || + current->is_lock_owned((address)mark.locker()), "invariant"); + if (mark.has_monitor()) { + // The BasicLock's displaced_header is marked as a recursive + // enter and we have an inflated Java Monitor (ObjectMonitor). + // This is a special case where the Java Monitor was inflated + // after this thread entered the stack-lock recursively. When a + // Java Monitor is inflated, we cannot safely walk the Java + // Monitor owner's stack and update the BasicLocks because a + // Java Monitor can be asynchronously inflated by a thread that + // does not own the Java Monitor. + ObjectMonitor* m = mark.monitor(); + assert(m->object()->mark() == mark, "invariant"); + assert(m->is_entered(current), "invariant"); + } } - } #endif - return; - } - - if (mark == markWord::from_pointer(lock)) { - // If the object is stack-locked by the current thread, try to - // swing the displaced header from the BasicLock back to the mark. - assert(dhw.is_neutral(), "invariant"); - if (object->cas_set_mark(dhw, mark) == mark) { return; } + + if (mark == markWord::from_pointer(lock)) { + // If the object is stack-locked by the current thread, try to + // swing the displaced header from the BasicLock back to the mark. + assert(dhw.is_neutral(), "invariant"); + if (object->cas_set_mark(dhw, mark) == mark) { + return; + } + } + } else if (VerifyHeavyMonitors) { + guarantee(!object->mark().has_locker(), "must not be stack-locked"); } // We have to take the slow-path of possible inflation and then exit. @@ -804,7 +855,10 @@ intptr_t ObjectSynchronizer::FastHashCode(Thread* current, oop obj) { markWord temp, test; intptr_t hash; markWord mark = read_stable_mark(obj); - + if (VerifyHeavyMonitors) { + assert(UseHeavyMonitors, "+VerifyHeavyMonitors requires +UseHeavyMonitors"); + guarantee(!mark.has_locker(), "must not be stack locked"); + } if (mark.is_neutral()) { // if this is a normal header hash = mark.hash(); if (hash != 0) { // if it has a hash, just return it @@ -972,11 +1026,18 @@ JavaThread* ObjectSynchronizer::get_lock_owner(ThreadsList * t_list, Handle h_ob // Visitors ... +// Iterate ObjectMonitors where the owner == thread; this does NOT include +// ObjectMonitors where owner is set to a stack lock address in thread. +// +// This version of monitors_iterate() works with the in-use monitor list. +// void ObjectSynchronizer::monitors_iterate(MonitorClosure* closure, JavaThread* thread) { MonitorList::Iterator iter = _in_use_list.iterator(); while (iter.has_next()) { ObjectMonitor* mid = iter.next(); if (mid->owner() != thread) { + // Not owned by the target thread and intentionally skips when owner + // is set to a stack lock address in the target thread. continue; } if (!mid->is_being_async_deflated() && mid->object_peek() != NULL) { @@ -993,6 +1054,31 @@ void ObjectSynchronizer::monitors_iterate(MonitorClosure* closure, JavaThread* t } } +// This version of monitors_iterate() works with the specified linked list. +// +void ObjectSynchronizer::monitors_iterate(MonitorClosure* closure, + ObjectMonitorsHashtable::PtrList* list, + JavaThread* thread) { + typedef LinkedListIterator ObjectMonitorIterator; + ObjectMonitorIterator iter(list->head()); + while (!iter.is_empty()) { + ObjectMonitor* mid = *iter.next(); + // Owner set to a stack lock address in thread should never be seen here: + assert(mid->owner() == thread, "must be"); + if (!mid->is_being_async_deflated() && mid->object_peek() != NULL) { + // Only process with closure if the object is set. + + // monitors_iterate() is only called at a safepoint or when the + // target thread is suspended or when the target thread is + // operating on itself. The current closures in use today are + // only interested in an owned ObjectMonitor and ownership + // cannot be dropped under the calling contexts so the + // ObjectMonitor cannot be async deflated. + closure->do_monitor(mid); + } + } +} + static bool monitors_used_above_threshold(MonitorList* list) { if (MonitorUsedDeflationThreshold == 0) { // disabled case is easy return false; @@ -1318,8 +1404,17 @@ void ObjectSynchronizer::chk_for_block_req(JavaThread* current, const char* op_n // Walk the in-use list and deflate (at most MonitorDeflationMax) idle // ObjectMonitors. Returns the number of deflated ObjectMonitors. +// +// If table != nullptr, we gather owned ObjectMonitors indexed by the +// owner in the table. Please note that ObjectMonitors where the owner +// is set to a stack lock address are NOT associated with the JavaThread +// that holds that stack lock. All of the current consumers of +// ObjectMonitorsHashtable info only care about JNI locked monitors and +// those do not have the owner set to a stack lock address. +// size_t ObjectSynchronizer::deflate_monitor_list(Thread* current, LogStream* ls, - elapsedTimer* timer_p) { + elapsedTimer* timer_p, + ObjectMonitorsHashtable* table) { MonitorList::Iterator iter = _in_use_list.iterator(); size_t deflated_count = 0; @@ -1330,6 +1425,18 @@ size_t ObjectSynchronizer::deflate_monitor_list(Thread* current, LogStream* ls, ObjectMonitor* mid = iter.next(); if (mid->deflate_monitor()) { deflated_count++; + } else if (table != nullptr) { + // The caller is interested in the owned ObjectMonitors. This does + // not include when owner is set to a stack lock address in thread. + // This also does not capture unowned ObjectMonitors that cannot be + // deflated because of a waiter. + void* key = mid->owner(); + // Since deflate_idle_monitors() and deflate_monitor_list() can be + // called more than once, we have to make sure the entry has not + // already been added. + if (key != nullptr && !table->has_entry(key, mid)) { + table->add_entry(key, mid); + } } if (current->is_Java_thread()) { @@ -1354,8 +1461,8 @@ class HandshakeForDeflation : public HandshakeClosure { // This function is called by the MonitorDeflationThread to deflate // ObjectMonitors. It is also called via do_final_audit_and_print_stats() -// by the VMThread. -size_t ObjectSynchronizer::deflate_idle_monitors() { +// and VM_ThreadDump::doit() by the VMThread. +size_t ObjectSynchronizer::deflate_idle_monitors(ObjectMonitorsHashtable* table) { Thread* current = Thread::current(); if (current->is_Java_thread()) { // The async deflation request has been processed. @@ -1380,7 +1487,7 @@ size_t ObjectSynchronizer::deflate_idle_monitors() { } // Deflate some idle ObjectMonitors. - size_t deflated_count = deflate_monitor_list(current, ls, &timer); + size_t deflated_count = deflate_monitor_list(current, ls, &timer, table); if (deflated_count > 0 || is_final_audit()) { // There are ObjectMonitors that have been deflated or this is the // final audit and all the remaining ObjectMonitors have been @@ -1438,6 +1545,10 @@ size_t ObjectSynchronizer::deflate_idle_monitors() { } ls->print_cr("end deflating: in_use_list stats: ceiling=" SIZE_FORMAT ", count=" SIZE_FORMAT ", max=" SIZE_FORMAT, in_use_list_ceiling(), _in_use_list.count(), _in_use_list.max()); + if (table != nullptr) { + ls->print_cr("ObjectMonitorsHashtable: key_count=" SIZE_FORMAT ", om_count=" SIZE_FORMAT, + table->key_count(), table->om_count()); + } } OM_PERFDATA_OP(MonExtant, set_value(_in_use_list.count())); @@ -1540,7 +1651,7 @@ void ObjectSynchronizer::do_final_audit_and_print_stats() { // Do a deflation in order to reduce the in-use monitor population // that is reported by ObjectSynchronizer::log_in_use_monitor_details() // which is called by ObjectSynchronizer::audit_and_print_stats(). - while (ObjectSynchronizer::deflate_idle_monitors() != 0) { + while (ObjectSynchronizer::deflate_idle_monitors(/* ObjectMonitorsHashtable is not needed here */ nullptr) >= (size_t)MonitorDeflationMax) { ; // empty } // The other audit_and_print_stats() call is done at the Debug diff --git a/src/hotspot/share/runtime/synchronizer.hpp b/src/hotspot/share/runtime/synchronizer.hpp index 5a331e306eeb01fce5fa582fd88bc1d50033267c..6fc47813f9916605dc3932a6cceb91eca96712e5 100644 --- a/src/hotspot/share/runtime/synchronizer.hpp +++ b/src/hotspot/share/runtime/synchronizer.hpp @@ -30,11 +30,69 @@ #include "runtime/basicLock.hpp" #include "runtime/handles.hpp" #include "utilities/growableArray.hpp" +#include "utilities/linkedlist.hpp" +#include "utilities/resourceHash.hpp" class LogStream; class ObjectMonitor; class ThreadsList; +// Hash table of void* to a list of ObjectMonitor* owned by the JavaThread. +// The JavaThread's owner key is either a JavaThread* or a stack lock +// address in the JavaThread so we use "void*". +// +class ObjectMonitorsHashtable { + private: + static unsigned int ptr_hash(void* const& s1) { + // 2654435761 = 2^32 * Phi (golden ratio) + return (unsigned int)(((uint32_t)(uintptr_t)s1) * 2654435761u); + } + + public: + typedef LinkedListImpl PtrList; + + // ResourceHashtable SIZE is specified at compile time so we + // use 1031 which is the first prime after 1024. + typedef ResourceHashtable PtrTable; + private: + PtrTable* _ptrs; + size_t _key_count; + size_t _om_count; + + public: + // ResourceHashtable is passed to various functions and populated in + // different places so we allocate it using C_HEAP to make it immune + // from any ResourceMarks that happen to be in the code paths. + ObjectMonitorsHashtable() : _ptrs(new (ResourceObj::C_HEAP, mtThread) PtrTable()), _key_count(0), _om_count(0) {} + + ~ObjectMonitorsHashtable(); + + void add_entry(void* key, ObjectMonitor* om); + + void add_entry(void* key, PtrList* list) { + _ptrs->put(key, list); + _key_count++; + } + + PtrList* get_entry(void* key) { + PtrList** listpp = _ptrs->get(key); + return (listpp == nullptr) ? nullptr : *listpp; + } + + bool has_entry(void* key) { + PtrList** listpp = _ptrs->get(key); + return listpp != nullptr && *listpp != nullptr; + } + + bool has_entry(void* key, ObjectMonitor* om); + + size_t key_count() { return _key_count; } + size_t om_count() { return _om_count; } +}; + class MonitorList { friend class VMStructs; @@ -133,21 +191,30 @@ class ObjectSynchronizer : AllStatic { // JNI detach support static void release_monitors_owned_by_thread(JavaThread* current); + + // Iterate ObjectMonitors where the owner == thread; this does NOT include + // ObjectMonitors where owner is set to a stack lock address in thread: + // + // This version of monitors_iterate() works with the in-use monitor list. static void monitors_iterate(MonitorClosure* m, JavaThread* thread); + // This version of monitors_iterate() works with the specified linked list. + static void monitors_iterate(MonitorClosure* closure, + ObjectMonitorsHashtable::PtrList* list, + JavaThread* thread); // Initialize the gInflationLocks static void initialize(); - // GC: we current use aggressive monitor deflation policy + // GC: we currently use aggressive monitor deflation policy // Basically we try to deflate all monitors that are not busy. - static size_t deflate_idle_monitors(); + static size_t deflate_idle_monitors(ObjectMonitorsHashtable* table); // Deflate idle monitors: static void chk_for_block_req(JavaThread* current, const char* op_name, const char* cnt_name, size_t cnt, LogStream* ls, elapsedTimer* timer_p); - static size_t deflate_monitor_list(Thread* current, LogStream* ls, - elapsedTimer* timer_p); + static size_t deflate_monitor_list(Thread* current, LogStream* ls, elapsedTimer* timer_p, + ObjectMonitorsHashtable* table); static size_t in_use_list_ceiling(); static void dec_in_use_list_ceiling(); static void inc_in_use_list_ceiling(); diff --git a/src/hotspot/share/runtime/thread.cpp b/src/hotspot/share/runtime/thread.cpp index 1e776285412ed3120a84bb530754ff30e3ddb7a6..c1e327d40a5f00a54623b9f56d1a67be52ea1d5e 100644 --- a/src/hotspot/share/runtime/thread.cpp +++ b/src/hotspot/share/runtime/thread.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2021, Azul Systems, Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -317,7 +317,6 @@ void Thread::record_stack_base_and_size() { } } -#if INCLUDE_NMT void Thread::register_thread_stack_with_NMT() { MemTracker::record_thread_stack(stack_end(), stack_size()); } @@ -325,7 +324,6 @@ void Thread::register_thread_stack_with_NMT() { void Thread::unregister_thread_stack_with_NMT() { MemTracker::release_thread_stack(stack_end(), stack_size()); } -#endif // INCLUDE_NMT void Thread::call_run() { DEBUG_ONLY(_run_state = CALL_RUN;) @@ -338,10 +336,10 @@ void Thread::call_run() { // Perform common initialization actions - register_thread_stack_with_NMT(); - MACOS_AARCH64_ONLY(this->init_wx()); + register_thread_stack_with_NMT(); + JFR_ONLY(Jfr::on_thread_start(this);) log_debug(os, thread)("Thread " UINTX_FORMAT " stack dimensions: " @@ -1111,7 +1109,7 @@ void JavaThread::interrupt() { debug_only(check_for_dangling_thread_pointer(this);) // For Windows _interrupt_event - osthread()->set_interrupted(true); + WINDOWS_ONLY(osthread()->set_interrupted(true);) // For Thread.sleep _SleepEvent->unpark(); @@ -1156,7 +1154,7 @@ bool JavaThread::is_interrupted(bool clear_interrupted) { if (interrupted && clear_interrupted) { assert(this == Thread::current(), "only the current thread can clear"); java_lang_Thread::set_interrupted(threadObj(), false); - osthread()->set_interrupted(false); + WINDOWS_ONLY(osthread()->set_interrupted(false);) } return interrupted; @@ -1375,23 +1373,24 @@ void JavaThread::exit(bool destroy_vm, ExitType exit_type) { } } - // Call Thread.exit(). We try 3 times in case we got another Thread.stop during - // the execution of the method. If that is not enough, then we don't really care. Thread.stop - // is deprecated anyhow. if (!is_Compiler_thread()) { - int count = 3; - while (java_lang_Thread::threadGroup(threadObj()) != NULL && (count-- > 0)) { - EXCEPTION_MARK; - JavaValue result(T_VOID); - Klass* thread_klass = vmClasses::Thread_klass(); - JavaCalls::call_virtual(&result, - threadObj, thread_klass, - vmSymbols::exit_method_name(), - vmSymbols::void_method_signature(), - THREAD); - CLEAR_PENDING_EXCEPTION; - } + // We have finished executing user-defined Java code and now have to do the + // implementation specific clean-up by calling Thread.exit(). We prevent any + // asynchronous exceptions from being delivered while in Thread.exit() + // to ensure the clean-up is not corrupted. + NoAsyncExceptionDeliveryMark _no_async(this); + + EXCEPTION_MARK; + JavaValue result(T_VOID); + Klass* thread_klass = vmClasses::Thread_klass(); + JavaCalls::call_virtual(&result, + threadObj, thread_klass, + vmSymbols::exit_method_name(), + vmSymbols::void_method_signature(), + THREAD); + CLEAR_PENDING_EXCEPTION; } + // notify JVMTI if (JvmtiExport::should_post_thread_life()) { JvmtiExport::post_thread_end(this); @@ -1594,7 +1593,7 @@ void JavaThread::check_and_handle_async_exceptions() { // If we are at a polling page safepoint (not a poll return) // then we must defer async exception because live registers // will be clobbered by the exception path. Poll return is - // ok because the call we a returning from already collides + // ok because the call we are returning from already collides // with exception handling registers and so there is no issue. // (The exception handling path kills call result registers but // this is ok since the exception kills the result anyway). @@ -1615,6 +1614,9 @@ void JavaThread::check_and_handle_async_exceptions() { } if (!clear_async_exception_condition()) { + if ((_suspend_flags & _async_delivery_disabled) != 0) { + log_info(exceptions)("Async exception delivery is disabled"); + } return; } @@ -1646,24 +1648,10 @@ void JavaThread::check_and_handle_async_exceptions() { // We may be at method entry which requires we save the do-not-unlock flag. UnlockFlagSaver fs(this); - switch (thread_state()) { - case _thread_in_vm: { - JavaThread* THREAD = this; - Exceptions::throw_unsafe_access_internal_error(THREAD, __FILE__, __LINE__, "a fault occurred in an unsafe memory access operation"); - // We might have blocked in a ThreadBlockInVM wrapper in the call above so make sure we process pending - // suspend requests and object reallocation operations if any since we might be going to Java after this. - SafepointMechanism::process_if_requested_with_exit_check(this, true /* check asyncs */); - return; - } - case _thread_in_Java: { - ThreadInVMfromJava tiv(this); - JavaThread* THREAD = this; - Exceptions::throw_unsafe_access_internal_error(THREAD, __FILE__, __LINE__, "a fault occurred in an unsafe memory access operation in compiled Java code"); - return; - } - default: - ShouldNotReachHere(); - } + Exceptions::throw_unsafe_access_internal_error(this, __FILE__, __LINE__, "a fault occurred in an unsafe memory access operation"); + // We might have blocked in a ThreadBlockInVM wrapper in the call above so make sure we process pending + // suspend requests and object reallocation operations if any since we might be going to Java after this. + SafepointMechanism::process_if_requested_with_exit_check(this, true /* check asyncs */); } } @@ -1770,27 +1758,19 @@ bool JavaThread::java_resume() { } // Wait for another thread to perform object reallocation and relocking on behalf of -// this thread. -// Raw thread state transition to _thread_blocked and back again to the original -// state before returning are performed. The current thread is required to -// change to _thread_blocked in order to be seen to be safepoint/handshake safe -// whilst suspended and only after becoming handshake safe, the other thread can -// complete the handshake used to synchronize with this thread and then perform -// the reallocation and relocking. We cannot use the thread state transition -// helpers because we arrive here in various states and also because the helpers -// indirectly call this method. After leaving _thread_blocked we have to check -// for safepoint/handshake, except if _thread_in_native. The thread is safe -// without blocking then. Allowed states are enumerated in -// SafepointSynchronize::block(). See also EscapeBarrier::sync_and_suspend_*() +// this thread. The current thread is required to change to _thread_blocked in order +// to be seen to be safepoint/handshake safe whilst suspended and only after becoming +// handshake safe, the other thread can complete the handshake used to synchronize +// with this thread and then perform the reallocation and relocking. +// See EscapeBarrier::sync_and_suspend_*() void JavaThread::wait_for_object_deoptimization() { assert(!has_last_Java_frame() || frame_anchor()->walkable(), "should have walkable stack"); assert(this == Thread::current(), "invariant"); - JavaThreadState state = thread_state(); bool spin_wait = os::is_MP(); do { - set_thread_state(_thread_blocked); + ThreadBlockInVM tbivm(this, true /* allow_suspend */); // Wait for object deoptimization if requested. if (spin_wait) { // A single deoptimization is typically very short. Microbenchmarks @@ -1808,14 +1788,6 @@ void JavaThread::wait_for_object_deoptimization() { ml.wait(); } } - // The current thread could have been suspended again. We have to check for - // suspend after restoring the saved state. Without this the current thread - // might return to _thread_in_Java and execute bytecode. - set_thread_state_fence(state); - - if (state != _thread_in_native) { - SafepointMechanism::process_if_requested(this); - } // A handshake for obj. deoptimization suspend could have been processed so // we must check after processing. } while (is_obj_deopt_suspend()); @@ -2734,10 +2706,8 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) { jint parse_result = Arguments::parse(args); if (parse_result != JNI_OK) return parse_result; -#if INCLUDE_NMT // Initialize NMT right after argument parsing to keep the pre-NMT-init window small. MemTracker::initialize(); -#endif // INCLUDE_NMT os::init_before_ergo(); @@ -3303,8 +3273,8 @@ void JavaThread::invoke_shutdown_hooks() { // Link all classes for dynamic CDS dumping before vm exit. // Same operation is being done in JVM_BeforeHalt for handling the // case where the application calls System.exit(). - if (DynamicDumpSharedSpaces) { - DynamicArchive::prepare_for_dynamic_dumping(); + if (DynamicArchive::should_dump_at_vm_exit()) { + DynamicArchive::prepare_for_dump_at_exit(); } #endif diff --git a/src/hotspot/share/runtime/thread.hpp b/src/hotspot/share/runtime/thread.hpp index 74916b982759d81b8c2e0ad17320696cbf356262..4256a44c39c4c217eeee57b915cb53f8cbeddaea 100644 --- a/src/hotspot/share/runtime/thread.hpp +++ b/src/hotspot/share/runtime/thread.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2021, Azul Systems, Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -550,8 +550,8 @@ protected: void set_stack_size(size_t size) { _stack_size = size; } address stack_end() const { return stack_base() - stack_size(); } void record_stack_base_and_size(); - void register_thread_stack_with_NMT() NOT_NMT_RETURN; - void unregister_thread_stack_with_NMT() NOT_NMT_RETURN; + void register_thread_stack_with_NMT(); + void unregister_thread_stack_with_NMT(); int lgrp_id() const { return _lgrp_id; } void set_lgrp_id(int value) { _lgrp_id = value; } @@ -785,9 +785,10 @@ class JavaThread: public Thread { enum SuspendFlags { // NOTE: avoid using the sign-bit as cc generates different test code // when the sign-bit is used, and sometimes incorrectly - see CR 6398077 - _has_async_exception = 0x00000001U, // there is a pending async exception - _trace_flag = 0x00000004U, // call tracing backend - _obj_deopt = 0x00000008U // suspend for object reallocation and relocking for JVMTI agent + _has_async_exception = 0x00000001U, // there is a pending async exception + _async_delivery_disabled = 0x00000002U, // async exception delivery is disabled + _trace_flag = 0x00000004U, // call tracing backend + _obj_deopt = 0x00000008U // suspend for object reallocation and relocking for JVMTI agent }; // various suspension related flags - atomically updated @@ -815,7 +816,8 @@ class JavaThread: public Thread { inline bool clear_async_exception_condition(); public: bool has_async_exception_condition() { - return (_suspend_flags & _has_async_exception) != 0; + return (_suspend_flags & _has_async_exception) != 0 && + (_suspend_flags & _async_delivery_disabled) == 0; } inline void set_pending_async_exception(oop e); inline void set_pending_unsafe_access_error(); @@ -823,6 +825,13 @@ class JavaThread: public Thread { void send_thread_stop(oop throwable); void check_and_handle_async_exceptions(); + class NoAsyncExceptionDeliveryMark : public StackObj { + friend JavaThread; + JavaThread *_target; + inline NoAsyncExceptionDeliveryMark(JavaThread *t); + inline ~NoAsyncExceptionDeliveryMark(); + }; + // Safepoint support public: // Expose _thread_state for SafeFetchInt() volatile JavaThreadState _thread_state; @@ -1299,6 +1308,12 @@ class JavaThread: public Thread { static ByteSize reserved_stack_activation_offset() { return byte_offset_of(JavaThread, _stack_overflow_state._reserved_stack_activation); } + static ByteSize shadow_zone_safe_limit() { + return byte_offset_of(JavaThread, _stack_overflow_state._shadow_zone_safe_limit); + } + static ByteSize shadow_zone_growth_watermark() { + return byte_offset_of(JavaThread, _stack_overflow_state._shadow_zone_growth_watermark); + } static ByteSize suspend_flags_offset() { return byte_offset_of(JavaThread, _suspend_flags); } @@ -1312,16 +1327,22 @@ class JavaThread: public Thread { // Returns the jni environment for this thread JNIEnv* jni_environment() { return &_jni_environment; } + // Returns the current thread as indicated by the given JNIEnv. + // We don't assert it is Thread::current here as that is done at the + // external JNI entry points where the JNIEnv is passed into the VM. static JavaThread* thread_from_jni_environment(JNIEnv* env) { - JavaThread *thread_from_jni_env = (JavaThread*)((intptr_t)env - in_bytes(jni_environment_offset())); - // Only return NULL if thread is off the thread list; starting to - // exit should not return NULL. - if (thread_from_jni_env->is_terminated()) { - thread_from_jni_env->block_if_vm_exited(); - return NULL; - } else { - return thread_from_jni_env; + JavaThread* current = (JavaThread*)((intptr_t)env - in_bytes(jni_environment_offset())); + // We can't normally get here in a thread that has completed its + // execution and so "is_terminated", except when the call is from + // AsyncGetCallTrace, which can be triggered by a signal at any point in + // a thread's lifecycle. A thread is also considered terminated if the VM + // has exited, so we have to check this and block in case this is a daemon + // thread returning to the VM (the JNI DirectBuffer entry points rely on + // this). + if (current->is_terminated()) { + current->block_if_vm_exited(); } + return current; } // JNI critical regions. These can nest. diff --git a/src/hotspot/share/runtime/thread.inline.hpp b/src/hotspot/share/runtime/thread.inline.hpp index 7d27a3bf257cacbeb075f15dac7e60611108ac35..cdb8d9abb230752d3f186d19e701147669064b2b 100644 --- a/src/hotspot/share/runtime/thread.inline.hpp +++ b/src/hotspot/share/runtime/thread.inline.hpp @@ -124,7 +124,9 @@ inline void JavaThread::clear_obj_deopt_flag() { inline bool JavaThread::clear_async_exception_condition() { bool ret = has_async_exception_condition(); - clear_suspend_flag(_has_async_exception); + if (ret) { + clear_suspend_flag(_has_async_exception); + } return ret; } @@ -138,6 +140,15 @@ inline void JavaThread::set_pending_unsafe_access_error() { DEBUG_ONLY(_is_unsafe_access_error = true); } + +inline JavaThread::NoAsyncExceptionDeliveryMark::NoAsyncExceptionDeliveryMark(JavaThread *t) : _target(t) { + assert((_target->_suspend_flags & _async_delivery_disabled) == 0, "Nesting is not supported"); + _target->set_suspend_flag(_async_delivery_disabled); +} +inline JavaThread::NoAsyncExceptionDeliveryMark::~NoAsyncExceptionDeliveryMark() { + _target->clear_suspend_flag(_async_delivery_disabled); +} + inline JavaThreadState JavaThread::thread_state() const { #if defined(PPC64) || defined (AARCH64) // Use membars when accessing volatile _thread_state. See diff --git a/src/hotspot/share/runtime/threadLocalStorage.hpp b/src/hotspot/share/runtime/threadLocalStorage.hpp index 93607612a4dc38751e9e0130eadfd70076e3f919..604b624757e6f5dd3ca19742c4313ba157136a02 100644 --- a/src/hotspot/share/runtime/threadLocalStorage.hpp +++ b/src/hotspot/share/runtime/threadLocalStorage.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -25,7 +25,7 @@ #ifndef SHARE_RUNTIME_THREADLOCALSTORAGE_HPP #define SHARE_RUNTIME_THREADLOCALSTORAGE_HPP -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" // forward-decl as we can't have an include cycle class Thread; diff --git a/src/hotspot/share/runtime/vframe.cpp b/src/hotspot/share/runtime/vframe.cpp index adf3c938d8d609d7571d39029011de3b25405dfe..14f4ee3a28c8c34ef976f23416a00e93179d8e21 100644 --- a/src/hotspot/share/runtime/vframe.cpp +++ b/src/hotspot/share/runtime/vframe.cpp @@ -608,13 +608,11 @@ javaVFrame* vframeStreamCommon::asJavaVFrame() { return result; } - #ifndef PRODUCT void vframe::print() { if (WizardMode) _fr.print_value_on(tty,NULL); } - void vframe::print_value() const { ((vframe*)this)->print(); } diff --git a/src/hotspot/share/runtime/vframeArray.cpp b/src/hotspot/share/runtime/vframeArray.cpp index 2c5bf70c4ac4a33006041ca15e48ff265a56fb51..2106ed7ef7c75a9e20ab9be308458c0aed1318c9 100644 --- a/src/hotspot/share/runtime/vframeArray.cpp +++ b/src/hotspot/share/runtime/vframeArray.cpp @@ -324,9 +324,11 @@ void vframeArrayElement::unpack_on_stack(int caller_actual_parameters, } } +#ifndef PRODUCT if (PrintDeoptimizationDetails) { tty->print_cr("Expressions size: %d", expressions()->size()); } +#endif // !PRODUCT // Unpack expression stack // If this is an intermediate frame (i.e. not top frame) then this @@ -337,20 +339,21 @@ void vframeArrayElement::unpack_on_stack(int caller_actual_parameters, for(i = 0; i < expressions()->size(); i++) { StackValue *value = expressions()->at(i); intptr_t* addr = iframe()->interpreter_frame_expression_stack_at(i); + assert(!is_bottom_frame || !(caller->is_compiled_caller() && addr >= caller->unextended_sp()), "overwriting caller frame!"); switch(value->type()) { case T_INT: *addr = value->get_int(); #ifndef PRODUCT if (PrintDeoptimizationDetails) { - tty->print_cr("Reconstructed expression %d (INT): %d", i, (int)(*addr)); + tty->print_cr(" - Reconstructed expression %d (INT): %d", i, (int)(*addr)); } -#endif +#endif // !PRODUCT break; case T_OBJECT: *addr = value->get_int(T_OBJECT); #ifndef PRODUCT if (PrintDeoptimizationDetails) { - tty->print("Reconstructed expression %d (OBJECT): ", i); + tty->print(" - Reconstructed expression %d (OBJECT): ", i); oop o = cast_to_oop((address)(*addr)); if (o == NULL) { tty->print_cr("NULL"); @@ -359,7 +362,7 @@ void vframeArrayElement::unpack_on_stack(int caller_actual_parameters, tty->print_raw_cr(o->klass()->name()->as_C_string()); } } -#endif +#endif // !PRODUCT break; case T_CONFLICT: // A dead stack slot. Initialize to null in case it is an oop. @@ -370,25 +373,31 @@ void vframeArrayElement::unpack_on_stack(int caller_actual_parameters, } } +#ifndef PRODUCT + if (PrintDeoptimizationDetails) { + tty->print_cr("Locals size: %d", locals()->size()); + } +#endif // !PRODUCT // Unpack the locals for(i = 0; i < locals()->size(); i++) { StackValue *value = locals()->at(i); intptr_t* addr = iframe()->interpreter_frame_local_at(i); + assert(!is_bottom_frame || !(caller->is_compiled_caller() && addr >= caller->unextended_sp()), "overwriting caller frame!"); switch(value->type()) { case T_INT: *addr = value->get_int(); #ifndef PRODUCT if (PrintDeoptimizationDetails) { - tty->print_cr("Reconstructed local %d (INT): %d", i, (int)(*addr)); + tty->print_cr(" - Reconstructed local %d (INT): %d", i, (int)(*addr)); } -#endif +#endif // !PRODUCT break; case T_OBJECT: *addr = value->get_int(T_OBJECT); #ifndef PRODUCT if (PrintDeoptimizationDetails) { - tty->print("Reconstructed local %d (OBJECT): ", i); + tty->print(" - Reconstructed local %d (OBJECT): ", i); oop o = cast_to_oop((address)(*addr)); if (o == NULL) { tty->print_cr("NULL"); @@ -397,7 +406,7 @@ void vframeArrayElement::unpack_on_stack(int caller_actual_parameters, tty->print_raw_cr(o->klass()->name()->as_C_string()); } } -#endif +#endif // !PRODUCT break; case T_CONFLICT: // A dead location. If it is an oop then we need a NULL to prevent GC from following it @@ -441,28 +450,15 @@ void vframeArrayElement::unpack_on_stack(int caller_actual_parameters, #ifndef PRODUCT if (PrintDeoptimizationDetails) { ttyLocker ttyl; - tty->print_cr("[%d Interpreted Frame]", ++unpack_counter); + tty->print_cr("[%d. Interpreted Frame]", ++unpack_counter); iframe()->print_on(tty); RegisterMap map(thread); vframe* f = vframe::new_vframe(iframe(), &map, thread); f->print(); - - tty->print_cr("locals size %d", locals()->size()); - tty->print_cr("expression size %d", expressions()->size()); - - method()->print_value(); + if (WizardMode && Verbose) method()->print_codes(); tty->cr(); - // method()->print_codes(); - } else if (TraceDeoptimization) { - tty->print(" "); - method()->print_value(); - Bytecodes::Code code = Bytecodes::java_code_at(method(), bcp); - int bci = method()->bci_from(bcp); - tty->print(" - %s", Bytecodes::name(code)); - tty->print(" @ bci %d ", bci); - tty->print_cr("sp = " PTR_FORMAT, p2i(iframe()->sp())); } -#endif // PRODUCT +#endif // !PRODUCT // The expression stack and locals are in the resource area don't leave // a dangling pointer in the vframeArray we leave around for debug @@ -569,6 +565,7 @@ void vframeArray::unpack_to_stack(frame &unpack_frame, int exec_mode, int caller // Find the skeletal interpreter frames to unpack into JavaThread* current = JavaThread::current(); + RegisterMap map(current, false); // Get the youngest frame we will unpack (last to be unpacked) frame me = unpack_frame.sender(&map); @@ -579,6 +576,18 @@ void vframeArray::unpack_to_stack(frame &unpack_frame, int exec_mode, int caller me = me.sender(&map); } + Events::log_deopt_message(current, "DEOPT UNPACKING pc=" INTPTR_FORMAT " sp=" INTPTR_FORMAT " mode %d", + p2i(unpack_frame.pc()), p2i(unpack_frame.sp()), exec_mode); + + if (TraceDeoptimization) { + ResourceMark rm; + stringStream st; + st.print_cr("DEOPT UNPACKING thread=" INTPTR_FORMAT " vframeArray=" INTPTR_FORMAT " mode=%d", + p2i(current), p2i(this), exec_mode); + st.print_cr(" Virtual frames (outermost/oldest first):"); + tty->print_raw(st.as_string()); + } + // Do the unpacking of interpreter frames; the frame at index 0 represents the top activation, so it has no callee // Unpack the frames from the oldest (frames() -1) to the youngest (0) frame* caller_frame = &me; @@ -598,6 +607,24 @@ void vframeArray::unpack_to_stack(frame &unpack_frame, int exec_mode, int caller callee_parameters = callee->size_of_parameters() + (has_member_arg ? 1 : 0); callee_locals = callee->max_locals(); } + if (TraceDeoptimization) { + ResourceMark rm; + stringStream st; + st.print(" VFrame %d (" INTPTR_FORMAT ")", index, p2i(elem)); + st.print(" - %s", elem->method()->name_and_sig_as_C_string()); + int bci = elem->raw_bci(); + const char* code_name; + if (bci == SynchronizationEntryBCI) { + code_name = "sync entry"; + } else { + Bytecodes::Code code = elem->method()->code_at(bci); + code_name = Bytecodes::name(code); + } + st.print(" - %s", code_name); + st.print(" @ bci=%d ", bci); + st.print_cr("sp=" PTR_FORMAT, p2i(elem->iframe()->sp())); + tty->print_raw(st.as_string()); + } elem->unpack_on_stack(caller_actual_parameters, callee_parameters, callee_locals, @@ -612,6 +639,9 @@ void vframeArray::unpack_to_stack(frame &unpack_frame, int exec_mode, int caller caller_actual_parameters = callee_parameters; } deallocate_monitor_chunks(); + if (TraceDeoptimization) { + tty->cr(); + } } void vframeArray::deallocate_monitor_chunks() { @@ -639,7 +669,7 @@ bool vframeArray::structural_compare(JavaThread* thread, GrowableArray= (size_t)MonitorDeflationMax) { + ; /* empty */ + } + } + if (_num_threads == 0) { // Snapshot all live threads @@ -293,7 +305,7 @@ void VM_ThreadDump::doit() { if (_with_locked_synchronizers) { tcl = concurrent_locks.thread_concurrent_locks(jt); } - snapshot_thread(jt, tcl); + snapshot_thread(jt, tcl, tablep); } } else { // Snapshot threads in the given _threads array @@ -328,14 +340,15 @@ void VM_ThreadDump::doit() { if (_with_locked_synchronizers) { tcl = concurrent_locks.thread_concurrent_locks(jt); } - snapshot_thread(jt, tcl); + snapshot_thread(jt, tcl, tablep); } } } -void VM_ThreadDump::snapshot_thread(JavaThread* java_thread, ThreadConcurrentLocks* tcl) { +void VM_ThreadDump::snapshot_thread(JavaThread* java_thread, ThreadConcurrentLocks* tcl, + ObjectMonitorsHashtable* table) { ThreadSnapshot* snapshot = _result->add_thread_snapshot(java_thread); - snapshot->dump_stack_at_safepoint(_max_depth, _with_locked_monitors); + snapshot->dump_stack_at_safepoint(_max_depth, _with_locked_monitors, table); snapshot->set_concurrent_locks(tcl); } diff --git a/src/hotspot/share/runtime/vmOperations.hpp b/src/hotspot/share/runtime/vmOperations.hpp index fa80d859b09fdd38c065f444e0267b83aa96ce87..262ac740c1c0fbe683c7de0a89b14c3040492fee 100644 --- a/src/hotspot/share/runtime/vmOperations.hpp +++ b/src/hotspot/share/runtime/vmOperations.hpp @@ -32,54 +32,50 @@ // A hodge podge of commonly used VM Operations -class VM_None: public VM_Operation { - const char* _reason; - public: - VM_None(const char* reason) : _reason(reason) {} - const char* name() const { return _reason; } - VMOp_Type type() const { return VMOp_None; } - void doit() {}; +class VM_EmptyOperation : public VM_Operation { +public: + virtual void doit() final {} + virtual bool skip_thread_oop_barriers() const final { + // Neither the doit function nor the the safepoint + // cleanup tasks read oops in the Java threads. + return true; + } }; -class VM_Cleanup: public VM_Operation { +class VM_Halt: public VM_EmptyOperation { public: - VMOp_Type type() const { return VMOp_Cleanup; } - void doit() {}; + VMOp_Type type() const { return VMOp_Halt; } }; -class VM_ClearICs: public VM_Operation { - private: - bool _preserve_static_stubs; +class VM_SafepointALot: public VM_EmptyOperation { public: - VM_ClearICs(bool preserve_static_stubs) { _preserve_static_stubs = preserve_static_stubs; } - void doit(); - VMOp_Type type() const { return VMOp_ClearICs; } + VMOp_Type type() const { return VMOp_SafepointALot; } }; -// empty vm op, evaluated just to force a safepoint -class VM_ForceSafepoint: public VM_Operation { +class VM_Cleanup: public VM_EmptyOperation { public: - void doit() {} - VMOp_Type type() const { return VMOp_ForceSafepoint; } + VMOp_Type type() const { return VMOp_Cleanup; } }; -// empty vm op, when forcing a safepoint to suspend a thread -class VM_ThreadSuspend: public VM_ForceSafepoint { +// empty vm op, evaluated just to force a safepoint +class VM_ForceSafepoint: public VM_EmptyOperation { public: - VMOp_Type type() const { return VMOp_ThreadSuspend; } + VMOp_Type type() const { return VMOp_ForceSafepoint; } }; -// empty vm op, when forcing a safepoint to suspend threads from jvmti -class VM_ThreadsSuspendJVMTI: public VM_ForceSafepoint { +// empty vm op, when forcing a safepoint due to inline cache buffers being full +class VM_ICBufferFull: public VM_EmptyOperation { public: - VMOp_Type type() const { return VMOp_ThreadsSuspendJVMTI; } + VMOp_Type type() const { return VMOp_ICBufferFull; } }; -// empty vm op, when forcing a safepoint due to inline cache buffers being full -class VM_ICBufferFull: public VM_ForceSafepoint { +class VM_ClearICs: public VM_Operation { + private: + bool _preserve_static_stubs; public: - VMOp_Type type() const { return VMOp_ICBufferFull; } - virtual bool skip_thread_oop_barriers() const { return true; } + VM_ClearICs(bool preserve_static_stubs) { _preserve_static_stubs = preserve_static_stubs; } + void doit(); + VMOp_Type type() const { return VMOp_ClearICs; } }; // Base class for invoking parts of a gtest in a safepoint. @@ -207,7 +203,8 @@ class VM_ThreadDump : public VM_Operation { bool _with_locked_monitors; bool _with_locked_synchronizers; - void snapshot_thread(JavaThread* java_thread, ThreadConcurrentLocks* tcl); + void snapshot_thread(JavaThread* java_thread, ThreadConcurrentLocks* tcl, + ObjectMonitorsHashtable* table); public: VM_ThreadDump(ThreadDumpResult* result, diff --git a/src/hotspot/share/runtime/vmStructs.cpp b/src/hotspot/share/runtime/vmStructs.cpp index 89abff4a0a8d530e1d9935daa89405f5509fa641..bebae07e5fb8bf95f9da7b3abae9660440ca2b64 100644 --- a/src/hotspot/share/runtime/vmStructs.cpp +++ b/src/hotspot/share/runtime/vmStructs.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -660,7 +660,7 @@ nonstatic_field(nmethod, _verified_entry_point, address) \ nonstatic_field(nmethod, _osr_entry_point, address) \ volatile_nonstatic_field(nmethod, _lock_count, jint) \ - volatile_nonstatic_field(nmethod, _stack_traversal_mark, long) \ + volatile_nonstatic_field(nmethod, _stack_traversal_mark, int64_t) \ nonstatic_field(nmethod, _compile_id, int) \ nonstatic_field(nmethod, _comp_level, int) \ \ @@ -1199,6 +1199,7 @@ declare_integer_type(ssize_t) \ declare_integer_type(intx) \ declare_integer_type(intptr_t) \ + declare_integer_type(int64_t) \ declare_unsigned_integer_type(uintx) \ declare_unsigned_integer_type(uintptr_t) \ declare_unsigned_integer_type(uint8_t) \ @@ -1767,6 +1768,7 @@ declare_c2_type(DivVFNode, VectorNode) \ declare_c2_type(DivVDNode, VectorNode) \ declare_c2_type(PopCountVINode, VectorNode) \ + declare_c2_type(PopCountVLNode, VectorNode) \ declare_c2_type(LShiftVBNode, VectorNode) \ declare_c2_type(LShiftVSNode, VectorNode) \ declare_c2_type(LShiftVINode, VectorNode) \ @@ -1845,6 +1847,9 @@ declare_c2_type(VectorCastL2XNode, VectorNode) \ declare_c2_type(VectorCastF2XNode, VectorNode) \ declare_c2_type(VectorCastD2XNode, VectorNode) \ + declare_c2_type(VectorUCastB2XNode, VectorNode) \ + declare_c2_type(VectorUCastS2XNode, VectorNode) \ + declare_c2_type(VectorUCastI2XNode, VectorNode) \ declare_c2_type(VectorInsertNode, VectorNode) \ declare_c2_type(VectorUnboxNode, VectorNode) \ declare_c2_type(VectorReinterpretNode, VectorNode) \ diff --git a/src/hotspot/share/runtime/vmThread.cpp b/src/hotspot/share/runtime/vmThread.cpp index 2e601a11f60d2c64d0e6505f678a488d925c4248..e22c33984868d386e2ef09d17682cffe751c0c51 100644 --- a/src/hotspot/share/runtime/vmThread.cpp +++ b/src/hotspot/share/runtime/vmThread.cpp @@ -96,8 +96,8 @@ void VMOperationTimeoutTask::disarm() { //------------------------------------------------------------------------------------------------------------------ // Implementation of VMThread stuff -static VM_None safepointALot_op("SafepointALot"); -static VM_Cleanup cleanup_op; +static VM_SafepointALot safepointALot_op; +static VM_Cleanup cleanup_op; bool VMThread::_should_terminate = false; bool VMThread::_terminated = false; @@ -147,7 +147,7 @@ void VMThread::destroy() { _vm_thread = NULL; // VM thread is gone } -static VM_None halt_op("Halt"); +static VM_Halt halt_op; void VMThread::run() { assert(this == vm_thread(), "check"); diff --git a/src/hotspot/share/runtime/vmThread.hpp b/src/hotspot/share/runtime/vmThread.hpp index 23384c61257b6afbd3d8a6127a0976aab245452d..0d7d58e258799acefdd70bfa372bdc0ef26e5d27 100644 --- a/src/hotspot/share/runtime/vmThread.hpp +++ b/src/hotspot/share/runtime/vmThread.hpp @@ -53,8 +53,7 @@ public: }; // -// A single VMThread (the primordial thread) spawns all other threads -// and is itself used by other threads to offload heavy vm operations +// A single VMThread is used by other threads to offload heavy vm operations // like scavenge, garbage_collect etc. // @@ -78,7 +77,6 @@ class VMThread: public NamedThread { void inner_execute(VM_Operation* op); void wait_for_operation(); - public: // Constructor VMThread(); @@ -87,14 +85,15 @@ class VMThread: public NamedThread { guarantee(false, "VMThread deletion must fix the race with VM termination"); } + // The ever running loop for the VMThread + void loop(); + + public: bool is_running() const { return Atomic::load(&_is_running); } // Tester bool is_VM_thread() const { return true; } - // The ever running loop for the VMThread - void loop(); - // Called to stop the VM thread static void wait_for_vm_thread_exit(); static bool should_terminate() { return _should_terminate; } diff --git a/src/hotspot/share/services/attachListener.cpp b/src/hotspot/share/services/attachListener.cpp index 957b34112d590a63cae988769a36f2ef31a07af4..f916f43849ffb567eafbfe0fcdf581dd898b7216 100644 --- a/src/hotspot/share/services/attachListener.cpp +++ b/src/hotspot/share/services/attachListener.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -292,6 +292,7 @@ static jint heap_inspection(AttachOperation* op, outputStream* out) { uintx num; if (!Arguments::parse_uintx(num_str, &num, 0)) { out->print_cr("Invalid parallel thread number: [%s]", num_str); + delete fs; return JNI_ERR; } parallel_thread_num = num == 0 ? parallel_thread_num : (uint)num; diff --git a/src/hotspot/share/services/attachListener.hpp b/src/hotspot/share/services/attachListener.hpp index 25fad127d0f71f19aff92d064ab5b806c4b78c7a..5765240c16c36c95a01719f544c143b6ae269c30 100644 --- a/src/hotspot/share/services/attachListener.hpp +++ b/src/hotspot/share/services/attachListener.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -25,7 +25,7 @@ #ifndef SHARE_SERVICES_ATTACHLISTENER_HPP #define SHARE_SERVICES_ATTACHLISTENER_HPP -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" #include "runtime/atomic.hpp" #include "runtime/globals.hpp" #include "utilities/debug.hpp" diff --git a/src/hotspot/share/services/diagnosticArgument.cpp b/src/hotspot/share/services/diagnosticArgument.cpp index f10fe6c4641560b0cc7f9ec8b1da0022b61b88e3..3dd75009175e86a0c2422de3b67704cdea212926 100644 --- a/src/hotspot/share/services/diagnosticArgument.cpp +++ b/src/hotspot/share/services/diagnosticArgument.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 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 @@ -28,6 +28,7 @@ #include "memory/resourceArea.hpp" #include "runtime/thread.hpp" #include "services/diagnosticArgument.hpp" +#include "utilities/globalDefinitions.hpp" StringArrayArgument::StringArrayArgument() { _array = new (ResourceObj::C_HEAP, mtServiceability) GrowableArray(32, mtServiceability); @@ -114,13 +115,12 @@ template <> void DCmdArgument::parse_value(const char* str, || sscanf(str, JLONG_FORMAT "%n", &_value, &scanned) != 1 || (size_t)scanned != len) { - ResourceMark rm; - - char* buf = NEW_RESOURCE_ARRAY(char, len + 1); - strncpy(buf, str, len); - buf[len] = '\0'; + const int maxprint = 64; Exceptions::fthrow(THREAD_AND_LOCATION, vmSymbols::java_lang_IllegalArgumentException(), - "Integer parsing error in command argument '%s'. Could not parse: %s.\n", _name, buf); + "Integer parsing error in command argument '%s'. Could not parse: %.*s%s.\n", _name, + MIN2((int)len, maxprint), + (str == NULL ? "" : str), + (len > maxprint ? "..." : "")); } } diff --git a/src/hotspot/share/services/diagnosticCommand.cpp b/src/hotspot/share/services/diagnosticCommand.cpp index 1b3710cf004c2a47d8b17e9c8f171781745b1f18..725d801613429171236d9b2669a291ce62c331e1 100644 --- a/src/hotspot/share/services/diagnosticCommand.cpp +++ b/src/hotspot/share/services/diagnosticCommand.cpp @@ -26,6 +26,7 @@ #include "jvm.h" #include "classfile/classLoaderHierarchyDCmd.hpp" #include "classfile/classLoaderStats.hpp" +#include "classfile/classLoaderDataGraph.hpp" #include "classfile/javaClasses.hpp" #include "classfile/systemDictionary.hpp" #include "classfile/vmClasses.hpp" @@ -36,6 +37,7 @@ #include "memory/metaspace/metaspaceDCmd.hpp" #include "memory/resourceArea.hpp" #include "memory/universe.hpp" +#include "oops/instanceKlass.hpp" #include "oops/objArrayOop.inline.hpp" #include "oops/oop.inline.hpp" #include "oops/typeArrayOop.inline.hpp" @@ -101,6 +103,7 @@ void DCmdRegistrant::register_dcmds(){ DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); @@ -419,6 +422,11 @@ void HeapInfoDCmd::execute(DCmdSource source, TRAPS) { void FinalizerInfoDCmd::execute(DCmdSource source, TRAPS) { ResourceMark rm(THREAD); + if (!InstanceKlass::is_finalization_enabled()) { + output()->print_cr("Finalization is disabled"); + return; + } + Klass* k = SystemDictionary::resolve_or_fail( vmSymbols::finalizer_histogram_klass(), true, CHECK); @@ -906,8 +914,9 @@ void CompilerDirectivesClearDCmd::execute(DCmdSource source, TRAPS) { ClassHierarchyDCmd::ClassHierarchyDCmd(outputStream* output, bool heap) : DCmdWithParser(output, heap), _print_interfaces("-i", "Inherited interfaces should be printed.", "BOOLEAN", false, "false"), - _print_subclasses("-s", "If a classname is specified, print its subclasses. " - "Otherwise only its superclasses are printed.", "BOOLEAN", false, "false"), + _print_subclasses("-s", "If a classname is specified, print its subclasses " + "in addition to its superclasses. Without this option only the " + "superclasses will be printed.", "BOOLEAN", false, "false"), _classname("classname", "Name of class whose hierarchy should be printed. " "If not specified, all class hierarchies are printed.", "STRING", false) { @@ -947,6 +956,41 @@ void TouchedMethodsDCmd::execute(DCmdSource source, TRAPS) { VMThread::execute(&dumper); } +ClassesDCmd::ClassesDCmd(outputStream* output, bool heap) : + DCmdWithParser(output, heap), + _verbose("-verbose", + "Dump the detailed content of a Java class. " + "Some classes are annotated with flags: " + "F = has, or inherits, a non-empty finalize method, " + "f = has final method, " + "W = methods rewritten, " + "C = marked with @Contended annotation, " + "R = has been redefined, " + "S = is shared class", + "BOOLEAN", false, "false") { + _dcmdparser.add_dcmd_option(&_verbose); +} + +class VM_PrintClasses : public VM_Operation { +private: + outputStream* _out; + bool _verbose; +public: + VM_PrintClasses(outputStream* out, bool verbose) : _out(out), _verbose(verbose) {} + + virtual VMOp_Type type() const { return VMOp_PrintClasses; } + + virtual void doit() { + PrintClassClosure closure(_out, _verbose); + ClassLoaderDataGraph::classes_do(&closure); + } +}; + +void ClassesDCmd::execute(DCmdSource source, TRAPS) { + VM_PrintClasses vmop(output(), _verbose.is_set()); + VMThread::execute(&vmop); +} + #if INCLUDE_CDS DumpSharedArchiveDCmd::DumpSharedArchiveDCmd(outputStream* output, bool heap) : DCmdWithParser(output, heap), diff --git a/src/hotspot/share/services/diagnosticCommand.hpp b/src/hotspot/share/services/diagnosticCommand.hpp index d276a3ca7569cef4524cda7c43943a6af28e3495..dfcdc783f88c0298723f331da67a1b6afcade4b8 100644 --- a/src/hotspot/share/services/diagnosticCommand.hpp +++ b/src/hotspot/share/services/diagnosticCommand.hpp @@ -858,6 +858,28 @@ public: virtual void execute(DCmdSource source, TRAPS); }; +class ClassesDCmd : public DCmdWithParser { +protected: + DCmdArgument _verbose; +public: + ClassesDCmd(outputStream* output, bool heap); + static const char* name() { + return "VM.classes"; + } + static const char* description() { + return "Print all loaded classes"; + } + static const char* impact() { + return "Medium: Depends on number of loaded classes."; + } + static const JavaPermission permission() { + JavaPermission p = {"java.lang.management.ManagementPermission", + "monitor", NULL}; + return p; + } + virtual void execute(DCmdSource source, TRAPS); +}; + #if INCLUDE_JVMTI class DebugOnCmdStartDCmd : public DCmd { public: diff --git a/src/hotspot/share/services/dtraceAttacher.hpp b/src/hotspot/share/services/dtraceAttacher.hpp deleted file mode 100644 index 1faf1adfaf0291950c5f863cbab0daf9c9a64f50..0000000000000000000000000000000000000000 --- a/src/hotspot/share/services/dtraceAttacher.hpp +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2006, 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_SERVICES_DTRACEATTACHER_HPP -#define SHARE_SERVICES_DTRACEATTACHER_HPP - -#define DTRACE_ALLOC_PROBES 0x1 -#define DTRACE_METHOD_PROBES 0x2 -#define DTRACE_MONITOR_PROBES 0x4 -#define DTRACE_ALL_PROBES (DTRACE_ALLOC_PROBES | \ - DTRACE_METHOD_PROBES | \ - DTRACE_MONITOR_PROBES) - -class DTrace : public AllStatic { - private: - // disable one or more probes - OR above constants - static void disable_dprobes(int probe_types); - - public: - // enable one or more probes - OR above constants - static void enable_dprobes(int probe_types); - // all clients detached, do any clean-up - static void detach_all_clients(); - // set ExtendedDTraceProbes flag - static void set_extended_dprobes(bool value); - // set DTraceMonitorProbes flag - static void set_monitor_dprobes(bool value); -}; - -#endif // SHARE_SERVICES_DTRACEATTACHER_HPP diff --git a/src/hotspot/share/services/gcNotifier.hpp b/src/hotspot/share/services/gcNotifier.hpp index a13b85e0e69b0deaad5aec15aee8cb368da7b2ec..1a4582025c42949bd2947e08dd32719ea785e015 100644 --- a/src/hotspot/share/services/gcNotifier.hpp +++ b/src/hotspot/share/services/gcNotifier.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 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 @@ -25,7 +25,7 @@ #ifndef SHARE_SERVICES_GCNOTIFIER_HPP #define SHARE_SERVICES_GCNOTIFIER_HPP -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" #include "services/memoryPool.hpp" #include "services/memoryService.hpp" #include "services/memoryManager.hpp" diff --git a/src/hotspot/share/services/heapDumper.cpp b/src/hotspot/share/services/heapDumper.cpp index c3c939c06d0e6383a4df9c8b7facc679c388704c..7204270393611f35c78e318ea01caa237570ef1d 100644 --- a/src/hotspot/share/services/heapDumper.cpp +++ b/src/hotspot/share/services/heapDumper.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -912,12 +912,10 @@ class DumperSupport : AllStatic { static void dump_instance_field_descriptors(AbstractDumpWriter* writer, Klass* k); // creates HPROF_GC_INSTANCE_DUMP record for the given object static void dump_instance(AbstractDumpWriter* writer, oop o); - // creates HPROF_GC_CLASS_DUMP record for the given class and each of its - // array classes - static void dump_class_and_array_classes(AbstractDumpWriter* writer, Klass* k); - // creates HPROF_GC_CLASS_DUMP record for a given primitive array - // class (and each multi-dimensional array class too) - static void dump_basic_type_array_class(AbstractDumpWriter* writer, Klass* k); + // creates HPROF_GC_CLASS_DUMP record for the given instance class + static void dump_instance_class(AbstractDumpWriter* writer, Klass* k); + // creates HPROF_GC_CLASS_DUMP record for a given array class + static void dump_array_class(AbstractDumpWriter* writer, Klass* k); // creates HPROF_GC_OBJ_ARRAY_DUMP record for the given object array static void dump_object_array(AbstractDumpWriter* writer, objArrayOop array); @@ -1243,9 +1241,8 @@ void DumperSupport::dump_instance(AbstractDumpWriter* writer, oop o) { writer->end_sub_record(); } -// creates HPROF_GC_CLASS_DUMP record for the given class and each of -// its array classes -void DumperSupport::dump_class_and_array_classes(AbstractDumpWriter* writer, Klass* k) { +// creates HPROF_GC_CLASS_DUMP record for the given instance class +void DumperSupport::dump_instance_class(AbstractDumpWriter* writer, Klass* k) { InstanceKlass* ik = InstanceKlass::cast(k); // We can safepoint and do a heap dump at a point where we have a Klass, @@ -1298,73 +1295,42 @@ void DumperSupport::dump_class_and_array_classes(AbstractDumpWriter* writer, Kla dump_instance_field_descriptors(writer, ik); writer->end_sub_record(); +} - // array classes - k = ik->array_klass_or_null(); - while (k != NULL) { - assert(k->is_objArray_klass(), "not an ObjArrayKlass"); - - u4 size = 1 + sizeof(address) + 4 + 6 * sizeof(address) + 4 + 2 + 2 + 2; - writer->start_sub_record(HPROF_GC_CLASS_DUMP, size); - writer->write_classID(k); - writer->write_u4(STACK_TRACE_ID); - - // super class of array classes is java.lang.Object - java_super = k->java_super(); - assert(java_super != NULL, "checking"); - writer->write_classID(java_super); - - writer->write_objectID(ik->class_loader()); - writer->write_objectID(ik->signers()); - writer->write_objectID(ik->protection_domain()); - - writer->write_objectID(oop(NULL)); // reserved - writer->write_objectID(oop(NULL)); - writer->write_u4(0); // instance size - writer->write_u2(0); // constant pool - writer->write_u2(0); // static fields - writer->write_u2(0); // instance fields - - writer->end_sub_record(); - - // get the array class for the next rank - k = k->array_klass_or_null(); +// creates HPROF_GC_CLASS_DUMP record for the given array class +void DumperSupport::dump_array_class(AbstractDumpWriter* writer, Klass* k) { + InstanceKlass* ik = NULL; // bottom class for object arrays, NULL for primitive type arrays + if (k->is_objArray_klass()) { + Klass *bk = ObjArrayKlass::cast(k)->bottom_klass(); + assert(bk != NULL, "checking"); + if (bk->is_instance_klass()) { + ik = InstanceKlass::cast(bk); + } } -} -// creates HPROF_GC_CLASS_DUMP record for a given primitive array -// class (and each multi-dimensional array class too) -void DumperSupport::dump_basic_type_array_class(AbstractDumpWriter* writer, Klass* k) { - // array classes - while (k != NULL) { - Klass* klass = k; - - u4 size = 1 + sizeof(address) + 4 + 6 * sizeof(address) + 4 + 2 + 2 + 2; - writer->start_sub_record(HPROF_GC_CLASS_DUMP, size); - writer->write_classID(klass); - writer->write_u4(STACK_TRACE_ID); - - // super class of array classes is java.lang.Object - InstanceKlass* java_super = klass->java_super(); - assert(java_super != NULL, "checking"); - writer->write_classID(java_super); + u4 size = 1 + sizeof(address) + 4 + 6 * sizeof(address) + 4 + 2 + 2 + 2; + writer->start_sub_record(HPROF_GC_CLASS_DUMP, size); + writer->write_classID(k); + writer->write_u4(STACK_TRACE_ID); - writer->write_objectID(oop(NULL)); // loader - writer->write_objectID(oop(NULL)); // signers - writer->write_objectID(oop(NULL)); // protection domain + // super class of array classes is java.lang.Object + InstanceKlass* java_super = k->java_super(); + assert(java_super != NULL, "checking"); + writer->write_classID(java_super); - writer->write_objectID(oop(NULL)); // reserved - writer->write_objectID(oop(NULL)); - writer->write_u4(0); // instance size - writer->write_u2(0); // constant pool - writer->write_u2(0); // static fields - writer->write_u2(0); // instance fields + writer->write_objectID(ik == NULL ? oop(NULL) : ik->class_loader()); + writer->write_objectID(ik == NULL ? oop(NULL) : ik->signers()); + writer->write_objectID(ik == NULL ? oop(NULL) : ik->protection_domain()); - writer->end_sub_record(); + writer->write_objectID(oop(NULL)); // reserved + writer->write_objectID(oop(NULL)); + writer->write_u4(0); // instance size + writer->write_u2(0); // constant pool + writer->write_u2(0); // static fields + writer->write_u2(0); // instance fields + + writer->end_sub_record(); - // get the array class for the next rank - k = klass->array_klass_or_null(); - } } // Hprof uses an u4 as record length field, @@ -1910,7 +1876,6 @@ class VM_HeapDumper : public VM_GC_Operation, public WorkerTask { // Number of dumper threads that only iterate heap. uint _heap_only_dumper_threads = _num_dumper_threads - 1 /* VMDumper thread */; _dumper_controller = new (std::nothrow) DumperController(_heap_only_dumper_threads); - _poi = Universe::heap()->parallel_object_iterator(_num_dumper_threads); } } @@ -1937,17 +1902,11 @@ class VM_HeapDumper : public VM_GC_Operation, public WorkerTask { bool skip_operation() const; // writes a HPROF_LOAD_CLASS record - class ClassesDo; static void do_load_class(Klass* k); // writes a HPROF_GC_CLASS_DUMP record for the given class - // (and each array class too) static void do_class_dump(Klass* k); - // writes a HPROF_GC_CLASS_DUMP records for a given basic type - // array (and each multi-dimensional array too) - static void do_basic_type_array_class_dump(Klass* k); - // HPROF_GC_ROOT_THREAD_OBJ records int do_thread(JavaThread* thread, u4 thread_serial_num); void do_threads(); @@ -1999,10 +1958,6 @@ class VM_HeapDumper : public VM_GC_Operation, public WorkerTask { } FREE_C_HEAP_ARRAY(ThreadStackTrace*, _stack_traces); } - if (_poi != NULL) { - delete _poi; - _poi = NULL; - } if (_dumper_controller != NULL) { delete _dumper_controller; _dumper_controller = NULL; @@ -2032,52 +1987,40 @@ void DumperSupport::end_of_dump(AbstractDumpWriter* writer) { writer->write_u4(0); } -// writes a HPROF_LOAD_CLASS record for the class (and each of its -// array classes) +// writes a HPROF_LOAD_CLASS record for the class void VM_HeapDumper::do_load_class(Klass* k) { static u4 class_serial_num = 0; // len of HPROF_LOAD_CLASS record u4 remaining = 2*oopSize + 2*sizeof(u4); - // write a HPROF_LOAD_CLASS for the class and each array class - do { - DumperSupport::write_header(writer(), HPROF_LOAD_CLASS, remaining); - - // class serial number is just a number - writer()->write_u4(++class_serial_num); + DumperSupport::write_header(writer(), HPROF_LOAD_CLASS, remaining); - // class ID - Klass* klass = k; - writer()->write_classID(klass); + // class serial number is just a number + writer()->write_u4(++class_serial_num); - // add the Klass* and class serial number pair - dumper()->add_class_serial_number(klass, class_serial_num); + // class ID + writer()->write_classID(k); - writer()->write_u4(STACK_TRACE_ID); + // add the Klass* and class serial number pair + dumper()->add_class_serial_number(k, class_serial_num); - // class name ID - Symbol* name = klass->name(); - writer()->write_symbolID(name); + writer()->write_u4(STACK_TRACE_ID); - // write a LOAD_CLASS record for the array type (if it exists) - k = klass->array_klass_or_null(); - } while (k != NULL); + // class name ID + Symbol* name = k->name(); + writer()->write_symbolID(name); } // writes a HPROF_GC_CLASS_DUMP record for the given class void VM_HeapDumper::do_class_dump(Klass* k) { if (k->is_instance_klass()) { - DumperSupport::dump_class_and_array_classes(writer(), k); + DumperSupport::dump_instance_class(writer(), k); + } else { + DumperSupport::dump_array_class(writer(), k); } } -// writes a HPROF_GC_CLASS_DUMP records for a given basic type -// array (and each multi-dimensional array too) -void VM_HeapDumper::do_basic_type_array_class_dump(Klass* k) { - DumperSupport::dump_basic_type_array_class(writer(), k); -} - // Walk the stack of the given thread. // Dumps a HPROF_GC_ROOT_JAVA_FRAME record for each local // Dumps a HPROF_GC_ROOT_JNI_LOCAL record for each JNI local @@ -2252,7 +2195,14 @@ void VM_HeapDumper::doit() { work(0); } else { prepare_parallel_dump(workers->active_workers()); - workers->run_task(this); + if (_num_dumper_threads > 1) { + ParallelObjectIterator poi(_num_dumper_threads); + _poi = &poi; + workers->run_task(this); + _poi = NULL; + } else { + workers->run_task(this); + } finish_parallel_dump(); } @@ -2289,7 +2239,6 @@ void VM_HeapDumper::work(uint worker_id) { LockedClassesDo locked_load_classes(&do_load_class); ClassLoaderDataGraph::classes_do(&locked_load_classes); } - Universe::basic_type_classes_do(&do_load_class); // write HPROF_FRAME and HPROF_TRACE records // this must be called after _klass_map is built when iterating the classes above. @@ -2300,7 +2249,6 @@ void VM_HeapDumper::work(uint worker_id) { LockedClassesDo locked_dump_class(&do_class_dump); ClassLoaderDataGraph::classes_do(&locked_dump_class); } - Universe::basic_type_classes_do(&do_basic_type_array_class_dump); // HPROF_GC_ROOT_THREAD_OBJ + frames + jni locals do_threads(); @@ -2386,7 +2334,7 @@ void VM_HeapDumper::dump_stack_traces() { HandleMark hm(current_thread); ThreadStackTrace* stack_trace = new ThreadStackTrace(thread, false); - stack_trace->dump_stack_at_safepoint(-1); + stack_trace->dump_stack_at_safepoint(-1, /* ObjectMonitorsHashtable is not needed here */ nullptr); _stack_traces[_num_threads++] = stack_trace; // write HPROF_FRAME records for this thread's stack trace diff --git a/src/hotspot/share/services/heapDumperCompression.cpp b/src/hotspot/share/services/heapDumperCompression.cpp index 0d6426017974012c0918d745672dcb3403c1c704..0c9958077d225f47cb8f26dd21cf0021ce38fd8c 100644 --- a/src/hotspot/share/services/heapDumperCompression.cpp +++ b/src/hotspot/share/services/heapDumperCompression.cpp @@ -1,4 +1,5 @@ /* + * Copyright (c) 2022, 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. * @@ -45,7 +46,7 @@ char const* FileWriter::open_writer() { FileWriter::~FileWriter() { if (_fd >= 0) { - os::close(_fd); + ::close(_fd); _fd = -1; } } @@ -54,7 +55,7 @@ char const* FileWriter::write_buf(char* buf, ssize_t size) { assert(_fd >= 0, "Must be open"); assert(size > 0, "Must write at least one byte"); - ssize_t n = (ssize_t) os::write(_fd, buf, (uint) size); + ssize_t n = os::write(_fd, buf, (uint) size); if (n <= 0) { return os::strerror(errno); diff --git a/src/hotspot/share/services/lowMemoryDetector.hpp b/src/hotspot/share/services/lowMemoryDetector.hpp index 09bb1ce640681cbf4a5f10a4c69c4ce81d5b861f..3070eb00ab7af8db4a41dce792078dcc6b79ff89 100644 --- a/src/hotspot/share/services/lowMemoryDetector.hpp +++ b/src/hotspot/share/services/lowMemoryDetector.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -25,7 +25,7 @@ #ifndef SHARE_SERVICES_LOWMEMORYDETECTOR_HPP #define SHARE_SERVICES_LOWMEMORYDETECTOR_HPP -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" #include "oops/oopHandle.hpp" #include "runtime/atomic.hpp" #include "services/memoryPool.hpp" diff --git a/src/hotspot/share/services/mallocSiteTable.cpp b/src/hotspot/share/services/mallocSiteTable.cpp index 869a67385318f78c6d299682ddea3432eac5e5e4..f8d30e1dca91895596a459e7a94c1264f1052153 100644 --- a/src/hotspot/share/services/mallocSiteTable.cpp +++ b/src/hotspot/share/services/mallocSiteTable.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -33,13 +33,6 @@ MallocSiteHashtableEntry* MallocSiteTable::_table[MallocSiteTable::table_size]; const NativeCallStack* MallocSiteTable::_hash_entry_allocation_stack = NULL; const MallocSiteHashtableEntry* MallocSiteTable::_hash_entry_allocation_site = NULL; -// concurrent access counter -volatile int MallocSiteTable::_access_count = 0; - -// Tracking hashtable contention -NOT_PRODUCT(int MallocSiteTable::_peak_count = 0;) - - /* * Initialize malloc site table. * Hashtable entry is malloc'd, so it can cause infinite recursion. @@ -49,7 +42,6 @@ NOT_PRODUCT(int MallocSiteTable::_peak_count = 0;) * time, it is in single-threaded mode from JVM perspective. */ bool MallocSiteTable::initialize() { - assert((size_t)table_size <= MAX_MALLOCSITE_TABLE_SIZE, "Hashtable overflow"); // Fake the call stack for hashtable entry allocation assert(NMT_TrackingStackDepth > 1, "At least one tracking stack"); @@ -114,13 +106,11 @@ bool MallocSiteTable::walk(MallocSiteWalker* walker) { * 2. Overflow hash bucket. * Under any of above circumstances, caller should handle the situation. */ -MallocSite* MallocSiteTable::lookup_or_add(const NativeCallStack& key, size_t* bucket_idx, - size_t* pos_idx, MEMFLAGS flags) { +MallocSite* MallocSiteTable::lookup_or_add(const NativeCallStack& key, uint32_t* marker, MEMFLAGS flags) { assert(flags != mtNone, "Should have a real memory type"); const unsigned int hash = key.calculate_hash(); const unsigned int index = hash_to_index(hash); - *bucket_idx = (size_t)index; - *pos_idx = 0; + *marker = 0; // First entry for this hash bucket if (_table[index] == NULL) { @@ -130,41 +120,47 @@ MallocSite* MallocSiteTable::lookup_or_add(const NativeCallStack& key, size_t* b // swap in the head if (Atomic::replace_if_null(&_table[index], entry)) { + *marker = build_marker(index, 0); return entry->data(); } delete entry; } + unsigned pos_idx = 0; MallocSiteHashtableEntry* head = _table[index]; - while (head != NULL && (*pos_idx) <= MAX_BUCKET_LENGTH) { + while (head != NULL && pos_idx < MAX_BUCKET_LENGTH) { if (head->hash() == hash) { MallocSite* site = head->data(); if (site->flag() == flags && site->equals(key)) { + *marker = build_marker(index, pos_idx); return head->data(); } } - if (head->next() == NULL && (*pos_idx) < MAX_BUCKET_LENGTH) { + if (head->next() == NULL && pos_idx < (MAX_BUCKET_LENGTH - 1)) { MallocSiteHashtableEntry* entry = new_entry(key, flags); // OOM check if (entry == NULL) return NULL; if (head->atomic_insert(entry)) { - (*pos_idx) ++; + pos_idx ++; + *marker = build_marker(index, pos_idx); return entry->data(); } // contended, other thread won delete entry; } head = (MallocSiteHashtableEntry*)head->next(); - (*pos_idx) ++; + pos_idx ++; } return NULL; } // Access malloc site -MallocSite* MallocSiteTable::malloc_site(size_t bucket_idx, size_t pos_idx) { +MallocSite* MallocSiteTable::malloc_site(uint32_t marker) { + uint16_t bucket_idx = bucket_idx_from_marker(marker); assert(bucket_idx < table_size, "Invalid bucket index"); + const uint16_t pos_idx = pos_idx_from_marker(marker); MallocSiteHashtableEntry* head = _table[bucket_idx]; for (size_t index = 0; index < pos_idx && head != NULL; @@ -204,122 +200,81 @@ void MallocSiteTable::delete_linked_list(MallocSiteHashtableEntry* head) { } } -void MallocSiteTable::shutdown() { - AccessLock locker(&_access_count); - locker.exclusiveLock(); - reset(); -} - bool MallocSiteTable::walk_malloc_site(MallocSiteWalker* walker) { assert(walker != NULL, "NuLL walker"); - AccessLock locker(&_access_count); - if (locker.sharedLock()) { - NOT_PRODUCT(_peak_count = MAX2(_peak_count, _access_count);) - return walk(walker); - } - return false; -} - - -void MallocSiteTable::AccessLock::exclusiveLock() { - int target; - int val; - - assert(_lock_state != ExclusiveLock, "Can only call once"); - assert(*_lock >= 0, "Can not content exclusive lock"); - - // make counter negative to block out shared locks - do { - val = *_lock; - target = _MAGIC_ + *_lock; - } while (Atomic::cmpxchg(_lock, val, target) != val); - - // wait for all readers to exit - while (*_lock != _MAGIC_) { -#ifdef _WINDOWS - os::naked_short_sleep(1); -#else - os::naked_yield(); -#endif - } - _lock_state = ExclusiveLock; + return walk(walker); } void MallocSiteTable::print_tuning_statistics(outputStream* st) { - - AccessLock locker(&_access_count); - if (locker.sharedLock()) { - // Total number of allocation sites, include empty sites - int total_entries = 0; - // Number of allocation sites that have all memory freed - int empty_entries = 0; - // Number of captured call stack distribution - int stack_depth_distribution[NMT_TrackingStackDepth + 1] = { 0 }; - // Chain lengths - int lengths[table_size] = { 0 }; - - for (int i = 0; i < table_size; i ++) { - int this_chain_length = 0; - const MallocSiteHashtableEntry* head = _table[i]; - while (head != NULL) { - total_entries ++; - this_chain_length ++; - if (head->size() == 0) { - empty_entries ++; - } - const int callstack_depth = head->peek()->call_stack()->frames(); - assert(callstack_depth >= 0 && callstack_depth <= NMT_TrackingStackDepth, - "Sanity (%d)", callstack_depth); - stack_depth_distribution[callstack_depth] ++; - head = head->next(); - } - lengths[i] = this_chain_length; - } - - st->print_cr("Malloc allocation site table:"); - st->print_cr("\tTotal entries: %d", total_entries); - st->print_cr("\tEmpty entries: %d (%2.2f%%)", empty_entries, ((float)empty_entries * 100) / total_entries); - st->cr(); - - // We report the hash distribution (chain length distribution) of the n shortest chains - // - under the assumption that this usually contains all lengths. Reporting threshold - // is 20, and the expected avg chain length is 5..6 (see table size). - static const int chain_length_threshold = 20; - int chain_length_distribution[chain_length_threshold] = { 0 }; - int over_threshold = 0; - int longest_chain_length = 0; - for (int i = 0; i < table_size; i ++) { - if (lengths[i] >= chain_length_threshold) { - over_threshold ++; - } else { - chain_length_distribution[lengths[i]] ++; + // Total number of allocation sites, include empty sites + int total_entries = 0; + // Number of allocation sites that have all memory freed + int empty_entries = 0; + // Number of captured call stack distribution + int stack_depth_distribution[NMT_TrackingStackDepth + 1] = { 0 }; + // Chain lengths + int lengths[table_size] = { 0 }; + + for (int i = 0; i < table_size; i ++) { + int this_chain_length = 0; + const MallocSiteHashtableEntry* head = _table[i]; + while (head != NULL) { + total_entries ++; + this_chain_length ++; + if (head->size() == 0) { + empty_entries ++; } - longest_chain_length = MAX2(longest_chain_length, lengths[i]); + const int callstack_depth = head->peek()->call_stack()->frames(); + assert(callstack_depth >= 0 && callstack_depth <= NMT_TrackingStackDepth, + "Sanity (%d)", callstack_depth); + stack_depth_distribution[callstack_depth] ++; + head = head->next(); } + lengths[i] = this_chain_length; + } - st->print_cr("Hash distribution:"); - if (chain_length_distribution[0] == 0) { - st->print_cr("no empty buckets."); + st->print_cr("Malloc allocation site table:"); + st->print_cr("\tTotal entries: %d", total_entries); + st->print_cr("\tEmpty entries: %d (%2.2f%%)", empty_entries, ((float)empty_entries * 100) / total_entries); + st->cr(); + + // We report the hash distribution (chain length distribution) of the n shortest chains + // - under the assumption that this usually contains all lengths. Reporting threshold + // is 20, and the expected avg chain length is 5..6 (see table size). + static const int chain_length_threshold = 20; + int chain_length_distribution[chain_length_threshold] = { 0 }; + int over_threshold = 0; + int longest_chain_length = 0; + for (int i = 0; i < table_size; i ++) { + if (lengths[i] >= chain_length_threshold) { + over_threshold ++; } else { - st->print_cr("%d buckets are empty.", chain_length_distribution[0]); - } - for (int len = 1; len < MIN2(longest_chain_length + 1, chain_length_threshold); len ++) { - st->print_cr("%2d %s: %d.", len, (len == 1 ? " entry" : "entries"), chain_length_distribution[len]); + chain_length_distribution[lengths[i]] ++; } - if (longest_chain_length >= chain_length_threshold) { - st->print_cr(">=%2d entries: %d.", chain_length_threshold, over_threshold); - } - st->print_cr("most entries: %d.", longest_chain_length); - st->cr(); + longest_chain_length = MAX2(longest_chain_length, lengths[i]); + } - st->print_cr("Call stack depth distribution:"); - for (int i = 0; i <= NMT_TrackingStackDepth; i ++) { - st->print_cr("\t%d: %d", i, stack_depth_distribution[i]); - } - st->cr(); - } // lock -} + st->print_cr("Hash distribution:"); + if (chain_length_distribution[0] == 0) { + st->print_cr("no empty buckets."); + } else { + st->print_cr("%d buckets are empty.", chain_length_distribution[0]); + } + for (int len = 1; len < MIN2(longest_chain_length + 1, chain_length_threshold); len ++) { + st->print_cr("%2d %s: %d.", len, (len == 1 ? " entry" : "entries"), chain_length_distribution[len]); + } + if (longest_chain_length >= chain_length_threshold) { + st->print_cr(">=%2d entries: %d.", chain_length_threshold, over_threshold); + } + st->print_cr("most entries: %d.", longest_chain_length); + st->cr(); + st->print_cr("Call stack depth distribution:"); + for (int i = 0; i <= NMT_TrackingStackDepth; i ++) { + st->print_cr("\t%d: %d", i, stack_depth_distribution[i]); + } + st->cr(); +} bool MallocSiteHashtableEntry::atomic_insert(MallocSiteHashtableEntry* entry) { return Atomic::replace_if_null(&_next, entry); diff --git a/src/hotspot/share/services/mallocSiteTable.hpp b/src/hotspot/share/services/mallocSiteTable.hpp index f401d456b18a9ed7b0b0331136389f215a0c5d9e..0511a557d419ef6a5c3da9038f3ab89d42c2d8d3 100644 --- a/src/hotspot/share/services/mallocSiteTable.hpp +++ b/src/hotspot/share/services/mallocSiteTable.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -25,15 +25,12 @@ #ifndef SHARE_SERVICES_MALLOCSITETABLE_HPP #define SHARE_SERVICES_MALLOCSITETABLE_HPP -#include "utilities/macros.hpp" - -#if INCLUDE_NMT - #include "memory/allocation.hpp" #include "runtime/atomic.hpp" #include "services/allocationSite.hpp" #include "services/mallocTracker.hpp" #include "services/nmtCommon.hpp" +#include "utilities/macros.hpp" #include "utilities/nativeCallStack.hpp" // MallocSite represents a code path that eventually calls @@ -114,105 +111,58 @@ class MallocSiteTable : AllStatic { table_size = (table_base_size * NMT_TrackingStackDepth - 1) }; + // Table cannot be wider than a 16bit bucket idx can hold +#define MAX_MALLOCSITE_TABLE_SIZE (USHRT_MAX - 1) + // Each bucket chain cannot be longer than what a 16 bit pos idx can hold (hopefully way shorter) +#define MAX_BUCKET_LENGTH (USHRT_MAX - 1) - // This is a very special lock, that allows multiple shared accesses (sharedLock), but - // once exclusive access (exclusiveLock) is requested, all shared accesses are - // rejected forever. - class AccessLock : public StackObj { - enum LockState { - NoLock, - SharedLock, - ExclusiveLock - }; - - private: - // A very large negative number. The only possibility to "overflow" - // this number is when there are more than -min_jint threads in - // this process, which is not going to happen in foreseeable future. - const static int _MAGIC_ = min_jint; - - LockState _lock_state; - volatile int* _lock; - public: - AccessLock(volatile int* lock) : - _lock_state(NoLock), _lock(lock) { - } + STATIC_ASSERT(table_size <= MAX_MALLOCSITE_TABLE_SIZE); - ~AccessLock() { - if (_lock_state == SharedLock) { - Atomic::dec(_lock); - } - } - // Acquire shared lock. - // Return true if shared access is granted. - inline bool sharedLock() { - jint res = Atomic::add(_lock, 1); - if (res < 0) { - Atomic::dec(_lock); - return false; - } - _lock_state = SharedLock; - return true; - } - // Acquire exclusive lock - void exclusiveLock(); - }; + static uint32_t build_marker(unsigned bucket_idx, unsigned pos_idx) { + assert(bucket_idx <= MAX_MALLOCSITE_TABLE_SIZE && pos_idx < MAX_BUCKET_LENGTH, "overflow"); + return (uint32_t)bucket_idx << 16 | pos_idx; + } + static uint16_t bucket_idx_from_marker(uint32_t marker) { return marker >> 16; } + static uint16_t pos_idx_from_marker(uint32_t marker) { return marker & 0xFFFF; } public: - static bool initialize(); - static void shutdown(); - NOT_PRODUCT(static int access_peak_count() { return _peak_count; }) + static bool initialize(); // Number of hash buckets static inline int hash_buckets() { return (int)table_size; } // Access and copy a call stack from this table. Shared lock should be // acquired before access the entry. - static inline bool access_stack(NativeCallStack& stack, size_t bucket_idx, - size_t pos_idx) { - AccessLock locker(&_access_count); - if (locker.sharedLock()) { - NOT_PRODUCT(_peak_count = MAX2(_peak_count, _access_count);) - MallocSite* site = malloc_site(bucket_idx, pos_idx); - if (site != NULL) { - stack = *site->call_stack(); - return true; - } + static inline bool access_stack(NativeCallStack& stack, uint32_t marker) { + MallocSite* site = malloc_site(marker); + if (site != NULL) { + stack = *site->call_stack(); + return true; } return false; } // Record a new allocation from specified call path. - // Return true if the allocation is recorded successfully, bucket_idx - // and pos_idx are also updated to indicate the entry where the allocation - // information was recorded. + // Return true if the allocation is recorded successfully and updates marker + // to indicate the entry where the allocation information was recorded. // Return false only occurs under rare scenarios: // 1. out of memory // 2. overflow hash bucket static inline bool allocation_at(const NativeCallStack& stack, size_t size, - size_t* bucket_idx, size_t* pos_idx, MEMFLAGS flags) { - AccessLock locker(&_access_count); - if (locker.sharedLock()) { - NOT_PRODUCT(_peak_count = MAX2(_peak_count, _access_count);) - MallocSite* site = lookup_or_add(stack, bucket_idx, pos_idx, flags); - if (site != NULL) site->allocate(size); - return site != NULL; - } - return false; + uint32_t* marker, MEMFLAGS flags) { + MallocSite* site = lookup_or_add(stack, marker, flags); + if (site != NULL) site->allocate(size); + return site != NULL; } - // Record memory deallocation. bucket_idx and pos_idx indicate where the allocation + // Record memory deallocation. marker indicates where the allocation // information was recorded. - static inline bool deallocation_at(size_t size, size_t bucket_idx, size_t pos_idx) { - AccessLock locker(&_access_count); - if (locker.sharedLock()) { - NOT_PRODUCT(_peak_count = MAX2(_peak_count, _access_count);) - MallocSite* site = malloc_site(bucket_idx, pos_idx); - if (site != NULL) { - site->deallocate(size); - return true; - } + static inline bool deallocation_at(size_t size, uint32_t marker) { + MallocSite* site = malloc_site(marker); + if (site != NULL) { + site->deallocate(size); + return true; } return false; } @@ -229,8 +179,8 @@ class MallocSiteTable : AllStatic { // Delete a bucket linked list static void delete_linked_list(MallocSiteHashtableEntry* head); - static MallocSite* lookup_or_add(const NativeCallStack& key, size_t* bucket_idx, size_t* pos_idx, MEMFLAGS flags); - static MallocSite* malloc_site(size_t bucket_idx, size_t pos_idx); + static MallocSite* lookup_or_add(const NativeCallStack& key, uint32_t* marker, MEMFLAGS flags); + static MallocSite* malloc_site(uint32_t marker); static bool walk(MallocSiteWalker* walker); static inline unsigned int hash_to_index(unsigned int hash) { @@ -248,18 +198,11 @@ class MallocSiteTable : AllStatic { } private: - // Counter for counting concurrent access - static volatile int _access_count; - // The callsite hashtable. It has to be a static table, // since malloc call can come from C runtime linker. static MallocSiteHashtableEntry* _table[table_size]; static const NativeCallStack* _hash_entry_allocation_stack; static const MallocSiteHashtableEntry* _hash_entry_allocation_site; - - - NOT_PRODUCT(static int _peak_count;) }; -#endif // INCLUDE_NMT #endif // SHARE_SERVICES_MALLOCSITETABLE_HPP diff --git a/src/hotspot/share/services/mallocTracker.cpp b/src/hotspot/share/services/mallocTracker.cpp index e67f2d8a2a909b13e602bc8119e3c2316e601af6..ff0d1d14f6dbb84a3eb991581e427b5830e08043 100644 --- a/src/hotspot/share/services/mallocTracker.cpp +++ b/src/hotspot/share/services/mallocTracker.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -23,10 +23,15 @@ */ #include "precompiled.hpp" +#include "runtime/os.hpp" +#include "runtime/safefetch.inline.hpp" #include "services/mallocSiteTable.hpp" #include "services/mallocTracker.hpp" -#include "services/mallocTracker.inline.hpp" #include "services/memTracker.hpp" +#include "utilities/debug.hpp" +#include "utilities/ostream.hpp" + +#include "jvm_io.h" size_t MallocMemorySummary::_snapshot[CALC_OBJ_SIZE_IN_TYPE(MallocMemorySnapshot, size_t)]; @@ -103,32 +108,118 @@ void MallocMemorySummary::initialize() { ::new ((void*)_snapshot)MallocMemorySnapshot(); } -void MallocHeader::release() const { - // Tracking already shutdown, no housekeeping is needed anymore - if (MemTracker::tracking_level() <= NMT_minimal) return; +void MallocHeader::mark_block_as_dead() { + _canary = _header_canary_dead_mark; + NOT_LP64(_alt_canary = _header_alt_canary_dead_mark); + set_footer(_footer_canary_dead_mark); +} - MallocMemorySummary::record_free(size(), flags()); - MallocMemorySummary::record_free_malloc_header(sizeof(MallocHeader)); - if (MemTracker::tracking_level() == NMT_detail) { - MallocSiteTable::deallocation_at(size(), _bucket_idx, _pos_idx); +void MallocHeader::print_block_on_error(outputStream* st, address bad_address) const { + assert(bad_address >= (address)this, "sanity"); + + // This function prints block information, including hex dump, in case of a detected + // corruption. The hex dump should show both block header and corruption site + // (which may or may not be close together or identical). Plus some surrounding area. + // + // Note that we use os::print_hex_dump(), which is able to cope with unmapped + // memory (it uses SafeFetch). + + st->print_cr("NMT Block at " PTR_FORMAT ", corruption at: " PTR_FORMAT ": ", + p2i(this), p2i(bad_address)); + static const size_t min_dump_length = 256; + address from1 = align_down((address)this, sizeof(void*)) - (min_dump_length / 2); + address to1 = from1 + min_dump_length; + address from2 = align_down(bad_address, sizeof(void*)) - (min_dump_length / 2); + address to2 = from2 + min_dump_length; + if (from2 > to1) { + // Dump gets too large, split up in two sections. + os::print_hex_dump(st, from1, to1, 1); + st->print_cr("..."); + os::print_hex_dump(st, from2, to2, 1); + } else { + // print one hex dump + os::print_hex_dump(st, from1, to2, 1); } } +void MallocHeader::assert_block_integrity() const { + char msg[256]; + address corruption = NULL; + if (!check_block_integrity(msg, sizeof(msg), &corruption)) { + if (corruption != NULL) { + print_block_on_error(tty, (address)this); + } + fatal("NMT corruption: Block at " PTR_FORMAT ": %s", p2i(this), msg); + } +} + +bool MallocHeader::check_block_integrity(char* msg, size_t msglen, address* p_corruption) const { + // Note: if you modify the error messages here, make sure you + // adapt the associated gtests too. + + // Weed out obviously wrong block addresses of NULL or very low + // values. Note that we should not call this for ::free(NULL), + // which should be handled by os::free() above us. + if (((size_t)p2i(this)) < K) { + jio_snprintf(msg, msglen, "invalid block address"); + return false; + } + + // From here on we assume the block pointer to be valid. We could + // use SafeFetch but since this is a hot path we don't. If we are + // wrong, we will crash when accessing the canary, which hopefully + // generates distinct crash report. + + // Weed out obviously unaligned addresses. NMT blocks, being the result of + // malloc calls, should adhere to malloc() alignment. Malloc alignment is + // specified by the standard by this requirement: + // "malloc returns a pointer which is suitably aligned for any built-in type" + // For us it means that it is *at least* 64-bit on all of our 32-bit and + // 64-bit platforms since we have native 64-bit types. It very probably is + // larger than that, since there exist scalar types larger than 64bit. Here, + // we test the smallest alignment we know. + // Should we ever start using std::max_align_t, this would be one place to + // fix up. + if (!is_aligned(this, sizeof(uint64_t))) { + *p_corruption = (address)this; + jio_snprintf(msg, msglen, "block address is unaligned"); + return false; + } + + // Check header canary + if (_canary != _header_canary_life_mark) { + *p_corruption = (address)this; + jio_snprintf(msg, msglen, "header canary broken"); + return false; + } + +#ifndef _LP64 + // On 32-bit we have a second canary, check that one too. + if (_alt_canary != _header_alt_canary_life_mark) { + *p_corruption = (address)this; + jio_snprintf(msg, msglen, "header canary broken"); + return false; + } +#endif -bool MallocHeader::record_malloc_site(const NativeCallStack& stack, size_t size, - size_t* bucket_idx, size_t* pos_idx, MEMFLAGS flags) const { - bool ret = MallocSiteTable::allocation_at(stack, size, bucket_idx, pos_idx, flags); + // Does block size seems reasonable? + if (_size >= max_reasonable_malloc_size) { + *p_corruption = (address)this; + jio_snprintf(msg, msglen, "header looks invalid (weirdly large block size)"); + return false; + } - // Something went wrong, could be OOM or overflow malloc site table. - // We want to keep tracking data under OOM circumstance, so transition to - // summary tracking. - if (!ret) { - MemTracker::transition_to(NMT_summary); + // Check footer canary + if (get_footer() != _footer_canary_life_mark) { + *p_corruption = footer_address(); + jio_snprintf(msg, msglen, "footer canary broken at " PTR_FORMAT " (buffer overflow?)", + p2i(footer_address())); + return false; } - return ret; + return true; } bool MallocHeader::get_stack(NativeCallStack& stack) const { - return MallocSiteTable::access_stack(stack, _bucket_idx, _pos_idx); + return MallocSiteTable::access_stack(stack, _mst_marker); } bool MallocTracker::initialize(NMT_TrackingLevel level) { @@ -142,43 +233,35 @@ bool MallocTracker::initialize(NMT_TrackingLevel level) { return true; } -bool MallocTracker::transition(NMT_TrackingLevel from, NMT_TrackingLevel to) { - assert(from != NMT_off, "Can not transition from off state"); - assert(to != NMT_off, "Can not transition to off state"); - assert (from != NMT_minimal, "cannot transition from minimal state"); - - if (from == NMT_detail) { - assert(to == NMT_minimal || to == NMT_summary, "Just check"); - MallocSiteTable::shutdown(); - } - return true; -} - // Record a malloc memory allocation void* MallocTracker::record_malloc(void* malloc_base, size_t size, MEMFLAGS flags, - const NativeCallStack& stack, NMT_TrackingLevel level) { - assert(level != NMT_off, "precondition"); - void* memblock; // the address for user data - MallocHeader* header = NULL; + const NativeCallStack& stack) +{ + assert(MemTracker::enabled(), "precondition"); + assert(malloc_base != NULL, "precondition"); - if (malloc_base == NULL) { - return NULL; + MallocMemorySummary::record_malloc(size, flags); + MallocMemorySummary::record_new_malloc_header(sizeof(MallocHeader)); + uint32_t mst_marker = 0; + if (MemTracker::tracking_level() == NMT_detail) { + MallocSiteTable::allocation_at(stack, size, &mst_marker, flags); } // Uses placement global new operator to initialize malloc header - - header = ::new (malloc_base)MallocHeader(size, flags, stack, level); - memblock = (void*)((char*)malloc_base + sizeof(MallocHeader)); + MallocHeader* const header = ::new (malloc_base)MallocHeader(size, flags, stack, mst_marker); + void* const memblock = (void*)((char*)malloc_base + sizeof(MallocHeader)); // The alignment check: 8 bytes alignment for 32 bit systems. // 16 bytes alignment for 64-bit systems. assert(((size_t)memblock & (sizeof(size_t) * 2 - 1)) == 0, "Alignment check"); #ifdef ASSERT - if (level > NMT_minimal) { - // Read back - assert(get_size(memblock) == size, "Wrong size"); - assert(get_flags(memblock) == flags, "Wrong flags"); + // Read back + { + MallocHeader* const header2 = malloc_header(memblock); + assert(header2->size() == size, "Wrong size"); + assert(header2->flags() == flags, "Wrong flags"); + header2->assert_block_integrity(); } #endif @@ -186,8 +269,48 @@ void* MallocTracker::record_malloc(void* malloc_base, size_t size, MEMFLAGS flag } void* MallocTracker::record_free(void* memblock) { - assert(MemTracker::tracking_level() != NMT_off && memblock != NULL, "precondition"); - MallocHeader* header = malloc_header(memblock); - header->release(); + assert(MemTracker::enabled(), "Sanity"); + assert(memblock != NULL, "precondition"); + + MallocHeader* const header = malloc_header(memblock); + header->assert_block_integrity(); + + MallocMemorySummary::record_free(header->size(), header->flags()); + MallocMemorySummary::record_free_malloc_header(sizeof(MallocHeader)); + if (MemTracker::tracking_level() == NMT_detail) { + MallocSiteTable::deallocation_at(header->size(), header->mst_marker()); + } + + header->mark_block_as_dead(); + return (void*)header; } + +// Given a pointer, if it seems to point to the start of a valid malloced block, +// print the block. Note that since there is very low risk of memory looking +// accidentally like a valid malloc block header (canaries and all) this is not +// totally failproof. Only use this during debugging or when you can afford +// signals popping up, e.g. when writing an hs_err file. +bool MallocTracker::print_pointer_information(const void* p, outputStream* st) { + assert(MemTracker::enabled(), "NMT must be enabled"); + if (CanUseSafeFetch32() && os::is_readable_pointer(p)) { + const NMT_TrackingLevel tracking_level = MemTracker::tracking_level(); + const MallocHeader* mhdr = malloc_header(p); + char msg[256]; + address p_corrupted; + if (os::is_readable_pointer(mhdr) && + mhdr->check_block_integrity(msg, sizeof(msg), &p_corrupted)) { + st->print_cr(PTR_FORMAT " malloc'd " SIZE_FORMAT " bytes by %s", + p2i(p), mhdr->size(), NMTUtil::flag_to_name(mhdr->flags())); + if (tracking_level == NMT_detail) { + NativeCallStack ncs; + if (mhdr->get_stack(ncs)) { + ncs.print_on(st); + st->cr(); + } + } + return true; + } + } + return false; +} diff --git a/src/hotspot/share/services/mallocTracker.hpp b/src/hotspot/share/services/mallocTracker.hpp index 74fbba3a51c04daf007b353f57a302a478895c0b..a0e09ee066eaf5e81d6b2df349a85e0972dabcfb 100644 --- a/src/hotspot/share/services/mallocTracker.hpp +++ b/src/hotspot/share/services/mallocTracker.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -25,14 +25,14 @@ #ifndef SHARE_SERVICES_MALLOCTRACKER_HPP #define SHARE_SERVICES_MALLOCTRACKER_HPP -#if INCLUDE_NMT - #include "memory/allocation.hpp" #include "runtime/atomic.hpp" #include "runtime/threadCritical.hpp" #include "services/nmtCommon.hpp" #include "utilities/nativeCallStack.hpp" +class outputStream; + /* * This counter class counts memory allocation and deallocation, * records total memory allocation size and number of allocations. @@ -239,68 +239,118 @@ class MallocMemorySummary : AllStatic { /* * Malloc tracking header. - * To satisfy malloc alignment requirement, NMT uses 2 machine words for tracking purpose, - * which ensures 8-bytes alignment on 32-bit systems and 16-bytes on 64-bit systems (Product build). + * + * If NMT is active (state >= minimal), we need to track allocations. A simple and cheap way to + * do this is by using malloc headers. + * + * The user allocation is preceded by a header and is immediately followed by a (possibly unaligned) + * footer canary: + * + * +--------------+------------- .... ------------------+-----+ + * | header | user | can | + * | | allocation | ary | + * +--------------+------------- .... ------------------+-----+ + * 16 bytes user size 2 byte + * + * Alignment: + * + * The start of the user allocation needs to adhere to malloc alignment. We assume 128 bits + * on both 64-bit/32-bit to be enough for that. So the malloc header is 16 bytes long on both + * 32-bit and 64-bit. + * + * Layout on 64-bit: + * + * 0 1 2 3 4 5 6 7 + * +--------+--------+--------+--------+--------+--------+--------+--------+ + * | 64-bit size | ... + * +--------+--------+--------+--------+--------+--------+--------+--------+ + * + * 8 9 10 11 12 13 14 15 16 ++ + * +--------+--------+--------+--------+--------+--------+--------+--------+ ------------------------ + * ... | malloc site table marker | flags | unused | canary | ... User payload .... + * +--------+--------+--------+--------+--------+--------+--------+--------+ ------------------------ + * + * Layout on 32-bit: + * + * 0 1 2 3 4 5 6 7 + * +--------+--------+--------+--------+--------+--------+--------+--------+ + * | alt. canary | 32-bit size | ... + * +--------+--------+--------+--------+--------+--------+--------+--------+ + * + * 8 9 10 11 12 13 14 15 16 ++ + * +--------+--------+--------+--------+--------+--------+--------+--------+ ------------------------ + * ... | malloc site table marker | flags | unused | canary | ... User payload .... + * +--------+--------+--------+--------+--------+--------+--------+--------+ ------------------------ + * + * Notes: + * - We have a canary in the two bytes directly preceding the user payload. That allows us to + * catch negative buffer overflows. + * - On 32-bit, due to the smaller size_t, we have some bits to spare. So we also have a second + * canary at the very start of the malloc header (generously sized 32 bits). + * - The footer canary consists of two bytes. Since the footer location may be unaligned to 16 bits, + * the bytes are stored individually. */ class MallocHeader { -#ifdef _LP64 - size_t _size : 64; - size_t _flags : 8; - size_t _pos_idx : 16; - size_t _bucket_idx: 40; -#define MAX_MALLOCSITE_TABLE_SIZE right_n_bits(40) -#define MAX_BUCKET_LENGTH right_n_bits(16) -#else - size_t _size : 32; - size_t _flags : 8; - size_t _pos_idx : 8; - size_t _bucket_idx: 16; -#define MAX_MALLOCSITE_TABLE_SIZE right_n_bits(16) -#define MAX_BUCKET_LENGTH right_n_bits(8) -#endif // _LP64 - public: - MallocHeader(size_t size, MEMFLAGS flags, const NativeCallStack& stack, NMT_TrackingLevel level) { - assert(sizeof(MallocHeader) == sizeof(void*) * 2, - "Wrong header size"); + NOT_LP64(uint32_t _alt_canary); + const size_t _size; + const uint32_t _mst_marker; + const uint8_t _flags; + const uint8_t _unused; + uint16_t _canary; - if (level == NMT_minimal) { - return; - } + static const uint16_t _header_canary_life_mark = 0xE99E; + static const uint16_t _header_canary_dead_mark = 0xD99D; + static const uint16_t _footer_canary_life_mark = 0xE88E; + static const uint16_t _footer_canary_dead_mark = 0xD88D; + NOT_LP64(static const uint32_t _header_alt_canary_life_mark = 0xE99EE99E;) + NOT_LP64(static const uint32_t _header_alt_canary_dead_mark = 0xD88DD88D;) - _flags = NMTUtil::flag_to_index(flags); - set_size(size); - if (level == NMT_detail) { - size_t bucket_idx; - size_t pos_idx; - if (record_malloc_site(stack, size, &bucket_idx, &pos_idx, flags)) { - assert(bucket_idx <= MAX_MALLOCSITE_TABLE_SIZE, "Overflow bucket index"); - assert(pos_idx <= MAX_BUCKET_LENGTH, "Overflow bucket position index"); - _bucket_idx = bucket_idx; - _pos_idx = pos_idx; - } - } + // We discount sizes larger than these + static const size_t max_reasonable_malloc_size = LP64_ONLY(256 * G) NOT_LP64(3500 * M); + + void print_block_on_error(outputStream* st, address bad_address) const; + + static uint16_t build_footer(uint8_t b1, uint8_t b2) { return ((uint16_t)b1 << 8) | (uint16_t)b2; } + + uint8_t* footer_address() const { return ((address)this) + sizeof(MallocHeader) + _size; } + uint16_t get_footer() const { return build_footer(footer_address()[0], footer_address()[1]); } + void set_footer(uint16_t v) { footer_address()[0] = v >> 8; footer_address()[1] = (uint8_t)v; } + + public: - MallocMemorySummary::record_malloc(size, flags); - MallocMemorySummary::record_new_malloc_header(sizeof(MallocHeader)); + MallocHeader(size_t size, MEMFLAGS flags, const NativeCallStack& stack, uint32_t mst_marker) + : _size(size), _mst_marker(mst_marker), _flags(NMTUtil::flag_to_index(flags)), + _unused(0), _canary(_header_canary_life_mark) + { + assert(size < max_reasonable_malloc_size, "Too large allocation size?"); + // On 32-bit we have some bits more, use them for a second canary + // guarding the start of the header. + NOT_LP64(_alt_canary = _header_alt_canary_life_mark;) + set_footer(_footer_canary_life_mark); // set after initializing _size } inline size_t size() const { return _size; } inline MEMFLAGS flags() const { return (MEMFLAGS)_flags; } + inline uint32_t mst_marker() const { return _mst_marker; } bool get_stack(NativeCallStack& stack) const; - // Cleanup tracking information before the memory is released. - void release() const; + void mark_block_as_dead(); - private: - inline void set_size(size_t size) { - _size = size; - } - bool record_malloc_site(const NativeCallStack& stack, size_t size, - size_t* bucket_idx, size_t* pos_idx, MEMFLAGS flags) const; + // If block is broken, fill in a short descriptive text in out, + // an option pointer to the corruption in p_corruption, and return false. + // Return true if block is fine. + bool check_block_integrity(char* msg, size_t msglen, address* p_corruption) const; + + // If block is broken, print out a report to tty (optionally with + // hex dump surrounding the broken block), then trigger a fatal error + void assert_block_integrity() const; }; +// This needs to be true on both 64-bit and 32-bit platforms +STATIC_ASSERT(sizeof(MallocHeader) == (sizeof(uint64_t) * 2)); + // Main class called from MemTracker to track malloc activities class MallocTracker : AllStatic { @@ -308,12 +358,9 @@ class MallocTracker : AllStatic { // Initialize malloc tracker for specific tracking level static bool initialize(NMT_TrackingLevel level); - static bool transition(NMT_TrackingLevel from, NMT_TrackingLevel to); - - // malloc tracking header size for specific tracking level - static inline size_t malloc_header_size(NMT_TrackingLevel level) { - return (level == NMT_off) ? 0 : sizeof(MallocHeader); - } + // The overhead that is incurred by switching on NMT (we need, per malloc allocation, + // space for header and 16-bit footer) + static const size_t overhead_per_malloc = sizeof(MallocHeader) + sizeof(uint16_t); // Parameter name convention: // memblock : the beginning address for user data @@ -325,35 +372,11 @@ class MallocTracker : AllStatic { // Record malloc on specified memory block static void* record_malloc(void* malloc_base, size_t size, MEMFLAGS flags, - const NativeCallStack& stack, NMT_TrackingLevel level); + const NativeCallStack& stack); // Record free on specified memory block static void* record_free(void* memblock); - // Offset memory address to header address - static inline void* get_base(void* memblock); - static inline void* get_base(void* memblock, NMT_TrackingLevel level) { - if (memblock == NULL || level == NMT_off) return memblock; - return (char*)memblock - malloc_header_size(level); - } - - // Get memory size - static inline size_t get_size(void* memblock) { - MallocHeader* header = malloc_header(memblock); - return header->size(); - } - - // Get memory type - static inline MEMFLAGS get_flags(void* memblock) { - MallocHeader* header = malloc_header(memblock); - return header->flags(); - } - - // Get header size - static inline size_t get_header_size(void* memblock) { - return (memblock == NULL) ? 0 : sizeof(MallocHeader); - } - static inline void record_new_arena(MEMFLAGS flags) { MallocMemorySummary::record_new_arena(flags); } @@ -365,15 +388,23 @@ class MallocTracker : AllStatic { static inline void record_arena_size_change(ssize_t size, MEMFLAGS flags) { MallocMemorySummary::record_arena_size_change(size, flags); } + + // Given a pointer, if it seems to point to the start of a valid malloced block, + // print the block. Note that since there is very low risk of memory looking + // accidentally like a valid malloc block header (canaries and all) this is not + // totally failproof. Only use this during debugging or when you can afford + // signals popping up, e.g. when writing an hs_err file. + static bool print_pointer_information(const void* p, outputStream* st); + private: static inline MallocHeader* malloc_header(void *memblock) { assert(memblock != NULL, "NULL pointer"); - MallocHeader* header = (MallocHeader*)((char*)memblock - sizeof(MallocHeader)); - return header; + return (MallocHeader*)((char*)memblock - sizeof(MallocHeader)); + } + static inline const MallocHeader* malloc_header(const void *memblock) { + assert(memblock != NULL, "NULL pointer"); + return (const MallocHeader*)((const char*)memblock - sizeof(MallocHeader)); } }; -#endif // INCLUDE_NMT - - #endif // SHARE_SERVICES_MALLOCTRACKER_HPP diff --git a/src/hotspot/share/services/management.cpp b/src/hotspot/share/services/management.cpp index 7f103ea784974bb34c6508051a65872ec8956f8c..09c8750f6f9abc547c6fce396e64c35da06df4bc 100644 --- a/src/hotspot/share/services/management.cpp +++ b/src/hotspot/share/services/management.cpp @@ -2015,7 +2015,7 @@ JVM_ENTRY(void, jmm_GetDiagnosticCommandInfo(JNIEnv *env, jobjectArray cmds, JVM_END JVM_ENTRY(void, jmm_GetDiagnosticCommandArgumentsInfo(JNIEnv *env, - jstring command, dcmdArgInfo* infoArray)) + jstring command, dcmdArgInfo* infoArray, jint count)) ResourceMark rm(THREAD); oop cmd = JNIHandles::resolve_external_guard(command); if (cmd == NULL) { @@ -2039,10 +2039,12 @@ JVM_ENTRY(void, jmm_GetDiagnosticCommandArgumentsInfo(JNIEnv *env, } DCmdMark mark(dcmd); GrowableArray* array = dcmd->argument_info_array(); - if (array->length() == 0) { - return; + const int num_args = array->length(); + if (num_args != count) { + assert(false, "jmm_GetDiagnosticCommandArgumentsInfo count mismatch (%d vs %d)", count, num_args); + THROW_MSG(vmSymbols::java_lang_InternalError(), "jmm_GetDiagnosticCommandArgumentsInfo count mismatch"); } - for (int i = 0; i < array->length(); i++) { + for (int i = 0; i < num_args; i++) { infoArray[i].name = array->at(i)->name(); infoArray[i].description = array->at(i)->description(); infoArray[i].type = array->at(i)->type(); diff --git a/src/hotspot/share/services/memBaseline.hpp b/src/hotspot/share/services/memBaseline.hpp index c43c937abb107648d4bd1e031aba0961d4972632..ef8013734649ab6ebc6b6ea2f04e43626aa5b36a 100644 --- a/src/hotspot/share/services/memBaseline.hpp +++ b/src/hotspot/share/services/memBaseline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -25,8 +25,6 @@ #ifndef SHARE_SERVICES_MEMBASELINE_HPP #define SHARE_SERVICES_MEMBASELINE_HPP -#if INCLUDE_NMT - #include "memory/metaspaceStats.hpp" #include "runtime/mutex.hpp" #include "services/mallocSiteTable.hpp" @@ -212,6 +210,4 @@ class MemBaseline { void virtual_memory_sites_to_reservation_site_order(); }; -#endif // INCLUDE_NMT - #endif // SHARE_SERVICES_MEMBASELINE_HPP diff --git a/src/hotspot/share/services/memReporter.hpp b/src/hotspot/share/services/memReporter.hpp index 77fb1d70a00a84d3fc719d428cf3f45ad360f98a..2051ab88e3cd7f48493a30a9cb02782fcbe2e61b 100644 --- a/src/hotspot/share/services/memReporter.hpp +++ b/src/hotspot/share/services/memReporter.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -25,8 +25,6 @@ #ifndef SHARE_SERVICES_MEMREPORTER_HPP #define SHARE_SERVICES_MEMREPORTER_HPP -#if INCLUDE_NMT - #include "memory/metaspace.hpp" #include "oops/instanceKlass.hpp" #include "services/memBaseline.hpp" @@ -239,6 +237,4 @@ class MemDetailDiffReporter : public MemSummaryDiffReporter { size_t current_committed, size_t early_reserved, size_t early_committed, MEMFLAGS flag) const; }; -#endif // INCLUDE_NMT - #endif // SHARE_SERVICES_MEMREPORTER_HPP diff --git a/src/hotspot/share/services/memTracker.cpp b/src/hotspot/share/services/memTracker.cpp index a28d3badbcf25e102eb76ad81eb2a905ed9b2761..343703213ad6a4d7fdc9c6ee609b1959a8b1b212 100644 --- a/src/hotspot/share/services/memTracker.cpp +++ b/src/hotspot/share/services/memTracker.cpp @@ -33,7 +33,7 @@ #include "runtime/vmOperations.hpp" #include "services/memBaseline.hpp" #include "services/memReporter.hpp" -#include "services/mallocTracker.inline.hpp" +#include "services/mallocTracker.hpp" #include "services/memTracker.hpp" #include "services/nmtCommon.hpp" #include "services/nmtPreInit.hpp" @@ -90,10 +90,6 @@ void MemTracker::initialize() { } } -void* MemTracker::malloc_base(void* memblock) { - return MallocTracker::get_base(memblock); -} - void Tracker::record(address addr, size_t size) { if (MemTracker::tracking_level() < NMT_summary) return; switch(_type) { @@ -108,41 +104,9 @@ void Tracker::record(address addr, size_t size) { } } - -// Shutdown can only be issued via JCmd, and NMT JCmd is serialized by lock -void MemTracker::shutdown() { - // We can only shutdown NMT to minimal tracking level if it is ever on. - if (tracking_level() > NMT_minimal) { - transition_to(NMT_minimal); - } -} - -bool MemTracker::transition_to(NMT_TrackingLevel level) { - NMT_TrackingLevel current_level = tracking_level(); - - assert(level != NMT_off || current_level == NMT_off, "Cannot transition NMT to off"); - - if (current_level == level) { - return true; - } else if (current_level > level) { - // Downgrade tracking level, we want to lower the tracking level first - _tracking_level = level; - // Make _tracking_level visible immediately. - OrderAccess::fence(); - VirtualMemoryTracker::transition(current_level, level); - MallocTracker::transition(current_level, level); - ThreadStackTracker::transition(current_level, level); - } else { - // Upgrading tracking level is not supported and has never been supported. - // Allocating and deallocating malloc tracking structures is not thread safe and - // leads to inconsistencies unless a lot coarser locks are added. - } - return true; -} - // Report during error reporting. void MemTracker::error_report(outputStream* output) { - if (tracking_level() >= NMT_summary) { + if (enabled()) { report(true, output, MemReporterBase::default_scale); // just print summary for error case. output->print("Preinit state:"); NMTPreInit::print_state(output); @@ -157,11 +121,8 @@ void MemTracker::final_report(outputStream* output) { // printing the final report during normal VM exit, it should not print // the final report again. In addition, it should be guarded from // recursive calls in case NMT reporting itself crashes. - if (Atomic::cmpxchg(&g_final_report_did_run, false, true) == false) { - NMT_TrackingLevel level = tracking_level(); - if (level >= NMT_summary) { - report(level == NMT_summary, output, 1); - } + if (enabled() && Atomic::cmpxchg(&g_final_report_did_run, false, true) == false) { + report(tracking_level() == NMT_summary, output, 1); } } @@ -189,7 +150,6 @@ void MemTracker::tuning_statistics(outputStream* out) { out->print_cr("State: %s", NMTUtil::tracking_level_to_string(_tracking_level)); out->print_cr("Malloc allocation site table size: %d", MallocSiteTable::hash_buckets()); out->print_cr(" Tracking stack depth: %d", NMT_TrackingStackDepth); - NOT_PRODUCT(out->print_cr("Peak concurrent access: %d", MallocSiteTable::access_peak_count());) out->cr(); MallocSiteTable::print_tuning_statistics(out); out->cr(); diff --git a/src/hotspot/share/services/memTracker.hpp b/src/hotspot/share/services/memTracker.hpp index d18746f452e3210817aed5b1c5d7df2f0d824dd1..97ec9abd9f583a4e24dd3d77d40ca2639ae3788e 100644 --- a/src/hotspot/share/services/memTracker.hpp +++ b/src/hotspot/share/services/memTracker.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -25,66 +25,14 @@ #ifndef SHARE_SERVICES_MEMTRACKER_HPP #define SHARE_SERVICES_MEMTRACKER_HPP -#include "services/nmtCommon.hpp" -#include "utilities/nativeCallStack.hpp" - - -#if !INCLUDE_NMT - -#define CURRENT_PC NativeCallStack::empty_stack() -#define CALLER_PC NativeCallStack::empty_stack() - -class Tracker : public StackObj { - public: - enum TrackerType { - uncommit, - release - }; - Tracker(enum TrackerType type) : _type(type) { } - void record(address addr, size_t size) { } - private: - enum TrackerType _type; -}; - -class MemTracker : AllStatic { - public: - static inline NMT_TrackingLevel tracking_level() { return NMT_off; } - static inline void shutdown() { } - static inline void init() { } - static bool check_launcher_nmt_support(const char* value) { return true; } - static bool verify_nmt_option() { return true; } - - static inline void* record_malloc(void* mem_base, size_t size, MEMFLAGS flag, - const NativeCallStack& stack, NMT_TrackingLevel level) { return mem_base; } - static inline size_t malloc_header_size(NMT_TrackingLevel level) { return 0; } - static inline size_t malloc_header_size(void* memblock) { return 0; } - static inline void* malloc_base(void* memblock) { return memblock; } - static inline void* record_free(void* memblock, NMT_TrackingLevel level) { return memblock; } - - static inline void record_new_arena(MEMFLAGS flag) { } - static inline void record_arena_free(MEMFLAGS flag) { } - static inline void record_arena_size_change(ssize_t diff, MEMFLAGS flag) { } - static inline void record_virtual_memory_reserve(void* addr, size_t size, const NativeCallStack& stack, - MEMFLAGS flag = mtNone) { } - static inline void record_virtual_memory_reserve_and_commit(void* addr, size_t size, - const NativeCallStack& stack, MEMFLAGS flag = mtNone) { } - static inline void record_virtual_memory_split_reserved(void* addr, size_t size, size_t split) { } - static inline void record_virtual_memory_commit(void* addr, size_t size, const NativeCallStack& stack) { } - static inline void record_virtual_memory_type(void* addr, MEMFLAGS flag) { } - static inline void record_thread_stack(void* addr, size_t size) { } - static inline void release_thread_stack(void* addr, size_t size) { } - - static void final_report(outputStream*) { } - static void error_report(outputStream*) { } -}; - -#else - #include "runtime/mutexLocker.hpp" #include "runtime/threadCritical.hpp" #include "services/mallocTracker.hpp" +#include "services/nmtCommon.hpp" #include "services/threadStackTracker.hpp" #include "services/virtualMemoryTracker.hpp" +#include "utilities/debug.hpp" +#include "utilities/nativeCallStack.hpp" #define CURRENT_PC ((MemTracker::tracking_level() == NMT_detail) ? \ NativeCallStack(0) : NativeCallStack::empty_stack()) @@ -136,65 +84,50 @@ class MemTracker : AllStatic { return _tracking_level; } - // Shutdown native memory tracking. - // This transitions the tracking level: - // summary -> minimal - // detail -> minimal - static void shutdown(); - - // Transition the tracking level to specified level - static bool transition_to(NMT_TrackingLevel level); - - static inline void* record_malloc(void* mem_base, size_t size, MEMFLAGS flag, - const NativeCallStack& stack, NMT_TrackingLevel level) { - if (level != NMT_off) { - return MallocTracker::record_malloc(mem_base, size, flag, stack, level); - } - return mem_base; + static inline bool enabled() { + return _tracking_level > NMT_off; } - static inline size_t malloc_header_size(NMT_TrackingLevel level) { - return MallocTracker::malloc_header_size(level); + // Per-malloc overhead incurred by NMT, depending on the current NMT level + static size_t overhead_per_malloc() { + return enabled() ? MallocTracker::overhead_per_malloc : 0; } - static size_t malloc_header_size(void* memblock) { - if (tracking_level() != NMT_off) { - return MallocTracker::get_header_size(memblock); + static inline void* record_malloc(void* mem_base, size_t size, MEMFLAGS flag, + const NativeCallStack& stack) { + assert(mem_base != NULL, "caller should handle NULL"); + if (enabled()) { + return MallocTracker::record_malloc(mem_base, size, flag, stack); } - return 0; + return mem_base; } - // To malloc base address, which is the starting address - // of malloc tracking header if tracking is enabled. - // Otherwise, it returns the same address. - static void* malloc_base(void* memblock); - // Record malloc free and return malloc base address - static inline void* record_free(void* memblock, NMT_TrackingLevel level) { + static inline void* record_free(void* memblock) { // Never turned on - if (level == NMT_off || memblock == NULL) { + assert(memblock != NULL, "caller should handle NULL"); + if (!enabled()) { return memblock; } return MallocTracker::record_free(memblock); } - // Record creation of an arena static inline void record_new_arena(MEMFLAGS flag) { - if (tracking_level() < NMT_summary) return; + if (!enabled()) return; MallocTracker::record_new_arena(flag); } // Record destruction of an arena static inline void record_arena_free(MEMFLAGS flag) { - if (tracking_level() < NMT_summary) return; + if (!enabled()) return; MallocTracker::record_arena_free(flag); } // Record arena size change. Arena size is the size of all arena // chuncks that backing up the arena. static inline void record_arena_size_change(ssize_t diff, MEMFLAGS flag) { - if (tracking_level() < NMT_summary) return; + if (!enabled()) return; MallocTracker::record_arena_size_change(diff, flag); } @@ -204,11 +137,9 @@ class MemTracker : AllStatic { static inline void record_virtual_memory_reserve(void* addr, size_t size, const NativeCallStack& stack, MEMFLAGS flag = mtNone) { assert_post_init(); - if (tracking_level() < NMT_summary) return; + if (!enabled()) return; if (addr != NULL) { ThreadCritical tc; - // Recheck to avoid potential racing during NMT shutdown - if (tracking_level() < NMT_summary) return; VirtualMemoryTracker::add_reserved_region((address)addr, size, stack, flag); } } @@ -216,10 +147,9 @@ class MemTracker : AllStatic { static inline void record_virtual_memory_reserve_and_commit(void* addr, size_t size, const NativeCallStack& stack, MEMFLAGS flag = mtNone) { assert_post_init(); - if (tracking_level() < NMT_summary) return; + if (!enabled()) return; if (addr != NULL) { ThreadCritical tc; - if (tracking_level() < NMT_summary) return; VirtualMemoryTracker::add_reserved_region((address)addr, size, stack, flag); VirtualMemoryTracker::add_committed_region((address)addr, size, stack); } @@ -228,10 +158,9 @@ class MemTracker : AllStatic { static inline void record_virtual_memory_commit(void* addr, size_t size, const NativeCallStack& stack) { assert_post_init(); - if (tracking_level() < NMT_summary) return; + if (!enabled()) return; if (addr != NULL) { ThreadCritical tc; - if (tracking_level() < NMT_summary) return; VirtualMemoryTracker::add_committed_region((address)addr, size, stack); } } @@ -244,28 +173,25 @@ class MemTracker : AllStatic { // memory flags of the original region. static inline void record_virtual_memory_split_reserved(void* addr, size_t size, size_t split) { assert_post_init(); - if (tracking_level() < NMT_summary) return; + if (!enabled()) return; if (addr != NULL) { ThreadCritical tc; - // Recheck to avoid potential racing during NMT shutdown - if (tracking_level() < NMT_summary) return; VirtualMemoryTracker::split_reserved_region((address)addr, size, split); } } static inline void record_virtual_memory_type(void* addr, MEMFLAGS flag) { assert_post_init(); - if (tracking_level() < NMT_summary) return; + if (!enabled()) return; if (addr != NULL) { ThreadCritical tc; - if (tracking_level() < NMT_summary) return; VirtualMemoryTracker::set_reserved_region_type((address)addr, flag); } } static void record_thread_stack(void* addr, size_t size) { assert_post_init(); - if (tracking_level() < NMT_summary) return; + if (!enabled()) return; if (addr != NULL) { ThreadStackTracker::new_thread_stack((address)addr, size, CALLER_PC); } @@ -273,7 +199,7 @@ class MemTracker : AllStatic { static inline void release_thread_stack(void* addr, size_t size) { assert_post_init(); - if (tracking_level() < NMT_summary) return; + if (!enabled()) return; if (addr != NULL) { ThreadStackTracker::delete_thread_stack((address)addr, size); } @@ -322,6 +248,4 @@ class MemTracker : AllStatic { static Mutex* _query_lock; }; -#endif // INCLUDE_NMT - #endif // SHARE_SERVICES_MEMTRACKER_HPP diff --git a/src/hotspot/share/services/nmtCommon.cpp b/src/hotspot/share/services/nmtCommon.cpp index 0137a880d8c55c42b6a51dd806be58ce1d535447..2494336595bb73866736690db4f1df1e1c513fc5 100644 --- a/src/hotspot/share/services/nmtCommon.cpp +++ b/src/hotspot/share/services/nmtCommon.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -28,11 +28,14 @@ #define MEMORY_TYPE_DECLARE_NAME(type, human_readable) \ human_readable, +STATIC_ASSERT(NMT_off > NMT_unknown); +STATIC_ASSERT(NMT_summary > NMT_off); +STATIC_ASSERT(NMT_detail > NMT_summary); + const char* NMTUtil::_memory_type_names[] = { MEMORY_TYPES_DO(MEMORY_TYPE_DECLARE_NAME) }; - const char* NMTUtil::scale_name(size_t scale) { switch(scale) { case 1: return ""; @@ -64,7 +67,6 @@ const char* NMTUtil::tracking_level_to_string(NMT_TrackingLevel lvl) { switch(lvl) { case NMT_unknown: return "unknown"; break; case NMT_off: return "off"; break; - case NMT_minimal: return "minimal"; break; case NMT_summary: return "summary"; break; case NMT_detail: return "detail"; break; default: return "invalid"; break; diff --git a/src/hotspot/share/services/nmtCommon.hpp b/src/hotspot/share/services/nmtCommon.hpp index 108769760915dc7cbfb549a6898e2fbdad695b6c..f25e5cfd8c95f58a1d93da616b158e456235c83d 100644 --- a/src/hotspot/share/services/nmtCommon.hpp +++ b/src/hotspot/share/services/nmtCommon.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -25,7 +25,7 @@ #ifndef SHARE_SERVICES_NMTCOMMON_HPP #define SHARE_SERVICES_NMTCOMMON_HPP -#include "memory/allocation.hpp" +#include "memory/allocation.hpp" // for MEMFLAGS only #include "utilities/align.hpp" #include "utilities/globalDefinitions.hpp" @@ -41,10 +41,6 @@ // - nothing is tracked // - no malloc headers are used // -// "minimal": after shutdown - NMT had been on at some point but has been switched off -// - nothing is tracked -// - malloc headers are allocated but not initialized not used -// // "summary": after initialization with NativeMemoryTracking=summary - NMT in summary mode // - category summaries per tag are tracked // - thread stacks are tracked @@ -59,25 +55,16 @@ // - malloc headers are used // - malloc call site table is allocated and used // -// Valid state transitions: -// -// unknown ----> off -// | -// |--> summary -- -// | | -// |--> detail --+--> minimal -// // Please keep relation of numerical values! -// unknown < off < minimal < summary < detail +// unknown < off < summary < detail // enum NMT_TrackingLevel { - NMT_unknown = 0, - NMT_off = 1, - NMT_minimal = 2, - NMT_summary = 3, - NMT_detail = 4 + NMT_unknown, + NMT_off, + NMT_summary, + NMT_detail }; // Number of stack frames to capture. This is a @@ -100,7 +87,7 @@ class NMTUtil : AllStatic { // Map memory type to index static inline int flag_to_index(MEMFLAGS flag) { - assert(flag_is_valid(flag), "Invalid flag"); + assert(flag_is_valid(flag), "Invalid flag (%u)", (unsigned)flag); return static_cast(flag); } @@ -111,7 +98,7 @@ class NMTUtil : AllStatic { // Map an index to memory type static MEMFLAGS index_to_flag(int index) { - assert(flag_index_is_valid(index), "Invalid flag"); + assert(flag_index_is_valid(index), "Invalid flag index (%d)", index); return static_cast(index); } diff --git a/src/hotspot/share/services/nmtDCmd.cpp b/src/hotspot/share/services/nmtDCmd.cpp index e89dd2c56e703b78e6abd6ce95c555f80a668965..dd8eb17c298bc264c7ec5a2badc552c5c94448cf 100644 --- a/src/hotspot/share/services/nmtDCmd.cpp +++ b/src/hotspot/share/services/nmtDCmd.cpp @@ -50,9 +50,6 @@ NMTDCmd::NMTDCmd(outputStream* output, "comparison against previous baseline, which shows the memory " \ "allocation activities at different callsites.", "BOOLEAN", false, "false"), - _shutdown("shutdown", "request runtime to shutdown itself and free the " \ - "memory used by runtime.", - "BOOLEAN", false, "false"), _statistics("statistics", "print tracker statistics for tuning purpose.", \ "BOOLEAN", false, "false"), _scale("scale", "Memory usage in which scale, KB, MB or GB", @@ -62,7 +59,6 @@ NMTDCmd::NMTDCmd(outputStream* output, _dcmdparser.add_dcmd_option(&_baseline); _dcmdparser.add_dcmd_option(&_summary_diff); _dcmdparser.add_dcmd_option(&_detail_diff); - _dcmdparser.add_dcmd_option(&_shutdown); _dcmdparser.add_dcmd_option(&_statistics); _dcmdparser.add_dcmd_option(&_scale); } @@ -79,9 +75,6 @@ void NMTDCmd::execute(DCmdSource source, TRAPS) { if (MemTracker::tracking_level() == NMT_off) { output()->print_cr("Native memory tracking is not enabled"); return; - } else if (MemTracker::tracking_level() == NMT_minimal) { - output()->print_cr("Native memory tracking has been shutdown"); - return; } const char* scale_value = _scale.value(); @@ -97,12 +90,11 @@ void NMTDCmd::execute(DCmdSource source, TRAPS) { if (_baseline.is_set() && _baseline.value()) { ++nopt; } if (_summary_diff.is_set() && _summary_diff.value()) { ++nopt; } if (_detail_diff.is_set() && _detail_diff.value()) { ++nopt; } - if (_shutdown.is_set() && _shutdown.value()) { ++nopt; } if (_statistics.is_set() && _statistics.value()) { ++nopt; } if (nopt > 1) { output()->print_cr("At most one of the following option can be specified: " \ - "summary, detail, metadata, baseline, summary.diff, detail.diff, shutdown"); + "summary, detail, metadata, baseline, summary.diff, detail.diff"); return; } else if (nopt == 0) { if (_summary.is_set()) { @@ -147,9 +139,6 @@ void NMTDCmd::execute(DCmdSource source, TRAPS) { } else { output()->print_cr("No detail baseline for comparison"); } - } else if (_shutdown.value()) { - MemTracker::shutdown(); - output()->print_cr("Native memory tracking has been turned off"); } else if (_statistics.value()) { if (check_detail_tracking_level(output())) { MemTracker::tuning_statistics(output()); diff --git a/src/hotspot/share/services/nmtDCmd.hpp b/src/hotspot/share/services/nmtDCmd.hpp index 1ea19735cdc41fdfc3127a6cd8a0d3eaa4835c30..23302b790a6bf65869207bbbb53be5dae857944f 100644 --- a/src/hotspot/share/services/nmtDCmd.hpp +++ b/src/hotspot/share/services/nmtDCmd.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -25,8 +25,6 @@ #ifndef SHARE_SERVICES_NMTDCMD_HPP #define SHARE_SERVICES_NMTDCMD_HPP -#if INCLUDE_NMT - #include "services/diagnosticArgument.hpp" #include "services/diagnosticFramework.hpp" #include "services/memBaseline.hpp" @@ -42,7 +40,6 @@ class NMTDCmd: public DCmdWithParser { DCmdArgument _baseline; DCmdArgument _summary_diff; DCmdArgument _detail_diff; - DCmdArgument _shutdown; DCmdArgument _statistics; DCmdArgument _scale; @@ -72,6 +69,4 @@ class NMTDCmd: public DCmdWithParser { bool check_detail_tracking_level(outputStream* out); }; -#endif // INCLUDE_NMT - #endif // SHARE_SERVICES_NMTDCMD_HPP diff --git a/src/hotspot/share/services/nmtPreInit.cpp b/src/hotspot/share/services/nmtPreInit.cpp index 1fdf4ba9d9f572d1cf5fb818debe1b8c8f397ded..67eb3eef41f6abf85e20b4057fedde326d08420b 100644 --- a/src/hotspot/share/services/nmtPreInit.cpp +++ b/src/hotspot/share/services/nmtPreInit.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2021 SAP SE. All rights reserved. - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022 SAP SE. All rights reserved. + * 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 @@ -31,8 +31,6 @@ #include "utilities/ostream.hpp" #include "utilities/globalDefinitions.hpp" -#if INCLUDE_NMT - // Obviously we cannot use os::malloc for any dynamic allocation during pre-NMT-init, so we must use // raw malloc; to make this very clear, wrap them. static void* raw_malloc(size_t s) { return ::malloc(s); } @@ -190,5 +188,3 @@ void NMTPreInit::print_state(outputStream* st) { st->print_cr("pre-init mallocs: %u, pre-init reallocs: %u, pre-init frees: %u", _num_mallocs_pre, _num_reallocs_pre, _num_frees_pre); } - -#endif // INCLUDE_NMT diff --git a/src/hotspot/share/services/nmtPreInit.hpp b/src/hotspot/share/services/nmtPreInit.hpp index eed2519113554db9f37ad3c53b8a4401d49fa892..d65ebaf5dc3bd22d932d690158c5ee0f6834adcd 100644 --- a/src/hotspot/share/services/nmtPreInit.hpp +++ b/src/hotspot/share/services/nmtPreInit.hpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2021 SAP SE. All rights reserved. - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022 SAP SE. All rights reserved. + * 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 @@ -34,8 +34,6 @@ #include "utilities/globalDefinitions.hpp" #include "utilities/macros.hpp" -#if INCLUDE_NMT - class outputStream; // NMTPreInit is the solution to a specific problem: @@ -353,7 +351,5 @@ public: DEBUG_ONLY(static void verify();) }; -#endif // INCLUDE_NMT - #endif // SHARE_SERVICES_NMT_PREINIT_HPP diff --git a/src/hotspot/share/services/threadIdTable.hpp b/src/hotspot/share/services/threadIdTable.hpp index 223b57fcecbf5597cc6893a6b398522a58e0940d..12772aed88c0b62c457ca0903bcd6d6b1ebeabdb 100644 --- a/src/hotspot/share/services/threadIdTable.hpp +++ b/src/hotspot/share/services/threadIdTable.hpp @@ -26,7 +26,7 @@ #ifndef SHARE_SERVICES_THREADIDTABLE_HPP #define SHARE_SERVICES_THREADIDTABLE_HPP -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" class JavaThread; class ThreadsList; diff --git a/src/hotspot/share/services/threadService.cpp b/src/hotspot/share/services/threadService.cpp index c99d789021b0dabfb0c460118203765010826980..42b38000a84f1ae863fa7ea4c3ca5de88cf3c02f 100644 --- a/src/hotspot/share/services/threadService.cpp +++ b/src/hotspot/share/services/threadService.cpp @@ -659,7 +659,7 @@ ThreadStackTrace::~ThreadStackTrace() { } } -void ThreadStackTrace::dump_stack_at_safepoint(int maxDepth) { +void ThreadStackTrace::dump_stack_at_safepoint(int maxDepth, ObjectMonitorsHashtable* table) { assert(SafepointSynchronize::is_at_safepoint(), "all threads are stopped"); if (_thread->has_last_Java_frame()) { @@ -683,9 +683,19 @@ void ThreadStackTrace::dump_stack_at_safepoint(int maxDepth) { if (_with_locked_monitors) { // Iterate inflated monitors and find monitors locked by this thread - // not found in the stack + // that are not found in the stack, e.g. JNI locked monitors: InflatedMonitorsClosure imc(this); - ObjectSynchronizer::monitors_iterate(&imc, _thread); + if (table != nullptr) { + // Get the ObjectMonitors locked by the target thread, if any, + // and does not include any where owner is set to a stack lock + // address in the target thread: + ObjectMonitorsHashtable::PtrList* list = table->get_entry(_thread); + if (list != nullptr) { + ObjectSynchronizer::monitors_iterate(&imc, list, _thread); + } + } else { + ObjectSynchronizer::monitors_iterate(&imc, _thread); + } } } @@ -936,9 +946,10 @@ ThreadSnapshot::~ThreadSnapshot() { delete _concurrent_locks; } -void ThreadSnapshot::dump_stack_at_safepoint(int max_depth, bool with_locked_monitors) { +void ThreadSnapshot::dump_stack_at_safepoint(int max_depth, bool with_locked_monitors, + ObjectMonitorsHashtable* table) { _stack_trace = new ThreadStackTrace(_thread, with_locked_monitors); - _stack_trace->dump_stack_at_safepoint(max_depth); + _stack_trace->dump_stack_at_safepoint(max_depth, table); } diff --git a/src/hotspot/share/services/threadService.hpp b/src/hotspot/share/services/threadService.hpp index e78fbab080866e9ea68ea0ad775fcf329dfe0de5..ed411d42a90d58fbfb5a2f017917598f6ac67e39 100644 --- a/src/hotspot/share/services/threadService.hpp +++ b/src/hotspot/share/services/threadService.hpp @@ -247,7 +247,8 @@ public: ThreadStackTrace* get_stack_trace() { return _stack_trace; } ThreadConcurrentLocks* get_concurrent_locks() { return _concurrent_locks; } - void dump_stack_at_safepoint(int max_depth, bool with_locked_monitors); + void dump_stack_at_safepoint(int max_depth, bool with_locked_monitors, + ObjectMonitorsHashtable* table); void set_concurrent_locks(ThreadConcurrentLocks* l) { _concurrent_locks = l; } void metadata_do(void f(Metadata*)); }; @@ -270,7 +271,7 @@ class ThreadStackTrace : public CHeapObj { int get_stack_depth() { return _depth; } void add_stack_frame(javaVFrame* jvf); - void dump_stack_at_safepoint(int max_depth); + void dump_stack_at_safepoint(int max_depth, ObjectMonitorsHashtable* table); Handle allocate_fill_stack_trace_element_array(TRAPS); void metadata_do(void f(Metadata*)); GrowableArray* jni_locked_monitors() { return _jni_locked_monitors; } diff --git a/src/hotspot/share/services/threadStackTracker.cpp b/src/hotspot/share/services/threadStackTracker.cpp index b426e81613bf1a41361a0453a9202fa073e6c98a..5caad66bb89f5558b1d157e96af8da7d33ba50ea 100644 --- a/src/hotspot/share/services/threadStackTracker.cpp +++ b/src/hotspot/share/services/threadStackTracker.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Red Hat, Inc. All rights reserved. + * Copyright (c) 2019, 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 @@ -42,19 +42,6 @@ bool ThreadStackTracker::initialize(NMT_TrackingLevel level) { return true; } -bool ThreadStackTracker::transition(NMT_TrackingLevel from, NMT_TrackingLevel to) { - assert (from != NMT_minimal, "cannot convert from the lowest tracking level to anything"); - if (to == NMT_minimal) { - assert(from == NMT_summary || from == NMT_detail, "Just check"); - ThreadCritical tc; - if (_simple_thread_stacks != NULL) { - delete _simple_thread_stacks; - _simple_thread_stacks = NULL; - } - } - return true; -} - int ThreadStackTracker::compare_thread_stack_base(const SimpleThreadStackSite& s1, const SimpleThreadStackSite& s2) { return s1.base() - s2.base(); } diff --git a/src/hotspot/share/services/threadStackTracker.hpp b/src/hotspot/share/services/threadStackTracker.hpp index 3eee93cd71c4e06b4b6753a1f51aa14b203f6a1c..db7fc0e8569f4e84960b958ff51e496a5e48c3ff 100644 --- a/src/hotspot/share/services/threadStackTracker.hpp +++ b/src/hotspot/share/services/threadStackTracker.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Red Hat, Inc. All rights reserved. + * Copyright (c) 2019, 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 @@ -25,8 +25,6 @@ #ifndef SHARE_SERVICES_THREADSTACKTRACKER_HPP #define SHARE_SERVICES_THREADSTACKTRACKER_HPP -#if INCLUDE_NMT - #include "services/allocationSite.hpp" #include "services/mallocSiteTable.hpp" #include "services/nmtCommon.hpp" @@ -72,7 +70,6 @@ private: static SortedLinkedList* _simple_thread_stacks; public: static bool initialize(NMT_TrackingLevel level); - static bool transition(NMT_TrackingLevel from, NMT_TrackingLevel to); static void new_thread_stack(void* base, size_t size, const NativeCallStack& stack); static void delete_thread_stack(void* base, size_t size); @@ -85,5 +82,5 @@ public: static bool walk_simple_thread_stack_site(MallocSiteWalker* walker); }; -#endif // INCLUDE_NMT #endif // SHARE_SERVICES_THREADSTACKTRACKER_HPP + diff --git a/src/hotspot/share/services/virtualMemoryTracker.cpp b/src/hotspot/share/services/virtualMemoryTracker.cpp index f9909f9e5691443077a4c066d6f952771d4a4264..d259966e6117d1ed7632fc7a9366e0051d8ad797 100644 --- a/src/hotspot/share/services/virtualMemoryTracker.cpp +++ b/src/hotspot/share/services/virtualMemoryTracker.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -672,19 +672,32 @@ bool VirtualMemoryTracker::walk_virtual_memory(VirtualMemoryWalker* walker) { return true; } -// Transition virtual memory tracking level. -bool VirtualMemoryTracker::transition(NMT_TrackingLevel from, NMT_TrackingLevel to) { - assert (from != NMT_minimal, "cannot convert from the lowest tracking level to anything"); - if (to == NMT_minimal) { - assert(from == NMT_summary || from == NMT_detail, "Just check"); - // Clean up virtual memory tracking data structures. - ThreadCritical tc; - // Check for potential race with other thread calling transition - if (_reserved_regions != NULL) { - delete _reserved_regions; - _reserved_regions = NULL; +class PrintRegionWalker : public VirtualMemoryWalker { +private: + const address _p; + outputStream* _st; +public: + PrintRegionWalker(const void* p, outputStream* st) : + _p((address)p), _st(st) { } + + bool do_allocation_site(const ReservedMemoryRegion* rgn) { + if (rgn->contain_address(_p)) { + _st->print_cr(PTR_FORMAT " in mmap'd memory region [" PTR_FORMAT " - " PTR_FORMAT "] by %s", + p2i(_p), p2i(rgn->base()), p2i(rgn->base() + rgn->size()), rgn->flag_name()); + if (MemTracker::tracking_level() == NMT_detail) { + rgn->call_stack()->print_on(_st); + _st->cr(); + } + return false; } + return true; } +}; + +// If p is contained within a known memory region, print information about it to the +// given stream and return true; false otherwise. +bool VirtualMemoryTracker::print_containing_region(const void* p, outputStream* st) { + PrintRegionWalker walker(p, st); + return !walk_virtual_memory(&walker); - return true; } diff --git a/src/hotspot/share/services/virtualMemoryTracker.hpp b/src/hotspot/share/services/virtualMemoryTracker.hpp index a7948f67447ead9d4d1f6933c1ea4740cc054bc7..9ae61a605fb1eab83873cdf822c338cd3ddf08a7 100644 --- a/src/hotspot/share/services/virtualMemoryTracker.hpp +++ b/src/hotspot/share/services/virtualMemoryTracker.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -25,8 +25,6 @@ #ifndef SHARE_SERVICES_VIRTUALMEMORYTRACKER_HPP #define SHARE_SERVICES_VIRTUALMEMORYTRACKER_HPP -#if INCLUDE_NMT - #include "memory/allocation.hpp" #include "memory/metaspace.hpp" // For MetadataType #include "memory/metaspaceStats.hpp" @@ -341,7 +339,7 @@ class ReservedMemoryRegion : public VirtualMemoryRegion { return *this; } - const char* flag_name() { return NMTUtil::flag_to_name(_flag); } + const char* flag_name() const { return NMTUtil::flag_to_name(_flag); } private: // The committed region contains the uncommitted region, subtract the uncommitted @@ -387,7 +385,9 @@ class VirtualMemoryTracker : AllStatic { // Walk virtual memory data structure for creating baseline, etc. static bool walk_virtual_memory(VirtualMemoryWalker* walker); - static bool transition(NMT_TrackingLevel from, NMT_TrackingLevel to); + // If p is contained within a known memory region, print information about it to the + // given stream and return true; false otherwise. + static bool print_containing_region(const void* p, outputStream* st); // Snapshot current thread stacks static void snapshot_thread_stacks(); @@ -396,6 +396,5 @@ class VirtualMemoryTracker : AllStatic { static SortedLinkedList* _reserved_regions; }; -#endif // INCLUDE_NMT - #endif // SHARE_SERVICES_VIRTUALMEMORYTRACKER_HPP + diff --git a/src/hotspot/share/utilities/accessFlags.hpp b/src/hotspot/share/utilities/accessFlags.hpp index cb3663349a82030d675997cde8811fb7b403e69e..71c9c286f8fc690f44e6a2796841cc680cf29962 100644 --- a/src/hotspot/share/utilities/accessFlags.hpp +++ b/src/hotspot/share/utilities/accessFlags.hpp @@ -69,11 +69,13 @@ enum { JVM_ACC_IS_SHARED_CLASS = 0x02000000, // True if klass is shared JVM_ACC_IS_HIDDEN_CLASS = 0x04000000, // True if klass is hidden JVM_ACC_IS_VALUE_BASED_CLASS = 0x08000000, // True if klass is marked as a ValueBased class + JVM_ACC_IS_BEING_REDEFINED = 0x00100000, // True if the klass is being redefined. + JVM_ACC_HAS_RESOLVED_METHODS = 0x00200000, // True if the klass has resolved methods // Klass* and Method* flags - JVM_ACC_HAS_LOCAL_VARIABLE_TABLE= 0x00200000, + JVM_ACC_HAS_LOCAL_VARIABLE_TABLE= 0x00400000, - JVM_ACC_PROMOTED_FLAGS = 0x00200000, // flags promoted from methods to the holding klass + JVM_ACC_PROMOTED_FLAGS = 0x00400000, // flags promoted from methods to the holding klass // field flags // Note: these flags must be defined in the low order 16 bits because @@ -159,6 +161,13 @@ class AccessFlags { void set_has_localvariable_table() { atomic_set_bits(JVM_ACC_HAS_LOCAL_VARIABLE_TABLE); } void clear_has_localvariable_table() { atomic_clear_bits(JVM_ACC_HAS_LOCAL_VARIABLE_TABLE); } + bool is_being_redefined() const { return (_flags & JVM_ACC_IS_BEING_REDEFINED) != 0; } + void set_is_being_redefined() { atomic_set_bits(JVM_ACC_IS_BEING_REDEFINED); } + void clear_is_being_redefined() { atomic_clear_bits(JVM_ACC_IS_BEING_REDEFINED); } + + bool has_resolved_methods() const { return (_flags & JVM_ACC_HAS_RESOLVED_METHODS) != 0; } + void set_has_resolved_methods() { atomic_set_bits(JVM_ACC_HAS_RESOLVED_METHODS); } + // field flags bool is_field_access_watched() const { return (_flags & JVM_ACC_FIELD_ACCESS_WATCHED) != 0; } bool is_field_modification_watched() const diff --git a/src/hotspot/share/utilities/constantTag.hpp b/src/hotspot/share/utilities/constantTag.hpp index 4926eafa81c8b342e4ccfeb53cb92f971e2136c2..d826fc0acc0528b6e40800222d2decb818106db4 100644 --- a/src/hotspot/share/utilities/constantTag.hpp +++ b/src/hotspot/share/utilities/constantTag.hpp @@ -86,6 +86,13 @@ class constantTag { return _tag == JVM_CONSTANT_DynamicInError; } + bool is_in_error() const { + return is_unresolved_klass_in_error() || + is_method_handle_in_error() || + is_method_type_in_error() || + is_dynamic_constant_in_error(); + } + bool is_klass_index() const { return _tag == JVM_CONSTANT_ClassIndex; } bool is_string_index() const { return _tag == JVM_CONSTANT_StringIndex; } @@ -121,18 +128,24 @@ class constantTag { _tag = tag; } - static constantTag ofBasicType(BasicType bt) { - if (is_subword_type(bt)) bt = T_INT; + static jbyte type2tag(BasicType bt) { + if (is_subword_type(bt)) { + bt = T_INT; + } + if (bt == T_ARRAY) { + bt = T_OBJECT; + } switch (bt) { - case T_OBJECT: return constantTag(JVM_CONSTANT_String); - case T_INT: return constantTag(JVM_CONSTANT_Integer); - case T_LONG: return constantTag(JVM_CONSTANT_Long); - case T_FLOAT: return constantTag(JVM_CONSTANT_Float); - case T_DOUBLE: return constantTag(JVM_CONSTANT_Double); - default: break; + case T_INT: return JVM_CONSTANT_Integer; + case T_LONG: return JVM_CONSTANT_Long; + case T_FLOAT: return JVM_CONSTANT_Float; + case T_DOUBLE: return JVM_CONSTANT_Double; + case T_OBJECT: return JVM_CONSTANT_String; + + default: + assert(false, "not supported: %s", type2name(bt)); + return JVM_CONSTANT_Invalid; } - assert(false, "bad basic type for tag"); - return constantTag(); } jbyte value() const { return _tag; } diff --git a/src/hotspot/share/utilities/copy.hpp b/src/hotspot/share/utilities/copy.hpp index bd502d5313d27b7cd712c097d9eea082df13075a..8c77f4d735bf19a5eadf7a02ea2dc84c9df2962a 100644 --- a/src/hotspot/share/utilities/copy.hpp +++ b/src/hotspot/share/utilities/copy.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -26,6 +26,7 @@ #define SHARE_UTILITIES_COPY_HPP #include "oops/oopsHierarchy.hpp" +#include "runtime/atomic.hpp" #include "runtime/globals.hpp" #include "utilities/align.hpp" #include "utilities/bytes.hpp" @@ -37,15 +38,6 @@ extern "C" { void _Copy_conjoint_words(const HeapWord* from, HeapWord* to, size_t count); void _Copy_disjoint_words(const HeapWord* from, HeapWord* to, size_t count); - void _Copy_conjoint_words_atomic(const HeapWord* from, HeapWord* to, size_t count); - void _Copy_disjoint_words_atomic(const HeapWord* from, HeapWord* to, size_t count); - - void _Copy_aligned_conjoint_words(const HeapWord* from, HeapWord* to, size_t count); - void _Copy_aligned_disjoint_words(const HeapWord* from, HeapWord* to, size_t count); - - void _Copy_conjoint_bytes(const void* from, void* to, size_t count); - - void _Copy_conjoint_bytes_atomic (const void* from, void* to, size_t count); void _Copy_conjoint_jshorts_atomic(const jshort* from, jshort* to, size_t count); void _Copy_conjoint_jints_atomic (const jint* from, jint* to, size_t count); void _Copy_conjoint_jlongs_atomic (const jlong* from, jlong* to, size_t count); @@ -55,7 +47,6 @@ extern "C" { void _Copy_arrayof_conjoint_jshorts(const HeapWord* from, HeapWord* to, size_t count); void _Copy_arrayof_conjoint_jints (const HeapWord* from, HeapWord* to, size_t count); void _Copy_arrayof_conjoint_jlongs (const HeapWord* from, HeapWord* to, size_t count); - void _Copy_arrayof_conjoint_oops (const HeapWord* from, HeapWord* to, size_t count); } class Copy : AllStatic { @@ -307,6 +298,28 @@ class Copy : AllStatic { pd_zero_to_bytes(to, count); } + protected: + inline static void shared_disjoint_words_atomic(const HeapWord* from, + HeapWord* to, size_t count) { + + switch (count) { + case 8: Atomic::store(&to[7], Atomic::load(&from[7])); + case 7: Atomic::store(&to[6], Atomic::load(&from[6])); + case 6: Atomic::store(&to[5], Atomic::load(&from[5])); + case 5: Atomic::store(&to[4], Atomic::load(&from[4])); + case 4: Atomic::store(&to[3], Atomic::load(&from[3])); + case 3: Atomic::store(&to[2], Atomic::load(&from[2])); + case 2: Atomic::store(&to[1], Atomic::load(&from[1])); + case 1: Atomic::store(&to[0], Atomic::load(&from[0])); + case 0: break; + default: + while (count-- > 0) { + Atomic::store(to++, Atomic::load(from++)); + } + break; + } + } + private: static bool params_disjoint(const HeapWord* from, HeapWord* to, size_t count) { if (from < to) { diff --git a/src/hotspot/share/utilities/debug.cpp b/src/hotspot/share/utilities/debug.cpp index 778d1a1b4a4ef8759a3359111b8ba325ceffdabe..a35770f2c52677ea84be60e44d4049f65a76dff1 100644 --- a/src/hotspot/share/utilities/debug.cpp +++ b/src/hotspot/share/utilities/debug.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -51,7 +51,9 @@ #include "runtime/vframe.hpp" #include "runtime/vm_version.hpp" #include "services/heapDumper.hpp" +#include "services/mallocTracker.hpp" #include "services/memTracker.hpp" +#include "services/virtualMemoryTracker.hpp" #include "utilities/defaultStream.hpp" #include "utilities/events.hpp" #include "utilities/formatBuffer.hpp" @@ -237,7 +239,6 @@ void report_vm_error(const char* file, int line, const char* error_msg) static void print_error_for_unit_test(const char* message, const char* detail_fmt, va_list detail_args) { -#ifdef ASSERT if (ExecutingUnitTests) { char detail_msg[256]; if (detail_fmt != NULL) { @@ -262,7 +263,6 @@ static void print_error_for_unit_test(const char* message, const char* detail_fm va_end(detail_args_copy); } } -#endif // ASSERT } void report_vm_error(const char* file, int line, const char* error_msg, const char* detail_fmt, ...) @@ -478,11 +478,31 @@ extern "C" JNIEXPORT void verify() { extern "C" JNIEXPORT void pp(void* p) { Command c("pp"); FlagSetting fl(DisplayVMOutput, true); + if (p == NULL) { + tty->print_cr("NULL"); + return; + } if (Universe::heap()->is_in(p)) { oop obj = cast_to_oop(p); obj->print(); } else { - tty->print(PTR_FORMAT, p2i(p)); + // Ask NMT about this pointer. + // GDB note: We will be using SafeFetch to access the supposed malloc header. If the address is + // not readable, this will generate a signal. That signal will trip up the debugger: gdb will + // catch the signal and disable the pp() command for further use. + // In order to avoid that, switch off SIGSEGV handling with "handle SIGSEGV nostop" before + // invoking pp() + if (MemTracker::enabled()) { + // Does it point into a known mmaped region? + if (VirtualMemoryTracker::print_containing_region(p, tty)) { + return; + } + // Does it look like the start of a malloced block? + if (MallocTracker::print_pointer_information(p, tty)) { + return; + } + } + tty->print_cr(PTR_FORMAT, p2i(p)); } } diff --git a/src/hotspot/share/utilities/decoder.hpp b/src/hotspot/share/utilities/decoder.hpp index ccf3ac4ba3cfb8a2428cdd3874463a5ac8761d95..b0a368fd058ebca5c01aa127e0b7d0e0b4e79938 100644 --- a/src/hotspot/share/utilities/decoder.hpp +++ b/src/hotspot/share/utilities/decoder.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -26,7 +26,7 @@ #ifndef SHARE_UTILITIES_DECODER_HPP #define SHARE_UTILITIES_DECODER_HPP -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" #include "runtime/mutex.hpp" #include "runtime/mutexLocker.hpp" #include "utilities/ostream.hpp" diff --git a/src/hotspot/share/utilities/elfFile.cpp b/src/hotspot/share/utilities/elfFile.cpp index 1e2a6a5279f868585da3c70fbd0b5bafbcfdcf76..2198d2943c17e32ef10534910bd3df8d2abc1187 100644 --- a/src/hotspot/share/utilities/elfFile.cpp +++ b/src/hotspot/share/utilities/elfFile.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -168,7 +168,7 @@ void ElfFile::cleanup_tables() { NullDecoder::decoder_status ElfFile::parse_elf(const char* filepath) { assert(filepath, "null file path"); - _file = fopen(filepath, "r"); + _file = os::fopen(filepath, "r"); if (_file != NULL) { return load_tables(); } else { diff --git a/src/hotspot/share/utilities/exceptions.cpp b/src/hotspot/share/utilities/exceptions.cpp index e71c48c6c423ffb1b29dbc982d768d25d4230b80..1b56009a27d70a54df3d621426eba597811f0763 100644 --- a/src/hotspot/share/utilities/exceptions.cpp +++ b/src/hotspot/share/utilities/exceptions.cpp @@ -461,9 +461,9 @@ volatile int Exceptions::_out_of_memory_error_metaspace_errors = 0; volatile int Exceptions::_out_of_memory_error_class_metaspace_errors = 0; void Exceptions::count_out_of_memory_exceptions(Handle exception) { - if (exception() == Universe::out_of_memory_error_metaspace()) { + if (Universe::is_out_of_memory_error_metaspace(exception())) { Atomic::inc(&_out_of_memory_error_metaspace_errors, memory_order_relaxed); - } else if (exception() == Universe::out_of_memory_error_class_metaspace()) { + } else if (Universe::is_out_of_memory_error_class_metaspace(exception())) { Atomic::inc(&_out_of_memory_error_class_metaspace_errors, memory_order_relaxed); } else { // everything else reported as java heap OOM @@ -538,7 +538,11 @@ void Exceptions::debug_check_abort(const char *value_string, const char* message strstr(value_string, AbortVMOnException)) { if (AbortVMOnExceptionMessage == NULL || (message != NULL && strstr(message, AbortVMOnExceptionMessage))) { - fatal("Saw %s, aborting", value_string); + if (message == NULL) { + fatal("Saw %s, aborting", value_string); + } else { + fatal("Saw %s: %s, aborting", value_string, message); + } } } } diff --git a/src/hotspot/share/utilities/exceptions.hpp b/src/hotspot/share/utilities/exceptions.hpp index 1ff750c103a958f01a8383deeed4be75d86b20b2..a599682e25bf234788a715feb9f1a443d72efdf8 100644 --- a/src/hotspot/share/utilities/exceptions.hpp +++ b/src/hotspot/share/utilities/exceptions.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -56,7 +56,7 @@ class methodHandle; // The ThreadShadow class is a helper class to access the _pending_exception // field of the Thread class w/o having access to the Thread's interface (for -// include hierachy reasons). +// include hierarchy reasons). class ThreadShadow: public CHeapObj { friend class VMStructs; diff --git a/src/hotspot/share/utilities/globalCounter.hpp b/src/hotspot/share/utilities/globalCounter.hpp index beba72a954a1a0115d8ae4acf05d59c69d9d659f..5f5eba263b98012992538de5027fa1c741b79ce0 100644 --- a/src/hotspot/share/utilities/globalCounter.hpp +++ b/src/hotspot/share/utilities/globalCounter.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -25,7 +25,7 @@ #ifndef SHARE_UTILITIES_GLOBALCOUNTER_HPP #define SHARE_UTILITIES_GLOBALCOUNTER_HPP -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" #include "memory/padded.hpp" class Thread; diff --git a/src/hotspot/share/utilities/globalDefinitions.cpp b/src/hotspot/share/utilities/globalDefinitions.cpp index a1d3cd9ccf386123e35650da261e003fff464a6b..349d99f3311f8eda545d60f1a1f03dd35c57ef86 100644 --- a/src/hotspot/share/utilities/globalDefinitions.cpp +++ b/src/hotspot/share/utilities/globalDefinitions.cpp @@ -39,6 +39,14 @@ int LogBitsPerHeapOop = 0; int BytesPerHeapOop = 0; int BitsPerHeapOop = 0; +// Old CDS options +bool DumpSharedSpaces; +bool DynamicDumpSharedSpaces; +bool RequireSharedSpaces; +extern "C" { +JNIEXPORT jboolean UseSharedSpaces = true; +} + // Object alignment, in units of HeapWords. // Defaults are -1 so things will break badly if incorrectly initialized. int MinObjAlignment = -1; diff --git a/src/hotspot/share/utilities/globalDefinitions.hpp b/src/hotspot/share/utilities/globalDefinitions.hpp index 78a8ffa11bfa9623950c57a257e52509a26d3f2a..fdd3db8875ad3295490ae050c1691bb5d54d0f5a 100644 --- a/src/hotspot/share/utilities/globalDefinitions.hpp +++ b/src/hotspot/share/utilities/globalDefinitions.hpp @@ -508,6 +508,16 @@ const jfloat max_jfloat = jfloat_cast(max_jintFloat); const int max_method_code_size = 64*K - 1; // JVM spec, 2nd ed. section 4.8.1 (p.134) +//---------------------------------------------------------------------------------------------------- +// old CDS options +extern bool DumpSharedSpaces; +extern bool DynamicDumpSharedSpaces; +extern bool RequireSharedSpaces; +extern "C" { +// Make sure UseSharedSpaces is accessible to the serviceability agent. +extern JNIEXPORT jboolean UseSharedSpaces; +} + //---------------------------------------------------------------------------------------------------- // Object alignment, in units of HeapWords. // @@ -1209,5 +1219,9 @@ template bool primitive_equals(const K& k0, const K& k1) { return k0 == k1; } +//---------------------------------------------------------------------------------------------------- + +// Allow use of C++ thread_local when approved - see JDK-8282469. +#define APPROVED_CPP_THREAD_LOCAL thread_local #endif // SHARE_UTILITIES_GLOBALDEFINITIONS_HPP diff --git a/src/hotspot/share/utilities/globalDefinitions_gcc.hpp b/src/hotspot/share/utilities/globalDefinitions_gcc.hpp index 30cca9ee7aef6abd56a4156d4dfb7e1f191bc542..4aed8605182f36cf7c71bdbc522b0a226eff0946 100644 --- a/src/hotspot/share/utilities/globalDefinitions_gcc.hpp +++ b/src/hotspot/share/utilities/globalDefinitions_gcc.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -127,11 +127,6 @@ inline int g_isfinite(jfloat f) { return isfinite(f); } inline int g_isfinite(jdouble f) { return isfinite(f); } -// Wide characters - -inline int wcslen(const jchar* x) { return wcslen((const wchar_t*)x); } - - // Formatting. #ifdef _LP64 # ifdef __APPLE__ diff --git a/src/hotspot/share/utilities/globalDefinitions_xlc.hpp b/src/hotspot/share/utilities/globalDefinitions_xlc.hpp index 4bfb6a2d5df6b75850a1fd67390ee5e33f1737b8..80c27729c7d0a2d8530db2c46da7a178ecf63f20 100644 --- a/src/hotspot/share/utilities/globalDefinitions_xlc.hpp +++ b/src/hotspot/share/utilities/globalDefinitions_xlc.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2022, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, 2021 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -109,10 +109,6 @@ inline int g_isnan(double f) { return isnan(f); } inline int g_isfinite(jfloat f) { return finite(f); } inline int g_isfinite(jdouble f) { return finite(f); } -// Wide characters -inline int wcslen(const jchar* x) { return wcslen((const wchar_t*)x); } - - // Formatting. #ifdef _LP64 #define FORMAT64_MODIFIER "l" diff --git a/src/hotspot/share/utilities/macros.hpp b/src/hotspot/share/utilities/macros.hpp index 9b362b88c11911a2c89360d0c7e08cc5d4678523..8dea1a754faa2166fcd78870782ffb2155c7aa69 100644 --- a/src/hotspot/share/utilities/macros.hpp +++ b/src/hotspot/share/utilities/macros.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -241,22 +241,6 @@ #define NOT_ZGC_RETURN_(code) { return code; } #endif // INCLUDE_ZGC -#ifndef INCLUDE_NMT -#define INCLUDE_NMT 1 -#endif // INCLUDE_NMT - -#if INCLUDE_NMT -#define NOT_NMT_RETURN /* next token must be ; */ -#define NOT_NMT_RETURN_(code) /* next token must be ; */ -#define NMT_ONLY(x) x -#define NOT_NMT(x) -#else -#define NOT_NMT_RETURN {} -#define NOT_NMT_RETURN_(code) { return code; } -#define NMT_ONLY(x) -#define NOT_NMT(x) x -#endif // INCLUDE_NMT - #ifndef INCLUDE_JFR #define INCLUDE_JFR 1 #endif @@ -528,7 +512,7 @@ // Note: There are two ARM ports. They set the following in the makefiles: // 1. 32-bit port: -DARM -DARM32 -DTARGET_ARCH_arm -// 2. 64-bit port: -DAARCH64 -D_LP64 -DTARGET_ARCH_aaarch64 +// 2. 64-bit port: -DAARCH64 -D_LP64 -DTARGET_ARCH_aarch64 #ifdef ARM #define ARM_ONLY(code) code #define NOT_ARM(code) @@ -553,6 +537,12 @@ #define NOT_AARCH64(code) code #endif +#ifdef TARGET_ARCH_aarch64 +#define AARCH64_PORT_ONLY(code) code +#else +#define AARCH64_PORT_ONLY(code) +#endif + #define MACOS_AARCH64_ONLY(x) MACOS_ONLY(AARCH64_ONLY(x)) #ifdef VM_LITTLE_ENDIAN diff --git a/src/hotspot/share/utilities/nonblockingQueue.hpp b/src/hotspot/share/utilities/nonblockingQueue.hpp index 6f8936b019f4e04deff95b73205ef1a79d3e2dcb..7ba4c80cfd6174e30a4d7667cf243536180d72f1 100644 --- a/src/hotspot/share/utilities/nonblockingQueue.hpp +++ b/src/hotspot/share/utilities/nonblockingQueue.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -45,7 +45,7 @@ // // A queue may temporarily appear to be empty even though elements have been // added and not removed. For example, after running the following program, -// the value of r may be NULL. +// the value of r may be nullptr. // // thread1: q.push(a); r = q.pop(); // thread2: q.push(b); @@ -96,22 +96,24 @@ public: inline size_t length() const; // Thread-safe add the object to the end of the queue. + // Subject to ABA behavior; callers must ensure usage is safe. inline void push(T& node) { append(node, node); } // Thread-safe add the objects from first to last to the end of the queue. + // Subject to ABA behavior; callers must ensure usage is safe. inline void append(T& first, T& last); // Thread-safe attempt to remove and return the first object in the queue. // Returns true if successful. If successful then *node_ptr is the former - // first object, or NULL if the queue was empty. If unsuccessful, because + // first object, or nullptr if the queue was empty. If unsuccessful, because // of contention with a concurrent modification, then returns false with // the value of *node_ptr unspecified. Subject to ABA behavior; callers // must ensure usage is safe. inline bool try_pop(T** node_ptr); - // Thread-safe remove and return the first object in the queue, or NULL if - // the queue was empty. This just iterates on try_pop() until it - // succeeds, returning the (possibly NULL) element obtained from that. + // Thread-safe remove and return the first object in the queue, or nullptr + // if the queue was empty. This just iterates on try_pop() until it + // succeeds, returning the (possibly nullptr) element obtained from that. // Subject to ABA behavior; callers must ensure usage is safe. inline T* pop(); diff --git a/src/hotspot/share/utilities/nonblockingQueue.inline.hpp b/src/hotspot/share/utilities/nonblockingQueue.inline.hpp index 355b21209021c703585478c9c3732b8842fb9194..f4e86c6fe65f228cf0c8c0194c89406527d969d6 100644 --- a/src/hotspot/share/utilities/nonblockingQueue.inline.hpp +++ b/src/hotspot/share/utilities/nonblockingQueue.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -40,13 +40,13 @@ void NonblockingQueue::set_next(T& node, T* new_next) { } template -NonblockingQueue::NonblockingQueue() : _head(NULL), _tail(NULL) {} +NonblockingQueue::NonblockingQueue() : _head(nullptr), _tail(nullptr) {} #ifdef ASSERT template NonblockingQueue::~NonblockingQueue() { - assert(_head == NULL, "precondition"); - assert(_tail == NULL, "precondition"); + assert(_head == nullptr, "precondition"); + assert(_tail == nullptr, "precondition"); } #endif @@ -61,7 +61,7 @@ T* NonblockingQueue::end_marker() const { template T* NonblockingQueue::first() const { T* head = Atomic::load(&_head); - return head == NULL ? end_marker() : head; + return head == nullptr ? end_marker() : head; } template @@ -71,7 +71,7 @@ bool NonblockingQueue::is_end(const T* entry) const { template bool NonblockingQueue::empty() const { - return Atomic::load(&_head) == NULL; + return Atomic::load(&_head) == nullptr; } template @@ -85,8 +85,8 @@ size_t NonblockingQueue::length() const { // An append operation atomically exchanges the new tail with the queue tail. // It then sets the "next" value of the old tail to the head of the list being -// appended. If the old tail is NULL then the queue was empty, then the head -// of the list being appended is instead stored in the queue head. +// appended. If the old tail is nullptr then the queue was empty, then the +// head of the list being appended is instead stored in the queue head. // // This means there is a period between the exchange and the old tail update // where the queue sequence is split into two parts, the list from the queue @@ -94,100 +94,139 @@ size_t NonblockingQueue::length() const { // push/append operations, each may introduce another such segment. But they // all eventually get resolved by their respective updates of their old tail's // "next" value. This also means that try_pop operation must handle an object -// with a NULL "next" value specially. +// differently depending on its "next" value. // // A push operation is just a degenerate append, where the object being pushed // is both the head and the tail of the list being appended. template void NonblockingQueue::append(T& first, T& last) { - assert(next(last) == NULL, "precondition"); + assert(next(last) == nullptr, "precondition"); + // Make last the new end of the queue. Any further push/appends will + // extend after last. We will try to extend from the previous end of + // queue. set_next(last, end_marker()); T* old_tail = Atomic::xchg(&_tail, &last); - bool is_old_tail_null = (old_tail == NULL); - if (is_old_tail_null || - // Try to install first as old_tail's next. - !is_end(Atomic::cmpxchg(next_ptr(*old_tail), end_marker(), &first))) { - // Install first as the new head if either - // (1) the list was empty, or - // (2) a concurrent try_pop claimed old_tail, so it is no longer in the list. - // Note that multiple concurrent push/append operations cannot modify - // _head simultaneously, because the Atomic::xchg() above orders these - // push/append operations so they perform Atomic::cmpxchg() on different - // old_tail. Thus, the cmpxchg can only fail because of a concurrent try_pop. + if (old_tail == nullptr) { + // If old_tail is nullptr then the queue was empty, and _head must also be + // nullptr. The correctness of this assertion depends on try_pop clearing + // first _head then _tail when taking the last entry. + assert(Atomic::load(&_head) == nullptr, "invariant"); + // Fall through to common update of _head. + } else if (is_end(Atomic::cmpxchg(next_ptr(*old_tail), end_marker(), &first))) { + // Successfully extended the queue list from old_tail to first. No + // other push/append could have competed with us, because we claimed + // old_tail for extension. We won any races with try_pop by changing + // away from end-marker. So we're done. + // + // Note that ABA is possible here. A concurrent try_pop could take + // old_tail before our update of old_tail's next_ptr, old_tail gets + // recycled and re-added to the end of this queue, and then we + // successfully cmpxchg, making the list in _tail circular. Callers + // must ensure this can't happen. + return; + } else { + // A concurrent try_pop has claimed old_tail, so it is no longer in the + // list. The queue was logically empty. _head is either nullptr or + // old_tail, depending on how far try_pop operations have progressed. DEBUG_ONLY(T* old_head = Atomic::load(&_head);) - // If old_tail is NULL, old_head could be NULL, or an unseen object - // that is being popped. Otherwise, old_head must be either NULL - // or the same as old_tail. - assert(is_old_tail_null || - old_head == NULL || old_head == old_tail, "invariant"); - Atomic::store(&_head, &first); + assert((old_head == nullptr) || (old_head == old_tail), "invariant"); + // Fall through to common update of _head. } + // The queue was empty, and first should become the new _head. The queue + // will appear to be empty to any further try_pops until done. + Atomic::store(&_head, &first); } template bool NonblockingQueue::try_pop(T** node_ptr) { // We only need memory_order_consume. Upgrade it to "load_acquire" // as the memory_order_consume API is not ready for use yet. - T* result = Atomic::load_acquire(&_head); - if (result == NULL) { - *node_ptr = NULL; + T* old_head = Atomic::load_acquire(&_head); + if (old_head == nullptr) { + *node_ptr = nullptr; return true; // Queue is empty. } - T* next_node = Atomic::load_acquire(next_ptr(*result)); - if (next_node == NULL) { - // A concurrent try_pop already claimed what was the last entry. That - // operation may not have cleared queue head yet, but we should still - // treat the queue as empty until a push/append operation changes head - // to an entry with a non-NULL next value. - *node_ptr = NULL; - return true; - - } else if (!is_end(next_node)) { - // The next_node is not at the end of the queue's list. Use the "usual" - // lock-free pop from the head of a singly linked list to try to take it. - if (result == Atomic::cmpxchg(&_head, result, next_node)) { - // Former head successfully taken. - set_next(*result, NULL); - *node_ptr = result; - return true; - } else { - // Lost race to take result from the head of the list. + T* next_node = Atomic::load_acquire(next_ptr(*old_head)); + if (!is_end(next_node)) { + // [Clause 1] + // There are several cases for next_node. + // (1) next_node is the extension of the queue's list. + // (2) next_node is nullptr, because a competing try_pop took old_head. + // (3) next_node is the extension of some unrelated list, because a + // competing try_pop took old_head and put it in some other list. + // + // Attempt to advance the list, replacing old_head with next_node in + // _head. The success or failure of that attempt, along with the value + // of next_node, are used to partially determine which case we're in and + // how to proceed. In particular, advancement will fail for case (3). + if (old_head != Atomic::cmpxchg(&_head, old_head, next_node)) { + // [Clause 1a] + // The cmpxchg to advance the list failed; a concurrent try_pop won + // the race and claimed old_head. This can happen for any of the + // next_node cases. return false; + } else if (next_node == nullptr) { + // [Clause 1b] + // The cmpxchg to advance the list succeeded, but a concurrent try_pop + // has already claimed old_head (see [Clause 2] - old_head was the last + // entry in the list) by nulling old_head's next field. The advance set + // _head to nullptr, "helping" the competing try_pop. _head will remain + // nullptr until a subsequent push/append. This is a lost race, and we + // report it as such for consistency, though we could report the queue + // was empty. We don't attempt to further help [Clause 2] by also + // trying to set _tail to nullptr, as that would just ensure that one or + // the other cmpxchg is a wasted failure. + return false; + } else { + // [Clause 1c] + // Successfully advanced the list and claimed old_head. next_node was + // in the extension of the queue's list. Return old_head after + // unlinking it from next_node. + set_next(*old_head, nullptr); + *node_ptr = old_head; + return true; } - } else if (is_end(Atomic::cmpxchg(next_ptr(*result), end_marker(), (T*)NULL))) { - // Result was the last entry and we've claimed it by setting its next - // value to NULL. However, this leaves the queue in disarray. Fix up + } else if (is_end(Atomic::cmpxchg(next_ptr(*old_head), next_node, (T*)nullptr))) { + // [Clause 2] + // Old_head was the last entry and we've claimed it by setting its next + // value to nullptr. However, this leaves the queue in disarray. Fix up // the queue, possibly in conjunction with other concurrent operations. // Any further try_pops will consider the queue empty until a // push/append completes by installing a new head. - // Attempt to change the queue tail from result to NULL. Failure of the - // cmpxchg indicates that a concurrent push/append updated the tail first. - // That operation will eventually recognize the old tail (our result) is - // no longer in the list and update head from the list being appended. - Atomic::cmpxchg(&_tail, result, (T*)NULL); + // The order of the two cmpxchgs doesn't matter algorithmically, but + // dealing with _head first gives a stronger invariant in append, and is + // also consistent with [Clause 1b]. + + // Attempt to change the queue head from old_head to nullptr. Failure of + // the cmpxchg indicates a concurrent operation updated _head first. That + // could be either a push/append or a try_pop in [Clause 1b]. + Atomic::cmpxchg(&_head, old_head, (T*)nullptr); - // Attempt to change the queue head from result to NULL. Failure of the - // cmpxchg indicates a concurrent push/append updated the head first. - Atomic::cmpxchg(&_head, result, (T*)NULL); + // Attempt to change the queue tail from old_head to nullptr. Failure of + // the cmpxchg indicates that a concurrent push/append updated _tail first. + // That operation will eventually recognize the old tail (our old_head) is + // no longer in the list and update _head from the list being appended. + Atomic::cmpxchg(&_tail, old_head, (T*)nullptr); - // The queue has been restored to order, and we can return the result. - *node_ptr = result; + // The queue has been restored to order, and we can return old_head. + *node_ptr = old_head; return true; } else { - // Result was the last entry in the list, but either a concurrent pop - // claimed it first or a concurrent push/append extended the list from - // it. Either way, we lost the race. + // [Clause 3] + // Old_head was the last entry in the list, but either a concurrent + // try_pop claimed it first or a concurrent push/append extended the + // list from it. Either way, we lost the race to claim it. return false; } } template T* NonblockingQueue::pop() { - T* result = NULL; + T* result = nullptr; // Typically try_pop() will succeed without retrying many times, thus we // omit SpinPause in the loop body. SpinPause or yield may be worthwhile // in rare, highly contended cases, and client code could implement such @@ -199,10 +238,10 @@ T* NonblockingQueue::pop() { template Pair NonblockingQueue::take_all() { T* tail = Atomic::load(&_tail); - if (tail != NULL) set_next(*tail, NULL); // Clear end marker. + if (tail != nullptr) set_next(*tail, nullptr); // Clear end marker. Pair result(Atomic::load(&_head), tail); - Atomic::store(&_head, (T*)NULL); - Atomic::store(&_tail, (T*)NULL); + Atomic::store(&_head, (T*)nullptr); + Atomic::store(&_tail, (T*)nullptr); return result; } diff --git a/src/hotspot/share/utilities/ostream.cpp b/src/hotspot/share/utilities/ostream.cpp index 04995064fe3a98489bebb3605ceadc9d02b38f95..efb6a4ac7e6b77a51a03eb58f79428b9aa199ed1 100644 --- a/src/hotspot/share/utilities/ostream.cpp +++ b/src/hotspot/share/utilities/ostream.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -545,7 +545,7 @@ const char* make_log_name(const char* log_name, const char* force_directory) { } fileStream::fileStream(const char* file_name) { - _file = fopen(file_name, "w"); + _file = os::fopen(file_name, "w"); if (_file != NULL) { _need_close = true; } else { @@ -555,7 +555,7 @@ fileStream::fileStream(const char* file_name) { } fileStream::fileStream(const char* file_name, const char* opentype) { - _file = fopen(file_name, opentype); + _file = os::fopen(file_name, opentype); if (_file != NULL) { _need_close = true; } else { @@ -614,7 +614,7 @@ void fileStream::flush() { void fdStream::write(const char* s, size_t len) { if (_fd != -1) { // Make an unused local variable to avoid warning from gcc compiler. - size_t count = ::write(_fd, s, (int)len); + ssize_t count = ::write(_fd, s, (int)len); update_position(s, len); } } @@ -1079,7 +1079,7 @@ networkStream::networkStream() : bufferedStream(1024*10, 1024*10) { _socket = -1; - int result = os::socket(AF_INET, SOCK_STREAM, 0); + int result = ::socket(AF_INET, SOCK_STREAM, 0); if (result <= 0) { assert(false, "Socket could not be created!"); } else { diff --git a/src/hotspot/share/utilities/quickSort.hpp b/src/hotspot/share/utilities/quickSort.hpp index 000f1bf4f4283bb65361d4358d6ca30ff3a751c0..a94a7cd8b6ce14d601f1a60236b2731c6dbd683a 100644 --- a/src/hotspot/share/utilities/quickSort.hpp +++ b/src/hotspot/share/utilities/quickSort.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 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 @@ -25,7 +25,7 @@ #ifndef SHARE_UTILITIES_QUICKSORT_HPP #define SHARE_UTILITIES_QUICKSORT_HPP -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" #include "runtime/globals.hpp" #include "utilities/debug.hpp" diff --git a/src/hotspot/share/utilities/stringUtils.cpp b/src/hotspot/share/utilities/stringUtils.cpp index 21fb7a6e8d32e7428679ce915cb1189ba9c2e683..0ee73de809a9ecba6840809064a53ccdc6909484 100644 --- a/src/hotspot/share/utilities/stringUtils.cpp +++ b/src/hotspot/share/utilities/stringUtils.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -26,6 +26,8 @@ #include "utilities/debug.hpp" #include "utilities/stringUtils.hpp" +#include + int StringUtils::replace_no_expand(char* string, const char* from, const char* to) { int replace_count = 0; size_t from_len = strlen(from); diff --git a/src/hotspot/share/utilities/stringUtils.hpp b/src/hotspot/share/utilities/stringUtils.hpp index 372222d7c70ff8b00a93b67330c9f172140722e5..54d6847a4c4dfa267ff8f3a6fd442a453022735e 100644 --- a/src/hotspot/share/utilities/stringUtils.hpp +++ b/src/hotspot/share/utilities/stringUtils.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -25,7 +25,7 @@ #ifndef SHARE_UTILITIES_STRINGUTILS_HPP #define SHARE_UTILITIES_STRINGUTILS_HPP -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" class StringUtils : AllStatic { public: diff --git a/src/hotspot/share/utilities/utf8.cpp b/src/hotspot/share/utilities/utf8.cpp index 6ebeb9a6c9b21d4f688f60a1b0f02d162ef805a3..81ad02a9ba608efa17a6047998a71ec74b2f108d 100644 --- a/src/hotspot/share/utilities/utf8.cpp +++ b/src/hotspot/share/utilities/utf8.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -23,8 +23,12 @@ */ #include "precompiled.hpp" +#include "memory/allocation.hpp" +#include "utilities/debug.hpp" +#include "utilities/globalDefinitions.hpp" #include "utilities/utf8.hpp" + // Assume the utf8 string is in legal form and has been // checked in the class file parser/format checker. template char* UTF8::next(const char* str, T* value) { diff --git a/src/hotspot/share/utilities/utf8.hpp b/src/hotspot/share/utilities/utf8.hpp index 0ebd65b0658aa60a329a2a29cb35e259c250480d..e7b2905e04614adeed4b6535095207cda2039871 100644 --- a/src/hotspot/share/utilities/utf8.hpp +++ b/src/hotspot/share/utilities/utf8.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -25,7 +25,9 @@ #ifndef SHARE_UTILITIES_UTF8_HPP #define SHARE_UTILITIES_UTF8_HPP -#include "memory/allocation.hpp" +#include "jni.h" +#include "memory/allStatic.hpp" +#include "utilities/debug.hpp" // Low-level interface for UTF8 strings diff --git a/src/hotspot/share/utilities/vmError.cpp b/src/hotspot/share/utilities/vmError.cpp index 4ae43cedf5215da88c240c1fa05569b0e58940cc..984c57a13ec5715685ebeeeeea47fb6abe818bfb 100644 --- a/src/hotspot/share/utilities/vmError.cpp +++ b/src/hotspot/share/utilities/vmError.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2017, 2020 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -115,7 +115,7 @@ static const char* env_list[] = { "DYLD_INSERT_LIBRARIES", // defined on Windows - "OS", "PROCESSOR_IDENTIFIER", "_ALT_JAVA_HOME_DIR", + "OS", "PROCESSOR_IDENTIFIER", "_ALT_JAVA_HOME_DIR", "TMP", "TEMP", (const char *)0 }; @@ -910,7 +910,7 @@ void VMError::report(outputStream* st, bool _verbose) { STEP("printing code blobs if possible") - if (_verbose && _context) { + if (_verbose) { const int printed_capacity = max_error_log_print_code; address printed[printed_capacity]; printed[0] = nullptr; @@ -929,7 +929,8 @@ void VMError::report(outputStream* st, bool _verbose) { printed_len++; } } else { - frame fr = os::fetch_frame_from_context(_context); + frame fr = _context ? os::fetch_frame_from_context(_context) + : os::current_frame(); while (printed_len < limit && fr.pc() != nullptr) { if (print_code(st, _thread, fr.pc(), fr.pc() == _pc, printed, printed_capacity)) { printed_len++; @@ -1654,7 +1655,7 @@ void VMError::report_and_die(int id, const char* message, const char* detail_fmt _current_step_info = ""; if (fd_log > 3) { - close(fd_log); + ::close(fd_log); fd_log = -1; } @@ -1676,7 +1677,7 @@ void VMError::report_and_die(int id, const char* message, const char* detail_fmt 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) { - FILE* replay_data_file = os::open(fd, "w"); + FILE* replay_data_file = os::fdopen(fd, "w"); if (replay_data_file != NULL) { fileStream replay_data_stream(replay_data_file, /*need_close=*/true); env->dump_replay_data_unsafe(&replay_data_stream); diff --git a/src/java.base/linux/classes/sun/nio/fs/LinuxDosFileAttributeView.java b/src/java.base/linux/classes/sun/nio/fs/LinuxDosFileAttributeView.java index a60f2ad45f995bfcb8f08adc98004e719912de13..70d701c1ef7bf08574c7633ec51968dfaae3bd5b 100644 --- a/src/java.base/linux/classes/sun/nio/fs/LinuxDosFileAttributeView.java +++ b/src/java.base/linux/classes/sun/nio/fs/LinuxDosFileAttributeView.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 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 @@ -182,7 +182,7 @@ class LinuxDosFileAttributeView x.rethrowAsIOException(file); return null; // keep compiler happy } finally { - close(fd); + close(fd, e -> null); } } @@ -277,7 +277,7 @@ class LinuxDosFileAttributeView } catch (UnixException x) { x.rethrowAsIOException(file); } finally { - close(fd); + close(fd, e -> null); } } } diff --git a/src/java.base/linux/classes/sun/nio/fs/LinuxFileStore.java b/src/java.base/linux/classes/sun/nio/fs/LinuxFileStore.java index 1b6fce47fc718bcd282549d492c5dcc32012cceb..6ff8fe4bbf8012d765ebb606bdd803c4bcf15a8c 100644 --- a/src/java.base/linux/classes/sun/nio/fs/LinuxFileStore.java +++ b/src/java.base/linux/classes/sun/nio/fs/LinuxFileStore.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 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 @@ -112,7 +112,7 @@ class LinuxFileStore int[] majorMinorMicro = new int[3]; int length = Math.min(matches.length, majorMinorMicro.length); for (int i = 0; i < length; i++) { - majorMinorMicro[i] = Integer.valueOf(matches[i]); + majorMinorMicro[i] = Integer.parseInt(matches[i]); } return majorMinorMicro; } diff --git a/src/java.base/linux/classes/sun/nio/fs/LinuxWatchService.java b/src/java.base/linux/classes/sun/nio/fs/LinuxWatchService.java index 3e53b59ff906ae7110ff57f6ee2b3820c6dfdd0e..43719e0d5be26ea52a56fc261f52b8b66ede1309 100644 --- a/src/java.base/linux/classes/sun/nio/fs/LinuxWatchService.java +++ b/src/java.base/linux/classes/sun/nio/fs/LinuxWatchService.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 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 @@ -70,7 +70,7 @@ class LinuxWatchService socketpair(sp); configureBlocking(sp[0], false); } catch (UnixException x) { - UnixNativeDispatcher.close(ifd); + UnixNativeDispatcher.close(ifd, e -> null); throw new IOException(x.errorString()); } @@ -296,9 +296,9 @@ class LinuxWatchService // free resources unsafe.freeMemory(address); - UnixNativeDispatcher.close(socketpair[0]); - UnixNativeDispatcher.close(socketpair[1]); - UnixNativeDispatcher.close(ifd); + UnixNativeDispatcher.close(socketpair[0], e -> null); + UnixNativeDispatcher.close(socketpair[1], e -> null); + UnixNativeDispatcher.close(ifd, e -> null); } /** diff --git a/src/java.base/macosx/classes/apple/security/KeychainStore.java b/src/java.base/macosx/classes/apple/security/KeychainStore.java index cf97d4e04c0e90a96604197ee3164db16d0b87c1..688d280f83812cde0d5aea750664a2d156b623a0 100644 --- a/src/java.base/macosx/classes/apple/security/KeychainStore.java +++ b/src/java.base/macosx/classes/apple/security/KeychainStore.java @@ -945,7 +945,6 @@ public final class KeychainStore extends KeyStoreSpi { byte[] safeContentsData; ContentInfo safeContents; DerInputStream sci; - byte[] eAlgId = null; sci = new DerInputStream(safeContentsArray[i].toByteArray()); safeContents = new ContentInfo(sci); @@ -984,7 +983,6 @@ public final class KeychainStore extends KeyStoreSpi { ObjectIdentifier bagId; DerInputStream sbi; DerValue bagValue; - Object bagItem = null; sbi = safeBags[i].toDerInputStream(); bagId = sbi.getOID(); diff --git a/src/java.base/share/classes/com/sun/crypto/provider/BlockCipherParamsCore.java b/src/java.base/share/classes/com/sun/crypto/provider/BlockCipherParamsCore.java index 20af0c78309c70f0d45084b8b292820845865bd4..738b34d3aeb41b0d46526f32a6ecce12ec3f0045 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/BlockCipherParamsCore.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/BlockCipherParamsCore.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 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 @@ -108,7 +108,7 @@ final class BlockCipherParamsCore { T getParameterSpec(Class paramSpec) throws InvalidParameterSpecException { - if (IvParameterSpec.class.isAssignableFrom(paramSpec)) { + if (paramSpec.isAssignableFrom(IvParameterSpec.class)) { return paramSpec.cast(new IvParameterSpec(this.iv)); } else { throw new InvalidParameterSpecException diff --git a/src/java.base/share/classes/com/sun/crypto/provider/BlowfishCrypt.java b/src/java.base/share/classes/com/sun/crypto/provider/BlowfishCrypt.java index f5483f7deff51dfc93b8d808aa6708ff7c7e37de..5fde830e519fa337945343e42ba1883fdc668258 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/BlowfishCrypt.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/BlowfishCrypt.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -64,7 +64,7 @@ final class BlowfishCrypt extends SymmetricCipher throw new InvalidKeyException("Key too long (> 448 bits)"); } // Step 1: Init P and then S arrays from pi bytes - int i, j, count; + int i, j; System.arraycopy(pi, 0, p, 0, 18); System.arraycopy(pi, 18, s0, 0, 256); diff --git a/src/java.base/share/classes/com/sun/crypto/provider/ChaCha20Cipher.java b/src/java.base/share/classes/com/sun/crypto/provider/ChaCha20Cipher.java index 8cb200876ac0d5348470a57478cdbd8fcfed0190..917921801cbcb9712c61ffe1cf91fef064c37c3d 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/ChaCha20Cipher.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/ChaCha20Cipher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -159,7 +159,7 @@ abstract class ChaCha20Cipher extends CipherSpi { * ciphers, but allow {@code NoPadding}. See JCE spec. * * @param padding The padding type. The only allowed value is - * {@code NoPadding} case insensitive). + * {@code NoPadding} case insensitive. * * @throws NoSuchPaddingException if a padding scheme besides * {@code NoPadding} is provided. @@ -393,7 +393,7 @@ abstract class ChaCha20Cipher extends CipherSpi { return; } - byte[] newNonce = null; + byte[] newNonce; switch (mode) { case MODE_NONE: throw new InvalidAlgorithmParameterException( @@ -420,12 +420,6 @@ abstract class ChaCha20Cipher extends CipherSpi { throw new RuntimeException("Invalid mode: " + mode); } - // If after all the above processing we still don't have a nonce value - // then supply a random one provided a random source has been given. - if (newNonce == null) { - newNonce = createRandomNonce(random); - } - // Continue with initialization init(opmode, key, newNonce); } diff --git a/src/java.base/share/classes/com/sun/crypto/provider/ChaCha20Poly1305Parameters.java b/src/java.base/share/classes/com/sun/crypto/provider/ChaCha20Poly1305Parameters.java index ad31fb6f6914fd74e4dbf96b9fb84e55b808953f..762827d0152ff705411f67be7affd0123c01fd6e 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/ChaCha20Poly1305Parameters.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/ChaCha20Poly1305Parameters.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -147,7 +147,7 @@ public final class ChaCha20Poly1305Parameters extends AlgorithmParametersSpi { T engineGetParameterSpec(Class paramSpec) throws InvalidParameterSpecException { - if (IvParameterSpec.class.isAssignableFrom(paramSpec)) { + if (paramSpec.isAssignableFrom(IvParameterSpec.class)) { return paramSpec.cast(new IvParameterSpec(nonce)); } else { throw new InvalidParameterSpecException diff --git a/src/java.base/share/classes/com/sun/crypto/provider/CipherCore.java b/src/java.base/share/classes/com/sun/crypto/provider/CipherCore.java index 93eede032f1a586c73f500d6c616f7bee389c1d5..64ce01c53ab5bd6a11d370ab7e749bf558bb681a 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/CipherCore.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/CipherCore.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 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 @@ -812,10 +812,13 @@ final class CipherCore { if (outputCapacity < estOutSize) { cipher.save(); } - // create temporary output buffer if the estimated size is larger - // than the user-provided buffer. - internalOutput = new byte[estOutSize]; - offset = 0; + if (outputCapacity < estOutSize || padding != null) { + // create temporary output buffer if the estimated size is larger + // than the user-provided buffer or a padding needs to be removed + // before copying the unpadded result to the output buffer + internalOutput = new byte[estOutSize]; + offset = 0; + } } byte[] outBuffer = (internalOutput != null) ? internalOutput : output; diff --git a/src/java.base/share/classes/com/sun/crypto/provider/DHKeyAgreement.java b/src/java.base/share/classes/com/sun/crypto/provider/DHKeyAgreement.java index 94f41e614f17ce6be4caaffbd0b317ce7809c31a..01f978fff615ff0ae7f3dd84f8791536fcf99d5d 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/DHKeyAgreement.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/DHKeyAgreement.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -344,6 +344,8 @@ extends KeyAgreementSpi { } else { // Array too short, pad it w/ leading 0s if (secret.length < expectedLen) { + Arrays.fill(sharedSecret, offset, + offset + (expectedLen - secret.length), (byte)0); System.arraycopy(secret, 0, sharedSecret, offset + (expectedLen - secret.length), secret.length); diff --git a/src/java.base/share/classes/com/sun/crypto/provider/DHParameters.java b/src/java.base/share/classes/com/sun/crypto/provider/DHParameters.java index da3129805b635d36597f1828cf8aa3ec6fa4270c..859c64dc4054266f76328f6ba38a64f452ab27e0 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/DHParameters.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/DHParameters.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -98,7 +98,7 @@ public final class DHParameters extends AlgorithmParametersSpi { T engineGetParameterSpec(Class paramSpec) throws InvalidParameterSpecException { - if (DHParameterSpec.class.isAssignableFrom(paramSpec)) { + if (paramSpec.isAssignableFrom(DHParameterSpec.class)) { return paramSpec.cast(new DHParameterSpec(this.p, this.g, this.l)); } else { throw new InvalidParameterSpecException diff --git a/src/java.base/share/classes/com/sun/crypto/provider/GCMParameters.java b/src/java.base/share/classes/com/sun/crypto/provider/GCMParameters.java index 911ccc558241bc9b9a2de463bf7d807523e88fb2..8060ca9b7de4d59b9f2b2f448a1cac2bd98f90e4 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/GCMParameters.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/GCMParameters.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -107,7 +107,7 @@ public final class GCMParameters extends AlgorithmParametersSpi { T engineGetParameterSpec(Class paramSpec) throws InvalidParameterSpecException { - if (GCMParameterSpec.class.isAssignableFrom(paramSpec)) { + if (paramSpec.isAssignableFrom(GCMParameterSpec.class)) { return paramSpec.cast(new GCMParameterSpec(tLen * 8, iv)); } else { throw new InvalidParameterSpecException diff --git a/src/java.base/share/classes/com/sun/crypto/provider/GaloisCounterMode.java b/src/java.base/share/classes/com/sun/crypto/provider/GaloisCounterMode.java index 728d463068e198bf4b39079e4ac8f17579bb5bc5..635061d613126bf83732f331ed811ee015277cb2 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/GaloisCounterMode.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/GaloisCounterMode.java @@ -1304,7 +1304,7 @@ abstract class GaloisCounterMode extends CipherSpi { // 'len' includes ibuffer data checkDataLength(len, tagLenBytes); if (dst.remaining() < len + tagLenBytes) { - throw new ShortBufferException("Output buffer too small, must" + + throw new ShortBufferException("Output buffer too small, must " + "be at least " + (len + tagLenBytes) + " bytes long"); } @@ -1472,7 +1472,7 @@ abstract class GaloisCounterMode extends CipherSpi { } if (len - tagLenBytes > out.length - outOfs) { - throw new ShortBufferException("Output buffer too small, must" + + throw new ShortBufferException("Output buffer too small, must " + "be at least " + (len - tagLenBytes) + " bytes long"); } diff --git a/src/java.base/share/classes/com/sun/crypto/provider/KeyProtector.java b/src/java.base/share/classes/com/sun/crypto/provider/KeyProtector.java index b13a1a905d7ccf1091b26ceb0863ab2530c66cb3..570aca63e09b241d407dcdf63dde12055e173822 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/KeyProtector.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/KeyProtector.java @@ -177,6 +177,10 @@ final class KeyProtector { byte[] encodedParams = encrInfo.getAlgorithm().getEncodedParams(); + if (encodedParams == null) { + throw new IOException("Missing PBE parameters"); + } + // parse the PBE parameters into the corresponding spec AlgorithmParameters pbeParams = AlgorithmParameters.getInstance("PBE"); diff --git a/src/java.base/share/classes/com/sun/crypto/provider/OAEPParameters.java b/src/java.base/share/classes/com/sun/crypto/provider/OAEPParameters.java index bdb1da97b63c7f52315fa5340671463f15ba9d9a..d8bf4386455ead620155807c1c266154f1852ab4 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/OAEPParameters.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/OAEPParameters.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -107,8 +107,12 @@ public final class OAEPParameters extends AlgorithmParametersSpi { if (!val.getOID().equals(OID_MGF1)) { throw new IOException("Only MGF1 mgf is supported"); } + byte[] encodedParams = val.getEncodedParams(); + if (encodedParams == null) { + throw new IOException("Missing MGF1 parameters"); + } AlgorithmId params = AlgorithmId.parse( - new DerValue(val.getEncodedParams())); + new DerValue(encodedParams)); mgfSpec = switch (params.getName()) { case "SHA-1" -> MGF1ParameterSpec.SHA1; case "SHA-224" -> MGF1ParameterSpec.SHA224; @@ -129,7 +133,12 @@ public final class OAEPParameters extends AlgorithmParametersSpi { if (!val.getOID().equals(OID_PSpecified)) { throw new IOException("Wrong OID for pSpecified"); } - p = DerValue.wrap(val.getEncodedParams()).getOctetString(); + byte[] encodedParams = val.getEncodedParams(); + if (encodedParams == null) { + throw new IOException("Missing pSpecified label"); + } + + p = DerValue.wrap(encodedParams).getOctetString(); } else { p = new byte[0]; } @@ -148,7 +157,7 @@ public final class OAEPParameters extends AlgorithmParametersSpi { protected T engineGetParameterSpec(Class paramSpec) throws InvalidParameterSpecException { - if (OAEPParameterSpec.class.isAssignableFrom(paramSpec)) { + if (paramSpec.isAssignableFrom(OAEPParameterSpec.class)) { return paramSpec.cast( new OAEPParameterSpec(mdName, "MGF1", mgfSpec, new PSource.PSpecified(p))); diff --git a/src/java.base/share/classes/com/sun/crypto/provider/PBEKeyFactory.java b/src/java.base/share/classes/com/sun/crypto/provider/PBEKeyFactory.java index ea2dfbf31aed646f6d1ef3781b31345f2548bf37..ed09fe94118bcd50a3682eec9218d1110e864e4b 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/PBEKeyFactory.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/PBEKeyFactory.java @@ -243,7 +243,7 @@ abstract class PBEKeyFactory extends SecretKeyFactorySpi { // Check if requested key spec is amongst the valid ones if ((keySpecCl != null) - && PBEKeySpec.class.isAssignableFrom(keySpecCl)) { + && keySpecCl.isAssignableFrom(PBEKeySpec.class)) { byte[] passwdBytes = key.getEncoded(); char[] passwdChars = new char[passwdBytes.length]; for (int i=0; i paramSpec) throws InvalidParameterSpecException { - if (PBEParameterSpec.class.isAssignableFrom(paramSpec)) { + if (paramSpec.isAssignableFrom(PBEParameterSpec.class)) { return paramSpec.cast( new PBEParameterSpec(this.salt, this.iCount, this.cipherParam)); } else { diff --git a/src/java.base/share/classes/com/sun/crypto/provider/PBES2Parameters.java b/src/java.base/share/classes/com/sun/crypto/provider/PBES2Parameters.java index a26c95b16d3703960700b709fd830cd11932e391..4e3c7e44a3837beb2ec5e27e5098e9db82404f73 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/PBES2Parameters.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/PBES2Parameters.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -334,7 +334,7 @@ abstract class PBES2Parameters extends AlgorithmParametersSpi { T engineGetParameterSpec(Class paramSpec) throws InvalidParameterSpecException { - if (PBEParameterSpec.class.isAssignableFrom(paramSpec)) { + if (paramSpec.isAssignableFrom(PBEParameterSpec.class)) { return paramSpec.cast( new PBEParameterSpec(this.salt, this.iCount, this.cipherParam)); } else { diff --git a/src/java.base/share/classes/com/sun/crypto/provider/PBKDF2Core.java b/src/java.base/share/classes/com/sun/crypto/provider/PBKDF2Core.java index 87207c778ecb43e3684219296d0ffdcac46a7c92..c9e754685828e51c2cecd8b1c4699da019723616 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/PBKDF2Core.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/PBKDF2Core.java @@ -92,7 +92,7 @@ abstract class PBKDF2Core extends SecretKeyFactorySpi { if (key instanceof javax.crypto.interfaces.PBEKey) { // Check if requested key spec is amongst the valid ones if ((keySpecCl != null) - && PBEKeySpec.class.isAssignableFrom(keySpecCl)) { + && keySpecCl.isAssignableFrom(PBEKeySpec.class)) { javax.crypto.interfaces.PBEKey pKey = (javax.crypto.interfaces.PBEKey) key; char[] passwd = pKey.getPassword(); diff --git a/src/java.base/share/classes/com/sun/crypto/provider/PBKDF2HmacSHA1Factory.java b/src/java.base/share/classes/com/sun/crypto/provider/PBKDF2HmacSHA1Factory.java deleted file mode 100644 index d8070e968b66e18625173781a95221a0c4c55a42..0000000000000000000000000000000000000000 --- a/src/java.base/share/classes/com/sun/crypto/provider/PBKDF2HmacSHA1Factory.java +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Copyright (c) 2005, 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 com.sun.crypto.provider; - -import java.security.InvalidKeyException; -import java.security.spec.KeySpec; -import java.security.spec.InvalidKeySpecException; -import java.util.Arrays; -import javax.crypto.SecretKey; -import javax.crypto.SecretKeyFactorySpi; -import javax.crypto.spec.PBEKeySpec; - -/** - * This class implements a key factory for PBE keys derived using - * PBKDF2 with HmacSHA1 psuedo random function(PRF) as defined in - * PKCS#5 v2.0. - * - * @author Valerie Peng - * - */ -public final class PBKDF2HmacSHA1Factory extends SecretKeyFactorySpi { - - /** - * Empty constructor - */ - public PBKDF2HmacSHA1Factory() { - } - - /** - * Generates a SecretKey object from the provided key - * specification (key material). - * - * @param keySpec the specification (key material) of the secret key - * - * @return the secret key - * - * @exception InvalidKeySpecException if the given key specification - * is inappropriate for this key factory to produce a public key. - */ - protected SecretKey engineGenerateSecret(KeySpec keySpec) - throws InvalidKeySpecException - { - if (!(keySpec instanceof PBEKeySpec)) { - throw new InvalidKeySpecException("Invalid key spec"); - } - PBEKeySpec ks = (PBEKeySpec) keySpec; - return new PBKDF2KeyImpl(ks, "HmacSHA1"); - } - - /** - * Returns a specification (key material) of the given key - * in the requested format. - * - * @param key the key - * - * @param keySpecCl the requested format in which the key material shall be - * returned - * - * @return the underlying key specification (key material) in the - * requested format - * - * @exception InvalidKeySpecException if the requested key - * specification is inappropriate for the given key, or the - * given key cannot be processed (e.g., the given key has an - * unrecognized algorithm or format). - */ - protected KeySpec engineGetKeySpec(SecretKey key, Class keySpecCl) - throws InvalidKeySpecException { - if (key instanceof javax.crypto.interfaces.PBEKey) { - // Check if requested key spec is amongst the valid ones - if ((keySpecCl != null) - && PBEKeySpec.class.isAssignableFrom(keySpecCl)) { - javax.crypto.interfaces.PBEKey pKey = - (javax.crypto.interfaces.PBEKey) key; - char[] passwd = pKey.getPassword(); - byte[] encoded = pKey.getEncoded(); - try { - return new PBEKeySpec(passwd, pKey.getSalt(), - pKey.getIterationCount(), encoded.length * 8); - } finally { - if (passwd != null) { - Arrays.fill(passwd, (char) 0); - } - Arrays.fill(encoded, (byte)0); - } - } else { - throw new InvalidKeySpecException("Invalid key spec"); - } - } else { - throw new InvalidKeySpecException("Invalid key " + - "format/algorithm"); - } - } - - /** - * Translates a SecretKey object, whose provider may be - * unknown or potentially untrusted, into a corresponding - * SecretKey object of this key factory. - * - * @param key the key whose provider is unknown or untrusted - * - * @return the translated key - * - * @exception InvalidKeyException if the given key cannot be processed by - * this key factory. - */ - protected SecretKey engineTranslateKey(SecretKey key) - throws InvalidKeyException { - if ((key != null) && - (key.getAlgorithm().equalsIgnoreCase("PBKDF2WithHmacSHA1")) && - (key.getFormat().equalsIgnoreCase("RAW"))) { - - // Check if key originates from this factory - if (key instanceof com.sun.crypto.provider.PBKDF2KeyImpl) { - return key; - } - // Check if key implements the PBEKey - if (key instanceof javax.crypto.interfaces.PBEKey) { - javax.crypto.interfaces.PBEKey pKey = - (javax.crypto.interfaces.PBEKey) key; - char[] password = pKey.getPassword(); - byte[] encoding = pKey.getEncoded(); - PBEKeySpec spec = - new PBEKeySpec(password, - pKey.getSalt(), - pKey.getIterationCount(), - encoding.length*8); - try { - return new PBKDF2KeyImpl(spec, "HmacSHA1"); - } catch (InvalidKeySpecException re) { - throw new InvalidKeyException - ("Invalid key component(s)", re); - } finally { - if (password != null) { - Arrays.fill(password, (char) 0); - spec.clearPassword(); - } - Arrays.fill(encoding, (byte)0); - } - } - } - throw new InvalidKeyException("Invalid key format/algorithm"); - } -} diff --git a/src/java.base/share/classes/com/sun/crypto/provider/RC2Parameters.java b/src/java.base/share/classes/com/sun/crypto/provider/RC2Parameters.java index e33ab101d707844eaae6fb19c3d0ff60ba64ea4f..919e1e7b2e93aef78b7400228ae23c4d434c7762 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/RC2Parameters.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/RC2Parameters.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -180,7 +180,7 @@ public final class RC2Parameters extends AlgorithmParametersSpi { T engineGetParameterSpec(Class paramSpec) throws InvalidParameterSpecException { - if (RC2ParameterSpec.class.isAssignableFrom(paramSpec)) { + if (paramSpec.isAssignableFrom(RC2ParameterSpec.class)) { return paramSpec.cast((iv == null ? new RC2ParameterSpec(effectiveKeySize) : new RC2ParameterSpec(effectiveKeySize, iv))); diff --git a/src/java.base/share/classes/com/sun/crypto/provider/SunJCE.java b/src/java.base/share/classes/com/sun/crypto/provider/SunJCE.java index a020e1c15d89ae22c72de3f2c2ab54e6f409b177..38836d2701eebe0e6b07c1798808a6de5be9563e 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/SunJCE.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/SunJCE.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -525,8 +525,8 @@ public final class SunJCE extends Provider { ps("AlgorithmParameters", "RC2", "com.sun.crypto.provider.RC2Parameters"); - ps("AlgorithmParameters", "OAEP", - "com.sun.crypto.provider.OAEPParameters"); + psA("AlgorithmParameters", "OAEP", + "com.sun.crypto.provider.OAEPParameters", null); psA("AlgorithmParameters", "ChaCha20-Poly1305", "com.sun.crypto.provider.ChaCha20Poly1305Parameters", null); diff --git a/src/java.base/share/classes/com/sun/crypto/provider/TlsKeyMaterialGenerator.java b/src/java.base/share/classes/com/sun/crypto/provider/TlsKeyMaterialGenerator.java index be1535d9a2b9ba5e508f787ece49367fb443e369..56e4dd976632aae8d3be0646cd2a3dd9530e6688 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/TlsKeyMaterialGenerator.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/TlsKeyMaterialGenerator.java @@ -213,7 +213,7 @@ public final class TlsKeyMaterialGenerator extends KeyGeneratorSpi { if (protocolVersion >= 0x0302) { // TLS 1.1+ throw new RuntimeException( - "Internal Error: TLS 1.1+ should not be negotiating" + + "Internal Error: TLS 1.1+ should not be negotiating " + "exportable ciphersuites"); } else if (protocolVersion == 0x0301) { // TLS 1.0 diff --git a/src/java.base/share/classes/java/io/ClassCache.java b/src/java.base/share/classes/java/io/ClassCache.java new file mode 100644 index 0000000000000000000000000000000000000000..48e7a36c05ab60bbeed37a9ab40adfa111e4d192 --- /dev/null +++ b/src/java.base/share/classes/java/io/ClassCache.java @@ -0,0 +1,116 @@ +/* + * 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. 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 java.io; + +import java.lang.ref.Reference; +import java.lang.ref.ReferenceQueue; +import java.lang.ref.SoftReference; +import java.util.Objects; + +// Maps Class instances to values of type T. Under memory pressure, the +// mapping is released (under soft references GC policy) and would be +// recomputed the next time it is queried. The mapping is bound to the +// lifetime of the class: when the class is unloaded, the mapping is +// removed too. +abstract class ClassCache { + + private static class CacheRef extends SoftReference { + private final Class type; + private T strongReferent; + + CacheRef(T referent, ReferenceQueue queue, Class type) { + super(referent, queue); + this.type = type; + this.strongReferent = referent; + } + + Class getType() { + return type; + } + + T getStrong() { + return strongReferent; + } + + void clearStrong() { + strongReferent = null; + } + } + + private final ReferenceQueue queue; + private final ClassValue> map; + + protected abstract T computeValue(Class cl); + + protected ClassCache() { + queue = new ReferenceQueue<>(); + map = new ClassValue<>() { + @Override + protected CacheRef computeValue(Class type) { + T v = ClassCache.this.computeValue(type); + Objects.requireNonNull(v); + return new CacheRef<>(v, queue, type); + } + }; + } + + T get(Class cl) { + while (true) { + processQueue(); + + CacheRef ref = map.get(cl); + + // Case 1: A recently created CacheRef. + // We might still have strong referent, and can return it. + // This guarantees progress for at least one thread on every CacheRef. + // Clear the strong referent before returning to make the cache soft. + T strongVal = ref.getStrong(); + if (strongVal != null) { + ref.clearStrong(); + return strongVal; + } + + // Case 2: Older or recently cleared CacheRef. + // Check if its soft referent is still available, and return it. + T val = ref.get(); + if (val != null) { + return val; + } + + // Case 3: The reference was cleared. + // Clear the mapping and retry. + map.remove(cl); + } + } + + private void processQueue() { + Reference ref; + while((ref = queue.poll()) != null) { + CacheRef cacheRef = (CacheRef)ref; + map.remove(cacheRef.getType()); + } + } +} diff --git a/src/java.base/share/classes/java/io/DataInput.java b/src/java.base/share/classes/java/io/DataInput.java index b8088ff78da2a6ee43839a670b49543327ebf00e..9fdc6bbaf52f68234dda4c96d93b5725ddf2fcdb 100644 --- a/src/java.base/share/classes/java/io/DataInput.java +++ b/src/java.base/share/classes/java/io/DataInput.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 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 @@ -493,7 +493,7 @@ public interface DataInput { * is encountered, it is discarded and reading * ceases. If the character {@code '\r'} * is encountered, it is discarded and, if - * the following byte converts to the + * the following byte converts to the * character {@code '\n'}, then that is * discarded also; reading then ceases. If * end of file is encountered before either diff --git a/src/java.base/share/classes/java/io/File.java b/src/java.base/share/classes/java/io/File.java index 3f7cd86cf7027eaa3b126a06e37e75a4ca7db517..f279ee56bf516cf0d0f31259228e1b67ab7ca24b 100644 --- a/src/java.base/share/classes/java/io/File.java +++ b/src/java.base/share/classes/java/io/File.java @@ -2012,7 +2012,7 @@ public class File int prefixLength = prefix.length(); int nusLength = nus.length(); - int suffixLength = suffix.length();; + int suffixLength = suffix.length(); String name; int nameMax = fs.getNameMax(dir.getPath()); diff --git a/src/java.base/share/classes/java/io/FilenameFilter.java b/src/java.base/share/classes/java/io/FilenameFilter.java index fcd81479ee12eaa4ad2e1a4a1d8caa1138039daa..43e041d546d0d1b3bd2ea5f305163f7bac4e478e 100644 --- a/src/java.base/share/classes/java/io/FilenameFilter.java +++ b/src/java.base/share/classes/java/io/FilenameFilter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 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 @@ -34,11 +34,12 @@ package java.io; * * @author Arthur van Hoff * @author Jonathan Payne - * @see java.awt.FileDialog#setFilenameFilter(java.io.FilenameFilter) + * @see java.desktop/java.awt.FileDialog#setFilenameFilter(java.io.FilenameFilter) * @see java.io.File * @see java.io.File#list(java.io.FilenameFilter) * @since 1.0 */ +@SuppressWarnings("doclint:reference") // cross-module links @FunctionalInterface public interface FilenameFilter { /** diff --git a/src/java.base/share/classes/java/io/InvalidClassException.java b/src/java.base/share/classes/java/io/InvalidClassException.java index 6de0e70f760fe88f7b7ce62886529d6fc7667318..be187597726a8356e0d31587946d1535864fd024 100644 --- a/src/java.base/share/classes/java/io/InvalidClassException.java +++ b/src/java.base/share/classes/java/io/InvalidClassException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 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 @@ -73,9 +73,34 @@ public class InvalidClassException extends ObjectStreamException { classname = cname; } + /** + * Report an InvalidClassException for the reason and cause specified. + * + * @param reason String describing the reason for the exception. + * @param cause the cause + * @since 19 + */ + public InvalidClassException(String reason, Throwable cause) { + super(reason, cause); + } + + /** + * Report an InvalidClassException for the reason and cause specified. + * + * @param cname a String naming the invalid class. + * @param reason String describing the reason for the exception. + * @param cause the cause + * @since 19 + */ + public InvalidClassException(String cname, String reason, Throwable cause) { + super(reason, cause); + classname = cname; + } + /** * Produce the message and include the classname, if present. */ + @Override public String getMessage() { if (classname == null) return super.getMessage(); diff --git a/src/java.base/share/classes/java/io/InvalidObjectException.java b/src/java.base/share/classes/java/io/InvalidObjectException.java index c6e626b238facc87b905dbad6647ea5c081c58f0..a6331de45ab474ceb2f3906cb1a775cbea19ad1e 100644 --- a/src/java.base/share/classes/java/io/InvalidObjectException.java +++ b/src/java.base/share/classes/java/io/InvalidObjectException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 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 @@ -45,7 +45,21 @@ public class InvalidObjectException extends ObjectStreamException { * * @see ObjectInputValidation */ - public InvalidObjectException(String reason) { + public InvalidObjectException(String reason) { super(reason); } + + /** + * Constructs an {@code InvalidObjectException} with the given + * reason and cause. + * + * @param reason Detailed message explaining the reason for the failure. + * @param cause the cause + * + * @see ObjectInputValidation + * @since 19 + */ + public InvalidObjectException(String reason, Throwable cause) { + super(reason, cause); + } } diff --git a/src/java.base/share/classes/java/io/LineNumberInputStream.java b/src/java.base/share/classes/java/io/LineNumberInputStream.java index eb04f499a5aef711e4649b06982616f533e98e3d..4557ef2579553f3f056bd401dd27f62e20fcf1ec 100644 --- a/src/java.base/share/classes/java/io/LineNumberInputStream.java +++ b/src/java.base/share/classes/java/io/LineNumberInputStream.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 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 @@ -149,9 +149,7 @@ public class LineNumberInputStream extends FilterInputStream { if (c == -1) { break; } - if (b != null) { - b[off + i] = (byte)c; - } + b[off + i] = (byte)c; } } catch (IOException ee) { } diff --git a/src/java.base/share/classes/java/io/ObjectInputFilter.java b/src/java.base/share/classes/java/io/ObjectInputFilter.java index c9722ea23e742aecd9f3c8b7f0fa21fb8fb0d1cf..3ec164f5aea891b5d48efc493a546aa9e2ab7741 100644 --- a/src/java.base/share/classes/java/io/ObjectInputFilter.java +++ b/src/java.base/share/classes/java/io/ObjectInputFilter.java @@ -27,7 +27,6 @@ package java.io; import jdk.internal.access.SharedSecrets; import jdk.internal.util.StaticProperty; -import sun.security.action.GetBooleanAction; import java.lang.reflect.InvocationTargetException; import java.security.AccessController; @@ -523,8 +522,15 @@ public interface ObjectInputFilter { * {@systemProperty jdk.serialFilter}, its value is used to configure the filter. * If the system property is not defined, and the {@link java.security.Security} property * {@code jdk.serialFilter} is defined then it is used to configure the filter. - * Otherwise, the filter is not configured during initialization and - * can be set with {@link #setSerialFilter(ObjectInputFilter) Config.setSerialFilter}. + * The filter is created as if {@link #createFilter(String) createFilter} is called, + * if the filter string is invalid the initialization fails and subsequent attempts to + * {@linkplain Config#getSerialFilter() get the filter}, {@linkplain Config#setSerialFilter set a filter}, + * or create an {@linkplain ObjectInputStream#ObjectInputStream(InputStream) ObjectInputStream} + * throw {@link IllegalStateException}. Deserialization is not possible with an + * invalid serial filter. + * If the system property {@code jdk.serialFilter} or the {@link java.security.Security} + * property {@code jdk.serialFilter} is not set the filter can be set with + * {@link #setSerialFilter(ObjectInputFilter) Config.setSerialFilter}. * Setting the {@code jdk.serialFilter} with {@link System#setProperty(String, String) * System.setProperty} does not set the filter. * The syntax for the property value is the same as for the @@ -543,9 +549,12 @@ public interface ObjectInputFilter { *

      The class must be public, must have a public zero-argument constructor, implement the * {@link BinaryOperator {@literal BinaryOperator}} interface, provide its implementation and * be accessible via the {@linkplain ClassLoader#getSystemClassLoader() application class loader}. - * If the filter factory constructor is not invoked successfully, an {@link ExceptionInInitializerError} - * is thrown and subsequent use of the filter factory for deserialization fails with - * {@link IllegalStateException}. + * If the filter factory constructor is not invoked successfully subsequent attempts to + * {@linkplain Config#getSerialFilterFactory() get the factory}, + * {@linkplain Config#setSerialFilterFactory(BinaryOperator) set the factory}, or create an + * {@link ObjectInputStream#ObjectInputStream(InputStream) ObjectInputStream} + * throw {@link IllegalStateException}. Deserialization is not possible with an + * invalid serial filter factory. * The filter factory configured using the system or security property during initialization * can NOT be replaced with {@link #setSerialFilterFactory(BinaryOperator) Config.setSerialFilterFactory}. * This ensures that a filter factory set on the command line is not overridden accidentally @@ -580,12 +589,22 @@ public interface ObjectInputFilter { */ private static volatile ObjectInputFilter serialFilter; + /** + * Saved message if the jdk.serialFilter property is invalid. + */ + private static final String invalidFilterMessage; + /** * Current serial filter factory. * @see Config#setSerialFilterFactory(BinaryOperator) */ private static volatile BinaryOperator serialFilterFactory; + /** + * Saved message if the jdk.serialFilterFactory property is invalid. + */ + private static final String invalidFactoryMessage; + /** * Boolean to indicate that the filter factory can not be set or replaced. * - an ObjectInputStream has already been created using the current filter factory @@ -628,23 +647,24 @@ public interface ObjectInputFilter { Security.getProperty(SERIAL_FILTER_PROPNAME)); // Initialize the static filter if the jdk.serialFilter is present - ObjectInputFilter filter = null; + String filterMessage = null; if (filterString != null) { configLog.log(DEBUG, "Creating deserialization filter from {0}", filterString); try { - filter = createFilter(filterString); + serialFilter = createFilter(filterString); } catch (RuntimeException re) { configLog.log(ERROR, "Error configuring filter: {0}", (Object) re); - // Do not continue if configuration not initialized - throw re; + // serialFilter remains null + filterMessage = "Invalid jdk.serialFilter: " + re.getMessage(); } } - serialFilter = filter; + invalidFilterMessage = filterMessage; // Initialize the filter factory if the jdk.serialFilterFactory is defined // otherwise use the builtin filter factory. + String factoryMessage = null; if (factoryClassName == null) { serialFilterFactory = new BuiltinFilterFactory(); } else { @@ -669,10 +689,13 @@ public interface ObjectInputFilter { Throwable th = (ex instanceof InvocationTargetException ite) ? ite.getCause() : ex; configLog.log(ERROR, "Error configuring filter factory: {0}", (Object)th); - // Do not continue if configuration not initialized - throw new ExceptionInInitializerError(th); + // Configuration not initialized + // serialFilterFactory remains null and filterFactoryNoReplace == true; + factoryMessage = "invalid jdk.serialFilterFactory: " + + factoryClassName + ": " + th.getClass().getName() + ": " + th.getMessage(); } } + invalidFactoryMessage = factoryMessage; // Setup shared secrets for RegistryImpl to use. SharedSecrets.setJavaObjectInputFilterAccess(Config::createFilter2); } @@ -694,8 +717,14 @@ public interface ObjectInputFilter { * Returns the static JVM-wide deserialization filter or {@code null} if not configured. * * @return the static JVM-wide deserialization filter or {@code null} if not configured + * @throws IllegalStateException if the initialization of the filter from the + * system property {@code jdk.serialFilter} or + * the security property {@code jdk.serialFilter} fails. */ public static ObjectInputFilter getSerialFilter() { + if (invalidFilterMessage != null) { + throw new IllegalStateException(invalidFilterMessage); + } return serialFilter; } @@ -705,7 +734,9 @@ public interface ObjectInputFilter { * @param filter the deserialization filter to set as the JVM-wide filter; not null * @throws SecurityException if there is security manager and the * {@code SerializablePermission("serialFilter")} is not granted - * @throws IllegalStateException if the filter has already been set + * @throws IllegalStateException if the filter has already been set or the initialization + * of the filter from the system property {@code jdk.serialFilter} or + * the security property {@code jdk.serialFilter} fails. */ public static void setSerialFilter(ObjectInputFilter filter) { Objects.requireNonNull(filter, "filter"); @@ -714,6 +745,9 @@ public interface ObjectInputFilter { if (sm != null) { sm.checkPermission(ObjectStreamConstants.SERIAL_FILTER_PERMISSION); } + if (invalidFilterMessage != null) { + throw new IllegalStateException(invalidFilterMessage); + } synchronized (serialFilterLock) { if (serialFilter != null) { throw new IllegalStateException("Serial filter can only be set once"); @@ -747,8 +781,10 @@ public interface ObjectInputFilter { * @since 17 */ public static BinaryOperator getSerialFilterFactory() { - if (serialFilterFactory == null) - throw new IllegalStateException("Serial filter factory initialization incomplete"); + if (serialFilterFactory == null) { + // If initializing the factory failed or not yet complete, throw with the message + throw new IllegalStateException(invalidFilterFactoryMessage()); + } return serialFilterFactory; } @@ -810,15 +846,26 @@ public interface ObjectInputFilter { } if (filterFactoryNoReplace.getAndSet(true)) { final String msg = serialFilterFactory != null - ? serialFilterFactory.getClass().getName() - : "initialization incomplete"; - throw new IllegalStateException("Cannot replace filter factory: " + msg); + ? "Cannot replace filter factory: " + serialFilterFactory.getClass().getName() + : invalidFilterFactoryMessage(); + throw new IllegalStateException(msg); } configLog.log(DEBUG, "Setting deserialization filter factory to {0}", filterFactory.getClass().getName()); serialFilterFactory = filterFactory; } + /* + * Return message for an invalid filter factory configuration saved from the static init. + * It can be called before the static initializer is complete and has set the message/null. + */ + private static String invalidFilterFactoryMessage() { + assert serialFilterFactory == null; // undefined if a filter factory has been set + return (invalidFactoryMessage != null) + ? invalidFactoryMessage + : "Serial filter factory initialization incomplete"; + } + /** * Returns an ObjectInputFilter from a string of patterns. *

      diff --git a/src/java.base/share/classes/java/io/ObjectInputStream.java b/src/java.base/share/classes/java/io/ObjectInputStream.java index d58bf1d91c9460b02b8bb559c9867e913456f46e..14812fea9adda11a9c03b39f1a6d29dce9adf468 100644 --- a/src/java.base/share/classes/java/io/ObjectInputStream.java +++ b/src/java.base/share/classes/java/io/ObjectInputStream.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 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 @@ -26,11 +26,9 @@ package java.io; import java.io.ObjectInputFilter.Config; -import java.io.ObjectStreamClass.WeakClassKey; import java.io.ObjectStreamClass.RecordSupport; import java.lang.System.Logger; import java.lang.invoke.MethodHandle; -import java.lang.ref.ReferenceQueue; import java.lang.reflect.Array; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Modifier; @@ -43,10 +41,6 @@ import java.security.PrivilegedExceptionAction; import java.util.Arrays; import java.util.Map; import java.util.Objects; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - -import static java.io.ObjectStreamClass.processQueue; import jdk.internal.access.SharedSecrets; import jdk.internal.event.DeserializationEvent; @@ -282,12 +276,13 @@ public class ObjectInputStream private static class Caches { /** cache of subclass security audit results */ - static final ConcurrentMap subclassAudits = - new ConcurrentHashMap<>(); - - /** queue for WeakReferences to audited subclasses */ - static final ReferenceQueue> subclassAuditsQueue = - new ReferenceQueue<>(); + static final ClassValue subclassAudits = + new ClassValue<>() { + @Override + protected Boolean computeValue(Class type) { + return auditSubclass(type); + } + }; /** * Property to permit setting a filter after objects @@ -297,6 +292,15 @@ public class ObjectInputStream static final boolean SET_FILTER_AFTER_READ = GetBooleanAction .privilegedGetProperty("jdk.serialSetFilterAfterRead"); + /** + * Property to control {@link GetField#get(String, Object)} conversion of + * {@link ClassNotFoundException} to {@code null}. If set to {@code true} + * {@link GetField#get(String, Object)} returns null otherwise + * throwing {@link ClassNotFoundException}. + */ + private static final boolean GETFIELD_CNFE_RETURNS_NULL = GetBooleanAction + .privilegedGetProperty("jdk.serialGetFieldCnfeReturnsNull"); + /** * Property to override the implementation limit on the number * of interfaces allowed for Proxies. The property value is clamped to 0..65535. @@ -373,8 +377,13 @@ public class ObjectInputStream * has written and flushed the header. * *

      The constructor initializes the deserialization filter to the filter returned - * by invoking the {@link Config#getSerialFilterFactory()} with {@code null} for the current filter + * by invoking the serial filter factory returned from {@link Config#getSerialFilterFactory()} + * with {@code null} for the current filter * and the {@linkplain Config#getSerialFilter() static JVM-wide filter} for the requested filter. + * If the serial filter or serial filter factory properties are invalid + * an {@link IllegalStateException} is thrown. + * When the filter factory {@code apply} method is invoked it may throw a runtime exception + * preventing the {@code ObjectInputStream} from being constructed. * *

      If a security manager is installed, this constructor will check for * the "enableSubclassImplementation" SerializablePermission when invoked @@ -387,6 +396,8 @@ public class ObjectInputStream * @throws IOException if an I/O error occurs while reading stream header * @throws SecurityException if untrusted subclass illegally overrides * security-sensitive methods + * @throws IllegalStateException if the initialization of {@link ObjectInputFilter.Config} + * fails due to invalid serial filter or serial filter factory properties. * @throws NullPointerException if {@code in} is {@code null} * @see ObjectInputStream#ObjectInputStream() * @see ObjectInputStream#readFields() @@ -410,8 +421,13 @@ public class ObjectInputStream * implementation of ObjectInputStream. * *

      The constructor initializes the deserialization filter to the filter returned - * by invoking the {@link Config#getSerialFilterFactory()} with {@code null} for the current filter + * by invoking the serial filter factory returned from {@link Config#getSerialFilterFactory()} + * with {@code null} for the current filter * and the {@linkplain Config#getSerialFilter() static JVM-wide filter} for the requested filter. + * If the serial filter or serial filter factory properties are invalid + * an {@link IllegalStateException} is thrown. + * When the filter factory {@code apply} method is invoked it may throw a runtime exception + * preventing the {@code ObjectInputStream} from being constructed. * *

      If there is a security manager installed, this method first calls the * security manager's {@code checkPermission} method with the @@ -422,6 +438,8 @@ public class ObjectInputStream * {@code checkPermission} method denies enabling * subclassing. * @throws IOException if an I/O error occurs while creating this stream + * @throws IllegalStateException if the initialization of {@link ObjectInputFilter.Config} + * fails due to invalid serial filter or serial filter factory properties. * @see SecurityManager#checkPermission * @see java.io.SerializablePermission */ @@ -720,7 +738,7 @@ public class ObjectInputStream * restored a final set of validations can be performed. * * @param obj the object to receive the validation callback. - * @param prio controls the order of callbacks;zero is a good default. + * @param prio controls the order of callbacks; zero is a good default. * Use higher numbers to be called back earlier, lower numbers for * later callbacks. Within a priority, callbacks are processed in * no particular order. @@ -1026,10 +1044,7 @@ public class ObjectInputStream if (buf == null) { throw new NullPointerException(); } - int endoff = off + len; - if (off < 0 || len < 0 || endoff > buf.length || endoff < 0) { - throw new IndexOutOfBoundsException(); - } + Objects.checkFromIndexSize(off, len, buf.length); return bin.read(buf, off, len, false); } @@ -1198,10 +1213,7 @@ public class ObjectInputStream * @throws IOException If other I/O error has occurred. */ public void readFully(byte[] buf, int off, int len) throws IOException { - int endoff = off + len; - if (off < 0 || len < 0 || endoff > buf.length || endoff < 0) { - throw new IndexOutOfBoundsException(); - } + Objects.checkFromIndexSize(off, len, buf.length); bin.readFully(buf, off, len, false); } @@ -1303,6 +1315,8 @@ public class ObjectInputStream *

    • each object reference previously deserialized from the stream * (class is {@code null}, arrayLength is -1), *
    • each regular class (class is not {@code null}, arrayLength is -1), + *
    • each interface class explicitly referenced in the stream + * (it is not called for interfaces implemented by classes in the stream), *
    • each interface of a dynamic proxy and the dynamic proxy class itself * (class is not {@code null}, arrayLength is -1), *
    • each array is filtered using the array type and length of the array @@ -1415,9 +1429,7 @@ public class ObjectInputStream event.commit(); } if (serialFilter != null && (status == null || status == ObjectInputFilter.Status.REJECTED)) { - InvalidClassException ice = new InvalidClassException("filter status: " + status); - ice.initCause(ex); - throw ice; + throw new InvalidClassException("filter status: " + status, ex); } } @@ -1596,12 +1608,13 @@ public class ObjectInputStream * @param val the default value to use if {@code name} does not * have a value * @return the value of the named {@code Object} field + * @throws ClassNotFoundException Class of a serialized object cannot be found. * @throws IOException if there are I/O errors while reading from the * underlying {@code InputStream} * @throws IllegalArgumentException if type of {@code name} is * not serializable or if the field type is incorrect */ - public abstract Object get(String name, Object val) throws IOException; + public abstract Object get(String name, Object val) throws IOException, ClassNotFoundException; } /** @@ -1620,13 +1633,7 @@ public class ObjectInputStream if (sm == null) { return; } - processQueue(Caches.subclassAuditsQueue, Caches.subclassAudits); - WeakClassKey key = new WeakClassKey(cl, Caches.subclassAuditsQueue); - Boolean result = Caches.subclassAudits.get(key); - if (result == null) { - result = auditSubclass(cl); - Caches.subclassAudits.putIfAbsent(key, result); - } + boolean result = Caches.subclassAudits.get(cl); if (!result) { sm.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION); } @@ -1986,11 +1993,11 @@ public class ObjectInputStream } } catch (ClassNotFoundException ex) { resolveEx = ex; + } catch (IllegalAccessError aie) { + throw new InvalidClassException(aie.getMessage(), aie); } catch (OutOfMemoryError memerr) { - IOException ex = new InvalidObjectException("Proxy interface limit exceeded: " + - Arrays.toString(ifaces)); - ex.initCause(memerr); - throw ex; + throw new InvalidObjectException("Proxy interface limit exceeded: " + + Arrays.toString(ifaces), memerr); } // Call filterCheck on the class before reading anything else @@ -2003,10 +2010,8 @@ public class ObjectInputStream depth++; desc.initProxy(cl, resolveEx, readClassDesc(false)); } catch (OutOfMemoryError memerr) { - IOException ex = new InvalidObjectException("Proxy interface limit exceeded: " + - Arrays.toString(ifaces)); - ex.initCause(memerr); - throw ex; + throw new InvalidObjectException("Proxy interface limit exceeded: " + + Arrays.toString(ifaces), memerr); } finally { depth--; } @@ -2037,8 +2042,8 @@ public class ObjectInputStream try { readDesc = readClassDescriptor(); } catch (ClassNotFoundException ex) { - throw (IOException) new InvalidClassException( - "failed to read class descriptor").initCause(ex); + throw new InvalidClassException("failed to read class descriptor", + ex); } Class cl = null; @@ -2064,6 +2069,30 @@ public class ObjectInputStream totalObjectRefs++; depth++; desc.initNonProxy(readDesc, cl, resolveEx, readClassDesc(false)); + + if (cl != null) { + // Check that serial filtering has been done on the local class descriptor's superclass, + // in case it does not appear in the stream. + + // Find the next super descriptor that has a local class descriptor. + // Descriptors for which there is no local class are ignored. + ObjectStreamClass superLocal = null; + for (ObjectStreamClass sDesc = desc.getSuperDesc(); sDesc != null; sDesc = sDesc.getSuperDesc()) { + if ((superLocal = sDesc.getLocalDesc()) != null) { + break; + } + } + + // Scan local descriptor superclasses for a match with the local descriptor of the super found above. + // For each super descriptor before the match, invoke the serial filter on the class. + // The filter is invoked for each class that has not already been filtered + // but would be filtered if the instance had been serialized by this Java runtime. + for (ObjectStreamClass lDesc = desc.getLocalDesc().getSuperDesc(); + lDesc != null && lDesc != superLocal; + lDesc = lDesc.getSuperDesc()) { + filterCheck(lDesc.forClass(), -1); + } + } } finally { depth--; } @@ -2184,9 +2213,8 @@ public class ObjectInputStream Enum en = Enum.valueOf((Class)cl, name); result = en; } catch (IllegalArgumentException ex) { - throw (IOException) new InvalidObjectException( - "enum constant " + name + " does not exist in " + - cl).initCause(ex); + throw new InvalidObjectException("enum constant " + + name + " does not exist in " + cl, ex); } if (!unshared) { handles.setObject(enumHandle, result); @@ -2225,9 +2253,8 @@ public class ObjectInputStream try { obj = desc.isInstantiable() ? desc.newInstance() : null; } catch (Exception ex) { - throw (IOException) new InvalidClassException( - desc.forClass().getName(), - "unable to create instance").initCause(ex); + throw new InvalidClassException(desc.forClass().getName(), + "unable to create instance", ex); } passHandle = handles.assign(unshared ? unsharedMarker : obj); @@ -2351,16 +2378,12 @@ public class ObjectInputStream try { return (Object) ctrMH.invokeExact(fieldValues.primValues, fieldValues.objValues); } catch (Exception e) { - InvalidObjectException ioe = new InvalidObjectException(e.getMessage()); - ioe.initCause(e); - throw ioe; + throw new InvalidObjectException(e.getMessage(), e); } catch (Error e) { throw e; } catch (Throwable t) { - ObjectStreamException ose = new InvalidObjectException( - "ReflectiveOperationException during deserialization"); - ose.initCause(t); - throw ose; + throw new InvalidObjectException("ReflectiveOperationException " + + "during deserialization", t); } } @@ -2522,6 +2545,13 @@ public class ObjectInputStream throw new InternalError(); } clear(); + // Check that an object follows the TC_EXCEPTION typecode + byte tc = bin.peekByte(); + if (tc != TC_OBJECT && + tc != TC_REFERENCE) { + throw new StreamCorruptedException( + String.format("invalid type code: %02X", tc)); + } return (IOException) readObject0(Object.class, false); } @@ -2645,13 +2675,19 @@ public class ObjectInputStream return (off >= 0) ? Bits.getDouble(primValues, off) : val; } - public Object get(String name, Object val) { + public Object get(String name, Object val) throws ClassNotFoundException { int off = getFieldOffset(name, Object.class); if (off >= 0) { int objHandle = objHandles[off]; handles.markDependency(passHandle, objHandle); - return (handles.lookupException(objHandle) == null) ? - objValues[off] : null; + ClassNotFoundException ex = handles.lookupException(objHandle); + if (ex == null) + return objValues[off]; + if (Caches.GETFIELD_CNFE_RETURNS_NULL) { + // Revert to the prior behavior; return null instead of CNFE + return null; + } + throw ex; } else { return val; } diff --git a/src/java.base/share/classes/java/io/ObjectOutputStream.java b/src/java.base/share/classes/java/io/ObjectOutputStream.java index 8d34fcec48396aa50ec167c4a814cb524b6a1bac..1ac6f60614f1b8113c937cee2bc4210a76db3458 100644 --- a/src/java.base/share/classes/java/io/ObjectOutputStream.java +++ b/src/java.base/share/classes/java/io/ObjectOutputStream.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 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 @@ -25,17 +25,13 @@ package java.io; -import java.io.ObjectStreamClass.WeakClassKey; -import java.lang.ref.ReferenceQueue; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Objects; import java.util.StringJoiner; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import static java.io.ObjectStreamClass.processQueue; import sun.reflect.misc.ReflectUtil; /** @@ -176,12 +172,13 @@ public class ObjectOutputStream private static class Caches { /** cache of subclass security audit results */ - static final ConcurrentMap subclassAudits = - new ConcurrentHashMap<>(); - - /** queue for WeakReferences to audited subclasses */ - static final ReferenceQueue> subclassAuditsQueue = - new ReferenceQueue<>(); + static final ClassValue subclassAudits = + new ClassValue<>() { + @Override + protected Boolean computeValue(Class type) { + return auditSubclass(type); + } + }; } /** filter stream for handling block data conversion */ @@ -659,10 +656,11 @@ public class ObjectOutputStream * stream. Subclasses of ObjectOutputStream may override this method to * customize the way in which class descriptors are written to the * serialization stream. The corresponding method in ObjectInputStream, - * {@code readClassDescriptor}, should then be overridden to + * {@link ObjectInputStream#readClassDescriptor readClassDescriptor}, should then be overridden to * reconstitute the class descriptor from its custom stream representation. * By default, this method writes class descriptors according to the format - * defined in the Object Serialization specification. + * defined in the + * Java Object Serialization Specification. * *

      Note that this method will only be called if the ObjectOutputStream * is not using the old serialization stream format (set by calling @@ -718,10 +716,7 @@ public class ObjectOutputStream if (buf == null) { throw new NullPointerException(); } - int endoff = off + len; - if (off < 0 || len < 0 || endoff > buf.length || endoff < 0) { - throw new IndexOutOfBoundsException(); - } + Objects.checkFromIndexSize(off, len, buf.length); bout.write(buf, off, len, false); } @@ -1067,13 +1062,7 @@ public class ObjectOutputStream if (sm == null) { return; } - processQueue(Caches.subclassAuditsQueue, Caches.subclassAudits); - WeakClassKey key = new WeakClassKey(cl, Caches.subclassAuditsQueue); - Boolean result = Caches.subclassAudits.get(key); - if (result == null) { - result = auditSubclass(cl); - Caches.subclassAudits.putIfAbsent(key, result); - } + boolean result = Caches.subclassAudits.get(cl); if (!result) { sm.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION); } diff --git a/src/java.base/share/classes/java/io/ObjectStreamClass.java b/src/java.base/share/classes/java/io/ObjectStreamClass.java index ff8a934a887da31dadb46a7dd62aa7711127c3b1..c41e8b1744a088c8377eb0decab9d9a11c3acb8b 100644 --- a/src/java.base/share/classes/java/io/ObjectStreamClass.java +++ b/src/java.base/share/classes/java/io/ObjectStreamClass.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 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 @@ -28,10 +28,6 @@ package java.io; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; -import java.lang.ref.Reference; -import java.lang.ref.ReferenceQueue; -import java.lang.ref.SoftReference; -import java.lang.ref.WeakReference; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; @@ -59,7 +55,6 @@ import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; import jdk.internal.misc.Unsafe; import jdk.internal.reflect.CallerSensitive; import jdk.internal.reflect.Reflection; @@ -108,19 +103,22 @@ public class ObjectStreamClass implements Serializable { private static class Caches { /** cache mapping local classes -> descriptors */ - static final ConcurrentMap> localDescs = - new ConcurrentHashMap<>(); + static final ClassCache localDescs = + new ClassCache<>() { + @Override + protected ObjectStreamClass computeValue(Class type) { + return new ObjectStreamClass(type); + } + }; /** cache mapping field group/local desc pairs -> field reflectors */ - static final ConcurrentMap> reflectors = - new ConcurrentHashMap<>(); - - /** queue for WeakReferences to local classes */ - private static final ReferenceQueue> localDescsQueue = - new ReferenceQueue<>(); - /** queue for WeakReferences to field reflectors keys */ - private static final ReferenceQueue> reflectorsQueue = - new ReferenceQueue<>(); + static final ClassCache> reflectors = + new ClassCache<>() { + @Override + protected Map computeValue(Class type) { + return new ConcurrentHashMap<>(); + } + }; } /** class associated with this descriptor (if any) */ @@ -362,136 +360,7 @@ public class ObjectStreamClass implements Serializable { if (!(all || Serializable.class.isAssignableFrom(cl))) { return null; } - processQueue(Caches.localDescsQueue, Caches.localDescs); - WeakClassKey key = new WeakClassKey(cl, Caches.localDescsQueue); - Reference ref = Caches.localDescs.get(key); - Object entry = null; - if (ref != null) { - entry = ref.get(); - } - EntryFuture future = null; - if (entry == null) { - EntryFuture newEntry = new EntryFuture(); - Reference newRef = new SoftReference<>(newEntry); - do { - if (ref != null) { - Caches.localDescs.remove(key, ref); - } - ref = Caches.localDescs.putIfAbsent(key, newRef); - if (ref != null) { - entry = ref.get(); - } - } while (ref != null && entry == null); - if (entry == null) { - future = newEntry; - } - } - - if (entry instanceof ObjectStreamClass) { // check common case first - return (ObjectStreamClass) entry; - } - if (entry instanceof EntryFuture) { - future = (EntryFuture) entry; - if (future.getOwner() == Thread.currentThread()) { - /* - * Handle nested call situation described by 4803747: waiting - * for future value to be set by a lookup() call further up the - * stack will result in deadlock, so calculate and set the - * future value here instead. - */ - entry = null; - } else { - entry = future.get(); - } - } - if (entry == null) { - try { - entry = new ObjectStreamClass(cl); - } catch (Throwable th) { - entry = th; - } - if (future.set(entry)) { - Caches.localDescs.put(key, new SoftReference<>(entry)); - } else { - // nested lookup call already set future - entry = future.get(); - } - } - - if (entry instanceof ObjectStreamClass) { - return (ObjectStreamClass) entry; - } else if (entry instanceof RuntimeException) { - throw (RuntimeException) entry; - } else if (entry instanceof Error) { - throw (Error) entry; - } else { - throw new InternalError("unexpected entry: " + entry); - } - } - - /** - * Placeholder used in class descriptor and field reflector lookup tables - * for an entry in the process of being initialized. (Internal) callers - * which receive an EntryFuture belonging to another thread as the result - * of a lookup should call the get() method of the EntryFuture; this will - * return the actual entry once it is ready for use and has been set(). To - * conserve objects, EntryFutures synchronize on themselves. - */ - private static class EntryFuture { - - private static final Object unset = new Object(); - private final Thread owner = Thread.currentThread(); - private Object entry = unset; - - /** - * Attempts to set the value contained by this EntryFuture. If the - * EntryFuture's value has not been set already, then the value is - * saved, any callers blocked in the get() method are notified, and - * true is returned. If the value has already been set, then no saving - * or notification occurs, and false is returned. - */ - synchronized boolean set(Object entry) { - if (this.entry != unset) { - return false; - } - this.entry = entry; - notifyAll(); - return true; - } - - /** - * Returns the value contained by this EntryFuture, blocking if - * necessary until a value is set. - */ - @SuppressWarnings("removal") - synchronized Object get() { - boolean interrupted = false; - while (entry == unset) { - try { - wait(); - } catch (InterruptedException ex) { - interrupted = true; - } - } - if (interrupted) { - AccessController.doPrivileged( - new PrivilegedAction<>() { - public Void run() { - Thread.currentThread().interrupt(); - return null; - } - } - ); - } - return entry; - } - - /** - * Returns the thread that created this EntryFuture. - */ - Thread getOwner() { - return owner; - } + return Caches.localDescs.get(cl); } /** @@ -840,8 +709,9 @@ public class ObjectStreamClass implements Serializable { try { fields[i] = new ObjectStreamField(fname, signature, false); } catch (RuntimeException e) { - throw (IOException) new InvalidClassException(name, - "invalid descriptor for field " + fname).initCause(e); + throw new InvalidClassException(name, + "invalid descriptor for field " + + fname, e); } } computeFieldOffsets(); @@ -2248,82 +2118,39 @@ public class ObjectStreamClass implements Serializable { { // class irrelevant if no fields Class cl = (localDesc != null && fields.length > 0) ? - localDesc.cl : null; - processQueue(Caches.reflectorsQueue, Caches.reflectors); - FieldReflectorKey key = new FieldReflectorKey(cl, fields, - Caches.reflectorsQueue); - Reference ref = Caches.reflectors.get(key); - Object entry = null; - if (ref != null) { - entry = ref.get(); - } - EntryFuture future = null; - if (entry == null) { - EntryFuture newEntry = new EntryFuture(); - Reference newRef = new SoftReference<>(newEntry); - do { - if (ref != null) { - Caches.reflectors.remove(key, ref); - } - ref = Caches.reflectors.putIfAbsent(key, newRef); - if (ref != null) { - entry = ref.get(); - } - } while (ref != null && entry == null); - if (entry == null) { - future = newEntry; - } - } + localDesc.cl : Void.class; - if (entry instanceof FieldReflector) { // check common case first - return (FieldReflector) entry; - } else if (entry instanceof EntryFuture) { - entry = ((EntryFuture) entry).get(); - } else if (entry == null) { - try { - entry = new FieldReflector(matchFields(fields, localDesc)); - } catch (Throwable th) { - entry = th; - } - future.set(entry); - Caches.reflectors.put(key, new SoftReference<>(entry)); - } - - if (entry instanceof FieldReflector) { - return (FieldReflector) entry; - } else if (entry instanceof InvalidClassException) { - throw (InvalidClassException) entry; - } else if (entry instanceof RuntimeException) { - throw (RuntimeException) entry; - } else if (entry instanceof Error) { - throw (Error) entry; - } else { - throw new InternalError("unexpected entry: " + entry); + var clReflectors = Caches.reflectors.get(cl); + var key = new FieldReflectorKey(fields); + var reflector = clReflectors.get(key); + if (reflector == null) { + reflector = new FieldReflector(matchFields(fields, localDesc)); + var oldReflector = clReflectors.putIfAbsent(key, reflector); + if (oldReflector != null) { + reflector = oldReflector; + } } + return reflector; } /** * FieldReflector cache lookup key. Keys are considered equal if they - * refer to the same class and equivalent field formats. + * refer to equivalent field formats. */ - private static class FieldReflectorKey extends WeakReference> { + private static class FieldReflectorKey { private final String[] sigs; private final int hash; - private final boolean nullClass; - FieldReflectorKey(Class cl, ObjectStreamField[] fields, - ReferenceQueue> queue) + FieldReflectorKey(ObjectStreamField[] fields) { - super(cl, queue); - nullClass = (cl == null); sigs = new String[2 * fields.length]; for (int i = 0, j = 0; i < fields.length; i++) { ObjectStreamField f = fields[i]; sigs[j++] = f.getName(); sigs[j++] = f.getSignature(); } - hash = System.identityHashCode(cl) + Arrays.hashCode(sigs); + hash = Arrays.hashCode(sigs); } public int hashCode() { @@ -2331,19 +2158,9 @@ public class ObjectStreamClass implements Serializable { } public boolean equals(Object obj) { - if (obj == this) { - return true; - } - - if (obj instanceof FieldReflectorKey other) { - Class referent; - return (nullClass ? other.nullClass - : ((referent = get()) != null) && - (other.refersTo(referent))) && - Arrays.equals(sigs, other.sigs); - } else { - return false; - } + return obj == this || + obj instanceof FieldReflectorKey other && + Arrays.equals(sigs, other.sigs); } } @@ -2407,68 +2224,6 @@ public class ObjectStreamClass implements Serializable { return matches; } - /** - * Removes from the specified map any keys that have been enqueued - * on the specified reference queue. - */ - static void processQueue(ReferenceQueue> queue, - ConcurrentMap>, ?> map) - { - Reference> ref; - while((ref = queue.poll()) != null) { - map.remove(ref); - } - } - - /** - * Weak key for Class objects. - * - **/ - static class WeakClassKey extends WeakReference> { - /** - * saved value of the referent's identity hash code, to maintain - * a consistent hash code after the referent has been cleared - */ - private final int hash; - - /** - * Create a new WeakClassKey to the given object, registered - * with a queue. - */ - WeakClassKey(Class cl, ReferenceQueue> refQueue) { - super(cl, refQueue); - hash = System.identityHashCode(cl); - } - - /** - * Returns the identity hash code of the original referent. - */ - public int hashCode() { - return hash; - } - - /** - * Returns true if the given object is this identical - * WeakClassKey instance, or, if this object's referent has not - * been cleared, if the given object is another WeakClassKey - * instance with the identical non-null referent as this one. - */ - public boolean equals(Object obj) { - if (obj == this) { - return true; - } - - if (obj instanceof WeakClassKey) { - Class referent = get(); - return (referent != null) && - (((WeakClassKey) obj).refersTo(referent)); - } else { - return false; - } - } - } - /** * A LRA cache of record deserialization constructors. */ diff --git a/src/java.base/share/classes/java/io/ObjectStreamException.java b/src/java.base/share/classes/java/io/ObjectStreamException.java index 779cc0627d3312882ce02c95467face69861a9c9..a7d19cdc1fa6302f3ffa04184f7035ffd31729c2 100644 --- a/src/java.base/share/classes/java/io/ObjectStreamException.java +++ b/src/java.base/share/classes/java/io/ObjectStreamException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 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 @@ -44,10 +44,32 @@ public abstract class ObjectStreamException extends IOException { super(message); } + /** + * Create an ObjectStreamException with the specified message and + * cause. + * + * @param message the detailed message for the exception + * @param cause the cause + * @since 19 + */ + protected ObjectStreamException(String message, Throwable cause) { + super(message, cause); + } + /** * Create an ObjectStreamException. */ protected ObjectStreamException() { super(); } + + /** + * Create an ObjectStreamException with the specified cause. + * + * @param cause the cause + * @since 19 + */ + protected ObjectStreamException(Throwable cause) { + super(cause); + } } diff --git a/src/java.base/share/classes/java/io/OutputStreamWriter.java b/src/java.base/share/classes/java/io/OutputStreamWriter.java index f9acde201b760f5385a2bb4123f7cee3e5fd6b1a..43b0b10e46abfa2f48a3b87754c0b8577fda0b96 100644 --- a/src/java.base/share/classes/java/io/OutputStreamWriter.java +++ b/src/java.base/share/classes/java/io/OutputStreamWriter.java @@ -99,7 +99,9 @@ public class OutputStreamWriter extends Writer { } /** - * Creates an OutputStreamWriter that uses the default character encoding. + * Creates an OutputStreamWriter that uses the default character encoding, or + * where {@code out} is a {@code PrintStream}, the charset used by the print + * stream. * * @param out An OutputStream * @see Charset#defaultCharset() @@ -107,7 +109,7 @@ public class OutputStreamWriter extends Writer { public OutputStreamWriter(OutputStream out) { super(out); se = StreamEncoder.forOutputStreamWriter(out, this, - Charset.defaultCharset()); + out instanceof PrintStream ps ? ps.charset() : Charset.defaultCharset()); } /** diff --git a/src/java.base/share/classes/java/io/PipedInputStream.java b/src/java.base/share/classes/java/io/PipedInputStream.java index 883751660295c2d60f5ba904990b76089cca8450..0d733fa4c748a0a939107f26374db5ffba31f82f 100644 --- a/src/java.base/share/classes/java/io/PipedInputStream.java +++ b/src/java.base/share/classes/java/io/PipedInputStream.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 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 @@ -25,6 +25,8 @@ package java.io; +import java.util.Objects; + /** * A piped input stream should be connected * to a piped output stream; the piped input @@ -220,7 +222,7 @@ public class PipedInputStream extends InputStream { * @param len the maximum number of bytes received * @throws IOException If the pipe is broken, * {@link #connect(java.io.PipedOutputStream) unconnected}, - * closed,or if an I/O error occurs. + * closed, or if an I/O error occurs. */ synchronized void receive(byte[] b, int off, int len) throws IOException { checkStateForReceive(); @@ -367,9 +369,9 @@ public class PipedInputStream extends InputStream { public synchronized int read(byte[] b, int off, int len) throws IOException { if (b == null) { throw new NullPointerException(); - } else if (off < 0 || len < 0 || len > b.length - off) { - throw new IndexOutOfBoundsException(); - } else if (len == 0) { + } + Objects.checkFromIndexSize(off, len, b.length); + if (len == 0) { return 0; } diff --git a/src/java.base/share/classes/java/io/PrintStream.java b/src/java.base/share/classes/java/io/PrintStream.java index acf1a4612823396b649b92a30afbbc312a974052..d18afa97d540f575cb790ed317aeb9cc2713daf4 100644 --- a/src/java.base/share/classes/java/io/PrintStream.java +++ b/src/java.base/share/classes/java/io/PrintStream.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 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 @@ -68,6 +68,7 @@ public class PrintStream extends FilterOutputStream private final boolean autoFlush; private boolean trouble = false; private Formatter formatter; + private final Charset charset; /** * Track both the text- and character-output streams, so that their buffers @@ -108,7 +109,8 @@ public class PrintStream extends FilterOutputStream private PrintStream(boolean autoFlush, OutputStream out) { super(out); this.autoFlush = autoFlush; - this.charOut = new OutputStreamWriter(this); + this.charset = out instanceof PrintStream ps ? ps.charset() : Charset.defaultCharset(); + this.charOut = new OutputStreamWriter(this, charset); this.textOut = new BufferedWriter(charOut); } @@ -124,7 +126,8 @@ public class PrintStream extends FilterOutputStream /** * Creates a new print stream, without automatic line flushing, with the * specified OutputStream. Characters written to the stream are converted - * to bytes using the default charset. + * to bytes using the default charset, or where {@code out} is a + * {@code PrintStream}, the charset used by the print stream. * * @param out The output stream to which values and objects will be * printed @@ -139,7 +142,8 @@ public class PrintStream extends FilterOutputStream /** * Creates a new print stream, with the specified OutputStream and line * flushing. Characters written to the stream are converted to bytes using - * the default charset. + * the default charset, or where {@code out} is a {@code PrintStream}, + * the charset used by the print stream. * * @param out The output stream to which values and objects will be * printed @@ -201,6 +205,7 @@ public class PrintStream extends FilterOutputStream this.autoFlush = autoFlush; this.charOut = new OutputStreamWriter(this, charset); this.textOut = new BufferedWriter(charOut); + this.charset = charset; } /** @@ -459,22 +464,11 @@ public class PrintStream extends FilterOutputStream } /** - * Flushes the stream and checks its error state. The internal error state - * is set to {@code true} when the underlying output stream throws an - * {@code IOException} other than {@code InterruptedIOException}, - * and when the {@code setError} method is invoked. If an operation - * on the underlying output stream throws an - * {@code InterruptedIOException}, then the {@code PrintStream} - * converts the exception back into an interrupt by doing: - *

      {@code
      -     *     Thread.currentThread().interrupt();
      -     * }
      - * or the equivalent. + * Flushes the stream if it's not closed and checks its error state. * * @return {@code true} if and only if this stream has encountered an - * {@code IOException} other than - * {@code InterruptedIOException}, or the - * {@code setError} method has been invoked + * {@code IOException}, or the {@code setError} method has been + * invoked */ public boolean checkError() { if (out != null) @@ -499,7 +493,7 @@ public class PrintStream extends FilterOutputStream } /** - * Clears the internal error state of this stream. + * Clears the error state of this stream. * *

      This method will cause subsequent invocations of {@link * #checkError()} to return {@code false} until another write @@ -1374,4 +1368,12 @@ public class PrintStream extends FilterOutputStream return this; } + /** + * {@return the charset used in this {@code PrintStream} instance} + * + * @since 18 + */ + public Charset charset() { + return charset; + } } diff --git a/src/java.base/share/classes/java/io/PrintWriter.java b/src/java.base/share/classes/java/io/PrintWriter.java index 447769d7fb320196d51fa76dbe7901cce692cdbc..249efc4d99a1297dfb4b47fe7fcbfa5648ef1cdd 100644 --- a/src/java.base/share/classes/java/io/PrintWriter.java +++ b/src/java.base/share/classes/java/io/PrintWriter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 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 @@ -118,7 +118,8 @@ public class PrintWriter extends Writer { * Creates a new PrintWriter, without automatic line flushing, from an * existing OutputStream. This convenience constructor creates the * necessary intermediate OutputStreamWriter, which will convert characters - * into bytes using the default charset. + * into bytes using the default charset, or where {@code out} is a + * {@code PrintStream}, the charset used by the print stream. * * @param out An output stream * @@ -132,8 +133,9 @@ public class PrintWriter extends Writer { /** * Creates a new PrintWriter from an existing OutputStream. This * convenience constructor creates the necessary intermediate - * OutputStreamWriter, which will convert characters into bytes using the - * default charset. + * OutputStreamWriter, which will convert characters into bytes using + * the default charset, or where {@code out} is a {@code PrintStream}, + * the charset used by the print stream. * * @param out An output stream * @param autoFlush A boolean; if true, the {@code println}, @@ -144,7 +146,7 @@ public class PrintWriter extends Writer { * @see Charset#defaultCharset() */ public PrintWriter(OutputStream out, boolean autoFlush) { - this(out, autoFlush, Charset.defaultCharset()); + this(out, autoFlush, out instanceof PrintStream ps ? ps.charset() : Charset.defaultCharset()); } /** @@ -426,9 +428,9 @@ public class PrintWriter extends Writer { /** * Flushes the stream if it's not closed and checks its error state. * - * @return {@code true} if the print stream has encountered an error, - * either on the underlying output stream or during a format - * conversion. + * @return {@code true} if and only if this stream has encountered an + * {@code IOException}, or the {@code setError} method has been + * invoked */ public boolean checkError() { if (out != null) { @@ -443,7 +445,7 @@ public class PrintWriter extends Writer { } /** - * Indicates that an error has occurred. + * Sets the error state of the stream to {@code true}. * *

      This method will cause subsequent invocations of {@link * #checkError()} to return {@code true} until {@link diff --git a/src/java.base/share/classes/java/io/PushbackInputStream.java b/src/java.base/share/classes/java/io/PushbackInputStream.java index 398751cdca0ba58ab8a6bfbaaade4c45139d83e5..9076657db266bdf3da0deca2a8cd7fae4742d929 100644 --- a/src/java.base/share/classes/java/io/PushbackInputStream.java +++ b/src/java.base/share/classes/java/io/PushbackInputStream.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 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 @@ -25,6 +25,8 @@ package java.io; +import java.util.Objects; + /** * A {@code PushbackInputStream} adds * functionality to another input stream, namely @@ -162,9 +164,9 @@ public class PushbackInputStream extends FilterInputStream { ensureOpen(); if (b == null) { throw new NullPointerException(); - } else if (off < 0 || len < 0 || len > b.length - off) { - throw new IndexOutOfBoundsException(); - } else if (len == 0) { + } + Objects.checkFromIndexSize(off, len, b.length); + if (len == 0) { return 0; } diff --git a/src/java.base/share/classes/java/io/SequenceInputStream.java b/src/java.base/share/classes/java/io/SequenceInputStream.java index 89b0507a5520ac15e76fe246ac07bbaec82595d6..5f692ce6c44de3f855d944dccd688ad403069fd2 100644 --- a/src/java.base/share/classes/java/io/SequenceInputStream.java +++ b/src/java.base/share/classes/java/io/SequenceInputStream.java @@ -25,8 +25,8 @@ package java.io; -import java.io.InputStream; import java.util.Enumeration; +import java.util.Objects; import java.util.Vector; /** @@ -189,9 +189,9 @@ public class SequenceInputStream extends InputStream { return -1; } else if (b == null) { throw new NullPointerException(); - } else if (off < 0 || len < 0 || len > b.length - off) { - throw new IndexOutOfBoundsException(); - } else if (len == 0) { + } + Objects.checkFromIndexSize(off, len, b.length); + if (len == 0) { return 0; } do { diff --git a/src/java.base/share/classes/java/io/Serial.java b/src/java.base/share/classes/java/io/Serial.java index 60ba804d3a299bb639b126140a6ae2725a983159..d648f0461593ee18a9531dd08f89ff18559e65d1 100644 --- a/src/java.base/share/classes/java/io/Serial.java +++ b/src/java.base/share/classes/java/io/Serial.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -30,7 +30,8 @@ import java.lang.annotation.*; /** * Indicates that an annotated field or method is part of the {@linkplain * Serializable serialization mechanism} defined by the - * Java Object Serialization Specification. This + * + * Java Object Serialization Specification. This * annotation type is intended to allow compile-time checking of * serialization-related declarations, analogous to the checking * enabled by the {@link java.lang.Override} annotation type to diff --git a/src/java.base/share/classes/java/io/package-info.java b/src/java.base/share/classes/java/io/package-info.java index 1c41f9835e6fc5959ea8f2c8bb07653bda3d7bf4..81f61412eedc50a606582d98fffcc04fc07e884e 100644 --- a/src/java.base/share/classes/java/io/package-info.java +++ b/src/java.base/share/classes/java/io/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -27,10 +27,14 @@ * Provides for system input and output through data streams, * serialization and the file system. * - * Unless otherwise noted, passing a null argument to a constructor or + * Unless otherwise noted, passing a {@code null} argument to a constructor or * method in any class or interface in this package will cause a * {@code NullPointerException} to be thrown. * + * A pathname string passed as a {@code String} argument to a + * constructor or method in any class or interface in this package will be + * interpreted as described in the class specification of {@link File}. + * *

      Object Serialization

      *

      Warning: Deserialization of untrusted data is inherently dangerous * and should be avoided. Untrusted data should be carefully validated according to the diff --git a/src/java.base/share/classes/java/lang/AbstractStringBuilder.java b/src/java.base/share/classes/java/lang/AbstractStringBuilder.java index fce54fcb3d1c6c47d6d293468311178ece75e17b..fed3a6f9178c00a224a199c0e8ec6b5a8d6c36ed 100644 --- a/src/java.base/share/classes/java/lang/AbstractStringBuilder.java +++ b/src/java.base/share/classes/java/lang/AbstractStringBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -56,7 +56,8 @@ import static java.lang.String.checkOffset; * @author Ulf Zibis * @since 1.5 */ -abstract class AbstractStringBuilder implements Appendable, CharSequence { +abstract sealed class AbstractStringBuilder implements Appendable, CharSequence + permits StringBuilder, StringBuffer { /** * The value is used for character storage. */ @@ -430,9 +431,7 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { * {@code beginIndex} is larger than {@code endIndex}. */ public int codePointCount(int beginIndex, int endIndex) { - if (beginIndex < 0 || endIndex > count || beginIndex > endIndex) { - throw new IndexOutOfBoundsException(); - } + Preconditions.checkFromToIndex(beginIndex, endIndex, length(), null); if (isLatin1()) { return endIndex - beginIndex; } diff --git a/src/java.base/share/classes/java/lang/Character.java b/src/java.base/share/classes/java/lang/Character.java index 4a5d9afb5856e415f2cd1bd31a4b10403155057a..d30743b143cb830637aa238df7f19e858cff7a20 100644 --- a/src/java.base/share/classes/java/lang/Character.java +++ b/src/java.base/share/classes/java/lang/Character.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 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 @@ -63,7 +63,7 @@ import static java.lang.constant.ConstantDescs.DEFAULT_NAME; * from the Unicode Consortium at * http://www.unicode.org. *

      - * Character information is based on the Unicode Standard, version 13.0. + * Character information is based on the Unicode Standard, version 14.0. *

      * The Java platform has supported different versions of the Unicode * Standard over time. Upgrades to newer versions of the Unicode Standard @@ -75,6 +75,8 @@ import static java.lang.constant.ConstantDescs.DEFAULT_NAME; * Unicode version * * + * Java SE 19 + * Unicode 14.0 * Java SE 15 * Unicode 13.0 * Java SE 13 @@ -735,10 +737,13 @@ class Character implements java.io.Serializable, Comparable, Constabl */ public static final class UnicodeBlock extends Subset { /** - * 684 - the expected number of entities + * NUM_ENTITIES should match the total number of UnicodeBlocks + * to calculate the initial capacity of the map. It should be + * adjusted whenever the Unicode Character Database is upgraded. + * * 0.75 - the default load factor of HashMap */ - private static final int NUM_ENTITIES = 684; + private static final int NUM_ENTITIES = 737; private static Map map = new HashMap<>((int)(NUM_ENTITIES / 0.75f + 1.0f)); @@ -3424,6 +3429,120 @@ class Character implements java.io.Serializable, Comparable, Constabl "CJK UNIFIED IDEOGRAPHS EXTENSION G", "CJKUNIFIEDIDEOGRAPHSEXTENSIONG"); + /** + * Constant for the "Arabic Extended-B" Unicode + * character block. + * @since 19 + */ + public static final UnicodeBlock ARABIC_EXTENDED_B = + new UnicodeBlock("ARABIC_EXTENDED_B", + "ARABIC EXTENDED-B", + "ARABICEXTENDED-B"); + + /** + * Constant for the "Vithkuqi" Unicode + * character block. + * @since 19 + */ + public static final UnicodeBlock VITHKUQI = + new UnicodeBlock("VITHKUQI"); + + /** + * Constant for the "Latin Extended-F" Unicode + * character block. + * @since 19 + */ + public static final UnicodeBlock LATIN_EXTENDED_F = + new UnicodeBlock("LATIN_EXTENDED_F", + "LATIN EXTENDED-F", + "LATINEXTENDED-F"); + + /** + * Constant for the "Old Uyghur" Unicode + * character block. + * @since 19 + */ + public static final UnicodeBlock OLD_UYGHUR = + new UnicodeBlock("OLD_UYGHUR", + "OLD UYGHUR", + "OLDUYGHUR"); + + /** + * Constant for the "Unified Canadian Aboriginal Syllabics Extended-A" Unicode + * character block. + * @since 19 + */ + public static final UnicodeBlock UNIFIED_CANADIAN_ABORIGINAL_SYLLABICS_EXTENDED_A = + new UnicodeBlock("UNIFIED_CANADIAN_ABORIGINAL_SYLLABICS_EXTENDED_A", + "UNIFIED CANADIAN ABORIGINAL SYLLABICS EXTENDED-A", + "UNIFIEDCANADIANABORIGINALSYLLABICSEXTENDED-A"); + + /** + * Constant for the "Cypro-Minoan" Unicode + * character block. + * @since 19 + */ + public static final UnicodeBlock CYPRO_MINOAN = + new UnicodeBlock("CYPRO_MINOAN", + "CYPRO-MINOAN", + "CYPRO-MINOAN"); + + /** + * Constant for the "Tangsa" Unicode + * character block. + * @since 19 + */ + public static final UnicodeBlock TANGSA = + new UnicodeBlock("TANGSA"); + + /** + * Constant for the "Kana Extended-B" Unicode + * character block. + * @since 19 + */ + public static final UnicodeBlock KANA_EXTENDED_B = + new UnicodeBlock("KANA_EXTENDED_B", + "KANA EXTENDED-B", + "KANAEXTENDED-B"); + + /** + * Constant for the "Znamenny Musical Notation" Unicode + * character block. + * @since 19 + */ + public static final UnicodeBlock ZNAMENNY_MUSICAL_NOTATION = + new UnicodeBlock("ZNAMENNY_MUSICAL_NOTATION", + "ZNAMENNY MUSICAL NOTATION", + "ZNAMENNYMUSICALNOTATION"); + + /** + * Constant for the "Latin Extended-G" Unicode + * character block. + * @since 19 + */ + public static final UnicodeBlock LATIN_EXTENDED_G = + new UnicodeBlock("LATIN_EXTENDED_G", + "LATIN EXTENDED-G", + "LATINEXTENDED-G"); + + /** + * Constant for the "Toto" Unicode + * character block. + * @since 19 + */ + public static final UnicodeBlock TOTO = + new UnicodeBlock("TOTO"); + + /** + * Constant for the "Ethiopic Extended-B" Unicode + * character block. + * @since 19 + */ + public static final UnicodeBlock ETHIOPIC_EXTENDED_B = + new UnicodeBlock("ETHIOPIC_EXTENDED_B", + "ETHIOPIC EXTENDED-B", + "ETHIOPICEXTENDED-B"); + private static final int[] blockStarts = { 0x0000, // 0000..007F; Basic Latin 0x0080, // 0080..00FF; Latin-1 Supplement @@ -3445,7 +3564,7 @@ class Character implements java.io.Serializable, Comparable, Constabl 0x0800, // 0800..083F; Samaritan 0x0840, // 0840..085F; Mandaic 0x0860, // 0860..086F; Syriac Supplement - 0x0870, // unassigned + 0x0870, // 0870..089F; Arabic Extended-B 0x08A0, // 08A0..08FF; Arabic Extended-A 0x0900, // 0900..097F; Devanagari 0x0980, // 0980..09FF; Bengali @@ -3612,9 +3731,11 @@ class Character implements java.io.Serializable, Comparable, Constabl 0x104B0, // 104B0..104FF; Osage 0x10500, // 10500..1052F; Elbasan 0x10530, // 10530..1056F; Caucasian Albanian - 0x10570, // unassigned + 0x10570, // 10570..105BF; Vithkuqi + 0x105C0, // unassigned 0x10600, // 10600..1077F; Linear A - 0x10780, // unassigned + 0x10780, // 10780..107BF; Latin Extended-F + 0x107C0, // unassigned 0x10800, // 10800..1083F; Cypriot Syllabary 0x10840, // 10840..1085F; Imperial Aramaic 0x10860, // 10860..1087F; Palmyrene @@ -3646,7 +3767,7 @@ class Character implements java.io.Serializable, Comparable, Constabl 0x10EC0, // unassigned 0x10F00, // 10F00..10F2F; Old Sogdian 0x10F30, // 10F30..10F6F; Sogdian - 0x10F70, // unassigned + 0x10F70, // 10F70..10FAF; Old Uyghur 0x10FB0, // 10FB0..10FDF; Chorasmian 0x10FE0, // 10FE0..10FFF; Elymaic 0x11000, // 11000..1107F; Brahmi @@ -3670,8 +3791,8 @@ class Character implements java.io.Serializable, Comparable, Constabl 0x11660, // 11660..1167F; Mongolian Supplement 0x11680, // 11680..116CF; Takri 0x116D0, // unassigned - 0x11700, // 11700..1173F; Ahom - 0x11740, // unassigned + 0x11700, // 11700..1174F; Ahom + 0x11750, // unassigned 0x11800, // 11800..1184F; Dogra 0x11850, // unassigned 0x118A0, // 118A0..118FF; Warang Citi @@ -3680,7 +3801,7 @@ class Character implements java.io.Serializable, Comparable, Constabl 0x119A0, // 119A0..119FF; Nandinagari 0x11A00, // 11A00..11A4F; Zanabazar Square 0x11A50, // 11A50..11AAF; Soyombo - 0x11AB0, // unassigned + 0x11AB0, // 11AB0..11ABF; Unified Canadian Aboriginal Syllabics Extended-A 0x11AC0, // 11AC0..11AFF; Pau Cin Hau 0x11B00, // unassigned 0x11C00, // 11C00..11C6F; Bhaiksuki @@ -3697,6 +3818,7 @@ class Character implements java.io.Serializable, Comparable, Constabl 0x12400, // 12400..1247F; Cuneiform Numbers and Punctuation 0x12480, // 12480..1254F; Early Dynastic Cuneiform 0x12550, // unassigned + 0x12F90, // 12F90..12FFF; Cypro-Minoan 0x13000, // 13000..1342F; Egyptian Hieroglyphs 0x13430, // 13430..1343F; Egyptian Hieroglyph Format Controls 0x13440, // unassigned @@ -3704,7 +3826,7 @@ class Character implements java.io.Serializable, Comparable, Constabl 0x14680, // unassigned 0x16800, // 16800..16A3F; Bamum Supplement 0x16A40, // 16A40..16A6F; Mro - 0x16A70, // unassigned + 0x16A70, // 16A70..16ACF; Tangsa 0x16AD0, // 16AD0..16AFF; Bassa Vah 0x16B00, // 16B00..16B8F; Pahawh Hmong 0x16B90, // unassigned @@ -3716,8 +3838,9 @@ class Character implements java.io.Serializable, Comparable, Constabl 0x17000, // 17000..187FF; Tangut 0x18800, // 18800..18AFF; Tangut Components 0x18B00, // 18B00..18CFF; Khitan Small Script - 0x18D00, // 18D00..18D8F; Tangut Supplement - 0x18D90, // unassigned + 0x18D00, // 18D00..18D7F; Tangut Supplement + 0x18D80, // unassigned + 0x1AFF0, // 1AFF0..1AFFF; Kana Extended-B 0x1B000, // 1B000..1B0FF; Kana Supplement 0x1B100, // 1B100..1B12F; Kana Extended-A 0x1B130, // 1B130..1B16F; Small Kana Extension @@ -3726,6 +3849,8 @@ class Character implements java.io.Serializable, Comparable, Constabl 0x1BC00, // 1BC00..1BC9F; Duployan 0x1BCA0, // 1BCA0..1BCAF; Shorthand Format Controls 0x1BCB0, // unassigned + 0x1CF00, // 1CF00..1CFCF; Znamenny Musical Notation + 0x1CFD0, // unassigned 0x1D000, // 1D000..1D0FF; Byzantine Musical Symbols 0x1D100, // 1D100..1D1FF; Musical Symbols 0x1D200, // 1D200..1D24F; Ancient Greek Musical Notation @@ -3737,12 +3862,15 @@ class Character implements java.io.Serializable, Comparable, Constabl 0x1D400, // 1D400..1D7FF; Mathematical Alphanumeric Symbols 0x1D800, // 1D800..1DAAF; Sutton SignWriting 0x1DAB0, // unassigned + 0x1DF00, // 1DF00..1DFFF; Latin Extended-G 0x1E000, // 1E000..1E02F; Glagolitic Supplement 0x1E030, // unassigned 0x1E100, // 1E100..1E14F; Nyiakeng Puachue Hmong 0x1E150, // unassigned + 0x1E290, // 1E290..1E2BF; Toto 0x1E2C0, // 1E2C0..1E2FF; Wancho 0x1E300, // unassigned + 0x1E7E0, // 1E7E0..1E7FF; Ethiopic Extended-B 0x1E800, // 1E800..1E8DF; Mende Kikakui 0x1E8E0, // unassigned 0x1E900, // 1E900..1E95F; Adlam @@ -3810,7 +3938,7 @@ class Character implements java.io.Serializable, Comparable, Constabl SAMARITAN, MANDAIC, SYRIAC_SUPPLEMENT, - null, + ARABIC_EXTENDED_B, ARABIC_EXTENDED_A, DEVANAGARI, BENGALI, @@ -3977,8 +4105,10 @@ class Character implements java.io.Serializable, Comparable, Constabl OSAGE, ELBASAN, CAUCASIAN_ALBANIAN, + VITHKUQI, null, LINEAR_A, + LATIN_EXTENDED_F, null, CYPRIOT_SYLLABARY, IMPERIAL_ARAMAIC, @@ -4011,7 +4141,7 @@ class Character implements java.io.Serializable, Comparable, Constabl null, OLD_SOGDIAN, SOGDIAN, - null, + OLD_UYGHUR, CHORASMIAN, ELYMAIC, BRAHMI, @@ -4045,7 +4175,7 @@ class Character implements java.io.Serializable, Comparable, Constabl NANDINAGARI, ZANABAZAR_SQUARE, SOYOMBO, - null, + UNIFIED_CANADIAN_ABORIGINAL_SYLLABICS_EXTENDED_A, PAU_CIN_HAU, null, BHAIKSUKI, @@ -4062,6 +4192,7 @@ class Character implements java.io.Serializable, Comparable, Constabl CUNEIFORM_NUMBERS_AND_PUNCTUATION, EARLY_DYNASTIC_CUNEIFORM, null, + CYPRO_MINOAN, EGYPTIAN_HIEROGLYPHS, EGYPTIAN_HIEROGLYPH_FORMAT_CONTROLS, null, @@ -4069,7 +4200,7 @@ class Character implements java.io.Serializable, Comparable, Constabl null, BAMUM_SUPPLEMENT, MRO, - null, + TANGSA, BASSA_VAH, PAHAWH_HMONG, null, @@ -4083,6 +4214,7 @@ class Character implements java.io.Serializable, Comparable, Constabl KHITAN_SMALL_SCRIPT, TANGUT_SUPPLEMENT, null, + KANA_EXTENDED_B, KANA_SUPPLEMENT, KANA_EXTENDED_A, SMALL_KANA_EXTENSION, @@ -4091,6 +4223,8 @@ class Character implements java.io.Serializable, Comparable, Constabl DUPLOYAN, SHORTHAND_FORMAT_CONTROLS, null, + ZNAMENNY_MUSICAL_NOTATION, + null, BYZANTINE_MUSICAL_SYMBOLS, MUSICAL_SYMBOLS, ANCIENT_GREEK_MUSICAL_NOTATION, @@ -4102,12 +4236,15 @@ class Character implements java.io.Serializable, Comparable, Constabl MATHEMATICAL_ALPHANUMERIC_SYMBOLS, SUTTON_SIGNWRITING, null, + LATIN_EXTENDED_G, GLAGOLITIC_SUPPLEMENT, null, NYIAKENG_PUACHUE_HMONG, null, + TOTO, WANCHO, null, + ETHIOPIC_EXTENDED_B, MENDE_KIKAKUI, null, ADLAM, @@ -4217,7 +4354,7 @@ class Character implements java.io.Serializable, Comparable, Constabl /** * Returns the UnicodeBlock with the given name. Block * names are determined by The Unicode Standard. The file - * {@code Blocks-.txt} defines blocks for a particular + * {@code Blocks.txt} defines blocks for a particular * version of the standard. The {@link Character} class specifies * the version of the standard that it supports. *

      @@ -5116,6 +5253,36 @@ class Character implements java.io.Serializable, Comparable, Constabl */ KHITAN_SMALL_SCRIPT, + /** + * Unicode script "Vithkuqi". + * @since 19 + */ + VITHKUQI, + + /** + * Unicode script "Old Uyghur". + * @since 19 + */ + OLD_UYGHUR, + + /** + * Unicode script "Cypro Minoan". + * @since 19 + */ + CYPRO_MINOAN, + + /** + * Unicode script "Tangsa". + * @since 19 + */ + TANGSA, + + /** + * Unicode script "Toto". + * @since 19 + */ + TOTO, + /** * Unicode script "Unknown". */ @@ -5185,9 +5352,7 @@ class Character implements java.io.Serializable, Comparable, Constabl 0x060C, // 060C ; COMMON 0x060D, // 060D..061A; ARABIC 0x061B, // 061B ; COMMON - 0x061C, // 061C ; ARABIC - 0x061D, // 061D ; UNKNOWN - 0x061E, // 061E ; ARABIC + 0x061C, // 061C..061E; ARABIC 0x061F, // 061F ; COMMON 0x0620, // 0620..063F; ARABIC 0x0640, // 0640 ; COMMON @@ -5218,12 +5383,12 @@ class Character implements java.io.Serializable, Comparable, Constabl 0x085E, // 085E ; MANDAIC 0x085F, // 085F ; UNKNOWN 0x0860, // 0860..086A; SYRIAC - 0x086B, // 086B..089F; UNKNOWN - 0x08A0, // 08A0..08B4; ARABIC - 0x08B5, // 08B5 ; UNKNOWN - 0x08B6, // 08B6..08C7; ARABIC - 0x08C8, // 08C8..08D2; UNKNOWN - 0x08D3, // 08D3..08E1; ARABIC + 0x086B, // 086B..086F; UNKNOWN + 0x0870, // 0870..088E; ARABIC + 0x088F, // 088F ; UNKNOWN + 0x0890, // 0890..0891; ARABIC + 0x0892, // 0892..0897; UNKNOWN + 0x0898, // 0898..08E1; ARABIC 0x08E2, // 08E2 ; COMMON 0x08E3, // 08E3..08FF; ARABIC 0x0900, // 0900..0950; DEVANAGARI @@ -5386,8 +5551,8 @@ class Character implements java.io.Serializable, Comparable, Constabl 0x0C12, // 0C12..0C28; TELUGU 0x0C29, // 0C29 ; UNKNOWN 0x0C2A, // 0C2A..0C39; TELUGU - 0x0C3A, // 0C3A..0C3C; UNKNOWN - 0x0C3D, // 0C3D..0C44; TELUGU + 0x0C3A, // 0C3A..0C3B; UNKNOWN + 0x0C3C, // 0C3C..0C44; TELUGU 0x0C45, // 0C45 ; UNKNOWN 0x0C46, // 0C46..0C48; TELUGU 0x0C49, // 0C49 ; UNKNOWN @@ -5396,7 +5561,9 @@ class Character implements java.io.Serializable, Comparable, Constabl 0x0C55, // 0C55..0C56; TELUGU 0x0C57, // 0C57 ; UNKNOWN 0x0C58, // 0C58..0C5A; TELUGU - 0x0C5B, // 0C5B..0C5F; UNKNOWN + 0x0C5B, // 0C5B..0C5C; UNKNOWN + 0x0C5D, // 0C5D ; TELUGU + 0x0C5E, // 0C5E..0C5F; UNKNOWN 0x0C60, // 0C60..0C63; TELUGU 0x0C64, // 0C64..0C65; UNKNOWN 0x0C66, // 0C66..0C6F; TELUGU @@ -5419,8 +5586,8 @@ class Character implements java.io.Serializable, Comparable, Constabl 0x0CCA, // 0CCA..0CCD; KANNADA 0x0CCE, // 0CCE..0CD4; UNKNOWN 0x0CD5, // 0CD5..0CD6; KANNADA - 0x0CD7, // 0CD7..0CDD; UNKNOWN - 0x0CDE, // 0CDE ; KANNADA + 0x0CD7, // 0CD7..0CDC; UNKNOWN + 0x0CDD, // 0CDD..0CDE; KANNADA 0x0CDF, // 0CDF ; UNKNOWN 0x0CE0, // 0CE0..0CE3; KANNADA 0x0CE4, // 0CE4..0CE5; UNKNOWN @@ -5565,10 +5732,9 @@ class Character implements java.io.Serializable, Comparable, Constabl 0x16EB, // 16EB..16ED; COMMON 0x16EE, // 16EE..16F8; RUNIC 0x16F9, // 16F9..16FF; UNKNOWN - 0x1700, // 1700..170C; TAGALOG - 0x170D, // 170D ; UNKNOWN - 0x170E, // 170E..1714; TAGALOG - 0x1715, // 1715..171F; UNKNOWN + 0x1700, // 1700..1715; TAGALOG + 0x1716, // 1716..171E; UNKNOWN + 0x171F, // 171F ; TAGALOG 0x1720, // 1720..1734; HANUNOO 0x1735, // 1735..1736; COMMON 0x1737, // 1737..173F; UNKNOWN @@ -5590,9 +5756,7 @@ class Character implements java.io.Serializable, Comparable, Constabl 0x1802, // 1802..1803; COMMON 0x1804, // 1804 ; MONGOLIAN 0x1805, // 1805 ; COMMON - 0x1806, // 1806..180E; MONGOLIAN - 0x180F, // 180F ; UNKNOWN - 0x1810, // 1810..1819; MONGOLIAN + 0x1806, // 1806..1819; MONGOLIAN 0x181A, // 181A..181F; UNKNOWN 0x1820, // 1820..1878; MONGOLIAN 0x1879, // 1879..187F; UNKNOWN @@ -5634,12 +5798,12 @@ class Character implements java.io.Serializable, Comparable, Constabl 0x1A9A, // 1A9A..1A9F; UNKNOWN 0x1AA0, // 1AA0..1AAD; TAI_THAM 0x1AAE, // 1AAE..1AAF; UNKNOWN - 0x1AB0, // 1AB0..1AC0; INHERITED - 0x1AC1, // 1AC1..1AFF; UNKNOWN - 0x1B00, // 1B00..1B4B; BALINESE - 0x1B4C, // 1B4C..1B4F; UNKNOWN - 0x1B50, // 1B50..1B7C; BALINESE - 0x1B7D, // 1B7D..1B7F; UNKNOWN + 0x1AB0, // 1AB0..1ACE; INHERITED + 0x1ACF, // 1ACF..1AFF; UNKNOWN + 0x1B00, // 1B00..1B4C; BALINESE + 0x1B4D, // 1B4D..1B4F; UNKNOWN + 0x1B50, // 1B50..1B7E; BALINESE + 0x1B7F, // 1B7F ; UNKNOWN 0x1B80, // 1B80..1BBF; SUNDANESE 0x1BC0, // 1BC0..1BF3; BATAK 0x1BF4, // 1BF4..1BFB; UNKNOWN @@ -5681,9 +5845,7 @@ class Character implements java.io.Serializable, Comparable, Constabl 0x1D78, // 1D78 ; CYRILLIC 0x1D79, // 1D79..1DBE; LATIN 0x1DBF, // 1DBF ; GREEK - 0x1DC0, // 1DC0..1DF9; INHERITED - 0x1DFA, // 1DFA ; UNKNOWN - 0x1DFB, // 1DFB..1DFF; INHERITED + 0x1DC0, // 1DC0..1DFF; INHERITED 0x1E00, // 1E00..1EFF; LATIN 0x1F00, // 1F00..1F15; GREEK 0x1F16, // 1F16..1F17; UNKNOWN @@ -5730,8 +5892,8 @@ class Character implements java.io.Serializable, Comparable, Constabl 0x208F, // 208F ; UNKNOWN 0x2090, // 2090..209C; LATIN 0x209D, // 209D..209F; UNKNOWN - 0x20A0, // 20A0..20BF; COMMON - 0x20C0, // 20C0..20CF; UNKNOWN + 0x20A0, // 20A0..20C0; COMMON + 0x20C1, // 20C1..20CF; UNKNOWN 0x20D0, // 20D0..20F0; INHERITED 0x20F1, // 20F1..20FF; UNKNOWN 0x2100, // 2100..2125; COMMON @@ -5757,10 +5919,7 @@ class Character implements java.io.Serializable, Comparable, Constabl 0x2B76, // 2B76..2B95; COMMON 0x2B96, // 2B96 ; UNKNOWN 0x2B97, // 2B97..2BFF; COMMON - 0x2C00, // 2C00..2C2E; GLAGOLITIC - 0x2C2F, // 2C2F ; UNKNOWN - 0x2C30, // 2C30..2C5E; GLAGOLITIC - 0x2C5F, // 2C5F ; UNKNOWN + 0x2C00, // 2C00..2C5F; GLAGOLITIC 0x2C60, // 2C60..2C7F; LATIN 0x2C80, // 2C80..2CF3; COPTIC 0x2CF4, // 2CF4..2CF8; UNKNOWN @@ -5795,8 +5954,8 @@ class Character implements java.io.Serializable, Comparable, Constabl 0x2DD8, // 2DD8..2DDE; ETHIOPIC 0x2DDF, // 2DDF ; UNKNOWN 0x2DE0, // 2DE0..2DFF; CYRILLIC - 0x2E00, // 2E00..2E52; COMMON - 0x2E53, // 2E53..2E7F; UNKNOWN + 0x2E00, // 2E00..2E5D; COMMON + 0x2E5E, // 2E5E..2E7F; UNKNOWN 0x2E80, // 2E80..2E99; HAN 0x2E9A, // 2E9A ; UNKNOWN 0x2E9B, // 2E9B..2EF3; HAN @@ -5847,8 +6006,7 @@ class Character implements java.io.Serializable, Comparable, Constabl 0x3358, // 3358..33FF; COMMON 0x3400, // 3400..4DBF; HAN 0x4DC0, // 4DC0..4DFF; COMMON - 0x4E00, // 4E00..9FFC; HAN - 0x9FFD, // 9FFD..9FFF; UNKNOWN + 0x4E00, // 4E00..9FFF; HAN 0xA000, // A000..A48C; YI 0xA48D, // A48D..A48F; UNKNOWN 0xA490, // A490..A4C6; YI @@ -5862,11 +6020,15 @@ class Character implements java.io.Serializable, Comparable, Constabl 0xA700, // A700..A721; COMMON 0xA722, // A722..A787; LATIN 0xA788, // A788..A78A; COMMON - 0xA78B, // A78B..A7BF; LATIN - 0xA7C0, // A7C0..A7C1; UNKNOWN - 0xA7C2, // A7C2..A7CA; LATIN - 0xA7CB, // A7CB..A7F4; UNKNOWN - 0xA7F5, // A7F5..A7FF; LATIN + 0xA78B, // A78B..A7CA; LATIN + 0xA7CB, // A7CB..A7CF; UNKNOWN + 0xA7D0, // A7D0..A7D1; LATIN + 0xA7D2, // A7D2 ; UNKNOWN + 0xA7D3, // A7D3 ; LATIN + 0xA7D4, // A7D4 ; UNKNOWN + 0xA7D5, // A7D5..A7D9; LATIN + 0xA7DA, // A7DA..A7F1; UNKNOWN + 0xA7F2, // A7F2..A7FF; LATIN 0xA800, // A800..A82C; SYLOTI_NAGRI 0xA82D, // A82D..A82F; UNKNOWN 0xA830, // A830..A839; COMMON @@ -5954,17 +6116,17 @@ class Character implements java.io.Serializable, Comparable, Constabl 0xFB43, // FB43..FB44; HEBREW 0xFB45, // FB45 ; UNKNOWN 0xFB46, // FB46..FB4F; HEBREW - 0xFB50, // FB50..FBC1; ARABIC - 0xFBC2, // FBC2..FBD2; UNKNOWN + 0xFB50, // FB50..FBC2; ARABIC + 0xFBC3, // FBC3..FBD2; UNKNOWN 0xFBD3, // FBD3..FD3D; ARABIC 0xFD3E, // FD3E..FD3F; COMMON - 0xFD40, // FD40..FD4F; UNKNOWN - 0xFD50, // FD50..FD8F; ARABIC + 0xFD40, // FD40..FD8F; ARABIC 0xFD90, // FD90..FD91; UNKNOWN 0xFD92, // FD92..FDC7; ARABIC - 0xFDC8, // FDC8..FDEF; UNKNOWN - 0xFDF0, // FDF0..FDFD; ARABIC - 0xFDFE, // FDFE..FDFF; UNKNOWN + 0xFDC8, // FDC8..FDCE; UNKNOWN + 0xFDCF, // FDCF ; ARABIC + 0xFDD0, // FDD0..FDEF; UNKNOWN + 0xFDF0, // FDF0..FDFF; ARABIC 0xFE00, // FE00..FE0F; INHERITED 0xFE10, // FE10..FE19; COMMON 0xFE1A, // FE1A..FE1F; UNKNOWN @@ -6071,13 +6233,34 @@ class Character implements java.io.Serializable, Comparable, Constabl 0x10530, // 10530..10563; CAUCASIAN_ALBANIAN 0x10564, // 10564..1056E; UNKNOWN 0x1056F, // 1056F ; CAUCASIAN_ALBANIAN - 0x10570, // 10570..105FF; UNKNOWN + 0x10570, // 10570..1057A; VITHKUQI + 0x1057B, // 1057B ; UNKNOWN + 0x1057C, // 1057C..1058A; VITHKUQI + 0x1058B, // 1058B ; UNKNOWN + 0x1058C, // 1058C..10592; VITHKUQI + 0x10593, // 10593 ; UNKNOWN + 0x10594, // 10594..10595; VITHKUQI + 0x10596, // 10596 ; UNKNOWN + 0x10597, // 10597..105A1; VITHKUQI + 0x105A2, // 105A2 ; UNKNOWN + 0x105A3, // 105A3..105B1; VITHKUQI + 0x105B2, // 105B2 ; UNKNOWN + 0x105B3, // 105B3..105B9; VITHKUQI + 0x105BA, // 105BA ; UNKNOWN + 0x105BB, // 105BB..105BC; VITHKUQI + 0x105BD, // 105BD..105FF; UNKNOWN 0x10600, // 10600..10736; LINEAR_A 0x10737, // 10737..1073F; UNKNOWN 0x10740, // 10740..10755; LINEAR_A 0x10756, // 10756..1075F; UNKNOWN 0x10760, // 10760..10767; LINEAR_A - 0x10768, // 10768..107FF; UNKNOWN + 0x10768, // 10768..1077F; UNKNOWN + 0x10780, // 10780..10785; LATIN + 0x10786, // 10786 ; UNKNOWN + 0x10787, // 10787..107B0; LATIN + 0x107B1, // 107B1 ; UNKNOWN + 0x107B2, // 107B2..107BA; LATIN + 0x107BB, // 107BB..107FF; UNKNOWN 0x10800, // 10800..10805; CYPRIOT 0x10806, // 10806..10807; UNKNOWN 0x10808, // 10808 ; CYPRIOT @@ -6175,18 +6358,20 @@ class Character implements java.io.Serializable, Comparable, Constabl 0x10F00, // 10F00..10F27; OLD_SOGDIAN 0x10F28, // 10F28..10F2F; UNKNOWN 0x10F30, // 10F30..10F59; SOGDIAN - 0x10F5A, // 10F5A..10FAF; UNKNOWN + 0x10F5A, // 10F5A..10F6F; UNKNOWN + 0x10F70, // 10F70..10F89; OLD_UYGHUR + 0x10F8A, // 10F8A..10FAF; UNKNOWN 0x10FB0, // 10FB0..10FCB; CHORASMIAN 0x10FCC, // 10FCC..10FDF; UNKNOWN 0x10FE0, // 10FE0..10FF6; ELYMAIC 0x10FF7, // 10FF7..10FFF; UNKNOWN 0x11000, // 11000..1104D; BRAHMI 0x1104E, // 1104E..11051; UNKNOWN - 0x11052, // 11052..1106F; BRAHMI - 0x11070, // 11070..1107E; UNKNOWN + 0x11052, // 11052..11075; BRAHMI + 0x11076, // 11076..1107E; UNKNOWN 0x1107F, // 1107F ; BRAHMI - 0x11080, // 11080..110C1; KAITHI - 0x110C2, // 110C2..110CC; UNKNOWN + 0x11080, // 11080..110C2; KAITHI + 0x110C3, // 110C3..110CC; UNKNOWN 0x110CD, // 110CD ; KAITHI 0x110CE, // 110CE..110CF; UNKNOWN 0x110D0, // 110D0..110E8; SORA_SOMPENG @@ -6270,16 +6455,16 @@ class Character implements java.io.Serializable, Comparable, Constabl 0x1165A, // 1165A..1165F; UNKNOWN 0x11660, // 11660..1166C; MONGOLIAN 0x1166D, // 1166D..1167F; UNKNOWN - 0x11680, // 11680..116B8; TAKRI - 0x116B9, // 116B9..116BF; UNKNOWN + 0x11680, // 11680..116B9; TAKRI + 0x116BA, // 116BA..116BF; UNKNOWN 0x116C0, // 116C0..116C9; TAKRI 0x116CA, // 116CA..116FF; UNKNOWN 0x11700, // 11700..1171A; AHOM 0x1171B, // 1171B..1171C; UNKNOWN 0x1171D, // 1171D..1172B; AHOM 0x1172C, // 1172C..1172F; UNKNOWN - 0x11730, // 11730..1173F; AHOM - 0x11740, // 11740..117FF; UNKNOWN + 0x11730, // 11730..11746; AHOM + 0x11747, // 11747..117FF; UNKNOWN 0x11800, // 11800..1183B; DOGRA 0x1183C, // 1183C..1189F; UNKNOWN 0x118A0, // 118A0..118F2; WARANG_CITI @@ -6310,7 +6495,8 @@ class Character implements java.io.Serializable, Comparable, Constabl 0x11A00, // 11A00..11A47; ZANABAZAR_SQUARE 0x11A48, // 11A48..11A4F; UNKNOWN 0x11A50, // 11A50..11AA2; SOYOMBO - 0x11AA3, // 11AA3..11ABF; UNKNOWN + 0x11AA3, // 11AA3..11AAF; UNKNOWN + 0x11AB0, // 11AB0..11ABF; CANADIAN_ABORIGINAL 0x11AC0, // 11AC0..11AF8; PAU_CIN_HAU 0x11AF9, // 11AF9..11BFF; UNKNOWN 0x11C00, // 11C00..11C08; BHAIKSUKI @@ -6367,7 +6553,9 @@ class Character implements java.io.Serializable, Comparable, Constabl 0x12470, // 12470..12474; CUNEIFORM 0x12475, // 12475..1247F; UNKNOWN 0x12480, // 12480..12543; CUNEIFORM - 0x12544, // 12544..12FFF; UNKNOWN + 0x12544, // 12544..12F8F; UNKNOWN + 0x12F90, // 12F90..12FF2; CYPRO_MINOAN + 0x12FF3, // 12FF3..12FFF; UNKNOWN 0x13000, // 13000..1342E; EGYPTIAN_HIEROGLYPHS 0x1342F, // 1342F ; UNKNOWN 0x13430, // 13430..13438; EGYPTIAN_HIEROGLYPHS @@ -6381,7 +6569,10 @@ class Character implements java.io.Serializable, Comparable, Constabl 0x16A60, // 16A60..16A69; MRO 0x16A6A, // 16A6A..16A6D; UNKNOWN 0x16A6E, // 16A6E..16A6F; MRO - 0x16A70, // 16A70..16ACF; UNKNOWN + 0x16A70, // 16A70..16ABE; TANGSA + 0x16ABF, // 16ABF ; UNKNOWN + 0x16AC0, // 16AC0..16AC9; TANGSA + 0x16ACA, // 16ACA..16ACF; UNKNOWN 0x16AD0, // 16AD0..16AED; BASSA_VAH 0x16AEE, // 16AEE..16AEF; UNKNOWN 0x16AF0, // 16AF0..16AF5; BASSA_VAH @@ -6406,7 +6597,7 @@ class Character implements java.io.Serializable, Comparable, Constabl 0x16FA0, // 16FA0..16FDF; UNKNOWN 0x16FE0, // 16FE0 ; TANGUT 0x16FE1, // 16FE1 ; NUSHU - 0x16FE2, // 16FE2..16FE3; COMMON + 0x16FE2, // 16FE2..16FE3; HAN 0x16FE4, // 16FE4 ; KHITAN_SMALL_SCRIPT 0x16FE5, // 16FE5..16FEF; UNKNOWN 0x16FF0, // 16FF0..16FF1; HAN @@ -6417,10 +6608,17 @@ class Character implements java.io.Serializable, Comparable, Constabl 0x18B00, // 18B00..18CD5; KHITAN_SMALL_SCRIPT 0x18CD6, // 18CD6..18CFF; UNKNOWN 0x18D00, // 18D00..18D08; TANGUT - 0x18D09, // 18D09..1AFFF; UNKNOWN + 0x18D09, // 18D09..1AFEF; UNKNOWN + 0x1AFF0, // 1AFF0..1AFF3; KATAKANA + 0x1AFF4, // 1AFF4 ; UNKNOWN + 0x1AFF5, // 1AFF5..1AFFB; KATAKANA + 0x1AFFC, // 1AFFC ; UNKNOWN + 0x1AFFD, // 1AFFD..1AFFE; KATAKANA + 0x1AFFF, // 1AFFF ; UNKNOWN 0x1B000, // 1B000 ; KATAKANA - 0x1B001, // 1B001..1B11E; HIRAGANA - 0x1B11F, // 1B11F..1B14F; UNKNOWN + 0x1B001, // 1B001..1B11F; HIRAGANA + 0x1B120, // 1B120..1B122; KATAKANA + 0x1B123, // 1B123..1B14F; UNKNOWN 0x1B150, // 1B150..1B152; HIRAGANA 0x1B153, // 1B153..1B163; UNKNOWN 0x1B164, // 1B164..1B167; KATAKANA @@ -6437,7 +6635,13 @@ class Character implements java.io.Serializable, Comparable, Constabl 0x1BC9A, // 1BC9A..1BC9B; UNKNOWN 0x1BC9C, // 1BC9C..1BC9F; DUPLOYAN 0x1BCA0, // 1BCA0..1BCA3; COMMON - 0x1BCA4, // 1BCA4..1CFFF; UNKNOWN + 0x1BCA4, // 1BCA4..1CEFF; UNKNOWN + 0x1CF00, // 1CF00..1CF2D; INHERITED + 0x1CF2E, // 1CF2E..1CF2F; UNKNOWN + 0x1CF30, // 1CF30..1CF46; INHERITED + 0x1CF47, // 1CF47..1CF4F; UNKNOWN + 0x1CF50, // 1CF50..1CFC3; COMMON + 0x1CFC4, // 1CFC4..1CFFF; UNKNOWN 0x1D000, // 1D000..1D0F5; COMMON 0x1D0F6, // 1D0F6..1D0FF; UNKNOWN 0x1D100, // 1D100..1D126; COMMON @@ -6450,8 +6654,8 @@ class Character implements java.io.Serializable, Comparable, Constabl 0x1D185, // 1D185..1D18B; INHERITED 0x1D18C, // 1D18C..1D1A9; COMMON 0x1D1AA, // 1D1AA..1D1AD; INHERITED - 0x1D1AE, // 1D1AE..1D1E8; COMMON - 0x1D1E9, // 1D1E9..1D1FF; UNKNOWN + 0x1D1AE, // 1D1AE..1D1EA; COMMON + 0x1D1EB, // 1D1EB..1D1FF; UNKNOWN 0x1D200, // 1D200..1D245; GREEK 0x1D246, // 1D246..1D2DF; UNKNOWN 0x1D2E0, // 1D2E0..1D2F3; COMMON @@ -6506,7 +6710,9 @@ class Character implements java.io.Serializable, Comparable, Constabl 0x1DA9B, // 1DA9B..1DA9F; SIGNWRITING 0x1DAA0, // 1DAA0 ; UNKNOWN 0x1DAA1, // 1DAA1..1DAAF; SIGNWRITING - 0x1DAB0, // 1DAB0..1DFFF; UNKNOWN + 0x1DAB0, // 1DAB0..1DEFF; UNKNOWN + 0x1DF00, // 1DF00..1DF1E; LATIN + 0x1DF1F, // 1DF1F..1DFFF; UNKNOWN 0x1E000, // 1E000..1E006; GLAGOLITIC 0x1E007, // 1E007 ; UNKNOWN 0x1E008, // 1E008..1E018; GLAGOLITIC @@ -6524,11 +6730,21 @@ class Character implements java.io.Serializable, Comparable, Constabl 0x1E140, // 1E140..1E149; NYIAKENG_PUACHUE_HMONG 0x1E14A, // 1E14A..1E14D; UNKNOWN 0x1E14E, // 1E14E..1E14F; NYIAKENG_PUACHUE_HMONG - 0x1E150, // 1E150..1E2BF; UNKNOWN + 0x1E150, // 1E150..1E28F; UNKNOWN + 0x1E290, // 1E290..1E2AE; TOTO + 0x1E2AF, // 1E2AF..1E2BF; UNKNOWN 0x1E2C0, // 1E2C0..1E2F9; WANCHO 0x1E2FA, // 1E2FA..1E2FE; UNKNOWN 0x1E2FF, // 1E2FF ; WANCHO - 0x1E300, // 1E300..1E7FF; UNKNOWN + 0x1E300, // 1E300..1E7DF; UNKNOWN + 0x1E7E0, // 1E7E0..1E7E6; ETHIOPIC + 0x1E7E7, // 1E7E7 ; UNKNOWN + 0x1E7E8, // 1E7E8..1E7EB; ETHIOPIC + 0x1E7EC, // 1E7EC ; UNKNOWN + 0x1E7ED, // 1E7ED..1E7EE; ETHIOPIC + 0x1E7EF, // 1E7EF ; UNKNOWN + 0x1E7F0, // 1E7F0..1E7FE; ETHIOPIC + 0x1E7FF, // 1E7FF ; UNKNOWN 0x1E800, // 1E800..1E8C4; MENDE_KIKAKUI 0x1E8C5, // 1E8C5..1E8C6; UNKNOWN 0x1E8C7, // 1E8C7..1E8D6; MENDE_KIKAKUI @@ -6638,8 +6854,8 @@ class Character implements java.io.Serializable, Comparable, Constabl 0x1F260, // 1F260..1F265; COMMON 0x1F266, // 1F266..1F2FF; UNKNOWN 0x1F300, // 1F300..1F6D7; COMMON - 0x1F6D8, // 1F6D8..1F6DF; UNKNOWN - 0x1F6E0, // 1F6E0..1F6EC; COMMON + 0x1F6D8, // 1F6D8..1F6DC; UNKNOWN + 0x1F6DD, // 1F6DD..1F6EC; COMMON 0x1F6ED, // 1F6ED..1F6EF; UNKNOWN 0x1F6F0, // 1F6F0..1F6FC; COMMON 0x1F6FD, // 1F6FD..1F6FF; UNKNOWN @@ -6648,7 +6864,9 @@ class Character implements java.io.Serializable, Comparable, Constabl 0x1F780, // 1F780..1F7D8; COMMON 0x1F7D9, // 1F7D9..1F7DF; UNKNOWN 0x1F7E0, // 1F7E0..1F7EB; COMMON - 0x1F7EC, // 1F7EC..1F7FF; UNKNOWN + 0x1F7EC, // 1F7EC..1F7EF; UNKNOWN + 0x1F7F0, // 1F7F0 ; COMMON + 0x1F7F1, // 1F7F1..1F7FF; UNKNOWN 0x1F800, // 1F800..1F80B; COMMON 0x1F80C, // 1F80C..1F80F; UNKNOWN 0x1F810, // 1F810..1F847; COMMON @@ -6661,38 +6879,38 @@ class Character implements java.io.Serializable, Comparable, Constabl 0x1F8AE, // 1F8AE..1F8AF; UNKNOWN 0x1F8B0, // 1F8B0..1F8B1; COMMON 0x1F8B2, // 1F8B2..1F8FF; UNKNOWN - 0x1F900, // 1F900..1F978; COMMON - 0x1F979, // 1F979 ; UNKNOWN - 0x1F97A, // 1F97A..1F9CB; COMMON - 0x1F9CC, // 1F9CC ; UNKNOWN - 0x1F9CD, // 1F9CD..1FA53; COMMON + 0x1F900, // 1F900..1FA53; COMMON 0x1FA54, // 1FA54..1FA5F; UNKNOWN 0x1FA60, // 1FA60..1FA6D; COMMON 0x1FA6E, // 1FA6E..1FA6F; UNKNOWN 0x1FA70, // 1FA70..1FA74; COMMON 0x1FA75, // 1FA75..1FA77; UNKNOWN - 0x1FA78, // 1FA78..1FA7A; COMMON - 0x1FA7B, // 1FA7B..1FA7F; UNKNOWN + 0x1FA78, // 1FA78..1FA7C; COMMON + 0x1FA7D, // 1FA7D..1FA7F; UNKNOWN 0x1FA80, // 1FA80..1FA86; COMMON 0x1FA87, // 1FA87..1FA8F; UNKNOWN - 0x1FA90, // 1FA90..1FAA8; COMMON - 0x1FAA9, // 1FAA9..1FAAF; UNKNOWN - 0x1FAB0, // 1FAB0..1FAB6; COMMON - 0x1FAB7, // 1FAB7..1FABF; UNKNOWN - 0x1FAC0, // 1FAC0..1FAC2; COMMON - 0x1FAC3, // 1FAC3..1FACF; UNKNOWN - 0x1FAD0, // 1FAD0..1FAD6; COMMON - 0x1FAD7, // 1FAD7..1FAFF; UNKNOWN + 0x1FA90, // 1FA90..1FAAC; COMMON + 0x1FAAD, // 1FAAD..1FAAF; UNKNOWN + 0x1FAB0, // 1FAB0..1FABA; COMMON + 0x1FABB, // 1FABB..1FABF; UNKNOWN + 0x1FAC0, // 1FAC0..1FAC5; COMMON + 0x1FAC6, // 1FAC6..1FACF; UNKNOWN + 0x1FAD0, // 1FAD0..1FAD9; COMMON + 0x1FADA, // 1FADA..1FADF; UNKNOWN + 0x1FAE0, // 1FAE0..1FAE7; COMMON + 0x1FAE8, // 1FAE8..1FAEF; UNKNOWN + 0x1FAF0, // 1FAF0..1FAF6; COMMON + 0x1FAF7, // 1FAF7..1FAFF; UNKNOWN 0x1FB00, // 1FB00..1FB92; COMMON 0x1FB93, // 1FB93 ; UNKNOWN 0x1FB94, // 1FB94..1FBCA; COMMON 0x1FBCB, // 1FBCB..1FBEF; UNKNOWN 0x1FBF0, // 1FBF0..1FBF9; COMMON 0x1FBFA, // 1FBFA..1FFFF; UNKNOWN - 0x20000, // 20000..2A6DD; HAN - 0x2A6DE, // 2A6DE..2A6FF; UNKNOWN - 0x2A700, // 2A700..2B734; HAN - 0x2B735, // 2B735..2B73F; UNKNOWN + 0x20000, // 20000..2A6DF; HAN + 0x2A6E0, // 2A6E0..2A6FF; UNKNOWN + 0x2A700, // 2A700..2B738; HAN + 0x2B739, // 2B739..2B73F; UNKNOWN 0x2B740, // 2B740..2B81D; HAN 0x2B81E, // 2B81E..2B81F; UNKNOWN 0x2B820, // 2B820..2CEA1; HAN @@ -6775,9 +6993,7 @@ class Character implements java.io.Serializable, Comparable, Constabl COMMON, // 060C ARABIC, // 060D..061A COMMON, // 061B - ARABIC, // 061C - UNKNOWN, // 061D - ARABIC, // 061E + ARABIC, // 061C..061E COMMON, // 061F ARABIC, // 0620..063F COMMON, // 0640 @@ -6808,12 +7024,12 @@ class Character implements java.io.Serializable, Comparable, Constabl MANDAIC, // 085E UNKNOWN, // 085F SYRIAC, // 0860..086A - UNKNOWN, // 086B..089F - ARABIC, // 08A0..08B4 - UNKNOWN, // 08B5 - ARABIC, // 08B6..08C7 - UNKNOWN, // 08C8..08D2 - ARABIC, // 08D3..08E1 + UNKNOWN, // 086B..086F + ARABIC, // 0870..088E + UNKNOWN, // 088F + ARABIC, // 0890..0891 + UNKNOWN, // 0892..0897 + ARABIC, // 0898..08E1 COMMON, // 08E2 ARABIC, // 08E3..08FF DEVANAGARI, // 0900..0950 @@ -6976,8 +7192,8 @@ class Character implements java.io.Serializable, Comparable, Constabl TELUGU, // 0C12..0C28 UNKNOWN, // 0C29 TELUGU, // 0C2A..0C39 - UNKNOWN, // 0C3A..0C3C - TELUGU, // 0C3D..0C44 + UNKNOWN, // 0C3A..0C3B + TELUGU, // 0C3C..0C44 UNKNOWN, // 0C45 TELUGU, // 0C46..0C48 UNKNOWN, // 0C49 @@ -6986,7 +7202,9 @@ class Character implements java.io.Serializable, Comparable, Constabl TELUGU, // 0C55..0C56 UNKNOWN, // 0C57 TELUGU, // 0C58..0C5A - UNKNOWN, // 0C5B..0C5F + UNKNOWN, // 0C5B..0C5C + TELUGU, // 0C5D + UNKNOWN, // 0C5E..0C5F TELUGU, // 0C60..0C63 UNKNOWN, // 0C64..0C65 TELUGU, // 0C66..0C6F @@ -7009,8 +7227,8 @@ class Character implements java.io.Serializable, Comparable, Constabl KANNADA, // 0CCA..0CCD UNKNOWN, // 0CCE..0CD4 KANNADA, // 0CD5..0CD6 - UNKNOWN, // 0CD7..0CDD - KANNADA, // 0CDE + UNKNOWN, // 0CD7..0CDC + KANNADA, // 0CDD..0CDE UNKNOWN, // 0CDF KANNADA, // 0CE0..0CE3 UNKNOWN, // 0CE4..0CE5 @@ -7155,10 +7373,9 @@ class Character implements java.io.Serializable, Comparable, Constabl COMMON, // 16EB..16ED RUNIC, // 16EE..16F8 UNKNOWN, // 16F9..16FF - TAGALOG, // 1700..170C - UNKNOWN, // 170D - TAGALOG, // 170E..1714 - UNKNOWN, // 1715..171F + TAGALOG, // 1700..1715 + UNKNOWN, // 1716..171E + TAGALOG, // 171F HANUNOO, // 1720..1734 COMMON, // 1735..1736 UNKNOWN, // 1737..173F @@ -7180,9 +7397,7 @@ class Character implements java.io.Serializable, Comparable, Constabl COMMON, // 1802..1803 MONGOLIAN, // 1804 COMMON, // 1805 - MONGOLIAN, // 1806..180E - UNKNOWN, // 180F - MONGOLIAN, // 1810..1819 + MONGOLIAN, // 1806..1819 UNKNOWN, // 181A..181F MONGOLIAN, // 1820..1878 UNKNOWN, // 1879..187F @@ -7224,12 +7439,12 @@ class Character implements java.io.Serializable, Comparable, Constabl UNKNOWN, // 1A9A..1A9F TAI_THAM, // 1AA0..1AAD UNKNOWN, // 1AAE..1AAF - INHERITED, // 1AB0..1AC0 - UNKNOWN, // 1AC1..1AFF - BALINESE, // 1B00..1B4B - UNKNOWN, // 1B4C..1B4F - BALINESE, // 1B50..1B7C - UNKNOWN, // 1B7D..1B7F + INHERITED, // 1AB0..1ACE + UNKNOWN, // 1ACF..1AFF + BALINESE, // 1B00..1B4C + UNKNOWN, // 1B4D..1B4F + BALINESE, // 1B50..1B7E + UNKNOWN, // 1B7F SUNDANESE, // 1B80..1BBF BATAK, // 1BC0..1BF3 UNKNOWN, // 1BF4..1BFB @@ -7271,9 +7486,7 @@ class Character implements java.io.Serializable, Comparable, Constabl CYRILLIC, // 1D78 LATIN, // 1D79..1DBE GREEK, // 1DBF - INHERITED, // 1DC0..1DF9 - UNKNOWN, // 1DFA - INHERITED, // 1DFB..1DFF + INHERITED, // 1DC0..1DFF LATIN, // 1E00..1EFF GREEK, // 1F00..1F15 UNKNOWN, // 1F16..1F17 @@ -7320,8 +7533,8 @@ class Character implements java.io.Serializable, Comparable, Constabl UNKNOWN, // 208F LATIN, // 2090..209C UNKNOWN, // 209D..209F - COMMON, // 20A0..20BF - UNKNOWN, // 20C0..20CF + COMMON, // 20A0..20C0 + UNKNOWN, // 20C1..20CF INHERITED, // 20D0..20F0 UNKNOWN, // 20F1..20FF COMMON, // 2100..2125 @@ -7347,10 +7560,7 @@ class Character implements java.io.Serializable, Comparable, Constabl COMMON, // 2B76..2B95 UNKNOWN, // 2B96 COMMON, // 2B97..2BFF - GLAGOLITIC, // 2C00..2C2E - UNKNOWN, // 2C2F - GLAGOLITIC, // 2C30..2C5E - UNKNOWN, // 2C5F + GLAGOLITIC, // 2C00..2C5F LATIN, // 2C60..2C7F COPTIC, // 2C80..2CF3 UNKNOWN, // 2CF4..2CF8 @@ -7385,8 +7595,8 @@ class Character implements java.io.Serializable, Comparable, Constabl ETHIOPIC, // 2DD8..2DDE UNKNOWN, // 2DDF CYRILLIC, // 2DE0..2DFF - COMMON, // 2E00..2E52 - UNKNOWN, // 2E53..2E7F + COMMON, // 2E00..2E5D + UNKNOWN, // 2E5E..2E7F HAN, // 2E80..2E99 UNKNOWN, // 2E9A HAN, // 2E9B..2EF3 @@ -7437,8 +7647,7 @@ class Character implements java.io.Serializable, Comparable, Constabl COMMON, // 3358..33FF HAN, // 3400..4DBF COMMON, // 4DC0..4DFF - HAN, // 4E00..9FFC - UNKNOWN, // 9FFD..9FFF + HAN, // 4E00..9FFF YI, // A000..A48C UNKNOWN, // A48D..A48F YI, // A490..A4C6 @@ -7452,11 +7661,15 @@ class Character implements java.io.Serializable, Comparable, Constabl COMMON, // A700..A721 LATIN, // A722..A787 COMMON, // A788..A78A - LATIN, // A78B..A7BF - UNKNOWN, // A7C0..A7C1 - LATIN, // A7C2..A7CA - UNKNOWN, // A7CB..A7F4 - LATIN, // A7F5..A7FF + LATIN, // A78B..A7CA + UNKNOWN, // A7CB..A7CF + LATIN, // A7D0..A7D1 + UNKNOWN, // A7D2 + LATIN, // A7D3 + UNKNOWN, // A7D4 + LATIN, // A7D5..A7D9 + UNKNOWN, // A7DA..A7F1 + LATIN, // A7F2..A7FF SYLOTI_NAGRI, // A800..A82C UNKNOWN, // A82D..A82F COMMON, // A830..A839 @@ -7544,17 +7757,17 @@ class Character implements java.io.Serializable, Comparable, Constabl HEBREW, // FB43..FB44 UNKNOWN, // FB45 HEBREW, // FB46..FB4F - ARABIC, // FB50..FBC1 - UNKNOWN, // FBC2..FBD2 + ARABIC, // FB50..FBC2 + UNKNOWN, // FBC3..FBD2 ARABIC, // FBD3..FD3D COMMON, // FD3E..FD3F - UNKNOWN, // FD40..FD4F - ARABIC, // FD50..FD8F + ARABIC, // FD40..FD8F UNKNOWN, // FD90..FD91 ARABIC, // FD92..FDC7 - UNKNOWN, // FDC8..FDEF - ARABIC, // FDF0..FDFD - UNKNOWN, // FDFE..FDFF + UNKNOWN, // FDC8..FDCE + ARABIC, // FDCF + UNKNOWN, // FDD0..FDEF + ARABIC, // FDF0..FDFF INHERITED, // FE00..FE0F COMMON, // FE10..FE19 UNKNOWN, // FE1A..FE1F @@ -7661,13 +7874,34 @@ class Character implements java.io.Serializable, Comparable, Constabl CAUCASIAN_ALBANIAN, // 10530..10563 UNKNOWN, // 10564..1056E CAUCASIAN_ALBANIAN, // 1056F - UNKNOWN, // 10570..105FF + VITHKUQI, // 10570..1057A + UNKNOWN, // 1057B + VITHKUQI, // 1057C..1058A + UNKNOWN, // 1058B + VITHKUQI, // 1058C..10592 + UNKNOWN, // 10593 + VITHKUQI, // 10594..10595 + UNKNOWN, // 10596 + VITHKUQI, // 10597..105A1 + UNKNOWN, // 105A2 + VITHKUQI, // 105A3..105B1 + UNKNOWN, // 105B2 + VITHKUQI, // 105B3..105B9 + UNKNOWN, // 105BA + VITHKUQI, // 105BB..105BC + UNKNOWN, // 105BD..105FF LINEAR_A, // 10600..10736 UNKNOWN, // 10737..1073F LINEAR_A, // 10740..10755 UNKNOWN, // 10756..1075F LINEAR_A, // 10760..10767 - UNKNOWN, // 10768..107FF + UNKNOWN, // 10768..1077F + LATIN, // 10780..10785 + UNKNOWN, // 10786 + LATIN, // 10787..107B0 + UNKNOWN, // 107B1 + LATIN, // 107B2..107BA + UNKNOWN, // 107BB..107FF CYPRIOT, // 10800..10805 UNKNOWN, // 10806..10807 CYPRIOT, // 10808 @@ -7765,18 +7999,20 @@ class Character implements java.io.Serializable, Comparable, Constabl OLD_SOGDIAN, // 10F00..10F27 UNKNOWN, // 10F28..10F2F SOGDIAN, // 10F30..10F59 - UNKNOWN, // 10F5A..10FAF + UNKNOWN, // 10F5A..10F6F + OLD_UYGHUR, // 10F70..10F89 + UNKNOWN, // 10F8A..10FAF CHORASMIAN, // 10FB0..10FCB UNKNOWN, // 10FCC..10FDF ELYMAIC, // 10FE0..10FF6 UNKNOWN, // 10FF7..10FFF BRAHMI, // 11000..1104D UNKNOWN, // 1104E..11051 - BRAHMI, // 11052..1106F - UNKNOWN, // 11070..1107E + BRAHMI, // 11052..11075 + UNKNOWN, // 11076..1107E BRAHMI, // 1107F - KAITHI, // 11080..110C1 - UNKNOWN, // 110C2..110CC + KAITHI, // 11080..110C2 + UNKNOWN, // 110C3..110CC KAITHI, // 110CD UNKNOWN, // 110CE..110CF SORA_SOMPENG, // 110D0..110E8 @@ -7860,16 +8096,16 @@ class Character implements java.io.Serializable, Comparable, Constabl UNKNOWN, // 1165A..1165F MONGOLIAN, // 11660..1166C UNKNOWN, // 1166D..1167F - TAKRI, // 11680..116B8 - UNKNOWN, // 116B9..116BF + TAKRI, // 11680..116B9 + UNKNOWN, // 116BA..116BF TAKRI, // 116C0..116C9 UNKNOWN, // 116CA..116FF AHOM, // 11700..1171A UNKNOWN, // 1171B..1171C AHOM, // 1171D..1172B UNKNOWN, // 1172C..1172F - AHOM, // 11730..1173F - UNKNOWN, // 11740..117FF + AHOM, // 11730..11746 + UNKNOWN, // 11747..117FF DOGRA, // 11800..1183B UNKNOWN, // 1183C..1189F WARANG_CITI, // 118A0..118F2 @@ -7900,7 +8136,8 @@ class Character implements java.io.Serializable, Comparable, Constabl ZANABAZAR_SQUARE, // 11A00..11A47 UNKNOWN, // 11A48..11A4F SOYOMBO, // 11A50..11AA2 - UNKNOWN, // 11AA3..11ABF + UNKNOWN, // 11AA3..11AAF + CANADIAN_ABORIGINAL, // 11AB0..11ABF PAU_CIN_HAU, // 11AC0..11AF8 UNKNOWN, // 11AF9..11BFF BHAIKSUKI, // 11C00..11C08 @@ -7957,7 +8194,9 @@ class Character implements java.io.Serializable, Comparable, Constabl CUNEIFORM, // 12470..12474 UNKNOWN, // 12475..1247F CUNEIFORM, // 12480..12543 - UNKNOWN, // 12544..12FFF + UNKNOWN, // 12544..12F8F + CYPRO_MINOAN, // 12F90..12FF2 + UNKNOWN, // 12FF3..12FFF EGYPTIAN_HIEROGLYPHS, // 13000..1342E UNKNOWN, // 1342F EGYPTIAN_HIEROGLYPHS, // 13430..13438 @@ -7971,7 +8210,10 @@ class Character implements java.io.Serializable, Comparable, Constabl MRO, // 16A60..16A69 UNKNOWN, // 16A6A..16A6D MRO, // 16A6E..16A6F - UNKNOWN, // 16A70..16ACF + TANGSA, // 16A70..16ABE + UNKNOWN, // 16ABF + TANGSA, // 16AC0..16AC9 + UNKNOWN, // 16ACA..16ACF BASSA_VAH, // 16AD0..16AED UNKNOWN, // 16AEE..16AEF BASSA_VAH, // 16AF0..16AF5 @@ -7996,7 +8238,7 @@ class Character implements java.io.Serializable, Comparable, Constabl UNKNOWN, // 16FA0..16FDF TANGUT, // 16FE0 NUSHU, // 16FE1 - COMMON, // 16FE2..16FE3 + HAN, // 16FE2..16FE3 KHITAN_SMALL_SCRIPT, // 16FE4 UNKNOWN, // 16FE5..16FEF HAN, // 16FF0..16FF1 @@ -8007,10 +8249,17 @@ class Character implements java.io.Serializable, Comparable, Constabl KHITAN_SMALL_SCRIPT, // 18B00..18CD5 UNKNOWN, // 18CD6..18CFF TANGUT, // 18D00..18D08 - UNKNOWN, // 18D09..1AFFF + UNKNOWN, // 18D09..1AFEF + KATAKANA, // 1AFF0..1AFF3 + UNKNOWN, // 1AFF4 + KATAKANA, // 1AFF5..1AFFB + UNKNOWN, // 1AFFC + KATAKANA, // 1AFFD..1AFFE + UNKNOWN, // 1AFFF KATAKANA, // 1B000 - HIRAGANA, // 1B001..1B11E - UNKNOWN, // 1B11F..1B14F + HIRAGANA, // 1B001..1B11F + KATAKANA, // 1B120..1B122 + UNKNOWN, // 1B123..1B14F HIRAGANA, // 1B150..1B152 UNKNOWN, // 1B153..1B163 KATAKANA, // 1B164..1B167 @@ -8027,7 +8276,13 @@ class Character implements java.io.Serializable, Comparable, Constabl UNKNOWN, // 1BC9A..1BC9B DUPLOYAN, // 1BC9C..1BC9F COMMON, // 1BCA0..1BCA3 - UNKNOWN, // 1BCA4..1CFFF + UNKNOWN, // 1BCA4..1CEFF + INHERITED, // 1CF00..1CF2D + UNKNOWN, // 1CF2E..1CF2F + INHERITED, // 1CF30..1CF46 + UNKNOWN, // 1CF47..1CF4F + COMMON, // 1CF50..1CFC3 + UNKNOWN, // 1CFC4..1CFFF COMMON, // 1D000..1D0F5 UNKNOWN, // 1D0F6..1D0FF COMMON, // 1D100..1D126 @@ -8040,8 +8295,8 @@ class Character implements java.io.Serializable, Comparable, Constabl INHERITED, // 1D185..1D18B COMMON, // 1D18C..1D1A9 INHERITED, // 1D1AA..1D1AD - COMMON, // 1D1AE..1D1E8 - UNKNOWN, // 1D1E9..1D1FF + COMMON, // 1D1AE..1D1EA + UNKNOWN, // 1D1EB..1D1FF GREEK, // 1D200..1D245 UNKNOWN, // 1D246..1D2DF COMMON, // 1D2E0..1D2F3 @@ -8096,7 +8351,9 @@ class Character implements java.io.Serializable, Comparable, Constabl SIGNWRITING, // 1DA9B..1DA9F UNKNOWN, // 1DAA0 SIGNWRITING, // 1DAA1..1DAAF - UNKNOWN, // 1DAB0..1DFFF + UNKNOWN, // 1DAB0..1DEFF + LATIN, // 1DF00..1DF1E + UNKNOWN, // 1DF1F..1DFFF GLAGOLITIC, // 1E000..1E006 UNKNOWN, // 1E007 GLAGOLITIC, // 1E008..1E018 @@ -8114,11 +8371,21 @@ class Character implements java.io.Serializable, Comparable, Constabl NYIAKENG_PUACHUE_HMONG, // 1E140..1E149 UNKNOWN, // 1E14A..1E14D NYIAKENG_PUACHUE_HMONG, // 1E14E..1E14F - UNKNOWN, // 1E150..1E2BF + UNKNOWN, // 1E150..1E28F + TOTO, // 1E290..1E2AE + UNKNOWN, // 1E2AF..1E2BF WANCHO, // 1E2C0..1E2F9 UNKNOWN, // 1E2FA..1E2FE WANCHO, // 1E2FF - UNKNOWN, // 1E300..1E7FF + UNKNOWN, // 1E300..1E7DF + ETHIOPIC, // 1E7E0..1E7E6 + UNKNOWN, // 1E7E7 + ETHIOPIC, // 1E7E8..1E7EB + UNKNOWN, // 1E7EC + ETHIOPIC, // 1E7ED..1E7EE + UNKNOWN, // 1E7EF + ETHIOPIC, // 1E7F0..1E7FE + UNKNOWN, // 1E7FF MENDE_KIKAKUI, // 1E800..1E8C4 UNKNOWN, // 1E8C5..1E8C6 MENDE_KIKAKUI, // 1E8C7..1E8D6 @@ -8228,8 +8495,8 @@ class Character implements java.io.Serializable, Comparable, Constabl COMMON, // 1F260..1F265 UNKNOWN, // 1F266..1F2FF COMMON, // 1F300..1F6D7 - UNKNOWN, // 1F6D8..1F6DF - COMMON, // 1F6E0..1F6EC + UNKNOWN, // 1F6D8..1F6DC + COMMON, // 1F6DD..1F6EC UNKNOWN, // 1F6ED..1F6EF COMMON, // 1F6F0..1F6FC UNKNOWN, // 1F6FD..1F6FF @@ -8238,7 +8505,9 @@ class Character implements java.io.Serializable, Comparable, Constabl COMMON, // 1F780..1F7D8 UNKNOWN, // 1F7D9..1F7DF COMMON, // 1F7E0..1F7EB - UNKNOWN, // 1F7EC..1F7FF + UNKNOWN, // 1F7EC..1F7EF + COMMON, // 1F7F0 + UNKNOWN, // 1F7F1..1F7FF COMMON, // 1F800..1F80B UNKNOWN, // 1F80C..1F80F COMMON, // 1F810..1F847 @@ -8251,38 +8520,38 @@ class Character implements java.io.Serializable, Comparable, Constabl UNKNOWN, // 1F8AE..1F8AF COMMON, // 1F8B0..1F8B1 UNKNOWN, // 1F8B2..1F8FF - COMMON, // 1F900..1F978 - UNKNOWN, // 1F979 - COMMON, // 1F97A..1F9CB - UNKNOWN, // 1F9CC - COMMON, // 1F9CD..1FA53 + COMMON, // 1F900..1FA53 UNKNOWN, // 1FA54..1FA5F COMMON, // 1FA60..1FA6D UNKNOWN, // 1FA6E..1FA6F COMMON, // 1FA70..1FA74 UNKNOWN, // 1FA75..1FA77 - COMMON, // 1FA78..1FA7A - UNKNOWN, // 1FA7B..1FA7F + COMMON, // 1FA78..1FA7C + UNKNOWN, // 1FA7D..1FA7F COMMON, // 1FA80..1FA86 UNKNOWN, // 1FA87..1FA8F - COMMON, // 1FA90..1FAA8 - UNKNOWN, // 1FAA9..1FAAF - COMMON, // 1FAB0..1FAB6 - UNKNOWN, // 1FAB7..1FABF - COMMON, // 1FAC0..1FAC2 - UNKNOWN, // 1FAC3..1FACF - COMMON, // 1FAD0..1FAD6 - UNKNOWN, // 1FAD7..1FAFF + COMMON, // 1FA90..1FAAC + UNKNOWN, // 1FAAD..1FAAF + COMMON, // 1FAB0..1FABA + UNKNOWN, // 1FABB..1FABF + COMMON, // 1FAC0..1FAC5 + UNKNOWN, // 1FAC6..1FACF + COMMON, // 1FAD0..1FAD9 + UNKNOWN, // 1FADA..1FADF + COMMON, // 1FAE0..1FAE7 + UNKNOWN, // 1FAE8..1FAEF + COMMON, // 1FAF0..1FAF6 + UNKNOWN, // 1FAF7..1FAFF COMMON, // 1FB00..1FB92 UNKNOWN, // 1FB93 COMMON, // 1FB94..1FBCA UNKNOWN, // 1FBCB..1FBEF COMMON, // 1FBF0..1FBF9 UNKNOWN, // 1FBFA..1FFFF - HAN, // 20000..2A6DD - UNKNOWN, // 2A6DE..2A6FF - HAN, // 2A700..2B734 - UNKNOWN, // 2B735..2B73F + HAN, // 20000..2A6DF + UNKNOWN, // 2A6E0..2A6FF + HAN, // 2A700..2B738 + UNKNOWN, // 2B739..2B73F HAN, // 2B740..2B81D UNKNOWN, // 2B81E..2B81F HAN, // 2B820..2CEA1 @@ -8303,7 +8572,7 @@ class Character implements java.io.Serializable, Comparable, Constabl private static final HashMap aliases; static { - aliases = new HashMap<>((int)(157 / 0.75f + 1.0f)); + aliases = new HashMap<>((int)(162 / 0.75f + 1.0f)); aliases.put("ADLM", ADLAM); aliases.put("AGHB", CAUCASIAN_ALBANIAN); aliases.put("AHOM", AHOM); @@ -8329,6 +8598,7 @@ class Character implements java.io.Serializable, Comparable, Constabl aliases.put("CHER", CHEROKEE); aliases.put("CHRS", CHORASMIAN); aliases.put("COPT", COPTIC); + aliases.put("CPMN", CYPRO_MINOAN); aliases.put("CPRT", CYPRIOT); aliases.put("CYRL", CYRILLIC); aliases.put("DEVA", DEVANAGARI); @@ -8409,6 +8679,7 @@ class Character implements java.io.Serializable, Comparable, Constabl aliases.put("ORYA", ORIYA); aliases.put("OSGE", OSAGE); aliases.put("OSMA", OSMANYA); + aliases.put("OUGR", OLD_UYGHUR); aliases.put("PALM", PALMYRENE); aliases.put("PAUC", PAU_CIN_HAU); aliases.put("PERM", OLD_PERMIC); @@ -8451,8 +8722,11 @@ class Character implements java.io.Serializable, Comparable, Constabl aliases.put("THAI", THAI); aliases.put("TIBT", TIBETAN); aliases.put("TIRH", TIRHUTA); + aliases.put("TNSA", TANGSA); + aliases.put("TOTO", TOTO); aliases.put("UGAR", UGARITIC); aliases.put("VAII", VAI); + aliases.put("VITH", VITHKUQI); aliases.put("WARA", WARANG_CITI); aliases.put("WCHO", WANCHO); aliases.put("XPEO", OLD_PERSIAN); @@ -8495,8 +8769,8 @@ class Character implements java.io.Serializable, Comparable, Constabl /** * Returns the UnicodeScript constant with the given Unicode script * name or the script name alias. Script names and their aliases are - * determined by The Unicode Standard. The files {@code Scripts.txt} - * and {@code PropertyValueAliases.txt} define script names + * determined by The Unicode Standard. The files {@code Scripts.txt} + * and {@code PropertyValueAliases.txt} define script names * and the script name aliases for a particular version of the * standard. The {@link Character} class specifies the version of * the standard that it supports. @@ -10031,9 +10305,10 @@ class Character implements java.io.Serializable, Comparable, Constabl * @see Character#isJavaIdentifierPart(char) * @see Character#isLetter(char) * @see Character#isUnicodeIdentifierStart(char) - * @see javax.lang.model.SourceVersion#isIdentifier(CharSequence) + * @see java.compiler/javax.lang.model.SourceVersion#isIdentifier(CharSequence) * @since 1.1 */ + @SuppressWarnings("doclint:reference") // cross-module links public static boolean isJavaIdentifierStart(char ch) { return isJavaIdentifierStart((int)ch); } @@ -10060,9 +10335,10 @@ class Character implements java.io.Serializable, Comparable, Constabl * @see Character#isJavaIdentifierPart(int) * @see Character#isLetter(int) * @see Character#isUnicodeIdentifierStart(int) - * @see javax.lang.model.SourceVersion#isIdentifier(CharSequence) + * @see java.compiler/javax.lang.model.SourceVersion#isIdentifier(CharSequence) * @since 1.5 */ + @SuppressWarnings("doclint:reference") // cross-module links public static boolean isJavaIdentifierStart(int codePoint) { return CharacterData.of(codePoint).isJavaIdentifierStart(codePoint); } @@ -10097,9 +10373,10 @@ class Character implements java.io.Serializable, Comparable, Constabl * @see Character#isJavaIdentifierStart(char) * @see Character#isLetterOrDigit(char) * @see Character#isUnicodeIdentifierPart(char) - * @see javax.lang.model.SourceVersion#isIdentifier(CharSequence) + * @see java.compiler/javax.lang.model.SourceVersion#isIdentifier(CharSequence) * @since 1.1 */ + @SuppressWarnings("doclint:reference") // cross-module links public static boolean isJavaIdentifierPart(char ch) { return isJavaIdentifierPart((int)ch); } @@ -10130,9 +10407,10 @@ class Character implements java.io.Serializable, Comparable, Constabl * @see Character#isJavaIdentifierStart(int) * @see Character#isLetterOrDigit(int) * @see Character#isUnicodeIdentifierPart(int) - * @see javax.lang.model.SourceVersion#isIdentifier(CharSequence) + * @see java.compiler/javax.lang.model.SourceVersion#isIdentifier(CharSequence) * @since 1.5 */ + @SuppressWarnings("doclint:reference") // cross-module links public static boolean isJavaIdentifierPart(int codePoint) { return CharacterData.of(codePoint).isJavaIdentifierPart(codePoint); } diff --git a/make/data/characterdata/CharacterData00.java.template b/src/java.base/share/classes/java/lang/CharacterData00.java.template similarity index 100% rename from make/data/characterdata/CharacterData00.java.template rename to src/java.base/share/classes/java/lang/CharacterData00.java.template diff --git a/make/data/characterdata/CharacterData01.java.template b/src/java.base/share/classes/java/lang/CharacterData01.java.template similarity index 100% rename from make/data/characterdata/CharacterData01.java.template rename to src/java.base/share/classes/java/lang/CharacterData01.java.template diff --git a/make/data/characterdata/CharacterData02.java.template b/src/java.base/share/classes/java/lang/CharacterData02.java.template similarity index 100% rename from make/data/characterdata/CharacterData02.java.template rename to src/java.base/share/classes/java/lang/CharacterData02.java.template diff --git a/make/data/characterdata/CharacterData03.java.template b/src/java.base/share/classes/java/lang/CharacterData03.java.template similarity index 100% rename from make/data/characterdata/CharacterData03.java.template rename to src/java.base/share/classes/java/lang/CharacterData03.java.template diff --git a/make/data/characterdata/CharacterData0E.java.template b/src/java.base/share/classes/java/lang/CharacterData0E.java.template similarity index 100% rename from make/data/characterdata/CharacterData0E.java.template rename to src/java.base/share/classes/java/lang/CharacterData0E.java.template diff --git a/make/data/characterdata/CharacterDataLatin1.java.template b/src/java.base/share/classes/java/lang/CharacterDataLatin1.java.template similarity index 100% rename from make/data/characterdata/CharacterDataLatin1.java.template rename to src/java.base/share/classes/java/lang/CharacterDataLatin1.java.template diff --git a/src/java.base/share/classes/java/lang/Class.java b/src/java.base/share/classes/java/lang/Class.java index 7eb5256e5e8f4b44493eb40383dd2ffa0a9afa06..840abc63aaf0eced2c0ac0ff4f3b36a8bb983dbe 100644 --- a/src/java.base/share/classes/java/lang/Class.java +++ b/src/java.base/share/classes/java/lang/Class.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 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 @@ -1582,7 +1582,7 @@ public final class Class implements java.io.Serializable, * representing the class in which it was declared. This method returns * null if this class or interface is not a member of any other class. If * this {@code Class} object represents an array class, a primitive - * type, or void,then this method returns null. + * type, or void, then this method returns null. * * @return the declaring class for this class * @throws SecurityException @@ -1732,8 +1732,18 @@ public final class Class implements java.io.Serializable, *

    • an array whose component type does not have a canonical name
    • * * + * The canonical name for a primitive class is the keyword for the + * corresponding primitive type ({@code byte}, {@code short}, + * {@code char}, {@code int}, and so on). + * + *

      An array type has a canonical name if and only if its + * component type has a canonical name. When an array type has a + * canonical name, it is equal to the canonical name of the + * component type followed by "{@code []}". + * * @return the canonical name of the underlying class if it exists, and * {@code null} otherwise. + * @jls 6.7 Fully Qualified Names and Canonical Names * @since 1.5 */ public String getCanonicalName() { @@ -2080,6 +2090,7 @@ public final class Class implements java.io.Serializable, * s.checkPackageAccess()} denies access to the package * of this class. * + * @see #getDeclaredConstructors() * @since 1.1 */ @CallerSensitive @@ -2279,7 +2290,9 @@ public final class Class implements java.io.Serializable, * @param parameterTypes the parameter array * @return the {@code Constructor} object of the public constructor that * matches the specified {@code parameterTypes} - * @throws NoSuchMethodException if a matching method is not found. + * @throws NoSuchMethodException if a matching constructor is not found, + * including when this {@code Class} object represents + * an interface, a primitive type, an array class, or void. * @throws SecurityException * If a security manager, s, is present and * the caller's class loader is not the same as or an @@ -2288,6 +2301,7 @@ public final class Class implements java.io.Serializable, * s.checkPackageAccess()} denies access to the package * of this class. * + * @see #getDeclaredConstructor(Class[]) * @since 1.1 */ @CallerSensitive @@ -2536,21 +2550,20 @@ public final class Class implements java.io.Serializable, return copyMethods(privateGetDeclaredMethods(false)); } - /** * Returns an array of {@code Constructor} objects reflecting all the - * constructors declared by the class represented by this + * constructors implicitly or explicitly declared by the class represented by this * {@code Class} object. These are public, protected, default * (package) access, and private constructors. The elements in the array * returned are not sorted and are not in any particular order. If the - * class has a default constructor, it is included in the returned array. + * class has a default constructor (JLS {@jls 8.8.9}), it is included in the returned array. + * If a record class has a canonical constructor (JLS {@jls + * 8.10.4.1}, {@jls 8.10.4.2}), it is included in the returned array. + * * This method returns an array of length 0 if this {@code Class} * object represents an interface, a primitive type, an array class, or * void. * - *

      See The Java Language Specification, - * section {@jls 8.2}. - * * @return the array of {@code Constructor} objects representing all the * declared constructors of this class * @throws SecurityException @@ -2575,6 +2588,7 @@ public final class Class implements java.io.Serializable, * * * @since 1.1 + * @see #getConstructors() * @jls 8.8 Constructor Declarations */ @CallerSensitive @@ -2736,7 +2750,7 @@ public final class Class implements java.io.Serializable, /** * Returns a {@code Constructor} object that reflects the specified - * constructor of the class or interface represented by this + * constructor of the class represented by this * {@code Class} object. The {@code parameterTypes} parameter is * an array of {@code Class} objects that identify the constructor's * formal parameter types, in declared order. @@ -2748,7 +2762,9 @@ public final class Class implements java.io.Serializable, * @param parameterTypes the parameter array * @return The {@code Constructor} object for the constructor with the * specified parameter list - * @throws NoSuchMethodException if a matching method is not found. + * @throws NoSuchMethodException if a matching constructor is not found, + * including when this {@code Class} object represents + * an interface, a primitive type, an array class, or void. * @throws SecurityException * If a security manager, s, is present and any of the * following conditions is met: @@ -2770,6 +2786,7 @@ public final class Class implements java.io.Serializable, * * * + * @see #getConstructor(Class[]) * @since 1.1 */ @CallerSensitive @@ -3820,12 +3837,13 @@ public final class Class implements java.io.Serializable, // Fetches the factory for reflective objects @SuppressWarnings("removal") private static ReflectionFactory getReflectionFactory() { - if (reflectionFactory == null) { - reflectionFactory = - java.security.AccessController.doPrivileged - (new ReflectionFactory.GetReflectionFactoryAction()); + var factory = reflectionFactory; + if (factory != null) { + return factory; } - return reflectionFactory; + return reflectionFactory = + java.security.AccessController.doPrivileged + (new ReflectionFactory.GetReflectionFactoryAction()); } private static ReflectionFactory reflectionFactory; @@ -4467,12 +4485,21 @@ public final class Class implements java.io.Serializable, * Returns a {@code Class} for an array type whose component type * is described by this {@linkplain Class}. * + * @throws UnsupportedOperationException if this component type is {@linkplain + * Void#TYPE void} or if the number of dimensions of the resulting array + * type would exceed 255. * @return a {@code Class} describing the array type + * @jvms 4.3.2 Field Descriptors + * @jvms 4.4.1 The {@code CONSTANT_Class_info} Structure * @since 12 */ @Override public Class arrayType() { - return Array.newInstance(this, 0).getClass(); + try { + return Array.newInstance(this, 0).getClass(); + } catch (IllegalArgumentException iae) { + throw new UnsupportedOperationException(iae); + } } /** diff --git a/src/java.base/share/classes/java/lang/ClassLoader.java b/src/java.base/share/classes/java/lang/ClassLoader.java index dffd56948f3b8c6a5df5d260509987c1a6511909..0aeb762018925e758a59ed30c603194524e2bf66 100644 --- a/src/java.base/share/classes/java/lang/ClassLoader.java +++ b/src/java.base/share/classes/java/lang/ClassLoader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2022, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2019, Azul Systems, Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -1606,9 +1606,16 @@ public abstract class ClassLoader { * *

      Note that once a class loader is registered as parallel capable, there * is no way to change it back.

      + *

      + * In cases where this method is called from a context where the caller is + * not a subclass of {@code ClassLoader} or there is no caller frame on the + * stack (e.g. when called directly from a JNI attached thread), + * {@code IllegalCallerException} is thrown. + *

      * * @return {@code true} if the caller is successfully registered as * parallel capable and {@code false} if otherwise. + * @throws IllegalCallerException if the caller is not a subclass of {@code ClassLoader} * * @see #isRegisteredAsParallelCapable() * @@ -1622,6 +1629,9 @@ public abstract class ClassLoader { // Caller-sensitive adapter method for reflective invocation @CallerSensitiveAdapter private static boolean registerAsParallelCapable(Class caller) { + if ((caller == null) || !ClassLoader.class.isAssignableFrom(caller)) { + throw new IllegalCallerException(caller + " not a subclass of ClassLoader"); + } return ParallelLoaders.register(caller.asSubclass(ClassLoader.class)); } @@ -2385,7 +2395,7 @@ public abstract class ClassLoader { return null; } - private final NativeLibraries libraries = NativeLibraries.jniNativeLibraries(this); + private final NativeLibraries libraries = NativeLibraries.newInstance(this); // Invoked in the java.lang.Runtime class to implement load and loadLibrary. static NativeLibrary loadLibrary(Class fromClass, File file) { diff --git a/src/java.base/share/classes/java/lang/Enum.java b/src/java.base/share/classes/java/lang/Enum.java index 636ad7c757e471c46c86a8ed4b524880b89387af..55926fc3a40140346cdba684ac16bec060cee482 100644 --- a/src/java.base/share/classes/java/lang/Enum.java +++ b/src/java.base/share/classes/java/lang/Enum.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -51,8 +51,9 @@ import static java.util.Objects.requireNonNull; * by the serialization mechanism. The serialized representation used * for enum constants cannot be customized. Declarations of methods * and fields that would otherwise interact with serialization are - * ignored, including {@code serialVersionUID}; see the Java - * Object Serialization Specification for details. + * ignored, including {@code serialVersionUID}; see the + * Java + * Object Serialization Specification for details. * *

      Note that when using an enumeration type as the type of a set * or as the type of the keys in a map, specialized and efficient @@ -275,8 +276,13 @@ public abstract class Enum> /** * enum classes cannot have finalize methods. + * + * @deprecated Finalization has been deprecated for removal. See + * {@link java.lang.Object#finalize} for background information and details + * about migration options. */ - @SuppressWarnings("deprecation") + @Deprecated(since="18", forRemoval=true) + @SuppressWarnings("removal") protected final void finalize() { } /** diff --git a/src/java.base/share/classes/java/lang/Integer.java b/src/java.base/share/classes/java/lang/Integer.java index 7d200e7edf531b224cc00c143d748dfbcbab4a91..9ec9d3941f898be8868cd8772a684db155db96c0 100644 --- a/src/java.base/share/classes/java/lang/Integer.java +++ b/src/java.base/share/classes/java/lang/Integer.java @@ -517,13 +517,9 @@ public final class Integer extends Number } // We know there are at most two digits left at this point. - q = i / 10; - r = (q * 10) - i; - buf[--charPos] = (byte)('0' + r); - - // Whatever left is the remaining digit. - if (q < 0) { - buf[--charPos] = (byte)('0' - q); + buf[--charPos] = DigitOnes[-i]; + if (i < -9) { + buf[--charPos] = DigitTens[-i]; } if (negative) { diff --git a/src/java.base/share/classes/java/lang/Long.java b/src/java.base/share/classes/java/lang/Long.java index 630b9e242b89c841e2c0bcb67432db6fd40d1301..2a5a230b321ca1146f0b7cc769d85aaa101600d7 100644 --- a/src/java.base/share/classes/java/lang/Long.java +++ b/src/java.base/share/classes/java/lang/Long.java @@ -565,13 +565,9 @@ public final class Long extends Number } // We know there are at most two digits left at this point. - q2 = i2 / 10; - r = (q2 * 10) - i2; - buf[--charPos] = (byte)('0' + r); - - // Whatever left is the remaining digit. - if (q2 < 0) { - buf[--charPos] = (byte)('0' - q2); + buf[--charPos] = Integer.DigitOnes[-i2]; + if (i2 < -9) { + buf[--charPos] = Integer.DigitTens[-i2]; } if (negative) { diff --git a/src/java.base/share/classes/java/lang/Math.java b/src/java.base/share/classes/java/lang/Math.java index 7341aa56a6ac870f6d05dfbac3adca52675f58c5..6d8fa48c9764e6207e2aa0dac074abad72b15ef4 100644 --- a/src/java.base/share/classes/java/lang/Math.java +++ b/src/java.base/share/classes/java/lang/Math.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 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 @@ -131,14 +131,27 @@ public final class Math { * The {@code double} value that is closer than any other to * e, the base of the natural logarithms. */ - public static final double E = 2.7182818284590452354; + public static final double E = 2.718281828459045; /** * The {@code double} value that is closer than any other to - * pi, the ratio of the circumference of a circle to its - * diameter. + * pi (π), the ratio of the circumference of a circle to + * its diameter. */ - public static final double PI = 3.14159265358979323846; + public static final double PI = 3.141592653589793; + + /** + * The {@code double} value that is closer than any other to + * tau (τ), the ratio of the circumference of a circle + * to its radius. + * + * @apiNote + * The value of pi is one half that of tau; in other + * words, tau is double pi . + * + * @since 19 + */ + public static final double TAU = 2.0 * PI; /** * Constant by which to multiply an angular value in degrees to obtain an diff --git a/src/java.base/share/classes/java/lang/Module.java b/src/java.base/share/classes/java/lang/Module.java index ab7d21038507d1c0dc02aacf8f5c87d43311657a..e822c951420669d2cc8c0b2e343b6a385dfd1ca3 100644 --- a/src/java.base/share/classes/java/lang/Module.java +++ b/src/java.base/share/classes/java/lang/Module.java @@ -68,6 +68,7 @@ import jdk.internal.org.objectweb.asm.ModuleVisitor; import jdk.internal.org.objectweb.asm.Opcodes; import jdk.internal.reflect.CallerSensitive; import jdk.internal.reflect.Reflection; +import jdk.internal.vm.annotation.Stable; import sun.security.util.SecurityConstants; /** @@ -110,7 +111,8 @@ public final class Module implements AnnotatedElement { private final ModuleDescriptor descriptor; // true, if this module allows restricted native access - private volatile boolean enableNativeAccess; + @Stable + private boolean enableNativeAccess; /** * Creates a new named Module. The resulting Module will be defined to the diff --git a/src/java.base/share/classes/java/lang/Object.java b/src/java.base/share/classes/java/lang/Object.java index b8085b230afb03ebf03ae8c6fbc3b1354deb655c..52028ba99a7c42f53659e9ee45a6b5d4b31357a4 100644 --- a/src/java.base/share/classes/java/lang/Object.java +++ b/src/java.base/share/classes/java/lang/Object.java @@ -478,6 +478,12 @@ public class Object { * A subclass overrides the {@code finalize} method to dispose of * system resources or to perform other cleanup. *

      + * When running in a Java virtual machine in which finalization has been + * disabled or removed, the garbage collector will never call + * {@code finalize()}. In a Java virtual machine in which finalization is + * enabled, the garbage collector might call {@code finalize} only after an + * indefinite delay. + *

      * The general contract of {@code finalize} is that it is invoked * if and when the Java virtual * machine has determined that there is no longer any @@ -543,27 +549,29 @@ public class Object { * } * } * - * @deprecated The finalization mechanism is inherently problematic. - * Finalization can lead to performance issues, deadlocks, and hangs. - * Errors in finalizers can lead to resource leaks; there is no way to cancel - * finalization if it is no longer necessary; and no ordering is specified - * among calls to {@code finalize} methods of different objects. - * Furthermore, there are no guarantees regarding the timing of finalization. - * The {@code finalize} method might be called on a finalizable object - * only after an indefinite delay, if at all. - * - * Classes whose instances hold non-heap resources should provide a method - * to enable explicit release of those resources, and they should also - * implement {@link AutoCloseable} if appropriate. - * The {@link java.lang.ref.Cleaner} and {@link java.lang.ref.PhantomReference} - * provide more flexible and efficient ways to release resources when an object - * becomes unreachable. + * @deprecated Finalization is deprecated and subject to removal in a future + * release. The use of finalization can lead to problems with security, + * performance, and reliability. + * See JEP 421 for + * discussion and alternatives. + *

      + * Subclasses that override {@code finalize} to perform cleanup should use + * alternative cleanup mechanisms and remove the {@code finalize} method. + * Use {@link java.lang.ref.Cleaner} and + * {@link java.lang.ref.PhantomReference} as safer ways to release resources + * when an object becomes unreachable. Alternatively, add a {@code close} + * method to explicitly release resources, and implement + * {@code AutoCloseable} to enable use of the {@code try}-with-resources + * statement. + *

      + * This method will remain in place until finalizers have been removed from + * most existing code. * * @throws Throwable the {@code Exception} raised by this method * @see java.lang.ref.WeakReference * @see java.lang.ref.PhantomReference * @jls 12.6 Finalization of Class Instances */ - @Deprecated(since="9") + @Deprecated(since="9", forRemoval=true) protected void finalize() throws Throwable { } } diff --git a/src/java.base/share/classes/java/lang/Runtime.java b/src/java.base/share/classes/java/lang/Runtime.java index 2288aca4d1114e4c839dee525a5e995020885f49..c674880c636170f221a1b0f4c35706fa910e066d 100644 --- a/src/java.base/share/classes/java/lang/Runtime.java +++ b/src/java.base/share/classes/java/lang/Runtime.java @@ -707,8 +707,17 @@ public class Runtime { * The method {@link System#runFinalization()} is the conventional * and convenient means of invoking this method. * + * @deprecated Finalization has been deprecated for removal. See + * {@link java.lang.Object#finalize} for background information and details + * about migration options. + *

      + * When running in a JVM in which finalization has been disabled or removed, + * no objects will be pending finalization, so this method does nothing. + * * @see java.lang.Object#finalize() + * @jls 12.6 Finalization of Class Instances */ + @Deprecated(since="18", forRemoval=true) public void runFinalization() { SharedSecrets.getJavaLangRefAccess().runFinalization(); } diff --git a/src/java.base/share/classes/java/lang/StrictMath.java b/src/java.base/share/classes/java/lang/StrictMath.java index b5e3541c85cf7db6171ae79a4e74fd413b498596..b551288a38f0194579d7ac0ab5621f42789b9d32 100644 --- a/src/java.base/share/classes/java/lang/StrictMath.java +++ b/src/java.base/share/classes/java/lang/StrictMath.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -92,27 +92,27 @@ public final class StrictMath { * The {@code double} value that is closer than any other to * e, the base of the natural logarithms. */ - public static final double E = 2.7182818284590452354; + public static final double E = 2.718281828459045; /** * The {@code double} value that is closer than any other to - * pi, the ratio of the circumference of a circle to its + * pi (π), the ratio of the circumference of a circle to its * diameter. */ - public static final double PI = 3.14159265358979323846; + public static final double PI = 3.141592653589793; /** - * Constant by which to multiply an angular value in degrees to obtain an - * angular value in radians. - */ - private static final double DEGREES_TO_RADIANS = 0.017453292519943295; - - /** - * Constant by which to multiply an angular value in radians to obtain an - * angular value in degrees. + * The {@code double} value that is closer than any other to + * tau (τ), the ratio of the circumference of a circle + * to its radius. + * + * @apiNote + * The value of pi is one half that of tau; in other + * words, tau is double pi . + * + * @since 19 */ - - private static final double RADIANS_TO_DEGREES = 57.29577951308232; + public static final double TAU = 2.0 * PI; /** * Returns the trigonometric sine of an angle. Special cases: @@ -397,7 +397,7 @@ public final class StrictMath { * @param a the value to be floored or ceiled * @param negativeBoundary result for values in (-1, 0) * @param positiveBoundary result for values in (0, 1) - * @param increment value to add when the argument is non-integral + * @param sign the sign of the result */ private static double floorOrCeil(double a, double negativeBoundary, @@ -408,8 +408,8 @@ public final class StrictMath { if (exponent < 0) { /* * Absolute value of argument is less than 1. - * floorOrceil(-0.0) => -0.0 - * floorOrceil(+0.0) => +0.0 + * floorOrCeil(-0.0) => -0.0 + * floorOrCeil(+0.0) => +0.0 */ return ((a == 0.0) ? a : ( (a < 0.0) ? negativeBoundary : positiveBoundary) ); diff --git a/src/java.base/share/classes/java/lang/String.java b/src/java.base/share/classes/java/lang/String.java index 50e5525bb3eff5341409575c99c5946a2e1a1995..009a61a9ba39518832cec7545f1965a417c5e26a 100644 --- a/src/java.base/share/classes/java/lang/String.java +++ b/src/java.base/share/classes/java/lang/String.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 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 @@ -230,7 +230,7 @@ public final class String * * A String instance is written into an ObjectOutputStream according to * - * Object Serialization Specification, Section 6.2, "Stream Elements" + * Java Object Serialization Specification, Section 6.2, "Stream Elements" */ @java.io.Serial private static final ObjectStreamField[] serialPersistentFields = @@ -261,6 +261,7 @@ public final class String this.value = original.value; this.coder = original.coder; this.hash = original.hash; + this.hashIsZero = original.hashIsZero; } /** @@ -524,57 +525,63 @@ public final class String this.value = "".value; this.coder = "".coder; } else if (charset == UTF_8.INSTANCE) { - if (COMPACT_STRINGS && !StringCoding.hasNegatives(bytes, offset, length)) { - this.value = Arrays.copyOfRange(bytes, offset, offset + length); - this.coder = LATIN1; - } else { + if (COMPACT_STRINGS) { + int dp = StringCoding.countPositives(bytes, offset, length); + if (dp == length) { + this.value = Arrays.copyOfRange(bytes, offset, offset + length); + this.coder = LATIN1; + return; + } int sl = offset + length; - int dp = 0; - byte[] dst = null; - if (COMPACT_STRINGS) { - dst = new byte[length]; - while (offset < sl) { - int b1 = bytes[offset]; - if (b1 >= 0) { - dst[dp++] = (byte)b1; + byte[] dst = new byte[length]; + if (dp > 0) { + System.arraycopy(bytes, offset, dst, 0, dp); + offset += dp; + } + while (offset < sl) { + int b1 = bytes[offset++]; + if (b1 >= 0) { + dst[dp++] = (byte)b1; + continue; + } + if ((b1 & 0xfe) == 0xc2 && offset < sl) { // b1 either 0xc2 or 0xc3 + int b2 = bytes[offset]; + if (b2 < -64) { // continuation bytes are always negative values in the range -128 to -65 + dst[dp++] = (byte)decode2(b1, b2); offset++; continue; } - if ((b1 == (byte)0xc2 || b1 == (byte)0xc3) && - offset + 1 < sl) { - int b2 = bytes[offset + 1]; - if (!isNotContinuation(b2)) { - dst[dp++] = (byte)decode2(b1, b2); - offset += 2; - continue; - } - } - // anything not a latin1, including the repl - // we have to go with the utf16 - break; - } - if (offset == sl) { - if (dp != dst.length) { - dst = Arrays.copyOf(dst, dp); - } - this.value = dst; - this.coder = LATIN1; - return; } + // anything not a latin1, including the REPL + // we have to go with the utf16 + offset--; + break; } - if (dp == 0 || dst == null) { - dst = new byte[length << 1]; - } else { - byte[] buf = new byte[length << 1]; - StringLatin1.inflate(dst, 0, buf, 0, dp); - dst = buf; + if (offset == sl) { + if (dp != dst.length) { + dst = Arrays.copyOf(dst, dp); + } + this.value = dst; + this.coder = LATIN1; + return; } + byte[] buf = new byte[length << 1]; + StringLatin1.inflate(dst, 0, buf, 0, dp); + dst = buf; dp = decodeUTF8_UTF16(bytes, offset, sl, dst, dp, true); if (dp != length) { dst = Arrays.copyOf(dst, dp << 1); } this.value = dst; this.coder = UTF16; + } else { // !COMPACT_STRINGS + byte[] dst = new byte[length << 1]; + int dp = decodeUTF8_UTF16(bytes, offset, offset + length, dst, 0, true); + if (dp != length) { + dst = Arrays.copyOf(dst, dp << 1); + } + this.value = dst; + this.coder = UTF16; } } else if (charset == ISO_8859_1.INSTANCE) { if (COMPACT_STRINGS) { @@ -682,42 +689,43 @@ public final class String if (length == 0) { return ""; } - if (COMPACT_STRINGS && !StringCoding.hasNegatives(bytes, offset, length)) { - return new String(Arrays.copyOfRange(bytes, offset, offset + length), LATIN1); - } else { + int dp; + byte[] dst; + if (COMPACT_STRINGS) { + dp = StringCoding.countPositives(bytes, offset, length); int sl = offset + length; - int dp = 0; - byte[] dst = null; - if (COMPACT_STRINGS) { - dst = new byte[length]; - while (offset < sl) { - int b1 = bytes[offset]; - if (b1 >= 0) { - dst[dp++] = (byte) b1; + if (dp == length) { + return new String(Arrays.copyOfRange(bytes, offset, offset + length), LATIN1); + } + dst = new byte[length]; + System.arraycopy(bytes, offset, dst, 0, dp); + offset += dp; + while (offset < sl) { + int b1 = bytes[offset++]; + if (b1 >= 0) { + dst[dp++] = (byte)b1; + continue; + } + if ((b1 & 0xfe) == 0xc2 && offset < sl) { // b1 either 0xc2 or 0xc3 + int b2 = bytes[offset]; + if (b2 < -64) { // continuation bytes are always negative values in the range -128 to -65 + dst[dp++] = (byte)decode2(b1, b2); offset++; continue; } - if ((b1 == (byte) 0xc2 || b1 == (byte) 0xc3) && - offset + 1 < sl) { - int b2 = bytes[offset + 1]; - if (!isNotContinuation(b2)) { - dst[dp++] = (byte) decode2(b1, b2); - offset += 2; - continue; - } - } - // anything not a latin1, including the REPL - // we have to go with the utf16 - break; } - if (offset == sl) { - if (dp != dst.length) { - dst = Arrays.copyOf(dst, dp); - } - return new String(dst, LATIN1); + // anything not a latin1, including the REPL + // we have to go with the utf16 + offset--; + break; + } + if (offset == sl) { + if (dp != dst.length) { + dst = Arrays.copyOf(dst, dp); } + return new String(dst, LATIN1); } - if (dp == 0 || dst == null) { + if (dp == 0) { dst = new byte[length << 1]; } else { byte[] buf = new byte[length << 1]; @@ -725,11 +733,14 @@ public final class String dst = buf; } dp = decodeUTF8_UTF16(bytes, offset, sl, dst, dp, false); - if (dp != length) { - dst = Arrays.copyOf(dst, dp << 1); - } - return new String(dst, UTF16); + } else { // !COMPACT_STRINGS + dst = new byte[length << 1]; + dp = decodeUTF8_UTF16(bytes, offset, offset + length, dst, 0, false); } + if (dp != length) { + dst = Arrays.copyOf(dst, dp << 1); + } + return new String(dst, UTF16); } static String newStringNoRepl(byte[] src, Charset cs) throws CharacterCodingException { @@ -1020,17 +1031,15 @@ public final class String */ /* package-private */ static int decodeASCII(byte[] sa, int sp, char[] da, int dp, int len) { - if (!StringCoding.hasNegatives(sa, sp, len)) { - StringLatin1.inflate(sa, sp, da, dp, len); - return len; - } else { - int start = sp; - int end = sp + len; - while (sp < end && sa[sp] >= 0) { - da[dp++] = (char) sa[sp++]; + int count = StringCoding.countPositives(sa, sp, len); + while (count < len) { + if (sa[sp + count] < 0) { + break; } - return sp - start; + count++; } + StringLatin1.inflate(sa, sp, da, dp, count); + return count; } private static boolean isNotContinuation(int b) { @@ -1283,14 +1292,17 @@ public final class String int sp = 0; int sl = val.length >> 1; byte[] dst = new byte[sl * 3]; - char c; - while (sp < sl && (c = StringUTF16.getChar(val, sp)) < '\u0080') { + while (sp < sl) { // ascii fast loop; + char c = StringUTF16.getChar(val, sp); + if (c >= '\u0080') { + break; + } dst[dp++] = (byte)c; sp++; } while (sp < sl) { - c = StringUTF16.getChar(val, sp++); + char c = StringUTF16.getChar(val, sp++); if (c < 0x80) { dst[dp++] = (byte)c; } else if (c < 0x800) { diff --git a/src/java.base/share/classes/java/lang/StringBuffer.java b/src/java.base/share/classes/java/lang/StringBuffer.java index e2ca48fdaf6e6ddf7664c6af146e746a06131cd8..1ba12bd29bc2b798dcabebf537d28a8cbe8ca612 100644 --- a/src/java.base/share/classes/java/lang/StringBuffer.java +++ b/src/java.base/share/classes/java/lang/StringBuffer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 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 @@ -26,7 +26,12 @@ package java.lang; import java.io.IOException; -import java.util.Arrays; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.ObjectStreamField; +import java.io.Serial; +import java.io.Serializable; +import java.io.StreamCorruptedException; import jdk.internal.vm.annotation.IntrinsicCandidate; /** @@ -106,7 +111,7 @@ import jdk.internal.vm.annotation.IntrinsicCandidate; */ public final class StringBuffer extends AbstractStringBuilder - implements java.io.Serializable, Comparable, CharSequence + implements Serializable, Comparable, CharSequence { /** @@ -116,7 +121,7 @@ import jdk.internal.vm.annotation.IntrinsicCandidate; private transient String toStringCache; /** use serialVersionUID from JDK 1.0.2 for interoperability */ - @java.io.Serial + @Serial static final long serialVersionUID = 3388685877147921107L; /** @@ -725,25 +730,25 @@ import jdk.internal.vm.annotation.IntrinsicCandidate; * A flag indicating whether the backing array is shared. * The value is ignored upon deserialization. */ - @java.io.Serial - private static final java.io.ObjectStreamField[] serialPersistentFields = + @Serial + private static final ObjectStreamField[] serialPersistentFields = { - new java.io.ObjectStreamField("value", char[].class), - new java.io.ObjectStreamField("count", Integer.TYPE), - new java.io.ObjectStreamField("shared", Boolean.TYPE), + new ObjectStreamField("value", char[].class), + new ObjectStreamField("count", Integer.TYPE), + new ObjectStreamField("shared", Boolean.TYPE), }; /** - * The {@code writeObject} method is called to write the state of the {@code StringBuffer} to - * a stream. + * The {@code writeObject} method is called to write the state of the + * {@code StringBuffer} to a stream. * * @param s the {@code ObjectOutputStream} to which data is written * @throws IOException if an I/O error occurs */ - @java.io.Serial - private synchronized void writeObject(java.io.ObjectOutputStream s) - throws java.io.IOException { - java.io.ObjectOutputStream.PutField fields = s.putFields(); + @Serial + private synchronized void writeObject(ObjectOutputStream s) + throws IOException { + ObjectOutputStream.PutField fields = s.putFields(); char[] val = new char[capacity()]; if (isLatin1()) { StringLatin1.getChars(value, 0, count, val, 0); @@ -757,20 +762,26 @@ import jdk.internal.vm.annotation.IntrinsicCandidate; } /** - * The {@code readObject} method is called to restore the state of the {@code StringBuffer} from - * a stream. + * The {@code readObject} method is called to restore the state of the + * {@code StringBuffer} from a 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 java.io.IOException, ClassNotFoundException { - java.io.ObjectInputStream.GetField fields = s.readFields(); + @Serial + private void readObject(ObjectInputStream s) + throws IOException, ClassNotFoundException { + ObjectInputStream.GetField fields = s.readFields(); + char[] val = (char[])fields.get("value", null); + int c = fields.get("count", 0); + if (c < 0 || c > val.length) { + throw new StreamCorruptedException("count value invalid"); + } initBytes(val, 0, val.length); - count = fields.get("count", 0); + count = c; + // ignore shared field } synchronized void getBytes(byte[] dst, int dstBegin, byte coder) { diff --git a/src/java.base/share/classes/java/lang/StringBuilder.java b/src/java.base/share/classes/java/lang/StringBuilder.java index b22ed99dbfc6b271db37e957826faf2dfa69fe16..8e759c213a9a80ae8631107feb6958c5fcf66bcb 100644 --- a/src/java.base/share/classes/java/lang/StringBuilder.java +++ b/src/java.base/share/classes/java/lang/StringBuilder.java @@ -28,6 +28,10 @@ package java.lang; import jdk.internal.vm.annotation.IntrinsicCandidate; import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serial; +import java.io.StreamCorruptedException; /** * A mutable sequence of characters. This class provides an API compatible @@ -90,7 +94,7 @@ public final class StringBuilder { /** use serialVersionUID for interoperability */ - @java.io.Serial + @Serial static final long serialVersionUID = 4383685877147921099L; /** @@ -464,9 +468,8 @@ public final class StringBuilder * @param s the {@code ObjectOutputStream} to which data is written * @throws IOException if an I/O error occurs */ - @java.io.Serial - private void writeObject(java.io.ObjectOutputStream s) - throws java.io.IOException { + @Serial + private void writeObject(ObjectOutputStream s) throws IOException { s.defaultWriteObject(); s.writeInt(count); char[] val = new char[capacity()]; @@ -486,13 +489,16 @@ public final class StringBuilder * @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 { + @Serial + private void readObject(ObjectInputStream s) + throws IOException, ClassNotFoundException { s.defaultReadObject(); - count = s.readInt(); + int c = s.readInt(); char[] val = (char[]) s.readObject(); + if (c < 0 || c > val.length) { + throw new StreamCorruptedException("count value invalid"); + } initBytes(val, 0, val.length); + count = c; } - } diff --git a/src/java.base/share/classes/java/lang/StringCoding.java b/src/java.base/share/classes/java/lang/StringCoding.java index ec81c3795799f1f91a41d3c373053007e8b565cc..293fbdb78dc85c6a272c4ffef9340944b83b41fb 100644 --- a/src/java.base/share/classes/java/lang/StringCoding.java +++ b/src/java.base/share/classes/java/lang/StringCoding.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -34,14 +34,27 @@ class StringCoding { private StringCoding() { } - @IntrinsicCandidate public static boolean hasNegatives(byte[] ba, int off, int len) { - for (int i = off; i < off + len; i++) { + return countPositives(ba, off, len) != len; + } + + /** + * Count the number of leading positive bytes in the range. + * + * @implSpec the implementation must return len if there are no negative + * bytes in the range. If there are negative bytes, the implementation must return + * a value that is less than or equal to the index of the first negative byte + * in the range. + */ + @IntrinsicCandidate + public static int countPositives(byte[] ba, int off, int len) { + int limit = off + len; + for (int i = off; i < limit; i++) { if (ba[i] < 0) { - return true; + return i - off; } } - return false; + return len; } @IntrinsicCandidate diff --git a/src/java.base/share/classes/java/lang/StringConcatHelper.java b/src/java.base/share/classes/java/lang/StringConcatHelper.java index f267fd9e1d6d9eb4e81b30b4cecaf295ba648f04..3867c10e8d6fcdead85bdc9b4f6d81dd31bd8177 100644 --- a/src/java.base/share/classes/java/lang/StringConcatHelper.java +++ b/src/java.base/share/classes/java/lang/StringConcatHelper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -430,7 +430,7 @@ final class StringConcatHelper { * Produce a String from a concatenation of single argument, which we * end up using for trivial concatenations like {@code "" + arg}. * - * This will always create a new Object to comply with JLS 15.18.1: + * This will always create a new Object to comply with JLS {@jls 15.18.1}: * "The String object is newly created unless the expression is a * compile-time constant expression". * diff --git a/src/java.base/share/classes/java/lang/StringUTF16.java b/src/java.base/share/classes/java/lang/StringUTF16.java index 29287aaa22cf1b8bf36af37a8ac7d214edf0fb89..b59b21fd1806205f5992fbe19009b72b1c0e237c 100644 --- a/src/java.base/share/classes/java/lang/StringUTF16.java +++ b/src/java.base/share/classes/java/lang/StringUTF16.java @@ -1549,13 +1549,9 @@ final class StringUTF16 { } // We know there are at most two digits left at this point. - q = i / 10; - r = (q * 10) - i; - putChar(buf, --charPos, '0' + r); - - // Whatever left is the remaining digit. - if (q < 0) { - putChar(buf, --charPos, '0' - q); + putChar(buf, --charPos, Integer.DigitOnes[-i]); + if (i < -9) { + putChar(buf, --charPos, Integer.DigitTens[-i]); } if (negative) { @@ -1604,13 +1600,9 @@ final class StringUTF16 { } // We know there are at most two digits left at this point. - q2 = i2 / 10; - r = (q2 * 10) - i2; - putChar(buf, --charPos, '0' + r); - - // Whatever left is the remaining digit. - if (q2 < 0) { - putChar(buf, --charPos, '0' - q2); + putChar(buf, --charPos, Integer.DigitOnes[-i2]); + if (i2 < -9) { + putChar(buf, --charPos, Integer.DigitTens[-i2]); } if (negative) { diff --git a/src/java.base/share/classes/java/lang/SuppressWarnings.java b/src/java.base/share/classes/java/lang/SuppressWarnings.java index 09ab6c4724b0b21d050eeb10ffcc6a0e25648aec..fd115fb8bef35ace0b2f875a614efa51bc9689ae 100644 --- a/src/java.base/share/classes/java/lang/SuppressWarnings.java +++ b/src/java.base/share/classes/java/lang/SuppressWarnings.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 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 @@ -29,21 +29,52 @@ import java.lang.annotation.*; import static java.lang.annotation.ElementType.*; /** - * Indicates that the named compiler warnings should be suppressed in the - * annotated element (and in all program elements contained in the annotated - * element). Note that the set of warnings suppressed in a given element is - * a superset of the warnings suppressed in all containing elements. For - * example, if you annotate a class to suppress one warning and annotate a - * method to suppress another, both warnings will be suppressed in the method. - * However, note that if a warning is suppressed in a {@code - * module-info} file, the suppression applies to elements within the - * file and not to types contained within the module. + * Indicates the warnings to be suppressed at compile time in the + * annotated element, and in all elements contained in the annotated + * element. * - *

      As a matter of style, programmers should always use this annotation - * on the most deeply nested element where it is effective. If you want to + *

      The {@code SuppressWarnings} annotation interface is applicable + * in all declaration contexts, so an {@code @SuppressWarnings} + * annotation can be used on any element. As a matter of style, + * programmers should always use this annotation on the most deeply + * nested element where it is effective. For example, if you want to * suppress a warning in a particular method, you should annotate that * method rather than its class. * + *

      The set of warnings suppressed in a given element is a union of + * the warnings suppressed in all containing elements. For example, + * if you annotate a class to suppress one warning and annotate a + * method in the class to suppress another, both warnings will be + * suppressed in the method. However, note that if a warning is + * suppressed in a {@code module-info} file, the suppression applies + * to elements within the file and not to types contained + * within the module. Likewise, if a warning is suppressed in a + * {@code package-info} file, the suppression applies to elements + * within the file and not to types contained within the + * package. + * + *

      Java compilers must recognize all the kinds of warnings defined + * in the Java Language Specification (JLS section {@jls + * 9.6.4.5}) which include: + * + *

        + *
      • Unchecked warnings, specified by the string {@code "unchecked"}. + *
      • Deprecation warnings, specified by the string {@code "deprecation"}. + *
      • Removal warnings, specified by the string {@code "removal"}. + *
      • Preview warnings, specified by the string {@code "preview"}. + *
      + * + * Whether or not a Java compiler recognizes other strings is a + * quality of implementation concern. Compiler vendors should + * document the additional warning names they support. Vendors are + * encouraged to cooperate to ensure that the same names work across + * multiple compilers. + * + * @implNote + * In addition to the mandated suppression strings, the {@code javac} + * reference implementation recognizes compilation-related warning + * names documented in its {@code --help-lint} output. + * * @author Josh Bloch * @since 1.5 * @jls 4.8 Raw Types @@ -52,7 +83,7 @@ import static java.lang.annotation.ElementType.*; * @jls 5.5 Casting Contexts * @jls 9.6.4.5 @SuppressWarnings */ -@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE, MODULE}) +// Implicitly target all declaration contexts by omitting a @Target annotation @Retention(RetentionPolicy.SOURCE) public @interface SuppressWarnings { /** @@ -63,12 +94,6 @@ public @interface SuppressWarnings { * ignore any warning names they do not recognize. They are, however, * free to emit a warning if an annotation contains an unrecognized * warning name. - * - *

      The string {@code "unchecked"} is used to suppress - * unchecked warnings. Compiler vendors should document the - * additional warning names they support in conjunction with this - * annotation type. They are encouraged to cooperate to ensure - * that the same names work across multiple compilers. * @return the set of warnings to be suppressed */ String[] value(); diff --git a/src/java.base/share/classes/java/lang/System.java b/src/java.base/share/classes/java/lang/System.java index 6d4137c7aa463966e81ffa4f222eb9c61c0f4fd3..96b32ecabb63e986abe4dc0b28229dab67fb9e64 100644 --- a/src/java.base/share/classes/java/lang/System.java +++ b/src/java.base/share/classes/java/lang/System.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 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 @@ -33,7 +33,6 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.PrintStream; -import java.io.UnsupportedEncodingException; import java.lang.annotation.Annotation; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodType; @@ -45,9 +44,9 @@ import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.net.URI; import java.net.URL; -import java.nio.charset.CharacterCodingException; import java.nio.channels.Channel; import java.nio.channels.spi.SelectorProvider; +import java.nio.charset.CharacterCodingException; import java.nio.charset.Charset; import java.security.AccessControlContext; import java.security.AccessController; @@ -84,6 +83,7 @@ import jdk.internal.vm.annotation.Stable; import sun.nio.fs.DefaultFileSystemProvider; import sun.reflect.annotation.AnnotationType; import sun.nio.ch.Interruptible; +import sun.nio.cs.UTF_8; import sun.security.util.SecurityConstants; /** @@ -188,6 +188,11 @@ public final class System { @SuppressWarnings("removal") private static volatile SecurityManager security; // read by VM + // `sun.jnu.encoding` if it is not supported. Otherwise null. + // It is initialized in `initPhase1()` before any charset providers + // are initialized. + private static String notSupportedJnuEncoding; + // return true if a security manager is allowed private static boolean allowSecurityManager() { return (allowSecurityManager != NEVER); @@ -1202,7 +1207,7 @@ public final class System { * Severity values and Mapping to {@code java.util.logging.Level}. *

      * {@linkplain System.Logger.Level System logger levels} are mapped to - * {@linkplain java.util.logging.Level java.util.logging levels} + * {@linkplain java.logging/java.util.logging.Level java.util.logging levels} * of corresponding severity. *
      The mapping is as follows: *

      @@ -1214,19 +1219,19 @@ public final class System { * * * {@link Logger.Level#ALL ALL} - * {@link java.util.logging.Level#ALL ALL} + * {@link java.logging/java.util.logging.Level#ALL ALL} * {@link Logger.Level#TRACE TRACE} - * {@link java.util.logging.Level#FINER FINER} + * {@link java.logging/java.util.logging.Level#FINER FINER} * {@link Logger.Level#DEBUG DEBUG} - * {@link java.util.logging.Level#FINE FINE} + * {@link java.logging/java.util.logging.Level#FINE FINE} * {@link Logger.Level#INFO INFO} - * {@link java.util.logging.Level#INFO INFO} + * {@link java.logging/java.util.logging.Level#INFO INFO} * {@link Logger.Level#WARNING WARNING} - * {@link java.util.logging.Level#WARNING WARNING} + * {@link java.logging/java.util.logging.Level#WARNING WARNING} * {@link Logger.Level#ERROR ERROR} - * {@link java.util.logging.Level#SEVERE SEVERE} + * {@link java.logging/java.util.logging.Level#SEVERE SEVERE} * {@link Logger.Level#OFF OFF} - * {@link java.util.logging.Level#OFF OFF} + * {@link java.logging/java.util.logging.Level#OFF OFF} * * * @@ -1235,6 +1240,7 @@ public final class System { * @see java.lang.System.LoggerFinder * @see java.lang.System.Logger */ + @SuppressWarnings("doclint:reference") // cross-module links public enum Level { // for convenience, we're reusing java.util.logging.Level int values @@ -1537,7 +1543,7 @@ public final class System { * {@code java.util.logging} as the backend framework when the * {@code java.logging} module is present. * It returns a {@linkplain System.Logger logger} instance - * that will route log messages to a {@link java.util.logging.Logger + * that will route log messages to a {@link java.logging/java.util.logging.Logger * java.util.logging.Logger}. Otherwise, if {@code java.logging} is not * present, the default implementation will return a simple logger * instance that will route log messages of {@code INFO} level and above to @@ -1551,7 +1557,7 @@ public final class System { * logging backend, and usually requires using APIs specific to that backend. *

      For the default {@code LoggerFinder} implementation * using {@code java.util.logging} as its backend, refer to - * {@link java.util.logging java.util.logging} for logging configuration. + * {@link java.logging/java.util.logging java.util.logging} for logging configuration. * For the default {@code LoggerFinder} implementation returning simple loggers * when the {@code java.logging} module is absent, the configuration * is implementation dependent. @@ -1586,7 +1592,7 @@ public final class System { * System.Logger.Level} to a level supported by the logging backend it uses. *
      The default LoggerFinder using {@code java.util.logging} as the backend * maps {@code System.Logger} levels to - * {@linkplain java.util.logging.Level java.util.logging} levels + * {@linkplain java.logging/java.util.logging.Level java.util.logging} levels * of corresponding severity - as described in {@link Logger.Level * Logger.Level}. * @@ -1595,6 +1601,7 @@ public final class System { * * @since 9 */ + @SuppressWarnings("doclint:reference") // cross-module links public abstract static class LoggerFinder { /** * The {@code RuntimePermission("loggerFinder")} is @@ -1917,8 +1924,18 @@ public final class System { * Runtime.getRuntime().runFinalization() * * + * @deprecated Finalization has been deprecated for removal. See + * {@link java.lang.Object#finalize} for background information and details + * about migration options. + *

      + * When running in a JVM in which finalization has been disabled or removed, + * no objects will be pending finalization, so this method does nothing. + * * @see java.lang.Runtime#runFinalization() + * @jls 12.6 Finalization of Class Instances */ + @Deprecated(since="18", forRemoval=true) + @SuppressWarnings("removal") public static void runFinalization() { Runtime.getRuntime().runFinalization(); } @@ -2017,10 +2034,9 @@ public final class System { * Create PrintStream for stdout/err based on encoding. */ private static PrintStream newPrintStream(FileOutputStream fos, String enc) { - if (enc != null) { - try { - return new PrintStream(new BufferedOutputStream(fos, 128), true, enc); - } catch (UnsupportedEncodingException uee) {} + if (enc != null) { + return new PrintStream(new BufferedOutputStream(fos, 128), true, + Charset.forName(enc, UTF_8.INSTANCE)); } return new PrintStream(new BufferedOutputStream(fos, 128), true); } @@ -2113,6 +2129,13 @@ public final class System { VM.saveProperties(tempProps); props = createProperties(tempProps); + // Check if sun.jnu.encoding is supported. If not, replace it with UTF-8. + var jnuEncoding = props.getProperty("sun.jnu.encoding"); + if (jnuEncoding == null || !Charset.isSupported(jnuEncoding)) { + notSupportedJnuEncoding = jnuEncoding == null ? "null" : jnuEncoding; + props.setProperty("sun.jnu.encoding", "UTF-8"); + } + StaticProperty.javaHome(); // Load StaticProperty to cache the property values lineSeparator = props.getProperty("line.separator"); @@ -2141,7 +2164,6 @@ public final class System { Thread current = Thread.currentThread(); current.getThreadGroup().add(current); - // Subsystems that are invoked during initialization can invoke // VM.isBooted() in order to avoid doing things that should // wait until the VM is fully initialized. The initialization level @@ -2248,6 +2270,14 @@ public final class System { WARNING: The Security Manager is deprecated and will be removed in a future release"""); } + // Emit a warning if `sun.jnu.encoding` is not supported. + if (notSupportedJnuEncoding != null) { + System.err.println( + "WARNING: The encoding of the underlying platform's" + + " file system is not supported: " + + notSupportedJnuEncoding); + } + initialErrStream = System.err; // initializing the system class loader @@ -2303,7 +2333,7 @@ public final class System { public Thread newThreadWithAcc(Runnable target, @SuppressWarnings("removal") AccessControlContext acc) { return new Thread(target, acc); } - @SuppressWarnings("deprecation") + @SuppressWarnings("removal") public void invokeFinalize(Object o) throws Throwable { o.finalize(); } diff --git a/src/java.base/share/classes/java/lang/Thread.java b/src/java.base/share/classes/java/lang/Thread.java index 17580d2aa8441c08efae7574c6fee301627c439e..0d41973b99e42884622acc54320b818aa963e891 100644 --- a/src/java.base/share/classes/java/lang/Thread.java +++ b/src/java.base/share/classes/java/lang/Thread.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 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 @@ -25,16 +25,11 @@ package java.lang; -import java.lang.ref.Reference; -import java.lang.ref.ReferenceQueue; -import java.lang.ref.WeakReference; import java.security.AccessController; import java.security.AccessControlContext; import java.security.PrivilegedAction; import java.util.Map; import java.util.HashMap; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.LockSupport; @@ -922,7 +917,7 @@ public class Thread implements Runnable { * Why * are Thread.stop, Thread.suspend and Thread.resume Deprecated?. */ - @Deprecated(since="1.2") + @Deprecated(since="1.2", forRemoval=true) public final void stop() { @SuppressWarnings("removal") SecurityManager security = System.getSecurityManager(); @@ -1672,16 +1667,15 @@ public class Thread implements Runnable { } /** cache of subclass security audit results */ - /* Replace with ConcurrentReferenceHashMap when/if it appears in a future - * release */ private static class Caches { /** cache of subclass security audit results */ - static final ConcurrentMap subclassAudits = - new ConcurrentHashMap<>(); - - /** queue for WeakReferences to audited subclasses */ - static final ReferenceQueue> subclassAuditsQueue = - new ReferenceQueue<>(); + static final ClassValue subclassAudits = + new ClassValue<>() { + @Override + protected Boolean computeValue(Class type) { + return auditSubclass(type); + } + }; } /** @@ -1694,15 +1688,7 @@ public class Thread implements Runnable { if (cl == Thread.class) return false; - processQueue(Caches.subclassAuditsQueue, Caches.subclassAudits); - WeakClassKey key = new WeakClassKey(cl, Caches.subclassAuditsQueue); - Boolean result = Caches.subclassAudits.get(key); - if (result == null) { - result = Boolean.valueOf(auditSubclass(cl)); - Caches.subclassAudits.putIfAbsent(key, result); - } - - return result.booleanValue(); + return Caches.subclassAudits.get(cl); } /** @@ -1976,8 +1962,8 @@ public class Thread implements Runnable { * @return the uncaught exception handler for this thread */ public UncaughtExceptionHandler getUncaughtExceptionHandler() { - return uncaughtExceptionHandler != null ? - uncaughtExceptionHandler : group; + UncaughtExceptionHandler handler = this.uncaughtExceptionHandler; + return handler != null ? handler : group; } /** @@ -2008,69 +1994,6 @@ public class Thread implements Runnable { getUncaughtExceptionHandler().uncaughtException(this, e); } - /** - * Removes from the specified map any keys that have been enqueued - * on the specified reference queue. - */ - static void processQueue(ReferenceQueue> queue, - ConcurrentMap>, ?> map) - { - Reference> ref; - while((ref = queue.poll()) != null) { - map.remove(ref); - } - } - - /** - * Weak key for Class objects. - **/ - static class WeakClassKey extends WeakReference> { - /** - * saved value of the referent's identity hash code, to maintain - * a consistent hash code after the referent has been cleared - */ - private final int hash; - - /** - * Create a new WeakClassKey to the given object, registered - * with a queue. - */ - WeakClassKey(Class cl, ReferenceQueue> refQueue) { - super(cl, refQueue); - hash = System.identityHashCode(cl); - } - - /** - * Returns the identity hash code of the original referent. - */ - @Override - public int hashCode() { - return hash; - } - - /** - * Returns true if the given object is this identical - * WeakClassKey instance, or, if this object's referent has not - * been cleared, if the given object is another WeakClassKey - * instance with the identical non-null referent as this one. - */ - @Override - public boolean equals(Object obj) { - if (obj == this) - return true; - - if (obj instanceof WeakClassKey) { - Class referent = get(); - return (referent != null) && - (((WeakClassKey) obj).refersTo(referent)); - } else { - return false; - } - } - } - - // The following three initially uninitialized fields are exclusively // managed by class java.util.concurrent.ThreadLocalRandom. These // fields are used to build the high-performance PRNGs in the diff --git a/src/java.base/share/classes/java/lang/ThreadGroup.java b/src/java.base/share/classes/java/lang/ThreadGroup.java index c6e532a74448925cf4892b9631cfe81b072c7de7..bd55ca1595e5b202fd414e9c84a490f89a126b9f 100644 --- a/src/java.base/share/classes/java/lang/ThreadGroup.java +++ b/src/java.base/share/classes/java/lang/ThreadGroup.java @@ -628,6 +628,7 @@ public class ThreadGroup implements Thread.UncaughtExceptionHandler { * {@link Thread#stop} for details. */ @Deprecated(since="1.2", forRemoval=true) + @SuppressWarnings("removal") public final void stop() { if (stopOrSuspend(false)) Thread.currentThread().stop(); diff --git a/src/java.base/share/classes/java/lang/annotation/ElementType.java b/src/java.base/share/classes/java/lang/annotation/ElementType.java index c046272b12c7b12d1ef75bd3b305b7269b4c1695..97275fb97ec8b6fe31d1293727f169075f106045 100644 --- a/src/java.base/share/classes/java/lang/annotation/ElementType.java +++ b/src/java.base/share/classes/java/lang/annotation/ElementType.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -40,14 +40,14 @@ package java.lang.annotation; *

      The constants {@link #ANNOTATION_TYPE}, {@link #CONSTRUCTOR}, {@link * #FIELD}, {@link #LOCAL_VARIABLE}, {@link #METHOD}, {@link #PACKAGE}, {@link * #MODULE}, {@link #PARAMETER}, {@link #TYPE}, and {@link #TYPE_PARAMETER} - * correspond to the declaration contexts in JLS 9.6.4.1. + * correspond to the declaration contexts in JLS {@jls 9.6.4.1}. * *

      For example, an annotation whose interface is meta-annotated with * {@code @Target(ElementType.FIELD)} may only be written as a modifier for a * field declaration. * *

      The constant {@link #TYPE_USE} corresponds to the type contexts in JLS - * 4.11, as well as to two declaration contexts: class and interface + * {@jls 4.11}, as well as to two declaration contexts: class and interface * declarations (including annotation declarations) and type parameter * declarations. * 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 14923594c0e1bc24cbfbce13bc91596dcd0495ac..6742b622a40c998a38ee52228622b95befb18205 100644 --- a/src/java.base/share/classes/java/lang/constant/ClassDesc.java +++ b/src/java.base/share/classes/java/lang/constant/ClassDesc.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -116,7 +116,7 @@ public sealed interface ClassDesc * followed by the field descriptor for the component type. Examples of * valid type descriptor strings include {@code "Ljava/lang/String;"}, {@code "I"}, * {@code "[I"}, {@code "V"}, {@code "[Ljava/lang/String;"}, etc. - * See JVMS 4.3.2 ("Field Descriptors") for more detail. + * See JVMS {@jvms 4.3.2 }("Field Descriptors") for more detail. * * @param descriptor a field descriptor string * @return a {@linkplain ClassDesc} describing the desired class @@ -148,7 +148,8 @@ public sealed interface ClassDesc * is described by this {@linkplain ClassDesc}. * * @return a {@linkplain ClassDesc} describing the array type - * @throws IllegalStateException if the resulting {@linkplain ClassDesc} would have an array rank of greater than 255 + * @throws IllegalStateException if the resulting {@linkplain + * ClassDesc} would have an array rank of greater than 255 * @jvms 4.4.1 The CONSTANT_Class_info Structure */ default ClassDesc arrayType() { @@ -167,14 +168,27 @@ public sealed interface ClassDesc * * @param rank the rank of the array * @return a {@linkplain ClassDesc} describing the array type - * @throws IllegalArgumentException if the rank is less than or equal to zero or if the rank of the resulting array type is + * @throws IllegalArgumentException if the rank is less than or + * equal to zero or if the rank of the resulting array type is * greater than 255 * @jvms 4.4.1 The CONSTANT_Class_info Structure */ default ClassDesc arrayType(int rank) { - int currentDepth = ConstantUtils.arrayDepth(descriptorString()); - if (rank <= 0 || currentDepth + rank > ConstantUtils.MAX_ARRAY_TYPE_DESC_DIMENSIONS) - throw new IllegalArgumentException("rank: " + currentDepth + rank); + int netRank; + if (rank <= 0) { + throw new IllegalArgumentException("rank " + rank + " is not a positive value"); + } + try { + int currentDepth = ConstantUtils.arrayDepth(descriptorString()); + netRank = Math.addExact(currentDepth, rank); + if (netRank > ConstantUtils.MAX_ARRAY_TYPE_DESC_DIMENSIONS) { + throw new IllegalArgumentException("rank: " + netRank + + " exceeds maximum supported dimension of " + + ConstantUtils.MAX_ARRAY_TYPE_DESC_DIMENSIONS); + } + } catch (ArithmeticException ae) { + throw new IllegalArgumentException("Integer overflow in rank computation"); + } return ClassDesc.ofDescriptor("[".repeat(rank) + descriptorString()); } diff --git a/src/java.base/share/classes/java/lang/constant/Constable.java b/src/java.base/share/classes/java/lang/constant/Constable.java index 33875654c05404d7e1fb8eeb96844626b9d235d7..e404dff6e4ba8a89ad035f89f1e88a71b816f8fb 100644 --- a/src/java.base/share/classes/java/lang/constant/Constable.java +++ b/src/java.base/share/classes/java/lang/constant/Constable.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -32,7 +32,7 @@ import java.util.Optional; /** * Represents a type which is constable. A constable type is one whose * values are constants that can be represented in the constant pool of a Java - * classfile as described in JVMS 4.4, and whose instances can describe themselves + * classfile as described in JVMS {@jvms 4.4}, and whose instances can describe themselves * nominally as a {@link ConstantDesc}. * *

      Some constable types have a native representation in the constant pool: @@ -48,7 +48,7 @@ import java.util.Optional; * Platform API are types that support Java language features such as {@link Enum}, * and runtime support classes such as {@link VarHandle}. These are typically * described with a {@link DynamicConstantDesc}, which describes dynamically - * generated constants (JVMS 4.4.10). + * generated constants (JVMS {@jvms 4.4.10}). * *

      The nominal form of an instance of a constable type is obtained via * {@link #describeConstable()}. A {@linkplain Constable} need diff --git a/src/java.base/share/classes/java/lang/constant/ConstantDesc.java b/src/java.base/share/classes/java/lang/constant/ConstantDesc.java index 70c5f8fcb558be811518d5c5b0b94249e2501ad4..401119989a9527b2a49542157d831ad79377b4bc 100644 --- a/src/java.base/share/classes/java/lang/constant/ConstantDesc.java +++ b/src/java.base/share/classes/java/lang/constant/ConstantDesc.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -32,7 +32,7 @@ import java.lang.invoke.VarHandle.VarHandleDesc; /** * A nominal descriptor for a loadable - * constant value, as defined in JVMS 4.4. Such a descriptor can be resolved via + * constant value, as defined in JVMS {@jvms 4.4}. Such a descriptor can be resolved via * {@link ConstantDesc#resolveConstantDesc(MethodHandles.Lookup)} to yield the * constant value itself. * @@ -87,7 +87,7 @@ public sealed interface ConstantDesc String { /** * Resolves this descriptor reflectively, emulating the resolution behavior - * of JVMS 5.4.3 and the access control behavior of JVMS 5.4.4. The resolution + * of JVMS {@jvms 5.4.3} and the access control behavior of JVMS {@jvms 5.4.4}. The resolution * and access control context is provided by the {@link MethodHandles.Lookup} * parameter. No caching of the resulting value is performed. * diff --git a/src/java.base/share/classes/java/lang/constant/package-info.java b/src/java.base/share/classes/java/lang/constant/package-info.java index 9bc978e44a192e0415d550f16d1a50cf7acfe565..fd85dfb93d74290ceb126d730856b5111d00bb46 100644 --- a/src/java.base/share/classes/java/lang/constant/package-info.java +++ b/src/java.base/share/classes/java/lang/constant/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -55,7 +55,7 @@ * referenced in their nominal description are present and accessible. * *

      The subtypes of {@link java.lang.constant.ConstantDesc} describe various kinds - * of constant values. For each type of loadable constant pool entry defined in JVMS 4.4, + * of constant values. For each type of loadable constant pool entry defined in JVMS {@jvms 4.4}, * there is a corresponding subtype of {@link java.lang.constant.ConstantDesc}: * {@link java.lang.constant.ClassDesc}, {@link java.lang.constant.MethodTypeDesc}, * {@link java.lang.constant.DirectMethodHandleDesc}, {@link java.lang.String}, diff --git a/src/java.base/share/classes/java/lang/invoke/CallSite.java b/src/java.base/share/classes/java/lang/invoke/CallSite.java index e159e235f30a30830bd263952566974d8bc61c91..ec002e1fc460aa4d4bf5ef378f14f608c1cde76a 100644 --- a/src/java.base/share/classes/java/lang/invoke/CallSite.java +++ b/src/java.base/share/classes/java/lang/invoke/CallSite.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 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 @@ -40,9 +40,9 @@ import jdk.internal.vm.annotation.Stable; * In any case, it may be invoked through an associated method handle * called its {@linkplain #dynamicInvoker dynamic invoker}. *

      - * {@code CallSite} is an abstract class which does not allow + * {@code CallSite} is an abstract sealed class which does not allow * direct subclassing by users. It has three immediate, - * concrete subclasses that may be either instantiated or subclassed. + * concrete non-sealed subclasses that may be either instantiated or subclassed. *

        *
      • If a mutable target is not required, an {@code invokedynamic} instruction * may be permanently bound by means of a {@linkplain ConstantCallSite constant call site}. @@ -85,7 +85,7 @@ private static CallSite bootstrapDynamic(MethodHandles.Lookup caller, String nam * @since 1.7 */ public -abstract class CallSite { +abstract sealed class CallSite permits ConstantCallSite, MutableCallSite, VolatileCallSite { // The actual payload of this call site. // Can be modified using {@link MethodHandleNatives#setCallSiteTargetNormal} or {@link MethodHandleNatives#setCallSiteTargetVolatile}. diff --git a/src/java.base/share/classes/java/lang/invoke/ConstantBootstraps.java b/src/java.base/share/classes/java/lang/invoke/ConstantBootstraps.java index 27d74284dc6d4361fd0f27a452332fa2d569a41b..b3858104e21e4cac947671dd26ff90c0dfd84114 100644 --- a/src/java.base/share/classes/java/lang/invoke/ConstantBootstraps.java +++ b/src/java.base/share/classes/java/lang/invoke/ConstantBootstraps.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -96,7 +96,7 @@ public final class ConstantBootstraps { * descriptor is specified by {@code name}. * * @param lookup unused - * @param name the descriptor (JVMS 4.3) of the desired primitive type + * @param name the descriptor (JVMS {@jvms 4.3}) of the desired primitive type * @param type the required result type (must be {@code Class.class}) * @return the {@link Class} mirror * @throws IllegalArgumentException if the name is not a descriptor for a diff --git a/src/java.base/share/classes/java/lang/invoke/ConstantCallSite.java b/src/java.base/share/classes/java/lang/invoke/ConstantCallSite.java index e2e3f478a3c864af83d5218218df0fc36cff490e..29e557ad141b2065f33c67bd5c5a0ab058417f7c 100644 --- a/src/java.base/share/classes/java/lang/invoke/ConstantCallSite.java +++ b/src/java.base/share/classes/java/lang/invoke/ConstantCallSite.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 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 @@ -35,7 +35,7 @@ import jdk.internal.vm.annotation.Stable; * @author John Rose, JSR 292 EG * @since 1.7 */ -public class ConstantCallSite extends CallSite { +public non-sealed class ConstantCallSite extends CallSite { private static final Unsafe UNSAFE = Unsafe.getUnsafe(); @Stable // should NOT be constant folded during instance initialization (isFrozen == false) 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 c687916dde4926ce50b2c70939fd7e0c7a6e056e..ca5bf8a765634b74bfa40cbff616b25b7b250183 100644 --- a/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java +++ b/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java @@ -683,6 +683,7 @@ class InvokerBytecodeGenerator { } private static MemberName resolveFrom(String name, MethodType type, Class holder) { + assert(!UNSAFE.shouldBeInitialized(holder)) : holder + "not initialized"; MemberName member = new MemberName(holder, name, type, REF_invokeStatic); MemberName resolvedMember = MemberName.getFactory().resolveOrNull(REF_invokeStatic, member, holder, LM_TRUSTED); traceLambdaForm(name, type, holder, resolvedMember); diff --git a/src/java.base/share/classes/java/lang/invoke/MemoryAccessVarHandleBase.java b/src/java.base/share/classes/java/lang/invoke/MemoryAccessVarHandleBase.java index 59098e9fa74dcd720ed825f7397b5de788beefd7..7703c997fc3393788f444a02c04e330f223dbd5e 100644 --- a/src/java.base/share/classes/java/lang/invoke/MemoryAccessVarHandleBase.java +++ b/src/java.base/share/classes/java/lang/invoke/MemoryAccessVarHandleBase.java @@ -50,7 +50,7 @@ abstract class MemoryAccessVarHandleBase extends VarHandle { this.alignmentMask = alignmentMask; } - static IllegalStateException newIllegalStateExceptionForMisalignedAccess(long address) { - return new IllegalStateException("Misaligned access at address: " + address); + static IllegalArgumentException newIllegalArgumentExceptionForMisalignedAccess(long address) { + return new IllegalArgumentException("Misaligned access at address: " + address); } } 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 ec910dbf8fe34598c1ba9ec0b9eebf7bab2daabb..fb7ef0afbac3f9be8d74e24880bc6ea621cc7368 100644 --- a/src/java.base/share/classes/java/lang/invoke/MethodHandle.java +++ b/src/java.base/share/classes/java/lang/invoke/MethodHandle.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 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 @@ -807,15 +807,15 @@ public abstract class MethodHandle implements Constable { * (The types do not need to be related in any particular way. * This is because a dynamic value of null can convert to any reference type.) *
      • If T0 and T1 are primitives, then a Java method invocation - * conversion (JLS 5.3) is applied, if one exists. + * conversion (JLS {@jls 5.3}) is applied, if one exists. * (Specifically, T0 must convert to T1 by a widening primitive conversion.) *
      • If T0 is a primitive and T1 a reference, - * a Java casting conversion (JLS 5.5) is applied if one exists. + * a Java casting conversion (JLS {@jls 5.5}) is applied if one exists. * (Specifically, the value is boxed from T0 to its wrapper class, * which is then widened as needed to T1.) *
      • If T0 is a reference and T1 a primitive, an unboxing * conversion will be applied at runtime, possibly followed - * by a Java method invocation conversion (JLS 5.3) + * by a Java method invocation conversion (JLS {@jls 5.3}) * on the primitive value. (These are the primitive widening conversions.) * T0 must be a wrapper class or a supertype of one. * (In the case where T0 is Object, these are the conversions 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 a428380443ee650e211d05558add277ef0f07eb0..404782c047e2ae418d95bc2128022bc1b2748e1a 100644 --- a/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java +++ b/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java @@ -1667,6 +1667,10 @@ abstract class MethodHandleImpl { return caller.makeHiddenClassDefiner(name, bytes, Set.of()).defineClassAsLookup(initialize, classData); } + @Override + public Class[] exceptionTypes(MethodHandle handle) { + return VarHandles.exceptionTypes(handle); + } }); } @@ -2273,15 +2277,16 @@ abstract class MethodHandleImpl { // Indexes into constant method handles: static final int - MH_cast = 0, - MH_selectAlternative = 1, - MH_countedLoopPred = 2, - MH_countedLoopStep = 3, - MH_initIterator = 4, - MH_iteratePred = 5, - MH_iterateNext = 6, - MH_Array_newInstance = 7, - MH_LIMIT = 8; + MH_cast = 0, + MH_selectAlternative = 1, + MH_countedLoopPred = 2, + MH_countedLoopStep = 3, + MH_initIterator = 4, + MH_iteratePred = 5, + MH_iterateNext = 6, + MH_Array_newInstance = 7, + MH_VarHandles_handleCheckedExceptions = 8, + MH_LIMIT = 9; static MethodHandle getConstantHandle(int idx) { MethodHandle handle = HANDLES[idx]; @@ -2331,6 +2336,9 @@ abstract class MethodHandleImpl { case MH_Array_newInstance: return IMPL_LOOKUP.findStatic(Array.class, "newInstance", MethodType.methodType(Object.class, Class.class, int.class)); + case MH_VarHandles_handleCheckedExceptions: + return IMPL_LOOKUP.findStatic(VarHandles.class, "handleCheckedExceptions", + MethodType.methodType(void.class, Throwable.class)); } } catch (ReflectiveOperationException ex) { throw newInternalError(ex); 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 4dd2b1fce7ecb5c9a6e2e513db8ad9dd85ded2a4..69d975a7289012e282494d8805571026990ac656 100644 --- a/src/java.base/share/classes/java/lang/invoke/MethodHandleProxies.java +++ b/src/java.base/share/classes/java/lang/invoke/MethodHandleProxies.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 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 @@ -28,9 +28,11 @@ package java.lang.invoke; import java.lang.reflect.*; import java.security.AccessController; import java.security.PrivilegedAction; + +import jdk.internal.access.JavaLangReflectAccess; +import jdk.internal.access.SharedSecrets; import sun.invoke.WrapperInstance; import java.util.ArrayList; -import java.util.concurrent.ConcurrentHashMap; import jdk.internal.reflect.CallerSensitive; import jdk.internal.reflect.Reflection; @@ -88,7 +90,7 @@ public class MethodHandleProxies { * Therefore, each instance must implement a unique single-method interface. * Implementations may not bundle together * multiple single-method interfaces onto single implementation classes - * in the style of {@link java.awt.AWTEventMulticaster}. + * in the style of {@link java.desktop/java.awt.AWTEventMulticaster}. *

        * The method handle may throw an undeclared exception, * which means any checked exception (or other checked throwable) @@ -152,7 +154,8 @@ public class MethodHandleProxies { // entry points, must be covered by hand-written or automatically // generated adapter classes. // - @SuppressWarnings("removal") + @SuppressWarnings({"removal", + "doclint:reference"}) // cross-module links @CallerSensitive public static T asInterfaceInstance(final Class intfc, final MethodHandle target) { if (!intfc.isInterface() || !Modifier.isPublic(intfc.getModifiers())) @@ -184,8 +187,6 @@ public class MethodHandleProxies { checkTarget = checkTarget.asType(checkTarget.type().changeReturnType(Object.class)); vaTargets[i] = checkTarget.asSpreader(Object[].class, smMT.parameterCount()); } - final ConcurrentHashMap defaultMethodMap = - hasDefaultMethods(intfc) ? new ConcurrentHashMap<>() : null; final InvocationHandler ih = new InvocationHandler() { private Object getArg(String name) { if ((Object)name == "getWrapperInstanceTarget") return target; @@ -202,7 +203,8 @@ public class MethodHandleProxies { if (isObjectMethod(method)) return callObjectMethod(proxy, method, args); if (isDefaultMethod(method)) { - return callDefaultMethod(defaultMethodMap, proxy, intfc, method, args); + // no additional access check is performed + return JLRA.invokeDefault(proxy, method, args, null); } throw newInternalError("bad proxy method: "+method); } @@ -292,7 +294,7 @@ public class MethodHandleProxies { private static Object callObjectMethod(Object self, Method m, Object[] args) { assert(isObjectMethod(m)) : m; return switch (m.getName()) { - case "toString" -> self.getClass().getName() + "@" + Integer.toHexString(self.hashCode()); + case "toString" -> java.util.Objects.toIdentityString(self); case "hashCode" -> System.identityHashCode(self); case "equals" -> (self == args[0]); default -> null; @@ -320,37 +322,5 @@ public class MethodHandleProxies { return !Modifier.isAbstract(m.getModifiers()); } - private static boolean hasDefaultMethods(Class intfc) { - for (Method m : intfc.getMethods()) { - if (!isObjectMethod(m) && - !Modifier.isAbstract(m.getModifiers())) { - return true; - } - } - return false; - } - - private static Object callDefaultMethod(ConcurrentHashMap defaultMethodMap, - Object self, Class intfc, Method m, Object[] args) throws Throwable { - assert(isDefaultMethod(m) && !isObjectMethod(m)) : m; - - // Lazily compute the associated method handle from the method - MethodHandle dmh = defaultMethodMap.computeIfAbsent(m, mk -> { - try { - // Look up the default method for special invocation thereby - // avoiding recursive invocation back to the proxy - MethodHandle mh = MethodHandles.Lookup.IMPL_LOOKUP.findSpecial( - intfc, mk.getName(), - MethodType.methodType(mk.getReturnType(), mk.getParameterTypes()), - self.getClass()); - return mh.asSpreader(Object[].class, mk.getParameterCount()); - } catch (NoSuchMethodException | IllegalAccessException e) { - // The method is known to exist and should be accessible, this - // method would not be called unless the invokeinterface to the - // default (public) method passed access control checks - throw new InternalError(e); - } - }); - return dmh.invoke(self, args); - } + private static final JavaLangReflectAccess JLRA = SharedSecrets.getJavaLangReflectAccess(); } 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 743ebb6675996de06691fbb2cbded1afef2d46fc..7488db060d23521cf6b1072d117af1d564018b8f 100644 --- a/src/java.base/share/classes/java/lang/invoke/MethodHandles.java +++ b/src/java.base/share/classes/java/lang/invoke/MethodHandles.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 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 @@ -109,14 +109,25 @@ public class MethodHandles { *

        * This method is caller sensitive, which means that it may return different * values to different callers. + * In cases where {@code MethodHandles.lookup} is called from a context where + * there is no caller frame on the stack (e.g. when called directly + * from a JNI attached thread), {@code IllegalCallerException} is thrown. + * To obtain a {@link Lookup lookup object} in such a context, use an auxiliary class that will + * implicitly be identified as the caller, or use {@link MethodHandles#publicLookup()} + * to obtain a low-privileged lookup instead. * @return a lookup object for the caller of this method, with * {@linkplain Lookup#ORIGINAL original} and * {@linkplain Lookup#hasFullPrivilegeAccess() full privilege access}. + * @throws IllegalCallerException if there is no caller frame on the stack. */ @CallerSensitive @ForceInline // to ensure Reflection.getCallerClass optimization public static Lookup lookup() { - return new Lookup(Reflection.getCallerClass()); + final Class c = Reflection.getCallerClass(); + if (c == null) { + throw new IllegalCallerException("no caller frame"); + } + return new Lookup(c); } /** @@ -1873,7 +1884,7 @@ public class MethodHandles { * as a normal class or interface has with its own defining loader. * This means that the hidden class may be unloaded if and only if * its defining loader is not reachable and thus may be reclaimed - * by a garbage collector (JLS 12.7). + * by a garbage collector (JLS {@jls 12.7}). * *

        By default, a hidden class or interface may be unloaded * even if the class loader that is marked as its defining loader is @@ -2002,7 +2013,7 @@ public class MethodHandles { * there is no internal form available to record in any class's constant pool. * A hidden class or interface is not discoverable by {@link Class#forName(String, boolean, ClassLoader)}, * {@link ClassLoader#loadClass(String, boolean)}, or {@link #findClass(String)}, and - * is not {@linkplain java.lang.instrument.Instrumentation#isModifiableClass(Class) + * is not {@linkplain java.instrument/java.lang.instrument.Instrumentation#isModifiableClass(Class) * modifiable} by Java agents or tool agents using the * JVM Tool Interface. * @@ -2013,7 +2024,7 @@ public class MethodHandles { * that {@linkplain Class#getClassLoader() defined it}. * This means that a class created by a class loader may be unloaded if and * only if its defining loader is not reachable and thus may be reclaimed - * by a garbage collector (JLS 12.7). + * by a garbage collector (JLS {@jls 12.7}). * * By default, however, a hidden class or interface may be unloaded even if * the class loader that is marked as its defining loader is @@ -2105,6 +2116,7 @@ public class MethodHandles { * @jvms 5.5 Initialization * @jls 12.7 Unloading of Classes and Interfaces */ + @SuppressWarnings("doclint:reference") // cross-module links public Lookup defineHiddenClass(byte[] bytes, boolean initialize, ClassOption... options) throws IllegalAccessException { @@ -2747,7 +2759,7 @@ assertEquals("[x, y, z]", pb.command().toString()); /** * Looks up a class by name from the lookup context defined by this {@code Lookup} object, * as if resolved by an {@code ldc} instruction. - * Such a resolution, as specified in JVMS 5.4.3.1 section, attempts to locate and load the class, + * Such a resolution, as specified in JVMS {@jvms 5.4.3.1}, attempts to locate and load the class, * and then determines whether the class is accessible to this lookup object. *

        * The lookup context here is determined by the {@linkplain #lookupClass() lookup class}, @@ -4745,15 +4757,15 @@ return invoker; * the boolean is converted to a byte value, 1 for true, 0 for false. * (This treatment follows the usage of the bytecode verifier.) *

      • If T1 is boolean and T0 is another primitive, - * T0 is converted to byte via Java casting conversion (JLS 5.5), + * T0 is converted to byte via Java casting conversion (JLS {@jls 5.5}), * and the low order bit of the result is tested, as if by {@code (x & 1) != 0}. *
      • If T0 and T1 are primitives other than boolean, - * then a Java casting conversion (JLS 5.5) is applied. + * then a Java casting conversion (JLS {@jls 5.5}) is applied. * (Specifically, T0 will convert to T1 by * widening and/or narrowing.) *
      • If T0 is a reference and T1 a primitive, an unboxing * conversion will be applied at runtime, possibly followed - * by a Java casting conversion (JLS 5.5) on the primitive value, + * by a Java casting conversion (JLS {@jls 5.5}) on the primitive value, * possibly followed by a conversion from byte to boolean by testing * the low-order bit. *
      • If T0 is a reference and T1 a primitive, diff --git a/src/java.base/share/classes/java/lang/invoke/MutableCallSite.java b/src/java.base/share/classes/java/lang/invoke/MutableCallSite.java index c16483d02ae5e87ad6e2ed5ebecddd889bd10145..50ba77d8f96f97add99f969df17bea3937f6deb5 100644 --- a/src/java.base/share/classes/java/lang/invoke/MutableCallSite.java +++ b/src/java.base/share/classes/java/lang/invoke/MutableCallSite.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 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 @@ -83,7 +83,7 @@ assertEquals("Wilma, dear?", (String) worker2.invokeExact()); * @author John Rose, JSR 292 EG * @since 1.7 */ -public class MutableCallSite extends CallSite { +public non-sealed class MutableCallSite extends CallSite { /** * Creates a blank call site object with the given method type. * The initial target is set to a method handle of the given type 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 5ff0cf84aecc6aae1c6e0af163b6874f7d976c11..7026591190ebc3a27409c47980943dee5f75f6c9 100644 --- a/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java +++ b/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -142,10 +142,10 @@ public final class StringConcatFactory { *
          *
        • zero inputs, concatenation results in an empty string;
        • *
        • one input, concatenation results in the single - * input converted as per JLS 5.1.11 "String Conversion"; otherwise
        • + * input converted as per JLS {@jls 5.1.11} "String Conversion"; otherwise *
        • two or more inputs, the inputs are concatenated as per - * requirements stated in JLS 15.18.1 "String Concatenation Operator +". - * The inputs are converted as per JLS 5.1.11 "String Conversion", + * requirements stated in JLS {@jls 15.18.1} "String Concatenation Operator +". + * The inputs are converted as per JLS {@jls 5.1.11} "String Conversion", * and combined from left to right.
        • *
        * @@ -223,10 +223,10 @@ public final class StringConcatFactory { *
          *
        • zero inputs, concatenation results in an empty string;
        • *
        • one input, concatenation results in the single - * input converted as per JLS 5.1.11 "String Conversion"; otherwise
        • + * input converted as per JLS {@jls 5.1.11} "String Conversion"; otherwise *
        • two or more inputs, the inputs are concatenated as per - * requirements stated in JLS 15.18.1 "String Concatenation Operator +". - * The inputs are converted as per JLS 5.1.11 "String Conversion", + * requirements stated in JLS {@jls 15.18.1} "String Concatenation Operator +". + * The inputs are converted as per JLS {@jls 5.1.11} "String Conversion", * and combined from left to right.
        • *
        * diff --git a/src/java.base/share/classes/java/lang/invoke/VarForm.java b/src/java.base/share/classes/java/lang/invoke/VarForm.java index 7b118dbe470dddc7e181f68bf3c9bbed56eb8ead..1308c48cebb6d95783e5aff9d63d537968bb80fa 100644 --- a/src/java.base/share/classes/java/lang/invoke/VarForm.java +++ b/src/java.base/share/classes/java/lang/invoke/VarForm.java @@ -109,9 +109,14 @@ final class VarForm { @ForceInline final MemberName getMemberName(int mode) { - MemberName mn = getMemberNameOrNull(mode); + // Can be simplified by calling getMemberNameOrNull, but written in this + // form to improve interpreter/coldpath performance. + MemberName mn = memberName_table[mode]; if (mn == null) { - throw new UnsupportedOperationException(); + mn = resolveMemberName(mode); + if (mn == null) { + throw new UnsupportedOperationException(); + } } return mn; } diff --git a/src/java.base/share/classes/java/lang/invoke/VarHandles.java b/src/java.base/share/classes/java/lang/invoke/VarHandles.java index fb86bfab0e8c7deff098c42cc674ec463f2f8ac8..45cdb75b2ee3045549ea1574fcfd0048d052fa6d 100644 --- a/src/java.base/share/classes/java/lang/invoke/VarHandles.java +++ b/src/java.base/share/classes/java/lang/invoke/VarHandles.java @@ -31,12 +31,9 @@ import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; -import java.lang.reflect.Parameter; import java.nio.ByteOrder; import java.util.ArrayList; -import java.util.LinkedHashMap; import java.util.List; -import java.util.Map; import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; @@ -45,8 +42,6 @@ import java.util.stream.Stream; import static java.lang.invoke.MethodHandleStatics.UNSAFE; import static java.lang.invoke.MethodHandleStatics.VAR_HANDLE_IDENTITY_ADAPT; import static java.lang.invoke.MethodHandleStatics.newIllegalArgumentException; -import static java.util.stream.Collectors.joining; -import static java.util.stream.Collectors.toList; final class VarHandles { @@ -359,13 +354,13 @@ final class VarHandles { return target; } - public static VarHandle filterValue(VarHandle target, MethodHandle filterToTarget, MethodHandle filterFromTarget) { + public static VarHandle filterValue(VarHandle target, MethodHandle pFilterToTarget, MethodHandle pFilterFromTarget) { Objects.requireNonNull(target); - Objects.requireNonNull(filterToTarget); - Objects.requireNonNull(filterFromTarget); + Objects.requireNonNull(pFilterToTarget); + Objects.requireNonNull(pFilterFromTarget); //check that from/to filters do not throw checked exceptions - noCheckedExceptions(filterToTarget); - noCheckedExceptions(filterFromTarget); + MethodHandle filterToTarget = adaptForCheckedExceptions(pFilterToTarget); + MethodHandle filterFromTarget = adaptForCheckedExceptions(pFilterFromTarget); List> newCoordinates = new ArrayList<>(); List> additionalCoordinates = new ArrayList<>(); @@ -473,8 +468,9 @@ final class VarHandles { List> newCoordinates = new ArrayList<>(targetCoordinates); for (int i = 0 ; i < filters.length ; i++) { - noCheckedExceptions(filters[i]); - MethodType filterType = filters[i].type(); + MethodHandle filter = Objects.requireNonNull(filters[i]); + filter = adaptForCheckedExceptions(filter); + MethodType filterType = filter.type(); if (filterType.parameterCount() != 1) { throw newIllegalArgumentException("Invalid filter type " + filterType); } else if (newCoordinates.get(pos + i) != filterType.returnType()) { @@ -564,10 +560,10 @@ final class VarHandles { return adjustedType; } - public static VarHandle collectCoordinates(VarHandle target, int pos, MethodHandle filter) { + public static VarHandle collectCoordinates(VarHandle target, int pos, MethodHandle pFilter) { Objects.requireNonNull(target); - Objects.requireNonNull(filter); - noCheckedExceptions(filter); + Objects.requireNonNull(pFilter); + MethodHandle filter = adaptForCheckedExceptions(pFilter); List> targetCoordinates = target.coordinateTypes(); if (pos < 0 || pos >= targetCoordinates.size()) { @@ -604,42 +600,55 @@ final class VarHandles { (mode, modeHandle) -> MethodHandles.dropArguments(modeHandle, 1 + pos, valueTypes)); } - private static void noCheckedExceptions(MethodHandle handle) { + private static MethodHandle adaptForCheckedExceptions(MethodHandle target) { + Class[] exceptionTypes = exceptionTypes(target); + if (exceptionTypes != null) { // exceptions known + if (Stream.of(exceptionTypes).anyMatch(VarHandles::isCheckedException)) { + throw newIllegalArgumentException("Cannot adapt a var handle with a method handle which throws checked exceptions"); + } + return target; // no adaptation needed + } else { + MethodHandle handler = MethodHandleImpl.getConstantHandle(MethodHandleImpl.MH_VarHandles_handleCheckedExceptions); + MethodHandle zero = MethodHandles.zero(target.type().returnType()); // dead branch + handler = MethodHandles.collectArguments(zero, 0, handler); + return MethodHandles.catchException(target, Throwable.class, handler); + } + } + + static void handleCheckedExceptions(Throwable throwable) throws Throwable { + if (isCheckedException(throwable.getClass())) { + throw new IllegalStateException("Adapter handle threw checked exception", throwable); + } + throw throwable; + } + + static Class[] exceptionTypes(MethodHandle handle) { if (handle instanceof DirectMethodHandle directHandle) { byte refKind = directHandle.member.getReferenceKind(); MethodHandleInfo info = new InfoFromMemberName( MethodHandles.Lookup.IMPL_LOOKUP, directHandle.member, refKind); - final Class[] exceptionTypes; if (MethodHandleNatives.refKindIsMethod(refKind)) { - exceptionTypes = info.reflectAs(Method.class, MethodHandles.Lookup.IMPL_LOOKUP) + return info.reflectAs(Method.class, MethodHandles.Lookup.IMPL_LOOKUP) .getExceptionTypes(); } else if (MethodHandleNatives.refKindIsField(refKind)) { - exceptionTypes = null; + return new Class[0]; } else if (MethodHandleNatives.refKindIsConstructor(refKind)) { - exceptionTypes = info.reflectAs(Constructor.class, MethodHandles.Lookup.IMPL_LOOKUP) + return info.reflectAs(Constructor.class, MethodHandles.Lookup.IMPL_LOOKUP) .getExceptionTypes(); } else { throw new AssertionError("Cannot get here"); } - if (exceptionTypes != null) { - if (Stream.of(exceptionTypes).anyMatch(VarHandles::isCheckedException)) { - throw newIllegalArgumentException("Cannot adapt a var handle with a method handle which throws checked exceptions"); - } - } } else if (handle instanceof DelegatingMethodHandle) { - noCheckedExceptions(((DelegatingMethodHandle)handle).getTarget()); - } else { - //bound - BoundMethodHandle boundHandle = (BoundMethodHandle)handle; - for (int i = 0 ; i < boundHandle.fieldCount() ; i++) { - Object arg = boundHandle.arg(i); - if (arg instanceof MethodHandle){ - noCheckedExceptions((MethodHandle) arg); - } - } + return exceptionTypes(((DelegatingMethodHandle)handle).getTarget()); + } else if (handle instanceof NativeMethodHandle) { + return new Class[0]; } + + assert handle instanceof BoundMethodHandle : "Unexpected handle type: " + handle; + // unknown + return null; } private static boolean isCheckedException(Class clazz) { diff --git a/src/java.base/share/classes/java/lang/invoke/VolatileCallSite.java b/src/java.base/share/classes/java/lang/invoke/VolatileCallSite.java index 742fa23737d02e73c851f5807b8e12341e052226..faf10fd79f4934a88e8b25e3fbfd5d2ab0b16283 100644 --- a/src/java.base/share/classes/java/lang/invoke/VolatileCallSite.java +++ b/src/java.base/share/classes/java/lang/invoke/VolatileCallSite.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 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 @@ -42,7 +42,7 @@ package java.lang.invoke; * @author John Rose, JSR 292 EG * @since 1.7 */ -public class VolatileCallSite extends CallSite { +public non-sealed class VolatileCallSite extends CallSite { /** * Creates a call site with a volatile binding to its target. * The initial target is set to a method handle diff --git a/src/java.base/share/classes/java/lang/invoke/X-VarHandleMemoryAccess.java.template b/src/java.base/share/classes/java/lang/invoke/X-VarHandleMemoryAccess.java.template index 0bdfd212e0783a1f22517fad179c350c1e836aee..bdb4904d9942d988fa40668159a71b192ab4acd7 100644 --- a/src/java.base/share/classes/java/lang/invoke/X-VarHandleMemoryAccess.java.template +++ b/src/java.base/share/classes/java/lang/invoke/X-VarHandleMemoryAccess.java.template @@ -106,7 +106,7 @@ final class MemoryAccessVarHandle$Type$Helper extends MemoryAccessVarHandleBase static long offset(boolean skipAlignmentMaskCheck, MemorySegmentProxy bb, long offset, long alignmentMask) { long address = offsetNoVMAlignCheck(skipAlignmentMaskCheck, bb, offset, alignmentMask); if ((address & VM_ALIGN) != 0) { - throw MemoryAccessVarHandleBase.newIllegalStateExceptionForMisalignedAccess(address); + throw MemoryAccessVarHandleBase.newIllegalArgumentExceptionForMisalignedAccess(address); } return address; } @@ -115,14 +115,15 @@ final class MemoryAccessVarHandle$Type$Helper extends MemoryAccessVarHandleBase static long offsetNoVMAlignCheck(boolean skipAlignmentMaskCheck, MemorySegmentProxy bb, long offset, long alignmentMask) { long base = bb.unsafeGetOffset(); long address = base + offset; + long maxAlignMask = bb.maxAlignMask(); if (skipAlignmentMaskCheck) { //note: the offset portion has already been aligned-checked, by construction - if ((base & alignmentMask) != 0) { - throw MemoryAccessVarHandleBase.newIllegalStateExceptionForMisalignedAccess(address); + if (((base | maxAlignMask) & alignmentMask) != 0) { + throw MemoryAccessVarHandleBase.newIllegalArgumentExceptionForMisalignedAccess(address); } } else { - if ((address & alignmentMask) != 0) { - throw MemoryAccessVarHandleBase.newIllegalStateExceptionForMisalignedAccess(address); + if (((address | maxAlignMask) & alignmentMask) != 0) { + throw MemoryAccessVarHandleBase.newIllegalArgumentExceptionForMisalignedAccess(address); } } return address; diff --git a/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java b/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java index 86ea7602c60639e74c87126e56b5ebf23092e3ca..05b010c18747557d5d0d85eec97c551a964a957d 100644 --- a/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java +++ b/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java @@ -893,7 +893,8 @@ public class ModuleDescriptor * integer or a string. Tokens are separated by the punctuation characters * {@code '.'}, {@code '-'}, or {@code '+'}, or by transitions from a * sequence of digits to a sequence of characters that are neither digits - * nor punctuation characters, or vice versa. + * nor punctuation characters, or vice versa. Consecutive repeated + * punctuation characters are treated as a single punctuation character. * *
          * diff --git a/src/java.base/share/classes/java/lang/ref/Cleaner.java b/src/java.base/share/classes/java/lang/ref/Cleaner.java index a736f23ad2f80734b84797791e6d43d41bc5a6a8..a4769e112b6e689118408c71f3399de400601b47 100644 --- a/src/java.base/share/classes/java/lang/ref/Cleaner.java +++ b/src/java.base/share/classes/java/lang/ref/Cleaner.java @@ -86,9 +86,13 @@ import java.util.function.Function; * by the Cleaner when the CleaningExample instance has become phantom reachable. *
          {@code
            * public class CleaningExample implements AutoCloseable {
          - *        // A cleaner, preferably one shared within a library
          - *        private static final Cleaner cleaner = ;
          + *        // A cleaner (preferably one shared within a library,
          +          // but for the sake of example, a new one is created here)
          + *        private static final Cleaner cleaner = Cleaner.create();
            *
          + *        // State class captures information necessary for cleanup.
          + *        // It must hold no reference to the instance being cleaned
          + *        // and therefore it is a static inner class in this example.
            *        static class State implements Runnable {
            *
            *            State(...) {
          diff --git a/src/java.base/share/classes/java/lang/ref/FinalReference.java b/src/java.base/share/classes/java/lang/ref/FinalReference.java
          index 9175516d4d0cec03562b36299f4941f4a8d9f583..06af37df67c94e062022a727f4841dd9c9579ef4 100644
          --- a/src/java.base/share/classes/java/lang/ref/FinalReference.java
          +++ b/src/java.base/share/classes/java/lang/ref/FinalReference.java
          @@ -1,5 +1,5 @@
           /*
          - * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved.
          + * 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
          @@ -28,7 +28,7 @@ package java.lang.ref;
           /**
            * Final references, used to implement finalization
            */
          -class FinalReference extends Reference {
          +sealed class FinalReference extends Reference permits Finalizer {
           
               public FinalReference(T referent, ReferenceQueue q) {
                   super(referent, q);
          diff --git a/src/java.base/share/classes/java/lang/ref/Finalizer.java b/src/java.base/share/classes/java/lang/ref/Finalizer.java
          index d5838b7a6b1b461d7dff80b400895ffbf089e606..18aedf11bb316f1a7a301559f11c84eeb8c8efa6 100644
          --- a/src/java.base/share/classes/java/lang/ref/Finalizer.java
          +++ b/src/java.base/share/classes/java/lang/ref/Finalizer.java
          @@ -61,9 +61,17 @@ final class Finalizer extends FinalReference { /* Package-private; must
                   return queue;
               }
           
          +    static final boolean ENABLED = isFinalizationEnabled();
          +
          +    private static native boolean isFinalizationEnabled();
          +
               /* Invoked by VM */
               static void register(Object finalizee) {
          -        new Finalizer(finalizee);
          +        if (ENABLED) {
          +            new Finalizer(finalizee);
          +        } else {
          +            throw new InternalError("unexpected call to Finalizer::register when finalization is disabled");
          +        }
               }
           
               private void runFinalizer(JavaLangAccess jla) {
          @@ -130,7 +138,7 @@ final class Finalizer extends FinalReference { /* Package-private; must
           
               /* Called by Runtime.runFinalization() */
               static void runFinalization() {
          -        if (VM.initLevel() == 0) {
          +        if (VM.initLevel() == 0 || ! ENABLED) {
                       return;
                   }
           
          @@ -182,14 +190,16 @@ final class Finalizer extends FinalReference { /* Package-private; must
               }
           
               static {
          -        ThreadGroup tg = Thread.currentThread().getThreadGroup();
          -        for (ThreadGroup tgn = tg;
          -             tgn != null;
          -             tg = tgn, tgn = tg.getParent());
          -        Thread finalizer = new FinalizerThread(tg);
          -        finalizer.setPriority(Thread.MAX_PRIORITY - 2);
          -        finalizer.setDaemon(true);
          -        finalizer.start();
          +        if (ENABLED) {
          +            ThreadGroup tg = Thread.currentThread().getThreadGroup();
          +            for (ThreadGroup tgn = tg;
          +                 tgn != null;
          +                 tg = tgn, tgn = tg.getParent());
          +            Thread finalizer = new FinalizerThread(tg);
          +            finalizer.setPriority(Thread.MAX_PRIORITY - 2);
          +            finalizer.setDaemon(true);
          +            finalizer.start();
          +        }
               }
           
           }
          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 2c1532b8eb2956898e8d8ec0515dfce78228e5bc..fef3bc7c50859fe90b8eab967c24a1cef2cf4f52 100644
          --- a/src/java.base/share/classes/java/lang/ref/PhantomReference.java
          +++ b/src/java.base/share/classes/java/lang/ref/PhantomReference.java
          @@ -1,5 +1,5 @@
           /*
          - * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved.
          + * 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
          @@ -50,7 +50,7 @@ import jdk.internal.vm.annotation.IntrinsicCandidate;
            * @since    1.2
            */
           
          -public class PhantomReference extends Reference {
          +public non-sealed class PhantomReference extends Reference {
           
               /**
                * Returns this reference object's referent.  Because the referent of a
          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 17d8c7b669c07e7831fd8ae6021aa77bf3f0ee58..777567085ebfa7a2b8e6797b38333e05002ef5d0 100644
          --- a/src/java.base/share/classes/java/lang/ref/Reference.java
          +++ b/src/java.base/share/classes/java/lang/ref/Reference.java
          @@ -1,5 +1,5 @@
           /*
          - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
          + * 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
          @@ -41,7 +41,8 @@ import jdk.internal.ref.Cleaner;
            * @since    1.2
            */
           
          -public abstract class Reference {
          +public abstract sealed class Reference
          +    permits PhantomReference, SoftReference, WeakReference, FinalReference {
           
               /* The state of a Reference object is characterized by two attributes.  It
                * may be either "active", "pending", or "inactive".  It may also be
          diff --git a/src/java.base/share/classes/java/lang/ref/SoftReference.java b/src/java.base/share/classes/java/lang/ref/SoftReference.java
          index 8ce74a67d0ad8c3366fe2d8f2244d0f4ab339b53..a0cb75dcf5031060dca3ca837d746ac4d3c12cbe 100644
          --- a/src/java.base/share/classes/java/lang/ref/SoftReference.java
          +++ b/src/java.base/share/classes/java/lang/ref/SoftReference.java
          @@ -1,5 +1,5 @@
           /*
          - * Copyright (c) 1997, 2003, Oracle and/or its affiliates. All rights reserved.
          + * 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
          @@ -61,7 +61,7 @@ package java.lang.ref;
            * @since    1.2
            */
           
          -public class SoftReference extends Reference {
          +public non-sealed class SoftReference extends Reference {
           
               /**
                * Timestamp clock, updated by the garbage collector
          diff --git a/src/java.base/share/classes/java/lang/ref/WeakReference.java b/src/java.base/share/classes/java/lang/ref/WeakReference.java
          index fdf2b5c9f023ea1deb48626a376cbdb0135087e6..1d1a01f3acd9624e4a234c64d1f0900ebe3ebfb4 100644
          --- a/src/java.base/share/classes/java/lang/ref/WeakReference.java
          +++ b/src/java.base/share/classes/java/lang/ref/WeakReference.java
          @@ -1,5 +1,5 @@
           /*
          - * Copyright (c) 1997, 2003, Oracle and/or its affiliates. All rights reserved.
          + * 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
          @@ -45,7 +45,7 @@ package java.lang.ref;
            * @since    1.2
            */
           
          -public class WeakReference extends Reference {
          +public non-sealed class WeakReference extends Reference {
           
               /**
                * Creates a new weak reference that refers to the given object.  The new
          diff --git a/src/java.base/share/classes/java/lang/reflect/AccessibleObject.java b/src/java.base/share/classes/java/lang/reflect/AccessibleObject.java
          index 19dbce14b7571ed919efe62f3b43a5465cbdcb67..2b620967a8aecc8df06248e87115953e93e1d6f6 100644
          --- a/src/java.base/share/classes/java/lang/reflect/AccessibleObject.java
          +++ b/src/java.base/share/classes/java/lang/reflect/AccessibleObject.java
          @@ -1,5 +1,5 @@
           /*
          - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
          + * 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
          @@ -168,6 +168,15 @@ public class AccessibleObject implements AnnotatedElement {
                *     open module. 
                * 
                *
          +     * 

          This method may be used by JNI code + * with no caller class on the stack to enable access to a {@link Member member} + * of {@link Member#getDeclaringClass() declaring class} {@code D} if and only if: + *

            + *
          • The member is {@code public} and {@code D} is {@code public} in + * a package that the module containing {@code D} {@link + * Module#isExported(String,Module) exports} unconditionally.
          • + *
          + * *

          This method cannot be used to enable access to private members, * members with default (package) access, protected instance members, or * protected constructors when the declaring class is in a different module @@ -246,6 +255,11 @@ public class AccessibleObject implements AnnotatedElement { * } * } * + *

          If this method is invoked by JNI code + * with no caller class on the stack, the {@code accessible} flag can + * only be set if the member and the declaring class are public, and + * the class is in a package that is exported unconditionally.

          + * *

          If there is a security manager, its {@code checkPermission} method * is first called with a {@code ReflectPermission("suppressAccessChecks")} * permission.

          @@ -304,6 +318,16 @@ public class AccessibleObject implements AnnotatedElement { throw new IllegalCallerException(); // should not happen } + if (caller == null) { + // No caller frame when a native thread attaches to the VM + // only allow access to a public accessible member + boolean canAccess = Reflection.verifyPublicMemberAccess(declaringClass, declaringClass.getModifiers()); + if (!canAccess && throwExceptionIfDenied) { + throwInaccessibleObjectException(caller, declaringClass); + } + return canAccess; + } + Module callerModule = caller.getModule(); Module declaringModule = declaringClass.getModule(); @@ -312,12 +336,7 @@ public class AccessibleObject implements AnnotatedElement { if (!declaringModule.isNamed()) return true; String pn = declaringClass.getPackageName(); - int modifiers; - if (this instanceof Executable) { - modifiers = ((Executable) this).getModifiers(); - } else { - modifiers = ((Field) this).getModifiers(); - } + int modifiers = ((Member)this).getModifiers(); // class is public and package is exported to caller boolean isClassPublic = Modifier.isPublic(declaringClass.getModifiers()); @@ -341,25 +360,37 @@ public class AccessibleObject implements AnnotatedElement { } if (throwExceptionIfDenied) { - // not accessible - String msg = "Unable to make "; - if (this instanceof Field) - msg += "field "; - msg += this + " accessible: " + declaringModule + " does not \""; - if (isClassPublic && Modifier.isPublic(modifiers)) - msg += "exports"; - else - msg += "opens"; - msg += " " + pn + "\" to " + callerModule; - InaccessibleObjectException e = new InaccessibleObjectException(msg); - if (printStackTraceWhenAccessFails()) { - e.printStackTrace(System.err); - } - throw e; + throwInaccessibleObjectException(caller, declaringClass); } return false; } + private void throwInaccessibleObjectException(Class caller, Class declaringClass) { + boolean isClassPublic = Modifier.isPublic(declaringClass.getModifiers()); + String pn = declaringClass.getPackageName(); + int modifiers = ((Member)this).getModifiers(); + + // not accessible + String msg = "Unable to make "; + if (this instanceof Field) + msg += "field "; + msg += this + " accessible"; + msg += caller == null ? " by JNI attached native thread with no caller frame: " : ": "; + msg += declaringClass.getModule() + " does not \""; + if (isClassPublic && Modifier.isPublic(modifiers)) + msg += "exports"; + else + msg += "opens"; + msg += " " + pn + "\"" ; + if (caller != null) + msg += " to " + caller.getModule(); + InaccessibleObjectException e = new InaccessibleObjectException(msg); + if (printStackTraceWhenAccessFails()) { + e.printStackTrace(System.err); + } + throw e; + } + private boolean isSubclassOf(Class queryClass, Class ofClass) { while (queryClass != null) { if (queryClass == ofClass) { @@ -409,7 +440,11 @@ public class AccessibleObject implements AnnotatedElement { * is set to {@code true}, i.e. the checks for Java language access control * are suppressed, or if the caller can access the member as * specified in The Java Language Specification, - * with the variation noted in the class description.

          + * with the variation noted in the class description. + * If this method is invoked by JNI code + * with no caller class on the stack, this method returns {@code true} + * if the member and the declaring class are public, and the class is in + * a package that is exported unconditionally.

          * * @param obj an instance object of the declaring class of this reflected * object if it is an instance method or field diff --git a/src/java.base/share/classes/java/lang/reflect/Constructor.java b/src/java.base/share/classes/java/lang/reflect/Constructor.java index 73ad66d5d5dc62a621ab2f6b40fc86e34b7e63bd..17277c7eb35590bf0da774581d2bda34dd499974 100644 --- a/src/java.base/share/classes/java/lang/reflect/Constructor.java +++ b/src/java.base/share/classes/java/lang/reflect/Constructor.java @@ -371,7 +371,7 @@ public final class Constructor extends Executable { sb.append(getDeclaringClass().getTypeName()); sb.append('('); StringJoiner sj = new StringJoiner(","); - for (Class parameterType : getParameterTypes()) { + for (Class parameterType : getSharedParameterTypes()) { sj.add(parameterType.getTypeName()); } sb.append(sj); diff --git a/src/java.base/share/classes/java/lang/reflect/InvocationHandler.java b/src/java.base/share/classes/java/lang/reflect/InvocationHandler.java index 4ca59906367966d51fae53e7f52a59ba3f394594..d5d00f34c868f42ef0520ee363f99a49f809c711 100644 --- a/src/java.base/share/classes/java/lang/reflect/InvocationHandler.java +++ b/src/java.base/share/classes/java/lang/reflect/InvocationHandler.java @@ -28,7 +28,6 @@ package java.lang.reflect; import jdk.internal.reflect.CallerSensitive; import jdk.internal.reflect.Reflection; -import java.lang.invoke.MethodHandle; import java.util.Objects; /** @@ -262,33 +261,6 @@ public interface InvocationHandler { throws Throwable { Objects.requireNonNull(proxy); Objects.requireNonNull(method); - - // verify that the object is actually a proxy instance - if (!Proxy.isProxyClass(proxy.getClass())) { - throw new IllegalArgumentException("'proxy' is not a proxy instance"); - } - if (!method.isDefault()) { - throw new IllegalArgumentException("\"" + method + "\" is not a default method"); - } - @SuppressWarnings("unchecked") - Class proxyClass = (Class)proxy.getClass(); - - Class intf = method.getDeclaringClass(); - // access check on the default method - method.checkAccess(Reflection.getCallerClass(), intf, proxyClass, method.getModifiers()); - - MethodHandle mh = Proxy.defaultMethodHandle(proxyClass, method); - // invoke the super method - try { - // the args array can be null if the number of formal parameters required by - // the method is zero (consistent with Method::invoke) - Object[] params = args != null ? args : Proxy.EMPTY_ARGS; - return mh.invokeExact(proxy, params); - } catch (ClassCastException | NullPointerException e) { - throw new IllegalArgumentException(e.getMessage(), e); - } catch (Proxy.InvocationException e) { - // unwrap and throw the exception thrown by the default method - throw e.getCause(); - } + return Proxy.invokeDefault(proxy, method, args, Reflection.getCallerClass()); } } diff --git a/src/java.base/share/classes/java/lang/reflect/Method.java b/src/java.base/share/classes/java/lang/reflect/Method.java index 5d8fe026b406eae1662b134f940cd01097c42346..2aff745d55367f5db32ee48211d7660c841c0210 100644 --- a/src/java.base/share/classes/java/lang/reflect/Method.java +++ b/src/java.base/share/classes/java/lang/reflect/Method.java @@ -431,7 +431,7 @@ public final class Method extends Executable { String toShortSignature() { StringJoiner sj = new StringJoiner(",", getName() + "(", ")"); - for (Class parameterType : getParameterTypes()) { + for (Class parameterType : getSharedParameterTypes()) { sj.add(parameterType.getTypeName()); } return sj.toString(); diff --git a/src/java.base/share/classes/java/lang/reflect/Proxy.java b/src/java.base/share/classes/java/lang/reflect/Proxy.java index c9e3bb259ae44bbd68edbdae7a29308fa6c07925..6dd5b3ef1db42a65e34371feb49599bf65f16277 100644 --- a/src/java.base/share/classes/java/lang/reflect/Proxy.java +++ b/src/java.base/share/classes/java/lang/reflect/Proxy.java @@ -1314,6 +1314,46 @@ public class Proxy implements java.io.Serializable { }); } + /* + * Invoke the default method of the given proxy with an explicit caller class. + * + * @throws IllegalAccessException if the proxy interface is inaccessible to the caller + * if caller is non-null + */ + static Object invokeDefault(Object proxy, Method method, Object[] args, Class caller) + throws Throwable { + // verify that the object is actually a proxy instance + if (!Proxy.isProxyClass(proxy.getClass())) { + throw new IllegalArgumentException("'proxy' is not a proxy instance"); + } + if (!method.isDefault()) { + throw new IllegalArgumentException("\"" + method + "\" is not a default method"); + } + @SuppressWarnings("unchecked") + Class proxyClass = (Class)proxy.getClass(); + + // skip access check if caller is null + if (caller != null) { + Class intf = method.getDeclaringClass(); + // access check on the default method + method.checkAccess(caller, intf, proxyClass, method.getModifiers()); + } + + MethodHandle mh = Proxy.defaultMethodHandle(proxyClass, method); + // invoke the super method + try { + // the args array can be null if the number of formal parameters required by + // the method is zero (consistent with Method::invoke) + Object[] params = args != null ? args : Proxy.EMPTY_ARGS; + return mh.invokeExact(proxy, params); + } catch (ClassCastException | NullPointerException e) { + throw new IllegalArgumentException(e.getMessage(), e); + } catch (Proxy.InvocationException e) { + // unwrap and throw the exception thrown by the default method + throw e.getCause(); + } + } + /** * Internal exception type to wrap the exception thrown by the default method * so that it can distinguish CCE and NPE thrown due to the arguments diff --git a/src/java.base/share/classes/java/lang/reflect/ReflectAccess.java b/src/java.base/share/classes/java/lang/reflect/ReflectAccess.java index 6ac890156b0f5668520da4c46283d67fa07c0269..fa5a5d453ec02c1398bfb821d1be5bfac5322647 100644 --- a/src/java.base/share/classes/java/lang/reflect/ReflectAccess.java +++ b/src/java.base/share/classes/java/lang/reflect/ReflectAccess.java @@ -127,4 +127,9 @@ class ReflectAccess implements jdk.internal.access.JavaLangReflectAccess { { return ctor.newInstanceWithCaller(args, true, caller); } + + public Object invokeDefault(Object proxy, Method method, Object[] args, Class caller) + throws Throwable { + return Proxy.invokeDefault(proxy, method, args, caller); + } } diff --git a/src/java.base/share/classes/java/lang/reflect/TypeVariable.java b/src/java.base/share/classes/java/lang/reflect/TypeVariable.java index 0064aed2a2203e12ead789f7e33284aea4f74cae..01746e34385088385277365c85b2005f3aaa9368 100644 --- a/src/java.base/share/classes/java/lang/reflect/TypeVariable.java +++ b/src/java.base/share/classes/java/lang/reflect/TypeVariable.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -30,8 +30,8 @@ package java.lang.reflect; * A type variable is created the first time it is needed by a reflective * method, as specified in this package. If a type variable t is referenced * by a type (i.e, class, interface or annotation type) T, and T is declared - * by the nth enclosing class of T (see JLS 8.1.2), then the creation of t - * requires the resolution (see JVMS 5) of the ith enclosing class of T, + * by the nth enclosing class of T (see JLS {@jls 8.1.2}), then the creation of t + * requires the resolution (see JVMS {@jvms 5}) of the ith enclosing class of T, * for i = 0 to n, inclusive. Creating a type variable must not cause the * creation of its bounds. Repeated creation of a type variable has no effect. * diff --git a/src/java.base/share/classes/java/lang/runtime/ObjectMethods.java b/src/java.base/share/classes/java/lang/runtime/ObjectMethods.java index 62c81c42f5c8dc641ca66dee35dc3206d59bdb67..c2d388d01bac0ed9935571a2b130cf49bd256e4d 100644 --- a/src/java.base/share/classes/java/lang/runtime/ObjectMethods.java +++ b/src/java.base/share/classes/java/lang/runtime/ObjectMethods.java @@ -29,9 +29,11 @@ import java.lang.invoke.ConstantCallSite; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; +import java.lang.invoke.StringConcatFactory; import java.lang.invoke.TypeDescriptor; import java.security.AccessController; import java.security.PrivilegedAction; +import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; @@ -52,6 +54,8 @@ public class ObjectMethods { private ObjectMethods() { } + private static final int MAX_STRING_CONCAT_SLOTS = 20; + private static final MethodType DESCRIPTOR_MT = MethodType.methodType(MethodType.class); private static final MethodType NAMES_MT = MethodType.methodType(List.class); private static final MethodHandle FALSE = MethodHandles.constant(boolean.class, false); @@ -251,44 +255,110 @@ public class ObjectMethods { * @param names the names * @return the method handle */ - private static MethodHandle makeToString(Class receiverClass, - List getters, + private static MethodHandle makeToString(MethodHandles.Lookup lookup, + Class receiverClass, + MethodHandle[] getters, List names) { - // This is a pretty lousy algorithm; we spread the receiver over N places, - // apply the N getters, apply N toString operations, and concat the result with String.format - // Better to use String.format directly, or delegate to StringConcatFactory - // Also probably want some quoting around String components - - assert getters.size() == names.size(); - - int[] invArgs = new int[getters.size()]; - Arrays.fill(invArgs, 0); - MethodHandle[] filters = new MethodHandle[getters.size()]; - StringBuilder sb = new StringBuilder(); - sb.append(receiverClass.getSimpleName()).append("["); - for (int i=0; i> splits; + MethodHandle[] toSplit = getters; + int namesIndex = 0; + do { + /* StringConcatFactory::makeConcatWithConstants can only deal with 200 slots, longs and double occupy two + * the rest 1 slot, we need to chop the current `getters` into chunks, it could be that for records with + * a lot of components that we need to do a couple of iterations. The main difference between the first + * iteration and the rest would be on the recipe + */ + splits = split(toSplit); + mhs = new MethodHandle[splits.size()]; + for (int splitIndex = 0; splitIndex < splits.size(); splitIndex++) { + String recipe = ""; + if (firstTime && splitIndex == 0) { + recipe = receiverClass.getSimpleName() + "["; + } + for (int i = 0; i < splits.get(splitIndex).size(); i++) { + recipe += firstTime ? names.get(namesIndex) + "=" + "\1" : "\1"; + if (firstTime && namesIndex != names.size() - 1) { + recipe += ", "; + } + namesIndex++; + } + if (firstTime && splitIndex == splits.size() - 1) { + recipe += "]"; + } + Class[] concatTypeArgs = new Class[splits.get(splitIndex).size()]; + // special case: no need to create another getters if there is only one split + MethodHandle[] currentSplitGetters = new MethodHandle[splits.get(splitIndex).size()]; + for (int j = 0; j < splits.get(splitIndex).size(); j++) { + concatTypeArgs[j] = splits.get(splitIndex).get(j).type().returnType(); + currentSplitGetters[j] = splits.get(splitIndex).get(j); + } + MethodType concatMT = MethodType.methodType(String.class, concatTypeArgs); + try { + mhs[splitIndex] = StringConcatFactory.makeConcatWithConstants( + lookup, "", + concatMT, + recipe, + new Object[0] + ).getTarget(); + mhs[splitIndex] = MethodHandles.filterArguments(mhs[splitIndex], 0, currentSplitGetters); + // this will spread the receiver class across all the getters + mhs[splitIndex] = MethodHandles.permuteArguments( + mhs[splitIndex], + MethodType.methodType(String.class, receiverClass), + new int[splits.get(splitIndex).size()] + ); + } catch (Throwable t) { + throw new RuntimeException(t); + } + } + toSplit = mhs; + firstTime = false; + } while (splits.size() > 1); + return mhs[0]; + } + + /** + * Chops the getters into smaller chunks according to the maximum number of slots + * StringConcatFactory::makeConcatWithConstants can chew + * @param getters the current getters + * @return chunks that wont surpass the maximum number of slots StringConcatFactory::makeConcatWithConstants can chew + */ + private static List> split(MethodHandle[] getters) { + List> splits = new ArrayList<>(); + + int slots = 0; + + // Need to peel, so that neither call has more than acceptable number + // of slots for the arguments. + List cArgs = new ArrayList<>(); + for (MethodHandle methodHandle : getters) { + Class returnType = methodHandle.type().returnType(); + int needSlots = (returnType == long.class || returnType == double.class) ? 2 : 1; + if (slots + needSlots > MAX_STRING_CONCAT_SLOTS) { + splits.add(cArgs); + cArgs = new ArrayList<>(); + slots = 0; + } + cArgs.add(methodHandle); + slots += needSlots; } - else { - MethodHandle filtered = MethodHandles.filterArguments(formatter, 0, filters); - formatter = MethodHandles.permuteArguments(filtered, MethodType.methodType(String.class, receiverClass), invArgs); + + // Flush the tail slice + if (!cArgs.isEmpty()) { + splits.add(cArgs); } - return formatter; + return splits; } /** @@ -326,15 +396,15 @@ public class ObjectMethods { * if invoked by a condy * @throws IllegalArgumentException if the bootstrap arguments are invalid * or inconsistent - * @throws NullPointerException if any argument but {@code lookup} is {@code null}, - * in the case of the {@code getters} argument, its - * contents cannot be {@code null} either + * @throws NullPointerException if any argument is {@code null} or if any element + * in the {@code getters} array is {@code null} * @throws Throwable if any exception is thrown during call site construction */ public static Object bootstrap(MethodHandles.Lookup lookup, String methodName, TypeDescriptor type, Class recordClass, String names, MethodHandle... getters) throws Throwable { + requireNonNull(lookup); requireNonNull(methodName); requireNonNull(type); requireNonNull(recordClass); @@ -367,7 +437,7 @@ public class ObjectMethods { List nameList = "".equals(names) ? List.of() : List.of(names.split(";")); if (nameList.size() != getterList.size()) throw new IllegalArgumentException("Name list and accessor list do not match"); - yield makeToString(recordClass, getterList, nameList); + yield makeToString(lookup, recordClass, getters, nameList); } default -> throw new IllegalArgumentException(methodName); }; diff --git a/src/java.base/share/classes/java/math/BigDecimal.java b/src/java.base/share/classes/java/math/BigDecimal.java index 8660a4513959af83beb6e9c0ec34b8a96c7cc4c7..c491346f9f58d9bab187904d67bb32874a77a70b 100644 --- a/src/java.base/share/classes/java/math/BigDecimal.java +++ b/src/java.base/share/classes/java/math/BigDecimal.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 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 @@ -1791,7 +1791,7 @@ public class BigDecimal extends Number implements Comparable { * @throws ArithmeticException if the result is inexact but the * rounding mode is {@code UNNECESSARY} or * {@code mc.precision == 0} and the quotient has a - * non-terminating decimal expansion,including dividing by zero + * non-terminating decimal expansion, including dividing by zero * @since 1.5 */ public BigDecimal divide(BigDecimal divisor, MathContext mc) { @@ -4405,7 +4405,7 @@ public class BigDecimal extends Number implements Comparable { x = -x; if (y < 0) y = -y; - return (x < y) ? -1 : ((x == y) ? 0 : 1); + return Long.compare(x, y); } private static int saturateLong(long s) { diff --git a/src/java.base/share/classes/java/math/BigInteger.java b/src/java.base/share/classes/java/math/BigInteger.java index 34f1953d003113b327ca75ed74e326236aadcf6c..81d9a9cf248ed1a574f43f114100884cc8a3cb0f 100644 --- a/src/java.base/share/classes/java/math/BigInteger.java +++ b/src/java.base/share/classes/java/math/BigInteger.java @@ -36,6 +36,9 @@ import java.io.ObjectStreamField; import java.util.Arrays; import java.util.Objects; import java.util.Random; +import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.ForkJoinWorkerThread; +import java.util.concurrent.RecursiveTask; import java.util.concurrent.ThreadLocalRandom; import jdk.internal.math.DoubleConsts; @@ -1581,7 +1584,30 @@ public class BigInteger extends Number implements Comparable { * @return {@code this * val} */ public BigInteger multiply(BigInteger val) { - return multiply(val, false); + return multiply(val, false, false, 0); + } + + /** + * Returns a BigInteger whose value is {@code (this * val)}. + * When both {@code this} and {@code val} are large, typically + * in the thousands of bits, parallel multiply might be used. + * This method returns the exact same mathematical result as + * {@link #multiply}. + * + * @implNote This implementation may offer better algorithmic + * performance when {@code val == this}. + * + * @implNote Compared to {@link #multiply}, an implementation's + * parallel multiplication algorithm would typically use more + * CPU resources to compute the result faster, and may do so + * with a slight increase in memory consumption. + * + * @param val value to be multiplied by this BigInteger. + * @return {@code this * val} + * @see #multiply + */ + public BigInteger parallelMultiply(BigInteger val) { + return multiply(val, false, true, 0); } /** @@ -1590,16 +1616,17 @@ public class BigInteger extends Number implements Comparable { * * @param val value to be multiplied by this BigInteger. * @param isRecursion whether this is a recursive invocation + * @param parallel whether the multiply should be done in parallel * @return {@code this * val} */ - private BigInteger multiply(BigInteger val, boolean isRecursion) { + private BigInteger multiply(BigInteger val, boolean isRecursion, boolean parallel, int depth) { if (val.signum == 0 || signum == 0) return ZERO; int xlen = mag.length; if (val == this && xlen > MULTIPLY_SQUARE_THRESHOLD) { - return square(); + return square(true, parallel, depth); } int ylen = val.mag.length; @@ -1677,7 +1704,7 @@ public class BigInteger extends Number implements Comparable { } } - return multiplyToomCook3(this, val); + return multiplyToomCook3(this, val, parallel, depth); } } } @@ -1844,6 +1871,88 @@ public class BigInteger extends Number implements Comparable { } } + @SuppressWarnings("serial") + private abstract static sealed class RecursiveOp extends RecursiveTask { + /** + * The threshold until when we should continue forking recursive ops + * if parallel is true. This threshold is only relevant for Toom Cook 3 + * multiply and square. + */ + private static final int PARALLEL_FORK_DEPTH_THRESHOLD = + calculateMaximumDepth(ForkJoinPool.getCommonPoolParallelism()); + + private static final int calculateMaximumDepth(int parallelism) { + return 32 - Integer.numberOfLeadingZeros(parallelism); + } + + final boolean parallel; + /** + * The current recursing depth. Since it is a logarithmic algorithm, + * we do not need an int to hold the number. + */ + final byte depth; + + private RecursiveOp(boolean parallel, int depth) { + this.parallel = parallel; + this.depth = (byte) depth; + } + + private static int getParallelForkDepthThreshold() { + if (Thread.currentThread() instanceof ForkJoinWorkerThread fjwt) { + return calculateMaximumDepth(fjwt.getPool().getParallelism()); + } + else { + return PARALLEL_FORK_DEPTH_THRESHOLD; + } + } + + protected RecursiveTask forkOrInvoke() { + if (parallel && depth <= getParallelForkDepthThreshold()) fork(); + else invoke(); + return this; + } + + @SuppressWarnings("serial") + private static final class RecursiveMultiply extends RecursiveOp { + private final BigInteger a; + private final BigInteger b; + + public RecursiveMultiply(BigInteger a, BigInteger b, boolean parallel, int depth) { + super(parallel, depth); + this.a = a; + this.b = b; + } + + @Override + public BigInteger compute() { + return a.multiply(b, true, parallel, depth); + } + } + + @SuppressWarnings("serial") + private static final class RecursiveSquare extends RecursiveOp { + private final BigInteger a; + + public RecursiveSquare(BigInteger a, boolean parallel, int depth) { + super(parallel, depth); + this.a = a; + } + + @Override + public BigInteger compute() { + return a.square(true, parallel, depth); + } + } + + private static RecursiveTask multiply(BigInteger a, BigInteger b, boolean parallel, int depth) { + return new RecursiveMultiply(a, b, parallel, depth).forkOrInvoke(); + } + + private static RecursiveTask square(BigInteger a, boolean parallel, int depth) { + return new RecursiveSquare(a, parallel, depth).forkOrInvoke(); + } + } + /** * Multiplies two BigIntegers using a 3-way Toom-Cook multiplication * algorithm. This is a recursive divide-and-conquer algorithm which is @@ -1872,7 +1981,7 @@ public class BigInteger extends Number implements Comparable { * LNCS #4547. Springer, Madrid, Spain, June 21-22, 2007. * */ - private static BigInteger multiplyToomCook3(BigInteger a, BigInteger b) { + private static BigInteger multiplyToomCook3(BigInteger a, BigInteger b, boolean parallel, int depth) { int alen = a.mag.length; int blen = b.mag.length; @@ -1896,16 +2005,20 @@ public class BigInteger extends Number implements Comparable { BigInteger v0, v1, v2, vm1, vinf, t1, t2, tm1, da1, db1; - v0 = a0.multiply(b0, true); + depth++; + var v0_task = RecursiveOp.multiply(a0, b0, parallel, depth); da1 = a2.add(a0); db1 = b2.add(b0); - vm1 = da1.subtract(a1).multiply(db1.subtract(b1), true); + var vm1_task = RecursiveOp.multiply(da1.subtract(a1), db1.subtract(b1), parallel, depth); da1 = da1.add(a1); db1 = db1.add(b1); - v1 = da1.multiply(db1, true); + var v1_task = RecursiveOp.multiply(da1, db1, parallel, depth); v2 = da1.add(a2).shiftLeft(1).subtract(a0).multiply( - db1.add(b2).shiftLeft(1).subtract(b0), true); - vinf = a2.multiply(b2, true); + db1.add(b2).shiftLeft(1).subtract(b0), true, parallel, depth); + vinf = a2.multiply(b2, true, parallel, depth); + v0 = v0_task.join(); + vm1 = vm1_task.join(); + v1 = v1_task.join(); // The algorithm requires two divisions by 2 and one by 3. // All divisions are known to be exact, that is, they do not produce @@ -2071,7 +2184,7 @@ public class BigInteger extends Number implements Comparable { * @return this2 */ private BigInteger square() { - return square(false); + return square(false, false, 0); } /** @@ -2081,7 +2194,7 @@ public class BigInteger extends Number implements Comparable { * @param isRecursion whether this is a recursive invocation * @return this2 */ - private BigInteger square(boolean isRecursion) { + private BigInteger square(boolean isRecursion, boolean parallel, int depth) { if (signum == 0) { return ZERO; } @@ -2103,7 +2216,7 @@ public class BigInteger extends Number implements Comparable { } } - return squareToomCook3(); + return squareToomCook3(parallel, depth); } } } @@ -2237,7 +2350,7 @@ public class BigInteger extends Number implements Comparable { * that has better asymptotic performance than the algorithm used in * squareToLen or squareKaratsuba. */ - private BigInteger squareToomCook3() { + private BigInteger squareToomCook3(boolean parallel, int depth) { int len = mag.length; // k is the size (in ints) of the lower-order slices. @@ -2254,13 +2367,17 @@ public class BigInteger extends Number implements Comparable { a0 = getToomSlice(k, r, 2, len); BigInteger v0, v1, v2, vm1, vinf, t1, t2, tm1, da1; - v0 = a0.square(true); + depth++; + var v0_fork = RecursiveOp.square(a0, parallel, depth); da1 = a2.add(a0); - vm1 = da1.subtract(a1).square(true); + var vm1_fork = RecursiveOp.square(da1.subtract(a1), parallel, depth); da1 = da1.add(a1); - v1 = da1.square(true); - vinf = a2.square(true); - v2 = da1.add(a2).shiftLeft(1).subtract(a0).square(true); + var v1_fork = RecursiveOp.square(da1, parallel, depth); + vinf = a2.square(true, parallel, depth); + v2 = da1.add(a2).shiftLeft(1).subtract(a0).square(true, parallel, depth); + v0 = v0_fork.join(); + vm1 = vm1_fork.join(); + v1 = v1_fork.join(); // The algorithm requires two divisions by 2 and one by 3. // All divisions are known to be exact, that is, they do not produce diff --git a/src/java.base/share/classes/java/math/MathContext.java b/src/java.base/share/classes/java/math/MathContext.java index e53db0f05bd9b44e1bea08b58810032e0519a032..da6de74bb58d557993640685097253b131e1b6b7 100644 --- a/src/java.base/share/classes/java/math/MathContext.java +++ b/src/java.base/share/classes/java/math/MathContext.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -58,7 +58,6 @@ public final class MathContext implements Serializable { /* ----- Constants ----- */ // defaults for constructors - private static final int DEFAULT_DIGITS = 9; private static final RoundingMode DEFAULT_ROUNDINGMODE = RoundingMode.HALF_UP; // Smallest values for digits (Maximum is Integer.MAX_VALUE) private static final int MIN_DIGITS = 0; @@ -140,7 +139,6 @@ public final class MathContext implements Serializable { */ public MathContext(int setPrecision) { this(setPrecision, DEFAULT_ROUNDINGMODE); - return; } /** @@ -162,7 +160,6 @@ public final class MathContext implements Serializable { precision = setPrecision; roundingMode = setRoundingMode; - return; } /** @@ -181,7 +178,6 @@ public final class MathContext implements Serializable { * @throws NullPointerException if the argument is {@code null} */ public MathContext(String val) { - boolean bad = false; int setPrecision; if (val == null) throw new NullPointerException("null String"); @@ -232,7 +228,6 @@ public final class MathContext implements Serializable { * @return a {@code RoundingMode} object which is the value of the * {@code roundingMode} setting */ - public RoundingMode getRoundingMode() { return roundingMode; } diff --git a/src/java.base/share/classes/java/math/MutableBigInteger.java b/src/java.base/share/classes/java/math/MutableBigInteger.java index 7d0ccbf1e09d25b8dd79cfddd6574c3d42719a32..91f710d67b8665103ca0665b0d03eb5fb03ae14a 100644 --- a/src/java.base/share/classes/java/math/MutableBigInteger.java +++ b/src/java.base/share/classes/java/math/MutableBigInteger.java @@ -945,13 +945,13 @@ class MutableBigInteger { x--; y--; diff = (a.value[x+a.offset] & LONG_MASK) - - (b.value[y+b.offset] & LONG_MASK) - ((int)-(diff>>32)); + (b.value[y+b.offset] & LONG_MASK) + (diff >> 32); result[rstart--] = (int)diff; } // Subtract remainder of longer number while (x > 0) { x--; - diff = (a.value[x+a.offset] & LONG_MASK) - ((int)-(diff>>32)); + diff = (a.value[x+a.offset] & LONG_MASK) + (diff >> 32); result[rstart--] = (int)diff; } @@ -986,13 +986,13 @@ class MutableBigInteger { while (y > 0) { x--; y--; diff = (a.value[a.offset+ x] & LONG_MASK) - - (b.value[b.offset+ y] & LONG_MASK) - ((int)-(diff>>32)); + (b.value[b.offset+ y] & LONG_MASK) + (diff >> 32); a.value[a.offset+x] = (int)diff; } // Subtract remainder of longer number - while (x > 0) { + while (diff < 0 && x > 0) { x--; - diff = (a.value[a.offset+ x] & LONG_MASK) - ((int)-(diff>>32)); + diff = (a.value[a.offset+ x] & LONG_MASK) + (diff >> 32); a.value[a.offset+x] = (int)diff; } diff --git a/src/java.base/share/classes/java/net/CookieManager.java b/src/java.base/share/classes/java/net/CookieManager.java index adc405b9b81b3788a2aa72e15201a3b52a6df181..b1540ad5612b9dca151c740cb3fe97782f12aef3 100644 --- a/src/java.base/share/classes/java/net/CookieManager.java +++ b/src/java.base/share/classes/java/net/CookieManager.java @@ -447,13 +447,7 @@ public class CookieManager extends CookieHandler // Check creation time. Sort older first long creation1 = c1.getCreationTime(); long creation2 = c2.getCreationTime(); - if (creation1 < creation2) { - return -1; - } - if (creation1 > creation2) { - return 1; - } - return 0; + return Long.compare(creation1, creation2); } } } diff --git a/src/java.base/share/classes/java/net/DatagramSocket.java b/src/java.base/share/classes/java/net/DatagramSocket.java index 114794be1f9904261ebb8e659424e5824b052e15..1833dd2470dd587ffd139ab0256840caa24c51af 100644 --- a/src/java.base/share/classes/java/net/DatagramSocket.java +++ b/src/java.base/share/classes/java/net/DatagramSocket.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 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 @@ -1353,9 +1353,7 @@ public class DatagramSocket implements java.io.Closeable { Throwable cause = e.getCause(); if (cause instanceof SocketException) return (SocketException) cause; - SocketException se = new SocketException(e.getMessage()); - se.initCause(e); - return se; + return new SocketException(e.getMessage(), e); } /** diff --git a/src/java.base/share/classes/java/net/HttpCookie.java b/src/java.base/share/classes/java/net/HttpCookie.java index dd8ae13914d1c8f4d181450f27db275abc70a532..0214359ccded8a2c4aad9bfe7b1b7bf882be2809 100644 --- a/src/java.base/share/classes/java/net/HttpCookie.java +++ b/src/java.base/share/classes/java/net/HttpCookie.java @@ -1078,13 +1078,13 @@ public final class HttpCookie implements Cloneable { int version = 0; header = header.toLowerCase(); - if (header.indexOf("expires=") != -1) { + if (header.contains("expires=")) { // only netscape cookie using 'expires' version = 0; - } else if (header.indexOf("version=") != -1) { + } else if (header.contains("version=")) { // version is mandatory for rfc 2965/2109 cookie version = 1; - } else if (header.indexOf("max-age") != -1) { + } else if (header.contains("max-age")) { // rfc 2965/2109 use 'max-age' version = 1; } else if (startsWithIgnoreCase(header, SET_COOKIE2)) { diff --git a/src/java.base/share/classes/java/net/HttpURLConnection.java b/src/java.base/share/classes/java/net/HttpURLConnection.java index 9f7779dd011b1d99d70d2a7c610f7b28e84e2070..dba500f017d2d34e07517d7fb42960364772ada2 100644 --- a/src/java.base/share/classes/java/net/HttpURLConnection.java +++ b/src/java.base/share/classes/java/net/HttpURLConnection.java @@ -600,7 +600,7 @@ public abstract class HttpURLConnection extends URLConnection { public long getHeaderFieldDate(String name, long Default) { String dateString = getHeaderField(name); try { - if (dateString.indexOf("GMT") == -1) { + if (!dateString.contains("GMT")) { dateString = dateString+" GMT"; } return Date.parse(dateString); diff --git a/src/java.base/share/classes/java/net/Inet6Address.java b/src/java.base/share/classes/java/net/Inet6Address.java index 751623536e765794de62ce1597af76455d1d5348..325765ff3b621d2dc74bc7b5f7c5682c456ebd6a 100644 --- a/src/java.base/share/classes/java/net/Inet6Address.java +++ b/src/java.base/share/classes/java/net/Inet6Address.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -593,10 +593,6 @@ class Inet6Address extends InetAddress { throws IOException, ClassNotFoundException { NetworkInterface scope_ifname = null; - if (getClass().getClassLoader() != null) { - throw new SecurityException ("invalid address type"); - } - ObjectInputStream.GetField gf = s.readFields(); byte[] ipaddress = (byte[])gf.get("ipaddress", new byte[0]); int scope_id = gf.get("scope_id", -1); diff --git a/src/java.base/share/classes/java/net/InetAddress.java b/src/java.base/share/classes/java/net/InetAddress.java index 3875216768be9deab04ee261dc940cba55f0c336..3bad2755978835aa9a828794510a3f6ee927abb5 100644 --- a/src/java.base/share/classes/java/net/InetAddress.java +++ b/src/java.base/share/classes/java/net/InetAddress.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 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 @@ -44,6 +44,7 @@ import java.io.ObjectInputStream; import java.io.ObjectInputStream.GetField; import java.io.ObjectOutputStream; import java.io.ObjectOutputStream.PutField; +import java.io.Serializable; import java.lang.annotation.Native; import java.util.ServiceLoader; import java.util.concurrent.ConcurrentHashMap; @@ -223,7 +224,7 @@ import static java.net.spi.InetAddressResolver.LookupPolicy.IPV6_FIRST; * @see java.net.InetAddress#getLocalHost() * @since 1.0 */ -public class InetAddress implements java.io.Serializable { +public sealed class InetAddress implements Serializable permits Inet4Address, Inet6Address { /** * Specify the address family: Internet Protocol, Version 4 @@ -1769,16 +1770,6 @@ public class InetAddress implements java.io.Serializable { return impl.anyLocalAddress(); } - /** - * Initializes an empty InetAddress. - */ - @java.io.Serial - private void readObjectNoData () { - if (getClass().getClassLoader() != null) { - throw new SecurityException ("invalid address type"); - } - } - private static final jdk.internal.misc.Unsafe UNSAFE = jdk.internal.misc.Unsafe.getUnsafe(); private static final long FIELDS_OFFSET @@ -1794,9 +1785,6 @@ public class InetAddress implements java.io.Serializable { @java.io.Serial private void readObject (ObjectInputStream s) throws IOException, ClassNotFoundException { - if (getClass().getClassLoader() != null) { - throw new SecurityException ("invalid address type"); - } GetField gf = s.readFields(); String host = (String)gf.get("hostName", null); int address = gf.get("address", 0); @@ -1830,11 +1818,7 @@ public class InetAddress implements java.io.Serializable { * @throws IOException if an I/O error occurs */ @java.io.Serial - private void writeObject (ObjectOutputStream s) throws - IOException { - if (getClass().getClassLoader() != null) { - throw new SecurityException ("invalid address type"); - } + private void writeObject (ObjectOutputStream s) throws IOException { PutField pf = s.putFields(); pf.put("hostName", holder().getHostName()); pf.put("address", holder().getAddress()); diff --git a/src/java.base/share/classes/java/net/ServerSocket.java b/src/java.base/share/classes/java/net/ServerSocket.java index 3d985f84df3cebf5e761d441a807714c56c49f3d..9441e6476e31967d88795e8667b966dd6749ee48 100644 --- a/src/java.base/share/classes/java/net/ServerSocket.java +++ b/src/java.base/share/classes/java/net/ServerSocket.java @@ -78,17 +78,17 @@ import sun.net.PlatformSocketImpl; */ public class ServerSocket implements java.io.Closeable { /** - * Various states of this socket. + * The underlying SocketImpl */ - private boolean created = false; - private boolean bound = false; - private boolean closed = false; - private Object closeLock = new Object(); + private final SocketImpl impl; /** - * The implementation of this Socket. + * Various states of this socket, need stateLock to change. */ - private SocketImpl impl; + private volatile boolean created; // impl.create(boolean) called + private volatile boolean bound; + private volatile boolean closed; + private final Object stateLock = new Object(); /** * Creates a server socket with a user-specified {@code SocketImpl}. @@ -124,7 +124,7 @@ public class ServerSocket implements java.io.Closeable { * @revised 1.4 */ public ServerSocket() throws IOException { - setImpl(); + this.impl = createImpl(); } /** @@ -264,18 +264,15 @@ public class ServerSocket implements java.io.Closeable { * @since 1.1 */ public ServerSocket(int port, int backlog, InetAddress bindAddr) throws IOException { - setImpl(); if (port < 0 || port > 0xFFFF) - throw new IllegalArgumentException( - "Port value out of range: " + port); + throw new IllegalArgumentException("Port value out of range: " + port); if (backlog < 1) - backlog = 50; + backlog = 50; + + this.impl = createImpl(); try { bind(new InetSocketAddress(bindAddr, port), backlog); - } catch(SecurityException e) { - close(); - throw e; - } catch(IOException e) { + } catch (IOException | SecurityException e) { close(); throw e; } @@ -289,35 +286,36 @@ public class ServerSocket implements java.io.Closeable { * @throws SocketException if creation fails. * @since 1.4 */ - SocketImpl getImpl() throws SocketException { - if (!created) - createImpl(); + private SocketImpl getImpl() throws SocketException { + if (!created) { + synchronized (stateLock) { + if (!created) { + if (closed) { + throw new SocketException("Socket is closed"); + } + try { + impl.create(true); + } catch (SocketException e) { + throw e; + } catch (IOException e) { + throw new SocketException(e.getMessage()); + } + created = true; + } + } + } return impl; } - private void setImpl() { + /** + * Create a SocketImpl for a server socket. + */ + private static SocketImpl createImpl() { SocketImplFactory factory = ServerSocket.factory; if (factory != null) { - impl = factory.createSocketImpl(); + return factory.createSocketImpl(); } else { - impl = SocketImpl.createPlatformSocketImpl(true); - } - } - - /** - * Creates the socket implementation. - * - * @throws SocketException if creation fails - * @since 1.4 - */ - void createImpl() throws SocketException { - if (impl == null) - setImpl(); - try { - impl.create(true); - created = true; - } catch (IOException e) { - throw new SocketException(e.getMessage()); + return SocketImpl.createPlatformSocketImpl(true); } } @@ -379,21 +377,21 @@ public class ServerSocket implements java.io.Closeable { if (epoint.isUnresolved()) throw new SocketException("Unresolved address"); if (backlog < 1) - backlog = 50; - try { - @SuppressWarnings("removal") - SecurityManager security = System.getSecurityManager(); - if (security != null) - security.checkListen(epoint.getPort()); + backlog = 50; + + @SuppressWarnings("removal") + SecurityManager security = System.getSecurityManager(); + if (security != null) + security.checkListen(epoint.getPort()); + + synchronized (stateLock) { + if (closed) + throw new SocketException("Socket is closed"); + if (bound) + throw new SocketException("Already bound"); getImpl().bind(epoint.getAddress(), epoint.getPort()); getImpl().listen(backlog); bound = true; - } catch(SecurityException e) { - bound = false; - throw e; - } catch(IOException e) { - bound = false; - throw e; } } @@ -711,12 +709,15 @@ public class ServerSocket implements java.io.Closeable { * @revised 1.4 */ public void close() throws IOException { - synchronized(closeLock) { - if (isClosed()) - return; - if (created) - impl.close(); - closed = true; + synchronized (stateLock) { + if (!closed) { + closed = true; + + // close underlying socket if created + if (created) { + impl.close(); + } + } } } @@ -760,9 +761,7 @@ public class ServerSocket implements java.io.Closeable { * @since 1.4 */ public boolean isClosed() { - synchronized(closeLock) { - return closed; - } + return closed; } /** @@ -783,7 +782,7 @@ public class ServerSocket implements java.io.Closeable { * @since 1.1 * @see #getSoTimeout() */ - public synchronized void setSoTimeout(int timeout) throws SocketException { + public void setSoTimeout(int timeout) throws SocketException { if (isClosed()) throw new SocketException("Socket is closed"); if (timeout < 0) @@ -799,7 +798,7 @@ public class ServerSocket implements java.io.Closeable { * @since 1.1 * @see #setSoTimeout(int) */ - public synchronized int getSoTimeout() throws IOException { + public int getSoTimeout() throws IOException { if (isClosed()) throw new SocketException("Socket is closed"); Object o = getImpl().getOption(SocketOptions.SO_TIMEOUT); @@ -984,7 +983,7 @@ public class ServerSocket implements java.io.Closeable { * @since 1.4 * @see #getReceiveBufferSize */ - public synchronized void setReceiveBufferSize (int size) throws SocketException { + public void setReceiveBufferSize (int size) throws SocketException { if (!(size > 0)) { throw new IllegalArgumentException("negative receive size"); } @@ -1007,8 +1006,7 @@ public class ServerSocket implements java.io.Closeable { * @see #setReceiveBufferSize(int) * @since 1.4 */ - public synchronized int getReceiveBufferSize() - throws SocketException{ + public int getReceiveBufferSize() throws SocketException { if (isClosed()) throw new SocketException("Socket is closed"); int result = 0; diff --git a/src/java.base/share/classes/java/net/SocketException.java b/src/java.base/share/classes/java/net/SocketException.java index f4a412258dfa33e7a94dba690a6d1ce044bae77c..7b73824992398380c6c9c55bbeb135fd49ea7fec 100644 --- a/src/java.base/share/classes/java/net/SocketException.java +++ b/src/java.base/share/classes/java/net/SocketException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 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 @@ -52,4 +52,27 @@ public class SocketException extends IOException { */ public SocketException() { } + + /** + * Constructs a new {@code SocketException} with the + * specified detail message and cause. + * + * @param msg the detail message. + * @param cause the cause + * @since 19 + */ + public SocketException(String msg, Throwable cause) { + super(msg, cause); + } + + /** + * Constructs a new {@code SocketException} with the + * specified cause. + * + * @param cause the cause + * @since 19 + */ + public SocketException(Throwable cause) { + super(cause); + } } diff --git a/src/java.base/share/classes/java/net/SocketPermission.java b/src/java.base/share/classes/java/net/SocketPermission.java index a3101c50ca368bdf0f1437ff066b6da2b7645149..aca7642931f4a9610ab249facbacc5e6831decf4 100644 --- a/src/java.base/share/classes/java/net/SocketPermission.java +++ b/src/java.base/share/classes/java/net/SocketPermission.java @@ -30,12 +30,10 @@ import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.ObjectStreamField; import java.io.Serializable; -import java.net.InetAddress; import java.security.AccessController; import java.security.Permission; import java.security.PermissionCollection; import java.security.PrivilegedAction; -import java.security.Security; import java.util.Collections; import java.util.Enumeration; import java.util.Map; @@ -333,7 +331,7 @@ public final class SocketPermission extends Permission ind = host.lastIndexOf(':'); host = "[" + host.substring(0, ind) + "]" + host.substring(ind); - } else if (tokens == 8 && host.indexOf("::") == -1) { + } else if (tokens == 8 && !host.contains("::")) { // IPv6 address only, not followed by port host = "[" + host + "]"; } else { 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 0c2d3e232dad4ef40d03d713ec36b1679dbc5cbd..e2d8bfe755c4577b11d59a887b8e12448c1fa2a4 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 @@ -176,6 +176,16 @@ of proxies.

          If HTTP keepalive is enabled (see above) this value determines the maximum number of idle connections that will be simultaneously kept alive, per destination.

          +
        • {@systemProperty http.keepAlive.time.server} and + {@systemProperty http.keepAlive.time.proxy}

          +

          These properties modify the behavior of the HTTP keepalive cache in the case + where the server (or proxy) has not specified a keepalive time. If the + property is set in this case, then idle connections will be closed after the + specified number of seconds. If the property is set, and the server does + specify a keepalive time in a "Keep-Alive" response header, then the time specified + by the server is used. If the property is not set and also the server + does not specify a keepalive time, then connections are kept alive for an + implementation defined time, assuming {@code http.keepAlive} is {@code true}.

        • {@systemProperty http.maxRedirects} (default: {@code 20})
          This integer value determines the maximum number, for a given request, of HTTP redirects that will be automatically followed by the @@ -214,6 +224,22 @@ of proxies.

          property is defined, then its value will be used as the domain name.

          +
        • {@systemProperty jdk.https.negotiate.cbt} (default: <never>)
          + This controls the generation and sending of TLS channel binding tokens (CBT) when Kerberos + or the Negotiate authentication scheme using Kerberos are employed over HTTPS with + {@code HttpsURLConnection}. There are three possible settings:

          +
            +
          1. "never". This is also the default value if the property is not set. In this case, + CBTs are never sent.

            +
          2. "always". CBTs are sent for all Kerberos authentication attempts over HTTPS.

            +
          3. "domain:<comma separated domain list>" Each domain in the list specifies destination + host or hosts for which a CBT is sent. Domains can be single hosts like foo, or foo.com, + or literal IP addresses as specified in RFC 2732, or wildcards like *.foo.com which matches + all hosts under foo.com and its sub-domains. CBTs are not sent to any destinations + that don't match one of the list entries

            +
          +

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

          All these properties are checked only once at startup.

          diff --git a/src/java.base/share/classes/java/net/package-info.java b/src/java.base/share/classes/java/net/package-info.java index b221c6bf2f73de4f12967a0d464afdc6ea715d2c..6fc9913dfedd3b520cdf07ab611ef1af4822c8c7 100644 --- a/src/java.base/share/classes/java/net/package-info.java +++ b/src/java.base/share/classes/java/net/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -122,7 +122,7 @@ *
        • {@link java.net.HttpURLConnection} is a subclass of URLConnection * and provides some additional functionalities specific to the * HTTP protocol. This API has been superseded by the newer - * {@linkplain java.net.http HTTP Client API}.
        • + * {@linkplain java.net.http/java.net.http HTTP Client API}. * *

          The recommended usage is to use {@link java.net.URI} to identify * resources, then convert it into a {@link java.net.URL} when it is time to @@ -157,4 +157,5 @@ * * @since 1.0 */ +@SuppressWarnings("doclint:reference") // cross-module links package java.net; diff --git a/src/java.base/share/classes/java/net/spi/InetAddressResolverProvider.java b/src/java.base/share/classes/java/net/spi/InetAddressResolverProvider.java index 30f1c4f5b3e7e33bc4bc441c3a8a45c883420349..6dff033ffc8897763324c7c18d126f4ea40a13aa 100644 --- a/src/java.base/share/classes/java/net/spi/InetAddressResolverProvider.java +++ b/src/java.base/share/classes/java/net/spi/InetAddressResolverProvider.java @@ -66,7 +66,8 @@ import java.util.ServiceLoader; * *

          If instantiating a custom resolver from a provider discovered in * step 1 throws an error or exception, the system-wide resolver will not be - * set and the error or exception will be propagated to the calling thread. + * set and the error or exception will be propagated to the caller of the method + * that triggered the lookup operation. * Otherwise, any lookup operation will be performed using the * system-wide resolver. * @@ -85,7 +86,7 @@ public abstract class InetAddressResolverProvider { * *

          Any error or exception thrown by this method is considered as * a failure of {@code InetAddressResolver} instantiation and will be propagated to - * the calling thread. + * the caller of the method that triggered the lookup operation. * @param configuration a {@link Configuration} instance containing platform built-in address * resolution configuration. * @return the resolver provided by this provider diff --git a/src/java.base/share/classes/java/nio/Buffer.java b/src/java.base/share/classes/java/nio/Buffer.java index 607d5d45183d7c25386cf86b425d9b756ad74e63..a452b1a28dd435e454104f05c36dc5e4a1dee223 100644 --- a/src/java.base/share/classes/java/nio/Buffer.java +++ b/src/java.base/share/classes/java/nio/Buffer.java @@ -767,7 +767,11 @@ public abstract class Buffer { final void checkScope() { ScopedMemoryAccess.Scope scope = scope(); if (scope != null) { - scope.checkValidState(); + try { + scope.checkValidState(); + } catch (ScopedMemoryAccess.Scope.ScopedAccessError e) { + throw new IllegalStateException("This segment is already closed"); + } } } @@ -820,7 +824,7 @@ public abstract class Buffer { } @Override - public Scope.Handle acquireScope(Buffer buffer, boolean async) { + public Runnable acquireScope(Buffer buffer, boolean async) { var scope = buffer.scope(); if (scope == null) { return null; @@ -828,7 +832,8 @@ public abstract class Buffer { if (async && scope.ownerThread() != null) { throw new IllegalStateException("Confined scope not supported"); } - return scope.acquire(); + scope.acquire0(); + return scope::release0; } @Override diff --git a/src/java.base/share/classes/java/nio/Heap-X-Buffer.java.template b/src/java.base/share/classes/java/nio/Heap-X-Buffer.java.template index 53d099396e13b497150b296f2213f11293538fb5..38e18ac625b9121e9f9e04c41ff9f021e8f71d15 100644 --- a/src/java.base/share/classes/java/nio/Heap-X-Buffer.java.template +++ b/src/java.base/share/classes/java/nio/Heap-X-Buffer.java.template @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -40,10 +40,10 @@ import jdk.internal.access.foreign.MemorySegmentProxy; * instance of this class rather than of the superclass. #end[rw] */ - class Heap$Type$Buffer$RW$ extends {#if[ro]?Heap}$Type$Buffer { +#if[rw] // Cached array base offset private static final long ARRAY_BASE_OFFSET = UNSAFE.arrayBaseOffset($type$[].class); @@ -53,11 +53,10 @@ class Heap$Type$Buffer$RW$ // For speed these fields are actually declared in X-Buffer; // these declarations are here as documentation /* -#if[rw] protected final $type$[] hb; protected final int offset; -#end[rw] */ +#end[rw] Heap$Type$Buffer$RW$(int cap, int lim, MemorySegmentProxy segment) { // package-private #if[rw] diff --git a/src/java.base/share/classes/java/nio/channels/AsynchronousFileChannel.java b/src/java.base/share/classes/java/nio/channels/AsynchronousFileChannel.java index 09054e30f8630e61c11b45f2d6460957d257afd3..2ad51f80a452b2c2f8a1200973fe982f0fb01723 100644 --- a/src/java.base/share/classes/java/nio/channels/AsynchronousFileChannel.java +++ b/src/java.base/share/classes/java/nio/channels/AsynchronousFileChannel.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 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 @@ -425,10 +425,13 @@ public abstract class AsynchronousFileChannel * required then a region starting at zero, and no smaller than the * expected maximum size of the file, should be locked. The two-argument * {@link #lock(Object,CompletionHandler)} method simply locks a region - * of size {@link Long#MAX_VALUE}. If a lock that overlaps the requested - * region is already held by this Java virtual machine, or this method has - * been invoked to lock an overlapping region and that operation has not - * completed, then this method throws {@link OverlappingFileLockException}. + * of size {@link Long#MAX_VALUE}. If the {@code position} is non-negative + * and the {@code size} is zero, then a lock of size + * {@code Long.MAX_VALUE - position} is returned. If a lock that + * overlaps the requested region is already held by this Java virtual + * machine, or this method has been invoked to lock an overlapping region + * and that operation has not completed, then this method throws + * {@link OverlappingFileLockException}. * *

          Some operating systems do not support a mechanism to acquire a file * lock in an asynchronous manner. Consequently an implementation may @@ -454,7 +457,10 @@ public abstract class AsynchronousFileChannel * non-negative * @param size * The size of the locked region; must be non-negative, and the sum - * {@code position} + {@code size} must be non-negative + * {@code position} + {@code size} must be non-negative. + * A value of zero means to lock all bytes from the specified + * starting position to the end of the file, regardless of whether + * the file is subsequently extended or truncated * @param shared * {@code true} to request a shared lock, in which case this * channel must be open for reading (and possibly writing); @@ -532,7 +538,10 @@ public abstract class AsynchronousFileChannel * non-negative * @param size * The size of the locked region; must be non-negative, and the sum - * {@code position} + {@code size} must be non-negative + * {@code position} + {@code size} must be non-negative. + * A value of zero means to lock all bytes from the specified + * starting position to the end of the file, regardless of whether + * the file is subsequently extended or truncated * @param shared * {@code true} to request a shared lock, in which case this * channel must be open for reading (and possibly writing); @@ -586,7 +595,9 @@ public abstract class AsynchronousFileChannel * either having acquired a lock on the requested region or having failed to * do so. If it fails to acquire a lock because an overlapping lock is held * by another program then it returns {@code null}. If it fails to acquire - * a lock for any other reason then an appropriate exception is thrown. + * a lock for any other reason then an appropriate exception is thrown. If + * the {@code position} is non-negative and the {@code size} is zero, then a + * lock of size {@code Long.MAX_VALUE - position} is returned. * * @param position * The position at which the locked region is to start; must be @@ -594,7 +605,10 @@ public abstract class AsynchronousFileChannel * * @param size * The size of the locked region; must be non-negative, and the sum - * {@code position} + {@code size} must be non-negative + * {@code position} + {@code size} must be non-negative. + * A value of zero means to lock all bytes from the specified + * starting position to the end of the file, regardless of whether + * the file is subsequently extended or truncated * * @param shared * {@code true} to request a shared lock, diff --git a/src/java.base/share/classes/java/nio/channels/Channels.java b/src/java.base/share/classes/java/nio/channels/Channels.java index 2d1637c53694973f6b193fd337080198cc0ac118..1d2ccaa778889a66a14436c8654e1cd668be23fe 100644 --- a/src/java.base/share/classes/java/nio/channels/Channels.java +++ b/src/java.base/share/classes/java/nio/channels/Channels.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -40,8 +40,6 @@ import java.nio.charset.UnsupportedCharsetException; import java.nio.channels.spi.AbstractInterruptibleChannel; import java.util.Objects; import java.util.concurrent.ExecutionException; -import sun.nio.ch.ChannelInputStream; -import sun.nio.ch.ChannelOutputStream; import sun.nio.cs.StreamDecoder; import sun.nio.cs.StreamEncoder; @@ -69,9 +67,12 @@ public final class Channels { /** * Constructs a stream that reads bytes from the given channel. * - *

          The {@code read} methods of the resulting stream will throw an - * {@link IllegalBlockingModeException} if invoked while the underlying - * channel is in non-blocking mode. The stream will not be buffered, and + *

          The {@code read} and {@code transferTo} methods of the resulting stream + * will throw an {@link IllegalBlockingModeException} if invoked while the + * underlying channel is in non-blocking mode. The {@code transferTo} method + * will also throw an {@code IllegalBlockingModeException} if invoked to + * transfer bytes to an output stream that writes to an underlying channel in + * non-blocking mode. The stream will not be buffered, and * it will not support the {@link InputStream#mark mark} or {@link * InputStream#reset reset} methods. The stream will be safe for access by * multiple concurrent threads. Closing the stream will in turn cause the @@ -84,7 +85,7 @@ public final class Channels { */ public static InputStream newInputStream(ReadableByteChannel ch) { Objects.requireNonNull(ch, "ch"); - return new ChannelInputStream(ch); + return sun.nio.ch.Streams.of(ch); } /** @@ -103,7 +104,7 @@ public final class Channels { */ public static OutputStream newOutputStream(WritableByteChannel ch) { Objects.requireNonNull(ch, "ch"); - return new ChannelOutputStream(ch); + return sun.nio.ch.Streams.of(ch); } /** diff --git a/src/java.base/share/classes/java/nio/channels/FileChannel.java b/src/java.base/share/classes/java/nio/channels/FileChannel.java index 2ea213b3509e859c1f6086d211b89c8fac49da93..524e8e67cee08fcd3792207a43607e136cf39ffb 100644 --- a/src/java.base/share/classes/java/nio/channels/FileChannel.java +++ b/src/java.base/share/classes/java/nio/channels/FileChannel.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -25,13 +25,16 @@ package java.nio.channels; -import java.io.*; +import java.io.IOException; import java.nio.ByteBuffer; import java.nio.MappedByteBuffer; import java.nio.channels.spi.AbstractInterruptibleChannel; -import java.nio.file.*; +import java.nio.file.FileAlreadyExistsException; +import java.nio.file.OpenOption; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; import java.nio.file.attribute.FileAttribute; -import java.nio.file.spi.*; +import java.nio.file.spi.FileSystemProvider; import java.util.Set; import java.util.HashSet; import java.util.Collections; @@ -403,6 +406,9 @@ public abstract class FileChannel * with the number of bytes actually written. Otherwise this method * behaves exactly as specified by the {@link WritableByteChannel} * interface.

          + * + * @throws NonWritableChannelException + * If this channel was not opened for writing */ public abstract int write(ByteBuffer src) throws IOException; @@ -417,6 +423,9 @@ public abstract class FileChannel * with the number of bytes actually written. Otherwise this method * behaves exactly as specified in the {@link GatheringByteChannel} * interface.

          + * + * @throws NonWritableChannelException + * If this channel was not opened for writing */ public abstract long write(ByteBuffer[] srcs, int offset, int length) throws IOException; @@ -431,6 +440,9 @@ public abstract class FileChannel * with the number of bytes actually written. Otherwise this method * behaves exactly as specified in the {@link GatheringByteChannel} * interface.

          + * + * @throws NonWritableChannelException + * If this channel was not opened for writing */ public final long write(ByteBuffer[] srcs) throws IOException { return write(srcs, 0, srcs.length); @@ -554,8 +566,11 @@ public abstract class FileChannel * actually done is system-dependent and is therefore unspecified. * *

          This method is only guaranteed to force changes that were made to - * this channel's file via the methods defined in this class. It may or - * may not force changes that were made by modifying the content of a + * this channel's file via the methods defined in this class, or the methods + * defined by {@link java.io.FileOutputStream} or + * {@link java.io.RandomAccessFile} when the channel was obtained with the + * {@code getChannel} method. It may or may not force changes that were made + * by modifying the content of a * {@link MappedByteBuffer mapped byte buffer} obtained by * invoking the {@link #map map} method. Invoking the {@link * MappedByteBuffer#force force} method of the mapped byte buffer will @@ -981,7 +996,9 @@ public abstract class FileChannel * required then a region starting at zero, and no smaller than the * expected maximum size of the file, should be locked. The zero-argument * {@link #lock()} method simply locks a region of size {@link - * Long#MAX_VALUE}. + * Long#MAX_VALUE}. If the {@code position} is non-negative and the + * {@code size} is zero, then a lock of size + * {@code Long.MAX_VALUE - position} is returned. * *

          Some operating systems do not support shared locks, in which case a * request for a shared lock is automatically converted into a request for @@ -999,7 +1016,10 @@ public abstract class FileChannel * * @param size * The size of the locked region; must be non-negative, and the sum - * {@code position} + {@code size} must be non-negative + * {@code position} + {@code size} must be non-negative. + * A value of zero means to lock all bytes from the specified + * starting position to the end of the file, regardless of whether + * the file is subsequently extended or truncated * * @param shared * {@code true} to request a shared lock, in which case this @@ -1030,7 +1050,7 @@ public abstract class FileChannel * region * * @throws NonReadableChannelException - * If {@code shared} is {@code true} this channel was not + * If {@code shared} is {@code true} but this channel was not * opened for reading * * @throws NonWritableChannelException @@ -1108,7 +1128,9 @@ public abstract class FileChannel * required then a region starting at zero, and no smaller than the * expected maximum size of the file, should be locked. The zero-argument * {@link #tryLock()} method simply locks a region of size {@link - * Long#MAX_VALUE}. + * Long#MAX_VALUE}. If the {@code position} is non-negative and the + * {@code size} is zero, then a lock of size + * {@code Long.MAX_VALUE - position} is returned. * *

          Some operating systems do not support shared locks, in which case a * request for a shared lock is automatically converted into a request for @@ -1126,7 +1148,10 @@ public abstract class FileChannel * * @param size * The size of the locked region; must be non-negative, and the sum - * {@code position} + {@code size} must be non-negative + * {@code position} + {@code size} must be non-negative. + * A value of zero means to lock all bytes from the specified + * starting position to the end of the file, regardless of whether + * the file is subsequently extended or truncated * * @param shared * {@code true} to request a shared lock, @@ -1148,6 +1173,14 @@ public abstract class FileChannel * blocked in this method and is attempting to lock an overlapping * region of the same file * + * @throws NonReadableChannelException + * If {@code shared} is {@code true} but this channel was not + * opened for reading + * + * @throws NonWritableChannelException + * If {@code shared} is {@code false} but this channel was not + * opened for writing + * * @throws IOException * If some other I/O error occurs * @@ -1180,6 +1213,9 @@ public abstract class FileChannel * blocked in this method and is attempting to lock an overlapping * region * + * @throws NonWritableChannelException + * If this channel was not opened for writing + * * @throws IOException * If some other I/O error occurs * diff --git a/src/java.base/share/classes/java/nio/channels/FileLock.java b/src/java.base/share/classes/java/nio/channels/FileLock.java index 0edd94d5e2520d0e31c64d35ffcd193627ad101f..3bd0b9c7b2ca988b27fe8a81723f553568c6f7ea 100644 --- a/src/java.base/share/classes/java/nio/channels/FileLock.java +++ b/src/java.base/share/classes/java/nio/channels/FileLock.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -269,14 +269,36 @@ public abstract class FileLock implements AutoCloseable { * @param size * The size of the lock range * - * @return {@code true} if, and only if, this lock and the given lock - * range overlap by at least one byte + * @return {@code true} if this lock and the given lock range overlap + * by at least one byte; {@code false} if {@code size} is + * negative or the lock range does not overlap this lock */ public final boolean overlaps(long position, long size) { - if (position + size <= this.position) - return false; // That is below this - if (this.position + this.size <= position) - return false; // This is below that + if (size < 0) + return false; + + // Test whether this is below that + try { + if (Math.addExact(this.position, this.size) <= position) + return false; + } catch (ArithmeticException ignored) { + // the sum of this.position and this.size overflows the range of + // long hence their mathematical sum is greater than position + } + + // if size == 0 then the specified lock range is unbounded and + // cannot be below the range of this lock + if (size > 0) { + // Test whether that is below this + try { + if (Math.addExact(position, size) <= this.position) + return false; + } catch (ArithmeticException ignored) { + // the sum of position and size overflows the range of long + // hence their mathematical sum is greater than this.position + } + } + return true; } diff --git a/src/java.base/share/classes/java/nio/channels/Selector.java b/src/java.base/share/classes/java/nio/channels/Selector.java index 4fb98f3a8cea70373c49c5b0e4887d35a588bd26..d8c0dc261bd6a9835fcd848b2a0a588a06d2dca1 100644 --- a/src/java.base/share/classes/java/nio/channels/Selector.java +++ b/src/java.base/share/classes/java/nio/channels/Selector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -355,7 +355,8 @@ public abstract class Selector implements Closeable { * of the {@link #wakeup wakeup} method.

          * * @return The number of keys, possibly zero, whose ready-operation sets - * were updated by the selection operation + * now indicate readiness for at least one category of operations + * for which the channel was not previously detected to be ready * * @throws IOException * If an I/O error occurs @@ -383,8 +384,9 @@ public abstract class Selector implements Closeable { * channel to become ready; if zero, block indefinitely; * must not be negative * - * @return The number of keys, possibly zero, - * whose ready-operation sets were updated + * @return The number of keys, possibly zero, whose ready-operation sets + * now indicate readiness for at least one category of operations + * for which the channel was not previously detected to be ready * * @throws IOException * If an I/O error occurs @@ -406,8 +408,9 @@ public abstract class Selector implements Closeable { * this selector's {@link #wakeup wakeup} method is invoked, or the current * thread is interrupted, whichever comes first.

          * - * @return The number of keys, possibly zero, - * whose ready-operation sets were updated + * @return The number of keys, possibly zero, whose ready-operation sets + * now indicate readiness for at least one category of operations + * for which the channel was not previously detected to be ready * * @throws IOException * If an I/O error occurs diff --git a/src/java.base/share/classes/java/nio/file/CopyMoveHelper.java b/src/java.base/share/classes/java/nio/file/CopyMoveHelper.java index ab9281807fdcd314b8072133d1268be3be3f784c..e5ca66fa631acbfbea06d6172868eb4bf3d8734f 100644 --- a/src/java.base/share/classes/java/nio/file/CopyMoveHelper.java +++ b/src/java.base/share/classes/java/nio/file/CopyMoveHelper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 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 @@ -105,11 +105,20 @@ class CopyMoveHelper { LinkOption[] linkOptions = (opts.followLinks) ? new LinkOption[0] : new LinkOption[] { LinkOption.NOFOLLOW_LINKS }; + // retrieve source posix view, null if unsupported + final PosixFileAttributeView sourcePosixView = + Files.getFileAttributeView(source, PosixFileAttributeView.class); + // attributes of source file - BasicFileAttributes attrs = Files.readAttributes(source, - BasicFileAttributes.class, - linkOptions); - if (attrs.isSymbolicLink()) + BasicFileAttributes sourceAttrs = sourcePosixView != null ? + Files.readAttributes(source, + PosixFileAttributes.class, + linkOptions) : + Files.readAttributes(source, + BasicFileAttributes.class, + linkOptions); + + if (sourceAttrs.isSymbolicLink()) throw new IOException("Copying of symbolic links not supported"); // delete target if it exists and REPLACE_EXISTING is specified @@ -119,7 +128,7 @@ class CopyMoveHelper { throw new FileAlreadyExistsException(target.toString()); // create directory or copy file - if (attrs.isDirectory()) { + if (sourceAttrs.isDirectory()) { Files.createDirectory(target); } else { try (InputStream in = Files.newInputStream(source)) { @@ -127,14 +136,29 @@ class CopyMoveHelper { } } - // copy basic attributes to target + // copy basic and, if supported, POSIX attributes to target if (opts.copyAttributes) { - BasicFileAttributeView view = - Files.getFileAttributeView(target, BasicFileAttributeView.class); + BasicFileAttributeView targetView = null; + if (sourcePosixView != null) { + targetView = Files.getFileAttributeView(target, + PosixFileAttributeView.class); + } + + // target might not support posix even if source does + if (targetView == null) { + targetView = Files.getFileAttributeView(target, + BasicFileAttributeView.class); + } + try { - view.setTimes(attrs.lastModifiedTime(), - attrs.lastAccessTime(), - attrs.creationTime()); + targetView.setTimes(sourceAttrs.lastModifiedTime(), + sourceAttrs.lastAccessTime(), + sourceAttrs.creationTime()); + + if (sourceAttrs instanceof PosixFileAttributes sourcePosixAttrs && + targetView instanceof PosixFileAttributeView targetPosixView) { + targetPosixView.setPermissions(sourcePosixAttrs.permissions()); + } } catch (Throwable x) { // rollback try { diff --git a/src/java.base/share/classes/java/nio/file/Files.java b/src/java.base/share/classes/java/nio/file/Files.java index 98efa051d11841d4cd00f2b0636dbc2db31d87b2..0d9bba9cbcae707d327d8d685e179a1536c86771 100644 --- a/src/java.base/share/classes/java/nio/file/Files.java +++ b/src/java.base/share/classes/java/nio/file/Files.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 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 @@ -824,7 +824,7 @@ public final class Files { * java.io.File#createTempFile(String,String,File)} method. * *

          As with the {@code File.createTempFile} methods, this method is only - * part of a temporary-file facility. Where used as a work files, + * part of a temporary-file facility. Where used as a work file, * the resulting file may be opened using the {@link * StandardOpenOption#DELETE_ON_CLOSE DELETE_ON_CLOSE} option so that the * file is deleted when the appropriate {@code close} method is invoked. @@ -1552,7 +1552,7 @@ public final class Files { *

            *
          • The two paths locate the {@linkplain #isSameFile(Path, Path) same file}, * even if two {@linkplain Path#equals(Object) equal} paths locate a file - * does not exist, or
          • + * that does not exist, or *
          • The two files are the same size, and every byte in the first file * is identical to the corresponding byte in the second file.
          • *
          @@ -1561,7 +1561,7 @@ public final class Files { * returned by this method is: *
            *
          • The position of the first mismatched byte, or
          • - *
          • The size of the smaller file (in bytes) when the files are different + *
          • The size of the smaller file (in bytes) when the files are of different * sizes and every byte of the smaller file is identical to the * corresponding byte of the larger file.
          • *
          diff --git a/src/java.base/share/classes/java/security/AccessControlContext.java b/src/java.base/share/classes/java/security/AccessControlContext.java index a7f3641bedadcc5181e6f99dd887596c65bbaddf..1cb35d9bdfc407c4532eb2d5a99bbbaac07a9f6b 100644 --- a/src/java.base/share/classes/java/security/AccessControlContext.java +++ b/src/java.base/share/classes/java/security/AccessControlContext.java @@ -916,7 +916,6 @@ public final class AccessControlContext { private boolean containsAllLimits(AccessControlContext that) { boolean match = false; - Permission thisPerm; if (this.permissions == null && that.permissions == null) return true; diff --git a/src/java.base/share/classes/java/security/Key.java b/src/java.base/share/classes/java/security/Key.java index b0159f0b33e207dd9b22928fb5fb876054974f36..4ea5ae0887b08807eec9b9107abb8c1d6885e7ca 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, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 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 @@ -84,7 +84,7 @@ package java.security; * which should not be exposed in untrusted environments. See the * * Security Appendix - * of the Serialization Specification for more information. + * of the Java Object Serialization Specification for more information. * * @see PublicKey * @see PrivateKey diff --git a/src/java.base/share/classes/java/security/KeyRep.java b/src/java.base/share/classes/java/security/KeyRep.java index 341c3d99af1bf819836c4a8a18c289290a3573e3..779f5a7181afb2c8d9da0bf36a54874520d39804 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, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -44,7 +44,7 @@ import javax.crypto.spec.SecretKeySpec; * which should not be exposed in untrusted environments. See the * * Security Appendix - * of the Serialization Specification for more information. + * of the Java Object Serialization Specification for more information. * * @see Key * @see KeyFactory diff --git a/src/java.base/share/classes/java/security/KeyStore.java b/src/java.base/share/classes/java/security/KeyStore.java index 2edbe65d26d57b5f69dbf55253b8e04e9e2f0516..efc18f53d33ebfff80457961df2caa35c57e6a49 100644 --- a/src/java.base/share/classes/java/security/KeyStore.java +++ b/src/java.base/share/classes/java/security/KeyStore.java @@ -1020,6 +1020,34 @@ public class KeyStore { return this.type; } + /** + * Retrieves the attributes associated with the given alias. + * + * @param alias the alias name + * @return an unmodifiable {@code Set} of attributes. This set is + * empty if the {@code KeyStoreSpi} implementation has not overridden + * {@link KeyStoreSpi#engineGetAttributes(String)}, or the given + * alias does not exist, or there are no attributes associated + * with the alias. This set may also be empty for + * {@code PrivateKeyEntry} or {@code SecretKeyEntry} + * entries that contain protected attributes and are only available + * through the {@link Entry#getAttributes} method after the entry + * is extracted. + * + * @throws KeyStoreException if the keystore has not been initialized + * (loaded). + * @throws NullPointerException if {@code alias} is {@code null} + * + * @since 18 + */ + public final Set getAttributes(String alias) + throws KeyStoreException { + if (!initialized) { + throw new KeyStoreException("Uninitialized keystore"); + } + return keyStoreSpi.engineGetAttributes(Objects.requireNonNull(alias)); + } + /** * Returns the key associated with the given alias, using the given * password to recover it. The key must have been associated with @@ -1384,7 +1412,9 @@ public class KeyStore { * integrity with the given password. * * @param stream the output stream to which this keystore is written. - * @param password the password to generate the keystore integrity check + * @param password the password to generate the keystore integrity check. + * May be {@code null} if the keystore does not support + * or require an integrity check. * * @throws KeyStoreException if the keystore has not been initialized * (loaded). diff --git a/src/java.base/share/classes/java/security/KeyStoreSpi.java b/src/java.base/share/classes/java/security/KeyStoreSpi.java index 7db1f52042e890f6fe757f62a861f851d139a57b..7702c0c93b5a7d109dabc763f73a02a2ddb77000 100644 --- a/src/java.base/share/classes/java/security/KeyStoreSpi.java +++ b/src/java.base/share/classes/java/security/KeyStoreSpi.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -289,7 +289,9 @@ public abstract class KeyStoreSpi { * integrity with the given password. * * @param stream the output stream to which this keystore is written. - * @param password the password to generate the keystore integrity check + * @param password the password to generate the keystore integrity check. + * May be {@code null} if the keystore does not support + * or require an integrity check. * * @throws IOException if there was an I/O problem with data * @throws NoSuchAlgorithmException if the appropriate data integrity @@ -445,6 +447,30 @@ public abstract class KeyStoreSpi { return; } + /** + * Retrieves the attributes associated with the given alias. + * + * @implSpec + * The default implementation returns an empty {@code Set}. + * {@code KeyStoreSpi} implementations that support attributes + * should override this method. + * + * @param alias the alias name + * @return an unmodifiable {@code Set} of attributes. This set is + * empty if the given alias does not exist or there are no + * attributes associated with the alias. This set may also be + * empty for {@code PrivateKeyEntry} or {@code SecretKeyEntry} + * entries that contain protected attributes. These protected + * attributes should be populated into the result returned by + * {@link #engineGetEntry} and can be retrieved by calling + * the {@link Entry#getAttributes} method. + * + * @since 18 + */ + public Set engineGetAttributes(String alias) { + return Collections.emptySet(); + } + /** * Gets a {@code KeyStore.Entry} for the specified alias * with the specified protection parameter. diff --git a/src/java.base/share/classes/java/security/Provider.java b/src/java.base/share/classes/java/security/Provider.java index 11c8eb29ca70ebcd85dbe7e4047d0a1f19eeb5c4..4a458cae7f8f29341c7ca9a9ba264eecd7ca4863 100644 --- a/src/java.base/share/classes/java/security/Provider.java +++ b/src/java.base/share/classes/java/security/Provider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 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 @@ -191,6 +191,8 @@ public abstract class Provider extends Properties { this.versionStr = Double.toString(version); this.info = info; this.serviceMap = new ConcurrentHashMap<>(); + this.legacyMap = new ConcurrentHashMap<>(); + this.prngAlgos = new LinkedHashSet(6); putId(); initialized = true; } @@ -229,6 +231,8 @@ public abstract class Provider extends Properties { this.version = parseVersionStr(versionStr); this.info = info; this.serviceMap = new ConcurrentHashMap<>(); + this.legacyMap = new ConcurrentHashMap<>(); + this.prngAlgos = new LinkedHashSet(6); putId(); initialized = true; } @@ -572,7 +576,6 @@ public abstract class Provider extends Properties { public synchronized boolean replace(Object key, Object oldValue, Object newValue) { check("putProviderProperty." + name); - if (debug != null) { debug.println("Replace " + name + " provider property " + key); } @@ -598,7 +601,6 @@ public abstract class Provider extends Properties { @Override public synchronized Object replace(Object key, Object value) { check("putProviderProperty." + name); - if (debug != null) { debug.println("Replace " + name + " provider property " + key); } @@ -627,7 +629,6 @@ public abstract class Provider extends Properties { public synchronized void replaceAll(BiFunction function) { check("putProviderProperty." + name); - if (debug != null) { debug.println("ReplaceAll " + name + " provider property "); } @@ -657,7 +658,6 @@ public abstract class Provider extends Properties { ? super Object, ? extends Object> remappingFunction) { check("putProviderProperty." + name); check("removeProviderProperty." + name); - if (debug != null) { debug.println("Compute " + name + " provider property " + key); } @@ -684,11 +684,10 @@ public abstract class Provider extends Properties { * @since 1.8 */ @Override - public synchronized Object computeIfAbsent(Object key, Function mappingFunction) { + public synchronized Object computeIfAbsent(Object key, + Function mappingFunction) { check("putProviderProperty." + name); check("removeProviderProperty." + name); - if (debug != null) { debug.println("ComputeIfAbsent " + name + " provider property " + key); @@ -714,11 +713,11 @@ public abstract class Provider extends Properties { * @since 1.8 */ @Override - public synchronized Object computeIfPresent(Object key, BiFunction remappingFunction) { + public synchronized Object computeIfPresent(Object key, + BiFunction + remappingFunction) { check("putProviderProperty." + name); check("removeProviderProperty." + name); - if (debug != null) { debug.println("ComputeIfPresent " + name + " provider property " + key); @@ -747,11 +746,11 @@ public abstract class Provider extends Properties { * @since 1.8 */ @Override - public synchronized Object merge(Object key, Object value, BiFunction remappingFunction) { + public synchronized Object merge(Object key, Object value, + BiFunction + remappingFunction) { check("putProviderProperty." + name); check("removeProviderProperty." + name); - if (debug != null) { debug.println("Merge " + name + " provider property " + key); } @@ -777,7 +776,8 @@ public abstract class Provider extends Properties { * @since 1.8 */ @Override - public synchronized void forEach(BiConsumer action) { + public synchronized void forEach(BiConsumer + action) { checkInitialized(); super.forEach(action); } @@ -817,14 +817,11 @@ public abstract class Provider extends Properties { } } - // legacy properties changed since last call to any services method? - private transient boolean legacyChanged; + // legacyMap changed since last call to getServices() + private transient volatile boolean legacyChanged; // serviceMap changed since last call to getServices() private transient volatile boolean servicesChanged; - // Map used to keep track of legacy registration - private transient Map legacyStrings; - // Map // used for services added via putService(), initialized on demand private transient Map serviceMap; @@ -832,6 +829,9 @@ public abstract class Provider extends Properties { // For backward compatibility, the registration ordering of // SecureRandom (RNG) algorithms needs to be preserved for // "new SecureRandom()" calls when this provider is used + // NOTE: may need extra mechanism for providers to indicate their + // preferred ordering of SecureRandom algorithms since registration + // ordering info is lost once serialized private transient Set prngAlgos; // Map @@ -840,7 +840,7 @@ public abstract class Provider extends Properties { // Set // Unmodifiable set of all services. Initialized on demand. - private transient Set serviceSet; + private transient volatile Set serviceSet; // register the id attributes for this provider // this is to ensure that equals() and hashCode() do not incorrectly @@ -872,6 +872,7 @@ public abstract class Provider extends Properties { for (Map.Entry entry : super.entrySet()) { copy.put(entry.getKey(), entry.getValue()); } + defaults = null; in.defaultReadObject(); if (this.versionStr == null) { @@ -882,23 +883,22 @@ public abstract class Provider extends Properties { this.version = parseVersionStr(this.versionStr); } this.serviceMap = new ConcurrentHashMap<>(); + this.legacyMap = new ConcurrentHashMap<>(); + this.prngAlgos = new LinkedHashSet(6); implClear(); initialized = true; putAll(copy); } - // check whether to update 'legacyString' with the specified key - private boolean checkLegacy(Object key) { - String keyString = (String)key; - if (keyString.startsWith("Provider.")) { + // returns false if no update necessary, i.e. key isn't String or + // is String but it's provider-related (name/version/info/className) + private static boolean checkLegacy(Object key) { + if (key instanceof String && ((String)key).startsWith("Provider.")) { + // ignore provider related updates return false; + } else { + return true; } - - legacyChanged = true; - if (legacyStrings == null) { - legacyStrings = new LinkedHashMap<>(); - } - return true; } /** @@ -913,149 +913,161 @@ public abstract class Provider extends Properties { } private Object implRemove(Object key) { - if (key instanceof String) { - if (!checkLegacy(key)) { - return null; - } - legacyStrings.remove((String)key); + if (!checkLegacy(key)) return null; + + Object o = super.remove(key); + if (o instanceof String so && key instanceof String sk) { + parseLegacy(sk, so, OPType.REMOVE); } - return super.remove(key); + return o; } private boolean implRemove(Object key, Object value) { - if (key instanceof String && value instanceof String) { - if (!checkLegacy(key)) { - return false; - } - legacyStrings.remove((String)key, (String)value); + if (!checkLegacy(key)) return false; + + boolean result = super.remove(key, value); + if (result && key instanceof String sk && value instanceof String sv) { + parseLegacy(sk, sv, OPType.REMOVE); } - return super.remove(key, value); + return result; } private boolean implReplace(Object key, Object oldValue, Object newValue) { - if ((key instanceof String) && (oldValue instanceof String) && - (newValue instanceof String)) { - if (!checkLegacy(key)) { - return false; + if (!checkLegacy(key)) return false; + + boolean result = super.replace(key, oldValue, newValue); + if (result && key instanceof String sk) { + if (newValue instanceof String sv) { + parseLegacy(sk, sv, OPType.ADD); + } else if (oldValue instanceof String sv) { + parseLegacy(sk, sv, OPType.REMOVE); } - legacyStrings.replace((String)key, (String)oldValue, - (String)newValue); } - return super.replace(key, oldValue, newValue); + return result; } private Object implReplace(Object key, Object value) { - if ((key instanceof String) && (value instanceof String)) { - if (!checkLegacy(key)) { - return null; + if (!checkLegacy(key)) return null; + + Object o = super.replace(key, value); + if (key instanceof String sk) { + if (o instanceof String so) { + if (value instanceof String sv) { + parseLegacy(sk, sv, OPType.ADD); + } else { + parseLegacy(sk, so, OPType.REMOVE); + } } - legacyStrings.replace((String)key, (String)value); } - return super.replace(key, value); + return o; } @SuppressWarnings("unchecked") // Function must actually operate over strings private void implReplaceAll(BiFunction function) { + + super.replaceAll(function); + // clear out all existing mappings and start fresh + legacyMap.clear(); legacyChanged = true; - if (legacyStrings == null) { - legacyStrings = new LinkedHashMap<>(); - } else { - legacyStrings.replaceAll((BiFunction) function); + for (Map.Entry entry : super.entrySet()) { + Object key = entry.getKey(); + Object value = entry.getValue(); + if ((key instanceof String sk) && (value instanceof String sv)) { + if (!checkLegacy(sk)) { + continue; + } + parseLegacy(sk, sv, OPType.ADD); + } } - super.replaceAll(function); } @SuppressWarnings("unchecked") // Function must actually operate over strings private Object implMerge(Object key, Object value, BiFunction remappingFunction) { - if ((key instanceof String) && (value instanceof String)) { - if (!checkLegacy(key)) { - return null; + if (!checkLegacy(key)) return null; + + Object o = super.merge(key, value, remappingFunction); + if (key instanceof String sk) { + if (o == null) { + parseLegacy(sk, null, OPType.REMOVE); + } else if (o instanceof String so) { + parseLegacy(sk, so, OPType.ADD); } - legacyStrings.merge((String)key, (String)value, - (BiFunction) remappingFunction); } - return super.merge(key, value, remappingFunction); + return o; } @SuppressWarnings("unchecked") // Function must actually operate over strings private Object implCompute(Object key, BiFunction remappingFunction) { - if (key instanceof String) { - if (!checkLegacy(key)) { - return null; + + if (!checkLegacy(key)) return null; + + Object o = super.compute(key, remappingFunction); + if (key instanceof String sk) { + if (o == null) { + parseLegacy(sk, null, OPType.REMOVE); + } else if (o instanceof String so) { + parseLegacy(sk, so, OPType.ADD); } - legacyStrings.compute((String) key, - (BiFunction) remappingFunction); } - return super.compute(key, remappingFunction); + return o; } @SuppressWarnings("unchecked") // Function must actually operate over strings private Object implComputeIfAbsent(Object key, Function mappingFunction) { - if (key instanceof String) { - if (!checkLegacy(key)) { - return null; - } - legacyStrings.computeIfAbsent((String) key, - (Function) - mappingFunction); + if (!checkLegacy(key)) return null; + + Object o = super.computeIfAbsent(key, mappingFunction); + if (o instanceof String so && key instanceof String sk) { + parseLegacy(sk, so, OPType.ADD); } - return super.computeIfAbsent(key, mappingFunction); + return o; } @SuppressWarnings("unchecked") // Function must actually operate over strings private Object implComputeIfPresent(Object key, BiFunction remappingFunction) { - if (key instanceof String) { - if (!checkLegacy(key)) { - return null; - } - legacyStrings.computeIfPresent((String) key, - (BiFunction) remappingFunction); + if (!checkLegacy(key)) return null; + + Object o = super.computeIfPresent(key, remappingFunction); + if (o instanceof String so && key instanceof String sk) { + parseLegacy(sk, so, OPType.ADD); } - return super.computeIfPresent(key, remappingFunction); + return o; } private Object implPut(Object key, Object value) { - if ((key instanceof String) && (value instanceof String)) { - if (!checkLegacy(key)) { - return null; - } - legacyStrings.put((String)key, (String)value); + if (!checkLegacy(key)) return null; + + Object o = super.put(key, value); + if (key instanceof String sk && value instanceof String sv) { + parseLegacy(sk, sv, OPType.ADD); } - return super.put(key, value); + return o; } private Object implPutIfAbsent(Object key, Object value) { - if ((key instanceof String) && (value instanceof String)) { - if (!checkLegacy(key)) { - return null; - } - legacyStrings.putIfAbsent((String)key, (String)value); + if (!checkLegacy(key)) return null; + + Object o = super.putIfAbsent(key, value); + if (o == null && key instanceof String sk && + value instanceof String sv) { + parseLegacy(sk, sv, OPType.ADD); } - return super.putIfAbsent(key, value); + return o; } private void implClear() { - if (legacyStrings != null) { - legacyStrings.clear(); - } - if (legacyMap != null) { - legacyMap.clear(); - } + legacyMap.clear(); serviceMap.clear(); legacyChanged = false; servicesChanged = false; serviceSet = null; - prngAlgos = null; + prngAlgos.clear(); super.clear(); putId(); } @@ -1085,40 +1097,8 @@ public abstract class Provider extends Properties { boolean matches(String type, String algorithm) { return (this.type == type) && (this.originalAlgorithm == algorithm); } - } - - /** - * Ensure all the legacy String properties are fully parsed into - * service objects. - */ - private void ensureLegacyParsed() { - if (legacyChanged == false || (legacyStrings == null)) { - return; - } - serviceSet = null; - if (legacyMap == null) { - legacyMap = new ConcurrentHashMap<>(); - } else { - legacyMap.clear(); - } - for (Map.Entry entry : legacyStrings.entrySet()) { - parseLegacyPut(entry.getKey(), entry.getValue()); - } - removeInvalidServices(legacyMap); - legacyChanged = false; - } - - /** - * Remove all invalid services from the Map. Invalid services can only - * occur if the legacy properties are inconsistent or incomplete. - */ - private void removeInvalidServices(Map map) { - for (Iterator> t = - map.entrySet().iterator(); t.hasNext(); ) { - Service s = t.next().getValue(); - if (s.isValid() == false) { - t.remove(); - } + public String toString() { + return type + "." + algorithm; } } @@ -1140,67 +1120,127 @@ public abstract class Provider extends Properties { private static final String ALIAS_PREFIX_LOWER = "alg.alias."; private static final int ALIAS_LENGTH = ALIAS_PREFIX.length(); - private void parseLegacyPut(String name, String value) { + private static enum OPType { + ADD, REMOVE; + } + + private void parseLegacy(String name, String value, OPType opType) { + // alias if (name.toLowerCase(ENGLISH).startsWith(ALIAS_PREFIX_LOWER)) { // e.g. put("Alg.Alias.MessageDigest.SHA", "SHA-1"); // aliasKey ~ MessageDigest.SHA - String stdAlg = value; - String aliasKey = name.substring(ALIAS_LENGTH); - String[] typeAndAlg = getTypeAndAlgorithm(aliasKey); + String aliasKeyStr = name.substring(ALIAS_LENGTH); + String[] typeAndAlg = getTypeAndAlgorithm(aliasKeyStr); if (typeAndAlg == null) { return; } + legacyChanged = true; + Objects.requireNonNull(value, "alias value should map to an alg"); String type = getEngineName(typeAndAlg[0]); String aliasAlg = typeAndAlg[1].intern(); - ServiceKey key = new ServiceKey(type, stdAlg, true); - Service s = legacyMap.get(key); - if (s == null) { - s = new Service(this, type, stdAlg); - legacyMap.put(key, s); + ServiceKey stdKey = new ServiceKey(type, value, true); + Service stdService = legacyMap.get(stdKey); + ServiceKey aliasKey = new ServiceKey(type, aliasAlg, true); + switch (opType) { + case ADD: + // clean up old alias if present + Service prevAliasService = legacyMap.get(aliasKey); + if (prevAliasService != null) { + prevAliasService.removeAlias(aliasAlg); + } + if (stdService == null) { + // add standard mapping in order to add alias + stdService = new Service(this, type, value); + legacyMap.put(stdKey, stdService); + } + stdService.addAlias(aliasAlg); + legacyMap.put(aliasKey, stdService); + break; + case REMOVE: + if (stdService != null) { + stdService.removeAlias(aliasAlg); + } + legacyMap.remove(aliasKey); + break; + default: + throw new AssertionError(); } - legacyMap.put(new ServiceKey(type, aliasAlg, true), s); - s.addAlias(aliasAlg); } else { String[] typeAndAlg = getTypeAndAlgorithm(name); if (typeAndAlg == null) { return; } + legacyChanged = true; int i = typeAndAlg[1].indexOf(' '); + // regular registration if (i == -1) { // e.g. put("MessageDigest.SHA-1", "sun.security.provider.SHA"); String type = getEngineName(typeAndAlg[0]); String stdAlg = typeAndAlg[1].intern(); - String className = value; - ServiceKey key = new ServiceKey(type, stdAlg, true); - Service s = legacyMap.get(key); - if (s == null) { - s = new Service(this, type, stdAlg); - legacyMap.put(key, s); - } - s.className = className; - - if (type.equals("SecureRandom")) { - updateSecureRandomEntries(true, s.algorithm); + ServiceKey stdKey = new ServiceKey(type, stdAlg, true); + Service stdService = legacyMap.get(stdKey); + switch (opType) { + case ADD: + Objects.requireNonNull(value, + "className can't be null"); + if (stdService == null) { + stdService = new Service(this, type, stdAlg); + legacyMap.put(stdKey, stdService); + } + stdService.className = value; + break; + case REMOVE: + // only remove if value also matches when non-null + if (stdService != null) { + if (value == null) { + legacyMap.remove(stdKey); + } else if (stdService.className.equals(value)) { + legacyMap.remove(stdKey, stdService); + } + // remove all corresponding alias mappings + for (String alias : stdService.getAliases()) { + legacyMap.remove(new ServiceKey(type, alias, + true), stdService); + } + } + break; + default: + throw new AssertionError(); } + checkAndUpdateSecureRandom(type, stdAlg, + (opType != OPType.REMOVE)); } else { // attribute // e.g. put("MessageDigest.SHA-1 ImplementedIn", "Software"); - String attributeValue = value; String type = getEngineName(typeAndAlg[0]); - String attributeString = typeAndAlg[1]; - String stdAlg = attributeString.substring(0, i).intern(); - String attributeName = attributeString.substring(i + 1); + String attrString = typeAndAlg[1]; + String stdAlg = attrString.substring(0, i).intern(); + String attrName = attrString.substring(i + 1); // kill additional spaces - while (attributeName.startsWith(" ")) { - attributeName = attributeName.substring(1); + while (attrName.startsWith(" ")) { + attrName = attrName.substring(1); } - attributeName = attributeName.intern(); - ServiceKey key = new ServiceKey(type, stdAlg, true); - Service s = legacyMap.get(key); - if (s == null) { - s = new Service(this, type, stdAlg); - legacyMap.put(key, s); + attrName = attrName.intern(); + ServiceKey stdKey = new ServiceKey(type, stdAlg, true); + Service stdService = legacyMap.get(stdKey); + switch (opType) { + case ADD: + Objects.requireNonNull(value, + "attribute value should not be null"); + + if (stdService == null) { + stdService = new Service(this, type, stdAlg); + legacyMap.put(stdKey, stdService); + } + stdService.addAttribute(attrName, value); + break; + case REMOVE: + if (stdService != null) { + stdService.removeAttribute(attrName, value); + } + break; + default: + throw new AssertionError(); } - s.addAttribute(attributeName, attributeValue); } } } @@ -1227,25 +1267,25 @@ public abstract class Provider extends Properties { */ public Service getService(String type, String algorithm) { checkInitialized(); - // avoid allocating a new ServiceKey object if possible ServiceKey key = previousKey; if (key.matches(type, algorithm) == false) { key = new ServiceKey(type, algorithm, false); previousKey = key; } - if (!serviceMap.isEmpty()) { - Service s = serviceMap.get(key); - if (s != null) { - return s; - } + + Service s = serviceMap.get(key); + if (s != null) { + return s; } - synchronized (this) { - ensureLegacyParsed(); - if (legacyMap != null && !legacyMap.isEmpty()) { - return legacyMap.get(key); - } + + s = legacyMap.get(key); + if (s != null && !s.isValid()) { + legacyMap.remove(key, s); + } else { + return s; } + return null; } @@ -1267,22 +1307,19 @@ public abstract class Provider extends Properties { * * @since 1.5 */ - public synchronized Set getServices() { + public Set getServices() { checkInitialized(); - if (legacyChanged || servicesChanged) { - serviceSet = null; - } - if (serviceSet == null) { - ensureLegacyParsed(); + if (serviceSet == null || legacyChanged || servicesChanged) { Set set = new LinkedHashSet<>(); if (!serviceMap.isEmpty()) { set.addAll(serviceMap.values()); } - if (legacyMap != null && !legacyMap.isEmpty()) { + if (!legacyMap.isEmpty()) { set.addAll(legacyMap.values()); } serviceSet = Collections.unmodifiableSet(set); servicesChanged = false; + legacyChanged = false; } return serviceSet; } @@ -1339,44 +1376,36 @@ public abstract class Provider extends Properties { servicesChanged = true; synchronized (this) { putPropertyStrings(s); - if (type.equals("SecureRandom")) { - updateSecureRandomEntries(true, s.algorithm); - } + checkAndUpdateSecureRandom(type, algorithm, true); } } - // keep tracks of the registered secure random algos and store them in order - private void updateSecureRandomEntries(boolean doAdd, String s) { - Objects.requireNonNull(s); - if (doAdd) { - if (prngAlgos == null) { - prngAlgos = new LinkedHashSet(); + private void checkAndUpdateSecureRandom(String type, String algo, + boolean doAdd) { + if (type.equalsIgnoreCase("SecureRandom")) { + if (doAdd) { + prngAlgos.add(algo); + } else { + prngAlgos.remove(algo); + } + if (debug != null) { + debug.println((doAdd? "Add":"Remove") + + " SecureRandom algo " + algo); } - prngAlgos.add(s); - } else { - prngAlgos.remove(s); - } - - if (debug != null) { - debug.println((doAdd? "Add":"Remove") + " SecureRandom algo " + s); } } // used by new SecureRandom() to find out the default SecureRandom // service for this provider - synchronized Service getDefaultSecureRandomService() { + Service getDefaultSecureRandomService() { checkInitialized(); - if (legacyChanged) { - prngAlgos = null; - ensureLegacyParsed(); - } - - if (prngAlgos != null && !prngAlgos.isEmpty()) { + if (!prngAlgos.isEmpty()) { + String algo = prngAlgos.iterator().next(); // IMPORTANT: use the Service obj returned by getService(...) call // as providers may override putService(...)/getService(...) and // return their own Service objects - return getService("SecureRandom", prngAlgos.iterator().next()); + return getService("SecureRandom", algo); } return null; @@ -1473,12 +1502,9 @@ public abstract class Provider extends Properties { for (String alias : s.getAliases()) { serviceMap.remove(new ServiceKey(type, alias, false)); } - synchronized (this) { - removePropertyStrings(s); - if (type.equals("SecureRandom")) { - updateSecureRandomEntries(false, s.algorithm); - } - } + + removePropertyStrings(s); + checkAndUpdateSecureRandom(type, algorithm, false); } // Wrapped String that behaves in a case insensitive way for equals/hashCode @@ -1513,21 +1539,12 @@ public abstract class Provider extends Properties { final String name; final boolean supportsParameter; final String constructorParameterClassName; - private volatile Class constructorParameterClass; EngineDescription(String name, boolean sp, String paramName) { this.name = name; this.supportsParameter = sp; this.constructorParameterClassName = paramName; } - Class getConstructorParameterClass() throws ClassNotFoundException { - Class clazz = constructorParameterClass; - if (clazz == null) { - clazz = Class.forName(constructorParameterClassName); - constructorParameterClass = clazz; - } - return clazz; - } } // built in knowledge of the engine types shipped as part of the JDK @@ -1686,6 +1703,13 @@ public abstract class Provider extends Properties { aliases.add(alias); } + private void removeAlias(String alias) { + if (aliases.isEmpty()) { + return; + } + aliases.remove(alias); + } + void addAttribute(String type, String value) { if (attributes.isEmpty()) { attributes = new HashMap<>(8); @@ -1693,6 +1717,17 @@ public abstract class Provider extends Properties { attributes.put(new UString(type), value); } + void removeAttribute(String type, String value) { + if (attributes.isEmpty()) { + return; + } + if (value == null) { + attributes.remove(new UString(type)); + } else { + attributes.remove(new UString(type), value); + } + } + /** * Construct a new service. * diff --git a/src/java.base/share/classes/java/security/Security.java b/src/java.base/share/classes/java/security/Security.java index 2ee706c2448ed6b72070b980b336b39a5cbc3b65..352dc5e7fac242fae09b8c1f1c531d32dcba8655 100644 --- a/src/java.base/share/classes/java/security/Security.java +++ b/src/java.base/share/classes/java/security/Security.java @@ -91,8 +91,7 @@ public final class Security { if (propFile.exists()) { InputStream is = null; try { - FileInputStream fis = new FileInputStream(propFile); - is = new BufferedInputStream(fis); + is = new FileInputStream(propFile); props.load(is); loadedProps = true; @@ -140,7 +139,7 @@ public final class Security { // now load the user-specified file so its values // will win if they conflict with the earlier values if (extraPropFile != null) { - BufferedInputStream bis = null; + InputStream is = null; try { URL propURL; @@ -152,8 +151,8 @@ public final class Security { } else { propURL = new URL(extraPropFile); } - bis = new BufferedInputStream(propURL.openStream()); - props.load(bis); + is = propURL.openStream(); + props.load(is); loadedProps = true; if (sdebug != null) { @@ -172,9 +171,9 @@ public final class Security { e.printStackTrace(); } } finally { - if (bis != null) { + if (is != null) { try { - bis.close(); + is.close(); } catch (IOException ioe) { if (sdebug != null) { sdebug.println("unable to close input stream"); diff --git a/src/java.base/share/classes/java/security/cert/CertPath.java b/src/java.base/share/classes/java/security/cert/CertPath.java index 28000591c00f0f861952c99341fca86ddfb08370..15f49ac3381751a3382c3052bcbda3a357d875a3 100644 --- a/src/java.base/share/classes/java/security/cert/CertPath.java +++ b/src/java.base/share/classes/java/security/cert/CertPath.java @@ -123,7 +123,7 @@ public abstract class CertPath implements Serializable { private static final long serialVersionUID = 6068470306649138683L; /** The type of certificates in this chain. */ - private String type; + private final transient String type; /** * Creates a {@code CertPath} of the specified type. @@ -270,9 +270,11 @@ public abstract class CertPath implements Serializable { /** * Replaces the {@code CertPath} to be serialized with a - * {@code CertPathRep} object. + * {@link CertPathRep CertPathRep} object containing the + * {@code Certificate} type and encoded bytes of the {@code CertPath}. * - * @return the {@code CertPathRep} to be serialized + * @return a {@code CertPathRep} containing the {@code Certificate} type + * and encoded bytes of the {@code CertPath} * * @throws ObjectStreamException if a {@code CertPathRep} object * representing this certification path could not be created @@ -299,16 +301,16 @@ public abstract class CertPath implements Serializable { @java.io.Serial private static final long serialVersionUID = 3015633072427920915L; - /** The Certificate type */ + /** The type of {@code Certificate}s in the {@code CertPath}. */ private String type; - /** The encoded form of the cert path */ + /** The encoded form of the {@code CertPath}. */ private byte[] data; /** * Creates a {@code CertPathRep} with the specified * type and encoded form of a certification path. * - * @param type the standard name of a {@code CertPath} type + * @param type the standard name of a {@code Certificate} type * @param data the encoded form of the certification path */ protected CertPathRep(String type, byte[] data) { @@ -317,11 +319,12 @@ public abstract class CertPath implements Serializable { } /** - * Returns a {@code CertPath} constructed from the type and data. + * Returns a {@code CertPath} constructed from the type and data of + * this {@code CertPathRep}. * * @return the resolved {@code CertPath} object * - * @throws ObjectStreamException if a {@code CertPath} could not + * @throws ObjectStreamException if a {@code CertPath} object could not * be constructed */ @java.io.Serial diff --git a/src/java.base/share/classes/java/security/cert/Certificate.java b/src/java.base/share/classes/java/security/cert/Certificate.java index a34f0316a8c468b66349ec3223388adcc4630006..4a020ddf1cbe8fc3d9e603090c3dd89f3f5f1f37 100644 --- a/src/java.base/share/classes/java/security/cert/Certificate.java +++ b/src/java.base/share/classes/java/security/cert/Certificate.java @@ -66,10 +66,10 @@ public abstract class Certificate implements java.io.Serializable { private static final long serialVersionUID = -3585440601605666277L; /** The certificate type. */ - private final String type; + private final transient String type; /** The hash code for the certificate. */ - private int hash = -1; // Default to -1 + private transient int hash = -1; // Default to -1 /** * Creates a certificate of the specified type. @@ -236,7 +236,7 @@ public abstract class Certificate implements java.io.Serializable { public abstract PublicKey getPublicKey(); /** - * Alternate Certificate class for serialization. + * Alternate {@code Certificate} class for serialization. * @since 1.3 */ protected static class CertificateRep implements java.io.Serializable { @@ -251,12 +251,12 @@ public abstract class Certificate implements java.io.Serializable { private byte[] data; /** - * Construct the alternate Certificate class with the Certificate - * type and Certificate encoding bytes. + * Construct the alternate {@code Certificate} class with the + * {@code Certificate} type and {@code Certificate} encoding bytes. * - * @param type the standard name of the Certificate type. + * @param type the standard name of the {@code Certificate} type. * - * @param data the Certificate data. + * @param data the {@code Certificate} data. */ protected CertificateRep(String type, byte[] data) { this.type = type; @@ -264,11 +264,12 @@ public abstract class Certificate implements java.io.Serializable { } /** - * Resolve the Certificate Object. + * Returns a {@code Certificate} with the type and data of this + * {@code CertificateRep}. * - * @return the resolved Certificate Object + * @return the resolved {@code Certificate} object * - * @throws java.io.ObjectStreamException if the Certificate + * @throws java.io.ObjectStreamException if the {@code Certificate} * could not be resolved */ @java.io.Serial @@ -288,12 +289,15 @@ public abstract class Certificate implements java.io.Serializable { } /** - * Replace the Certificate to be serialized. + * Replace the {@code Certificate} to be serialized with a + * {@link CertificateRep CertificateRep} object containing the type and + * encoded bytes of the {@code Certificate}. * - * @return the alternate Certificate object to be serialized + * @return a {@code CertificateRep} object containing the type and encoded + * bytes of the {@code Certificate} * - * @throws java.io.ObjectStreamException if a new object representing - * this Certificate could not be created + * @throws java.io.ObjectStreamException if a {@code CertificateRep} object + * representing this {@code Certificate} could not be created * @since 1.3 */ @java.io.Serial diff --git a/src/java.base/share/classes/java/security/cert/PKIXCertPathBuilderResult.java b/src/java.base/share/classes/java/security/cert/PKIXCertPathBuilderResult.java index 01cedffe9c86bec98e103554e89518a4802b3a51..4812e380bb33784b5d5d69ea722d6505094b0d9e 100644 --- a/src/java.base/share/classes/java/security/cert/PKIXCertPathBuilderResult.java +++ b/src/java.base/share/classes/java/security/cert/PKIXCertPathBuilderResult.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -110,8 +110,8 @@ public class PKIXCertPathBuilderResult extends PKIXCertPathValidatorResult StringBuilder sb = new StringBuilder(); sb.append("PKIXCertPathBuilderResult: [\n"); sb.append(" Certification Path: " + certPath + "\n"); - sb.append(" Trust Anchor: " + getTrustAnchor().toString() + "\n"); - sb.append(" Policy Tree: " + String.valueOf(getPolicyTree()) + "\n"); + sb.append(" Trust Anchor: " + getTrustAnchor() + "\n"); + sb.append(" Policy Tree: " + getPolicyTree() + "\n"); sb.append(" Subject Public Key: " + getPublicKey() + "\n"); sb.append("]"); return sb.toString(); diff --git a/src/java.base/share/classes/java/security/cert/PKIXCertPathValidatorResult.java b/src/java.base/share/classes/java/security/cert/PKIXCertPathValidatorResult.java index 3ba1e335a5495be02b353008ad8d0aa08a4c0f16..5552078ff5cb5f73f49129367312d8fcbf163c24 100644 --- a/src/java.base/share/classes/java/security/cert/PKIXCertPathValidatorResult.java +++ b/src/java.base/share/classes/java/security/cert/PKIXCertPathValidatorResult.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -150,8 +150,8 @@ public class PKIXCertPathValidatorResult implements CertPathValidatorResult { public String toString() { StringBuilder sb = new StringBuilder(); sb.append("PKIXCertPathValidatorResult: [\n"); - sb.append(" Trust Anchor: " + trustAnchor.toString() + "\n"); - sb.append(" Policy Tree: " + String.valueOf(policyTree) + "\n"); + sb.append(" Trust Anchor: " + trustAnchor + "\n"); + sb.append(" Policy Tree: " + policyTree + "\n"); sb.append(" Subject Public Key: " + subjectPublicKey + "\n"); sb.append("]"); return sb.toString(); diff --git a/src/java.base/share/classes/java/security/cert/PKIXParameters.java b/src/java.base/share/classes/java/security/cert/PKIXParameters.java index d29269e9c42bb31f41941b56f8aa0494d4e9e00f..88e77f0b6cfa936b7b25f13f06d3a8be67b44374 100644 --- a/src/java.base/share/classes/java/security/cert/PKIXParameters.java +++ b/src/java.base/share/classes/java/security/cert/PKIXParameters.java @@ -696,8 +696,7 @@ public class PKIXParameters implements CertPathParameters { /* start with trusted anchor info */ if (unmodTrustAnchors != null) { - sb.append(" Trust Anchors: " + unmodTrustAnchors.toString() - + "\n"); + sb.append(" Trust Anchors: " + unmodTrustAnchors + "\n"); } /* now, append initial state information */ @@ -706,13 +705,13 @@ public class PKIXParameters implements CertPathParameters { sb.append(" Initial Policy OIDs: any\n"); } else { sb.append(" Initial Policy OIDs: [" - + unmodInitialPolicies.toString() + "]\n"); + + unmodInitialPolicies + "]\n"); } } /* now, append constraints on all certificates in the path */ - sb.append(" Validity Date: " + String.valueOf(date) + "\n"); - sb.append(" Signature Provider: " + String.valueOf(sigProvider) + "\n"); + sb.append(" Validity Date: " + date + "\n"); + sb.append(" Signature Provider: " + sigProvider + "\n"); sb.append(" Default Revocation Enabled: " + revocationEnabled + "\n"); sb.append(" Explicit Policy Required: " + explicitPolicyRequired + "\n"); sb.append(" Policy Mapping Inhibited: " + policyMappingInhibited + "\n"); @@ -720,14 +719,14 @@ public class PKIXParameters implements CertPathParameters { sb.append(" Policy Qualifiers Rejected: " + policyQualifiersRejected + "\n"); /* now, append target cert requirements */ - sb.append(" Target Cert Constraints: " + String.valueOf(certSelector) + "\n"); + sb.append(" Target Cert Constraints: " + certSelector + "\n"); /* finally, append miscellaneous parameters */ if (certPathCheckers != null) sb.append(" Certification Path Checkers: [" - + certPathCheckers.toString() + "]\n"); + + certPathCheckers + "]\n"); if (certStores != null) - sb.append(" CertStores: [" + certStores.toString() + "]\n"); + sb.append(" CertStores: [" + certStores + "]\n"); sb.append("]"); return sb.toString(); } 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 f026bea41790b726be764ceb703003e3e37500cf..ab60b5cbd9ae6828e4805ff6e4a61a7f3d300927 100644 --- a/src/java.base/share/classes/java/security/cert/TrustAnchor.java +++ b/src/java.base/share/classes/java/security/cert/TrustAnchor.java @@ -323,14 +323,13 @@ public class TrustAnchor { StringBuilder sb = new StringBuilder(); sb.append("[\n"); if (pubKey != null) { - sb.append(" Trusted CA Public Key: " + pubKey.toString() + "\n"); - sb.append(" Trusted CA Issuer Name: " - + String.valueOf(caName) + "\n"); + sb.append(" Trusted CA Public Key: " + pubKey + "\n"); + sb.append(" Trusted CA Issuer Name: " + caName + "\n"); } else { - sb.append(" Trusted CA cert: " + trustedCert.toString() + "\n"); + sb.append(" Trusted CA cert: " + trustedCert + "\n"); } if (nc != null) - sb.append(" Name Constraints: " + nc.toString() + "\n"); + sb.append(" Name Constraints: " + nc + "\n"); return sb.toString(); } 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 86c516191a956607ec8048ca12d82d0f4736d1b0..5a25ba5927f1a9f1815b7c0cd9375e56810cf34c 100644 --- a/src/java.base/share/classes/java/security/cert/X509CertSelector.java +++ b/src/java.base/share/classes/java/security/cert/X509CertSelector.java @@ -1763,10 +1763,10 @@ public class X509CertSelector implements CertSelector { StringBuilder sb = new StringBuilder(); sb.append("X509CertSelector: [\n"); if (x509Cert != null) { - sb.append(" Certificate: " + x509Cert.toString() + "\n"); + sb.append(" Certificate: " + x509Cert + "\n"); } if (serialNumber != null) { - sb.append(" Serial Number: " + serialNumber.toString() + "\n"); + sb.append(" Serial Number: " + serialNumber + "\n"); } if (issuer != null) { sb.append(" Issuer: " + getIssuerAsString() + "\n"); @@ -1775,7 +1775,7 @@ public class X509CertSelector implements CertSelector { sb.append(" Subject: " + getSubjectAsString() + "\n"); } sb.append(" matchAllSubjectAltNames flag: " - + String.valueOf(matchAllSubjectAltNames) + "\n"); + + matchAllSubjectAltNames + "\n"); if (subjectAlternativeNames != null) { sb.append(" SubjectAlternativeNames:\n"); for (List list : subjectAlternativeNames) { @@ -1795,29 +1795,29 @@ public class X509CertSelector implements CertSelector { } if (certificateValid != null) { sb.append(" Certificate Valid: " + - certificateValid.toString() + "\n"); + certificateValid + "\n"); } if (privateKeyValid != null) { sb.append(" Private Key Valid: " + - privateKeyValid.toString() + "\n"); + privateKeyValid + "\n"); } if (subjectPublicKeyAlgID != null) { sb.append(" Subject Public Key AlgID: " + - subjectPublicKeyAlgID.toString() + "\n"); + subjectPublicKeyAlgID + "\n"); } if (subjectPublicKey != null) { sb.append(" Subject Public Key: " + - subjectPublicKey.toString() + "\n"); + subjectPublicKey + "\n"); } if (keyUsage != null) { sb.append(" Key Usage: " + keyUsageToString(keyUsage) + "\n"); } if (keyPurposeSet != null) { sb.append(" Extended Key Usage: " + - keyPurposeSet.toString() + "\n"); + keyPurposeSet + "\n"); } if (policy != null) { - sb.append(" Policy: " + policy.toString() + "\n"); + sb.append(" Policy: " + policy + "\n"); } if (pathToGeneralNames != null) { sb.append(" Path to names:\n"); @@ -2145,7 +2145,7 @@ public class X509CertSelector implements CertSelector { debug.println("X509CertSelector.match: private key usage not " + "within validity date; ext.NOT_BEFORE: " + time + "; X509CertSelector: " - + this.toString()); + + this); e2.printStackTrace(); } return false; @@ -2153,7 +2153,7 @@ public class X509CertSelector implements CertSelector { if (debug != null) { debug.println("X509CertSelector.match: IOException in " + "private key usage check; X509CertSelector: " - + this.toString()); + + this); e4.printStackTrace(); } return false; 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 bc0df9b45a17147fc8962d85b6ba8fc4e21e10e3..127f60b41806cdb1a908328fd4aef35be42d815b 100644 --- a/src/java.base/share/classes/java/security/cert/X509Certificate.java +++ b/src/java.base/share/classes/java/security/cert/X509Certificate.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -562,6 +562,10 @@ implements X509Extension { * uniformResourceIdentifier [6] IA5String, * iPAddress [7] OCTET STRING, * registeredID [8] OBJECT IDENTIFIER} + * + * OtherName ::= SEQUENCE { + * type-id OBJECT IDENTIFIER, + * value [0] EXPLICIT ANY DEFINED BY type-id } * *

          * If this certificate does not contain a {@code SubjectAltName} @@ -571,7 +575,7 @@ implements X509Extension { * {@code List} whose first entry is an {@code Integer} * (the name type, 0-8) and whose second entry is a {@code String} * or a byte array (the name, in string or ASN.1 DER encoded form, - * respectively). + * respectively). More entries may exist depending on the name type. *

          * RFC 822, DNS, and URI * names are returned as {@code String}s, @@ -581,12 +585,18 @@ implements X509Extension { * in the form "a1:a2:...:a8", where a1-a8 are hexadecimal values * representing the eight 16-bit pieces of the address. OID names are * returned as {@code String}s represented as a series of nonnegative - * integers separated by periods. And directory names (distinguished names) + * integers separated by periods. Directory names (distinguished names) * are returned in - * RFC 2253 string format. No standard string format is - * defined for otherNames, X.400 names, EDI party names, or any - * other type of names. They are returned as byte arrays - * containing the ASN.1 DER encoded form of the name. + * RFC 2253 string format. No standard string format is defined for + * X.400 names or EDI party names. They are returned as byte arrays + * containing the ASN.1 DER encoded form of the name. otherNames are also + * returned as byte arrays containing the ASN.1 DER encoded form of the + * name. A third entry may also be present in the list containing the + * {@code type-id} of the otherName in string form, and a fourth entry + * containing its {@code value} as either a string (if the value is + * a valid supported character string) or a byte array containing the + * ASN.1 DER encoded form of the value without the context-specific + * constructed tag with number 0. *

          * Note that the {@code Collection} returned may contain more * than one name of the same type. Also, note that the returned @@ -599,6 +609,9 @@ implements X509Extension { * and it provides a default implementation. Subclasses * should override this method with a correct implementation. * + * @implNote The JDK SUN provider supports the third and fourth + * otherName entries. + * * @return an immutable {@code Collection} of subject alternative * names (or {@code null}) * @throws CertificateParsingException if the extension cannot be decoded @@ -627,7 +640,8 @@ implements X509Extension { * {@code List} whose first entry is an {@code Integer} * (the name type, 0-8) and whose second entry is a {@code String} * or a byte array (the name, in string or ASN.1 DER encoded form, - * respectively). For more details about the formats used for each + * respectively). More entries may exist depending on the name type. + * For more details about the formats used for each * name type, see the {@code getSubjectAlternativeNames} method. *

          * Note that the {@code Collection} returned may contain more diff --git a/src/java.base/share/classes/java/text/AttributedCharacterIterator.java b/src/java.base/share/classes/java/text/AttributedCharacterIterator.java index 31b5b7d8d3c64a82dee99978d8c1ba739b87836a..6a2f33630e0181e1c8ef5be8d7a7573d50917021 100644 --- a/src/java.base/share/classes/java/text/AttributedCharacterIterator.java +++ b/src/java.base/share/classes/java/text/AttributedCharacterIterator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -67,15 +67,15 @@ import java.util.Set; * *

          * Attribute keys are instances of {@link AttributedCharacterIterator.Attribute} and its - * subclasses, such as {@link java.awt.font.TextAttribute}. + * subclasses, such as {@link java.desktop/java.awt.font.TextAttribute}. * * @see AttributedCharacterIterator.Attribute - * @see java.awt.font.TextAttribute + * @see java.desktop/java.awt.font.TextAttribute * @see AttributedString * @see Annotation * @since 1.2 */ - +@SuppressWarnings("doclint:reference") // cross-module links public interface AttributedCharacterIterator extends CharacterIterator { /** diff --git a/src/java.base/share/classes/java/text/Bidi.java b/src/java.base/share/classes/java/text/Bidi.java index 00a878e1c6425c129ce52a9b6208681d5092e9e8..2ec7bea6988cf9d2fe8f1ce0c3b5154041959b13 100644 --- a/src/java.base/share/classes/java/text/Bidi.java +++ b/src/java.base/share/classes/java/text/Bidi.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -121,10 +121,11 @@ public final class Bidi { * * @param paragraph a paragraph of text with optional character and paragraph attribute information * - * @see java.awt.font.TextAttribute#BIDI_EMBEDDING - * @see java.awt.font.TextAttribute#NUMERIC_SHAPING - * @see java.awt.font.TextAttribute#RUN_DIRECTION + * @see java.desktop/java.awt.font.TextAttribute#BIDI_EMBEDDING + * @see java.desktop/java.awt.font.TextAttribute#NUMERIC_SHAPING + * @see java.desktop/java.awt.font.TextAttribute#RUN_DIRECTION */ + @SuppressWarnings("doclint:reference") // cross-module links public Bidi(AttributedCharacterIterator paragraph) { if (paragraph == null) { throw new IllegalArgumentException("paragraph is null"); diff --git a/src/java.base/share/classes/java/text/CompactNumberFormat.java b/src/java.base/share/classes/java/text/CompactNumberFormat.java index 0449133d5b8a237bcf0562546cb0e39beafd2c1b..551945cc8326a3f323ba988e2f325916706b6194 100644 --- a/src/java.base/share/classes/java/text/CompactNumberFormat.java +++ b/src/java.base/share/classes/java/text/CompactNumberFormat.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -589,6 +589,10 @@ public final class CompactNumberFormat extends NumberFormat { if (compactDataIndex != -1) { long divisor = (Long) divisors.get(compactDataIndex); int iPart = getIntegerPart(number, divisor); + if (checkIncrement(iPart, compactDataIndex, divisor)) { + divisor = (Long) divisors.get(++compactDataIndex); + iPart = getIntegerPart(number, divisor); + } String prefix = getAffix(false, true, isNegative, compactDataIndex, iPart); String suffix = getAffix(false, false, isNegative, compactDataIndex, iPart); @@ -658,6 +662,10 @@ public final class CompactNumberFormat extends NumberFormat { if (compactDataIndex != -1) { long divisor = (Long) divisors.get(compactDataIndex); int iPart = getIntegerPart(number, divisor); + if (checkIncrement(iPart, compactDataIndex, divisor)) { + divisor = (Long) divisors.get(++compactDataIndex); + iPart = getIntegerPart(number, divisor); + } String prefix = getAffix(false, true, isNegative, compactDataIndex, iPart); String suffix = getAffix(false, false, isNegative, compactDataIndex, iPart); if (!prefix.isEmpty() || !suffix.isEmpty()) { @@ -753,6 +761,10 @@ public final class CompactNumberFormat extends NumberFormat { if (compactDataIndex != -1) { Number divisor = divisors.get(compactDataIndex); int iPart = getIntegerPart(number.doubleValue(), divisor.doubleValue()); + if (checkIncrement(iPart, compactDataIndex, divisor.doubleValue())) { + divisor = divisors.get(++compactDataIndex); + iPart = getIntegerPart(number.doubleValue(), divisor.doubleValue()); + } String prefix = getAffix(false, true, isNegative, compactDataIndex, iPart); String suffix = getAffix(false, false, isNegative, compactDataIndex, iPart); if (!prefix.isEmpty() || !suffix.isEmpty()) { @@ -820,6 +832,10 @@ public final class CompactNumberFormat extends NumberFormat { if (compactDataIndex != -1) { Number divisor = divisors.get(compactDataIndex); int iPart = getIntegerPart(number.doubleValue(), divisor.doubleValue()); + if (checkIncrement(iPart, compactDataIndex, divisor.doubleValue())) { + divisor = divisors.get(++compactDataIndex); + iPart = getIntegerPart(number.doubleValue(), divisor.doubleValue()); + } String prefix = getAffix(false, true, isNegative, compactDataIndex, iPart); String suffix = getAffix(false, false, isNegative, compactDataIndex, iPart); if (!prefix.isEmpty() || !suffix.isEmpty()) { @@ -875,7 +891,7 @@ public final class CompactNumberFormat extends NumberFormat { * Appends the {@code prefix} to the {@code result} and also set the * {@code NumberFormat.Field.SIGN} and {@code NumberFormat.Field.PREFIX} * field positions. - * @param result the resulting string, where the pefix is to be appended + * @param result the resulting string, where the prefix is to be appended * @param prefix prefix to append * @param delegate notified of the locations of * {@code NumberFormat.Field.SIGN} and @@ -910,7 +926,7 @@ public final class CompactNumberFormat extends NumberFormat { * @param result the resulting string, where the text is to be appended * @param string the text to append * @param delegate notified of the locations of sub fields - * @param positions a list of {@code FieldPostion} in the given + * @param positions a list of {@code FieldPosition} in the given * string */ private void append(StringBuffer result, String string, @@ -956,10 +972,10 @@ public final class CompactNumberFormat extends NumberFormat { } /** - * Returns a list of {@code FieldPostion} in the given {@code pattern}. + * Returns a list of {@code FieldPosition} in the given {@code pattern}. * @param pattern the pattern to be parsed for {@code FieldPosition} * @param field whether a PREFIX or SUFFIX field - * @return a list of {@code FieldPostion} + * @return a list of {@code FieldPosition} */ private List getFieldPositions(String pattern, Field field) { List positions = new ArrayList<>(); @@ -1769,7 +1785,7 @@ public final class CompactNumberFormat extends NumberFormat { if (cnfMultiplier.longValue() != 1L) { double doubleResult = number.doubleValue() * cnfMultiplier.doubleValue(); doubleResult = (double) convertIfNegative(doubleResult, status, gotLongMin); - // Check if a double can be represeneted as a long + // Check if a double can be represented as a long long longResult = (long) doubleResult; gotDouble = ((doubleResult != (double) longResult) || (doubleResult == 0.0 && 1 / doubleResult < 0.0)); @@ -2396,6 +2412,19 @@ public final class CompactNumberFormat extends NumberFormat { .divide(BigDecimal.valueOf(divisor), roundingMode).intValue(); } + // Checks whether the iPart is incremented by the BigDecimal division in + // getIntegerPart(), and affects the compact number index. + private boolean checkIncrement(int iPart, int index, double divisor) { + if (index < compactPatterns.length - 1 && + !"".equals(compactPatterns[index])) { // ignore empty pattern + var nextDiv = divisors.get(index + 1).doubleValue(); + if (divisor != nextDiv) { + return Math.log10(iPart) == Math.log10(nextDiv) - Math.log10(divisor); + } + } + return false; + } + /** * Returns LDML's tag from the plurals rules * diff --git a/src/java.base/share/classes/java/text/DecimalFormat.java b/src/java.base/share/classes/java/text/DecimalFormat.java index ea125b7d14bbb938756055fda5e351adda03f5b5..094a5258b09d605211b6a479d86afc821e1a95d6 100644 --- a/src/java.base/share/classes/java/text/DecimalFormat.java +++ b/src/java.base/share/classes/java/text/DecimalFormat.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 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 @@ -3210,16 +3210,18 @@ public class DecimalFormat extends NumberFormat { for (i = digitCount; i > 0; --i) { if (i != digitCount && isGroupingUsed() && groupingSize != 0 && i % groupingSize == 0) { - result.append(localized ? symbols.getGroupingSeparator() : - PATTERN_GROUPING_SEPARATOR); + result.append(localized ? + (isCurrencyFormat ? symbols.getMonetaryGroupingSeparator() : symbols.getGroupingSeparator()) : + PATTERN_GROUPING_SEPARATOR); } result.append(i <= getMinimumIntegerDigits() ? (localized ? symbols.getZeroDigit() : PATTERN_ZERO_DIGIT) : (localized ? symbols.getDigit() : PATTERN_DIGIT)); } if (getMaximumFractionDigits() > 0 || decimalSeparatorAlwaysShown) - result.append(localized ? symbols.getDecimalSeparator() : - PATTERN_DECIMAL_SEPARATOR); + result.append(localized ? + (isCurrencyFormat ? symbols.getMonetaryDecimalSeparator() : symbols.getDecimalSeparator()) : + PATTERN_DECIMAL_SEPARATOR); for (i = 0; i < getMaximumFractionDigits(); ++i) { if (i < getMinimumFractionDigits()) { result.append(localized ? symbols.getZeroDigit() : diff --git a/src/java.base/share/classes/java/text/DecimalFormatSymbols.java b/src/java.base/share/classes/java/text/DecimalFormatSymbols.java index 11fd24573ef877e58178fa9a2e506b9e733be377..795e087a35174514f2d6ccc33aed10c705479e83 100644 --- a/src/java.base/share/classes/java/text/DecimalFormatSymbols.java +++ b/src/java.base/share/classes/java/text/DecimalFormatSymbols.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 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 @@ -188,6 +188,15 @@ public class DecimalFormatSymbols implements Cloneable, Serializable { return dfsyms; } + /** + * {@return locale used to create this instance} + * + * @since 19 + */ + public Locale getLocale() { + return locale; + } + /** * Gets the character used for zero. Different for Arabic, etc. * diff --git a/src/java.base/share/classes/java/text/MessageFormat.java b/src/java.base/share/classes/java/text/MessageFormat.java index e304d072411401b427f7c169179dbed2113e8372..98f9d1a144d91389cc3d0a9931528704e00b4610 100644 --- a/src/java.base/share/classes/java/text/MessageFormat.java +++ b/src/java.base/share/classes/java/text/MessageFormat.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 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 @@ -778,7 +778,7 @@ public class MessageFormat extends Format { * {@code null} or has fewer than argumentIndex+1 elements. * * - * + * * * * * * - * + * * * * @@ -373,15 +373,15 @@ import sun.util.locale.provider.TimeZoneNameUtility; * letters throws {@code IllegalArgumentException}. *

          * Zone names: This outputs the display name of the time-zone ID. If the - * pattern letter is 'z' the output is the daylight savings aware zone name. + * pattern letter is 'z' the output is the daylight saving aware zone name. * If there is insufficient information to determine whether DST applies, - * the name ignoring daylight savings time will be used. + * the name ignoring daylight saving time will be used. * If the count of letters is one, two or three, then the short name is output. * If the count of letters is four, then the full name is output. * Five or more letters throws {@code IllegalArgumentException}. *

          * If the pattern letter is 'v' the output provides the zone name ignoring - * daylight savings time. If the count of letters is one, then the short name is output. + * daylight saving time. If the count of letters is one, then the short name is output. * If the count of letters is four, then the full name is output. * Two, three and five or more letters throw {@code IllegalArgumentException}. *

          @@ -502,7 +502,10 @@ import sun.util.locale.provider.TimeZoneNameUtility; * {@code LocalDateTime} to form the instant, with any zone ignored. * If a {@code ZoneId} was parsed without an offset then the zone will be * combined with the {@code LocalDateTime} to form the instant using the rules - * of {@link ChronoLocalDateTime#atZone(ZoneId)}. + * of {@link ChronoLocalDateTime#atZone(ZoneId)}. If the {@code ZoneId} was + * parsed from a zone name that indicates whether daylight saving time is in + * operation or not, then that fact will be used to select the correct offset + * at the local time-line overlap. * * * @implSpec @@ -714,6 +717,57 @@ public final class DateTimeFormatter { .toFormatter(ResolverStyle.SMART, IsoChronology.INSTANCE); } + //----------------------------------------------------------------------- + /** + * Creates a locale specific formatter derived from the requested template for + * the ISO chronology. The requested template is a series of typical pattern + * symbols in canonical order from the largest date or time unit to the smallest, + * which can be expressed with the following regular expression: + * {@snippet : + * "G{0,5}" + // Era + * "y*" + // Year + * "Q{0,5}" + // Quarter + * "M{0,5}" + // Month + * "w*" + // Week of Week Based Year + * "E{0,5}" + // Day of Week + * "d{0,2}" + // Day of Month + * "B{0,5}" + // Period/AmPm of Day + * "[hHjC]{0,2}" + // Hour of Day/AmPm (refer to LDML for 'j' and 'C') + * "m{0,2}" + // Minute of Hour + * "s{0,2}" + // Second of Minute + * "[vz]{0,4}" // Zone + * } + * All pattern symbols are optional, and each pattern symbol represents a field, + * for example, 'M' represents the Month field. The number of the pattern symbol letters follows the + * same presentation, such as "number" or "text" as in the Patterns for + * Formatting and Parsing section. Other pattern symbols in the requested template are + * invalid. + *

          + * The mapping of the requested template to the closest of the available localized formats + * is defined by the + * + * Unicode LDML specification. For example, the formatter created from the requested template + * {@code yMMM} will format the date '2020-06-16' to 'Jun 2020' in the {@link Locale#US US locale}. + *

          + * The locale is determined from the formatter. The formatter returned directly by + * this method uses the {@link Locale#getDefault() default FORMAT locale}. + * The locale can be controlled using {@link DateTimeFormatter#withLocale(Locale) withLocale(Locale)} + * on the result of this method. + *

          + * The returned formatter has no override zone. + * It uses {@link ResolverStyle#SMART SMART} resolver style. + * + * @param requestedTemplate the requested template, not null + * @return the formatter based on the {@code requestedTemplate} pattern, not null + * @throws IllegalArgumentException if {@code requestedTemplate} is invalid + * @see #ofPattern(String) + * @since 19 + */ + public static DateTimeFormatter ofLocalizedPattern(String requestedTemplate) { + return new DateTimeFormatterBuilder().appendLocalized(requestedTemplate) + .toFormatter(ResolverStyle.SMART, IsoChronology.INSTANCE); + } + //----------------------------------------------------------------------- /** * The ISO date formatter that formats or parses a date without an @@ -1519,7 +1573,7 @@ public final class DateTimeFormatter { /** * Gets the DecimalStyle to be used during formatting. * - * @return the locale of this formatter, not null + * @return the DecimalStyle of this formatter, not null */ public DecimalStyle getDecimalStyle() { return decimalStyle; diff --git a/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java b/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java index 7af964f106b8aef27047a10a5c72b72fcfd185c5..d45bfa03f9181766518936137555b6a8dc420861 100644 --- a/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java +++ b/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -227,6 +227,42 @@ public final class DateTimeFormatterBuilder { CalendarDataUtility.findRegionOverride(locale)); } + /** + * Returns the formatting pattern for the requested template for a locale and chronology. + * The locale and chronology are used to lookup the locale specific format + * for the requested template. + *

          + * If the locale contains the "rg" (region override) + * Unicode extensions, + * the formatting pattern is overridden with the one appropriate for the region. + *

          + * Refer to {@link #appendLocalized(String)} for the detail of {@code requestedTemplate} + * argument. + * + * @param requestedTemplate the requested template, not null + * @param chrono the Chronology, non-null + * @param locale the locale, non-null + * @return the locale and Chronology specific formatting pattern + * @throws IllegalArgumentException if {@code requestedTemplate} does not match + * the regular expression syntax described in {@link #appendLocalized(String)}. + * @throws DateTimeException if a match for the localized pattern for + * {@code requestedTemplate} is not available + * @see #appendLocalized(String) + * @since 19 + */ + public static String getLocalizedDateTimePattern(String requestedTemplate, + Chronology chrono, Locale locale) { + Objects.requireNonNull(requestedTemplate, "requestedTemplate"); + Objects.requireNonNull(chrono, "chrono"); + Objects.requireNonNull(locale, "locale"); + Locale override = CalendarDataUtility.findRegionOverride(locale); + LocaleProviderAdapter adapter = LocaleProviderAdapter.getAdapter(JavaTimeDateTimePatternProvider.class, override); + JavaTimeDateTimePatternProvider provider = adapter.getJavaTimeDateTimePatternProvider(); + return provider.getJavaTimeDateTimePattern(requestedTemplate, + chrono.getCalendarType(), + override); + } + /** * Converts the given FormatStyle to the java.text.DateFormat style. * @@ -1423,6 +1459,84 @@ public final class DateTimeFormatterBuilder { return this; } + //----------------------------------------------------------------------- + // RegEx pattern for skeleton validity checking + private static final Pattern VALID_TEMPLATE_PATTERN = Pattern.compile( + "G{0,5}" + // Era + "y*" + // Year + "Q{0,5}" + // Quarter + "M{0,5}" + // Month + "w*" + // Week of Week Based Year + "E{0,5}" + // Day of Week + "d{0,2}" + // Day of Month + "B{0,5}" + // Period/AmPm of Day + "[hHjC]{0,2}" + // Hour of Day/AmPm + "m{0,2}" + // Minute of Hour + "s{0,2}" + // Second of Minute + "[vz]{0,4}"); // Zone + /** + * Appends a localized pattern to the formatter using the requested template. + *

          + * This appends a localized section to the builder, suitable for outputting + * a date, time or date-time combination. The format of the localized + * section is lazily looked up based on three items: + *

            + *
          • the {@code requestedTemplate} specified to this method + *
          • the {@code Locale} of the {@code DateTimeFormatter} + *
          • the {@code Chronology} of the {@code DateTimeFormatter} unless overridden + *
          + * During formatting, the chronology is obtained from the temporal object + * being formatted, which may have been overridden by + * {@link DateTimeFormatter#withChronology(Chronology)}. + *

          + * During parsing, if a chronology has already been parsed, then it is used. + * Otherwise the default from {@code DateTimeFormatter.withChronology(Chronology)} + * is used, with {@code IsoChronology} as the fallback. + *

          + * The requested template is a series of typical pattern + * symbols in canonical order from the largest date or time unit to the smallest, + * which can be expressed with the following regular expression: + * {@snippet : + * "G{0,5}" + // Era + * "y*" + // Year + * "Q{0,5}" + // Quarter + * "M{0,5}" + // Month + * "w*" + // Week of Week Based Year + * "E{0,5}" + // Day of Week + * "d{0,2}" + // Day of Month + * "B{0,5}" + // Period/AmPm of Day + * "[hHjC]{0,2}" + // Hour of Day/AmPm (refer to LDML for 'j' and 'C') + * "m{0,2}" + // Minute of Hour + * "s{0,2}" + // Second of Minute + * "[vz]{0,4}" // Zone + * } + * All pattern symbols are optional, and each pattern symbol represents a field, + * for example, 'M' represents the Month field. The number of the pattern symbol letters follows the + * same presentation, such as "number" or "text" as in the + * Patterns for Formatting and Parsing section. + * Other pattern symbols in the requested template are invalid. + *

          + * The mapping of the requested template to the closest of the available localized formats + * is defined by the + * + * Unicode LDML specification. For example, the formatter created from the requested template + * {@code yMMM} will format the date '2020-06-16' to 'Jun 2020' in the {@link Locale#US US locale}. + * + * @param requestedTemplate the requested template to use, not null + * @return this, for chaining, not null + * @throws IllegalArgumentException if {@code requestedTemplate} is invalid + * @see #appendPattern(String) + * @since 19 + */ + public DateTimeFormatterBuilder appendLocalized(String requestedTemplate) { + Objects.requireNonNull(requestedTemplate, "requestedTemplate"); + if (!VALID_TEMPLATE_PATTERN.matcher(requestedTemplate).matches()) { + throw new IllegalArgumentException("Requested template is invalid: " + requestedTemplate); + } + appendInternal(new LocalizedPrinterParser(requestedTemplate)); + return this; + } + //----------------------------------------------------------------------- /** * Appends a character literal to the formatter. @@ -1660,7 +1774,7 @@ public final class DateTimeFormatterBuilder { * D 1 appendValue(ChronoField.DAY_OF_YEAR) * DD 2 appendValue(ChronoField.DAY_OF_YEAR, 2, 3, SignStyle.NOT_NEGATIVE) * DDD 3 appendValue(ChronoField.DAY_OF_YEAR, 3) - * F 1 appendValue(ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH) + * F 1 appendValue(ChronoField.ALIGNED_WEEK_OF_MONTH) * g..g 1..n appendValue(JulianFields.MODIFIED_JULIAN_DAY, n, 19, SignStyle.NORMAL) * E 1 appendText(ChronoField.DAY_OF_WEEK, TextStyle.SHORT) * EE 2 appendText(ChronoField.DAY_OF_WEEK, TextStyle.SHORT) @@ -2069,7 +2183,7 @@ public final class DateTimeFormatterBuilder { FIELD_MAP.put('L', ChronoField.MONTH_OF_YEAR); // SDF, LDML (stand-alone) FIELD_MAP.put('D', ChronoField.DAY_OF_YEAR); // SDF, LDML FIELD_MAP.put('d', ChronoField.DAY_OF_MONTH); // SDF, LDML - FIELD_MAP.put('F', ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH); // SDF, LDML + FIELD_MAP.put('F', ChronoField.ALIGNED_WEEK_OF_MONTH); // SDF, LDML FIELD_MAP.put('E', ChronoField.DAY_OF_WEEK); // SDF, LDML (different to both for 1/2 chars) FIELD_MAP.put('c', ChronoField.DAY_OF_WEEK); // LDML (stand-alone) FIELD_MAP.put('e', ChronoField.DAY_OF_WEEK); // LDML (needs localized week number) @@ -2378,11 +2492,11 @@ public final class DateTimeFormatterBuilder { private final DateTimePrinterParser[] printerParsers; private final boolean optional; - CompositePrinterParser(List printerParsers, boolean optional) { + private CompositePrinterParser(List printerParsers, boolean optional) { this(printerParsers.toArray(new DateTimePrinterParser[0]), optional); } - CompositePrinterParser(DateTimePrinterParser[] printerParsers, boolean optional) { + private CompositePrinterParser(DateTimePrinterParser[] printerParsers, boolean optional) { this.printerParsers = printerParsers; this.optional = optional; } @@ -2476,7 +2590,7 @@ public final class DateTimeFormatterBuilder { * @param padWidth the width to pad to, 1 or greater * @param padChar the pad character */ - PadPrinterParserDecorator(DateTimePrinterParser printerParser, int padWidth, char padChar) { + private PadPrinterParserDecorator(DateTimePrinterParser printerParser, int padWidth, char padChar) { // input checked by DateTimeFormatterBuilder this.printerParser = printerParser; this.padWidth = padWidth; @@ -2584,7 +2698,7 @@ public final class DateTimeFormatterBuilder { private final TemporalField field; private final long value; - DefaultValueParser(TemporalField field, long value) { + private DefaultValueParser(TemporalField field, long value) { this.field = field; this.value = value; } @@ -2608,7 +2722,7 @@ public final class DateTimeFormatterBuilder { static final class CharLiteralPrinterParser implements DateTimePrinterParser { private final char literal; - CharLiteralPrinterParser(char literal) { + private CharLiteralPrinterParser(char literal) { this.literal = literal; } @@ -2651,7 +2765,7 @@ public final class DateTimeFormatterBuilder { static final class StringLiteralPrinterParser implements DateTimePrinterParser { private final String literal; - StringLiteralPrinterParser(String literal) { + private StringLiteralPrinterParser(String literal) { this.literal = literal; // validated by caller } @@ -2717,7 +2831,7 @@ public final class DateTimeFormatterBuilder { * @param maxWidth the maximum field width, from minWidth to 19 * @param signStyle the positive/negative sign style, not null */ - NumberPrinterParser(TemporalField field, int minWidth, int maxWidth, SignStyle signStyle) { + private NumberPrinterParser(TemporalField field, int minWidth, int maxWidth, SignStyle signStyle) { // validated by caller this.field = field; this.minWidth = minWidth; @@ -3008,7 +3122,7 @@ public final class DateTimeFormatterBuilder { * @param baseValue the base value * @param baseDate the base date */ - ReducedPrinterParser(TemporalField field, int minWidth, int maxWidth, + private ReducedPrinterParser(TemporalField field, int minWidth, int maxWidth, int baseValue, ChronoLocalDate baseDate) { this(field, minWidth, maxWidth, baseValue, baseDate, 0); if (minWidth < 1 || minWidth > 10) { @@ -3161,7 +3275,7 @@ public final class DateTimeFormatterBuilder { * @param maxWidth the maximum width to output, from 0 to 9 * @param decimalPoint whether to output the localized decimal point symbol */ - NanosPrinterParser(int minWidth, int maxWidth, boolean decimalPoint) { + private NanosPrinterParser(int minWidth, int maxWidth, boolean decimalPoint) { this(minWidth, maxWidth, decimalPoint, 0); if (minWidth < 0 || minWidth > 9) { throw new IllegalArgumentException("Minimum width must be from 0 to 9 inclusive but was " + minWidth); @@ -3183,7 +3297,7 @@ public final class DateTimeFormatterBuilder { * @param decimalPoint whether to output the localized decimal point symbol * @param subsequentWidth the subsequentWidth for this instance */ - NanosPrinterParser(int minWidth, int maxWidth, boolean decimalPoint, int subsequentWidth) { + private NanosPrinterParser(int minWidth, int maxWidth, boolean decimalPoint, int subsequentWidth) { super(NANO_OF_SECOND, minWidth, maxWidth, SignStyle.NOT_NEGATIVE, subsequentWidth); this.decimalPoint = decimalPoint; } @@ -3366,7 +3480,7 @@ public final class DateTimeFormatterBuilder { * @param maxWidth the maximum width to output, from 0 to 9 * @param decimalPoint whether to output the localized decimal point symbol */ - FractionPrinterParser(TemporalField field, int minWidth, int maxWidth, boolean decimalPoint) { + private FractionPrinterParser(TemporalField field, int minWidth, int maxWidth, boolean decimalPoint) { this(field, minWidth, maxWidth, decimalPoint, 0); Objects.requireNonNull(field, "field"); if (field.range().isFixed() == false) { @@ -3393,7 +3507,7 @@ public final class DateTimeFormatterBuilder { * @param decimalPoint whether to output the localized decimal point symbol * @param subsequentWidth the subsequentWidth for this instance */ - FractionPrinterParser(TemporalField field, int minWidth, int maxWidth, boolean decimalPoint, int subsequentWidth) { + private FractionPrinterParser(TemporalField field, int minWidth, int maxWidth, boolean decimalPoint, int subsequentWidth) { super(field, minWidth, maxWidth, SignStyle.NOT_NEGATIVE, subsequentWidth); this.decimalPoint = decimalPoint; ValueRange range = field.range(); @@ -3583,7 +3697,7 @@ public final class DateTimeFormatterBuilder { * @param textStyle the text style, not null * @param provider the text provider, not null */ - TextPrinterParser(TemporalField field, TextStyle textStyle, DateTimeTextProvider provider) { + private TextPrinterParser(TemporalField field, TextStyle textStyle, DateTimeTextProvider provider) { // validated by caller this.field = field; this.textStyle = textStyle; @@ -3681,7 +3795,7 @@ public final class DateTimeFormatterBuilder { private static final long SECONDS_0000_TO_1970 = ((146097L * 5L) - (30L * 365L + 7L)) * 86400L; private final int fractionalDigits; - InstantPrinterParser(int fractionalDigits) { + private InstantPrinterParser(int fractionalDigits) { this.fractionalDigits = fractionalDigits; } @@ -3830,7 +3944,7 @@ public final class DateTimeFormatterBuilder { * @param pattern the pattern * @param noOffsetText the text to use for UTC, not null */ - OffsetIdPrinterParser(String pattern, String noOffsetText) { + private OffsetIdPrinterParser(String pattern, String noOffsetText) { Objects.requireNonNull(pattern, "pattern"); Objects.requireNonNull(noOffsetText, "noOffsetText"); this.type = checkPattern(pattern); @@ -4312,7 +4426,7 @@ public final class DateTimeFormatterBuilder { /** Display in generic time-zone format. True in case of pattern letter 'v' */ private final boolean isGeneric; - ZoneTextPrinterParser(TextStyle textStyle, Set preferredZones, boolean isGeneric) { + private ZoneTextPrinterParser(TextStyle textStyle, Set preferredZones, boolean isGeneric) { super(TemporalQueries.zone(), "ZoneText(" + textStyle + ")"); this.textStyle = Objects.requireNonNull(textStyle, "textStyle"); this.isGeneric = isGeneric; @@ -4324,9 +4438,10 @@ public final class DateTimeFormatterBuilder { } } - private static final int STD = 0; - private static final int DST = 1; - private static final int GENERIC = 2; + static final int UNDEFINED = -1; + static final int STD = 0; + static final int DST = 1; + static final int GENERIC = 2; private static final Map>> cache = new ConcurrentHashMap<>(); @@ -4433,11 +4548,11 @@ public final class DateTimeFormatterBuilder { nonRegionIds.add(zid); continue; } - tree.add(zid, zid); // don't convert zid -> metazone + tree.add(zid, zid, UNDEFINED); // don't convert zid -> metazone zid = ZoneName.toZid(zid, locale); int i = textStyle == TextStyle.FULL ? 1 : 2; for (; i < names.length; i += 2) { - tree.add(names[i], zid); + tree.add(names[i], zid, (i - 1) / 2); } } @@ -4450,7 +4565,7 @@ public final class DateTimeFormatterBuilder { int i = textStyle == TextStyle.FULL ? 1 : 2; for (; i < cidNames.length; i += 2) { if (cidNames[i] != null && !cidNames[i].isEmpty()) { - t.add(cidNames[i], cid); + t.add(cidNames[i], cid, (i - 1) / 2); } } }); @@ -4465,7 +4580,7 @@ public final class DateTimeFormatterBuilder { } int i = textStyle == TextStyle.FULL ? 1 : 2; for (; i < names.length; i += 2) { - tree.add(names[i], zid); + tree.add(names[i], zid, (i - 1) / 2); } } } @@ -4483,7 +4598,7 @@ public final class DateTimeFormatterBuilder { private final TemporalQuery query; private final String description; - ZoneIdPrinterParser(TemporalQuery query, String description) { + private ZoneIdPrinterParser(TemporalQuery query, String description) { this.query = query; this.description = description; } @@ -4571,15 +4686,16 @@ public final class DateTimeFormatterBuilder { // parse PrefixTree tree = getTree(context); ParsePosition ppos = new ParsePosition(position); - String parsedZoneId = tree.match(text, ppos); - if (parsedZoneId == null) { + PrefixTree parsedZoneId = tree.match(text, ppos); + if (parsedZoneId.value == null) { if (context.charEquals(nextChar, 'Z')) { context.setParsed(ZoneOffset.UTC); return position + 1; } return ~position; } - context.setParsed(ZoneId.of(parsedZoneId)); + context.setParsed(ZoneId.of(parsedZoneId.value)); + context.setParsedZoneNameType(parsedZoneId.type); return ppos.getIndex(); } @@ -4641,14 +4757,16 @@ public final class DateTimeFormatterBuilder { static class PrefixTree { protected String key; protected String value; + protected int type; protected char c0; // performance optimization to avoid the // boundary check cost of key.charat(0) protected PrefixTree child; protected PrefixTree sibling; - private PrefixTree(String k, String v, PrefixTree child) { + private PrefixTree(String k, String v, int type, PrefixTree child) { this.key = k; this.value = v; + this.type = type; this.child = child; if (k.isEmpty()) { c0 = 0xffff; @@ -4664,13 +4782,10 @@ public final class DateTimeFormatterBuilder { * @return the tree, not null */ public static PrefixTree newTree(DateTimeParseContext context) { - //if (!context.isStrict()) { - // return new LENIENT("", null, null); - //} if (context.isCaseSensitive()) { - return new PrefixTree("", null, null); + return new PrefixTree("", null, ZoneTextPrinterParser.UNDEFINED, null); } - return new CI("", null, null); + return new CI("", null, ZoneTextPrinterParser.UNDEFINED, null); } /** @@ -4683,7 +4798,7 @@ public final class DateTimeFormatterBuilder { public static PrefixTree newTree(Set keys, DateTimeParseContext context) { PrefixTree tree = newTree(context); for (String k : keys) { - tree.add0(k, k); + tree.add0(k, k, ZoneTextPrinterParser.UNDEFINED); } return tree; } @@ -4692,7 +4807,7 @@ public final class DateTimeFormatterBuilder { * Clone a copy of this tree */ public PrefixTree copyTree() { - PrefixTree copy = new PrefixTree(key, value, null); + PrefixTree copy = new PrefixTree(key, value, type, null); if (child != null) { copy.child = child.copyTree(); } @@ -4710,11 +4825,11 @@ public final class DateTimeFormatterBuilder { * @param v the value, not null * @return true if the pair is added successfully */ - public boolean add(String k, String v) { - return add0(k, v); + public boolean add(String k, String v, int t) { + return add0(k, v, t); } - private boolean add0(String k, String v) { + private boolean add0(String k, String v, int t) { k = toKey(k); int prefixLen = prefixLength(k); if (prefixLen == key.length()) { @@ -4723,12 +4838,12 @@ public final class DateTimeFormatterBuilder { PrefixTree c = child; while (c != null) { if (isEqual(c.c0, subKey.charAt(0))) { - return c.add0(subKey, v); + return c.add0(subKey, v, t); } c = c.sibling; } // add the node as the child of the current node - c = newNode(subKey, v, null); + c = newNode(subKey, v, t, null); c.sibling = child; child = c; return true; @@ -4738,18 +4853,20 @@ public final class DateTimeFormatterBuilder { // return false; //} value = v; + type = t; return true; } // split the existing node - PrefixTree n1 = newNode(key.substring(prefixLen), value, child); + PrefixTree n1 = newNode(key.substring(prefixLen), value, type, child); key = k.substring(0, prefixLen); child = n1; if (prefixLen < k.length()) { - PrefixTree n2 = newNode(k.substring(prefixLen), v, null); + PrefixTree n2 = newNode(k.substring(prefixLen), v, t, null); child.sibling = n2; value = null; } else { value = v; + type = t; } return true; } @@ -4760,9 +4877,9 @@ public final class DateTimeFormatterBuilder { * @param text the input text to parse, not null * @param off the offset position to start parsing at * @param end the end position to stop parsing - * @return the resulting string, or null if no match found. + * @return the resulting tree, or null if no match found. */ - public String match(CharSequence text, int off, int end) { + public PrefixTree match(CharSequence text, int off, int end) { if (!prefixOf(text, off, end)){ return null; } @@ -4770,16 +4887,16 @@ public final class DateTimeFormatterBuilder { PrefixTree c = child; do { if (isEqual(c.c0, text.charAt(off))) { - String found = c.match(text, off, end); + PrefixTree found = c.match(text, off, end); if (found != null) { return found; } - return value; + return this; } c = c.sibling; } while (c != null); } - return value; + return this; } /** @@ -4789,9 +4906,9 @@ public final class DateTimeFormatterBuilder { * @param pos the position to start parsing at, from 0 to the text * length. Upon return, position will be updated to the new parse * position, or unchanged, if no match found. - * @return the resulting string, or null if no match found. + * @return the resulting tree, or null if no match found. */ - public String match(CharSequence text, ParsePosition pos) { + public PrefixTree match(CharSequence text, ParsePosition pos) { int off = pos.getIndex(); int end = text.length(); if (!prefixOf(text, off, end)){ @@ -4803,7 +4920,7 @@ public final class DateTimeFormatterBuilder { do { if (isEqual(c.c0, text.charAt(off))) { pos.setIndex(off); - String found = c.match(text, pos); + PrefixTree found = c.match(text, pos); if (found != null) { return found; } @@ -4813,15 +4930,15 @@ public final class DateTimeFormatterBuilder { } while (c != null); } pos.setIndex(off); - return value; + return this; } protected String toKey(String k) { return k; } - protected PrefixTree newNode(String k, String v, PrefixTree child) { - return new PrefixTree(k, v, child); + protected PrefixTree newNode(String k, String v, int t, PrefixTree child) { + return new PrefixTree(k, v, t, child); } protected boolean isEqual(char c1, char c2) { @@ -4861,13 +4978,13 @@ public final class DateTimeFormatterBuilder { */ private static class CI extends PrefixTree { - private CI(String k, String v, PrefixTree child) { - super(k, v, child); + private CI(String k, String v, int t, PrefixTree child) { + super(k, v, t, child); } @Override - protected CI newNode(String k, String v, PrefixTree child) { - return new CI(k, v, child); + protected CI newNode(String k, String v, int t, PrefixTree child) { + return new CI(k, v, t, child); } @Override @@ -4890,86 +5007,6 @@ public final class DateTimeFormatterBuilder { return true; } } - - /** - * Lenient prefix tree. Case insensitive and ignores characters - * like space, underscore and slash. - */ - private static class LENIENT extends CI { - - private LENIENT(String k, String v, PrefixTree child) { - super(k, v, child); - } - - @Override - protected CI newNode(String k, String v, PrefixTree child) { - return new LENIENT(k, v, child); - } - - private boolean isLenientChar(char c) { - return c == ' ' || c == '_' || c == '/'; - } - - protected String toKey(String k) { - for (int i = 0; i < k.length(); i++) { - if (isLenientChar(k.charAt(i))) { - StringBuilder sb = new StringBuilder(k.length()); - sb.append(k, 0, i); - i++; - while (i < k.length()) { - if (!isLenientChar(k.charAt(i))) { - sb.append(k.charAt(i)); - } - i++; - } - return sb.toString(); - } - } - return k; - } - - @Override - public String match(CharSequence text, ParsePosition pos) { - int off = pos.getIndex(); - int end = text.length(); - int len = key.length(); - int koff = 0; - while (koff < len && off < end) { - if (isLenientChar(text.charAt(off))) { - off++; - continue; - } - if (!isEqual(key.charAt(koff++), text.charAt(off++))) { - return null; - } - } - if (koff != len) { - return null; - } - if (child != null && off != end) { - int off0 = off; - while (off0 < end && isLenientChar(text.charAt(off0))) { - off0++; - } - if (off0 < end) { - PrefixTree c = child; - do { - if (isEqual(c.c0, text.charAt(off0))) { - pos.setIndex(off0); - String found = c.match(text, pos); - if (found != null) { - return found; - } - break; - } - c = c.sibling; - } while (c != null); - } - } - pos.setIndex(off); - return value; - } - } } //----------------------------------------------------------------------- @@ -4980,7 +5017,7 @@ public final class DateTimeFormatterBuilder { /** The text style to output, null means the ID. */ private final TextStyle textStyle; - ChronoPrinterParser(TextStyle textStyle) { + private ChronoPrinterParser(TextStyle textStyle) { // validated by caller this.textStyle = textStyle; } @@ -5055,6 +5092,7 @@ public final class DateTimeFormatterBuilder { private final FormatStyle dateStyle; private final FormatStyle timeStyle; + private final String requestedTemplate; /** * Constructor. @@ -5062,10 +5100,23 @@ public final class DateTimeFormatterBuilder { * @param dateStyle the date style to use, may be null * @param timeStyle the time style to use, may be null */ - LocalizedPrinterParser(FormatStyle dateStyle, FormatStyle timeStyle) { - // validated by caller + private LocalizedPrinterParser(FormatStyle dateStyle, FormatStyle timeStyle) { + // params validated by caller this.dateStyle = dateStyle; this.timeStyle = timeStyle; + this.requestedTemplate = null; + } + + /** + * Constructor. + * + * @param requestedTemplate the requested template to use, not null + */ + private LocalizedPrinterParser(String requestedTemplate) { + // param validated by caller + this.dateStyle = null; + this.timeStyle = null; + this.requestedTemplate = requestedTemplate; } @Override @@ -5083,7 +5134,8 @@ public final class DateTimeFormatterBuilder { /** * Gets the formatter to use. *

          - * The formatter will be the most appropriate to use for the date and time style in the locale. + * The formatter will be the most appropriate to use for the date and time style, or + * the requested template for the locale. * For example, some locales will use the month name while others will use the number. * * @param locale the locale to use, not null @@ -5092,23 +5144,22 @@ public final class DateTimeFormatterBuilder { * @throws IllegalArgumentException if the formatter cannot be found */ private DateTimeFormatter formatter(Locale locale, Chronology chrono) { - String key = chrono.getId() + '|' + locale.toString() + '|' + dateStyle + timeStyle; - DateTimeFormatter formatter = FORMATTER_CACHE.get(key); - if (formatter == null) { - String pattern = getLocalizedDateTimePattern(dateStyle, timeStyle, chrono, locale); - formatter = new DateTimeFormatterBuilder().appendPattern(pattern).toFormatter(locale); - DateTimeFormatter old = FORMATTER_CACHE.putIfAbsent(key, formatter); - if (old != null) { - formatter = old; - } - } - return formatter; + String key = chrono.getId() + '|' + locale.toString() + '|' + + (requestedTemplate != null ? requestedTemplate : Objects.toString(dateStyle) + timeStyle); + + return FORMATTER_CACHE.computeIfAbsent(key, k -> + new DateTimeFormatterBuilder() + .appendPattern(requestedTemplate != null ? + getLocalizedDateTimePattern(requestedTemplate, chrono, locale) : + getLocalizedDateTimePattern(dateStyle, timeStyle, chrono, locale)) + .toFormatter(locale)); } @Override public String toString() { - return "Localized(" + (dateStyle != null ? dateStyle : "") + "," + - (timeStyle != null ? timeStyle : "") + ")"; + return "Localized(" + (requestedTemplate != null ? requestedTemplate : + (dateStyle != null ? dateStyle : "") + "," + + (timeStyle != null ? timeStyle : "")) + ")"; } } @@ -5133,7 +5184,7 @@ public final class DateTimeFormatterBuilder { * @param minWidth the minimum field width, from 1 to 19 * @param maxWidth the maximum field width, from minWidth to 19 */ - WeekBasedFieldPrinterParser(char chr, int count, int minWidth, int maxWidth) { + private WeekBasedFieldPrinterParser(char chr, int count, int minWidth, int maxWidth) { this(chr, count, minWidth, maxWidth, 0); } @@ -5147,7 +5198,7 @@ public final class DateTimeFormatterBuilder { * @param subsequentWidth the width of subsequent non-negative numbers, 0 or greater, * -1 if fixed width due to active adjacent parsing */ - WeekBasedFieldPrinterParser(char chr, int count, int minWidth, int maxWidth, + private WeekBasedFieldPrinterParser(char chr, int count, int minWidth, int maxWidth, int subsequentWidth) { super(null, minWidth, maxWidth, SignStyle.NOT_NEGATIVE, subsequentWidth); this.chr = chr; @@ -5278,7 +5329,7 @@ public final class DateTimeFormatterBuilder { * * @param textStyle the text style, not null */ - DayPeriodPrinterParser(TextStyle textStyle) { + private DayPeriodPrinterParser(TextStyle textStyle) { // validated by caller this.textStyle = textStyle; } diff --git a/src/java.base/share/classes/java/time/format/DateTimeParseContext.java b/src/java.base/share/classes/java/time/format/DateTimeParseContext.java index 32eefcecc3009263ba3ba6b068b60b23bb7750ca..0a4c7e825a3b60c4e05475281b696d2da923c11f 100644 --- a/src/java.base/share/classes/java/time/format/DateTimeParseContext.java +++ b/src/java.base/share/classes/java/time/format/DateTimeParseContext.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -417,6 +417,24 @@ final class DateTimeParseContext { currentParsed().zone = zone; } + /** + * Stores the parsed zone name type. + *

          + * This stores the zone name type that has been parsed. + * The parsed type should either be; + *

            + *
          • {@link DateTimeFormatterBuilder.ZoneTextPrinterParser#UNDEFINED}
          • + *
          • {@link DateTimeFormatterBuilder.ZoneTextPrinterParser#STD}
          • + *
          • {@link DateTimeFormatterBuilder.ZoneTextPrinterParser#DST}
          • + *
          • {@link DateTimeFormatterBuilder.ZoneTextPrinterParser#GENERIC}
          • + *
          + * + * @param type the parsed zone name type + */ + void setParsedZoneNameType(int type) { + currentParsed().zoneNameType = type; + } + /** * Stores the parsed leap second. */ diff --git a/src/java.base/share/classes/java/time/format/Parsed.java b/src/java.base/share/classes/java/time/format/Parsed.java index 567c2700a155855ae7e19a5d9087a849d6f4c68e..1ec956dfa2cd39ceb60023e5087ba415af876169 100644 --- a/src/java.base/share/classes/java/time/format/Parsed.java +++ b/src/java.base/share/classes/java/time/format/Parsed.java @@ -87,6 +87,7 @@ import java.time.LocalTime; import java.time.Period; import java.time.ZoneId; import java.time.ZoneOffset; +import java.time.ZonedDateTime; import java.time.chrono.ChronoLocalDate; import java.time.chrono.ChronoLocalDateTime; import java.time.chrono.ChronoZonedDateTime; @@ -132,6 +133,10 @@ final class Parsed implements TemporalAccessor { * The parsed zone. */ ZoneId zone; + /** + * The parsed zone name type. + */ + int zoneNameType = DateTimeFormatterBuilder.ZoneTextPrinterParser.UNDEFINED; /** * The parsed chronology. */ @@ -175,6 +180,7 @@ final class Parsed implements TemporalAccessor { Parsed cloned = new Parsed(); cloned.fieldValues.putAll(this.fieldValues); cloned.zone = this.zone; + cloned.zoneNameType = this.zoneNameType; cloned.chrono = this.chrono; cloned.leapSecond = this.leapSecond; cloned.dayPeriod = this.dayPeriod; @@ -652,8 +658,12 @@ final class Parsed implements TemporalAccessor { fieldValues.put(INSTANT_SECONDS, instant); } else { if (zone != null) { - long instant = date.atTime(time).atZone(zone).toEpochSecond(); - fieldValues.put(INSTANT_SECONDS, instant); + var czdt = date.atTime(time).atZone(zone); + if (zoneNameType == DateTimeFormatterBuilder.ZoneTextPrinterParser.STD || + zoneNameType == DateTimeFormatterBuilder.ZoneTextPrinterParser.GENERIC) { + czdt = czdt.withLaterOffsetAtOverlap(); + } + fieldValues.put(INSTANT_SECONDS, czdt.toEpochSecond()); } } } @@ -718,6 +728,7 @@ final class Parsed implements TemporalAccessor { buf.append(fieldValues).append(',').append(chrono); if (zone != null) { buf.append(',').append(zone); + buf.append(',').append(zoneNameType); } if (date != null || time != null) { buf.append(" resolved to "); diff --git a/src/java.base/share/classes/java/util/Calendar.java b/src/java.base/share/classes/java/util/Calendar.java index 08954ac010430f33f2df80b8809acf8eb9724f09..5a31aade9187910721275db42558766105fadaa7 100644 --- a/src/java.base/share/classes/java/util/Calendar.java +++ b/src/java.base/share/classes/java/util/Calendar.java @@ -3416,8 +3416,7 @@ public abstract class Calendar implements Serializable, Cloneable, Comparable t) ? 1 : (thisTime == t) ? 0 : -1; + return Long.compare(getMillisOf(this), t); } private static long getMillisOf(Calendar calendar) { diff --git a/src/java.base/share/classes/java/util/Date.java b/src/java.base/share/classes/java/util/Date.java index d0b31a4026848df7e1f6401f63a33964b21016aa..52b70b55d9876901e47a0b00b5e8f9fba75e1236 100644 --- a/src/java.base/share/classes/java/util/Date.java +++ b/src/java.base/share/classes/java/util/Date.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 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 @@ -26,18 +26,13 @@ package java.util; import java.text.DateFormat; -import java.time.LocalDate; import java.io.IOException; import java.io.ObjectOutputStream; import java.io.ObjectInputStream; -import java.lang.ref.SoftReference; import java.time.Instant; import sun.util.calendar.BaseCalendar; -import sun.util.calendar.CalendarDate; import sun.util.calendar.CalendarSystem; import sun.util.calendar.CalendarUtils; -import sun.util.calendar.Era; -import sun.util.calendar.Gregorian; import sun.util.calendar.ZoneInfo; /** @@ -975,10 +970,9 @@ public class Date * @since 1.2 * @throws NullPointerException if {@code anotherDate} is null. */ + @Override public int compareTo(Date anotherDate) { - long thisTime = getMillisOf(this); - long anotherTime = getMillisOf(anotherDate); - return (thisTime> extends AbstractSet - implements Cloneable, java.io.Serializable +public abstract sealed class EnumSet> extends AbstractSet + implements Cloneable, java.io.Serializable permits JumboEnumSet, RegularEnumSet { // declare EnumSet.class serialization compatibility with JDK 8 @java.io.Serial diff --git a/src/java.base/share/classes/java/util/Formatter.java b/src/java.base/share/classes/java/util/Formatter.java index d3f2ecd977babfabe6a4d7c44c938ba9deef427f..5c5859c767dc3a0e729e2e38e23d04e12bd4555e 100644 --- a/src/java.base/share/classes/java/util/Formatter.java +++ b/src/java.base/share/classes/java/util/Formatter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -2008,15 +2008,41 @@ import sun.util.locale.provider.ResourceBundleBasedAdapter; * @since 1.5 */ public final class Formatter implements Closeable, Flushable { + // Caching DecimalFormatSymbols. Non-volatile to avoid thread slamming. + private static DecimalFormatSymbols DFS = null; + private static DecimalFormatSymbols getDecimalFormatSymbols(Locale locale) { + // Capture local copy to avoid thread race. + DecimalFormatSymbols dfs = DFS; + if (dfs != null && dfs.getLocale().equals(locale)) { + return dfs; + } + // Fetch a new local instance of DecimalFormatSymbols. Note that DFS are mutable + // and this instance is reserved for Formatter. + dfs = DecimalFormatSymbols.getInstance(locale); + // Non-volatile here is acceptable heuristic. + DFS = dfs; + return dfs; + } + + // Use zero from cached DecimalFormatSymbols. + private static char getZero(Locale locale) { + return locale == null ? '0' : getDecimalFormatSymbols(locale).getZeroDigit(); + } + + // Use decimal separator from cached DecimalFormatSymbols. + private static char getDecimalSeparator(Locale locale) { + return locale == null ? '.' : getDecimalFormatSymbols(locale).getDecimalSeparator(); + } + + // Use grouping separator from cached DecimalFormatSymbols. + private static char getGroupingSeparator(Locale locale) { + return locale == null ? ',' : getDecimalFormatSymbols(locale).getGroupingSeparator(); + } + private Appendable a; private final Locale l; - private IOException lastException; - // Non-character value used to mark zero as uninitialized - private static final char ZERO_SENTINEL = '\uFFFE'; - private char zero = ZERO_SENTINEL; - /** * Returns a charset object for the given charset name. * @throws NullPointerException is csn is null @@ -2034,7 +2060,7 @@ public final class Formatter implements Closeable, Flushable { } } - private static final Appendable nonNullAppendable(Appendable a) { + private static Appendable nonNullAppendable(Appendable a) { if (a == null) return new StringBuilder(); @@ -2523,20 +2549,6 @@ public final class Formatter implements Closeable, Flushable { this(l, new BufferedWriter(new OutputStreamWriter(os, charset))); } - private char zero() { - char zero = this.zero; - if (zero == ZERO_SENTINEL) { - if ((l != null) && !l.equals(Locale.US)) { - DecimalFormatSymbols dfs = DecimalFormatSymbols.getInstance(l); - zero = dfs.getZeroDigit(); - } else { - zero = '0'; - } - this.zero = zero; - } - return zero; - } - /** * Returns the locale set by the construction of this formatter. * @@ -2755,24 +2767,24 @@ public final class Formatter implements Closeable, Flushable { try { switch (index) { case -2 -> // fixed string, "%n", or "%%" - fs.print(null, l); + fs.print(this, null, l); case -1 -> { // relative index if (last < 0 || (args != null && last > args.length - 1)) throw new MissingFormatArgumentException(fs.toString()); - fs.print((args == null ? null : args[last]), l); + fs.print(this, (args == null ? null : args[last]), l); } case 0 -> { // ordinary index lasto++; last = lasto; if (args != null && lasto > args.length - 1) throw new MissingFormatArgumentException(fs.toString()); - fs.print((args == null ? null : args[lasto]), l); + fs.print(this, (args == null ? null : args[lasto]), l); } default -> { // explicit index last = index - 1; if (args != null && last > args.length - 1) throw new MissingFormatArgumentException(fs.toString()); - fs.print((args == null ? null : args[last]), l); + fs.print(this, (args == null ? null : args[last]), l); } } } catch (IOException x) { @@ -2836,11 +2848,11 @@ public final class Formatter implements Closeable, Flushable { private interface FormatString { int index(); - void print(Object arg, Locale l) throws IOException; + void print(Formatter fmt, Object arg, Locale l) throws IOException; String toString(); } - private class FixedString implements FormatString { + private static class FixedString implements FormatString { private final String s; private final int start; private final int end; @@ -2850,8 +2862,8 @@ public final class Formatter implements Closeable, Flushable { this.end = end; } public int index() { return -2; } - public void print(Object arg, Locale l) - throws IOException { a.append(s, start, end); } + public void print(Formatter fmt, Object arg, Locale l) + throws IOException { fmt.a.append(s, start, end); } public String toString() { return s.substring(start, end); } } @@ -2870,10 +2882,10 @@ public final class Formatter implements Closeable, Flushable { DECIMAL_FLOAT }; - private class FormatSpecifier implements FormatString { + private static class FormatSpecifier implements FormatString { private int index = 0; - private Flags f = Flags.NONE; + private int flags = Flags.NONE; private int width = -1; private int precision = -1; private boolean dt = false; @@ -2898,8 +2910,8 @@ public final class Formatter implements Closeable, Flushable { } private void flags(String s, int start, int end) { - f = Flags.parse(s, start, end); - if (f.contains(Flags.PREVIOUS)) + flags = Flags.parse(s, start, end); + if (Flags.contains(flags, Flags.PREVIOUS)) index = -1; } @@ -2935,7 +2947,7 @@ public final class Formatter implements Closeable, Flushable { throw new UnknownFormatConversionException(String.valueOf(c)); } if (Character.isUpperCase(c)) { - f.add(Flags.UPPERCASE); + flags = Flags.add(flags, Flags.UPPERCASE); c = Character.toLowerCase(c); } if (Conversion.isText(c)) { @@ -2947,7 +2959,7 @@ public final class Formatter implements Closeable, Flushable { FormatSpecifier(char conv) { c = conv; if (Character.isUpperCase(conv)) { - f = Flags.UPPERCASE; + flags = Flags.UPPERCASE; c = Character.toLowerCase(conv); } if (Conversion.isText(conv)) { @@ -2965,7 +2977,7 @@ public final class Formatter implements Closeable, Flushable { if (tTStart >= 0) { dt = true; if (s.charAt(tTStart) == 'T') { - f.add(Flags.UPPERCASE); + flags = Flags.add(flags, Flags.UPPERCASE); } } conversion(s.charAt(m.start(6))); @@ -2986,79 +2998,79 @@ public final class Formatter implements Closeable, Flushable { throw new UnknownFormatConversionException(String.valueOf(c)); } - public void print(Object arg, Locale l) throws IOException { + public void print(Formatter fmt, Object arg, Locale l) throws IOException { if (dt) { - printDateTime(arg, l); + printDateTime(fmt, arg, l); return; } switch(c) { case Conversion.DECIMAL_INTEGER: case Conversion.OCTAL_INTEGER: case Conversion.HEXADECIMAL_INTEGER: - printInteger(arg, l); + printInteger(fmt, arg, l); break; case Conversion.SCIENTIFIC: case Conversion.GENERAL: case Conversion.DECIMAL_FLOAT: case Conversion.HEXADECIMAL_FLOAT: - printFloat(arg, l); + printFloat(fmt, arg, l); break; case Conversion.CHARACTER: - printCharacter(arg, l); + printCharacter(fmt, arg, l); break; case Conversion.BOOLEAN: - printBoolean(arg, l); + printBoolean(fmt, arg, l); break; case Conversion.STRING: - printString(arg, l); + printString(fmt, arg, l); break; case Conversion.HASHCODE: - printHashCode(arg, l); + printHashCode(fmt, arg, l); break; case Conversion.LINE_SEPARATOR: - a.append(System.lineSeparator()); + fmt.a.append(System.lineSeparator()); break; case Conversion.PERCENT_SIGN: - print("%", l); + print(fmt, "%", l); break; default: assert false; } } - private void printInteger(Object arg, Locale l) throws IOException { + private void printInteger(Formatter fmt, Object arg, Locale l) throws IOException { if (arg == null) - print("null", l); + print(fmt, "null", l); else if (arg instanceof Byte) - print(((Byte)arg).byteValue(), l); + print(fmt, ((Byte)arg).byteValue(), l); else if (arg instanceof Short) - print(((Short)arg).shortValue(), l); + print(fmt, ((Short)arg).shortValue(), l); else if (arg instanceof Integer) - print(((Integer)arg).intValue(), l); + print(fmt, ((Integer)arg).intValue(), l); else if (arg instanceof Long) - print(((Long)arg).longValue(), l); + print(fmt, ((Long)arg).longValue(), l); else if (arg instanceof BigInteger) - print(((BigInteger)arg), l); + print(fmt, ((BigInteger)arg), l); else failConversion(c, arg); } - private void printFloat(Object arg, Locale l) throws IOException { + private void printFloat(Formatter fmt, Object arg, Locale l) throws IOException { if (arg == null) - print("null", l); + print(fmt, "null", l); else if (arg instanceof Float) - print(((Float)arg).floatValue(), l); + print(fmt, ((Float)arg).floatValue(), l); else if (arg instanceof Double) - print(((Double)arg).doubleValue(), l); + print(fmt, ((Double)arg).doubleValue(), l); else if (arg instanceof BigDecimal) - print(((BigDecimal)arg), l); + print(fmt, ((BigDecimal)arg), l); else failConversion(c, arg); } - private void printDateTime(Object arg, Locale l) throws IOException { + private void printDateTime(Formatter fmt, Object arg, Locale l) throws IOException { if (arg == null) { - print("null", l); + print(fmt, "null", l); return; } Calendar cal = null; @@ -3079,19 +3091,19 @@ public final class Formatter implements Closeable, Flushable { cal = (Calendar) ((Calendar) arg).clone(); cal.setLenient(true); } else if (arg instanceof TemporalAccessor) { - print((TemporalAccessor) arg, c, l); + print(fmt, (TemporalAccessor) arg, c, l); return; } else { failConversion(c, arg); } // Use the provided locale so that invocations of // localizedMagnitude() use optimizations for null. - print(cal, c, l); + print(fmt, cal, c, l); } - private void printCharacter(Object arg, Locale l) throws IOException { + private void printCharacter(Formatter fmt, Object arg, Locale l) throws IOException { if (arg == null) { - print("null", l); + print(fmt, "null", l); return; } String s = null; @@ -3118,26 +3130,25 @@ public final class Formatter implements Closeable, Flushable { } else { failConversion(c, arg); } - print(s, l); + print(fmt, s, l); } - private void printString(Object arg, Locale l) throws IOException { + private void printString(Formatter fmt, Object arg, Locale l) throws IOException { if (arg instanceof Formattable) { - Formatter fmt = Formatter.this; if (fmt.locale() != l) fmt = new Formatter(fmt.out(), l); - ((Formattable)arg).formatTo(fmt, f.valueOf(), width, precision); + ((Formattable)arg).formatTo(fmt, flags, width, precision); } else { - if (f.contains(Flags.ALTERNATE)) + if (Flags.contains(flags, Flags.ALTERNATE)) failMismatch(Flags.ALTERNATE, 's'); if (arg == null) - print("null", l); + print(fmt, "null", l); else - print(arg.toString(), l); + print(fmt, arg.toString(), l); } } - private void printBoolean(Object arg, Locale l) throws IOException { + private void printBoolean(Formatter fmt, Object arg, Locale l) throws IOException { String s; if (arg != null) s = ((arg instanceof Boolean) @@ -3145,22 +3156,22 @@ public final class Formatter implements Closeable, Flushable { : Boolean.toString(true)); else s = Boolean.toString(false); - print(s, l); + print(fmt, s, l); } - private void printHashCode(Object arg, Locale l) throws IOException { + private void printHashCode(Formatter fmt, Object arg, Locale l) throws IOException { String s = (arg == null ? "null" : Integer.toHexString(arg.hashCode())); - print(s, l); + print(fmt, s, l); } - private void print(String s, Locale l) throws IOException { + private void print(Formatter fmt, String s, Locale l) throws IOException { if (precision != -1 && precision < s.length()) s = s.substring(0, precision); - if (f.contains(Flags.UPPERCASE)) + if (Flags.contains(flags, Flags.UPPERCASE)) s = toUpperCaseWithLocale(s, l); - appendJustified(a, s); + appendJustified(fmt.a, s); } private String toUpperCaseWithLocale(String s, Locale l) { @@ -3173,7 +3184,7 @@ public final class Formatter implements Closeable, Flushable { a.append(cs); return; } - boolean padRight = f.contains(Flags.LEFT_JUSTIFY); + boolean padRight = Flags.contains(flags, Flags.LEFT_JUSTIFY); int sp = width - cs.length(); if (padRight) { a.append(cs); @@ -3189,8 +3200,7 @@ public final class Formatter implements Closeable, Flushable { public String toString() { StringBuilder sb = new StringBuilder("%"); // Flags.UPPERCASE is set internally for legal conversions. - Flags dupf = f.dup().remove(Flags.UPPERCASE); - sb.append(dupf.toString()); + sb.append(Flags.toString(Flags.remove(flags, Flags.UPPERCASE))); if (index > 0) sb.append(index).append('$'); if (width != -1) @@ -3198,21 +3208,21 @@ public final class Formatter implements Closeable, Flushable { if (precision != -1) sb.append('.').append(precision); if (dt) - sb.append(f.contains(Flags.UPPERCASE) ? 'T' : 't'); - sb.append(f.contains(Flags.UPPERCASE) + sb.append(Flags.contains(flags, Flags.UPPERCASE) ? 'T' : 't'); + sb.append(Flags.contains(flags, Flags.UPPERCASE) ? Character.toUpperCase(c) : c); return sb.toString(); } private void checkGeneral() { if ((c == Conversion.BOOLEAN || c == Conversion.HASHCODE) - && f.contains(Flags.ALTERNATE)) + && Flags.contains(flags, Flags.ALTERNATE)) failMismatch(Flags.ALTERNATE, c); // '-' requires a width - if (width == -1 && f.contains(Flags.LEFT_JUSTIFY)) + if (width == -1 && Flags.contains(flags, Flags.LEFT_JUSTIFY)) throw new MissingFormatWidthException(toString()); - checkBadFlags(Flags.PLUS, Flags.LEADING_SPACE, Flags.ZERO_PAD, - Flags.GROUP, Flags.PARENTHESES); + checkBadFlags(Flags.PLUS | Flags.LEADING_SPACE | Flags.ZERO_PAD | + Flags.GROUP | Flags.PARENTHESES); } private void checkDateTime() { @@ -3220,20 +3230,20 @@ public final class Formatter implements Closeable, Flushable { throw new IllegalFormatPrecisionException(precision); if (!DateTime.isValid(c)) throw new UnknownFormatConversionException("t" + c); - checkBadFlags(Flags.ALTERNATE, Flags.PLUS, Flags.LEADING_SPACE, - Flags.ZERO_PAD, Flags.GROUP, Flags.PARENTHESES); + checkBadFlags(Flags.ALTERNATE | Flags.PLUS | Flags.LEADING_SPACE | + Flags.ZERO_PAD | Flags.GROUP | Flags.PARENTHESES); // '-' requires a width - if (width == -1 && f.contains(Flags.LEFT_JUSTIFY)) + if (width == -1 && Flags.contains(flags, Flags.LEFT_JUSTIFY)) throw new MissingFormatWidthException(toString()); } private void checkCharacter() { if (precision != -1) throw new IllegalFormatPrecisionException(precision); - checkBadFlags(Flags.ALTERNATE, Flags.PLUS, Flags.LEADING_SPACE, - Flags.ZERO_PAD, Flags.GROUP, Flags.PARENTHESES); + checkBadFlags(Flags.ALTERNATE | Flags.PLUS | Flags.LEADING_SPACE | + Flags.ZERO_PAD | Flags.GROUP | Flags.PARENTHESES); // '-' requires a width - if (width == -1 && f.contains(Flags.LEFT_JUSTIFY)) + if (width == -1 && Flags.contains(flags, Flags.LEFT_JUSTIFY)) throw new MissingFormatWidthException(toString()); } @@ -3250,17 +3260,17 @@ public final class Formatter implements Closeable, Flushable { checkBadFlags(Flags.GROUP); } - private void checkBadFlags(Flags ... badFlags) { - for (Flags badFlag : badFlags) - if (f.contains(badFlag)) - failMismatch(badFlag, c); + private void checkBadFlags(int badFlags) { + if ((flags & badFlags) != 0) { + failMismatch(flags & badFlags, c); + } } private void checkFloat() { checkNumeric(); if (c == Conversion.DECIMAL_FLOAT) { } else if (c == Conversion.HEXADECIMAL_FLOAT) { - checkBadFlags(Flags.PARENTHESES, Flags.GROUP); + checkBadFlags(Flags.PARENTHESES | Flags.GROUP); } else if (c == Conversion.SCIENTIFIC) { checkBadFlags(Flags.GROUP); } else if (c == Conversion.GENERAL) { @@ -3277,13 +3287,13 @@ public final class Formatter implements Closeable, Flushable { // '-' and '0' require a width if (width == -1 - && (f.contains(Flags.LEFT_JUSTIFY) || f.contains(Flags.ZERO_PAD))) + && (Flags.containsAny(flags, Flags.LEFT_JUSTIFY | Flags.ZERO_PAD))) throw new MissingFormatWidthException(toString()); // bad combination - if ((f.contains(Flags.PLUS) && f.contains(Flags.LEADING_SPACE)) - || (f.contains(Flags.LEFT_JUSTIFY) && f.contains(Flags.ZERO_PAD))) - throw new IllegalFormatFlagsException(f.toString()); + if ((Flags.contains(flags, Flags.PLUS | Flags.LEADING_SPACE)) + || (Flags.contains(flags, Flags.LEFT_JUSTIFY | Flags.ZERO_PAD))) + throw new IllegalFormatFlagsException(Flags.toString(flags)); } private void checkText() { @@ -3291,35 +3301,35 @@ public final class Formatter implements Closeable, Flushable { throw new IllegalFormatPrecisionException(precision); switch (c) { case Conversion.PERCENT_SIGN: - if (f.valueOf() != Flags.LEFT_JUSTIFY.valueOf() - && f.valueOf() != Flags.NONE.valueOf()) - throw new IllegalFormatFlagsException(f.toString()); + if (flags != Flags.LEFT_JUSTIFY + && flags != Flags.NONE) + throw new IllegalFormatFlagsException(Flags.toString(flags)); // '-' requires a width - if (width == -1 && f.contains(Flags.LEFT_JUSTIFY)) + if (width == -1 && Flags.contains(flags, Flags.LEFT_JUSTIFY)) throw new MissingFormatWidthException(toString()); break; case Conversion.LINE_SEPARATOR: if (width != -1) throw new IllegalFormatWidthException(width); - if (f.valueOf() != Flags.NONE.valueOf()) - throw new IllegalFormatFlagsException(f.toString()); + if (flags != Flags.NONE) + throw new IllegalFormatFlagsException(Flags.toString(flags)); break; default: assert false; } } - private void print(byte value, Locale l) throws IOException { + private void print(Formatter fmt, byte value, Locale l) throws IOException { long v = value; if (value < 0 && (c == Conversion.OCTAL_INTEGER || c == Conversion.HEXADECIMAL_INTEGER)) { v += (1L << 8); } - print(v, l); + print(fmt, v, l); } - private void print(short value, Locale l) throws IOException { + private void print(Formatter fmt, short value, Locale l) throws IOException { long v = value; if (value < 0 && (c == Conversion.OCTAL_INTEGER @@ -3327,10 +3337,10 @@ public final class Formatter implements Closeable, Flushable { v += (1L << 16); assert v >= 0 : v; } - print(v, l); + print(fmt, v, l); } - private void print(int value, Locale l) throws IOException { + private void print(Formatter fmt, int value, Locale l) throws IOException { long v = value; if (value < 0 && (c == Conversion.OCTAL_INTEGER @@ -3338,10 +3348,10 @@ public final class Formatter implements Closeable, Flushable { v += (1L << 32); assert v >= 0 : v; } - print(v, l); + print(fmt, v, l); } - private void print(long value, Locale l) throws IOException { + private void print(Formatter fmt, long value, Locale l) throws IOException { StringBuilder sb = new StringBuilder(); @@ -3353,58 +3363,56 @@ public final class Formatter implements Closeable, Flushable { leadingSign(sb, neg); // the value - localizedMagnitude(sb, valueStr, neg ? 1 : 0, f, adjustWidth(width, f, neg), l); + localizedMagnitude(fmt, sb, valueStr, neg ? 1 : 0, flags, adjustWidth(width, flags, neg), l); // trailing sign indicator trailingSign(sb, neg); } else if (c == Conversion.OCTAL_INTEGER) { - checkBadFlags(Flags.PARENTHESES, Flags.LEADING_SPACE, - Flags.PLUS); + checkBadFlags(Flags.PARENTHESES | Flags.LEADING_SPACE | Flags.PLUS); String s = Long.toOctalString(value); - int len = (f.contains(Flags.ALTERNATE) + int len = (Flags.contains(flags, Flags.ALTERNATE) ? s.length() + 1 : s.length()); // apply ALTERNATE (radix indicator for octal) before ZERO_PAD - if (f.contains(Flags.ALTERNATE)) + if (Flags.contains(flags, Flags.ALTERNATE)) sb.append('0'); - if (f.contains(Flags.ZERO_PAD)) { + if (Flags.contains(flags, Flags.ZERO_PAD)) { trailingZeros(sb, width - len); } sb.append(s); } else if (c == Conversion.HEXADECIMAL_INTEGER) { - checkBadFlags(Flags.PARENTHESES, Flags.LEADING_SPACE, - Flags.PLUS); + checkBadFlags(Flags.PARENTHESES | Flags.LEADING_SPACE | Flags.PLUS); String s = Long.toHexString(value); - int len = (f.contains(Flags.ALTERNATE) + int len = (Flags.contains(flags, Flags.ALTERNATE) ? s.length() + 2 : s.length()); // apply ALTERNATE (radix indicator for hex) before ZERO_PAD - if (f.contains(Flags.ALTERNATE)) - sb.append(f.contains(Flags.UPPERCASE) ? "0X" : "0x"); - if (f.contains(Flags.ZERO_PAD)) { + if (Flags.contains(flags, Flags.ALTERNATE)) + sb.append(Flags.contains(flags, Flags.UPPERCASE) ? "0X" : "0x"); + if (Flags.contains(flags, Flags.ZERO_PAD)) { trailingZeros(sb, width - len); } - if (f.contains(Flags.UPPERCASE)) + if (Flags.contains(flags, Flags.UPPERCASE)) s = toUpperCaseWithLocale(s, l); sb.append(s); } // justify based on width - appendJustified(a, sb); + appendJustified(fmt.a, sb); } // neg := val < 0 private StringBuilder leadingSign(StringBuilder sb, boolean neg) { if (!neg) { - if (f.contains(Flags.PLUS)) { + if (Flags.contains(flags, Flags.PLUS)) { sb.append('+'); - } else if (f.contains(Flags.LEADING_SPACE)) { + } else if (Flags.contains(flags, Flags.LEADING_SPACE)) { sb.append(' '); } } else { - if (f.contains(Flags.PARENTHESES)) + if (Flags.contains(flags, Flags.PARENTHESES)) sb.append('('); else sb.append('-'); @@ -3414,12 +3422,12 @@ public final class Formatter implements Closeable, Flushable { // neg := val < 0 private StringBuilder trailingSign(StringBuilder sb, boolean neg) { - if (neg && f.contains(Flags.PARENTHESES)) + if (neg && Flags.contains(flags, Flags.PARENTHESES)) sb.append(')'); return sb; } - private void print(BigInteger value, Locale l) throws IOException { + private void print(Formatter fmt, BigInteger value, Locale l) throws IOException { StringBuilder sb = new StringBuilder(); boolean neg = value.signum() == -1; BigInteger v = value.abs(); @@ -3429,20 +3437,20 @@ public final class Formatter implements Closeable, Flushable { // the value if (c == Conversion.DECIMAL_INTEGER) { - localizedMagnitude(sb, v.toString(), 0, f, adjustWidth(width, f, neg), l); + localizedMagnitude(fmt, sb, v.toString(), 0, flags, adjustWidth(width, flags, neg), l); } else if (c == Conversion.OCTAL_INTEGER) { String s = v.toString(8); int len = s.length() + sb.length(); - if (neg && f.contains(Flags.PARENTHESES)) + if (neg && Flags.contains(flags, Flags.PARENTHESES)) len++; // apply ALTERNATE (radix indicator for octal) before ZERO_PAD - if (f.contains(Flags.ALTERNATE)) { + if (Flags.contains(flags, Flags.ALTERNATE)) { len++; sb.append('0'); } - if (f.contains(Flags.ZERO_PAD)) { + if (Flags.contains(flags, Flags.ZERO_PAD)) { trailingZeros(sb, width - len); } sb.append(s); @@ -3450,18 +3458,18 @@ public final class Formatter implements Closeable, Flushable { String s = v.toString(16); int len = s.length() + sb.length(); - if (neg && f.contains(Flags.PARENTHESES)) + if (neg && Flags.contains(flags, Flags.PARENTHESES)) len++; // apply ALTERNATE (radix indicator for hex) before ZERO_PAD - if (f.contains(Flags.ALTERNATE)) { + if (Flags.contains(flags, Flags.ALTERNATE)) { len += 2; - sb.append(f.contains(Flags.UPPERCASE) ? "0X" : "0x"); + sb.append(Flags.contains(flags, Flags.UPPERCASE) ? "0X" : "0x"); } - if (f.contains(Flags.ZERO_PAD)) { + if (Flags.contains(flags, Flags.ZERO_PAD)) { trailingZeros(sb, width - len); } - if (f.contains(Flags.UPPERCASE)) + if (Flags.contains(flags, Flags.UPPERCASE)) s = toUpperCaseWithLocale(s, l); sb.append(s); } @@ -3470,14 +3478,14 @@ public final class Formatter implements Closeable, Flushable { trailingSign(sb, (value.signum() == -1)); // justify based on width - appendJustified(a, sb); + appendJustified(fmt.a, sb); } - private void print(float value, Locale l) throws IOException { - print((double) value, l); + private void print(Formatter fmt, float value, Locale l) throws IOException { + print(fmt, (double) value, l); } - private void print(double value, Locale l) throws IOException { + private void print(Formatter fmt, double value, Locale l) throws IOException { StringBuilder sb = new StringBuilder(); boolean neg = Double.compare(value, 0.0) == -1; @@ -3489,24 +3497,24 @@ public final class Formatter implements Closeable, Flushable { // the value if (!Double.isInfinite(v)) - print(sb, v, l, f, c, precision, neg); + print(fmt, sb, v, l, flags, c, precision, neg); else - sb.append(f.contains(Flags.UPPERCASE) + sb.append(Flags.contains(flags, Flags.UPPERCASE) ? "INFINITY" : "Infinity"); // trailing sign indicator trailingSign(sb, neg); } else { - sb.append(f.contains(Flags.UPPERCASE) ? "NAN" : "NaN"); + sb.append(Flags.contains(flags, Flags.UPPERCASE) ? "NAN" : "NaN"); } // justify based on width - appendJustified(a, sb); + appendJustified(fmt.a, sb); } // !Double.isInfinite(value) && !Double.isNaN(value) - private void print(StringBuilder sb, double value, Locale l, - Flags f, char c, int precision, boolean neg) + private void print(Formatter fmt, StringBuilder sb, double value, Locale l, + int flags, char c, int precision, boolean neg) throws IOException { if (c == Conversion.SCIENTIFIC) { @@ -3523,7 +3531,7 @@ public final class Formatter implements Closeable, Flushable { // If the precision is zero and the '#' flag is set, add the // requested decimal point. - if (f.contains(Flags.ALTERNATE) && (prec == 0)) { + if (Flags.contains(flags, Flags.ALTERNATE) && (prec == 0)) { mant.append('.'); } @@ -3532,17 +3540,17 @@ public final class Formatter implements Closeable, Flushable { int newW = width; if (width != -1) { - newW = adjustWidth(width - exp.length - 1, f, neg); + newW = adjustWidth(width - exp.length - 1, flags, neg); } - localizedMagnitude(sb, mant, 0, f, newW, l); + localizedMagnitude(fmt, sb, mant, 0, flags, newW, l); - sb.append(f.contains(Flags.UPPERCASE) ? 'E' : 'e'); + sb.append(Flags.contains(flags, Flags.UPPERCASE) ? 'E' : 'e'); char sign = exp[0]; assert(sign == '+' || sign == '-'); sb.append(sign); - localizedMagnitudeExp(sb, exp, 1, l); + localizedMagnitudeExp(fmt, sb, exp, 1, l); } else if (c == Conversion.DECIMAL_FLOAT) { // Create a new FormattedFloatingDecimal with the desired // precision. @@ -3557,13 +3565,13 @@ public final class Formatter implements Closeable, Flushable { // If the precision is zero and the '#' flag is set, add the // requested decimal point. - if (f.contains(Flags.ALTERNATE) && (prec == 0)) + if (Flags.contains(flags, Flags.ALTERNATE) && (prec == 0)) mant.append('.'); int newW = width; if (width != -1) - newW = adjustWidth(width, f, neg); - localizedMagnitude(sb, mant, 0, f, newW, l); + newW = adjustWidth(width, flags, neg); + localizedMagnitude(fmt, sb, mant, 0, flags, newW, l); } else if (c == Conversion.GENERAL) { int prec = precision; if (precision == -1) @@ -3596,27 +3604,27 @@ public final class Formatter implements Closeable, Flushable { addZeros(mant, prec); // If the precision is zero and the '#' flag is set, add the // requested decimal point. - if (f.contains(Flags.ALTERNATE) && (prec == 0)) { + if (Flags.contains(flags, Flags.ALTERNATE) && (prec == 0)) { mant.append('.'); } int newW = width; if (width != -1) { if (exp != null) - newW = adjustWidth(width - exp.length - 1, f, neg); + newW = adjustWidth(width - exp.length - 1, flags, neg); else - newW = adjustWidth(width, f, neg); + newW = adjustWidth(width, flags, neg); } - localizedMagnitude(sb, mant, 0, f, newW, l); + localizedMagnitude(fmt, sb, mant, 0, flags, newW, l); if (exp != null) { - sb.append(f.contains(Flags.UPPERCASE) ? 'E' : 'e'); + sb.append(Flags.contains(flags, Flags.UPPERCASE) ? 'E' : 'e'); char sign = exp[0]; assert(sign == '+' || sign == '-'); sb.append(sign); - localizedMagnitudeExp(sb, exp, 1, l); + localizedMagnitudeExp(fmt, sb, exp, 1, l); } } else if (c == Conversion.HEXADECIMAL_FLOAT) { int prec = precision; @@ -3629,13 +3637,13 @@ public final class Formatter implements Closeable, Flushable { String s = hexDouble(value, prec); StringBuilder va = new StringBuilder(); - boolean upper = f.contains(Flags.UPPERCASE); + boolean upper = Flags.contains(flags, Flags.UPPERCASE); sb.append(upper ? "0X" : "0x"); - if (f.contains(Flags.ZERO_PAD)) { + if (Flags.contains(flags, Flags.ZERO_PAD)) { int leadingCharacters = 2; - if(f.contains(Flags.LEADING_SPACE) || - f.contains(Flags.PLUS) || neg) { + if(Flags.contains(flags, Flags.LEADING_SPACE) || + Flags.contains(flags, Flags.PLUS) || neg) { leadingCharacters = 3; } trailingZeros(sb, width - s.length() - leadingCharacters); @@ -3774,7 +3782,7 @@ public final class Formatter implements Closeable, Flushable { } } - private void print(BigDecimal value, Locale l) throws IOException { + private void print(Formatter fmt, BigDecimal value, Locale l) throws IOException { if (c == Conversion.HEXADECIMAL_FLOAT) failConversion(c, value); StringBuilder sb = new StringBuilder(); @@ -3784,18 +3792,18 @@ public final class Formatter implements Closeable, Flushable { leadingSign(sb, neg); // the value - print(sb, v, l, f, c, precision, neg); + print(fmt, sb, v, l, flags, c, precision, neg); // trailing sign indicator trailingSign(sb, neg); // justify based on width - appendJustified(a, sb); + appendJustified(fmt.a, sb); } // value > 0 - private void print(StringBuilder sb, BigDecimal value, Locale l, - Flags f, char c, int precision, boolean neg) + private void print(Formatter fmt, StringBuilder sb, BigDecimal value, Locale l, + int flags, char c, int precision, boolean neg) throws IOException { if (c == Conversion.SCIENTIFIC) { @@ -3829,7 +3837,7 @@ public final class Formatter implements Closeable, Flushable { // precision is one. Append a decimal point if '#' is set or if // we require zero padding to get to the requested precision. if ((origPrec == 1 || !bdl.hasDot()) - && (nzeros > 0 || (f.contains(Flags.ALTERNATE)))) { + && (nzeros > 0 || (Flags.contains(flags, Flags.ALTERNATE)))) { mant.append('.'); } @@ -3840,18 +3848,18 @@ public final class Formatter implements Closeable, Flushable { StringBuilder exp = bdl.exponent(); int newW = width; if (width != -1) { - newW = adjustWidth(width - exp.length() - 1, f, neg); + newW = adjustWidth(width - exp.length() - 1, flags, neg); } - localizedMagnitude(sb, mant, 0, f, newW, l); + localizedMagnitude(fmt, sb, mant, 0, flags, newW, l); - sb.append(f.contains(Flags.UPPERCASE) ? 'E' : 'e'); + sb.append(Flags.contains(flags, Flags.UPPERCASE) ? 'E' : 'e'); - Flags flags = f.dup().remove(Flags.GROUP); + int adaptedFlags = Flags.remove(flags, Flags.GROUP); char sign = exp.charAt(0); assert(sign == '+' || sign == '-'); sb.append(sign); - sb.append(localizedMagnitude(null, exp, 1, flags, -1, l)); + sb.append(localizedMagnitude(fmt, null, exp, 1, adaptedFlags, -1, l)); } else if (c == Conversion.DECIMAL_FLOAT) { // Create a new BigDecimal with the desired precision. int prec = (precision == -1 ? 6 : precision); @@ -3883,7 +3891,7 @@ public final class Formatter implements Closeable, Flushable { // representation has no fractional part). Append a decimal // point if '#' is set or we require zero padding to get to the // requested precision. - if (bdl.scale() == 0 && (f.contains(Flags.ALTERNATE) + if (bdl.scale() == 0 && (Flags.contains(flags, Flags.ALTERNATE) || nzeros > 0)) { mant.append('.'); } @@ -3892,7 +3900,7 @@ public final class Formatter implements Closeable, Flushable { // number of available digits after the decimal separator. trailingZeros(mant, nzeros); - localizedMagnitude(sb, mant, 0, f, adjustWidth(width, f, neg), l); + localizedMagnitude(fmt, sb, mant, 0, flags, adjustWidth(width, flags, neg), l); } else if (c == Conversion.GENERAL) { int prec = precision; if (precision == -1) @@ -3920,10 +3928,10 @@ public final class Formatter implements Closeable, Flushable { // => f precision = g precision - exponent - 1 prec = prec - e - 1; - print(sb, value, l, f, Conversion.DECIMAL_FLOAT, prec, + print(fmt, sb, value, l, flags, Conversion.DECIMAL_FLOAT, prec, neg); } else { - print(sb, value, l, f, Conversion.SCIENTIFIC, prec - 1, neg); + print(fmt, sb, value, l, flags, Conversion.SCIENTIFIC, prec - 1, neg); } } else if (c == Conversion.HEXADECIMAL_FLOAT) { // This conversion isn't supported. The error should be @@ -4045,9 +4053,9 @@ public final class Formatter implements Closeable, Flushable { } } - private int adjustWidth(int width, Flags f, boolean neg) { + private int adjustWidth(int width, int flags, boolean neg) { int newW = width; - if (newW != -1 && neg && f.contains(Flags.PARENTHESES)) + if (newW != -1 && neg && Flags.contains(flags, Flags.PARENTHESES)) newW--; return newW; } @@ -4059,19 +4067,19 @@ public final class Formatter implements Closeable, Flushable { } } - private void print(Calendar t, char c, Locale l) throws IOException { + private void print(Formatter fmt, Calendar t, char c, Locale l) throws IOException { StringBuilder sb = new StringBuilder(); - print(sb, t, c, l); + print(fmt, sb, t, c, l); // justify based on width - if (f.contains(Flags.UPPERCASE)) { - appendJustified(a, toUpperCaseWithLocale(sb.toString(), l)); + if (Flags.contains(flags, Flags.UPPERCASE)) { + appendJustified(fmt.a, toUpperCaseWithLocale(sb.toString(), l)); } else { - appendJustified(a, sb); + appendJustified(fmt.a, sb); } } - private Appendable print(StringBuilder sb, Calendar t, char c, Locale l) + private Appendable print(Formatter fmt, StringBuilder sb, Calendar t, char c, Locale l) throws IOException { if (sb == null) sb = new StringBuilder(); @@ -4083,35 +4091,31 @@ public final class Formatter implements Closeable, Flushable { int i = t.get(Calendar.HOUR_OF_DAY); if (c == DateTime.HOUR_0 || c == DateTime.HOUR) i = (i == 0 || i == 12 ? 12 : i % 12); - Flags flags = (c == DateTime.HOUR_OF_DAY_0 + int flags = (c == DateTime.HOUR_OF_DAY_0 || c == DateTime.HOUR_0 ? Flags.ZERO_PAD : Flags.NONE); - sb.append(localizedMagnitude(null, i, flags, 2, l)); + sb.append(localizedMagnitude(fmt, null, i, flags, 2, l)); break; } case DateTime.MINUTE: { // 'M' (00 - 59) int i = t.get(Calendar.MINUTE); - Flags flags = Flags.ZERO_PAD; - sb.append(localizedMagnitude(null, i, flags, 2, l)); + sb.append(localizedMagnitude(fmt, null, i, Flags.ZERO_PAD, 2, l)); break; } case DateTime.NANOSECOND: { // 'N' (000000000 - 999999999) int i = t.get(Calendar.MILLISECOND) * 1000000; - Flags flags = Flags.ZERO_PAD; - sb.append(localizedMagnitude(null, i, flags, 9, l)); + sb.append(localizedMagnitude(fmt, null, i, Flags.ZERO_PAD, 9, l)); break; } case DateTime.MILLISECOND: { // 'L' (000 - 999) int i = t.get(Calendar.MILLISECOND); - Flags flags = Flags.ZERO_PAD; - sb.append(localizedMagnitude(null, i, flags, 3, l)); + sb.append(localizedMagnitude(fmt, null, i, Flags.ZERO_PAD, 3, l)); break; } case DateTime.MILLISECOND_SINCE_EPOCH: { // 'Q' (0 - 99...?) long i = t.getTimeInMillis(); - Flags flags = Flags.NONE; - sb.append(localizedMagnitude(null, i, flags, width, l)); + sb.append(localizedMagnitude(fmt, null, i, Flags.NONE, width, l)); break; } case DateTime.AM_PM: { // 'p' (am or pm) @@ -4128,14 +4132,12 @@ public final class Formatter implements Closeable, Flushable { } case DateTime.SECONDS_SINCE_EPOCH: { // 's' (0 - 99...?) long i = t.getTimeInMillis() / 1000; - Flags flags = Flags.NONE; - sb.append(localizedMagnitude(null, i, flags, width, l)); + sb.append(localizedMagnitude(fmt, null, i, Flags.NONE, width, l)); break; } case DateTime.SECOND: { // 'S' (00 - 60 - leap second) int i = t.get(Calendar.SECOND); - Flags flags = Flags.ZERO_PAD; - sb.append(localizedMagnitude(null, i, flags, 2, l)); + sb.append(localizedMagnitude(fmt, null, i, Flags.ZERO_PAD, 2, l)); break; } case DateTime.ZONE_NUMERIC: { // 'z' ({-|+}####) - ls minus? @@ -4147,9 +4149,8 @@ public final class Formatter implements Closeable, Flushable { int min = i / 60000; // combine minute and hour into a single integer int offset = (min / 60) * 100 + (min % 60); - Flags flags = Flags.ZERO_PAD; - sb.append(localizedMagnitude(null, offset, flags, 4, l)); + sb.append(localizedMagnitude(fmt, null, offset, Flags.ZERO_PAD, 4, l)); break; } case DateTime.ZONE: { // 'Z' (symbol) @@ -4194,29 +4195,26 @@ public final class Formatter implements Closeable, Flushable { case DateTime.YEAR_2 -> i %= 100; case DateTime.YEAR_4 -> size = 4; } - Flags flags = Flags.ZERO_PAD; - sb.append(localizedMagnitude(null, i, flags, size, l)); + sb.append(localizedMagnitude(fmt, null, i, Flags.ZERO_PAD, size, l)); break; } case DateTime.DAY_OF_MONTH_0: // 'd' (01 - 31) case DateTime.DAY_OF_MONTH: { // 'e' (1 - 31) -- like d int i = t.get(Calendar.DATE); - Flags flags = (c == DateTime.DAY_OF_MONTH_0 + int flags = (c == DateTime.DAY_OF_MONTH_0 ? Flags.ZERO_PAD : Flags.NONE); - sb.append(localizedMagnitude(null, i, flags, 2, l)); + sb.append(localizedMagnitude(fmt, null, i, flags, 2, l)); break; } case DateTime.DAY_OF_YEAR: { // 'j' (001 - 366) int i = t.get(Calendar.DAY_OF_YEAR); - Flags flags = Flags.ZERO_PAD; - sb.append(localizedMagnitude(null, i, flags, 3, l)); + sb.append(localizedMagnitude(fmt, null, i, Flags.ZERO_PAD, 3, l)); break; } case DateTime.MONTH: { // 'm' (01 - 12) int i = t.get(Calendar.MONTH) + 1; - Flags flags = Flags.ZERO_PAD; - sb.append(localizedMagnitude(null, i, flags, 2, l)); + sb.append(localizedMagnitude(fmt, null, i, Flags.ZERO_PAD, 2, l)); break; } @@ -4224,48 +4222,48 @@ public final class Formatter implements Closeable, Flushable { case DateTime.TIME: // 'T' (24 hour hh:mm:ss - %tH:%tM:%tS) case DateTime.TIME_24_HOUR: { // 'R' (hh:mm same as %H:%M) char sep = ':'; - print(sb, t, DateTime.HOUR_OF_DAY_0, l).append(sep); - print(sb, t, DateTime.MINUTE, l); + print(fmt, sb, t, DateTime.HOUR_OF_DAY_0, l).append(sep); + print(fmt, sb, t, DateTime.MINUTE, l); if (c == DateTime.TIME) { sb.append(sep); - print(sb, t, DateTime.SECOND, l); + print(fmt, sb, t, DateTime.SECOND, l); } break; } case DateTime.TIME_12_HOUR: { // 'r' (hh:mm:ss [AP]M) char sep = ':'; - print(sb, t, DateTime.HOUR_0, l).append(sep); - print(sb, t, DateTime.MINUTE, l).append(sep); - print(sb, t, DateTime.SECOND, l).append(' '); + print(fmt, sb, t, DateTime.HOUR_0, l).append(sep); + print(fmt, sb, t, DateTime.MINUTE, l).append(sep); + print(fmt, sb, t, DateTime.SECOND, l).append(' '); // this may be in wrong place for some locales StringBuilder tsb = new StringBuilder(); - print(tsb, t, DateTime.AM_PM, l); + print(fmt, tsb, t, DateTime.AM_PM, l); sb.append(toUpperCaseWithLocale(tsb.toString(), l)); break; } case DateTime.DATE_TIME: { // 'c' (Sat Nov 04 12:02:33 EST 1999) char sep = ' '; - print(sb, t, DateTime.NAME_OF_DAY_ABBREV, l).append(sep); - print(sb, t, DateTime.NAME_OF_MONTH_ABBREV, l).append(sep); - print(sb, t, DateTime.DAY_OF_MONTH_0, l).append(sep); - print(sb, t, DateTime.TIME, l).append(sep); - print(sb, t, DateTime.ZONE, l).append(sep); - print(sb, t, DateTime.YEAR_4, l); + print(fmt, sb, t, DateTime.NAME_OF_DAY_ABBREV, l).append(sep); + print(fmt, sb, t, DateTime.NAME_OF_MONTH_ABBREV, l).append(sep); + print(fmt, sb, t, DateTime.DAY_OF_MONTH_0, l).append(sep); + print(fmt, sb, t, DateTime.TIME, l).append(sep); + print(fmt, sb, t, DateTime.ZONE, l).append(sep); + print(fmt, sb, t, DateTime.YEAR_4, l); break; } case DateTime.DATE: { // 'D' (mm/dd/yy) char sep = '/'; - print(sb, t, DateTime.MONTH, l).append(sep); - print(sb, t, DateTime.DAY_OF_MONTH_0, l).append(sep); - print(sb, t, DateTime.YEAR_2, l); + print(fmt, sb, t, DateTime.MONTH, l).append(sep); + print(fmt, sb, t, DateTime.DAY_OF_MONTH_0, l).append(sep); + print(fmt, sb, t, DateTime.YEAR_2, l); break; } case DateTime.ISO_STANDARD_DATE: { // 'F' (%Y-%m-%d) char sep = '-'; - print(sb, t, DateTime.YEAR_4, l).append(sep); - print(sb, t, DateTime.MONTH, l).append(sep); - print(sb, t, DateTime.DAY_OF_MONTH_0, l); + print(fmt, sb, t, DateTime.YEAR_4, l).append(sep); + print(fmt, sb, t, DateTime.MONTH, l).append(sep); + print(fmt, sb, t, DateTime.DAY_OF_MONTH_0, l); break; } default: @@ -4274,18 +4272,18 @@ public final class Formatter implements Closeable, Flushable { return sb; } - private void print(TemporalAccessor t, char c, Locale l) throws IOException { + private void print(Formatter fmt, TemporalAccessor t, char c, Locale l) throws IOException { StringBuilder sb = new StringBuilder(); - print(sb, t, c, l); + print(fmt, sb, t, c, l); // justify based on width - if (f.contains(Flags.UPPERCASE)) { - appendJustified(a, toUpperCaseWithLocale(sb.toString(), l)); + if (Flags.contains(flags, Flags.UPPERCASE)) { + appendJustified(fmt.a, toUpperCaseWithLocale(sb.toString(), l)); } else { - appendJustified(a, sb); + appendJustified(fmt.a, sb); } } - private Appendable print(StringBuilder sb, TemporalAccessor t, char c, + private Appendable print(Formatter fmt, StringBuilder sb, TemporalAccessor t, char c, Locale l) throws IOException { if (sb == null) sb = new StringBuilder(); @@ -4293,28 +4291,27 @@ public final class Formatter implements Closeable, Flushable { switch (c) { case DateTime.HOUR_OF_DAY_0: { // 'H' (00 - 23) int i = t.get(ChronoField.HOUR_OF_DAY); - sb.append(localizedMagnitude(null, i, Flags.ZERO_PAD, 2, l)); + sb.append(localizedMagnitude(fmt, null, i, Flags.ZERO_PAD, 2, l)); break; } case DateTime.HOUR_OF_DAY: { // 'k' (0 - 23) -- like H int i = t.get(ChronoField.HOUR_OF_DAY); - sb.append(localizedMagnitude(null, i, Flags.NONE, 2, l)); + sb.append(localizedMagnitude(fmt, null, i, Flags.NONE, 2, l)); break; } case DateTime.HOUR_0: { // 'I' (01 - 12) int i = t.get(ChronoField.CLOCK_HOUR_OF_AMPM); - sb.append(localizedMagnitude(null, i, Flags.ZERO_PAD, 2, l)); + sb.append(localizedMagnitude(fmt, null, i, Flags.ZERO_PAD, 2, l)); break; } case DateTime.HOUR: { // 'l' (1 - 12) -- like I int i = t.get(ChronoField.CLOCK_HOUR_OF_AMPM); - sb.append(localizedMagnitude(null, i, Flags.NONE, 2, l)); + sb.append(localizedMagnitude(fmt, null, i, Flags.NONE, 2, l)); break; } case DateTime.MINUTE: { // 'M' (00 - 59) int i = t.get(ChronoField.MINUTE_OF_HOUR); - Flags flags = Flags.ZERO_PAD; - sb.append(localizedMagnitude(null, i, flags, 2, l)); + sb.append(localizedMagnitude(fmt, null, i, Flags.ZERO_PAD, 2, l)); break; } case DateTime.NANOSECOND: { // 'N' (000000000 - 999999999) @@ -4324,21 +4321,18 @@ public final class Formatter implements Closeable, Flushable { } catch (UnsupportedTemporalTypeException u) { i = t.get(ChronoField.MILLI_OF_SECOND) * 1000000; } - Flags flags = Flags.ZERO_PAD; - sb.append(localizedMagnitude(null, i, flags, 9, l)); + sb.append(localizedMagnitude(fmt, null, i, Flags.ZERO_PAD, 9, l)); break; } case DateTime.MILLISECOND: { // 'L' (000 - 999) int i = t.get(ChronoField.MILLI_OF_SECOND); - Flags flags = Flags.ZERO_PAD; - sb.append(localizedMagnitude(null, i, flags, 3, l)); + sb.append(localizedMagnitude(fmt, null, i, Flags.ZERO_PAD, 3, l)); break; } case DateTime.MILLISECOND_SINCE_EPOCH: { // 'Q' (0 - 99...?) long i = t.getLong(ChronoField.INSTANT_SECONDS) * 1000L + t.getLong(ChronoField.MILLI_OF_SECOND); - Flags flags = Flags.NONE; - sb.append(localizedMagnitude(null, i, flags, width, l)); + sb.append(localizedMagnitude(fmt, null, i, Flags.NONE, width, l)); break; } case DateTime.AM_PM: { // 'p' (am or pm) @@ -4355,14 +4349,12 @@ public final class Formatter implements Closeable, Flushable { } case DateTime.SECONDS_SINCE_EPOCH: { // 's' (0 - 99...?) long i = t.getLong(ChronoField.INSTANT_SECONDS); - Flags flags = Flags.NONE; - sb.append(localizedMagnitude(null, i, flags, width, l)); + sb.append(localizedMagnitude(fmt, null, i, Flags.NONE, width, l)); break; } case DateTime.SECOND: { // 'S' (00 - 60 - leap second) int i = t.get(ChronoField.SECOND_OF_MINUTE); - Flags flags = Flags.ZERO_PAD; - sb.append(localizedMagnitude(null, i, flags, 2, l)); + sb.append(localizedMagnitude(fmt, null, i, Flags.ZERO_PAD, 2, l)); break; } case DateTime.ZONE_NUMERIC: { // 'z' ({-|+}####) - ls minus? @@ -4374,8 +4366,7 @@ public final class Formatter implements Closeable, Flushable { int min = i / 60; // combine minute and hour into a single integer int offset = (min / 60) * 100 + (min % 60); - Flags flags = Flags.ZERO_PAD; - sb.append(localizedMagnitude(null, offset, flags, 4, l)); + sb.append(localizedMagnitude(fmt, null, offset, Flags.ZERO_PAD, 4, l)); break; } case DateTime.ZONE: { // 'Z' (symbol) @@ -4429,29 +4420,26 @@ public final class Formatter implements Closeable, Flushable { case DateTime.YEAR_2 -> i %= 100; case DateTime.YEAR_4 -> size = 4; } - Flags flags = Flags.ZERO_PAD; - sb.append(localizedMagnitude(null, i, flags, size, l)); + sb.append(localizedMagnitude(fmt, null, i, Flags.ZERO_PAD, size, l)); break; } case DateTime.DAY_OF_MONTH_0: // 'd' (01 - 31) case DateTime.DAY_OF_MONTH: { // 'e' (1 - 31) -- like d int i = t.get(ChronoField.DAY_OF_MONTH); - Flags flags = (c == DateTime.DAY_OF_MONTH_0 + int flags = (c == DateTime.DAY_OF_MONTH_0 ? Flags.ZERO_PAD : Flags.NONE); - sb.append(localizedMagnitude(null, i, flags, 2, l)); + sb.append(localizedMagnitude(fmt, null, i, flags, 2, l)); break; } case DateTime.DAY_OF_YEAR: { // 'j' (001 - 366) int i = t.get(ChronoField.DAY_OF_YEAR); - Flags flags = Flags.ZERO_PAD; - sb.append(localizedMagnitude(null, i, flags, 3, l)); + sb.append(localizedMagnitude(fmt, null, i, Flags.ZERO_PAD, 3, l)); break; } case DateTime.MONTH: { // 'm' (01 - 12) int i = t.get(ChronoField.MONTH_OF_YEAR); - Flags flags = Flags.ZERO_PAD; - sb.append(localizedMagnitude(null, i, flags, 2, l)); + sb.append(localizedMagnitude(fmt, null, i, Flags.ZERO_PAD, 2, l)); break; } @@ -4459,47 +4447,47 @@ public final class Formatter implements Closeable, Flushable { case DateTime.TIME: // 'T' (24 hour hh:mm:ss - %tH:%tM:%tS) case DateTime.TIME_24_HOUR: { // 'R' (hh:mm same as %H:%M) char sep = ':'; - print(sb, t, DateTime.HOUR_OF_DAY_0, l).append(sep); - print(sb, t, DateTime.MINUTE, l); + print(fmt, sb, t, DateTime.HOUR_OF_DAY_0, l).append(sep); + print(fmt, sb, t, DateTime.MINUTE, l); if (c == DateTime.TIME) { sb.append(sep); - print(sb, t, DateTime.SECOND, l); + print(fmt, sb, t, DateTime.SECOND, l); } break; } case DateTime.TIME_12_HOUR: { // 'r' (hh:mm:ss [AP]M) char sep = ':'; - print(sb, t, DateTime.HOUR_0, l).append(sep); - print(sb, t, DateTime.MINUTE, l).append(sep); - print(sb, t, DateTime.SECOND, l).append(' '); + print(fmt, sb, t, DateTime.HOUR_0, l).append(sep); + print(fmt, sb, t, DateTime.MINUTE, l).append(sep); + print(fmt, sb, t, DateTime.SECOND, l).append(' '); // this may be in wrong place for some locales StringBuilder tsb = new StringBuilder(); - print(tsb, t, DateTime.AM_PM, l); + print(fmt, tsb, t, DateTime.AM_PM, l); sb.append(toUpperCaseWithLocale(tsb.toString(), l)); break; } case DateTime.DATE_TIME: { // 'c' (Sat Nov 04 12:02:33 EST 1999) char sep = ' '; - print(sb, t, DateTime.NAME_OF_DAY_ABBREV, l).append(sep); - print(sb, t, DateTime.NAME_OF_MONTH_ABBREV, l).append(sep); - print(sb, t, DateTime.DAY_OF_MONTH_0, l).append(sep); - print(sb, t, DateTime.TIME, l).append(sep); - print(sb, t, DateTime.ZONE, l).append(sep); - print(sb, t, DateTime.YEAR_4, l); + print(fmt, sb, t, DateTime.NAME_OF_DAY_ABBREV, l).append(sep); + print(fmt, sb, t, DateTime.NAME_OF_MONTH_ABBREV, l).append(sep); + print(fmt, sb, t, DateTime.DAY_OF_MONTH_0, l).append(sep); + print(fmt, sb, t, DateTime.TIME, l).append(sep); + print(fmt, sb, t, DateTime.ZONE, l).append(sep); + print(fmt, sb, t, DateTime.YEAR_4, l); break; } case DateTime.DATE: { // 'D' (mm/dd/yy) char sep = '/'; - print(sb, t, DateTime.MONTH, l).append(sep); - print(sb, t, DateTime.DAY_OF_MONTH_0, l).append(sep); - print(sb, t, DateTime.YEAR_2, l); + print(fmt, sb, t, DateTime.MONTH, l).append(sep); + print(fmt, sb, t, DateTime.DAY_OF_MONTH_0, l).append(sep); + print(fmt, sb, t, DateTime.YEAR_2, l); break; } case DateTime.ISO_STANDARD_DATE: { // 'F' (%Y-%m-%d) char sep = '-'; - print(sb, t, DateTime.YEAR_4, l).append(sep); - print(sb, t, DateTime.MONTH, l).append(sep); - print(sb, t, DateTime.DAY_OF_MONTH_0, l); + print(fmt, sb, t, DateTime.YEAR_4, l).append(sep); + print(fmt, sb, t, DateTime.MONTH, l).append(sep); + print(fmt, sb, t, DateTime.DAY_OF_MONTH_0, l); break; } default: @@ -4513,8 +4501,8 @@ public final class Formatter implements Closeable, Flushable { // -- Methods to support throwing exceptions -- - private void failMismatch(Flags f, char c) { - String fs = f.toString(); + private void failMismatch(int f, char c) { + String fs = Flags.toString(f); throw new FormatFlagsConversionMismatchException(fs, c); } @@ -4522,21 +4510,13 @@ public final class Formatter implements Closeable, Flushable { throw new IllegalFormatConversionException(c, arg.getClass()); } - private char getZero(Locale l) { - if ((l != null) && !l.equals(locale())) { - DecimalFormatSymbols dfs = DecimalFormatSymbols.getInstance(l); - return dfs.getZeroDigit(); - } - return zero(); - } - - private StringBuilder localizedMagnitude(StringBuilder sb, - long value, Flags f, int width, Locale l) { - return localizedMagnitude(sb, Long.toString(value, 10), 0, f, width, l); + private StringBuilder localizedMagnitude(Formatter fmt, StringBuilder sb, + long value, int flags, int width, Locale l) { + return localizedMagnitude(fmt, sb, Long.toString(value, 10), 0, flags, width, l); } - private StringBuilder localizedMagnitude(StringBuilder sb, - CharSequence value, final int offset, Flags f, int width, + private StringBuilder localizedMagnitude(Formatter fmt, StringBuilder sb, + CharSequence value, final int offset, int f, int width, Locale l) { if (sb == null) { sb = new StringBuilder(); @@ -4560,21 +4540,15 @@ public final class Formatter implements Closeable, Flushable { } if (dot < len) { - if (l == null || l.equals(Locale.US)) { - decSep = '.'; - } else { - DecimalFormatSymbols dfs = DecimalFormatSymbols.getInstance(l); - decSep = dfs.getDecimalSeparator(); - } + decSep = getDecimalSeparator(l); } - if (f.contains(Flags.GROUP)) { + if (Flags.contains(f, Flags.GROUP)) { + grpSep = getGroupingSeparator(l); + if (l == null || l.equals(Locale.US)) { - grpSep = ','; grpSize = 3; } else { - DecimalFormatSymbols dfs = DecimalFormatSymbols.getInstance(l); - grpSep = dfs.getGroupingSeparator(); DecimalFormat df = null; NumberFormat nf = NumberFormat.getNumberInstance(l); if (nf instanceof DecimalFormat) { @@ -4591,7 +4565,7 @@ public final class Formatter implements Closeable, Flushable { } String[] all = adapter.getLocaleResources(l) .getNumberPatterns(); - df = new DecimalFormat(all[0], dfs); + df = new DecimalFormat(all[0], getDecimalFormatSymbols(l)); } grpSize = df.getGroupingSize(); // Some locales do not use grouping (the number @@ -4622,7 +4596,7 @@ public final class Formatter implements Closeable, Flushable { } // apply zero padding - if (width != -1 && f.contains(Flags.ZERO_PAD)) { + if (width != -1 && Flags.contains(f, Flags.ZERO_PAD)) { for (int k = sb.length(); k < width; k++) { sb.insert(begin, zero); } @@ -4634,7 +4608,7 @@ public final class Formatter implements Closeable, Flushable { // Specialized localization of exponents, where the source value can only // contain characters '0' through '9', starting at index offset, and no // group separators is added for any locale. - private void localizedMagnitudeExp(StringBuilder sb, char[] value, + private void localizedMagnitudeExp(Formatter fmt, StringBuilder sb, char[] value, final int offset, Locale l) { char zero = getZero(l); @@ -4647,65 +4621,54 @@ public final class Formatter implements Closeable, Flushable { } private static class Flags { - private int flags; - static final Flags NONE = new Flags(0); // '' + static final int NONE = 0; // '' // duplicate declarations from Formattable.java - static final Flags LEFT_JUSTIFY = new Flags(1<<0); // '-' - static final Flags UPPERCASE = new Flags(1<<1); // '^' - static final Flags ALTERNATE = new Flags(1<<2); // '#' + static final int LEFT_JUSTIFY = 1<<0; // '-' + static final int UPPERCASE = 1<<1; // '^' + static final int ALTERNATE = 1<<2; // '#' // numerics - static final Flags PLUS = new Flags(1<<3); // '+' - static final Flags LEADING_SPACE = new Flags(1<<4); // ' ' - static final Flags ZERO_PAD = new Flags(1<<5); // '0' - static final Flags GROUP = new Flags(1<<6); // ',' - static final Flags PARENTHESES = new Flags(1<<7); // '(' + static final int PLUS = 1<<3; // '+' + static final int LEADING_SPACE = 1<<4; // ' ' + static final int ZERO_PAD = 1<<5; // '0' + static final int GROUP = 1<<6; // ',' + static final int PARENTHESES = 1<<7; // '(' // indexing - static final Flags PREVIOUS = new Flags(1<<8); // '<' + static final int PREVIOUS = 1<<8; // '<' - private Flags(int f) { - flags = f; + public static boolean contains(int flags, int f) { + return (flags & f) == f; } - public int valueOf() { - return flags; + public static boolean containsAny(int flags, int f) { + return (flags & f) != 0; } - public boolean contains(Flags f) { - return (flags & f.valueOf()) == f.valueOf(); + private static int add(int flags, int f) { + return flags | f; } - public Flags dup() { - return new Flags(flags); + public static int remove(int flags, int f) { + return flags & ~f; } - private Flags add(Flags f) { - flags |= f.valueOf(); - return this; - } - - public Flags remove(Flags f) { - flags &= ~f.valueOf(); - return this; - } - - public static Flags parse(String s, int start, int end) { - Flags f = new Flags(0); + public static int parse(String s, int start, int end) { + int f = 0; for (int i = start; i < end; i++) { char c = s.charAt(i); - Flags v = parse(c); - if (f.contains(v)) - throw new DuplicateFormatFlagsException(v.toString()); - f.add(v); + int v = parse(c); + if (contains(f, v)) + throw new DuplicateFormatFlagsException(toString(v)); + f = add(f, v); } return f; } // parse those flags which may be provided by users - private static Flags parse(char c) { + private static int parse(char c) { return switch (c) { case '-' -> LEFT_JUSTIFY; case '#' -> ALTERNATE; @@ -4720,21 +4683,17 @@ public final class Formatter implements Closeable, Flushable { } // Returns a string representation of the current {@code Flags}. - public static String toString(Flags f) { - return f.toString(); - } - - public String toString() { + public static String toString(int f) { StringBuilder sb = new StringBuilder(); - if (contains(LEFT_JUSTIFY)) sb.append('-'); - if (contains(UPPERCASE)) sb.append('^'); - if (contains(ALTERNATE)) sb.append('#'); - if (contains(PLUS)) sb.append('+'); - if (contains(LEADING_SPACE)) sb.append(' '); - if (contains(ZERO_PAD)) sb.append('0'); - if (contains(GROUP)) sb.append(','); - if (contains(PARENTHESES)) sb.append('('); - if (contains(PREVIOUS)) sb.append('<'); + if (contains(f, LEFT_JUSTIFY)) sb.append('-'); + if (contains(f, UPPERCASE)) sb.append('^'); + if (contains(f, ALTERNATE)) sb.append('#'); + if (contains(f, PLUS)) sb.append('+'); + if (contains(f, LEADING_SPACE)) sb.append(' '); + if (contains(f, ZERO_PAD)) sb.append('0'); + if (contains(f, GROUP)) sb.append(','); + if (contains(f, PARENTHESES)) sb.append('('); + if (contains(f, PREVIOUS)) sb.append('<'); return sb.toString(); } } diff --git a/src/java.base/share/classes/java/util/HashMap.java b/src/java.base/share/classes/java/util/HashMap.java index 24fcd9516ca475245ffb470f79849faa52eb14f4..997273aa104f1575ebe8d62273da59b6e35b0d16 100644 --- a/src/java.base/share/classes/java/util/HashMap.java +++ b/src/java.base/share/classes/java/util/HashMap.java @@ -495,9 +495,9 @@ public class HashMap extends AbstractMap int s = m.size(); if (s > 0) { if (table == null) { // pre-size - float ft = ((float)s / loadFactor) + 1.0F; - int t = ((ft < (float)MAXIMUM_CAPACITY) ? - (int)ft : MAXIMUM_CAPACITY); + double dt = Math.ceil(s / (double)loadFactor); + int t = ((dt < (double)MAXIMUM_CAPACITY) ? + (int)dt : MAXIMUM_CAPACITY); if (t > threshold) threshold = tableSizeFor(t); } else { @@ -1527,12 +1527,12 @@ public class HashMap extends AbstractMap } else if (mappings == 0) { // use defaults } else if (mappings > 0) { - float fc = (float)mappings / lf + 1.0f; - int cap = ((fc < DEFAULT_INITIAL_CAPACITY) ? + double dc = Math.ceil(mappings / (double)lf); + int cap = ((dc < DEFAULT_INITIAL_CAPACITY) ? DEFAULT_INITIAL_CAPACITY : - (fc >= MAXIMUM_CAPACITY) ? + (dc >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : - tableSizeFor((int)fc)); + tableSizeFor((int)dc)); float ft = (float)cap * lf; threshold = ((cap < MAXIMUM_CAPACITY && ft < MAXIMUM_CAPACITY) ? (int)ft : Integer.MAX_VALUE); diff --git a/src/java.base/share/classes/java/util/Hashtable.java b/src/java.base/share/classes/java/util/Hashtable.java index c103df557901fa506b4f829b25da578f59002a05..5d722879bc03f1633f8aa5444ff620978cad017f 100644 --- a/src/java.base/share/classes/java/util/Hashtable.java +++ b/src/java.base/share/classes/java/util/Hashtable.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 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 @@ -1254,7 +1254,7 @@ public class Hashtable * Reconstitute the Hashtable from a stream (i.e., deserialize it). */ @java.io.Serial - private void readObject(java.io.ObjectInputStream s) + private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException { readHashtable(s); } @@ -1263,14 +1263,16 @@ public class Hashtable * Perform deserialization of the Hashtable from an ObjectInputStream. * The Properties class overrides this method. */ - void readHashtable(java.io.ObjectInputStream s) + void readHashtable(ObjectInputStream s) throws IOException, ClassNotFoundException { - // Read in the threshold and loadFactor - s.defaultReadObject(); - // Validate loadFactor (ignore threshold - it will be re-computed) - if (loadFactor <= 0 || Float.isNaN(loadFactor)) - throw new StreamCorruptedException("Illegal Load: " + loadFactor); + ObjectInputStream.GetField fields = s.readFields(); + + // Read and validate loadFactor (ignore threshold - it will be re-computed) + float lf = fields.get("loadFactor", 0.75f); + if (lf <= 0 || Float.isNaN(lf)) + throw new StreamCorruptedException("Illegal load factor: " + lf); + lf = Math.min(Math.max(0.25f, lf), 4.0f); // Read the original length of the array and number of elements int origlength = s.readInt(); @@ -1282,13 +1284,13 @@ public class Hashtable // Clamp original length to be more than elements / loadFactor // (this is the invariant enforced with auto-growth) - origlength = Math.max(origlength, (int)(elements / loadFactor) + 1); + origlength = Math.max(origlength, (int)(elements / lf) + 1); // Compute new length with a bit of room 5% + 3 to grow but // no larger than the clamped original length. Make the length // odd if it's large enough, this helps distribute the entries. // Guard against the length ending up zero, that's not valid. - int length = (int)((elements + elements / 20) / loadFactor) + 3; + int length = (int)(elements * 1.05f / lf) + 3; if (length > elements && (length & 1) == 0) length--; length = Math.min(length, origlength); @@ -1300,8 +1302,9 @@ public class Hashtable // Check Map.Entry[].class since it's the nearest public type to // what we're actually creating. SharedSecrets.getJavaObjectInputStreamAccess().checkArray(s, Map.Entry[].class, length); + Hashtable.UnsafeHolder.putLoadFactor(this, lf); table = new Entry[length]; - threshold = (int)Math.min(length * loadFactor, MAX_ARRAY_SIZE + 1); + threshold = (int)Math.min(length * lf, MAX_ARRAY_SIZE + 1); count = 0; // Read the number of elements and then all the key/value objects @@ -1315,6 +1318,18 @@ public class Hashtable } } + // Support for resetting final field during deserializing + private static final class UnsafeHolder { + private UnsafeHolder() { throw new InternalError(); } + private static final jdk.internal.misc.Unsafe unsafe + = jdk.internal.misc.Unsafe.getUnsafe(); + private static final long LF_OFFSET + = unsafe.objectFieldOffset(Hashtable.class, "loadFactor"); + static void putLoadFactor(Hashtable table, float lf) { + unsafe.putFloat(table, LF_OFFSET, lf); + } + } + /** * The put method used by readObject. This is provided because put * is overridable and should not be called in readObject since the diff --git a/src/java.base/share/classes/java/util/IdentityHashMap.java b/src/java.base/share/classes/java/util/IdentityHashMap.java index 34d6722ac098f12b5b5a56dc7b594a5a5a66da8f..4795c30b3d5ee1595504dd0700d8656695a69474 100644 --- a/src/java.base/share/classes/java/util/IdentityHashMap.java +++ b/src/java.base/share/classes/java/util/IdentityHashMap.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -25,6 +25,8 @@ package java.util; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; import java.lang.reflect.Array; import java.util.function.BiConsumer; import java.util.function.BiFunction; @@ -1267,12 +1269,12 @@ public class IdentityHashMap * particular order. */ @java.io.Serial - private void writeObject(java.io.ObjectOutputStream s) + private void writeObject(ObjectOutputStream s) throws java.io.IOException { - // Write out and any hidden stuff + // Write out size (number of mappings) and any hidden stuff s.defaultWriteObject(); - // Write out size (number of Mappings) + // Write out size again (maintained for backward compatibility) s.writeInt(size); // Write out keys and values (alternating) @@ -1291,18 +1293,20 @@ public class IdentityHashMap * deserializes it). */ @java.io.Serial - private void readObject(java.io.ObjectInputStream s) + private void readObject(ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { - // Read in any hidden stuff - s.defaultReadObject(); + // Size (number of mappings) is written to the stream twice + // Read first size value and ignore it + s.readFields(); - // Read in size (number of Mappings) + // Read second size value, validate and assign to size field int size = s.readInt(); if (size < 0) throw new java.io.StreamCorruptedException ("Illegal mappings count: " + size); int cap = capacity(size); - SharedSecrets.getJavaObjectInputStreamAccess().checkArray(s, Object[].class, cap); + SharedSecrets.getJavaObjectInputStreamAccess().checkArray(s, Object[].class, cap*2); + this.size = size; init(cap); // Read the keys and values, and put the mappings in the table diff --git a/src/java.base/share/classes/java/util/ImmutableCollections.java b/src/java.base/share/classes/java/util/ImmutableCollections.java index c207e4f1427d60e0cc10c2997bfb1b06fdd79547..4c8fd0cfc8fa14ceab4ed02f7b47024bbc2c0f5d 100644 --- a/src/java.base/share/classes/java/util/ImmutableCollections.java +++ b/src/java.base/share/classes/java/util/ImmutableCollections.java @@ -1062,7 +1062,7 @@ class ImmutableCollections { // ---------- Map Implementations ---------- - @jdk.internal.ValueBased + // Not a jdk.internal.ValueBased class; disqualified by fields in superclass AbstractMap abstract static class AbstractImmutableMap extends AbstractMap implements Serializable { @Override public void clear() { throw uoe(); } @Override public V compute(K key, BiFunction rf) { throw uoe(); } @@ -1093,7 +1093,7 @@ class ImmutableCollections { } } - @jdk.internal.ValueBased + // Not a jdk.internal.ValueBased class; disqualified by fields in superclass AbstractMap static final class Map1 extends AbstractImmutableMap { @Stable private final K k0; @@ -1160,7 +1160,7 @@ class ImmutableCollections { * @param the key type * @param the value type */ - @jdk.internal.ValueBased + // Not a jdk.internal.ValueBased class; disqualified by fields in superclass AbstractMap static final class MapN extends AbstractImmutableMap { @Stable diff --git a/src/java.base/share/classes/java/util/JumboEnumSet.java b/src/java.base/share/classes/java/util/JumboEnumSet.java index f80e5056803b37c75c5201639b247811d0802cbe..126fc077b6cd40c890a208ced45d40c704d14d9c 100644 --- a/src/java.base/share/classes/java/util/JumboEnumSet.java +++ b/src/java.base/share/classes/java/util/JumboEnumSet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -33,7 +33,7 @@ package java.util; * @since 1.5 * @serial exclude */ -class JumboEnumSet> extends EnumSet { +final class JumboEnumSet> extends EnumSet { @java.io.Serial private static final long serialVersionUID = 334349849919042784L; diff --git a/src/java.base/share/classes/java/util/Locale.java b/src/java.base/share/classes/java/util/Locale.java index 90a242984f1763f25ab0a22698c3d7c4b212d74b..2da179a5dd7b74b6144b3d2f027e9f2d14d65cda 100644 --- a/src/java.base/share/classes/java/util/Locale.java +++ b/src/java.base/share/classes/java/util/Locale.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 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 @@ -2003,7 +2003,7 @@ public final class Locale implements Cloneable, Serializable { /** * Returns a name for the locale that is appropriate for display * to the user. This will be the values returned by - * getDisplayLanguage(), getDisplayScript(),getDisplayCountry() + * getDisplayLanguage(), getDisplayScript(), getDisplayCountry(), * getDisplayVariant(), and optional * Unicode extensions assembled into a single string. The non-empty * values are used in order, with the second and subsequent names in diff --git a/src/java.base/share/classes/java/util/Objects.java b/src/java.base/share/classes/java/util/Objects.java index c32a67441da9d069c00f0d57fc6f2cc34427dade..066c20d6551850efe91adb278298e2b25e46faf8 100644 --- a/src/java.base/share/classes/java/util/Objects.java +++ b/src/java.base/share/classes/java/util/Objects.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 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 @@ -164,6 +164,30 @@ public final class Objects { return (o != null) ? o.toString() : nullDefault; } + /** + * {@return a string equivalent to the string returned by {@code + * Object.toString} if that method and {@code hashCode} are not + * overridden} + * + * @implNote + * This method constructs a string for an object without calling + * any overridable methods of the object. + * + * @implSpec + * The method returns a string equivalent to:
          + * {@code o.getClass().getName() + "@" + Integer.toHexString(System.identityHashCode(o))} + * + * @param o an object + * @throws NullPointerException if the argument is null + * @see Object#toString + * @see System#identityHashCode(Object) + * @since 19 + */ + public static String toIdentityString(Object o) { + requireNonNull(o); + return o.getClass().getName() + "@" + Integer.toHexString(System.identityHashCode(o)); + } + /** * Returns 0 if the arguments are identical and {@code * c.compare(a, b)} otherwise. @@ -203,6 +227,7 @@ public final class Objects { * @return {@code obj} if not {@code null} * @throws NullPointerException if {@code obj} is {@code null} */ + @ForceInline public static T requireNonNull(T obj) { if (obj == null) throw new NullPointerException(); @@ -228,6 +253,7 @@ public final class Objects { * @return {@code obj} if not {@code null} * @throws NullPointerException if {@code obj} is {@code null} */ + @ForceInline public static T requireNonNull(T obj, String message) { if (obj == null) throw new NullPointerException(message); diff --git a/src/java.base/share/classes/java/util/Observable.java b/src/java.base/share/classes/java/util/Observable.java index d71bf5d5d4c3bb40b7cbed8b11a210a7a8751bc7..01956702c2d82f43eafe01d836e84437c8bc5675 100644 --- a/src/java.base/share/classes/java/util/Observable.java +++ b/src/java.base/share/classes/java/util/Observable.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 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 @@ -66,13 +66,14 @@ package java.util; * {@code Observable} is unspecified, and state changes are not in * one-for-one correspondence with notifications. * For a richer event model, consider using the - * {@link java.beans} package. For reliable and ordered + * {@link java.desktop/java.beans} package. For reliable and ordered * messaging among threads, consider using one of the concurrent data * structures in the {@link java.util.concurrent} package. * For reactive streams style programming, see the * {@link java.util.concurrent.Flow} API. */ @Deprecated(since="9") +@SuppressWarnings("doclint:reference") // cross-module links public class Observable { private boolean changed = false; private Vector obs; diff --git a/src/java.base/share/classes/java/util/Optional.java b/src/java.base/share/classes/java/util/Optional.java index 64647ee49d5c18f34d083e959c564d14fedff069..cd8b2b6048fb60a32445aef0f7d22e92eb31f329 100644 --- a/src/java.base/share/classes/java/util/Optional.java +++ b/src/java.base/share/classes/java/util/Optional.java @@ -454,7 +454,7 @@ public final class Optional { @Override public String toString() { return value != null - ? String.format("Optional[%s]", value) + ? ("Optional[" + value + "]") : "Optional.empty"; } } diff --git a/src/java.base/share/classes/java/util/OptionalDouble.java b/src/java.base/share/classes/java/util/OptionalDouble.java index 61e54cfec2992c66db501b139c5722ef3f3e0b67..752aaac1e547ed28f69cafa9fbd38106825316b1 100644 --- a/src/java.base/share/classes/java/util/OptionalDouble.java +++ b/src/java.base/share/classes/java/util/OptionalDouble.java @@ -328,7 +328,7 @@ public final class OptionalDouble { @Override public String toString() { return isPresent - ? String.format("OptionalDouble[%s]", value) + ? ("OptionalDouble[" + value + "]") : "OptionalDouble.empty"; } } diff --git a/src/java.base/share/classes/java/util/OptionalInt.java b/src/java.base/share/classes/java/util/OptionalInt.java index d693a3ddba2fd109ef6b8f00377205d8f8babe18..c1e62090c25c5e10bb635dc5066bd81598f37aa5 100644 --- a/src/java.base/share/classes/java/util/OptionalInt.java +++ b/src/java.base/share/classes/java/util/OptionalInt.java @@ -326,7 +326,7 @@ public final class OptionalInt { @Override public String toString() { return isPresent - ? String.format("OptionalInt[%s]", value) + ? ("OptionalInt[" + value + "]") : "OptionalInt.empty"; } } diff --git a/src/java.base/share/classes/java/util/OptionalLong.java b/src/java.base/share/classes/java/util/OptionalLong.java index f92c5bdff175c34402c93523a7b513366ebf73f8..2c1171f86e9b763c7f63186113282b9a139b68d6 100644 --- a/src/java.base/share/classes/java/util/OptionalLong.java +++ b/src/java.base/share/classes/java/util/OptionalLong.java @@ -326,7 +326,7 @@ public final class OptionalLong { @Override public String toString() { return isPresent - ? String.format("OptionalLong[%s]", value) + ? ("OptionalLong[" + value + "]") : "OptionalLong.empty"; } } diff --git a/src/java.base/share/classes/java/util/RegularEnumSet.java b/src/java.base/share/classes/java/util/RegularEnumSet.java index 1deda8a293529c065e08156a1e2542cadc84de50..f06adcbf692c1b4980c255daca7301f3af746f0c 100644 --- a/src/java.base/share/classes/java/util/RegularEnumSet.java +++ b/src/java.base/share/classes/java/util/RegularEnumSet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -33,7 +33,7 @@ package java.util; * @since 1.5 * @serial exclude */ -class RegularEnumSet> extends EnumSet { +final class RegularEnumSet> extends EnumSet { @java.io.Serial private static final long serialVersionUID = 3411599620347842686L; /** diff --git a/src/java.base/share/classes/java/util/ResourceBundle.java b/src/java.base/share/classes/java/util/ResourceBundle.java index 8f57d782d474b28276aca502aeb9e8fdc90a0627..2e6ecf465826a8f2f14e58f5f35025787a890851 100644 --- a/src/java.base/share/classes/java/util/ResourceBundle.java +++ b/src/java.base/share/classes/java/util/ResourceBundle.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 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 @@ -256,6 +256,12 @@ import static sun.security.util.SecurityConstants.GET_CLASSLOADER_PERMISSION; * resource bundle provider, it does not fall back to the * class loader search. * + *

          + * In cases where the {@code getBundle} factory method is called from a context + * where there is no caller frame on the stack (e.g. when called directly from + * a JNI attached thread), the caller module is default to the unnamed module for the + * {@linkplain ClassLoader#getSystemClassLoader system class loader}. + * *

          Resource bundles in automatic modules

          * * A common format of resource bundles is in {@linkplain PropertyResourceBundle @@ -1505,7 +1511,8 @@ public abstract class ResourceBundle { } private static Control getDefaultControl(Class caller, String baseName) { - return getDefaultControl(caller.getModule(), baseName); + Module callerModule = getCallerModule(caller); + return getDefaultControl(callerModule, baseName); } private static Control getDefaultControl(Module targetModule, String baseName) { @@ -1536,7 +1543,8 @@ public abstract class ResourceBundle { } private static void checkNamedModule(Class caller) { - if (caller.getModule().isNamed()) { + Module callerModule = getCallerModule(caller); + if (callerModule.isNamed()) { throw new UnsupportedOperationException( "ResourceBundle.Control not supported in named modules"); } @@ -1546,7 +1554,19 @@ public abstract class ResourceBundle { Locale locale, Class caller, Control control) { - return getBundleImpl(baseName, locale, caller, caller.getClassLoader(), control); + ClassLoader loader = getLoader(getCallerModule(caller)); + return getBundleImpl(baseName, locale, caller, loader, control); + } + + /* + * Determine the module to be used for the caller. If + * Reflection::getCallerClass is called from JNI with an empty + * stack frame the caller will be null, so the system class loader unnamed + * module will be used. + */ + private static Module getCallerModule(Class caller) { + return (caller != null) ? caller.getModule() + : ClassLoader.getSystemClassLoader().getUnnamedModule(); } /** @@ -1565,10 +1585,7 @@ public abstract class ResourceBundle { Class caller, ClassLoader loader, Control control) { - if (caller == null) { - throw new InternalError("null caller"); - } - Module callerModule = caller.getModule(); + Module callerModule = getCallerModule(caller); // get resource bundles for a named module only if loader is the module's class loader if (callerModule.isNamed() && loader == getLoader(callerModule)) { @@ -1592,7 +1609,7 @@ public abstract class ResourceBundle { Locale locale, Control control) { Objects.requireNonNull(module); - Module callerModule = caller.getModule(); + Module callerModule = getCallerModule(caller); if (callerModule != module) { @SuppressWarnings("removal") SecurityManager sm = System.getSecurityManager(); @@ -2228,9 +2245,9 @@ public abstract class ResourceBundle { */ @CallerSensitive public static final void clearCache() { - Class caller = Reflection.getCallerClass(); + Module callerModule = getCallerModule(Reflection.getCallerClass()); cacheList.keySet().removeIf( - key -> key.getCallerModule() == caller.getModule() + key -> key.getCallerModule() == callerModule ); } @@ -3729,7 +3746,7 @@ public abstract class ResourceBundle { } - private static final boolean TRACE_ON = Boolean.valueOf( + private static final boolean TRACE_ON = Boolean.parseBoolean( GetPropertyAction.privilegedGetProperty("resource.bundle.debug", "false")); private static void trace(String format, Object... params) { diff --git a/src/java.base/share/classes/java/util/ServiceLoader.java b/src/java.base/share/classes/java/util/ServiceLoader.java index 64b01c3157e3928b22621615997446d7ca43fbbe..531ffa3f09c785a5b6a8bef9fa1f8f3c14a2f99b 100644 --- a/src/java.base/share/classes/java/util/ServiceLoader.java +++ b/src/java.base/share/classes/java/util/ServiceLoader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -1585,7 +1585,7 @@ public final class ServiceLoader * are located in the order that its module descriptor {@linkplain * java.lang.module.ModuleDescriptor.Provides#providers() lists the * providers}. Providers added dynamically by instrumentation agents (see - * {@link java.lang.instrument.Instrumentation#redefineModule redefineModule}) + * {@link java.instrument/java.lang.instrument.Instrumentation#redefineModule redefineModule}) * are always located after providers declared by the module.

          * *
        • Step 2: Locate providers in unnamed modules.

          @@ -1647,6 +1647,7 @@ public final class ServiceLoader * @revised 9 */ @CallerSensitive + @SuppressWarnings("doclint:reference") // cross-module links public static ServiceLoader load(Class service, ClassLoader loader) { diff --git a/src/java.base/share/classes/java/util/StringTokenizer.java b/src/java.base/share/classes/java/util/StringTokenizer.java index f30f7b863a46b7541e44289a7c6fcdf749e9c4ec..61fbfe8a716e3e1a61f8fe7c0b82cfdd5e5b89c3 100644 --- a/src/java.base/share/classes/java/util/StringTokenizer.java +++ b/src/java.base/share/classes/java/util/StringTokenizer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 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 @@ -174,9 +174,11 @@ public class StringTokenizer implements Enumeration { *

          * If the {@code returnDelims} flag is {@code true}, then * the delimiter characters are also returned as tokens. Each - * delimiter is returned as a string of length one. If the flag is - * {@code false}, the delimiter characters are skipped and only - * serve as separators between tokens. + * delimiter is returned as a string consisting of a single + * Unicode code point + * of the delimiter (which may be one or two {@code char}s). If the + * flag is {@code false}, the delimiter characters are skipped + * and only serve as separators between tokens. *

          * Note that if {@code delim} is {@code null}, this constructor does * not throw an exception. However, trying to invoke other methods on the diff --git a/src/java.base/share/classes/java/util/UUID.java b/src/java.base/share/classes/java/util/UUID.java index 897409053240a119296a73e9bcebf2dfb92976a6..0378df95a79863f16eaf068a6854cec2cde55a6d 100644 --- a/src/java.base/share/classes/java/util/UUID.java +++ b/src/java.base/share/classes/java/util/UUID.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -512,10 +512,7 @@ public final class UUID implements java.io.Serializable, Comparable { public int compareTo(UUID val) { // The ordering is intentionally set up so that the UUIDs // can simply be numerically compared as two numbers - return (this.mostSigBits < val.mostSigBits ? -1 : - (this.mostSigBits > val.mostSigBits ? 1 : - (this.leastSigBits < val.leastSigBits ? -1 : - (this.leastSigBits > val.leastSigBits ? 1 : - 0)))); + int mostSigBits = Long.compare(this.mostSigBits, val.mostSigBits); + return mostSigBits != 0 ? mostSigBits : Long.compare(this.leastSigBits, val.leastSigBits); } } diff --git a/src/java.base/share/classes/java/util/WeakHashMap.java b/src/java.base/share/classes/java/util/WeakHashMap.java index 03aee09e992f52447a799f53292c0cf533a909f1..bc31985b66ee2f68928600d32bb2f89acad0cb2e 100644 --- a/src/java.base/share/classes/java/util/WeakHashMap.java +++ b/src/java.base/share/classes/java/util/WeakHashMap.java @@ -213,9 +213,7 @@ public class WeakHashMap if (loadFactor <= 0 || Float.isNaN(loadFactor)) throw new IllegalArgumentException("Illegal Load factor: "+ loadFactor); - int capacity = 1; - while (capacity < initialCapacity) - capacity <<= 1; + int capacity = HashMap.tableSizeFor(initialCapacity); table = newTable(capacity); this.loadFactor = loadFactor; threshold = (int)(capacity * loadFactor); @@ -251,7 +249,7 @@ public class WeakHashMap * @since 1.3 */ public WeakHashMap(Map m) { - this(Math.max((int) ((float)m.size() / DEFAULT_LOAD_FACTOR + 1.0F), + this(Math.max((int) Math.ceil(m.size() / (double)DEFAULT_LOAD_FACTOR), DEFAULT_INITIAL_CAPACITY), DEFAULT_LOAD_FACTOR); putAll(m); @@ -468,7 +466,7 @@ public class WeakHashMap modCount++; Entry e = tab[i]; tab[i] = new Entry<>(k, value, queue, h, e); - if (++size >= threshold) + if (++size > threshold) resize(tab.length * 2); return null; } @@ -557,7 +555,7 @@ public class WeakHashMap * to at most one extra resize. */ if (numKeysToBeAdded > threshold) { - int targetCapacity = (int)(numKeysToBeAdded / loadFactor + 1); + int targetCapacity = (int)Math.ceil(numKeysToBeAdded / (double)loadFactor); if (targetCapacity > MAXIMUM_CAPACITY) targetCapacity = MAXIMUM_CAPACITY; int newCapacity = table.length; @@ -1040,7 +1038,7 @@ public class WeakHashMap Objects.requireNonNull(function); int expectedModCount = modCount; - Entry[] tab = getTable();; + Entry[] tab = getTable(); for (Entry entry : tab) { while (entry != null) { Object key = entry.get(); diff --git a/src/java.base/share/classes/java/util/concurrent/Executors.java b/src/java.base/share/classes/java/util/concurrent/Executors.java index a9e7de32a002f60f887ea74c0bc37f545d7a4e99..3345153bd9777e5901519aa58162d24d8566aab9 100644 --- a/src/java.base/share/classes/java/util/concurrent/Executors.java +++ b/src/java.base/share/classes/java/util/concurrent/Executors.java @@ -791,7 +791,7 @@ public class Executors { FinalizableDelegatedExecutorService(ExecutorService executor) { super(executor); } - @SuppressWarnings("deprecation") + @SuppressWarnings("removal") protected void finalize() { super.shutdown(); } diff --git a/src/java.base/share/classes/java/util/concurrent/ThreadPoolExecutor.java b/src/java.base/share/classes/java/util/concurrent/ThreadPoolExecutor.java index 49d2a29b2624bc078526b284b85c8371d7dbf359..f23e72a8f70c82f2bba7845c54f02f2d9d920de1 100644 --- a/src/java.base/share/classes/java/util/concurrent/ThreadPoolExecutor.java +++ b/src/java.base/share/classes/java/util/concurrent/ThreadPoolExecutor.java @@ -1477,8 +1477,13 @@ public class ThreadPoolExecutor extends AbstractExecutorService { * @implNote Previous versions of this class had a finalize method * that shut down this executor, but in this version, finalize * does nothing. + * + * @deprecated Finalization has been deprecated for removal. See + * {@link java.lang.Object#finalize} for background information and details + * about migration options. */ - @Deprecated(since="9") + @Deprecated(since="9", forRemoval=true) + @SuppressWarnings("removal") protected void finalize() {} /** diff --git a/src/java.base/share/classes/java/util/jar/Attributes.java b/src/java.base/share/classes/java/util/jar/Attributes.java index a33d1086285d792a105d6c19a6779e82c8f65a14..3b59f74275fd6ec901ede9681afc9a84c4490ed4 100644 --- a/src/java.base/share/classes/java/util/jar/Attributes.java +++ b/src/java.base/share/classes/java/util/jar/Attributes.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -25,6 +25,7 @@ package java.util.jar; +import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; import java.io.IOException; import java.util.Collection; @@ -366,7 +367,7 @@ public class Attributes implements Map, Cloneable { int read(Manifest.FastInputStream is, byte[] lbuf, String filename, int lineNumber) throws IOException { String name = null, value; - byte[] lastline = null; + ByteArrayOutputStream fullLine = new ByteArrayOutputStream(); int len; while ((len = is.readLine(lbuf)) != -1) { @@ -392,15 +393,12 @@ public class Attributes implements Map, Cloneable { + Manifest.getErrorPosition(filename, lineNumber) + ")"); } lineContinued = true; - byte[] buf = new byte[lastline.length + len - 1]; - System.arraycopy(lastline, 0, buf, 0, lastline.length); - System.arraycopy(lbuf, 1, buf, lastline.length, len - 1); + fullLine.write(lbuf, 1, len - 1); if (is.peek() == ' ') { - lastline = buf; continue; } - value = new String(buf, 0, buf.length, UTF_8.INSTANCE); - lastline = null; + value = fullLine.toString(UTF_8.INSTANCE); + fullLine.reset(); } else { while (lbuf[i++] != ':') { if (i >= len) { @@ -414,8 +412,8 @@ public class Attributes implements Map, Cloneable { } name = new String(lbuf, 0, i - 2, UTF_8.INSTANCE); if (is.peek() == ' ') { - lastline = new byte[len - i]; - System.arraycopy(lbuf, i, lastline, 0, len - i); + fullLine.reset(); + fullLine.write(lbuf, i, len - i); continue; } value = new String(lbuf, i, len - i, UTF_8.INSTANCE); diff --git a/src/java.base/share/classes/java/util/jar/JarFile.java b/src/java.base/share/classes/java/util/jar/JarFile.java index f0cd0e5c3820fb7ed0bcb57aa08d8455cc8e7e54..e6a55b9cb273b0c9e851d71a5cd81bb4a0a975bd 100644 --- a/src/java.base/share/classes/java/util/jar/JarFile.java +++ b/src/java.base/share/classes/java/util/jar/JarFile.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -826,7 +826,8 @@ public class JarFile extends ZipFile { * zip file entry. * @param ze the zip file entry * @return an input stream for reading the contents of the specified - * zip file entry + * zip file entry or null if the zip file entry does not exist + * within the jar file * @throws ZipException if a zip file format error has occurred * @throws IOException if an I/O error has occurred * @throws SecurityException if any of the jar file entries @@ -837,6 +838,8 @@ public class JarFile extends ZipFile { public synchronized InputStream getInputStream(ZipEntry ze) throws IOException { + Objects.requireNonNull(ze, "ze"); + maybeInstantiateVerifier(); if (jv == null) { return super.getInputStream(ze); @@ -850,21 +853,33 @@ public class JarFile extends ZipFile { if (jv == null) return super.getInputStream(ze); } - + // Return null InputStream when the specified entry is not found in the + // Jar + var je = verifiableEntry(ze); + if (je == null) { + return null; + } // wrap a verifier stream around the real stream return new JarVerifier.VerifierStream( - getManifestFromReference(), - verifiableEntry(ze), - super.getInputStream(ze), - jv); + getManifestFromReference(), + je, + super.getInputStream(ze), + jv); + } - private JarEntry verifiableEntry(ZipEntry ze) { + private JarEntry verifiableEntry(ZipEntry ze) throws ZipException { if (ze instanceof JarFileEntry) { // assure the name and entry match for verification return ((JarFileEntry)ze).realEntry(); } - ze = getJarEntry(ze.getName()); + // ZipEntry::getName should not return null, if it does, return null + var entryName = ze.getName(); + if (entryName != null) { + ze = getJarEntry(entryName); + } else { + return null; + } if (ze instanceof JarFileEntry) { return ((JarFileEntry)ze).realEntry(); } diff --git a/src/java.base/share/classes/java/util/jar/JarVerifier.java b/src/java.base/share/classes/java/util/jar/JarVerifier.java index 280d64e9d37a95a0b337b72c1a86d231f78bf368..e6a217b424cc7eff46209bc1fb5ea7f6a04a5131 100644 --- a/src/java.base/share/classes/java/util/jar/JarVerifier.java +++ b/src/java.base/share/classes/java/util/jar/JarVerifier.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -96,6 +96,10 @@ class JarVerifier { /** collect -DIGEST-MANIFEST values for deny list */ private List manifestDigests; + /* A cache mapping code signers to the algorithms used to digest jar + entries, and whether or not the algorithms are permitted. */ + private Map> signersToAlgs; + public JarVerifier(String name, byte[] rawBytes) { manifestName = name; manifestRawBytes = rawBytes; @@ -105,6 +109,7 @@ class JarVerifier { pendingBlocks = new ArrayList<>(); baos = new ByteArrayOutputStream(); manifestDigests = new ArrayList<>(); + signersToAlgs = new HashMap<>(); } /** @@ -244,7 +249,8 @@ class JarVerifier { if (!parsingBlockOrSF) { JarEntry je = mev.getEntry(); if ((je != null) && (je.signers == null)) { - je.signers = mev.verify(verifiedSigners, sigFileSigners); + je.signers = mev.verify(verifiedSigners, sigFileSigners, + signersToAlgs); je.certs = mapSignersToCertArray(je.signers); } } else { diff --git a/src/java.base/share/classes/java/util/random/RandomGenerator.java b/src/java.base/share/classes/java/util/random/RandomGenerator.java index 9feff7131920000a61c23516c80d6eb631150257..a5e20e55161cc836b854ab6dee385679a4ba2f34 100644 --- a/src/java.base/share/classes/java/util/random/RandomGenerator.java +++ b/src/java.base/share/classes/java/util/random/RandomGenerator.java @@ -1196,7 +1196,7 @@ public interface RandomGenerator { * * @return a stream of objects that implement the {@link RandomGenerator} interface * - * @implSpec The default implementation calls {@link JumpableGenerator#jump jump}(). + * @implSpec The default implementation calls {@link JumpableGenerator#jumps jumps}(). */ default Stream rngs() { return this.jumps(); diff --git a/src/java.base/share/classes/java/util/random/package-info.java b/src/java.base/share/classes/java/util/random/package-info.java index 8efaa0bd4c37111dbec6725e8617cce647a4cdec..102410bffe600a55f94d18c329defd76109260a7 100644 --- a/src/java.base/share/classes/java/util/random/package-info.java +++ b/src/java.base/share/classes/java/util/random/package-info.java @@ -347,12 +347,12 @@ * supported by the interface {@link RandomGenerator.JumpableGenerator}. * Sometimes it is desirable to support two levels of jumping (by long distances * and by really long distances); this strategy is supported by the - * interface {@link RandomGenerator.LeapableGenerator}. There is also an interface + * interface {@link RandomGenerator.LeapableGenerator}. In this package, + * implementations of this interface include "Xoroshiro128PlusPlus" and + * "Xoshiro256PlusPlus". There is also an interface * {@link RandomGenerator.ArbitrarilyJumpableGenerator} for algorithms that allow - * jumping along the state cycle by any user-specified distance. In this package, - * implementations of these interfaces include - * "Xoroshiro128PlusPlus", and - * "Xoshiro256PlusPlus". + * jumping along the state cycle by any user-specified distance; there are currently + * no implementations of this interface in this package. * *

          A more recent category of "splittable" pseudorandom generator algorithms * uses a large family of state cycles and makes some attempt to ensure that @@ -382,13 +382,18 @@ * equidistribution, scalability, and better quality. Each of the * specific implementations here combines one of the best currently known * XBG algorithms (xoroshiro128 or xoshiro256, described by Blackman and - * Vigna in "Scrambled Linear Pseudorandom Number Generators", ACM Transactions - * on Mathematical Software, 2021) with an LCG that uses one of the best + * Vigna in "Scrambled Linear Pseudorandom Number Generators", ACM Transactions + * on Mathematical Software, 2021) with an LCG that uses one of the best * currently known multipliers (found by a search for better multipliers - * in 2019 by Steele and Vigna), and then applies either a mixing function - * identified by Doug Lea or a simple scrambler proposed by Blackman and Vigna. - * Testing has confirmed that the LXM algorithm is far superior in quality to - * the SplitMix algorithm (2014) used by {@code SplittableRandom}. + * in 2019 by Steele and Vigna, described in "Computationally Easy, Spectrally + * Good Multipliers for Congruential Pseudorandom Number Generators", + * Software: Practice and Experience (2021), doi:10.1002/spe.3030), + * and then applies either a mixing function identified by Doug Lea or + * or a simple scrambler proposed by Blackman and Vigna. Testing has + * confirmed that the LXM algorithm is far superior in quality to the + * SplitMix algorithm (2014) used by {@code SplittableRandom} + * (see Steele and Vigna, "LXM: Better Splittable Pseudorandom Number + * Generators (and Almost as Fast)", Proc. 2021 ACM OOPSLA Conference). * * Each class with a name of the form * {@code L}p{@code X}q{@code SomethingRandom} diff --git a/src/java.base/share/classes/java/util/regex/Grapheme.java b/src/java.base/share/classes/java/util/regex/Grapheme.java index efc92158dfecb932cbe13f09191654622c669369..9922cab121a91475f7ec63c584f6672c2f150a71 100644 --- a/src/java.base/share/classes/java/util/regex/Grapheme.java +++ b/src/java.base/share/classes/java/util/regex/Grapheme.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -35,8 +35,8 @@ final class Grapheme { *

          * See Unicode Standard Annex #29 Unicode Text Segmentation for the specification * for the extended grapheme cluster boundary rules. The following implementation - * is based on version 12.0 of the annex. - * (http://www.unicode.org/reports/tr29/tr29-35.html) + * is based on the annex for Unicode version 14.0. + * (http://www.unicode.org/reports/tr29/tr29-38.html) * * @param src the {@code CharSequence} to be scanned * @param off offset to start looking for the next boundary in the src @@ -97,7 +97,7 @@ final class Grapheme { private static final int FIRST_TYPE = 0; private static final int LAST_TYPE = 14; - private static boolean[][] rules; + private static final boolean[][] rules; static { rules = new boolean[LAST_TYPE + 1][LAST_TYPE + 1]; // GB 999 Any + Any -> default @@ -201,8 +201,9 @@ final class Grapheme { if (cp == 0x200D) return ZWJ; if (cp >= 0x0600 && cp <= 0x0605 || - cp == 0x06DD || cp == 0x070F || cp == 0x08E2 || - cp == 0x110BD || cp == 0x110CD) + cp == 0x06DD || cp == 0x070F || + cp == 0x0890 || cp == 0x0891 || + cp == 0x08E2 || cp == 0x110BD || cp == 0x110CD) return PREPEND; return CONTROL; case Character.NON_SPACING_MARK: diff --git a/src/java.base/share/classes/java/util/regex/Pattern.java b/src/java.base/share/classes/java/util/regex/Pattern.java index 5b2533111f4ef224bb5343d5f8d0dc20dad8c28f..5bb6ec76a7c6f5e2e6f386e96a3f24ee0036a728 100644 --- a/src/java.base/share/classes/java/util/regex/Pattern.java +++ b/src/java.base/share/classes/java/util/regex/Pattern.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -396,7 +396,7 @@ import jdk.internal.util.ArraysSupport; *

          Backslashes within string literals in Java source code are interpreted * as required by * The Java Language Specification - * as either Unicode escapes (section {@jls 3.3}) or other character escapes (section {@jls 3.10.6}) + * as either Unicode escapes (section {@jls 3.3}) or other character escapes (section {@jls 3.10.6}). * It is therefore necessary to double backslashes in string * literals that represent regular expressions to protect them from * interpretation by the Java bytecode compiler. The string literal @@ -1795,6 +1795,8 @@ loop: for(int x=0, offset=0; x= 0 && index < seq.length()); + if (lengthInCodePoints == 1 && index >= 0 && index < seq.length() && + !Character.isHighSurrogate(seq.charAt(index))) { return 1; } int length = seq.length(); @@ -4001,8 +4005,9 @@ loop: for(int x=0, offset=0; x matcher.to) { + if (i + groupSizeChars > matcher.to) { matcher.hitEnd = true; return false; } @@ -5071,7 +5076,13 @@ loop: for(int x=0, offset=0; x= Character.MIN_SUPPLEMENTARY_CODE_POINT) { + //Group size is guessed in terms of chars, but we need to + //adjust if we spot a 2-char codePoint. + groupCodepoints--; + } } - return next.match(matcher, i+groupSize, seq); + return next.match(matcher, i+groupSizeChars, seq); } boolean study(TreeInfo info) { info.maxValid = false; @@ -5605,50 +5622,69 @@ NEXT: while (i <= last) { } } + private static CharPredicate and(CharPredicate p1, CharPredicate p2, + boolean bmpChar) { + if (bmpChar) { + return (BmpCharPredicate)(ch -> p1.is(ch) && p2.is(ch)); + } else { + return (CharPredicate)(ch -> p1.is(ch) && p2.is(ch)); + } + } + + private static CharPredicate union(CharPredicate p1, CharPredicate p2, + boolean bmpChar) { + if (bmpChar) { + return (BmpCharPredicate)(ch -> p1.is(ch) || p2.is(ch)); + } else { + return (CharPredicate)(ch -> p1.is(ch) || p2.is(ch)); + } + } + + private static CharPredicate union(CharPredicate p1, CharPredicate p2, + CharPredicate p3, boolean bmpChar) { + if (bmpChar) { + return (BmpCharPredicate)(ch -> p1.is(ch) || p2.is(ch) || p3.is(ch)); + } else { + return (CharPredicate)(ch -> p1.is(ch) || p2.is(ch) || p3.is(ch)); + } + } + + private static CharPredicate negate(CharPredicate p1) { + return (CharPredicate)(ch -> !p1.is(ch)); + } + @FunctionalInterface static interface CharPredicate { boolean is(int ch); default CharPredicate and(CharPredicate p) { - return ch -> is(ch) && p.is(ch); + return Pattern.and(this, p, false); } default CharPredicate union(CharPredicate p) { - return ch -> is(ch) || p.is(ch); + return Pattern.union(this, p, false); } default CharPredicate union(CharPredicate p1, CharPredicate p2) { - return ch -> is(ch) || p1.is(ch) || p2.is(ch); + return Pattern.union(this, p1, p2, false); } default CharPredicate negate() { - return ch -> !is(ch); + return Pattern.negate(this); } } static interface BmpCharPredicate extends CharPredicate { default CharPredicate and(CharPredicate p) { - if (p instanceof BmpCharPredicate) - return (BmpCharPredicate)(ch -> is(ch) && p.is(ch)); - return ch -> is(ch) && p.is(ch); + return Pattern.and(this, p, p instanceof BmpCharPredicate); } default CharPredicate union(CharPredicate p) { - if (p instanceof BmpCharPredicate) - return (BmpCharPredicate)(ch -> is(ch) || p.is(ch)); - return ch -> is(ch) || p.is(ch); - } - static CharPredicate union(CharPredicate... predicates) { - CharPredicate cp = ch -> { - for (CharPredicate p : predicates) { - if (!p.is(ch)) - return false; - } - return true; - }; - for (CharPredicate p : predicates) { - if (! (p instanceof BmpCharPredicate)) - return cp; - } - return (BmpCharPredicate)cp; + return Pattern.union(this, p, p instanceof BmpCharPredicate); + } + default CharPredicate union(CharPredicate p1, + CharPredicate p2) { + return Pattern.union(this, p1, p2, + p1 instanceof BmpCharPredicate && + p2 instanceof BmpCharPredicate); } } diff --git a/src/java.base/share/classes/java/util/stream/AbstractTask.java b/src/java.base/share/classes/java/util/stream/AbstractTask.java index 44c2656157b4083df7dd29ca6b65860930437124..9a61729f68d6234a4fdea154eeb5192928368a6b 100644 --- a/src/java.base/share/classes/java/util/stream/AbstractTask.java +++ b/src/java.base/share/classes/java/util/stream/AbstractTask.java @@ -180,7 +180,7 @@ abstract class AbstractTask The type of input element diff --git a/src/java.base/share/classes/java/util/stream/Node.java b/src/java.base/share/classes/java/util/stream/Node.java index 131195944eeaa414177707294b07e7e02019b5ef..7c4dda8adaf901bc3aef156420563cddef5b7981 100644 --- a/src/java.base/share/classes/java/util/stream/Node.java +++ b/src/java.base/share/classes/java/util/stream/Node.java @@ -200,7 +200,7 @@ interface Node { Node build(); /** - * Specialized @{code Node.Builder} for int elements + * Specialized {@code Node.Builder} for int elements */ interface OfInt extends Node.Builder, Sink.OfInt { @Override @@ -208,7 +208,7 @@ interface Node { } /** - * Specialized @{code Node.Builder} for long elements + * Specialized {@code Node.Builder} for long elements */ interface OfLong extends Node.Builder, Sink.OfLong { @Override @@ -216,7 +216,7 @@ interface Node { } /** - * Specialized @{code Node.Builder} for double elements + * Specialized {@code Node.Builder} for double elements */ interface OfDouble extends Node.Builder, Sink.OfDouble { @Override diff --git a/src/java.base/share/classes/java/util/stream/Nodes.java b/src/java.base/share/classes/java/util/stream/Nodes.java index ae0c202e51499aa484773dc29e53d67d08861271..33e1d920c26c39db9e66512ce6db019350e44e12 100644 --- a/src/java.base/share/classes/java/util/stream/Nodes.java +++ b/src/java.base/share/classes/java/util/stream/Nodes.java @@ -170,7 +170,7 @@ final class Nodes { } /** - * Produces a variable size @{link Node.Builder}. + * Produces a variable size {@link Node.Builder}. * * @param the type of elements of the node builder * @return a {@code Node.Builder} @@ -208,7 +208,7 @@ final class Nodes { } /** - * Produces a variable size @{link Node.Builder.OfInt}. + * Produces a variable size {@link Node.Builder.OfInt}. * * @return a {@code Node.Builder.OfInt} */ @@ -245,7 +245,7 @@ final class Nodes { } /** - * Produces a variable size @{link Node.Builder.OfLong}. + * Produces a variable size {@link Node.Builder.OfLong}. * * @return a {@code Node.Builder.OfLong} */ @@ -282,7 +282,7 @@ final class Nodes { } /** - * Produces a variable size @{link Node.Builder.OfDouble}. + * Produces a variable size {@link Node.Builder.OfDouble}. * * @return a {@code Node.Builder.OfDouble} */ diff --git a/src/java.base/share/classes/java/util/stream/PipelineHelper.java b/src/java.base/share/classes/java/util/stream/PipelineHelper.java index 7503bb6bf56fbb26e46ae463427408c6f75aac74..9571311ac1ff91014600f7d9e68e46ea54769247 100644 --- a/src/java.base/share/classes/java/util/stream/PipelineHelper.java +++ b/src/java.base/share/classes/java/util/stream/PipelineHelper.java @@ -163,7 +163,7 @@ abstract class PipelineHelper { abstract Spliterator wrapSpliterator(Spliterator spliterator); /** - * Constructs a @{link Node.Builder} compatible with the output shape of + * Constructs a {@link Node.Builder} compatible with the output shape of * this {@code PipelineHelper}. * * @param exactSizeIfKnown if >=0 then a builder will be created that has a diff --git a/src/java.base/share/classes/java/util/zip/Deflater.java b/src/java.base/share/classes/java/util/zip/Deflater.java index d41b8a7e12627f0e63937f7157aabc2aa01d9798..155264e4afe4b3940904febeb6103caad052054d 100644 --- a/src/java.base/share/classes/java/util/zip/Deflater.java +++ b/src/java.base/share/classes/java/util/zip/Deflater.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 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 @@ -895,6 +895,16 @@ public class Deflater { throw new NullPointerException("Deflater has been closed"); } + /** + * Returns the value of 'finish' flag. + * 'finish' will be set to true if def.finish() method is called. + */ + boolean shouldFinish() { + synchronized (zsRef) { + return finish; + } + } + private static native long init(int level, int strategy, boolean nowrap); private static native void setDictionary(long addr, byte[] b, int off, int len); diff --git a/src/java.base/share/classes/java/util/zip/DeflaterInputStream.java b/src/java.base/share/classes/java/util/zip/DeflaterInputStream.java index e0ecba0fcad5649e35e33aa7849b513824db3132..84d2c888543525ad94bf23544232879e3b7cd02b 100644 --- a/src/java.base/share/classes/java/util/zip/DeflaterInputStream.java +++ b/src/java.base/share/classes/java/util/zip/DeflaterInputStream.java @@ -28,6 +28,7 @@ package java.util.zip; import java.io.FilterInputStream; import java.io.InputStream; import java.io.IOException; +import java.util.Objects; /** * Implements an input stream filter for compressing data in the "deflate" @@ -172,9 +173,9 @@ public class DeflaterInputStream extends FilterInputStream { ensureOpen(); if (b == null) { throw new NullPointerException("Null buffer for read"); - } else if (off < 0 || len < 0 || len > b.length - off) { - throw new IndexOutOfBoundsException(); - } else if (len == 0) { + } + Objects.checkFromIndexSize(off, len, b.length); + if (len == 0) { return 0; } diff --git a/src/java.base/share/classes/java/util/zip/DeflaterOutputStream.java b/src/java.base/share/classes/java/util/zip/DeflaterOutputStream.java index 365bc676b082e372b4bbe9fdc7c8b3c55cb73fc8..c856d8999b39f4bb6a88d0ef24da027f89042f3d 100644 --- a/src/java.base/share/classes/java/util/zip/DeflaterOutputStream.java +++ b/src/java.base/share/classes/java/util/zip/DeflaterOutputStream.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 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 @@ -220,9 +220,15 @@ public class DeflaterOutputStream extends FilterOutputStream { */ public void finish() throws IOException { if (!def.finished()) { - def.finish(); - while (!def.finished()) { - deflate(); + try{ + def.finish(); + while (!def.finished()) { + deflate(); + } + } catch(IOException e) { + if (usesDefaultDeflater) + def.end(); + throw e; } } } @@ -234,9 +240,12 @@ public class DeflaterOutputStream extends FilterOutputStream { */ public void close() throws IOException { if (!closed) { - finish(); - if (usesDefaultDeflater) - def.end(); + try { + finish(); + } finally { + if (usesDefaultDeflater) + def.end(); + } out.close(); closed = true; } diff --git a/src/java.base/share/classes/java/util/zip/GZIPOutputStream.java b/src/java.base/share/classes/java/util/zip/GZIPOutputStream.java index 153af0959b18189086a05a838e38bc499ffc2ef0..cdfac329cfa83896f3eb69a14221ac2578baeba7 100644 --- a/src/java.base/share/classes/java/util/zip/GZIPOutputStream.java +++ b/src/java.base/share/classes/java/util/zip/GZIPOutputStream.java @@ -157,24 +157,30 @@ public class GZIPOutputStream extends DeflaterOutputStream { */ public void finish() throws IOException { if (!def.finished()) { - def.finish(); - while (!def.finished()) { - int len = def.deflate(buf, 0, buf.length); - if (def.finished() && len <= buf.length - TRAILER_SIZE) { - // last deflater buffer. Fit trailer at the end - writeTrailer(buf, len); - len = len + TRAILER_SIZE; - out.write(buf, 0, len); - return; + try { + def.finish(); + while (!def.finished()) { + int len = def.deflate(buf, 0, buf.length); + if (def.finished() && len <= buf.length - TRAILER_SIZE) { + // last deflater buffer. Fit trailer at the end + writeTrailer(buf, len); + len = len + TRAILER_SIZE; + out.write(buf, 0, len); + return; + } + if (len > 0) + out.write(buf, 0, len); } - if (len > 0) - out.write(buf, 0, len); + // if we can't fit the trailer at the end of the last + // deflater buffer, we write it separately + byte[] trailer = new byte[TRAILER_SIZE]; + writeTrailer(trailer, 0); + out.write(trailer); + } catch (IOException e) { + if (usesDefaultDeflater) + def.end(); + throw e; } - // if we can't fit the trailer at the end of the last - // deflater buffer, we write it separately - byte[] trailer = new byte[TRAILER_SIZE]; - writeTrailer(trailer, 0); - out.write(trailer); } } diff --git a/src/java.base/share/classes/java/util/zip/InflaterInputStream.java b/src/java.base/share/classes/java/util/zip/InflaterInputStream.java index 534241d3d0a59aca11471cfa6f9a3c80f4af7bd3..a87f78b38381cfece362bfd02845e61465132cb1 100644 --- a/src/java.base/share/classes/java/util/zip/InflaterInputStream.java +++ b/src/java.base/share/classes/java/util/zip/InflaterInputStream.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 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 @@ -29,6 +29,7 @@ import java.io.FilterInputStream; import java.io.InputStream; import java.io.IOException; import java.io.EOFException; +import java.util.Objects; /** * This class implements a stream filter for uncompressing data in the @@ -142,14 +143,14 @@ public class InflaterInputStream extends FilterInputStream { ensureOpen(); if (b == null) { throw new NullPointerException(); - } else if (off < 0 || len < 0 || len > b.length - off) { - throw new IndexOutOfBoundsException(); - } else if (len == 0) { + } + Objects.checkFromIndexSize(off, len, b.length); + if (len == 0) { return 0; } try { int n; - while ((n = inf.inflate(b, off, len)) == 0) { + do { if (inf.finished() || inf.needsDictionary()) { reachEOF = true; return -1; @@ -157,7 +158,7 @@ public class InflaterInputStream extends FilterInputStream { if (inf.needsInput()) { fill(); } - } + } while ((n = inf.inflate(b, off, len)) == 0); return n; } catch (DataFormatException e) { String s = e.getMessage(); @@ -188,8 +189,6 @@ public class InflaterInputStream extends FilterInputStream { } } - private byte[] b = new byte[512]; - /** * Skips specified number of bytes of uncompressed data. * @param n the number of bytes to skip @@ -204,6 +203,7 @@ public class InflaterInputStream extends FilterInputStream { ensureOpen(); int max = (int)Math.min(n, Integer.MAX_VALUE); int total = 0; + byte[] b = new byte[Math.min(max, 512)]; while (total < max) { int len = max - total; if (len > b.length) { diff --git a/src/java.base/share/classes/java/util/zip/InflaterOutputStream.java b/src/java.base/share/classes/java/util/zip/InflaterOutputStream.java index aa306239224133f743e0aa7b7942432807f10611..7b08d5b45385caaecec8d14ceee6c3eb3ec3a4f9 100644 --- a/src/java.base/share/classes/java/util/zip/InflaterOutputStream.java +++ b/src/java.base/share/classes/java/util/zip/InflaterOutputStream.java @@ -28,6 +28,7 @@ package java.util.zip; import java.io.FilterOutputStream; import java.io.IOException; import java.io.OutputStream; +import java.util.Objects; /** * Implements an output stream filter for uncompressing data stored in the @@ -223,9 +224,9 @@ public class InflaterOutputStream extends FilterOutputStream { ensureOpen(); if (b == null) { throw new NullPointerException("Null buffer for read"); - } else if (off < 0 || len < 0 || len > b.length - off) { - throw new IndexOutOfBoundsException(); - } else if (len == 0) { + } + Objects.checkFromIndexSize(off, len, b.length); + if (len == 0) { return; } diff --git a/src/java.base/share/classes/java/util/zip/ZipEntry.java b/src/java.base/share/classes/java/util/zip/ZipEntry.java index 9ff3533116c6fa980114443f6f9bde72fd50279a..5846d6cc3bb64ea820107f5fa7ff976db126e1e7 100644 --- a/src/java.base/share/classes/java/util/zip/ZipEntry.java +++ b/src/java.base/share/classes/java/util/zip/ZipEntry.java @@ -153,7 +153,7 @@ public class ZipEntry implements ZipConstants, Cloneable { * be stored into the {@code date and time fields} of the zip file * entry and encoded in standard {@code MS-DOS date and time format}. * The {@link java.util.TimeZone#getDefault() default TimeZone} is - * used to convert the epoch time to the MS-DOS data and time. + * used to convert the epoch time to the MS-DOS date and time. * * @param time * The last modification time of the entry in milliseconds diff --git a/src/java.base/share/classes/java/util/zip/ZipFile.java b/src/java.base/share/classes/java/util/zip/ZipFile.java index 47edf1ffae1403faba3b7ca1a1fda6c6457893e9..8538b4aef89f4a5582f4f7f2b950f3f47b12bc35 100644 --- a/src/java.base/share/classes/java/util/zip/ZipFile.java +++ b/src/java.base/share/classes/java/util/zip/ZipFile.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 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 @@ -208,7 +208,7 @@ public class ZipFile implements ZipConstants, Closeable { * * @throws SecurityException * if a security manager exists and its {@code checkRead} - * method doesn't allow read access to the file,or its + * method doesn't allow read access to the file, or its * {@code checkDelete} method doesn't allow deleting the * file when the {@code OPEN_DELETE} flag is set * @@ -345,7 +345,8 @@ public class ZipFile implements ZipConstants, Closeable { * * @param entry the zip file entry * @return the input stream for reading the contents of the specified - * zip file entry. + * zip file entry or null if the zip file entry does not exist + * within the zip file. * @throws ZipException if a ZIP format error has occurred * @throws IOException if an I/O error has occurred * @throws IllegalStateException if the zip file has been closed @@ -368,28 +369,28 @@ public class ZipFile implements ZipConstants, Closeable { } in = new ZipFileInputStream(zsrc.cen, pos); switch (CENHOW(zsrc.cen, pos)) { - case STORED: - synchronized (istreams) { - istreams.add(in); - } - return in; - case DEFLATED: - // Inflater likes a bit of slack - // MORE: Compute good size for inflater stream: - long size = CENLEN(zsrc.cen, pos) + 2; - if (size > 65536) { - size = 8192; - } - if (size <= 0) { - size = 4096; - } - InputStream is = new ZipFileInflaterInputStream(in, res, (int)size); - synchronized (istreams) { - istreams.add(is); - } - return is; - default: - throw new ZipException("invalid compression method"); + case STORED: + synchronized (istreams) { + istreams.add(in); + } + return in; + case DEFLATED: + // Inflater likes a bit of slack + // MORE: Compute good size for inflater stream: + long size = CENLEN(zsrc.cen, pos) + 2; + if (size > 65536) { + size = 8192; + } + if (size <= 0) { + size = 4096; + } + InputStream is = new ZipFileInflaterInputStream(in, res, (int) size); + synchronized (istreams) { + istreams.add(is); + } + return is; + default: + throw new ZipException("invalid compression method"); } } } @@ -1205,8 +1206,17 @@ public class ZipFile implements ZipConstants, Closeable { entries[index++] = hash; entries[index++] = next; entries[index ] = pos; + // Validate comment if it exists + // if the bytes representing the comment cannot be converted to + // a String via zcp.toString, an Exception will be thrown + int clen = CENCOM(cen, pos); + if (clen > 0) { + int elen = CENEXT(cen, pos); + int start = entryPos + nlen + elen; + zcp.toString(cen, start, clen); + } } catch (Exception e) { - zerror("invalid CEN header (bad entry name)"); + zerror("invalid CEN header (bad entry name or comment)"); } return nlen; } @@ -1497,6 +1507,9 @@ public class ZipFile implements ZipConstants, Closeable { zerror("invalid END header (bad central directory offset)"); } // read in the CEN and END + if (end.cenlen + ENDHDR >= Integer.MAX_VALUE) { + zerror("invalid END header (central directory size too large)"); + } cen = this.cen = new byte[(int)(end.cenlen + ENDHDR)]; if (readFullyAt(cen, 0, cen.length, cenpos) != end.cenlen + ENDHDR) { zerror("read CEN tables failed"); diff --git a/src/java.base/share/classes/java/util/zip/ZipInputStream.java b/src/java.base/share/classes/java/util/zip/ZipInputStream.java index 4c1eac3204c0fe9153db69b69fbb9cdc93d7c504..5f740a76655b7d8f6f08d01bc34fac4cd2e6cf16 100644 --- a/src/java.base/share/classes/java/util/zip/ZipInputStream.java +++ b/src/java.base/share/classes/java/util/zip/ZipInputStream.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 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 @@ -30,6 +30,7 @@ import java.io.IOException; import java.io.EOFException; import java.io.PushbackInputStream; import java.nio.charset.Charset; +import java.util.Objects; import sun.nio.cs.UTF_8; @@ -182,9 +183,8 @@ public class ZipInputStream extends InflaterInputStream implements ZipConstants */ public int read(byte[] b, int off, int len) throws IOException { ensureOpen(); - if (off < 0 || len < 0 || off > b.length - len) { - throw new IndexOutOfBoundsException(); - } else if (len == 0) { + Objects.checkFromIndexSize(off, len, b.length); + if (len == 0) { return 0; } diff --git a/src/java.base/share/classes/java/util/zip/ZipOutputStream.java b/src/java.base/share/classes/java/util/zip/ZipOutputStream.java index c6dfa69536e3911ec1f96c110730feddf223697f..d11eb4d4aae51032855b67994c7bb27389d6f757 100644 --- a/src/java.base/share/classes/java/util/zip/ZipOutputStream.java +++ b/src/java.base/share/classes/java/util/zip/ZipOutputStream.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 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 @@ -28,6 +28,7 @@ package java.util.zip; import java.io.OutputStream; import java.io.IOException; import java.nio.charset.Charset; +import java.util.Objects; import java.util.Vector; import java.util.HashSet; import static java.util.zip.ZipConstants64.*; @@ -144,11 +145,14 @@ public class ZipOutputStream extends DeflaterOutputStream implements ZipConstant * ZIP file comment is greater than 0xFFFF bytes */ public void setComment(String comment) { + byte[] bytes = null; if (comment != null) { - this.comment = zc.getBytes(comment); - if (this.comment.length > 0xffff) - throw new IllegalArgumentException("ZIP file comment too long."); + bytes = zc.getBytes(comment); + if (bytes.length > 0xffff) { + throw new IllegalArgumentException("ZIP file comment too long"); + } } + this.comment = bytes; } /** @@ -256,58 +260,64 @@ public class ZipOutputStream extends DeflaterOutputStream implements ZipConstant public void closeEntry() throws IOException { ensureOpen(); if (current != null) { - ZipEntry e = current.entry; - switch (e.method) { - case DEFLATED -> { - def.finish(); - while (!def.finished()) { - deflate(); - } - if ((e.flag & 8) == 0) { - // verify size, compressed size, and crc-32 settings - if (e.size != def.getBytesRead()) { - throw new ZipException( - "invalid entry size (expected " + e.size + - " but got " + def.getBytesRead() + " bytes)"); - } - if (e.csize != def.getBytesWritten()) { - throw new ZipException( - "invalid entry compressed size (expected " + - e.csize + " but got " + def.getBytesWritten() + " bytes)"); + try { + ZipEntry e = current.entry; + switch (e.method) { + case DEFLATED -> { + def.finish(); + while (!def.finished()) { + deflate(); + } + if ((e.flag & 8) == 0) { + // verify size, compressed size, and crc-32 settings + if (e.size != def.getBytesRead()) { + throw new ZipException( + "invalid entry size (expected " + e.size + + " but got " + def.getBytesRead() + " bytes)"); + } + if (e.csize != def.getBytesWritten()) { + throw new ZipException( + "invalid entry compressed size (expected " + + e.csize + " but got " + def.getBytesWritten() + " bytes)"); + } + if (e.crc != crc.getValue()) { + throw new ZipException( + "invalid entry CRC-32 (expected 0x" + + Long.toHexString(e.crc) + " but got 0x" + + Long.toHexString(crc.getValue()) + ")"); + } + } else { + e.size = def.getBytesRead(); + e.csize = def.getBytesWritten(); + e.crc = crc.getValue(); + writeEXT(e); + } + def.reset(); + written += e.csize; } - if (e.crc != crc.getValue()) { - throw new ZipException( - "invalid entry CRC-32 (expected 0x" + - Long.toHexString(e.crc) + " but got 0x" + - Long.toHexString(crc.getValue()) + ")"); + case STORED -> { + // we already know that both e.size and e.csize are the same + if (e.size != written - locoff) { + throw new ZipException( + "invalid entry size (expected " + e.size + + " but got " + (written - locoff) + " bytes)"); + } + if (e.crc != crc.getValue()) { + throw new ZipException( + "invalid entry crc-32 (expected 0x" + + Long.toHexString(e.crc) + " but got 0x" + + Long.toHexString(crc.getValue()) + ")"); + } } - } else { - e.size = def.getBytesRead(); - e.csize = def.getBytesWritten(); - e.crc = crc.getValue(); - writeEXT(e); - } - def.reset(); - written += e.csize; - } - case STORED -> { - // we already know that both e.size and e.csize are the same - if (e.size != written - locoff) { - throw new ZipException( - "invalid entry size (expected " + e.size + - " but got " + (written - locoff) + " bytes)"); - } - if (e.crc != crc.getValue()) { - throw new ZipException( - "invalid entry crc-32 (expected 0x" + - Long.toHexString(e.crc) + " but got 0x" + - Long.toHexString(crc.getValue()) + ")"); + default -> throw new ZipException("invalid compression method"); } + crc.reset(); + current = null; + } catch (IOException e) { + if (def.shouldFinish() && usesDefaultDeflater && !(e instanceof ZipException)) + def.end(); + throw e; } - default -> throw new ZipException("invalid compression method"); - } - crc.reset(); - current = null; } } @@ -324,9 +334,8 @@ public class ZipOutputStream extends DeflaterOutputStream implements ZipConstant throws IOException { ensureOpen(); - if (off < 0 || len < 0 || off > b.length - len) { - throw new IndexOutOfBoundsException(); - } else if (len == 0) { + Objects.checkFromIndexSize(off, len, b.length); + if (len == 0) { return; } diff --git a/src/java.base/share/classes/javax/crypto/Cipher.java b/src/java.base/share/classes/javax/crypto/Cipher.java index 1517ec984ceaf43121cc9b004118e026113da678..a6751e886bdbcf26d538534b35ae036b12e662db 100644 --- a/src/java.base/share/classes/javax/crypto/Cipher.java +++ b/src/java.base/share/classes/javax/crypto/Cipher.java @@ -340,7 +340,7 @@ public class Cipher { "format:" + transformation); } if ((parts[0] == null) || (parts[0].isEmpty())) { - throw new NoSuchAlgorithmException("Invalid transformation:" + + throw new NoSuchAlgorithmException("Invalid transformation: " + "algorithm not specified-" + transformation); } @@ -2833,7 +2833,7 @@ public class Cipher { break; default: // should never happen - sb.append("error:").append(Integer.toString(opmode)); + sb.append("error:").append(opmode); } sb.append(", algorithm from: ").append(getProviderName()); return sb.toString(); diff --git a/src/java.base/share/classes/javax/crypto/CryptoPolicyParser.java b/src/java.base/share/classes/javax/crypto/CryptoPolicyParser.java index 5ccaa8143152b3b995f453f5203edd7a2f6ecd64..5d53bc112c00256e0474fd3f9a6bae4b1d427830 100644 --- a/src/java.base/share/classes/javax/crypto/CryptoPolicyParser.java +++ b/src/java.base/share/classes/javax/crypto/CryptoPolicyParser.java @@ -395,7 +395,7 @@ final class CryptoPolicyParser { switch (lookahead) { case StreamTokenizer.TT_NUMBER: throw new ParsingException(st.lineno(), expect, - "number "+String.valueOf(st.nval)); + "number " + st.nval); case StreamTokenizer.TT_EOF: throw new ParsingException("expected "+expect+", read end of file"); case StreamTokenizer.TT_WORD: diff --git a/src/java.base/share/classes/javax/crypto/EncryptedPrivateKeyInfo.java b/src/java.base/share/classes/javax/crypto/EncryptedPrivateKeyInfo.java index 59b4a07f3497d5af64eaa6d270f20f288e649671..09c69748d5a8da90b8bce9e73eadb464de53af5f 100644 --- a/src/java.base/share/classes/javax/crypto/EncryptedPrivateKeyInfo.java +++ b/src/java.base/share/classes/javax/crypto/EncryptedPrivateKeyInfo.java @@ -77,15 +77,18 @@ public class EncryptedPrivateKeyInfo { * @exception NullPointerException if the encoded is null. * @exception IOException if error occurs when parsing the ASN.1 encoding. */ - public EncryptedPrivateKeyInfo(byte[] encoded) - throws IOException { + public EncryptedPrivateKeyInfo(byte[] encoded) throws IOException { if (encoded == null) { throw new NullPointerException("the encoded parameter " + - "must be non-null"); + "must be non-null"); } - this.encoded = encoded.clone(); - DerValue val = new DerValue(this.encoded); + DerValue val = new DerValue(encoded); + if (val.tag != DerValue.tag_Sequence) { + throw new IOException("DER header error: no SEQ tag"); + } + + this.encoded = encoded.clone(); DerValue[] seq = new DerValue[2]; seq[0] = val.data.getDerValue(); diff --git a/src/java.base/share/classes/javax/crypto/SealedObject.java b/src/java.base/share/classes/javax/crypto/SealedObject.java index 354bc0e8d738288a37eddcde1259d289a25a7734..a1242213e44811a041dfd60135075b72e101e9d8 100644 --- a/src/java.base/share/classes/javax/crypto/SealedObject.java +++ b/src/java.base/share/classes/javax/crypto/SealedObject.java @@ -292,12 +292,9 @@ public class SealedObject implements Serializable { throws IOException, ClassNotFoundException, IllegalBlockSizeException, BadPaddingException { - ObjectInput a = getExtObjectInputStream(c); - try { + try (ObjectInput a = getExtObjectInputStream(c)) { Object obj = a.readObject(); return obj; - } finally { - a.close(); } } @@ -412,12 +409,9 @@ public class SealedObject implements Serializable { throw new RuntimeException(iape.getMessage()); } - ObjectInput a = getExtObjectInputStream(c); - try { + try (ObjectInput a = getExtObjectInputStream(c)) { Object obj = a.readObject(); return obj; - } finally { - a.close(); } } diff --git a/src/java.base/share/classes/javax/net/SocketFactory.java b/src/java.base/share/classes/javax/net/SocketFactory.java index 5d56483b9de78701e246fca1252a89356eacc0cb..285167500b8e987999ef05e4438964a2d741c0fb 100644 --- a/src/java.base/share/classes/javax/net/SocketFactory.java +++ b/src/java.base/share/classes/javax/net/SocketFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -120,12 +120,8 @@ public abstract class SocketFactory // The Exception is used by HttpsClient to signal that // unconnected sockets have not been implemented. // - UnsupportedOperationException uop = new - UnsupportedOperationException(); - SocketException se = new SocketException( - "Unconnected sockets not implemented"); - se.initCause(uop); - throw se; + throw new SocketException("Unconnected sockets not implemented", + new UnsupportedOperationException()); } 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 b3007b2a9a13a4bee8d84c55623f9c81303be021..f60ab53f34e2dd2c15951141f4fbce31746d60cb 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, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -920,9 +920,9 @@ public abstract class SSLEngine { * The returned array includes cipher suites from the list of standard * cipher suite names in the - * JSSE Cipher Suite Names section of the Java Cryptography - * Architecture Standard Algorithm Name Documentation, and may also - * include other cipher suites that the provider supports. + * JSSE Cipher Suite Names section of the Java Security Standard + * Algorithm Names Specification, and may also include other cipher + * suites that the provider supports. * * @return an array of cipher suite names * @see #getEnabledCipherSuites() @@ -946,9 +946,9 @@ public abstract class SSLEngine { * The returned array includes cipher suites from the list of standard * cipher suite names in the - * JSSE Cipher Suite Names section of the Java Cryptography - * Architecture Standard Algorithm Name Documentation, and may also - * include other cipher suites that the provider supports. + * JSSE Cipher Suite Names section of the Java Security Standard + * Algorithm Names Specification, and may also include other cipher + * suites that the provider supports. * * @return an array of cipher suite names * @see #getSupportedCipherSuites() @@ -968,10 +968,10 @@ public abstract class SSLEngine { * Note that the standard list of cipher suite names may be found in the * - * JSSE Cipher Suite Names section of the Java Cryptography - * Architecture Standard Algorithm Name Documentation. Providers - * may support cipher suite names not found in this list or might not - * use the recommended name for a certain cipher suite. + * JSSE Cipher Suite Names section of the Java Security Standard + * Algorithm Names Specification. Providers may support cipher suite + * names not found in this list or might not use the recommended name + * for a certain cipher suite. *

          * See {@link #getEnabledCipherSuites()} for more information * on why a specific cipher suite may never be used on a engine. diff --git a/src/java.base/share/classes/javax/net/ssl/SSLException.java b/src/java.base/share/classes/javax/net/ssl/SSLException.java index c77992db3014ff4793ffb32c56fd280bb0f38b1b..b2e96afa7d62860da2b36187250c2a4751f6d4dd 100644 --- a/src/java.base/share/classes/javax/net/ssl/SSLException.java +++ b/src/java.base/share/classes/javax/net/ssl/SSLException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 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 @@ -36,9 +36,7 @@ import java.io.IOException; * @since 1.4 * @author David Brownell */ -public -class SSLException extends IOException -{ +public class SSLException extends IOException { @java.io.Serial private static final long serialVersionUID = 4511006460650708967L; @@ -48,8 +46,7 @@ class SSLException extends IOException * * @param reason describes the problem. */ - public SSLException(String reason) - { + public SSLException(String reason) { super(reason); } @@ -66,8 +63,7 @@ class SSLException extends IOException * @since 1.5 */ public SSLException(String message, Throwable cause) { - super(message); - initCause(cause); + super(message, cause); } /** @@ -83,7 +79,6 @@ class SSLException extends IOException * @since 1.5 */ public SSLException(Throwable cause) { - super(cause == null ? null : cause.toString()); - initCause(cause); + super(cause); } } diff --git a/src/java.base/share/classes/javax/net/ssl/SSLHandshakeException.java b/src/java.base/share/classes/javax/net/ssl/SSLHandshakeException.java index 5f342b074db855edfd00852777696abc5162810a..e6fa239bdcbbd0eae201a6a4f02580d55632dccc 100644 --- a/src/java.base/share/classes/javax/net/ssl/SSLHandshakeException.java +++ b/src/java.base/share/classes/javax/net/ssl/SSLHandshakeException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 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 @@ -23,10 +23,8 @@ * questions. */ - package javax.net.ssl; - /** * Indicates that the client and server could not negotiate the * desired level of security. The connection is no longer usable. @@ -34,9 +32,7 @@ package javax.net.ssl; * @since 1.4 * @author David Brownell */ -public -class SSLHandshakeException extends SSLException -{ +public class SSLHandshakeException extends SSLException { @java.io.Serial private static final long serialVersionUID = -5045881315018326890L; @@ -46,8 +42,23 @@ class SSLHandshakeException extends SSLException * * @param reason describes the problem. */ - public SSLHandshakeException(String reason) - { + public SSLHandshakeException(String reason) { super(reason); } + + /** + * Creates a {@code SSLHandshakeException} with the specified detail + * message and cause. + * + * @param message the detail message (which is saved for later retrieval + * by the {@link #getMessage()} method). + * @param cause the cause (which is saved for later retrieval by the + * {@link #getCause()} method). (A {@code null} value is + * permitted, and indicates that the cause is nonexistent or + * unknown.) + * @since 19 + */ + public SSLHandshakeException(String message, Throwable cause) { + super(message, cause); + } } diff --git a/src/java.base/share/classes/javax/net/ssl/SSLKeyException.java b/src/java.base/share/classes/javax/net/ssl/SSLKeyException.java index 49fe57c369dbec171d40c38861a02bfa614bbf23..f27c9ee554c6f3156e446482eee9ab080222d42e 100644 --- a/src/java.base/share/classes/javax/net/ssl/SSLKeyException.java +++ b/src/java.base/share/classes/javax/net/ssl/SSLKeyException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 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 @@ -33,9 +33,7 @@ package javax.net.ssl; * @since 1.4 * @author David Brownell */ -public -class SSLKeyException extends SSLException -{ +public class SSLKeyException extends SSLException { @java.io.Serial private static final long serialVersionUID = -8071664081941937874L; @@ -45,8 +43,23 @@ class SSLKeyException extends SSLException * * @param reason describes the problem. */ - public SSLKeyException(String reason) - { + public SSLKeyException(String reason) { super(reason); } + + /** + * Creates a {@code SSLKeyException} with the specified detail + * message and cause. + * + * @param message the detail message (which is saved for later retrieval + * by the {@link #getMessage()} method). + * @param cause the cause (which is saved for later retrieval by the + * {@link #getCause()} method). (A {@code null} value is + * permitted, and indicates that the cause is nonexistent or + * unknown.) + * @since 19 + */ + public SSLKeyException(String message, Throwable cause) { + super(message, cause); + } } 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 b156a8a5dac8d53b7ab9fbf722dd1e1fe4a4f177..b4fbdf9a437927d99617ee23b37f6c69c307058f 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, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -26,31 +26,27 @@ package javax.net.ssl; import java.security.AlgorithmConstraints; -import java.util.Map; -import java.util.List; -import java.util.HashMap; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.LinkedHashMap; +import java.util.*; /** * Encapsulates parameters for an SSL/TLS/DTLS connection. The parameters * are the list of ciphersuites to be accepted in an SSL/TLS/DTLS handshake, * the list of protocols to be allowed, the endpoint identification * algorithm during SSL/TLS/DTLS handshaking, the Server Name Indication (SNI), - * the maximum network packet size, the algorithm constraints and whether - * SSL/TLS/DTLS servers should request or require client authentication, etc. + * the maximum network packet size, the algorithm constraints, the signature + * schemes and whether SSL/TLS/DTLS servers should request or require client + * authentication, etc. *

          - * SSLParameters can be created via the constructors in this class. - * Objects can also be obtained using the {@code getSSLParameters()} - * methods in + * {@code SSLParameter} objects can be created via the constructors in this + * class, and can be described as pre-populated objects. {@code SSLParameter} + * objects can also be obtained using the {@code getSSLParameters()} methods in * {@link SSLSocket#getSSLParameters SSLSocket} and * {@link SSLServerSocket#getSSLParameters SSLServerSocket} and * {@link SSLEngine#getSSLParameters SSLEngine} or the * {@link SSLContext#getDefaultSSLParameters getDefaultSSLParameters()} and * {@link SSLContext#getSupportedSSLParameters getSupportedSSLParameters()} - * methods in {@code SSLContext}. + * methods in {@code SSLContext}, and can be described as connection populated + * objects. *

          * SSLParameters can be applied to a connection via the methods * {@link SSLSocket#setSSLParameters SSLSocket.setSSLParameters()} and @@ -82,22 +78,23 @@ public class SSLParameters { private boolean needClientAuth; private String identificationAlgorithm; private AlgorithmConstraints algorithmConstraints; - private Map sniNames = null; - private Map sniMatchers = null; + private List sniNames = null; // immutable list + private Collection sniMatchers = null; // immutable collection private boolean preferLocalCipherSuites; private boolean enableRetransmissions = true; private int maximumPacketSize = 0; private String[] applicationProtocols = new String[0]; + private String[] signatureSchemes = null; /** * Constructs SSLParameters. *

          * The values of cipherSuites, protocols, cryptographic algorithm - * constraints, endpoint identification algorithm, server names and - * server name matchers are set to {@code null}; useCipherSuitesOrder, - * wantClientAuth and needClientAuth are set to {@code false}; - * enableRetransmissions is set to {@code true}; maximum network packet - * size is set to {@code 0}. + * constraints, endpoint identification algorithm, signature schemes, + * server names and server name matchers are set to {@code null}; + * useCipherSuitesOrder, wantClientAuth and needClientAuth are set + * to {@code false}; enableRetransmissions is set to {@code true}; + * maximum network packet size is set to {@code 0}. */ public SSLParameters() { // empty @@ -111,9 +108,9 @@ public class SSLParameters { * {@code setCipherSuites(cipherSuites);}. Note that the * standard list of cipher suite names may be found in the - * JSSE Cipher Suite Names section of the Java Cryptography - * Architecture Standard Algorithm Name Documentation. Providers - * may support cipher suite names not found in this list. + * JSSE Cipher Suite Names section of the Java Security Standard + * Algorithm Names Specification. Providers may support cipher suite + * names not found in this list. * * @param cipherSuites the array of ciphersuites (or null) */ @@ -131,9 +128,9 @@ public class SSLParameters { * Note that the standard list of cipher suite names may be found in the * - * JSSE Cipher Suite Names section of the Java Cryptography - * Architecture Standard Algorithm Name Documentation. Providers - * may support cipher suite names not found in this list. + * JSSE Cipher Suite Names section of the Java Security Standard + * Algorithm Names Specification. Providers may support cipher suite + * names not found in this list. * * @param cipherSuites the array of ciphersuites (or null) * @param protocols the array of protocols (or null) @@ -154,9 +151,9 @@ public class SSLParameters { * The returned array includes cipher suites from the list of standard * cipher suite names in the - * JSSE Cipher Suite Names section of the Java Cryptography - * Architecture Standard Algorithm Name Documentation, and may also - * include other cipher suites that the provider supports. + * JSSE Cipher Suite Names section of the Java Security Standard + * Algorithm Names Specification, and may also include other cipher suites + * that the provider supports. * * @return a copy of the array of ciphersuites or null if none * have been set. @@ -171,10 +168,10 @@ public class SSLParameters { * @param cipherSuites the array of ciphersuites (or null). Note that the * standard list of cipher suite names may be found in the - * JSSE Cipher Suite Names section of the Java Cryptography - * Architecture Standard Algorithm Name Documentation. Providers - * may support cipher suite names not found in this list or might not - * use the recommended name for a certain cipher suite. + * JSSE Cipher Suite Names section of the Java Security Standard + * Algorithm Names Specification. Providers may support cipher suite + * names not found in this list or might not use the recommended name + * for a certain cipher suite. */ public void setCipherSuites(String[] cipherSuites) { this.cipherSuites = clone(cipherSuites); @@ -332,22 +329,29 @@ public class SSLParameters { * @since 1.8 */ public final void setServerNames(List serverNames) { - if (serverNames != null) { - if (!serverNames.isEmpty()) { - sniNames = new LinkedHashMap<>(serverNames.size()); - for (SNIServerName serverName : serverNames) { - if (sniNames.put(serverName.getType(), - serverName) != null) { - throw new IllegalArgumentException( - "Duplicated server name of type " + + if (this.sniNames == serverNames) { + return; + } + + if (serverNames == null) { + sniNames = null; + } else if (serverNames.isEmpty()) { + sniNames = Collections.emptyList(); + } else { + List sniTypes = new ArrayList<>(serverNames.size()); + List sniValues = new ArrayList<>(serverNames.size()); + for (SNIServerName serverName : serverNames) { + if (sniTypes.contains(serverName.getType())) { + throw new IllegalArgumentException( + "Duplicated server name of type " + serverName.getType()); - } + } else { + sniTypes.add(serverName.getType()); + sniValues.add(serverName); } - } else { - sniNames = Collections.emptyMap(); } - } else { - sniNames = null; + + sniNames = Collections.unmodifiableList(sniValues); } } @@ -366,7 +370,7 @@ public class SSLParameters { *

          * It is recommended that providers initialize default Server Name * Indications when creating {@code SSLSocket}/{@code SSLEngine}s. - * In the following examples, the server name could be represented by an + * In the following examples, the server name may be represented by an * instance of {@link SNIHostName} which has been initialized with the * hostname "www.example.com" and type * {@link StandardConstants#SNI_HOST_NAME}. @@ -389,16 +393,7 @@ public class SSLParameters { * @since 1.8 */ public final List getServerNames() { - if (sniNames != null) { - if (!sniNames.isEmpty()) { - return Collections.unmodifiableList( - new ArrayList<>(sniNames.values())); - } else { - return Collections.emptyList(); - } - } - - return null; + return sniNames; } /** @@ -426,22 +421,29 @@ public class SSLParameters { * @since 1.8 */ public final void setSNIMatchers(Collection matchers) { - if (matchers != null) { - if (!matchers.isEmpty()) { - sniMatchers = new HashMap<>(matchers.size()); - for (SNIMatcher matcher : matchers) { - if (sniMatchers.put(matcher.getType(), - matcher) != null) { - throw new IllegalArgumentException( - "Duplicated server name of type " + - matcher.getType()); - } + if (this.sniMatchers == matchers) { + return; + } + + if (matchers == null) { + this.sniMatchers = null; + } else if (matchers.isEmpty()) { + sniMatchers = Collections.emptyList(); + } else { + List matcherTypes = new ArrayList<>(matchers.size()); + List matcherValues = new ArrayList<>(matchers.size()); + for (SNIMatcher matcher : matchers) { + if (matcherTypes.contains(matcher.getType())) { + throw new IllegalArgumentException( + "Duplicated server name of type " + + matcher.getType()); + } else { + matcherTypes.add(matcher.getType()); + matcherValues.add(matcher); } - } else { - sniMatchers = Collections.emptyMap(); } - } else { - sniMatchers = null; + + this.sniMatchers = Collections.unmodifiableList(matcherValues); } } @@ -464,16 +466,7 @@ public class SSLParameters { * @since 1.8 */ public final Collection getSNIMatchers() { - if (sniMatchers != null) { - if (!sniMatchers.isEmpty()) { - return Collections.unmodifiableList( - new ArrayList<>(sniMatchers.values())); - } else { - return Collections.emptyList(); - } - } - - return null; + return sniMatchers; } /** @@ -617,7 +610,7 @@ public class SSLParameters { * * @return a non-null, possibly zero-length array of application protocol * {@code String}s. The array is ordered based on protocol - * preference, with {@code protocols[0]} being the most preferred. + * preference, with the first entry being the most preferred. * @see #setApplicationProtocols * @since 9 */ @@ -696,4 +689,125 @@ public class SSLParameters { } applicationProtocols = tempProtocols; } + + /** + * Returns a prioritized array of signature scheme names that can be used + * over the SSL/TLS/DTLS protocols. + *

          + * Note that the standard list of signature scheme names are defined in + * the + * Signature Schemes section of the Java Security Standard Algorithm + * Names Specification. Providers may support signature schemes not defined + * in this list or may not use the recommended name for a certain + * signature scheme. + *

          + * The set of signature schemes that will be used over the SSL/TLS/DTLS + * connections is determined by the returned array of this method and the + * underlying provider-specific default signature schemes. + *

          + * If the returned array is {@code null}, then the underlying + * provider-specific default signature schemes will be used over the + * SSL/TLS/DTLS connections. + *

          + * If the returned array is empty (zero-length), then the signature scheme + * negotiation mechanism is turned off for SSL/TLS/DTLS protocols, and + * the connections may not be able to be established if the negotiation + * mechanism is required by a certain SSL/TLS/DTLS protocol. This + * parameter will override the underlying provider-specific default + * signature schemes. + *

          + * If the returned array is not {@code null} or empty (zero-length), + * then the signature schemes in the returned array will be used over + * the SSL/TLS/DTLS connections. This parameter will override the + * underlying provider-specific default signature schemes. + *

          + * This method returns the most recent value passed to + * {@link #setSignatureSchemes} if that method has been called and + * otherwise returns the default signature schemes for connection + * populated objects, or {@code null} for pre-populated objects. + * + * @apiNote + * Note that a provider may not have been updated to support this method + * and in that case may return {@code null} instead of the default + * signature schemes for connection populated objects. + * + * @implNote + * The SunJSSE provider supports this method. + * + * @implNote + * Note that applications may use the + * {@systemProperty jdk.tls.client.SignatureSchemes} and/or + * {@systemProperty jdk.tls.server.SignatureSchemes} system properties + * with the SunJSSE provider to override the provider-specific default + * signature schemes. + * + * @return an array of signature scheme {@code Strings} or {@code null} if + * none have been set. For non-null returns, this method will + * return a new array each time it is invoked. The array is + * ordered based on signature scheme preference, with the first + * entry being the most preferred. Providers should ignore unknown + * signature scheme names while establishing the SSL/TLS/DTLS + * connections. + * @see #setSignatureSchemes + * + * @since 19 + */ + public String[] getSignatureSchemes() { + return clone(signatureSchemes); + } + + /** + * Sets the prioritized array of signature scheme names that + * can be used over the SSL/TLS/DTLS protocols. + *

          + * Note that the standard list of signature scheme names are defined in + * the + * Signature Schemes section of the Java Security Standard Algorithm + * Names Specification. Providers may support signature schemes not + * defined in this list or may not use the recommended name for a certain + * signature scheme. + *

          + * The set of signature schemes that will be used over the SSL/TLS/DTLS + * connections is determined by the input parameter {@code signatureSchemes} + * array and the underlying provider-specific default signature schemes. + * See {@link #getSignatureSchemes} for specific details on how the + * parameters are used in SSL/TLS/DTLS connections. + * + * @apiNote + * Note that a provider may not have been updated to support this method + * and in that case may ignore the schemes that are set. + * + * @implNote + * The SunJSSE provider supports this method. + * + * @param signatureSchemes an ordered array of signature scheme names with + * the first entry being the most preferred, or {@code null}. This + * method will make a copy of this array. Providers should ignore + * unknown signature scheme names while establishing the + * SSL/TLS/DTLS connections. + * @throws IllegalArgumentException if any element in the + * {@code signatureSchemes} array is {@code null} or + * {@linkplain String#isBlank() blank}. + * + * @see #getSignatureSchemes + * + * @since 19 + */ + public void setSignatureSchemes(String[] signatureSchemes) { + String[] tempSchemes = null; + + if (signatureSchemes != null) { + tempSchemes = signatureSchemes.clone(); + for (String scheme : tempSchemes) { + if (scheme == null || scheme.isBlank()) { + throw new IllegalArgumentException( + "An element of signatureSchemes is null or blank"); + } + } + } + + this.signatureSchemes = tempSchemes; + } } diff --git a/src/java.base/share/classes/javax/net/ssl/SSLPeerUnverifiedException.java b/src/java.base/share/classes/javax/net/ssl/SSLPeerUnverifiedException.java index e98e2b4b7f46b6cef6dcddd4f42ea9473bf20d90..3fbec6c04345a24a8167cc4ebf928abc674437ae 100644 --- a/src/java.base/share/classes/javax/net/ssl/SSLPeerUnverifiedException.java +++ b/src/java.base/share/classes/javax/net/ssl/SSLPeerUnverifiedException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 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 @@ -39,9 +39,7 @@ package javax.net.ssl; * @since 1.4 * @author David Brownell */ -public -class SSLPeerUnverifiedException extends SSLException -{ +public class SSLPeerUnverifiedException extends SSLException { @java.io.Serial private static final long serialVersionUID = -8919512675000600547L; @@ -51,8 +49,23 @@ class SSLPeerUnverifiedException extends SSLException * * @param reason describes the problem. */ - public SSLPeerUnverifiedException(String reason) - { + public SSLPeerUnverifiedException(String reason) { super(reason); } + + /** + * Creates a {@code SSLPeerUnverifiedException} with the specified detail + * message and cause. + * + * @param message the detail message (which is saved for later retrieval + * by the {@link #getMessage()} method). + * @param cause the cause (which is saved for later retrieval by the + * {@link #getCause()} method). (A {@code null} value is + * permitted, and indicates that the cause is nonexistent or + * unknown.) + * @since 19 + */ + public SSLPeerUnverifiedException(String message, Throwable cause) { + super(message, cause); + } } diff --git a/src/java.base/share/classes/javax/net/ssl/SSLProtocolException.java b/src/java.base/share/classes/javax/net/ssl/SSLProtocolException.java index a39b2048924977dfcf382462d59dccb457895c82..bf590430b3fffc8378149048b364871fe29e81d5 100644 --- a/src/java.base/share/classes/javax/net/ssl/SSLProtocolException.java +++ b/src/java.base/share/classes/javax/net/ssl/SSLProtocolException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 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 @@ -33,9 +33,7 @@ package javax.net.ssl; * @since 1.4 * @author David Brownell */ -public -class SSLProtocolException extends SSLException -{ +public class SSLProtocolException extends SSLException { @java.io.Serial private static final long serialVersionUID = 5445067063799134928L; @@ -45,8 +43,23 @@ class SSLProtocolException extends SSLException * * @param reason describes the problem. */ - public SSLProtocolException(String reason) - { + public SSLProtocolException(String reason) { super(reason); } + + /** + * Creates a {@code SSLProtocolException} with the specified detail + * message and cause. + * + * @param message the detail message (which is saved for later retrieval + * by the {@link #getMessage()} method). + * @param cause the cause (which is saved for later retrieval by the + * {@link #getCause()} method). (A {@code null} value is + * permitted, and indicates that the cause is nonexistent or + * unknown.) + * @since 19 + */ + public SSLProtocolException(String message, Throwable cause) { + super(message, cause); + } } diff --git a/src/java.base/share/classes/javax/net/ssl/SSLServerSocket.java b/src/java.base/share/classes/javax/net/ssl/SSLServerSocket.java index 00a8bed19f091a40f230cce941e6a1e6e33c547d..20d7e7af676a1b37c47a4047827480333a401232 100644 --- a/src/java.base/share/classes/javax/net/ssl/SSLServerSocket.java +++ b/src/java.base/share/classes/javax/net/ssl/SSLServerSocket.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -197,9 +197,9 @@ public abstract class SSLServerSocket extends ServerSocket { * The returned array includes cipher suites from the list of standard * cipher suite names in the - * JSSE Cipher Suite Names section of the Java Cryptography - * Architecture Standard Algorithm Name Documentation, and may also - * include other cipher suites that the provider supports. + * JSSE Cipher Suite Names section of the Java Security Standard + * Algorithm Names Specification, and may also include other cipher + * suites that the provider supports. * * @return an array of cipher suites enabled * @see #getSupportedCipherSuites() @@ -223,10 +223,10 @@ public abstract class SSLServerSocket extends ServerSocket { * Note that the standard list of cipher suite names may be found in the * - * JSSE Cipher Suite Names section of the Java Cryptography - * Architecture Standard Algorithm Name Documentation. Providers - * may support cipher suite names not found in this list or might not - * use the recommended name for a certain cipher suite. + * JSSE Cipher Suite Names section of the Java Security Standard + * Algorithm Names Specification. Providers may support cipher suite + * names not found in this list or might not use the recommended name + * for a certain cipher suite. *

          * SSLSockets returned from accept() * inherit this setting. @@ -253,9 +253,9 @@ public abstract class SSLServerSocket extends ServerSocket { * The returned array includes cipher suites from the list of standard * cipher suite names in the - * JSSE Cipher Suite Names section of the Java Cryptography - * Architecture Standard Algorithm Name Documentation, and may also - * include other cipher suites that the provider supports. + * JSSE Cipher Suite Names section of the Java Security Standard + * Algorithm Names Specification, and may also include other cipher + * suites that the provider supports. * * @return an array of cipher suite names * @see #getEnabledCipherSuites() diff --git a/src/java.base/share/classes/javax/net/ssl/SSLServerSocketFactory.java b/src/java.base/share/classes/javax/net/ssl/SSLServerSocketFactory.java index e66bd11239d9192a7aae6b38f7c57c1cc40b0fee..22f64f98f29fce57193e2c2153f8ae1e1dc5929a 100644 --- a/src/java.base/share/classes/javax/net/ssl/SSLServerSocketFactory.java +++ b/src/java.base/share/classes/javax/net/ssl/SSLServerSocketFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -87,9 +87,9 @@ public abstract class SSLServerSocketFactory extends ServerSocketFactory { * The returned array includes cipher suites from the list of standard * cipher suite names in the - * JSSE Cipher Suite Names section of the Java Cryptography - * Architecture Standard Algorithm Name Documentation, and may also - * include other cipher suites that the provider supports. + * JSSE Cipher Suite Names section of the Java Security Standard + * Algorithm Names Specification, and may also include other cipher + * suites that the provider supports. * * @see #getSupportedCipherSuites() * @return array of the cipher suites enabled by default @@ -108,9 +108,9 @@ public abstract class SSLServerSocketFactory extends ServerSocketFactory { * The returned array includes cipher suites from the list of standard * cipher suite names in the - * JSSE Cipher Suite Names section of the Java Cryptography - * Architecture Standard Algorithm Name Documentation, and may also - * include other cipher suites that the provider supports. + * JSSE Cipher Suite Names section of the Java Security Standard + * Algorithm Names Specification, and may also include other cipher + * suites that the provider supports. * * @return an array of cipher suite names * @see #getDefaultCipherSuites() @@ -173,8 +173,7 @@ class DefaultSSLServerSocketFactory extends SSLServerSocketFactory { } private ServerSocket throwException() throws SocketException { - throw (SocketException) - new SocketException(reason.toString()).initCause(reason); + throw new SocketException(reason.toString(), reason); } @Override 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 84e5be716feab684ff7852f0f5a2fa3596cefaef..e5cdd3741b944ab2eebff261240458dd376e7736 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, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -174,17 +174,19 @@ import java.util.function.BiFunction; * @apiNote * When the connection is no longer needed, the client and server * applications should each close both sides of their respective connection. - * For {@code SSLSocket} objects, for example, an application can call - * {@link Socket#shutdownOutput()} or {@link java.io.OutputStream#close()} - * for output stream close and call {@link Socket#shutdownInput()} or - * {@link java.io.InputStream#close()} for input stream close. Note that - * in some cases, closing the input stream may depend on the peer's output - * stream being closed first. If the connection is not closed in an orderly - * manner (for example {@link Socket#shutdownInput()} is called before the - * peer's write closure notification has been received), exceptions may - * be raised to indicate that an error has occurred. Once an - * {@code SSLSocket} is closed, it is not reusable: a new {@code SSLSocket} - * must be created. + * This can be done either in one shot by calling {@link Socket#close()}, + * or by closing each side individually using + * {@link Socket#shutdownOutput()} / {@link Socket#shutdownInput()} which is + * useful for protocol versions that can support half-closed connections. + * + *

          Note that in some cases, closing the input stream may depend on the + * peer's output stream being closed first. If the connection is not closed + * in an orderly manner (for example {@link Socket#shutdownInput()} is called + * before the peer's write closure notification has been received), exceptions + * may be raised to indicate that an error has occurred. + * + *

          Once an {@code SSLSocket} is closed, it is not reusable: a new + * {@code SSLSocket} must be created. * * @see java.net.Socket * @see SSLServerSocket @@ -327,9 +329,9 @@ public abstract class SSLSocket extends Socket * The returned array includes cipher suites from the list of standard * cipher suite names in the - * JSSE Cipher Suite Names section of the Java Cryptography - * Architecture Standard Algorithm Name Documentation, and may also - * include other cipher suites that the provider supports. + * JSSE Cipher Suite Names section of the Java Security Standard + * Algorithm Names Specification, and may also include other cipher + * suites that the provider supports. * * @return an array of cipher suite names * @see #getEnabledCipherSuites() @@ -353,9 +355,9 @@ public abstract class SSLSocket extends Socket * The returned array includes cipher suites from the list of standard * cipher suite names in the - * JSSE Cipher Suite Names section of the Java Cryptography - * Architecture Standard Algorithm Name Documentation, and may also - * include other cipher suites that the provider supports. + * JSSE Cipher Suite Names section of the Java Security Standard + * Algorithm Names Specification, and may also include other cipher + * suites that the provider supports. * * @return an array of cipher suite names * @see #getSupportedCipherSuites() @@ -375,10 +377,10 @@ public abstract class SSLSocket extends Socket * Note that the standard list of cipher suite names may be found in the * - * JSSE Cipher Suite Names section of the Java Cryptography - * Architecture Standard Algorithm Name Documentation. Providers - * may support cipher suite names not found in this list or might not - * use the recommended name for a certain cipher suite. + * JSSE Cipher Suite Names section of the Java Security Standard + * Algorithm Names Specification. Providers may support cipher suite + * names not found in this list or might not use the recommended name + * for a certain cipher suite. *

          * See {@link #getEnabledCipherSuites()} for more information * on why a specific ciphersuite may never be used on a connection. 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 6db6d740750d15eebaa1e8beba7a719f58eefda0..6a01687dc56fb004b7751b3a421174ec3a09f49c 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, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -113,9 +113,9 @@ public abstract class SSLSocketFactory extends SocketFactory { * The returned array includes cipher suites from the list of standard * cipher suite names in the - * JSSE Cipher Suite Names section of the Java Cryptography - * Architecture Standard Algorithm Name Documentation, and may also - * include other cipher suites that the provider supports. + * JSSE Cipher Suite Names section of the Java Security Standard + * Algorithm Names Specification, and may also include other cipher suites + * that the provider supports. * * @see #getSupportedCipherSuites() * @return array of the cipher suites enabled by default @@ -132,9 +132,9 @@ public abstract class SSLSocketFactory extends SocketFactory { * The returned array includes cipher suites from the list of standard * cipher suite names in the - * JSSE Cipher Suite Names section of the Java Cryptography - * Architecture Standard Algorithm Name Documentation, and may also - * include other cipher suites that the provider supports. + * JSSE Cipher Suite Names section of the Java Security Standard + * Algorithm Names Specification, and may also include other cipher suites + * that the provider supports. * * @see #getDefaultCipherSuites() * @return an array of cipher suite names @@ -263,8 +263,7 @@ class DefaultSSLSocketFactory extends SSLSocketFactory } private Socket throwException() throws SocketException { - throw (SocketException) - new SocketException(reason.toString()).initCause(reason); + throw new SocketException(reason.toString(), reason); } @Override diff --git a/src/java.base/share/classes/javax/security/auth/Subject.java b/src/java.base/share/classes/javax/security/auth/Subject.java index 8e30f84ff4467114ded80e4b21792b245eb03770..c1235bffd532f34d9f7dd02faf1c8a8271a9fc6a 100644 --- a/src/java.base/share/classes/javax/security/auth/Subject.java +++ b/src/java.base/share/classes/javax/security/auth/Subject.java @@ -402,6 +402,7 @@ public final class Subject implements java.io.Serializable { */ public static T callAs(final Subject subject, final Callable action) throws CompletionException { + Objects.requireNonNull(action); if (USE_TL) { Subject oldSubject = SUBJECT_THREAD_LOCAL.get(); SUBJECT_THREAD_LOCAL.set(subject); diff --git a/src/java.base/share/classes/jdk/internal/access/JavaLangInvokeAccess.java b/src/java.base/share/classes/jdk/internal/access/JavaLangInvokeAccess.java index ee655188c9d3e4dc9174c9f03dbecf053c862c23..20823fcfcad90f1f73385664450059211ead423c 100644 --- a/src/java.base/share/classes/jdk/internal/access/JavaLangInvokeAccess.java +++ b/src/java.base/share/classes/jdk/internal/access/JavaLangInvokeAccess.java @@ -181,4 +181,11 @@ public interface JavaLangInvokeAccess { * The given bytes is trusted. */ Lookup defineHiddenClassWithClassData(Lookup caller, String name, byte[] bytes, Object classData, boolean initialize); + + /** + * A best-effort method that tries to find any exceptions thrown by the given method handle. + * @param handle the handle to check + * @return an array of exceptions, or {@code null}. + */ + Class[] exceptionTypes(MethodHandle handle); } diff --git a/src/java.base/share/classes/jdk/internal/access/JavaLangReflectAccess.java b/src/java.base/share/classes/jdk/internal/access/JavaLangReflectAccess.java index 4082fae336fe7807017823838698934ebe720789..9e3ce846f02498b58fbc294a64cd4bf612743fd5 100644 --- a/src/java.base/share/classes/jdk/internal/access/JavaLangReflectAccess.java +++ b/src/java.base/share/classes/jdk/internal/access/JavaLangReflectAccess.java @@ -102,4 +102,11 @@ public interface JavaLangReflectAccess { /** Returns a new instance created by the given constructor with access check */ public T newInstance(Constructor ctor, Object[] args, Class caller) throws IllegalAccessException, InstantiationException, InvocationTargetException; + + /** Invokes the given default method if the method's declaring interface is + * accessible to the given caller. Otherwise, IllegalAccessException will + * be thrown. If the caller is null, no access check is performed. + */ + public Object invokeDefault(Object proxy, Method method, Object[] args, Class caller) + throws Throwable; } diff --git a/src/java.base/share/classes/jdk/internal/access/JavaNioAccess.java b/src/java.base/share/classes/jdk/internal/access/JavaNioAccess.java index c639e4ced83217cbbb5d36cd1c018e686d8f0f56..82739b9bf074ca56a53c491bfd5f6ae5a954e6c0 100644 --- a/src/java.base/share/classes/jdk/internal/access/JavaNioAccess.java +++ b/src/java.base/share/classes/jdk/internal/access/JavaNioAccess.java @@ -92,7 +92,7 @@ public interface JavaNioAccess { * scope handle. Null is returned if the buffer has no scope, or * acquiring is not required to guarantee safety. */ - Scope.Handle acquireScope(Buffer buffer, boolean async); + Runnable acquireScope(Buffer buffer, boolean async); /** * Used by {@code jdk.internal.foreign.MappedMemorySegmentImpl} and byte buffer var handle views. diff --git a/src/java.base/share/classes/jdk/internal/access/foreign/MemorySegmentProxy.java b/src/java.base/share/classes/jdk/internal/access/foreign/MemorySegmentProxy.java index a00b6516a55bc13de48658de94fd7cfd34aae17d..068fcfa1a6b50bea45bcfff29c7d70c0c5eb269a 100644 --- a/src/java.base/share/classes/jdk/internal/access/foreign/MemorySegmentProxy.java +++ b/src/java.base/share/classes/jdk/internal/access/foreign/MemorySegmentProxy.java @@ -44,6 +44,7 @@ public abstract class MemorySegmentProxy { public abstract Object unsafeGetBase(); public abstract boolean isSmall(); public abstract ScopedMemoryAccess.Scope scope(); + public abstract long maxAlignMask(); /* Helper functions for offset computations. These are required so that we can avoid issuing long opcodes * (e.g. LMUL, LADD) when we're operating on 'small' segments (segments whose length can be expressed with an int). diff --git a/src/java.base/share/classes/jdk/internal/icu/impl/Punycode.java b/src/java.base/share/classes/jdk/internal/icu/impl/Punycode.java index 52f6e546f3ae379e3744322904e60b01f1a6695c..6fe1ebcc54677d32cf2e6a9f8758c41925f10ec7 100644 --- a/src/java.base/share/classes/jdk/internal/icu/impl/Punycode.java +++ b/src/java.base/share/classes/jdk/internal/icu/impl/Punycode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -76,9 +76,6 @@ public final class Punycode { // TODO: eliminate the 256 limitation private static final int MAX_CP_COUNT = 256; - private static final int UINT_MAGIC = 0x80000000; - private static final long ULONG_MAGIC = 0x8000000000000000L; - private static int adaptBias(int delta, int length, boolean firstTime){ if(firstTime){ delta /=DAMP; @@ -96,34 +93,25 @@ public final class Punycode { } /** - * basicToDigit[] contains the numeric value of a basic code - * point (for use in representing integers) in the range 0 to - * BASE-1, or -1 if b is does not represent a value. + * @return the numeric value of a basic code point (for use in representing integers) + * in the range 0 to BASE-1, or a negative value if cp is invalid. */ - static final int[] basicToDigit= new int[]{ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, -1, - - -1, 0, 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, -1, -1, -1, -1, -1, - - -1, 0, 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, -1, -1, -1, -1, -1, - - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 + private static final int decodeDigit(int cp) { + if(cp<='Z') { + if(cp<='9') { + if(cp<'0') { + return -1; + } else { + return cp-'0'+26; // 0..9 -> 26..35 + } + } else { + return cp-'A'; // A-Z -> 0..25 + } + } else if(cp<='z') { + return cp-'a'; // a..z -> 0..25 + } else { + return -1; + } }; private static char asciiCaseMap(char b, boolean uppercase) { @@ -158,6 +146,12 @@ public final class Punycode { return (char)((ZERO-26)+digit); } } + + // ICU-13727: Limit input length for n^2 algorithm + // where well-formed strings are at most 59 characters long. + private static final int ENCODE_MAX_CODE_UNITS = 1000; + private static final int DECODE_MAX_CHARS = 2000; + /** * Converts Unicode to Punycode. * The input string must not contain single, unpaired surrogates. @@ -174,6 +168,10 @@ public final class Punycode { int n, delta, handledCPCount, basicLength, destLength, bias, j, m, q, k, t, srcCPCount; char c, c2; int srcLength = src.length(); + if (srcLength > ENCODE_MAX_CODE_UNITS) { + throw new RuntimeException( + "input too long: " + srcLength + " UTF-16 code units"); + } int destCapacity = MAX_CP_COUNT; char[] dest = new char[destCapacity]; StringBuffer result = new StringBuffer(); @@ -251,7 +249,7 @@ public final class Punycode { * Increase delta enough to advance the decoder's * state to , but guard against overflow: */ - if(m-n>(0x7fffffff-MAX_CP_COUNT-delta)/(handledCPCount+1)) { + if(m-n>(0x7fffffff-handledCPCount-delta)/(handledCPCount+1)) { throw new RuntimeException("Internal program error"); } delta+=(m-n)*(handledCPCount+1); @@ -332,6 +330,9 @@ public final class Punycode { public static StringBuffer decode(StringBuffer src, boolean[] caseFlags) throws ParseException{ int srcLength = src.length(); + if (srcLength > DECODE_MAX_CHARS) { + throw new RuntimeException("input too long: " + srcLength + " characters"); + } StringBuffer result = new StringBuffer(); int n, destLength, i, bias, basicLength, j, in, oldi, w, k, digit, t, destCPCount, firstSupplementaryIndex, cpLength; @@ -395,7 +396,7 @@ public final class Punycode { throw new ParseException("Illegal char found", -1); } - digit=basicToDigit[(byte)src.charAt(in++)]; + digit=decodeDigit(src.charAt(in++)); if(digit<0) { throw new ParseException("Invalid char found", -1); } diff --git a/src/java.base/share/classes/jdk/internal/icu/impl/UnicodeSetStringSpan.java b/src/java.base/share/classes/jdk/internal/icu/impl/UnicodeSetStringSpan.java index ee5e80dd8830f783536f4ba3a16f5ec7aa9f1041..331ab234f5954e3be18be1d7e7ad4704d26fe6ba 100644 --- a/src/java.base/share/classes/jdk/internal/icu/impl/UnicodeSetStringSpan.java +++ b/src/java.base/share/classes/jdk/internal/icu/impl/UnicodeSetStringSpan.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -134,9 +134,15 @@ public class UnicodeSetStringSpan { int i, spanLength; someRelevant = false; - for (i = 0; i < stringsLength; ++i) { + for (i = 0; i < stringsLength;) { String string = strings.get(i); int length16 = string.length(); + if (length16 == 0) { + // Remove the empty string. + strings.remove(i); + --stringsLength; + continue; + } spanLength = spanSet.span(string, SpanCondition.CONTAINED); if (spanLength < length16) { // Relevant string. someRelevant = true; @@ -144,6 +150,7 @@ public class UnicodeSetStringSpan { if (/* (0 != (which & UTF16)) && */ length16 > maxLength16) { maxLength16 = length16; } + ++i; } if (!someRelevant && (which & WITH_COUNT) == 0) { return; diff --git a/src/java.base/share/classes/jdk/internal/icu/impl/data/icudt67b/uprops.icu b/src/java.base/share/classes/jdk/internal/icu/impl/data/icudt67b/uprops.icu deleted file mode 100644 index ee08ff5b011d49d5866413c5856f37f58b0ab8cc..0000000000000000000000000000000000000000 Binary files a/src/java.base/share/classes/jdk/internal/icu/impl/data/icudt67b/uprops.icu and /dev/null differ diff --git a/src/java.base/share/classes/jdk/internal/icu/impl/data/icudt67b/nfc.nrm b/src/java.base/share/classes/jdk/internal/icu/impl/data/icudt70b/nfc.nrm similarity index 86% rename from src/java.base/share/classes/jdk/internal/icu/impl/data/icudt67b/nfc.nrm rename to src/java.base/share/classes/jdk/internal/icu/impl/data/icudt70b/nfc.nrm index 45c260858f9aea1031520e13b6087be76b6c9301..b42accf8ad174cb046bf609e13179e1b3c2ec70e 100644 Binary files a/src/java.base/share/classes/jdk/internal/icu/impl/data/icudt67b/nfc.nrm and b/src/java.base/share/classes/jdk/internal/icu/impl/data/icudt70b/nfc.nrm differ diff --git a/src/java.base/share/classes/jdk/internal/icu/impl/data/icudt67b/nfkc.nrm b/src/java.base/share/classes/jdk/internal/icu/impl/data/icudt70b/nfkc.nrm similarity index 67% rename from src/java.base/share/classes/jdk/internal/icu/impl/data/icudt67b/nfkc.nrm rename to src/java.base/share/classes/jdk/internal/icu/impl/data/icudt70b/nfkc.nrm index 2c0587b6d455a6221287faf70600adcea6a7ef7b..450b6ed323b8ecd52cffd1f91c59bc284fdeb161 100644 Binary files a/src/java.base/share/classes/jdk/internal/icu/impl/data/icudt67b/nfkc.nrm and b/src/java.base/share/classes/jdk/internal/icu/impl/data/icudt70b/nfkc.nrm differ diff --git a/src/java.base/share/classes/jdk/internal/icu/impl/data/icudt67b/ubidi.icu b/src/java.base/share/classes/jdk/internal/icu/impl/data/icudt70b/ubidi.icu similarity index 63% rename from src/java.base/share/classes/jdk/internal/icu/impl/data/icudt67b/ubidi.icu rename to src/java.base/share/classes/jdk/internal/icu/impl/data/icudt70b/ubidi.icu index bec7b093064530bb5049258a4280cf55a113ec8a..b125866b8e2d907c50bcd715e3174bbf1796c03a 100644 Binary files a/src/java.base/share/classes/jdk/internal/icu/impl/data/icudt67b/ubidi.icu and b/src/java.base/share/classes/jdk/internal/icu/impl/data/icudt70b/ubidi.icu differ diff --git a/src/java.base/share/classes/jdk/internal/icu/impl/data/icudt70b/uprops.icu b/src/java.base/share/classes/jdk/internal/icu/impl/data/icudt70b/uprops.icu new file mode 100644 index 0000000000000000000000000000000000000000..335caa93cc2803e26e5b34342bb0c9e45074b155 Binary files /dev/null and b/src/java.base/share/classes/jdk/internal/icu/impl/data/icudt70b/uprops.icu differ diff --git a/src/java.base/share/classes/jdk/internal/icu/lang/UCharacter.java b/src/java.base/share/classes/jdk/internal/icu/lang/UCharacter.java index 716aa9827900ed8c4384dbbdecc9aa039147e4fd..b703611cf275bd41d0def5ba4e0747daf354d4a1 100644 --- a/src/java.base/share/classes/jdk/internal/icu/lang/UCharacter.java +++ b/src/java.base/share/classes/jdk/internal/icu/lang/UCharacter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 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 @@ -84,7 +84,7 @@ import jdk.internal.icu.util.VersionInfo; *

          * Further detail on differences can be determined using the program * + * "https://github.com/unicode-org/icu/blob/main/icu4j/main/tests/core/src/com/ibm/icu/dev/test/lang/UCharacterCompare.java"> * com.ibm.icu.dev.test.lang.UCharacterCompare *

          *

          @@ -101,9 +101,9 @@ import jdk.internal.icu.util.VersionInfo; * For more information see * "About the Unicode Character Database" * (http://www.unicode.org/ucd/) - * and the ICU + * and the ICU * User Guide chapter on Properties - * (http://www.icu-project.org/userguide/properties.html). + * (https://unicode-org.github.io/icu/userguide/strings/properties). *

          *

          * There are also functions that provide easy migration from C/POSIX functions diff --git a/src/java.base/share/classes/jdk/internal/icu/lang/UCharacterDirection.java b/src/java.base/share/classes/jdk/internal/icu/lang/UCharacterDirection.java index db9beb0c3acd1b4337d2cf81367f624438243f07..22b878155bb4ba61e2b89d5e25bd569ebc43e8df 100644 --- a/src/java.base/share/classes/jdk/internal/icu/lang/UCharacterDirection.java +++ b/src/java.base/share/classes/jdk/internal/icu/lang/UCharacterDirection.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -53,7 +53,7 @@ public final class UCharacterDirection implements UCharacterEnums.ECharacterDire // private constructor ========================================= ///CLOVER:OFF /** - * Private constructor to prevent initialisation + * Private constructor to prevent initialization */ private UCharacterDirection() { diff --git a/src/java.base/share/classes/jdk/internal/icu/lang/UCharacterEnums.java b/src/java.base/share/classes/jdk/internal/icu/lang/UCharacterEnums.java index 9b4809ae411e930f49f4845a439c62481cc7183e..38f8684ea04c1d8fb187236e8c70e2877e7472eb 100644 --- a/src/java.base/share/classes/jdk/internal/icu/lang/UCharacterEnums.java +++ b/src/java.base/share/classes/jdk/internal/icu/lang/UCharacterEnums.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -62,7 +62,7 @@ package jdk.internal.icu.lang; @Deprecated class UCharacterEnums { - /** This is just a namespace, it is not instantiatable. */ + /** This is just a namespace, it is not instantiable. */ private UCharacterEnums() {}; /** diff --git a/src/java.base/share/classes/jdk/internal/icu/text/BidiBase.java b/src/java.base/share/classes/jdk/internal/icu/text/BidiBase.java index 1714c15143a6b22b160efa792ceeb3ee75e1eb97..1161e9c84649775efc69e3a43751db3565ee9bf1 100644 --- a/src/java.base/share/classes/jdk/internal/icu/text/BidiBase.java +++ b/src/java.base/share/classes/jdk/internal/icu/text/BidiBase.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 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 @@ -63,7 +63,7 @@ import jdk.internal.icu.impl.UBiDiProps; * * This is an implementation of the Unicode Bidirectional Algorithm. The * algorithm is defined in the - * Unicode Standard Annex #9: + * Unicode Standard Annex #9: * Unicode Bidirectional Algorithm. *

          * @@ -985,7 +985,7 @@ public class BidiBase { /** * Enumerated property Bidi_Paired_Bracket_Type (new in Unicode 6.3). * Used in - * Unicode Standard Annex #9: + * Unicode Standard Annex #9: * Unicode Bidirectional Algorithm. * Returns UCharacter.BidiPairedBracketType values. * @stable ICU 52 @@ -3365,7 +3365,7 @@ public class BidiBase { /** * Perform the Unicode Bidi algorithm. It is defined in the - * Unicode Standard Annex #9: + * Unicode Standard Annex #9: * Unicode Bidirectional Algorithm, version 13, * also described in The Unicode Standard, Version 4.0 .

          * @@ -3450,7 +3450,7 @@ public class BidiBase { /** * Perform the Unicode Bidi algorithm. It is defined in the - * Unicode Standard Annex #9: + * Unicode Standard Annex #9: * Unicode Bidirectional Algorithm, version 13, * also described in The Unicode Standard, Version 4.0 .

          * @@ -3786,7 +3786,7 @@ public class BidiBase { /** * Perform the Unicode Bidi algorithm on a given paragraph, as defined in the - * Unicode Standard Annex #9: + * Unicode Standard Annex #9: * Unicode Bidirectional Algorithm, version 13, * also described in The Unicode Standard, Version 4.0 .

          * diff --git a/src/java.base/share/classes/jdk/internal/icu/text/BidiLine.java b/src/java.base/share/classes/jdk/internal/icu/text/BidiLine.java index 6a358abebd7785c4ecde5affe8a1c0ff6ba2f98e..d8fa4f61fa46afe0bbb53c3c303c46f5d1fbc48b 100644 --- a/src/java.base/share/classes/jdk/internal/icu/text/BidiLine.java +++ b/src/java.base/share/classes/jdk/internal/icu/text/BidiLine.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 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 @@ -47,7 +47,7 @@ final class BidiLine { * text in a single paragraph or in a line of a single paragraph * which has already been processed according to * the Unicode 3.0 Bidi algorithm as defined in - * Unicode Standard Annex #9: + * Unicode Standard Annex #9: * Unicode Bidirectional Algorithm, version 13, * also described in The Unicode Standard, Version 4.0.1 . * diff --git a/src/java.base/share/classes/jdk/internal/icu/text/Normalizer2.java b/src/java.base/share/classes/jdk/internal/icu/text/Normalizer2.java index f7fc6d294a3566785d1cf3cf3f87ee5c0c161171..db0d1fc20bf9902e3251003c8b75d6d17fc73d7d 100644 --- a/src/java.base/share/classes/jdk/internal/icu/text/Normalizer2.java +++ b/src/java.base/share/classes/jdk/internal/icu/text/Normalizer2.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -43,7 +43,7 @@ import jdk.internal.icu.impl.Norm2AllModes; * The primary functions are to produce a normalized string and to detect whether * a string is already normalized. * The most commonly used normalization forms are those defined in - * Unicode Standard Annex #15: + * Unicode Standard Annex #15: * Unicode Normalization Forms. * However, this API supports additional normalization forms for specialized purposes. * For example, NFKC_Casefold is provided via getInstance("nfkc_cf", COMPOSE) diff --git a/src/java.base/share/classes/jdk/internal/icu/text/NormalizerBase.java b/src/java.base/share/classes/jdk/internal/icu/text/NormalizerBase.java index ffe065413a532c47c21bfb2b2d958860bccfab93..f2566d9d419b77c597be0a170cd411d21eb939b0 100644 --- a/src/java.base/share/classes/jdk/internal/icu/text/NormalizerBase.java +++ b/src/java.base/share/classes/jdk/internal/icu/text/NormalizerBase.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -44,7 +44,7 @@ import java.text.Normalizer; * normalize transforms Unicode text into an equivalent composed or * decomposed form, allowing for easier sorting and searching of text. * normalize supports the standard normalization forms described in - * + * * Unicode Standard Annex #15 — Unicode Normalization Forms. * * Characters with accents or other adornments can be encoded in diff --git a/src/java.base/share/classes/jdk/internal/icu/text/StringPrep.java b/src/java.base/share/classes/jdk/internal/icu/text/StringPrep.java index 82fe7d3a5a9fab86924b09722a98a1091b0fd189..f05d0403665682063770531583e5c2b08b2fe4d0 100644 --- a/src/java.base/share/classes/jdk/internal/icu/text/StringPrep.java +++ b/src/java.base/share/classes/jdk/internal/icu/text/StringPrep.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -67,9 +67,9 @@ import jdk.internal.icu.util.VersionInfo; *

        • Unassigned Table: Contains code points that are unassigned * in the Unicode Version supported by StringPrep. Currently * RFC 3454 supports Unicode 3.2.
        • - *
        • Prohibited Table: Contains code points that are prohibted from + *
        • Prohibited Table: Contains code points that are prohibited from * the output of the StringPrep processing function.
        • - *
        • Mapping Table: Contains code ponts that are deleted from the output or case mapped.
        • + *
        • Mapping Table: Contains code points that are deleted from the output or case mapped.
        • * * * The procedure for preparing Unicode strings: @@ -226,8 +226,8 @@ public final class StringPrep { sprepUniVer = getVersionInfo(reader.getUnicodeVersion()); normCorrVer = getVersionInfo(indexes[NORM_CORRECTNS_LAST_UNI_VERSION]); VersionInfo normUniVer = UCharacter.getUnicodeVersion(); - if(normUniVer.compareTo(sprepUniVer) < 0 && /* the Unicode version of SPREP file must be less than the Unicode Vesion of the normalization data */ - normUniVer.compareTo(normCorrVer) < 0 && /* the Unicode version of the NormalizationCorrections.txt file should be less than the Unicode Vesion of the normalization data */ + if(normUniVer.compareTo(sprepUniVer) < 0 && /* the Unicode version of SPREP file must be less than the Unicode Version of the normalization data */ + normUniVer.compareTo(normCorrVer) < 0 && /* the Unicode version of the NormalizationCorrections.txt file should be less than the Unicode Version of the normalization data */ ((indexes[OPTIONS] & NORMALIZATION_ON) > 0) /* normalization turned on*/ ){ throw new IOException("Normalization Correction version not supported"); @@ -325,7 +325,7 @@ public final class StringPrep { ch -= val.value; } }else if(val.type == DELETE){ - // just consume the codepoint and contine + // just consume the codepoint and continue continue; } //copy the source into destination diff --git a/src/java.base/share/classes/jdk/internal/icu/text/UCharacterIterator.java b/src/java.base/share/classes/jdk/internal/icu/text/UCharacterIterator.java index e85a08c4605e86f0731f752aaa75e06639943aca..93978372c3a03822342b1717a82f8b93ab2b450a 100644 --- a/src/java.base/share/classes/jdk/internal/icu/text/UCharacterIterator.java +++ b/src/java.base/share/classes/jdk/internal/icu/text/UCharacterIterator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -147,9 +147,9 @@ public abstract class UCharacterIterator */ public int nextCodePoint(){ int ch1 = next(); - if(UTF16.isLeadSurrogate((char)ch1)){ + if(UTF16.isLeadSurrogate(ch1)){ int ch2 = next(); - if(UTF16.isTrailSurrogate((char)ch2)){ + if(UTF16.isTrailSurrogate(ch2)){ return UCharacterProperty.getRawSupplementary((char)ch1, (char)ch2); }else if (ch2 != DONE) { @@ -175,7 +175,7 @@ public abstract class UCharacterIterator /** * Retreat to the start of the previous code point in the text, * and return it (pre-decrement semantics). If the index is not - * preceeded by a valid surrogate pair, the behavior is the same + * preceded by a valid surrogate pair, the behavior is the same * as previous(). Otherwise the iterator is * decremented to the start of the surrogate pair, and the code * point represented by the pair is returned. @@ -185,9 +185,9 @@ public abstract class UCharacterIterator */ public int previousCodePoint(){ int ch1 = previous(); - if(UTF16.isTrailSurrogate((char)ch1)){ + if(UTF16.isTrailSurrogate(ch1)){ int ch2 = previous(); - if(UTF16.isLeadSurrogate((char)ch2)){ + if(UTF16.isLeadSurrogate(ch2)){ return UCharacterProperty.getRawSupplementary((char)ch2, (char)ch1); }else if (ch2 != DONE) { diff --git a/src/java.base/share/classes/jdk/internal/icu/text/UTF16.java b/src/java.base/share/classes/jdk/internal/icu/text/UTF16.java index b35d842b0d5c2350556347979ab10d07fd2ed67d..4205487a966fe75ce73bb315d0506f6355885c10 100644 --- a/src/java.base/share/classes/jdk/internal/icu/text/UTF16.java +++ b/src/java.base/share/classes/jdk/internal/icu/text/UTF16.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -382,36 +382,39 @@ public final class UTF16 } /** - * Determines whether the code value is a surrogate. - * @param char16 the input character. - * @return true if the input character is a surrogate. - * @stable ICU 2.1 + * Determines whether the code point is a surrogate. + * + * @param codePoint The input character. + * (In ICU 2.1-69 the type of this parameter was char.) + * @return true If the input code point is a surrogate. + * @stable ICU 70 */ - public static boolean isSurrogate(char char16) - { - return (char16 & SURROGATE_BITMASK) == SURROGATE_BITS; + public static boolean isSurrogate(int codePoint) { + return (codePoint & SURROGATE_BITMASK) == SURROGATE_BITS; } /** - * Determines whether the character is a trail surrogate. - * @param char16 the input character. - * @return true if the input character is a trail surrogate. - * @stable ICU 2.1 + * Determines whether the code point is a trail surrogate. + * + * @param codePoint The input character. + * (In ICU 2.1-69 the type of this parameter was char.) + * @return true If the input code point is a trail surrogate. + * @stable ICU 70 */ - public static boolean isTrailSurrogate(char char16) - { - return (char16 & TRAIL_SURROGATE_BITMASK) == TRAIL_SURROGATE_BITS; + public static boolean isTrailSurrogate(int codePoint) { + return (codePoint & TRAIL_SURROGATE_BITMASK) == TRAIL_SURROGATE_BITS; } /** - * Determines whether the character is a lead surrogate. - * @param char16 the input character. - * @return true if the input character is a lead surrogate - * @stable ICU 2.1 + * Determines whether the code point is a lead surrogate. + * + * @param codePoint The input character. + * (In ICU 2.1-69 the type of this parameter was char.) + * @return true If the input code point is a lead surrogate + * @stable ICU 70 */ - public static boolean isLeadSurrogate(char char16) - { - return (char16 & LEAD_SURROGATE_BITMASK) == LEAD_SURROGATE_BITS; + public static boolean isLeadSurrogate(int codePoint) { + return (codePoint & LEAD_SURROGATE_BITMASK) == LEAD_SURROGATE_BITS; } /** diff --git a/src/java.base/share/classes/jdk/internal/icu/text/UnicodeSet.java b/src/java.base/share/classes/jdk/internal/icu/text/UnicodeSet.java index 63188dca460231fb7f6137aac56843335abfbf12..6f5919e016bdc5c3668236bfbe936ea71590f3c8 100644 --- a/src/java.base/share/classes/jdk/internal/icu/text/UnicodeSet.java +++ b/src/java.base/share/classes/jdk/internal/icu/text/UnicodeSet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -135,8 +135,8 @@ import jdk.internal.icu.util.VersionInfo; * "[:Lu:]" and the Perl-like syntax "\p{Lu}" are recognized. For a * complete list of supported property patterns, see the User's Guide * for UnicodeSet at - * - * http://www.icu-project.org/userguide/unicodeSet.html. + * + * https://unicode-org.github.io/icu/userguide/strings/unicodeset. * Actual determination of property data is defined by the underlying * Unicode database as implemented by UCharacter. * @@ -147,6 +147,13 @@ import jdk.internal.icu.util.VersionInfo; * their delimiters; "[:^foo]" and "\P{foo}". In any other location, * '^' has no special meaning. * + *

          Since ICU 70, "[^...]", "[:^foo]", "\P{foo}", and "[:binaryProperty=No:]" + * perform a "code point complement" (all code points minus the original set), + * removing all multicharacter strings, + * equivalent to .{@link #complement()}.{@link #removeAllStrings()} . + * The {@link #complement()} API function continues to perform a + * symmetric difference with all code points and thus retains all multicharacter strings. + * *

          Ranges are indicated by placing two a '-' between two * characters, as in "a-z". This specifies the range of all * characters from the left to the right, in Unicode order. If the @@ -189,8 +196,6 @@ import jdk.internal.icu.util.VersionInfo; * Unicode property *

        • Examples of subformat,argument,and formatted textExamples of subformat, argument, and formatted text
          Subformat diff --git a/src/java.base/share/classes/java/time/ZoneId.java b/src/java.base/share/classes/java/time/ZoneId.java index fc9dcc4e0543f8a8c0fbc6496e3d6be58834ea82..829ed5f2fdf25724caebfcaacdc8bcc8894a3974 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, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -169,14 +169,14 @@ import static java.util.Map.entry; * The {@code equals} method should be used for comparisons. * * @implSpec - * This abstract class has two implementations, both of which are immutable and thread-safe. - * One implementation models region-based IDs, the other is {@code ZoneOffset} modelling - * offset-based IDs. This difference is visible in serialization. + * This abstract sealed class permits two implementations, both of which are immutable and + * thread-safe. One implementation models region-based IDs, the other is {@code ZoneOffset} + * modelling offset-based IDs. This difference is visible in serialization. * * @since 1.8 */ @jdk.internal.ValueBased -public abstract class ZoneId implements Serializable { +public abstract sealed class ZoneId implements Serializable permits ZoneOffset, ZoneRegion { /** * A map of zone overrides to enable the short time-zone names to be used. @@ -471,11 +471,7 @@ public abstract class ZoneId implements Serializable { /** * Constructor only accessible within the package. */ - ZoneId() { - if (getClass() != ZoneOffset.class && getClass() != ZoneRegion.class) { - throw new AssertionError("Invalid subclass"); - } - } + ZoneId() {} //----------------------------------------------------------------------- /** diff --git a/src/java.base/share/classes/java/time/chrono/HijrahChronology.java b/src/java.base/share/classes/java/time/chrono/HijrahChronology.java index 87f307e15d3c878d46dc9a6009868fb293eec30a..1ce99906708aa197d0ec4e95c6cd4b8446e490e0 100644 --- a/src/java.base/share/classes/java/time/chrono/HijrahChronology.java +++ b/src/java.base/share/classes/java/time/chrono/HijrahChronology.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -533,18 +533,14 @@ public final class HijrahChronology extends AbstractChronology implements Serial @Override public ValueRange range(ChronoField field) { checkCalendarInit(); - if (field instanceof ChronoField) { - ChronoField f = field; - return switch (f) { - case DAY_OF_MONTH -> ValueRange.of(1, 1, getMinimumMonthLength(), getMaximumMonthLength()); - case DAY_OF_YEAR -> ValueRange.of(1, getMaximumDayOfYear()); - case ALIGNED_WEEK_OF_MONTH -> ValueRange.of(1, 5); - case YEAR, YEAR_OF_ERA -> ValueRange.of(getMinimumYear(), getMaximumYear()); - case ERA -> ValueRange.of(1, 1); - default -> field.range(); - }; - } - return field.range(); + return switch (field) { + case DAY_OF_MONTH -> ValueRange.of(1, 1, getMinimumMonthLength(), getMaximumMonthLength()); + case DAY_OF_YEAR -> ValueRange.of(1, getMaximumDayOfYear()); + case ALIGNED_WEEK_OF_MONTH -> ValueRange.of(1, 5); + case YEAR, YEAR_OF_ERA -> ValueRange.of(getMinimumYear(), getMaximumYear()); + case ERA -> ValueRange.of(1, 1); + default -> field.range(); + }; } //----------------------------------------------------------------------- diff --git a/src/java.base/share/classes/java/time/format/DateTimeFormatter.java b/src/java.base/share/classes/java/time/format/DateTimeFormatter.java index c94b123b26c9d5a57e3e1793d4cbd9b189298a21..d5a5c162fd2de72fd15ed357a03b67e6888fffe2 100644 --- a/src/java.base/share/classes/java/time/format/DateTimeFormatter.java +++ b/src/java.base/share/classes/java/time/format/DateTimeFormatter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -297,7 +297,7 @@ import sun.util.locale.provider.TimeZoneNameUtility; *
          W week-of-month number 4
          E day-of-week text Tue; Tuesday; T
          e/c localized day-of-week number/text 2; 02; Tue; Tuesday; T
          F day-of-week-in-month number 3
          F aligned-week-of-month number 3
          a am-pm-of-day text PM
          B period-of-day text in the morning
          * - *

          Warning: you cannot add an empty string ("") to a UnicodeSet.

          - * *

          Formal syntax

          * *
          @@ -230,9 +235,8 @@ import jdk.internal.icu.util.VersionInfo; * * * hex :=  - * any character for which - * Character.digit(c, 16) - * returns a non-negative result + * '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' |
          + *     'A' | 'B' | 'C' | 'D' | 'E' | 'F' | 'a' | 'b' | 'c' | 'd' | 'e' | 'f'
          * * * property :=  @@ -487,7 +491,7 @@ public class UnicodeSet { else if (i > 0 && c == list[i-1]) { // c is after end of prior range list[i-1]++; - // no need to chcek for collapse here + // no need to check for collapse here } else { @@ -528,7 +532,6 @@ public class UnicodeSet { * present. If this set already contains the multicharacter, * the call leaves this set unchanged. * Thus {@code "ch" => {"ch"}} - *
          Warning: you cannot add an empty string ("") to a UnicodeSet. * @param s the source string * @return this object, for chaining * @stable ICU 2.0 @@ -546,22 +549,19 @@ public class UnicodeSet { /** * Utility for getting code point from single code point CharSequence. - * See the public UTF16.getSingleCodePoint() + * See the public UTF16.getSingleCodePoint() (which returns -1 for null rather than throwing NPE). + * * @return a code point IF the string consists of a single one. * otherwise returns -1. * @param s to test */ private static int getSingleCP(CharSequence s) { - if (s.length() < 1) { - throw new IllegalArgumentException("Can't use zero-length strings in UnicodeSet"); - } - if (s.length() > 2) return -1; if (s.length() == 1) return s.charAt(0); - - // at this point, len = 2 - int cp = UTF16.charAt(s, 0); - if (cp > 0xFFFF) { // is surrogate pair - return cp; + if (s.length() == 2) { + int cp = Character.codePointAt(s, 0); + if (cp > 0xFFFF) { // is surrogate pair + return cp; + } } return -1; } @@ -569,13 +569,11 @@ public class UnicodeSet { /** * Complements the specified range in this set. Any character in * the range will be removed if it is in this set, or will be - * added if it is not in this set. If {@code end > start} + * added if it is not in this set. If start > end * then an empty range is complemented, leaving the set unchanged. * - * @param start first character, inclusive, of range to be removed - * from this set. - * @param end last character, inclusive, of range to be removed - * from this set. + * @param start first character, inclusive, of range + * @param end last character, inclusive, of range * @stable ICU 2.0 */ public UnicodeSet complement(int start, int end) { diff --git a/src/java.base/share/classes/jdk/internal/icu/util/CodePointTrie.java b/src/java.base/share/classes/jdk/internal/icu/util/CodePointTrie.java index 1738696f75ab2a210fc2c54d311f20660753aece..7aaa0be68c8b9c54d45d5b995237c7d0f1c3c816 100644 --- a/src/java.base/share/classes/jdk/internal/icu/util/CodePointTrie.java +++ b/src/java.base/share/classes/jdk/internal/icu/util/CodePointTrie.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -43,7 +43,7 @@ import static jdk.internal.icu.impl.NormalizerImpl.UTF16Plus; /** * Immutable Unicode code point trie. * Fast, reasonably compact, map from Unicode code points (U+0000..U+10FFFF) to integer values. - * For details see http://site.icu-project.org/design/struct/utrie + * For details see https://icu.unicode.org/design/struct/utrie * *

          This class is not intended for public subclassing. * diff --git a/src/java.base/share/classes/jdk/internal/icu/util/VersionInfo.java b/src/java.base/share/classes/jdk/internal/icu/util/VersionInfo.java index d79ee84731b3027a9e2c36ba3741ccf6b5124480..799d570e2aa8296bcd9cf84e7b8cda3dc7b0a524 100644 --- a/src/java.base/share/classes/jdk/internal/icu/util/VersionInfo.java +++ b/src/java.base/share/classes/jdk/internal/icu/util/VersionInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -54,7 +54,7 @@ public final class VersionInfo * @deprecated This API is ICU internal only. */ @Deprecated - public static final String ICU_DATA_VERSION_PATH = "67b"; + public static final String ICU_DATA_VERSION_PATH = "70b"; // public methods ------------------------------------------------------ @@ -148,7 +148,15 @@ public final class VersionInfo */ public int compareTo(VersionInfo other) { - return m_version_ - other.m_version_; + // m_version_ is an int, a signed 32-bit integer. + // When the major version is >=128, then the version int is negative. + // Compare it in two steps to simulate an unsigned-int comparison. + // (Alternatively we could turn each int into a long and reset the upper 32 bits.) + // Compare the upper bits first, using logical shift right (unsigned). + int diff = (m_version_ >>> 1) - (other.m_version_ >>> 1); + if (diff != 0) { return diff; } + // Compare the remaining bits. + return (m_version_ & 1) - (other.m_version_ & 1); } // private data members ---------------------------------------------- diff --git a/src/java.base/share/classes/jdk/internal/jimage/ImageStringsReader.java b/src/java.base/share/classes/jdk/internal/jimage/ImageStringsReader.java index f5773302004030b195109bc4195a0f8453725a03..c4601ef3e6cc62a17683b95c005d0a548fa33b07 100644 --- a/src/java.base/share/classes/jdk/internal/jimage/ImageStringsReader.java +++ b/src/java.base/share/classes/jdk/internal/jimage/ImageStringsReader.java @@ -309,7 +309,7 @@ public class ImageStringsReader implements ImageStrings { return -1; } } - return length; + return current - offset + length; } static int mutf8FromStringLength(String s) { diff --git a/src/java.base/share/classes/jdk/internal/jrtfs/JrtPath.java b/src/java.base/share/classes/jdk/internal/jrtfs/JrtPath.java index 4720d9c98ad40b6d475d4123cb4b84a25794fef3..a3772b5e26dee4650ee8648dfabd333c0fa2c2a5 100644 --- a/src/java.base/share/classes/jdk/internal/jrtfs/JrtPath.java +++ b/src/java.base/share/classes/jdk/internal/jrtfs/JrtPath.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -485,7 +485,7 @@ final class JrtPath implements Path { // Remove DotSlash(./) and resolve DotDot (..) components private String getResolved() { int length = path.length(); - if (length == 0 || (path.indexOf("./") == -1 && path.charAt(length - 1) != '.')) { + if (length == 0 || (!path.contains("./") && path.charAt(length - 1) != '.')) { return path; } else { return resolvePath(); diff --git a/src/java.base/share/classes/jdk/internal/loader/BootLoader.java b/src/java.base/share/classes/jdk/internal/loader/BootLoader.java index ca9222d32a9bd9818fad09959c654fd4a3eec5f2..98ff60a73095a197d050767ea8618ab50c6216f0 100644 --- a/src/java.base/share/classes/jdk/internal/loader/BootLoader.java +++ b/src/java.base/share/classes/jdk/internal/loader/BootLoader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -74,7 +74,7 @@ public class BootLoader { // native libraries loaded by the boot class loader private static final NativeLibraries NATIVE_LIBS - = NativeLibraries.jniNativeLibraries(null); + = NativeLibraries.newInstance(null); /** * Returns the unnamed module for the boot loader. diff --git a/src/java.base/share/classes/jdk/internal/loader/NativeLibraries.java b/src/java.base/share/classes/jdk/internal/loader/NativeLibraries.java index 11df544fd7c79627f9f2d54dbc0666929a0db58c..c5ede021e00bfaee3c27fd8d122c18649c92a9e3 100644 --- a/src/java.base/share/classes/jdk/internal/loader/NativeLibraries.java +++ b/src/java.base/share/classes/jdk/internal/loader/NativeLibraries.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -36,7 +36,6 @@ import java.util.ArrayDeque; import java.util.Deque; import java.util.function.BiFunction; import java.util.function.Function; -import java.util.Objects; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; @@ -62,8 +61,6 @@ public final class NativeLibraries { // unless specified private final Class caller; // may be null private final boolean searchJavaLibraryPath; - // loading JNI native libraries - private final boolean isJNI; /** * Creates a NativeLibraries instance for loading JNI native libraries @@ -81,48 +78,14 @@ public final class NativeLibraries { * @see * JNI Specification: Library and Version Management */ - public static NativeLibraries jniNativeLibraries(ClassLoader loader) { - return new NativeLibraries(loader); + public static NativeLibraries newInstance(ClassLoader loader) { + return new NativeLibraries(loader, loader != null ? null : NativeLibraries.class, loader != null); } - /** - * Creates a raw NativeLibraries instance that has the following properties: - * 1. Native libraries loaded in this raw NativeLibraries instance are - * not JNI native libraries. Hence JNI_OnLoad and JNI_OnUnload will - * be ignored. No support for linking of native method. - * 2. Native libraries not auto-unloaded. They may be explicitly unloaded - * via NativeLibraries::unload. - * 3. No relationship with class loaders. - * - * This static factory method is restricted for JDK trusted class use. - */ - public static NativeLibraries rawNativeLibraries(Class trustedCaller, - boolean searchJavaLibraryPath) { - return new NativeLibraries(trustedCaller, searchJavaLibraryPath); - } - - private NativeLibraries(ClassLoader loader) { - // for null loader, default the caller to this class and - // do not search java.library.path + private NativeLibraries(ClassLoader loader, Class caller, boolean searchJavaLibraryPath) { this.loader = loader; - this.caller = loader != null ? null : NativeLibraries.class; - this.searchJavaLibraryPath = loader != null ? true : false; - this.isJNI = true; - } - - /* - * Constructs a NativeLibraries instance of no relationship with class loaders - * and disabled auto unloading. - */ - private NativeLibraries(Class caller, boolean searchJavaLibraryPath) { - Objects.requireNonNull(caller); - if (!VM.isSystemDomainLoader(caller.getClassLoader())) { - throw new IllegalArgumentException("must be JDK trusted class"); - } - this.loader = caller.getClassLoader(); this.caller = caller; this.searchJavaLibraryPath = searchJavaLibraryPath; - this.isJNI = false; } /* @@ -227,7 +190,7 @@ public final class NativeLibraries { } } - NativeLibraryImpl lib = new NativeLibraryImpl(fromClass, name, isBuiltin, isJNI); + NativeLibraryImpl lib = new NativeLibraryImpl(fromClass, name, isBuiltin); // load the native library NativeLibraryContext.push(lib); try { @@ -237,8 +200,7 @@ public final class NativeLibraries { // auto unloading is only supported for JNI native libraries // loaded by custom class loaders that can be unloaded. // built-in class loaders are never unloaded. - boolean autoUnload = isJNI && !VM.isSystemDomainLoader(loader) - && loader != ClassLoaders.appClassLoader(); + boolean autoUnload = !VM.isSystemDomainLoader(loader) && loader != ClassLoaders.appClassLoader(); if (autoUnload) { // register the loaded native library for auto unloading // when the class loader is reclaimed, all native libraries @@ -269,8 +231,6 @@ public final class NativeLibraries { */ public NativeLibrary loadLibrary(String name) { assert name.indexOf(File.separatorChar) < 0; - assert caller != null; - return loadLibrary(caller, name); } @@ -293,29 +253,6 @@ public final class NativeLibraries { return lib; } - /** - * Unloads the given native library - * - * @param lib native library - */ - public void unload(NativeLibrary lib) { - if (isJNI) { - throw new UnsupportedOperationException("explicit unloading cannot be used with auto unloading"); - } - Objects.requireNonNull(lib); - acquireNativeLibraryLock(lib.name()); - try { - NativeLibraryImpl nl = libraries.remove(lib.name()); - if (nl != lib) { - throw new IllegalArgumentException(lib.name() + " not loaded by this NativeLibraries instance"); - } - // unload the native library and also remove from the global name registry - nl.unloader().run(); - } finally { - releaseNativeLibraryLock(lib.name()); - } - } - private NativeLibrary findFromPaths(String[] paths, Class fromClass, String name) { for (String path : paths) { File libfile = new File(path, System.mapLibraryName(name)); @@ -344,7 +281,7 @@ public final class NativeLibraries { * the VM when it loads the library, and used by the VM to pass the correct * version of JNI to the native methods. */ - static class NativeLibraryImpl implements NativeLibrary { + static class NativeLibraryImpl extends NativeLibrary { // the class from which the library is loaded, also indicates // the loader this native library belongs. final Class fromClass; @@ -353,21 +290,16 @@ public final class NativeLibraries { final String name; // Indicates if the native library is linked into the VM final boolean isBuiltin; - // Indicate if this is JNI native library - final boolean isJNI; // opaque handle to native library, used in native code. long handle; // the version of JNI environment the native library requires. int jniVersion; - NativeLibraryImpl(Class fromClass, String name, boolean isBuiltin, boolean isJNI) { - assert !isBuiltin || isJNI : "a builtin native library must be JNI library"; - + NativeLibraryImpl(Class fromClass, String name, boolean isBuiltin) { this.fromClass = fromClass; this.name = name; this.isBuiltin = isBuiltin; - this.isJNI = isJNI; } @Override @@ -377,11 +309,15 @@ public final class NativeLibraries { @Override public long find(String name) { - return findEntry0(this, name); + return findEntry0(handle, name); } - Runnable unloader() { - return new Unloader(name, handle, isBuiltin, isJNI); + /* + * Unloader::run method is invoked to unload the native library + * when this class loader becomes phantom reachable. + */ + private Runnable unloader() { + return new Unloader(name, handle, isBuiltin); } /* @@ -392,7 +328,14 @@ public final class NativeLibraries { throw new InternalError("Native library " + name + " has been loaded"); } - return load(this, name, isBuiltin, isJNI, loadLibraryOnlyIfPresent); + return load(this, name, isBuiltin, loadLibraryOnlyIfPresent); + } + + /* + * Close this native library. + */ + void close() { + unload(name, isBuiltin, handle); } } @@ -404,15 +347,13 @@ public final class NativeLibraries { // This represents the context when a native library is unloaded // and getFromClass() will return null, static final NativeLibraryImpl UNLOADER = - new NativeLibraryImpl(null, "dummy", false, false); + new NativeLibraryImpl(null, "dummy", false); final String name; final long handle; final boolean isBuiltin; - final boolean isJNI; - Unloader(String name, long handle, boolean isBuiltin, boolean isJNI) { - assert !isBuiltin || isJNI : "a builtin native library must be JNI library"; + Unloader(String name, long handle, boolean isBuiltin) { if (handle == 0) { throw new IllegalArgumentException( "Invalid handle for native library " + name); @@ -421,7 +362,6 @@ public final class NativeLibraries { this.name = name; this.handle = handle; this.isBuiltin = isBuiltin; - this.isJNI = isJNI; } @Override @@ -434,7 +374,7 @@ public final class NativeLibraries { } NativeLibraryContext.push(UNLOADER); try { - unload(name, isBuiltin, isJNI, handle); + unload(name, isBuiltin, handle); } finally { NativeLibraryContext.pop(); } @@ -576,12 +516,22 @@ public final class NativeLibraries { return NativeLibraryContext.peek().fromClass; } - // JNI FindClass expects the caller class if invoked from JNI_OnLoad - // and JNI_OnUnload is NativeLibrary class + /* + * Return true if the given library is successfully loaded. + * If the given library cannot be loaded for any reason, + * if throwExceptionIfFail is false, then this method returns false; + * otherwise, UnsatisfiedLinkError will be thrown. + * + * JNI FindClass expects the caller class if invoked from JNI_OnLoad + * and JNI_OnUnload is NativeLibrary class. + */ private static native boolean load(NativeLibraryImpl impl, String name, - boolean isBuiltin, boolean isJNI, + boolean isBuiltin, boolean throwExceptionIfFail); - private static native void unload(String name, boolean isBuiltin, boolean isJNI, long handle); + /* + * Unload the named library. JNI_OnUnload, if present, will be invoked + * before the native library is unloaded. + */ + private static native void unload(String name, boolean isBuiltin, long handle); private static native String findBuiltinLib(String name); - private static native long findEntry0(NativeLibraryImpl lib, String name); } diff --git a/src/java.base/share/classes/jdk/internal/loader/NativeLibrary.java b/src/java.base/share/classes/jdk/internal/loader/NativeLibrary.java index 2b684e0bf357c70cea38109f2637561f8c04ca55..228356e0773b3409def0b85a4df8b2a4bf9e031f 100644 --- a/src/java.base/share/classes/jdk/internal/loader/NativeLibrary.java +++ b/src/java.base/share/classes/jdk/internal/loader/NativeLibrary.java @@ -28,8 +28,8 @@ package jdk.internal.loader; /** * NativeLibrary represents a loaded native library instance. */ -public interface NativeLibrary { - String name(); +public abstract class NativeLibrary { + public abstract String name(); /** * Finds the address of the entry of the given name. Returns 0 @@ -37,7 +37,7 @@ public interface NativeLibrary { * * @param name the name of the symbol to be found */ - long find(String name); + public abstract long find(String name); /** * Finds the address of the entry of the given name. @@ -45,11 +45,17 @@ public interface NativeLibrary { * @param name the name of the symbol to be found * @throws NoSuchMethodException if the named entry is not found. */ - default long lookup(String name) throws NoSuchMethodException { + public final long lookup(String name) throws NoSuchMethodException { long addr = find(name); if (0 == addr) { throw new NoSuchMethodException("Cannot find symbol " + name + " in library " + name()); } return addr; } + + /* + * Returns the address of the named symbol defined in the library of + * the given handle. Returns 0 if not found. + */ + static native long findEntry0(long handle, String name); } diff --git a/src/java.base/share/classes/jdk/internal/loader/RawNativeLibraries.java b/src/java.base/share/classes/jdk/internal/loader/RawNativeLibraries.java new file mode 100644 index 0000000000000000000000000000000000000000..972e34e1fd20b94a33ded6d6839f5c727154ba62 --- /dev/null +++ b/src/java.base/share/classes/jdk/internal/loader/RawNativeLibraries.java @@ -0,0 +1,177 @@ +/* + * 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. 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.loader; + +import jdk.internal.misc.VM; + +import java.io.IOException; +import java.lang.invoke.MethodHandles; +import java.nio.file.Path; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; + +/** + * RawNativeLibraries has the following properties: + * 1. Native libraries loaded in this RawNativeLibraries instance are + * not JNI native libraries. Hence JNI_OnLoad and JNI_OnUnload will + * be ignored. No support for linking of native method. + * 2. Native libraries not auto-unloaded. They may be explicitly unloaded + * via NativeLibraries::unload. + * 3. No relationship with class loaders. + */ +public final class RawNativeLibraries { + final Map libraries = new ConcurrentHashMap<>(); + final Class caller; + + private RawNativeLibraries(MethodHandles.Lookup trustedCaller) { + this.caller = trustedCaller.lookupClass(); + } + + /** + * Creates a RawNativeLibraries instance that has no relationship with + * any class loaders and disabled auto unloading. + * + * This static factory method is restricted for JDK trusted class use. + */ + public static RawNativeLibraries newInstance(MethodHandles.Lookup trustedCaller) { + if (!trustedCaller.hasFullPrivilegeAccess() || + !VM.isSystemDomainLoader(trustedCaller.lookupClass().getClassLoader())) { + throw new InternalError(trustedCaller + " does not have access to raw native library loading"); + } + return new RawNativeLibraries(trustedCaller); + } + + /* + * Load a native library from the given path. Returns null if the given + * library is determined to be non-loadable, which is system-dependent. + * + * @param path the path of the native library + */ + @SuppressWarnings("removal") + public NativeLibrary load(Path path) { + String name = AccessController.doPrivileged(new PrivilegedAction<>() { + public String run() { + try { + return path.toRealPath().toString(); + } catch (IOException e) { + return null; + } + } + }); + if (name == null) { + return null; + } + return load(name); + } + + /** + * Load a native library of the given pathname, which is platform-specific. + * Returns null if it fails to load the given pathname. + * + * If the given pathname does not contain a name-separator character, + * for example on Unix a slash character, the library search strategy + * is system-dependent for example on Unix, see dlopen. + * + * @apiNote + * The {@code pathname} argument is platform-specific. + * {@link System#mapLibraryName} can be used to convert a name to + * a platform-specific pathname: + * {@snippet + * RawNativeLibraries libs = RawNativeLibraries.newInstance(MethodHandles.lookup()); + * NativeLibrary lib = libs.load(System.mapLibraryName("blas")); + * } + * + * @param pathname the pathname of the native library + * @see System#mapLibraryName(String) + */ + public NativeLibrary load(String pathname) { + return libraries.computeIfAbsent(pathname, this::get); + } + + private RawNativeLibraryImpl get(String pathname) { + RawNativeLibraryImpl lib = new RawNativeLibraryImpl(caller, pathname); + if (!lib.open()) { + return null; + } + return lib; + } + + /* + * Unloads the given native library. + */ + public void unload(NativeLibrary lib) { + Objects.requireNonNull(lib); + if (!libraries.remove(lib.name(), lib)) { + throw new IllegalArgumentException(lib.name() + " not loaded by this RawNativeLibraries instance"); + } + RawNativeLibraryImpl nl = (RawNativeLibraryImpl)lib; + nl.close(); + } + + static class RawNativeLibraryImpl extends NativeLibrary { + // the name of the raw native library. + final String name; + // opaque handle to raw native library, used in native code. + long handle; + + RawNativeLibraryImpl(Class fromClass, String name) { + this.name = name; + } + + @Override + public String name() { + return name; + } + + @Override + public long find(String name) { + return findEntry0(handle, name); + } + + /* + * Loads the named native library. + */ + boolean open() { + if (handle != 0) { + throw new InternalError("Native library " + name + " has been loaded"); + } + return load0(this, name); + } + + /* + * Close this native library. + */ + void close() { + unload0(name, handle); + } + } + + private static native boolean load0(RawNativeLibraryImpl impl, String name); + private static native void unload0(String name, long handle); +} + diff --git a/src/java.base/share/classes/jdk/internal/loader/URLClassPath.java b/src/java.base/share/classes/jdk/internal/loader/URLClassPath.java index dad2f25917bbc03e561f6d047b96826021a8e6e2..1961e669e876c681464f06058fa8ad04db475a6c 100644 --- a/src/java.base/share/classes/jdk/internal/loader/URLClassPath.java +++ b/src/java.base/share/classes/jdk/internal/loader/URLClassPath.java @@ -561,11 +561,11 @@ public class URLClassPath { // fallback to checkRead/checkConnect for pre 1.2 // security managers if ((perm instanceof java.io.FilePermission) && - perm.getActions().indexOf("read") != -1) { + perm.getActions().contains("read")) { security.checkRead(perm.getName()); } else if ((perm instanceof java.net.SocketPermission) && - perm.getActions().indexOf("connect") != -1) { + perm.getActions().contains("connect")) { URL locUrl = url; if (urlConnection instanceof JarURLConnection) { locUrl = ((JarURLConnection)urlConnection).getJarFileURL(); @@ -1254,7 +1254,7 @@ public class URLClassPath { URLClassPath.check(url); final File file; - if (name.indexOf("..") != -1) { + if (name.contains("..")) { file = (new File(dir, name.replace('/', File.separatorChar))) .getCanonicalFile(); if ( !((file.getPath()).startsWith(dir.getPath())) ) { diff --git a/src/java.base/share/classes/jdk/internal/logger/LoggerFinderLoader.java b/src/java.base/share/classes/jdk/internal/logger/LoggerFinderLoader.java index dbf4ccca128e4c292231f66fd1e3f33f11296cd3..4f009973e2742a2468aa2437353f23bcd178a99a 100644 --- a/src/java.base/share/classes/jdk/internal/logger/LoggerFinderLoader.java +++ b/src/java.base/share/classes/jdk/internal/logger/LoggerFinderLoader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -129,7 +129,7 @@ public final class LoggerFinderLoader { result = iterator.next(); if (iterator.hasNext() && ensureSingletonProvider()) { throw new ServiceConfigurationError( - "More than on LoggerFinder implementation"); + "More than one LoggerFinder implementation"); } } else { result = loadDefaultImplementation(); diff --git a/src/java.base/share/classes/jdk/internal/misc/CDS.java b/src/java.base/share/classes/jdk/internal/misc/CDS.java index 43f6128cc0576f5e979b2b9682794c885cd9c9e2..370086612cd83b8ed4cdf23fc129ee31f5970d32 100644 --- a/src/java.base/share/classes/jdk/internal/misc/CDS.java +++ b/src/java.base/share/classes/jdk/internal/misc/CDS.java @@ -66,7 +66,7 @@ public class CDS { } /** - * Is sharing enabled via the UseSharedSpaces flag. + * Is sharing enabled. */ public static boolean isSharingEnabled() { return isSharingEnabled; @@ -232,15 +232,11 @@ public class CDS { private static String[] excludeFlags = { "-XX:DumpLoadedClassList=", - "-XX:+DumpSharedSpaces", - "-XX:+DynamicDumpSharedSpaces", "-XX:+RecordDynamicDumpInfo", "-Xshare:", "-XX:SharedClassListFile=", "-XX:SharedArchiveFile=", - "-XX:ArchiveClassesAtExit=", - "-XX:+UseSharedSpaces", - "-XX:+RequireSharedSpaces"}; + "-XX:ArchiveClassesAtExit="}; private static boolean containsExcludedFlags(String testStr) { for (String e : excludeFlags) { if (testStr.contains(e)) { diff --git a/src/java.base/share/classes/jdk/internal/misc/X-ScopedMemoryAccess.java.template b/src/java.base/share/classes/jdk/internal/misc/X-ScopedMemoryAccess.java.template index e4cf2f5b2ed984527d703ea4137797701b9aa7e4..be2e8cb24ffc74025a317a8bb7020a6c834b11f9 100644 --- a/src/java.base/share/classes/jdk/internal/misc/X-ScopedMemoryAccess.java.template +++ b/src/java.base/share/classes/jdk/internal/misc/X-ScopedMemoryAccess.java.template @@ -103,19 +103,13 @@ public class ScopedMemoryAccess { */ public interface Scope { - interface Handle { - Scope scope(); - } - void checkValidState(); Thread ownerThread(); - boolean isImplicit(); - - Handle acquire(); + void acquire0(); - void release(Handle handle); + void release0(); /** * Error thrown when memory access fails because the memory has already been released. diff --git a/src/java.base/share/classes/jdk/internal/module/ModulePath.java b/src/java.base/share/classes/jdk/internal/module/ModulePath.java index 47c21ed3b3d26f465c784592af0836564bb31ed2..3bce921cfe74c9aeee5c3b64309748577af4e9b9 100644 --- a/src/java.base/share/classes/jdk/internal/module/ModulePath.java +++ b/src/java.base/share/classes/jdk/internal/module/ModulePath.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -527,7 +527,6 @@ public class ModulePath implements ModuleFinder { Set packages = classFiles.stream() .map(this::toPackageName) .flatMap(Optional::stream) - .distinct() .collect(Collectors.toSet()); // all packages are exported and open @@ -663,11 +662,12 @@ public class ModulePath implements ModuleFinder { // -- exploded directories -- private Set explodedPackages(Path dir) { + String separator = dir.getFileSystem().getSeparator(); try { return Files.find(dir, Integer.MAX_VALUE, ((path, attrs) -> attrs.isRegularFile() && !isHidden(path))) .map(path -> dir.relativize(path)) - .map(this::toPackageName) + .map(path -> toPackageName(path, separator)) .flatMap(Optional::stream) .collect(Collectors.toSet()); } catch (IOException x) { @@ -738,7 +738,7 @@ public class ModulePath implements ModuleFinder { * @throws InvalidModuleDescriptorException if the name is a class file in * the top-level directory (and it's not module-info.class) */ - private Optional toPackageName(Path file) { + private Optional toPackageName(Path file, String separator) { assert file.getRoot() == null; Path parent = file.getParent(); @@ -752,7 +752,7 @@ public class ModulePath implements ModuleFinder { return Optional.empty(); } - String pn = parent.toString().replace(File.separatorChar, '.'); + String pn = parent.toString().replace(separator, "."); if (Checks.isPackageName(pn)) { return Optional.of(pn); } else { diff --git a/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassReader.java b/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassReader.java index 17575546518ee5a5b7b1aa007fedaab8e5f25abf..e306e60d45bf209990bd019099ecc8ed605cadcd 100644 --- a/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassReader.java +++ b/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassReader.java @@ -222,7 +222,7 @@ public class ClassReader { this.b = classFileBuffer; // Check the class' major_version. This field is after the magic and minor_version fields, which // use 4 and 2 bytes respectively. - if (checkClassVersion && readShort(classFileOffset + 6) > Opcodes.V18) { + if (checkClassVersion && readShort(classFileOffset + 6) > Opcodes.V19) { throw new IllegalArgumentException( "Unsupported class file major version " + readShort(classFileOffset + 6)); } diff --git a/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Opcodes.java b/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Opcodes.java index e8be8c1935ccfb1e6f082bd04a4a0e6a2e874bc8..d1b6d52865cca24e5ed7d767f8789e1038b69c39 100644 --- a/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Opcodes.java +++ b/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Opcodes.java @@ -314,6 +314,7 @@ public interface Opcodes { int V16 = 0 << 16 | 60; int V17 = 0 << 16 | 61; int V18 = 0 << 16 | 62; + int V19 = 0 << 16 | 63; /** * Version flag indicating that the class is using 'preview' features. 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 cba836c5edd47c282a167fef057132bb383af77e..baeb6bf895692d7ddb7b17d99b2674978482b9a4 100644 --- a/src/java.base/share/classes/jdk/internal/reflect/FieldAccessorImpl.java +++ b/src/java.base/share/classes/jdk/internal/reflect/FieldAccessorImpl.java @@ -120,7 +120,7 @@ abstract class FieldAccessorImpl extends MagicAccessorImpl } } - private String getQualifiedFieldName() { + protected String getQualifiedFieldName() { return field.getDeclaringClass().getName() + "." +field.getName(); } @@ -223,16 +223,6 @@ abstract class FieldAccessorImpl extends MagicAccessorImpl return err; } - protected String getMessage(boolean getter, String attemptedType) { - String err = "Can not " + (getter ? "get" : "set"); - if (Modifier.isStatic(field.getModifiers())) - err += " static"; - if (Modifier.isFinal(field.getModifiers())) - err += " final"; - err += " " + field.getType().getName() + " field " + getQualifiedFieldName() + " on " + attemptedType; - return err; - } - protected void throwSetIllegalArgumentException(String attemptedType, String attemptedValue) { throw new IllegalArgumentException(getSetMessage(attemptedType,attemptedValue)); diff --git a/src/java.base/share/classes/jdk/internal/reflect/MethodHandleBooleanFieldAccessorImpl.java b/src/java.base/share/classes/jdk/internal/reflect/MethodHandleBooleanFieldAccessorImpl.java index 10ec2f0e909d60fb655d3d392404c2a6514384df..2e0609264bd2d2ead71830bf7e7c09456dae6e17 100644 --- a/src/java.base/share/classes/jdk/internal/reflect/MethodHandleBooleanFieldAccessorImpl.java +++ b/src/java.base/share/classes/jdk/internal/reflect/MethodHandleBooleanFieldAccessorImpl.java @@ -56,7 +56,6 @@ class MethodHandleBooleanFieldAccessorImpl extends MethodHandleFieldAccessorImpl } public boolean getBoolean(Object obj) throws IllegalArgumentException { - ensureObj(obj); try { if (isStatic()) { return (boolean) getter.invokeExact(); @@ -66,7 +65,7 @@ class MethodHandleBooleanFieldAccessorImpl extends MethodHandleFieldAccessorImpl } catch (IllegalArgumentException|NullPointerException e) { throw e; } catch (ClassCastException e) { - throw newGetIllegalArgumentException(obj.getClass()); + throw newGetIllegalArgumentException(obj); } catch (Throwable e) { throw new InternalError(e); } @@ -122,8 +121,8 @@ class MethodHandleBooleanFieldAccessorImpl extends MethodHandleFieldAccessorImpl public void setBoolean(Object obj, boolean z) throws IllegalArgumentException, IllegalAccessException { - ensureObj(obj); if (isReadOnly()) { + ensureObj(obj); // throw NPE if obj is null on instance field throwFinalFieldIllegalAccessException(z); } try { @@ -135,7 +134,8 @@ class MethodHandleBooleanFieldAccessorImpl extends MethodHandleFieldAccessorImpl } catch (IllegalArgumentException|NullPointerException e) { throw e; } catch (ClassCastException e) { - throw newSetIllegalArgumentException(obj.getClass()); + // receiver is of invalid type + throw newSetIllegalArgumentException(obj); } catch (Throwable e) { throw new InternalError(e); } diff --git a/src/java.base/share/classes/jdk/internal/reflect/MethodHandleByteFieldAccessorImpl.java b/src/java.base/share/classes/jdk/internal/reflect/MethodHandleByteFieldAccessorImpl.java index 7e88e080854667ff3d2cac1149d6069f1c2ad22c..b56fbbcbcb28e8e84bb1ef58a9c0dfd3ee5ebba6 100644 --- a/src/java.base/share/classes/jdk/internal/reflect/MethodHandleByteFieldAccessorImpl.java +++ b/src/java.base/share/classes/jdk/internal/reflect/MethodHandleByteFieldAccessorImpl.java @@ -69,7 +69,7 @@ class MethodHandleByteFieldAccessorImpl extends MethodHandleFieldAccessorImpl { } catch (IllegalArgumentException|NullPointerException e) { throw e; } catch (ClassCastException e) { - throw newGetIllegalArgumentException(obj.getClass()); + throw newGetIllegalArgumentException(obj); } catch (Throwable e) { throw new InternalError(e); } @@ -127,8 +127,8 @@ class MethodHandleByteFieldAccessorImpl extends MethodHandleFieldAccessorImpl { public void setByte(Object obj, byte b) throws IllegalArgumentException, IllegalAccessException { - ensureObj(obj); if (isReadOnly()) { + ensureObj(obj); // throw NPE if obj is null on instance field throwFinalFieldIllegalAccessException(b); } try { @@ -140,7 +140,8 @@ class MethodHandleByteFieldAccessorImpl extends MethodHandleFieldAccessorImpl { } catch (IllegalArgumentException|NullPointerException e) { throw e; } catch (ClassCastException e) { - throw newSetIllegalArgumentException(obj.getClass()); + // receiver is of invalid type + throw newSetIllegalArgumentException(obj); } catch (Throwable e) { throw new InternalError(e); } diff --git a/src/java.base/share/classes/jdk/internal/reflect/MethodHandleCharacterFieldAccessorImpl.java b/src/java.base/share/classes/jdk/internal/reflect/MethodHandleCharacterFieldAccessorImpl.java index 1e8b4e25525ee1a648bce701d37c53f4e3e5e61c..c1f357326f4e2517ad18b201aaf252850c57be5d 100644 --- a/src/java.base/share/classes/jdk/internal/reflect/MethodHandleCharacterFieldAccessorImpl.java +++ b/src/java.base/share/classes/jdk/internal/reflect/MethodHandleCharacterFieldAccessorImpl.java @@ -73,7 +73,7 @@ class MethodHandleCharacterFieldAccessorImpl extends MethodHandleFieldAccessorIm } catch (IllegalArgumentException|NullPointerException e) { throw e; } catch (ClassCastException e) { - throw newGetIllegalArgumentException(obj.getClass()); + throw newGetIllegalArgumentException(obj); } catch (Throwable e) { throw new InternalError(e); } @@ -102,8 +102,8 @@ class MethodHandleCharacterFieldAccessorImpl extends MethodHandleFieldAccessorIm public void set(Object obj, Object value) throws IllegalArgumentException, IllegalAccessException { + ensureObj(obj); if (isReadOnly()) { - ensureObj(obj); // throw NPE if obj is null on instance field throwFinalFieldIllegalAccessException(value); } @@ -146,7 +146,8 @@ class MethodHandleCharacterFieldAccessorImpl extends MethodHandleFieldAccessorIm } catch (IllegalArgumentException|NullPointerException e) { throw e; } catch (ClassCastException e) { - throw newSetIllegalArgumentException(obj.getClass()); + // receiver is of invalid type + throw newSetIllegalArgumentException(obj); } catch (Throwable e) { throw new InternalError(e); } diff --git a/src/java.base/share/classes/jdk/internal/reflect/MethodHandleDoubleFieldAccessorImpl.java b/src/java.base/share/classes/jdk/internal/reflect/MethodHandleDoubleFieldAccessorImpl.java index 2d370c331be69860590addca68f1d5241d61c170..01652951e427280e3cc77a71262ed0969963e233 100644 --- a/src/java.base/share/classes/jdk/internal/reflect/MethodHandleDoubleFieldAccessorImpl.java +++ b/src/java.base/share/classes/jdk/internal/reflect/MethodHandleDoubleFieldAccessorImpl.java @@ -93,7 +93,7 @@ class MethodHandleDoubleFieldAccessorImpl extends MethodHandleFieldAccessorImpl } catch (IllegalArgumentException|NullPointerException e) { throw e; } catch (ClassCastException e) { - throw newGetIllegalArgumentException(obj.getClass()); + throw newGetIllegalArgumentException(obj); } catch (Throwable e) { throw new InternalError(e); } @@ -102,8 +102,8 @@ class MethodHandleDoubleFieldAccessorImpl extends MethodHandleFieldAccessorImpl public void set(Object obj, Object value) throws IllegalArgumentException, IllegalAccessException { + ensureObj(obj); if (isReadOnly()) { - ensureObj(obj); // throw NPE if obj is null on instance field throwFinalFieldIllegalAccessException(value); } @@ -195,7 +195,8 @@ class MethodHandleDoubleFieldAccessorImpl extends MethodHandleFieldAccessorImpl } catch (IllegalArgumentException|NullPointerException e) { throw e; } catch (ClassCastException e) { - throw newSetIllegalArgumentException(obj.getClass()); + // receiver is of invalid type + throw newSetIllegalArgumentException(obj); } catch (Throwable e) { throw new InternalError(e); } diff --git a/src/java.base/share/classes/jdk/internal/reflect/MethodHandleFieldAccessorImpl.java b/src/java.base/share/classes/jdk/internal/reflect/MethodHandleFieldAccessorImpl.java index ab59b61d1a20757ae29709d36e15a65772c34096..f979d38f9ab73a15003e45372b9376051f53e2de 100644 --- a/src/java.base/share/classes/jdk/internal/reflect/MethodHandleFieldAccessorImpl.java +++ b/src/java.base/share/classes/jdk/internal/reflect/MethodHandleFieldAccessorImpl.java @@ -27,6 +27,7 @@ package jdk.internal.reflect; import java.lang.invoke.MethodHandle; import java.lang.reflect.Field; +import java.lang.reflect.Modifier; abstract class MethodHandleFieldAccessorImpl extends FieldAccessorImpl { private static final int IS_READ_ONLY_BIT = 0x0001; @@ -64,21 +65,32 @@ abstract class MethodHandleFieldAccessorImpl extends FieldAccessorImpl { } } + private String getMessage(boolean getter, Class type) { + String err = "Can not " + (getter ? "get" : "set"); + if (Modifier.isStatic(field.getModifiers())) + err += " static"; + if (Modifier.isFinal(field.getModifiers())) + err += " final"; + err += " " + field.getType().getName() + " field " + getQualifiedFieldName(); + if (type != null) { + err += " on " + type.getName(); + } + return err; + } + /** * IllegalArgumentException because Field::get on the specified object, which * is not an instance of the class or interface declaring the underlying method */ - protected IllegalArgumentException newGetIllegalArgumentException(Class type) { - return new IllegalArgumentException(getMessage(true, type.getName())); + protected IllegalArgumentException newGetIllegalArgumentException(Object o) { + return new IllegalArgumentException(getMessage(true, o != null ? o.getClass() : null)); } /** * IllegalArgumentException because Field::set on the specified object, which * is not an instance of the class or interface declaring the underlying method */ - protected IllegalArgumentException newSetIllegalArgumentException(Class type) { - return new IllegalArgumentException(getMessage(false, type.getName())); + protected IllegalArgumentException newSetIllegalArgumentException(Object o) { + return new IllegalArgumentException(getMessage(false, o != null ? o.getClass() : null)); } - - } diff --git a/src/java.base/share/classes/jdk/internal/reflect/MethodHandleFloatFieldAccessorImpl.java b/src/java.base/share/classes/jdk/internal/reflect/MethodHandleFloatFieldAccessorImpl.java index ee1850f33a8419a2aa107defed9ce594ceebaf66..5ac00ec5ea8e8399ceb7cf52891a03796f7e7658 100644 --- a/src/java.base/share/classes/jdk/internal/reflect/MethodHandleFloatFieldAccessorImpl.java +++ b/src/java.base/share/classes/jdk/internal/reflect/MethodHandleFloatFieldAccessorImpl.java @@ -89,7 +89,7 @@ class MethodHandleFloatFieldAccessorImpl extends MethodHandleFieldAccessorImpl { } catch (IllegalArgumentException|NullPointerException e) { throw e; } catch (ClassCastException e) { - throw newGetIllegalArgumentException(obj.getClass()); + throw newGetIllegalArgumentException(obj); } catch (Throwable e) { throw new InternalError(e); } @@ -102,8 +102,8 @@ class MethodHandleFloatFieldAccessorImpl extends MethodHandleFieldAccessorImpl { public void set(Object obj, Object value) throws IllegalArgumentException, IllegalAccessException { + ensureObj(obj); if (isReadOnly()) { - ensureObj(obj); // throw NPE if obj is null on instance field throwFinalFieldIllegalAccessException(value); } @@ -186,7 +186,8 @@ class MethodHandleFloatFieldAccessorImpl extends MethodHandleFieldAccessorImpl { } catch (IllegalArgumentException|NullPointerException e) { throw e; } catch (ClassCastException e) { - throw newSetIllegalArgumentException(obj.getClass()); + // receiver is of invalid type + throw newSetIllegalArgumentException(obj); } catch (Throwable e) { throw new InternalError(e); } diff --git a/src/java.base/share/classes/jdk/internal/reflect/MethodHandleIntegerFieldAccessorImpl.java b/src/java.base/share/classes/jdk/internal/reflect/MethodHandleIntegerFieldAccessorImpl.java index 19a17cc1ca38b5130b234775a7d4270f9bd96aff..62e3ab083dbdcb2b1d140a94713dd864b3bc6d39 100644 --- a/src/java.base/share/classes/jdk/internal/reflect/MethodHandleIntegerFieldAccessorImpl.java +++ b/src/java.base/share/classes/jdk/internal/reflect/MethodHandleIntegerFieldAccessorImpl.java @@ -81,7 +81,7 @@ class MethodHandleIntegerFieldAccessorImpl extends MethodHandleFieldAccessorImpl } catch (IllegalArgumentException|NullPointerException e) { throw e; } catch (ClassCastException e) { - throw newGetIllegalArgumentException(obj.getClass()); + throw newGetIllegalArgumentException(obj); } catch (Throwable e) { throw new InternalError(e); } @@ -102,8 +102,8 @@ class MethodHandleIntegerFieldAccessorImpl extends MethodHandleFieldAccessorImpl public void set(Object obj, Object value) throws IllegalArgumentException, IllegalAccessException { + ensureObj(obj); if (isReadOnly()) { - ensureObj(obj); // throw NPE if obj is null on instance field throwFinalFieldIllegalAccessException(value); } @@ -168,7 +168,8 @@ class MethodHandleIntegerFieldAccessorImpl extends MethodHandleFieldAccessorImpl } catch (IllegalArgumentException|NullPointerException e) { throw e; } catch (ClassCastException e) { - throw newSetIllegalArgumentException(obj.getClass()); + // receiver is of invalid type + throw newSetIllegalArgumentException(obj); } catch (Throwable e) { throw new InternalError(e); } diff --git a/src/java.base/share/classes/jdk/internal/reflect/MethodHandleLongFieldAccessorImpl.java b/src/java.base/share/classes/jdk/internal/reflect/MethodHandleLongFieldAccessorImpl.java index 42ef4c75c0505e1f3a21cc5f6bcbba88de426821..a0e02204b310120940f58775b2966aedeb6e8092 100644 --- a/src/java.base/share/classes/jdk/internal/reflect/MethodHandleLongFieldAccessorImpl.java +++ b/src/java.base/share/classes/jdk/internal/reflect/MethodHandleLongFieldAccessorImpl.java @@ -85,7 +85,7 @@ class MethodHandleLongFieldAccessorImpl extends MethodHandleFieldAccessorImpl { } catch (IllegalArgumentException|NullPointerException e) { throw e; } catch (ClassCastException e) { - throw newGetIllegalArgumentException(obj.getClass()); + throw newGetIllegalArgumentException(obj); } catch (Throwable e) { throw new InternalError(e); } @@ -102,8 +102,8 @@ class MethodHandleLongFieldAccessorImpl extends MethodHandleFieldAccessorImpl { public void set(Object obj, Object value) throws IllegalArgumentException, IllegalAccessException { + ensureObj(obj); if (isReadOnly()) { - ensureObj(obj); // throw NPE if obj is null on instance field throwFinalFieldIllegalAccessException(value); } @@ -177,7 +177,8 @@ class MethodHandleLongFieldAccessorImpl extends MethodHandleFieldAccessorImpl { } catch (IllegalArgumentException|NullPointerException e) { throw e; } catch (ClassCastException e) { - throw newSetIllegalArgumentException(obj.getClass()); + // receiver is of invalid type + throw newSetIllegalArgumentException(obj); } catch (Throwable e) { throw new InternalError(e); } diff --git a/src/java.base/share/classes/jdk/internal/reflect/MethodHandleObjectFieldAccessorImpl.java b/src/java.base/share/classes/jdk/internal/reflect/MethodHandleObjectFieldAccessorImpl.java index 57da6081c84dc6b39f84080a7395256564d64493..722d73d22a6adc1a18dbacc42eb5b659e8c3490a 100644 --- a/src/java.base/share/classes/jdk/internal/reflect/MethodHandleObjectFieldAccessorImpl.java +++ b/src/java.base/share/classes/jdk/internal/reflect/MethodHandleObjectFieldAccessorImpl.java @@ -58,7 +58,7 @@ class MethodHandleObjectFieldAccessorImpl extends MethodHandleFieldAccessorImpl } catch (IllegalArgumentException|NullPointerException e) { throw e; } catch (ClassCastException e) { - throw newGetIllegalArgumentException(obj.getClass()); + throw newGetIllegalArgumentException(obj); } catch (Throwable e) { throw new InternalError(e); } @@ -98,8 +98,8 @@ class MethodHandleObjectFieldAccessorImpl extends MethodHandleFieldAccessorImpl @Override public void set(Object obj, Object value) throws IllegalAccessException { + ensureObj(obj); if (isReadOnly()) { - ensureObj(obj); // throw NPE if obj is null on instance field throwFinalFieldIllegalAccessException(value); } try { @@ -111,7 +111,8 @@ class MethodHandleObjectFieldAccessorImpl extends MethodHandleFieldAccessorImpl } catch (IllegalArgumentException|NullPointerException e) { throw e; } catch (ClassCastException e) { - throw newSetIllegalArgumentException(obj.getClass()); + // already ensure the receiver type. So this CCE is due to the value. + throwSetIllegalArgumentException(value); } catch (Throwable e) { throw new InternalError(e); } diff --git a/src/java.base/share/classes/jdk/internal/reflect/MethodHandleShortFieldAccessorImpl.java b/src/java.base/share/classes/jdk/internal/reflect/MethodHandleShortFieldAccessorImpl.java index d9ac93d727621897f7b8e74df39aca7bde6d1a5b..265c555421a3ed7641c90946ad5257fee64af87e 100644 --- a/src/java.base/share/classes/jdk/internal/reflect/MethodHandleShortFieldAccessorImpl.java +++ b/src/java.base/share/classes/jdk/internal/reflect/MethodHandleShortFieldAccessorImpl.java @@ -77,7 +77,7 @@ class MethodHandleShortFieldAccessorImpl extends MethodHandleFieldAccessorImpl { } catch (IllegalArgumentException|NullPointerException e) { throw e; } catch (ClassCastException e) { - throw newGetIllegalArgumentException(obj.getClass()); + throw newGetIllegalArgumentException(obj); } catch (Throwable e) { throw new InternalError(e); } @@ -102,8 +102,8 @@ class MethodHandleShortFieldAccessorImpl extends MethodHandleFieldAccessorImpl { public void set(Object obj, Object value) throws IllegalArgumentException, IllegalAccessException { + ensureObj(obj); if (isReadOnly()) { - ensureObj(obj); // throw NPE if obj is null on instance field throwFinalFieldIllegalAccessException(value); } @@ -156,7 +156,8 @@ class MethodHandleShortFieldAccessorImpl extends MethodHandleFieldAccessorImpl { } catch (IllegalArgumentException|NullPointerException e) { throw e; } catch (ClassCastException e) { - throw newSetIllegalArgumentException(obj.getClass()); + // receiver is of invalid type + throw newSetIllegalArgumentException(obj); } catch (Throwable e) { throw new InternalError(e); } diff --git a/src/java.base/share/classes/jdk/internal/reflect/Reflection.java b/src/java.base/share/classes/jdk/internal/reflect/Reflection.java index ce9655f7a78358c1d7249fb0e4e86bab994cce11..23b686041e67f647d5e2dfe2fe268d63d24cc0da 100644 --- a/src/java.base/share/classes/jdk/internal/reflect/Reflection.java +++ b/src/java.base/share/classes/jdk/internal/reflect/Reflection.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -32,6 +32,7 @@ import java.util.Objects; import java.util.Set; import jdk.internal.access.SharedSecrets; import jdk.internal.misc.VM; +import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.annotation.IntrinsicCandidate; /** Common utility routines used by both java.lang and @@ -106,6 +107,7 @@ public class Reflection { } } + @ForceInline public static void ensureNativeAccess(Class currentClass) { Module module = currentClass.getModule(); if (!SharedSecrets.getJavaLangAccess().isEnableNativeAccess(module)) { @@ -377,11 +379,8 @@ public class Reflection { String msg = currentClass + currentSuffix + " cannot access "; if (m2.isExported(memberPackageName, m1)) { - // module access okay so include the modifiers in the message - msg += "a member of " + memberClass + memberSuffix + - " with modifiers \"" + Modifier.toString(modifiers) + "\""; - + msg += "a member of " + memberClass + memberSuffix + msgSuffix(modifiers); } else { // module access failed msg += memberClass + memberSuffix+ " because " @@ -408,11 +407,8 @@ public class Reflection { String msg = "JNI attached native thread (null caller frame) cannot access "; if (m2.isExported(memberPackageName)) { - // module access okay so include the modifiers in the message - msg += "a member of " + memberClass + memberSuffix + - " with modifiers \"" + Modifier.toString(modifiers) + "\""; - + msg += "a member of " + memberClass + memberSuffix + msgSuffix(modifiers); } else { // module access failed msg += memberClass + memberSuffix+ " because " @@ -422,6 +418,16 @@ public class Reflection { return new IllegalAccessException(msg); } + private static String msgSuffix(int modifiers) { + boolean packageAccess = + ((Modifier.PRIVATE | + Modifier.PROTECTED | + Modifier.PUBLIC) & modifiers) == 0; + return packageAccess ? + " with package access" : + " with modifiers \"" + Modifier.toString(modifiers) + "\""; + } + /** * Returns true if {@code currentClass} and {@code memberClass} * are nestmates - that is, if they have the same nesthost as 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 ee264330d2ba89bb4a5b28f012622c2eaa666d8e..20de7a6bc84168b9bddc50372ba3addf97b591dc 100644 --- a/src/java.base/share/classes/jdk/internal/reflect/ReflectionFactory.java +++ b/src/java.base/share/classes/jdk/internal/reflect/ReflectionFactory.java @@ -44,6 +44,7 @@ import java.util.Properties; import jdk.internal.access.JavaLangReflectAccess; import jdk.internal.access.SharedSecrets; import jdk.internal.misc.VM; +import jdk.internal.vm.annotation.Stable; import sun.security.action.GetPropertyAction; import sun.security.util.SecurityConstants; @@ -61,42 +62,12 @@ import sun.security.util.SecurityConstants; public class ReflectionFactory { - private static boolean initted = false; private static final ReflectionFactory soleInstance = new ReflectionFactory(); /* Method for static class initializer , or null */ private static volatile Method hasStaticInitializerMethod; - // - // "Inflation" mechanism. Loading bytecodes to implement - // Method.invoke() and Constructor.newInstance() currently costs - // 3-4x more than an invocation via native code for the first - // invocation (though subsequent invocations have been benchmarked - // to be over 20x faster). Unfortunately this cost increases - // startup time for certain applications that use reflection - // intensively (but only once per class) to bootstrap themselves. - // To avoid this penalty we reuse the existing JVM entry points - // for the first few invocations of Methods and Constructors and - // then switch to the bytecode-based implementations. - // - // Package-private to be accessible to NativeMethodAccessorImpl - // and NativeConstructorAccessorImpl - private static boolean noInflation = false; - private static int inflationThreshold = 15; - - // - // New implementation uses direct invocation of method handles - private static final int METHOD_MH_ACCESSOR = 0x1; - private static final int FIELD_MH_ACCESSOR = 0x2; - private static final int ALL_MH_ACCESSORS = METHOD_MH_ACCESSOR|FIELD_MH_ACCESSOR; - - private static int useDirectMethodHandle = ALL_MH_ACCESSORS; - private static boolean useNativeAccessorOnly = false; // for testing only - - // true if deserialization constructor checking is disabled - private static boolean disableSerialConstructorChecks = false; - private final JavaLangReflectAccess langReflectAccess; private ReflectionFactory() { this.langReflectAccess = SharedSecrets.getJavaLangReflectAccess(); @@ -160,8 +131,6 @@ public class ReflectionFactory { * @param override true if caller has overridden accessibility */ public FieldAccessor newFieldAccessor(Field field, boolean override) { - checkInitted(); - Field root = langReflectAccess.getRoot(field); if (root != null) { // FieldAccessor will use the root unless the modifiers have @@ -180,8 +149,6 @@ public class ReflectionFactory { } public MethodAccessor newMethodAccessor(Method method, boolean callerSensitive) { - checkInitted(); - // use the root Method that will not cache caller class Method root = langReflectAccess.getRoot(method); if (root != null) { @@ -191,7 +158,7 @@ public class ReflectionFactory { if (useMethodHandleAccessor()) { return MethodHandleAccessorFactory.newMethodAccessor(method, callerSensitive); } else { - if (noInflation && !method.getDeclaringClass().isHidden()) { + if (noInflation() && !method.getDeclaringClass().isHidden()) { return generateMethodAccessor(method); } else { NativeMethodAccessorImpl acc = new NativeMethodAccessorImpl(method); @@ -215,8 +182,6 @@ public class ReflectionFactory { } public ConstructorAccessor newConstructorAccessor(Constructor c) { - checkInitted(); - Class declaringClass = c.getDeclaringClass(); if (Modifier.isAbstract(declaringClass.getModifiers())) { return new InstantiationExceptionConstructorAccessorImpl(null); @@ -242,7 +207,7 @@ public class ReflectionFactory { return new BootstrapConstructorAccessorImpl(c); } - if (noInflation && !c.getDeclaringClass().isHidden()) { + if (noInflation() && !c.getDeclaringClass().isHidden()) { return new MethodAccessorGenerator(). generateConstructor(c.getDeclaringClass(), c.getParameterTypes(), @@ -430,7 +395,7 @@ public class ReflectionFactory { while (Serializable.class.isAssignableFrom(initCl)) { Class prev = initCl; if ((initCl = initCl.getSuperclass()) == null || - (!disableSerialConstructorChecks && !superHasAccessibleConstructor(prev))) { + (!disableSerialConstructorChecks() && !superHasAccessibleConstructor(prev))) { return null; } } @@ -623,41 +588,108 @@ public class ReflectionFactory { // Internals only below this point // + // Package-private to be accessible to NativeMethodAccessorImpl + // and NativeConstructorAccessorImpl static int inflationThreshold() { - return inflationThreshold; + return config().inflationThreshold; } static boolean noInflation() { - return noInflation; + return config().noInflation; } static boolean useMethodHandleAccessor() { - return (useDirectMethodHandle & METHOD_MH_ACCESSOR) == METHOD_MH_ACCESSOR; + return (config().useDirectMethodHandle & METHOD_MH_ACCESSOR) == METHOD_MH_ACCESSOR; } static boolean useFieldHandleAccessor() { - return (useDirectMethodHandle & FIELD_MH_ACCESSOR) == FIELD_MH_ACCESSOR; + return (config().useDirectMethodHandle & FIELD_MH_ACCESSOR) == FIELD_MH_ACCESSOR; } static boolean useNativeAccessorOnly() { - return useNativeAccessorOnly; + return config().useNativeAccessorOnly; } - /** We have to defer full initialization of this class until after - the static initializer is run since java.lang.reflect.Method's - static initializer (more properly, that for - java.lang.reflect.AccessibleObject) causes this class's to be - run, before the system properties are set up. */ - private static void checkInitted() { - if (initted) return; + private static boolean disableSerialConstructorChecks() { + return config().disableSerialConstructorChecks; + } + + // New implementation uses direct invocation of method handles + private static final int METHOD_MH_ACCESSOR = 0x1; + private static final int FIELD_MH_ACCESSOR = 0x2; + private static final int ALL_MH_ACCESSORS = METHOD_MH_ACCESSOR | FIELD_MH_ACCESSOR; + + /** + * The configuration is lazily initialized after the module system is initialized. The + * default config would be used before the proper config is loaded. + * + * The static initializer of ReflectionFactory is run before the system properties are set up. + * The class initialization is caused by the class initialization of java.lang.reflect.Method + * (more properly, caused by the class initialization for java.lang.reflect.AccessibleObject) + * that happens very early VM startup, initPhase1. + */ + private static @Stable Config config; + + // "Inflation" mechanism. Loading bytecodes to implement + // Method.invoke() and Constructor.newInstance() currently costs + // 3-4x more than an invocation via native code for the first + // invocation (though subsequent invocations have been benchmarked + // to be over 20x faster). Unfortunately this cost increases + // startup time for certain applications that use reflection + // intensively (but only once per class) to bootstrap themselves. + // To avoid this penalty we reuse the existing JVM entry points + // for the first few invocations of Methods and Constructors and + // then switch to the bytecode-based implementations. + + private static final Config DEFAULT_CONFIG = new Config(false, // noInflation + 15, // inflationThreshold + ALL_MH_ACCESSORS, // useDirectMethodHandle + false, // useNativeAccessorOnly + false); // disableSerialConstructorChecks + + /** + * The configurations for the reflection factory. Configurable via + * system properties but only available after ReflectionFactory is + * loaded during early VM startup. + * + * Note that the default implementations of the object methods of + * this Config record (toString, equals, hashCode) use indy, + * which is available to use only after initPhase1. These methods + * are currently not called, but should they be needed, a workaround + * is to override them. + */ + private record Config(boolean noInflation, + int inflationThreshold, + int useDirectMethodHandle, + boolean useNativeAccessorOnly, + boolean disableSerialConstructorChecks) { + } + + private static Config config() { + Config c = config; + if (c != null) { + return c; + } // Defer initialization until module system is initialized so as // to avoid inflation and spinning bytecode in unnamed modules // during early startup. if (!VM.isModuleSystemInited()) { - return; + return DEFAULT_CONFIG; } + return config = loadConfig(); + } + + private static Config loadConfig() { + assert VM.isModuleSystemInited(); + + boolean noInflation = DEFAULT_CONFIG.noInflation; + int inflationThreshold = DEFAULT_CONFIG.inflationThreshold; + int useDirectMethodHandle = DEFAULT_CONFIG.useDirectMethodHandle; + boolean useNativeAccessorOnly = DEFAULT_CONFIG.useNativeAccessorOnly; + boolean disableSerialConstructorChecks = DEFAULT_CONFIG.disableSerialConstructorChecks; + Properties props = GetPropertyAction.privilegedGetProperties(); String val = props.getProperty("sun.reflect.noInflation"); if (val != null && val.equals("true")) { @@ -690,7 +722,11 @@ public class ReflectionFactory { disableSerialConstructorChecks = "true".equals(props.getProperty("jdk.disableSerialConstructorChecks")); - initted = true; + return new Config(noInflation, + inflationThreshold, + useDirectMethodHandle, + useNativeAccessorOnly, + disableSerialConstructorChecks); } /** diff --git a/src/java.base/share/classes/jdk/internal/util/random/RandomSupport.java b/src/java.base/share/classes/jdk/internal/util/random/RandomSupport.java index 1d64432979d907864d3ebb928e78fe4125b7d3af..24a73f734d3ceb0b368051fd20811e05be2ef846 100644 --- a/src/java.base/share/classes/jdk/internal/util/random/RandomSupport.java +++ b/src/java.base/share/classes/jdk/internal/util/random/RandomSupport.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -265,7 +265,7 @@ public class RandomSupport { final int m = Math.min(seed.length, n << 3); // Distribute seed bytes into the words to be formed. for (int j = 0; j < m; j++) { - result[j>>3] = (result[j>>3] << 8) | seed[j]; + result[j>>3] = (result[j>>3] << 8) | (seed[j] & 0xFF); } // If there aren't enough seed bytes for all the words we need, // use a SplitMix-style PRNG to fill in the rest. @@ -645,7 +645,7 @@ public class RandomSupport { if (origin < bound) { r = r * (bound - origin) + origin; if (r >= bound) // may need to correct a rounding problem - r = Double.longBitsToDouble(Double.doubleToLongBits(bound) - 1); + r = Math.nextAfter(bound, origin); } return r; } @@ -677,7 +677,7 @@ public class RandomSupport { double r = rng.nextDouble(); r = r * bound; if (r >= bound) // may need to correct a rounding problem - r = Double.longBitsToDouble(Double.doubleToLongBits(bound) - 1); + r = Math.nextDown(bound); return r; } @@ -1186,10 +1186,10 @@ public class RandomSupport { // For the exponential distribution, every overhang is convex. final double[] X = DoubleZigguratTables.exponentialX; final double[] Y = DoubleZigguratTables.exponentialY; - for (;; U1 = (rng.nextLong() >>> 1)) { + // At this point, the high-order bits of U1 have not been used yet, + // but we need the value in U1 to be positive. + for (U1 = (U1 >>> 1);; U1 = (rng.nextLong() >>> 1)) { long U2 = (rng.nextLong() >>> 1); - // Compute the actual x-coordinate of the randomly chosen point. - double x = (X[j] * 0x1.0p63) + ((X[j-1] - X[j]) * (double)U1); // Does the point lie below the curve? long Udiff = U2 - U1; if (Udiff < 0) { @@ -1200,11 +1200,13 @@ public class RandomSupport { U2 = U1; U1 -= Udiff; } + // Compute the actual x-coordinate of the randomly chosen point. + double x = (X[j] * 0x1.0p63) + ((X[j-1] - X[j]) * (double)U1); if (Udiff >= DoubleZigguratTables.exponentialConvexMargin) { return x + extra; // The chosen point is way below the curve; accept it. } // Compute the actual y-coordinate of the randomly chosen point. - double y = (Y[j] * 0x1.0p63) + ((Y[j] - Y[j-1]) * (double)U2); + double y = (Y[j] * 0x1.0p63) + ((Y[j-1] - Y[j]) * (double)U2); // Now see how that y-coordinate compares to the curve if (y <= Math.exp(-x)) { return x + extra; // The chosen point is below the curve; accept it. @@ -1323,7 +1325,7 @@ public class RandomSupport { continue; // The chosen point is way above the curve; reject it. } // Compute the actual y-coordinate of the randomly chosen point. - double y = (Y[j] * 0x1.0p63) + ((Y[j] - Y[j-1]) * (double)U2); + double y = (Y[j] * 0x1.0p63) + ((Y[j-1] - Y[j]) * (double)U2); // Now see how that y-coordinate compares to the curve if (y <= Math.exp(-0.5*x*x)) { break; // The chosen point is below the curve; accept it. @@ -1348,8 +1350,6 @@ public class RandomSupport { } else if (j < DoubleZigguratTables.normalInflectionIndex) { // Convex overhang for (;; U1 = (rng.nextLong() >>> 1)) { long U2 = (rng.nextLong() >>> 1); - // Compute the actual x-coordinate of the randomly chosen point. - x = (X[j] * 0x1.0p63) + ((X[j-1] - X[j]) * (double)U1); // Does the point lie below the curve? long Udiff = U2 - U1; if (Udiff < 0) { @@ -1360,11 +1360,13 @@ public class RandomSupport { U2 = U1; U1 -= Udiff; } + // Compute the actual x-coordinate of the randomly chosen point. + x = (X[j] * 0x1.0p63) + ((X[j-1] - X[j]) * (double)U1); if (Udiff >= DoubleZigguratTables.normalConvexMargin) { break; // The chosen point is way below the curve; accept it. } // Compute the actual y-coordinate of the randomly chosen point. - double y = (Y[j] * 0x1.0p63) + ((Y[j] - Y[j-1]) * (double)U2); + double y = (Y[j] * 0x1.0p63) + ((Y[j-1] - Y[j]) * (double)U2); // Now see how that y-coordinate compares to the curve if (y <= Math.exp(-0.5*x*x)) break; // The chosen point is below the curve; accept it. // Otherwise, we reject this sample and have to try again. @@ -1384,7 +1386,7 @@ public class RandomSupport { continue; // The chosen point is way above the curve; reject it. } // Compute the actual y-coordinate of the randomly chosen point. - double y = (Y[j] * 0x1.0p63) + ((Y[j] - Y[j-1]) * (double)U2); + double y = (Y[j] * 0x1.0p63) + ((Y[j-1] - Y[j]) * (double)U2); // Now see how that y-coordinate compares to the curve if (y <= Math.exp(-0.5*x*x)) { break; // The chosen point is below the curve; accept it. 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 63e007657929b255c160724b8a99bc3f8eae98c8..13d75662ab6f80d41b6735005510b6e94656ece5 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 @@ -63,17 +63,18 @@ public class VectorSupport { public static final int VECTOR_OP_URSHIFT = 16; public static final int VECTOR_OP_CAST = 17; - public static final int VECTOR_OP_REINTERPRET = 18; + public static final int VECTOR_OP_UCAST = 18; + public static final int VECTOR_OP_REINTERPRET = 19; // Mask manipulation operations - public static final int VECTOR_OP_MASK_TRUECOUNT = 19; - public static final int VECTOR_OP_MASK_FIRSTTRUE = 20; - public static final int VECTOR_OP_MASK_LASTTRUE = 21; - public static final int VECTOR_OP_MASK_TOLONG = 22; + public static final int VECTOR_OP_MASK_TRUECOUNT = 20; + public static final int VECTOR_OP_MASK_FIRSTTRUE = 21; + public static final int VECTOR_OP_MASK_LASTTRUE = 22; + public static final int VECTOR_OP_MASK_TOLONG = 23; // Rotate operations - public static final int VECTOR_OP_LROTATE = 23; - public static final int VECTOR_OP_RROTATE = 24; + public static final int VECTOR_OP_LROTATE = 24; + public static final int VECTOR_OP_RROTATE = 25; // Math routines public static final int VECTOR_OP_TAN = 101; @@ -114,6 +115,10 @@ public class VectorSupport { public static final int BT_ult = BT_lt | BT_unsigned_compare; public static final int BT_ugt = BT_gt | BT_unsigned_compare; + // Various broadcasting modes. + public static final int MODE_BROADCAST = 0; + public static final int MODE_BITS_COERCED_LONG_TO_MASK = 1; + // BasicType codes, for primitives only: public static final int T_FLOAT = 6, @@ -157,9 +162,9 @@ public class VectorSupport { } /* ============================================================================ */ - public interface BroadcastOperation> { - VM broadcast(long l, S s); + public interface FromBitsCoercedOperation> { + VM fromBits(long l, S s); } @IntrinsicCandidate @@ -167,12 +172,12 @@ public class VectorSupport { , E> - VM broadcastCoerced(Class vmClass, Class eClass, - int length, - long bits, S s, - BroadcastOperation defaultImpl) { + VM fromBitsCoerced(Class vmClass, Class eClass, + int length, + long bits, int mode, S s, + FromBitsCoercedOperation defaultImpl) { assert isNonCapturingLambda(defaultImpl) : defaultImpl; - return defaultImpl.broadcast(bits, s); + return defaultImpl.fromBits(bits, s); } /* ============================================================================ */ diff --git a/src/java.base/share/classes/sun/launcher/LauncherHelper.java b/src/java.base/share/classes/sun/launcher/LauncherHelper.java index 82b73d01c6b6321284dda8fbab3561683e83ca1f..1f2db91f472b1e0b5d03baf373ca157754709d79 100644 --- a/src/java.base/share/classes/sun/launcher/LauncherHelper.java +++ b/src/java.base/share/classes/sun/launcher/LauncherHelper.java @@ -34,11 +34,6 @@ package sun.launcher; * */ -/** - * A utility package for the java(1), javaw(1) launchers. - * The following are helper methods that the native launcher uses - * to perform checks etc. using JNI, see src/share/bin/java.c - */ import java.io.File; import java.io.IOException; import java.io.PrintStream; @@ -88,7 +83,11 @@ import jdk.internal.module.Modules; import jdk.internal.platform.Container; import jdk.internal.platform.Metrics; - +/** + * A utility package for the java(1), javaw(1) launchers. + * The following are helper methods that the native launcher uses + * to perform checks etc. using JNI, see src/share/bin/java.c + */ public final class LauncherHelper { // No instantiation @@ -154,8 +153,8 @@ public final class LauncherHelper { long initialHeapSize, long maxHeapSize, long stackSize) { initOutput(printToStderr); - String opts[] = optionFlag.split(":"); - String optStr = (opts.length > 1 && opts[1] != null) + String[] opts = optionFlag.split(":"); + String optStr = opts.length > 1 ? opts[1].trim() : "all"; switch (optStr) { diff --git a/src/java.base/share/classes/sun/launcher/resources/launcher.properties b/src/java.base/share/classes/sun/launcher/resources/launcher.properties index efcc4d69969431a35398d81a083ca035d810bb87..4a80f1f685d2596b8e095e0e846bb39eb654765d 100644 --- a/src/java.base/share/classes/sun/launcher/resources/launcher.properties +++ b/src/java.base/share/classes/sun/launcher/resources/launcher.properties @@ -194,7 +194,11 @@ java.launcher.X.usage=\n\ \ override or augment a module with classes and resources\n\ \ in JAR files or directories.\n\ \ --source \n\ -\ set the version of the source in source-file mode.\n\n\ +\ set the version of the source in source-file mode.\n\ +\ --finalization=\n\ +\ controls whether the JVM performs finalization of objects,\n\ +\ where is one of "enabled" or "disabled".\n\ +\ Finalization is enabled by default.\n\n\ These extra options are subject to change without notice.\n # Translators please note do not translate the options themselves diff --git a/src/java.base/share/classes/sun/net/NetProperties.java b/src/java.base/share/classes/sun/net/NetProperties.java index 5ff150b105a8a6ea8eaa4487cd62689539437815..d3f0bd4905bdf7113be0bb62fab821ebb2783434 100644 --- a/src/java.base/share/classes/sun/net/NetProperties.java +++ b/src/java.base/share/classes/sun/net/NetProperties.java @@ -68,10 +68,9 @@ public class NetProperties { File f = new File(fname, "conf"); f = new File(f, "net.properties"); fname = f.getCanonicalPath(); - InputStream in = new FileInputStream(fname); - BufferedInputStream bin = new BufferedInputStream(in); - props.load(bin); - bin.close(); + try (FileInputStream in = new FileInputStream(fname)) { + props.load(in); + } } catch (Exception e) { // Do nothing. We couldn't find or access the file // so we won't have default properties... diff --git a/src/java.base/share/classes/sun/net/www/MeteredStream.java b/src/java.base/share/classes/sun/net/www/MeteredStream.java index 049b16c03c6b90828ee8fdcb2e87eb17a81e98c8..fc0579a679e107c9325e4b63326e0f8f0db3b912 100644 --- a/src/java.base/share/classes/sun/net/www/MeteredStream.java +++ b/src/java.base/share/classes/sun/net/www/MeteredStream.java @@ -242,7 +242,7 @@ public class MeteredStream extends FilterInputStream { return readLock.isHeldByCurrentThread(); } - @SuppressWarnings("deprecation") + @SuppressWarnings("removal") protected void finalize() throws Throwable { try { close(); diff --git a/src/java.base/share/classes/sun/net/www/MimeEntry.java b/src/java.base/share/classes/sun/net/www/MimeEntry.java index 48b847cf558d18fb570655254a8a21809ad4064a..3422b58e1bc39cc6bb1eb7db7bca053f6fcaf5fc 100644 --- a/src/java.base/share/classes/sun/net/www/MimeEntry.java +++ b/src/java.base/share/classes/sun/net/www/MimeEntry.java @@ -24,7 +24,6 @@ */ package sun.net.www; -import java.net.URL; import java.io.*; import java.util.StringJoiner; import java.util.StringTokenizer; @@ -63,34 +62,6 @@ public class MimeEntry implements Cloneable { this(type, UNKNOWN, null, null, null); } - // - // The next two constructors are used only by the deprecated - // PlatformMimeTable classes or, in last case, is called by the public - // constructor. They are kept here anticipating putting support for - // mailcap formatted config files back in (so BOTH the properties format - // and the mailcap formats are supported). - // - MimeEntry(String type, String imageFileName, String extensionString) { - typeName = type.toLowerCase(); - action = UNKNOWN; - command = null; - this.imageFileName = imageFileName; - setExtensions(extensionString); - starred = isStarred(typeName); - } - - // For use with MimeTable::parseMailCap - MimeEntry(String typeName, int action, String command, - String tempFileNameTemplate) { - this.typeName = typeName.toLowerCase(); - this.action = action; - this.command = command; - this.imageFileName = null; - this.fileExtensions = null; - - this.tempFileNameTemplate = tempFileNameTemplate; - } - // This is the one called by the public constructor. MimeEntry(String typeName, int action, String command, String imageFileName, String fileExtensions[]) { diff --git a/src/java.base/share/classes/sun/net/www/MimeTable.java b/src/java.base/share/classes/sun/net/www/MimeTable.java index fd8c5565dfafcdddd8192e0f20ab69c055246711..accbe8b1c199945fd5969a13cb782f24330b9e8e 100644 --- a/src/java.base/share/classes/sun/net/www/MimeTable.java +++ b/src/java.base/share/classes/sun/net/www/MimeTable.java @@ -37,11 +37,11 @@ import java.util.StringTokenizer; public class MimeTable implements FileNameMap { /** Keyed by content type, returns MimeEntries */ private Hashtable entries - = new Hashtable(); + = new Hashtable<>(); /** Keyed by file extension (with the .), returns MimeEntries */ private Hashtable extensionMap - = new Hashtable(); + = new Hashtable<>(); // Will be reset if in the platform-specific data file @SuppressWarnings("removal") @@ -55,7 +55,6 @@ public class MimeTable implements FileNameMap { }); private static final String filePreamble = "sun.net.www MIME content-types table"; - private static final String fileMagic = "#" + filePreamble; MimeTable() { load(); @@ -67,7 +66,7 @@ public class MimeTable implements FileNameMap { @SuppressWarnings("removal") static MimeTable getDefaultInstance() { return java.security.AccessController.doPrivileged( - new java.security.PrivilegedAction() { + new java.security.PrivilegedAction<>() { public MimeTable run() { MimeTable instance = new MimeTable(); URLConnection.setFileNameMap(instance); @@ -244,8 +243,8 @@ public class MimeTable implements FileNameMap { throw new InternalError("default mime table not found"); } - try (BufferedInputStream bin = new BufferedInputStream(in)) { - entries.load(bin); + try (in) { + entries.load(in); } catch (IOException e) { System.err.println("Warning: " + e.getMessage()); } @@ -349,17 +348,6 @@ public class MimeTable implements FileNameMap { // else illegal name exception } - String[] getExtensions(String list) { - StringTokenizer tokenizer = new StringTokenizer(list, ","); - int n = tokenizer.countTokens(); - String[] extensions = new String[n]; - for (int i = 0; i < n; i++) { - extensions[i] = tokenizer.nextToken(); - } - - return extensions; - } - int getActionCode(String action) { for (int i = 0; i < MimeEntry.actionKeywords.length; i++) { if (action.equalsIgnoreCase(MimeEntry.actionKeywords[i])) { @@ -382,9 +370,7 @@ public class MimeTable implements FileNameMap { } protected boolean saveAsProperties(File file) { - FileOutputStream os = null; - try { - os = new FileOutputStream(file); + try (FileOutputStream os = new FileOutputStream(file)) { Properties properties = getAsProperties(); properties.put("temp.file.template", tempFileTemplate); String tag; @@ -407,11 +393,6 @@ public class MimeTable implements FileNameMap { e.printStackTrace(); return false; } - finally { - if (os != null) { - try { os.close(); } catch (IOException e) {} - } - } return true; } diff --git a/src/java.base/share/classes/sun/net/www/http/HttpCapture.java b/src/java.base/share/classes/sun/net/www/http/HttpCapture.java index 48e3dccd58c59f39b40c51f775ba4650fa3eae98..1d2732e0473ab0b3cd484e1f372ac6f21f27de65 100644 --- a/src/java.base/share/classes/sun/net/www/http/HttpCapture.java +++ b/src/java.base/share/classes/sun/net/www/http/HttpCapture.java @@ -157,7 +157,7 @@ public class HttpCapture { if (p.matcher(s).find()) { String f = capFiles.get(i); File fi; - if (f.indexOf("%d") >= 0) { + if (f.contains("%d")) { java.util.Random rand = new java.util.Random(); do { String f2 = f.replace("%d", Integer.toString(rand.nextInt())); diff --git a/src/java.base/share/classes/sun/net/www/http/HttpClient.java b/src/java.base/share/classes/sun/net/www/http/HttpClient.java index 4b3c40b4fc01f7ed30f680409a2e1e725a48b716..a603badb0c6cb595cd345ef76f8518954250e903 100644 --- a/src/java.base/share/classes/sun/net/www/http/HttpClient.java +++ b/src/java.base/share/classes/sun/net/www/http/HttpClient.java @@ -122,13 +122,13 @@ public class HttpClient extends NetworkClient { recomputing the value of keepingAlive */ int keepAliveConnections = -1; /* number of keep-alives left */ - /**Idle timeout value, in milliseconds. Zero means infinity, - * iff keepingAlive=true. - * Unfortunately, we can't always believe this one. If I'm connected - * through a Netscape proxy to a server that sent me a keep-alive - * time of 15 sec, the proxy unilaterally terminates my connection - * after 5 sec. So we have to hard code our effective timeout to - * 4 sec for the case where we're using a proxy. *SIGH* + /* + * The timeout if specified by the server. Following values possible + * 0: the server specified no keep alive headers + * -1: the server provided "Connection: keep-alive" but did not specify a + * a particular time in a "Keep-Alive:" headers + * Positive values are the number of seconds specified by the server + * in a "Keep-Alive" header */ int keepAliveTimeout = 0; @@ -144,12 +144,27 @@ public class HttpClient extends NetworkClient { // Traffic capture tool, if configured. See HttpCapture class for info private HttpCapture capture = null; + /* "jdk.https.negotiate.cbt" property can be set to "always" (always sent), "never" (never sent) or + * "domain:a,c.d,*.e.f" (sent to host a, or c.d or to the domain e.f and any of its subdomains). This is + * a comma separated list of arbitrary length with no white-space allowed. + * If enabled (for a particular destination) then Negotiate/SPNEGO authentication requests will include + * a channel binding token for the destination server. The default behavior and setting for the + * property is "never" + */ + private static final String spnegoCBT; + private static final PlatformLogger logger = HttpURLConnection.getHttpLogger(); + private static void logFinest(String msg) { if (logger.isLoggable(PlatformLogger.Level.FINEST)) { logger.finest(msg); } } + private static void logError(String msg) { + if (logger.isLoggable(PlatformLogger.Level.SEVERE)) { + logger.severe(msg); + } + } protected volatile String authenticatorKey; @@ -165,6 +180,18 @@ public class HttpClient extends NetworkClient { return keepAliveTimeout; } + static String normalizeCBT(String s) { + if (s == null || s.equals("never")) { + return "never"; + } + if (s.equals("always") || s.startsWith("domain:")) { + return s; + } else { + logError("Unexpected value for \"jdk.https.negotiate.cbt\" system property"); + return "never"; + } + } + static { Properties props = GetPropertyAction.privilegedGetProperties(); String keepAlive = props.getProperty("http.keepAlive"); @@ -172,6 +199,9 @@ public class HttpClient extends NetworkClient { String cacheNTLM = props.getProperty("jdk.ntlm.cache"); String cacheSPNEGO = props.getProperty("jdk.spnego.cache"); + String s = props.getProperty("jdk.https.negotiate.cbt"); + spnegoCBT = normalizeCBT(s); + if (keepAlive != null) { keepAliveProp = Boolean.parseBoolean(keepAlive); } else { @@ -205,6 +235,9 @@ public class HttpClient extends NetworkClient { return keepAliveProp; } + public String getSpnegoCBT() { + return spnegoCBT; + } protected HttpClient() { } @@ -864,7 +897,7 @@ public class HttpClient extends NetworkClient { responses.findValue("Keep-Alive")); /* default should be larger in case of proxy */ keepAliveConnections = p.findInt("max", usingProxy?50:5); - keepAliveTimeout = p.findInt("timeout", usingProxy?60:5); + keepAliveTimeout = p.findInt("timeout", -1); } } else if (b[7] != '0') { /* @@ -1117,6 +1150,10 @@ public class HttpClient extends NetworkClient { } } + public boolean getUsingProxy() { + return usingProxy; + } + /** * @return the proxy port being used for this client. Meaningless * if getProxyHostUsed() gives null. diff --git a/src/java.base/share/classes/sun/net/www/http/KeepAliveCache.java b/src/java.base/share/classes/sun/net/www/http/KeepAliveCache.java index 45dfdad08e090b45c70401bc390adff823bce321..85569e599c2db3d9de79c3529cd03be0ccd5be30 100644 --- a/src/java.base/share/classes/sun/net/www/http/KeepAliveCache.java +++ b/src/java.base/share/classes/sun/net/www/http/KeepAliveCache.java @@ -41,6 +41,8 @@ import java.util.concurrent.locks.ReentrantLock; import jdk.internal.misc.InnocuousThread; import sun.security.action.GetIntegerAction; +import sun.net.www.protocol.http.HttpURLConnection; +import sun.util.logging.PlatformLogger; /** * A class that implements a cache of idle Http connections for keep-alive @@ -54,6 +56,32 @@ public class KeepAliveCache @java.io.Serial private static final long serialVersionUID = -2937172892064557949L; + // Keep alive time set according to priority specified here: + // 1. If server specifies a time with a Keep-Alive header + // 2. If user specifies a time with system property below + // 3. Default values which depend on proxy vs server and whether + // a Connection: keep-alive header was sent by server + + // name suffixed with "server" or "proxy" + private static final String keepAliveProp = "http.keepAlive.time."; + + private static final int userKeepAliveServer; + private static final int userKeepAliveProxy; + + static final PlatformLogger logger = HttpURLConnection.getHttpLogger(); + + @SuppressWarnings("removal") + static int getUserKeepAliveSeconds(String type) { + int v = AccessController.doPrivileged( + new GetIntegerAction(keepAliveProp+type, -1)).intValue(); + return v < -1 ? -1 : v; + } + + static { + userKeepAliveServer = getUserKeepAliveSeconds("server"); + userKeepAliveProxy = getUserKeepAliveSeconds("proxy"); + } + /* maximum # keep-alive connections to maintain at once * This should be 2 by the HTTP spec, but because we don't support pipe-lining * a larger value is more appropriate. So we now set a default of 5, and the value @@ -127,10 +155,29 @@ public class KeepAliveCache if (v == null) { int keepAliveTimeout = http.getKeepAliveTimeout(); - v = new ClientVector(keepAliveTimeout > 0 ? - keepAliveTimeout * 1000 : LIFETIME); - v.put(http); - super.put(key, v); + if (keepAliveTimeout == 0) { + keepAliveTimeout = getUserKeepAlive(http.getUsingProxy()); + if (keepAliveTimeout == -1) { + // same default for server and proxy + keepAliveTimeout = 5; + } + } else if (keepAliveTimeout == -1) { + keepAliveTimeout = getUserKeepAlive(http.getUsingProxy()); + if (keepAliveTimeout == -1) { + // different default for server and proxy + keepAliveTimeout = http.getUsingProxy() ? 60 : 5; + } + } + // at this point keepAliveTimeout is the number of seconds to keep + // alive, which could be 0, if the user specified 0 for the property + assert keepAliveTimeout >= 0; + if (keepAliveTimeout == 0) { + http.closeServer(); + } else { + v = new ClientVector(keepAliveTimeout * 1000); + v.put(http); + super.put(key, v); + } } else { v.put(http); } @@ -139,6 +186,11 @@ public class KeepAliveCache } } + // returns the keep alive set by user in system property or -1 if not set + private static int getUserKeepAlive(boolean isProxy) { + return isProxy ? userKeepAliveProxy : userKeepAliveServer; + } + /* remove an obsolete HttpClient from its VectorCache */ public void remove(HttpClient h, Object obj) { cacheLock.lock(); @@ -277,6 +329,11 @@ class ClientVector extends ArrayDeque { e.hc.closeServer(); } else { hc = e.hc; + if (KeepAliveCache.logger.isLoggable(PlatformLogger.Level.FINEST)) { + String msg = "cached HttpClient was idle for " + + Long.toString(currentTime - e.idleStartTime); + KeepAliveCache.logger.finest(msg); + } } } while ((hc == null) && (!isEmpty())); return hc; diff --git a/src/java.base/share/classes/sun/net/www/protocol/http/HttpCallerInfo.java b/src/java.base/share/classes/sun/net/www/protocol/http/HttpCallerInfo.java index 038f7adfe905880754fe68a93b4f543f1df3cf2a..5afed084c7f35603b048b2a6530afee2228b0f9c 100644 --- a/src/java.base/share/classes/sun/net/www/protocol/http/HttpCallerInfo.java +++ b/src/java.base/share/classes/sun/net/www/protocol/http/HttpCallerInfo.java @@ -29,6 +29,7 @@ import java.net.Authenticator; import java.net.Authenticator.RequestorType; import java.net.InetAddress; import java.net.URL; +import java.security.cert.X509Certificate; /** * Used in HTTP/Negotiate, to feed HTTP request info into JGSS as a HttpCaller, @@ -51,6 +52,9 @@ public final class HttpCallerInfo { public final InetAddress addr; public final RequestorType authType; public final Authenticator authenticator; + // Used to obtain server cert for SPNEGO CBT. + // May be null in which case CBT is not set + public final X509Certificate serverCert; /** * Create a schemed object based on an un-schemed one. @@ -65,13 +69,19 @@ public final class HttpCallerInfo { this.authType = old.authType; this.scheme = scheme; this.authenticator = old.authenticator; + this.serverCert = old.serverCert; } /** * Constructor an un-schemed object for site access. */ public HttpCallerInfo(URL url, Authenticator a) { + this(url, null, a); + } + + public HttpCallerInfo(URL url, X509Certificate serverCert, Authenticator a) { this.url= url; + this.serverCert= serverCert; prompt = ""; host = url.getHost(); @@ -100,9 +110,14 @@ public final class HttpCallerInfo { * Constructor an un-schemed object for proxy access. */ public HttpCallerInfo(URL url, String host, int port, Authenticator a) { + this(url, host, port, null, a); + } + + public HttpCallerInfo(URL url, String host, int port, X509Certificate serverCert, Authenticator a) { this.url= url; this.host = host; this.port = port; + this.serverCert = serverCert; prompt = ""; addr = null; protocol = url.getProtocol(); 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 cba385f04fa2a2621ad853b7817576f794d6f191..0ce0d29ee675e18ec1cccfd6249cf5506ea0f91e 100644 --- a/src/java.base/share/classes/sun/net/www/protocol/http/HttpURLConnection.java +++ b/src/java.base/share/classes/sun/net/www/protocol/http/HttpURLConnection.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 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 @@ -288,8 +288,7 @@ public class HttpURLConnection extends java.net.HttpURLConnection { } static final String httpVersion = "HTTP/1.1"; - static final String acceptString = - "text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2"; + static final String acceptString = "*/*"; // the following http request headers should NOT have their values // returned for security reasons. @@ -1740,7 +1739,7 @@ public class HttpURLConnection extends java.net.HttpURLConnection { AuthenticationHeader authhdr = new AuthenticationHeader ( "Proxy-Authenticate", responses, - new HttpCallerInfo(url, + getHttpCallerInfo(url, http.getProxyHostUsed(), http.getProxyPortUsed(), authenticator), @@ -1815,7 +1814,7 @@ public class HttpURLConnection extends java.net.HttpURLConnection { srvHdr = new AuthenticationHeader ( "WWW-Authenticate", responses, - new HttpCallerInfo(url, authenticator), + getHttpCallerInfo(url, authenticator), dontUseNegotiate ); @@ -2211,7 +2210,7 @@ public class HttpURLConnection extends java.net.HttpURLConnection { AuthenticationHeader authhdr = new AuthenticationHeader( "Proxy-Authenticate", responses, - new HttpCallerInfo(url, + getHttpCallerInfo(url, http.getProxyHostUsed(), http.getProxyPortUsed(), authenticator), @@ -2280,6 +2279,21 @@ public class HttpURLConnection extends java.net.HttpURLConnection { responses.reset(); } + /** + * Overridden in https to also include the server certificate + */ + protected HttpCallerInfo getHttpCallerInfo(URL url, String proxy, int port, + Authenticator authenticator) { + return new HttpCallerInfo(url, proxy, port, authenticator); + } + + /** + * Overridden in https to also include the server certificate + */ + protected HttpCallerInfo getHttpCallerInfo(URL url, Authenticator authenticator) { + return new HttpCallerInfo(url, authenticator); + } + static String connectRequestURI(URL url) { String host = url.getHost(); int port = url.getPort(); diff --git a/src/java.base/share/classes/sun/net/www/protocol/https/AbstractDelegateHttpsURLConnection.java b/src/java.base/share/classes/sun/net/www/protocol/https/AbstractDelegateHttpsURLConnection.java index 3828eb3cd29a38cad87f9c6b7428fa7287e0f3f5..ff54e474b8e696d2b93c0ff6e13f103617e2ff0b 100644 --- a/src/java.base/share/classes/sun/net/www/protocol/https/AbstractDelegateHttpsURLConnection.java +++ b/src/java.base/share/classes/sun/net/www/protocol/https/AbstractDelegateHttpsURLConnection.java @@ -1,4 +1,4 @@ -/* +/** * Copyright (c) 2001, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -25,10 +25,13 @@ package sun.net.www.protocol.https; +import java.net.Authenticator; import java.net.URL; import java.net.Proxy; import java.net.SecureCacheResponse; import java.security.Principal; +import java.security.cert.Certificate; +import java.security.cert.X509Certificate; import java.io.IOException; import java.util.List; import java.util.Optional; @@ -36,6 +39,7 @@ import javax.net.ssl.SSLSession; import javax.net.ssl.SSLPeerUnverifiedException; import sun.net.www.http.*; import sun.net.www.protocol.http.HttpURLConnection; +import sun.net.www.protocol.http.HttpCallerInfo; /** * HTTPS URL connection support. @@ -309,4 +313,72 @@ public abstract class AbstractDelegateHttpsURLConnection extends return ((HttpsClient)http).getSSLSession(); } + + /* + * If no SSL Session available or if the system config does not allow it + * don't use the extended caller info (the server cert). + * Otherwise return true to include the server cert + */ + private boolean useExtendedCallerInfo(URL url) { + HttpsClient https = (HttpsClient)http; + if (https.getSSLSession() == null) { + return false; + } + String prop = http.getSpnegoCBT(); + if (prop.equals("never")) { + return false; + } + String target = url.getHost(); + if (prop.startsWith("domain:")) { + String[] domains = prop.substring(7).split(","); + for (String domain : domains) { + if (target.equalsIgnoreCase(domain)) { + return true; + } + if (domain.startsWith("*.") && target.regionMatches( + true, target.length() - domain.length() + 1, domain, 1, domain.length() - 1)) { + return true; + } + } + return false; + } + return true; + } + + @Override + protected HttpCallerInfo getHttpCallerInfo(URL url, String proxy, int port, + Authenticator authenticator) + { + if (!useExtendedCallerInfo(url)) { + return super.getHttpCallerInfo(url, proxy, port, authenticator); + } + HttpsClient https = (HttpsClient)http; + try { + Certificate[] certs = https.getServerCertificates(); + if (certs[0] instanceof X509Certificate x509Cert) { + return new HttpCallerInfo(url, proxy, port, x509Cert, authenticator); + } + } catch (SSLPeerUnverifiedException e) { + // ignore + } + return super.getHttpCallerInfo(url, proxy, port, authenticator); + } + + @Override + protected HttpCallerInfo getHttpCallerInfo(URL url, Authenticator authenticator) + { + if (!useExtendedCallerInfo(url)) { + return super.getHttpCallerInfo(url, authenticator); + } + HttpsClient https = (HttpsClient)http; + try { + Certificate[] certs = https.getServerCertificates(); + if (certs[0] instanceof X509Certificate x509Cert) { + return new HttpCallerInfo(url, x509Cert, authenticator); + } + } catch (SSLPeerUnverifiedException e) { + // ignore + } + return super.getHttpCallerInfo(url, authenticator); + } } diff --git a/src/java.base/share/classes/sun/net/www/protocol/https/HttpsClient.java b/src/java.base/share/classes/sun/net/www/protocol/https/HttpsClient.java index 2f718e5bcc93293fee54ae224e8709b9c4e9e566..1cb435f7fdfe0885eafc883b4e439299bc82d845 100644 --- a/src/java.base/share/classes/sun/net/www/protocol/https/HttpsClient.java +++ b/src/java.base/share/classes/sun/net/www/protocol/https/HttpsClient.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -645,7 +645,7 @@ final class HttpsClient extends HttpClient // ignore } - if ((cipher != null) && (cipher.indexOf("_anon_") != -1)) { + if ((cipher != null) && (cipher.contains("_anon_"))) { return; } else if ((hostnameVerifier != null) && (hostnameVerifier.verify(host, session))) { @@ -661,12 +661,17 @@ final class HttpsClient extends HttpClient @Override protected void putInKeepAliveCache() { - if (inCache) { - assert false : "Duplicate put to keep alive cache"; - return; + lock(); + try { + if (inCache) { + assert false : "Duplicate put to keep alive cache"; + return; + } + inCache = true; + kac.put(url, sslSocketFactory, this); + } finally { + unlock(); } - inCache = true; - kac.put(url, sslSocketFactory, this); } /* diff --git a/src/java.base/share/classes/sun/net/www/protocol/jar/JarURLConnection.java b/src/java.base/share/classes/sun/net/www/protocol/jar/JarURLConnection.java index 4ccf7819914400104a3b0cf9c94c7a6bab73f2eb..234827fb76f2ef2fd45ead6d3520852a2baf31cf 100644 --- a/src/java.base/share/classes/sun/net/www/protocol/jar/JarURLConnection.java +++ b/src/java.base/share/classes/sun/net/www/protocol/jar/JarURLConnection.java @@ -25,21 +25,17 @@ package sun.net.www.protocol.jar; -import java.io.InputStream; -import java.io.IOException; -import java.io.FileNotFoundException; import java.io.BufferedInputStream; -import java.net.URL; -import java.net.URLConnection; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; import java.net.MalformedURLException; -import java.net.UnknownServiceException; -import java.util.Enumeration; -import java.util.Map; +import java.net.URL; +import java.security.Permission; import java.util.List; +import java.util.Map; import java.util.jar.JarEntry; import java.util.jar.JarFile; -import java.util.jar.Manifest; -import java.security.Permission; /** * @author Benjamin Renaud @@ -47,26 +43,10 @@ import java.security.Permission; */ public class JarURLConnection extends java.net.JarURLConnection { - private static final boolean debug = false; - /* the Jar file factory. It handles both retrieval and caching. */ private static final JarFileFactory factory = JarFileFactory.getInstance(); - /* the url for the Jar file */ - private URL jarFileURL; - - /* the permission to get this JAR file. This is the actual, ultimate, - * permission, returned by the jar file factory. - */ - private Permission permission; - - /* the url connection for the JAR file */ - private URLConnection jarFileURLConnection; - - /* the entry name, if any */ - private String entryName; - /* the JarEntry */ private JarEntry jarEntry; @@ -80,12 +60,10 @@ public class JarURLConnection extends java.net.JarURLConnection { throws MalformedURLException, IOException { super(url); - jarFileURL = getJarFileURL(); - jarFileURLConnection = jarFileURL.openConnection(); + jarFileURLConnection = getJarFileURL().openConnection(); // whether, or not, the embedded URL should use the cache will depend // on this instance's cache value jarFileURLConnection.setUseCaches(useCaches); - entryName = getEntryName(); } public JarFile getJarFile() throws IOException { @@ -120,7 +98,7 @@ public class JarURLConnection extends java.net.JarURLConnection { public void connect() throws IOException { if (!connected) { boolean useCaches = getUseCaches(); - String entryName = this.entryName; + String entryName = getEntryName(); /* the factory call will do the security checks */ URL url = getJarFileURL(); @@ -176,6 +154,7 @@ public class JarURLConnection extends java.net.JarURLConnection { InputStream result = null; + String entryName = getEntryName(); if (entryName == null) { throw new IOException("no entry name specified"); } else { @@ -216,7 +195,7 @@ public class JarURLConnection extends java.net.JarURLConnection { Object result = null; connect(); - if (entryName == null) { + if (getEntryName() == null) { result = jarFile; } else { result = super.getContent(); @@ -226,6 +205,7 @@ public class JarURLConnection extends java.net.JarURLConnection { public String getContentType() { if (contentType == null) { + String entryName = getEntryName(); if (entryName == null) { contentType = "x-java/jar"; } else { diff --git a/src/java.base/share/classes/sun/net/www/protocol/mailto/Handler.java b/src/java.base/share/classes/sun/net/www/protocol/mailto/Handler.java index e9052397483abdeb6c17274ffb88100947b387ea..cb8e490995e5f467d6f75ac87f4a590e3c9e8b25 100644 --- a/src/java.base/share/classes/sun/net/www/protocol/mailto/Handler.java +++ b/src/java.base/share/classes/sun/net/www/protocol/mailto/Handler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 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 @@ -32,10 +32,6 @@ package sun.net.www.protocol.mailto; import java.net.URL; import java.net.URLConnection; import java.net.URLStreamHandler; -import java.io.*; -import sun.net.www.*; -//import sun.net.www.protocol.news.ArticlePoster; -import sun.net.smtp.SmtpClient; /** open an nntp input stream given a URL */ public class Handler extends URLStreamHandler { @@ -99,7 +95,7 @@ public class Handler extends URLStreamHandler { // } */ - public synchronized URLConnection openConnection(URL u) { + public URLConnection openConnection(URL u) { return new MailToURLConnection(u); } @@ -126,33 +122,16 @@ public class Handler extends URLStreamHandler { /* * Let's just make sure we DO have an Email address in the URL. */ - boolean nogood = false; - if (file == null || file.isEmpty()) - nogood = true; - else { - boolean allwhites = true; - for (int i = 0; i < file.length(); i++) - if (!Character.isWhitespace(file.charAt(i))) - allwhites = false; - if (allwhites) - nogood = true; - } - if (nogood) + if (file.isBlank()) throw new RuntimeException("No email address"); - setURLHandler(u, protocol, host, port, file, null); + setURLHandler(u, protocol, host, port, file); } /** * This method is used to suppress the deprecated warning - * - * @param u the URL to receive the result of parsing the spec - * @param spec the URL string to parse - * @param start the character position to start parsing at. This is - * just past the ':'. - * @param limit the character position to stop parsing at. */ @SuppressWarnings("deprecation") - private void setURLHandler(URL u, String protocol, String host, int port, String file, String ref) { - setURL(u,protocol,host,port,file,null); + private void setURLHandler(URL u, String protocol, String host, int port, String file) { + setURL(u, protocol, host, port, file, null); } } 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 6f312cb9ed2e74bf7506ec2eb78689714b461ad7..6397eda0c936722dcf34b3f442239c1fb2263e2c 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, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -34,63 +34,58 @@ import java.nio.channels.IllegalBlockingModeException; import java.nio.channels.ReadableByteChannel; import java.nio.channels.SeekableByteChannel; import java.nio.channels.SelectableChannel; +import java.nio.channels.WritableByteChannel; import java.util.Arrays; import java.util.Objects; import jdk.internal.util.ArraysSupport; /** - * This class is defined here rather than in java.nio.channels.Channels - * so that code can be shared with SocketAdaptor. + * An InputStream that reads bytes from a channel. * * @author Mike McCloskey * @author Mark Reinhold - * @since 1.4 */ - -public class ChannelInputStream - extends InputStream -{ +class ChannelInputStream extends InputStream { private static final int DEFAULT_BUFFER_SIZE = 8192; - public static int read(ReadableByteChannel ch, ByteBuffer bb, - boolean block) - throws IOException - { + private final ReadableByteChannel ch; + private ByteBuffer bb; + private byte[] bs; // Invoker's previous array + private byte[] b1; + + /** + * Initialize a ChannelInputStream that reads from the given channel. + */ + ChannelInputStream(ReadableByteChannel ch) { + this.ch = ch; + } + + /** + * Reads a sequence of bytes from the channel into the given buffer. + */ + private int read(ByteBuffer bb) throws IOException { if (ch instanceof SelectableChannel sc) { synchronized (sc.blockingLock()) { - boolean bm = sc.isBlocking(); - if (!bm) + if (!sc.isBlocking()) throw new IllegalBlockingModeException(); - if (bm != block) - sc.configureBlocking(block); - int n = ch.read(bb); - if (bm != block) - sc.configureBlocking(bm); - return n; + return ch.read(bb); } } else { return ch.read(bb); } } - protected final ReadableByteChannel ch; - private ByteBuffer bb = null; - private byte[] bs = null; // Invoker's previous array - private byte[] b1 = null; - - public ChannelInputStream(ReadableByteChannel ch) { - this.ch = ch; - } - + @Override public synchronized int read() throws IOException { if (b1 == null) b1 = new byte[1]; - int n = this.read(b1); + int n = read(b1); if (n == 1) return b1[0] & 0xff; return -1; } + @Override public synchronized int read(byte[] bs, int off, int len) throws IOException { @@ -108,12 +103,6 @@ public class ChannelInputStream return read(bb); } - protected int read(ByteBuffer bb) - throws IOException - { - return ChannelInputStream.read(ch, bb, true); - } - @Override public byte[] readAllBytes() throws IOException { if (!(ch instanceof SeekableByteChannel sbc)) @@ -200,6 +189,7 @@ public class ChannelInputStream return (capacity == nread) ? buf : Arrays.copyOf(buf, nread); } + @Override public int available() throws IOException { // special case where the channel is to a file if (ch instanceof SeekableByteChannel sbc) { @@ -209,6 +199,7 @@ public class ChannelInputStream return 0; } + @Override public synchronized long skip(long n) throws IOException { // special case where the channel is to a file if (ch instanceof SeekableByteChannel sbc) { @@ -229,33 +220,62 @@ public class ChannelInputStream return super.skip(n); } - public void close() throws IOException { - ch.close(); - } - @Override public long transferTo(OutputStream out) throws IOException { Objects.requireNonNull(out, "out"); - if (out instanceof ChannelOutputStream cos - && ch instanceof FileChannel fc - && cos.channel() instanceof FileChannel dst) { - return transfer(fc, dst); + if (ch instanceof FileChannel fc) { + // FileChannel -> SocketChannel + if (out instanceof SocketOutputStream sos) { + SocketChannelImpl sc = sos.channel(); + synchronized (sc.blockingLock()) { + if (!sc.isBlocking()) + throw new IllegalBlockingModeException(); + return transfer(fc, sc); + } + } + + // FileChannel -> WritableByteChannel + if (out instanceof ChannelOutputStream cos) { + WritableByteChannel wbc = cos.channel(); + + if (wbc instanceof SelectableChannel sc) { + synchronized (sc.blockingLock()) { + if (!sc.isBlocking()) + throw new IllegalBlockingModeException(); + return transfer(fc, wbc); + } + } + + return transfer(fc, wbc); + } } return super.transferTo(out); } - private static long transfer(FileChannel src, FileChannel dst) throws IOException { - long initialPos = src.position(); + /** + * Transfers all bytes from a channel's file to a target writeable byte channel. + * If the writeable byte channel is a selectable channel then it must be in + * blocking mode. + */ + private static long transfer(FileChannel fc, WritableByteChannel target) + throws IOException + { + long initialPos = fc.position(); long pos = initialPos; try { - while (pos < src.size()) { - pos += src.transferTo(pos, Long.MAX_VALUE, dst); + while (pos < fc.size()) { + pos += fc.transferTo(pos, Long.MAX_VALUE, target); } } finally { - src.position(pos); + fc.position(pos); } return pos - initialPos; } + + @Override + public void close() throws IOException { + ch.close(); + } } diff --git a/src/java.base/share/classes/sun/nio/ch/ChannelOutputStream.java b/src/java.base/share/classes/sun/nio/ch/ChannelOutputStream.java index a1e838efab460c191949770c35662fe347db4fbb..dff8af9ebafc14c4e1629d12a15e93b655b3e454 100644 --- a/src/java.base/share/classes/sun/nio/ch/ChannelOutputStream.java +++ b/src/java.base/share/classes/sun/nio/ch/ChannelOutputStream.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -25,68 +25,30 @@ package sun.nio.ch; -import java.io.*; -import java.nio.*; -import java.nio.channels.*; -import java.nio.channels.spi.*; +import java.io.IOException; +import java.io.OutputStream; +import java.nio.ByteBuffer; +import java.nio.channels.IllegalBlockingModeException; +import java.nio.channels.SelectableChannel; +import java.nio.channels.WritableByteChannel; import java.util.Objects; /** - * This class is defined here rather than in java.nio.channels.Channels - * so that it will be accessible from java.nio.channels.Channels and - * sun.nio.ch.ChannelInputStream. - * + * An OutputStream that writes bytes to a channel. * * @author Mark Reinhold * @author Mike McCloskey - * @author JSR-51 Expert Group - * @since 18 */ -public class ChannelOutputStream extends OutputStream { - +class ChannelOutputStream extends OutputStream { private final WritableByteChannel ch; private ByteBuffer bb; private byte[] bs; // Invoker's previous array private byte[] b1; /** - * Write all remaining bytes in buffer to the given channel. - * If the channel is selectable then it must be configured blocking. - */ - private static void writeFullyImpl(WritableByteChannel ch, ByteBuffer bb) - throws IOException - { - while (bb.remaining() > 0) { - int n = ch.write(bb); - if (n <= 0) - throw new RuntimeException("no bytes written"); - } - } - - /** - * Write all remaining bytes in buffer to the given channel. - * - * @throws IllegalBlockingModeException - * If the channel is selectable and configured non-blocking. - */ - private static void writeFully(WritableByteChannel ch, ByteBuffer bb) - throws IOException - { - if (ch instanceof SelectableChannel sc) { - synchronized (sc.blockingLock()) { - if (!sc.isBlocking()) - throw new IllegalBlockingModeException(); - writeFullyImpl(ch, bb); - } - } else { - writeFullyImpl(ch, bb); - } - } - - /** - * @param ch The channel wrapped by this stream. + * Initialize a ChannelOutputStream that writes to the given channel. */ - public ChannelOutputStream(WritableByteChannel ch) { + ChannelOutputStream(WritableByteChannel ch) { this.ch = ch; } @@ -97,17 +59,30 @@ public class ChannelOutputStream extends OutputStream { return ch; } + /** + * Write all remaining bytes in buffer to the channel. + * If the channel is selectable then it must be configured blocking. + */ + private void writeFully(ByteBuffer bb) throws IOException { + while (bb.remaining() > 0) { + int n = ch.write(bb); + if (n <= 0) + throw new RuntimeException("no bytes written"); + } + } + @Override public synchronized void write(int b) throws IOException { if (b1 == null) b1 = new byte[1]; b1[0] = (byte) b; - this.write(b1); + write(b1); } @Override public synchronized void write(byte[] bs, int off, int len) - throws IOException { + throws IOException + { Objects.checkFromIndexSize(off, len, bs.length); if (len == 0) { return; @@ -119,12 +94,20 @@ public class ChannelOutputStream extends OutputStream { bb.position(off); this.bb = bb; this.bs = bs; - writeFully(ch, bb); + + if (ch instanceof SelectableChannel sc) { + synchronized (sc.blockingLock()) { + if (!sc.isBlocking()) + throw new IllegalBlockingModeException(); + writeFully(bb); + } + } else { + writeFully(bb); + } } @Override public void close() throws IOException { ch.close(); } - } diff --git a/src/java.base/share/classes/sun/nio/ch/DatagramSocketAdaptor.java b/src/java.base/share/classes/sun/nio/ch/DatagramSocketAdaptor.java index abe33000cda6099baa974a1372fe2f65b2b7ebde..d962cdf36930a62f53207fbd5c60512f769cf0f9 100644 --- a/src/java.base/share/classes/sun/nio/ch/DatagramSocketAdaptor.java +++ b/src/java.base/share/classes/sun/nio/ch/DatagramSocketAdaptor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -219,9 +219,7 @@ public class DatagramSocketAdaptor } catch (AlreadyConnectedException e) { throw new IllegalArgumentException("Connected and packet address differ"); } catch (ClosedChannelException e) { - var exc = new SocketException("Socket closed"); - exc.initCause(e); - throw exc; + throw new SocketException("Socket closed", e); } } finally { if (bb != null) { @@ -249,9 +247,7 @@ public class DatagramSocketAdaptor p.setSocketAddress(sender); } } catch (ClosedChannelException e) { - var exc = new SocketException("Socket closed"); - exc.initCause(e); - throw exc; + throw new SocketException("Socket closed", e); } finally { Util.offerFirstTemporaryDirectBuffer(bb); } @@ -481,7 +477,7 @@ public class DatagramSocketAdaptor joinGroup(new InetSocketAddress(group, 0), null); } catch (IllegalArgumentException iae) { // 1-arg joinGroup does not specify IllegalArgumentException - throw (SocketException) new SocketException("joinGroup failed").initCause(iae); + throw new SocketException("joinGroup failed", iae); } } @@ -493,7 +489,7 @@ public class DatagramSocketAdaptor leaveGroup(new InetSocketAddress(group, 0), null); } catch (IllegalArgumentException iae) { // 1-arg leaveGroup does not specify IllegalArgumentException - throw (SocketException) new SocketException("leaveGroup failed").initCause(iae); + throw new SocketException("leaveGroup failed", iae); } } 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 ec0bc767eb7a4c1a791da8144afece6bdfd8a9dc..31a54a57a75ec56733fabed59a0be310766bca26 100644 --- a/src/java.base/share/classes/sun/nio/ch/FileChannelImpl.java +++ b/src/java.base/share/classes/sun/nio/ch/FileChannelImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -1271,6 +1271,8 @@ public class FileChannelImpl throw new NonReadableChannelException(); if (!shared && !writable) throw new NonWritableChannelException(); + if (size == 0) + size = Long.MAX_VALUE - Math.max(0, position); FileLockImpl fli = new FileLockImpl(this, position, size, shared); FileLockTable flt = fileLockTable(); flt.add(fli); @@ -1316,6 +1318,8 @@ public class FileChannelImpl throw new NonReadableChannelException(); if (!shared && !writable) throw new NonWritableChannelException(); + if (size == 0) + size = Long.MAX_VALUE - Math.max(0, position); FileLockImpl fli = new FileLockImpl(this, position, size, shared); FileLockTable flt = fileLockTable(); flt.add(fli); diff --git a/src/java.base/share/classes/sun/nio/ch/IOUtil.java b/src/java.base/share/classes/sun/nio/ch/IOUtil.java index 900bb4e40883dbde2efbae4b3be0a75502bc9479..bea092befaeff79759a3e3e8fd8fcb669c371f6c 100644 --- a/src/java.base/share/classes/sun/nio/ch/IOUtil.java +++ b/src/java.base/share/classes/sun/nio/ch/IOUtil.java @@ -475,15 +475,15 @@ public class IOUtil { private static final JavaNioAccess NIO_ACCESS = SharedSecrets.getJavaNioAccess(); - static Scope.Handle acquireScope(ByteBuffer bb, boolean async) { + static Runnable acquireScope(ByteBuffer bb, boolean async) { return NIO_ACCESS.acquireScope(bb, async); } - private static void releaseScope(Scope.Handle handle) { + private static void releaseScope(Runnable handle) { if (handle == null) return; try { - handle.scope().release(handle); + handle.run(); } catch (Exception e) { throw new IllegalStateException(e); } @@ -535,11 +535,11 @@ public class IOUtil { } } - static record Releaser(Scope.Handle handle) implements Runnable { + static record Releaser(Runnable handle) implements Runnable { Releaser { Objects.requireNonNull(handle) ; } @Override public void run() { releaseScope(handle); } - static Runnable of(Scope.Handle handle) { return new Releaser(handle); } - static Runnable ofNullable(Scope.Handle handle) { + static Runnable of(Runnable handle) { return new Releaser(handle); } + static Runnable ofNullable(Runnable handle) { if (handle == null) return () -> { }; return new Releaser(handle); diff --git a/src/java.base/share/classes/sun/nio/ch/SimpleAsynchronousFileChannelImpl.java b/src/java.base/share/classes/sun/nio/ch/SimpleAsynchronousFileChannelImpl.java index 5658480558f77a2eace70f9143add8730b28121f..b41430c8d9d6975729ebd13471b8b12925e141d0 100644 --- a/src/java.base/share/classes/sun/nio/ch/SimpleAsynchronousFileChannelImpl.java +++ b/src/java.base/share/classes/sun/nio/ch/SimpleAsynchronousFileChannelImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 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 @@ -181,8 +181,10 @@ public class SimpleAsynchronousFileChannelImpl if (!shared && !writing) throw new NonWritableChannelException(); + long len = (size != 0) ? size : Long.MAX_VALUE - Math.max(0, position); + // add to lock table - final FileLockImpl fli = addToFileLockTable(position, size, shared); + final FileLockImpl fli = addToFileLockTable(position, len, shared); if (fli == null) { Throwable exc = new ClosedChannelException(); if (handler == null) @@ -203,7 +205,7 @@ public class SimpleAsynchronousFileChannelImpl try { begin(); do { - n = nd.lock(fdObj, true, position, size, shared); + n = nd.lock(fdObj, true, position, len, shared); } while ((n == FileDispatcher.INTERRUPTED) && isOpen()); if (n != FileDispatcher.LOCKED || !isOpen()) { throw new AsynchronousCloseException(); @@ -248,6 +250,9 @@ public class SimpleAsynchronousFileChannelImpl if (!shared && !writing) throw new NonWritableChannelException(); + if (size == 0) + size = Long.MAX_VALUE - Math.max(0, position); + // add to lock table FileLockImpl fli = addToFileLockTable(position, size, shared); if (fli == null) diff --git a/src/java.base/share/classes/sun/nio/ch/SocketAdaptor.java b/src/java.base/share/classes/sun/nio/ch/SocketAdaptor.java index bcab4b67a75754414a3c9c89ecbd6966cda40d79..745d8d7f1f8a0674cbd5f8eca4fefa37d5838461 100644 --- a/src/java.base/share/classes/sun/nio/ch/SocketAdaptor.java +++ b/src/java.base/share/classes/sun/nio/ch/SocketAdaptor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -177,32 +177,7 @@ class SocketAdaptor throw new SocketException("Socket is not connected"); if (!sc.isInputOpen()) throw new SocketException("Socket input is shutdown"); - return new InputStream() { - @Override - public int read() throws IOException { - byte[] a = new byte[1]; - int n = read(a, 0, 1); - return (n > 0) ? (a[0] & 0xff) : -1; - } - @Override - public int read(byte[] b, int off, int len) throws IOException { - int timeout = SocketAdaptor.this.timeout; - if (timeout > 0) { - long nanos = MILLISECONDS.toNanos(timeout); - return sc.blockingRead(b, off, len, nanos); - } else { - return sc.blockingRead(b, off, len, 0); - } - } - @Override - public int available() throws IOException { - return sc.available(); - } - @Override - public void close() throws IOException { - sc.close(); - } - }; + return new SocketInputStream(sc, () -> timeout); } @Override @@ -213,21 +188,7 @@ class SocketAdaptor throw new SocketException("Socket is not connected"); if (!sc.isOutputOpen()) throw new SocketException("Socket output is shutdown"); - return new OutputStream() { - @Override - public void write(int b) throws IOException { - byte[] a = new byte[]{(byte) b}; - write(a, 0, 1); - } - @Override - public void write(byte[] b, int off, int len) throws IOException { - sc.blockingWriteFully(b, off, len); - } - @Override - public void close() throws IOException { - sc.close(); - } - }; + return new SocketOutputStream(sc); } private void setBooleanOption(SocketOption name, boolean value) diff --git a/src/java.base/share/classes/sun/nio/ch/SocketChannelImpl.java b/src/java.base/share/classes/sun/nio/ch/SocketChannelImpl.java index 477fa1afca2384391734437f2d1d326a3c66ddf5..117c14d5711e55c45eaed7593587d75249367e7e 100644 --- a/src/java.base/share/classes/sun/nio/ch/SocketChannelImpl.java +++ b/src/java.base/share/classes/sun/nio/ch/SocketChannelImpl.java @@ -700,11 +700,11 @@ class SocketChannelImpl private SocketAddress unixBind(SocketAddress local) throws IOException { UnixDomainSockets.checkPermission(); if (local == null) { - return UnixDomainSockets.UNNAMED; + return UnixDomainSockets.unnamed(); } else { Path path = UnixDomainSockets.checkAddress(local).getPath(); if (path.toString().isEmpty()) { - return UnixDomainSockets.UNNAMED; + return UnixDomainSockets.unnamed(); } else { // bind to non-empty path UnixDomainSockets.bind(fd, path); diff --git a/src/java.base/share/classes/sun/nio/ch/SocketInputStream.java b/src/java.base/share/classes/sun/nio/ch/SocketInputStream.java new file mode 100644 index 0000000000000000000000000000000000000000..6c69eaf5214c74822eab09419d9acf409b0484b9 --- /dev/null +++ b/src/java.base/share/classes/sun/nio/ch/SocketInputStream.java @@ -0,0 +1,83 @@ +/* + * 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. 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.nio.ch; + +import java.io.IOException; +import java.io.InputStream; +import java.util.function.IntSupplier; +import static java.util.concurrent.TimeUnit.MILLISECONDS; + +/** + * An InputStream that reads bytes from a socket channel. + */ +class SocketInputStream extends InputStream { + private final SocketChannelImpl sc; + private final IntSupplier timeoutSupplier; + + /** + * Initialize a SocketInputStream that reads from the given socket channel. + * @param sc the socket channel + * @param timeoutSupplier supplies the read timeout, in milliseconds + */ + SocketInputStream(SocketChannelImpl sc, IntSupplier timeoutSupplier) { + this.sc = sc; + this.timeoutSupplier = timeoutSupplier; + } + + /** + * Initialize a SocketInputStream that reads from the given socket channel. + */ + SocketInputStream(SocketChannelImpl sc) { + this(sc, () -> 0); + } + + @Override + public int read() throws IOException { + byte[] a = new byte[1]; + int n = read(a, 0, 1); + return (n > 0) ? (a[0] & 0xff) : -1; + } + + @Override + public int read(byte[] b, int off, int len) throws IOException { + int timeout = timeoutSupplier.getAsInt(); + if (timeout > 0) { + long nanos = MILLISECONDS.toNanos(timeout); + return sc.blockingRead(b, off, len, nanos); + } else { + return sc.blockingRead(b, off, len, 0); + } + } + + @Override + public int available() throws IOException { + return sc.available(); + } + + @Override + public void close() throws IOException { + sc.close(); + } +} diff --git a/src/java.base/share/classes/sun/nio/ch/SocketOutputStream.java b/src/java.base/share/classes/sun/nio/ch/SocketOutputStream.java new file mode 100644 index 0000000000000000000000000000000000000000..78d0dce46fa1e4fc726c544701b5049ae38217b3 --- /dev/null +++ b/src/java.base/share/classes/sun/nio/ch/SocketOutputStream.java @@ -0,0 +1,65 @@ +/* + * 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. 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.nio.ch; + +import java.io.IOException; +import java.io.OutputStream; + +/** + * An OutputStream that writes bytes to a socket channel. + */ +class SocketOutputStream extends OutputStream { + private final SocketChannelImpl sc; + + /** + * Initialize a SocketOutputStream that writes to the given socket channel. + */ + SocketOutputStream(SocketChannelImpl sc) { + this.sc = sc; + } + + /** + * Returns the socket channel. + */ + SocketChannelImpl channel() { + return sc; + } + + @Override + public void write(int b) throws IOException { + byte[] a = new byte[]{(byte) b}; + write(a, 0, 1); + } + + @Override + public void write(byte[] b, int off, int len) throws IOException { + sc.blockingWriteFully(b, off, len); + } + + @Override + public void close() throws IOException { + sc.close(); + } +} diff --git a/src/java.base/share/classes/sun/nio/ch/Streams.java b/src/java.base/share/classes/sun/nio/ch/Streams.java new file mode 100644 index 0000000000000000000000000000000000000000..4326c9e2e0b911711fb2190798c7fd4cd6f77326 --- /dev/null +++ b/src/java.base/share/classes/sun/nio/ch/Streams.java @@ -0,0 +1,59 @@ +/* + * 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. 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.nio.ch; + +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.channels.ReadableByteChannel; +import java.nio.channels.WritableByteChannel; + +/** + * Factory methods for input/output streams based on channels. + */ +public class Streams { + private Streams() { } + + /** + * Return an input stream that reads bytes from the given channel. + */ + public static InputStream of(ReadableByteChannel ch) { + if (ch instanceof SocketChannelImpl sc) { + return new SocketInputStream(sc); + } else { + return new ChannelInputStream(ch); + } + } + + /** + * Return an output stream that writes bytes to the given channel. + */ + public static OutputStream of(WritableByteChannel ch) { + if (ch instanceof SocketChannelImpl sc) { + return new SocketOutputStream(sc); + } else { + return new ChannelOutputStream(ch); + } + } +} diff --git a/src/java.base/share/classes/sun/nio/ch/UnixDomainSockets.java b/src/java.base/share/classes/sun/nio/ch/UnixDomainSockets.java index ee7e1d9d51ab92801a89f9c64588c3908eccf752..251e79c6ecc694ad45f1a27865230486d38c42bf 100644 --- a/src/java.base/share/classes/sun/nio/ch/UnixDomainSockets.java +++ b/src/java.base/share/classes/sun/nio/ch/UnixDomainSockets.java @@ -44,7 +44,9 @@ import sun.nio.fs.AbstractFileSystemProvider; class UnixDomainSockets { private UnixDomainSockets() { } - static final UnixDomainSocketAddress UNNAMED = UnixDomainSocketAddress.of(""); + private static class UnnamedHolder { + static final UnixDomainSocketAddress UNNAMED = UnixDomainSocketAddress.of(""); + } private static final boolean supported; @@ -71,7 +73,7 @@ class UnixDomainSockets { // Security check passed } catch (SecurityException e) { // Return unnamed address only if security check fails - addr = UNNAMED; + addr = unnamed(); } return addr; } @@ -133,7 +135,11 @@ class UnixDomainSockets { throw new BindException("Could not locate temporary directory for sockets"); int rnd = random.nextInt(Integer.MAX_VALUE); try { - Path path = Path.of(dir, "socket_" + rnd); + final Path path = Path.of(dir, "socket_" + rnd); + if (path.getFileSystem().provider() != sun.nio.fs.DefaultFileSystemProvider.instance()) { + throw new UnsupportedOperationException( + "Unix Domain Sockets not supported on non-default file system"); + } return UnixDomainSocketAddress.of(path); } catch (InvalidPathException e) { throw new BindException("Invalid temporary directory"); @@ -160,6 +166,10 @@ class UnixDomainSockets { return n; } + static UnixDomainSocketAddress unnamed() { + return UnnamedHolder.UNNAMED; + } + private static native boolean init(); private static native int socket0() throws IOException; diff --git a/src/java.base/share/classes/sun/reflect/annotation/AnnotationInvocationHandler.java b/src/java.base/share/classes/sun/reflect/annotation/AnnotationInvocationHandler.java index c4cc4ccdec739523ba233ea2dcaae3b1c7871bf2..74eec629b3e85342985671d3c9920871b416ee2c 100644 --- a/src/java.base/share/classes/sun/reflect/annotation/AnnotationInvocationHandler.java +++ b/src/java.base/share/classes/sun/reflect/annotation/AnnotationInvocationHandler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -145,7 +145,9 @@ class AnnotationInvocationHandler implements InvocationHandler, Serializable { private String toStringImpl() { StringBuilder result = new StringBuilder(128); result.append('@'); - result.append(type.getName()); + // Guard against null canonical name; shouldn't happen + result.append(Objects.toString(type.getCanonicalName(), + "")); result.append('('); boolean firstMember = true; Set> entries = memberValues.entrySet(); @@ -189,6 +191,10 @@ class AnnotationInvocationHandler implements InvocationHandler, Serializable { return toSourceString((long) value); else if (type == Byte.class) return toSourceString((byte) value); + else if (value instanceof Enum v) + // Predicate above covers enum constants, including + // those with specialized class bodies. + return toSourceString(v); else return value.toString(); } else { @@ -219,6 +225,10 @@ class AnnotationInvocationHandler implements InvocationHandler, Serializable { stringStream = Arrays.stream((String[])value). map(AnnotationInvocationHandler::toSourceString); + else if (type.getComponentType().isEnum()) + stringStream = + Arrays.stream((Enum[])value). + map(AnnotationInvocationHandler::toSourceString); else stringStream = Arrays.stream((Object[])value).map(Objects::toString); @@ -231,15 +241,9 @@ class AnnotationInvocationHandler implements InvocationHandler, Serializable { * string representation of an annotation. */ private static String toSourceString(Class clazz) { - Class finalComponent = clazz; - StringBuilder arrayBrackets = new StringBuilder(); - - while(finalComponent.isArray()) { - finalComponent = finalComponent.getComponentType(); - arrayBrackets.append("[]"); - } - - return finalComponent.getName() + arrayBrackets.toString() + ".class"; + // Guard against null canonical name; shouldn't happen + return Objects.toString(clazz.getCanonicalName(), + "") + ".class"; } private static String toSourceString(float f) { @@ -307,6 +311,10 @@ class AnnotationInvocationHandler implements InvocationHandler, Serializable { return String.valueOf(ell) + "L"; } + private static String toSourceString(Enum enumConstant) { + return enumConstant.name(); + } + /** * Return a string suitable for use in the string representation * of an annotation. diff --git a/src/java.base/share/classes/sun/reflect/annotation/TypeAnnotationParser.java b/src/java.base/share/classes/sun/reflect/annotation/TypeAnnotationParser.java index 5c7356fca81a11113e2bbcbd64d3280ed43bdbae..fc51faad6fce86c3b1cbf8c46a1ba4eb0b27bc11 100644 --- a/src/java.base/share/classes/sun/reflect/annotation/TypeAnnotationParser.java +++ b/src/java.base/share/classes/sun/reflect/annotation/TypeAnnotationParser.java @@ -132,7 +132,8 @@ public final class TypeAnnotationParser { Class declaringClass = ctor.getDeclaringClass(); if (!declaringClass.isEnum() && (declaringClass.isMemberClass() && - (declaringClass.getModifiers() & Modifier.STATIC) == 0) ) { + (declaringClass.getModifiers() & Modifier.STATIC) == 0) && + filter == TypeAnnotation.TypeAnnotationTarget.METHOD_FORMAL_PARAMETER) { offset = true; } } diff --git a/src/java.base/share/classes/sun/security/pkcs/ContentInfo.java b/src/java.base/share/classes/sun/security/pkcs/ContentInfo.java index 125da2c9e2c58901af3f0a0998e6e9c44c7ff711..fbc6a46fc00ac9e71a6428819d023ea2f11a1131 100644 --- a/src/java.base/share/classes/sun/security/pkcs/ContentInfo.java +++ b/src/java.base/share/classes/sun/security/pkcs/ContentInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 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 @@ -127,7 +127,9 @@ public class ContentInfo { if (oldStyle) { // JDK1.1.x-style encoding - content = typeAndContent[1]; + if (typeAndContent.length > 1) { // content is OPTIONAL + content = typeAndContent[1]; + } } else { // This is the correct, standards-compliant encoding. // Parse the content (OPTIONAL field). diff --git a/src/java.base/share/classes/sun/security/pkcs/PKCS7.java b/src/java.base/share/classes/sun/security/pkcs/PKCS7.java index 63d1451148f1b1bf3f6aed476488e2d74ff0e955..3484bd04c32d3bfc4bde87ff94c7e3326f8bbb3e 100644 --- a/src/java.base/share/classes/sun/security/pkcs/PKCS7.java +++ b/src/java.base/share/classes/sun/security/pkcs/PKCS7.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 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 @@ -53,8 +53,6 @@ import sun.security.x509.*; */ public class PKCS7 { - private ObjectIdentifier contentType; - // the ASN.1 members for a signedData (and other) contentTypes private BigInteger version = null; private AlgorithmId[] digestAlgorithmIds = null; @@ -167,7 +165,7 @@ public class PKCS7 { throws IOException { ContentInfo block = new ContentInfo(derin, oldStyle); - contentType = block.contentType; + ObjectIdentifier contentType = block.contentType; DerValue content = block.getContent(); if (contentType.equals(ContentInfo.SIGNED_DATA_OID)) { @@ -240,14 +238,10 @@ public class PKCS7 { bais.close(); bais = null; } - } catch (CertificateException ce) { + } catch (CertificateException | IOException ce) { ParsingException pe = new ParsingException(ce.getMessage()); pe.initCause(ce); throw pe; - } catch (IOException ioe) { - ParsingException pe = new ParsingException(ioe.getMessage()); - pe.initCause(ioe); - throw pe; } finally { if (bais != null) bais.close(); @@ -330,14 +324,10 @@ public class PKCS7 { } count++; } - } catch (CertificateException ce) { + } catch (CertificateException | IOException ce) { ParsingException pe = new ParsingException(ce.getMessage()); pe.initCause(ce); throw pe; - } catch (IOException ioe) { - ParsingException pe = new ParsingException(ioe.getMessage()); - pe.initCause(ioe); - throw pe; } finally { if (bais != null) bais.close(); @@ -444,14 +434,10 @@ public class PKCS7 { bais.close(); bais = null; } - } catch (CertificateException ce) { + } catch (CertificateException | IOException ce) { ParsingException pe = new ParsingException(ce.getMessage()); pe.initCause(ce); throw pe; - } catch (IOException ioe) { - ParsingException pe = new ParsingException(ioe.getMessage()); - pe.initCause(ioe); - throw pe; } finally { if (bais != null) bais.close(); diff --git a/src/java.base/share/classes/sun/security/pkcs/PKCS9Attribute.java b/src/java.base/share/classes/sun/security/pkcs/PKCS9Attribute.java index 79eaee18862c6c09bfcdb81895a4c9300afcdb3b..6083cb18afcb702fb02e918e82a435d3ca71f8fa 100644 --- a/src/java.base/share/classes/sun/security/pkcs/PKCS9Attribute.java +++ b/src/java.base/share/classes/sun/security/pkcs/PKCS9Attribute.java @@ -481,12 +481,12 @@ public class PKCS9Attribute implements DerEncoder { "attribute not supported."); // break unnecessary case 10: // issuerAndserialNumber attribute -- not supported - throw new IOException("PKCS9 IssuerAndSerialNumber" + + throw new IOException("PKCS9 IssuerAndSerialNumber " + "attribute not supported."); // break unnecessary case 11: // RSA DSI proprietary case 12: // RSA DSI proprietary - throw new IOException("PKCS9 RSA DSI attributes" + + throw new IOException("PKCS9 RSA DSI attributes " + "11 and 12, not supported."); // break unnecessary case 13: // S/MIME unused attribute @@ -604,12 +604,12 @@ public class PKCS9Attribute implements DerEncoder { "attribute not supported."); // break unnecessary case 10: // issuerAndserialNumber attribute -- not supported - throw new IOException("PKCS9 IssuerAndSerialNumber" + + throw new IOException("PKCS9 IssuerAndSerialNumber " + "attribute not supported."); // break unnecessary case 11: // RSA DSI proprietary case 12: // RSA DSI proprietary - throw new IOException("PKCS9 RSA DSI attributes" + + throw new IOException("PKCS9 RSA DSI attributes " + "11 and 12, not supported."); // break unnecessary case 13: // S/MIME unused attribute diff --git a/src/java.base/share/classes/sun/security/pkcs/PKCS9Attributes.java b/src/java.base/share/classes/sun/security/pkcs/PKCS9Attributes.java index f37070cd64e24c3a8d28f37c9fee258d8b0b7a00..7f6c1af5b1bba63dacccec5b351979c294d4fd9b 100644 --- a/src/java.base/share/classes/sun/security/pkcs/PKCS9Attributes.java +++ b/src/java.base/share/classes/sun/security/pkcs/PKCS9Attributes.java @@ -275,11 +275,13 @@ public class PKCS9Attributes { */ public PKCS9Attribute[] getAttributes() { PKCS9Attribute[] attribs = new PKCS9Attribute[attributes.size()]; - ObjectIdentifier oid; int j = 0; for (int i=1; i < PKCS9Attribute.PKCS9_OIDS.length && j < attribs.length; i++) { + if (PKCS9Attribute.PKCS9_OIDS[i] == null) { + continue; + } attribs[j] = getAttribute(PKCS9Attribute.PKCS9_OIDS[i]); if (attribs[j] != null) @@ -323,11 +325,13 @@ public class PKCS9Attributes { StringBuilder sb = new StringBuilder(200); sb.append("PKCS9 Attributes: [\n\t"); - ObjectIdentifier oid; PKCS9Attribute value; boolean first = true; for (int i = 1; i < PKCS9Attribute.PKCS9_OIDS.length; i++) { + if (PKCS9Attribute.PKCS9_OIDS[i] == null) { + continue; + } value = getAttribute(PKCS9Attribute.PKCS9_OIDS[i]); if (value == null) continue; @@ -338,7 +342,7 @@ public class PKCS9Attributes { else sb.append(";\n\t"); - sb.append(value.toString()); + sb.append(value); } sb.append("\n\t] (end PKCS9 Attributes)"); diff --git a/src/java.base/share/classes/sun/security/pkcs/SignerInfo.java b/src/java.base/share/classes/sun/security/pkcs/SignerInfo.java index 1689672b7a9993af04396c38e4016c6c96f03013..af466e6615683fa2dc6d5d99b906d6a878bc20ef 100644 --- a/src/java.base/share/classes/sun/security/pkcs/SignerInfo.java +++ b/src/java.base/share/classes/sun/security/pkcs/SignerInfo.java @@ -76,10 +76,12 @@ public class SignerInfo implements DerEncoder { /** * A map containing the algorithms in this SignerInfo. This is used to * avoid checking algorithms to see if they are disabled more than once. - * The key is the AlgorithmId of the algorithm, and the value is the name of - * the field or attribute. + * The key is the AlgorithmId of the algorithm, and the value is a record + * containing the name of the field or attribute and whether the key + * should also be checked (ex: if it is a signature algorithm). */ - private Map algorithms = new HashMap<>(); + private record AlgorithmInfo(String field, boolean checkKey) {} + private Map algorithms = new HashMap<>(); public SignerInfo(X500Name issuerName, BigInteger serial, @@ -350,7 +352,8 @@ public class SignerInfo implements DerEncoder { } String digestAlgName = digestAlgorithmId.getName(); - algorithms.put(digestAlgorithmId, "SignerInfo digestAlgorithm field"); + algorithms.put(digestAlgorithmId, + new AlgorithmInfo("SignerInfo digestAlgorithm field", false)); byte[] dataSigned; @@ -380,8 +383,15 @@ public class SignerInfo implements DerEncoder { if (digestAlgName.equals("SHAKE256") || digestAlgName.equals("SHAKE256-LEN")) { if (digestAlgName.equals("SHAKE256-LEN")) { - int v = new DerValue(digestAlgorithmId - .getEncodedParams()).getInteger(); + // RFC8419: for EdDSA in CMS, the id-shake256-len + // algorithm id must contain parameter value 512 + // encoded as a positive integer value + byte[] params = digestAlgorithmId.getEncodedParams(); + if (params == null) { + throw new SignatureException( + "id-shake256-len oid missing length"); + } + int v = new DerValue(params).getInteger(); if (v != 512) { throw new SignatureException( "Unsupported id-shake256-" + v); @@ -421,7 +431,8 @@ public class SignerInfo implements DerEncoder { new AlgorithmId(ObjectIdentifier.of(oid), digestEncryptionAlgorithmId.getParameters()); algorithms.put(sigAlgId, - "SignerInfo digestEncryptionAlgorithm field"); + new AlgorithmInfo( + "SignerInfo digestEncryptionAlgorithm field", true)); } X509Certificate cert = getCertificate(block); @@ -523,6 +534,7 @@ public class SignerInfo implements DerEncoder { if (spec == null) { throw new NoSuchAlgorithmException("Missing PSSParameterSpec for RSASSA-PSS algorithm"); } + if (!AlgorithmId.get(spec.getDigestAlgorithm()).equals(digAlgId)) { throw new NoSuchAlgorithmException("Incompatible digest algorithm"); } @@ -677,7 +689,8 @@ public class SignerInfo implements DerEncoder { throws NoSuchAlgorithmException, SignatureException { AlgorithmId digestAlgId = token.getHashAlgorithm(); - algorithms.put(digestAlgId, "TimestampToken digestAlgorithm field"); + algorithms.put(digestAlgId, + new AlgorithmInfo("TimestampToken digestAlgorithm field", false)); MessageDigest md = MessageDigest.getInstance(digestAlgId.getName()); @@ -734,18 +747,19 @@ public class SignerInfo implements DerEncoder { */ public static Set verifyAlgorithms(SignerInfo[] infos, JarConstraintsParameters params, String name) throws SignatureException { - Map algorithms = new HashMap<>(); + Map algorithms = new HashMap<>(); for (SignerInfo info : infos) { algorithms.putAll(info.algorithms); } Set enabledAlgorithms = new HashSet<>(); try { - for (Map.Entry algorithm : algorithms.entrySet()) { - params.setExtendedExceptionMsg(name, algorithm.getValue()); - AlgorithmId algId = algorithm.getKey(); + for (var algEntry : algorithms.entrySet()) { + AlgorithmInfo info = algEntry.getValue(); + params.setExtendedExceptionMsg(name, info.field()); + AlgorithmId algId = algEntry.getKey(); JAR_DISABLED_CHECK.permits(algId.getName(), - algId.getParameters(), params); + algId.getParameters(), params, info.checkKey()); enabledAlgorithms.add(algId.getName()); } } catch (CertPathValidatorException e) { diff --git a/src/java.base/share/classes/sun/security/pkcs10/PKCS10.java b/src/java.base/share/classes/sun/security/pkcs10/PKCS10.java index 2a28f809888fedde59886c2cacd284235f70af23..05bb19fe1c10032330c0700667c725d1ee1b75af 100644 --- a/src/java.base/share/classes/sun/security/pkcs10/PKCS10.java +++ b/src/java.base/share/classes/sun/security/pkcs10/PKCS10.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 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 @@ -141,7 +141,6 @@ public class PKCS10 { // Inner sequence: version, name, key, attributes // BigInteger serial; - DerValue val; serial = seq[0].data.getBigInteger(); if (!serial.equals(BigInteger.ZERO)) diff --git a/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java b/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java index db79e2fcb639ab05fd0aafde1e14e58ee64929c7..b7bc494a04a491c5b7e24acf72002d15d77c7a7e 100644 --- a/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java +++ b/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java @@ -635,7 +635,7 @@ public final class PKCS12KeyStore extends KeyStoreSpi { } } } else { - throw new KeyStoreException("Private key is not encoded" + + throw new KeyStoreException("Private key is not encoded " + "as PKCS#8"); } @@ -1259,14 +1259,20 @@ public final class PKCS12KeyStore extends KeyStoreSpi { " certificate(s) in a PKCS#7 encryptedData"); } - byte[] encrData = createEncryptedData(password); - if (!certProtectionAlgorithm.equalsIgnoreCase("NONE")) { + byte[] certsData = getCertificateData(); + if (password != null && !certProtectionAlgorithm.equalsIgnoreCase("NONE")) { + // -- SEQUENCE of EncryptedData + DerOutputStream encrData = new DerOutputStream(); + encrData.putInteger(0); + encrData.write(encryptContent(certsData, password)); + DerOutputStream encrDataContent = new DerOutputStream(); + encrDataContent.write(DerValue.tag_Sequence, encrData); ContentInfo encrContentInfo = new ContentInfo(ContentInfo.ENCRYPTED_DATA_OID, - new DerValue(encrData)); + new DerValue(encrDataContent.toByteArray())); encrContentInfo.encode(authSafeContentInfo); } else { - ContentInfo dataContentInfo = new ContentInfo(encrData); + ContentInfo dataContentInfo = new ContentInfo(certsData); dataContentInfo.encode(authSafeContentInfo); } } @@ -1289,7 +1295,7 @@ public final class PKCS12KeyStore extends KeyStoreSpi { if (macIterationCount < 0) { macIterationCount = defaultMacIterationCount(); } - if (!macAlgorithm.equalsIgnoreCase("NONE")) { + if (password != null && !macAlgorithm.equalsIgnoreCase("NONE")) { byte[] macData = calculateMac(password, authenticatedSafe); pfx.write(macData); } @@ -1301,6 +1307,15 @@ public final class PKCS12KeyStore extends KeyStoreSpi { stream.flush(); } + @Override + public Set engineGetAttributes(String alias) { + if (!engineContainsAlias(alias)) { + return super.engineGetAttributes(alias); + } + Entry entry = entries.get(alias.toLowerCase(Locale.ENGLISH)); + return Collections.unmodifiableSet(new HashSet<>(getAttributes(entry))); + } + /** * Gets a KeyStore.Entry for the specified alias * with the specified protection parameter. @@ -1704,12 +1719,11 @@ public final class PKCS12KeyStore extends KeyStoreSpi { } /* - * Create EncryptedData content type, that contains EncryptedContentInfo. - * Includes certificates in individual SafeBags of type CertBag. - * Each CertBag may include pkcs12 attributes + * Create Data content type, includes certificates in individual + * SafeBags of type CertBag. Each CertBag may include pkcs12 attributes * (see comments in getBagAttributes) */ - private byte[] createEncryptedData(char[] password) + private byte[] getCertificateData() throws CertificateException, IOException { DerOutputStream out = new DerOutputStream(); @@ -1803,22 +1817,7 @@ public final class PKCS12KeyStore extends KeyStoreSpi { // wrap as SequenceOf SafeBag DerOutputStream safeBagValue = new DerOutputStream(); safeBagValue.write(DerValue.tag_SequenceOf, out); - byte[] safeBagData = safeBagValue.toByteArray(); - - // encrypt the content (EncryptedContentInfo) - if (!certProtectionAlgorithm.equalsIgnoreCase("NONE")) { - byte[] encrContentInfo = encryptContent(safeBagData, password); - - // -- SEQUENCE of EncryptedData - DerOutputStream encrData = new DerOutputStream(); - DerOutputStream encrDataContent = new DerOutputStream(); - encrData.putInteger(0); - encrData.write(encrContentInfo); - encrDataContent.write(DerValue.tag_Sequence, encrData); - return encrDataContent.toByteArray(); - } else { - return safeBagData; - } + return safeBagValue.toByteArray(); } /* @@ -2266,11 +2265,6 @@ public final class PKCS12KeyStore extends KeyStoreSpi { /* Update existing KeyEntry in entries table */ if (chain.size() > 0) { entry.chain = chain.toArray(new Certificate[chain.size()]); - } else { - // Remove private key entries where there is no associated - // certs. Most likely the keystore is loaded with a null - // password. - entries.remove(entry); } } } diff --git a/src/java.base/share/classes/sun/security/provider/DSAParameters.java b/src/java.base/share/classes/sun/security/provider/DSAParameters.java index 9a71ae1df860b787f7ed16c4008e1711f020efa2..9b8486894623a857544959283b064fa86764e180 100644 --- a/src/java.base/share/classes/sun/security/provider/DSAParameters.java +++ b/src/java.base/share/classes/sun/security/provider/DSAParameters.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -101,7 +101,7 @@ public class DSAParameters extends AlgorithmParametersSpi { try { Class dsaParamSpec = Class.forName ("java.security.spec.DSAParameterSpec"); - if (dsaParamSpec.isAssignableFrom(paramSpec)) { + if (paramSpec.isAssignableFrom(dsaParamSpec)) { return paramSpec.cast( new DSAParameterSpec(this.p, this.q, this.g)); } else { diff --git a/src/java.base/share/classes/sun/security/provider/DomainKeyStore.java b/src/java.base/share/classes/sun/security/provider/DomainKeyStore.java index a6ace711faa05c1cbeafb21c9b8aa6904abc9d93..588f2ed78e68151635d364395e3b6845271fcd9d 100644 --- a/src/java.base/share/classes/sun/security/provider/DomainKeyStore.java +++ b/src/java.base/share/classes/sun/security/provider/DomainKeyStore.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -236,6 +236,28 @@ abstract class DomainKeyStore extends KeyStoreSpi { return date; } + @Override + public Set engineGetAttributes(String alias) { + + AbstractMap.SimpleEntry> pair = + getKeystoresForReading(alias); + Set result = Collections.emptySet(); + + try { + String entryAlias = pair.getKey(); + for (KeyStore keystore : pair.getValue()) { + result = keystore.getAttributes(entryAlias); + if (result != null) { + break; + } + } + } catch (KeyStoreException e) { + throw new IllegalStateException(e); + } + + return result; + } + /** * Assigns the given private key to the given alias, protecting * it with the given password as defined in PKCS8. @@ -397,20 +419,22 @@ abstract class DomainKeyStore extends KeyStoreSpi { if (aliases.hasMoreElements()) { return true; } else { - if (iterator.hasNext()) { + while (iterator.hasNext()) { keystoresEntry = iterator.next(); prefix = keystoresEntry.getKey() + - entryNameSeparator; + entryNameSeparator; aliases = keystoresEntry.getValue().aliases(); - } else { - return false; + if (aliases.hasMoreElements()) { + return true; + } else { + continue; + } } + return false; } } catch (KeyStoreException e) { return false; } - - return aliases.hasMoreElements(); } public String nextElement() { diff --git a/src/java.base/share/classes/sun/security/provider/PolicyFile.java b/src/java.base/share/classes/sun/security/provider/PolicyFile.java index a9be95dd5983fcba555c154d4e97a15fad8a05c1..0708b5ee01aadec818b8325258677f6e420138d3 100644 --- a/src/java.base/share/classes/sun/security/provider/PolicyFile.java +++ b/src/java.base/share/classes/sun/security/provider/PolicyFile.java @@ -723,7 +723,7 @@ public class PolicyFile extends java.security.Policy { + SELF; } // check for self - if (pe.name != null && pe.name.indexOf(SELF) != -1) { + if (pe.name != null && pe.name.contains(SELF)) { // Create a "SelfPermission" , it could be an // an unresolved permission which will be resolved // when implies is called diff --git a/src/java.base/share/classes/sun/security/provider/PolicyParser.java b/src/java.base/share/classes/sun/security/provider/PolicyParser.java index cc6a304cb77e6148d2d5c11d61f1a376d0dc10d9..347bc8f9b564323053a61125e899e918659dfe53 100644 --- a/src/java.base/share/classes/sun/security/provider/PolicyParser.java +++ b/src/java.base/share/classes/sun/security/provider/PolicyParser.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -733,8 +733,7 @@ public class PolicyParser { switch (lookahead) { case StreamTokenizer.TT_NUMBER: throw new ParsingException(st.lineno(), expect, - LocalizedMessage.getNonlocalized("number.") + - String.valueOf(st.nval)); + LocalizedMessage.getNonlocalized("number.") + st.nval); case StreamTokenizer.TT_EOF: LocalizedMessage localizedMsg = new LocalizedMessage ("expected.expect.read.end.of.file."); @@ -826,8 +825,7 @@ public class PolicyParser { switch (lookahead) { case StreamTokenizer.TT_NUMBER: throw new ParsingException(st.lineno(), ";", - LocalizedMessage.getNonlocalized("number.") + - String.valueOf(st.nval)); + LocalizedMessage.getNonlocalized("number.") + st.nval); case StreamTokenizer.TT_EOF: throw new ParsingException(LocalizedMessage.getNonlocalized ("expected.read.end.of.file.")); 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 fb21e3ceb6e0ee85ffb5d34d9c7fce0711ae2bb6..f8fdf8790a819832daa39fdcc7f472750f42de4b 100644 --- a/src/java.base/share/classes/sun/security/provider/SHA3.java +++ b/src/java.base/share/classes/sun/security/provider/SHA3.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -158,99 +158,6 @@ abstract class SHA3 extends DigestBase { } } - /** - * Step mapping Theta as defined in section 3.2.1 . - */ - private static long[] smTheta(long[] a) { - long c0 = a[0]^a[5]^a[10]^a[15]^a[20]; - long c1 = a[1]^a[6]^a[11]^a[16]^a[21]; - long c2 = a[2]^a[7]^a[12]^a[17]^a[22]; - long c3 = a[3]^a[8]^a[13]^a[18]^a[23]; - long c4 = a[4]^a[9]^a[14]^a[19]^a[24]; - long d0 = c4 ^ Long.rotateLeft(c1, 1); - long d1 = c0 ^ Long.rotateLeft(c2, 1); - long d2 = c1 ^ Long.rotateLeft(c3, 1); - long d3 = c2 ^ Long.rotateLeft(c4, 1); - long d4 = c3 ^ Long.rotateLeft(c0, 1); - for (int y = 0; y < a.length; y += DM) { - a[y] ^= d0; - a[y+1] ^= d1; - a[y+2] ^= d2; - a[y+3] ^= d3; - a[y+4] ^= d4; - } - return a; - } - - /** - * Merged Step mapping Rho (section 3.2.2) and Pi (section 3.2.3). - * for performance. Optimization is achieved by precalculating - * shift constants for the following loop - * int xNext, yNext; - * for (int t = 0, x = 1, y = 0; t <= 23; t++, x = xNext, y = yNext) { - * int numberOfShift = ((t + 1)*(t + 2)/2) % 64; - * a[y][x] = Long.rotateLeft(a[y][x], numberOfShift); - * xNext = y; - * yNext = (2 * x + 3 * y) % DM; - * } - * and with inplace permutation. - */ - private static long[] smPiRho(long[] a) { - long tmp = Long.rotateLeft(a[10], 3); - a[10] = Long.rotateLeft(a[1], 1); - a[1] = Long.rotateLeft(a[6], 44); - a[6] = Long.rotateLeft(a[9], 20); - a[9] = Long.rotateLeft(a[22], 61); - a[22] = Long.rotateLeft(a[14], 39); - a[14] = Long.rotateLeft(a[20], 18); - a[20] = Long.rotateLeft(a[2], 62); - a[2] = Long.rotateLeft(a[12], 43); - a[12] = Long.rotateLeft(a[13], 25); - a[13] = Long.rotateLeft(a[19], 8); - a[19] = Long.rotateLeft(a[23], 56); - a[23] = Long.rotateLeft(a[15], 41); - a[15] = Long.rotateLeft(a[4], 27); - a[4] = Long.rotateLeft(a[24], 14); - a[24] = Long.rotateLeft(a[21], 2); - a[21] = Long.rotateLeft(a[8], 55); - a[8] = Long.rotateLeft(a[16], 45); - a[16] = Long.rotateLeft(a[5], 36); - a[5] = Long.rotateLeft(a[3], 28); - a[3] = Long.rotateLeft(a[18], 21); - a[18] = Long.rotateLeft(a[17], 15); - a[17] = Long.rotateLeft(a[11], 10); - a[11] = Long.rotateLeft(a[7], 6); - a[7] = tmp; - return a; - } - - /** - * Step mapping Chi as defined in section 3.2.4. - */ - private static long[] smChi(long[] a) { - for (int y = 0; y < a.length; y+=DM) { - long ay0 = a[y]; - long ay1 = a[y+1]; - long ay2 = a[y+2]; - long ay3 = a[y+3]; - long ay4 = a[y+4]; - a[y] = ay0 ^ ((~ay1) & ay2); - a[y+1] = ay1 ^ ((~ay2) & ay3); - a[y+2] = ay2 ^ ((~ay3) & ay4); - a[y+3] = ay3 ^ ((~ay4) & ay0); - a[y+4] = ay4 ^ ((~ay0) & ay1); - } - return a; - } - - /** - * Step mapping Iota as defined in section 3.2.5. - */ - private static long[] smIota(long[] a, int rndIndex) { - a[0] ^= RC_CONSTANTS[rndIndex]; - return a; - } - /** * The function Keccak as defined in section 5.2 with * rate r = 1600 and capacity c = (digest length x 2). @@ -258,10 +165,124 @@ abstract class SHA3 extends DigestBase { private void keccak() { // convert the 200-byte state into 25 lanes bytes2Lanes(state, lanes); + + long a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12; + long a13, a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24; + // move data into local variables + a0 = lanes[0]; a1 = lanes[1]; a2 = lanes[2]; a3 = lanes[3]; a4 = lanes[4]; + a5 = lanes[5]; a6 = lanes[6]; a7 = lanes[7]; a8 = lanes[8]; a9 = lanes[9]; + a10 = lanes[10]; a11 = lanes[11]; a12 = lanes[12]; a13 = lanes[13]; a14 = lanes[14]; + a15 = lanes[15]; a16 = lanes[16]; a17 = lanes[17]; a18 = lanes[18]; a19 = lanes[19]; + a20 = lanes[20]; a21 = lanes[21]; a22 = lanes[22]; a23 = lanes[23]; a24 = lanes[24]; + // process the lanes through step mappings for (int ir = 0; ir < NR; ir++) { - smIota(smChi(smPiRho(smTheta(lanes))), ir); + // Step mapping Theta as defined in section 3.2.1. + long c0 = a0^a5^a10^a15^a20; + long c1 = a1^a6^a11^a16^a21; + long c2 = a2^a7^a12^a17^a22; + long c3 = a3^a8^a13^a18^a23; + long c4 = a4^a9^a14^a19^a24; + long d0 = c4 ^ Long.rotateLeft(c1, 1); + long d1 = c0 ^ Long.rotateLeft(c2, 1); + long d2 = c1 ^ Long.rotateLeft(c3, 1); + long d3 = c2 ^ Long.rotateLeft(c4, 1); + long d4 = c3 ^ Long.rotateLeft(c0, 1); + a0 ^= d0; a1 ^= d1; a2 ^= d2; a3 ^= d3; a4 ^= d4; + a5 ^= d0; a6 ^= d1; a7 ^= d2; a8 ^= d3; a9 ^= d4; + a10 ^= d0; a11 ^= d1; a12 ^= d2; a13 ^= d3; a14 ^= d4; + a15 ^= d0; a16 ^= d1; a17 ^= d2; a18 ^= d3; a19 ^= d4; + a20 ^= d0; a21 ^= d1; a22 ^= d2; a23 ^= d3; a24 ^= d4; + + /** + * Merged Step mapping Rho (section 3.2.2) and Pi (section 3.2.3). + * for performance. Optimization is achieved by precalculating + * shift constants for the following loop + * int xNext, yNext; + * for (int t = 0, x = 1, y = 0; t <= 23; t++, x = xNext, y = yNext) { + * int numberOfShift = ((t + 1)*(t + 2)/2) % 64; + * a[y][x] = Long.rotateLeft(a[y][x], numberOfShift); + * xNext = y; + * yNext = (2 * x + 3 * y) % DM; + * } + * and with inplace permutation. + */ + long ay = Long.rotateLeft(a10, 3); + a10 = Long.rotateLeft(a1, 1); + a1 = Long.rotateLeft(a6, 44); + a6 = Long.rotateLeft(a9, 20); + a9 = Long.rotateLeft(a22, 61); + a22 = Long.rotateLeft(a14, 39); + a14 = Long.rotateLeft(a20, 18); + a20 = Long.rotateLeft(a2, 62); + a2 = Long.rotateLeft(a12, 43); + a12 = Long.rotateLeft(a13, 25); + a13 = Long.rotateLeft(a19, 8); + a19 = Long.rotateLeft(a23, 56); + a23 = Long.rotateLeft(a15, 41); + a15 = Long.rotateLeft(a4, 27); + a4 = Long.rotateLeft(a24, 14); + a24 = Long.rotateLeft(a21, 2); + a21 = Long.rotateLeft(a8, 55); + a8 = Long.rotateLeft(a16, 45); + a16 = Long.rotateLeft(a5, 36); + a5 = Long.rotateLeft(a3, 28); + a3 = Long.rotateLeft(a18, 21); + a18 = Long.rotateLeft(a17, 15); + a17 = Long.rotateLeft(a11, 10); + a11 = Long.rotateLeft(a7, 6); + a7 = ay; + + // Step mapping Chi as defined in section 3.2.4. + long tmp0 = a0; + long tmp1 = a1; + long tmp2 = a2; + long tmp3 = a3; + long tmp4 = a4; + a0 = tmp0 ^ ((~tmp1) & tmp2); + a1 = tmp1 ^ ((~tmp2) & tmp3); + a2 = tmp2 ^ ((~tmp3) & tmp4); + a3 = tmp3 ^ ((~tmp4) & tmp0); + a4 = tmp4 ^ ((~tmp0) & tmp1); + + tmp0 = a5; tmp1 = a6; tmp2 = a7; tmp3 = a8; tmp4 = a9; + a5 = tmp0 ^ ((~tmp1) & tmp2); + a6 = tmp1 ^ ((~tmp2) & tmp3); + a7 = tmp2 ^ ((~tmp3) & tmp4); + a8 = tmp3 ^ ((~tmp4) & tmp0); + a9 = tmp4 ^ ((~tmp0) & tmp1); + + tmp0 = a10; tmp1 = a11; tmp2 = a12; tmp3 = a13; tmp4 = a14; + a10 = tmp0 ^ ((~tmp1) & tmp2); + a11 = tmp1 ^ ((~tmp2) & tmp3); + a12 = tmp2 ^ ((~tmp3) & tmp4); + a13 = tmp3 ^ ((~tmp4) & tmp0); + a14 = tmp4 ^ ((~tmp0) & tmp1); + + tmp0 = a15; tmp1 = a16; tmp2 = a17; tmp3 = a18; tmp4 = a19; + a15 = tmp0 ^ ((~tmp1) & tmp2); + a16 = tmp1 ^ ((~tmp2) & tmp3); + a17 = tmp2 ^ ((~tmp3) & tmp4); + a18 = tmp3 ^ ((~tmp4) & tmp0); + a19 = tmp4 ^ ((~tmp0) & tmp1); + + tmp0 = a20; tmp1 = a21; tmp2 = a22; tmp3 = a23; tmp4 = a24; + a20 = tmp0 ^ ((~tmp1) & tmp2); + a21 = tmp1 ^ ((~tmp2) & tmp3); + a22 = tmp2 ^ ((~tmp3) & tmp4); + a23 = tmp3 ^ ((~tmp4) & tmp0); + a24 = tmp4 ^ ((~tmp0) & tmp1); + + // Step mapping Iota as defined in section 3.2.5. + a0 ^= RC_CONSTANTS[ir]; } + + lanes[0] = a0; lanes[1] = a1; lanes[2] = a2; lanes[3] = a3; lanes[4] = a4; + lanes[5] = a5; lanes[6] = a6; lanes[7] = a7; lanes[8] = a8; lanes[9] = a9; + lanes[10] = a10; lanes[11] = a11; lanes[12] = a12; lanes[13] = a13; lanes[14] = a14; + lanes[15] = a15; lanes[16] = a16; lanes[17] = a17; lanes[18] = a18; lanes[19] = a19; + lanes[20] = a20; lanes[21] = a21; lanes[22] = a22; lanes[23] = a23; lanes[24] = a24; + // convert the resulting 25 lanes back into 200-byte state lanes2Bytes(lanes, state); } diff --git a/src/java.base/share/classes/sun/security/provider/SunEntries.java b/src/java.base/share/classes/sun/security/provider/SunEntries.java index 912cad5971475253f7fbf544b5f5886ddd370cbf..c7fdd230830f7ce329c9f94d0e86054ef2e65b49 100644 --- a/src/java.base/share/classes/sun/security/provider/SunEntries.java +++ b/src/java.base/share/classes/sun/security/provider/SunEntries.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 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 @@ -210,8 +210,10 @@ public final class SunEntries { /* * Digest engines */ - add(p, "MessageDigest", "MD2", "sun.security.provider.MD2", attrs); - add(p, "MessageDigest", "MD5", "sun.security.provider.MD5", attrs); + addWithAlias(p, "MessageDigest", "MD2", "sun.security.provider.MD2", + attrs); + addWithAlias(p, "MessageDigest", "MD5", "sun.security.provider.MD5", + attrs); addWithAlias(p, "MessageDigest", "SHA-1", "sun.security.provider.SHA", attrs); diff --git a/src/java.base/share/classes/sun/security/provider/certpath/AlgorithmChecker.java b/src/java.base/share/classes/sun/security/provider/certpath/AlgorithmChecker.java index 4a79c3a3f51e783f943efd64742c50ccf8595a17..4451aa7e533553879b34bd621a63df82b55cff7d 100644 --- a/src/java.base/share/classes/sun/security/provider/certpath/AlgorithmChecker.java +++ b/src/java.base/share/classes/sun/security/provider/certpath/AlgorithmChecker.java @@ -38,7 +38,6 @@ import java.security.KeyFactory; import java.security.AlgorithmParameters; import java.security.GeneralSecurityException; import java.security.cert.Certificate; -import java.security.cert.X509CRL; import java.security.cert.X509Certificate; import java.security.cert.PKIXCertPathChecker; import java.security.cert.TrustAnchor; @@ -57,7 +56,6 @@ import sun.security.util.DisabledAlgorithmConstraints; import sun.security.validator.Validator; import sun.security.x509.AlgorithmId; import sun.security.x509.X509CertImpl; -import sun.security.x509.X509CRLImpl; /** * A {@code PKIXCertPathChecker} implementation to check whether a @@ -226,13 +224,13 @@ public final class AlgorithmChecker extends PKIXCertPathChecker { CertPathConstraintsParameters cp = new CertPathConstraintsParameters(trustedPubKey, variant, anchor, date); - dac.permits(trustedPubKey.getAlgorithm(), cp); + dac.permits(trustedPubKey.getAlgorithm(), cp, true); } // Check the signature algorithm and parameters against constraints CertPathConstraintsParameters cp = new CertPathConstraintsParameters(x509Cert, variant, anchor, date); - dac.permits(currSigAlg, currSigAlgParams, cp); + dac.permits(currSigAlg, currSigAlgParams, cp, true); } else { if (prevPubKey != null) { if (!constraints.permits(SIGNATURE_PRIMITIVE_SET, @@ -362,29 +360,6 @@ public final class AlgorithmChecker extends PKIXCertPathChecker { } } - /** - * Check the signature algorithm with the specified public key. - * - * @param key the public key to verify the CRL signature - * @param crl the target CRL - * @param variant the Validator variant of the operation. A null value - * passed will set it to Validator.GENERIC. - * @param anchor the trust anchor selected to validate the CRL issuer - */ - static void check(PublicKey key, X509CRL crl, String variant, - TrustAnchor anchor) throws CertPathValidatorException { - - X509CRLImpl x509CRLImpl = null; - try { - x509CRLImpl = X509CRLImpl.toImpl(crl); - } catch (CRLException ce) { - throw new CertPathValidatorException(ce); - } - - AlgorithmId algorithmId = x509CRLImpl.getSigAlgId(); - check(key, algorithmId, variant, anchor); - } - /** * Check the signature algorithm with the specified public key. * @@ -399,7 +374,7 @@ public final class AlgorithmChecker extends PKIXCertPathChecker { DisabledAlgorithmConstraints.certPathConstraints().permits( algorithmId.getName(), algorithmId.getParameters(), - new CertPathConstraintsParameters(key, variant, anchor, null)); + new CertPathConstraintsParameters(key, variant, anchor, null), true); } } diff --git a/src/java.base/share/classes/sun/security/provider/certpath/Builder.java b/src/java.base/share/classes/sun/security/provider/certpath/Builder.java index 186d1269de315888ab83563c7b20f2987e39a983..b5cf0c5e44287e00fb94405344c61d782f24c05e 100644 --- a/src/java.base/share/classes/sun/security/provider/certpath/Builder.java +++ b/src/java.base/share/classes/sun/security/provider/certpath/Builder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -26,7 +26,6 @@ package sun.security.provider.certpath; import java.io.IOException; -import java.security.AccessController; import java.security.GeneralSecurityException; import java.security.cert.*; import java.util.*; @@ -337,7 +336,7 @@ public abstract class Builder { if (debug != null) { debug.println("Builder.targetDistance() merged constraints: " - + String.valueOf(constraints)); + + constraints); } /* reduce permitted by excluded */ GeneralSubtrees permitted = diff --git a/src/java.base/share/classes/sun/security/provider/certpath/ConstraintsChecker.java b/src/java.base/share/classes/sun/security/provider/certpath/ConstraintsChecker.java index 28fb322ddc4d8385089a65730427cf84cc928ddd..00d67de5a079d5e18f7cfe2b7165678bdf2101fb 100644 --- a/src/java.base/share/classes/sun/security/provider/certpath/ConstraintsChecker.java +++ b/src/java.base/share/classes/sun/security/provider/certpath/ConstraintsChecker.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -185,14 +185,14 @@ class ConstraintsChecker extends PKIXCertPathChecker { if (debug != null) { debug.println("prevNC = " + prevNC + - ", newNC = " + String.valueOf(newConstraints)); + ", newNC = " + newConstraints); } // if there are no previous name constraints, we just return the // new name constraints. if (prevNC == null) { if (debug != null) { - debug.println("mergedNC = " + String.valueOf(newConstraints)); + debug.println("mergedNC = " + newConstraints); } if (newConstraints == null) { return newConstraints; diff --git a/src/java.base/share/classes/sun/security/provider/certpath/DistributionPointFetcher.java b/src/java.base/share/classes/sun/security/provider/certpath/DistributionPointFetcher.java index bce426cef5776f7359b2aa0348afe8e858273709..413faa85e89c3f1dc0cbf3577bdf36a7daa7dc0b 100644 --- a/src/java.base/share/classes/sun/security/provider/certpath/DistributionPointFetcher.java +++ b/src/java.base/share/classes/sun/security/provider/certpath/DistributionPointFetcher.java @@ -653,7 +653,8 @@ public class DistributionPointFetcher { // check the crl signature algorithm try { - AlgorithmChecker.check(prevKey, crl, variant, anchor); + AlgorithmChecker.check(prevKey, crlImpl.getSigAlgId(), + variant, anchor); } catch (CertPathValidatorException cpve) { if (debug != null) { debug.println("CRL signature algorithm check failed: " + cpve); diff --git a/src/java.base/share/classes/sun/security/provider/certpath/ForwardBuilder.java b/src/java.base/share/classes/sun/security/provider/certpath/ForwardBuilder.java index 6122fdaa97077ae8f1266f882cd81ebd99dc495e..19dd5dd8d751fe8fc6fd123ae65c99f6517d2a27 100644 --- a/src/java.base/share/classes/sun/security/provider/certpath/ForwardBuilder.java +++ b/src/java.base/share/classes/sun/security/provider/certpath/ForwardBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -34,7 +34,6 @@ import java.security.cert.CertPathValidatorException; import java.security.cert.PKIXReason; import java.security.cert.CertStore; import java.security.cert.CertStoreException; -import java.security.cert.PKIXBuilderParameters; import java.security.cert.PKIXCertPathChecker; import java.security.cert.TrustAnchor; import java.security.cert.X509Certificate; @@ -598,8 +597,8 @@ class ForwardBuilder extends Builder { X500Name tAo1 = tSubjectName.commonAncestor(cIssuer1Name); X500Name tAo2 = tSubjectName.commonAncestor(cIssuer2Name); if (debug != null) { - debug.println(METHOD_NME +" tAo1: " + String.valueOf(tAo1)); - debug.println(METHOD_NME +" tAo2: " + String.valueOf(tAo2)); + debug.println(METHOD_NME +" tAo1: " + tAo1); + debug.println(METHOD_NME +" tAo2: " + tAo2); } if (tAo1 != null || tAo2 != null) { if (tAo1 != null && tAo2 != null) { diff --git a/src/java.base/share/classes/sun/security/provider/certpath/ForwardState.java b/src/java.base/share/classes/sun/security/provider/certpath/ForwardState.java index 2dc9e208e924f212b4b9d6a26fbac752e599967d..5cbd0d7f404d83cca7d61faca68357cc1a56b64a 100644 --- a/src/java.base/share/classes/sun/security/provider/certpath/ForwardState.java +++ b/src/java.base/share/classes/sun/security/provider/certpath/ForwardState.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -117,9 +117,8 @@ class ForwardState implements State { sb.append("State ["); sb.append("\n issuerDN of last cert: ").append(issuerDN); sb.append("\n traversedCACerts: ").append(traversedCACerts); - sb.append("\n init: ").append(String.valueOf(init)); - sb.append("\n keyParamsNeeded: ").append - (String.valueOf(keyParamsNeededFlag)); + sb.append("\n init: ").append(init); + sb.append("\n keyParamsNeeded: ").append(keyParamsNeededFlag); sb.append("\n subjectNamesTraversed: \n").append (subjectNamesTraversed); sb.append("]\n"); diff --git a/src/java.base/share/classes/sun/security/rsa/PSSParameters.java b/src/java.base/share/classes/sun/security/rsa/PSSParameters.java index fef496ed50c88360e3ef9e319c95577178ccee66..5a1584b0a9ea1244820d800597329c995cf5663c 100644 --- a/src/java.base/share/classes/sun/security/rsa/PSSParameters.java +++ b/src/java.base/share/classes/sun/security/rsa/PSSParameters.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -102,8 +102,13 @@ public final class PSSParameters extends AlgorithmParametersSpi { if (!val.getOID().equals(AlgorithmId.MGF1_oid)) { throw new IOException("Only MGF1 mgf is supported"); } + + byte[] encodedParams = val.getEncodedParams(); + if (encodedParams == null) { + throw new IOException("Missing MGF1 parameters"); + } AlgorithmId params = AlgorithmId.parse( - new DerValue(val.getEncodedParams())); + new DerValue(encodedParams)); String mgfDigestName = params.getName(); switch (mgfDigestName) { case "SHA-1": @@ -180,7 +185,7 @@ public final class PSSParameters extends AlgorithmParametersSpi { protected T engineGetParameterSpec(Class paramSpec) throws InvalidParameterSpecException { - if (PSSParameterSpec.class.isAssignableFrom(paramSpec)) { + if (paramSpec.isAssignableFrom(PSSParameterSpec.class)) { return paramSpec.cast(spec); } else { throw new InvalidParameterSpecException diff --git a/src/java.base/share/classes/sun/security/rsa/RSAPSSSignature.java b/src/java.base/share/classes/sun/security/rsa/RSAPSSSignature.java index 994d9f14cce92cf443352780762c6ddf3a1f4b72..15c143127fb24bb8c150596ea7e714b467170c3f 100644 --- a/src/java.base/share/classes/sun/security/rsa/RSAPSSSignature.java +++ b/src/java.base/share/classes/sun/security/rsa/RSAPSSSignature.java @@ -59,7 +59,7 @@ public class RSAPSSSignature extends SignatureSpi { private boolean isDigestEqual(String stdAlg, String givenAlg) { if (stdAlg == null || givenAlg == null) return false; - if (givenAlg.indexOf("-") != -1) { + if (givenAlg.contains("-")) { return stdAlg.equalsIgnoreCase(givenAlg); } else { if (stdAlg.equals("SHA-1")) { @@ -255,7 +255,6 @@ public class RSAPSSSignature extends SignatureSpi { * internal signature parameters. */ private void isValid(RSAKey rsaKey) throws InvalidKeyException { - AlgorithmParameterSpec keyParams = rsaKey.getParams(); // validate key parameters if (!isCompatible(rsaKey.getParams(), this.sigParams)) { throw new InvalidKeyException diff --git a/src/java.base/share/classes/sun/security/rsa/RSAPadding.java b/src/java.base/share/classes/sun/security/rsa/RSAPadding.java index c54dbdb8d43847fa1afab10b7d95c53b6c6811fc..3fe86cfea09840c503766f5dad2f74d6f89f8bf6 100644 --- a/src/java.base/share/classes/sun/security/rsa/RSAPadding.java +++ b/src/java.base/share/classes/sun/security/rsa/RSAPadding.java @@ -270,7 +270,7 @@ public final class RSAPadding { */ public byte[] unpad(byte[] padded) throws BadPaddingException { if (padded.length != paddedSize) { - throw new BadPaddingException("Decryption error." + + throw new BadPaddingException("Decryption error. " + "The padded array length (" + padded.length + ") is not the specified padded size (" + paddedSize + ")"); } diff --git a/src/java.base/share/classes/sun/security/rsa/RSAPrivateCrtKeyImpl.java b/src/java.base/share/classes/sun/security/rsa/RSAPrivateCrtKeyImpl.java index fbc9fda05faf23ca9594ec51310309ba00bb6a32..8ca5135fe85be196d9b85cb18af3946911b6e1ac 100644 --- a/src/java.base/share/classes/sun/security/rsa/RSAPrivateCrtKeyImpl.java +++ b/src/java.base/share/classes/sun/security/rsa/RSAPrivateCrtKeyImpl.java @@ -141,7 +141,7 @@ public final class RSAPrivateCrtKeyImpl BigInteger n, BigInteger e, BigInteger d, BigInteger p, BigInteger q, BigInteger pe, BigInteger qe, BigInteger coeff) throws InvalidKeyException { - RSAPrivateKey key; + if ((e.signum() == 0) || (p.signum() == 0) || (q.signum() == 0) || (pe.signum() == 0) || (qe.signum() == 0) || (coeff.signum() == 0)) { diff --git a/src/java.base/share/classes/sun/security/rsa/RSAUtil.java b/src/java.base/share/classes/sun/security/rsa/RSAUtil.java index 1d2e991e1bd58bf546264845419793a917576d3b..eb1a2e81e4941e46f71f0212dd43bcf775d47f92 100644 --- a/src/java.base/share/classes/sun/security/rsa/RSAUtil.java +++ b/src/java.base/share/classes/sun/security/rsa/RSAUtil.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -25,7 +25,6 @@ package sun.security.rsa; -import java.io.IOException; import java.security.*; import java.security.spec.*; import sun.security.util.ObjectIdentifier; @@ -61,9 +60,9 @@ public class RSAUtil { // match loosely in order to work with 3rd party providers which // may not follow the standard names - if (name.indexOf("PSS") != -1) { + if (name.contains("PSS")) { return PSS; - } else if (name.indexOf("RSA") != -1) { + } else if (name.contains("RSA")) { return RSA; } else { // no match throw new ProviderException("Unsupported algorithm " + name); @@ -151,7 +150,7 @@ public class RSAUtil { } catch (ProviderException pe) { // accommodate RSA keys encoded with various RSA signature oids // for backward compatibility - if (algName.indexOf("RSA") != -1) { + if (algName.contains("RSA")) { result[0] = KeyType.RSA; } else { // pass it up diff --git a/src/java.base/share/classes/sun/security/ssl/Alert.java b/src/java.base/share/classes/sun/security/ssl/Alert.java index bc034dc8c3bcfbc0eae58c61e75d7017a5b4e3eb..922937887aaaceb25a202578dda1eecc191e6fc9 100644 --- a/src/java.base/share/classes/sun/security/ssl/Alert.java +++ b/src/java.base/share/classes/sun/security/ssl/Alert.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -122,22 +122,15 @@ enum Alert { reason = (cause != null) ? cause.getMessage() : ""; } - SSLException ssle; if (cause instanceof IOException) { - ssle = new SSLException(reason); + return new SSLException(reason, cause); } else if ((this == UNEXPECTED_MESSAGE)) { - ssle = new SSLProtocolException(reason); + return new SSLProtocolException(reason, cause); } else if (handshakeOnly) { - ssle = new SSLHandshakeException(reason); + return new SSLHandshakeException(reason, cause); } else { - ssle = new SSLException(reason); + return new SSLException(reason, cause); } - - if (cause != null) { - ssle.initCause(cause); - } - - return ssle; } /** diff --git a/src/java.base/share/classes/sun/security/ssl/BaseSSLSocketImpl.java b/src/java.base/share/classes/sun/security/ssl/BaseSSLSocketImpl.java index ba58741d759279b642c044745d36baafe29a1dd9..8923dee25c98a01a6c6a17d6bc8224f69a3b6169 100644 --- a/src/java.base/share/classes/sun/security/ssl/BaseSSLSocketImpl.java +++ b/src/java.base/share/classes/sun/security/ssl/BaseSSLSocketImpl.java @@ -270,7 +270,7 @@ abstract class BaseSSLSocketImpl extends SSLSocket { * the penalty of prematurly killing SSL sessions. */ @Override - @SuppressWarnings("deprecation") + @SuppressWarnings("removal") protected final void finalize() throws Throwable { try { close(); diff --git a/src/java.base/share/classes/sun/security/ssl/CertificateAuthoritiesExtension.java b/src/java.base/share/classes/sun/security/ssl/CertificateAuthoritiesExtension.java index 760daf4b3a15259741bd9bb50d8ad85771c97905..6315c7fdd9f985b0be9f606305d55f405997a70c 100644 --- a/src/java.base/share/classes/sun/security/ssl/CertificateAuthoritiesExtension.java +++ b/src/java.base/share/classes/sun/security/ssl/CertificateAuthoritiesExtension.java @@ -211,7 +211,7 @@ final class CertificateAuthoritiesExtension { if (encodedCAs.isEmpty()) { if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { SSLLogger.warning( - "The number of CAs exceeds the maximum size" + + "The number of CAs exceeds the maximum size " + "of the certificate_authorities extension"); } diff --git a/src/java.base/share/classes/sun/security/ssl/CipherSuite.java b/src/java.base/share/classes/sun/security/ssl/CipherSuite.java index 8500ae7e188ee0c750a01f647eaf6b6ae8fd22dd..d957d7b20bdda7ee183a916f0fd2d01c687bbd6a 100644 --- a/src/java.base/share/classes/sun/security/ssl/CipherSuite.java +++ b/src/java.base/share/classes/sun/security/ssl/CipherSuite.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 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 @@ -54,9 +54,9 @@ enum CipherSuite { // changed later, see below). // 2. Prefer forward secrecy cipher suites. // 3. Prefer the stronger bulk cipher, in the order of AES_256(GCM), - // AES_128(GCM), AES_256, AES_128, 3DES-EDE. + // AES_128(GCM), AES_256, AES_128. // 4. Prefer the stronger MAC algorithm, in the order of SHA384, - // SHA256, SHA, MD5. + // SHA256, SHA. // 5. Prefer the better performance of key exchange and digital // signature algorithm, in the order of ECDHE-ECDSA, ECDHE-RSA, // DHE-RSA, DHE-DSS, ECDH-ECDSA, ECDH-RSA, RSA. @@ -327,41 +327,6 @@ enum CipherSuite { ProtocolVersion.PROTOCOLS_TO_12, K_RSA, B_AES_128, M_SHA, H_SHA256), - // 3DES_EDE, forward secrecy. - TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA( - 0xC008, true, "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA", "", - ProtocolVersion.PROTOCOLS_TO_12, - K_ECDHE_ECDSA, B_3DES, M_SHA, H_SHA256), - TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA( - 0xC012, true, "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA", "", - ProtocolVersion.PROTOCOLS_TO_12, - K_ECDHE_RSA, B_3DES, M_SHA, H_SHA256), - SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA( - 0x0016, true, "SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA", - "TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA", - ProtocolVersion.PROTOCOLS_TO_12, - K_DHE_RSA, B_3DES, M_SHA, H_SHA256), - SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA( - 0x0013, true, "SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA", - "TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA", - ProtocolVersion.PROTOCOLS_TO_12, - K_DHE_DSS, B_3DES, M_SHA, H_SHA256), - - // 3DES_EDE, not forward secrecy. - TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA( - 0xC003, true, "TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA", "", - ProtocolVersion.PROTOCOLS_TO_12, - K_ECDH_ECDSA, B_3DES, M_SHA, H_SHA256), - TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA( - 0xC00D, true, "TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA", "", - ProtocolVersion.PROTOCOLS_TO_12, - K_ECDH_RSA, B_3DES, M_SHA, H_SHA256), - SSL_RSA_WITH_3DES_EDE_CBC_SHA( - 0x000A, true, "SSL_RSA_WITH_3DES_EDE_CBC_SHA", - "TLS_RSA_WITH_3DES_EDE_CBC_SHA", - ProtocolVersion.PROTOCOLS_TO_12, - K_RSA, B_3DES, M_SHA, H_SHA256), - // Renegotiation protection request Signalling Cipher Suite Value (SCSV). TLS_EMPTY_RENEGOTIATION_INFO_SCSV( // RFC 5746, TLS 1.2 and prior 0x00FF, true, "TLS_EMPTY_RENEGOTIATION_INFO_SCSV", "", @@ -413,6 +378,41 @@ enum CipherSuite { 0x0034, false, "TLS_DH_anon_WITH_AES_128_CBC_SHA", "", ProtocolVersion.PROTOCOLS_TO_12, K_DH_ANON, B_AES_128, M_SHA, H_SHA256), + + // 3DES_EDE, forward secrecy. + TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA( + 0xC008, false, "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA", "", + ProtocolVersion.PROTOCOLS_TO_12, + K_ECDHE_ECDSA, B_3DES, M_SHA, H_SHA256), + TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA( + 0xC012, false, "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA", "", + ProtocolVersion.PROTOCOLS_TO_12, + K_ECDHE_RSA, B_3DES, M_SHA, H_SHA256), + SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA( + 0x0016, false, "SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA", + "TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA", + ProtocolVersion.PROTOCOLS_TO_12, + K_DHE_RSA, B_3DES, M_SHA, H_SHA256), + SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA( + 0x0013, false, "SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA", + "TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA", + ProtocolVersion.PROTOCOLS_TO_12, + K_DHE_DSS, B_3DES, M_SHA, H_SHA256), + + // 3DES_EDE, not forward secrecy. + TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA( + 0xC003, false, "TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA", "", + ProtocolVersion.PROTOCOLS_TO_12, + K_ECDH_ECDSA, B_3DES, M_SHA, H_SHA256), + TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA( + 0xC00D, false, "TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA", "", + ProtocolVersion.PROTOCOLS_TO_12, + K_ECDH_RSA, B_3DES, M_SHA, H_SHA256), + SSL_RSA_WITH_3DES_EDE_CBC_SHA( + 0x000A, false, "SSL_RSA_WITH_3DES_EDE_CBC_SHA", + "TLS_RSA_WITH_3DES_EDE_CBC_SHA", + ProtocolVersion.PROTOCOLS_TO_12, + K_RSA, B_3DES, M_SHA, H_SHA256), TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA( 0xC017, false, "TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA", "", ProtocolVersion.PROTOCOLS_TO_12, 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 1197802842d056bfcd971fe75ba11ac46a3c67c6..b75491def4cf775ad66123ee310a0e98e0025a77 100644 --- a/src/java.base/share/classes/sun/security/ssl/ClientHello.java +++ b/src/java.base/share/classes/sun/security/ssl/ClientHello.java @@ -568,15 +568,15 @@ final class ClientHello { "No new session is allowed and " + "no existing session can be resumed"); } - - if (chc.maximumActiveProtocol.useTLS13PlusSpec() && - SSLConfiguration.useCompatibilityMode) { - // In compatibility mode, the TLS 1.3 legacy_session_id - // field MUST be non-empty, so a client not offering a - // pre-TLS 1.3 session MUST generate a new 32-byte value. - sessionId = + } + if (sessionId.length() == 0 && + chc.maximumActiveProtocol.useTLS13PlusSpec() && + SSLConfiguration.useCompatibilityMode) { + // In compatibility mode, the TLS 1.3 legacy_session_id + // field MUST be non-empty, so a client not offering a + // pre-TLS 1.3 session MUST generate a new 32-byte value. + sessionId = new SessionId(true, chc.sslContext.getSecureRandom()); - } } ProtocolVersion minimumVersion = ProtocolVersion.NONE; diff --git a/src/java.base/share/classes/sun/security/ssl/DHClientKeyExchange.java b/src/java.base/share/classes/sun/security/ssl/DHClientKeyExchange.java index f9753ffe078b6c13f813e23500aa9556c75e27b0..996e3f78ec162b97f95b3abbe150f7a8d942f120 100644 --- a/src/java.base/share/classes/sun/security/ssl/DHClientKeyExchange.java +++ b/src/java.base/share/classes/sun/security/ssl/DHClientKeyExchange.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -295,8 +295,8 @@ final class DHClientKeyExchange { shc.handshakeCredentials.add( new DHECredentials(peerPublicKey, namedGroup)); } catch (GeneralSecurityException | java.io.IOException e) { - throw (SSLHandshakeException)(new SSLHandshakeException( - "Could not generate DHPublicKey").initCause(e)); + throw new SSLHandshakeException( + "Could not generate DHPublicKey", e); } // update the states diff --git a/src/java.base/share/classes/sun/security/ssl/DHServerKeyExchange.java b/src/java.base/share/classes/sun/security/ssl/DHServerKeyExchange.java index af64383457a8b8d8b15e48d81cefeca5498ccdc9..38e97073eb1fb8abd0bc1dcfc308e926ab20b652 100644 --- a/src/java.base/share/classes/sun/security/ssl/DHServerKeyExchange.java +++ b/src/java.base/share/classes/sun/security/ssl/DHServerKeyExchange.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -444,7 +444,6 @@ final class DHServerKeyExchange { */ private void updateSignature(Signature sig, byte[] clntNonce, byte[] svrNonce) throws SignatureException { - int tmp; sig.update(clntNonce); sig.update(svrNonce); diff --git a/src/java.base/share/classes/sun/security/ssl/ECDHKeyExchange.java b/src/java.base/share/classes/sun/security/ssl/ECDHKeyExchange.java index 59bc40411ce86580ebfefd2a6daf62d985aa4cc9..9833ea94e8d48ec3aa80f87226fbf16515c275da 100644 --- a/src/java.base/share/classes/sun/security/ssl/ECDHKeyExchange.java +++ b/src/java.base/share/classes/sun/security/ssl/ECDHKeyExchange.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -160,8 +160,7 @@ final class ECDHKeyExchange { ka.doPhase(peerPublicKey, true); return ka.generateSecret("TlsPremasterSecret"); } catch (GeneralSecurityException e) { - throw (SSLHandshakeException) new SSLHandshakeException( - "Could not generate secret").initCause(e); + throw new SSLHandshakeException("Could not generate secret", e); } } @@ -177,8 +176,7 @@ final class ECDHKeyExchange { PublicKey peerPublicKey = kf.generatePublic(spec); return getAgreedSecret(peerPublicKey); } catch (GeneralSecurityException | java.io.IOException e) { - throw (SSLHandshakeException) new SSLHandshakeException( - "Could not generate secret").initCause(e); + throw new SSLHandshakeException("Could not generate secret", e); } } @@ -202,8 +200,8 @@ final class ECDHKeyExchange { "ECPublicKey does not comply to algorithm constraints"); } } catch (GeneralSecurityException | java.io.IOException e) { - throw (SSLHandshakeException) new SSLHandshakeException( - "Could not generate ECPublicKey").initCause(e); + throw new SSLHandshakeException( + "Could not generate ECPublicKey", e); } } diff --git a/src/java.base/share/classes/sun/security/ssl/InputRecord.java b/src/java.base/share/classes/sun/security/ssl/InputRecord.java index 8277c799f7f6f0381194938808ed7e1ac10b6ddc..de860fd15b08fc7d8097640302ff14a6581a3f12 100644 --- a/src/java.base/share/classes/sun/security/ssl/InputRecord.java +++ b/src/java.base/share/classes/sun/security/ssl/InputRecord.java @@ -122,7 +122,7 @@ abstract class InputRecord implements Record, Closeable { * Since MAC's doFinal() is called for every SSL/TLS packet, it's * not necessary to do the same with MAC's. */ - readCipher.dispose(); + this.readCipher.dispose(); this.readCipher = readCipher; } diff --git a/src/java.base/share/classes/sun/security/ssl/KAKeyDerivation.java b/src/java.base/share/classes/sun/security/ssl/KAKeyDerivation.java index 7c791e85f773481a632d3313fc62bde60637c353..b76da75c763cca16cb8933af724c3ac86a371e6c 100644 --- a/src/java.base/share/classes/sun/security/ssl/KAKeyDerivation.java +++ b/src/java.base/share/classes/sun/security/ssl/KAKeyDerivation.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -88,8 +88,7 @@ public class KAKeyDerivation implements SSLKeyDerivation { context, preMasterSecret); return kd.deriveKey("MasterSecret", params); } catch (GeneralSecurityException gse) { - throw (SSLHandshakeException) new SSLHandshakeException( - "Could not generate secret").initCause(gse); + throw new SSLHandshakeException("Could not generate secret", gse); } } @@ -125,8 +124,7 @@ public class KAKeyDerivation implements SSLKeyDerivation { // derive handshake secret return hkdf.extract(saltSecret, sharedSecret, algorithm); } catch (GeneralSecurityException gse) { - throw (SSLHandshakeException) new SSLHandshakeException( - "Could not generate secret").initCause(gse); + throw new SSLHandshakeException("Could not generate secret", gse); } } } diff --git a/src/java.base/share/classes/sun/security/ssl/NewSessionTicket.java b/src/java.base/share/classes/sun/security/ssl/NewSessionTicket.java index 50f19dbf715c1e101a92923f098b54edb0b68eff..337c83849915be30a3e27e862ef571cc3dc0406b 100644 --- a/src/java.base/share/classes/sun/security/ssl/NewSessionTicket.java +++ b/src/java.base/share/classes/sun/security/ssl/NewSessionTicket.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -302,8 +302,7 @@ final class NewSessionTicket { return hkdf.expand(resumptionMasterSecret, hkdfInfo, hashAlg.hashLength, "TlsPreSharedKey"); } catch (GeneralSecurityException gse) { - throw (SSLHandshakeException) new SSLHandshakeException( - "Could not derive PSK").initCause(gse); + throw new SSLHandshakeException("Could not derive PSK", gse); } } diff --git a/src/java.base/share/classes/sun/security/ssl/OutputRecord.java b/src/java.base/share/classes/sun/security/ssl/OutputRecord.java index 696251ff3b1c9a2782df404db7a3e57d31cad355..7a9657152b744af4fba3407cc1ebbae9b1b5f56c 100644 --- a/src/java.base/share/classes/sun/security/ssl/OutputRecord.java +++ b/src/java.base/share/classes/sun/security/ssl/OutputRecord.java @@ -141,6 +141,11 @@ abstract class OutputRecord // SSLEngine and SSLSocket abstract void encodeChangeCipherSpec() throws IOException; + // SSLEngine and SSLSocket + void disposeWriteCipher() { + throw new UnsupportedOperationException(); + } + // apply to SSLEngine only Ciphertext encode( ByteBuffer[] srcs, int srcsOffset, int srcsLength, @@ -190,7 +195,7 @@ abstract class OutputRecord * Since MAC's doFinal() is called for every SSL/TLS packet, it's * not necessary to do the same with MAC's. */ - writeCipher.dispose(); + disposeWriteCipher(); this.writeCipher = writeCipher; this.isFirstAppOutputRecord = true; @@ -219,7 +224,7 @@ abstract class OutputRecord flush(); // Dispose of any intermediate state in the underlying cipher. - writeCipher.dispose(); + disposeWriteCipher(); this.writeCipher = writeCipher; this.isFirstAppOutputRecord = true; diff --git a/src/java.base/share/classes/sun/security/ssl/ProtocolVersion.java b/src/java.base/share/classes/sun/security/ssl/ProtocolVersion.java index e4cb5637c60e1cf55cce2c10a71e069bc435ce2f..32c112a499126476b1f100b1e2f993c7316abb75 100644 --- a/src/java.base/share/classes/sun/security/ssl/ProtocolVersion.java +++ b/src/java.base/share/classes/sun/security/ssl/ProtocolVersion.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 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 @@ -290,7 +290,7 @@ enum ProtocolVersion { ProtocolVersion pv = ProtocolVersion.nameOf(pn); if (pv == null) { throw new IllegalArgumentException( - "Unsupported protocol" + pn); + "Unsupported protocol: " + pn); } pvs.add(pv); diff --git a/src/java.base/share/classes/sun/security/ssl/SSLBasicKeyDerivation.java b/src/java.base/share/classes/sun/security/ssl/SSLBasicKeyDerivation.java index 7f6934006379551ad9c1fc220f71e67d78c284be..20fc711259379d262fcf866c30d425a23487b6bc 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLBasicKeyDerivation.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLBasicKeyDerivation.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -52,8 +52,7 @@ final class SSLBasicKeyDerivation implements SSLKeyDerivation { return hkdf.expand(secret, hkdfInfo, ((SecretSizeSpec)keySpec).length, algorithm); } catch (GeneralSecurityException gse) { - throw (SSLHandshakeException) new SSLHandshakeException( - "Could not generate secret").initCause(gse); + throw new SSLHandshakeException("Could not generate secret", gse); } } diff --git a/src/java.base/share/classes/sun/security/ssl/SSLCipher.java b/src/java.base/share/classes/sun/security/ssl/SSLCipher.java index 26e7ea2225d749fe11e5533b91c3d0398a3878d2..d44fb11014e1f202ef90342af66612065f16d71d 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLCipher.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLCipher.java @@ -39,6 +39,7 @@ import java.security.spec.AlgorithmParameterSpec; import java.util.AbstractMap.SimpleImmutableEntry; import java.util.Arrays; import java.util.HashMap; +import java.util.Locale; import java.util.Map; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; @@ -430,7 +431,8 @@ enum SSLCipher { for (String entry : propvalue) { int index; // If this is not a UsageLimit, goto to next entry. - String[] values = entry.trim().toUpperCase().split(" "); + String[] values = + entry.trim().toUpperCase(Locale.ENGLISH).split(" "); if (values[1].contains(tag[0])) { index = 0; @@ -1865,10 +1867,10 @@ enum SSLCipher { this.random = random; keyLimitCountdown = cipherLimits.getOrDefault( - algorithm.toUpperCase() + ":" + tag[0], 0L); + algorithm.toUpperCase(Locale.ENGLISH) + ":" + tag[0], 0L); if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { SSLLogger.fine("KeyLimit read side: algorithm = " + - algorithm.toUpperCase() + ":" + tag[0] + + algorithm + ":" + tag[0] + "\ncountdown value = " + keyLimitCountdown); } if (keyLimitCountdown > 0) { @@ -2019,10 +2021,10 @@ enum SSLCipher { this.random = random; keyLimitCountdown = cipherLimits.getOrDefault( - algorithm.toUpperCase() + ":" + tag[0], 0L); + algorithm.toUpperCase(Locale.ENGLISH) + ":" + tag[0], 0L); if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { SSLLogger.fine("KeyLimit write side: algorithm = " - + algorithm.toUpperCase() + ":" + tag[0] + + + algorithm + ":" + tag[0] + "\ncountdown value = " + keyLimitCountdown); } if (keyLimitCountdown > 0) { @@ -2279,9 +2281,9 @@ enum SSLCipher { this.random = random; keyLimitCountdown = cipherLimits.getOrDefault( - algorithm.toUpperCase() + ":" + tag[0], 0L); + algorithm.toUpperCase(Locale.ENGLISH) + ":" + tag[0], 0L); if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { - SSLLogger.fine("algorithm = " + algorithm.toUpperCase() + + SSLLogger.fine("algorithm = " + algorithm + ":" + tag[0] + "\ncountdown value = " + keyLimitCountdown); } @@ -2561,9 +2563,9 @@ enum SSLCipher { this.random = random; keyLimitCountdown = cipherLimits.getOrDefault( - algorithm.toUpperCase() + ":" + tag[0], 0L); + algorithm.toUpperCase(Locale.ENGLISH) + ":" + tag[0], 0L); if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { - SSLLogger.fine("algorithm = " + algorithm.toUpperCase() + + SSLLogger.fine("algorithm = " + algorithm + ":" + tag[0] + "\ncountdown value = " + keyLimitCountdown); } diff --git a/src/java.base/share/classes/sun/security/ssl/SSLConfiguration.java b/src/java.base/share/classes/sun/security/ssl/SSLConfiguration.java index 04ebefa6364403cd31d5b5f332b86ce9f91f31d5..056f00a5a3c369ba0a5311d72d7923c5c2d0692d 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLConfiguration.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -29,11 +29,7 @@ import java.security.AccessControlContext; import java.security.AccessController; import java.security.AlgorithmConstraints; import java.security.NoSuchAlgorithmException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; +import java.util.*; import java.util.function.BiFunction; import javax.crypto.KeyGenerator; import javax.net.ssl.HandshakeCompletedListener; @@ -66,7 +62,7 @@ final class SSLConfiguration implements Cloneable { // The configured signature schemes for "signature_algorithms" and // "signature_algorithms_cert" extensions - List signatureSchemes; + String[] signatureSchemes; // the maximum protocol version of enabled protocols ProtocolVersion maximumProtocolVersion; @@ -97,7 +93,7 @@ final class SSLConfiguration implements Cloneable { static final boolean allowLegacyMasterSecret = Utilities.getBooleanProperty("jdk.tls.allowLegacyMasterSecret", true); - // Allow full handshake without Extended Master Secret extension. + // Use TLS1.3 middlebox compatibility mode. static final boolean useCompatibilityMode = Utilities.getBooleanProperty( "jdk.tls.client.useCompatibilityMode", true); @@ -204,6 +200,7 @@ final class SSLConfiguration implements Cloneable { params.setUseCipherSuitesOrder(this.preferLocalCipherSuites); params.setEnableRetransmissions(this.enableRetransmissions); params.setMaximumPacketSize(this.maximumPacketSize); + params.setSignatureSchemes(this.signatureSchemes); return params; } @@ -261,6 +258,13 @@ final class SSLConfiguration implements Cloneable { this.applicationProtocols = sa; } // otherwise, use the default values + String[] ss = params.getSignatureSchemes(); + if (ss != null) { + // Note if 'ss' is empty, then no signature schemes should be + // specified over the connections. + this.signatureSchemes = ss; + } // Otherwise, use the default values + this.preferLocalCipherSuites = params.getUseCipherSuitesOrder(); this.enableRetransmissions = params.getEnableRetransmissions(); this.maximumPacketSize = params.getMaximumPacketSize(); @@ -403,10 +407,15 @@ final class SSLConfiguration implements Cloneable { void toggleClientMode() { this.isClientMode ^= true; - // reset the signature schemes - this.signatureSchemes = isClientMode ? - CustomizedClientSignatureSchemes.signatureSchemes : - CustomizedServerSignatureSchemes.signatureSchemes; + // Reset the signature schemes, if it was configured with SSLParameters. + if (Arrays.equals(signatureSchemes, + CustomizedClientSignatureSchemes.signatureSchemes) || + Arrays.equals(signatureSchemes, + CustomizedServerSignatureSchemes.signatureSchemes)) { + this.signatureSchemes = isClientMode ? + CustomizedClientSignatureSchemes.signatureSchemes : + CustomizedServerSignatureSchemes.signatureSchemes; + } } @Override @@ -434,7 +443,7 @@ final class SSLConfiguration implements Cloneable { // // See Effective Java Second Edition: Item 71. private static final class CustomizedClientSignatureSchemes { - private static final List signatureSchemes = + private static final String[] signatureSchemes = getCustomizedSignatureScheme("jdk.tls.client.SignatureSchemes"); } @@ -442,7 +451,7 @@ final class SSLConfiguration implements Cloneable { // // See Effective Java Second Edition: Item 71. private static final class CustomizedServerSignatureSchemes { - private static final List signatureSchemes = + private static final String[] signatureSchemes = getCustomizedSignatureScheme("jdk.tls.server.SignatureSchemes"); } @@ -450,14 +459,12 @@ final class SSLConfiguration implements Cloneable { * Get the customized signature schemes specified by the given * system property. */ - private static List getCustomizedSignatureScheme( - String propertyName) { - + private static String[] getCustomizedSignatureScheme(String propertyName) { String property = GetPropertyAction.privilegedGetProperty(propertyName); if (SSLLogger.isOn && SSLLogger.isOn("ssl,sslctx")) { SSLLogger.fine( "System property " + propertyName + " is set to '" + - property + "'"); + property + "'"); } if (property != null && !property.isEmpty()) { // remove double quote marks from beginning/end of the property @@ -469,31 +476,34 @@ final class SSLConfiguration implements Cloneable { if (property != null && !property.isEmpty()) { String[] signatureSchemeNames = property.split(","); - List signatureSchemes = - new ArrayList<>(signatureSchemeNames.length); - for (int i = 0; i < signatureSchemeNames.length; i++) { - signatureSchemeNames[i] = signatureSchemeNames[i].trim(); - if (signatureSchemeNames[i].isEmpty()) { + List signatureSchemes = + new ArrayList<>(signatureSchemeNames.length); + for (String schemeName : signatureSchemeNames) { + schemeName = schemeName.trim(); + if (schemeName.isEmpty()) { continue; } - SignatureScheme scheme = - SignatureScheme.nameOf(signatureSchemeNames[i]); + // Check the availability + SignatureScheme scheme = SignatureScheme.nameOf(schemeName); if (scheme != null && scheme.isAvailable) { - signatureSchemes.add(scheme); + signatureSchemes.add(schemeName); } else { if (SSLLogger.isOn && SSLLogger.isOn("ssl,sslctx")) { SSLLogger.fine( - "The current installed providers do not " + - "support signature scheme: " + - signatureSchemeNames[i]); + "The current installed providers do not " + + "support signature scheme: " + schemeName); } } } - return signatureSchemes; + if (!signatureSchemes.isEmpty()) { + return signatureSchemes.toArray(new String[0]); + } } - return Collections.emptyList(); + // Note that if the System Property value is not defined (JDK + // default value) or empty, the provider-specific default is used. + return null; } } diff --git a/src/java.base/share/classes/sun/security/ssl/SSLEngineImpl.java b/src/java.base/share/classes/sun/security/ssl/SSLEngineImpl.java index ca4a80c5a5c550706ab85692df6c7e5170f3a62e..1db9ba8d86bad0a3db0a96b80a8b59f48f425dba 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLEngineImpl.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLEngineImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -1167,17 +1167,13 @@ final class SSLEngineImpl extends SSLEngine implements SSLTransport { if (taskThrown instanceof RuntimeException) { throw new RuntimeException(msg, taskThrown); } else if (taskThrown instanceof SSLHandshakeException) { - return (SSLHandshakeException) - new SSLHandshakeException(msg).initCause(taskThrown); + return new SSLHandshakeException(msg, taskThrown); } else if (taskThrown instanceof SSLKeyException) { - return (SSLKeyException) - new SSLKeyException(msg).initCause(taskThrown); + return new SSLKeyException(msg, taskThrown); } else if (taskThrown instanceof SSLPeerUnverifiedException) { - return (SSLPeerUnverifiedException) - new SSLPeerUnverifiedException(msg).initCause(taskThrown); + return new SSLPeerUnverifiedException(msg, taskThrown); } else if (taskThrown instanceof SSLProtocolException) { - return (SSLProtocolException) - new SSLProtocolException(msg).initCause(taskThrown); + return new SSLProtocolException(msg, taskThrown); } else if (taskThrown instanceof SSLException) { return (SSLException)taskThrown; } else { diff --git a/src/java.base/share/classes/sun/security/ssl/SSLEngineInputRecord.java b/src/java.base/share/classes/sun/security/ssl/SSLEngineInputRecord.java index 31abe94e9a1122a9ae71a53e6da9aa7960e28d85..dc957ca141949a99d2c155cd445895091724f4cb 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLEngineInputRecord.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLEngineInputRecord.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 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 @@ -242,8 +242,7 @@ final class SSLEngineInputRecord extends InputRecord implements SSLRecord { } catch (BadPaddingException bpe) { throw bpe; } catch (GeneralSecurityException gse) { - throw (SSLProtocolException)(new SSLProtocolException( - "Unexpected exception")).initCause(gse); + throw new SSLProtocolException("Unexpected exception", gse); } finally { // consume a complete record packet.limit(srcLim); @@ -358,7 +357,6 @@ final class SSLEngineInputRecord extends InputRecord implements SSLRecord { // The packet should be a complete record. // int srcPos = packet.position(); - int srcLim = packet.limit(); byte firstByte = packet.get(srcPos); byte thirdByte = packet.get(srcPos + 2); diff --git a/src/java.base/share/classes/sun/security/ssl/SSLEngineOutputRecord.java b/src/java.base/share/classes/sun/security/ssl/SSLEngineOutputRecord.java index 5de047dfcffed72f01277140bd5cf8624badb20f..63eff56b4b641e28dbc52357bc85facada05adac 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLEngineOutputRecord.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLEngineOutputRecord.java @@ -151,6 +151,15 @@ final class SSLEngineOutputRecord extends OutputRecord implements SSLRecord { fragmenter.queueUpChangeCipherSpec(); } + @Override + void disposeWriteCipher() { + if (fragmenter == null) { + writeCipher.dispose(); + } else { + fragmenter.queueUpCipherDispose(); + } + } + @Override void encodeV2NoCipher() throws IOException { isTalkingToV2 = true; @@ -361,6 +370,7 @@ final class SSLEngineOutputRecord extends OutputRecord implements SSLRecord { byte majorVersion; byte minorVersion; SSLWriteCipher encodeCipher; + boolean disposeCipher; byte[] fragment; } @@ -422,6 +432,15 @@ final class SSLEngineOutputRecord extends OutputRecord implements SSLRecord { handshakeMemos.add(memo); } + void queueUpCipherDispose() { + RecordMemo lastMemo = handshakeMemos.peekLast(); + if (lastMemo != null) { + lastMemo.disposeCipher = true; + } else { + writeCipher.dispose(); + } + } + Ciphertext acquireCiphertext(ByteBuffer dstBuf) throws IOException { if (isEmpty()) { return null; @@ -521,6 +540,9 @@ final class SSLEngineOutputRecord extends OutputRecord implements SSLRecord { dstPos, dstLim, headerSize, ProtocolVersion.valueOf(memo.majorVersion, memo.minorVersion)); + if (memo.disposeCipher) { + memo.encodeCipher.dispose(); + } if (SSLLogger.isOn && SSLLogger.isOn("packet")) { ByteBuffer temporary = dstBuf.duplicate(); diff --git a/src/java.base/share/classes/sun/security/ssl/SSLSecretDerivation.java b/src/java.base/share/classes/sun/security/ssl/SSLSecretDerivation.java index a7ba9a5e566a5aeabfae7e0083d63ec4d42e4807..ff13948a67c20b65b4b5c2e48112ff17b3fd2b6e 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLSecretDerivation.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLSecretDerivation.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -113,8 +113,7 @@ final class SSLSecretDerivation implements SSLKeyDerivation { HKDF hkdf = new HKDF(hashAlg.name); return hkdf.expand(secret, hkdfInfo, hashAlg.hashLength, algorithm); } catch (GeneralSecurityException gse) { - throw (SSLHandshakeException) new SSLHandshakeException( - "Could not generate secret").initCause(gse); + throw new SSLHandshakeException("Could not generate secret", gse); } } diff --git a/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java b/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java index e55419d70eef683e06984b4adeffcdbbadf0fc75..68fb386020339c39e6d9d608223714659b59552a 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 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 @@ -107,6 +107,11 @@ public final class SSLSocketImpl private static final boolean trustNameService = Utilities.getBooleanProperty("jdk.tls.trustNameService", false); + /* + * Default timeout to skip bytes from the open socket + */ + private static final int DEFAULT_SKIP_TIMEOUT = 1; + /** * Package-private constructor used to instantiate an unconnected * socket. @@ -1704,19 +1709,13 @@ public final class SSLSocketImpl private Plaintext handleEOF(EOFException eofe) throws IOException { if (requireCloseNotify || conContext.handshakeContext != null) { - SSLException ssle; if (conContext.handshakeContext != null) { - ssle = new SSLHandshakeException( - "Remote host terminated the handshake"); + throw new SSLHandshakeException( + "Remote host terminated the handshake", eofe); } else { - ssle = new SSLProtocolException( - "Remote host terminated the connection"); - } - - if (eofe != null) { - ssle.initCause(eofe); + throw new SSLProtocolException( + "Remote host terminated the connection", eofe); } - throw ssle; } else { // treat as if we had received a close_notify conContext.isInputCloseNotified = true; @@ -1781,9 +1780,21 @@ public final class SSLSocketImpl if (conContext.inputRecord instanceof SSLSocketInputRecord inputRecord && isConnected) { if (appInput.readLock.tryLock()) { + int soTimeout = getSoTimeout(); try { + // deplete could hang on the skip operation + // in case of infinite socket read timeout. + // Change read timeout to avoid deadlock. + // This workaround could be replaced later + // with the right synchronization + if (soTimeout == 0) + setSoTimeout(DEFAULT_SKIP_TIMEOUT); inputRecord.deplete(false); + } catch (java.net.SocketTimeoutException stEx) { + // skip timeout exception during deplete } finally { + if (soTimeout == 0) + setSoTimeout(soTimeout); appInput.readLock.unlock(); } } diff --git a/src/java.base/share/classes/sun/security/ssl/SSLSocketInputRecord.java b/src/java.base/share/classes/sun/security/ssl/SSLSocketInputRecord.java index da189f4f3fff342abd2e53a47f642d25c22507b7..7afacb0f3d77c96e7d233428a54d1b0f086e1a93 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLSocketInputRecord.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLSocketInputRecord.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2022, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2020, Azul Systems, Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -263,8 +263,7 @@ final class SSLSocketInputRecord extends InputRecord implements SSLRecord { } catch (BadPaddingException bpe) { throw bpe; } catch (GeneralSecurityException gse) { - throw (SSLProtocolException)(new SSLProtocolException( - "Unexpected exception")).initCause(gse); + throw new SSLProtocolException("Unexpected exception", gse); } if (contentType != ContentType.HANDSHAKE.id && diff --git a/src/java.base/share/classes/sun/security/ssl/SSLSocketOutputRecord.java b/src/java.base/share/classes/sun/security/ssl/SSLSocketOutputRecord.java index 07a4093b12a9caf28d4b65ba8c18aaf59adec381..3b0473d4eb0ced261ea7101a68f65ccce103d8c6 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLSocketOutputRecord.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLSocketOutputRecord.java @@ -243,6 +243,11 @@ final class SSLSocketOutputRecord extends OutputRecord implements SSLRecord { } } + @Override + void disposeWriteCipher() { + writeCipher.dispose(); + } + @Override public void flush() throws IOException { recordLock.lock(); diff --git a/src/java.base/share/classes/sun/security/ssl/SSLTrafficKeyDerivation.java b/src/java.base/share/classes/sun/security/ssl/SSLTrafficKeyDerivation.java index ac39cbb16fbd930d0befc33522127fbd2f6dc11e..6e890c8818dc05228f50052cc5284fb707283b7b 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLTrafficKeyDerivation.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLTrafficKeyDerivation.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -154,8 +154,8 @@ enum SSLTrafficKeyDerivation implements SSLKeyDerivationGenerator { ks.getKeyLength(cs), ks.getAlgorithm(cs, algorithm)); } catch (GeneralSecurityException gse) { - throw (SSLHandshakeException)(new SSLHandshakeException( - "Could not generate secret").initCause(gse)); + throw new SSLHandshakeException( + "Could not generate secret", gse); } } diff --git a/src/java.base/share/classes/sun/security/ssl/ServerHello.java b/src/java.base/share/classes/sun/security/ssl/ServerHello.java index 193a71cde861ebaac056b74caa2650051ce33a39..efbe860bfd6be6fc64dfe73a31c19e95039ad6c2 100644 --- a/src/java.base/share/classes/sun/security/ssl/ServerHello.java +++ b/src/java.base/share/classes/sun/security/ssl/ServerHello.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -1205,8 +1205,7 @@ final class ServerHello { hc.handshakeKeyDerivation = new SSLSecretDerivation(hc, earlySecret); } catch (GeneralSecurityException gse) { - throw (SSLHandshakeException) new SSLHandshakeException( - "Could not generate secret").initCause(gse); + throw new SSLHandshakeException("Could not generate secret", gse); } } diff --git a/src/java.base/share/classes/sun/security/ssl/ServerNameExtension.java b/src/java.base/share/classes/sun/security/ssl/ServerNameExtension.java index 74f38bf5b56c448f84d0ca3bef6143c8e17b6404..eaf154af3bb4c989df54cc609d7d14f0f570039e 100644 --- a/src/java.base/share/classes/sun/security/ssl/ServerNameExtension.java +++ b/src/java.base/share/classes/sun/security/ssl/ServerNameExtension.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -135,9 +135,8 @@ final class ServerNameExtension { nameType + "), name=" + (new String(encoded, StandardCharsets.UTF_8)) + ", value={" + - Utilities.toHexString(encoded) + "}"); - throw hc.conContext.fatal(Alert.ILLEGAL_PARAMETER, - (SSLProtocolException)spe.initCause(iae)); + Utilities.toHexString(encoded) + "}", iae); + throw hc.conContext.fatal(Alert.ILLEGAL_PARAMETER, spe); } } else { try { @@ -146,9 +145,8 @@ final class ServerNameExtension { SSLProtocolException spe = new SSLProtocolException( "Illegal server name, type=(" + nameType + "), value={" + - Utilities.toHexString(encoded) + "}"); - throw hc.conContext.fatal(Alert.ILLEGAL_PARAMETER, - (SSLProtocolException)spe.initCause(iae)); + Utilities.toHexString(encoded) + "}", iae); + throw hc.conContext.fatal(Alert.ILLEGAL_PARAMETER, spe); } } diff --git a/src/java.base/share/classes/sun/security/ssl/SignatureScheme.java b/src/java.base/share/classes/sun/security/ssl/SignatureScheme.java index 706cb4371d3da0888efe089f11e9edd4f7923202..87feda0e83bee8a3b85eec0d1a8c829ef9168988 100644 --- a/src/java.base/share/classes/sun/security/ssl/SignatureScheme.java +++ b/src/java.base/share/classes/sun/security/ssl/SignatureScheme.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -181,7 +181,7 @@ enum SignatureScheme { "anonymous", "rsa", "dsa", "ecdsa", }; - static enum SigAlgParamSpec { // support RSASSA-PSS only now + enum SigAlgParamSpec { // support RSASSA-PSS only now RSA_PSS_SHA256 ("SHA-256", 32), RSA_PSS_SHA384 ("SHA-384", 48), RSA_PSS_SHA512 ("SHA-512", 64); @@ -224,13 +224,13 @@ enum SignatureScheme { Collections.unmodifiableSet(EnumSet.of(CryptoPrimitive.SIGNATURE)); - private SignatureScheme(int id, String name, + SignatureScheme(int id, String name, String algorithm, String keyAlgorithm, ProtocolVersion[] supportedProtocols) { this(id, name, algorithm, keyAlgorithm, -1, supportedProtocols); } - private SignatureScheme(int id, String name, + SignatureScheme(int id, String name, String algorithm, String keyAlgorithm, int minimalKeySize, ProtocolVersion[] supportedProtocols) { @@ -238,7 +238,7 @@ enum SignatureScheme { null, minimalKeySize, supportedProtocols); } - private SignatureScheme(int id, String name, + SignatureScheme(int id, String name, String algorithm, String keyAlgorithm, SigAlgParamSpec signAlgParamSpec, int minimalKeySize, ProtocolVersion[] supportedProtocols) { @@ -247,7 +247,7 @@ enum SignatureScheme { supportedProtocols, supportedProtocols); } - private SignatureScheme(int id, String name, + SignatureScheme(int id, String name, String algorithm, String keyAlgorithm, NamedGroup namedGroup, ProtocolVersion[] supportedProtocols) { @@ -256,7 +256,7 @@ enum SignatureScheme { supportedProtocols, supportedProtocols); } - private SignatureScheme(int id, String name, + SignatureScheme(int id, String name, String algorithm, String keyAlgorithm, SigAlgParamSpec signAlgParams, NamedGroup namedGroup, int minimalKeySize, @@ -376,15 +376,10 @@ enum SignatureScheme { List activeProtocols) { List supported = new LinkedList<>(); - // If config.signatureSchemes is non-empty then it means that - // it was defined by a System property. Per - // SSLConfiguration.getCustomizedSignatureScheme() the list will - // only contain schemes that are in the enum. - // Otherwise, use the enum constants (converted to a List). List schemesToCheck = - config.signatureSchemes.isEmpty() ? + config.signatureSchemes == null ? Arrays.asList(SignatureScheme.values()) : - config.signatureSchemes; + namesOfAvailable(config.signatureSchemes); for (SignatureScheme ss: schemesToCheck) { if (!ss.isAvailable) { @@ -437,8 +432,8 @@ enum SignatureScheme { } } else if (ss.isAvailable && ss.supportedProtocols.contains(protocolVersion) && - (config.signatureSchemes.isEmpty() || - config.signatureSchemes.contains(ss)) && + (config.signatureSchemes == null || + Utilities.contains(config.signatureSchemes, ss.name)) && ss.isPermitted(constraints)) { supported.add(ss); } else { @@ -563,6 +558,33 @@ enum SignatureScheme { return new String[0]; } + private static List namesOfAvailable( + String[] signatureSchemes) { + + if (signatureSchemes == null || signatureSchemes.length == 0) { + return Collections.emptyList(); + } + + List sss = new ArrayList<>(signatureSchemes.length); + for (String ss : signatureSchemes) { + SignatureScheme scheme = SignatureScheme.nameOf(ss); + if (scheme == null || !scheme.isAvailable) { + if (SSLLogger.isOn && + SSLLogger.isOn("ssl,handshake,verbose")) { + SSLLogger.finest( + "Ignore the signature algorithm (" + ss + + "), unsupported or unavailable"); + } + + continue; + } + + sss.add(scheme); + } + + return sss; + } + // This method is used to get the signature instance of this signature // scheme for the specific public key. Unlike getSigner(), the exception // is bubbled up. If the public key does not support this signature diff --git a/src/java.base/share/classes/sun/security/ssl/SupportedGroupsExtension.java b/src/java.base/share/classes/sun/security/ssl/SupportedGroupsExtension.java index 94ff8801fab184d207cc50890a28171281ae1c0f..3cf357254aa7a5a30b4f009eaeb2f664d9ae02bc 100644 --- a/src/java.base/share/classes/sun/security/ssl/SupportedGroupsExtension.java +++ b/src/java.base/share/classes/sun/security/ssl/SupportedGroupsExtension.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -112,7 +112,7 @@ final class SupportedGroupsExtension { @Override public String toString() { MessageFormat messageFormat = new MessageFormat( - "\"versions\": '['{0}']'", Locale.ENGLISH); + "\"named groups\": '['{0}']'", Locale.ENGLISH); if (namedGroupsIds == null || namedGroupsIds.length == 0) { Object[] messageFields = { diff --git a/src/java.base/share/classes/sun/security/ssl/Utilities.java b/src/java.base/share/classes/sun/security/ssl/Utilities.java index 19fe784e0cae05d207030dd46d98c6729385d455..441f978c84f23b5e1b079d11b8578a1981a21221 100644 --- a/src/java.base/share/classes/sun/security/ssl/Utilities.java +++ b/src/java.base/share/classes/sun/security/ssl/Utilities.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -101,14 +101,19 @@ final class Utilities { * not look like a FQDN */ private static SNIHostName rawToSNIHostName(String hostname) { - SNIHostName sniHostName = null; + // Is it a Fully-Qualified Domain Names (FQDN) ending with a dot? + if (hostname != null && hostname.endsWith(".")) { + // Remove the ending dot, which is not allowed in SNIHostName. + hostname = hostname.substring(0, hostname.length() - 1); + } + if (hostname != null && hostname.indexOf('.') > 0 && !hostname.endsWith(".") && !IPAddressUtil.isIPv4LiteralAddress(hostname) && !IPAddressUtil.isIPv6LiteralAddress(hostname)) { try { - sniHostName = new SNIHostName(hostname); + return new SNIHostName(hostname); } catch (IllegalArgumentException iae) { // don't bother to handle illegal host_name if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { @@ -118,7 +123,7 @@ final class Utilities { } } - return sniHostName; + return null; } /** @@ -224,6 +229,16 @@ final class Utilities { } } + static boolean contains(T[] array, T item) { + for (T t : array) { + if (item.equals(t)) { + return true; + } + } + + return false; + } + private static void swap(byte[] arr, int i, int j) { byte tmp = arr[i]; arr[i] = arr[j]; diff --git a/src/java.base/share/classes/sun/security/ssl/X509KeyManagerImpl.java b/src/java.base/share/classes/sun/security/ssl/X509KeyManagerImpl.java index c5bc20521255066acb7592d37b2e8dc6d645e26a..120f6b9938ce4627208ad25e333b77fc2016e897 100644 --- a/src/java.base/share/classes/sun/security/ssl/X509KeyManagerImpl.java +++ b/src/java.base/share/classes/sun/security/ssl/X509KeyManagerImpl.java @@ -382,15 +382,13 @@ final class X509KeyManagerImpl extends X509ExtendedKeyManager issuerSet, false, checkType, constraints, requestedServerNames, idAlgorithm); if (results != null) { - // the results will either be a single perfect match - // or 1 or more imperfect matches - // if it's a perfect match, return immediately - EntryStatus status = results.get(0); - if (status.checkResult == CheckResult.OK) { - if (SSLLogger.isOn && SSLLogger.isOn("keymanager")) { - SSLLogger.fine("KeyMgr: choosing key: " + status); + for (EntryStatus status : results) { + if (status.checkResult == CheckResult.OK) { + if (SSLLogger.isOn && SSLLogger.isOn("keymanager")) { + SSLLogger.fine("KeyMgr: choosing key: " + status); + } + return makeAlias(status); } - return makeAlias(status); } if (allResults == null) { allResults = new ArrayList(); diff --git a/src/java.base/share/classes/sun/security/ssl/X509TrustManagerImpl.java b/src/java.base/share/classes/sun/security/ssl/X509TrustManagerImpl.java index 63651db53c36bbb7df7adf4b7f83c9daffc1a6b1..5b18641b3adc49477357952f348c19b54c93b0cb 100644 --- a/src/java.base/share/classes/sun/security/ssl/X509TrustManagerImpl.java +++ b/src/java.base/share/classes/sun/security/ssl/X509TrustManagerImpl.java @@ -404,6 +404,12 @@ final class X509TrustManagerImpl extends X509ExtendedTrustManager boolean identifiable = false; String peerHost = session.getPeerHost(); + // Is it a Fully-Qualified Domain Names (FQDN) ending with a dot? + if (peerHost != null && peerHost.endsWith(".")) { + // Remove the ending dot, which is not allowed in SNIHostName. + peerHost = peerHost.substring(0, peerHost.length() - 1); + } + if (!checkClientTrusted) { List sniNames = getRequestedServerNames(session); String sniHostName = getHostNameInSNI(sniNames); diff --git a/src/java.base/share/classes/sun/security/timestamp/HttpTimestamper.java b/src/java.base/share/classes/sun/security/timestamp/HttpTimestamper.java index cba296c6b97e64e8bfc8b2e9cbcdd818615c0909..03070fab053b7c0b3f574992dfbb5b8fbb52f9b0 100644 --- a/src/java.base/share/classes/sun/security/timestamp/HttpTimestamper.java +++ b/src/java.base/share/classes/sun/security/timestamp/HttpTimestamper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -30,7 +30,6 @@ import java.io.DataOutputStream; import java.io.EOFException; import java.io.IOException; import java.net.URI; -import java.net.URL; import java.net.HttpURLConnection; import java.util.*; @@ -112,9 +111,7 @@ public class HttpTimestamper implements Timestamper { connection.connect(); // No HTTP authentication is performed // Send the request - DataOutputStream output = null; - try { - output = new DataOutputStream(connection.getOutputStream()); + try (var output = new DataOutputStream(connection.getOutputStream())) { byte[] request = tsQuery.encode(); output.write(request, 0, request.length); output.flush(); @@ -122,17 +119,11 @@ public class HttpTimestamper implements Timestamper { debug.println("sent timestamp query (length=" + request.length + ")"); } - } finally { - if (output != null) { - output.close(); - } } // Receive the reply - BufferedInputStream input = null; byte[] replyBuffer = null; - try { - input = new BufferedInputStream(connection.getInputStream()); + try (var input = new BufferedInputStream(connection.getInputStream())) { if (debug != null) { String header = connection.getHeaderField(0); debug.println(header); @@ -157,10 +148,6 @@ public class HttpTimestamper implements Timestamper { debug.println("received timestamp response (length=" + replyBuffer.length + ")"); } - } finally { - if (input != null) { - input.close(); - } } return new TSResponse(replyBuffer); } diff --git a/src/java.base/share/classes/sun/security/tools/KeyStoreUtil.java b/src/java.base/share/classes/sun/security/tools/KeyStoreUtil.java index 6c7cc402bf71da645597a3e1e3165f4a6b1eb34f..6095bb914721b435fcdc9cde46299c0fc7e5fd65 100644 --- a/src/java.base/share/classes/sun/security/tools/KeyStoreUtil.java +++ b/src/java.base/share/classes/sun/security/tools/KeyStoreUtil.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -225,7 +225,9 @@ public class KeyStoreUtil { List result = new ArrayList<>(); Properties p = new Properties(); - p.load(new FileInputStream(file)); + try (FileInputStream is = new FileInputStream(file)) { + p.load(is); + } String s = p.getProperty(tool + ".all"); if (s != null) { diff --git a/src/java.base/share/classes/sun/security/tools/keytool/Main.java b/src/java.base/share/classes/sun/security/tools/keytool/Main.java index 4d0b92fff00197990e4e0cf141164412f086a1e4..462606c7f84c28176c44a0f549b6c410c85f677a 100644 --- a/src/java.base/share/classes/sun/security/tools/keytool/Main.java +++ b/src/java.base/share/classes/sun/security/tools/keytool/Main.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -31,15 +31,17 @@ import java.nio.file.Path; import java.security.*; import java.security.cert.Certificate; import java.security.cert.CertificateFactory; +import java.security.cert.CertPathValidatorException; +import java.security.cert.CertPathValidatorException.BasicReason; import java.security.cert.CertStoreException; import java.security.cert.CRL; import java.security.cert.X509Certificate; import java.security.cert.CertificateException; +import java.security.cert.CertificateParsingException; +import java.security.cert.TrustAnchor; import java.security.cert.URICertStoreParameters; -import java.security.interfaces.ECKey; -import java.security.interfaces.EdECKey; import java.security.spec.ECParameterSpec; import java.text.Collator; import java.text.MessageFormat; @@ -60,6 +62,7 @@ import javax.security.auth.x500.X500Principal; import java.util.Base64; import sun.security.pkcs12.PKCS12KeyStore; +import sun.security.provider.certpath.CertPathConstraintsParameters; import sun.security.util.ECKeySizeParameterSpec; import sun.security.util.KeyUtil; import sun.security.util.NamedCurve; @@ -83,6 +86,7 @@ import sun.security.tools.KeyStoreUtil; import sun.security.tools.PathList; import sun.security.util.DerValue; import sun.security.util.Pem; +import sun.security.validator.Validator; import sun.security.x509.*; import static java.security.KeyStore.*; @@ -178,6 +182,8 @@ public final class Main { // Warnings on weak algorithms etc private List weakWarnings = new ArrayList<>(); + private Set trustedCerts = new HashSet<>(); + private static final DisabledAlgorithmConstraints DISABLED_CHECK = new DisabledAlgorithmConstraints( DisabledAlgorithmConstraints.PROPERTY_CERTPATH_DISABLED_ALGS); @@ -816,9 +822,7 @@ public final class Main { if (providerClasses != null) { ClassLoader cl = null; if (pathlist != null) { - String path = null; - path = PathList.appendPath( - path, System.getProperty("java.class.path")); + String path = System.getProperty("java.class.path"); path = PathList.appendPath( path, System.getProperty("env.class.path")); path = PathList.appendPath(path, pathlist); @@ -1118,6 +1122,7 @@ public final class Main { } } + KeyStore cakstore = buildTrustedCerts(); // -trustcacerts can be specified on -importcert, -printcert or -printcrl. // Reset it so that warnings on CA cert will remain for other command. if (command != IMPORTCERT && command != PRINTCERT @@ -1126,7 +1131,13 @@ public final class Main { } if (trustcacerts) { - caks = KeyStoreUtil.getCacertsKeyStore(); + if (cakstore != null) { + caks = cakstore; + } else { + // try to load cacerts again, and let exception propagate + // if it cannot be loaded + caks = KeyStoreUtil.getCacertsKeyStore(); + } } // Perform the specified command @@ -1273,6 +1284,7 @@ public final class Main { kssave = true; } else if (command == LIST) { if (storePass == null + && !protectedPath && !KeyStoreUtil.isWindowsKeyStore(storetype) && !isPasswordlessKeyStore) { printNoIntegrityWarning(); @@ -1473,10 +1485,10 @@ public final class Main { if (s == null) break; // OpenSSL does not use NEW //if (s.startsWith("-----BEGIN NEW CERTIFICATE REQUEST-----")) { - if (s.startsWith("-----BEGIN") && s.indexOf("REQUEST") >= 0) { + if (s.startsWith("-----BEGIN") && s.contains("REQUEST")) { canRead = true; //} else if (s.startsWith("-----END NEW CERTIFICATE REQUEST-----")) { - } else if (s.startsWith("-----END") && s.indexOf("REQUEST") >= 0) { + } else if (s.startsWith("-----END") && s.contains("REQUEST")) { break; } else if (canRead) { sb.append(s); @@ -1485,7 +1497,9 @@ public final class Main { byte[] rawReq = Pem.decode(new String(sb)); PKCS10 req = new PKCS10(rawReq); - checkWeak(rb.getString("the.certificate.request"), req); + CertPathConstraintsParameters cpcp = new CertPathConstraintsParameters( + req.getSubjectPublicKeyInfo(), null, null, null); + checkWeakConstraint(rb.getString("the.certificate.request"), req, cpcp); info.set(X509CertInfo.KEY, new CertificateX509Key(req.getSubjectPublicKeyInfo())); info.set(X509CertInfo.SUBJECT, @@ -1542,8 +1556,11 @@ public final class Main { } } - checkWeak(rb.getString("the.issuer"), keyStore.getCertificateChain(alias)); - checkWeak(rb.getString("the.generated.certificate"), cert); + checkWeakConstraint(rb.getString("the.issuer"), + keyStore.getCertificateChain(alias)); + cpcp = buildCertPathConstraint(cert, null); + checkWeakConstraint(rb.getString("the.generated.certificate"), + cert, cpcp); } private void doGenCRL(PrintStream out) @@ -1592,7 +1609,10 @@ public final class Main { } else { out.write(crl.getEncodedInternal()); } - checkWeak(rb.getString("the.generated.crl"), crl, privateKey); + CertPathConstraintsParameters cpcp = new CertPathConstraintsParameters( + privateKey, null, null, null); + checkWeakConstraint(rb.getString("the.generated.crl"), crl, privateKey, + cpcp); } /** @@ -1638,7 +1658,10 @@ public final class Main { request.encodeAndSign(subject, privKey, sigAlgName); request.print(out); - checkWeak(rb.getString("the.generated.certificate.request"), request); + CertPathConstraintsParameters cpcp = new CertPathConstraintsParameters( + request.getSubjectPublicKeyInfo(), null, null, null); + checkWeakConstraint(rb.getString("the.generated.certificate.request"), + request, cpcp); } /** @@ -1661,6 +1684,7 @@ public final class Main { throws Exception { if (storePass == null + && !protectedPath && !KeyStoreUtil.isWindowsKeyStore(storetype) && !isPasswordlessKeyStore) { printNoIntegrityWarning(); @@ -1683,7 +1707,9 @@ public final class Main { throw new Exception(form.format(source)); } dumpCert(cert, out); - checkWeak(rb.getString("the.certificate"), cert); + CertPathConstraintsParameters cpcp = + buildCertPathConstraint(cert, null); + checkWeakConstraint(rb.getString("the.certificate"), cert, cpcp); } /** @@ -1990,7 +2016,7 @@ public final class Main { ("Generating.keysize.bit.keyAlgName.key.pair.and.a.certificate.sigAlgName.issued.by.signerAlias.with.a.validity.of.validality.days.for")); Object[] source = { groupName == null ? keysize : KeyUtil.getKeySize(privKey), - fullDisplayAlgName(privKey), + KeyUtil.fullDisplayAlgName(privKey), newCert.getSigAlgName(), signerAlias, validity, @@ -2001,7 +2027,7 @@ public final class Main { ("Generating.keysize.bit.keyAlgName.key.pair.and.self.signed.certificate.sigAlgName.with.a.validity.of.validality.days.for")); Object[] source = { groupName == null ? keysize : KeyUtil.getKeySize(privKey), - fullDisplayAlgName(privKey), + KeyUtil.fullDisplayAlgName(privKey), newCert.getSigAlgName(), validity, x500Name}; @@ -2021,7 +2047,8 @@ public final class Main { } else { finalChain = new Certificate[] { newCert }; } - checkWeak(rb.getString("the.generated.certificate"), finalChain); + checkWeakConstraint(rb.getString("the.generated.certificate"), + finalChain); keyStore.setKeyEntry(alias, privKey, keyPass, finalChain); } @@ -2114,6 +2141,7 @@ public final class Main { private void doPrintEntry(String label, String alias, PrintStream out) throws Exception { + CertPathConstraintsParameters cpcp; if (keyStore.containsAlias(alias) == false) { MessageFormat form = new MessageFormat (rb.getString("Alias.alias.does.not.exist")); @@ -2170,6 +2198,10 @@ public final class Main { if (verbose || rfc || debug) { out.println(rb.getString ("Certificate.chain.length.") + chain.length); + + X509Certificate[] xcerts = convertCerts(chain); + List certs = Arrays.asList(xcerts); + TrustAnchor anchor = findTrustAnchor(certs); for (int i = 0; i < chain.length; i ++) { MessageFormat form = new MessageFormat (rb.getString("Certificate.i.1.")); @@ -2182,14 +2214,26 @@ public final class Main { } else { dumpCert(chain[i], out); } - checkWeak(label, chain[i]); + + if (i == 0 && + ((X509Certificate)chain[0]). + getBasicConstraints() == -1) { + // this is an EE + cpcp = buildCertPathConstraint((X509Certificate) chain[i], anchor); + } else { + cpcp = new CertPathConstraintsParameters( + (X509Certificate)chain[i], null, anchor, + null); + } + + checkWeakConstraint(label, chain[i], cpcp); } } else { // Print the digest of the user cert only out.println (rb.getString("Certificate.fingerprint.SHA.256.") + getCertFingerPrint("SHA-256", chain[0])); - checkWeak(label, chain); + checkWeakConstraint(label, chain); } } else { out.println(rb.getString @@ -2215,7 +2259,8 @@ public final class Main { out.println(rb.getString("Certificate.fingerprint.SHA.256.") + getCertFingerPrint("SHA-256", cert)); } - checkWeak(label, cert); + cpcp = buildCertPathConstraint((X509Certificate)cert, null); + checkWeakConstraint(label, cert, cpcp); } else { out.println(rb.getString("Unknown.Entry.Type")); } @@ -2442,7 +2487,9 @@ public final class Main { try { Certificate c = srckeystore.getCertificate(alias); if (c != null) { - checkWeak("<" + newAlias + ">", c); + CertPathConstraintsParameters cpcp = + buildCertPathConstraint((X509Certificate)c, null); + checkWeakConstraint("<" + newAlias + ">", c, cpcp); } keyStore.setEntry(newAlias, entry, pp); // Place the check so that only successful imports are blocked. @@ -2639,11 +2686,14 @@ public final class Main { issuer = verifyCRL(caks, crl); if (issuer != null) { signer = caks.getCertificate(issuer); + CertPathConstraintsParameters cpcp = + buildCertPathConstraint((X509Certificate)signer, + null); out.printf(rb.getString( "verified.by.s.in.s.weak"), issuer, "cacerts", - withWeak(signer.getPublicKey())); + withWeakConstraint(signer.getPublicKey(), cpcp)); out.println(); } } @@ -2651,11 +2701,14 @@ public final class Main { issuer = verifyCRL(keyStore, crl); if (issuer != null) { signer = keyStore.getCertificate(issuer); + CertPathConstraintsParameters cpcp = + buildCertPathConstraint((X509Certificate)signer, + null); out.printf(rb.getString( "verified.by.s.in.s.weak"), issuer, "keystore", - withWeak(signer.getPublicKey())); + withWeakConstraint(signer.getPublicKey(), cpcp)); out.println(); } } @@ -2672,7 +2725,15 @@ public final class Main { out.println(rb.getString ("STARNN")); } - checkWeak(rb.getString("the.crl"), crl, signer == null ? null : signer.getPublicKey()); + + if (signer != null) { + CertPathConstraintsParameters cpcp = + buildCertPathConstraint((X509Certificate)signer, null); + checkWeakConstraint(rb.getString("the.crl"), crl, + signer.getPublicKey(), cpcp); + } else { + checkWeak(rb.getString("the.crl"), crl, null); + } } } @@ -2718,10 +2779,12 @@ public final class Main { PKCS10 req = new PKCS10(Pem.decode(new String(sb))); PublicKey pkey = req.getSubjectPublicKeyInfo(); + CertPathConstraintsParameters cpcp = + new CertPathConstraintsParameters(pkey, null, null, null); out.printf(rb.getString("PKCS.10.with.weak"), req.getSubjectName(), pkey.getFormat(), - withWeak(pkey), + withWeakConstraint(pkey, cpcp), withWeak(req.getSigAlg())); for (PKCS10Attribute attr: req.getAttributes().getAttributes()) { ObjectIdentifier oid = attr.getAttributeId(); @@ -2745,7 +2808,12 @@ public final class Main { if (debug) { out.println(req); // Just to see more, say, public key length... } - checkWeak(rb.getString("the.certificate.request"), req); + + CertPathConstraintsParameters cpcp1 = + new CertPathConstraintsParameters( + req.getSubjectPublicKeyInfo(), null, null, null); + checkWeakConstraint(rb.getString("the.certificate.request"), req, + cpcp1); } /** @@ -2765,6 +2833,9 @@ public final class Main { throw new Exception(rb.getString("Empty.input")); } Certificate[] certs = c.toArray(new Certificate[c.size()]); + X509Certificate[] xcerts = convertCerts(certs); + List chain = Arrays.asList(xcerts); + TrustAnchor anchor = findTrustAnchor(chain); for (int i=0; i certs = signer.getSignerCertPath().getCertificates(); + @SuppressWarnings("unchecked") + List chain = + (List)certs; + TrustAnchor anchor = findTrustAnchor(chain); + CertPathConstraintsParameters cpcp; int cc = 0; for (Certificate cert: certs) { out.printf(rb.getString("Certificate.d."), ++cc); @@ -2913,16 +2999,27 @@ public final class Main { printX509Cert(x, out); } out.println(); - checkWeak(oneInManys(rb.getString( + if (cc == 0 && x.getBasicConstraints() == -1) { + // this is an EE + cpcp = buildCertPathConstraint(x, anchor); + } else { + cpcp = new CertPathConstraintsParameters( + x, null, anchor, null); + } + checkWeakConstraint(oneInManys(rb.getString( "the.certificate"), cc, certs.size(), pos, - ss.size()), x); + ss.size()), x, cpcp); } Timestamp ts = signer.getTimestamp(); if (ts != null) { out.println(rb.getString("Timestamp.")); out.println(); certs = ts.getSignerCertPath().getCertificates(); + @SuppressWarnings("unchecked") + List tschain = + (List)certs; + anchor = findTrustAnchor(tschain); cc = 0; for (Certificate cert: certs) { out.printf(rb.getString("Certificate.d."), ++cc); @@ -2935,10 +3032,18 @@ public final class Main { printX509Cert(x, out); } out.println(); - checkWeak(oneInManys(rb.getString( + if (cc == 0 && + x.getBasicConstraints() == -1) { + // this is an EE + cpcp = buildCertPathConstraint(x, anchor); + } else { + cpcp = new CertPathConstraintsParameters( + x, null, anchor, null); + } + checkWeakConstraint(oneInManys(rb.getString( "the.tsa.certificate"), cc, certs.size(), pos, - ss.size()), x); + ss.size()), x, cpcp); } } } @@ -2968,6 +3073,9 @@ public final class Main { } int i = 0; + @SuppressWarnings("unchecked") + List xcerts = (List)chain; + TrustAnchor anchor = findTrustAnchor(xcerts); for (Certificate cert : chain) { try { if (rfc) { @@ -2978,7 +3086,17 @@ public final class Main { printX509Cert((X509Certificate)cert, out); out.println(); } - checkWeak(oneInMany(rb.getString("the.certificate"), i++, chain.size()), cert); + X509Certificate x = (X509Certificate)cert; + CertPathConstraintsParameters cpcp; + if (i == 0 && x.getBasicConstraints() == -1) { + // this is an EE + cpcp = buildCertPathConstraint(x, anchor); + } else { + cpcp = new CertPathConstraintsParameters( + x, null, anchor, null); + } + checkWeakConstraint(oneInMany(rb.getString( + "the.certificate"), i++, chain.size()), x, cpcp); } catch (Exception e) { if (debug) { e.printStackTrace(); @@ -3202,8 +3320,11 @@ public final class Main { throw new Exception(rb.getString("Input.not.an.X.509.certificate")); } + CertPathConstraintsParameters cpcp = + buildCertPathConstraint(cert, null); + if (noprompt) { - checkWeak(rb.getString("the.input"), cert); + checkWeakConstraint(rb.getString("the.input"), cert, cpcp); keyStore.setCertificateEntry(alias, cert); return true; } @@ -3223,7 +3344,7 @@ public final class Main { ("Certificate.already.exists.in.keystore.under.alias.trustalias.")); Object[] source = {trustalias}; System.err.println(form.format(source)); - checkWeak(rb.getString("the.input"), cert); + checkWeakConstraint(rb.getString("the.input"), cert, cpcp); printWeakWarnings(true); reply = getYesNoReply (rb.getString("Do.you.still.want.to.add.it.no.")); @@ -3234,7 +3355,7 @@ public final class Main { ("Certificate.already.exists.in.system.wide.CA.keystore.under.alias.trustalias.")); Object[] source = {trustalias}; System.err.println(form.format(source)); - checkWeak(rb.getString("the.input"), cert); + checkWeakConstraint(rb.getString("the.input"), cert, cpcp); printWeakWarnings(true); reply = getYesNoReply (rb.getString("Do.you.still.want.to.add.it.to.your.own.keystore.no.")); @@ -3243,7 +3364,7 @@ public final class Main { // Print the cert and ask user if they really want to add // it to their keystore printX509Cert(cert, System.out); - checkWeak(rb.getString("the.input"), cert); + checkWeakConstraint(rb.getString("the.input"), cert, cpcp); printWeakWarnings(true); reply = getYesNoReply (rb.getString("Trust.this.certificate.no.")); @@ -3270,7 +3391,7 @@ public final class Main { // Print the cert and ask user if they really want to add it to // their keystore printX509Cert(cert, System.out); - checkWeak(rb.getString("the.input"), cert); + checkWeakConstraint(rb.getString("the.input"), cert, cpcp); printWeakWarnings(true); reply = getYesNoReply (rb.getString("Trust.this.certificate.no.")); @@ -3410,6 +3531,21 @@ public final class Main { return keyPass; } + private String withWeakConstraint(String alg, + CertPathConstraintsParameters cpcp) { + try { + DISABLED_CHECK.permits(alg, cpcp, false); + } catch (CertPathValidatorException e) { + return String.format(rb.getString("with.disabled"), alg); + } + try { + LEGACY_CHECK.permits(alg, cpcp, false); + return alg; + } catch (CertPathValidatorException e) { + return String.format(rb.getString("with.weak"), alg); + } + } + private String withWeak(String alg) { if (DISABLED_CHECK.permits(SIG_PRIMITIVE_SET, alg, null)) { if (LEGACY_CHECK.permits(SIG_PRIMITIVE_SET, alg, null)) { @@ -3422,35 +3558,24 @@ public final class Main { } } - private String fullDisplayAlgName(Key key) { - String result = key.getAlgorithm(); - if (key instanceof ECKey) { - ECParameterSpec paramSpec = ((ECKey) key).getParams(); - if (paramSpec instanceof NamedCurve) { - NamedCurve nc = (NamedCurve)paramSpec; - result += " (" + nc.getNameAndAliases()[0] + ")"; - } - } else if (key instanceof EdECKey) { - result = ((EdECKey) key).getParams().getName(); - } - return result; - } - - private String withWeak(Key key) { + private String withWeakConstraint(Key key, + CertPathConstraintsParameters cpcp) { int kLen = KeyUtil.getKeySize(key); - String displayAlg = fullDisplayAlgName(key); - if (DISABLED_CHECK.permits(SIG_PRIMITIVE_SET, key)) { - if (LEGACY_CHECK.permits(SIG_PRIMITIVE_SET, key)) { - if (kLen >= 0) { - return String.format(rb.getString("key.bit"), kLen, displayAlg); - } else { - return String.format(rb.getString("unknown.size.1"), displayAlg); - } + String displayAlg = KeyUtil.fullDisplayAlgName(key); + try { + DISABLED_CHECK.permits(key.getAlgorithm(), cpcp, true); + } catch (CertPathValidatorException e) { + return String.format(rb.getString("key.bit.disabled"), kLen, displayAlg); + } + try { + LEGACY_CHECK.permits(key.getAlgorithm(), cpcp, true); + if (kLen >= 0) { + return String.format(rb.getString("key.bit"), kLen, displayAlg); } else { - return String.format(rb.getString("key.bit.weak"), kLen, displayAlg); + return String.format(rb.getString("unknown.size.1"), displayAlg); } - } else { - return String.format(rb.getString("key.bit.disabled"), kLen, displayAlg); + } catch (CertPathValidatorException e) { + return String.format(rb.getString("key.bit.weak"), kLen, displayAlg); } } @@ -3465,9 +3590,11 @@ public final class Main { (rb.getString(".PATTERN.printX509Cert.with.weak")); PublicKey pkey = cert.getPublicKey(); String sigName = cert.getSigAlgName(); + CertPathConstraintsParameters cpcp = + buildCertPathConstraint(cert, null); // No need to warn about sigalg of a trust anchor if (!isTrustedCert(cert)) { - sigName = withWeak(sigName); + sigName = withWeakConstraint(sigName, cpcp); } Object[] source = {cert.getSubjectX500Principal().toString(), cert.getIssuerX500Principal().toString(), @@ -3477,7 +3604,7 @@ public final class Main { getCertFingerPrint("SHA-1", cert), getCertFingerPrint("SHA-256", cert), sigName, - withWeak(pkey), + withWeakConstraint(pkey, cpcp), cert.getVersion() }; out.println(form.format(source)); @@ -3801,7 +3928,7 @@ public final class Main { throws Exception { - checkWeak(rb.getString("reply"), replyCerts); + checkWeakConstraint(rb.getString("reply"), replyCerts); // order the certs in the reply (bottom-up). // we know that all certs in the reply are of type X.509, because @@ -3883,11 +4010,14 @@ public final class Main { replyCerts.length); tmpCerts[tmpCerts.length-1] = root.snd; replyCerts = tmpCerts; - checkWeak(String.format(fromKeyStore + CertPathConstraintsParameters cpcp = + buildCertPathConstraint((X509Certificate)root.snd, + null); + checkWeakConstraint(String.format(fromKeyStore ? rb.getString("alias.in.keystore") : rb.getString("alias.in.cacerts"), root.fst), - root.snd); + root.snd, cpcp); } } return replyCerts; @@ -3952,7 +4082,9 @@ public final class Main { (X509Certificate) certToVerify), chain, certs)) { for (Pair p : chain) { - checkWeak(p.fst, p.snd); + CertPathConstraintsParameters cpcp = + buildCertPathConstraint(p.snd, null); + checkWeakConstraint(p.fst, p.snd, cpcp); } Certificate[] newChain = new Certificate[chain.size()]; @@ -4161,18 +4293,18 @@ public final class Main { } if (date != null) { if (date.matches("\\d\\d\\d\\d\\/\\d\\d\\/\\d\\d")) { - c.set(Integer.valueOf(date.substring(0, 4)), - Integer.valueOf(date.substring(5, 7))-1, - Integer.valueOf(date.substring(8, 10))); + c.set(Integer.parseInt(date.substring(0, 4)), + Integer.parseInt(date.substring(5, 7))-1, + Integer.parseInt(date.substring(8, 10))); } else { throw ioe; } } if (time != null) { if (time.matches("\\d\\d:\\d\\d:\\d\\d")) { - c.set(Calendar.HOUR_OF_DAY, Integer.valueOf(time.substring(0, 2))); - c.set(Calendar.MINUTE, Integer.valueOf(time.substring(3, 5))); - c.set(Calendar.SECOND, Integer.valueOf(time.substring(6, 8))); + c.set(Calendar.HOUR_OF_DAY, Integer.parseInt(time.substring(0, 2))); + c.set(Calendar.MINUTE, Integer.parseInt(time.substring(3, 5))); + c.set(Calendar.SECOND, Integer.parseInt(time.substring(6, 8))); c.set(Calendar.MILLISECOND, 0); } else { throw ioe; @@ -4748,6 +4880,67 @@ public final class Main { } } + private void checkWeakConstraint(String label, String sigAlg, Key key, + CertPathConstraintsParameters cpcp) throws Exception { + if (sigAlg != null) { + try { + DISABLED_CHECK.permits(sigAlg, cpcp, false); + try { + LEGACY_CHECK.permits(sigAlg, cpcp, false); + } catch (CertPathValidatorException e) { + weakWarnings.add(String.format( + rb.getString("whose.sigalg.weak"), label, sigAlg)); + } + } catch (CertPathValidatorException e) { + String eMessage = e.getMessage(); + if (eMessage.contains("denyAfter constraint check failed") && + e.getReason() == BasicReason.ALGORITHM_CONSTRAINED) { + String startSeparator = "Constraint date: "; + int startSepPos = eMessage.indexOf(startSeparator); + String endSeparator = "; params date"; + int endSepPos = eMessage.indexOf(endSeparator); + String denyAfterDate = null; + try { + denyAfterDate = eMessage.substring(startSepPos + startSeparator.length(), + endSepPos); + } catch (IndexOutOfBoundsException e1) { + throw new Exception(rb.getString( + "Unable.to.parse.denyAfter.string.in.exception.message")); + } + + weakWarnings.add(String.format( + rb.getString("whose.sigalg.usagesignedjar"), label, sigAlg, + denyAfterDate)); + } else { + weakWarnings.add(String.format( + rb.getString("whose.sigalg.disabled"), label, sigAlg)); + } + if (debug) { + e.printStackTrace(); + } + } + } + + if (key != null) { + try { + DISABLED_CHECK.permits(key.getAlgorithm(), cpcp, true); + try { + LEGACY_CHECK.permits(key.getAlgorithm(), cpcp, true); + } catch (CertPathValidatorException e) { + weakWarnings.add(String.format( + rb.getString("whose.key.weak"), label, + String.format(rb.getString("key.bit"), + KeyUtil.getKeySize(key), KeyUtil.fullDisplayAlgName(key)))); + } + } catch (CertPathValidatorException e) { + weakWarnings.add(String.format( + rb.getString("whose.key.disabled"), label, + String.format(rb.getString("key.bit"), + KeyUtil.getKeySize(key), KeyUtil.fullDisplayAlgName(key)))); + } + } + } + private void checkWeak(String label, String sigAlg, Key key) { if (sigAlg != null) { if (!DISABLED_CHECK.permits(SIG_PRIMITIVE_SET, sigAlg, null)) { @@ -4764,18 +4957,21 @@ public final class Main { weakWarnings.add(String.format( rb.getString("whose.key.disabled"), label, String.format(rb.getString("key.bit"), - KeyUtil.getKeySize(key), fullDisplayAlgName(key)))); + KeyUtil.getKeySize(key), KeyUtil.fullDisplayAlgName(key)))); } else if (!LEGACY_CHECK.permits(SIG_PRIMITIVE_SET, key)) { weakWarnings.add(String.format( rb.getString("whose.key.weak"), label, String.format(rb.getString("key.bit"), - KeyUtil.getKeySize(key), fullDisplayAlgName(key)))); + KeyUtil.getKeySize(key), KeyUtil.fullDisplayAlgName(key)))); } } } - private void checkWeak(String label, Certificate[] certs) - throws KeyStoreException { + private void checkWeakConstraint(String label, Certificate[] certs) + throws KeyStoreException, Exception { + X509Certificate[] xcerts = convertCerts(certs); + List chain = Arrays.asList(xcerts); + TrustAnchor anchor = findTrustAnchor(chain); for (int i = 0; i < certs.length; i++) { Certificate cert = certs[i]; if (cert instanceof X509Certificate) { @@ -4784,23 +4980,43 @@ public final class Main { if (certs.length > 1) { fullLabel = oneInMany(label, i, certs.length); } - checkWeak(fullLabel, xc); + + CertPathConstraintsParameters cpcp = null; + if (i == 0 && xc.getBasicConstraints() == -1) { + // this is an EE + cpcp = buildCertPathConstraint(xc, anchor); + } else { + cpcp = new CertPathConstraintsParameters( + xc, null, anchor, null); + } + checkWeakConstraint(fullLabel, xc, cpcp); } } } - private void checkWeak(String label, Certificate cert) - throws KeyStoreException { + private void checkWeakConstraint(String label, Certificate cert, + CertPathConstraintsParameters cpcp) + throws KeyStoreException, Exception { if (cert instanceof X509Certificate) { X509Certificate xc = (X509Certificate)cert; // No need to check the sigalg of a trust anchor String sigAlg = isTrustedCert(cert) ? null : xc.getSigAlgName(); - checkWeak(label, sigAlg, xc.getPublicKey()); + checkWeakConstraint(label, sigAlg, xc.getPublicKey(), cpcp); } } - private void checkWeak(String label, PKCS10 p10) { - checkWeak(label, p10.getSigAlg(), p10.getSubjectPublicKeyInfo()); + private void checkWeakConstraint(String label, PKCS10 p10, + CertPathConstraintsParameters cpcp) throws Exception { + checkWeakConstraint(label, p10.getSigAlg(), + p10.getSubjectPublicKeyInfo(), cpcp); + } + + private void checkWeakConstraint(String label, CRL crl, Key key, + CertPathConstraintsParameters cpcp) throws Exception { + if (crl instanceof X509CRLImpl) { + X509CRLImpl impl = (X509CRLImpl)crl; + checkWeakConstraint(label, impl.getSigAlgName(), key, cpcp); + } } private void checkWeak(String label, CRL crl, Key key) { @@ -4810,6 +5026,76 @@ public final class Main { } } + private KeyStore buildTrustedCerts() { + KeyStore caks = null; + try { + caks = KeyStoreUtil.getCacertsKeyStore(); + if (caks != null) { + Enumeration aliases = caks.aliases(); + while (aliases.hasMoreElements()) { + String a = aliases.nextElement(); + try { + trustedCerts.add((X509Certificate)caks.getCertificate(a)); + } catch (Exception e2) { + // ignore, if the keystore has not been loaded/initialized properly + } + } + } + } catch (Exception e) { + // Ignore, if cacerts cannot be loaded + } + return caks; + } + + private TrustAnchor findTrustAnchor(List chain) { + if (chain.isEmpty()) { + return null; + } + + X509Certificate last = chain.get(chain.size() - 1); + Optional trusted = + trustedCerts.stream() + .filter(c -> c.getSubjectX500Principal().equals(last.getIssuerX500Principal())) + .findFirst(); + return trusted.isPresent() ? new TrustAnchor(trusted.get(), null) : null; + } + + private X509Certificate[] convertCerts(Certificate[] certs) { + X509Certificate[] xcerts = new X509Certificate[certs.length]; + + for (int i = 0; i < certs.length; i++) { + if (certs[i] instanceof X509Certificate) { + xcerts[i] = (X509Certificate) certs[i]; + } + } + return xcerts; + } + + private CertPathConstraintsParameters buildCertPathConstraint( + X509Certificate xcert, TrustAnchor anchor) throws Exception{ + List eku = xcert.getExtendedKeyUsage(); + if (eku == null) { + return new CertPathConstraintsParameters(xcert, null, + anchor, null); + } + + if (eku.contains(KnownOIDs.codeSigning.value())) { + return new CertPathConstraintsParameters(xcert, + Validator.VAR_CODE_SIGNING, anchor, null); + } else if (eku.contains(KnownOIDs.clientAuth.value())) { + return new CertPathConstraintsParameters(xcert, + Validator.VAR_TLS_CLIENT, anchor, null); + } else if (eku.contains(KnownOIDs.serverAuth.value())) { + return new CertPathConstraintsParameters(xcert, + Validator.VAR_TLS_SERVER, anchor, null); + } else if (eku.contains(KnownOIDs.KP_TimeStamping.value())) { + return new CertPathConstraintsParameters(xcert, + Validator.VAR_TSA_SERVER, anchor, null); + } + return new CertPathConstraintsParameters(xcert, Validator.VAR_GENERIC, + anchor, null); + } + private void printWeakWarnings(boolean newLine) { if (!weakWarnings.isEmpty() && !nowarn) { System.err.println("\nWarning:"); diff --git a/src/java.base/share/classes/sun/security/tools/keytool/Resources.java b/src/java.base/share/classes/sun/security/tools/keytool/Resources.java index df0147e529ded693a1a82999fa077aed65198d3f..f26b2a13bd8324ffc2eea394237b983a3cb6fa0e 100644 --- a/src/java.base/share/classes/sun/security/tools/keytool/Resources.java +++ b/src/java.base/share/classes/sun/security/tools/keytool/Resources.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -483,6 +483,8 @@ public class Resources extends java.util.ListResourceBundle { "Subject: %1$s\nFormat: %2$s\nPublic Key: %3$s\nSignature algorithm: %4$s\n"}, {"verified.by.s.in.s.weak", "Verified by %1$s in %2$s with a %3$s"}, {"whose.sigalg.disabled", "%1$s uses the %2$s signature algorithm which is considered a security risk and is disabled."}, + {"whose.sigalg.usagesignedjar", "%1$s uses the %2$s signature algorithm which is considered a security risk and cannot be used to sign JARs after %3$s."}, + {"Unable.to.parse.denyAfter.string.in.exception.message", "Unable to parse denyAfter date string in exception message"}, {"whose.sigalg.weak", "%1$s uses the %2$s signature algorithm which is considered a security risk. This algorithm will be disabled in a future update."}, {"whose.key.disabled", "%1$s uses a %2$s which is considered a security risk and is disabled."}, {"whose.key.weak", "%1$s uses a %2$s which is considered a security risk. This key size will be disabled in a future update."}, diff --git a/src/java.base/share/classes/sun/security/util/AlgorithmDecomposer.java b/src/java.base/share/classes/sun/security/util/AlgorithmDecomposer.java index 69eaa22aafb043b6548c91222238c285c27a1407..3f4984759324f4f75a6ea8cd7cb02667b08d9c1f 100644 --- a/src/java.base/share/classes/sun/security/util/AlgorithmDecomposer.java +++ b/src/java.base/share/classes/sun/security/util/AlgorithmDecomposer.java @@ -57,7 +57,7 @@ public class AlgorithmDecomposer { String[] transTokens = algorithm.split("/"); for (String transToken : transTokens) { - if (transToken == null || transToken.isEmpty()) { + if (transToken.isEmpty()) { continue; } @@ -70,7 +70,7 @@ public class AlgorithmDecomposer { String[] tokens = PATTERN.split(transToken); for (String token : tokens) { - if (token == null || token.isEmpty()) { + if (token.isEmpty()) { continue; } diff --git a/src/java.base/share/classes/sun/security/util/ChannelBindingException.java b/src/java.base/share/classes/sun/security/util/ChannelBindingException.java new file mode 100644 index 0000000000000000000000000000000000000000..847cd0741a0d2a14171c82ec78fcf1590a0f1d00 --- /dev/null +++ b/src/java.base/share/classes/sun/security/util/ChannelBindingException.java @@ -0,0 +1,60 @@ +/* + * 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. 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.util; + +import java.security.GeneralSecurityException; + +/** + * Thrown by TlsChannelBinding if an error occurs + */ +public class ChannelBindingException extends GeneralSecurityException { + + @java.io.Serial + private static final long serialVersionUID = -5021387249782788460L; + + /** + * Constructs a ChannelBindingException with no detail message. A detail + * message is a String that describes this particular exception. + */ + public ChannelBindingException() { + super(); + } + + /** + * Constructs a ChannelBindingException with a detail message and + * specified cause. + */ + public ChannelBindingException(String msg, Exception e) { + super(msg, e); + } + + /** + * Constructs a ChannelBindingException with a detail message + */ + public ChannelBindingException(String msg) { + super(msg); + } +} diff --git a/src/java.base/share/classes/sun/security/util/Debug.java b/src/java.base/share/classes/sun/security/util/Debug.java index 31c650e521da547cd8a342428b40ca1930702d7c..77db7492878c326339b4a804c3cfd3d77e98bc28 100644 --- a/src/java.base/share/classes/sun/security/util/Debug.java +++ b/src/java.base/share/classes/sun/security/util/Debug.java @@ -161,10 +161,10 @@ public class Debug { if (args == null) return false; else { - if (args.indexOf("all") != -1) + if (args.contains("all")) return true; else - return (args.indexOf(option) != -1); + return (args.contains(option)); } } diff --git a/src/java.base/share/classes/sun/security/util/DisabledAlgorithmConstraints.java b/src/java.base/share/classes/sun/security/util/DisabledAlgorithmConstraints.java index 2bf39bfae6f4668c47d1db296264b6887038340f..0cdb85decaf2083606a0bf7e5b07ad1d15fc6795 100644 --- a/src/java.base/share/classes/sun/security/util/DisabledAlgorithmConstraints.java +++ b/src/java.base/share/classes/sun/security/util/DisabledAlgorithmConstraints.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 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 @@ -39,9 +39,12 @@ import java.security.spec.InvalidParameterSpecException; import java.security.spec.MGF1ParameterSpec; import java.security.spec.NamedParameterSpec; import java.security.spec.PSSParameterSpec; +import java.time.DateTimeException; +import java.time.Instant; +import java.time.ZonedDateTime; +import java.time.ZoneId; import java.util.ArrayList; import java.util.Arrays; -import java.util.Calendar; import java.util.Date; import java.util.HashMap; import java.util.HashSet; @@ -51,7 +54,6 @@ import java.util.Map; import java.util.Set; import java.util.Collection; import java.util.StringTokenizer; -import java.util.TimeZone; import java.util.regex.Pattern; import java.util.regex.Matcher; @@ -192,15 +194,15 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints { } public final void permits(String algorithm, AlgorithmParameters ap, - ConstraintsParameters cp) throws CertPathValidatorException { - - permits(algorithm, cp); + ConstraintsParameters cp, boolean checkKey) + throws CertPathValidatorException { + permits(algorithm, cp, checkKey); if (ap != null) { permits(ap, cp); } } - private void permits(AlgorithmParameters ap, ConstraintsParameters cp) + public void permits(AlgorithmParameters ap, ConstraintsParameters cp) throws CertPathValidatorException { switch (ap.getAlgorithm().toUpperCase(Locale.ENGLISH)) { @@ -219,13 +221,13 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints { PSSParameterSpec pssParams = ap.getParameterSpec(PSSParameterSpec.class); String digestAlg = pssParams.getDigestAlgorithm(); - permits(digestAlg, cp); + permits(digestAlg, cp, false); AlgorithmParameterSpec mgfParams = pssParams.getMGFParameters(); if (mgfParams instanceof MGF1ParameterSpec) { String mgfDigestAlg = ((MGF1ParameterSpec)mgfParams).getDigestAlgorithm(); if (!mgfDigestAlg.equalsIgnoreCase(digestAlg)) { - permits(mgfDigestAlg, cp); + permits(mgfDigestAlg, cp, false); } } } catch (InvalidParameterSpecException ipse) { @@ -233,22 +235,22 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints { } } - public final void permits(String algorithm, ConstraintsParameters cp) - throws CertPathValidatorException { - - // Check if named curves in the key are disabled. - for (Key key : cp.getKeys()) { - for (String curve : getNamedCurveFromKey(key)) { - if (!checkAlgorithm(disabledAlgorithms, curve, decomposer)) { - throw new CertPathValidatorException( + public final void permits(String algorithm, ConstraintsParameters cp, + boolean checkKey) throws CertPathValidatorException { + if (checkKey) { + // Check if named curves in the key are disabled. + for (Key key : cp.getKeys()) { + for (String curve : getNamedCurveFromKey(key)) { + if (!checkAlgorithm(disabledAlgorithms, curve, decomposer)) { + throw new CertPathValidatorException( "Algorithm constraints check failed on disabled " + "algorithm: " + curve, null, null, -1, BasicReason.ALGORITHM_CONSTRAINED); + } } } } - - algorithmConstraints.permits(algorithm, cp); + algorithmConstraints.permits(algorithm, cp, checkKey); } private static List getNamedCurveFromKey(Key key) { @@ -451,7 +453,7 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints { for (Constraint constraint : list) { if (!constraint.permits(key)) { if (debug != null) { - debug.println("Constraints: failed key size" + + debug.println("Constraints: failed key size " + "constraint check " + KeyUtil.getKeySize(key)); } return false; @@ -481,8 +483,8 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints { return true; } - public void permits(String algorithm, ConstraintsParameters cp) - throws CertPathValidatorException { + public void permits(String algorithm, ConstraintsParameters cp, + boolean checkKey) throws CertPathValidatorException { if (debug != null) { debug.println("Constraints.permits(): " + algorithm + ", " @@ -496,8 +498,10 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints { algorithms.add(algorithm); } - for (Key key : cp.getKeys()) { - algorithms.add(key.getAlgorithm()); + if (checkKey) { + for (Key key : cp.getKeys()) { + algorithms.add(key.getAlgorithm()); + } } // Check all applicable constraints @@ -507,6 +511,9 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints { continue; } for (Constraint constraint : list) { + if (!checkKey && constraint instanceof KeySizeConstraint) { + continue; + } constraint.permits(cp); } } @@ -681,41 +688,30 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints { * timezone. */ private static class DenyAfterConstraint extends Constraint { - private Date denyAfterDate; + private ZonedDateTime zdt; + private Instant denyAfterDate; DenyAfterConstraint(String algo, int year, int month, int day) { - Calendar c; algorithm = algo; if (debug != null) { - debug.println("DenyAfterConstraint read in as: year " + + debug.println("DenyAfterConstraint read in as: year " + year + ", month = " + month + ", day = " + day); } - c = new Calendar.Builder().setTimeZone(TimeZone.getTimeZone("GMT")) - .setDate(year, month - 1, day).build(); - - if (year > c.getActualMaximum(Calendar.YEAR) || - year < c.getActualMinimum(Calendar.YEAR)) { - throw new IllegalArgumentException( - "Invalid year given in constraint: " + year); - } - if ((month - 1) > c.getActualMaximum(Calendar.MONTH) || - (month - 1) < c.getActualMinimum(Calendar.MONTH)) { - throw new IllegalArgumentException( - "Invalid month given in constraint: " + month); - } - if (day > c.getActualMaximum(Calendar.DAY_OF_MONTH) || - day < c.getActualMinimum(Calendar.DAY_OF_MONTH)) { + try { + zdt = ZonedDateTime + .of(year, month, day, 0, 0, 0, 0, ZoneId.of("GMT")); + denyAfterDate = zdt.toInstant(); + } catch (DateTimeException dte) { throw new IllegalArgumentException( - "Invalid Day of Month given in constraint: " + day); + "Invalid denyAfter date", dte); } - denyAfterDate = c.getTime(); if (debug != null) { debug.println("DenyAfterConstraint date set to: " + - denyAfterDate); + zdt.toLocalDate()); } } @@ -730,23 +726,22 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints { @Override public void permits(ConstraintsParameters cp) throws CertPathValidatorException { - Date currentDate; - String errmsg; + Instant currentDate; if (cp.getDate() != null) { - currentDate = cp.getDate(); + currentDate = cp.getDate().toInstant(); } else { - currentDate = new Date(); + currentDate = Instant.now(); } - if (!denyAfterDate.after(currentDate)) { + if (!denyAfterDate.isAfter(currentDate)) { if (next(cp)) { return; } throw new CertPathValidatorException( "denyAfter constraint check failed: " + algorithm + " used with Constraint date: " + - denyAfterDate + "; params date: " + + zdt.toLocalDate() + "; params date: " + currentDate + cp.extendedExceptionMsg(), null, null, -1, BasicReason.ALGORITHM_CONSTRAINED); } @@ -765,7 +760,7 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints { debug.println("DenyAfterConstraints.permits(): " + algorithm); } - return denyAfterDate.after(new Date()); + return denyAfterDate.isAfter(Instant.now()); } } @@ -788,7 +783,7 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints { for (String usage : usages) { boolean match = false; - switch (usage.toLowerCase()) { + switch (usage.toLowerCase(Locale.ENGLISH)) { case "tlsserver": match = variant.equals(Validator.VAR_TLS_SERVER); break; diff --git a/src/java.base/share/classes/sun/security/util/ECParameters.java b/src/java.base/share/classes/sun/security/util/ECParameters.java index 317fad31ce4e92f74602ea5565e7da644f057758..429b022cc1baa9a21ccae8dd20fc2fdadc522e28 100644 --- a/src/java.base/share/classes/sun/security/util/ECParameters.java +++ b/src/java.base/share/classes/sun/security/util/ECParameters.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 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 @@ -122,8 +122,9 @@ public final class ECParameters extends AlgorithmParametersSpi { int keySize = ((ECKeySizeParameterSpec)paramSpec).getKeySize(); namedCurve = CurveDB.lookup(keySize); } else { - throw new InvalidParameterSpecException - ("Only ECParameterSpec and ECGenParameterSpec supported"); + throw new InvalidParameterSpecException( + "Only ECParameterSpec, ECGenParameterSpec " + + "and ECKeySizeParameterSpec supported"); } if (namedCurve == null) { @@ -213,7 +214,8 @@ public final class ECParameters extends AlgorithmParametersSpi { } throw new InvalidParameterSpecException( - "Only ECParameterSpec and ECGenParameterSpec supported"); + "Only ECParameterSpec, ECGenParameterSpec " + + "and ECKeySizeParameterSpec supported"); } protected byte[] engineGetEncoded() throws IOException { @@ -233,4 +235,3 @@ public final class ECParameters extends AlgorithmParametersSpi { return namedCurve.toString(); } } - diff --git a/src/java.base/share/classes/sun/security/util/GCMParameters.java b/src/java.base/share/classes/sun/security/util/GCMParameters.java index 02390777a039dd919a0d6ff7457247d8cdd589eb..d54965f975dfe7c46f82d21f125b81be5395eae6 100644 --- a/src/java.base/share/classes/sun/security/util/GCMParameters.java +++ b/src/java.base/share/classes/sun/security/util/GCMParameters.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -111,7 +111,7 @@ public final class GCMParameters extends AlgorithmParametersSpi { T engineGetParameterSpec(Class paramSpec) throws InvalidParameterSpecException { - if (GCMParameterSpec.class.isAssignableFrom(paramSpec)) { + if (paramSpec.isAssignableFrom(GCMParameterSpec.class)) { return paramSpec.cast(new GCMParameterSpec(tLen * 8, iv)); } else { throw new InvalidParameterSpecException diff --git a/src/java.base/share/classes/sun/security/util/HostnameChecker.java b/src/java.base/share/classes/sun/security/util/HostnameChecker.java index aacd94837c962cb92ad48c6ced680539886e84f6..4c0bca36830706a8b9c695a7410ea311dd45c27d 100644 --- a/src/java.base/share/classes/sun/security/util/HostnameChecker.java +++ b/src/java.base/share/classes/sun/security/util/HostnameChecker.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 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 @@ -178,7 +178,7 @@ public class HostnameChecker { * Certification Authorities are encouraged to use the dNSName instead. * * Matching is performed using the matching rules specified by - * [RFC5280]. If more than one identity of a given type is present in + * [RFC6125]. If more than one identity of a given type is present in * the certificate (e.g., more than one dNSName name, a match in any one * of the set is considered acceptable.) */ @@ -262,7 +262,7 @@ public class HostnameChecker { /** * Returns true if name matches against template.

          * - * The matching is performed as per RFC 2818 rules for TLS and + * The matching is performed as per RFC 2818/6125 rules for TLS and * RFC 2830 rules for LDAP.

          * * The name parameter should represent a DNS name. The @@ -299,9 +299,7 @@ public class HostnameChecker { return false; } - if (checkType == TYPE_TLS) { - return matchAllWildcards(name, template); - } else if (checkType == TYPE_LDAP) { + if (checkType == TYPE_TLS || checkType == TYPE_LDAP) { return matchLeftmostWildcard(name, template); } else { return false; @@ -371,37 +369,6 @@ public class HostnameChecker { return false; } - /** - * Returns true if name matches against template.

          - * - * According to RFC 2818, section 3.1 - - * Names may contain the wildcard character * which is - * considered to match any single domain name component - * or component fragment. - * E.g., *.a.com matches foo.a.com but not - * bar.foo.a.com. f*.com matches foo.com but not bar.com. - */ - private static boolean matchAllWildcards(String name, - String template) { - name = name.toLowerCase(Locale.ENGLISH); - template = template.toLowerCase(Locale.ENGLISH); - StringTokenizer nameSt = new StringTokenizer(name, "."); - StringTokenizer templateSt = new StringTokenizer(template, "."); - - if (nameSt.countTokens() != templateSt.countTokens()) { - return false; - } - - while (nameSt.hasMoreTokens()) { - if (!matchWildCards(nameSt.nextToken(), - templateSt.nextToken())) { - return false; - } - } - return true; - } - - /** * Returns true if name matches against template.

          * diff --git a/src/java.base/share/classes/sun/security/util/JarConstraintsParameters.java b/src/java.base/share/classes/sun/security/util/JarConstraintsParameters.java index 9cf2bf9ffb3e03aaea556e80888a7ca412a60a45..28c959d3f59db71ac6ce8c15bb7f593184b2d6af 100644 --- a/src/java.base/share/classes/sun/security/util/JarConstraintsParameters.java +++ b/src/java.base/share/classes/sun/security/util/JarConstraintsParameters.java @@ -98,16 +98,11 @@ public class JarConstraintsParameters implements ConstraintsParameters { this.timestamp = latestTimestamp; } - public JarConstraintsParameters(List chain, Timestamp timestamp) { + public JarConstraintsParameters(List chain, Date timestamp) { this.keys = new HashSet<>(); this.certsIssuedByAnchor = new HashSet<>(); addToCertsAndKeys(chain); - if (timestamp != null) { - addToCertsAndKeys(timestamp.getSignerCertPath()); - this.timestamp = timestamp.getTimestamp(); - } else { - this.timestamp = null; - } + this.timestamp = timestamp; } // extract last certificate and signer's public key from chain @@ -178,7 +173,7 @@ public class JarConstraintsParameters implements ConstraintsParameters { @Override public String extendedExceptionMsg() { - return message; + return message == null ? "." : message; } @Override diff --git a/src/java.base/share/classes/sun/security/util/KeyStoreDelegator.java b/src/java.base/share/classes/sun/security/util/KeyStoreDelegator.java index d3e3de0d9919d719d6d7f600415c7190cbb6baff..27cde4b205381c9ccc044bff6669bed4b3306238 100644 --- a/src/java.base/share/classes/sun/security/util/KeyStoreDelegator.java +++ b/src/java.base/share/classes/sun/security/util/KeyStoreDelegator.java @@ -129,6 +129,11 @@ public class KeyStoreDelegator extends KeyStoreSpi { keystore.engineDeleteEntry(alias); } + @Override + public Set engineGetAttributes(String alias) { + return keystore.engineGetAttributes(alias); + } + @Override public Enumeration engineAliases() { return keystore.engineAliases(); 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 a20ebffa5ff53a72ffd38633307cf588150990b6..3648447e10e138616d30c086781d2bb83b8e8547 100644 --- a/src/java.base/share/classes/sun/security/util/KeyUtil.java +++ b/src/java.base/share/classes/sun/security/util/KeyUtil.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -190,6 +190,28 @@ public final class KeyUtil { return -1; } + /** + * Returns the algorithm name of the given key object. If an EC key is + * specified, returns the algorithm name and its named curve. + * + * @param key the key object, cannot be null + * @return the algorithm name of the given key object, or return in the + * form of "EC (named curve)" if the given key object is an EC key + */ + public static final String fullDisplayAlgName(Key key) { + String result = key.getAlgorithm(); + if (key instanceof ECKey) { + ECParameterSpec paramSpec = ((ECKey) key).getParams(); + if (paramSpec instanceof NamedCurve) { + NamedCurve nc = (NamedCurve)paramSpec; + result += " (" + nc.getNameAndAliases()[0] + ")"; + } + } else if (key instanceof EdECKey) { + result = ((EdECKey) key).getParams().getName(); + } + return result; + } + /** * Returns whether the key is valid or not. *

          diff --git a/src/java.base/share/classes/sun/security/util/ManifestEntryVerifier.java b/src/java.base/share/classes/sun/security/util/ManifestEntryVerifier.java index 43d0e751dee4501e4d6fbd939046cb56cde07238..187922cc8f294722f77c032530ecdbb25a0446e1 100644 --- a/src/java.base/share/classes/sun/security/util/ManifestEntryVerifier.java +++ b/src/java.base/share/classes/sun/security/util/ManifestEntryVerifier.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -192,7 +192,8 @@ public class ManifestEntryVerifier { * */ public CodeSigner[] verify(Hashtable verifiedSigners, - Hashtable sigFileSigners) + Hashtable sigFileSigners, + Map> signersToAlgs) throws JarException { if (skip) { @@ -207,38 +208,60 @@ public class ManifestEntryVerifier { return signers; } - JarConstraintsParameters params = - getParams(verifiedSigners, sigFileSigners); + CodeSigner[] entrySigners = sigFileSigners.get(name); + Map algsPermittedStatus = + algsPermittedStatusForSigners(signersToAlgs, entrySigners); + // Flag that indicates if only disabled algorithms are used and jar + // entry should be treated as unsigned. + boolean disabledAlgs = true; + JarConstraintsParameters params = null; for (int i=0; i < digests.size(); i++) { MessageDigest digest = digests.get(i); - if (params != null) { - try { - params.setExtendedExceptionMsg(JarFile.MANIFEST_NAME, - name + " entry"); - DisabledAlgorithmConstraints.jarConstraints() - .permits(digest.getAlgorithm(), params); - } catch (GeneralSecurityException e) { - if (debug != null) { - debug.println("Digest algorithm is restricted: " + e); + String digestAlg = digest.getAlgorithm(); + + // Check if this algorithm is permitted, skip if false. + if (algsPermittedStatus != null) { + Boolean permitted = algsPermittedStatus.get(digestAlg); + if (permitted == null) { + if (params == null) { + params = new JarConstraintsParameters(entrySigners); } - return null; + if (!checkConstraints(digestAlg, params)) { + algsPermittedStatus.put(digestAlg, Boolean.FALSE); + continue; + } else { + algsPermittedStatus.put(digestAlg, Boolean.TRUE); + } + } else if (!permitted) { + continue; } } + + // A non-disabled algorithm was used. + disabledAlgs = false; + byte [] manHash = manifestHashes.get(i); byte [] theHash = digest.digest(); if (debug != null) { debug.println("Manifest Entry: " + - name + " digest=" + digest.getAlgorithm()); + name + " digest=" + digestAlg); debug.println(" manifest " + HexFormat.of().formatHex(manHash)); debug.println(" computed " + HexFormat.of().formatHex(theHash)); debug.println(); } - if (!MessageDigest.isEqual(theHash, manHash)) - throw new SecurityException(digest.getAlgorithm()+ + if (!MessageDigest.isEqual(theHash, manHash)) { + throw new SecurityException(digestAlg + " digest error for "+name); + } + } + + // If there were only disabled algorithms used, return null and jar + // entry will be treated as unsigned. + if (disabledAlgs) { + return null; } // take it out of sigFileSigners and put it in verifiedSigners... @@ -249,40 +272,36 @@ public class ManifestEntryVerifier { return signers; } - /** - * Get constraints parameters for JAR. The constraints should be - * checked against all code signers. Returns the parameters, - * or null if the signers for this entry have already been checked - * or there are no signers for this entry. - */ - private JarConstraintsParameters getParams( - Map verifiedSigners, - Map sigFileSigners) { - - // verifiedSigners is usually preloaded with the Manifest's signers. - // If verifiedSigners contains the Manifest, then it will have all of - // the signers of the JAR. But if it doesn't then we need to fallback - // and check verifiedSigners to see if the signers of this entry have - // been checked already. - if (verifiedSigners.containsKey(manifestFileName)) { - if (verifiedSigners.size() > 1) { - // this means we already checked it previously - return null; - } else { - return new JarConstraintsParameters( - verifiedSigners.get(manifestFileName)); + // Gets the algorithms permitted status for the signers of this entry. + private static Map algsPermittedStatusForSigners( + Map> signersToAlgs, + CodeSigner[] signers) { + if (signers != null) { + Map algs = signersToAlgs.get(signers); + // create new HashMap if absent + if (algs == null) { + algs = new HashMap<>(); + signersToAlgs.put(signers, algs); } - } else { + return algs; + } + return null; + } + + // Checks the algorithm constraints against the signers of this entry. + private boolean checkConstraints(String algorithm, + JarConstraintsParameters params) { + try { + params.setExtendedExceptionMsg(JarFile.MANIFEST_NAME, + name + " entry"); + DisabledAlgorithmConstraints.jarConstraints() + .permits(algorithm, params, false); + return true; + } catch (GeneralSecurityException e) { if (debug != null) { - debug.println(manifestFileName + " not present in verifiedSigners"); - } - CodeSigner[] signers = sigFileSigners.get(name); - if (signers == null || verifiedSigners.containsValue(signers)) { - return null; - } else { - return new JarConstraintsParameters(signers); + debug.println("Digest algorithm is restricted: " + e); } + return false; } } } - diff --git a/src/java.base/share/classes/sun/security/util/PolicyUtil.java b/src/java.base/share/classes/sun/security/util/PolicyUtil.java index 3bea048f539004969afe5512b8918abeed42ef4c..b0ce1c496027e26c598640aa13b5a17c8c9e0025 100644 --- a/src/java.base/share/classes/sun/security/util/PolicyUtil.java +++ b/src/java.base/share/classes/sun/security/util/PolicyUtil.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 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 @@ -124,14 +124,8 @@ public class PolicyUtil { debug.println("reading password"+passURL); } - InputStream in = null; - try { - in = passURL.openStream(); + try (InputStream in = passURL.openStream()) { keyStorePassword = Password.readPassword(in); - } finally { - if (in != null) { - in.close(); - } } } @@ -159,13 +153,9 @@ public class PolicyUtil { debug.println("reading keystore"+keyStoreUrl); } - InputStream inStream = null; - try { - inStream = - new BufferedInputStream(getInputStream(keyStoreUrl)); + try (InputStream inStream = + new BufferedInputStream(getInputStream(keyStoreUrl))) { ks.load(inStream, keyStorePassword); - } finally { - inStream.close(); } return ks; } diff --git a/src/java.base/share/classes/sun/security/util/SecurityProviderConstants.java b/src/java.base/share/classes/sun/security/util/SecurityProviderConstants.java index ed826dff24ae49028796a944a82773e58af86600..166c4a5130f7c1efa024bac6c164d31a7979a4fb 100644 --- a/src/java.base/share/classes/sun/security/util/SecurityProviderConstants.java +++ b/src/java.base/share/classes/sun/security/util/SecurityProviderConstants.java @@ -140,7 +140,8 @@ public final class SecurityProviderConstants { } continue; } - String algoName = algoAndValue[0].trim().toUpperCase(); + String algoName = + algoAndValue[0].trim().toUpperCase(Locale.ENGLISH); int value = -1; try { value = Integer.parseInt(algoAndValue[1].trim()); diff --git a/src/java.base/share/classes/sun/security/util/SignatureFileVerifier.java b/src/java.base/share/classes/sun/security/util/SignatureFileVerifier.java index 1af7417b7f1ada332c14bcfb68c7e439aecc541d..6cc86b03b505190df32357814c755a105111cc6d 100644 --- a/src/java.base/share/classes/sun/security/util/SignatureFileVerifier.java +++ b/src/java.base/share/classes/sun/security/util/SignatureFileVerifier.java @@ -383,10 +383,11 @@ public class SignatureFileVerifier { try { params.setExtendedExceptionMsg(name + ".SF", key + " attribute"); DisabledAlgorithmConstraints - .jarConstraints().permits(algorithm, params); + .jarConstraints().permits(algorithm, params, false); } catch (GeneralSecurityException e) { permittedAlgs.put(algorithm, Boolean.FALSE); - permittedAlgs.put(key.toUpperCase(), Boolean.FALSE); + permittedAlgs.put(key.toUpperCase(Locale.ENGLISH), + Boolean.FALSE); if (debug != null) { if (e.getMessage() != null) { debug.println(key + ": " + e.getMessage()); 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 6ad35d12386339084eb7c65eaa420ccafc232a87..ec86df854fcc50827614f152f89bf31dc0dc8c2c 100644 --- a/src/java.base/share/classes/sun/security/util/SignatureUtil.java +++ b/src/java.base/share/classes/sun/security/util/SignatureUtil.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -47,32 +47,39 @@ import sun.security.x509.AlgorithmId; public class SignatureUtil { /** - * Convert OID.1.2.3.4 or 1.2.3.4 to its matching stdName. + * Convert OID.1.2.3.4 or 1.2.3.4 to its matching stdName, and return + * upper case algorithm name. * * @param algName input, could be in any form - * @return the matching stdName, or {@code algName} if it is not in the - * form of an OID, or the OID value if no match is found. + * @return the matching algorithm name or the OID string in upper case. */ private static String checkName(String algName) { - if (algName.indexOf(".") == -1) { - return algName; - } else { + algName = algName.toUpperCase(Locale.ENGLISH); + if (algName.contains(".")) { // convert oid to String if (algName.startsWith("OID.")) { algName = algName.substring(4); } + KnownOIDs ko = KnownOIDs.findMatch(algName); - return ko != null ? ko.stdName() : algName; + if (ko != null) { + return ko.stdName().toUpperCase(Locale.ENGLISH); + } } + + return algName; } // Utility method of creating an AlgorithmParameters object with // the specified algorithm name and encoding + // + // Note this method can be called only after converting OID.1.2.3.4 or + // 1.2.3.4 to its matching stdName, which is implemented in the + // checkName(String) method. private static AlgorithmParameters createAlgorithmParameters(String algName, byte[] paramBytes) throws ProviderException { try { - algName = checkName(algName); AlgorithmParameters result = AlgorithmParameters.getInstance(algName); result.init(paramBytes); @@ -96,11 +103,11 @@ public class SignatureUtil { AlgorithmParameterSpec paramSpec = null; if (params != null) { - sigName = checkName(sigName).toUpperCase(Locale.ENGLISH); + sigName = checkName(sigName); // AlgorithmParameters.getAlgorithm() may returns oid if it's // created during DER decoding. Convert to use the standard name // before passing it to RSAUtil - if (params.getAlgorithm().indexOf(".") != -1) { + if (params.getAlgorithm().contains(".")) { try { params = createAlgorithmParameters(sigName, params.getEncoded()); @@ -109,9 +116,9 @@ public class SignatureUtil { } } - if (sigName.indexOf("RSA") != -1) { + if (sigName.contains("RSA")) { paramSpec = RSAUtil.getParamSpec(params); - } else if (sigName.indexOf("ECDSA") != -1) { + } else if (sigName.contains("ECDSA")) { try { paramSpec = params.getParameterSpec(ECParameterSpec.class); } catch (Exception e) { @@ -140,12 +147,12 @@ public class SignatureUtil { AlgorithmParameterSpec paramSpec = null; if (paramBytes != null) { - sigName = checkName(sigName).toUpperCase(Locale.ENGLISH); - if (sigName.indexOf("RSA") != -1) { + sigName = checkName(sigName); + if (sigName.contains("RSA")) { AlgorithmParameters params = createAlgorithmParameters(sigName, paramBytes); paramSpec = RSAUtil.getParamSpec(params); - } else if (sigName.indexOf("ECDSA") != -1) { + } else if (sigName.contains("ECDSA")) { try { Provider p = Signature.getInstance(sigName).getProvider(); paramSpec = ECUtil.getECParameterSpec(p, paramBytes); @@ -313,7 +320,7 @@ public class SignatureUtil { public static AlgorithmParameterSpec getDefaultParamSpec( String sigAlg, Key k) { sigAlg = checkName(sigAlg); - if (sigAlg.equalsIgnoreCase("RSASSA-PSS")) { + if (sigAlg.equals("RSASSA-PSS")) { if (k instanceof RSAKey) { AlgorithmParameterSpec spec = ((RSAKey) k).getParams(); if (spec instanceof PSSParameterSpec) { @@ -428,7 +435,7 @@ public class SignatureUtil { */ public static void checkKeyAndSigAlgMatch(PrivateKey key, String sAlg) { String kAlg = key.getAlgorithm().toUpperCase(Locale.ENGLISH); - sAlg = checkName(sAlg).toUpperCase(Locale.ENGLISH); + sAlg = checkName(sAlg); switch (sAlg) { case "RSASSA-PSS" -> { if (!kAlg.equals("RSASSA-PSS") diff --git a/src/java.naming/share/classes/com/sun/jndi/ldap/sasl/TlsChannelBinding.java b/src/java.base/share/classes/sun/security/util/TlsChannelBinding.java similarity index 81% rename from src/java.naming/share/classes/com/sun/jndi/ldap/sasl/TlsChannelBinding.java rename to src/java.base/share/classes/sun/security/util/TlsChannelBinding.java index 922fa18028ce345464d02be8e1f2d239a6925655..fffd4fa6707c4c08367e0dc30288bbe33de1cb60 100644 --- a/src/java.naming/share/classes/com/sun/jndi/ldap/sasl/TlsChannelBinding.java +++ b/src/java.base/share/classes/sun/security/util/TlsChannelBinding.java @@ -22,16 +22,16 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package com.sun.jndi.ldap.sasl; -import javax.naming.NamingException; -import javax.security.sasl.SaslException; +package sun.security.util; + import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.cert.CertificateEncodingException; import java.security.cert.X509Certificate; import java.util.Arrays; import java.util.Hashtable; +import java.util.Locale; /** * This class implements the Channel Binding for TLS as defined in @@ -47,14 +47,6 @@ import java.util.Hashtable; public class TlsChannelBinding { - // TLS channel binding type property - public static final String CHANNEL_BINDING_TYPE = - "com.sun.jndi.ldap.tls.cbtype"; - - // internal TLS channel binding property - public static final String CHANNEL_BINDING = - "jdk.internal.sasl.tlschannelbinding"; - public enum TlsChannelBindingType { /** @@ -80,19 +72,18 @@ public class TlsChannelBinding { } /** - * Parse value of "com.sun.jndi.ldap.tls.cbtype" property + * Parse given value to see if it is a recognized and supported channel binding type + * * @param cbType - * @return TLS Channel Binding type or null if - * "com.sun.jndi.ldap.tls.cbtype" property has not been set. - * @throws NamingException + * @return TLS Channel Binding type or null if given string is null + * @throws ChannelBindingException */ - public static TlsChannelBindingType parseType(String cbType) throws NamingException { + public static TlsChannelBindingType parseType(String cbType) throws ChannelBindingException { if (cbType != null) { if (cbType.equals(TlsChannelBindingType.TLS_SERVER_END_POINT.getName())) { return TlsChannelBindingType.TLS_SERVER_END_POINT; } else { - throw new NamingException("Illegal value for " + - CHANNEL_BINDING_TYPE + " property."); + throw new ChannelBindingException("Illegal value for channel binding type: " + cbType); } } return null; @@ -104,14 +95,14 @@ public class TlsChannelBinding { /** * Construct tls-server-end-point Channel Binding data * @param serverCertificate - * @throws SaslException + * @throws ChannelBindingException */ - public static TlsChannelBinding create(X509Certificate serverCertificate) throws SaslException { + public static TlsChannelBinding create(X509Certificate serverCertificate) throws ChannelBindingException { try { final byte[] prefix = TlsChannelBindingType.TLS_SERVER_END_POINT.getName().concat(":").getBytes(); String hashAlg = serverCertificate.getSigAlgName(). - replace("SHA", "SHA-").toUpperCase(); + toUpperCase(Locale.ENGLISH).replace("SHA", "SHA-"); int ind = hashAlg.indexOf("WITH"); if (ind > 0) { hashAlg = hashAlg.substring(0, ind); @@ -127,7 +118,7 @@ public class TlsChannelBinding { System.arraycopy(hash, 0, cbData, prefix.length, hash.length); return new TlsChannelBinding(TlsChannelBindingType.TLS_SERVER_END_POINT, cbData); } catch (NoSuchAlgorithmException | CertificateEncodingException e) { - throw new SaslException("Cannot create TLS channel binding data", e); + throw new ChannelBindingException("Cannot create TLS channel binding data", e); } } diff --git a/src/java.base/share/classes/sun/security/validator/EndEntityChecker.java b/src/java.base/share/classes/sun/security/validator/EndEntityChecker.java index d0363f7482ba35005ab70ff19f99fd74b6e7d343..f048fffdbb48b85de5b7b2ebed4ef992b4639794 100644 --- a/src/java.base/share/classes/sun/security/validator/EndEntityChecker.java +++ b/src/java.base/share/classes/sun/security/validator/EndEntityChecker.java @@ -105,6 +105,7 @@ class EndEntityChecker { // bit numbers in the key usage extension private static final int KU_SIGNATURE = 0; + private static final int KU_NON_REPUDIATION = 1; private static final int KU_KEY_ENCIPHERMENT = 2; private static final int KU_KEY_AGREEMENT = 4; @@ -356,9 +357,11 @@ class EndEntityChecker { */ private void checkTSAServer(X509Certificate cert, Set exts) throws CertificateException { - if (checkKeyUsage(cert, KU_SIGNATURE) == false) { + // KU and EKU should be consistent + if (!checkKeyUsage(cert, KU_SIGNATURE) + && !checkKeyUsage(cert, KU_NON_REPUDIATION)) { throw new ValidatorException - ("KeyUsage does not allow digital signatures", + ("KeyUsage does not allow digital signatures or non repudiation", ValidatorException.T_EE_EXTENSIONS, cert); } diff --git a/src/java.base/share/classes/sun/security/x509/AlgorithmId.java b/src/java.base/share/classes/sun/security/x509/AlgorithmId.java index 627fb503ba9c41d88b46166fc59da611f7105a1e..5f2403f3b40defc0799b7a4bdcee558d2835fb38 100644 --- a/src/java.base/share/classes/sun/security/x509/AlgorithmId.java +++ b/src/java.base/share/classes/sun/security/x509/AlgorithmId.java @@ -520,7 +520,7 @@ public class AlgorithmId implements Serializable, DerEncoder { } // unknown algorithm oids - if (name.indexOf(".") == -1) { + if (!name.contains(".")) { // see if there is a matching oid string alias mapping from // 3rd party providers name = name.toUpperCase(Locale.ENGLISH); diff --git a/src/java.base/share/classes/sun/security/x509/CRLNumberExtension.java b/src/java.base/share/classes/sun/security/x509/CRLNumberExtension.java index 9434e613441ac1aede6b75eea4d6fc54fb9bf2ba..244e9d5df9be125162130bef9355f819d3e3d4f2 100644 --- a/src/java.base/share/classes/sun/security/x509/CRLNumberExtension.java +++ b/src/java.base/share/classes/sun/security/x509/CRLNumberExtension.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -199,7 +199,6 @@ implements CertAttrSet { * @exception IOException on encoding errors. */ public void encode(OutputStream out) throws IOException { - DerOutputStream tmp = new DerOutputStream(); encode(out, PKIXExtensions.CRLNumber_Id, true); } diff --git a/src/java.base/share/classes/sun/security/x509/CertificateIssuerExtension.java b/src/java.base/share/classes/sun/security/x509/CertificateIssuerExtension.java index 0dd8f39642a3bb87c7234992df95a9e5cd6fb693..40eba681244e979b22bc79cf0698e3ba1d2a3af9 100644 --- a/src/java.base/share/classes/sun/security/x509/CertificateIssuerExtension.java +++ b/src/java.base/share/classes/sun/security/x509/CertificateIssuerExtension.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -170,7 +170,7 @@ public class CertificateIssuerExtension extends Extension */ public String toString() { return super.toString() + "Certificate Issuer [\n" + - String.valueOf(names) + "]\n"; + names + "]\n"; } /** diff --git a/src/java.base/share/classes/sun/security/x509/DeltaCRLIndicatorExtension.java b/src/java.base/share/classes/sun/security/x509/DeltaCRLIndicatorExtension.java index 10b5a9dc09e9528a4cfc1e3cd961dc11b1f8a886..5933758874a79123ddbf9a51f116b92f96c3e16c 100644 --- a/src/java.base/share/classes/sun/security/x509/DeltaCRLIndicatorExtension.java +++ b/src/java.base/share/classes/sun/security/x509/DeltaCRLIndicatorExtension.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -28,9 +28,6 @@ package sun.security.x509; import java.io.IOException; import java.io.OutputStream; import java.math.BigInteger; -import java.util.Enumeration; - -import sun.security.util.*; /** * Represents the Delta CRL Indicator Extension. @@ -80,7 +77,7 @@ public class DeltaCRLIndicatorExtension extends CRLNumberExtension { } /** - * Creates a delta CRL indictor extension with the BigInteger value . + * Creates a delta CRL indicator extension with the BigInteger value . * The criticality is set to true. * * @param crlNum the value to be set for the extension. @@ -110,7 +107,6 @@ public class DeltaCRLIndicatorExtension extends CRLNumberExtension { * @exception IOException on encoding errors. */ public void encode(OutputStream out) throws IOException { - DerOutputStream tmp = new DerOutputStream(); super.encode(out, PKIXExtensions.DeltaCRLIndicator_Id, true); } } diff --git a/src/java.base/share/classes/sun/security/x509/GeneralSubtrees.java b/src/java.base/share/classes/sun/security/x509/GeneralSubtrees.java index 8adafe203444d94fc37ffc17554178718a0f8c9b..c47fc0c8245c8eec481eb0e8b8c3dffb5d029428 100644 --- a/src/java.base/share/classes/sun/security/x509/GeneralSubtrees.java +++ b/src/java.base/share/classes/sun/security/x509/GeneralSubtrees.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -130,7 +130,7 @@ public class GeneralSubtrees implements Cloneable { /** * Encode the GeneralSubtrees. * - * @param out the DerOutputStrean to encode this object to. + * @param out the DerOutputStream to encode this object to. */ public void encode(DerOutputStream out) throws IOException { DerOutputStream seq = new DerOutputStream(); @@ -346,7 +346,6 @@ public class GeneralSubtrees implements Cloneable { // same type in this. for (int i = 0; i < size(); i++) { GeneralNameInterface thisEntry = getGeneralNameInterface(i); - boolean removeThisEntry = false; // Step 3a: If the widest name of this type in other narrows // thisEntry, remove thisEntry and add widest other to newThis. diff --git a/src/java.base/share/classes/sun/security/x509/InvalidityDateExtension.java b/src/java.base/share/classes/sun/security/x509/InvalidityDateExtension.java index 7fac65f3ee592c28fe608e27a01c212433bb86f9..b731cba41027477e05da0991e1a142bbae5334cb 100644 --- a/src/java.base/share/classes/sun/security/x509/InvalidityDateExtension.java +++ b/src/java.base/share/classes/sun/security/x509/InvalidityDateExtension.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 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 @@ -168,7 +168,7 @@ public class InvalidityDateExtension extends Extension * Returns a printable representation of the Invalidity Date. */ public String toString() { - return super.toString() + " Invalidity Date: " + String.valueOf(date); + return super.toString() + " Invalidity Date: " + date; } /** diff --git a/src/java.base/share/classes/sun/security/x509/OtherName.java b/src/java.base/share/classes/sun/security/x509/OtherName.java index 0a2842a00be9a9f7dcc2ec16aaaf382ae527ab66..f274a221dd4efbeccad361eb3c4c4e9b85cbba77 100644 --- a/src/java.base/share/classes/sun/security/x509/OtherName.java +++ b/src/java.base/share/classes/sun/security/x509/OtherName.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -48,10 +48,10 @@ import sun.security.util.*; */ public class OtherName implements GeneralNameInterface { - private String name; - private ObjectIdentifier oid; - private byte[] nameValue = null; - private GeneralNameInterface gni = null; + private final ObjectIdentifier oid; + private final String name; + private final byte[] nameValue; // value inside [0] + private final GeneralNameInterface gni; private static final byte TAG_VALUE = 0; @@ -89,8 +89,12 @@ public class OtherName implements GeneralNameInterface { DerInputStream in = derValue.toDerInputStream(); oid = in.getOID(); - DerValue val = in.getDerValue(); - nameValue = val.toByteArray(); + DerValue derValue1 = in.getDerValue(); + if (derValue1.isContextSpecific((byte) 0) && derValue1.isConstructed()) { + nameValue = derValue1.data.toByteArray(); + } else { + throw new IOException("value is not EXPLICTly tagged [0]"); + } gni = getGNI(oid, nameValue); if (gni != null) { name = gni.toString(); @@ -125,12 +129,13 @@ public class OtherName implements GeneralNameInterface { return null; } Class[] params = { Object.class }; - Constructor cons = extClass.getConstructor(params); - - Object[] passed = new Object[] { nameValue }; - GeneralNameInterface gni = - (GeneralNameInterface)cons.newInstance(passed); - return gni; + Constructor cons; + try { + cons = extClass.getConstructor(Object.class); + } catch (NoSuchMethodException e) { + cons = extClass.getConstructor(byte[].class); + } + return (GeneralNameInterface)cons.newInstance(nameValue); } catch (Exception e) { throw new IOException("Instantiation error: " + e, e); } diff --git a/src/java.base/share/classes/sun/security/x509/PolicyConstraintsExtension.java b/src/java.base/share/classes/sun/security/x509/PolicyConstraintsExtension.java index eca45828aa638fed2c3a7ecf16c4874399b7e0cf..eda195ba60b95ae2325b22055970c37d9d8de9ce 100644 --- a/src/java.base/share/classes/sun/security/x509/PolicyConstraintsExtension.java +++ b/src/java.base/share/classes/sun/security/x509/PolicyConstraintsExtension.java @@ -154,7 +154,7 @@ implements CertAttrSet { if (next.isContextSpecific(TAG_REQUIRE) && !next.isConstructed()) { if (this.require != -1) - throw new IOException("Duplicate requireExplicitPolicy" + + throw new IOException("Duplicate requireExplicitPolicy " + "found in the PolicyConstraintsExtension"); next.resetTag(DerValue.tag_Integer); this.require = next.getInteger(); @@ -162,7 +162,7 @@ implements CertAttrSet { } else if (next.isContextSpecific(TAG_INHIBIT) && !next.isConstructed()) { if (this.inhibit != -1) - throw new IOException("Duplicate inhibitPolicyMapping" + + throw new IOException("Duplicate inhibitPolicyMapping " + "found in the PolicyConstraintsExtension"); next.resetTag(DerValue.tag_Integer); this.inhibit = next.getInteger(); diff --git a/src/java.base/share/classes/sun/security/x509/PolicyInformation.java b/src/java.base/share/classes/sun/security/x509/PolicyInformation.java index bf92d2694e94c344467e5150d68efe308895dc9d..0fc8d71c8d60cc8817171bb15457cb8d59769048 100644 --- a/src/java.base/share/classes/sun/security/x509/PolicyInformation.java +++ b/src/java.base/share/classes/sun/security/x509/PolicyInformation.java @@ -202,7 +202,7 @@ public class PolicyInformation { if (obj instanceof Set) { for (Object obj1 : (Set) obj) { if (!(obj1 instanceof PolicyQualifierInfo)) { - throw new IOException("Attribute value must be a" + + throw new IOException("Attribute value must be a " + "Set of PolicyQualifierInfo objects."); } } 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 1523cde227d38ed6f227d24c9c47f72f8c60561a..551e38ad31cee6c67a4111bc86815c4bfa45981b 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, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -1047,7 +1047,6 @@ public class X509CRLImpl extends X509CRL implements DerEncoder { * * @param oid ObjectIdentifier of extension desired * @return Object of type {@code } or null, if not found - * @throws IOException on error */ public Object getExtension(ObjectIdentifier oid) { if (extensions == null) diff --git a/src/java.base/share/classes/sun/security/x509/X509CertImpl.java b/src/java.base/share/classes/sun/security/x509/X509CertImpl.java index 3a1817327f9624fc09cbedd11f7b15d9f2e50b61..103c9f86b84823b725554f9f2490d0b5fde6a9ff 100644 --- a/src/java.base/share/classes/sun/security/x509/X509CertImpl.java +++ b/src/java.base/share/classes/sun/security/x509/X509CertImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 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 @@ -1584,6 +1584,17 @@ public class X509CertImpl extends X509Certificate implements DerEncoder { throw new RuntimeException("name cannot be encoded", ioe); } nameEntry.add(derOut.toByteArray()); + if (name.getType() == GeneralNameInterface.NAME_ANY + && name instanceof OtherName oname) { + nameEntry.add(oname.getOID().toString()); + byte[] nameValue = oname.getNameValue(); + try { + String v = new DerValue(nameValue).getAsString(); + nameEntry.add(v == null ? nameValue : v); + } catch (IOException ioe) { + nameEntry.add(nameValue); + } + } break; } newNames.add(Collections.unmodifiableList(nameEntry)); diff --git a/src/java.base/share/classes/sun/security/x509/X509CertInfo.java b/src/java.base/share/classes/sun/security/x509/X509CertInfo.java index 5fbc9a08f54fed80b3dea514cdec633d29aaf398..09a9ed2932078f50f445b60546ab36c44a03f248 100644 --- a/src/java.base/share/classes/sun/security/x509/X509CertInfo.java +++ b/src/java.base/share/classes/sun/security/x509/X509CertInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -729,7 +729,6 @@ public class X509CertInfo implements CertAttrSet { "has no extensions"); } SubjectAlternativeNameExtension subjectAltNameExt = null; - SubjectAlternativeNameExtension extValue = null; GeneralNames names = null; try { subjectAltNameExt = (SubjectAlternativeNameExtension) diff --git a/src/java.base/share/classes/sun/security/x509/X509Key.java b/src/java.base/share/classes/sun/security/x509/X509Key.java index faf7cfb927febb12ea9960f27af764c4369d7085..19979cb8e7e1509cbe3a6d8a5e691d669b5a41d7 100644 --- a/src/java.base/share/classes/sun/security/x509/X509Key.java +++ b/src/java.base/share/classes/sun/security/x509/X509Key.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 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 @@ -27,7 +27,6 @@ package sun.security.x509; import java.io.*; import java.util.Arrays; -import java.util.Properties; import java.security.Key; import java.security.PublicKey; import java.security.KeyFactory; @@ -150,10 +149,10 @@ public class X509Key implements PublicKey { * this kind of key, a subclass is returned. Otherwise, a generic * X509Key object is returned. * - *

          This mechanism gurantees that keys (and algorithms) may be + *

          This mechanism guarantees that keys (and algorithms) may be * freely manipulated and transferred, without risk of losing * information. Also, when a key (or algorithm) needs some special - * handling, that specific need can be accomodated. + * handling, that specific need can be accommodated. * * @param in the DER-encoded SubjectPublicKeyInfo value * @exception IOException on data format errors @@ -233,8 +232,6 @@ public class X509Key implements PublicKey { */ String classname = ""; try { - Properties props; - String keytype; Provider sunProvider; sunProvider = Security.getProvider("SUN"); diff --git a/src/java.base/share/classes/sun/text/RuleBasedBreakIterator.java b/src/java.base/share/classes/sun/text/RuleBasedBreakIterator.java index b3abf812f29dad922ba187e88b5d3baf9750a390..4d46cbd1c9c1b50912e0f8a4158a4c5562fc1e6a 100644 --- a/src/java.base/share/classes/sun/text/RuleBasedBreakIterator.java +++ b/src/java.base/share/classes/sun/text/RuleBasedBreakIterator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -70,7 +70,7 @@ import sun.text.SupplementaryCharacterData; * expression defines a set of characters (the "ignore characters") that * will be transparent to the BreakIterator.  A sequence of characters will break the * same way it would if any ignore characters it contains are taken out.  Break - * positions never occur befoer ignore characters.

          + * positions never occur before ignore characters.

          * *

          A regular expression uses a subset of the normal Unix regular-expression syntax, and * defines a sequence of characters to be kept together. With one significant exception, the @@ -151,7 +151,7 @@ import sun.text.SupplementaryCharacterData; * If ! appears at the beginning of a regular expression, it tells the regexp * parser that this expression specifies the backwards-iteration behavior of the iterator, * and not its normal iteration behavior.  This is generally only used in situations - * where the automatically-generated backwards-iteration brhavior doesn't produce + * where the automatically-generated backwards-iteration behavior doesn't produce * satisfactory results and must be supplemented with extra client-specified rules. * * diff --git a/src/java.base/share/classes/sun/text/spi/JavaTimeDateTimePatternProvider.java b/src/java.base/share/classes/sun/text/spi/JavaTimeDateTimePatternProvider.java index c8fd888e2b2699f253a97735c6263c6f4e831f89..58235c9dff0bf54f12bbf773260ecf4cf661ce98 100644 --- a/src/java.base/share/classes/sun/text/spi/JavaTimeDateTimePatternProvider.java +++ b/src/java.base/share/classes/sun/text/spi/JavaTimeDateTimePatternProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -27,6 +27,7 @@ package sun.text.spi; +import java.time.DateTimeException; import java.util.Locale; import java.util.spi.LocaleServiceProvider; @@ -41,21 +42,43 @@ public abstract class JavaTimeDateTimePatternProvider extends LocaleServiceProvi } /** - * Gets the formatting pattern for a timeStyle + * Returns the formatting pattern for a timeStyle * dateStyle, calendarType and locale. * Concrete implementation of this method will retrieve - * a java.time specific dateTime Pattern from selected Locale Provider. + * a java.time specific dateTime Pattern from the selected Locale Provider. * - * @param timeStyle an {@code int} value representing FormatStyle constant, -1 + * @param timeStyle an {@code int} value, representing FormatStyle constant, -1 * for date-only pattern - * @param dateStyle an {@code int} value,representing FormatStyle constant, -1 + * @param dateStyle an {@code int} value, representing FormatStyle constant, -1 * for time-only pattern * @param locale {@code locale}, non-null - * @param calType a {@code String},non-null representing CalendarType such as "japanese", + * @param calType a {@code String}, non-null representing CalendarType such as "japanese", * "iso8601" * @return formatting pattern {@code String} * @see java.time.format.DateTimeFormatterBuilder#convertStyle(java.time.format.FormatStyle) * @since 9 */ public abstract String getJavaTimeDateTimePattern(int timeStyle, int dateStyle, String calType, Locale locale); + + /** + * Returns the formatting pattern for the requested template, calendarType, and locale. + * Concrete implementation of this method will retrieve + * a java.time specific pattern from selected Locale Provider. + * + * @param requestedTemplate the requested template, not null + * @param calType a {@code String}, non-null representing CalendarType such as "japanese", + * "iso8601" + * @param locale {@code locale}, non-null + * @throws IllegalArgumentException if {@code requestedTemplate} does not match + * the regular expression syntax described in + * {@link java.time.format.DateTimeFormatterBuilder#appendLocalized(String)}. + * @throws DateTimeException if a match for the formatting pattern for + * {@code requestedTemplate} is not available + * @return formatting pattern {@code String} + * @since 19 + */ + public String getJavaTimeDateTimePattern(String requestedTemplate, String calType, Locale locale) { + // default implementation throws exception + throw new DateTimeException("Formatting pattern is not available for the requested template: " + requestedTemplate); + } } diff --git a/src/java.base/share/classes/sun/util/cldr/CLDRTimeZoneNameProviderImpl.java b/src/java.base/share/classes/sun/util/cldr/CLDRTimeZoneNameProviderImpl.java index 6d78d77f64d1d5669727318a92b05a5cfb70c57f..f97888a697783cfd5508dac07759419c4b1d49d8 100644 --- a/src/java.base/share/classes/sun/util/cldr/CLDRTimeZoneNameProviderImpl.java +++ b/src/java.base/share/classes/sun/util/cldr/CLDRTimeZoneNameProviderImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -82,7 +82,7 @@ public class CLDRTimeZoneNameProviderImpl extends TimeZoneNameProviderImpl { } if (namesSuper != null) { - // CLDR's resource bundle has an translated entry for this id. + // CLDR's resource bundle has a translated entry for this id. // Fix up names if needed, either missing or no-inheritance namesSuper[INDEX_TZID] = id; @@ -91,7 +91,7 @@ public class CLDRTimeZoneNameProviderImpl extends TimeZoneNameProviderImpl { case "": // Fill in empty elements deriveFallbackName(namesSuper, i, locale, - !TimeZone.getTimeZone(id).useDaylightTime()); + TimeZone.getTimeZone(id).toZoneId().getRules().isFixedOffset()); break; case NO_INHERITANCE_MARKER: // CLDR's "no inheritance marker" @@ -129,7 +129,7 @@ public class CLDRTimeZoneNameProviderImpl extends TimeZoneNameProviderImpl { // Derive fallback time zone name according to LDML's logic private void deriveFallbackNames(String[] names, Locale locale) { - boolean noDST = !TimeZone.getTimeZone(names[0]).useDaylightTime(); + boolean noDST = TimeZone.getTimeZone(names[0]).toZoneId().getRules().isFixedOffset(); for (int i = INDEX_STD_LONG; i <= INDEX_GEN_SHORT; i++) { deriveFallbackName(names, i, locale, noDST); @@ -149,13 +149,12 @@ public class CLDRTimeZoneNameProviderImpl extends TimeZoneNameProviderImpl { return; } - // Check parent locale first + // Check parent locales first if (!exists(names, index)) { - CLDRLocaleProviderAdapter clpa = (CLDRLocaleProviderAdapter)LocaleProviderAdapter.forType(Type.CLDR); - var cands = clpa.getCandidateLocales("", locale); - if (cands.size() > 1) { - var parentLoc = cands.get(1); // immediate parent locale - String[] parentNames = super.getDisplayNameArray(id, parentLoc); + var cands = ((CLDRLocaleProviderAdapter)LocaleProviderAdapter.forType(Type.CLDR)) + .getCandidateLocales("", locale); + for (int i = 1; i < cands.size() ; i++) { + String[] parentNames = super.getDisplayNameArray(id, cands.get(i)); if (parentNames != null && !parentNames[index].isEmpty()) { names[index] = parentNames[index]; return; @@ -163,18 +162,20 @@ public class CLDRTimeZoneNameProviderImpl extends TimeZoneNameProviderImpl { } } + // Type Fallback + if (noDST && typeFallback(names, index)) { + return; + } + // Check if COMPAT can substitute the name - if (LocaleProviderAdapter.getAdapterPreference().contains(Type.JRE)) { + if (!exists(names, index) && + LocaleProviderAdapter.getAdapterPreference().contains(Type.JRE)) { String[] compatNames = (String[])LocaleProviderAdapter.forJRE() - .getLocaleResources(mapChineseLocale(locale)) - .getTimeZoneNames(id); + .getLocaleResources(mapChineseLocale(locale)) + .getTimeZoneNames(id); if (compatNames != null) { - for (int i = INDEX_STD_LONG; i <= INDEX_GEN_SHORT; i++) { - // Assumes COMPAT has no empty slots - if (i == index || !exists(names, i)) { - names[i] = compatNames[i]; - } - } + // Assumes COMPAT has no empty slots + names[index] = compatNames[index]; return; } } @@ -184,11 +185,6 @@ public class CLDRTimeZoneNameProviderImpl extends TimeZoneNameProviderImpl { return; } - // Type Fallback - if (noDST && typeFallback(names, index)) { - return; - } - // last resort names[index] = toGMTFormat(id, index == INDEX_DST_LONG || index == INDEX_DST_SHORT, @@ -234,6 +230,11 @@ public class CLDRTimeZoneNameProviderImpl extends TimeZoneNameProviderImpl { } private boolean regionFormatFallback(String[] names, int index, Locale l) { + if (index % 2 == 0) { + // ignore short names + return false; + } + String id = names[INDEX_TZID]; LocaleResources lr = LocaleProviderAdapter.forType(Type.CLDR).getLocaleResources(l); ResourceBundle fd = lr.getJavaTimeFormatData(); diff --git a/src/java.base/share/classes/sun/util/locale/LocaleMatcher.java b/src/java.base/share/classes/sun/util/locale/LocaleMatcher.java index 93629220de5586df5347a756ee2dcbc4d29c942b..72844b966d032c90566024927a2c800b564d92b7 100644 --- a/src/java.base/share/classes/sun/util/locale/LocaleMatcher.java +++ b/src/java.base/share/classes/sun/util/locale/LocaleMatcher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -83,7 +83,7 @@ public final class LocaleMatcher { for (LanguageRange lr : priorityList) { String range = lr.getRange(); if (range.startsWith("*-") - || range.indexOf("-*") != -1) { // Extended range + || range.contains("-*")) { // Extended range if (mode == AUTOSELECT_FILTERING) { return filterExtended(priorityList, tags); } else if (mode == MAP_EXTENDED_RANGES) { @@ -124,8 +124,18 @@ public final class LocaleMatcher { for (LanguageRange lr : nonZeroRanges) { String range = lr.getRange(); if (range.equals("*")) { - tags = removeTagsMatchingBasicZeroRange(zeroRanges, tags); - return new ArrayList(tags); + for (String tag : tags) { + // change to lowercase for case-insensitive matching + String lowerCaseTag = tag.toLowerCase(Locale.ROOT); + + if (!caseInsensitiveMatch(list, lowerCaseTag) + && !shouldIgnoreFilterBasicMatch(zeroRanges, lowerCaseTag)) { + // preserving the case of the input tag + list.add(tag); + } + } + + break; } else { for (String tag : tags) { // change to lowercase for case-insensitive matching @@ -148,44 +158,6 @@ public final class LocaleMatcher { return list; } - /** - * Removes the tag(s) which are falling in the basic exclusion range(s) i.e - * range(s) with q=0 and returns the updated collection. If the basic - * language ranges contains '*' as one of its non zero range then instead of - * returning all the tags, remove those which are matching the range with - * quality weight q=0. - */ - private static Collection removeTagsMatchingBasicZeroRange( - List zeroRange, Collection tags) { - if (zeroRange.isEmpty()) { - tags = removeDuplicates(tags); - return tags; - } - - List matchingTags = new ArrayList<>(); - for (String tag : tags) { - // change to lowercase for case-insensitive matching - String lowerCaseTag = tag.toLowerCase(Locale.ROOT); - if (!shouldIgnoreFilterBasicMatch(zeroRange, lowerCaseTag) - && !caseInsensitiveMatch(matchingTags, lowerCaseTag)) { - matchingTags.add(tag); // preserving the case of the input tag - } - } - - return matchingTags; - } - - /** - * Remove duplicate tags from the given {@code tags} by - * ignoring case considerations. - */ - private static Collection removeDuplicates( - Collection tags) { - Set distinctTags = new TreeSet<>(String.CASE_INSENSITIVE_ORDER); - return tags.stream().filter(x -> distinctTags.add(x)) - .toList(); - } - /** * Returns true if the given {@code list} contains an element which matches * with the given {@code tag} ignoring case considerations. @@ -240,8 +212,18 @@ public final class LocaleMatcher { for (LanguageRange lr : nonZeroRanges) { String range = lr.getRange(); if (range.equals("*")) { - tags = removeTagsMatchingExtendedZeroRange(zeroRanges, tags); - return new ArrayList(tags); + for (String tag : tags) { + // change to lowercase for case-insensitive matching + String lowerCaseTag = tag.toLowerCase(Locale.ROOT); + + if (!caseInsensitiveMatch(list, lowerCaseTag) + && !shouldIgnoreFilterExtendedMatch(zeroRanges, lowerCaseTag)) { + // preserving the case of the input tag + list.add(tag); + } + } + + break; } String[] rangeSubtags = range.split("-"); for (String tag : tags) { @@ -267,33 +249,6 @@ public final class LocaleMatcher { return list; } - /** - * Removes the tag(s) which are falling in the extended exclusion range(s) - * i.e range(s) with q=0 and returns the updated collection. If the extended - * language ranges contains '*' as one of its non zero range then instead of - * returning all the tags, remove those which are matching the range with - * quality weight q=0. - */ - private static Collection removeTagsMatchingExtendedZeroRange( - List zeroRange, Collection tags) { - if (zeroRange.isEmpty()) { - tags = removeDuplicates(tags); - return tags; - } - - List matchingTags = new ArrayList<>(); - for (String tag : tags) { - // change to lowercase for case-insensitive matching - String lowerCaseTag = tag.toLowerCase(Locale.ROOT); - if (!shouldIgnoreFilterExtendedMatch(zeroRange, lowerCaseTag) - && !caseInsensitiveMatch(matchingTags, lowerCaseTag)) { - matchingTags.add(tag); // preserve the case of the input tag - } - } - - return matchingTags; - } - /** * The tag which is falling in the extended exclusion range(s) should * not be considered as the matching tag. Ignores the tag matching with the diff --git a/src/java.base/share/classes/sun/util/locale/provider/JavaTimeDateTimePatternImpl.java b/src/java.base/share/classes/sun/util/locale/provider/JavaTimeDateTimePatternImpl.java index 41de2dd7f650a7ec1de8f5baefe21a2e3b64eaf0..c39cea799b3b7ae432800072f7f66f1de2db4747 100644 --- a/src/java.base/share/classes/sun/util/locale/provider/JavaTimeDateTimePatternImpl.java +++ b/src/java.base/share/classes/sun/util/locale/provider/JavaTimeDateTimePatternImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -24,7 +24,10 @@ */ package sun.util.locale.provider; +import java.time.DateTimeException; import java.util.Locale; +import java.util.Objects; +import java.util.Optional; import java.util.Set; import sun.text.spi.JavaTimeDateTimePatternProvider; @@ -63,10 +66,21 @@ public class JavaTimeDateTimePatternImpl extends JavaTimeDateTimePatternProvider @Override public String getJavaTimeDateTimePattern(int timeStyle, int dateStyle, String calType, Locale locale) { LocaleResources lr = LocaleProviderAdapter.getResourceBundleBased().getLocaleResources(locale); - String pattern = lr.getJavaTimeDateTimePattern( - timeStyle, dateStyle, calType); - return pattern; + return lr.getJavaTimeDateTimePattern(timeStyle, dateStyle, calType); + } + @Override + public String getJavaTimeDateTimePattern(String requestedTemplate, String calType, Locale locale) { + LocaleProviderAdapter lpa = LocaleProviderAdapter.getResourceBundleBased(); + return ((ResourceBundleBasedAdapter)lpa).getCandidateLocales("", locale).stream() + .map(lpa::getLocaleResources) + .map(lr -> lr.getLocalizedPattern(requestedTemplate, calType)) + .filter(Objects::nonNull) + .findFirst() + .or(() -> calType.equals("generic") ? Optional.empty(): + Optional.of(getJavaTimeDateTimePattern(requestedTemplate, "generic", locale))) + .orElseThrow(() -> new DateTimeException("Requested template \"" + requestedTemplate + + "\" cannot be resolved in the locale \"" + locale + "\"")); } @Override diff --git a/src/java.base/share/classes/sun/util/locale/provider/LocaleResources.java b/src/java.base/share/classes/sun/util/locale/provider/LocaleResources.java index b6351cf1aca9a2702324dd9ddbbde34ba881d57d..aa991359c6801abc40cfc3635565ac0c400d3774 100644 --- a/src/java.base/share/classes/sun/util/locale/provider/LocaleResources.java +++ b/src/java.base/share/classes/sun/util/locale/provider/LocaleResources.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -46,15 +46,21 @@ import java.text.MessageFormat; import java.text.NumberFormat; import java.util.Arrays; import java.util.Calendar; +import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashSet; +import java.util.List; import java.util.Locale; +import java.util.Map; import java.util.Objects; import java.util.ResourceBundle; import java.util.Set; import java.util.TimeZone; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import java.util.regex.Pattern; +import java.util.stream.Stream; + import sun.security.action.GetPropertyAction; import sun.util.resources.LocaleData; import sun.util.resources.OpenListResourceBundle; @@ -91,6 +97,10 @@ public class LocaleResources { private static final String COMPACT_NUMBER_PATTERNS_CACHEKEY = "CNP"; private static final String DATE_TIME_PATTERN = "DTP."; private static final String RULES_CACHEKEY = "RULE"; + private static final String SKELETON_PATTERN = "SP."; + + // ResourceBundle key names for skeletons + private static final String SKELETON_INPUT_REGIONS_KEY = "DateFormatItemInputRegions"; // TimeZoneNamesBundle exemplar city prefix private static final String TZNB_EXCITY_PREFIX = "timezone.excity."; @@ -98,6 +108,31 @@ public class LocaleResources { // null singleton cache value private static final Object NULLOBJECT = new Object(); + // RegEx pattern for skeleton validity checking + private static final Pattern VALID_SKELETON_PATTERN = Pattern.compile( + "(?" + + "G{0,5}" + // Era + "y*" + // Year + "Q{0,5}" + // Quarter + "M{0,5}" + // Month + "w*" + // Week of Week Based Year + "E{0,5}" + // Day of Week + "d{0,2})" + // Day of Month + "(?

          For example, if an annotation * processor tries to create a source file, {@code * GeneratedFromUserSource}, in response to processing * @@ -126,9 +132,6 @@ import java.io.IOException; * factories instead of public constructors so that only subclass * instances would be presented to clients of the parent class. * - * @author Joseph D. Darcy - * @author Scott Seligman - * @author Peter von der Ahé * @since 1.6 */ public interface Filer { diff --git a/src/java.compiler/share/classes/javax/annotation/processing/FilerException.java b/src/java.compiler/share/classes/javax/annotation/processing/FilerException.java index 0e7d9cdda76a74a7974250611e704ef68a5dedc4..26ee999e5335a8900855d14b2ebf09003b1e6e15 100644 --- a/src/java.compiler/share/classes/javax/annotation/processing/FilerException.java +++ b/src/java.compiler/share/classes/javax/annotation/processing/FilerException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -35,9 +35,6 @@ import java.io.IOException; * interface or package, and not creating files for classes or * interfaces with invalid names. * - * @author Joseph D. Darcy - * @author Scott Seligman - * @author Peter von der Ahé * @since 1.6 */ public class FilerException extends IOException { diff --git a/src/java.compiler/share/classes/javax/annotation/processing/Messager.java b/src/java.compiler/share/classes/javax/annotation/processing/Messager.java index a5f7add18f6eb105af2959834249ad35d4ac3658..11127a73108b0dd13f12a33cb426fb87c515bbfb 100644 --- a/src/java.compiler/share/classes/javax/annotation/processing/Messager.java +++ b/src/java.compiler/share/classes/javax/annotation/processing/Messager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -46,9 +46,6 @@ import javax.lang.model.element.*; * choose to present this information in a different fashion, such as * messages in a window. * - * @author Joseph D. Darcy - * @author Scott Seligman - * @author Peter von der Ahé * @see ProcessingEnvironment#getLocale * @since 1.6 */ diff --git a/src/java.compiler/share/classes/javax/annotation/processing/ProcessingEnvironment.java b/src/java.compiler/share/classes/javax/annotation/processing/ProcessingEnvironment.java index 2a31129c3191df77bf0cd5cee9880f041a1e2c27..9c04acb3e0bf335b0f2461eae0db75e383f8cbee 100644 --- a/src/java.compiler/share/classes/javax/annotation/processing/ProcessingEnvironment.java +++ b/src/java.compiler/share/classes/javax/annotation/processing/ProcessingEnvironment.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -53,9 +53,6 @@ import javax.lang.model.util.Types; * of a wrapper class must know whether or not the same base facility * object has been wrapped before.) * - * @author Joseph D. Darcy - * @author Scott Seligman - * @author Peter von der Ahé * @since 1.6 */ public interface ProcessingEnvironment { diff --git a/src/java.compiler/share/classes/javax/annotation/processing/Processor.java b/src/java.compiler/share/classes/javax/annotation/processing/Processor.java index d70910c9d49a2e8fe16affcc065ef3fbc33fbc97..01de039d2c2c8bd88c05a579c4ca26cdf9c10d3e 100644 --- a/src/java.compiler/share/classes/javax/annotation/processing/Processor.java +++ b/src/java.compiler/share/classes/javax/annotation/processing/Processor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -198,9 +198,6 @@ import javax.lang.model.SourceVersion; * to extend {@link AbstractProcessor} rather than implementing this * interface directly. * - * @author Joseph D. Darcy - * @author Scott Seligman - * @author Peter von der Ahé * @since 1.6 */ public interface Processor { diff --git a/src/java.compiler/share/classes/javax/annotation/processing/RoundEnvironment.java b/src/java.compiler/share/classes/javax/annotation/processing/RoundEnvironment.java index 6323bda133914568927acb8d95210b31d88f3914..4c8144016472d735c7c02038f6e1934b814a6423 100644 --- a/src/java.compiler/share/classes/javax/annotation/processing/RoundEnvironment.java +++ b/src/java.compiler/share/classes/javax/annotation/processing/RoundEnvironment.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -37,9 +37,6 @@ import java.lang.annotation.Annotation; * implementing this interface} so that the processor can query for * information about a round of annotation processing. * - * @author Joseph D. Darcy - * @author Scott Seligman - * @author Peter von der Ahé * @since 1.6 */ public interface RoundEnvironment { diff --git a/src/java.compiler/share/classes/javax/annotation/processing/SupportedAnnotationTypes.java b/src/java.compiler/share/classes/javax/annotation/processing/SupportedAnnotationTypes.java index bb6c87ef7e2212acbdfd95bdf4e022951c4a3df0..8eb2fc3fd2f0e16719873e0c0f31f9ea6a479b7b 100644 --- a/src/java.compiler/share/classes/javax/annotation/processing/SupportedAnnotationTypes.java +++ b/src/java.compiler/share/classes/javax/annotation/processing/SupportedAnnotationTypes.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -38,9 +38,6 @@ import static java.lang.annotation.ElementType.*; * Processor#getSupportedAnnotationTypes strings conforming to the * grammar} should be used as values. * - * @author Joseph D. Darcy - * @author Scott Seligman - * @author Peter von der Ahé * @since 1.6 */ @Documented diff --git a/src/java.compiler/share/classes/javax/annotation/processing/SupportedOptions.java b/src/java.compiler/share/classes/javax/annotation/processing/SupportedOptions.java index 7f8817a011cc099609aaa44426f49c398ea9af31..321a0a03df2ee2dc3710cc7f72a427c4b7ce2943 100644 --- a/src/java.compiler/share/classes/javax/annotation/processing/SupportedOptions.java +++ b/src/java.compiler/share/classes/javax/annotation/processing/SupportedOptions.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -37,9 +37,6 @@ import static java.lang.annotation.ElementType.*; * Processor#getSupportedOptions strings conforming to the * grammar} should be used as values. * - * @author Joseph D. Darcy - * @author Scott Seligman - * @author Peter von der Ahé * @since 1.6 */ @Documented diff --git a/src/java.compiler/share/classes/javax/annotation/processing/SupportedSourceVersion.java b/src/java.compiler/share/classes/javax/annotation/processing/SupportedSourceVersion.java index 18fa42075a83ca421f3008dd51345c4d02cbfa73..487bfce686c7906986e0bc581aefe75e45111ad9 100644 --- a/src/java.compiler/share/classes/javax/annotation/processing/SupportedSourceVersion.java +++ b/src/java.compiler/share/classes/javax/annotation/processing/SupportedSourceVersion.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -38,9 +38,6 @@ import javax.lang.model.SourceVersion; * result from the value of this annotation, as done by {@link * AbstractProcessor#getSupportedSourceVersion}. * - * @author Joseph D. Darcy - * @author Scott Seligman - * @author Peter von der Ahé * @since 1.6 */ @Documented diff --git a/src/java.compiler/share/classes/javax/annotation/processing/package-info.java b/src/java.compiler/share/classes/javax/annotation/processing/package-info.java index 64bbf611032c3881c0e1e0df7a9722fb9334ba94..fec9c2900585e3dd09661c7b4e1bea96e0bf7e10 100644 --- a/src/java.compiler/share/classes/javax/annotation/processing/package-info.java +++ b/src/java.compiler/share/classes/javax/annotation/processing/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -35,9 +35,6 @@ *

          Unless otherwise specified, methods in this package will throw * a {@code NullPointerException} if given a {@code null} argument. * - * @author Joseph D. Darcy - * @author Scott Seligman - * @author Peter von der Ahé * @since 1.6 */ package javax.annotation.processing; diff --git a/src/java.compiler/share/classes/javax/lang/model/SourceVersion.java b/src/java.compiler/share/classes/javax/lang/model/SourceVersion.java index 32adcd11fff33c22b3e7b068575c8e7ce4ec6def..c31a2eb7d8e685901105d42ade3f7961eb504200 100644 --- a/src/java.compiler/share/classes/javax/lang/model/SourceVersion.java +++ b/src/java.compiler/share/classes/javax/lang/model/SourceVersion.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -39,9 +39,6 @@ import java.util.HashSet; *

          Note that additional source version constants will be added to * model future releases of the language. * - * @author Joseph D. Darcy - * @author Scott Seligman - * @author Peter von der Ahé * @since 1.6 */ public enum SourceVersion { @@ -252,7 +249,15 @@ public enum SourceVersion { * * @since 18 */ - RELEASE_18; + RELEASE_18, + + /** + * The version recognized by the Java Platform, Standard Edition + * 19. + * + * @since 19 + */ + RELEASE_19; // Note that when adding constants for newer releases, the // behavior of latest() and latestSupported() must be updated too. @@ -261,7 +266,7 @@ public enum SourceVersion { * {@return the latest source version that can be modeled} */ public static SourceVersion latest() { - return RELEASE_18; + return RELEASE_19; } private static final SourceVersion latestSupported = getLatestSupported(); @@ -276,7 +281,7 @@ public enum SourceVersion { private static SourceVersion getLatestSupported() { int intVersion = Runtime.version().feature(); return (intVersion >= 11) ? - valueOf("RELEASE_" + Math.min(18, intVersion)): + valueOf("RELEASE_" + Math.min(19, intVersion)): RELEASE_10; } @@ -312,8 +317,8 @@ public enum SourceVersion { * Character#isJavaIdentifierStart(int)} returns {@code true}, * followed only by characters for which {@link * Character#isJavaIdentifierPart(int)} returns {@code true}. - * This pattern matches regular identifiers, keywords, restricted - * keywords, restricted identifiers and the literals {@code "true"}, + * This pattern matches regular identifiers, keywords, contextual + * keywords, and the literals {@code "true"}, * {@code "false"}, {@code "null"}. * * The method returns {@code false} for all other strings. @@ -359,8 +364,8 @@ public enum SourceVersion { * {@code false} for keywords, boolean literals, and the null * literal in any segment. * - * This method returns {@code true} for restricted - * keywords and restricted identifiers. + * This method returns {@code true} for contextual + * keywords. * * @param name the string to check * @return {@code true} if this string is a @@ -385,8 +390,8 @@ public enum SourceVersion { * {@code false} for keywords, boolean literals, and the null * literal in any segment. * - * This method returns {@code true} for restricted - * keywords and restricted identifiers. + * This method returns {@code true} for contextual + * keywords. * * @param name the string to check * @param version the version to use @@ -409,8 +414,8 @@ public enum SourceVersion { /** * Returns whether or not {@code s} is a keyword, boolean literal, * or null literal in the latest source version. - * This method returns {@code false} for restricted - * keywords and restricted identifiers. + * This method returns {@code false} for contextual + * keywords. * * @param s the string to check * @return {@code true} if {@code s} is a keyword, or boolean @@ -426,8 +431,8 @@ public enum SourceVersion { /** * Returns whether or not {@code s} is a keyword, boolean literal, * or null literal in the given source version. - * This method returns {@code false} for restricted - * keywords and restricted identifiers. + * This method returns {@code false} for contextual + * keywords. * * @param s the string to check * @param version the version to use diff --git a/src/java.compiler/share/classes/javax/lang/model/UnknownEntityException.java b/src/java.compiler/share/classes/javax/lang/model/UnknownEntityException.java index 3e2cee42400a2331ece4be02f9f85b5070c80749..2ca3a1d988c765d3207f186415b9cdb7e9e2b8c3 100644 --- a/src/java.compiler/share/classes/javax/lang/model/UnknownEntityException.java +++ b/src/java.compiler/share/classes/javax/lang/model/UnknownEntityException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 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 @@ -32,7 +32,6 @@ package javax.lang.model; * this exception may be thrown by visitors to indicate that the * visitor was created for a prior version of the language. * - * @author Joseph D. Darcy * @see javax.lang.model.element.UnknownElementException * @see javax.lang.model.element.UnknownAnnotationValueException * @see javax.lang.model.type.UnknownTypeException diff --git a/src/java.compiler/share/classes/javax/lang/model/element/AnnotationMirror.java b/src/java.compiler/share/classes/javax/lang/model/element/AnnotationMirror.java index e1c3a86883d311a7f590b4b93462b505b43fe062..8986463832518c0b0aac29b97784ab5131b1e6d7 100644 --- a/src/java.compiler/share/classes/javax/lang/model/element/AnnotationMirror.java +++ b/src/java.compiler/share/classes/javax/lang/model/element/AnnotationMirror.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -36,9 +36,6 @@ import javax.lang.model.type.DeclaredType; * method. There is no guarantee that any particular annotation will * always be represented by the same object. * - * @author Joseph D. Darcy - * @author Scott Seligman - * @author Peter von der Ahé * @since 1.6 */ public interface AnnotationMirror { diff --git a/src/java.compiler/share/classes/javax/lang/model/element/AnnotationValue.java b/src/java.compiler/share/classes/javax/lang/model/element/AnnotationValue.java index ed7a180537e0aa57bffc04ca884de6e6d7b00352..77521dac191659c7410c8a03c24bc96dd9455b5d 100644 --- a/src/java.compiler/share/classes/javax/lang/model/element/AnnotationValue.java +++ b/src/java.compiler/share/classes/javax/lang/model/element/AnnotationValue.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -37,9 +37,6 @@ package javax.lang.model.element; * (representing the elements, in declared order, if the value is an array) * * - * @author Joseph D. Darcy - * @author Scott Seligman - * @author Peter von der Ahé * @since 1.6 */ public interface AnnotationValue { diff --git a/src/java.compiler/share/classes/javax/lang/model/element/AnnotationValueVisitor.java b/src/java.compiler/share/classes/javax/lang/model/element/AnnotationValueVisitor.java index be66b95e4fc60e033dcd98cf568a1c06272989d8..71292a4ee3cb5a3e3bb95979aa360607c734a15d 100644 --- a/src/java.compiler/share/classes/javax/lang/model/element/AnnotationValueVisitor.java +++ b/src/java.compiler/share/classes/javax/lang/model/element/AnnotationValueVisitor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -115,9 +115,6 @@ import javax.lang.model.util.*; * * @param the return type of this visitor's methods * @param

          the type of the additional parameter to this visitor's methods. - * @author Joseph D. Darcy - * @author Scott Seligman - * @author Peter von der Ahé * @since 1.6 */ public interface AnnotationValueVisitor { diff --git a/src/java.compiler/share/classes/javax/lang/model/element/Element.java b/src/java.compiler/share/classes/javax/lang/model/element/Element.java index 0cb49fd985f32ed92cf4df359a8570d4847bc9e9..df2ecee8243abdafa5121761706222f4ae1ab72e 100644 --- a/src/java.compiler/share/classes/javax/lang/model/element/Element.java +++ b/src/java.compiler/share/classes/javax/lang/model/element/Element.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -52,9 +52,6 @@ import javax.lang.model.util.*; * hierarchy since an implementation may choose to have a single object * implement multiple {@code Element} subinterfaces. * - * @author Joseph D. Darcy - * @author Scott Seligman - * @author Peter von der Ahé * @see Elements * @see TypeMirror * @since 1.6 diff --git a/src/java.compiler/share/classes/javax/lang/model/element/ElementKind.java b/src/java.compiler/share/classes/javax/lang/model/element/ElementKind.java index 2639358cb74b50d134e17f8c470f704d91c63a07..4190e2acdab31579a4f7400c62a2ec223c24719d 100644 --- a/src/java.compiler/share/classes/javax/lang/model/element/ElementKind.java +++ b/src/java.compiler/share/classes/javax/lang/model/element/ElementKind.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -32,9 +32,6 @@ package javax.lang.model.element; * to accommodate new, currently unknown, language structures added to * future versions of the Java programming language. * - * @author Joseph D. Darcy - * @author Scott Seligman - * @author Peter von der Ahé * @see Element * @since 1.6 */ @@ -136,7 +133,6 @@ public enum ElementKind { * * @return {@code true} if this is a kind of class */ - @SuppressWarnings("preview") public boolean isClass() { return this == CLASS || this == ENUM || this == RECORD; } @@ -151,6 +147,17 @@ public enum ElementKind { return this == INTERFACE || this == ANNOTATION_TYPE; } + /** + * {@return {@code true} if this is a kind of declared type, a + * {@linkplain #isClass() class} or an {@linkplain #isInterface() + * interface}, and {@code false} otherwise} + * + * @since 19 + */ + public boolean isDeclaredType() { + return isClass() || isInterface(); + } + /** * Returns {@code true} if this is a kind of field: * either {@code FIELD} or {@code ENUM_CONSTANT}. @@ -160,4 +167,50 @@ public enum ElementKind { public boolean isField() { return this == FIELD || this == ENUM_CONSTANT; } + + /** + * Returns {@code true} if this is a kind of executable: either + * {@code METHOD} or {@code CONSTRUCTOR} or {@code STATIC_INIT} or + * {@code INSTANCE_INIT}. + * + * @return {@code true} if this is a kind of executable + * @since 19 + */ + public boolean isExecutable() { + return switch(this) { + case METHOD, CONSTRUCTOR, STATIC_INIT, INSTANCE_INIT -> true; + default -> false; + }; + } + + /** + * Returns {@code true} if this is a kind of initializer: either + * {@code STATIC_INIT} or {@code INSTANCE_INIT}. + * + * @return {@code true} if this is a kind of initializer + * @since 19 + */ + public boolean isInitializer() { + return switch(this) { + case STATIC_INIT, INSTANCE_INIT -> true; + default -> false; + }; + } + /** + * Returns {@code true} if this is a kind of variable: including + * {@code ENUM_CONSTANT}, {@code FIELD}, {@code PARAMETER}, + * {@code LOCAL_VARIABLE}, {@code EXCEPTION_PARAMETER}, + * {@code RESOURCE_VARIABLE}, and {@code BINDING_VARIABLE}. + * + * @return {@code true} if this is a kind of variable + * @since 19 + */ + public boolean isVariable() { + return switch(this) { + case ENUM_CONSTANT, FIELD, PARAMETER, + LOCAL_VARIABLE, EXCEPTION_PARAMETER, RESOURCE_VARIABLE, + BINDING_VARIABLE -> true; + default -> false; + }; + } } diff --git a/src/java.compiler/share/classes/javax/lang/model/element/ElementVisitor.java b/src/java.compiler/share/classes/javax/lang/model/element/ElementVisitor.java index e921a9ba2d63de986c1d057f6bcfaa04973a2dae..03ca36ba434efef1c103ed6d060f493714c801fe 100644 --- a/src/java.compiler/share/classes/javax/lang/model/element/ElementVisitor.java +++ b/src/java.compiler/share/classes/javax/lang/model/element/ElementVisitor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -117,9 +117,6 @@ import javax.lang.model.util.*; * methods. Use {@code Void} for visitors that do not need an * additional parameter. * - * @author Joseph D. Darcy - * @author Scott Seligman - * @author Peter von der Ahé * @since 1.6 */ public interface ElementVisitor { diff --git a/src/java.compiler/share/classes/javax/lang/model/element/ExecutableElement.java b/src/java.compiler/share/classes/javax/lang/model/element/ExecutableElement.java index 9f8e3997781c75516010419c0ff1de85fa0c45a4..3bc0457755260a85244d256aa13aa333213a4cd1 100644 --- a/src/java.compiler/share/classes/javax/lang/model/element/ExecutableElement.java +++ b/src/java.compiler/share/classes/javax/lang/model/element/ExecutableElement.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -33,9 +33,6 @@ import javax.lang.model.type.*; * instance) of a class or interface, including annotation type * elements. * - * @author Joseph D. Darcy - * @author Scott Seligman - * @author Peter von der Ahé * @see ExecutableType * @since 1.6 */ @@ -131,6 +128,12 @@ public interface ExecutableElement extends Element, Parameterizable { */ AnnotationValue getDefaultValue(); + /** + * {@return the class or interface defining the executable} + */ + @Override + Element getEnclosingElement(); + /** * {@return the simple name of a constructor, method, or * initializer} For a constructor, the name {@code ""} is diff --git a/src/java.compiler/share/classes/javax/lang/model/element/Modifier.java b/src/java.compiler/share/classes/javax/lang/model/element/Modifier.java index dfbd76d2bf1367e0057a5c0930d5d729b0a3cdf6..9dcd8390b60d6ca557a2e5a124f1b300bdbca3d5 100644 --- a/src/java.compiler/share/classes/javax/lang/model/element/Modifier.java +++ b/src/java.compiler/share/classes/javax/lang/model/element/Modifier.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -44,9 +44,6 @@ package javax.lang.model.element; * @jls 8.8.3 Constructor Modifiers * @jls 9.1.1 Interface Modifiers * - * @author Joseph D. Darcy - * @author Scott Seligman - * @author Peter von der Ahé * @since 1.6 */ diff --git a/src/java.compiler/share/classes/javax/lang/model/element/Name.java b/src/java.compiler/share/classes/javax/lang/model/element/Name.java index 9e40bcf740076b9e2721a8e581c3214c7338b070..70bc5e0ad6361e2961e75722c572ca8f00a4ddf7 100644 --- a/src/java.compiler/share/classes/javax/lang/model/element/Name.java +++ b/src/java.compiler/share/classes/javax/lang/model/element/Name.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 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 @@ -46,9 +46,6 @@ package javax.lang.model.element; * to each other, including successive annotation processing * {@linkplain javax.annotation.processing.RoundEnvironment rounds}. * - * @author Joseph D. Darcy - * @author Scott Seligman - * @author Peter von der Ahé * @see javax.lang.model.util.Elements#getName * @since 1.6 */ diff --git a/src/java.compiler/share/classes/javax/lang/model/element/NestingKind.java b/src/java.compiler/share/classes/javax/lang/model/element/NestingKind.java index 62cc65d8c5ad65723fb1bd05b6e091bb9bbc4c06..7f8cee373f70de03306edd8113d0a2b520f0b6ea 100644 --- a/src/java.compiler/share/classes/javax/lang/model/element/NestingKind.java +++ b/src/java.compiler/share/classes/javax/lang/model/element/NestingKind.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -76,9 +76,6 @@ package javax.lang.model.element; * } *

          * - * @author Joseph D. Darcy - * @author Scott Seligman - * @author Peter von der Ahé * @since 1.6 */ public enum NestingKind { diff --git a/src/java.compiler/share/classes/javax/lang/model/element/PackageElement.java b/src/java.compiler/share/classes/javax/lang/model/element/PackageElement.java index 42d62cb289c34edd5ae2f470b65d5f061ec799ec..f16daca0b0605f8b488a9a685ce6071f30d3ad29 100644 --- a/src/java.compiler/share/classes/javax/lang/model/element/PackageElement.java +++ b/src/java.compiler/share/classes/javax/lang/model/element/PackageElement.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -32,9 +32,6 @@ import javax.lang.model.type.TypeMirror; * Represents a package program element. Provides access to information * about the package and its members. * - * @author Joseph D. Darcy - * @author Scott Seligman - * @author Peter von der Ahé * @see javax.lang.model.util.Elements#getPackageOf * @since 1.6 */ diff --git a/src/java.compiler/share/classes/javax/lang/model/element/Parameterizable.java b/src/java.compiler/share/classes/javax/lang/model/element/Parameterizable.java index 55d9042bca8dbe489334c0a872bff2db742667ea..cf0bbdfba37531a3a2f53716548c07c6bc1f1b70 100644 --- a/src/java.compiler/share/classes/javax/lang/model/element/Parameterizable.java +++ b/src/java.compiler/share/classes/javax/lang/model/element/Parameterizable.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 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 @@ -30,7 +30,6 @@ import java.util.List; /** * A mixin interface for an element that has type parameters. * - * @author Joseph D. Darcy * @since 1.7 */ public interface Parameterizable extends Element { diff --git a/src/java.compiler/share/classes/javax/lang/model/element/QualifiedNameable.java b/src/java.compiler/share/classes/javax/lang/model/element/QualifiedNameable.java index fe7663aa578b1f082848c1400f76860064272eea..1b0316f893f51d3507fb50b5e508a68b8a92107b 100644 --- a/src/java.compiler/share/classes/javax/lang/model/element/QualifiedNameable.java +++ b/src/java.compiler/share/classes/javax/lang/model/element/QualifiedNameable.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 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 @@ -28,7 +28,6 @@ package javax.lang.model.element; /** * A mixin interface for an element that has a qualified name. * - * @author Joseph D. Darcy * @since 1.7 */ public interface QualifiedNameable extends Element { diff --git a/src/java.compiler/share/classes/javax/lang/model/element/TypeElement.java b/src/java.compiler/share/classes/javax/lang/model/element/TypeElement.java index ab6221b06d363a3be0b2fe7daa9f4d414cb03811..4f2caafdfe8e71f84072c680ff3cb4f382cda4a0 100644 --- a/src/java.compiler/share/classes/javax/lang/model/element/TypeElement.java +++ b/src/java.compiler/share/classes/javax/lang/model/element/TypeElement.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -53,9 +53,6 @@ import javax.lang.model.util.*; * source of information is Java source code, then the elements will be * returned in source code order. * - * @author Joseph D. Darcy - * @author Scott Seligman - * @author Peter von der Ahé * @see DeclaredType * @since 1.6 */ diff --git a/src/java.compiler/share/classes/javax/lang/model/element/TypeParameterElement.java b/src/java.compiler/share/classes/javax/lang/model/element/TypeParameterElement.java index bd8e0a3d1f6dc009e8e56db571b2f35b3204e3ff..cbaa8969126b4a0ce4a046fde589df9e2bb9c347 100644 --- a/src/java.compiler/share/classes/javax/lang/model/element/TypeParameterElement.java +++ b/src/java.compiler/share/classes/javax/lang/model/element/TypeParameterElement.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -34,9 +34,6 @@ import javax.lang.model.type.TypeVariable; * or constructor element. * A type parameter declares a {@link TypeVariable}. * - * @author Joseph D. Darcy - * @author Scott Seligman - * @author Peter von der Ahé * @see TypeVariable * @since 1.6 */ diff --git a/src/java.compiler/share/classes/javax/lang/model/element/UnknownAnnotationValueException.java b/src/java.compiler/share/classes/javax/lang/model/element/UnknownAnnotationValueException.java index efe761ef1c6b9662820f5896653386d48cae1680..869235d88d3d02ffdc0fbb53c984b956006b6223 100644 --- a/src/java.compiler/share/classes/javax/lang/model/element/UnknownAnnotationValueException.java +++ b/src/java.compiler/share/classes/javax/lang/model/element/UnknownAnnotationValueException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -35,9 +35,6 @@ import javax.lang.model.UnknownEntityException; * indicate that the visitor was created for a prior version of the * language. * - * @author Joseph D. Darcy - * @author Scott Seligman - * @author Peter von der Ahé * @see AnnotationValueVisitor#visitUnknown * @since 1.6 */ diff --git a/src/java.compiler/share/classes/javax/lang/model/element/UnknownDirectiveException.java b/src/java.compiler/share/classes/javax/lang/model/element/UnknownDirectiveException.java index 534183a3a933c37f63881ba84bd61484f83eebdc..7139573824af63080784bb886bf6203da3e5e661 100644 --- a/src/java.compiler/share/classes/javax/lang/model/element/UnknownDirectiveException.java +++ b/src/java.compiler/share/classes/javax/lang/model/element/UnknownDirectiveException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -34,9 +34,6 @@ import javax.lang.model.UnknownEntityException; * {@linkplain ModuleElement.DirectiveVisitor directive visitor} to * indicate that the visitor was created for a prior version of the language. * - * @author Joseph D. Darcy - * @author Scott Seligman - * @author Peter von der Ahé * @see ModuleElement.DirectiveVisitor#visitUnknown * @since 9 */ diff --git a/src/java.compiler/share/classes/javax/lang/model/element/UnknownElementException.java b/src/java.compiler/share/classes/javax/lang/model/element/UnknownElementException.java index 39779918c7167c6e1ce02ccdf1fab5d77dcac5e6..bb1f1d495b695dc0583e1448c3feae7a8f2598c4 100644 --- a/src/java.compiler/share/classes/javax/lang/model/element/UnknownElementException.java +++ b/src/java.compiler/share/classes/javax/lang/model/element/UnknownElementException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -34,9 +34,6 @@ import javax.lang.model.UnknownEntityException; * {@linkplain ElementVisitor element visitor} to indicate that the * visitor was created for a prior version of the language. * - * @author Joseph D. Darcy - * @author Scott Seligman - * @author Peter von der Ahé * @see ElementVisitor#visitUnknown * @since 1.6 */ diff --git a/src/java.compiler/share/classes/javax/lang/model/element/VariableElement.java b/src/java.compiler/share/classes/javax/lang/model/element/VariableElement.java index ac7a949d9bbea3a0791002a26d167eeb8e59f258..a838aa383b7d161d24e7eed668a250a853a14c73 100644 --- a/src/java.compiler/share/classes/javax/lang/model/element/VariableElement.java +++ b/src/java.compiler/share/classes/javax/lang/model/element/VariableElement.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -34,9 +34,6 @@ import javax.lang.model.type.TypeKind; * parameter, local variable, resource variable, or exception * parameter. * - * @author Joseph D. Darcy - * @author Scott Seligman - * @author Peter von der Ahé * @since 1.6 */ public interface VariableElement extends Element { diff --git a/src/java.compiler/share/classes/javax/lang/model/element/package-info.java b/src/java.compiler/share/classes/javax/lang/model/element/package-info.java index 094dd1825bd7ff20ec1c2c5fe643def98cf5cecc..aee2b235e79f41f86d01aaeb3dd95b65430d3324 100644 --- a/src/java.compiler/share/classes/javax/lang/model/element/package-info.java +++ b/src/java.compiler/share/classes/javax/lang/model/element/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -36,19 +36,20 @@ * appearing inside method bodies, such as local variables and * anonymous classes. * - *

          When used in the context of annotation processing, an accurate - * model of the element being represented must be returned. As this - * is a language model, the source code provides the fiducial - * (reference) representation of the construct in question rather than - * a representation in an executable output like a class file. - * Executable output may serve as the basis for creating a modeling - * element. However, the process of translating source code to - * executable output may not permit recovering some aspects of the - * source code representation. For example, annotations with - * {@linkplain java.lang.annotation.RetentionPolicy#SOURCE source} - * {@linkplain java.lang.annotation.Retention retention} cannot be - * recovered from class files and class files might not be able to - * provide source position information. + *

          When used in the context of annotation + * processing, an accurate model of the element being represented must + * be returned. As this is a language model, the source code provides + * the fiducial (reference) representation of the construct in + * question rather than a representation in an executable output like + * a class file. Executable output may serve as the basis for + * creating a modeling element. However, the process of translating + * source code to executable output may not permit recovering some + * aspects of the source code representation. For example, + * annotations with {@linkplain + * java.lang.annotation.RetentionPolicy#SOURCE source} {@linkplain + * java.lang.annotation.Retention retention} cannot be recovered from + * class files and class files might not be able to provide source + * position information. * * Names of {@linkplain * javax.lang.model.element.ExecutableElement#getParameters() @@ -106,9 +107,6 @@ *

          Unless otherwise specified, methods in this package will throw * a {@code NullPointerException} if given a {@code null} argument. * - * @author Joseph D. Darcy - * @author Scott Seligman - * @author Peter von der Ahé * @see javax.lang.model.util.Elements * @jls 6.1 Declarations * @jls 7.4 Package Declarations diff --git a/src/java.compiler/share/classes/javax/lang/model/package-info.java b/src/java.compiler/share/classes/javax/lang/model/package-info.java index fbdb003b1f2fcb987375fae28b00b812d8b0d5bc..65b0d407efb24b6cbd8c51f3fcfbc165e60b665b 100644 --- a/src/java.compiler/share/classes/javax/lang/model/package-info.java +++ b/src/java.compiler/share/classes/javax/lang/model/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -52,9 +52,6 @@ *

          Unless otherwise specified, methods in this package will throw * a {@code NullPointerException} if given a {@code null} argument. * - * @author Joseph D. Darcy - * @author Scott Seligman - * @author Peter von der Ahé * @since 1.6 */ diff --git a/src/java.compiler/share/classes/javax/lang/model/type/ArrayType.java b/src/java.compiler/share/classes/javax/lang/model/type/ArrayType.java index ac8c96c55f40ad959a900ab31a83bb5d0af36861..09e0de8b7e74dff08df6790b998acddc46cbb36d 100644 --- a/src/java.compiler/share/classes/javax/lang/model/type/ArrayType.java +++ b/src/java.compiler/share/classes/javax/lang/model/type/ArrayType.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -31,9 +31,6 @@ package javax.lang.model.type; * A multidimensional array type is represented as an array type * whose component type is also an array type. * - * @author Joseph D. Darcy - * @author Scott Seligman - * @author Peter von der Ahé * @since 1.6 */ public interface ArrayType extends ReferenceType { diff --git a/src/java.compiler/share/classes/javax/lang/model/type/DeclaredType.java b/src/java.compiler/share/classes/javax/lang/model/type/DeclaredType.java index 3f6857049b820d13dd248a7336925479fe252f0e..ae799981a6af7ec68998a1e52f660b9cc89a1d2c 100644 --- a/src/java.compiler/share/classes/javax/lang/model/type/DeclaredType.java +++ b/src/java.compiler/share/classes/javax/lang/model/type/DeclaredType.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -49,9 +49,6 @@ import javax.lang.model.util.Types; * Types#directSupertypes(TypeMirror)} method. This returns the * supertypes with any type arguments substituted in. * - * @author Joseph D. Darcy - * @author Scott Seligman - * @author Peter von der Ahé * @see TypeElement * @since 1.6 */ diff --git a/src/java.compiler/share/classes/javax/lang/model/type/ErrorType.java b/src/java.compiler/share/classes/javax/lang/model/type/ErrorType.java index 9d03ab93be987f09457822aa9f70632dffe07128..08654cdcb078d14333d8eef1d62b1f42ed4c00d7 100644 --- a/src/java.compiler/share/classes/javax/lang/model/type/ErrorType.java +++ b/src/java.compiler/share/classes/javax/lang/model/type/ErrorType.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -33,9 +33,6 @@ package javax.lang.model.type; * information derived from such a type (such as its members or its * supertype) will not, in general, return meaningful results. * - * @author Joseph D. Darcy - * @author Scott Seligman - * @author Peter von der Ahé * @since 1.6 */ public interface ErrorType extends DeclaredType { diff --git a/src/java.compiler/share/classes/javax/lang/model/type/ExecutableType.java b/src/java.compiler/share/classes/javax/lang/model/type/ExecutableType.java index f711ebcb79b7ebca2e0def057bdebe959facb2f9..19953ff5e4a12d4e7be296b52e9e956158a3938f 100644 --- a/src/java.compiler/share/classes/javax/lang/model/type/ExecutableType.java +++ b/src/java.compiler/share/classes/javax/lang/model/type/ExecutableType.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -41,9 +41,6 @@ import javax.lang.model.element.ExecutableElement; * type arguments are substituted into any types returned by the methods of * this interface. * - * @author Joseph D. Darcy - * @author Scott Seligman - * @author Peter von der Ahé * @see ExecutableElement * @since 1.6 */ diff --git a/src/java.compiler/share/classes/javax/lang/model/type/MirroredTypeException.java b/src/java.compiler/share/classes/javax/lang/model/type/MirroredTypeException.java index 21af5070a76aa2c9581bec8d13e3ede6ee94d50d..61117bc2cc6d0e1c14d6dba0054dd858b63a5169 100644 --- a/src/java.compiler/share/classes/javax/lang/model/type/MirroredTypeException.java +++ b/src/java.compiler/share/classes/javax/lang/model/type/MirroredTypeException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -34,9 +34,6 @@ import javax.lang.model.element.Element; * Thrown when an application attempts to access the {@link Class} object * corresponding to a {@link TypeMirror}. * - * @author Joseph D. Darcy - * @author Scott Seligman - * @author Peter von der Ahé * @see MirroredTypesException * @see Element#getAnnotation(Class) * @since 1.6 diff --git a/src/java.compiler/share/classes/javax/lang/model/type/MirroredTypesException.java b/src/java.compiler/share/classes/javax/lang/model/type/MirroredTypesException.java index 2cff3ffdaf6ec8bf703449f667c8e6d9f61b1aed..9fa3c5e8c3c01e3abe6e0d892c1325452ce985f8 100644 --- a/src/java.compiler/share/classes/javax/lang/model/type/MirroredTypesException.java +++ b/src/java.compiler/share/classes/javax/lang/model/type/MirroredTypesException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -37,9 +37,6 @@ import javax.lang.model.element.Element; * Thrown when an application attempts to access a sequence of {@link * Class} objects each corresponding to a {@link TypeMirror}. * - * @author Joseph D. Darcy - * @author Scott Seligman - * @author Peter von der Ahé * @see MirroredTypeException * @see Element#getAnnotation(Class) * @since 1.6 diff --git a/src/java.compiler/share/classes/javax/lang/model/type/NoType.java b/src/java.compiler/share/classes/javax/lang/model/type/NoType.java index 2be7e4b9b28ab6516c92fac0c3c7b142eb0a5256..84cb1297ef2c2353f9af0d139147bba7a2d7f003 100644 --- a/src/java.compiler/share/classes/javax/lang/model/type/NoType.java +++ b/src/java.compiler/share/classes/javax/lang/model/type/NoType.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -40,9 +40,6 @@ import javax.lang.model.element.ExecutableElement; * of {@code java.lang.Object}. * * - * @author Joseph D. Darcy - * @author Scott Seligman - * @author Peter von der Ahé * @see ExecutableElement#getReturnType() * @see javax.lang.model.util.Types#getNoType(TypeKind) * @since 1.6 diff --git a/src/java.compiler/share/classes/javax/lang/model/type/NullType.java b/src/java.compiler/share/classes/javax/lang/model/type/NullType.java index a846e07dc2e87f35cf779ef78f95243e3bd2b4c2..92feb514aab8c6cf9d4ed709342334cd9994536a 100644 --- a/src/java.compiler/share/classes/javax/lang/model/type/NullType.java +++ b/src/java.compiler/share/classes/javax/lang/model/type/NullType.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -28,11 +28,8 @@ package javax.lang.model.type; /** * Represents the null type. - * This is the type of the expression {@code null}, + * This is the type of the expression {@code null}. * - * @author Joseph D. Darcy - * @author Scott Seligman - * @author Peter von der Ahé * @jls 3.10.7 The Null Literal * @jls 4.1 The Kinds of Types and Values * @see javax.lang.model.util.Types#getNullType() diff --git a/src/java.compiler/share/classes/javax/lang/model/type/PrimitiveType.java b/src/java.compiler/share/classes/javax/lang/model/type/PrimitiveType.java index 343f4b619900cb6d4d9008803ed5fece5149d05a..2772726113b6fdd8fcd075ae6f3845a6b122a30c 100644 --- a/src/java.compiler/share/classes/javax/lang/model/type/PrimitiveType.java +++ b/src/java.compiler/share/classes/javax/lang/model/type/PrimitiveType.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -31,9 +31,6 @@ package javax.lang.model.type; * {@code boolean}, {@code byte}, {@code short}, {@code int}, * {@code long}, {@code char}, {@code float}, and {@code double}. * - * @author Joseph D. Darcy - * @author Scott Seligman - * @author Peter von der Ahé * @jls 4.2 Primitive Types and Values * @see javax.lang.model.util.Types#getPrimitiveType(TypeKind) * @since 1.6 diff --git a/src/java.compiler/share/classes/javax/lang/model/type/ReferenceType.java b/src/java.compiler/share/classes/javax/lang/model/type/ReferenceType.java index 9ab823ee81bbb17a488d4109c835a9c8dde46def..f9ce2dfcd6b311f29559f4f4596196b30d1a4fa0 100644 --- a/src/java.compiler/share/classes/javax/lang/model/type/ReferenceType.java +++ b/src/java.compiler/share/classes/javax/lang/model/type/ReferenceType.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -31,9 +31,6 @@ package javax.lang.model.type; * These include class and interface types, array types, type variables, * and the null type. * - * @author Joseph D. Darcy - * @author Scott Seligman - * @author Peter von der Ahé * @jls 4.3 Reference Types and Values * @since 1.6 */ diff --git a/src/java.compiler/share/classes/javax/lang/model/type/TypeKind.java b/src/java.compiler/share/classes/javax/lang/model/type/TypeKind.java index cd6ece839393447a03c8d730543c70d00c9e7e65..5a6b8974ef8a63265181db45ce4671359de20861 100644 --- a/src/java.compiler/share/classes/javax/lang/model/type/TypeKind.java +++ b/src/java.compiler/share/classes/javax/lang/model/type/TypeKind.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -33,9 +33,6 @@ package javax.lang.model.type; * accommodate new, currently unknown, language structures added to * future versions of the Java programming language. * - * @author Joseph D. Darcy - * @author Scott Seligman - * @author Peter von der Ahé * @see TypeMirror * @since 1.6 */ diff --git a/src/java.compiler/share/classes/javax/lang/model/type/TypeMirror.java b/src/java.compiler/share/classes/javax/lang/model/type/TypeMirror.java index 974f5439219cbdfe0efda3fd7e34a1f79714b059..a9a4613feb448f9c5fb06e19a2d7bc8b85f99458 100644 --- a/src/java.compiler/share/classes/javax/lang/model/type/TypeMirror.java +++ b/src/java.compiler/share/classes/javax/lang/model/type/TypeMirror.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -50,9 +50,6 @@ import javax.lang.model.util.Types; * hierarchy since an implementation may choose to have a single * object implement multiple {@code TypeMirror} subinterfaces. * - * @author Joseph D. Darcy - * @author Scott Seligman - * @author Peter von der Ahé * @see Element * @see Types * @jls 4.1 The Kinds of Types and Values diff --git a/src/java.compiler/share/classes/javax/lang/model/type/TypeVariable.java b/src/java.compiler/share/classes/javax/lang/model/type/TypeVariable.java index fbb06d6693443a8100524a7a998059d63597cf18..e5ab0458f693a644cb75b3f8a2bb3da171e8ff90 100644 --- a/src/java.compiler/share/classes/javax/lang/model/type/TypeVariable.java +++ b/src/java.compiler/share/classes/javax/lang/model/type/TypeVariable.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -41,9 +41,6 @@ import javax.lang.model.util.Types; * (see chapter {@jls 5} of * The Java Language Specification). * - * @author Joseph D. Darcy - * @author Scott Seligman - * @author Peter von der Ahé * @see TypeParameterElement * @jls 4.4 Type Variables * @since 1.6 diff --git a/src/java.compiler/share/classes/javax/lang/model/type/TypeVisitor.java b/src/java.compiler/share/classes/javax/lang/model/type/TypeVisitor.java index 7172c17a614117f4a6a3e2df968ec178df439c77..31d75fe7929405d4af675d59438abf19af93b49c 100644 --- a/src/java.compiler/share/classes/javax/lang/model/type/TypeVisitor.java +++ b/src/java.compiler/share/classes/javax/lang/model/type/TypeVisitor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -112,9 +112,6 @@ import javax.lang.model.util.*; * methods. Use {@code Void} for visitors that do not need an * additional parameter. * - * @author Joseph D. Darcy - * @author Scott Seligman - * @author Peter von der Ahé * @since 1.6 */ public interface TypeVisitor { diff --git a/src/java.compiler/share/classes/javax/lang/model/type/UnknownTypeException.java b/src/java.compiler/share/classes/javax/lang/model/type/UnknownTypeException.java index bd187d05145486a2f8139855a4632d750c682328..dac3fecf86c2b3aa0ae1b75af522396a57bee21b 100644 --- a/src/java.compiler/share/classes/javax/lang/model/type/UnknownTypeException.java +++ b/src/java.compiler/share/classes/javax/lang/model/type/UnknownTypeException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -34,9 +34,6 @@ import javax.lang.model.UnknownEntityException; * TypeVisitor type visitor} to indicate that the visitor was created * for a prior version of the language. * - * @author Joseph D. Darcy - * @author Scott Seligman - * @author Peter von der Ahé * @see TypeVisitor#visitUnknown * @since 1.6 */ diff --git a/src/java.compiler/share/classes/javax/lang/model/type/WildcardType.java b/src/java.compiler/share/classes/javax/lang/model/type/WildcardType.java index ee1d0dac5553c1b19c2a3569ea320517dac6d170..1ac9e25ffb65047b21f90e3ef689ac7eaa26807b 100644 --- a/src/java.compiler/share/classes/javax/lang/model/type/WildcardType.java +++ b/src/java.compiler/share/classes/javax/lang/model/type/WildcardType.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -38,9 +38,6 @@ package javax.lang.model.type; * {@code extends} clause, its lower bound explicitly set by a * {@code super} clause, or neither (but not both). * - * @author Joseph D. Darcy - * @author Scott Seligman - * @author Peter von der Ahé * @jls 4.5.1 Type Arguments of Parameterized Types * @since 1.6 */ diff --git a/src/java.compiler/share/classes/javax/lang/model/type/package-info.java b/src/java.compiler/share/classes/javax/lang/model/type/package-info.java index 13ec0f638bc9d7e8ffe07d5d8e863df0bb2ecd08..c5500d59ecb8ddc9a4eb4b1202e01be51e7df866 100644 --- a/src/java.compiler/share/classes/javax/lang/model/type/package-info.java +++ b/src/java.compiler/share/classes/javax/lang/model/type/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -33,9 +33,6 @@ *

          Unless otherwise specified, methods in this package will throw * a {@code NullPointerException} if given a {@code null} argument. * - * @author Joseph D. Darcy - * @author Scott Seligman - * @author Peter von der Ahé * @see javax.lang.model.util.Types * @jls 4.1 The Kinds of Types and Values * @jls 4.2 Primitive Types and Values diff --git a/src/java.compiler/share/classes/javax/lang/model/util/AbstractAnnotationValueVisitor14.java b/src/java.compiler/share/classes/javax/lang/model/util/AbstractAnnotationValueVisitor14.java index fa49170a7c621313a9b22d0b29ec652520a6cb97..004aa596b3a8004d5391961d95e7fd7db58565d0 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/AbstractAnnotationValueVisitor14.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/AbstractAnnotationValueVisitor14.java @@ -44,7 +44,7 @@ import javax.annotation.processing.SupportedSourceVersion; * @see AbstractAnnotationValueVisitor9 * @since 14 */ -@SupportedSourceVersion(RELEASE_18) +@SupportedSourceVersion(RELEASE_19) public abstract class AbstractAnnotationValueVisitor14 extends AbstractAnnotationValueVisitor9 { /** diff --git a/src/java.compiler/share/classes/javax/lang/model/util/AbstractAnnotationValueVisitor6.java b/src/java.compiler/share/classes/javax/lang/model/util/AbstractAnnotationValueVisitor6.java index 0bf5674a6fb2de0c9dfb5db034584395a1aad28d..9d30df232121f9e88c9ee1f601e0632ba706baf1 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/AbstractAnnotationValueVisitor6.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/AbstractAnnotationValueVisitor6.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -60,10 +60,6 @@ import javax.annotation.processing.SupportedSourceVersion; * @param the return type of this visitor's methods * @param

          the type of the additional parameter to this visitor's methods. * - * @author Joseph D. Darcy - * @author Scott Seligman - * @author Peter von der Ahé - * * @see AbstractAnnotationValueVisitor7 * @see AbstractAnnotationValueVisitor8 * @see AbstractAnnotationValueVisitor9 diff --git a/src/java.compiler/share/classes/javax/lang/model/util/AbstractElementVisitor14.java b/src/java.compiler/share/classes/javax/lang/model/util/AbstractElementVisitor14.java index 7c69778c89e765266205a02d0ee9c633eaf28b3f..8200e6c00deec0f3b93e5dd236f6686460ef3417 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/AbstractElementVisitor14.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/AbstractElementVisitor14.java @@ -49,7 +49,7 @@ import static javax.lang.model.SourceVersion.*; * @see AbstractElementVisitor9 * @since 16 */ -@SupportedSourceVersion(RELEASE_18) +@SupportedSourceVersion(RELEASE_19) public abstract class AbstractElementVisitor14 extends AbstractElementVisitor9 { /** * Constructor for concrete subclasses to call. diff --git a/src/java.compiler/share/classes/javax/lang/model/util/AbstractElementVisitor6.java b/src/java.compiler/share/classes/javax/lang/model/util/AbstractElementVisitor6.java index 38adeb00b266a380f52dea912830dd0ab796e22c..943c16f4d6ca45b68c8f7410a291f878a6bc4b7a 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/AbstractElementVisitor6.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/AbstractElementVisitor6.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -62,10 +62,6 @@ import static javax.lang.model.SourceVersion.*; * methods. Use {@code Void} for visitors that do not need an * additional parameter. * - * @author Joseph D. Darcy - * @author Scott Seligman - * @author Peter von der Ahé - * * @see AbstractElementVisitor7 * @see AbstractElementVisitor8 * @see AbstractElementVisitor9 @@ -159,7 +155,6 @@ public abstract class AbstractElementVisitor6 implements ElementVisitor extends AbstractTypeVisitor9 { /** * Constructor for concrete subclasses to call. diff --git a/src/java.compiler/share/classes/javax/lang/model/util/AbstractTypeVisitor6.java b/src/java.compiler/share/classes/javax/lang/model/util/AbstractTypeVisitor6.java index 52e2686e055cfba9746a05177943f21981dbcd0d..01609d4d51a85979b2b15f730348e739170ba98e 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/AbstractTypeVisitor6.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/AbstractTypeVisitor6.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -61,10 +61,6 @@ import static javax.lang.model.SourceVersion.*; * methods. Use {@code Void} for visitors that do not need an * additional parameter. * - * @author Joseph D. Darcy - * @author Scott Seligman - * @author Peter von der Ahé - * * @see AbstractTypeVisitor7 * @see AbstractTypeVisitor8 * @see AbstractTypeVisitor9 diff --git a/src/java.compiler/share/classes/javax/lang/model/util/ElementFilter.java b/src/java.compiler/share/classes/javax/lang/model/util/ElementFilter.java index 20589053776cf00ada922d4d2ef3803278665731..9df7959d8b94a08bdc18e3d8ed8613734c481a43 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/ElementFilter.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/ElementFilter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -55,10 +55,6 @@ import javax.lang.model.element.ModuleElement.UsesDirective; * arguments to methods in this class, a {@code NullPointerException} * will be thrown. * - * @author Joseph D. Darcy - * @author Scott Seligman - * @author Peter von der Ahé - * @author Martin Buchholz * @since 1.6 */ public class ElementFilter { @@ -79,7 +75,6 @@ public class ElementFilter { private static final Set MODULE_KIND = Collections.unmodifiableSet(EnumSet.of(ElementKind.MODULE)); - @SuppressWarnings("preview") private static final Set TYPE_KINDS = Collections.unmodifiableSet(EnumSet.of(ElementKind.CLASS, ElementKind.ENUM, @@ -87,7 +82,6 @@ public class ElementFilter { ElementKind.RECORD, ElementKind.ANNOTATION_TYPE)); - @SuppressWarnings("preview") private static final Set RECORD_COMPONENT_KIND = Set.of(ElementKind.RECORD_COMPONENT); diff --git a/src/java.compiler/share/classes/javax/lang/model/util/ElementKindVisitor14.java b/src/java.compiler/share/classes/javax/lang/model/util/ElementKindVisitor14.java index ab71cdb9c9d9de29c77f080d7336a716ba555e72..93b035e17721cde0dab6d5a30082f9d8edd7a970 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/ElementKindVisitor14.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/ElementKindVisitor14.java @@ -61,7 +61,7 @@ import javax.lang.model.SourceVersion; * @see ElementKindVisitor9 * @since 16 */ -@SupportedSourceVersion(RELEASE_18) +@SupportedSourceVersion(RELEASE_19) public class ElementKindVisitor14 extends ElementKindVisitor9 { /** * Constructor for concrete subclasses; uses {@code null} for the diff --git a/src/java.compiler/share/classes/javax/lang/model/util/ElementKindVisitor6.java b/src/java.compiler/share/classes/javax/lang/model/util/ElementKindVisitor6.java index 3d40feed86959e784bd2df82110a64fa6a3ac5eb..bdc4fe82ccf8f1a0f506167eee8afabda72f47d6 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/ElementKindVisitor6.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/ElementKindVisitor6.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -73,10 +73,6 @@ import javax.lang.model.SourceVersion; * methods. Use {@code Void} for visitors that do not need an * additional parameter. * - * @author Joseph D. Darcy - * @author Scott Seligman - * @author Peter von der Ahé - * * @see ElementKindVisitor7 * @see ElementKindVisitor8 * @see ElementKindVisitor9 @@ -139,7 +135,6 @@ public class ElementKindVisitor6 * @param p {@inheritDoc} * @return the result of the kind-specific visit method */ - @SuppressWarnings("preview") @Override public R visitType(TypeElement e, P p) { ElementKind k = e.getKind(); diff --git a/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner14.java b/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner14.java index cdc86c1f63be64e32f5999453f139c7a4d4fccf6..4365c6df53ca387a26d7efa71ba7b05510538182 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner14.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner14.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -37,15 +37,16 @@ import static javax.lang.model.SourceVersion.*; * appropriate for the {@link SourceVersion#RELEASE_14 RELEASE_14} * source version. * - * The visitXyz methods in this - * class scan their component elements by calling {@code scan} on - * their {@linkplain Element#getEnclosedElements enclosed elements}, - * {@linkplain ExecutableElement#getParameters parameters}, etc., as - * indicated in the individual method specifications. A subclass can - * control the order elements are visited by overriding the - * visitXyz methods. Note that clients of a scanner - * may get the desired behavior be invoking {@code v.scan(e, p)} rather - * than {@code v.visit(e, p)} on the root objects of interest. + * The visitXyz methods in this class scan their + * component elements by calling {@link ElementScanner6#scan(Element, + * Object) scan} on their {@linkplain Element#getEnclosedElements + * enclosed elements}, {@linkplain ExecutableElement#getParameters + * parameters}, etc., as indicated in the individual method + * specifications. A subclass can control the order elements are + * visited by overriding the visitXyz methods. + * Note that clients of a scanner may get the desired behavior by + * invoking {@code v.scan(e, p)} rather than {@code v.visit(e, p)} on + * the root objects of interest. * *

          When a subclass overrides a visitXyz method, the * new method can cause the enclosed elements to be scanned in the @@ -76,7 +77,7 @@ import static javax.lang.model.SourceVersion.*; * @see ElementScanner9 * @since 16 */ -@SupportedSourceVersion(RELEASE_18) +@SupportedSourceVersion(RELEASE_19) public class ElementScanner14 extends ElementScanner9 { /** * Constructor for concrete subclasses; uses {@code null} for the diff --git a/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner6.java b/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner6.java index f19fd5607722fc84b79fde3400f84559e99dc6a1..c2b628b033c2c8d6dde434531191a6994d46b334 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner6.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner6.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -35,14 +35,16 @@ import static javax.lang.model.SourceVersion.*; * A scanning visitor of program elements with default behavior * appropriate for the {@link SourceVersion#RELEASE_6 RELEASE_6} * source version. The visitXyz methods in this - * class scan their component elements by calling {@code scan} on - * their {@linkplain Element#getEnclosedElements enclosed elements}, - * {@linkplain ExecutableElement#getParameters parameters}, etc., as - * indicated in the individual method specifications. A subclass can - * control the order elements are visited by overriding the - * visitXyz methods. Note that clients of a scanner - * may get the desired behavior be invoking {@code v.scan(e, p)} rather - * than {@code v.visit(e, p)} on the root objects of interest. + * class scan their component elements by calling {@link + * #scan(Element, P) scan} on their {@linkplain + * Element#getEnclosedElements enclosed elements}, {@linkplain + * ExecutableElement#getParameters parameters}, etc., as indicated in + * the individual method specifications. A subclass can control the + * order elements are visited by overriding the + * visitXyz methods. Note that clients of a + * scanner may get the desired behavior by invoking {@code v.scan(e, + * p)} rather than {@code v.visit(e, p)} on the root objects of + * interest. * *

          When a subclass overrides a visitXyz method, the * new method can cause the enclosed elements to be scanned in the @@ -83,10 +85,6 @@ import static javax.lang.model.SourceVersion.*; * methods. Use {@code Void} for visitors that do not need an * additional parameter. * - * @author Joseph D. Darcy - * @author Scott Seligman - * @author Peter von der Ahé - * * @see ElementScanner7 * @see ElementScanner8 * @see ElementScanner9 diff --git a/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner7.java b/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner7.java index e79af27dacf617cd5b8f3ce723153b13bc201c68..73e286cea55602ce24449f9edb40d397f9d5c855 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner7.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner7.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 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 @@ -35,14 +35,16 @@ import static javax.lang.model.SourceVersion.*; * A scanning visitor of program elements with default behavior * appropriate for the {@link SourceVersion#RELEASE_7 RELEASE_7} * source version. The visitXyz methods in this - * class scan their component elements by calling {@code scan} on - * their {@linkplain Element#getEnclosedElements enclosed elements}, - * {@linkplain ExecutableElement#getParameters parameters}, etc., as - * indicated in the individual method specifications. A subclass can - * control the order elements are visited by overriding the - * visitXyz methods. Note that clients of a scanner - * may get the desired behavior be invoking {@code v.scan(e, p)} rather - * than {@code v.visit(e, p)} on the root objects of interest. + * class scan their component elements by calling {@link + * ElementScanner6#scan(Element, Object) scan} on their {@linkplain + * Element#getEnclosedElements enclosed elements}, {@linkplain + * ExecutableElement#getParameters parameters}, etc., as indicated in + * the individual method specifications. A subclass can control the + * order elements are visited by overriding the + * visitXyz methods. Note that clients of a + * scanner may get the desired behavior by invoking {@code v.scan(e, + * p)} rather than {@code v.visit(e, p)} on the root objects of + * interest. * *

          When a subclass overrides a visitXyz method, the * new method can cause the enclosed elements to be scanned in the diff --git a/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner8.java b/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner8.java index 229ab1a512ce12ae8c426ec94122d01568140b66..db3ee069d4b78f785febf3eae62f761e442fa0c9 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner8.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner8.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 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 @@ -35,14 +35,16 @@ import static javax.lang.model.SourceVersion.*; * A scanning visitor of program elements with default behavior * appropriate for the {@link SourceVersion#RELEASE_8 RELEASE_8} * source version. The visitXyz methods in this - * class scan their component elements by calling {@code scan} on - * their {@linkplain Element#getEnclosedElements enclosed elements}, - * {@linkplain ExecutableElement#getParameters parameters}, etc., as - * indicated in the individual method specifications. A subclass can - * control the order elements are visited by overriding the - * visitXyz methods. Note that clients of a scanner - * may get the desired behavior be invoking {@code v.scan(e, p)} rather - * than {@code v.visit(e, p)} on the root objects of interest. + * class scan their component elements by calling {@link + * ElementScanner6#scan(Element, Object) scan} on their {@linkplain + * Element#getEnclosedElements enclosed elements}, {@linkplain + * ExecutableElement#getParameters parameters}, etc., as indicated in + * the individual method specifications. A subclass can control the + * order elements are visited by overriding the + * visitXyz methods. Note that clients of a + * scanner may get the desired behavior by invoking {@code v.scan(e, + * p)} rather than {@code v.visit(e, p)} on the root objects of + * interest. * *

          When a subclass overrides a visitXyz method, the * new method can cause the enclosed elements to be scanned in the diff --git a/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner9.java b/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner9.java index b36235afd2a0dff8bf38c893303e3e7dd7ed9da1..3ee290d70cf975535546e773895a6e74339f2d23 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner9.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner9.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 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 @@ -36,15 +36,16 @@ import static javax.lang.model.SourceVersion.*; * appropriate for source versions {@link SourceVersion#RELEASE_9 * RELEASE_9} through {@link SourceVersion#RELEASE_14 RELEASE_14}. * - * The visitXyz methods in this - * class scan their component elements by calling {@code scan} on - * their {@linkplain Element#getEnclosedElements enclosed elements}, - * {@linkplain ExecutableElement#getParameters parameters}, etc., as - * indicated in the individual method specifications. A subclass can - * control the order elements are visited by overriding the - * visitXyz methods. Note that clients of a scanner - * may get the desired behavior be invoking {@code v.scan(e, p)} rather - * than {@code v.visit(e, p)} on the root objects of interest. + * The visitXyz methods in this class scan their + * component elements by calling {@link ElementScanner6#scan(Element, + * Object) scan} on their {@linkplain Element#getEnclosedElements + * enclosed elements}, {@linkplain ExecutableElement#getParameters + * parameters}, etc., as indicated in the individual method + * specifications. A subclass can control the order elements are + * visited by overriding the visitXyz methods. + * Note that clients of a scanner may get the desired behavior by + * invoking {@code v.scan(e, p)} rather than {@code v.visit(e, p)} on + * the root objects of interest. * *

          When a subclass overrides a visitXyz method, the * new method can cause the enclosed elements to be scanned in the 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 f8071dd98444dce0d14861c25249ea3650a9c91c..6e3ea7a95e4dbb3368b7cc3039d47887800ab32b 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -42,9 +42,6 @@ import javax.lang.model.element.*; *

          Compatibility Note: Methods may be added to this interface * in future releases of the platform. * - * @author Joseph D. Darcy - * @author Scott Seligman - * @author Peter von der Ahé * @see javax.annotation.processing.ProcessingEnvironment#getElementUtils * @since 1.6 */ @@ -68,8 +65,8 @@ public interface Elements { * * * - * If this process leads to a list with a single element, - * the single element is returned, otherwise null is returned. + * If this process leads to a list with a single element, the + * single element is returned, otherwise {@code null} is returned. * * @param name fully qualified package name, * or an empty string for an unnamed package @@ -155,8 +152,8 @@ public interface Elements { * * * - * If this process leads to a list with a single element, - * the single element is returned, otherwise null is returned. + * If this process leads to a list with a single element, the + * single element is returned, otherwise {@code null} is returned. * * @param name the canonical name * @return the named type element, @@ -735,8 +732,9 @@ public interface Elements { } /** - * Returns the record component for the given accessor. Returns null if the - * given method is not a record component accessor. + * Returns the record component for the given accessor. Returns + * {@code null} if the given method is not a record component + * accessor. * * @implSpec The default implementation of this method checks if the element * enclosing the accessor has kind {@link ElementKind#RECORD RECORD} if that is @@ -747,8 +745,8 @@ public interface Elements { * record component is returned, in any other case {@code null} is returned. * * @param accessor the method for which the record component should be found. - * @return the record component, or null if the given method is not a record - * component accessor + * @return the record component, or {@code null} if the given + * method is not a record component accessor * @since 16 */ default RecordComponentElement recordComponentFor(ExecutableElement accessor) { @@ -761,4 +759,100 @@ public interface Elements { } return null; } + + /** + * {@return the file object for this element or {@code null} if + * there is no such file object} + * + *

          The returned file object is for the reference + * representation of the information used to construct the + * element. For example, if during compilation or annotation + * processing, a source file for class {@code Foo} is compiled + * into a class file, the file object returned for the element + * representing {@code Foo} would be for the source file and + * not for the class file. + * + *

          An implementation may choose to not support the + * functionality of this method, in which case {@link + * UnsupportedOperationException} is thrown. + * + *

          In the context of annotation processing, a non-{@code null} + * value is returned if the element was included as part of the + * initial inputs or the containing file was created during the + * run of the annotation processing tool. Otherwise, a {@code + * null} may be returned. In annotation processing, if a + * {@linkplain javax.annotation.processing.Filer#createClassFile + * class file is created}, that class file can serve as the + * reference representation for elements. + * + *

          If it has a file object, the file object for a package will + * be a {@code package-info} file. A package may exist and not + * have any {@code package-info} file even if the package is + * (implicitly) created during an annotation processing run from + * the creation of source or class files in that package. An + * {@linkplain PackageElement#isUnnamed unnamed package} will have + * a {@code null} file since it cannot be declared in a + * compilation unit. + * + *

          If it has a file object, the file object for a module will + * be a {@code module-info} file. An {@linkplain + * ModuleElement#isUnnamed unnamed module} will have a {@code + * null} file since it cannot be declared in a compilation unit. + * An {@linkplain #isAutomaticModule automatic module} will have a + * {@code null} file since it is implicitly declared. + * + *

          If it has a file object, the file object for a top-level + * {@code public} class or interface will be a source or class + * file corresponding to that class or interface. In this case, + * typically the leading portion of the name of the file will + * match the name of the class or interface. A single compilation + * unit can define multiple top-level classes and interfaces, such + * as a primary {@code public} class or interfaces whose name + * corresponds to the file name and one or more auxiliary + * classes or interfaces whose names do not correspond to the file + * name. If a source file is providing the reference + * representation of an auxiliary class or interface, the file for + * the primary class is returned. (An auxiliary class or interface + * can also be defined in a {@code package-info} source file, in + * which case the file for the {@code package-info} file is + * returned.) If a class file is providing the reference + * representation of an auxiliary class or interface, the separate + * class file for the auxiliary class is returned. + * + *

          For a nested class or interface, if it has a file object: + * + *

            + * + *
          • if a source file is providing the reference representation, + * the file object will be that of the {@linkplain + * #getOutermostTypeElement(Element) outermost enclosing} class or + * interface + * + *
          • if a class file is providing the reference representation, + * the file object will be that of the nested class or interface + * itself + * + *
          + * + *

          For other lexically enclosed elements, such as {@linkplain + * VariableElement#getEnclosingElement() variables}, {@linkplain + * ExecutableElement#getEnclosingElement() methods, and + * constructors}, if they have a file object, the file object will + * be the object associated with the {@linkplain + * Element#getEnclosingElement() enclosing element} of the + * lexically enclosed element. + * + * @implSpec The default implementation unconditionally throws + * {@link UnsupportedOperationException}. + * + * @throws UnsupportedOperationException if this functionality is + * not supported + * + * @param e the element to find a file object for + * @since 18 + */ + default javax.tools.JavaFileObject getFileObjectOf(Element e) { + throw new UnsupportedOperationException(); + } } diff --git a/src/java.compiler/share/classes/javax/lang/model/util/SimpleAnnotationValueVisitor14.java b/src/java.compiler/share/classes/javax/lang/model/util/SimpleAnnotationValueVisitor14.java index b9015109bb86ecc31c9bdc6e20c28081e1f467b4..9174602cde0f3299b222d87613caf7394503755b 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/SimpleAnnotationValueVisitor14.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/SimpleAnnotationValueVisitor14.java @@ -52,7 +52,7 @@ import static javax.lang.model.SourceVersion.*; * @see SimpleAnnotationValueVisitor9 * @since 14 */ -@SupportedSourceVersion(RELEASE_18) +@SupportedSourceVersion(RELEASE_19) public class SimpleAnnotationValueVisitor14 extends SimpleAnnotationValueVisitor9 { /** * Constructor for concrete subclasses; uses {@code null} for the diff --git a/src/java.compiler/share/classes/javax/lang/model/util/SimpleAnnotationValueVisitor6.java b/src/java.compiler/share/classes/javax/lang/model/util/SimpleAnnotationValueVisitor6.java index 64bbdda4fc44227a90856a3752217607c4978ff6..bf63d64f6b075cad90b2ac6df2bac4daf048ce23 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/SimpleAnnotationValueVisitor6.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/SimpleAnnotationValueVisitor6.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -67,10 +67,6 @@ import javax.annotation.processing.SupportedSourceVersion; * @param the return type of this visitor's methods * @param

          the type of the additional parameter to this visitor's methods. * - * @author Joseph D. Darcy - * @author Scott Seligman - * @author Peter von der Ahé - * * @see SimpleAnnotationValueVisitor7 * @see SimpleAnnotationValueVisitor8 * @see SimpleAnnotationValueVisitor9 diff --git a/src/java.compiler/share/classes/javax/lang/model/util/SimpleElementVisitor14.java b/src/java.compiler/share/classes/javax/lang/model/util/SimpleElementVisitor14.java index b90c2c97c96eb7d034c39f1f06b525a107f39a15..8e992025e4a8abe318b694c93b34986e6e16a5aa 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/SimpleElementVisitor14.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/SimpleElementVisitor14.java @@ -57,7 +57,7 @@ import static javax.lang.model.SourceVersion.*; * @see SimpleElementVisitor9 * @since 16 */ -@SupportedSourceVersion(RELEASE_18) +@SupportedSourceVersion(RELEASE_19) public class SimpleElementVisitor14 extends SimpleElementVisitor9 { /** * Constructor for concrete subclasses; uses {@code null} for the diff --git a/src/java.compiler/share/classes/javax/lang/model/util/SimpleElementVisitor6.java b/src/java.compiler/share/classes/javax/lang/model/util/SimpleElementVisitor6.java index 385ace89f5a2f2217836e8eeaeadf954e2c3271f..e894a0762957a5890c195745f35779d1823c930e 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/SimpleElementVisitor6.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/SimpleElementVisitor6.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -72,10 +72,6 @@ import static javax.lang.model.SourceVersion.*; * @param

          the type of the additional parameter to this visitor's methods. Use {@code Void} * for visitors that do not need an additional parameter. * - * @author Joseph D. Darcy - * @author Scott Seligman - * @author Peter von der Ahé - * * @see SimpleElementVisitor7 * @see SimpleElementVisitor8 * @see SimpleElementVisitor9 diff --git a/src/java.compiler/share/classes/javax/lang/model/util/SimpleTypeVisitor14.java b/src/java.compiler/share/classes/javax/lang/model/util/SimpleTypeVisitor14.java index 331297c8f2ee4573459627f9b3193688988a95eb..86e7cb1d981e398e82c7df10a4015a19c40e1329 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/SimpleTypeVisitor14.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/SimpleTypeVisitor14.java @@ -56,7 +56,7 @@ import static javax.lang.model.SourceVersion.*; * @see SimpleTypeVisitor9 * @since 14 */ -@SupportedSourceVersion(RELEASE_18) +@SupportedSourceVersion(RELEASE_19) public class SimpleTypeVisitor14 extends SimpleTypeVisitor9 { /** * Constructor for concrete subclasses; uses {@code null} for the diff --git a/src/java.compiler/share/classes/javax/lang/model/util/SimpleTypeVisitor6.java b/src/java.compiler/share/classes/javax/lang/model/util/SimpleTypeVisitor6.java index 38701ee71fdced3a8c9d68e0f1a20be71a61e58d..8e169094df26ace6a0502143b97b22aa8e79428e 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/SimpleTypeVisitor6.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/SimpleTypeVisitor6.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -72,10 +72,6 @@ import static javax.lang.model.SourceVersion.*; * methods. Use {@code Void} for visitors that do not need an * additional parameter. * - * @author Joseph D. Darcy - * @author Scott Seligman - * @author Peter von der Ahé - * * @see SimpleTypeVisitor7 * @see SimpleTypeVisitor8 * @see SimpleTypeVisitor9 diff --git a/src/java.compiler/share/classes/javax/lang/model/util/TypeKindVisitor14.java b/src/java.compiler/share/classes/javax/lang/model/util/TypeKindVisitor14.java index 66743281bb031dfd7b405c6482934f19fc22fa85..b83307c20959fc75edbbda45f2c2de036ebb7ca0 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/TypeKindVisitor14.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/TypeKindVisitor14.java @@ -61,7 +61,7 @@ import static javax.lang.model.SourceVersion.*; * @see TypeKindVisitor9 * @since 14 */ -@SupportedSourceVersion(RELEASE_18) +@SupportedSourceVersion(RELEASE_19) public class TypeKindVisitor14 extends TypeKindVisitor9 { /** * Constructor for concrete subclasses to call; uses {@code null} diff --git a/src/java.compiler/share/classes/javax/lang/model/util/TypeKindVisitor6.java b/src/java.compiler/share/classes/javax/lang/model/util/TypeKindVisitor6.java index 661ecdd6e760093b696c2c0e70e3f1e7d8f5d576..602e89ae08b111473d77847476aeae072da0c77a 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/TypeKindVisitor6.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/TypeKindVisitor6.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -71,10 +71,6 @@ import static javax.lang.model.SourceVersion.*; * methods. Use {@code Void} for visitors that do not need an * additional parameter. * - * @author Joseph D. Darcy - * @author Scott Seligman - * @author Peter von der Ahé - * * @see TypeKindVisitor7 * @see TypeKindVisitor8 * @see TypeKindVisitor9 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 cd1fe050ec5b42973a9e1b6df468ea58d1b0bde3..02c7085bd8cbad7e60e89940f4a0c5ffeb5bc60d 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -38,9 +38,6 @@ import javax.lang.model.type.*; *

          Compatibility Note: Methods may be added to this interface * in future releases of the platform. * - * @author Joseph D. Darcy - * @author Scott Seligman - * @author Peter von der Ahé * @see javax.annotation.processing.ProcessingEnvironment#getTypeUtils * @since 1.6 */ diff --git a/src/java.compiler/share/classes/javax/lang/model/util/package-info.java b/src/java.compiler/share/classes/javax/lang/model/util/package-info.java index 97489de8f2f974ce7b2d3b05823091e20a5b1ef2..e6f34e6870ac4a63f88ba95e161e6803b72001a9 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/package-info.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -35,9 +35,6 @@ *

          Unless otherwise specified, methods in this package will throw * a {@code NullPointerException} if given a {@code null} argument. * - * @author Joseph D. Darcy - * @author Scott Seligman - * @author Peter von der Ahé * @since 1.6 */ package javax.lang.model.util; diff --git a/src/java.compiler/share/classes/javax/tools/Diagnostic.java b/src/java.compiler/share/classes/javax/tools/Diagnostic.java index 8c3c2a34c8a3f819decff2116e0444c10882c59c..6ee666551f58adddde0bcd7d0c28b66997e1b0b1 100644 --- a/src/java.compiler/share/classes/javax/tools/Diagnostic.java +++ b/src/java.compiler/share/classes/javax/tools/Diagnostic.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -41,8 +41,6 @@ import java.util.Locale; * * @param the type of source object used by this diagnostic * - * @author Peter von der Ahé - * @author Jonathan Gibbons * @since 1.6 */ public interface Diagnostic { diff --git a/src/java.compiler/share/classes/javax/tools/DiagnosticCollector.java b/src/java.compiler/share/classes/javax/tools/DiagnosticCollector.java index e1cfc33a3f763721d2de9765f932a7dd11834782..7e1ee34d3c8ae49480ca69a805ea628aad3fc1dd 100644 --- a/src/java.compiler/share/classes/javax/tools/DiagnosticCollector.java +++ b/src/java.compiler/share/classes/javax/tools/DiagnosticCollector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 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 @@ -36,7 +36,6 @@ import java.util.Objects; * @param the type of source objects used by diagnostics received * by this object * - * @author Peter von der Ahé * @since 1.6 */ public final class DiagnosticCollector implements DiagnosticListener { diff --git a/src/java.compiler/share/classes/javax/tools/DiagnosticListener.java b/src/java.compiler/share/classes/javax/tools/DiagnosticListener.java index 85a15dd225df7e33e03a415efa83ea2740df96be..6ed5191dd38defe10eda764591c044004a522831 100644 --- a/src/java.compiler/share/classes/javax/tools/DiagnosticListener.java +++ b/src/java.compiler/share/classes/javax/tools/DiagnosticListener.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -31,8 +31,6 @@ package javax.tools; * @param the type of source objects used by diagnostics received * by this listener * - * @author Jonathan Gibbons - * @author Peter von der Ahé * @since 1.6 */ public interface DiagnosticListener { diff --git a/src/java.compiler/share/classes/javax/tools/FileObject.java b/src/java.compiler/share/classes/javax/tools/FileObject.java index 492ca6b3cc9c9bbf2055bdb5297581d5abd0e9f3..89a8499bf51bcbb4ac44379d269b55cbade5f95d 100644 --- a/src/java.compiler/share/classes/javax/tools/FileObject.java +++ b/src/java.compiler/share/classes/javax/tools/FileObject.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 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 @@ -44,8 +44,6 @@ import java.net.URI; *

          Unless explicitly allowed, all methods in this interface might * throw a NullPointerException if given a {@code null} argument. * - * @author Peter von der Ahé - * @author Jonathan Gibbons * @since 1.6 */ public interface FileObject { diff --git a/src/java.compiler/share/classes/javax/tools/ForwardingFileObject.java b/src/java.compiler/share/classes/javax/tools/ForwardingFileObject.java index 57bdb84000e95ccebc0200c122f4537507311721..98bb5a650a4062bcf41739356bfce5c2a30c9165 100644 --- a/src/java.compiler/share/classes/javax/tools/ForwardingFileObject.java +++ b/src/java.compiler/share/classes/javax/tools/ForwardingFileObject.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 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 @@ -42,7 +42,6 @@ import java.util.Objects; * should be interpreted as referring indirectly to the {@link #fileObject delegate file object}. * * @param the kind of file object forwarded to by this object - * @author Peter von der Ahé * @since 1.6 */ public class ForwardingFileObject implements FileObject { diff --git a/src/java.compiler/share/classes/javax/tools/ForwardingJavaFileManager.java b/src/java.compiler/share/classes/javax/tools/ForwardingJavaFileManager.java index 27b55f3603aa5a8d5b19f3f6395312d020ed48bc..e0bb999c05b7f4acd19938ad2760ec3b0fe7c169 100644 --- a/src/java.compiler/share/classes/javax/tools/ForwardingJavaFileManager.java +++ b/src/java.compiler/share/classes/javax/tools/ForwardingJavaFileManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -26,6 +26,7 @@ package javax.tools; import java.io.IOException; +import java.lang.reflect.Method; import java.util.Iterator; import java.util.Objects; import java.util.ServiceLoader; @@ -41,7 +42,6 @@ import javax.tools.JavaFileObject.Kind; * should be interpreted as referring indirectly to the {@link #fileManager delegate file manager}. * * @param the kind of file manager forwarded to by this object - * @author Peter von der Ahé * @since 1.6 */ public class ForwardingJavaFileManager implements JavaFileManager { @@ -144,6 +144,39 @@ public class ForwardingJavaFileManager implements Jav return fileManager.getJavaFileForOutput(location, className, kind, sibling); } + /**{@inheritDoc} + * + * @implSpec If the subclass of the {@code ForwardingJavaFileManager} overrides the + * {@link #getJavaFileForOutput} method, this method will delegate to it as per the + * general contract of {@link JavaFileManager#getJavaFileForOutputForOriginatingFiles}. + * If the subclass does not override the method, the call will be delegated to the + * {@code fileManager}. + * + * @throws IllegalArgumentException {@inheritDoc} + * @throws IllegalStateException {@inheritDoc} + */ + @Override + public JavaFileObject getJavaFileForOutputForOriginatingFiles(Location location, + String className, + Kind kind, + FileObject... originatingFiles) throws IOException { + try { + Method delegate = getClass().getMethod("getJavaFileForOutput", + Location.class, String.class, + Kind.class, FileObject.class); + if (delegate.getDeclaringClass() == ForwardingJavaFileManager.class) { + return fileManager.getJavaFileForOutputForOriginatingFiles(location, className, + kind, originatingFiles); + } else { + return JavaFileManager.super + .getJavaFileForOutputForOriginatingFiles(location, className, + kind, originatingFiles); + } + } catch (NoSuchMethodException ex) { + throw new InternalError("This should never happen.", ex); + } + } + /** * @throws IllegalArgumentException {@inheritDoc} * @throws IllegalStateException {@inheritDoc} @@ -171,6 +204,39 @@ public class ForwardingJavaFileManager implements Jav return fileManager.getFileForOutput(location, packageName, relativeName, sibling); } + /**{@inheritDoc} + * + * @implSpec If the subclass of the {@code ForwardingJavaFileManager} overrides the + * {@link #getFileForOutput} method, this method will delegate to it as per the + * general contract of {@link JavaFileManager#getFileForOutputForOriginatingFiles}. + * If the subclass does not override the method, the call will be delegated to the + * {@code fileManager}. + * + * @throws IllegalArgumentException {@inheritDoc} + * @throws IllegalStateException {@inheritDoc} + */ + @Override + public FileObject getFileForOutputForOriginatingFiles(Location location, + String packageName, + String relativeName, + FileObject... originatingFiles) throws IOException { + try { + Method delegate = getClass().getMethod("getFileForOutput", + Location.class, String.class, + String.class, FileObject.class); + if (delegate.getDeclaringClass() == ForwardingJavaFileManager.class) { + return fileManager.getFileForOutputForOriginatingFiles(location, packageName, + relativeName, originatingFiles); + } else { + return JavaFileManager.super + .getFileForOutputForOriginatingFiles(location, packageName, + relativeName, originatingFiles); + } + } catch (NoSuchMethodException ex) { + throw new InternalError("This should never happen.", ex); + } + } + @Override public void flush() throws IOException { fileManager.flush(); diff --git a/src/java.compiler/share/classes/javax/tools/ForwardingJavaFileObject.java b/src/java.compiler/share/classes/javax/tools/ForwardingJavaFileObject.java index 90f607cf3dc39881dab76377f418ab0257a108af..a940b23009d8e0874b815a2e7a8363f92c27e510 100644 --- a/src/java.compiler/share/classes/javax/tools/ForwardingJavaFileObject.java +++ b/src/java.compiler/share/classes/javax/tools/ForwardingJavaFileObject.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -37,7 +37,6 @@ import javax.lang.model.element.NestingKind; * should be interpreted as referring indirectly to the {@link #fileObject delegate file object}. * * @param the kind of file object forwarded to by this object - * @author Peter von der Ahé * @since 1.6 */ public class ForwardingJavaFileObject diff --git a/src/java.compiler/share/classes/javax/tools/JavaCompiler.java b/src/java.compiler/share/classes/javax/tools/JavaCompiler.java index f7c1c61a41bc9bcfa2b4667325ac433c257dbfe9..7415a4d6fb92e45cb4107f7b6658f5645a530372 100644 --- a/src/java.compiler/share/classes/javax/tools/JavaCompiler.java +++ b/src/java.compiler/share/classes/javax/tools/JavaCompiler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -26,6 +26,7 @@ package javax.tools; import java.io.Writer; +import java.net.URI; import java.nio.charset.Charset; import java.util.Locale; import java.util.concurrent.Callable; @@ -106,42 +107,45 @@ import javax.annotation.processing.Processor; * work with multiple sequential compilations making the following * example a recommended coding pattern: * - *

          - *       File[] files1 = ... ; // input for first compilation task
          - *       File[] files2 = ... ; // input for second compilation task
          + *     {@snippet id="use-sjfm" lang=java :
          + *       File[] files1 = null ; // input for first compilation task     // @replace substring=null replacement="..."
          + *       File[] files2 = null ; // input for second compilation task    // @replace substring=null replacement="..."
            *
            *       JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
            *       StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
            *
          - *       {@code Iterable} compilationUnits1 =
          - *           fileManager.getJavaFileObjectsFromFiles({@linkplain java.util.Arrays#asList Arrays.asList}(files1));
          + *       Iterable compilationUnits1 =
          + *           fileManager.getJavaFileObjectsFromFiles(Arrays.asList(files1));  // @link substring=Arrays.asList target="java.util.Arrays#asList"
            *       compiler.getTask(null, fileManager, null, null, null, compilationUnits1).call();
            *
          - *       {@code Iterable} compilationUnits2 =
          + *       Iterable compilationUnits2 =
            *           fileManager.getJavaFileObjects(files2); // use alternative method
            *       // reuse the same file manager to allow caching of jar files
            *       compiler.getTask(null, fileManager, null, null, null, compilationUnits2).call();
            *
          - *       fileManager.close();
          + * fileManager.close(); + * } * * * *
          {@link DiagnosticCollector}
          *
          * Used to collect diagnostics in a list, for example: - *
          - *       {@code Iterable} compilationUnits = ...;
          + *     {@snippet id="use-diag-collector" lang=java :
          + *       Iterable compilationUnits = null;        // @replace substring=null replacement="..."
            *       JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
          - *       {@code DiagnosticCollector diagnostics = new DiagnosticCollector();}
          + *       DiagnosticCollector diagnostics = new DiagnosticCollector();
            *       StandardJavaFileManager fileManager = compiler.getStandardFileManager(diagnostics, null, null);
            *       compiler.getTask(null, fileManager, diagnostics, null, null, compilationUnits).call();
            *
          - *       for ({@code Diagnostic} diagnostic : diagnostics.getDiagnostics())
          + *       for (Diagnostic diagnostic : diagnostics.getDiagnostics()) {
            *           System.out.format("Error on line %d in %s%n",
            *                             diagnostic.getLineNumber(),
            *                             diagnostic.getSource().toUri());
          + *       }
            *
          - *       fileManager.close();
          + * fileManager.close(); + * } *
          * *
          @@ -158,9 +162,9 @@ import javax.annotation.processing.Processor; * allowing customizing behavior. For example, consider how to * log all calls to {@linkplain JavaFileManager#flush}: * - *
          - *       final  Logger logger = ...;
          - *       {@code Iterable} compilationUnits = ...;
          + *     {@snippet id="forward-fm" lang=java :
          + *       final  Logger logger = null;                                       // @replace substring=null replacement="..."
          + *       Iterable compilationUnits = null;        // @replace substring=null replacement="..."
            *       JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
            *       StandardJavaFileManager stdFileManager = compiler.getStandardFileManager(null, null, null);
            *       JavaFileManager fileManager = new ForwardingJavaFileManager(stdFileManager) {
          @@ -170,7 +174,8 @@ import javax.annotation.processing.Processor;
            *               logger.exiting(StandardJavaFileManager.class.getName(), "flush");
            *           }
            *       };
          - *       compiler.getTask(null, fileManager, null, null, null, compilationUnits).call();
          + * compiler.getTask(null, fileManager, null, null, null, compilationUnits).call(); + * } * * *
          {@link SimpleJavaFileObject}
          @@ -181,37 +186,10 @@ import javax.annotation.processing.Processor; * example, here is how to define a file object which represent * source code stored in a string: * - *
          - *       /**
          - *        * A file object used to represent source coming from a string.
          - *        {@code *}/
          - *       public class JavaSourceFromString extends SimpleJavaFileObject {
          - *           /**
          - *            * The source code of this "file".
          - *            {@code *}/
          - *           final String code;
          - *
          - *           /**
          - *            * Constructs a new JavaSourceFromString.
          - *            * {@code @}param name the name of the compilation unit represented by this file object
          - *            * {@code @}param code the source code for the compilation unit represented by this file object
          - *            {@code *}/
          - *           JavaSourceFromString(String name, String code) {
          - *               super({@linkplain java.net.URI#create URI.create}("string:///" + name.replace('.','/') + Kind.SOURCE.extension),
          - *                     Kind.SOURCE);
          - *               this.code = code;
          - *           }
          - *
          - *           {@code @}Override
          - *           public CharSequence getCharContent(boolean ignoreEncodingErrors) {
          - *               return code;
          - *           }
          - *       }
          + * {@snippet id=fileObject class=JavaSourceFromString } * * * - * @author Peter von der Ahé - * @author Jonathan Gibbons * @see DiagnosticListener * @see Diagnostic * @see JavaFileManager diff --git a/src/java.compiler/share/classes/javax/tools/JavaFileManager.java b/src/java.compiler/share/classes/javax/tools/JavaFileManager.java index 85cde42addc6ec7f9fe1105abc6eb8bf2dd7a6c6..524109bdf4dbf3147636cc506dcfc74b20488e1a 100644 --- a/src/java.compiler/share/classes/javax/tools/JavaFileManager.java +++ b/src/java.compiler/share/classes/javax/tools/JavaFileManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -28,9 +28,12 @@ package javax.tools; import java.io.Closeable; import java.io.Flushable; import java.io.IOException; +import java.net.URI; import java.util.Iterator; import java.util.ServiceLoader; import java.util.Set; +import javax.annotation.processing.Filer; +import javax.lang.model.util.Elements; import static javax.tools.JavaFileObject.Kind; @@ -78,8 +81,10 @@ import static javax.tools.JavaFileObject.Kind; * href="http://www.ietf.org/rfc/rfc3986.txt">RFC 3986, * section 3.3. Informally, this should be true: * - * - *
            URI.{@linkplain java.net.URI#create create}(relativeName).{@linkplain java.net.URI#normalize() normalize}().{@linkplain java.net.URI#getPath getPath}().equals(relativeName)
          + * {@snippet id="valid-relative-name" lang=java : + * // @link substring="create" target="URI#create" @link substring=normalize target="URI#normalize" @link substring=getPath target="URI#getPath" : + * URI.create(relativeName).normalize().getPath().equals(relativeName) + * } * *

          All methods in this interface might throw a SecurityException. * @@ -98,8 +103,6 @@ import static javax.tools.JavaFileObject.Kind; *

          Unless explicitly allowed, all methods in this interface might * throw a NullPointerException if given a {@code null} argument. * - * @author Peter von der Ahé - * @author Jonathan Gibbons * @see JavaFileObject * @see FileObject * @since 1.6 @@ -338,6 +341,51 @@ public interface JavaFileManager extends Closeable, Flushable, OptionChecker { FileObject sibling) throws IOException; + /** + * Returns a {@linkplain JavaFileObject file object} for output + * representing the specified class of the specified kind in the + * given package-oriented location. + * + *

          The provided {@code originatingFiles} represent files that + * were, in an unspecified way, used to create the content of + * the file created by this method. See {@code originatingElements} + * in {@link Filer#createSourceFile}. {@link Elements#getFileObjectOf} + * may be used to convert the {@code Element}s to {@code FileObject}s. + * + * @implSpec The default implementation calls + * {@link #getJavaFileForOutput(javax.tools.JavaFileManager.Location, java.lang.String, javax.tools.JavaFileObject.Kind, javax.tools.FileObject) } + * with the first element of the {@code originatingFiles}, if any, as a {@code sibling}. + * + * @param location a package-oriented location + * @param className the name of a class + * @param kind the kind of file, must be one of {@link + * JavaFileObject.Kind#SOURCE SOURCE} or {@link + * JavaFileObject.Kind#CLASS CLASS} + * @param originatingFiles the files which are contributing to this newly created file; + * {@code null} is equivalent to empty {@code originatingFiles}, + * meaning no known originating files + * @return a file object for output + * @throws IllegalArgumentException if sibling is not known to + * this file manager, or if the location is not known to this file + * manager and the file manager does not support unknown + * locations, or if the kind is not valid, or if the location is + * not an output location + * @throws IOException if an I/O error occurred, or if {@link + * #close} has been called and this file manager cannot be + * reopened + * @throws IllegalStateException {@link #close} has been called + * and this file manager cannot be reopened + * @since 18 + * @see Filer#createSourceFile + */ + default JavaFileObject getJavaFileForOutputForOriginatingFiles(Location location, + String className, + Kind kind, + FileObject... originatingFiles) + throws IOException { + return getJavaFileForOutput(location, className, kind, siblingFrom(originatingFiles)); + } + /** * Returns a {@linkplain FileObject file object} for input * representing the specified relative @@ -356,7 +404,9 @@ public interface JavaFileManager extends Closeable, Flushable, OptionChecker { * StandardLocation#SOURCE_PATH SOURCE_PATH} location, this method * might be called like so: * - *

          getFileForInput(SOURCE_PATH, "com.sun.tools.javac", "resources/compiler.properties");
          + * {@snippet id="call-getFileForInput" lang=java : + * getFileForInput(SOURCE_PATH, "com.sun.tools.javac", "resources/compiler.properties"); + * } * *

          If the call was executed on Windows, with SOURCE_PATH set to * "C:\Documents and Settings\UncleBob\src\share\classes", @@ -430,6 +480,59 @@ public interface JavaFileManager extends Closeable, Flushable, OptionChecker { FileObject sibling) throws IOException; + /** + * Returns a {@linkplain FileObject file object} for output + * representing the specified relative + * name in the specified package in the given location. + * + *

          The provided {@code originatingFiles} represent files that + * were, in an unspecified way, used to create the content of + * the file created by this method. See {@code originatingElements} + * in {@link Filer#createResource}. {@link Elements#getFileObjectOf} + * may be used to convert the {@code Element}s to {@code FileObject}s. + * + *

          If the returned object represents a {@linkplain + * JavaFileObject.Kind#SOURCE source} or {@linkplain + * JavaFileObject.Kind#CLASS class} file, it must be an instance + * of {@link JavaFileObject}. + * + *

          Informally, the file object returned by this method is + * located in the concatenation of the location, package name, and + * relative name or in a location inferred from the {@code originatingFiles}. + * See {@link #getFileForInput getFileForInput} for an example. + * + * @implSpec The default implementation calls + * {@link #getFileForOutput(javax.tools.JavaFileManager.Location, java.lang.String, java.lang.String, javax.tools.FileObject) } + * with the first element of the {@code originatingFiles}, if any, as a {@code sibling}. + * + * @param location an output location + * @param packageName a package name + * @param relativeName a relative name + * @param originatingFiles the files which are contributing to this newly created file; + * {@code null} is equivalent to empty {@code originatingFiles}, + * meaning no known originating files + * @return a file object + * @throws IllegalArgumentException if sibling is not known to + * this file manager, or if the location is not known to this file + * manager and the file manager does not support unknown + * locations, or if {@code relativeName} is not valid, + * or if the location is not an output location + * @throws IOException if an I/O error occurred, or if {@link + * #close} has been called and this file manager cannot be + * reopened + * @throws IllegalStateException if {@link #close} has been called + * and this file manager cannot be reopened + * @since 18 + * @see Filer#createResource + */ + default FileObject getFileForOutputForOriginatingFiles(Location location, + String packageName, + String relativeName, + FileObject... originatingFiles) + throws IOException { + return getFileForOutput(location, packageName, relativeName, siblingFrom(originatingFiles)); + } + /** * Flushes any resources opened for output by this file manager * directly or indirectly. Flushing a closed file manager has no @@ -566,16 +669,17 @@ public interface JavaFileManager extends Closeable, Flushable, OptionChecker { *

          For a package-oriented location, a file object is contained in the location if there exist * values for packageName and relativeName such that either of the following * calls would return the {@link #isSameFile same} file object: - *

          -     *     getFileForInput(location, packageName, relativeName)
          -     *     getFileForOutput(location, packageName, relativeName, null)
          -     * 
          + * {@snippet : + * // @highlight region substring=packageName type=italic @highlight region substring=relativeName type=italic : + * getFileForInput(location, packageName, relativeName) + * getFileForOutput(location, packageName, relativeName, null) // @end @end + * } * *

          For a module-oriented location, a file object is contained in the location if there exists * a module that may be obtained by the call: - *

          -     *     getLocationForModule(location, moduleName)
          -     * 
          + * {@snippet id="call-getLocationForModule" lang=java : + * getLocationForModule(location, moduleName) // @highlight substring=moduleName type=italic + * } * such that the file object is contained in the (package-oriented) location for that module. * * @implSpec This implementation throws {@code UnsupportedOperationException}. @@ -594,4 +698,8 @@ public interface JavaFileManager extends Closeable, Flushable, OptionChecker { throw new UnsupportedOperationException(); } + private static FileObject siblingFrom(FileObject[] originatingFiles) { + return originatingFiles != null && originatingFiles.length > 0 ? originatingFiles[0] : null; + } + } diff --git a/src/java.compiler/share/classes/javax/tools/JavaFileObject.java b/src/java.compiler/share/classes/javax/tools/JavaFileObject.java index 48d6388df9e377d74602e816a75f343dbdb0e4be..0cac57a3176e427765f2a466fb041fd8c1bb0304 100644 --- a/src/java.compiler/share/classes/javax/tools/JavaFileObject.java +++ b/src/java.compiler/share/classes/javax/tools/JavaFileObject.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -39,8 +39,6 @@ import java.util.Objects; *

          Unless explicitly allowed, all methods in this interface might * throw a NullPointerException if given a {@code null} argument. * - * @author Peter von der Ahé - * @author Jonathan Gibbons * @see JavaFileManager * @since 1.6 */ diff --git a/src/java.compiler/share/classes/javax/tools/OptionChecker.java b/src/java.compiler/share/classes/javax/tools/OptionChecker.java index 653cf8fae244e903d10c9cb76f1abb5ea5423ff6..73c4311b44e49677d9170e3e603543f590a745a2 100644 --- a/src/java.compiler/share/classes/javax/tools/OptionChecker.java +++ b/src/java.compiler/share/classes/javax/tools/OptionChecker.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 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 @@ -28,7 +28,6 @@ package javax.tools; /** * Interface for recognizing options. * - * @author Peter von der Ahé * @since 1.6 */ public interface OptionChecker { diff --git a/src/java.compiler/share/classes/javax/tools/SimpleJavaFileObject.java b/src/java.compiler/share/classes/javax/tools/SimpleJavaFileObject.java index 9c8d491996aacde4786c42297d5db0362b5ed1c9..b43bc4a60d8ce43b8fa8521b16e9747ed76e27c7 100644 --- a/src/java.compiler/share/classes/javax/tools/SimpleJavaFileObject.java +++ b/src/java.compiler/share/classes/javax/tools/SimpleJavaFileObject.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -39,7 +39,6 @@ import javax.lang.model.element.NestingKind; * implementation and specification of any method of this class as * long as the general contract of JavaFileObject is obeyed. * - * @author Peter von der Ahé * @since 1.6 */ public class SimpleJavaFileObject implements JavaFileObject { diff --git a/src/java.compiler/share/classes/javax/tools/StandardJavaFileManager.java b/src/java.compiler/share/classes/javax/tools/StandardJavaFileManager.java index 5b6590bf926a524536f781e67c2edc4f5de33e92..769856535acee7aaf6b8a21ee99926864db0a01f 100644 --- a/src/java.compiler/share/classes/javax/tools/StandardJavaFileManager.java +++ b/src/java.compiler/share/classes/javax/tools/StandardJavaFileManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 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 @@ -75,9 +75,10 @@ import java.util.List; * {@linkplain FileObject#openReader(boolean)} * must succeed if the following would succeed (ignoring * encoding issues): - *

          - *
          new {@linkplain java.io.FileInputStream#FileInputStream(File) FileInputStream}(new {@linkplain File#File(java.net.URI) File}({@linkplain FileObject fileObject}.{@linkplain FileObject#toUri() toUri}()))
          - *
          + * {@snippet id="equiv-input" lang=java : + * // @link substring=FileInputStream target="java.io.FileInputStream#FileInputStream(File)" @link regex="File\b" target="File#File(java.net.URI)" @link substring=fileObject target=FileObject @link substring=toUri target="FileObject#toUri()" : + * new FileInputStream(new File(fileObject.toUri())) + * } * *
        • * and the methods @@ -85,9 +86,10 @@ import java.util.List; * {@linkplain FileObject#openWriter()} must * succeed if the following would succeed (ignoring encoding * issues): - *
          - *
          new {@linkplain java.io.FileOutputStream#FileOutputStream(File) FileOutputStream}(new {@linkplain File#File(java.net.URI) File}({@linkplain FileObject fileObject}.{@linkplain FileObject#toUri() toUri}()))
          - *
          + * {@snippet id="equiv-output" lang=java : + * // @link substring=FileOutputStream target="java.io.FileOutputStream#FileOutputStream(File)" @link regex="File\b" target="File#File(java.net.URI)" @link substring=fileObject target=FileObject @link substring=toUri target="FileObject#toUri()" : + * new FileOutputStream(new File(fileObject.toUri())) + * } *
        • * * @@ -153,8 +155,6 @@ import java.util.List; * correct to call these methods with a single {@code Path} and have it be treated as * an {@code Iterable} of its components. * - * - * @author Peter von der Ahé * @since 1.6 */ public interface StandardJavaFileManager extends JavaFileManager { @@ -241,9 +241,9 @@ public interface StandardJavaFileManager extends JavaFileManager { * Returns file objects representing the given files. * Convenience method equivalent to: * - *
          -     *     getJavaFileObjectsFromFiles({@linkplain java.util.Arrays#asList Arrays.asList}(files))
          -     * 
          + * {@snippet id="equiv-getJavaFileObjects" lang=java : + * getJavaFileObjectsFromFiles(Arrays.asList(files)) // @link substring="Arrays.asList" target="Arrays#asList" + * } * * @param files an array of files * @return a list of file objects @@ -259,9 +259,9 @@ public interface StandardJavaFileManager extends JavaFileManager { * Returns file objects representing the given paths. * Convenience method equivalent to: * - *
          -     *     getJavaFileObjectsFromPaths({@linkplain java.util.Arrays#asList Arrays.asList}(paths))
          -     * 
          + * {@snippet id="equiv-getJavaFileObjectsFromPaths" lang=java : + * getJavaFileObjectsFromPaths(Arrays.asList(paths)) // @link substring="Arrays.asList" target="Arrays#asList" + * } * * @implSpec * The default implementation will only throw {@code NullPointerException} @@ -296,9 +296,9 @@ public interface StandardJavaFileManager extends JavaFileManager { * Returns file objects representing the given file names. * Convenience method equivalent to: * - *
          -     *     getJavaFileObjectsFromStrings({@linkplain java.util.Arrays#asList Arrays.asList}(names))
          -     * 
          + * {@snippet id="equiv-getJavaFileObjectsFromStrings" lang=java : + * getJavaFileObjectsFromStrings(Arrays.asList(names)) // @link substring="Arrays.asList" target="Arrays#asList" + * } * * @param names a list of file names * @return a list of file objects diff --git a/src/java.compiler/share/classes/javax/tools/StandardLocation.java b/src/java.compiler/share/classes/javax/tools/StandardLocation.java index afadab02f3d48f1dfae4eb3db56c2f6ef6aa1c95..2a9079f57245937ba814e93af8e90db068ee9c4d 100644 --- a/src/java.compiler/share/classes/javax/tools/StandardLocation.java +++ b/src/java.compiler/share/classes/javax/tools/StandardLocation.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 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 @@ -32,7 +32,6 @@ import java.util.concurrent.*; /** * Standard locations of file objects. * - * @author Peter von der Ahé * @since 1.6 */ public enum StandardLocation implements Location { diff --git a/src/java.compiler/share/classes/javax/tools/Tool.java b/src/java.compiler/share/classes/javax/tools/Tool.java index cb9a79d16455312e99a05dc94c6b8379a5868dd5..62c7fdb06c969a01c73741ed5e28328a243f5be8 100644 --- a/src/java.compiler/share/classes/javax/tools/Tool.java +++ b/src/java.compiler/share/classes/javax/tools/Tool.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -39,9 +39,6 @@ import javax.lang.model.SourceVersion; *

          Tools can be located using {@link * java.util.ServiceLoader#load(Class)}. * - * @author Neal M Gafter - * @author Peter von der Ahé - * @author Jonathan Gibbons * @since 1.6 */ public interface Tool { diff --git a/src/java.compiler/share/classes/javax/tools/ToolProvider.java b/src/java.compiler/share/classes/javax/tools/ToolProvider.java index 3e2bff923905394faf59ef92a85798796ed49884..d05b65b0ffe94c7b0e756cc5bc8edd84d5e2a9e0 100644 --- a/src/java.compiler/share/classes/javax/tools/ToolProvider.java +++ b/src/java.compiler/share/classes/javax/tools/ToolProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -36,7 +36,6 @@ import java.util.ServiceLoader; * providers of compilers. This class complements the * functionality of {@link java.util.ServiceLoader}. * - * @author Peter von der Ahé * @since 1.6 */ public class ToolProvider { diff --git a/src/java.compiler/share/classes/javax/tools/package-info.java b/src/java.compiler/share/classes/javax/tools/package-info.java index c5ec54e7871e0495204da9cc29df9996a20b2512..6a7a3c3bb329628b0e273733d868f51f53cf854c 100644 --- a/src/java.compiler/share/classes/javax/tools/package-info.java +++ b/src/java.compiler/share/classes/javax/tools/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -52,7 +52,9 @@ * a default compiler is provided, it can be located using the * {@link javax.tools.ToolProvider}, for example: * - *

          {@code JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();} + * {@snippet id="show-getSystemJavaCompiler" lang=java : + * JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); + * } * *

          It is possible to provide alternative compilers or tools * through the {@linkplain java.util.ServiceLoader service provider @@ -64,15 +66,17 @@ * META-INF/services/javax.tools.JavaCompiler}. This file would * contain the single line: * - *

          {@code com.vendor.VendorJavaCompiler} + * {@snippet id="show-service" : + * com.vendor.VendorJavaCompiler + * } * - *

          If the jar file is on the class path, VendorJavaCompiler can be + *

          If the jar file is on the class path, {@code VendorJavaCompiler} can be * located using code like this: * - *

          {@code JavaCompiler compiler = ServiceLoader.load(JavaCompiler.class).iterator().next();} + * {@snippet id="show-serviceLoader" lang=java : + * JavaCompiler compiler = ServiceLoader.load(JavaCompiler.class).iterator().next(); + * } * - * @author Peter von der Ahé - * @author Jonathan Gibbons * @since 1.6 */ package javax.tools; diff --git a/src/java.compiler/share/classes/javax/tools/snippet-files/JavaSourceFromString.java b/src/java.compiler/share/classes/javax/tools/snippet-files/JavaSourceFromString.java new file mode 100644 index 0000000000000000000000000000000000000000..f0555a02e9e3baf276857052c22659a1923d5bf1 --- /dev/null +++ b/src/java.compiler/share/classes/javax/tools/snippet-files/JavaSourceFromString.java @@ -0,0 +1,54 @@ +// @replace region replacement="" +/* + * 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. 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. + */ + +import javax.tools.SimpleJavaFileObject; +import java.net.URI; +// @end +/** + * A file object used to represent source coming from a string. + */ +public class JavaSourceFromString extends SimpleJavaFileObject { + /** + * The source code of this "file". + */ + final String code; + + /** + * Constructs a new JavaSourceFromString. + * @param name the name of the compilation unit represented by this file object + * @param code the source code for the compilation unit represented by this file object + */ + JavaSourceFromString(String name, String code) { + super(URI.create("string:///" + name.replace('.','/') + Kind.SOURCE.extension), // @link substring="URI.create" target="URI#create(String)" + Kind.SOURCE); + this.code = code; + } + + @Override + public CharSequence getCharContent(boolean ignoreEncodingErrors) { + return code; + } +} diff --git a/src/java.compiler/share/classes/module-info.java b/src/java.compiler/share/classes/module-info.java index 3d937e09f0cc88d558360becf9b7158f0199de09..0793855d1dc6efb9846d77c5219be91b8a25ce84 100644 --- a/src/java.compiler/share/classes/module-info.java +++ b/src/java.compiler/share/classes/module-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -24,7 +24,9 @@ */ /** - * Defines the Language Model, Annotation Processing, and Java Compiler APIs. + * Defines the {@index "Language Model"}, {@index "Annotation Processing"}, and + * {@index "Java Compiler"} APIs. + * *

          * These APIs model declarations and types of the Java programming language, * and define interfaces for tools such as compilers which can be invoked diff --git a/src/java.datatransfer/share/classes/java/awt/datatransfer/Clipboard.java b/src/java.datatransfer/share/classes/java/awt/datatransfer/Clipboard.java index ad3a56a701fd824b64ae6490274cc295e53e3050..bc3ed00a0300ad14f0b45ec30c1f7c7b792a66e9 100644 --- a/src/java.datatransfer/share/classes/java/awt/datatransfer/Clipboard.java +++ b/src/java.datatransfer/share/classes/java/awt/datatransfer/Clipboard.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 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 @@ -43,10 +43,11 @@ import sun.datatransfer.DataFlavorUtil; * * @author Amy Fowler * @author Alexander Gerasimov - * @see java.awt.Toolkit#getSystemClipboard - * @see java.awt.Toolkit#getSystemSelection + * @see java.desktop/java.awt.Toolkit#getSystemClipboard + * @see java.desktop/java.awt.Toolkit#getSystemSelection * @since 1.1 */ +@SuppressWarnings("doclint:reference") // cross-module links public class Clipboard { String name; @@ -81,7 +82,7 @@ public class Clipboard { * Creates a clipboard object. * * @param name for the clipboard - * @see java.awt.Toolkit#getSystemClipboard + * @see java.desktop/java.awt.Toolkit#getSystemClipboard */ public Clipboard(String name) { this.name = name; @@ -91,7 +92,7 @@ public class Clipboard { * Returns the name of this clipboard object. * * @return the name of this clipboard object - * @see java.awt.Toolkit#getSystemClipboard + * @see java.desktop/java.awt.Toolkit#getSystemClipboard */ public String getName() { return name; @@ -118,7 +119,7 @@ public class Clipboard { * content * @param owner the object which owns the clipboard content * @throws IllegalStateException if the clipboard is currently unavailable - * @see java.awt.Toolkit#getSystemClipboard + * @see java.desktop/java.awt.Toolkit#getSystemClipboard */ public synchronized void setContents(Transferable contents, ClipboardOwner owner) { final ClipboardOwner oldOwner = this.owner; @@ -145,7 +146,7 @@ public class Clipboard { * @param requestor the object requesting the clip data (not used) * @return the current transferable object on the clipboard * @throws IllegalStateException if the clipboard is currently unavailable - * @see java.awt.Toolkit#getSystemClipboard + * @see java.desktop/java.awt.Toolkit#getSystemClipboard */ public synchronized Transferable getContents(Object requestor) { return contents; diff --git a/make/data/fontconfig/aix.fontconfig.properties b/src/java.desktop/aix/data/fontconfig/fontconfig.properties similarity index 100% rename from make/data/fontconfig/aix.fontconfig.properties rename to src/java.desktop/aix/data/fontconfig/fontconfig.properties diff --git a/make/data/fontconfig/bsd.fontconfig.properties b/src/java.desktop/bsd/data/fontconfig/fontconfig.properties similarity index 100% rename from make/data/fontconfig/bsd.fontconfig.properties rename to src/java.desktop/bsd/data/fontconfig/fontconfig.properties diff --git a/src/java.desktop/macosx/classes/apple/laf/JRSUIControl.java b/src/java.desktop/macosx/classes/apple/laf/JRSUIControl.java index e3579449b7570396b7c0767272d2720ebfd27fe2..6e6c86ccf7ac33d8e1116a1c8bd4978cb7635e9a 100644 --- a/src/java.desktop/macosx/classes/apple/laf/JRSUIControl.java +++ b/src/java.desktop/macosx/classes/apple/laf/JRSUIControl.java @@ -114,7 +114,7 @@ public final class JRSUIControl { changes.putAll(other.changes); } - @SuppressWarnings("deprecation") + @SuppressWarnings("removal") protected synchronized void finalize() throws Throwable { if (cfDictionaryPtr == 0) return; disposeCFDictionary(cfDictionaryPtr); diff --git a/src/java.desktop/macosx/classes/com/apple/eawt/_AppEventHandler.java b/src/java.desktop/macosx/classes/com/apple/eawt/_AppEventHandler.java index e64e9b158b568d9f30726e80102607f51277d4b9..248ae55f6d74d4f59c89499a4924baea7c9d4185 100644 --- a/src/java.desktop/macosx/classes/com/apple/eawt/_AppEventHandler.java +++ b/src/java.desktop/macosx/classes/com/apple/eawt/_AppEventHandler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 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 @@ -281,7 +281,7 @@ class _AppEventHandler { } } - class _PreferencesDispatcher extends _AppEventDispatcher { + static class _PreferencesDispatcher extends _AppEventDispatcher { synchronized void setHandler(final PreferencesHandler handler) { super.setHandler(handler); @@ -294,20 +294,20 @@ class _AppEventHandler { } } - class _OpenAppDispatcher extends _QueuingAppEventDispatcher { + static class _OpenAppDispatcher extends _QueuingAppEventDispatcher { void performUsing(com.apple.eawt._OpenAppHandler handler, _NativeEvent event) { handler.handleOpenApp(); } } - class _AppReOpenedDispatcher extends _AppEventMultiplexor { + static class _AppReOpenedDispatcher extends _AppEventMultiplexor { void performOnListener(AppReopenedListener listener, final _NativeEvent event) { final AppReopenedEvent e = new AppReopenedEvent(); listener.appReopened(e); } } - class _AppForegroundDispatcher extends _BooleanAppEventMultiplexor { + static class _AppForegroundDispatcher extends _BooleanAppEventMultiplexor { AppForegroundEvent createEvent(final boolean isTrue) { return new AppForegroundEvent(); } void performFalseEventOn(final AppForegroundListener listener, final AppForegroundEvent e) { @@ -319,7 +319,7 @@ class _AppEventHandler { } } - class _HiddenAppDispatcher extends _BooleanAppEventMultiplexor { + static class _HiddenAppDispatcher extends _BooleanAppEventMultiplexor { AppHiddenEvent createEvent(final boolean isTrue) { return new AppHiddenEvent(); } void performFalseEventOn(final AppHiddenListener listener, final AppHiddenEvent e) { @@ -331,7 +331,7 @@ class _AppEventHandler { } } - class _UserSessionDispatcher extends _BooleanAppEventMultiplexor { + static class _UserSessionDispatcher extends _BooleanAppEventMultiplexor { UserSessionEvent createEvent(final boolean isTrue) { return new UserSessionEvent(Reason.UNSPECIFIED); } @@ -349,7 +349,7 @@ class _AppEventHandler { } } - class _ScreenSleepDispatcher extends _BooleanAppEventMultiplexor { + static class _ScreenSleepDispatcher extends _BooleanAppEventMultiplexor { ScreenSleepEvent createEvent(final boolean isTrue) { return new ScreenSleepEvent(); } void performFalseEventOn(final ScreenSleepListener listener, final ScreenSleepEvent e) { @@ -365,7 +365,7 @@ class _AppEventHandler { } } - class _SystemSleepDispatcher extends _BooleanAppEventMultiplexor { + static class _SystemSleepDispatcher extends _BooleanAppEventMultiplexor { SystemSleepEvent createEvent(final boolean isTrue) { return new SystemSleepEvent(); } void performFalseEventOn(final SystemSleepListener listener, final SystemSleepEvent e) { @@ -381,7 +381,7 @@ class _AppEventHandler { } } - class _OpenFileDispatcher extends _QueuingAppEventDispatcher { + static class _OpenFileDispatcher extends _QueuingAppEventDispatcher { void performUsing(final OpenFilesHandler handler, final _NativeEvent event) { // create file list from fileNames final List fileNameList = event.get(0); @@ -394,7 +394,7 @@ class _AppEventHandler { } } - class _PrintFileDispatcher extends _QueuingAppEventDispatcher { + static class _PrintFileDispatcher extends _QueuingAppEventDispatcher { void performUsing(final PrintFilesHandler handler, final _NativeEvent event) { // create file list from fileNames final List fileNameList = event.get(0); @@ -406,7 +406,7 @@ class _AppEventHandler { } // Java URLs can't handle unknown protocol types, which is why we use URIs - class _OpenURIDispatcher extends _QueuingAppEventDispatcher { + static class _OpenURIDispatcher extends _QueuingAppEventDispatcher { void performUsing(final OpenURIHandler handler, final _NativeEvent event) { final String urlString = event.get(0); try { @@ -450,7 +450,7 @@ class _AppEventHandler { } } - abstract class _AppEventMultiplexor { + abstract static class _AppEventMultiplexor { private final Map listenerToAppContext = new IdentityHashMap(); boolean nativeListenerRegistered; @@ -503,7 +503,7 @@ class _AppEventHandler { } } - abstract class _BooleanAppEventMultiplexor extends _AppEventMultiplexor { + abstract static class _BooleanAppEventMultiplexor extends _AppEventMultiplexor { @Override void performOnListener(L listener, final _NativeEvent event) { final boolean isTrue = Boolean.TRUE.equals(event.get(0)); @@ -530,7 +530,7 @@ class _AppEventHandler { * * User code is not (and should not be) run under any synchronized lock. */ - abstract class _AppEventDispatcher { + abstract static class _AppEventDispatcher { H _handler; AppContext handlerContext; @@ -575,7 +575,7 @@ class _AppEventHandler { } } - abstract class _QueuingAppEventDispatcher extends _AppEventDispatcher { + abstract static class _QueuingAppEventDispatcher extends _AppEventDispatcher { List<_NativeEvent> queuedEvents = new LinkedList<_NativeEvent>(); @Override diff --git a/src/java.desktop/macosx/classes/com/apple/laf/AquaBorder.java b/src/java.desktop/macosx/classes/com/apple/laf/AquaBorder.java index f9e099fd4d48c3765f2013866ffab90954a6ea9c..cf75ab164bac54104e30e32113f9f401b7d51ae1 100644 --- a/src/java.desktop/macosx/classes/com/apple/laf/AquaBorder.java +++ b/src/java.desktop/macosx/classes/com/apple/laf/AquaBorder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 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 @@ -128,7 +128,7 @@ public abstract class AquaBorder implements Border, UIResource { if (!((javax.swing.text.JTextComponent)focusable).isEditable()) return false; } - return (focusable != null && focusable instanceof JComponent && ((JComponent)focusable).hasFocus()); + return (focusable instanceof JComponent jComponent) && jComponent.hasFocus(); } @Override diff --git a/src/java.desktop/macosx/classes/com/apple/laf/AquaButtonBorder.java b/src/java.desktop/macosx/classes/com/apple/laf/AquaButtonBorder.java index f58c518d2d4179911e913f5f414c21268e8adc33..1d11a0a8d96f4e35ebe60d1b8bf66916a52f4508 100644 --- a/src/java.desktop/macosx/classes/com/apple/laf/AquaButtonBorder.java +++ b/src/java.desktop/macosx/classes/com/apple/laf/AquaButtonBorder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 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 @@ -145,9 +145,9 @@ public abstract class AquaButtonBorder extends AquaBorder implements Border, UIR * @param c the component for which this border insets value applies */ public Insets getBorderInsets(final Component c) { - if (c == null || !(c instanceof AbstractButton)) return new Insets(0, 0, 0, 0); + if (!(c instanceof AbstractButton button)) return new Insets(0, 0, 0, 0); - Insets margin = ((AbstractButton)c).getMargin(); + Insets margin = button.getMargin(); margin = (margin == null) ? new InsetsUIResource(0, 0, 0, 0) : (Insets)margin.clone(); margin.top += sizeVariant.margins.top; diff --git a/src/java.desktop/macosx/classes/com/apple/laf/AquaButtonLabeledUI.java b/src/java.desktop/macosx/classes/com/apple/laf/AquaButtonLabeledUI.java index 3a9ed6b12f511e960e8703f7c407e35cbe0c504b..3c21b325f36cfb400a46b1a9a1dd9ffe751fd33c 100644 --- a/src/java.desktop/macosx/classes/com/apple/laf/AquaButtonLabeledUI.java +++ b/src/java.desktop/macosx/classes/com/apple/laf/AquaButtonLabeledUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 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 @@ -170,7 +170,7 @@ public abstract class AquaButtonLabeledUI extends AquaButtonToggleUI implements } int offset = 0; - if (b.isFocusOwner()) { + if (b.isFocusOwner() && b.isFocusPainted()) { offset = 2; altIcon = AquaFocus.createFocusedIcon(altIcon, c, 2); } diff --git a/src/java.desktop/macosx/classes/com/apple/laf/AquaButtonUI.java b/src/java.desktop/macosx/classes/com/apple/laf/AquaButtonUI.java index 38f409f81fd24c0bd1cf8fc875e6639d38e20512..1ed74c0d9b000b68efdf594b614efb014bf5fb56 100644 --- a/src/java.desktop/macosx/classes/com/apple/laf/AquaButtonUI.java +++ b/src/java.desktop/macosx/classes/com/apple/laf/AquaButtonUI.java @@ -305,7 +305,15 @@ public class AquaButtonUI extends BasicButtonUI implements Sizeable { } // performs icon and text rect calculations - final String text = layoutAndGetText(g, b, aquaBorder, i, viewRect, iconRect, textRect); + final String text; + final View v = (View)c.getClientProperty(BasicHTML.propertyKey); + if (v != null) { + // use zero insets for view since layout only handles text calculations + text = layoutAndGetText(g, b, aquaBorder, new Insets(0,0,0,0), + viewRect, iconRect, textRect); + } else { + text = layoutAndGetText(g, b, aquaBorder, i, viewRect, iconRect, textRect); + } // Paint the Icon if (b.getIcon() != null) { @@ -317,7 +325,6 @@ public class AquaButtonUI extends BasicButtonUI implements Sizeable { } if (text != null && !text.isEmpty()) { - final View v = (View)c.getClientProperty(BasicHTML.propertyKey); if (v != null) { v.paint(g, textRect); } else { diff --git a/src/java.desktop/macosx/classes/com/apple/laf/AquaComboBoxUI.java b/src/java.desktop/macosx/classes/com/apple/laf/AquaComboBoxUI.java index 06f84d0eae12e5a27bb3cbde969891ce8ef39f87..c25d89559fc0c25e17a01ef01916761842e79502 100644 --- a/src/java.desktop/macosx/classes/com/apple/laf/AquaComboBoxUI.java +++ b/src/java.desktop/macosx/classes/com/apple/laf/AquaComboBoxUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 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 @@ -598,8 +598,7 @@ public class AquaComboBoxUI extends BasicComboBoxUI implements Sizeable { final boolean editable = comboBox.isEditable(); final Dimension size; - if (!editable && arrowButton != null && arrowButton instanceof AquaComboBoxButton) { - final AquaComboBoxButton button = (AquaComboBoxButton)arrowButton; + if (!editable && arrowButton instanceof final AquaComboBoxButton button) { final Insets buttonInsets = button.getInsets(); // Insets insets = comboBox.getInsets(); final Insets insets = new Insets(0, 5, 0, 25);//comboBox.getInsets(); diff --git a/src/java.desktop/macosx/classes/com/apple/laf/AquaFileChooserUI.java b/src/java.desktop/macosx/classes/com/apple/laf/AquaFileChooserUI.java index 71a4f01211607e2a3b1b193265ace9ffbeee4833..d8bfca02fe75d9dd1063e98dbdf95734f85513c8 100644 --- a/src/java.desktop/macosx/classes/com/apple/laf/AquaFileChooserUI.java +++ b/src/java.desktop/macosx/classes/com/apple/laf/AquaFileChooserUI.java @@ -519,14 +519,14 @@ public class AquaFileChooserUI extends FileChooserUI { void setPackageIsTraversable(final Object o) { int newProp = -1; - if (o != null && o instanceof String) newProp = parseTraversableProperty((String)o); + if (o instanceof String s) newProp = parseTraversableProperty(s); if (newProp != -1) fPackageIsTraversable = newProp; else fPackageIsTraversable = sGlobalPackageIsTraversable; } void setApplicationIsTraversable(final Object o) { int newProp = -1; - if (o != null && o instanceof String) newProp = parseTraversableProperty((String)o); + if (o instanceof String s) newProp = parseTraversableProperty(s); if (newProp != -1) fApplicationIsTraversable = newProp; else fApplicationIsTraversable = sGlobalApplicationIsTraversable; } @@ -1985,11 +1985,11 @@ public class AquaFileChooserUI extends FileChooserUI { static { Object o = UIManager.get(PACKAGE_TRAVERSABLE_PROPERTY); - if (o != null && o instanceof String) sGlobalPackageIsTraversable = parseTraversableProperty((String)o); + if (o instanceof String s) sGlobalPackageIsTraversable = parseTraversableProperty(s); else sGlobalPackageIsTraversable = kOpenConditional; o = UIManager.get(APPLICATION_TRAVERSABLE_PROPERTY); - if (o != null && o instanceof String) sGlobalApplicationIsTraversable = parseTraversableProperty((String)o); + if (o instanceof String s) sGlobalApplicationIsTraversable = parseTraversableProperty(s); else sGlobalApplicationIsTraversable = kOpenConditional; } static final String sDataPrefix = "FileChooser."; @@ -2445,7 +2445,7 @@ public class AquaFileChooserUI extends FileChooserUI { // Convenience, to translate from the JList directory view to the Mac-style JTable // & minimize diffs between this and BasicFileChooserUI @SuppressWarnings("serial") // Superclass is not serializable across versions - class JTableExtension extends JTable { + static class JTableExtension extends JTable { public void setSelectedIndex(final int index) { getSelectionModel().setSelectionInterval(index, index); } diff --git a/src/java.desktop/macosx/classes/com/apple/laf/AquaFileSystemModel.java b/src/java.desktop/macosx/classes/com/apple/laf/AquaFileSystemModel.java index 14aa78ec8498f2bd1e9dfeb02da50fb49d533e91..80ffc080f999e20663670e727d66dc757c775220 100644 --- a/src/java.desktop/macosx/classes/com/apple/laf/AquaFileSystemModel.java +++ b/src/java.desktop/macosx/classes/com/apple/laf/AquaFileSystemModel.java @@ -278,7 +278,7 @@ class AquaFileSystemModel extends AbstractTableModel implements PropertyChangeLi // @param a an integer array // @param lo0 left boundary of array partition // @param hi0 right boundary of array partition - abstract class QuickSort { + abstract static class QuickSort { final void quickSort(final Vector v, final int lo0, final int hi0) { int lo = lo0; int hi = hi0; @@ -338,7 +338,7 @@ class AquaFileSystemModel extends AbstractTableModel implements PropertyChangeLi protected abstract boolean lt(SortableFile a, SortableFile b); } - class QuickSortNames extends QuickSort { + static class QuickSortNames extends QuickSort { protected boolean lt(final SortableFile a, final SortableFile b) { final String aLower = a.fName.toLowerCase(); final String bLower = b.fName.toLowerCase(); @@ -346,14 +346,14 @@ class AquaFileSystemModel extends AbstractTableModel implements PropertyChangeLi } } - class QuickSortDates extends QuickSort { + static class QuickSortDates extends QuickSort { protected boolean lt(final SortableFile a, final SortableFile b) { return a.fDateValue < b.fDateValue; } } // for speed in sorting, displaying - class SortableFile /* extends FileView */{ + static class SortableFile /* extends FileView */{ File fFile; String fName; long fDateValue; diff --git a/src/java.desktop/macosx/classes/com/apple/laf/AquaInternalFrameBorder.java b/src/java.desktop/macosx/classes/com/apple/laf/AquaInternalFrameBorder.java index a5165710ea7ffb8a76e3312d74308771032189eb..74697ed417bca5ba24eb9733cf2352c22e6e2312 100644 --- a/src/java.desktop/macosx/classes/com/apple/laf/AquaInternalFrameBorder.java +++ b/src/java.desktop/macosx/classes/com/apple/laf/AquaInternalFrameBorder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 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 @@ -378,9 +378,7 @@ public class AquaInternalFrameBorder implements Border, UIResource { final int x = inX; final int y = inY; final int w = inW; - int h = inH; - - h = metrics.titleBarHeight + inH; + final int h = inH; // paint the background titleBarPainter.state.set(frame.isSelected() ? State.ACTIVE : State.INACTIVE); diff --git a/src/java.desktop/macosx/classes/com/apple/laf/AquaInternalFramePaneUI.java b/src/java.desktop/macosx/classes/com/apple/laf/AquaInternalFramePaneUI.java index e12033fceb5feb1fa8fd7df8e4f078da21882fbb..a0c26ac7841236a9216e6830d5f41c06859a168c 100644 --- a/src/java.desktop/macosx/classes/com/apple/laf/AquaInternalFramePaneUI.java +++ b/src/java.desktop/macosx/classes/com/apple/laf/AquaInternalFramePaneUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 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 @@ -187,7 +187,7 @@ public class AquaInternalFramePaneUI extends BasicDesktopPaneUI implements Mouse } @SuppressWarnings("serial") // JDK implementation class - class AquaDockingDesktopManager extends AquaInternalFrameManager { + static class AquaDockingDesktopManager extends AquaInternalFrameManager { public void openFrame(final JInternalFrame f) { final JInternalFrame.JDesktopIcon desktopIcon = f.getDesktopIcon(); final Container dock = desktopIcon.getParent(); diff --git a/src/java.desktop/macosx/classes/com/apple/laf/AquaLookAndFeel.java b/src/java.desktop/macosx/classes/com/apple/laf/AquaLookAndFeel.java index 610b408c99b372cd8330543b75b088d8f8fc4c1a..dad0b2279ebeff20c6e653803205e7e5e2564575 100644 --- a/src/java.desktop/macosx/classes/com/apple/laf/AquaLookAndFeel.java +++ b/src/java.desktop/macosx/classes/com/apple/laf/AquaLookAndFeel.java @@ -188,8 +188,8 @@ public class AquaLookAndFeel extends BasicLookAndFeel { KeyboardFocusManager.getCurrentKeyboardFocusManager().removeKeyEventPostProcessor(AquaMnemonicHandler.getInstance()); final PopupFactory popupFactory = PopupFactory.getSharedInstance(); - if (popupFactory != null && popupFactory instanceof ScreenPopupFactory) { - ((ScreenPopupFactory)popupFactory).setActive(false); + if (popupFactory instanceof ScreenPopupFactory spf) { + spf.setActive(false); } super.uninitialize(); diff --git a/src/java.desktop/macosx/classes/com/apple/laf/AquaRootPaneUI.java b/src/java.desktop/macosx/classes/com/apple/laf/AquaRootPaneUI.java index a4e179645a958bd3d6e916845233b45d86e89e00..2b4e1bb0867f8e6a46483bffd26d75367940b884 100644 --- a/src/java.desktop/macosx/classes/com/apple/laf/AquaRootPaneUI.java +++ b/src/java.desktop/macosx/classes/com/apple/laf/AquaRootPaneUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 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 @@ -75,8 +75,7 @@ public class AquaRootPaneUI extends BasicRootPaneUI implements AncestorListener, // it is not since we are going to grab the one that was set on the JFrame. :( final Component parent = c.getParent(); - if (parent != null && parent instanceof JFrame) { - final JFrame frameParent = (JFrame)parent; + if (parent instanceof JFrame frameParent) { final Color bg = frameParent.getBackground(); if (bg == null || bg instanceof UIResource) { frameParent.setBackground(UIManager.getColor("Panel.background")); @@ -126,8 +125,8 @@ public class AquaRootPaneUI extends BasicRootPaneUI implements AncestorListener, final Window owningWindow = SwingUtilities.getWindowAncestor(jmb); // Could be a JDialog, and may have been added to a JRootPane not yet in a window. - if (owningWindow != null && owningWindow instanceof JFrame) { - ((AquaMenuBarUI)mbui).setScreenMenuBar((JFrame)owningWindow); + if (owningWindow instanceof JFrame frame) { + ((AquaMenuBarUI)mbui).setScreenMenuBar(frame); } } } @@ -154,8 +153,8 @@ public class AquaRootPaneUI extends BasicRootPaneUI implements AncestorListener, final Window owningWindow = SwingUtilities.getWindowAncestor(jmb); // Could be a JDialog, and may have been added to a JRootPane not yet in a window. - if (owningWindow != null && owningWindow instanceof JFrame) { - ((AquaMenuBarUI)mbui).clearScreenMenuBar((JFrame)owningWindow); + if (owningWindow instanceof JFrame frame) { + ((AquaMenuBarUI)mbui).clearScreenMenuBar(frame); } } } diff --git a/src/java.desktop/macosx/classes/com/apple/laf/AquaScrollBarUI.java b/src/java.desktop/macosx/classes/com/apple/laf/AquaScrollBarUI.java index 9d87013c48e2c29056033ee13aedc0630f9ccc11..ea239d83a23a6a91192f81dba3814e689e3a2881 100644 --- a/src/java.desktop/macosx/classes/com/apple/laf/AquaScrollBarUI.java +++ b/src/java.desktop/macosx/classes/com/apple/laf/AquaScrollBarUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -144,7 +144,8 @@ public class AquaScrollBarUI extends ScrollBarUI { public void paint(final Graphics g, final JComponent c) { syncState(c); - painter.paint(g, c, 0, 0, fScrollBar.getWidth(), fScrollBar.getHeight()); + Rectangle trackBounds = getTrackBounds(); + painter.paint(g, c, trackBounds.x, trackBounds.y, trackBounds.width, trackBounds.height); } protected State getState(final JComponent c, final ScrollBarPart pressedPart) { @@ -188,11 +189,17 @@ public class AquaScrollBarUI extends ScrollBarUI { } protected Rectangle getTrackBounds() { - return new Rectangle(0, 0, fScrollBar.getWidth(), fScrollBar.getHeight()); + Insets insets = fScrollBar.getInsets(); + return new Rectangle(insets.left, insets.top, + fScrollBar.getWidth() - (insets.left + insets.right), + fScrollBar.getHeight() - (insets.top + insets.bottom)); } protected Rectangle getDragBounds() { - return new Rectangle(0, 0, fScrollBar.getWidth(), fScrollBar.getHeight()); + Insets insets = fScrollBar.getInsets(); + return new Rectangle(insets.left, insets.top, + fScrollBar.getWidth() - (insets.left + insets.right), + fScrollBar.getHeight() - (insets.top + insets.bottom)); } protected void startTimer(final boolean initial) { @@ -228,7 +235,10 @@ public class AquaScrollBarUI extends ScrollBarUI { protected Hit getPartHit(final int x, final int y) { syncState(fScrollBar); - return JRSUIUtils.HitDetection.getHitForPoint(painter.getControl(), 0, 0, fScrollBar.getWidth(), fScrollBar.getHeight(), x, y); + Insets insets = fScrollBar.getInsets(); + return JRSUIUtils.HitDetection.getHitForPoint(painter.getControl(), insets.left, insets.top, + fScrollBar.getWidth() - (insets.left + insets.right), + fScrollBar.getHeight() - (insets.top + insets.bottom), x, y); } protected class PropertyChangeHandler implements PropertyChangeListener { @@ -344,7 +354,9 @@ public class AquaScrollBarUI extends ScrollBarUI { // scroller goes 0-100 with a visible area of 20 we are getting a ratio of the // remaining 80. syncState(fScrollBar); - final double offsetChange = JRSUIUtils.ScrollBar.getNativeOffsetChange(painter.getControl(), 0, 0, fScrollBar.getWidth(), fScrollBar.getHeight(), offsetWeCareAbout, visibleAmt, extent); + final Rectangle limitRect = getDragBounds(); // GetThemeTrackDragRect + final double offsetChange = JRSUIUtils.ScrollBar.getNativeOffsetChange(painter.getControl(), + limitRect.x, limitRect.y, limitRect.width, limitRect.height, offsetWeCareAbout, visibleAmt, extent); // the scrollable area is the extent - visible amount; final int scrollableArea = extent - visibleAmt; @@ -597,7 +609,7 @@ public class AquaScrollBarUI extends ScrollBarUI { // determine the bounding rectangle for our thumb region syncState(fScrollBar); double[] rect = new double[4]; - JRSUIUtils.ScrollBar.getPartBounds(rect, painter.getControl(), 0, 0, fScrollBar.getWidth(), fScrollBar.getHeight(), ScrollBarPart.THUMB); + JRSUIUtils.ScrollBar.getPartBounds(rect, painter.getControl(), limitRect.x, limitRect.y, limitRect.width, limitRect.height, ScrollBarPart.THUMB); final Rectangle r = new Rectangle((int)rect[0], (int)rect[1], (int)rect[2], (int)rect[3]); // figure out the scroll-to-here start location based on our orientation, the diff --git a/src/java.desktop/macosx/classes/com/apple/laf/AquaSliderUI.java b/src/java.desktop/macosx/classes/com/apple/laf/AquaSliderUI.java index 3775fc859e44348111e479578bc190d68dd412ab..50da054c1f8dcb5b27830953a5e81b261de0bbe6 100644 --- a/src/java.desktop/macosx/classes/com/apple/laf/AquaSliderUI.java +++ b/src/java.desktop/macosx/classes/com/apple/laf/AquaSliderUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 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 @@ -266,8 +266,8 @@ public class AquaSliderUI extends BasicSliderUI implements Sizeable { if (slider.getPaintTicks() || slider.getPaintLabels()) return true; final Object shouldPaintArrowThumbProperty = slider.getClientProperty("Slider.paintThumbArrowShape"); - if (shouldPaintArrowThumbProperty != null && shouldPaintArrowThumbProperty instanceof Boolean) { - return ((Boolean)shouldPaintArrowThumbProperty).booleanValue(); + if (shouldPaintArrowThumbProperty instanceof Boolean b) { + return b; } return false; diff --git a/src/java.desktop/macosx/classes/com/apple/laf/AquaTabbedPaneCopyFromBasicUI.java b/src/java.desktop/macosx/classes/com/apple/laf/AquaTabbedPaneCopyFromBasicUI.java index 5722b28e576c6a40856267219443c69816b42025..6c92b5bbf8ad729b2026d160d737cc55a85cf106 100644 --- a/src/java.desktop/macosx/classes/com/apple/laf/AquaTabbedPaneCopyFromBasicUI.java +++ b/src/java.desktop/macosx/classes/com/apple/laf/AquaTabbedPaneCopyFromBasicUI.java @@ -3261,7 +3261,7 @@ public class AquaTabbedPaneCopyFromBasicUI extends TabbedPaneUI implements Swing } @SuppressWarnings("serial") // Superclass is not serializable across versions - private class ScrollableTabButton extends javax.swing.plaf.basic.BasicArrowButton implements UIResource, SwingConstants { + private static class ScrollableTabButton extends javax.swing.plaf.basic.BasicArrowButton implements UIResource, SwingConstants { public ScrollableTabButton(final int direction) { super(direction, UIManager.getColor("TabbedPane.selected"), UIManager.getColor("TabbedPane.shadow"), UIManager.getColor("TabbedPane.darkShadow"), UIManager.getColor("TabbedPane.highlight")); } diff --git a/src/java.desktop/macosx/classes/com/apple/laf/AquaTableHeaderBorder.java b/src/java.desktop/macosx/classes/com/apple/laf/AquaTableHeaderBorder.java index 68aafa5119ee2b16d8473607acba5ee2652bb47f..04f0d08edf0327f683ea901fa82736df9cc1b049 100644 --- a/src/java.desktop/macosx/classes/com/apple/laf/AquaTableHeaderBorder.java +++ b/src/java.desktop/macosx/classes/com/apple/laf/AquaTableHeaderBorder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 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 @@ -105,7 +105,7 @@ public class AquaTableHeaderBorder extends AbstractBorder { final int newWidth = width; final int newHeight = height; - painter.paint(g, c, newX - 1, newY - 1, newWidth + 1, newHeight); + painter.paint(g, c, newX - 1, newY - 1, newWidth + 1, newHeight + 1); // Draw the header g.clipRect(newX, y, newWidth, height); diff --git a/src/java.desktop/macosx/classes/com/apple/laf/AquaTableHeaderUI.java b/src/java.desktop/macosx/classes/com/apple/laf/AquaTableHeaderUI.java index 85577ce46ca458377b1f0a31e4959fa1cdc84ccb..af5621657de1cd8fda58890ab3478376d51c713e 100644 --- a/src/java.desktop/macosx/classes/com/apple/laf/AquaTableHeaderUI.java +++ b/src/java.desktop/macosx/classes/com/apple/laf/AquaTableHeaderUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 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 @@ -103,9 +103,8 @@ public class AquaTableHeaderUI extends BasicTableHeaderUI { } final TableHeaderUI headerUI = target.getUI(); - if (headerUI == null || !(headerUI instanceof AquaTableHeaderUI)) return; + if (!(headerUI instanceof AquaTableHeaderUI aquaHeaderUI)) return; - final AquaTableHeaderUI aquaHeaderUI = (AquaTableHeaderUI)headerUI; aquaHeaderUI.sortColumn = tableColumn.getModelIndex(); aquaHeaderUI.sortOrder = sortDirection; final AquaTableCellRenderer renderer = aquaHeaderUI.new AquaTableCellRenderer(); @@ -145,8 +144,7 @@ public class AquaTableHeaderUI extends BasicTableHeaderUI { } protected static TableColumn getTableColumn(final JTableHeader target, final Object value) { - if (value == null || !(value instanceof Integer)) return null; - final int columnIndex = ((Integer)value).intValue(); + if (!(value instanceof Integer columnIndex)) return null; final TableColumnModel columnModel = target.getColumnModel(); if (columnIndex < 0 || columnIndex >= columnModel.getColumnCount()) return null; diff --git a/src/java.desktop/macosx/classes/com/apple/laf/ScreenMenu.java b/src/java.desktop/macosx/classes/com/apple/laf/ScreenMenu.java index 4f6e006faf82825227cc311faa92f04a54074728..747e8ac137ecfc35cf6c939eecc0f4da4d374a5c 100644 --- a/src/java.desktop/macosx/classes/com/apple/laf/ScreenMenu.java +++ b/src/java.desktop/macosx/classes/com/apple/laf/ScreenMenu.java @@ -351,11 +351,8 @@ final class ScreenMenu extends Menu // Tell our parent to add/remove us final MenuContainer parent = getParent(); - if (parent != null) { - if (parent instanceof ScreenMenu) { - final ScreenMenu sm = (ScreenMenu)parent; - sm.setChildVisible(fInvoker, b); - } + if (parent instanceof ScreenMenu sm) { + sm.setChildVisible(fInvoker, b); } } diff --git a/src/java.desktop/macosx/classes/sun/awt/CGraphicsEnvironment.java b/src/java.desktop/macosx/classes/sun/awt/CGraphicsEnvironment.java index e96ce7e18d79ac35bf2552e1ac6ef92b4278f7b0..fe4431e3091284a994bbc42e40f50330a41638dc 100644 --- a/src/java.desktop/macosx/classes/sun/awt/CGraphicsEnvironment.java +++ b/src/java.desktop/macosx/classes/sun/awt/CGraphicsEnvironment.java @@ -144,7 +144,7 @@ public final class CGraphicsEnvironment extends SunGraphicsEnvironment { } @Override - @SuppressWarnings("deprecation") + @SuppressWarnings("removal") protected void finalize() throws Throwable { try { super.finalize(); diff --git a/src/java.desktop/macosx/classes/sun/font/CFont.java b/src/java.desktop/macosx/classes/sun/font/CFont.java index 885fc7fc471d2bb3241b9d06b138ea76fe31cb10..073364719f04d06ef5ea155ce6d38609dc5ad838 100644 --- a/src/java.desktop/macosx/classes/sun/font/CFont.java +++ b/src/java.desktop/macosx/classes/sun/font/CFont.java @@ -206,7 +206,7 @@ public final class CFont extends PhysicalFont implements FontSubstitution { // In some italic cases the standard Mac cascade list is missing Arabic. listOfString.add("GeezaPro"); - FontManager fm = FontManagerFactory.getInstance(); + CFontManager fm = (CFontManager) FontManagerFactory.getInstance(); int numFonts = 1 + listOfString.size(); PhysicalFont[] fonts = new PhysicalFont[numFonts]; fonts[0] = this; @@ -222,7 +222,7 @@ public final class CFont extends PhysicalFont implements FontSubstitution { // Don't know why we get the weird name above .. replace. s = "AppleSymbols"; } - Font2D f2d = fm.findFont2D(s, Font.PLAIN, FontManager.NO_FALLBACK); + Font2D f2d = fm.getOrCreateFallbackFont(s); if (f2d == null || f2d == this) { continue; } @@ -247,7 +247,7 @@ public final class CFont extends PhysicalFont implements FontSubstitution { return compFont; } - @SuppressWarnings("deprecation") + @SuppressWarnings("removal") protected synchronized void finalize() { if (nativeFontPtr != 0) { disposeNativeFont(nativeFontPtr); diff --git a/src/java.desktop/macosx/classes/sun/font/CFontManager.java b/src/java.desktop/macosx/classes/sun/font/CFontManager.java index 85182158ec152c3c130c7a8b6b087fd46d0b7b3a..5af2be3f60c97d158d7f8568f0b1478e92cec16d 100644 --- a/src/java.desktop/macosx/classes/sun/font/CFontManager.java +++ b/src/java.desktop/macosx/classes/sun/font/CFontManager.java @@ -33,8 +33,10 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.Hashtable; import java.util.Locale; +import java.util.Map; import java.util.TreeMap; import java.util.Vector; +import java.util.concurrent.ConcurrentHashMap; import javax.swing.plaf.FontUIResource; @@ -45,6 +47,7 @@ import sun.lwawt.macosx.*; public final class CFontManager extends SunFontManager { private static Hashtable genericFonts = new Hashtable(); + private final Map fallbackFonts = new ConcurrentHashMap<>(); @Override protected FontConfiguration createFontConfiguration() { @@ -283,9 +286,9 @@ public final class CFontManager extends SunFontManager { if (realFamily == null) return false; Font2D realFont = realFamily.getFontWithExactStyleMatch(style); - if (realFont == null || !(realFont instanceof CFont)) return false; + if (!(realFont instanceof CFont cFont)) return false; - CFont newFont = new CFont((CFont)realFont, logicalFamilyName); + CFont newFont = new CFont(cFont, logicalFamilyName); registerGenericFont(newFont, true); return true; @@ -321,4 +324,17 @@ public final class CFontManager extends SunFontManager { @Override protected void populateFontFileNameMap(HashMap fontToFileMap, HashMap fontToFamilyNameMap, HashMap> familyToFontListMap, Locale locale) {} + + Font2D getOrCreateFallbackFont(String fontName) { + Font2D font2D = findFont2D(fontName, Font.PLAIN, FontManager.NO_FALLBACK); + if (font2D != null || fontName.startsWith(".")) { + return font2D; + } else { + // macOS doesn't list some system fonts in [NSFontManager availableFontFamilies] output, + // so they are not registered in font manager as part of 'loadNativeFonts'. + // These fonts are present in [NSFontManager availableFonts] output though, + // and can be accessed in the same way as other system fonts. + return fallbackFonts.computeIfAbsent(fontName, name -> new CFont(name, null)); + } + } } diff --git a/src/java.desktop/macosx/classes/sun/font/CStrike.java b/src/java.desktop/macosx/classes/sun/font/CStrike.java index 088fb01591e2b83031bc59e6463c2e7e78c26a3d..eb049c3d449d4b1ffb975090ff7e2c9062244bc6 100644 --- a/src/java.desktop/macosx/classes/sun/font/CStrike.java +++ b/src/java.desktop/macosx/classes/sun/font/CStrike.java @@ -125,7 +125,7 @@ public final class CStrike extends PhysicalStrike { return nativeStrikePtr; } - @SuppressWarnings("deprecation") + @SuppressWarnings("removal") protected synchronized void finalize() throws Throwable { if (nativeStrikePtr != 0) { disposeNativeStrikePtr(nativeStrikePtr); diff --git a/src/java.desktop/macosx/classes/sun/java2d/metal/MTLRenderer.java b/src/java.desktop/macosx/classes/sun/java2d/metal/MTLRenderer.java index 5ca368d446eeba742c83a4c501d1070ac7862a27..5f4b8183d42aab5e928672b20d1230d0da8445aa 100644 --- a/src/java.desktop/macosx/classes/sun/java2d/metal/MTLRenderer.java +++ b/src/java.desktop/macosx/classes/sun/java2d/metal/MTLRenderer.java @@ -110,7 +110,7 @@ class MTLRenderer extends BufferedRenderPipe { return new Tracer(this); } - private class Tracer extends MTLRenderer { + private static class Tracer extends MTLRenderer { private MTLRenderer mtlr; Tracer(MTLRenderer mtlr) { super(mtlr.rq); diff --git a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessibility.java b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessibility.java index 2f23d8d0fdf258dd956d0508ac628ff73e34a78c..f338f25f05ed8d4d6a75582b7e4aa60b93ed06cf 100644 --- a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessibility.java +++ b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessibility.java @@ -627,8 +627,8 @@ class CAccessibility implements PropertyChangeListener { return invokeAndWait(new Callable() { public Accessible call() throws Exception { Component c = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner(); - if (c == null || !(c instanceof Accessible)) return null; - return CAccessible.getCAccessible((Accessible)c); + if (!(c instanceof Accessible accessible)) return null; + return CAccessible.getCAccessible(accessible); } }, c); } diff --git a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessible.java b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessible.java index b59c8cfe57435fff20f9505e5f8321a318f8580b..d983635f9e9d7f9131ce0fe11d4d127dba9acb64 100644 --- a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessible.java +++ b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessible.java @@ -164,24 +164,18 @@ class CAccessible extends CFRetainedResource implements Accessible { treeNodeCollapsed(ptr); } - // At least for now don't handle combo box menu state changes. - // This may change when later fixing issues which currently - // exist for combo boxes, but for now the following is only - // for JPopupMenus, not for combobox menus. - if (parentRole != AccessibleRole.COMBO_BOX) { - if (thisRole == AccessibleRole.POPUP_MENU) { - if ( newValue != null && - ((AccessibleState)newValue) == AccessibleState.VISIBLE ) { - menuOpened(ptr); - } else if ( oldValue != null && - ((AccessibleState)oldValue) == AccessibleState.VISIBLE ) { - menuClosed(ptr); - } - } else if (thisRole == AccessibleRole.MENU_ITEM) { - if ( newValue != null && - ((AccessibleState)newValue) == AccessibleState.FOCUSED ) { - menuItemSelected(ptr); - } + if (thisRole == AccessibleRole.POPUP_MENU) { + if ( newValue != null && + ((AccessibleState)newValue) == AccessibleState.VISIBLE ) { + menuOpened(ptr); + } else if ( oldValue != null && + ((AccessibleState)oldValue) == AccessibleState.VISIBLE ) { + menuClosed(ptr); + } + } else if (thisRole == AccessibleRole.MENU_ITEM) { + if ( newValue != null && + ((AccessibleState)newValue) == AccessibleState.FOCUSED ) { + menuItemSelected(ptr); } } diff --git a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CDataTransferer.java b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CDataTransferer.java index 0ea70549d430b33bf41f263e8a805c3ccb6eab60..e6a16ed670fc2808e85f3da8f5b1dea85564e04d 100644 --- a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CDataTransferer.java +++ b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CDataTransferer.java @@ -33,8 +33,6 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.net.URL; import java.nio.charset.Charset; -import java.text.Normalizer; -import java.text.Normalizer.Form; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -165,9 +163,6 @@ public class CDataTransferer extends DataTransferer { // regular string that allows to translate data to target represantation // class by base method format = CF_STRING; - } else if (format == CF_STRING) { - String src = new String(bytes, UTF_8); - bytes = Normalizer.normalize(src, Form.NFC).getBytes(UTF_8); } return super.translateBytes(bytes, flavor, format, transferable); diff --git a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CFRetainedResource.java b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CFRetainedResource.java index de0553501e6b400a06c0e807ac581ac8384a54c5..43d6c218b29686652edc52357254e76a875f421b 100644 --- a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CFRetainedResource.java +++ b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CFRetainedResource.java @@ -163,7 +163,7 @@ public class CFRetainedResource { } @Override - @SuppressWarnings("deprecation") + @SuppressWarnings("removal") protected final void finalize() throws Throwable { dispose(); } diff --git a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java index eb97221dc728893322ebd7b5d0d78580e105ba68..1aa4eae1e5d1b375663aed01382a9d61549fc304 100644 --- a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java +++ b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java @@ -244,12 +244,12 @@ public class CPlatformWindow extends CFRetainedResource implements PlatformWindo c.execute(ptr -> nativeRevalidateNSWindowShadow(ptr)); }}, new Property(WINDOW_DOCUMENT_FILE) { public void applyProperty(final CPlatformWindow c, final Object value) { - if (value == null || !(value instanceof java.io.File)) { + if (!(value instanceof java.io.File file)) { c.execute(ptr->nativeSetNSWindowRepresentedFilename(ptr, null)); return; } - final String filename = ((java.io.File)value).getAbsolutePath(); + final String filename = file.getAbsolutePath(); c.execute(ptr->nativeSetNSWindowRepresentedFilename(ptr, filename)); }}, new Property(WINDOW_FULL_CONTENT) { diff --git a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPrinterJob.java b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPrinterJob.java index 4849c16b79f0ce303e8816d89872dabbcf32d158..8dd0246228437192f5d08799196fb925b527f87e 100644 --- a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPrinterJob.java +++ b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPrinterJob.java @@ -598,7 +598,7 @@ public final class CPrinterJob extends RasterPrinterJob { // The following methods are CPrinterJob specific. @Override - @SuppressWarnings("deprecation") + @SuppressWarnings("removal") protected void finalize() { synchronized (fNSPrintInfoLock) { if (fNSPrintInfo != -1) { @@ -845,10 +845,10 @@ public final class CPrinterJob extends RasterPrinterJob { @Override protected MediaSize getMediaSize(Media media, PrintService service, PageFormat page) { - if (media == null || !(media instanceof MediaSizeName)) { + if (!(media instanceof MediaSizeName msn)) { return getDefaultMediaSize(page); } - MediaSize size = MediaSize.getMediaSizeForName((MediaSizeName) media); + MediaSize size = MediaSize.getMediaSizeForName(msn); return size != null ? size : getDefaultMediaSize(page); } diff --git a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CRobot.java b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CRobot.java index 49125443b2e0ab79962cdfafbdfb1cae9b81b470..5dba06cb612b54b58c82d0097a5a8823f09d5a10 100644 --- a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CRobot.java +++ b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CRobot.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 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 @@ -168,9 +168,9 @@ final class CRobot implements RobotPeer { */ @Override public int getRGBPixel(int x, int y) { - int[] c = new int[1]; - double scale = fDevice.getScaleFactor(); - getScreenPixels(new Rectangle(x, y, (int) scale, (int) scale), c); + int scale = fDevice.getScaleFactor(); + int[] c = new int[scale * scale]; + getScreenPixels(new Rectangle(x, y, scale, scale), c); return c[0]; } diff --git a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CTextPipe.java b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CTextPipe.java index f4dcc7ec675353aafc8464b44464b8ca7886d0e3..6aa36453ac0f9a6124dadf314689cdeab4c7cf12 100644 --- a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CTextPipe.java +++ b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CTextPipe.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 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 @@ -81,10 +81,57 @@ public class CTextPipe implements TextPipe { } } - public void drawGlyphVector(final SunGraphics2D sg2d, final GlyphVector gV, final float x, final float y) { - final Font prevFont = sg2d.getFont(); - sg2d.setFont(gV.getFont()); + private boolean hasSlotData(GlyphVector gv) { + final int length = gv.getNumGlyphs(); + for (int i = 0; i < length; i++) { + if ((gv.getGlyphCode(i) & CompositeGlyphMapper.SLOTMASK) != 0) { + return true; + } + } + return false; + } + + private Font getSlotFont(Font font, int slot) { + Font2D f2d = FontUtilities.getFont2D(font); + if (f2d instanceof CFont) { + CompositeFont cf = ((CFont)f2d).getCompositeFont2D(); + PhysicalFont pf = cf.getSlotFont(slot); + Font f = new Font(pf.getFontName(null), + font.getStyle(), font.getSize()); + return f; + } + return null; + } + + private GlyphVector getGlyphVectorWithRange(final Font font, final GlyphVector gV, int start, int count) { + int[] glyphs = new int[count]; + for (int i = 0; i < count; i++) { + glyphs[i] = gV.getGlyphCode(start+i) & CompositeGlyphMapper.GLYPHMASK; + } + // Positions should be null to recalculate by native methods, + // if GV was segmented. + StandardGlyphVector sgv = new StandardGlyphVector(font, + gV.getFontRenderContext(), + glyphs, + null, // positions + null, // indices + gV.getLayoutFlags()); + return sgv; + } + + private int getLengthOfSameSlot(final GlyphVector gV, final int targetSlot, final int start, final int length) { + int count = 1; + for (; start + count < length; count++) { + int slot = (gV.getGlyphCode(start + count) & + CompositeGlyphMapper.SLOTMASK) >> 24; + if (targetSlot != slot) { + break; + } + } + return count; + } + private void drawGlyphVectorImpl(final SunGraphics2D sg2d, final GlyphVector gV, final float x, final float y) { final long nativeStrikePtr = getNativeStrikePtr(sg2d); if (OSXSurfaceData.IsSimpleColor(sg2d.paint) && nativeStrikePtr != 0) { final OSXSurfaceData surfaceData = (OSXSurfaceData)sg2d.getSurfaceData(); @@ -92,6 +139,31 @@ public class CTextPipe implements TextPipe { } else { drawGlyphVectorAsShape(sg2d, gV, x, y); } + } + + public void drawGlyphVector(final SunGraphics2D sg2d, final GlyphVector gV, final float x, final float y) { + final Font prevFont = sg2d.getFont(); + sg2d.setFont(gV.getFont()); + + if (hasSlotData(gV)) { + final int length = gV.getNumGlyphs(); + float[] positions = gV.getGlyphPositions(0, length, null); + int start = 0; + while (start < length) { + int slot = (gV.getGlyphCode(start) & + CompositeGlyphMapper.SLOTMASK) >> 24; + sg2d.setFont(getSlotFont(gV.getFont(), slot)); + int count = getLengthOfSameSlot(gV, slot, start, length); + GlyphVector rangeGV = getGlyphVectorWithRange(sg2d.getFont(), + gV, start, count); + drawGlyphVectorImpl(sg2d, rangeGV, + x + positions[start * 2], + y + positions[start * 2 + 1]); + start += count; + } + } else { + drawGlyphVectorImpl(sg2d, gV, x, y); + } sg2d.setFont(prevFont); } diff --git a/src/java.desktop/macosx/classes/sun/lwawt/macosx/LWCToolkit.java b/src/java.desktop/macosx/classes/sun/lwawt/macosx/LWCToolkit.java index 1b037510299e476c9a13fc7b52e3b486d91837ba..2362b68c41cfc3f97aaef0d15e7e4e1ef2c0e193 100644 --- a/src/java.desktop/macosx/classes/sun/lwawt/macosx/LWCToolkit.java +++ b/src/java.desktop/macosx/classes/sun/lwawt/macosx/LWCToolkit.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 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 @@ -426,8 +426,7 @@ public final class LWCToolkit extends LWToolkit { // TODO Auto-generated method stub } - class OSXPlatformFont extends sun.awt.PlatformFont - { + static class OSXPlatformFont extends sun.awt.PlatformFont { OSXPlatformFont(String name, int style) { super(name, style); @@ -454,7 +453,7 @@ public final class LWCToolkit extends LWToolkit { desktopProperties.put("awt.multiClickInterval", getMultiClickTime()); // These DnD properties must be set, otherwise Swing ends up spewing NPEs - // all over the place. The values came straight off of MToolkit. + // all over the place. The values came straight off of XToolkit. desktopProperties.put("DnD.Autoscroll.initialDelay", Integer.valueOf(50)); desktopProperties.put("DnD.Autoscroll.interval", Integer.valueOf(50)); desktopProperties.put("DnD.Autoscroll.cursorHysteresis", Integer.valueOf(5)); diff --git a/make/data/fontconfig/macosx.fontconfig.properties b/src/java.desktop/macosx/data/fontconfig/fontconfig.properties similarity index 100% rename from make/data/fontconfig/macosx.fontconfig.properties rename to src/java.desktop/macosx/data/fontconfig/fontconfig.properties diff --git a/make/data/macosxicons/JavaApp.icns b/src/java.desktop/macosx/data/macosxicons/JavaApp.icns similarity index 100% rename from make/data/macosxicons/JavaApp.icns rename to src/java.desktop/macosx/data/macosxicons/JavaApp.icns diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTView.m b/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTView.m index 8e44052333c2c8786405d3f888abb91ef82d4094..15be2ae90f2243fe29c019c6d8f6a3b32c95c5c6 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTView.m +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTView.m @@ -546,12 +546,13 @@ static BOOL shouldUsePressAndHold() { -(BOOL) isCodePointInUnicodeBlockNeedingIMEvent: (unichar) codePoint { if ((codePoint == 0x0024) || (codePoint == 0x00A3) || (codePoint == 0x00A5) || + ((codePoint >= 0x900) && (codePoint <= 0x97F)) || ((codePoint >= 0x20A3) && (codePoint <= 0x20BF)) || ((codePoint >= 0x3000) && (codePoint <= 0x303F)) || ((codePoint >= 0xFF00) && (codePoint <= 0xFFEF))) { // Code point is in 'CJK Symbols and Punctuation' or // 'Halfwidth and Fullwidth Forms' Unicode block or - // currency symbols unicode + // currency symbols unicode or Devanagari script return YES; } return NO; @@ -957,11 +958,17 @@ static jclass jc_CInputMethod = NULL; #ifdef IM_DEBUG NSLog(@"insertText kbdlayout %@ ",(NSString *)kbdLayout); + + NSLog(@"utf8Length %lu utf16Length %lu", (unsigned long)utf8Length, (unsigned long)utf16Length); + NSLog(@"codePoint %x", codePoint); #endif // IM_DEBUG if ((utf16Length > 2) || ((utf8Length > 1) && [self isCodePointInUnicodeBlockNeedingIMEvent:codePoint]) || ((codePoint == 0x5c) && ([(NSString *)kbdLayout containsString:@"Kotoeri"]))) { +#ifdef IM_DEBUG + NSLog(@"string complex "); +#endif aStringIsComplex = YES; } diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTWindow.m b/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTWindow.m index 150e82c6965d1acd77b4cedd940a2829315de88b..34644c8073dff3fa9e1796f1732b9909fbbaaa83 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTWindow.m +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTWindow.m @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 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 @@ -213,20 +213,20 @@ AWT_NS_WINDOW_IMPLEMENTATION NSUInteger type = 0; if (IS(styleBits, DECORATED)) { type |= NSTitledWindowMask; - if (IS(styleBits, CLOSEABLE)) type |= NSClosableWindowMask; - if (IS(styleBits, RESIZABLE)) type |= NSResizableWindowMask; - if (IS(styleBits, FULL_WINDOW_CONTENT)) type |= NSFullSizeContentViewWindowMask; + if (IS(styleBits, CLOSEABLE)) type |= NSWindowStyleMaskClosable; + if (IS(styleBits, RESIZABLE)) type |= NSWindowStyleMaskResizable; + if (IS(styleBits, FULL_WINDOW_CONTENT)) type |= NSWindowStyleMaskFullSizeContentView; } else { - type |= NSBorderlessWindowMask; + type |= NSWindowStyleMaskBorderless; } - if (IS(styleBits, MINIMIZABLE)) type |= NSMiniaturizableWindowMask; - if (IS(styleBits, TEXTURED)) type |= NSTexturedBackgroundWindowMask; - if (IS(styleBits, UNIFIED)) type |= NSUnifiedTitleAndToolbarWindowMask; - if (IS(styleBits, UTILITY)) type |= NSUtilityWindowMask; - if (IS(styleBits, HUD)) type |= NSHUDWindowMask; + if (IS(styleBits, MINIMIZABLE)) type |= NSWindowStyleMaskMiniaturizable; + if (IS(styleBits, TEXTURED)) type |= NSWindowStyleMaskTexturedBackground; + if (IS(styleBits, UNIFIED)) type |= NSWindowStyleMaskUnifiedTitleAndToolbar; + if (IS(styleBits, UTILITY)) type |= NSWindowStyleMaskUtilityWindow; + if (IS(styleBits, HUD)) type |= NSWindowStyleMaskHUDWindow; if (IS(styleBits, SHEET)) type |= NSWindowStyleMaskDocModalWindow; - if (IS(styleBits, NONACTIVATING)) type |= NSNonactivatingPanelMask; + if (IS(styleBits, NONACTIVATING)) type |= NSWindowStyleMaskNonactivatingPanel; return type; } @@ -269,7 +269,7 @@ AWT_NS_WINDOW_IMPLEMENTATION if (IS(mask, FULLSCREENABLE) && [self.nsWindow respondsToSelector:@selector(toggleFullScreen:)]) { if (IS(bits, FULLSCREENABLE)) { - [self.nsWindow setCollectionBehavior:(1 << 7) /*NSWindowCollectionBehaviorFullScreenPrimary*/]; + [self.nsWindow setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary]; } else { [self.nsWindow setCollectionBehavior:NSWindowCollectionBehaviorDefault]; } @@ -343,7 +343,7 @@ AWT_ASSERT_APPKIT_THREAD; [self setPropertiesForStyleBits:styleBits mask:MASK(_METHOD_PROP_BITMASK)]; if (IS(self.styleBits, IS_POPUP)) { - [self.nsWindow setCollectionBehavior:(1 << 8) /*NSWindowCollectionBehaviorFullScreenAuxiliary*/]; + [self.nsWindow setCollectionBehavior:NSWindowCollectionBehaviorFullScreenAuxiliary]; } if (IS(bits, SHEET) && owner != nil) { @@ -1690,7 +1690,7 @@ JNI_COCOA_ENTER(env); if (CGDisplayCapture(aID) == kCGErrorSuccess) { // remove window decoration NSUInteger styleMask = [AWTWindow styleMaskForStyleBits:window.styleBits]; - [nsWindow setStyleMask:(styleMask & ~NSTitledWindowMask) | NSBorderlessWindowMask]; + [nsWindow setStyleMask:(styleMask & ~NSTitledWindowMask) | NSWindowStyleMaskBorderless]; int shieldLevel = CGShieldingWindowLevel(); window.preFullScreenLevel = [nsWindow level]; diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/CRobot.m b/src/java.desktop/macosx/native/libawt_lwawt/awt/CRobot.m index 9d90086677d819cdb05cdc3724db034dade5893d..55df129960f2cd324710cc76f3f80499bd0986cb 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/CRobot.m +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/CRobot.m @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -321,6 +321,11 @@ Java_sun_lwawt_macosx_CRobot_nativeGetScreenPixels jint picY = y; jint picWidth = width; jint picHeight = height; + jsize size = (*env)->GetArrayLength(env, pixels); + if (size < (long) picWidth * picHeight || picWidth < 0 || picHeight < 0) { + JNU_ThrowInternalError(env, "Invalid arguments to get screen pixels"); + return; + } CGRect screenRect = CGRectMake(picX / scale, picY / scale, picWidth / scale, picHeight / scale); diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/JavaAccessibilityAction.m b/src/java.desktop/macosx/native/libawt_lwawt/awt/JavaAccessibilityAction.m index 06e998ec4098e6f3a67ae98e505f225adbca9320..173ad891051ff6ba5a68cf7736b81337675fcc79 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/JavaAccessibilityAction.m +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/JavaAccessibilityAction.m @@ -161,8 +161,8 @@ void initializeActions() { [sActions setObject:NSAccessibilityPressAction forKey:@"click"]; [sActions setObject:NSAccessibilityIncrementAction forKey:@"increment"]; [sActions setObject:NSAccessibilityDecrementAction forKey:@"decrement"]; - [sActions setObject:NSAccessibilityShowMenuAction forKey:@"togglePopup"]; - [sActions setObject:NSAccessibilityPressAction forKey:@"toggleExpand"]; + [sActions setObject:NSAccessibilityShowMenuAction forKey:@"toggle popup"]; + [sActions setObject:NSAccessibilityPressAction forKey:@"toggleexpand"]; sActionSelectors = [[NSMutableDictionary alloc] initWithCapacity:actionsCount]; diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/JavaComponentAccessibility.m b/src/java.desktop/macosx/native/libawt_lwawt/awt/JavaComponentAccessibility.m index a1dc40ffd174f20a988a8aa09a47e0208fb38a94..da83387a58da4b74d2617715eb8586012f2b3820 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/JavaComponentAccessibility.m +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/JavaComponentAccessibility.m @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 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 @@ -1140,7 +1140,7 @@ static NSObject *sAttributeNamesLOCK = nil; - (BOOL)accessibilityIsSizeAttributeSettable { - // SIZE is settable in windows if [self styleMask] & NSResizableWindowMask - but windows are heavyweight so we're ok here + // SIZE is settable in windows if [self styleMask] & NSWindowStyleMaskResizable - but windows are heavyweight so we're ok here // SIZE is settable in columns if [[self tableValue] allowsColumnResizing - haven't dealt with columns yet return NO; } @@ -1516,54 +1516,6 @@ JNI_COCOA_ENTER(env); JNI_COCOA_EXIT(env); } -/* - * Class: sun_lwawt_macosx_CAccessible - * Method: menuOpened - * Signature: (I)V - */ -JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CAccessible_menuOpened -(JNIEnv *env, jclass jklass, jlong element) -{ -JNI_COCOA_ENTER(env); - [ThreadUtilities performOnMainThread:@selector(postMenuOpened) - on:(JavaComponentAccessibility *)jlong_to_ptr(element) - withObject:nil - waitUntilDone:NO]; -JNI_COCOA_EXIT(env); -} - -/* - * Class: sun_lwawt_macosx_CAccessible - * Method: menuClosed - * Signature: (I)V - */ -JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CAccessible_menuClosed -(JNIEnv *env, jclass jklass, jlong element) -{ -JNI_COCOA_ENTER(env); - [ThreadUtilities performOnMainThread:@selector(postMenuClosed) - on:(JavaComponentAccessibility *)jlong_to_ptr(element) - withObject:nil - waitUntilDone:NO]; -JNI_COCOA_EXIT(env); -} - -/* - * Class: sun_lwawt_macosx_CAccessible - * Method: menuItemSelected - * Signature: (I)V - */ -JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CAccessible_menuItemSelected -(JNIEnv *env, jclass jklass, jlong element) -{ -JNI_COCOA_ENTER(env); - [ThreadUtilities performOnMainThread:@selector(postMenuItemSelected) - on:(JavaComponentAccessibility *)jlong_to_ptr(element) - withObject:nil - waitUntilDone:NO]; -JNI_COCOA_EXIT(env); -} - /* * Class: sun_lwawt_macosx_CAccessible * Method: unregisterFromCocoaAXSystem diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/CellAccessibility.h b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/CellAccessibility.h index ef67c92a06d556f31253d4a4f47f6f48d7013a6c..103f2c3191239eca5dc95ee99d269d4ab6db671d 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/CellAccessibility.h +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/CellAccessibility.h @@ -5,7 +5,9 @@ * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/CellAccessibility.m b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/CellAccessibility.m index c44309a1e3cf49a6a36465df7f1976103f1c588f..ba91dbb8b6f582d3947261f9e2fb2ad089fae0d9 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/CellAccessibility.m +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/CellAccessibility.m @@ -5,7 +5,9 @@ * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ColumnAccessibility.h b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ColumnAccessibility.h index a78afaa924b0162adafe7fc78caae0bbf79853b0..80f633f4a911390f239fdfa0cb31654f1bc55c34 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ColumnAccessibility.h +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ColumnAccessibility.h @@ -5,7 +5,9 @@ * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ColumnAccessibility.m b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ColumnAccessibility.m index 238b82f609e6ef188315cce627eba5527caa2b5a..fb41511275b21897fe36c2b818833f9f910ed01e 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ColumnAccessibility.m +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ColumnAccessibility.m @@ -5,7 +5,9 @@ * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ComboBoxAccessibility.h b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ComboBoxAccessibility.h index 4a39938a826faf87c59d6b05b5f65127c72d647e..cfdd1faee61e37548e7a873a001ab9384b44be14 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ComboBoxAccessibility.h +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ComboBoxAccessibility.h @@ -5,7 +5,9 @@ * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ComboBoxAccessibility.m b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ComboBoxAccessibility.m index 0fd70eb81516502803a862e3676b1d6a666ab841..0029436579f788f899754b47bce968b0ad8404bb 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ComboBoxAccessibility.m +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ComboBoxAccessibility.m @@ -5,7 +5,9 @@ * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/CommonComponentAccessibility.h b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/CommonComponentAccessibility.h index 33ab5c5fd2e5cb9623ba41eb7023ab96a427efcd..be0169a064df06e2bb279d311774a598200ccc52 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/CommonComponentAccessibility.h +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/CommonComponentAccessibility.h @@ -83,6 +83,7 @@ - (NSView* _Nonnull)view; - (NSWindow* _Nonnull)window; - (id _Nonnull)parent; +- (CommonComponentAccessibility* _Nullable)typeSafeParent; - (NSString* _Nonnull)javaRole; - (BOOL)isMenu; diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/CommonComponentAccessibility.m b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/CommonComponentAccessibility.m index aa7068180398a95ccc75f26118f92dc2bbaa8651..d53d0350abf31c391e25a54e7088bef9fe4d5602 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/CommonComponentAccessibility.m +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/CommonComponentAccessibility.m @@ -95,7 +95,11 @@ static jobject sAccessibilityClass = NULL; return NO; } - return isChildSelected(env, ((CommonComponentAccessibility *)[self parent])->fAccessible, fIndex, fComponent); + CommonComponentAccessibility* parent = [self typeSafeParent]; + if (parent != nil) { + return isChildSelected(env, parent->fAccessible, fIndex, fComponent); + } + return NO; } - (BOOL)isSelectable:(JNIEnv *)env @@ -122,7 +126,7 @@ static jobject sAccessibilityClass = NULL; /* * Here we should keep all the mapping between the accessibility roles and implementing classes */ - rolesMap = [[NSMutableDictionary alloc] initWithCapacity:46]; + rolesMap = [[NSMutableDictionary alloc] initWithCapacity:51]; [rolesMap setObject:@"ButtonAccessibility" forKey:@"pushbutton"]; [rolesMap setObject:@"ImageAccessibility" forKey:@"icon"]; @@ -152,6 +156,11 @@ static jobject sAccessibilityClass = NULL; [rolesMap setObject:@"ListAccessibility" forKey:@"list"]; [rolesMap setObject:@"OutlineAccessibility" forKey:@"tree"]; [rolesMap setObject:@"TableAccessibility" forKey:@"table"]; + [rolesMap setObject:@"MenuBarAccessibility" forKey:@"menubar"]; + [rolesMap setObject:@"MenuAccessibility" forKey:@"menu"]; + [rolesMap setObject:@"MenuItemAccessibility" forKey:@"menuitem"]; + [rolesMap setObject:@"MenuAccessibility" forKey:@"popupmenu"]; + [rolesMap setObject:@"ProgressIndicatorAccessibility" forKey:@"progressbar"]; /* * All the components below should be ignored by the accessibility subsystem, @@ -703,6 +712,15 @@ static jobject sAccessibilityClass = NULL; return fParent; } +- (CommonComponentAccessibility *)typeSafeParent +{ + id parent = [self parent]; + if ([parent isKindOfClass:[CommonComponentAccessibility class]]) { + return (CommonComponentAccessibility*)parent; + } + return nil; +} + - (NSString *)javaRole { if(fJavaRole == nil) { @@ -787,7 +805,7 @@ static jobject sAccessibilityClass = NULL; (*env)->DeleteLocalRef(env, axComponent); point.y += size.height; - point.y = [[[[self view] window] screen] frame].size.height - point.y; + point.y = [[[NSScreen screens] objectAtIndex:0] frame].size.height - point.y; return NSMakeRect(point.x, point.y, size.width, size.height); } @@ -819,11 +837,13 @@ static jobject sAccessibilityClass = NULL; if (fNSRole == nil) { NSString *javaRole = [self javaRole]; fNSRole = [sRoles objectForKey:javaRole]; + CommonComponentAccessibility* parent = [self typeSafeParent]; // The sRoles NSMutableDictionary maps popupmenu to Mac's popup button. // JComboBox behavior currently relies on this. However this is not the // proper mapping for a JPopupMenu so fix that. if ( [javaRole isEqualToString:@"popupmenu"] && - ![[[self parent] javaRole] isEqualToString:@"combobox"] ) { + parent != nil && + ![[parent javaRole] isEqualToString:@"combobox"] ) { fNSRole = NSAccessibilityMenuRole; } if (fNSRole == nil) { @@ -985,7 +1005,7 @@ static jobject sAccessibilityClass = NULL; point.y += size.height; // Now make it into Cocoa screen coords. - point.y = [[[[self view] window] screen] frame].size.height - point.y; + point.y = [[[NSScreen screens] objectAtIndex:0] frame].size.height - point.y; return point; } @@ -1020,8 +1040,9 @@ static jobject sAccessibilityClass = NULL; // This may change when later fixing issues which currently // exist for combo boxes, but for now the following is only // for JPopupMenus, not for combobox menus. - id parent = [self parent]; + id parent = [self typeSafeParent]; if ( [[self javaRole] isEqualToString:@"popupmenu"] && + parent != nil && ![[parent javaRole] isEqualToString:@"combobox"] ) { NSArray *children = [CommonComponentAccessibility childrenOfParent:self @@ -1093,7 +1114,7 @@ static jobject sAccessibilityClass = NULL; "(Ljava/awt/Container;FF)Ljavax/accessibility/Accessible;", nil); // Make it into java screen coords - point.y = [[[[self view] window] screen] frame].size.height - point.y; + point.y = [[[NSScreen screens] objectAtIndex:0] frame].size.height - point.y; jobject jparent = fComponent; @@ -1253,3 +1274,51 @@ JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CAccessible_selectedCellsChanged waitUntilDone:NO]; JNI_COCOA_EXIT(env); } + +/* + * Class: sun_lwawt_macosx_CAccessible + * Method: menuOpened + * Signature: (I)V + */ +JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CAccessible_menuOpened + (JNIEnv *env, jclass jklass, jlong element) +{ + JNI_COCOA_ENTER(env); + [ThreadUtilities performOnMainThread:@selector(postMenuOpened) + on:(CommonComponentAccessibility *)jlong_to_ptr(element) + withObject:nil + waitUntilDone:NO]; + JNI_COCOA_EXIT(env); +} + +/* + * Class: sun_lwawt_macosx_CAccessible + * Method: menuClosed + * Signature: (I)V + */ +JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CAccessible_menuClosed + (JNIEnv *env, jclass jklass, jlong element) +{ + JNI_COCOA_ENTER(env); + [ThreadUtilities performOnMainThread:@selector(postMenuClosed) + on:(CommonComponentAccessibility *)jlong_to_ptr(element) + withObject:nil + waitUntilDone:NO]; + JNI_COCOA_EXIT(env); +} + +/* + * Class: sun_lwawt_macosx_CAccessible + * Method: menuItemSelected + * Signature: (I)V + */ +JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CAccessible_menuItemSelected + (JNIEnv *env, jclass jklass, jlong element) +{ + JNI_COCOA_ENTER(env); + [ThreadUtilities performOnMainThread:@selector(postMenuItemSelected) + on:(CommonComponentAccessibility *)jlong_to_ptr(element) + withObject:nil + waitUntilDone:NO]; + JNI_COCOA_EXIT(env); +} diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ComponentWrapperAccessibility.h b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ComponentWrapperAccessibility.h index fd1e774c274cbdb5a766b2169d8a0457c1f5c452..269ea2d5ff8e101eb502e5f9893d40e463f79096 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ComponentWrapperAccessibility.h +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ComponentWrapperAccessibility.h @@ -5,7 +5,9 @@ * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ComponentWrapperAccessibility.m b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ComponentWrapperAccessibility.m index 2101d7042fe62fa757022b09fcc8f2d6ebee1ee7..c2ce32608717b83adcdd929ea0b7f222470837eb 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ComponentWrapperAccessibility.m +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ComponentWrapperAccessibility.m @@ -5,7 +5,9 @@ * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ListAccessibility.h b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ListAccessibility.h index ddfcd2217f8cb7f2ca7fc4b46771d93ec3d49cd1..88f55f99c348781c5762a06001d00d1e4fa3ba0c 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ListAccessibility.h +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ListAccessibility.h @@ -5,7 +5,9 @@ * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ListAccessibility.m b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ListAccessibility.m index 4dc958886bb2142af48b89bc4f7996704e29ff1b..fc75efc6029c81f2c572cd2daee0636e671d80d3 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ListAccessibility.m +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ListAccessibility.m @@ -5,7 +5,9 @@ * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ListRowAccessibility.h b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ListRowAccessibility.h index 130d12721e6de0e54a793204aaa5991885182cee..2b3b4412beb9c6ae5f8741a56c05e896c180d118 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ListRowAccessibility.h +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ListRowAccessibility.h @@ -5,7 +5,9 @@ * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ListRowAccessibility.m b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ListRowAccessibility.m index 8b30080c85b78eb772eda242b61dbc6c9e4f9172..dc9e617d43c50d2a5c2f83163de730acabb601f5 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ListRowAccessibility.m +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ListRowAccessibility.m @@ -5,7 +5,9 @@ * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/MenuAccessibility.h b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/MenuAccessibility.h new file mode 100644 index 0000000000000000000000000000000000000000..65e127aceed343f615df4cacb23ee3125bde3cfe --- /dev/null +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/MenuAccessibility.h @@ -0,0 +1,35 @@ +/* + * 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. 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. + */ + +#import "CommonComponentAccessibility.h" +#import "GroupAccessibility.h" + +#import + +@interface MenuAccessibility : GroupAccessibility { + +}; +- (NSAccessibilityRole _Nonnull)accessibilityRole; +@end diff --git a/bin/print-config.js b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/MenuAccessibility.m similarity index 66% rename from bin/print-config.js rename to src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/MenuAccessibility.m index 1abb2069b1f37dcf5946b12c0744a0f06cf0c6ee..6dc4d050db2190be4f2b0236e38ad14cecd29d03 100644 --- a/bin/print-config.js +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/MenuAccessibility.m @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -23,23 +23,23 @@ * questions. */ +#import "MenuAccessibility.h" + /* - * This little utility can be used to expand the jib-profiles configuration - * files into plain json. - * - * Usage: - * - * jjs -scripting print-config.js -- [] - * + * Implementing a protocol that represents menus both as submenu and as a + * MenuBar components */ +@implementation MenuAccessibility +- (NSAccessibilityRole _Nonnull)accessibilityRole +{ + return [[[self parent] javaRole] isEqualToString:@"combobox"] + ? NSAccessibilityPopUpButtonRole + : NSAccessibilityMenuRole; +} -var file = $ARG[0]; -if (file == null) { - file = new java.io.File(__DIR__, "../conf/jib-profiles.js").getCanonicalPath(); +- (BOOL)isAccessibilityElement +{ + return YES; } -load(file); -var input = {}; -input.get = function(dependencyName, attribute) { - return "\${" + dependencyName + "." + attribute + "}"; -}; -print(JSON.stringify(getJibProfiles(input), null, 2)); + +@end diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/MenuBarAccessibility.h b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/MenuBarAccessibility.h new file mode 100644 index 0000000000000000000000000000000000000000..3a69dd40c457ab414f2d2e9cd49c4064e1177dee --- /dev/null +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/MenuBarAccessibility.h @@ -0,0 +1,34 @@ +/* + * 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. 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. + */ + +#import "CommonComponentAccessibility.h" + +#import + +@interface MenuBarAccessibility : CommonComponentAccessibility { + +}; +- (NSAccessibilityRole _Nonnull)accessibilityRole; +@end diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/MenuBarAccessibility.m b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/MenuBarAccessibility.m new file mode 100644 index 0000000000000000000000000000000000000000..d21bf5318daea87f2b9fb48d8137b4e2cedad998 --- /dev/null +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/MenuBarAccessibility.m @@ -0,0 +1,45 @@ +/* + * 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. 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. + */ + +#import "MenuBarAccessibility.h" +#import "JNIUtilities.h" +#import "ThreadUtilities.h" +#import "sun_lwawt_macosx_CAccessibility.h" + +/* + * This is the protocol for the Menu Bar component + */ +@implementation MenuBarAccessibility +- (NSAccessibilityRole _Nonnull)accessibilityRole +{ + return NSAccessibilityMenuBarRole; +} + +- (BOOL)isAccessibilityElement +{ + return YES; +} + +@end diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/MenuItemAccessibility.h b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/MenuItemAccessibility.h new file mode 100644 index 0000000000000000000000000000000000000000..19a1cc71a694a5806a3e46664c1d5a8fc302a9f7 --- /dev/null +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/MenuItemAccessibility.h @@ -0,0 +1,36 @@ +/* + * 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. 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. + */ + +#import "CommonComponentAccessibility.h" +#import "ButtonAccessibility.h" + +#import + +@interface MenuItemAccessibility : ButtonAccessibility { + +}; +- (NSAccessibilityRole _Nonnull)accessibilityRole; +- (void)handleAction:(NSMenuItem * _Nonnull)sender; +@end diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/MenuItemAccessibility.m b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/MenuItemAccessibility.m new file mode 100644 index 0000000000000000000000000000000000000000..945e50975ebb1df0cd78b5a426573f6fff21da13 --- /dev/null +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/MenuItemAccessibility.m @@ -0,0 +1,62 @@ +/* + * 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. 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. + */ + +#import "MenuItemAccessibility.h" + +/* + * This is the protocol for the MenuItem component. + */ +@implementation MenuItemAccessibility +- (NSAccessibilityRole _Nonnull)accessibilityRole +{ + return NSAccessibilityMenuItemRole; +} + +- (BOOL)isAccessibilityElement +{ + return YES; +} + +- (BOOL)accessibilityPerformPick +{ + return [self performAccessibleAction:0]; +} + +- (BOOL)accessibilityPerformPress +{ + return [self performAccessibleAction:0]; +} + +- (NSString * _Nullable)accessibilityLabel +{ + return [super accessibilityLabel]; +} + +- (id _Nullable)accessibilityValue +{ + return [super accessibilityValue]; +} + +@end diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/NavigableTextAccessibility.h b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/NavigableTextAccessibility.h index 33a05318b5a4abe6c0e991081aa54833b82b09f2..ebf314c7394cf6589521f908414f6eb81307d94b 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/NavigableTextAccessibility.h +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/NavigableTextAccessibility.h @@ -5,7 +5,9 @@ * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/NavigableTextAccessibility.m b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/NavigableTextAccessibility.m index 84d8785e20541b9ca4942b0e1df4ced0d87da99d..138d502f10fb67fede121bf0d4d6839fb37380cf 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/NavigableTextAccessibility.m +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/NavigableTextAccessibility.m @@ -5,7 +5,9 @@ * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/OutlineAccessibility.h b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/OutlineAccessibility.h index 48074b209e0bef591a95cf4bbe589c9d9c1ff00c..2992d82cbe4f521ebf444979f287897b5a6579f5 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/OutlineAccessibility.h +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/OutlineAccessibility.h @@ -5,7 +5,9 @@ * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/OutlineAccessibility.m b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/OutlineAccessibility.m index acc5727cd6b31abc26d75afc1e6d4878b027153d..cdf6dbbd4ab7783d393246ded05d6a5911038ebd 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/OutlineAccessibility.m +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/OutlineAccessibility.m @@ -5,7 +5,9 @@ * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/OutlineRowAccessibility.h b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/OutlineRowAccessibility.h index 8cc8e1760c60777dd3db21a5a2ed8d9d56992017..4185c0a27b91779de0fbb6cce0b63c8e7bef464c 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/OutlineRowAccessibility.h +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/OutlineRowAccessibility.h @@ -5,7 +5,9 @@ * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/OutlineRowAccessibility.m b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/OutlineRowAccessibility.m index e4d7e66027d9609dce2ec94c2e5854167d103542..4653821283dac1623b4de5357212fd8bdd727d14 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/OutlineRowAccessibility.m +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/OutlineRowAccessibility.m @@ -5,7 +5,9 @@ * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ProgressIndicatorAccessibility.h b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ProgressIndicatorAccessibility.h new file mode 100644 index 0000000000000000000000000000000000000000..e5b58ea3f8b6b0c59ae896911f0870ad406aef5c --- /dev/null +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ProgressIndicatorAccessibility.h @@ -0,0 +1,36 @@ +/* + * 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. 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. + */ + +#import "JavaComponentAccessibility.h" +#import "GroupAccessibility.h" + +#import + +@interface ProgressIndicatorAccessibility : GroupAccessibility { + +}; +- (NSAccessibilityRole _Nonnull)accessibilityRole; +- (NSString * _Nullable)accessibilityValue; +@end diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ProgressIndicatorAccessibility.m b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ProgressIndicatorAccessibility.m new file mode 100644 index 0000000000000000000000000000000000000000..13ba383f166df8f78ba3a2b2bd08b25b1715eb98 --- /dev/null +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ProgressIndicatorAccessibility.m @@ -0,0 +1,44 @@ +/* + * 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. 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. + */ + +#import "ProgressIndicatorAccessibility.h" + +/* + * Implementation of the accessibility peer for the NSProgressIndicator role. + * Main usage is JProgressBar + */ +@implementation ProgressIndicatorAccessibility + +- (NSAccessibilityRole _Nonnull)accessibilityRole +{ + return NSAccessibilityProgressIndicatorRole; +} + +- (NSString * _Nullable)accessibilityValue +{ + return [super accessibilityValue]; +} + +@end diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/TabButtonAccessibility.h b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/TabButtonAccessibility.h index 0b497d4afc26497e0945896875a7a30a601ea2e1..892225cf2acb0781cb29a148b33ade07700a0e23 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/TabButtonAccessibility.h +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/TabButtonAccessibility.h @@ -5,7 +5,9 @@ * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/TabButtonAccessibility.m b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/TabButtonAccessibility.m index 4caf97c21cb67ad5c69f6d8b531206bbfc92761b..2b22db80aa8eb21cf35c9e28ab9b8e740c20f94a 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/TabButtonAccessibility.m +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/TabButtonAccessibility.m @@ -5,7 +5,9 @@ * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or @@ -59,11 +61,14 @@ - (jobject)tabGroup { if (fTabGroupAxContext == NULL) { - JNIEnv* env = [ThreadUtilities getJNIEnv]; - jobject tabGroupAxContext = [(CommonComponentAccessibility *)[self parent] axContextWithEnv:env]; - fTabGroupAxContext = (*env)->NewWeakGlobalRef(env, tabGroupAxContext); - CHECK_EXCEPTION(); - (*env)->DeleteLocalRef(env, tabGroupAxContext); + CommonComponentAccessibility* parent = [self typeSafeParent]; + if (parent != nil) { + JNIEnv *env = [ThreadUtilities getJNIEnv]; + jobject tabGroupAxContext = [parent axContextWithEnv:env]; + fTabGroupAxContext = (*env)->NewWeakGlobalRef(env, tabGroupAxContext); + CHECK_EXCEPTION(); + (*env)->DeleteLocalRef(env, tabGroupAxContext); + } } return fTabGroupAxContext; } diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/TabGroupAccessibility.h b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/TabGroupAccessibility.h index c99b18c904e95d0549314aa1b61306075cc23dbb..c660ff0e780a332270632a9b2cf8d9eb66804755 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/TabGroupAccessibility.h +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/TabGroupAccessibility.h @@ -5,7 +5,9 @@ * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/TabGroupAccessibility.m b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/TabGroupAccessibility.m index 76fafc0faafdabb0035d693c4982465b4aef4bf1..06375fc293426e47426c9fc5dd09737ac499c030 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/TabGroupAccessibility.m +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/TabGroupAccessibility.m @@ -5,7 +5,9 @@ * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/TableAccessibility.h b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/TableAccessibility.h index 5fe04aa257f61376c355d53f57ccb09052a3af29..6fa9fd0b636acab0edafb39b939f74a037b5d0fb 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/TableAccessibility.h +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/TableAccessibility.h @@ -5,7 +5,9 @@ * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/TableAccessibility.m b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/TableAccessibility.m index d6382822e1e52a95a6a43691724e35a8175449a3..d9d18b24fcedf2ed42dec73e39c51db1d893e54d 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/TableAccessibility.m +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/TableAccessibility.m @@ -5,7 +5,9 @@ * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/TableRowAccessibility.h b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/TableRowAccessibility.h index afa9eb44e3f22891049981e4e1d3f461e69d6ab0..d9c19ccbc424025e8033aceb2cf10ffdb216cb84 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/TableRowAccessibility.h +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/TableRowAccessibility.h @@ -5,7 +5,9 @@ * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/TableRowAccessibility.m b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/TableRowAccessibility.m index 31636dd99bb4acdfd08aaeda34aee3db6e1d6276..890ac973311f2aebe5479900d86b6153356063e1 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/TableRowAccessibility.m +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/TableRowAccessibility.m @@ -5,7 +5,9 @@ * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or diff --git a/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/EncoderManager.m b/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/EncoderManager.m index 0fb18c3f4c314e29eeae50141aa885160a121398..95374d2c93e53f1d4af0bd960b70e9b7be584bee 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/EncoderManager.m +++ b/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/EncoderManager.m @@ -41,11 +41,9 @@ const SurfaceRasterFlags defaultRasterFlags = { JNI_FALSE, JNI_TRUE }; - (void)dealloc; - (void)reset:(id)destination - isDstOpaque:(jboolean)isDstOpaque - isDstPremultiplied:(jboolean)isDstPremultiplied - isAA:(jboolean)isAA - isText:(jboolean)isText - isLCD:(jboolean)isLCD; + isAA:(jboolean)isAA + isText:(jboolean)isText + isLCD:(jboolean)isLCD; - (void)updateEncoder:(id)encoder context:(MTLContext *)mtlc @@ -64,7 +62,6 @@ const SurfaceRasterFlags defaultRasterFlags = { JNI_FALSE, JNI_TRUE }; // Persistent encoder properties id _destination; - SurfaceRasterFlags _dstFlags; jboolean _isAA; jboolean _isText; @@ -123,14 +120,10 @@ const SurfaceRasterFlags defaultRasterFlags = { JNI_FALSE, JNI_TRUE }; } - (void)reset:(id)destination - isDstOpaque:(jboolean)isDstOpaque - isDstPremultiplied:(jboolean)isDstPremultiplied - isAA:(jboolean)isAA - isText:(jboolean)isText - isLCD:(jboolean)isLCD { + isAA:(jboolean)isAA + isText:(jboolean)isText + isLCD:(jboolean)isLCD { _destination = destination; - _dstFlags.isOpaque = isDstOpaque; - _dstFlags.isPremultiplied = isDstPremultiplied; _isAA = isAA; _isText = isText; _isLCD = isLCD; @@ -288,20 +281,20 @@ const SurfaceRasterFlags defaultRasterFlags = { JNI_FALSE, JNI_TRUE }; - (id _Nonnull)getAARenderEncoder:(const BMTLSDOps * _Nonnull)dstOps { id dstTxt = dstOps->pTexture; - RenderOptions roptions = {JNI_FALSE, JNI_TRUE, INTERPOLATION_NEAREST_NEIGHBOR, defaultRasterFlags, {dstOps->isOpaque, JNI_TRUE}, JNI_FALSE, JNI_FALSE, JNI_FALSE}; + RenderOptions roptions = {JNI_FALSE, JNI_TRUE, INTERPOLATION_NEAREST_NEIGHBOR, defaultRasterFlags, JNI_FALSE, JNI_FALSE, JNI_FALSE}; return [self getEncoder:dstTxt renderOptions:&roptions]; } - (id _Nonnull)getAAShaderRenderEncoder:(const BMTLSDOps * _Nonnull)dstOps { - RenderOptions roptions = {JNI_FALSE, JNI_FALSE, INTERPOLATION_NEAREST_NEIGHBOR, defaultRasterFlags, {dstOps->isOpaque, JNI_TRUE}, JNI_FALSE, JNI_FALSE, JNI_TRUE}; + RenderOptions roptions = {JNI_FALSE, JNI_FALSE, INTERPOLATION_NEAREST_NEIGHBOR, defaultRasterFlags, JNI_FALSE, JNI_FALSE, JNI_TRUE}; return [self getEncoder:dstOps->pTexture renderOptions:&roptions]; } - (id _Nonnull)getRenderEncoder:(id _Nonnull)dest isDstOpaque:(bool)isOpaque { - RenderOptions roptions = {JNI_FALSE, JNI_FALSE, INTERPOLATION_NEAREST_NEIGHBOR, defaultRasterFlags, {isOpaque, JNI_TRUE}, JNI_FALSE, JNI_FALSE, JNI_FALSE}; + RenderOptions roptions = {JNI_FALSE, JNI_FALSE, INTERPOLATION_NEAREST_NEIGHBOR, defaultRasterFlags, JNI_FALSE, JNI_FALSE, JNI_FALSE}; return [self getEncoder:dest renderOptions:&roptions]; } @@ -329,7 +322,7 @@ const SurfaceRasterFlags defaultRasterFlags = { JNI_FALSE, JNI_TRUE }; isSrcOpaque:(bool)isSrcOpaque isDstOpaque:(bool)isDstOpaque { - RenderOptions roptions = {JNI_TRUE, JNI_FALSE, INTERPOLATION_NEAREST_NEIGHBOR, {isSrcOpaque, JNI_TRUE }, {isDstOpaque, JNI_TRUE}, JNI_FALSE, JNI_TRUE, JNI_FALSE}; + RenderOptions roptions = {JNI_TRUE, JNI_FALSE, INTERPOLATION_NEAREST_NEIGHBOR, {isSrcOpaque, JNI_TRUE }, JNI_FALSE, JNI_TRUE, JNI_FALSE}; return [self getEncoder:dest renderOptions:&roptions]; } @@ -339,7 +332,7 @@ const SurfaceRasterFlags defaultRasterFlags = { JNI_FALSE, JNI_TRUE }; interpolation:(int)interpolation isAA:(jboolean)isAA { - RenderOptions roptions = {JNI_TRUE, isAA, interpolation, { isSrcOpaque, JNI_TRUE }, {isDstOpaque, JNI_TRUE}, JNI_FALSE, JNI_FALSE, JNI_FALSE}; + RenderOptions roptions = {JNI_TRUE, isAA, interpolation, { isSrcOpaque, JNI_TRUE }, JNI_FALSE, JNI_FALSE, JNI_FALSE}; return [self getEncoder:dest renderOptions:&roptions]; } @@ -354,7 +347,8 @@ const SurfaceRasterFlags defaultRasterFlags = { JNI_FALSE, JNI_TRUE }; - (id _Nonnull) getTextEncoder:(const BMTLSDOps * _Nonnull)dstOps isSrcOpaque:(bool)isSrcOpaque { - RenderOptions roptions = {JNI_TRUE, JNI_FALSE, INTERPOLATION_NEAREST_NEIGHBOR, { isSrcOpaque, JNI_TRUE }, {dstOps->isOpaque, JNI_TRUE}, JNI_TRUE, JNI_FALSE, JNI_FALSE}; + RenderOptions roptions = {JNI_TRUE, JNI_FALSE, INTERPOLATION_NEAREST_NEIGHBOR, { isSrcOpaque, JNI_TRUE }, + JNI_TRUE, JNI_FALSE, JNI_FALSE}; return [self getEncoder:dstOps->pTexture renderOptions:&roptions]; } @@ -437,11 +431,9 @@ const SurfaceRasterFlags defaultRasterFlags = { JNI_FALSE, JNI_TRUE }; _encoder = [[cbw getCommandBuffer] renderCommandEncoderWithDescriptor:rpd]; [_encoderStates reset:dest - isDstOpaque:renderOptions->dstFlags.isOpaque - isDstPremultiplied:YES - isAA:renderOptions->isAA - isText:renderOptions->isText - isLCD:renderOptions->isLCD]; + isAA:renderOptions->isAA + isText:renderOptions->isText + isLCD:renderOptions->isLCD]; } // diff --git a/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLBlitLoops.m b/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLBlitLoops.m index bf55d8c8976d0454cd1e1f43bf895b917ac72b45..47571a5e7ae4a98862c92d59fa8aa5de880efaa0 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLBlitLoops.m +++ b/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLBlitLoops.m @@ -595,8 +595,9 @@ MTLBlitLoops_Blit(JNIEnv *env, } #ifdef TRACE_BLIT - J2dTraceImpl(J2D_TRACE_VERBOSE, JNI_FALSE, - "MTLBlitLoops_Blit [tx=%d, xf=%d, AC=%s]: bdst=%s, src=%p (%dx%d) O=%d premul=%d | (%d, %d, %d, %d)->(%1.2f, %1.2f, %1.2f, %1.2f)", + J2dTraceImpl(J2D_TRACE_VERBOSE, JNI_TRUE, + "MTLBlitLoops_Blit srctype=%d [tx=%d, xf=%d, AC=%s]: bdst=%s, src=%p (%dx%d) O=%d premul=%d | (%d, " + "%d, %d, %d)->(%1.2f, %1.2f, %1.2f, %1.2f)", srctype, texture, xform, [mtlc getCompositeDescription].cString, getSurfaceDescription(dstOps).cString, srcOps, sx2 - sx1, sy2 - sy1, diff --git a/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLClip.m b/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLClip.m index 35d8ba624c9bd00f85a1e3bea6ea0a291b50c3de..effe7aebae6f89a71e2c5c98dea19ebac98bb18d 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLClip.m +++ b/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLClip.m @@ -58,7 +58,6 @@ static void initTemplatePipelineDescriptors() { BMTLSDOps* _dstOps; BOOL _stencilMaskGenerationInProgress; BOOL _stencilMaskGenerationStarted; - BOOL _clipReady; MTLOrigin _clipShapeOrigin; MTLSize _clipShapeSize; } @@ -73,7 +72,6 @@ static void initTemplatePipelineDescriptors() { _dstOps = NULL; _stencilMaskGenerationInProgress = NO; _stencilMaskGenerationStarted = NO; - _clipReady = NO; } return self; } @@ -189,7 +187,6 @@ static void initTemplatePipelineDescriptors() { _stencilMaskGenerationStarted = NO; _dstOps = dstOps; _clipType = SHAPE_CLIP; - _clipReady = NO; } - (void)setMaskGenerationPipelineState:(id)encoder diff --git a/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLPaints.m b/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLPaints.m index a3b1254bf13745882cac470186788b5ada3151a3..5686449a295602e900b46342ccdc819484475993 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLPaints.m +++ b/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLPaints.m @@ -56,7 +56,7 @@ static MTLRenderPipelineDescriptor * templateLCDPipelineDesc = nil; static MTLRenderPipelineDescriptor * templateAAPipelineDesc = nil; static void setTxtUniforms(MTLContext *mtlc, int color, id encoder, int interpolation, bool repeat, - jfloat extraAlpha, const SurfaceRasterFlags *srcFlags, const SurfaceRasterFlags *dstFlags, int mode); + jfloat extraAlpha, const SurfaceRasterFlags *srcFlags, int mode); static void initTemplatePipelineDescriptors() { if (templateRenderPipelineDesc != nil && templateTexturePipelineDesc != nil && @@ -228,8 +228,8 @@ jint _color; rpDesc = [[templateLCDPipelineDesc copy] autorelease]; } setTxtUniforms(mtlc, _color, encoder, - renderOptions->interpolation, NO, [mtlc.composite getExtraAlpha], &renderOptions->srcFlags, - &renderOptions->dstFlags, 1); + renderOptions->interpolation, NO, [mtlc.composite getExtraAlpha], + &renderOptions->srcFlags, 1); } else if (renderOptions->isAAShader) { vertShader = @"vert_col_aa"; fragShader = @"frag_col_aa"; @@ -270,7 +270,7 @@ jint _color; setTxtUniforms(mtlc, col, encoder, renderOptions->interpolation, NO, [mtlc.composite getExtraAlpha], - &renderOptions->srcFlags, &renderOptions->dstFlags, 1); + &renderOptions->srcFlags, 1); [encoder setFragmentBytes:&xorColor length:sizeof(xorColor) atIndex:0]; [encoder setFragmentTexture:dstOps->pTexture atIndex:1]; @@ -809,9 +809,8 @@ jint _color; [encoder setFragmentTexture:_paintTexture atIndex:0]; } const SurfaceRasterFlags srcFlags = {_isOpaque, renderOptions->srcFlags.isPremultiplied}; - setTxtUniforms(mtlc, 0, encoder, - renderOptions->interpolation, YES, [mtlc.composite getExtraAlpha], - &srcFlags, &renderOptions->dstFlags, 0); + setTxtUniforms(mtlc, 0, encoder, renderOptions->interpolation, YES, [mtlc.composite getExtraAlpha], + &srcFlags, 0); id pipelineState = [pipelineStateStorage getPipelineState:rpDesc vertexShaderId:vertShader @@ -893,8 +892,8 @@ jint _color; static void setTxtUniforms(MTLContext *mtlc, int color, id encoder, int interpolation, bool repeat, - jfloat extraAlpha, const SurfaceRasterFlags *srcFlags, const SurfaceRasterFlags *dstFlags, int mode) { - struct TxtFrameUniforms uf = {RGBA_TO_V4(color), mode, srcFlags->isOpaque, dstFlags->isOpaque, extraAlpha}; + jfloat extraAlpha, const SurfaceRasterFlags *srcFlags, int mode) { + struct TxtFrameUniforms uf = {RGBA_TO_V4(color), mode, srcFlags->isOpaque, extraAlpha}; [encoder setFragmentBytes:&uf length:sizeof(uf) atIndex:FrameUniformBuffer]; [mtlc.samplerManager setSamplerWithEncoder:encoder interpolation:interpolation repeat:repeat]; } @@ -956,8 +955,7 @@ setTxtUniforms(MTLContext *mtlc, int color, id encoder } else { setTxtUniforms(mtlc, 0, encoder, renderOptions->interpolation, NO, [mtlc.composite getExtraAlpha], - &renderOptions->srcFlags, - &renderOptions->dstFlags, 0); + &renderOptions->srcFlags, 0); } id pipelineState = [pipelineStateStorage getPipelineState:rpDesc @@ -998,7 +996,7 @@ setTxtUniforms(MTLContext *mtlc, int color, id encoder const int col = 0 ^ xorColor; setTxtUniforms(mtlc, col, encoder, renderOptions->interpolation, NO, [mtlc.composite getExtraAlpha], - &renderOptions->srcFlags, &renderOptions->dstFlags, 0); + &renderOptions->srcFlags, 0); [encoder setFragmentBytes:&xorColor length:sizeof(xorColor) atIndex: 0]; BMTLSDOps *dstOps = MTLRenderQueue_GetCurrentDestination(); @@ -1006,8 +1004,7 @@ setTxtUniforms(MTLContext *mtlc, int color, id encoder setTxtUniforms(mtlc, 0, encoder, renderOptions->interpolation, NO, [mtlc.composite getExtraAlpha], - &renderOptions->srcFlags, - &renderOptions->dstFlags, 0); + &renderOptions->srcFlags, 0); id pipelineState = [pipelineStateStorage getPipelineState:rpDesc vertexShaderId:vertShader diff --git a/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLPipelineStatesStorage.m b/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLPipelineStatesStorage.m index 0928f12d426958d74803eff3e1353a40ecad5b89..9a7862e8c263044cd1a1c9c8977add83640a3587 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLPipelineStatesStorage.m +++ b/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLPipelineStatesStorage.m @@ -84,7 +84,7 @@ static void setBlendingFactors( vertexShaderId:(NSString *)vertexShaderId fragmentShaderId:(NSString *)fragmentShaderId { - RenderOptions defaultOptions = {JNI_FALSE, JNI_FALSE, 0/*unused*/, {JNI_FALSE, JNI_TRUE}, {JNI_FALSE, JNI_TRUE}, JNI_FALSE, JNI_FALSE, JNI_FALSE}; + RenderOptions defaultOptions = {JNI_FALSE, JNI_FALSE, 0/*unused*/, {JNI_FALSE, JNI_TRUE}, JNI_FALSE, JNI_FALSE, JNI_FALSE}; return [self getPipelineState:pipelineDescriptor vertexShaderId:vertexShaderId fragmentShaderId:fragmentShaderId @@ -98,7 +98,7 @@ static void setBlendingFactors( fragmentShaderId:(NSString *)fragmentShaderId stencilNeeded:(bool)stencilNeeded { - RenderOptions defaultOptions = {JNI_FALSE, JNI_FALSE, 0/*unused*/, {JNI_FALSE, JNI_TRUE}, {JNI_FALSE, JNI_TRUE}, JNI_FALSE, JNI_FALSE, JNI_FALSE}; + RenderOptions defaultOptions = {JNI_FALSE, JNI_FALSE, 0/*unused*/, {JNI_FALSE, JNI_TRUE}, JNI_FALSE, JNI_FALSE, JNI_FALSE}; return [self getPipelineState:pipelineDescriptor vertexShaderId:vertexShaderId fragmentShaderId:fragmentShaderId @@ -107,6 +107,19 @@ static void setBlendingFactors( stencilNeeded:stencilNeeded]; } +// Pipeline state index +union StateIndex { + uint32_t value; + struct { + uint32_t srcPremultiplied : 1, + srcOpaque : 1, + stencil : 1, + aa : 1, + extAlpha : 1, + compositeRule : 27; + } bits; +}; + // Base method to obtain MTLRenderPipelineState. // NOTE: parameters compositeRule, srcFlags, dstFlags are used to set MTLRenderPipelineColorAttachmentDescriptor multipliers - (id) getPipelineState:(MTLRenderPipelineDescriptor *) pipelineDescriptor @@ -123,45 +136,31 @@ static void setBlendingFactors( // Calculate index by flags and compositeRule // TODO: reimplement, use map with convenient key (calculated by all arguments) - int subIndex = 0; + union StateIndex index; + index.value = 0; if (useXorComposite) { // compositeRule value is already XOR_COMPOSITE_RULE } else { if (useComposite) { - if (!renderOptions->srcFlags.isPremultiplied) - subIndex |= 1; - if (renderOptions->srcFlags.isOpaque) - subIndex |= 1 << 1; - if (!renderOptions->dstFlags.isPremultiplied) - subIndex |= 1 << 2; - if (renderOptions->dstFlags.isOpaque) - subIndex |= 1 << 3; + index.bits.srcPremultiplied = renderOptions->srcFlags.isPremultiplied; + index.bits.srcOpaque = renderOptions->srcFlags.isOpaque; } else compositeRule = RULE_Src; } - if (stencilNeeded) { - subIndex |= 1 << 4; - } - - if (renderOptions->isAA) { - subIndex |= 1 << 5; - } - - if ((composite != nil && FLT_LT([composite getExtraAlpha], 1.0f))) { - subIndex |= 1 << 6; - } - - int index = compositeRule*128 + subIndex; + index.bits.stencil = stencilNeeded; + index.bits.aa = renderOptions->isAA; + index.bits.extAlpha = composite != nil && FLT_LT([composite getExtraAlpha], 1.0f); + index.bits.compositeRule = compositeRule; NSPointerArray * subStates = [self getSubStates:vertexShaderId fragmentShader:fragmentShaderId]; - if (index >= subStates.count) { - subStates.count = (NSUInteger) (index + 1); + if (index.value >= subStates.count) { + subStates.count = index.value + 1; } - id result = [subStates pointerAtIndex:index]; + id result = [subStates pointerAtIndex:index.value]; if (result == nil) { @autoreleasepool { id vertexShader = [self getShader:vertexShaderId]; @@ -222,7 +221,7 @@ static void setBlendingFactors( exit(0); } - [subStates insertPointer:result atIndex:index]; + [subStates replacePointerAtIndex:index.value withPointer:result]; } } diff --git a/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/RenderOptions.h b/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/RenderOptions.h index 46521ca5b09a93d389cb96c6eb10d4131671d87f..f24f131631af88b6106e617a8032f2afa980172a 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/RenderOptions.h +++ b/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/RenderOptions.h @@ -35,7 +35,6 @@ typedef struct { jboolean isAA; int interpolation; SurfaceRasterFlags srcFlags; - SurfaceRasterFlags dstFlags; jboolean isText; jboolean isLCD; jboolean isAAShader; diff --git a/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/common.h b/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/common.h index 556bbf5d88ef4ded24a60900a1806f8baab6cf4a..70218f7e849c56a711d4771dd21278b20a40a263 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/common.h +++ b/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/common.h @@ -114,7 +114,6 @@ struct TxtFrameUniforms { vector_float4 color; int mode; // NOTE: consider to use bit fields int isSrcOpaque; - int isDstOpaque; float extraAlpha; }; diff --git a/src/java.desktop/macosx/native/libawt_lwawt/java2d/opengl/CGLGraphicsConfig.m b/src/java.desktop/macosx/native/libawt_lwawt/java2d/opengl/CGLGraphicsConfig.m index ca8717bc819936ba21a8738b325a0e7972454343..9ffaba58c02e9872bf5e7036819ddfb53f822340 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/java2d/opengl/CGLGraphicsConfig.m +++ b/src/java.desktop/macosx/native/libawt_lwawt/java2d/opengl/CGLGraphicsConfig.m @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 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 @@ -166,7 +166,7 @@ Java_sun_java2d_opengl_CGLGraphicsConfig_getCGLConfigInfo NSWindow *window = [[NSWindow alloc] initWithContentRect: contentRect - styleMask: NSBorderlessWindowMask + styleMask: NSWindowStyleMaskBorderless backing: NSBackingStoreBuffered defer: false]; if (window == nil) { diff --git a/src/java.desktop/macosx/native/libsplashscreen/splashscreen_sys.m b/src/java.desktop/macosx/native/libsplashscreen/splashscreen_sys.m index c28fe904102dd27e0e131a812da721e972741df8..3c634f4f5a2d904ec007db8c810e484c0b3c05fc 100644 --- a/src/java.desktop/macosx/native/libsplashscreen/splashscreen_sys.m +++ b/src/java.desktop/macosx/native/libsplashscreen/splashscreen_sys.m @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 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 @@ -434,7 +434,7 @@ SplashScreenThread(void *param) { splash->window = (void*) [[NSWindow alloc] initWithContentRect: NSMakeRect(splash->x, splash->y, splash->width, splash->height) - styleMask: NSBorderlessWindowMask + styleMask: NSWindowStyleMaskBorderless backing: NSBackingStoreBuffered defer: NO screen: SplashNSScreen()]; diff --git a/src/java.desktop/share/classes/com/sun/beans/TypeResolver.java b/src/java.desktop/share/classes/com/sun/beans/TypeResolver.java index 25f079473100cafe6e41dd85de85e6d8ca0be293..c8f2d1891dc0672ec840c9201009cb4181c3c2d5 100644 --- a/src/java.desktop/share/classes/com/sun/beans/TypeResolver.java +++ b/src/java.desktop/share/classes/com/sun/beans/TypeResolver.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -104,7 +104,7 @@ public final class TypeResolver { * of those parameters. For example, Map<K,V> is a generic class, and * a corresponding ParameterizedType might look like * Map<K=String,V=Integer>. Given such a ParameterizedType, this method - * will replace K with String, or List<K> with List<String;, or + * will replace K with String, or List<K> with List<String>, or * List<? super K> with List<? super String>.

          * *

          The {@code actual} argument to this method can also be a Class. diff --git a/src/java.desktop/share/classes/com/sun/beans/introspect/MethodInfo.java b/src/java.desktop/share/classes/com/sun/beans/introspect/MethodInfo.java index e5e79dc2a2f41ce7cd16aaadc9a67cfc655be309..5216f4423d4748febfe8c6b81af023afaeae92b4 100644 --- a/src/java.desktop/share/classes/com/sun/beans/introspect/MethodInfo.java +++ b/src/java.desktop/share/classes/com/sun/beans/introspect/MethodInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -98,10 +98,7 @@ final class MethodInfo { /** * A comparator that defines a total order so that methods have the same - * name and identical signatures appear next to each others. The methods are - * sorted in such a way that methods which override each other will sit next - * to each other, with the overridden method last - e.g. is Integer getFoo() - * placed before Object getFoo(). + * name and identical signatures appear next to each others. **/ private static final class MethodOrder implements Comparator { @@ -132,18 +129,7 @@ final class MethodInfo { } final Class aret = a.getReturnType(); final Class bret = b.getReturnType(); - if (aret == bret) { - return 0; - } - - // Super type comes last: Integer, Number, Object - if (aret.isAssignableFrom(bret)) { - return 1; - } - if (bret.isAssignableFrom(aret)) { - return -1; - } - return aret.getName().compareTo(bret.getName()); + return aret == bret ? 0 : aret.getName().compareTo(bret.getName()); } static final MethodOrder instance = new MethodOrder(); diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPImageReader.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPImageReader.java index df283e8102cd9ab099fbbe759718ac2669df6d0a..2e1c2db03ca84d64cdaa2c2abb00dabffeb1edb9 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPImageReader.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPImageReader.java @@ -52,6 +52,7 @@ import java.security.AccessController; import java.security.PrivilegedAction; import java.util.ArrayList; import java.util.Iterator; +import java.util.List; import javax.imageio.IIOException; import javax.imageio.ImageIO; import javax.imageio.ImageReadParam; @@ -223,6 +224,33 @@ public class BMPImageReader extends ImageReader implements BMPConstants { } } + private void readColorPalette(int sizeOfPalette) throws IOException { + final int UNIT_SIZE = 1024000; + if (sizeOfPalette < UNIT_SIZE) { + palette = new byte[sizeOfPalette]; + iis.readFully(palette, 0, sizeOfPalette); + } else { + int bytesToRead = sizeOfPalette; + int bytesRead = 0; + List bufs = new ArrayList<>(); + while (bytesToRead != 0) { + int sz = Math.min(bytesToRead, UNIT_SIZE); + byte[] unit = new byte[sz]; + iis.readFully(unit, 0, sz); + bufs.add(unit); + bytesRead += sz; + bytesToRead -= sz; + } + byte[] paletteData = new byte[bytesRead]; + int copiedBytes = 0; + for (byte[] ba : bufs) { + System.arraycopy(ba, 0, paletteData, copiedBytes, ba.length); + copiedBytes += ba.length; + } + palette = paletteData; + } + } + /** * Process the image header. * @@ -305,8 +333,7 @@ public class BMPImageReader extends ImageReader implements BMPConstants { // Read in the palette int numberOfEntries = (int)((bitmapOffset - 14 - size) / 3); int sizeOfPalette = numberOfEntries*3; - palette = new byte[sizeOfPalette]; - iis.readFully(palette, 0, sizeOfPalette); + readColorPalette(sizeOfPalette); metadata.palette = palette; metadata.paletteSize = numberOfEntries; } else { @@ -343,8 +370,7 @@ public class BMPImageReader extends ImageReader implements BMPConstants { } int numberOfEntries = (int)((bitmapOffset-14-size) / 4); int sizeOfPalette = numberOfEntries * 4; - palette = new byte[sizeOfPalette]; - iis.readFully(palette, 0, sizeOfPalette); + readColorPalette(sizeOfPalette); metadata.palette = palette; metadata.paletteSize = numberOfEntries; @@ -404,8 +430,7 @@ public class BMPImageReader extends ImageReader implements BMPConstants { if (colorsUsed != 0) { // there is a palette sizeOfPalette = (int)colorsUsed*4; - palette = new byte[sizeOfPalette]; - iis.readFully(palette, 0, sizeOfPalette); + readColorPalette(sizeOfPalette); metadata.palette = palette; metadata.paletteSize = (int)colorsUsed; @@ -430,8 +455,7 @@ public class BMPImageReader extends ImageReader implements BMPConstants { // Read in the palette int numberOfEntries = (int)((bitmapOffset-14-size) / 4); int sizeOfPalette = numberOfEntries*4; - palette = new byte[sizeOfPalette]; - iis.readFully(palette, 0, sizeOfPalette); + readColorPalette(sizeOfPalette); metadata.palette = palette; metadata.paletteSize = numberOfEntries; @@ -529,8 +553,7 @@ public class BMPImageReader extends ImageReader implements BMPConstants { // Read in the palette int numberOfEntries = (int)((bitmapOffset-14-size) / 4); int sizeOfPalette = numberOfEntries*4; - palette = new byte[sizeOfPalette]; - iis.readFully(palette, 0, sizeOfPalette); + readColorPalette(sizeOfPalette); metadata.palette = palette; metadata.paletteSize = numberOfEntries; @@ -592,7 +615,7 @@ public class BMPImageReader extends ImageReader implements BMPConstants { } if (metadata.compression == BI_RGB) { - long imageDataSize = (width * height * (bitsPerPixel / 8)); + long imageDataSize = ((long)width * height * (bitsPerPixel / 8)); if (imageDataSize > (bitmapFileSize - bitmapOffset)) { throw new IIOException(I18N.getString("BMPImageReader9")); } diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPImageWriter.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPImageWriter.java index 6a020ae934354f4e8766b6f10e98122cdd9f7888..56c21e18548b539aec9b07fb908f58cc0b456eba 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPImageWriter.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPImageWriter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -210,10 +210,8 @@ public class BMPImageWriter extends ImageWriter implements BMPConstants { IIOMetadata imageMetadata = image.getMetadata(); BMPMetadata bmpImageMetadata = null; - if (imageMetadata != null - && imageMetadata instanceof BMPMetadata) - { - bmpImageMetadata = (BMPMetadata)imageMetadata; + if (imageMetadata instanceof BMPMetadata bmp) { + bmpImageMetadata = bmp; } else { ImageTypeSpecifier imageType = new ImageTypeSpecifier(colorModel, sampleModel); diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/common/ReaderUtil.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/common/ReaderUtil.java index 0f8d1d66a28d206c2092ab3541e060d05622c7b5..906aa3a8a38fa7377456112b05b86474e2b53db1 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/common/ReaderUtil.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/common/ReaderUtil.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -28,6 +28,8 @@ package com.sun.imageio.plugins.common; import java.awt.Point; import java.awt.Rectangle; import java.io.IOException; +import java.util.List; +import java.util.ArrayList; import javax.imageio.stream.ImageInputStream; /** @@ -213,4 +215,47 @@ public class ReaderUtil { } return result; } + + /** + * An utility method to allocate and initialize a byte array + * step by step with pre-defined limit, instead of allocating + * a large array up-front based on the length derived from + * an image header. + * + * @param iis a {@code ImageInputStream} to decode data and store + * it in byte array. + * @param length the size of data to decode + * + * @return array of size length when decode succeeeds + * + * @throws IOException if decoding of stream fails + */ + public static byte[] staggeredReadByteStream(ImageInputStream iis, + int length) throws IOException { + final int UNIT_SIZE = 1024000; + byte[] decodedData; + if (length < UNIT_SIZE) { + decodedData = new byte[length]; + iis.readFully(decodedData, 0, length); + } else { + int bytesToRead = length; + int bytesRead = 0; + List bufs = new ArrayList<>(); + while (bytesToRead != 0) { + int sz = Math.min(bytesToRead, UNIT_SIZE); + byte[] unit = new byte[sz]; + iis.readFully(unit, 0, sz); + bufs.add(unit); + bytesRead += sz; + bytesToRead -= sz; + } + decodedData = new byte[bytesRead]; + int copiedBytes = 0; + for (byte[] ba : bufs) { + System.arraycopy(ba, 0, decodedData, copiedBytes, ba.length); + copiedBytes += ba.length; + } + } + return decodedData; + } } diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/common/SimpleCMYKColorSpace.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/common/SimpleCMYKColorSpace.java index 95c4d9ec5970f045470e84ce1efbd5694ac0ef23..75586561598ad0cb7048647f6565df7867036640 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/common/SimpleCMYKColorSpace.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/common/SimpleCMYKColorSpace.java @@ -59,7 +59,7 @@ public final class SimpleCMYKColorSpace extends ColorSpace { } public boolean equals(Object o) { - return o != null && o instanceof SimpleCMYKColorSpace; + return o instanceof SimpleCMYKColorSpace; } public int hashCode() { diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/common/SubImageInputStream.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/common/SubImageInputStream.java index 8ddffc522f1873a8689e14a19ca0667d174d71e4..10211c6636c90bb572937f71794925fdbc21cff1 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/common/SubImageInputStream.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/common/SubImageInputStream.java @@ -72,7 +72,7 @@ public final class SubImageInputStream extends ImageInputStreamImpl { streamPos = pos; } - @SuppressWarnings("deprecation") + @SuppressWarnings("removal") protected void finalize() throws Throwable { // Empty finalizer (for improved performance; no need to call // super.finalize() in this case) diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageReader.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageReader.java index 2bedc9440ee9435349836be4a2a76d284c5694c7..9632e37d1d41d06a5079857c3701c04d423266d9 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageReader.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageReader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -1007,6 +1007,11 @@ public class GIFImageReader extends ImageReader { } } + if (tableIndex >= prefix.length) { + throw new IIOException("Code buffer limit reached," + + " no End of Image tag present, possibly data is corrupted. "); + } + int ti = tableIndex; int oc = oldCode; diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFWritableImageMetadata.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFWritableImageMetadata.java index 8566d45f6a482dd62f64b6622f6d2905ea6d652a..a3e8a769490b7822efab8e63814930b01a1f8bce 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFWritableImageMetadata.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFWritableImageMetadata.java @@ -248,8 +248,7 @@ class GIFWritableImageMetadata extends GIFImageMetadata { Object applicationExtensionData = applicationExtension.getUserObject(); - if (applicationExtensionData == null || - !(applicationExtensionData instanceof byte[])) { + if (!(applicationExtensionData instanceof byte[])) { fatal(applicationExtension, "Bad user object in ApplicationExtension!"); } diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/DHTMarkerSegment.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/DHTMarkerSegment.java index 34eca627d97dd4276ff5c03cb1f38d9743c6ffa7..c14402522db4173af05dbbbafbe84f28259e7441 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/DHTMarkerSegment.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/DHTMarkerSegment.java @@ -138,7 +138,7 @@ class DHTMarkerSegment extends MarkerSegment { /** * A Huffman table within a DHT marker segment. */ - class Htable implements Cloneable { + static class Htable implements Cloneable { int tableClass; // 0 == DC, 1 == AC int tableID; // 0 - 4 private static final int NUM_LENGTHS = 16; diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/DQTMarkerSegment.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/DQTMarkerSegment.java index be11577f0e342b34b18b41bd01ce2720a628e4d6..8b983afc24545d8c219df220391df90cf6fa5824 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/DQTMarkerSegment.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/DQTMarkerSegment.java @@ -171,7 +171,7 @@ class DQTMarkerSegment extends MarkerSegment { /** * A quantization table within a DQT marker segment. */ - class Qtable implements Cloneable { + static class Qtable implements Cloneable { int elementPrecision; int tableID; final int QTABLE_SIZE = 64; diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JFIFMarkerSegment.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JFIFMarkerSegment.java index e03ceecd3934472e12472ed91110104c0869e317..8b95d8adc65fec021e1402c1ce709304d2a53f60 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JFIFMarkerSegment.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JFIFMarkerSegment.java @@ -552,7 +552,7 @@ class JFIFMarkerSegment extends MarkerSegment { // Could put reason codes in here to be parsed in writeJFXXSegment // in order to provide more meaningful warnings. @SuppressWarnings("serial") // JDK-implementation class - private class IllegalThumbException extends Exception {} + private static class IllegalThumbException extends Exception {} /** * Writes out a new JFXX extension segment, without saving it. @@ -794,7 +794,7 @@ class JFIFMarkerSegment extends MarkerSegment { * A superclass for the varieties of thumbnails that can * be stored in a JFIF extension marker segment. */ - abstract class JFIFThumb implements Cloneable { + abstract static class JFIFThumb implements Cloneable { long streamPos = -1L; // Save the thumbnail pos when reading abstract int getLength(); // When writing abstract int getWidth(); @@ -1111,7 +1111,7 @@ class JFIFMarkerSegment extends MarkerSegment { * to clip these, but the entire image must fit into a * single JFXX marker segment. */ - class JFIFThumbJPEG extends JFIFThumb { + static class JFIFThumbJPEG extends JFIFThumb { JPEGMetadata thumbMetadata = null; byte [] data = null; // Compressed image data, for writing private static final int PREAMBLE_SIZE = 6; @@ -1234,7 +1234,7 @@ class JFIFMarkerSegment extends MarkerSegment { return retval; } - private class ThumbnailReadListener + private static class ThumbnailReadListener implements IIOReadProgressListener { JPEGImageReader reader = null; ThumbnailReadListener (JPEGImageReader reader) { diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReader.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReader.java index ab15bdfc6b810e9b40779164d2dcdfb351d623ef..a7edf73cb80b6cbb4e518ea9150dac18ac62dedc 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReader.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReader.java @@ -1156,6 +1156,13 @@ public class JPEGImageReader extends ImageReader { throw new IIOException("Unsupported Image Type"); } + if ((long)width * height > Integer.MAX_VALUE - 2) { + // We are not able to properly decode image that has number + // of pixels greater than Integer.MAX_VALUE - 2 + throw new IIOException("Can not read image of the size " + + width + " by " + height); + } + image = getDestination(param, imageTypes, width, height); imRas = image.getRaster(); diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGMetadata.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGMetadata.java index ece1df86fcf50984241eab5c36666f7b67d498ae..a2fe287bc3dbef9dee20c63017d3873eddf07bad 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGMetadata.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGMetadata.java @@ -371,8 +371,8 @@ public class JPEGMetadata extends IIOMetadata implements Cloneable { JPEGImageWriteParam jparam = null; - if ((param != null) && (param instanceof JPEGImageWriteParam)) { - jparam = (JPEGImageWriteParam) param; + if (param instanceof JPEGImageWriteParam p) { + jparam = p; if (!jparam.areTablesSet()) { jparam = null; } diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/SOFMarkerSegment.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/SOFMarkerSegment.java index 8cc1813a23e618e7a865aa96d42469b7b35811b7..e5b7e8619243839b2dcc145c7bdcef8c647ff80f 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/SOFMarkerSegment.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/SOFMarkerSegment.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -199,7 +199,7 @@ class SOFMarkerSegment extends MarkerSegment { /** * A component spec within an SOF marker segment. */ - class ComponentSpec implements Cloneable { + static class ComponentSpec implements Cloneable { int componentId; int HsamplingFactor; int VsamplingFactor; diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/SOSMarkerSegment.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/SOSMarkerSegment.java index c8f223190fd9b8792863c342585b47298915282c..f40acdd0375821d59c6fc7d0d0242bf2fb3e049a 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/SOSMarkerSegment.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/SOSMarkerSegment.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -25,7 +25,6 @@ package com.sun.imageio.plugins.jpeg; -//import javax.imageio.IIOException; import javax.imageio.metadata.IIOInvalidTreeException; import javax.imageio.metadata.IIOMetadataNode; import javax.imageio.stream.ImageOutputStream; @@ -181,7 +180,7 @@ class SOSMarkerSegment extends MarkerSegment { /** * A scan component spec within an SOS marker segment. */ - class ScanComponentSpec implements Cloneable { + static class ScanComponentSpec implements Cloneable { int componentSelector; int dcHuffTable; int acHuffTable; diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGImageReader.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGImageReader.java index fc731506af37c0a758735c935161525dcc89b72b..edebce1d62e00837b3646347971cee02eb85176b 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGImageReader.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGImageReader.java @@ -669,18 +669,9 @@ public class PNGImageReader extends ImageReader { private static byte[] inflate(byte[] b) throws IOException { InputStream bais = new ByteArrayInputStream(b); - InputStream iis = new InflaterInputStream(bais); - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - - int c; - try { - while ((c = iis.read()) != -1) { - baos.write(c); - } - } finally { - iis.close(); + try (InputStream iis = new InflaterInputStream(bais)) { + return iis.readAllBytes(); } - return baos.toByteArray(); } private void parse_zTXt_chunk(int chunkLength) throws IOException { @@ -1424,6 +1415,13 @@ public class PNGImageReader extends ImageReader { int width = metadata.IHDR_width; int height = metadata.IHDR_height; + if ((long)width * height > Integer.MAX_VALUE - 2) { + // We are not able to properly decode image that has number + // of pixels greater than Integer.MAX_VALUE - 2 + throw new IIOException("Can not read image of the size " + + width + " by " + height); + } + // Init default values sourceXSubsampling = 1; sourceYSubsampling = 1; diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGImageWriter.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGImageWriter.java index 449661b8c91800b48d8c835dc52ff946a3a58866..ce6f771ecdceb539a4bc27562fbda1167cb429d0 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGImageWriter.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGImageWriter.java @@ -147,7 +147,7 @@ final class ChunkStream extends ImageOutputStreamImpl { } @Override - @SuppressWarnings("deprecation") + @SuppressWarnings("removal") protected void finalize() throws Throwable { // Empty finalizer (for improved performance; no need to call // super.finalize() in this case) @@ -284,7 +284,7 @@ final class IDATOutputStream extends ImageOutputStreamImpl { } @Override - @SuppressWarnings("deprecation") + @SuppressWarnings("removal") protected void finalize() throws Throwable { // Empty finalizer (for improved performance; no need to call // super.finalize() in this case) diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFBaseJPEGCompressor.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFBaseJPEGCompressor.java index d78cb1cbdd9cc4c415cb89be01a7f9187c88e477..dba8d87816953a71c6cd094e663196dd9ffd65f2 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFBaseJPEGCompressor.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFBaseJPEGCompressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -274,8 +274,8 @@ public abstract class TIFFBaseJPEGCompressor extends TIFFCompressor { // Initialize the ImageWriteParam. if(this.JPEGParam == null) { - if(param != null && param instanceof JPEGImageWriteParam) { - JPEGParam = (JPEGImageWriteParam)param; + if (param instanceof JPEGImageWriteParam p) { + JPEGParam = p; } else { JPEGParam = new JPEGImageWriteParam(writer != null ? @@ -435,7 +435,7 @@ public abstract class TIFFBaseJPEGCompressor extends TIFFCompressor { return compDataLength; } - @SuppressWarnings("deprecation") + @SuppressWarnings("removal") protected void finalize() throws Throwable { super.finalize(); if(JPEGWriter != null) { diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFDecompressor.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFDecompressor.java index a1b0439097758409a855b970b552dd897f79a679..4516ce0ad82e391319cb46d7332112d2892b5c26 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFDecompressor.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFDecompressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -1438,7 +1438,11 @@ public abstract class TIFFDecompressor { * * @param byteCount the number of bytes of compressed data. */ - public void setByteCount(int byteCount) { + public void setByteCount(int byteCount) throws IOException{ + if (byteCount < 0) { + throw new IIOException("Strip byte count can't be" + + " negative: " + byteCount); + } this.byteCount = byteCount; } diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFFaxDecompressor.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFFaxDecompressor.java index 22ebda2187af01eccbccad45acb7f973b374f27c..4d64072075a6ea362e99c2cf7e99835ad6b2f8bd 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFFaxDecompressor.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFFaxDecompressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -29,6 +29,7 @@ import java.io.EOFException; import javax.imageio.IIOException; import javax.imageio.plugins.tiff.BaselineTIFFTagSet; import javax.imageio.plugins.tiff.TIFFField; +import com.sun.imageio.plugins.common.ReaderUtil; class TIFFFaxDecompressor extends TIFFDecompressor { @@ -637,14 +638,14 @@ class TIFFFaxDecompressor extends TIFFDecompressor { this.bitsPerScanline = scanlineStride*8; this.lineBitNum = 8*dstOffset; - this.data = new byte[byteCount]; this.bitPointer = 0; this.bytePointer = 0; this.prevChangingElems = new int[w + 1]; this.currChangingElems = new int[w + 1]; stream.seek(offset); - stream.readFully(data); + this.data = ReaderUtil. + staggeredReadByteStream(stream, byteCount); if (compression == BaselineTIFFTagSet.COMPRESSION_CCITT_RLE) { decodeRLE(); diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageWriter.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageWriter.java index 1d2cff4231105a04ed3239d8f604c54f6faeac22..07186c0deb5a24e33f837bf1e83ccdfab889424a 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageWriter.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageWriter.java @@ -2895,7 +2895,7 @@ public class TIFFImageWriter extends ImageWriter { int numThumbs = thumbnails.size(); for(int i = 0; i < numThumbs; i++) { Object thumb = thumbnails.get(i); - if(thumb == null || !(thumb instanceof BufferedImage)) { + if (!(thumb instanceof BufferedImage)) { throw new IllegalArgumentException ("thumbnails contains null references or objects other than BufferedImages!"); } diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFJPEGDecompressor.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFJPEGDecompressor.java index 384687f8344b104ac1d93287f7732f5927c77d8f..0b21835901b44621456e41188e3a2c8d256eb59e 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFJPEGDecompressor.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFJPEGDecompressor.java @@ -139,7 +139,7 @@ public class TIFFJPEGDecompressor extends TIFFDecompressor { JPEGReader.read(0, JPEGParam); } - @SuppressWarnings("deprecation") + @SuppressWarnings("removal") protected void finalize() throws Throwable { super.finalize(); JPEGReader.dispose(); diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFLZWDecompressor.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFLZWDecompressor.java index 9010674bdb18abe8cee1b5133f0442802ab89d21..fc682589ce2700cbb29547ca9bd6323474a20002 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFLZWDecompressor.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFLZWDecompressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -27,6 +27,7 @@ package com.sun.imageio.plugins.tiff; import java.io.IOException; import javax.imageio.IIOException; import javax.imageio.plugins.tiff.BaselineTIFFTagSet; +import com.sun.imageio.plugins.common.ReaderUtil; class TIFFLZWDecompressor extends TIFFDecompressor { @@ -95,9 +96,8 @@ class TIFFLZWDecompressor extends TIFFDecompressor { } stream.seek(offset); - - byte[] sdata = new byte[byteCount]; - stream.readFully(sdata); + byte[] sdata = ReaderUtil. + staggeredReadByteStream(stream, byteCount); if (flipBits) { for (int i = 0; i < byteCount; i++) { diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFNullDecompressor.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFNullDecompressor.java index 6ffc1f0acb7da9d4b3b5dc9a9f2fdfe458ac9c1f..9b5a746eec1da0eddd064a8ff785ad5150982d5a 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFNullDecompressor.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFNullDecompressor.java @@ -136,12 +136,7 @@ public class TIFFNullDecompressor extends TIFFDecompressor { int lastRow = activeSrcHeight - 1; for (int y = 0; y < activeSrcHeight; y++) { - int bytesRead = stream.read(b, dstOffset, activeBytesPerRow); - if (bytesRead < 0) { - throw new EOFException(); - } else if (bytesRead != activeBytesPerRow) { - break; - } + stream.readFully(b, dstOffset, activeBytesPerRow); dstOffset += scanlineStride; // Skip unneeded bytes (row suffix + row prefix). @@ -154,17 +149,10 @@ public class TIFFNullDecompressor extends TIFFDecompressor { stream.seek(offset); int bytesPerRow = (srcWidth*bitsPerPixel + 7)/8; if(bytesPerRow == scanlineStride) { - if (stream.read(b, dstOffset, bytesPerRow*srcHeight) < 0) { - throw new EOFException(); - } + stream.readFully(b, dstOffset, bytesPerRow*srcHeight); } else { for (int y = 0; y < srcHeight; y++) { - int bytesRead = stream.read(b, dstOffset, bytesPerRow); - if (bytesRead < 0) { - throw new EOFException(); - } else if (bytesRead != bytesPerRow) { - break; - } + stream.readFully(b, dstOffset, bytesPerRow); dstOffset += scanlineStride; } } diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFOldJPEGDecompressor.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFOldJPEGDecompressor.java index 67dd60f8a79a4480a8c4cf99b288f920e0cf0582..3cd89b396ccc007beec977d0db210194bc1ba53b 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFOldJPEGDecompressor.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFOldJPEGDecompressor.java @@ -610,7 +610,7 @@ public class TIFFOldJPEGDecompressor extends TIFFJPEGDecompressor { JPEGReader.read(0, JPEGParam); } - @SuppressWarnings("deprecation") + @SuppressWarnings("removal") protected void finalize() throws Throwable { super.finalize(); JPEGReader.dispose(); diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFPackBitsDecompressor.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFPackBitsDecompressor.java index 42a44a43eee4e396005496ab4f8cf1e3fed5362a..0a5dfe8308e206620c5bb87fb2a2c2fe9b2c1add 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFPackBitsDecompressor.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFPackBitsDecompressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -25,6 +25,7 @@ package com.sun.imageio.plugins.tiff; import java.io.IOException; +import com.sun.imageio.plugins.common.ReaderUtil; public class TIFFPackBitsDecompressor extends TIFFDecompressor { @@ -77,8 +78,8 @@ public class TIFFPackBitsDecompressor extends TIFFDecompressor { int scanlineStride) throws IOException { stream.seek(offset); - byte[] srcData = new byte[byteCount]; - stream.readFully(srcData); + byte[] srcData = ReaderUtil. + staggeredReadByteStream(stream, byteCount); int bytesPerRow = (srcWidth*bitsPerPixel + 7)/8; byte[] buf; diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFYCbCrDecompressor.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFYCbCrDecompressor.java index 11151d8e6c8e71700e3465d95d52fcc477854d87..0f10904cab413b5fa6126387d69d36a0eea41331 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFYCbCrDecompressor.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFYCbCrDecompressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -180,7 +180,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { super.setOffset(offset); } - public void setByteCount(int byteCount) { + public void setByteCount(int byteCount) throws IOException { if(decompressor != null) { decompressor.setByteCount(byteCount); } diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/wbmp/WBMPImageReader.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/wbmp/WBMPImageReader.java index 5676733e65f33fe13b0e342b15091ec09e512f82..ac62269b2d9b6456aeb8332a21d52fd4e6cdfb8d 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/wbmp/WBMPImageReader.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/wbmp/WBMPImageReader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -244,8 +244,8 @@ public class WBMPImageReader extends ImageReader { } // If noTransform is necessary, read the data. - iis.read(((DataBufferByte)tile.getDataBuffer()).getData(), - 0, height*sm.getScanlineStride()); + iis.readFully(((DataBufferByte)tile.getDataBuffer()).getData(), + 0, height*sm.getScanlineStride()); processImageUpdate(bi, 0, 0, width, height, 1, 1, @@ -280,7 +280,7 @@ public class WBMPImageReader extends ImageReader { if (abortRequested()) break; - iis.read(buf, 0, len); + iis.readFully(buf, 0, len); for (int i = 0; i < destinationRegion.width; i++) { //get the bit and assign to the data buffer of the raster int v = (buf[srcPos[i]] >> srcOff[i]) & 1; diff --git a/src/java.desktop/share/classes/com/sun/imageio/stream/StreamFinalizer.java b/src/java.desktop/share/classes/com/sun/imageio/stream/StreamFinalizer.java index be1e659ee6e7784e1131d48f22a4d1846642c3c1..012d7e106459823b25b62310c06bd48296e370ea 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/stream/StreamFinalizer.java +++ b/src/java.desktop/share/classes/com/sun/imageio/stream/StreamFinalizer.java @@ -60,7 +60,7 @@ public class StreamFinalizer { this.stream = stream; } - @SuppressWarnings("deprecation") + @SuppressWarnings("removal") protected void finalize() throws Throwable { try { stream.close(); diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKColorChooserPanel.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKColorChooserPanel.java index 77c0e65dabc388856d5049d7af82874677a0e39f..78fa1e9663545bc374ed4832482fff7882b64296 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKColorChooserPanel.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKColorChooserPanel.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 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 @@ -1298,7 +1298,7 @@ class GTKColorChooserPanel extends AbstractColorChooserPanel implements } @SuppressWarnings("serial") // Superclass is not serializable across versions - private class OpaqueLabel extends JLabel { + private static class OpaqueLabel extends JLabel { public boolean isOpaque() { return true; } diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/Metacity.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/Metacity.java index 134cdd9a2dc6cadaa8194f5ecd671c0e3422e725..d2388fa6b04e639019d6090d0b5d7fc102e77e5d 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/Metacity.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/Metacity.java @@ -583,15 +583,16 @@ class Metacity implements SynthConstants { URL url = new URL(new File(userHome).toURI().toURL(), ".gconf/apps/metacity/general/%25gconf.xml"); // Pending: verify character encoding spec for gconf - Reader reader = new InputStreamReader(url.openStream(), - ISO_8859_1); - char[] buf = new char[1024]; StringBuilder sb = new StringBuilder(); - int n; - while ((n = reader.read(buf)) >= 0) { - sb.append(buf, 0, n); + try (InputStream in = url.openStream(); + Reader reader = new InputStreamReader(in, ISO_8859_1)) + { + char[] buf = new char[1024]; + int n; + while ((n = reader.read(buf)) >= 0) { + sb.append(buf, 0, n); + } } - reader.close(); String str = sb.toString(); if (str != null) { String strLowerCase = str.toLowerCase(); diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifDesktopPaneUI.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifDesktopPaneUI.java index 60552b8c780ba9a39f5d902782e50fe71fa91f5c..d25188dc07722c7a7981db063d8a602afbda0e5a 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifDesktopPaneUI.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifDesktopPaneUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -74,7 +74,7 @@ public class MotifDesktopPaneUI extends javax.swing.plaf.basic.BasicDesktopPaneU /// DragPane class //////////////////////////////////////////////////////////////////////////////////// @SuppressWarnings("serial") // Superclass is not serializable across versions - private class DragPane extends JComponent { + private static class DragPane extends JComponent { public void paint(Graphics g) { g.setColor(Color.darkGray); g.drawRect(0, 0, getWidth()-1, getHeight()-1); @@ -85,7 +85,7 @@ public class MotifDesktopPaneUI extends javax.swing.plaf.basic.BasicDesktopPaneU /// MotifDesktopManager class //////////////////////////////////////////////////////////////////////////////////// @SuppressWarnings("serial") // JDK-implementation class - private class MotifDesktopManager extends DefaultDesktopManager implements Serializable, UIResource { + private static class MotifDesktopManager extends DefaultDesktopManager implements Serializable, UIResource { JComponent dragPane; boolean usingDragPane = false; private transient JLayeredPane layeredPaneForDragPane; diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifFileChooserUI.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifFileChooserUI.java index fcb9e724febc603974d113416c3dee647af85d0a..847fbf4117d4cda0caa99fbc1f1f00660f1bd3e1 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifFileChooserUI.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifFileChooserUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -787,8 +787,8 @@ public class MotifFileChooserUI extends BasicFileChooserUI { super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); - if (value != null && value instanceof FileFilter) { - setText(((FileFilter)value).getDescription()); + if (value instanceof FileFilter fileFilter) { + setText(fileFilter.getDescription()); } return this; diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifMenuUI.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifMenuUI.java index eaeb5b2ab662e1aea28429a2b89bb618229a9aec..bcee2e666fa682df552602a44850b555003773bd 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifMenuUI.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifMenuUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -110,10 +110,10 @@ public class MotifMenuUI extends BasicMenuUI manager.clearSelectedPath(); } else { Container cnt = menu.getParent(); - if(cnt != null && cnt instanceof JMenuBar) { + if (cnt instanceof JMenuBar menuBar) { MenuElement[] me = new MenuElement[2]; - me[0]=(MenuElement)cnt; - me[1]=menu; + me[0] = menuBar; + me[1] = menu; manager.setSelectedPath(me); } } diff --git a/src/java.desktop/share/classes/com/sun/media/sound/AbstractMidiDevice.java b/src/java.desktop/share/classes/com/sun/media/sound/AbstractMidiDevice.java index 52588387a788120a248781a38bdeb23ab8ad5005..3ba4ce2ed366b13eb76709bcf4f8eb4bd707fd3e 100644 --- a/src/java.desktop/share/classes/com/sun/media/sound/AbstractMidiDevice.java +++ b/src/java.desktop/share/classes/com/sun/media/sound/AbstractMidiDevice.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -425,7 +425,7 @@ abstract class AbstractMidiDevice implements MidiDevice, ReferenceCountingDevice * close this device if discarded by the garbage collector. */ @Override - @SuppressWarnings("deprecation") + @SuppressWarnings("removal") protected final void finalize() { close(); } @@ -576,11 +576,9 @@ abstract class AbstractMidiDevice implements MidiDevice, ReferenceCountingDevice if (midiOutReceiver == oldR) { midiOutReceiver = null; } - if (newR != null) { - if ((newR instanceof MidiOutDevice.MidiOutReceiver) + if ((newR instanceof MidiOutDevice.MidiOutReceiver newReceiver) && (midiOutReceiver == null)) { - midiOutReceiver = ((MidiOutDevice.MidiOutReceiver) newR); - } + midiOutReceiver = newReceiver; } optimizedReceiverCount = ((midiOutReceiver!=null)?1:0); diff --git a/src/java.desktop/share/classes/com/sun/media/sound/AudioFileSoundbankReader.java b/src/java.desktop/share/classes/com/sun/media/sound/AudioFileSoundbankReader.java index de9d124753fcaea58a47348752e20d56c4dcd7cd..32b06d47bd2965dce4375fd3a1ee9526d1527086 100644 --- a/src/java.desktop/share/classes/com/sun/media/sound/AudioFileSoundbankReader.java +++ b/src/java.desktop/share/classes/com/sun/media/sound/AudioFileSoundbankReader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 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 @@ -48,10 +48,8 @@ public final class AudioFileSoundbankReader extends SoundbankReader { @Override public Soundbank getSoundbank(URL url) throws InvalidMidiDataException, IOException { - try { - AudioInputStream ais = AudioSystem.getAudioInputStream(url); + try (AudioInputStream ais = AudioSystem.getAudioInputStream(url)) { Soundbank sbk = getSoundbank(ais); - ais.close(); return sbk; } catch (UnsupportedAudioFileException e) { return null; diff --git a/src/java.desktop/share/classes/com/sun/media/sound/AudioFloatFormatConverter.java b/src/java.desktop/share/classes/com/sun/media/sound/AudioFloatFormatConverter.java index 6dbbb3384506580f36947d8de7e8c247f5a48ccc..cb0dcf9df7e0eca50f661358c4b302446d25dcca 100644 --- a/src/java.desktop/share/classes/com/sun/media/sound/AudioFloatFormatConverter.java +++ b/src/java.desktop/share/classes/com/sun/media/sound/AudioFloatFormatConverter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 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 @@ -293,8 +293,7 @@ public final class AudioFloatFormatConverter extends FormatConversionProvider { format.getSampleRate(), sourceFormat.isBigEndian()); nrofchannels = targetFormat.getChannels(); Object interpolation = format.getProperty("interpolation"); - if (interpolation != null && (interpolation instanceof String)) { - String resamplerType = (String) interpolation; + if (interpolation instanceof String resamplerType) { if (resamplerType.equalsIgnoreCase("point")) this.resampler = new SoftPointResampler(); if (resamplerType.equalsIgnoreCase("linear")) diff --git a/src/java.desktop/share/classes/com/sun/media/sound/DLSSoundbank.java b/src/java.desktop/share/classes/com/sun/media/sound/DLSSoundbank.java index 3d62b3ae5a63074180f5dda2828a69978dc668e9..ba25dcacd20b92a990c5d6686adb98f340808809 100644 --- a/src/java.desktop/share/classes/com/sun/media/sound/DLSSoundbank.java +++ b/src/java.desktop/share/classes/com/sun/media/sound/DLSSoundbank.java @@ -191,22 +191,16 @@ public final class DLSSoundbank implements Soundbank { } public DLSSoundbank(URL url) throws IOException { - InputStream is = url.openStream(); - try { + try (InputStream is = url.openStream()) { readSoundbank(is); - } finally { - is.close(); } } public DLSSoundbank(File file) throws IOException { largeFormat = true; sampleFile = file; - InputStream is = new FileInputStream(file); - try { + try (InputStream is = new FileInputStream(file)) { readSoundbank(is); - } finally { - is.close(); } } @@ -875,15 +869,21 @@ public final class DLSSoundbank implements Soundbank { } public void save(String name) throws IOException { - writeSoundbank(new RIFFWriter(name, "DLS ")); + try (RIFFWriter writer = new RIFFWriter(name, "DLS ")) { + writeSoundbank(writer); + } } public void save(File file) throws IOException { - writeSoundbank(new RIFFWriter(file, "DLS ")); + try (RIFFWriter writer = new RIFFWriter(file, "DLS ")) { + writeSoundbank(writer); + } } public void save(OutputStream out) throws IOException { - writeSoundbank(new RIFFWriter(out, "DLS ")); + try (RIFFWriter writer = new RIFFWriter(out, "DLS ")) { + writeSoundbank(writer); + } } private void writeSoundbank(RIFFWriter writer) throws IOException { @@ -923,8 +923,6 @@ public final class DLSSoundbank implements Soundbank { writer.seek(bak); writeInfo(writer.writeList("INFO"), info); - - writer.close(); } private void writeSample(RIFFWriter writer, DLSSample sample) diff --git a/src/java.desktop/share/classes/com/sun/media/sound/DataPusher.java b/src/java.desktop/share/classes/com/sun/media/sound/DataPusher.java index 8944df836aef4f68821ff47e90f61d6a00ab8585..d40c2cd8c317f5faa67ae58b4e6bd4232a2436ed 100644 --- a/src/java.desktop/share/classes/com/sun/media/sound/DataPusher.java +++ b/src/java.desktop/share/classes/com/sun/media/sound/DataPusher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 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 @@ -108,7 +108,7 @@ public final class DataPusher implements Runnable { source.start(); if (pushThread == null) { pushThread = JSSecurityManager.createThread(this, - null, // name + "DataPusher", // name false, // daemon -1, // priority true); // doStart diff --git a/src/java.desktop/share/classes/com/sun/media/sound/DirectAudioDevice.java b/src/java.desktop/share/classes/com/sun/media/sound/DirectAudioDevice.java index b261b6799ef4a4f012240a14edb7b1f2eb47865f..2e01d46201c1d13bb87aa6c8580df7c1fc89537d 100644 --- a/src/java.desktop/share/classes/com/sun/media/sound/DirectAudioDevice.java +++ b/src/java.desktop/share/classes/com/sun/media/sound/DirectAudioDevice.java @@ -1297,8 +1297,9 @@ final class DirectAudioDevice extends AbstractMixer { } } while (doIO && thread == curThread) { - if (newFramePosition >= 0) { - clipBytePosition = newFramePosition * frameSize; + int npf = newFramePosition; // copy into local variable + if (npf >= 0) { + clipBytePosition = npf * frameSize; newFramePosition = -1; } int endFrame = getFrameLength() - 1; diff --git a/src/java.desktop/share/classes/com/sun/media/sound/EventDispatcher.java b/src/java.desktop/share/classes/com/sun/media/sound/EventDispatcher.java index 4b5027b12d2d598e4a998abfb712f52b67ef7058..1d66df87f1d7a7259607239fb3c30d6326933c98 100644 --- a/src/java.desktop/share/classes/com/sun/media/sound/EventDispatcher.java +++ b/src/java.desktop/share/classes/com/sun/media/sound/EventDispatcher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -350,7 +350,7 @@ final class EventDispatcher implements Runnable { /** * Container for an event and a set of listeners to deliver it to. */ - private class EventInfo { + private static class EventInfo { private final Object event; private final Object[] listeners; @@ -383,7 +383,7 @@ final class EventDispatcher implements Runnable { /** * Container for a clip with its expiration time. */ - private class ClipInfo { + private static class ClipInfo { private final AutoClosingClip clip; private final long expiration; diff --git a/src/java.desktop/share/classes/com/sun/media/sound/JARSoundbankReader.java b/src/java.desktop/share/classes/com/sun/media/sound/JARSoundbankReader.java index e01bc10cf3912b013deb4247378caa1b2ae6c6b6..967d35d31dc35caf2720cd7214c029d9665dcf56 100644 --- a/src/java.desktop/share/classes/com/sun/media/sound/JARSoundbankReader.java +++ b/src/java.desktop/share/classes/com/sun/media/sound/JARSoundbankReader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 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 @@ -51,8 +51,7 @@ public final class JARSoundbankReader extends SoundbankReader { private static boolean isZIP(URL url) { boolean ok = false; try { - InputStream stream = url.openStream(); - try { + try (InputStream stream = url.openStream()) { byte[] buff = new byte[4]; ok = stream.read(buff) == 4; if (ok) { @@ -61,8 +60,6 @@ public final class JARSoundbankReader extends SoundbankReader { && buff[2] == 0x03 && buff[3] == 0x04); } - } finally { - stream.close(); } } catch (IOException e) { } @@ -81,8 +78,7 @@ public final class JARSoundbankReader extends SoundbankReader { "META-INF/services/javax.sound.midi.Soundbank"); if (stream == null) return null; - try - { + try (stream) { BufferedReader r = new BufferedReader(new InputStreamReader(stream)); String line = r.readLine(); while (line != null) { @@ -100,10 +96,6 @@ public final class JARSoundbankReader extends SoundbankReader { line = r.readLine(); } } - finally - { - stream.close(); - } if (soundbanks.size() == 0) return null; if (soundbanks.size() == 1) diff --git a/src/java.desktop/share/classes/com/sun/media/sound/JSSecurityManager.java b/src/java.desktop/share/classes/com/sun/media/sound/JSSecurityManager.java index f593ed8b89749206a6d9f4b058c41c7cc8a1f45f..51482b24aeaae88ecab6d19bb8a35463841f2831 100644 --- a/src/java.desktop/share/classes/com/sun/media/sound/JSSecurityManager.java +++ b/src/java.desktop/share/classes/com/sun/media/sound/JSSecurityManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -112,7 +112,6 @@ final class JSSecurityManager { final boolean isDaemon, final int priority, final boolean doStart) { - String name = (threadName != null) ? threadName : "JSSM Thread"; Thread thread = new Thread(null, runnable, threadName, 0, false); thread.setDaemon(isDaemon); diff --git a/src/java.desktop/share/classes/com/sun/media/sound/JavaSoundAudioClip.java b/src/java.desktop/share/classes/com/sun/media/sound/JavaSoundAudioClip.java index bc2f87fe33f04797bbde82e52870dd0ea6e1d4dc..c804a0e49c225ff1a0b852c54479d9dd71d41df7 100644 --- a/src/java.desktop/share/classes/com/sun/media/sound/JavaSoundAudioClip.java +++ b/src/java.desktop/share/classes/com/sun/media/sound/JavaSoundAudioClip.java @@ -283,6 +283,7 @@ public final class JavaSoundAudioClip implements AudioClip, MetaEventListener, L } @Override + @SuppressWarnings("removal") protected void finalize() { if (clip != null) { diff --git a/src/java.desktop/share/classes/com/sun/media/sound/ModelByteBuffer.java b/src/java.desktop/share/classes/com/sun/media/sound/ModelByteBuffer.java index 13cbf54fe6d27708e6f45a5ac557c813f1454ccd..2476ff09bbcc7d18c816fd04b4c8670a7449c852 100644 --- a/src/java.desktop/share/classes/com/sun/media/sound/ModelByteBuffer.java +++ b/src/java.desktop/share/classes/com/sun/media/sound/ModelByteBuffer.java @@ -315,11 +315,13 @@ public final class ModelByteBuffer { "No file associated with this ByteBuffer!"); } - DataInputStream is = new DataInputStream(getInputStream()); - buffer = new byte[(int) capacity()]; - offset = 0; - is.readFully(buffer); - is.close(); + try (InputStream is = getInputStream(); + DataInputStream dis = new DataInputStream(is)) + { + buffer = new byte[(int) capacity()]; + offset = 0; + dis.readFully(buffer); + } } diff --git a/src/java.desktop/share/classes/com/sun/media/sound/ModelByteBufferWavetable.java b/src/java.desktop/share/classes/com/sun/media/sound/ModelByteBufferWavetable.java index 45fa29542117d0e2b470bd6327908c2a60060e50..bc8829d288c6fe7620d6190a831c2d8abf542290 100644 --- a/src/java.desktop/share/classes/com/sun/media/sound/ModelByteBufferWavetable.java +++ b/src/java.desktop/share/classes/com/sun/media/sound/ModelByteBufferWavetable.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 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 @@ -182,18 +182,12 @@ public final class ModelByteBufferWavetable implements ModelWavetable { if (format == null) { if (buffer == null) return null; - InputStream is = buffer.getInputStream(); AudioFormat format = null; - try { + try (InputStream is = buffer.getInputStream()) { format = AudioSystem.getAudioFileFormat(is).getFormat(); } catch (Exception e) { //e.printStackTrace(); } - try { - is.close(); - } catch (IOException e) { - //e.printStackTrace(); - } return format; } return format; diff --git a/src/java.desktop/share/classes/com/sun/media/sound/PortMixer.java b/src/java.desktop/share/classes/com/sun/media/sound/PortMixer.java index 5f2c24788d399a40953a3984248c506604ec3279..099067f3ad62ee9d54ce6ead5e42b67753e719fe 100644 --- a/src/java.desktop/share/classes/com/sun/media/sound/PortMixer.java +++ b/src/java.desktop/share/classes/com/sun/media/sound/PortMixer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 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 @@ -115,7 +115,7 @@ final class PortMixer extends AbstractMixer { public Line getLine(Line.Info info) throws LineUnavailableException { Line.Info fullInfo = getLineInfo(info); - if ((fullInfo != null) && (fullInfo instanceof Port.Info)) { + if (fullInfo instanceof Port.Info) { for (int i = 0; i < portInfos.length; i++) { if (fullInfo.equals(portInfos[i])) { return getPort(i); diff --git a/src/java.desktop/share/classes/com/sun/media/sound/RealTimeSequencer.java b/src/java.desktop/share/classes/com/sun/media/sound/RealTimeSequencer.java index b0239d33995553289ecf7f9f85d0e0a8b246a898..6fa6fa59c5cdf76d7909a4d8c898d67bfad949ce 100644 --- a/src/java.desktop/share/classes/com/sun/media/sound/RealTimeSequencer.java +++ b/src/java.desktop/share/classes/com/sun/media/sound/RealTimeSequencer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -1024,7 +1024,7 @@ final class RealTimeSequencer extends AbstractMidiDevice } } // class Info - private class ControllerListElement { + private static class ControllerListElement { // $$jb: using an array for controllers b/c its // easier to deal with than turning all the diff --git a/src/java.desktop/share/classes/com/sun/media/sound/SF2Soundbank.java b/src/java.desktop/share/classes/com/sun/media/sound/SF2Soundbank.java index ccade6b1a2e5abba6e3f49537b3888ea9d2e8176..831423664e69c68b14ad761a4a552be636876943 100644 --- a/src/java.desktop/share/classes/com/sun/media/sound/SF2Soundbank.java +++ b/src/java.desktop/share/classes/com/sun/media/sound/SF2Soundbank.java @@ -92,23 +92,16 @@ public final class SF2Soundbank implements Soundbank { } public SF2Soundbank(URL url) throws IOException { - - InputStream is = url.openStream(); - try { + try (InputStream is = url.openStream()) { readSoundbank(is); - } finally { - is.close(); } } public SF2Soundbank(File file) throws IOException { largeFormat = true; sampleFile = file; - InputStream is = new FileInputStream(file); - try { + try (InputStream is = new FileInputStream(file)) { readSoundbank(is); - } finally { - is.close(); } } @@ -517,22 +510,27 @@ public final class SF2Soundbank implements Soundbank { } public void save(String name) throws IOException { - writeSoundbank(new RIFFWriter(name, "sfbk")); + try (RIFFWriter writer = new RIFFWriter(name, "sfbk")) { + writeSoundbank(writer); + } } public void save(File file) throws IOException { - writeSoundbank(new RIFFWriter(file, "sfbk")); + try (RIFFWriter writer = new RIFFWriter(file, "sfbk")) { + writeSoundbank(writer); + } } public void save(OutputStream out) throws IOException { - writeSoundbank(new RIFFWriter(out, "sfbk")); + try (RIFFWriter writer = new RIFFWriter(out, "sfbk")) { + writeSoundbank(writer); + } } private void writeSoundbank(RIFFWriter writer) throws IOException { writeInfo(writer.writeList("INFO")); writeSdtaChunk(writer.writeList("sdta")); writePdtaChunk(writer.writeList("pdta")); - writer.close(); } private void writeInfoStringChunk(RIFFWriter writer, String name, diff --git a/src/java.desktop/share/classes/com/sun/media/sound/SoftMainMixer.java b/src/java.desktop/share/classes/com/sun/media/sound/SoftMainMixer.java index f603375f3b51d25de3201f16e58f72754f7e7367..34ebd3900ae443aeadeedd3f55039b396e2376b7 100644 --- a/src/java.desktop/share/classes/com/sun/media/sound/SoftMainMixer.java +++ b/src/java.desktop/share/classes/com/sun/media/sound/SoftMainMixer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 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 @@ -48,8 +48,7 @@ public final class SoftMainMixer { // A private class thats contains a ModelChannelMixer and it's private buffers. // This becomes necessary when we want to have separate delay buffers for each channel mixer. - private class SoftChannelMixerContainer - { + private static class SoftChannelMixerContainer { ModelChannelMixer mixer; SoftAudioBuffer[] buffers; } diff --git a/src/java.desktop/share/classes/com/sun/media/sound/SoftMixingDataLine.java b/src/java.desktop/share/classes/com/sun/media/sound/SoftMixingDataLine.java index 99962841c8fe117078ae628b8f9a4ee2b6e73b1d..4ba5e61487489a5de915cd97d43a95990d190fef 100644 --- a/src/java.desktop/share/classes/com/sun/media/sound/SoftMixingDataLine.java +++ b/src/java.desktop/share/classes/com/sun/media/sound/SoftMixingDataLine.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 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 @@ -102,8 +102,7 @@ public abstract class SoftMixingDataLine implements DataLine { format.getSampleRate(), sourceFormat.isBigEndian()); nrofchannels = targetFormat.getChannels(); Object interpolation = format.getProperty("interpolation"); - if (interpolation != null && (interpolation instanceof String)) { - String resamplerType = (String) interpolation; + if (interpolation instanceof String resamplerType) { if (resamplerType.equalsIgnoreCase("point")) this.resampler = new SoftPointResampler(); if (resamplerType.equalsIgnoreCase("linear")) diff --git a/src/java.desktop/share/classes/com/sun/media/sound/SoftSynthesizer.java b/src/java.desktop/share/classes/com/sun/media/sound/SoftSynthesizer.java index 9d73c68e6ade115101cbc63175f1f93d9cf3ad60..d614fbc10e5fb447e69e54a19d3537cf5e49c61c 100644 --- a/src/java.desktop/share/classes/com/sun/media/sound/SoftSynthesizer.java +++ b/src/java.desktop/share/classes/com/sun/media/sound/SoftSynthesizer.java @@ -574,25 +574,25 @@ public final class SoftSynthesizer implements AudioSynthesizer, @Override public boolean loadInstrument(Instrument instrument) { - if (instrument == null || (!(instrument instanceof ModelInstrument))) { + if (!(instrument instanceof ModelInstrument modelInstrument)) { throw new IllegalArgumentException("Unsupported instrument: " + instrument); } List instruments = new ArrayList<>(); - instruments.add((ModelInstrument)instrument); + instruments.add(modelInstrument); return loadInstruments(instruments); } @Override public void unloadInstrument(Instrument instrument) { - if (instrument == null || (!(instrument instanceof ModelInstrument))) { + if (!(instrument instanceof ModelInstrument modelInstrument)) { throw new IllegalArgumentException("Unsupported instrument: " + instrument); } if (!isOpen()) return; - String pat = patchToString(instrument.getPatch()); + String pat = patchToString(modelInstrument.getPatch()); synchronized (control_mutex) { for (SoftChannel c: channels) c.current_instrument = null; @@ -755,10 +755,8 @@ public final class SoftSynthesizer implements AudioSynthesizer, InputStream is = AccessController.doPrivileged(action); if(is == null) continue; Soundbank sbk; - try { + try (is) { sbk = MidiSystem.getSoundbank(new BufferedInputStream(is)); - } finally { - is.close(); } if (sbk != null) { defaultSoundBank = sbk; @@ -802,9 +800,8 @@ public final class SoftSynthesizer implements AudioSynthesizer, return null; }); if (out != null) { - try { + try (out) { ((SF2Soundbank) defaultSoundBank).save(out); - out.close(); } catch (final IOException ignored) { } } @@ -841,11 +838,11 @@ public final class SoftSynthesizer implements AudioSynthesizer, public boolean loadAllInstruments(Soundbank soundbank) { List instruments = new ArrayList<>(); for (Instrument ins: soundbank.getInstruments()) { - if (ins == null || !(ins instanceof ModelInstrument)) { + if (!(ins instanceof ModelInstrument modelInstrument)) { throw new IllegalArgumentException( "Unsupported instrument: " + ins); } - instruments.add((ModelInstrument)ins); + instruments.add(modelInstrument); } return loadInstruments(instruments); } @@ -870,11 +867,11 @@ public final class SoftSynthesizer implements AudioSynthesizer, List instruments = new ArrayList<>(); for (Patch patch: patchList) { Instrument ins = soundbank.getInstrument(patch); - if (ins == null || !(ins instanceof ModelInstrument)) { + if (!(ins instanceof ModelInstrument modelInstrument)) { throw new IllegalArgumentException( "Unsupported instrument: " + ins); } - instruments.add((ModelInstrument)ins); + instruments.add(modelInstrument); } return loadInstruments(instruments); } diff --git a/src/java.desktop/share/classes/com/sun/media/sound/StandardMidiFileReader.java b/src/java.desktop/share/classes/com/sun/media/sound/StandardMidiFileReader.java index e13bae6ce92d6c924be2076e64f3e05962aceaef..7303cb771756e8c11a27792433ee208751da1fb3 100644 --- a/src/java.desktop/share/classes/com/sun/media/sound/StandardMidiFileReader.java +++ b/src/java.desktop/share/classes/com/sun/media/sound/StandardMidiFileReader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -146,34 +146,27 @@ public final class StandardMidiFileReader extends MidiFileReader { @Override public MidiFileFormat getMidiFileFormat(URL url) throws InvalidMidiDataException, IOException { - InputStream urlStream = url.openStream(); // throws IOException - BufferedInputStream bis = new BufferedInputStream( urlStream, bisBufferSize ); - MidiFileFormat fileFormat = null; - try { - fileFormat = getMidiFileFormat( bis ); // throws InvalidMidiDataException - } finally { - bis.close(); + try (InputStream urlStream = url.openStream(); // throws IOException + BufferedInputStream bis = new BufferedInputStream(urlStream, bisBufferSize)) + { + MidiFileFormat fileFormat = getMidiFileFormat(bis); // throws InvalidMidiDataException + return fileFormat; } - return fileFormat; } @Override public MidiFileFormat getMidiFileFormat(File file) throws InvalidMidiDataException, IOException { - FileInputStream fis = new FileInputStream(file); // throws IOException - BufferedInputStream bis = new BufferedInputStream(fis, bisBufferSize); - - // $$fb 2002-04-17: part of fix for 4635286: MidiSystem.getMidiFileFormat() returns format having invalid length - long length = file.length(); - if (length > Integer.MAX_VALUE) { - length = MidiFileFormat.UNKNOWN_LENGTH; - } - MidiFileFormat fileFormat = null; - try { - fileFormat = getMidiFileFormatFromStream(bis, (int) length, null); - } finally { - bis.close(); + try (FileInputStream fis = new FileInputStream(file); // throws IOException + BufferedInputStream bis = new BufferedInputStream(fis, bisBufferSize)) + { + // $$fb 2002-04-17: part of fix for 4635286: MidiSystem.getMidiFileFormat() returns format having invalid length + long length = file.length(); + if (length > Integer.MAX_VALUE) { + length = MidiFileFormat.UNKNOWN_LENGTH; + } + MidiFileFormat fileFormat = getMidiFileFormatFromStream(bis, (int) length, null); + return fileFormat; } - return fileFormat; } @Override @@ -204,28 +197,22 @@ public final class StandardMidiFileReader extends MidiFileReader { @Override public Sequence getSequence(URL url) throws InvalidMidiDataException, IOException { - InputStream is = url.openStream(); // throws IOException - is = new BufferedInputStream(is, bisBufferSize); - Sequence seq = null; - try { - seq = getSequence(is); - } finally { - is.close(); + try (InputStream is = url.openStream(); // throws IOException + BufferedInputStream bis = new BufferedInputStream(is, bisBufferSize)) + { + Sequence seq = getSequence(bis); + return seq; } - return seq; } @Override public Sequence getSequence(File file) throws InvalidMidiDataException, IOException { - InputStream is = new FileInputStream(file); // throws IOException - is = new BufferedInputStream(is, bisBufferSize); - Sequence seq = null; - try { - seq = getSequence(is); - } finally { - is.close(); + try (InputStream is = new FileInputStream(file); // throws IOException + BufferedInputStream bis = new BufferedInputStream(is, bisBufferSize)) + { + Sequence seq = getSequence(bis); + return seq; } - return seq; } } @@ -392,6 +379,10 @@ final class SMFParser { // meta int metaType = readUnsigned(); int metaLength = (int) readVarInt(); + if (metaLength < 0) { + throw new InvalidMidiDataException("length out of bounds: " + + metaLength); + } final byte[] metaData; try { metaData = new byte[metaLength]; diff --git a/src/java.desktop/share/classes/com/sun/media/sound/StandardMidiFileWriter.java b/src/java.desktop/share/classes/com/sun/media/sound/StandardMidiFileWriter.java index a46a2e4e46783e6c0ba748d3e32cb26c5c96aac7..7d96bfaebfc3dade1f61ca449686a20e1bf72473 100644 --- a/src/java.desktop/share/classes/com/sun/media/sound/StandardMidiFileWriter.java +++ b/src/java.desktop/share/classes/com/sun/media/sound/StandardMidiFileWriter.java @@ -129,10 +129,10 @@ public final class StandardMidiFileWriter extends MidiFileWriter { @Override public int write(Sequence in, int type, File out) throws IOException { Objects.requireNonNull(in); - FileOutputStream fos = new FileOutputStream(out); // throws IOException - int bytesWritten = write( in, type, fos ); - fos.close(); - return bytesWritten; + try (FileOutputStream fos = new FileOutputStream(out)) { // throws IOException + int bytesWritten = write(in, type, fos); + return bytesWritten; + } } //================================================================================= diff --git a/src/java.desktop/share/classes/com/sun/media/sound/SunFileWriter.java b/src/java.desktop/share/classes/com/sun/media/sound/SunFileWriter.java index 538c547cef511772996f114e1c1e992ff0b19ad8..1d54bcfe91c0c60294c037f43c1827b2a40071ed 100644 --- a/src/java.desktop/share/classes/com/sun/media/sound/SunFileWriter.java +++ b/src/java.desktop/share/classes/com/sun/media/sound/SunFileWriter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -151,7 +151,7 @@ abstract class SunFileWriter extends AudioFileWriter { * The class is usefull for use with SequenceInputStream to prevent * closing of the source input streams. */ - final class NoCloseInputStream extends InputStream { + static final class NoCloseInputStream extends InputStream { private final InputStream in; NoCloseInputStream(InputStream in) { diff --git a/src/java.desktop/share/classes/com/sun/media/sound/WaveFloatFileReader.java b/src/java.desktop/share/classes/com/sun/media/sound/WaveFloatFileReader.java index 2c3be1507fc1c0d11fbd36ded942bf72304f19f2..f8365f7178080e6c1bac2e4361c8bdd50a36df80 100644 --- a/src/java.desktop/share/classes/com/sun/media/sound/WaveFloatFileReader.java +++ b/src/java.desktop/share/classes/com/sun/media/sound/WaveFloatFileReader.java @@ -73,6 +73,10 @@ public final class WaveFloatFileReader extends SunFileReader { samplerate = chunk.readUnsignedInt(); /* framerate = */chunk.readUnsignedInt(); framesize = chunk.readUnsignedShort(); + if (framesize == 0) { + throw new UnsupportedAudioFileException( + "Can not process audio format with 0 frame size"); + } bits = chunk.readUnsignedShort(); } if (chunk.getFormat().equals("data")) { diff --git a/src/java.desktop/share/classes/java/awt/AWTEvent.java b/src/java.desktop/share/classes/java/awt/AWTEvent.java index 404a4fb221ba88d51c39ca2e77d76cddf461bdab..93def2fadc9fdf69cdb05bd762341f9e769424d4 100644 --- a/src/java.desktop/share/classes/java/awt/AWTEvent.java +++ b/src/java.desktop/share/classes/java/awt/AWTEvent.java @@ -355,8 +355,7 @@ public abstract class AWTEvent extends EventObject { Component comp = null; if (newSource instanceof Component) { comp = (Component)newSource; - while (comp != null && comp.peer != null && - (comp.peer instanceof LightweightPeer)) { + while (comp != null && (comp.peer instanceof LightweightPeer)) { comp = comp.parent; } } diff --git a/src/java.desktop/share/classes/java/awt/AWTEventMulticaster.java b/src/java.desktop/share/classes/java/awt/AWTEventMulticaster.java index a9f102643f4b91ad39ac3dc7048c7fb075eac0b8..b7584fc84ddb91d79a12bb133a8e550b64e0a7aa 100644 --- a/src/java.desktop/share/classes/java/awt/AWTEventMulticaster.java +++ b/src/java.desktop/share/classes/java/awt/AWTEventMulticaster.java @@ -1097,9 +1097,9 @@ public class AWTEventMulticaster implements * FooListeners by the specified multicast * listener, or an empty array if no such listeners have been * chained by the specified multicast listener - * @exception NullPointerException if the specified + * @throws NullPointerException if the specified * {@code listenertype} parameter is {@code null} - * @exception ClassCastException if {@code listenerType} + * @throws ClassCastException if {@code listenerType} * doesn't specify a class or interface that implements * {@code java.util.EventListener} * diff --git a/src/java.desktop/share/classes/java/awt/BorderLayout.java b/src/java.desktop/share/classes/java/awt/BorderLayout.java index 88edc23dec4fae6f6c959d0a02a4af686162ffe5..e3b92a7996ae75e4e5ec4be21dd8ee3b3ecfd92a 100644 --- a/src/java.desktop/share/classes/java/awt/BorderLayout.java +++ b/src/java.desktop/share/classes/java/awt/BorderLayout.java @@ -419,7 +419,7 @@ public class BorderLayout implements LayoutManager2, * @param constraints an object that specifies how and where * the component is added to the layout. * @see java.awt.Container#add(java.awt.Component, java.lang.Object) - * @exception IllegalArgumentException if the constraint object is not + * @throws IllegalArgumentException if the constraint object is not * a string, or if it not one of the five specified constants. * @since 1.1 */ @@ -514,7 +514,7 @@ public class BorderLayout implements LayoutManager2, * {@code LINE_START}, {@code LINE_END} * @return the component at the given location, or {@code null} if * the location is empty - * @exception IllegalArgumentException if the constraint object is + * @throws IllegalArgumentException if the constraint object is * not one of the nine specified constants * @see #addLayoutComponent(java.awt.Component, java.lang.Object) * @since 1.5 @@ -562,9 +562,9 @@ public class BorderLayout implements LayoutManager2, * {@code Container}'s component orientation. * @return the component at the given location, or {@code null} if * the location is empty - * @exception IllegalArgumentException if the constraint object is + * @throws IllegalArgumentException if the constraint object is * not one of the five specified constants - * @exception NullPointerException if the target parameter is null + * @throws NullPointerException if the target parameter is null * @see #addLayoutComponent(java.awt.Component, java.lang.Object) * @since 1.5 */ diff --git a/src/java.desktop/share/classes/java/awt/BufferCapabilities.java b/src/java.desktop/share/classes/java/awt/BufferCapabilities.java index 18c3d725b369eda5ab3c13ec54a254e8a6bc4466..6edeae843aa45f50186c1e9a48ce6d5d10fd4fa7 100644 --- a/src/java.desktop/share/classes/java/awt/BufferCapabilities.java +++ b/src/java.desktop/share/classes/java/awt/BufferCapabilities.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -47,7 +47,7 @@ public class BufferCapabilities implements Cloneable { * cannot be {@code null} * @param flipContents the contents of the back buffer after page-flipping, * {@code null} if page flipping is not used (implies blitting) - * @exception IllegalArgumentException if frontCaps or backCaps are + * @throws IllegalArgumentException if frontCaps or backCaps are * {@code null} */ public BufferCapabilities(ImageCapabilities frontCaps, @@ -62,6 +62,8 @@ public class BufferCapabilities implements Cloneable { } /** + * Returns the image capabilities of the front (displayed) buffer. + * * @return the image capabilities of the front (displayed) buffer */ public ImageCapabilities getFrontBufferCapabilities() { @@ -69,6 +71,9 @@ public class BufferCapabilities implements Cloneable { } /** + * Returns the image capabilities of all back buffers (intermediate buffers + * are considered back buffers). + * * @return the image capabilities of all back buffers (intermediate buffers * are considered back buffers) */ @@ -77,27 +82,31 @@ public class BufferCapabilities implements Cloneable { } /** - * @return whether or not the buffer strategy uses page flipping; a set of - * buffers that uses page flipping + * Returns whether or not the buffer strategy uses page flipping. + * A set of buffers that uses page flipping * can swap the contents internally between the front buffer and one or * more back buffers by switching the video pointer (or by copying memory * internally). A non-flipping set of * buffers uses blitting to copy the contents from one buffer to * another; when this is the case, {@code getFlipContents} returns - * {@code null} + * {@code null}. + * + * @return whether or not the buffer strategy uses page flipping */ public boolean isPageFlipping() { return (getFlipContents() != null); } /** - * @return the resulting contents of the back buffer after page-flipping. + * Returns the resulting contents of the back buffer after page-flipping. * This value is {@code null} when the {@code isPageFlipping} * returns {@code false}, implying blitting. It can be one of * {@code FlipContents.UNDEFINED} * (the assumed default), {@code FlipContents.BACKGROUND}, * {@code FlipContents.PRIOR}, or * {@code FlipContents.COPIED}. + * + * @return the resulting contents of the back buffer after page-flipping * @see #isPageFlipping * @see FlipContents#UNDEFINED * @see FlipContents#BACKGROUND @@ -109,9 +118,11 @@ public class BufferCapabilities implements Cloneable { } /** - * @return whether page flipping is only available in full-screen mode. If this + * Returns whether page flipping is only available in full-screen mode. If this * is {@code true}, full-screen exclusive mode is required for * page-flipping. + * + * @return whether page flipping is only available in full-screen mode * @see #isPageFlipping * @see GraphicsDevice#setFullScreenWindow */ @@ -120,9 +131,12 @@ public class BufferCapabilities implements Cloneable { } /** - * @return whether or not + * Returns whether or not * page flipping can be performed using more than two buffers (one or more * intermediate buffers as well as the front and back buffer). + * + * @return whether or not + * page flipping can be performed using more than two buffers * @see #isPageFlipping */ public boolean isMultiBufferAvailable() { diff --git a/src/java.desktop/share/classes/java/awt/Button.java b/src/java.desktop/share/classes/java/awt/Button.java index 35acb8d292882f2dc5ba7229de975da7b9751aef..524008e401a6273dfab4fd582508419d21d7b2c8 100644 --- a/src/java.desktop/share/classes/java/awt/Button.java +++ b/src/java.desktop/share/classes/java/awt/Button.java @@ -140,7 +140,7 @@ public class Button extends Component implements Accessible { /** * Constructs a button with an empty string for its label. * - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true * @see java.awt.GraphicsEnvironment#isHeadless */ @@ -153,7 +153,7 @@ public class Button extends Component implements Accessible { * * @param label a string label for the button, or * {@code null} for no label - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true * @see java.awt.GraphicsEnvironment#isHeadless */ @@ -339,7 +339,7 @@ public class Button extends Component implements Accessible { * FooListeners on this button, * or an empty array if no such * listeners have been added - * @exception ClassCastException if {@code listenerType} + * @throws ClassCastException if {@code listenerType} * doesn't specify a class or interface that implements * {@code java.util.EventListener} * diff --git a/src/java.desktop/share/classes/java/awt/Canvas.java b/src/java.desktop/share/classes/java/awt/Canvas.java index 1ee5380c6df08be44d8fea8ff81cb8568ef26310..7d90e148b6c313a9be2d917f9075031e1284a171 100644 --- a/src/java.desktop/share/classes/java/awt/Canvas.java +++ b/src/java.desktop/share/classes/java/awt/Canvas.java @@ -166,8 +166,8 @@ public class Canvas extends Component implements Accessible { * Each time this method is called, * the existing buffer strategy for this component is discarded. * @param numBuffers number of buffers to create, including the front buffer - * @exception IllegalArgumentException if numBuffers is less than 1. - * @exception IllegalStateException if the component is not displayable + * @throws IllegalArgumentException if numBuffers is less than 1. + * @throws IllegalStateException if the component is not displayable * @see #isDisplayable * @see #getBufferStrategy * @since 1.4 @@ -187,11 +187,11 @@ public class Canvas extends Component implements Accessible { * @param numBuffers number of buffers to create * @param caps the required capabilities for creating the buffer strategy; * cannot be {@code null} - * @exception AWTException if the capabilities supplied could not be + * @throws AWTException if the capabilities supplied could not be * supported or met; this may happen, for example, if there is not enough * accelerated memory currently available, or if page flipping is specified * but not possible. - * @exception IllegalArgumentException if numBuffers is less than 1, or if + * @throws IllegalArgumentException if numBuffers is less than 1, or if * caps is {@code null} * @see #getBufferStrategy * @since 1.4 diff --git a/src/java.desktop/share/classes/java/awt/CardLayout.java b/src/java.desktop/share/classes/java/awt/CardLayout.java index f7ea3a0ba761ec405d9c9cb8ae5c0ed5a7bdfccb..915376d032095727f5ff440706fdbd81b4152201 100644 --- a/src/java.desktop/share/classes/java/awt/CardLayout.java +++ b/src/java.desktop/share/classes/java/awt/CardLayout.java @@ -74,7 +74,7 @@ public class CardLayout implements LayoutManager2, /** * A pair of component and string that represents its name. */ - class Card implements Serializable { + static class Card implements Serializable { /** * Use serialVersionUID from JDK 1.4 for interoperability. @@ -206,7 +206,7 @@ public class CardLayout implements LayoutManager2, * @param constraints a tag that identifies a particular * card in the layout. * @see java.awt.CardLayout#show(java.awt.Container, java.lang.String) - * @exception IllegalArgumentException if the constraint is not a string. + * @throws IllegalArgumentException if the constraint is not a string. */ public void addLayoutComponent(Component comp, Object constraints) { synchronized (comp.getTreeLock()) { diff --git a/src/java.desktop/share/classes/java/awt/Checkbox.java b/src/java.desktop/share/classes/java/awt/Checkbox.java index e72d249f8e31139b0903b5bb2aa1e99907600d7f..f4a642cb3297c13cd13a157058dc9f6c8bb8648b 100644 --- a/src/java.desktop/share/classes/java/awt/Checkbox.java +++ b/src/java.desktop/share/classes/java/awt/Checkbox.java @@ -146,7 +146,7 @@ public class Checkbox extends Component implements ItemSelectable, Accessible { * Creates a check box with an empty string for its label. * The state of this check box is set to "off," and it is not * part of any check box group. - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true * @see java.awt.GraphicsEnvironment#isHeadless */ @@ -161,7 +161,7 @@ public class Checkbox extends Component implements ItemSelectable, Accessible { * * @param label a string label for this check box, * or {@code null} for no label. - * @exception HeadlessException if + * @throws HeadlessException if * {@code GraphicsEnvironment.isHeadless} * returns {@code true} * @see java.awt.GraphicsEnvironment#isHeadless @@ -178,7 +178,7 @@ public class Checkbox extends Component implements ItemSelectable, Accessible { * @param label a string label for this check box, * or {@code null} for no label * @param state the initial state of this check box - * @exception HeadlessException if + * @throws HeadlessException if * {@code GraphicsEnvironment.isHeadless} * returns {@code true} * @see java.awt.GraphicsEnvironment#isHeadless @@ -196,7 +196,7 @@ public class Checkbox extends Component implements ItemSelectable, Accessible { * @param state the initial state of this check box. * @param group a check box group for this check box, * or {@code null} for no group. - * @exception HeadlessException if + * @throws HeadlessException if * {@code GraphicsEnvironment.isHeadless} * returns {@code true} * @see java.awt.GraphicsEnvironment#isHeadless @@ -222,7 +222,7 @@ public class Checkbox extends Component implements ItemSelectable, Accessible { * @param group a check box group for this check box, * or {@code null} for no group. * @param state the initial state of this check box. - * @exception HeadlessException if + * @throws HeadlessException if * {@code GraphicsEnvironment.isHeadless} * returns {@code true} * @see java.awt.GraphicsEnvironment#isHeadless @@ -508,7 +508,7 @@ public class Checkbox extends Component implements ItemSelectable, Accessible { * FooListeners on this checkbox, * or an empty array if no such * listeners have been added - * @exception ClassCastException if {@code listenerType} + * @throws ClassCastException if {@code listenerType} * doesn't specify a class or interface that implements * {@code java.util.EventListener} * diff --git a/src/java.desktop/share/classes/java/awt/CheckboxMenuItem.java b/src/java.desktop/share/classes/java/awt/CheckboxMenuItem.java index 4df4ddbef856a39e7d23566383f4ce2322b4edbe..f95d1d39424a7894b528aa3868b655df84e43871 100644 --- a/src/java.desktop/share/classes/java/awt/CheckboxMenuItem.java +++ b/src/java.desktop/share/classes/java/awt/CheckboxMenuItem.java @@ -110,7 +110,7 @@ public class CheckboxMenuItem extends MenuItem implements ItemSelectable, Access /** * Create a check box menu item with an empty label. * The item's state is initially set to "off." - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true * @see java.awt.GraphicsEnvironment#isHeadless * @since 1.1 @@ -125,7 +125,7 @@ public class CheckboxMenuItem extends MenuItem implements ItemSelectable, Access * @param label a string label for the check box menu item, * or {@code null} for an unlabeled menu item. - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true * @see java.awt.GraphicsEnvironment#isHeadless */ @@ -140,7 +140,7 @@ public class CheckboxMenuItem extends MenuItem implements ItemSelectable, Access * @param state the initial state of the menu item, where * {@code true} indicates "on" and * {@code false} indicates "off." - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true * @see java.awt.GraphicsEnvironment#isHeadless * @since 1.1 @@ -316,7 +316,7 @@ public class CheckboxMenuItem extends MenuItem implements ItemSelectable, Access * FooListeners on this checkbox menuitem, * or an empty array if no such * listeners have been added - * @exception ClassCastException if {@code listenerType} + * @throws ClassCastException if {@code listenerType} * doesn't specify a class or interface that implements * {@code java.util.EventListener} * diff --git a/src/java.desktop/share/classes/java/awt/Choice.java b/src/java.desktop/share/classes/java/awt/Choice.java index d8e8ab4c0267a44a96d98f0d7e4af6ddd3866e67..2b04239fd314c89a682d98675417b7efb3bdfa01 100644 --- a/src/java.desktop/share/classes/java/awt/Choice.java +++ b/src/java.desktop/share/classes/java/awt/Choice.java @@ -124,7 +124,7 @@ public class Choice extends Component implements ItemSelectable, Accessible { * By default, the first item added to the choice menu becomes the * selected item, until a different selection is made by the user * by calling one of the {@code select} methods. - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true * @see java.awt.GraphicsEnvironment#isHeadless * @see #select(int) @@ -205,7 +205,7 @@ public class Choice extends Component implements ItemSelectable, Accessible { /** * Adds an item to this {@code Choice} menu. * @param item the item to be added - * @exception NullPointerException if the item's value is + * @throws NullPointerException if the item's value is * {@code null} * @since 1.1 */ @@ -219,7 +219,7 @@ public class Choice extends Component implements ItemSelectable, Accessible { *

          * Adds an item to this {@code Choice} menu. * @param item the item to be added - * @exception NullPointerException if the item's value is equal to + * @throws NullPointerException if the item's value is equal to * {@code null} */ public void addItem(String item) { @@ -238,7 +238,7 @@ public class Choice extends Component implements ItemSelectable, Accessible { * invoking this method. * @param item the item to be added * @param index the new item position - * @exception NullPointerException if the item's value is equal to + * @throws NullPointerException if the item's value is equal to * {@code null} */ private void insertNoInvalidate(String item, int index) { @@ -274,7 +274,7 @@ public class Choice extends Component implements ItemSelectable, Accessible { * the selected item. * @param item the non-{@code null} item to be inserted * @param index the position at which the item should be inserted - * @exception IllegalArgumentException if index is less than 0 + * @throws IllegalArgumentException if index is less than 0 */ public void insert(String item, int index) { synchronized (this) { @@ -300,7 +300,7 @@ public class Choice extends Component implements ItemSelectable, Accessible { * item remains selected (and the selected index is * updated accordingly). * @param item the item to remove from this {@code Choice} menu - * @exception IllegalArgumentException if the item doesn't + * @throws IllegalArgumentException if the item doesn't * exist in the choice menu * @since 1.1 */ @@ -430,7 +430,7 @@ public class Choice extends Component implements ItemSelectable, Accessible { * {@code ItemEvent} is by user interaction. * * @param pos the position of the selected item - * @exception IllegalArgumentException if the specified + * @throws IllegalArgumentException if the specified * position is greater than the * number of items or less than zero * @see #getSelectedItem @@ -561,7 +561,7 @@ public class Choice extends Component implements ItemSelectable, Accessible { * FooListeners on this choice, * or an empty array if no such * listeners have been added - * @exception ClassCastException if {@code listenerType} + * @throws ClassCastException if {@code listenerType} * doesn't specify a class or interface that implements * {@code java.util.EventListener} * diff --git a/src/java.desktop/share/classes/java/awt/Color.java b/src/java.desktop/share/classes/java/awt/Color.java index aae90be8616dd0de749497032ef51dad7a4253ab..6bb4befd8e83c5eed52d4f98736c86d74c2b2109 100644 --- a/src/java.desktop/share/classes/java/awt/Color.java +++ b/src/java.desktop/share/classes/java/awt/Color.java @@ -722,7 +722,7 @@ public class Color implements Paint, java.io.Serializable { * an opaque color as a 24-bit integer * @return the new {@code Color} object. * @see java.lang.Integer#decode - * @exception NumberFormatException if the specified string cannot + * @throws NumberFormatException if the specified string cannot * be interpreted as a decimal, * octal, or hexadecimal integer. * @since 1.1 diff --git a/src/java.desktop/share/classes/java/awt/Component.java b/src/java.desktop/share/classes/java/awt/Component.java index ff522f5141a5ca64e5a36d7af6ee586ccfba9e9e..cfd4cbe025a25632f2c17b8fa318a8c2bb542ec3 100644 --- a/src/java.desktop/share/classes/java/awt/Component.java +++ b/src/java.desktop/share/classes/java/awt/Component.java @@ -1420,7 +1420,7 @@ public abstract class Component implements ImageObserver, MenuContainer, * pointer. If the return value of this method is {@code null}, mouse * pointer is not directly above the {@code Component}. * - * @exception HeadlessException if GraphicsEnvironment.isHeadless() returns true + * @throws HeadlessException if GraphicsEnvironment.isHeadless() returns true * @see #isShowing * @see Container#getMousePosition * @return mouse coordinates relative to this {@code Component}, or null @@ -1984,7 +1984,7 @@ public abstract class Component implements ImageObserver, MenuContainer, * @return this component's locale; if this component does not * have a locale, the locale of its parent is returned * @see #setLocale - * @exception IllegalComponentStateException if the {@code Component} + * @throws IllegalComponentStateException if the {@code Component} * does not have its own locale and has not yet been added to * a containment hierarchy such that the locale can be determined * from the containing parent @@ -3827,8 +3827,8 @@ public abstract class Component implements ImageObserver, MenuContainer, * Each time this method is called, * the existing buffer strategy for this component is discarded. * @param numBuffers number of buffers to create, including the front buffer - * @exception IllegalArgumentException if numBuffers is less than 1. - * @exception IllegalStateException if the component is not displayable + * @throws IllegalArgumentException if numBuffers is less than 1. + * @throws IllegalStateException if the component is not displayable * @see #isDisplayable * @see Window#getBufferStrategy() * @see Canvas#getBufferStrategy() @@ -3884,11 +3884,11 @@ public abstract class Component implements ImageObserver, MenuContainer, * @param numBuffers number of buffers to create * @param caps the required capabilities for creating the buffer strategy; * cannot be {@code null} - * @exception AWTException if the capabilities supplied could not be + * @throws AWTException if the capabilities supplied could not be * supported or met; this may happen, for example, if there is not enough * accelerated memory currently available, or if page flipping is specified * but not possible. - * @exception IllegalArgumentException if numBuffers is less than 1, or if + * @throws IllegalArgumentException if numBuffers is less than 1, or if * caps is {@code null} * @see Window#getBufferStrategy() * @see Canvas#getBufferStrategy() @@ -3931,7 +3931,7 @@ public abstract class Component implements ImageObserver, MenuContainer, * * @see sun.java2d.SunGraphicsEnvironment#isFlipStrategyPreferred(ComponentPeer) */ - private class ProxyCapabilities extends ExtendedBufferCapabilities { + private static class ProxyCapabilities extends ExtendedBufferCapabilities { private BufferCapabilities orig; private ProxyCapabilities(BufferCapabilities orig) { super(orig.getFrontBufferCapabilities(), @@ -4032,12 +4032,12 @@ public abstract class Component implements ImageObserver, MenuContainer, * @see Applet * @param numBuffers the number of buffers * @param caps the capabilities of the buffers - * @exception AWTException if the capabilities supplied could not be + * @throws AWTException if the capabilities supplied could not be * supported or met - * @exception ClassCastException if the component is not a canvas or + * @throws ClassCastException if the component is not a canvas or * window. - * @exception IllegalStateException if the component has no peer - * @exception IllegalArgumentException if {@code numBuffers} is less than two, + * @throws IllegalStateException if the component has no peer + * @throws IllegalArgumentException if {@code numBuffers} is less than two, * or if {@code BufferCapabilities.isPageFlipping} is not * {@code true}. * @see #createBuffers(int, BufferCapabilities) @@ -4066,10 +4066,10 @@ public abstract class Component implements ImageObserver, MenuContainer, * @param caps the capabilities of the buffers. * {@code BufferCapabilities.isPageFlipping} must be * {@code true}. - * @exception AWTException if the capabilities supplied could not be + * @throws AWTException if the capabilities supplied could not be * supported or met - * @exception IllegalStateException if the component has no peer - * @exception IllegalArgumentException if numBuffers is less than two, + * @throws IllegalStateException if the component has no peer + * @throws IllegalArgumentException if numBuffers is less than two, * or if {@code BufferCapabilities.isPageFlipping} is not * {@code true}. * @see java.awt.BufferCapabilities#isPageFlipping() @@ -4132,8 +4132,10 @@ public abstract class Component implements ImageObserver, MenuContainer, } /** - * @return direct access to the back buffer, as an image. - * @exception IllegalStateException if the buffers have not yet + * Provides direct access to the back buffer as an image. + * + * @return the back buffer as an image + * @throws IllegalStateException if the buffers have not yet * been created */ protected Image getBackBuffer() { @@ -4152,7 +4154,7 @@ public abstract class Component implements ImageObserver, MenuContainer, * for the contents of the back buffer. This should be one of the * values of the {@code BufferCapabilities.FlipContents} * property. - * @exception IllegalStateException if the buffers have not yet + * @throws IllegalStateException if the buffers have not yet * been created * @see java.awt.BufferCapabilities#getFlipContents() */ @@ -4692,9 +4694,12 @@ public abstract class Component implements ImageObserver, MenuContainer, } /** - * @return whether or not paint messages received from the operating system + * Returns whether or not paint messages received from the operating system * should be ignored. * + * @return whether or not paint messages received from the operating system + * should be ignored + * * @since 1.4 * @see #setIgnoreRepaint */ @@ -4944,8 +4949,8 @@ public abstract class Component implements ImageObserver, MenuContainer, // the active/passive/peered clients loose focus. if (id == FocusEvent.FOCUS_GAINED) { InputContext inputContext = getInputContext(); - if (inputContext != null && inputContext instanceof sun.awt.im.InputContext) { - ((sun.awt.im.InputContext)inputContext).disableNativeIM(); + if (inputContext instanceof sun.awt.im.InputContext ctx) { + ctx.disableNativeIM(); } } } @@ -6055,7 +6060,7 @@ public abstract class Component implements ImageObserver, MenuContainer, * @return an array of all objects registered as * FooListeners on this component, * or an empty array if no such listeners have been added - * @exception ClassCastException if {@code listenerType} + * @throws ClassCastException if {@code listenerType} * doesn't specify a class or interface that implements * {@code java.util.EventListener} * @throws NullPointerException if {@code listenerType} is {@code null} @@ -8347,7 +8352,7 @@ public abstract class Component implements ImageObserver, MenuContainer, * Adds the specified popup menu to the component. * @param popup the popup menu to be added to the component. * @see #remove(MenuComponent) - * @exception NullPointerException if {@code popup} is {@code null} + * @throws NullPointerException if {@code popup} is {@code null} * @since 1.1 */ public void add(PopupMenu popup) { @@ -9187,7 +9192,7 @@ public abstract class Component implements ImageObserver, MenuContainer, * * @param orientation the new component orientation of this component and * the components contained within it. - * @exception NullPointerException if {@code orientation} is null. + * @throws NullPointerException if {@code orientation} is null. * @see #setComponentOrientation * @see #getComponentOrientation * @see #invalidate diff --git a/src/java.desktop/share/classes/java/awt/Container.java b/src/java.desktop/share/classes/java/awt/Container.java index 68270d35adae69e00ca9043e2d5fa06a86abdc38..f63c507a829abdcf04069e02d6bb9e4bba3de2c6 100644 --- a/src/java.desktop/share/classes/java/awt/Container.java +++ b/src/java.desktop/share/classes/java/awt/Container.java @@ -340,7 +340,7 @@ public class Container extends Component { * * @param n the index of the component to get. * @return the nth component in this container. - * @exception ArrayIndexOutOfBoundsException + * @throws ArrayIndexOutOfBoundsException * if the nth value does not exist. * @see Component#getTreeLock() */ @@ -429,7 +429,7 @@ public class Container extends Component { * display the added component. * * @param comp the component to be added - * @exception NullPointerException if {@code comp} is {@code null} + * @throws NullPointerException if {@code comp} is {@code null} * @see #addImpl * @see #invalidate * @see #validate @@ -456,7 +456,7 @@ public class Container extends Component { * @param name the name of the component to be added * @param comp the component to be added * @return the component added - * @exception NullPointerException if {@code comp} is {@code null} + * @throws NullPointerException if {@code comp} is {@code null} * @see #add(Component, Object) * @see #invalidate */ @@ -479,8 +479,8 @@ public class Container extends Component { * @param comp the component to be added * @param index the position at which to insert the component, * or {@code -1} to append the component to the end - * @exception NullPointerException if {@code comp} is {@code null} - * @exception IllegalArgumentException if {@code index} is invalid (see + * @throws NullPointerException if {@code comp} is {@code null} + * @throws IllegalArgumentException if {@code index} is invalid (see * {@link #addImpl} for details) * @return the component {@code comp} * @see #addImpl @@ -764,17 +764,17 @@ public class Container extends Component { * @param index the position in the container's list to * insert the component, where {@code getComponentCount()} * appends to the end - * @exception NullPointerException if {@code comp} is + * @throws NullPointerException if {@code comp} is * {@code null} - * @exception IllegalArgumentException if {@code comp} is one of the + * @throws IllegalArgumentException if {@code comp} is one of the * container's parents - * @exception IllegalArgumentException if {@code index} is not in + * @throws IllegalArgumentException if {@code index} is not in * the range {@code [0, getComponentCount()]} for moving * between containers, or not in the range * {@code [0, getComponentCount()-1]} for moving inside * a container - * @exception IllegalArgumentException if adding a container to itself - * @exception IllegalArgumentException if adding a {@code Window} + * @throws IllegalArgumentException if adding a container to itself + * @throws IllegalArgumentException if adding a {@code Window} * to a container * @see #getComponentZOrder(java.awt.Component) * @see #invalidate @@ -989,7 +989,7 @@ public class Container extends Component { * @param comp the component to be added * @param constraints an object expressing * layout constraints for this component - * @exception NullPointerException if {@code comp} is {@code null} + * @throws NullPointerException if {@code comp} is {@code null} * @see #addImpl * @see #invalidate * @see #validate @@ -1019,8 +1019,8 @@ public class Container extends Component { * @param index the position in the container's list at which to insert * the component; {@code -1} means insert at the end * component - * @exception NullPointerException if {@code comp} is {@code null} - * @exception IllegalArgumentException if {@code index} is invalid (see + * @throws NullPointerException if {@code comp} is {@code null} + * @throws IllegalArgumentException if {@code index} is invalid (see * {@link #addImpl} for details) * @see #addImpl * @see #invalidate @@ -1082,16 +1082,16 @@ public class Container extends Component { * @param index the position in the container's list at which to * insert the component, where {@code -1} * means append to the end - * @exception IllegalArgumentException if {@code index} is invalid; + * @throws IllegalArgumentException if {@code index} is invalid; * if {@code comp} is a child of this container, the valid * range is {@code [-1, getComponentCount()-1]}; if component is * not a child of this container, the valid range is * {@code [-1, getComponentCount()]} * - * @exception IllegalArgumentException if {@code comp} is an ancestor of + * @throws IllegalArgumentException if {@code comp} is an ancestor of * this container - * @exception IllegalArgumentException if adding a window to a container - * @exception NullPointerException if {@code comp} is {@code null} + * @throws IllegalArgumentException if adding a window to a container + * @throws NullPointerException if {@code comp} is {@code null} * @see #add(Component) * @see #add(Component, int) * @see #add(Component, java.lang.Object) @@ -2213,10 +2213,10 @@ public class Container extends Component { * @return an array of all objects registered as * FooListeners on this container, * or an empty array if no such listeners have been added - * @exception ClassCastException if {@code listenerType} + * @throws ClassCastException if {@code listenerType} * doesn't specify a class or interface that implements * {@code java.util.EventListener} - * @exception NullPointerException if {@code listenerType} is {@code null} + * @throws NullPointerException if {@code listenerType} is {@code null} * * @see #getContainerListeners * @@ -2622,7 +2622,7 @@ public class Container extends Component { * a non-null value if the mouse pointer is above {@code Container} or any * of its descendants. * - * @exception HeadlessException if GraphicsEnvironment.isHeadless() returns true + * @throws HeadlessException if GraphicsEnvironment.isHeadless() returns true * @param allowChildren true if children should be taken into account * @see Component#getMousePosition * @return mouse coordinates relative to this {@code Component}, or null @@ -3556,7 +3556,7 @@ public class Container extends Component { * * @param o the new component orientation of this container and * the components contained within it. - * @exception NullPointerException if {@code orientation} is null. + * @throws NullPointerException if {@code orientation} is null. * @see Component#setComponentOrientation * @see Component#getComponentOrientation * @see #invalidate @@ -3891,18 +3891,18 @@ public class Container extends Component { public void componentAdded(ContainerEvent e) { Component c = e.getChild(); - if (c != null && c instanceof Accessible) { + if (c instanceof Accessible accessible) { AccessibleAWTContainer.this.firePropertyChange( AccessibleContext.ACCESSIBLE_CHILD_PROPERTY, - null, ((Accessible) c).getAccessibleContext()); + null, accessible.getAccessibleContext()); } } public void componentRemoved(ContainerEvent e) { Component c = e.getChild(); - if (c != null && c instanceof Accessible) { + if (c instanceof Accessible accessible) { AccessibleAWTContainer.this.firePropertyChange( AccessibleContext.ACCESSIBLE_CHILD_PROPERTY, - ((Accessible) c).getAccessibleContext(), null); + accessible.getAccessibleContext(), null); } } } diff --git a/src/java.desktop/share/classes/java/awt/Cursor.java b/src/java.desktop/share/classes/java/awt/Cursor.java index 936d17da46f6e2f8dc4f53485ddacbf51133f53c..cfccf06723becd6a24be72fb99cde1a7142ee1b8 100644 --- a/src/java.desktop/share/classes/java/awt/Cursor.java +++ b/src/java.desktop/share/classes/java/awt/Cursor.java @@ -285,9 +285,9 @@ public class Cursor implements java.io.Serializable { * * @param name a string describing the desired system-specific custom cursor * @return the system specific custom cursor named - * @exception HeadlessException if + * @throws HeadlessException if * {@code GraphicsEnvironment.isHeadless} returns true - * @exception AWTException in case of erroneous retrieving of the cursor + * @throws AWTException in case of erroneous retrieving of the cursor */ public static Cursor getSystemCustomCursor(final String name) throws AWTException, HeadlessException { diff --git a/src/java.desktop/share/classes/java/awt/Dialog.java b/src/java.desktop/share/classes/java/awt/Dialog.java index 1a54d70730697ca0aeff76ff75ea0f8c37ad9c1c..2c126e74ffc80b22fe657dbdac1c8b91b52af483 100644 --- a/src/java.desktop/share/classes/java/awt/Dialog.java +++ b/src/java.desktop/share/classes/java/awt/Dialog.java @@ -329,9 +329,9 @@ public class Dialog extends Window { * * @param owner the owner of the dialog or {@code null} if * this dialog has no owner - * @exception java.lang.IllegalArgumentException if the {@code owner}'s + * @throws java.lang.IllegalArgumentException if the {@code owner}'s * {@code GraphicsConfiguration} is not from a screen device - * @exception HeadlessException when + * @throws HeadlessException when * {@code GraphicsEnvironment.isHeadless()} returns {@code true} * * @see java.awt.GraphicsEnvironment#isHeadless @@ -352,9 +352,9 @@ public class Dialog extends Window { * windows when shown. If {@code false}, the dialog is {@code MODELESS}; * if {@code true}, the modality type property is set to * {@code DEFAULT_MODALITY_TYPE} - * @exception java.lang.IllegalArgumentException if the {@code owner}'s + * @throws java.lang.IllegalArgumentException if the {@code owner}'s * {@code GraphicsConfiguration} is not from a screen device - * @exception HeadlessException when + * @throws HeadlessException when * {@code GraphicsEnvironment.isHeadless()} returns {@code true} * * @see java.awt.Dialog.ModalityType @@ -376,9 +376,9 @@ public class Dialog extends Window { * this dialog has no owner * @param title the title of the dialog or {@code null} if this dialog * has no title - * @exception IllegalArgumentException if the {@code owner}'s + * @throws IllegalArgumentException if the {@code owner}'s * {@code GraphicsConfiguration} is not from a screen device - * @exception HeadlessException when + * @throws HeadlessException when * {@code GraphicsEnvironment.isHeadless()} returns {@code true} * * @see java.awt.GraphicsEnvironment#isHeadless @@ -401,9 +401,9 @@ public class Dialog extends Window { * windows when shown. If {@code false}, the dialog is {@code MODELESS}; * if {@code true}, the modality type property is set to * {@code DEFAULT_MODALITY_TYPE} - * @exception java.lang.IllegalArgumentException if the {@code owner}'s + * @throws java.lang.IllegalArgumentException if the {@code owner}'s * {@code GraphicsConfiguration} is not from a screen device - * @exception HeadlessException when + * @throws HeadlessException when * {@code GraphicsEnvironment.isHeadless()} returns {@code true} * * @see java.awt.Dialog.ModalityType @@ -433,9 +433,9 @@ public class Dialog extends Window { * @param gc the {@code GraphicsConfiguration} of the target screen device; * if {@code null}, the default system {@code GraphicsConfiguration} * is assumed - * @exception java.lang.IllegalArgumentException if {@code gc} + * @throws java.lang.IllegalArgumentException if {@code gc} * is not from a screen device - * @exception HeadlessException when + * @throws HeadlessException when * {@code GraphicsEnvironment.isHeadless()} returns {@code true} * * @see java.awt.Dialog.ModalityType @@ -459,9 +459,9 @@ public class Dialog extends Window { * * @param owner the owner of the dialog or {@code null} if this * dialog has no owner - * @exception java.lang.IllegalArgumentException if the {@code owner}'s + * @throws java.lang.IllegalArgumentException if the {@code owner}'s * {@code GraphicsConfiguration} is not from a screen device - * @exception HeadlessException when + * @throws HeadlessException when * {@code GraphicsEnvironment.isHeadless()} returns {@code true} * @see java.awt.GraphicsEnvironment#isHeadless * @since 1.2 @@ -478,9 +478,9 @@ public class Dialog extends Window { * has no owner * @param title the title of the dialog or {@code null} if this dialog * has no title - * @exception java.lang.IllegalArgumentException if the {@code owner}'s + * @throws java.lang.IllegalArgumentException if the {@code owner}'s * {@code GraphicsConfiguration} is not from a screen device - * @exception HeadlessException when + * @throws HeadlessException when * {@code GraphicsEnvironment.isHeadless()} returns {@code true} * * @see java.awt.GraphicsEnvironment#isHeadless @@ -502,9 +502,9 @@ public class Dialog extends Window { * windows when shown. If {@code false}, the dialog is {@code MODELESS}; * if {@code true}, the modality type property is set to * {@code DEFAULT_MODALITY_TYPE} - * @exception IllegalArgumentException if the {@code owner}'s + * @throws IllegalArgumentException if the {@code owner}'s * {@code GraphicsConfiguration} is not from a screen device - * @exception HeadlessException when + * @throws HeadlessException when * {@code GraphicsEnvironment.isHeadless()} returns {@code true} * * @see java.awt.Dialog.ModalityType @@ -536,9 +536,9 @@ public class Dialog extends Window { * @param gc the {@code GraphicsConfiguration} of the target screen device; * if {@code null}, the default system {@code GraphicsConfiguration} * is assumed - * @exception java.lang.IllegalArgumentException if {@code gc} + * @throws java.lang.IllegalArgumentException if {@code gc} * is not from a screen device - * @exception HeadlessException when + * @throws HeadlessException when * {@code GraphicsEnvironment.isHeadless()} returns {@code true} * * @see java.awt.Dialog.ModalityType @@ -565,12 +565,12 @@ public class Dialog extends Window { * {@link java.awt.Dialog Dialog}, {@link java.awt.Frame Frame}, any * of their descendants or {@code null} * - * @exception java.lang.IllegalArgumentException if the {@code owner} + * @throws java.lang.IllegalArgumentException if the {@code owner} * is not an instance of {@link java.awt.Dialog Dialog} or {@link * java.awt.Frame Frame} - * @exception java.lang.IllegalArgumentException if the {@code owner}'s + * @throws java.lang.IllegalArgumentException if the {@code owner}'s * {@code GraphicsConfiguration} is not from a screen device - * @exception HeadlessException when + * @throws HeadlessException when * {@code GraphicsEnvironment.isHeadless()} returns {@code true} * * @see java.awt.GraphicsEnvironment#isHeadless @@ -591,12 +591,12 @@ public class Dialog extends Window { * @param title the title of the dialog or {@code null} if this dialog * has no title * - * @exception java.lang.IllegalArgumentException if the {@code owner} + * @throws java.lang.IllegalArgumentException if the {@code owner} * is not an instance of {@link java.awt.Dialog Dialog} or {@link * java.awt.Frame Frame} - * @exception java.lang.IllegalArgumentException if the {@code owner}'s + * @throws java.lang.IllegalArgumentException if the {@code owner}'s * {@code GraphicsConfiguration} is not from a screen device - * @exception HeadlessException when + * @throws HeadlessException when * {@code GraphicsEnvironment.isHeadless()} returns {@code true} * * @see java.awt.GraphicsEnvironment#isHeadless @@ -618,14 +618,14 @@ public class Dialog extends Window { * windows when shown. {@code null} value and unsupported modality * types are equivalent to {@code MODELESS} * - * @exception java.lang.IllegalArgumentException if the {@code owner} + * @throws java.lang.IllegalArgumentException if the {@code owner} * is not an instance of {@link java.awt.Dialog Dialog} or {@link * java.awt.Frame Frame} - * @exception java.lang.IllegalArgumentException if the {@code owner}'s + * @throws java.lang.IllegalArgumentException if the {@code owner}'s * {@code GraphicsConfiguration} is not from a screen device - * @exception HeadlessException when + * @throws HeadlessException when * {@code GraphicsEnvironment.isHeadless()} returns {@code true} - * @exception SecurityException if the calling thread does not have permission + * @throws SecurityException if the calling thread does not have permission * to create modal dialogs with the given {@code modalityType} * * @see java.awt.Dialog.ModalityType @@ -653,14 +653,14 @@ public class Dialog extends Window { * windows when shown. {@code null} value and unsupported modality * types are equivalent to {@code MODELESS} * - * @exception java.lang.IllegalArgumentException if the {@code owner} + * @throws java.lang.IllegalArgumentException if the {@code owner} * is not an instance of {@link java.awt.Dialog Dialog} or {@link * java.awt.Frame Frame} - * @exception java.lang.IllegalArgumentException if the {@code owner}'s + * @throws java.lang.IllegalArgumentException if the {@code owner}'s * {@code GraphicsConfiguration} is not from a screen device - * @exception HeadlessException when + * @throws HeadlessException when * {@code GraphicsEnvironment.isHeadless()} returns {@code true} - * @exception SecurityException if the calling thread does not have permission + * @throws SecurityException if the calling thread does not have permission * to create modal dialogs with the given {@code modalityType} * * @see java.awt.Dialog.ModalityType @@ -704,14 +704,14 @@ public class Dialog extends Window { * if {@code null}, the default system {@code GraphicsConfiguration} * is assumed * - * @exception java.lang.IllegalArgumentException if the {@code owner} + * @throws java.lang.IllegalArgumentException if the {@code owner} * is not an instance of {@link java.awt.Dialog Dialog} or {@link * java.awt.Frame Frame} - * @exception java.lang.IllegalArgumentException if {@code gc} + * @throws java.lang.IllegalArgumentException if {@code gc} * is not from a screen device - * @exception HeadlessException when + * @throws HeadlessException when * {@code GraphicsEnvironment.isHeadless()} returns {@code true} - * @exception SecurityException if the calling thread does not have permission + * @throws SecurityException if the calling thread does not have permission * to create modal dialogs with the given {@code modalityType} * * @see java.awt.Dialog.ModalityType @@ -848,7 +848,7 @@ public class Dialog extends Window { * @param type specifies whether dialog blocks input to other * windows when shown. {@code null} value and unsupported modality * types are equivalent to {@code MODELESS} - * @exception SecurityException if the calling thread does not have permission + * @throws SecurityException if the calling thread does not have permission * to create modal dialogs with the given {@code modalityType} * * @see java.awt.Dialog#getModalityType diff --git a/src/java.desktop/share/classes/java/awt/EventQueue.java b/src/java.desktop/share/classes/java/awt/EventQueue.java index e7d1dcc82863c1c536ee3c5679f9486c73eefaec..4dce257f7278f47a563748d12dc14ab683457a74 100644 --- a/src/java.desktop/share/classes/java/awt/EventQueue.java +++ b/src/java.desktop/share/classes/java/awt/EventQueue.java @@ -544,7 +544,7 @@ public class EventQueue { * returns it. This method will block until an event has * been posted by another thread. * @return the next {@code AWTEvent} - * @exception InterruptedException + * @throws InterruptedException * if any thread has interrupted this thread */ public AWTEvent getNextEvent() throws InterruptedException { @@ -946,7 +946,7 @@ public class EventQueue { * Warning: To avoid deadlock, do not declare this method * synchronized in a subclass. * - * @exception EmptyStackException if no previous push was made + * @throws EmptyStackException if no previous push was made * on this {@code EventQueue} * @see java.awt.EventQueue#push * @since 1.2 @@ -1331,9 +1331,9 @@ public class EventQueue { * synchronously in the * {@link #isDispatchThread event dispatch thread} * of {@link Toolkit#getSystemEventQueue the system EventQueue} - * @exception InterruptedException if any thread has + * @throws InterruptedException if any thread has * interrupted this thread - * @exception InvocationTargetException if an throwable is thrown + * @throws InvocationTargetException if an throwable is thrown * when running {@code runnable} * @see #invokeLater * @see Toolkit#getSystemEventQueue diff --git a/src/java.desktop/share/classes/java/awt/FileDialog.java b/src/java.desktop/share/classes/java/awt/FileDialog.java index b6a501b44e96b7c73f690c063989b590b64a1d9a..399544b954789ccb0100be92e08542a177c51c6b 100644 --- a/src/java.desktop/share/classes/java/awt/FileDialog.java +++ b/src/java.desktop/share/classes/java/awt/FileDialog.java @@ -232,7 +232,7 @@ public class FileDialog extends Dialog { * @param title the title of the dialog * @param mode the mode of the dialog; either * {@code FileDialog.LOAD} or {@code FileDialog.SAVE} - * @exception IllegalArgumentException if an illegal file + * @throws IllegalArgumentException if an illegal file * dialog mode is supplied * @see java.awt.FileDialog#LOAD * @see java.awt.FileDialog#SAVE @@ -255,10 +255,10 @@ public class FileDialog extends Dialog { * displayed. * * @param parent the owner of the dialog - * @exception java.lang.IllegalArgumentException if the {@code parent}'s + * @throws java.lang.IllegalArgumentException if the {@code parent}'s * {@code GraphicsConfiguration} * is not from a screen device; - * @exception java.lang.IllegalArgumentException if {@code parent} + * @throws java.lang.IllegalArgumentException if {@code parent} * is {@code null}; this exception is always thrown when * {@code GraphicsEnvironment.isHeadless} * returns {@code true} @@ -285,10 +285,10 @@ public class FileDialog extends Dialog { * @param title the title of the dialog; a {@code null} value * will be accepted without causing a * {@code NullPointerException} to be thrown - * @exception java.lang.IllegalArgumentException if the {@code parent}'s + * @throws java.lang.IllegalArgumentException if the {@code parent}'s * {@code GraphicsConfiguration} * is not from a screen device; - * @exception java.lang.IllegalArgumentException if {@code parent} + * @throws java.lang.IllegalArgumentException if {@code parent} * is {@code null}; this exception is always thrown when * {@code GraphicsEnvironment.isHeadless} * returns {@code true} @@ -321,12 +321,12 @@ public class FileDialog extends Dialog { * {@code NullPointerException} to be thrown * @param mode the mode of the dialog; either * {@code FileDialog.LOAD} or {@code FileDialog.SAVE} - * @exception java.lang.IllegalArgumentException if an illegal + * @throws java.lang.IllegalArgumentException if an illegal * file dialog mode is supplied; - * @exception java.lang.IllegalArgumentException if the {@code parent}'s + * @throws java.lang.IllegalArgumentException if the {@code parent}'s * {@code GraphicsConfiguration} * is not from a screen device; - * @exception java.lang.IllegalArgumentException if {@code parent} + * @throws java.lang.IllegalArgumentException if {@code parent} * is {@code null}; this exception is always thrown when * {@code GraphicsEnvironment.isHeadless} * returns {@code true} @@ -408,7 +408,7 @@ public class FileDialog extends Dialog { * @see java.awt.FileDialog#LOAD * @see java.awt.FileDialog#SAVE * @see java.awt.FileDialog#getMode - * @exception IllegalArgumentException if an illegal file + * @throws IllegalArgumentException if an illegal file * dialog mode is supplied * @since 1.1 */ diff --git a/src/java.desktop/share/classes/java/awt/Font.java b/src/java.desktop/share/classes/java/awt/Font.java index 95087864d2a0e9bc663c86228055bfbd83a68d72..020bd95b3b37c95b45dd37535491384a525f9ba3 100644 --- a/src/java.desktop/share/classes/java/awt/Font.java +++ b/src/java.desktop/share/classes/java/awt/Font.java @@ -1131,7 +1131,7 @@ public class Font implements java.io.Serializable if (tracker != null) { tracker.set(tFile, outStream); } - try { + try (outStream) { /* don't close the input stream */ byte[] buf = new byte[8192]; for (;;) { int bytesRead = fontStream.read(buf); @@ -1152,9 +1152,6 @@ public class Font implements java.io.Serializable } outStream.write(buf, 0, bytesRead); } - /* don't close the input stream */ - } finally { - outStream.close(); } /* After all references to a Font2D are dropped, the file * will be removed. To support long-lived AppContexts, diff --git a/src/java.desktop/share/classes/java/awt/Frame.java b/src/java.desktop/share/classes/java/awt/Frame.java index 6dde9373c38714974047be58de9212643f82961f..e01ef082d4229865c0c964723719621ceb99f1cc 100644 --- a/src/java.desktop/share/classes/java/awt/Frame.java +++ b/src/java.desktop/share/classes/java/awt/Frame.java @@ -383,7 +383,7 @@ public class Frame extends Window implements MenuContainer { * Constructs a new instance of {@code Frame} that is * initially invisible. The title of the {@code Frame} * is empty. - * @exception HeadlessException when + * @throws HeadlessException when * {@code GraphicsEnvironment.isHeadless()} returns {@code true} * @see java.awt.GraphicsEnvironment#isHeadless() * @see Component#setSize @@ -401,9 +401,9 @@ public class Frame extends Window implements MenuContainer { * of the target screen device. If {@code gc} * is {@code null}, the system default * {@code GraphicsConfiguration} is assumed. - * @exception IllegalArgumentException if + * @throws IllegalArgumentException if * {@code gc} is not from a screen device. - * @exception HeadlessException when + * @throws HeadlessException when * {@code GraphicsEnvironment.isHeadless()} returns {@code true} * @see java.awt.GraphicsEnvironment#isHeadless() * @since 1.3 @@ -418,7 +418,7 @@ public class Frame extends Window implements MenuContainer { * @param title the title to be displayed in the frame's border. * A {@code null} value * is treated as an empty string, "". - * @exception HeadlessException when + * @throws HeadlessException when * {@code GraphicsEnvironment.isHeadless()} returns {@code true} * @see java.awt.GraphicsEnvironment#isHeadless() * @see java.awt.Component#setSize @@ -440,9 +440,9 @@ public class Frame extends Window implements MenuContainer { * of the target screen device. If {@code gc} is * {@code null}, the system default * {@code GraphicsConfiguration} is assumed. - * @exception IllegalArgumentException if {@code gc} + * @throws IllegalArgumentException if {@code gc} * is not from a screen device. - * @exception HeadlessException when + * @throws HeadlessException when * {@code GraphicsEnvironment.isHeadless()} returns {@code true} * @see java.awt.GraphicsEnvironment#isHeadless() * @see java.awt.Component#setSize diff --git a/src/java.desktop/share/classes/java/awt/Graphics.java b/src/java.desktop/share/classes/java/awt/Graphics.java index 51cdd6a88da30d1f732fb09f58d621897c5e8d28..5ed31aeadb0565e5d14cbf539843c07f0d4ac1d8 100644 --- a/src/java.desktop/share/classes/java/awt/Graphics.java +++ b/src/java.desktop/share/classes/java/awt/Graphics.java @@ -1162,17 +1162,14 @@ public abstract class Graphics { /** * Disposes of this graphics context once it is no longer referenced. * - * @deprecated The {@code finalize} method has been deprecated. - * Subclasses that override {@code finalize} in order to perform cleanup - * should be modified to use alternative cleanup mechanisms and - * to remove the overriding {@code finalize} method. - * When overriding the {@code finalize} method, its implementation must explicitly - * ensure that {@code super.finalize()} is invoked as described in {@link Object#finalize}. - * See the specification for {@link Object#finalize()} for further - * information about migration options. + * @deprecated Finalization has been deprecated for removal. See + * {@link java.lang.Object#finalize} for background information and details + * about migration options. + * * @see #dispose */ - @Deprecated(since="9") + @Deprecated(since="9", forRemoval=true) + @SuppressWarnings("removal") public void finalize() { dispose(); } diff --git a/src/java.desktop/share/classes/java/awt/GraphicsConfiguration.java b/src/java.desktop/share/classes/java/awt/GraphicsConfiguration.java index b698f0f3706d1e08fd328073e4b7ced0f1c3a57f..58d502ac03f47f57a06db6eab39a36ae4c06d706 100644 --- a/src/java.desktop/share/classes/java/awt/GraphicsConfiguration.java +++ b/src/java.desktop/share/classes/java/awt/GraphicsConfiguration.java @@ -261,7 +261,7 @@ public abstract class GraphicsConfiguration { * @param width the width of the returned {@code VolatileImage} * @param height the height of the returned {@code VolatileImage} * @param caps the image capabilities - * @exception AWTException if the supplied image capabilities could not + * @throws AWTException if the supplied image capabilities could not * be met by this graphics configuration * @since 1.4 */ @@ -294,7 +294,7 @@ public abstract class GraphicsConfiguration { * @see Transparency#BITMASK * @see Transparency#TRANSLUCENT * @throws IllegalArgumentException if the transparency is not a valid value - * @exception AWTException if the supplied image capabilities could not + * @throws AWTException if the supplied image capabilities could not * be met by this graphics configuration * @see Component#createVolatileImage(int, int) * @since 1.5 diff --git a/src/java.desktop/share/classes/java/awt/GraphicsDevice.java b/src/java.desktop/share/classes/java/awt/GraphicsDevice.java index d878f610fca9a9d8bc1bcd9e29a81c21ea84254f..c08c5580ae73fc388bc8d67f8e90a697e37b3d86 100644 --- a/src/java.desktop/share/classes/java/awt/GraphicsDevice.java +++ b/src/java.desktop/share/classes/java/awt/GraphicsDevice.java @@ -418,10 +418,10 @@ public abstract class GraphicsDevice { * * * @param dm The new display mode of this graphics device. - * @exception IllegalArgumentException if the {@code DisplayMode} + * @throws IllegalArgumentException if the {@code DisplayMode} * supplied is {@code null}, or is not available in the array returned * by {@code getDisplayModes} - * @exception UnsupportedOperationException if + * @throws UnsupportedOperationException if * {@code isDisplayChangeSupported} returns {@code false} * @see #getDisplayMode * @see #getDisplayModes diff --git a/src/java.desktop/share/classes/java/awt/GraphicsEnvironment.java b/src/java.desktop/share/classes/java/awt/GraphicsEnvironment.java index 438f9f399a0471c2c57d4b11090d212fcf943ad7..79102059b0ef782bf30290a7be8d3af8c25a9593 100644 --- a/src/java.desktop/share/classes/java/awt/GraphicsEnvironment.java +++ b/src/java.desktop/share/classes/java/awt/GraphicsEnvironment.java @@ -191,7 +191,7 @@ public abstract class GraphicsEnvironment { * objects. * @return an array containing all the {@code GraphicsDevice} * objects that represent screen devices - * @exception HeadlessException if isHeadless() returns true + * @throws HeadlessException if isHeadless() returns true * @see #isHeadless() */ public abstract GraphicsDevice[] getScreenDevices() @@ -201,7 +201,7 @@ public abstract class GraphicsEnvironment { * Returns the default screen {@code GraphicsDevice}. * @return the {@code GraphicsDevice} that represents the * default screen device - * @exception HeadlessException if isHeadless() returns true + * @throws HeadlessException if isHeadless() returns true * @see #isHeadless() */ public abstract GraphicsDevice getDefaultScreenDevice() @@ -383,7 +383,7 @@ public abstract class GraphicsEnvironment { * within the available display area using getMaximumWindowBounds(). * @return the point where Windows should be centered * - * @exception HeadlessException if isHeadless() returns true + * @throws HeadlessException if isHeadless() returns true * @see #getMaximumWindowBounds * @since 1.4 */ @@ -409,7 +409,7 @@ public abstract class GraphicsEnvironment { * {@code Toolkit.getScreenInsets()}. * @return the maximum bounds for centered Windows * - * @exception HeadlessException if isHeadless() returns true + * @throws HeadlessException if isHeadless() returns true * @see #getCenterPoint * @see GraphicsConfiguration#getBounds * @see Toolkit#getScreenInsets diff --git a/src/java.desktop/share/classes/java/awt/GridBagLayout.java b/src/java.desktop/share/classes/java/awt/GridBagLayout.java index ff3bec8b1153e36fe2db7d0021452ce0354f3c17..e0692ac0624bb5990201b4fd8745f0973b24c101 100644 --- a/src/java.desktop/share/classes/java/awt/GridBagLayout.java +++ b/src/java.desktop/share/classes/java/awt/GridBagLayout.java @@ -688,7 +688,7 @@ java.io.Serializable { * @param comp the component to be added * @param constraints an object that determines how * the component is added to the layout - * @exception IllegalArgumentException if {@code constraints} + * @throws IllegalArgumentException if {@code constraints} * is not a {@code GridBagConstraint} */ public void addLayoutComponent(Component comp, Object constraints) { diff --git a/src/java.desktop/share/classes/java/awt/GridLayout.java b/src/java.desktop/share/classes/java/awt/GridLayout.java index 4a3b66f4332e86c243260761106a083200453d5e..5c9265bc91214d8d0ca2fa3b977741985dcc3cac 100644 --- a/src/java.desktop/share/classes/java/awt/GridLayout.java +++ b/src/java.desktop/share/classes/java/awt/GridLayout.java @@ -186,7 +186,7 @@ public class GridLayout implements LayoutManager, java.io.Serializable { * any number of columns * @param hgap the horizontal gap * @param vgap the vertical gap - * @exception IllegalArgumentException if the value of both + * @throws IllegalArgumentException if the value of both * {@code rows} and {@code cols} is * set to zero */ @@ -212,7 +212,7 @@ public class GridLayout implements LayoutManager, java.io.Serializable { /** * Sets the number of rows in this layout to the specified value. * @param rows the number of rows in this layout - * @exception IllegalArgumentException if the value of both + * @throws IllegalArgumentException if the value of both * {@code rows} and {@code cols} is set to zero * @since 1.1 */ @@ -240,7 +240,7 @@ public class GridLayout implements LayoutManager, java.io.Serializable { * of columns displayed in the layout is determined by the total * number of components and the number of rows specified. * @param cols the number of columns in this layout - * @exception IllegalArgumentException if the value of both + * @throws IllegalArgumentException if the value of both * {@code rows} and {@code cols} is set to zero * @since 1.1 */ diff --git a/src/java.desktop/share/classes/java/awt/Image.java b/src/java.desktop/share/classes/java/awt/Image.java index 7e6273232694a0a3e6f5ecb14b6956316a81329d..1ad4ec9226f07c4549ea001fde8e02f4a31cf96f 100644 --- a/src/java.desktop/share/classes/java/awt/Image.java +++ b/src/java.desktop/share/classes/java/awt/Image.java @@ -105,7 +105,7 @@ public abstract class Image { * Creates a graphics context for drawing to an off-screen image. * This method can only be called for off-screen images. * @return a graphics context to draw to the off-screen image. - * @exception UnsupportedOperationException if called for a + * @throws UnsupportedOperationException if called for a * non-off-screen image. * @see java.awt.Graphics * @see java.awt.Component#createImage(int, int) @@ -162,7 +162,7 @@ public abstract class Image { * @param hints flags to indicate the type of algorithm to use * for image resampling. * @return a scaled version of the image. - * @exception IllegalArgumentException if {@code width} + * @throws IllegalArgumentException if {@code width} * or {@code height} is zero. * @see java.awt.Image#SCALE_DEFAULT * @see java.awt.Image#SCALE_FAST diff --git a/src/java.desktop/share/classes/java/awt/Label.java b/src/java.desktop/share/classes/java/awt/Label.java index b061efb51700631abef5c58954a7234bcbb1609d..ad8ff4c2b828c17c8bf93ec041ca5fd2a8ed7c28 100644 --- a/src/java.desktop/share/classes/java/awt/Label.java +++ b/src/java.desktop/share/classes/java/awt/Label.java @@ -114,7 +114,7 @@ public class Label extends Component implements Accessible { /** * Constructs an empty label. * The text of the label is the empty string {@code ""}. - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true. * @see java.awt.GraphicsEnvironment#isHeadless */ @@ -129,7 +129,7 @@ public class Label extends Component implements Accessible { * A {@code null} value * will be accepted without causing a NullPointerException * to be thrown. - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true. * @see java.awt.GraphicsEnvironment#isHeadless */ @@ -147,7 +147,7 @@ public class Label extends Component implements Accessible { * will be accepted without causing a NullPointerException * to be thrown. * @param alignment the alignment value. - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true. * @see java.awt.GraphicsEnvironment#isHeadless */ @@ -216,7 +216,7 @@ public class Label extends Component implements Accessible { * Possible values are {@code Label.LEFT}, * {@code Label.RIGHT}, and {@code Label.CENTER}. * @param alignment the alignment to be set. - * @exception IllegalArgumentException if an improper value for + * @throws IllegalArgumentException if an improper value for * {@code alignment} is given. * @see java.awt.Label#getAlignment */ diff --git a/src/java.desktop/share/classes/java/awt/List.java b/src/java.desktop/share/classes/java/awt/List.java index 3877fcd3b3dba01866bfb16f88c6ba810c6aa3d5..fe1a5dc5530434058afe64baa62341928b30b851 100644 --- a/src/java.desktop/share/classes/java/awt/List.java +++ b/src/java.desktop/share/classes/java/awt/List.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 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 @@ -193,7 +193,7 @@ public class List extends Component implements ItemSelectable, Accessible { * not allowed. Note that this is a convenience method for * {@code List(0, false)}. Also note that the number of visible * lines in the list cannot be changed after it has been created. - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true. * @see java.awt.GraphicsEnvironment#isHeadless */ @@ -209,7 +209,7 @@ public class List extends Component implements ItemSelectable, Accessible { * of visible rows in the list cannot be changed after it has * been created. * @param rows the number of items to show. - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true. * @see java.awt.GraphicsEnvironment#isHeadless * @since 1.1 @@ -238,7 +238,7 @@ public class List extends Component implements ItemSelectable, Accessible { * @param multipleMode if {@code true}, * then multiple selections are allowed; * otherwise, only one item can be selected at a time. - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true. * @see java.awt.GraphicsEnvironment#isHeadless */ @@ -411,7 +411,7 @@ public class List extends Component implements ItemSelectable, Accessible { * with the new string. * @param newValue a new string to replace an existing item * @param index the position of the item to replace - * @exception ArrayIndexOutOfBoundsException if {@code index} + * @throws ArrayIndexOutOfBoundsException if {@code index} * is out of range */ public synchronized void replaceItem(String newValue, int index) { @@ -448,7 +448,7 @@ public class List extends Component implements ItemSelectable, Accessible { * If the specified item is selected, and is the only selected * item in the list, the list is set to have no selection. * @param item the item to remove from the list - * @exception IllegalArgumentException + * @throws IllegalArgumentException * if the item doesn't exist in the list * @since 1.1 */ @@ -470,7 +470,7 @@ public class List extends Component implements ItemSelectable, Accessible { * @param position the index of the item to delete * @see #add(String, int) * @since 1.1 - * @exception ArrayIndexOutOfBoundsException + * @throws ArrayIndexOutOfBoundsException * if the {@code position} is less than 0 or * greater than {@code getItemCount()-1} */ @@ -1053,7 +1053,7 @@ public class List extends Component implements ItemSelectable, Accessible { * FooListeners on this list, * or an empty array if no such * listeners have been added - * @exception ClassCastException if {@code listenerType} + * @throws ClassCastException if {@code listenerType} * doesn't specify a class or interface that implements * {@code java.util.EventListener} * @@ -1631,7 +1631,7 @@ public class List extends Component implements ItemSelectable, Accessible { * @return This component's locale. If this component does not have * a locale, the locale of its parent is returned. * - * @exception IllegalComponentStateException + * @throws IllegalComponentStateException * If the Component does not have its own locale and has not yet * been added to a containment hierarchy such that the locale can * be determined from the containing parent. @@ -1750,7 +1750,7 @@ public class List extends Component implements ItemSelectable, Accessible { /** * Get the Font of this object. * - * @return the Font,if supported, for the object; otherwise, null + * @return the Font, if supported, for the object; otherwise, null * @see #setFont */ public Font getFont() { diff --git a/src/java.desktop/share/classes/java/awt/MediaTracker.java b/src/java.desktop/share/classes/java/awt/MediaTracker.java index e2b754c40afd3b2c55469b7a8d6be8e74739ded3..37e372d0d1f6b521031f1090ff4e5ade3e8dbbc6 100644 --- a/src/java.desktop/share/classes/java/awt/MediaTracker.java +++ b/src/java.desktop/share/classes/java/awt/MediaTracker.java @@ -396,7 +396,7 @@ public class MediaTracker implements java.io.Serializable { * @see java.awt.MediaTracker#waitForAll(long) * @see java.awt.MediaTracker#isErrorAny * @see java.awt.MediaTracker#isErrorID - * @exception InterruptedException if any thread has + * @throws InterruptedException if any thread has * interrupted this thread */ public void waitForAll() throws InterruptedException { @@ -421,7 +421,7 @@ public class MediaTracker implements java.io.Serializable { * @see java.awt.MediaTracker#waitForAll(long) * @see java.awt.MediaTracker#isErrorAny * @see java.awt.MediaTracker#isErrorID - * @exception InterruptedException if any thread has + * @throws InterruptedException if any thread has * interrupted this thread. */ public synchronized boolean waitForAll(long ms) @@ -627,7 +627,7 @@ public class MediaTracker implements java.io.Serializable { * @see java.awt.MediaTracker#waitForAll * @see java.awt.MediaTracker#isErrorAny() * @see java.awt.MediaTracker#isErrorID(int) - * @exception InterruptedException if any thread has + * @throws InterruptedException if any thread has * interrupted this thread. */ public void waitForID(int id) throws InterruptedException { @@ -655,7 +655,7 @@ public class MediaTracker implements java.io.Serializable { * @see java.awt.MediaTracker#statusID * @see java.awt.MediaTracker#isErrorAny() * @see java.awt.MediaTracker#isErrorID(int) - * @exception InterruptedException if any thread has + * @throws InterruptedException if any thread has * interrupted this thread. */ public synchronized boolean waitForID(int id, long ms) diff --git a/src/java.desktop/share/classes/java/awt/Menu.java b/src/java.desktop/share/classes/java/awt/Menu.java index 5f24c7cb8bdd8e72965b41d1b1c0c0660e79b279..79c3dfe0d82dd6c417d76d76ae9aac0c9c9cad50 100644 --- a/src/java.desktop/share/classes/java/awt/Menu.java +++ b/src/java.desktop/share/classes/java/awt/Menu.java @@ -125,7 +125,7 @@ public class Menu extends MenuItem implements MenuContainer, Accessible { /** * Constructs a new menu with an empty label. This menu is not * a tear-off menu. - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true. * @see java.awt.GraphicsEnvironment#isHeadless * @since 1.1 @@ -139,7 +139,7 @@ public class Menu extends MenuItem implements MenuContainer, Accessible { * a tear-off menu. * @param label the menu's label in the menu bar, or in * another menu of which this menu is a submenu. - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true. * @see java.awt.GraphicsEnvironment#isHeadless */ @@ -158,7 +158,7 @@ public class Menu extends MenuItem implements MenuContainer, Accessible { * another menu of which this menu is a submenu. * @param tearOff if {@code true}, the menu * is a tear-off menu. - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true. * @see java.awt.GraphicsEnvironment#isHeadless */ @@ -313,7 +313,7 @@ public class Menu extends MenuItem implements MenuContainer, Accessible { * item should be inserted. * @see java.awt.Menu#add(java.lang.String) * @see java.awt.Menu#add(java.awt.MenuItem) - * @exception IllegalArgumentException if the value of + * @throws IllegalArgumentException if the value of * {@code index} is less than zero * @since 1.1 */ @@ -357,7 +357,7 @@ public class Menu extends MenuItem implements MenuContainer, Accessible { * should be inserted * @see java.awt.Menu#add(java.lang.String) * @see java.awt.Menu#add(java.awt.MenuItem) - * @exception IllegalArgumentException if the value of + * @throws IllegalArgumentException if the value of * {@code index} is less than zero * @since 1.1 */ @@ -378,7 +378,7 @@ public class Menu extends MenuItem implements MenuContainer, Accessible { * Inserts a separator at the specified position. * @param index the position at which the * menu separator should be inserted. - * @exception IllegalArgumentException if the value of + * @throws IllegalArgumentException if the value of * {@code index} is less than 0. * @see java.awt.Menu#addSeparator * @since 1.1 diff --git a/src/java.desktop/share/classes/java/awt/MenuBar.java b/src/java.desktop/share/classes/java/awt/MenuBar.java index 2f78371407aa67869ba076feef67d778b8daa374..c1016f5bd0b2f15236438dcefcf05c24ea129046 100644 --- a/src/java.desktop/share/classes/java/awt/MenuBar.java +++ b/src/java.desktop/share/classes/java/awt/MenuBar.java @@ -127,7 +127,7 @@ public class MenuBar extends MenuComponent implements MenuContainer, Accessible /** * Creates a new menu bar. - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true. * @see java.awt.GraphicsEnvironment#isHeadless */ diff --git a/src/java.desktop/share/classes/java/awt/MenuComponent.java b/src/java.desktop/share/classes/java/awt/MenuComponent.java index e66b5867b239825f45f8b788edbb223e9689aca9..a2d28fb9e3e3d606eeb306586d2b117616b42bdf 100644 --- a/src/java.desktop/share/classes/java/awt/MenuComponent.java +++ b/src/java.desktop/share/classes/java/awt/MenuComponent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 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 @@ -176,7 +176,7 @@ public abstract class MenuComponent implements java.io.Serializable { /** * Creates a {@code MenuComponent}. - * @exception HeadlessException if + * @throws HeadlessException if * {@code GraphicsEnvironment.isHeadless} * returns {@code true} * @see java.awt.GraphicsEnvironment#isHeadless @@ -373,8 +373,7 @@ public abstract class MenuComponent implements java.io.Serializable { Toolkit.getDefaultToolkit().notifyAWTEventListeners(e); if (newEventsOnly || - (parent != null && parent instanceof MenuComponent && - ((MenuComponent)parent).newEventsOnly)) { + (parent instanceof MenuComponent mc && mc.newEventsOnly)) { if (eventEnabled(e)) { processEvent(e); } else if (e instanceof ActionEvent && parent != null) { @@ -743,7 +742,7 @@ public abstract class MenuComponent implements java.io.Serializable { /** * Gets the {@code Font} of this object. * - * @return the {@code Font},if supported, for the object; + * @return the {@code Font}, if supported, for the object; * otherwise, {@code null} */ public Font getFont() { diff --git a/src/java.desktop/share/classes/java/awt/MenuItem.java b/src/java.desktop/share/classes/java/awt/MenuItem.java index d1f6f59aa156bb4b8e8dd91af3ab53db11011fd6..adc37db7111a4c76fc0591ccccebe62677f5a84e 100644 --- a/src/java.desktop/share/classes/java/awt/MenuItem.java +++ b/src/java.desktop/share/classes/java/awt/MenuItem.java @@ -185,7 +185,7 @@ public class MenuItem extends MenuComponent implements Accessible { /** * Constructs a new MenuItem with an empty label and no keyboard * shortcut. - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true. * @see java.awt.GraphicsEnvironment#isHeadless * @since 1.1 @@ -201,7 +201,7 @@ public class MenuItem extends MenuComponent implements Accessible { * menu items. By default, all menu items except for * separators are enabled. * @param label the label for this menu item. - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true. * @see java.awt.GraphicsEnvironment#isHeadless * @since 1.0 @@ -218,7 +218,7 @@ public class MenuItem extends MenuComponent implements Accessible { * @param label the label for this menu item. * @param s the instance of {@code MenuShortcut} * associated with this menu item. - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true. * @see java.awt.GraphicsEnvironment#isHeadless * @since 1.1 @@ -616,7 +616,7 @@ public class MenuItem extends MenuComponent implements Accessible { * FooListeners on this menu item, * or an empty array if no such * listeners have been added - * @exception ClassCastException if {@code listenerType} + * @throws ClassCastException if {@code listenerType} * doesn't specify a class or interface that implements * {@code java.util.EventListener} * diff --git a/src/java.desktop/share/classes/java/awt/MouseInfo.java b/src/java.desktop/share/classes/java/awt/MouseInfo.java index 76b5ed6e39747b28de073524f6fa325f359dcaf3..3dd115e0724f98719e910cfa96df52efb0fd0794 100644 --- a/src/java.desktop/share/classes/java/awt/MouseInfo.java +++ b/src/java.desktop/share/classes/java/awt/MouseInfo.java @@ -62,8 +62,8 @@ public class MouseInfo { * permission before creating and returning a {@code PointerInfo} * object. This may result in a {@code SecurityException}. * - * @exception HeadlessException if GraphicsEnvironment.isHeadless() returns true - * @exception SecurityException if a security manager exists and its + * @throws HeadlessException if GraphicsEnvironment.isHeadless() returns true + * @throws SecurityException if a security manager exists and its * {@code checkPermission} method doesn't allow the operation * @see GraphicsConfiguration * @see SecurityManager#checkPermission @@ -124,7 +124,7 @@ public class MouseInfo { * by requesting the {@code "awt.mouse.numButtons"} desktop property * which is set by the underlying native platform. * - * @exception HeadlessException if GraphicsEnvironment.isHeadless() returns true + * @throws HeadlessException if GraphicsEnvironment.isHeadless() returns true * @return number of buttons on the mouse * @see Toolkit#getDesktopProperty * @since 1.5 diff --git a/src/java.desktop/share/classes/java/awt/Polygon.java b/src/java.desktop/share/classes/java/awt/Polygon.java index ed6f24a91c24998e3b6c96f111cb525b0097fa61..e74ce5cb10faae4c97860a9495d15eb761e0fb1d 100644 --- a/src/java.desktop/share/classes/java/awt/Polygon.java +++ b/src/java.desktop/share/classes/java/awt/Polygon.java @@ -139,12 +139,12 @@ public class Polygon implements Shape, java.io.Serializable { * @param ypoints an array of Y coordinates * @param npoints the total number of points in the * {@code Polygon} - * @exception NegativeArraySizeException if the value of + * @throws NegativeArraySizeException if the value of * {@code npoints} is negative. - * @exception IndexOutOfBoundsException if {@code npoints} is + * @throws IndexOutOfBoundsException if {@code npoints} is * greater than the length of {@code xpoints} * or the length of {@code ypoints}. - * @exception NullPointerException if {@code xpoints} or + * @throws NullPointerException if {@code xpoints} or * {@code ypoints} is {@code null}. * @since 1.0 */ @@ -575,7 +575,7 @@ public class Polygon implements Shape, java.io.Serializable { return getPathIterator(at); } - class PolygonPathIterator implements PathIterator { + static class PolygonPathIterator implements PathIterator { Polygon poly; AffineTransform transform; int index; diff --git a/src/java.desktop/share/classes/java/awt/PopupMenu.java b/src/java.desktop/share/classes/java/awt/PopupMenu.java index fd56461df555ce617b7bfbea82c1cae85afe33d5..e9b88d2a12f4b2c4cf64b34b3cc0cd70243fa7d2 100644 --- a/src/java.desktop/share/classes/java/awt/PopupMenu.java +++ b/src/java.desktop/share/classes/java/awt/PopupMenu.java @@ -69,7 +69,7 @@ public class PopupMenu extends Menu { /** * Creates a new popup menu with an empty name. - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true. * @see java.awt.GraphicsEnvironment#isHeadless */ @@ -82,7 +82,7 @@ public class PopupMenu extends Menu { * * @param label a non-{@code null} string specifying * the popup menu's label - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true. * @see java.awt.GraphicsEnvironment#isHeadless */ @@ -149,12 +149,12 @@ public class PopupMenu extends Menu { * @param origin the component which defines the coordinate space * @param x the x coordinate position to popup the menu * @param y the y coordinate position to popup the menu - * @exception NullPointerException if the parent is {@code null} - * @exception IllegalArgumentException if this {@code PopupMenu} + * @throws NullPointerException if the parent is {@code null} + * @throws IllegalArgumentException if this {@code PopupMenu} * has a non-{@code Component} parent - * @exception IllegalArgumentException if the origin is not in the + * @throws IllegalArgumentException if the origin is not in the * parent's hierarchy - * @exception RuntimeException if the parent is not showing on screen + * @throws RuntimeException if the parent is not showing on screen */ @SuppressWarnings("deprecation") public void show(Component origin, int x, int y) { diff --git a/src/java.desktop/share/classes/java/awt/PrintJob.java b/src/java.desktop/share/classes/java/awt/PrintJob.java index a9e2bd8bea29aa1fb9eabf8962117548349e17e8..f4ea24efd97b383dd3d054320c8db8de5259f5a4 100644 --- a/src/java.desktop/share/classes/java/awt/PrintJob.java +++ b/src/java.desktop/share/classes/java/awt/PrintJob.java @@ -85,17 +85,14 @@ public abstract class PrintJob { /** * Ends this print job once it is no longer referenced. * - * @deprecated The {@code finalize} method has been deprecated. - * Subclasses that override {@code finalize} in order to perform cleanup - * should be modified to use alternative cleanup mechanisms and - * to remove the overriding {@code finalize} method. - * When overriding the {@code finalize} method, its implementation must explicitly - * ensure that {@code super.finalize()} is invoked as described in {@link Object#finalize}. - * See the specification for {@link Object#finalize()} for further - * information about migration options. + * @deprecated Finalization has been deprecated for removal. See + * {@link java.lang.Object#finalize} for background information and details + * about migration options. + * * @see #end */ - @Deprecated(since="9") + @Deprecated(since="9", forRemoval=true) + @SuppressWarnings("removal") public void finalize() { end(); } diff --git a/src/java.desktop/share/classes/java/awt/RenderingHints.java b/src/java.desktop/share/classes/java/awt/RenderingHints.java index d69ed339eee1cd108cca05bc2b3b589aeb33712b..46d2fda103198c9bac6138a6d4c1470f006078d1 100644 --- a/src/java.desktop/share/classes/java/awt/RenderingHints.java +++ b/src/java.desktop/share/classes/java/awt/RenderingHints.java @@ -1064,7 +1064,7 @@ public class RenderingHints * {@code RenderingHints} is to be tested. * @return {@code true} if this {@code RenderingHints} * contains a mapping for the specified key. - * @exception ClassCastException if the key can not + * @throws ClassCastException if the key can not * be cast to {@code RenderingHints.Key} */ public boolean containsKey(Object key) { @@ -1099,7 +1099,7 @@ public class RenderingHints * @return the value to which the key is mapped in this object or * {@code null} if the key is not mapped to any value in * this object. - * @exception ClassCastException if the key can not + * @throws ClassCastException if the key can not * be cast to {@code RenderingHints.Key} * @see #put(Object, Object) */ @@ -1117,11 +1117,11 @@ public class RenderingHints * @param value the rendering hint value. * @return the previous value of the specified key in this object * or {@code null} if it did not have one. - * @exception NullPointerException if the key is + * @throws NullPointerException if the key is * {@code null}. - * @exception ClassCastException if the key can not + * @throws ClassCastException if the key can not * be cast to {@code RenderingHints.Key} - * @exception IllegalArgumentException if the + * @throws IllegalArgumentException if the * {@link Key#isCompatibleValue(java.lang.Object) * Key.isCompatibleValue()} * method of the specified key returns false for the @@ -1163,7 +1163,7 @@ public class RenderingHints * {@code RenderingHints} object. This method does nothing if the * key is not in this {@code RenderingHints} object. * @param key the rendering hints key that needs to be removed - * @exception ClassCastException if the key can not + * @throws ClassCastException if the key can not * be cast to {@code RenderingHints.Key} * @return the value to which the key had previously been mapped in this * {@code RenderingHints} object, or {@code null} @@ -1179,10 +1179,10 @@ public class RenderingHints * any mappings that this {@code RenderingHints} had for any * of the keys currently in the specified {@code Map}. * @param m the specified {@code Map} - * @exception ClassCastException class of a key or value + * @throws ClassCastException class of a key or value * in the specified {@code Map} prevents it from being * stored in this {@code RenderingHints}. - * @exception IllegalArgumentException some aspect + * @throws IllegalArgumentException some aspect * of a key or value in the specified {@code Map} * prevents it from being stored in * this {@code RenderingHints}. diff --git a/src/java.desktop/share/classes/java/awt/ScrollPane.java b/src/java.desktop/share/classes/java/awt/ScrollPane.java index 05ffe6130f8c793fe27fcedea2b3c3f8c410c777..2b51bb671a34880089dcb52a29672158d8a1a156 100644 --- a/src/java.desktop/share/classes/java/awt/ScrollPane.java +++ b/src/java.desktop/share/classes/java/awt/ScrollPane.java @@ -740,8 +740,7 @@ public class ScrollPane extends Container implements Accessible { /** * Invoked when the value of the adjustable has changed. */ - class PeerFixer implements AdjustmentListener, java.io.Serializable - { + static class PeerFixer implements AdjustmentListener, java.io.Serializable { /** * Use serialVersionUID from JDK 1.1.1 for interoperability. */ diff --git a/src/java.desktop/share/classes/java/awt/Scrollbar.java b/src/java.desktop/share/classes/java/awt/Scrollbar.java index 34cd3ecc79934186f15fa998ac8895e2fa9352ad..c8f100cc1c28f35e4ffbe1d6898e754bf3a9db99 100644 --- a/src/java.desktop/share/classes/java/awt/Scrollbar.java +++ b/src/java.desktop/share/classes/java/awt/Scrollbar.java @@ -349,7 +349,7 @@ public class Scrollbar extends Component implements Adjustable, Accessible { * * * - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true. * @see java.awt.GraphicsEnvironment#isHeadless */ @@ -366,9 +366,9 @@ public class Scrollbar extends Component implements Adjustable, Accessible { * indicating a horizontal or vertical scroll bar, respectively. * * @param orientation indicates the orientation of the scroll bar - * @exception IllegalArgumentException when an illegal value for + * @throws IllegalArgumentException when an illegal value for * the {@code orientation} argument is supplied - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true. * @see java.awt.GraphicsEnvironment#isHeadless */ @@ -394,9 +394,9 @@ public class Scrollbar extends Component implements Adjustable, Accessible { * represented by the size of the bubble * @param minimum the minimum value of the scroll bar * @param maximum the maximum value of the scroll bar - * @exception IllegalArgumentException when an illegal value for + * @throws IllegalArgumentException when an illegal value for * the {@code orientation} argument is supplied - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true. * @see #setValues * @see java.awt.GraphicsEnvironment#isHeadless @@ -457,7 +457,7 @@ public class Scrollbar extends Component implements Adjustable, Accessible { * {@code Scrollbar.HORIZONTAL} or * {@code Scrollbar.VERTICAL} * @see java.awt.Scrollbar#getOrientation - * @exception IllegalArgumentException if the value supplied + * @throws IllegalArgumentException if the value supplied * for {@code orientation} is not a * legal value * @since 1.1 @@ -1062,7 +1062,7 @@ public class Scrollbar extends Component implements Adjustable, Accessible { * @return an array of all objects registered as * FooListeners on this component, * or an empty array if no such listeners have been added - * @exception ClassCastException if {@code listenerType} + * @throws ClassCastException if {@code listenerType} * doesn't specify a class or interface that implements * {@code java.util.EventListener} * diff --git a/src/java.desktop/share/classes/java/awt/TextArea.java b/src/java.desktop/share/classes/java/awt/TextArea.java index 5e3e5ca6b331ae3ead354742bb8d7112cbd98aee..4c7baa52e4e767bdae7e7c681bd920329b8a74e7 100644 --- a/src/java.desktop/share/classes/java/awt/TextArea.java +++ b/src/java.desktop/share/classes/java/awt/TextArea.java @@ -157,7 +157,7 @@ public class TextArea extends TextComponent { * This text area is created with scrollbar visibility equal to * {@link #SCROLLBARS_BOTH}, so both vertical and horizontal * scrollbars will be visible for this text area. - * @exception HeadlessException if + * @throws HeadlessException if * {@code GraphicsEnvironment.isHeadless} returns true * @see java.awt.GraphicsEnvironment#isHeadless() */ @@ -173,7 +173,7 @@ public class TextArea extends TextComponent { * @param text the text to be displayed; if * {@code text} is {@code null}, the empty * string {@code ""} will be displayed - * @exception HeadlessException if + * @throws HeadlessException if * {@code GraphicsEnvironment.isHeadless} returns true * @see java.awt.GraphicsEnvironment#isHeadless() */ @@ -191,7 +191,7 @@ public class TextArea extends TextComponent { * text area. * @param rows the number of rows * @param columns the number of columns - * @exception HeadlessException if + * @throws HeadlessException if * {@code GraphicsEnvironment.isHeadless} returns true * @see java.awt.GraphicsEnvironment#isHeadless() */ @@ -212,7 +212,7 @@ public class TextArea extends TextComponent { * string {@code ""} will be displayed * @param rows the number of rows * @param columns the number of columns - * @exception HeadlessException if + * @throws HeadlessException if * {@code GraphicsEnvironment.isHeadless} returns true * @see java.awt.GraphicsEnvironment#isHeadless() */ @@ -252,7 +252,7 @@ public class TextArea extends TextComponent { * @param scrollbars a constant that determines what * scrollbars are created to view the text area * @since 1.1 - * @exception HeadlessException if + * @throws HeadlessException if * {@code GraphicsEnvironment.isHeadless} returns true * @see java.awt.GraphicsEnvironment#isHeadless() */ @@ -421,7 +421,7 @@ public class TextArea extends TextComponent { * @param rows the number of rows * @see #getRows() * @see #setColumns(int) - * @exception IllegalArgumentException if the value + * @throws IllegalArgumentException if the value * supplied for {@code rows} * is less than {@code 0} * @since 1.1 @@ -452,7 +452,7 @@ public class TextArea extends TextComponent { * @param columns the number of columns * @see #getColumns() * @see #setRows(int) - * @exception IllegalArgumentException if the value + * @throws IllegalArgumentException if the value * supplied for {@code columns} * is less than {@code 0} * @since 1.1 diff --git a/src/java.desktop/share/classes/java/awt/TextComponent.java b/src/java.desktop/share/classes/java/awt/TextComponent.java index 5dc8d4068cc7bfa0007fd7b0249abe0cf9c59240..b471b4e5ec6e8544b5a1296315a7b8485ccc5243 100644 --- a/src/java.desktop/share/classes/java/awt/TextComponent.java +++ b/src/java.desktop/share/classes/java/awt/TextComponent.java @@ -137,7 +137,7 @@ public class TextComponent extends Component implements Accessible { * @param text the text to be displayed; if * {@code text} is {@code null}, the empty * string {@code ""} will be displayed - * @exception HeadlessException if + * @throws HeadlessException if * {@code GraphicsEnvironment.isHeadless} * returns true * @see java.awt.GraphicsEnvironment#isHeadless @@ -511,7 +511,7 @@ public class TextComponent extends Component implements Accessible { * is thrown. * * @param position the position of the text insertion caret - * @exception IllegalArgumentException if {@code position} + * @throws IllegalArgumentException if {@code position} * is less than zero * @since 1.1 */ @@ -645,7 +645,7 @@ public class TextComponent extends Component implements Accessible { * FooListeners on this text component, * or an empty array if no such * listeners have been added - * @exception ClassCastException if {@code listenerType} + * @throws ClassCastException if {@code listenerType} * doesn't specify a class or interface that implements * {@code java.util.EventListener} * diff --git a/src/java.desktop/share/classes/java/awt/TextField.java b/src/java.desktop/share/classes/java/awt/TextField.java index 5ca720ee80ef95ecaf7826e06899da202f0eeee3..d2bfa0360b9bc80fb4a2531df3ef0f4ac553b302 100644 --- a/src/java.desktop/share/classes/java/awt/TextField.java +++ b/src/java.desktop/share/classes/java/awt/TextField.java @@ -152,7 +152,7 @@ public class TextField extends TextComponent { /** * Constructs a new text field. - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true. * @see java.awt.GraphicsEnvironment#isHeadless */ @@ -167,7 +167,7 @@ public class TextField extends TextComponent { * string {@code ""} will be displayed. * If {@code text} contains EOL and/or LF characters, then * each will be replaced by space character. - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true. * @see java.awt.GraphicsEnvironment#isHeadless */ @@ -182,7 +182,7 @@ public class TextField extends TextComponent { * @param columns the number of columns. If * {@code columns} is less than {@code 0}, * {@code columns} is set to {@code 0}. - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true. * @see java.awt.GraphicsEnvironment#isHeadless */ @@ -203,7 +203,7 @@ public class TextField extends TextComponent { * @param columns the number of columns. If * {@code columns} is less than {@code 0}, * {@code columns} is set to {@code 0}. - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true. * @see java.awt.GraphicsEnvironment#isHeadless */ @@ -369,7 +369,7 @@ public class TextField extends TextComponent { * approximate average character width that is platform-dependent. * @param columns the number of columns. * @see java.awt.TextField#getColumns - * @exception IllegalArgumentException if the value + * @throws IllegalArgumentException if the value * supplied for {@code columns} * is less than {@code 0}. * @since 1.1 @@ -585,7 +585,7 @@ public class TextField extends TextComponent { * FooListeners on this textfield, * or an empty array if no such * listeners have been added - * @exception ClassCastException if {@code listenerType} + * @throws ClassCastException if {@code listenerType} * doesn't specify a class or interface that implements * {@code java.util.EventListener} * diff --git a/src/java.desktop/share/classes/java/awt/Toolkit.java b/src/java.desktop/share/classes/java/awt/Toolkit.java index 354b5b3f3f3a3efb11e37473f4c115d37812882e..7399ced02bb463ebe410e5acbaa5dde65e98cc46 100644 --- a/src/java.desktop/share/classes/java/awt/Toolkit.java +++ b/src/java.desktop/share/classes/java/awt/Toolkit.java @@ -149,7 +149,7 @@ public abstract class Toolkit { * with the current system color values. * * @param systemColors an integer array. - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true * @see java.awt.GraphicsEnvironment#isHeadless * @since 1.1 @@ -181,7 +181,7 @@ public abstract class Toolkit { * @param dynamic If true, Containers should re-layout their * components as the Container is being resized. If false, * the layout will be validated after resizing is completed. - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true * @see #isDynamicLayoutSet() * @see #isDynamicLayoutActive() @@ -208,7 +208,7 @@ public abstract class Toolkit { * * @return true if validation of Containers is done dynamically, * false if validation is done after resizing is finished. - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true * @see #setDynamicLayout(boolean dynamic) * @see #isDynamicLayoutActive() @@ -274,7 +274,7 @@ public abstract class Toolkit { * available from {@code GraphicsConfiguration} and * {@code GraphicsDevice}. * @return the size of this toolkit's screen, in pixels. - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true * @see java.awt.GraphicsConfiguration#getBounds * @see java.awt.GraphicsDevice#getDisplayMode @@ -286,7 +286,7 @@ public abstract class Toolkit { /** * Returns the screen resolution in dots-per-inch. * @return this toolkit's screen resolution, in dots-per-inch. - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true * @see java.awt.GraphicsEnvironment#isHeadless */ @@ -297,7 +297,7 @@ public abstract class Toolkit { * Gets the insets of the screen. * @param gc a {@code GraphicsConfiguration} * @return the insets of this toolkit's screen, in pixels. - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true * @see java.awt.GraphicsEnvironment#isHeadless * @since 1.4 @@ -324,7 +324,7 @@ public abstract class Toolkit { * {@code getColorModel} method * of the {@code Component} class. * @return the color model of this toolkit's screen. - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true * @see java.awt.GraphicsEnvironment#isHeadless * @see java.awt.image.ColorModel @@ -413,12 +413,10 @@ public abstract class Toolkit { File propsFile = new File( System.getProperty("user.home") + sep + ".accessibility.properties"); - FileInputStream in = - new FileInputStream(propsFile); - - // Inputstream has been buffered in Properties class - properties.load(in); - in.close(); + try (FileInputStream in = new FileInputStream(propsFile)) { + // Inputstream has been buffered in Properties class + properties.load(in); + } } catch (Exception e) { // Per-user accessibility properties file does not exist } @@ -431,12 +429,10 @@ public abstract class Toolkit { File propsFile = new File( System.getProperty("java.home") + sep + "conf" + sep + "accessibility.properties"); - FileInputStream in = - new FileInputStream(propsFile); - - // Inputstream has been buffered in Properties class - properties.load(in); - in.close(); + try (FileInputStream in = new FileInputStream(propsFile)) { + // Inputstream has been buffered in Properties class + properties.load(in); + } } catch (Exception e) { // System-wide accessibility properties file does // not exist; @@ -977,7 +973,7 @@ public abstract class Toolkit { * checkPermission} method to check {@code AWTPermission("accessClipboard")}. * * @return the system Clipboard - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true * @see java.awt.GraphicsEnvironment#isHeadless * @see java.awt.datatransfer.Clipboard @@ -1024,7 +1020,7 @@ public abstract class Toolkit { * @return the system selection as a {@code Clipboard}, or * {@code null} if the native platform does not support a * system selection {@code Clipboard} - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true * * @see java.awt.datatransfer.Clipboard @@ -1061,7 +1057,7 @@ public abstract class Toolkit { * Control key isn't the correct key for accelerators. * @return the modifier mask on the {@code Event} class * that is used for menu shortcuts on this toolkit. - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true * @see java.awt.GraphicsEnvironment#isHeadless * @see java.awt.MenuBar @@ -1115,12 +1111,12 @@ public abstract class Toolkit { * @param keyCode the key code * @return {@code true} if the given key is currently in its "on" state; * otherwise {@code false} - * @exception java.lang.IllegalArgumentException if {@code keyCode} + * @throws java.lang.IllegalArgumentException if {@code keyCode} * is not one of the valid key codes - * @exception java.lang.UnsupportedOperationException if the host system doesn't + * @throws java.lang.UnsupportedOperationException if the host system doesn't * allow getting the state of this key programmatically, or if the keyboard * doesn't have this key - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true * @see java.awt.GraphicsEnvironment#isHeadless * @since 1.3 @@ -1151,12 +1147,12 @@ public abstract class Toolkit { * * @param keyCode the key code * @param on the state of the key - * @exception java.lang.IllegalArgumentException if {@code keyCode} + * @throws java.lang.IllegalArgumentException if {@code keyCode} * is not one of the valid key codes - * @exception java.lang.UnsupportedOperationException if the host system doesn't + * @throws java.lang.UnsupportedOperationException if the host system doesn't * allow setting the state of this key programmatically, or if the keyboard * doesn't have this key - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true * @see java.awt.GraphicsEnvironment#isHeadless * @since 1.3 @@ -1197,10 +1193,10 @@ public abstract class Toolkit { * hotSpot values must be less than the Dimension returned by * {@code getBestCursorSize} * @param name a localized description of the cursor, for Java Accessibility use - * @exception IndexOutOfBoundsException if the hotSpot values are outside + * @throws IndexOutOfBoundsException if the hotSpot values are outside * the bounds of the cursor * @return the cursor created - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true * @see java.awt.GraphicsEnvironment#isHeadless * @since 1.2 @@ -1236,7 +1232,7 @@ public abstract class Toolkit { * to use. * @return the closest matching supported cursor size, or a dimension of 0,0 if * the Toolkit implementation doesn't support custom cursors. - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true * @see java.awt.GraphicsEnvironment#isHeadless * @since 1.2 @@ -1266,7 +1262,7 @@ public abstract class Toolkit { * * @return the maximum number of colors, or zero if custom cursors are not * supported by this Toolkit implementation. - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true * @see java.awt.GraphicsEnvironment#isHeadless * @since 1.2 @@ -1314,7 +1310,7 @@ public abstract class Toolkit { * @param state one of named frame state constants. * @return {@code true} is this frame state is supported by * this Toolkit implementation, {@code false} otherwise. - * @exception HeadlessException + * @throws HeadlessException * if {@code GraphicsEnvironment.isHeadless()} * returns {@code true}. * @see java.awt.Window#addWindowStateListener @@ -2090,7 +2086,7 @@ public abstract class Toolkit { } } - private class SelectiveAWTEventListener implements AWTEventListener { + private static class SelectiveAWTEventListener implements AWTEventListener { AWTEventListener listener; private long eventMask; // This array contains the number of times to call the eventlistener @@ -2207,7 +2203,7 @@ public abstract class Toolkit { * returned is unmodifiable. * @param highlight input method highlight * @return style attribute map, or {@code null} - * @exception HeadlessException if + * @throws HeadlessException if * {@code GraphicsEnvironment.isHeadless} returns true * @see java.awt.GraphicsEnvironment#isHeadless * @since 1.3 @@ -2364,7 +2360,7 @@ public abstract class Toolkit { * initialized with {@code true}. * Changing this value after the {@code Toolkit} class initialization will have no effect. * - * @exception HeadlessException if GraphicsEnvironment.isHeadless() returns true + * @throws HeadlessException if GraphicsEnvironment.isHeadless() returns true * @return {@code true} if events from extra mouse buttons are allowed to be processed and posted; * {@code false} otherwise * @see System#getProperty(String propertyName) diff --git a/src/java.desktop/share/classes/java/awt/Window.java b/src/java.desktop/share/classes/java/awt/Window.java index 59e63abbb3ca4d958027e0931ba4f9348858ec84..c58b2a5e94a3d0211a0e179bb56a72d3a40935e5 100644 --- a/src/java.desktop/share/classes/java/awt/Window.java +++ b/src/java.desktop/share/classes/java/awt/Window.java @@ -442,9 +442,9 @@ public class Window extends Container implements Accessible { * @param gc the {@code GraphicsConfiguration} of the target screen * device. If {@code gc} is {@code null}, the system default * {@code GraphicsConfiguration} is assumed - * @exception IllegalArgumentException if {@code gc} + * @throws IllegalArgumentException if {@code gc} * is not from a screen device - * @exception HeadlessException when + * @throws HeadlessException when * {@code GraphicsEnvironment.isHeadless()} returns {@code true} * * @see java.awt.GraphicsEnvironment#isHeadless @@ -544,7 +544,7 @@ public class Window extends Container implements Accessible { * If that check fails with a {@code SecurityException} then a warning * banner is created. * - * @exception HeadlessException when + * @throws HeadlessException when * {@code GraphicsEnvironment.isHeadless()} returns {@code true} * * @see java.awt.GraphicsEnvironment#isHeadless @@ -566,9 +566,9 @@ public class Window extends Container implements Accessible { * * @param owner the {@code Frame} to act as owner or {@code null} * if this window has no owner - * @exception IllegalArgumentException if the {@code owner}'s + * @throws IllegalArgumentException if the {@code owner}'s * {@code GraphicsConfiguration} is not from a screen device - * @exception HeadlessException when + * @throws HeadlessException when * {@code GraphicsEnvironment.isHeadless} returns {@code true} * * @see java.awt.GraphicsEnvironment#isHeadless @@ -593,9 +593,9 @@ public class Window extends Container implements Accessible { * * @param owner the {@code Window} to act as owner or * {@code null} if this window has no owner - * @exception IllegalArgumentException if the {@code owner}'s + * @throws IllegalArgumentException if the {@code owner}'s * {@code GraphicsConfiguration} is not from a screen device - * @exception HeadlessException when + * @throws HeadlessException when * {@code GraphicsEnvironment.isHeadless()} returns * {@code true} * @@ -627,9 +627,9 @@ public class Window extends Container implements Accessible { * @param gc the {@code GraphicsConfiguration} of the target * screen device; if {@code gc} is {@code null}, * the system default {@code GraphicsConfiguration} is assumed - * @exception IllegalArgumentException if {@code gc} + * @throws IllegalArgumentException if {@code gc} * is not from a screen device - * @exception HeadlessException when + * @throws HeadlessException when * {@code GraphicsEnvironment.isHeadless()} returns * {@code true} * @@ -1964,10 +1964,10 @@ public class Window extends Container implements Accessible { * FooListeners on this window, * or an empty array if no such * listeners have been added - * @exception ClassCastException if {@code listenerType} + * @throws ClassCastException if {@code listenerType} * doesn't specify a class or interface that implements * {@code java.util.EventListener} - * @exception NullPointerException if {@code listenerType} is {@code null} + * @throws NullPointerException if {@code listenerType} is {@code null} * * @see #getWindowListeners * @since 1.3 @@ -3372,8 +3372,8 @@ public class Window extends Container implements Accessible { * Each time this method is called, * the existing buffer strategy for this component is discarded. * @param numBuffers number of buffers to create - * @exception IllegalArgumentException if numBuffers is less than 1. - * @exception IllegalStateException if the component is not displayable + * @throws IllegalArgumentException if numBuffers is less than 1. + * @throws IllegalStateException if the component is not displayable * @see #isDisplayable * @see #getBufferStrategy * @since 1.4 @@ -3393,11 +3393,11 @@ public class Window extends Container implements Accessible { * @param numBuffers number of buffers to create, including the front buffer * @param caps the required capabilities for creating the buffer strategy; * cannot be {@code null} - * @exception AWTException if the capabilities supplied could not be + * @throws AWTException if the capabilities supplied could not be * supported or met; this may happen, for example, if there is not enough * accelerated memory currently available, or if page flipping is specified * but not possible. - * @exception IllegalArgumentException if numBuffers is less than 1, or if + * @throws IllegalArgumentException if numBuffers is less than 1, or if * caps is {@code null} * @see #getBufferStrategy * @since 1.4 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 8bbdfc24c06bf8cbc2ed114895ca3086dfaf946c..71bf6d27c8341b6974aa1e1f1bc9b438b91ebeb5 100644 --- a/src/java.desktop/share/classes/java/awt/dnd/DragSource.java +++ b/src/java.desktop/share/classes/java/awt/dnd/DragSource.java @@ -217,7 +217,7 @@ public class DragSource implements Serializable { * the underlying platform. * * @return the platform DragSource - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true * @see java.awt.GraphicsEnvironment#isHeadless */ @@ -255,7 +255,7 @@ public class DragSource implements Serializable { /** * Creates a new {@code DragSource}. * - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true * @see java.awt.GraphicsEnvironment#isHeadless */ @@ -682,7 +682,7 @@ public class DragSource implements Serializable { * FooListeners on this * {@code DragSource}, or an empty array if no such listeners * have been added - * @exception ClassCastException if {@code listenerType} + * @throws ClassCastException if {@code listenerType} * doesn't specify a class or interface that implements * {@code java.util.EventListener} * diff --git a/src/java.desktop/share/classes/java/awt/dnd/DropTarget.java b/src/java.desktop/share/classes/java/awt/dnd/DropTarget.java index a05dbdebad26f72fb3d7aa2f0bed5fa9d2dd2fe8..fbd086792a5bff6d04010cabf08a4782d0b586c6 100644 --- a/src/java.desktop/share/classes/java/awt/dnd/DropTarget.java +++ b/src/java.desktop/share/classes/java/awt/dnd/DropTarget.java @@ -89,7 +89,7 @@ public class DropTarget implements DropTargetListener, Serializable { * @param dtl The {@code DropTargetListener} for this {@code DropTarget} * @param act Is the {@code DropTarget} accepting drops. * @param fm The {@code FlavorMap} to use, or null for the default {@code FlavorMap} - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true * @see java.awt.GraphicsEnvironment#isHeadless */ @@ -136,7 +136,7 @@ public class DropTarget implements DropTargetListener, Serializable { * @param ops The default acceptable actions for this {@code DropTarget} * @param dtl The {@code DropTargetListener} for this {@code DropTarget} * @param act Is the {@code DropTarget} accepting drops. - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true * @see java.awt.GraphicsEnvironment#isHeadless */ @@ -149,7 +149,7 @@ public class DropTarget implements DropTargetListener, Serializable { /** * Creates a {@code DropTarget}. - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true * @see java.awt.GraphicsEnvironment#isHeadless */ @@ -165,7 +165,7 @@ public class DropTarget implements DropTargetListener, Serializable { * The Component will receive drops only if it is enabled. * @param c The {@code Component} with which this {@code DropTarget} is associated * @param dtl The {@code DropTargetListener} for this {@code DropTarget} - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true * @see java.awt.GraphicsEnvironment#isHeadless */ @@ -185,7 +185,7 @@ public class DropTarget implements DropTargetListener, Serializable { * @param c The {@code Component} with which this {@code DropTarget} is associated * @param ops The default acceptable actions for this {@code DropTarget} * @param dtl The {@code DropTargetListener} for this {@code DropTarget} - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true * @see java.awt.GraphicsEnvironment#isHeadless */ @@ -793,7 +793,7 @@ public class DropTarget implements DropTargetListener, Serializable { */ protected void initializeAutoscrolling(Point p) { - if (component == null || !(component instanceof Autoscroll)) return; + if (!(component instanceof Autoscroll)) return; autoScroller = createDropTargetAutoScroller(component, p); } diff --git a/src/java.desktop/share/classes/java/awt/doc-files/Modality.html b/src/java.desktop/share/classes/java/awt/doc-files/Modality.html index eeb779672dc85a826481fed0fe507ecb4e2a54b7..e20d9175fb775a7f8303327cd994efe51bedc1fd 100644 --- a/src/java.desktop/share/classes/java/awt/doc-files/Modality.html +++ b/src/java.desktop/share/classes/java/awt/doc-files/Modality.html @@ -8,7 +8,7 @@ */ @Override - @ForceInline - public final + public abstract VectorMask test(VectorOperators.Test op, - VectorMask m) { - return test(op).and(m); + VectorMask m); + + /*package-private*/ + @ForceInline + final + > + M testTemplate(Class maskType, Test op, M mask) { + ByteSpecies vsp = vspecies(); + mask.check(maskType, this); + if (opKind(op, VO_SPECIAL)) { + VectorMask m = mask; + if (op == IS_DEFAULT) { + m = compare(EQ, (byte) 0, m); + } else if (op == IS_NEGATIVE) { + m = compare(LT, (byte) 0, m); + } + else { + throw new AssertionError(op); + } + return maskType.cast(m); + } + int opc = opCode(op); + throw new AssertionError(op); } /** @@ -2595,7 +2614,8 @@ public abstract class ByteVector extends AbstractVector { VectorMask m) { m.check(maskClass, this); if (op == FIRST_NONZERO) { - ByteVector v = reduceIdentityVector(op).blend(this, m); + // FIXME: The JIT should handle this. + ByteVector v = broadcast((byte) 0).blend(this, m); return v.reduceLanesTemplate(op); } int opc = opCode(op); @@ -2610,10 +2630,11 @@ public abstract class ByteVector extends AbstractVector { final byte reduceLanesTemplate(VectorOperators.Associative op) { if (op == FIRST_NONZERO) { - // FIXME: The JIT should handle this, and other scan ops alos. + // FIXME: The JIT should handle this. VectorMask thisNZ = this.viewAsIntegralLanes().compare(NE, (byte) 0); - return this.lane(thisNZ.firstTrue()); + int ft = thisNZ.firstTrue(); + return ft < length() ? this.lane(ft) : (byte) 0; } int opc = opCode(op); return fromBits(VectorSupport.reductionCoerced( @@ -2646,34 +2667,6 @@ public abstract class ByteVector extends AbstractVector { } } - private - @ForceInline - ByteVector reduceIdentityVector(VectorOperators.Associative op) { - int opc = opCode(op); - UnaryOperator fn - = REDUCE_ID_IMPL.find(op, opc, (opc_) -> { - switch (opc_) { - case VECTOR_OP_ADD: - case VECTOR_OP_OR: - case VECTOR_OP_XOR: - return v -> v.broadcast(0); - case VECTOR_OP_MUL: - return v -> v.broadcast(1); - case VECTOR_OP_AND: - return v -> v.broadcast(-1); - case VECTOR_OP_MIN: - return v -> v.broadcast(MAX_OR_INF); - case VECTOR_OP_MAX: - return v -> v.broadcast(MIN_OR_INF); - default: return null; - } - }); - return fn.apply(this); - } - private static final - ImplCache> REDUCE_ID_IMPL - = new ImplCache<>(Associative.class, ByteVector.class); - private static final byte MIN_OR_INF = Byte.MIN_VALUE; private static final byte MAX_OR_INF = Byte.MAX_VALUE; @@ -4149,9 +4142,9 @@ public abstract class ByteVector extends AbstractVector { @ForceInline final ByteVector broadcastBits(long bits) { return (ByteVector) - VectorSupport.broadcastCoerced( + VectorSupport.fromBitsCoerced( vectorType, byte.class, laneCount, - bits, this, + bits, MODE_BROADCAST, this, (bits_, s_) -> s_.rvOp(i -> bits_)); } @@ -4343,12 +4336,12 @@ public abstract class ByteVector extends AbstractVector { */ static ByteSpecies species(VectorShape s) { Objects.requireNonNull(s); - switch (s) { - case S_64_BIT: return (ByteSpecies) SPECIES_64; - case S_128_BIT: return (ByteSpecies) SPECIES_128; - case S_256_BIT: return (ByteSpecies) SPECIES_256; - case S_512_BIT: return (ByteSpecies) SPECIES_512; - case S_Max_BIT: return (ByteSpecies) SPECIES_MAX; + switch (s.switchKey) { + case VectorShape.SK_64_BIT: return (ByteSpecies) SPECIES_64; + case VectorShape.SK_128_BIT: return (ByteSpecies) SPECIES_128; + case VectorShape.SK_256_BIT: return (ByteSpecies) SPECIES_256; + case VectorShape.SK_512_BIT: return (ByteSpecies) SPECIES_512; + case VectorShape.SK_Max_BIT: return (ByteSpecies) SPECIES_MAX; default: throw new IllegalArgumentException("Bad shape: " + s); } } 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 62f2eb5eff586a3f8f64c315ab1baf5a930b6862..24c32c848c35489dfe9e6ebfaceba2167692a488 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -357,6 +357,12 @@ final class Double128Vector extends DoubleVector { return super.testTemplate(Double128Mask.class, op); // specialize } + @Override + @ForceInline + public final Double128Mask test(Test op, VectorMask m) { + return super.testTemplate(Double128Mask.class, op, (Double128Mask) m); // specialize + } + // Specialized comparisons @Override @@ -718,9 +724,9 @@ final class Double128Vector extends DoubleVector { @ForceInline /*package-private*/ static Double128Mask maskAll(boolean bit) { - return VectorSupport.broadcastCoerced(Double128Mask.class, long.class, VLENGTH, - (bit ? -1 : 0), null, - (v, __) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); + return VectorSupport.fromBitsCoerced(Double128Mask.class, long.class, VLENGTH, + (bit ? -1 : 0), MODE_BROADCAST, null, + (v, __) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); } private static final Double128Mask TRUE_MASK = new Double128Mask(true); private static final Double128Mask FALSE_MASK = new Double128Mask(false); 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 547684af87d29652d788386febe4e02e35a6f490..e265dc86288437af12ede90e5eff7bd815c4ad16 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -357,6 +357,12 @@ final class Double256Vector extends DoubleVector { return super.testTemplate(Double256Mask.class, op); // specialize } + @Override + @ForceInline + public final Double256Mask test(Test op, VectorMask m) { + return super.testTemplate(Double256Mask.class, op, (Double256Mask) m); // specialize + } + // Specialized comparisons @Override @@ -722,9 +728,9 @@ final class Double256Vector extends DoubleVector { @ForceInline /*package-private*/ static Double256Mask maskAll(boolean bit) { - return VectorSupport.broadcastCoerced(Double256Mask.class, long.class, VLENGTH, - (bit ? -1 : 0), null, - (v, __) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); + return VectorSupport.fromBitsCoerced(Double256Mask.class, long.class, VLENGTH, + (bit ? -1 : 0), MODE_BROADCAST, null, + (v, __) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); } private static final Double256Mask TRUE_MASK = new Double256Mask(true); private static final Double256Mask FALSE_MASK = new Double256Mask(false); 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 bacc0cde0881f2a5dc4e8c7fd9395b07fb52012b..77b52f511d629d21b1886720d273ea802e718684 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -357,6 +357,12 @@ final class Double512Vector extends DoubleVector { return super.testTemplate(Double512Mask.class, op); // specialize } + @Override + @ForceInline + public final Double512Mask test(Test op, VectorMask m) { + return super.testTemplate(Double512Mask.class, op, (Double512Mask) m); // specialize + } + // Specialized comparisons @Override @@ -730,9 +736,9 @@ final class Double512Vector extends DoubleVector { @ForceInline /*package-private*/ static Double512Mask maskAll(boolean bit) { - return VectorSupport.broadcastCoerced(Double512Mask.class, long.class, VLENGTH, - (bit ? -1 : 0), null, - (v, __) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); + return VectorSupport.fromBitsCoerced(Double512Mask.class, long.class, VLENGTH, + (bit ? -1 : 0), MODE_BROADCAST, null, + (v, __) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); } private static final Double512Mask TRUE_MASK = new Double512Mask(true); private static final Double512Mask FALSE_MASK = new Double512Mask(false); 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 29977c72c6aeaf271a2888cbc67df202db0e1aec..dba680a6a3cf5dce43d3ab1c9ac03063889224b1 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -357,6 +357,12 @@ final class Double64Vector extends DoubleVector { return super.testTemplate(Double64Mask.class, op); // specialize } + @Override + @ForceInline + public final Double64Mask test(Test op, VectorMask m) { + return super.testTemplate(Double64Mask.class, op, (Double64Mask) m); // specialize + } + // Specialized comparisons @Override @@ -716,9 +722,9 @@ final class Double64Vector extends DoubleVector { @ForceInline /*package-private*/ static Double64Mask maskAll(boolean bit) { - return VectorSupport.broadcastCoerced(Double64Mask.class, long.class, VLENGTH, - (bit ? -1 : 0), null, - (v, __) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); + return VectorSupport.fromBitsCoerced(Double64Mask.class, long.class, VLENGTH, + (bit ? -1 : 0), MODE_BROADCAST, null, + (v, __) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); } private static final Double64Mask TRUE_MASK = new Double64Mask(true); private static final Double64Mask FALSE_MASK = new Double64Mask(false); 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 c9db9f93b40a9092288c6ba4e21ad5a6ff00d28f..8c454d3f872b911d050290dd7ddc5864ce6f8c2c 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -357,6 +357,12 @@ final class DoubleMaxVector extends DoubleVector { return super.testTemplate(DoubleMaxMask.class, op); // specialize } + @Override + @ForceInline + public final DoubleMaxMask test(Test op, VectorMask m) { + return super.testTemplate(DoubleMaxMask.class, op, (DoubleMaxMask) m); // specialize + } + // Specialized comparisons @Override @@ -715,9 +721,9 @@ final class DoubleMaxVector extends DoubleVector { @ForceInline /*package-private*/ static DoubleMaxMask maskAll(boolean bit) { - return VectorSupport.broadcastCoerced(DoubleMaxMask.class, long.class, VLENGTH, - (bit ? -1 : 0), null, - (v, __) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); + return VectorSupport.fromBitsCoerced(DoubleMaxMask.class, long.class, VLENGTH, + (bit ? -1 : 0), MODE_BROADCAST, null, + (v, __) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); } private static final DoubleMaxMask TRUE_MASK = new DoubleMaxMask(true); private static final DoubleMaxMask FALSE_MASK = new DoubleMaxMask(false); 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 691a4def745301984b2448f9e8527c8d2cc2b961..4d62284bb6e1e9da8c2c6689a08a7c8e04efdd14 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -444,8 +444,8 @@ public abstract class DoubleVector extends AbstractVector { @ForceInline public static DoubleVector zero(VectorSpecies species) { DoubleSpecies vsp = (DoubleSpecies) species; - return VectorSupport.broadcastCoerced(vsp.vectorType(), double.class, species.length(), - toBits(0.0f), vsp, + return VectorSupport.fromBitsCoerced(vsp.vectorType(), double.class, species.length(), + toBits(0.0f), MODE_BROADCAST, vsp, ((bits_, s_) -> s_.rvOp(i -> bits_))); } @@ -1715,7 +1715,7 @@ public abstract class DoubleVector extends AbstractVector { else { throw new AssertionError(op); } - return maskType.cast(m.cast(this.vspecies())); + return maskType.cast(m.cast(vsp)); } int opc = opCode(op); throw new AssertionError(op); @@ -1725,11 +1725,48 @@ public abstract class DoubleVector extends AbstractVector { * {@inheritDoc} */ @Override - @ForceInline - public final + public abstract VectorMask test(VectorOperators.Test op, - VectorMask m) { - return test(op).and(m); + VectorMask m); + + /*package-private*/ + @ForceInline + final + > + M testTemplate(Class maskType, Test op, M mask) { + DoubleSpecies vsp = vspecies(); + mask.check(maskType, this); + if (opKind(op, VO_SPECIAL)) { + LongVector bits = this.viewAsIntegralLanes(); + VectorMask m = mask.cast(LongVector.species(shape())); + if (op == IS_DEFAULT) { + m = bits.compare(EQ, (long) 0, m); + } else if (op == IS_NEGATIVE) { + m = bits.compare(LT, (long) 0, m); + } + else if (op == IS_FINITE || + op == IS_NAN || + op == IS_INFINITE) { + // first kill the sign: + bits = bits.and(Long.MAX_VALUE); + // next find the bit pattern for infinity: + long infbits = (long) toBits(Double.POSITIVE_INFINITY); + // now compare: + if (op == IS_FINITE) { + m = bits.compare(LT, infbits, m); + } else if (op == IS_NAN) { + m = bits.compare(GT, infbits, m); + } else { + m = bits.compare(EQ, infbits, m); + } + } + else { + throw new AssertionError(op); + } + return maskType.cast(m.cast(vsp)); + } + int opc = opCode(op); + throw new AssertionError(op); } /** @@ -2419,7 +2456,8 @@ public abstract class DoubleVector extends AbstractVector { VectorMask m) { m.check(maskClass, this); if (op == FIRST_NONZERO) { - DoubleVector v = reduceIdentityVector(op).blend(this, m); + // FIXME: The JIT should handle this. + DoubleVector v = broadcast((double) 0).blend(this, m); return v.reduceLanesTemplate(op); } int opc = opCode(op); @@ -2434,10 +2472,11 @@ public abstract class DoubleVector extends AbstractVector { final double reduceLanesTemplate(VectorOperators.Associative op) { if (op == FIRST_NONZERO) { - // FIXME: The JIT should handle this, and other scan ops alos. + // FIXME: The JIT should handle this. VectorMask thisNZ = this.viewAsIntegralLanes().compare(NE, (long) 0); - return this.lane(thisNZ.firstTrue()); + int ft = thisNZ.firstTrue(); + return ft < length() ? this.lane(ft) : (double) 0; } int opc = opCode(op); return fromBits(VectorSupport.reductionCoerced( @@ -2464,30 +2503,6 @@ public abstract class DoubleVector extends AbstractVector { } } - private - @ForceInline - DoubleVector reduceIdentityVector(VectorOperators.Associative op) { - int opc = opCode(op); - UnaryOperator fn - = REDUCE_ID_IMPL.find(op, opc, (opc_) -> { - switch (opc_) { - case VECTOR_OP_ADD: - return v -> v.broadcast(0); - case VECTOR_OP_MUL: - return v -> v.broadcast(1); - case VECTOR_OP_MIN: - return v -> v.broadcast(MAX_OR_INF); - case VECTOR_OP_MAX: - return v -> v.broadcast(MIN_OR_INF); - default: return null; - } - }); - return fn.apply(this); - } - private static final - ImplCache> REDUCE_ID_IMPL - = new ImplCache<>(Associative.class, DoubleVector.class); - private static final double MIN_OR_INF = Double.NEGATIVE_INFINITY; private static final double MAX_OR_INF = Double.POSITIVE_INFINITY; @@ -3754,9 +3769,9 @@ public abstract class DoubleVector extends AbstractVector { @ForceInline final DoubleVector broadcastBits(long bits) { return (DoubleVector) - VectorSupport.broadcastCoerced( + VectorSupport.fromBitsCoerced( vectorType, double.class, laneCount, - bits, this, + bits, MODE_BROADCAST, this, (bits_, s_) -> s_.rvOp(i -> bits_)); } @@ -3948,12 +3963,12 @@ public abstract class DoubleVector extends AbstractVector { */ static DoubleSpecies species(VectorShape s) { Objects.requireNonNull(s); - switch (s) { - case S_64_BIT: return (DoubleSpecies) SPECIES_64; - case S_128_BIT: return (DoubleSpecies) SPECIES_128; - case S_256_BIT: return (DoubleSpecies) SPECIES_256; - case S_512_BIT: return (DoubleSpecies) SPECIES_512; - case S_Max_BIT: return (DoubleSpecies) SPECIES_MAX; + switch (s.switchKey) { + case VectorShape.SK_64_BIT: return (DoubleSpecies) SPECIES_64; + case VectorShape.SK_128_BIT: return (DoubleSpecies) SPECIES_128; + case VectorShape.SK_256_BIT: return (DoubleSpecies) SPECIES_256; + case VectorShape.SK_512_BIT: return (DoubleSpecies) SPECIES_512; + case VectorShape.SK_Max_BIT: return (DoubleSpecies) SPECIES_MAX; default: throw new IllegalArgumentException("Bad shape: " + s); } } 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 4e0dd018d269986843332e216b4ddafe64b72000..1d6195486ae0e7274b66ff17a36b774c56b51358 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -357,6 +357,12 @@ final class Float128Vector extends FloatVector { return super.testTemplate(Float128Mask.class, op); // specialize } + @Override + @ForceInline + public final Float128Mask test(Test op, VectorMask m) { + return super.testTemplate(Float128Mask.class, op, (Float128Mask) m); // specialize + } + // Specialized comparisons @Override @@ -722,9 +728,9 @@ final class Float128Vector extends FloatVector { @ForceInline /*package-private*/ static Float128Mask maskAll(boolean bit) { - return VectorSupport.broadcastCoerced(Float128Mask.class, int.class, VLENGTH, - (bit ? -1 : 0), null, - (v, __) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); + return VectorSupport.fromBitsCoerced(Float128Mask.class, int.class, VLENGTH, + (bit ? -1 : 0), MODE_BROADCAST, null, + (v, __) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); } private static final Float128Mask TRUE_MASK = new Float128Mask(true); private static final Float128Mask FALSE_MASK = new Float128Mask(false); 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 7812876f4eb59f8874ed9c977d653e22230681cb..6a2a1003cf467d0b8871e3f90c8bfdf35fde7cb8 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -357,6 +357,12 @@ final class Float256Vector extends FloatVector { return super.testTemplate(Float256Mask.class, op); // specialize } + @Override + @ForceInline + public final Float256Mask test(Test op, VectorMask m) { + return super.testTemplate(Float256Mask.class, op, (Float256Mask) m); // specialize + } + // Specialized comparisons @Override @@ -730,9 +736,9 @@ final class Float256Vector extends FloatVector { @ForceInline /*package-private*/ static Float256Mask maskAll(boolean bit) { - return VectorSupport.broadcastCoerced(Float256Mask.class, int.class, VLENGTH, - (bit ? -1 : 0), null, - (v, __) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); + return VectorSupport.fromBitsCoerced(Float256Mask.class, int.class, VLENGTH, + (bit ? -1 : 0), MODE_BROADCAST, null, + (v, __) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); } private static final Float256Mask TRUE_MASK = new Float256Mask(true); private static final Float256Mask FALSE_MASK = new Float256Mask(false); 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 a8936709baadb9c7e3a379b59fa7bae36376fda6..5b29c2cca10650b26c6a5c4091f30aa8d561c2c5 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -357,6 +357,12 @@ final class Float512Vector extends FloatVector { return super.testTemplate(Float512Mask.class, op); // specialize } + @Override + @ForceInline + public final Float512Mask test(Test op, VectorMask m) { + return super.testTemplate(Float512Mask.class, op, (Float512Mask) m); // specialize + } + // Specialized comparisons @Override @@ -746,9 +752,9 @@ final class Float512Vector extends FloatVector { @ForceInline /*package-private*/ static Float512Mask maskAll(boolean bit) { - return VectorSupport.broadcastCoerced(Float512Mask.class, int.class, VLENGTH, - (bit ? -1 : 0), null, - (v, __) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); + return VectorSupport.fromBitsCoerced(Float512Mask.class, int.class, VLENGTH, + (bit ? -1 : 0), MODE_BROADCAST, null, + (v, __) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); } private static final Float512Mask TRUE_MASK = new Float512Mask(true); private static final Float512Mask FALSE_MASK = new Float512Mask(false); 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 0c91d46e64e46788d840b52abbd186b2deb4f3bb..0eea80c244fbf0fe701b1e274363395482f0a6c1 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -357,6 +357,12 @@ final class Float64Vector extends FloatVector { return super.testTemplate(Float64Mask.class, op); // specialize } + @Override + @ForceInline + public final Float64Mask test(Test op, VectorMask m) { + return super.testTemplate(Float64Mask.class, op, (Float64Mask) m); // specialize + } + // Specialized comparisons @Override @@ -718,9 +724,9 @@ final class Float64Vector extends FloatVector { @ForceInline /*package-private*/ static Float64Mask maskAll(boolean bit) { - return VectorSupport.broadcastCoerced(Float64Mask.class, int.class, VLENGTH, - (bit ? -1 : 0), null, - (v, __) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); + return VectorSupport.fromBitsCoerced(Float64Mask.class, int.class, VLENGTH, + (bit ? -1 : 0), MODE_BROADCAST, null, + (v, __) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); } private static final Float64Mask TRUE_MASK = new Float64Mask(true); private static final Float64Mask FALSE_MASK = new Float64Mask(false); 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 f2e1bd05c13d290677c414ae909b4597f2b43e88..0db9aab9c57d7155119a92fbc65f6b82e810a38d 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -357,6 +357,12 @@ final class FloatMaxVector extends FloatVector { return super.testTemplate(FloatMaxMask.class, op); // specialize } + @Override + @ForceInline + public final FloatMaxMask test(Test op, VectorMask m) { + return super.testTemplate(FloatMaxMask.class, op, (FloatMaxMask) m); // specialize + } + // Specialized comparisons @Override @@ -715,9 +721,9 @@ final class FloatMaxVector extends FloatVector { @ForceInline /*package-private*/ static FloatMaxMask maskAll(boolean bit) { - return VectorSupport.broadcastCoerced(FloatMaxMask.class, int.class, VLENGTH, - (bit ? -1 : 0), null, - (v, __) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); + return VectorSupport.fromBitsCoerced(FloatMaxMask.class, int.class, VLENGTH, + (bit ? -1 : 0), MODE_BROADCAST, null, + (v, __) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); } private static final FloatMaxMask TRUE_MASK = new FloatMaxMask(true); private static final FloatMaxMask FALSE_MASK = new FloatMaxMask(false); 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 d5dbc2f9efa36fd125f5c3cf7d812ca0b6c2ca20..60da7eb57fcbb405136423e0888b779bdef8bda8 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -444,8 +444,8 @@ public abstract class FloatVector extends AbstractVector { @ForceInline public static FloatVector zero(VectorSpecies species) { FloatSpecies vsp = (FloatSpecies) species; - return VectorSupport.broadcastCoerced(vsp.vectorType(), float.class, species.length(), - toBits(0.0f), vsp, + return VectorSupport.fromBitsCoerced(vsp.vectorType(), float.class, species.length(), + toBits(0.0f), MODE_BROADCAST, vsp, ((bits_, s_) -> s_.rvOp(i -> bits_))); } @@ -1727,7 +1727,7 @@ public abstract class FloatVector extends AbstractVector { else { throw new AssertionError(op); } - return maskType.cast(m.cast(this.vspecies())); + return maskType.cast(m.cast(vsp)); } int opc = opCode(op); throw new AssertionError(op); @@ -1737,11 +1737,48 @@ public abstract class FloatVector extends AbstractVector { * {@inheritDoc} */ @Override - @ForceInline - public final + public abstract VectorMask test(VectorOperators.Test op, - VectorMask m) { - return test(op).and(m); + VectorMask m); + + /*package-private*/ + @ForceInline + final + > + M testTemplate(Class maskType, Test op, M mask) { + FloatSpecies vsp = vspecies(); + mask.check(maskType, this); + if (opKind(op, VO_SPECIAL)) { + IntVector bits = this.viewAsIntegralLanes(); + VectorMask m = mask.cast(IntVector.species(shape())); + if (op == IS_DEFAULT) { + m = bits.compare(EQ, (int) 0, m); + } else if (op == IS_NEGATIVE) { + m = bits.compare(LT, (int) 0, m); + } + else if (op == IS_FINITE || + op == IS_NAN || + op == IS_INFINITE) { + // first kill the sign: + bits = bits.and(Integer.MAX_VALUE); + // next find the bit pattern for infinity: + int infbits = (int) toBits(Float.POSITIVE_INFINITY); + // now compare: + if (op == IS_FINITE) { + m = bits.compare(LT, infbits, m); + } else if (op == IS_NAN) { + m = bits.compare(GT, infbits, m); + } else { + m = bits.compare(EQ, infbits, m); + } + } + else { + throw new AssertionError(op); + } + return maskType.cast(m.cast(vsp)); + } + int opc = opCode(op); + throw new AssertionError(op); } /** @@ -2439,7 +2476,8 @@ public abstract class FloatVector extends AbstractVector { VectorMask m) { m.check(maskClass, this); if (op == FIRST_NONZERO) { - FloatVector v = reduceIdentityVector(op).blend(this, m); + // FIXME: The JIT should handle this. + FloatVector v = broadcast((float) 0).blend(this, m); return v.reduceLanesTemplate(op); } int opc = opCode(op); @@ -2454,10 +2492,11 @@ public abstract class FloatVector extends AbstractVector { final float reduceLanesTemplate(VectorOperators.Associative op) { if (op == FIRST_NONZERO) { - // FIXME: The JIT should handle this, and other scan ops alos. + // FIXME: The JIT should handle this. VectorMask thisNZ = this.viewAsIntegralLanes().compare(NE, (int) 0); - return this.lane(thisNZ.firstTrue()); + int ft = thisNZ.firstTrue(); + return ft < length() ? this.lane(ft) : (float) 0; } int opc = opCode(op); return fromBits(VectorSupport.reductionCoerced( @@ -2484,30 +2523,6 @@ public abstract class FloatVector extends AbstractVector { } } - private - @ForceInline - FloatVector reduceIdentityVector(VectorOperators.Associative op) { - int opc = opCode(op); - UnaryOperator fn - = REDUCE_ID_IMPL.find(op, opc, (opc_) -> { - switch (opc_) { - case VECTOR_OP_ADD: - return v -> v.broadcast(0); - case VECTOR_OP_MUL: - return v -> v.broadcast(1); - case VECTOR_OP_MIN: - return v -> v.broadcast(MAX_OR_INF); - case VECTOR_OP_MAX: - return v -> v.broadcast(MIN_OR_INF); - default: return null; - } - }); - return fn.apply(this); - } - private static final - ImplCache> REDUCE_ID_IMPL - = new ImplCache<>(Associative.class, FloatVector.class); - private static final float MIN_OR_INF = Float.NEGATIVE_INFINITY; private static final float MAX_OR_INF = Float.POSITIVE_INFINITY; @@ -3704,9 +3719,9 @@ public abstract class FloatVector extends AbstractVector { @ForceInline final FloatVector broadcastBits(long bits) { return (FloatVector) - VectorSupport.broadcastCoerced( + VectorSupport.fromBitsCoerced( vectorType, float.class, laneCount, - bits, this, + bits, MODE_BROADCAST, this, (bits_, s_) -> s_.rvOp(i -> bits_)); } @@ -3898,12 +3913,12 @@ public abstract class FloatVector extends AbstractVector { */ static FloatSpecies species(VectorShape s) { Objects.requireNonNull(s); - switch (s) { - case S_64_BIT: return (FloatSpecies) SPECIES_64; - case S_128_BIT: return (FloatSpecies) SPECIES_128; - case S_256_BIT: return (FloatSpecies) SPECIES_256; - case S_512_BIT: return (FloatSpecies) SPECIES_512; - case S_Max_BIT: return (FloatSpecies) SPECIES_MAX; + switch (s.switchKey) { + case VectorShape.SK_64_BIT: return (FloatSpecies) SPECIES_64; + case VectorShape.SK_128_BIT: return (FloatSpecies) SPECIES_128; + case VectorShape.SK_256_BIT: return (FloatSpecies) SPECIES_256; + case VectorShape.SK_512_BIT: return (FloatSpecies) SPECIES_512; + case VectorShape.SK_Max_BIT: return (FloatSpecies) SPECIES_MAX; default: throw new IllegalArgumentException("Bad shape: " + s); } } 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 f54042159699ce51d8bf954ec127399f501d6c8d..3baf712aa7c5a55ea955e3d7be349ef34184dabc 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -370,6 +370,12 @@ final class Int128Vector extends IntVector { return super.testTemplate(Int128Mask.class, op); // specialize } + @Override + @ForceInline + public final Int128Mask test(Test op, VectorMask m) { + return super.testTemplate(Int128Mask.class, op, (Int128Mask) m); // specialize + } + // Specialized comparisons @Override @@ -733,9 +739,9 @@ final class Int128Vector extends IntVector { @ForceInline /*package-private*/ static Int128Mask maskAll(boolean bit) { - return VectorSupport.broadcastCoerced(Int128Mask.class, int.class, VLENGTH, - (bit ? -1 : 0), null, - (v, __) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); + return VectorSupport.fromBitsCoerced(Int128Mask.class, int.class, VLENGTH, + (bit ? -1 : 0), MODE_BROADCAST, null, + (v, __) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); } private static final Int128Mask TRUE_MASK = new Int128Mask(true); private static final Int128Mask FALSE_MASK = new Int128Mask(false); 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 f5ed7ce09b87069317a722e64922e2e8c56bb7e5..a82f1cf1d072779e2f54c3b9e6066e56197f1916 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -370,6 +370,12 @@ final class Int256Vector extends IntVector { return super.testTemplate(Int256Mask.class, op); // specialize } + @Override + @ForceInline + public final Int256Mask test(Test op, VectorMask m) { + return super.testTemplate(Int256Mask.class, op, (Int256Mask) m); // specialize + } + // Specialized comparisons @Override @@ -741,9 +747,9 @@ final class Int256Vector extends IntVector { @ForceInline /*package-private*/ static Int256Mask maskAll(boolean bit) { - return VectorSupport.broadcastCoerced(Int256Mask.class, int.class, VLENGTH, - (bit ? -1 : 0), null, - (v, __) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); + return VectorSupport.fromBitsCoerced(Int256Mask.class, int.class, VLENGTH, + (bit ? -1 : 0), MODE_BROADCAST, null, + (v, __) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); } private static final Int256Mask TRUE_MASK = new Int256Mask(true); private static final Int256Mask FALSE_MASK = new Int256Mask(false); 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 6da5f59d602c040812e21ebd2053f88f66530e72..40b7246b63ffac9159234bb48bd246d1441c3100 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -370,6 +370,12 @@ final class Int512Vector extends IntVector { return super.testTemplate(Int512Mask.class, op); // specialize } + @Override + @ForceInline + public final Int512Mask test(Test op, VectorMask m) { + return super.testTemplate(Int512Mask.class, op, (Int512Mask) m); // specialize + } + // Specialized comparisons @Override @@ -757,9 +763,9 @@ final class Int512Vector extends IntVector { @ForceInline /*package-private*/ static Int512Mask maskAll(boolean bit) { - return VectorSupport.broadcastCoerced(Int512Mask.class, int.class, VLENGTH, - (bit ? -1 : 0), null, - (v, __) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); + return VectorSupport.fromBitsCoerced(Int512Mask.class, int.class, VLENGTH, + (bit ? -1 : 0), MODE_BROADCAST, null, + (v, __) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); } private static final Int512Mask TRUE_MASK = new Int512Mask(true); private static final Int512Mask FALSE_MASK = new Int512Mask(false); 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 c9b1afb21b7a9c2e87f1696377aa09dc08b750fb..59c54a6007bb1527f8a46796023fb115b7551f25 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -370,6 +370,12 @@ final class Int64Vector extends IntVector { return super.testTemplate(Int64Mask.class, op); // specialize } + @Override + @ForceInline + public final Int64Mask test(Test op, VectorMask m) { + return super.testTemplate(Int64Mask.class, op, (Int64Mask) m); // specialize + } + // Specialized comparisons @Override @@ -729,9 +735,9 @@ final class Int64Vector extends IntVector { @ForceInline /*package-private*/ static Int64Mask maskAll(boolean bit) { - return VectorSupport.broadcastCoerced(Int64Mask.class, int.class, VLENGTH, - (bit ? -1 : 0), null, - (v, __) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); + return VectorSupport.fromBitsCoerced(Int64Mask.class, int.class, VLENGTH, + (bit ? -1 : 0), MODE_BROADCAST, null, + (v, __) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); } private static final Int64Mask TRUE_MASK = new Int64Mask(true); private static final Int64Mask FALSE_MASK = new Int64Mask(false); 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 7b28a5947b067896540e5f31b6b92e45744535ef..58588448c06e03ef5c2c9b98538e2ff69e819bb7 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -370,6 +370,12 @@ final class IntMaxVector extends IntVector { return super.testTemplate(IntMaxMask.class, op); // specialize } + @Override + @ForceInline + public final IntMaxMask test(Test op, VectorMask m) { + return super.testTemplate(IntMaxMask.class, op, (IntMaxMask) m); // specialize + } + // Specialized comparisons @Override @@ -727,9 +733,9 @@ final class IntMaxVector extends IntVector { @ForceInline /*package-private*/ static IntMaxMask maskAll(boolean bit) { - return VectorSupport.broadcastCoerced(IntMaxMask.class, int.class, VLENGTH, - (bit ? -1 : 0), null, - (v, __) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); + return VectorSupport.fromBitsCoerced(IntMaxMask.class, int.class, VLENGTH, + (bit ? -1 : 0), MODE_BROADCAST, null, + (v, __) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); } private static final IntMaxMask TRUE_MASK = new IntMaxMask(true); private static final IntMaxMask FALSE_MASK = new IntMaxMask(false); 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 3deb61e990403ac289c3187820c50699f29fff21..e5033ac5366a4af671a38665784406a8de34530e 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -455,8 +455,8 @@ public abstract class IntVector extends AbstractVector { @ForceInline public static IntVector zero(VectorSpecies species) { IntSpecies vsp = (IntSpecies) species; - return VectorSupport.broadcastCoerced(vsp.vectorType(), int.class, species.length(), - 0, vsp, + return VectorSupport.fromBitsCoerced(vsp.vectorType(), int.class, species.length(), + 0, MODE_BROADCAST, vsp, ((bits_, s_) -> s_.rvOp(i -> bits_))); } @@ -1854,12 +1854,11 @@ public abstract class IntVector extends AbstractVector { M testTemplate(Class maskType, Test op) { IntSpecies vsp = vspecies(); if (opKind(op, VO_SPECIAL)) { - IntVector bits = this.viewAsIntegralLanes(); VectorMask m; if (op == IS_DEFAULT) { - m = bits.compare(EQ, (int) 0); + m = compare(EQ, (int) 0); } else if (op == IS_NEGATIVE) { - m = bits.compare(LT, (int) 0); + m = compare(LT, (int) 0); } else { throw new AssertionError(op); @@ -1874,11 +1873,31 @@ public abstract class IntVector extends AbstractVector { * {@inheritDoc} */ @Override - @ForceInline - public final + public abstract VectorMask test(VectorOperators.Test op, - VectorMask m) { - return test(op).and(m); + VectorMask m); + + /*package-private*/ + @ForceInline + final + > + M testTemplate(Class maskType, Test op, M mask) { + IntSpecies vsp = vspecies(); + mask.check(maskType, this); + if (opKind(op, VO_SPECIAL)) { + VectorMask m = mask; + if (op == IS_DEFAULT) { + m = compare(EQ, (int) 0, m); + } else if (op == IS_NEGATIVE) { + m = compare(LT, (int) 0, m); + } + else { + throw new AssertionError(op); + } + return maskType.cast(m); + } + int opc = opCode(op); + throw new AssertionError(op); } /** @@ -2594,7 +2613,8 @@ public abstract class IntVector extends AbstractVector { VectorMask m) { m.check(maskClass, this); if (op == FIRST_NONZERO) { - IntVector v = reduceIdentityVector(op).blend(this, m); + // FIXME: The JIT should handle this. + IntVector v = broadcast((int) 0).blend(this, m); return v.reduceLanesTemplate(op); } int opc = opCode(op); @@ -2609,10 +2629,11 @@ public abstract class IntVector extends AbstractVector { final int reduceLanesTemplate(VectorOperators.Associative op) { if (op == FIRST_NONZERO) { - // FIXME: The JIT should handle this, and other scan ops alos. + // FIXME: The JIT should handle this. VectorMask thisNZ = this.viewAsIntegralLanes().compare(NE, (int) 0); - return this.lane(thisNZ.firstTrue()); + int ft = thisNZ.firstTrue(); + return ft < length() ? this.lane(ft) : (int) 0; } int opc = opCode(op); return fromBits(VectorSupport.reductionCoerced( @@ -2645,34 +2666,6 @@ public abstract class IntVector extends AbstractVector { } } - private - @ForceInline - IntVector reduceIdentityVector(VectorOperators.Associative op) { - int opc = opCode(op); - UnaryOperator fn - = REDUCE_ID_IMPL.find(op, opc, (opc_) -> { - switch (opc_) { - case VECTOR_OP_ADD: - case VECTOR_OP_OR: - case VECTOR_OP_XOR: - return v -> v.broadcast(0); - case VECTOR_OP_MUL: - return v -> v.broadcast(1); - case VECTOR_OP_AND: - return v -> v.broadcast(-1); - case VECTOR_OP_MIN: - return v -> v.broadcast(MAX_OR_INF); - case VECTOR_OP_MAX: - return v -> v.broadcast(MIN_OR_INF); - default: return null; - } - }); - return fn.apply(this); - } - private static final - ImplCache> REDUCE_ID_IMPL - = new ImplCache<>(Associative.class, IntVector.class); - private static final int MIN_OR_INF = Integer.MIN_VALUE; private static final int MAX_OR_INF = Integer.MAX_VALUE; @@ -3874,9 +3867,9 @@ public abstract class IntVector extends AbstractVector { @ForceInline final IntVector broadcastBits(long bits) { return (IntVector) - VectorSupport.broadcastCoerced( + VectorSupport.fromBitsCoerced( vectorType, int.class, laneCount, - bits, this, + bits, MODE_BROADCAST, this, (bits_, s_) -> s_.rvOp(i -> bits_)); } @@ -4068,12 +4061,12 @@ public abstract class IntVector extends AbstractVector { */ static IntSpecies species(VectorShape s) { Objects.requireNonNull(s); - switch (s) { - case S_64_BIT: return (IntSpecies) SPECIES_64; - case S_128_BIT: return (IntSpecies) SPECIES_128; - case S_256_BIT: return (IntSpecies) SPECIES_256; - case S_512_BIT: return (IntSpecies) SPECIES_512; - case S_Max_BIT: return (IntSpecies) SPECIES_MAX; + switch (s.switchKey) { + case VectorShape.SK_64_BIT: return (IntSpecies) SPECIES_64; + case VectorShape.SK_128_BIT: return (IntSpecies) SPECIES_128; + case VectorShape.SK_256_BIT: return (IntSpecies) SPECIES_256; + case VectorShape.SK_512_BIT: return (IntSpecies) SPECIES_512; + case VectorShape.SK_Max_BIT: return (IntSpecies) SPECIES_MAX; default: throw new IllegalArgumentException("Bad shape: " + s); } } diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LaneType.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LaneType.java index d402938f5b628d655d213636c22f685871377954..6abf9f4994783d9a89b28364df382632965cdf98 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LaneType.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LaneType.java @@ -95,10 +95,12 @@ enum LaneType { return printName; } + @ForceInline LaneType asIntegral() { return asIntegral.check(); } + @ForceInline LaneType asFloating() { if (asFloating == null) { throw badElementType(elementType, "either int or long, to reinterpret as float or double"); 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 81dbb215f0df0bfe3443c657dfbe12d8601a3af7..7a11c0005a4f47fb6497dd3cc4a52792a7ad3195 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -365,6 +365,12 @@ final class Long128Vector extends LongVector { return super.testTemplate(Long128Mask.class, op); // specialize } + @Override + @ForceInline + public final Long128Mask test(Test op, VectorMask m) { + return super.testTemplate(Long128Mask.class, op, (Long128Mask) m); // specialize + } + // Specialized comparisons @Override @@ -719,9 +725,9 @@ final class Long128Vector extends LongVector { @ForceInline /*package-private*/ static Long128Mask maskAll(boolean bit) { - return VectorSupport.broadcastCoerced(Long128Mask.class, long.class, VLENGTH, - (bit ? -1 : 0), null, - (v, __) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); + return VectorSupport.fromBitsCoerced(Long128Mask.class, long.class, VLENGTH, + (bit ? -1 : 0), MODE_BROADCAST, null, + (v, __) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); } private static final Long128Mask TRUE_MASK = new Long128Mask(true); private static final Long128Mask FALSE_MASK = new Long128Mask(false); 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 569bd91eafa3a3845d72383b2224ae5267c65fa2..ad4057dc07083bc2fca7390c6a9c407bd4ac82f9 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -365,6 +365,12 @@ final class Long256Vector extends LongVector { return super.testTemplate(Long256Mask.class, op); // specialize } + @Override + @ForceInline + public final Long256Mask test(Test op, VectorMask m) { + return super.testTemplate(Long256Mask.class, op, (Long256Mask) m); // specialize + } + // Specialized comparisons @Override @@ -723,9 +729,9 @@ final class Long256Vector extends LongVector { @ForceInline /*package-private*/ static Long256Mask maskAll(boolean bit) { - return VectorSupport.broadcastCoerced(Long256Mask.class, long.class, VLENGTH, - (bit ? -1 : 0), null, - (v, __) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); + return VectorSupport.fromBitsCoerced(Long256Mask.class, long.class, VLENGTH, + (bit ? -1 : 0), MODE_BROADCAST, null, + (v, __) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); } private static final Long256Mask TRUE_MASK = new Long256Mask(true); private static final Long256Mask FALSE_MASK = new Long256Mask(false); 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 543baf97d47127ff11f06cdb9872f6e51695a884..6f7bee397a15c8cedcee8fcd09e073d3d7486f63 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -365,6 +365,12 @@ final class Long512Vector extends LongVector { return super.testTemplate(Long512Mask.class, op); // specialize } + @Override + @ForceInline + public final Long512Mask test(Test op, VectorMask m) { + return super.testTemplate(Long512Mask.class, op, (Long512Mask) m); // specialize + } + // Specialized comparisons @Override @@ -731,9 +737,9 @@ final class Long512Vector extends LongVector { @ForceInline /*package-private*/ static Long512Mask maskAll(boolean bit) { - return VectorSupport.broadcastCoerced(Long512Mask.class, long.class, VLENGTH, - (bit ? -1 : 0), null, - (v, __) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); + return VectorSupport.fromBitsCoerced(Long512Mask.class, long.class, VLENGTH, + (bit ? -1 : 0), MODE_BROADCAST, null, + (v, __) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); } private static final Long512Mask TRUE_MASK = new Long512Mask(true); private static final Long512Mask FALSE_MASK = new Long512Mask(false); 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 328b399d59eb4c47b074427222f7e39a4c0ab5aa..e7ab1241f4e575016df0c938263ccfad2fb01b1f 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -365,6 +365,12 @@ final class Long64Vector extends LongVector { return super.testTemplate(Long64Mask.class, op); // specialize } + @Override + @ForceInline + public final Long64Mask test(Test op, VectorMask m) { + return super.testTemplate(Long64Mask.class, op, (Long64Mask) m); // specialize + } + // Specialized comparisons @Override @@ -717,9 +723,9 @@ final class Long64Vector extends LongVector { @ForceInline /*package-private*/ static Long64Mask maskAll(boolean bit) { - return VectorSupport.broadcastCoerced(Long64Mask.class, long.class, VLENGTH, - (bit ? -1 : 0), null, - (v, __) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); + return VectorSupport.fromBitsCoerced(Long64Mask.class, long.class, VLENGTH, + (bit ? -1 : 0), MODE_BROADCAST, null, + (v, __) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); } private static final Long64Mask TRUE_MASK = new Long64Mask(true); private static final Long64Mask FALSE_MASK = new Long64Mask(false); 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 23e9d9f3fb68eaec6ac2189d882314b6c0eb892f..56ce68f1fc327e48baec96480a4f33c911a61bf3 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -365,6 +365,12 @@ final class LongMaxVector extends LongVector { return super.testTemplate(LongMaxMask.class, op); // specialize } + @Override + @ForceInline + public final LongMaxMask test(Test op, VectorMask m) { + return super.testTemplate(LongMaxMask.class, op, (LongMaxMask) m); // specialize + } + // Specialized comparisons @Override @@ -717,9 +723,9 @@ final class LongMaxVector extends LongVector { @ForceInline /*package-private*/ static LongMaxMask maskAll(boolean bit) { - return VectorSupport.broadcastCoerced(LongMaxMask.class, long.class, VLENGTH, - (bit ? -1 : 0), null, - (v, __) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); + return VectorSupport.fromBitsCoerced(LongMaxMask.class, long.class, VLENGTH, + (bit ? -1 : 0), MODE_BROADCAST, null, + (v, __) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); } private static final LongMaxMask TRUE_MASK = new LongMaxMask(true); private static final LongMaxMask FALSE_MASK = new LongMaxMask(false); 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 b48778f5ec3a3252302b3f27336fe36cd9166d08..37ba71896791229a1a3189ae2cdb902f649b20d4 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -455,8 +455,8 @@ public abstract class LongVector extends AbstractVector { @ForceInline public static LongVector zero(VectorSpecies species) { LongSpecies vsp = (LongSpecies) species; - return VectorSupport.broadcastCoerced(vsp.vectorType(), long.class, species.length(), - 0, vsp, + return VectorSupport.fromBitsCoerced(vsp.vectorType(), long.class, species.length(), + 0, MODE_BROADCAST, vsp, ((bits_, s_) -> s_.rvOp(i -> bits_))); } @@ -1767,12 +1767,11 @@ public abstract class LongVector extends AbstractVector { M testTemplate(Class maskType, Test op) { LongSpecies vsp = vspecies(); if (opKind(op, VO_SPECIAL)) { - LongVector bits = this.viewAsIntegralLanes(); VectorMask m; if (op == IS_DEFAULT) { - m = bits.compare(EQ, (long) 0); + m = compare(EQ, (long) 0); } else if (op == IS_NEGATIVE) { - m = bits.compare(LT, (long) 0); + m = compare(LT, (long) 0); } else { throw new AssertionError(op); @@ -1787,11 +1786,31 @@ public abstract class LongVector extends AbstractVector { * {@inheritDoc} */ @Override - @ForceInline - public final + public abstract VectorMask test(VectorOperators.Test op, - VectorMask m) { - return test(op).and(m); + VectorMask m); + + /*package-private*/ + @ForceInline + final + > + M testTemplate(Class maskType, Test op, M mask) { + LongSpecies vsp = vspecies(); + mask.check(maskType, this); + if (opKind(op, VO_SPECIAL)) { + VectorMask m = mask; + if (op == IS_DEFAULT) { + m = compare(EQ, (long) 0, m); + } else if (op == IS_NEGATIVE) { + m = compare(LT, (long) 0, m); + } + else { + throw new AssertionError(op); + } + return maskType.cast(m); + } + int opc = opCode(op); + throw new AssertionError(op); } /** @@ -2460,7 +2479,8 @@ public abstract class LongVector extends AbstractVector { VectorMask m) { m.check(maskClass, this); if (op == FIRST_NONZERO) { - LongVector v = reduceIdentityVector(op).blend(this, m); + // FIXME: The JIT should handle this. + LongVector v = broadcast((long) 0).blend(this, m); return v.reduceLanesTemplate(op); } int opc = opCode(op); @@ -2475,10 +2495,11 @@ public abstract class LongVector extends AbstractVector { final long reduceLanesTemplate(VectorOperators.Associative op) { if (op == FIRST_NONZERO) { - // FIXME: The JIT should handle this, and other scan ops alos. + // FIXME: The JIT should handle this. VectorMask thisNZ = this.viewAsIntegralLanes().compare(NE, (long) 0); - return this.lane(thisNZ.firstTrue()); + int ft = thisNZ.firstTrue(); + return ft < length() ? this.lane(ft) : (long) 0; } int opc = opCode(op); return fromBits(VectorSupport.reductionCoerced( @@ -2511,34 +2532,6 @@ public abstract class LongVector extends AbstractVector { } } - private - @ForceInline - LongVector reduceIdentityVector(VectorOperators.Associative op) { - int opc = opCode(op); - UnaryOperator fn - = REDUCE_ID_IMPL.find(op, opc, (opc_) -> { - switch (opc_) { - case VECTOR_OP_ADD: - case VECTOR_OP_OR: - case VECTOR_OP_XOR: - return v -> v.broadcast(0); - case VECTOR_OP_MUL: - return v -> v.broadcast(1); - case VECTOR_OP_AND: - return v -> v.broadcast(-1); - case VECTOR_OP_MIN: - return v -> v.broadcast(MAX_OR_INF); - case VECTOR_OP_MAX: - return v -> v.broadcast(MIN_OR_INF); - default: return null; - } - }); - return fn.apply(this); - } - private static final - ImplCache> REDUCE_ID_IMPL - = new ImplCache<>(Associative.class, LongVector.class); - private static final long MIN_OR_INF = Long.MIN_VALUE; private static final long MAX_OR_INF = Long.MAX_VALUE; @@ -3809,9 +3802,9 @@ public abstract class LongVector extends AbstractVector { @ForceInline final LongVector broadcastBits(long bits) { return (LongVector) - VectorSupport.broadcastCoerced( + VectorSupport.fromBitsCoerced( vectorType, long.class, laneCount, - bits, this, + bits, MODE_BROADCAST, this, (bits_, s_) -> s_.rvOp(i -> bits_)); } @@ -3994,12 +3987,12 @@ public abstract class LongVector extends AbstractVector { */ static LongSpecies species(VectorShape s) { Objects.requireNonNull(s); - switch (s) { - case S_64_BIT: return (LongSpecies) SPECIES_64; - case S_128_BIT: return (LongSpecies) SPECIES_128; - case S_256_BIT: return (LongSpecies) SPECIES_256; - case S_512_BIT: return (LongSpecies) SPECIES_512; - case S_Max_BIT: return (LongSpecies) SPECIES_MAX; + switch (s.switchKey) { + case VectorShape.SK_64_BIT: return (LongSpecies) SPECIES_64; + case VectorShape.SK_128_BIT: return (LongSpecies) SPECIES_128; + case VectorShape.SK_256_BIT: return (LongSpecies) SPECIES_256; + case VectorShape.SK_512_BIT: return (LongSpecies) SPECIES_512; + case VectorShape.SK_Max_BIT: return (LongSpecies) SPECIES_MAX; default: throw new IllegalArgumentException("Bad shape: " + s); } } 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 cd52dc003b6b8ab589785bf41769debbe6fc62d3..ce7e3ca8c1826255a878a16a2e6e8c47882420be 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -370,6 +370,12 @@ final class Short128Vector extends ShortVector { return super.testTemplate(Short128Mask.class, op); // specialize } + @Override + @ForceInline + public final Short128Mask test(Test op, VectorMask m) { + return super.testTemplate(Short128Mask.class, op, (Short128Mask) m); // specialize + } + // Specialized comparisons @Override @@ -741,9 +747,9 @@ final class Short128Vector extends ShortVector { @ForceInline /*package-private*/ static Short128Mask maskAll(boolean bit) { - return VectorSupport.broadcastCoerced(Short128Mask.class, short.class, VLENGTH, - (bit ? -1 : 0), null, - (v, __) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); + return VectorSupport.fromBitsCoerced(Short128Mask.class, short.class, VLENGTH, + (bit ? -1 : 0), MODE_BROADCAST, null, + (v, __) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); } private static final Short128Mask TRUE_MASK = new Short128Mask(true); private static final Short128Mask FALSE_MASK = new Short128Mask(false); 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 66f6d409e6aed546271d27f5313c42220661209e..3d7b00ddcd0f00b0ff98d0602a77ee747cb6203b 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -370,6 +370,12 @@ final class Short256Vector extends ShortVector { return super.testTemplate(Short256Mask.class, op); // specialize } + @Override + @ForceInline + public final Short256Mask test(Test op, VectorMask m) { + return super.testTemplate(Short256Mask.class, op, (Short256Mask) m); // specialize + } + // Specialized comparisons @Override @@ -757,9 +763,9 @@ final class Short256Vector extends ShortVector { @ForceInline /*package-private*/ static Short256Mask maskAll(boolean bit) { - return VectorSupport.broadcastCoerced(Short256Mask.class, short.class, VLENGTH, - (bit ? -1 : 0), null, - (v, __) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); + return VectorSupport.fromBitsCoerced(Short256Mask.class, short.class, VLENGTH, + (bit ? -1 : 0), MODE_BROADCAST, null, + (v, __) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); } private static final Short256Mask TRUE_MASK = new Short256Mask(true); private static final Short256Mask FALSE_MASK = new Short256Mask(false); 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 a2a8a07ddd3eddbe084fe6a8569c5645b12b941a..2d23dcae93fadecf6b9dde444b634c0398452cc5 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -370,6 +370,12 @@ final class Short512Vector extends ShortVector { return super.testTemplate(Short512Mask.class, op); // specialize } + @Override + @ForceInline + public final Short512Mask test(Test op, VectorMask m) { + return super.testTemplate(Short512Mask.class, op, (Short512Mask) m); // specialize + } + // Specialized comparisons @Override @@ -789,9 +795,9 @@ final class Short512Vector extends ShortVector { @ForceInline /*package-private*/ static Short512Mask maskAll(boolean bit) { - return VectorSupport.broadcastCoerced(Short512Mask.class, short.class, VLENGTH, - (bit ? -1 : 0), null, - (v, __) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); + return VectorSupport.fromBitsCoerced(Short512Mask.class, short.class, VLENGTH, + (bit ? -1 : 0), MODE_BROADCAST, null, + (v, __) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); } private static final Short512Mask TRUE_MASK = new Short512Mask(true); private static final Short512Mask FALSE_MASK = new Short512Mask(false); 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 ff2b2d7e063f3736f9f6b674770f4ada350aa4d6..f7e0c0162d311ae21b02b87e2680800b638215de 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -370,6 +370,12 @@ final class Short64Vector extends ShortVector { return super.testTemplate(Short64Mask.class, op); // specialize } + @Override + @ForceInline + public final Short64Mask test(Test op, VectorMask m) { + return super.testTemplate(Short64Mask.class, op, (Short64Mask) m); // specialize + } + // Specialized comparisons @Override @@ -733,9 +739,9 @@ final class Short64Vector extends ShortVector { @ForceInline /*package-private*/ static Short64Mask maskAll(boolean bit) { - return VectorSupport.broadcastCoerced(Short64Mask.class, short.class, VLENGTH, - (bit ? -1 : 0), null, - (v, __) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); + return VectorSupport.fromBitsCoerced(Short64Mask.class, short.class, VLENGTH, + (bit ? -1 : 0), MODE_BROADCAST, null, + (v, __) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); } private static final Short64Mask TRUE_MASK = new Short64Mask(true); private static final Short64Mask FALSE_MASK = new Short64Mask(false); 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 7aa01264a738deb58b1137119745700289a8fcd6..154096d9d6f6c2d1664cc5617db41840481fbf3b 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -370,6 +370,12 @@ final class ShortMaxVector extends ShortVector { return super.testTemplate(ShortMaxMask.class, op); // specialize } + @Override + @ForceInline + public final ShortMaxMask test(Test op, VectorMask m) { + return super.testTemplate(ShortMaxMask.class, op, (ShortMaxMask) m); // specialize + } + // Specialized comparisons @Override @@ -727,9 +733,9 @@ final class ShortMaxVector extends ShortVector { @ForceInline /*package-private*/ static ShortMaxMask maskAll(boolean bit) { - return VectorSupport.broadcastCoerced(ShortMaxMask.class, short.class, VLENGTH, - (bit ? -1 : 0), null, - (v, __) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); + return VectorSupport.fromBitsCoerced(ShortMaxMask.class, short.class, VLENGTH, + (bit ? -1 : 0), MODE_BROADCAST, null, + (v, __) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); } private static final ShortMaxMask TRUE_MASK = new ShortMaxMask(true); private static final ShortMaxMask FALSE_MASK = new ShortMaxMask(false); 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 e1cada48f17ac18350bd8e015133628a646a57d2..8c6dd4718f75a5d022d9d01c83f1a62bfd37b0f0 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -455,8 +455,8 @@ public abstract class ShortVector extends AbstractVector { @ForceInline public static ShortVector zero(VectorSpecies species) { ShortSpecies vsp = (ShortSpecies) species; - return VectorSupport.broadcastCoerced(vsp.vectorType(), short.class, species.length(), - 0, vsp, + return VectorSupport.fromBitsCoerced(vsp.vectorType(), short.class, species.length(), + 0, MODE_BROADCAST, vsp, ((bits_, s_) -> s_.rvOp(i -> bits_))); } @@ -1855,12 +1855,11 @@ public abstract class ShortVector extends AbstractVector { M testTemplate(Class maskType, Test op) { ShortSpecies vsp = vspecies(); if (opKind(op, VO_SPECIAL)) { - ShortVector bits = this.viewAsIntegralLanes(); VectorMask m; if (op == IS_DEFAULT) { - m = bits.compare(EQ, (short) 0); + m = compare(EQ, (short) 0); } else if (op == IS_NEGATIVE) { - m = bits.compare(LT, (short) 0); + m = compare(LT, (short) 0); } else { throw new AssertionError(op); @@ -1875,11 +1874,31 @@ public abstract class ShortVector extends AbstractVector { * {@inheritDoc} */ @Override - @ForceInline - public final + public abstract VectorMask test(VectorOperators.Test op, - VectorMask m) { - return test(op).and(m); + VectorMask m); + + /*package-private*/ + @ForceInline + final + > + M testTemplate(Class maskType, Test op, M mask) { + ShortSpecies vsp = vspecies(); + mask.check(maskType, this); + if (opKind(op, VO_SPECIAL)) { + VectorMask m = mask; + if (op == IS_DEFAULT) { + m = compare(EQ, (short) 0, m); + } else if (op == IS_NEGATIVE) { + m = compare(LT, (short) 0, m); + } + else { + throw new AssertionError(op); + } + return maskType.cast(m); + } + int opc = opCode(op); + throw new AssertionError(op); } /** @@ -2595,7 +2614,8 @@ public abstract class ShortVector extends AbstractVector { VectorMask m) { m.check(maskClass, this); if (op == FIRST_NONZERO) { - ShortVector v = reduceIdentityVector(op).blend(this, m); + // FIXME: The JIT should handle this. + ShortVector v = broadcast((short) 0).blend(this, m); return v.reduceLanesTemplate(op); } int opc = opCode(op); @@ -2610,10 +2630,11 @@ public abstract class ShortVector extends AbstractVector { final short reduceLanesTemplate(VectorOperators.Associative op) { if (op == FIRST_NONZERO) { - // FIXME: The JIT should handle this, and other scan ops alos. + // FIXME: The JIT should handle this. VectorMask thisNZ = this.viewAsIntegralLanes().compare(NE, (short) 0); - return this.lane(thisNZ.firstTrue()); + int ft = thisNZ.firstTrue(); + return ft < length() ? this.lane(ft) : (short) 0; } int opc = opCode(op); return fromBits(VectorSupport.reductionCoerced( @@ -2646,34 +2667,6 @@ public abstract class ShortVector extends AbstractVector { } } - private - @ForceInline - ShortVector reduceIdentityVector(VectorOperators.Associative op) { - int opc = opCode(op); - UnaryOperator fn - = REDUCE_ID_IMPL.find(op, opc, (opc_) -> { - switch (opc_) { - case VECTOR_OP_ADD: - case VECTOR_OP_OR: - case VECTOR_OP_XOR: - return v -> v.broadcast(0); - case VECTOR_OP_MUL: - return v -> v.broadcast(1); - case VECTOR_OP_AND: - return v -> v.broadcast(-1); - case VECTOR_OP_MIN: - return v -> v.broadcast(MAX_OR_INF); - case VECTOR_OP_MAX: - return v -> v.broadcast(MIN_OR_INF); - default: return null; - } - }); - return fn.apply(this); - } - private static final - ImplCache> REDUCE_ID_IMPL - = new ImplCache<>(Associative.class, ShortVector.class); - private static final short MIN_OR_INF = Short.MIN_VALUE; private static final short MAX_OR_INF = Short.MAX_VALUE; @@ -4143,9 +4136,9 @@ public abstract class ShortVector extends AbstractVector { @ForceInline final ShortVector broadcastBits(long bits) { return (ShortVector) - VectorSupport.broadcastCoerced( + VectorSupport.fromBitsCoerced( vectorType, short.class, laneCount, - bits, this, + bits, MODE_BROADCAST, this, (bits_, s_) -> s_.rvOp(i -> bits_)); } @@ -4337,12 +4330,12 @@ public abstract class ShortVector extends AbstractVector { */ static ShortSpecies species(VectorShape s) { Objects.requireNonNull(s); - switch (s) { - case S_64_BIT: return (ShortSpecies) SPECIES_64; - case S_128_BIT: return (ShortSpecies) SPECIES_128; - case S_256_BIT: return (ShortSpecies) SPECIES_256; - case S_512_BIT: return (ShortSpecies) SPECIES_512; - case S_Max_BIT: return (ShortSpecies) SPECIES_MAX; + switch (s.switchKey) { + case VectorShape.SK_64_BIT: return (ShortSpecies) SPECIES_64; + case VectorShape.SK_128_BIT: return (ShortSpecies) SPECIES_128; + case VectorShape.SK_256_BIT: return (ShortSpecies) SPECIES_256; + case VectorShape.SK_512_BIT: return (ShortSpecies) SPECIES_512; + case VectorShape.SK_Max_BIT: return (ShortSpecies) SPECIES_MAX; default: throw new IllegalArgumentException("Bad shape: " + s); } } diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/VectorMask.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/VectorMask.java index b57a2abbb1f1600728cbcf4db048ab295ad2a447..506535d030f99b202dccd69475f32c7e99ae837a 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/VectorMask.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/VectorMask.java @@ -237,26 +237,25 @@ public abstract class VectorMask extends jdk.internal.vm.vector.VectorSupport */ @ForceInline public static VectorMask fromLong(VectorSpecies species, long bits) { - AbstractSpecies vspecies = (AbstractSpecies) species; - int laneCount = vspecies.laneCount(); - if (laneCount < Long.SIZE) { - int extraSignBits = Long.SIZE - laneCount; - bits <<= extraSignBits; - bits >>= extraSignBits; - } - if (bits == (bits >> 1)) { - // Special case. - assert(bits == 0 || bits == -1); - return vspecies.maskAll(bits != 0); - } - // FIXME: Intrinsify this. - long shifted = bits; - boolean[] a = new boolean[laneCount]; - for (int i = 0; i < a.length; i++) { - a[i] = ((shifted & 1) != 0); - shifted >>= 1; // replicate sign bit - } - return fromValues(vspecies, a); + AbstractSpecies vsp = (AbstractSpecies) species; + bits = bits & (0xFFFFFFFFFFFFFFFFL >>> (64 - vsp.laneCount())); + return VectorSupport.fromBitsCoerced(vsp.maskType(), vsp.elementType(), vsp.laneCount(), bits, + VectorSupport.MODE_BITS_COERCED_LONG_TO_MASK, vsp, + (m, s) -> { + if (m == (m >> 1)) { + // Special case. + assert(m == 0 || m == -1); + return s.maskAll(m != 0); + } + + long shifted = m; + boolean[] a = new boolean[s.laneCount()]; + for (int i = 0; i < a.length; i++) { + a[i] = ((shifted & 1) != 0); + shifted >>= 1; // replicate sign bit + } + return fromValues(s, a); + }); } /** 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 45c2cf9267c798f6a4f6d33b748ac7a0d8b33ce6..6c5ed6b9c13fd6b66c7001c10544e235a89dee43 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -470,12 +470,12 @@ public abstract class $abstractvectortype$ extends AbstractVector<$Boxtype$> { public static $abstractvectortype$ zero(VectorSpecies<$Boxtype$> species) { $Type$Species vsp = ($Type$Species) species; #if[FP] - return VectorSupport.broadcastCoerced(vsp.vectorType(), $type$.class, species.length(), - toBits(0.0f), vsp, + return VectorSupport.fromBitsCoerced(vsp.vectorType(), $type$.class, species.length(), + toBits(0.0f), MODE_BROADCAST, vsp, ((bits_, s_) -> s_.rvOp(i -> bits_))); #else[FP] - return VectorSupport.broadcastCoerced(vsp.vectorType(), $type$.class, species.length(), - 0, vsp, + return VectorSupport.fromBitsCoerced(vsp.vectorType(), $type$.class, species.length(), + 0, MODE_BROADCAST, vsp, ((bits_, s_) -> s_.rvOp(i -> bits_))); #end[FP] } @@ -2128,12 +2128,14 @@ public abstract class $abstractvectortype$ extends AbstractVector<$Boxtype$> { M testTemplate(Class maskType, Test op) { $Type$Species vsp = vspecies(); if (opKind(op, VO_SPECIAL)) { +#if[FP] $Bitstype$Vector bits = this.viewAsIntegralLanes(); +#end[FP] VectorMask<$Boxbitstype$> m; if (op == IS_DEFAULT) { - m = bits.compare(EQ, ($bitstype$) 0); + m = {#if[FP]?bits.}compare(EQ, ($bitstype$) 0); } else if (op == IS_NEGATIVE) { - m = bits.compare(LT, ($bitstype$) 0); + m = {#if[FP]?bits.}compare(LT, ($bitstype$) 0); } #if[FP] else if (op == IS_FINITE || @@ -2156,7 +2158,7 @@ public abstract class $abstractvectortype$ extends AbstractVector<$Boxtype$> { else { throw new AssertionError(op); } - return maskType.cast(m{#if[FP]?.cast(this.vspecies())}); + return maskType.cast(m{#if[FP]?.cast(vsp)}); } int opc = opCode(op); throw new AssertionError(op); @@ -2166,11 +2168,54 @@ public abstract class $abstractvectortype$ extends AbstractVector<$Boxtype$> { * {@inheritDoc} */ @Override - @ForceInline - public final + public abstract VectorMask<$Boxtype$> test(VectorOperators.Test op, - VectorMask<$Boxtype$> m) { - return test(op).and(m); + VectorMask<$Boxtype$> m); + + /*package-private*/ + @ForceInline + final + > + M testTemplate(Class maskType, Test op, M mask) { + $Type$Species vsp = vspecies(); + mask.check(maskType, this); + if (opKind(op, VO_SPECIAL)) { +#if[FP] + $Bitstype$Vector bits = this.viewAsIntegralLanes(); + VectorMask<$Boxbitstype$> m = mask.cast($Bitstype$Vector.species(shape())); +#else[FP] + VectorMask<$Boxbitstype$> m = mask; +#end[FP] + if (op == IS_DEFAULT) { + m = {#if[FP]?bits.}compare(EQ, ($bitstype$) 0, m); + } else if (op == IS_NEGATIVE) { + m = {#if[FP]?bits.}compare(LT, ($bitstype$) 0, m); + } +#if[FP] + else if (op == IS_FINITE || + op == IS_NAN || + op == IS_INFINITE) { + // first kill the sign: + bits = bits.and($Boxbitstype$.MAX_VALUE); + // next find the bit pattern for infinity: + $bitstype$ infbits = ($bitstype$) toBits($Boxtype$.POSITIVE_INFINITY); + // now compare: + if (op == IS_FINITE) { + m = bits.compare(LT, infbits, m); + } else if (op == IS_NAN) { + m = bits.compare(GT, infbits, m); + } else { + m = bits.compare(EQ, infbits, m); + } + } +#end[FP] + else { + throw new AssertionError(op); + } + return maskType.cast(m{#if[FP]?.cast(vsp)}); + } + int opc = opCode(op); + throw new AssertionError(op); } /** @@ -3021,7 +3066,8 @@ public abstract class $abstractvectortype$ extends AbstractVector<$Boxtype$> { VectorMask<$Boxtype$> m) { m.check(maskClass, this); if (op == FIRST_NONZERO) { - $abstractvectortype$ v = reduceIdentityVector(op).blend(this, m); + // FIXME: The JIT should handle this. + $abstractvectortype$ v = broadcast(($type$) 0).blend(this, m); return v.reduceLanesTemplate(op); } int opc = opCode(op); @@ -3036,10 +3082,11 @@ public abstract class $abstractvectortype$ extends AbstractVector<$Boxtype$> { final $type$ reduceLanesTemplate(VectorOperators.Associative op) { if (op == FIRST_NONZERO) { - // FIXME: The JIT should handle this, and other scan ops alos. + // FIXME: The JIT should handle this. VectorMask<$Boxbitstype$> thisNZ = this.viewAsIntegralLanes().compare(NE, ($bitstype$) 0); - return this.lane(thisNZ.firstTrue()); + int ft = thisNZ.firstTrue(); + return ft < length() ? this.lane(ft) : ($type$) 0; } int opc = opCode(op); return fromBits(VectorSupport.reductionCoerced( @@ -3074,38 +3121,6 @@ public abstract class $abstractvectortype$ extends AbstractVector<$Boxtype$> { } } - private - @ForceInline - $abstractvectortype$ reduceIdentityVector(VectorOperators.Associative op) { - int opc = opCode(op); - UnaryOperator<$abstractvectortype$> fn - = REDUCE_ID_IMPL.find(op, opc, (opc_) -> { - switch (opc_) { - case VECTOR_OP_ADD: -#if[BITWISE] - case VECTOR_OP_OR: - case VECTOR_OP_XOR: -#end[BITWISE] - return v -> v.broadcast(0); - case VECTOR_OP_MUL: - return v -> v.broadcast(1); -#if[BITWISE] - case VECTOR_OP_AND: - return v -> v.broadcast(-1); -#end[BITWISE] - case VECTOR_OP_MIN: - return v -> v.broadcast(MAX_OR_INF); - case VECTOR_OP_MAX: - return v -> v.broadcast(MIN_OR_INF); - default: return null; - } - }); - return fn.apply(this); - } - private static final - ImplCache> REDUCE_ID_IMPL - = new ImplCache<>(Associative.class, $Type$Vector.class); - #if[FP] private static final $type$ MIN_OR_INF = $Boxtype$.NEGATIVE_INFINITY; private static final $type$ MAX_OR_INF = $Boxtype$.POSITIVE_INFINITY; @@ -5327,9 +5342,9 @@ public abstract class $abstractvectortype$ extends AbstractVector<$Boxtype$> { @ForceInline final $abstractvectortype$ broadcastBits(long bits) { return ($abstractvectortype$) - VectorSupport.broadcastCoerced( + VectorSupport.fromBitsCoerced( vectorType, $type$.class, laneCount, - bits, this, + bits, MODE_BROADCAST, this, (bits_, s_) -> s_.rvOp(i -> bits_)); } @@ -5528,12 +5543,12 @@ public abstract class $abstractvectortype$ extends AbstractVector<$Boxtype$> { */ static $Type$Species species(VectorShape s) { Objects.requireNonNull(s); - switch (s) { - case S_64_BIT: return ($Type$Species) SPECIES_64; - case S_128_BIT: return ($Type$Species) SPECIES_128; - case S_256_BIT: return ($Type$Species) SPECIES_256; - case S_512_BIT: return ($Type$Species) SPECIES_512; - case S_Max_BIT: return ($Type$Species) SPECIES_MAX; + switch (s.switchKey) { + case VectorShape.SK_64_BIT: return ($Type$Species) SPECIES_64; + case VectorShape.SK_128_BIT: return ($Type$Species) SPECIES_128; + case VectorShape.SK_256_BIT: return ($Type$Species) SPECIES_256; + case VectorShape.SK_512_BIT: return ($Type$Species) SPECIES_512; + case VectorShape.SK_Max_BIT: return ($Type$Species) SPECIES_MAX; default: throw new IllegalArgumentException("Bad shape: " + s); } } 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 df15c85fcccc301c668efa9d2dde61da4c11b6a3..ec6e714f218507cf78533016960837d34ec7d52c 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -374,6 +374,12 @@ final class $vectortype$ extends $abstractvectortype$ { return super.testTemplate($masktype$.class, op); // specialize } + @Override + @ForceInline + public final $masktype$ test(Test op, VectorMask<$Boxtype$> m) { + return super.testTemplate($masktype$.class, op, ($masktype$) m); // specialize + } + // Specialized comparisons @Override @@ -1000,9 +1006,9 @@ final class $vectortype$ extends $abstractvectortype$ { @ForceInline /*package-private*/ static $masktype$ maskAll(boolean bit) { - return VectorSupport.broadcastCoerced($masktype$.class, $bitstype$.class, VLENGTH, - (bit ? -1 : 0), null, - (v, __) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); + return VectorSupport.fromBitsCoerced($masktype$.class, $bitstype$.class, VLENGTH, + (bit ? -1 : 0), MODE_BROADCAST, null, + (v, __) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); } private static final $masktype$ TRUE_MASK = new $masktype$(true); private static final $masktype$ FALSE_MASK = new $masktype$(false); diff --git a/src/jdk.internal.jvmstat/share/classes/sun/jvmstat/monitor/HostIdentifier.java b/src/jdk.internal.jvmstat/share/classes/sun/jvmstat/monitor/HostIdentifier.java index b80fccaf52f0317175294f100f160bb570388e1e..c7472e75abd70f99105add54b42f67de159a6cef 100644 --- a/src/jdk.internal.jvmstat/share/classes/sun/jvmstat/monitor/HostIdentifier.java +++ b/src/jdk.internal.jvmstat/share/classes/sun/jvmstat/monitor/HostIdentifier.java @@ -106,7 +106,7 @@ public class HostIdentifier { * by the string. */ private URI canonicalize(String uriString) throws URISyntaxException { - if ((uriString == null) || (uriString.compareTo("localhost") == 0)) { + if (uriString == null || uriString.equals("localhost")) { uriString = "//localhost"; return new URI(uriString); } @@ -247,7 +247,7 @@ public class HostIdentifier { String authority = vmid.getAuthority(); // check for 'file:' VmIdentifiers and handled as a special case. - if ((scheme != null) && (scheme.compareTo("file") == 0)) { + if ("file".equals(scheme)) { try { uri = new URI("file://localhost"); } catch (URISyntaxException e) { }; @@ -343,7 +343,7 @@ public class HostIdentifier { String host = vmid.getHost(); String authority = vmid.getAuthority(); - if ((scheme != null) && (scheme.compareTo("file") == 0)) { + if ("file".equals(scheme)) { // don't attempt to resolve a file based VmIdentifier. return vmid; } diff --git a/src/jdk.internal.jvmstat/share/classes/sun/jvmstat/monitor/MonitoredHost.java b/src/jdk.internal.jvmstat/share/classes/sun/jvmstat/monitor/MonitoredHost.java index b119a00452090e7be232148659346fe1d685a3b9..12969fa670ed2524588d97590764e49ce46b33ec 100644 --- a/src/jdk.internal.jvmstat/share/classes/sun/jvmstat/monitor/MonitoredHost.java +++ b/src/jdk.internal.jvmstat/share/classes/sun/jvmstat/monitor/MonitoredHost.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 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 @@ -203,7 +203,7 @@ public abstract class MonitoredHost { assert hostname != null; if (scheme == null) { - if (hostname.compareTo("localhost") == 0) { + if (hostname.equals("localhost")) { scheme = LOCAL_PROTOCOL; } else { scheme = REMOTE_PROTOCOL; diff --git a/src/jdk.internal.jvmstat/share/classes/sun/jvmstat/monitor/MonitoredVmUtil.java b/src/jdk.internal.jvmstat/share/classes/sun/jvmstat/monitor/MonitoredVmUtil.java index 7c1149bdc34fb3f851738627679cc6ec62d3836b..81e1e962077bfdb6e35419b60b75349dbf32d05c 100644 --- a/src/jdk.internal.jvmstat/share/classes/sun/jvmstat/monitor/MonitoredVmUtil.java +++ b/src/jdk.internal.jvmstat/share/classes/sun/jvmstat/monitor/MonitoredVmUtil.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 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 @@ -82,7 +82,7 @@ public class MonitoredVmUtil { int firstSpace = commandLine.indexOf(' '); if (firstSpace > 0) { return commandLine.substring(firstSpace + 1); - } else if (commandLine.compareTo("Unknown") == 0) { + } else if (commandLine.equals("Unknown")) { return commandLine; } else { return null; diff --git a/src/jdk.internal.jvmstat/share/classes/sun/jvmstat/monitor/VmIdentifier.java b/src/jdk.internal.jvmstat/share/classes/sun/jvmstat/monitor/VmIdentifier.java index 6e7f1cc1f77e242bc532d69e5869d44f5fdd2bc7..da484b1c87859d21f5c69dfb33a5dd223b652228 100644 --- a/src/jdk.internal.jvmstat/share/classes/sun/jvmstat/monitor/VmIdentifier.java +++ b/src/jdk.internal.jvmstat/share/classes/sun/jvmstat/monitor/VmIdentifier.java @@ -174,7 +174,7 @@ public class VmIdentifier { private void validate() throws URISyntaxException { // file:// uri, which is a special case where the lvmid is not required. String s = getScheme(); - if ((s != null) && (s.compareTo("file") == 0)) { + if ("file".equals(s)) { return; } if (getLocalVmId() == -1) { diff --git a/src/jdk.internal.jvmstat/share/classes/sun/jvmstat/perfdata/monitor/AliasFileParser.java b/src/jdk.internal.jvmstat/share/classes/sun/jvmstat/perfdata/monitor/AliasFileParser.java index 3a4134bc6f957bb27511f81172084e7672a0f229..3b5d35eafbfdf8c38c14f532076b54338383f328 100644 --- a/src/jdk.internal.jvmstat/share/classes/sun/jvmstat/perfdata/monitor/AliasFileParser.java +++ b/src/jdk.internal.jvmstat/share/classes/sun/jvmstat/perfdata/monitor/AliasFileParser.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 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 @@ -28,7 +28,6 @@ package sun.jvmstat.perfdata.monitor; import java.net.*; import java.io.*; import java.util.*; -import java.util.regex.*; /** * Class for parsing alias files. File format is expected to follow @@ -127,7 +126,7 @@ public class AliasFileParser { while (currentToken.ttype != StreamTokenizer.TT_EOF) { // look for the start symbol if ((currentToken.ttype != StreamTokenizer.TT_WORD) - || (currentToken.sval.compareTo(ALIAS) != 0)) { + || !currentToken.sval.equals(ALIAS)) { nextToken(); continue; } @@ -143,7 +142,7 @@ public class AliasFileParser { match(StreamTokenizer.TT_WORD); } while ((currentToken.ttype != StreamTokenizer.TT_EOF) - && (currentToken.sval.compareTo(ALIAS) != 0)); + && !currentToken.sval.equals(ALIAS)); map.put(name, aliases); } diff --git a/src/jdk.internal.jvmstat/share/classes/sun/jvmstat/perfdata/monitor/protocol/file/PerfDataBuffer.java b/src/jdk.internal.jvmstat/share/classes/sun/jvmstat/perfdata/monitor/protocol/file/PerfDataBuffer.java index 9e42ac4f4d81279b04beb04e4a4ba750943df768..e6feb5759c7c047c72968d4df0a833107fa10b7f 100644 --- a/src/jdk.internal.jvmstat/share/classes/sun/jvmstat/perfdata/monitor/protocol/file/PerfDataBuffer.java +++ b/src/jdk.internal.jvmstat/share/classes/sun/jvmstat/perfdata/monitor/protocol/file/PerfDataBuffer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 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 @@ -28,7 +28,6 @@ package sun.jvmstat.perfdata.monitor.protocol.file; import sun.jvmstat.monitor.*; import sun.jvmstat.perfdata.monitor.*; import java.io.*; -import java.net.URI; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; @@ -60,9 +59,9 @@ public class PerfDataBuffer extends AbstractPerfDataBuffer { FileChannel fc = new RandomAccessFile(f, mode).getChannel(); ByteBuffer bb = null; - if (mode.compareTo("r") == 0) { + if (mode.equals("r")) { bb = fc.map(FileChannel.MapMode.READ_ONLY, 0L, (int)fc.size()); - } else if (mode.compareTo("rw") == 0) { + } else if (mode.equals("rw")) { bb = fc.map(FileChannel.MapMode.READ_WRITE, 0L, (int)fc.size()); } else { throw new IllegalArgumentException("Invalid mode: " + mode); diff --git a/src/jdk.internal.jvmstat/share/classes/sun/jvmstat/perfdata/monitor/v1_0/PerfDataBuffer.java b/src/jdk.internal.jvmstat/share/classes/sun/jvmstat/perfdata/monitor/v1_0/PerfDataBuffer.java index d9f981e7de0e9c0bbfd192d7253eb7eb99183c79..60c512b9e41f53aa8baa15ad384d04eeaaf6f2c7 100644 --- a/src/jdk.internal.jvmstat/share/classes/sun/jvmstat/perfdata/monitor/v1_0/PerfDataBuffer.java +++ b/src/jdk.internal.jvmstat/share/classes/sun/jvmstat/perfdata/monitor/v1_0/PerfDataBuffer.java @@ -28,7 +28,6 @@ package sun.jvmstat.perfdata.monitor.v1_0; import sun.jvmstat.monitor.*; import sun.jvmstat.perfdata.monitor.*; import java.util.*; -import java.util.regex.*; import java.nio.*; /** @@ -360,7 +359,7 @@ public class PerfDataBuffer extends PerfDataBufferImpl { String cname = "hotspot.gc.collector.0.name"; StringMonitor collector = (StringMonitor)map.get(cname); - if (collector.stringValue().compareTo("PSScavenge") == 0) { + if (collector.stringValue().equals("PSScavenge")) { boolean adaptiveSizePolicy = true; /* diff --git a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/impl/AbstractTerminal.java b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/impl/AbstractTerminal.java index e92233c7b4f47f38f9a62a44b0ef200a0019d3c3..8a464a6726565253e566669032766edcc0b0fd45 100644 --- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/impl/AbstractTerminal.java +++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/impl/AbstractTerminal.java @@ -55,7 +55,7 @@ public abstract class AbstractTerminal implements Terminal { public AbstractTerminal(String name, String type, Charset encoding, SignalHandler signalHandler) throws IOException { this.name = name; this.type = type != null ? type : "ansi"; - this.encoding = encoding != null ? encoding : Charset.defaultCharset(); + this.encoding = encoding != null ? encoding : System.out.charset(); for (Signal signal : Signal.values()) { handlers.put(signal, signalHandler); } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.aarch64/src/jdk/vm/ci/aarch64/AArch64.java b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.aarch64/src/jdk/vm/ci/aarch64/AArch64.java index c2a7fa2b5cd9f124b4dd22811ae1e30751dc9a87..a4b5ba3ffa5da4579537f9185a1d3c55c979455e 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.aarch64/src/jdk/vm/ci/aarch64/AArch64.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.aarch64/src/jdk/vm/ci/aarch64/AArch64.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -177,6 +177,7 @@ public class AArch64 extends Architecture { SHA3, SHA512, SVE, + PACA, SVE2, STXR_PREFETCH, A53MAC, diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/MemoryBarriers.java b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/MemoryBarriers.java index 074882c9054fcd3e0dd91899a268174ab7639ac7..08bc0856d3ed664774d1d0cd79ff54ecb71f04a5 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/MemoryBarriers.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/MemoryBarriers.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 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 diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/CompilerToVM.java b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/CompilerToVM.java index 50f35021ac8ae272b771331165c5fa9666cf5856..2c9097839b6bc560c4f6f4d5b342ceaa7e8f3f35 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/CompilerToVM.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/CompilerToVM.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 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 @@ -849,7 +849,7 @@ final class CompilerToVM { /** * @see HotSpotJVMCIRuntime#translate(Object) */ - native long translate(Object obj); + native long translate(Object obj, boolean callPostTranslation); /** * @see HotSpotJVMCIRuntime#unhand(Class, long) diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotCallingConventionType.java b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotCallingConventionType.java index b554f17397228af599fe85d9c069c5e76ebda550..3a6f28ce2a9ef588aca63abf96f1c086df27e98b 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotCallingConventionType.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotCallingConventionType.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2016, Oracle and/or its affiliates. All rights reserved. + * 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 diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotCodeCacheProvider.java b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotCodeCacheProvider.java index 6c642e84bbd027c6eddaf6893cd182c7898d0514..6dfca075566530714d35c2e7d17edc21c10fdf0b 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotCodeCacheProvider.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotCodeCacheProvider.java @@ -109,22 +109,12 @@ public class HotSpotCodeCacheProvider implements CodeCacheProvider { HotSpotCompiledCode hsCompiledCode = (HotSpotCompiledCode) compiledCode; String name = hsCompiledCode.getName(); HotSpotCompiledNmethod hsCompiledNmethod = null; - if (method == null) { - // Must be a stub - resultInstalledCode = new HotSpotRuntimeStub(name); - } else { - hsCompiledNmethod = (HotSpotCompiledNmethod) hsCompiledCode; - HotSpotResolvedJavaMethodImpl hsMethod = (HotSpotResolvedJavaMethodImpl) method; - resultInstalledCode = new HotSpotNmethod(hsMethod, name, isDefault, hsCompiledNmethod.id); - } - HotSpotSpeculationLog speculationLog = null; if (log != null) { if (log.hasSpeculations()) { speculationLog = (HotSpotSpeculationLog) log; } } - byte[] speculations; long failedSpeculationsAddress; if (speculationLog != null) { @@ -134,6 +124,18 @@ public class HotSpotCodeCacheProvider implements CodeCacheProvider { speculations = new byte[0]; failedSpeculationsAddress = 0L; } + + if (method == null) { + // Must be a stub + resultInstalledCode = new HotSpotRuntimeStub(name); + } else { + hsCompiledNmethod = (HotSpotCompiledNmethod) hsCompiledCode; + HotSpotResolvedJavaMethodImpl hsMethod = (HotSpotResolvedJavaMethodImpl) method; + HotSpotNmethod nmethod = new HotSpotNmethod(hsMethod, name, isDefault, hsCompiledNmethod.id); + nmethod.setSpeculationLog(speculationLog); + resultInstalledCode = nmethod; + } + int result = runtime.getCompilerToVM().installCode(target, (HotSpotCompiledCode) compiledCode, resultInstalledCode, failedSpeculationsAddress, speculations); if (result != config.codeInstallResultOk) { String resultDesc = config.getCodeInstallResultDescription(result); diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java index c7bfc83401c14987c780f82f730166d1e73cda85..b15035dd5cc74b30cd65d13dea406600c7ac9b71 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -46,6 +46,8 @@ import java.util.Map; import java.util.Objects; import java.util.ServiceLoader; import java.util.function.Predicate; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import jdk.internal.misc.Unsafe; import jdk.vm.ci.code.Architecture; @@ -66,6 +68,7 @@ import jdk.vm.ci.runtime.JVMCICompiler; import jdk.vm.ci.runtime.JVMCICompilerFactory; import jdk.vm.ci.runtime.JVMCIRuntime; import jdk.vm.ci.services.JVMCIServiceLocator; +import jdk.vm.ci.services.Services; /** * HotSpot implementation of a JVMCI runtime. @@ -199,14 +202,44 @@ public final class HotSpotJVMCIRuntime implements JVMCIRuntime { return result; } + /** + * Decodes the exception encoded in {@code buffer} and throws it. + * + * @param buffer a native byte buffer containing an exception encoded by + * {@link #encodeThrowable} + */ @VMEntryPoint - static Throwable decodeThrowable(String encodedThrowable) throws Throwable { - return TranslatedException.decodeThrowable(encodedThrowable); + static void decodeAndThrowThrowable(long buffer) throws Throwable { + Unsafe unsafe = UnsafeAccess.UNSAFE; + int encodingLength = unsafe.getInt(buffer); + byte[] encoding = new byte[encodingLength]; + unsafe.copyMemory(null, buffer + 4, encoding, Unsafe.ARRAY_BYTE_BASE_OFFSET, encodingLength); + throw TranslatedException.decodeThrowable(encoding); } + /** + * If {@code bufferSize} is large enough, encodes {@code throwable} into a byte array and writes + * it to {@code buffer}. The encoding in {@code buffer} can be decoded by + * {@link #decodeAndThrowThrowable}. + * + * @param throwable the exception to encode + * @param buffer a native byte buffer + * @param bufferSize the size of {@code buffer} in bytes + * @return the number of bytes written into {@code buffer} if {@code bufferSize} is large + * enough, otherwise {@code -N} where {@code N} is the value {@code bufferSize} needs to + * be to fit the encoding + */ @VMEntryPoint - static String encodeThrowable(Throwable throwable) throws Throwable { - return TranslatedException.encodeThrowable(throwable); + static int encodeThrowable(Throwable throwable, long buffer, int bufferSize) throws Throwable { + byte[] encoding = TranslatedException.encodeThrowable(throwable); + int requiredSize = 4 + encoding.length; + if (bufferSize < requiredSize) { + return -requiredSize; + } + Unsafe unsafe = UnsafeAccess.UNSAFE; + unsafe.putInt(buffer, encoding.length); + unsafe.copyMemory(encoding, Unsafe.ARRAY_BYTE_BASE_OFFSET, null, buffer + 4, encoding.length); + return requiredSize; } @VMEntryPoint @@ -235,6 +268,10 @@ public final class HotSpotJVMCIRuntime implements JVMCIRuntime { // Note: The following one is not used (see InitTimer.ENABLED). It is added here // so that -XX:+JVMCIPrintProperties shows the option. InitTimer(Boolean.class, false, "Specifies if initialization timing is enabled."), + ForceTranslateFailure(String.class, null, "Forces HotSpotJVMCIRuntime.translate to throw an exception in the context " + + "of the peer runtime. The value is a filter that can restrict the forced failure to matching translated " + + "objects. See HotSpotJVMCIRuntime.postTranslation for more details. This option exists soley to test " + + "correct handling of translation failure."), PrintConfig(Boolean.class, false, "Prints VM configuration available via JVMCI."), AuditHandles(Boolean.class, false, "Record stack trace along with scoped foreign object reference wrappers " + "to debug issue with a wrapper being used after its scope has closed."), @@ -1180,7 +1217,88 @@ public final class HotSpotJVMCIRuntime implements JVMCIRuntime { * @see "https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/design.html#global_and_local_references" */ public long translate(Object obj) { - return compilerToVm.translate(obj); + return compilerToVm.translate(obj, Option.ForceTranslateFailure.getString() != null); + } + + private static final Pattern FORCE_TRANSLATE_FAILURE_FILTER_RE = Pattern.compile("(?:(method|type|nmethod)/)?([^:]+)(?::(hotspot|native))?"); + + /** + * Forces translation failure based on {@code translatedObject} and the value of + * {@link Option#ForceTranslateFailure}. The value is zero or more filters separated by a comma. + * The syntax for a filter is: + * + *

          +     *   Filter = [ TypeSelector "/" ] Substring [ ":" JVMCIEnvSelector ] .
          +     *   TypeSelector = "type" | "method" | "nmethod"
          +     *   JVMCIEnvSelector = "native" | "hotspot"
          +     * 
          + * + * For example: + * + *
          +     *   -Djvmci.ForceTranslateFailure=nmethod/StackOverflowError:native,method/computeHash,execute
          +     * 
          + * + * will cause failure of: + *
            + *
          • translating a {@link HotSpotNmethod} to the libjvmci heap whose fully qualified name + * contains "StackOverflowError"
          • + *
          • translating a {@link HotSpotResolvedJavaMethodImpl} to the libjvmci or HotSpot heap whose + * fully qualified name contains "computeHash"
          • + *
          • translating a {@link HotSpotNmethod}, {@link HotSpotResolvedJavaMethodImpl} or + * {@link HotSpotResolvedObjectTypeImpl} to the libjvmci or HotSpot heap whose fully qualified + * name contains "execute"
          • + *
          + */ + @VMEntryPoint + static void postTranslation(Object translatedObject) { + String value = Option.ForceTranslateFailure.getString(); + String toMatch; + String type; + if (translatedObject instanceof HotSpotResolvedJavaMethodImpl) { + toMatch = ((HotSpotResolvedJavaMethodImpl) translatedObject).format("%H.%n"); + type = "method"; + } else if (translatedObject instanceof HotSpotResolvedObjectTypeImpl) { + toMatch = ((HotSpotResolvedObjectTypeImpl) translatedObject).toJavaName(); + type = "type"; + } else if (translatedObject instanceof HotSpotNmethod) { + HotSpotNmethod nmethod = (HotSpotNmethod) translatedObject; + if (nmethod.getMethod() != null) { + toMatch = nmethod.getMethod().format("%H.%n"); + } else { + toMatch = String.valueOf(nmethod.getName()); + } + type = "nmethod"; + } else { + return; + } + String[] filters = value.split(","); + for (String filter : filters) { + Matcher m = FORCE_TRANSLATE_FAILURE_FILTER_RE.matcher(filter); + if (!m.matches()) { + throw new JVMCIError(Option.ForceTranslateFailure + " filter does not match " + FORCE_TRANSLATE_FAILURE_FILTER_RE + ": " + filter); + } + String typeSelector = m.group(1); + String substring = m.group(2); + String jvmciEnvSelector = m.group(3); + if (jvmciEnvSelector != null) { + if (jvmciEnvSelector.equals("native")) { + if (!Services.IS_IN_NATIVE_IMAGE) { + continue; + } + } else { + if (Services.IS_IN_NATIVE_IMAGE) { + continue; + } + } + } + if (typeSelector != null && !typeSelector.equals(type)) { + continue; + } + if (toMatch.contains(substring)) { + throw new JVMCIError("translation of " + translatedObject + " failed due to matching " + Option.ForceTranslateFailure + " filter \"" + filter + "\""); + } + } } /** diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotNmethod.java b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotNmethod.java index 99fd3016f9834eb7ec54a3e2294901126c7bdb24..a18f7b556fafaacf04f27f1acccc37f989ea0c8e 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotNmethod.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotNmethod.java @@ -68,8 +68,8 @@ public class HotSpotNmethod extends HotSpotInstalledCode { /** * If this field is 0, this object is in the oops table of the nmethod. Otherwise, the value of - * the field records the nmethod's compile identifier. This value is used to confirm an entry in - * the code cache retrieved by {@link #address} is indeed the nmethod represented by this + * the field records the nmethod's compile identifier. This value is used to confirm if an entry + * in the code cache retrieved by {@link #address} is indeed the nmethod represented by this * object. * * @see #inOopsTable @@ -85,6 +85,23 @@ public class HotSpotNmethod extends HotSpotInstalledCode { assert inOopsTable || compileId != 0L : this; } + /** + * Attaches {@code log} to this object. If {@code log.managesFailedSpeculations() == true}, this + * ensures the failed speculation list lives at least as long as this object. + */ + public void setSpeculationLog(HotSpotSpeculationLog log) { + this.speculationLog = log; + } + + /** + * The speculation log containing speculations embedded in the nmethod. + * + * If {@code speculationLog.managesFailedSpeculations() == true}, this field ensures the failed + * speculation list lives at least as long as this object. This prevents deoptimization from + * appending to an already freed list. + */ + @SuppressWarnings("unused") private HotSpotSpeculationLog speculationLog; + /** * Determines if the nmethod associated with this object is the compiled entry point for * {@link #getMethod()}. diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfig.java b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfig.java index 1a477cf02b08507d2b00bbb33c089be969ea76ff..927dbed4297d16c4957ce687fa2ca412010bfd51 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfig.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfig.java @@ -336,7 +336,7 @@ class HotSpotVMConfig extends HotSpotVMConfigAccess { final int deoptReasonLoopLimitCheck = getConstant("Deoptimization::Reason_loop_limit_check", Integer.class); final int deoptReasonAliasing = getConstant("Deoptimization::Reason_aliasing", Integer.class); final int deoptReasonTransferToInterpreter = getConstant("Deoptimization::Reason_transfer_to_interpreter", Integer.class); - final int deoptReasonOSROffset = getConstant("Deoptimization::Reason_LIMIT", Integer.class); + final int deoptReasonOSROffset = getConstant("Deoptimization::Reason_TRAP_HISTORY_LENGTH", Integer.class); final int deoptActionNone = getConstant("Deoptimization::Action_none", Integer.class); final int deoptActionMaybeRecompile = getConstant("Deoptimization::Action_maybe_recompile", Integer.class); diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/TranslatedException.java b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/TranslatedException.java index a47735faf802006bf72031dc60ba6c5b6f235ec1..53f99733ba93f86d27059f525f7038a58f26598d 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/TranslatedException.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/TranslatedException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -22,13 +22,20 @@ */ package jdk.vm.ci.hotspot; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; -import java.util.Formatter; import java.util.List; -import java.util.Objects; +import java.util.zip.GZIPInputStream; +import java.util.zip.GZIPOutputStream; + +import jdk.vm.ci.common.JVMCIError; /** * Support for translating exceptions between different runtime heaps. @@ -36,6 +43,26 @@ import java.util.Objects; @SuppressWarnings("serial") final class TranslatedException extends Exception { + /** + * The value returned by {@link #encodeThrowable(Throwable)} when encoding fails due to an + * {@link OutOfMemoryError}. + */ + private static final byte[] FALLBACK_ENCODED_OUTOFMEMORYERROR_BYTES; + + /** + * The value returned by {@link #encodeThrowable(Throwable)} when encoding fails for any reason + * other than {@link OutOfMemoryError}. + */ + private static final byte[] FALLBACK_ENCODED_THROWABLE_BYTES; + static { + try { + FALLBACK_ENCODED_THROWABLE_BYTES = encodeThrowable(new TranslatedException("error during encoding", ""), false); + FALLBACK_ENCODED_OUTOFMEMORYERROR_BYTES = encodeThrowable(new OutOfMemoryError(), false); + } catch (IOException e) { + throw new JVMCIError(e); + } + } + /** * Class name of exception that could not be instantiated. */ @@ -110,83 +137,74 @@ final class TranslatedException extends Exception { } } - /** - * Encodes an exception message to distinguish a null message from an empty message. - * - * @return {@code value} with a space prepended iff {@code value != null} - */ - private static String encodeMessage(String value) { - return value != null ? ' ' + value : value; - } - - private static String decodeMessage(String value) { - if (value.length() == 0) { - return null; - } - return value.substring(1); + private static String emptyIfNull(String value) { + return value == null ? "" : value; } - private static String encodedString(String value) { - return Objects.toString(value, "").replace('|', '_'); + private static String emptyAsNull(String value) { + return value.isEmpty() ? null : value; } /** - * Encodes {@code throwable} including its stack and causes as a string. The encoding format of - * a single exception is: - * - *
          -     *  '|'  '|'  '|' [  '|'  '|'  '|'  '|'  '|'  '|'  '|' ]*
          -     * 
          - * - * Each exception is encoded before the exception it causes. + * Encodes {@code throwable} including its stack and causes as a {@linkplain GZIPOutputStream + * compressed} byte array that can be decoded by {@link #decodeThrowable}. */ @VMEntryPoint - static String encodeThrowable(Throwable throwable) throws Throwable { + static byte[] encodeThrowable(Throwable throwable) throws Throwable { try { - Formatter enc = new Formatter(); + return encodeThrowable(throwable, true); + } catch (OutOfMemoryError e) { + return FALLBACK_ENCODED_OUTOFMEMORYERROR_BYTES; + } catch (Throwable e) { + return FALLBACK_ENCODED_THROWABLE_BYTES; + } + } + + private static byte[] encodeThrowable(Throwable throwable, boolean withCauseAndStack) throws IOException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try (DataOutputStream dos = new DataOutputStream(new GZIPOutputStream(baos))) { List throwables = new ArrayList<>(); for (Throwable current = throwable; current != null; current = current.getCause()) { throwables.add(current); + if (!withCauseAndStack) { + break; + } } // Encode from inner most cause outwards Collections.reverse(throwables); for (Throwable current : throwables) { - enc.format("%s|%s|", current.getClass().getName(), encodedString(encodeMessage(current.getMessage()))); - StackTraceElement[] stackTrace = current.getStackTrace(); + dos.writeUTF(current.getClass().getName()); + dos.writeUTF(emptyIfNull(current.getMessage())); + StackTraceElement[] stackTrace = withCauseAndStack ? current.getStackTrace() : null; if (stackTrace == null) { stackTrace = new StackTraceElement[0]; } - enc.format("%d|", stackTrace.length); + dos.writeInt(stackTrace.length); for (int i = 0; i < stackTrace.length; i++) { StackTraceElement frame = stackTrace[i]; if (frame != null) { - enc.format("%s|%s|%s|%s|%s|%s|%d|", encodedString(frame.getClassLoaderName()), - encodedString(frame.getModuleName()), encodedString(frame.getModuleVersion()), - frame.getClassName(), frame.getMethodName(), - encodedString(frame.getFileName()), frame.getLineNumber()); + dos.writeUTF(emptyIfNull(frame.getClassLoaderName())); + dos.writeUTF(emptyIfNull(frame.getModuleName())); + dos.writeUTF(emptyIfNull(frame.getModuleVersion())); + dos.writeUTF(emptyIfNull(frame.getClassName())); + dos.writeUTF(emptyIfNull(frame.getMethodName())); + dos.writeUTF(emptyIfNull(frame.getFileName())); + dos.writeInt(frame.getLineNumber()); } } } - return enc.toString(); - } catch (Throwable e) { - assert printStackTrace(e); - try { - return e.getClass().getName() + "|" + encodedString(e.getMessage()) + "|0|"; - } catch (Throwable e2) { - assert printStackTrace(e2); - return "java.lang.Throwable|too many errors during encoding|0|"; - } } + return baos.toByteArray(); } /** * Gets the stack of the current thread without the frames between this call and the one just - * below the frame of the first method in {@link CompilerToVM}. The chopped frames are specific - * to the implementation of {@link HotSpotJVMCIRuntime#decodeThrowable(String)}. + * below the frame of the first method in {@link CompilerToVM}. The chopped frames are for the + * VM call to {@link HotSpotJVMCIRuntime#decodeAndThrowThrowable}. */ - private static StackTraceElement[] getStackTraceSuffix() { + private static StackTraceElement[] getMyStackTrace() { StackTraceElement[] stack = new Exception().getStackTrace(); for (int i = 0; i < stack.length; i++) { StackTraceElement e = stack[i]; @@ -206,43 +224,47 @@ final class TranslatedException extends Exception { * {@link #encodeThrowable} */ @VMEntryPoint - static Throwable decodeThrowable(String encodedThrowable) { - try { - int i = 0; - String[] parts = encodedThrowable.split("\\|"); + static Throwable decodeThrowable(byte[] encodedThrowable) { + try (DataInputStream dis = new DataInputStream(new GZIPInputStream(new ByteArrayInputStream(encodedThrowable)))) { Throwable cause = null; Throwable throwable = null; - while (i != parts.length) { - String exceptionClassName = parts[i++]; - String exceptionMessage = decodeMessage(parts[i++]); + StackTraceElement[] myStack = getMyStackTrace(); + while (dis.available() != 0) { + String exceptionClassName = dis.readUTF(); + String exceptionMessage = emptyAsNull(dis.readUTF()); throwable = create(exceptionClassName, exceptionMessage, cause); - int stackTraceDepth = Integer.parseInt(parts[i++]); - - StackTraceElement[] suffix = getStackTraceSuffix(); - StackTraceElement[] stackTrace = new StackTraceElement[stackTraceDepth + suffix.length]; + int stackTraceDepth = dis.readInt(); + StackTraceElement[] stackTrace = new StackTraceElement[stackTraceDepth + myStack.length]; + int stackTraceIndex = 0; + int myStackIndex = 0; for (int j = 0; j < stackTraceDepth; j++) { - String classLoaderName = parts[i++]; - String moduleName = parts[i++]; - String moduleVersion = parts[i++]; - String className = parts[i++]; - String methodName = parts[i++]; - String fileName = parts[i++]; - int lineNumber = Integer.parseInt(parts[i++]); - if (classLoaderName.isEmpty()) { - classLoaderName = null; - } - if (moduleName.isEmpty()) { - moduleName = null; - } - if (moduleVersion.isEmpty()) { - moduleVersion = null; - } - if (fileName.isEmpty()) { - fileName = null; + String classLoaderName = emptyAsNull(dis.readUTF()); + String moduleName = emptyAsNull(dis.readUTF()); + String moduleVersion = emptyAsNull(dis.readUTF()); + String className = emptyAsNull(dis.readUTF()); + String methodName = emptyAsNull(dis.readUTF()); + String fileName = emptyAsNull(dis.readUTF()); + int lineNumber = dis.readInt(); + StackTraceElement ste = new StackTraceElement(classLoaderName, moduleName, moduleVersion, className, methodName, fileName, lineNumber); + + if (ste.isNativeMethod()) { + // Best effort attempt to weave stack traces from two heaps into + // a single stack trace using native method frames as stitching points. + // This is not 100% reliable as there's no guarantee that native method + // frames only exist for calls between HotSpot and libjvmci. + while (myStackIndex < myStack.length) { + StackTraceElement suffixSTE = myStack[myStackIndex++]; + if (suffixSTE.isNativeMethod()) { + break; + } + stackTrace[stackTraceIndex++] = suffixSTE; + } } - stackTrace[j] = new StackTraceElement(classLoaderName, moduleName, moduleVersion, className, methodName, fileName, lineNumber); + stackTrace[stackTraceIndex++] = ste; + } + while (myStackIndex < myStack.length) { + stackTrace[stackTraceIndex++] = myStack[myStackIndex++]; } - System.arraycopy(suffix, 0, stackTrace, stackTraceDepth, suffix.length); throwable.setStackTrace(stackTrace); cause = throwable; } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/UnsafeAccess.java b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/UnsafeAccess.java index 61b0f949655b442c0f43bf064424c0ac9327a4dc..afdff7a88901b6b2d67c653d78911c6ec5391361 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/UnsafeAccess.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/UnsafeAccess.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/Constant.java b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/Constant.java index c7cc38959877642fd49845808aee74d815001078..63002463fb595ff971266cc165957044459ce968 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/Constant.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/Constant.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/DeoptimizationReason.java b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/DeoptimizationReason.java index bcefe66cc79151783ccaa11f4309f39674c75c88..36c422beda59b108a894ffaf3215f03675c7ce60 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/DeoptimizationReason.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/DeoptimizationReason.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/InvokeTarget.java b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/InvokeTarget.java index afaa0f635c6efd03447da74a3ba44998b5869252..d22d7a9d622d7b44acc657240d10faeb0c02885c 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/InvokeTarget.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/InvokeTarget.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/MetaUtil.java b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/MetaUtil.java index 528bb34e0592cefa93ab35cc1591c017134d4413..54a55dc31222b0738aeb71a7cfe041a825857f94 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/MetaUtil.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/MetaUtil.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -27,6 +27,11 @@ package jdk.vm.ci.meta; */ public class MetaUtil { + public static final char PACKAGE_SEPARATOR_INTERNAL = '/'; + public static final char HIDDEN_SEPARATOR_INTERNAL = '.'; + public static final char PACKAGE_SEPARATOR_JAVA = HIDDEN_SEPARATOR_INTERNAL; + public static final char HIDDEN_SEPARATOR_JAVA = PACKAGE_SEPARATOR_INTERNAL; + /** * Extends the functionality of {@link Class#getSimpleName()} to include a non-empty string for * anonymous and local classes. @@ -87,25 +92,27 @@ public class MetaUtil { } /** - * Classes for lambdas can have {@code /} characters that are not package separators. These are - * distinguished by being followed by a character that is not a + * Hidden classes have {@code /} characters in their internal names and {@code .} characters in their names returned + * by {@link Class#getName()} that are not package separators. + * These are distinguished by being followed by a character that is not a * {@link Character#isJavaIdentifierStart(char)} (e.g., * "jdk.vm.ci.runtime.test.TypeUniverse$$Lambda$1/869601985"). + * + * @param name the name to perform the replacements on + * @param packageSeparator the {@link Character} used as the package separator, e.g. {@code /} in internal form + * @param hiddenSeparator the {@link Character} used as the hidden class separator, e.g. {@code .} in internal form */ - private static String replacePackageSeparatorsWithDot(String name) { + private static String replacePackageAndHiddenSeparators(String name, Character packageSeparator, Character hiddenSeparator) { + int index = name.indexOf(hiddenSeparator); // check if it's a hidden class int length = name.length(); - int i = 0; StringBuilder buf = new StringBuilder(length); - while (i < length - 1) { - char ch = name.charAt(i); - if (ch == '/' && Character.isJavaIdentifierStart(name.charAt(i + 1))) { - buf.append('.'); - } else { - buf.append(ch); - } - i++; + if (index < 0) { + buf.append(name.replace(packageSeparator, hiddenSeparator)); + } else { + buf.append(name.substring(0, index).replace(packageSeparator, hiddenSeparator)); + buf.append(packageSeparator); + buf.append(name.substring(index + 1)); } - buf.append(name.charAt(length - 1)); return buf.toString(); } @@ -122,9 +129,10 @@ public class MetaUtil { public static String internalNameToJava(String name, boolean qualified, boolean classForNameCompatible) { switch (name.charAt(0)) { case 'L': { - String result = replacePackageSeparatorsWithDot(name.substring(1, name.length() - 1)); + String type = name.substring(1, name.length() - 1); + String result = replacePackageAndHiddenSeparators(type, PACKAGE_SEPARATOR_INTERNAL, HIDDEN_SEPARATOR_INTERNAL); if (!qualified) { - final int lastDot = result.lastIndexOf('.'); + final int lastDot = result.lastIndexOf(HIDDEN_SEPARATOR_INTERNAL); if (lastDot != -1) { result = result.substring(lastDot + 1); } @@ -132,7 +140,11 @@ public class MetaUtil { return result; } case '[': - return classForNameCompatible ? replacePackageSeparatorsWithDot(name) : internalNameToJava(name.substring(1), qualified, classForNameCompatible) + "[]"; + if (classForNameCompatible) { + return replacePackageAndHiddenSeparators(name, PACKAGE_SEPARATOR_INTERNAL, HIDDEN_SEPARATOR_INTERNAL); + } else { + return internalNameToJava(name.substring(1), qualified, false) + "[]"; + } default: if (name.length() != 1) { throw new IllegalArgumentException("Illegal internal name: " + name); @@ -213,7 +225,7 @@ public class MetaUtil { public static String toInternalName(String className) { if (className.startsWith("[")) { /* Already in the correct array style. */ - return className.replace('.', '/'); + return replacePackageAndHiddenSeparators(className, PACKAGE_SEPARATOR_JAVA, HIDDEN_SEPARATOR_JAVA); } StringBuilder result = new StringBuilder(); @@ -252,7 +264,9 @@ public class MetaUtil { result.append("V"); break; default: - result.append("L").append(base.replace('.', '/')).append(";"); + result.append("L") + .append(replacePackageAndHiddenSeparators(base, PACKAGE_SEPARATOR_JAVA, HIDDEN_SEPARATOR_JAVA)) + .append(";"); break; } return result.toString(); diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/MethodHandleAccessProvider.java b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/MethodHandleAccessProvider.java index c533123ccd84d24ac894962bcd9951b0fa3ac57d..0faa2af57047457248331015120846cb3e20c3ae 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/MethodHandleAccessProvider.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/MethodHandleAccessProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ProfilingInfo.java b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ProfilingInfo.java index 2ba915c9892714d763bc6f5dfa0403dd42fa2cc5..7eaa8e966705652037085a9190915194a8fd57cb 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ProfilingInfo.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ProfilingInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/VMConstant.java b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/VMConstant.java index e7b0484dbd3188e8db8e96f85cfcc5d3e3638027..ecd15057e97693a4ea88415b82c26d98717835b6 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/VMConstant.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/VMConstant.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 diff --git a/src/jdk.jartool/share/classes/module-info.java b/src/jdk.jartool/share/classes/module-info.java index 1bba6faebaf1eaf392c48dd03129183d0403221e..b14e47f7c29dab96f811bfcf7cec19effc811b8d 100644 --- a/src/jdk.jartool/share/classes/module-info.java +++ b/src/jdk.jartool/share/classes/module-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -39,6 +39,11 @@ * @toolGuide jar * @toolGuide jarsigner * + * @provides java.util.spi.ToolProvider + * Use {@link java.util.spi.ToolProvider#findFirst ToolProvider.findFirst("jar")} + * to obtain an instance of a {@code ToolProvider} that provides the equivalent + * of command-line access to the {@code jar} tool. + * * @moduleGraph * @since 9 */ 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 83383823303e8eee86bb5f5212605cbcdac7da9a..1b9e23f0fde8eace75184933e53e9449e96ca82e 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -27,8 +27,10 @@ package sun.security.tools.jarsigner; import java.io.*; import java.net.UnknownHostException; +import java.net.URLClassLoader; import java.security.cert.CertPathValidatorException; import java.security.cert.PKIXBuilderParameters; +import java.security.interfaces.ECKey; import java.util.*; import java.util.stream.Collectors; import java.util.zip.*; @@ -59,6 +61,7 @@ import sun.security.pkcs.SignerInfo; import sun.security.provider.certpath.CertPathConstraintsParameters; import sun.security.timestamp.TimestampToken; import sun.security.tools.KeyStoreUtil; +import sun.security.tools.PathList; import sun.security.validator.Validator; import sun.security.validator.ValidatorException; import sun.security.x509.*; @@ -152,6 +155,7 @@ public class Main { List providerClasses = null; // list of provider classes // arguments for provider constructors HashMap providerArgs = new HashMap<>(); + String pathlist = null; char[] keypass; // private key password String sigfile; // name of .SF file String sigalg; // name of signature algorithm @@ -246,7 +250,18 @@ public class Main { } if (providerClasses != null) { - ClassLoader cl = ClassLoader.getSystemClassLoader(); + ClassLoader cl; + if (pathlist != null) { + String path = System.getProperty("java.class.path"); + path = PathList.appendPath( + path, System.getProperty("env.class.path")); + path = PathList.appendPath(path, pathlist); + + URL[] urls = PathList.pathToURLs(path); + cl = new URLClassLoader(urls); + } else { + cl = ClassLoader.getSystemClassLoader(); + } for (String provClass: providerClasses) { try { KeyStoreUtil.loadProviderByClass(provClass, @@ -434,6 +449,9 @@ public class Main { n += 2; } } + } else if (collator.compare(flags, "-providerpath") == 0) { + if (++n == args.length) usageNoArg(); + pathlist = args[n]; } else if (collator.compare(flags, "-protected") ==0) { protectedPath = true; } else if (collator.compare(flags, "-certchain") ==0) { @@ -705,6 +723,9 @@ public class Main { System.out.println(rb.getString (".providerArg.option.2")); System.out.println(); + System.out.println(rb.getString + (".providerPath.option")); + System.out.println(); System.out.println(rb.getString (".strict.treat.warnings.as.errors")); System.out.println(); @@ -834,9 +855,9 @@ public class Main { } // Only used when -verbose provided - StringBuffer sb = null; + StringBuilder sb = null; if (verbose != null) { - sb = new StringBuffer(); + sb = new StringBuilder(); boolean inManifest = ((man.getAttributes(name) != null) || (man.getAttributes("./"+name) != null) || @@ -1001,6 +1022,8 @@ public class Main { si.getDigestAlgorithmId(), si.getDigestEncryptionAlgorithmId(), si.getAuthenticatedAttributes() == null); + AlgorithmId encAlgId = si.getDigestEncryptionAlgorithmId(); + AlgorithmParameters sigAlgParams = encAlgId.getParameters(); PublicKey key = signer.getPublicKey(); PKCS7 tsToken = si.getTsToken(); if (tsToken != null) { @@ -1015,31 +1038,38 @@ public class Main { tsSi.getDigestAlgorithmId(), tsSi.getDigestEncryptionAlgorithmId(), tsSi.getAuthenticatedAttributes() == null); + AlgorithmId tsEncAlgId = tsSi.getDigestEncryptionAlgorithmId(); + AlgorithmParameters tsSigAlgParams = tsEncAlgId.getParameters(); Calendar c = Calendar.getInstance( TimeZone.getTimeZone("UTC"), Locale.getDefault(Locale.Category.FORMAT)); - c.setTime(tsTokenInfo.getDate()); + Date tsDate = tsTokenInfo.getDate(); + c.setTime(tsDate); JarConstraintsParameters jcp = - new JarConstraintsParameters(chain, si.getTimestamp()); + new JarConstraintsParameters(chain, tsDate); + JarConstraintsParameters jcpts = + new JarConstraintsParameters( + tsSi.getCertificateChain(tsToken), + tsDate); history = String.format( rb.getString("history.with.ts"), signer.getSubjectX500Principal(), - verifyWithWeak(digestAlg, DIGEST_PRIMITIVE_SET, false, jcp), - verifyWithWeak(sigAlg, SIG_PRIMITIVE_SET, false, jcp), + verifyWithWeak(digestAlg, DIGEST_PRIMITIVE_SET, false, jcp, null), + verifyWithWeak(sigAlg, SIG_PRIMITIVE_SET, false, jcp, sigAlgParams), verifyWithWeak(key, jcp), c, tsSigner.getSubjectX500Principal(), - verifyWithWeak(tsDigestAlg, DIGEST_PRIMITIVE_SET, true, jcp), - verifyWithWeak(tsSigAlg, SIG_PRIMITIVE_SET, true, jcp), - verifyWithWeak(tsKey, jcp)); + verifyWithWeak(tsDigestAlg, DIGEST_PRIMITIVE_SET, true, jcpts, null), + verifyWithWeak(tsSigAlg, SIG_PRIMITIVE_SET, true, jcpts, tsSigAlgParams), + verifyWithWeak(tsKey, jcpts)); } else { JarConstraintsParameters jcp = new JarConstraintsParameters(chain, null); history = String.format( rb.getString("history.without.ts"), signer.getSubjectX500Principal(), - verifyWithWeak(digestAlg, DIGEST_PRIMITIVE_SET, false, jcp), - verifyWithWeak(sigAlg, SIG_PRIMITIVE_SET, false, jcp), + verifyWithWeak(digestAlg, DIGEST_PRIMITIVE_SET, false, jcp, null), + verifyWithWeak(sigAlg, SIG_PRIMITIVE_SET, false, jcp, sigAlgParams), verifyWithWeak(key, jcp)); } } catch (Exception e) { @@ -1215,13 +1245,13 @@ public class Main { if ((legacyAlg & 8) == 8) { warnings.add(String.format( rb.getString("The.1.signing.key.has.a.keysize.of.2.which.is.considered.a.security.risk..This.key.size.will.be.disabled.in.a.future.update."), - privateKey.getAlgorithm(), KeyUtil.getKeySize(privateKey))); + KeyUtil.fullDisplayAlgName(privateKey), KeyUtil.getKeySize(privateKey))); } if ((disabledAlg & 8) == 8) { errors.add(String.format( rb.getString("The.1.signing.key.has.a.keysize.of.2.which.is.considered.a.security.risk.and.is.disabled."), - privateKey.getAlgorithm(), KeyUtil.getKeySize(privateKey))); + KeyUtil.fullDisplayAlgName(privateKey), KeyUtil.getKeySize(privateKey))); } } else { if ((legacyAlg & 1) != 0) { @@ -1245,7 +1275,7 @@ public class Main { if ((legacyAlg & 8) == 8) { warnings.add(String.format( rb.getString("The.1.signing.key.has.a.keysize.of.2.which.is.considered.a.security.risk..This.key.size.will.be.disabled.in.a.future.update."), - weakPublicKey.getAlgorithm(), KeyUtil.getKeySize(weakPublicKey))); + KeyUtil.fullDisplayAlgName(weakPublicKey), KeyUtil.getKeySize(weakPublicKey))); } } @@ -1368,17 +1398,26 @@ public class Main { } private String verifyWithWeak(String alg, Set primitiveSet, - boolean tsa, JarConstraintsParameters jcp) { + boolean tsa, JarConstraintsParameters jcp, AlgorithmParameters algParams) { try { - JAR_DISABLED_CHECK.permits(alg, jcp); + JAR_DISABLED_CHECK.permits(alg, jcp, false); } catch (CertPathValidatorException e) { disabledAlgFound = true; return String.format(rb.getString("with.disabled"), alg); } + if (algParams != null) { + try { + JAR_DISABLED_CHECK.permits(algParams, jcp); + } catch (CertPathValidatorException e) { + disabledAlgFound = true; + return String.format(rb.getString("with.algparams.disabled"), + alg, algParams); + } + } + try { - LEGACY_CHECK.permits(alg, jcp); - return alg; + LEGACY_CHECK.permits(alg, jcp, false); } catch (CertPathValidatorException e) { if (primitiveSet == SIG_PRIMITIVE_SET) { legacyAlg |= 2; @@ -1394,18 +1433,34 @@ public class Main { } return String.format(rb.getString("with.weak"), alg); } + if (algParams != null) { + try { + LEGACY_CHECK.permits(algParams, jcp); + } catch (CertPathValidatorException e) { + legacyAlg |= 2; + legacySigAlg = alg; + return String.format(rb.getString("with.algparams.weak"), + alg, algParams); + } + } + return alg; } private String verifyWithWeak(PublicKey key, JarConstraintsParameters jcp) { int kLen = KeyUtil.getKeySize(key); try { - JAR_DISABLED_CHECK.permits(key.getAlgorithm(), jcp); + JAR_DISABLED_CHECK.permits(key.getAlgorithm(), jcp, true); } catch (CertPathValidatorException e) { disabledAlgFound = true; - return String.format(rb.getString("key.bit.disabled"), kLen); + if (key instanceof ECKey) { + return String.format(rb.getString("key.bit.eccurve.disabled"), kLen, + KeyUtil.fullDisplayAlgName(key)); + } else { + return String.format(rb.getString("key.bit.disabled"), kLen); + } } try { - LEGACY_CHECK.permits(key.getAlgorithm(), jcp); + LEGACY_CHECK.permits(key.getAlgorithm(), jcp, true); if (kLen >= 0) { return String.format(rb.getString("key.bit"), kLen); } else { @@ -1414,7 +1469,12 @@ public class Main { } catch (CertPathValidatorException e) { weakPublicKey = key; legacyAlg |= 8; - return String.format(rb.getString("key.bit.weak"), kLen); + if (key instanceof ECKey) { + return String.format(rb.getString("key.bit.eccurve.weak"), kLen, + KeyUtil.fullDisplayAlgName(key)); + } else { + return String.format(rb.getString("key.bit.weak"), kLen); + } } } @@ -1422,9 +1482,9 @@ public class Main { boolean tsa, JarConstraintsParameters jcp) { try { - JAR_DISABLED_CHECK.permits(alg, jcp); + JAR_DISABLED_CHECK.permits(alg, jcp, false); try { - LEGACY_CHECK.permits(alg, jcp); + LEGACY_CHECK.permits(alg, jcp, false); } catch (CertPathValidatorException e) { if (primitiveSet == SIG_PRIMITIVE_SET) { legacyAlg |= 2; @@ -1451,9 +1511,9 @@ public class Main { private void checkWeakSign(PrivateKey key, JarConstraintsParameters jcp) { try { - JAR_DISABLED_CHECK.permits(key.getAlgorithm(), jcp); + JAR_DISABLED_CHECK.permits(key.getAlgorithm(), jcp, true); try { - LEGACY_CHECK.permits(key.getAlgorithm(), jcp); + LEGACY_CHECK.permits(key.getAlgorithm(), jcp, true); } catch (CertPathValidatorException e) { legacyAlg |= 8; } @@ -1465,30 +1525,40 @@ public class Main { private static String checkWeakKey(PublicKey key, CertPathConstraintsParameters cpcp) { int kLen = KeyUtil.getKeySize(key); try { - CERTPATH_DISABLED_CHECK.permits(key.getAlgorithm(), cpcp); + CERTPATH_DISABLED_CHECK.permits(key.getAlgorithm(), cpcp, true); } catch (CertPathValidatorException e) { - return String.format(rb.getString("key.bit.disabled"), kLen); + if (key instanceof ECKey) { + return String.format(rb.getString("key.bit.eccurve.disabled"), kLen, + KeyUtil.fullDisplayAlgName(key)); + } else { + return String.format(rb.getString("key.bit.disabled"), kLen); + } } try { - LEGACY_CHECK.permits(key.getAlgorithm(), cpcp); + LEGACY_CHECK.permits(key.getAlgorithm(), cpcp, true); if (kLen >= 0) { return String.format(rb.getString("key.bit"), kLen); } else { return rb.getString("unknown.size"); } } catch (CertPathValidatorException e) { - return String.format(rb.getString("key.bit.weak"), kLen); + if (key instanceof ECKey) { + return String.format(rb.getString("key.bit.eccurve.weak"), kLen, + KeyUtil.fullDisplayAlgName(key)); + } else { + return String.format(rb.getString("key.bit.weak"), kLen); + } } } private static String checkWeakAlg(String alg, CertPathConstraintsParameters cpcp) { try { - CERTPATH_DISABLED_CHECK.permits(alg, cpcp); + CERTPATH_DISABLED_CHECK.permits(alg, cpcp, false); } catch (CertPathValidatorException e) { return String.format(rb.getString("with.disabled"), alg); } try { - LEGACY_CHECK.permits(alg, cpcp); + LEGACY_CHECK.permits(alg, cpcp, false); return alg; } catch (CertPathValidatorException e) { return String.format(rb.getString("with.weak"), alg); @@ -2160,7 +2230,7 @@ public class Main { && !KeyStoreUtil.isWindowsKeyStore(storetype)) { storepass = getPass (rb.getString("Enter.Passphrase.for.keystore.")); - } else if (!token && storepass == null && prompt) { + } else if (!token && storepass == null && prompt && !protectedPath) { storepass = getPass (rb.getString("Enter.Passphrase.for.keystore.")); } 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 45e56f4d049c646f47bc501006c3da384e839b26..37a1f24f90d018b452ad5482ceee51e4ff389781 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -119,6 +119,8 @@ public class Resources extends java.util.ListResourceBundle { "[-providerClass add security provider by fully-qualified class name"}, {".providerArg.option.2", " [-providerArg ]] ... configure argument for -providerClass"}, + {".providerPath.option", + "[-providerPath ] provider classpath"}, {".strict.treat.warnings.as.errors", "[-strict] treat warnings as errors"}, {".conf.url.specify.a.pre.configured.options.file", @@ -174,10 +176,14 @@ public class Resources extends java.util.ListResourceBundle { {"history.nobk", "- Missing block file for signature-related file META-INF/%s.SF"}, {"with.weak", "%s (weak)"}, + {"with.algparams.weak", "%1$s using %2$s (weak)"}, {"with.disabled", "%s (disabled)"}, + {"with.algparams.disabled", "%1$s using %2$s (disabled)"}, {"key.bit", "%d-bit key"}, {"key.bit.weak", "%d-bit key (weak)"}, + {"key.bit.eccurve.weak", "%1$d-bit %2$s key (weak)"}, {"key.bit.disabled", "%d-bit key (disabled)"}, + {"key.bit.eccurve.disabled", "%1$d-bit %2$s key (disabled)"}, {"unknown.size", "unknown size"}, {"extra.attributes.detected", "POSIX file permission and/or symlink attributes detected. These attributes are ignored when signing and are not protected by the signature."}, 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 bcc4bb32f066af93b2951529842e234a37c4bddc..8686210b209bdc8c6ddb56d5633a76cd0c99076d 100644 --- a/src/jdk.jartool/share/classes/sun/tools/jar/GNUStyleOptions.java +++ b/src/jdk.jartool/share/classes/sun/tools/jar/GNUStyleOptions.java @@ -34,12 +34,21 @@ import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; import jdk.internal.module.ModulePath; import jdk.internal.module.ModuleResolution; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; /** * Parser for GNU Style Options. */ class GNUStyleOptions { + // Valid --date range + static final ZonedDateTime DATE_MIN = ZonedDateTime.parse("1980-01-01T00:00:02Z"); + static final ZonedDateTime DATE_MAX = ZonedDateTime.parse("2099-12-31T23:59:59Z"); + static class BadArgs extends Exception { static final long serialVersionUID = 0L; @@ -188,6 +197,20 @@ class GNUStyleOptions { jartool.flag0 = true; } }, + new Option(true, OptionType.CREATE_UPDATE_INDEX, "--date") { + void process(Main jartool, String opt, String arg) throws BadArgs { + try { + ZonedDateTime date = ZonedDateTime.parse(arg, DateTimeFormatter.ISO_ZONED_DATE_TIME) + .withZoneSameInstant(ZoneOffset.UTC); + if (date.isBefore(DATE_MIN) || date.isAfter(DATE_MAX)) { + throw new BadArgs("error.date.out.of.range", arg); + } + jartool.date = date.toLocalDateTime(); + } catch (DateTimeParseException x) { + throw new BadArgs("error.date.notvalid", arg); + } + } + }, // Hidden options new Option(false, OptionType.OTHER, "-P") { 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 4458cd00b445e5f73baece10eadcf62612056b31..c582f2d80cefaea74e0fbe566867d4748c9fbee9 100644 --- a/src/jdk.jartool/share/classes/sun/tools/jar/Main.java +++ b/src/jdk.jartool/share/classes/sun/tools/jar/Main.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 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 @@ -44,6 +44,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardCopyOption; +import java.nio.file.attribute.FileTime; import java.text.MessageFormat; import java.util.*; import java.util.function.Consumer; @@ -59,6 +60,7 @@ import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import java.util.zip.ZipInputStream; import java.util.zip.ZipOutputStream; +import java.util.concurrent.TimeUnit; import jdk.internal.module.Checks; import jdk.internal.module.ModuleHashes; import jdk.internal.module.ModuleHashesBuilder; @@ -67,6 +69,8 @@ import jdk.internal.module.ModuleInfoExtender; import jdk.internal.module.ModuleResolution; import jdk.internal.module.ModuleTarget; import jdk.internal.util.jar.JarIndex; +import java.time.LocalDateTime; +import java.time.ZoneOffset; import static java.nio.file.StandardCopyOption.REPLACE_EXISTING; import static java.util.jar.JarFile.MANIFEST_NAME; @@ -120,14 +124,17 @@ public class Main { Set entries = new LinkedHashSet<>(); // module-info.class entries need to be added/updated. - Map moduleInfos = new HashMap<>(); + Map moduleInfos = new HashMap<>(); // A paths Set for each version, where each Set contains directories // specified by the "-C" operation. Map> pathsMap = new HashMap<>(); // There's also a files array per version - Map filesMap = new HashMap<>(); + // base version is the first entry and then follow with the version given + // from the --release option in the command-line order. + // The value of each entry is the files given in the command-line order. + Map filesMap = new LinkedHashMap<>(); // Do we think this is a multi-release jar? Set to true // if --release option found followed by at least file @@ -170,6 +177,9 @@ public class Main { static final int VERSIONS_DIR_LENGTH = VERSIONS_DIR.length(); private static ResourceBundle rsrc; + /* Date option for entry timestamps resolved to UTC Local time */ + LocalDateTime date; + /** * If true, maintain compatibility with JDK releases prior to 6.0 by * timestamping extracted files with the time at which they are extracted. @@ -417,10 +427,10 @@ public class Main { fatalError(e); ok = false; } catch (Error ee) { - ee.printStackTrace(); + ee.printStackTrace(err); ok = false; } catch (Throwable t) { - t.printStackTrace(); + t.printStackTrace(err); ok = false; } finally { if (tmpFile != null && tmpFile.exists()) @@ -451,7 +461,12 @@ public class Main { try { if (ok) { if (fname != null) { - Files.move(path, Paths.get(fname), StandardCopyOption.REPLACE_EXISTING); + Path target = Paths.get(fname); + Path parent = target.getParent(); + if (parent != null) { + Files.createDirectories(parent); + } + Files.move(path, target, StandardCopyOption.REPLACE_EXISTING); } else { Files.copy(path, new FileOutputStream(FileDescriptor.out)); } @@ -772,15 +787,17 @@ public class Main { private void expand(File dir, String[] files, Set cpaths, int version) throws IOException { - if (files == null) + if (files == null) { return; + } for (int i = 0; i < files.length; i++) { File f; - if (dir == null) + if (dir == null) { f = new File(files[i]); - else + } else { f = new File(dir, files[i]); + } boolean isDir = f.isDirectory(); String name = toEntryName(f.getPath(), cpaths, isDir); @@ -801,19 +818,24 @@ public class Main { if (f.isFile()) { Entry e = new Entry(f, name, false); if (isModuleInfoEntry(name)) { - moduleInfos.putIfAbsent(name, Files.readAllBytes(f.toPath())); - if (uflag) + Path path = f.toPath(); + byte[] fileContent = Files.readAllBytes(path); + ModuleInfoEntry mie = new StreamedModuleInfoEntry(name, fileContent, Files.getLastModifiedTime(path)); + moduleInfos.putIfAbsent(name, mie); + if (uflag) { entryMap.put(name, e); + } } else if (entries.add(e)) { - if (uflag) + if (uflag) { entryMap.put(name, e); + } } } else if (isDir) { Entry e = new Entry(f, name, true); if (entries.add(e)) { // utilize entryMap for the duplicate dir check even in // case of cflag == true. - // dir name confilict/duplicate could happen with -C option. + // dir name conflict/duplicate could happen with -C option. // just remove the last "e" from the "entries" (zos will fail // with "duplicated" entries), but continue expanding the // sub tree @@ -822,7 +844,12 @@ public class Main { } else { entryMap.put(name, e); } - expand(f, f.list(), cpaths, version); + String[] dirFiles = f.list(); + // Ensure files list is sorted for reproducible jar content + if (dirFiles != null) { + Arrays.sort(dirFiles); + } + expand(f, dirFiles, cpaths, version); } } else { error(formatMsg("error.nosuch.fileordir", String.valueOf(f))); @@ -846,12 +873,12 @@ public class Main { output(getMsg("out.added.manifest")); } ZipEntry e = new ZipEntry(MANIFEST_DIR); - e.setTime(System.currentTimeMillis()); + setZipEntryTime(e); e.setSize(0); e.setCrc(0); zos.putNextEntry(e); e = new ZipEntry(MANIFEST_NAME); - e.setTime(System.currentTimeMillis()); + setZipEntryTime(e); if (flag0) { crc32Manifest(e, manifest); } @@ -895,7 +922,7 @@ public class Main { */ boolean update(InputStream in, OutputStream out, InputStream newManifest, - Map moduleInfos, + Map moduleInfos, JarIndex jarIndex) throws IOException { ZipInputStream zis = new ZipInputStream(in); @@ -944,14 +971,14 @@ public class Main { return false; } } else if (moduleInfos != null && isModuleInfoEntry) { - moduleInfos.putIfAbsent(name, zis.readAllBytes()); + moduleInfos.putIfAbsent(name, new StreamedModuleInfoEntry(name, zis.readAllBytes(), e.getLastModifiedTime())); } else { boolean isDir = e.isDirectory(); if (!entryMap.containsKey(name)) { // copy the old stuff // do our own compression ZipEntry e2 = new ZipEntry(name); e2.setMethod(e.getMethod()); - e2.setTime(e.getTime()); + setZipEntryTime(e2, e.getTime()); e2.setComment(e.getComment()); e2.setExtra(e.getExtra()); if (e.getMethod() == ZipEntry.STORED) { @@ -1017,7 +1044,7 @@ public class Main { throws IOException { ZipEntry e = new ZipEntry(INDEX_NAME); - e.setTime(System.currentTimeMillis()); + setZipEntryTime(e); if (flag0) { CRC32OutputStream os = new CRC32OutputStream(); index.write(os); @@ -1028,15 +1055,21 @@ public class Main { zos.closeEntry(); } - private void updateModuleInfo(Map moduleInfos, ZipOutputStream zos) + private void updateModuleInfo(Map moduleInfos, ZipOutputStream zos) throws IOException { String fmt = uflag ? "out.update.module-info": "out.added.module-info"; - for (Map.Entry mi : moduleInfos.entrySet()) { + for (Map.Entry mi : moduleInfos.entrySet()) { String name = mi.getKey(); - byte[] bytes = mi.getValue(); + ModuleInfoEntry mie = mi.getValue(); + byte[] bytes = mie.readAllBytes(); ZipEntry e = new ZipEntry(name); - e.setTime(System.currentTimeMillis()); + FileTime lastModified = mie.getLastModifiedTime(); + if (lastModified != null) { + setZipEntryTime(e, lastModified.toMillis()); + } else { + setZipEntryTime(e); + } if (flag0) { crc32ModuleInfo(e, bytes); } @@ -1061,7 +1094,7 @@ public class Main { addMultiRelease(m); } ZipEntry e = new ZipEntry(MANIFEST_NAME); - e.setTime(System.currentTimeMillis()); + setZipEntryTime(e); if (flag0) { crc32Manifest(e, m); } @@ -1182,7 +1215,7 @@ public class Main { out.print(formatMsg("out.adding", name)); } ZipEntry e = new ZipEntry(name); - e.setTime(file.lastModified()); + setZipEntryTime(e, file.lastModified()); if (size == 0) { e.setMethod(ZipEntry.STORED); e.setSize(0); @@ -1625,7 +1658,7 @@ public class Main { * A fatal exception has been caught. No recovery possible */ void fatalError(Exception e) { - e.printStackTrace(); + e.printStackTrace(err); } /** @@ -1731,12 +1764,23 @@ public class Main { /** * Associates a module descriptor's zip entry name along with its - * bytes and an optional URI. Used when describing modules. + * bytes and an optional URI. */ interface ModuleInfoEntry { - String name(); - Optional uriString(); - InputStream bytes() throws IOException; + String name(); + Optional uriString(); + InputStream bytes() throws IOException; + /** + * @return Returns the last modified time of the module-info.class. + * Returns null if the last modified time is unknown or cannot be + * determined. + */ + FileTime getLastModifiedTime(); + default byte[] readAllBytes() throws IOException { + try (InputStream is = bytes()) { + return is.readAllBytes(); + } + } } static class ZipFileModuleInfoEntry implements ModuleInfoEntry { @@ -1750,6 +1794,12 @@ public class Main { @Override public InputStream bytes() throws IOException { return zipFile.getInputStream(entry); } + + @Override + public FileTime getLastModifiedTime() { + return entry.getLastModifiedTime(); + } + /** Returns an optional containing the effective URI. */ @Override public Optional uriString() { String uri = (Paths.get(zipFile.getName())).toUri().toString(); @@ -1761,14 +1811,28 @@ public class Main { static class StreamedModuleInfoEntry implements ModuleInfoEntry { private final String name; private final byte[] bytes; - StreamedModuleInfoEntry(String name, byte[] bytes) { + private final FileTime lastModifiedTime; + + StreamedModuleInfoEntry(String name, byte[] bytes, FileTime lastModifiedTime) { this.name = name; this.bytes = bytes; + this.lastModifiedTime = lastModifiedTime; } @Override public String name() { return name; } @Override public InputStream bytes() throws IOException { return new ByteArrayInputStream(bytes); } + + @Override + public byte[] readAllBytes() throws IOException { + return bytes; + } + + @Override + public FileTime getLastModifiedTime() { + return lastModifiedTime; + } + /** Returns an empty optional. */ @Override public Optional uriString() { return Optional.empty(); // no URI can be derived @@ -1820,7 +1884,7 @@ public class Main { while ((e = zis.getNextEntry()) != null) { String ename = e.getName(); if (isModuleInfoEntry(ename)) { - infos.add(new StreamedModuleInfoEntry(ename, zis.readAllBytes())); + infos.add(new StreamedModuleInfoEntry(ename, zis.readAllBytes(), e.getLastModifiedTime())); } } } @@ -2033,14 +2097,14 @@ public class Main { return (classname.replace('.', '/')) + ".class"; } - private boolean checkModuleInfo(byte[] moduleInfoBytes, Set entries) + private boolean checkModuleInfo(ModuleInfoEntry moduleInfoEntry, Set entries) throws IOException { boolean ok = true; - if (moduleInfoBytes != null) { // no root module-info.class if null + if (moduleInfoEntry != null) { // no root module-info.class if null try { // ModuleDescriptor.read() checks open/exported pkgs vs packages - ModuleDescriptor md = ModuleDescriptor.read(ByteBuffer.wrap(moduleInfoBytes)); + ModuleDescriptor md = ModuleDescriptor.read(moduleInfoEntry.bytes()); // A module must have the implementation class of the services it 'provides'. if (md.provides().stream().map(Provides::providers).flatMap(List::stream) .filter(p -> !entries.contains(toBinaryName(p))) @@ -2058,15 +2122,19 @@ public class Main { /** * Adds extended modules attributes to the given module-info's. The given - * Map values are updated in-place. Returns false if an error occurs. + * Map values are updated in-place. */ - private void addExtendedModuleAttributes(Map moduleInfos, + private void addExtendedModuleAttributes(Map moduleInfos, Set packages) throws IOException { - for (Map.Entry e: moduleInfos.entrySet()) { - ModuleDescriptor md = ModuleDescriptor.read(ByteBuffer.wrap(e.getValue())); - e.setValue(extendedInfoBytes(md, e.getValue(), packages)); + for (Map.Entry e: moduleInfos.entrySet()) { + ModuleInfoEntry mie = e.getValue(); + byte[] bytes = mie.readAllBytes(); + ModuleDescriptor md = ModuleDescriptor.read(ByteBuffer.wrap(bytes)); + byte[] extended = extendedInfoBytes(md, bytes, packages); + // replace the entry value with the extended bytes + e.setValue(new StreamedModuleInfoEntry(mie.name(), extended, mie.getLastModifiedTime())); } } @@ -2261,4 +2329,18 @@ public class Main { static Comparator ENTRY_COMPARATOR = Comparator.comparing(ZipEntry::getName, ENTRYNAME_COMPARATOR); + // Set the ZipEntry dostime using date if specified otherwise the current time + private void setZipEntryTime(ZipEntry e) { + setZipEntryTime(e, System.currentTimeMillis()); + } + + // Set the ZipEntry dostime using the date if specified + // otherwise the original time + private void setZipEntryTime(ZipEntry e, long origTime) { + if (date != null) { + e.setTimeLocal(date); + } else { + e.setTime(origTime); + } + } } 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 61b9ecc241299d08ae9754982b142b4613ddeafa..c08c6ff7f066a348ba0874fa9da903b45fc7fde7 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, 2018, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1999, 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 @@ -82,6 +82,10 @@ error.release.value.toosmall=\ release {0} not valid, must be >= 9 error.release.unexpected.versioned.entry=\ unexpected versioned entry {0} for release {1} +error.date.notvalid=\ + date {0} is not a valid ISO-8601 extended offset date-time with optional time-zone +error.date.out.of.range=\ + date {0} is not within the valid range 1980-01-01T00:00:02Z to 2099-12-31T23:59:59Z error.validator.jarfile.exception=\ can not validate {0}: {1} error.validator.jarfile.invalid=\ @@ -165,7 +169,7 @@ usage.compat=\ \n\ Usage: jar {ctxui}[vfmn0PMe] [jar-file] [manifest-file] [entry-point] [-C dir] files] ...\n\ Options:\n\ -\ \ -c create new archive\n\ +\ \ -c create new archive (including missing parent directories)\n\ \ \ -t list table of contents for archive\n\ \ \ -x extract named (or all) files from archive\n\ \ \ -u update existing archive\n\ @@ -223,7 +227,9 @@ text file and pass it to the jar command with the at sign (@) as a prefix.\n\ main.help.opt.main=\ \ Main operation mode:\n main.help.opt.main.create=\ -\ -c, --create Create the archive +\ -c, --create Create the archive. When the archive file name specified\n\ +\ by -f or --file contains a path, missing parent directories\n\ +\ will also be created main.help.opt.main.generate-index=\ \ -i, --generate-index=FILE Generate index information for the specified jar\n\ \ archives @@ -290,6 +296,10 @@ main.help.opt.create.update.index=\ \ Operation modifiers valid only in create, update, and generate-index mode:\n main.help.opt.create.update.index.no-compress=\ \ -0, --no-compress Store only; use no ZIP compression +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.other=\ \ Other options:\n main.help.opt.other.help=\ diff --git a/src/jdk.jartool/share/man/jar.1 b/src/jdk.jartool/share/man/jar.1 index 4a8c8f4ae6697fdbd7dadafc2ad4ff685e389ea9..fd134fe1467b0498f596924f082999597e96bd55 100644 --- a/src/jdk.jartool/share/man/jar.1 +++ b/src/jdk.jartool/share/man/jar.1 @@ -21,7 +21,7 @@ .\" .\" Automatically generated by Pandoc 2.3.1 .\" -.TH "JAR" "1" "2021" "JDK 18\-ea" "JDK Commands" +.TH "JAR" "1" "2022" "JDK 19\-ea" "JDK Commands" .hy .SH NAME .PP diff --git a/src/jdk.jartool/share/man/jarsigner.1 b/src/jdk.jartool/share/man/jarsigner.1 index 592a64ed8360dbcbedf35f801f8c518dec0b3f92..bcf457fb6f65603e70b40af8bc5150667766e584 100644 --- a/src/jdk.jartool/share/man/jarsigner.1 +++ b/src/jdk.jartool/share/man/jarsigner.1 @@ -1,4 +1,4 @@ -.\" Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved. +.\" Copyright (c) 1998, 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 @@ -22,7 +22,7 @@ .\"t .\" Automatically generated by Pandoc 2.3.1 .\" -.TH "JARSIGNER" "1" "2021" "JDK 18\-ea" "JDK Commands" +.TH "JARSIGNER" "1" "2022" "JDK 19\-ea" "JDK Commands" .hy .SH NAME .PP @@ -33,6 +33,8 @@ jarsigner \- sign and verify Java Archive (JAR) files .PP \f[CB]jarsigner\f[R] \f[CB]\-verify\f[R] [\f[I]options\f[R]] \f[I]jar\-file\f[R] [\f[I]alias\f[R] ...] +.PP +\f[CB]jarsigner\f[R] \f[CB]\-version\f[R] .TP .B \f[I]options\f[R] The command\-line options. @@ -69,6 +71,12 @@ The aliases are defined in the keystore specified by \f[CB]\-keystore\f[R] or the default keystore. .RS .RE +.TP +.B \f[CB]\-version\f[R] +The \f[CB]\-version\f[R] option prints the program version of +\f[CB]jarsigner\f[R]. +.RS +.RE .SH DESCRIPTION .PP The \f[CB]jarsigner\f[R] tool has two purposes: @@ -1079,6 +1087,11 @@ The property keys supported are "jarsigner.all" for all actions, name(s) cannot be set in this file. .RS .RE +.TP +.B \f[CB]\-version\f[R] +Prints the program version. +.RS +.RE .SH DEPRECATED OPTIONS .PP The following \f[CB]jarsigner\f[R] options are deprecated as of JDK 9 and diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/doclet/package-info.java b/src/jdk.javadoc/share/classes/jdk/javadoc/doclet/package-info.java index 2e895024b93db50d4d35fbdef547fb987a4a5678..3658ed74d85febdcef6be556e1a0b49925ad7c3f 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/doclet/package-info.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/doclet/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -51,9 +51,9 @@ * The invocation is defined by the interface {@link jdk.javadoc.doclet.Doclet} * -- the {@link jdk.javadoc.doclet.Doclet#run(DocletEnvironment) run} interface * method, defines the entry point. - *
          - *    public boolean run(DocletEnvironment environment)
          - * 
          + * {@snippet id="entry-point" lang=java : + * public boolean run(DocletEnvironment environment) // @highlight substring="run" + * } * The {@link jdk.javadoc.doclet.DocletEnvironment} instance holds the * environment that the doclet will be initialized with. From this environment * all other information can be extracted, in the form of @@ -185,120 +185,147 @@ * * The following is an example doclet that displays information of a class * and its members, supporting an option. - *
          - * // note imports deleted for clarity
          + *
          + * {@snippet lang=java id="Example.java" :
          + * // @replace region=imports replacement=" // Note: imports deleted for clarity"
          + * import com.sun.source.doctree.DocCommentTree;
          + * import com.sun.source.util.DocTrees;
          + * import jdk.javadoc.doclet.Doclet;
          + * import jdk.javadoc.doclet.DocletEnvironment;
          + * import jdk.javadoc.doclet.Reporter;
          + *
          + * import javax.lang.model.SourceVersion;
          + * import javax.lang.model.element.Element;
          + * import javax.lang.model.element.TypeElement;
          + * import javax.lang.model.util.ElementFilter;
          + * import javax.tools.Diagnostic.Kind;
          + * import java.io.IOException;
          + * import java.io.PrintWriter;
          + * import java.util.List;
          + * import java.util.Locale;
          + * import java.util.Set;
          + * // @end
          + *
          + *
            * public class Example implements Doclet {
          - *    Reporter reporter;
          - *    @Override
          - *    public void init(Locale locale, Reporter reporter) {
          - *        reporter.print(Kind.NOTE, "Doclet using locale: " + locale);
          - *        this.reporter = reporter;
          - *    }
          - *
          - *    public void printElement(DocTrees trees, Element e) {
          - *        DocCommentTree docCommentTree = trees.getDocCommentTree(e);
          - *        if (docCommentTree != null) {
          - *            System.out.println("Element (" + e.getKind() + ": "
          - *                    + e + ") has the following comments:");
          - *            System.out.println("Entire body: " + docCommentTree.getFullBody());
          - *            System.out.println("Block tags: " + docCommentTree.getBlockTags());
          - *        }
          - *    }
          - *
          - *    @Override
          - *    public boolean run(DocletEnvironment docEnv) {
          - *        reporter.print(Kind.NOTE, "overviewfile: " + overviewfile);
          - *        // get the DocTrees utility class to access document comments
          - *        DocTrees docTrees = docEnv.getDocTrees();
          - *
          - *        // location of an element in the same directory as overview.html
          - *        try {
          - *            Element e = ElementFilter.typesIn(docEnv.getSpecifiedElements()).iterator().next();
          - *            DocCommentTree docCommentTree
          - *                    = docTrees.getDocCommentTree(e, overviewfile);
          - *            if (docCommentTree != null) {
          - *                System.out.println("Overview html: " + docCommentTree.getFullBody());
          - *            }
          - *        } catch (IOException missing) {
          - *            reporter.print(Kind.ERROR, "No overview.html found.");
          - *        }
          - *
          - *        for (TypeElement t : ElementFilter.typesIn(docEnv.getIncludedElements())) {
          - *            System.out.println(t.getKind() + ":" + t);
          - *            for (Element e : t.getEnclosedElements()) {
          - *                printElement(docTrees, e);
          - *            }
          - *        }
          - *        return true;
          - *    }
          - *
          - *    @Override
          - *    public String getName() {
          - *        return "Example";
          - *    }
          - *
          - *    private String overviewfile;
          - *
          - *    @Override
          - *    public Set<? extends Option> getSupportedOptions() {
          - *        Option[] options = {
          - *            new Option() {
          - *                private final List<String> someOption = Arrays.asList(
          - *                        "-overviewfile",
          - *                        "--overview-file",
          - *                        "-o"
          - *                );
          - *
          - *                @Override
          - *                public int getArgumentCount() {
          - *                    return 1;
          - *                }
          - *
          - *                @Override
          - *                public String getDescription() {
          - *                    return "an option with aliases";
          - *                }
          - *
          - *                @Override
          - *                public Option.Kind getKind() {
          - *                    return Option.Kind.STANDARD;
          - *                }
          - *
          - *                @Override
          - *                public List<String> getNames() {
          - *                    return someOption;
          - *                }
          - *
          - *                @Override
          - *                public String getParameters() {
          - *                    return "file";
          - *                }
          - *
          - *                @Override
          - *                public boolean process(String opt, List<String> arguments) {
          - *                    overviewfile = arguments.get(0);
          - *                    return true;
          - *                }
          - *            }
          - *        };
          - *        return new HashSet<>(Arrays.asList(options));
          - *    }
          - *
          - *    @Override
          - *    public SourceVersion getSupportedSourceVersion() {
          - *        // support the latest release
          - *        return SourceVersion.latest();
          - *    }
          + *     private Reporter reporter;
          + *     private PrintWriter stdout;
          + *
          + *     @Override
          + *     public void init(Locale locale, Reporter reporter) {
          + *         reporter.print(Kind.NOTE, "Doclet using locale: " + locale);
          + *         this.reporter = reporter;
          + *         stdout = reporter.getStandardWriter();
          + *     }
          + *
          + *     public void printElement(DocTrees trees, Element e) {
          + *         DocCommentTree docCommentTree = trees.getDocCommentTree(e);
          + *         if (docCommentTree != null) {
          + *             stdout.println("Element (" + e.getKind() + ": "
          + *                     + e + ") has the following comments:");
          + *             stdout.println("Entire body: " + docCommentTree.getFullBody());
          + *             stdout.println("Block tags: " + docCommentTree.getBlockTags());
          + *         }
          + *     }
          + *
          + *     @Override
          + *     public boolean run(DocletEnvironment docEnv) {
          + *         reporter.print(Kind.NOTE, "overviewFile: " + overviewFile);
          + *
          + *         // get the DocTrees utility class to access document comments
          + *         DocTrees docTrees = docEnv.getDocTrees();
          + *
          + *         // location of an element in the same directory as overview.html
          + *         try {
          + *             Element e = ElementFilter.typesIn(docEnv.getSpecifiedElements()).iterator().next();
          + *             DocCommentTree docCommentTree
          + *                     = docTrees.getDocCommentTree(e, overviewFile);
          + *             if (docCommentTree != null) {
          + *                 stdout.println("Overview html: " + docCommentTree.getFullBody());
          + *             }
          + *         } catch (IOException missing) {
          + *             reporter.print(Kind.ERROR, "No overview.html found.");
          + *         }
          + *
          + *         for (TypeElement t : ElementFilter.typesIn(docEnv.getIncludedElements())) {
          + *             stdout.println(t.getKind() + ":" + t);
          + *             for (Element e : t.getEnclosedElements()) {
          + *                 printElement(docTrees, e);
          + *             }
          + *         }
          + *         return true;
          + *     }
          + *
          + *     @Override
          + *     public String getName() {
          + *         return "Example";
          + *     }
          + *
          + *     private String overviewFile;
          + *
          + *     @Override
          + *     public Set getSupportedOptions() {
          + *         Option[] options = {
          + *             new Option() {
          + *                 private final List someOption = List.of(
          + *                         "--overview-file",
          + *                         "-overviewfile",
          + *                         "-o"
          + *                 );
          + *
          + *                 @Override
          + *                 public int getArgumentCount() {
          + *                     return 1;
          + *                 }
          + *
          + *                 @Override
          + *                 public String getDescription() {
          + *                     return "an option with aliases";
          + *                 }
          + *
          + *                 @Override
          + *                 public Option.Kind getKind() {
          + *                     return Option.Kind.STANDARD;
          + *                 }
          + *
          + *                 @Override
          + *                 public List getNames() {
          + *                     return someOption;
          + *                 }
          + *
          + *                 @Override
          + *                 public String getParameters() {
          + *                     return "file";
          + *                 }
          + *
          + *                 @Override
          + *                 public boolean process(String opt, List arguments) {
          + *                     overviewFile = arguments.get(0);
          + *                     return true;
          + *                 }
          + *             }
          + *         };
          + *
          + *         return Set.of(options);
          + *     }
          + *
          + *     @Override
          + *     public SourceVersion getSupportedSourceVersion() {
          + *         // support the latest release
          + *         return SourceVersion.latest();
          + *     }
          + * }
            * }
          - * 
          + * *

          * This doclet can be invoked with a command line, such as: - *

          - *     javadoc -doclet Example \
          - *       -overviewfile overview.html \
          - *       -sourcepath source-location \
          - *       source-location/Example.java
          - * 
          + * {@snippet id="run-doclet": + * javadoc -docletpath doclet-classes \ // @highlight substring="doclet-classes " type=italic + * -doclet Example \ + * --overview-file overview.html \ + * --source-path source-location \ // @highlight region substring="source-location" type=italic + * source-location/Example.java // @end + * } * *

          Migration Guide

          * diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassUseWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassUseWriter.java index f91b06105a3a82d8043a6e1e6cd4be4123e74e5e..840676e875cab6ec486a4f948ddd24605c8e2004 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassUseWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassUseWriter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -296,8 +296,7 @@ public class ClassUseWriter extends SubWriterHolderWriter { * @param contentTree the content tree to which the class elements will be added */ protected void addClassList(Content contentTree) { - HtmlTree ul = new HtmlTree(TagName.UL); - ul.setStyle(HtmlStyle.blockList); + HtmlTree ul = HtmlTree.UL(HtmlStyle.blockList); for (PackageElement pkg : pkgSet) { HtmlTree htmlTree = HtmlTree.SECTION(HtmlStyle.detail) .setId(htmlIds.forPackage(pkg)); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassWriterImpl.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassWriterImpl.java index 40db035c8b9a4263672d9c29545ebbf5c65d65d2..45b10dc89e16241d7c5519a26b94d211c98487e0 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassWriterImpl.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassWriterImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -105,8 +105,7 @@ public class ClassWriterImpl extends SubWriterHolderWriter implements ClassWrite @Override public Content getHeader(String header) { HtmlTree bodyTree = getBody(getWindowTitle(utils.getSimpleName(typeElement))); - HtmlTree div = new HtmlTree(TagName.DIV); - div.setStyle(HtmlStyle.header); + HtmlTree div = HtmlTree.DIV(HtmlStyle.header); if (configuration.showModules) { ModuleElement mdle = configuration.docEnv.getElementUtils().getModuleOf(typeElement); Content classModuleLabel = HtmlTree.SPAN(HtmlStyle.moduleLabelInType, contents.moduleLabel); @@ -254,7 +253,7 @@ public class ClassWriterImpl extends SubWriterHolderWriter implements ClassWrite */ private Content getTreeForClassHelper(TypeMirror type) { Content content = new ContentBuilder(); - if (type.equals(typeElement.asType())) { + if (utils.typeUtils.isSameType(type, typeElement.asType())) { Content typeParameters = getTypeParameterLinks( new HtmlLinkInfo(configuration, HtmlLinkInfo.Kind.TREE, typeElement)); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ConstantsSummaryWriterImpl.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ConstantsSummaryWriterImpl.java index 2bd163b24de86046c962b2522202ea4248682ef0..1723bc6ecfd5a93650116abae9618c3b4c8947ef 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ConstantsSummaryWriterImpl.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ConstantsSummaryWriterImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -165,9 +165,7 @@ public class ConstantsSummaryWriterImpl extends HtmlDocletWriter implements Cons @Override public Content getClassConstantHeader() { - HtmlTree ul = new HtmlTree(TagName.UL); - ul.setStyle(HtmlStyle.blockList); - return ul; + return HtmlTree.UL(HtmlStyle.blockList); } @Override diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HelpWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HelpWriter.java index 167b24b622b8ede28cd7ab7bcde464eccdfb8e7d..11ed54c2d864f4eb9c6873b3533ea921a0194238 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HelpWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HelpWriter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -128,9 +128,7 @@ public class HelpWriter extends HtmlDocletWriter { * */ protected void addHelpFileContents(Content contentTree) { - HtmlTree mainTOC = new HtmlTree(TagName.UL).setStyle(HtmlStyle.helpTOC); - - + HtmlTree mainTOC = HtmlTree.UL(HtmlStyle.helpTOC); contentTree.add(HtmlTree.HEADING(Headings.PAGE_TITLE_HEADING, HtmlStyle.title, getContent("doclet.help.main_heading"))) @@ -185,7 +183,7 @@ public class HelpWriter extends HtmlDocletWriter { } content.add(navSection); - HtmlTree subTOC = new HtmlTree(TagName.UL).setStyle(HtmlStyle.helpSubTOC); + HtmlTree subTOC = HtmlTree.UL(HtmlStyle.helpSubTOC); HtmlTree section; @@ -193,7 +191,7 @@ public class HelpWriter extends HtmlDocletWriter { if (options.createIndex()) { section = newHelpSection(getContent("doclet.help.search.head"), subTOC, HtmlIds.HELP_SEARCH); Content searchIntro = HtmlTree.P(getContent("doclet.help.search.intro")); - Content searchExamples = new HtmlTree(TagName.UL).setStyle(HtmlStyle.helpSectionList); + Content searchExamples = HtmlTree.UL(HtmlStyle.helpSectionList); for (String[] example : SEARCH_EXAMPLES) { searchExamples.add(HtmlTree.LI( getContent("doclet.help.search.example", @@ -240,7 +238,7 @@ public class HelpWriter extends HtmlDocletWriter { .add(HtmlTree.HEADING(Headings.CONTENT_HEADING, pageKindsHeading).setId(HtmlIds.HELP_PAGES)) .add(contents.getContent("doclet.help.page_kinds.intro")); - HtmlTree subTOC = new HtmlTree(TagName.UL).setStyle(HtmlStyle.helpSubTOC); + HtmlTree subTOC = HtmlTree.UL(HtmlStyle.helpSubTOC); HtmlTree section; diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlConfiguration.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlConfiguration.java index 100ad33940b19d780525a88a042ba5bed448504c..a11ad5db0446d0d9d7fad9d113a4540736bd1e7e 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlConfiguration.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -25,6 +25,7 @@ package jdk.javadoc.internal.doclets.formats.html; +import java.time.ZonedDateTime; import java.util.ArrayList; import java.util.Date; import java.util.EnumSet; @@ -166,6 +167,11 @@ public class HtmlConfiguration extends BaseConfiguration { */ public final Set conditionalPages; + /** + * The build date, to be recorded in generated files. + */ + private ZonedDateTime buildDate; + /** * Constructs the full configuration needed by the doclet, including * the format-specific part, defined in this class, and the format-independent @@ -215,6 +221,7 @@ public class HtmlConfiguration extends BaseConfiguration { conditionalPages = EnumSet.noneOf(ConditionalPage.class); } + protected void initConfiguration(DocletEnvironment docEnv, Function resourceKeyMapper) { super.initConfiguration(docEnv, resourceKeyMapper); @@ -223,7 +230,6 @@ public class HtmlConfiguration extends BaseConfiguration { } private final Runtime.Version docletVersion; - public final Date startTime = new Date(); @Override public Runtime.Version getDocletVersion() { @@ -259,6 +265,10 @@ public class HtmlConfiguration extends BaseConfiguration { if (!options.validateOptions()) { return false; } + + ZonedDateTime zdt = options.date(); + buildDate = zdt != null ? zdt : ZonedDateTime.now(); + if (!getSpecifiedTypeElements().isEmpty()) { Map map = new HashMap<>(); PackageElement pkg; @@ -279,6 +289,13 @@ public class HtmlConfiguration extends BaseConfiguration { return true; } + /** + * {@return the date to be recorded in generated files} + */ + public ZonedDateTime getBuildDate() { + return buildDate; + } + /** * Decide the page which will appear first in the right-hand frame. It will * be "overview-summary.html" if "-overview" option is used or no diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDoclet.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDoclet.java index b33c39005447de519c637160a8e0dc87d7761039..e8fb77654d16521783e76c54e4b6368ab62aa26f 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDoclet.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDoclet.java @@ -313,7 +313,7 @@ public class HtmlDoclet extends AbstractDoclet { private void copyJqueryFiles() throws DocletException { List files = Arrays.asList( - "jquery-3.5.1.min.js", + "jquery-3.6.0.min.js", "jquery-ui.min.js", "jquery-ui.min.css", "jquery-ui.structure.min.css", 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 76709124ff2659d456136dbb14b46e71a3d30c30..ac6d395cb25b761355ab0a61310acc131e95df29 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -27,6 +27,7 @@ package jdk.javadoc.internal.doclets.formats.html; import java.util.ArrayList; import java.util.Collections; +import java.util.Comparator; import java.util.EnumSet; import java.util.HashMap; import java.util.HashSet; @@ -36,6 +37,7 @@ import java.util.ListIterator; import java.util.Locale; import java.util.Map; import java.util.Objects; +import java.util.Optional; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -262,7 +264,7 @@ public class HtmlDocletWriter { do { int match = docrootMatcher.start(); // append htmlstr up to start of next {@docroot} - buf.append(htmlstr.substring(prevEnd, match)); + buf.append(htmlstr, prevEnd, match); prevEnd = docrootMatcher.end(); if (options.docrootParent().length() > 0 && htmlstr.startsWith("/..", prevEnd)) { // Insert the absolute link if {@docRoot} is followed by "/..". @@ -451,7 +453,7 @@ public class HtmlDocletWriter { throws DocFileIOException { List additionalStylesheets = configuration.getAdditionalStylesheets(); additionalStylesheets.addAll(localStylesheets); - Head head = new Head(path, configuration.getDocletVersion(), configuration.startTime) + Head head = new Head(path, configuration.getDocletVersion(), configuration.getBuildDate()) .setTimestamp(!options.noTimestamp()) .setDescription(description) .setGenerator(getGenerator(getClass())) @@ -548,8 +550,7 @@ public class HtmlDocletWriter { protected Content getNavLinkMainTree(String label) { Content mainTreeContent = links.createLink(pathToRoot.resolve(DocPaths.OVERVIEW_TREE), Text.of(label)); - Content li = HtmlTree.LI(mainTreeContent); - return li; + return HtmlTree.LI(mainTreeContent); } /** @@ -622,7 +623,7 @@ public class HtmlDocletWriter { } else { flags = EnumSet.noneOf(ElementFlag.class); } - DocLink targetLink = null; + DocLink targetLink; if (included || packageElement == null) { targetLink = new DocLink(pathString(packageElement, DocPaths.PACKAGE_SUMMARY)); } else { @@ -896,7 +897,7 @@ public class HtmlDocletWriter { * Return the link for the given member. * * @param context the id of the context where the link will be printed. - * @param typeElement the typeElement that we should link to. This is not + * @param typeElement the typeElement that we should link to. This is * not necessarily the type containing element since we may be * inheriting comments. * @param element the member being linked to. @@ -912,7 +913,7 @@ public class HtmlDocletWriter { * Return the link for the given member. * * @param context the id of the context where the link will be printed. - * @param typeElement the typeElement that we should link to. This is not + * @param typeElement the typeElement that we should link to. This is * not necessarily the type containing element since we may be * inheriting comments. * @param element the member being linked to. @@ -929,7 +930,7 @@ public class HtmlDocletWriter { * Return the link for the given member. * * @param context the id of the context where the link will be printed. - * @param typeElement the typeElement that we should link to. This is not + * @param typeElement the typeElement that we should link to. This is * not necessarily the type containing element since we may be * inheriting comments. * @param element the member being linked to. @@ -945,7 +946,7 @@ public class HtmlDocletWriter { * Return the link for the given member. * * @param context the id of the context where the link will be printed. - * @param typeElement the typeElement that we should link to. This is not + * @param typeElement the typeElement that we should link to. This is * not necessarily the type containing element since we may be * inheriting comments. * @param element the member being linked to. @@ -1009,6 +1010,10 @@ public class HtmlDocletWriter { // @see reference label... label = ref.subList(1, ref.size()); } + case ERRONEOUS -> { + return invalidTagOutput(resources.getText("doclet.tag.invalid_input", seeText), + Optional.empty()); + } default -> throw new IllegalStateException(ref.get(0).getKind().toString()); } @@ -1063,7 +1068,8 @@ public class HtmlDocletWriter { "doclet.see.class_or_package_not_found", "@" + tagName, seeText); - return (labelContent.isEmpty() ? text: labelContent); + return invalidTagOutput(resources.getText("doclet.tag.invalid", tagName), + Optional.of(labelContent.isEmpty() ? text: labelContent)); } } } else if (refMemName == null) { @@ -1407,14 +1413,6 @@ public class HtmlDocletWriter { return false; } - boolean isAllWhiteSpace(String body) { - for (int i = 0 ; i < body.length(); i++) { - if (!Character.isWhitespace(body.charAt(i))) - return false; - } - return true; - } - // Notify the next DocTree handler to take necessary action private boolean commentRemoved = false; @@ -1505,7 +1503,7 @@ public class HtmlDocletWriter { // Ignore any trailing whitespace OR whitespace after removed html comment if ((isLastNode || commentRemoved) && tag.getKind() == TEXT - && isAllWhiteSpace(ch.getText(tag))) + && ch.getText(tag).isBlank()) continue; // Ignore any leading html comments @@ -1537,18 +1535,11 @@ public class HtmlDocletWriter { return false; } sb.append("="); - String quote; - switch (node.getValueKind()) { - case DOUBLE: - quote = "\""; - break; - case SINGLE: - quote = "'"; - break; - default: - quote = ""; - break; - } + String quote = switch (node.getValueKind()) { + case DOUBLE -> "\""; + case SINGLE -> "'"; + default -> ""; + }; sb.append(quote); result.add(sb); Content docRootContent = new ContentBuilder(); @@ -1622,13 +1613,18 @@ public class HtmlDocletWriter { DocTreePath dtp = ch.getDocTreePath(node); if (dtp != null) { String body = node.getBody(); - if (body.matches("(?i)\\{@[a-z]+.*")) { - messages.warning(dtp,"doclet.tag.invalid_usage", body); - } else { + Matcher m = Pattern.compile("(?i)\\{@([a-z]+).*").matcher(body); + String tagName = m.matches() ? m.group(1) : null; + if (tagName == null) { messages.warning(dtp, "doclet.tag.invalid_input", body); + result.add(invalidTagOutput(resources.getText("doclet.tag.invalid_input", body), + Optional.empty())); + } else { + messages.warning(dtp, "doclet.tag.invalid_usage", body); + result.add(invalidTagOutput(resources.getText("doclet.tag.invalid", tagName), + Optional.of(Text.of(body)))); } } - result.add(Text.of(node.toString())); return false; } @@ -1782,6 +1778,24 @@ public class HtmlDocletWriter { && currentPageElement != utils.getEnclosingTypeElement(element)); } + /** + * Returns the output for an invalid tag. The returned content uses special styling to + * highlight the problem. Depending on the presence of the {@code detail} string the method + * returns a plain text span or an expandable component. + * + * @param summary the single-line summary message + * @param detail the optional detail message which may contain preformatted text + * @return the output + */ + protected Content invalidTagOutput(String summary, Optional detail) { + if (detail.isEmpty() || detail.get().isEmpty()) { + return HtmlTree.SPAN(HtmlStyle.invalidTag, Text.of(summary)); + } + return HtmlTree.DETAILS(HtmlStyle.invalidTag) + .add(HtmlTree.SUMMARY(Text.of(summary))) + .add(HtmlTree.PRE(detail.get())); + } + /** * Returns true if element lives in the same package as the type or package * element of this writer. @@ -2209,17 +2223,13 @@ public class HtmlDocletWriter { for (Element e: chain) { String name; switch (e.getKind()) { - case MODULE: - case PACKAGE: + case MODULE, PACKAGE -> { name = ((QualifiedNameable) e).getQualifiedName().toString(); if (name.length() == 0) { name = ""; } - break; - - default: - name = e.getSimpleName().toString(); - break; + } + default -> name = e.getSimpleName().toString(); } if (sb.length() == 0) { @@ -2363,8 +2373,7 @@ public class HtmlDocletWriter { Content leadingNote = contents.getContent("doclet.PreviewLeadingNote", nameCode); previewDiv.add(HtmlTree.SPAN(HtmlStyle.previewLabel, leadingNote)); - HtmlTree ul = new HtmlTree(TagName.UL); - ul.setStyle(HtmlStyle.previewComment); + HtmlTree ul = HtmlTree.UL(HtmlStyle.previewComment); for (Content note : previewNotes) { ul.add(HtmlTree.LI(note)); } @@ -2394,6 +2403,10 @@ public class HtmlDocletWriter { if (!utils.isIncluded(enclosed)) { continue; } + if (utils.isPreviewAPI(enclosed)) { + //for class summary, ignore methods that are themselves preview: + continue; + } if (!enclosed.getKind().isClass() && !enclosed.getKind().isInterface()) { PreviewSummary memberAPITypes = utils.declaredUsingPreviewAPIs(enclosed); declaredUsingPreviewFeature.addAll(memberAPITypes.declaredUsingPreviewFeature); @@ -2428,8 +2441,7 @@ public class HtmlDocletWriter { private Content withPreviewFeatures(String key, String className, String featureName, List features) { String[] sep = new String[] {""}; ContentBuilder featureCodes = new ContentBuilder(); - features.stream() - .forEach(c -> { + features.forEach(c -> { featureCodes.add(sep[0]); featureCodes.add(HtmlTree.CODE(new ContentBuilder().add(c))); sep[0] = ", "; @@ -2444,7 +2456,7 @@ public class HtmlDocletWriter { String[] sep = new String[] {""}; ContentBuilder links = new ContentBuilder(); elements.stream() - .sorted((te1, te2) -> te1.getSimpleName().toString().compareTo(te2.getSimpleName().toString())) + .sorted(Comparator.comparing(te -> te.getSimpleName().toString())) .distinct() .map(te -> getLink(new HtmlLinkInfo(configuration, HtmlLinkInfo.Kind.CLASS, te) .label(HtmlTree.CODE(Text.of(te.getSimpleName()))).skipPreview(true))) diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlLinkFactory.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlLinkFactory.java index ee09e99cea6d93891f25aca562ce529c4d39a7cf..3956987baa9f8beeaaba1893aa4ae2554b6a189c 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlLinkFactory.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlLinkFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -89,18 +89,29 @@ public class HtmlLinkFactory extends LinkFactory { } Content label = classLinkInfo.getClassLinkLabel(configuration); Set flags; - Element target; + Element previewTarget; boolean showPreview = !classLinkInfo.skipPreview; if (!hasWhere && showPreview) { flags = utils.elementFlags(typeElement); - target = typeElement; + previewTarget = typeElement; } else if ((classLinkInfo.context == HtmlLinkInfo.Kind.SEE_TAG || classLinkInfo.context == HtmlLinkInfo.Kind.MEMBER_DEPRECATED_PREVIEW) && classLinkInfo.targetMember != null && showPreview) { flags = utils.elementFlags(classLinkInfo.targetMember); - target = classLinkInfo.targetMember; + TypeElement enclosing = utils.getEnclosingTypeElement(classLinkInfo.targetMember); + Set enclosingFlags = utils.elementFlags(enclosing); + if (flags.contains(ElementFlag.PREVIEW) && enclosingFlags.contains(ElementFlag.PREVIEW)) { + if (enclosing.equals(m_writer.getCurrentPageElement())) { + //skip the PREVIEW tag: + flags = EnumSet.copyOf(flags); + flags.remove(ElementFlag.PREVIEW); + } + previewTarget = enclosing; + } else { + previewTarget = classLinkInfo.targetMember; + } } else { flags = EnumSet.noneOf(ElementFlag.class); - target = null; + previewTarget = null; } Content link = new ContentBuilder(); @@ -115,7 +126,7 @@ public class HtmlLinkFactory extends LinkFactory { title)); if (flags.contains(ElementFlag.PREVIEW)) { link.add(HtmlTree.SUP(m_writer.links.createLink( - filename.fragment(m_writer.htmlIds.forPreviewSection(target).name()), + filename.fragment(m_writer.htmlIds.forPreviewSection(previewTarget).name()), m_writer.contents.previewMark))); } return link; @@ -130,7 +141,7 @@ public class HtmlLinkFactory extends LinkFactory { if (flags.contains(ElementFlag.PREVIEW)) { link.add(HtmlTree.SUP(m_writer.getCrossClassLink( typeElement, - m_writer.htmlIds.forPreviewSection(target).name(), + m_writer.htmlIds.forPreviewSection(previewTarget).name(), m_writer.contents.previewMark, null, false))); } @@ -192,7 +203,7 @@ public class HtmlLinkFactory extends LinkFactory { */ protected Content getTypeParameterLink(LinkInfo linkInfo, TypeMirror typeParam) { HtmlLinkInfo typeLinkInfo = new HtmlLinkInfo(m_writer.configuration, - ((HtmlLinkInfo) linkInfo).getContext(), typeParam).skipPreview(true); + ((HtmlLinkInfo) linkInfo).getContext(), typeParam); typeLinkInfo.excludeTypeBounds = linkInfo.excludeTypeBounds; typeLinkInfo.excludeTypeParameterLinks = linkInfo.excludeTypeParameterLinks; typeLinkInfo.linkToSelf = linkInfo.linkToSelf; diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlSerialFieldWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlSerialFieldWriter.java index d57d82d98479deab4d7c06ea8952d8ef016f42cd..7278ac8e3155a030914e5c3e29a23a79f92ea423 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlSerialFieldWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlSerialFieldWriter.java @@ -71,9 +71,7 @@ public class HtmlSerialFieldWriter extends FieldWriterImpl */ @Override public Content getSerializableFieldsHeader() { - HtmlTree ul = new HtmlTree(TagName.UL); - ul.setStyle(HtmlStyle.blockList); - return ul; + return HtmlTree.UL(HtmlStyle.blockList); } /** @@ -84,9 +82,7 @@ public class HtmlSerialFieldWriter extends FieldWriterImpl */ @Override public Content getFieldsContentHeader(boolean isLastContent) { - HtmlTree li = new HtmlTree(TagName.LI); - li.setStyle(HtmlStyle.blockList); - return li; + return new HtmlTree(TagName.LI).setStyle(HtmlStyle.blockList); } /** diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlSerialMethodWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlSerialMethodWriter.java index aa6e31e7c12ff1105cfd2cdc7bcb810a8f90c170..8b2bed47a00593cba96ab8b275e7a7b9ae1b13e8 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlSerialMethodWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlSerialMethodWriter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -60,9 +60,7 @@ public class HtmlSerialMethodWriter extends MethodWriterImpl implements */ @Override public Content getSerializableMethodsHeader() { - HtmlTree ul = new HtmlTree(TagName.UL); - ul.setStyle(HtmlStyle.blockList); - return ul; + return HtmlTree.UL(HtmlStyle.blockList); } /** @@ -73,9 +71,7 @@ public class HtmlSerialMethodWriter extends MethodWriterImpl implements */ @Override public Content getMethodsContentHeader(boolean isLastContent) { - HtmlTree li = new HtmlTree(TagName.LI); - li.setStyle(HtmlStyle.blockList); - return li; + return new HtmlTree(TagName.LI); } /** diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/IndexRedirectWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/IndexRedirectWriter.java index 3e169dab6f0a9d2628a26ea5b41e42106b7f5c19..299e565a65782735981e105330e9a7a8ee329675 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/IndexRedirectWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/IndexRedirectWriter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -74,7 +74,7 @@ public class IndexRedirectWriter extends HtmlDocletWriter { * @throws DocFileIOException if there is a problem generating the file */ private void generateIndexFile() throws DocFileIOException { - Head head = new Head(path, configuration.getDocletVersion(), configuration.startTime) + Head head = new Head(path, configuration.getDocletVersion(), configuration.getBuildDate()) .setTimestamp(!options.noTimestamp()) .setDescription("index redirect") .setGenerator(getGenerator(getClass())) diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/IndexWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/IndexWriter.java index 4fadb86baa7562bb85897cb71662cea841c93ade..9e486b74ab9af8a8021a9ee8a75eccb2ad31d728 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/IndexWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/IndexWriter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -292,8 +292,7 @@ public class IndexWriter extends HtmlDocletWriter { */ protected void addComment(Element element, Content contentTree) { Content span = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, getDeprecatedPhrase(element)); - HtmlTree div = new HtmlTree(TagName.DIV); - div.setStyle(HtmlStyle.deprecationBlock); + HtmlTree div = HtmlTree.DIV(HtmlStyle.deprecationBlock); if (utils.isDeprecated(element)) { div.add(span); List tags = utils.getDeprecatedTrees(element); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ModuleWriterImpl.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ModuleWriterImpl.java index e4dd2efd10dfe5c961e43e10ddbe3b8fa460a7b8..30803551b2fc66bf6d3825f1b93a0c39515ae68f 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ModuleWriterImpl.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ModuleWriterImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -180,8 +180,7 @@ public class ModuleWriterImpl extends HtmlDocletWriter implements ModuleSummaryW @Override public Content getModuleHeader(String heading) { HtmlTree bodyTree = getBody(getWindowTitle(mdle.getQualifiedName().toString())); - HtmlTree div = new HtmlTree(TagName.DIV); - div.setStyle(HtmlStyle.header); + HtmlTree div = HtmlTree.DIV(HtmlStyle.header); Content moduleHead = new ContentBuilder(); moduleHead.add(mdle.isOpen() && (configuration.docEnv.getModuleMode() == ModuleMode.ALL) ? contents.openModuleLabel : contents.moduleLabel); @@ -222,7 +221,7 @@ public class ModuleWriterImpl extends HtmlDocletWriter implements ModuleSummaryW */ @Override public Content getSummariesList() { - return new HtmlTree(TagName.UL).setStyle(HtmlStyle.summaryList); + return HtmlTree.UL(HtmlStyle.summaryList); } /** @@ -799,8 +798,7 @@ public class ModuleWriterImpl extends HtmlDocletWriter implements ModuleSummaryW List deprs = utils.getDeprecatedTrees(mdle); if (utils.isDeprecated(mdle)) { CommentHelper ch = utils.getCommentHelper(mdle); - HtmlTree deprDiv = new HtmlTree(TagName.DIV); - deprDiv.setStyle(HtmlStyle.deprecationBlock); + HtmlTree deprDiv = HtmlTree.DIV(HtmlStyle.deprecationBlock); Content deprPhrase = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, getDeprecatedPhrase(mdle)); deprDiv.add(deprPhrase); if (!deprs.isEmpty()) { @@ -859,8 +857,7 @@ public class ModuleWriterImpl extends HtmlDocletWriter implements ModuleSummaryW public void addPackageDeprecationInfo(Content li, PackageElement pkg) { if (utils.isDeprecated(pkg)) { List deprs = utils.getDeprecatedTrees(pkg); - HtmlTree deprDiv = new HtmlTree(TagName.DIV); - deprDiv.setStyle(HtmlStyle.deprecationBlock); + HtmlTree deprDiv = HtmlTree.DIV(HtmlStyle.deprecationBlock); Content deprPhrase = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, getDeprecatedPhrase(pkg)); deprDiv.add(deprPhrase); if (!deprs.isEmpty()) { diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Navigation.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Navigation.java index 4ebd0c3f5c0df01feffcd945ff6d4e73b18f67e8..3e8e556974a300210e1bc63c8db5101ac9eaf63a 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Navigation.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Navigation.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -29,7 +29,6 @@ import java.util.List; import java.util.Set; import javax.lang.model.element.Element; -import javax.lang.model.element.ElementKind; import javax.lang.model.element.ModuleElement; import javax.lang.model.element.PackageElement; import javax.lang.model.element.TypeElement; @@ -635,21 +634,21 @@ public class Navigation { .put(HtmlAttr.TITLE, rowListTitle); addMainNavLinks(navList); navDiv.add(navList); - HtmlTree ulNavSummaryRight = new HtmlTree(TagName.UL).setStyle(HtmlStyle.subNavListSmall); + HtmlTree ulNavSummaryRight = HtmlTree.UL(HtmlStyle.subNavListSmall); addSummaryLinks(ulNavSummaryRight, true); addDetailLinks(ulNavSummaryRight, true); navDiv.add(ulNavSummaryRight); tree.add(navDiv); - HtmlTree subDiv = new HtmlTree(TagName.DIV).setStyle(HtmlStyle.subNav); + HtmlTree subDiv = HtmlTree.DIV(HtmlStyle.subNav); HtmlTree div = new HtmlTree(TagName.DIV).setId(HtmlIds.NAVBAR_SUB_LIST); // Add the summary links if present. - HtmlTree ulNavSummary = new HtmlTree(TagName.UL).setStyle(HtmlStyle.subNavList); + HtmlTree ulNavSummary = HtmlTree.UL(HtmlStyle.subNavList); addSummaryLinks(ulNavSummary, false); div.add(ulNavSummary); // Add the detail links if present. - HtmlTree ulNavDetail = new HtmlTree(TagName.UL).setStyle(HtmlStyle.subNavList); + HtmlTree ulNavDetail = HtmlTree.UL(HtmlStyle.subNavList); addDetailLinks(ulNavDetail, false); div.add(ulNavDetail); subDiv.add(div); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageTreeWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageTreeWriter.java index ba54e2a26dcada166c5c793796f82479b0c7e30f..9618be166f994cb766ae7467d2a9099ad27f3c35 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageTreeWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageTreeWriter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -147,8 +147,7 @@ public class PackageTreeWriter extends AbstractTreeWriter { Content span = HtmlTree.SPAN(HtmlStyle.packageHierarchyLabel, contents.packageHierarchies); div.add(span); - HtmlTree ul = new HtmlTree (TagName.UL); - ul.setStyle(HtmlStyle.horizontal); + HtmlTree ul = HtmlTree.UL(HtmlStyle.horizontal); ul.add(getNavLinkMainTree(resources.getText("doclet.All_Packages"))); div.add(ul); } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageUseWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageUseWriter.java index b6c40c39a577876cdffbf206bf09bafbb40b55fc..1c44a1308685a2870f036d1bcc8608b4d9af6ba3 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageUseWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageUseWriter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -181,8 +181,7 @@ public class PackageUseWriter extends SubWriterHolderWriter { protected void addClassList(Content contentTree) { TableHeader classTableHeader = new TableHeader( contents.classLabel, contents.descriptionLabel); - HtmlTree ul = new HtmlTree(TagName.UL); - ul.setStyle(HtmlStyle.blockList); + HtmlTree ul = HtmlTree.UL(HtmlStyle.blockList); for (String packageName : usingPackageToUsedClasses.keySet()) { PackageElement usingPackage = utils.elementUtils.getPackageElement(packageName); HtmlTree section = HtmlTree.SECTION(HtmlStyle.detail) diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageWriterImpl.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageWriterImpl.java index 6bca82f17be7eb30e862a027eb4f4f5b272e584e..231ab6c50e2a3e357ee503005e7c74a1a1c9507e 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageWriterImpl.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageWriterImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -111,8 +111,7 @@ public class PackageWriterImpl extends HtmlDocletWriter public Content getPackageHeader() { String packageName = getLocalizedPackageName(packageElement).toString(); HtmlTree bodyTree = getBody(getWindowTitle(packageName)); - HtmlTree div = new HtmlTree(TagName.DIV); - div.setStyle(HtmlStyle.header); + HtmlTree div = HtmlTree.DIV(HtmlStyle.header); if (configuration.showModules) { ModuleElement mdle = configuration.docEnv.getElementUtils().getModuleOf(packageElement); Content classModuleLabel = HtmlTree.SPAN(HtmlStyle.moduleLabelInPackage, contents.moduleLabel); @@ -212,8 +211,7 @@ public class PackageWriterImpl extends HtmlDocletWriter List deprs = utils.getDeprecatedTrees(packageElement); if (utils.isDeprecated(packageElement)) { CommentHelper ch = utils.getCommentHelper(packageElement); - HtmlTree deprDiv = new HtmlTree(TagName.DIV); - deprDiv.setStyle(HtmlStyle.deprecationBlock); + HtmlTree deprDiv = HtmlTree.DIV(HtmlStyle.deprecationBlock); Content deprPhrase = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, getDeprecatedPhrase(packageElement)); deprDiv.add(deprPhrase); if (!deprs.isEmpty()) { @@ -228,7 +226,7 @@ public class PackageWriterImpl extends HtmlDocletWriter @Override public Content getSummariesList() { - return new HtmlTree(TagName.UL).setStyle(HtmlStyle.summaryList); + return HtmlTree.UL(HtmlStyle.summaryList); } @Override diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SerializedFormWriterImpl.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SerializedFormWriterImpl.java index 8d97e0c5b4ff6c4681bac97242f1e4b9b26988b3..242ebf371999841833b6f5a2fe3aa6d5866c0a33 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SerializedFormWriterImpl.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SerializedFormWriterImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -33,7 +33,6 @@ import javax.lang.model.element.TypeElement; import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; import jdk.javadoc.internal.doclets.formats.html.markup.Entity; import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; -import jdk.javadoc.internal.doclets.formats.html.markup.TagName; import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; import jdk.javadoc.internal.doclets.formats.html.Navigation.PageMode; import jdk.javadoc.internal.doclets.formats.html.markup.Text; @@ -90,9 +89,7 @@ public class SerializedFormWriterImpl extends SubWriterHolderWriter */ @Override public Content getSerializedSummariesHeader() { - HtmlTree ul = new HtmlTree(TagName.UL); - ul.setStyle(HtmlStyle.blockList); - return ul; + return HtmlTree.UL(HtmlStyle.blockList); } /** @@ -127,9 +124,8 @@ public class SerializedFormWriterImpl extends SubWriterHolderWriter */ @Override public Content getClassSerializedHeader() { - HtmlTree ul = new HtmlTree(TagName.UL); - ul.setStyle(HtmlStyle.blockList); - return ul; + return HtmlTree.UL(HtmlStyle.blockList); + } /** @@ -220,9 +216,8 @@ public class SerializedFormWriterImpl extends SubWriterHolderWriter */ @Override public Content getClassContentHeader() { - HtmlTree ul = new HtmlTree(TagName.UL); - ul.setStyle(HtmlStyle.blockList); - return ul; + return HtmlTree.UL(HtmlStyle.blockList); + } /** diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SourceToHTMLConverter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SourceToHTMLConverter.java index 7bc1f96b6488420756cd530640d54d94acc2c28e..4efa6a70d229eb80bf471a8b56c6a6c391b8232f 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SourceToHTMLConverter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SourceToHTMLConverter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -232,7 +232,7 @@ public class SourceToHTMLConverter { * @param path the path for the file. */ private void writeToFile(Content body, DocPath path, TypeElement te) throws DocFileIOException { - Head head = new Head(path, configuration.getDocletVersion(), configuration.startTime) + Head head = new Head(path, configuration.getDocletVersion(), configuration.getBuildDate()) // .setTimestamp(!options.notimestamp) // temporary: compatibility! .setTitle(resources.getText("doclet.Window_Source_title")) // .setCharset(options.charset) // temporary: compatibility! diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SubWriterHolderWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SubWriterHolderWriter.java index 5f09e20fd7404c2c7226b7a6db3ccdfefedd2504..0a22ce4ae4a1333b0166534658632991167aba35 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SubWriterHolderWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SubWriterHolderWriter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -36,7 +36,6 @@ import jdk.javadoc.internal.doclets.formats.html.markup.BodyContents; import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; import jdk.javadoc.internal.doclets.formats.html.markup.HtmlId; import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; -import jdk.javadoc.internal.doclets.formats.html.markup.TagName; import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; import jdk.javadoc.internal.doclets.toolkit.Content; import jdk.javadoc.internal.doclets.toolkit.util.DocPath; @@ -207,9 +206,7 @@ public abstract class SubWriterHolderWriter extends HtmlDocletWriter { * @return a content tree for the member header */ public Content getMemberTreeHeader() { - HtmlTree ul = new HtmlTree(TagName.UL); - ul.setStyle(HtmlStyle.blockList); - return ul; + return HtmlTree.UL(HtmlStyle.blockList); } /** @@ -218,7 +215,7 @@ public abstract class SubWriterHolderWriter extends HtmlDocletWriter { * @return a list to be used for the list of summaries for members of a given kind */ public Content getSummariesList() { - return new HtmlTree(TagName.UL).setStyle(HtmlStyle.summaryList); + return HtmlTree.UL(HtmlStyle.summaryList); } /** @@ -238,7 +235,7 @@ public abstract class SubWriterHolderWriter extends HtmlDocletWriter { * @return a list to be used for the list of details for members of a given kind */ public Content getDetailsList() { - return new HtmlTree(TagName.UL).setStyle(HtmlStyle.detailsList); + return HtmlTree.UL(HtmlStyle.detailsList); } /** @@ -257,7 +254,7 @@ public abstract class SubWriterHolderWriter extends HtmlDocletWriter { * @return a list to be used for the list of members of a given kind */ public Content getMemberList() { - return new HtmlTree(TagName.UL).setStyle(HtmlStyle.memberList); + return HtmlTree.UL(HtmlStyle.memberList); } /** @@ -271,9 +268,7 @@ public abstract class SubWriterHolderWriter extends HtmlDocletWriter { } public Content getMemberInheritedTree() { - HtmlTree div = new HtmlTree(TagName.DIV); - div.setStyle(HtmlStyle.inheritedList); - return div; + return HtmlTree.DIV(HtmlStyle.inheritedList); } /** diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Table.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Table.java index 25f7e98f4f259017d0de7e3e9e13c632d94555f6..8cf2e3710f08c4460135dc8b8092415d80f4362b 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Table.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Table.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -386,7 +386,7 @@ public class Table extends Content { default -> throw new IllegalStateException(); }; - HtmlTree table = new HtmlTree(TagName.DIV).setStyle(tableStyle).addStyle(columnStyle); + HtmlTree table = HtmlTree.DIV(tableStyle).addStyle(columnStyle); if ((tabMap == null || tabs.size() == 1) && !alwaysShowDefaultTab) { if (tabMap == null) { main.add(caption); @@ -396,7 +396,7 @@ public class Table extends Content { table.add(getTableBody()); main.add(table); } else { - HtmlTree tablist = new HtmlTree(TagName.DIV).setStyle(tabListStyle) + HtmlTree tablist = HtmlTree.DIV(tabListStyle) .put(HtmlAttr.ROLE, "tablist") .put(HtmlAttr.ARIA_ORIENTATION, "horizontal"); @@ -481,8 +481,6 @@ public class Table extends Content { } private HtmlTree getCaption(Content title) { - return new HtmlTree(TagName.DIV) - .setStyle(HtmlStyle.caption) - .add(HtmlTree.SPAN(title)); + return HtmlTree.DIV(HtmlStyle.caption, HtmlTree.SPAN(title)); } } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/TagletWriterImpl.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/TagletWriterImpl.java index 68506e3140ef3a2b98954d3f7ba2ddf44d99c600..adf98e0b8a0942c10524aca5bc002f94716d55fb 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/TagletWriterImpl.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/TagletWriterImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -29,6 +29,7 @@ import java.util.ArrayList; import java.util.EnumSet; import java.util.HashSet; import java.util.List; +import java.util.Optional; import java.util.Set; import javax.lang.model.element.Element; @@ -75,6 +76,7 @@ import jdk.javadoc.internal.doclets.toolkit.util.DocPath; import jdk.javadoc.internal.doclets.toolkit.util.DocPaths; import jdk.javadoc.internal.doclets.toolkit.util.IndexItem; import jdk.javadoc.internal.doclets.toolkit.util.Utils; +import jdk.javadoc.internal.doclets.toolkit.util.Utils.PreviewFlagProvider; /** * The taglet writer that writes HTML. @@ -351,8 +353,7 @@ public class TagletWriterImpl extends TagletWriter { // Use a different style if any link label is longer than 30 chars or contains commas. boolean hasLongLabels = links.stream() .anyMatch(c -> c.charCount() > SEE_TAG_MAX_INLINE_LENGTH || c.toString().contains(",")); - HtmlTree seeList = new HtmlTree(TagName.UL) - .setStyle(hasLongLabels ? HtmlStyle.seeListLong : HtmlStyle.seeList); + HtmlTree seeList = HtmlTree.UL(hasLongLabels ? HtmlStyle.seeListLong : HtmlStyle.seeList); links.stream().filter(Content::isValid).forEach(item -> { seeList.add(HtmlTree.LI(item)); }); @@ -401,6 +402,7 @@ public class TagletWriterImpl extends TagletWriter { Element e = null; String t = null; boolean linkEncountered = false; + boolean markupEncountered = false; Set classes = new HashSet<>(); for (Style s : styles) { if (s instanceof Style.Name n) { @@ -414,6 +416,8 @@ public class TagletWriterImpl extends TagletWriter { // TODO: diagnostic output } } else if (s instanceof Style.Markup) { + markupEncountered = true; + break; } else { // TODO: transform this if...else into an exhaustive // switch over the sealed Style hierarchy when "Pattern @@ -423,22 +427,30 @@ public class TagletWriterImpl extends TagletWriter { } } Content c; - if (linkEncountered) { + if (markupEncountered) { + return; + } else if (linkEncountered) { assert e != null; String line = sequence.toString(); String strippedLine = line.strip(); int idx = line.indexOf(strippedLine); assert idx >= 0; // because the stripped line is a substring of the line being stripped - Text whitespace = Text.of(line.substring(0, idx)); - // If the leading whitespace is not excluded from the link, - // browsers might exhibit unwanted behavior. For example, a - // browser might display hand-click cursor while user hovers - // over that whitespace portion of the line; or use - // underline decoration. - c = new ContentBuilder(whitespace, htmlWriter.linkToContent(element, e, t, strippedLine)); + Text whitespace = Text.of(utils.normalizeNewlines(line.substring(0, idx))); + //disable preview tagging inside the snippets: + PreviewFlagProvider prevPreviewProvider = utils.setPreviewFlagProvider(el -> false); + try { + // If the leading whitespace is not excluded from the link, + // browsers might exhibit unwanted behavior. For example, a + // browser might display hand-click cursor while user hovers + // over that whitespace portion of the line; or use + // underline decoration. + c = new ContentBuilder(whitespace, htmlWriter.linkToContent(element, e, t, strippedLine)); + } finally { + utils.setPreviewFlagProvider(prevPreviewProvider); + } // We don't care about trailing whitespace. } else { - c = HtmlTree.SPAN(Text.of(sequence)); + c = HtmlTree.SPAN(Text.of(text)); classes.forEach(((HtmlTree) c)::addStyle); } code.add(c); @@ -531,6 +543,14 @@ public class TagletWriterImpl extends TagletWriter { : Text.of(constantVal); } + @Override + protected Content invalidTagOutput(String summary, Optional detail) { + return htmlWriter.invalidTagOutput(summary, + detail.isEmpty() || detail.get().isEmpty() + ? Optional.empty() + : Optional.of(Text.of(utils.normalizeNewlines(detail.get())))); + } + @Override public Content commentTagsToOutput(DocTree holder, List tags) { return commentTagsToOutput(null, holder, tags, false); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/TreeWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/TreeWriter.java index 12971fc19dcba2d78ec7bc9aad512fa8f0b521e4..57b2b470dee83178bf8c72435fb4233c253f3727 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/TreeWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/TreeWriter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -32,10 +32,8 @@ import javax.lang.model.element.PackageElement; import jdk.javadoc.internal.doclets.formats.html.markup.BodyContents; import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; -import jdk.javadoc.internal.doclets.formats.html.markup.TagName; import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; import jdk.javadoc.internal.doclets.formats.html.Navigation.PageMode; -import jdk.javadoc.internal.doclets.formats.html.markup.Text; import jdk.javadoc.internal.doclets.toolkit.Content; import jdk.javadoc.internal.doclets.toolkit.util.ClassTree; import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException; @@ -135,8 +133,7 @@ public class TreeWriter extends AbstractTreeWriter { Content span = HtmlTree.SPAN(HtmlStyle.packageHierarchyLabel, contents.packageHierarchies); contentTree.add(span); - HtmlTree ul = new HtmlTree(TagName.UL); - ul.setStyle(HtmlStyle.horizontal); + HtmlTree ul = HtmlTree.UL(HtmlStyle.horizontal); int i = 0; for (PackageElement pkg : packages) { // If the package name length is 0 or if -nodeprecated option diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Head.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Head.java index 975154b7d1d29c67947d1f89bd833bfa82e11089..adbd5ef09fd3b257b77087fbcb2032592e022a5d 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Head.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Head.java @@ -27,12 +27,14 @@ package jdk.javadoc.internal.doclets.formats.html.markup; import java.io.IOException; import java.io.Writer; -import java.text.SimpleDateFormat; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Date; import java.util.List; +import java.util.Locale; import jdk.javadoc.internal.doclets.toolkit.Content; import jdk.javadoc.internal.doclets.toolkit.util.DocPath; @@ -50,7 +52,7 @@ import jdk.javadoc.internal.doclets.toolkit.util.DocPaths; */ public class Head extends Content { private final Runtime.Version docletVersion; - private final Date generatedDate; + private final ZonedDateTime generatedDate; private final DocPath pathToRoot; private String title; private String charset; @@ -78,7 +80,7 @@ public class Head extends Content { * @param path the path for the file that will include this HEAD element * @param docletVersion the doclet version */ - public Head(DocPath path, Runtime.Version docletVersion, Date generatedDate) { + public Head(DocPath path, Runtime.Version docletVersion, ZonedDateTime generatedDate) { this.docletVersion = docletVersion; this.generatedDate = generatedDate; pathToRoot = path.parent().invert(); @@ -279,8 +281,8 @@ public class Head extends Content { } if (showTimestamp) { - SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); - tree.add(HtmlTree.META("dc.created", dateFormat.format(generatedDate))); + DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd"); + tree.add(HtmlTree.META("dc.created", generatedDate.format(dateFormat))); } if (description != null) { @@ -309,11 +311,14 @@ public class Head extends Content { return tree; } - private Comment getGeneratedBy(boolean timestamp, Date now) { + + private Comment getGeneratedBy(boolean timestamp, ZonedDateTime buildDate) { String text = "Generated by javadoc"; // marker string, deliberately not localized text += " (" + docletVersion.feature() + ")"; if (timestamp) { - text += " on " + now; + DateTimeFormatter fmt = + DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss zzz yyyy").withLocale(Locale.US); + text += " on " + buildDate.format(fmt); } return new Comment(text); } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlStyle.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlStyle.java index 1d22926b8162ef6009c34e4b70dc38a49386c768..8301e9b9255cc0a900505b8a95d2dd0535df7cc2 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlStyle.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlStyle.java @@ -48,20 +48,14 @@ import java.util.regex.Pattern; * or {@link javax.lang.model.element.Element "language model elements"}. * The usage is made explicit when it is not clear from the surrounding context. * + * @apiNote + * The stylized use of {@code editor-fold} comments and line comments (beginning {@code //}) + * is to support extracting details of declarations with external tools. Edit with care! + * * @see WhatWG: {@code class} attribute */ public enum HtmlStyle { - /** - * The class of the {@code div} element containing a snippet element. - */ - snippetContainer, - - /** - * The class of the {@code a} element to copy snippet content to the clipboard. - */ - snippetCopy, - // // // The following constants are used for the main navigation bar that appears in the @@ -324,17 +318,6 @@ public enum HtmlStyle { */ propertyDetails, - /** - * The class for the list containing the {@code @see} tags of an element. - */ - seeList, - - /** - * The class for the list containing the {@code @see} tags of an element - * when some of the tags have longer labels. - */ - seeListLong, - /** * The class for a {@code section} element containing details of the * serialized form of an element, on the "Serialized Form" page. @@ -391,6 +374,17 @@ public enum HtmlStyle { */ previewLabel, + /** + * The class for the list containing the {@code @see} tags of an element. + */ + seeList, + + /** + * The class for the list containing the {@code @see} tags of an element + * when some of the tags have longer labels. + */ + seeListLong, + // // @@ -844,6 +838,44 @@ public enum HtmlStyle { // + // + // + // The following constants are used for the contents of snippets. + // In addition, the translation of a snippet may use the class + // {@code language-LANG} where LANG is either specified explicitly + // by the "lang" attribute in a snippet tag, or can be inferred + // from the kind of an external snippet. + + /** + * The class of the {@code pre} element presenting a snippet. + */ + snippet, + + /** + * The class of the {@code div} element containing a snippet element. + */ + snippetContainer, + + /** + * The class of the UI element to copy snippet content to the clipboard. + */ + snippetCopy, + + /** + * The class of text highlighted with the type {@code bold}. + */ + bold, + + /** + * The class of text highlighted with the type {@code italic}. + */ + italic, + + /** + * The class of text highlighted with the type {@code highlighted}. + */ + highlighted, + // // // The following constants are used in various places across a variety of pages. @@ -907,6 +939,12 @@ public enum HtmlStyle { */ inheritedList, + /** + * The class of an element that acts as a notification for an invalid tag + * or other invalid items. + */ + invalidTag, + /** * The class of a {@code p} element containing legal copy in the page footer. */ @@ -918,7 +956,7 @@ public enum HtmlStyle { memberNameLink, /** - * The class for a {@code dl} element containing serial UID information in + * The class of a {@code dl} element containing serial UID information in * the serialized form page. */ nameValue, @@ -959,11 +997,6 @@ public enum HtmlStyle { */ sourceLineNo, - /** - * The class of the {@code pre} element presenting a snippet. - */ - snippet, - /** * The class of an {@code a} element for a link to a class or interface. */ diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlTree.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlTree.java index 1d05cd8c4d4cd676531fb4c0aeb74cc1ff241d98..4b954ef1a31b7570caaf8cf1618a96f98cfff75c 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlTree.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 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 @@ -27,14 +27,17 @@ package jdk.javadoc.internal.doclets.formats.html.markup; import java.io.IOException; import java.io.Writer; +import java.net.URI; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.BitSet; +import java.util.Collection; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.function.Function; import jdk.javadoc.internal.doclets.formats.html.markup.HtmlAttr.Role; import jdk.javadoc.internal.doclets.toolkit.Content; @@ -222,6 +225,20 @@ public class HtmlTree extends Content { return this; } + /** + * Adds each of a collection of items, using a map function to create the content for each item. + * + * @param items the items + * @param mapper the map function to generate the content for each item + * + * @return this object + */ + @Override + public HtmlTree addAll(Collection items, Function mapper) { + items.forEach(item -> add(mapper.apply(item))); + return this; + } + @Override public int charCount() { int n = 0; @@ -301,6 +318,7 @@ public class HtmlTree extends Content { /** * Creates an HTML {@code A} element. + * The {@code ref} argument will be URL-encoded for use as the attribute value. * * @param ref the value for the {@code href} attribute} * @param body the content for element @@ -312,6 +330,22 @@ public class HtmlTree extends Content { .add(body); } + /** + * Creates an HTML {@code A} element. + * The {@code ref} argument is assumed to be already suitably encoded, + * and will not be additionally URL-encoded, but will be + * {@link URI#toASCIIString() converted} to ASCII for use as the attribute value. + * + * @param ref the value for the {@code href} attribute} + * @param body the content for element + * @return the element + */ + public static HtmlTree A(URI ref, Content body) { + return new HtmlTree(TagName.A) + .put(HtmlAttr.HREF, ref.toASCIIString()) + .add(body); + } + /** * Creates an HTML {@code CAPTION} element with the given content. * @@ -345,6 +379,16 @@ public class HtmlTree extends Content { .add(body); } + /** + * Creates an HTML {@code DETAILS} element. + * + * @return the element + */ + public static HtmlTree DETAILS(HtmlStyle style) { + return new HtmlTree(TagName.DETAILS) + .setStyle(style); + } + /** * Creates an HTML {@code DL} element with the given style. * @@ -495,12 +539,10 @@ public class HtmlTree extends Content { } private static TagName checkHeading(TagName headingTag) { - switch (headingTag) { - case H1: case H2: case H3: case H4: case H5: case H6: - return headingTag; - default: - throw new IllegalArgumentException(headingTag.toString()); - } + return switch (headingTag) { + case H1, H2, H3, H4, H5, H6 -> headingTag; + default -> throw new IllegalArgumentException(headingTag.toString()); + }; } /** @@ -682,6 +724,16 @@ public class HtmlTree extends Content { .setStyle(style); } + /** + * Creates an HTML {@code PRE} element with some content. + * + * @param body the content + * @return the element + */ + public static HtmlTree PRE(Content body) { + return new HtmlTree(TagName.PRE).add(body); + } + /** * Creates an HTML {@code SCRIPT} element with some script content. * The type of the script is set to {@code text/javascript}. @@ -782,6 +834,17 @@ public class HtmlTree extends Content { .add(body); } + /** + * Creates an HTML {@code SUMMARY} element with the given content. + * + * @param body the content + * @return the element + */ + public static HtmlTree SUMMARY(Content body) { + return new HtmlTree(TagName.SUMMARY) + .add(body); + } + /** * Creates an HTML {@code SUP} element with the given content. * @@ -845,6 +908,17 @@ public class HtmlTree extends Content { .add(body); } + /** + * Creates an HTML {@code UL} element with the given style. + * + * @param style the style + * @return the element + */ + public static HtmlTree UL(HtmlStyle style) { + return new HtmlTree(TagName.UL) + .setStyle(style); + } + /** * Creates an HTML {@code UL} element with the given style and some content. * @@ -863,6 +937,21 @@ public class HtmlTree extends Content { return htmlTree; } + /** + * Creates an HTML {@code UL} element with the given style and content generated + * from a collection of items.. + * + * @param style the style + * @param items the items to be added to the list + * @param mapper a mapper to create the content for each item + * @return the element + */ + public static HtmlTree UL(HtmlStyle style, Collection items, Function mapper) { + return new HtmlTree(TagName.UL) + .setStyle(style) + .addAll(items, mapper); + } + @Override public boolean isEmpty() { return (!hasContent() && !hasAttrs()); @@ -905,30 +994,29 @@ public class HtmlTree extends Content { */ @Override public boolean isValid() { - switch (tagName) { - case A: - return (hasAttr(HtmlAttr.ID) || (hasAttr(HtmlAttr.HREF) && hasContent())); - case BR: - return (!hasContent() && (!hasAttrs() || hasAttr(HtmlAttr.CLEAR))); - case HR: - case INPUT: - return (!hasContent()); - case IMG: - return (hasAttr(HtmlAttr.SRC) && hasAttr(HtmlAttr.ALT) && !hasContent()); - case LINK: - return (hasAttr(HtmlAttr.HREF) && !hasContent()); - case META: - return (hasAttr(HtmlAttr.CONTENT) && !hasContent()); - case SCRIPT: - return ((hasAttr(HtmlAttr.TYPE) && hasAttr(HtmlAttr.SRC) && !hasContent()) || - (hasAttr(HtmlAttr.TYPE) && hasContent())); - case SPAN: - return (hasAttr(HtmlAttr.ID) || hasContent()); - case WBR: - return (!hasContent()); - default : - return hasContent(); - } + return switch (tagName) { + case A -> + hasAttr(HtmlAttr.ID) || (hasAttr(HtmlAttr.HREF) && hasContent()); + case BR -> + !hasContent() && (!hasAttrs() || hasAttr(HtmlAttr.CLEAR)); + case HR, INPUT -> + !hasContent(); + case IMG -> + hasAttr(HtmlAttr.SRC) && hasAttr(HtmlAttr.ALT) && !hasContent(); + case LINK -> + hasAttr(HtmlAttr.HREF) && !hasContent(); + case META -> + hasAttr(HtmlAttr.CONTENT) && !hasContent(); + case SCRIPT -> + (hasAttr(HtmlAttr.TYPE) && hasAttr(HtmlAttr.SRC) && !hasContent()) + || (hasAttr(HtmlAttr.TYPE) && hasContent()); + case SPAN -> + hasAttr(HtmlAttr.ID) || hasContent(); + case WBR -> + !hasContent(); + default -> + hasContent(); + }; } /** @@ -939,14 +1027,10 @@ public class HtmlTree extends Content { * @see Phrasing Content */ public boolean isInline() { - switch (tagName) { - case A: case BUTTON: case BR: case CODE: case EM: case I: case IMG: - case LABEL: case SMALL: case SPAN: case STRONG: case SUB: case SUP: - case WBR: - return true; - default: - return false; - } + return switch (tagName) { + case A, BUTTON, BR, CODE, EM, I, IMG, LABEL, SMALL, SPAN, STRONG, SUB, SUP, WBR -> true; + default -> false; + }; } /** @@ -957,12 +1041,10 @@ public class HtmlTree extends Content { * @see Void Elements */ public boolean isVoid() { - switch (tagName) { - case BR: case HR: case IMG: case INPUT: case LINK: case META: case WBR: - return true; - default: - return false; - } + return switch (tagName) { + case BR, HR, IMG, INPUT, LINK, META, WBR -> true; + default -> false; + }; } @Override diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/TagName.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/TagName.java index 34655300b30b6dfbe154ac5c8568b91511b085c8..59aad16bf2d88f28fa15d0836466238f2d2255bf 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/TagName.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/TagName.java @@ -47,6 +47,7 @@ public enum TagName { CAPTION, CODE, DD, + DETAILS, DIV, DL, DT, @@ -83,6 +84,7 @@ public enum TagName { SPAN, STRONG, SUB, + SUMMARY, SUP, TABLE, TBODY, diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/script-dir/jquery-3.5.1.min.js b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/script-dir/jquery-3.5.1.min.js deleted file mode 100644 index b0614034ad3a95e4ae9f53c2b015eeb3e8d68bde..0000000000000000000000000000000000000000 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/script-dir/jquery-3.5.1.min.js +++ /dev/null @@ -1,2 +0,0 @@ -/*! jQuery v3.5.1 | (c) JS Foundation and other contributors | jquery.org/license */ -!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],r=Object.getPrototypeOf,s=t.slice,g=t.flat?function(e){return t.flat.call(e)}:function(e){return t.concat.apply([],e)},u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType},x=function(e){return null!=e&&e===e.window},E=C.document,c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.5.1",S=function(e,t){return new S.fn.init(e,t)};function p(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp(F),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+F),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(p.childNodes),p.childNodes),t[p.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!N[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&(U.test(t)||z.test(t))){(f=ee.test(t)&&ye(e.parentNode)||e)===e&&d.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=S)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+xe(l[o]);c=l.join(",")}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){N(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return g(t.replace($,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[S]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e.namespaceURI,n=(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:p;return r!=C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),p!=C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.scope=ce(function(e){return a.appendChild(e).appendChild(C.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length}),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=S,!C.getElementsByName||!C.getElementsByName(S).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+S+"-]").length||v.push("~="),(t=C.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||v.push("\\["+M+"*name"+M+"*="+M+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+S+"+*").length||v.push(".#.+[+~]"),e.querySelectorAll("\\\f"),v.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",F)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},D=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e==C||e.ownerDocument==p&&y(p,e)?-1:t==C||t.ownerDocument==p&&y(p,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==C?-1:t==C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]==p?-1:s[r]==p?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(T(e),d.matchesSelector&&E&&!N[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){N(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function D(e,n,r){return m(n)?S.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?S.grep(e,function(e){return e===n!==r}):"string"!=typeof n?S.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(S.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||j,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:q.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof S?t[0]:t,S.merge(this,S.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),N.test(r[1])&&S.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(S):S.makeArray(e,this)}).prototype=S.fn,j=S(E);var L=/^(?:parents|prev(?:Until|All))/,H={children:!0,contents:!0,next:!0,prev:!0};function O(e,t){while((e=e[t])&&1!==e.nodeType);return e}S.fn.extend({has:function(e){var t=S(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i;ce=E.createDocumentFragment().appendChild(E.createElement("div")),(fe=E.createElement("input")).setAttribute("type","radio"),fe.setAttribute("checked","checked"),fe.setAttribute("name","t"),ce.appendChild(fe),y.checkClone=ce.cloneNode(!0).cloneNode(!0).lastChild.checked,ce.innerHTML="",y.noCloneChecked=!!ce.cloneNode(!0).lastChild.defaultValue,ce.innerHTML="",y.option=!!ce.lastChild;var ge={thead:[1,"","
          "],col:[2,"","
          "],tr:[2,"","
          "],td:[3,"","
          "],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?S.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;n",""]);var me=/<|&#?\w+;/;function xe(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function qe(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&S(e).children("tbody")[0]||e}function Le(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function He(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Oe(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0,r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var Ut,Xt=[],Vt=/(=)\?(?=&|$)|\?\?/;S.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Xt.pop()||S.expando+"_"+Ct.guid++;return this[e]=!0,e}}),S.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Vt.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Vt.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Vt,"$1"+r):!1!==e.jsonp&&(e.url+=(Et.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||S.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?S(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Xt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((Ut=E.implementation.createHTMLDocument("").body).innerHTML="
          ",2===Ut.childNodes.length),S.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=N.exec(e))?[t.createElement(i[1])]:(i=xe([e],t,o),o&&o.length&&S(o).remove(),S.merge([],i.childNodes)));var r,i,o},S.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(S.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},S.expr.pseudos.animated=function(t){return S.grep(S.timers,function(e){return t===e.elem}).length},S.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=S.css(e,"position"),c=S(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=S.css(e,"top"),u=S.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,S.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):("number"==typeof f.top&&(f.top+="px"),"number"==typeof f.left&&(f.left+="px"),c.css(f))}},S.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){S.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===S.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===S.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=S(e).offset()).top+=S.css(e,"borderTopWidth",!0),i.left+=S.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-S.css(r,"marginTop",!0),left:t.left-i.left-S.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===S.css(e,"position"))e=e.offsetParent;return e||re})}}),S.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;S.fn[t]=function(e){return $(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),S.each(["top","left"],function(e,n){S.cssHooks[n]=$e(y.pixelPosition,function(e,t){if(t)return t=Be(e,n),Me.test(t)?S(e).position()[n]+"px":t})}),S.each({Height:"height",Width:"width"},function(a,s){S.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){S.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return $(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?S.css(e,t,i):S.style(e,t,n,i)},s,n?e:void 0,n)}})}),S.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){S.fn[t]=function(e){return this.on(t,e)}}),S.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),S.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){S.fn[n]=function(e,t){return 0 elements - // (i.e., `typeof document.createElement( "object" ) === "function"`). - // We don't want to classify *any* DOM node as a function. - return typeof obj === "function" && typeof obj.nodeType !== "number"; - }; + // Support: Chrome <=57, Firefox <=52 + // In some browsers, typeof returns "function" for HTML elements + // (i.e., `typeof document.createElement( "object" ) === "function"`). + // We don't want to classify *any* DOM node as a function. + // Support: QtWeb <=3.8.5, WebKit <=534.34, wkhtmltopdf tool <=0.12.5 + // Plus for old WebKit, typeof returns "function" for HTML collections + // (e.g., `typeof document.getElementsByTagName("div") === "function"`). (gh-4756) + return typeof obj === "function" && typeof obj.nodeType !== "number" && + typeof obj.item !== "function"; + }; var isWindow = function isWindow( obj ) { @@ -147,7 +151,7 @@ function toType( obj ) { var - version = "3.5.1", + version = "3.6.0", // Define a local copy of jQuery jQuery = function( selector, context ) { @@ -401,7 +405,7 @@ jQuery.extend( { if ( isArrayLike( Object( arr ) ) ) { jQuery.merge( ret, typeof arr === "string" ? - [ arr ] : arr + [ arr ] : arr ); } else { push.call( ret, arr ); @@ -496,9 +500,9 @@ if ( typeof Symbol === "function" ) { // Populate the class2type map jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ), -function( _i, name ) { - class2type[ "[object " + name + "]" ] = name.toLowerCase(); -} ); + function( _i, name ) { + class2type[ "[object " + name + "]" ] = name.toLowerCase(); + } ); function isArrayLike( obj ) { @@ -518,14 +522,14 @@ function isArrayLike( obj ) { } var Sizzle = /*! - * Sizzle CSS Selector Engine v2.3.5 + * Sizzle CSS Selector Engine v2.3.6 * https://sizzlejs.com/ * * Copyright JS Foundation and other contributors * Released under the MIT license * https://js.foundation/ * - * Date: 2020-03-14 + * Date: 2021-02-16 */ ( function( window ) { var i, @@ -1108,8 +1112,8 @@ support = Sizzle.support = {}; * @returns {Boolean} True iff elem is a non-HTML XML node */ isXML = Sizzle.isXML = function( elem ) { - var namespace = elem.namespaceURI, - docElem = ( elem.ownerDocument || elem ).documentElement; + var namespace = elem && elem.namespaceURI, + docElem = elem && ( elem.ownerDocument || elem ).documentElement; // Support: IE <=8 // Assume HTML when documentElement doesn't yet exist, such as inside loading iframes @@ -3024,9 +3028,9 @@ var rneedsContext = jQuery.expr.match.needsContext; function nodeName( elem, name ) { - return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); + return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); -}; +} var rsingleTag = ( /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i ); @@ -3997,8 +4001,8 @@ jQuery.extend( { resolveContexts = Array( i ), resolveValues = slice.call( arguments ), - // the master Deferred - master = jQuery.Deferred(), + // the primary Deferred + primary = jQuery.Deferred(), // subordinate callback factory updateFunc = function( i ) { @@ -4006,30 +4010,30 @@ jQuery.extend( { resolveContexts[ i ] = this; resolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value; if ( !( --remaining ) ) { - master.resolveWith( resolveContexts, resolveValues ); + primary.resolveWith( resolveContexts, resolveValues ); } }; }; // Single- and empty arguments are adopted like Promise.resolve if ( remaining <= 1 ) { - adoptValue( singleValue, master.done( updateFunc( i ) ).resolve, master.reject, + adoptValue( singleValue, primary.done( updateFunc( i ) ).resolve, primary.reject, !remaining ); // Use .then() to unwrap secondary thenables (cf. gh-3000) - if ( master.state() === "pending" || + if ( primary.state() === "pending" || isFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) { - return master.then(); + return primary.then(); } } // Multiple arguments are aggregated like Promise.all array elements while ( i-- ) { - adoptValue( resolveValues[ i ], updateFunc( i ), master.reject ); + adoptValue( resolveValues[ i ], updateFunc( i ), primary.reject ); } - return master.promise(); + return primary.promise(); } } ); @@ -4180,8 +4184,8 @@ var access = function( elems, fn, key, value, chainable, emptyGet, raw ) { for ( ; i < len; i++ ) { fn( elems[ i ], key, raw ? - value : - value.call( elems[ i ], i, fn( elems[ i ], key ) ) + value : + value.call( elems[ i ], i, fn( elems[ i ], key ) ) ); } } @@ -5089,10 +5093,7 @@ function buildFragment( elems, context, scripts, selection, ignored ) { } -var - rkeyEvent = /^key/, - rmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/, - rtypenamespace = /^([^.]*)(?:\.(.+)|)/; +var rtypenamespace = /^([^.]*)(?:\.(.+)|)/; function returnTrue() { return true; @@ -5387,8 +5388,8 @@ jQuery.event = { event = jQuery.event.fix( nativeEvent ), handlers = ( - dataPriv.get( this, "events" ) || Object.create( null ) - )[ event.type ] || [], + dataPriv.get( this, "events" ) || Object.create( null ) + )[ event.type ] || [], special = jQuery.event.special[ event.type ] || {}; // Use the fix-ed jQuery.Event rather than the (read-only) native event @@ -5512,12 +5513,12 @@ jQuery.event = { get: isFunction( hook ) ? function() { if ( this.originalEvent ) { - return hook( this.originalEvent ); + return hook( this.originalEvent ); } } : function() { if ( this.originalEvent ) { - return this.originalEvent[ name ]; + return this.originalEvent[ name ]; } }, @@ -5656,7 +5657,13 @@ function leverageNative( el, type, expectSync ) { // Cancel the outer synthetic event event.stopImmediatePropagation(); event.preventDefault(); - return result.value; + + // Support: Chrome 86+ + // In Chrome, if an element having a focusout handler is blurred by + // clicking outside of it, it invokes the handler synchronously. If + // that handler calls `.remove()` on the element, the data is cleared, + // leaving `result` undefined. We need to guard against this. + return result && result.value; } // If this is an inner synthetic event for an event with a bubbling surrogate @@ -5821,34 +5828,7 @@ jQuery.each( { targetTouches: true, toElement: true, touches: true, - - which: function( event ) { - var button = event.button; - - // Add which for key events - if ( event.which == null && rkeyEvent.test( event.type ) ) { - return event.charCode != null ? event.charCode : event.keyCode; - } - - // Add which for click: 1 === left; 2 === middle; 3 === right - if ( !event.which && button !== undefined && rmouseEvent.test( event.type ) ) { - if ( button & 1 ) { - return 1; - } - - if ( button & 2 ) { - return 3; - } - - if ( button & 4 ) { - return 2; - } - - return 0; - } - - return event.which; - } + which: true }, jQuery.event.addProp ); jQuery.each( { focus: "focusin", blur: "focusout" }, function( type, delegateType ) { @@ -5874,6 +5854,12 @@ jQuery.each( { focus: "focusin", blur: "focusout" }, function( type, delegateTyp return true; }, + // Suppress native focus or blur as it's already being fired + // in leverageNative. + _default: function() { + return true; + }, + delegateType: delegateType }; } ); @@ -6541,6 +6527,10 @@ var rboxStyle = new RegExp( cssExpand.join( "|" ), "i" ); // set in CSS while `offset*` properties report correct values. // Behavior in IE 9 is more subtle than in newer versions & it passes // some versions of this test; make sure not to make it pass there! + // + // Support: Firefox 70+ + // Only Firefox includes border widths + // in computed dimensions. (gh-4529) reliableTrDimensions: function() { var table, tr, trChild, trStyle; if ( reliableTrDimensionsVal == null ) { @@ -6548,17 +6538,32 @@ var rboxStyle = new RegExp( cssExpand.join( "|" ), "i" ); tr = document.createElement( "tr" ); trChild = document.createElement( "div" ); - table.style.cssText = "position:absolute;left:-11111px"; + table.style.cssText = "position:absolute;left:-11111px;border-collapse:separate"; + tr.style.cssText = "border:1px solid"; + + // Support: Chrome 86+ + // Height set through cssText does not get applied. + // Computed height then comes back as 0. tr.style.height = "1px"; trChild.style.height = "9px"; + // Support: Android 8 Chrome 86+ + // In our bodyBackground.html iframe, + // display for all div elements is set to "inline", + // which causes a problem only in Android 8 Chrome 86. + // Ensuring the div is display: block + // gets around this issue. + trChild.style.display = "block"; + documentElement .appendChild( table ) .appendChild( tr ) .appendChild( trChild ); trStyle = window.getComputedStyle( tr ); - reliableTrDimensionsVal = parseInt( trStyle.height ) > 3; + reliableTrDimensionsVal = ( parseInt( trStyle.height, 10 ) + + parseInt( trStyle.borderTopWidth, 10 ) + + parseInt( trStyle.borderBottomWidth, 10 ) ) === tr.offsetHeight; documentElement.removeChild( table ); } @@ -7022,10 +7027,10 @@ jQuery.each( [ "height", "width" ], function( _i, dimension ) { // Running getBoundingClientRect on a disconnected node // in IE throws an error. ( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ? - swap( elem, cssShow, function() { - return getWidthOrHeight( elem, dimension, extra ); - } ) : - getWidthOrHeight( elem, dimension, extra ); + swap( elem, cssShow, function() { + return getWidthOrHeight( elem, dimension, extra ); + } ) : + getWidthOrHeight( elem, dimension, extra ); } }, @@ -7084,7 +7089,7 @@ jQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft, swap( elem, { marginLeft: 0 }, function() { return elem.getBoundingClientRect().left; } ) - ) + "px"; + ) + "px"; } } ); @@ -7223,7 +7228,7 @@ Tween.propHooks = { if ( jQuery.fx.step[ tween.prop ] ) { jQuery.fx.step[ tween.prop ]( tween ); } else if ( tween.elem.nodeType === 1 && ( - jQuery.cssHooks[ tween.prop ] || + jQuery.cssHooks[ tween.prop ] || tween.elem.style[ finalPropName( tween.prop ) ] != null ) ) { jQuery.style( tween.elem, tween.prop, tween.now + tween.unit ); } else { @@ -7468,7 +7473,7 @@ function defaultPrefilter( elem, props, opts ) { anim.done( function() { - /* eslint-enable no-loop-func */ + /* eslint-enable no-loop-func */ // The final step of a "hide" animation is actually hiding the element if ( !hidden ) { @@ -7588,7 +7593,7 @@ function Animation( elem, properties, options ) { tweens: [], createTween: function( prop, end ) { var tween = jQuery.Tween( elem, animation.opts, prop, end, - animation.opts.specialEasing[ prop ] || animation.opts.easing ); + animation.opts.specialEasing[ prop ] || animation.opts.easing ); animation.tweens.push( tween ); return tween; }, @@ -7761,7 +7766,8 @@ jQuery.fn.extend( { anim.stop( true ); } }; - doAnimation.finish = doAnimation; + + doAnimation.finish = doAnimation; return empty || optall.queue === false ? this.each( doAnimation ) : @@ -8401,8 +8407,8 @@ jQuery.fn.extend( { if ( this.setAttribute ) { this.setAttribute( "class", className || value === false ? - "" : - dataPriv.get( this, "__className__" ) || "" + "" : + dataPriv.get( this, "__className__" ) || "" ); } } @@ -8417,7 +8423,7 @@ jQuery.fn.extend( { while ( ( elem = this[ i++ ] ) ) { if ( elem.nodeType === 1 && ( " " + stripAndCollapse( getClass( elem ) ) + " " ).indexOf( className ) > -1 ) { - return true; + return true; } } @@ -8707,9 +8713,7 @@ jQuery.extend( jQuery.event, { special.bindType || type; // jQuery handler - handle = ( - dataPriv.get( cur, "events" ) || Object.create( null ) - )[ event.type ] && + handle = ( dataPriv.get( cur, "events" ) || Object.create( null ) )[ event.type ] && dataPriv.get( cur, "handle" ); if ( handle ) { handle.apply( cur, data ); @@ -8856,7 +8860,7 @@ var rquery = ( /\?/ ); // Cross-browser xml parsing jQuery.parseXML = function( data ) { - var xml; + var xml, parserErrorElem; if ( !data || typeof data !== "string" ) { return null; } @@ -8865,12 +8869,17 @@ jQuery.parseXML = function( data ) { // IE throws on parseFromString with invalid input. try { xml = ( new window.DOMParser() ).parseFromString( data, "text/xml" ); - } catch ( e ) { - xml = undefined; - } + } catch ( e ) {} - if ( !xml || xml.getElementsByTagName( "parsererror" ).length ) { - jQuery.error( "Invalid XML: " + data ); + parserErrorElem = xml && xml.getElementsByTagName( "parsererror" )[ 0 ]; + if ( !xml || parserErrorElem ) { + jQuery.error( "Invalid XML: " + ( + parserErrorElem ? + jQuery.map( parserErrorElem.childNodes, function( el ) { + return el.textContent; + } ).join( "\n" ) : + data + ) ); } return xml; }; @@ -8971,16 +8980,14 @@ jQuery.fn.extend( { // Can add propHook for "elements" to filter or add form elements var elements = jQuery.prop( this, "elements" ); return elements ? jQuery.makeArray( elements ) : this; - } ) - .filter( function() { + } ).filter( function() { var type = this.type; // Use .is( ":disabled" ) so that fieldset[disabled] works return this.name && !jQuery( this ).is( ":disabled" ) && rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) && ( this.checked || !rcheckableType.test( type ) ); - } ) - .map( function( _i, elem ) { + } ).map( function( _i, elem ) { var val = jQuery( this ).val(); if ( val == null ) { @@ -9033,7 +9040,8 @@ var // Anchor tag for parsing the document origin originAnchor = document.createElement( "a" ); - originAnchor.href = location.href; + +originAnchor.href = location.href; // Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport function addToPrefiltersOrTransports( structure ) { @@ -9414,8 +9422,8 @@ jQuery.extend( { // Context for global events is callbackContext if it is a DOM node or jQuery collection globalEventContext = s.context && ( callbackContext.nodeType || callbackContext.jquery ) ? - jQuery( callbackContext ) : - jQuery.event, + jQuery( callbackContext ) : + jQuery.event, // Deferreds deferred = jQuery.Deferred(), @@ -9727,8 +9735,10 @@ jQuery.extend( { response = ajaxHandleResponses( s, jqXHR, responses ); } - // Use a noop converter for missing script - if ( !isSuccess && jQuery.inArray( "script", s.dataTypes ) > -1 ) { + // Use a noop converter for missing script but not if jsonp + if ( !isSuccess && + jQuery.inArray( "script", s.dataTypes ) > -1 && + jQuery.inArray( "json", s.dataTypes ) < 0 ) { s.converters[ "text script" ] = function() {}; } @@ -10466,12 +10476,6 @@ jQuery.offset = { options.using.call( elem, props ); } else { - if ( typeof props.top === "number" ) { - props.top += "px"; - } - if ( typeof props.left === "number" ) { - props.left += "px"; - } curElem.css( props ); } } @@ -10640,8 +10644,11 @@ jQuery.each( [ "top", "left" ], function( _i, prop ) { // Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods jQuery.each( { Height: "height", Width: "width" }, function( name, type ) { - jQuery.each( { padding: "inner" + name, content: type, "": "outer" + name }, - function( defaultExtra, funcName ) { + jQuery.each( { + padding: "inner" + name, + content: type, + "": "outer" + name + }, function( defaultExtra, funcName ) { // Margin is only for outerHeight, outerWidth jQuery.fn[ funcName ] = function( margin, value ) { @@ -10726,7 +10733,8 @@ jQuery.fn.extend( { } } ); -jQuery.each( ( "blur focus focusin focusout resize scroll click dblclick " + +jQuery.each( + ( "blur focus focusin focusout resize scroll click dblclick " + "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + "change select submit keydown keypress keyup contextmenu" ).split( " " ), function( _i, name ) { @@ -10737,7 +10745,8 @@ jQuery.each( ( "blur focus focusin focusout resize scroll click dblclick " + this.on( name, null, data, fn ) : this.trigger( name ); }; - } ); + } +); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/script-dir/jquery-3.6.0.min.js b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/script-dir/jquery-3.6.0.min.js new file mode 100644 index 0000000000000000000000000000000000000000..c4c6022f2982e8dae64cebd6b9a2b59f2547faad --- /dev/null +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/script-dir/jquery-3.6.0.min.js @@ -0,0 +1,2 @@ +/*! jQuery v3.6.0 | (c) OpenJS Foundation and other contributors | jquery.org/license */ +!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],r=Object.getPrototypeOf,s=t.slice,g=t.flat?function(e){return t.flat.call(e)}:function(e){return t.concat.apply([],e)},u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},x=function(e){return null!=e&&e===e.window},E=C.document,c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.6.0",S=function(e,t){return new S.fn.init(e,t)};function p(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp(F),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+F),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(p.childNodes),p.childNodes),t[p.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!N[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&(U.test(t)||z.test(t))){(f=ee.test(t)&&ye(e.parentNode)||e)===e&&d.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=S)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+xe(l[o]);c=l.join(",")}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){N(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return g(t.replace($,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[S]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e&&e.namespaceURI,n=e&&(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:p;return r!=C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),p!=C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.scope=ce(function(e){return a.appendChild(e).appendChild(C.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length}),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=S,!C.getElementsByName||!C.getElementsByName(S).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+S+"-]").length||v.push("~="),(t=C.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||v.push("\\["+M+"*name"+M+"*="+M+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+S+"+*").length||v.push(".#.+[+~]"),e.querySelectorAll("\\\f"),v.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",F)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},j=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e==C||e.ownerDocument==p&&y(p,e)?-1:t==C||t.ownerDocument==p&&y(p,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==C?-1:t==C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]==p?-1:s[r]==p?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(T(e),d.matchesSelector&&E&&!N[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){N(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?S.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?S.grep(e,function(e){return e===n!==r}):"string"!=typeof n?S.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(S.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||D,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:q.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof S?t[0]:t,S.merge(this,S.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),N.test(r[1])&&S.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(S):S.makeArray(e,this)}).prototype=S.fn,D=S(E);var L=/^(?:parents|prev(?:Until|All))/,H={children:!0,contents:!0,next:!0,prev:!0};function O(e,t){while((e=e[t])&&1!==e.nodeType);return e}S.fn.extend({has:function(e){var t=S(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i;ce=E.createDocumentFragment().appendChild(E.createElement("div")),(fe=E.createElement("input")).setAttribute("type","radio"),fe.setAttribute("checked","checked"),fe.setAttribute("name","t"),ce.appendChild(fe),y.checkClone=ce.cloneNode(!0).cloneNode(!0).lastChild.checked,ce.innerHTML="",y.noCloneChecked=!!ce.cloneNode(!0).lastChild.defaultValue,ce.innerHTML="",y.option=!!ce.lastChild;var ge={thead:[1,"","
          "],col:[2,"","
          "],tr:[2,"","
          "],td:[3,"","
          "],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?S.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;n",""]);var me=/<|&#?\w+;/;function xe(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function je(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&S(e).children("tbody")[0]||e}function De(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function qe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Le(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0,r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var _t,zt=[],Ut=/(=)\?(?=&|$)|\?\?/;S.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=zt.pop()||S.expando+"_"+wt.guid++;return this[e]=!0,e}}),S.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Ut.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Ut.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Ut,"$1"+r):!1!==e.jsonp&&(e.url+=(Tt.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||S.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?S(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,zt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((_t=E.implementation.createHTMLDocument("").body).innerHTML="
          ",2===_t.childNodes.length),S.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=N.exec(e))?[t.createElement(i[1])]:(i=xe([e],t,o),o&&o.length&&S(o).remove(),S.merge([],i.childNodes)));var r,i,o},S.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(S.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},S.expr.pseudos.animated=function(t){return S.grep(S.timers,function(e){return t===e.elem}).length},S.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=S.css(e,"position"),c=S(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=S.css(e,"top"),u=S.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,S.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},S.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){S.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===S.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===S.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=S(e).offset()).top+=S.css(e,"borderTopWidth",!0),i.left+=S.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-S.css(r,"marginTop",!0),left:t.left-i.left-S.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===S.css(e,"position"))e=e.offsetParent;return e||re})}}),S.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;S.fn[t]=function(e){return $(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),S.each(["top","left"],function(e,n){S.cssHooks[n]=Fe(y.pixelPosition,function(e,t){if(t)return t=We(e,n),Pe.test(t)?S(e).position()[n]+"px":t})}),S.each({Height:"height",Width:"width"},function(a,s){S.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){S.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return $(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?S.css(e,t,i):S.style(e,t,n,i)},s,n?e:void 0,n)}})}),S.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){S.fn[t]=function(e){return this.on(t,e)}}),S.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),S.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){S.fn[n]=function(e,t){return 0 +doclet.usage.date.description=\ + Specifies the value to be used to timestamp the generated\n\ + pages, in ISO 8601 format + doclet.usage.doctitle.parameters=\ doclet.usage.doctitle.description=\ @@ -457,6 +470,14 @@ doclet.usage.linkoffline.parameters=\ doclet.usage.linkoffline.description=\ Link to docs at using package list at +# L10N: do not localize the option parameters: warn info +doclet.usage.link-modularity-mismatch.parameters=\ + (warn|info) +doclet.usage.link-modularity-mismatch.description=\ + Report external documentation with wrong modularity with either\n\ + a warning or informational message. The default behaviour is to\n\ + report a warning. + doclet.usage.link-platform-properties.parameters=\ doclet.usage.link-platform-properties.description=\ diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/BaseConfiguration.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/BaseConfiguration.java index e5f89ad2d3cd248b0435758d670209f00e755509..be6deabf6cda662e8ff0d8817838a804404e340e 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/BaseConfiguration.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/BaseConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -206,7 +206,7 @@ public abstract class BaseConfiguration { protected static final String sharedResourceBundleName = "jdk.javadoc.internal.doclets.toolkit.resources.doclets"; - VisibleMemberCache visibleMemberCache = null; + private VisibleMemberCache visibleMemberCache; public PropertyUtils propertyUtils = null; @@ -709,7 +709,7 @@ public abstract class BaseConfiguration { return getOptions().allowScriptInComments(); } - public synchronized VisibleMemberTable getVisibleMemberTable(TypeElement te) { + public VisibleMemberTable getVisibleMemberTable(TypeElement te) { return visibleMemberCache.getVisibleMemberTable(te); } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/BaseOptions.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/BaseOptions.java index 5fe0e514884306d47f5bf530a1a13dff0f25fe2c..30a6b4bb8c1425061a9a2103d3b8cdf59de0052e 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/BaseOptions.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/BaseOptions.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -30,12 +30,21 @@ import java.io.IOException; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.UnsupportedEncodingException; +import java.time.Instant; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; +import java.time.temporal.ChronoUnit; +import java.time.temporal.TemporalUnit; import java.util.ArrayList; import java.util.Arrays; +import java.util.Calendar; import java.util.Collections; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.List; +import java.util.Locale; import java.util.MissingResourceException; import java.util.Set; import java.util.StringTokenizer; @@ -81,6 +90,12 @@ public abstract class BaseOptions { */ private final LinkedHashSet> customTagStrs = new LinkedHashSet<>(); + /** + * Argument for command-line option {@code --date}. + * {@code null} if option not given. + */ + private ZonedDateTime date; + /** * Argument for command-line option {@code -d}. * Destination directory name, in which doclet will generate the entire @@ -165,6 +180,20 @@ public abstract class BaseOptions { // A list of pairs containing urls and package list private final List> linkOfflineList = new ArrayList<>(); + /** + * An enum of policies for handling modularity mismatches in external documentation. + */ + public enum ModularityMismatchPolicy { + INFO, + WARN + } + + /** + * Argument for command-line option {@code --link-modularity-mismatch}. + * Describes how to handle external documentation with non-matching modularity. + */ + private ModularityMismatchPolicy linkModularityMismatch = ModularityMismatchPolicy.WARN; + /** * Location of alternative platform link properties file. */ @@ -269,7 +298,7 @@ public abstract class BaseOptions { /** * Value for command-line option {@code --override-methods summary} - * or {@code --override-methods detail}. + * or {@code --override-methods detail}. * Specifies whether those methods that override a super-type's method * with no changes to the API contract should be summarized in the * footnote section. @@ -323,6 +352,33 @@ public abstract class BaseOptions { } }, + new XOption(resources, "--date", 1) { + // Valid --date range: within ten years of now + private static final ZonedDateTime now = ZonedDateTime.now(); + static final ZonedDateTime DATE_MIN = now.minusYears(10); + static final ZonedDateTime DATE_MAX = now.plusYears(10); + + @Override + public boolean process(String opt, List args) { + if (noTimestamp) { + messages.error("doclet.Option_conflict", "--date", "-notimestamp"); + return false; + } + String arg = args.get(0); + try { + date = ZonedDateTime.parse(arg, DateTimeFormatter.ISO_ZONED_DATE_TIME); + if (date.isBefore(DATE_MIN) || date.isAfter(DATE_MAX)) { + messages.error("doclet.Option_date_out_of_range", arg); + return false; + } + return true; + } catch (DateTimeParseException x) { + messages.error("doclet.Option_date_not_valid", arg); + return false; + } + } + }, + new Option(resources, "-docencoding", 1) { @Override public boolean process(String opt, List args) { @@ -403,6 +459,23 @@ public abstract class BaseOptions { } }, + new Option(resources, "--link-modularity-mismatch", 1) { + @Override + public boolean process(String opt, List args) { + String s = args.get(0); + switch (s) { + case "warn", "info" -> + linkModularityMismatch = ModularityMismatchPolicy.valueOf(s.toUpperCase(Locale.ROOT)); + default -> { + reporter.print(ERROR, resources.getText( + "doclet.Option_invalid", s, "--link-modularity-mismatch")); + return false; + } + } + return true; + } + }, + new Option(resources, "--link-platform-properties", 1) { @Override public boolean process(String opt, List args) { @@ -439,6 +512,10 @@ public abstract class BaseOptions { @Override public boolean process(String opt, List args) { noTimestamp = true; + if (date != null) { + messages.error("doclet.Option_conflict", "--date", "-notimestamp"); + return false; + } return true; } }, @@ -464,16 +541,13 @@ public abstract class BaseOptions { public boolean process(String opt, List args) { String o = args.get(0); switch (o) { - case "summary": - summarizeOverriddenMethods = true; - break; - case "detail": - summarizeOverriddenMethods = false; - break; - default: + case "summary" -> summarizeOverriddenMethods = true; + case "detail" -> summarizeOverriddenMethods = false; + default -> { reporter.print(ERROR, resources.getText("doclet.Option_invalid",o, "--override-methods")); return false; + } } return true; } @@ -710,6 +784,13 @@ public abstract class BaseOptions { return customTagStrs; } + /** + * Argument for command-line option {@code --date}. + */ + public ZonedDateTime date() { + return date; + } + /** * Argument for command-line option {@code -d}. * Destination directory name, in which doclet will generate the entire @@ -827,6 +908,14 @@ public abstract class BaseOptions { return linkOfflineList; } + /** + * Argument for command-line option {@code --link-modularity-mismatch}. + * Describes how to handle external documentation with non-matching modularity. + */ + public ModularityMismatchPolicy linkModularityMismatch() { + return linkModularityMismatch; + } + /** * Argument for command-line option {@code --link-platform-properties}. */ @@ -959,7 +1048,7 @@ public abstract class BaseOptions { /** * Value for command-line option {@code --override-methods summary} - * or {@code --override-methods detail}. + * or {@code --override-methods detail}. * Specifies whether those methods that override a super-type's method * with no changes to the API contract should be summarized in the * footnote section. diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/ConstructorWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/ConstructorWriter.java index dd12824670c962193eceec81dc52e282f097dbf8..380ac5ce530c8b36a798b367ebec61a77eb5cc65 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/ConstructorWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/ConstructorWriter.java @@ -74,7 +74,7 @@ public interface ConstructorWriter extends MemberWriter { * Add the preview output for the given member. * * @param member the member being documented - * @param annotationDocTree content tree to which the preview information will be added + * @param contentTree content tree to which the preview information will be added */ void addPreview(ExecutableElement member, Content contentTree); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/Content.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/Content.java index 84cc66912b4a712bcb9b0794fccd0a69383852da..80dd9c48587167ec891a2d32982a8f52f51e4141 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/Content.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/Content.java @@ -28,6 +28,8 @@ package jdk.javadoc.internal.doclets.toolkit; import java.io.IOException; import java.io.StringWriter; import java.io.Writer; +import java.util.Collection; +import java.util.function.Function; /** * A class to create content for javadoc output pages. @@ -89,6 +91,25 @@ public abstract class Content { throw new UnsupportedOperationException(); } + /** + * Adds content to the existing content, generated from a collection of items + * This is an optional operation. + * + * @implSpec This implementation delegates to {@link #add(Content)}. + * + * @param items the items to be added + * @param mapper the function to create content for each item + * + * @return this object + * @throws UnsupportedOperationException if this operation is not supported by + * a particular implementation + * @throws IllegalArgumentException if the content is not suitable to be added + */ + public Content addAll(Collection items, Function mapper) { + items.forEach(item -> add(mapper.apply(item))); + return this; + } + /** * Writes content to a writer. * diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/EnumConstantWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/EnumConstantWriter.java index 835be5e4d3a0ed474654674646960ebd7562bfe4..aa483714d1b4c79e1976a7c4a0d374455376843c 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/EnumConstantWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/EnumConstantWriter.java @@ -79,7 +79,7 @@ public interface EnumConstantWriter extends MemberWriter { * Add the preview output for the given member. * * @param member the member being documented - * @param annotationDocTree content tree to which the preview information will be added + * @param contentTree content tree to which the preview information will be added */ void addPreview(VariableElement member, Content contentTree); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/MethodWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/MethodWriter.java index b4efc8a777b510383eeb93b6a8de015742feb59b..d13ba652ae4b8fb3d41c95cac2a20c46ea4c8576 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/MethodWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/MethodWriter.java @@ -75,7 +75,7 @@ public interface MethodWriter extends MemberWriter { * Adds the preview output for the given member. * * @param member the member being documented - * @param annotationDocTree content tree to which the preview information will be added + * @param contentTree content tree to which the preview information will be added */ void addPreview(ExecutableElement member, Content contentTree); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/WorkArounds.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/WorkArounds.java index a7ae68aa89b531ceabb93fff2d35411fd7e89d6a..d3fae655dd2d851c0d440e48e7bda8ffd53aea5e 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/WorkArounds.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/WorkArounds.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -39,6 +39,7 @@ import javax.lang.model.element.ModuleElement; import javax.lang.model.element.PackageElement; import javax.lang.model.element.TypeElement; import javax.lang.model.element.VariableElement; +import javax.lang.model.type.DeclaredType; import javax.lang.model.type.TypeMirror; import javax.lang.model.util.Elements; import javax.lang.model.util.Types; @@ -46,7 +47,6 @@ import javax.tools.FileObject; import javax.tools.JavaFileManager.Location; import com.sun.source.util.TreePath; -import com.sun.tools.javac.code.Attribute; import com.sun.tools.javac.code.Flags; import com.sun.tools.javac.code.Scope; import com.sun.tools.javac.code.Symbol; @@ -55,6 +55,7 @@ import com.sun.tools.javac.code.Symbol.MethodSymbol; import com.sun.tools.javac.code.Symbol.ModuleSymbol; import com.sun.tools.javac.code.Symbol.PackageSymbol; import com.sun.tools.javac.code.Symbol.VarSymbol; +import com.sun.tools.javac.code.Type; import com.sun.tools.javac.code.TypeTag; import com.sun.tools.javac.comp.AttrContext; import com.sun.tools.javac.comp.Env; @@ -201,31 +202,38 @@ public class WorkArounds { // TODO: need to re-implement this using j.l.m. correctly!, this has // implications on testInterface, the note here is that javac's supertype // does the right thing returning Parameters in scope. - /** - * Return the type containing the method that this method overrides. - * It may be a TypeElement or a TypeParameterElement. - * @param method target - * @return a type + /* + * Returns the closest superclass (not the superinterface) that contains + * a method that is both: + * + * - overridden by the specified method, and + * - is not itself a *simple* override + * + * If no such class can be found, returns null. + * + * If the specified method belongs to an interface, the only considered + * superclass is java.lang.Object no matter how many other interfaces + * that interface extends. */ - public TypeMirror overriddenType(ExecutableElement method) { + public DeclaredType overriddenType(ExecutableElement method) { if (utils.isStatic(method)) { return null; } MethodSymbol sym = (MethodSymbol) method; ClassSymbol origin = (ClassSymbol) sym.owner; - for (com.sun.tools.javac.code.Type t = javacTypes.supertype(origin.type); - t.hasTag(TypeTag.CLASS); - t = javacTypes.supertype(t)) { + for (Type t = javacTypes.supertype(origin.type); + t.hasTag(TypeTag.CLASS); + t = javacTypes.supertype(t)) { ClassSymbol c = (ClassSymbol) t.tsym; - for (com.sun.tools.javac.code.Symbol sym2 : c.members().getSymbolsByName(sym.name)) { + for (Symbol sym2 : c.members().getSymbolsByName(sym.name)) { if (sym.overrides(sym2, origin, javacTypes, true)) { // Ignore those methods that may be a simple override // and allow the real API method to be found. - if (sym2.type.hasTag(TypeTag.METHOD) && - utils.isSimpleOverride((MethodSymbol)sym2)) { + if (utils.isSimpleOverride((MethodSymbol)sym2)) { continue; } - return t; + assert t.hasTag(TypeTag.CLASS) && !t.isInterface(); + return (Type.ClassType) t; } } } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/ClassBuilder.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/ClassBuilder.java index 5642ebaad75efc24acf0ef1b58cb772ece594571..0d3e881adac330932ea3ab507ae8ce65801322f6 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/ClassBuilder.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/ClassBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -108,12 +108,12 @@ public class ClassBuilder extends AbstractBuilder { buildClassDoc(); } - /** - * Handles the {@literal } tag. - * - * @throws DocletException if there is a problem while building the documentation - */ - protected void buildClassDoc() throws DocletException { + /** + * Handles the {@literal } tag. + * + * @throws DocletException if there is a problem while building the documentation + */ + protected void buildClassDoc() throws DocletException { String key = switch (typeElement.getKind()) { case INTERFACE -> "doclet.Interface"; case ENUM -> "doclet.Enum"; @@ -122,7 +122,7 @@ public class ClassBuilder extends AbstractBuilder { case CLASS -> "doclet.Class"; default -> throw new IllegalStateException(typeElement.getKind() + " " + typeElement); }; - Content contentTree = writer.getHeader(resources.getText(key) + " " + Content contentTree = writer.getHeader(resources.getText(key) + " " + utils.getSimpleName(typeElement)); Content classContentTree = writer.getClassContentHeader(); @@ -137,11 +137,11 @@ public class ClassBuilder extends AbstractBuilder { copyDocFiles(); } - /** - * Build the class tree documentation. - * - * @param classContentTree the content tree to which the documentation will be added - */ + /** + * Build the class tree documentation. + * + * @param classContentTree the content tree to which the documentation will be added + */ protected void buildClassTree(Content classContentTree) { writer.addClassTree(classContentTree); } @@ -256,7 +256,7 @@ public class ClassBuilder extends AbstractBuilder { * * @throws DocFileIOException if there is a problem while copying the files */ - private void copyDocFiles() throws DocletException { + private void copyDocFiles() throws DocletException { PackageElement containingPackage = utils.containingPackage(typeElement); if ((configuration.packages == null || !configuration.packages.contains(containingPackage)) && @@ -270,7 +270,7 @@ public class ClassBuilder extends AbstractBuilder { docFilesHandler.copyDocFiles(); containingPackagesSeen.add(containingPackage); } - } + } /** * Build the signature of the current class. @@ -287,7 +287,7 @@ public class ClassBuilder extends AbstractBuilder { * @param classInfoTree the content tree to which the documentation will be added */ protected void buildClassDescription(Content classInfoTree) { - writer.addClassDescription(classInfoTree); + writer.addClassDescription(classInfoTree); } /** @@ -296,7 +296,7 @@ public class ClassBuilder extends AbstractBuilder { * @param classInfoTree the content tree to which the documentation will be added */ protected void buildClassTagInfo(Content classInfoTree) { - writer.addClassTagInfo(classInfoTree); + writer.addClassTagInfo(classInfoTree); } /** diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets.properties b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets.properties index edc3b53ea46da68e2f9c33a4982e117f3a57a49b..c67865344eebf4c6dc60d1c06b4ffb657eab46a0 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets.properties +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets.properties @@ -45,7 +45,7 @@ doclet.exception.write.file=Error writing file: {0}\n\ \t({1}) doclet.exception.read.resource=Error reading system resource: {0}\n\ \t({1}) -doclet.internal.exception=An internal exception has occurred. \n\ +doclet.internal.exception=An internal exception has occurred.\n\ \t({0}) doclet.internal.report.bug=\ Please file a bug against the javadoc tool via the Java bug reporting page\n\ @@ -361,6 +361,9 @@ doclet.snippet.region.not_found=\ doclet.tag.attribute.value.illegal=\ illegal value for attribute "{0}": "{1}" +doclet.tag.attribute.value.missing=\ + missing value for attribute "{0}" + doclet.tag.attribute.repeated=\ repeated attribute: "{0}" @@ -370,6 +373,8 @@ doclet.snippet.contents.mismatch=\ doclet.snippet.markup=\ snippet markup: {0} +doclet.snippet.markup.spurious=\ + spurious markup doclet.snippet.markup.attribute.absent=\ missing attribute "{0}" doclet.snippet.markup.attribute.simultaneous.use=\ diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/stylesheet.css b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/stylesheet.css index d61caef2a0ebff9cd018180b9a968ad95efc9c19..69252eab283f2f5efd01df10943e84306e438613 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/stylesheet.css +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/stylesheet.css @@ -555,6 +555,18 @@ div.block { div.block div.deprecation-comment { font-style:normal; } +details.invalid-tag, span.invalid-tag { + font-size:14px; + font-family:'DejaVu Serif', Georgia, "Times New Roman", Times, serif; + background: #ffe6e6; + border: thin solid #000000; + border-radius:2px; + padding: 2px 4px; + display:inline-block; +} +details.invalid-tag summary { + cursor: pointer; +} /* * Styles specific to HTML5 elements. */ @@ -991,11 +1003,9 @@ button.snippet-copy:active { pre.snippet .italic { font-style: italic; } - pre.snippet .bold { font-weight: bold; } - pre.snippet .highlighted { background-color: #f7c590; border-radius: 10%; diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/ParamTaglet.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/ParamTaglet.java index b41260743ee5be3ee222050fa5b6d1207eb4dd1f..2af114d322b2cd0f3b420702cac57f40a868e628 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/ParamTaglet.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/ParamTaglet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -152,7 +152,7 @@ public class ParamTaglet extends BaseTaglet implements InheritableTaglet { } /** - * Given an array of {@code @param DocTree}s,return its string representation. + * Given an array of {@code @param DocTree}s, return its string representation. * Try to inherit the param tags that are missing. * * @param holder the element that holds the param tags. @@ -165,54 +165,29 @@ public class ParamTaglet extends BaseTaglet implements InheritableTaglet { private Content getTagletOutput(ParamKind kind, Element holder, TagletWriter writer, List formalParameters, List paramTags) { Content result = writer.getOutputInstance(); - Set alreadyDocumented = new HashSet<>(); - if (!paramTags.isEmpty()) { - result.add( - processParamTags(holder, kind, paramTags, - getRankMap(writer.configuration().utils, formalParameters), writer, alreadyDocumented) - ); - } - if (alreadyDocumented.size() != formalParameters.size()) { - //Some parameters are missing corresponding @param tags. - //Try to inherit them. - result.add(getInheritedTagletOutput(kind, holder, - writer, formalParameters, alreadyDocumented)); - } + result.add(processParamTags(holder, kind, paramTags, formalParameters, writer)); return result; } /** - * Loop through each individual parameter, despite not having a - * corresponding param tag, try to inherit it. + * Try to get the inherited taglet documentation for a specific parameter. */ private Content getInheritedTagletOutput(ParamKind kind, Element holder, - TagletWriter writer, List formalParameters, - Set alreadyDocumented) { + TagletWriter writer, Element param, int rank, + boolean isFirst) { Utils utils = writer.configuration().utils; Content result = writer.getOutputInstance(); - if ((!alreadyDocumented.contains(null)) && utils.isExecutableElement(holder)) { - for (int i = 0; i < formalParameters.size(); i++) { - if (alreadyDocumented.contains(String.valueOf(i))) { - continue; - } - // This parameter does not have any @param documentation. - // Try to inherit it. - Input input = new DocFinder.Input(writer.configuration().utils, holder, this, - Integer.toString(i), kind == ParamKind.TYPE_PARAMETER); - DocFinder.Output inheritedDoc = DocFinder.search(writer.configuration(), input); - if (inheritedDoc.inlineTags != null && !inheritedDoc.inlineTags.isEmpty()) { - Element e = formalParameters.get(i); - String lname = kind != ParamKind.TYPE_PARAMETER - ? utils.getSimpleName(e) - : utils.getTypeName(e.asType(), false); - Content content = processParamTag(inheritedDoc.holder, kind, writer, - (ParamTree) inheritedDoc.holderTag, - lname, - alreadyDocumented.isEmpty()); - result.add(content); - } - alreadyDocumented.add(String.valueOf(i)); - } + Input input = new DocFinder.Input(writer.configuration().utils, holder, this, + Integer.toString(rank), kind == ParamKind.TYPE_PARAMETER); + DocFinder.Output inheritedDoc = DocFinder.search(writer.configuration(), input); + if (inheritedDoc.inlineTags != null && !inheritedDoc.inlineTags.isEmpty()) { + String lname = kind != ParamKind.TYPE_PARAMETER + ? utils.getSimpleName(param) + : utils.getTypeName(param.asType(), false); + Content content = processParamTag(inheritedDoc.holder, kind, writer, + (ParamTree) inheritedDoc.holderTag, + lname, isFirst); + result.add(content); } return result; } @@ -225,23 +200,15 @@ public class ParamTaglet extends BaseTaglet implements InheritableTaglet { * * @param paramTags the array of {@code @param DocTree} to convert. * @param writer the TagletWriter that will write this tag. - * @param alreadyDocumented the set of exceptions that have already - * been documented. - * @param rankMap a {@link java.util.Map} which holds ordering - * information about the parameters. - * @param rankMap a {@link java.util.Map} which holds a mapping - of a rank of a parameter to its name. This is - used to ensure that the right name is used - when parameter documentation is inherited. * @return the Content representation of this {@code @param DocTree}. */ - private Content processParamTags(Element e, ParamKind kind, - List paramTags, Map rankMap, TagletWriter writer, - Set alreadyDocumented) { + private Content processParamTags(Element e, ParamKind kind, List paramTags, + List formalParameters, TagletWriter writer) { + Map documented = new HashMap<>(); Messages messages = writer.configuration().getMessages(); - Content result = writer.getOutputInstance(); + CommentHelper ch = writer.configuration().utils.getCommentHelper(e); if (!paramTags.isEmpty()) { - CommentHelper ch = writer.configuration().utils.getCommentHelper(e); + Map rankMap = getRankMap(writer.configuration().utils, formalParameters); for (ParamTree dt : paramTags) { String name = ch.getParameterName(dt); String paramName = kind == ParamKind.TYPE_PARAMETER ? "<" + name + ">" : name; @@ -250,23 +217,45 @@ public class ParamTaglet extends BaseTaglet implements InheritableTaglet { case PARAMETER -> "doclet.Parameters_warn"; case TYPE_PARAMETER -> "doclet.TypeParameters_warn"; case RECORD_COMPONENT -> "doclet.RecordComponents_warn"; - default -> throw new IllegalArgumentException(kind.toString()); }; messages.warning(ch.getDocTreePath(dt), key, paramName); } String rank = rankMap.get(name); - if (rank != null && alreadyDocumented.contains(rank)) { - String key = switch (kind) { - case PARAMETER -> "doclet.Parameters_dup_warn"; - case TYPE_PARAMETER -> "doclet.TypeParameters_dup_warn"; - case RECORD_COMPONENT -> "doclet.RecordComponents_dup_warn"; - default -> throw new IllegalArgumentException(kind.toString()); - }; - messages.warning(ch.getDocTreePath(dt), key, paramName); + if (rank != null) { + if (documented.containsKey(rank)) { + String key = switch (kind) { + case PARAMETER -> "doclet.Parameters_dup_warn"; + case TYPE_PARAMETER -> "doclet.TypeParameters_dup_warn"; + case RECORD_COMPONENT -> "doclet.RecordComponents_dup_warn"; + }; + messages.warning(ch.getDocTreePath(dt), key, paramName); + } else { + documented.put(rank, dt); + } } + } + } + // Document declared parameters for which taglet documentation is available + // (either directly or inherited) in order of their declaration. + Content result = writer.getOutputInstance(); + for (int i = 0; i < formalParameters.size(); i++) { + ParamTree dt = documented.get(String.valueOf(i)); + if (dt != null) { result.add(processParamTag(e, kind, writer, dt, - name, alreadyDocumented.isEmpty())); - alreadyDocumented.add(rank); + ch.getParameterName(dt), result.isEmpty())); + } else if (writer.configuration().utils.isExecutableElement(e)) { + result.add(getInheritedTagletOutput(kind, e, writer, + formalParameters.get(i), i, result.isEmpty())); + } + } + if (paramTags.size() > documented.size()) { + // Generate documentation for remaining taglets that do not match a declared parameter. + // These are erroneous but we generate them anyway. + for (ParamTree dt : paramTags) { + if (!documented.containsValue(dt)) { + result.add(processParamTag(e, kind, writer, dt, + ch.getParameterName(dt), result.isEmpty())); + } } } return result; diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/SnippetTaglet.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/SnippetTaglet.java index 9219a78814acebc6631a9e32a20794872f6baed2..3c13b194c226543e801e7110169379fa12aa9ee6 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/SnippetTaglet.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/SnippetTaglet.java @@ -28,9 +28,9 @@ package jdk.javadoc.internal.doclets.toolkit.taglets; import java.io.IOException; import java.util.EnumSet; import java.util.HashMap; -import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Optional; import java.util.stream.Collectors; import javax.lang.model.element.Element; @@ -64,6 +64,38 @@ import jdk.javadoc.internal.doclets.toolkit.util.Utils; */ public class SnippetTaglet extends BaseTaglet { + public enum Language { + + JAVA("java"), + PROPERTIES("properties"); + + private static final Map languages; + + static { + Map tmp = new HashMap<>(); + for (var language : values()) { + String id = Objects.requireNonNull(language.identifier); + if (tmp.put(id, language) != null) + throw new IllegalStateException(); // 1-1 correspondence + } + languages = Map.copyOf(tmp); + } + + Language(String id) { + identifier = id; + } + + private final String identifier; + + public static Optional of(String identifier) { + if (identifier == null) + return Optional.empty(); + return Optional.ofNullable(languages.get(identifier)); + } + + public String getIdentifier() {return identifier;} + } + public SnippetTaglet() { super(DocTree.Kind.SNIPPET, true, EnumSet.allOf(Taglet.Location.class)); } @@ -84,6 +116,46 @@ public class SnippetTaglet extends BaseTaglet { */ @Override public Content getInlineTagOutput(Element holder, DocTree tag, TagletWriter writer) { + try { + return generateContent(holder, tag, writer); + } catch (BadSnippetException e) { + error(writer, holder, e.tag(), e.key(), e.args()); + String details = writer.configuration().getDocResources().getText(e.key(), e.args()); + return badSnippet(writer, Optional.of(details)); + } + } + + private static final class BadSnippetException extends Exception { + + @java.io.Serial + private static final long serialVersionUID = 1; + + private final transient DocTree tag; + private final String key; + private final transient Object[] args; + + BadSnippetException(DocTree tag, String key, Object... args) { + this.tag = tag; + this.key = key; + this.args = args; + } + + DocTree tag() { + return tag; + } + + String key() { + return key; + } + + Object[] args() { + return args; + } + } + + private Content generateContent(Element holder, DocTree tag, TagletWriter writer) + throws BadSnippetException + { SnippetTree snippetTag = (SnippetTree) tag; // organize snippet attributes in a map, performing basic checks along the way @@ -98,9 +170,8 @@ public class SnippetTaglet extends BaseTaglet { // two like-named attributes found; although we report on the most // recently encountered of the two, the iteration order might differ // from the source order (see JDK-8266826) - error(writer, holder, a, "doclet.tag.attribute.repeated", - a.getName().toString()); - return badSnippet(writer); + throw new BadSnippetException(a, "doclet.tag.attribute.repeated", + a.getName().toString()); } final String CLASS = "class"; @@ -111,22 +182,19 @@ public class SnippetTaglet extends BaseTaglet { final boolean containsBody = snippetTag.getBody() != null; if (containsClass && containsFile) { - error(writer, holder, attributes.get(CLASS), - "doclet.snippet.contents.ambiguity.external"); - return badSnippet(writer); + throw new BadSnippetException(attributes.get(CLASS), + "doclet.snippet.contents.ambiguity.external"); } else if (!containsClass && !containsFile && !containsBody) { - error(writer, holder, tag, "doclet.snippet.contents.none"); - return badSnippet(writer); + throw new BadSnippetException(tag, "doclet.snippet.contents.none"); } String regionName = null; AttributeTree region = attributes.get("region"); if (region != null) { - regionName = stringOf(region.getValue()); + regionName = stringValueOf(region); if (regionName.isBlank()) { - error(writer, holder, region, "doclet.tag.attribute.value.illegal", - "region", region.getValue()); - return badSnippet(writer); + throw new BadSnippetException(region, "doclet.tag.attribute.value.illegal", + "region", region.getValue()); } } @@ -141,12 +209,12 @@ public class SnippetTaglet extends BaseTaglet { if (containsFile || containsClass) { AttributeTree a; String v = containsFile - ? stringOf((a = attributes.get(FILE)).getValue()) - : stringOf((a = attributes.get(CLASS)).getValue()).replace(".", "/") + ".java"; + ? stringValueOf((a = attributes.get(FILE))) + : stringValueOf((a = attributes.get(CLASS))).replace(".", "/") + ".java"; if (v.isBlank()) { - error(writer, holder, a, "doclet.tag.attribute.value.illegal", - containsFile ? FILE : CLASS, v); + throw new BadSnippetException(a, "doclet.tag.attribute.value.illegal", + containsFile ? FILE : CLASS, v); } // we didn't create JavaFileManager, so we won't close it; even if an error occurs @@ -165,56 +233,74 @@ public class SnippetTaglet extends BaseTaglet { if (fileObject == null && fileManager.hasLocation(Location.SNIPPET_PATH)) { fileObject = fileManager.getFileForInput(Location.SNIPPET_PATH, "", v); } - } catch (IOException | IllegalArgumentException e) { + } catch (IOException | IllegalArgumentException e) { // TODO: test this when JDK-8276892 is integrated // JavaFileManager.getFileForInput can throw IllegalArgumentException in certain cases - error(writer, holder, a, "doclet.exception.read.file", v, e.getCause()); - return badSnippet(writer); + throw new BadSnippetException(a, "doclet.exception.read.file", v, e.getCause()); } if (fileObject == null) { // i.e. the file does not exist - error(writer, holder, a, "doclet.File_not_found", v); - return badSnippet(writer); + throw new BadSnippetException(a, "doclet.File_not_found", v); } try { externalContent = fileObject.getCharContent(true).toString(); - } catch (IOException e) { - error(writer, holder, a, "doclet.exception.read.file", - fileObject.getName(), e.getCause()); - return badSnippet(writer); + } catch (IOException e) { // TODO: test this when JDK-8276892 is integrated + throw new BadSnippetException(a, "doclet.exception.read.file", + fileObject.getName(), e.getCause()); } } + String lang = null; + AttributeTree langAttr = attributes.get("lang"); + if (langAttr != null) { + lang = stringValueOf(langAttr); + } else if (containsClass) { + lang = "java"; + } else if (containsFile) { + lang = languageFromFileName(fileObject.getName()); + } + + Optional language = Language.of(lang); + + // TODO cache parsed external snippet (WeakHashMap) StyledText inlineSnippet = null; StyledText externalSnippet = null; try { + Diags d = (text, pos) -> { + var path = writer.configuration().utils.getCommentHelper(holder) + .getDocTreePath(snippetTag.getBody()); + writer.configuration().getReporter().print(Diagnostic.Kind.WARNING, + path, pos, pos, pos, text); + }; if (inlineContent != null) { - inlineSnippet = parse(writer.configuration().getDocResources(), inlineContent); + inlineSnippet = parse(writer.configuration().getDocResources(), d, language, inlineContent); } } catch (ParseException e) { var path = writer.configuration().utils.getCommentHelper(holder) - .getDocTreePath(snippetTag.getBody()); + .getDocTreePath(snippetTag.getBody()); // TODO: there should be a method in Messages; that method should mirror Reporter's; use that method instead accessing Reporter. String msg = writer.configuration().getDocResources() - .getText("doclet.snippet.markup", e.getMessage()); + .getText("doclet.snippet.markup", e.getMessage()); writer.configuration().getReporter().print(Diagnostic.Kind.ERROR, - path, e.getPosition(), e.getPosition(), e.getPosition(), msg); - return badSnippet(writer); + path, e.getPosition(), e.getPosition(), e.getPosition(), msg); + return badSnippet(writer, Optional.of(e.getMessage())); } try { + var finalFileObject = fileObject; + Diags d = (text, pos) -> writer.configuration().getMessages().warning(finalFileObject, pos, pos, pos, text); if (externalContent != null) { - externalSnippet = parse(writer.configuration().getDocResources(), externalContent); + externalSnippet = parse(writer.configuration().getDocResources(), d, language, externalContent); } } catch (ParseException e) { assert fileObject != null; writer.configuration().getMessages().error(fileObject, e.getPosition(), - e.getPosition(), e.getPosition(), "doclet.snippet.markup", e.getMessage()); - return badSnippet(writer); + e.getPosition(), e.getPosition(), "doclet.snippet.markup", e.getMessage()); + return badSnippet(writer, Optional.of(e.getMessage())); } // the region must be matched at least in one content: it can be matched @@ -235,8 +321,7 @@ public class SnippetTaglet extends BaseTaglet { } } if (r1 == null && r2 == null) { - error(writer, holder, tag, "doclet.snippet.region.not_found", regionName); - return badSnippet(writer); + throw new BadSnippetException(tag, "doclet.snippet.region.not_found", regionName); } } @@ -252,28 +337,17 @@ public class SnippetTaglet extends BaseTaglet { String inlineStr = inlineSnippet.asCharSequence().toString(); String externalStr = externalSnippet.asCharSequence().toString(); if (!Objects.equals(inlineStr, externalStr)) { - error(writer, holder, tag, "doclet.snippet.contents.mismatch", diff(inlineStr, externalStr)); - // output one above the other - return badSnippet(writer); + throw new BadSnippetException(tag, "doclet.snippet.contents.mismatch", diff(inlineStr, externalStr)); } } assert inlineSnippet != null || externalSnippet != null; StyledText text = inlineSnippet != null ? inlineSnippet : externalSnippet; - String lang = null; - AttributeTree langAttr = attributes.get("lang"); - if (langAttr != null && langAttr.getValueKind() != AttributeTree.ValueKind.EMPTY) { - lang = stringOf(langAttr.getValue()); - } else if (containsClass) { - lang = "java"; - } else if (containsFile) { - lang = languageFromFileName(fileObject.getName()); - } AttributeTree idAttr = attributes.get("id"); - String id = idAttr == null || idAttr.getValueKind() == AttributeTree.ValueKind.EMPTY - ? null - : stringOf(idAttr.getValue()); + String id = idAttr == null + ? null + : stringValueOf(idAttr); return writer.snippetTagOutput(holder, snippetTag, text, id, lang); } @@ -298,14 +372,22 @@ public class SnippetTaglet extends BaseTaglet { """.formatted(inline, external); } - private StyledText parse(Resources resources, String content) throws ParseException { - Parser.Result result = new Parser(resources).parse(content); + private StyledText parse(Resources resources, Diags diags, Optional language, String content) throws ParseException { + Parser.Result result = new Parser(resources).parse(diags, language, content); result.actions().forEach(Action::perform); return result.text(); } - private static String stringOf(List value) { - return value.stream() + public interface Diags { + void warn(String text, int pos); + } + + private static String stringValueOf(AttributeTree at) throws BadSnippetException { + if (at.getValueKind() == AttributeTree.ValueKind.EMPTY) { + throw new BadSnippetException(at, "doclet.tag.attribute.value.missing", + at.getName().toString()); + } + return at.getValue().stream() // value consists of TextTree or ErroneousTree nodes; // ErroneousTree is a subtype of TextTree .map(t -> ((TextTree) t).getBody()) @@ -327,8 +409,9 @@ public class SnippetTaglet extends BaseTaglet { writer.configuration().utils.getCommentHelper(holder).getDocTreePath(tag), key, args); } - private Content badSnippet(TagletWriter writer) { - return writer.getOutputInstance().add("bad snippet"); + private Content badSnippet(TagletWriter writer, Optional details) { + Resources resources = writer.configuration().getDocResources(); + return writer.invalidTagOutput(resources.getText("doclet.tag.invalid", "snippet"), details); } private String packageName(PackageElement pkg, Utils utils) { diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/TagletManager.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/TagletManager.java index 19928eee306456eb1bd32a323a46d5fdf5a2cafd..134d54276340ffed28277e853d3f67f063ea63b8 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/TagletManager.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/TagletManager.java @@ -250,23 +250,22 @@ public class TagletManager { * @param fileManager the file manager to load classes and resources */ public void addCustomTag(String classname, JavaFileManager fileManager) { + ClassLoader tagClassLoader = fileManager.getClassLoader(TAGLET_PATH); + if (configuration.workArounds.accessInternalAPI()) { + Module thisModule = getClass().getModule(); + Module tagletLoaderUnnamedModule = tagClassLoader.getUnnamedModule(); + List pkgs = List.of( + "jdk.javadoc.doclet", + "jdk.javadoc.internal.doclets.toolkit", + "jdk.javadoc.internal.doclets.formats.html"); + pkgs.forEach(p -> thisModule.addOpens(p, tagletLoaderUnnamedModule)); + } try { - ClassLoader tagClassLoader; - tagClassLoader = fileManager.getClassLoader(TAGLET_PATH); - if (configuration.workArounds.accessInternalAPI()) { - Module thisModule = getClass().getModule(); - Module tagletLoaderUnnamedModule = tagClassLoader.getUnnamedModule(); - List pkgs = List.of( - "jdk.javadoc.doclet", - "jdk.javadoc.internal.doclets.toolkit", - "jdk.javadoc.internal.doclets.formats.html"); - pkgs.forEach(p -> thisModule.addOpens(p, tagletLoaderUnnamedModule)); - } Class customTagClass = tagClassLoader.loadClass(classname).asSubclass(jdk.javadoc.doclet.Taglet.class); jdk.javadoc.doclet.Taglet instance = customTagClass.getConstructor().newInstance(); registerTaglet(instance); - } catch (ReflectiveOperationException exc) { + } catch (ReflectiveOperationException | ExceptionInInitializerError | ClassCastException exc) { messages.error("doclet.Error_taglet_not_registered", exc.getClass().getName(), classname); } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/TagletWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/TagletWriter.java index a12c7b42ffd8045f17b6367db48c2df253708433..b9142d6721a3a2f7936c6a8b4db43bd7193f6f97 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/TagletWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/TagletWriter.java @@ -27,6 +27,7 @@ package jdk.javadoc.internal.doclets.toolkit.taglets; import java.util.List; import java.util.Map; +import java.util.Optional; import javax.lang.model.element.Element; import javax.lang.model.element.ElementKind; import javax.lang.model.element.TypeElement; @@ -239,6 +240,17 @@ public abstract class TagletWriter { protected abstract Content valueTagOutput(VariableElement field, String constantVal, boolean includeLink); + /** + * Returns the output for an invalid tag. The returned content uses special styling to + * highlight the problem. Depending on the presence of the {@code detail} string the method + * returns a plain text span or an expandable component. + * + * @param summary the single-line summary message + * @param detail the optional detail message which may contain preformatted text + * @return the output + */ + protected abstract Content invalidTagOutput(String summary, Optional detail); + /** * Returns the main type element of the current page or null for pages that don't have one. * diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/ThrowsTaglet.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/ThrowsTaglet.java index 88a947ffdc719e0ca6497b36dcda2a97f19a41f0..9e3213e68a778efbd5db75c2ca1ddaa7cc991131 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/ThrowsTaglet.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/ThrowsTaglet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -42,6 +42,7 @@ import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.TypeElement; import javax.lang.model.type.ExecutableType; import javax.lang.model.type.TypeMirror; +import javax.lang.model.util.Types; import com.sun.source.doctree.DocTree; import com.sun.source.doctree.ThrowsTree; @@ -166,7 +167,9 @@ public class ThrowsTaglet extends BaseTaglet writer.getCurrentPageElement(), (ExecutableElement)holder); List thrownTypes = instantiatedType.getThrownTypes(); Map typeSubstitutions = getSubstitutedThrownTypes( - ((ExecutableElement) holder).getThrownTypes(), thrownTypes); + writer.configuration().utils.typeUtils, + ((ExecutableElement) holder).getThrownTypes(), + thrownTypes); Map, ExecutableElement> tagsMap = new LinkedHashMap<>(); tagsMap.put(utils.getThrowsTrees(execHolder), execHolder); Content result = writer.getOutputInstance(); @@ -233,7 +236,8 @@ public class ThrowsTaglet extends BaseTaglet * @param instantiatedThrownTypes the thrown types in the context of the current type. * @return map of declared to instantiated thrown types or an empty map. */ - private Map getSubstitutedThrownTypes(List declaredThrownTypes, + private Map getSubstitutedThrownTypes(Types types, + List declaredThrownTypes, List instantiatedThrownTypes) { if (!instantiatedThrownTypes.equals(declaredThrownTypes)) { Map map = new HashMap<>(); @@ -242,7 +246,7 @@ public class ThrowsTaglet extends BaseTaglet while (i1.hasNext() && i2.hasNext()) { TypeMirror t1 = i1.next(); TypeMirror t2 = i2.next(); - if (!t1.equals(t2)) + if (!types.isSameType(t1, t2)) map.put(t2.toString(), t1); } return map; diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/snippet/Attribute.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/snippet/Attribute.java index af2587373ea590b6c718a0559487e35e7fe89d36..3289da827643ab95ab45ef08c6ce269c6ffc2ce7 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/snippet/Attribute.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/snippet/Attribute.java @@ -58,8 +58,7 @@ import java.util.Objects; * This code and its internal interfaces are subject to change or * deletion without notice. */ -// TODO: uncomment /* sealed */ when minimum boot JDK version >= 17 -public /* sealed */ abstract class Attribute { +public abstract class Attribute { private final String name; diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/snippet/Attributes.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/snippet/Attributes.java index 616063d85030af9dbda0a7fe894aaf55596cf505..2548ccf0256fe648afe53a566e42d13ab8dcb993 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/snippet/Attributes.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/snippet/Attributes.java @@ -67,12 +67,4 @@ public final class Attributes { .map(type::cast) .findAny(); } - - public int size() { - return attributes.values().stream().mapToInt(List::size).sum(); - } - - public boolean isEmpty() { - return attributes.isEmpty(); - } } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/snippet/MarkupParser.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/snippet/MarkupParser.java index 879ba7bf2e40e5843ef09dd297b4ce1bb3c46991..59d6b3f9fdb3381e5dab55d3c5255b80d06c50cd 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/snippet/MarkupParser.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/snippet/MarkupParser.java @@ -31,11 +31,8 @@ import java.util.List; import jdk.javadoc.internal.doclets.toolkit.Resources; // -// markup-comment = { markup-tag } ; -// markup-tag = "@" , tag-name , {attribute} [":"] ; -// -// If optional trailing ":" is present, the tag refers to the next line -// rather than to this line. +// markup-comment = { markup-tag } [":"] ; +// markup-tag = "@" , tag-name , {attribute} ; // /** @@ -76,15 +73,28 @@ public final class MarkupParser { } protected List parse() throws ParseException { + List tags = readTags(); + if (ch == ':') { + tags.forEach(t -> t.appliesToNextLine = true); + nextChar(); + } + skipWhitespace(); + if (ch != EOI) { + return List.of(); + } + return tags; + } + + protected List readTags() throws ParseException { List tags = new ArrayList<>(); - // TODO: what to do with leading and trailing unrecognized markup? + skipWhitespace(); while (bp < buflen) { - switch (ch) { - case '@' -> tags.add(readTag()); - default -> nextChar(); + if (ch == '@') { + tags.add(readTag()); + } else { + break; } } - return tags; } @@ -94,26 +104,13 @@ public final class MarkupParser { String name = readIdentifier(); skipWhitespace(); - boolean appliesToNextLine = false; - List attributes = List.of(); - - if (ch == ':') { - appliesToNextLine = true; - nextChar(); - } else { - attributes = attrs(); - skipWhitespace(); - if (ch == ':') { - appliesToNextLine = true; - nextChar(); - } - } + List attributes = attrs(); + skipWhitespace(); Parser.Tag i = new Parser.Tag(); i.nameLineOffset = nameBp; i.name = name; i.attributes = attributes; - i.appliesToNextLine = appliesToNextLine; return i; } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/snippet/Parser.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/snippet/Parser.java index 2dd7d5b4b6ed9e4417384c369db4af0d05152eae..3ed4ac03166d23b38922de2eb173e1cb18d3f7ce 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/snippet/Parser.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/snippet/Parser.java @@ -39,6 +39,7 @@ import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; import jdk.javadoc.internal.doclets.toolkit.Resources; +import jdk.javadoc.internal.doclets.toolkit.taglets.SnippetTaglet; /* * Semantics of a EOL comment; plus @@ -76,10 +77,10 @@ import jdk.javadoc.internal.doclets.toolkit.Resources; */ public final class Parser { - // next-line tag behaves as if it were specified on the next line - - private String eolMarker; - private Matcher markedUpLine; + private static final Pattern JAVA_COMMENT = Pattern.compile( + "^(?.*)//(?\\s*@\\s*\\w+.+?)$"); + private static final Pattern PROPERTIES_COMMENT = Pattern.compile( + "^(?[ \t]*([#!].*)?)[#!](?\\s*@\\s*\\w+.+?)$"); private final Resources resources; private final MarkupParser markupParser; @@ -93,32 +94,23 @@ public final class Parser { this.markupParser = new MarkupParser(resources); } - public Result parse(String source) throws ParseException { - return parse("//", source); + public Result parse(SnippetTaglet.Diags diags, Optional language, String source) throws ParseException { + SnippetTaglet.Language lang = language.orElse(SnippetTaglet.Language.JAVA); + var p = switch (lang) { + case JAVA -> JAVA_COMMENT; + case PROPERTIES -> PROPERTIES_COMMENT; + }; + return parse(diags, p, source); } /* * Newline characters in the returned text are of the \n form. */ - public Result parse(String eolMarker, String source) throws ParseException { - Objects.requireNonNull(eolMarker); + private Result parse(SnippetTaglet.Diags diags, Pattern commentPattern, String source) throws ParseException { + Objects.requireNonNull(commentPattern); Objects.requireNonNull(source); - if (!Objects.equals(eolMarker, this.eolMarker)) { - if (eolMarker.length() < 1) { - throw new IllegalArgumentException(); - } - for (int i = 0; i < eolMarker.length(); i++) { - switch (eolMarker.charAt(i)) { - case '\f', '\n', '\r' -> throw new IllegalArgumentException(); - } - } - this.eolMarker = eolMarker; - // capture the rightmost eolMarker (e.g. "//") - // The below Pattern.compile should never throw PatternSyntaxException - Pattern pattern = Pattern.compile("^(.*)(" + Pattern.quote(eolMarker) - + "(\\s*@\\s*\\w+.+?))$"); - this.markedUpLine = pattern.matcher(""); // reusable matcher - } + + Matcher markedUpLine = commentPattern.matcher(""); // reusable matcher tags.clear(); regions.clear(); @@ -147,21 +139,22 @@ public final class Parser { String rawLine = next.line(); boolean addLineTerminator = iterator.hasNext() || trailingNewline; String line; + boolean hasMarkup = false; markedUpLine.reset(rawLine); if (!markedUpLine.matches()) { // (1) line = rawLine + (addLineTerminator ? "\n" : ""); } else { - String maybeMarkup = markedUpLine.group(3); - List parsedTags = null; + String maybeMarkup = rawLine.substring(markedUpLine.start("markup")); + List parsedTags; try { parsedTags = markupParser.parse(maybeMarkup); } catch (ParseException e) { - // adjust index - throw new ParseException(e::getMessage, markedUpLine.start(3) + e.getPosition()); + // translate error position from markup to file line + throw new ParseException(e::getMessage, next.offset() + markedUpLine.start("markup") + e.getPosition()); } for (Tag t : parsedTags) { - t.lineSourceOffset = next.offset; - t.markupLineOffset = markedUpLine.start(3); + t.lineSourceOffset = next.offset(); + t.markupLineOffset = markedUpLine.start("markup"); } thisLineTags.addAll(parsedTags); for (var tagIterator = thisLineTags.iterator(); tagIterator.hasNext(); ) { @@ -173,10 +166,11 @@ public final class Parser { } } if (parsedTags.isEmpty()) { // (2) - // TODO: log this with NOTICE; + diags.warn(resources.getText("doclet.snippet.markup.spurious"), next.offset() + markedUpLine.start("markup")); line = rawLine + (addLineTerminator ? "\n" : ""); } else { // (3) - String payload = markedUpLine.group(1); + hasMarkup = true; + String payload = rawLine.substring(0, markedUpLine.end("payload")); line = payload + (addLineTerminator ? "\n" : ""); } } @@ -193,7 +187,7 @@ public final class Parser { thisLineTags.clear(); - append(text, Set.of(), line); + append(text, line.isBlank() && hasMarkup ? Set.of(new Style.Markup()) : Set.of(), line); // TODO: mark up trailing whitespace! lineStart += line.length(); } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/snippet/Replace.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/snippet/Replace.java index 20820d8762d54a7d30bf824ffaf277e36d3e126c..1777bf65a74179a8b5ce8d1939f2114854cefffc 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/snippet/Replace.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/snippet/Replace.java @@ -66,7 +66,7 @@ public final class Replace implements Action { Matcher matcher = pattern.matcher(textString); var replacements = new ArrayList(); StringBuilder b = new StringBuilder(); - int off = 0; // offset because of the replacements (can be negative) + int off = 0; // cumulative offset caused by replacements (can become negative) while (matcher.find()) { int start = matcher.start(); int end = matcher.end(); @@ -79,7 +79,7 @@ public final class Replace implements Action { // there's no need to call matcher.appendTail(b) for (int i = replacements.size() - 1; i >= 0; i--) { Replacement r = replacements.get(i); - text.subText(r.start, r.end).replace(Set.of(), r.value); + text.subText(r.start(), r.end()).replace(Set.of(), r.value()); } } } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/snippet/Style.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/snippet/Style.java index fa6a2c293b60cb9050927c1ff89dd04305ddd53e..f7fd6aab9cb7483f35bcbee1c4663524df9bfdec 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/snippet/Style.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/snippet/Style.java @@ -33,26 +33,25 @@ package jdk.javadoc.internal.doclets.toolkit.taglets.snippet; * This code and its internal interfaces are subject to change or * deletion without notice. */ -// TODO: uncomment /* sealed */ when minimum boot JDK version >= 17 -public /* sealed */ interface Style { +public sealed interface Style { /** * A style that describes a link. Characters of this style are typically - * processed by wrapping into an HTML {@code A} element pointing to the + * processed by being wrapped into an HTML {@code A} element pointing to the * provided target. */ record Link(String target) implements Style { } /** * A named style. Characters of this style are typically processed by - * wrapping into an HTML {@code SPAN} element with the {@code class} + * being wrapped into an HTML {@code SPAN} element with the {@code class} * attribute which is obtained from the provided name. */ record Name(String name) implements Style { } /** * A marker of belonging to markup. Characters of this style are typically - * processed by omitting from the output. + * processed by being omitted from the output. */ record Markup() implements Style { } } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/snippet/StyledText.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/snippet/StyledText.java index d7e51a4e9370c85598bf5460abca524f32d2ede6..2a64b87acfaf3236539364c258df0f9d0ab1003c 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/snippet/StyledText.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/snippet/StyledText.java @@ -74,8 +74,8 @@ public class StyledText { } /* - * For each character of this text adds the provided objects to a set of - * objects associated with that character. + * For each character of this text adds the provided styles to a set of + * styles associated with that character. */ public void addStyle(Set additionalStyles) { styles.add(0, length(), additionalStyles); @@ -87,7 +87,7 @@ public class StyledText { /* * Replaces all characters of this text with the provided sequence of - * characters, each of which is associated with all the provided objects. + * characters, each of which is associated with all the provided styles. */ public void replace(Set styles, CharSequence plaintext) { replace(0, length(), styles, plaintext); 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 b96ada5367b9d0d2d6974cfa8729bc9397162022..b8c90fee82309b334cc7b6d9ca6f10820d158392 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 @@ -104,7 +104,7 @@ public class DocPaths { public static final DocPath JQUERY_OVERRIDES_CSS = DocPath.create("jquery-ui.overrides.css"); /** The name of the default jQuery javascript file. */ - public static final DocPath JQUERY_JS = DocPath.create("jquery-3.5.1.min.js"); + public static final DocPath JQUERY_JS = DocPath.create("jquery-3.6.0.min.js"); /** The name of the default jQuery UI stylesheet file. */ public static final DocPath JQUERY_UI_CSS = DocPath.create("jquery-ui.min.css"); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Extern.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Extern.java index 052fe0eb13b10277c611baa96aa7fe94f8e1f26d..71ec19d270cb445040e5b63310194d399859dc28 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Extern.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Extern.java @@ -514,7 +514,7 @@ public class Extern { DocPath elempath; String moduleName = null; DocPath basePath = DocPath.create(path); - boolean issueWarning = true; + boolean showDiagnostic = true; while ((elemname = in.readLine()) != null) { if (elemname.length() > 0) { elempath = basePath; @@ -534,14 +534,14 @@ public class Extern { // For user provided libraries we check whether modularity matches the actual library. // We trust modularity to be correct for platform library element lists. if (platformVersion == 0) { - actualModuleName = checkLinkCompatibility(elemname, moduleName, path, issueWarning); + actualModuleName = checkLinkCompatibility(elemname, moduleName, path, showDiagnostic); } else { actualModuleName = moduleName == null ? DocletConstants.DEFAULT_ELEMENT_NAME : moduleName; } Item item = new Item(elemname, elempath, relative); packageItems.computeIfAbsent(actualModuleName, k -> new TreeMap<>()) .putIfAbsent(elemname, item); // first-one-wins semantics - issueWarning = false; + showDiagnostic = false; } } } @@ -556,25 +556,23 @@ public class Extern { * @param packageName the package name * @param moduleName the module name or null * @param path the documentation path - * @param issueWarning whether to print a warning in case of modularity mismatch + * @param showDiagnostic whether to print a diagnostic message in case of modularity mismatch * @return the module name to use according to actual modularity of the package */ - private String checkLinkCompatibility(String packageName, String moduleName, String path, boolean issueWarning) { + private String checkLinkCompatibility(String packageName, String moduleName, String path, boolean showDiagnostic) { PackageElement pe = utils.elementUtils.getPackageElement(packageName); if (pe != null) { ModuleElement me = (ModuleElement)pe.getEnclosingElement(); if (me == null || me.isUnnamed()) { - if (moduleName != null && issueWarning) { - configuration.getReporter().print(Kind.WARNING, - resources.getText("doclet.linkMismatch_PackagedLinkedtoModule", path)); + if (moduleName != null && showDiagnostic) { + printModularityMismatchDiagnostic("doclet.linkMismatch_PackagedLinkedtoModule", path); } // library is not modular, ignore module name even if documentation is modular return DocletConstants.DEFAULT_ELEMENT_NAME; } else if (moduleName == null) { - // suppress the warning message in the case of automatic modules - if (!utils.elementUtils.isAutomaticModule(me) && issueWarning) { - configuration.getReporter().print(Kind.WARNING, - resources.getText("doclet.linkMismatch_ModuleLinkedtoPackage", path)); + // suppress the diagnostic message in the case of automatic modules + if (!utils.elementUtils.isAutomaticModule(me) && showDiagnostic) { + printModularityMismatchDiagnostic("doclet.linkMismatch_ModuleLinkedtoPackage", path); } // library is modular, use module name for lookup even though documentation is not return utils.getModuleName(me); @@ -659,4 +657,11 @@ public class Extern { return in; } + + private void printModularityMismatchDiagnostic(String key, Object arg) { + switch (configuration.getOptions().linkModularityMismatch()) { + case INFO -> configuration.getMessages().notice(key, arg); + case WARN -> configuration.getMessages().warning(key, arg); + } + } } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/UncheckedDocletException.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/UncheckedDocletException.java index b1644b439ca5870733923a74a198a066d54d66a4..5c358b784023f93816f28aea07eccaf0f54c7b00 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/UncheckedDocletException.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/UncheckedDocletException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -45,12 +45,7 @@ public class UncheckedDocletException extends Error { } @Override - public synchronized Throwable getCause() { - return super.getCause(); - } - - @Override - public synchronized Throwable initCause(Throwable cause) { + public Throwable initCause(Throwable cause) { throw new UnsupportedOperationException(); } } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Utils.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Utils.java index 4d289797bcf1533a9d30e99f7194e4314887fb22..21f16a01c5c1bdc87dc2c8b61f7dfe37a6c2e696 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Utils.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Utils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -159,27 +159,22 @@ public class Utils { } // our own little symbol table - private HashMap symtab = new HashMap<>(); + private final Map symtab = new HashMap<>(); public TypeMirror getSymbol(String signature) { - TypeMirror type = symtab.get(signature); - if (type == null) { - TypeElement typeElement = elementUtils.getTypeElement(signature); - if (typeElement == null) - return null; - type = typeElement.asType(); - if (type == null) - return null; - symtab.put(signature, type); - } - return type; + return symtab.computeIfAbsent(signature, s -> { + var typeElement = elementUtils.getTypeElement(s); + return typeElement == null ? null : typeElement.asType(); + }); } public TypeMirror getObjectType() { return getSymbol("java.lang.Object"); } - public TypeMirror getThrowableType() { return getSymbol("java.lang.Throwable"); } + public TypeMirror getThrowableType() { + return getSymbol("java.lang.Throwable"); + } public TypeMirror getSerializableType() { return getSymbol("java.io.Serializable"); @@ -189,14 +184,6 @@ public class Utils { return getSymbol("java.io.Externalizable"); } - public TypeMirror getIllegalArgumentExceptionType() { - return getSymbol("java.lang.IllegalArgumentException"); - } - - public TypeMirror getNullPointerExceptionType() { - return getSymbol("java.lang.NullPointerException"); - } - public TypeMirror getDeprecatedType() { return getSymbol("java.lang.Deprecated"); } @@ -205,22 +192,6 @@ public class Utils { return getSymbol("java.lang.FunctionalInterface"); } - /** - * Return array of class members whose documentation is to be generated. - * If the member is deprecated do not include such a member in the - * returned array. - * - * @param members Array of members to choose from. - * @return List List of eligible members for whom - * documentation is getting generated. - */ - public List excludeDeprecatedMembers(List members) { - return members.stream() - .filter(member -> !isDeprecated(member)) - .sorted(comparators.makeGeneralPurposeComparator()) - .collect(Collectors.toCollection(ArrayList::new)); - } - /** * Search for the given method in the given class. * @@ -241,9 +212,9 @@ public class Utils { /** * Test whether a class is a subclass of another class. * - * @param t1 the candidate superclass. - * @param t2 the target - * @return true if t1 is a superclass of t2. + * @param t1 the candidate subclass + * @param t2 the candidate superclass + * @return true if t1 is a superclass of t2 */ public boolean isSubclassOf(TypeElement t1, TypeElement t2) { return typeUtils.isSubtype(typeUtils.erasure(t1.asType()), typeUtils.erasure(t2.asType())); @@ -261,20 +232,14 @@ public class Utils { List parameters2 = e2.getParameters(); if (e1.getSimpleName().equals(e2.getSimpleName()) && parameters1.size() == parameters2.size()) { - int j; - for (j = 0 ; j < parameters1.size(); j++) { + for (int j = 0; j < parameters1.size(); j++) { VariableElement v1 = parameters1.get(j); VariableElement v2 = parameters2.get(j); - String t1 = getTypeName(v1.asType(), true); - String t2 = getTypeName(v2.asType(), true); - if (!(t1.equals(t2) || - isTypeVariable(v1.asType()) || isTypeVariable(v2.asType()))) { - break; + if (!typeUtils.isSameType(v1.asType(), v2.asType())) { + return false; } } - if (j == parameters1.size()) { - return true; - } + return true; } return false; } else { @@ -320,10 +285,6 @@ public class Utils { return !e.getAnnotationMirrors().isEmpty(); } - public boolean isAnnotated(Element e) { - return !e.getAnnotationMirrors().isEmpty(); - } - public boolean isAnnotationType(Element e) { return new SimpleElementVisitor14() { @Override @@ -361,10 +322,6 @@ public class Utils { return e.getKind() == ENUM; } - boolean isEnumConstant(Element e) { - return e.getKind() == ENUM_CONSTANT; - } - public boolean isField(Element e) { return e.getKind() == FIELD; } @@ -511,57 +468,26 @@ public class Utils { return typeUtils.isSubtype(te.asType(), getThrowableType()); } - public boolean isPrimitive(TypeMirror t) { - return new SimpleTypeVisitor14() { - - @Override - public Boolean visitNoType(NoType t, Void p) { - return t.getKind() == VOID; - } - @Override - public Boolean visitPrimitive(PrimitiveType t, Void p) { - return true; - } - @Override - public Boolean visitArray(ArrayType t, Void p) { - return visit(t.getComponentType()); - } - @Override - protected Boolean defaultAction(TypeMirror e, Void p) { - return false; - } - }.visit(t); - } - public boolean isExecutableElement(Element e) { - ElementKind kind = e.getKind(); - switch (kind) { - case CONSTRUCTOR: case METHOD: case INSTANCE_INIT: - return true; - default: - return false; - } + return switch (e.getKind()) { + case CONSTRUCTOR, METHOD, INSTANCE_INIT -> true; + default -> false; + }; } public boolean isVariableElement(Element e) { - ElementKind kind = e.getKind(); - switch(kind) { - case ENUM_CONSTANT: case EXCEPTION_PARAMETER: case FIELD: - case LOCAL_VARIABLE: case PARAMETER: - case RESOURCE_VARIABLE: - return true; - default: - return false; - } + return switch (e.getKind()) { + case ENUM_CONSTANT, EXCEPTION_PARAMETER, FIELD, LOCAL_VARIABLE, + PARAMETER, RESOURCE_VARIABLE -> true; + default -> false; + }; } public boolean isTypeElement(Element e) { - switch (e.getKind()) { - case CLASS: case ENUM: case INTERFACE: case ANNOTATION_TYPE: case RECORD: - return true; - default: - return false; - } + return switch (e.getKind()) { + case CLASS, ENUM, INTERFACE, ANNOTATION_TYPE, RECORD -> true; + default -> false; + }; } /** @@ -693,14 +619,6 @@ public class Utils { return t.getKind() == DECLARED; } - public boolean isErrorType(TypeMirror t) { - return t.getKind() == ERROR; - } - - public boolean isIntersectionType(TypeMirror t) { - return t.getKind() == INTERSECTION; - } - public boolean isTypeParameterElement(Element e) { return e.getKind() == TYPE_PARAMETER; } @@ -713,12 +631,8 @@ public class Utils { return t.getKind() == VOID; } - public boolean isWildCard(TypeMirror t) { - return t.getKind() == WILDCARD; - } - public boolean ignoreBounds(TypeMirror bound) { - return bound.equals(getObjectType()) && !isAnnotated(bound); + return typeUtils.isSameType(bound, getObjectType()) && !isAnnotated(bound); } /* @@ -783,11 +697,20 @@ public class Utils { !((DeclaredType)e.getEnclosingElement().asType()).getTypeArguments().isEmpty(); } - /** - * Return the type containing the method that this method overrides. - * It may be a {@code TypeElement} or a {@code TypeParameterElement}. + /* + * Returns the closest superclass (not the superinterface) that contains + * a method that is both: + * + * - overridden by the specified method, and + * - is not itself a *simple* override + * + * If no such class can be found, returns null. + * + * If the specified method belongs to an interface, the only considered + * superclass is java.lang.Object no matter how many other interfaces + * that interface extends. */ - public TypeMirror overriddenType(ExecutableElement method) { + public DeclaredType overriddenType(ExecutableElement method) { return configuration.workArounds.overriddenType(method); } @@ -800,28 +723,14 @@ public class Utils { return getType(t); } - /** - * Return the class that originally defined the method that - * is overridden by the current definition, or null if no - * such class exists. - * - * @return a TypeElement representing the superclass that - * originally defined this method, null if this method does - * not override a definition in a superclass. - */ - public TypeElement overriddenClass(ExecutableElement ee) { - TypeMirror type = overriddenType(ee); - return (type != null) ? asTypeElement(type) : null; - } - public ExecutableElement overriddenMethod(ExecutableElement method) { if (isStatic(method)) { return null; } final TypeElement origin = getEnclosingTypeElement(method); for (TypeMirror t = getSuperType(origin); - t.getKind() == DECLARED; - t = getSuperType(asTypeElement(t))) { + t.getKind() == DECLARED; + t = getSuperType(asTypeElement(t))) { TypeElement te = asTypeElement(t); if (te == null) { return null; @@ -834,7 +743,7 @@ public class Utils { return ee; } } - if (t.equals(getObjectType())) + if (typeUtils.isSameType(t, getObjectType())) return null; } return null; @@ -916,30 +825,69 @@ public class Utils { */ public Set getAllInterfaces(TypeElement te) { Set results = new LinkedHashSet<>(); - getAllInterfaces(te.asType(), results); + addSuperInterfaces(te.asType(), results, new HashSet<>()); + assert noSameTypes(results); return results; } - private void getAllInterfaces(TypeMirror type, Set results) { - List intfacs = typeUtils.directSupertypes(type); + private boolean noSameTypes(Set results) { + for (TypeMirror t1 : results) { + for (TypeMirror t2 : results) { + if (t1 == t2) { + continue; + } + if (typeUtils.isSameType(t1, t2)) { + return false; + } + } + } + return true; + } + + /* + * Instances of TypeMirror should be compared using + * Types.isSameType. However, there's no hash function + * consistent with that method. This makes it problematic to + * store TypeMirror in a collection that relies on hashing. + * + * To work around that, along with accumulating the resulting set of type + * mirrors, we also maintain a set of elements that correspond to those + * type mirrors. Element provides strong equals and hashCode. We only add + * a type mirror into the result set if we don't already have an element + * that corresponds to this type mirror in the set of seen elements. + * + * Although this might seem wrong, as an instance of Element corresponds + * to multiple instances of TypeMirror (one-to-many), in an + * inheritance hierarchy the correspondence is effectively one-to-one. + * This is because it is NOT possible for a type to be a subtype + * of different generic invocations of the same supertype; e.g., + * + * interface X extends G, G + */ + private void addSuperInterfaces(TypeMirror type, Set results, Set visited) { TypeMirror superType = null; - for (TypeMirror intfac : intfacs) { - if (intfac == getObjectType()) + for (TypeMirror t : typeUtils.directSupertypes(type)) { + if (typeUtils.isSameType(t, getObjectType())) continue; - TypeElement e = asTypeElement(intfac); + TypeElement e = asTypeElement(t); if (isInterface(e)) { - if (isPublic(e) || isLinkable(e)) - results.add(intfac); - - getAllInterfaces(intfac, results); + if (!visited.add(e)) { + continue; // seen it before + } + if (isPublic(e) || isLinkable(e)) { + results.add(t); + } + addSuperInterfaces(t, results, visited); } else { + // there can be at most one superclass and it is not null + assert superType == null && t != null : superType; // Save the supertype for later. - superType = intfac; + superType = t; } } // Collect the super-interfaces of the supertype. if (superType != null) - getAllInterfaces(superType, results); + addSuperInterfaces(superType, results, visited); } /** @@ -995,13 +943,6 @@ public class Utils { return searchResult; } - /** - * Enclose in quotes, used for paths and filenames that contains spaces - */ - public String quote(String filepath) { - return ("\"" + filepath + "\""); - } - /** * Parse the package name. We only want to display package name up to * 2 levels. @@ -1176,8 +1117,7 @@ public class Utils { } public TypeElement getSuperClass(TypeElement te) { - if (isInterface(te) || isAnnotationType(te) || - te.asType().equals(getObjectType())) { + if (checkType(te)) { return null; } TypeMirror superclass = te.getSuperclass(); @@ -1187,9 +1127,13 @@ public class Utils { return asTypeElement(superclass); } + private boolean checkType(TypeElement te) { + return isInterface(te) || typeUtils.isSameType(te.asType(), getObjectType()) + || isAnnotationType(te); + } + public TypeElement getFirstVisibleSuperClassAsTypeElement(TypeElement te) { - if (isAnnotationType(te) || isInterface(te) || - te.asType().equals(getObjectType())) { + if (checkType(te)) { return null; } TypeMirror firstVisibleSuperClass = getFirstVisibleSuperClass(te); @@ -1202,7 +1146,6 @@ public class Utils { * @return the closest visible super class. Return null if it cannot * be found. */ - public TypeMirror getFirstVisibleSuperClass(TypeMirror type) { return getFirstVisibleSuperClass(asTypeElement(type)); } @@ -1213,7 +1156,7 @@ public class Utils { * * @param te the TypeElement to be interrogated * @return the closest visible super class. Return null if it cannot - * be found.. + * be found. */ public TypeMirror getFirstVisibleSuperClass(TypeElement te) { TypeMirror superType = te.getSuperclass(); @@ -1233,7 +1176,7 @@ public class Utils { superType = supersuperType; superClass = supersuperClass; } - if (te.asType().equals(superType)) { + if (typeUtils.isSameType(te.asType(), superType)) { return null; } return superType; @@ -1481,10 +1424,14 @@ public class Utils { return hasBlockTag(e, DocTree.Kind.HIDDEN); } - /** - * Returns true if the method has no comments, or a lone @inheritDoc. - * @param m a method - * @return true if there are no comments, false otherwise + /* + * Returns true if the passed method does not change the specification it + * inherited. + * + * If the passed method is not deprecated and has either no comment or a + * comment consisting of single {@inheritDoc} tag, the inherited + * specification is deemed unchanged and this method returns true; + * otherwise this method returns false. */ public boolean isSimpleOverride(ExecutableElement m) { if (!options.summarizeOverriddenMethods() || !isIncluded(m)) { @@ -1562,19 +1509,6 @@ public class Utils { return compareStrings(true, s1, s2); } - /** - * A general purpose case sensitive String comparator, which - * compares two Strings using a Collator strength of "SECONDARY". - * - * @param s1 first String to compare. - * @param s2 second String to compare. - * @return a negative integer, zero, or a positive integer as the first - * argument is less than, equal to, or greater than the second. - */ - public int compareCaseCompare(String s1, String s2) { - return compareStrings(false, s1, s2); - } - private DocCollator tertiaryCollator = null; private DocCollator secondaryCollator = null; @@ -1766,26 +1700,6 @@ public class Utils { } - /** - * Returns the documented annotation interfaces in a package. - * - * @param pkg the package - * @return the annotation interfaces - */ - public List getAnnotationTypes(PackageElement pkg) { - return getDocumentedItems(pkg, ANNOTATION_TYPE, TypeElement.class); - } - - /** - * Returns the documented record classes in a package. - * - * @param pkg the package - * @return the record classes - */ - public List getRecords(PackageElement pkg) { - return getDocumentedItems(pkg, RECORD, TypeElement.class); - } - /** * Returns the documented fields in a type element. * @@ -1838,13 +1752,6 @@ public class Utils { return getDocumentedItems(te, METHOD, ExecutableElement.class); } - public int getOrdinalValue(VariableElement member) { - if (member == null || member.getKind() != ENUM_CONSTANT) { - throw new IllegalArgumentException("must be an enum constant: " + member); - } - return member.getEnclosingElement().getEnclosedElements().indexOf(member); - } - private Map> modulePackageMap = null; public Map> getModulePackageMap() { if (modulePackageMap == null) { @@ -1916,16 +1823,6 @@ public class Utils { return lineMap.getLineNumber(pos); } - /** - * Returns the documented interfaces in a package. - * - * @param pkg the package - * @return the interfaces - */ - public List getInterfaces(PackageElement pkg) { - return getDocumentedItems(pkg, INTERFACE, TypeElement.class); - } - /** * Returns the documented enum constants in a type element. * @@ -1936,16 +1833,6 @@ public class Utils { return getDocumentedItems(te, ENUM_CONSTANT, VariableElement.class); } - /** - * Returns the documented enum classes in a package. - * - * @param pkg the package - * @return the interfaces - */ - public List getEnums(PackageElement pkg) { - return getDocumentedItems(pkg, ENUM, TypeElement.class); - } - /** * Returns all the classes in a package. * @@ -2347,102 +2234,6 @@ public class Utils { return mdle.getQualifiedName().toString(); } - public boolean isAttribute(DocTree doctree) { - return isKind(doctree, ATTRIBUTE); - } - - public boolean isAuthor(DocTree doctree) { - return isKind(doctree, AUTHOR); - } - - public boolean isComment(DocTree doctree) { - return isKind(doctree, COMMENT); - } - - public boolean isDeprecated(DocTree doctree) { - return isKind(doctree, DEPRECATED); - } - - public boolean isDocComment(DocTree doctree) { - return isKind(doctree, DOC_COMMENT); - } - - public boolean isDocRoot(DocTree doctree) { - return isKind(doctree, DOC_ROOT); - } - - public boolean isEndElement(DocTree doctree) { - return isKind(doctree, END_ELEMENT); - } - - public boolean isEntity(DocTree doctree) { - return isKind(doctree, ENTITY); - } - - public boolean isErroneous(DocTree doctree) { - return isKind(doctree, ERRONEOUS); - } - - public boolean isException(DocTree doctree) { - return isKind(doctree, EXCEPTION); - } - - public boolean isIdentifier(DocTree doctree) { - return isKind(doctree, IDENTIFIER); - } - - public boolean isInheritDoc(DocTree doctree) { - return isKind(doctree, INHERIT_DOC); - } - - public boolean isLink(DocTree doctree) { - return isKind(doctree, LINK); - } - - public boolean isLinkPlain(DocTree doctree) { - return isKind(doctree, LINK_PLAIN); - } - - public boolean isLiteral(DocTree doctree) { - return isKind(doctree, LITERAL); - } - - public boolean isOther(DocTree doctree) { - return doctree.getKind() == DocTree.Kind.OTHER; - } - - public boolean isParam(DocTree doctree) { - return isKind(doctree, PARAM); - } - - public boolean isReference(DocTree doctree) { - return isKind(doctree, REFERENCE); - } - - public boolean isReturn(DocTree doctree) { - return isKind(doctree, RETURN); - } - - public boolean isSee(DocTree doctree) { - return isKind(doctree, SEE); - } - - public boolean isSerial(DocTree doctree) { - return isKind(doctree, SERIAL); - } - - public boolean isSerialData(DocTree doctree) { - return isKind(doctree, SERIAL_DATA); - } - - public boolean isSerialField(DocTree doctree) { - return isKind(doctree, SERIAL_FIELD); - } - - public boolean isSince(DocTree doctree) { - return isKind(doctree, SINCE); - } - public boolean isStartElement(DocTree doctree) { return isKind(doctree, START_ELEMENT); } @@ -2451,26 +2242,6 @@ public class Utils { return isKind(doctree, TEXT); } - public boolean isThrows(DocTree doctree) { - return isKind(doctree, THROWS); - } - - public boolean isUnknownBlockTag(DocTree doctree) { - return isKind(doctree, UNKNOWN_BLOCK_TAG); - } - - public boolean isUnknownInlineTag(DocTree doctree) { - return isKind(doctree, UNKNOWN_INLINE_TAG); - } - - public boolean isValue(DocTree doctree) { - return isKind(doctree, VALUE); - } - - public boolean isVersion(DocTree doctree) { - return isKind(doctree, VERSION); - } - private boolean isKind(DocTree doctree, DocTree.Kind match) { return doctree.getKind() == match; } @@ -2516,10 +2287,6 @@ public class Utils { return getBlockTags(element, t -> t.getKind() == kind, tClass); } - public List getBlockTags(Element element, DocTree.Kind kind, DocTree.Kind altKind) { - return getBlockTags(element, t -> t.getKind() == kind || t.getKind() == altKind); - } - public List getBlockTags(Element element, Taglet taglet) { return getBlockTags(element, t -> { if (taglet instanceof BaseTaglet baseTaglet) { @@ -2592,7 +2359,7 @@ public class Utils { /** * A cache of doc comment info objects for elements. - * The entries may come from the AST and DocCommentParser, or may be autromatically + * The entries may come from the AST and DocCommentParser, or may be automatically * generated comments for mandated elements and JavaFX properties. * * @see CommentUtils#dcInfoMap @@ -2795,19 +2562,6 @@ public class Utils { return elementUtils.getPackageOf(e); } - public TypeElement getTopMostContainingTypeElement(Element e) { - if (isPackage(e)) { - return null; - } - TypeElement outer = getEnclosingTypeElement(e); - if (outer == null) - return (TypeElement)e; - while (outer != null && outer.getNestingKind().isNested()) { - outer = getEnclosingTypeElement(outer); - } - return outer; - } - /** * A memory-sensitive cache for {@link CommentHelper} objects, * which are expensive to compute. @@ -2893,8 +2647,11 @@ public class Utils { } public PreviewSummary declaredUsingPreviewAPIs(Element el) { - List usedInDeclaration = new ArrayList<>(); - usedInDeclaration.addAll(annotations2Classes(el)); + if (el.asType().getKind() == ERROR) { + // Can happen with undocumented --ignore-source-errors option + return new PreviewSummary(Collections.emptySet(), Collections.emptySet(), Collections.emptySet()); + } + List usedInDeclaration = new ArrayList<>(annotations2Classes(el)); switch (el.getKind()) { case ANNOTATION_TYPE, CLASS, ENUM, INTERFACE, RECORD -> { TypeElement te = (TypeElement) el; @@ -3050,9 +2807,11 @@ public class Utils { */ public boolean isPreviewAPI(Element el) { boolean parentPreviewAPI = false; - Element enclosing = el.getEnclosingElement(); - if (enclosing != null && (enclosing.getKind().isClass() || enclosing.getKind().isInterface())) { - parentPreviewAPI = configuration.workArounds.isPreviewAPI(enclosing); + if (!isClassOrInterface(el)) { + Element enclosing = el.getEnclosingElement(); + if (isClassOrInterface(enclosing)) { + parentPreviewAPI = configuration.workArounds.isPreviewAPI(enclosing); + } } boolean previewAPI = configuration.workArounds.isPreviewAPI(el); return !parentPreviewAPI && previewAPI; @@ -3079,18 +2838,12 @@ public class Utils { */ public Set elementFlags(Element el) { Set flags = EnumSet.noneOf(ElementFlag.class); - PreviewSummary previewAPIs = declaredUsingPreviewAPIs(el); if (isDeprecated(el)) { flags.add(ElementFlag.DEPRECATED); } - if ((!previewLanguageFeaturesUsed(el).isEmpty() || - configuration.workArounds.isPreviewAPI(el) || - !previewAPIs.previewAPI.isEmpty() || - !previewAPIs.reflectivePreviewAPI.isEmpty() || - !previewAPIs.declaredUsingPreviewFeature.isEmpty()) && - !hasNoProviewAnnotation(el)) { + if (previewFlagProvider.isPreview(el)) { flags.add(ElementFlag.PREVIEW); } @@ -3106,9 +2859,42 @@ public class Utils { PREVIEW } - private boolean hasNoProviewAnnotation(Element el) { + private boolean isClassOrInterface(Element el) { + return el != null && (el.getKind().isClass() || el.getKind().isInterface()); + } + + private boolean hasNoPreviewAnnotation(Element el) { return el.getAnnotationMirrors() .stream() .anyMatch(am -> "jdk.internal.javac.NoPreview".equals(getQualifiedTypeName(am.getAnnotationType()))); } + + private PreviewFlagProvider previewFlagProvider = new PreviewFlagProvider() { + @Override + public boolean isPreview(Element el) { + PreviewSummary previewAPIs = declaredUsingPreviewAPIs(el); + Element enclosing = el.getEnclosingElement(); + + return ( !previewLanguageFeaturesUsed(el).isEmpty() + || configuration.workArounds.isPreviewAPI(el) + || ( !isClassOrInterface(el) && isClassOrInterface(enclosing) + && configuration.workArounds.isPreviewAPI(enclosing)) + || !previewAPIs.previewAPI.isEmpty() + || !previewAPIs.reflectivePreviewAPI.isEmpty() + || !previewAPIs.declaredUsingPreviewFeature.isEmpty()) + && !hasNoPreviewAnnotation(el); + } + }; + + public PreviewFlagProvider setPreviewFlagProvider(PreviewFlagProvider provider) { + Objects.requireNonNull(provider); + PreviewFlagProvider old = previewFlagProvider; + previewFlagProvider = provider; + return old; + } + + public interface PreviewFlagProvider { + public boolean isPreview(Element el); + } + } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/VisibleMemberTable.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/VisibleMemberTable.java index 096b23a2e1272a93e7839b8454dad172c441ed1d..5ef16d61fcf7642dc8d8a18bd9ba9f2ff3a2beae 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/VisibleMemberTable.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/VisibleMemberTable.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -43,6 +43,7 @@ import javax.lang.model.util.SimpleElementVisitor14; import javax.lang.model.util.SimpleTypeVisitor14; import java.lang.ref.SoftReference; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.EnumMap; import java.util.EnumSet; @@ -63,12 +64,12 @@ import jdk.javadoc.internal.doclets.toolkit.PropertyUtils; /** * This class computes the main data structure for the doclet's * operations. Essentially, the implementation encapsulating the - * javax.lang.models view of what can be documented about a + * javax.lang.model's view of what can be documented about a * type element's members. *

          * The general operations are as follows: *

          - * Members: these are the members from jx.l.m's view but + * Members: these are the members from j.l.m's view but * are structured along the kinds of this class. *

          * Extra Members: these are members enclosed in an undocumented @@ -146,23 +147,23 @@ public class VisibleMemberTable { } } - final TypeElement te; - final TypeElement parent; + private final TypeElement te; + private final TypeElement parent; - final BaseConfiguration config; - final BaseOptions options; - final Utils utils; - final VisibleMemberCache mcache; + private final BaseConfiguration config; + private final BaseOptions options; + private final Utils utils; + private final VisibleMemberCache mcache; private final List allSuperclasses; private final List allSuperinterfaces; private final List parents; - private Map> visibleMembers = null; + private Map> visibleMembers; private final Map propertyMap = new HashMap<>(); // Keeps track of method overrides - Map overriddenMethodTable + private final Map overriddenMethodTable = new LinkedHashMap<>(); protected VisibleMemberTable(TypeElement typeElement, BaseConfiguration configuration, @@ -178,7 +179,7 @@ public class VisibleMemberTable { parents = new ArrayList<>(); } - private synchronized void ensureInitialized() { + private void ensureInitialized() { if (visibleMembers != null) return; @@ -208,7 +209,7 @@ public class VisibleMemberTable { * a. The list may or may not contain simple overridden methods. * A simple overridden method is one that overrides a super method * with no specification changes as indicated by the existence of a - * sole @inheritDoc or devoid of any API comments. + * sole {@code @inheritDoc} or devoid of any API comments. *

          * b.The list may contain (extra) members, inherited by inaccessible * super types, primarily package private types. These members are @@ -279,24 +280,22 @@ public class VisibleMemberTable { OverriddenMethodInfo found = overriddenMethodTable.get(e); if (found != null && (found.simpleOverride || utils.isUndocumentedEnclosure(utils.getEnclosingTypeElement(e)))) { - return found.overridden; + return found.overriddenMethod; } return null; } /** - * Returns the simply overridden method. + * {@return true if the specified method is NOT a simple override of some + * other method, otherwise false} + * * @param e the method to check - * @return the overridden method or null */ - public ExecutableElement getSimplyOverriddenMethod(ExecutableElement e) { + public boolean isNotSimpleOverride(ExecutableElement e) { ensureInitialized(); - OverriddenMethodInfo found = overriddenMethodTable.get(e); - if (found != null && found.simpleOverride) { - return found.overridden; - } - return null; + var info = overriddenMethodTable.get(e); + return info == null || !info.simpleOverride; } /** @@ -306,7 +305,7 @@ public class VisibleMemberTable { * order C, B, A, j.l.O. The super-interfaces however are * alpha sorted and appended to the resulting set. * - * @return the list of visible classes in this map. + * @return the set of visible classes in this map */ public Set getVisibleTypeElements() { ensureInitialized(); @@ -527,12 +526,11 @@ public class VisibleMemberTable { Map> overriddenByTable = new HashMap<>(); for (VisibleMemberTable pvmt : parents) { // Merge the lineage overrides into local table - pvmt.overriddenMethodTable.entrySet().forEach(e -> { - OverriddenMethodInfo p = e.getValue(); - if (!p.simpleOverride) { // consider only real overrides - List list = overriddenByTable.computeIfAbsent(p.overridden, + pvmt.overriddenMethodTable.forEach((method, methodInfo) -> { + if (!methodInfo.simpleOverride) { // consider only real overrides + List list = overriddenByTable.computeIfAbsent(methodInfo.overriddenMethod, k -> new ArrayList<>()); - list.add(e.getKey()); + list.add(method); } }); inheritedMethods.addAll(pvmt.getAllVisibleMembers(Kind.METHODS)); @@ -544,7 +542,7 @@ public class VisibleMemberTable { // c. are hidden in the type being considered // see allowInheritedMethod, which performs the above actions // nb. This statement has side effects that can initialize - // members of the overridenMethodTable field, so it must be + // members of the overriddenMethodTable field, so it must be // evaluated eagerly with toList(). List inheritedMethodsList = inheritedMethods.stream() .filter(e -> allowInheritedMethod((ExecutableElement) e, overriddenByTable, lmt)) @@ -565,7 +563,7 @@ public class VisibleMemberTable { // Merge the above list and stream, making sure the local methods precede the others // Final filtration of elements - List list = Stream.concat(localStream,inheritedMethodsList.stream()) + List list = Stream.concat(localStream, inheritedMethodsList.stream()) .filter(this::mustDocument) .toList(); @@ -575,7 +573,6 @@ public class VisibleMemberTable { for (VisibleMemberTable pvmt : parents) { overriddenMethodTable.putAll(pvmt.overriddenMethodTable); } - overriddenMethodTable = Collections.unmodifiableMap(overriddenMethodTable); } boolean isEnclosureInterface(Element e) { @@ -850,7 +847,7 @@ public class VisibleMemberTable { Map> map = memberMap.get(kind); return map.getOrDefault(key, Collections.emptyList()) .stream() - .map(e -> clazz.cast(e)) + .map(clazz::cast) .toList(); } @@ -967,7 +964,8 @@ public class VisibleMemberTable { // Future cleanups - Map> implementMethodsFinders = new HashMap<>(); + private final Map> + implementMethodsFinders = new HashMap<>(); private ImplementedMethods getImplementedMethodsFinder(ExecutableElement method) { SoftReference ref = implementMethodsFinders.get(method); @@ -983,7 +981,7 @@ public class VisibleMemberTable { public List getImplementedMethods(ExecutableElement method) { ImplementedMethods imf = getImplementedMethodsFinder(method); return imf.getImplementedMethods().stream() - .filter(m -> getSimplyOverriddenMethod(m) == null) + .filter(this::isNotSimpleOverride) .toList(); } @@ -996,112 +994,46 @@ public class VisibleMemberTable { private class ImplementedMethods { private final Map interfaces = new HashMap<>(); - private final List methlist = new ArrayList<>(); + private final LinkedHashSet methods = new LinkedHashSet<>(); public ImplementedMethods(ExecutableElement method) { - TypeElement typeElement = utils.getEnclosingTypeElement(method); + // ExecutableElement.getEnclosingElement() returns "the class or + // interface defining the executable", which has to be TypeElement + TypeElement typeElement = (TypeElement) method.getEnclosingElement(); Set intfacs = utils.getAllInterfaces(typeElement); - /* - * Search for the method in the list of interfaces. If found check if it is - * overridden by any other subinterface method which this class - * implements. If it is not overridden, add it in the method list. - * Do this recursively for all the extended interfaces for each interface - * from the list. - */ for (TypeMirror interfaceType : intfacs) { + // TODO: this method also finds static methods which are pseudo-inherited; + // this needs to be fixed ExecutableElement found = utils.findMethod(utils.asTypeElement(interfaceType), method); - if (found != null) { - removeOverriddenMethod(found); - if (!overridingMethodFound(found)) { - methlist.add(found); - interfaces.put(found, interfaceType); - } + if (found != null && !methods.contains(found)) { + methods.add(found); + interfaces.put(found, interfaceType); } } } /** - * Return the list of interface methods which the method passed in the + * Returns a collection of interface methods which the method passed in the * constructor is implementing. The search/build order is as follows: *

                    * 1. Search in all the immediate interfaces which this method's class is
                    *    implementing. Do it recursively for the superinterfaces as well.
                    * 2. Traverse all the superclasses and search recursively in the
                    *    interfaces which those superclasses implement.
          -         *
          + * * - * @return SortedSet of implemented methods. + * @return a collection of implemented methods */ - List getImplementedMethods() { - return methlist; + Collection getImplementedMethods() { + return methods; } TypeMirror getMethodHolder(ExecutableElement ee) { return interfaces.get(ee); } - - /** - * Search in the method list and check if it contains a method which - * is overridden by the method as parameter. If found, remove the - * overridden method from the method list. - * - * @param method Is this method overriding a method in the method list. - */ - private void removeOverriddenMethod(ExecutableElement method) { - TypeElement overriddenClass = utils.overriddenClass(method); - if (overriddenClass != null) { - for (int i = 0; i < methlist.size(); i++) { - TypeElement te = utils.getEnclosingTypeElement(methlist.get(i)); - if (te == overriddenClass || utils.isSubclassOf(overriddenClass, te)) { - methlist.remove(i); // remove overridden method - return; - } - } - } - } - - /** - * Search in the already found methods' list and check if it contains - * a method which is overriding the method parameter or is the method - * parameter itself. - * - * @param method method to be searched - */ - private boolean overridingMethodFound(ExecutableElement method) { - TypeElement containingClass = utils.getEnclosingTypeElement(method); - for (ExecutableElement listmethod : methlist) { - if (containingClass == utils.getEnclosingTypeElement(listmethod)) { - // it's the same method. - return true; - } - TypeElement te = utils.overriddenClass(listmethod); - if (te == null) { - continue; - } - if (te == containingClass || utils.isSubclassOf(te, containingClass)) { - return true; - } - } - return false; - } } - /** - * A simple container to encapsulate an overridden method - * and the type of override. - */ - static class OverriddenMethodInfo { - final ExecutableElement overridden; - final boolean simpleOverride; - - public OverriddenMethodInfo(ExecutableElement overridden, boolean simpleOverride) { - this.overridden = overridden; - this.simpleOverride = simpleOverride; - } - - @Override - public String toString() { - return "OverriddenMethodInfo[" + overridden + ",simple:" + simpleOverride + "]"; - } + private record OverriddenMethodInfo(ExecutableElement overriddenMethod, + boolean simpleOverride) { } } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/links/LinkFactory.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/links/LinkFactory.java index c5e6799022110bd95d29650c229c3beb81460254..04a238800cd07d7b43e595c4dbe57f1f22e4c1cf 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/links/LinkFactory.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/links/LinkFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -151,7 +151,7 @@ public abstract class LinkFactory { // we get everything as extends java.lang.Object we suppress // all of them except those that have multiple extends if (bounds.size() == 1 && - bound.equals(utils.getObjectType()) && + utils.typeUtils.isSameType(bound, utils.getObjectType()) && !utils.isAnnotated(bound)) { continue; } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/Checker.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/Checker.java index 0d73d233cc166af98273ec654db57c070abda3d8..6b167aa393329f1070d18dacaf118a6a74be9970 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/Checker.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/Checker.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -41,6 +41,7 @@ import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; +import javax.lang.model.SourceVersion; import javax.lang.model.element.Element; import javax.lang.model.element.ElementKind; import javax.lang.model.element.ExecutableElement; @@ -952,11 +953,31 @@ public class Checker extends DocTreePathScanner { @Override @DefinedBy(Api.COMPILER_TREE) public Void visitReference(ReferenceTree tree, Void ignore) { Element e = env.trees.getElement(getCurrentPath()); - if (e == null) - env.messages.error(REFERENCE, tree, "dc.ref.not.found"); + if (e == null) { + reportBadReference(tree); + } return super.visitReference(tree, ignore); } + private void reportBadReference(ReferenceTree tree) { + if (!env.strictReferenceChecks) { + String refSig = tree.getSignature(); + int sep = refSig.indexOf("/"); + if (sep > 0) { + String moduleName = refSig.substring(0, sep); + if (SourceVersion.isName(moduleName)) { + Element m = env.elements.getModuleElement(moduleName); + if (m == null) { + env.messages.warning(REFERENCE, tree, "dc.ref.in.missing.module", moduleName); + return; + } + } + } + } + + env.messages.error(REFERENCE, tree, "dc.ref.not.found"); + } + @Override @DefinedBy(Api.COMPILER_TREE) public Void visitReturn(ReturnTree tree, Void ignore) { if (foundReturn) { @@ -964,8 +985,8 @@ public class Checker extends DocTreePathScanner { } if (tree.isInline()) { DocCommentTree dct = getCurrentPath().getDocComment(); - if (tree != dct.getFirstSentence().get(0)) { - env.messages.warning(REFERENCE, tree, "dc.return.not.first"); + if (dct.getFirstSentence().isEmpty() || tree != dct.getFirstSentence().get(0)) { + env.messages.warning(SYNTAX, tree, "dc.return.not.first"); } } @@ -1236,13 +1257,7 @@ public class Checker extends DocTreePathScanner { } boolean hasNonWhitespace(TextTree tree) { - String s = tree.getBody(); - for (int i = 0; i < s.length(); i++) { - Character c = s.charAt(i); - if (!Character.isWhitespace(s.charAt(i))) - return true; - } - return false; + return !tree.getBody().isBlank(); } // diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/DocLint.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/DocLint.java index 1c4f3a3d6509b1bfc987877636f9454927cd3d4b..9a1d0f2e4ccb3240af39c95cca3dfdaf030dc9bc 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/DocLint.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/DocLint.java @@ -274,6 +274,14 @@ public class DocLint extends com.sun.tools.doclint.DocLint { // + /** + * Initialize DocLint for use with a {@code JavacTask}. + * {@link Env#strictReferenceChecks Strict reference checks} are not enabled by default. + * + * @param task the task + * @param args arguments to configure DocLint + * @param addTaskListener whether or not to register a {@code TaskListener} to invoke DocLint + */ public void init(JavacTask task, String[] args, boolean addTaskListener) { env = new Env(); env.init(task); @@ -319,9 +327,19 @@ public class DocLint extends com.sun.tools.doclint.DocLint { } } + /** + * Initialize DocLint with the given utility objects and arguments. + * {@link Env#strictReferenceChecks Strict reference checks} are enabled by default. + * + * @param trees the {@code DocTrees} utility class + * @param elements the {@code Elements} utility class + * @param types the {@code Types} utility class + * @param args arguments to configure DocLint + */ public void init(DocTrees trees, Elements elements, Types types, String... args) { env = new Env(); env.init(trees, elements, types); + env.strictReferenceChecks = true; processArgs(env, args); checker = new Checker(env); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/Env.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/Env.java index 01a0a8676732f1403256569254722eac3e30e2a1..be13ca43fd1c0d9fe0cf7ab473fd5eb7a475e612 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/Env.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/Env.java @@ -108,6 +108,20 @@ public class Env { Set includePackages; Set excludePackages; + /** + * How to handle bad references. + * + * If {@code false}, a reference into a module that is not + * in the module graph will just be reported as a warning. + * All other bad references will be reported as errors. + * This is the desired behavior for javac. + * + * If {@code true}, all bad references will be reported as + * errors. This is the desired behavior for javadoc. + * + */ + boolean strictReferenceChecks = false; + // Utility classes DocTrees trees; Elements elements; diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/resources/doclint.properties b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/resources/doclint.properties index 091316f0e29d075bbdb1c36dd83261105ade4bfe..fbcb2c0088149a0b9395daa55c67d8f4e8c697a6 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/resources/doclint.properties +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/resources/doclint.properties @@ -61,6 +61,7 @@ dc.no.alt.attr.for.image = no "alt" attribute for image dc.no.summary.or.caption.for.table=no caption for table dc.param.name.not.found = @param name not found dc.ref.not.found = reference not found +dc.ref.in.missing.module = module for reference not found: {0} dc.return.not.first = '{@return} not at beginning of description dc.service.not.found = service-type not found dc.tag.code.within.code = '{@code} within diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/package-info.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/package-info.java index 473e44ff4214a07f59007c58270638c68dedf5eb..4d7da0ba7cded3b005c9abce0ca1f993d34447bf 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/package-info.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -24,21 +24,146 @@ */ /** - * The implementation of the javadoc tool, and associated doclets. + * The implementation of the javadoc tool and associated doclets. * - *

          Internally, javadoc is composed of two primary parts: + *

          Internally, javadoc is composed of two primary parts: * the {@link jdk.javadoc.internal.tool tool}, and a series of * {@link jdk.javadoc.internal.doclets doclets}. * - * The tool provides a common infrastructure for command-line processing, - * and for reading the documentation comments in Java source files, + *

          The tool provides a common infrastructure for command-line processing, + * and for reading the declarations and documentation comments in Java source files, * while doclets provide a user-selectable backend for determining - * how to process the documentation comments. + * how to process the declarations and their documentation comments. + * + *

          The following provides a top-down description of the overall javadoc + * software stack. + * + *

          + *
          Doclets + *
          + *
          + *
          The Standard Doclet + *

          + * The {@link jdk.javadoc.doclet.StandardDoclet} is a thin public wrapper + * around the internal HTML doclet. + * + *

          The HTML Doclet + *

          + * The {@link jdk.javadoc.internal.doclets.formats.html.HtmlDoclet} class + * and other classes in the + * {@link jdk.javadoc.internal.doclets.formats.html formats.html} package + * customize the abstract pages generated by the toolkit layer to generate + * HTML pages. Some pages are specific to the HTML output format, + * and do not have an abstract builder in the toolkit layer. + * + *

          Individual pages of output are generated by page-specific subtypes of + * {@link jdk.javadoc.internal.doclets.formats.html.HtmlDocletWriter}. + * + *

          The {@link jdk.javadoc.internal.doclets.formats.html.HtmlConfiguration} class + * provides configuration information that is relevant to all the generated pages. + * The class extends the {@link jdk.javadoc.internal.doclets.toolkit.BaseConfiguration} + * class provided by the toolkit layer. + * + *

          The classes in the {@code formats.html} package use an internal + * library in the + * {@link jdk.javadoc.internal.doclets.formats.html.markup formats.html.markup} package, + * to create trees (or acyclic graphs) of + * {@linkplain jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree HTML tree nodes}. + * Apart from using a common format-neutral supertype, + * {@link jdk.javadoc.internal.doclets.toolkit.Content}, the {@code markup} library + * is mostly independent of the rest of the javadoc software stack. + * + *

          Toolkit + *

          + * The {@link jdk.javadoc.internal.doclets.toolkit toolkit} package provides + * support for a format-neutral + * {@linkplain jdk.javadoc.internal.doclets.toolkit.AbstractDoclet abstract doclet}, + * which uses + * {@linkplain jdk.javadoc.internal.doclets.toolkit.builders.AbstractBuilder builders} + * to generate pages of abstract + * {@linkplain jdk.javadoc.internal.doclets.toolkit.Content content}. + * + *

          The format-specific content for each page is provided by implementations + * of various writer interfaces, created by a format-specific + * {@linkplain jdk.javadoc.internal.doclets.toolkit.WriterFactory writer factory}. + * + *

          The {@link jdk.javadoc.internal.doclets.toolkit.BaseConfiguration} provides + * configuration information that is relevant to all the generated pages. + * Some of the information is provided by abstract methods which are implemented + * in format-specific subtypes of the class. + * + *

          The toolkit layer also provides + * {@linkplain jdk.javadoc.internal.doclets.toolkit.util utility classes} + * used by this layer and by format-specific layers. + * + *

          Generally, it is intended that doclets should use the + * {@link javax.lang.model Language Model API} to navigate the structure of a Java program, + * without needing to access any internal details of the underlying javac implementation. + * However, there are still some shortcomings of the Language Model API, + * and so it is still necessary to provide limited access to some of those internal details. + * Although not enforceable by the module system, by design the access to javac + * internal details by doclets based on {@code AbstractDoclet} is restricted to the aptly-named + * {@link jdk.javadoc.internal.doclets.toolkit.WorkArounds} class. + * + *

          Other Doclets + *

          + * Doclets are obviously not required to use + * {@link jdk.javadoc.internal.doclets.toolkit.AbstractDoclet} and other classes in + * the toolkit layer. In times past, it was common to write doclets to analyze + * code using the then-current API as an early version of a Java language model. + * That old API has been replaced by the {@link javax.lang.model Language Model API}, + * and tools that wish to use that API to analyze Java programs have a choice of + * how to invoke it, using the javac support for + * {@linkplain javax.annotation.processing annotation processing}, + * or {@linkplain com.sun.source.util.Plugin plugins}, as well as doclets. + * Which is best for any application will depend of the circumstances, but + * if a tool does not need access to the documentation comments in a program, + * it is possible that one of the other invocation mechanisms will be more convenient. + * + *

          + * + *
          The Doclet Interface + *

          + * The {@linkplain jdk.javadoc.doclet Doclet API} is the interface layer between + * the javadoc tool and the code to process the elements specified to the tool. + * + *

          Above this layer, in any doclet, the code is expected to use the + * {@linkplain javax.lang.model Language Model API} to navigate around the specified + * elements, and/or the {@linkplain com.sun.source.doctree DocTree API} to examine + * the corresponding documentation comments. + * + *

          The javadoc Tool + *

          + * After reading the command-line options, the tool uses a modified javac + * front end to read the necessary files and thus instantiate the + * {@linkplain javax.lang.model.element.Element elements} to be made available to + * the doclet that will be used to process them. + * + * The tool uses an internal feature of the javac architecture, which + * allows various components to be replaced by subtypes with modified behavior. + * This is done by pre-registering the desired components in the javac + * {@code Context}. + * The tool uses this mechanism to do the following: + *

            + *
          • although source files are parsed in their entirety, the + * content of method bodies is quickly discarded as unnecessary; + *
          • the class reader is updated to handle {@code package.html} + * files in any package directories that are read; and + *
          • the compilation pipeline for each source file is terminated + * after the parse and enter phases, meaning that + * the files are processed enough to instantiate the elements to + * be made available to the doclet, but no more. + *
          + *
          * * *
          +
          %s
          +

          This is NOT part of any supported API. * If you write code that depends on this, you do so at your own risk. * This code and its internal interfaces are subject to change or * deletion without notice. + * + * @see JavaDoc Architecture + * @see Using the new Doclet API + * @see Processing Code */ -package jdk.javadoc.internal; +package jdk.javadoc.internal; \ No newline at end of file diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/ElementsTable.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/ElementsTable.java index 20362f6a09d099b39f3708ff551e170e0e4541ce..e92176cbd8573abce616ecbd49936741c739173a 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/ElementsTable.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/ElementsTable.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -793,7 +793,7 @@ public class ElementsTable { Collection collection, boolean recurse) throws ToolException { for (ModulePackage modpkg : collection) { - toolEnv.notice("main.Loading_source_files_for_package", modpkg.toString()); + toolEnv.printInfo("main.Loading_source_files_for_package", modpkg.toString()); List files = getFiles(modpkg, recurse); if (files.isEmpty()) { String text = log.getText("main.no_source_files_for_package", diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/JavadocLog.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/JavadocLog.java index 8409169968b0f6dc5636a43f9741509c88bc816d..04f24fcde9cb35c9a861a4144c8648c5804588ee 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/JavadocLog.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/JavadocLog.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -292,12 +292,6 @@ public class JavadocLog extends Log implements Reporter { report(dt, flags, ds, dp, message); } - private int getSourcePos(DocTreePath path, int offset) { - DCTree.DCDocComment docComment = (DCTree.DCDocComment) path.getDocComment(); - DCTree tree = (DCTree) path.getLeaf(); - return docComment.getSourcePosition(tree.getStartPosition() + offset); - } - @Override // Reporter public void print(Kind kind, Element element, String message) { DiagnosticType dt = getDiagnosticType(kind); @@ -450,22 +444,27 @@ public class JavadocLog extends Log implements Reporter { } /** - * Prints a "notice" message to the standard writer. + * Prints a "notice" message. * - * @param key the resource key for the message - * @param args the arguments for the message + * @param message the message */ - public void noticeUsingKey(String key, Object... args) { - printRawLines(getStandardWriter(), getText(key, args)); + public void printNote(String message) { + // Ideally, for consistency with errors and warnings, we would use the following: + // report(Kind.NOTE, null, null, message); + // but the default formatting in Log for Kind.NOTE is to prefix the line with "Note:" + // which is undesirable and inconsistent with existing javadoc output. + // For now, to avoid the prefix, we write directly to the underlying stream. + printRawLines(WriterKind.NOTICE, message); } /** - * Prints a "notice" message to the standard writer. + * Prints a "notice" message. * - * @param message the message + * @param key the resource key for the message + * @param args the arguments for the message */ - public void notice(String message) { - printRawLines(getStandardWriter(), message); + public void printNoteUsingKey(String key, Object... args) { + printNote(getText(key, args)); } /** diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/JavadocTool.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/JavadocTool.java index 16f9ce2ca68c81261ec44c5a1828efdc9e3d68ca..94d3d21413172b138f9d7079b9f964a5b796be49 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/JavadocTool.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/JavadocTool.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -207,7 +207,7 @@ public class JavadocTool extends com.sun.tools.javac.main.JavaCompiler { } // Enter symbols for all files - toolEnv.notice("main.Building_tree"); + toolEnv.printInfo("main.Building_tree"); javadocEnter.main(allTrees.toList()); if (log.hasErrors()) { @@ -284,7 +284,7 @@ public class JavadocTool extends com.sun.tools.javac.main.JavaCompiler { for (JavaFileObject fo: files) { if (uniquefiles.add(fo)) { // ignore duplicates if (trace) - toolEnv.notice("main.Loading_source_file", fo.getName()); + toolEnv.printInfo("main.Loading_source_file", fo.getName()); trees.append(parse(fo)); } } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/Main.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/Main.java index 467c28adba1e466ca988e6adc3575224b98690cf..cb12e6e25e6c9dd22d6669a1b80c1ee6698c64f7 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/Main.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/Main.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -24,7 +24,12 @@ */ package jdk.javadoc.internal.tool; +import javax.tools.JavaFileManager; +import javax.tools.StandardJavaFileManager; import java.io.PrintWriter; +import java.util.Objects; + +import com.sun.tools.javac.util.Context; /** * Provides external entry points (tool and programmatic) for the javadoc program. @@ -37,11 +42,6 @@ import java.io.PrintWriter; public class Main { - /** - * This constructor should never be called. - */ - private Main() { throw new AssertionError(); } - /** * The main entry point called by the launcher. This will call * System.exit with an appropriate return value. @@ -88,6 +88,65 @@ public class Main { return jdoc.begin(args).exitCode; } + + // builder-style API to run javadoc + + private PrintWriter outWriter; + private PrintWriter errWriter; + private StandardJavaFileManager fileManager; + + /** + * Creates a default builder to run javadoc. + */ + public Main() { } + + /** + * Sets the output and error streams to be used when running javadoc. + * The streams may be the same; they must not be {@code null}. + * + * @param outWriter the output stream + * @param errWriter the error stream + * + * @return this object + */ + public Main setStreams(PrintWriter outWriter, PrintWriter errWriter) { + this.outWriter = Objects.requireNonNull(outWriter); + this.errWriter = Objects.requireNonNull(errWriter); + return this; + } + + /** + * Sets the file manager to be used when running javadoc. + * A value of {@code null} means to use the default file manager. + * + * @param fileManager the file manager to use + * + * @return this object + */ + public Main setFileManager(StandardJavaFileManager fileManager) { + this.fileManager = fileManager; + return this; + } + + /** + * Runs javadoc with preconfigured values and a given set of arguments. + * Any errors will be reported to the error stream, or to {@link System#err} + * if no error stream has been specified with {@code setStreams}. + * + * @param args the arguments + * + * @return a value indicating the success or otherwise of the run + */ + public Result run(String... args) { + Context context = null; + if (fileManager != null) { + context = new Context(); + context.put(JavaFileManager.class, fileManager); + } + Start jdoc = new Start(context, null, outWriter, errWriter, null, null); + return jdoc.begin(args); + } + public enum Result { /** completed with no errors */ OK(0), diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/Start.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/Start.java index 307c5d6517ef40a14cba5115263a0f72ea558a1a..4d25ac5f22adc892c7eeb06b8b01662593e71337 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/Start.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/Start.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -36,6 +36,7 @@ import java.util.Comparator; import java.util.IllformedLocaleException; import java.util.List; import java.util.Locale; +import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.function.Supplier; @@ -195,7 +196,7 @@ public class Start { } private void showUsage(String headerKey, ToolOption.Kind kind, String footerKey) { - log.noticeUsingKey(headerKey); + showLinesUsingKey(headerKey); showToolOptions(kind); // let doclet print usage information @@ -204,12 +205,13 @@ public class Start { ? Option.Kind.EXTENDED : Option.Kind.STANDARD); } - if (footerKey != null) - log.noticeUsingKey(footerKey); + if (footerKey != null) { + showLinesUsingKey(footerKey); + } } private void showVersion(String labelKey, String value) { - log.noticeUsingKey(labelKey, log.programName, value); + showLinesUsingKey(labelKey, log.programName, value); } private void showToolOptions(ToolOption.Kind kind) { @@ -252,7 +254,7 @@ public class Start { if (options.isEmpty()) { return; } - log.noticeUsingKey("main.doclet.usage.header", name); + showLinesUsingKey("main.doclet.usage.header", name); Comparator comp = new Comparator() { final Collator collator = Collator.getInstance(Locale.US); @@ -307,22 +309,30 @@ public class Start { if (synopses.length() < DEFAULT_SYNOPSIS_WIDTH && !description.contains("\n") && (SMALL_INDENT.length() + DEFAULT_SYNOPSIS_WIDTH + 1 + description.length() <= DEFAULT_MAX_LINE_LENGTH)) { - log.notice(String.format(COMPACT_FORMAT, synopses, description)); + showLines(String.format(COMPACT_FORMAT, synopses, description)); return; } // If option synopses fit on a single line of reasonable length, show that; // otherwise, show 1 per line if (synopses.length() <= DEFAULT_MAX_LINE_LENGTH) { - log.notice(SMALL_INDENT + synopses); + showLines(SMALL_INDENT + synopses); } else { for (String name: names) { - log.notice(SMALL_INDENT + name + parameters); + showLines(SMALL_INDENT + name + parameters); } } // Finally, show the description - log.notice(LARGE_INDENT + description.replace("\n", "\n" + LARGE_INDENT)); + showLines(LARGE_INDENT + description.replace("\n", "\n" + LARGE_INDENT)); + } + + private void showLinesUsingKey(String key, Object... args) { + showLines(log.getText(key, args)); + } + + private void showLines(String message) { + log.printRawLines(Log.WriterKind.STDOUT, message); } @@ -520,7 +530,21 @@ public class Start { } if (fileManager instanceof BaseFileManager bfm) { + // standard file manager: use direct support for handling options bfm.handleOptions(options.fileManagerOptions()); + } else { + // unrecognized file manager: + for (Map.Entry e: options.fileManagerOptions().entrySet()) { + String optName = e.getKey().getPrimaryName(); + String optValue = e.getValue(); + try { + if (!fileManager.handleOption(optName, List.of(optValue).iterator())) { + log.error("main.unknown.option.for.filemanager", optName); + } + } catch (IllegalArgumentException ex) { + log.error("main.bad.arg.for.filemanager.option", optName, ex.getMessage()); + } + } } String mr = com.sun.tools.javac.main.Option.MULTIRELEASE.primaryName; diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/ToolEnvironment.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/ToolEnvironment.java index ef6f1b74940ff4ef79d24f4c85d9aa366872c3fb..b42245da5a973be96b679f20b2c19d807a2718cc 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/ToolEnvironment.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/ToolEnvironment.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -191,28 +191,14 @@ public class ToolEnvironment { } /** - * Print a notice, iff quiet is not specified. + * Prints a notice unless {@code -quiet} was specified. * * @param key selects message from resource */ - public void notice(String key) { - if (quiet) { - return; + public void printInfo(String key, Object... args) { + if (!quiet) { + log.printNoteUsingKey(key, args); } - JavadocLog.printRawLines(log.getDiagnosticWriter(), log.getText(key)); - } - - /** - * Print a notice, iff quiet is not specified. - * - * @param key selects message from resource - * @param a1 first argument - */ - public void notice(String key, String a1) { - if (quiet) { - return; - } - JavadocLog.printRawLines(log.getDiagnosticWriter(), log.getText(key, a1)); } TreePath getTreePath(JCCompilationUnit tree) { @@ -247,8 +233,4 @@ public class ToolEnvironment { public Env getEnv(ClassSymbol tsym) { return enter.getEnv(tsym); } - - public boolean isQuiet() { - return quiet; - } } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/resources/javadoc.properties b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/resources/javadoc.properties index 8b46fcf88925cbc4927d231309da8fb64935d452..77e73e19955a875509866880838fb790c9843d16 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/resources/javadoc.properties +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/resources/javadoc.properties @@ -302,6 +302,8 @@ main.warnings.Werror=warnings found and -Werror specified main.unknown.error=an unknown error has occurred main.internal.error=an internal error has occurred main.unexpected.exception=an unexpected exception was caught: {0} +main.unknown.option.for.filemanager=option not supported by file manager: {0} +main.bad.arg.for.filemanager.option=bad value for file manager option {0}: "{1}" doclet.internal.report.bug=\ Please file a bug against the javadoc tool via the Java bug reporting page\n\ (http://bugreport.java.com) after checking the Bug Database (http://bugs.java.com)\n\ diff --git a/src/jdk.javadoc/share/classes/module-info.java b/src/jdk.javadoc/share/classes/module-info.java index cd15f00994b0e02f355bae90454c2cff6f694c48..b666517e3f09c06a8889883a8e724f8c5d0daa44 100644 --- a/src/jdk.javadoc/share/classes/module-info.java +++ b/src/jdk.javadoc/share/classes/module-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -45,6 +45,9 @@ * @toolGuide javadoc * * @provides java.util.spi.ToolProvider + * Use {@link java.util.spi.ToolProvider#findFirst ToolProvider.findFirst("javadoc")} + * to obtain an instance of a {@code ToolProvider} that provides the equivalent + * of command-line access to the {@code javadoc} tool. * @provides javax.tools.DocumentationTool * @provides javax.tools.Tool * diff --git a/src/jdk.javadoc/share/legal/jquery.md b/src/jdk.javadoc/share/legal/jquery.md index 8054a34c8305c2a49f8eee5c34406521becdaa2b..f7b72e3fbeccff958a8e6eae219761d258043045 100644 --- a/src/jdk.javadoc/share/legal/jquery.md +++ b/src/jdk.javadoc/share/legal/jquery.md @@ -1,9 +1,9 @@ -## jQuery v3.5.1 +## jQuery v3.6.0 ### jQuery License ``` -jQuery v 3.5.1 -Copyright JS Foundation and other contributors, https://js.foundation/ +jQuery v 3.6.0 +Copyright OpenJS Foundation and other contributors, https://openjsf.org/ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the @@ -26,7 +26,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ****************************************** -The jQuery JavaScript Library v3.5.1 also includes Sizzle.js +The jQuery JavaScript Library v3.6.0 also includes Sizzle.js Sizzle.js includes the following license: diff --git a/src/jdk.javadoc/share/man/javadoc.1 b/src/jdk.javadoc/share/man/javadoc.1 index c052a4ca136f62e53b839b89cf8fd66def28a942..4f64deb532fa18c518da06803821b68436edf798 100644 --- a/src/jdk.javadoc/share/man/javadoc.1 +++ b/src/jdk.javadoc/share/man/javadoc.1 @@ -1,4 +1,4 @@ -.\" Copyright (c) 1994, 2020, Oracle and/or its affiliates. All rights reserved. +.\" Copyright (c) 1994, 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 @@ -21,7 +21,7 @@ .\" .\" Automatically generated by Pandoc 2.3.1 .\" -.TH "JAVADOC" "1" "2021" "JDK 18\-ea" "JDK Commands" +.TH "JAVADOC" "1" "2022" "JDK 19\-ea" "JDK Commands" .hy .SH NAME .PP @@ -34,9 +34,9 @@ files .TP .B \f[I]options\f[R] Specifies command\-line options, separated by spaces. -See \f[B]Options for javadoc\f[R], \f[B]Extended Options\f[R], -\f[B]Standard doclet Options\f[R], and \f[B]Additional Options Provided -by the Standard doclet\f[R]. +See \f[B]Standard \f[BC]javadoc\f[B] Options\f[R], \f[B]Extra +\f[BC]javadoc\f[B] Options\f[R], \f[B]Standard Options for the Standard +Doclet\f[R], and \f[B]Extra Options for the Standard Doclet\f[R]. .RS .RE .TP @@ -88,19 +88,15 @@ option either to recursively traverse a directory and its subdirectories, or to pass in an explicit list of package names. When you document individual source files, pass in a list of Java source file names. -See \f[B]javadoc Overview\f[R] -[https://www.oracle.com/pls/topic/lookup?ctx=en/java/javase/13/tools&id=JSJAV\-GUID\-7A344353\-3BBF\-45C4\-8B28\-15025DDCC643] -in Java Platform, Standard Edition Javadoc Guide for information about -using the \f[CB]javadoc\f[R] tool. -.SH CONFORMANCE +.SS Conformance .PP -The standard doclet does not validate the content of documentation +The Standard Doclet does not validate the content of documentation comments for conformance, nor does it attempt to correct any errors in documentation comments. Anyone running javadoc is advised to be aware of the problems that may arise when generating non\-conformant output or output containing executable content, such as JavaScript. -The standard doclet does provide the \f[CB]doclint\f[R] feature to help +The Standard Doclet does provide the \f[B]DocLint\f[R] feature to help developers detect common problems in documentation comments; but it is also recommended to check the generated output with any appropriate conformance and other checking tools. @@ -112,7 +108,16 @@ in the HTML5 Specification. For more details on security issues related to web pages, see the \f[B]Open Web Application Security Project (OWASP)\f[R] [https://www.owasp.org] page. -.SH OPTIONS FOR JAVADOC +.SH OPTIONS +.PP +\f[CB]javadoc\f[R] supports command\-line options for both the main +\f[CB]javadoc\f[R] tool and the currently selected doclet. +The Standard Doclet is used if no other doclet is specified. +.PP +GNU\-style options (that is, those beginning with \f[CB]\-\-\f[R]) can use +an equal sign (\f[CB]=\f[R]) instead of whitespace characters to separate +the name of an option from its value. +.SS Standard \f[CB]javadoc\f[R] Options .PP The following core \f[CB]javadoc\f[R] options are equivalent to corresponding \f[CB]javac\f[R] options. @@ -151,12 +156,6 @@ descriptions of using these options: .PP The following options are the core \f[CB]javadoc\f[R] options that are not equivalent to a corresponding \f[CB]javac\f[R] option: -.PP -\f[B]Note:\f[R] -.PP -In tools that support \f[CB]\-\-\f[R] style options, the GNU\-style -options can use the equal sign (=) instead of a white space to separate -the name of an option from its value. .TP .B \f[CB]\-breakiterator\f[R] Computes the first sentence with \f[CB]BreakIterator\f[R]. @@ -222,20 +221,24 @@ exclude packages rooted at \f[CB]java.net\f[R] and \f[CB]java.lang\f[R]. Notice that these examples exclude \f[CB]java.lang.ref\f[R], which is a subpackage of \f[CB]java.lang\f[R]. .IP \[bu] 2 -\f[B]Linux and OS X:\f[R] +\f[B]Linux and macOS:\f[R] .RS 2 -.RS -.PP -\f[CB]javadoc\ \-sourcepath\ /home/user/src\ \-subpackages\ java\ \-exclude\ java.net:java.lang\f[R] -.RE +.IP +.nf +\f[CB] +javadoc\ \-sourcepath\ /home/user/src\ \-subpackages\ java\ \-exclude\ java.net:java.lang +\f[R] +.fi .RE .IP \[bu] 2 \f[B]Windows:\f[R] .RS 2 -.RS -.PP -\f[CB]javadoc\ \-sourcepath\ \\user\\src\ \-subpackages\ java\ \-exclude\ java.net:java.lang\f[R] -.RE +.IP +.nf +\f[CB] +javadoc\ \-sourcepath\ \\user\\src\ \-subpackages\ java\ \-exclude\ java.net:java.lang +\f[R] +.fi .RE .RE .TP @@ -283,9 +286,9 @@ used to run the \f[CB]javadoc\f[R] tool. .nf \f[CB] javadoc\ \-J\-version -java\ version\ "10\-ea"\ 2018\-03\-20 -Java(TM)\ SE\ Runtime\ Environment\ 18.3\ (build\ 10\-ea+36) -Java\ HotSpot(TM)\ 64\-Bit\ Server\ VM\ 18.3\ (build\ 10\-ea+36,\ mixed\ mode) +java\ version\ "17"\ 2021\-09\-14\ LTS +Java(TM)\ SE\ Runtime\ Environment\ (build\ 17+35\-LTS\-2724) +Java\ HotSpot(TM)\ 64\-Bit\ Server\ VM\ (build\ 17+35\-LTS\-2724,\ mixed\ mode,\ sharing) \f[R] .fi .RE @@ -298,13 +301,6 @@ The argument is the name of the locale, as described in (English, United States) or \f[CB]en_US_WIN\f[R] (Windows variant). .RS .PP -\f[B]Note:\f[R] -.PP -The \f[CB]\-locale\f[R] option must be placed ahead (to the left) of any -options provided by the standard doclet or any other doclet. -Otherwise, the navigation bars appear in English. -This is the only command\-line option that depends on order. -.PP Specifying a locale causes the \f[CB]javadoc\f[R] tool to choose the resource files of that locale for messages such as strings in the navigation bar, headings for lists and tables, help file contents, @@ -349,13 +345,14 @@ Specifies which members (fields or methods) are documented, where \f[I]value\f[R] can be any of the following: .RS .IP \[bu] 2 -\f[CB]protected\f[R]: The default value is protected. +\f[CB]public\f[R] \-\-\- shows only public members .IP \[bu] 2 -\f[CB]public\f[R]: Shows only public values. +\f[CB]protected\f[R] \-\-\- shows public and protected members; this is +the default .IP \[bu] 2 -\f[CB]package\f[R]: Shows public, protected, and package members. +\f[CB]package\f[R] \-\-\- shows public, protected, and package members .IP \[bu] 2 -\f[CB]private\f[R]: Shows all members. +\f[CB]private\f[R] \-\-\- shows all members .RE .TP .B \f[CB]\-\-show\-module\-contents\f[R] \f[I]value\f[R] @@ -375,14 +372,14 @@ Specifies which types (classes, interfaces, etc.) are documented, where \f[I]value\f[R] can be any of the following: .RS .IP \[bu] 2 -\f[CB]protected\f[R]: The default value. -Shows public and protected types. +\f[CB]public\f[R] \-\-\- shows only public types .IP \[bu] 2 -\f[CB]public\f[R]: Shows only public values. +\f[CB]protected\f[R] \-\-\- shows public and protected types; this is the +default .IP \[bu] 2 -\f[CB]package\f[R]: Shows public, protected, and package types. +\f[CB]package\f[R] \-\-\- shows public, protected, and package types .IP \[bu] 2 -\f[CB]private\f[R]: Shows all types. +\f[CB]private\f[R] \-\-\- shows all types .RE .TP .B \f[CB]\-subpackages\f[R] \f[I]subpkglist\f[R] @@ -404,20 +401,24 @@ For example, the following commands generates documentation for packages named \f[CB]java\f[R] and \f[CB]javax.swing\f[R] and all of their subpackages. .IP \[bu] 2 -\f[B]Linux and OS X:\f[R] +\f[B]Linux and macOS:\f[R] .RS 2 -.RS -.PP -\f[CB]javadoc\ \-d\ docs\ \-sourcepath\ /home/user/src\ \-subpackages\ java:javax.swing\f[R] -.RE +.IP +.nf +\f[CB] +javadoc\ \-d\ docs\ \-sourcepath\ /home/user/src\ \-subpackages\ java:javax.swing +\f[R] +.fi .RE .IP \[bu] 2 \f[B]Windows:\f[R] .RS 2 -.RS -.PP -\f[CB]javadoc\ \-d\ docs\ \-sourcepath\ \\user\\src\ \-subpackages\ java:javax.swing\f[R] -.RE +.IP +.nf +\f[CB] +javadoc\ \-d\ docs\ \-sourcepath\ \\user\\src\ \-subpackages\ java:javax.swing +\f[R] +.fi .RE .RE .TP @@ -440,14 +441,12 @@ Prints version information. Reports an error if any warnings occur. .RS .RE -.SH EXTENDED OPTIONS -.PP -\f[B]Note:\f[R] +.SS Extra \f[CB]javadoc\f[R] Options .PP -The extended options for \f[CB]javadoc\f[R] are subject to change without -notice. +\f[I]Note:\f[R] The additional options for \f[CB]javadoc\f[R] are subject +to change without notice. .PP -The following extended \f[CB]javadoc\f[R] options are equivalent to +The following additional \f[CB]javadoc\f[R] options are equivalent to corresponding \f[CB]javac\f[R] options. See \f[I]Extra Options\f[R] in \f[B]javac\f[R] for the detailed descriptions of using these options: @@ -461,25 +460,42 @@ descriptions of using these options: \f[CB]\-Xmaxerrs\f[R] .IP \[bu] 2 \f[CB]\-Xmaxwarns\f[R] -.SH STANDARD DOCLET OPTIONS +.SS Standard Options for the Standard Doclet .PP The following options are provided by the standard doclet. .TP -.B \f[CB]\-\-add\-stylesheet\f[R] \f[I]file\f[R] -Adds additional stylesheet file for the generated documentation. -This option can be used one or more times to specify additional -stylesheets included in the documentation. +.B \f[CB]\-\-add\-script\f[R] \f[I]file\f[R] +Adds \f[I]file\f[R] as an additional JavaScript file to the generated +documentation. +This option can be used one or more times to specify additional script +files. .RS .PP Command\-line example: .RS .PP -\f[CB]javadoc\ \-\-add\-stylesheet\ new_stylesheet_1.css\ \-\-add\-stylesheet\ new_stylesheet_2.css\ pkg_foo\f[R] +\f[CB]javadoc\ \-\-add\-script\ first_script.js\ \-\-add\-script\ second_script.js\ pkg_foo\f[R] .RE .RE .TP +.B \f[CB]\-\-add\-stylesheet\f[R] \f[I]file\f[R] +Adds \f[I]file\f[R] as an additional stylesheet file to the generated +documentation. +This option can be used one or more times to specify additional +stylesheets included in the documentation. +.RS +.PP +Command\-line example: +.IP +.nf +\f[CB] +javadoc\ \-\-add\-stylesheet\ new_stylesheet_1.css\ \-\-add\-stylesheet\ new_stylesheet_2.css\ pkg_foo +\f[R] +.fi +.RE +.TP .B \f[CB]\-\-allow\-script\-in\-comments\f[R] -Allow JavaScript in options and comments +Allow JavaScript in options and comments. .RS .RE .TP @@ -506,19 +522,23 @@ Registry, Character Sets\f[R] .RS .PP For example: -.RS -.PP -\f[CB]javadoc\ \-charset\ "iso\-8859\-1"\ mypackage\f[R] -.RE +.IP +.nf +\f[CB] +javadoc\ \-charset\ "iso\-8859\-1"\ mypackage +\f[R] +.fi .PP This command inserts the following line in the head of every generated page: -.RS -.PP -\f[CB]\f[R] -.RE +.IP +.nf +\f[CB] + +\f[R] +.fi .PP -The \f[CB]META\f[R] tag is described in the \f[B]HTML standard (4197265 +The \f[CB]meta\f[R] tag is described in the \f[B]HTML standard (4197265 and 4137321), HTML Document Representation\f[R] [http://www.w3.org/TR/REC\-html40/charset.html#h\-5.2.2]. .RE @@ -534,24 +554,28 @@ The destination directory is automatically created when the \f[CB]javadoc\f[R] tool runs. .RS .IP \[bu] 2 -\f[B]Linux and OS X:\f[R] For example, the following command generates +\f[B]Linux and macOS:\f[R] For example, the following command generates the documentation for the package \f[CB]com.mypackage\f[R] and saves the results in the \f[CB]/user/doc/\f[R] directory: .RS 2 -.RS -.PP -\f[CB]javadoc\ \-d\ /user/doc/\ com.mypackage\f[R] -.RE +.IP +.nf +\f[CB] +javadoc\ \-d\ /user/doc/\ com.mypackage +\f[R] +.fi .RE .IP \[bu] 2 \f[B]Windows:\f[R] For example, the following command generates the documentation for the package \f[CB]com.mypackage\f[R] and saves the results in the \f[CB]\\user\\doc\\\f[R] directory: .RS 2 -.RS -.PP -\f[CB]javadoc\ \-d\ \\user\\doc\\\ com.mypackage\f[R] -.RE +.IP +.nf +\f[CB] +javadoc\ \-d\ \\user\\doc\\\ com.mypackage +\f[R] +.fi .RE .RE .TP @@ -572,14 +596,15 @@ Of the three available options, at most, only the input and an output encoding option are used in a single encoding command. If you specify both input and output encoding options in a command, they must be the same value. -If you specify neither output option, it the tool defaults to the input -encoding. +If you specify neither output option, it defaults to the input encoding. .PP For example: -.RS -.PP -\f[CB]javadoc\ \-docencoding\ "iso\-8859\-1"\ mypackage\f[R] -.RE +.IP +.nf +\f[CB] +javadoc\ \-docencoding\ "iso\-8859\-1"\ mypackage +\f[R] +.fi .RE .TP .B \f[CB]\-docfilessubdirs\f[R] @@ -596,12 +621,12 @@ it does, you must enclose the title in quotation marks. Additional quotation marks within the \f[CB]title\f[R] tag must be escaped. For example, -\f[CB]javadoc\ \-doctitle\ "My\ Library
          v1.0"\ com.mypackage.\f[R] +\f[CB]javadoc\ \-doctitle\ "My\ Library
          v1.0"\ com.mypackage\f[R]. .RS .RE .TP .B \f[CB]\-excludedocfilessubdir\f[R] \f[I]name\f[R] -Excludes any doc files sub directories with the given name. +Excludes any doc files subdirectories with the given name. Enables deep copying of doc\-files directories. Subdirectories and all contents are recursively copied to the destination. @@ -635,7 +660,7 @@ The \f[CB]header\f[R] can contain HTML tags and white space, but when it does, the \f[CB]header\f[R] must be enclosed in quotation marks. Use escape characters for internal quotation marks within a header. For example, -\f[CB]javadoc\ \-header\ "My\ Library
          v1.0"\ com.mypackage.\f[R] +\f[CB]javadoc\ \-header\ "My\ Library
          v1.0"\ com.mypackage\f[R]. .RS .RE .TP @@ -653,20 +678,24 @@ accordingly. For example: .RS .IP \[bu] 2 -\f[B]Linux and OS X:\f[R] +\f[B]Linux and macOS:\f[R] .RS 2 -.RS -.PP -\f[CB]javadoc\ \-helpfile\ /home/user/myhelp.html\ java.awt.\f[R] -.RE +.IP +.nf +\f[CB] +javadoc\ \-helpfile\ /home/user/myhelp.html\ java.awt +\f[R] +.fi .RE .IP \[bu] 2 \f[B]Windows:\f[R] .RS 2 -.RS -.PP -\f[CB]javadoc\ \-helpfile\ C:\\user\\myhelp.html\ java.awt.\f[R] -.RE +.IP +.nf +\f[CB] +javadoc\ \-helpfile\ C:\\user\\myhelp.html\ java.awt +\f[R] +.fi .RE .RE .TP @@ -678,19 +707,21 @@ compatibility. .TP .B \f[CB]\-\-javafx\f[R] or \f[CB]\-javafx\f[R] Enables JavaFX functionality. +This option is enabled by default if the JavaFX library classes are +detected on the module path. .RS .RE .TP .B \f[CB]\-keywords\f[R] -Adds HTML keyword \f[CB]\f[R] tags to the generated file for each +Adds HTML keyword \f[CB]\f[R] tags to the generated file for each class. -These tags can help search engines that look for \f[CB]\f[R] tags +These tags can help search engines that look for \f[CB]\f[R] tags find the pages. Most search engines that search the entire Internet don\[aq]t look at -\f[CB]\f[R] tags, because pages can misuse them. +\f[CB]\f[R] tags, because pages can misuse them. Search engines offered by companies that confine their searches to their -own website can benefit by looking at \f[CB]\f[R] tags. -The \f[CB]\f[R] tags include the fully qualified name of the class +own website can benefit by looking at \f[CB]\f[R] tags. +The \f[CB]\f[R] tags include the fully qualified name of the class and the unqualified names of the fields and methods. Constructors aren\[aq]t included because they are identical to the class name. @@ -699,10 +730,10 @@ For example, the class \f[CB]String\f[R] starts with these keywords: .IP .nf \f[CB] - - - - + + + + \f[R] .fi .RE @@ -721,10 +752,8 @@ Either a \f[CB]package\-list\f[R] or an \f[CB]element\-list\f[R] file must be in this \f[I]url\f[R] directory (otherwise, use the \f[CB]\-linkoffline\f[R] option). .PP -\f[B]Note:\f[R] -.PP -The \f[CB]package\-list\f[R] and \f[CB]element\-list\f[R] files are -generated by the \f[CB]javadoc\f[R] tool when generating the API +\f[I]Note:\f[R] The \f[CB]package\-list\f[R] and \f[CB]element\-list\f[R] +files are generated by the \f[CB]javadoc\f[R] tool when generating the API documentation and should not be modified by the user. .PP When you use the \f[CB]javadoc\f[R] tool to document packages, it uses the @@ -769,6 +798,15 @@ Uniform Resource Locators\f[R] [http://www.ietf.org/rfc/rfc1738.txt]. .fi .RE .TP +.B \f[CB]\-\-link\-modularity\-mismatch\f[R] (\f[CB]warn\f[R]|\f[CB]info\f[R]) +Specifies whether external documentation with wrong modularity (e.g. +non\-modular documentation for a modular library, or the reverse case) +should be reported as a warning (\f[CB]warn\f[R]) or just a message +(\f[CB]info\f[R]). +The default behavior is to report a warning. +.RS +.RE +.TP .B \f[CB]\-linkoffline\f[R] \f[I]url1\f[R] \f[I]url2\f[R] This option is a variation of the \f[CB]\-link\f[R] option. They both create links to \f[CB]javadoc\f[R] generated documentation for @@ -788,10 +826,8 @@ the URL location, but does exist at a different location and can be specified by either the \f[CB]package\-list\f[R] or \f[CB]element\-list\f[R] file (typically local). .PP -\f[B]Note:\f[R] -.PP -The \f[CB]package\-list\f[R] and \f[CB]element\-list\f[R] files are -generated by the \f[CB]javadoc\f[R] tool when generating the API +\f[I]Note:\f[R] The \f[CB]package\-list\f[R] and \f[CB]element\-list\f[R] +files are generated by the \f[CB]javadoc\f[R] tool when generating the API documentation and should not be modified by the user. .PP If \f[I]url1\f[R] is accessible only on the World Wide Web, then the @@ -820,6 +856,38 @@ root of the packages being linked to. See \f[I]url\f[R] in the \f[CB]\-link\f[R] option. .RE .TP +.B \f[CB]\-\-link\-platform\-properties\f[R] \f[I]url\f[R] +Specifies a properties file used to configure links to platform +documentation. +.RS +.PP +The \f[I]url\f[R] argument is expected to point to a properties file +containing one or more entries with the following format, where +\f[CB]\f[R] is the platform version as passed to the +\f[CB]\-\-release\f[R] or \f[CB]\-\-source\f[R] option and \f[CB]\f[R] is +the base URL of the corresponding platform API documentation: +.IP +.nf +\f[CB] +doclet.platform.docs.= +\f[R] +.fi +.PP +For instance, a properties file containing URLs for releases 15 to 17 +might contain the following lines: +.IP +.nf +\f[CB] +doclet.platform.docs.15=https://example.com/api/15/ +doclet.platform.docs.16=https://example.com/api/16/ +doclet.platform.docs.17=https://example.com/api/17/ +\f[R] +.fi +.PP +If the properties file does not contain an entry for a particular +release no platform links are generated. +.RE +.TP .B \f[CB]\-linksource\f[R] Creates an HTML version of each source file (with line numbers) and adds links to them from the standard HTML documentation. @@ -840,17 +908,21 @@ classes or interfaces are accessible through links. Each link appears on the name of the identifier in its declaration. For example, the link to the source code of the \f[CB]Button\f[R] class would be on the word \f[CB]Button\f[R]: -.RS -.PP -\f[CB]public\ class\ Button\ extends\ Component\ implements\ Accessible\f[R] -.RE +.IP +.nf +\f[CB] +public\ class\ Button\ extends\ Component\ implements\ Accessible +\f[R] +.fi .PP The link to the source code of the \f[CB]getLabel\f[R] method in the \f[CB]Button\f[R] class is on the word \f[CB]getLabel\f[R]: -.RS -.PP -\f[CB]public\ String\ getLabel()\f[R] -.RE +.IP +.nf +\f[CB] +public\ String\ getLabel() +\f[R] +.fi .RE .TP .B \f[CB]\-\-main\-stylesheet\f[R] \f[I]file\f[R] or \f[CB]\-stylesheetfile\f[R] \f[I]file\f[R] @@ -865,10 +937,12 @@ The \f[CB]\-\-main\-stylesheet\f[R] option is the preferred form. .RS .PP Command\-line example: -.RS -.PP -\f[CB]javadoc\ \-\-main\-stylesheet\ main_stylesheet.css\ pkg_foo\f[R] -.RE +.IP +.nf +\f[CB] +javadoc\ \-\-main\-stylesheet\ main_stylesheet.css\ pkg_foo +\f[R] +.fi .RE .TP .B \f[CB]\-nocomment\f[R] @@ -901,15 +975,9 @@ you want to make the navigation bar cleaner. .RS .RE .TP -.B \f[CB]\-\-no\-frames\f[R] -This option is a no\-op and is just retained for backwards -compatibility. -.RS -.RE -.TP .B \f[CB]\-nohelp\f[R] -Omits the HELP link in the navigation bars at the top and bottom of each -page of output. +Omits the HELP link in the navigation bar at the top of each page of +output. .RS .RE .TP @@ -922,7 +990,7 @@ The index is produced by default. .B \f[CB]\-nonavbar\f[R] Prevents the generation of the navigation bar, header, and footer, that are usually found at the top and bottom of the generated pages. -The \f[CB]\-nonavbar\f[R] option has no affect on the \f[CB]\-bottom\f[R] +The \f[CB]\-nonavbar\f[R] option has no effect on the \f[CB]\-bottom\f[R] option. The \f[CB]\-nonavbar\f[R] option is useful when you are interested only in the content and have no need for navigation, such as when you are @@ -930,6 +998,12 @@ converting the files to PostScript or PDF for printing only. .RS .RE .TP +.B \f[CB]\-\-no\-platform\-links\f[R] +Prevents the generation of links to platform documentation. +These links are generated by default. +.RS +.RE +.TP .B \f[CB]\-noqualifier\f[R] \f[I]name1\f[R]\f[CB]:\f[R]\f[I]name2\f[R]... Excludes the list of qualifiers from the output. The package name is removed from places where class or interface names @@ -1000,14 +1074,14 @@ that contains the topmost package directories. In this location, no path is needed when documenting packages, because the \f[CB]\-sourcepath\f[R] option points to this file. .IP \[bu] 2 -\f[B]Linux and OS X:\f[R] For example, if the source tree for the -\f[CB]java.lang\f[R] package is \f[CB]/src/classes/java/lang/\f[R], then you -could place the overview file at /src/classes/overview.html. +\f[B]Linux and macOS:\f[R] For example, if the source tree for the +\f[CB]java.lang\f[R] package is \f[CB]src/classes/java/lang/\f[R], then you +could place the overview file at src/classes/overview.html. .IP \[bu] 2 \f[B]Windows:\f[R] For example, if the source tree for the -\f[CB]java.lang\f[R] package is \f[CB]\\src\\classes\\java\\lang\\\f[R], -then you could place the overview file at -\f[CB]\\src\\classes\\overview.html\f[R] +\f[CB]java.lang\f[R] package is \f[CB]src\\classes\\java\\lang\\\f[R], then +you could place the overview file at +\f[CB]src\\classes\\overview.html\f[R] .PP The overview page is created only when you pass two or more package names to the \f[CB]javadoc\f[R] tool. @@ -1022,6 +1096,43 @@ document default serializable fields and \f[CB]writeExternal\f[R] methods. .RS .RE .TP +.B \f[CB]\-\-since\f[R] \f[I]release\f[R](\f[CB],\f[R]\f[I]release\f[R])* +Generates documentation for APIs that were added or newly deprecated in +the specified \f[I]release\f[R]s. +.RS +.PP +If the \f[CB]\@since\f[R] tag in the \f[CB]javadoc\f[R] comment of an +element in the documented source code matches a \f[I]release\f[R] passed +as option argument, information about the element and the release it was +added in is included in a "New API" page. +.PP +If the "Deprecated API" page is generated and the \f[CB]since\f[R] element +of the \f[CB]java.lang.Deprecated\f[R] annotation of a documented element +matches a \f[I]release\f[R] in the option arguments, information about +the release the element was deprecated in is added to the "Deprecated +API" page. +.PP +Releases are compared using case\-sensitive string comparison. +.RE +.TP +.B \f[CB]\-\-since\-label\f[R] \f[I]text\f[R] +Specifies the \f[I]text\f[R] to use in the heading of the "New API" page. +This may contain information about the releases covered in the page, +e.g. +"New API in release 2.0", or "New API since release 1". +.RS +.RE +.TP +.B \f[CB]\-\-snippet\-path\f[R] \f[I]snippetpathlist\f[R] +Specifies the search paths for finding files for external snippets. +The \f[I]snippetpathlist\f[R] can contain multiple paths by separating +them with the platform path separator (\f[CB];\f[R] on Windows; \f[CB]:\f[R] +on other platforms.) The Standard Doclet first searches the +\f[CB]snippet\-files\f[R] subdirectory in the package containing the +snippet, and then searches all the directories in the given list. +.RS +.RE +.TP .B \f[CB]\-sourcetab\f[R] \f[I]tablength\f[R] Specifies the number of spaces each tab uses in the source. .RS @@ -1141,8 +1252,8 @@ Specifies the title to be placed in the HTML \f[CB]\f[R] tag. The text specified in the \f[CB]title\f[R] tag appears in the window title and in any browser bookmarks (favorite places) that someone creates for this page. -This title shouldn\[aq]t contain any HTML tags because the browser -doesn\[aq]t interpret them correctly. +This title should not contain any HTML tags because a browser will not +interpret them correctly. Use escape characters on any internal quotation marks within the \f[CB]title\f[R] tag. If the \f[CB]\-windowtitle\f[R] option is omitted, then the @@ -1152,131 +1263,276 @@ For example, \f[CB]javadoc\ \-windowtitle\ "My\ Library"\ com.mypackage\f[R]. .RS .RE -.SH ADDITIONAL OPTIONS PROVIDED BY THE STANDARD DOCLET +.SS Extra Options for the Standard Doclet .PP -The following are additional options provided by the standard doclet and +The following are additional options provided by the Standard Doclet and are subject to change without notice. Additional options are less commonly used or are otherwise regarded as advanced. .TP -.B \f[CB]\-Xdoclint\f[R] -Enables recommended checks for problems in documentation comments. +.B \f[CB]\-\-legal\-notices\f[R] (\f[CB]default\f[R]|\f[CB]none\f[R]|\f[I]directory\f[R]) +Specifies the location from which to copy legal files to the generated +documentation. +If the option is not specified or is used with the value +\f[CB]default\f[R], the files are copied from the default location. +If the argument is used with value \f[CB]none\f[R], no files are copied. +Every other argument is interpreted as directory from which to copy the +legal files. .RS .RE .TP -.B \f[CB]\-Xdoclint:\f[R](\f[CB]all\f[R]|\f[CB]none\f[R]|[\f[CB]\-\f[R]]\f[I]group\f[R]) -Enable or disable specific checks for bad references, accessibility -issues, missing documentation comments, errors in documentation comment -syntax and missing HTML tags. +.B \f[CB]\-\-no\-frames\f[R] +This option is a no\-op and is just retained for backwards +compatibility. +.RS +.RE +.TP +.B \f[CB]\-Xdoclint\f[R] +Enables recommended checks for problems in documentation comments. .RS -.PP -This option enables the \f[CB]javadoc\f[R] tool to check for all -documentation comments included in the generated output. -You can select which items to include in the generated output with the -standard options \f[CB]\-public\f[R], \f[CB]\-protected\f[R], -\f[CB]\-package\f[R] and \f[CB]\-private\f[R]. -.PP -When the \f[CB]\-Xdoclint\f[R] option is enabled, it reports issues with -messages similar to the \f[CB]javac\f[R] command. -The \f[CB]javadoc\f[R] tool prints a message, a copy of the source line, -and a caret pointing at the exact position where the error was detected. -Messages may be either warnings or errors, depending on their severity -and the likelihood to cause an error if the generated documentation were -to be run through a validator. -For example: missing documentation comments, duplicate information, and -extraneous comments do not cause the \f[CB]javadoc\f[R] tool to generate -invalid HTML, so these issues are reported as warnings; syntax errors, -missing required HTML end tags, and references to missing or misspelled -elements cause the \f[CB]javadoc\f[R] tool to generate invalid output, so -these issues are reported as errors. -.PP -\f[CB]\-Xdoclint\f[R] option validates input comments based upon the -requested markup. .PP By default, the \f[CB]\-Xdoclint\f[R] option is enabled. Disable it with the option \f[CB]\-Xdoclint:none\f[R]. .PP -The following options change what the \f[CB]\-Xdoclint\f[R] option -reports: -.IP \[bu] 2 -\f[CB]\-Xdoclint\ none\f[R]: Disables the \f[CB]\-Xdoclint\f[R] option -.IP \[bu] 2 -\f[CB]\-Xdoclint\f[R] \f[I]group\f[R]: Enables \f[I]group\f[R] checks -.IP \[bu] 2 -\f[CB]\-Xdoclint\ all\f[R]: Enables all groups of checks -.IP \[bu] 2 -\f[CB]\-Xdoclint\ all,\-\f[R]\f[I]group\f[R]: Enables all checks except -\f[I]group\f[R] checks -.PP -The \f[I]group\f[R] variable has one of the following values: -.IP \[bu] 2 -\f[CB]accessibility\f[R]: Checks for the issues to be detected by an -accessibility checker (for example, no caption or summary attributes -specified in a \f[CB]<table>\f[R] tag). -.IP \[bu] 2 -\f[CB]html\f[R]: Detects high\-level HTML issues, such as putting block -elements inside inline elements, or not closing elements that require an -end tag. -The rules are derived from the \f[B]HTML 4 Specification\f[R] -[https://www.w3.org/TR/html4/] or the \f[B]HTML 5 Specification\f[R] -[http://www.w3.org/TR/2014/REC\-html5\-20141028/] based on the standard -doclet \f[CB]html\f[R] output generation selected. -This type of check enables the \f[CB]javadoc\f[R] tool to detect HTML -issues that some browsers might not interpret as intended. -.IP \[bu] 2 -\f[CB]missing\f[R]: Checks for missing documentation comments or tags (for -example, a missing comment or class, or a missing \f[CB]\@return\f[R] tag -or similar tag on a method). -.IP \[bu] 2 -\f[CB]reference\f[R]: Checks for issues relating to the references to Java -API elements from documentation comment tags (for example, item not -found in \f[CB]\@see\f[R], or a bad name after \f[CB]\@param)\f[R]. -.IP \[bu] 2 -\f[CB]syntax\f[R]: Checks for low level issues like unescaped angle -brackets (\f[CB]<\f[R] and \f[CB]>\f[R]) and ampersands (\f[CB]&\f[R]) and -invalid documentation comment tags. -.PP -You can specify the \f[CB]\-Xdoclint\f[R] option multiple times to enable -the option to check errors and warnings in multiple categories. -Alternatively, you can specify multiple error and warning categories by -using the preceding options. -For example, use either of the following commands to check for the HTML, -syntax, and accessibility issues in the file \f[I]filename\f[R]. -.RS -.PP -\f[CB]javadoc\ \-Xdoclint:html\ \-Xdoclint:syntax\ \-Xdoclint:accessibility\f[R] -\f[I]filename\f[R] +For more details, see \f[B]DocLint\f[R]. .RE +.TP +.B \f[CB]\-Xdoclint:\f[R]\f[I]flag\f[R],\f[I]flag\f[R],... +Enable or disable specific checks for different kinds of issues in +documentation comments. .RS .PP -\f[CB]javadoc\ \-Xdoclint:html,syntax,accessibility\f[R] \f[I]filename\f[R] -.RE +Each \f[I]flag\f[R] can be one of \f[CB]all\f[R], \f[CB]none\f[R], or +\f[CB][\-]\f[R]\f[I]group\f[R] where \f[I]group\f[R] has one of the +following values: \f[CB]accessibility\f[R], \f[CB]html\f[R], +\f[CB]missing\f[R], \f[CB]reference\f[R], \f[CB]syntax\f[R]. +For more details on these values, see \f[B]DocLint Groups\f[R]. .PP -\f[B]Note:\f[R] +When specifying two or more flags, you can either use a single +\f[CB]\-Xdoclint:...\f[R] option, listing all the desired flags, or you +can use multiple options giving one or more flag in each option. +For example, use either of the following commands to check for the HTML, +syntax, and accessibility issues in the file \f[CB]MyFile.java\f[R]. +.IP +.nf +\f[CB] +javadoc\ \-Xdoclint:html\ \-Xdoclint:syntax\ \-Xdoclint:accessibility\ MyFile.java +javadoc\ \-Xdoclint:html,syntax,accessibility\ MyFile.java +\f[R] +.fi .PP -The \f[CB]javadoc\f[R] tool doesn\[aq]t guarantee the completeness of -these checks. -In particular, it isn\[aq]t a full HTML compliance checker. -The goal of the \-\f[CB]Xdoclint\f[R] option is to enable the -\f[CB]javadoc\f[R] tool to report majority of common errors. +The following examples illustrate how to change what DocLint reports: +.IP \[bu] 2 +\f[CB]\-Xdoclint:none\f[R] \-\-\- disables all checks +.IP \[bu] 2 +\f[CB]\-Xdoclint:\f[R]\f[I]group\f[R] \-\-\- enables \f[I]group\f[R] checks +.IP \[bu] 2 +\f[CB]\-Xdoclint:all\f[R] \-\-\- enables all groups of checks +.IP \[bu] 2 +\f[CB]\-Xdoclint:all,\-\f[R]\f[I]group\f[R] \-\-\- enables all checks +except \f[I]group\f[R] checks .PP -The \f[CB]javadoc\f[R] tool doesn\[aq]t attempt to fix invalid input, it -just reports it. +For more details, see \f[B]DocLint\f[R]. .RE .TP .B \f[CB]\-Xdoclint/package:\f[R][\f[CB]\-\f[R]]\f[I]packages\f[R] Enables or disables checks in specific packages. \f[I]packages\f[R] is a comma separated list of package specifiers. A package specifier is either a qualified name of a package or a package -name prefix followed by \f[CB]*\f[R], which expands to all sub packages of +name prefix followed by \f[CB]*\f[R], which expands to all subpackages of the given package. Prefix the package specifier with \f[CB]\-\f[R] to disable checks for the specified packages. .RS +.PP +For more details, see \f[B]DocLint\f[R]. .RE .TP .B \f[CB]\-Xdocrootparent\f[R] \f[I]url\f[R] -Replaces all \f[CB]\@docRoot\f[R] items followed by\f[CB]/..\f[R] in Javadoc -comments with the \f[I]url\f[R]. +Replaces all \f[CB]\@docRoot\f[R] items followed by \f[CB]/..\f[R] in +documentation comments with \f[I]url\f[R]. .RS .RE +.SH DOCLINT +.PP +DocLint provides the ability to check for possible problems in +documentation comments. +Problems may be reported as warnings or errors, depending on their +severity. +For example, a missing comment may be bad style that deserves a warning, +but a link to an unknown Java declaration is more serious and deserves +an error. +Problems are organized into \f[B]groups\f[R], and options can be used to +enable or disable messages in one or more groups. +Within the source code, messages in one or more groups can be +\f[B]suppressed\f[R] by using \f[CB]\@SuppressWarnings\f[R] annotations. +.PP +When invoked from \f[CB]javadoc\f[R], by default DocLint checks all +comments that are used in the generated documentation. +It thus relies on other command\-line options to determine which +declarations, and which corresponding documentation comments will be +included. +\f[I]Note:\f[R] this may mean that even comments on some private members +of serializable classes will also be checked, if the members need to be +documented in the generated \f[CB]Serialized\ Forms\f[R] page. +.PP +In contrast, when DocLint is invoked from \f[CB]javac\f[R], DocLint solely +relies on the various \f[CB]\-Xdoclint...\f[R] options to determine which +documentation comments to check. +.PP +DocLint doesn\[aq]t attempt to fix invalid input, it just reports it. +.PP +\f[I]Note:\f[R] DocLint doesn\[aq]t guarantee the completeness of these +checks. +In particular, it isn\[aq]t a full HTML compliance checker. +The goal is to just report common errors in a convenient manner. +.SS Groups +.PP +The checks performed by DocLint are organized into groups. +The warnings and errors in each group can be enabled or disabled with +command\-line options, or suppressed with \f[CB]\@SuppressWarnings\f[R] +annotations. +.PP +The groups are as follows: +.IP \[bu] 2 +\f[CB]accessibility\f[R] \-\-\- Checks for issues related to +accessibility. For example, no \f[CB]alt\f[R] attribute specified in an +\f[CB]<img>\f[R] element, or no caption or summary attributes specified in +a \f[CB]<table>\f[R] element. +.RS 2 +.PP +Issues are reported as errors if a downstream validation tool might be +expected to report an error in the files generated by \f[CB]javadoc\f[R]. +.PP +For reference, see the \f[B]Web Content Accessibility Guidelines\f[R] +[https://www.w3.org/WAI/standards\-guidelines/wcag/]. +.RE +.IP \[bu] 2 +\f[CB]html\f[R] \-\-\- Detects common high\-level HTML issues. For +example, putting block elements inside inline elements, or not closing +elements that require an end tag. +.RS 2 +.PP +Issues are reported as errors if a downstream validation tool might be +expected to report an error in the files generated by \f[CB]javadoc\f[R]. +.PP +For reference, see the \f[B]HTML Living Standard\f[R] +[https://html.spec.whatwg.org/multipage/]. +.RE +.IP \[bu] 2 +\f[CB]missing\f[R] \-\-\- Checks for missing documentation comments or +tags. For example, a missing comment on a class declaration, or a +missing \f[CB]\@param\f[R] or \f[CB]\@return\f[R] tag in the comment for a +method declaration. +.RS 2 +.PP +Issues related to missing items are typically reported as warnings +because they are unlikely to be reported as errors by downstream +validation tools that may be used to check the output generated by +\f[CB]javadoc\f[R]. +.RE +.IP \[bu] 2 +\f[CB]reference\f[R] \-\-\- Checks for issues relating to the references +to Java API elements from documentation comment tags. For example, the +reference in \f[CB]\@see\f[R] or \f[CB]{\@link\ ...}\f[R] cannot be found, +or a bad name is given for \f[CB]\@param\f[R] or \f[CB]\@throws\f[R]. +.RS 2 +.PP +Issues are typically reported as errors because while the issue may not +cause problems in the generated files, the author has likely made a +mistake that will lead to incorrect or unexpected documentation. +.RE +.IP \[bu] 2 +\f[CB]syntax\f[R] \-\-\- Checks for low\-level syntactic issues in +documentation comments. For example, unescaped angle brackets +(\f[CB]<\f[R] and \f[CB]>\f[R]) and ampersands (\f[CB]&\f[R]) and invalid +documentation comment tags. +.RS 2 +.PP +Issues are typically reported as errors because the issues may lead to +incorrect or unexpected documentation. +.RE +.SS Suppressing Messages +.PP +DocLint checks for and recognizes two strings that may be present in the +arguments for an \f[CB]\@SuppressWarnings\f[R] annotation. +.IP \[bu] 2 +\f[CB]doclint\f[R] +.IP \[bu] 2 +\f[CB]doclint:\f[R]\f[I]LIST\f[R] +.PP +where \f[I]LIST\f[R] is a comma\-separated list of one or more of +\f[CB]accessibility\f[R], \f[CB]html\f[R], \f[CB]missing\f[R], +\f[CB]syntax\f[R], \f[CB]reference\f[R]. +.PP +The names in \f[I]LIST\f[R] are the same \f[B]group\f[R] names supported +by the command\-line \f[CB]\-Xdoclint\f[R] option for \f[CB]javac\f[R] and +\f[CB]javadoc\f[R]. +(This is the same convention honored by the \f[CB]javac\f[R] +\f[CB]\-Xlint\f[R] option and the corresponding names supported by +\f[CB]\@SuppressWarnings\f[R].) +.PP +The names in \f[I]LIST\f[R] can equivalently be specified in separate +arguments of the annotation. +For example, the following are equivalent: +.IP \[bu] 2 +\f[CB]\@SuppressWarnings("doclint:accessibility,missing")\f[R] +.IP \[bu] 2 +\f[CB]\@SuppressWarnings("doclint:accessibility",\ "doclint:missing")\f[R] +.PP +When DocLint detects an issue in a documentation comment, it checks for +the presence of \f[CB]\@SuppressWarnings\f[R] on the associated +declaration and on all lexically enclosing declarations. +The issue will be ignored if any such annotation is found containing the +simple string \f[CB]doclint\f[R] or the longer form \f[CB]doclint:LIST\f[R] +where \f[I]LIST\f[R] contains the name of the group for the issue. +.PP +\f[I]Note:\f[R] as with other uses of \f[CB]\@SuppressWarnings\f[R], using +the annotation on a module or package declaration only affects that +declaration; it does not affect the contents of the module or package in +other source files. +.PP +All messages related to an issue are suppressed by the presence of an +appropriate \f[CB]\@SuppressWarnings\f[R] annotation: this includes errors +as well as warnings. +.PP +\f[I]Note:\f[R] It is only possible to \f[I]suppress\f[R] messages. +If an annotation of \f[CB]\@SuppressWarnings("doclint")\f[R] is given on a +top\-level declaration, all DocLint messages for that declaration and +any enclosed declarations will be suppressed; it is not possible to +selectively re\-enable messages for issues in enclosed declarations. +.SS Comparison with downstream validation tools +.PP +DocLint is a utility built into \f[CB]javac\f[R] and \f[CB]javadoc\f[R] that +checks the content of documentation comments, as found in source files. +In contrast, downstream validation tools can be used to validate the +output generated from those documentation comments by \f[CB]javadoc\f[R] +and the Standard Doclet. +.PP +Although there is some overlap in functionality, the two mechanisms are +different and each has its own strengths and weaknesses. +.IP \[bu] 2 +Downstream validation tools can check the end result of any generated +documentation, as it will be seen by the end user. +This includes content from all sources, including documentation +comments, the Standard Doclet itself, user\-provided taglets, and +content supplied via command\-line options. +Because such tools are analyzing complete HTML pages, they can do more +complete checks than can DocLint. +However, when a problem is found in the generated pages, it can be +harder to track down exactly where in the build pipeline the problem +needs to be fixed. +.IP \[bu] 2 +DocLint checks the content of documentation comments, in source files. +This makes it very easy to identify the exact position of any issues +that may be found. +DocLint can also detect some semantic errors in documentation comments +that downstream tools cannot detect, such as missing comments, using an +\f[CB]\@return\f[R] tag in a method returning \f[CB]void\f[R], or an +\f[CB]\@param\f[R] tag describing a non\-existent parameter. +But by its nature, DocLint cannot report on problems such as missing +links, or errors in user\-provided custom taglets, or problems in the +Standard Doclet itself. +It also cannot reliably detect errors in documentation comments at the +boundaries between content in a documentation comment and content +generated by a custom taglet. diff --git a/src/jdk.jcmd/share/classes/sun/tools/jmap/JMap.java b/src/jdk.jcmd/share/classes/sun/tools/jmap/JMap.java index e383f8dc7af8286e3aa64f6f2887626dbc53907f..8939d60930dbf72d4e03f97e0d88be950d809649 100644 --- a/src/jdk.jcmd/share/classes/sun/tools/jmap/JMap.java +++ b/src/jdk.jcmd/share/classes/sun/tools/jmap/JMap.java @@ -31,7 +31,6 @@ import java.io.InputStream; import java.util.Collection; import com.sun.tools.attach.VirtualMachine; -import com.sun.tools.attach.VirtualMachineDescriptor; import com.sun.tools.attach.AttachNotSupportedException; import sun.tools.attach.HotSpotVirtualMachine; import sun.tools.common.ProcessArgumentMatcher; @@ -171,8 +170,7 @@ public class JMap { String parallel = null; String subopts[] = options.split(","); - for (int i = 0; i < subopts.length; i++) { - String subopt = subopts[i]; + for (String subopt : subopts) { if (subopt.equals("") || subopt.equals("all")) { // pass } else if (subopt.equals("live")) { @@ -184,11 +182,11 @@ public class JMap { usage(1); } } else if (subopt.startsWith("parallel=")) { - parallel = subopt.substring("parallel=".length()); - if (parallel == null) { + parallel = subopt.substring("parallel=".length()); + if (parallel == null) { System.err.println("Fail: no number provided in option: '" + subopt + "'"); usage(1); - } + } } else { System.err.println("Fail: invalid option: '" + subopt + "'"); usage(1); @@ -209,8 +207,7 @@ public class JMap { String liveopt = "-all"; String compress_level = null; - for (int i = 0; i < subopts.length; i++) { - String subopt = subopts[i]; + for (String subopt : subopts) { if (subopt.equals("") || subopt.equals("all")) { // pass } else if (subopt.equals("live")) { diff --git a/src/jdk.jcmd/share/classes/sun/tools/jps/Arguments.java b/src/jdk.jcmd/share/classes/sun/tools/jps/Arguments.java index 10db7c39aa95e876ca3d627f89b4a8150b3356e9..be37f408c514fd3786cc9e52429a28daf71ac8e7 100644 --- a/src/jdk.jcmd/share/classes/sun/tools/jps/Arguments.java +++ b/src/jdk.jcmd/share/classes/sun/tools/jps/Arguments.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 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 @@ -64,11 +64,11 @@ public class Arguments { int argc = 0; if (args.length == 1) { - if ((args[0].compareTo("-?") == 0) - || (args[0].compareTo("-h")== 0) - || (args[0].compareTo("--help")== 0) + if ((args[0].equals("-?")) + || (args[0].equals("-h")) + || (args[0].equals("--help")) // -help: legacy. - || (args[0].compareTo("-help")== 0)) { + || (args[0].equals("-help"))) { help = true; return; } @@ -78,7 +78,7 @@ public class Arguments { argc++) { String arg = args[argc]; - if (arg.compareTo("-q") == 0) { + if (arg.equals("-q")) { quiet = true; } else if (arg.startsWith("-")) { for (int j = 1; j < arg.length(); j++) { diff --git a/src/jdk.jcmd/share/classes/sun/tools/jstat/Arguments.java b/src/jdk.jcmd/share/classes/sun/tools/jstat/Arguments.java index 5441725d06b6f00b51e47f9f6f43fef74523216a..553a902e33f21b26ce06d41690364a8d1e990305 100644 --- a/src/jdk.jcmd/share/classes/sun/tools/jstat/Arguments.java +++ b/src/jdk.jcmd/share/classes/sun/tools/jstat/Arguments.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 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 @@ -115,8 +115,8 @@ public class Arguments { String unitString = null; String valueString = s; - for (int i = 0; i < unitStrings.length; i++) { - int index = s.indexOf(unitStrings[i]); + for (String unit : unitStrings) { + int index = s.indexOf(unit); if (index > 0) { unitString = s.substring(index); valueString = s.substring(0, index); @@ -127,9 +127,9 @@ public class Arguments { try { int value = Integer.parseInt(valueString); - if (unitString == null || unitString.compareTo("ms") == 0) { + if (unitString == null || unitString.equals("ms")) { return value; - } else if (unitString.compareTo("s") == 0) { + } else if (unitString.equals("s")) { return value * 1000; } else { throw new IllegalArgumentException( @@ -149,17 +149,17 @@ public class Arguments { return; } - if ((args[0].compareTo("-?") == 0) - || (args[0].compareTo("-h") == 0) - || (args[0].compareTo("--help") == 0) + if ((args[0].equals("-?")) + || (args[0].equals("-h")) + || (args[0].equals("--help")) // -help: legacy. - || (args[0].compareTo("-help") == 0)) { + || (args[0].equals("-help"))) { help = true; return; - } else if (args[0].compareTo("-options") == 0) { + } else if (args[0].equals("-options")) { options = true; return; - } else if (args[0].compareTo("-list") == 0) { + } else if (args[0].equals("-list")) { list = true; if (args.length > 2) { throw new IllegalArgumentException("invalid argument count"); @@ -171,23 +171,23 @@ public class Arguments { for ( ; (argc < args.length) && (args[argc].startsWith("-")); argc++) { String arg = args[argc]; - if (arg.compareTo("-a") == 0) { + if (arg.equals("-a")) { comparator = new AscendingMonitorComparator(); - } else if (arg.compareTo("-d") == 0) { + } else if (arg.equals("-d")) { comparator = new DescendingMonitorComparator(); - } else if (arg.compareTo("-t") == 0) { + } else if (arg.equals("-t")) { timestamp = true; - } else if (arg.compareTo("-v") == 0) { + } else if (arg.equals("-v")) { verbose = true; - } else if ((arg.compareTo("-constants") == 0) - || (arg.compareTo("-c") == 0)) { + } else if ((arg.equals("-constants")) + || (arg.equals("-c"))) { constants = true; - } else if ((arg.compareTo("-strings") == 0) - || (arg.compareTo("-s") == 0)) { + } else if ((arg.equals("-strings")) + || (arg.equals("-s"))) { strings = true; } else if (arg.startsWith("-h")) { String value; - if (arg.compareTo("-h") != 0) { + if (!arg.equals("-h")) { value = arg.substring(2); } else { argc++; @@ -245,7 +245,7 @@ public class Arguments { } catch (NumberFormatException nfe) { // it didn't parse. check for the -snap or jstat_options // file options. - if ((argc == 0) && (args[argc].compareTo("-snap") == 0)) { + if ((argc == 0) && (args[argc].equals("-snap"))) { snap = true; } else if (argc == 0) { specialOption = args[argc].substring(1); diff --git a/src/jdk.jcmd/share/classes/sun/tools/jstat/ColumnFormat.java b/src/jdk.jcmd/share/classes/sun/tools/jstat/ColumnFormat.java index fc0dfe0483cec90aab987886e7562a2831515950..c716a6e079b7cedc4a634b5d5f7a627daacb61a6 100644 --- a/src/jdk.jcmd/share/classes/sun/tools/jstat/ColumnFormat.java +++ b/src/jdk.jcmd/share/classes/sun/tools/jstat/ColumnFormat.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 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 @@ -25,8 +25,6 @@ package sun.tools.jstat; -import java.util.*; - /** * A class to represent the format for a column of data. * @@ -156,9 +154,8 @@ public class ColumnFormat extends OptionFormat { + ";scale=" + scale.toString() + ";align=" + align.toString() + ";required=" + required); - for (Iterator<OptionFormat> i = children.iterator(); i.hasNext(); /* empty */) { - OptionFormat of = i.next(); - of.printFormat(indentLevel+1); + for (OptionFormat of : children) { + of.printFormat(indentLevel + 1); } System.out.println(indent + "}"); diff --git a/src/jdk.jcmd/share/classes/sun/tools/jstat/OptionFormat.java b/src/jdk.jcmd/share/classes/sun/tools/jstat/OptionFormat.java index c5d9f79c43f189c84829d141703880a313179ed7..ee72b05456e91a8e537e9a0842b1cfe71c136dcd 100644 --- a/src/jdk.jcmd/share/classes/sun/tools/jstat/OptionFormat.java +++ b/src/jdk.jcmd/share/classes/sun/tools/jstat/OptionFormat.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 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 @@ -77,15 +77,14 @@ public class OptionFormat { public void apply(Closure c) throws MonitorException { - for (Iterator<OptionFormat> i = children.iterator(); i.hasNext(); /* empty */) { - OptionFormat o = i.next(); - c.visit(o, i.hasNext()); - } + for (Iterator<OptionFormat> i = children.iterator(); i.hasNext(); /* empty */) { + OptionFormat o = i.next(); + c.visit(o, i.hasNext()); + } - for (Iterator <OptionFormat>i = children.iterator(); i.hasNext(); /* empty */) { - OptionFormat o = i.next(); - o.apply(c); - } + for (OptionFormat o : children) { + o.apply(c); + } } public void printFormat() { diff --git a/src/jdk.jcmd/share/classes/sun/tools/jstat/OptionLister.java b/src/jdk.jcmd/share/classes/sun/tools/jstat/OptionLister.java index 384b6a54383e42f99902d8f09726b3afdc9ba173..c417236344c058d114865f3f1f121c566d8cdb66 100644 --- a/src/jdk.jcmd/share/classes/sun/tools/jstat/OptionLister.java +++ b/src/jdk.jcmd/share/classes/sun/tools/jstat/OptionLister.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 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 @@ -73,7 +73,7 @@ public class OptionLister { } for ( OptionFormat of : options) { - if (of.getName().compareTo("timestamp") == 0) { + if (of.getName().equals("timestamp")) { // ignore the special timestamp OptionFormat. continue; } diff --git a/src/jdk.jcmd/share/classes/sun/tools/jstat/Parser.java b/src/jdk.jcmd/share/classes/sun/tools/jstat/Parser.java index 5693e422fe6c149bc794ca9cc7cbbff51e9b8b26..70e3553e77ee1593d2a0d10b1b176b456bc467e2 100644 --- a/src/jdk.jcmd/share/classes/sun/tools/jstat/Parser.java +++ b/src/jdk.jcmd/share/classes/sun/tools/jstat/Parser.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 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 @@ -80,7 +80,7 @@ public class Parser { }; - private static Set<String> reservedWords; + private static final Set<String> reservedWords = Set.of(otherKeyWords); private StreamTokenizer st; private String filename; @@ -103,17 +103,12 @@ public class Parser { st.slashSlashComments(true); st.slashStarComments(true); - reservedWords = new HashSet<String>(); - for (int i = 0; i < otherKeyWords.length; i++) { - reservedWords.add(otherKeyWords[i]); + for (char delimiter : delimiters) { + st.ordinaryChar(delimiter); } - for (int i = 0; i < delimiters.length; i++ ) { - st.ordinaryChar(delimiters[i]); - } - - for (int i = 0; i < infixOps.length; i++ ) { - st.ordinaryChar(infixOps[i]); + for (char infixOp : infixOps) { + st.ordinaryChar(infixOp); } } @@ -231,8 +226,8 @@ public class Parser { * determine if the give work is a reserved key word */ private boolean isInfixOperator(char op) { - for (int i = 0; i < infixOps.length; i++) { - if (op == infixOps[i]) { + for (char infixOp : infixOps) { + if (op == infixOp) { return true; } } @@ -473,19 +468,19 @@ public class Parser { return; } - if (lookahead.sval.compareTo(DATA) == 0) { + if (lookahead.sval.equals(DATA)) { dataStmt(cf); - } else if (lookahead.sval.compareTo(HEADER) == 0) { + } else if (lookahead.sval.equals(HEADER)) { headerStmt(cf); - } else if (lookahead.sval.compareTo(WIDTH) == 0) { + } else if (lookahead.sval.equals(WIDTH)) { widthStmt(cf); - } else if (lookahead.sval.compareTo(FORMAT) == 0) { + } else if (lookahead.sval.equals(FORMAT)) { formatStmt(cf); - } else if (lookahead.sval.compareTo(ALIGN) == 0) { + } else if (lookahead.sval.equals(ALIGN)) { alignStmt(cf); - } else if (lookahead.sval.compareTo(SCALE) == 0) { + } else if (lookahead.sval.equals(SCALE)) { scaleStmt(cf); - } else if (lookahead.sval.compareTo(REQUIRED) == 0) { + } else if (lookahead.sval.equals(REQUIRED)) { requiredStmt(cf); } else { return; @@ -544,7 +539,7 @@ public class Parser { while (lookahead.ttype != StreamTokenizer.TT_EOF) { // look for the start symbol if ((lookahead.ttype != StreamTokenizer.TT_WORD) - || (lookahead.sval.compareTo(START) != 0)) { + || (!lookahead.sval.equals(START))) { // skip tokens until a start symbol is found nextToken(); continue; @@ -574,7 +569,7 @@ public class Parser { while (lookahead.ttype != StreamTokenizer.TT_EOF) { // look for the start symbol if ((lookahead.ttype != StreamTokenizer.TT_WORD) - || (lookahead.sval.compareTo(START) != 0)) { + || (!lookahead.sval.equals(START))) { // skip tokens until a start symbol is found nextToken(); continue; diff --git a/src/jdk.jcmd/share/classes/sun/tools/jstat/RawOutputFormatter.java b/src/jdk.jcmd/share/classes/sun/tools/jstat/RawOutputFormatter.java index cbd129cbe50201b228ec6d57def3058da79d6fad..02a083ba1cd29ede348af417a9de235b6027d201 100644 --- a/src/jdk.jcmd/share/classes/sun/tools/jstat/RawOutputFormatter.java +++ b/src/jdk.jcmd/share/classes/sun/tools/jstat/RawOutputFormatter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 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 @@ -48,8 +48,7 @@ public class RawOutputFormatter implements OutputFormatter { if (header == null) { // build the header string and prune out any unwanted monitors StringBuilder headerBuilder = new StringBuilder(); - for (Iterator<Monitor> i = logged.iterator(); i.hasNext(); /* empty */ ) { - Monitor m = i.next(); + for (Monitor m : logged) { headerBuilder.append(m.getName()).append(' '); } header = headerBuilder.toString(); @@ -60,8 +59,7 @@ public class RawOutputFormatter implements OutputFormatter { public String getRow() throws MonitorException { StringBuilder row = new StringBuilder(); int count = 0; - for (Iterator<Monitor> i = logged.iterator(); i.hasNext(); /* empty */ ) { - Monitor m = i.next(); + for (Monitor m : logged) { if (count++ > 0) { row.append(" "); } diff --git a/src/jdk.jcmd/share/man/jcmd.1 b/src/jdk.jcmd/share/man/jcmd.1 index a5f16e6a82d25b7939e56ab608d17a1a40ef3a7b..9342943ac2a99b40ac22e85c8823564747d217f8 100644 --- a/src/jdk.jcmd/share/man/jcmd.1 +++ b/src/jdk.jcmd/share/man/jcmd.1 @@ -1,4 +1,4 @@ -.\" Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved. +.\" Copyright (c) 2012, 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 @@ -21,7 +21,7 @@ .\" .\" Automatically generated by Pandoc 2.3.1 .\" -.TH "JCMD" "1" "2021" "JDK 18\-ea" "JDK Commands" +.TH "JCMD" "1" "2022" "JDK 19\-ea" "JDK Commands" .hy .SH NAME .PP @@ -596,8 +596,8 @@ To list available options, use the \f[CB]JAVA_HOME\f[R]/bin/jfr tool. .IP \[bu] 2 \f[CB]event\-setting\f[R]: (Optional) Specifies the event setting value to modify. -Use the form: #= To add a new event setting, prefix the event name with -\[aq]+\[aq]. +Use the form: \f[CB]<event\-name>#<setting\-name>=<value>\f[R] To add a +new event setting, prefix the event name with \[aq]+\[aq]. .PP You can specify values for multiple event settings and .jfc options by separating them with a whitespace. @@ -802,7 +802,8 @@ false) .RE .TP .B \f[CB]VM.cds\f[R] [\f[I]arguments\f[R]] -Dump a static or dynamic shared archive including all shareable classes. +Dumps a static or dynamic shared archive that includes all currently +loaded classes. .RS .PP Impact: Medium \-\-\- pause time depends on number of loaded classes @@ -811,11 +812,22 @@ Permission: \f[CB]java.lang.management.ManagementPermission(monitor)\f[R] .PP \f[I]arguments\f[R]: .IP \[bu] 2 -\f[CB]subcmd\f[R]: \f[CB]static_dump\f[R] | \f[CB]dynamic_dump\f[R] (STRING, -no default value) +\f[CB]subcmd\f[R]: must be either \f[CB]static_dump\f[R] or +\f[CB]dynamic_dump\f[R] (STRING, no default value) .IP \[bu] 2 \f[CB]filename\f[R]: (Optional) Name of the shared archive to be dumped (STRING, no default value) +.PP +If \f[CB]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[CB]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. +.PP +If \f[CB]dynamic_dump\f[R] is specified, the target JVM must be started +with the JVM option \f[CB]\-XX:+RecordDynamicDumpInfo\f[R]. .RE .TP .B \f[CB]VM.classloaders\f[R] [\f[I]options\f[R]] @@ -873,9 +885,9 @@ The following \f[I]options\f[R] must be specified using either \f[CB]\-i\f[R]: (Optional) Inherited interfaces should be printed. (BOOLEAN, false) .IP \[bu] 2 -\f[CB]\-s\f[R]: (Optional) If a class name is specified, it prints the -subclasses. -If the class name is not specified, only the superclasses are printed. +\f[CB]\-s\f[R]: (Optional) If a classname is specified, print its +subclasses in addition to its superclasses. +Without this option only the superclasses will be printed. (BOOLEAN, false) .PP \f[I]arguments\f[R]: @@ -1077,10 +1089,6 @@ detail comparison against previous baseline, which shows the memory allocation activities at different callsites. (BOOLEAN, false) .IP \[bu] 2 -\f[CB]shutdown\f[R]: (Optional) Requests runtime to shutdown itself and -free the memory used by runtime. -(BOOLEAN, false) -.IP \[bu] 2 \f[CB]statistics\f[R]: (Optional) Prints tracker statistics for tuning purpose. (BOOLEAN, false) diff --git a/src/jdk.jcmd/share/man/jinfo.1 b/src/jdk.jcmd/share/man/jinfo.1 index 30de6c169247c81e4017bd129ad35ed3b713fca3..40cf79d2b6ecd26de8b6ae740d83615232e872c2 100644 --- a/src/jdk.jcmd/share/man/jinfo.1 +++ b/src/jdk.jcmd/share/man/jinfo.1 @@ -21,7 +21,7 @@ .\" .\" Automatically generated by Pandoc 2.3.1 .\" -.TH "JINFO" "1" "2021" "JDK 18\-ea" "JDK Commands" +.TH "JINFO" "1" "2022" "JDK 19\-ea" "JDK Commands" .hy .SH NAME .PP diff --git a/src/jdk.jcmd/share/man/jmap.1 b/src/jdk.jcmd/share/man/jmap.1 index 82e16d0ae2091bc1ec1fb5c3a5768fa0ac63a249..d29f8e84cfede203c73ef516b3039a26695ff1ba 100644 --- a/src/jdk.jcmd/share/man/jmap.1 +++ b/src/jdk.jcmd/share/man/jmap.1 @@ -21,7 +21,7 @@ .\" .\" Automatically generated by Pandoc 2.3.1 .\" -.TH "JMAP" "1" "2021" "JDK 18\-ea" "JDK Commands" +.TH "JMAP" "1" "2022" "JDK 19\-ea" "JDK Commands" .hy .SH NAME .PP diff --git a/src/jdk.jcmd/share/man/jps.1 b/src/jdk.jcmd/share/man/jps.1 index a6d10fe911afe0b289b8cd83a1cdd2ee11fb7be5..a442c4665fbcc4d2862ab936a4b96ab21bdf855d 100644 --- a/src/jdk.jcmd/share/man/jps.1 +++ b/src/jdk.jcmd/share/man/jps.1 @@ -21,7 +21,7 @@ .\" .\" Automatically generated by Pandoc 2.3.1 .\" -.TH "JPS" "1" "2021" "JDK 18\-ea" "JDK Commands" +.TH "JPS" "1" "2022" "JDK 19\-ea" "JDK Commands" .hy .SH NAME .PP diff --git a/src/jdk.jcmd/share/man/jstack.1 b/src/jdk.jcmd/share/man/jstack.1 index 302b9e5c24ab799cf56be7a33197231c2e159dc8..80674a67552c021ce8708acffe057695a61cf32b 100644 --- a/src/jdk.jcmd/share/man/jstack.1 +++ b/src/jdk.jcmd/share/man/jstack.1 @@ -21,7 +21,7 @@ .\" .\" Automatically generated by Pandoc 2.3.1 .\" -.TH "JSTACK" "1" "2021" "JDK 18\-ea" "JDK Commands" +.TH "JSTACK" "1" "2022" "JDK 19\-ea" "JDK Commands" .hy .SH NAME .PP diff --git a/src/jdk.jcmd/share/man/jstat.1 b/src/jdk.jcmd/share/man/jstat.1 index 9996833ece9c06c6c54683e19f33bd7a79a023b4..f235acf0c116a8a90751d74037a285d4fb0215a8 100644 --- a/src/jdk.jcmd/share/man/jstat.1 +++ b/src/jdk.jcmd/share/man/jstat.1 @@ -21,7 +21,7 @@ .\" .\" Automatically generated by Pandoc 2.3.1 .\" -.TH "JSTAT" "1" "2021" "JDK 18\-ea" "JDK Commands" +.TH "JSTAT" "1" "2022" "JDK 19\-ea" "JDK Commands" .hy .SH NAME .PP diff --git a/src/jdk.jconsole/share/classes/sun/tools/jconsole/SummaryTab.java b/src/jdk.jconsole/share/classes/sun/tools/jconsole/SummaryTab.java index f70f1b1f35895391c2eb76424df5350ab21464cd..3168665cfc0f99185ea98516f69746ac40f47e9c 100644 --- a/src/jdk.jconsole/share/classes/sun/tools/jconsole/SummaryTab.java +++ b/src/jdk.jconsole/share/classes/sun/tools/jconsole/SummaryTab.java @@ -113,6 +113,7 @@ class SummaryTab extends Tab { StringBuilder buf; + @SuppressWarnings("deprecation") synchronized Result formatSummary() { Result result = new Result(); ProxyClient proxyClient = vmPanel.getProxyClient(); diff --git a/src/jdk.jconsole/share/man/jconsole.1 b/src/jdk.jconsole/share/man/jconsole.1 index f9e29abb1acd76d171aea8ed68d7a1249a3e5203..a32e6d0d447de86c12479365b274869b0866f68b 100644 --- a/src/jdk.jconsole/share/man/jconsole.1 +++ b/src/jdk.jconsole/share/man/jconsole.1 @@ -21,7 +21,7 @@ .\" .\" Automatically generated by Pandoc 2.3.1 .\" -.TH "JCONSOLE" "1" "2021" "JDK 18\-ea" "JDK Commands" +.TH "JCONSOLE" "1" "2022" "JDK 19\-ea" "JDK Commands" .hy .SH NAME .PP diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/TypeAnnotation.java b/src/jdk.jdeps/share/classes/com/sun/tools/classfile/TypeAnnotation.java index 5d591705d52ea4628caff04dc99c0fbda1788559..707cb8315402ffbf122198bd514812be56c67bda 100644 --- a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/TypeAnnotation.java +++ b/src/jdk.jdeps/share/classes/com/sun/tools/classfile/TypeAnnotation.java @@ -130,7 +130,7 @@ public class TypeAnnotation { break; // class extends or implements clause case CLASS_EXTENDS: - position.type_index = cr.readUnsignedShort();; + position.type_index = cr.readUnsignedShort(); break; // throws case THROWS: diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/ClassFileReader.java b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/ClassFileReader.java index 1c4df796279f39f7c64e86360fbb37de45115996..b03c175da240f715188fbab10ad35413c23e8ce6 100644 --- a/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/ClassFileReader.java +++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/ClassFileReader.java @@ -356,7 +356,8 @@ public class ClassFileReader implements Closeable { protected ClassFile readClassFile(JarFile jarfile, JarEntry e) throws IOException { try (InputStream is = jarfile.getInputStream(e)) { ClassFile cf = ClassFile.read(is); - if (jarfile.isMultiRelease()) { + // exclude module-info.class since this jarFile is on classpath + if (jarfile.isMultiRelease() && !cf.getName().equals("module-info")) { VersionHelper.add(jarfile, e, cf); } return cf; @@ -437,5 +438,4 @@ public class ClassFileReader implements Closeable { throw new UnsupportedOperationException("Not supported yet."); } } - private static final String MODULE_INFO = "module-info.class"; } diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/DependencyFinder.java b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/DependencyFinder.java index 514e2ef607a12b5f0e43c1b482aef8bd2534288a..d9a07700134adb5d06f4d5cd3d8910e5f32b91d7 100644 --- a/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/DependencyFinder.java +++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/DependencyFinder.java @@ -268,7 +268,14 @@ class DependencyFinder { } return targets; } catch (InterruptedException|ExecutionException e) { - throw new Error(e); + Throwable cause = e.getCause(); + if (cause instanceof RuntimeException x) { + throw x; + } else if (cause instanceof Error x) { + throw x; + } else { + throw new Error(e); + } } } diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/ModuleDotGraph.java b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/ModuleDotGraph.java index 21c4d67829c412fa83923b84d3587c58bac2248e..a23f25be9d2aeda5bfe8d92d8261cab937e298ed 100644 --- a/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/ModuleDotGraph.java +++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/ModuleDotGraph.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -65,7 +65,6 @@ public class ModuleDotGraph { this(config, config.rootModules().stream() .map(Module::name) - .sorted() .collect(toMap(Function.identity(), mn -> config.resolve(Set.of(mn)))), apiOnly); } diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/MultiReleaseException.java b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/MultiReleaseException.java index 0341923f926ef37432af4fdc3b1675050ae7f48a..0943287b93398807b67bcc9a8bc9f61f77aac0f3 100644 --- a/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/MultiReleaseException.java +++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/MultiReleaseException.java @@ -47,7 +47,7 @@ class MultiReleaseException extends RuntimeException { * The detail message array */ public MultiReleaseException(String key, Object... params) { - super(); + super(JdepsTask.getMessage(key, params)); this.key = key; this.params = params; } diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/VersionHelper.java b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/VersionHelper.java index 9ff358a63d38d873cfd879816566fc85894f3057..227c9ccd264db332f19f3f3eeedfbe5c0172d3a0 100644 --- a/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/VersionHelper.java +++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/VersionHelper.java @@ -55,15 +55,10 @@ public class VersionHelper { String version = realName.substring(len, n); assert (Integer.parseInt(version) > 8); String name = cf.getName().replace('/', '.'); - if (nameToVersion.containsKey(name)) { - if (!version.equals(nameToVersion.get(name))) { - throw new MultiReleaseException( - "err.multirelease.version.associated", - name, nameToVersion.get(name), version - ); - } - } else { - nameToVersion.put(name, version); + String v = nameToVersion.computeIfAbsent(name, _n -> version); + if (!version.equals(v)) { + throw new MultiReleaseException("err.multirelease.version.associated", + name, nameToVersion.get(name), version); } } else { throw new MultiReleaseException("err.multirelease.jar.malformed", diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/resources/jdeps.properties b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/resources/jdeps.properties index 98babe8e7ede8f33a1da9a7d3b6940370f5e8e9e..10bada578f8eab665819a20ab3b1ca219aa305a3 100644 --- a/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/resources/jdeps.properties +++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/resources/jdeps.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2012, 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 @@ -241,6 +241,7 @@ err.module.not.found=module not found: {0} err.root.module.not.set=root module set empty err.option.already.specified={0} option specified more than once. err.filter.not.specified=--package (-p), --regex (-e), --require option must be specified +err.invalid.filters=Only one of --package (-p), --regex (-e), --require option can be specified err.multirelease.option.exists={0} is not a multi-release jar file but --multi-release option is set err.multirelease.option.notfound={0} is a multi-release jar file but --multi-release option is not set err.multirelease.version.associated=class {0} already associated with version {1}, trying to add version {2} diff --git a/src/jdk.jdeps/share/classes/module-info.java b/src/jdk.jdeps/share/classes/module-info.java index 6bbfccc9c59383c661bbb9e855e28def1dc81aa3..a3f47954842ab429e00b48a48034bc288e3c1345 100644 --- a/src/jdk.jdeps/share/classes/module-info.java +++ b/src/jdk.jdeps/share/classes/module-info.java @@ -49,6 +49,10 @@ * @toolGuide jdeps * * @provides java.util.spi.ToolProvider + * Use {@link java.util.spi.ToolProvider#findFirst ToolProvider.findFirst("javap")} + * or {@link java.util.spi.ToolProvider#findFirst ToolProvider.findFirst("jdeps")} + * to obtain an instance of a {@code ToolProvider} that provides the equivalent + * of command-line access to the {@code javap} or {@code jdeps} tool. * * @moduleGraph * @since 9 diff --git a/src/jdk.jdeps/share/man/javap.1 b/src/jdk.jdeps/share/man/javap.1 index 02fc77a0e158b23979597fa133341159ef1f8c1e..c63d7a3a82dfd27f6113a58bf6250d12cd65b2b4 100644 --- a/src/jdk.jdeps/share/man/javap.1 +++ b/src/jdk.jdeps/share/man/javap.1 @@ -21,7 +21,7 @@ .\" .\" Automatically generated by Pandoc 2.3.1 .\" -.TH "JAVAP" "1" "2021" "JDK 18\-ea" "JDK Commands" +.TH "JAVAP" "1" "2022" "JDK 19\-ea" "JDK Commands" .hy .SH NAME .PP diff --git a/src/jdk.jdeps/share/man/jdeprscan.1 b/src/jdk.jdeps/share/man/jdeprscan.1 index 109e97890ef8db3aa2763d620b2fb31b666b42be..d168901b5bcddb4546f1699136689698961232ae 100644 --- a/src/jdk.jdeps/share/man/jdeprscan.1 +++ b/src/jdk.jdeps/share/man/jdeprscan.1 @@ -21,7 +21,7 @@ .\" .\" Automatically generated by Pandoc 2.3.1 .\" -.TH "JDEPRSCAN" "1" "2021" "JDK 18\-ea" "JDK Commands" +.TH "JDEPRSCAN" "1" "2022" "JDK 19\-ea" "JDK Commands" .hy .SH NAME .PP diff --git a/src/jdk.jdeps/share/man/jdeps.1 b/src/jdk.jdeps/share/man/jdeps.1 index 110a314af733229080239c34e5908860ebbe0fdd..e8cb14c460afc4290d0681938bb1e1633d1668e9 100644 --- a/src/jdk.jdeps/share/man/jdeps.1 +++ b/src/jdk.jdeps/share/man/jdeps.1 @@ -21,7 +21,7 @@ .\" .\" Automatically generated by Pandoc 2.3.1 .\" -.TH "JDEPS" "1" "2021" "JDK 18\-ea" "JDK Commands" +.TH "JDEPS" "1" "2022" "JDK 19\-ea" "JDK Commands" .hy .SH NAME .PP diff --git a/src/jdk.jdi/share/classes/com/sun/jdi/ReferenceType.java b/src/jdk.jdi/share/classes/com/sun/jdi/ReferenceType.java index 2e84651fbd093107d8231489014b70a840ded252..043acc839f7d4b1a0b97897e26444f19cbbfcd8c 100644 --- a/src/jdk.jdi/share/classes/com/sun/jdi/ReferenceType.java +++ b/src/jdk.jdi/share/classes/com/sun/jdi/ReferenceType.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -413,13 +413,13 @@ public interface ReferenceType /** * Returns a list containing each {@link Method} * declared or inherited by this type. Methods from superclasses - * or superinterfaces that that have been hidden or overridden + * or superinterfaces that have been hidden or overridden * are not included. * <p> * Note that despite this exclusion, multiple inherited methods * with the same signature can be present in the returned list, but * at most one can be a member of a {@link ClassType}. - * See JLS section 8.4.6 for details. + * See JLS section 8.4.8 for details. * <p> * For arrays ({@link ArrayType}) and primitive classes, the returned * list is always empty. @@ -454,7 +454,7 @@ public interface ReferenceType * find overloaded methods. * <p> * Overridden and hidden methods are not included. - * See JLS (8.4.6) for details. + * See JLS (8.4.8) for details. * <p> * For arrays ({@link ArrayType}) and primitive classes, the returned * list is always empty. @@ -478,7 +478,7 @@ public interface ReferenceType * <li><code>(IIII)Z</code> * </ul> * This method follows the inheritance rules specified - * in the JLS (8.4.6) to determine visibility. + * in the JLS (8.4.8) to determine visibility. * <p> * At most one method in the list is a concrete method and a * component of {@link ClassType}; any other methods in the list diff --git a/src/jdk.jdi/share/classes/com/sun/jdi/VirtualMachineManager.java b/src/jdk.jdi/share/classes/com/sun/jdi/VirtualMachineManager.java index 8b5957dc0d90a07e3911c515971a85730675cb4e..eee09ded39b0b27601711e78b9051b1ee42b6461 100644 --- a/src/jdk.jdi/share/classes/com/sun/jdi/VirtualMachineManager.java +++ b/src/jdk.jdi/share/classes/com/sun/jdi/VirtualMachineManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -97,7 +97,7 @@ import com.sun.jdi.event.VMStartEvent; * {@code -agentlib:jdwp=transport=xxx,server=y} * </LI> * <LI> - * Target VM generates and outputs the tranport-specific address at which it will + * Target VM generates and outputs the transport-specific address at which it will * listen for a connection.</LI> * <LI> * Debugger is launched. Debugger selects a connector in the list @@ -158,7 +158,7 @@ import com.sun.jdi.event.VMStartEvent; * </LI> * <LI> * Later, an uncaught exception is thrown in the target VM. The target - * VM generates the tranport-specific address at which it will + * VM generates the transport-specific address at which it will * listen for a connection. * <LI>Target VM launches the debugger with the following items concatenated * together (separated by spaces) to form the command line: diff --git a/src/jdk.jdi/share/classes/com/sun/tools/example/debug/tty/Commands.java b/src/jdk.jdi/share/classes/com/sun/tools/example/debug/tty/Commands.java index 15091d310d5aa402e3538545233824832df9dac9..121038a6d72e1630fdfd82c781e2022149c3a4ea 100644 --- a/src/jdk.jdi/share/classes/com/sun/tools/example/debug/tty/Commands.java +++ b/src/jdk.jdi/share/classes/com/sun/tools/example/debug/tty/Commands.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -501,7 +501,7 @@ class Commands { void commandThreadGroup(StringTokenizer t) { if (!t.hasMoreTokens()) { - MessageOutput.println("Threadgroup name not specified."); + ThreadInfo.setThreadGroup(null); // reset to default (top level ThreadGroup) return; } String name = t.nextToken(); diff --git a/src/jdk.jdi/share/classes/com/sun/tools/example/debug/tty/TTY.java b/src/jdk.jdi/share/classes/com/sun/tools/example/debug/tty/TTY.java index 6e1ddcb1b846f091579f655af2e45bee8e50947a..9373bc9e0e037e5cf94eb15628d897144cbee40a 100644 --- a/src/jdk.jdi/share/classes/com/sun/tools/example/debug/tty/TTY.java +++ b/src/jdk.jdi/share/classes/com/sun/tools/example/debug/tty/TTY.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -993,6 +993,8 @@ public class TTY implements EventNotifier { token.startsWith("-ss") || token.startsWith("-oss") ) { javaArgs = addArgument(javaArgs, token); + } else if (token.startsWith("-R")) { + javaArgs = addArgument(javaArgs, token.substring(2)); } else if (token.equals("-tclassic")) { usageError("Classic VM no longer supported."); return; diff --git a/src/jdk.jdi/share/classes/com/sun/tools/example/debug/tty/TTYResources.java b/src/jdk.jdi/share/classes/com/sun/tools/example/debug/tty/TTYResources.java index 8ba3c42c83ad47f587d963f7614f70f2bbdccbc2..e7090c8c8c827e4e2473365f79c10caf622f5fb3 100644 --- a/src/jdk.jdi/share/classes/com/sun/tools/example/debug/tty/TTYResources.java +++ b/src/jdk.jdi/share/classes/com/sun/tools/example/debug/tty/TTYResources.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -312,7 +312,6 @@ public class TTYResources extends java.util.ListResourceBundle { {"Thread has been resumed", "Thread has been resumed"}, {"Thread not suspended", "Thread not suspended"}, {"thread group number description name", "{0,number,integer}. {1} {2}"}, - {"Threadgroup name not specified.", "Threadgroup name not specified."}, {"<thread_id> option not valid until the VM is started with the run command", "<thread_id> option not valid until the VM is started with the run command"}, {"Threads must be suspended", "Threads must be suspended"}, @@ -354,7 +353,7 @@ public class TTYResources extends java.util.ListResourceBundle { "\n" + "run [class [args]] -- start execution of application's main class\n" + "\n" + - "threads [threadgroup] -- list threads\n" + + "threads [threadgroup] -- list threads in threadgroup. Use current threadgroup if none specified.\n" + "thread <thread id> -- set default thread\n" + "suspend [thread id(s)] -- suspend threads (default: all)\n" + "resume [thread id(s)] -- resume threads (default: all)\n" + @@ -377,7 +376,8 @@ public class TTYResources extends java.util.ListResourceBundle { "fields <class id> -- list a class's fields\n" + "\n" + "threadgroups -- list threadgroups\n" + - "threadgroup <name> -- set current threadgroup\n" + + "threadgroup <name> -- set current threadgroup to <name>\n" + + "threadgroup -- set current threadgroup back to the top level threadgroup\n" + "\n" + "stop [go|thread] [<thread_id>] <at|in> <location>\n" + " -- set a breakpoint\n" + @@ -477,8 +477,9 @@ public class TTYResources extends java.util.ListResourceBundle { " -dbgtrace [flags] print info for debugging {0}\n" + " -tclient run the application in the HotSpot(TM) Client Compiler\n" + " -tserver run the application in the HotSpot(TM) Server Compiler\n" + + " -R<option> forward <option> to debuggee process if launched by jdb, otherwise ignored\n" + "\n" + - "options forwarded to debuggee process:\n" + + "options forwarded to debuggee process if lauched by jdb (shorthand instead of using -R):\n" + " -v -verbose[:class|gc|jni]\n" + " turn on verbose mode\n" + " -D<name>=<value> set a system property\n" + diff --git a/src/jdk.jdi/share/classes/com/sun/tools/example/debug/tty/TTYResources_ja.java b/src/jdk.jdi/share/classes/com/sun/tools/example/debug/tty/TTYResources_ja.java index 1f0dd4a3e22601394742e31de77c94e852d0857c..330fc33a82096e9290d24d0b6ca0ed69d42109e3 100644 --- a/src/jdk.jdi/share/classes/com/sun/tools/example/debug/tty/TTYResources_ja.java +++ b/src/jdk.jdi/share/classes/com/sun/tools/example/debug/tty/TTYResources_ja.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -302,7 +302,6 @@ public class TTYResources_ja extends java.util.ListResourceBundle { {"Thread has been resumed", "\u30B9\u30EC\u30C3\u30C9\u304C\u518D\u958B\u3057\u307E\u3057\u305F"}, {"Thread not suspended", "\u30B9\u30EC\u30C3\u30C9\u306F\u4E2D\u65AD\u3057\u3066\u3044\u307E\u305B\u3093"}, {"thread group number description name", "{0,number,integer}. {1} {2}"}, - {"Threadgroup name not specified.", "\u30B9\u30EC\u30C3\u30C9\u30B0\u30EB\u30FC\u30D7\u540D\u304C\u6307\u5B9A\u3055\u308C\u3066\u3044\u307E\u305B\u3093\u3002"}, {"<thread_id> option not valid until the VM is started with the run command", "<thread_id>\u30AA\u30D7\u30B7\u30E7\u30F3\u306F\u3001VM\u304Crun\u30B3\u30DE\u30F3\u30C9\u3067\u958B\u59CB\u3055\u308C\u308B\u307E\u3067\u7121\u52B9\u3067\u3059"}, {"Threads must be suspended", "\u30B9\u30EC\u30C3\u30C9\u3092\u4E2D\u65AD\u3059\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059"}, diff --git a/src/jdk.jdi/share/classes/com/sun/tools/example/debug/tty/TTYResources_zh_CN.java b/src/jdk.jdi/share/classes/com/sun/tools/example/debug/tty/TTYResources_zh_CN.java index 88c1cd3e878cc7cad4b3e1c63158ee74cb7d93b5..6c4be9777050bb6a5a16c21f6f8a3f5feba0458b 100644 --- a/src/jdk.jdi/share/classes/com/sun/tools/example/debug/tty/TTYResources_zh_CN.java +++ b/src/jdk.jdi/share/classes/com/sun/tools/example/debug/tty/TTYResources_zh_CN.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -302,7 +302,6 @@ public class TTYResources_zh_CN extends java.util.ListResourceBundle { {"Thread has been resumed", "\u5DF2\u6062\u590D\u7EBF\u7A0B"}, {"Thread not suspended", "\u672A\u6302\u8D77\u7EBF\u7A0B"}, {"thread group number description name", "{0,number,integer}\u3002{1} {2}"}, - {"Threadgroup name not specified.", "\u672A\u6307\u5B9A\u7EBF\u7A0B\u7EC4\u540D\u3002"}, {"<thread_id> option not valid until the VM is started with the run command", "\u5728\u4F7F\u7528 run \u547D\u4EE4\u542F\u52A8 VM \u524D\uFF0C<thread_id> \u9009\u9879\u65E0\u6548"}, {"Threads must be suspended", "\u5FC5\u987B\u6302\u8D77\u7EBF\u7A0B"}, diff --git a/src/jdk.jdi/share/man/jdb.1 b/src/jdk.jdi/share/man/jdb.1 index dfac04e3e275051c942a886236d5d05b0e2fd21d..dd4aefe18124b802d63983d30db71d6371bf8ceb 100644 --- a/src/jdk.jdi/share/man/jdb.1 +++ b/src/jdk.jdi/share/man/jdb.1 @@ -1,4 +1,4 @@ -.\" Copyright (c) 1995, 2018, Oracle and/or its affiliates. All rights reserved. +.\" Copyright (c) 1995, 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 @@ -21,7 +21,7 @@ .\" .\" Automatically generated by Pandoc 2.3.1 .\" -.TH "JDB" "1" "2021" "JDK 18\-ea" "JDK Commands" +.TH "JDB" "1" "2022" "JDK 19\-ea" "JDK Commands" .hy .SH NAME .PP @@ -230,8 +230,9 @@ Runs the application in the Java HotSpot VM server. .RE .TP .B \f[CB]\-J\f[R]\f[I]option\f[R] -Passes \f[I]option\f[R] to the JVM, where option is one of the options -described on the reference page for the Java application launcher. +Passes \f[I]option\f[R] to the JDB JVM, where option is one of the +options described on the reference page for the Java application +launcher. For example, \f[CB]\-J\-Xms48m\f[R] sets the startup memory to 48 MB. See \f[I]Overview of Java Options\f[R] in \f[B]java\f[R]. .RS @@ -239,6 +240,15 @@ See \f[I]Overview of Java Options\f[R] in \f[B]java\f[R]. .PP The following options are forwarded to the debuggee process: .TP +.B \f[CB]\-R\f[R]\f[I]option\f[R] +Passes \f[I]option\f[R] to the debuggee JVM, where option is one of the +options described on the reference page for the Java application +launcher. +For example, \f[CB]\-R\-Xms48m\f[R] sets the startup memory to 48 MB. +See \f[I]Overview of Java Options\f[R] in \f[B]java\f[R]. +.RS +.RE +.TP .B \f[CB]\-v\f[R] or \f[CB]\-verbose\f[R][\f[CB]:\f[R]\f[I]class\f[R]|\f[CB]gc\f[R]|\f[CB]jni\f[R]] Turns on the verbose mode. .RS diff --git a/src/jdk.jdwp.agent/share/native/libjdwp/ArrayTypeImpl.c b/src/jdk.jdwp.agent/share/native/libjdwp/ArrayTypeImpl.c index c1631c2993827561caa50839896fdfbd53879afe..4176f0171d24228c7ee684a68ed099f6d49f18c9 100644 --- a/src/jdk.jdwp.agent/share/native/libjdwp/ArrayTypeImpl.c +++ b/src/jdk.jdwp.agent/share/native/libjdwp/ArrayTypeImpl.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -227,7 +227,7 @@ newInstance(PacketInputStream *in, PacketOutputStream *out) error = classSignature(arrayClass, &signature, NULL); if ( error != JVMTI_ERROR_NONE ) { outStream_setError(out, map2jdwpError(error)); - return JNI_FALSE; + return JNI_TRUE; } componentSignature = componentTypeSignature(signature); diff --git a/src/jdk.jdwp.agent/share/native/libjdwp/classTrack.c b/src/jdk.jdwp.agent/share/native/libjdwp/classTrack.c index 62513115234d87b0dfae3cf354db3b1b830ec220..613b02c8d1e20d0634c3bfe4b87608bb3be70d6b 100644 --- a/src/jdk.jdwp.agent/share/native/libjdwp/classTrack.c +++ b/src/jdk.jdwp.agent/share/native/libjdwp/classTrack.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -81,14 +81,22 @@ cbTrackingObjectFree(jvmtiEnv* jvmti_env, jlong tag) struct bag * classTrack_processUnloads(JNIEnv *env) { - debugMonitorEnter(classTrackLock); if (deletedSignatures == NULL) { - // Class tracking not initialized, nobody's interested. - debugMonitorExit(classTrackLock); - return NULL; + return NULL; } + + /* Allocate new bag outside classTrackLock lock to avoid deadlock. + * + * Note: jvmtiAllocate/jvmtiDeallocate() may be blocked by ongoing safepoints. + * It is dangerous to call them (via bagCreateBag/bagDestroyBag()) while holding monitor(s), + * because jvmti may post events, e.g. JVMTI_EVENT_OBJECT_FREE at safepoints and event processing + * code may acquire the same monitor(s), e.g. classTrackLock in cbTrackingObjectFree(), + * which can lead to deadlock. + */ + struct bag* new_bag = bagCreateBag(sizeof(char*), 10); + debugMonitorEnter(classTrackLock); struct bag* deleted = deletedSignatures; - deletedSignatures = bagCreateBag(sizeof(char*), 10); + deletedSignatures = new_bag; debugMonitorExit(classTrackLock); return deleted; } @@ -102,21 +110,28 @@ classTrack_addPreparedClass(JNIEnv *env_unused, jclass klass) jvmtiError error; jvmtiEnv* env = trackingEnv; + char* signature; + error = classSignature(klass, &signature, NULL); + if (error != JVMTI_ERROR_NONE) { + EXIT_ERROR(error,"signature"); + } + if (gdata && gdata->assertOn) { - // Check this is not already tagged. + // Check if already tagged. jlong tag; error = JVMTI_FUNC_PTR(trackingEnv, GetTag)(env, klass, &tag); if (error != JVMTI_ERROR_NONE) { EXIT_ERROR(error, "Unable to GetTag with class trackingEnv"); } - JDI_ASSERT(tag == NOT_TAGGED); + if (tag != NOT_TAGGED) { + // If tagged, the old tag better be the same as the new. + char* oldSignature = (char*)jlong_to_ptr(tag); + JDI_ASSERT(strcmp(signature, oldSignature) == 0); + jvmtiDeallocate(signature); + return; + } } - char* signature; - error = classSignature(klass, &signature, NULL); - if (error != JVMTI_ERROR_NONE) { - EXIT_ERROR(error,"signature"); - } error = JVMTI_FUNC_PTR(trackingEnv, SetTag)(env, klass, ptr_to_jlong(signature)); if (error != JVMTI_ERROR_NONE) { jvmtiDeallocate(signature); @@ -194,8 +209,11 @@ classTrack_initialize(JNIEnv *env) void classTrack_activate(JNIEnv *env) { + // Allocate bag outside classTrackLock lock to avoid deadlock. + // See comments in classTrack_processUnloads() for details. + struct bag* new_bag = bagCreateBag(sizeof(char*), 1000); debugMonitorEnter(classTrackLock); - deletedSignatures = bagCreateBag(sizeof(char*), 1000); + deletedSignatures = new_bag; debugMonitorExit(classTrackLock); } @@ -214,12 +232,14 @@ void classTrack_reset(void) { debugMonitorEnter(classTrackLock); + struct bag* to_delete = deletedSignatures; + deletedSignatures = NULL; + debugMonitorExit(classTrackLock); - if (deletedSignatures != NULL) { - bagEnumerateOver(deletedSignatures, cleanDeleted, NULL); - bagDestroyBag(deletedSignatures); - deletedSignatures = NULL; + // Deallocate bag outside classTrackLock to avoid deadlock. + // See comments in classTrack_processUnloads() for details. + if (to_delete != NULL) { + bagEnumerateOver(to_delete, cleanDeleted, NULL); + bagDestroyBag(to_delete); } - - debugMonitorExit(classTrackLock); } diff --git a/src/jdk.jdwp.agent/share/native/libjdwp/commonRef.c b/src/jdk.jdwp.agent/share/native/libjdwp/commonRef.c index bc7ddb660bf048714b5aea061bb2e99e5c866c46..d55c517332bd93f0e8df04b6178c628260f014ea 100644 --- a/src/jdk.jdwp.agent/share/native/libjdwp/commonRef.c +++ b/src/jdk.jdwp.agent/share/native/libjdwp/commonRef.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -82,6 +82,14 @@ newSeqNum(void) return gdata->nextSeqNum++; } +/* Returns true if this is a strong reference, meaning that either or both of + isPinAll and isCommonPin are true. */ +static jboolean +isStrong(RefNode* node) +{ + return node->isPinAll || node->isCommonPin; +} + /* Create a fresh RefNode structure, create a weak ref and tag the object */ static RefNode * createNode(JNIEnv *env, jobject ref) @@ -89,7 +97,7 @@ createNode(JNIEnv *env, jobject ref) RefNode *node; jobject strongOrWeakRef; jvmtiError error; - jboolean pin = gdata->pinAllCount != 0; + jboolean pinAll = gdata->pinAllCount != 0; /* Could allocate RefNode's in blocks, not sure it would help much */ node = (RefNode*)jvmtiAllocate((int)sizeof(RefNode)); @@ -97,7 +105,7 @@ createNode(JNIEnv *env, jobject ref) return NULL; } - if (pin) { + if (pinAll) { /* Create strong reference to make sure we have a reference */ strongOrWeakRef = JNI_FUNC_PTR(env,NewGlobalRef)(env, ref); } else { @@ -116,7 +124,7 @@ createNode(JNIEnv *env, jobject ref) error = JVMTI_FUNC_PTR(gdata->jvmti, SetTag) (gdata->jvmti, strongOrWeakRef, ptr_to_jlong(node)); if ( error != JVMTI_ERROR_NONE ) { - if (pin) { + if (pinAll) { JNI_FUNC_PTR(env,DeleteGlobalRef)(env, strongOrWeakRef); } else { JNI_FUNC_PTR(env,DeleteWeakGlobalRef)(env, strongOrWeakRef); @@ -128,7 +136,8 @@ createNode(JNIEnv *env, jobject ref) /* Fill in RefNode */ node->ref = strongOrWeakRef; node->count = 1; - node->strongCount = pin ? 1 : 0; + node->isPinAll = pinAll; + node->isCommonPin = JNI_FALSE; node->seqNum = newSeqNum(); /* Count RefNode's created */ @@ -146,7 +155,7 @@ deleteNode(JNIEnv *env, RefNode *node) /* Clear tag */ (void)JVMTI_FUNC_PTR(gdata->jvmti,SetTag) (gdata->jvmti, node->ref, NULL_OBJECT_ID); - if (node->strongCount != 0) { + if (isStrong(node)) { JNI_FUNC_PTR(env,DeleteGlobalRef)(env, node->ref); } else { JNI_FUNC_PTR(env,DeleteWeakGlobalRef)(env, node->ref); @@ -158,9 +167,9 @@ deleteNode(JNIEnv *env, RefNode *node) /* Change a RefNode to have a strong reference */ static jobject -strengthenNode(JNIEnv *env, RefNode *node) +strengthenNode(JNIEnv *env, RefNode *node, jboolean isPinAll) { - if (node->strongCount == 0) { + if (!isStrong(node)) { jobject strongRef; strongRef = JNI_FUNC_PTR(env,NewGlobalRef)(env, node->ref); @@ -176,20 +185,27 @@ strengthenNode(JNIEnv *env, RefNode *node) if (strongRef != NULL) { JNI_FUNC_PTR(env,DeleteWeakGlobalRef)(env, node->ref); node->ref = strongRef; - node->strongCount = 1; + } else { + return NULL; } - return strongRef; + } + if (isPinAll) { + node->isPinAll = JNI_TRUE; } else { - node->strongCount++; - return node->ref; + node->isCommonPin = JNI_TRUE; } + return node->ref; } /* Change a RefNode to have a weak reference */ static jweak -weakenNode(JNIEnv *env, RefNode *node) +weakenNode(JNIEnv *env, RefNode *node, jboolean isUnpinAll) { - if (node->strongCount == 1) { + jboolean willStillBeStrong = (node->isPinAll && !isUnpinAll) || (node->isCommonPin && isUnpinAll); + + // If the node is strong, but the reason(s) for it being strong + // will no longer exist, then weaken it. + if (isStrong(node) && !willStillBeStrong) { jweak weakRef; weakRef = JNI_FUNC_PTR(env,NewWeakGlobalRef)(env, node->ref); @@ -200,16 +216,18 @@ weakenNode(JNIEnv *env, RefNode *node) if (weakRef != NULL) { JNI_FUNC_PTR(env,DeleteGlobalRef)(env, node->ref); - node->ref = weakRef; - node->strongCount = 0; + node->ref = weakRef; + } else { + return NULL; } - return weakRef; + } + + if (isUnpinAll) { + node->isPinAll = JNI_FALSE; } else { - if (node->strongCount > 0) { - node->strongCount--; - } - return node->ref; + node->isCommonPin = JNI_FALSE; } + return node->ref; } /* @@ -470,7 +488,7 @@ commonRef_idToRef(JNIEnv *env, jlong id) node = findNodeByID(env, id); if (node != NULL) { - if (node->strongCount != 0) { + if (isStrong(node)) { saveGlobalRef(env, node->ref, &ref); } else { jobject lref; @@ -522,7 +540,7 @@ commonRef_pin(jlong id) } else { jobject strongRef; - strongRef = strengthenNode(env, node); + strongRef = strengthenNode(env, node, JNI_FALSE /* isPinAll */); if (strongRef == NULL) { /* * Referent has been collected, clean up now. @@ -551,7 +569,7 @@ commonRef_unpin(jlong id) if (node != NULL) { jweak weakRef; - weakRef = weakenNode(env, node); + weakRef = weakenNode(env, node, JNI_FALSE /* isUnpinAll */); if (weakRef == NULL) { error = AGENT_ERROR_OUT_OF_MEMORY; } @@ -585,7 +603,7 @@ commonRef_pinAll() while (node != NULL) { jobject strongRef; - strongRef = strengthenNode(env, node); + strongRef = strengthenNode(env, node, JNI_TRUE /* isPinAll */); /* Has the object been collected? */ if (strongRef == NULL) { @@ -628,7 +646,7 @@ commonRef_unpinAll() for (node = gdata->objectsByID[i]; node != NULL; node = node->next) { jweak weakRef; - weakRef = weakenNode(env, node); + weakRef = weakenNode(env, node, JNI_TRUE /* isUnpinAll */); if (weakRef == NULL) { EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"NewWeakGlobalRef"); } @@ -676,8 +694,7 @@ commonRef_compact(void) prev = NULL; while (node != NULL) { /* Has the object been collected? */ - if ( (node->strongCount == 0) && - isSameObject(env, node->ref, NULL)) { + if (!isStrong(node) && isSameObject(env, node->ref, NULL)) { RefNode *freed; /* Detach from the ID list */ diff --git a/src/jdk.jdwp.agent/share/native/libjdwp/eventHandler.c b/src/jdk.jdwp.agent/share/native/libjdwp/eventHandler.c index 7b11afa92253f1545c338591c162908b96f2c028..210849bc13a9997e84a607a238096687c2406a85 100644 --- a/src/jdk.jdwp.agent/share/native/libjdwp/eventHandler.c +++ b/src/jdk.jdwp.agent/share/native/libjdwp/eventHandler.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -534,6 +534,62 @@ synthesizeUnloadEvent(void *signatureVoid, void *envVoid) /* Garbage Collection Happened */ static unsigned int garbageCollected = 0; +/* + * Run the event through each HandlerNode's filter, and if it passes, call the HandlerNode's + * HandlerFunction for the event, and then report all accumulated events to the debugger. + */ +static void +filterAndHandleEvent(JNIEnv *env, EventInfo *evinfo, EventIndex ei, + struct bag *eventBag, jbyte eventSessionID) +{ + debugMonitorEnter(handlerLock); + { + HandlerNode *node; + char *classname; + + /* We must keep track of all classes prepared to know what's unloaded */ + if (evinfo->ei == EI_CLASS_PREPARE) { + classTrack_addPreparedClass(env, evinfo->clazz); + } + + node = getHandlerChain(ei)->first; + classname = getClassname(evinfo->clazz); + + /* Filter the event over each handler node. */ + while (node != NULL) { + /* Save next so handlers can remove themselves. */ + HandlerNode *next = NEXT(node); + jboolean shouldDelete; + + if (eventFilterRestricted_passesFilter(env, classname, + evinfo, node, + &shouldDelete)) { + HandlerFunction func = HANDLER_FUNCTION(node); + if (func == NULL) { + EXIT_ERROR(AGENT_ERROR_INTERNAL,"handler function NULL"); + } + /* Handle the event by calling the event handler. */ + (*func)(env, evinfo, node, eventBag); + } + if (shouldDelete) { + /* We can safely free the node now that we are done using it. */ + (void)freeHandler(node); + } + node = next; + } + jvmtiDeallocate(classname); + } + debugMonitorExit(handlerLock); + + /* + * The events destined for the debugger were accumulated in eventBag. Report all these events. + */ + if (eventBag != NULL) { + reportEvents(env, eventSessionID, evinfo->thread, evinfo->ei, + evinfo->clazz, evinfo->method, evinfo->location, eventBag); + } +} + /* * The JVMTI generic event callback. Each event is passed to a sequence of * handlers in a chain until the chain ends or one handler @@ -634,51 +690,7 @@ event_callback(JNIEnv *env, EventInfo *evinfo) } } - debugMonitorEnter(handlerLock); - { - HandlerNode *node; - char *classname; - - /* We must keep track of all classes prepared to know what's unloaded */ - if (evinfo->ei == EI_CLASS_PREPARE) { - classTrack_addPreparedClass(env, evinfo->clazz); - } - - node = getHandlerChain(evinfo->ei)->first; - classname = getClassname(evinfo->clazz); - - while (node != NULL) { - /* save next so handlers can remove themselves */ - HandlerNode *next = NEXT(node); - jboolean shouldDelete; - - if (eventFilterRestricted_passesFilter(env, classname, - evinfo, node, - &shouldDelete)) { - HandlerFunction func; - - func = HANDLER_FUNCTION(node); - if ( func == NULL ) { - EXIT_ERROR(AGENT_ERROR_INTERNAL,"handler function NULL"); - } - (*func)(env, evinfo, node, eventBag); - } - if (shouldDelete) { - /* We can safely free the node now that we are done - * using it. - */ - (void)freeHandler(node); - } - node = next; - } - jvmtiDeallocate(classname); - } - debugMonitorExit(handlerLock); - - if (eventBag != NULL) { - reportEvents(env, eventSessionID, thread, evinfo->ei, - evinfo->clazz, evinfo->method, evinfo->location, eventBag); - } + filterAndHandleEvent(env, evinfo, ei, eventBag, eventSessionID); /* we are continuing after VMDeathEvent - now we are dead */ if (evinfo->ei == EI_VM_DEATH) { diff --git a/src/jdk.jdwp.agent/share/native/libjdwp/invoker.c b/src/jdk.jdwp.agent/share/native/libjdwp/invoker.c index fdc7a0bc613aa07a05c1c9e9c842ebc85ccaa97b..2f6eb5f40a1ac20b2e8962f02b6e36e5dca0c954 100644 --- a/src/jdk.jdwp.agent/share/native/libjdwp/invoker.c +++ b/src/jdk.jdwp.agent/share/native/libjdwp/invoker.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -232,6 +232,7 @@ fillInvokeRequest(JNIEnv *env, InvokeRequest *request, /* * Squirrel away the method signature */ + JDI_ASSERT_MSG(request->methodSignature == NULL, "Request methodSignature not null"); error = methodSignature(method, NULL, &request->methodSignature, NULL); if (error != JVMTI_ERROR_NONE) { return error; @@ -752,7 +753,9 @@ invoker_completeInvokeRequest(jthread thread) } id = request->id; exc = request->exception; + request->exception = NULL; returnValue = request->returnValue; + request->returnValue.l = NULL; /* Release return value and exception references, but delay the release * until after the return packet was sent. */ @@ -773,6 +776,10 @@ invoker_completeInvokeRequest(jthread thread) */ deleteGlobalArgumentRefs(env, request); + JDI_ASSERT_MSG(request->methodSignature != NULL, "methodSignature is NULL"); + jvmtiDeallocate(request->methodSignature); + request->methodSignature = NULL; + /* From now on, do not access the request structure anymore * for this request id, because once we give up the invokerLock it may * be immediately reused by a new invoke request. @@ -790,23 +797,20 @@ invoker_completeInvokeRequest(jthread thread) (void)outStream_writeValue(env, &out, tag, returnValue); (void)outStream_writeObjectTag(env, &out, exc); (void)outStream_writeObjectRef(env, &out, exc); + /* + * Delete potentially saved global references for return value + * and exception. This must be done before sending the reply or + * these objects will briefly be viewable by the debugger as live + * when they shouldn't be. + */ + if (mustReleaseReturnValue && returnValue.l != NULL) { + tossGlobalRef(env, &returnValue.l); + } + if (exc != NULL) { + tossGlobalRef(env, &exc); + } outStream_sendReply(&out); } - - /* - * Delete potentially saved global references of return value - * and exception - */ - eventHandler_lock(); // for proper lock order - debugMonitorEnter(invokerLock); - if (mustReleaseReturnValue && returnValue.l != NULL) { - tossGlobalRef(env, &returnValue.l); - } - if (exc != NULL) { - tossGlobalRef(env, &exc); - } - debugMonitorExit(invokerLock); - eventHandler_unlock(); } jboolean diff --git a/src/jdk.jdwp.agent/share/native/libjdwp/stepControl.c b/src/jdk.jdwp.agent/share/native/libjdwp/stepControl.c index a819d7e3fbfdf598d17ea75afef74f4fcfbecaac..adf38547c39433c29decc7487101f3454d2aac42 100644 --- a/src/jdk.jdwp.agent/share/native/libjdwp/stepControl.c +++ b/src/jdk.jdwp.agent/share/native/libjdwp/stepControl.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -463,14 +463,18 @@ handleMethodEnterEvent(JNIEnv *env, EventInfo *evinfo, */ JDI_ASSERT(step->depth == JDWP_STEP_DEPTH(INTO)); - if ( (!eventFilter_predictFiltering(step->stepHandlerNode, - clazz, classname)) - && ( step->granularity != JDWP_STEP_SIZE(LINE) - || hasLineNumbers(method) ) ) { + /* + * We need to figure out if we are entering a method that we want to resume + * single stepping in. If the class of this method is being filtered out, then + * we don't resume. Otherwise, if we are not line stepping then we resume, and + * if we are line stepping we don't resume unless the method has LineNumbers. + */ + jboolean filteredOut = eventFilter_predictFiltering(step->stepHandlerNode, clazz, classname); + jboolean isStepLine = step->granularity == JDWP_STEP_SIZE(LINE); + if (!filteredOut && (!isStepLine || hasLineNumbers(method))) { /* - * We've found a suitable method in which to stop. Step - * until we reach the next safe location to complete the step->, - * and we can get rid of the method entry handler. + * We've found a suitable method in which to resume stepping. + * We can also get rid of the method entry handler now. */ enableStepping(thread); if ( step->methodEnterHandlerNode != NULL ) { diff --git a/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c b/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c index a130006a5fc8a7d9c8c280e3bd0a8f47b4d2a3dc..eae26521f67cc4db99f4180d43eca92d35aed316 100644 --- a/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c +++ b/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -69,7 +69,7 @@ typedef struct ThreadNode { unsigned int pendingInterrupt : 1; /* true if thread is interrupted while handling an event. */ unsigned int isDebugThread : 1; /* true if this is one of our debug agent threads. */ unsigned int suspendOnStart : 1; /* true for new threads if we are currently in a VM.suspend(). */ - unsigned int isStarted : 1; /* THREAD_START or VIRTUAL_THREAD_SCHEDULED event received. */ + unsigned int isStarted : 1; /* THREAD_START event received. */ unsigned int popFrameEvent : 1; unsigned int popFrameProceed : 1; unsigned int popFrameThread : 1; diff --git a/src/jdk.jdwp.agent/share/native/libjdwp/util.h b/src/jdk.jdwp.agent/share/native/libjdwp/util.h index 134bf03db7aae089a6f6ef196df31ce1b8e378d1..0619648d9579960ba430950ce8ce474dc038df7b 100644 --- a/src/jdk.jdwp.agent/share/native/libjdwp/util.h +++ b/src/jdk.jdwp.agent/share/native/libjdwp/util.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -65,7 +65,8 @@ typedef struct RefNode { jobject ref; /* could be strong or weak */ struct RefNode *next; /* next RefNode* in bucket chain */ jint count; /* count of references */ - unsigned strongCount; /* count of strong reference */ + jboolean isPinAll; /* true if this is a strong reference due to a commonRef_pinAll() */ + jboolean isCommonPin; /* true if this is a strong reference due to a commonRef_pin() */ } RefNode; /* Value of a NULL ID */ diff --git a/src/jdk.jfr/share/classes/jdk/jfr/AnnotationElement.java b/src/jdk.jfr/share/classes/jdk/jfr/AnnotationElement.java index 19c1f4db14f84d64171d7a47f941646e19bbbe88..9bb9ca70343cf7a0017110bf49f8f895d4bc6a5c 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/AnnotationElement.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/AnnotationElement.java @@ -46,22 +46,7 @@ import jdk.jfr.internal.Utils; * <p> * The following example shows how {@code AnnotationElement} can be used to dynamically define events. * - * <pre>{@literal - * List<AnnotationElement> typeAnnotations = new ArrayList<>(); - * typeAnnotations.add(new AnnotationElement(Name.class, "com.example.HelloWorld")); - * typeAnnotations.add(new AnnotationElement(Label.class, "Hello World")); - * typeAnnotations.add(new AnnotationElement(Description.class, "Helps programmer getting started")); - * - * List<AnnotationElement> fieldAnnotations = new ArrayList<>(); - * fieldAnnotations.add(new AnnotationElement(Label.class, "Message")); - * - * List<ValueDescriptor> fields = new ArrayList<>(); - * fields.add(new ValueDescriptor(String.class, "message", fieldAnnotations)); - * - * EventFactory f = EventFactory.create(typeAnnotations, fields); - * Event event = f.newEvent(); - * event.commit(); - * }</pre> + * {@snippet class="Snippets" region="AnnotationElementOverview"} * * @since 9 */ @@ -127,8 +112,8 @@ public final class AnnotationElement { * signatures in the {@code annotationType} */ public AnnotationElement(Class<? extends Annotation> annotationType, Map<String, Object> values) { - Objects.requireNonNull(annotationType); - Objects.requireNonNull(values); + Objects.requireNonNull(annotationType, "annotationType"); + Objects.requireNonNull(values, "values"); Utils.checkRegisterPermission(); // copy values to avoid modification after validation HashMap<String, Object> map = new HashMap<>(values); @@ -307,7 +292,7 @@ public final class AnnotationElement { * not exist in the annotation */ public Object getValue(String name) { - Objects.requireNonNull(name); + Objects.requireNonNull(name, "name"); int index = type.indexOf(name); if (index != -1) { return annotationValues.get(index); @@ -329,7 +314,7 @@ public final class AnnotationElement { * @return {@code true} if method exists, {@code false} otherwise */ public boolean hasValue(String name) { - Objects.requireNonNull(name); + Objects.requireNonNull(name, "name"); return type.indexOf(name) != -1; } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/Configuration.java b/src/jdk.jfr/share/classes/jdk/jfr/Configuration.java index f95647e3fb5a4f286bc4026f3f4fbfbb32d536d1..5afd5e1a7da941c68ae6c350ae0f116562cddc76 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/Configuration.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/Configuration.java @@ -138,7 +138,7 @@ public final class Configuration { * @see java.lang.SecurityManager#checkRead(java.lang.String) */ public static Configuration create(Path path) throws IOException, ParseException { - Objects.requireNonNull(path); + Objects.requireNonNull(path, "path"); JVMSupport.ensureWithIOException(); try (Reader reader = Files.newBufferedReader(path)) { return JFC.create(JFC.nameFromPath(path), reader); @@ -156,7 +156,7 @@ public final class Configuration { * @throws ParseException if the file can't be parsed */ public static Configuration create(Reader reader) throws IOException, ParseException { - Objects.requireNonNull(reader); + Objects.requireNonNull(reader, "reader"); JVMSupport.ensureWithIOException(); return JFC.create(null, reader); } @@ -177,6 +177,7 @@ public final class Configuration { * @throws ParseException if the configuration file can't be parsed */ public static Configuration getConfiguration(String name) throws IOException, ParseException { + Objects.requireNonNull(name, "name"); JVMSupport.ensureWithIOException(); return JFC.getPredefined(name); } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/ContentType.java b/src/jdk.jfr/share/classes/jdk/jfr/ContentType.java index 13a5ae226ba133d93145b9cf83664a872987828f..3580997ad240a4e851e15612b2ed7785aa32c0c9 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/ContentType.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/ContentType.java @@ -33,6 +33,22 @@ import java.lang.annotation.Target; /** * Meta annotation, specifies that an annotation represents a content type, such * as a time span or a frequency. + * <p> + * The following example shows how a temperature content type can be created and + * used. + * <p> + * First declare a temperature annotation using the {@code ContentType} + * annotation: + * + * {@snippet class="Snippets" region="ContentTypeDeclaration"} + * + * Then declare an event, annotate a field and commit the data: + * + * {@snippet class="Snippets" region="ContentTypeEvent"} + * + * Finally, inspect the annotation when displaying event data: + * + * {@snippet class="Snippets" region="ContentTypeConsumption"} * * @since 9 */ diff --git a/src/jdk.jfr/share/classes/jdk/jfr/Event.java b/src/jdk.jfr/share/classes/jdk/jfr/Event.java index be9ed57eebe018c0a77660d1de25ecfbfb05f45e..c33d7749b5c0ead0efe1e486956123c7712624ab 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/Event.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/Event.java @@ -31,27 +31,7 @@ package jdk.jfr; * <p> * The following example shows how to implement an {@code Event} class. * - * <pre>{@literal - * import jdk.jfr.Event; - * import jdk.jfr.Description; - * import jdk.jfr.Label; - * - * public class Example { - * - * @Label("Hello World") - * @Description("Helps programmer getting started") - * static class HelloWorld extends Event { - * @Label("Message") - * String message; - * } - * - * public static void main(String... args) { - * HelloWorld event = new HelloWorld(); - * event.message = "hello, world!"; - * event.commit(); - * } - * } - * }</pre> + * {@snippet class="Snippets" region="EventOverview"} * <p> * After an event is allocated and its field members are populated, it can be * written to the Flight Recorder system by using the {@link #commit()} method. diff --git a/src/jdk.jfr/share/classes/jdk/jfr/EventFactory.java b/src/jdk.jfr/share/classes/jdk/jfr/EventFactory.java index 71b08e74baa15db4ad187702c0a930caee734d57..614bece20adda93505e724c9c1145341493c6e6f 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/EventFactory.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/EventFactory.java @@ -52,29 +52,7 @@ import jdk.jfr.internal.Utils; * <p> * The following example shows how to implement a dynamic {@code Event} class. * - * <pre> - * {@code - * List<ValueDescriptor> fields = new ArrayList<>(); - * List<AnnotationElement> messageAnnotations = Collections.singletonList(new AnnotationElement(Label.class, "Message")); - * fields.add(new ValueDescriptor(String.class, "message", messageAnnotations)); - * List<AnnotationElement> numberAnnotations = Collections.singletonList(new AnnotationElement(Label.class, "Number")); - * fields.add(new ValueDescriptor(int.class, "number", numberAnnotations)); - * - * String[] category = { "Example", "Getting Started" }; - * List<AnnotationElement> eventAnnotations = new ArrayList<>(); - * eventAnnotations.add(new AnnotationElement(Name.class, "com.example.HelloWorld")); - * eventAnnotations.add(new AnnotationElement(Label.class, "Hello World")); - * eventAnnotations.add(new AnnotationElement(Description.class, "Helps programmer getting started")); - * eventAnnotations.add(new AnnotationElement(Category.class, category)); - * - * EventFactory f = EventFactory.create(eventAnnotations, fields); - * - * Event event = f.newEvent(); - * event.set(0, "hello, world!"); - * event.set(1, 4711); - * event.commit(); - * } - * </pre> + * {@snippet class="Snippets" region="EventFactoryOverview"} * * @since 9 */ @@ -119,8 +97,8 @@ public final class EventFactory { * @see Event#set(int, Object) */ public static EventFactory create(List<AnnotationElement> annotationElements, List<ValueDescriptor> fields) { - Objects.requireNonNull(fields); - Objects.requireNonNull(annotationElements); + Objects.requireNonNull(annotationElements, "annotationElements"); + Objects.requireNonNull(fields, "fields"); JVMSupport.ensureWithInternalError(); Utils.checkRegisterPermission(); diff --git a/src/jdk.jfr/share/classes/jdk/jfr/EventSettings.java b/src/jdk.jfr/share/classes/jdk/jfr/EventSettings.java index 0d4c20aad45b02955786316ef22de164ca9e6d7e..17ce98d166c3360c2028cf1f90a23221837e93b1 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/EventSettings.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/EventSettings.java @@ -27,6 +27,7 @@ package jdk.jfr; import java.time.Duration; import java.util.Map; +import java.util.Objects; import jdk.jfr.internal.management.EventSettingsModifier; @@ -38,21 +39,9 @@ import jdk.jfr.internal.management.EventSettingsModifier; * chaining. * <p> * The following example shows how to use the {@code EventSettings} class. - * <pre> - * {@code - * Recording r = new Recording(); - * r.enable("jdk.CPULoad") - * .withPeriod(Duration.ofSeconds(1)); - * r.enable("jdk.FileWrite") - * .withoutStackTrace() - * .withThreshold(Duration.ofNanos(10)); - * r.start(); - * Thread.sleep(10_000); - * r.stop(); - * r.dump(Files.createTempFile("recording", ".jfr")); * - * } - * </pre> + * {@snippet class="Snippets" region="EventSettingOverview"} + * * @since 9 */ public abstract class EventSettings { @@ -67,8 +56,10 @@ public abstract class EventSettings { @Override public EventSettings with(String name, String value) { - delegate.with(name, value); - return this; + Objects.requireNonNull(name, "name"); + Objects.requireNonNull(value, "value"); + delegate.with(name, value); + return this; } @Override @@ -123,6 +114,7 @@ public abstract class EventSettings { * @return event settings object for further configuration, not {@code null} */ public final EventSettings withPeriod(Duration duration) { + Objects.requireNonNull(duration, "duration"); return with(Period.NAME, duration.toNanos() + " ns"); } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/EventType.java b/src/jdk.jfr/share/classes/jdk/jfr/EventType.java index 27bb9825abd6dfb8070b64e61597472e1feed478..3d069fe8e396c79eab66e86d3779e77ba4930bae 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/EventType.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/EventType.java @@ -75,7 +75,7 @@ public final class EventType { * the field with the specified name doesn't exist */ public ValueDescriptor getField(String name) { - Objects.requireNonNull(name); + Objects.requireNonNull(name, "name"); if (cache == null) { List<ValueDescriptor> fields = getFields(); Map<String, ValueDescriptor> newCache = new LinkedHashMap<>(fields.size()); @@ -181,7 +181,7 @@ public final class EventType { * directly present, else {@code null} */ public <A extends Annotation> A getAnnotation(Class<A> annotationClass) { - Objects.requireNonNull(annotationClass); + Objects.requireNonNull(annotationClass, "annotationClass"); return platformEventType.getAnnotation(annotationClass); } @@ -198,7 +198,7 @@ public final class EventType { * {@code Registered(false)}, but not manually registered */ public static EventType getEventType(Class<? extends Event> eventClass) { - Objects.requireNonNull(eventClass); + Objects.requireNonNull(eventClass, "eventClass"); Utils.ensureValidEventSubclass(eventClass); JVMSupport.ensureWithInternalError(); return MetadataRepository.getInstance().getEventType(eventClass); @@ -241,4 +241,9 @@ public final class EventType { PlatformEventType getPlatformEventType() { return platformEventType; } + + // package private + boolean isVisible() { + return platformEventType.isVisible(); + } } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/FlightRecorder.java b/src/jdk.jfr/share/classes/jdk/jfr/FlightRecorder.java index b7f558a17cbe60cf31a6d41bb94165aee854cce6..27cc96507ee6eeaa156446f3082be099eb1b36db 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/FlightRecorder.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/FlightRecorder.java @@ -92,15 +92,7 @@ public final class FlightRecorder { * <p> * The following example shows how to create a snapshot and write a subset of the data to a file. * - * <pre>{@literal - * try (Recording snapshot = FlightRecorder.getFlightRecorder().takeSnapshot()) { - * if (snapshot.getSize() > 0) { - * snapshot.setMaxSize(100_000_000); - * snapshot.setMaxAge(Duration.ofMinutes(5)); - * snapshot.dump(Paths.get("snapshot.jfr")); - * } - * } - * }</pre> + * {@snippet class="Snippets" region="FlightRecorderTakeSnapshot"} * * The caller must close the recording when access to the data is no longer * needed. @@ -128,7 +120,7 @@ public final class FlightRecorder { * does not have {@code FlightRecorderPermission("registerEvent")} */ public static void register(Class<? extends Event> eventClass) { - Objects.requireNonNull(eventClass); + Objects.requireNonNull(eventClass, "eventClass"); if (JVMSupport.isNotAvailable()) { return; } @@ -150,7 +142,7 @@ public final class FlightRecorder { * does not have {@code FlightRecorderPermission("registerEvent")} */ public static void unregister(Class<? extends Event> eventClass) { - Objects.requireNonNull(eventClass); + Objects.requireNonNull(eventClass, "eventClass"); if (JVMSupport.isNotAvailable()) { return; } @@ -192,7 +184,6 @@ public final class FlightRecorder { Logger.log(JFR, DEBUG, "globalbuffersize: " + Options.getGlobalBufferSize()+ " bytes"); Logger.log(JFR, DEBUG, "globalbuffercount: " + Options.getGlobalBufferCount()); Logger.log(JFR, DEBUG, "dumppath: " + Options.getDumpPath()); - Logger.log(JFR, DEBUG, "samplethreads: " + Options.getSampleThreads()); Logger.log(JFR, DEBUG, "stackdepth: " + Options.getStackDepth()); Logger.log(JFR, DEBUG, "threadbuffersize: " + Options.getThreadBufferSize()); } @@ -224,8 +215,8 @@ public final class FlightRecorder { * does not have {@code FlightRecorderPermission("registerEvent")} */ public static void addPeriodicEvent(Class<? extends Event> eventClass, Runnable hook) throws SecurityException { - Objects.requireNonNull(eventClass); - Objects.requireNonNull(hook); + Objects.requireNonNull(eventClass, "eventClass"); + Objects.requireNonNull(hook, "hook"); if (JVMSupport.isNotAvailable()) { return; } @@ -246,7 +237,7 @@ public final class FlightRecorder { * does not have {@code FlightRecorderPermission("registerEvent")} */ public static boolean removePeriodicEvent(Runnable hook) throws SecurityException { - Objects.requireNonNull(hook); + Objects.requireNonNull(hook, "hook"); Utils.checkRegisterPermission(); if (JVMSupport.isNotAvailable()) { return false; @@ -283,7 +274,7 @@ public final class FlightRecorder { * {@code FlightRecorderPermission("accessFlightRecorder")} */ public static void addListener(FlightRecorderListener changeListener) { - Objects.requireNonNull(changeListener); + Objects.requireNonNull(changeListener, "changeListener"); Utils.checkAccessFlightRecorder(); if (JVMSupport.isNotAvailable()) { return; @@ -307,7 +298,7 @@ public final class FlightRecorder { * otherwise */ public static boolean removeListener(FlightRecorderListener changeListener) { - Objects.requireNonNull(changeListener); + Objects.requireNonNull(changeListener, "changeListener"); Utils.checkAccessFlightRecorder(); if (JVMSupport.isNotAvailable()) { return false; diff --git a/src/jdk.jfr/share/classes/jdk/jfr/FlightRecorderPermission.java b/src/jdk.jfr/share/classes/jdk/jfr/FlightRecorderPermission.java index 789fa18fdb3008e82fdc1082b569d711ff1a0700..a76122c929a786f3b2f9815218582761d408f102 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/FlightRecorderPermission.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/FlightRecorderPermission.java @@ -203,6 +203,11 @@ public final class FlightRecorderPermission extends java.security.BasicPermissio public EventSettings newEventSettings(EventSettingsModifier esm) { return new EventSettings.DelegatedEventSettings(esm); } + + @Override + public boolean isVisible(EventType t) { + return t.isVisible(); + } } /** @@ -215,7 +220,7 @@ public final class FlightRecorderPermission extends java.security.BasicPermissio * @throws IllegalArgumentException if {@code name} is empty or not valid */ public FlightRecorderPermission(String name) { - super(Objects.requireNonNull(name)); + super(Objects.requireNonNull(name, "name")); if (!name.equals(Utils.ACCESS_FLIGHT_RECORDER) && !name.equals(Utils.REGISTER_EVENT)) { throw new IllegalArgumentException("name: " + name); } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/MetadataDefinition.java b/src/jdk.jfr/share/classes/jdk/jfr/MetadataDefinition.java index 919c7b01cff7967563fb2a1e67c4bda00945ff2d..56c669a2b348e0446ccd79c53ae236c502657ca2 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/MetadataDefinition.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/MetadataDefinition.java @@ -36,36 +36,7 @@ import java.lang.annotation.Target; * In the following example, a transaction event is defined with two * user-defined annotations, {@code @Severity} and {@code @TransactionId}. * - * <pre>{@literal - * @MetadataDefinition - * @Label("Severity") - * @Description("Value between 0 and 100 that indicates severity. 100 is most severe.") - * @Retention(RetentionPolicy.RUNTIME) - * @Target({ElementType.TYPE}) - * public @interface Severity { - * int value() default 50; - * } - * - * @MetadataDefinition - * @Label("Transaction Id") - * @Relational - * @Retention(RetentionPolicy.RUNTIME) - * @Target({ElementType.FIELD}) - * public @interface TransactionId { - * } - * - * @Severity(80) - * @Label("Transaction Blocked") - * class TransactionBlocked extends Event { - * @TransactionId - * @Label("Transaction") - * long transactionId1; - * - * @TransactionId - * @Label("Transaction Blocker") - * long transactionId2; - * } - * }</pre> + * {@snippet class="Snippets" region="MetadataDefinitionOverview"} * * Adding {@code @MetadataDefinition} to the declaration of {@code @Severity} and {@code @TransactionId} * ensures the information is saved by Flight Recorder. diff --git a/src/jdk.jfr/share/classes/jdk/jfr/Recording.java b/src/jdk.jfr/share/classes/jdk/jfr/Recording.java index 71ef9cebc258b26f2b2088ae4f1bb9c2bc7c80ea..c5c01f4370c525fbbc837352d3c10de94b53907f 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/Recording.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/Recording.java @@ -46,15 +46,7 @@ import jdk.jfr.internal.WriteableUserPath; * <p> * The following example shows how configure, start, stop and dump recording data to disk. * - * <pre>{@literal - * Configuration c = Configuration.getConfiguration("default"); - * Recording r = new Recording(c); - * r.start(); - * System.gc(); - * Thread.sleep(5000); - * r.stop(); - * r.dump(Files.createTempFile("my-recording", ".jfr")); - * }</pre> + * {@snippet class="Snippets" region="RecordingOverview"} * * @since 9 */ @@ -78,7 +70,8 @@ public final class Recording implements Closeable { @Override public EventSettings with(String name, String value) { - Objects.requireNonNull(value); + Objects.requireNonNull(name, "name"); + Objects.requireNonNull(value, "value"); recording.setSetting(identifier + "#" + name, value); return this; } @@ -109,7 +102,7 @@ public final class Recording implements Closeable { * @see jdk.jfr */ public Recording(Map<String, String> settings) { - Objects.requireNonNull(settings); + Objects.requireNonNull(settings, "settings"); Map<String, String> sanitized = Utils.sanitizeNullFreeStringMap(settings); PlatformRecorder r = FlightRecorder.getFlightRecorder().getInternal(); synchronized (r) { @@ -143,9 +136,9 @@ public final class Recording implements Closeable { * <p> * The following example shows how create a recording that uses a predefined configuration. * - * <pre>{@literal + * {@snippet : * Recording r = new Recording(Configuration.getConfiguration("default")); - * }</pre> + * } * * The newly created recording is in the {@link RecordingState#NEW} state. To * start the recording, invoke the {@link Recording#start()} method. @@ -163,7 +156,7 @@ public final class Recording implements Closeable { * @see Configuration */ public Recording(Configuration configuration) { - this(configuration.getSettings()); + this(Objects.requireNonNull(configuration, "configuration").getSettings()); } /** @@ -195,7 +188,7 @@ public final class Recording implements Closeable { * @throws IllegalStateException if the recording is not it the {@code NEW} state */ public void scheduleStart(Duration delay) { - Objects.requireNonNull(delay); + Objects.requireNonNull(delay, "delay"); internal.scheduleStart(delay); } @@ -307,26 +300,26 @@ public final class Recording implements Closeable { * <p> * The following example shows how to set event settings for a recording. * - * <pre>{@literal + * {@snippet : * Map<String, String> settings = new HashMap<>(); * settings.putAll(EventSettings.enabled("jdk.CPUSample").withPeriod(Duration.ofSeconds(2)).toMap()); * settings.putAll(EventSettings.enabled(MyEvent.class).withThreshold(Duration.ofSeconds(2)).withoutStackTrace().toMap()); * settings.put("jdk.ExecutionSample#period", "10 ms"); * recording.setSettings(settings); - * }</pre> + * } * * The following example shows how to merge settings. * - * <pre>{@literal + * {@snippet : * Map<String, String> settings = recording.getSettings(); * settings.putAll(additionalSettings); * recording.setSettings(settings); - * }</pre> + * } * * @param settings the settings to set, not {@code null} */ public void setSettings(Map<String, String> settings) { - Objects.requireNonNull(settings); + Objects.requireNonNull(settings, "settings"); Map<String, String> sanitized = Utils.sanitizeNullFreeStringMap(settings); internal.setSettings(sanitized); } @@ -383,7 +376,7 @@ public final class Recording implements Closeable { * have {@code FilePermission} to write to the destination path */ public void dump(Path destination) throws IOException { - Objects.requireNonNull(destination); + Objects.requireNonNull(destination, "destination"); internal.dump(new WriteableUserPath(destination)); } @@ -424,25 +417,6 @@ public final class Recording implements Closeable { internal.setMaxSize(maxSize); } - /** - * Determines how often events are made available for streaming. - * - * @param interval the interval at which events are made available for streaming. - * - * @throws IllegalArgumentException if {@code interval} is negative - * - * @throws IllegalStateException if the recording is in the {@code CLOSED} state - * - * @since 14 - */ - /*package private*/ void setFlushInterval(Duration interval) { - Objects.requireNonNull(interval); - if (interval.isNegative()) { - throw new IllegalArgumentException("Stream interval can't be negative"); - } - internal.setFlushInterval(interval); - } - /** * Returns how often events are made available for streaming purposes. * @@ -536,7 +510,7 @@ public final class Recording implements Closeable { * @throws IllegalStateException if the recording is in {@code CLOSED} state */ public void setName(String name) { - Objects.requireNonNull(name); + Objects.requireNonNull(name, "name"); internal.setName(name); } @@ -646,7 +620,7 @@ public final class Recording implements Closeable { * @see EventType */ public EventSettings enable(String name) { - Objects.requireNonNull(name); + Objects.requireNonNull(name, "name"); RecordingSettings rs = new RecordingSettings(this, name); rs.with("enabled", "true"); return rs; @@ -667,7 +641,7 @@ public final class Recording implements Closeable { * */ public EventSettings disable(String name) { - Objects.requireNonNull(name); + Objects.requireNonNull(name, "name"); RecordingSettings rs = new RecordingSettings(this, name); rs.with("enabled", "false"); return rs; @@ -684,7 +658,7 @@ public final class Recording implements Closeable { * @return an event setting for further configuration, not {@code null} */ public EventSettings enable(Class<? extends Event> eventClass) { - Objects.requireNonNull(eventClass); + Objects.requireNonNull(eventClass, "eventClass"); RecordingSettings rs = new RecordingSettings(this, eventClass); rs.with("enabled", "true"); return rs; @@ -702,7 +676,7 @@ public final class Recording implements Closeable { * */ public EventSettings disable(Class<? extends Event> eventClass) { - Objects.requireNonNull(eventClass); + Objects.requireNonNull(eventClass, "eventClass"); RecordingSettings rs = new RecordingSettings(this, eventClass); rs.with("enabled", "false"); return rs; diff --git a/src/jdk.jfr/share/classes/jdk/jfr/Relational.java b/src/jdk.jfr/share/classes/jdk/jfr/Relational.java index f195d6ac67bf20ec104e126b24d619a4068a864d..153346a19acd759d32135371f50b3d1e23531082 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/Relational.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/Relational.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -32,6 +32,13 @@ import java.lang.annotation.Target; /** * Meta annotation for relational annotations, to be used on an annotation. + * <p> + * The following example shows how a relational annotation can be created and + * used. The {@code Orderid} annotation indicates there is a relation between + * {@code OrderEvent} and {@code OrderLineEvent}. if they have the same ID, + * the order line belongs to the order. + * + * {@snippet class="Snippets" region="RelationalOverview"} * * @since 9 */ diff --git a/src/jdk.jfr/share/classes/jdk/jfr/SettingControl.java b/src/jdk.jfr/share/classes/jdk/jfr/SettingControl.java index 431b984ebf2647b2658992eefd4831ad233f4be2..1c699247800c02c56e105f1cd553b4d510cd8743 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/SettingControl.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/SettingControl.java @@ -37,30 +37,7 @@ import jdk.jfr.internal.settings.JDKSettingControl; * The following example shows a naive implementation of a setting control for * regular expressions: * - * <pre>{@literal - * final class RegExpControl extends SettingControl { - * private Pattern pattern = Pattern.compile(".*"); - * - * @Override - * public void setValue(String value) { - * this.pattern = Pattern.compile(value); - * } - * - * @Override - * public String combine(Set<String> values) { - * return String.join("|", values); - * } - * - * @Override - * public String getValue() { - * return pattern.toString(); - * } - * - * public boolean matches(String s) { - * return pattern.matcher(s).find(); - * } - * } - * }</pre> + * {@snippet class="Snippets" region="SettingControlOverview1"} * * The {@code setValue(String)}, {@code getValue()} and * {@code combine(Set<String>)} methods are invoked when a setting value @@ -85,55 +62,13 @@ import jdk.jfr.internal.settings.JDKSettingControl; * The following example shows how to create an event that uses the * regular expression filter defined above. * - * <pre>{@literal - * abstract class HTTPRequest extends Event { - * @Label("Request URI") - * protected String uri; - * - * @Label("Servlet URI Filter") - * @SettingDefinition - * protected boolean uriFilter(RegExpControl regExp) { - * return regExp.matches(uri); - * } - * } - * - * @Label("HTTP Get Request") - * class HTTPGetRequest extends HTTPRequest { - * } - * - * @Label("HTTP Post Request") - * class HTTPPostRequest extends HTTPRequest { - * } - * - * class ExampleServlet extends HttpServlet { - * protected void doGet(HttpServletRequest req, HttpServletResponse resp) { - * HTTPGetRequest request = new HTTPGetRequest(); - * request.begin(); - * request.uri = req.getRequestURI(); - * ... - * request.commit(); - * } - * - * protected void doPost(HttpServletRequest req, HttpServletResponse resp) { - * HTTPPostRequest request = new HTTPPostRequest(); - * request.begin(); - * request.uri = req.getRequestURI(); - * ... - * request.commit(); - * } - * } - * }</pre> + * {@snippet class="Snippets" region="SettingControlOverview2"} * * <p> * The following example shows how an event can be filtered by assigning the * {@code "uriFilter"} setting with the specified regular expressions. * - * <pre>{@literal - * Recording r = new Recording(); - * r.enable("HTTPGetRequest").with("uriFilter", "https://www.example.com/list/.*"); - * r.enable("HTTPPostRequest").with("uriFilter", "https://www.example.com/login/.*"); - * r.start(); - * }</pre> + * {@snippet class="Snippets" region="SettingControlOverview3"} * * @see SettingDefinition * diff --git a/src/jdk.jfr/share/classes/jdk/jfr/ValueDescriptor.java b/src/jdk.jfr/share/classes/jdk/jfr/ValueDescriptor.java index 26e523ed40cb97bc81f6ad460f4b2e5594f139b1..7f517e07b61f8c0b46e164893079ae944a40ce88 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/ValueDescriptor.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/ValueDescriptor.java @@ -139,7 +139,9 @@ public final class ValueDescriptor { ValueDescriptor(Class<?> type, String name, List<AnnotationElement> annotations, boolean allowArray) { - Objects.requireNonNull(annotations); + Objects.requireNonNull(type, "type"); + Objects.requireNonNull(name, "name"); + Objects.requireNonNull(annotations, "annotations"); Utils.checkRegisterPermission(); if (!allowArray) { if (type.isArray()) { @@ -271,7 +273,7 @@ public final class ValueDescriptor { * directly present, else {@code null} */ public <A extends Annotation> A getAnnotation(Class<A> annotationType) { - Objects.requireNonNull(annotationType); + Objects.requireNonNull(annotationType, "annotationType"); return annotationConstruct.getAnnotation(annotationType); } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/consumer/EventStream.java b/src/jdk.jfr/share/classes/jdk/jfr/consumer/EventStream.java index dc877b52efdded9bb5659ab551400a9c25549921..895c1f2d4a408d1ff5315b8555763f01d062b56e 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/consumer/EventStream.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/consumer/EventStream.java @@ -95,25 +95,7 @@ import jdk.jfr.internal.consumer.FileAccess; * The following example shows how an {@code EventStream} can be used to listen * to events on a JVM running Flight Recorder * - * <pre>{@literal - * try (var es = EventStream.openRepository()) { - * es.onEvent("jdk.CPULoad", event -> { - * System.out.println("CPU Load " + event.getEndTime()); - * System.out.println(" Machine total: " + 100 * event.getFloat("machineTotal") + "%"); - * System.out.println(" JVM User: " + 100 * event.getFloat("jvmUser") + "%"); - * System.out.println(" JVM System: " + 100 * event.getFloat("jvmSystem") + "%"); - * System.out.println(); - * }); - * es.onEvent("jdk.GarbageCollection", event -> { - * System.out.println("Garbage collection: " + event.getLong("gcId")); - * System.out.println(" Cause: " + event.getString("cause")); - * System.out.println(" Total pause: " + event.getDuration("sumOfPauses")); - * System.out.println(" Longest pause: " + event.getDuration("longestPause")); - * System.out.println(); - * }); - * es.start(); - * } - * }</pre> + * {@snippet class="Snippets" region="EventStreamOverview"} * <p> * To start recording together with the stream, see {@link RecordingStream}. * @@ -167,7 +149,7 @@ public interface EventStream extends AutoCloseable { * files in the directory. */ public static EventStream openRepository(Path directory) throws IOException { - Objects.requireNonNull(directory); + Objects.requireNonNull(directory, "directory"); @SuppressWarnings("removal") AccessControlContext acc = AccessController.getContext(); return new EventDirectoryStream( @@ -197,6 +179,7 @@ public interface EventStream extends AutoCloseable { */ @SuppressWarnings("removal") static EventStream openFile(Path file) throws IOException { + Objects.requireNonNull(file, "file"); return new EventFileStream(AccessController.getContext(), file); } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedEvent.java b/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedEvent.java index 7a9cc510985b353bf7f54f734c55aa02745b0e8d..b0ffe88b9c71edcb65bf151f25f68a8db1b249a2 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedEvent.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedEvent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -107,6 +107,9 @@ public final class RecordedEvent extends RecordedObject { * @return the duration in nanoseconds, not {@code null} */ public Duration getDuration() { + if(startTimeTicks == endTimeTicks) { + return Duration.ZERO; + } return Duration.ofNanos(getEndTimeNanos() - getStartTimeNanos()); } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedObject.java b/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedObject.java index c366934f23b8d30c19edd0cc3156d9b392de132f..14d5ce4985fb79c0f05887fffdb9a42fda883f5a 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedObject.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedObject.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -150,16 +150,7 @@ public class RecordedObject { JdkJfrConsumer.setAccess(access); } - private static final class UnsignedValue { - private final Object o; - - UnsignedValue(Object o) { - this.o = o; - } - - Object value() { - return o; - } + private static final record UnsignedValue(Object value) { } final Object[] objects; @@ -234,23 +225,7 @@ public class RecordedObject { * for callers of this method is to validate the field before attempting access. * <p> * Example - * - * <pre>{@literal - * if (event.hasField("intValue")) { - * int intValue = event.getValue("intValue"); - * System.out.println("Int value: " + intValue); - * } - * - * if (event.hasField("objectClass")) { - * RecordedClass clazz = event.getValue("objectClass"); - * System.out.println("Class name: " + clazz.getName()); - * } - * - * if (event.hasField("sampledThread")) { - * RecordedThread sampledThread = event.getValue("sampledThread"); - * System.out.println("Sampled thread: " + sampledThread.getJavaName()); - * } - * }</pre> + * {@snippet class="Snippets" region="RecordedObjectGetValue"} * * @param <T> the return type * @param name of the field to get, not {@code null} @@ -272,7 +247,7 @@ public class RecordedObject { } private Object getValue(String name, boolean allowUnsigned) { - Objects.requireNonNull(name); + Objects.requireNonNull(name, "name"); int index = 0; for (ValueDescriptor v : objectContext.fields) { if (name.equals(v.getName())) { @@ -354,14 +329,14 @@ public class RecordedObject { return v; } } - throw new IllegalArgumentException("\"Attempt to get unknown field \"" + name + "\""); + throw new IllegalArgumentException("Attempt to get unknown field \"" + name + "\""); } // Gets a value, but checks that type and name is correct first // This is to prevent a call to getString on a thread field, that is // null to succeed. private <T> T getTypedValue(String name, String typeName) { - Objects.requireNonNull(name); + Objects.requireNonNull(name, "name"); // Validate name and type first getValueDescriptor(objectContext.fields, name, typeName); return getValue(name); @@ -827,8 +802,11 @@ public class RecordedObject { throw newIllegalArgumentException(name, "java.time.Duration"); } - private Duration getDuration(long timespan, String name) throws InternalError { + private Duration getDuration(long timespan, String name) { ValueDescriptor v = getValueDescriptor(objectContext.fields, name, null); + if (timespan == 0) { + return Duration.ZERO; + } if (timespan == Long.MIN_VALUE) { return Duration.ofSeconds(Long.MIN_VALUE, 0); } @@ -997,7 +975,7 @@ public class RecordedObject { if (instant.equals(Instant.MIN)) { return OffsetDateTime.MIN; } - return OffsetDateTime.ofInstant(getInstant(name), objectContext.getZoneOffset()); + return OffsetDateTime.ofInstant(instant, objectContext.getZoneOffset()); } private static IllegalArgumentException newIllegalArgumentException(String name, String typeName) { diff --git a/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordingFile.java b/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordingFile.java index 5ebe57bcce4876f4c2a28dc4c67b81f189374669..d52449f4d745513ecbdb23d0deea641deca419e6 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordingFile.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordingFile.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -34,33 +34,33 @@ import java.nio.file.Path; import java.util.ArrayList; import java.util.HashSet; import java.util.List; - +import java.util.Objects; +import java.util.function.Predicate; import jdk.jfr.EventType; import jdk.jfr.internal.MetadataDescriptor; import jdk.jfr.internal.Type; +import jdk.jfr.internal.consumer.ChunkParser.ParserConfiguration; +import jdk.jfr.internal.consumer.ParserFilter; import jdk.jfr.internal.consumer.ChunkHeader; import jdk.jfr.internal.consumer.ChunkParser; import jdk.jfr.internal.consumer.FileAccess; +import jdk.jfr.internal.consumer.ParserState; import jdk.jfr.internal.consumer.RecordingInput; +import jdk.jfr.internal.consumer.filter.ChunkWriter; /** * A recording file. * <p> * The following example shows how read and print all events in a recording file. * - * <pre>{@literal - * try (RecordingFile recordingFile = new RecordingFile(Paths.get("recording.jfr"))) { - * while (recordingFile.hasMoreEvents()) { - * RecordedEvent event = recordingFile.readEvent(); - * System.out.println(event); - * } - * } - * }</pre> + * {@snippet class="Snippets" region="RecordingFileOverview"} * * @since 9 */ public final class RecordingFile implements Closeable { + private final ParserState parserState = new ParserState(); + private final ChunkWriter chunkWriter; private boolean isLastEventInChunk; private final File file; private RecordingInput input; @@ -80,8 +80,18 @@ public final class RecordingFile implements Closeable { * {@code checkRead} method denies read access to the file. */ public RecordingFile(Path file) throws IOException { + Objects.requireNonNull(file, "file"); this.file = file.toFile(); this.input = new RecordingInput(this.file, FileAccess.UNPRIVILEGED); + this.chunkWriter = null; + findNext(); + } + + // Only used by RecordingFile::write(Path, Predicate<RecordedEvent>) + private RecordingFile(ChunkWriter chunkWriter) throws IOException { + this.file = null; // not used + this.input = chunkWriter.getInput(); + this.chunkWriter = chunkWriter; findNext(); } @@ -204,6 +214,34 @@ public final class RecordingFile implements Closeable { } } + /** + * Filter out events and write them to a new file. + * + * @param destination path where the new file should be written, not + * {@code null} + * + * @param filter filter that determines if an event should be included, not + * {@code null} + * @throws IOException if an I/O error occurred, it's not a Flight + * Recorder file or a version of a JFR file that can't + * be parsed + * + * @throws SecurityException if a security manager exists and its + * {@code checkWrite} method denies write access to the + * file + */ + public void write(Path destination, Predicate<RecordedEvent> filter) throws IOException { + Objects.requireNonNull(destination, "destination"); + Objects.requireNonNull(filter, "filter"); + try (ChunkWriter cw = new ChunkWriter(file.toPath(), destination, filter)) { + try (RecordingFile rf = new RecordingFile(cw)) { + while (rf.hasMoreEvents()) { + rf.readEvent(); + } + } + } + } + /** * Returns a list of all events in a file. * <p> @@ -242,15 +280,15 @@ public final class RecordingFile implements Closeable { return isLastEventInChunk; } - // either sets next to an event or sets eof to true private void findNext() throws IOException { while (nextEvent == null) { if (chunkParser == null) { - chunkParser = new ChunkParser(input); + chunkParser = createChunkParser(); } else if (!chunkParser.isLastChunk()) { - chunkParser = chunkParser.nextChunkParser(); + chunkParser = nextChunkParser(); } else { + endChunkParser(); eof = true; return; } @@ -261,6 +299,36 @@ public final class RecordingFile implements Closeable { } } + private ChunkParser createChunkParser() throws IOException { + if (chunkWriter != null) { + boolean reuse = true; + boolean ordered = false; + ParserConfiguration pc = new ParserConfiguration(0, Long.MAX_VALUE, reuse, ordered, ParserFilter.ACCEPT_ALL, chunkWriter); + ChunkParser chunkParser = new ChunkParser(chunkWriter.getInput(), pc, new ParserState()); + chunkWriter.beginChunk(chunkParser.getHeader()); + return chunkParser; + } else { + return new ChunkParser(input, parserState); + } + } + + private void endChunkParser() throws IOException { + if (chunkWriter != null) { + chunkWriter.endChunk(chunkParser.getHeader()); + } + } + + private ChunkParser nextChunkParser() throws IOException { + if (chunkWriter != null) { + chunkWriter.endChunk(chunkParser.getHeader()); + } + ChunkParser next = chunkParser.nextChunkParser(); + if (chunkWriter != null) { + chunkWriter.beginChunk(next.getHeader()); + } + return next; + } + private void ensureOpen() throws IOException { if (input == null) { throw new IOException("Stream Closed"); diff --git a/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordingStream.java b/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordingStream.java index ea6d2a05bf92fd7b4ffc21cf214ddcd5e36e0bac..475d9ce760ad8e2b922eeb8ed850fd0133763942 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordingStream.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordingStream.java @@ -56,15 +56,8 @@ import jdk.jfr.internal.consumer.EventDirectoryStream; * The following example shows how to record events using the default * configuration and print the Garbage Collection, CPU Load and JVM Information * event to standard out. - * <pre>{@literal - * Configuration c = Configuration.getConfiguration("default"); - * try (var rs = new RecordingStream(c)) { - * rs.onEvent("jdk.GarbageCollection", System.out::println); - * rs.onEvent("jdk.CPULoad", System.out::println); - * rs.onEvent("jdk.JVMInformation", System.out::println); - * rs.start(); - * } - * }</pre> + * + * {@snippet class="Snippets" region="RecordingStreamOverview"} * * @since 14 */ @@ -104,6 +97,10 @@ public final class RecordingStream implements AutoCloseable, EventStream { * {@code FlightRecorderPermission("accessFlightRecorder")} */ public RecordingStream() { + this(Map.of()); + } + + private RecordingStream(Map<String, String> settings) { Utils.checkAccessFlightRecorder(); @SuppressWarnings("removal") AccessControlContext acc = AccessController.getContext(); @@ -124,6 +121,9 @@ public final class RecordingStream implements AutoCloseable, EventStream { this.recording.close(); throw new IllegalStateException(ioe.getMessage()); } + if (!settings.isEmpty()) { + recording.setSettings(settings); + } } private List<Configuration> configurations() { @@ -140,13 +140,7 @@ public final class RecordingStream implements AutoCloseable, EventStream { * The following example shows how to create a recording stream that uses a * predefined configuration. * - * <pre>{@literal - * var c = Configuration.getConfiguration("default"); - * try (var rs = new RecordingStream(c)) { - * rs.onEvent(System.out::println); - * rs.start(); - * } - * }</pre> + * {@snippet class="Snippets" region="RecordingStreamConstructor"} * * @param configuration configuration that contains the settings to use, * not {@code null} @@ -161,8 +155,7 @@ public final class RecordingStream implements AutoCloseable, EventStream { * @see Configuration */ public RecordingStream(Configuration configuration) { - this(); - recording.setSettings(configuration.getSettings()); + this(Objects.requireNonNull(configuration, "configuration").getSettings()); } /** @@ -189,17 +182,7 @@ public final class RecordingStream implements AutoCloseable, EventStream { * The following example records 20 seconds using the "default" configuration * and then changes settings to the "profile" configuration. * - * <pre>{@literal - * Configuration defaultConfiguration = Configuration.getConfiguration("default"); - * Configuration profileConfiguration = Configuration.getConfiguration("profile"); - * try (var rs = new RecordingStream(defaultConfiguration)) { - * rs.onEvent(System.out::println); - * rs.startAsync(); - * Thread.sleep(20_000); - * rs.setSettings(profileConfiguration.getSettings()); - * Thread.sleep(20_000); - * } - * }</pre> + * {@snippet class="Snippets" region="RecordingStreamSetSettings"} * * @param settings the settings to set, not {@code null} * @@ -384,16 +367,8 @@ public final class RecordingStream implements AutoCloseable, EventStream { * The following example prints the CPU usage for ten seconds. When * the current thread leaves the try-with-resources block the * stream is stopped/closed. - * <pre>{@literal - * try (var stream = new RecordingStream()) { - * stream.enable("jdk.CPULoad").withPeriod(Duration.ofSeconds(1)); - * stream.onEvent("jdk.CPULoad", event -> { - * System.out.println(event); - * }); - * stream.startAsync(); - * Thread.sleep(10_000); - * } - * }</pre> + * + * {@snippet class="Snippets" region="RecordingStreamStartAsync"} * * @throws IllegalStateException if the stream is already started or closed */ diff --git a/src/jdk.jfr/share/classes/jdk/jfr/consumer/package-info.java b/src/jdk.jfr/share/classes/jdk/jfr/consumer/package-info.java index 5b34deaf24911b5a09ecb7bab2bf87a5b4e76649..81f7977deba91b48e55a1bb6a79e7ad065d73cac 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/consumer/package-info.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/consumer/package-info.java @@ -27,29 +27,8 @@ * This package contains classes for consuming Flight Recorder data. * <p> * In the following example, the program prints a histogram of all method samples in a recording. - * <pre>{@literal - * public static void main(String[] args) throws IOException { - * if (args.length != 1) { - * System.err.println("Must specify a recording file."); - * return; - * } * - * RecordingFile.readAllEvents(Path.of(args[0])).stream() - * .filter(e -> e.getEventType().getName().equals("jdk.ExecutionSample")) - * .map(e -> e.getStackTrace()) - * .filter(s -> s != null) - * .map(s -> s.getFrames().get(0)) - * .filter(f -> f.isJavaFrame()) - * .map(f -> f.getMethod()) - * .collect( - * Collectors.groupingBy(m -> m.getType().getName() + "." + m.getName() + " " + m.getDescriptor(), - * Collectors.counting())) - * .entrySet() - * .stream() - * .sorted((a, b) -> b.getValue().compareTo(a.getValue())) - * .forEach(e -> System.out.printf("%8d %s\n", e.getValue(), e.getKey())); - * } - * }</pre> + * {@snippet class="Snippets" region="PackageOverview"} * <p> * <b>Null-handling</b> * <p> diff --git a/src/jdk.jfr/share/classes/jdk/jfr/consumer/snippet-files/Snippets.java b/src/jdk.jfr/share/classes/jdk/jfr/consumer/snippet-files/Snippets.java new file mode 100644 index 0000000000000000000000000000000000000000..d80879a22ecf5e3671562bfd6d24dcb5363eb5ce --- /dev/null +++ b/src/jdk.jfr/share/classes/jdk/jfr/consumer/snippet-files/Snippets.java @@ -0,0 +1,169 @@ +/* + * 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. 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 example2; + +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.time.Duration; +import java.util.stream.Collectors; +import jdk.jfr.consumer.EventStream; +import jdk.jfr.consumer.RecordingFile; +import jdk.jfr.consumer.RecordedClass; +import jdk.jfr.consumer.RecordedThread; +import jdk.jfr.consumer.RecordingStream; +import jdk.jfr.Configuration; +import jdk.jfr.consumer.RecordedEvent; + +public class Snippets { + + class PackageOveriview { + // @start region="PackageOverview" + public static void main(String[] args) throws IOException { + if (args.length != 1) { + System.err.println("Must specify a recording file."); + return; + } + + RecordingFile.readAllEvents(Path.of(args[0])).stream() + .filter(e -> e.getEventType().getName().equals("jdk.ExecutionSample")) + .map(e -> e.getStackTrace()) + .filter(s -> s != null) + .map(s -> s.getFrames().get(0)) + .filter(f -> f.isJavaFrame()) + .map(f -> f.getMethod()) + .collect( + Collectors.groupingBy(m -> m.getType().getName() + "." + m.getName() + " " + m.getDescriptor(), + Collectors.counting())) + .entrySet() + .stream() + .sorted((a, b) -> b.getValue().compareTo(a.getValue())) + .forEach(e -> System.out.printf("%8d %s\n", e.getValue(), e.getKey())); + } + // @end + } + + void EventStreamOverview() throws Exception { + // @start region="EventStreamOverview" + try (var es = EventStream.openRepository()) { + es.onEvent("jdk.CPULoad", event -> { + System.out.println("CPU Load " + event.getEndTime()); + System.out.println(" Machine total: " + 100 * event.getFloat("machineTotal") + "%"); + System.out.println(" JVM User: " + 100 * event.getFloat("jvmUser") + "%"); + System.out.println(" JVM System: " + 100 * event.getFloat("jvmSystem") + "%"); + System.out.println(); + }); + es.onEvent("jdk.GarbageCollection", event -> { + System.out.println("Garbage collection: " + event.getLong("gcId")); + System.out.println(" Cause: " + event.getString("cause")); + System.out.println(" Total pause: " + event.getDuration("sumOfPauses")); + System.out.println(" Longest pause: " + event.getDuration("longestPause")); + System.out.println(); + }); + es.start(); + } + // @end + } + + void RecordingFileOverview() throws Exception { + // @start region="RecordingFileOverview" + try (RecordingFile recordingFile = new RecordingFile(Paths.get("recording.jfr"))) { + while (recordingFile.hasMoreEvents()) { + RecordedEvent event = recordingFile.readEvent(); + System.out.println(event); + } + } + // @end + } + + void RecordedObjectGetValue() { + RecordedEvent event = null; + // @start region="RecordedObjectGetValue" + if (event.hasField("intValue")) { + int intValue = event.getValue("intValue"); + System.out.println("Int value: " + intValue); + } + + if (event.hasField("objectClass")) { + RecordedClass clazz = event.getValue("objectClass"); + System.out.println("Class name: " + clazz.getName()); + } + + if (event.hasField("sampledThread")) { + RecordedThread sampledThread = event.getValue("sampledThread"); + System.out.println("Sampled thread: " + sampledThread.getJavaName()); + } + // @end + } + + void RecordingStreamOverview() throws Exception { + // @start region="RecordingStreamOverview" + Configuration c = Configuration.getConfiguration("default"); + try (var rs = new RecordingStream(c)) { + rs.onEvent("jdk.GarbageCollection", System.out::println); + rs.onEvent("jdk.CPULoad", System.out::println); + rs.onEvent("jdk.JVMInformation", System.out::println); + rs.start(); + } + // @end + } + + void RecordingStreamConstructor() throws Exception { + // @start region="RecordingStreamConstructor" + var c = Configuration.getConfiguration("default"); + try (var rs = new RecordingStream(c)) { + rs.onEvent(System.out::println); + rs.start(); + } + // @end + } + + void RecordingStreamSetSettings() throws Exception { + // @start region="RecordingStreamSetSettings" + Configuration defaultConfiguration = Configuration.getConfiguration("default"); + Configuration profileConfiguration = Configuration.getConfiguration("profile"); + try (var rs = new RecordingStream(defaultConfiguration)) { + rs.onEvent(System.out::println); + rs.startAsync(); + Thread.sleep(20_000); + rs.setSettings(profileConfiguration.getSettings()); + Thread.sleep(20_000); + } + // @end + } + + void RecordingStreamStartAsync() throws Exception { + // @start region="RecordingStreamStartAsync" + try (var stream = new RecordingStream()) { + stream.enable("jdk.CPULoad").withPeriod(Duration.ofSeconds(1)); + stream.onEvent("jdk.CPULoad", event -> { + System.out.println(event); + }); + stream.startAsync(); + Thread.sleep(10_000); + } + // @end + } +} diff --git a/src/jdk.jfr/share/classes/jdk/jfr/events/FileReadEvent.java b/src/jdk.jfr/share/classes/jdk/jfr/events/FileReadEvent.java index 703f0d1271c73c7e48df79c0821f2157d07d9990..a3a53c6a7e92318bd31c85b5fcb65811dbd9b750 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/events/FileReadEvent.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/events/FileReadEvent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -42,7 +42,7 @@ public final class FileReadEvent extends AbstractJDKEvent { // EventHandler::write(..., String, long, boolean) @Label("Path") - @Description("Full path of the file") + @Description("Full path of the file, or N/A if a file descriptor was used to create the stream, for example System.in") public String path; @Label("Bytes Read") diff --git a/src/jdk.jfr/share/classes/jdk/jfr/events/FileWriteEvent.java b/src/jdk.jfr/share/classes/jdk/jfr/events/FileWriteEvent.java index 7554fee09c29c487f190b3e43e9566e9819c1855..01ffc5dfa48045750743df781613a3bd3f4c113f 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/events/FileWriteEvent.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/events/FileWriteEvent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -42,7 +42,7 @@ public final class FileWriteEvent extends AbstractJDKEvent { // EventHandler::write(..., String, long) @Label("Path") - @Description("Full path of the file") + @Description("Full path of the file, or N/A if a file descriptor was used to create the stream, for example System.out and System.err") public String path; @Label("Bytes Written") diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/ChunkInputStream.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/ChunkInputStream.java index a5e1d01783f2ae988db772f0eee6b4965ea3a3ed..5b192443980606cf7a2c70e110fa9f11fe29e16b 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/ChunkInputStream.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/ChunkInputStream.java @@ -112,7 +112,7 @@ final class ChunkInputStream extends InputStream { } @Override - @SuppressWarnings("deprecation") + @SuppressWarnings("removal") protected void finalize() throws Throwable { super.finalize(); close(); diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/ChunksChannel.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/ChunksChannel.java index 1139536c93876f8fa49ed46a625e2b07d057b49a..b606105d29e5506006508b0a6ce05b9712874795 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/ChunksChannel.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/ChunksChannel.java @@ -137,7 +137,7 @@ final class ChunksChannel implements ReadableByteChannel { } @Override - @SuppressWarnings("deprecation") + @SuppressWarnings("removal") protected void finalize() throws Throwable { super.finalize(); close(); diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/Control.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/Control.java index 0887d1ce0ed9c2c04c677e0dba49f07d51fe0115..27281cd5f58b8bfee4163f3ffd95380e988a6977 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/Control.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/Control.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -75,7 +75,7 @@ public final class Control { public String getValue() { if (context == null) { // VM events requires no access control context - return getValue(); + return delegate.getValue(); } else { return AccessController.doPrivileged(new PrivilegedAction<String>() { @Override diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/EventControl.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/EventControl.java index 6a89ce02d1e00ba0d21ac72d19b05113306b8a95..b0fdce2d6c92114d149835e58cd17e14598046af 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/EventControl.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/EventControl.java @@ -292,7 +292,7 @@ public final class EventControl { } ActiveSettingEvent event = ActiveSettingEvent.EVENT.get(); for (NamedControl nc : namedControls) { - if (Utils.isSettingVisible(nc.control, type.hasEventHook())) { + if (Utils.isSettingVisible(nc.control, type.hasEventHook()) && type.isVisible()) { String value = nc.control.getLastValue(); if (value == null) { value = nc.control.getDefaultValue(); diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/JVM.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/JVM.java index b5aff49cbe070aa3afb8a5fe5815e3dc50c8e3de..0739a0bfacbf2093bd8130a72f503c14a1b98b1b 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/JVM.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/JVM.java @@ -301,15 +301,6 @@ public final class JVM { */ public native void setForceInstrumentation(boolean force); - /** - * Turn on/off thread sampling. - * - * @param sampleThreads true if threads should be sampled, false otherwise. - * - * @throws IllegalStateException if state can't be changed. - */ - public native void setSampleThreads(boolean sampleThreads) throws IllegalStateException; - /** * Turn on/off compressed integers. * @@ -473,13 +464,26 @@ public final class JVM { public native void flush(); /** - * Sets the location of the disk repository, to be used at an emergency - * dump. + * Sets the location of the disk repository. * * @param dirText */ public native void setRepositoryLocation(String dirText); + /** + * Sets the path to emergency dump. + * + * @param dumpPathText + */ + public native void setDumpPath(String dumpPathText); + + /** + * Gets the path to emergency dump. + * + * @return The path to emergency dump. + */ + public native String getDumpPath(); + /** * Access to VM termination support. * diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/JVMUpcalls.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/JVMUpcalls.java index 2e4e4c95a3f30dff520c97cd8a1f4bfbc9bc3d53..be1dab301b785ad0f4b161fce1437942e328d06c 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/JVMUpcalls.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/JVMUpcalls.java @@ -125,14 +125,22 @@ final class JVMUpcalls { } } + /** + * Called by the JVM to ensure metadata for internal events/types become public. + * + * Must be called after metadata repository has been initialized (JFR created). + * + */ + static void unhideInternalTypes() { + MetadataRepository.unhideInternalTypes(); + } + /** * Called by the JVM to create the recorder thread. * - * @param systemThreadGroup - * the system thread group + * @param systemThreadGroup the system thread group * - * @param contextClassLoader - * the context class loader. + * @param contextClassLoader the context class loader. * * @return a new thread */ diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/MetadataLoader.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/MetadataLoader.java index ef9c22556f2410536044376306956e7143d89dfc..552b070527e84334a8caffa8cfa6de8f11545c6e 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/MetadataLoader.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/MetadataLoader.java @@ -53,7 +53,8 @@ public final class MetadataLoader { // Caching to reduce allocation pressure and heap usage private final AnnotationElement RELATIONAL = new AnnotationElement(Relational.class); - private final AnnotationElement ENABLED = new AnnotationElement(Enabled.class, false); + private final AnnotationElement ENABLED = new AnnotationElement(Enabled.class, true); + private final AnnotationElement DISABLED = new AnnotationElement(Enabled.class, false); private final AnnotationElement THRESHOLD = new AnnotationElement(Threshold.class, "0 ns"); private final AnnotationElement STACK_TRACE = new AnnotationElement(StackTrace.class, true); private final AnnotationElement TRANSITION_TO = new AnnotationElement(TransitionTo.class); @@ -82,6 +83,7 @@ public final class MetadataLoader { private final boolean isEvent; private final boolean isRelation; private final boolean experimental; + private final boolean internal; private final long id; public TypeElement(DataInputStream dis) throws IOException { @@ -101,6 +103,7 @@ public final class MetadataLoader { cutoff = dis.readBoolean(); throttle = dis.readBoolean(); experimental = dis.readBoolean(); + internal = dis.readBoolean(); id = dis.readLong(); isEvent = dis.readBoolean(); isRelation = dis.readBoolean(); @@ -315,7 +318,11 @@ public final class MetadataLoader { } Type type; if (t.isEvent) { - aes.add(ENABLED); + if (t.internal) { + aes.add(ENABLED); + } else { + aes.add(DISABLED); + } type = new PlatformEventType(t.name, t.id, false, true); } else { type = knownTypeMap.get(t.name); @@ -328,6 +335,15 @@ public final class MetadataLoader { } } } + if (t.internal) { + type.setInternal(true); + // Internal types are hidden by default + type.setVisible(false); + // Internal events are enabled by default + if (type instanceof PlatformEventType pe) { + pe.setEnabled(true); + } + } type.setAnnotations(aes); typeMap.put(t.name, type); } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/MetadataReader.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/MetadataReader.java index ca5c5c31ecd40ccf0363d311b47f49d665e2867f..91d243402aa35bd6b3766c1ec5f490624184120c 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/MetadataReader.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/MetadataReader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -40,7 +40,7 @@ import static jdk.jfr.internal.MetadataDescriptor.ELEMENT_TYPE; import java.io.DataInput; import java.io.IOException; import java.util.ArrayList; -import java.util.Collections; +import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -84,7 +84,7 @@ final class MetadataReader { descriptor.root = root; if (Logger.shouldLog(LogTag.JFR_SYSTEM_PARSER, LogLevel.TRACE)) { List<Type> ts = new ArrayList<>(types.values()); - Collections.sort(ts, (x,y) -> x.getName().compareTo(y.getName())); + ts.sort(Comparator.comparing(Type::getName)); for (Type t : ts) { t.log("Found", LogTag.JFR_SYSTEM_PARSER, LogLevel.TRACE); } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/MetadataRepository.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/MetadataRepository.java index 0c798b8b28eca3f1439661ede8f5be5e4d035de1..f76fdc62a74c5f671479ee30e8b4feca375e897d 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/MetadataRepository.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/MetadataRepository.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -34,6 +34,7 @@ import java.io.IOException; import java.time.Instant; import java.util.ArrayList; import java.util.Collections; +import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -71,7 +72,7 @@ public final class MetadataRepository { private void initializeJVMEventTypes() { List<RequestHook> requestHooks = new ArrayList<>(); - for (Type type : typeLibrary.getTypes()) { + for (Type type : new ArrayList<>(typeLibrary.getTypes())) { if (type instanceof PlatformEventType pEventType) { EventType eventType = PrivateAccess.getInstance().newEventType(pEventType); pEventType.setHasDuration(eventType.getAnnotation(Threshold.class) != null); @@ -106,7 +107,11 @@ public final class MetadataRepository { eventTypes.add(h.getEventType()); } } - eventTypes.addAll(nativeEventTypes); + for (EventType t : nativeEventTypes) { + if (PrivateAccess.getInstance().isVisible(t)) { + eventTypes.add(t); + } + } return eventTypes; } @@ -243,7 +248,13 @@ public final class MetadataRepository { ByteArrayOutputStream baos = new ByteArrayOutputStream(40000); DataOutputStream daos = new DataOutputStream(baos); try { - List<Type> types = typeLibrary.getTypes(); + List<Type> types = typeLibrary.getVisibleTypes(); + if (Logger.shouldLog(LogTag.JFR_METADATA, LogLevel.DEBUG)) { + Collections.sort(types,Comparator.comparing(Type::getName)); + for (Type t: types) { + Logger.log(LogTag.JFR_METADATA, LogLevel.INFO, "Serialized type: " + t.getName() + " id=" + t.getId()); + } + } Collections.sort(types); MetadataDescriptor.write(types, daos); daos.flush(); @@ -269,9 +280,12 @@ public final class MetadataRepository { if (staleMetadata) { storeDescriptorInJVM(); } - awaitUniqueTimestamp(); jvm.setOutput(filename); - long nanos = jvm.getChunkStartNanos(); + // Each chunk needs a unique start timestamp and + // if the clock resolution is low, two chunks may + // get the same timestamp. Utils.getChunkStartNanos() + // ensures the timestamp is unique for the next chunk + long chunkStart = Utils.getChunkStartNanos(); if (filename != null) { RepositoryFiles.notifyNewFile(); } @@ -282,29 +296,7 @@ public final class MetadataRepository { } unregistered = false; } - return Utils.epochNanosToInstant(nanos); - } - - // Each chunk needs a unique start timestamp and - // if the clock resolution is low, two chunks may - // get the same timestamp. - private void awaitUniqueTimestamp() { - if (outputChange == null) { - outputChange = Instant.now(); - return; - } - while (true) { - Instant time = Instant.now(); - if (!time.equals(outputChange)) { - outputChange = time; - return; - } - try { - Thread.sleep(0, 100); - } catch (InterruptedException iex) { - // ignore - } - } + return Utils.epochNanosToInstant(chunkStart); } private void unregisterUnloaded() { @@ -349,4 +341,20 @@ public final class MetadataRepository { jvm.flush(); } + static void unhideInternalTypes() { + for (Type t : TypeLibrary.getInstance().getTypes()) { + if (t.isInternal()) { + t.setVisible(true); + Logger.log(LogTag.JFR_METADATA, LogLevel.DEBUG, "Unhiding internal type " + t.getName()); + } + } + // Singleton should have been initialized here. + // It's not possible to call MetadataRepository().getInstance(), + // because it will deadlock with Java thread calling flush() or setOutput(); + instance.storeDescriptorInJVM(); + } + + public synchronized List<Type> getVisibleTypes() { + return typeLibrary.getVisibleTypes(); + } } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/Options.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/Options.java index 4d430bebba2c4e3c92b265eaf03182a01e6d1bf6..efd3ce6480799d84486b6ec38dce7efcfcee1a3f 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/Options.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/Options.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -25,9 +25,16 @@ package jdk.jfr.internal; +import java.io.IOException; + +import jdk.jfr.internal.LogLevel; +import jdk.jfr.internal.LogTag; +import jdk.jfr.internal.Logger; import jdk.jfr.internal.SecuritySupport.SafePath; import jdk.internal.misc.Unsafe; +import static java.nio.file.LinkOption.*; + /** * Options that control Flight Recorder. * @@ -46,18 +53,15 @@ public final class Options { private static final long DEFAULT_MEMORY_SIZE = DEFAULT_GLOBAL_BUFFER_COUNT * DEFAULT_GLOBAL_BUFFER_SIZE; private static long DEFAULT_THREAD_BUFFER_SIZE; private static final int DEFAULT_STACK_DEPTH = 64; - private static final boolean DEFAULT_SAMPLE_THREADS = true; private static final long DEFAULT_MAX_CHUNK_SIZE = 12 * 1024 * 1024; - private static final SafePath DEFAULT_DUMP_PATH = SecuritySupport.USER_HOME; + private static final SafePath DEFAULT_DUMP_PATH = null; private static long memorySize; private static long globalBufferSize; private static long globalBufferCount; private static long threadBufferSize; private static int stackDepth; - private static boolean sampleThreads; private static long maxChunkSize; - private static SafePath dumpPath; static { final long pageSize = Unsafe.getUnsafe().pageSize(); @@ -113,12 +117,19 @@ public final class Options { globalBufferSize = globalBufsize; } - public static synchronized void setDumpPath(SafePath path) { - dumpPath = path; + public static synchronized void setDumpPath(SafePath path) throws IOException { + if (path != null) { + if (SecuritySupport.isWritable(path)) { + path = SecuritySupport.toRealPath(path, NOFOLLOW_LINKS); + } else { + throw new IOException("Cannot write JFR emergency dump to " + path.toString()); + } + } + jvm.setDumpPath(path == null ? null : path.toString()); } public static synchronized SafePath getDumpPath() { - return dumpPath; + return new SafePath(jvm.getDumpPath()); } public static synchronized void setStackDepth(Integer stackTraceDepth) { @@ -130,22 +141,16 @@ public final class Options { return stackDepth; } - public static synchronized void setSampleThreads(Boolean sample) { - jvm.setSampleThreads(sample); - sampleThreads = sample; - } - - public static synchronized boolean getSampleThreads() { - return sampleThreads; - } - private static synchronized void reset() { setMaxChunkSize(DEFAULT_MAX_CHUNK_SIZE); setMemorySize(DEFAULT_MEMORY_SIZE); setGlobalBufferSize(DEFAULT_GLOBAL_BUFFER_SIZE); setGlobalBufferCount(DEFAULT_GLOBAL_BUFFER_COUNT); - setDumpPath(DEFAULT_DUMP_PATH); - setSampleThreads(DEFAULT_SAMPLE_THREADS); + try { + setDumpPath(DEFAULT_DUMP_PATH); + } catch (IOException e) { + // Ignore (depends on default value in JVM: it would be NULL) + } setStackDepth(DEFAULT_STACK_DEPTH); setThreadBufferSize(DEFAULT_THREAD_BUFFER_SIZE); } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformRecorder.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformRecorder.java index ef1d51a06228e03d35edcfcf178c10dbdac4bc65..c0c62c64bb0c4dd2e48baa8ac8bfffd4590beaee 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformRecorder.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformRecorder.java @@ -36,7 +36,6 @@ import java.security.AccessControlContext; import java.security.AccessController; import java.time.Duration; import java.time.Instant; -import java.time.ZonedDateTime; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -249,7 +248,7 @@ public final class PlatformRecorder { } currentChunk = newChunk; jvm.beginRecording(); - startNanos = jvm.getChunkStartNanos(); + startNanos = Utils.getChunkStartNanos(); startTime = Utils.epochNanosToInstant(startNanos); if (currentChunk != null) { currentChunk.setStartTime(startTime); @@ -270,7 +269,7 @@ public final class PlatformRecorder { startTime = MetadataRepository.getInstance().setOutput(p); newChunk.setStartTime(startTime); } - startNanos = jvm.getChunkStartNanos(); + startNanos = Utils.getChunkStartNanos(); startTime = Utils.epochNanosToInstant(startNanos); recording.setStartTime(startTime); recording.setState(RecordingState.RUNNING); @@ -317,7 +316,7 @@ public final class PlatformRecorder { } } OldObjectSample.emit(recording); - recording.setFinalStartnanos(jvm.getChunkStartNanos()); + recording.setFinalStartnanos(Utils.getChunkStartNanos()); if (endPhysical) { RequestEngine.doChunkEnd(); @@ -437,7 +436,7 @@ public final class PlatformRecorder { } // n*log(n), should be able to do n*log(k) with a priority queue, // where k = number of recordings, n = number of chunks - Collections.sort(chunks, RepositoryChunk.END_TIME_COMPARATOR); + chunks.sort(RepositoryChunk.END_TIME_COMPARATOR); return chunks; } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/PrivateAccess.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/PrivateAccess.java index def05bba4c985843d3ff9e1dcc545e99605e2e08..09d53b4b5620b374376fed7c658956ac3deb30c6 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/PrivateAccess.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/PrivateAccess.java @@ -103,4 +103,6 @@ public abstract class PrivateAccess { public abstract AccessControlContext getContext(SettingControl sc); public abstract EventSettings newEventSettings(EventSettingsModifier esm); + + public abstract boolean isVisible(EventType t); } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/RepositoryChunk.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/RepositoryChunk.java index af5ff3e08e4e1a3bce09c5bfe43c4b8709da4e49..8cb8bd85c3791ebd9e7686b6c6151047607d4db2 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/RepositoryChunk.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/RepositoryChunk.java @@ -134,7 +134,7 @@ final class RepositoryChunk { } @Override - @SuppressWarnings("deprecation") + @SuppressWarnings("removal") protected void finalize() { boolean destroy = false; synchronized (this) { diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/RequestEngine.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/RequestEngine.java index 49aa2bcd3f24676400ce81b27564f36ecb254c17..ff728fbf4f2a7d8eedf87047d4b8e8c097627054 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/RequestEngine.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/RequestEngine.java @@ -28,7 +28,6 @@ package jdk.jfr.internal; import java.security.AccessControlContext; import java.security.AccessController; import java.security.PrivilegedAction; -import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; @@ -162,10 +161,8 @@ public final class RequestEngine { // Only to be used for JVM events. No access control contest // or check if hook already exists static void addHooks(List<RequestHook> newEntries) { - List<RequestHook> addEntries = new ArrayList<>(); for (RequestHook rh : newEntries) { rh.type.setEventHook(true); - addEntries.add(rh); logHook("Added", rh.type); } entries.addAll(newEntries); diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/SecuritySupport.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/SecuritySupport.java index d761eb98c58c548021ade6d1dfdd05613304b459..ee30821dcf83b4f660af48f777a03e7d3e976b83 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/SecuritySupport.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/SecuritySupport.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -33,7 +33,6 @@ import java.io.RandomAccessFile; import java.io.Reader; import java.lang.invoke.MethodHandles; import java.lang.reflect.Constructor; -import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.ReflectPermission; import java.nio.channels.FileChannel; @@ -41,6 +40,7 @@ import java.nio.channels.ReadableByteChannel; import java.nio.file.DirectoryStream; import java.nio.file.FileVisitResult; import java.nio.file.Files; +import java.nio.file.LinkOption; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.SimpleFileVisitor; @@ -77,7 +77,6 @@ public final class SecuritySupport { private static final Module JFR_MODULE = Event.class.getModule(); public static final SafePath JFC_DIRECTORY = getPathInProperty("java.home", "lib/jfr"); public static final FileAccess PRIVILEGED = new Privileged(); - static final SafePath USER_HOME = getPathInProperty("user.home", null); static final SafePath JAVA_IO_TMPDIR = getPathInProperty("java.io.tmpdir", null); static { @@ -150,7 +149,7 @@ public final class SecuritySupport { } /** - * Path created by the default file provider,and not + * Path created by the default file provider, and not * a malicious provider. * */ @@ -267,14 +266,11 @@ public final class SecuritySupport { public static List<SafePath> getPredefinedJFCFiles() { List<SafePath> list = new ArrayList<>(); - try { - Iterator<Path> pathIterator = doPrivilegedIOWithReturn(() -> { - return Files.newDirectoryStream(JFC_DIRECTORY.toPath(), "*").iterator(); - }); - while (pathIterator.hasNext()) { - Path path = pathIterator.next(); - if (path.toString().endsWith(".jfc")) { - list.add(new SafePath(path)); + try (var ds = doPrivilegedIOWithReturn(() -> Files.newDirectoryStream(JFC_DIRECTORY.toPath(), "*.jfc"))) { + for (Path path : ds) { + SafePath s = new SafePath(path); + if (!SecuritySupport.isDirectory(s)) { + list.add(s); } } } catch (IOException ioe) { @@ -357,16 +353,12 @@ public final class SecuritySupport { doPrivileged(() -> thread.setUncaughtExceptionHandler(eh), new RuntimePermission("modifyThread")); } - static void moveReplace(SafePath from, SafePath to) throws IOException { - doPrivilegedIOWithReturn(() -> Files.move(from.toPath(), to.toPath())); - } - static void clearDirectory(SafePath safePath) throws IOException { doPriviligedIO(() -> Files.walkFileTree(safePath.toPath(), new DirectoryCleaner())); } - static SafePath toRealPath(SafePath safePath) throws IOException { - return new SafePath(doPrivilegedIOWithReturn(() -> safePath.toPath().toRealPath())); + static SafePath toRealPath(SafePath safePath, LinkOption... options) throws IOException { + return new SafePath(doPrivilegedIOWithReturn(() -> safePath.toPath().toRealPath(options))); } static boolean existDirectory(SafePath directory) throws IOException { @@ -407,10 +399,6 @@ public final class SecuritySupport { return doPrivilegedIOWithReturn(() -> Files.isWritable(safePath.toPath())); } - static void deleteOnExit(SafePath safePath) { - doPrivileged(() -> safePath.toPath().toFile().deleteOnExit()); - } - static ReadableByteChannel newFileChannelToRead(SafePath safePath) throws IOException { return doPrivilegedIOWithReturn(() -> FileChannel.open(safePath.toPath(), StandardOpenOption.READ)); } @@ -423,10 +411,6 @@ public final class SecuritySupport { return doPrivilegedIOWithReturn(() -> Files.newBufferedReader(safePath.toPath())); } - static void touch(SafePath path) throws IOException { - doPriviligedIO(() -> new RandomAccessFile(path.toPath().toFile(), "rw").close()); - } - static void setAccessible(Method method) { doPrivileged(() -> method.setAccessible(true), new ReflectPermission("suppressAccessChecks")); } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/SettingsManager.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/SettingsManager.java index db239b980e504b94ae55bfdc0e6dad37d70c3cee..d6078ef9f985e637580804bf852ef54ec18bfdd1 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/SettingsManager.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/SettingsManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -27,7 +27,7 @@ package jdk.jfr.internal; import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; +import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; @@ -140,7 +140,7 @@ final class SettingsManager { } } else { if (Logger.shouldLog(LogTag.JFR_SETTING, LogLevel.INFO)) { - Collections.sort(eventControls, (x,y) -> x.getEventType().getName().compareTo(y.getEventType().getName())); + eventControls.sort(Comparator.comparing(x -> x.getEventType().getName())); } for (EventControl ec : eventControls) { setEventControl(ec); 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 9b6891bcdec515acb376d0bb14a6e0c08b61af4e..27938ed023c30678d5dd9a19449827481082e08e 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/Type.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/Type.java @@ -89,6 +89,8 @@ public class Type implements Comparable<Type> { private Boolean simpleType; // calculated lazy private boolean remove = true; private long id; + private boolean visible = true; + private boolean internal; /** * Creates a type @@ -337,4 +339,20 @@ public class Type implements Comparable<Type> { public void setId(long id) { this.id = id; } + + public void setVisible(boolean visible) { + this.visible = visible; + } + + public boolean isVisible() { + return visible; + } + + public void setInternal(boolean internal) { + this.internal = internal; + } + + public boolean isInternal() { + return internal; + } } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/TypeLibrary.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/TypeLibrary.java index fb16c92f1716a1d9d8098fa9b16b09ba2ddbc769..1555bcc2aac660500288ecea18429f32defad535 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/TypeLibrary.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/TypeLibrary.java @@ -36,6 +36,7 @@ import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; @@ -108,7 +109,7 @@ public final class TypeLibrary { List<Type> jvmTypes; try { jvmTypes = MetadataLoader.createTypes(); - Collections.sort(jvmTypes, (a,b) -> Long.compare(a.getId(), b.getId())); + jvmTypes.sort(Comparator.comparingLong(Type::getId)); } catch (IOException e) { throw new Error("JFR: Could not read metadata"); } @@ -118,8 +119,19 @@ public final class TypeLibrary { } } - public List<Type> getTypes() { - return new ArrayList<>(types.values()); + public Collection<Type> getTypes() { + return types.values(); + } + + // Returned list should be mutable (for in-place sorting) + public List<Type> getVisibleTypes() { + List<Type> visible = new ArrayList<>(types.size()); + types.values().forEach(t -> { + if (t.isVisible()) { + visible.add(t); + } + }); + return visible; } public static Type createAnnotationType(Class<? extends Annotation> a) { diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/Utils.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/Utils.java index 38179ba891b75553fad3987d42d9fd23c68bff93..c0324d2d7f6d38fb8b29e55900ab55b04bcda3bf 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/Utils.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/Utils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -97,6 +97,7 @@ public final class Utils { * The possible data race is benign and is worth of not introducing any contention here. */ private static Metrics[] metrics; + private static Instant lastTimestamp; public static void checkAccessFlightRecorder() throws SecurityException { @SuppressWarnings("removal") @@ -866,4 +867,30 @@ public final class Utils { throw new IllegalArgumentException("'" + name + "' is not a valid Java identifier"); } } + + public static long getChunkStartNanos() { + long nanos = JVM.getJVM().getChunkStartNanos(); + // JVM::getChunkStartNanos() may return a bumped timestamp, +1 ns or +2 ns. + // Spin here to give Instant.now() a chance to catch up. + awaitUniqueTimestamp(); + return nanos; + } + + private static void awaitUniqueTimestamp() { + if (lastTimestamp == null) { + lastTimestamp = Instant.now(); // lazy initialization + } + while (true) { + Instant time = Instant.now(); + if (!time.equals(lastTimestamp)) { + lastTimestamp = time; + return; + } + try { + Thread.sleep(0, 100); + } catch (InterruptedException iex) { + // ignore + } + } + } } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/AbstractEventStream.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/AbstractEventStream.java index 4323e0cfeae3c2323a47859e9f41f207eb88255b..f3e6090149fa9b3cfae5423147c3fc65fd65f959 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/AbstractEventStream.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/AbstractEventStream.java @@ -65,7 +65,7 @@ public abstract class AbstractEventStream implements EventStream { private volatile Thread thread; private Dispatcher dispatcher; - private volatile boolean closed; + protected final ParserState parserState = new ParserState(); private boolean daemon = false; @@ -111,7 +111,7 @@ public abstract class AbstractEventStream implements EventStream { @Override public final void setStartTime(Instant startTime) { - Objects.requireNonNull(startTime); + Objects.requireNonNull(startTime, "startTime"); synchronized (streamConfiguration) { if (streamConfiguration.started) { throw new IllegalStateException("Stream is already started"); @@ -125,7 +125,7 @@ public abstract class AbstractEventStream implements EventStream { @Override public final void setEndTime(Instant endTime) { - Objects.requireNonNull(endTime); + Objects.requireNonNull(endTime, "endTime"); synchronized (streamConfiguration) { if (streamConfiguration.started) { throw new IllegalStateException("Stream is already started"); @@ -136,38 +136,38 @@ public abstract class AbstractEventStream implements EventStream { @Override public final void onEvent(Consumer<RecordedEvent> action) { - Objects.requireNonNull(action); + Objects.requireNonNull(action, "action"); streamConfiguration.addEventAction(action); } @Override public final void onEvent(String eventName, Consumer<RecordedEvent> action) { - Objects.requireNonNull(eventName); - Objects.requireNonNull(action); + Objects.requireNonNull(eventName, "eventName"); + Objects.requireNonNull(action, "action"); streamConfiguration.addEventAction(eventName, action); } @Override public final void onFlush(Runnable action) { - Objects.requireNonNull(action); + Objects.requireNonNull(action, "action"); streamConfiguration.addFlushAction(action); } @Override public final void onClose(Runnable action) { - Objects.requireNonNull(action); + Objects.requireNonNull(action, "action"); streamConfiguration.addCloseAction(action); } @Override public final void onError(Consumer<Throwable> action) { - Objects.requireNonNull(action); + Objects.requireNonNull(action, "action"); streamConfiguration.addErrorAction(action); } @Override public final boolean remove(Object action) { - Objects.requireNonNull(action); + Objects.requireNonNull(action, "action"); return streamConfiguration.remove(action); } @@ -178,7 +178,7 @@ public abstract class AbstractEventStream implements EventStream { @Override public final void awaitTermination(Duration timeout) throws InterruptedException { - Objects.requireNonNull(timeout); + Objects.requireNonNull(timeout, "timeout"); if (timeout.isNegative()) { throw new IllegalArgumentException("timeout value is negative"); } @@ -215,12 +215,12 @@ public abstract class AbstractEventStream implements EventStream { protected abstract void process() throws IOException; - protected final void setClosed(boolean closed) { - this.closed = closed; + protected final void closeParser() { + parserState.close(); } protected final boolean isClosed() { - return closed; + return parserState.isClosed(); } public final void startAsync(long startNanos) { @@ -298,7 +298,7 @@ public abstract class AbstractEventStream implements EventStream { @Override public void onMetadata(Consumer<MetadataEvent> action) { - Objects.requireNonNull(action); + Objects.requireNonNull(action, "action"); synchronized (streamConfiguration) { if (streamConfiguration.started) { throw new IllegalStateException("Stream is already started"); diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ChunkHeader.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ChunkHeader.java index 4027f447cf4caba8867b0d69c8f1a54cdc573bbc..550878888cd74e936a627906dc294c5abc7b9aa1 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ChunkHeader.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ChunkHeader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -34,9 +34,9 @@ import jdk.jfr.internal.MetadataDescriptor; import jdk.jfr.internal.Utils; public final class ChunkHeader { - static final long HEADER_SIZE = 68; + public static final long HEADER_SIZE = 68; static final byte UPDATING_CHUNK_HEADER = (byte) 255; - static final long CHUNK_SIZE_POSITION = 8; + public static final long CHUNK_SIZE_POSITION = 8; static final long DURATION_NANOS_POSITION = 40; static final long FILE_STATE_POSITION = 64; static final long FLAG_BYTE_POSITION = 67; @@ -92,10 +92,10 @@ public final class ChunkHeader { } long c = input.readRawLong(); // chunk size Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.INFO, "Chunk: chunkSize=" + c); - input.readRawLong(); // constant pool position - Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.INFO, "Chunk: constantPoolPosition=" + constantPoolPosition); - input.readRawLong(); // metadata position - Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.INFO, "Chunk: metadataPosition=" + metadataPosition); + long cp = input.readRawLong(); // constant pool position + Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.INFO, "Chunk: constantPoolPosition=" + cp); + long mp = input.readRawLong(); // metadata position + Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.INFO, "Chunk: metadataPosition=" + mp); chunkStartNanos = input.readRawLong(); // nanos since epoch Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.INFO, "Chunk: startNanos=" + chunkStartNanos); durationNanos = input.readRawLong(); // duration nanos, not used @@ -109,14 +109,19 @@ public final class ChunkHeader { input.position(absoluteEventStart); } + private byte readFileState() throws IOException { + byte fs; + input.positionPhysical(absoluteChunkStart + FILE_STATE_POSITION); + while ((fs = input.readPhysicalByte()) == UPDATING_CHUNK_HEADER) { + Utils.takeNap(1); + input.positionPhysical(absoluteChunkStart + FILE_STATE_POSITION); + } + return fs; + } + public void refresh() throws IOException { while (true) { - byte fileState1; - input.positionPhysical(absoluteChunkStart + FILE_STATE_POSITION); - while ((fileState1 = input.readPhysicalByte()) == UPDATING_CHUNK_HEADER) { - Utils.takeNap(1); - input.positionPhysical(absoluteChunkStart + FILE_STATE_POSITION); - } + byte fileState1 = readFileState(); input.positionPhysical(absoluteChunkStart + CHUNK_SIZE_POSITION); long chunkSize = input.readPhysicalLong(); long constantPoolPosition = input.readPhysicalLong(); @@ -163,24 +168,15 @@ public final class ChunkHeader { } } - public boolean readHeader(byte[] bytes, int count) throws IOException { - input.position(absoluteChunkStart); - for (int i = 0; i< count; i++) { - bytes[i] = input.readPhysicalByte(); - } - return bytes[(int)FILE_STATE_POSITION] != UPDATING_CHUNK_HEADER; - } - public void awaitFinished() throws IOException { if (finished) { return; } long pos = input.position(); try { - input.positionPhysical(absoluteChunkStart + FILE_STATE_POSITION); while (true) { - byte filestate = input.readPhysicalByte(); - if (filestate == 0) { + byte fileState = readFileState(); + if (fileState == 0) { finished = true; return; } @@ -251,7 +247,7 @@ public final class ChunkHeader { return constantPoolPosition; } - public long getMetataPosition() { + public long getMetadataPosition() { return metadataPosition; } public long getStartTicks() { diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ChunkParser.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ChunkParser.java index afa868f85b6821ef47bc57c09cd3431cc27f6d66..9d88adcf478a24e01de6e816088ba1b143dc582d 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ChunkParser.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ChunkParser.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -41,6 +41,8 @@ import jdk.jfr.internal.LongMap; import jdk.jfr.internal.MetadataDescriptor; import jdk.jfr.internal.Type; import jdk.jfr.internal.Utils; +import jdk.jfr.internal.consumer.filter.CheckpointEvent; +import jdk.jfr.internal.consumer.filter.ChunkWriter; /** * Parses a chunk. @@ -48,24 +50,26 @@ import jdk.jfr.internal.Utils; */ public final class ChunkParser { - static final class ParserConfiguration { + public static final class ParserConfiguration { private final boolean reuse; private final boolean ordered; private final ParserFilter eventFilter; + private final ChunkWriter chunkWriter; long filterStart; long filterEnd; - ParserConfiguration(long filterStart, long filterEnd, boolean reuse, boolean ordered, ParserFilter filter) { + public ParserConfiguration(long filterStart, long filterEnd, boolean reuse, boolean ordered, ParserFilter filter, ChunkWriter chunkWriter) { this.filterStart = filterStart; this.filterEnd = filterEnd; this.reuse = reuse; this.ordered = ordered; this.eventFilter = filter; + this.chunkWriter = chunkWriter; } public ParserConfiguration() { - this(0, Long.MAX_VALUE, false, false, ParserFilter.ACCEPT_ALL); + this(0, Long.MAX_VALUE, false, false, ParserFilter.ACCEPT_ALL, null); } public boolean isOrdered() { @@ -73,7 +77,7 @@ public final class ChunkParser { } } - private enum CheckPointType { + private enum CheckpointType { // Checkpoint that finishes a flush segment FLUSH(1), // Checkpoint contains chunk header information in the first pool @@ -83,7 +87,7 @@ public final class ChunkParser { // Checkpoint contains thread related information THREAD(8); private final int mask; - private CheckPointType(int mask) { + private CheckpointType(int mask) { this.mask = mask; } @@ -97,7 +101,7 @@ public final class ChunkParser { private final RecordingInput input; private final ChunkHeader chunkHeader; private final TimeConverter timeConverter; - + private final ParserState parserState; private final LongMap<ConstantLookup> constantLookups; private LongMap<Type> typeMap; @@ -105,24 +109,24 @@ public final class ChunkParser { private boolean chunkFinished; private ParserConfiguration configuration; - private volatile boolean closed; private MetadataDescriptor previousMetadata; private MetadataDescriptor metadata; private boolean staleMetadata = true; - public ChunkParser(RecordingInput input) throws IOException { - this(input, new ParserConfiguration()); + public ChunkParser(RecordingInput input, ParserState ps) throws IOException { + this(input, new ParserConfiguration(), ps); } - ChunkParser(RecordingInput input, ParserConfiguration pc) throws IOException { - this(new ChunkHeader(input), null, pc); + public ChunkParser(RecordingInput input, ParserConfiguration pc, ParserState ps) throws IOException { + this(new ChunkHeader(input), null, pc, ps); } - private ChunkParser(ChunkParser previous) throws IOException { - this(new ChunkHeader(previous.input), previous, new ParserConfiguration()); - } + private ChunkParser(ChunkParser previous, ParserState ps) throws IOException { + this(new ChunkHeader(previous.input), previous, new ParserConfiguration(), ps); + } - private ChunkParser(ChunkHeader header, ChunkParser previous, ParserConfiguration pc) throws IOException { + private ChunkParser(ChunkHeader header, ChunkParser previous, ParserConfiguration pc, ParserState ps) throws IOException { + this.parserState = ps; this.configuration = pc; this.input = header.getInput(); this.chunkHeader = header; @@ -155,7 +159,7 @@ public final class ChunkParser { } public ChunkParser nextChunkParser() throws IOException { - return new ChunkParser(chunkHeader.nextHeader(), this, configuration); + return new ChunkParser(chunkHeader.nextHeader(), this, configuration, parserState); } private void updateConfiguration() { @@ -199,7 +203,7 @@ public final class ChunkParser { return event; } long lastValid = absoluteChunkEnd; - long metadataPosition = chunkHeader.getMetataPosition(); + long metadataPosition = chunkHeader.getMetadataPosition(); long constantPosition = chunkHeader.getConstantPoolPosition(); chunkFinished = awaitUpdatedHeader(absoluteChunkEnd, configuration.filterEnd); if (chunkFinished) { @@ -208,7 +212,7 @@ public final class ChunkParser { } absoluteChunkEnd = chunkHeader.getEnd(); // Read metadata and constant pools for the next segment - if (chunkHeader.getMetataPosition() != metadataPosition) { + if (chunkHeader.getMetadataPosition() != metadataPosition) { Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.INFO, "Found new metadata in chunk. Rebuilding types and parsers"); this.previousMetadata = this.metadata; this.metadata = chunkHeader.readMetadata(previousMetadata); @@ -247,13 +251,23 @@ public final class ChunkParser { // Fast path RecordedEvent event = ep.parse(input); if (event != null) { + ChunkWriter chunkWriter = configuration.chunkWriter; + if (chunkWriter != null) { + if (chunkWriter.accept(event)) { + chunkWriter.writeEvent(pos, input.position()); + input.position(pos); + input.readInt(); // size + input.readLong(); // type + chunkWriter.touch(ep.parseReferences(input)); + } + } input.position(pos + size); return event; } // Not accepted by filter } else { if (typeId == 1) { // checkpoint event - if (CheckPointType.FLUSH.is(parseCheckpointType())) { + if (CheckpointType.FLUSH.is(parseCheckpointType())) { input.position(pos + size); return FLUSH_MARKER; } @@ -280,7 +294,7 @@ public final class ChunkParser { Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.INFO, "Waiting for more data (streaming). Read so far: " + chunkHeader.getChunkSize() + " bytes"); } while (true) { - if (closed) { + if (parserState.isClosed()) { return true; } if (chunkHeader.getLastNanos() > filterEnd) { @@ -303,6 +317,10 @@ public final class ChunkParser { long delta = -1; boolean logTrace = Logger.shouldLog(LogTag.JFR_SYSTEM_PARSER, LogLevel.TRACE); while (thisCP != abortCP && delta != 0) { + CheckpointEvent cp = null; + if (configuration.chunkWriter != null) { + cp = configuration.chunkWriter.newCheckpointEvent(thisCP); + } input.position(thisCP); lastCP = thisCP; int size = input.readInt(); // size @@ -333,7 +351,7 @@ public final class ChunkParser { throw new IOException( "Error parsing constant pool type " + getName(id) + " at position " + input.position() + " at check point between [" + lastCP + ", " + (lastCP + size) + "]"); } - ConstantMap pool = new ConstantMap(ObjectFactory.create(type, timeConverter), type.getName()); + ConstantMap pool = new ConstantMap(ObjectFactory.create(type, timeConverter), type); lookup = new ConstantLookup(pool, type); constantLookups.put(type.getId(), lookup); } @@ -350,6 +368,7 @@ public final class ChunkParser { Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.TRACE, "Constant Pool " + i + ": " + type.getName()); } for (int j = 0; j < count; j++) { + long position = input.position(); long key = input.readLong(); Object resolved = lookup.getPreviousResolved(key); if (resolved == null) { @@ -361,6 +380,12 @@ public final class ChunkParser { logConstant(key, resolved, true); lookup.getLatestPool().putResolved(key, resolved); } + if (cp != null) { + input.position(position); + input.readLong(); + Object refs = parser.parseReferences(input); + cp.addEntry(type, key, position, input.position(), refs); + } } } catch (Exception e) { throw new IOException("Error parsing constant pool type " + getName(id) + " at position " + input.position() + " at check point between [" + lastCP + ", " + (lastCP + size) + "]", @@ -436,8 +461,8 @@ public final class ChunkParser { return chunkHeader.isLastChunk(); } - ChunkParser newChunkParser() throws IOException { - return new ChunkParser(this); + public ChunkParser newChunkParser() throws IOException { + return new ChunkParser(this, parserState); } public boolean isChunkFinished() { @@ -457,7 +482,7 @@ public final class ChunkParser { } public void close() { - this.closed = true; + parserState.close(); try { input.close(); } catch(IOException e) { @@ -488,4 +513,8 @@ public final class ChunkParser { }); } } + + public ChunkHeader getHeader() { + return chunkHeader; + } } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/CompositeParser.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/CompositeParser.java new file mode 100644 index 0000000000000000000000000000000000000000..72a9bf0ec668562b9b6de157ce2302f867e2150e --- /dev/null +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/CompositeParser.java @@ -0,0 +1,74 @@ +/* + * 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. 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.jfr.internal.consumer; + +import java.io.IOException; +import java.util.ArrayList; + +public final class CompositeParser extends Parser { + final Parser[] parsers; + + public CompositeParser(Parser[] valueParsers) { + this.parsers = valueParsers; + } + + @Override + public Object parse(RecordingInput input) throws IOException { + final Object[] values = new Object[parsers.length]; + for (int i = 0; i < values.length; i++) { + values[i] = parsers[i].parse(input); + } + return values; + } + + @Override + public void skip(RecordingInput input) throws IOException { + for (int i = 0; i < parsers.length; i++) { + parsers[i].skip(input); + } + } + + @Override + public Object parseReferences(RecordingInput input) throws IOException { + return parseReferences(input, parsers); + } + + static Object parseReferences(RecordingInput input, Parser[] parsers) throws IOException { + ArrayList<Object> refs = new ArrayList<>(parsers.length); + for (int i = 0; i < parsers.length; i++) { + Object ref = parsers[i].parseReferences(input); + if (ref != null) { + refs.add(ref); + } + } + if (refs.isEmpty()) { + return null; + } + if (refs.size() == 1) { + return refs.get(0); + } + return refs.toArray(); + } +} \ No newline at end of file diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ConstantLookup.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ConstantLookup.java index 4ae6cde058b2dd55df3df1444e8a1a49519f4a8c..e4c5435cc30276e5ee387531d0fc490f41088f56 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ConstantLookup.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ConstantLookup.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -28,7 +28,7 @@ package jdk.jfr.internal.consumer; import jdk.jfr.internal.Type; final class ConstantLookup { - private final Type type; + final Type type; private ConstantMap current; private ConstantMap previous = ConstantMap.EMPTY; @@ -47,7 +47,7 @@ final class ConstantLookup { public void newPool() { previous = current; - current = new ConstantMap(current.factory, current.name); + current = new ConstantMap(current.factory, current.type); } public Object getPreviousResolved(long key) { diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ConstantMap.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ConstantMap.java index 55b60b7240f1ec9fa4201a36f7cc8556f6e7a58b..79d001fcac452111c54a3f48c8b53c98cf29c005 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ConstantMap.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ConstantMap.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -30,6 +30,7 @@ import jdk.jfr.internal.LogTag; import jdk.jfr.internal.Logger; import jdk.jfr.internal.LongMap; +import jdk.jfr.internal.Type; /** * Holds mapping between a set of keys and their corresponding object. @@ -38,49 +39,23 @@ import jdk.jfr.internal.LongMap; * {@link ObjectFactory} can be supplied which will instantiate a typed object. */ final class ConstantMap { - private static final int RESOLUTION_FINISHED = 0; private static final int RESOLUTION_STARTED = 1; public static final ConstantMap EMPTY = new ConstantMap(); - // A temporary placeholder, so objects can - // reference themselves (directly, or indirectly), - // when making a transition from numeric id references - // to normal Java references. - private static final class Reference { - private final long key; - private final ConstantMap pool; - - Reference(ConstantMap pool, long key) { - this.pool = pool; - this.key = key; - } - - Object resolve() { - return pool.get(key); - } - - @Override - public String toString() { - return "ref: " + pool.name + "[" + key + "]"; - } - } - final ObjectFactory<?> factory; - final String name; - + final Type type; private final LongMap<Object> objects; - private boolean resolving; private boolean allResolved; private ConstantMap() { - this(null, "<empty>"); + this(null, null); allResolved = true; } - ConstantMap(ObjectFactory<?> factory, String name) { - this.name = name; + ConstantMap(ObjectFactory<?> factory, Type type) { + this.type = type; this.objects = new LongMap<>(2); this.factory = factory; } @@ -100,7 +75,7 @@ final class ConstantMap { if (value == null) { // unless id is 0 which is used to represent null if (id != 0) { - Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.INFO, "Missing object id=" + id + " in pool " + name + ". All ids should reference an object"); + Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.INFO, "Missing object id=" + id + " in pool " + getName() + ". All ids should reference an object"); } return null; } @@ -174,7 +149,12 @@ final class ConstantMap { } public String getName() { - return name; + return type == null ? "<empty>" : type.getName(); + } + + // Can be null + public Type getType() { + return type; } public Object getResolved(long id) { @@ -189,4 +169,8 @@ final class ConstantMap { public void setAllResolved(boolean allResolved) { this.allResolved = allResolved; } + + public LongMap<Object> getObjects() { + return objects; + } } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/Dispatcher.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/Dispatcher.java index 721d5b190fc9cbbc4a6e4e5d8b1a2d7510111ed8..094e7d9538bbdcc4c939b85ec230bbbe9b5ffc0b 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/Dispatcher.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/Dispatcher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -85,7 +85,7 @@ final class Dispatcher { this.errorActions = c.errorActions.toArray(new Consumer[0]); this.metadataActions = c.metadataActions.toArray(new Consumer[0]); this.dispatchers = c.eventActions.toArray(new EventDispatcher[0]); - this.parserConfiguration = new ParserConfiguration(0, Long.MAX_VALUE, c.reuse, c.ordered, buildFilter(dispatchers)); + this.parserConfiguration = new ParserConfiguration(0, Long.MAX_VALUE, c.reuse, c.ordered, buildFilter(dispatchers), null); this.startTime = c.startTime; this.endTime = c.endTime; this.startNanos = c.startNanos; @@ -160,6 +160,7 @@ final class Dispatcher { dispatcherLookup.put(type.getId(), dispatchers); } cacheDispatchers = dispatchers; + cacheEventType = type; } // Expected behavior if exception occurs in onEvent: // diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/EventDirectoryStream.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/EventDirectoryStream.java index 28db3b68f3fec54ebc1910f4e9f4f6a60e505bd5..37fea4b9439980a74113e3af0de0a511cfcdcc90 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/EventDirectoryStream.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/EventDirectoryStream.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -28,7 +28,6 @@ package jdk.jfr.internal.consumer; import java.io.IOException; import java.nio.file.Path; import java.security.AccessControlContext; -import java.time.Duration; import java.time.Instant; import java.util.Arrays; import java.util.Comparator; @@ -49,7 +48,7 @@ import jdk.jfr.internal.consumer.ChunkParser.ParserConfiguration; * with chunk files. * */ -public class EventDirectoryStream extends AbstractEventStream { +public final class EventDirectoryStream extends AbstractEventStream { private static final Comparator<? super RecordedEvent> EVENT_COMPARATOR = JdkJfrConsumer.instance().eventComparator(); @@ -60,8 +59,6 @@ public class EventDirectoryStream extends AbstractEventStream { private long currentChunkStartNanos; private RecordedEvent[] sortedCache; private int threadExclusionLevel = 0; - protected volatile long maxSize; - protected volatile Duration maxAge; private volatile Consumer<Long> onCompleteHandler; @@ -83,7 +80,7 @@ public class EventDirectoryStream extends AbstractEventStream { @Override public void close() { - setClosed(true); + closeParser(); dispatcher().runCloseActions(); repositoryFiles.close(); if (currentParser != null) { @@ -148,7 +145,7 @@ public class EventDirectoryStream extends AbstractEventStream { } currentChunkStartNanos = repositoryFiles.getTimestamp(path); try (RecordingInput input = new RecordingInput(path.toFile(), fileAccess)) { - currentParser = new ChunkParser(input, disp.parserConfiguration); + currentParser = new ChunkParser(input, disp.parserConfiguration, parserState); long segmentStart = currentParser.getStartNanos() + currentParser.getChunkDuration(); long filterStart = validStartTime ? disp.startNanos : segmentStart; long filterEnd = disp.endTime != null ? disp.endNanos : Long.MAX_VALUE; @@ -259,12 +256,4 @@ public class EventDirectoryStream extends AbstractEventStream { c.dispatch(e); } } - - public void setMaxSize(long maxSize) { - this.maxSize = maxSize; - } - - public void setMaxAge(Duration maxAge) { - this.maxAge = maxAge; - } } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/EventFileStream.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/EventFileStream.java index c4595ab639d599d1bbc4a0c8137211966bde4dbf..bbd06c8b8a83b5738781acc7e96f8d974d8b92a8 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/EventFileStream.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/EventFileStream.java @@ -46,10 +46,9 @@ public final class EventFileStream extends AbstractEventStream { private ChunkParser currentParser; private RecordedEvent[] cacheSorted; - public EventFileStream(@SuppressWarnings("removal") AccessControlContext acc, Path path) throws IOException { + public EventFileStream(@SuppressWarnings("removal") AccessControlContext acc, Path file) throws IOException { super(acc, null, Collections.emptyList()); - Objects.requireNonNull(path); - this.input = new RecordingInput(path.toFile(), FileAccess.UNPRIVILEGED); + this.input = new RecordingInput(file.toFile(), FileAccess.UNPRIVILEGED); } @Override @@ -64,7 +63,7 @@ public final class EventFileStream extends AbstractEventStream { @Override public void close() { - setClosed(true); + closeParser(); dispatcher().runCloseActions(); try { input.close(); @@ -85,7 +84,7 @@ public final class EventFileStream extends AbstractEventStream { end = disp.endNanos; } - currentParser = new ChunkParser(input, disp.parserConfiguration); + currentParser = new ChunkParser(input, disp.parserConfiguration, parserState); while (!isClosed()) { onMetadata(currentParser); if (currentParser.getStartNanos() > end) { diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/EventParser.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/EventParser.java index 56ac81d269cb8c704bd614a6ed2f0451abe07083..9ed091704e57a3782f5c57a1c71c894d9d27176b 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/EventParser.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/EventParser.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -28,7 +28,9 @@ package jdk.jfr.internal.consumer; import static jdk.jfr.internal.EventInstrumentation.FIELD_DURATION; import java.io.IOException; +import java.util.ArrayList; import java.util.List; +import java.util.function.Predicate; import jdk.jfr.EventType; import jdk.jfr.ValueDescriptor; @@ -154,6 +156,11 @@ final class EventParser extends Parser { return PRIVATE_ACCESS.newRecordedEvent(objectContext, values, startTicks, endTicks); } + @Override + public Object parseReferences(RecordingInput input) throws IOException { + return CompositeParser.parseReferences(input, parsers); + } + @Override public void skip(RecordingInput input) throws IOException { throw new InternalError("Should not call this method. More efficient to read event size and skip ahead"); diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ObjectContext.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ObjectContext.java index 3c946ba2097535aba8efa5acd4e9643b22e3f7ce..e855d0212a232923ec1cb5751b1066343d413258 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ObjectContext.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ObjectContext.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -26,7 +26,8 @@ package jdk.jfr.internal.consumer; import java.time.ZoneId; -import java.util.HashMap; +import java.util.ArrayDeque; +import java.util.IdentityHashMap; import java.util.List; import java.util.Map; @@ -34,33 +35,48 @@ import jdk.jfr.EventType; import jdk.jfr.ValueDescriptor; public final class ObjectContext { - private final Map<ValueDescriptor, ObjectContext> contextLookup; + private Map<ValueDescriptor, ObjectContext> contextLookup; private final TimeConverter timeConverter; - public final EventType eventType; public final List<ValueDescriptor> fields; ObjectContext(EventType eventType, List<ValueDescriptor> fields, TimeConverter timeConverter) { - this.contextLookup = new HashMap<>(); this.eventType = eventType; this.fields = fields; this.timeConverter = timeConverter; } - private ObjectContext(ObjectContext parent, ValueDescriptor descriptor) { - this.eventType = parent.eventType; - this.contextLookup = parent.contextLookup; - this.timeConverter = parent.timeConverter; - this.fields = descriptor.getFields(); + private ObjectContext(Map<ValueDescriptor, ObjectContext> contextLookup, EventType eventType, List<ValueDescriptor> fields, TimeConverter timeConverter) { + this.eventType = eventType; + this.contextLookup = contextLookup; + this.timeConverter = timeConverter; + this.fields = fields; } public ObjectContext getInstance(ValueDescriptor descriptor) { - ObjectContext context = contextLookup.get(descriptor); - if (context == null) { - context = new ObjectContext(this, descriptor); - contextLookup.put(descriptor, context); + if (contextLookup == null) { + // Lazy, only needed when accessing nested structures. + contextLookup = buildContextLookup(fields); + } + return contextLookup.get(descriptor); + } + + // Create mapping from ValueDescriptor to ObjectContext for all reachable + // ValueDescriptors. + public Map<ValueDescriptor, ObjectContext> buildContextLookup(List<ValueDescriptor> fields) { + Map<ValueDescriptor, ObjectContext> lookup = new IdentityHashMap<>(); + ArrayDeque<ValueDescriptor> q = new ArrayDeque<>(fields); + while (!q.isEmpty()) { + ValueDescriptor vd = q.pop(); + if (!lookup.containsKey(vd)) { + List<ValueDescriptor> children = vd.getFields(); + lookup.put(vd, new ObjectContext(lookup, eventType, children, timeConverter)); + for (ValueDescriptor v : children) { + q.add(v); + } + } } - return context; + return lookup; } public long convertTimestamp(long ticks) { diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/Parser.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/Parser.java index 49cbc13bdcbbb9bfac92ed1382bc2442e61358da..b1e0f27ff287544d43c8e38190bbcf4c2f1e143c 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/Parser.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/Parser.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -35,12 +35,28 @@ abstract class Parser { * Parses data from a {@link RecordingInput} and return an object. * * @param input input to read from - * @return an object + * @return an {@code Object}, an {@code Object[]}, or {@code null} * @throws IOException if operation couldn't be completed due to I/O * problems */ public abstract Object parse(RecordingInput input) throws IOException; + /** + * Parses data from a {@link RecordingInput} to find references to constants. If + * data is not a reference, {@code null} is returned. + * <p> + * @implSpec The default implementation of this method skips data and returns + * {@code Object}. + * + * @param input input to read from, not {@code null} + * @return a {@code Reference}, a {@code Reference[]}, or {@code null} + * @throws IOException if operation couldn't be completed due to I/O problems + */ + public Object parseReferences(RecordingInput input) throws IOException { + skip(input); + return null; + } + /** * Skips data that would usually be by parsed the {@link #parse(RecordingInput)} method. * diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ParserFactory.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ParserFactory.java index c04b80bd37a0aa6aa6c442588a6e610497257b95..51e10a5219e0642cfaab0ef7f4f6f77d89fd5415 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ParserFactory.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ParserFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -101,7 +101,7 @@ final class ParserFactory { if (constantPool) { ConstantLookup lookup = constantLookups.get(id); if (lookup == null) { - ConstantMap pool = new ConstantMap(ObjectFactory.create(type, timeConverter), type.getName()); + ConstantMap pool = new ConstantMap(ObjectFactory.create(type, timeConverter), type); lookup = new ConstantLookup(pool, type); constantLookups.put(id, lookup); } @@ -140,7 +140,7 @@ final class ParserFactory { case "byte": return new ByteParser(); case "java.lang.String": - ConstantMap pool = new ConstantMap(ObjectFactory.create(type, timeConverter), type.getName()); + ConstantMap pool = new ConstantMap(ObjectFactory.create(type, timeConverter), type); ConstantLookup lookup = new ConstantLookup(pool, type); constantLookups.put(type.getId(), lookup); return new StringParser(lookup, event); @@ -270,7 +270,7 @@ final class ParserFactory { @Override public void skip(RecordingInput input) throws IOException { - input.skipBytes(Float.SIZE); + input.skipBytes(Float.BYTES); } } @@ -282,7 +282,7 @@ final class ParserFactory { @Override public void skip(RecordingInput input) throws IOException { - input.skipBytes(Double.SIZE); + input.skipBytes(Double.BYTES); } } @@ -304,34 +304,20 @@ final class ParserFactory { } @Override - public void skip(RecordingInput input) throws IOException { + public Object parseReferences(RecordingInput input) throws IOException { final int size = input.readInt(); + final Object[] array = new Object[size]; for (int i = 0; i < size; i++) { - elementParser.skip(input); - } - } - } - - private static final class CompositeParser extends Parser { - private final Parser[] parsers; - - public CompositeParser(Parser[] valueParsers) { - this.parsers = valueParsers; - } - - @Override - public Object parse(RecordingInput input) throws IOException { - final Object[] values = new Object[parsers.length]; - for (int i = 0; i < values.length; i++) { - values[i] = parsers[i].parse(input); + array[i] = elementParser.parse(input); } - return values; + return array; } @Override public void skip(RecordingInput input) throws IOException { - for (int i = 0; i < parsers.length; i++) { - parsers[i].skip(input); + final int size = input.readInt(); + for (int i = 0; i < size; i++) { + elementParser.skip(input); } } } @@ -340,6 +326,8 @@ final class ParserFactory { private final ConstantLookup lookup; private Object lastValue = 0; private long lastKey = -1; + private Object lastReferenceValue; + private long lastReferenceKey = -1; EventValueConstantParser(ConstantLookup lookup) { this.lookup = lookup; } @@ -359,6 +347,17 @@ final class ParserFactory { public void skip(RecordingInput input) throws IOException { input.readLong(); } + + @Override + public Object parseReferences(RecordingInput input) throws IOException { + long key = input.readLong(); + if (key == lastReferenceKey) { + return lastReferenceValue; + } + lastReferenceKey = key; + lastReferenceValue = new Reference(lookup.getLatestPool(), key); + return lastReferenceValue; + } } private static final class ConstantValueParser extends Parser { @@ -376,5 +375,10 @@ final class ParserFactory { public void skip(RecordingInput input) throws IOException { input.readLong(); } + + @Override + public Object parseReferences(RecordingInput input) throws IOException { + return new Reference(lookup.getLatestPool(), input.readLong()); + } } } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ParserFilter.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ParserFilter.java index d805b934c932bf99e3273d0ea60e4c17d15d60ad..529823ec9be6cf3a99fd3732e4739647a143fe5b 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ParserFilter.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ParserFilter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -29,7 +29,7 @@ import java.util.HashMap; import java.util.Map; import java.util.StringJoiner; -final class ParserFilter { +public final class ParserFilter { public static final ParserFilter ACCEPT_ALL = new ParserFilter(true, Map.of()); private final Map<String, Long> thresholds; diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ParserState.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ParserState.java new file mode 100644 index 0000000000000000000000000000000000000000..a03cddfff9ea453bf753e894f96484162109cedd --- /dev/null +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ParserState.java @@ -0,0 +1,38 @@ +/* + * 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. 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.jfr.internal.consumer; + +public final class ParserState { + private volatile boolean closed; + + public boolean isClosed() { + return closed; + } + + public void close() { + closed = true; + } +} diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/Reference.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/Reference.java new file mode 100644 index 0000000000000000000000000000000000000000..0426898a5ae3cc7cdbbf28a69f19a31d13bdbcd6 --- /dev/null +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/Reference.java @@ -0,0 +1,49 @@ +/* + * 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. 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.jfr.internal.consumer; + +import jdk.jfr.internal.Type; + +/** + * A temporary placeholder, so objects can reference themselves (directly, or + * indirectly), when making a transition from numeric id references to Java + * object references. + */ +public record Reference(ConstantMap pool, long key) { + + Object resolve() { + return pool.get(key); + } + + public Type type() { + return pool.getType(); + } + + @Override + public String toString() { + return "ref: " + pool.getName() + "[" + key + "]"; + } +} \ No newline at end of file diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/RepositoryFiles.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/RepositoryFiles.java index 78bd18ddc7ad3beb8adcbd58d5b643f87da8981f..6ef88ecad375005f5dc99f0182dda52c64f8e0d3 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/RepositoryFiles.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/RepositoryFiles.java @@ -213,7 +213,7 @@ public final class RepositoryFiles { pathSet.remove(time); pathLookup.remove(remove); } - Collections.sort(added, (p1, p2) -> p1.compareTo(p2)); + Collections.sort(added); for (Path p : added) { // Only add files that have a complete header // as the JVM may be in progress writing the file diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/StringParser.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/StringParser.java index 4cc8f4252aa35d2e769edd63702950c2a9b76780..1fd116beda128d746de4af75b7b1ad8e93400d91 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/StringParser.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/StringParser.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -220,4 +220,31 @@ public final class StringParser extends Parser { } throw new IOException("Unknown string encoding " + encoding); } + + @Override + public Object parseReferences(RecordingInput input) throws IOException { + byte encoding = input.readByte(); + if (Encoding.CONSTANT_POOL.is(encoding)) { + return new Reference(stringLookup.getLatestPool(), input.readLong()); + } + if (Encoding.EMPTY_STRING.is(encoding)) { + return null; + } + if (Encoding.NULL.is(encoding)) { + return null; + } + if (Encoding.CHAR_ARRAY.is(encoding)) { + charArrayParser.skip(input); + return null; + } + if (Encoding.UT8_BYTE_ARRAY.is(encoding)) { + utf8parser.skip(input); + return null; + } + if (Encoding.LATIN1_BYTE_ARRAY.is(encoding)) { + latin1parser.skip(input); + return null; + } + throw new IOException("Unknown string encoding " + encoding); + } } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/filter/CheckpointEvent.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/filter/CheckpointEvent.java new file mode 100644 index 0000000000000000000000000000000000000000..72f40c0e7a722d33ff7998ffa7a268fdf2f1c7a4 --- /dev/null +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/filter/CheckpointEvent.java @@ -0,0 +1,86 @@ +/* + * 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. 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.jfr.internal.consumer.filter; + +import java.util.Collection; +import java.util.LinkedHashMap; + +import jdk.jfr.internal.Type; + +/** + * Represents a checkpoint event. + * <p> + * All positional values are relative to file start, not the chunk. + */ +public final class CheckpointEvent { + private final ChunkWriter chunkWriter; + private final LinkedHashMap<Long, CheckpointPool> pools = new LinkedHashMap<>(); + private final long startPosition; + + public CheckpointEvent(ChunkWriter chunkWriter, long startPosition) { + this.chunkWriter = chunkWriter; + this.startPosition = startPosition; + } + + public PoolEntry addEntry(Type type, long id, long startPosition, long endPosition, Object references) { + long typeId = type.getId(); + PoolEntry pe = new PoolEntry(startPosition, endPosition, type, id, references); + var cpp = pools.computeIfAbsent(typeId, k -> new CheckpointPool(typeId)); + cpp.add(pe); + chunkWriter.getPool(type).add(id, pe); + return pe; + } + + public long touchedPools() { + int count = 0; + for (CheckpointPool cpp : pools.values()) { + if (cpp.isTouched()) { + count++; + } + } + return count; + } + + public Collection<CheckpointPool> getPools() { + return pools.values(); + } + + public long getStartPosition() { + return startPosition; + } + + public String toString() { + StringBuilder sb = new StringBuilder(); + for (CheckpointPool p : pools.values()) { + for (var e : p.getEntries()) { + if (e.isTouched()) { + sb.append(e.getType().getName() + " " + e.getId() + "\n"); + } + } + } + return sb.toString(); + } +} \ No newline at end of file diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/filter/CheckpointPool.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/filter/CheckpointPool.java new file mode 100644 index 0000000000000000000000000000000000000000..d4b1ce926be94d6f5636009488a242a33279b91a --- /dev/null +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/filter/CheckpointPool.java @@ -0,0 +1,70 @@ +/* + * 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. 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.jfr.internal.consumer.filter; + +import java.util.ArrayList; +import java.util.List; +/** + * Represents a constant pool in a checkpoint, both entries and type id + */ +final class CheckpointPool { + private final List<PoolEntry> entries = new ArrayList<>(); + private final long typeId; + + public CheckpointPool(long typeId) { + this.typeId = typeId; + } + + public boolean isTouched() { + for (var entry : entries) { + if (entry.isTouched()) { + return true; + } + } + return false; + } + + public long getTouchedCount() { + int count = 0; + for (var entry : entries) { + if (entry.isTouched()) { + count++; + } + } + return count; + } + + public void add(PoolEntry pe) { + entries.add(pe); + } + + public long getTypeId() { + return typeId; + } + + public List<PoolEntry> getEntries() { + return entries; + } +} \ No newline at end of file diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/filter/ChunkWriter.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/filter/ChunkWriter.java new file mode 100644 index 0000000000000000000000000000000000000000..8c22432512a1ad5a9c4daffce01e9fbec077e331 --- /dev/null +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/filter/ChunkWriter.java @@ -0,0 +1,239 @@ +/* + * 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. 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.jfr.internal.consumer.filter; + +import java.io.Closeable; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayDeque; +import java.util.Deque; +import java.util.function.Predicate; + +import jdk.jfr.consumer.RecordedEvent; +import jdk.jfr.internal.LongMap; +import jdk.jfr.internal.Type; +import jdk.jfr.internal.consumer.ChunkHeader; +import jdk.jfr.internal.consumer.FileAccess; +import jdk.jfr.internal.Logger; +import jdk.jfr.internal.LogLevel; +import jdk.jfr.internal.LogTag; +import jdk.jfr.internal.consumer.RecordingInput; +import jdk.jfr.internal.consumer.Reference; + +/** + * Class that can filter out events and associated constants from a recording + * file. + * <p> + * All positional values are relative to file start, not the chunk. + */ +public final class ChunkWriter implements Closeable { + private LongMap<Constants> pools = new LongMap<>(); + private final Deque<CheckpointEvent> checkpoints = new ArrayDeque<>(); + private final Path destination; + private final RecordingInput input; + private final RecordingOutput output; + private final Predicate<RecordedEvent> filter; + + private long chunkStartPosition; + private boolean chunkComplete; + private long lastCheckpoint; + + public ChunkWriter(Path source, Path destination, Predicate<RecordedEvent> filter) throws IOException { + this.destination = destination; + this.output = new RecordingOutput(destination.toFile()); + this.input = new RecordingInput(source.toFile(), FileAccess.UNPRIVILEGED); + this.filter = filter; + } + + Constants getPool(Type type) { + long typeId = type.getId(); + Constants pool = pools.get(typeId); + if (pool == null) { + pool = new Constants(type); + pools.put(typeId, pool); + } + return pool; + } + + public CheckpointEvent newCheckpointEvent(long startPosition) { + CheckpointEvent event = new CheckpointEvent(this, startPosition); + checkpoints.add(event); + return event; + } + + public boolean accept(RecordedEvent event) { + return filter.test(event); + } + + public void touch(Object object) { + if (object instanceof Object[] array) { + for (int i = 0; i < array.length; i++) { + touch(array[i]); + } + return; + } + if (object instanceof Reference ref) { + touchRef(ref); + } + } + + private void touchRef(Reference ref) { + Constants pool = pools.get(ref.type().getId()); + if (pool == null) { + String msg = "Can't resolve " + ref.type().getName() + "[" + ref.key() + "]"; + Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.DEBUG, msg); + return; + } + PoolEntry entry = pool.get(ref.key()); + if (entry != null && !entry.isTouched()) { + entry.touch(); + touch(entry.getReferences()); + } + } + public void writeEvent(long startPosition, long endPosition) throws IOException { + writeCheckpointEvents(startPosition); + write(startPosition, endPosition); + } + + // Write check point events before a position + private void writeCheckpointEvents(long before) throws IOException { + CheckpointEvent cp = checkpoints.peek(); + while (cp != null && cp.getStartPosition() < before) { + checkpoints.poll(); + long delta = 0; + if (lastCheckpoint != 0) { + delta = lastCheckpoint - output.position(); + } + lastCheckpoint = output.position(); + write(cp, delta); + cp = checkpoints.peek(); + } + } + + public void write(long startPosition, long endPosition) throws IOException { + if (endPosition < startPosition) { + throw new IOException("Start position must come before end position, start=" + startPosition + ", end=" + endPosition); + } + long backup = input.position(); + input.position(startPosition); + long n = endPosition - startPosition; + for (long i = 0; i < n; i++) { + output.writeByte(input.readByte()); + } + input.position(backup); + } + + @Override + public void close() throws IOException { + try { + output.close(); + } finally { + if (!chunkComplete) { + // Error occurred, clean up + if (Files.exists(destination)) { + Files.delete(destination); + } + } + } + } + + public void beginChunk(ChunkHeader header) throws IOException { + this.chunkComplete = false; + this.chunkStartPosition = output.position(); + input.position(header.getAbsoluteChunkStart()); + for (int i = 0; i < ChunkHeader.HEADER_SIZE; i++) { + output.writeByte(input.readByte()); + } + } + + public void endChunk(ChunkHeader header) throws IOException { + // write all outstanding checkpoints + writeCheckpointEvents(Long.MAX_VALUE); + long metadata = output.position(); + writeMetadataEvent(header); + updateHeader(output.position(), lastCheckpoint, metadata); + pools = new LongMap<>(); + chunkComplete = true; + lastCheckpoint = 0; + } + + private void writeMetadataEvent(ChunkHeader header) throws IOException { + long metadataposition = header.getMetadataPosition() + header.getAbsoluteChunkStart(); + input.position(metadataposition); + long size = input.readLong(); + input.position(metadataposition); + for (int i = 0; i < size; i++) { + output.writeByte(input.readByte()); + } + } + + private void write(CheckpointEvent event, long delta) throws IOException { + input.position(event.getStartPosition()); + long startPosition = output.position(); + + input.readLong(); // Read size + output.writePaddedUnsignedInt(0); // Size, 4 bytes reserved + output.writeLong(input.readLong()); // Constant pool id + output.writeLong(input.readLong()); // Start time + output.writeLong(input.readLong()); // Duration + input.readLong(); // Read delta + output.writeLong(delta); // Delta + output.writeByte(input.readByte()); // flush marker + + // Write even if touched pools are zero, checkpoint works as sync point + output.writeLong(event.touchedPools()); // Pool count + for (CheckpointPool pool : event.getPools()) { + if (pool.isTouched()) { + output.writeLong(pool.getTypeId()); + output.writeLong(pool.getTouchedCount()); + for (PoolEntry pe : pool.getEntries()) { + if (pe.isTouched()) { + write(pe.getStartPosition(), pe.getEndPosition()); // key + value + } + } + } + } + long endPosition = output.position(); + long size = endPosition - startPosition; + output.position(startPosition); + output.writePaddedUnsignedInt(size); + output.position(endPosition); + } + + private void updateHeader(long size, long constantPosition, long metadataPosition) throws IOException { + long backup = output.position(); + output.position(ChunkHeader.CHUNK_SIZE_POSITION + chunkStartPosition); + // Write chunk relative values + output.writeRawLong(size - chunkStartPosition); + output.writeRawLong(constantPosition - chunkStartPosition); + output.writeRawLong(metadataPosition - chunkStartPosition); + output.position(backup); + } + + public RecordingInput getInput() { + return input; + } +} \ No newline at end of file diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/filter/Constants.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/filter/Constants.java new file mode 100644 index 0000000000000000000000000000000000000000..c670aded874d7f53b663c88b253b5e7320c4a727 --- /dev/null +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/filter/Constants.java @@ -0,0 +1,52 @@ +/* + * 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. 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.jfr.internal.consumer.filter; + +import jdk.jfr.internal.LongMap; +import jdk.jfr.internal.Type; + +/** + * Holds the chunk global state of constants + */ +final class Constants { + private final LongMap<PoolEntry> table = new LongMap<>(); + private final Type type; + + public Constants(Type type) { + this.type = type; + } + + public void add(long key, PoolEntry entry) { + table.put(key, entry); + } + + public PoolEntry get(long key) { + return table.get(key); + } + + public String toString() { + return "Pool: " + type.getName() + " size = " + table.size(); + } +} \ No newline at end of file diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/filter/PoolEntry.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/filter/PoolEntry.java new file mode 100644 index 0000000000000000000000000000000000000000..7e5d7745a1e4e56f6378549237275bd73aeeb6ca --- /dev/null +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/filter/PoolEntry.java @@ -0,0 +1,88 @@ +/* + * 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. 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.jfr.internal.consumer.filter; + +import jdk.jfr.internal.Type; + +/** + * Represents the binary content of constant pool, both key and value. + * <p> + * All positional values are relative to file start, not the chunk. + */ +final class PoolEntry { + private final long startPosition; + private final long endPosition; + private final Type type; + private final long keyId; + private final Object references; + + private boolean touched; + + PoolEntry(long startPosition, long endPosition, Type type, long keyId, Object references) { + this.startPosition = startPosition; + this.endPosition = endPosition; + this.type = type; + this.keyId = keyId; + this.references = references; + } + + public void touch() { + this.touched = true; + } + + public boolean isTouched() { + return touched; + } + + public Object getReferences() { + return references; + } + + public long getStartPosition() { + return startPosition; + } + + public long getEndPosition() { + return endPosition; + } + + public Type getType() { + return type; + } + + public long getId() { + return keyId; + } + + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("start: ").append(startPosition).append("\n"); + sb.append("end: ").append(endPosition).append("\n"); + sb.append("type: ").append(type).append(" (").append(type.getId()).append(")\n"); + sb.append("key: ").append(keyId).append("\n"); + sb.append("object: ").append(references).append("\n"); + return sb.toString(); + } +} \ No newline at end of file diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/filter/RecordingOutput.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/filter/RecordingOutput.java new file mode 100644 index 0000000000000000000000000000000000000000..9aebb27238c5b90fcc6c88e0285387a8d5a305c6 --- /dev/null +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/filter/RecordingOutput.java @@ -0,0 +1,154 @@ +/* + * 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. 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.jfr.internal.consumer.filter; + +import java.io.Closeable; +import java.io.File; +import java.io.IOException; +import java.io.RandomAccessFile; + +/** + * Write cache and LEB128 encoder + */ +final class RecordingOutput implements Closeable { + private final RandomAccessFile file; + private final byte[] buffer = new byte[16384]; + private int bufferPosition; + private long position; + + public RecordingOutput(File file) throws IOException { + this.file = new RandomAccessFile(file, "rw"); + } + + public void writeByte(byte value) throws IOException { + if (!(bufferPosition < buffer.length)) { + flush(); + } + buffer[bufferPosition++] = value; + position++; + } + + public void writeRawLong(long v) throws IOException { + writeByte((byte) ((v >> 56) & 0xff)); + writeByte((byte) ((v >> 48) & 0xff)); + writeByte((byte) ((v >> 40) & 0xff)); + writeByte((byte) ((v >> 32) & 0xff)); + writeByte((byte) ((v >> 24) & 0xff)); + writeByte((byte) ((v >> 16) & 0xff)); + writeByte((byte) ((v >> 8) & 0xff)); + writeByte((byte) ((v) & 0xff)); + } + + public void writePaddedUnsignedInt(long value) throws IOException { + if (value < 0) { + throw new IOException("Padded value can't be negative"); + } + if (value >= 1 << 28) { + throw new IOException("Padded value must fit four bytes"); + } + byte b0 = (byte) (value | 0x80); + byte b1 = (byte) (value >> 7 | 0x80); + byte b2 = (byte) (value >> 14 | 0x80); + byte b3 = (byte) (value >> 21); + writeByte(b0); + writeByte(b1); + writeByte(b2); + writeByte(b3); + } + + // Essentially copied from EventWriter#putLong + public void writeLong(long v) throws IOException { + if ((v & ~0x7FL) == 0L) { + writeByte((byte) v); // 0-6 + return; + } + writeByte((byte) (v | 0x80L)); // 0-6 + v >>>= 7; + if ((v & ~0x7FL) == 0L) { + writeByte((byte) v); // 7-13 + return; + } + writeByte((byte) (v | 0x80L)); // 7-13 + v >>>= 7; + if ((v & ~0x7FL) == 0L) { + writeByte((byte) v); // 14-20 + return; + } + writeByte((byte) (v | 0x80L)); // 14-20 + v >>>= 7; + if ((v & ~0x7FL) == 0L) { + writeByte((byte) v); // 21-27 + return; + } + writeByte((byte) (v | 0x80L)); // 21-27 + v >>>= 7; + if ((v & ~0x7FL) == 0L) { + writeByte((byte) v); // 28-34 + return; + } + writeByte((byte) (v | 0x80L)); // 28-34 + v >>>= 7; + if ((v & ~0x7FL) == 0L) { + writeByte((byte) v); // 35-41 + return; + } + writeByte((byte) (v | 0x80L)); // 35-41 + v >>>= 7; + if ((v & ~0x7FL) == 0L) { + writeByte((byte) v); // 42-48 + return; + } + writeByte((byte) (v | 0x80L)); // 42-48 + v >>>= 7; + + if ((v & ~0x7FL) == 0L) { + writeByte((byte) v); // 49-55 + return; + } + writeByte((byte) (v | 0x80L)); // 49-55 + writeByte((byte) (v >>> 7)); // 56-63, last byte as is. + } + + public void position(long pos) throws IOException { + flush(); + position = pos; + file.seek(position); + } + + public long position() throws IOException { + return position; + } + + public void flush() throws IOException { + file.write(buffer, 0, bufferPosition); + bufferPosition = 0; + } + + @Override + public void close() throws IOException { + flush(); + file.close(); + } +} diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/AbstractDCmd.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/AbstractDCmd.java index a6130b2ece704198453c49c51f475fc4f9bd19f5..b7fb23c940266639560d772f2bbbd1d735087d6b 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/AbstractDCmd.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/AbstractDCmd.java @@ -32,7 +32,6 @@ import java.nio.file.Paths; import java.time.Duration; import java.time.LocalDateTime; import java.util.ArrayList; -import java.util.Collections; import java.util.Comparator; import java.util.List; @@ -169,7 +168,7 @@ abstract class AbstractDCmd { protected final List<Recording> getRecordings() { List<Recording> list = new ArrayList<>(getFlightRecorder().getRecordings()); - Collections.sort(list, Comparator.comparing(Recording::getId)); + list.sort(Comparator.comparingLong(Recording::getId)); return list; } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/DCmdCheck.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/DCmdCheck.java index ef32321120ba87b95d3111fd1aa81af6c62fad65..888ca4eda2ab2b593ec3ddd7c8f7de4e8bc41dcd 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/DCmdCheck.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/DCmdCheck.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -27,7 +27,6 @@ package jdk.jfr.internal.dcmd; import java.time.Duration; import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Map; @@ -135,12 +134,7 @@ final class DCmdCheck extends AbstractDCmd { private static List<EventType> sortByEventPath(Collection<EventType> events) { List<EventType> sorted = new ArrayList<>(); sorted.addAll(events); - Collections.sort(sorted, new Comparator<EventType>() { - @Override - public int compare(EventType e1, EventType e2) { - return e1.getName().compareTo(e2.getName()); - } - }); + sorted.sort(Comparator.comparing(EventType::getName)); return sorted; } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/DCmdConfigure.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/DCmdConfigure.java index 4cfc9ae4800a81d1d7102323f1fa692526b421b8..69a0bd88378a697219fdef8347399a3f11fd3517 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/DCmdConfigure.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/DCmdConfigure.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -25,7 +25,7 @@ package jdk.jfr.internal.dcmd; - +import java.io.IOException; import jdk.jfr.FlightRecorder; import jdk.jfr.internal.LogLevel; @@ -69,8 +69,7 @@ final class DCmdConfigure extends AbstractDCmd { Long globalBufferSize, Long threadBufferSize, Long memorySize, - Long maxChunkSize, - Boolean sampleThreads + Long maxChunkSize ) throws DCmdException { if (Logger.shouldLog(LogTag.JFR_DCMD, LogLevel.DEBUG)) { @@ -81,8 +80,7 @@ final class DCmdConfigure extends AbstractDCmd { ", globalbuffersize=" + globalBufferSize + ", thread_buffer_size=" + threadBufferSize + ", memorysize=" + memorySize + - ", maxchunksize=" + maxChunkSize + - ", samplethreads=" + sampleThreads); + ", maxchunksize=" + maxChunkSize); } @@ -106,7 +104,11 @@ final class DCmdConfigure extends AbstractDCmd { } if (dumpPath != null) { - Options.setDumpPath(new SafePath(dumpPath)); + try { + Options.setDumpPath(new SafePath(dumpPath)); + } catch (IOException e) { + throw new DCmdException("Could not set " + dumpPath + " to emergency dump path. " + e.getMessage(), e); + } Logger.log(LogTag.JFR, LogLevel.INFO, "Emergency dump path set to " + dumpPath); if (verbose) { printDumpPath(); @@ -168,14 +170,6 @@ final class DCmdConfigure extends AbstractDCmd { updated = true; } - if (sampleThreads != null) { - Options.setSampleThreads(sampleThreads); - Logger.log(LogTag.JFR, LogLevel.INFO, "Sample threads set to " + sampleThreads); - if (verbose) { - printSampleThreads(); - } - updated = true; - } if (!verbose) { return new String[0]; } @@ -183,13 +177,13 @@ final class DCmdConfigure extends AbstractDCmd { println("Current configuration:"); println(); printRepositoryPath(); + printDumpPath(); printStackDepth(); printGlobalBufferCount(); printGlobalBufferSize(); printThreadBufferSize(); printMemorySize(); printMaxChunkSize(); - printSampleThreads(); } return getResult(); } @@ -206,10 +200,6 @@ final class DCmdConfigure extends AbstractDCmd { println(); } - private void printSampleThreads() { - println("Sample threads: " + Options.getSampleThreads()); - } - private void printStackDepth() { println("Stack depth: " + Options.getStackDepth()); } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/DCmdStart.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/DCmdStart.java index 77b8cccd77a17d615f7fa08325c9a1477bb51790..5d7f70c2a3409f135d1baaaa9ebba11dfe6a80f2 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/DCmdStart.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/DCmdStart.java @@ -42,10 +42,14 @@ import java.util.Set; import jdk.jfr.FlightRecorder; import jdk.jfr.Recording; import jdk.jfr.internal.JVM; +import jdk.jfr.internal.LogLevel; +import jdk.jfr.internal.LogTag; +import jdk.jfr.internal.Logger; import jdk.jfr.internal.OldObjectSample; import jdk.jfr.internal.PlatformRecording; import jdk.jfr.internal.PrivateAccess; import jdk.jfr.internal.SecuritySupport.SafePath; +import jdk.jfr.internal.SecuritySupport; import jdk.jfr.internal.Type; import jdk.jfr.internal.jfc.JFC; import jdk.jfr.internal.jfc.model.JFCModel; @@ -240,7 +244,7 @@ final class DCmdStart extends AbstractDCmd { paths.add(JFC.createSafePath(setting)); } try { - JFCModel model = new JFCModel(paths); + JFCModel model = new JFCModel(paths, l -> logWarning(l)); Set<String> jfcOptions = new HashSet<>(); for (XmlInput input : model.getInputs()) { jfcOptions.add(input.getName()); @@ -364,7 +368,7 @@ final class DCmdStart extends AbstractDCmd { Turn on this flag only when you have an application that you suspect has a memory leak. If the settings parameter is set to 'profile', then the information collected includes the stack - trace from where the potential leaking object wasallocated. + trace from where the potential leaking object was allocated. (BOOLEAN, false) settings (Optional) Name of the settings file that identifies which events @@ -394,7 +398,7 @@ final class DCmdStart extends AbstractDCmd { take precedence. The whitespace character can be omitted for timespan values, i.e. 20s. For more information about the settings syntax, see Javadoc of the jdk.jfr package. - + %s Options must be specified using the <key> or <key>=<value> syntax. Example usage: @@ -414,7 +418,28 @@ final class DCmdStart extends AbstractDCmd { Note, if the default event settings are modified, overhead may exceed 1%%. - """.formatted(exampleDirectory()).lines().toArray(String[]::new); + """.formatted(jfcOptions(), exampleDirectory()).lines().toArray(String[]::new); + } + + private static String jfcOptions() { + try { + StringBuilder sb = new StringBuilder(); + for (SafePath s : SecuritySupport.getPredefinedJFCFiles()) { + String name = JFC.nameFromPath(s.toPath()); + JFCModel model = JFCModel.create(s, l -> {}); + sb.append('\n'); + sb.append("Options for ").append(name).append(":\n"); + sb.append('\n'); + for (XmlInput input : model.getInputs()) { + sb.append(" ").append(input.getOptionSyntax()).append('\n'); + sb.append('\n'); + } + } + return sb.toString(); + } catch (IOException | ParseException e) { + Logger.log(LogTag.JFR_DCMD, LogLevel.DEBUG, "Could not list .jfc options for JFR.start. " + e.getMessage()); + return ""; + } } @Override diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/instrument/SocketChannelImplInstrumentor.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/instrument/SocketChannelImplInstrumentor.java index 6d353112dff0d062e7b4169be646bf1ecb0fde19..a83fabfbaa82b4ecbeffe8ff094517b021c34904 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/instrument/SocketChannelImplInstrumentor.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/instrument/SocketChannelImplInstrumentor.java @@ -52,7 +52,7 @@ final class SocketChannelImplInstrumentor { int bytesRead = 0; long start = 0; try { - start = EventHandler.timestamp();; + start = EventHandler.timestamp(); bytesRead = read(dst); } finally { long duration = EventHandler.timestamp() - start; diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/jfc/JFC.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/jfc/JFC.java index 6d798e294dddc2ed2ab2408c13b05e26cd983c3b..6a37bea34ad4e6caebf9f97834076d32c05a63fc 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/jfc/JFC.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/jfc/JFC.java @@ -25,9 +25,11 @@ package jdk.jfr.internal.jfc; +import java.io.FileReader; import java.io.IOException; import java.io.InputStream; import java.io.Reader; +import java.io.StringReader; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.NoSuchFileException; @@ -62,9 +64,11 @@ public final class JFC { private final String content; private final String filename; private final String name; + private final SafePath path; private Configuration configuration; public KnownConfiguration(SafePath knownPath) throws IOException { + this.path = knownPath; this.content = readContent(knownPath); this.name = nameFromPath(knownPath.toPath()); this.filename = nullSafeFileName(knownPath.toPath()); @@ -270,4 +274,13 @@ public final class JFC { } throw new NoSuchFileException("Could not locate configuration with name " + name); } + + public static Reader newReader(SafePath sf) throws IOException { + for (KnownConfiguration c : getKnownConfigurations()) { + if (c.path.equals(sf)) { + return new StringReader(c.content); + } + } + return new FileReader(sf.toFile(), StandardCharsets.UTF_8); + } } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/jfc/model/JFCModel.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/jfc/model/JFCModel.java index bf9424265b8ea25c9059dd2af28bd573995c7833..746954a3e715a8718624a2d121f1d06b8ce98714 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/jfc/model/JFCModel.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/jfc/model/JFCModel.java @@ -26,14 +26,17 @@ package jdk.jfr.internal.jfc.model; import java.io.IOException; import java.io.PrintWriter; +import java.io.Reader; import java.text.ParseException; import java.util.ArrayList; import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.function.Consumer; import jdk.jfr.internal.SecuritySupport.SafePath; +import jdk.jfr.internal.jfc.JFC; import static java.nio.charset.StandardCharsets.UTF_8; @@ -42,19 +45,23 @@ public final class JFCModel { private final Map<String, List<ControlElement>> controls = new LinkedHashMap<>(); private final XmlConfiguration configuration; - public JFCModel(SafePath file) throws ParseException, IOException { - this.configuration = createConfiguration(file); - this.configuration.validate(); + private JFCModel(XmlConfiguration configuration) throws ParseException { + configuration.validate(); + this.configuration = configuration; + } + + public JFCModel(Reader reader, Consumer<String> logger) throws ParseException, IOException { + this(Parser.parse(reader)); addControls(); wireConditions(); - wireSettings(); + wireSettings(logger); } - public JFCModel(List<SafePath> files) throws IOException, ParseException { + public JFCModel(List<SafePath> files, Consumer<String> logger) throws IOException, ParseException { this.configuration = new XmlConfiguration(); this.configuration.setAttribute("version", "2.0"); for (SafePath file : files) { - JFCModel model = new JFCModel(file); + JFCModel model = JFCModel.create(file, logger); for (var entry : model.controls.entrySet()) { String name = entry.getKey(); // Fail-fast checks that prevents an ambiguous file to be written later @@ -69,6 +76,18 @@ public final class JFCModel { } } + public static JFCModel create(SafePath file, Consumer<String> logger) throws ParseException, IOException { + if (file.toString().equals("none")) { + XmlConfiguration configuration = new XmlConfiguration(); + configuration.setAttribute("version", "2.0"); + configuration.setAttribute("label", "None"); + return new JFCModel(configuration); + } + try (Reader r = JFC.newReader(file)) { + return new JFCModel(r, logger); + } + } + public void setLabel(String label) { configuration.setAttribute("label", label); } @@ -183,14 +202,14 @@ public final class JFCModel { } } - private void wireSettings() { + private void wireSettings(Consumer<String> logger) { for (XmlEvent event : configuration.getEvents()) { for (XmlSetting setting : event.getSettings()) { var controlName = setting.getControl(); if (controlName.isPresent()) { List<ControlElement> controls = getControlElements(controlName.get()); if (controls.isEmpty()) { - System.out.println("Warning! Setting '" + setting.getFullName() + "' refers to missing control '" + controlName.get() + "'"); + logger.accept("Setting '" + setting.getFullName() + "' refers to missing control '" + controlName.get() + "'"); } for (ControlElement ce : controls) { XmlElement control = (XmlElement) ce; @@ -204,14 +223,4 @@ public final class JFCModel { private void add(ControlElement control) { controls.computeIfAbsent(control.getName(), x -> new ArrayList<>()).add(control); } - - private XmlConfiguration createConfiguration(SafePath file) throws ParseException, IOException { - if (file.toString().equals("none")) { - XmlConfiguration configuration = new XmlConfiguration(); - configuration.setAttribute("version", "2.0"); - configuration.setAttribute("label", "None"); - return configuration; - } - return Parser.parse(file.toPath()); - } } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/jfc/model/Parser.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/jfc/model/Parser.java index 78fd246ca7eb76a4fde8df0f3be2c30b8102d533..3b6aa05d9bd49d86fbf5e7fb170930ff7ed5520f 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/jfc/model/Parser.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/jfc/model/Parser.java @@ -24,9 +24,8 @@ */ package jdk.jfr.internal.jfc.model; -import java.io.FileReader; import java.io.IOException; -import java.nio.file.Path; +import java.io.Reader; import java.text.ParseException; import java.util.ArrayDeque; import java.util.Deque; @@ -38,15 +37,13 @@ import jdk.internal.org.xml.sax.helpers.DefaultHandler; import jdk.internal.util.xml.SAXParser; import jdk.internal.util.xml.impl.SAXParserImpl; -import static java.nio.charset.StandardCharsets.UTF_8; - final class Parser { - static XmlConfiguration parse(Path path) throws ParseException, IOException { - try (FileReader r = new FileReader(path.toFile(), UTF_8)) { + static XmlConfiguration parse(Reader reader) throws ParseException, IOException { + try { SAXParser saxParser = new SAXParserImpl(); ConfigurationHandler handler = new ConfigurationHandler(); - saxParser.parse(new InputSource(r), handler); + saxParser.parse(new InputSource(reader), handler); return handler.configuration; } catch (SAXException sp) { ParseException pe = new ParseException(sp.getMessage(), -1); diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/jfc/model/XmlFlag.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/jfc/model/XmlFlag.java index d494d3eb57ded2ba185ee1725f02c74eace40a3e..8e3431bc5a343761e302bc518237b514caac4418 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/jfc/model/XmlFlag.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/jfc/model/XmlFlag.java @@ -29,7 +29,7 @@ final class XmlFlag extends XmlInput { @Override public String getOptionSyntax() { - return getName() + "=<true|false>"; + return getName() + "=<true|false>" + " (" + getContent() + ")"; } @Override diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/jfc/model/XmlSelection.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/jfc/model/XmlSelection.java index d3bf22404797777b9caf69b09b7c6cb22a0d640c..c451119fb1af2881ca63cdd9ab030e4b3db2dc62 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/jfc/model/XmlSelection.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/jfc/model/XmlSelection.java @@ -36,7 +36,15 @@ final class XmlSelection extends XmlInput { for (XmlOption option : getOptions()) { sj.add(option.getName()); } - return getName() + "=" + sj.toString(); + StringBuilder sb = new StringBuilder(); + sb.append(getName()); + sb.append("="); + sb.append(sj.toString()); + XmlOption selected = getSelected(); + if (selected != null) { + sb.append(" (").append(selected.getName()).append(")"); + } + return sb.toString(); } @Override diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/jfc/model/XmlText.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/jfc/model/XmlText.java index 789243d2d5fb4fa651c4aa019f1984174178232b..4d90dd3c51cebb477b6c039f94471b97c656b535 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/jfc/model/XmlText.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/jfc/model/XmlText.java @@ -34,6 +34,14 @@ final class XmlText extends XmlInput { sb.append("=<"); sb.append(getContentType().orElse("text")); sb.append(">"); + sb.append(" ("); + String content = getContent(); + if (isTimespan()) { + // "20 ms" becomes "20ms" + content = content.replaceAll("\\s", ""); + } + sb.append(content); + sb.append(")"); return sb.toString(); } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/management/ChunkFilename.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/management/ChunkFilename.java index 236c980acd0c741962497e73567add846dc9e0b4..8cc2cfeb180bdd2c763bb42a3fab77962e3d5a0f 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/management/ChunkFilename.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/management/ChunkFilename.java @@ -74,7 +74,7 @@ public final class ChunkFilename { // If more than one file per second while (counter < MAX_CHUNK_NAMES) { - String extendedName = String.format("%s_%02d%s", filename, counter, FILE_EXTENSION); + String extendedName = makeExtendedName(filename, counter); p = directory.resolve(extendedName); counter++; if (!fileAcess.exists(p)) { @@ -83,4 +83,16 @@ public final class ChunkFilename { } throw new IOException("Unable to find unused filename after " + counter + " attempts"); } + + private String makeExtendedName(String filename, int counter) { + StringBuilder sb = new StringBuilder(); + sb.append(filename); + sb.append('_'); + if (counter < 10) { // chronological sorted + sb.append('0'); + } + sb.append(counter); + sb.append(FILE_EXTENSION); + return sb.toString(); + } } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/CutoffSetting.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/CutoffSetting.java index 8a35a6b963915a90ee21fb232effc65dc33447fc..bdbeb4959b38feaddda9a28703bad8e38a8b730d 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/CutoffSetting.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/CutoffSetting.java @@ -78,10 +78,6 @@ public final class CutoffSetting extends JDKSettingControl { return value; } - public static boolean isType(long typeId) { - return CutoffSetting.typeId == typeId; - } - public static long parseValueSafe(String value) { if (value == null) { return 0L; diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/ThrottleSetting.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/ThrottleSetting.java index a05544c25c481e33dfdce3463da65b2643a7c4f3..49d676d636a80d2295f3dd8d7cbc8322b1fb0ee6 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/ThrottleSetting.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/ThrottleSetting.java @@ -91,9 +91,5 @@ public final class ThrottleSetting extends JDKSettingControl { public String getValue() { return value; } - - public static boolean isType(long typeId) { - return ThrottleSetting.typeId == typeId; - } } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Command.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Command.java index 031dbd28da905f7816bc07a51196e969c7e636c3..fc3b46ced54bd97f19c2bb78ee3ba223516e175e 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Command.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Command.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -38,13 +38,7 @@ import java.nio.file.Paths; import java.util.ArrayList; import java.util.Collections; import java.util.Deque; -import java.util.HashMap; import java.util.List; -import java.util.Map; -import java.util.function.Function; -import java.util.function.Predicate; - -import jdk.jfr.EventType; abstract class Command { public static final String title = "Tool for working with Flight Recorder files"; @@ -56,6 +50,7 @@ abstract class Command { commands.add(new Print()); commands.add(new Configure()); commands.add(new Metadata()); + commands.add(new Scrub()); commands.add(new Summary()); commands.add(new Assemble()); commands.add(new Disassemble()); @@ -287,6 +282,10 @@ abstract class Command { displayOptionUsage(stream); } + protected static char quoteCharacter() { + return File.pathSeparatorChar == ';' ? '"' : '\''; + } + protected final void println() { System.out.println(); } @@ -299,6 +298,12 @@ abstract class Command { System.out.println(text); } + public static void checkCommonError(Deque<String> options, String typo, String correct) throws UserSyntaxException { + if (typo.equals(options.peek())) { + throw new UserSyntaxException("unknown option " + typo + ", did you mean " + correct + "?"); + } + } + protected final boolean matches(String command) { for (String s : getNames()) { if (s.equals(command)) { @@ -319,107 +324,4 @@ abstract class Command { return names; } - public static void checkCommonError(Deque<String> options, String typo, String correct) throws UserSyntaxException { - if (typo.equals(options.peek())) { - throw new UserSyntaxException("unknown option " + typo + ", did you mean " + correct + "?"); - } - } - - protected static final char quoteCharacter() { - return File.pathSeparatorChar == ';' ? '"' : '\''; - } - - private static <T> Predicate<T> recurseIfPossible(Predicate<T> filter) { - return x -> filter != null && filter.test(x); - } - - private static String acronomify(String multipleWords) { - boolean newWord = true; - String acronym = ""; - for (char c : multipleWords.toCharArray()) { - if (newWord) { - if (Character.isAlphabetic(c) && Character.isUpperCase(c)) { - acronym += c; - } - } - newWord = Character.isWhitespace(c); - } - return acronym; - } - - private static boolean match(String text, String filter) { - if (filter.length() == 0) { - // empty filter string matches if string is empty - return text.length() == 0; - } - if (filter.charAt(0) == '*') { // recursive check - filter = filter.substring(1); - for (int n = 0; n <= text.length(); n++) { - if (match(text.substring(n), filter)) - return true; - } - } else if (text.length() == 0) { - // empty string and non-empty filter does not match - return false; - } else if (filter.charAt(0) == '?') { - // eat any char and move on - return match(text.substring(1), filter.substring(1)); - } else if (filter.charAt(0) == text.charAt(0)) { - // eat chars and move on - return match(text.substring(1), filter.substring(1)); - } - return false; - } - - private static List<String> explodeFilter(String filter) throws UserSyntaxException { - List<String> list = new ArrayList<>(); - for (String s : filter.split(",")) { - s = s.trim(); - if (!s.isEmpty()) { - list.add(s); - } - } - return list; - } - - protected static final Predicate<EventType> addCategoryFilter(String filterText, Predicate<EventType> eventFilter) throws UserSyntaxException { - List<String> filters = explodeFilter(filterText); - Predicate<EventType> newFilter = recurseIfPossible(eventType -> { - for (String category : eventType.getCategoryNames()) { - for (String filter : filters) { - if (match(category, filter)) { - return true; - } - if (category.contains(" ") && acronomify(category).equals(filter)) { - return true; - } - } - } - return false; - }); - return eventFilter == null ? newFilter : eventFilter.or(newFilter); - } - - protected static final Predicate<EventType> addEventFilter(String filterText, final Predicate<EventType> eventFilter) throws UserSyntaxException { - List<String> filters = explodeFilter(filterText); - Predicate<EventType> newFilter = recurseIfPossible(eventType -> { - for (String filter : filters) { - String fullEventName = eventType.getName(); - if (match(fullEventName, filter)) { - return true; - } - String eventName = fullEventName.substring(fullEventName.lastIndexOf(".") + 1); - if (match(eventName, filter)) { - return true; - } - } - return false; - }); - return eventFilter == null ? newFilter : eventFilter.or(newFilter); - } - - protected static final <T, X> Predicate<T> addCache(final Predicate<T> filter, Function<T, X> cacheFunction) { - Map<X, Boolean> cache = new HashMap<>(); - return t -> cache.computeIfAbsent(cacheFunction.apply(t), x -> filter.test(t)); - } } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Configure.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Configure.java index 037ad6dbf060c97a43851a5b1b53af5d92fcc7cc..551264c6889f77d79395ee6f396a760c167ac904 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Configure.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Configure.java @@ -127,7 +127,7 @@ final class Configure extends Command { } private void displayParameters(PrintStream stream, SafePath path, String name) throws ParseException, IOException { - JFCModel parameters = new JFCModel(path); + JFCModel parameters = JFCModel.create(path, l -> stream.println("Warning! " + l)); stream.println(); stream.println("Options for " + name + ":"); stream.println(); @@ -195,7 +195,7 @@ final class Configure extends Command { output = new SafePath(Path.of("custom.jfc")); } UserInterface ui = new UserInterface(); - JFCModel model = new JFCModel(inputFiles); + JFCModel model = new JFCModel(inputFiles, l -> ui.println("Warning! " + l)); model.setLabel("Custom"); if (log) { SettingsLog.enable(); diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/EventPrintWriter.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/EventPrintWriter.java index 9a393f30ee8c5c2ac630599ae19f1823b613bb18..a6c92761a57047e6d6d04aa93a4da4ae06e351ac 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/EventPrintWriter.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/EventPrintWriter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -30,7 +30,6 @@ import java.io.IOException; import java.io.PrintWriter; import java.nio.file.Path; import java.util.ArrayList; -import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -77,7 +76,7 @@ abstract class EventPrintWriter extends StructuredWriter { events.add(event); } if (PRIVATE_ACCESS.isLastEventInChunk(file)) { - Collections.sort(events, PRIVATE_ACCESS.eventComparator()); + events.sort(PRIVATE_ACCESS.eventComparator()); print(events); events.clear(); } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Filters.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Filters.java new file mode 100644 index 0000000000000000000000000000000000000000..cc567bf9a3a2d75d52ac057179dcb7fb08f6b035 --- /dev/null +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Filters.java @@ -0,0 +1,178 @@ +/* + * 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. 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.jfr.internal.tool; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.function.Predicate; + +import jdk.jfr.EventType; +import jdk.jfr.consumer.RecordedThread; +import jdk.jfr.consumer.RecordedEvent; + +/** + * Helper class for creating filters. + */ +public class Filters { + private static final Predicate<RecordedThread> FALSE_THREAD_PREDICATE = e -> false; + + static Predicate<EventType> createCategoryFilter(String filterText) throws UserSyntaxException { + List<String> filters = explodeFilter(filterText); + Predicate<EventType> f = eventType -> { + for (String category : eventType.getCategoryNames()) { + for (String filter : filters) { + if (match(category, filter)) { + return true; + } + if (category.contains(" ") && acronymify(category).equals(filter)) { + return true; + } + } + } + return false; + }; + return createCache(f, EventType::getId); + } + + static Predicate<EventType> createEventTypeFilter(String filterText) throws UserSyntaxException { + List<String> filters = explodeFilter(filterText); + Predicate<EventType> f = eventType -> { + for (String filter : filters) { + String fullEventName = eventType.getName(); + if (match(fullEventName, filter)) { + return true; + } + String eventName = fullEventName.substring(fullEventName.lastIndexOf(".") + 1); + if (match(eventName, filter)) { + return true; + } + } + return false; + }; + return createCache(f, EventType::getId); + } + + public static <T> Predicate<T> matchAny(List<Predicate<T>> filters) { + if (filters.isEmpty()) { + return t -> true; + } + if (filters.size() == 1) { + return filters.get(0); + } + return t -> { + for (Predicate<T> p : filters) { + if (!p.test(t)) { + return false; + } + } + return true; + }; + } + + static Predicate<RecordedEvent> fromEventType(Predicate<EventType> filter) { + return e -> filter.test(e.getEventType()); + } + + static Predicate<RecordedEvent> fromRecordedThread(Predicate<RecordedThread> filter) { + Predicate<RecordedThread> cachePredicate = createCache(filter, RecordedThread::getId); + return event -> { + RecordedThread t = event.getThread(); + if (t == null || t.getJavaName() == null) { + return false; + } + return cachePredicate.test(t); + }; + } + + static Predicate<RecordedThread> createThreadFilter(String filterText) throws UserSyntaxException { + List<String> filters = explodeFilter(filterText); + return thread -> { + String threadName = thread.getJavaName(); + for (String filter : filters) { + if (match(threadName, filter)) { + return true; + } + } + return false; + }; + } + + private static final <T, X> Predicate<T> createCache(final Predicate<T> filter, Function<T, X> cacheFunction) { + Map<X, Boolean> cache = new HashMap<>(); + return t -> cache.computeIfAbsent(cacheFunction.apply(t), x -> filter.test(t)); + } + + private static String acronymify(String multipleWords) { + boolean newWord = true; + String acronym = ""; + for (char c : multipleWords.toCharArray()) { + if (newWord) { + if (Character.isAlphabetic(c) && Character.isUpperCase(c)) { + acronym += c; + } + } + newWord = Character.isWhitespace(c); + } + return acronym; + } + + private static boolean match(String text, String filter) { + if (filter.length() == 0) { + // empty filter string matches if string is empty + return text.length() == 0; + } + if (filter.charAt(0) == '*') { // recursive check + filter = filter.substring(1); + for (int n = 0; n <= text.length(); n++) { + if (match(text.substring(n), filter)) + return true; + } + } else if (text.length() == 0) { + // empty string and non-empty filter does not match + return false; + } else if (filter.charAt(0) == '?') { + // eat any char and move on + return match(text.substring(1), filter.substring(1)); + } else if (filter.charAt(0) == text.charAt(0)) { + // eat chars and move on + return match(text.substring(1), filter.substring(1)); + } + return false; + } + + private static List<String> explodeFilter(String filter) throws UserSyntaxException { + List<String> list = new ArrayList<>(); + for (String s : filter.split(",")) { + s = s.trim(); + if (!s.isEmpty()) { + list.add(s); + } + } + return list; + } +} diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/JSONWriter.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/JSONWriter.java index cbf508306d54376127d3e75c20ec5414bc79d854..3be2dd6c19913fde55a36f40722538e07b64a9f2 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/JSONWriter.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/JSONWriter.java @@ -63,7 +63,7 @@ final class JSONWriter extends EventPrintWriter { @Override protected void printEnd() { - printArrayEnd();; + printArrayEnd(); printObjectEnd(); printObjectEnd(); } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Main.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Main.java index 1629e4d28c85efaac2484be864ea815d88f054e6..36e6ea1c234aad380cf2c63f9ef6a167d04a43d5 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Main.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Main.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -66,7 +66,7 @@ public final class Main { System.out.println(); System.out.println(" jfr print --json --events CPULoad recording.jfr"); System.out.println(); - char q = Print.quoteCharacter(); + char q = Command.quoteCharacter(); System.out.println(" jfr print --categories " + q + "GC,JVM,Java*" + q + " recording.jfr"); System.out.println(); System.out.println(" jfr print --events " + q + "jdk.*" + q + " --stack-depth 64 recording.jfr"); diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Metadata.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Metadata.java index c72a34edfd0b78efa164fec72bcf8ff331aabdb6..65e38f7326f22c5f7829bc0592c2255e448e73a4 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Metadata.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Metadata.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -31,7 +31,6 @@ import java.io.PrintWriter; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; -import java.util.Collections; import java.util.Comparator; import java.util.Deque; import java.util.List; @@ -43,7 +42,7 @@ import jdk.jfr.consumer.RecordingFile; import jdk.jfr.internal.PlatformEventType; import jdk.jfr.internal.PrivateAccess; import jdk.jfr.internal.Type; -import jdk.jfr.internal.TypeLibrary; +import jdk.jfr.internal.MetadataRepository; import jdk.jfr.internal.consumer.JdkJfrConsumer; import static java.nio.charset.StandardCharsets.UTF_8; @@ -164,6 +163,7 @@ final class Metadata extends Command { boolean showIds = false; boolean foundEventFilter = false; boolean foundCategoryFilter = false; + List<Predicate<EventType>> filters = new ArrayList<>(); Predicate<EventType> filter = null; int optionCount = options.size(); while (optionCount > 0) { @@ -178,7 +178,7 @@ final class Metadata extends Command { foundEventFilter = true; String filterStr = options.remove(); warnForWildcardExpansion("--events", filterStr); - filter = addEventFilter(filterStr, filter); + filters.add(Filters.createEventTypeFilter(filterStr)); } if (acceptFilterOption(options, "--categories")) { if (foundCategoryFilter) { @@ -187,7 +187,7 @@ final class Metadata extends Command { foundCategoryFilter = true; String filterStr = options.remove(); warnForWildcardExpansion("--categories", filterStr); - filter = addCategoryFilter(filterStr, filter); + filters.add(Filters.createCategoryFilter(filterStr)); } if (optionCount == options.size()) { // No progress made @@ -201,12 +201,12 @@ final class Metadata extends Command { try (PrintWriter pw = new PrintWriter(System.out, false, UTF_8)) { PrettyWriter prettyWriter = new PrettyWriter(pw); prettyWriter.setShowIds(showIds); - if (filter != null) { - filter = addCache(filter, type -> type.getId()); + if (!filters.isEmpty()) { + filter = Filters.matchAny(filters); } List<Type> types = findTypes(file); - Collections.sort(types, new TypeComparator()); + types.sort(new TypeComparator()); for (Type type : types) { if (filter != null) { // If --events or --categories, only operate on events @@ -231,7 +231,7 @@ final class Metadata extends Command { if (file == null) { // Force initialization FlightRecorder.getFlightRecorder().getEventTypes(); - return TypeLibrary.getInstance().getTypes(); + return MetadataRepository.getInstance().getVisibleTypes(); } try (RecordingFile rf = new RecordingFile(file)) { return PRIVATE_ACCESS.readTypes(rf); diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/PrettyWriter.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/PrettyWriter.java index 32178df920c41c3ac022b4372b24e0fbf19151c7..c13bdb2ae2735458acba4d87e16fa73c13794e57 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/PrettyWriter.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/PrettyWriter.java @@ -59,7 +59,7 @@ import jdk.jfr.internal.Utils; */ public final class PrettyWriter extends EventPrintWriter { private static final String TYPE_OLD_OBJECT = Type.TYPES_PREFIX + "OldObject"; - private static final DateTimeFormatter TIME_FORMAT = DateTimeFormatter.ofPattern("HH:mm:ss.SSS (YYYY-MM-dd)"); + private static final DateTimeFormatter TIME_FORMAT = DateTimeFormatter.ofPattern("HH:mm:ss.SSS (yyyy-MM-dd)"); private static final Long ZERO = 0L; private boolean showIds; private RecordedEvent currentEvent; diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Print.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Print.java index 991ac554f4c0e23ada3c3ab13c578b279fdcc06b..2fc33a90cd9754176443afef7f04c7fc3cee3dbc 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Print.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Print.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -102,7 +102,7 @@ final class Print extends Command { public void execute(Deque<String> options) throws UserSyntaxException, UserDataException { Path file = getJFRInputFile(options); PrintWriter pw = new PrintWriter(System.out, false, UTF_8); - Predicate<EventType> eventFilter = null; + List<Predicate<EventType>> eventFilters = new ArrayList<>(); int stackDepth = 5; EventPrintWriter eventWriter = null; int optionCount = options.size(); @@ -116,7 +116,7 @@ final class Print extends Command { foundEventFilter = true; String filter = options.remove(); warnForWildcardExpansion("--events", filter); - eventFilter = addEventFilter(filter, eventFilter); + eventFilters.add(Filters.createEventTypeFilter(filter)); } if (acceptFilterOption(options, "--categories")) { if (foundCategoryFilter) { @@ -125,7 +125,7 @@ final class Print extends Command { foundCategoryFilter = true; String filter = options.remove(); warnForWildcardExpansion("--categories", filter); - eventFilter = addCategoryFilter(filter, eventFilter); + eventFilters.add(Filters.createCategoryFilter(filter)); } if (acceptOption(options, "--stack-depth")) { String value = options.pop(); @@ -156,9 +156,8 @@ final class Print extends Command { eventWriter = new PrettyWriter(pw); // default to pretty printer } eventWriter.setStackDepth(stackDepth); - if (eventFilter != null) { - eventFilter = addCache(eventFilter, eventType -> eventType.getId()); - eventWriter.setEventFilter(eventFilter); + if (!eventFilters.isEmpty()) { + eventWriter.setEventFilter(Filters.matchAny(eventFilters)); } try { eventWriter.print(file); diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Scrub.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Scrub.java new file mode 100644 index 0000000000000000000000000000000000000000..f553e4e8144ac9b759ef158a77eedcbb5374e2ef --- /dev/null +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Scrub.java @@ -0,0 +1,194 @@ +/* + * 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. 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.jfr.internal.tool; + +import java.io.IOException; +import java.io.PrintStream; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Deque; +import java.util.List; +import java.util.function.Predicate; + +import jdk.jfr.consumer.RecordedEvent; +import jdk.jfr.consumer.RecordingFile; + +final class Scrub extends Command { + + @Override + public String getName() { + return "scrub"; + } + + @Override + public List<String> getOptionSyntax() { + List<String> list = new ArrayList<>(); + list.add("[--include-events <filter>]"); + list.add("[--exclude-events <filter>]"); + list.add("[--include-categories <filter>]"); + list.add("[--exclude-categories <filter>]"); + list.add("[--include-threads <filter>]"); + list.add("[--exclude-threads <filter>]"); + list.add("<input-file>"); + list.add("[<output-file>]"); + return list; + } + + @Override + protected String getTitle() { + return "Scrub contents of a recording file"; + } + + @Override + public String getDescription() { + return getTitle() + ". See 'jfr help scrub' for details."; + } + + @Override + public void displayOptionUsage(PrintStream stream) { + // 01234567890123456789012345678901234567890123467890123456789012345678901234567890 + stream.println(" --include-events <filter> Select events matching an event name"); + stream.println(); + stream.println(" --exclude-events <filter> Exclude events matching an event name"); + stream.println(); + stream.println(" --include-categories <filter> Select events matching a category name"); + stream.println(); + stream.println(" --exclude-categories <filter> Exclude events matching a category name"); + stream.println(); + stream.println(" --include-threads <filter> Select events matching a thread name"); + stream.println(); + stream.println(" --exclude-threads <filter> Exclude events matching a thread name"); + stream.println(); + stream.println(" <input-file> The input file to read events from"); + stream.println(); + stream.println(" <output-file> The output file to write filter events to. "); + stream.println(" If no file is specified, it will be written to"); + stream.println(" the same path as the input file, but with"); + stream.println(" \"-scrubbed\" appended to the filename"); + stream.println(); + stream.println(" The filter is a comma-separated list of names, simple and/or qualified,"); + stream.println(" and/or quoted glob patterns. If multiple filters are used, they "); + stream.println(" are applied in the specified order"); + stream.println(); + stream.println("Example usage:"); + stream.println(); + stream.println(" jfr scrub --include-events 'jdk.Socket*' recording.jfr socket-only.jfr"); + stream.println(); + stream.println(" jfr scrub --exclude-events InitialEnvironmentVariable recording.jfr no-psw.jfr"); + stream.println(); + stream.println(" jfr scrub --include-threads main recording.jfr"); + stream.println(); + stream.println(" jfr scrub --exclude-threads 'Foo*' recording.jfr"); + stream.println(); + stream.println(" jfr scrub --include-categories 'My App' recording.jfr"); + stream.println(); + stream.println(" jfr scrub --exclude-categories JVM,OS recording.jfr"); + } + + @Override + public void execute(Deque<String> options) throws UserSyntaxException, UserDataException { + ensureMinArgumentCount(options, 1); + + Path last = Path.of(options.pollLast()); + ensureFileExtension(last, ".jfr"); + Path output = null; + Path input = null; + String peek = options.peekLast(); + if (peek != null && peek.endsWith(".jfr")) { + // Both source and destination specified + input = Path.of(options.pollLast()); + output = last; + } else { + // Only source file specified + Path file = last.getFileName(); + Path dir = last.getParent(); + String filename = file.toString(); + int index = filename.lastIndexOf("."); + String s = filename.substring(0, index); + String t = s + "-scrubbed.jfr"; + input = last; + output = dir == null ? Path.of(t) : dir.resolve(t); + } + ensureFileDoesNotExist(output); + + List<Predicate<RecordedEvent>> filters = new ArrayList<>(); + int optionCount = options.size(); + while (optionCount > 0) { + if (acceptFilterOption(options, "--include-events")) { + String filter = options.remove(); + warnForWildcardExpansion("--include-events", filter); + var f = Filters.createEventTypeFilter(filter); + filters.add(Filters.fromEventType(f)); + } + if (acceptFilterOption(options, "--exclude-events")) { + String filter = options.remove(); + warnForWildcardExpansion("--exclude-events", filter); + var f = Filters.createEventTypeFilter(filter); + filters.add(Filters.fromEventType(f.negate())); + } + if (acceptFilterOption(options, "--include-categories")) { + String filter = options.remove(); + warnForWildcardExpansion("--include-categories", filter); + var f = Filters.createCategoryFilter(filter); + filters.add(Filters.fromEventType(f)); + } + if (acceptFilterOption(options, "--exclude-categories")) { + String filter = options.remove(); + warnForWildcardExpansion("--exclude-categories", filter); + var f = Filters.createCategoryFilter(filter); + filters.add(Filters.fromEventType(f.negate())); + } + if (acceptFilterOption(options, "--include-threads")) { + String filter = options.remove(); + warnForWildcardExpansion("--include-threads", filter); + var f = Filters.createThreadFilter(filter); + filters.add(Filters.fromRecordedThread(f)); + } + if (acceptFilterOption(options, "--exclude-threads")) { + String filter = options.remove(); + warnForWildcardExpansion("--exclude-threads", filter); + var f = Filters.createThreadFilter(filter); + filters.add(Filters.fromRecordedThread(f).negate()); + } + if (optionCount == options.size()) { + // No progress made + checkCommonError(options, "--include-event", "--include-events"); + checkCommonError(options, "--include-category", "--include-categories"); + checkCommonError(options, "--include-thread", "--include-threads"); + throw new UserSyntaxException("unknown option " + options.peek()); + } + optionCount = options.size(); + } + + try (RecordingFile rf = new RecordingFile(input)) { + rf.write(output, Filters.matchAny(filters)); + } catch (IOException ioe) { + couldNotReadError(input, ioe); + } + println("Scrubbed recording file written to:"); + println(output.toAbsolutePath().toString()); + } +} diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Summary.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Summary.java index 3375ec3f7a6a41d53b1a2634ba5dcc3fa5761461..850e995acf37a608eaf5d58150259bd5a4928773 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Summary.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Summary.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -32,7 +32,6 @@ import java.time.Instant; import java.time.ZoneOffset; import java.time.format.DateTimeFormatter; import java.util.ArrayList; -import java.util.Collections; import java.util.Deque; import java.util.HashMap; import java.util.List; @@ -101,7 +100,7 @@ final class Summary extends Command { } HashMap<Long, Statistics> stats = new HashMap<>(); stats.put(0L, new Statistics(eventPrefix + "Metadata")); - stats.put(1L, new Statistics(eventPrefix + "CheckPoint")); + stats.put(1L, new Statistics(eventPrefix + "Checkpoint")); int minWidth = 0; while (true) { long chunkEnd = ch.getEnd(); @@ -143,7 +142,7 @@ final class Summary extends Command { println(" Start: " + DATE_FORMAT.format(Instant.ofEpochSecond(epochSeconds, adjustNanos)) + " (UTC)"); println(" Duration: " + (totalDuration + 500_000_000) / 1_000_000_000 + " s"); List<Statistics> statsList = new ArrayList<>(stats.values()); - Collections.sort(statsList, (u, v) -> Long.compare(v.count, u.count)); + statsList.sort((u, v) -> Long.compare(v.count, u.count)); println(); String header = " Count Size (bytes) "; String typeHeader = " Event Type"; diff --git a/src/jdk.jfr/share/classes/jdk/jfr/snippet-files/Snippets.java b/src/jdk.jfr/share/classes/jdk/jfr/snippet-files/Snippets.java new file mode 100644 index 0000000000000000000000000000000000000000..ef2ff2f3670c9fd6183bc573272d14a6c5db08d7 --- /dev/null +++ b/src/jdk.jfr/share/classes/jdk/jfr/snippet-files/Snippets.java @@ -0,0 +1,413 @@ +/* + * 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. 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 example1; + +import jdk.jfr.AnnotationElement; +import jdk.jfr.ValueDescriptor; +import jdk.jfr.EventFactory; +import jdk.jfr.Event; +import jdk.jfr.Name; +import jdk.jfr.Label; +import jdk.jfr.Description; +import jdk.jfr.Category; +import jdk.jfr.ContentType; +import jdk.jfr.Period; +import jdk.jfr.Recording; +import jdk.jfr.StackTrace; +import jdk.jfr.MetadataDefinition; +import jdk.jfr.Relational; +import jdk.jfr.consumer.RecordingFile; +import jdk.jfr.Configuration; +import jdk.jfr.SettingDefinition; +import jdk.jfr.SettingControl; +import jdk.jfr.Timestamp; +import jdk.jfr.FlightRecorder; +import jdk.jfr.consumer.RecordedEvent; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.time.Duration; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Set; +import java.util.regex.Pattern; +import java.util.stream.Collectors; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.lang.annotation.ElementType; + +public class Snippets { + + void AnnotationElementOverview() { + // @start region="AnnotationElementOverview" + List<AnnotationElement> typeAnnotations = new ArrayList<>(); + typeAnnotations.add(new AnnotationElement(Name.class, "com.example.HelloWorld")); + typeAnnotations.add(new AnnotationElement(Label.class, "Hello World")); + typeAnnotations.add(new AnnotationElement(Description.class, "Helps programmer getting started")); + + List<AnnotationElement> fieldAnnotations = new ArrayList<>(); + fieldAnnotations.add(new AnnotationElement(Label.class, "Message")); + + List<ValueDescriptor> fields = new ArrayList<>(); + fields.add(new ValueDescriptor(String.class, "message", fieldAnnotations)); + + EventFactory f = EventFactory.create(typeAnnotations, fields); + Event event = f.newEvent(); + event.commit(); + // @end + } + + record CPU(String id, float temperature) { + } + + private static List<CPU> listCPUs() { + return List.of(); + } + + // @start region="ContentTypeDeclaration" + @MetadataDefinition + @ContentType + @Name("com.example.Temperature") + @Label("Temperature") + @Target(ElementType.FIELD) + @Retention(RetentionPolicy.RUNTIME) + public @interface Temperature { + public final static String KELVIN = "KELVIN"; + public final static String CELSIUS = "CELSIUS"; + public final static String FAHRENEHIT = "FAHRENHEIT"; + + String value() default CELSIUS; + } + // @end + + // @start region="ContentTypeEvent" + @Name("com.example.CPU") + @Label("CPU") + @Category({ "Hardware", "CPU" }) + @Period("1 s") + @StackTrace(false) + static public class CPUEvent extends Event { + @Label("ID") + String id; + + @Temperature(Temperature.KELVIN) + @Label("Temperature") + float temperature; + } + + public static void main(String... args) throws InterruptedException { + FlightRecorder.addPeriodicEvent(CPUEvent.class, () -> { + for (var cpu : listCPUs()) { + CPUEvent event = new CPUEvent(); + event.id = cpu.id(); + event.temperature = cpu.temperature(); // in Kelvin + event.commit(); + } + }); + Thread.sleep(10_000); + } + // @end + + // @start region="ContentTypeConsumption" + void printTemperaturesInCelsius(Path file) throws IOException { + for (RecordedEvent event : RecordingFile.readAllEvents(file)) { + for (ValueDescriptor field : event.getEventType().getFields()) { + for (AnnotationElement ae : field.getAnnotationElements()) { + ContentType type = ae.getAnnotation(ContentType.class); + if (type != null) { + if (ae.getTypeName().equals("com.example.Temperature")) { + double value = event.getDouble(field.getName()); + String unit = (String) ae.getValue("value"); + double celsius = switch (unit) { + case "CELSIUS" -> value; + case "KELVIN" -> value - 273.15; + case "FAHRENHEIT" -> (value - 32) / 1.8; + default -> throw new IllegalStateException("Unknown temperature unit '" + unit + "'"); + }; + System.out.println(celsius + " C"); + } else { + System.err.println("Can't format content type " + ae.getTypeName() + " for field " + field.getName()); + } + } + } + } + } + } + // @end + + // @start region="EventOverview" + public class Example { + + @Label("Hello World") + @Description("Helps programmer getting started") + static class HelloWorld extends Event { + @Label("Message") + String message; + } + + public static void main(String... args) { + HelloWorld event = new HelloWorld(); + event.message = "hello, world!"; + event.commit(); + } + } + // @end + + void EventFactoryOverview() { + // @start region="EventFactoryOverview" + List<ValueDescriptor> fields = new ArrayList<>(); + List<AnnotationElement> messageAnnotations = Collections.singletonList(new AnnotationElement(Label.class, "Message")); + fields.add(new ValueDescriptor(String.class, "message", messageAnnotations)); + List<AnnotationElement> numberAnnotations = Collections.singletonList(new AnnotationElement(Label.class, "Number")); + fields.add(new ValueDescriptor(int.class, "number", numberAnnotations)); + + String[] category = { "Example", "Getting Started" }; + List<AnnotationElement> eventAnnotations = new ArrayList<>(); + eventAnnotations.add(new AnnotationElement(Name.class, "com.example.HelloWorld")); + eventAnnotations.add(new AnnotationElement(Label.class, "Hello World")); + eventAnnotations.add(new AnnotationElement(Description.class, "Helps programmer getting started")); + eventAnnotations.add(new AnnotationElement(Category.class, category)); + + EventFactory f = EventFactory.create(eventAnnotations, fields); + + Event event = f.newEvent(); + event.set(0, "hello, world!"); + event.set(1, 4711); + event.commit(); + // @end + } + + void EventSettingOverview() throws Exception { + // @start region="EventSettingOverview" + Recording r = new Recording(); + r.enable("jdk.CPULoad") + .withPeriod(Duration.ofSeconds(1)); + r.enable("jdk.FileWrite") + .withoutStackTrace() + .withThreshold(Duration.ofNanos(10)); + r.start(); + Thread.sleep(10_000); + r.stop(); + r.dump(Files.createTempFile("recording", ".jfr")); + // @end + } + + void FlightRecorderTakeSnapshot() throws Exception { + // @start region="FlightRecorderTakeSnapshot" + try (Recording snapshot = FlightRecorder.getFlightRecorder().takeSnapshot()) { + if (snapshot.getSize() > 0) { + snapshot.setMaxSize(100_000_000); + snapshot.setMaxAge(Duration.ofMinutes(5)); + snapshot.dump(Paths.get("snapshot.jfr")); + } + } + // @end + } + + // @start region="MetadataDefinitionOverview" + @MetadataDefinition + @Label("Severity") + @Description("Value between 0 and 100 that indicates severity. 100 is most severe.") + @Retention(RetentionPolicy.RUNTIME) + @Target({ ElementType.TYPE }) + public @interface Severity { + int value() default 50; + } + + @MetadataDefinition + @Label("Transaction Id") + @Relational + @Retention(RetentionPolicy.RUNTIME) + @Target({ ElementType.FIELD }) + public @interface TransactionId { + } + + @Severity(80) + @Label("Transaction Blocked") + class TransactionBlocked extends Event { + @TransactionId + @Label("Transaction") + long transactionId1; + + @TransactionId + @Label("Transaction Blocker") + long transactionId2; + } + // @end + + // @start region="RelationalOverview" + @MetadataDefinition + @Relational + @Name("com.example.OrderId") + @Label("Order ID") + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.FIELD) + public @interface OrderId { + } + + @Name("com.example.Order") + @Label("Order") + @Category("Orders") + class OrderEvent extends Event { + @Label("Order ID") + @OrderId + long orderId; + + @Label("Order Date") + @Timestamp + long orderDate; + } + + @Name("com.example.OrderLine") + @Label("Order Line") + @Category("Orders") + class OrderLineEvent extends Event { + @Label("Order ID") + @OrderId + long orderId; + + @Label("Quantity") + long quantity; + + @Label("Product") + String product; + } + // @end + + void RecordingnOverview() throws Exception { + // @start region="RecordingOverview" + Configuration c = Configuration.getConfiguration("default"); + Recording r = new Recording(c); + r.start(); + System.gc(); + Thread.sleep(5000); + r.stop(); + r.dump(Files.createTempFile("my-recording", ".jfr")); + // @end + } + + // @start region="SettingControlOverview1" + final class RegExpControl extends SettingControl { + private Pattern pattern = Pattern.compile(".*"); + + @Override + public void setValue(String value) { + this.pattern = Pattern.compile(value); + } + + @Override + public String combine(Set<String> values) { + return String.join("|", values); + } + + @Override + public String getValue() { + return pattern.toString(); + } + + public boolean matches(String s) { + return pattern.matcher(s).find(); + } + } + // @end + + class HttpServlet { + } + + class HttpServletRequest { + public String getRequestURI() { + return null; + } + } + + class HttpServletResponse { + } + + // @start region="SettingControlOverview2" + abstract class HTTPRequest extends Event { + @Label("Request URI") + protected String uri; + + @Label("Servlet URI Filter") + @SettingDefinition + protected boolean uriFilter(RegExpControl regExp) { + return regExp.matches(uri); + } + } + + @Label("HTTP Get Request") + class HTTPGetRequest extends HTTPRequest { + } + + @Label("HTTP Post Request") + class HTTPPostRequest extends HTTPRequest { + } + + class ExampleServlet extends HttpServlet { + protected void doGet(HttpServletRequest req, HttpServletResponse resp) { + HTTPGetRequest request = new HTTPGetRequest(); + request.begin(); + request.uri = req.getRequestURI(); + code: // @replace regex='code:' replacement="..." + request.commit(); + } + + protected void doPost(HttpServletRequest req, HttpServletResponse resp) { + HTTPPostRequest request = new HTTPPostRequest(); + request.begin(); + request.uri = req.getRequestURI(); + code: // @replace regex='code:' replacement="..." + request.commit(); + } + } + // @end + + void SettingControlOverview3() { + // @start region="SettingControlOverview3" + Recording r = new Recording(); + r.enable("HTTPGetRequest").with("uriFilter", "https://www.example.com/list/.*"); + r.enable("HTTPPostRequest").with("uriFilter", "https://www.example.com/login/.*"); + r.start(); + // @end + } + + // @start region="SettingDefinitionOverview" + class HelloWorld extends Event { + + @Label("Message") + String message; + + @SettingDefinition + @Label("Message Filter") + public boolean filter(RegExpControl regExp) { + return regExp.matches(message); + } + } + // @end +} diff --git a/src/jdk.jfr/share/man/jfr.1 b/src/jdk.jfr/share/man/jfr.1 index 27e4e630dc1374c8c66f1649dc4da859f65e1a0c..321562e90b81b6d0c5932161c68413509d156a2e 100644 --- a/src/jdk.jfr/share/man/jfr.1 +++ b/src/jdk.jfr/share/man/jfr.1 @@ -21,7 +21,7 @@ .\" .\" Automatically generated by Pandoc 2.3.1 .\" -.TH "JFR" "1" "2021" "JDK 18\-ea" "JDK Commands" +.TH "JFR" "1" "2022" "JDK 19\-ea" "JDK Commands" .hy .SH NAME .PP diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImagePluginStack.java b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImagePluginStack.java index bd68c451b743732c616728d5782cdee2da63e720..4bf5987a64367fe0e890014a031acece654b7e31 100644 --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImagePluginStack.java +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImagePluginStack.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -282,7 +282,7 @@ public final class ImagePluginStack { * This pool wrap the original pool and automatically uncompress ResourcePoolEntry * if needed. */ - private class LastPoolManager extends ResourcePoolManager { + private static class LastPoolManager extends ResourcePoolManager { private class LastModule implements ResourcePoolModule { final ResourcePoolModule module; diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java index d90e4cf38e45c563564d56fbc99adfa3313d1fbe..835294d26de0d69cf63093dcb131546c65ad85da 100644 --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java @@ -78,7 +78,7 @@ import jdk.internal.module.ModuleResolution; * ## Should use jdk.joptsimple some day. */ public class JlinkTask { - static final boolean DEBUG = Boolean.getBoolean("jlink.debug"); + public static final boolean DEBUG = Boolean.getBoolean("jlink.debug"); // jlink API ignores by default. Remove when signing is implemented. static final boolean IGNORE_SIGNING_DEFAULT = true; diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePoolManager.java b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePoolManager.java index d7125d103d1cae5a321fb7c3b9ebac093f079935..67823180480eb7624da8405384f7e45fd6cd87e1 100644 --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePoolManager.java +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePoolManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -74,7 +74,7 @@ public class ResourcePoolManager { Resources.canEncapsulate(path); } - class ResourcePoolModuleImpl implements ResourcePoolModule { + static class ResourcePoolModuleImpl implements ResourcePoolModule { final Map<String, ResourcePoolEntry> moduleContent = new LinkedHashMap<>(); // lazily initialized diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/AbstractPlugin.java b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/AbstractPlugin.java index fd4fdcd39dda98474db2b7113cc53ab102c0b5e8..cf46ac684079381d1300e17f23d9635f236808b0 100644 --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/AbstractPlugin.java +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/AbstractPlugin.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -26,10 +26,17 @@ package jdk.tools.jlink.internal.plugins; import jdk.tools.jlink.plugin.Plugin; +import jdk.tools.jlink.internal.JlinkTask; +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; import java.util.Locale; import java.util.MissingResourceException; import java.util.ResourceBundle; +import jdk.internal.org.objectweb.asm.ClassReader; +import jdk.tools.jlink.plugin.ResourcePoolEntry; public abstract class AbstractPlugin implements Plugin { @@ -61,6 +68,50 @@ public abstract class AbstractPlugin implements Plugin { this.name = name; this.pluginsBundle = bundle; } + + private void dumpClassFile(String path, byte[] buf) { + try { + String fullPath = String.format("%d-%s%s%s", + ProcessHandle.current().pid(), + getName(), File.separator, + path.replace('/', File.separatorChar)); + System.err.printf("Dumping class file %s\n", fullPath); + new File(fullPath.substring(0, fullPath.lastIndexOf('/'))).mkdirs(); + Files.write(Paths.get(fullPath), buf); + } catch (IOException ioExp) { + System.err.println("writing " + path + " failed"); + ioExp.printStackTrace(); + } + } + + ClassReader newClassReader(String path, ResourcePoolEntry resource) { + byte[] content = resource.contentBytes(); + try { + return new ClassReader(content); + } catch (Exception e) { + if (JlinkTask.DEBUG) { + System.err.printf("Failed to parse class file: %s from resource of type %s\n", path, + resource.getClass().getName()); + e.printStackTrace(); + dumpClassFile(path, content); + } + throw e; + } + } + + protected ClassReader newClassReader(String path, byte[] buf) { + try { + return new ClassReader(buf); + } catch (Exception e) { + if (JlinkTask.DEBUG) { + System.err.printf("Failed to parse class file: %s\n", path); + e.printStackTrace(); + dumpClassFile(path, buf); + } + throw e; + } + } + @Override public String getName() { return name; diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/IncludeLocalesPlugin.java b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/IncludeLocalesPlugin.java index 17062af55f35fd9ce91945d2f978ac1cba030493..623b7f2917b0e450eb924c7d0c3d2c5d0a19c605 100644 --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/IncludeLocalesPlugin.java +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/IncludeLocalesPlugin.java @@ -158,7 +158,7 @@ public final class IncludeLocalesPlugin extends AbstractPlugin implements Resour if (resource != null && resource.type().equals(ResourcePoolEntry.Type.CLASS_OR_RESOURCE)) { byte[] bytes = resource.contentBytes(); - ClassReader cr = new ClassReader(bytes); + ClassReader cr = newClassReader(path, bytes); if (Arrays.stream(cr.getInterfaces()) .anyMatch(i -> i.contains(METAINFONAME)) && stripUnsupportedLocales(bytes, cr)) { diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/StripJavaDebugAttributesPlugin.java b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/StripJavaDebugAttributesPlugin.java index c7c3979992122bb40905b84a3d97da2680a5cb0f..d56ffc729ad95d2910a8160d694ad5bdbf112617 100644 --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/StripJavaDebugAttributesPlugin.java +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/StripJavaDebugAttributesPlugin.java @@ -59,7 +59,7 @@ public final class StripJavaDebugAttributesPlugin extends AbstractPlugin { if (path.endsWith("module-info.class")) { // XXX. Do we have debug info? Is Asm ready for module-info? } else { - ClassReader reader = new ClassReader(resource.contentBytes()); + ClassReader reader = newClassReader(path, resource); ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS); reader.accept(writer, ClassReader.SKIP_DEBUG); byte[] content = writer.toByteArray(); diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/SystemModulesPlugin.java b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/SystemModulesPlugin.java index 4d1129ac8dc60178a9dd110c1070feb7f2c8bb5c..c58013d54436e4ff5124a0bea2846bd8294324ad 100644 --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/SystemModulesPlugin.java +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/SystemModulesPlugin.java @@ -477,7 +477,7 @@ public final class SystemModulesPlugin extends AbstractPlugin { return bais; } - class ModuleInfoRewriter extends ByteArrayOutputStream { + static class ModuleInfoRewriter extends ByteArrayOutputStream { final ModuleInfoExtender extender; ModuleInfoRewriter(InputStream in) { this.extender = ModuleInfoExtender.newExtender(in); @@ -625,7 +625,7 @@ public final class SystemModulesPlugin extends AbstractPlugin { } /** - * Generate byteccode for no-arg constructor + * Generate bytecode for no-arg constructor */ private void genConstructor(ClassWriter cw) { MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null); diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/VersionPropsPlugin.java b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/VersionPropsPlugin.java index 8c1c8374faf0305fb905e0b82200ee4b3e7316c0..af241efcea7b80a5ee1495f7c20b5748035d696a 100644 --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/VersionPropsPlugin.java +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/VersionPropsPlugin.java @@ -96,9 +96,9 @@ abstract class VersionPropsPlugin extends AbstractPlugin { private boolean redefined = false; - private byte[] redefine(byte[] classFile) { + private byte[] redefine(String path, byte[] classFile) { - var cr = new ClassReader(classFile); + var cr = newClassReader(path, classFile); var cw = new ClassWriter(0); cr.accept(new ClassVisitor(Opcodes.ASM7, cw) { @@ -189,7 +189,7 @@ abstract class VersionPropsPlugin extends AbstractPlugin { in.transformAndCopy(res -> { if (res.type().equals(ResourcePoolEntry.Type.CLASS_OR_RESOURCE)) { if (res.path().equals(VERSION_PROPS_CLASS)) { - return res.copyWithContent(redefine(res.contentBytes())); + return res.copyWithContent(redefine(res.path(), res.contentBytes())); } } return res; diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins.properties b/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins.properties index 958c43c2ca4c7754f2c26094452f9020241cf0e2..017c46baab02df2c3318ad7447b10f5c31a355dc 100644 --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins.properties +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins.properties @@ -142,7 +142,8 @@ generate-cds-archive.description=\ CDS plugin: generate cds archives if the runtime image supports CDS feature.\n\ generate-cds-archive.usage=\ -\ --generate-cds-archive Generate CDS archives if the runtime image supports CDS feature. +\ --generate-cds-archive Generate CDS archive if the runtime image supports\n\ +\ the CDS feature. generate-jli-classes.argument=@filename diff --git a/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodOutputStream.java b/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodOutputStream.java index 5fae838a59e050a31236d8da5b2acc5fb6690d8c..895500291f9e2fe71cd84b00295e1b2c94414811 100644 --- a/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodOutputStream.java +++ b/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodOutputStream.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -41,6 +41,7 @@ import java.util.Set; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; import jdk.internal.jmod.JmodFile; +import java.time.LocalDateTime; import static jdk.internal.jmod.JmodFile.*; @@ -54,15 +55,17 @@ class JmodOutputStream extends OutputStream implements AutoCloseable { * This method creates (or overrides, if exists) the JMOD file, * returning the the output stream to write to the JMOD file. */ - static JmodOutputStream newOutputStream(Path file) throws IOException { + static JmodOutputStream newOutputStream(Path file, LocalDateTime date) throws IOException { OutputStream out = Files.newOutputStream(file); BufferedOutputStream bos = new BufferedOutputStream(out); - return new JmodOutputStream(bos); + return new JmodOutputStream(bos, date); } private final ZipOutputStream zos; - private JmodOutputStream(OutputStream out) { + private final LocalDateTime date; + private JmodOutputStream(OutputStream out, LocalDateTime date) { this.zos = new ZipOutputStream(out); + this.date = date; try { JmodFile.writeMagicNumber(out); } catch (IOException e) { @@ -104,7 +107,11 @@ class JmodOutputStream extends OutputStream implements AutoCloseable { // sun.tools.jar.Main.update() ZipEntry e2 = new ZipEntry(e1.getName()); e2.setMethod(e1.getMethod()); - e2.setTime(e1.getTime()); + if (date != null) { + e2.setTimeLocal(date); + } else { + e2.setTime(e1.getTime()); + } e2.setComment(e1.getComment()); e2.setExtra(e1.getExtra()); if (e1.getMethod() == ZipEntry.STORED) { @@ -124,7 +131,11 @@ class JmodOutputStream extends OutputStream implements AutoCloseable { String name = Paths.get(prefix, path).toString() .replace(File.separatorChar, '/'); entries.get(section).add(path); - return new ZipEntry(name); + ZipEntry zipEntry = new ZipEntry(name); + if (date != null) { + zipEntry.setTimeLocal(date); + } + return zipEntry; } public boolean contains(Section section, String path) { diff --git a/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java b/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java index eb541bba63fb210bc18fd3a70f1dec0f17971a7f..52d6222d5a2288a9959821611334c5c831d59e8c 100644 --- a/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java +++ b/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -62,6 +62,11 @@ import java.util.stream.Collectors; import java.util.zip.ZipEntry; import java.util.zip.ZipException; import java.util.zip.ZipFile; +import java.time.LocalDateTime; +import java.time.ZonedDateTime; +import java.time.ZoneOffset; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; import jdk.internal.jmod.JmodFile; import jdk.internal.jmod.JmodFile.Section; @@ -160,8 +165,13 @@ public class JmodTask { boolean dryrun; List<PathMatcher> excludes; Path extractDir; + LocalDateTime date; } + // Valid --date range + static final ZonedDateTime DATE_MIN = ZonedDateTime.parse("1980-01-01T00:00:02Z"); + static final ZonedDateTime DATE_MAX = ZonedDateTime.parse("2099-12-31T23:59:59Z"); + public int run(String[] args) { try { @@ -427,7 +437,7 @@ public class JmodTask { Path target = options.jmodFile; Path tempTarget = jmodTempFilePath(target); try { - try (JmodOutputStream jos = JmodOutputStream.newOutputStream(tempTarget)) { + try (JmodOutputStream jos = JmodOutputStream.newOutputStream(tempTarget, options.date)) { jmod.write(jos); } Files.move(tempTarget, target); @@ -680,7 +690,6 @@ public class JmodTask { .filter(path -> isResource(path.toString())) .map(path -> toPackageName(path)) .filter(pkg -> pkg.length() > 0) - .distinct() .collect(Collectors.toSet()); } catch (IOException ioe) { throw new UncheckedIOException(ioe); @@ -695,7 +704,6 @@ public class JmodTask { .filter(e -> !e.isDirectory() && isResource(e.getName())) .map(e -> toPackageName(e)) .filter(pkg -> pkg.length() > 0) - .distinct() .collect(Collectors.toSet()); } @@ -767,6 +775,10 @@ public class JmodTask { void processSection(JmodOutputStream out, Section section, Path path) throws IOException { + // Keep a sorted set of files to be processed, so that the jmod + // content is reproducible as Files.walkFileTree order is not defined + SortedMap<String, Path> filesToProcess = new TreeMap<String, Path>(); + Files.walkFileTree(path, Set.of(FileVisitOption.FOLLOW_LINKS), Integer.MAX_VALUE, new SimpleFileVisitor<Path>() { @Override @@ -782,14 +794,21 @@ public class JmodTask { if (out.contains(section, name)) { warning("warn.ignore.duplicate.entry", name, section); } else { - try (InputStream in = Files.newInputStream(file)) { - out.writeEntry(in, section, name); - } + filesToProcess.put(name, file); } } return FileVisitResult.CONTINUE; } }); + + // Process files in sorted order for deterministic jmod content + for (Map.Entry<String, Path> entry : filesToProcess.entrySet()) { + String name = entry.getKey(); + Path file = entry.getValue(); + try (InputStream in = Files.newInputStream(file)) { + out.writeEntry(in, section, name); + } + } } boolean matches(Path path, List<PathMatcher> matchers) { @@ -973,7 +992,11 @@ public class JmodTask { if (e.getName().equals(MODULE_INFO)) { // what about module-info.class in versioned entries? ZipEntry ze = new ZipEntry(e.getName()); - ze.setTime(System.currentTimeMillis()); + if (options.date != null) { + ze.setTimeLocal(options.date); + } else { + ze.setTime(System.currentTimeMillis()); + } jos.putNextEntry(ze); recordHashes(in, jos, moduleHashes); jos.closeEntry(); @@ -1001,7 +1024,7 @@ public class JmodTask { { try (JmodFile jf = new JmodFile(target); - JmodOutputStream jos = JmodOutputStream.newOutputStream(tempTarget)) + JmodOutputStream jos = JmodOutputStream.newOutputStream(tempTarget, options.date)) { jf.stream().forEach(e -> { try (InputStream in = jf.getInputStream(e.section(), e.name())) { @@ -1136,6 +1159,26 @@ public class JmodTask { @Override public String valuePattern() { return "module-version"; } } + static class DateConverter implements ValueConverter<LocalDateTime> { + @Override + public LocalDateTime convert(String value) { + try { + ZonedDateTime date = ZonedDateTime.parse(value, DateTimeFormatter.ISO_ZONED_DATE_TIME) + .withZoneSameInstant(ZoneOffset.UTC); + if (date.isBefore(DATE_MIN) || date.isAfter(DATE_MAX)) { + throw new CommandException("err.date.out.of.range", value); + } + return date.toLocalDateTime(); + } catch (DateTimeParseException x) { + throw new CommandException("err.invalid.date", value, x.getMessage()); + } + } + + @Override public Class<LocalDateTime> valueType() { return LocalDateTime.class; } + + @Override public String valuePattern() { return "date"; } + } + static class WarnIfResolvedReasonConverter implements ValueConverter<ModuleResolution> { @@ -1371,6 +1414,11 @@ public class JmodTask { OptionSpec<Void> version = parser.accepts("version", getMessage("main.opt.version")); + OptionSpec<LocalDateTime> date + = parser.accepts("date", getMessage("main.opt.date")) + .withRequiredArg() + .withValuesConvertedBy(new DateConverter()); + NonOptionArgumentSpec<String> nonOptions = parser.nonOptions(); @@ -1414,6 +1462,8 @@ public class JmodTask { options.manPages = getLastElement(opts.valuesOf(manPages)); if (opts.has(legalNotices)) options.legalNotices = getLastElement(opts.valuesOf(legalNotices)); + if (opts.has(date)) + options.date = opts.valueOf(date); if (opts.has(modulePath)) { Path[] dirs = getLastElement(opts.valuesOf(modulePath)).toArray(new Path[0]); options.moduleFinder = ModulePath.of(Runtime.version(), true, dirs); diff --git a/src/jdk.jlink/share/classes/jdk/tools/jmod/resources/jmod.properties b/src/jdk.jlink/share/classes/jdk/tools/jmod/resources/jmod.properties index 09aa5ae44b3175b274a1727708f1f0c5d0a8a70f..c1022b0fb5e8e89b0e3ea1eb9385e908bf7a5db2 100644 --- a/src/jdk.jlink/share/classes/jdk/tools/jmod/resources/jmod.properties +++ b/src/jdk.jlink/share/classes/jdk/tools/jmod/resources/jmod.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. +# 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 @@ -74,6 +74,9 @@ main.opt.hash-modules=Compute and record hashes to tie a packaged module\ main.opt.do-not-resolve-by-default=Exclude from the default root set of modules main.opt.warn-if-resolved=Hint for a tool to issue a warning if the module \ is resolved. One of deprecated, deprecated-for-removal, or incubating +main.opt.date=Date and time for the timestamps of entries, specified in ISO-8601\ +\ extended offset date-time with optional time-zone format, e.g.\ +\ "2022-02-12T12:30:00-05:00" main.opt.cmdfile=Read options from the specified file @@ -106,6 +109,8 @@ err.module.descriptor.not.found=Module descriptor not found err.missing.export.or.open.packages=Packages that are exported or open in {0} are not present: {1} err.module.resolution.fail=Resolution failed: {0} err.no.moduleToHash=No hashes recorded: no module matching {0} found to record hashes +err.invalid.date=--date {0} is not a valid ISO-8601 extended offset date-time with optional time-zone format: {1} +err.date.out.of.range=--date {0} is out of the valid range 1980-01-01T00:00:02Z to 2099-12-31T23:59:59Z warn.invalid.arg=Invalid classname or pathname not exist: {0} warn.no.module.hashes=No hashes recorded: no module specified for hashing depends on {0} warn.ignore.entry=ignoring entry {0}, in section {1} diff --git a/src/jdk.jlink/share/classes/module-info.java b/src/jdk.jlink/share/classes/module-info.java index d2db4c5f9e4424999eade0f5ff6c568fe0931c44..8b7c08509661c60c88bb672ee5963e5c6fb7a8e6 100644 --- a/src/jdk.jlink/share/classes/module-info.java +++ b/src/jdk.jlink/share/classes/module-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -44,6 +44,9 @@ * @toolGuide jmod * * @provides java.util.spi.ToolProvider + * Use {@link java.util.spi.ToolProvider#findFirst ToolProvider.findFirst("jlink")} + * to obtain an instance of a {@code ToolProvider} that provides the equivalent + * of command-line access to the {@code jlink} tool. * * @moduleGraph * @since 9 diff --git a/src/jdk.jlink/share/man/jlink.1 b/src/jdk.jlink/share/man/jlink.1 index f5324309efcfd1f7e867ebedc5f7c80f85174cf2..fbe660189431b54d4a6d39214303e6850497d896 100644 --- a/src/jdk.jlink/share/man/jlink.1 +++ b/src/jdk.jlink/share/man/jlink.1 @@ -21,7 +21,7 @@ .\" .\" Automatically generated by Pandoc 2.3.1 .\" -.TH "JLINK" "1" "2021" "JDK 18\-ea" "JDK Commands" +.TH "JLINK" "1" "2022" "JDK 19\-ea" "JDK Commands" .hy .SH NAME .PP @@ -294,6 +294,17 @@ Example: Strips debug information from the output image. .RS .RE +.SS Plugin \f[CB]generate\-cds\-archive\f[R] +.TP +.B Options +\f[CB]\-\-generate\-cds\-archive\f[R] +.RS +.RE +.TP +.B Description +Generate CDS archive if the runtime image supports the CDS feature. +.RS +.RE .SH JLINK EXAMPLES .PP The following command creates a runtime image in the directory diff --git a/src/jdk.jlink/share/man/jmod.1 b/src/jdk.jlink/share/man/jmod.1 index 16f595782a5077791a3b8fda38aa5fdd15c975f4..a9c68e1a8dcab0d28ca12dab826dd735ad363227 100644 --- a/src/jdk.jlink/share/man/jmod.1 +++ b/src/jdk.jlink/share/man/jmod.1 @@ -21,7 +21,7 @@ .\" .\" Automatically generated by Pandoc 2.3.1 .\" -.TH "JMOD" "1" "2021" "JDK 18\-ea" "JDK Commands" +.TH "JMOD" "1" "2022" "JDK 19\-ea" "JDK Commands" .hy .SH NAME .PP diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppImageBuilder.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppImageBuilder.java index a12ed59c10ec155c92824247d542d1919355c1ee..7291d56218a217ec6381cea8835038a816d24cd2 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppImageBuilder.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppImageBuilder.java @@ -101,7 +101,7 @@ public class LinuxAppImageBuilder extends AbstractAppImageBuilder { private void createLauncherLib() throws IOException { Path path = appLayout.pathGroup().getPath( ApplicationLayout.PathRole.LINUX_APPLAUNCHER_LIB); - try (InputStream resource = getResourceAsStream("libjpackageapplauncher.so")) { + try (InputStream resource = getResourceAsStream("libjpackageapplauncheraux.so")) { writeEntry(resource, path); } 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 f1eed5f5f1538e15138a3231b854ac0ad1f84403..fd33ffbb3db61e9c2eb4608c8ca0a3a15545257b 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageBuilder.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageBuilder.java @@ -593,7 +593,6 @@ public class MacAppImageBuilder extends AbstractAppImageBuilder { Log.error(I18N.getString("message.keychain.error")); return; } - boolean contains = keychainList.stream().anyMatch( str -> str.trim().equals("\""+keyChainPath.trim()+"\"")); if (contains) { @@ -608,7 +607,9 @@ public class MacAppImageBuilder extends AbstractAppImageBuilder { if (path.startsWith("\"") && path.endsWith("\"")) { path = path.substring(1, path.length()-1); } - keyChains.add(path); + if (!keyChains.contains(path)) { + keyChains.add(path); + } }); List<String> args = new ArrayList<>(); @@ -682,27 +683,23 @@ public class MacAppImageBuilder extends AbstractAppImageBuilder { Log.verbose(MessageFormat.format(I18N.getString( "message.ignoring.symlink"), p.toString())); } else { - List<String> args; - // runtime and Framework files will be signed below - // but they need to be unsigned first here - if ((p.toString().contains("/Contents/runtime")) || - (p.toString().contains("/Contents/Frameworks"))) { - - args = new ArrayList<>(); - args.addAll(Arrays.asList("/usr/bin/codesign", - "--remove-signature", p.toString())); - try { - Set<PosixFilePermission> oldPermissions = - Files.getPosixFilePermissions(p); - p.toFile().setWritable(true, true); - ProcessBuilder pb = new ProcessBuilder(args); - IOUtils.exec(pb); - Files.setPosixFilePermissions(p,oldPermissions); - } catch (IOException ioe) { - Log.verbose(ioe); - toThrow.set(ioe); - return; - } + // unsign everything before signing + List<String> args = new ArrayList<>(); + args.addAll(Arrays.asList("/usr/bin/codesign", + "--remove-signature", p.toString())); + try { + Set<PosixFilePermission> oldPermissions = + Files.getPosixFilePermissions(p); + p.toFile().setWritable(true, true); + ProcessBuilder pb = new ProcessBuilder(args); + // run quietly + IOUtils.exec(pb, false, null, false, + Executor.INFINITE_TIMEOUT, true); + Files.setPosixFilePermissions(p,oldPermissions); + } catch (IOException ioe) { + Log.verbose(ioe); + toThrow.set(ioe); + return; } args = new ArrayList<>(); args.addAll(Arrays.asList("/usr/bin/codesign", @@ -727,7 +724,9 @@ public class MacAppImageBuilder extends AbstractAppImageBuilder { Files.getPosixFilePermissions(p); p.toFile().setWritable(true, true); ProcessBuilder pb = new ProcessBuilder(args); - IOUtils.exec(pb); + // run quietly + IOUtils.exec(pb, false, null, false, + Executor.INFINITE_TIMEOUT, true); Files.setPosixFilePermissions(p, oldPermissions); } catch (IOException ioe) { toThrow.set(ioe); 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 23a4f9d0437cb7b658ec48a98d851e99c20a1dd0..25a9facea5f2d1e2916e622efb80968c4c9a1a6f 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 @@ -1,5 +1,5 @@ # -# Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. +# 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 @@ -80,7 +80,7 @@ message.building-dmg=Building DMG package for {0}. message.running-script=Running shell script on application image [{0}]. message.preparing-dmg-setup=Preparing dmg setup: {0}. message.creating-dmg-file=Creating DMG file: {0}. -message.dmg-cannot-be-overwritten=Dmg file exists ({0} and can not be removed. +message.dmg-cannot-be-overwritten=Dmg file exists [{0}] and can not be removed. message.output-to-location=Result DMG installer for {0}: {1}. message.building-pkg=Building PKG package for {0}. message.preparing-scripts=Preparing package scripts. 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 d9da226ec9229c948e3d46bbd15115e159ac4bf5..291130fb23737ee9ac9db6c0d260f41fe617da54 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 @@ -1,5 +1,5 @@ # -# Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. +# 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 @@ -79,7 +79,7 @@ message.building-dmg={0}\u306EDMG\u30D1\u30C3\u30B1\u30FC\u30B8\u3092\u4F5C\u621 message.running-script=\u30A2\u30D7\u30EA\u30B1\u30FC\u30B7\u30E7\u30F3\u30FB\u30A4\u30E1\u30FC\u30B8[{0}]\u3067\u30B7\u30A7\u30EB\u30FB\u30B9\u30AF\u30EA\u30D7\u30C8\u3092\u5B9F\u884C\u3057\u3066\u3044\u307E\u3059\u3002 message.preparing-dmg-setup=dmg\u306E\u8A2D\u5B9A\u3092\u6E96\u5099\u3057\u3066\u3044\u307E\u3059: {0} message.creating-dmg-file=DMG\u30D5\u30A1\u30A4\u30EB\u3092\u4F5C\u6210\u3057\u3066\u3044\u307E\u3059: {0} -message.dmg-cannot-be-overwritten=Dmg\u30D5\u30A1\u30A4\u30EB\u306F\u5B58\u5728\u3057({0}\u3001\u524A\u9664\u3067\u304D\u307E\u305B\u3093\u3002 +message.dmg-cannot-be-overwritten=Dmg\u30D5\u30A1\u30A4\u30EB\u306F\u5B58\u5728\u3057[{0}]\u3001\u524A\u9664\u3067\u304D\u307E\u305B\u3093\u3002 message.output-to-location={0}\u306E\u7D50\u679C\u306EDMG\u30A4\u30F3\u30B9\u30C8\u30FC\u30E9: {1} message.building-pkg={0}\u306EPKG\u30D1\u30C3\u30B1\u30FC\u30B8\u3092\u4F5C\u6210\u3057\u3066\u3044\u307E\u3059 message.preparing-scripts=\u30D1\u30C3\u30B1\u30FC\u30B8\u30FB\u30B9\u30AF\u30EA\u30D7\u30C8\u3092\u6E96\u5099\u3057\u3066\u3044\u307E\u3059 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 d6f47a7bc85e7641da6253ba695ba2b5ab2a37fc..ecf9e8796d52114881bad9faf4f5baa64d7871d7 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 @@ -1,5 +1,5 @@ # -# Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. +# 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 @@ -79,7 +79,7 @@ message.building-dmg=\u6B63\u5728\u4E3A {0} \u6784\u5EFA DMG \u7A0B\u5E8F\u5305\ message.running-script=\u6B63\u5728\u5E94\u7528\u7A0B\u5E8F\u6620\u50CF [{0}] \u4E0A\u8FD0\u884C shell \u811A\u672C\u3002 message.preparing-dmg-setup=\u6B63\u5728\u51C6\u5907 dmg \u8BBE\u7F6E: {0}\u3002 message.creating-dmg-file=\u6B63\u5728\u521B\u5EFA DMG \u6587\u4EF6: {0}\u3002 -message.dmg-cannot-be-overwritten=Dmg \u6587\u4EF6\u5DF2\u5B58\u5728 ({0}) \u4E14\u65E0\u6CD5\u5220\u9664\u3002 +message.dmg-cannot-be-overwritten=Dmg \u6587\u4EF6\u5DF2\u5B58\u5728 [{0}] \u4E14\u65E0\u6CD5\u5220\u9664\u3002 message.output-to-location=\u4E3A {0} \u751F\u6210\u7684 DMG \u5B89\u88C5\u7A0B\u5E8F: {1}\u3002 message.building-pkg=\u6B63\u5728\u4E3A {0} \u6784\u5EFA PKG \u7A0B\u5E8F\u5305\u3002 message.preparing-scripts=\u6B63\u5728\u51C6\u5907\u7A0B\u5E8F\u5305\u811A\u672C\u3002 diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AddLauncherArguments.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AddLauncherArguments.java index 84eb9197a2b89be6fd3eac285086f206085bc1d8..59268992602dd9d6ff3821affdc83aa5b9a71679 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AddLauncherArguments.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AddLauncherArguments.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -54,6 +54,7 @@ import static jdk.jpackage.internal.StandardBundlerParam.SHORTCUT_HINT; * The add-launcher properties file may have any of: * * appVersion + * description * module * main-jar * main-class @@ -111,6 +112,9 @@ class AddLauncherArguments { Arguments.putUnlessNull(bundleParams, CLIOptions.VERSION.getId(), getOptionValue(CLIOptions.VERSION)); + Arguments.putUnlessNull(bundleParams, CLIOptions.DESCRIPTION.getId(), + getOptionValue(CLIOptions.DESCRIPTION)); + Arguments.putUnlessNull(bundleParams, CLIOptions.RELEASE.getId(), getOptionValue(CLIOptions.RELEASE)); 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 bc32df6a9bae3cbe864c612134b0a7f7ddfcf379..c41d8ff3bbb68d34913e62c8948ee46acc9fc149 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/IOUtils.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/IOUtils.java @@ -190,14 +190,24 @@ public class IOUtils { static void exec(ProcessBuilder pb, boolean testForPresenceOnly, PrintStream consumer, boolean writeOutputToFile, long timeout) throws IOException { + exec(pb, testForPresenceOnly, consumer, writeOutputToFile, + timeout, false); + } + + static void exec(ProcessBuilder pb, boolean testForPresenceOnly, + PrintStream consumer, boolean writeOutputToFile, + long timeout, boolean quiet) throws IOException { List<String> output = new ArrayList<>(); - Executor exec = Executor.of(pb).setWriteOutputToFile(writeOutputToFile) - .setTimeout(timeout).setOutputConsumer(lines -> { - lines.forEach(output::add); - if (consumer != null) { - output.forEach(consumer::println); - } - }); + Executor exec = Executor.of(pb) + .setWriteOutputToFile(writeOutputToFile) + .setTimeout(timeout) + .setQuiet(quiet) + .setOutputConsumer(lines -> { + lines.forEach(output::add); + if (consumer != null) { + output.forEach(consumer::println); + } + }); if (testForPresenceOnly) { exec.execute(); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Log.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Log.java index 22e43b4311f75f5db57be18331988adc56e90171..b14b4ab22caeb708e49e2a7cbe052eb6a68cf3ea 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Log.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Log.java @@ -108,7 +108,7 @@ public class Log { public void verbose(List<String> strings, List<String> output, int returnCode, long pid) { if (verbose) { - StringBuffer sb = new StringBuffer(); + StringBuilder sb = new StringBuilder(); sb.append("Command [PID: "); sb.append(pid); sb.append("]:\n "); @@ -116,13 +116,13 @@ public class Log { for (String s : strings) { sb.append(" " + s); } - verbose(new String(sb)); + verbose(sb.toString()); if (output != null && !output.isEmpty()) { - sb = new StringBuffer("Output:"); + sb = new StringBuilder("Output:"); for (String s : output) { sb.append("\n " + s); } - verbose(new String(sb)); + verbose(sb.toString()); } verbose("Returned: " + returnCode + "\n"); } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/OverridableResource.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/OverridableResource.java index 9680691bc5db94d2322ba72e0be54c90f8848510..c455ef7150034918bab35f2dcb7a030c6fc672c5 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/OverridableResource.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/OverridableResource.java @@ -36,6 +36,8 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardCopyOption; import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -279,11 +281,35 @@ final class OverridableResource { private static Stream<String> substitute(Stream<String> lines, Map<String, String> substitutionData) { + // Order substitution data by the length of keys. + // Longer keys go first. + // This is needed to properly handle cases when one key is + // a subtring of another and try the later first. + var orderedEntries = substitutionData.entrySet().stream() + .sorted(Map.Entry.<String, String>comparingByKey( + Comparator.comparingInt(String::length)).reversed()) + .toList(); return lines.map(line -> { String result = line; - for (var entry : substitutionData.entrySet()) { - result = result.replace(entry.getKey(), Optional.ofNullable( - entry.getValue()).orElse("")); + var workEntries = orderedEntries; + var it = workEntries.listIterator(); + while (it.hasNext()) { + var entry = it.next(); + String newResult = result.replace(entry.getKey(), + Optional.ofNullable(entry.getValue()).orElse("")); + if (!newResult.equals(result)) { + // Substitution occured. + // Remove the matching substitution key from the list and + // go over the list of substitution entries again. + if (workEntries == orderedEntries) { + workEntries = new ArrayList<>(orderedEntries); + it = workEntries.listIterator(it.nextIndex() - 1); + it.next(); + } + it.remove(); + it = workEntries.listIterator(); + result = newResult; + } } return result; }); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/HelpResources.properties b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/HelpResources.properties index 27f0a491c2a22a1bd632e8fa747fdad1944a8145..658cb603cff690075bb127cc4535c899413c2d37 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/HelpResources.properties +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/HelpResources.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. +# 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 @@ -138,7 +138,7 @@ Generic Options:\n\ \ Name of launcher, and a path to a Properties file that contains\n\ \ a list of key, value pairs\n\ \ (absolute path or relative to the current directory)\n\ -\ The keys "module", "main-jar", "main-class",\n\ +\ The keys "module", "main-jar", "main-class", "description",\n\ \ "arguments", "java-options", "app-version", "icon",\n\ \ "win-console", "win-shortcut", "win-menu",\n\ \ "linux-app-category", and "linux-shortcut" can be used.\n\ diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/HelpResources_ja.properties b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/HelpResources_ja.properties index b241ab8403dc6309a7238e2a9d2cfd661e22b698..6ed6c2c90a9a857e801966aeeb209ab6fd18eeed 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/HelpResources_ja.properties +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/HelpResources_ja.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. +# 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 @@ -138,7 +138,7 @@ Generic Options:\n\ \ Name of launcher, and a path to a Properties file that contains\n\ \ a list of key, value pairs\n\ \ (absolute path or relative to the current directory)\n\ -\ The keys "module", "main-jar", "main-class",\n\ +\ The keys "module", "main-jar", "main-class", "description",\n\ \ "arguments", "java-options", "app-version", "icon",\n\ \ "win-console", "win-shortcut", "win-menu",\n\ \ "linux-app-category", and "linux-shortcut" can be used.\n\ diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/HelpResources_zh_CN.properties b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/HelpResources_zh_CN.properties index 09de3241d1b66ab94f01c3fd6a81140f6728c489..73a3db560edf62bac28f9c455a923371862f4672 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/HelpResources_zh_CN.properties +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/HelpResources_zh_CN.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. +# 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 @@ -138,7 +138,7 @@ Generic Options:\n\ \ Name of launcher, and a path to a Properties file that contains\n\ \ a list of key, value pairs\n\ \ (absolute path or relative to the current directory)\n\ -\ The keys "module", "main-jar", "main-class",\n\ +\ The keys "module", "main-jar", "main-class", "description",\n\ \ "arguments", "java-options", "app-version", "icon",\n\ \ "win-console", "win-shortcut", "win-menu",\n\ \ "linux-app-category", and "linux-shortcut" can be used.\n\ diff --git a/src/jdk.jpackage/share/classes/module-info.java b/src/jdk.jpackage/share/classes/module-info.java index 475daa0bd56f2f0e89978a8c53f06c9d29c73042..5fd36ee6b2f78c9de41937b595fc5a8ce69e77c6 100644 --- a/src/jdk.jpackage/share/classes/module-info.java +++ b/src/jdk.jpackage/share/classes/module-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -41,6 +41,10 @@ * concurrently, even with separate {@code "jpackage"} {@code ToolProvider} * instances, or undefined behavior may result. * + * @provides java.util.spi.ToolProvider + * Use {@link java.util.spi.ToolProvider#findFirst ToolProvider.findFirst("jpackage")} + * to obtain an instance of a {@code ToolProvider} that provides the equivalent + * of command-line access to the {@code jpackage} tool. * * @moduleGraph * @since 16 diff --git a/src/jdk.jpackage/share/man/jpackage.1 b/src/jdk.jpackage/share/man/jpackage.1 index 2b85c96cb468fd7d9021599a097dbe796ab32a7e..51b45f7bdfcb73c27fa10187c7422d8a9b4317d9 100644 --- a/src/jdk.jpackage/share/man/jpackage.1 +++ b/src/jdk.jpackage/share/man/jpackage.1 @@ -21,7 +21,7 @@ .\" .\" Automatically generated by Pandoc 2.3.1 .\" -.TH "JPACKAGE" "1" "2021" "JDK 18\-ea" "JDK Commands" +.TH "JPACKAGE" "1" "2022" "JDK 19\-ea" "JDK Commands" .hy .SH NAME .PP @@ -56,7 +56,7 @@ Read options from a file. This option can be used multiple times. .RE .TP -.B \f[CB]\-\-type\f[R] or \f[CB]\-t\f[R] <type string> +.B \f[CB]\-\-type\f[R] or \f[CB]\-t\f[R] \f[I]type\f[R] The type of package to create .RS .PP @@ -67,17 +67,17 @@ If this option is not specified a platform dependent default type will be created. .RE .TP -.B \f[CB]\-\-app\-version\f[R] <version> +.B \f[CB]\-\-app\-version\f[R] \f[I]version\f[R] Version of the application and/or package .RS .RE .TP -.B \f[CB]\-\-copyright\f[R] <copyright string> +.B \f[CB]\-\-copyright\f[R] \f[I]copyright\f[R] Copyright for the application .RS .RE .TP -.B \f[CB]\-\-description\f[R] <description string> +.B \f[CB]\-\-description\f[R] \f[I]description\f[R] Description of the application .RS .RE @@ -88,30 +88,33 @@ for the current platform to the output stream, and exit. .RS .RE .TP -.B \f[CB]\-\-icon\f[R] <icon file path> -Path of the icon of the application package (absolute path or relative -to the current directory) +.B \f[CB]\-\-icon\f[R] \f[I]path\f[R] +Path of the icon of the application package .RS +.PP +(absolute path or relative to the current directory) .RE .TP -.B \f[CB]\-\-name\f[R] or \f[CB]\-n\f[R] <name> +.B \f[CB]\-\-name\f[R] or \f[CB]\-n\f[R] \f[I]name\f[R] Name of the application and/or package .RS .RE .TP -.B \f[CB]\-\-dest\f[R] or \f[CB]\-d\f[R] <output path> +.B \f[CB]\-\-dest\f[R] or \f[CB]\-d\f[R] \f[I]destination\f[R] Path where generated output file is placed .RS .PP -Defaults to the current working directory. (absolute path or relative to the current directory). +.PP +Defaults to the current working directory. .RE .TP -.B \f[CB]\-\-temp\f[R] <directory path> +.B \f[CB]\-\-temp\f[R] \f[I]directory\f[R] Path of a new or empty directory used to create temporary files -(absolute path or relative to the current directory) .RS .PP +(absolute path or relative to the current directory) +.PP If specified, the temp dir will not be removed upon the task completion and must be removed manually. .PP @@ -119,7 +122,7 @@ If not specified, a temporary directory will be created and removed upon the task completion. .RE .TP -.B \f[CB]\-\-vendor\f[R] <vendor string> +.B \f[CB]\-\-vendor\f[R] \f[I]vendor\f[R] Vendor of the application .RS .RE @@ -135,7 +138,7 @@ Print the product version to the output stream and exit. .RE .SS Options for creating the runtime image: .TP -.B \f[CB]\-\-add\-modules\f[R] <module name> [\f[CB],\f[R]<module name>...] +.B \f[CB]\-\-add\-modules\f[R] \f[I]module\-name\f[R] [\f[CB],\f[R]\f[I]module\-name\f[R]...] A comma (",") separated list of modules to add .RS .PP @@ -148,7 +151,7 @@ specified) are used. This option can be used multiple times. .RE .TP -.B \f[CB]\-\-module\-path\f[R] or \f[CB]\-p\f[R] <module path>... +.B \f[CB]\-\-module\-path\f[R] or \f[CB]\-p\f[R] \f[I]module\-path\f[R] [\f[CB],\f[R]\f[I]module\-path\f[R]...] A File.pathSeparator separated list of paths .RS .PP @@ -158,7 +161,7 @@ and is absolute or relative to the current directory. This option can be used multiple times. .RE .TP -.B \f[CB]\-\-jlink\-options\f[R] <jlink options> +.B \f[CB]\-\-jlink\-options\f[R] \f[I]options\f[R] A space separated list of options to pass to jlink .RS .PP @@ -168,34 +171,48 @@ If not specified, defaults to "\-\-strip\-native\-commands This option can be used multiple times. .RE .TP -.B \f[CB]\-\-runtime\-image\f[R] <directory path> +.B \f[CB]\-\-runtime\-image\f[R] \f[I]directory\f[R] Path of the predefined runtime image that will be copied into the -application image (absolute path or relative to the current directory) +application image .RS .PP +(absolute path or relative to the current directory) +.PP If \-\-runtime\-image is not specified, jpackage will run jlink to create the runtime image using options specified by \-\-jlink\-options. .RE .SS Options for creating the application image: .TP -.B \f[CB]\-\-input\f[R] or \f[CB]\-i\f[R] <input path> +.B \f[CB]\-\-input\f[R] or \f[CB]\-i\f[R] \f[I]directory\f[R] Path of the input directory that contains the files to be packaged -(absolute path or relative to the current directory) .RS .PP +(absolute path or relative to the current directory) +.PP All files in the input directory will be packaged into the application image. .RE +.TP +.B `\-\-app\-content \f[I]additional\-content\f[R][,\f[I]additional\-content\f[R]...] +A comma separated list of paths to files and/or directories to add to +the application payload. +.RS +.PP +This option can be used more than once. +.RE .SS Options for creating the application launcher(s): .TP -.B \f[CB]\-\-add\-launcher\f[R] <launcher name>=<file path> +.B \f[CB]\-\-add\-launcher\f[R] \f[I]name\f[R]=\f[I]path\f[R] Name of launcher, and a path to a Properties file that contains a list -of key, value pairs (absolute path or relative to the current directory) +of key, value pairs .RS .PP +(absolute path or relative to the current directory) +.PP The keys "module", "main\-jar", "main\-class", "arguments", -"java\-options", "app\-version", "icon", "linux\-app\-category", -"linux\-app\-release", and "win\-console" can be used. +"java\-options", "app\-version", "icon", "win\-console", +"win\-shortcut", "win\-menu", "linux\-app\-category", and +"linux\-shortcut", can be used. .PP These options are added to, or used to overwrite, the original command line options to build an additional alternative launcher. @@ -206,7 +223,7 @@ this option can be used multiple times to build multiple additional launchers. .RE .TP -.B \f[CB]\-\-arguments\f[R] <main class arguments> +.B \f[CB]\-\-arguments\f[R] \f[I]arguments\f[R] Command line arguments to pass to the main class if no command line arguments are given to the launcher .RS @@ -214,21 +231,21 @@ arguments are given to the launcher This option can be used multiple times. .RE .TP -.B \f[CB]\-\-java\-options\f[R] <java options> +.B \f[CB]\-\-java\-options\f[R] \f[I]options\f[R] Options to pass to the Java runtime .RS .PP This option can be used multiple times. .RE .TP -.B \f[CB]\-\-main\-class\f[R] <class name> +.B \f[CB]\-\-main\-class\f[R] \f[I]class\-name\f[R] Qualified name of the application main class to execute .RS .PP This option can only be used if \-\-main\-jar is specified. .RE .TP -.B \f[CB]\-\-main\-jar\f[R] <main jar file> +.B \f[CB]\-\-main\-jar\f[R] \f[I]main\-jar\f[R] The main JAR of the application; containing the main class (specified as a path relative to the input path) .RS @@ -236,7 +253,7 @@ a path relative to the input path) Either \-\-module or \-\-main\-jar option can be specified but not both. .RE .TP -.B \f[CB]\-\-module\f[R] or \f[CB]\-m\f[R] <module name>/<main class>] +.B \f[CB]\-\-module\f[R] or \f[CB]\-m\f[R] \f[I]module\-name\f[R][/\f[I]main\-class\f[R]] The main module (and optionally main class) of the application .RS .PP @@ -256,7 +273,7 @@ application which requires console interactions .RE .SS macOS platform options (available only when running on macOS): .TP -.B \f[CB]\-\-mac\-package\-identifier\f[R] <ID string> +.B \f[CB]\-\-mac\-package\-identifier\f[R] \f[I]identifier\f[R] An identifier that uniquely identifies the application for macOS .RS .PP @@ -266,7 +283,7 @@ May only use alphanumeric (A\-Z,a\-z,0\-9), hyphen (\-), and period (.) characters. .RE .TP -.B \f[CB]\-\-mac\-package\-name\f[R] <name string> +.B \f[CB]\-\-mac\-package\-name\f[R] \f[I]name\f[R] Name of the application as it appears in the Menu Bar .RS .PP @@ -277,7 +294,7 @@ displaying in the menu bar and the application Info window. Defaults to the application name. .RE .TP -.B \f[CB]\-\-mac\-package\-signing\-prefix\f[R] <prefix string> +.B \f[CB]\-\-mac\-package\-signing\-prefix\f[R] \f[I]prefix\f[R] When signing the application package, this value is prefixed to all components that need to be signed that don\[aq]t have an existing package identifier. @@ -289,14 +306,14 @@ Request that the bundle be signed. .RS .RE .TP -.B \f[CB]\-\-mac\-signing\-keychain\f[R] <keychain name> +.B \f[CB]\-\-mac\-signing\-keychain\f[R] \f[I]keychain\-name\f[R] Name of the keychain to search for the signing identity .RS .PP If not specified, the standard keychains are used. .RE .TP -.B \f[CB]\-\-mac\-signing\-key\-user\-name\f[R] <team name> +.B \f[CB]\-\-mac\-signing\-key\-user\-name\f[R] \f[I]name\f[R] Team or user name portion in Apple signing identities .RS .RE @@ -306,13 +323,13 @@ Indicates that the jpackage output is intended for the Mac App Store. .RS .RE .TP -.B \f[CB]\-\-mac\-entitlements\f[R] <file path> +.B \f[CB]\-\-mac\-entitlements\f[R] \f[I]path\f[R] Path to file containing entitlements to use when signing executables and libraries in the bundle .RS .RE .TP -.B \f[CB]\-\-mac\-app\-category\f[R] <category string> +.B \f[CB]\-\-mac\-app\-category\f[R] \f[I]category\f[R] String used to construct LSApplicationCategoryType in application plist .RS .PP @@ -320,59 +337,63 @@ The default value is "utilities". .RE .SS Options for creating the application package: .TP -.B \f[CB]\-\-about\-url\f[R] <url> +.B \f[CB]\-\-about\-url\f[R] \f[I]url\f[R] URL of the application\[aq]s home page .RS .RE .TP -.B \f[CB]\-\-app\-image\f[R] <directory path> +.B \f[CB]\-\-app\-image\f[R] \f[I]directory\f[R] Location of the predefined application image that is used to build an installable package .RS .PP -(absolute path or relative to the current directory). +(absolute path or relative to the current directory) .PP See create\-app\-image mode options to create the application image. .RE .TP -.B \f[CB]\-\-file\-associations\f[R] <file path> +.B \f[CB]\-\-file\-associations\f[R] \f[I]path\f[R] Path to a Properties file that contains list of key, value pairs -(absolute path or relative to the current directory) .RS .PP +(absolute path or relative to the current directory) +.PP The keys "extension", "mime\-type", "icon", and "description" can be used to describe the association. .PP This option can be used multiple times. .RE .TP -.B \f[CB]\-\-install\-dir\f[R] <directory path> +.B \f[CB]\-\-install\-dir\f[R] \f[I]path\f[R] Absolute path of the installation directory of the application (on macos or linux), or relative sub\-path of the installation directory such as "Program Files" or "AppData" (on Windows) .RS .RE .TP -.B \f[CB]\-\-license\-file\f[R] <file path> -Path to the license file (absolute path or relative to the current -directory) +.B \f[CB]\-\-license\-file\f[R] \f[I]path\f[R] +Path to the license file .RS +.PP +(absolute path or relative to the current directory) .RE .TP -.B \f[CB]\-\-resource\-dir\f[R] <directory path> -Path to override jpackage resources (absolute path or relative to the -current directory) +.B \f[CB]\-\-resource\-dir\f[R] \f[I]path\f[R] +Path to override jpackage resources .RS .PP +(absolute path or relative to the current directory) +.PP Icons, template files, and other resources of jpackage can be over\-ridden by adding replacement resources to this directory. .RE .TP -.B \f[CB]\-\-runtime\-image\f[R] <directory path> -Path of the predefined runtime image to install (absolute path or -relative to the current directory) +.B \f[CB]\-\-runtime\-image\f[R] \f[I]path\f[R] +Path of the predefined runtime image to install .RS .PP +(absolute path or relative to the current directory) +.PP Option is required when creating a runtime installer. .RE .SS Platform dependent options for creating the application package: @@ -384,7 +405,7 @@ product is installed. .RS .RE .TP -.B \f[CB]\-\-win\-help\-url\f[R] <url> +.B \f[CB]\-\-win\-help\-url\f[R] \f[I]url\f[R] URL where user can obtain further information or technical support .RS .RE @@ -394,7 +415,7 @@ Request to add a Start Menu shortcut for this application .RS .RE .TP -.B \f[CB]\-\-win\-menu\-group\f[R] <menu group name> +.B \f[CB]\-\-win\-menu\-group\f[R] \f[I]menu\-group\-name\f[R] Start Menu group this application is placed in .RS .RE @@ -415,30 +436,30 @@ by installer .RS .RE .TP -.B \f[CB]\-\-win\-update\-url\f[R] <url> +.B \f[CB]\-\-win\-update\-url\f[R] \f[I]url\f[R] URL of available application update information .RS .RE .TP -.B \f[CB]\-\-win\-upgrade\-uuid\f[R] <id string> +.B \f[CB]\-\-win\-upgrade\-uuid\f[R] \f[I]id\f[R] UUID associated with upgrades for this package .RS .RE .SS Linux platform options (available only when running on Linux): .TP -.B \f[CB]\-\-linux\-package\-name\f[R] <package name> +.B \f[CB]\-\-linux\-package\-name\f[R] \f[I]name\f[R] Name for Linux package .RS .PP Defaults to the application name. .RE .TP -.B \f[CB]\-\-linux\-deb\-maintainer\f[R] <email address> +.B \f[CB]\-\-linux\-deb\-maintainer\f[R] \f[I]email\-address\f[R] Maintainer for .deb bundle .RS .RE .TP -.B \f[CB]\-\-linux\-menu\-group\f[R] <menu\-group\-name> +.B \f[CB]\-\-linux\-menu\-group\f[R] \f[I]menu\-group\-name\f[R] Menu group this application is placed in .RS .RE @@ -448,20 +469,19 @@ Required packages or capabilities for the application .RS .RE .TP -.B \f[CB]\-\-linux\-rpm\-license\-type\f[R] <type string> -Type of the license ("License: <value>" of the RPM .spec) +.B \f[CB]\-\-linux\-rpm\-license\-type\f[R] \f[I]type\f[R] +Type of the license ("License: \f[I]value\f[R]" of the RPM .spec) .RS .RE .TP -.B \f[CB]\-\-linux\-app\-release\f[R] <release string> +.B \f[CB]\-\-linux\-app\-release\f[R] \f[I]release\f[R] Release value of the RPM <name>.spec file or Debian revision value of the DEB control file .RS .RE .TP -.B \f[CB]\-\-linux\-app\-category\f[R] <category string> -Group value of the RPM <name>.spec file or Section value of DEB control -file +.B \f[CB]\-\-linux\-app\-category\f[R] \f[I]category\-value\f[R] +Group value of the RPM /.spec file or Section value of DEB control file .RS .RE .TP @@ -469,6 +489,14 @@ file Creates a shortcut for the application. .RS .RE +.SS macOS platform options (available only when running on macOS): +.TP +.B \[aq]\-\-mac\-dmg\-content \f[I]additional\-content\f[R][,\f[I]additional\-content\f[R]...] +Include all the referenced content in the dmg. +.RS +.PP +This option can be used more than once. +.RE .SH JPACKAGE EXAMPLES .IP .nf diff --git a/src/jdk.jpackage/share/native/applauncher/JvmLauncher.cpp b/src/jdk.jpackage/share/native/applauncher/JvmLauncher.cpp index 105b512b260a9544abb2bed34b7341b5946aef3c..db01cd164bc50d0905cc23b59f2ba14d9371d15a 100644 --- a/src/jdk.jpackage/share/native/applauncher/JvmLauncher.cpp +++ b/src/jdk.jpackage/share/native/applauncher/JvmLauncher.cpp @@ -23,6 +23,7 @@ * questions. */ +#include <cstddef> #include <cstring> #include "tstrings.h" #include "JvmLauncher.h" diff --git a/src/jdk.jpackage/windows/native/libwixhelper/libwixhelper.cpp b/src/jdk.jpackage/windows/native/libwixhelper/libwixhelper.cpp index 85e0229bc212f6708b7ca87f4262cdbc819a820a..6588ff05bbc410d0c34bb5cbf1badaf14e26b845 100644 --- a/src/jdk.jpackage/windows/native/libwixhelper/libwixhelper.cpp +++ b/src/jdk.jpackage/windows/native/libwixhelper/libwixhelper.cpp @@ -59,7 +59,7 @@ extern "C" { DWORD cchSize = 0; UINT result = MsiGetProperty(hInstall, TEXT("INSTALLDIR"), - TEXT(""), &cchSize); + (LPTSTR)TEXT(""), &cchSize); if (result == ERROR_MORE_DATA) { cchSize = cchSize + 1; // NULL termination szValue = new TCHAR[cchSize]; diff --git a/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/Feedback.java b/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/Feedback.java index 60a14bddf099ed10eba976e7210edfc22652e570..a6c92b67e9678cc7aa5235cdfb3b09cf426b7571 100644 --- a/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/Feedback.java +++ b/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/Feedback.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -372,7 +372,7 @@ class Feedback { return ""; } Matcher m = FIELD_PATTERN.matcher(format); - StringBuffer sb = new StringBuffer(format.length()); + StringBuilder sb = new StringBuilder(format.length()); while (m.find()) { String fieldName = m.group(1); String sub = format(fieldName, selector); @@ -626,7 +626,7 @@ class Feedback { } /** - * Set mode. Create, changed, or delete a feedback mode. For @{code /set + * Set mode. Create, changed, or delete a feedback mode. For {@code /set * mode <mode> [<old-mode>] [-command|-quiet|-delete|-retain]}. * * @return true if successful diff --git a/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java b/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java index 532454b7cbcc1fa9fd6fe6521876f64a909f84c0..ac78e23eff6565d01c9f9dde51118df57ce4a123 100644 --- a/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java +++ b/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java @@ -254,7 +254,7 @@ public class JShellTool implements MessageHandler { Pattern.compile(OPTION_PRE_PATTERN.pattern() + "(?<dd>-??)(?<flag>-([a-z][a-z\\-]*)?)"); // match an option flag and a (possibly missing or incomplete) value private static final Pattern OPTION_VALUE_PATTERN = - Pattern.compile(OPTION_PATTERN.pattern() + "\\s+(?<val>\\S*)"); + Pattern.compile(OPTION_PATTERN.pattern() + "\\s+(?<val>(\\S|\\\\ )*)"); // Tool id (tid) mapping: the three name spaces NameSpace mainNamespace; @@ -274,6 +274,7 @@ public class JShellTool implements MessageHandler { ADD_EXPORTS("--add-exports", false), ENABLE_PREVIEW("--enable-preview", true), SOURCE_RELEASE("-source", true, true, true, false, false), // virtual option, generated by --enable-preview + ENABLE_NATIVE_ACCESS("--enable-native-access", true, true, false, true, true), TO_COMPILER("-C", false, false, true, false, false), TO_REMOTE_VM("-R", false, false, false, true, false),; final String optionFlag; @@ -363,6 +364,7 @@ public class JShellTool implements MessageHandler { private final OptionSpec<String> argAddModules = parser.accepts("add-modules").withRequiredArg(); private final OptionSpec<String> argAddExports = parser.accepts("add-exports").withRequiredArg(); private final OptionSpecBuilder argEnablePreview = parser.accepts("enable-preview"); + private final OptionSpecBuilder argEnableNativeAccess = parser.accepts("enable-native-access"); private final NonOptionArgumentSpec<String> argNonOptions = parser.nonOptions(); private Options opts = new Options(); @@ -471,6 +473,10 @@ public class JShellTool implements MessageHandler { OptionKind.SOURCE_RELEASE.optionFlag, System.getProperty("java.specification.version"))); } + if (options.has(argEnableNativeAccess)) { + opts.addAll(OptionKind.ENABLE_NATIVE_ACCESS, List.of( + OptionKind.ENABLE_NATIVE_ACCESS.optionFlag, "ALL-UNNAMED")); + } if (failed) { exitCode = 1; @@ -1555,13 +1561,13 @@ public class JShellTool implements MessageHandler { private static CompletionProvider fileCompletions(Predicate<Path> accept) { return (code, cursor, anchor) -> { int lastSlash = code.lastIndexOf('/'); - String path = code.substring(0, lastSlash + 1); - String prefix = lastSlash != (-1) ? code.substring(lastSlash + 1) : code; + String path = code.substring(0, lastSlash + 1).replace("\\ ", " "); + String prefix = (lastSlash != (-1) ? code.substring(lastSlash + 1) : code).replace("\\ ", " "); Path current = toPathResolvingUserHome(path); List<Suggestion> result = new ArrayList<>(); try (Stream<Path> dir = Files.list(current)) { dir.filter(f -> accept.test(f) && f.getFileName().toString().startsWith(prefix)) - .map(f -> new ArgSuggestion(f.getFileName() + (Files.isDirectory(f) ? "/" : ""))) + .map(f -> new ArgSuggestion(f.getFileName().toString().replace(" ", "\\ ") + (Files.isDirectory(f) ? "/" : ""))) .forEach(result::add); } catch (IOException ex) { //ignore... diff --git a/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/Selector.java b/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/Selector.java index 9d5408471487e99aa3811848ec719f2098136c35..aec5116bb2e03ef77731ad390b2825c7cdf1d620 100644 --- a/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/Selector.java +++ b/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/Selector.java @@ -302,7 +302,7 @@ class Selector { <E extends Enum<E> & SelectorInstanceWithDoc<E>> SelectorKind(Class<E> k) { - this.all = EnumSet.allOf(FormatCase.class);; + this.all = EnumSet.allOf(FormatCase.class); this.k = k; } } diff --git a/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/resources/l10n.properties b/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/resources/l10n.properties index dd21e32031786ff6a45939b75d5468339bb4edb4..8606527e557dab5611f17bb7fd197b4292c0d265 100644 --- a/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/resources/l10n.properties +++ b/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/resources/l10n.properties @@ -207,6 +207,8 @@ where possible options include:\n\ \ --add-modules <module>(,<module>)*\n\ \ Specify modules to resolve, or all modules on the\n\ \ module path if <module> is ALL-MODULE-PATHs\n\ +\ --enable-native-access\n\ +\ Allow code to run restricted native methods\n\ \ --enable-preview Allow code to depend on preview features of this release\n\ \ --startup <file> One run replacement for the startup definitions\n\ \ --no-startup Do not run the startup definitions\n\ diff --git a/src/jdk.jshell/share/classes/jdk/jshell/execution/RemoteExecutionControl.java b/src/jdk.jshell/share/classes/jdk/jshell/execution/RemoteExecutionControl.java index 810e80acf47d9ee7857292050297b1ced90567b5..d8818dee5417e1f7b7d24e3f79c91f53663801f9 100644 --- a/src/jdk.jshell/share/classes/jdk/jshell/execution/RemoteExecutionControl.java +++ b/src/jdk.jshell/share/classes/jdk/jshell/execution/RemoteExecutionControl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -63,8 +63,8 @@ public class RemoteExecutionControl extends DirectExecutionControl implements Ex InputStream inStream = socket.getInputStream(); OutputStream outStream = socket.getOutputStream(); Map<String, Consumer<OutputStream>> outputs = new HashMap<>(); - outputs.put("out", st -> System.setOut(new PrintStream(st, true))); - outputs.put("err", st -> System.setErr(new PrintStream(st, true))); + outputs.put("out", st -> System.setOut(new PrintStream(st, true, System.out.charset()))); + outputs.put("err", st -> System.setErr(new PrintStream(st, true, System.err.charset()))); Map<String, Consumer<InputStream>> input = new HashMap<>(); input.put("in", System::setIn); forwardExecutionControlAndIO(new RemoteExecutionControl(), inStream, outStream, outputs, input); diff --git a/src/jdk.jshell/share/man/jshell.1 b/src/jdk.jshell/share/man/jshell.1 index 1865d30f90ac95bde6a6abb759963336b4ecc48e..0eddce3469c645a5ba8d6b9ae7d8d31cb3803785 100644 --- a/src/jdk.jshell/share/man/jshell.1 +++ b/src/jdk.jshell/share/man/jshell.1 @@ -22,7 +22,7 @@ .\"t .\" Automatically generated by Pandoc 2.3.1 .\" -.TH "JSHELL" "1" "2021" "JDK 18\-ea" "JDK Commands" +.TH "JSHELL" "1" "2022" "JDK 19\-ea" "JDK Commands" .hy .SH NAME .PP diff --git a/src/jdk.jstatd/share/classes/sun/tools/jstatd/Jstatd.java b/src/jdk.jstatd/share/classes/sun/tools/jstatd/Jstatd.java index 30fe303fa61c8c337381e8895283ba9a462713fb..5dc7f1fa2fbcec72cb04fb1e24838993ed99394c 100644 --- a/src/jdk.jstatd/share/classes/sun/tools/jstatd/Jstatd.java +++ b/src/jdk.jstatd/share/classes/sun/tools/jstatd/Jstatd.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 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 @@ -25,6 +25,7 @@ package sun.tools.jstatd; +import java.io.ObjectInputFilter; import java.rmi.*; import java.rmi.server.*; import java.rmi.registry.Registry; @@ -47,6 +48,8 @@ public class Jstatd { private static boolean startRegistry = true; private static RemoteHost remoteHost; + private static final String rmiFilterPattern = "sun.jvmstat.monitor.remote.RemoteVm;com.sun.proxy.jdk.proxy*;java.lang.reflect.Proxy;java.rmi.server.RemoteObjectInvocationHandler;java.rmi.server.RemoteObject;!*"; + private static void printUsage() { System.err.println("usage: jstatd [-nr] [-p port] [-r rmiport] [-n rminame]\n" + " jstatd -?|-h|--help"); @@ -72,7 +75,6 @@ public class Jstatd { } } - @SuppressWarnings({"removal","deprecation"}) // Use of RMISecurityManager public static void main(String[] args) { String rminame = null; int rmiPort = 0; @@ -132,10 +134,6 @@ public class Jstatd { System.exit(1); } - if (System.getSecurityManager() == null) { - System.setSecurityManager(new RMISecurityManager()); - } - StringBuilder name = new StringBuilder(); if (port >= 0) { @@ -149,11 +147,10 @@ public class Jstatd { name.append("/").append(rminame); try { - // use 1.5.0 dynamically generated subs. - System.setProperty("java.rmi.server.ignoreSubClasses", "true"); remoteHost = new RemoteHostImpl(rmiPort); + ObjectInputFilter filter = ObjectInputFilter.Config.createFilter(rmiFilterPattern); RemoteHost stub = (RemoteHost) UnicastRemoteObject.exportObject( - remoteHost, rmiPort); + remoteHost, rmiPort, filter); bind(name.toString(), stub); System.out.println("jstatd started (bound to " + name.toString() + ")"); System.out.flush(); diff --git a/src/jdk.jstatd/share/man/jstatd.1 b/src/jdk.jstatd/share/man/jstatd.1 index ccfe6e000aa213fee8fcd06bd6fda180aedb017f..d5181f3668c01525437610ef96a481aedd65d43b 100644 --- a/src/jdk.jstatd/share/man/jstatd.1 +++ b/src/jdk.jstatd/share/man/jstatd.1 @@ -1,4 +1,4 @@ -.\" Copyright (c) 2004, 2020, Oracle and/or its affiliates. All rights reserved. +.\" Copyright (c) 2004, 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 @@ -21,7 +21,7 @@ .\" .\" Automatically generated by Pandoc 2.3.1 .\" -.TH "JSTATD" "1" "2021" "JDK 18\-ea" "JDK Commands" +.TH "JSTATD" "1" "2022" "JDK 19\-ea" "JDK Commands" .hy .SH NAME .PP @@ -120,15 +120,12 @@ local security policies should be considered before you start the \f[CB]jstatd\f[R] process, particularly in production environments or on networks that aren\[aq]t secure. .PP -The \f[CB]jstatd\f[R] server installs an instance of -\f[CB]RMISecurityPolicy\f[R] when no other security manager is installed, -and therefore, requires a security policy file to be specified. -The policy file must conform to Default Policy Implementation and Policy -File Syntax. +For security purposes, the \f[CB]jstatd\f[R] server uses an RMI +ObjectInputFilter to allow only essential classes to be deserialized. .PP -If your security concerns can\[aq]t be addressed with a customized -policy file, then the safest action is to not run the \f[CB]jstatd\f[R] -server and use the \f[CB]jstat\f[R] and \f[CB]jps\f[R] tools locally. +If your security concerns can\[aq]t be addressed, then the safest action +is to not run the \f[CB]jstatd\f[R] server and use the \f[CB]jstat\f[R] and +\f[CB]jps\f[R] tools locally. However, when using \f[CB]jps\f[R] to get a list of instrumented JVMs, the list will not include any JVMs running in docker containers. .SH REMOTE INTERFACE @@ -149,7 +146,7 @@ This example assumes that no other server is bound to the default RMI registry port (port \f[CB]1099\f[R]). .RS .PP -\f[CB]jstatd\ \-J\-Djava.security.policy=all.policy\f[R] +\f[CB]jstatd\f[R] .RE .SH EXTERNAL RMI REGISTRY .PP @@ -159,7 +156,7 @@ registry. .nf \f[CB] rmiregistry& -jstatd\ \-J\-Djava.security.policy=all.policy +jstatd \f[R] .fi .PP @@ -169,7 +166,7 @@ registry server on port \f[CB]2020\f[R]. .nf \f[CB] jrmiregistry\ 2020& -jstatd\ \-J\-Djava.security.policy=all.policy\ \-p\ 2020 +jstatd\ \-p\ 2020 \f[R] .fi .PP @@ -180,7 +177,7 @@ registry server on port \f[CB]2020\f[R] and JMX connector bound to port .nf \f[CB] jrmiregistry\ 2020& -jstatd\ \-J\-Djava.security.policy=all.policy\ \-p\ 2020\ \-r\ 2021 +jstatd\ \-p\ 2020\ \-r\ 2021 \f[R] .fi .PP @@ -191,7 +188,7 @@ registry on port 2020 that\[aq]s bound to .nf \f[CB] rmiregistry\ 2020& -jstatd\ \-J\-Djava.security.policy=all.policy\ \-p\ 2020\ \-n\ AlternateJstatdServerName +jstatd\ \-p\ 2020\ \-n\ AlternateJstatdServerName \f[R] .fi .SH STOP THE CREATION OF AN IN\-PROCESS RMI REGISTRY @@ -203,7 +200,7 @@ If an RMI registry isn\[aq]t running, then an error message is displayed. .RS .PP -\f[CB]jstatd\ \-J\-Djava.security.policy=all.policy\ \-nr\f[R] +\f[CB]jstatd\ \-nr\f[R] .RE .SH ENABLE RMI LOGGING .PP @@ -213,5 +210,5 @@ This technique is useful as a troubleshooting aid or for monitoring server activities. .RS .PP -\f[CB]jstatd\ \-J\-Djava.security.policy=all.policy\ \-J\-Djava.rmi.server.logCalls=true\f[R] +\f[CB]jstatd\ \-J\-Djava.rmi.server.logCalls=true\f[R] .RE diff --git a/src/jdk.management.agent/share/classes/jdk/internal/agent/Agent.java b/src/jdk.management.agent/share/classes/jdk/internal/agent/Agent.java index 06856f972783773c04759623b2f8f6b722576437..175c736e420c795daa088766ff74fc2a68864aec 100644 --- a/src/jdk.management.agent/share/classes/jdk/internal/agent/Agent.java +++ b/src/jdk.management.agent/share/classes/jdk/internal/agent/Agent.java @@ -51,7 +51,6 @@ import javax.management.remote.JMXConnectorServer; import javax.management.remote.JMXServiceURL; import static jdk.internal.agent.AgentConfigurationError.*; -import jdk.internal.agent.spi.AgentProvider; import jdk.internal.vm.VMSupport; import sun.management.jdp.JdpController; import sun.management.jdp.JdpException; @@ -564,8 +563,7 @@ public class Agent { InputStream in = null; try { in = new FileInputStream(configFile); - BufferedInputStream bin = new BufferedInputStream(in); - p.load(bin); + p.load(in); } catch (FileNotFoundException e) { error(CONFIG_FILE_OPEN_FAILED, e.getMessage()); } catch (IOException e) { diff --git a/src/jdk.management.agent/share/classes/jdk/internal/agent/spi/AgentProvider.java b/src/jdk.management.agent/share/classes/jdk/internal/agent/spi/AgentProvider.java deleted file mode 100644 index ea42d5974862d487509a0a7d6e2fda1f4b688cab..0000000000000000000000000000000000000000 --- a/src/jdk.management.agent/share/classes/jdk/internal/agent/spi/AgentProvider.java +++ /dev/null @@ -1,93 +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. 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.agent.spi; - -import java.util.Properties; - -/** - * Service interface for management agent - */ -public abstract class AgentProvider { - - /** - * Instantiates a new AgentProvider. - * - * @throws SecurityException if the subclass (and calling code) does not - * have - * {@code RuntimePermission("sun.management.spi.AgentProvider.subclass")} - */ - protected AgentProvider() { - this(checkSubclassPermission()); - } - - private AgentProvider(Void unused) { - } - - private static Void checkSubclassPermission() { - @SuppressWarnings("removal") - SecurityManager sm = System.getSecurityManager(); - if (sm != null) { - sm.checkPermission(new RuntimePermission(AgentProvider.class.getName() + ".subclass")); - } - return null; - } - - /** - * Gets the name of the agent provider. - * - * @return name of agent provider - */ - public abstract String getName(); - - /** - * Initializes and starts the agent. - * - * @throws IllegalStateException if this agent has already been started. - */ - public abstract void startAgent(); - - /** - * Initializes and starts the agent at given port and with given properties - * - * @param props environment variables for agent - * - * @throws IllegalStateException if this agent has already been started. - */ - public abstract void startAgent(Properties props); - - /** - * Checks if agent is started and not terminated. - * - * @return true if agent is running, false otherwise. - */ - public abstract boolean isActive(); - - /** - * Stops this agent. - * - * @throws IllegalStateException if this agent is not started. - */ - public abstract void stopAgent(); -} diff --git a/src/jdk.management.agent/share/classes/module-info.java b/src/jdk.management.agent/share/classes/module-info.java index 921744822b61197d23c6f0438df741d7f0fccaac..9688e22b9f9740eb4b3df2e38381a03edfc156cb 100644 --- a/src/jdk.management.agent/share/classes/module-info.java +++ b/src/jdk.management.agent/share/classes/module-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -39,6 +39,4 @@ module jdk.management.agent { requires java.management.rmi; exports jdk.internal.agent to jdk.jconsole; - - uses jdk.internal.agent.spi.AgentProvider; } diff --git a/src/jdk.management.agent/share/classes/sun/management/jmxremote/ConnectorBootstrap.java b/src/jdk.management.agent/share/classes/sun/management/jmxremote/ConnectorBootstrap.java index 6630124f374c3c6d85b31dcd50f4920afbedd2b8..aaa32944ddff771e2199c15b8355111742e97920 100644 --- a/src/jdk.management.agent/share/classes/sun/management/jmxremote/ConnectorBootstrap.java +++ b/src/jdk.management.agent/share/classes/sun/management/jmxremote/ConnectorBootstrap.java @@ -692,8 +692,7 @@ public final class ConnectorBootstrap { // Load the SSL keystore properties from the config file Properties p = new Properties(); try (InputStream in = new FileInputStream(sslConfigFileName)) { - BufferedInputStream bin = new BufferedInputStream(in); - p.load(bin); + p.load(in); } String keyStore = p.getProperty("javax.net.ssl.keyStore"); diff --git a/src/jdk.management.jfr/share/classes/jdk/management/jfr/DiskRepository.java b/src/jdk.management.jfr/share/classes/jdk/management/jfr/DiskRepository.java index 7ce5f9c93602e0b7e3a637018c847c42a33371be..d8ff2debe9ef92b550edebb9d3d046fbeadd8d66 100644 --- a/src/jdk.management.jfr/share/classes/jdk/management/jfr/DiskRepository.java +++ b/src/jdk.management.jfr/share/classes/jdk/management/jfr/DiskRepository.java @@ -179,7 +179,7 @@ final class DiskRepository implements Closeable { bufferIndex = 0; break; case CHECKPOINT_EVENT_HEADER_BYTE_ARRAY_CONTENT: - processCheckPointHeader(); + processCheckpointHeader(); break; case CHECKPOINT_EVENT_FLUSH_TYPE: processFlush(); @@ -286,10 +286,10 @@ final class DiskRepository implements Closeable { } } - private void processCheckPointHeader() throws IOException { + private void processCheckpointHeader() throws IOException { buffer.put(bufferIndex, nextByte(true)); if (bufferIndex == HEADER_SIZE) { - writeCheckPointHeader(); + writeCheckpointHeader(); state = State.EVENT_PAYLOAD; bufferIndex = 0; } @@ -321,7 +321,7 @@ final class DiskRepository implements Closeable { } } - private void writeCheckPointHeader() throws IOException { + private void writeCheckpointHeader() throws IOException { Objects.requireNonNull(raf); byte state = buffer.get(HEADER_FILE_STATE_POSITION); boolean complete = state == COMPLETE_STATE; diff --git a/src/jdk.management.jfr/share/classes/jdk/management/jfr/FlightRecorderMXBeanImpl.java b/src/jdk.management.jfr/share/classes/jdk/management/jfr/FlightRecorderMXBeanImpl.java index be71c5113b849c0180d17be469eeec56194e7434..11afb8310cab9b918e5ab1353ea685f51d76183e 100644 --- a/src/jdk.management.jfr/share/classes/jdk/management/jfr/FlightRecorderMXBeanImpl.java +++ b/src/jdk.management.jfr/share/classes/jdk/management/jfr/FlightRecorderMXBeanImpl.java @@ -215,10 +215,10 @@ final class FlightRecorderMXBeanImpl extends StandardEmitterMBean implements Fli } @Override - public void setRecordingSettings(long recording, Map<String, String> values) throws IllegalArgumentException { - Objects.requireNonNull(values); + public void setRecordingSettings(long recording, Map<String, String> settings) throws IllegalArgumentException { + Objects.requireNonNull(settings, "settings"); MBeanUtils.checkControl(); - getExistingRecording(recording).setSettings(values); + getExistingRecording(recording).setSettings(settings); } @SuppressWarnings("removal") @@ -241,11 +241,11 @@ final class FlightRecorderMXBeanImpl extends StandardEmitterMBean implements Fli } @Override - public void setConfiguration(long recording, String configuration) throws IllegalArgumentException { - Objects.requireNonNull(configuration); + public void setConfiguration(long recording, String contents) throws IllegalArgumentException { + Objects.requireNonNull(contents, "contents"); MBeanUtils.checkControl(); try { - Configuration c = Configuration.create(new StringReader(configuration)); + Configuration c = Configuration.create(new StringReader(contents)); getExistingRecording(recording).setSettings(c.getSettings()); } catch (IOException | ParseException e) { throw new IllegalArgumentException("Could not parse configuration", e); @@ -254,7 +254,7 @@ final class FlightRecorderMXBeanImpl extends StandardEmitterMBean implements Fli @Override public void setPredefinedConfiguration(long recording, String configurationName) throws IllegalArgumentException { - Objects.requireNonNull(configurationName); + Objects.requireNonNull(configurationName, "configurationName"); MBeanUtils.checkControl(); Recording r = getExistingRecording(recording); for (Configuration c : Configuration.getConfigurations()) { @@ -267,15 +267,15 @@ final class FlightRecorderMXBeanImpl extends StandardEmitterMBean implements Fli } @Override - public void copyTo(long recording, String path) throws IOException { - Objects.requireNonNull(path); + public void copyTo(long recording, String outputFile) throws IOException { + Objects.requireNonNull(outputFile, "outputFile"); MBeanUtils.checkControl(); - getExistingRecording(recording).dump(Paths.get(path)); + getExistingRecording(recording).dump(Paths.get(outputFile)); } @Override public void setRecordingOptions(long recording, Map<String, String> options) throws IllegalArgumentException { - Objects.requireNonNull(options); + Objects.requireNonNull(options, "options"); MBeanUtils.checkControl(); // Make local copy to prevent concurrent modification Map<String, String> ops = new HashMap<String, String>(options); diff --git a/src/jdk.management.jfr/share/classes/jdk/management/jfr/RecordingInfo.java b/src/jdk.management.jfr/share/classes/jdk/management/jfr/RecordingInfo.java index 16a710ee14aec6ba1404406f3a7e244f5f439f8b..8d2f1e061ccdc34bbef21c419fd31762963962db 100644 --- a/src/jdk.management.jfr/share/classes/jdk/management/jfr/RecordingInfo.java +++ b/src/jdk.management.jfr/share/classes/jdk/management/jfr/RecordingInfo.java @@ -300,10 +300,10 @@ public final class RecordingInfo { /** * Returns the desired duration, measured in seconds, of the recording - * associated with this {@link RecordingInfo}, or {code 0} if no duration + * associated with this {@link RecordingInfo}, or {@code 0} if no duration * has been set. * - * @return the desired duration, or {code 0} if no duration has been set + * @return the desired duration, or {@code 0} if no duration has been set * * @see Recording#getDuration() */ diff --git a/src/jdk.management/share/native/libmanagement_ext/DiagnosticCommandImpl.c b/src/jdk.management/share/native/libmanagement_ext/DiagnosticCommandImpl.c index b94c60589c93aef9bbed1cdf221b86c7ce6ff24a..021fd7c2db63a2dc080ace90c200769a78bc30d1 100644 --- a/src/jdk.management/share/native/libmanagement_ext/DiagnosticCommandImpl.c +++ b/src/jdk.management/share/native/libmanagement_ext/DiagnosticCommandImpl.c @@ -79,7 +79,7 @@ jobject getDiagnosticCommandArgumentInfoArray(JNIEnv *env, jstring command, return NULL; } jmm_interface->GetDiagnosticCommandArgumentsInfo(env, command, - dcmd_arg_info_array); + dcmd_arg_info_array, num_arg); dcmdArgInfoCls = (*env)->FindClass(env, "com/sun/management/internal/DiagnosticCommandArgumentInfo"); POP_EXCEPTION_CHECK_AND_FREE(0, dcmd_arg_info_array); 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 ed4f2d8a1054a101da37b7edd6a70d6786878ce5..7083b4cd1158315b9d1758a43eb2473aedefc78d 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, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -26,10 +26,12 @@ package com.sun.jndi.dns; import java.io.IOException; +import java.io.UncheckedIOException; import java.net.DatagramSocket; import java.net.DatagramPacket; import java.net.InetAddress; import java.net.InetSocketAddress; +import java.net.PortUnreachableException; import java.net.Socket; import java.net.SocketTimeoutException; import java.security.SecureRandom; @@ -148,7 +150,7 @@ public class DnsClient { } } - @SuppressWarnings("deprecation") + @SuppressWarnings("removal") protected void finalize() { close(); } @@ -275,7 +277,16 @@ public class DnsClient { } // servers } return new ResourceRecords(msg, msg.length, hdr, false); - + } catch (UncheckedIOException | PortUnreachableException ex) { + // DatagramSocket.connect in doUdpQuery can throw UncheckedIOException + // DatagramSocket.send in doUdpQuery can throw PortUnreachableException + if (debug) { + dprint("Caught Exception:" + ex); + } + if (caughtException == null) { + caughtException = ex; + } + doNotRetry[i] = true; } catch (IOException e) { if (debug) { dprint("Caught IOException:" + e); @@ -283,12 +294,6 @@ public class DnsClient { if (caughtException == null) { caughtException = e; } - // Use reflection to allow pre-1.4 compilation. - // This won't be needed much longer. - if (e.getClass().getName().equals( - "java.net.PortUnreachableException")) { - doNotRetry[i] = true; - } } catch (NameNotFoundException e) { // This is authoritative, so return immediately throw e; diff --git a/src/jdk.naming.rmi/share/classes/com/sun/jndi/rmi/registry/RegistryContext.java b/src/jdk.naming.rmi/share/classes/com/sun/jndi/rmi/registry/RegistryContext.java index bea428a60680661ab181d889893ec67a3874d606..d77055d280876bcba0c42636b31bfd88b5ca3e3a 100644 --- a/src/jdk.naming.rmi/share/classes/com/sun/jndi/rmi/registry/RegistryContext.java +++ b/src/jdk.naming.rmi/share/classes/com/sun/jndi/rmi/registry/RegistryContext.java @@ -120,7 +120,7 @@ public class RegistryContext implements Context, Referenceable { reference = ctx.reference; } - @SuppressWarnings("deprecation") + @SuppressWarnings("removal") protected void finalize() { close(); } @@ -596,7 +596,7 @@ class BindingEnumeration implements NamingEnumeration<Binding> { nextName = 0; } - @SuppressWarnings("deprecation") + @SuppressWarnings("removal") protected void finalize() { ctx.close(); } diff --git a/src/jdk.random/share/classes/jdk/random/L128X1024MixRandom.java b/src/jdk.random/share/classes/jdk/random/L128X1024MixRandom.java index a612233f2ca63fe4eb7e7f91220293d4417bfc0a..46f8a642d54ad93765da2558ea1bcb8667320c6a 100644 --- a/src/jdk.random/share/classes/jdk/random/L128X1024MixRandom.java +++ b/src/jdk.random/share/classes/jdk/random/L128X1024MixRandom.java @@ -323,17 +323,7 @@ public final class L128X1024MixRandom extends AbstractSplittableWithBrineGenerat // Update the LCG subgenerator // The LCG is, in effect, s = ((1LL << 64) + ML) * s + a, if only we had 128-bit arithmetic. final long u = ML * sl; - - // Note that Math.multiplyHigh computes the high half of the product of signed values, - // but what we need is the high half of the product of unsigned values; for this we use the - // formula "unsignedMultiplyHigh(a, b) = multiplyHigh(a, b) + ((a >> 63) & b) + ((b >> 63) & a)"; - // in effect, each operand is added to the result iff the sign bit of the other operand is 1. - // (See Henry S. Warren, Jr., _Hacker's Delight_ (Second Edition), Addison-Wesley (2013), - // Section 8-3, p. 175; or see the First Edition, Addison-Wesley (2003), Section 8-3, p. 133.) - // If Math.unsignedMultiplyHigh(long, long) is ever implemented, the following line can become: - // sh = (ML * sh) + Math.unsignedMultiplyHigh(ML, sl) + sl + ah; - // and this entire comment can be deleted. - sh = (ML * sh) + (Math.multiplyHigh(ML, sl) + ((ML >> 63) & sl) + ((sl >> 63) & ML)) + sl + ah; + sh = (ML * sh) + Math.unsignedMultiplyHigh(ML, sl) + sl + ah; sl = u + al; if (Long.compareUnsigned(sl, u) < 0) ++sh; // Handle the carry propagation from low half to high half. diff --git a/src/jdk.random/share/classes/jdk/random/L128X128MixRandom.java b/src/jdk.random/share/classes/jdk/random/L128X128MixRandom.java index 1b7d25850a65c81a8cf5e66282025afd6fa5ae65..ac12b96b4d227a34c1ccb87f8247d8550c455386 100644 --- a/src/jdk.random/share/classes/jdk/random/L128X128MixRandom.java +++ b/src/jdk.random/share/classes/jdk/random/L128X128MixRandom.java @@ -248,16 +248,7 @@ public final class L128X128MixRandom extends AbstractSplittableWithBrineGenerato // Update the LCG subgenerator // The LCG is, in effect, s = ((1LL << 64) + ML) * s + a, if only we had 128-bit arithmetic. final long u = ML * sl; - // Note that Math.multiplyHigh computes the high half of the product of signed values, - // but what we need is the high half of the product of unsigned values; for this we use the - // formula "unsignedMultiplyHigh(a, b) = multiplyHigh(a, b) + ((a >> 63) & b) + ((b >> 63) & a)"; - // in effect, each operand is added to the result iff the sign bit of the other operand is 1. - // (See Henry S. Warren, Jr., _Hacker's Delight_ (Second Edition), Addison-Wesley (2013), - // Section 8-3, p. 175; or see the First Edition, Addison-Wesley (2003), Section 8-3, p. 133.) - // If Math.unsignedMultiplyHigh(long, long) is ever implemented, the following line can become: - // sh = (ML * sh) + Math.unsignedMultiplyHigh(ML, sl) + sl + ah; - // and this entire comment can be deleted. - sh = (ML * sh) + (Math.multiplyHigh(ML, sl) + ((ML >> 63) & sl) + ((sl >> 63) & ML)) + sl + ah; + sh = (ML * sh) + Math.unsignedMultiplyHigh(ML, sl) + sl + ah; sl = u + al; if (Long.compareUnsigned(sl, u) < 0) ++sh; // Handle the carry propagation from low half to high half. diff --git a/src/jdk.random/share/classes/jdk/random/L128X256MixRandom.java b/src/jdk.random/share/classes/jdk/random/L128X256MixRandom.java index dad792d8c94f6fb3a8331d2e09a9356e80ed9f68..024d8525b3f7a131eee47bab786f40c188a616dd 100644 --- a/src/jdk.random/share/classes/jdk/random/L128X256MixRandom.java +++ b/src/jdk.random/share/classes/jdk/random/L128X256MixRandom.java @@ -269,16 +269,7 @@ public final class L128X256MixRandom extends AbstractSplittableWithBrineGenerato // Update the LCG subgenerator // The LCG is, in effect, s = ((1LL << 64) + ML) * s + a, if only we had 128-bit arithmetic. final long u = ML * sl; - // Note that Math.multiplyHigh computes the high half of the product of signed values, - // but what we need is the high half of the product of unsigned values; for this we use the - // formula "unsignedMultiplyHigh(a, b) = multiplyHigh(a, b) + ((a >> 63) & b) + ((b >> 63) & a)"; - // in effect, each operand is added to the result iff the sign bit of the other operand is 1. - // (See Henry S. Warren, Jr., _Hacker's Delight_ (Second Edition), Addison-Wesley (2013), - // Section 8-3, p. 175; or see the First Edition, Addison-Wesley (2003), Section 8-3, p. 133.) - // If Math.unsignedMultiplyHigh(long, long) is ever implemented, the following line can become: - // sh = (ML * sh) + Math.unsignedMultiplyHigh(ML, sl) + sl + ah; - // and this entire comment can be deleted. - sh = (ML * sh) + (Math.multiplyHigh(ML, sl) + ((ML >> 63) & sl) + ((sl >> 63) & ML)) + sl + ah; + sh = (ML * sh) + Math.unsignedMultiplyHigh(ML, sl) + sl + ah; sl = u + al; if (Long.compareUnsigned(sl, u) < 0) ++sh; // Handle the carry propagation from low half to high half. diff --git a/src/jdk.random/share/classes/jdk/random/L32X64MixRandom.java b/src/jdk.random/share/classes/jdk/random/L32X64MixRandom.java index 1cb222e9cca93db7e9df4445357110c0857abeb2..1b64a4b28cd9292c07faf74e10f2421b158f15e4 100644 --- a/src/jdk.random/share/classes/jdk/random/L32X64MixRandom.java +++ b/src/jdk.random/share/classes/jdk/random/L32X64MixRandom.java @@ -155,6 +155,8 @@ public final class L32X64MixRandom extends AbstractSplittableWithBrineGenerator // Force a to be odd. this.a = a | 1; this.s = s; + this.x0 = x0; + this.x1 = x1; // If x0 and x1 are both zero, we must choose nonzero values. if ((x0 | x1) == 0) { int v = s; diff --git a/src/jdk.security.auth/share/classes/com/sun/security/auth/module/KeyStoreLoginModule.java b/src/jdk.security.auth/share/classes/com/sun/security/auth/module/KeyStoreLoginModule.java index 44692bdd21959169196e3b3c8a4a4bd97f5ef268..a399447405013592703d0b01af25121178375518 100644 --- a/src/jdk.security.auth/share/classes/com/sun/security/auth/module/KeyStoreLoginModule.java +++ b/src/jdk.security.auth/share/classes/com/sun/security/auth/module/KeyStoreLoginModule.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -712,7 +712,7 @@ public class KeyStoreLoginModule implements LoginModule { * {@code login} method), then this method associates a * {@code X500Principal} for the subject distinguished name of the * first certificate in the alias's credentials in the subject's - * principals,the alias's certificate path in the subject's public + * principals, the alias's certificate path in the subject's public * credentials, and a {@code X500PrivateCredential} whose certificate * is the first certificate in the alias's certificate path and whose * private key is the alias's private key in the subject's private diff --git a/src/jdk.security.jgss/share/classes/com/sun/security/sasl/gsskerb/GssKrb5Base.java b/src/jdk.security.jgss/share/classes/com/sun/security/sasl/gsskerb/GssKrb5Base.java index 04cc61a5d2e45e29c9eddf9bb4f2f9240f11ead3..afdb7279c170e158fe2f640dc88f2473ca915a3e 100644 --- a/src/jdk.security.jgss/share/classes/com/sun/security/sasl/gsskerb/GssKrb5Base.java +++ b/src/jdk.security.jgss/share/classes/com/sun/security/sasl/gsskerb/GssKrb5Base.java @@ -162,7 +162,7 @@ abstract class GssKrb5Base extends AbstractSaslImpl { } } - @SuppressWarnings("deprecation") + @SuppressWarnings("removal") protected void finalize() throws Throwable { dispose(); } diff --git a/src/jdk.unsupported/share/classes/sun/misc/Unsafe.java b/src/jdk.unsupported/share/classes/sun/misc/Unsafe.java index e0ab5f3dffad290fa3d0d94d39b35b08fc6067d8..2f8d397c6c99baba3aef8341a694491c0517303b 100644 --- a/src/jdk.unsupported/share/classes/sun/misc/Unsafe.java +++ b/src/jdk.unsupported/share/classes/sun/misc/Unsafe.java @@ -633,8 +633,15 @@ public final class Unsafe { * the field locations in a form usable by {@link #getInt(Object,long)}. * Therefore, code which will be ported to such JVMs on 64-bit platforms * must preserve all bits of static field offsets. + * + * @deprecated The guarantee that a field will always have the same offset + * and base may not be true in a future release. The ability to provide an + * offset and object reference to a heap memory accessor will be removed + * in a future release. Use {@link java.lang.invoke.VarHandle} instead. + * * @see #getInt(Object, long) */ + @Deprecated(since="18") @ForceInline public long objectFieldOffset(Field f) { if (f == null) { @@ -665,8 +672,15 @@ public final class Unsafe { * a few bits to encode an offset within a non-array object, * However, for consistency with other methods in this class, * this method reports its result as a long value. + * + * @deprecated The guarantee that a field will always have the same offset + * and base may not be true in a future release. The ability to provide an + * offset and object reference to a heap memory accessor will be removed + * in a future release. Use {@link java.lang.invoke.VarHandle} instead. + * * @see #getInt(Object, long) */ + @Deprecated(since="18") @ForceInline public long staticFieldOffset(Field f) { if (f == null) { @@ -691,7 +705,13 @@ public final class Unsafe { * which is a "cookie", not guaranteed to be a real Object, and it should * not be used in any way except as argument to the get and put routines in * this class. + * + * @deprecated The guarantee that a field will always have the same offset + * and base may not be true in a future release. The ability to provide an + * offset and object reference to a heap memory accessor will be removed + * in a future release. Use {@link java.lang.invoke.VarHandle} instead. */ + @Deprecated(since="18") @ForceInline public Object staticFieldBase(Field f) { if (f == null) { diff --git a/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipFileSystem.java b/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipFileSystem.java index 4f9b4e427bc57a30b33b5e01c2dcadd49598b13a..dd85df4cc609e83c1a78c6cfaa41200f1d99a611 100644 --- a/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipFileSystem.java +++ b/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipFileSystem.java @@ -1219,7 +1219,7 @@ class ZipFileSystem extends FileSystem { return zc.toString(name); } - @SuppressWarnings("deprecation") + @SuppressWarnings("removal") protected void finalize() throws IOException { close(); } @@ -1471,6 +1471,13 @@ class ZipFileSystem extends FileSystem { }; } + /** + * Package-private accessor to entry alias map used by ZipPath. + */ + byte[] lookupPath(byte[] resolvedPath) { + return entryLookup.apply(resolvedPath); + } + /** * Create a sorted version map of version -> inode, for inodes <= max version. * 9 -> META-INF/versions/9 diff --git a/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipPath.java b/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipPath.java index 5cccce8d113e3b017536bdaaa0807ef5481bb775..234c54f5d0287954f8f8d1be31ecdb998ed811c1 100644 --- a/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipPath.java +++ b/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipPath.java @@ -200,13 +200,19 @@ final class ZipPath implements Path { return new URI("jar", decodeUri(zfs.getZipFile().toUri().toString()) + "!" + - zfs.getString(toAbsolutePath().path), + getRealPath(), null); } catch (Exception ex) { throw new AssertionError(ex); } } + private String getRealPath() { + byte[] resolvedPath = getResolvedPath(); + byte[] realPath = zfs.lookupPath(resolvedPath); + return zfs.getString(realPath != null ? realPath : resolvedPath); + } + private boolean equalsNameAt(ZipPath other, int index) { int mbegin = offsets[index]; int mlen; diff --git a/src/utils/IdealGraphVisualizer/.java-version b/src/utils/IdealGraphVisualizer/.java-version new file mode 100644 index 0000000000000000000000000000000000000000..60d3b2f4a4cd5f1637eba020358bfe5ecb5edcf2 --- /dev/null +++ b/src/utils/IdealGraphVisualizer/.java-version @@ -0,0 +1 @@ +15 diff --git a/src/utils/IdealGraphVisualizer/BatikSVGProxy/pom.xml b/src/utils/IdealGraphVisualizer/BatikSVGProxy/pom.xml deleted file mode 100644 index dccb16b356b9564407a46d198bb45c6f8fdd8499..0000000000000000000000000000000000000000 --- a/src/utils/IdealGraphVisualizer/BatikSVGProxy/pom.xml +++ /dev/null @@ -1,85 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. - - 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. - - - Neither the name of Oracle nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - 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. ---> - -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - <modelVersion>4.0.0</modelVersion> - <parent> - <artifactId>IdealGraphVisualizer-parent</artifactId> - <groupId>com.sun.hotspot.igv</groupId> - <version>1.0-SNAPSHOT</version> - </parent> - <groupId>com.sun.hotspot.igv</groupId> - <artifactId>BatikSVGProxy</artifactId> - <version>1.0-SNAPSHOT</version> - <packaging>nbm</packaging> - <name>BatikSVGProxy</name> - <properties> - <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> - </properties> - <dependencies> - </dependencies> - <build> - <plugins> - <plugin> - <groupId>org.apache.netbeans.utilities</groupId> - <artifactId>nbm-maven-plugin</artifactId> - <version>${nbmmvnplugin.version}</version> - <extensions>true</extensions> - <configuration> - <publicPackages> - <publicPackage>com.sun.hotspot.igv.svg</publicPackage> - </publicPackages> - </configuration> - </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-compiler-plugin</artifactId> - <version>${mvncompilerplugin.version}</version> - <configuration> - <source>1.8</source> - <target>1.8</target> - </configuration> - </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-jar-plugin</artifactId> - <version>${mvnjarplugin.version}</version> - <configuration> - <!-- to have the jar plugin pickup the nbm generated manifest --> - <archive> - <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile> - </archive> - </configuration> - </plugin> - </plugins> - </build> -</project> diff --git a/src/utils/IdealGraphVisualizer/BatikSVGProxy/src/main/java/com/sun/hotspot/igv/svg/BatikSVG.java b/src/utils/IdealGraphVisualizer/BatikSVGProxy/src/main/java/com/sun/hotspot/igv/svg/BatikSVG.java deleted file mode 100644 index 8c3d92dc0642ec5a8525338e298fe7cc3e4cb80a..0000000000000000000000000000000000000000 --- a/src/utils/IdealGraphVisualizer/BatikSVGProxy/src/main/java/com/sun/hotspot/igv/svg/BatikSVG.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (c) 2008, 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. - * - */ -package com.sun.hotspot.igv.svg; - -import java.awt.Graphics2D; -import java.io.Writer; -import java.io.File; -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLClassLoader; -import org.w3c.dom.DOMImplementation; - -/** - * Utility class - * @author Thomas Wuerthinger - */ -public class BatikSVG { - - private BatikSVG() { - } - - private static Constructor SVGGraphics2DConstructor; - private static Method streamMethod; - private static Method createDefaultMethod; - private static Method getDOMImplementationMethod; - private static Method setEmbeddedFontsOnMethod; - private static Class<?> classSVGGraphics2D; - - /** - * Creates a graphics object that allows to be exported to SVG data using the {@link #printToStream(Graphics2D, Writer, boolean) printToStream} method. - * @return the newly created Graphics2D object or null if the library does not exist - */ - public static Graphics2D createGraphicsObject() { - try { - if (SVGGraphics2DConstructor == null) { - String batikJar = System.getenv().get("IGV_BATIK_JAR"); - if (batikJar == null) { - return null; - } - // Load batik in it's own class loader since some it's support jars interfere with the JDK - URL url = new File(batikJar).toURI().toURL(); - ClassLoader cl = new URLClassLoader(new URL[] { url }); - Class<?> classGenericDOMImplementation = cl.loadClass("org.apache.batik.dom.GenericDOMImplementation"); - Class<?> classSVGGeneratorContext = cl.loadClass("org.apache.batik.svggen.SVGGeneratorContext"); - classSVGGraphics2D = cl.loadClass("org.apache.batik.svggen.SVGGraphics2D"); - getDOMImplementationMethod = classGenericDOMImplementation.getDeclaredMethod("getDOMImplementation", new Class[0]); - createDefaultMethod = classSVGGeneratorContext.getDeclaredMethod("createDefault", new Class[]{org.w3c.dom.Document.class}); - setEmbeddedFontsOnMethod = classSVGGeneratorContext.getDeclaredMethod("setEmbeddedFontsOn", new Class[]{boolean.class}); - streamMethod = classSVGGraphics2D.getDeclaredMethod("stream", Writer.class, boolean.class); - SVGGraphics2DConstructor = classSVGGraphics2D.getConstructor(classSVGGeneratorContext, boolean.class); - } - DOMImplementation dom = (DOMImplementation) getDOMImplementationMethod.invoke(null); - org.w3c.dom.Document document = dom.createDocument("http://www.w3.org/2000/svg", "svg", null); - Object ctx = createDefaultMethod.invoke(null, document); - setEmbeddedFontsOnMethod.invoke(ctx, true); - Graphics2D svgGenerator = (Graphics2D) SVGGraphics2DConstructor.newInstance(ctx, true); - return svgGenerator; - } catch (ClassNotFoundException e) { - return null; - } catch (NoSuchMethodException e) { - return null; - } catch (IllegalAccessException e) { - return null; - } catch (InvocationTargetException e) { - return null; - } catch (InstantiationException e) { - return null; - } catch (MalformedURLException e) { - return null; - } - } - - /** - * Serializes a graphics object to a stream in SVG format. - * @param svgGenerator the graphics object. Only graphics objects created by the {@link #createGraphicsObject() createGraphicsObject} method are valid. - * @param stream the stream to which the data is written - * @param useCSS whether to use CSS styles in the SVG output - */ - public static void printToStream(Graphics2D svgGenerator, Writer stream, boolean useCSS) { - assert classSVGGraphics2D != null; - assert classSVGGraphics2D.isInstance(svgGenerator); - try { - streamMethod.invoke(svgGenerator, stream, useCSS); - } catch (IllegalAccessException e) { - assert false; - } catch (InvocationTargetException e) { - assert false; - } - } -} diff --git a/src/utils/IdealGraphVisualizer/BatikSVGProxy/src/main/nbm/manifest.mf b/src/utils/IdealGraphVisualizer/BatikSVGProxy/src/main/nbm/manifest.mf deleted file mode 100644 index 175014d653e04296c592e979574aa9a6106b25a1..0000000000000000000000000000000000000000 --- a/src/utils/IdealGraphVisualizer/BatikSVGProxy/src/main/nbm/manifest.mf +++ /dev/null @@ -1,5 +0,0 @@ -Manifest-Version: 1.0 -OpenIDE-Module: com.sun.hotspot.igv.svg -OpenIDE-Module-Localizing-Bundle: com/sun/hotspot/igv/svg/Bundle.properties -OpenIDE-Module-Specification-Version: 1.0 - diff --git a/src/utils/IdealGraphVisualizer/BatikSVGProxy/src/main/resources/com/sun/hotspot/igv/svg/Bundle.properties b/src/utils/IdealGraphVisualizer/BatikSVGProxy/src/main/resources/com/sun/hotspot/igv/svg/Bundle.properties deleted file mode 100644 index e579912925b2e5fcefa7760785bcb5ad974985a5..0000000000000000000000000000000000000000 --- a/src/utils/IdealGraphVisualizer/BatikSVGProxy/src/main/resources/com/sun/hotspot/igv/svg/Bundle.properties +++ /dev/null @@ -1 +0,0 @@ -OpenIDE-Module-Name=BatikSVGProxy diff --git a/src/utils/IdealGraphVisualizer/Bytecodes/pom.xml b/src/utils/IdealGraphVisualizer/Bytecodes/pom.xml index 188537f81d6efdf3605da92463fffd2fcaf0d8d4..e87ad7fb5099876d51ff073cab63cb6bd62953a1 100644 --- a/src/utils/IdealGraphVisualizer/Bytecodes/pom.xml +++ b/src/utils/IdealGraphVisualizer/Bytecodes/pom.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions @@ -125,6 +125,10 @@ </archive> </configuration> </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-enforcer-plugin</artifactId> + </plugin> </plugins> </build> </project> diff --git a/src/utils/IdealGraphVisualizer/ControlFlow/pom.xml b/src/utils/IdealGraphVisualizer/ControlFlow/pom.xml index 491a1ae504b8e2814f15f750a2814ff249bbd396..9b77a418dd205ad7f6a1595c9e8515abc2cf3499 100644 --- a/src/utils/IdealGraphVisualizer/ControlFlow/pom.xml +++ b/src/utils/IdealGraphVisualizer/ControlFlow/pom.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions @@ -125,6 +125,10 @@ </archive> </configuration> </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-enforcer-plugin</artifactId> + </plugin> </plugins> </build> </project> diff --git a/src/utils/IdealGraphVisualizer/Coordinator/pom.xml b/src/utils/IdealGraphVisualizer/Coordinator/pom.xml index 9c6617876e9190134ae9b82f20832b3c8c79431b..5bdd2391302c8642e70865d0cf71f7d37d33c189 100644 --- a/src/utils/IdealGraphVisualizer/Coordinator/pom.xml +++ b/src/utils/IdealGraphVisualizer/Coordinator/pom.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions @@ -150,6 +150,10 @@ </archive> </configuration> </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-enforcer-plugin</artifactId> + </plugin> </plugins> </build> </project> diff --git a/src/utils/IdealGraphVisualizer/Data/pom.xml b/src/utils/IdealGraphVisualizer/Data/pom.xml index 055b085ffc8dabc39cc5776ecae2150574551ffc..832be674e9885461966c1796ba849358ec4e6ed5 100644 --- a/src/utils/IdealGraphVisualizer/Data/pom.xml +++ b/src/utils/IdealGraphVisualizer/Data/pom.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions @@ -94,6 +94,10 @@ </archive> </configuration> </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-enforcer-plugin</artifactId> + </plugin> </plugins> </build> </project> diff --git a/src/utils/IdealGraphVisualizer/Difference/pom.xml b/src/utils/IdealGraphVisualizer/Difference/pom.xml index 7f78b4c355e9562535832ed9e4d1d48df5ee3920..d4605c60727224df7e8c42b3db91421d79d70a15 100644 --- a/src/utils/IdealGraphVisualizer/Difference/pom.xml +++ b/src/utils/IdealGraphVisualizer/Difference/pom.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions @@ -95,6 +95,10 @@ </archive> </configuration> </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-enforcer-plugin</artifactId> + </plugin> </plugins> </build> </project> diff --git a/src/utils/IdealGraphVisualizer/Filter/pom.xml b/src/utils/IdealGraphVisualizer/Filter/pom.xml index 0b1fe3426051351f077db7c3d383503c25075e11..fa5089c8e65f8672fe8ad9261b3f4a4583e7aac6 100644 --- a/src/utils/IdealGraphVisualizer/Filter/pom.xml +++ b/src/utils/IdealGraphVisualizer/Filter/pom.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions @@ -96,7 +96,7 @@ <dependency> <groupId>org.openjdk.nashorn</groupId> <artifactId>nashorn-core</artifactId> - <version>15.2</version> + <version>15.3</version> </dependency> </dependencies> </profile> @@ -134,6 +134,10 @@ </archive> </configuration> </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-enforcer-plugin</artifactId> + </plugin> </plugins> </build> </project> diff --git a/src/utils/IdealGraphVisualizer/FilterWindow/pom.xml b/src/utils/IdealGraphVisualizer/FilterWindow/pom.xml index a130fccd2db18b2f63c0efa79d921bd539a73c1c..1617e1a5fa7db51a76f281ecffd078d5099d546f 100644 --- a/src/utils/IdealGraphVisualizer/FilterWindow/pom.xml +++ b/src/utils/IdealGraphVisualizer/FilterWindow/pom.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions @@ -145,6 +145,10 @@ </archive> </configuration> </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-enforcer-plugin</artifactId> + </plugin> </plugins> </build> </project> diff --git a/src/utils/IdealGraphVisualizer/Graal/pom.xml b/src/utils/IdealGraphVisualizer/Graal/pom.xml index f4170426c7c56545c4c4cd8b1dd2d6b7868cb77e..06a6e3be01c052bd3f2ff37a350584abb7444566 100644 --- a/src/utils/IdealGraphVisualizer/Graal/pom.xml +++ b/src/utils/IdealGraphVisualizer/Graal/pom.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions @@ -95,6 +95,10 @@ </archive> </configuration> </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-enforcer-plugin</artifactId> + </plugin> </plugins> </build> </project> diff --git a/src/utils/IdealGraphVisualizer/Graph/pom.xml b/src/utils/IdealGraphVisualizer/Graph/pom.xml index bf31f002e576739528b230f3a848ab47a6494e83..3dba21fa7a0484251867640323b2f11f48ffa28f 100644 --- a/src/utils/IdealGraphVisualizer/Graph/pom.xml +++ b/src/utils/IdealGraphVisualizer/Graph/pom.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions @@ -96,6 +96,10 @@ </archive> </configuration> </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-enforcer-plugin</artifactId> + </plugin> </plugins> </build> </project> diff --git a/src/utils/IdealGraphVisualizer/HierarchicalLayout/pom.xml b/src/utils/IdealGraphVisualizer/HierarchicalLayout/pom.xml index 2b3f09dcee5cfbdac5f1aa7bf7099ed43f2e18cf..be9cb1d882f615676070f0135596e02f4274af62 100644 --- a/src/utils/IdealGraphVisualizer/HierarchicalLayout/pom.xml +++ b/src/utils/IdealGraphVisualizer/HierarchicalLayout/pom.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions @@ -85,6 +85,10 @@ </archive> </configuration> </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-enforcer-plugin</artifactId> + </plugin> </plugins> </build> </project> diff --git a/src/utils/IdealGraphVisualizer/Layout/pom.xml b/src/utils/IdealGraphVisualizer/Layout/pom.xml index af6d2a11484e13c10bcf35072ed73ad9c5855956..6a046b5e6b8719499a480e87845ad9efe8fd76a3 100644 --- a/src/utils/IdealGraphVisualizer/Layout/pom.xml +++ b/src/utils/IdealGraphVisualizer/Layout/pom.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions @@ -78,6 +78,10 @@ </archive> </configuration> </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-enforcer-plugin</artifactId> + </plugin> </plugins> </build> </project> diff --git a/src/utils/IdealGraphVisualizer/NetworkConnection/pom.xml b/src/utils/IdealGraphVisualizer/NetworkConnection/pom.xml index 8f20e3fc57056db0aac1cd920f0838a1ce3dce5a..93ffbcee64be6a951a9f32cc9943743d52c62ae0 100644 --- a/src/utils/IdealGraphVisualizer/NetworkConnection/pom.xml +++ b/src/utils/IdealGraphVisualizer/NetworkConnection/pom.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions @@ -100,6 +100,10 @@ </archive> </configuration> </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-enforcer-plugin</artifactId> + </plugin> </plugins> </build> </project> diff --git a/src/utils/IdealGraphVisualizer/README.md b/src/utils/IdealGraphVisualizer/README.md index 382a2f4903b2d6cf2b124fe043a9e7f0aed2c562..f15f78f5a559d1d450ecef213d8c59ead493056d 100644 --- a/src/utils/IdealGraphVisualizer/README.md +++ b/src/utils/IdealGraphVisualizer/README.md @@ -8,7 +8,7 @@ tool itself is fairly general with only a few modules that contain C2 specific elements. The tool is built on top of the NetBeans Platform, and requires a JDK version -between 8 and 15 (the latest JDK supported by the current NetBeans Platform). +between 11 and 17 (the JDKs supported by the current NetBeans Platform). # Building and Running diff --git a/src/utils/IdealGraphVisualizer/SelectionCoordinator/pom.xml b/src/utils/IdealGraphVisualizer/SelectionCoordinator/pom.xml index 0ad4c203a1c19b1834ff3f15890181d827b6dbe7..cf813426bdea328aea5e15613e0aad776b88d2e1 100644 --- a/src/utils/IdealGraphVisualizer/SelectionCoordinator/pom.xml +++ b/src/utils/IdealGraphVisualizer/SelectionCoordinator/pom.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions @@ -85,6 +85,10 @@ </archive> </configuration> </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-enforcer-plugin</artifactId> + </plugin> </plugins> </build> </project> diff --git a/src/utils/IdealGraphVisualizer/ServerCompiler/pom.xml b/src/utils/IdealGraphVisualizer/ServerCompiler/pom.xml index b43145fa9745214a52466b0c0fc60bdd4326ec7e..86980e79c50fc24d48e0cc71d6eacf35e5e18df1 100644 --- a/src/utils/IdealGraphVisualizer/ServerCompiler/pom.xml +++ b/src/utils/IdealGraphVisualizer/ServerCompiler/pom.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions @@ -61,6 +61,11 @@ <artifactId>org-openide-util-ui</artifactId> <version>${netbeans.version}</version> </dependency> + <dependency> + <groupId>com.ibm.wala</groupId> + <artifactId>com.ibm.wala.util</artifactId> + <version>${wala.version}</version> + </dependency> </dependencies> <build> <plugins> @@ -90,6 +95,10 @@ </archive> </configuration> </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-enforcer-plugin</artifactId> + </plugin> </plugins> </build> </project> diff --git a/src/utils/IdealGraphVisualizer/ServerCompiler/src/main/java/com/sun/hotspot/igv/servercompiler/ServerCompilerScheduler.java b/src/utils/IdealGraphVisualizer/ServerCompiler/src/main/java/com/sun/hotspot/igv/servercompiler/ServerCompilerScheduler.java index 844eb4d4332309714f735fa394ef3e024bb1422c..5e4f6d0fc489aa28afa952b13c7c06a75ef44dba 100644 --- a/src/utils/IdealGraphVisualizer/ServerCompiler/src/main/java/com/sun/hotspot/igv/servercompiler/ServerCompilerScheduler.java +++ b/src/utils/IdealGraphVisualizer/ServerCompiler/src/main/java/com/sun/hotspot/igv/servercompiler/ServerCompilerScheduler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -32,6 +32,9 @@ import com.sun.hotspot.igv.data.services.Scheduler; import java.util.*; import org.openide.ErrorManager; import org.openide.util.lookup.ServiceProvider; +import com.ibm.wala.util.graph.Graph; +import com.ibm.wala.util.graph.impl.SlowSparseNumberedGraph; +import com.ibm.wala.util.graph.dominators.Dominators; /** * @@ -362,19 +365,6 @@ public class ServerCompilerScheduler implements Scheduler { } } - private class BlockIntermediate { - - InputBlock block; - int index; - int dominator; - int semi; - int parent; - int label; - int ancestor; - List<Integer> pred; - List<Integer> bucket; - } - public void buildCommonDominators() { commonDominator = new InputBlock[this.blocks.size()][this.blocks.size()]; for (int i = 0; i < blocks.size(); i++) { @@ -412,157 +402,30 @@ public class ServerCompilerScheduler implements Scheduler { if (blocks.size() == 0) { return; } - Vector<BlockIntermediate> intermediate = new Vector<>(graph.getBlocks().size()); - Map<InputBlock, BlockIntermediate> map = new HashMap<>(graph.getBlocks().size()); - int z = 0; - for (InputBlock b : blocks) { - BlockIntermediate bi = new BlockIntermediate(); - bi.block = b; - bi.index = z; - bi.dominator = -1; - bi.semi = -1; - bi.parent = -1; - bi.label = z; - bi.ancestor = -1; - bi.pred = new ArrayList<>(); - bi.bucket = new ArrayList<>(); - intermediate.add(bi); - map.put(b, bi); - z++; - } - Stack<Integer> stack = new Stack<>(); - stack.add(0); - - Vector<BlockIntermediate> array = new Vector<>(); - intermediate.get(0).dominator = 0; - int n = 0; - while (!stack.isEmpty()) { - int index = stack.pop(); - BlockIntermediate ib = intermediate.get(index); - ib.semi = n; - array.add(ib); - n = n + 1; - for (InputBlock b : ib.block.getSuccessors()) { - BlockIntermediate succ = map.get(b); - if (succ.semi == -1) { - succ.parent = index; - stack.push(succ.index); // TODO: check if same node could be pushed twice - } - succ.pred.add(index); - } - } - - for (int i = n - 1; i > 0; i--) { - BlockIntermediate block = array.get(i); - int block_index = block.index; - for (int predIndex : block.pred) { - int curIndex = eval(predIndex, intermediate); - BlockIntermediate curBlock = intermediate.get(curIndex); - if (curBlock.semi < block.semi) { - block.semi = curBlock.semi; - } - } - - - int semiIndex = block.semi; - BlockIntermediate semiBlock = array.get(semiIndex); - semiBlock.bucket.add(block_index); - - link(block.parent, block_index, intermediate); - BlockIntermediate parentBlock = intermediate.get(block.parent); - - for (int j = 0; j < parentBlock.bucket.size(); j++) { - for (int curIndex : parentBlock.bucket) { - int newIndex = eval(curIndex, intermediate); - BlockIntermediate curBlock = intermediate.get(curIndex); - BlockIntermediate newBlock = intermediate.get(newIndex); - int dom = block.parent; - if (newBlock.semi < curBlock.semi) { - dom = newIndex; - } - - curBlock.dominator = dom; - } - } - - - parentBlock.bucket.clear(); - } - - for (int i = 1; i < n; i++) { - - BlockIntermediate block = array.get(i); - int block_index = block.index; - - int semi_index = block.semi; - BlockIntermediate semi_block = array.get(semi_index); - - if (block.dominator != semi_block.index) { - int new_dom = intermediate.get(block.dominator).dominator; - block.dominator = new_dom; - } - } - - for (BlockIntermediate ib : intermediate) { - if (ib.dominator == -1) { - ib.dominator = 0; - } + Graph<InputBlock> CFG = SlowSparseNumberedGraph.make(); + for (InputBlock b : blocks) { + CFG.addNode(b); } - - for (BlockIntermediate bi : intermediate) { - InputBlock b = bi.block; - int dominator = bi.dominator; - InputBlock dominatorBlock = null; - if (dominator != -1) { - dominatorBlock = intermediate.get(dominator).block; - } - - if (dominatorBlock == b) { - dominatorBlock = null; + for (InputBlock p : blocks) { + for (InputBlock s : p.getSuccessors()) { + CFG.addEdge(p, s); } - this.dominatorMap.put(b, dominatorBlock); } - } - - private void compress(int index, Vector<BlockIntermediate> blocks) { - BlockIntermediate block = blocks.get(index); - - int ancestor = block.ancestor; - assert ancestor != -1; - BlockIntermediate ancestor_block = blocks.get(ancestor); - if (ancestor_block.ancestor != -1) { - compress(ancestor, blocks); + InputBlock root = findRoot().block; + Dominators<InputBlock> D = Dominators.make(CFG, root); - int label = block.label; - BlockIntermediate label_block = blocks.get(label); - - int ancestor_label = ancestor_block.label; - BlockIntermediate ancestor_label_block = blocks.get(label); - if (ancestor_label_block.semi < label_block.semi) { - block.label = ancestor_label; + for (InputBlock b : blocks) { + InputBlock idom = D.getIdom(b); + if (idom == null && b != root) { + // getCommonDominator expects a single root node. + idom = root; } - - block.ancestor = ancestor_block.ancestor; + dominatorMap.put(b, idom); } } - private int eval(int index, Vector<BlockIntermediate> blocks) { - BlockIntermediate block = blocks.get(index); - if (block.ancestor == -1) { - return index; - } else { - compress(index, blocks); - return block.label; - } - } - - private void link(int index1, int index2, Vector<BlockIntermediate> blocks) { - BlockIntermediate block2 = blocks.get(index2); - block2.ancestor = index1; - } - private boolean isRegion(Node n) { return n.inputNode.getProperties().get("name").equals("Region"); } diff --git a/src/utils/IdealGraphVisualizer/Settings/pom.xml b/src/utils/IdealGraphVisualizer/Settings/pom.xml index 97b6e7a783759ef8ab112459dd59215d2bead070..4003013bfa6eb076f92911ab0cc9d18d426b4552 100644 --- a/src/utils/IdealGraphVisualizer/Settings/pom.xml +++ b/src/utils/IdealGraphVisualizer/Settings/pom.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions @@ -110,6 +110,10 @@ </archive> </configuration> </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-enforcer-plugin</artifactId> + </plugin> </plugins> </build> </project> diff --git a/src/utils/IdealGraphVisualizer/Util/pom.xml b/src/utils/IdealGraphVisualizer/Util/pom.xml index d253fb5c53450c5e75ce45bf6e420b02a13bcaf1..bc27c79d175321a01d99d277796df4cb8eeb44cc 100644 --- a/src/utils/IdealGraphVisualizer/Util/pom.xml +++ b/src/utils/IdealGraphVisualizer/Util/pom.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions @@ -115,6 +115,10 @@ </archive> </configuration> </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-enforcer-plugin</artifactId> + </plugin> </plugins> </build> </project> diff --git a/src/utils/IdealGraphVisualizer/View/pom.xml b/src/utils/IdealGraphVisualizer/View/pom.xml index 12b2a8678b41ccdc1c4b2530e7a9326cb3d29953..c66cb8c9a2430b4bb5eae20cf54a81f28fecd1e5 100644 --- a/src/utils/IdealGraphVisualizer/View/pom.xml +++ b/src/utils/IdealGraphVisualizer/View/pom.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions @@ -81,11 +81,6 @@ <artifactId>SelectionCoordinator</artifactId> <version>${project.version}</version> </dependency> - <dependency> - <groupId>com.sun.hotspot.igv</groupId> - <artifactId>BatikSVGProxy</artifactId> - <version>${project.version}</version> - </dependency> <dependency> <groupId>com.sun.hotspot.igv</groupId> <artifactId>Settings</artifactId> @@ -151,6 +146,21 @@ <artifactId>org-netbeans-api-visual</artifactId> <version>${netbeans.version}</version> </dependency> + <dependency> + <groupId>org.apache.xmlgraphics</groupId> + <artifactId>batik-dom</artifactId> + <version>${batik.version}</version> + </dependency> + <dependency> + <groupId>org.apache.xmlgraphics</groupId> + <artifactId>batik-svggen</artifactId> + <version>${batik.version}</version> + </dependency> + <dependency> + <groupId>com.github.librepdf</groupId> + <artifactId>openpdf</artifactId> + <version>${openpdf.version}</version> + </dependency> </dependencies> <build> <plugins> @@ -185,6 +195,10 @@ </archive> </configuration> </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-enforcer-plugin</artifactId> + </plugin> </plugins> </build> </project> diff --git a/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/DiagramViewer.java b/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/DiagramViewer.java index 42697d025fe9bb17a5487d8de2eb48d19f8e0d24..2c58ac4dd26adb4846ce05f6ca90bbce6e7f5186 100644 --- a/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/DiagramViewer.java +++ b/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/DiagramViewer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 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 @@ -27,6 +27,7 @@ package com.sun.hotspot.igv.view; import com.sun.hotspot.igv.graph.Figure; import java.awt.Component; import java.awt.Graphics2D; +import java.awt.Rectangle; import java.util.Collection; import java.util.List; import javax.swing.JComponent; @@ -44,7 +45,7 @@ interface DiagramViewer { PANNING, } - public void paint(Graphics2D svgGenerator); + public void paint(Graphics2D generator); public Lookup getLookup(); @@ -70,4 +71,6 @@ interface DiagramViewer { public void setInteractionMode(InteractionMode mode); + public Rectangle getBounds(); + } diff --git a/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/EditorTopComponent.java b/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/EditorTopComponent.java index 76a73b9706837d05ca6fd75681243b1fe9ac3c83..cf5e965de69b58206bca4a956e34b64612e3f321 100644 --- a/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/EditorTopComponent.java +++ b/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/EditorTopComponent.java @@ -36,7 +36,6 @@ import com.sun.hotspot.igv.filter.FilterChainProvider; import com.sun.hotspot.igv.graph.Diagram; import com.sun.hotspot.igv.graph.Figure; import com.sun.hotspot.igv.graph.services.DiagramProvider; -import com.sun.hotspot.igv.svg.BatikSVG; import com.sun.hotspot.igv.util.LookupHistory; import com.sun.hotspot.igv.util.RangeSlider; import com.sun.hotspot.igv.view.actions.*; @@ -48,10 +47,21 @@ import java.awt.event.KeyListener; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.*; +import java.nio.charset.StandardCharsets; import java.util.List; import java.util.*; import javax.swing.*; import javax.swing.border.Border; +import org.apache.batik.dom.GenericDOMImplementation; +import org.apache.batik.svggen.SVGGeneratorContext; +import org.apache.batik.svggen.SVGGraphics2D; +import com.lowagie.text.Document; +import com.lowagie.text.Rectangle; +import com.lowagie.text.pdf.PdfWriter; +import com.lowagie.text.pdf.PdfContentByte; +import com.lowagie.text.pdf.PdfTemplate; +import com.lowagie.text.pdf.PdfGraphics2D; +import org.w3c.dom.DOMImplementation; import org.openide.DialogDisplayer; import org.openide.NotifyDescriptor; import org.openide.actions.RedoAction; @@ -103,30 +113,14 @@ public final class EditorTopComponent extends TopComponent implements PropertyCh @Override public void export(File f) { - Graphics2D svgGenerator = BatikSVG.createGraphicsObject(); - - if (svgGenerator == null) { - NotifyDescriptor message = new NotifyDescriptor.Message("For export to SVG files the Batik SVG Toolkit must be intalled.", NotifyDescriptor.ERROR_MESSAGE); - DialogDisplayer.getDefault().notifyLater(message); + String lcFileName = f.getName().toLowerCase(); + if (lcFileName.endsWith(".pdf")) { + exportToPDF(scene, f); + } else if (lcFileName.endsWith(".svg")) { + exportToSVG(scene, f); } else { - scene.paint(svgGenerator); - FileOutputStream os = null; - try { - os = new FileOutputStream(f); - Writer out = new OutputStreamWriter(os, UTF_8); - BatikSVG.printToStream(svgGenerator, out, true); - } catch (FileNotFoundException e) { - NotifyDescriptor message = new NotifyDescriptor.Message("For export to SVG files the Batik SVG Toolkit must be intalled.", NotifyDescriptor.ERROR_MESSAGE); - DialogDisplayer.getDefault().notifyLater(message); - } finally { - if (os != null) { - try { - os.close(); - } catch (IOException e) { - } - } - } - + NotifyDescriptor message = new NotifyDescriptor.Message("Unknown image file extension: expected either '.pdf' or '.svg'", NotifyDescriptor.ERROR_MESSAGE); + DialogDisplayer.getDefault().notifyLater(message); } } }; @@ -639,5 +633,47 @@ public final class EditorTopComponent extends TopComponent implements PropertyCh @Override protected Object writeReplace() throws ObjectStreamException { throw new NotSerializableException(); -} + } + + private static void exportToPDF(DiagramViewer scene, File f) { + int width = scene.getBounds().width; + int height = scene.getBounds().height; + com.lowagie.text.Document document = new Document(new Rectangle(width, height)); + PdfWriter writer = null; + try { + writer = PdfWriter.getInstance(document, new FileOutputStream(f)); + writer.setCloseStream(true); + document.open(); + PdfContentByte contentByte = writer.getDirectContent(); + PdfTemplate template = contentByte.createTemplate(width, height); + PdfGraphics2D pdfGenerator = new PdfGraphics2D(contentByte, width, height); + scene.paint(pdfGenerator); + pdfGenerator.dispose(); + contentByte.addTemplate(template, 0, 0); + } catch (Exception e) { + e.printStackTrace(); + } finally { + if (document.isOpen()) { + document.close(); + } + if (writer != null) { + writer.close(); + } + } + } + + private static void exportToSVG(DiagramViewer scene, File f) { + DOMImplementation dom = GenericDOMImplementation.getDOMImplementation(); + org.w3c.dom.Document document = dom.createDocument("http://www.w3.org/2000/svg", "svg", null); + SVGGeneratorContext ctx = SVGGeneratorContext.createDefault(document); + ctx.setEmbeddedFontsOn(true); + SVGGraphics2D svgGenerator = new SVGGraphics2D(ctx, true); + scene.paint(svgGenerator); + try (FileOutputStream os = new FileOutputStream(f)) { + Writer out = new OutputStreamWriter(os, StandardCharsets.UTF_8); + svgGenerator.stream(out, true); + } catch (IOException e) { + e.printStackTrace(); + } + } } diff --git a/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/actions/ExportAction.java b/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/actions/ExportAction.java index 8583a6fbf3503845496cff33b85688347b4f4fc4..e5ea4025c3364f7c5050cbc11e5a94c94dc23d50 100644 --- a/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/actions/ExportAction.java +++ b/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/actions/ExportAction.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 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 @@ -45,7 +45,7 @@ public final class ExportAction extends CallableSystemAction implements LookupLi private final Lookup.Result<ExportCookie> result; public ExportAction() { - putValue(Action.SHORT_DESCRIPTION, "Export current graph as SVG file"); + putValue(Action.SHORT_DESCRIPTION, "Export current graph as image file"); putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_E, InputEvent.CTRL_MASK)); lookup = Utilities.actionsGlobalContext(); result = lookup.lookup(new Lookup.Template<>(ExportCookie.class)); @@ -66,12 +66,15 @@ public final class ExportAction extends CallableSystemAction implements LookupLi @Override public boolean accept(File f) { - return true; + String lcFileName = f.getName().toLowerCase(); + return lcFileName.endsWith(".pdf") || + lcFileName.endsWith(".svg") || + f.isDirectory(); } @Override public String getDescription() { - return "SVG files (*.svg)"; + return "Image files (*.pdf, *.svg)"; } }); fc.setCurrentDirectory(new File(Settings.get().get(Settings.DIRECTORY, Settings.DIRECTORY_DEFAULT))); @@ -80,7 +83,7 @@ public final class ExportAction extends CallableSystemAction implements LookupLi if (fc.showSaveDialog(null) == JFileChooser.APPROVE_OPTION) { File file = fc.getSelectedFile(); if (!file.getName().contains(".")) { - file = new File(file.getAbsolutePath() + ".svg"); + file = new File(file.getAbsolutePath() + ".pdf"); } File dir = file; diff --git a/src/utils/IdealGraphVisualizer/application/pom.xml b/src/utils/IdealGraphVisualizer/application/pom.xml index b5422fecb52abc64f9683064b4c5ad98c4e29cfb..3d30697c01f17865a50b5eac665c70cddd0cafce 100644 --- a/src/utils/IdealGraphVisualizer/application/pom.xml +++ b/src/utils/IdealGraphVisualizer/application/pom.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions @@ -142,11 +142,6 @@ <artifactId>Graal</artifactId> <version>${project.version}</version> </dependency> - <dependency> - <groupId>${project.groupId}</groupId> - <artifactId>BatikSVGProxy</artifactId> - <version>${project.version}</version> - </dependency> <dependency> <groupId>${project.groupId}</groupId> <artifactId>View</artifactId> @@ -158,6 +153,9 @@ <plugin> <groupId>org.apache.netbeans.utilities</groupId> <artifactId>nbm-maven-plugin</artifactId> + <configuration> + <etcConfFile>src/main/resources/${brandingToken}.conf</etcConfFile> + </configuration> </plugin> <!-- Permits NbModuleSuite to be run in integration-test phase: --> <plugin> diff --git a/src/utils/IdealGraphVisualizer/application/src/main/resources/idealgraphvisualizer.conf b/src/utils/IdealGraphVisualizer/application/src/main/resources/idealgraphvisualizer.conf new file mode 100644 index 0000000000000000000000000000000000000000..500ed32f280aaec3c6faf6d61716e4007195551c --- /dev/null +++ b/src/utils/IdealGraphVisualizer/application/src/main/resources/idealgraphvisualizer.conf @@ -0,0 +1,24 @@ +# 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. + +# Open/export modules still accessed by the NetBeans Platform. +# All options must be passed in a single line for multi-platform support. +default_options="-J--add-opens=java.base/java.net=ALL-UNNAMED -J--add-opens=java.desktop/javax.swing.plaf.synth=ALL-UNNAMED -J--add-opens=java.desktop/com.sun.java.swing.plaf.gtk=ALL-UNNAMED -J--add-opens=java.desktop/javax.swing=ALL-UNNAMED -J--add-exports=java.desktop/sun.awt=ALL-UNNAMED" \ No newline at end of file diff --git a/src/utils/IdealGraphVisualizer/branding/pom.xml b/src/utils/IdealGraphVisualizer/branding/pom.xml index 67821ff46216ec7334cf240a681f6a11b0cb7221..ed33298d3e4c522d30f472a0b33e37e2ecf87265 100644 --- a/src/utils/IdealGraphVisualizer/branding/pom.xml +++ b/src/utils/IdealGraphVisualizer/branding/pom.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions @@ -61,6 +61,10 @@ </archive> </configuration> </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-enforcer-plugin</artifactId> + </plugin> </plugins> </build> </project> diff --git a/src/utils/IdealGraphVisualizer/pom.xml b/src/utils/IdealGraphVisualizer/pom.xml index c1b1896dde4eda03c1c8a5b42dbb757ca2f20769..5f7578c8e1a1c47f6749d9459336e79549fc7af9 100644 --- a/src/utils/IdealGraphVisualizer/pom.xml +++ b/src/utils/IdealGraphVisualizer/pom.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8" standalone="no"?> <!-- - Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions @@ -64,6 +64,27 @@ <artifactId>maven-jar-plugin</artifactId> <version>${mvnjarplugin.version}</version> </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-enforcer-plugin</artifactId> + <version>${mvnenforcerplugin.version}</version> + <executions> + <execution> + <id>enforce-java</id> + <goals> + <goal>enforce</goal> + </goals> + <configuration> + <rules> + <requireJavaVersion> + <version>[11,18)</version> + <message>IGV requires a JDK version between 11 and 17</message> + </requireJavaVersion> + </rules> + </configuration> + </execution> + </executions> + </plugin> </plugins> </pluginManagement> </build> @@ -86,16 +107,19 @@ <module>ServerCompiler</module> <module>FilterWindow</module> <module>Graal</module> - <module>BatikSVGProxy</module> <module>View</module> </modules> <properties> - <netbeans.version>RELEASE123</netbeans.version> + <netbeans.version>RELEASE126</netbeans.version> <swinglayouts.version>1.0.2</swinglayouts.version> - <nbmmvnplugin.version>4.3</nbmmvnplugin.version> + <nbmmvnplugin.version>4.6</nbmmvnplugin.version> <mvncompilerplugin.version>3.8.1</mvncompilerplugin.version> - <mvnjarplugin.version>3.1.2</mvnjarplugin.version> + <mvnjarplugin.version>3.2.0</mvnjarplugin.version> + <mvnenforcerplugin.version>3.0.0</mvnenforcerplugin.version> <junit.version>4.13.2</junit.version> + <batik.version>1.14</batik.version> + <openpdf.version>1.3.26</openpdf.version> + <wala.version>1.5.7</wala.version> <brandingToken>idealgraphvisualizer</brandingToken> </properties> </project> diff --git a/src/utils/LogCompilation/src/main/java/com/sun/hotspot/tools/compiler/LogParser.java b/src/utils/LogCompilation/src/main/java/com/sun/hotspot/tools/compiler/LogParser.java index b0fc682f65a688c0f1ddd9549b0698b121bb7d3a..05407f8c969b45dc1aace35faae4e4b2c4000d5a 100644 --- a/src/utils/LogCompilation/src/main/java/com/sun/hotspot/tools/compiler/LogParser.java +++ b/src/utils/LogCompilation/src/main/java/com/sun/hotspot/tools/compiler/LogParser.java @@ -973,7 +973,7 @@ public class LogParser extends DefaultHandler implements ErrorHandler { m.setHolder(type(search(atts, "holder"))); m.setName(search(atts, "name")); m.setReturnType(type(search(atts, "return"))); - String arguments = atts.getValue("arguments");; + String arguments = atts.getValue("arguments"); if (arguments == null) { m.setSignature("()" + sigtype(atts.getValue("return"))); } else { diff --git a/src/utils/hsdis/README b/src/utils/hsdis/README deleted file mode 100644 index aee40f6bd27e80e0e03b631d4826eace43483b2e..0000000000000000000000000000000000000000 --- a/src/utils/hsdis/README +++ /dev/null @@ -1,98 +0,0 @@ -Copyright (c) 2008, 2021, Oracle and/or its affiliates. All rights reserved. -DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - -The Universal Permissive License (UPL), Version 1.0 - -Subject to the condition set forth below, permission is hereby granted to -any person obtaining a copy of this software, associated documentation -and/or data (collectively the "Software"), free of charge and under any -and all copyright rights in the Software, and any and all patent rights -owned or freely licensable by each licensor hereunder covering either (i) -the unmodified Software as contributed to or provided by such licensor, -or (ii) the Larger Works (as defined below), to deal in both - -(a) the Software, and - -(b) any piece of software and/or hardware listed in the lrgrwrks.txt file -if one is included with the Software (each a "Larger Work" to which the -Software is contributed by such licensors), - -without restriction, including without limitation the rights to copy, -create derivative works of, display, perform, and distribute the Software -and make, use, sell, offer for sale, import, export, have made, and have -sold the Software and the Larger Work(s), and to sublicense the foregoing -rights on either these or other terms. - -This license is subject to the following condition: - -The above copyright notice and either this complete permission notice or -at a minimum a reference to the UPL must be included in all copies or -substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -USE OR OTHER DEALINGS IN THE SOFTWARE. - -Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -or visit www.oracle.com if you need additional information or have any -questions. - -________________________________________________________________________ - -'hsdis': A HotSpot plugin for disassembling dynamically generated code. - -The files in this directory are built independently of the HotSpot JVM. - -* Building - -To build this project you need a copy of GNU binutils to build against. It is -known to work with binutils 2.37. Building against versions older than 2.29 is -not supported. Download a copy of the software from -http://directory.fsf.org/project/binutils or one of its mirrors. - -To build this library, you must enable building in configure by "bash configure ---with-hsdis=binutils". - -You must also specify where binutils is located. To facilitate building, you can -point to a place where the (unpacked) binutils sources are located using -"--with-binutils-src=<location>", and configure will build binutils for you. On -repeated runs, you can keep this command line option, since configure will -figure out that the binutils binaries are already present and skip building, or -you can replace it with "--with-binutils=<location>". - -If you have pre-built binutils binaries, you can point to them directly using -"--with-binutils=<location>". - -When you have created a proper configuration, you can then build the hsdis -library using "make build-hsdis". - -* Building on Windows - -On Windows, the normal Microsoft Visual Studio toolchain cannot build binutils. -Instead we need to use the mingw compiler. This is available as a cygwin -package. You need to install the "gcc-core" and "mingw64-x86_64-gcc-core" -packages (or "mingw64-i686-gcc-core", if you want the 32-bit version) and -"mingw64-x86_64-glib2.0". - -* Installing - -To build the hsdis library, run "make build-hsdis". This will build the library -in a separate directory, but not make it available to the JDK in the -configuration. To actually install it in the JDK, run "make install-hsdis". - -Note: The resulting build may not be distributable. Please get legal advice if -you intend to distribute the result of your build. - -* Using the library - -The hsdis library will be automatically loaded by Hotspot when you use the -diagnostic option "-XX:+PrintAssembly". Note that since this is a diagnostic -option, you need to unlock these first, so in practice you activate it using -"-XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly". - -More information is available at the wiki -[https://wiki.openjdk.java.net/display/HotSpot/PrintAssembly]. diff --git a/src/utils/hsdis/README.md b/src/utils/hsdis/README.md new file mode 100644 index 0000000000000000000000000000000000000000..02bab9706f846a040d54fce13e27c707a66e0a1b --- /dev/null +++ b/src/utils/hsdis/README.md @@ -0,0 +1,191 @@ +``` +Copyright (c) 2008, 2022, Oracle and/or its affiliates. All rights reserved. +DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + +The Universal Permissive License (UPL), Version 1.0 + +Subject to the condition set forth below, permission is hereby granted to +any person obtaining a copy of this software, associated documentation +and/or data (collectively the "Software"), free of charge and under any +and all copyright rights in the Software, and any and all patent rights +owned or freely licensable by each licensor hereunder covering either (i) +the unmodified Software as contributed to or provided by such licensor, +or (ii) the Larger Works (as defined below), to deal in both + +(a) the Software, and + +(b) any piece of software and/or hardware listed in the lrgrwrks.txt file +if one is included with the Software (each a "Larger Work" to which the +Software is contributed by such licensors), + +without restriction, including without limitation the rights to copy, +create derivative works of, display, perform, and distribute the Software +and make, use, sell, offer for sale, import, export, have made, and have +sold the Software and the Larger Work(s), and to sublicense the foregoing +rights on either these or other terms. + +This license is subject to the following condition: + +The above copyright notice and either this complete permission notice or +at a minimum a reference to the UPL must be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +USE OR OTHER DEALINGS IN THE SOFTWARE. + +Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +or visit www.oracle.com if you need additional information or have any +questions. +``` + +--- + +# hsdis - a HotSpot plugin for disassembling dynamically generated code + +The files in this directory are built independently of the HotSpot JVM. + +hsdis is an interface exposed by Hotspot. There are several backends that +implement this interface, using different disassembly engines. Included in the +JDK is support for building hsdis with Capstone, LLVM or GNU binutils. The +interface is fairly straightforward and easy to implement using other backends. + +## Building and installing + +To compile hsdis, you need to activate hsdis support, and select the proper +backend to use. This is done with the configure switch `--with-hsdis=<backend>`, +where `<backend>` is either `capstone`, `llvm` or `binutils`. For details, see +the sections on the respective backends below. + +To build the hsdis library, run `make build-hsdis`. This will build the library +in a separate directory, but not make it available to the JDK in the +configuration. To actually install it in the JDK, run `make install-hsdis`. + +**NOTE:** If you do this using the binutils backend, the resulting build may not +be distributable. Please get legal advice if you intend to distribute the result +of your build. + +## Using the library + +The hsdis library will be automatically loaded by Hotspot when you use the +diagnostic option `-XX:+PrintAssembly`. Note that since this is a diagnostic +option, you need to unlock these first, so in practice you activate it using +`-XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly`. + +If using the LLVM backend on Windows, you need to be sure that the LLVM DLL file +(or files) can be found by hsdis. In practice, this means that you either need +to copy `LLVM-C.DLL` to a place on your `PATH` or the JDK `bin` directory, or +you need to augment your `PATH` variable to also point to where you installed +LLVM (like `C:\LLVM\bin`). + +More information is available at the [HotSpot +wiki](https://wiki.openjdk.java.net/display/HotSpot/PrintAssembly). + +## Building with Capstone + +To build this project using Capstone you need to have Capstone installed. +Typical ways of installation can be `sudo apt install libcapstone-dev` (on +Debian and derivatives), or `brew install capstone` (on macOS with Homebrew). +For Windows, you need to download the "Core Engine", and unzip it. See the +[Capstone Download +page](https://www.capstone-engine.org/download.html#windows---core-engine-) for +up-to-date download links. + +This has been tested with Capstone v4.0.2, but earlier (and later) versions are +also likely to work. + +To build hsdis using Capstone, you must enable it in configure by `bash +configure --with-hsdis=capstone`. + +On Linux and macOS, the location Capstone can most often be auto-detected. If +this fails, or if you are building on Windows, you need to specify where +Capstone is located using `--with-capstone=<path>`. This path should point to +where you have extracted the Core Engine zip file. + +## Building with LLVM + +To build this project using LLVM you need to have LLVM installed. Typical ways +of installation can be `sudo apt install llvm` (on Debian and derivatives), or +`brew install llvm` (on macOS with Homebrew). For Windows, see below. + +This has been tested with LLVM v13.0.0, but earlier (and later) versions are +also likely to work. + +To build hsdis using LLVM, you must enable it in configure by `bash configure +--with-hsdis=llvm`. + +If `llvm-config` is not in your path, you will need to specify the LLVM home using +`--with-llvm=<LLVM home>`. Example: If your `llvm-config` is in `~/my-llvm/bin`, +then you should use `--with-llvm=~/my-llvm`. + +### Building with LLVM on Windows + +Getting a usable installation on Windows is trickier than on the other +platforms. You can download (and patch) the official distribution, or you can +build it yourself. + +Links to the latest version of the official build is available at [LLVMs +download page](https://releases.llvm.org/download.html). Download the file +*LLVM-nn.n.n-win64.exe*, and run it to let it install itself. The default +installation location is `C:\Program Files\LLVM`. This is not ideal due to the +spaces in the path, so it is recommended to put it elsewhere (e.g. `C:\LLVM`). + +For very unclear reasons, the official Windows build is missing almost all LLVM +include files. (At least this was the case up to and including LLVM 13.) You +will need to complement your installation with the proper include files. One way +to do this is to install LLVM in Cygwin. This will give you (apart from the Cygwin-based dll +files which are unusable with Visual Studio) a complete set of the +headers. These are located in `/usr/include/llvm` and `/usr/include/llvm-c`. Copy +these directories, with all their content, into `$LLVM_HOME/include`. + +Alternatively, you can build LLVM yourself from source. This process is +documented at the [LLVM Visual Studio +page](https://llvm.org/docs/GettingStartedVS.html). + +Either which way, you must tell configure the location of your LLVM installation +using `--with-llvm=<path to LLVM home>`. + +The `llvm-config` tool, which configure uses on other platforms to get the +proper compile and link flags to use, is unfortunately not usable on Windows. In +the official distribution, it is just missing. And the self-built version tend +to give broken and unusable output. Therefore configure uses heuristics to setup +proper flags to the compiler and linker. This was verified to work for LLVM v13, +but might be incorrect for other versions. Manual override of `HSDIS_CFLAGS`, +`HSDIS_LDFLAGS` and/or `HSDIS_LIBS` on the make command line might be needed in +that case. + +## Building with binutils + +To build this project using binutils you need a copy of GNU binutils to build +against. It is known to work with binutils 2.37. Building against versions older +than 2.29 is not supported. Download a copy of the software from [FSF binutils +page](http://directory.fsf.org/project/binutils) or one of its mirrors. + +To build this library, you must enable building in configure by `bash configure +--with-hsdis=binutils`. + +You must also specify where binutils is located. To facilitate building, you can +point to a place where the (unpacked) binutils sources are located using +`--with-binutils-src=<location>`, and configure will build binutils for you. On +repeated runs, you can keep this command line option, since configure will +figure out that the binutils binaries are already present and skip building, or +you can replace it with `--with-binutils=<location>`. + +If you have pre-built binutils binaries, you can point to them directly using +`--with-binutils=<location>`. + +If you want to build hsdis with binutils provided by system (e.g. binutils-devel +from Fedora, binutils-dev from Ubuntu), you can pass `--with-binutils=system`. +`system` is available on Linux only. + +### Building with binutils on Windows + +On Windows, the normal Microsoft Visual Studio toolchain cannot build binutils. +Instead we need to use the mingw compiler. This is available as a cygwin +package. You need to install the `gcc-core` and `mingw64-x86_64-gcc-core` +packages (or `mingw64-i686-gcc-core`, if you want the 32-bit version) and +`mingw64-x86_64-glib2.0`. diff --git a/src/utils/hsdis/hsdis.c b/src/utils/hsdis/binutils/hsdis-binutils.c similarity index 99% rename from src/utils/hsdis/hsdis.c rename to src/utils/hsdis/binutils/hsdis-binutils.c index 8e3f0ca7836021e320390936f378b2e048260eae..279ed53ba5d24559e9e78fc34a54e2e78ef68d53 100644 --- a/src/utils/hsdis/hsdis.c +++ b/src/utils/hsdis/binutils/hsdis-binutils.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -49,14 +49,16 @@ HotSpot PrintAssembly option. */ +#ifndef SYSTEM_BINUTILS #include <config.h> /* required by bfd.h */ +#endif + #include <errno.h> #include <inttypes.h> #include <string.h> #include <libiberty.h> #include <bfd.h> -#include <bfdver.h> #include <dis-asm.h> #include "hsdis.h" @@ -565,7 +567,7 @@ static void init_disassemble_info_from_bfd(struct disassemble_info* dinfo, dinfo->arch = bfd_get_arch(abfd); dinfo->mach = bfd_get_mach(abfd); dinfo->disassembler_options = disassembler_options; -#if BFD_VERSION >= 234000000 +#ifdef SEC_ELF_OCTETS /* bfd_octets_per_byte() has 2 args since binutils 2.34 */ dinfo->octets_per_byte = bfd_octets_per_byte (abfd, NULL); #else diff --git a/src/utils/hsdis/capstone/hsdis-capstone.c b/src/utils/hsdis/capstone/hsdis-capstone.c new file mode 100644 index 0000000000000000000000000000000000000000..d71330ee6a766d63e2128160b6e5f6701fc39366 --- /dev/null +++ b/src/utils/hsdis/capstone/hsdis-capstone.c @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * The Universal Permissive License (UPL), Version 1.0 + * + * Subject to the condition set forth below, permission is hereby granted to + * any person obtaining a copy of this software, associated documentation + * and/or data (collectively the "Software"), free of charge and under any + * and all copyright rights in the Software, and any and all patent rights + * owned or freely licensable by each licensor hereunder covering either (i) + * the unmodified Software as contributed to or provided by such licensor, + * or (ii) the Larger Works (as defined below), to deal in both + * + * (a) the Software, and + * + * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file + * if one is included with the Software (each a "Larger Work" to which the + * Software is contributed by such licensors), + * + * without restriction, including without limitation the rights to copy, + * create derivative works of, display, perform, and distribute the Software + * and make, use, sell, offer for sale, import, export, have made, and have + * sold the Software and the Larger Work(s), and to sublicense the foregoing + * rights on either these or other terms. + * + * This license is subject to the following condition: + * + * The above copyright notice and either this complete permission notice or + * at a minimum a reference to the UPL must be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN + * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* hsdis.c -- dump a range of addresses as native instructions + This implements the plugin protocol required by the + HotSpot PrintAssembly option. +*/ + +#include <inttypes.h> + +#include <capstone.h> + +#include "hsdis.h" + +/* short names for stuff in hsdis.h */ +typedef decode_instructions_event_callback_ftype event_callback_t; +typedef decode_instructions_printf_callback_ftype printf_callback_t; + +#define print(...) (*printf_callback) (printf_stream, __VA_ARGS__) + +#ifdef _WIN32 +__declspec(dllexport) +#endif +void* decode_instructions_virtual(uintptr_t start_va, uintptr_t end_va, + unsigned char* buffer, uintptr_t length, + void* (*event_callback)(void*, const char*, void*), + void* event_stream, + int (*printf_callback)(void*, const char*, ...), + void* printf_stream, + const char* options, + int newline /* bool value for nice new line */) { + csh cs_handle; + + if (cs_open(CAPSTONE_ARCH, CAPSTONE_MODE, &cs_handle) != CS_ERR_OK) { + print("Could not open cs_handle"); + return NULL; + } + + // TODO: Support intel syntax + cs_option(cs_handle, CS_OPT_SYNTAX, CS_OPT_SYNTAX_ATT); + + cs_insn *insn; + size_t count = cs_disasm(cs_handle, buffer, length, (uintptr_t) buffer, 0 , &insn); + if (count) { + for (unsigned int j = 0; j < count; j++) { + print(" 0x%" PRIx64 ":\t%s\t\t%s\n", insn[j].address, insn[j].mnemonic, insn[j].op_str); + } + cs_free(insn, count); + } + + cs_close(&cs_handle); + + return NULL; +} diff --git a/src/utils/hsdis/hsdis-license.txt b/src/utils/hsdis/hsdis-license.txt new file mode 100644 index 0000000000000000000000000000000000000000..3c0b08232658857672727e7774b0c3b20413fcca --- /dev/null +++ b/src/utils/hsdis/hsdis-license.txt @@ -0,0 +1,35 @@ +The Universal Permissive License (UPL), Version 1.0 + +Subject to the condition set forth below, permission is hereby granted to +any person obtaining a copy of this software, associated documentation +and/or data (collectively the "Software"), free of charge and under any +and all copyright rights in the Software, and any and all patent rights +owned or freely licensable by each licensor hereunder covering either (i) +the unmodified Software as contributed to or provided by such licensor, +or (ii) the Larger Works (as defined below), to deal in both + +(a) the Software, and + +(b) any piece of software and/or hardware listed in the lrgrwrks.txt file +if one is included with the Software (each a "Larger Work" to which the +Software is contributed by such licensors), + +without restriction, including without limitation the rights to copy, +create derivative works of, display, perform, and distribute the Software +and make, use, sell, offer for sale, import, export, have made, and have +sold the Software and the Larger Work(s), and to sublicense the foregoing +rights on either these or other terms. + +This license is subject to the following condition: + +The above copyright notice and either this complete permission notice or +at a minimum a reference to the UPL must be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/src/utils/hsdis/hsdis.h b/src/utils/hsdis/hsdis.h index a6b45a57ba8102f1ff5f2fc48109ce896b3f387f..7e3b8e397af9ed59bebe1ce9f5bf3ebbe2f25598 100644 --- a/src/utils/hsdis/hsdis.h +++ b/src/utils/hsdis/hsdis.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -72,9 +72,14 @@ #ifndef SHARED_TOOLS_HSDIS_H #define SHARED_TOOLS_HSDIS_H +#ifdef __cplusplus +extern "C" +{ +#endif + extern -#ifdef DLL_EXPORT - DLL_EXPORT +#ifdef _WIN32 +__declspec(dllexport) #endif void* decode_instructions_virtual(uintptr_t start_va, uintptr_t end_va, unsigned char* buffer, uintptr_t length, @@ -87,8 +92,8 @@ void* decode_instructions_virtual(uintptr_t start_va, uintptr_t end_va, /* This is the compatability interface for older versions of hotspot */ extern -#ifdef DLL_ENTRY - DLL_ENTRY +#ifdef _WIN32 +__declspec(dllexport) #endif void* decode_instructions(void* start_pv, void* end_pv, void* (*event_callback)(void*, const char*, void*), @@ -115,4 +120,9 @@ typedef void* (*decode_func_stype) (void* start_pv, void* end_pv, decode_instructions_printf_callback_ftype printf_callback, void* printf_stream, const char* options); + +#ifdef __cplusplus +} +#endif + #endif /* SHARED_TOOLS_HSDIS_H */ diff --git a/src/utils/hsdis/llvm/hsdis-llvm.cpp b/src/utils/hsdis/llvm/hsdis-llvm.cpp new file mode 100644 index 0000000000000000000000000000000000000000..34edfac2113521ec0532e47af1ed011f74ea195f --- /dev/null +++ b/src/utils/hsdis/llvm/hsdis-llvm.cpp @@ -0,0 +1,358 @@ +/* + * Copyright (c) 2008, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * The Universal Permissive License (UPL), Version 1.0 + * + * Subject to the condition set forth below, permission is hereby granted to + * any person obtaining a copy of this software, associated documentation + * and/or data (collectively the "Software"), free of charge and under any + * and all copyright rights in the Software, and any and all patent rights + * owned or freely licensable by each licensor hereunder covering either (i) + * the unmodified Software as contributed to or provided by such licensor, + * or (ii) the Larger Works (as defined below), to deal in both + * + * (a) the Software, and + * + * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file + * if one is included with the Software (each a "Larger Work" to which the + * Software is contributed by such licensors), + * + * without restriction, including without limitation the rights to copy, + * create derivative works of, display, perform, and distribute the Software + * and make, use, sell, offer for sale, import, export, have made, and have + * sold the Software and the Larger Work(s), and to sublicense the foregoing + * rights on either these or other terms. + * + * This license is subject to the following condition: + * + * The above copyright notice and either this complete permission notice or + * at a minimum a reference to the UPL must be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN + * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* hsdis.cpp -- dump a range of addresses as native instructions + This implements the plugin protocol required by the + HotSpot PrintAssembly option. +*/ + +#include <stdlib.h> +#include <stdio.h> +#include <errno.h> +#include <inttypes.h> +#include <string.h> + +#include <llvm-c/Disassembler.h> +#include <llvm-c/DisassemblerTypes.h> +#include <llvm-c/Target.h> +#include <llvm-c/TargetMachine.h> + +#include "hsdis.h" + +/* short names for stuff in hsdis.h */ +typedef decode_instructions_event_callback_ftype event_callback_t; +typedef decode_instructions_printf_callback_ftype printf_callback_t; + +class hsdis_backend_base { + protected: + uintptr_t _start_va; + uintptr_t _end_va; + unsigned char* _buffer; + uintptr_t _length; + event_callback_t _event_callback; + void* _event_stream; + printf_callback_t _printf_callback; + void* _printf_stream; + int _do_newline; + + bool _losing; + const char* _arch_name; + + virtual void print_help(const char* msg, const char* arg) = 0; + virtual void print_insns_config() = 0; + virtual size_t decode_instruction(uintptr_t p, uintptr_t start, uintptr_t end) = 0; + virtual const char* format_insn_close(const char* close, char* buf, size_t bufsize) = 0; + + private: + /* ignore all events, return a null */ + static void* null_event_callback(void* ignore_stream, const char* ignore_event, void* arg) { + return NULL; + } + + /* print all events as XML markup */ + static void* xml_event_callback(void* stream, const char* event, void* arg) { + FILE* fp = (FILE*) stream; +#define NS_PFX "dis:" + if (event[0] != '/') { + /* issue the tag, with or without a formatted argument */ + fprintf(fp, "<" NS_PFX); + fprintf(fp, event, arg); + fprintf(fp, ">"); + } else { + ++event; /* skip slash */ + const char* argp = strchr(event, ' '); + if (argp == NULL) { + /* no arguments; just issue the closing tag */ + fprintf(fp, "</" NS_PFX "%s>", event); + } else { + /* split out the closing attributes as <dis:foo_done attr='val'/> */ + size_t event_prefix =(argp - event); + fprintf(fp, "<" NS_PFX "%.*s_done", (int) event_prefix, event); + fprintf(fp, argp, arg); + fprintf(fp, "/></" NS_PFX "%.*s>", (int) event_prefix, event); + } + } +#undef NS_PFX + return NULL; + } + +protected: + hsdis_backend_base(uintptr_t start_va, uintptr_t end_va, + unsigned char* buffer, uintptr_t length, + event_callback_t event_callback, void* event_stream, + printf_callback_t printf_callback, void* printf_stream, + int do_newline) : + _start_va(start_va), _end_va(end_va), + _buffer(buffer), _length(length), + _event_callback(event_callback), _event_stream(event_stream), + _printf_callback(printf_callback), _printf_stream(printf_stream), + _do_newline(do_newline), + _losing(false), _arch_name(NULL) + { + /* Make reasonable defaults for null callbacks. + A non-null stream for a null callback is assumed to be a FILE* for output. + Events are rendered as XML. + */ + if (_printf_callback == NULL) { + int (*fprintf_callback)(FILE*, const char*, ...) = &fprintf; + FILE* fprintf_stream = stdout; + _printf_callback = (printf_callback_t) fprintf_callback; + if (_printf_stream == NULL) + _printf_stream = (void*) fprintf_stream; + } + if (_event_callback == NULL) { + if (_event_stream == NULL) + _event_callback = (event_callback_t)&null_event_callback; + else + _event_callback = (event_callback_t)&xml_event_callback; + } + } + + public: + void* decode() { + uintptr_t start = _start_va; + uintptr_t end = _end_va; + uintptr_t p = start; + + (*_event_callback)(_event_stream, "insns", (void*)start); + + print_insns_config(); + + while (p < end && !_losing) { + (*_event_callback)(_event_stream, "insn", (void*) p); + + size_t size = decode_instruction(p, start, end); + if (size > 0) p += size; + else _losing = true; + + if (!_losing) { + char buf[128]; + const char* insn_close = format_insn_close("/insn", buf, sizeof(buf)); + (*_event_callback)(_event_stream, insn_close, (void*) p); + + if (_do_newline) { + /* follow each complete insn by a nice newline */ + (*_printf_callback)(_printf_stream, "\n"); + } + } + } + + if (_losing) (*_event_callback)(_event_stream, "/insns", (void*) p); + return (void*) p; + } +}; + + +class hsdis_backend : public hsdis_backend_base { + private: + LLVMDisasmContextRef _dcontext; + char _target_triple[128]; + + void parse_caller_options(const char* options) { + memset(&_target_triple, 0, sizeof(_target_triple)); + const char* p; + for (p = options; p != NULL; ) { + const char* q = strchr(p, ','); + size_t plen = (q == NULL) ? strlen(p) : ((q++) - p); + if (plen == 4 && strncmp(p, "help", plen) == 0) { + print_help(NULL, NULL); + } else if (plen > 6 && strncmp(p, "hsdis-", 6) == 0) { + // do not pass these to the next level + } else if (plen >= 14 && strncmp(p, "target_triple=", 14) == 0) { + char* target_triple = _target_triple; + size_t target_triple_size = sizeof(_target_triple); + target_triple_size -= 1; /*leave room for the null*/ + if (plen > target_triple_size) plen = target_triple_size; + strncpy(target_triple, p, plen); + target_triple[plen] = '\0'; + } + p = q; + } + } + + const char* native_target_triple() { + return LLVM_DEFAULT_TRIPLET; + } + + public: + hsdis_backend(uintptr_t start_va, uintptr_t end_va, + unsigned char* buffer, uintptr_t length, + event_callback_t event_callback, void* event_stream, + printf_callback_t printf_callback, void* printf_stream, + const char* options, int newline) + : hsdis_backend_base(start_va, end_va, + buffer, length, + event_callback, event_stream, + printf_callback, printf_stream, + newline), + _dcontext(NULL) { + /* Look into _options for anything interesting. */ + if (options != NULL) + parse_caller_options(options); + + /* Discover which architecture we are going to disassemble. */ + _arch_name = &_target_triple[0]; + if (_arch_name[0] == '\0') + _arch_name = native_target_triple(); + + if (LLVMInitializeNativeTarget() != 0) { + static bool complained = false; + if (!complained) + (*_printf_callback)(_printf_stream, "failed to initialize LLVM native target\n"); + complained = true; + /* must bail out */ + _losing = true; + return; + } + if (LLVMInitializeNativeAsmPrinter() != 0) { + static bool complained = false; + if (!complained) + (*_printf_callback)(_printf_stream, "failed to initialize LLVM native asm printer\n"); + complained = true; + /* must bail out */ + _losing = true; + return; + } + if (LLVMInitializeNativeDisassembler() != 0) { + static bool complained = false; + if (!complained) + (*_printf_callback)(_printf_stream, "failed to initialize LLVM native disassembler\n"); + complained = true; + /* must bail out */ + _losing = true; + return; + } + if ((_dcontext = LLVMCreateDisasm(_arch_name, NULL, 0, NULL, NULL)) == NULL) { + static bool complained = false; + const char* bad = _arch_name; + if (bad == &_target_triple[0]) + print_help("bad target_triple=%s", bad); + else if (!complained) + print_help("bad native target_triple=%s; please port hsdis to this platform", bad); + complained = true; + /* must bail out */ + _losing = true; + return; + } + + LLVMSetDisasmOptions(_dcontext, LLVMDisassembler_Option_PrintImmHex); + } + + ~hsdis_backend() { + if (_dcontext != NULL) { + LLVMDisasmDispose(_dcontext); + } + } + + protected: + virtual void print_help(const char* msg, const char* arg) { + if (msg != NULL) { + (*_printf_callback)(_printf_stream, "hsdis: "); + (*_printf_callback)(_printf_stream, msg, arg); + (*_printf_callback)(_printf_stream, "\n"); + } + (*_printf_callback)(_printf_stream, "hsdis output options:\n"); + (*_printf_callback)(_printf_stream, " target_triple=<triple> select disassembly target\n"); + (*_printf_callback)(_printf_stream, " help print this message\n"); + } + + virtual void print_insns_config() { + (*_event_callback)(_event_stream, "target_triple name='%s'", + (void*) _arch_name); + } + + virtual size_t decode_instruction(uintptr_t p, uintptr_t start, uintptr_t end) { + char buf[128]; + size_t size = LLVMDisasmInstruction(_dcontext, (uint8_t*)p, (uint64_t)(end - start), (uint64_t)p, buf, sizeof(buf)); + if (size > 0) { + (*_printf_callback)(_printf_stream, "%s", buf); + } else { + // LLVM encountered an unknown instruction + if (end - start >= 4) { + // Print the following word and skip past it + snprintf(buf, sizeof(buf), "\t.inst\t#0x%08x ; undefined", *(uint32_t*)p); + size = 4; + } else { + snprintf(buf, sizeof(buf), "\t<invalid instruction, aborting hsdis>"); + } + } + return size; + } + + virtual const char* format_insn_close(const char* close, char* buf, size_t bufsize) { + return close; + } +}; + + +void* decode_instructions_virtual(uintptr_t start_va, uintptr_t end_va, + unsigned char* buffer, uintptr_t length, + event_callback_t event_callback_arg, void* event_stream_arg, + printf_callback_t printf_callback_arg, void* printf_stream_arg, + const char* options, int newline) { + return hsdis_backend(start_va, end_va, + buffer, length, + event_callback_arg, event_stream_arg, + printf_callback_arg, printf_stream_arg, + options, newline == 0 ? false : true) + .decode(); +} + +/* This is the compatability interface for older version of hotspot */ +void* decode_instructions(void* start_pv, void* end_pv, + event_callback_t event_callback_arg, void* event_stream_arg, + printf_callback_t printf_callback_arg, void* printf_stream_arg, + const char* options) { + return decode_instructions_virtual((uintptr_t)start_pv, + (uintptr_t)end_pv, + (unsigned char*)start_pv, + (uintptr_t)end_pv - (uintptr_t)start_pv, + event_callback_arg, + event_stream_arg, + printf_callback_arg, + printf_stream_arg, + options, false); +} diff --git a/test/hotspot/gtest/aarch64/aarch64-asmtest.py b/test/hotspot/gtest/aarch64/aarch64-asmtest.py index a7df17b2129e941e8f3e69169757eb044db8043a..40892ae0d94f967b1014297ea53795c5254740d5 100644 --- a/test/hotspot/gtest/aarch64/aarch64-asmtest.py +++ b/test/hotspot/gtest/aarch64/aarch64-asmtest.py @@ -7,6 +7,55 @@ AARCH64_AS = "as" AARCH64_OBJDUMP = "objdump" AARCH64_OBJCOPY = "objcopy" +# These tables are legal immediate logical operands +immediates8 \ + = [0x1, 0x0c, 0x3e, 0x60, 0x7c, 0x80, 0x83, + 0xe1, 0xbf, 0xef, 0xf3, 0xfe] + +immediates16 \ + = [0x1, 0x38, 0x7e, 0xff, 0x1fc, 0x1ff, 0x3f0, + 0x7e0, 0xfc0, 0x1f80, 0x3ff0, 0x7e00, 0x7e00, + 0x8000, 0x81ff, 0xc1ff, 0xc003, 0xc7ff, 0xdfff, + 0xe03f, 0xe10f, 0xe1ff, 0xf801, 0xfc00, 0xfc07, + 0xff03, 0xfffe] + +immediates32 \ + = [0x1, 0x3f, 0x1f0, 0x7e0, + 0x1c00, 0x3ff0, 0x8000, 0x1e000, + 0x3e000, 0x78000, 0xe0000, 0x100000, + 0x1fffe0, 0x3fe000, 0x780000, 0x7ffff8, + 0xff8000, 0x1800180, 0x1fffc00, 0x3c003c0, + 0x3ffff00, 0x7c00000, 0x7fffe00, 0xf000f00, + 0xfffe000, 0x18181818, 0x1ffc0000, 0x1ffffffe, + 0x3f003f00, 0x3fffe000, 0x60006000, 0x7f807f80, + 0x7ffffc00, 0x800001ff, 0x803fffff, 0x9f9f9f9f, + 0xc0000fff, 0xc0c0c0c0, 0xe0000000, 0xe003e003, + 0xe3ffffff, 0xf0000fff, 0xf0f0f0f0, 0xf80000ff, + 0xf83ff83f, 0xfc00007f, 0xfc1fffff, 0xfe0001ff, + 0xfe3fffff, 0xff003fff, 0xff800003, 0xff87ff87, + 0xffc00fff, 0xffe0000f, 0xffefffef, 0xfff1fff1, + 0xfff83fff, 0xfffc0fff, 0xfffe0fff, 0xffff3fff, + 0xffffc007, 0xffffe1ff, 0xfffff80f, 0xfffffe07, + 0xffffffbf, 0xfffffffd] + +immediates64 \ + = [0x1, 0x1f80, 0x3fff0, 0x3ffffc, + 0x3fe0000, 0x1ffc0000, 0xf8000000, 0x3ffffc000, + 0xffffffe00, 0x3ffffff800, 0xffffc00000, 0x3f000000000, + 0x7fffffff800, 0x1fe000001fe0, 0x3ffffff80000, 0xc00000000000, + 0x1ffc000000000, 0x3ffff0003ffff, 0x7ffffffe00000, 0xfffffffffc000, + 0x1ffffffffffc00, 0x3fffffffffff00, 0x7ffffffffffc00, 0xffffffffff8000, + 0x1ffffffff800000, 0x3fffffc03fffffc, 0x7fffc0000000000, 0xff80ff80ff80ff8, + 0x1c00000000000000, 0x1fffffffffff0000, 0x3fffff803fffff80, 0x7fc000007fc00000, + 0x8000000000000000, 0x803fffff803fffff, 0xc000007fc000007f, 0xe00000000000ffff, + 0xe3ffffffffffffff, 0xf007f007f007f007, 0xf80003ffffffffff, 0xfc000003fc000003, + 0xfe000000007fffff, 0xff00000000007fff, 0xff800000000003ff, 0xffc00000000000ff, + 0xffe00000000003ff, 0xfff0000000003fff, 0xfff80000001fffff, 0xfffc0000fffc0000, + 0xfffe003fffffffff, 0xffff3fffffffffff, 0xffffc0000007ffff, 0xffffe01fffffe01f, + 0xfffff800000007ff, 0xfffffc0fffffffff, 0xffffff00003fffff, 0xffffffc0000007ff, + 0xfffffff0000001ff, 0xfffffffc00003fff, 0xffffffff07ffffff, 0xffffffffe003ffff, + 0xfffffffffc01ffff, 0xffffffffffc00003, 0xfffffffffffc000f, 0xffffffffffffe07f] + class Operand(object): def generate(self): @@ -160,15 +209,17 @@ class Instruction(object): self._name = name self.isWord = name.endswith("w") | name.endswith("wi") self.asmRegPrefix = ["x", "w"][self.isWord] + self.isPostfixException = False def aname(self): - if (self._name.endswith("wi")): + if self.isPostfixException: + return self._name + elif (self._name.endswith("wi")): return self._name[:len(self._name)-2] + elif (self._name.endswith("i") | self._name.endswith("w")): + return self._name[:len(self._name)-1] else: - if (self._name.endswith("i") | self._name.endswith("w")): - return self._name[:len(self._name)-1] - else: - return self._name + return self._name def emit(self) : pass @@ -299,6 +350,12 @@ class OneRegOp(Instruction): return (super(OneRegOp, self).astr() + '%s' % self.reg.astr(self.asmRegPrefix)) +class PostfixExceptionOneRegOp(OneRegOp): + + def __init__(self, op): + OneRegOp.__init__(self, op) + self.isPostfixException=True + class ArithOp(ThreeRegInstruction): def generate(self): @@ -351,51 +408,12 @@ class AddSubImmOp(TwoRegImmedInstruction): return super(AddSubImmOp, self).cstr() + ");" class LogicalImmOp(AddSubImmOp): - - # These tables are legal immediate logical operands - immediates32 \ - = [0x1, 0x3f, 0x1f0, 0x7e0, - 0x1c00, 0x3ff0, 0x8000, 0x1e000, - 0x3e000, 0x78000, 0xe0000, 0x100000, - 0x1fffe0, 0x3fe000, 0x780000, 0x7ffff8, - 0xff8000, 0x1800180, 0x1fffc00, 0x3c003c0, - 0x3ffff00, 0x7c00000, 0x7fffe00, 0xf000f00, - 0xfffe000, 0x18181818, 0x1ffc0000, 0x1ffffffe, - 0x3f003f00, 0x3fffe000, 0x60006000, 0x7f807f80, - 0x7ffffc00, 0x800001ff, 0x803fffff, 0x9f9f9f9f, - 0xc0000fff, 0xc0c0c0c0, 0xe0000000, 0xe003e003, - 0xe3ffffff, 0xf0000fff, 0xf0f0f0f0, 0xf80000ff, - 0xf83ff83f, 0xfc00007f, 0xfc1fffff, 0xfe0001ff, - 0xfe3fffff, 0xff003fff, 0xff800003, 0xff87ff87, - 0xffc00fff, 0xffe0000f, 0xffefffef, 0xfff1fff1, - 0xfff83fff, 0xfffc0fff, 0xfffe0fff, 0xffff3fff, - 0xffffc007, 0xffffe1ff, 0xfffff80f, 0xfffffe07, - 0xffffffbf, 0xfffffffd] - - immediates \ - = [0x1, 0x1f80, 0x3fff0, 0x3ffffc, - 0x3fe0000, 0x1ffc0000, 0xf8000000, 0x3ffffc000, - 0xffffffe00, 0x3ffffff800, 0xffffc00000, 0x3f000000000, - 0x7fffffff800, 0x1fe000001fe0, 0x3ffffff80000, 0xc00000000000, - 0x1ffc000000000, 0x3ffff0003ffff, 0x7ffffffe00000, 0xfffffffffc000, - 0x1ffffffffffc00, 0x3fffffffffff00, 0x7ffffffffffc00, 0xffffffffff8000, - 0x1ffffffff800000, 0x3fffffc03fffffc, 0x7fffc0000000000, 0xff80ff80ff80ff8, - 0x1c00000000000000, 0x1fffffffffff0000, 0x3fffff803fffff80, 0x7fc000007fc00000, - 0x8000000000000000, 0x803fffff803fffff, 0xc000007fc000007f, 0xe00000000000ffff, - 0xe3ffffffffffffff, 0xf007f007f007f007, 0xf80003ffffffffff, 0xfc000003fc000003, - 0xfe000000007fffff, 0xff00000000007fff, 0xff800000000003ff, 0xffc00000000000ff, - 0xffe00000000003ff, 0xfff0000000003fff, 0xfff80000001fffff, 0xfffc0000fffc0000, - 0xfffe003fffffffff, 0xffff3fffffffffff, 0xffffc0000007ffff, 0xffffe01fffffe01f, - 0xfffff800000007ff, 0xfffffc0fffffffff, 0xffffff00003fffff, 0xffffffc0000007ff, - 0xfffffff0000001ff, 0xfffffffc00003fff, 0xffffffff07ffffff, 0xffffffffe003ffff, - 0xfffffffffc01ffff, 0xffffffffffc00003, 0xfffffffffffc000f, 0xffffffffffffe07f] - def generate(self): AddSubImmOp.generate(self) self.immed = \ - self.immediates32[random.randint(0, len(self.immediates32)-1)] \ + immediates32[random.randint(0, len(immediates32)-1)] \ if self.isWord else \ - self.immediates[random.randint(0, len(self.immediates)-1)] + immediates64[random.randint(0, len(immediates64)-1)] return self @@ -406,6 +424,44 @@ class LogicalImmOp(AddSubImmOp): def cstr(self): return super(AddSubImmOp, self).cstr() + "ll);" +class SVEBinaryImmOp(Instruction): + def __init__(self, name): + reg = SVEVectorRegister().generate() + self.reg = [reg, reg] + self.numRegs = len(self.reg) + self._width = RegVariant(0, 3) + self._isLogical = False + if name in ["and", "eor", "orr"]: + self._isLogical = True + Instruction.__init__(self, name) + + def generate(self): + Instruction.generate(self) + self.immed = random.randint(0, (1<<8)-1) + if self._isLogical: + vectype = self._width.cstr() + if vectype == "__ B": + self.immed = immediates8[random.randint(0, len(immediates8)-1)] + elif vectype == "__ H": + self.immed = immediates16[random.randint(0, len(immediates16)-1)] + elif vectype == "__ S": + self.immed = immediates32[random.randint(0, len(immediates32)-1)] + elif vectype == "__ D": + self.immed = immediates64[random.randint(0, len(immediates64)-1)] + return self + + def cstr(self): + formatStr = "%s%s, %s, %su);" + return (formatStr + % tuple(["__ sve_" + self._name + "("] + + [str(self.reg[0]), self._width.cstr(), self.immed])) + + def astr(self): + formatStr = "%s%s, %s, #0x%x" + Regs = [str(self.reg[i]) + self._width.astr() for i in range(0, self.numRegs)] + return (formatStr + % tuple([Instruction.astr(self)] + Regs + [self.immed])) + class MultiOp(): def multipleForms(self): @@ -549,6 +605,13 @@ class Op(Instruction): def astr(self): return self.aname(); + +class PostfixExceptionOp(Op): + + def __init__(self, op): + Op.__init__(self, op) + self.isPostfixException=True + class SystemOp(Instruction): def __init__(self, op): @@ -1287,14 +1350,26 @@ generate (CondBranchOp, ["EQ", "NE", "HS", "CS", "LO", "CC", "MI", "PL", "VS", " generate (ImmOp, ["svc", "hvc", "smc", "brk", "hlt", # "dcps1", "dcps2", "dcps3" ]) -generate (Op, ["nop", "eret", "drps", "isb"]) +generate (Op, ["nop", "yield", "wfe", "sev", "sevl", + "autia1716", "autiasp", "autiaz", "autib1716", "autibsp", "autibz", + "pacia1716", "paciasp", "paciaz", "pacib1716", "pacibsp", "pacibz", + "eret", "drps", "isb",]) + +# Ensure the "i" is not stripped off the end of the instruction +generate (PostfixExceptionOp, ["wfi", "xpaclri"]) barriers = ["OSHLD", "OSHST", "OSH", "NSHLD", "NSHST", "NSH", "ISHLD", "ISHST", "ISH", "LD", "ST", "SY"] generate (SystemOp, [["dsb", barriers], ["dmb", barriers]]) -generate (OneRegOp, ["br", "blr"]) +generate (OneRegOp, ["br", "blr", + "paciza", "pacizb", "pacdza", "pacdzb", + "autiza", "autizb", "autdza", "autdzb", "xpacd", + "braaz", "brabz", "blraaz", "blrabz"]) + +# Ensure the "i" is not stripped off the end of the instruction +generate (PostfixExceptionOneRegOp, ["xpaci"]) for mode in 'xwhb': generate (LoadStoreExclusiveOp, [["stxr", mode, 3], ["stlxr", mode, 3], @@ -1339,7 +1414,10 @@ generate(ConditionalSelectOp, generate(TwoRegOp, ["rbitw", "rev16w", "revw", "clzw", "clsw", "rbit", - "rev16", "rev32", "rev", "clz", "cls"]) + "rev16", "rev32", "rev", "clz", "cls", + "pacia", "pacib", "pacda", "pacdb", "autia", "autib", "autda", "autdb", + "braa", "brab", "blraa", "blrab"]) + generate(ThreeRegOp, ["udivw", "sdivw", "lslvw", "lsrvw", "asrvw", "rorvw", "udiv", "sdiv", "lslv", "lsrv", "asrv", "rorv", "umulh", "smulh"]) @@ -1523,10 +1601,10 @@ generate(SpecialCases, [["ccmn", "__ ccmn(zr, zr, 3u, Assembler::LE);", ["stxpw", "__ stxpw(r6, zr, zr, sp);", "stxp\tw6, wzr, wzr, [sp]"], ["dup", "__ dup(v0, __ T16B, zr);", "dup\tv0.16b, wzr"], ["dup", "__ dup(v0, __ S, v1);", "dup\ts0, v1.s[0]"], - ["mov", "__ mov(v1, __ T1D, 0, zr);", "mov\tv1.d[0], xzr"], - ["mov", "__ mov(v1, __ T2S, 1, zr);", "mov\tv1.s[1], wzr"], - ["mov", "__ mov(v1, __ T4H, 2, zr);", "mov\tv1.h[2], wzr"], - ["mov", "__ mov(v1, __ T8B, 3, zr);", "mov\tv1.b[3], wzr"], + ["mov", "__ mov(v1, __ D, 0, zr);", "mov\tv1.d[0], xzr"], + ["mov", "__ mov(v1, __ S, 1, zr);", "mov\tv1.s[1], wzr"], + ["mov", "__ mov(v1, __ H, 2, zr);", "mov\tv1.h[2], wzr"], + ["mov", "__ mov(v1, __ B, 3, zr);", "mov\tv1.b[3], wzr"], ["smov", "__ smov(r0, v1, __ S, 0);", "smov\tx0, v1.s[0]"], ["smov", "__ smov(r0, v1, __ H, 1);", "smov\tx0, v1.h[1]"], ["smov", "__ smov(r0, v1, __ B, 2);", "smov\tx0, v1.b[2]"], @@ -1675,9 +1753,22 @@ generate(SpecialCases, [["ccmn", "__ ccmn(zr, zr, 3u, Assembler::LE);", ["bic", "__ sve_bic(p10, p7, p9, p11);", "bic\tp10.b, p7/z, p9.b, p11.b"], ["ptest", "__ sve_ptest(p7, p1);", "ptest\tp7, p1.b"], ["ptrue", "__ sve_ptrue(p1, __ B);", "ptrue\tp1.b"], + ["ptrue", "__ sve_ptrue(p1, __ B, 0b00001);", "ptrue\tp1.b, vl1"], + ["ptrue", "__ sve_ptrue(p1, __ B, 0b00101);", "ptrue\tp1.b, vl5"], + ["ptrue", "__ sve_ptrue(p1, __ B, 0b01001);", "ptrue\tp1.b, vl16"], + ["ptrue", "__ sve_ptrue(p1, __ B, 0b01101);", "ptrue\tp1.b, vl256"], ["ptrue", "__ sve_ptrue(p2, __ H);", "ptrue\tp2.h"], + ["ptrue", "__ sve_ptrue(p2, __ H, 0b00010);", "ptrue\tp2.h, vl2"], + ["ptrue", "__ sve_ptrue(p2, __ H, 0b00110);", "ptrue\tp2.h, vl6"], + ["ptrue", "__ sve_ptrue(p2, __ H, 0b01010);", "ptrue\tp2.h, vl32"], ["ptrue", "__ sve_ptrue(p3, __ S);", "ptrue\tp3.s"], + ["ptrue", "__ sve_ptrue(p3, __ S, 0b00011);", "ptrue\tp3.s, vl3"], + ["ptrue", "__ sve_ptrue(p3, __ S, 0b00111);", "ptrue\tp3.s, vl7"], + ["ptrue", "__ sve_ptrue(p3, __ S, 0b01011);", "ptrue\tp3.s, vl64"], ["ptrue", "__ sve_ptrue(p4, __ D);", "ptrue\tp4.d"], + ["ptrue", "__ sve_ptrue(p4, __ D, 0b00100);", "ptrue\tp4.d, vl4"], + ["ptrue", "__ sve_ptrue(p4, __ D, 0b01000);", "ptrue\tp4.d, vl8"], + ["ptrue", "__ sve_ptrue(p4, __ D, 0b01100);", "ptrue\tp4.d, vl128"], ["pfalse", "__ sve_pfalse(p7);", "pfalse\tp7.b"], ["uzp1", "__ sve_uzp1(p0, __ B, p0, p1);", "uzp1\tp0.b, p0.b, p1.b"], ["uzp1", "__ sve_uzp1(p0, __ H, p0, p1);", "uzp1\tp0.h, p0.h, p1.h"], @@ -1719,6 +1810,9 @@ generate(SHA3SIMDOp, ["bcax", "eor3", "rax1", "xar"]) generate(SHA512SIMDOp, ["sha512h", "sha512h2", "sha512su0", "sha512su1"]) +for i in range(6): + generate(SVEBinaryImmOp, ["add", "sub", "and", "eor", "orr"]) + generate(SVEVectorOp, [["add", "ZZZ"], ["sub", "ZZZ"], ["fadd", "ZZZ"], @@ -1728,6 +1822,7 @@ generate(SVEVectorOp, [["add", "ZZZ"], ["add", "ZPZ", "m", "dn"], ["and", "ZPZ", "m", "dn"], ["asr", "ZPZ", "m", "dn"], + ["bic", "ZPZ", "m", "dn"], ["cnt", "ZPZ", "m"], ["eor", "ZPZ", "m", "dn"], ["lsl", "ZPZ", "m", "dn"], @@ -1774,8 +1869,8 @@ outfile.write("forth:\n") outfile.close() -# compile for sve with 8.2 and sha3 because of SHA3 crypto extension. -subprocess.check_call([AARCH64_AS, "-march=armv8.2-a+sha3+sve", "aarch64ops.s", "-o", "aarch64ops.o"]) +# compile for sve with 8.3 and sha3 because of SHA3 crypto extension. +subprocess.check_call([AARCH64_AS, "-march=armv8.3-a+sha3+sve", "aarch64ops.s", "-o", "aarch64ops.o"]) print print "/*" diff --git a/test/hotspot/gtest/aarch64/asmtest.out.h b/test/hotspot/gtest/aarch64/asmtest.out.h index 85aca7268f48ef2edab498560cc43c97b7fb6e6a..03147cba0496c128153a5cd378dc76c677bf748c 100644 --- a/test/hotspot/gtest/aarch64/asmtest.out.h +++ b/test/hotspot/gtest/aarch64/asmtest.out.h @@ -168,10 +168,30 @@ // Op __ nop(); // nop + __ yield(); // yield + __ wfe(); // wfe + __ sev(); // sev + __ sevl(); // sevl + __ autia1716(); // autia1716 + __ autiasp(); // autiasp + __ autiaz(); // autiaz + __ autib1716(); // autib1716 + __ autibsp(); // autibsp + __ autibz(); // autibz + __ pacia1716(); // pacia1716 + __ paciasp(); // paciasp + __ paciaz(); // paciaz + __ pacib1716(); // pacib1716 + __ pacibsp(); // pacibsp + __ pacibz(); // pacibz __ eret(); // eret __ drps(); // drps __ isb(); // isb +// PostfixExceptionOp + __ wfi(); // wfi + __ xpaclri(); // xpaclri + // SystemOp __ dsb(Assembler::ST); // dsb ST __ dmb(Assembler::OSHST); // dmb OSHST @@ -179,527 +199,555 @@ // OneRegOp __ br(r16); // br x16 __ blr(r20); // blr x20 + __ paciza(r10); // paciza x10 + __ pacizb(r27); // pacizb x27 + __ pacdza(r8); // pacdza x8 + __ pacdzb(r0); // pacdzb x0 + __ autiza(r1); // autiza x1 + __ autizb(r21); // autizb x21 + __ autdza(r17); // autdza x17 + __ autdzb(r29); // autdzb x29 + __ xpacd(r29); // xpacd x29 + __ braaz(r28); // braaz x28 + __ brabz(r1); // brabz x1 + __ blraaz(r23); // blraaz x23 + __ blrabz(r21); // blrabz x21 + +// PostfixExceptionOneRegOp + __ xpaci(r20); // xpaci x20 // LoadStoreExclusiveOp - __ stxr(r10, r27, r8); // stxr w10, x27, [x8] - __ stlxr(r0, r1, r21); // stlxr w0, x1, [x21] - __ ldxr(r17, r29); // ldxr x17, [x29] - __ ldaxr(r29, r28); // ldaxr x29, [x28] - __ stlr(r1, r23); // stlr x1, [x23] - __ ldar(r21, r20); // ldar x21, [x20] + __ stxr(r22, r27, r19); // stxr w22, x27, [x19] + __ stlxr(r11, r16, r6); // stlxr w11, x16, [x6] + __ ldxr(r17, r0); // ldxr x17, [x0] + __ ldaxr(r4, r10); // ldaxr x4, [x10] + __ stlr(r24, r22); // stlr x24, [x22] + __ ldar(r10, r19); // ldar x10, [x19] // LoadStoreExclusiveOp - __ stxrw(r22, r27, r19); // stxr w22, w27, [x19] - __ stlxrw(r11, r16, r6); // stlxr w11, w16, [x6] - __ ldxrw(r17, r0); // ldxr w17, [x0] - __ ldaxrw(r4, r10); // ldaxr w4, [x10] - __ stlrw(r24, r22); // stlr w24, [x22] - __ ldarw(r10, r19); // ldar w10, [x19] + __ stxrw(r1, r5, r30); // stxr w1, w5, [x30] + __ stlxrw(r8, r12, r17); // stlxr w8, w12, [x17] + __ ldxrw(r9, r14); // ldxr w9, [x14] + __ ldaxrw(r7, r1); // ldaxr w7, [x1] + __ stlrw(r5, r16); // stlr w5, [x16] + __ ldarw(r2, r12); // ldar w2, [x12] // LoadStoreExclusiveOp - __ stxrh(r1, r5, r30); // stxrh w1, w5, [x30] - __ stlxrh(r8, r12, r17); // stlxrh w8, w12, [x17] - __ ldxrh(r9, r14); // ldxrh w9, [x14] - __ ldaxrh(r7, r1); // ldaxrh w7, [x1] - __ stlrh(r5, r16); // stlrh w5, [x16] - __ ldarh(r2, r12); // ldarh w2, [x12] + __ stxrh(r10, r12, r3); // stxrh w10, w12, [x3] + __ stlxrh(r28, r14, r26); // stlxrh w28, w14, [x26] + __ ldxrh(r30, r10); // ldxrh w30, [x10] + __ ldaxrh(r14, r21); // ldaxrh w14, [x21] + __ stlrh(r13, r9); // stlrh w13, [x9] + __ ldarh(r22, r27); // ldarh w22, [x27] // LoadStoreExclusiveOp - __ stxrb(r10, r12, r3); // stxrb w10, w12, [x3] - __ stlxrb(r28, r14, r26); // stlxrb w28, w14, [x26] - __ ldxrb(r30, r10); // ldxrb w30, [x10] - __ ldaxrb(r14, r21); // ldaxrb w14, [x21] - __ stlrb(r13, r9); // stlrb w13, [x9] - __ ldarb(r22, r27); // ldarb w22, [x27] + __ stxrb(r28, r19, r11); // stxrb w28, w19, [x11] + __ stlxrb(r30, r19, r2); // stlxrb w30, w19, [x2] + __ ldxrb(r2, r23); // ldxrb w2, [x23] + __ ldaxrb(r1, r0); // ldaxrb w1, [x0] + __ stlrb(r12, r16); // stlrb w12, [x16] + __ ldarb(r13, r15); // ldarb w13, [x15] // LoadStoreExclusiveOp - __ ldxp(r28, r19, r11); // ldxp x28, x19, [x11] - __ ldaxp(r30, r19, r2); // ldaxp x30, x19, [x2] - __ stxp(r2, r23, r1, r0); // stxp w2, x23, x1, [x0] - __ stlxp(r12, r16, r13, r15); // stlxp w12, x16, x13, [x15] + __ ldxp(r17, r21, r13); // ldxp x17, x21, [x13] + __ ldaxp(r11, r30, r8); // ldaxp x11, x30, [x8] + __ stxp(r24, r13, r11, r1); // stxp w24, x13, x11, [x1] + __ stlxp(r26, r21, r27, r13); // stlxp w26, x21, x27, [x13] // LoadStoreExclusiveOp - __ ldxpw(r17, r21, r13); // ldxp w17, w21, [x13] - __ ldaxpw(r11, r30, r8); // ldaxp w11, w30, [x8] - __ stxpw(r24, r13, r11, r1); // stxp w24, w13, w11, [x1] - __ stlxpw(r26, r21, r27, r13); // stlxp w26, w21, w27, [x13] + __ ldxpw(r20, r3, r12); // ldxp w20, w3, [x12] + __ ldaxpw(r6, r1, r29); // ldaxp w6, w1, [x29] + __ stxpw(r6, r4, r11, r16); // stxp w6, w4, w11, [x16] + __ stlxpw(r4, r30, r12, r21); // stlxp w4, w30, w12, [x21] // base_plus_unscaled_offset // LoadStoreOp - __ str(r11, Address(r20, -103)); // str x11, [x20, -103] - __ strw(r28, Address(r16, 62)); // str w28, [x16, 62] - __ strb(r27, Address(r9, -9)); // strb w27, [x9, -9] - __ strh(r2, Address(r25, -50)); // strh w2, [x25, -50] - __ ldr(r4, Address(r2, -241)); // ldr x4, [x2, -241] - __ ldrw(r30, Address(r20, -31)); // ldr w30, [x20, -31] - __ ldrb(r17, Address(r23, -23)); // ldrb w17, [x23, -23] - __ ldrh(r29, Address(r26, -1)); // ldrh w29, [x26, -1] - __ ldrsb(r1, Address(r9, 6)); // ldrsb x1, [x9, 6] - __ ldrsh(r11, Address(r12, 19)); // ldrsh x11, [x12, 19] - __ ldrshw(r11, Address(r1, -50)); // ldrsh w11, [x1, -50] - __ ldrsw(r19, Address(r24, 41)); // ldrsw x19, [x24, 41] - __ ldrd(v24, Address(r24, 95)); // ldr d24, [x24, 95] - __ ldrs(v15, Address(r5, -43)); // ldr s15, [x5, -43] - __ strd(v21, Address(r27, 1)); // str d21, [x27, 1] - __ strs(v23, Address(r13, -107)); // str s23, [x13, -107] + __ str(r6, Address(r27, 97)); // str x6, [x27, 97] + __ strw(r17, Address(r10, 45)); // str w17, [x10, 45] + __ strb(r26, Address(r22, -29)); // strb w26, [x22, -29] + __ strh(r21, Address(r10, -50)); // strh w21, [x10, -50] + __ ldr(r14, Address(r24, 125)); // ldr x14, [x24, 125] + __ ldrw(r7, Address(r24, -16)); // ldr w7, [x24, -16] + __ ldrb(r8, Address(r2, 13)); // ldrb w8, [x2, 13] + __ ldrh(r30, Address(r25, -61)); // ldrh w30, [x25, -61] + __ ldrsb(r3, Address(r12, -14)); // ldrsb x3, [x12, -14] + __ ldrsh(r10, Address(r17, -28)); // ldrsh x10, [x17, -28] + __ ldrshw(r21, Address(r3, -5)); // ldrsh w21, [x3, -5] + __ ldrsw(r2, Address(r25, 23)); // ldrsw x2, [x25, 23] + __ ldrd(v25, Address(r1, -69)); // ldr d25, [x1, -69] + __ ldrs(v29, Address(r27, 6)); // ldr s29, [x27, 6] + __ strd(v29, Address(r12, 41)); // str d29, [x12, 41] + __ strs(v2, Address(r22, -115)); // str s2, [x22, -115] // pre // LoadStoreOp - __ str(r10, Address(__ pre(r0, 8))); // str x10, [x0, 8]! - __ strw(r3, Address(__ pre(r0, 29))); // str w3, [x0, 29]! - __ strb(r10, Address(__ pre(r14, 9))); // strb w10, [x14, 9]! - __ strh(r29, Address(__ pre(r25, -3))); // strh w29, [x25, -3]! - __ ldr(r12, Address(__ pre(r16, -144))); // ldr x12, [x16, -144]! - __ ldrw(r12, Address(__ pre(r22, -6))); // ldr w12, [x22, -6]! - __ ldrb(r13, Address(__ pre(r11, -10))); // ldrb w13, [x11, -10]! - __ ldrh(r0, Address(__ pre(r21, -21))); // ldrh w0, [x21, -21]! - __ ldrsb(r23, Address(__ pre(r6, 4))); // ldrsb x23, [x6, 4]! - __ ldrsh(r3, Address(__ pre(r7, -53))); // ldrsh x3, [x7, -53]! - __ ldrshw(r28, Address(__ pre(r4, -7))); // ldrsh w28, [x4, -7]! - __ ldrsw(r24, Address(__ pre(r8, -18))); // ldrsw x24, [x8, -18]! - __ ldrd(v14, Address(__ pre(r11, 12))); // ldr d14, [x11, 12]! - __ ldrs(v19, Address(__ pre(r12, -67))); // ldr s19, [x12, -67]! - __ strd(v20, Address(__ pre(r0, -253))); // str d20, [x0, -253]! - __ strs(v8, Address(__ pre(r0, 64))); // str s8, [x0, 64]! + __ str(r26, Address(__ pre(r5, 3))); // str x26, [x5, 3]! + __ strw(r20, Address(__ pre(r5, -103))); // str w20, [x5, -103]! + __ strb(r8, Address(__ pre(r12, -25))); // strb w8, [x12, -25]! + __ strh(r20, Address(__ pre(r2, -57))); // strh w20, [x2, -57]! + __ ldr(r14, Address(__ pre(r29, -234))); // ldr x14, [x29, -234]! + __ ldrw(r13, Address(__ pre(r29, 4))); // ldr w13, [x29, 4]! + __ ldrb(r24, Address(__ pre(r19, -9))); // ldrb w24, [x19, -9]! + __ ldrh(r3, Address(__ pre(r27, -19))); // ldrh w3, [x27, -19]! + __ ldrsb(r17, Address(__ pre(r1, -5))); // ldrsb x17, [x1, -5]! + __ ldrsh(r17, Address(__ pre(r19, -13))); // ldrsh x17, [x19, -13]! + __ ldrshw(r21, Address(__ pre(r11, -26))); // ldrsh w21, [x11, -26]! + __ ldrsw(r1, Address(__ pre(r9, -60))); // ldrsw x1, [x9, -60]! + __ ldrd(v26, Address(__ pre(r23, -247))); // ldr d26, [x23, -247]! + __ ldrs(v22, Address(__ pre(r21, -127))); // ldr s22, [x21, -127]! + __ strd(v13, Address(__ pre(r7, -216))); // str d13, [x7, -216]! + __ strs(v12, Address(__ pre(r13, -104))); // str s12, [x13, -104]! // post // LoadStoreOp - __ str(r3, Address(__ post(r28, -94))); // str x3, [x28], -94 - __ strw(r11, Address(__ post(r7, -54))); // str w11, [x7], -54 - __ strb(r27, Address(__ post(r10, -24))); // strb w27, [x10], -24 - __ strh(r6, Address(__ post(r7, 27))); // strh w6, [x7], 27 - __ ldr(r13, Address(__ post(r10, -202))); // ldr x13, [x10], -202 - __ ldrw(r15, Address(__ post(r5, -41))); // ldr w15, [x5], -41 - __ ldrb(r2, Address(__ post(r13, 9))); // ldrb w2, [x13], 9 - __ ldrh(r28, Address(__ post(r13, -20))); // ldrh w28, [x13], -20 - __ ldrsb(r9, Address(__ post(r13, -31))); // ldrsb x9, [x13], -31 - __ ldrsh(r3, Address(__ post(r24, -36))); // ldrsh x3, [x24], -36 - __ ldrshw(r20, Address(__ post(r3, 6))); // ldrsh w20, [x3], 6 - __ ldrsw(r7, Address(__ post(r19, -1))); // ldrsw x7, [x19], -1 - __ ldrd(v30, Address(__ post(r8, -130))); // ldr d30, [x8], -130 - __ ldrs(v25, Address(__ post(r15, 21))); // ldr s25, [x15], 21 - __ strd(v14, Address(__ post(r23, 90))); // str d14, [x23], 90 - __ strs(v8, Address(__ post(r0, -33))); // str s8, [x0], -33 + __ str(r20, Address(__ post(r5, -237))); // str x20, [x5], -237 + __ strw(r29, Address(__ post(r28, -74))); // str w29, [x28], -74 + __ strb(r4, Address(__ post(r24, -22))); // strb w4, [x24], -22 + __ strh(r13, Address(__ post(r9, -21))); // strh w13, [x9], -21 + __ ldr(r26, Address(__ post(r7, -55))); // ldr x26, [x7], -55 + __ ldrw(r13, Address(__ post(r3, -115))); // ldr w13, [x3], -115 + __ ldrb(r1, Address(__ post(r5, 12))); // ldrb w1, [x5], 12 + __ ldrh(r8, Address(__ post(r13, -34))); // ldrh w8, [x13], -34 + __ ldrsb(r23, Address(__ post(r20, -27))); // ldrsb x23, [x20], -27 + __ ldrsh(r20, Address(__ post(r6, -2))); // ldrsh x20, [x6], -2 + __ ldrshw(r9, Address(__ post(r17, -42))); // ldrsh w9, [x17], -42 + __ ldrsw(r21, Address(__ post(r6, -30))); // ldrsw x21, [x6], -30 + __ ldrd(v16, Address(__ post(r22, -29))); // ldr d16, [x22], -29 + __ ldrs(v9, Address(__ post(r11, -3))); // ldr s9, [x11], -3 + __ strd(v22, Address(__ post(r26, 60))); // str d22, [x26], 60 + __ strs(v16, Address(__ post(r29, -2))); // str s16, [x29], -2 // base_plus_reg // LoadStoreOp - __ str(r10, Address(r17, r21, Address::sxtw(3))); // str x10, [x17, w21, sxtw #3] - __ strw(r4, Address(r13, r22, Address::sxtw(2))); // str w4, [x13, w22, sxtw #2] - __ strb(r13, Address(r0, r19, Address::uxtw(0))); // strb w13, [x0, w19, uxtw #0] - __ strh(r12, Address(r27, r6, Address::sxtw(0))); // strh w12, [x27, w6, sxtw #0] - __ ldr(r0, Address(r8, r16, Address::lsl(0))); // ldr x0, [x8, x16, lsl #0] - __ ldrw(r0, Address(r4, r26, Address::sxtx(0))); // ldr w0, [x4, x26, sxtx #0] - __ ldrb(r14, Address(r25, r5, Address::sxtw(0))); // ldrb w14, [x25, w5, sxtw #0] - __ ldrh(r9, Address(r4, r17, Address::uxtw(0))); // ldrh w9, [x4, w17, uxtw #0] - __ ldrsb(r27, Address(r4, r7, Address::lsl(0))); // ldrsb x27, [x4, x7, lsl #0] - __ ldrsh(r15, Address(r17, r30, Address::sxtw(0))); // ldrsh x15, [x17, w30, sxtw #0] - __ ldrshw(r16, Address(r0, r22, Address::sxtw(0))); // ldrsh w16, [x0, w22, sxtw #0] - __ ldrsw(r22, Address(r10, r30, Address::sxtx(2))); // ldrsw x22, [x10, x30, sxtx #2] - __ ldrd(v29, Address(r21, r10, Address::sxtx(3))); // ldr d29, [x21, x10, sxtx #3] - __ ldrs(v3, Address(r11, r19, Address::uxtw(0))); // ldr s3, [x11, w19, uxtw #0] - __ strd(v13, Address(r28, r29, Address::uxtw(3))); // str d13, [x28, w29, uxtw #3] - __ strs(v23, Address(r29, r5, Address::sxtx(2))); // str s23, [x29, x5, sxtx #2] + __ str(r1, Address(r22, r4, Address::sxtw(0))); // str x1, [x22, w4, sxtw #0] + __ strw(r23, Address(r30, r13, Address::lsl(2))); // str w23, [x30, x13, lsl #2] + __ strb(r12, Address(r11, r12, Address::uxtw(0))); // strb w12, [x11, w12, uxtw #0] + __ strh(r25, Address(r12, r0, Address::lsl(1))); // strh w25, [x12, x0, lsl #1] + __ ldr(r17, Address(r7, r0, Address::uxtw(3))); // ldr x17, [x7, w0, uxtw #3] + __ ldrw(r1, Address(r19, r14, Address::uxtw(2))); // ldr w1, [x19, w14, uxtw #2] + __ ldrb(r12, Address(r2, r9, Address::lsl(0))); // ldrb w12, [x2, x9, lsl #0] + __ ldrh(r22, Address(r9, r27, Address::sxtw(0))); // ldrh w22, [x9, w27, sxtw #0] + __ ldrsb(r21, Address(r12, r15, Address::sxtx(0))); // ldrsb x21, [x12, x15, sxtx #0] + __ ldrsh(r28, Address(r6, r16, Address::lsl(1))); // ldrsh x28, [x6, x16, lsl #1] + __ ldrshw(r25, Address(r17, r22, Address::sxtw(0))); // ldrsh w25, [x17, w22, sxtw #0] + __ ldrsw(r4, Address(r17, r29, Address::sxtx(0))); // ldrsw x4, [x17, x29, sxtx #0] + __ ldrd(v5, Address(r1, r3, Address::sxtx(3))); // ldr d5, [x1, x3, sxtx #3] + __ ldrs(v24, Address(r17, r13, Address::uxtw(2))); // ldr s24, [x17, w13, uxtw #2] + __ strd(v17, Address(r17, r23, Address::sxtx(3))); // str d17, [x17, x23, sxtx #3] + __ strs(v17, Address(r30, r5, Address::sxtw(2))); // str s17, [x30, w5, sxtw #2] // base_plus_scaled_offset // LoadStoreOp - __ str(r5, Address(r8, 12600)); // str x5, [x8, 12600] - __ strw(r29, Address(r24, 7880)); // str w29, [x24, 7880] - __ strb(r19, Address(r17, 1566)); // strb w19, [x17, 1566] - __ strh(r13, Address(r19, 3984)); // strh w13, [x19, 3984] - __ ldr(r19, Address(r23, 13632)); // ldr x19, [x23, 13632] - __ ldrw(r23, Address(r29, 6264)); // ldr w23, [x29, 6264] - __ ldrb(r22, Address(r11, 2012)); // ldrb w22, [x11, 2012] - __ ldrh(r3, Address(r10, 3784)); // ldrh w3, [x10, 3784] - __ ldrsb(r8, Address(r16, 1951)); // ldrsb x8, [x16, 1951] - __ ldrsh(r23, Address(r20, 3346)); // ldrsh x23, [x20, 3346] - __ ldrshw(r2, Address(r1, 3994)); // ldrsh w2, [x1, 3994] - __ ldrsw(r4, Address(r17, 7204)); // ldrsw x4, [x17, 7204] - __ ldrd(v20, Address(r27, 14400)); // ldr d20, [x27, 14400] - __ ldrs(v25, Address(r14, 8096)); // ldr s25, [x14, 8096] - __ strd(v26, Address(r10, 15024)); // str d26, [x10, 15024] - __ strs(v9, Address(r3, 6936)); // str s9, [x3, 6936] + __ str(r29, Address(r11, 14160)); // str x29, [x11, 14160] + __ strw(r28, Address(r21, 7752)); // str w28, [x21, 7752] + __ strb(r28, Address(r2, 1746)); // strb w28, [x2, 1746] + __ strh(r0, Address(r28, 3296)); // strh w0, [x28, 3296] + __ ldr(r25, Address(r7, 15408)); // ldr x25, [x7, 15408] + __ ldrw(r0, Address(r3, 6312)); // ldr w0, [x3, 6312] + __ ldrb(r30, Address(r5, 1992)); // ldrb w30, [x5, 1992] + __ ldrh(r14, Address(r23, 3194)); // ldrh w14, [x23, 3194] + __ ldrsb(r10, Address(r19, 1786)); // ldrsb x10, [x19, 1786] + __ ldrsh(r29, Address(r17, 3482)); // ldrsh x29, [x17, 3482] + __ ldrshw(r25, Address(r30, 3362)); // ldrsh w25, [x30, 3362] + __ ldrsw(r17, Address(r2, 7512)); // ldrsw x17, [x2, 7512] + __ ldrd(v15, Address(r16, 15176)); // ldr d15, [x16, 15176] + __ ldrs(v12, Address(r30, 6220)); // ldr s12, [x30, 6220] + __ strd(v1, Address(r1, 15216)); // str d1, [x1, 15216] + __ strs(v5, Address(r11, 7832)); // str s5, [x11, 7832] // pcrel // LoadStoreOp - __ ldr(r27, forth); // ldr x27, forth - __ ldrw(r11, __ pc()); // ldr w11, . + __ ldr(r17, back); // ldr x17, back + __ ldrw(r2, back); // ldr w2, back // LoadStoreOp - __ prfm(Address(r3, -187)); // prfm PLDL1KEEP, [x3, -187] + __ prfm(Address(r25, 111)); // prfm PLDL1KEEP, [x25, 111] // LoadStoreOp - __ prfm(__ pc()); // prfm PLDL1KEEP, . + __ prfm(back); // prfm PLDL1KEEP, back // LoadStoreOp - __ prfm(Address(r29, r14, Address::lsl(0))); // prfm PLDL1KEEP, [x29, x14, lsl #0] + __ prfm(Address(r14, r27, Address::uxtw(0))); // prfm PLDL1KEEP, [x14, w27, uxtw #0] // LoadStoreOp - __ prfm(Address(r4, 13312)); // prfm PLDL1KEEP, [x4, 13312] + __ prfm(Address(r14, 12328)); // prfm PLDL1KEEP, [x14, 12328] // AddSubCarryOp - __ adcw(r21, r1, r7); // adc w21, w1, w7 - __ adcsw(r8, r5, r7); // adcs w8, w5, w7 - __ sbcw(r7, r27, r14); // sbc w7, w27, w14 - __ sbcsw(r27, r4, r17); // sbcs w27, w4, w17 - __ adc(r0, r28, r0); // adc x0, x28, x0 - __ adcs(r12, r24, r30); // adcs x12, x24, x30 - __ sbc(r0, r25, r15); // sbc x0, x25, x15 - __ sbcs(r1, r24, r3); // sbcs x1, x24, x3 + __ adcw(r0, r25, r15); // adc w0, w25, w15 + __ adcsw(r1, r24, r3); // adcs w1, w24, w3 + __ sbcw(r17, r24, r20); // sbc w17, w24, w20 + __ sbcsw(r11, r0, r13); // sbcs w11, w0, w13 + __ adc(r28, r10, r7); // adc x28, x10, x7 + __ adcs(r4, r15, r16); // adcs x4, x15, x16 + __ sbc(r2, r12, r20); // sbc x2, x12, x20 + __ sbcs(r29, r13, r13); // sbcs x29, x13, x13 // AddSubExtendedOp - __ addw(r17, r24, r20, ext::uxtb, 2); // add w17, w24, w20, uxtb #2 - __ addsw(r13, r28, r10, ext::uxth, 1); // adds w13, w28, w10, uxth #1 - __ sub(r15, r16, r2, ext::sxth, 2); // sub x15, x16, x2, sxth #2 - __ subsw(r29, r13, r13, ext::uxth, 2); // subs w29, w13, w13, uxth #2 - __ add(r12, r20, r12, ext::sxtw, 3); // add x12, x20, x12, sxtw #3 - __ adds(r30, r27, r11, ext::sxtb, 1); // adds x30, x27, x11, sxtb #1 - __ sub(r14, r7, r1, ext::sxtw, 2); // sub x14, x7, x1, sxtw #2 - __ subs(r29, r3, r27, ext::sxth, 1); // subs x29, x3, x27, sxth #1 + __ addw(r14, r6, r12, ext::uxtx, 3); // add w14, w6, w12, uxtx #3 + __ addsw(r17, r25, r30, ext::uxtw, 4); // adds w17, w25, w30, uxtw #4 + __ sub(r0, r17, r14, ext::uxtb, 1); // sub x0, x17, x14, uxtb #1 + __ subsw(r9, r24, r29, ext::sxtx, 1); // subs w9, w24, w29, sxtx #1 + __ add(r1, r22, r0, ext::sxtw, 2); // add x1, x22, x0, sxtw #2 + __ adds(r12, r28, r22, ext::uxth, 3); // adds x12, x28, x22, uxth #3 + __ sub(r10, r12, r17, ext::uxtw, 4); // sub x10, x12, x17, uxtw #4 + __ subs(r15, r28, r10, ext::sxtw, 3); // subs x15, x28, x10, sxtw #3 // ConditionalCompareOp - __ ccmnw(r0, r13, 14u, Assembler::MI); // ccmn w0, w13, #14, MI - __ ccmpw(r22, r17, 6u, Assembler::CC); // ccmp w22, w17, #6, CC - __ ccmn(r17, r30, 14u, Assembler::VS); // ccmn x17, x30, #14, VS - __ ccmp(r10, r19, 12u, Assembler::HI); // ccmp x10, x19, #12, HI + __ ccmnw(r19, r23, 2u, Assembler::LE); // ccmn w19, w23, #2, LE + __ ccmpw(r17, r9, 6u, Assembler::LO); // ccmp w17, w9, #6, LO + __ ccmn(r21, r8, 2u, Assembler::CC); // ccmn x21, x8, #2, CC + __ ccmp(r19, r5, 1u, Assembler::MI); // ccmp x19, x5, #1, MI // ConditionalCompareImmedOp - __ ccmnw(r6, 18, 2, Assembler::LE); // ccmn w6, #18, #2, LE - __ ccmpw(r9, 13, 4, Assembler::HI); // ccmp w9, #13, #4, HI - __ ccmn(r21, 11, 11, Assembler::LO); // ccmn x21, #11, #11, LO - __ ccmp(r4, 13, 2, Assembler::VC); // ccmp x4, #13, #2, VC + __ ccmnw(r22, 17, 12, Assembler::HI); // ccmn w22, #17, #12, HI + __ ccmpw(r17, 7, 3, Assembler::HS); // ccmp w17, #7, #3, HS + __ ccmn(r16, 28, 5, Assembler::LT); // ccmn x16, #28, #5, LT + __ ccmp(r22, 3, 5, Assembler::LS); // ccmp x22, #3, #5, LS // ConditionalSelectOp - __ cselw(r12, r2, r22, Assembler::HI); // csel w12, w2, w22, HI - __ csincw(r24, r16, r17, Assembler::HS); // csinc w24, w16, w17, HS - __ csinvw(r6, r7, r16, Assembler::LT); // csinv w6, w7, w16, LT - __ csnegw(r11, r27, r22, Assembler::LS); // csneg w11, w27, w22, LS - __ csel(r10, r3, r29, Assembler::LT); // csel x10, x3, x29, LT - __ csinc(r12, r26, r27, Assembler::CC); // csinc x12, x26, x27, CC - __ csinv(r15, r10, r21, Assembler::GT); // csinv x15, x10, x21, GT - __ csneg(r30, r23, r9, Assembler::GT); // csneg x30, x23, x9, GT + __ cselw(r29, r26, r12, Assembler::LT); // csel w29, w26, w12, LT + __ csincw(r27, r10, r15, Assembler::CC); // csinc w27, w10, w15, CC + __ csinvw(r21, r28, r30, Assembler::LS); // csinv w21, w28, w30, LS + __ csnegw(r9, r27, r30, Assembler::CC); // csneg w9, w27, w30, CC + __ csel(r29, r15, r29, Assembler::LE); // csel x29, x15, x29, LE + __ csinc(r25, r21, r4, Assembler::EQ); // csinc x25, x21, x4, EQ + __ csinv(r17, r21, r29, Assembler::VS); // csinv x17, x21, x29, VS + __ csneg(r21, r20, r6, Assembler::HI); // csneg x21, x20, x6, HI // TwoRegOp - __ rbitw(r30, r10); // rbit w30, w10 - __ rev16w(r29, r15); // rev16 w29, w15 - __ revw(r29, r30); // rev w29, w30 - __ clzw(r25, r21); // clz w25, w21 - __ clsw(r4, r0); // cls w4, w0 - __ rbit(r17, r21); // rbit x17, x21 - __ rev16(r29, r16); // rev16 x29, x16 - __ rev32(r21, r20); // rev32 x21, x20 - __ rev(r6, r19); // rev x6, x19 - __ clz(r30, r3); // clz x30, x3 - __ cls(r21, r19); // cls x21, x19 + __ rbitw(r30, r3); // rbit w30, w3 + __ rev16w(r21, r19); // rev16 w21, w19 + __ revw(r11, r24); // rev w11, w24 + __ clzw(r0, r27); // clz w0, w27 + __ clsw(r25, r14); // cls w25, w14 + __ rbit(r3, r14); // rbit x3, x14 + __ rev16(r17, r7); // rev16 x17, x7 + __ rev32(r15, r24); // rev32 x15, x24 + __ rev(r28, r17); // rev x28, x17 + __ clz(r25, r2); // clz x25, x2 + __ cls(r26, r28); // cls x26, x28 + __ pacia(r5, r25); // pacia x5, x25 + __ pacib(r26, r27); // pacib x26, x27 + __ pacda(r16, r17); // pacda x16, x17 + __ pacdb(r6, r21); // pacdb x6, x21 + __ autia(r12, r0); // autia x12, x0 + __ autib(r4, r12); // autib x4, x12 + __ autda(r27, r17); // autda x27, x17 + __ autdb(r28, r28); // autdb x28, x28 + __ braa(r2, r17); // braa x2, x17 + __ brab(r10, r15); // brab x10, x15 + __ blraa(r14, r14); // blraa x14, x14 + __ blrab(r3, r25); // blrab x3, x25 // ThreeRegOp - __ udivw(r11, r24, r0); // udiv w11, w24, w0 - __ sdivw(r27, r25, r14); // sdiv w27, w25, w14 - __ lslvw(r3, r14, r17); // lslv w3, w14, w17 - __ lsrvw(r7, r15, r24); // lsrv w7, w15, w24 - __ asrvw(r28, r17, r25); // asrv w28, w17, w25 - __ rorvw(r2, r26, r28); // rorv w2, w26, w28 - __ udiv(r5, r25, r26); // udiv x5, x25, x26 - __ sdiv(r27, r16, r17); // sdiv x27, x16, x17 - __ lslv(r6, r21, r12); // lslv x6, x21, x12 - __ lsrv(r0, r4, r12); // lsrv x0, x4, x12 - __ asrv(r27, r17, r28); // asrv x27, x17, x28 - __ rorv(r28, r2, r17); // rorv x28, x2, x17 - __ umulh(r10, r15, r14); // umulh x10, x15, x14 - __ smulh(r14, r3, r25); // smulh x14, x3, x25 + __ udivw(r15, r19, r14); // udiv w15, w19, w14 + __ sdivw(r5, r16, r4); // sdiv w5, w16, w4 + __ lslvw(r26, r25, r4); // lslv w26, w25, w4 + __ lsrvw(r2, r2, r12); // lsrv w2, w2, w12 + __ asrvw(r29, r17, r8); // asrv w29, w17, w8 + __ rorvw(r7, r3, r4); // rorv w7, w3, w4 + __ udiv(r25, r4, r26); // udiv x25, x4, x26 + __ sdiv(r25, r4, r17); // sdiv x25, x4, x17 + __ lslv(r0, r26, r17); // lslv x0, x26, x17 + __ lsrv(r23, r15, r21); // lsrv x23, x15, x21 + __ asrv(r28, r17, r27); // asrv x28, x17, x27 + __ rorv(r10, r3, r0); // rorv x10, x3, x0 + __ umulh(r7, r25, r9); // umulh x7, x25, x9 + __ smulh(r6, r15, r29); // smulh x6, x15, x29 // FourRegMulOp - __ maddw(r15, r19, r14, r5); // madd w15, w19, w14, w5 - __ msubw(r16, r4, r26, r25); // msub w16, w4, w26, w25 - __ madd(r4, r2, r2, r12); // madd x4, x2, x2, x12 - __ msub(r29, r17, r8, r7); // msub x29, x17, x8, x7 - __ smaddl(r3, r4, r25, r4); // smaddl x3, w4, w25, x4 - __ smsubl(r26, r25, r4, r17); // smsubl x26, w25, w4, x17 - __ umaddl(r0, r26, r17, r23); // umaddl x0, w26, w17, x23 - __ umsubl(r15, r21, r28, r17); // umsubl x15, w21, w28, x17 + __ maddw(r15, r10, r2, r17); // madd w15, w10, w2, w17 + __ msubw(r7, r11, r11, r23); // msub w7, w11, w11, w23 + __ madd(r7, r29, r23, r14); // madd x7, x29, x23, x14 + __ msub(r27, r11, r11, r4); // msub x27, x11, x11, x4 + __ smaddl(r24, r12, r15, r14); // smaddl x24, w12, w15, x14 + __ smsubl(r20, r11, r28, r13); // smsubl x20, w11, w28, x13 + __ umaddl(r11, r12, r23, r30); // umaddl x11, w12, w23, x30 + __ umsubl(r26, r14, r9, r13); // umsubl x26, w14, w9, x13 // ThreeRegFloatOp - __ fabds(v27, v10, v3); // fabd s27, s10, s3 - __ fmuls(v0, v7, v25); // fmul s0, s7, s25 - __ fdivs(v9, v6, v15); // fdiv s9, s6, s15 - __ fadds(v29, v15, v10); // fadd s29, s15, s10 - __ fsubs(v2, v17, v7); // fsub s2, s17, s7 - __ fabdd(v11, v11, v23); // fabd d11, d11, d23 - __ fmuld(v7, v29, v23); // fmul d7, d29, d23 - __ fdivd(v14, v27, v11); // fdiv d14, d27, d11 - __ faddd(v11, v4, v24); // fadd d11, d4, d24 - __ fsubd(v12, v15, v14); // fsub d12, d15, d14 + __ fabds(v10, v7, v5); // fabd s10, s7, s5 + __ fmuls(v29, v15, v3); // fmul s29, s15, s3 + __ fdivs(v11, v12, v15); // fdiv s11, s12, s15 + __ fadds(v30, v30, v17); // fadd s30, s30, s17 + __ fsubs(v19, v20, v15); // fsub s19, s20, s15 + __ fabdd(v15, v9, v21); // fabd d15, d9, d21 + __ fmuld(v2, v9, v27); // fmul d2, d9, d27 + __ fdivd(v7, v29, v30); // fdiv d7, d29, d30 + __ faddd(v17, v1, v2); // fadd d17, d1, d2 + __ fsubd(v6, v10, v3); // fsub d6, d10, d3 // FourRegFloatOp - __ fmadds(v20, v11, v28, v13); // fmadd s20, s11, s28, s13 - __ fmsubs(v11, v12, v23, v30); // fmsub s11, s12, s23, s30 - __ fnmadds(v26, v14, v9, v13); // fnmadd s26, s14, s9, s13 - __ fnmadds(v10, v7, v5, v29); // fnmadd s10, s7, s5, s29 - __ fmaddd(v15, v3, v11, v12); // fmadd d15, d3, d11, d12 - __ fmsubd(v15, v30, v30, v17); // fmsub d15, d30, d30, d17 - __ fnmaddd(v19, v20, v15, v15); // fnmadd d19, d20, d15, d15 - __ fnmaddd(v9, v21, v2, v9); // fnmadd d9, d21, d2, d9 + __ fmadds(v24, v11, v7, v1); // fmadd s24, s11, s7, s1 + __ fmsubs(v11, v0, v3, v17); // fmsub s11, s0, s3, s17 + __ fnmadds(v28, v6, v22, v6); // fnmadd s28, s6, s22, s6 + __ fnmadds(v0, v27, v26, v2); // fnmadd s0, s27, s26, s2 + __ fmaddd(v5, v7, v28, v11); // fmadd d5, d7, d28, d11 + __ fmsubd(v25, v13, v11, v23); // fmsub d25, d13, d11, d23 + __ fnmaddd(v19, v8, v17, v21); // fnmadd d19, d8, d17, d21 + __ fnmaddd(v25, v20, v19, v17); // fnmadd d25, d20, d19, d17 // TwoRegFloatOp - __ fmovs(v27, v7); // fmov s27, s7 - __ fabss(v29, v30); // fabs s29, s30 - __ fnegs(v17, v1); // fneg s17, s1 - __ fsqrts(v2, v6); // fsqrt s2, s6 - __ fcvts(v10, v3); // fcvt d10, s3 - __ fmovd(v24, v11); // fmov d24, d11 - __ fabsd(v7, v1); // fabs d7, d1 - __ fnegd(v11, v0); // fneg d11, d0 - __ fsqrtd(v3, v17); // fsqrt d3, d17 - __ fcvtd(v28, v6); // fcvt s28, d6 + __ fmovs(v2, v29); // fmov s2, s29 + __ fabss(v22, v8); // fabs s22, s8 + __ fnegs(v21, v19); // fneg s21, s19 + __ fsqrts(v20, v11); // fsqrt s20, s11 + __ fcvts(v17, v20); // fcvt d17, s20 + __ fmovd(v6, v15); // fmov d6, d15 + __ fabsd(v3, v3); // fabs d3, d3 + __ fnegd(v28, v3); // fneg d28, d3 + __ fsqrtd(v27, v14); // fsqrt d27, d14 + __ fcvtd(v14, v10); // fcvt s14, d10 // FloatConvertOp - __ fcvtzsw(r22, v6); // fcvtzs w22, s6 - __ fcvtzs(r0, v27); // fcvtzs x0, s27 - __ fcvtzdw(r26, v2); // fcvtzs w26, d2 - __ fcvtzd(r5, v7); // fcvtzs x5, d7 - __ scvtfws(v28, r11); // scvtf s28, w11 - __ scvtfs(v25, r13); // scvtf s25, x13 - __ scvtfwd(v11, r23); // scvtf d11, w23 - __ scvtfd(v19, r8); // scvtf d19, x8 - __ fmovs(r17, v21); // fmov w17, s21 - __ fmovd(r25, v20); // fmov x25, d20 - __ fmovs(v19, r17); // fmov s19, w17 - __ fmovd(v2, r29); // fmov d2, x29 + __ fcvtzsw(r12, v11); // fcvtzs w12, s11 + __ fcvtzs(r17, v10); // fcvtzs x17, s10 + __ fcvtzdw(r25, v7); // fcvtzs w25, d7 + __ fcvtzd(r7, v14); // fcvtzs x7, d14 + __ scvtfws(v28, r0); // scvtf s28, w0 + __ scvtfs(v22, r0); // scvtf s22, x0 + __ scvtfwd(v12, r23); // scvtf d12, w23 + __ scvtfd(v13, r13); // scvtf d13, x13 + __ fmovs(r7, v14); // fmov w7, s14 + __ fmovd(r7, v8); // fmov x7, d8 + __ fmovs(v20, r17); // fmov s20, w17 + __ fmovd(v28, r30); // fmov d28, x30 // TwoRegFloatOp - __ fcmps(v22, v8); // fcmp s22, s8 - __ fcmpd(v21, v19); // fcmp d21, d19 + __ fcmps(v16, v2); // fcmp s16, s2 + __ fcmpd(v9, v16); // fcmp d9, d16 __ fcmps(v20, 0.0); // fcmp s20, #0.0 - __ fcmpd(v11, 0.0); // fcmp d11, #0.0 + __ fcmpd(v29, 0.0); // fcmp d29, #0.0 // LoadStorePairOp - __ stpw(r20, r6, Address(r15, -32)); // stp w20, w6, [x15, #-32] - __ ldpw(r27, r14, Address(r3, -208)); // ldp w27, w14, [x3, #-208] - __ ldpsw(r16, r10, Address(r11, -80)); // ldpsw x16, x10, [x11, #-80] - __ stp(r7, r7, Address(r14, 64)); // stp x7, x7, [x14, #64] - __ ldp(r12, r23, Address(r0, 112)); // ldp x12, x23, [x0, #112] + __ stpw(r1, r26, Address(r24, -208)); // stp w1, w26, [x24, #-208] + __ ldpw(r5, r11, Address(r12, 48)); // ldp w5, w11, [x12, #48] + __ ldpsw(r21, r15, Address(r27, 48)); // ldpsw x21, x15, [x27, #48] + __ stp(r5, r28, Address(r22, 32)); // stp x5, x28, [x22, #32] + __ ldp(r27, r17, Address(r19, -32)); // ldp x27, x17, [x19, #-32] // LoadStorePairOp - __ stpw(r13, r7, Address(__ pre(r6, -80))); // stp w13, w7, [x6, #-80]! - __ ldpw(r30, r15, Address(__ pre(r2, -144))); // ldp w30, w15, [x2, #-144]! - __ ldpsw(r4, r1, Address(__ pre(r27, -144))); // ldpsw x4, x1, [x27, #-144]! - __ stp(r23, r14, Address(__ pre(r11, 64))); // stp x23, x14, [x11, #64]! - __ ldp(r29, r27, Address(__ pre(r21, -192))); // ldp x29, x27, [x21, #-192]! + __ stpw(r13, r7, Address(__ pre(r26, -176))); // stp w13, w7, [x26, #-176]! + __ ldpw(r13, r21, Address(__ pre(r6, -48))); // ldp w13, w21, [x6, #-48]! + __ ldpsw(r20, r30, Address(__ pre(r27, 16))); // ldpsw x20, x30, [x27, #16]! + __ stp(r21, r5, Address(__ pre(r10, -128))); // stp x21, x5, [x10, #-128]! + __ ldp(r14, r4, Address(__ pre(r23, -96))); // ldp x14, x4, [x23, #-96]! // LoadStorePairOp - __ stpw(r22, r5, Address(__ post(r21, -48))); // stp w22, w5, [x21], #-48 - __ ldpw(r27, r17, Address(__ post(r6, -32))); // ldp w27, w17, [x6], #-32 - __ ldpsw(r16, r5, Address(__ post(r1, -80))); // ldpsw x16, x5, [x1], #-80 - __ stp(r13, r20, Address(__ post(r22, -208))); // stp x13, x20, [x22], #-208 - __ ldp(r30, r27, Address(__ post(r10, 80))); // ldp x30, x27, [x10], #80 + __ stpw(r29, r12, Address(__ post(r16, 32))); // stp w29, w12, [x16], #32 + __ ldpw(r26, r17, Address(__ post(r27, 96))); // ldp w26, w17, [x27], #96 + __ ldpsw(r4, r20, Address(__ post(r14, -96))); // ldpsw x4, x20, [x14], #-96 + __ stp(r16, r2, Address(__ post(r14, -112))); // stp x16, x2, [x14], #-112 + __ ldp(r23, r24, Address(__ post(r7, -256))); // ldp x23, x24, [x7], #-256 // LoadStorePairOp - __ stnpw(r5, r17, Address(r11, 16)); // stnp w5, w17, [x11, #16] - __ ldnpw(r14, r4, Address(r26, -96)); // ldnp w14, w4, [x26, #-96] - __ stnp(r23, r29, Address(r12, 32)); // stnp x23, x29, [x12, #32] - __ ldnp(r0, r6, Address(r21, -80)); // ldnp x0, x6, [x21, #-80] + __ stnpw(r0, r26, Address(r15, 128)); // stnp w0, w26, [x15, #128] + __ ldnpw(r26, r6, Address(r8, -208)); // ldnp w26, w6, [x8, #-208] + __ stnp(r15, r10, Address(r25, -112)); // stnp x15, x10, [x25, #-112] + __ ldnp(r16, r1, Address(r19, -160)); // ldnp x16, x1, [x19, #-160] // LdStNEONOp - __ ld1(v15, __ T8B, Address(r26)); // ld1 {v15.8B}, [x26] - __ ld1(v23, v24, __ T16B, Address(__ post(r11, 32))); // ld1 {v23.16B, v24.16B}, [x11], 32 - __ ld1(v8, v9, v10, __ T1D, Address(__ post(r23, r7))); // ld1 {v8.1D, v9.1D, v10.1D}, [x23], x7 - __ ld1(v19, v20, v21, v22, __ T8H, Address(__ post(r25, 64))); // ld1 {v19.8H, v20.8H, v21.8H, v22.8H}, [x25], 64 - __ ld1r(v29, __ T8B, Address(r17)); // ld1r {v29.8B}, [x17] - __ ld1r(v24, __ T4S, Address(__ post(r23, 4))); // ld1r {v24.4S}, [x23], 4 - __ ld1r(v10, __ T1D, Address(__ post(r5, r25))); // ld1r {v10.1D}, [x5], x25 - __ ld2(v17, v18, __ T2D, Address(r10)); // ld2 {v17.2D, v18.2D}, [x10] - __ ld2(v12, v13, __ T4H, Address(__ post(r15, 16))); // ld2 {v12.4H, v13.4H}, [x15], 16 - __ ld2r(v25, v26, __ T16B, Address(r17)); // ld2r {v25.16B, v26.16B}, [x17] - __ ld2r(v1, v2, __ T2S, Address(__ post(r30, 8))); // ld2r {v1.2S, v2.2S}, [x30], 8 - __ ld2r(v16, v17, __ T2D, Address(__ post(r17, r9))); // ld2r {v16.2D, v17.2D}, [x17], x9 - __ ld3(v25, v26, v27, __ T4S, Address(__ post(r12, r2))); // ld3 {v25.4S, v26.4S, v27.4S}, [x12], x2 - __ ld3(v26, v27, v28, __ T2S, Address(r19)); // ld3 {v26.2S, v27.2S, v28.2S}, [x19] - __ ld3r(v15, v16, v17, __ T8H, Address(r21)); // ld3r {v15.8H, v16.8H, v17.8H}, [x21] - __ ld3r(v25, v26, v27, __ T4S, Address(__ post(r13, 12))); // ld3r {v25.4S, v26.4S, v27.4S}, [x13], 12 - __ ld3r(v14, v15, v16, __ T1D, Address(__ post(r28, r29))); // ld3r {v14.1D, v15.1D, v16.1D}, [x28], x29 - __ ld4(v17, v18, v19, v20, __ T8H, Address(__ post(r29, 64))); // ld4 {v17.8H, v18.8H, v19.8H, v20.8H}, [x29], 64 - __ ld4(v27, v28, v29, v30, __ T8B, Address(__ post(r7, r0))); // ld4 {v27.8B, v28.8B, v29.8B, v30.8B}, [x7], x0 - __ ld4r(v24, v25, v26, v27, __ T8B, Address(r17)); // ld4r {v24.8B, v25.8B, v26.8B, v27.8B}, [x17] - __ ld4r(v0, v1, v2, v3, __ T4H, Address(__ post(r26, 8))); // ld4r {v0.4H, v1.4H, v2.4H, v3.4H}, [x26], 8 - __ ld4r(v12, v13, v14, v15, __ T2S, Address(__ post(r25, r2))); // ld4r {v12.2S, v13.2S, v14.2S, v15.2S}, [x25], x2 + __ ld1(v27, __ T8B, Address(r30)); // ld1 {v27.8B}, [x30] + __ ld1(v25, v26, __ T16B, Address(__ post(r3, 32))); // ld1 {v25.16B, v26.16B}, [x3], 32 + __ ld1(v30, v31, v0, __ T1D, Address(__ post(r16, r10))); // ld1 {v30.1D, v31.1D, v0.1D}, [x16], x10 + __ ld1(v16, v17, v18, v19, __ T8H, Address(__ post(r19, 64))); // ld1 {v16.8H, v17.8H, v18.8H, v19.8H}, [x19], 64 + __ ld1r(v23, __ T8B, Address(r24)); // ld1r {v23.8B}, [x24] + __ ld1r(v8, __ T4S, Address(__ post(r10, 4))); // ld1r {v8.4S}, [x10], 4 + __ ld1r(v9, __ T1D, Address(__ post(r20, r23))); // ld1r {v9.1D}, [x20], x23 + __ ld2(v2, v3, __ T2D, Address(r3)); // ld2 {v2.2D, v3.2D}, [x3] + __ ld2(v8, v9, __ T4H, Address(__ post(r30, 16))); // ld2 {v8.4H, v9.4H}, [x30], 16 + __ ld2r(v4, v5, __ T16B, Address(r26)); // ld2r {v4.16B, v5.16B}, [x26] + __ ld2r(v3, v4, __ T2S, Address(__ post(r17, 8))); // ld2r {v3.2S, v4.2S}, [x17], 8 + __ ld2r(v29, v30, __ T2D, Address(__ post(r11, r16))); // ld2r {v29.2D, v30.2D}, [x11], x16 + __ ld3(v1, v2, v3, __ T4S, Address(__ post(r0, r23))); // ld3 {v1.4S, v2.4S, v3.4S}, [x0], x23 + __ ld3(v0, v1, v2, __ T2S, Address(r21)); // ld3 {v0.2S, v1.2S, v2.2S}, [x21] + __ ld3r(v5, v6, v7, __ T8H, Address(r7)); // ld3r {v5.8H, v6.8H, v7.8H}, [x7] + __ ld3r(v1, v2, v3, __ T4S, Address(__ post(r7, 12))); // ld3r {v1.4S, v2.4S, v3.4S}, [x7], 12 + __ ld3r(v2, v3, v4, __ T1D, Address(__ post(r5, r15))); // ld3r {v2.1D, v3.1D, v4.1D}, [x5], x15 + __ ld4(v27, v28, v29, v30, __ T8H, Address(__ post(r29, 64))); // ld4 {v27.8H, v28.8H, v29.8H, v30.8H}, [x29], 64 + __ ld4(v24, v25, v26, v27, __ T8B, Address(__ post(r4, r7))); // ld4 {v24.8B, v25.8B, v26.8B, v27.8B}, [x4], x7 + __ ld4r(v15, v16, v17, v18, __ T8B, Address(r23)); // ld4r {v15.8B, v16.8B, v17.8B, v18.8B}, [x23] + __ ld4r(v14, v15, v16, v17, __ T4H, Address(__ post(r21, 8))); // ld4r {v14.4H, v15.4H, v16.4H, v17.4H}, [x21], 8 + __ ld4r(v20, v21, v22, v23, __ T2S, Address(__ post(r9, r25))); // ld4r {v20.2S, v21.2S, v22.2S, v23.2S}, [x9], x25 // NEONReduceInstruction - __ addv(v22, __ T8B, v23); // addv b22, v23.8B - __ addv(v27, __ T16B, v28); // addv b27, v28.16B - __ addv(v4, __ T4H, v5); // addv h4, v5.4H - __ addv(v7, __ T8H, v8); // addv h7, v8.8H - __ addv(v6, __ T4S, v7); // addv s6, v7.4S - __ smaxv(v1, __ T8B, v2); // smaxv b1, v2.8B - __ smaxv(v26, __ T16B, v27); // smaxv b26, v27.16B - __ smaxv(v15, __ T4H, v16); // smaxv h15, v16.4H - __ smaxv(v2, __ T8H, v3); // smaxv h2, v3.8H - __ smaxv(v13, __ T4S, v14); // smaxv s13, v14.4S - __ fmaxv(v13, __ T4S, v14); // fmaxv s13, v14.4S - __ sminv(v24, __ T8B, v25); // sminv b24, v25.8B - __ uminv(v23, __ T8B, v24); // uminv b23, v24.8B - __ sminv(v4, __ T16B, v5); // sminv b4, v5.16B - __ uminv(v19, __ T16B, v20); // uminv b19, v20.16B - __ sminv(v15, __ T4H, v16); // sminv h15, v16.4H - __ uminv(v0, __ T4H, v1); // uminv h0, v1.4H - __ sminv(v4, __ T8H, v5); // sminv h4, v5.8H - __ uminv(v20, __ T8H, v21); // uminv h20, v21.8H - __ sminv(v11, __ T4S, v12); // sminv s11, v12.4S - __ uminv(v29, __ T4S, v30); // uminv s29, v30.4S - __ fminv(v15, __ T4S, v16); // fminv s15, v16.4S - __ fmaxp(v21, v22, __ S); // fmaxp s21, v22.2S - __ fmaxp(v4, v5, __ D); // fmaxp d4, v5.2D - __ fminp(v14, v15, __ S); // fminp s14, v15.2S - __ fminp(v22, v23, __ D); // fminp d22, v23.2D + __ addv(v23, __ T8B, v24); // addv b23, v24.8B + __ addv(v26, __ T16B, v27); // addv b26, v27.16B + __ addv(v5, __ T4H, v6); // addv h5, v6.4H + __ addv(v6, __ T8H, v7); // addv h6, v7.8H + __ addv(v15, __ T4S, v16); // addv s15, v16.4S + __ smaxv(v15, __ T8B, v16); // smaxv b15, v16.8B + __ smaxv(v25, __ T16B, v26); // smaxv b25, v26.16B + __ smaxv(v16, __ T4H, v17); // smaxv h16, v17.4H + __ smaxv(v27, __ T8H, v28); // smaxv h27, v28.8H + __ smaxv(v24, __ T4S, v25); // smaxv s24, v25.4S + __ fmaxv(v15, __ T4S, v16); // fmaxv s15, v16.4S + __ sminv(v25, __ T8B, v26); // sminv b25, v26.8B + __ uminv(v14, __ T8B, v15); // uminv b14, v15.8B + __ sminv(v10, __ T16B, v11); // sminv b10, v11.16B + __ uminv(v13, __ T16B, v14); // uminv b13, v14.16B + __ sminv(v14, __ T4H, v15); // sminv h14, v15.4H + __ uminv(v20, __ T4H, v21); // uminv h20, v21.4H + __ sminv(v1, __ T8H, v2); // sminv h1, v2.8H + __ uminv(v22, __ T8H, v23); // uminv h22, v23.8H + __ sminv(v30, __ T4S, v31); // sminv s30, v31.4S + __ uminv(v14, __ T4S, v15); // uminv s14, v15.4S + __ fminv(v2, __ T4S, v3); // fminv s2, v3.4S + __ fmaxp(v6, v7, __ S); // fmaxp s6, v7.2S + __ fmaxp(v3, v4, __ D); // fmaxp d3, v4.2D + __ fminp(v7, v8, __ S); // fminp s7, v8.2S + __ fminp(v24, v25, __ D); // fminp d24, v25.2D // TwoRegNEONOp - __ absr(v25, __ T8B, v26); // abs v25.8B, v26.8B - __ absr(v6, __ T16B, v7); // abs v6.16B, v7.16B - __ absr(v12, __ T4H, v13); // abs v12.4H, v13.4H - __ absr(v14, __ T8H, v15); // abs v14.8H, v15.8H - __ absr(v13, __ T2S, v14); // abs v13.2S, v14.2S - __ absr(v14, __ T4S, v15); // abs v14.4S, v15.4S - __ absr(v9, __ T2D, v10); // abs v9.2D, v10.2D + __ absr(v0, __ T8B, v1); // abs v0.8B, v1.8B + __ absr(v27, __ T16B, v28); // abs v27.16B, v28.16B + __ absr(v29, __ T4H, v30); // abs v29.4H, v30.4H + __ absr(v5, __ T8H, v6); // abs v5.8H, v6.8H + __ absr(v5, __ T2S, v6); // abs v5.2S, v6.2S + __ absr(v29, __ T4S, v30); // abs v29.4S, v30.4S + __ absr(v11, __ T2D, v12); // abs v11.2D, v12.2D __ fabs(v25, __ T2S, v26); // fabs v25.2S, v26.2S - __ fabs(v28, __ T4S, v29); // fabs v28.4S, v29.4S - __ fabs(v10, __ T2D, v11); // fabs v10.2D, v11.2D - __ fneg(v19, __ T2S, v20); // fneg v19.2S, v20.2S - __ fneg(v11, __ T4S, v12); // fneg v11.4S, v12.4S - __ fneg(v17, __ T2D, v18); // fneg v17.2D, v18.2D - __ fsqrt(v21, __ T2S, v22); // fsqrt v21.2S, v22.2S - __ fsqrt(v15, __ T4S, v16); // fsqrt v15.4S, v16.4S - __ fsqrt(v20, __ T2D, v21); // fsqrt v20.2D, v21.2D - __ notr(v23, __ T8B, v24); // not v23.8B, v24.8B - __ notr(v26, __ T16B, v27); // not v26.16B, v27.16B + __ fabs(v0, __ T4S, v1); // fabs v0.4S, v1.4S + __ fabs(v30, __ T2D, v31); // fabs v30.2D, v31.2D + __ fneg(v0, __ T2S, v1); // fneg v0.2S, v1.2S + __ fneg(v17, __ T4S, v18); // fneg v17.4S, v18.4S + __ fneg(v28, __ T2D, v29); // fneg v28.2D, v29.2D + __ fsqrt(v25, __ T2S, v26); // fsqrt v25.2S, v26.2S + __ fsqrt(v9, __ T4S, v10); // fsqrt v9.4S, v10.4S + __ fsqrt(v25, __ T2D, v26); // fsqrt v25.2D, v26.2D + __ notr(v12, __ T8B, v13); // not v12.8B, v13.8B + __ notr(v15, __ T16B, v16); // not v15.16B, v16.16B // ThreeRegNEONOp - __ andr(v5, __ T8B, v6, v7); // and v5.8B, v6.8B, v7.8B - __ andr(v6, __ T16B, v7, v8); // and v6.16B, v7.16B, v8.16B - __ orr(v15, __ T8B, v16, v17); // orr v15.8B, v16.8B, v17.8B - __ orr(v15, __ T16B, v16, v17); // orr v15.16B, v16.16B, v17.16B - __ eor(v25, __ T8B, v26, v27); // eor v25.8B, v26.8B, v27.8B - __ eor(v16, __ T16B, v17, v18); // eor v16.16B, v17.16B, v18.16B - __ addv(v27, __ T8B, v28, v29); // add v27.8B, v28.8B, v29.8B - __ addv(v24, __ T16B, v25, v26); // add v24.16B, v25.16B, v26.16B - __ addv(v15, __ T4H, v16, v17); // add v15.4H, v16.4H, v17.4H - __ addv(v25, __ T8H, v26, v27); // add v25.8H, v26.8H, v27.8H - __ addv(v14, __ T2S, v15, v16); // add v14.2S, v15.2S, v16.2S - __ addv(v10, __ T4S, v11, v12); // add v10.4S, v11.4S, v12.4S - __ addv(v13, __ T2D, v14, v15); // add v13.2D, v14.2D, v15.2D - __ fadd(v14, __ T2S, v15, v16); // fadd v14.2S, v15.2S, v16.2S + __ andr(v11, __ T8B, v12, v13); // and v11.8B, v12.8B, v13.8B + __ andr(v10, __ T16B, v11, v12); // and v10.16B, v11.16B, v12.16B + __ orr(v17, __ T8B, v18, v19); // orr v17.8B, v18.8B, v19.8B + __ orr(v24, __ T16B, v25, v26); // orr v24.16B, v25.16B, v26.16B + __ eor(v21, __ T8B, v22, v23); // eor v21.8B, v22.8B, v23.8B + __ eor(v23, __ T16B, v24, v25); // eor v23.16B, v24.16B, v25.16B + __ addv(v0, __ T8B, v1, v2); // add v0.8B, v1.8B, v2.8B + __ addv(v16, __ T16B, v17, v18); // add v16.16B, v17.16B, v18.16B + __ addv(v10, __ T4H, v11, v12); // add v10.4H, v11.4H, v12.4H + __ addv(v6, __ T8H, v7, v8); // add v6.8H, v7.8H, v8.8H + __ addv(v28, __ T2S, v29, v30); // add v28.2S, v29.2S, v30.2S + __ addv(v6, __ T4S, v7, v8); // add v6.4S, v7.4S, v8.4S + __ addv(v5, __ T2D, v6, v7); // add v5.2D, v6.2D, v7.2D + __ fadd(v5, __ T2S, v6, v7); // fadd v5.2S, v6.2S, v7.2S __ fadd(v20, __ T4S, v21, v22); // fadd v20.4S, v21.4S, v22.4S - __ fadd(v1, __ T2D, v2, v3); // fadd v1.2D, v2.2D, v3.2D - __ subv(v22, __ T8B, v23, v24); // sub v22.8B, v23.8B, v24.8B - __ subv(v30, __ T16B, v31, v0); // sub v30.16B, v31.16B, v0.16B - __ subv(v14, __ T4H, v15, v16); // sub v14.4H, v15.4H, v16.4H - __ subv(v2, __ T8H, v3, v4); // sub v2.8H, v3.8H, v4.8H - __ subv(v6, __ T2S, v7, v8); // sub v6.2S, v7.2S, v8.2S - __ subv(v3, __ T4S, v4, v5); // sub v3.4S, v4.4S, v5.4S - __ subv(v7, __ T2D, v8, v9); // sub v7.2D, v8.2D, v9.2D - __ fsub(v24, __ T2S, v25, v26); // fsub v24.2S, v25.2S, v26.2S - __ fsub(v0, __ T4S, v1, v2); // fsub v0.4S, v1.4S, v2.4S - __ fsub(v27, __ T2D, v28, v29); // fsub v27.2D, v28.2D, v29.2D - __ mulv(v29, __ T8B, v30, v31); // mul v29.8B, v30.8B, v31.8B - __ mulv(v5, __ T16B, v6, v7); // mul v5.16B, v6.16B, v7.16B - __ mulv(v5, __ T4H, v6, v7); // mul v5.4H, v6.4H, v7.4H - __ mulv(v29, __ T8H, v30, v31); // mul v29.8H, v30.8H, v31.8H - __ mulv(v11, __ T2S, v12, v13); // mul v11.2S, v12.2S, v13.2S - __ mulv(v25, __ T4S, v26, v27); // mul v25.4S, v26.4S, v27.4S - __ fabd(v0, __ T2S, v1, v2); // fabd v0.2S, v1.2S, v2.2S - __ fabd(v30, __ T4S, v31, v0); // fabd v30.4S, v31.4S, v0.4S - __ fabd(v0, __ T2D, v1, v2); // fabd v0.2D, v1.2D, v2.2D - __ fmul(v17, __ T2S, v18, v19); // fmul v17.2S, v18.2S, v19.2S - __ fmul(v28, __ T4S, v29, v30); // fmul v28.4S, v29.4S, v30.4S - __ fmul(v25, __ T2D, v26, v27); // fmul v25.2D, v26.2D, v27.2D - __ mlav(v9, __ T4H, v10, v11); // mla v9.4H, v10.4H, v11.4H - __ mlav(v25, __ T8H, v26, v27); // mla v25.8H, v26.8H, v27.8H - __ mlav(v12, __ T2S, v13, v14); // mla v12.2S, v13.2S, v14.2S - __ mlav(v15, __ T4S, v16, v17); // mla v15.4S, v16.4S, v17.4S - __ fmla(v11, __ T2S, v12, v13); // fmla v11.2S, v12.2S, v13.2S - __ fmla(v10, __ T4S, v11, v12); // fmla v10.4S, v11.4S, v12.4S - __ fmla(v17, __ T2D, v18, v19); // fmla v17.2D, v18.2D, v19.2D - __ mlsv(v24, __ T4H, v25, v26); // mls v24.4H, v25.4H, v26.4H - __ mlsv(v21, __ T8H, v22, v23); // mls v21.8H, v22.8H, v23.8H - __ mlsv(v23, __ T2S, v24, v25); // mls v23.2S, v24.2S, v25.2S - __ mlsv(v0, __ T4S, v1, v2); // mls v0.4S, v1.4S, v2.4S - __ fmls(v16, __ T2S, v17, v18); // fmls v16.2S, v17.2S, v18.2S - __ fmls(v10, __ T4S, v11, v12); // fmls v10.4S, v11.4S, v12.4S - __ fmls(v6, __ T2D, v7, v8); // fmls v6.2D, v7.2D, v8.2D - __ fdiv(v28, __ T2S, v29, v30); // fdiv v28.2S, v29.2S, v30.2S - __ fdiv(v6, __ T4S, v7, v8); // fdiv v6.4S, v7.4S, v8.4S - __ fdiv(v5, __ T2D, v6, v7); // fdiv v5.2D, v6.2D, v7.2D - __ maxv(v5, __ T8B, v6, v7); // smax v5.8B, v6.8B, v7.8B - __ maxv(v20, __ T16B, v21, v22); // smax v20.16B, v21.16B, v22.16B - __ maxv(v17, __ T4H, v18, v19); // smax v17.4H, v18.4H, v19.4H - __ maxv(v15, __ T8H, v16, v17); // smax v15.8H, v16.8H, v17.8H - __ maxv(v17, __ T2S, v18, v19); // smax v17.2S, v18.2S, v19.2S - __ maxv(v29, __ T4S, v30, v31); // smax v29.4S, v30.4S, v31.4S - __ smaxp(v26, __ T8B, v27, v28); // smaxp v26.8B, v27.8B, v28.8B - __ smaxp(v28, __ T16B, v29, v30); // smaxp v28.16B, v29.16B, v30.16B - __ smaxp(v1, __ T4H, v2, v3); // smaxp v1.4H, v2.4H, v3.4H - __ smaxp(v27, __ T8H, v28, v29); // smaxp v27.8H, v28.8H, v29.8H - __ smaxp(v0, __ T2S, v1, v2); // smaxp v0.2S, v1.2S, v2.2S - __ smaxp(v20, __ T4S, v21, v22); // smaxp v20.4S, v21.4S, v22.4S - __ fmax(v28, __ T2S, v29, v30); // fmax v28.2S, v29.2S, v30.2S - __ fmax(v15, __ T4S, v16, v17); // fmax v15.4S, v16.4S, v17.4S - __ fmax(v12, __ T2D, v13, v14); // fmax v12.2D, v13.2D, v14.2D - __ minv(v10, __ T8B, v11, v12); // smin v10.8B, v11.8B, v12.8B - __ minv(v28, __ T16B, v29, v30); // smin v28.16B, v29.16B, v30.16B - __ minv(v28, __ T4H, v29, v30); // smin v28.4H, v29.4H, v30.4H - __ minv(v19, __ T8H, v20, v21); // smin v19.8H, v20.8H, v21.8H - __ minv(v22, __ T2S, v23, v24); // smin v22.2S, v23.2S, v24.2S - __ minv(v10, __ T4S, v11, v12); // smin v10.4S, v11.4S, v12.4S - __ sminp(v4, __ T8B, v5, v6); // sminp v4.8B, v5.8B, v6.8B - __ sminp(v30, __ T16B, v31, v0); // sminp v30.16B, v31.16B, v0.16B - __ sminp(v20, __ T4H, v21, v22); // sminp v20.4H, v21.4H, v22.4H - __ sminp(v8, __ T8H, v9, v10); // sminp v8.8H, v9.8H, v10.8H - __ sminp(v30, __ T2S, v31, v0); // sminp v30.2S, v31.2S, v0.2S - __ sminp(v17, __ T4S, v18, v19); // sminp v17.4S, v18.4S, v19.4S - __ fmin(v10, __ T2S, v11, v12); // fmin v10.2S, v11.2S, v12.2S - __ fmin(v27, __ T4S, v28, v29); // fmin v27.4S, v28.4S, v29.4S - __ fmin(v2, __ T2D, v3, v4); // fmin v2.2D, v3.2D, v4.2D - __ cmeq(v24, __ T8B, v25, v26); // cmeq v24.8B, v25.8B, v26.8B - __ cmeq(v4, __ T16B, v5, v6); // cmeq v4.16B, v5.16B, v6.16B - __ cmeq(v3, __ T4H, v4, v5); // cmeq v3.4H, v4.4H, v5.4H - __ cmeq(v8, __ T8H, v9, v10); // cmeq v8.8H, v9.8H, v10.8H - __ cmeq(v22, __ T2S, v23, v24); // cmeq v22.2S, v23.2S, v24.2S + __ fadd(v17, __ T2D, v18, v19); // fadd v17.2D, v18.2D, v19.2D + __ subv(v15, __ T8B, v16, v17); // sub v15.8B, v16.8B, v17.8B + __ subv(v17, __ T16B, v18, v19); // sub v17.16B, v18.16B, v19.16B + __ subv(v29, __ T4H, v30, v31); // sub v29.4H, v30.4H, v31.4H + __ subv(v26, __ T8H, v27, v28); // sub v26.8H, v27.8H, v28.8H + __ subv(v28, __ T2S, v29, v30); // sub v28.2S, v29.2S, v30.2S + __ subv(v1, __ T4S, v2, v3); // sub v1.4S, v2.4S, v3.4S + __ subv(v27, __ T2D, v28, v29); // sub v27.2D, v28.2D, v29.2D + __ fsub(v0, __ T2S, v1, v2); // fsub v0.2S, v1.2S, v2.2S + __ fsub(v20, __ T4S, v21, v22); // fsub v20.4S, v21.4S, v22.4S + __ fsub(v28, __ T2D, v29, v30); // fsub v28.2D, v29.2D, v30.2D + __ mulv(v15, __ T8B, v16, v17); // mul v15.8B, v16.8B, v17.8B + __ mulv(v12, __ T16B, v13, v14); // mul v12.16B, v13.16B, v14.16B + __ mulv(v10, __ T4H, v11, v12); // mul v10.4H, v11.4H, v12.4H + __ mulv(v28, __ T8H, v29, v30); // mul v28.8H, v29.8H, v30.8H + __ mulv(v28, __ T2S, v29, v30); // mul v28.2S, v29.2S, v30.2S + __ mulv(v19, __ T4S, v20, v21); // mul v19.4S, v20.4S, v21.4S + __ fabd(v22, __ T2S, v23, v24); // fabd v22.2S, v23.2S, v24.2S + __ fabd(v10, __ T4S, v11, v12); // fabd v10.4S, v11.4S, v12.4S + __ fabd(v4, __ T2D, v5, v6); // fabd v4.2D, v5.2D, v6.2D + __ fmul(v30, __ T2S, v31, v0); // fmul v30.2S, v31.2S, v0.2S + __ fmul(v20, __ T4S, v21, v22); // fmul v20.4S, v21.4S, v22.4S + __ fmul(v8, __ T2D, v9, v10); // fmul v8.2D, v9.2D, v10.2D + __ mlav(v30, __ T4H, v31, v0); // mla v30.4H, v31.4H, v0.4H + __ mlav(v17, __ T8H, v18, v19); // mla v17.8H, v18.8H, v19.8H + __ mlav(v10, __ T2S, v11, v12); // mla v10.2S, v11.2S, v12.2S + __ mlav(v27, __ T4S, v28, v29); // mla v27.4S, v28.4S, v29.4S + __ fmla(v2, __ T2S, v3, v4); // fmla v2.2S, v3.2S, v4.2S + __ fmla(v24, __ T4S, v25, v26); // fmla v24.4S, v25.4S, v26.4S + __ fmla(v4, __ T2D, v5, v6); // fmla v4.2D, v5.2D, v6.2D + __ mlsv(v3, __ T4H, v4, v5); // mls v3.4H, v4.4H, v5.4H + __ mlsv(v8, __ T8H, v9, v10); // mls v8.8H, v9.8H, v10.8H + __ mlsv(v22, __ T2S, v23, v24); // mls v22.2S, v23.2S, v24.2S + __ mlsv(v17, __ T4S, v18, v19); // mls v17.4S, v18.4S, v19.4S + __ fmls(v13, __ T2S, v14, v15); // fmls v13.2S, v14.2S, v15.2S + __ fmls(v4, __ T4S, v5, v6); // fmls v4.4S, v5.4S, v6.4S + __ fmls(v28, __ T2D, v29, v30); // fmls v28.2D, v29.2D, v30.2D + __ fdiv(v23, __ T2S, v24, v25); // fdiv v23.2S, v24.2S, v25.2S + __ fdiv(v21, __ T4S, v22, v23); // fdiv v21.4S, v22.4S, v23.4S + __ fdiv(v25, __ T2D, v26, v27); // fdiv v25.2D, v26.2D, v27.2D + __ maxv(v24, __ T8B, v25, v26); // smax v24.8B, v25.8B, v26.8B + __ maxv(v3, __ T16B, v4, v5); // smax v3.16B, v4.16B, v5.16B + __ maxv(v23, __ T4H, v24, v25); // smax v23.4H, v24.4H, v25.4H + __ maxv(v26, __ T8H, v27, v28); // smax v26.8H, v27.8H, v28.8H + __ maxv(v23, __ T2S, v24, v25); // smax v23.2S, v24.2S, v25.2S + __ maxv(v14, __ T4S, v15, v16); // smax v14.4S, v15.4S, v16.4S + __ smaxp(v21, __ T8B, v22, v23); // smaxp v21.8B, v22.8B, v23.8B + __ smaxp(v3, __ T16B, v4, v5); // smaxp v3.16B, v4.16B, v5.16B + __ smaxp(v23, __ T4H, v24, v25); // smaxp v23.4H, v24.4H, v25.4H + __ smaxp(v8, __ T8H, v9, v10); // smaxp v8.8H, v9.8H, v10.8H + __ smaxp(v24, __ T2S, v25, v26); // smaxp v24.2S, v25.2S, v26.2S + __ smaxp(v19, __ T4S, v20, v21); // smaxp v19.4S, v20.4S, v21.4S + __ fmax(v15, __ T2S, v16, v17); // fmax v15.2S, v16.2S, v17.2S + __ fmax(v16, __ T4S, v17, v18); // fmax v16.4S, v17.4S, v18.4S + __ fmax(v2, __ T2D, v3, v4); // fmax v2.2D, v3.2D, v4.2D + __ minv(v1, __ T8B, v2, v3); // smin v1.8B, v2.8B, v3.8B + __ minv(v0, __ T16B, v1, v2); // smin v0.16B, v1.16B, v2.16B + __ minv(v24, __ T4H, v25, v26); // smin v24.4H, v25.4H, v26.4H + __ minv(v4, __ T8H, v5, v6); // smin v4.8H, v5.8H, v6.8H + __ minv(v3, __ T2S, v4, v5); // smin v3.2S, v4.2S, v5.2S + __ minv(v11, __ T4S, v12, v13); // smin v11.4S, v12.4S, v13.4S + __ sminp(v30, __ T8B, v31, v0); // sminp v30.8B, v31.8B, v0.8B + __ sminp(v27, __ T16B, v28, v29); // sminp v27.16B, v28.16B, v29.16B + __ sminp(v9, __ T4H, v10, v11); // sminp v9.4H, v10.4H, v11.4H + __ sminp(v25, __ T8H, v26, v27); // sminp v25.8H, v26.8H, v27.8H + __ sminp(v2, __ T2S, v3, v4); // sminp v2.2S, v3.2S, v4.2S + __ sminp(v12, __ T4S, v13, v14); // sminp v12.4S, v13.4S, v14.4S + __ fmin(v17, __ T2S, v18, v19); // fmin v17.2S, v18.2S, v19.2S + __ fmin(v30, __ T4S, v31, v0); // fmin v30.4S, v31.4S, v0.4S + __ fmin(v1, __ T2D, v2, v3); // fmin v1.2D, v2.2D, v3.2D + __ cmeq(v12, __ T8B, v13, v14); // cmeq v12.8B, v13.8B, v14.8B + __ cmeq(v28, __ T16B, v29, v30); // cmeq v28.16B, v29.16B, v30.16B + __ cmeq(v0, __ T4H, v1, v2); // cmeq v0.4H, v1.4H, v2.4H + __ cmeq(v17, __ T8H, v18, v19); // cmeq v17.8H, v18.8H, v19.8H + __ cmeq(v12, __ T2S, v13, v14); // cmeq v12.2S, v13.2S, v14.2S __ cmeq(v17, __ T4S, v18, v19); // cmeq v17.4S, v18.4S, v19.4S - __ cmeq(v13, __ T2D, v14, v15); // cmeq v13.2D, v14.2D, v15.2D - __ fcmeq(v4, __ T2S, v5, v6); // fcmeq v4.2S, v5.2S, v6.2S - __ fcmeq(v28, __ T4S, v29, v30); // fcmeq v28.4S, v29.4S, v30.4S - __ fcmeq(v23, __ T2D, v24, v25); // fcmeq v23.2D, v24.2D, v25.2D - __ cmgt(v21, __ T8B, v22, v23); // cmgt v21.8B, v22.8B, v23.8B - __ cmgt(v25, __ T16B, v26, v27); // cmgt v25.16B, v26.16B, v27.16B - __ cmgt(v24, __ T4H, v25, v26); // cmgt v24.4H, v25.4H, v26.4H - __ cmgt(v3, __ T8H, v4, v5); // cmgt v3.8H, v4.8H, v5.8H - __ cmgt(v23, __ T2S, v24, v25); // cmgt v23.2S, v24.2S, v25.2S - __ cmgt(v26, __ T4S, v27, v28); // cmgt v26.4S, v27.4S, v28.4S - __ cmgt(v23, __ T2D, v24, v25); // cmgt v23.2D, v24.2D, v25.2D - __ cmhi(v14, __ T8B, v15, v16); // cmhi v14.8B, v15.8B, v16.8B - __ cmhi(v21, __ T16B, v22, v23); // cmhi v21.16B, v22.16B, v23.16B - __ cmhi(v3, __ T4H, v4, v5); // cmhi v3.4H, v4.4H, v5.4H - __ cmhi(v23, __ T8H, v24, v25); // cmhi v23.8H, v24.8H, v25.8H + __ cmeq(v21, __ T2D, v22, v23); // cmeq v21.2D, v22.2D, v23.2D + __ fcmeq(v12, __ T2S, v13, v14); // fcmeq v12.2S, v13.2S, v14.2S + __ fcmeq(v27, __ T4S, v28, v29); // fcmeq v27.4S, v28.4S, v29.4S + __ fcmeq(v29, __ T2D, v30, v31); // fcmeq v29.2D, v30.2D, v31.2D + __ cmgt(v30, __ T8B, v31, v0); // cmgt v30.8B, v31.8B, v0.8B + __ cmgt(v1, __ T16B, v2, v3); // cmgt v1.16B, v2.16B, v3.16B + __ cmgt(v25, __ T4H, v26, v27); // cmgt v25.4H, v26.4H, v27.4H + __ cmgt(v27, __ T8H, v28, v29); // cmgt v27.8H, v28.8H, v29.8H + __ cmgt(v4, __ T2S, v5, v6); // cmgt v4.2S, v5.2S, v6.2S + __ cmgt(v29, __ T4S, v30, v31); // cmgt v29.4S, v30.4S, v31.4S + __ cmgt(v3, __ T2D, v4, v5); // cmgt v3.2D, v4.2D, v5.2D + __ cmhi(v6, __ T8B, v7, v8); // cmhi v6.8B, v7.8B, v8.8B + __ cmhi(v29, __ T16B, v30, v31); // cmhi v29.16B, v30.16B, v31.16B + __ cmhi(v25, __ T4H, v26, v27); // cmhi v25.4H, v26.4H, v27.4H + __ cmhi(v17, __ T8H, v18, v19); // cmhi v17.8H, v18.8H, v19.8H __ cmhi(v8, __ T2S, v9, v10); // cmhi v8.2S, v9.2S, v10.2S - __ cmhi(v24, __ T4S, v25, v26); // cmhi v24.4S, v25.4S, v26.4S - __ cmhi(v19, __ T2D, v20, v21); // cmhi v19.2D, v20.2D, v21.2D - __ cmhs(v15, __ T8B, v16, v17); // cmhs v15.8B, v16.8B, v17.8B - __ cmhs(v16, __ T16B, v17, v18); // cmhs v16.16B, v17.16B, v18.16B - __ cmhs(v2, __ T4H, v3, v4); // cmhs v2.4H, v3.4H, v4.4H - __ cmhs(v1, __ T8H, v2, v3); // cmhs v1.8H, v2.8H, v3.8H - __ cmhs(v0, __ T2S, v1, v2); // cmhs v0.2S, v1.2S, v2.2S - __ cmhs(v24, __ T4S, v25, v26); // cmhs v24.4S, v25.4S, v26.4S - __ cmhs(v4, __ T2D, v5, v6); // cmhs v4.2D, v5.2D, v6.2D - __ fcmgt(v3, __ T2S, v4, v5); // fcmgt v3.2S, v4.2S, v5.2S - __ fcmgt(v11, __ T4S, v12, v13); // fcmgt v11.4S, v12.4S, v13.4S - __ fcmgt(v30, __ T2D, v31, v0); // fcmgt v30.2D, v31.2D, v0.2D - __ cmge(v27, __ T8B, v28, v29); // cmge v27.8B, v28.8B, v29.8B - __ cmge(v9, __ T16B, v10, v11); // cmge v9.16B, v10.16B, v11.16B - __ cmge(v25, __ T4H, v26, v27); // cmge v25.4H, v26.4H, v27.4H - __ cmge(v2, __ T8H, v3, v4); // cmge v2.8H, v3.8H, v4.8H - __ cmge(v12, __ T2S, v13, v14); // cmge v12.2S, v13.2S, v14.2S - __ cmge(v17, __ T4S, v18, v19); // cmge v17.4S, v18.4S, v19.4S - __ cmge(v30, __ T2D, v31, v0); // cmge v30.2D, v31.2D, v0.2D + __ cmhi(v7, __ T4S, v8, v9); // cmhi v7.4S, v8.4S, v9.4S + __ cmhi(v12, __ T2D, v13, v14); // cmhi v12.2D, v13.2D, v14.2D + __ cmhs(v0, __ T8B, v1, v2); // cmhs v0.8B, v1.8B, v2.8B + __ cmhs(v19, __ T16B, v20, v21); // cmhs v19.16B, v20.16B, v21.16B + __ cmhs(v1, __ T4H, v2, v3); // cmhs v1.4H, v2.4H, v3.4H + __ cmhs(v23, __ T8H, v24, v25); // cmhs v23.8H, v24.8H, v25.8H + __ cmhs(v2, __ T2S, v3, v4); // cmhs v2.2S, v3.2S, v4.2S + __ cmhs(v0, __ T4S, v1, v2); // cmhs v0.4S, v1.4S, v2.4S + __ cmhs(v8, __ T2D, v9, v10); // cmhs v8.2D, v9.2D, v10.2D + __ fcmgt(v23, __ T2S, v24, v25); // fcmgt v23.2S, v24.2S, v25.2S + __ fcmgt(v25, __ T4S, v26, v27); // fcmgt v25.4S, v26.4S, v27.4S + __ fcmgt(v15, __ T2D, v16, v17); // fcmgt v15.2D, v16.2D, v17.2D + __ cmge(v29, __ T8B, v30, v31); // cmge v29.8B, v30.8B, v31.8B + __ cmge(v3, __ T16B, v4, v5); // cmge v3.16B, v4.16B, v5.16B + __ cmge(v10, __ T4H, v11, v12); // cmge v10.4H, v11.4H, v12.4H + __ cmge(v22, __ T8H, v23, v24); // cmge v22.8H, v23.8H, v24.8H + __ cmge(v10, __ T2S, v11, v12); // cmge v10.2S, v11.2S, v12.2S + __ cmge(v4, __ T4S, v5, v6); // cmge v4.4S, v5.4S, v6.4S + __ cmge(v17, __ T2D, v18, v19); // cmge v17.2D, v18.2D, v19.2D __ fcmge(v1, __ T2S, v2, v3); // fcmge v1.2S, v2.2S, v3.2S - __ fcmge(v12, __ T4S, v13, v14); // fcmge v12.4S, v13.4S, v14.4S - __ fcmge(v28, __ T2D, v29, v30); // fcmge v28.2D, v29.2D, v30.2D + __ fcmge(v11, __ T4S, v12, v13); // fcmge v11.4S, v12.4S, v13.4S + __ fcmge(v7, __ T2D, v8, v9); // fcmge v7.2D, v8.2D, v9.2D // SpecialCases __ ccmn(zr, zr, 3u, Assembler::LE); // ccmn xzr, xzr, #3, LE @@ -713,10 +761,10 @@ __ stxpw(r6, zr, zr, sp); // stxp w6, wzr, wzr, [sp] __ dup(v0, __ T16B, zr); // dup v0.16b, wzr __ dup(v0, __ S, v1); // dup s0, v1.s[0] - __ mov(v1, __ T1D, 0, zr); // mov v1.d[0], xzr - __ mov(v1, __ T2S, 1, zr); // mov v1.s[1], wzr - __ mov(v1, __ T4H, 2, zr); // mov v1.h[2], wzr - __ mov(v1, __ T8B, 3, zr); // mov v1.b[3], wzr + __ mov(v1, __ D, 0, zr); // mov v1.d[0], xzr + __ mov(v1, __ S, 1, zr); // mov v1.s[1], wzr + __ mov(v1, __ H, 2, zr); // mov v1.h[2], wzr + __ mov(v1, __ B, 3, zr); // mov v1.b[3], wzr __ smov(r0, v1, __ S, 0); // smov x0, v1.s[0] __ smov(r0, v1, __ H, 1); // smov x0, v1.h[1] __ smov(r0, v1, __ B, 2); // smov x0, v1.b[2] @@ -864,9 +912,22 @@ __ sve_bic(p10, p7, p9, p11); // bic p10.b, p7/z, p9.b, p11.b __ sve_ptest(p7, p1); // ptest p7, p1.b __ sve_ptrue(p1, __ B); // ptrue p1.b + __ sve_ptrue(p1, __ B, 0b00001); // ptrue p1.b, vl1 + __ sve_ptrue(p1, __ B, 0b00101); // ptrue p1.b, vl5 + __ sve_ptrue(p1, __ B, 0b01001); // ptrue p1.b, vl16 + __ sve_ptrue(p1, __ B, 0b01101); // ptrue p1.b, vl256 __ sve_ptrue(p2, __ H); // ptrue p2.h + __ sve_ptrue(p2, __ H, 0b00010); // ptrue p2.h, vl2 + __ sve_ptrue(p2, __ H, 0b00110); // ptrue p2.h, vl6 + __ sve_ptrue(p2, __ H, 0b01010); // ptrue p2.h, vl32 __ sve_ptrue(p3, __ S); // ptrue p3.s + __ sve_ptrue(p3, __ S, 0b00011); // ptrue p3.s, vl3 + __ sve_ptrue(p3, __ S, 0b00111); // ptrue p3.s, vl7 + __ sve_ptrue(p3, __ S, 0b01011); // ptrue p3.s, vl64 __ sve_ptrue(p4, __ D); // ptrue p4.d + __ sve_ptrue(p4, __ D, 0b00100); // ptrue p4.d, vl4 + __ sve_ptrue(p4, __ D, 0b01000); // ptrue p4.d, vl8 + __ sve_ptrue(p4, __ D, 0b01100); // ptrue p4.d, vl128 __ sve_pfalse(p7); // pfalse p7.b __ sve_uzp1(p0, __ B, p0, p1); // uzp1 p0.b, p0.b, p1.b __ sve_uzp1(p0, __ H, p0, p1); // uzp1 p0.h, p0.h, p1.h @@ -914,162 +975,205 @@ __ fmovd(v0, -1.0625); // fmov d0, #-1.0625 // LSEOp - __ swp(Assembler::xword, r0, r19, r12); // swp x0, x19, [x12] - __ ldadd(Assembler::xword, r17, r22, r13); // ldadd x17, x22, [x13] - __ ldbic(Assembler::xword, r28, r30, sp); // ldclr x28, x30, [sp] - __ ldeor(Assembler::xword, r1, r26, r28); // ldeor x1, x26, [x28] - __ ldorr(Assembler::xword, r4, r30, r4); // ldset x4, x30, [x4] - __ ldsmin(Assembler::xword, r6, r30, r26); // ldsmin x6, x30, [x26] - __ ldsmax(Assembler::xword, r16, r9, r8); // ldsmax x16, x9, [x8] - __ ldumin(Assembler::xword, r12, r0, r20); // ldumin x12, x0, [x20] - __ ldumax(Assembler::xword, r1, r24, r2); // ldumax x1, x24, [x2] + __ swp(Assembler::xword, r10, r15, r17); // swp x10, x15, [x17] + __ ldadd(Assembler::xword, r2, r10, r12); // ldadd x2, x10, [x12] + __ ldbic(Assembler::xword, r12, r15, r13); // ldclr x12, x15, [x13] + __ ldeor(Assembler::xword, r2, r7, r20); // ldeor x2, x7, [x20] + __ ldorr(Assembler::xword, r26, r16, r4); // ldset x26, x16, [x4] + __ ldsmin(Assembler::xword, r2, r4, r12); // ldsmin x2, x4, [x12] + __ ldsmax(Assembler::xword, r16, r21, r16); // ldsmax x16, x21, [x16] + __ ldumin(Assembler::xword, r16, r11, r21); // ldumin x16, x11, [x21] + __ ldumax(Assembler::xword, r23, r12, r26); // ldumax x23, x12, [x26] // LSEOp - __ swpa(Assembler::xword, r0, r9, r24); // swpa x0, x9, [x24] - __ ldadda(Assembler::xword, r26, r16, r30); // ldadda x26, x16, [x30] - __ ldbica(Assembler::xword, r3, r10, r23); // ldclra x3, x10, [x23] - __ ldeora(Assembler::xword, r10, r4, r15); // ldeora x10, x4, [x15] - __ ldorra(Assembler::xword, r2, r11, r8); // ldseta x2, x11, [x8] - __ ldsmina(Assembler::xword, r10, r15, r17); // ldsmina x10, x15, [x17] - __ ldsmaxa(Assembler::xword, r2, r10, r12); // ldsmaxa x2, x10, [x12] - __ ldumina(Assembler::xword, r12, r15, r13); // ldumina x12, x15, [x13] - __ ldumaxa(Assembler::xword, r2, r7, r20); // ldumaxa x2, x7, [x20] + __ swpa(Assembler::xword, r23, r28, r14); // swpa x23, x28, [x14] + __ ldadda(Assembler::xword, r11, r24, r1); // ldadda x11, x24, [x1] + __ ldbica(Assembler::xword, r12, zr, r10); // ldclra x12, xzr, [x10] + __ ldeora(Assembler::xword, r16, r7, r2); // ldeora x16, x7, [x2] + __ ldorra(Assembler::xword, r3, r13, r19); // ldseta x3, x13, [x19] + __ ldsmina(Assembler::xword, r17, r16, r3); // ldsmina x17, x16, [x3] + __ ldsmaxa(Assembler::xword, r1, r11, r30); // ldsmaxa x1, x11, [x30] + __ ldumina(Assembler::xword, r5, r8, r15); // ldumina x5, x8, [x15] + __ ldumaxa(Assembler::xword, r29, r30, r0); // ldumaxa x29, x30, [x0] // LSEOp - __ swpal(Assembler::xword, r26, r16, r4); // swpal x26, x16, [x4] - __ ldaddal(Assembler::xword, r2, r4, r12); // ldaddal x2, x4, [x12] - __ ldbical(Assembler::xword, r16, r21, r16); // ldclral x16, x21, [x16] - __ ldeoral(Assembler::xword, r16, r11, r21); // ldeoral x16, x11, [x21] - __ ldorral(Assembler::xword, r23, r12, r26); // ldsetal x23, x12, [x26] - __ ldsminal(Assembler::xword, r23, r28, r14); // ldsminal x23, x28, [x14] - __ ldsmaxal(Assembler::xword, r11, r24, r1); // ldsmaxal x11, x24, [x1] - __ lduminal(Assembler::xword, r12, zr, r10); // lduminal x12, xzr, [x10] - __ ldumaxal(Assembler::xword, r16, r7, r2); // ldumaxal x16, x7, [x2] + __ swpal(Assembler::xword, r20, r7, r20); // swpal x20, x7, [x20] + __ ldaddal(Assembler::xword, r23, r28, r21); // ldaddal x23, x28, [x21] + __ ldbical(Assembler::xword, r27, r25, r5); // ldclral x27, x25, [x5] + __ ldeoral(Assembler::xword, r1, r23, r16); // ldeoral x1, x23, [x16] + __ ldorral(Assembler::xword, zr, r5, r12); // ldsetal xzr, x5, [x12] + __ ldsminal(Assembler::xword, r9, r28, r15); // ldsminal x9, x28, [x15] + __ ldsmaxal(Assembler::xword, r29, r22, sp); // ldsmaxal x29, x22, [sp] + __ lduminal(Assembler::xword, r19, zr, r5); // lduminal x19, xzr, [x5] + __ ldumaxal(Assembler::xword, r14, r16, sp); // ldumaxal x14, x16, [sp] // LSEOp - __ swpl(Assembler::xword, r3, r13, r19); // swpl x3, x13, [x19] - __ ldaddl(Assembler::xword, r17, r16, r3); // ldaddl x17, x16, [x3] - __ ldbicl(Assembler::xword, r1, r11, r30); // ldclrl x1, x11, [x30] - __ ldeorl(Assembler::xword, r5, r8, r15); // ldeorl x5, x8, [x15] - __ ldorrl(Assembler::xword, r29, r30, r0); // ldsetl x29, x30, [x0] - __ ldsminl(Assembler::xword, r20, r7, r20); // ldsminl x20, x7, [x20] - __ ldsmaxl(Assembler::xword, r23, r28, r21); // ldsmaxl x23, x28, [x21] - __ lduminl(Assembler::xword, r27, r25, r5); // lduminl x27, x25, [x5] - __ ldumaxl(Assembler::xword, r1, r23, r16); // ldumaxl x1, x23, [x16] + __ swpl(Assembler::xword, r16, r27, r20); // swpl x16, x27, [x20] + __ ldaddl(Assembler::xword, r16, r12, r11); // ldaddl x16, x12, [x11] + __ ldbicl(Assembler::xword, r9, r6, r30); // ldclrl x9, x6, [x30] + __ ldeorl(Assembler::xword, r17, r27, r28); // ldeorl x17, x27, [x28] + __ ldorrl(Assembler::xword, r30, r7, r10); // ldsetl x30, x7, [x10] + __ ldsminl(Assembler::xword, r20, r10, r4); // ldsminl x20, x10, [x4] + __ ldsmaxl(Assembler::xword, r24, r17, r17); // ldsmaxl x24, x17, [x17] + __ lduminl(Assembler::xword, r22, r3, r29); // lduminl x22, x3, [x29] + __ ldumaxl(Assembler::xword, r15, r22, r19); // ldumaxl x15, x22, [x19] // LSEOp - __ swp(Assembler::word, zr, r5, r12); // swp wzr, w5, [x12] - __ ldadd(Assembler::word, r9, r28, r15); // ldadd w9, w28, [x15] - __ ldbic(Assembler::word, r29, r22, sp); // ldclr w29, w22, [sp] - __ ldeor(Assembler::word, r19, zr, r5); // ldeor w19, wzr, [x5] - __ ldorr(Assembler::word, r14, r16, sp); // ldset w14, w16, [sp] - __ ldsmin(Assembler::word, r16, r27, r20); // ldsmin w16, w27, [x20] - __ ldsmax(Assembler::word, r16, r12, r11); // ldsmax w16, w12, [x11] - __ ldumin(Assembler::word, r9, r6, r30); // ldumin w9, w6, [x30] - __ ldumax(Assembler::word, r17, r27, r28); // ldumax w17, w27, [x28] + __ swp(Assembler::word, r19, r22, r2); // swp w19, w22, [x2] + __ ldadd(Assembler::word, r15, r6, r12); // ldadd w15, w6, [x12] + __ ldbic(Assembler::word, r16, r11, r13); // ldclr w16, w11, [x13] + __ ldeor(Assembler::word, r23, r1, r30); // ldeor w23, w1, [x30] + __ ldorr(Assembler::word, r19, r5, r17); // ldset w19, w5, [x17] + __ ldsmin(Assembler::word, r2, r16, r22); // ldsmin w2, w16, [x22] + __ ldsmax(Assembler::word, r13, r10, r21); // ldsmax w13, w10, [x21] + __ ldumin(Assembler::word, r29, r27, r12); // ldumin w29, w27, [x12] + __ ldumax(Assembler::word, r27, r3, r1); // ldumax w27, w3, [x1] // LSEOp - __ swpa(Assembler::word, r30, r7, r10); // swpa w30, w7, [x10] - __ ldadda(Assembler::word, r20, r10, r4); // ldadda w20, w10, [x4] - __ ldbica(Assembler::word, r24, r17, r17); // ldclra w24, w17, [x17] - __ ldeora(Assembler::word, r22, r3, r29); // ldeora w22, w3, [x29] - __ ldorra(Assembler::word, r15, r22, r19); // ldseta w15, w22, [x19] - __ ldsmina(Assembler::word, r19, r22, r2); // ldsmina w19, w22, [x2] - __ ldsmaxa(Assembler::word, r15, r6, r12); // ldsmaxa w15, w6, [x12] - __ ldumina(Assembler::word, r16, r11, r13); // ldumina w16, w11, [x13] - __ ldumaxa(Assembler::word, r23, r1, r30); // ldumaxa w23, w1, [x30] + __ swpa(Assembler::word, zr, r24, r19); // swpa wzr, w24, [x19] + __ ldadda(Assembler::word, r17, r9, r28); // ldadda w17, w9, [x28] + __ ldbica(Assembler::word, r27, r15, r7); // ldclra w27, w15, [x7] + __ ldeora(Assembler::word, r21, r23, sp); // ldeora w21, w23, [sp] + __ ldorra(Assembler::word, r25, r2, sp); // ldseta w25, w2, [sp] + __ ldsmina(Assembler::word, r27, r16, r10); // ldsmina w27, w16, [x10] + __ ldsmaxa(Assembler::word, r23, r19, r3); // ldsmaxa w23, w19, [x3] + __ ldumina(Assembler::word, r16, r0, r25); // ldumina w16, w0, [x25] + __ ldumaxa(Assembler::word, r26, r23, r2); // ldumaxa w26, w23, [x2] // LSEOp - __ swpal(Assembler::word, r19, r5, r17); // swpal w19, w5, [x17] - __ ldaddal(Assembler::word, r2, r16, r22); // ldaddal w2, w16, [x22] - __ ldbical(Assembler::word, r13, r10, r21); // ldclral w13, w10, [x21] - __ ldeoral(Assembler::word, r29, r27, r12); // ldeoral w29, w27, [x12] - __ ldorral(Assembler::word, r27, r3, r1); // ldsetal w27, w3, [x1] - __ ldsminal(Assembler::word, zr, r24, r19); // ldsminal wzr, w24, [x19] - __ ldsmaxal(Assembler::word, r17, r9, r28); // ldsmaxal w17, w9, [x28] - __ lduminal(Assembler::word, r27, r15, r7); // lduminal w27, w15, [x7] - __ ldumaxal(Assembler::word, r21, r23, sp); // ldumaxal w21, w23, [sp] + __ swpal(Assembler::word, r16, r12, r4); // swpal w16, w12, [x4] + __ ldaddal(Assembler::word, r28, r30, r29); // ldaddal w28, w30, [x29] + __ ldbical(Assembler::word, r16, r27, r6); // ldclral w16, w27, [x6] + __ ldeoral(Assembler::word, r9, r29, r15); // ldeoral w9, w29, [x15] + __ ldorral(Assembler::word, r7, r4, r7); // ldsetal w7, w4, [x7] + __ ldsminal(Assembler::word, r15, r9, r23); // ldsminal w15, w9, [x23] + __ ldsmaxal(Assembler::word, r8, r2, r28); // ldsmaxal w8, w2, [x28] + __ lduminal(Assembler::word, r21, zr, r5); // lduminal w21, wzr, [x5] + __ ldumaxal(Assembler::word, r27, r0, r17); // ldumaxal w27, w0, [x17] // LSEOp - __ swpl(Assembler::word, r25, r2, sp); // swpl w25, w2, [sp] - __ ldaddl(Assembler::word, r27, r16, r10); // ldaddl w27, w16, [x10] - __ ldbicl(Assembler::word, r23, r19, r3); // ldclrl w23, w19, [x3] - __ ldeorl(Assembler::word, r16, r0, r25); // ldeorl w16, w0, [x25] - __ ldorrl(Assembler::word, r26, r23, r2); // ldsetl w26, w23, [x2] - __ ldsminl(Assembler::word, r16, r12, r4); // ldsminl w16, w12, [x4] - __ ldsmaxl(Assembler::word, r28, r30, r29); // ldsmaxl w28, w30, [x29] - __ lduminl(Assembler::word, r16, r27, r6); // lduminl w16, w27, [x6] - __ ldumaxl(Assembler::word, r9, r29, r15); // ldumaxl w9, w29, [x15] + __ swpl(Assembler::word, r15, r4, r26); // swpl w15, w4, [x26] + __ ldaddl(Assembler::word, r8, r28, r22); // ldaddl w8, w28, [x22] + __ ldbicl(Assembler::word, r27, r27, r25); // ldclrl w27, w27, [x25] + __ ldeorl(Assembler::word, r23, r0, r4); // ldeorl w23, w0, [x4] + __ ldorrl(Assembler::word, r6, r16, r0); // ldsetl w6, w16, [x0] + __ ldsminl(Assembler::word, r4, r15, r1); // ldsminl w4, w15, [x1] + __ ldsmaxl(Assembler::word, r10, r7, r5); // ldsmaxl w10, w7, [x5] + __ lduminl(Assembler::word, r10, r28, r7); // lduminl w10, w28, [x7] + __ ldumaxl(Assembler::word, r20, r23, r21); // ldumaxl w20, w23, [x21] // SHA3SIMDOp - __ bcax(v7, __ T16B, v4, v7, v15); // bcax v7.16B, v4.16B, v7.16B, v15.16B - __ eor3(v9, __ T16B, v22, v8, v2); // eor3 v9.16B, v22.16B, v8.16B, v2.16B - __ rax1(v27, __ T2D, v20, v30); // rax1 v27.2D, v20.2D, v30.2D - __ xar(v5, __ T2D, v26, v0, 34); // xar v5.2D, v26.2D, v0.2D, #34 + __ bcax(v5, __ T16B, v10, v8, v16); // bcax v5.16B, v10.16B, v8.16B, v16.16B + __ eor3(v30, __ T16B, v6, v17, v2); // eor3 v30.16B, v6.16B, v17.16B, v2.16B + __ rax1(v11, __ T2D, v29, v28); // rax1 v11.2D, v29.2D, v28.2D + __ xar(v2, __ T2D, v26, v22, 58); // xar v2.2D, v26.2D, v22.2D, #58 // SHA512SIMDOp - __ sha512h(v14, __ T2D, v3, v25); // sha512h q14, q3, v25.2D - __ sha512h2(v8, __ T2D, v27, v21); // sha512h2 q8, q27, v21.2D - __ sha512su0(v26, __ T2D, v26); // sha512su0 v26.2D, v26.2D - __ sha512su1(v24, __ T2D, v22, v0); // sha512su1 v24.2D, v22.2D, v0.2D + __ sha512h(v14, __ T2D, v13, v27); // sha512h q14, q13, v27.2D + __ sha512h2(v16, __ T2D, v23, v5); // sha512h2 q16, q23, v5.2D + __ sha512su0(v2, __ T2D, v13); // sha512su0 v2.2D, v13.2D + __ sha512su1(v10, __ T2D, v15, v10); // sha512su1 v10.2D, v15.2D, v10.2D + +// SVEBinaryImmOp + __ sve_add(z26, __ S, 98u); // add z26.s, z26.s, #0x62 + __ sve_sub(z3, __ S, 138u); // sub z3.s, z3.s, #0x8a + __ sve_and(z4, __ B, 131u); // and z4.b, z4.b, #0x83 + __ sve_eor(z17, __ H, 16368u); // eor z17.h, z17.h, #0x3ff0 + __ sve_orr(z2, __ S, 4164941887u); // orr z2.s, z2.s, #0xf83ff83f + +// SVEBinaryImmOp + __ sve_add(z23, __ B, 51u); // add z23.b, z23.b, #0x33 + __ sve_sub(z7, __ S, 104u); // sub z7.s, z7.s, #0x68 + __ sve_and(z27, __ S, 7864320u); // and z27.s, z27.s, #0x780000 + __ sve_eor(z2, __ D, 68719476224u); // eor z2.d, z2.d, #0xffffffe00 + __ sve_orr(z6, __ S, 1056980736u); // orr z6.s, z6.s, #0x3f003f00 + +// SVEBinaryImmOp + __ sve_add(z12, __ S, 67u); // add z12.s, z12.s, #0x43 + __ sve_sub(z24, __ S, 154u); // sub z24.s, z24.s, #0x9a + __ sve_and(z0, __ H, 511u); // and z0.h, z0.h, #0x1ff + __ sve_eor(z19, __ D, 9241386433220968447u); // eor z19.d, z19.d, #0x803fffff803fffff + __ sve_orr(z6, __ B, 128u); // orr z6.b, z6.b, #0x80 + +// SVEBinaryImmOp + __ sve_add(z17, __ D, 74u); // add z17.d, z17.d, #0x4a + __ sve_sub(z10, __ S, 170u); // sub z10.s, z10.s, #0xaa + __ sve_and(z22, __ D, 17179852800u); // and z22.d, z22.d, #0x3ffffc000 + __ sve_eor(z15, __ S, 8388600u); // eor z15.s, z15.s, #0x7ffff8 + __ sve_orr(z4, __ D, 8064u); // orr z4.d, z4.d, #0x1f80 + +// SVEBinaryImmOp + __ sve_add(z8, __ S, 162u); // add z8.s, z8.s, #0xa2 + __ sve_sub(z22, __ B, 130u); // sub z22.b, z22.b, #0x82 + __ sve_and(z9, __ S, 4292870159u); // and z9.s, z9.s, #0xffe0000f + __ sve_eor(z5, __ D, 1150687262887383032u); // eor z5.d, z5.d, #0xff80ff80ff80ff8 + __ sve_orr(z22, __ H, 32256u); // orr z22.h, z22.h, #0x7e00 + +// SVEBinaryImmOp + __ sve_add(z8, __ S, 134u); // add z8.s, z8.s, #0x86 + __ sve_sub(z25, __ H, 39u); // sub z25.h, z25.h, #0x27 + __ sve_and(z4, __ S, 4186112u); // and z4.s, z4.s, #0x3fe000 + __ sve_eor(z29, __ B, 131u); // eor z29.b, z29.b, #0x83 + __ sve_orr(z29, __ D, 4611685469745315712u); // orr z29.d, z29.d, #0x3fffff803fffff80 // SVEVectorOp - __ sve_add(z4, __ B, z6, z17); // add z4.b, z6.b, z17.b - __ sve_sub(z3, __ H, z15, z1); // sub z3.h, z15.h, z1.h - __ sve_fadd(z6, __ D, z5, z9); // fadd z6.d, z5.d, z9.d - __ sve_fmul(z7, __ D, z20, z22); // fmul z7.d, z20.d, z22.d - __ sve_fsub(z5, __ D, z10, z8); // fsub z5.d, z10.d, z8.d - __ sve_abs(z30, __ B, p1, z17); // abs z30.b, p1/m, z17.b - __ sve_add(z11, __ B, p7, z28); // add z11.b, p7/m, z11.b, z28.b - __ sve_and(z26, __ H, p5, z28); // and z26.h, p5/m, z26.h, z28.h - __ sve_asr(z13, __ D, p7, z16); // asr z13.d, p7/m, z13.d, z16.d - __ sve_cnt(z5, __ H, p0, z13); // cnt z5.h, p0/m, z13.h - __ sve_eor(z15, __ S, p2, z26); // eor z15.s, p2/m, z15.s, z26.s - __ sve_lsl(z11, __ S, p1, z22); // lsl z11.s, p1/m, z11.s, z22.s - __ sve_lsr(z4, __ S, p0, z19); // lsr z4.s, p0/m, z4.s, z19.s - __ sve_mul(z17, __ H, p3, z14); // mul z17.h, p3/m, z17.h, z14.h - __ sve_neg(z2, __ S, p4, z3); // neg z2.s, p4/m, z3.s - __ sve_not(z23, __ B, p1, z6); // not z23.b, p1/m, z6.b - __ sve_orr(z17, __ S, p3, z27); // orr z17.s, p3/m, z17.s, z27.s - __ sve_smax(z16, __ D, p1, z2); // smax z16.d, p1/m, z16.d, z2.d - __ sve_smin(z3, __ S, p1, z6); // smin z3.s, p1/m, z3.s, z6.s - __ sve_sub(z19, __ S, p3, z12); // sub z19.s, p3/m, z19.s, z12.s - __ sve_fabs(z8, __ D, p6, z19); // fabs z8.d, p6/m, z19.d - __ sve_fadd(z0, __ S, p2, z23); // fadd z0.s, p2/m, z0.s, z23.s - __ sve_fdiv(z19, __ D, p7, z13); // fdiv z19.d, p7/m, z19.d, z13.d - __ sve_fmax(z6, __ S, p0, z7); // fmax z6.s, p0/m, z6.s, z7.s - __ sve_fmin(z17, __ S, p6, z8); // fmin z17.s, p6/m, z17.s, z8.s - __ sve_fmul(z22, __ D, p5, z22); // fmul z22.d, p5/m, z22.d, z22.d - __ sve_fneg(z2, __ D, p0, z15); // fneg z2.d, p0/m, z15.d - __ sve_frintm(z20, __ D, p1, z4); // frintm z20.d, p1/m, z4.d - __ sve_frintn(z7, __ D, p0, z8); // frintn z7.d, p0/m, z8.d - __ sve_frintp(z19, __ D, p5, z4); // frintp z19.d, p5/m, z4.d - __ sve_fsqrt(z9, __ D, p5, z11); // fsqrt z9.d, p5/m, z11.d - __ sve_fsub(z5, __ S, p7, z16); // fsub z5.s, p7/m, z5.s, z16.s - __ sve_fmad(z22, __ S, p3, z1, z13); // fmad z22.s, p3/m, z1.s, z13.s - __ sve_fmla(z20, __ S, p4, z25, z15); // fmla z20.s, p4/m, z25.s, z15.s - __ sve_fmls(z4, __ D, p4, z8, z6); // fmls z4.d, p4/m, z8.d, z6.d - __ sve_fnmla(z4, __ D, p7, z16, z29); // fnmla z4.d, p7/m, z16.d, z29.d - __ sve_fnmls(z9, __ D, p3, z2, z11); // fnmls z9.d, p3/m, z2.d, z11.d - __ sve_mla(z3, __ S, p1, z1, z26); // mla z3.s, p1/m, z1.s, z26.s - __ sve_mls(z17, __ S, p3, z8, z17); // mls z17.s, p3/m, z8.s, z17.s - __ sve_and(z24, z5, z19); // and z24.d, z5.d, z19.d - __ sve_eor(z17, z22, z16); // eor z17.d, z22.d, z16.d - __ sve_orr(z20, z19, z0); // orr z20.d, z19.d, z0.d - __ sve_bic(z17, z23, z4); // bic z17.d, z23.d, z4.d - __ sve_uzp1(z4, __ S, z23, z25); // uzp1 z4.s, z23.s, z25.s - __ sve_uzp2(z2, __ H, z8, z8); // uzp2 z2.h, z8.h, z8.h + __ sve_add(z2, __ B, z11, z28); // add z2.b, z11.b, z28.b + __ sve_sub(z7, __ S, z1, z26); // sub z7.s, z1.s, z26.s + __ sve_fadd(z17, __ D, z14, z8); // fadd z17.d, z14.d, z8.d + __ sve_fmul(z21, __ D, z24, z5); // fmul z21.d, z24.d, z5.d + __ sve_fsub(z21, __ D, z17, z22); // fsub z21.d, z17.d, z22.d + __ sve_abs(z29, __ B, p5, z19); // abs z29.b, p5/m, z19.b + __ sve_add(z4, __ B, p4, z23); // add z4.b, p4/m, z4.b, z23.b + __ sve_and(z19, __ D, p1, z23); // and z19.d, p1/m, z19.d, z23.d + __ sve_asr(z19, __ H, p0, z8); // asr z19.h, p0/m, z19.h, z8.h + __ sve_bic(z14, __ D, p6, z17); // bic z14.d, p6/m, z14.d, z17.d + __ sve_cnt(z21, __ B, p1, z30); // cnt z21.b, p1/m, z30.b + __ sve_eor(z10, __ B, p5, z12); // eor z10.b, p5/m, z10.b, z12.b + __ sve_lsl(z9, __ S, p1, z24); // lsl z9.s, p1/m, z9.s, z24.s + __ sve_lsr(z4, __ H, p6, z6); // lsr z4.h, p6/m, z4.h, z6.h + __ sve_mul(z27, __ S, p6, z13); // mul z27.s, p6/m, z27.s, z13.s + __ sve_neg(z30, __ S, p5, z22); // neg z30.s, p5/m, z22.s + __ sve_not(z30, __ H, p7, z9); // not z30.h, p7/m, z9.h + __ sve_orr(z19, __ D, p1, z20); // orr z19.d, p1/m, z19.d, z20.d + __ sve_smax(z9, __ H, p2, z13); // smax z9.h, p2/m, z9.h, z13.h + __ sve_smin(z19, __ H, p0, z24); // smin z19.h, p0/m, z19.h, z24.h + __ sve_sub(z19, __ S, p3, z17); // sub z19.s, p3/m, z19.s, z17.s + __ sve_fabs(z16, __ S, p1, z0); // fabs z16.s, p1/m, z0.s + __ sve_fadd(z11, __ S, p2, z15); // fadd z11.s, p2/m, z11.s, z15.s + __ sve_fdiv(z15, __ D, p1, z15); // fdiv z15.d, p1/m, z15.d, z15.d + __ sve_fmax(z5, __ D, p0, z10); // fmax z5.d, p0/m, z5.d, z10.d + __ sve_fmin(z26, __ S, p0, z0); // fmin z26.s, p0/m, z26.s, z0.s + __ sve_fmul(z19, __ D, p7, z10); // fmul z19.d, p7/m, z19.d, z10.d + __ sve_fneg(z3, __ D, p5, z7); // fneg z3.d, p5/m, z7.d + __ sve_frintm(z28, __ S, p3, z21); // frintm z28.s, p3/m, z21.s + __ sve_frintn(z26, __ D, p3, z17); // frintn z26.d, p3/m, z17.d + __ sve_frintp(z17, __ D, p3, z2); // frintp z17.d, p3/m, z2.d + __ sve_fsqrt(z16, __ S, p5, z20); // fsqrt z16.s, p5/m, z20.s + __ sve_fsub(z19, __ D, p0, z1); // fsub z19.d, p0/m, z19.d, z1.d + __ sve_fmad(z17, __ D, p2, z16, z17); // fmad z17.d, p2/m, z16.d, z17.d + __ sve_fmla(z0, __ S, p1, z2, z23); // fmla z0.s, p1/m, z2.s, z23.s + __ sve_fmls(z6, __ D, p2, z20, z14); // fmls z6.d, p2/m, z20.d, z14.d + __ sve_fnmla(z29, __ D, p3, z3, z3); // fnmla z29.d, p3/m, z3.d, z3.d + __ sve_fnmls(z9, __ S, p0, z24, z27); // fnmls z9.s, p0/m, z24.s, z27.s + __ sve_mla(z19, __ S, p5, z7, z25); // mla z19.s, p5/m, z7.s, z25.s + __ sve_mls(z13, __ B, p1, z7, z25); // mls z13.b, p1/m, z7.b, z25.b + __ sve_and(z21, z17, z17); // and z21.d, z17.d, z17.d + __ sve_eor(z3, z9, z19); // eor z3.d, z9.d, z19.d + __ sve_orr(z7, z11, z14); // orr z7.d, z11.d, z14.d + __ sve_bic(z17, z11, z13); // bic z17.d, z11.d, z13.d + __ sve_uzp1(z17, __ H, z30, z17); // uzp1 z17.h, z30.h, z17.h + __ sve_uzp2(z15, __ S, z14, z26); // uzp2 z15.s, z14.s, z26.s // SVEReductionOp - __ sve_andv(v24, __ S, p4, z30); // andv s24, p4, z30.s - __ sve_orv(v4, __ H, p7, z1); // orv h4, p7, z1.h - __ sve_eorv(v19, __ H, p3, z0); // eorv h19, p3, z0.h - __ sve_smaxv(v7, __ B, p6, z17); // smaxv b7, p6, z17.b - __ sve_sminv(v27, __ D, p1, z9); // sminv d27, p1, z9.d - __ sve_fminv(v23, __ D, p3, z16); // fminv d23, p3, z16.d - __ sve_fmaxv(v22, __ D, p5, z20); // fmaxv d22, p5, z20.d - __ sve_fadda(v28, __ D, p2, z13); // fadda d28, p2, d28, z13.d - __ sve_uaddv(v7, __ H, p5, z28); // uaddv d7, p5, z28.h + __ sve_andv(v27, __ H, p5, z7); // andv h27, p5, z7.h + __ sve_orv(v5, __ H, p7, z27); // orv h5, p7, z27.h + __ sve_eorv(v0, __ S, p3, z24); // eorv s0, p3, z24.s + __ sve_smaxv(v20, __ S, p0, z3); // smaxv s20, p0, z3.s + __ sve_sminv(v25, __ D, p1, z25); // sminv d25, p1, z25.d + __ sve_fminv(v17, __ S, p4, z1); // fminv s17, p4, z1.s + __ sve_fmaxv(v14, __ S, p7, z13); // fmaxv s14, p7, z13.s + __ sve_fadda(v17, __ D, p0, z30); // fadda d17, p0, d17, z30.d + __ sve_uaddv(v22, __ H, p5, z29); // uaddv d22, p5, z29.h __ bind(forth); @@ -1088,144 +1192,155 @@ 0x9101a1a0, 0xb10a5cc8, 0xd10810aa, 0xf10fd061, 0x120cb166, 0x321764bc, 0x52174681, 0x720c0227, 0x9241018e, 0xb25a2969, 0xd278b411, 0xf26aad01, - 0x14000000, 0x17ffffd7, 0x1400037a, 0x94000000, - 0x97ffffd4, 0x94000377, 0x3400000a, 0x34fffa2a, - 0x34006e8a, 0x35000008, 0x35fff9c8, 0x35006e28, - 0xb400000b, 0xb4fff96b, 0xb4006dcb, 0xb500001d, - 0xb5fff91d, 0xb5006d7d, 0x10000013, 0x10fff8b3, - 0x10006d13, 0x90000013, 0x36300016, 0x3637f836, - 0x36306c96, 0x3758000c, 0x375ff7cc, 0x37586c2c, + 0x14000000, 0x17ffffd7, 0x140003d2, 0x94000000, + 0x97ffffd4, 0x940003cf, 0x3400000a, 0x34fffa2a, + 0x3400798a, 0x35000008, 0x35fff9c8, 0x35007928, + 0xb400000b, 0xb4fff96b, 0xb40078cb, 0xb500001d, + 0xb5fff91d, 0xb500787d, 0x10000013, 0x10fff8b3, + 0x10007813, 0x90000013, 0x36300016, 0x3637f836, + 0x36307796, 0x3758000c, 0x375ff7cc, 0x3758772c, 0x128313a0, 0x528a32c7, 0x7289173b, 0x92ab3acc, 0xd2a0bf94, 0xf2c285e8, 0x9358722f, 0x330e652f, 0x53067f3b, 0x93577c53, 0xb34a1aac, 0xd35a4016, 0x13946c63, 0x93c3dbc8, 0x54000000, 0x54fff5a0, - 0x54006a00, 0x54000001, 0x54fff541, 0x540069a1, - 0x54000002, 0x54fff4e2, 0x54006942, 0x54000002, - 0x54fff482, 0x540068e2, 0x54000003, 0x54fff423, - 0x54006883, 0x54000003, 0x54fff3c3, 0x54006823, - 0x54000004, 0x54fff364, 0x540067c4, 0x54000005, - 0x54fff305, 0x54006765, 0x54000006, 0x54fff2a6, - 0x54006706, 0x54000007, 0x54fff247, 0x540066a7, - 0x54000008, 0x54fff1e8, 0x54006648, 0x54000009, - 0x54fff189, 0x540065e9, 0x5400000a, 0x54fff12a, - 0x5400658a, 0x5400000b, 0x54fff0cb, 0x5400652b, - 0x5400000c, 0x54fff06c, 0x540064cc, 0x5400000d, - 0x54fff00d, 0x5400646d, 0x5400000e, 0x54ffefae, - 0x5400640e, 0x5400000f, 0x54ffef4f, 0x540063af, + 0x54007500, 0x54000001, 0x54fff541, 0x540074a1, + 0x54000002, 0x54fff4e2, 0x54007442, 0x54000002, + 0x54fff482, 0x540073e2, 0x54000003, 0x54fff423, + 0x54007383, 0x54000003, 0x54fff3c3, 0x54007323, + 0x54000004, 0x54fff364, 0x540072c4, 0x54000005, + 0x54fff305, 0x54007265, 0x54000006, 0x54fff2a6, + 0x54007206, 0x54000007, 0x54fff247, 0x540071a7, + 0x54000008, 0x54fff1e8, 0x54007148, 0x54000009, + 0x54fff189, 0x540070e9, 0x5400000a, 0x54fff12a, + 0x5400708a, 0x5400000b, 0x54fff0cb, 0x5400702b, + 0x5400000c, 0x54fff06c, 0x54006fcc, 0x5400000d, + 0x54fff00d, 0x54006f6d, 0x5400000e, 0x54ffefae, + 0x54006f0e, 0x5400000f, 0x54ffef4f, 0x54006eaf, 0xd40658e1, 0xd4014d22, 0xd4046543, 0xd4273f60, - 0xd44cad80, 0xd503201f, 0xd69f03e0, 0xd6bf03e0, - 0xd5033fdf, 0xd5033e9f, 0xd50332bf, 0xd61f0200, - 0xd63f0280, 0xc80a7d1b, 0xc800fea1, 0xc85f7fb1, - 0xc85fff9d, 0xc89ffee1, 0xc8dffe95, 0x88167e7b, - 0x880bfcd0, 0x885f7c11, 0x885ffd44, 0x889ffed8, - 0x88dffe6a, 0x48017fc5, 0x4808fe2c, 0x485f7dc9, - 0x485ffc27, 0x489ffe05, 0x48dffd82, 0x080a7c6c, - 0x081cff4e, 0x085f7d5e, 0x085ffeae, 0x089ffd2d, - 0x08dfff76, 0xc87f4d7c, 0xc87fcc5e, 0xc8220417, - 0xc82cb5f0, 0x887f55b1, 0x887ff90b, 0x88382c2d, - 0x883aedb5, 0xf819928b, 0xb803e21c, 0x381f713b, - 0x781ce322, 0xf850f044, 0xb85e129e, 0x385e92f1, - 0x785ff35d, 0x39801921, 0x7881318b, 0x78dce02b, - 0xb8829313, 0xfc45f318, 0xbc5d50af, 0xfc001375, - 0xbc1951b7, 0xf8008c0a, 0xb801dc03, 0x38009dca, - 0x781fdf3d, 0xf8570e0c, 0xb85faecc, 0x385f6d6d, - 0x785ebea0, 0x38804cd7, 0x789cbce3, 0x78df9c9c, - 0xb89eed18, 0xfc40cd6e, 0xbc5bdd93, 0xfc103c14, - 0xbc040c08, 0xf81a2783, 0xb81ca4eb, 0x381e855b, - 0x7801b4e6, 0xf853654d, 0xb85d74af, 0x384095a2, - 0x785ec5bc, 0x389e15a9, 0x789dc703, 0x78c06474, - 0xb89ff667, 0xfc57e51e, 0xbc4155f9, 0xfc05a6ee, - 0xbc1df408, 0xf835da2a, 0xb836d9a4, 0x3833580d, - 0x7826cb6c, 0xf8706900, 0xb87ae880, 0x3865db2e, - 0x78714889, 0x38a7789b, 0x78beca2f, 0x78f6c810, - 0xb8bef956, 0xfc6afabd, 0xbc734963, 0xfc3d5b8d, - 0xbc25fbb7, 0xf9189d05, 0xb91ecb1d, 0x39187a33, - 0x791f226d, 0xf95aa2f3, 0xb9587bb7, 0x395f7176, - 0x795d9143, 0x399e7e08, 0x799a2697, 0x79df3422, - 0xb99c2624, 0xfd5c2374, 0xbd5fa1d9, 0xfd1d595a, - 0xbd1b1869, 0x580053fb, 0x1800000b, 0xf8945060, - 0xd8000000, 0xf8ae6ba0, 0xf99a0080, 0x1a070035, - 0x3a0700a8, 0x5a0e0367, 0x7a11009b, 0x9a000380, - 0xba1e030c, 0xda0f0320, 0xfa030301, 0x0b340b11, - 0x2b2a278d, 0xcb22aa0f, 0x6b2d29bd, 0x8b2cce8c, - 0xab2b877e, 0xcb21c8ee, 0xeb3ba47d, 0x3a4d400e, - 0x7a5132c6, 0xba5e622e, 0xfa53814c, 0x3a52d8c2, - 0x7a4d8924, 0xba4b3aab, 0xfa4d7882, 0x1a96804c, - 0x1a912618, 0x5a90b0e6, 0x5a96976b, 0x9a9db06a, - 0x9a9b374c, 0xda95c14f, 0xda89c6fe, 0x5ac0015e, - 0x5ac005fd, 0x5ac00bdd, 0x5ac012b9, 0x5ac01404, - 0xdac002b1, 0xdac0061d, 0xdac00a95, 0xdac00e66, - 0xdac0107e, 0xdac01675, 0x1ac00b0b, 0x1ace0f3b, - 0x1ad121c3, 0x1ad825e7, 0x1ad92a3c, 0x1adc2f42, - 0x9ada0b25, 0x9ad10e1b, 0x9acc22a6, 0x9acc2480, - 0x9adc2a3b, 0x9ad12c5c, 0x9bce7dea, 0x9b597c6e, - 0x1b0e166f, 0x1b1ae490, 0x9b023044, 0x9b089e3d, - 0x9b391083, 0x9b24c73a, 0x9bb15f40, 0x9bbcc6af, - 0x7ea3d55b, 0x1e3908e0, 0x1e2f18c9, 0x1e2a29fd, - 0x1e273a22, 0x7ef7d56b, 0x1e770ba7, 0x1e6b1b6e, - 0x1e78288b, 0x1e6e39ec, 0x1f1c3574, 0x1f17f98b, - 0x1f2935da, 0x1f2574ea, 0x1f4b306f, 0x1f5ec7cf, - 0x1f6f3e93, 0x1f6226a9, 0x1e2040fb, 0x1e20c3dd, - 0x1e214031, 0x1e21c0c2, 0x1e22c06a, 0x1e604178, - 0x1e60c027, 0x1e61400b, 0x1e61c223, 0x1e6240dc, - 0x1e3800d6, 0x9e380360, 0x1e78005a, 0x9e7800e5, - 0x1e22017c, 0x9e2201b9, 0x1e6202eb, 0x9e620113, - 0x1e2602b1, 0x9e660299, 0x1e270233, 0x9e6703a2, - 0x1e2822c0, 0x1e7322a0, 0x1e202288, 0x1e602168, - 0x293c19f4, 0x2966387b, 0x69762970, 0xa9041dc7, - 0xa9475c0c, 0x29b61ccd, 0x29ee3c5e, 0x69ee0764, - 0xa9843977, 0xa9f46ebd, 0x28ba16b6, 0x28fc44db, - 0x68f61430, 0xa8b352cd, 0xa8c56d5e, 0x28024565, - 0x2874134e, 0xa8027597, 0xa87b1aa0, 0x0c40734f, - 0x4cdfa177, 0x0cc76ee8, 0x4cdf2733, 0x0d40c23d, - 0x4ddfcaf8, 0x0dd9ccaa, 0x4c408d51, 0x0cdf85ec, - 0x4d60c239, 0x0dffcbc1, 0x4de9ce30, 0x4cc24999, - 0x0c404a7a, 0x4d40e6af, 0x4ddfe9b9, 0x0dddef8e, - 0x4cdf07b1, 0x0cc000fb, 0x0d60e238, 0x0dffe740, - 0x0de2eb2c, 0x0e31baf6, 0x4e31bb9b, 0x0e71b8a4, - 0x4e71b907, 0x4eb1b8e6, 0x0e30a841, 0x4e30ab7a, - 0x0e70aa0f, 0x4e70a862, 0x4eb0a9cd, 0x6e30f9cd, - 0x0e31ab38, 0x2e31ab17, 0x4e31a8a4, 0x6e31aa93, - 0x0e71aa0f, 0x2e71a820, 0x4e71a8a4, 0x6e71aab4, - 0x4eb1a98b, 0x6eb1abdd, 0x6eb0fa0f, 0x7e30fad5, - 0x7e70f8a4, 0x7eb0f9ee, 0x7ef0faf6, 0x0e20bb59, - 0x4e20b8e6, 0x0e60b9ac, 0x4e60b9ee, 0x0ea0b9cd, - 0x4ea0b9ee, 0x4ee0b949, 0x0ea0fb59, 0x4ea0fbbc, - 0x4ee0f96a, 0x2ea0fa93, 0x6ea0f98b, 0x6ee0fa51, - 0x2ea1fad5, 0x6ea1fa0f, 0x6ee1fab4, 0x2e205b17, - 0x6e205b7a, 0x0e271cc5, 0x4e281ce6, 0x0eb11e0f, - 0x4eb11e0f, 0x2e3b1f59, 0x6e321e30, 0x0e3d879b, - 0x4e3a8738, 0x0e71860f, 0x4e7b8759, 0x0eb085ee, - 0x4eac856a, 0x4eef85cd, 0x0e30d5ee, 0x4e36d6b4, - 0x4e63d441, 0x2e3886f6, 0x6e2087fe, 0x2e7085ee, - 0x6e648462, 0x2ea884e6, 0x6ea58483, 0x6ee98507, - 0x0ebad738, 0x4ea2d420, 0x4efdd79b, 0x0e3f9fdd, - 0x4e279cc5, 0x0e679cc5, 0x4e7f9fdd, 0x0ead9d8b, - 0x4ebb9f59, 0x2ea2d420, 0x6ea0d7fe, 0x6ee2d420, - 0x2e33de51, 0x6e3edfbc, 0x6e7bdf59, 0x0e6b9549, - 0x4e7b9759, 0x0eae95ac, 0x4eb1960f, 0x0e2dcd8b, - 0x4e2ccd6a, 0x4e73ce51, 0x2e7a9738, 0x6e7796d5, - 0x2eb99717, 0x6ea29420, 0x0eb2ce30, 0x4eaccd6a, - 0x4ee8cce6, 0x2e3effbc, 0x6e28fce6, 0x6e67fcc5, - 0x0e2764c5, 0x4e3666b4, 0x0e736651, 0x4e71660f, - 0x0eb36651, 0x4ebf67dd, 0x0e3ca77a, 0x4e3ea7bc, - 0x0e63a441, 0x4e7da79b, 0x0ea2a420, 0x4eb6a6b4, - 0x0e3ef7bc, 0x4e31f60f, 0x4e6ef5ac, 0x0e2c6d6a, - 0x4e3e6fbc, 0x0e7e6fbc, 0x4e756e93, 0x0eb86ef6, - 0x4eac6d6a, 0x0e26aca4, 0x4e20affe, 0x0e76aeb4, - 0x4e6aad28, 0x0ea0affe, 0x4eb3ae51, 0x0eacf56a, - 0x4ebdf79b, 0x4ee4f462, 0x2e3a8f38, 0x6e268ca4, - 0x2e658c83, 0x6e6a8d28, 0x2eb88ef6, 0x6eb38e51, - 0x6eef8dcd, 0x0e26e4a4, 0x4e3ee7bc, 0x4e79e717, - 0x0e3736d5, 0x4e3b3759, 0x0e7a3738, 0x4e653483, - 0x0eb93717, 0x4ebc377a, 0x4ef93717, 0x2e3035ee, - 0x6e3736d5, 0x2e653483, 0x6e793717, 0x2eaa3528, - 0x6eba3738, 0x6ef53693, 0x2e313e0f, 0x6e323e30, - 0x2e643c62, 0x6e633c41, 0x2ea23c20, 0x6eba3f38, - 0x6ee63ca4, 0x2ea5e483, 0x6eade58b, 0x6ee0e7fe, - 0x0e3d3f9b, 0x4e2b3d49, 0x0e7b3f59, 0x4e643c62, - 0x0eae3dac, 0x4eb33e51, 0x4ee03ffe, 0x2e23e441, - 0x6e2ee5ac, 0x6e7ee7bc, 0xba5fd3e3, 0x3a5f03e5, + 0xd44cad80, 0xd503201f, 0xd503203f, 0xd503205f, + 0xd503209f, 0xd50320bf, 0xd503219f, 0xd50323bf, + 0xd503239f, 0xd50321df, 0xd50323ff, 0xd50323df, + 0xd503211f, 0xd503233f, 0xd503231f, 0xd503215f, + 0xd503237f, 0xd503235f, 0xd69f03e0, 0xd6bf03e0, + 0xd5033fdf, 0xd503207f, 0xd50320ff, 0xd5033e9f, + 0xd50332bf, 0xd61f0200, 0xd63f0280, 0xdac123ea, + 0xdac127fb, 0xdac12be8, 0xdac12fe0, 0xdac133e1, + 0xdac137f5, 0xdac13bf1, 0xdac13ffd, 0xdac147fd, + 0xd61f0b9f, 0xd61f0c3f, 0xd63f0aff, 0xd63f0ebf, + 0xdac143f4, 0xc8167e7b, 0xc80bfcd0, 0xc85f7c11, + 0xc85ffd44, 0xc89ffed8, 0xc8dffe6a, 0x88017fc5, + 0x8808fe2c, 0x885f7dc9, 0x885ffc27, 0x889ffe05, + 0x88dffd82, 0x480a7c6c, 0x481cff4e, 0x485f7d5e, + 0x485ffeae, 0x489ffd2d, 0x48dfff76, 0x081c7d73, + 0x081efc53, 0x085f7ee2, 0x085ffc01, 0x089ffe0c, + 0x08dffded, 0xc87f55b1, 0xc87ff90b, 0xc8382c2d, + 0xc83aedb5, 0x887f0d94, 0x887f87a6, 0x88262e04, + 0x8824b2be, 0xf8061366, 0xb802d151, 0x381e32da, + 0x781ce155, 0xf847d30e, 0xb85f0307, 0x39403448, + 0x785c333e, 0x389f2183, 0x789e422a, 0x78dfb075, + 0xb8817322, 0xfc5bb039, 0xbc40637d, 0xfc02919d, + 0xbc18d2c2, 0xf8003cba, 0xb8199cb4, 0x381e7d88, + 0x781c7c54, 0xf8516fae, 0xb8404fad, 0x385f7e78, + 0x785edf63, 0x389fbc31, 0x789f3e71, 0x78de6d75, + 0xb89c4d21, 0xfc509efa, 0xbc581eb6, 0xfc128ced, + 0xbc198dac, 0xf81134b4, 0xb81b679d, 0x381ea704, + 0x781eb52d, 0xf85c94fa, 0xb858d46d, 0x3840c4a1, + 0x785de5a8, 0x389e5697, 0x789fe4d4, 0x78dd6629, + 0xb89e24d5, 0xfc5e36d0, 0xbc5fd569, 0xfc03c756, + 0xbc1fe7b0, 0xf824cac1, 0xb82d7bd7, 0x382c596c, + 0x78207999, 0xf86058f1, 0xb86e5a61, 0x3869784c, + 0x787bc936, 0x38aff995, 0x78b078dc, 0x78f6ca39, + 0xb8bdea24, 0xfc63f825, 0xbc6d5a38, 0xfc37fa31, + 0xbc25dbd1, 0xf91ba97d, 0xb91e4abc, 0x391b485c, + 0x7919c380, 0xf95e18f9, 0xb958a860, 0x395f20be, + 0x7958f6ee, 0x399bea6a, 0x799b363d, 0x79da47d9, + 0xb99d5851, 0xfd5da60f, 0xbd584fcc, 0xfd1db821, + 0xbd1e9965, 0x58ffdb71, 0x18ffdb42, 0xf886f320, + 0xd8ffdb00, 0xf8bb49c0, 0xf99815c0, 0x1a0f0320, + 0x3a030301, 0x5a140311, 0x7a0d000b, 0x9a07015c, + 0xba1001e4, 0xda140182, 0xfa0d01bd, 0x0b2c6cce, + 0x2b3e5331, 0xcb2e0620, 0x6b3de709, 0x8b20cac1, + 0xab362f8c, 0xcb31518a, 0xeb2acf8f, 0x3a57d262, + 0x7a493226, 0xba4832a2, 0xfa454261, 0x3a518acc, + 0x7a472a23, 0xba5cba05, 0xfa439ac5, 0x1a8cb35d, + 0x1a8f355b, 0x5a9e9395, 0x5a9e3769, 0x9a9dd1fd, + 0x9a8406b9, 0xda9d62b1, 0xda868695, 0x5ac0007e, + 0x5ac00675, 0x5ac00b0b, 0x5ac01360, 0x5ac015d9, + 0xdac001c3, 0xdac004f1, 0xdac00b0f, 0xdac00e3c, + 0xdac01059, 0xdac0179a, 0xdac10325, 0xdac1077a, + 0xdac10a30, 0xdac10ea6, 0xdac1100c, 0xdac11584, + 0xdac11a3b, 0xdac11f9c, 0xd71f0851, 0xd71f0d4f, + 0xd73f09ce, 0xd73f0c79, 0x1ace0a6f, 0x1ac40e05, + 0x1ac4233a, 0x1acc2442, 0x1ac82a3d, 0x1ac42c67, + 0x9ada0899, 0x9ad10c99, 0x9ad12340, 0x9ad525f7, + 0x9adb2a3c, 0x9ac02c6a, 0x9bc97f27, 0x9b5d7de6, + 0x1b02454f, 0x1b0bdd67, 0x9b173ba7, 0x9b0b917b, + 0x9b2f3998, 0x9b3cb574, 0x9bb7798b, 0x9ba9b5da, + 0x7ea5d4ea, 0x1e2309fd, 0x1e2f198b, 0x1e312bde, + 0x1e2f3a93, 0x7ef5d52f, 0x1e7b0922, 0x1e7e1ba7, + 0x1e622831, 0x1e633946, 0x1f070578, 0x1f03c40b, + 0x1f3618dc, 0x1f3a0b60, 0x1f5c2ce5, 0x1f4bddb9, + 0x1f715513, 0x1f734699, 0x1e2043a2, 0x1e20c116, + 0x1e214275, 0x1e21c174, 0x1e22c291, 0x1e6041e6, + 0x1e60c063, 0x1e61407c, 0x1e61c1db, 0x1e62414e, + 0x1e38016c, 0x9e380151, 0x1e7800f9, 0x9e7801c7, + 0x1e22001c, 0x9e220016, 0x1e6202ec, 0x9e6201ad, + 0x1e2601c7, 0x9e660107, 0x1e270234, 0x9e6703dc, + 0x1e222200, 0x1e702120, 0x1e202288, 0x1e6023a8, + 0x29266b01, 0x29462d85, 0x69463f75, 0xa90272c5, + 0xa97e467b, 0x29aa1f4d, 0x29fa54cd, 0x69c27b74, + 0xa9b81555, 0xa9fa12ee, 0x2884321d, 0x28cc477a, + 0x68f451c4, 0xa8b909d0, 0xa8f060f7, 0x281069e0, + 0x2866191a, 0xa8392b2f, 0xa8760670, 0x0c4073db, + 0x4cdfa079, 0x0cca6e1e, 0x4cdf2670, 0x0d40c317, + 0x4ddfc948, 0x0dd7ce89, 0x4c408c62, 0x0cdf87c8, + 0x4d60c344, 0x0dffca23, 0x4df0cd7d, 0x4cd74801, + 0x0c404aa0, 0x4d40e4e5, 0x4ddfe8e1, 0x0dcfeca2, + 0x4cdf07bb, 0x0cc70098, 0x0d60e2ef, 0x0dffe6ae, + 0x0df9e934, 0x0e31bb17, 0x4e31bb7a, 0x0e71b8c5, + 0x4e71b8e6, 0x4eb1ba0f, 0x0e30aa0f, 0x4e30ab59, + 0x0e70aa30, 0x4e70ab9b, 0x4eb0ab38, 0x6e30fa0f, + 0x0e31ab59, 0x2e31a9ee, 0x4e31a96a, 0x6e31a9cd, + 0x0e71a9ee, 0x2e71aab4, 0x4e71a841, 0x6e71aaf6, + 0x4eb1abfe, 0x6eb1a9ee, 0x6eb0f862, 0x7e30f8e6, + 0x7e70f883, 0x7eb0f907, 0x7ef0fb38, 0x0e20b820, + 0x4e20bb9b, 0x0e60bbdd, 0x4e60b8c5, 0x0ea0b8c5, + 0x4ea0bbdd, 0x4ee0b98b, 0x0ea0fb59, 0x4ea0f820, + 0x4ee0fbfe, 0x2ea0f820, 0x6ea0fa51, 0x6ee0fbbc, + 0x2ea1fb59, 0x6ea1f949, 0x6ee1fb59, 0x2e2059ac, + 0x6e205a0f, 0x0e2d1d8b, 0x4e2c1d6a, 0x0eb31e51, + 0x4eba1f38, 0x2e371ed5, 0x6e391f17, 0x0e228420, + 0x4e328630, 0x0e6c856a, 0x4e6884e6, 0x0ebe87bc, + 0x4ea884e6, 0x4ee784c5, 0x0e27d4c5, 0x4e36d6b4, + 0x4e73d651, 0x2e31860f, 0x6e338651, 0x2e7f87dd, + 0x6e7c877a, 0x2ebe87bc, 0x6ea38441, 0x6efd879b, + 0x0ea2d420, 0x4eb6d6b4, 0x4efed7bc, 0x0e319e0f, + 0x4e2e9dac, 0x0e6c9d6a, 0x4e7e9fbc, 0x0ebe9fbc, + 0x4eb59e93, 0x2eb8d6f6, 0x6eacd56a, 0x6ee6d4a4, + 0x2e20dffe, 0x6e36deb4, 0x6e6add28, 0x0e6097fe, + 0x4e739651, 0x0eac956a, 0x4ebd979b, 0x0e24cc62, + 0x4e3acf38, 0x4e66cca4, 0x2e659483, 0x6e6a9528, + 0x2eb896f6, 0x6eb39651, 0x0eafcdcd, 0x4ea6cca4, + 0x4efecfbc, 0x2e39ff17, 0x6e37fed5, 0x6e7bff59, + 0x0e3a6738, 0x4e256483, 0x0e796717, 0x4e7c677a, + 0x0eb96717, 0x4eb065ee, 0x0e37a6d5, 0x4e25a483, + 0x0e79a717, 0x4e6aa528, 0x0ebaa738, 0x4eb5a693, + 0x0e31f60f, 0x4e32f630, 0x4e64f462, 0x0e236c41, + 0x4e226c20, 0x0e7a6f38, 0x4e666ca4, 0x0ea56c83, + 0x4ead6d8b, 0x0e20affe, 0x4e3daf9b, 0x0e6bad49, + 0x4e7baf59, 0x0ea4ac62, 0x4eaeadac, 0x0eb3f651, + 0x4ea0f7fe, 0x4ee3f441, 0x2e2e8dac, 0x6e3e8fbc, + 0x2e628c20, 0x6e738e51, 0x2eae8dac, 0x6eb38e51, + 0x6ef78ed5, 0x0e2ee5ac, 0x4e3de79b, 0x4e7fe7dd, + 0x0e2037fe, 0x4e233441, 0x0e7b3759, 0x4e7d379b, + 0x0ea634a4, 0x4ebf37dd, 0x4ee53483, 0x2e2834e6, + 0x6e3f37dd, 0x2e7b3759, 0x6e733651, 0x2eaa3528, + 0x6ea93507, 0x6eee35ac, 0x2e223c20, 0x6e353e93, + 0x2e633c41, 0x6e793f17, 0x2ea43c62, 0x6ea23c20, + 0x6eea3d28, 0x2eb9e717, 0x6ebbe759, 0x6ef1e60f, + 0x0e3f3fdd, 0x4e253c83, 0x0e6c3d6a, 0x4e783ef6, + 0x0eac3d6a, 0x4ea63ca4, 0x4ef33e51, 0x2e23e441, + 0x6e2de58b, 0x6e69e507, 0xba5fd3e3, 0x3a5f03e5, 0xfa411be4, 0x7a42cbe2, 0x93df03ff, 0xc820ffff, 0x8822fc7f, 0xc8247cbf, 0x88267fff, 0x4e010fe0, 0x5e040420, 0x4e081fe1, 0x4e0c1fe1, 0x4e0a1fe1, @@ -1266,51 +1381,62 @@ 0xc5b040af, 0xe57080af, 0xe5b080af, 0x25034440, 0x254054c4, 0x25034640, 0x25415a05, 0x25834440, 0x25c54489, 0x250b5d3a, 0x2550dc20, 0x2518e3e1, - 0x2558e3e2, 0x2598e3e3, 0x25d8e3e4, 0x2518e407, - 0x05214800, 0x05614800, 0x05a14800, 0x05e14800, - 0x05214c00, 0x05614c00, 0x05a14c00, 0x05e14c00, - 0x05304001, 0x05314001, 0x1e601000, 0x1e603000, - 0x1e621000, 0x1e623000, 0x1e641000, 0x1e643000, - 0x1e661000, 0x1e663000, 0x1e681000, 0x1e683000, - 0x1e6a1000, 0x1e6a3000, 0x1e6c1000, 0x1e6c3000, - 0x1e6e1000, 0x1e6e3000, 0x1e701000, 0x1e703000, - 0x1e721000, 0x1e723000, 0x1e741000, 0x1e743000, - 0x1e761000, 0x1e763000, 0x1e781000, 0x1e783000, - 0x1e7a1000, 0x1e7a3000, 0x1e7c1000, 0x1e7c3000, - 0x1e7e1000, 0x1e7e3000, 0xf8208193, 0xf83101b6, - 0xf83c13fe, 0xf821239a, 0xf824309e, 0xf826535e, - 0xf8304109, 0xf82c7280, 0xf8216058, 0xf8a08309, - 0xf8ba03d0, 0xf8a312ea, 0xf8aa21e4, 0xf8a2310b, - 0xf8aa522f, 0xf8a2418a, 0xf8ac71af, 0xf8a26287, - 0xf8fa8090, 0xf8e20184, 0xf8f01215, 0xf8f022ab, - 0xf8f7334c, 0xf8f751dc, 0xf8eb4038, 0xf8ec715f, - 0xf8f06047, 0xf863826d, 0xf8710070, 0xf86113cb, - 0xf86521e8, 0xf87d301e, 0xf8745287, 0xf87742bc, - 0xf87b70b9, 0xf8616217, 0xb83f8185, 0xb82901fc, - 0xb83d13f6, 0xb83320bf, 0xb82e33f0, 0xb830529b, - 0xb830416c, 0xb82973c6, 0xb831639b, 0xb8be8147, - 0xb8b4008a, 0xb8b81231, 0xb8b623a3, 0xb8af3276, - 0xb8b35056, 0xb8af4186, 0xb8b071ab, 0xb8b763c1, - 0xb8f38225, 0xb8e202d0, 0xb8ed12aa, 0xb8fd219b, - 0xb8fb3023, 0xb8ff5278, 0xb8f14389, 0xb8fb70ef, - 0xb8f563f7, 0xb87983e2, 0xb87b0150, 0xb8771073, - 0xb8702320, 0xb87a3057, 0xb870508c, 0xb87c43be, - 0xb87070db, 0xb86961fd, 0xce273c87, 0xce080ac9, - 0xce7e8e9b, 0xce808b45, 0xce79806e, 0xce758768, - 0xcec0835a, 0xce608ad8, 0x043100c4, 0x046105e3, - 0x65c900a6, 0x65d60a87, 0x65c80545, 0x0416a63e, - 0x04001f8b, 0x045a179a, 0x04d09e0d, 0x045aa1a5, - 0x04990b4f, 0x049386cb, 0x04918264, 0x04500dd1, - 0x0497b062, 0x041ea4d7, 0x04980f71, 0x04c80450, - 0x048a04c3, 0x04810d93, 0x04dcba68, 0x65808ae0, - 0x65cd9db3, 0x658680e6, 0x65879911, 0x65c296d6, - 0x04dda1e2, 0x65c2a494, 0x65c0a107, 0x65c1b493, - 0x65cdb569, 0x65819e05, 0x65ad8c36, 0x65af1334, - 0x65e63104, 0x65fd5e04, 0x65eb6c49, 0x049a4423, - 0x04916d11, 0x043330b8, 0x04b032d1, 0x04603274, - 0x04e432f1, 0x05b96ae4, 0x05686d02, 0x049a33d8, - 0x04583c24, 0x04592c13, 0x04083a27, 0x04ca253b, - 0x65c72e17, 0x65c63696, 0x65d829bc, 0x04413787, + 0x2518e021, 0x2518e0a1, 0x2518e121, 0x2518e1a1, + 0x2558e3e2, 0x2558e042, 0x2558e0c2, 0x2558e142, + 0x2598e3e3, 0x2598e063, 0x2598e0e3, 0x2598e163, + 0x25d8e3e4, 0x25d8e084, 0x25d8e104, 0x25d8e184, + 0x2518e407, 0x05214800, 0x05614800, 0x05a14800, + 0x05e14800, 0x05214c00, 0x05614c00, 0x05a14c00, + 0x05e14c00, 0x05304001, 0x05314001, 0x1e601000, + 0x1e603000, 0x1e621000, 0x1e623000, 0x1e641000, + 0x1e643000, 0x1e661000, 0x1e663000, 0x1e681000, + 0x1e683000, 0x1e6a1000, 0x1e6a3000, 0x1e6c1000, + 0x1e6c3000, 0x1e6e1000, 0x1e6e3000, 0x1e701000, + 0x1e703000, 0x1e721000, 0x1e723000, 0x1e741000, + 0x1e743000, 0x1e761000, 0x1e763000, 0x1e781000, + 0x1e783000, 0x1e7a1000, 0x1e7a3000, 0x1e7c1000, + 0x1e7c3000, 0x1e7e1000, 0x1e7e3000, 0xf82a822f, + 0xf822018a, 0xf82c11af, 0xf8222287, 0xf83a3090, + 0xf8225184, 0xf8304215, 0xf83072ab, 0xf837634c, + 0xf8b781dc, 0xf8ab0038, 0xf8ac115f, 0xf8b02047, + 0xf8a3326d, 0xf8b15070, 0xf8a143cb, 0xf8a571e8, + 0xf8bd601e, 0xf8f48287, 0xf8f702bc, 0xf8fb10b9, + 0xf8e12217, 0xf8ff3185, 0xf8e951fc, 0xf8fd43f6, + 0xf8f370bf, 0xf8ee63f0, 0xf870829b, 0xf870016c, + 0xf86913c6, 0xf871239b, 0xf87e3147, 0xf874508a, + 0xf8784231, 0xf87673a3, 0xf86f6276, 0xb8338056, + 0xb82f0186, 0xb83011ab, 0xb83723c1, 0xb8333225, + 0xb82252d0, 0xb82d42aa, 0xb83d719b, 0xb83b6023, + 0xb8bf8278, 0xb8b10389, 0xb8bb10ef, 0xb8b523f7, + 0xb8b933e2, 0xb8bb5150, 0xb8b74073, 0xb8b07320, + 0xb8ba6057, 0xb8f0808c, 0xb8fc03be, 0xb8f010db, + 0xb8e921fd, 0xb8e730e4, 0xb8ef52e9, 0xb8e84382, + 0xb8f570bf, 0xb8fb6220, 0xb86f8344, 0xb86802dc, + 0xb87b133b, 0xb8772080, 0xb8663010, 0xb864502f, + 0xb86a40a7, 0xb86a70fc, 0xb87462b7, 0xce284145, + 0xce1108de, 0xce7c8fab, 0xce96eb42, 0xce7b81ae, + 0xce6586f0, 0xcec081a2, 0xce6a89ea, 0x25a0cc5a, + 0x25a1d143, 0x05800e44, 0x05406531, 0x05002d42, + 0x2520c677, 0x25a1cd07, 0x0580687b, 0x0543bb42, + 0x050044a6, 0x25a0c86c, 0x25a1d358, 0x05800500, + 0x05400ad3, 0x05000e06, 0x25e0c951, 0x25a1d54a, + 0x05839276, 0x0540ea6f, 0x0503c8a4, 0x25a0d448, + 0x2521d056, 0x058059c9, 0x05406d05, 0x05003cb6, + 0x25a0d0c8, 0x2561c4f9, 0x05809904, 0x05400e5d, + 0x0500cadd, 0x043c0162, 0x04ba0427, 0x65c801d1, + 0x65c50b15, 0x65d60635, 0x0416b67d, 0x040012e4, + 0x04da06f3, 0x04508113, 0x04db1a2e, 0x041aa7d5, + 0x0419158a, 0x04938709, 0x045198c4, 0x049019bb, + 0x0497b6de, 0x045ebd3e, 0x04d80693, 0x044809a9, + 0x044a0313, 0x04810e33, 0x049ca410, 0x658089eb, + 0x65cd85ef, 0x65c68145, 0x6587801a, 0x65c29d53, + 0x04ddb4e3, 0x6582aebc, 0x65c0ae3a, 0x65c1ac51, + 0x658db690, 0x65c18033, 0x65f18a11, 0x65b70440, + 0x65ee2a86, 0x65e34c7d, 0x65bb6309, 0x049954f3, + 0x041964ed, 0x04313235, 0x04b33123, 0x046e3167, + 0x04ed3171, 0x05716bd1, 0x05ba6dcf, 0x045a34fb, + 0x04583f65, 0x04992f00, 0x04882074, 0x04ca2739, + 0x65873031, 0x65863dae, 0x65d823d1, 0x044137b6, }; // END Generated code -- do not edit diff --git a/test/hotspot/gtest/classfile/test_AltHashing.cpp b/test/hotspot/gtest/classfile/test_AltHashing.cpp index d11dc0fb4a202c2d3271ab9f32830f1974d29bd3..0070c4fd2c12fd0b5892adb73acb1c40cc1a43fa 100644 --- a/test/hotspot/gtest/classfile/test_AltHashing.cpp +++ b/test/hotspot/gtest/classfile/test_AltHashing.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -24,6 +24,7 @@ #include "classfile/altHashing.hpp" #include "utilities/debug.hpp" #include "utilities/formatBuffer.hpp" +#include "utilities/globalDefinitions.hpp" #include "unittest.hpp" class AltHashingTest : public ::testing::Test { diff --git a/test/hotspot/gtest/gc/g1/test_freeRegionList.cpp b/test/hotspot/gtest/gc/g1/test_freeRegionList.cpp index 9a69816558bb71a0416613676d3b6e4cc042d649..2cf82eb403774ae7359f8f9281e6c871c2dfa28f 100644 --- a/test/hotspot/gtest/gc/g1/test_freeRegionList.cpp +++ b/test/hotspot/gtest/gc/g1/test_freeRegionList.cpp @@ -57,7 +57,7 @@ TEST_VM(FreeRegionList, length) { bot_rs.size(), os::vm_page_size(), HeapRegion::GrainBytes, - BOTConstants::N_bytes, + BOTConstants::card_size(), mtGC); G1BlockOffsetTable bot(heap, bot_storage); bot_storage->commit_regions(0, num_regions_in_test); diff --git a/test/hotspot/gtest/gc/g1/test_g1CardSet.cpp b/test/hotspot/gtest/gc/g1/test_g1CardSet.cpp index 58e6f3e3c2489c62f84753396275d013739f0c0e..004fd71cb2fb240a40441e2f853dbff24df757f3 100644 --- a/test/hotspot/gtest/gc/g1/test_g1CardSet.cpp +++ b/test/hotspot/gtest/gc/g1/test_g1CardSet.cpp @@ -25,16 +25,18 @@ #include "gc/g1/g1CardSet.inline.hpp" #include "gc/g1/g1CardSetContainers.hpp" #include "gc/g1/g1CardSetMemory.hpp" +#include "gc/g1/g1SegmentedArrayFreePool.hpp" #include "gc/g1/heapRegionRemSet.hpp" #include "gc/shared/gcTraceTime.inline.hpp" #include "gc/shared/workerThread.hpp" #include "logging/log.hpp" +#include "memory/allocation.hpp" #include "unittest.hpp" #include "utilities/powerOfTwo.hpp" class G1CardSetTest : public ::testing::Test { - class G1CountCardsClosure : public G1CardSet::G1CardSetCardIterator { + class G1CountCardsClosure : public G1CardSet::CardClosure { public: size_t _num_cards; @@ -82,7 +84,7 @@ public: static void translate_cards(uint cards_per_region, uint region_idx, uint* cards, uint num_cards); - static void iterate_cards(G1CardSet* card_set, G1CardSet::G1CardSetCardIterator* cl); + static void iterate_cards(G1CardSet* card_set, G1CardSet::CardClosure* cl); }; WorkerThreads* G1CardSetTest::_workers = NULL; @@ -101,7 +103,7 @@ void G1CardSetTest::add_cards(G1CardSet* card_set, uint cards_per_region, uint* } } -class G1CheckCardClosure : public G1CardSet::G1CardSetCardIterator { +class G1CheckCardClosure : public G1CardSet::CardClosure { G1CardSet* _card_set; uint _cards_per_region; @@ -163,13 +165,13 @@ void G1CardSetTest::translate_cards(uint cards_per_region, uint region_idx, uint } } -class G1CountCardsOccupied : public G1CardSet::G1CardSetPtrIterator { +class G1CountCardsOccupied : public G1CardSet::ContainerPtrClosure { size_t _num_occupied; public: G1CountCardsOccupied() : _num_occupied(0) { } - void do_cardsetptr(uint region_idx, size_t num_occupied, G1CardSet::CardSetPtr card_set) override { + void do_containerptr(uint region_idx, size_t num_occupied, G1CardSet::ContainerPtr container) override { _num_occupied += num_occupied; } @@ -178,7 +180,7 @@ public: void G1CardSetTest::check_iteration(G1CardSet* card_set, const size_t expected, const bool single_threaded) { - class CheckIterator : public G1CardSet::G1CardSetCardIterator { + class CheckIterator : public G1CardSet::CardClosure { public: G1CardSet* _card_set; size_t _num_found; @@ -343,17 +345,17 @@ void G1CardSetTest::cardset_basic_test() { ASSERT_TRUE(count == card_set.occupied()); } - G1AddCardResult res = card_set.add_card(99, config.num_cards_in_howl_bitmap() - 1); + G1AddCardResult res = card_set.add_card(99, config.max_cards_in_howl_bitmap() - 1); // Adding above card should have coarsened Bitmap -> Full. ASSERT_TRUE(res == Added); - ASSERT_TRUE(config.num_cards_in_howl_bitmap() == card_set.occupied()); + ASSERT_TRUE(config.max_cards_in_howl_bitmap() == card_set.occupied()); - res = card_set.add_card(99, config.num_cards_in_howl_bitmap() - 2); + res = card_set.add_card(99, config.max_cards_in_howl_bitmap() - 2); ASSERT_TRUE(res == Found); uint threshold = config.cards_in_howl_threshold(); uint adjusted_threshold = config.cards_in_howl_bitmap_threshold() * config.num_buckets_in_howl(); - i = config.num_cards_in_howl_bitmap(); + i = config.max_cards_in_howl_bitmap(); count = i; for (; i < threshold; i++) { G1AddCardResult res = card_set.add_card(99, i); diff --git a/test/hotspot/gtest/gc/g1/test_g1CardSetContainers.cpp b/test/hotspot/gtest/gc/g1/test_g1CardSetContainers.cpp index c2ebeadd4811979a52d0c783cd122bb9598bba1a..0ad3aed18cceeec2f739ec6b47753191b0ef4ebc 100644 --- a/test/hotspot/gtest/gc/g1/test_g1CardSetContainers.cpp +++ b/test/hotspot/gtest/gc/g1/test_g1CardSetContainers.cpp @@ -83,7 +83,7 @@ void G1CardSetContainersTest::cardset_inlineptr_test(uint bits_per_card) { G1AddCardResult res; - G1CardSet::CardSetPtr value = G1CardSetInlinePtr(); + G1CardSet::ContainerPtr value = G1CardSetInlinePtr(); for (uint i = 0; i < CardsPerSet; i++) { { @@ -240,7 +240,7 @@ TEST_VM_F(G1CardSetContainersTest, basic_cardset_inptr_test) { uint const max = (uint)log2i(HeapRegionBounds::max_size()); for (uint i = min; i <= max; i++) { - G1CardSetContainersTest::cardset_inlineptr_test(i - CardTable::card_shift); + G1CardSetContainersTest::cardset_inlineptr_test(i - CardTable::card_shift()); } } diff --git a/test/hotspot/gtest/gc/shared/test_preservedMarks.cpp b/test/hotspot/gtest/gc/shared/test_preservedMarks.cpp index 4ef7cb20d2408ffa3733ccb685c74cd3e3b54e3d..5f9a361105ec76ac381ee74ada272fb230cb6e2c 100644 --- a/test/hotspot/gtest/gc/shared/test_preservedMarks.cpp +++ b/test/hotspot/gtest/gc/shared/test_preservedMarks.cpp @@ -68,8 +68,8 @@ TEST_VM(PreservedMarks, iterate_and_restore) { ASSERT_MARK_WORD_EQ(o2.mark(), FakeOop::changedMark()); // Push o1 and o2 to have their marks preserved. - pm.push(o1.get_oop(), o1.mark()); - pm.push(o2.get_oop(), o2.mark()); + pm.push_if_necessary(o1.get_oop(), o1.mark()); + pm.push_if_necessary(o2.get_oop(), o2.mark()); // Fake a move from o1->o3 and o2->o4. o1.forward_to(o3.get_oop()); diff --git a/test/hotspot/gtest/gc/shared/test_ptrQueueBufferAllocator.cpp b/test/hotspot/gtest/gc/shared/test_ptrQueueBufferAllocator.cpp index 978dd1e6f8c8d1848cff0ef5f3f63f1d466c560b..1fe3b645abd0f86e8a38b81cea2b2759d1405cb0 100644 --- a/test/hotspot/gtest/gc/shared/test_ptrQueueBufferAllocator.cpp +++ b/test/hotspot/gtest/gc/shared/test_ptrQueueBufferAllocator.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -38,7 +38,7 @@ class BufferNode::TestSupport : AllStatic { public: static bool try_transfer_pending(Allocator* allocator) { - return allocator->try_transfer_pending(); + return allocator->flush_free_list(); } class CompletedList; @@ -71,13 +71,6 @@ TEST_VM(PtrQueueBufferAllocatorTest, test) { } ASSERT_TRUE(BufferNode::TestSupport::try_transfer_pending(&allocator)); ASSERT_EQ(node_count, allocator.free_count()); - for (size_t i = 0; i < node_count; ++i) { - if (i == 0) { - ASSERT_EQ((BufferNode*)NULL, nodes[i]->next()); - } else { - ASSERT_EQ(nodes[i - 1], nodes[i]->next()); - } - } // Allocate nodes from the free list. for (size_t i = 0; i < node_count; ++i) { diff --git a/test/hotspot/gtest/logging/logTestUtils.inline.hpp b/test/hotspot/gtest/logging/logTestUtils.inline.hpp index 4295c6a000f2eb52726533ae56e2997e3d379578..3e49c610b4189ddfd7d345264e1769606b2f43ef 100644 --- a/test/hotspot/gtest/logging/logTestUtils.inline.hpp +++ b/test/hotspot/gtest/logging/logTestUtils.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -138,8 +138,8 @@ static inline char* read_line(FILE* fp) { static bool file_contains_substrings_in_order(const char* filename, const char* substrs[]) { AsyncLogWriter::flush(); - FILE* fp = fopen(filename, "r"); - assert(fp != NULL, "error opening file %s: %s", filename, strerror(errno)); + FILE* fp = os::fopen(filename, "r"); + assert(fp != NULL, "error opening file %s: %s", filename, os::strerror(errno)); size_t idx = 0; while (substrs[idx] != NULL) { diff --git a/test/hotspot/gtest/logging/test_asynclog.cpp b/test/hotspot/gtest/logging/test_asynclog.cpp index ffabbb524c2b2bd40f8163e08c9a902732d5995e..16bdd6e18c72440a93796fffa6b397f272df7f37 100644 --- a/test/hotspot/gtest/logging/test_asynclog.cpp +++ b/test/hotspot/gtest/logging/test_asynclog.cpp @@ -1,5 +1,6 @@ /* * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. + * 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 @@ -66,6 +67,38 @@ LOG_LEVEL_LIST log_trace(logging)("log_trace-test"); log_debug(logging)("log_debug-test"); } + + void test_asynclog_drop_messages() { + if (AsyncLogWriter::instance() != nullptr) { + const size_t sz = 100; + + // shrink async buffer. + AutoModifyRestore<size_t> saver(AsyncLogBufferSize, sz * 1024 /*in byte*/); + LogMessage(logging) lm; + + // write 100x more messages than its capacity in burst + for (size_t i = 0; i < sz * 100; ++i) { + lm.debug("a lot of log..."); + } + lm.flush(); + } + } + + // stdout/stderr support + bool write_to_file(const std::string& output) { + FILE* f = os::fopen(TestLogFileName, "w"); + + if (f != NULL) { + size_t sz = output.size(); + size_t written = fwrite(output.c_str(), sizeof(char), output.size(), f); + + if (written == sz * sizeof(char)) { + return fclose(f) == 0; + } + } + + return false; + } }; TEST_VM(AsyncLogBufferTest, fifo) { @@ -198,19 +231,48 @@ TEST_VM_F(AsyncLogTest, logMessage) { TEST_VM_F(AsyncLogTest, droppingMessage) { set_log_config(TestLogFileName, "logging=debug"); - const size_t sz = 100; + test_asynclog_drop_messages(); + AsyncLogWriter::flush(); if (AsyncLogWriter::instance() != nullptr) { - // shrink async buffer. - AutoModifyRestore<size_t> saver(AsyncLogBufferSize, sz * 1024 /*in byte*/); - LogMessage(logging) lm; + EXPECT_TRUE(file_contains_substring(TestLogFileName, "messages dropped due to async logging")); + } +} - // write 100x more messages than its capacity in burst - for (size_t i = 0; i < sz * 100; ++i) { - lm.debug("a lot of log..."); - } - lm.flush(); - AsyncLogWriter::flush(); +TEST_VM_F(AsyncLogTest, stdoutOutput) { + testing::internal::CaptureStdout(); + set_log_config("stdout", "logging=debug"); + + test_asynclog_ls(); + test_asynclog_drop_messages(); + + AsyncLogWriter::flush(); + EXPECT_TRUE(write_to_file(testing::internal::GetCapturedStdout())); + + EXPECT_TRUE(file_contains_substring(TestLogFileName, "LogStreamWithAsyncLogImpl")); + EXPECT_TRUE(file_contains_substring(TestLogFileName, "logStream msg1-msg2-msg3")); + EXPECT_TRUE(file_contains_substring(TestLogFileName, "logStream newline")); + + if (AsyncLogWriter::instance() != nullptr) { + EXPECT_TRUE(file_contains_substring(TestLogFileName, "messages dropped due to async logging")); + } +} + +TEST_VM_F(AsyncLogTest, stderrOutput) { + testing::internal::CaptureStderr(); + set_log_config("stderr", "logging=debug"); + + test_asynclog_ls(); + test_asynclog_drop_messages(); + + AsyncLogWriter::flush(); + EXPECT_TRUE(write_to_file(testing::internal::GetCapturedStderr())); + + EXPECT_TRUE(file_contains_substring(TestLogFileName, "LogStreamWithAsyncLogImpl")); + EXPECT_TRUE(file_contains_substring(TestLogFileName, "logStream msg1-msg2-msg3")); + EXPECT_TRUE(file_contains_substring(TestLogFileName, "logStream newline")); + + if (AsyncLogWriter::instance() != nullptr) { EXPECT_TRUE(file_contains_substring(TestLogFileName, "messages dropped due to async logging")); } } diff --git a/test/hotspot/gtest/logging/test_log.cpp b/test/hotspot/gtest/logging/test_log.cpp index ccd928474d438ef339471395bb7907290d4d39a6..7ae276aad376851744d6020a04897b3eb5041bd1 100644 --- a/test/hotspot/gtest/logging/test_log.cpp +++ b/test/hotspot/gtest/logging/test_log.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -60,7 +60,7 @@ TEST_VM_F(LogTest, large_message) { AsyncLogWriter::flush(); ResourceMark rm; - FILE* fp = fopen(TestLogFileName, "r"); + FILE* fp = os::fopen(TestLogFileName, "r"); ASSERT_NE((void*)NULL, fp); char* output = read_line(fp); fclose(fp); diff --git a/test/hotspot/gtest/logging/test_logConfiguration.cpp b/test/hotspot/gtest/logging/test_logConfiguration.cpp index 0d092dc0d750a55534422bfce30c8769b76a7450..38997af68cb6140fa5b0dfa308855528d5985eeb 100644 --- a/test/hotspot/gtest/logging/test_logConfiguration.cpp +++ b/test/hotspot/gtest/logging/test_logConfiguration.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -359,6 +359,29 @@ TEST_VM_F(LogConfigurationTest, parse_command_line_arguments) { ret = jio_snprintf(buf, sizeof(buf), ":%s", TestLogFileName); ASSERT_NE(-1, ret); EXPECT_TRUE(LogConfiguration::parse_command_line_arguments(buf)); + +#ifdef _WINDOWS + // We need to test the special-case parsing for drive letters in + // log file paths e.g. c:\log.txt and c:/log.txt. Our temp directory + // based TestLogFileName should already be the \ format (we print it + // below to visually verify) so we only need to convert to /. + printf("Checked: %s\n", buf); + // First disable logging so the current log file will be closed and we + // can delete it, so that UL won't try to perform log file rotation. + // The rotated file would not be auto-deleted. + set_log_config(TestLogFileName, "all=off"); + delete_file(TestLogFileName); + + // now convert \ to / + char* current_pos = strchr(buf,'\\'); + while (current_pos != nullptr) { + *current_pos = '/'; + current_pos = strchr(current_pos + 1, '\\'); + } + printf("Checking: %s\n", buf); + EXPECT_TRUE(LogConfiguration::parse_command_line_arguments(buf)); +#endif + } // Test split up log configuration arguments diff --git a/test/hotspot/gtest/logging/test_logTagSetDescriptions.cpp b/test/hotspot/gtest/logging/test_logTagSetDescriptions.cpp index 7cb37ff43498f05f7287442c4428217aab8d4bce..84253e19433786937a64aef8cebe056711106d27 100644 --- a/test/hotspot/gtest/logging/test_logTagSetDescriptions.cpp +++ b/test/hotspot/gtest/logging/test_logTagSetDescriptions.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -50,7 +50,7 @@ TEST_VM(LogTagSetDescriptions, describe) { TEST_VM(LogTagSetDescriptions, command_line_help) { ResourceMark rm; const char* filename = prepend_temp_dir("logtagset_descriptions"); - FILE* fp = fopen(filename, "w+"); + FILE* fp = os::fopen(filename, "w+"); ASSERT_NE((void*)NULL, fp); fileStream stream(fp); LogConfiguration::print_command_line_help(&stream); diff --git a/test/hotspot/gtest/nmt/test_nmt_buffer_overflow_detection.cpp b/test/hotspot/gtest/nmt/test_nmt_buffer_overflow_detection.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ce30fb8d61d71751bf98be76c32abf7106728f30 --- /dev/null +++ b/test/hotspot/gtest/nmt/test_nmt_buffer_overflow_detection.cpp @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2022 SAP SE. All rights reserved. + * 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 "memory/allocation.hpp" +#include "runtime/os.hpp" +#include "services/memTracker.hpp" +#include "utilities/debug.hpp" +#include "utilities/ostream.hpp" +#include "unittest.hpp" +#include "testutils.hpp" + +// This prefix shows up on any c heap corruption NMT detects. If unsure which assert will +// come, just use this one. +#define COMMON_NMT_HEAP_CORRUPTION_MESSAGE_PREFIX "NMT corruption" + +#define DEFINE_TEST(test_function, expected_assertion_message) \ + TEST_VM_FATAL_ERROR_MSG(NMT, test_function, ".*" expected_assertion_message ".*") { \ + if (MemTracker::tracking_level() > NMT_off) { \ + tty->print_cr("NMT overwrite death test, please ignore subsequent error dump."); \ + test_function (); \ + } else { \ + /* overflow detection requires NMT to be on. If off, fake assert. */ \ + guarantee(false, \ + "fake message ignore this - " expected_assertion_message); \ + } \ + } + +/////// + +static void test_overwrite_front() { + address p = (address) os::malloc(1, mtTest); + *(p - 1) = 'a'; + os::free(p); +} + +DEFINE_TEST(test_overwrite_front, "header canary broken") + +/////// + +static void test_overwrite_back() { + address p = (address) os::malloc(1, mtTest); + *(p + 1) = 'a'; + os::free(p); +} + +DEFINE_TEST(test_overwrite_back, "footer canary broken") + +/////// + +// A overwrite farther away from the NMT header; the report should show the hex dump split up +// in two parts, containing both header and corruption site. +static void test_overwrite_back_long(size_t distance) { + address p = (address) os::malloc(distance, mtTest); + *(p + distance) = 'a'; + os::free(p); +} +static void test_overwrite_back_long_aligned_distance() { test_overwrite_back_long(0x2000); } +DEFINE_TEST(test_overwrite_back_long_aligned_distance, "footer canary broken") +static void test_overwrite_back_long_unaligned_distance() { test_overwrite_back_long(0x2001); } +DEFINE_TEST(test_overwrite_back_long_unaligned_distance, "footer canary broken") + +/////// + +static void test_double_free() { + address p = (address) os::malloc(1, mtTest); + os::free(p); + // Now a double free. Note that this is susceptible to concurrency issues should + // a concurrent thread have done a malloc and gotten the same address after the + // first free. To decrease chance of this happening, we repeat the double free + // several times. + for (int i = 0; i < 100; i ++) { + os::free(p); + } +} + +// What assertion message we will see depends on whether the VM wipes the memory-to-be-freed +// on the first free(), and whether the libc uses the freed memory to store bookkeeping information. +// If the death marker in the header is still intact after the first free, we will recognize this as +// double free; if it got wiped, we should at least see a broken header canary. +// The message would be either +// - "header canary broken" or +// - "header canary dead (double free?)". +// However, since gtest regex expressions do not support unions (a|b), I search for a reasonable +// subset here. +DEFINE_TEST(test_double_free, "header canary") + +/////// + +static void test_invalid_block_address() { + // very low, like the result of an overflow or of accessing a NULL this pointer + os::free((void*)0x100); +} +DEFINE_TEST(test_invalid_block_address, "invalid block address") + +/////// + +static void test_unaliged_block_address() { + address p = (address) os::malloc(1, mtTest); + os::free(p + 6); +} +DEFINE_TEST(test_unaliged_block_address, "block address is unaligned"); + +/////// + +// Test that we notice block corruption on realloc too +static void test_corruption_on_realloc(size_t s1, size_t s2) { + address p1 = (address) os::malloc(s1, mtTest); + *(p1 + s1) = 'a'; + address p2 = (address) os::realloc(p1, s2, mtTest); + + // Still here? + tty->print_cr("NMT did not detect corruption on os::realloc?"); + // Note: don't use ASSERT here, that does not work as expected in death tests. Just + // let the test run its course, it should notice something is amiss. +} +static void test_corruption_on_realloc_growing() { test_corruption_on_realloc(0x10, 0x11); } +DEFINE_TEST(test_corruption_on_realloc_growing, COMMON_NMT_HEAP_CORRUPTION_MESSAGE_PREFIX); +static void test_corruption_on_realloc_shrinking() { test_corruption_on_realloc(0x11, 0x10); } +DEFINE_TEST(test_corruption_on_realloc_shrinking, COMMON_NMT_HEAP_CORRUPTION_MESSAGE_PREFIX); + +/////// + +// realloc is the trickiest of the bunch. Test that realloc works and correctly takes over +// NMT header and footer to the resized block. We just test that nothing crashes - if the +// header/footer get corrupted, NMT heap corruption checker will trigger alert on os::free()). +TEST_VM(NMT, test_realloc) { + // We test both directions (growing and shrinking) and a small range for each to cover all + // size alignment variants. Should not matter, but this should be cheap. + for (size_t s1 = 0xF0; s1 < 0x110; s1 ++) { + for (size_t s2 = 0x100; s2 > 0xF0; s2 --) { + address p1 = (address) os::malloc(s1, mtTest); + ASSERT_NOT_NULL(p1); + GtestUtils::mark_range(p1, s1); // mark payload range... + address p2 = (address) os::realloc(p1, s2, mtTest); + ASSERT_NOT_NULL(p2); + ASSERT_RANGE_IS_MARKED(p2, MIN2(s1, s2)) // ... and check that it survived the resize + << s1 << "->" << s2 << std::endl; + os::free(p2); // <- if NMT headers/footers got corrupted this asserts + } + } +} diff --git a/test/hotspot/gtest/nmt/test_nmtpreinit.cpp b/test/hotspot/gtest/nmt/test_nmtpreinit.cpp index 310cbb187b2fe3c393a80c92f47ed260c48210f9..6475e86570881fac7da9c12737066c417e631f3a 100644 --- a/test/hotspot/gtest/nmt/test_nmtpreinit.cpp +++ b/test/hotspot/gtest/nmt/test_nmtpreinit.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2021 SAP SE. All rights reserved. - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2022 SAP SE. All rights reserved. + * 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 @@ -54,8 +54,6 @@ // us. So inside that scope VM initialization ran and with it the NMT initialization. // To be sure, we assert those assumptions. -#if INCLUDE_NMT - // Some shorts to save writing out the flags every time static void* os_malloc(size_t s) { return os::malloc(s, mtTest); } static void* os_realloc(void* old, size_t s) { return os::realloc(old, s, mtTest); } @@ -127,5 +125,3 @@ TEST_VM(NMTPreInit, pre_to_post_allocs) { g_test_allocations.test_post(); g_test_allocations.free_all(); } - -#endif // INCLUDE_NMT diff --git a/test/hotspot/gtest/nmt/test_nmtpreinitmap.cpp b/test/hotspot/gtest/nmt/test_nmtpreinitmap.cpp index 356c79a8d4a08cfeed10a0cef368b679a749f988..e68d5ca069aae2f8f9e7a8d45c427cf95aa9600c 100644 --- a/test/hotspot/gtest/nmt/test_nmtpreinitmap.cpp +++ b/test/hotspot/gtest/nmt/test_nmtpreinitmap.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2021 SAP SE. All rights reserved. - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2022 SAP SE. All rights reserved. + * 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 @@ -31,8 +31,6 @@ #include "utilities/ostream.hpp" #include "unittest.hpp" -#if INCLUDE_NMT - // This tests the NMTPreInitAllocationTable hash table used to store C-heap allocations before NMT initialization ran. static size_t small_random_nonzero_size() { @@ -132,5 +130,3 @@ TEST_VM_ASSERT_MSG(NMTPreInit, assert_on_lu_table_overflow, ".*NMT preinit looku table.verify(); } #endif // ASSERT - -#endif // INCLUDE_NMT diff --git a/test/hotspot/gtest/oops/test_instanceKlass.cpp b/test/hotspot/gtest/oops/test_instanceKlass.cpp index 5af8f4406fe8b3fd6ce106e7e09301d87077a613..377c03d1ca08f215b7dac2a9cea05d6eb92952f1 100644 --- a/test/hotspot/gtest/oops/test_instanceKlass.cpp +++ b/test/hotspot/gtest/oops/test_instanceKlass.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -22,11 +22,14 @@ */ #include "precompiled.hpp" +#include "classfile/symbolTable.hpp" #include "classfile/systemDictionary.hpp" #include "classfile/vmClasses.hpp" +#include "classfile/vmSymbols.hpp" #include "memory/resourceArea.hpp" #include "oops/instanceKlass.hpp" #include "oops/klass.inline.hpp" +#include "oops/method.hpp" #include "unittest.hpp" // Tests for InstanceKlass::is_class_loader_instance_klass() function @@ -62,3 +65,21 @@ TEST_VM(InstanceKlass, class_loader_printer) { ASSERT_TRUE(strstr(st.as_string(), "'java/lang/ClassLoader'") != NULL) << "Must be in ClassLoader"; #endif } + +#ifndef PRODUCT +// This class is friends with Method. +class MethodTest : public ::testing::Test{ + public: + static void compare_names(Method* method, Symbol* name) { + ASSERT_EQ(method->_name, name) << "Method name field isn't set"; + } +}; + +TEST_VM(Method, method_name) { + InstanceKlass* ik = vmClasses::Object_klass(); + Symbol* tostring = SymbolTable::new_symbol("toString"); + Method* method = ik->find_method(tostring, vmSymbols::void_string_signature()); + ASSERT_TRUE(method != nullptr) << "Object must have toString"; + MethodTest::compare_names(method, tostring); +} +#endif diff --git a/test/hotspot/gtest/runtime/test_arguments.cpp b/test/hotspot/gtest/runtime/test_arguments.cpp index 81bae6c468aecafe7950fa7e9ba4652509aeb5a1..234bb2a015be6e84c405995a19be24d54ae40d49 100644 --- a/test/hotspot/gtest/runtime/test_arguments.cpp +++ b/test/hotspot/gtest/runtime/test_arguments.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -25,6 +25,7 @@ #include "jvm.h" #include "unittest.hpp" #include "runtime/arguments.hpp" +#include "runtime/flags/jvmFlag.hpp" #include "utilities/align.hpp" #include "utilities/globalDefinitions.hpp" @@ -41,6 +42,16 @@ public: static jint parse_xss(const JavaVMOption* option, const char* tail, intx* out_ThreadStackSize) { return Arguments::parse_xss(option, tail, out_ThreadStackSize); } + + static bool parse_argument(const char* name, const char* value) { + char buf[1024]; + int ret = jio_snprintf(buf, sizeof(buf), "%s=%s", name, value); + if (ret > 0) { + return Arguments::parse_argument(buf, JVMFlagOrigin::COMMAND_LINE); + } else { + return false; + } + } }; TEST_F(ArgumentsTest, atojulong) { @@ -201,3 +212,356 @@ TEST_VM_F(ArgumentsTest, parse_xss) { EXPECT_EQ(parse_xss_inner(to_string(K + 1), JNI_OK), calc_expected(K + 1)); } } + +struct Dummy {}; +static Dummy BAD; + +template <typename T> +struct NumericArgument { + bool bad; + const char* str; + T expected_value; + + NumericArgument(const char* s, T v) : bad(false), str(s), expected_value(v) {} + NumericArgument(const char* s, Dummy & dummy) : bad(true), str(s), expected_value(0) {} +}; + +static void check_invalid_numeric_string(JVMFlag* flag, const char** invalid_strings) { + for (uint i = 0; ; i++) { + const char* str = invalid_strings[i]; + if (str == NULL) { + return; + } + ASSERT_FALSE(ArgumentsTest::parse_argument(flag->name(), str)) + << "Invalid string '" << str + << "' parsed without error for type " << flag->type_string() << "."; + } +} + +template <typename T> +void check_numeric_flag(JVMFlag* flag, T getvalue(JVMFlag* flag), + NumericArgument<T>* valid_args, size_t n, + bool is_double = false) { + for (size_t i = 0; i < n; i++) { + NumericArgument<T>* info = &valid_args[i]; + const char* str = info->str; + if (info->bad) { + ASSERT_FALSE(ArgumentsTest::parse_argument(flag->name(), str)) + << "Invalid string '" << str + << "' parsed without error for type " << flag->type_string() << "."; + } else { + ASSERT_TRUE(ArgumentsTest::parse_argument(flag->name(), str)) + << "Valid string '" << + str << "' did not parse for type " << flag->type_string() << "."; + ASSERT_EQ(getvalue(flag), info->expected_value) + << "Valid string '" << str + << "' did not parse to the correct value for type " + << flag->type_string() << "."; + } + } + + { + // Invalid strings for *any* type of integer VM arguments + const char* invalid_strings[] = { + "", " 1", "2 ", "3 2", + "0x", "0x0x1" "e" + "K", "M", "G", "1MB", "1KM", "AA", "0B", + "18446744073709551615K", "17179869184G", + "999999999999999999999999999999", + "0x10000000000000000", "18446744073709551616", + "-0x10000000000000000", "-18446744073709551616", + "-0x8000000000000001", "-9223372036854775809", + "0x8000000t", "0x800000000g", + "0x800000000000m", "0x800000000000000k", + "-0x8000000t", "-0x800000000g", + "-0x800000000000m", "-0x800000000000000k", + NULL, + }; + check_invalid_numeric_string(flag, invalid_strings); + } + + if (!is_double) { + const char* invalid_strings_for_integers[] = { + "1.0", "0x4.5", "0.001", "4e10", + NULL, + }; + check_invalid_numeric_string(flag, invalid_strings_for_integers); + } +} + +#define INTEGER_TEST_TABLE(f) \ + /*input i32 u32 i64 u64 */ \ + f("0", 0, 0, 0, 0 ) \ + f("-0", 0, BAD, 0, BAD ) \ + f("-1", -1, BAD, -1, BAD ) \ + f("0x1", 1, 1, 1, 1 ) \ + f("-0x1", -1, BAD, -1, BAD ) \ + f("4711", 4711, 4711, 4711, 4711 ) \ + f("1K", 1024, 1024, 1024, 1024 ) \ + f("1k", 1024, 1024, 1024, 1024 ) \ + f("2M", 2097152, 2097152, 2097152, 2097152 ) \ + f("2m", 2097152, 2097152, 2097152, 2097152 ) \ + f("1G", 1073741824, 1073741824, 1073741824, 1073741824 ) \ + f("2G", BAD, 0x80000000, 2147483648LL, 2147483648ULL ) \ + f("1T", BAD, BAD, 1099511627776LL, 1099511627776ULL ) \ + f("1t", BAD, BAD, 1099511627776LL, 1099511627776ULL ) \ + f("-1K", -1024, BAD, -1024, BAD ) \ + f("0x1K", 1024, 1024, 1024, 1024 ) \ + f("-0x1K", -1024, BAD, -1024, BAD ) \ + f("0K", 0, 0, 0, 0 ) \ + f("0x1000000k", BAD, BAD, 17179869184LL, 17179869184ULL ) \ + f("0x800000m", BAD, BAD, 0x80000000000LL, 0x80000000000ULL ) \ + f("0x8000g", BAD, BAD, 0x200000000000LL, 0x200000000000ULL ) \ + f("0x8000t", BAD, BAD, 0x80000000000000LL, 0x80000000000000ULL ) \ + f("-0x1000000k", BAD, BAD, -17179869184LL, BAD ) \ + f("-0x800000m", BAD, BAD, -0x80000000000LL, BAD ) \ + f("-0x8000g", BAD, BAD, -0x200000000000LL, BAD ) \ + f("-0x8000t", BAD, BAD, -0x80000000000000LL, BAD ) \ + f("0x7fffffff", 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff ) \ + f("0xffffffff", BAD, 0xffffffff, 0xffffffff, 0xffffffff ) \ + f("0x80000000", BAD, 0x80000000, 0x80000000, 0x80000000 ) \ + f("-0x7fffffff", -2147483647, BAD, -2147483647LL, BAD ) \ + f("-0x80000000", -2147483648, BAD, -2147483648LL, BAD ) \ + f("-0x80000001", BAD, BAD, -2147483649LL, BAD ) \ + f("0x100000000", BAD, BAD, 0x100000000LL, 0x100000000ULL ) \ + f("0xcafebabe", BAD, 0xcafebabe, 0xcafebabe, 0xcafebabe ) \ + f("0XCAFEBABE", BAD, 0xcafebabe, 0xcafebabe, 0xcafebabe ) \ + f("0XCAFEbabe", BAD, 0xcafebabe, 0xcafebabe, 0xcafebabe ) \ + f("0xcafebabe1", BAD, BAD, 0xcafebabe1, 0xcafebabe1 ) \ + f("0x7fffffffffffffff", BAD, BAD, max_jlong, 9223372036854775807ULL ) \ + f("0x8000000000000000", BAD, BAD, BAD, 9223372036854775808ULL ) \ + f("0xffffffffffffffff", BAD, BAD, BAD, max_julong ) \ + f("9223372036854775807", BAD, BAD, 9223372036854775807LL, 9223372036854775807ULL ) \ + f("9223372036854775808", BAD, BAD, BAD, 9223372036854775808ULL ) \ + f("-9223372036854775808", BAD, BAD, min_jlong, BAD ) \ + f("18446744073709551615", BAD, BAD, BAD, max_julong ) \ + \ + /* All edge cases without a k/m/g/t suffix */ \ + f("0x7ffffffe", max_jint-1, 0x7ffffffe, 0x7ffffffeLL, 0x7ffffffeULL ) \ + f("0x7fffffff", max_jint, 0x7fffffff, 0x7fffffffLL, 0x7fffffffULL ) \ + f("0x80000000", BAD, 0x80000000, 0x80000000LL, 0x80000000ULL ) \ + f("0xfffffffe", BAD, max_juint-1, 0xfffffffeLL, 0xfffffffeULL ) \ + f("0xffffffff", BAD, max_juint, 0xffffffffLL, 0xffffffffULL ) \ + f("0x100000000", BAD, BAD, 0x100000000LL, 0x100000000ULL ) \ + f("-0x7fffffff", min_jint+1, BAD, -0x7fffffffLL, BAD ) \ + f("-0x80000000", min_jint, BAD, -0x80000000LL, BAD ) \ + f("-0x80000001", BAD, BAD, -0x80000001LL, BAD ) \ + \ + f("0x7ffffffffffffffe", BAD, BAD, max_jlong-1, 0x7ffffffffffffffeULL ) \ + f("0x7fffffffffffffff", BAD, BAD, max_jlong, 0x7fffffffffffffffULL ) \ + f("0x8000000000000000", BAD, BAD, BAD, 0x8000000000000000ULL ) \ + f("0xfffffffffffffffe", BAD, BAD, BAD, max_julong-1 ) \ + f("0xffffffffffffffff", BAD, BAD, BAD, max_julong ) \ + f("0x10000000000000000", BAD, BAD, BAD, BAD ) \ + f("-0x7fffffffffffffff", BAD, BAD, min_jlong+1, BAD ) \ + f("-0x8000000000000000", BAD, BAD, min_jlong, BAD ) \ + f("-0x8000000000000001", BAD, BAD, BAD, BAD ) \ + \ + /* edge cases for suffix: K */ \ + f("0x1ffffek", 0x1ffffe * k, 0x1ffffeU * k,0x1ffffeLL * k, 0x1ffffeULL * k ) \ + f("0x1fffffk", 0x1fffff * k, 0x1fffffU * k,0x1fffffLL * k, 0x1fffffULL * k ) \ + f("0x200000k", BAD, 0x200000U * k,0x200000LL * k, 0x200000ULL * k ) \ + f("0x3ffffek", BAD, 0x3ffffeU * k,0x3ffffeLL * k, 0x3ffffeULL * k ) \ + f("0x3fffffk", BAD, 0x3fffffU * k,0x3fffffLL * k, 0x3fffffULL * k ) \ + f("0x400000k", BAD, BAD, 0x400000LL * k, 0x400000ULL * k ) \ + f("-0x1fffffk", -0x1fffff * k, BAD, -0x1fffffLL * k, BAD ) \ + f("-0x200000k", -0x200000 * k, BAD, -0x200000LL * k, BAD ) \ + f("-0x200001k", BAD, BAD, -0x200001LL * k, BAD ) \ + \ + f("0x1ffffffffffffek", BAD, BAD, 0x1ffffffffffffeLL * k, 0x1ffffffffffffeULL * k ) \ + f("0x1fffffffffffffk", BAD, BAD, 0x1fffffffffffffLL * k, 0x1fffffffffffffULL * k ) \ + f("0x20000000000000k", BAD, BAD, BAD, 0x20000000000000ULL * k ) \ + f("0x3ffffffffffffek", BAD, BAD, BAD, 0x3ffffffffffffeULL * k ) \ + f("0x3fffffffffffffk", BAD, BAD, BAD, 0x3fffffffffffffULL * k ) \ + f("0x40000000000000k", BAD, BAD, BAD, BAD ) \ + f("-0x1fffffffffffffk", BAD, BAD, -0x1fffffffffffffLL * k, BAD ) \ + f("-0x20000000000000k", BAD, BAD, -0x20000000000000LL * k, BAD ) \ + f("-0x20000000000001k", BAD, BAD, BAD, BAD ) \ + \ + /* edge cases for suffix: M */ \ + f("0x7fem", 0x7fe * m, 0x7feU * m, 0x7feLL * m, 0x7feULL * m ) \ + f("0x7ffm", 0x7ff * m, 0x7ffU * m, 0x7ffLL * m, 0x7ffULL * m ) \ + f("0x800m", BAD, 0x800U * m, 0x800LL * m, 0x800ULL * m ) \ + f("0xffem", BAD, 0xffeU * m, 0xffeLL * m, 0xffeULL * m ) \ + f("0xfffm", BAD, 0xfffU * m, 0xfffLL * m, 0xfffULL * m ) \ + f("0x1000m", BAD, BAD, 0x1000LL * m, 0x1000ULL * m ) \ + f("-0x7ffm", -0x7ff * m, BAD, -0x7ffLL * m, BAD ) \ + f("-0x800m", -0x800 * m, BAD, -0x800LL * m, BAD ) \ + f("-0x801m", BAD, BAD, -0x801LL * m, BAD ) \ + \ + f("0x7fffffffffem", BAD, BAD, 0x7fffffffffeLL * m, 0x7fffffffffeULL * m ) \ + f("0x7ffffffffffm", BAD, BAD, 0x7ffffffffffLL * m, 0x7ffffffffffULL * m ) \ + f("0x80000000000m", BAD, BAD, BAD, 0x80000000000ULL * m ) \ + f("0xffffffffffem", BAD, BAD, BAD, 0xffffffffffeULL * m ) \ + f("0xfffffffffffm", BAD, BAD, BAD, 0xfffffffffffULL * m ) \ + f("0x100000000000m", BAD, BAD, BAD, BAD ) \ + f("-0x7ffffffffffm", BAD, BAD, -0x7ffffffffffLL * m, BAD ) \ + f("-0x80000000000m", BAD, BAD, -0x80000000000LL * m, BAD ) \ + f("-0x80000000001m", BAD, BAD, BAD, BAD ) \ + \ + /* edge cases for suffix: G */ \ + f("0x0g", 0x0 * g, 0x0U * g, 0x0LL * g, 0x0ULL * g ) \ + f("0x1g", 0x1 * g, 0x1U * g, 0x1LL * g, 0x1ULL * g ) \ + f("0x2g", BAD, 0x2U * g, 0x2LL * g, 0x2ULL * g ) \ + f("0x3g", BAD, 0x3U * g, 0x3LL * g, 0x3ULL * g ) \ + f("0x4g", BAD, BAD, 0x4LL * g, 0x4ULL * g ) \ + f("-0x1g", -0x1 * g, BAD, -0x1LL * g, BAD ) \ + f("-0x2g", -0x2 * g, BAD, -0x2LL * g, BAD ) \ + f("-0x3g", BAD, BAD, -0x3LL * g, BAD ) \ + \ + f("0x1fffffffeg", BAD, BAD, 0x1fffffffeLL * g, 0x1fffffffeULL * g ) \ + f("0x1ffffffffg", BAD, BAD, 0x1ffffffffLL * g, 0x1ffffffffULL * g ) \ + f("0x200000000g", BAD, BAD, BAD, 0x200000000ULL * g ) \ + f("0x3fffffffeg", BAD, BAD, BAD, 0x3fffffffeULL * g ) \ + f("0x3ffffffffg", BAD, BAD, BAD, 0x3ffffffffULL * g ) \ + f("0x400000000g", BAD, BAD, BAD, BAD ) \ + f("-0x1ffffffffg", BAD, BAD, -0x1ffffffffLL * g, BAD ) \ + f("-0x200000000g", BAD, BAD, -0x200000000LL * g, BAD ) \ + f("-0x200000001g", BAD, BAD, BAD, BAD ) \ + \ + /* edge cases for suffix: T */ \ + f("0x7ffffet", BAD, BAD, 0x7ffffeLL * t, 0x7ffffeULL * t ) \ + f("0x7ffffft", BAD, BAD, 0x7fffffLL * t, 0x7fffffULL * t ) \ + f("0x800000t", BAD, BAD, BAD, 0x800000ULL * t ) \ + f("0xfffffet", BAD, BAD, BAD, 0xfffffeULL * t ) \ + f("0xfffffft", BAD, BAD, BAD, 0xffffffULL * t ) \ + f("0x1000000t", BAD, BAD, BAD, BAD ) \ + f("-0x7ffffft", BAD, BAD, -0x7fffffLL * t, BAD ) \ + f("-0x800000t", BAD, BAD, -0x800000LL * t, BAD ) \ + f("-0x800001t", BAD, BAD, BAD, BAD ) + +#define INTEGER_TEST_i32(s, i32, u32, i64, u64) NumericArgument<T>(s, i32), +#define INTEGER_TEST_u32(s, i32, u32, i64, u64) NumericArgument<T>(s, u32), +#define INTEGER_TEST_i64(s, i32, u32, i64, u64) NumericArgument<T>(s, i64), +#define INTEGER_TEST_u64(s, i32, u32, i64, u64) NumericArgument<T>(s, u64), + +// signed 32-bit +template <typename T, ENABLE_IF(std::is_signed<T>::value), ENABLE_IF(sizeof(T) == 4)> +void check_flag(const char* f, T getvalue(JVMFlag* flag)) { + JVMFlag* flag = JVMFlag::find_flag(f); + if (flag == NULL) { // not available in product builds + return; + } + + T k = static_cast<T>(K); + T m = static_cast<T>(M); + T g = static_cast<T>(G); + NumericArgument<T> valid_strings[] = { INTEGER_TEST_TABLE(INTEGER_TEST_i32) }; + check_numeric_flag(flag, getvalue, valid_strings, ARRAY_SIZE(valid_strings)); +} + +// unsigned 32-bit +template <typename T, ENABLE_IF(!std::is_signed<T>::value), ENABLE_IF(sizeof(T) == 4)> +void check_flag(const char* f, T getvalue(JVMFlag* flag)) { + JVMFlag* flag = JVMFlag::find_flag(f); + if (flag == NULL) { // not available in product builds + return; + } + + T k = static_cast<T>(K); + T m = static_cast<T>(M); + T g = static_cast<T>(G); + NumericArgument<T> valid_strings[] = { INTEGER_TEST_TABLE(INTEGER_TEST_u32) }; + check_numeric_flag(flag, getvalue, valid_strings, ARRAY_SIZE(valid_strings)); +} + +// signed 64-bit +template <typename T, ENABLE_IF(std::is_signed<T>::value), ENABLE_IF(sizeof(T) == 8)> +void check_flag(const char* f, T getvalue(JVMFlag* flag)) { + JVMFlag* flag = JVMFlag::find_flag(f); + if (flag == NULL) { // not available in product builds + return; + } + + T k = static_cast<T>(K); + T m = static_cast<T>(M); + T g = static_cast<T>(G); + T t = static_cast<T>(G) * k; + NumericArgument<T> valid_strings[] = { INTEGER_TEST_TABLE(INTEGER_TEST_i64) }; + check_numeric_flag(flag, getvalue, valid_strings, ARRAY_SIZE(valid_strings)); +} + +// unsigned 64-bit +template <typename T, ENABLE_IF(!std::is_signed<T>::value), ENABLE_IF(sizeof(T) == 8)> +void check_flag(const char* f, T getvalue(JVMFlag* flag)) { + JVMFlag* flag = JVMFlag::find_flag(f); + if (flag == NULL) { // not available in product builds + return; + } + + T k = static_cast<T>(K); + T m = static_cast<T>(M); + T g = static_cast<T>(G); + T t = static_cast<T>(G) * k; + NumericArgument<T> valid_strings[] = { INTEGER_TEST_TABLE(INTEGER_TEST_u64) }; + check_numeric_flag(flag, getvalue, valid_strings, ARRAY_SIZE(valid_strings)); +} + +// Testing the parsing of -XX:<SomeFlag>=<an integer value> +// +// All of the integral types that can be used for command line options: +// int, uint, intx, uintx, uint64_t, size_t +// +// In all supported platforms, these types can be mapped to only 4 native types: +// {signed, unsigned} x {32-bit, 64-bit} +// +// We use SFINAE to pick the correct column in the INTEGER_TEST_TABLE for each type. + +TEST_VM_F(ArgumentsTest, set_numeric_flag_int) { + check_flag<int>("TestFlagFor_int", [] (JVMFlag* flag) { + return flag->get_int(); + }); +} + +TEST_VM_F(ArgumentsTest, set_numeric_flag_uint) { + check_flag<uint>("TestFlagFor_uint", [] (JVMFlag* flag) { + return flag->get_uint(); + }); +} + +TEST_VM_F(ArgumentsTest, set_numeric_flag_intx) { + check_flag<intx>("TestFlagFor_intx", [] (JVMFlag* flag) { + return flag->get_intx(); + }); +} + +TEST_VM_F(ArgumentsTest, set_numeric_flag_uintx) { + check_flag<uintx>("TestFlagFor_uintx", [] (JVMFlag* flag) { + return flag->get_uintx(); + }); +} + +TEST_VM_F(ArgumentsTest, set_numeric_flag_uint64_t) { + check_flag<uint64_t>("TestFlagFor_uint64_t", [] (JVMFlag* flag) { + return flag->get_uint64_t(); + }); +} + +TEST_VM_F(ArgumentsTest, set_numeric_flag_size_t) { + check_flag<size_t>("TestFlagFor_size_t", [] (JVMFlag* flag) { + return flag->get_size_t(); + }); +} + +TEST_VM_F(ArgumentsTest, set_numeric_flag_double) { + JVMFlag* flag = JVMFlag::find_flag("TestFlagFor_double"); + if (flag == NULL) { // not available in product builds + return; + } + + // TODO -- JDK-8282774 + // Need to add more test input that have a fractional part like "4.2". + NumericArgument<double> valid_strings[] = { + NumericArgument<double>("0", 0.0), + NumericArgument<double>("1", 1.0), + NumericArgument<double>("-0", -0.0), + NumericArgument<double>("-1", -1.0), + }; + + auto getvalue = [] (JVMFlag* flag) { + return flag->get_double(); + }; + + check_numeric_flag<double>(flag, getvalue, valid_strings, + ARRAY_SIZE(valid_strings), /*is_double=*/true); +} diff --git a/test/hotspot/gtest/runtime/test_committed_virtualmemory.cpp b/test/hotspot/gtest/runtime/test_committed_virtualmemory.cpp index 0abc004a93542aaba5a9f5f21ff8cdba357312e5..b95b86c1247b19eaae31627a61217e19b1771d02 100644 --- a/test/hotspot/gtest/runtime/test_committed_virtualmemory.cpp +++ b/test/hotspot/gtest/runtime/test_committed_virtualmemory.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -26,8 +26,6 @@ // Included early because the NMT flags don't include it. #include "utilities/macros.hpp" -#if INCLUDE_NMT - #include "runtime/thread.hpp" #include "services/memTracker.hpp" #include "services/virtualMemoryTracker.hpp" @@ -223,5 +221,3 @@ TEST_VM(CommittedVirtualMemoryTracker, test_committed_virtualmemory_region) { } } - -#endif // INCLUDE_NMT diff --git a/test/hotspot/gtest/runtime/test_os.cpp b/test/hotspot/gtest/runtime/test_os.cpp index 1c8ed269b54c28a03de783d662ed14dc722a6f7a..270710e94c0270559e7e02aa26eac81a7654bef8 100644 --- a/test/hotspot/gtest/runtime/test_os.cpp +++ b/test/hotspot/gtest/runtime/test_os.cpp @@ -32,6 +32,7 @@ #include "utilities/ostream.hpp" #include "utilities/align.hpp" #include "unittest.hpp" +#include "runtime/frame.inline.hpp" static size_t small_page_size() { return os::vm_page_size(); @@ -351,6 +352,23 @@ TEST_VM(os, jio_snprintf) { test_snprintf(jio_snprintf, false); } +#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, +// we need to verify that we can do so by asking for a tiny executable +// memory chunk. +static inline bool can_reserve_executable_memory(void) { + bool executable = true; + size_t len = 128; + char* p = os::reserve_memory(len, executable); + bool exec_supported = (p != NULL); + if (exec_supported) { + os::release_memory(p, len); + } + return exec_supported; +} +#endif + // Test that os::release_memory() can deal with areas containing multiple mappings. #define PRINT_MAPPINGS(s) { tty->print_cr("%s", s); os::print_memory_mappings((char*)p, total_range_len, tty); } //#define PRINT_MAPPINGS @@ -360,6 +378,13 @@ TEST_VM(os, jio_snprintf) { // (from multiple calls to os::reserve_memory) static address reserve_multiple(int num_stripes, size_t stripe_len) { assert(is_aligned(stripe_len, os::vm_allocation_granularity()), "Sanity"); + +#ifdef __APPLE__ + // Workaround: try reserving executable memory to figure out + // if such operation is supported on this macOS version + const bool exec_supported = can_reserve_executable_memory(); +#endif + size_t total_range_len = num_stripes * stripe_len; // Reserve a large contiguous area to get the address space... address p = (address)os::reserve_memory(total_range_len); @@ -371,7 +396,11 @@ static address reserve_multiple(int num_stripes, size_t stripe_len) { address q = p + (stripe * stripe_len); // Commit, alternatingly with or without exec permission, // to prevent kernel from folding these mappings. +#ifdef __APPLE__ + const bool executable = exec_supported ? (stripe % 2 == 0) : false; +#else const bool executable = stripe % 2 == 0; +#endif q = (address)os::attempt_reserve_memory_at((char*)q, stripe_len, executable); EXPECT_NE(q, (address)NULL); EXPECT_TRUE(os::commit_memory((char*)q, stripe_len, executable)); @@ -413,11 +442,7 @@ struct NUMASwitcher { #endif #ifndef _AIX // JDK-8257041 -#if defined(__APPLE__) && !defined(AARCH64) // See JDK-8267341. - TEST_VM(os, DISABLED_release_multi_mappings) { -#else - TEST_VM(os, release_multi_mappings) { -#endif +TEST_VM(os, release_multi_mappings) { // With NMT enabled, this will trigger JDK-8263464. For now disable the test if NMT=on. if (MemTracker::tracking_level() > NMT_off) { @@ -425,8 +450,26 @@ struct NUMASwitcher { } // Test that we can release an area created with multiple reservation calls - const size_t stripe_len = 4 * M; - const int num_stripes = 4; + // What we do: + // A) we reserve 6 small segments (stripes) adjacent to each other. We commit + // them with alternating permissions to prevent the kernel from folding them into + // a single segment. + // -stripe-stripe-stripe-stripe-stripe-stripe- + // B) we release the middle four stripes with a single os::release_memory call. This + // tests that os::release_memory indeed works across multiple segments created with + // multiple os::reserve calls. + // -stripe-___________________________-stripe- + // C) Into the now vacated address range between the first and the last stripe, we + // re-reserve a new memory range. We expect this to work as a proof that the address + // range was really released by the single release call (B). + // + // Note that this is inherently racy. Between (B) and (C), some other thread may have + // reserved something into the hole in the meantime. Therefore we keep that range small and + // entrenched between the first and last stripe, which reduces the chance of some concurrent + // thread grabbing that memory. + + const size_t stripe_len = os::vm_allocation_granularity(); + const int num_stripes = 6; const size_t total_range_len = stripe_len * num_stripes; // reserve address space... @@ -434,22 +477,27 @@ struct NUMASwitcher { ASSERT_NE(p, (address)NULL); PRINT_MAPPINGS("A"); - // .. release it... + // .. release the middle stripes... + address p_middle_stripes = p + stripe_len; + const size_t middle_stripe_len = (num_stripes - 2) * stripe_len; { - // On Windows, use UseNUMAInterleaving=1 which makes - // os::release_memory accept multi-map-ranges. - // Otherwise we would assert (see below for death test). + // On Windows, temporarily switch on UseNUMAInterleaving to allow release_memory to release + // multiple mappings in one go (otherwise we assert, which we test too, see death test below). WINDOWS_ONLY(NUMASwitcher b(true);) - ASSERT_TRUE(os::release_memory((char*)p, total_range_len)); + ASSERT_TRUE(os::release_memory((char*)p_middle_stripes, middle_stripe_len)); } PRINT_MAPPINGS("B"); - // re-reserve it. This should work unless release failed. - address p2 = (address)os::attempt_reserve_memory_at((char*)p, total_range_len); - ASSERT_EQ(p2, p); + // ...re-reserve the middle stripes. This should work unless release silently failed. + address p2 = (address)os::attempt_reserve_memory_at((char*)p_middle_stripes, middle_stripe_len); + ASSERT_EQ(p2, p_middle_stripes); PRINT_MAPPINGS("C"); - ASSERT_TRUE(os::release_memory((char*)p, total_range_len)); + // Clean up. Release all mappings. + { + WINDOWS_ONLY(NUMASwitcher b(true);) // allow release_memory to release multiple regions + ASSERT_TRUE(os::release_memory((char*)p, total_range_len)); + } } #endif // !AIX @@ -818,3 +866,13 @@ TEST_VM(os, iso8601_time) { // Canary should still be intact EXPECT_EQ(buffer[os::iso8601_timestamp_size], 'X'); } + +TEST_VM(os, is_first_C_frame) { +#if !defined(_WIN32) && !defined(ZERO) + frame invalid_frame; + EXPECT_TRUE(os::is_first_C_frame(&invalid_frame)); // the frame has zeroes for all values + + frame cur_frame = os::current_frame(); // this frame has to have a sender + EXPECT_FALSE(os::is_first_C_frame(&cur_frame)); +#endif // _WIN32 +} diff --git a/test/hotspot/gtest/runtime/test_os_windows.cpp b/test/hotspot/gtest/runtime/test_os_windows.cpp index 0308857989cb9f819c2c4715007ade31eefb2de2..b4e51065e8180ba484823afb4d600786a70c78bd 100644 --- a/test/hotspot/gtest/runtime/test_os_windows.cpp +++ b/test/hotspot/gtest/runtime/test_os_windows.cpp @@ -177,7 +177,7 @@ static void delete_rel_file_w(const wchar_t* path) { EXPECT_TRUE(result) << "Failed to delete file \"" << path << "\": " << GetLastError(); } -static bool convert_to_cstring(char* c_str, size_t size, wchar_t* w_str) { +static bool convert_to_cstring(char* c_str, size_t size, const wchar_t* w_str) { size_t converted; errno_t err = wcstombs_s(&converted, c_str, size, w_str, size - 1); EXPECT_EQ(err, ERROR_SUCCESS) << "Could not convert \"" << w_str << "\" to c-string"; @@ -307,7 +307,7 @@ static void check_file_impl(wchar_t* path) { } } -static void check_file_not_present_impl(wchar_t* path) { +static void check_file_not_present_impl(const wchar_t* path) { char buf[JVM_MAXPATHLEN]; if (convert_to_cstring(buf, JVM_MAXPATHLEN, path)) { @@ -361,7 +361,7 @@ static void check_file(wchar_t* path) { } } -static void check_file_not_present(wchar_t* path) { +static void check_file_not_present(const wchar_t* path) { check_file_not_present_impl(path); for (int i = 0; mods_filter != Allow_None && i < mods_per_path; ++i) { @@ -455,7 +455,7 @@ static void bench_path(wchar_t* path) { } } -static void print_attr_result_for_path(wchar_t* path) { +static void print_attr_result_for_path(const wchar_t* path) { WIN32_FILE_ATTRIBUTE_DATA file_data; struct stat st; char buf[JVM_MAXPATHLEN]; @@ -476,7 +476,7 @@ static void print_attr_result_for_path(wchar_t* path) { } } -static void print_attr_result(wchar_t* format, ...) { +static void print_attr_result(const wchar_t* format, ...) { va_list argptr; wchar_t buf[JVM_MAXPATHLEN]; @@ -513,10 +513,10 @@ TEST_VM(os_windows, handle_long_paths) { static wchar_t root_dir_path[JVM_MAXPATHLEN]; static wchar_t root_rel_dir_path[JVM_MAXPATHLEN]; - wchar_t* dir_prefix = L"os_windows_long_paths_dir_"; - wchar_t* empty_dir_name = L"empty_directory_with_long_path"; - wchar_t* not_empty_dir_name = L"not_empty_directory_with_long_path"; - wchar_t* file_name = L"file"; + const wchar_t* dir_prefix = L"os_windows_long_paths_dir_"; + const wchar_t* empty_dir_name = L"empty_directory_with_long_path"; + const wchar_t* not_empty_dir_name = L"not_empty_directory_with_long_path"; + const wchar_t* file_name = L"file"; wchar_t dir_letter; WIN32_FILE_ATTRIBUTE_DATA file_data; bool can_test_unc = false; @@ -683,7 +683,7 @@ TEST_VM(os_windows, handle_long_paths) { // The other drive letter should not overwrite the original one. if (dir_letter) { static wchar_t tmp[JVM_MAXPATHLEN]; - wchar_t* other_letter = dir_letter == L'D' ? L"C" : L"D"; + const wchar_t* other_letter = dir_letter == L'D' ? L"C" : L"D"; wsprintfW(tmp, L"%2ls\\..\\%ls:%ls", nearly_long_file_path, other_letter, nearly_long_file_path + 2); check_file_not_present(tmp); wsprintfW(tmp, L"%2ls\\..\\%ls:%ls", file_path, other_letter, file_path + 2); diff --git a/test/hotspot/gtest/runtime/test_virtualMemoryTracker.cpp b/test/hotspot/gtest/runtime/test_virtualMemoryTracker.cpp index ae4457f3e9358e5b52ae17b65c14b5275dbfa0ce..4aa058dc160e3c70059801f52d6671380d9a0436 100644 --- a/test/hotspot/gtest/runtime/test_virtualMemoryTracker.cpp +++ b/test/hotspot/gtest/runtime/test_virtualMemoryTracker.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -32,16 +32,13 @@ #include "precompiled.hpp" -// Included early because the NMT flags don't include it. -#include "utilities/macros.hpp" - -#if INCLUDE_NMT - #include "memory/virtualspace.hpp" #include "services/memTracker.hpp" #include "services/virtualMemoryTracker.hpp" #include "utilities/globalDefinitions.hpp" +#include "utilities/macros.hpp" #include "unittest.hpp" + #include <stdio.h> // #define LOG(...) printf(__VA_ARGS__); printf("\n"); fflush(stdout); @@ -566,5 +563,3 @@ TEST_VM(NMT_VirtualMemoryTracker, remove_uncommitted_region) { tty->print_cr("skipped."); } } - -#endif // INCLUDE_NMT diff --git a/test/hotspot/gtest/testutils.cpp b/test/hotspot/gtest/testutils.cpp index 47351f056affa96a4abcaeb53f693701c99ca2f9..eb2898a526dc87e1a7fd3d30724e8d209942b7ed 100644 --- a/test/hotspot/gtest/testutils.cpp +++ b/test/hotspot/gtest/testutils.cpp @@ -57,7 +57,8 @@ bool GtestUtils::check_range(const void* p, size_t s, uint8_t expected) { } if (first_wrong != NULL) { - tty->print_cr("wrong pattern around " PTR_FORMAT, p2i(first_wrong)); + tty->print_cr("check_range [" PTR_FORMAT ".." PTR_FORMAT "), 0x%X, : wrong pattern around " PTR_FORMAT, + p2i(p), p2i(p) + s, expected, p2i(first_wrong)); // Note: We deliberately print the surroundings too without bounds check. Might be interesting, // and os::print_hex_dump uses SafeFetch, so this is fine without bounds checks. os::print_hex_dump(tty, (address)(align_down(p2, 0x10) - 0x10), diff --git a/test/hotspot/gtest/testutils.hpp b/test/hotspot/gtest/testutils.hpp index 8ed72f4644fab778465d144ede8ac1122a210651..9852e87cadae22b18fbf7b70fa18024ddee75807 100644 --- a/test/hotspot/gtest/testutils.hpp +++ b/test/hotspot/gtest/testutils.hpp @@ -51,8 +51,8 @@ public: #define ASSERT_RANGE_IS_MARKED(p, size) ASSERT_TRUE(GtestUtils::check_range(p, size)) // Convenience asserts -#define ASSERT_NOT_NULL(p) ASSERT_NE(p, (char*)NULL) -#define ASSERT_NULL(p) ASSERT_EQ(p, (char*)NULL) +#define ASSERT_NOT_NULL(p) ASSERT_NE(p2i(p), 0) +#define ASSERT_NULL(p) ASSERT_EQ(p2i(p), 0) #define ASSERT_ALIGN(p, n) ASSERT_TRUE(is_aligned(p, n)) diff --git a/test/hotspot/gtest/threadHelper.inline.hpp b/test/hotspot/gtest/threadHelper.inline.hpp index 52c044850e8def28e7bbd07506b8b67c2e495a60..3c6b951df0a208055ec5d65e60f572d25e54e267 100644 --- a/test/hotspot/gtest/threadHelper.inline.hpp +++ b/test/hotspot/gtest/threadHelper.inline.hpp @@ -49,13 +49,13 @@ static void startTestThread(JavaThread* thread, const char* name) { } } -class VM_StopSafepoint : public VM_Operation { +class VM_GTestStopSafepoint : public VM_Operation { public: Semaphore* _running; Semaphore* _test_complete; - VM_StopSafepoint(Semaphore* running, Semaphore* wait_for) : + VM_GTestStopSafepoint(Semaphore* running, Semaphore* wait_for) : _running(running), _test_complete(wait_for) {} - VMOp_Type type() const { return VMOp_None; } + VMOp_Type type() const { return VMOp_GTestStopSafepoint; } bool evaluate_at_safepoint() const { return false; } void doit() { _running->signal(); _test_complete->wait(); } }; @@ -67,7 +67,7 @@ class VMThreadBlocker : public JavaThread { static void blocker_thread_entry(JavaThread* thread, TRAPS) { VMThreadBlocker* t = static_cast<VMThreadBlocker*>(thread); - VM_StopSafepoint ss(&t->_ready, &t->_unblock); + VM_GTestStopSafepoint ss(&t->_ready, &t->_unblock); VMThread::execute(&ss); } diff --git a/test/hotspot/gtest/unittest.hpp b/test/hotspot/gtest/unittest.hpp index b414b2fbdd97c811c254040f1ad3753e3a8b483b..fefcc8efc398541c313410337909e417c4698ec6 100644 --- a/test/hotspot/gtest/unittest.hpp +++ b/test/hotspot/gtest/unittest.hpp @@ -149,4 +149,21 @@ TEST_VM_ASSERT_MSG is only available in debug builds #endif +#define TEST_VM_FATAL_ERROR_MSG(category, name, msg) \ + static void test_ ## category ## _ ## name ## _(); \ + \ + static void child_ ## category ## _ ## name ## _() { \ + ::testing::GTEST_FLAG(throw_on_failure) = true; \ + test_ ## category ## _ ## name ## _(); \ + exit(0); \ + } \ + \ + TEST(category, CONCAT(name, _vm_assert)) { \ + ASSERT_EXIT(child_ ## category ## _ ## name ## _(), \ + ::testing::ExitedWithCode(1), \ + msg); \ + } \ + \ + void test_ ## category ## _ ## name ## _() + #endif // UNITTEST_HPP diff --git a/test/hotspot/jtreg/ProblemList-Xcomp.txt b/test/hotspot/jtreg/ProblemList-Xcomp.txt index 9647d4d2cf8a3c2b0d5515a3b13b167eba7508cc..23f25da41d0aa997b30f091c8c4bc56f3a244c31 100644 --- a/test/hotspot/jtreg/ProblemList-Xcomp.txt +++ b/test/hotspot/jtreg/ProblemList-Xcomp.txt @@ -27,16 +27,11 @@ # ############################################################################# -compiler/intrinsics/bmi/verifycode/BzhiTestI2L.java 8268033 generic-x64 - vmTestbase/nsk/jvmti/SetFieldAccessWatch/setfldw001/TestDescription.java 8205957 generic-all vmTestbase/vm/mlvm/mixed/stress/regression/b6969574/INDIFY_Test.java 8265295 linux-x64,windows-x64 vmTestbase/nsk/jvmti/scenarios/sampling/SP07/sp07t002/TestDescription.java 8245680 windows-x64 -vmTestbase/vm/mlvm/hiddenloader/stress/oome/heap/Test.java 8273095 generic-all - serviceability/sa/TestJhsdbJstackMixed.java 8248675 linux-aarch64 -compiler/codegen/aes/TestAESMain.java 8274323 linux-x64,windows-x64 diff --git a/test/hotspot/jtreg/ProblemList-zgc.txt b/test/hotspot/jtreg/ProblemList-zgc.txt index 5a92dbd5daac05055f006c92776f7649757d0cae..5976517630f09f813666656841a12a95f43ad8ee 100644 --- a/test/hotspot/jtreg/ProblemList-zgc.txt +++ b/test/hotspot/jtreg/ProblemList-zgc.txt @@ -27,8 +27,6 @@ # ############################################################################# -vmTestbase/jit/escape/AdaptiveBlocking/AdaptiveBlocking001/AdaptiveBlocking001.java 8260303 windows-x64 - resourcehogs/serviceability/sa/TestHeapDumpForLargeArray.java 8276539 generic-all serviceability/sa/CDSJMapClstats.java 8276539 generic-all serviceability/sa/ClhsdbJhisto.java 8276539 generic-all diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index 7a2d384325a1c21b72edac6545c39117b0a65b2b..870f1d3c596e431984c93de765268c4994301998 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -1,5 +1,5 @@ # -# Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. +# 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 @@ -38,9 +38,6 @@ # ############################################################################# -vmTestbase/nsk/jvmti/AttachOnDemand/attach002a/TestDescription.java 8265795 generic-all -vmTestbase/nsk/jvmti/AttachOnDemand/attach022/TestDescription.java 8265795 generic-all -vmTestbase/nsk/jdi/ObjectReference/referringObjects/referringObjects002/referringObjects002.java 8265796 generic-all ############################################################################# @@ -70,11 +67,11 @@ compiler/rtm/print/TestPrintPreciseRTMLockingStatistics.java 8183263 generic-x64 compiler/c2/Test8004741.java 8235801 generic-all -compiler/whitebox/ClearMethodStateTest.java 8265360 macosx-aarch64 -compiler/whitebox/EnqueueMethodForCompilationTest.java 8265360 macosx-aarch64 -compiler/whitebox/MakeMethodNotCompilableTest.java 8265360 macosx-aarch64 +compiler/whitebox/ClearMethodStateTest.java 8265360 macosx-all +compiler/whitebox/EnqueueMethodForCompilationTest.java 8265360 macosx-all +compiler/whitebox/MakeMethodNotCompilableTest.java 8265360 macosx-all -compiler/codecache/jmx/PoolsIndependenceTest.java 8264632 macosx-x64 +compiler/codecache/jmx/PoolsIndependenceTest.java 8264632 macosx-all compiler/codecache/TestStressCodeBuffers.java 8272094 generic-aarch64 @@ -97,7 +94,6 @@ gc/metaspace/CompressedClassSpaceSizeInJmapHeap.java 8241293 macosx-x64 # :hotspot_runtime runtime/cds/appcds/jigsaw/modulepath/ModulePathAndCP_JFR.java 8253437 windows-x64 -runtime/cds/DeterministicDump.java 8253495 generic-all runtime/jni/terminatedThread/TestTerminatedThread.java 8219652 aix-ppc64 runtime/os/TestTracePageSizes.java#no-options 8267460 linux-aarch64 runtime/os/TestTracePageSizes.java#explicit-large-page-size 8267460 linux-aarch64 @@ -105,9 +101,12 @@ runtime/os/TestTracePageSizes.java#compiler-options 8267460 linux-aarch64 runtime/os/TestTracePageSizes.java#G1 8267460 linux-aarch64 runtime/os/TestTracePageSizes.java#Parallel 8267460 linux-aarch64 runtime/os/TestTracePageSizes.java#Serial 8267460 linux-aarch64 +runtime/ErrorHandling/CreateCoredumpOnCrash.java 8267433 macosx-x64 applications/jcstress/copy.java 8229852 linux-all +containers/docker/TestJcmd.java 8278102 linux-aarch64 + ############################################################################# # :hotspot_serviceability @@ -118,10 +117,13 @@ serviceability/sa/TestRevPtrsForInvokeDynamic.java 8241235 generic-all serviceability/jvmti/ModuleAwareAgents/ThreadStart/MAAThreadStart.java 8225354 windows-all serviceability/dcmd/gc/RunFinalizationTest.java 8227120 linux-all,windows-x64 -serviceability/sa/ClhsdbCDSCore.java 8269982 macosx-aarch64 -serviceability/sa/ClhsdbFindPC.java#xcomp-core 8269982 macosx-aarch64 -serviceability/sa/ClhsdbFindPC.java#no-xcomp-core 8269982 macosx-aarch64 -serviceability/sa/ClhsdbPstack.java#core 8269982 macosx-aarch64 +serviceability/sa/ClhsdbCDSCore.java 8269982,8267433 macosx-aarch64,macosx-x64 +serviceability/sa/ClhsdbFindPC.java#xcomp-core 8269982,8267433 macosx-aarch64,macosx-x64 +serviceability/sa/ClhsdbFindPC.java#no-xcomp-core 8269982,8267433 macosx-aarch64,macosx-x64 +serviceability/sa/ClhsdbPmap.java#core 8269982,8267433 macosx-aarch64,macosx-x64 +serviceability/sa/ClhsdbPstack.java#core 8269982,8267433 macosx-aarch64,macosx-x64 +serviceability/sa/TestJmapCore.java 8269982,8267433 macosx-aarch64,macosx-x64 +serviceability/sa/TestJmapCoreMetaspace.java 8269982,8267433 macosx-aarch64,macosx-x64 ############################################################################# @@ -142,7 +144,6 @@ vmTestbase/nsk/monitoring/MemoryPoolMBean/isUsageThresholdExceeded/isexceeded002 vmTestbase/nsk/monitoring/MemoryPoolMBean/isUsageThresholdExceeded/isexceeded003/TestDescription.java 8198668 generic-all vmTestbase/nsk/monitoring/MemoryPoolMBean/isUsageThresholdExceeded/isexceeded004/TestDescription.java 8153598 generic-all vmTestbase/nsk/monitoring/MemoryPoolMBean/isUsageThresholdExceeded/isexceeded005/TestDescription.java 8153598 generic-all -vmTestbase/nsk/monitoring/ThreadMXBean/ThreadInfo/Deadlock/JavaDeadlock001/TestDescription.java 8060733 generic-all vmTestbase/nsk/jdi/HiddenClass/events/events001.java 8257705 generic-all vmTestbase/nsk/jdi/ThreadReference/stop/stop001/TestDescription.java 7034630 generic-all @@ -156,9 +157,7 @@ vmTestbase/nsk/jvmti/AttachOnDemand/attach045/TestDescription.java 8202971 gener vmTestbase/nsk/jvmti/scenarios/jni_interception/JI05/ji05t001/TestDescription.java 8219652 aix-ppc64 vmTestbase/nsk/jvmti/scenarios/jni_interception/JI06/ji06t001/TestDescription.java 8219652 aix-ppc64 vmTestbase/nsk/jvmti/SetJNIFunctionTable/setjniftab001/TestDescription.java 8219652 aix-ppc64 -vmTestbase/nsk/jvmti/SuspendThread/suspendthrd003/TestDescription.java 8264605 generic-all -vmTestbase/nsk/jvmti/PopFrame/popframe011/TestDescription.java 8266593 generic-all -vmTestbase/nsk/jvmti/RedefineClasses/StressRedefineWithoutBytecodeCorruption/TestDescription.java 8272800 generic-all +vmTestbase/nsk/jvmti/AttachOnDemand/attach002a/TestDescription.java 8277812 generic-all vmTestbase/gc/lock/jni/jnilock002/TestDescription.java 8192647 generic-all diff --git a/test/hotspot/jtreg/TEST.ROOT b/test/hotspot/jtreg/TEST.ROOT index 84ccf8ec91cb7cdf9be347fc007b67d952e5b2d8..c4015b00fd5683d218798ddcdab20faaa97e9886 100644 --- a/test/hotspot/jtreg/TEST.ROOT +++ b/test/hotspot/jtreg/TEST.ROOT @@ -63,6 +63,7 @@ requires.properties= \ vm.debug \ vm.hasSA \ vm.hasJFR \ + vm.hasDTrace \ vm.rtm.cpu \ vm.rtm.compiler \ vm.cds \ diff --git a/test/hotspot/jtreg/TEST.groups b/test/hotspot/jtreg/TEST.groups index 9578e55493ad7d03b151012ea009882b9eb9d070..b1403a935d19015db77910a271cefb5ffabc546f 100644 --- a/test/hotspot/jtreg/TEST.groups +++ b/test/hotspot/jtreg/TEST.groups @@ -46,6 +46,10 @@ hotspot_gc = \ hotspot_runtime = \ runtime +hotspot_runtime_no_cds = \ + runtime \ + -runtime/cds + hotspot_handshake = \ runtime/handshake @@ -71,6 +75,13 @@ hotspot_native_sanity = \ hotspot_containers = \ containers +# Test sets for running inside container environment +hotspot_containers_extended = \ + runtime \ + serviceability \ + vmTestbase/nsk/jvmti \ + vmTestbase/nsk/monitoring + hotspot_vector_1 = \ compiler/c2/cr6340864 \ compiler/codegen \ @@ -94,6 +105,9 @@ hotspot_vector_2 = \ compiler/vectorapi/VectorRebracket128Test.java \ -compiler/intrinsics/string/TestStringLatin1IndexOfChar.java +hotspot_compiler_arraycopy = \ + compiler/arraycopy/stress + tier1_common = \ sanity/BasicVMTest.java \ gtest/GTestWrapper.java \ @@ -115,7 +129,8 @@ hotspot_not_fast_compiler = \ hotspot_slow_compiler = \ compiler/codegen/aes \ compiler/codecache/stress \ - compiler/gcbarriers/PreserveFPRegistersTest.java + compiler/gcbarriers/PreserveFPRegistersTest.java \ + :hotspot_compiler_arraycopy tier1_compiler_1 = \ compiler/arraycopy/ \ @@ -132,6 +147,7 @@ tier1_compiler_1 = \ -compiler/c2/Test6792161.java \ -compiler/c2/Test6603011.java \ -compiler/c2/Test6912517.java \ + -:hotspot_slow_compiler tier1_compiler_2 = \ compiler/classUnloading/ \ @@ -173,6 +189,50 @@ tier1_compiler_3 = \ -compiler/loopopts/Test7052494.java \ -compiler/runtime/Test6826736.java +tier2_compiler = \ + compiler/allocation/ \ + compiler/arguments/ \ + compiler/calls/ \ + compiler/cha/ \ + compiler/controldependency/ \ + compiler/conversions/ \ + compiler/codegen/ \ + compiler/linkage/ \ + compiler/loopstripmining/ \ + compiler/loopopts/Test7052494.java \ + compiler/longcountedloops/ \ + compiler/intrinsics/bmi \ + compiler/intrinsics/mathexact \ + compiler/intrinsics/sha \ + compiler/intrinsics/bigInteger/TestMultiplyToLen.java \ + compiler/intrinsics/zip/TestAdler32.java \ + compiler/membars/ \ + compiler/onSpinWait/ \ + compiler/parsing/ \ + compiler/rangechecks/ \ + compiler/reflection/ \ + compiler/rtm/ \ + compiler/runtime/Test6826736.java \ + compiler/stable/ \ + compiler/stringopts/ \ + -:tier1_compiler \ + -:hotspot_slow_compiler + +tier3_compiler = \ + compiler/c2/ \ + compiler/ciReplay/ \ + compiler/compilercontrol/ \ + compiler/debug/ \ + compiler/oracle/ \ + compiler/print/ \ + compiler/relocations/ \ + compiler/tiered/ \ + compiler/vectorapi/ \ + compiler/whitebox/ \ + :hotspot_slow_compiler \ + -:tier1_compiler \ + -:tier2_compiler + tier1_compiler_not_xcomp = \ compiler/profiling @@ -328,6 +388,8 @@ hotspot_cds = \ runtime/cds/ \ runtime/CompressedOops/ +hotspot_cds_only = \ + runtime/cds/ hotspot_appcds_dynamic = \ runtime/cds/appcds/ \ @@ -349,11 +411,13 @@ hotspot_appcds_dynamic = \ -runtime/cds/appcds/BadBSM.java \ -runtime/cds/appcds/DumpClassList.java \ -runtime/cds/appcds/DumpClassListWithLF.java \ + -runtime/cds/appcds/DumpingWithNoCoops.java \ -runtime/cds/appcds/ExtraSymbols.java \ -runtime/cds/appcds/LambdaContainsOldInf.java \ -runtime/cds/appcds/LambdaEagerInit.java \ -runtime/cds/appcds/LambdaProxyClasslist.java \ -runtime/cds/appcds/LambdaVerificationFailedDuringDump.java \ + -runtime/cds/appcds/LambdaWithJavaAgent.java \ -runtime/cds/appcds/LambdaWithOldClass.java \ -runtime/cds/appcds/LongClassListPath.java \ -runtime/cds/appcds/LotsOfClasses.java \ @@ -364,6 +428,7 @@ hotspot_appcds_dynamic = \ -runtime/cds/appcds/StaticArchiveWithLambda.java \ -runtime/cds/appcds/TestCombinedCompressedFlags.java \ -runtime/cds/appcds/TestEpsilonGCWithCDS.java \ + -runtime/cds/appcds/TestParallelGCWithCDS.java \ -runtime/cds/appcds/TestSerialGCWithCDS.java \ -runtime/cds/appcds/TestZGCWithCDS.java \ -runtime/cds/appcds/UnusedCPDuringDump.java \ @@ -467,11 +532,13 @@ tier2 = \ :hotspot_tier2_runtime \ :hotspot_tier2_runtime_platform_agnostic \ :hotspot_tier2_serviceability \ + :tier2_compiler \ :tier2_gc_epsilon \ :tier2_gc_shenandoah tier3 = \ :hotspot_tier3_runtime \ + :tier3_compiler \ :tier3_gc_shenandoah # Everything that is not in other tiers, but not apps diff --git a/test/hotspot/jtreg/compiler/allocation/TestAllocArrayAfterAllocNoUse.java b/test/hotspot/jtreg/compiler/allocation/TestAllocArrayAfterAllocNoUse.java new file mode 100644 index 0000000000000000000000000000000000000000..e2bc9bfdd16d96175e2bbe89dae59c72ca207cfc --- /dev/null +++ b/test/hotspot/jtreg/compiler/allocation/TestAllocArrayAfterAllocNoUse.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 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. + */ + +/** + * @test + * @bug 8279125 + * @summary fatal error: no reachable node should have no use + * @requires vm.flavor == "server" + * + * @run main/othervm -XX:-BackgroundCompilation -XX:-DoEscapeAnalysis TestAllocArrayAfterAllocNoUse + * + */ + +public class TestAllocArrayAfterAllocNoUse { + private static Object field; + + public static void main(String[] args) { + for (int i = 0; i < 20_000; i++) { + test(); + } + } + + private static void test() { + try { + final TestAllocArrayAfterAllocNoUse o = new TestAllocArrayAfterAllocNoUse(); + } catch (Exception e) { + final int[] array = new int[100]; + field = array; + } + + } +} diff --git a/test/hotspot/jtreg/compiler/allocation/TestCCPAllocateArray.java b/test/hotspot/jtreg/compiler/allocation/TestCCPAllocateArray.java new file mode 100644 index 0000000000000000000000000000000000000000..9e312a7953031383422e2e9f391130220e0dd9dd --- /dev/null +++ b/test/hotspot/jtreg/compiler/allocation/TestCCPAllocateArray.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 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. + */ + +/** + * @test + * @bug 8279062 + * @summary C2: assert(t->meet(t0) == t) failed: Not monotonic after JDK-8278413 + * + * @run main/othervm -XX:-BackgroundCompilation TestCCPAllocateArray + * + */ + +public class TestCCPAllocateArray { + public static void main(String[] args) { + for (int i = 0; i < 20_000; i++) { + try { + test(); + } catch (OutOfMemoryError e) { + } + length(42); + } + } + + private static int[] test() { + int i = 2; + for (; i < 4; i *= 2); + return new int[length(i)]; + } + + private static int length(int i) { + return i == 4 ? Integer.MAX_VALUE : 0; + } +} diff --git a/test/hotspot/jtreg/compiler/allocation/TestFailedAllocationBadGraph.java b/test/hotspot/jtreg/compiler/allocation/TestFailedAllocationBadGraph.java new file mode 100644 index 0000000000000000000000000000000000000000..bd720a9b4f1bfe35b28fdb0925a2a473706c5bf1 --- /dev/null +++ b/test/hotspot/jtreg/compiler/allocation/TestFailedAllocationBadGraph.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 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. + */ + +/* + * @test + * bug 8279219 + * @summary C2 crash when allocating array of size too large + * @library /test/lib / + * @build sun.hotspot.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -ea -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:-BackgroundCompilation TestFailedAllocationBadGraph + */ + +import sun.hotspot.WhiteBox; +import java.lang.reflect.Method; +import compiler.whitebox.CompilerWhiteBoxTest; + +public class TestFailedAllocationBadGraph { + private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); + + private static long[] array; + private static int field; + private static volatile int barrier; + + public static void main(String[] args) throws Exception { + run("test1"); + run("test2"); + } + + private static void run(String method) throws Exception { + Method m = TestFailedAllocationBadGraph.class.getDeclaredMethod(method); + WHITE_BOX.enqueueMethodForCompilation(m, CompilerWhiteBoxTest.COMP_LEVEL_FULL_OPTIMIZATION); + if (!WHITE_BOX.isMethodCompiled(m) || WHITE_BOX.getMethodCompilationLevel(m) != CompilerWhiteBoxTest.COMP_LEVEL_FULL_OPTIMIZATION) { + throw new RuntimeException("should still be compiled"); + } + } + + private static int test1() { + int length = Integer.MAX_VALUE; + try { + array = new long[length]; + } catch (OutOfMemoryError outOfMemoryError) { + barrier = 0x42; + length = field; + } + return length; + } + + private static int test2() { + int length = -1; + try { + array = new long[length]; + } catch (OutOfMemoryError outOfMemoryError) { + barrier = 0x42; + length = field; + } + return length; + } +} diff --git a/test/hotspot/jtreg/compiler/arguments/TestCodeEntryAlignment.java b/test/hotspot/jtreg/compiler/arguments/TestCodeEntryAlignment.java new file mode 100644 index 0000000000000000000000000000000000000000..15a603822455ff29e745a7b402a946a1d2c0ce2c --- /dev/null +++ b/test/hotspot/jtreg/compiler/arguments/TestCodeEntryAlignment.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2022, Red Hat, Inc. All rights reserved. + * 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. + */ + +/* + * @test + * @library /test/lib / + * @bug 8281467 + * @requires vm.flagless + * @requires os.arch=="amd64" | os.arch=="x86_64" + * + * @summary Test large CodeEntryAlignments are accepted + * @run driver compiler.arguments.TestCodeEntryAlignment + */ + +package compiler.arguments; + +import java.io.IOException; +import java.util.List; +import java.util.Arrays; +import java.util.ArrayList; +import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.process.OutputAnalyzer; + +public class TestCodeEntryAlignment { + + public static void main(String[] args) throws IOException { + if (args.length == 0) { + driver(); + } else { + System.out.println("Pass"); + } + } + + private static List<String> cmdline(String[] args) { + List<String> r = new ArrayList(); + r.addAll(Arrays.asList(args)); + r.add("compiler.arguments.TestCodeEntryAlignment"); + r.add("run"); + return r; + } + + public static void shouldPass(String... args) throws IOException { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(cmdline(args)); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldHaveExitValue(0); + } + + public static void driver() throws IOException { + for (int align = 16; align < 256; align *= 2) { + shouldPass( + "-XX:+UnlockExperimentalVMOptions", + "-XX:CodeEntryAlignment=" + align + ); + } + for (int align = 256; align <= 1024; align *= 2) { + shouldPass( + "-XX:+UnlockExperimentalVMOptions", + "-XX:CodeCacheSegmentSize=" + align, + "-XX:CodeEntryAlignment=" + align + ); + } + } + +} diff --git a/test/hotspot/jtreg/compiler/arguments/TestOptoLoopAlignment.java b/test/hotspot/jtreg/compiler/arguments/TestOptoLoopAlignment.java new file mode 100644 index 0000000000000000000000000000000000000000..15f9bebc22994e4c5b8911edadd95c1ad9661dcf --- /dev/null +++ b/test/hotspot/jtreg/compiler/arguments/TestOptoLoopAlignment.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) 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. + */ + +/* + * @test + * @library /test/lib / + * @bug 8281467 + * @requires vm.flagless + * @requires os.arch=="amd64" | os.arch=="x86_64" + * + * @summary Test large OptoLoopAlignments are accepted + * @run driver compiler.arguments.TestOptoLoopAlignment + */ + +package compiler.arguments; + +import java.io.IOException; +import java.util.List; +import java.util.Arrays; +import java.util.ArrayList; +import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.process.OutputAnalyzer; + +public class TestOptoLoopAlignment { + + public static void main(String[] args) throws IOException { + if (args.length == 0) { + driver(); + } else { + System.out.println("Pass"); + } + } + + private static final String MSG = "must be less or equal to CodeEntryAlignment"; + + private static List<String> cmdline(String[] args) { + List<String> r = new ArrayList(); + r.addAll(Arrays.asList(args)); + r.add("compiler.arguments.TestOptoLoopAlignment"); + r.add("run"); + return r; + } + + public static void shouldFail(String... args) throws IOException { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(cmdline(args)); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldNotHaveExitValue(0); + output.shouldContain(MSG); + } + + public static void shouldPass(String... args) throws IOException { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(cmdline(args)); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldHaveExitValue(0); + output.shouldNotContain(MSG); + } + + public static void driver() throws IOException { + for (int align = 1; align < 64; align *= 2) { + shouldPass( + "-XX:OptoLoopAlignment=" + align + ); + } + for (int align = 64; align <= 128; align *= 2) { + shouldFail( + "-XX:OptoLoopAlignment=" + align + ); + } + } + +} diff --git a/test/hotspot/jtreg/compiler/arraycopy/TestArrayCopyAsLoadsStores.java b/test/hotspot/jtreg/compiler/arraycopy/TestArrayCopyAsLoadsStores.java index 4c4c38848d81dbd5ad257ae14091dde8ef2cc0c6..103e99fefefe395a8d12ae8c8c5f5ba493c0f376 100644 --- a/test/hotspot/jtreg/compiler/arraycopy/TestArrayCopyAsLoadsStores.java +++ b/test/hotspot/jtreg/compiler/arraycopy/TestArrayCopyAsLoadsStores.java @@ -38,6 +38,19 @@ * compiler.arraycopy.TestArrayCopyAsLoadsStores */ +/* + * @test + * @bug 8282590 + * @library / + * + * @run main/othervm -ea -XX:-BackgroundCompilation -XX:-UseOnStackReplacement + * -XX:CompileCommand=dontinline,compiler.arraycopy.TestArrayCopyAsLoadsStores::m* + * -XX:TypeProfileLevel=200 + * -XX:+IgnoreUnrecognizedVMOptions -XX:+StressArrayCopyMacroNode + * -XX:-TieredCompilation -XX:+StressReflectiveCode -XX:-ReduceInitialCardMarks + * compiler.arraycopy.TestArrayCopyAsLoadsStores + */ + package compiler.arraycopy; import java.util.Arrays; diff --git a/test/hotspot/jtreg/compiler/arraycopy/stress/AbstractStressArrayCopy.java b/test/hotspot/jtreg/compiler/arraycopy/stress/AbstractStressArrayCopy.java new file mode 100644 index 0000000000000000000000000000000000000000..f74c9b9cfcc6971a27325c56aff3387c2485f0a7 --- /dev/null +++ b/test/hotspot/jtreg/compiler/arraycopy/stress/AbstractStressArrayCopy.java @@ -0,0 +1,166 @@ +/* + * Copyright (c) 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. + */ + +package compiler.arraycopy.stress; + +import java.util.Random; + +public abstract class AbstractStressArrayCopy { + /** + * Max array size to test. This should be reasonably high to test + * massive vectorized copies, plus cases that cross the cache lines and + * (small) page boundaries. But it should also be reasonably low to + * keep the test costs down. + * + * A rough guideline: + * - AVX-512: 64-byte copies over 32 registers copies roughly 2K per step. + * - AArch64: small pages can be about 64K large + */ + static final int MAX_SIZE = 128*1024 + 1; + + /** + * Arrays up to this size would be tested exhaustively: with all combinations + * of source/destination starts and copy lengths. Exercise restraint when bumping + * this value, as the test costs are proportional to N^3 of this setting. + */ + static final int EXHAUSTIVE_SIZES = Integer.getInteger("exhaustiveSizes", 192); + + /* + * Larger arrays would fuzzed with this many attempts. + */ + static final int FUZZ_COUNT = Integer.getInteger("fuzzCount", 300); + + public static void throwSeedError(int len, int pos) { + throw new RuntimeException("Error after seed: " + + len + " elements, at pos " + pos); + } + + public static void throwContentsError(int l, int r, int len, int pos) { + throwError("in contents", l, r, len, pos); + } + + public static void throwHeadError(int l, int r, int len, int pos) { + throwError("in head", l, r, len, pos); + } + + public static void throwTailError(int l, int r, int len, int pos) { + throwError("in tail", l, r, len, pos); + } + + private static void throwError(String phase, int l, int r, int len, int pos) { + throw new RuntimeException("Error " + phase + ": " + + len + " elements, " + + "[" + l + ", " + (l+len) + ") -> " + + "[" + r + ", " + (r+len) + "), " + + "at pos " + pos); + } + + protected abstract void testWith(int size, int l, int r, int len); + + private void checkBounds(int size, int l, int r, int len) { + if (l >= size) throw new IllegalStateException("l is out of bounds"); + if (l + len > size) throw new IllegalStateException("l+len is out of bounds"); + if (r >= size) throw new IllegalStateException("r is out of bounds"); + if (r + len > size) throw new IllegalStateException("r+len is out of bounds: " + l + " " + r + " " + len + " " + size); + } + + private void checkDisjoint(int size, int l, int r, int len) { + if (l == r) throw new IllegalStateException("Not disjoint: l == r"); + if (l < r && l + len > r) throw new IllegalStateException("Not disjoint"); + if (l > r && r + len > l) throw new IllegalStateException("Not disjoint"); + } + + private void checkConjoint(int size, int l, int r, int len) { + if (l == r) return; // Definitely conjoint, even with zero len + if (l < r && l + len < r) throw new IllegalStateException("Not conjoint"); + if (l > r && r + len < l) throw new IllegalStateException("Not conjoint"); + } + + public void exhaustiveWith(int size) { + for (int l = 0; l < size; l++) { + for (int r = 0; r < size; r++) { + int maxLen = Math.min(size - l, size - r); + for (int len = 0; len <= maxLen; len++) { + checkBounds(size, l, r, len); + testWith(size, l, r, len); + } + } + } + } + + public void fuzzWith(Random rand, int size) { + // Some basic checks first + testWith(size, 0, 1, 1); + testWith(size, 0, 1, size-1); + + // Test disjoint: + for (int c = 0; c < FUZZ_COUNT; c++) { + int l = rand.nextInt(size / 2); + int len = rand.nextInt((size - l) / 2); + int r = (l + len + 1) + rand.nextInt(size - 2*len - l - 1); + + checkBounds(size, l, r, len); + checkDisjoint(size, l, r, len); + + testWith(size, l, r, len); + testWith(size, r, l, len); + } + + // Test conjoint: + for (int c = 0; c < FUZZ_COUNT; c++) { + int l = rand.nextInt(size); + int len = rand.nextInt(size - l); + int r = Math.min(l + (len > 0 ? rand.nextInt(len) : 0), size - len); + + checkBounds(size, l, r, len); + checkConjoint(size, l, r, len); + + testWith(size, l, r, len); + testWith(size, r, l, len); + } + } + + public void run(Random rand) { + // Exhaustive on all small arrays + for (int size = 1; size <= EXHAUSTIVE_SIZES; size++) { + exhaustiveWith(size); + } + + // Fuzz powers of ten + for (int size = 10; size < MAX_SIZE; size *= 10) { + if (size <= EXHAUSTIVE_SIZES) continue; + fuzzWith(rand, size - 1); + fuzzWith(rand, size); + fuzzWith(rand, size + 1); + } + + // Fuzz powers of two + for (int size = 2; size < MAX_SIZE; size *= 2) { + if (size <= EXHAUSTIVE_SIZES) continue; + fuzzWith(rand, size - 1); + fuzzWith(rand, size); + fuzzWith(rand, size + 1); + } + } + +} diff --git a/test/hotspot/jtreg/compiler/arraycopy/stress/StressBooleanArrayCopy.java b/test/hotspot/jtreg/compiler/arraycopy/stress/StressBooleanArrayCopy.java new file mode 100644 index 0000000000000000000000000000000000000000..bd424c393d85d751da3c88acc8f9d3ff292ffa2f --- /dev/null +++ b/test/hotspot/jtreg/compiler/arraycopy/stress/StressBooleanArrayCopy.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 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. + */ + +package compiler.arraycopy.stress; + +import java.util.Arrays; +import java.util.Random; +import jdk.test.lib.Utils; + +public class StressBooleanArrayCopy extends AbstractStressArrayCopy { + + private static final boolean[] orig = new boolean[MAX_SIZE]; + private static final boolean[] test = new boolean[MAX_SIZE]; + + protected void testWith(int size, int l, int r, int len) { + // Seed the test from the original + System.arraycopy(orig, 0, test, 0, size); + + // Check the seed is correct + { + int m = Arrays.mismatch(test, 0, size, + orig, 0, size); + if (m != -1) { + throwSeedError(size, m); + } + } + + // Perform the tested copy + System.arraycopy(test, l, test, r, len); + + // Check the copy has proper contents + { + int m = Arrays.mismatch(test, r, r+len, + orig, l, l+len); + if (m != -1) { + throwContentsError(l, r, len, r+m); + } + } + + // Check anything else was not affected: head and tail + { + int m = Arrays.mismatch(test, 0, r, + orig, 0, r); + if (m != -1) { + throwHeadError(l, r, len, m); + } + } + { + int m = Arrays.mismatch(test, r + len, size, + orig, r + len, size); + if (m != -1) { + throwTailError(l, r, len, m); + } + } + } + + public static void main(String... args) { + Random rand = Utils.getRandomInstance(); + for (int c = 0; c < orig.length; c++) { + orig[c] = rand.nextBoolean(); + } + new StressBooleanArrayCopy().run(rand); + } + +} diff --git a/test/hotspot/jtreg/compiler/arraycopy/stress/StressByteArrayCopy.java b/test/hotspot/jtreg/compiler/arraycopy/stress/StressByteArrayCopy.java new file mode 100644 index 0000000000000000000000000000000000000000..86d957bf2cb52f6a926cb4a998751046af0bf508 --- /dev/null +++ b/test/hotspot/jtreg/compiler/arraycopy/stress/StressByteArrayCopy.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 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. + */ + +package compiler.arraycopy.stress; + +import java.util.Arrays; +import java.util.Random; +import jdk.test.lib.Utils; + +public class StressByteArrayCopy extends AbstractStressArrayCopy { + + private static final byte[] orig = new byte[MAX_SIZE]; + private static final byte[] test = new byte[MAX_SIZE]; + + protected void testWith(int size, int l, int r, int len) { + // Seed the test from the original + System.arraycopy(orig, 0, test, 0, size); + + // Check the seed is correct + { + int m = Arrays.mismatch(test, 0, size, + orig, 0, size); + if (m != -1) { + throwSeedError(size, m); + } + } + + // Perform the tested copy + System.arraycopy(test, l, test, r, len); + + // Check the copy has proper contents + { + int m = Arrays.mismatch(test, r, r+len, + orig, l, l+len); + if (m != -1) { + throwContentsError(l, r, len, r+m); + } + } + + // Check anything else was not affected: head and tail + { + int m = Arrays.mismatch(test, 0, r, + orig, 0, r); + if (m != -1) { + throwHeadError(l, r, len, m); + } + } + { + int m = Arrays.mismatch(test, r + len, size, + orig, r + len, size); + if (m != -1) { + throwTailError(l, r, len, m); + } + } + } + + public static void main(String... args) { + Random rand = Utils.getRandomInstance(); + for (int c = 0; c < orig.length; c++) { + orig[c] = (byte)rand.nextInt(); + } + new StressByteArrayCopy().run(rand); + } + +} diff --git a/test/hotspot/jtreg/compiler/arraycopy/stress/StressCharArrayCopy.java b/test/hotspot/jtreg/compiler/arraycopy/stress/StressCharArrayCopy.java new file mode 100644 index 0000000000000000000000000000000000000000..0770f4aa4881c90d92696d4d8960ab4c8ce395f1 --- /dev/null +++ b/test/hotspot/jtreg/compiler/arraycopy/stress/StressCharArrayCopy.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 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. + */ + +package compiler.arraycopy.stress; + +import java.util.Arrays; +import java.util.Random; +import jdk.test.lib.Utils; + +public class StressCharArrayCopy extends AbstractStressArrayCopy { + + private static final char[] orig = new char[MAX_SIZE]; + private static final char[] test = new char[MAX_SIZE]; + + protected void testWith(int size, int l, int r, int len) { + // Seed the test from the original + System.arraycopy(orig, 0, test, 0, size); + + // Check the seed is correct + { + int m = Arrays.mismatch(test, 0, size, + orig, 0, size); + if (m != -1) { + throwSeedError(size, m); + } + } + + // Perform the tested copy + System.arraycopy(test, l, test, r, len); + + // Check the copy has proper contents + { + int m = Arrays.mismatch(test, r, r+len, + orig, l, l+len); + if (m != -1) { + throwContentsError(l, r, len, r+m); + } + } + + // Check anything else was not affected: head and tail + { + int m = Arrays.mismatch(test, 0, r, + orig, 0, r); + if (m != -1) { + throwHeadError(l, r, len, m); + } + } + { + int m = Arrays.mismatch(test, r + len, size, + orig, r + len, size); + if (m != -1) { + throwTailError(l, r, len, m); + } + } + } + + public static void main(String... args) { + Random rand = Utils.getRandomInstance(); + for (int c = 0; c < orig.length; c++) { + orig[c] = (char)rand.nextInt(); + } + new StressCharArrayCopy().run(rand); + } + +} diff --git a/test/hotspot/jtreg/compiler/arraycopy/stress/StressDoubleArrayCopy.java b/test/hotspot/jtreg/compiler/arraycopy/stress/StressDoubleArrayCopy.java new file mode 100644 index 0000000000000000000000000000000000000000..c0cb54ca9694e537e914cd10c3a861abf9b11055 --- /dev/null +++ b/test/hotspot/jtreg/compiler/arraycopy/stress/StressDoubleArrayCopy.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 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. + */ + +package compiler.arraycopy.stress; + +import java.util.Arrays; +import java.util.Random; +import jdk.test.lib.Utils; + +public class StressDoubleArrayCopy extends AbstractStressArrayCopy { + + private static final double[] orig = new double[MAX_SIZE]; + private static final double[] test = new double[MAX_SIZE]; + + protected void testWith(int size, int l, int r, int len) { + // Seed the test from the original + System.arraycopy(orig, 0, test, 0, size); + + // Check the seed is correct + { + int m = Arrays.mismatch(test, 0, size, + orig, 0, size); + if (m != -1) { + throwSeedError(size, m); + } + } + + // Perform the tested copy + System.arraycopy(test, l, test, r, len); + + // Check the copy has proper contents + { + int m = Arrays.mismatch(test, r, r+len, + orig, l, l+len); + if (m != -1) { + throwContentsError(l, r, len, r+m); + } + } + + // Check anything else was not affected: head and tail + { + int m = Arrays.mismatch(test, 0, r, + orig, 0, r); + if (m != -1) { + throwHeadError(l, r, len, m); + } + } + { + int m = Arrays.mismatch(test, r + len, size, + orig, r + len, size); + if (m != -1) { + throwTailError(l, r, len, m); + } + } + } + + public static void main(String... args) { + Random rand = Utils.getRandomInstance(); + for (int c = 0; c < orig.length; c++) { + orig[c] = rand.nextDouble(); + } + new StressDoubleArrayCopy().run(rand); + } + +} diff --git a/test/hotspot/jtreg/compiler/arraycopy/stress/StressFloatArrayCopy.java b/test/hotspot/jtreg/compiler/arraycopy/stress/StressFloatArrayCopy.java new file mode 100644 index 0000000000000000000000000000000000000000..d5c10570f373f4beed659f78b0edb3c587cd7bf3 --- /dev/null +++ b/test/hotspot/jtreg/compiler/arraycopy/stress/StressFloatArrayCopy.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 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. + */ + +package compiler.arraycopy.stress; + +import java.util.Arrays; +import java.util.Random; +import jdk.test.lib.Utils; + +public class StressFloatArrayCopy extends AbstractStressArrayCopy { + + private static final float[] orig = new float[MAX_SIZE]; + private static final float[] test = new float[MAX_SIZE]; + + protected void testWith(int size, int l, int r, int len) { + // Seed the test from the original + System.arraycopy(orig, 0, test, 0, size); + + // Check the seed is correct + { + int m = Arrays.mismatch(test, 0, size, + orig, 0, size); + if (m != -1) { + throwSeedError(size, m); + } + } + + // Perform the tested copy + System.arraycopy(test, l, test, r, len); + + // Check the copy has proper contents + { + int m = Arrays.mismatch(test, r, r+len, + orig, l, l+len); + if (m != -1) { + throwContentsError(l, r, len, r+m); + } + } + + // Check anything else was not affected: head and tail + { + int m = Arrays.mismatch(test, 0, r, + orig, 0, r); + if (m != -1) { + throwHeadError(l, r, len, m); + } + } + { + int m = Arrays.mismatch(test, r + len, size, + orig, r + len, size); + if (m != -1) { + throwTailError(l, r, len, m); + } + } + } + + public static void main(String... args) { + Random rand = Utils.getRandomInstance(); + for (int c = 0; c < orig.length; c++) { + orig[c] = rand.nextFloat(); + } + new StressFloatArrayCopy().run(rand); + } + +} diff --git a/test/hotspot/jtreg/compiler/arraycopy/stress/StressIntArrayCopy.java b/test/hotspot/jtreg/compiler/arraycopy/stress/StressIntArrayCopy.java new file mode 100644 index 0000000000000000000000000000000000000000..3cad6ce8793fce4c842d7a590b5f68a1e197ad17 --- /dev/null +++ b/test/hotspot/jtreg/compiler/arraycopy/stress/StressIntArrayCopy.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 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. + */ + +package compiler.arraycopy.stress; + +import java.util.Arrays; +import java.util.Random; +import jdk.test.lib.Utils; + +public class StressIntArrayCopy extends AbstractStressArrayCopy { + + private static final int[] orig = new int[MAX_SIZE]; + private static final int[] test = new int[MAX_SIZE]; + + protected void testWith(int size, int l, int r, int len) { + // Seed the test from the original + System.arraycopy(orig, 0, test, 0, size); + + // Check the seed is correct + { + int m = Arrays.mismatch(test, 0, size, + orig, 0, size); + if (m != -1) { + throwSeedError(size, m); + } + } + + // Perform the tested copy + System.arraycopy(test, l, test, r, len); + + // Check the copy has proper contents + { + int m = Arrays.mismatch(test, r, r+len, + orig, l, l+len); + if (m != -1) { + throwContentsError(l, r, len, r+m); + } + } + + // Check anything else was not affected: head and tail + { + int m = Arrays.mismatch(test, 0, r, + orig, 0, r); + if (m != -1) { + throwHeadError(l, r, len, m); + } + } + { + int m = Arrays.mismatch(test, r + len, size, + orig, r + len, size); + if (m != -1) { + throwTailError(l, r, len, m); + } + } + } + + public static void main(String... args) { + Random rand = Utils.getRandomInstance(); + for (int c = 0; c < orig.length; c++) { + orig[c] = rand.nextInt(); + } + new StressIntArrayCopy().run(rand); + } + +} diff --git a/test/hotspot/jtreg/compiler/arraycopy/stress/StressLongArrayCopy.java b/test/hotspot/jtreg/compiler/arraycopy/stress/StressLongArrayCopy.java new file mode 100644 index 0000000000000000000000000000000000000000..988e8ad56f9f02298abe3828b5c5ffe3cc708a2a --- /dev/null +++ b/test/hotspot/jtreg/compiler/arraycopy/stress/StressLongArrayCopy.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 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. + */ + +package compiler.arraycopy.stress; + +import java.util.Arrays; +import java.util.Random; +import jdk.test.lib.Utils; + +public class StressLongArrayCopy extends AbstractStressArrayCopy { + + private static final long[] orig = new long[MAX_SIZE]; + private static final long[] test = new long[MAX_SIZE]; + + protected void testWith(int size, int l, int r, int len) { + // Seed the test from the original + System.arraycopy(orig, 0, test, 0, size); + + // Check the seed is correct + { + int m = Arrays.mismatch(test, 0, size, + orig, 0, size); + if (m != -1) { + throwSeedError(size, m); + } + } + + // Perform the tested copy + System.arraycopy(test, l, test, r, len); + + // Check the copy has proper contents + { + int m = Arrays.mismatch(test, r, r+len, + orig, l, l+len); + if (m != -1) { + throwContentsError(l, r, len, r+m); + } + } + + // Check anything else was not affected: head and tail + { + int m = Arrays.mismatch(test, 0, r, + orig, 0, r); + if (m != -1) { + throwHeadError(l, r, len, m); + } + } + { + int m = Arrays.mismatch(test, r + len, size, + orig, r + len, size); + if (m != -1) { + throwTailError(l, r, len, m); + } + } + } + + public static void main(String... args) { + Random rand = Utils.getRandomInstance(); + for (int c = 0; c < orig.length; c++) { + orig[c] = rand.nextLong(); + } + new StressLongArrayCopy().run(rand); + } + +} diff --git a/test/hotspot/jtreg/compiler/arraycopy/stress/StressObjectArrayCopy.java b/test/hotspot/jtreg/compiler/arraycopy/stress/StressObjectArrayCopy.java new file mode 100644 index 0000000000000000000000000000000000000000..562daa4a820e21a8be2f8746c69f9438da2bce1a --- /dev/null +++ b/test/hotspot/jtreg/compiler/arraycopy/stress/StressObjectArrayCopy.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 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. + */ + +package compiler.arraycopy.stress; + +import java.util.Arrays; +import java.util.Random; +import jdk.test.lib.Utils; + +public class StressObjectArrayCopy extends AbstractStressArrayCopy { + + private static final Object[] orig = new Object[MAX_SIZE]; + private static final Object[] test = new Object[MAX_SIZE]; + + protected void testWith(int size, int l, int r, int len) { + // Seed the test from the original + System.arraycopy(orig, 0, test, 0, size); + + // Check the seed is correct + { + int m = Arrays.mismatch(test, 0, size, + orig, 0, size); + if (m != -1) { + throwSeedError(size, m); + } + } + + // Perform the tested copy + System.arraycopy(test, l, test, r, len); + + // Check the copy has proper contents + { + int m = Arrays.mismatch(test, r, r+len, + orig, l, l+len); + if (m != -1) { + throwContentsError(l, r, len, r+m); + } + } + + // Check anything else was not affected: head and tail + { + int m = Arrays.mismatch(test, 0, r, + orig, 0, r); + if (m != -1) { + throwHeadError(l, r, len, m); + } + } + { + int m = Arrays.mismatch(test, r + len, size, + orig, r + len, size); + if (m != -1) { + throwTailError(l, r, len, m); + } + } + } + + public static void main(String... args) { + Random rand = Utils.getRandomInstance(); + for (int c = 0; c < orig.length; c++) { + orig[c] = new Object(); + } + new StressObjectArrayCopy().run(rand); + } + +} diff --git a/test/hotspot/jtreg/compiler/arraycopy/stress/StressShortArrayCopy.java b/test/hotspot/jtreg/compiler/arraycopy/stress/StressShortArrayCopy.java new file mode 100644 index 0000000000000000000000000000000000000000..1594d54ca3653570f6a37211f9f71fe4942753ca --- /dev/null +++ b/test/hotspot/jtreg/compiler/arraycopy/stress/StressShortArrayCopy.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 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. + */ + +package compiler.arraycopy.stress; + +import java.util.Arrays; +import java.util.Random; +import jdk.test.lib.Utils; + +public class StressShortArrayCopy extends AbstractStressArrayCopy { + + private static final short[] orig = new short[MAX_SIZE]; + private static final short[] test = new short[MAX_SIZE]; + + protected void testWith(int size, int l, int r, int len) { + // Seed the test from the original + System.arraycopy(orig, 0, test, 0, size); + + // Check the seed is correct + { + int m = Arrays.mismatch(test, 0, size, + orig, 0, size); + if (m != -1) { + throwSeedError(size, m); + } + } + + // Perform the tested copy + System.arraycopy(test, l, test, r, len); + + // Check the copy has proper contents + { + int m = Arrays.mismatch(test, r, r+len, + orig, l, l+len); + if (m != -1) { + throwContentsError(l, r, len, r+m); + } + } + + // Check anything else was not affected: head and tail + { + int m = Arrays.mismatch(test, 0, r, + orig, 0, r); + if (m != -1) { + throwHeadError(l, r, len, m); + } + } + { + int m = Arrays.mismatch(test, r + len, size, + orig, r + len, size); + if (m != -1) { + throwTailError(l, r, len, m); + } + } + } + + public static void main(String... args) { + Random rand = Utils.getRandomInstance(); + for (int c = 0; c < orig.length; c++) { + orig[c] = (short)rand.nextInt(); + } + new StressShortArrayCopy().run(rand); + } + +} diff --git a/test/hotspot/jtreg/compiler/arraycopy/stress/TestStressArrayCopy.java b/test/hotspot/jtreg/compiler/arraycopy/stress/TestStressArrayCopy.java new file mode 100644 index 0000000000000000000000000000000000000000..5153f85c9d7099246f3638f11fc84a5304310825 --- /dev/null +++ b/test/hotspot/jtreg/compiler/arraycopy/stress/TestStressArrayCopy.java @@ -0,0 +1,217 @@ +/* + * Copyright (c) 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. + */ + +package compiler.arraycopy.stress; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +import jdk.test.lib.Platform; +import jdk.test.lib.Utils; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; + +import jdk.test.whitebox.cpuinfo.CPUInfo; + +/** + * @test + * @key stress randomness + * @library /test/lib + * @build compiler.arraycopy.stress.AbstractStressArrayCopy + * compiler.arraycopy.stress.StressBooleanArrayCopy + * compiler.arraycopy.stress.StressByteArrayCopy + * compiler.arraycopy.stress.StressCharArrayCopy + * compiler.arraycopy.stress.StressShortArrayCopy + * compiler.arraycopy.stress.StressIntArrayCopy + * compiler.arraycopy.stress.StressFloatArrayCopy + * compiler.arraycopy.stress.StressLongArrayCopy + * compiler.arraycopy.stress.StressDoubleArrayCopy + * compiler.arraycopy.stress.StressObjectArrayCopy + * jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * + * @run main/othervm/timeout=7200 + * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * compiler.arraycopy.stress.TestStressArrayCopy + */ +public class TestStressArrayCopy { + + // These tests are remarkably memory bandwidth hungry. Running multiple + // configs in parallel makes sense only when running a single test in + // isolation, and only on machines with many memory channels. In common + // testing, or even running all arraycopy stress tests at once, overloading + // the system with many configs become counter-productive very quickly. + // + // Default to 1/4 of the CPUs, and allow users to override. + static final int MAX_PARALLELISM = Integer.getInteger("maxParallelism", + Math.max(1, Runtime.getRuntime().availableProcessors() / 4)); + + private static List<String> mix(List<String> o, String... mix) { + List<String> n = new ArrayList<>(o); + for (String m : mix) { + n.add(m); + } + return n; + } + + private static List<List<String>> product(List<List<String>> list, String... mix) { + List<List<String>> newList = new ArrayList<>(); + for (List<String> c : list) { + for (String m : mix) { + newList.add(mix(c, m)); + } + } + return newList; + } + + private static List<List<String>> alternate(List<List<String>> list, String opt) { + return product(list, "-XX:+" + opt, "-XX:-" + opt); + } + + private static boolean containsFuzzy(List<String> list, String sub) { + for (String s : list) { + if (s.contains(sub)) return true; + } + return false; + } + + public static void main(String... args) throws Exception { + List<List<String>> configs = new ArrayList<>(); + List<String> cpuFeatures = CPUInfo.getFeatures(); + + if (Platform.isX64() || Platform.isX86()) { + // If CPU features were not found, provide a default config. + if (cpuFeatures.isEmpty()) { + configs.add(new ArrayList()); + } + + // Otherwise, select the tests that make sense on current platform. + if (containsFuzzy(cpuFeatures, "avx512")) { + configs.add(List.of("-XX:UseAVX=3")); + } + if (containsFuzzy(cpuFeatures, "avx2")) { + configs.add(List.of("-XX:UseAVX=2")); + } + if (containsFuzzy(cpuFeatures, "avx")) { + configs.add(List.of("-XX:UseAVX=1")); + } + if (containsFuzzy(cpuFeatures, "sse4")) { + configs.add(List.of("-XX:UseAVX=0", "-XX:UseSSE=4")); + } + if (containsFuzzy(cpuFeatures, "sse3")) { + configs.add(List.of("-XX:UseAVX=0", "-XX:UseSSE=3")); + } + if (containsFuzzy(cpuFeatures, "sse2")) { + configs.add(List.of("-XX:UseAVX=0", "-XX:UseSSE=2")); + } + + // x86_64 always has UseSSE >= 2. These lower configurations only + // make sense for x86_32. + if (Platform.isX86()) { + if (containsFuzzy(cpuFeatures, "sse")) { + configs.add(List.of("-XX:UseAVX=0", "-XX:UseSSE=1")); + } + + configs.add(List.of("-XX:UseAVX=0", "-XX:UseSSE=0")); + } + + // Alternate configs with other flags + if (Platform.isX64()) { + configs = alternate(configs, "UseCompressedOops"); + } + configs = alternate(configs, "UseUnalignedLoadStores"); + + } else if (Platform.isAArch64()) { + // AArch64. + configs.add(new ArrayList()); + + // Alternate configs with other flags + configs = alternate(configs, "UseCompressedOops"); + configs = alternate(configs, "UseSIMDForMemoryOps"); + } else { + // Generic config. + configs.add(new ArrayList()); + } + + String[] classNames = { + "compiler.arraycopy.stress.StressBooleanArrayCopy", + "compiler.arraycopy.stress.StressByteArrayCopy", + "compiler.arraycopy.stress.StressCharArrayCopy", + "compiler.arraycopy.stress.StressShortArrayCopy", + "compiler.arraycopy.stress.StressIntArrayCopy", + "compiler.arraycopy.stress.StressFloatArrayCopy", + "compiler.arraycopy.stress.StressLongArrayCopy", + "compiler.arraycopy.stress.StressDoubleArrayCopy", + "compiler.arraycopy.stress.StressObjectArrayCopy", + }; + + ArrayList<Fork> forks = new ArrayList<>(); + int jobs = 0; + + for (List<String> c : configs) { + for (String className : classNames) { + // Start a new job + { + ProcessBuilder pb = ProcessTools.createTestJvm(mix(c, "-Xmx256m", className)); + Process p = pb.start(); + OutputAnalyzer oa = new OutputAnalyzer(p); + forks.add(new Fork(p, oa)); + jobs++; + } + + // Wait for the completion of other jobs + while (jobs >= MAX_PARALLELISM) { + Fork f = findDone(forks); + if (f != null) { + OutputAnalyzer oa = f.oa(); + oa.shouldHaveExitValue(0); + forks.remove(f); + jobs--; + } else { + // Nothing is done, wait a little. + Thread.sleep(200); + } + } + } + } + + // Drain the rest + for (Fork f : forks) { + OutputAnalyzer oa = f.oa(); + oa.shouldHaveExitValue(0); + } + } + + private static Fork findDone(List<Fork> forks) { + for (Fork f : forks) { + if (!f.p().isAlive()) { + return f; + } + } + return null; + } + + private static record Fork(Process p, OutputAnalyzer oa) {}; + +} diff --git a/test/hotspot/jtreg/compiler/c1/Test8271202.java b/test/hotspot/jtreg/compiler/c1/Test8271202.java new file mode 100644 index 0000000000000000000000000000000000000000..e867e391114ddb4ed357e73e36c95c41488e3ccf --- /dev/null +++ b/test/hotspot/jtreg/compiler/c1/Test8271202.java @@ -0,0 +1,67 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8271202 + * @requires vm.debug == true & vm.compiler1.enabled + * @run main/othervm -Xbatch -XX:TieredStopAtLevel=1 -XX:+DeoptimizeALot + * Test8271202 + */ + +public class Test8271202 { + public static void main(String[] strArr) { + try { + test(); + } catch (Exception e) { + // Expected + } + } + + static void test() { + long l6 = 10L; + int counter = 0; + int i2, i26, i29, iArr[] = new int[400]; + boolean b3 = true; + for (int smallinvoc = 0; smallinvoc < 139; smallinvoc++) { + } + for (i2 = 13; i2 < 1000; i2++) { + for (i26 = 2; i26 < 114; l6 += 2) { + // Infinite loop + if (b3) { + for (i29 = 1; i29 < 2; i29++) { + try { + iArr[i26] = 0; + } catch (ArithmeticException a_e) { + } + } + } + counter++; + if (counter == 100000) { + throw new RuntimeException("expected"); + } + } + } + } +} + diff --git a/test/hotspot/jtreg/compiler/c1/Test8275337.java b/test/hotspot/jtreg/compiler/c1/Test8275337.java new file mode 100644 index 0000000000000000000000000000000000000000..5e7ab912e20c010f86b98eb5ce48f8a36e573b1f --- /dev/null +++ b/test/hotspot/jtreg/compiler/c1/Test8275337.java @@ -0,0 +1,65 @@ +/* + * 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. + */ +/* + * @test + * @bug 8275337 + * @run main/othervm -Xcomp -XX:TieredStopAtLevel=1 compiler.c1.Test8275337 + */ + + +package compiler.c1; + +public class Test8275337 { + public static final int N = 400; + + public static void mainTest() { + int iArr1[] = new int[N]; + float fArr1[][] = new float[N][N]; + + for (int i = 9; i < 171; i++) { + int z; + try { + z = i % i; + } catch (ArithmeticException a_e) {} + for (int j = 1; j < 155; ++j) { + fArr1[j - 1][i] -= 1; + iArr1[i - 1] = 1; + } + for (int j = 4; j < 155; j++) { + for (int k = 1; k < 2; ++k) { + iArr1[i - 1] += 1; + fArr1[k - 1][j] -= 2; + } + } + } + } + public static void main(String[] strArr) { + + try { + for (int i = 0; i < 10; i++) { + mainTest(); + } + } catch (Exception ex) { + } + } +} diff --git a/test/hotspot/jtreg/compiler/c1/TestC1PhiPlacementPathology.jasm b/test/hotspot/jtreg/compiler/c1/TestC1PhiPlacementPathology.jasm new file mode 100644 index 0000000000000000000000000000000000000000..c504a7bf3fcf56273802b99ec46d1354b6c859cd --- /dev/null +++ b/test/hotspot/jtreg/compiler/c1/TestC1PhiPlacementPathology.jasm @@ -0,0 +1,76 @@ +/* + * 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. + * + */ +super public class TestC1PhiPlacementPathology + version 62:0 +{ + public static volatile Field sideEffect:I; + + public Method "<init>":"()V" + stack 1 locals 1 + { + aload_0; + invokespecial Method java/lang/Object."<init>":"()V"; + return; + } + private static Method effect:"(I)V" + stack 2 locals 1 + { + getstatic Field sideEffect:"I"; + iload_0; + iadd; + putstatic Field sideEffect:"I"; + return; + } + public static Method test:"(I)V" + stack 2 locals 2 + { + iconst_0; + istore_1; + iload_0; + iconst_2; + irem; + ifne MODIFY_LOCAL; + iinc 1, 1; + goto LH2; + MODIFY_LOCAL: stack_frame_type append; + locals_map int; + iinc 1, 2; + iinc 0, 1; + goto LH1; + LH1: stack_frame_type same; + iinc 1, 1; + iload_1; + sipush 10000; + if_icmpge EXIT; + LH2: stack_frame_type same; + iinc 1, 1; + goto LH1; + EXIT: stack_frame_type same; + iload_1; + iload_0; + iadd; + invokestatic Method effect:"(I)V"; + return; + } +} // end Class TestC1PhiPlacementPathology diff --git a/test/jdk/sun/tools/jps/TestJpsHostName.java b/test/hotspot/jtreg/compiler/c1/TestC1PhiPlacementPathologyMain.java similarity index 60% rename from test/jdk/sun/tools/jps/TestJpsHostName.java rename to test/hotspot/jtreg/compiler/c1/TestC1PhiPlacementPathologyMain.java index 4ef9d91ac31b2907a17419aef22d517ce264392f..8edab2967665cbcc59cefa550e345165d30e1735 100644 --- a/test/jdk/sun/tools/jps/TestJpsHostName.java +++ b/test/hotspot/jtreg/compiler/c1/TestC1PhiPlacementPathologyMain.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. + * 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 @@ -21,26 +21,20 @@ * questions. */ -import jdk.test.lib.process.OutputAnalyzer; - /* * @test - * @bug 8251155 - * @summary Test host names starting with digits - * @library /test/lib - * @build JpsHelper - * @run driver TestJpsHostName + * @bug 8277447 + * @summary Test a pathological case for phi placement with an irreducible loop of a particular shape. + * + * @compile TestC1PhiPlacementPathology.jasm + * @run main/othervm -Xbatch -XX:CompileCommand=compileonly,TestC1PhiPlacementPathology::test + * -XX:CompilationMode=quick-only -XX:-UseOnStackReplacement TestC1PhiPlacementPathologyMain */ -public class TestJpsHostName { - public static void main(String[] args) throws Throwable { - testJpsHostName("12345"); - testJpsHostName("12345:37266"); +public class TestC1PhiPlacementPathologyMain { + public static void main(String[] args) { + for (int i = 0; i < 11000; i++) { + TestC1PhiPlacementPathology.test(0); + } } - - private static void testJpsHostName(String hostname) throws Exception { - OutputAnalyzer output = JpsHelper.jps(hostname); - output.shouldNotContain("Malformed Host Identifier: " + hostname); - } - } diff --git a/test/hotspot/jtreg/compiler/c2/TestCMoveInfiniteGVN.java b/test/hotspot/jtreg/compiler/c2/TestCMoveInfiniteGVN.java new file mode 100644 index 0000000000000000000000000000000000000000..50d9d02dea651ce3cd4e4edd2d1147293ae32c2c --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/TestCMoveInfiniteGVN.java @@ -0,0 +1,68 @@ +/* + * 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. + */ + +/* + * @test + * @key stress randomness + * @bug 8280123 + * @run main/othervm -Xcomp -XX:-TieredCompilation + * -XX:CompileCommand=compileonly,compiler.c2.TestCMoveInfiniteGVN::test + * -XX:+UnlockDiagnosticVMOptions -XX:+StressIGVN -XX:StressSeed=43739875 + * compiler.c2.TestCMoveInfiniteGVN + * @run main/othervm -Xcomp -XX:-TieredCompilation + * -XX:CompileCommand=compileonly,compiler.c2.TestCMoveInfiniteGVN::test + * -XX:+UnlockDiagnosticVMOptions -XX:+StressIGVN + * compiler.c2.TestCMoveInfiniteGVN + */ + +package compiler.c2; + +public class TestCMoveInfiniteGVN { + + static int test(boolean b, int i) { + int iArr[] = new int[2]; + + double d = Math.max(i, i); + for (int i1 = 1; i1 < 2; i1++) { + if (i1 != 0) { + return (b ? 1 : 0); // CMoveI + } + for (int i2 = 1; i2 < 2; i2++) { + switch (i2) { + case 1: d -= Math.max(i1, i2); break; + } + d -= iArr[i1 - 1]; + } + } + return 0; + } + + static void test() { + test(true, 234); + } + + public static void main(String[] strArr) { + test(); // compilation, then nmethod invalidation during execution + test(); // trigger crashing recompilation + } +} diff --git a/test/hotspot/jtreg/compiler/c2/TestModDivTopInput.java b/test/hotspot/jtreg/compiler/c2/TestModDivTopInput.java new file mode 100644 index 0000000000000000000000000000000000000000..9e4ba1dd6f0a14bcb2fcad9e369a4841b64d2752 --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/TestModDivTopInput.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 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. + */ + +/* + * @test + * @bug 8283451 + * @summary C2: assert(_base == Long) failed: Not a Long + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+StressLCM -XX:+StressGCM -XX:+StressCCP -XX:+StressIGVN + * -Xcomp -XX:CompileOnly=TestModDivTopInput -XX:-TieredCompilation -XX:StressSeed=87628618 TestModDivTopInput + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+StressLCM -XX:+StressGCM -XX:+StressCCP -XX:+StressIGVN + * -Xcomp -XX:CompileOnly=TestModDivTopInput -XX:-TieredCompilation TestModDivTopInput + */ + +public class TestModDivTopInput { + + public static final int N = 400; + + public static float fFld=-2.447F; + public long lFld=-189L; + + public void mainTest(String[] strArr1) { + + int i18, i20=-14, i21, iArr2[]=new int[N]; + boolean b2=true; + double d2; + long l; + + init(iArr2, -13265); + + for (i18 = 13; i18 < 315; ++i18) { + if (b2) continue; + for (d2 = 5; d2 < 83; d2++) { + } + for (i21 = 4; i21 < 83; i21++) { + for (l = 1; 2 > l; l++) { + } + b2 = b2; + lFld %= (i20 | 1); + i20 = (int)fFld; + i20 += (int)d2; + } + } + } + + public static void main(String[] strArr) { + TestModDivTopInput _instance = new TestModDivTopInput(); + for (int i = 0; i < 10; i++ ) { + _instance.mainTest(strArr); + } + } + + static void init(int[] arr, int v) { + for (int i = 0; i < arr.length; i++) { + arr[i] = v; + } + } + +} diff --git a/test/hotspot/jtreg/compiler/c2/TestSqrt.java b/test/hotspot/jtreg/compiler/c2/TestSqrt.java new file mode 100644 index 0000000000000000000000000000000000000000..9c4871569d77e4681d23aed75dff5f98a09dc5b4 --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/TestSqrt.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 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. + */ + +package compiler.c2; + +/* + * @test + * @bug 8279076 + * @summary SqrtD/SqrtF should be matched only on supported platforms + * @requires vm.debug + * + * @run main/othervm -XX:-TieredCompilation -Xcomp + * -XX:CompileOnly=compiler/c2/TestSqrt + * -XX:CompileOnly=java/lang/Math + * compiler.c2.TestSqrt + */ +public class TestSqrt { + static float srcF = 42.0f; + static double srcD = 42.0d; + static float dstF; + static double dstD; + + public static void test() { + dstF = (float)Math.sqrt((double)srcF); + dstD = Math.sqrt(srcD); + } + + public static void main(String args[]) { + for (int i = 0; i < 20_000; i++) { + test(); + } + } +} + diff --git a/test/hotspot/jtreg/compiler/c2/TestSubIdealC0Minus_YPlusC1_.java b/test/hotspot/jtreg/compiler/c2/TestSubIdealC0Minus_YPlusC1_.java new file mode 100644 index 0000000000000000000000000000000000000000..b623e1a2393fcec932f023f9d223f5d071a34235 --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/TestSubIdealC0Minus_YPlusC1_.java @@ -0,0 +1,133 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8277882 + * @summary New subnode ideal optimization: converting "c0 - (x + c1)" into "(c0 - c1) - x" + * @library /test/lib + * @run main/othervm -XX:-TieredCompilation -Xbatch + * -XX:CompileCommand=dontinline,compiler.c2.TestSubIdealC0Minus_YPlusC1_::test* + * -XX:CompileCommand=compileonly,compiler.c2.TestSubIdealC0Minus_YPlusC1_::test* + * compiler.c2.TestSubIdealC0Minus_YPlusC1_ + */ +package compiler.c2; + +import jdk.test.lib.Asserts; + +public class TestSubIdealC0Minus_YPlusC1_ { + + private static final int I_C0_0 = 1234; + private static final int I_C1 = 1234; + private static final int I_C0_1 = 4321; + + private static final long L_C0_0 = 123_456_789_123L; + private static final long L_C1 = 123_456_789_123L; + private static final long L_C0_1 = 654_321; + + public static int testIC0EqualsC1(int x) { + return I_C0_0 - (x + I_C1); + } + + public static long testLC0EqualsC1(long x) { + return L_C0_0 - (x + L_C1); + } + + public static int testIC0NotEqualsC1(int x) { + return I_C0_1 - (x + I_C1); + } + + public static long testLC0NotEqualsC1(long x) { + return L_C0_1 - (x + L_C1); + } + + public static int testIXPlusC1IsOverflow(int x) { + return Integer.MAX_VALUE - (x + Integer.MAX_VALUE); + } + + public static long testLXPlusC1IsOverflow(long x) { + return Long.MAX_VALUE - (x + Long.MAX_VALUE); + } + + public static int testIXPlusC1IsUnderflow(int x) { + return Integer.MIN_VALUE - (x + Integer.MIN_VALUE); + } + + public static long testLXPlusC1IsUnderflow(long x) { + return Long.MIN_VALUE - (x + Long.MIN_VALUE); + } + + public static int testIC0MinusC1IsOverflow(int x) { + return Integer.MAX_VALUE - (x + Integer.MIN_VALUE); + } + + public static long testLC0MinusC1IsOverflow(long x) { + return Long.MAX_VALUE - (x + Long.MIN_VALUE); + } + + public static int testIC0MinusC1IsUnderflow(int x) { + return Integer.MIN_VALUE - (x + Integer.MAX_VALUE); + } + + public static long testLC0MinusC1IsUnderflow(long x) { + return Long.MIN_VALUE - (x + Long.MAX_VALUE); + } + + public static int testIResultIsOverflow(int x) { + return 2147483637 - (x + 10); // Integer.MAX_VALUE == 2147483647 + } + + public static long testLResultIsOverflow(long x) { + return 9223372036854775797L - (x + 10); // Long.MAX_VALUE == 9223372036854775807 + } + + public static int testIResultIsUnderflow(int x) { + return -2147483637 - (x + 10); // Integer.MIN_VALUE == -2147483648 + } + + public static long testLResultIsUnderflow(long x) { + return -9223372036854775797L - (x + 10); // Long.MIN_VALUE == -9223372036854775808 + } + + public static void main(String... args) { + for (int i = 0; i < 50_000; i++) { + Asserts.assertTrue(testIC0EqualsC1(10) == -10); + Asserts.assertTrue(testIC0NotEqualsC1(100) == 2987); + Asserts.assertTrue(testIXPlusC1IsOverflow(10) == -10); + Asserts.assertTrue(testIXPlusC1IsUnderflow(-10) == 10); + Asserts.assertTrue(testIC0MinusC1IsOverflow(10) == -11); + Asserts.assertTrue(testIC0MinusC1IsUnderflow(10) == -9); + Asserts.assertTrue(testIResultIsOverflow(-21) == Integer.MIN_VALUE); + Asserts.assertTrue(testIResultIsUnderflow(2) == Integer.MAX_VALUE); + + Asserts.assertTrue(testLC0EqualsC1(10) == -10); + Asserts.assertTrue(testLC0NotEqualsC1(100) == -123456134902L); + Asserts.assertTrue(testLXPlusC1IsOverflow(10) == -10); + Asserts.assertTrue(testLXPlusC1IsUnderflow(-10) == 10); + Asserts.assertTrue(testLC0MinusC1IsOverflow(10) == -11); + Asserts.assertTrue(testLC0MinusC1IsUnderflow(10) == -9); + Asserts.assertTrue(testLResultIsOverflow(-21) == Long.MIN_VALUE); + Asserts.assertTrue(testLResultIsUnderflow(2) == Long.MAX_VALUE); + } + } +} diff --git a/test/hotspot/jtreg/compiler/c2/cr6865031/Test.java b/test/hotspot/jtreg/compiler/c2/cr6865031/Test.java index 71689eaca1843368ef1fc73b45a8aa4656045751..af23628577b0ecb98fcbaebddb0cb74693e457cb 100644 --- a/test/hotspot/jtreg/compiler/c2/cr6865031/Test.java +++ b/test/hotspot/jtreg/compiler/c2/cr6865031/Test.java @@ -1,5 +1,6 @@ /* * Copyright 2009 Goldman Sachs International. All Rights Reserved. + * Copyright (C) 2022 THL A29 Limited, a Tencent company. All rights reserved. * 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 +28,7 @@ * @bug 6865031 * @summary Application gives bad result (throws bad exception) with compressed oops * + * @requires vm.bits == 64 * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+UseCompressedOops * -XX:HeapBaseMinAddress=32g -XX:-LoopUnswitching * -XX:CompileCommand=inline,compiler.c2.cr6865031.AbstractMemoryEfficientList::equals diff --git a/test/hotspot/jtreg/compiler/c2/irTests/AddINodeIdealizationTests.java b/test/hotspot/jtreg/compiler/c2/irTests/AddINodeIdealizationTests.java new file mode 100644 index 0000000000000000000000000000000000000000..ede1f4e89c033c7697a597dde3ba20d28b7f2894 --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/irTests/AddINodeIdealizationTests.java @@ -0,0 +1,250 @@ +/* + * 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. + */ +package compiler.c2.irTests; + +import jdk.test.lib.Asserts; +import compiler.lib.ir_framework.*; + +/* + * @test + * @bug 8267265 + * @summary Test that Ideal transformations of AddINode* are being performed as expected. + * @library /test/lib / + * @run driver compiler.c2.irTests.AddINodeIdealizationTests + */ +public class AddINodeIdealizationTests { + public static void main(String[] args) { + TestFramework.run(); + } + + @Run(test = {"additions", "xMinusX", "test1", + "test2", "test3", "test4", + "test5", "test6", "test7", + "test8", "test9", "test10", + "test11", "test12", "test13", + "test14", "test15", "test16", + "test17", "test18", "test19"}) + public void runMethod() { + int a = RunInfo.getRandom().nextInt(); + int b = RunInfo.getRandom().nextInt(); + int c = RunInfo.getRandom().nextInt(); + int d = RunInfo.getRandom().nextInt(); + + int min = Integer.MIN_VALUE; + int max = Integer.MAX_VALUE; + + assertResult(0, 0, 0, 0); + assertResult(a, b, c, d); + assertResult(min, min, min, min); + assertResult(max, max, max, max); + } + + @DontCompile + public void assertResult(int a, int b, int c, int d) { + Asserts.assertEQ(((a+a) + (a+a)) , additions(a)); + Asserts.assertEQ(0 , xMinusX(a)); + Asserts.assertEQ(a + 1 + 2 , test1(a)); + Asserts.assertEQ((a + 2021) + b , test2(a, b)); + Asserts.assertEQ(a + (b + 2021) , test3(a, b)); + Asserts.assertEQ((1 - a) + 2 , test4(a)); + Asserts.assertEQ((a - b) + (c - d), test5(a, b, c, d)); + Asserts.assertEQ((a - b) + (b + c), test6(a, b, c)); + Asserts.assertEQ((a - b) + (c + b), test7(a, b, c)); + Asserts.assertEQ((a - b) + (b - c), test8(a, b, c)); + Asserts.assertEQ((a - b) + (c - a), test9(a, b, c)); + Asserts.assertEQ(a + (0 - b) , test10(a, b)); + Asserts.assertEQ((0 - b) + a , test11(a, b)); + Asserts.assertEQ((a - b) + b , test12(a, b)); + Asserts.assertEQ(b + (a - b) , test13(a, b)); + Asserts.assertEQ(a + 0 , test14(a)); + Asserts.assertEQ(0 + a , test15(a)); + Asserts.assertEQ(a*b + a*c , test16(a, b, c)); + Asserts.assertEQ(a*b + b*c , test17(a, b, c)); + Asserts.assertEQ(a*c + b*c , test18(a, b, c)); + Asserts.assertEQ(a*b + c*a , test19(a, b, c)); + } + + @Test + @IR(counts = {IRNode.ADD, "2"}) + // Checks (x + x) + (x + x) => a=(x + x); r=a+a + public int additions(int x) { + return (x + x) + (x + x); + } + + @Test + @IR(failOn = {IRNode.ADD, IRNode.SUB}) + // Checks (x - x) + (x - x) => 0 + public int xMinusX(int x) { + return (x - x) + (x - x); + } + + @Test + @IR(counts = {IRNode.ADD, "1"}) + // Checks (x + c1) + c2 => x + c3 where c3 = c1 + c2 + public int test1(int x) { + return (x + 1) + 2; + } + + @Test + @IR(counts = {IRNode.ADD, "2"}) + // Checks (x + c1) + y => (x + y) + c1 + public int test2(int x, int y) { + return (x + 2021) + y; + } + + @Test + @IR(counts = {IRNode.ADD, "2"}) + // Checks x + (y + c1) => (x + y) + c1 + public int test3(int x, int y) { + return x + (y + 2021); + } + + @Test + @IR(failOn = {IRNode.ADD}) + @IR(counts = {IRNode.SUB, "1"}) + // Checks (c1 - x) + c2 => c3 - x where c3 = c1 + c2 + public int test4(int x) { + return (1 - x) + 2; + } + + @Test + @IR(counts = {IRNode.SUB, "1", + IRNode.ADD, "2", + }) + // Checks (a - b) + (c - d) => (a + c) - (b + d) + public int test5(int a, int b, int c, int d) { + return (a - b) + (c - d); + } + + @Test + @IR(failOn = {IRNode.SUB}) + @IR(counts = {IRNode.ADD, "1"}) + // Checks (a - b) + (b + c) => (a + c) + public int test6(int a, int b, int c) { + return (a - b) + (b + c); + } + + @Test + @IR(failOn = {IRNode.SUB}) + @IR(counts = {IRNode.ADD, "1"}) + // Checks (a - b) + (c + b) => (a + c) + public int test7(int a, int b, int c) { + return (a - b) + (c + b); + } + + @Test + @IR(failOn = {IRNode.ADD}) + @IR(counts = {IRNode.SUB, "1"}) + // Checks (a - b) + (b - c) => (a - c) + public int test8(int a, int b, int c) { + return (a - b) + (b - c); + } + + @Test + @IR(failOn = {IRNode.ADD}) + @IR(counts = {IRNode.SUB, "1"}) + // Checks (a - b) + (c - a) => (c - b) + public int test9(int a, int b, int c) { + return (a - b) + (c - a); + } + + @Test + @IR(failOn = {IRNode.ADD}) + @IR(counts = {IRNode.SUB, "1"}) + // Checks x + (0 - y) => (x - y) + public int test10(int x, int y) { + return x + (0 - y); + } + + @Test + @IR(failOn = {IRNode.ADD}) + @IR(counts = {IRNode.SUB, "1"}) + // Checks (0 - y) + x => (x - y) + public int test11(int x, int y) { + return (0 - y) + x; + } + + @Test + @IR(failOn = {IRNode.ADD, IRNode.SUB}) + // Checks (x - y) + y => x + public int test12(int x, int y) { + return (x - y) + y; + } + + @Test + @IR(failOn = {IRNode.ADD, IRNode.SUB}) + // Checks y + (x - y) => x + public int test13(int x, int y) { + return y + (x - y); + } + + @Test + @IR(failOn = {IRNode.ADD}) + // Checks x + 0 => x + public int test14(int x) { + return x + 0; + } + + @Test + @IR(failOn = {IRNode.ADD}) + // Checks 0 + x => x + public int test15(int x) { + return 0 + x; + } + + @Test + @IR(counts = {IRNode.MUL, "1", + IRNode.ADD, "1" + }) + // Checks "a*b + a*c => a*(b+c) + public int test16(int a, int b, int c) { + return a*b + a*c; + } + + @Test + @IR(counts = {IRNode.MUL, "1", + IRNode.ADD, "1" + }) + // Checks a*b + b*c => b*(a+c) + public int test17(int a, int b, int c) { + return a*b + b*c; + } + + @Test + @IR(counts = {IRNode.MUL, "1", + IRNode.ADD, "1" + }) + // Checks a*c + b*c => (a+b)*c + public int test18(int a, int b, int c) { + return a*c + b*c; + } + + @Test + @IR(counts = {IRNode.MUL, "1", + IRNode.ADD, "1" + }) + // Checks a*b + c*a => a*(b+c) + public int test19(int a, int b, int c) { + return a*b + c*a; + } +} diff --git a/test/hotspot/jtreg/compiler/c2/irTests/AddLNodeIdealizationTests.java b/test/hotspot/jtreg/compiler/c2/irTests/AddLNodeIdealizationTests.java new file mode 100644 index 0000000000000000000000000000000000000000..6ea1cf6a2629868c427524db83a5464005a5ccfd --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/irTests/AddLNodeIdealizationTests.java @@ -0,0 +1,241 @@ +/* + * 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. + */ +package compiler.c2.irTests; + +import jdk.test.lib.Asserts; +import compiler.lib.ir_framework.*; + +/* + * @test + * @bug 8267265 + * @summary Test that Ideal transformations of AddLNode* are being performed as expected. + * @library /test/lib / + * @run driver compiler.c2.irTests.AddLNodeIdealizationTests + */ +public class AddLNodeIdealizationTests { + public static void main(String[] args) { + TestFramework.run(); + } + + @Run(test = {"additions", "xMinusX", "test1", + "test2", "test3", "test4", + "test5", "test6", "test7", + "test8", "test9", "test10", + "test11", "test12", "test13", + "test14", "test15", "test16", + "test17", "test18"}) + public void runMethod() { + long a = RunInfo.getRandom().nextLong(); + long b = RunInfo.getRandom().nextLong(); + long c = RunInfo.getRandom().nextLong(); + long d = RunInfo.getRandom().nextLong(); + + long min = Long.MIN_VALUE; + long max = Long.MAX_VALUE; + + assertResult(0, 0, 0, 0); + assertResult(a, b, c, d); + assertResult(min, min, min, min); + assertResult(max, max, max, max); + } + + @DontCompile + public void assertResult(long a, long b, long c, long d) { + Asserts.assertEQ(((a+a) + (a+a)) , additions(a)); + Asserts.assertEQ(0L , xMinusX(a)); + Asserts.assertEQ(a + 1 + 2 , test1(a)); + Asserts.assertEQ((a + 2021) + b , test2(a, b)); + Asserts.assertEQ(a + (b + 2021) , test3(a, b)); + Asserts.assertEQ((1 - a) + 2 , test4(a)); + Asserts.assertEQ((a - b) + (c - d), test5(a, b, c, d)); + Asserts.assertEQ((a - b) + (b + c), test6(a, b, c)); + Asserts.assertEQ((a - b) + (c + b), test7(a, b, c)); + Asserts.assertEQ((a - b) + (c - a), test8(a, b, c)); + Asserts.assertEQ(a + (0 - b) , test9(a, b)); + Asserts.assertEQ((0 - b) + a , test10(a, b)); + Asserts.assertEQ((a - b) + b , test11(a, b)); + Asserts.assertEQ(b + (a - b) , test12(a, b)); + Asserts.assertEQ(a + 0 , test13(a)); + Asserts.assertEQ(0 + a , test14(a)); + Asserts.assertEQ(a*b + a*c , test15(a, b, c)); + Asserts.assertEQ(a*b + b*c , test16(a, b, c)); + Asserts.assertEQ(a*c + b*c , test17(a, b, c)); + Asserts.assertEQ(a*b + c*a , test18(a, b, c)); + } + + @Test + @IR(counts = {IRNode.ADD, "2"}) + // Checks (x + x) + (x + x) => a=(x + x); r=a+a + public long additions(long x) { + return (x + x) + (x + x); + } + + @Test + @IR(failOn = {IRNode.ADD, IRNode.SUB}) + // Checks (x - x) => 0 and 0 - 0 => 0 + public long xMinusX(long x) { + return (x - x) + (x - x); + } + + @Test + @IR(counts = {IRNode.ADD, "1"}) + // Checks (x + c1) + c2 => x + c3 where c3 = c1 + c2 + public long test1(long x) { + return (x + 1) + 2; + } + + @Test + @IR(counts = {IRNode.ADD, "2"}) + // Checks (x + c1) + y => (x + y) + c1 + public long test2(long x, long y) { + return (x + 2021) + y; + } + + @Test + @IR(counts = {IRNode.ADD, "2"}) + // Checks x + (y + c1) => (x + y) + c1 + public long test3(long x, long y) { + return x + (y + 2021); + } + + @Test + @IR(failOn = {IRNode.ADD}) + @IR(counts = {IRNode.SUB, "1"}) + // Checks (c1 - x) + c2 => c3 - x where c3 = c1 + c2 + public long test4(long x) { + return (1 - x) + 2; + } + + @Test + @IR(counts = {IRNode.SUB, "1", + IRNode.ADD, "2", + }) + // Checks (a - b) + (c - d) => (a + c) - (b + d) + public long test5(long a, long b, long c, long d) { + return (a - b) + (c - d); + } + + @Test + @IR(failOn = {IRNode.SUB}) + @IR(counts = {IRNode.ADD, "1"}) + // Checks (a - b) + (b + c) => (a + c) + public long test6(long a, long b, long c) { + return (a - b) + (b + c); + } + + @Test + @IR(failOn = {IRNode.SUB}) + @IR(counts = {IRNode.ADD, "1"}) + // Checks (a - b) + (c + b) => (a + c) + public long test7(long a, long b, long c) { + return (a - b) + (c + b); + } + + @Test + @IR(failOn = {IRNode.ADD}) + @IR(counts = {IRNode.SUB, "1"}) + // Checks (a - b) + (c - a) => (c - b) + public long test8(long a, long b, long c) { + return (a - b) + (c - a); + } + + @Test + @IR(failOn = {IRNode.ADD}) + @IR(counts = {IRNode.SUB, "1"}) + // Checks x + (0 - y) => (x - y) + public long test9(long x, long y) { + return x + (0 - y); + } + + @Test + @IR(failOn = {IRNode.ADD}) + @IR(counts = {IRNode.SUB, "1"}) + // Checks (0 - y) + x => (x - y) + public long test10(long x, long y) { + return (0 - y) + x; + } + + @Test + @IR(failOn = {IRNode.ADD, IRNode.SUB}) + // Checks (x - y) + y => x + public long test11(long x, long y) { + return (x - y) + y; + } + + @Test + @IR(failOn = {IRNode.ADD, IRNode.SUB}) + // Checks y + (x - y) => x + public long test12(long x, long y) { + return y + (x - y); + } + + @Test + @IR(failOn = {IRNode.ADD}) + // Checks x + 0 => x + public long test13(long x) { + return x + 0; + } + + @Test + @IR(failOn = {IRNode.ADD}) + // Checks 0 + x => x + public long test14(long x) { + return 0 + x; + } + + @Test + @IR(counts = {IRNode.MUL, "1", + IRNode.ADD, "1" + }) + // Checks "a*b + a*c => a*(b+c) + public long test15(long a, long b, long c) { + return a*b + a*c; + } + + @Test + @IR(counts = {IRNode.MUL, "1", + IRNode.ADD, "1" + }) + // Checks a*b + b*c => b*(a+c) + public long test16(long a, long b, long c) { + return a*b + b*c; + } + + @Test + @IR(counts = {IRNode.MUL, "1", + IRNode.ADD, "1" + }) + // Checks a*c + b*c => (a+b)*c + public long test17(long a, long b, long c) { + return a*c + b*c; + } + + @Test + @IR(counts = {IRNode.MUL, "1", + IRNode.ADD, "1" + }) + // Checks a*b + c*a => a*(b+c) + public long test18(long a, long b, long c) { + return a*b + c*a; + } +} diff --git a/test/hotspot/jtreg/compiler/c2/irTests/DivINodeIdealizationTests.java b/test/hotspot/jtreg/compiler/c2/irTests/DivINodeIdealizationTests.java new file mode 100644 index 0000000000000000000000000000000000000000..1fd38bbae90eb08e27949e0cfea5df6525234466 --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/irTests/DivINodeIdealizationTests.java @@ -0,0 +1,205 @@ +/* + * 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. + */ +package compiler.c2.irTests; + +import jdk.test.lib.Asserts; +import compiler.lib.ir_framework.*; + +/* + * @test + * @bug 8267265 + * @summary Test that Ideal transformations of DivINode* are being performed as expected. + * @library /test/lib / + * @run driver compiler.c2.irTests.DivINodeIdealizationTests + */ +public class DivINodeIdealizationTests { + public static void main(String[] args) { + TestFramework.run(); + } + + @Run(test = {"constant", "identity", "identityAgain", "identityThird", + "retainDenominator", "divByNegOne", "divByPow2And", + "divByPow2And1", "divByPow2", "divByNegPow2", + "magicDiv"}) + public void runMethod() { + int a = RunInfo.getRandom().nextInt(); + a = (a == 0) ? 1 : a; + int b = RunInfo.getRandom().nextInt(); + b = (b == 0) ? 1 : b; + + int min = Integer.MIN_VALUE; + int max = Integer.MAX_VALUE; + + assertResult(0, 0, true); + assertResult(a, b, false); + assertResult(min, min, false); + assertResult(max, max, false); + } + + @DontCompile + public void assertResult(int a, int b, boolean shouldThrow) { + try { + Asserts.assertEQ(a / a, constant(a)); + Asserts.assertFalse(shouldThrow, "Expected an exception to be thrown."); + } + catch (ArithmeticException e) { + Asserts.assertTrue(shouldThrow, "Did not expected an exception to be thrown."); + } + + try { + Asserts.assertEQ(a / (b / b), identityThird(a, b)); + Asserts.assertFalse(shouldThrow, "Expected an exception to be thrown."); + } + catch (ArithmeticException e) { + Asserts.assertTrue(shouldThrow, "Did not expected an exception to be thrown."); + } + + try { + Asserts.assertEQ((a * b) / b, retainDenominator(a, b)); + Asserts.assertFalse(shouldThrow, "Expected an exception to be thrown."); + } + catch (ArithmeticException e) { + Asserts.assertTrue(shouldThrow, "Did not expected an exception to be thrown."); + } + + Asserts.assertEQ(a / 1 , identity(a)); + Asserts.assertEQ(a / (13 / 13), identityAgain(a)); + Asserts.assertEQ(a / -1 , divByNegOne(a)); + Asserts.assertEQ((a & -4) / 2 , divByPow2And(a)); + Asserts.assertEQ((a & -2) / 2 , divByPow2And1(a)); + Asserts.assertEQ(a / 8 , divByPow2(a)); + Asserts.assertEQ(a / -8 , divByNegPow2(a)); + Asserts.assertEQ(a / 13 , magicDiv(a)); + } + + @Test + @IR(failOn = {IRNode.DIV}) + @IR(counts = {IRNode.DIV_BY_ZERO_TRAP, "1"}) + // Checks x / x => 1 + public int constant(int x) { + return x / x; + } + + @Test + @IR(failOn = {IRNode.DIV}) + // Checks x / 1 => x + public int identity(int x) { + return x / 1; + } + + @Test + @IR(failOn = {IRNode.DIV}) + // Checks x / (c / c) => x + public int identityAgain(int x) { + return x / (13 / 13); + } + + @Test + @IR(failOn = {IRNode.DIV}) + @IR(counts = {IRNode.DIV_BY_ZERO_TRAP, "1"}) + // Checks x / (y / y) => x + public int identityThird(int x, int y) { + return x / (y / y); + } + + @Test + @IR(counts = {IRNode.MUL, "1", + IRNode.DIV, "1", + IRNode.DIV_BY_ZERO_TRAP, "1" + }) + // Hotspot should keep the division because it may cause a division by zero trap + public int retainDenominator(int x, int y) { + return (x * y) / y; + } + + @Test + @IR(failOn = {IRNode.DIV}) + @IR(counts = {IRNode.SUB_I, "1"}) + // Checks x / -1 => 0 - x + public int divByNegOne(int x) { + return x / -1; + } + + @Test + @IR(failOn = {IRNode.DIV}) + @IR(counts = {IRNode.AND, "1", + IRNode.RSHIFT, "1", + }) + // Checks (x & -(2^c0)) / 2^c1 => (x >> c1) & (2^c0 >> c1) => (x >> c1) & c3 where 2^c0 > |2^c1| "AND" c3 = 2^c0 >> c1 + // Having a large enough and in the dividend removes the need to account for rounding when converting to shifts and multiplies as in divByPow2() + public int divByPow2And(int x) { + return (x & -4) / 2; + } + + @Test + @IR(failOn = {IRNode.DIV, IRNode.AND}) + @IR(counts = {IRNode.RSHIFT, "1"}) + // Checks (x & -(2^c0)) / 2^c0 => x >> c0 + // If the negative of the constant within the & equals the divisor then the and can be removed as it only affects bits that will be shifted off + public int divByPow2And1(int x) { + return (x & -2) / 2; + } + + @Test + @IR(failOn = {IRNode.DIV}) + @IR(counts = {IRNode.URSHIFT, "1", + IRNode.RSHIFT, "2", + IRNode.ADD_I, "1", + }) + // Checks x / 2^c0 => x + ((x >> (32-1)) >>> (32 - c0)) >> c0 => x + ((x >> 31) >>> c1) >> c0 where c1 = 32 - c0 + // An additional (dividend - 1) needs to be added to the shift to account for rounding when dealing with negative numbers. + // Since x may be negative in this method, an additional add, logical right shift, and signed shift are needed to account for rounding. + public int divByPow2(int x) { + return x / 8; + } + + @Test + @IR(failOn = {IRNode.DIV}) + @IR(counts = {IRNode.URSHIFT, "1", + IRNode.RSHIFT, "2", + IRNode.ADD_I, "1", + IRNode.SUB_I, "1", + }) + // Checks x / -(2^c0) =>0 - (x + ((x >> (32-1)) >>> (32 - c0)) >> c0) => 0 - (x + ((x >> 31) >>> c1) >> c0) where c1 = 32 - c0 + // Similar to divByPow2() except a negative divisor turns positive. + // After the transformations, 0 is subtracted by the whole expression + // to account for the negative. + public int divByNegPow2(int x) { + return x / -8; + } + + @Test + @IR(failOn = {IRNode.DIV}) + @IR(counts = {IRNode.SUB, "1", + IRNode.MUL, "1", + IRNode.CONV_I2L, "1", + IRNode.CONV_L2I, "1", + }) + // Checks magic int division occurs in general when dividing by a non power of 2. + // More tests can be made to cover the specific cases for differences in the + // graph that depend upon different values for the "magic constant" and the + // "shift constant" + public int magicDiv(int x) { + return x / 13; + } +} diff --git a/test/hotspot/jtreg/compiler/c2/irTests/DivLNodeIdealizationTests.java b/test/hotspot/jtreg/compiler/c2/irTests/DivLNodeIdealizationTests.java new file mode 100644 index 0000000000000000000000000000000000000000..452b90066375581dda0281795c5ec226d36bf32d --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/irTests/DivLNodeIdealizationTests.java @@ -0,0 +1,190 @@ +/* + * 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. + */ +package compiler.c2.irTests; + +import jdk.test.lib.Asserts; +import compiler.lib.ir_framework.*; + +/* + * @test + * @bug 8267265 + * @summary Test that Ideal transformations of DivLNode* are being performed as expected. + * @library /test/lib / + * @run driver compiler.c2.irTests.DivLNodeIdealizationTests + */ +public class DivLNodeIdealizationTests { + public static void main(String[] args) { + TestFramework.run(); + } + + @Run(test = {"constant", "identity", "identityAgain", "identityThird", + "retainDenominator", "divByNegOne", "divByPow2And", + "divByPow2And1", "divByPow2", "divByNegPow2"}) + public void runMethod() { + long a = RunInfo.getRandom().nextLong(); + a = (a == 0) ? 1 : a; + long b = RunInfo.getRandom().nextLong(); + b = (b == 0) ? 1 : b; + + long min = Long.MIN_VALUE; + long max = Long.MAX_VALUE; + + assertResult(0, 0, true); + assertResult(a, b, false); + assertResult(min, min, false); + assertResult(max, max, false); + } + + @DontCompile + public void assertResult(long a, long b, boolean shouldThrow) { + try { + Asserts.assertEQ(a / a, constant(a)); + Asserts.assertFalse(shouldThrow, "Expected an exception to be thrown."); + } + catch (ArithmeticException e) { + Asserts.assertTrue(shouldThrow, "Did not expected an exception to be thrown."); + } + + try { + Asserts.assertEQ((a * b) / b, retainDenominator(a, b)); + Asserts.assertFalse(shouldThrow, "Expected an exception to be thrown."); + } + catch (ArithmeticException e) { + Asserts.assertTrue(shouldThrow, "Did not expected an exception to be thrown."); + } + + try { + Asserts.assertEQ(a / (b / b), identityThird(a, b)); + Asserts.assertFalse(shouldThrow, "Expected an exception to be thrown."); + } + catch (ArithmeticException e) { + Asserts.assertTrue(shouldThrow, "Did not expected an exception to be thrown."); + } + + Asserts.assertEQ(a / 1 , identity(a)); + Asserts.assertEQ(a / (13 / 13), identityAgain(a)); + Asserts.assertEQ(a / -1 , divByNegOne(a)); + Asserts.assertEQ((a & -4) / 2 , divByPow2And(a)); + Asserts.assertEQ((a & -2) / 2 , divByPow2And1(a)); + Asserts.assertEQ(a / 8 , divByPow2(a)); + Asserts.assertEQ(a / -8 , divByNegPow2(a)); + } + + @Test + @IR(failOn = {IRNode.DIV}) + @IR(counts = {IRNode.DIV_BY_ZERO_TRAP, "1"}) + // Checks x / x => 1 + public long constant(long x) { + return x / x; + } + + @Test + @IR(failOn = {IRNode.DIV}) + // Checks x / 1 => x + public long identity(long x) { + return x / 1L; + } + + @Test + @IR(failOn = {IRNode.DIV}) + // Checks x / (c / c) => x + public long identityAgain(long x) { + return x / (13L / 13L); + } + + @Test + @IR(failOn = {IRNode.DIV}) + @IR(counts = {IRNode.DIV_BY_ZERO_TRAP, "1"}) + // Checks x / (y / y) => x + public long identityThird(long x, long y) { + return x / (y / y); + } + + @Test + @IR(counts = {IRNode.MUL_L, "1", + IRNode.DIV_L, "1", + IRNode.DIV_BY_ZERO_TRAP, "1" + }) + // Hotspot should keep the division because it may cause a division by zero trap + public long retainDenominator(long x, long y) { + return (x * y) / y; + } + + @Test + @IR(failOn = {IRNode.DIV}) + @IR(counts = {IRNode.SUB, "1"}) + // Checks x / -1 => 0 - x + public long divByNegOne(long x) { + return x / -1L; + } + + @Test + @IR(failOn = {IRNode.DIV}) + @IR(counts = {IRNode.AND, "1", + IRNode.RSHIFT, "1", + }) + // Checks (x & -(2^c0)) / 2^c1 => (x >> c1) & (2^c0 >> c1) => (x >> c1) & c3 where 2^c0 > |2^c1| "and" c3 = 2^c0 >> c1 + // Having a large enough and in the dividend removes the need to account for + // rounding when converting to shifts and multiplies as in divByPow2() + public long divByPow2And(long x) { + return (x & -4L) / 2L; + } + + @Test + @IR(failOn = {IRNode.DIV, IRNode.AND}) + @IR(counts = {IRNode.RSHIFT, "1"}) + // Checks (x & -(2^c0)) / 2^c0 => x >> c0 + // If the negative of the constant within the & equals the divisor then + // the and can be removed as it only affects bits that will be shifted off + public long divByPow2And1(long x) { + return (x & -2L) / 2L; + } + + @Test + @IR(failOn = {IRNode.DIV}) + @IR(counts = {IRNode.URSHIFT, "1", + IRNode.RSHIFT, "2", + IRNode.ADD, "1", + }) + // Checks x / 2^c0 => x + ((x >>)ith negative numbers. Since x may be negative + // in this method, an additional add, logical right shift, and signed shift + // are needed to account for rounding. + public long divByPow2(long x) { + return x / 8L; + } + + @Test + @IR(failOn = {IRNode.DIV}) + @IR(counts = {IRNode.URSHIFT, "1", + IRNode.RSHIFT, "2", + IRNode.ADD, "1", + IRNode.SUB, "1", + }) + // Checks x / -(2^c0) =>0 - (x + ((x >> (32-1)) >>> (32 - c0)) >> c0) => 0 - (x + ((x >> 31) >>> c1) >> c0) where c1 = 32 - c0 + // Similar to divByPow2() except a negative divisor turns positive. + // After the transformations, 0 is subtracted by the whole expression + // to account for the negative. + public long divByNegPow2(long x) { + return x / -8L; + } +} diff --git a/test/hotspot/jtreg/compiler/c2/irTests/MulINodeIdealizationTests.java b/test/hotspot/jtreg/compiler/c2/irTests/MulINodeIdealizationTests.java new file mode 100644 index 0000000000000000000000000000000000000000..233efe84a0462fd18a66ce59220adca918538784 --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/irTests/MulINodeIdealizationTests.java @@ -0,0 +1,166 @@ +/* + * 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. + */ +package compiler.c2.irTests; + +import jdk.test.lib.Asserts; +import compiler.lib.ir_framework.*; + +/* + * @test + * @bug 8267265 + * @summary Test that Ideal transformations of MulINode* are being performed as expected. + * @library /test/lib / + * @run driver compiler.c2.irTests.MulINodeIdealizationTests + */ +public class MulINodeIdealizationTests { + public static void main(String[] args) { + TestFramework.run(); + } + + @Run(test = {"combineConstants", "moveConstants", "moveConstantsAgain", + "multiplyZero", "multiplyZeroAgain", "distribute", + "identity", "identityAgain", "powerTwo", + "powerTwoAgain", "powerTwoPlusOne", "powerTwoMinusOne"}) + public void runMethod() { + int a = RunInfo.getRandom().nextInt(); + int b = RunInfo.getRandom().nextInt(); + + int min = Integer.MIN_VALUE; + int max = Integer.MAX_VALUE; + + assertResult(0, 0); + assertResult(a, b); + assertResult(min, min); + assertResult(max, max); + } + + @DontCompile + public void assertResult(int a, int b) { + Asserts.assertEQ((a * 13) * 14 , combineConstants(a)); + Asserts.assertEQ((a * 13) * b , moveConstants(a, b)); + Asserts.assertEQ(a * (b * 13) , moveConstantsAgain(a, b)); + Asserts.assertEQ(0 * a , multiplyZero(a)); + Asserts.assertEQ(a * 0 , multiplyZeroAgain(a)); + Asserts.assertEQ((13 + a) * 14 , distribute(a)); + Asserts.assertEQ(1 * a , identity(a)); + Asserts.assertEQ(a * 1 , identityAgain(a)); + Asserts.assertEQ(a * 64 , powerTwo(a)); + Asserts.assertEQ(a * (1025 - 1), powerTwoAgain(a)); + Asserts.assertEQ(a * (64 + 1) , powerTwoPlusOne(a)); + Asserts.assertEQ(a * (64 - 1) , powerTwoMinusOne(a)); + } + + @Test + @IR(counts = {IRNode.MUL, "1"}) + //Checks (x * c1) * c2 => x * c3 where c3 = c1 * c2 + public int combineConstants(int x){ + return (x * 13) * 14; + } + + @Test + @IR(counts = {IRNode.MUL, "2"}) + // Checks (x * c1) * y => (x * y) * c1 + public int moveConstants(int x, int y) { + return (x * 13) * y; + } + + @Test + @IR(counts = {IRNode.MUL, "2"}) + // Checks x * (y * c1) => (x * y) * c1 + public int moveConstantsAgain(int x, int y) { + return x * (y * 13); + } + + @Test + @IR(failOn = {IRNode.MUL}) + // Checks 0 * x => 0 + public int multiplyZero(int x) { + return 0 * x; + } + + @Test + @IR(failOn = {IRNode.MUL}) + // Checks x * 0 => 0 + public int multiplyZeroAgain(int x) { + return x * 0; + } + + @Test + @IR(counts = {IRNode.MUL, "1", + IRNode.ADD, "1", + }) + // Checks (c1 + x) * c2 => x * c2 + c3 where c3 = c1 * c2 + public int distribute(int x) { + return (13 + x) * 14; + } + + @Test + @IR(failOn = {IRNode.MUL}) + // Checks 1 * x => x + public int identity(int x) { + return 1 * x; + } + + @Test + @IR(failOn = {IRNode.MUL}) + // Checks x * 1 => x + public int identityAgain(int x) { + return x * 1; + } + + @Test + @IR(failOn = {IRNode.MUL}) + @IR(counts = {IRNode.LSHIFT, "1"}) + // Checks x * 2^n => x << n + public int powerTwo(int x) { + return x * 64; + } + + @Test + @IR(failOn = {IRNode.SUB, IRNode.MUL}) + @IR(counts = {IRNode.LSHIFT, "1"}) + // Checks x * 2^n => x << n + public int powerTwoAgain(int x) { + return x * (1025 - 1); + } + + @Test + @IR(failOn = {IRNode.MUL}) + @IR(counts = {IRNode.LSHIFT, "1", + IRNode.ADD, "1", + }) + // Checks x * (2^n + 1) => (x << n) + x + public int powerTwoPlusOne(int x) { + return x * (64 + 1); + } + + @Test + @IR(failOn = {IRNode.MUL}) + @IR(counts = {IRNode.LSHIFT, "1", + IRNode.SUB, "1", + }) + // Checks x * (2^n - 1) => (x << n) - x + public int powerTwoMinusOne(int x) { + return x * (64 - 1); + } +} diff --git a/test/hotspot/jtreg/compiler/c2/irTests/MulLNodeIdealizationTests.java b/test/hotspot/jtreg/compiler/c2/irTests/MulLNodeIdealizationTests.java new file mode 100644 index 0000000000000000000000000000000000000000..8a8b5923bcc9e2a0b9a756cd126442790c8a9730 --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/irTests/MulLNodeIdealizationTests.java @@ -0,0 +1,166 @@ +/* + * 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. + */ +package compiler.c2.irTests; + +import jdk.test.lib.Asserts; +import compiler.lib.ir_framework.*; + +/* + * @test + * @bug 8267265 + * @summary Test that Ideal transformations of MulLNode* are being performed as expected. + * @library /test/lib / + * @run driver compiler.c2.irTests.MulLNodeIdealizationTests + */ +public class MulLNodeIdealizationTests { + public static void main(String[] args) { + TestFramework.run(); + } + + @Run(test = {"combineConstants", "moveConstants", "moveConstantsAgain", + "multiplyZero", "multiplyZeroAgain", "distribute", + "identity", "identityAgain", "powerTwo", + "powerTwoAgain", "powerTwoPlusOne", "powerTwoMinusOne"}) + public void runMethod() { + long a = RunInfo.getRandom().nextLong(); + long b = RunInfo.getRandom().nextLong(); + + long min = Long.MIN_VALUE; + long max = Long.MAX_VALUE; + + assertResult(0, 0); + assertResult(a, b); + assertResult(min, min); + assertResult(max, max); + } + + @DontCompile + public void assertResult(long a, long b) { + Asserts.assertEQ((a * 13) * 14 * 15, combineConstants(a)); + Asserts.assertEQ((a * 13) * b , moveConstants(a, b)); + Asserts.assertEQ(a * (b * 13) , moveConstantsAgain(a, b)); + Asserts.assertEQ(0 * a , multiplyZero(a)); + Asserts.assertEQ(a * 0 , multiplyZeroAgain(a)); + Asserts.assertEQ((13 + a) * 14 , distribute(a)); + Asserts.assertEQ(1 * a , identity(a)); + Asserts.assertEQ(a * 1 , identityAgain(a)); + Asserts.assertEQ(a * 64 , powerTwo(a)); + Asserts.assertEQ(a * (1025 - 1) , powerTwoAgain(a)); + Asserts.assertEQ(a * (64 + 1) , powerTwoPlusOne(a)); + Asserts.assertEQ(a * (64 - 1) , powerTwoMinusOne(a)); + } + + @Test + @IR(counts = {IRNode.MUL, "1"}) + //Checks (x * c1) * c2 => x * c3 where c3 = c1 * c2 + public long combineConstants(long x){ + return (x * 13) * 14 * 15; + } + + @Test + @IR(counts = {IRNode.MUL, "2"}) + // Checks (x * c1) * y => (x * y) * c1 + public long moveConstants(long x, long y) { + return (x * 13) * y; + } + + @Test + @IR(counts = {IRNode.MUL, "2"}) + // Checks x * (y * c1) => (x * y) * c1 + public long moveConstantsAgain(long x, long y) { + return x * (y * 13); + } + + @Test + @IR(failOn = {IRNode.MUL}) + // Checks 0 * x => 0 + public long multiplyZero(long x) { + return 0 * x; + } + + @Test + @IR(failOn = {IRNode.MUL}) + // Checks x * 0 => 0 + public long multiplyZeroAgain(long x) { + return x * 0; + } + + @Test + @IR(counts = {IRNode.MUL, "1", + IRNode.ADD, "1", + }) + // Checks (c1 + x) * c2 => x * c2 + c3 where c3 = c1 * c2 + public long distribute(long x) { + return (13 + x) * 14; + } + + @Test + @IR(failOn = {IRNode.MUL}) + // Checks 1 * x => x + public long identity(long x) { + return 1 * x; + } + + @Test + @IR(failOn = {IRNode.MUL}) + // Checks x * 1 => x + public long identityAgain(long x) { + return x * 1; + } + + @Test + @IR(failOn = {IRNode.MUL}) + @IR(counts = {IRNode.LSHIFT, "1"}) + // Checks x * 2^n => x << n + public long powerTwo(long x) { + return x * 64; + } + + @Test + @IR(failOn = {IRNode.SUB, IRNode.MUL}) + @IR(counts = {IRNode.LSHIFT, "1"}) + // Checks x * 2^n => x << n + public long powerTwoAgain(long x) { + return x * (1025 - 1); + } + + @Test + @IR(failOn = {IRNode.MUL}) + @IR(counts = {IRNode.LSHIFT, "1", + IRNode.ADD, "1", + }) + // Checks x * (2^n + 1) => (x << n) + x + public long powerTwoPlusOne(long x) { + return x * (64 + 1); + } + + @Test + @IR(failOn = {IRNode.MUL}) + @IR(counts = {IRNode.LSHIFT, "1", + IRNode.SUB, "1", + }) + // Checks x * (2^n - 1) => (x << n) - x + public long powerTwoMinusOne(long x) { + return x * (64 - 1); + } +} diff --git a/test/hotspot/jtreg/compiler/c2/irTests/SubINodeIdealizationTests.java b/test/hotspot/jtreg/compiler/c2/irTests/SubINodeIdealizationTests.java new file mode 100644 index 0000000000000000000000000000000000000000..04a122000e56067c9fc519522d86ca72f06b5b78 --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/irTests/SubINodeIdealizationTests.java @@ -0,0 +1,252 @@ +/* + * 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. + */ +package compiler.c2.irTests; + +import jdk.test.lib.Asserts; +import compiler.lib.ir_framework.*; + +/* + * @test + * @bug 8267265 + * @summary Test that Ideal transformations of SubINode* are being performed as expected. + * @library /test/lib / + * @run driver compiler.c2.irTests.SubINodeIdealizationTests + */ +public class SubINodeIdealizationTests { + public static void main(String[] args) { + TestFramework.run(); + } + + @Run(test = {"test1", "test2", "test3", + "test4", "test5", "test6", + "test7", "test8", "test9", + "test10", "test11", "test12", + "test13", "test14", "test15", + "test16", "test17", "test18", + "test19", "test20", "test21"}) + public void runMethod() { + int a = RunInfo.getRandom().nextInt(); + int b = RunInfo.getRandom().nextInt(); + int c = RunInfo.getRandom().nextInt(); + + int min = Integer.MIN_VALUE; + int max = Integer.MAX_VALUE; + + assertResult(0, 0, 0); + assertResult(a, b, c); + assertResult(min, min, min); + assertResult(max, max, max); + } + + @DontCompile + public void assertResult(int a, int b, int c) { + Asserts.assertEQ(a - 1 , test1(a)); + Asserts.assertEQ((a + 1) - b , test2(a, b)); + Asserts.assertEQ(a - (b + 2021) , test3(a, b)); + Asserts.assertEQ(a - (a + b) , test4(a, b)); + Asserts.assertEQ((a - b) - a , test5(a, b)); + Asserts.assertEQ(a - (b + a) , test6(a, b)); + Asserts.assertEQ(0 - (a - b) , test7(a, b)); + Asserts.assertEQ(0 - (a + 2021) , test8(a)); + Asserts.assertEQ((a + b) - (a + c), test9(a, b, c)); + Asserts.assertEQ((b + a) - (c + a), test10(a, b, c)); + Asserts.assertEQ((b + a) - (a + c), test11(a, b, c)); + Asserts.assertEQ((a + b) - (c + a), test12(a, b, c)); + Asserts.assertEQ(a - (b - c) , test13(a, b, c)); + Asserts.assertEQ(0 - (a >> 31) , test14(a)); + Asserts.assertEQ(0 - (0 - a) , test15(a)); + Asserts.assertEQ((a + b) - b , test16(a, b)); + Asserts.assertEQ((a + b) - a , test17(a, b)); + Asserts.assertEQ(a*b - a*c , test18(a, b, c)); + Asserts.assertEQ(a*b - b*c , test19(a, b, c)); + Asserts.assertEQ(a*c - b*c , test20(a, b, c)); + Asserts.assertEQ(a*b - c*a , test21(a, b, c)); + } + + @Test + @IR(failOn = {IRNode.SUB}) + @IR(counts = {IRNode.ADD, "1"}) + // Checks (x - c0) => x + (-c0) + public int test1(int x) { + return (x - 1); + } + + @Test + @IR(counts = {IRNode.ADD, "1", + IRNode.SUB, "1" + }) + // Checks (x + c0) - y => (x - y) + c0 + public int test2(int x, int y) { + return (x + 1) - y; + } + + @Test + @IR(counts = {IRNode.SUB, "1", + IRNode.ADD, "1" + }) + // Checks x - (y + c0) => (x - y) + (-c0) + public int test3(int x, int y) { + return x - (y + 2021); + } + + @Test + @IR(failOn = {IRNode.ADD}) + @IR(counts = {IRNode.SUB, "1"}) + // Checks x - (x + y) => 0 - y + public int test4(int x, int y) { + return x - (x + y); + } + + @Test + @IR(counts = {IRNode.SUB, "1"}) + // Checks (x - y) - x => 0 - y + public int test5(int x, int y) { + return (x - y) - x; + } + + @Test + @IR(failOn = {IRNode.ADD}) + @IR(counts = {IRNode.SUB, "1"}) + // Checks x - (y + x) => 0 - y + public int test6(int x, int y) { + return x - (y + x); + } + + @Test + @IR(counts = {IRNode.SUB, "1"}) + // Checks 0 - (x - y) => y - x + public int test7(int x, int y) { + return 0 - (x - y); + } + + @Test + @IR(failOn = {IRNode.ADD}) + @IR(counts = {IRNode.SUB, "1"}) + // Checks 0 - (x + 2021) => -2021 - x + public int test8(int x) { + return 0 - (x + 2021); + } + + @Test + @IR(failOn = {IRNode.ADD}) + @IR(counts = {IRNode.SUB, "1"}) + // Checks (x + a) - (x + b) => a - b; + public int test9(int x, int a, int b) { + return (x + a) - (x + b); + } + + @Test + @IR(failOn = {IRNode.ADD}) + @IR(counts = {IRNode.SUB, "1"}) + // Checks (a + x) - (b + x) => a - b + public int test10(int x, int a, int b) { + return (a + x) - (b + x); + } + + @Test + @IR(failOn = {IRNode.ADD}) + @IR(counts = {IRNode.SUB, "1"}) + // Checks (a + x) - (x + b) => a - b + public int test11(int x, int a, int b) { + return (a + x) - (x + b); + } + + @Test + @IR(failOn = {IRNode.ADD}) + @IR(counts = {IRNode.SUB, "1"}) + // Checks (x + a) - (b + x) => a - b + public int test12(int x, int a, int b) { + return (x + a) - (b + x); + } + + @Test + @IR(counts = {IRNode.SUB, "1", + IRNode.ADD, "1" + }) + // Checks a - (b - c) => (a + c) - b + public int test13(int a, int b, int c) { + return a - (b - c); + } + + @Test + @IR(failOn = {IRNode.SUB, IRNode.RSHIFT_I}) + @IR(counts = {IRNode.URSHIFT_I, "1"}) + // Checks 0 - (a >> 31) => a >>> 31 + // signed ^^ ^^^ unsigned + public int test14(int a) { + return 0 - (a >> 31); + } + + @Test + @IR(failOn = {IRNode.SUB}) + // Checks 0 - (0 - x) => x + public int test15(int x) { + return 0 - (0 - x); + } + + @Test + @IR(failOn = {IRNode.SUB, IRNode.ADD}) + // Checks (x + y) - y => x + public int test16(int x, int y) { + return (x + y) - y; + } + + @Test + @IR(failOn = {IRNode.SUB, IRNode.ADD}) + // Checks (x + y) - x => y + public int test17(int x, int y) { + return (x + y) - x; + } + + @Test + @IR(counts = {IRNode.MUL, "1", + IRNode.SUB, "1"}) + // Checks "a*b-a*c => a*(b-c) + public int test18(int a, int b, int c) { + return a*b - a*c; + } + + @Test + @IR(counts = {IRNode.MUL, "1", + IRNode.SUB, "1"}) + // Checks a*b-b*c => b*(a-c) + public int test19(int a, int b, int c) { + return a*b - b*c; + } + + @Test + @IR(counts = {IRNode.MUL, "1", + IRNode.SUB, "1"}) + // Checks a*c-b*c => (a-b)*c + public int test20(int a, int b, int c) { + return a*c - b*c; + } + + @Test + @IR(counts = {IRNode.MUL, "1", + IRNode.SUB, "1"}) + // Checks a*b-c*a => a*(b-c) + public int test21(int a, int b, int c) { + return a*b - c*a; + } +} diff --git a/test/hotspot/jtreg/compiler/c2/irTests/SubLNodeIdealizationTests.java b/test/hotspot/jtreg/compiler/c2/irTests/SubLNodeIdealizationTests.java new file mode 100644 index 0000000000000000000000000000000000000000..f03a07d84d030eb34791fb67d043156fbc48f8d7 --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/irTests/SubLNodeIdealizationTests.java @@ -0,0 +1,252 @@ +/* + * 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. + */ +package compiler.c2.irTests; + +import jdk.test.lib.Asserts; +import compiler.lib.ir_framework.*; + +/* + * @test + * @bug 8267265 8272735 + * @summary Test that Ideal transformations of SubLNode* are being performed as expected. + * @library /test/lib / + * @run driver compiler.c2.irTests.SubLNodeIdealizationTests + */ +public class SubLNodeIdealizationTests { + public static void main(String[] args) { + TestFramework.run(); + } + + @Run(test = {"test1", "test2", "test3", + "test4", "test5", "test6", + "test7", "test8", "test9", + "test10", "test11", "test12", + "test13", "test14", "test15", + "test16", "test17", "test18", + "test19", "test20", "test21"}) + public void runMethod() { + long a = RunInfo.getRandom().nextLong(); + long b = RunInfo.getRandom().nextLong(); + long c = RunInfo.getRandom().nextLong(); + + long min = Long.MIN_VALUE; + long max = Long.MAX_VALUE; + + assertResult(0, 0, 0); + assertResult(a, b, c); + assertResult(min, min, min); + assertResult(max, max, max); + } + + @DontCompile + public void assertResult(long a, long b, long c) { + Asserts.assertEQ(a - 1 , test1(a)); + Asserts.assertEQ((a + 1) - b , test2(a, b)); + Asserts.assertEQ(a - (b + 2021) , test3(a, b)); + Asserts.assertEQ(a - (a + b) , test4(a, b)); + Asserts.assertEQ((a - b) - a , test5(a, b)); + Asserts.assertEQ(a - (b + a) , test6(a, b)); + Asserts.assertEQ(0 - (a - b) , test7(a, b)); + Asserts.assertEQ(0 - (a + 2021) , test8(a, b)); + Asserts.assertEQ((a + b) - (a + c), test9(a, b, c)); + Asserts.assertEQ((b + a) - (c + a), test10(a, b, c)); + Asserts.assertEQ((b + a) - (a + c), test11(a, b, c)); + Asserts.assertEQ((a + b) - (c + a), test12(a, b, c)); + Asserts.assertEQ(a - (b - c) , test13(a, b, c)); + Asserts.assertEQ(0 - (a >> 63) , test14(a)); + Asserts.assertEQ(0 - (0 - a) , test15(a)); + Asserts.assertEQ((a + b) - b , test16(a, b)); + Asserts.assertEQ((a + b) - a , test17(a, b)); + Asserts.assertEQ(a*b - a*c , test18(a, b, c)); + Asserts.assertEQ(a*b - b*c , test19(a, b, c)); + Asserts.assertEQ(a*c - b*c , test20(a, b, c)); + Asserts.assertEQ(a*b - c*a , test21(a, b, c)); + } + + @Test + @IR(failOn = {IRNode.SUB}) + @IR(counts = {IRNode.ADD, "1"}) + // Checks (x - c0) => x + (-c0) + public long test1(long x) { + return (x - 1); + } + + @Test + @IR(counts = {IRNode.ADD, "1", + IRNode.SUB, "1" + }) + // Checks (x + c0) - y => (x - y) + c0 + public long test2(long x, long y) { + return (x + 1) - y; + } + + @Test + @IR(counts = {IRNode.SUB, "1", + IRNode.ADD, "1" + }) + // Checks x - (y + c0) => (x - y) + (-c0) + public long test3(long x, long y) { + return x - (y + 2021); + } + + @Test + @IR(failOn = {IRNode.ADD}) + @IR(counts = {IRNode.SUB, "1"}) + // Checks x - (x + y) => 0 - y + public long test4(long x, long y) { + return x - (x + y); + } + + @Test + @IR(counts = {IRNode.SUB, "1"}) + // Checks (x - y) - x => 0 - y + public long test5(long x, long y) { + return (x - y) - x; + } + + @Test + @IR(failOn = {IRNode.ADD}) + @IR(counts = {IRNode.SUB, "1"}) + // Checks x - (y + x) => 0 - y + public long test6(long x, long y) { + return x - (y + x); + } + + @Test + @IR(counts = {IRNode.SUB, "1"}) + // Checks 0 - (x - y) => y - x + public long test7(long x, long y) { + return 0 - (x - y); + } + + @Test + @IR(failOn = {IRNode.ADD}) + @IR(counts = {IRNode.SUB, "1"}) + // Checks 0 - (x + 2021) => -2021 - x + public long test8(long x, long y) { + return 0 - (x + 2021); + } + + @Test + @IR(failOn = {IRNode.ADD}) + @IR(counts = {IRNode.SUB, "1"}) + // Checks (x + a) - (x + b) => a - b; + public long test9(long x, long a, long b) { + return (x + a) - (x + b); + } + + @Test + @IR(failOn = {IRNode.ADD}) + @IR(counts = {IRNode.SUB, "1"}) + // Checks (a + x) - (b + x) => a - b + public long test10(long x, long a, long b) { + return (a + x) - (b + x); + } + + @Test + @IR(failOn = {IRNode.ADD}) + @IR(counts = {IRNode.SUB, "1"}) + // Checks (a + x) - (x + b) => a - b + public long test11(long x, long a, long b) { + return (a + x) - (x + b); + } + + @Test + @IR(failOn = {IRNode.ADD}) + @IR(counts = {IRNode.SUB, "1"}) + // Checks (x + a) - (b + x) => a - b + public long test12(long x, long a, long b) { + return (x + a) - (b + x); + } + + @Test + @IR(counts = {IRNode.SUB, "1", + IRNode.ADD, "1" + }) + // Checks a - (b - c) => (a + c) - b + public long test13(long a, long b, long c) { + return a - (b - c); + } + + @Test + @IR(failOn = {IRNode.SUB, IRNode.RSHIFT_L}) + @IR(counts = {IRNode.URSHIFT_L, "1"}) + // Checks 0 - (a >> 63) => a >>> 63 + // signed ^^ ^^^ unsigned + public long test14(long a) { + return 0 - (a >> 63); + } + + @Test + @IR(failOn = {IRNode.SUB}) + // Checks 0 - (0 - x) => x + public long test15(long x) { + return 0 - (0 - x); + } + + @Test + @IR(failOn = {IRNode.SUB, IRNode.ADD}) + // Checks (x + y) - y => x + public long test16(long x, long y) { + return (x + y) - y; + } + + @Test + @IR(failOn = {IRNode.SUB, IRNode.ADD}) + // Checks (x + y) - x => y + public long test17(long x, long y) { + return (x + y) - x; + } + + @Test + @IR(counts = {IRNode.MUL, "1", + IRNode.SUB, "1"}) + // Checks "a*b-a*c => a*(b-c) + public long test18(long a, long b, long c) { + return a*b - a*c; + } + + @Test + @IR(counts = {IRNode.MUL, "1", + IRNode.SUB, "1"}) + // Checks a*b-b*c => b*(a-c) + public long test19(long a, long b, long c) { + return a*b - b*c; + } + + @Test + @IR(counts = {IRNode.MUL, "1", + IRNode.SUB, "1"}) + // Checks a*c-b*c => (a-b)*c + public long test20(long a, long b, long c) { + return a*c - b*c; + } + + @Test + @IR(counts = {IRNode.MUL, "1", + IRNode.SUB, "1"}) + // Checks a*b-c*a => a*(b-c) + public long test21(long a, long b, long c) { + return a*b - c*a; + } +} diff --git a/test/hotspot/jtreg/compiler/c2/irTests/TestAutoVectorization2DArray.java b/test/hotspot/jtreg/compiler/c2/irTests/TestAutoVectorization2DArray.java new file mode 100644 index 0000000000000000000000000000000000000000..c79fbf993dbeca0fb80b62158ac2d9f0a31c8cf6 --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/irTests/TestAutoVectorization2DArray.java @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2022 THL A29 Limited, a Tencent company. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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; + +import compiler.lib.ir_framework.*; + +/* + * @test + * @bug 8279258 + * @summary Auto-vectorization enhancement for two-dimensional array operations + * @library /test/lib / + * @run driver compiler.c2.irTests.TestAutoVectorization2DArray + */ + +public class TestAutoVectorization2DArray { + final private static int NUM = 64; + + private static double[][] a = new double[NUM][NUM]; + private static double[][] b = new double[NUM][NUM]; + private static double[][] c = new double[NUM][NUM]; + + public static void main(String[] args) { + TestFramework.run(); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR, " >0 " }) + @IR(counts = { IRNode.ADD_VD, " >0 " }) + @IR(counts = { IRNode.STORE_VECTOR, " >0 " }) + private static void testDouble(double[][] a , double[][] b, double[][] c) { + for(int i = 0; i < a.length; i++) { + for (int j = 0; j < a[0].length; j++) { + a[i][j] = b[i][j] + c[i][j]; + } + } + } + + @Run(test = "testDouble") + private void testDouble_runner() { + testDouble(a, b, c); + } +} diff --git a/test/hotspot/jtreg/runtime/NMT/ChangeTrackingLevel.java b/test/hotspot/jtreg/compiler/c2/irTests/TestBackToBackIfs.java similarity index 52% rename from test/hotspot/jtreg/runtime/NMT/ChangeTrackingLevel.java rename to test/hotspot/jtreg/compiler/c2/irTests/TestBackToBackIfs.java index 0cc059c13b93dec578f16e7c5ad2c98595b4b8dd..207b16a806270d0ad46dd2cf08a51bdedbbea1b3 100644 --- a/test/hotspot/jtreg/runtime/NMT/ChangeTrackingLevel.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/TestBackToBackIfs.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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 @@ -21,29 +21,45 @@ * questions. */ +package compiler.c2.irTests; + +import compiler.lib.ir_framework.*; +import jdk.test.lib.Utils; +import java.util.Random; + /* * @test - * @bug 8059100 - * @summary Test that you can decrease NMT tracking level but not increase it. - * @modules java.base/jdk.internal.misc - * @library /test/lib - * @build sun.hotspot.WhiteBox - * @run driver jdk.test.lib.helpers.ClassFileInstaller sun.hotspot.WhiteBox - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:NativeMemoryTracking=detail ChangeTrackingLevel + * @bug 8278228 + * @summary C2: Improve identical back-to-back if elimination + * @library /test/lib / + * @run driver compiler.c2.irTests.TestBackToBackIfs */ -import sun.hotspot.WhiteBox; +public class TestBackToBackIfs { + public static void main(String[] args) { + TestFramework.run(); + } -public class ChangeTrackingLevel { + static private int int_field; - public static WhiteBox wb = WhiteBox.getWhiteBox(); - public static void main(String args[]) throws Exception { - boolean testChangeLevel = wb.NMTChangeTrackingLevel(); - if (testChangeLevel) { - System.out.println("NMT level change test passed."); + @Test + @IR(counts = { IRNode.IF, "1" }) + public static void test(int a, int b) { + if (a == b) { + int_field = 0x42; } else { - // it also fails if the VM asserts. - throw new RuntimeException("NMT level change test failed"); + int_field = 42; } + if (a == b) { + int_field = 0x42; + } else { + int_field = 42; + } + } + + @Run(test = "test") + public static void test_runner() { + test(42, 0x42); + test(0x42, 0x42); } -}; +} diff --git a/test/hotspot/jtreg/compiler/c2/irTests/TestCountedLoopSafepoint.java b/test/hotspot/jtreg/compiler/c2/irTests/TestCountedLoopSafepoint.java new file mode 100644 index 0000000000000000000000000000000000000000..a56fd1592fd1c8b00036c6a49381ce2b5a69058d --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/irTests/TestCountedLoopSafepoint.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 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. + */ + +package compiler.c2.irTests; + +import compiler.lib.ir_framework.*; + +/* + * @test + * bug 8281322 + * @summary check counted loop is properly constructed with/without safepoint + * @library /test/lib / + * @run driver compiler.c2.irTests.TestCountedLoopSafepoint + */ + +public class TestCountedLoopSafepoint { + public static void main(String[] args) { + TestFramework.runWithFlags("-XX:LoopMaxUnroll=1", "-XX:-UseCountedLoopSafepoints"); + TestFramework.runWithFlags("-XX:LoopMaxUnroll=1", "-XX:+UseCountedLoopSafepoints", "-XX:LoopStripMiningIter=1"); + TestFramework.runWithFlags("-XX:LoopMaxUnroll=1", "-XX:+UseCountedLoopSafepoints", "-XX:LoopStripMiningIter=1000"); + } + + @Test + @IR(counts = { IRNode.COUNTEDLOOP, "1" }) + @IR(applyIf = { "LoopStripMiningIter", "0" }, failOn = { IRNode.SAFEPOINT, IRNode.OUTERSTRIPMINEDLOOP }) + @IR(applyIf = { "LoopStripMiningIter", "1" }, counts = { IRNode.SAFEPOINT, "1" }, failOn = { IRNode.OUTERSTRIPMINEDLOOP }) + @IR(applyIf = { "LoopStripMiningIter", "> 1" }, counts = { IRNode.SAFEPOINT, "1", IRNode.OUTERSTRIPMINEDLOOP, "1" }) + public static float test(int start, int stop) { + float v = 1; + for (int i = start; i < stop; i++) { + v *= 2; + } + return v; + } + + @Run(test = "test") + private void testRunner() { + test(0, 100); + } + +} diff --git a/test/hotspot/jtreg/compiler/c2/irTests/TestFewIterationsCountedLoop.java b/test/hotspot/jtreg/compiler/c2/irTests/TestFewIterationsCountedLoop.java new file mode 100644 index 0000000000000000000000000000000000000000..1d3fed1c87a9d5ee7a67793d2a025ad196f7d0b7 --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/irTests/TestFewIterationsCountedLoop.java @@ -0,0 +1,139 @@ +/* + * Copyright (c) 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. + */ + +package compiler.c2.irTests; + +import compiler.lib.ir_framework.*; + +/* + * @test + * @bug 8262721 + * @summary Add Tests to verify single iteration loops are properly optimized + * @library /test/lib / + * @run driver compiler.c2.irTests.TestFewIterationsCountedLoop + */ + +public class TestFewIterationsCountedLoop { + + public static void main(String[] args) { + TestFramework.runWithFlags("-XX:LoopUnrollLimit=0"); + TestFramework.run(); + } + + static volatile int barrier; + static final Object object = new Object(); + + @Test + @IR(failOn = { IRNode.COUNTEDLOOP, IRNode.LOOP }) + public static void singleIterationFor() { + for (int i = 0; i < 1; i++) { + barrier = 0x42; // something that can't be optimized out + } + } + + @Test + @IR(failOn = { IRNode.COUNTEDLOOP, IRNode.LOOP }) + public static void singleIterationWhile() { + int i = 0; + while (i < 1) { + barrier = 0x42; + i++; + } + } + + @Test + @IR(failOn = { IRNode.COUNTEDLOOP, IRNode.LOOP }) + @Warmup(1) // So C2 can't rely on profile data + public static void singleIterationDoWhile() { + int i = 0; + do { + synchronized(object) {} // so loop head is not cloned by ciTypeFlow + barrier = 0x42; + i++; + } while (i < 1); + } + + @Test + @IR(applyIf = { "LoopUnrollLimit", "0" }, counts = { IRNode.COUNTEDLOOP, "1" }) + @IR(applyIf = { "LoopUnrollLimit", "> 0" }, failOn = { IRNode.COUNTEDLOOP, IRNode.LOOP }) + public static void twoIterationsFor() { + for (int i = 0; i < 2; i++) { + barrier = 0x42; // something that can't be optimized out + } + } + + @Test + @IR(applyIf = { "LoopUnrollLimit", "0" }, counts = { IRNode.COUNTEDLOOP, "1" }) + @IR(applyIf = { "LoopUnrollLimit", "> 0" }, failOn = { IRNode.COUNTEDLOOP, IRNode.LOOP }) + public static void twoIterationsWhile() { + int i = 0; + while (i < 2) { + barrier = 0x42; + i++; + } + } + + @Test + @IR(applyIf = { "LoopUnrollLimit", "0" }, counts = { IRNode.COUNTEDLOOP, "1" }) + @IR(applyIf = { "LoopUnrollLimit", "> 0" }, failOn = { IRNode.COUNTEDLOOP, IRNode.LOOP }) + public static void twoIterationsDoWhile() { + int i = 0; + do { + synchronized(object) {} // so loop head is not cloned by ciTypeFlow + barrier = 0x42; + i++; + } while (i < 2); + } + + @Test + @IR(applyIf = { "LoopUnrollLimit", "0" }, counts = { IRNode.COUNTEDLOOP, "1" }) + @IR(applyIf = { "LoopUnrollLimit", "> 0" }, failOn = { IRNode.COUNTEDLOOP, IRNode.LOOP }) + public static void threadIterationsFor() { + for (int i = 0; i < 2; i++) { + barrier = 0x42; // something that can't be optimized out + } + } + + @Test + @IR(applyIf = { "LoopUnrollLimit", "0" }, counts = { IRNode.COUNTEDLOOP, "1" }) + @IR(applyIf = { "LoopUnrollLimit", "> 0" }, failOn = { IRNode.COUNTEDLOOP, IRNode.LOOP }) + public static void threeIterationsWhile() { + int i = 0; + while (i < 2) { + barrier = 0x42; + i++; + } + } + + @Test + @IR(applyIf = { "LoopUnrollLimit", "0" }, counts = { IRNode.COUNTEDLOOP, "1" }) + @IR(applyIf = { "LoopUnrollLimit", "> 0" }, failOn = { IRNode.COUNTEDLOOP, IRNode.LOOP }) + public static void threeIterationsDoWhile() { + int i = 0; + do { + synchronized(object) {} // so loop head is not cloned by ciTypeFlow + barrier = 0x42; + i++; + } while (i < 2); + } +} diff --git a/test/hotspot/jtreg/compiler/c2/irTests/TestIRAbs.java b/test/hotspot/jtreg/compiler/c2/irTests/TestIRAbs.java new file mode 100644 index 0000000000000000000000000000000000000000..8ba786d6f20e5b4acff95e17c7073e3fd3bf48da --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/irTests/TestIRAbs.java @@ -0,0 +1,232 @@ +/* + * Copyright (c) 2022, 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. + */ + +package compiler.c2.irTests; + +import jdk.test.lib.Asserts; +import compiler.lib.ir_framework.*; + +/* + * @test + * @bug 8276673 8280089 + * @summary Test abs nodes optimization in C2. + * @requires os.arch=="amd64" | os.arch=="x86_64" | os.arch=="aarch64" + * @library /test/lib / + * @run driver compiler.c2.irTests.TestIRAbs + */ + +public class TestIRAbs { + + public static char [] cspecial = { + 0, 42, 128, 256, 1024, 4096, 65535 + }; + + public static int [] ispecial = { + 0, Integer.MAX_VALUE, Integer.MIN_VALUE, -42, 42, -1, 1 + }; + + public static long [] lspecial = { + 0, Long.MAX_VALUE, Long.MIN_VALUE, -42, 42, -1, 1 + }; + + public static float [] fspecial = { + 0.0f, + -0.0f, + Float.MAX_VALUE, + Float.MIN_VALUE, + -Float.MAX_VALUE, + -Float.MIN_VALUE, + Float.NaN, + Float.POSITIVE_INFINITY, + Float.NEGATIVE_INFINITY, + Integer.MAX_VALUE, + Integer.MIN_VALUE, + Long.MAX_VALUE, + Long.MIN_VALUE, + -1.0f, + 1.0f, + -42.0f, + 42.0f + }; + + public static double [] dspecial = { + 0.0, + -0.0, + Double.MAX_VALUE, + Double.MIN_VALUE, + -Double.MAX_VALUE, + -Double.MIN_VALUE, + Double.NaN, + Double.POSITIVE_INFINITY, + Double.NEGATIVE_INFINITY, + Integer.MAX_VALUE, + Integer.MIN_VALUE, + Long.MIN_VALUE, + Long.MAX_VALUE, + -1, + 1, + 42, + -42, + Math.PI, + Math.E, + Float.MAX_VALUE, + Float.MIN_VALUE, + -Float.MAX_VALUE, + -Float.MIN_VALUE, + Float.NaN, + Float.POSITIVE_INFINITY, + Float.NEGATIVE_INFINITY + }; + + public static void main(String[] args) { + TestFramework.run(); + } + + @Test + @IR(failOn = {IRNode.ABS_I, IRNode.ABS_L, IRNode.ABS_F, IRNode.ABS_D}) + public void testAbsConstant() { + // Test abs(constant) optimization for int + Asserts.assertEquals(Integer.MAX_VALUE, Math.abs(Integer.MAX_VALUE)); + Asserts.assertEquals(Integer.MIN_VALUE, Math.abs(Integer.MIN_VALUE)); + Asserts.assertEquals(Integer.MAX_VALUE, Math.abs(-Integer.MAX_VALUE)); + + // Test abs(constant) optimization for long + Asserts.assertEquals(Long.MAX_VALUE, Math.abs(Long.MAX_VALUE)); + Asserts.assertEquals(Long.MIN_VALUE, Math.abs(Long.MIN_VALUE)); + Asserts.assertEquals(Long.MAX_VALUE, Math.abs(-Long.MAX_VALUE)); + + // Test abs(constant) optimization for float + Asserts.assertTrue(Float.isNaN(Math.abs(Float.NaN))); + Asserts.assertEquals(Float.POSITIVE_INFINITY, Math.abs(Float.NEGATIVE_INFINITY)); + Asserts.assertEquals(Float.POSITIVE_INFINITY, Math.abs(Float.POSITIVE_INFINITY)); + Asserts.assertEquals(0.0f, Math.abs(0.0f)); + Asserts.assertEquals(0.0f, Math.abs(-0.0f)); + Asserts.assertEquals(Float.MAX_VALUE, Math.abs(Float.MAX_VALUE)); + Asserts.assertEquals(Float.MIN_VALUE, Math.abs(Float.MIN_VALUE)); + Asserts.assertEquals(Float.MAX_VALUE, Math.abs(-Float.MAX_VALUE)); + Asserts.assertEquals(Float.MIN_VALUE, Math.abs(-Float.MIN_VALUE)); + + // Test abs(constant) optimization for double + Asserts.assertTrue(Double.isNaN(Math.abs(Double.NaN))); + Asserts.assertEquals(Double.POSITIVE_INFINITY, Math.abs(Double.NEGATIVE_INFINITY)); + Asserts.assertEquals(Double.POSITIVE_INFINITY, Math.abs(Double.POSITIVE_INFINITY)); + Asserts.assertEquals(0.0, Math.abs(0.0)); + Asserts.assertEquals(0.0, Math.abs(-0.0)); + Asserts.assertEquals(Double.MAX_VALUE, Math.abs(Double.MAX_VALUE)); + Asserts.assertEquals(Double.MIN_VALUE, Math.abs(Double.MIN_VALUE)); + Asserts.assertEquals(Double.MAX_VALUE, Math.abs(-Double.MAX_VALUE)); + Asserts.assertEquals(Double.MIN_VALUE, Math.abs(-Double.MIN_VALUE)); + } + + @Test + @IR(counts = {IRNode.ABS_I, "1"}) + public int testInt0(int x) { + return Math.abs(Math.abs(x)); // transformed to Math.abs(x) + } + + @Test + @IR(failOn = {IRNode.SUB_I}) + @IR(counts = {IRNode.ABS_I, "1"}) + public int testInt1(int x) { + return Math.abs(0 - x); // transformed to Math.abs(x) + } + + @Run(test = {"testInt0", "testInt1"}) + public void checkTestInt(RunInfo info) { + for (int i = 0; i < ispecial.length; i++) { + Asserts.assertEquals(Math.abs(ispecial[i]), testInt0(ispecial[i])); + Asserts.assertEquals(Math.abs(ispecial[i]), testInt1(ispecial[i])); + } + } + + @Test + @IR(counts = {IRNode.ABS_L, "1"}) + public long testLong0(long x) { + return Math.abs(Math.abs(x)); // transformed to Math.abs(x) + } + + @Test + @IR(failOn = {IRNode.SUB_L}) + @IR(counts = {IRNode.ABS_L, "1"}) + public long testLong1(long x) { + return Math.abs(0 - x); // transformed to Math.abs(x) + } + + @Run(test = {"testLong0", "testLong1"}) + public void checkTestLong(RunInfo info) { + for (int i = 0; i < lspecial.length; i++) { + Asserts.assertEquals(Math.abs(lspecial[i]), testLong0(lspecial[i])); + Asserts.assertEquals(Math.abs(lspecial[i]), testLong1(lspecial[i])); + } + } + + @Test + @IR(counts = {IRNode.ABS_F, "1"}) + public float testFloat0(float x) { + return Math.abs(Math.abs(x)); // transformed to Math.abs(x) + } + + @Test + @IR(failOn = {IRNode.SUB_F}) + @IR(counts = {IRNode.ABS_F, "1"}) + public float testFloat1(float x) { + return Math.abs(0 - x); // transformed to Math.abs(x) + } + + @Run(test = {"testFloat0", "testFloat1"}) + public void checkTestFloat(RunInfo info) { + for (int i = 0; i < fspecial.length; i++) { + Asserts.assertEquals(Math.abs(fspecial[i]), testFloat0(fspecial[i])); + Asserts.assertEquals(Math.abs(fspecial[i]), testFloat1(fspecial[i])); + } + } + + @Test + @IR(counts = {IRNode.ABS_D, "1"}) + public double testDouble0(double x) { + return Math.abs(Math.abs(x)); // transformed to Math.abs(x) + } + + @Test + @IR(failOn = {IRNode.SUB_D}) + @IR(counts = {IRNode.ABS_D, "1"}) + public double testDouble1(double x) { + return Math.abs(0 - x); // transformed to Math.abs(x) + } + + @Run(test = {"testDouble0", "testDouble1"}) + public void checkTestDouble(RunInfo info) { + for (int i = 0; i < dspecial.length; i++) { + Asserts.assertEquals(Math.abs(dspecial[i]), testDouble0(dspecial[i])); + Asserts.assertEquals(Math.abs(dspecial[i]), testDouble1(dspecial[i])); + } + } + + @Test + @IR(failOn = {IRNode.ABS_I}) + public void testChar() { + for (int i = 0; i < cspecial.length; i++) { + Asserts.assertEquals(cspecial[i], (char) Math.abs(cspecial[i])); + } + } + } diff --git a/test/hotspot/jtreg/compiler/c2/irTests/TestIRAddIdealNotXPlusC.java b/test/hotspot/jtreg/compiler/c2/irTests/TestIRAddIdealNotXPlusC.java new file mode 100644 index 0000000000000000000000000000000000000000..3d632b998566d5565ed1f39b6d345782a2a0961f --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/irTests/TestIRAddIdealNotXPlusC.java @@ -0,0 +1,366 @@ +/* + * 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. + */ + +package compiler.c2.irTests; + +import jdk.test.lib.Asserts; +import compiler.lib.ir_framework.*; + +/* + * @test + * @bug 8279607 + * @summary Test that transformation from ~x + c to (c - 1) - x and + * from ~(x + c) to (-c - 1) - x works as intended. + * @library /test/lib / + * @run driver compiler.c2.irTests.TestIRAddIdealNotXPlusC + */ +public class TestIRAddIdealNotXPlusC { + + public static void main(String[] args) { + TestFramework.run(); + } + + @Test + @IR(failOn = {IRNode.ADD_I, IRNode.XOR_I}) + @IR(counts = {IRNode.SUB_I, "1"}) + public int testIntConIsNormal1(int x) { + return ~x + 1234; // transformed to 1233 - x + } + + @Run(test = "testIntConIsNormal1") + public void checkTestIntConIsNormal1(RunInfo info) { + assertC2Compiled(info); + Asserts.assertEquals(1223, testIntConIsNormal1(10)); + Asserts.assertEquals(1233, testIntConIsNormal1(0)); + } + + @Test + @IR(failOn = {IRNode.ADD_I, IRNode.XOR_I}) + @IR(counts = {IRNode.SUB_I, "1"}) + public int testIntConIsNormal2(int x) { + return ~(x + -1234); // transformed to 1233 - x + } + + @Run(test = "testIntConIsNormal2") + public void checkTestIntConIsNormal2(RunInfo info) { + assertC2Compiled(info); + Asserts.assertEquals(1223, testIntConIsNormal2(10)); + Asserts.assertEquals(1233, testIntConIsNormal2(0)); + } + + @Test + @IR(failOn = {IRNode.ADD_L, IRNode.XOR_L}) + @IR(counts = {IRNode.SUB_L, "1"}) + public long testLongConIsNormal1(long x) { + return ~x + 123_456_789_123L; // transformed to 123_456_789_122L - x + } + + @Run(test = "testLongConIsNormal1") + public void checkTestLongConIsNormal1(RunInfo info) { + assertC2Compiled(info); + Asserts.assertEquals(113_456_789_122L, testLongConIsNormal1(10_000_000_000L)); + Asserts.assertEquals(123_456_789_122L, testLongConIsNormal1(0L)); + } + + @Test + @IR(failOn = {IRNode.ADD_L, IRNode.XOR_L}) + @IR(counts = {IRNode.SUB_L, "1"}) + public long testLongConIsNormal2(long x) { + return ~(x + -123_456_789_123L); // transformed to 123_456_789_122L - x + } + + @Run(test = "testLongConIsNormal2") + public void checkTestLongConIsNormal2(RunInfo info) { + assertC2Compiled(info); + Asserts.assertEquals(113_456_789_122L, testLongConIsNormal2(10_000_000_000L)); + Asserts.assertEquals(123_456_789_122L, testLongConIsNormal2(0L)); + } + + @Test + @IR(failOn = {IRNode.ADD_I, IRNode.XOR_I}) + @IR(counts = {IRNode.SUB_I, "1"}) + public int testIntConIsZero1(int x) { + return ~x + 0; // transformed to -1 - x + } + + @Run(test = "testIntConIsZero1") + public void checkTestIntConIsZero1(RunInfo info) { + assertC2Compiled(info); + Asserts.assertEquals(-11, testIntConIsZero1(10)); + } + + @Test + @IR(failOn = {IRNode.ADD_I, IRNode.SUB_I}) + @IR(counts = {IRNode.XOR_I, "1"}) + public int testIntConIsZero2(int x) { + return ~(x + 0); // should not happen, transformed to ~x + } + + @Run(test = "testIntConIsZero2") + public void checkTestIntConIsZero2(RunInfo info) { + assertC2Compiled(info); + Asserts.assertEquals(-11, testIntConIsZero2(10)); + } + + @Test + @IR(failOn = {IRNode.ADD_L, IRNode.XOR_L}) + @IR(counts = {IRNode.SUB_L, "1"}) + public long testLongConIsZero1(long x) { + return ~x + 0L; // transformed to -1 - x + } + + @Run(test = "testLongConIsZero1") + public void checkTestLongConIsZero1(RunInfo info) { + assertC2Compiled(info); + Asserts.assertEquals(-10_000_000_001L, testLongConIsZero1(10_000_000_000L)); + } + + @Test + @IR(failOn = {IRNode.ADD_L, IRNode.SUB_L}) + @IR(counts = {IRNode.XOR_L, "1"}) + public long testLongConIsZero2(long x) { + return ~(x + 0L); // should not happen, transformed to ~x + } + + @Run(test = "testLongConIsZero2") + public void checkTestLongConIsZero2(RunInfo info) { + assertC2Compiled(info); + Asserts.assertEquals(-10_000_000_001L, testLongConIsZero2(10_000_000_000L)); + } + + @Test + @IR(failOn = {IRNode.ADD_I, IRNode.XOR_I}) + @IR(counts = {IRNode.SUB_I, "1"}) + public int testIntConIsOne1(int x) { + return ~x + 1; // transformed to 0 - x + } + + @Run(test = "testIntConIsOne1") + public void checkTestIntConIsOne1(RunInfo info) { + assertC2Compiled(info); + Asserts.assertEquals(-10, testIntConIsOne1(10)); + } + + @Test + @IR(failOn = {IRNode.ADD_I, IRNode.XOR_I}) + @IR(counts = {IRNode.SUB_I, "1"}) + public int testIntConIsNegOne2(int x) { + return ~(x + -1); // transformed to 0 - x + } + + @Run(test = "testIntConIsNegOne2") + public void checkTestIntConIsNegOne2(RunInfo info) { + assertC2Compiled(info); + Asserts.assertEquals(-10, testIntConIsNegOne2(10)); + } + + @Test + @IR(failOn = {IRNode.ADD_L, IRNode.XOR_L}) + @IR(counts = {IRNode.SUB_L, "1"}) + public long testLongConIsOne1(long x) { + return ~x + 1L; // transformed to 0 - x + } + + @Run(test = "testLongConIsOne1") + public void checkTestLongConIsOne1(RunInfo info) { + assertC2Compiled(info); + Asserts.assertEquals(-10_000_000_000L, testLongConIsOne1(10_000_000_000L)); + } + + @Test + @IR(failOn = {IRNode.ADD_L, IRNode.XOR_L}) + @IR(counts = {IRNode.SUB_L, "1"}) + public long testLongConIsNegOne2(long x) { + return ~(x + -1L); // transformed to 0 - x + } + + @Run(test = "testLongConIsNegOne2") + public void checkTestLongConIsNegOne2(RunInfo info) { + assertC2Compiled(info); + Asserts.assertEquals(-10_000_000_000L, testLongConIsNegOne2(10_000_000_000L)); + } + + @Test + @IR(failOn = {IRNode.ADD_I, IRNode.XOR_I}) + @IR(counts = {IRNode.SUB_I, "1"}) + public int testIntConMinusOneIsUnderflow1(int x) { + return ~x + Integer.MIN_VALUE; // transformed to Integer.MAX_VALUE - x + } + + @Run(test = "testIntConMinusOneIsUnderflow1") + public void checkTestIntConMinusOneIsUnderflow1(RunInfo info) { + assertC2Compiled(info); + Asserts.assertEquals(2147483637, testIntConMinusOneIsUnderflow1(10)); + } + + @Test + @IR(failOn = {IRNode.ADD_I, IRNode.XOR_I}) + @IR(counts = {IRNode.SUB_I, "1"}) + public int testIntNegConMinusOneIsUnderflow2(int x) { + return ~(x + Integer.MIN_VALUE); // transformed to Integer.MAX_VALUE - x + } + + @Run(test = "testIntNegConMinusOneIsUnderflow2") + public void checkTestIntNegConMinusOneIsUnderflow2(RunInfo info) { + assertC2Compiled(info); + Asserts.assertEquals(2147483637, testIntNegConMinusOneIsUnderflow2(10)); + } + + @Test + @IR(failOn = {IRNode.ADD_L, IRNode.XOR_L}) + @IR(counts = {IRNode.SUB_L, "1"}) + public long testLongConMinusOneIsUnderflow1(long x) { + return ~x + Long.MIN_VALUE; // transformed to Long.MAX_VALUE - x + } + + @Run(test = "testLongConMinusOneIsUnderflow1") + public void checkTestLongConMinusOneIsUnderflow1(RunInfo info) { + assertC2Compiled(info); + Asserts.assertEquals(9223372036854775797L, testLongConMinusOneIsUnderflow1(10)); + } + + @Test + @IR(failOn = {IRNode.ADD_L, IRNode.XOR_L}) + @IR(counts = {IRNode.SUB_L, "1"}) + public long testLongNegConMinusOneIsUnderflow2(long x) { + return ~(x + Long.MIN_VALUE); // transformed to Long.MAX_VALUE - x + } + + @Run(test = "testLongNegConMinusOneIsUnderflow2") + public void checkTestLongNegConMinusOneIsUnderflow2(RunInfo info) { + assertC2Compiled(info); + Asserts.assertEquals(9223372036854775797L, testLongNegConMinusOneIsUnderflow2(10)); + } + + @Test + @IR(failOn = {IRNode.ADD_I, IRNode.XOR_I}) + @IR(counts = {IRNode.SUB_I, "1"}) + public int testIntResultIsUnderflow1(int x) { + return ~x + -2147483638; // transformed to -2147483639 - x + } + + @Run(test = "testIntResultIsUnderflow1") + public void checkTestIntResultIsUnderflow1(RunInfo info) { + assertC2Compiled(info); + Asserts.assertEquals(Integer.MAX_VALUE, testIntResultIsUnderflow1(10)); + } + + @Test + @IR(failOn = {IRNode.ADD_I, IRNode.XOR_I}) + @IR(counts = {IRNode.SUB_I, "1"}) + public int testIntResultIsUnderflow2(int x) { + return ~(x + 2147483638); // transformed to -2147483639 - x + } + + @Run(test = "testIntResultIsUnderflow2") + public void checkTestIntResultIsUnderflow2(RunInfo info) { + assertC2Compiled(info); + Asserts.assertEquals(Integer.MAX_VALUE, testIntResultIsUnderflow2(10)); + } + + @Test + @IR(failOn = {IRNode.ADD_L, IRNode.XOR_L}) + @IR(counts = {IRNode.SUB_L, "1"}) + public long testLongResultIsUnderflow1(long x) { + return ~x + -9223372036854775798L; // transformed to -9223372036854775799L - x + } + + @Run(test = "testLongResultIsUnderflow1") + public void checkTestLongResultIsUnderflow1(RunInfo info) { + assertC2Compiled(info); + Asserts.assertEquals(Long.MAX_VALUE, testLongResultIsUnderflow1(10)); + } + + @Test + @IR(failOn = {IRNode.ADD_L, IRNode.XOR_L}) + @IR(counts = {IRNode.SUB_L, "1"}) + public long testLongResultIsUnderflow2(long x) { + return ~(x + 9223372036854775798L); // transformed to -9223372036854775799L - x + } + + @Run(test = "testLongResultIsUnderflow2") + public void checkTestLongResultIsUnderflow2(RunInfo info) { + assertC2Compiled(info); + Asserts.assertEquals(Long.MAX_VALUE, testLongResultIsUnderflow2(10)); + } + + @Test + @IR(failOn = {IRNode.ADD_I, IRNode.XOR_I}) + @IR(counts = {IRNode.SUB_I, "1"}) + public int testIntResultIsOverflow1(int x) { + return ~x + 2147483637; // transformed to 2147483646 - x + } + + @Run(test = "testIntResultIsOverflow1") + public void checkTestIntResultIsOverflow1(RunInfo info) { + assertC2Compiled(info); + Asserts.assertEquals(Integer.MIN_VALUE, testIntResultIsOverflow1(-12)); + } + @Test + @IR(failOn = {IRNode.ADD_I, IRNode.XOR_I}) + @IR(counts = {IRNode.SUB_I, "1"}) + public int testIntResultIsOverflow2(int x) { + return ~(x + -2147483637); // transformed to 2147483646 - x + } + + @Run(test = "testIntResultIsOverflow2") + public void checkTestIntResultIsOverflow2(RunInfo info) { + assertC2Compiled(info); + Asserts.assertEquals(Integer.MIN_VALUE, testIntResultIsOverflow2(-12)); + } + + @Test + @IR(failOn = {IRNode.ADD_L, IRNode.XOR_L}) + @IR(counts = {IRNode.SUB_L, "1"}) + public long testLongResultIsOverflow1(long x) { + return ~x + 9223372036854775797L; // transformed to 9223372036854775798L - x + } + + @Run(test = "testLongResultIsOverflow1") + public void checkTestLongResultIsOverflow1(RunInfo info) { + assertC2Compiled(info); + Asserts.assertEquals(Long.MIN_VALUE, testLongResultIsOverflow1(-12)); + } + + @Test + @IR(failOn = {IRNode.ADD_L, IRNode.XOR_L}) + @IR(counts = {IRNode.SUB_L, "1"}) + public long testLongResultIsOverflow2(long x) { + return ~(x + -9223372036854775797L); // transformed to 9223372036854775798L - x + } + + @Run(test = "testLongResultIsOverflow2") + public void checkTestLongResultIsOverflow2(RunInfo info) { + assertC2Compiled(info); + Asserts.assertEquals(Long.MIN_VALUE, testLongResultIsOverflow2(-12)); + } + + private void assertC2Compiled(RunInfo info) { + // Test VM allows C2 to work + Asserts.assertTrue(info.isC2CompilationEnabled()); + if (!info.isWarmUp()) { + // C2 compilation happens + Asserts.assertTrue(info.isTestC2Compiled()); + } + } +} diff --git a/test/hotspot/jtreg/compiler/c2/irTests/TestIRLShiftIdeal_XPlusX_LShiftC.java b/test/hotspot/jtreg/compiler/c2/irTests/TestIRLShiftIdeal_XPlusX_LShiftC.java new file mode 100644 index 0000000000000000000000000000000000000000..dc42ff9cdc13c3a46c02723624aa952ce4be0b80 --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/irTests/TestIRLShiftIdeal_XPlusX_LShiftC.java @@ -0,0 +1,151 @@ +/* + * 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. + */ + +package compiler.c2.irTests; + +import jdk.test.lib.Asserts; +import compiler.lib.ir_framework.*; + +/* + * @test + * @bug 8278114 + * @summary Test that transformation from (x + x) >> c to x >> (c + 1) works as intended. + * @library /test/lib / + * @run driver compiler.c2.irTests.TestIRLShiftIdeal_XPlusX_LShiftC + */ +public class TestIRLShiftIdeal_XPlusX_LShiftC { + + private static final int[] INT_IN = { + -10, -2, -1, 0, 1, 2, 10, + 0x8000_0000, 0x7FFF_FFFF, 0x5678_1234, + }; + + private static final int[][] INT_OUT = { + // Do testInt0(x) for each x in INT_IN + { + -160, -32, -16, 0, 16, 32, 160, + 0x0000_0000, 0xFFFF_FFF0, 0x6781_2340, + }, + + // Do testInt1(x) for each x in INT_IN + { + -10485760, -2097152, -1048576, 0, 1048576, 2097152, 10485760, + 0x0000_0000, 0xFFF0_0000, 0x2340_0000, + }, + }; + + private static final long[] LONG_IN = { + -10L, -2L, -1L, 0L, 1L, 2L, 10L, + 0x8000_0000_0000_0000L, 0x7FFF_FFFF_FFFF_FFFFL, 0x5678_1234_4321_8765L, + }; + + private static final long[][] LONG_OUT = { + // Do testLong0(x) for each x in LONG_IN + { + -160L, -32L, -16L, 0L, 16L, 32L, 160L, + 0x0000_0000_0000_0000L, 0xFFFF_FFFF_FFFF_FFF0L, 0x6781_2344_3218_7650L, + }, + + // Do testLong1(x) for each x in LONG_IN + { + -687194767360L, -137438953472L, -68719476736L, 0L, 68719476736L, 137438953472L, 687194767360L, + 0x0000_0000_0000_0000L, 0xFFFF_FFF0_0000_0000L, 0x3218_7650_0000_0000L, + }, + }; + + public static void main(String[] args) { + TestFramework.run(); + } + + @Test + @IR(failOn = {IRNode.ADD_I, IRNode.MUL_I}) + @IR(counts = {IRNode.LSHIFT_I, "1"}) + public int testInt0(int x) { + return (x + x) << 3; // transformed to x << 4 + } + + @Run(test = "testInt0") + public void checkTestInt0(RunInfo info) { + assertC2Compiled(info); + for (int i = 0; i < INT_IN.length; i++) { + Asserts.assertEquals(INT_OUT[0][i], testInt0(INT_IN[i])); + } + } + + @Test + @IR(failOn = {IRNode.MUL_I}) + @IR(counts = {IRNode.LSHIFT_I, "1", + IRNode.ADD_I, "1"}) + public int testInt1(int x) { + return (x + x) << 19; // no transformation because 19 is + // greater than 16 (see implementation + // in LShiftINode::Ideal) + } + + @Run(test = "testInt1") + public void checkTestInt1(RunInfo info) { + assertC2Compiled(info); + for (int i = 0; i < INT_IN.length; i++) { + Asserts.assertEquals(INT_OUT[1][i], testInt1(INT_IN[i])); + } + } + + @Test + @IR(failOn = {IRNode.ADD_L, IRNode.MUL_L}) + @IR(counts = {IRNode.LSHIFT_L, "1"}) + public long testLong0(long x) { + return (x + x) << 3; // transformed to x << 4 + } + + @Run(test = "testLong0") + public void checkTestLong0(RunInfo info) { + assertC2Compiled(info); + for (int i = 0; i < LONG_IN.length; i++) { + Asserts.assertEquals(LONG_OUT[0][i], testLong0(LONG_IN[i])); + } + } + + @Test + @IR(failOn = {IRNode.ADD_L, IRNode.MUL_L}) + @IR(counts = {IRNode.LSHIFT_L, "1"}) + public long testLong1(long x) { + return (x + x) << 35; // transformed to x << 36 + } + + @Run(test = "testLong1") + public void checkTestLong1(RunInfo info) { + assertC2Compiled(info); + for (int i = 0; i < LONG_IN.length; i++) { + Asserts.assertEquals(LONG_OUT[1][i], testLong1(LONG_IN[i])); + } + } + + private void assertC2Compiled(RunInfo info) { + // Test VM allows C2 to work + Asserts.assertTrue(info.isC2CompilationEnabled()); + if (!info.isWarmUp()) { + // C2 compilation happens + Asserts.assertTrue(info.isTestC2Compiled()); + } + } +} diff --git a/test/hotspot/jtreg/compiler/c2/irTests/TestIterativeEA.java b/test/hotspot/jtreg/compiler/c2/irTests/TestIterativeEA.java new file mode 100644 index 0000000000000000000000000000000000000000..1bfaebabec84d299450871444ba9878a4d0c0849 --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/irTests/TestIterativeEA.java @@ -0,0 +1,128 @@ +/* + * 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. + */ + +package compiler.c2.irTests; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import jdk.test.lib.Asserts; +import compiler.lib.ir_framework.*; + +/* + * @test + * @bug 8276455 + * @summary Test C2 iterative Escape Analysis to remove all allocations in test + * @library /test/lib / + * @run driver compiler.c2.irTests.TestIterativeEA + */ +public class TestIterativeEA { + + public static void main(String[] args) { + TestFramework.run(); + } + + static class MyClass { + int val; + public MyClass(int val) { + this.val = val; + } + } + + static class AbstractClass { + final int unused; + public AbstractClass() { + unused = 42; + } + } + + static class HolderWithSuper extends AbstractClass { + final MyClass obj; + public HolderWithSuper(MyClass obj) { + this.obj = obj; + } + } + + static class Holder { + final MyClass obj; + public Holder(MyClass obj) { + this.obj = obj; + } + } + + static class GenericHolder { + final Object obj; + public GenericHolder(Object obj) { + this.obj = obj; + } + } + + @Test + @Arguments({ Argument.RANDOM_EACH }) + @IR(failOn = { IRNode.ALLOC }) + public static int testSlow(int val) { + MyClass obj = new MyClass(val); + HolderWithSuper h1 = new HolderWithSuper(obj); + GenericHolder h2 = new GenericHolder(h1); + return ((HolderWithSuper)h2.obj).obj.val; + } + + @Test + @Arguments({ Argument.RANDOM_EACH }) + @IR(failOn = { IRNode.ALLOC }) + public static int testFast(int val) { + MyClass obj = new MyClass(val); + Holder h1 = new Holder(obj); + GenericHolder h2 = new GenericHolder(h1); + return ((Holder)h2.obj).obj.val; + } + + static class A { + int i; + public A(int i) { + this.i = i; + } + } + + static class B { + A a; + public B(A a) { + this.a = a; + } + } + + static class C { + B b; + public C(B b) { + this.b = b; + } + } + + @Test + @Arguments({ Argument.RANDOM_EACH }) + @IR(failOn = { IRNode.ALLOC }) + static int testNested(int i) { + C c = new C(new B(new A(i))); + return c.b.a.i; + } +} diff --git a/test/hotspot/jtreg/compiler/c2/irTests/TestLongRangeChecks.java b/test/hotspot/jtreg/compiler/c2/irTests/TestLongRangeChecks.java index 298f00942011115c9fccd4228d27ffa57e0b5675..87bfd94388830dd0558325d7f60e076f9a73b0d1 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/TestLongRangeChecks.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/TestLongRangeChecks.java @@ -28,7 +28,7 @@ import java.util.Objects; /* * @test - * @bug 8259609 + * @bug 8259609 8276116 * @summary C2: optimize long range checks in long counted loops * @library /test/lib / * @run driver compiler.c2.irTests.TestLongRangeChecks @@ -36,13 +36,15 @@ import java.util.Objects; public class TestLongRangeChecks { public static void main(String[] args) { - TestFramework.run(); + TestFramework.runWithFlags("-XX:-UseCountedLoopSafepoints"); + TestFramework.runWithFlags("-XX:+UseCountedLoopSafepoints", "-XX:LoopStripMiningIter=1"); + TestFramework.runWithFlags("-XX:+UseCountedLoopSafepoints", "-XX:LoopStripMiningIter=1000"); } @Test - @IR(counts = { IRNode.LOOP, "1"}) - @IR(failOn = { IRNode.COUNTEDLOOP}) + @IR(counts = { IRNode.LOOP, "1" }) + @IR(failOn = { IRNode.COUNTEDLOOP }) public static void testStridePosScalePos(long start, long stop, long length, long offset) { final long scale = 1; final long stride = 1; @@ -60,4 +62,186 @@ public class TestLongRangeChecks { private void testStridePosScalePos_runner() { testStridePosScalePos(0, 100, 100, 0); } + + @Test + @IR(counts = { IRNode.LOOP, "1" }) + @IR(failOn = { IRNode.COUNTEDLOOP }) + public static void testStridePosScalePosInIntLoop1(int start, int stop, long length, long offset) { + final long scale = 2; + final int stride = 1; + + // Same but with int loop + for (int i = start; i < stop; i += stride) { + Objects.checkIndex(scale * i + offset, length); + } + } + + @Run(test = "testStridePosScalePosInIntLoop1") + private void testStridePosScalePosInIntLoop1_runner() { + testStridePosScalePosInIntLoop1(0, 100, 200, 0); + } + + @Test + @IR(counts = { IRNode.LOOP, "1" }) + @IR(failOn = { IRNode.COUNTEDLOOP }) + public static void testStridePosScalePosInIntLoop2(int start, int stop, long length, long offset) { + final int scale = 2; + final int stride = 1; + + // Same but with int loop + for (int i = start; i < stop; i += stride) { + Objects.checkIndex(scale * i + offset, length); + } + } + + @Run(test = "testStridePosScalePosInIntLoop2") + private void testStridePosScalePosInIntLoop2_runner() { + testStridePosScalePosInIntLoop2(0, 100, 200, 0); + } + + @Test + @IR(counts = { IRNode.LOOP, "1"}) + @IR(failOn = { IRNode.COUNTEDLOOP}) + public static void testStrideNegScaleNeg(long start, long stop, long length, long offset) { + final long scale = -1; + final long stride = 1; + for (long i = stop; i > start; i -= stride) { + Objects.checkIndex(scale * i + offset, length); + } + } + + @Run(test = "testStrideNegScaleNeg") + private void testStrideNegScaleNeg_runner() { + testStrideNegScaleNeg(0, 100, 100, 100); + } + + @Test + @IR(counts = { IRNode.LOOP, "1" }) + @IR(failOn = { IRNode.COUNTEDLOOP }) + public static void testStrideNegScaleNegInIntLoop1(int start, int stop, long length, long offset) { + final long scale = -2; + final int stride = 1; + + for (int i = stop; i > start; i -= stride) { + Objects.checkIndex(scale * i + offset, length); + } + } + + @Run(test = "testStrideNegScaleNegInIntLoop1") + private void testStrideNegScaleNegInIntLoop1_runner() { + testStrideNegScaleNegInIntLoop1(0, 100, 200, 200); + } + + @Test + @IR(counts = { IRNode.LOOP, "1" }) + @IR(failOn = { IRNode.COUNTEDLOOP }) + public static void testStrideNegScaleNegInIntLoop2(int start, int stop, long length, long offset) { + final int scale = -2; + final int stride = 1; + + for (int i = stop; i > start; i -= stride) { + Objects.checkIndex(scale * i + offset, length); + } + } + + @Run(test = "testStrideNegScaleNegInIntLoop2") + private void testStrideNegScaleNegInIntLoop2_runner() { + testStrideNegScaleNegInIntLoop2(0, 100, 200, 200); + } + + @Test + @IR(counts = { IRNode.LOOP, "1"}) + @IR(failOn = { IRNode.COUNTEDLOOP}) + public static void testStrideNegScalePos(long start, long stop, long length, long offset) { + final long scale = 1; + final long stride = 1; + for (long i = stop-1; i >= start; i -= stride) { + Objects.checkIndex(scale * i + offset, length); + } + } + + @Run(test = "testStrideNegScalePos") + private void testStrideNegScalePos_runner() { + testStrideNegScalePos(0, 100, 100, 0); + } + + @Test + @IR(counts = { IRNode.LOOP, "1" }) + @IR(failOn = { IRNode.COUNTEDLOOP }) + public static void testStrideNegScalePosInIntLoop1(int start, int stop, long length, long offset) { + final long scale = 2; + final int stride = 1; + for (int i = stop-1; i >= start; i -= stride) { + Objects.checkIndex(scale * i + offset, length); + } + } + + @Run(test = "testStrideNegScalePosInIntLoop1") + private void testStrideNegScalePosInIntLoop1_runner() { + testStrideNegScalePosInIntLoop1(0, 100, 200, 0); + } + + @Test + @IR(counts = { IRNode.LOOP, "1" }) + @IR(failOn = { IRNode.COUNTEDLOOP }) + public static void testStrideNegScalePosInIntLoop2(int start, int stop, long length, long offset) { + final int scale = 2; + final int stride = 1; + for (int i = stop-1; i >= start; i -= stride) { + Objects.checkIndex(scale * i + offset, length); + } + } + + @Run(test = "testStrideNegScalePosInIntLoop2") + private void testStrideNegScalePosInIntLoop2_runner() { + testStrideNegScalePosInIntLoop1(0, 100, 200, 0); + } + + @Test + @IR(counts = { IRNode.LOOP, "1"}) + @IR(failOn = { IRNode.COUNTEDLOOP}) + public static void testStridePosScaleNeg(long start, long stop, long length, long offset) { + final long scale = -1; + final long stride = 1; + for (long i = start; i < stop; i += stride) { + Objects.checkIndex(scale * i + offset, length); + } + } + + @Run(test = "testStridePosScaleNeg") + private void testStridePosScaleNeg_runner() { + testStridePosScaleNeg(0, 100, 100, 99); + } + + @Test + @IR(counts = { IRNode.LOOP, "1"}) + @IR(failOn = { IRNode.COUNTEDLOOP}) + public static void testStridePosScaleNegInIntLoop1(int start, int stop, long length, long offset) { + final long scale = -2; + final int stride = 1; + for (int i = start; i < stop; i += stride) { + Objects.checkIndex(scale * i + offset, length); + } + } + + @Run(test = "testStridePosScaleNegInIntLoop1") + private void testStridePosScaleNegInIntLoop1_runner() { + testStridePosScaleNegInIntLoop1(0, 100, 200, 198); + } + + @Test + @IR(counts = { IRNode.LOOP, "1"}) + @IR(failOn = { IRNode.COUNTEDLOOP}) + public static void testStridePosScaleNegInIntLoop2(int start, int stop, long length, long offset) { + final int scale = -2; + final int stride = 1; + for (int i = start; i < stop; i += stride) { + Objects.checkIndex(scale * i + offset, length); + } + } + + @Run(test = "testStridePosScaleNegInIntLoop2") + private void testStridePosScaleNegInIntLoop2_runner() { + testStridePosScaleNegInIntLoop1(0, 100, 200, 198); + } } diff --git a/test/hotspot/jtreg/compiler/c2/irTests/TestRemixAddressExpressions.java b/test/hotspot/jtreg/compiler/c2/irTests/TestRemixAddressExpressions.java new file mode 100644 index 0000000000000000000000000000000000000000..f35b9273a56185fbc4b0584e2592e8c52125ecb8 --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/irTests/TestRemixAddressExpressions.java @@ -0,0 +1,106 @@ +/* + * Copyright (c) 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. + */ + +package compiler.c2.irTests; + +import compiler.lib.ir_framework.*; + +/* + * @test + * @bug 8278784 + * @summary C2: Refactor PhaseIdealLoop::remix_address_expressions() so it operates on longs + * @library /test/lib / + * @run driver compiler.c2.irTests.TestRemixAddressExpressions + */ + +public class TestRemixAddressExpressions { + public static void main(String[] args) { + TestFramework.run(); + } + + @Test + @IR(counts = { IRNode.ADD_I, "1", IRNode.LSHIFT_I, "2" }) + @Arguments({Argument.RANDOM_EACH, Argument.RANDOM_EACH}) + public static float invPlusVarLshiftInt(int inv, int scale) { + float res = 0; + for (int i = 1; i < 100; i *= 11) { + res += (i + inv) << scale; + } + return res; + } + + @Test + @IR(counts = { IRNode.ADD_L, "1", IRNode.LSHIFT_L, "2" }) + @Arguments({Argument.RANDOM_EACH, Argument.RANDOM_EACH}) + public static float invPlusVarLshiftLong(long inv, int scale) { + float res = 0; + for (long i = 1; i < 100; i *= 11) { + res += (i + inv) << scale; + } + return res; + } + + @Test + @IR(counts = { IRNode.ADD_I, "1", IRNode.SUB_I, "1", IRNode.LSHIFT_I, "2" }) + @Arguments({Argument.RANDOM_EACH, Argument.RANDOM_EACH}) + public static float invMinusVarLshiftInt(int inv, int scale) { + float res = 0; + for (int i = 1; i < 100; i *= 11) { + res += (inv - i) << scale; + } + return res; + } + + @Test + @IR(counts = { IRNode.ADD_L, "1", IRNode.SUB_L, "1", IRNode.LSHIFT_L, "2" }) + @Arguments({Argument.RANDOM_EACH, Argument.RANDOM_EACH}) + public static float invMinusVarLshiftLong(long inv, int scale) { + float res = 0; + for (long i = 1; i < 100; i *= 11) { + res += (inv - i) << scale; + } + return res; + } + + @Test + @IR(counts = { IRNode.ADD_I, "1", IRNode.SUB_I, "1", IRNode.LSHIFT_I, "2" }) + @Arguments({Argument.RANDOM_EACH, Argument.RANDOM_EACH}) + public static float varMinusInvLshiftInt(int inv, int scale) { + float res = 0; + for (int i = 1; i < 100; i *= 11) { + res += (i - inv) << scale; + } + return res; + } + + @Test + @IR(counts = { IRNode.ADD_L, "1", IRNode.SUB_L, "1", IRNode.LSHIFT_L, "2" }) + @Arguments({Argument.RANDOM_EACH, Argument.RANDOM_EACH}) + public static float varMinusInvLshiftLong(long inv, int scale) { + float res = 0; + for (long i = 1; i < 100; i *= 11) { + res += (i - inv) << scale; + } + return res; + } +} diff --git a/test/hotspot/jtreg/compiler/c2/irTests/TestShiftAndMask.java b/test/hotspot/jtreg/compiler/c2/irTests/TestShiftAndMask.java new file mode 100644 index 0000000000000000000000000000000000000000..3423ca075b794162e627e4d69a274214186e0e9c --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/irTests/TestShiftAndMask.java @@ -0,0 +1,340 @@ +/* + * Copyright (c) 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. + */ + +package compiler.c2.irTests; + +import compiler.lib.ir_framework.*; +import jdk.test.lib.Utils; +import java.util.Random; + +/* + * @test + * @bug 8277850 8278949 + * @summary C2: optimize mask checks in counted loops + * @library /test/lib / + * @run driver compiler.c2.irTests.TestShiftAndMask + */ + +public class TestShiftAndMask { + private static final Random RANDOM = Utils.getRandomInstance(); + + public static void main(String[] args) { + TestFramework.run(); + } + + @Test + @Arguments(Argument.RANDOM_EACH) + @IR(failOn = { IRNode.AND_I, IRNode.LSHIFT_I }) + public static int shiftMaskInt(int i) { + return (i << 2) & 3; // transformed to: return 0; + } + + @Check(test = "shiftMaskInt") + public static void checkShiftMaskInt(int res) { + if (res != 0) { + throw new RuntimeException("incorrect result: " + res); + } + } + + @Test + @Arguments(Argument.RANDOM_EACH) + @IR(failOn = { IRNode.AND_L, IRNode.LSHIFT_L }) + public static long shiftMaskLong(long i) { + return (i << 2) & 3; // transformed to: return 0; + } + + + @Check(test = "shiftMaskLong") + public static void checkShiftMaskLong(long res) { + if (res != 0) { + throw new RuntimeException("incorrect result: " + res); + } + } + + static volatile int barrier; + + @Test + @Arguments({Argument.RANDOM_EACH, Argument.BOOLEAN_TOGGLE_FIRST_TRUE}) + @IR(failOn = { IRNode.AND_I, IRNode.LSHIFT_I }) + public static int shiftNonConstMaskInt(int i, boolean flag) { + int mask; + if (flag) { + barrier = 42; + mask = 3; + } else { + mask = 1; + } + return mask & (i << 2); // transformed to: return 0; + } + + @Check(test = "shiftNonConstMaskInt") + public static void checkShiftNonConstMaskInt(int res) { + if (res != 0) { + throw new RuntimeException("incorrect result: " + res); + } + } + + @Test + @Arguments({Argument.RANDOM_EACH, Argument.BOOLEAN_TOGGLE_FIRST_TRUE}) + @IR(failOn = { IRNode.AND_L, IRNode.LSHIFT_L }) + public static long shiftNonConstMaskLong(long i, boolean flag) { + long mask; + if (flag) { + barrier = 42; + mask = 3; + } else { + mask = 1; + } + return mask & (i << 2); // transformed to: return 0; + } + + @Check(test = "shiftNonConstMaskLong") + public static void checkShiftNonConstMaskLong(long res) { + if (res != 0) { + throw new RuntimeException("incorrect result: " + res); + } + } + + @Test + @IR(counts = { IRNode.AND_I, "1" }) + @IR(failOn = { IRNode.ADD_I, IRNode.LSHIFT_I }) + public static int addShiftMaskInt(int i, int j) { + return (j + (i << 2)) & 3; // transformed to: return j & 3; + } + + @Run(test = "addShiftMaskInt") + public static void addShiftMaskInt_runner() { + int i = RANDOM.nextInt(); + int j = RANDOM.nextInt(); + int res = addShiftMaskInt(i, j); + if (res != (j & 3)) { + throw new RuntimeException("incorrect result: " + res); + } + } + + @Test + @IR(counts = { IRNode.AND_I, "1" }) + @IR(failOn = { IRNode.ADD_I, IRNode.LSHIFT_I }) + public static int addSshiftNonConstMaskInt(int i, int j, boolean flag) { + int mask; + if (flag) { + barrier = 42; + mask = 3; + } else { + mask = 1; + } + return mask & (j + (i << 2)); // transformed to: return j & mask; + } + + @Run(test = "addSshiftNonConstMaskInt") + public static void addSshiftNonConstMaskInt_runner() { + int i = RANDOM.nextInt(); + int j = RANDOM.nextInt(); + int res = addSshiftNonConstMaskInt(i, j, true); + if (res != (j & 3)) { + throw new RuntimeException("incorrect result: " + res); + } + res = addSshiftNonConstMaskInt(i, j, false); + if (res != (j & 1)) { + throw new RuntimeException("incorrect result: " + res); + } + } + + @Test + @IR(counts = { IRNode.AND_L, "1" }) + @IR(failOn = { IRNode.ADD_L, IRNode.LSHIFT_L }) + public static long addShiftMaskLong(long i, long j) { + return (j + (i << 2)) & 3; // transformed to: return j & 3; + } + + @Run(test = "addShiftMaskLong") + public static void addShiftMaskLong_runner() { + long i = RANDOM.nextLong(); + long j = RANDOM.nextLong(); + long res = addShiftMaskLong(i, j); + if (res != (j & 3)) { + throw new RuntimeException("incorrect result: " + res); + } + } + + @Test + @IR(counts = { IRNode.AND_L, "1" }) + @IR(failOn = { IRNode.ADD_L, IRNode.LSHIFT_L }) + public static long addSshiftNonConstMaskLong(long i, long j, boolean flag) { + int mask; + if (flag) { + barrier = 42; + mask = 3; + } else { + mask = 1; + } + return mask & (j + (i << 2)); // transformed to: return j & mask; + } + + @Run(test = "addSshiftNonConstMaskLong") + public static void addSshiftNonConstMaskLong_runner() { + long i = RANDOM.nextLong(); + long j = RANDOM.nextLong(); + long res = addSshiftNonConstMaskLong(i, j, true); + if (res != (j & 3)) { + throw new RuntimeException("incorrect result: " + res); + } + res = addSshiftNonConstMaskLong(i, j, false); + if (res != (j & 1)) { + throw new RuntimeException("incorrect result: " + res); + } + } + + @Test + @Arguments({Argument.RANDOM_EACH, Argument.RANDOM_EACH}) + @IR(failOn = { IRNode.AND_I, IRNode.ADD_I, IRNode.LSHIFT_I }) + public static int addShiftMaskInt2(int i, int j) { + return ((j << 2) + (i << 2)) & 3; // transformed to: return 0; + } + + @Check(test = "addShiftMaskInt2") + public static void checkAddShiftMaskInt2(int res) { + if (res != 0) { + throw new RuntimeException("incorrect result: " + res); + } + } + + @Test + @Arguments({Argument.RANDOM_EACH, Argument.RANDOM_EACH}) + @IR(failOn = { IRNode.AND_L, IRNode.ADD_L, IRNode.LSHIFT_L }) + public static long addShiftMaskLong2(long i, long j) { + return ((j << 2) + (i << 2)) & 3; // transformed to: return 0; + } + + @Check(test = "addShiftMaskLong2") + public static void checkAddShiftMaskLong2(long res) { + if (res != 0) { + throw new RuntimeException("incorrect result: " + res); + } + } + + // Try to get add inputs swapped compared to other tests + @Test + @IR(counts = { IRNode.AND_I, "1" }) + @IR(failOn = { IRNode.ADD_I, IRNode.LSHIFT_I }) + public static int addShiftMaskInt3(int i, long j) { + int add1 = (i << 2); + int add2 = (int)j; + return (add1 + add2) & 3; // transformed to: return j & 3; + } + + @Run(test = "addShiftMaskInt3") + public static void addShiftMaskInt3_runner() { + int i = RANDOM.nextInt(); + int j = RANDOM.nextInt(); + int res = addShiftMaskInt3(i, j); + if (res != (j & 3)) { + throw new RuntimeException("incorrect result: " + res); + } + } + + @Test + @IR(counts = { IRNode.AND_L, "1" }) + @IR(failOn = { IRNode.ADD_L, IRNode.LSHIFT_L }) + public static long addShiftMaskLong3(long i, float j) { + long add1 = (i << 2); + long add2 = (long)j; + return (add1 + add2) & 3; // transformed to: return j & 3; + } + + @Run(test = "addShiftMaskLong3") + public static void addShiftMaskLong3_runner() { + long i = RANDOM.nextLong(); + float j = RANDOM.nextFloat(); + long res = addShiftMaskLong3(i, j); + if (res != (((long)j) & 3)) { + throw new RuntimeException("incorrect result: " + res); + } + } + + @Test + @Arguments({Argument.RANDOM_EACH}) + @IR(failOn = { IRNode.AND_L, IRNode.LSHIFT_I }) + public static long shiftConvMask(int i) { + return ((long)(i << 2)) & 3; // transformed to: return 0; + } + + @Check(test = "shiftConvMask") + public static void checkShiftConvMask(long res) { + if (res != 0) { + throw new RuntimeException("incorrect result: " + res); + } + } + + @Test + @Arguments({Argument.RANDOM_EACH, Argument.BOOLEAN_TOGGLE_FIRST_TRUE}) + @IR(failOn = { IRNode.AND_L, IRNode.LSHIFT_L }) + public static long shiftNotConstConvMask(int i, boolean flag) { + long mask; + if (flag) { + barrier = 42; + mask = 3; + } else { + mask = 1; + } + return mask & ((long)(i << 2)); // transformed to: return 0; + } + + @Check(test = "shiftNotConstConvMask") + public static void checkShiftNotConstConvMask(long res) { + if (res != 0) { + throw new RuntimeException("incorrect result: " + res); + } + } + + @Test + @IR(counts = { IRNode.AND_L, "1" }) + @IR(failOn = { IRNode.ADD_L, IRNode.LSHIFT_I, IRNode.CONV_I2L }) + public static long addShiftConvMask(int i, long j) { + return (j + (i << 2)) & 3; // transformed to: return j & 3; + } + + @Run(test = "addShiftConvMask") + public static void addShiftConvMask_runner() { + int i = RANDOM.nextInt(); + long j = RANDOM.nextLong(); + long res = addShiftConvMask(i, j); + if (res != (j & 3)) { + throw new RuntimeException("incorrect result: " + res); + } + } + + @Test + @Arguments({Argument.RANDOM_EACH, Argument.RANDOM_EACH}) + @IR(failOn = { IRNode.AND_L, IRNode.ADD_L, IRNode.LSHIFT_L }) + public static long addShiftConvMask2(int i, int j) { + return (((long)(j << 2)) + ((long)(i << 2))) & 3; // transformed to: return 0; + } + + @Check(test = "addShiftConvMask2") + public static void checkAddShiftConvMask2(long res) { + if (res != 0) { + throw new RuntimeException("incorrect result: " + res); + } + } +} diff --git a/test/hotspot/jtreg/compiler/c2/irTests/TestSkeletonPredicates.java b/test/hotspot/jtreg/compiler/c2/irTests/TestSkeletonPredicates.java new file mode 100644 index 0000000000000000000000000000000000000000..79bcd16cfb252ff539cf3b57136d20e35f10e5be --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/irTests/TestSkeletonPredicates.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 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. + */ + +package compiler.c2.irTests; + +import compiler.lib.ir_framework.*; +import jdk.test.lib.Utils; +import java.util.Random; + +/* + * @test + * @bug 8278228 + * @summary C2: Improve identical back-to-back if elimination + * @library /test/lib / + * @run driver compiler.c2.irTests.TestSkeletonPredicates + */ + +public class TestSkeletonPredicates { + public static void main(String[] args) { + TestFramework.runWithFlags("-XX:-UseLoopPredicate", "-XX:LoopUnrollLimit=240", "-XX:+StressIGVN", "-XX:StressSeed=255527877"); + TestFramework.runWithFlags("-XX:-UseLoopPredicate", "-XX:LoopUnrollLimit=240", "-XX:+StressIGVN"); + } + + static volatile int barrier; + + @ForceInline + static boolean test1_helper(int start, int stop, double[] array1, double[] array2) { + for (int i = start; i < stop; i++) { + if ((i % 2) == 0) { + array1[i] = 42.42; + } else { + barrier = 0x42; + } + } + return false; + } + + @Test + @IR(counts = { IRNode.COUNTEDLOOP, "3" }) + static double[] test1(int stop, double[] array2) { + double[] array1 = null; + array1 = new double[10]; + for (int j = 0; j < stop; j++) { + if (test1_helper(8, j, array1, array2)) { + return null; + } + } + return array1; + } + + @Run(test = "test1") + void test1_runner() { + double[] array2 = new double[10]; + double[] array3 = new double[1000]; + test1_helper(1, 1000, array3, array3); + test1(11, array3); + } +} diff --git a/test/hotspot/jtreg/compiler/c2/irTests/TestSpecialCasesOf_AMinusB_Plus_CMinusD_InAddIdeal.java b/test/hotspot/jtreg/compiler/c2/irTests/TestSpecialCasesOf_AMinusB_Plus_CMinusD_InAddIdeal.java new file mode 100644 index 0000000000000000000000000000000000000000..4cbbcd9330131dcd07e1aba68b146bba29121299 --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/irTests/TestSpecialCasesOf_AMinusB_Plus_CMinusD_InAddIdeal.java @@ -0,0 +1,76 @@ +/* + * 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. + */ + +package compiler.c2.irTests; + +import jdk.test.lib.Asserts; +import compiler.lib.ir_framework.*; + +/* + * @test + * @bug 8278471 + * @summary Remove unreached rules in AddNode::IdealIL + * @library /test/lib / + * @run driver compiler.c2.irTests.TestSpecialCasesOf_AMinusB_Plus_CMinusD_InAddIdeal + */ +/* Test conversion from (a - b) + (b - c) to (a - c) and conversion + * from (a - b) + (c - a) to (c - b) have really happened so we can + * safely remove both. */ +public class TestSpecialCasesOf_AMinusB_Plus_CMinusD_InAddIdeal { + + public static void main(String[] args) { + TestFramework.run(); + } + + @Test + @Arguments({Argument.RANDOM_ONCE, Argument.RANDOM_ONCE, Argument.RANDOM_ONCE}) + @IR(failOn = {IRNode.ADD_I}) + @IR(counts = {IRNode.SUB_I, "1"}) + public int test1Int(int a, int b, int c) { + return (a - b) + (b - c); // transformed to a - c rather than (a + b) - (b + c) + } + + @Test + @Arguments({Argument.RANDOM_ONCE, Argument.RANDOM_ONCE, Argument.RANDOM_ONCE}) + @IR(failOn = {IRNode.ADD_L}) + @IR(counts = {IRNode.SUB_L, "1"}) + public long test1Long(long a, long b, long c) { + return (a - b) + (b - c); // transformed to a - c rather than (a + b) - (b + c) + } + + @Test + @Arguments({Argument.RANDOM_ONCE, Argument.RANDOM_ONCE, Argument.RANDOM_ONCE}) + @IR(failOn = {IRNode.ADD_I}) + @IR(counts = {IRNode.SUB_I, "1"}) + public int test2Int(int b, int a, int c) { // make sure inputs sorted + return (a - b) + (c - a); // transformed to c - b rather than (a + c) - (b + a) + } + + @Test + @Arguments({Argument.RANDOM_ONCE, Argument.RANDOM_ONCE, Argument.RANDOM_ONCE}) + @IR(failOn = {IRNode.ADD_L}) + @IR(counts = {IRNode.SUB_L, "1"}) + public long test2Long(long b, long a, long c) { // make sure inputs sorted + return (a - b) + (c - a); // transformed to return c - b rather than (a + c) - (b + a) + } +} diff --git a/test/hotspot/jtreg/compiler/c2/irTests/TestStripMiningDropsSafepoint.java b/test/hotspot/jtreg/compiler/c2/irTests/TestStripMiningDropsSafepoint.java new file mode 100644 index 0000000000000000000000000000000000000000..951b94ed1a7b6840ec58823dd6ad73f778ff0a8f --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/irTests/TestStripMiningDropsSafepoint.java @@ -0,0 +1,132 @@ +/* + * Copyright (c) 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. + */ + +package compiler.c2.irTests; + +import compiler.lib.ir_framework.*; + +/* + * @test + * @bug 8282045 + * @summary When loop strip mining fails, safepoints are removed from loop anyway + * @library /test/lib / + * @run driver compiler.c2.irTests.TestStripMiningDropsSafepoint + */ + +public class TestStripMiningDropsSafepoint { + public static void main(String[] args) { + TestFramework.runWithFlags("-XX:+UseCountedLoopSafepoints", "-XX:LoopStripMiningIter=1000", "-XX:LoopMaxUnroll=1", "-XX:-RangeCheckElimination"); + TestFramework.runWithFlags("-XX:+UseCountedLoopSafepoints", "-XX:LoopStripMiningIter=1000", "-XX:LoopMaxUnroll=1", "-XX:-RangeCheckElimination", "-XX:-PartialPeelLoop"); + } + + @Test + @IR(applyIf = { "PartialPeelLoop", "true" }, counts = { IRNode.COUNTEDLOOP, "1", IRNode.OUTERSTRIPMINEDLOOP, "1", IRNode.SAFEPOINT, "1" }) + private static void test1(int[] dst, int[] src) { + // Partial peel is applied. No side effect between exit and + // safepoint. + for (int i = 0; ; ) { + // prevent ciTypeFlow from cloning head + synchronized (new Object()) {} + i++; + if (i >= src.length) { + break; + } + dst[i] = src[i]; + if (i / 2 >= 2000) { + break; + } + } + } + + @Run(test = "test1") + private static void test1_runner() { + int[] array1 = new int[1000]; + int[] array2 = new int[10000]; + test1(array1, array1); + test1(array2, array2); + } + + @Test + @IR(applyIf = { "PartialPeelLoop", "true" }, counts = { IRNode.COUNTEDLOOP, "1", IRNode.SAFEPOINT, "1" }) + @IR(applyIf = { "PartialPeelLoop", "true" }, failOn = { IRNode.OUTERSTRIPMINEDLOOP }) + private static void test2(int[] dst, int[] src) { + // Partial peel is applied. Some side effect between exit and + // safepoint. + int v = src[0]; + for (int i = 0; ; ) { + synchronized (new Object()) {} + dst[i] = v; + i++; + if (i >= src.length) { + break; + } + v = src[i]; + if (i / 2 >= 2000) { + break; + } + } + } + + @Run(test = "test2") + private static void test2_runner() { + int[] array1 = new int[1000]; + int[] array2 = new int[10000]; + test2(array1, array1); + test2(array2, array2); + } + + @Test + @IR(applyIf = { "PartialPeelLoop", "false" }, counts = { IRNode.COUNTEDLOOP, "1", IRNode.OUTERSTRIPMINEDLOOP, "1", IRNode.SAFEPOINT, "1" }) + private static void test3(int[] dst, int[] src) { + int v = src[0]; + for (int i = 0; ; ) { + synchronized (new Object()) {} + dst[i] = v; + int inc = test3_helper(2); + v = src[i]; + i += (inc / 2); + if (i >= src.length) { + break; + } + for (int j = 0; j < 10; j++) { + } + // safepoint on backedge + } + } + + private static int test3_helper(int stop) { + int i = 1; + do { + synchronized (new Object()) {} + i *= 2; + } while (i < stop); + return i; + } + + @Run(test = "test3") + private static void test3_runner() { + int[] array1 = new int[1000]; + test3(array1, array1); + test3_helper(10); + } +} diff --git a/test/hotspot/jtreg/compiler/c2/irTests/TestUnsignedComparison.java b/test/hotspot/jtreg/compiler/c2/irTests/TestUnsignedComparison.java new file mode 100644 index 0000000000000000000000000000000000000000..f50075cbfa4ba8fcc2ab7e6b2d204dd1c2fd30c2 --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/irTests/TestUnsignedComparison.java @@ -0,0 +1,345 @@ +/* + * 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. + */ + +package compiler.c2.irTests; + +import jdk.test.lib.Asserts; +import compiler.lib.ir_framework.*; + +/* + * @test + * @bug 8276162 + * @summary Test that unsigned comparison transformation works as intended. + * @library /test/lib / + * @run driver compiler.c2.irTests.TestUnsignedComparison + */ +public class TestUnsignedComparison { + private static final String CMP_REGEX = "(\\d+(\\s){2}(" + "Cmp(I|L)" + ".*)+(\\s){2}===.*)"; + private static final String CMPU_REGEX = "(\\d+(\\s){2}(" + "Cmp(U|UL)" + ".*)+(\\s){2}===.*)"; + private static final String ADD_REGEX = "(\\d+(\\s){2}(" + "Add(I|L)" + ".*)+(\\s){2}===.*)"; + + private static final int INT_MIN = Integer.MIN_VALUE; + private static final long LONG_MIN = Long.MIN_VALUE; + + // Integers are sorted in unsignedly increasing order + private static final int[] INT_DATA = { + 0, + 1, + 2, + 3, + 0x8000_0000, + 0x8000_0001, + 0x8000_0002, + 0x8000_0003, + 0xFFFF_FFFE, + 0xFFFF_FFFF, + }; + + // Longs are sorted in unsignedly increasing order + private static final long[] LONG_DATA = { + 0L, + 1L, + 2L, + 3L, + 0x00000000_80000000L, + 0x00000000_FFFFFFFFL, + 0x00000001_00000000L, + 0x80000000_00000000L, + 0x80000000_00000001L, + 0x80000000_00000002L, + 0x80000000_00000003L, + 0x80000000_80000000L, + 0xFFFFFFFF_FFFFFFFEL, + 0xFFFFFFFF_FFFFFFFFL, + }; + + // Constants to compare against, add MIN_VALUE beforehand for convenience + private static final int CONST_INDEX = 6; + private static final int INT_CONST = INT_DATA[CONST_INDEX] + INT_MIN; + private static final long LONG_CONST = LONG_DATA[CONST_INDEX] + LONG_MIN; + + public static void main(String[] args) { + TestFramework framework = new TestFramework(); + framework.start(); + } + + @Test + @IR(failOn = {CMP_REGEX, ADD_REGEX}) + @IR(counts = {CMPU_REGEX, "1"}) + public boolean testIntVarEQ(int x, int y) { + return x + INT_MIN == y + INT_MIN; + } + + @Test + @IR(failOn = {CMP_REGEX, ADD_REGEX}) + @IR(counts = {CMPU_REGEX, "1"}) + public boolean testIntVarNE(int x, int y) { + return x + INT_MIN != y + INT_MIN; + } + + @Test + @IR(failOn = {CMP_REGEX, ADD_REGEX}) + @IR(counts = {CMPU_REGEX, "1"}) + public boolean testIntVarLT(int x, int y) { + return x + INT_MIN < y + INT_MIN; + } + + @Test + @IR(failOn = {CMP_REGEX, ADD_REGEX}) + @IR(counts = {CMPU_REGEX, "1"}) + public boolean testIntVarLE(int x, int y) { + return x + INT_MIN <= y + INT_MIN; + } + + @Test + @IR(failOn = {CMP_REGEX, ADD_REGEX}) + @IR(counts = {CMPU_REGEX, "1"}) + public boolean testIntVarGT(int x, int y) { + return x + INT_MIN > y + INT_MIN; + } + + @Test + @IR(failOn = {CMP_REGEX, ADD_REGEX}) + @IR(counts = {CMPU_REGEX, "1"}) + public boolean testIntVarGE(int x, int y) { + return x + INT_MIN >= y + INT_MIN; + } + + @Run(test = {"testIntVarEQ", "testIntVarNE", + "testIntVarLT", "testIntVarLE", + "testIntVarGT", "testIntVarGE"}) + public void checkTestIntVar() { + // Verify the transformation "cmp (add X min_jint) (add Y min_jint)" + // to "cmpu X Y" + for (int i = 0; i < INT_DATA.length; i++) { + for (int j = 0; j < INT_DATA.length; j++) { + Asserts.assertEquals(testIntVarEQ(INT_DATA[i], INT_DATA[j]), + i == j); + Asserts.assertEquals(testIntVarNE(INT_DATA[i], INT_DATA[j]), + i != j); + Asserts.assertEquals(testIntVarLT(INT_DATA[i], INT_DATA[j]), + i < j); + Asserts.assertEquals(testIntVarLE(INT_DATA[i], INT_DATA[j]), + i <= j); + Asserts.assertEquals(testIntVarGT(INT_DATA[i], INT_DATA[j]), + i > j); + Asserts.assertEquals(testIntVarGE(INT_DATA[i], INT_DATA[j]), + i >= j); + } + } + } + + @Test + @IR(failOn = {CMP_REGEX, ADD_REGEX}) + @IR(counts = {CMPU_REGEX, "1"}) + public boolean testIntConEQ(int x) { + return x + INT_MIN == INT_CONST; + } + + @Test + @IR(failOn = {CMP_REGEX, ADD_REGEX}) + @IR(counts = {CMPU_REGEX, "1"}) + public boolean testIntConNE(int x) { + return x + INT_MIN != INT_CONST; + } + + @Test + @IR(failOn = {CMP_REGEX, ADD_REGEX}) + @IR(counts = {CMPU_REGEX, "1"}) + public boolean testIntConLT(int x) { + return x + INT_MIN < INT_CONST; + } + + @Test + @IR(failOn = {CMP_REGEX, ADD_REGEX}) + @IR(counts = {CMPU_REGEX, "1"}) + public boolean testIntConLE(int x) { + return x + INT_MIN <= INT_CONST; + } + + @Test + @IR(failOn = {CMP_REGEX, ADD_REGEX}) + @IR(counts = {CMPU_REGEX, "1"}) + public boolean testIntConGT(int x) { + return x + INT_MIN > INT_CONST; + } + + @Test + @IR(failOn = {CMP_REGEX, ADD_REGEX}) + @IR(counts = {CMPU_REGEX, "1"}) + public boolean testIntConGE(int x) { + return x + INT_MIN >= INT_CONST; + } + + @Run(test = {"testIntConEQ", "testIntConNE", + "testIntConLT", "testIntConLE", + "testIntConGT", "testIntConGE"}) + public void checkTestIntCon() { + // Verify the transformation "cmp (add X min_jint) c" + // to "cmpu X (c + min_jint)" + for (int i = 0; i < INT_DATA.length; i++) { + Asserts.assertEquals(testIntConEQ(INT_DATA[i]), + i == CONST_INDEX); + Asserts.assertEquals(testIntConNE(INT_DATA[i]), + i != CONST_INDEX); + Asserts.assertEquals(testIntConLT(INT_DATA[i]), + i < CONST_INDEX); + Asserts.assertEquals(testIntConLE(INT_DATA[i]), + i <= CONST_INDEX); + Asserts.assertEquals(testIntConGT(INT_DATA[i]), + i > CONST_INDEX); + Asserts.assertEquals(testIntConGE(INT_DATA[i]), + i >= CONST_INDEX); + } + } + + @Test + @IR(failOn = {CMP_REGEX, ADD_REGEX}) + @IR(counts = {CMPU_REGEX, "1"}) + public boolean testLongVarEQ(long x, long y) { + return x + LONG_MIN == y + LONG_MIN; + } + + @Test + @IR(failOn = {CMP_REGEX, ADD_REGEX}) + @IR(counts = {CMPU_REGEX, "1"}) + public boolean testLongVarNE(long x, long y) { + return x + LONG_MIN != y + LONG_MIN; + } + + @Test + @IR(failOn = {CMP_REGEX, ADD_REGEX}) + @IR(counts = {CMPU_REGEX, "1"}) + public boolean testLongVarLT(long x, long y) { + return x + LONG_MIN < y + LONG_MIN; + } + + @Test + @IR(failOn = {CMP_REGEX, ADD_REGEX}) + @IR(counts = {CMPU_REGEX, "1"}) + public boolean testLongVarLE(long x, long y) { + return x + LONG_MIN <= y + LONG_MIN; + } + + @Test + @IR(failOn = {CMP_REGEX, ADD_REGEX}) + @IR(counts = {CMPU_REGEX, "1"}) + public boolean testLongVarGT(long x, long y) { + return x + LONG_MIN > y + LONG_MIN; + } + + @Test + @IR(failOn = {CMP_REGEX, ADD_REGEX}) + @IR(counts = {CMPU_REGEX, "1"}) + public boolean testLongVarGE(long x, long y) { + return x + LONG_MIN >= y + LONG_MIN; + } + + @Run(test = {"testLongVarEQ", "testLongVarNE", + "testLongVarLT", "testLongVarLE", + "testLongVarGT", "testLongVarGE"}) + public void checkTestLongVar() { + // Verify the transformation "cmp (add X min_jlong) (add Y min_jlong)" + // to "cmpu X Y" + for (int i = 0; i < LONG_DATA.length; i++) { + for (int j = 0; j < LONG_DATA.length; j++) { + Asserts.assertEquals(testLongVarEQ(LONG_DATA[i], LONG_DATA[j]), + i == j); + Asserts.assertEquals(testLongVarNE(LONG_DATA[i], LONG_DATA[j]), + i != j); + Asserts.assertEquals(testLongVarLT(LONG_DATA[i], LONG_DATA[j]), + i < j); + Asserts.assertEquals(testLongVarLE(LONG_DATA[i], LONG_DATA[j]), + i <= j); + Asserts.assertEquals(testLongVarGT(LONG_DATA[i], LONG_DATA[j]), + i > j); + Asserts.assertEquals(testLongVarGE(LONG_DATA[i], LONG_DATA[j]), + i >= j); + } + } + } + + @Test + @IR(failOn = {CMP_REGEX, ADD_REGEX}) + @IR(counts = {CMPU_REGEX, "1"}) + public boolean testLongConEQ(long x) { + return x + LONG_MIN == LONG_CONST; + } + + @Test + @IR(failOn = {CMP_REGEX, ADD_REGEX}) + @IR(counts = {CMPU_REGEX, "1"}) + public boolean testLongConNE(long x) { + return x + LONG_MIN != LONG_CONST; + } + + @Test + @IR(failOn = {CMP_REGEX, ADD_REGEX}) + @IR(counts = {CMPU_REGEX, "1"}) + public boolean testLongConLT(long x) { + return x + LONG_MIN < LONG_CONST; + } + + @Test + @IR(failOn = {CMP_REGEX, ADD_REGEX}) + @IR(counts = {CMPU_REGEX, "1"}) + public boolean testLongConLE(long x) { + return x + LONG_MIN <= LONG_CONST; + } + + @Test + @IR(failOn = {CMP_REGEX, ADD_REGEX}) + @IR(counts = {CMPU_REGEX, "1"}) + public boolean testLongConGT(long x) { + return x + LONG_MIN > LONG_CONST; + } + + @Test + @IR(failOn = {CMP_REGEX, ADD_REGEX}) + @IR(counts = {CMPU_REGEX, "1"}) + public boolean testLongConGE(long x) { + return x + LONG_MIN >= LONG_CONST; + } + + @Run(test = {"testLongConEQ", "testLongConNE", + "testLongConLT", "testLongConLE", + "testLongConGT", "testLongConGE"}) + public void checkTestLongConGE() { + // Verify the transformation "cmp (add X min_jlong) c" + // to "cmpu X (c + min_jlong)" + for (int i = 0; i < LONG_DATA.length; i++) { + Asserts.assertEquals(testLongConEQ(LONG_DATA[i]), + i == CONST_INDEX); + Asserts.assertEquals(testLongConNE(LONG_DATA[i]), + i != CONST_INDEX); + Asserts.assertEquals(testLongConLT(LONG_DATA[i]), + i < CONST_INDEX); + Asserts.assertEquals(testLongConLE(LONG_DATA[i]), + i <= CONST_INDEX); + Asserts.assertEquals(testLongConGT(LONG_DATA[i]), + i > CONST_INDEX); + Asserts.assertEquals(testLongConGE(LONG_DATA[i]), + i >= CONST_INDEX); + } + } +} diff --git a/test/hotspot/jtreg/compiler/c2/irTests/loopOpts/LoopIdealizationTests.java b/test/hotspot/jtreg/compiler/c2/irTests/loopOpts/LoopIdealizationTests.java new file mode 100644 index 0000000000000000000000000000000000000000..237b97b6c257e87471c5a3598e9f8ff383585b32 --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/irTests/loopOpts/LoopIdealizationTests.java @@ -0,0 +1,171 @@ +/* + * 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. + */ +package compiler.c2.irTests.loopOpts; + +import compiler.lib.ir_framework.*; + +/* + * @test + * @bug 8267265 + * @summary Test that Ideal transformations of CountedLoopNode* are being performed as expected. + * @library /test/lib / + * @run driver compiler.c2.irTests.loopOpts.LoopIdealizationTests + */ +public class LoopIdealizationTests { + public static void main(String[] args) { + TestFramework.run(); + } + + @DontInline + private void blackhole() { } + + @Test + @IR(failOn = {IRNode.MUL, IRNode.DIV, IRNode.ADD, IRNode.LOOP, IRNode.COUNTEDLOOP, IRNode.COUNTEDLOOP_MAIN, IRNode.CALL}) + // Checks that a for loop with 0 iterations is removed + public void zeroIterForLoop() { + for (int i = 0; i < 0; i++) { + System.out.println(13 / 17 * 23 + 1); + } + } + + @Test + @IR(failOn = {IRNode.ADD, IRNode.LOOP, IRNode.COUNTEDLOOP, IRNode.COUNTEDLOOP_MAIN, IRNode.CALL}) + // Checks that a for loop with 1 iteration doesn't have CountedLoop nodes + public void iterOneBreakForLoop() { + for (int i = 0; i < 500; i++) { + break; + } + } + + @Test + @IR(failOn = {IRNode.ADD, IRNode.LOOP, IRNode.COUNTEDLOOP, IRNode.COUNTEDLOOP_MAIN, IRNode.TRAP}) + @IR(counts = {IRNode.CALL, "1"}) + // Checks that a for loop with 1 iteration is simplified to straight code + public void oneIterForLoop() { + for (int i = 0; i < 1; i++) { + this.blackhole(); + } + } + + @Test + @IR(failOn = {IRNode.ADD, IRNode.LOOP, IRNode.COUNTEDLOOP, IRNode.COUNTEDLOOP_MAIN, IRNode.TRAP}) + @IR(counts = {IRNode.CALL, "1"}) + // Checks that a for loop with 1 iteration is simplified to straight code + public void oneIterForLoop1() { + for (int i = 0; i < 500; i++) { + this.blackhole(); + break; + } + } + + @Test + @IR(failOn = {IRNode.ADD, IRNode.LOOP, IRNode.COUNTEDLOOP, IRNode.COUNTEDLOOP_MAIN, IRNode.TRAP}) + @IR(counts = {IRNode.CALL, "1"}) + // Checks that a for loop with 1 iteration is simplified to straight code + public void oneIterForLoop2() { + for (int i = 0; i < 500; i++) { + this.blackhole(); + if (i == 0) { + break; + } + else { + this.blackhole(); + i++; + } + } + } + + @Test + @IR(failOn = {IRNode.LOOP, IRNode.TRAP}) + @IR(counts = {IRNode.CALL, "1"}) + // Checks that a while loop with 1 iteration is simplified to straight code + public void oneIterWhileLoop() { + while (true) { + this.blackhole(); + break; + } + } + + @Test + @IR(failOn = {IRNode.ADD, IRNode.LOOP, IRNode.COUNTEDLOOP, IRNode.COUNTEDLOOP_MAIN, IRNode.TRAP}) + @IR(counts = {IRNode.CALL, "1"}) + // Checks that a while loop with 1 iteration is simplified to straight code + public void oneIterWhileLoop1() { + int i = 0; + while (i < 1) { + this.blackhole(); + i++; + } + } + + @Test + @IR(failOn = {IRNode.ADD, IRNode.LOOP, IRNode.COUNTEDLOOP, IRNode.COUNTEDLOOP_MAIN, IRNode.TRAP}) + @IR(counts = {IRNode.CALL, "1"}) + // Checks that a while loop with 1 iteration is simplified to straight code + public void oneIterWhileLoop2() { + int i = 0; + while (i < 500) { + this.blackhole(); + if (i == 0) { + break; + } + else { + this.blackhole(); + i++; + } + } + } + + @Test + @IR(failOn = {IRNode.LOOP, IRNode.TRAP}) + @IR(counts = {IRNode.CALL, "1"}) + // Checks that a while loop with 1 iteration is simplified to straight code + public void oneIterDoWhileLoop() { + do { + this.blackhole(); + break; + } while (true); + } + + @Test + @IR(failOn = {IRNode.LOOP, IRNode.TRAP}) + @IR(counts = {IRNode.CALL, "1"}) + // Checks that a while loop with 1 iteration is simplified to straight code + public void oneIterDoWhileLoop1() { + do { + this.blackhole(); + } while (false); + } + + @Test + @IR(failOn = {IRNode.ADD, IRNode.LOOP, IRNode.TRAP}) + @IR(counts = {IRNode.CALL, "1"}) + // Checks that a while loop with 1 iteration is simplified to straight code + public void oneIterDoWhileLoop2() { + int i = 0; + do { + this.blackhole(); + i++; + } while (i == -1); + } +} diff --git a/test/hotspot/jtreg/compiler/c2/irTests/scalarReplacement/ScalarReplacementTests.java b/test/hotspot/jtreg/compiler/c2/irTests/scalarReplacement/ScalarReplacementTests.java new file mode 100644 index 0000000000000000000000000000000000000000..191f995962dd0479a8a030646b54f49c9f9976fc --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/irTests/scalarReplacement/ScalarReplacementTests.java @@ -0,0 +1,100 @@ +/* + * 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. + */ +package compiler.c2.irTests.scalarReplacement; + +import compiler.lib.ir_framework.*; + +/* + * @test + * @bug 8267265 + * @summary Tests that Escape Analysis and Scalar Replacement is able to handle some simple cases. + * @library /test/lib / + * @run driver compiler.c2.irTests.scalarReplacement.ScalarReplacementTests + */ +public class ScalarReplacementTests { + private class Person { + private String name; + private int age; + + public Person(Person p) { + this.name = p.getName(); + this.age = p.getAge(); + } + + public Person(String name, int age) { + this.name = name; + this.age = age; + } + + public String getName() { return name; } + public int getAge() { return age; } + } + + public static void main(String[] args) { + TestFramework.run(); + } + + @Test + @Arguments(Argument.RANDOM_EACH) + @IR(failOn = {IRNode.CALL, IRNode.LOAD, IRNode.STORE, IRNode.FIELD_ACCESS, IRNode.ALLOC}) + public String stringConstant(int age) { + Person p = new Person("Java", age); + return p.getName(); + } + + @Test + @Arguments(Argument.RANDOM_EACH) + @IR(failOn = {IRNode.CALL, IRNode.LOAD, IRNode.STORE, IRNode.FIELD_ACCESS, IRNode.ALLOC}) + public int intConstant(int age) { + Person p = new Person("Java", age); + return p.getAge(); + } + + @Test + @Arguments(Argument.RANDOM_EACH) + @IR(failOn = {IRNode.CALL, IRNode.LOAD, IRNode.STORE, IRNode.FIELD_ACCESS, IRNode.ALLOC}) + public String nestedStringConstant(int age) { + Person p1 = new Person("Java", age); + Person p2 = new Person(p1); + return p2.getName(); + } + + @Test + @Arguments(Argument.RANDOM_EACH) + @IR(failOn = {IRNode.CALL, IRNode.LOAD, IRNode.STORE, IRNode.FIELD_ACCESS, IRNode.ALLOC}) + public int nestedIntConstant(int age) { + Person p1 = new Person("Java", age); + Person p2 = new Person(p1); + return p2.getAge(); + } + + @Test + @Arguments({Argument.RANDOM_EACH, Argument.RANDOM_EACH}) + @IR(failOn = {IRNode.CALL, IRNode.LOAD, IRNode.STORE, IRNode.FIELD_ACCESS, IRNode.ALLOC}) + public int nestedConstants(int age1, int age2) { + Person p = new Person( + new Person("Java", age1).getName(), + new Person("Java", age2).getAge()); + return p.getAge(); + } +} diff --git a/test/hotspot/jtreg/compiler/cha/AbstractRootMethod.java b/test/hotspot/jtreg/compiler/cha/AbstractRootMethod.java index a450b1e02e138c0d7aff33968e9622990d6159bb..01787593412e44c89cb52b8fe0f77c80354bb92f 100644 --- a/test/hotspot/jtreg/compiler/cha/AbstractRootMethod.java +++ b/test/hotspot/jtreg/compiler/cha/AbstractRootMethod.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -50,12 +50,23 @@ */ package compiler.cha; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; + import static compiler.cha.Utils.*; public class AbstractRootMethod { public static void main(String[] args) { run(AbstractClass.class); run(AbstractInterface.class); + + // Implementation limitation: CHA is not performed by C1 during inlining through MH linkers. + if (!sun.hotspot.code.Compiler.isC1Enabled()) { + run(AbstractClass.TestMH.class, AbstractClass.class); + run(AbstractInterface.TestMH.class, AbstractInterface.class); + } + + System.out.println("TEST PASSED"); } public static class AbstractClass extends ATest<AbstractClass.C> { @@ -124,7 +135,21 @@ public class AbstractRootMethod { call(new G() { public Object m() { return CORRECT; } }); // Gn <: G.m <: C.m ABSTRACT assertCompiled(); } + + public static class TestMH extends AbstractClass { + static final MethodHandle TEST_MH = findVirtualHelper(C.class, "m", Object.class, MethodHandles.lookup()); + + @Override + public Object test(C obj) { + try { + return TEST_MH.invokeExact(obj); // invokevirtual C.m() + } catch (Throwable e) { + throw new InternalError(e); + } + } + } } + public static class AbstractInterface extends ATest<AbstractInterface.C> { public AbstractInterface() { super(C.class, D.class); @@ -193,5 +218,18 @@ public class AbstractRootMethod { call(new G() { public Object m() { return CORRECT; } }); // Gn <: G.m <: C <: I.m ABSTRACT assertCompiled(); } + + public static class TestMH extends AbstractInterface { + static final MethodHandle TEST_MH = findVirtualHelper(C.class, "m", Object.class, MethodHandles.lookup()); + + @Override + public Object test(C obj) { + try { + return TEST_MH.invokeExact(obj); // invokevirtual C.m() + } catch (Throwable e) { + throw new InternalError(e); + } + } + } } } diff --git a/test/hotspot/jtreg/compiler/cha/DefaultRootMethod.java b/test/hotspot/jtreg/compiler/cha/DefaultRootMethod.java index 354412d77480c47c5d9a0043f7f97e2a4db97a09..a13a9cfdd26a190d8b6f97fd50a35b2e59d5405f 100644 --- a/test/hotspot/jtreg/compiler/cha/DefaultRootMethod.java +++ b/test/hotspot/jtreg/compiler/cha/DefaultRootMethod.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -50,12 +50,22 @@ */ package compiler.cha; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; + import static compiler.cha.Utils.*; public class DefaultRootMethod { public static void main(String[] args) { run(DefaultRoot.class); run(InheritedDefault.class); + + // Implementation limitation: CHA is not performed by C1 during inlining through MH linkers. + if (!sun.hotspot.code.Compiler.isC1Enabled()) { + run(DefaultRoot.TestMH.class, DefaultRoot.class); + run(InheritedDefault.TestMH.class, InheritedDefault.class); + } + System.out.println("TEST PASSED"); } @@ -83,7 +93,7 @@ public class DefaultRootMethod { static class G extends C { public Object m() { return CORRECT; } } @Override - public Object test(C obj) { + public Object test(C obj) throws Throwable { return obj.m(); // invokevirtual C.m() } @@ -122,6 +132,15 @@ public class DefaultRootMethod { call(new G() { public Object m() { return CORRECT; } }); // Gn <: G.m <: C <: I.m DEFAULT assertCompiled(); } + + public static class TestMH extends DefaultRoot { + static final MethodHandle TEST_MH = findVirtualHelper(C.class, "m", Object.class, MethodHandles.lookup()); + + @Override + public Object test(C obj) throws Throwable { + return TEST_MH.invokeExact(obj); // invokevirtual C.m() + } + } } public static class InheritedDefault extends ATest<InheritedDefault.C> { @@ -151,7 +170,7 @@ public class DefaultRootMethod { static class G extends C implements K { /* inherits K.m DEFAULT */ } @Override - public Object test(C obj) { + public Object test(C obj) throws Throwable { return obj.m(); // invokevirtual C.m() } @@ -190,5 +209,14 @@ public class DefaultRootMethod { call(new G() { public Object m() { return CORRECT; } }); // Gn <: G.m <: C <: I.m DEFAULT assertCompiled(); } + + public static class TestMH extends InheritedDefault { + static final MethodHandle TEST_MH = findVirtualHelper(C.class, "m", Object.class, MethodHandles.lookup()); + + @Override + public Object test(C obj) throws Throwable { + return TEST_MH.invokeExact(obj); // invokevirtual C.m() + } + } } } diff --git a/test/hotspot/jtreg/compiler/cha/Utils.java b/test/hotspot/jtreg/compiler/cha/Utils.java index cad185b1110306147f20daa34c76f30eaa782b66..f45ab256fbb710206b0994a0c6e06ea2fd610d17 100644 --- a/test/hotspot/jtreg/compiler/cha/Utils.java +++ b/test/hotspot/jtreg/compiler/cha/Utils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -34,6 +34,7 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; import java.lang.reflect.Method; import java.util.HashMap; import java.util.concurrent.Callable; @@ -45,6 +46,7 @@ import static jdk.test.lib.Asserts.assertTrue; public class Utils { public static final Unsafe U = Unsafe.getUnsafe(); + public static final WhiteBox WB = WhiteBox.getWhiteBox(); interface Test<T> { void call(T o); @@ -99,8 +101,6 @@ public class Utils { } public static abstract class ATest<T> implements Test<T> { - public static final WhiteBox WB = WhiteBox.getWhiteBox(); - public static final Object CORRECT = new Object(); public static final Object WRONG = new Object(); @@ -117,7 +117,7 @@ public class Utils { } @DontInline - public abstract Object test(T i); + public abstract Object test(T i) throws Throwable; public abstract void checkInvalidReceiver(); @@ -133,7 +133,6 @@ public class Utils { })); } - public void compile(Runnable r) { while (!WB.isMethodCompiled(TEST)) { for (int i = 0; i < 100; i++) { @@ -161,19 +160,35 @@ public class Utils { @Override public void call(T i) { - assertTrue(test(i) != WRONG); + try { + assertTrue(test(i) != WRONG); + } catch (Throwable e) { + throw new InternalError(e); + } + } + + public static <T> T compute(Callable<T> c) { + try { + return c.call(); + } catch (Exception e) { + throw new Error(e); + } + } + + public static MethodHandle findVirtualHelper(Class<?> refc, String name, Class<?> returnType, MethodHandles.Lookup lookup) { + return compute(() -> lookup.findVirtual(refc, name, MethodType.methodType(returnType))); } } @Retention(value = RetentionPolicy.RUNTIME) public @interface TestCase {} - static void run(Class<?> test) { + static void run(Class<?> test, Class<?> enclosed) { try { - for (Method m : test.getDeclaredMethods()) { + for (Method m : test.getMethods()) { if (m.isAnnotationPresent(TestCase.class)) { System.out.println(m.toString()); - ClassLoader cl = new MyClassLoader(test); + ClassLoader cl = new MyClassLoader(enclosed); Class<?> c = cl.loadClass(test.getName()); c.getMethod(m.getName()).invoke(c.getDeclaredConstructor().newInstance()); } @@ -183,6 +198,10 @@ public class Utils { } } + static void run(Class<?> test) { + run(test, test); + } + static class ObjectToStringHelper { static Object testHelper(Object o) { throw new Error("not used"); @@ -303,7 +322,7 @@ public class Utils { try { r.run(); throw new AssertionError("Exception not thrown: " + expectedException.getName()); - } catch(Throwable e) { + } catch (Throwable e) { if (expectedException == e.getClass()) { // success: proper exception is thrown } else { @@ -320,12 +339,4 @@ public class Utils { throw new Error(e); } } - - static <T> T compute(Callable<T> c) { - try { - return c.call(); - } catch (Exception e) { - throw new Error(e); - } - } } diff --git a/test/hotspot/jtreg/compiler/ciReplay/CiReplayBase.java b/test/hotspot/jtreg/compiler/ciReplay/CiReplayBase.java index 2fccc385ee1af56eab9241de6aee8f88cbf692e8..a025962081cc3b79c8bfad8dbf8cd5db7305b560 100644 --- a/test/hotspot/jtreg/compiler/ciReplay/CiReplayBase.java +++ b/test/hotspot/jtreg/compiler/ciReplay/CiReplayBase.java @@ -24,10 +24,17 @@ package compiler.ciReplay; import compiler.whitebox.CompilerWhiteBoxTest; -import java.io.IOException; -import java.io.File; +import jdk.test.lib.Asserts; +import jdk.test.lib.Platform; +import jdk.test.lib.Utils; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.util.CoreUtils; + import java.io.BufferedReader; +import java.io.File; import java.io.FileReader; +import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -36,14 +43,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Optional; -import java.util.regex.Pattern; -import java.util.regex.Matcher; -import jdk.test.lib.Platform; -import jdk.test.lib.process.ProcessTools; -import jdk.test.lib.process.OutputAnalyzer; -import jdk.test.lib.Asserts; -import jdk.test.lib.Utils; -import jdk.test.lib.util.CoreUtils; public abstract class CiReplayBase { public static final String REPLAY_FILE_NAME = "test_replay.txt"; @@ -296,4 +295,41 @@ public abstract class CiReplayBase { throw new Error("Can't create process builder: " + t, t); } } + + protected void removeVersionFromReplayFile() { + setNewVersionLineInReplayFile(null); + } + + protected void setNewVersionInReplayFile(int newVersionNumber) { + setNewVersionLineInReplayFile("version " + newVersionNumber); + } + + private void setNewVersionLineInReplayFile(String firstLineString) { + List<String> newLines = new ArrayList<>(); + Path replayFilePath = Paths.get(getReplayFileName()); + try (var br = Files.newBufferedReader(replayFilePath)) { + String line; + boolean firstLine = true; + while ((line = br.readLine()) != null) { + if (firstLine) { + firstLine = false; + Asserts.assertTrue(line.startsWith("version"), "version number must exist in a proper replay file"); + if (firstLineString != null) { + newLines.add(firstLineString); + } + // Else: Remove first line by skipping it. + } else { + newLines.add(line); + } + } + Asserts.assertFalse(firstLine, replayFilePath + " should not be empty"); + } catch (IOException e) { + throw new Error("Failed to read replay data: " + e, e); + } + try { + Files.write(replayFilePath, newLines, StandardOpenOption.TRUNCATE_EXISTING); + } catch (IOException e) { + throw new Error("Failed to write replay data: " + e, e); + } + } } diff --git a/test/hotspot/jtreg/compiler/ciReplay/InliningBase.java b/test/hotspot/jtreg/compiler/ciReplay/InliningBase.java new file mode 100644 index 0000000000000000000000000000000000000000..b89e9b7cb5f0359125912adac24558c3996bdf3a --- /dev/null +++ b/test/hotspot/jtreg/compiler/ciReplay/InliningBase.java @@ -0,0 +1,174 @@ +/* + * 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. + */ + +package compiler.ciReplay; + +import jdk.test.lib.Asserts; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public abstract class InliningBase extends DumpReplayBase { + public static final String LOG_FILE_NORMAL = "hotspot_normal.log"; + public static final String LOG_FILE_REPLAY = "hotspot_replay.log"; + protected final String[] commandLineReplay; + protected final List<String> commandLineNormal; + protected final Class<?> testClass; + + protected InliningBase(Class<?> testClass) { + this.testClass = testClass; + commandLineNormal = new ArrayList<>(List.of("-XX:LogFile=" + LOG_FILE_NORMAL + "", "-XX:+LogCompilation", "-XX:-TieredCompilation", + "-XX:CompileCommand=exclude," + testClass.getName() + "::main", + "-XX:CompileCommand=option," + testClass.getName() + "::test,bool,PrintInlining,true")); + commandLineReplay = new String[] + {"-XX:LogFile=" + LOG_FILE_REPLAY, "-XX:+LogCompilation", + "-XX:CompileCommand=option," + testClass.getName() + "::test,bool,PrintInlining,true"}; + } + + protected void runTest() { + runTest(commandLineNormal.toArray(new String[0])); + } + + @Override + public String getTestClass() { + return testClass.getName(); + } + + @Override + public void cleanup() { + super.cleanup(); + remove(LOG_FILE_NORMAL); + remove(LOG_FILE_REPLAY); + } + + static class InlineEntry { + String klass; + String method; + String reason; + + public InlineEntry(String klass, String method, String reason) { + this.klass = klass; + this.method = method; + this.reason = reason; + } + + public boolean isNormalInline() { + return reason.equals("inline (hot)"); + } + + public boolean isForcedByReplay() { + return reason.equals("force inline by ciReplay"); + } + + public boolean isDisallowedByReplay() { + return reason.equals("disallowed by ciReplay"); + } + + public boolean isUnloadedSignatureClasses() { + return reason.equals("unloaded signature classes"); + } + + public boolean isForcedIncrementalInlineByReplay() { + return reason.equals("force (incremental) inline by ciReplay"); + } + + public boolean isForcedInline() { + return reason.equals("force inline by annotation"); + } + + public boolean isTooDeep() { + return reason.equals("inlining too deep"); + } + + @Override + public boolean equals(Object other) { + if (other == this) { + return true; + } + + if (!(other instanceof InlineEntry)) { + return false; + } + + InlineEntry e = (InlineEntry)other; + return klass.equals(e.klass) && method.equals(e.method); + } + + public boolean compare(String klass, String method, boolean kind) { + return this.klass.equals(klass) && this.method.equals(method) && kind; + } + } + + protected static List<InlineEntry> parseLogFile(String logFile, String rootMethod, String nmethodMatch, int inlineeCount) { + String nmethodStart = "<nmethod"; + List<InlineEntry> inlinees = new ArrayList<>(); + int foundLines = 0; + try (var br = Files.newBufferedReader(Paths.get(logFile))) { + String line; + boolean nmethodLine = false; + boolean inlinineLine = false; + while ((line = br.readLine()) != null) { + if (nmethodLine) { + // Ignore other entries which could be in between nmethod entry and inlining statements + if (line.startsWith(" ")) { + inlinineLine = true; + Pattern p = Pattern.compile("(\\S+)::(\\S+).*bytes\\)\s+(.*)"); + Matcher matcher = p.matcher(line); + Asserts.assertTrue(matcher.find(), "must find inlinee method"); + inlinees.add(new InlineEntry(matcher.group(1), matcher.group(2), matcher.group(3).trim())); + foundLines++; + } else if (inlinineLine) { + Asserts.assertEQ(foundLines, inlineeCount, "did not find all inlinees"); + return inlinees; + } + } else { + nmethodLine = line.startsWith(nmethodStart) && line.contains(nmethodMatch); + if (nmethodLine) { + Asserts.assertTrue(line.contains(rootMethod), "should only dump inline information for " + rootMethod); + } + } + } + } catch (IOException e) { + throw new Error("Failed to read " + logFile + " data: " + e, e); + } + Asserts.fail("Should have found inlinees"); + return inlinees; + } + + protected void verifyLists(List<InlineEntry> inlineesNormal, List<InlineEntry> inlineesReplay, int expectedSize) { + if (!inlineesNormal.equals(inlineesReplay)) { + System.err.println("Normal entries:"); + inlineesNormal.forEach(System.err::println); + System.err.println("Replay entries:"); + inlineesReplay.forEach(System.err::println); + Asserts.fail("different inlining decision in normal run vs. replay run"); + } + Asserts.assertEQ(expectedSize, inlineesNormal.size(), "unexpected number of inlinees found"); + } +} + diff --git a/test/hotspot/jtreg/compiler/ciReplay/TestIncrementalInlining.java b/test/hotspot/jtreg/compiler/ciReplay/TestIncrementalInlining.java new file mode 100644 index 0000000000000000000000000000000000000000..8bac1ea283c862fc93d9f748a6169f6b7c011218 --- /dev/null +++ b/test/hotspot/jtreg/compiler/ciReplay/TestIncrementalInlining.java @@ -0,0 +1,188 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8254108 + * @library / /test/lib + * @summary Testing of ciReplay with incremental inlining. + * @requires vm.flightRecorder != true & vm.compMode != "Xint" & vm.compMode != "Xcomp" & vm.debug == true & vm.compiler2.enabled + * @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.ciReplay.TestIncrementalInlining + */ + +package compiler.ciReplay; + +import jdk.test.lib.Asserts; +import jdk.test.lib.Utils; +import jdk.test.whitebox.WhiteBox; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardOpenOption; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class TestIncrementalInlining extends InliningBase { + + private List<InlineEntry> inlineesNormal; + private List<InlineEntry> inlineesReplay; + public static void main(String[] args) { + new TestIncrementalInlining(); + } + + TestIncrementalInlining() { + super(IncrementalInliningTest.class); + // Enable Whitebox access for test VM. + commandLineNormal.add("-Dtest.jdk=" + Utils.TEST_JDK); + commandLineNormal.add("-cp"); + commandLineNormal.add(Utils.TEST_CLASS_PATH); + commandLineNormal.add("-Xbootclasspath/a:."); + commandLineNormal.add("-XX:+UnlockDiagnosticVMOptions"); + commandLineNormal.add("-XX:+WhiteBoxAPI"); + commandLineNormal.add("-XX:MaxInlineLevel=2"); + commandLineNormal.add("-XX:-AlwaysIncrementalInline"); + runTest(); + } + + @Override + public void testAction() { + positiveTest(commandLineReplay); + inlineesNormal = parseLogFile(LOG_FILE_NORMAL, getTestClass() + " " + "test", "compile_id='" + getCompileIdFromFile(getReplayFileName()), 5); + verify(true); + + // Incremental inlining is supported in version 2+ + // Test replay file version 1. + removeIncrementalInlineInfo(); + setNewVersionInReplayFile(1); + positiveTest(commandLineReplay); + verify(false); + + // Test replay file without version. + removeVersionFromReplayFile(); + positiveTest(commandLineReplay); + verify(false); + } + + private void verify(boolean isNewFormat) { + inlineesReplay = parseLogFile(LOG_FILE_REPLAY, getTestClass() + " " + "test", "test ()V", 5); + verifyLists(inlineesNormal, inlineesReplay, 5); + checkInlining(isNewFormat); + } + + // Check if inlining is done correctly in ciReplay. + private void checkInlining(boolean isNewFormat) { + String klass = getTestClass(); + Asserts.assertTrue(inlineesNormal.get(0).compare(klass, "level0", inlineesNormal.get(0).isForcedInline())); + Asserts.assertTrue(inlineesReplay.get(0).compare(klass, "level0", inlineesReplay.get(0).isForcedByReplay())); + Asserts.assertTrue(inlineesNormal.get(1).compare(klass, "level1", inlineesNormal.get(1).isNormalInline())); + Asserts.assertTrue(inlineesReplay.get(1).compare(klass, "level1", inlineesReplay.get(1).isForcedByReplay())); + Asserts.assertTrue(inlineesNormal.get(2).compare(klass, "level2", inlineesNormal.get(2).isForcedInline())); + Asserts.assertTrue(inlineesReplay.get(2).compare(klass, "level2", inlineesReplay.get(2).isForcedByReplay())); + Asserts.assertTrue(inlineesNormal.get(3).compare(klass, "late", inlineesNormal.get(3).isForcedInline())); + Asserts.assertTrue(inlineesReplay.get(3).compare(klass, "late", isNewFormat ? + inlineesReplay.get(3).isForcedIncrementalInlineByReplay() + : inlineesReplay.get(3).isForcedByReplay())); + Asserts.assertTrue(inlineesNormal.get(4).compare(klass, "level4", inlineesNormal.get(4).isTooDeep())); + Asserts.assertTrue(inlineesReplay.get(4).compare(klass, "level4", inlineesReplay.get(4).isDisallowedByReplay())); + } + + private void removeIncrementalInlineInfo() { + try { + Path replayFilePath = Paths.get(getReplayFileName()); + List<String> replayContent = Files.readAllLines(replayFilePath); + for (int i = 0; i < replayContent.size(); i++) { + String line = replayContent.get(i); + if (line.startsWith("compile ")) { + int lastIndex = 0; + StringBuilder newLine = new StringBuilder(); + Pattern p = Pattern.compile("(\\d (-?\\d)) \\d compiler"); + Matcher m = p.matcher(line); + boolean firstMatch = true; + while (m.find()) { + newLine.append(line, lastIndex, m.start()) + .append(m.group(1)) + .append(" compiler"); + lastIndex = m.end(); + String bci = m.group(2); + Asserts.assertTrue(firstMatch ? bci.equals("-1") : bci.equals("0"), "only root has -1"); + firstMatch = false; + } + Asserts.assertLessThan(lastIndex, line.length(), "not reached end of line, yet"); + newLine.append(line, lastIndex, line.length()); + replayContent.set(i, newLine.toString()); + } + } + Files.write(replayFilePath, replayContent, StandardOpenOption.TRUNCATE_EXISTING); + } catch (IOException ioe) { + throw new Error("Failed to read/write replay data: " + ioe, ioe); + } + } +} + +class IncrementalInliningTest { + private static final WhiteBox WB = WhiteBox.getWhiteBox(); + private static String s; + + public static void main(String[] args) throws NoSuchMethodException { + WB.testSetForceInlineMethod(IncrementalInliningTest.class.getDeclaredMethod("level0"), true); + WB.testSetForceInlineMethod(IncrementalInliningTest.class.getDeclaredMethod("level2"), true); + WB.testSetForceInlineMethod(IncrementalInliningTest.class.getDeclaredMethod("late"), true); + for (int i = 0; i < 10000; i++) { + test(); + } + } + + private static void test() { + level0(); + } + + public static void level0() { + level1(); + } + + public static void level1() { + level2(); + } + + public static void level2() { + late(); + } + + // Reached max inline level but forced to be inlined -> inline late. + public static void late() { + level4(); + } + + // Reached max inline level and not forced to be inlined -> no inline. + public static void level4() { + s = "HelloWorld"; + } + +} diff --git a/test/hotspot/jtreg/compiler/ciReplay/TestInliningProtectionDomain.java b/test/hotspot/jtreg/compiler/ciReplay/TestInliningProtectionDomain.java index 6693295a5d5e30d6d999c9c6e9c112b1fe1d15cb..0a900fda8e58c1ecab201d024007e529965d9ac6 100644 --- a/test/hotspot/jtreg/compiler/ciReplay/TestInliningProtectionDomain.java +++ b/test/hotspot/jtreg/compiler/ciReplay/TestInliningProtectionDomain.java @@ -28,173 +28,49 @@ * @summary Testing that ciReplay inlining does not fail with unresolved signature classes. * @requires vm.flightRecorder != true & vm.compMode != "Xint" & vm.compMode != "Xcomp" & vm.debug == true & vm.compiler2.enabled * @modules java.base/jdk.internal.misc - * @build sun.hotspot.WhiteBox - * @run driver jdk.test.lib.helpers.ClassFileInstaller sun.hotspot.WhiteBox - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI - * compiler.ciReplay.TestInliningProtectionDomain + * @run driver compiler.ciReplay.TestInliningProtectionDomain */ package compiler.ciReplay; import jdk.test.lib.Asserts; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.util.ArrayList; import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -public class TestInliningProtectionDomain extends DumpReplayBase { - public static final String LOG_FILE_NORMAL = "hotspot_normal.log"; - public static final String LOG_FILE_REPLAY = "hotspot_replay.log"; - private final String[] commandLineReplay; - - private final String className; +public class TestInliningProtectionDomain extends InliningBase { public static void main(String[] args) { - new TestInliningProtectionDomain("ProtectionDomainTestCompiledBefore", true); - new TestInliningProtectionDomain("ProtectionDomainTestNoOtherCompilationPublic", false); - new TestInliningProtectionDomain("ProtectionDomainTestNoOtherCompilationPrivate", false); - new TestInliningProtectionDomain("ProtectionDomainTestNoOtherCompilationPrivateString", false); + new TestInliningProtectionDomain(ProtectionDomainTestCompiledBefore.class, true); + new TestInliningProtectionDomain(ProtectionDomainTestNoOtherCompilationPublic.class, false); + new TestInliningProtectionDomain(ProtectionDomainTestNoOtherCompilationPrivate.class, false); + new TestInliningProtectionDomain(ProtectionDomainTestNoOtherCompilationPrivateString.class, false); } - public TestInliningProtectionDomain(String className, boolean compileBar) { - this.className = className; - List<String> commandLineNormal = new ArrayList<>(List.of("-XX:LogFile=" + LOG_FILE_NORMAL + "", "-XX:+LogCompilation", "-XX:-TieredCompilation", - "-XX:CompileCommand=exclude," + getTestClass() + "::main", - "-XX:CompileCommand=option," + getTestClass() + "::test,bool,PrintInlining,true")); + public TestInliningProtectionDomain(Class<?> testClass, boolean compileBar) { + super(testClass); if (compileBar) { - commandLineNormal.add("-XX:CompileCommand=compileonly," + getTestClass() + "::bar"); + commandLineNormal.add("-XX:CompileCommand=compileonly," + testClass.getName() + "::bar"); } - commandLineReplay = new String[] - {"-XX:LogFile=" + LOG_FILE_REPLAY + "", "-XX:+LogCompilation", - "-XX:CompileCommand=option," + getTestClass() + "::test,bool,PrintInlining,true"}; - runTest(commandLineNormal.toArray(new String[0])); + runTest(); } @Override public void testAction() { positiveTest(commandLineReplay); - String klass = "compiler.ciReplay." + className; - String entryString = klass + " " + "test"; - boolean inlineFails = className.equals("ProtectionDomainTestNoOtherCompilationPrivate"); + String entryString = getTestClass() + " " + "test"; + boolean inlineFails = testClass == ProtectionDomainTestNoOtherCompilationPrivate.class; int inlineeCount = inlineFails ? 1 : 5; - List<Entry> inlineesNormal = parseLogFile(LOG_FILE_NORMAL, entryString, "compile_id='" + getCompileIdFromFile(getReplayFileName()), inlineeCount); - List<Entry> inlineesReplay = parseLogFile(LOG_FILE_REPLAY, entryString, "test ()V", inlineeCount); + List<InlineEntry> inlineesNormal = parseLogFile(LOG_FILE_NORMAL, entryString, "compile_id='" + getCompileIdFromFile(getReplayFileName()), inlineeCount); + List<InlineEntry> inlineesReplay = parseLogFile(LOG_FILE_REPLAY, entryString, "test ()V", inlineeCount); verifyLists(inlineesNormal, inlineesReplay, inlineeCount); if (inlineFails) { - Asserts.assertTrue(compare(inlineesNormal.get(0), "compiler.ciReplay.ProtectionDomainTestNoOtherCompilationPrivate", - "bar", inlineesNormal.get(0).isUnloadedSignatureClasses())); - Asserts.assertTrue(compare(inlineesReplay.get(0), "compiler.ciReplay.ProtectionDomainTestNoOtherCompilationPrivate", - "bar", inlineesReplay.get(0).isDisallowedByReplay())); + Asserts.assertTrue(inlineesNormal.get(0).compare("compiler.ciReplay.ProtectionDomainTestNoOtherCompilationPrivate", "bar", inlineesNormal.get(0).isUnloadedSignatureClasses())); + Asserts.assertTrue(inlineesReplay.get(0).compare("compiler.ciReplay.ProtectionDomainTestNoOtherCompilationPrivate", "bar", inlineesReplay.get(0).isDisallowedByReplay())); } else { - Asserts.assertTrue(compare(inlineesNormal.get(4), "compiler.ciReplay.InliningBar", "bar2", inlineesNormal.get(4).isNormalInline())); - Asserts.assertTrue(compare(inlineesReplay.get(4), "compiler.ciReplay.InliningBar", "bar2", inlineesReplay.get(4).isForcedByReplay())); - } - remove(LOG_FILE_NORMAL); - remove(LOG_FILE_REPLAY); - } - - private void verifyLists(List<Entry> inlineesNormal, List<Entry> inlineesReplay, int expectedSize) { - if (!inlineesNormal.equals(inlineesReplay)) { - System.err.println("Normal entries:"); - inlineesNormal.forEach(System.err::println); - System.err.println("Replay entries:"); - inlineesReplay.forEach(System.err::println); - Asserts.fail("different inlining decision in normal run vs. replay run"); - } - Asserts.assertEQ(expectedSize, inlineesNormal.size(), "unexpected number of inlinees found"); - } - - public static boolean compare(Entry e, String klass, String method, boolean kind) { - return e.klass.equals(klass) && e.method.equals(method) && kind; - } - - public static List<Entry> parseLogFile(String logFile, String rootMethod, String nmethodMatch, int inlineeCount) { - String nmethodStart = "<nmethod"; - List<Entry> inlinees = new ArrayList<>(); - int foundLines = 0; - try (var br = Files.newBufferedReader(Paths.get(logFile))) { - String line; - boolean nmethodLine = false; - boolean inlinineLine = false; - while ((line = br.readLine()) != null) { - if (nmethodLine) { - // Ignore other entries which could be in between nmethod entry and inlining statements - if (line.startsWith(" ")) { - inlinineLine = true; - Pattern p = Pattern.compile("(\\S+)::(\\S+).*bytes\\)\s+(.*)"); - Matcher matcher = p.matcher(line); - Asserts.assertTrue(matcher.find(), "must find inlinee method"); - inlinees.add(new Entry(matcher.group(1), matcher.group(2), matcher.group(3).trim())); - foundLines++; - } else if (inlinineLine) { - Asserts.assertEQ(foundLines, inlineeCount, "did not find all inlinees"); - return inlinees; - } - } else { - nmethodLine = line.startsWith(nmethodStart) && line.contains(nmethodMatch); - if (nmethodLine) { - Asserts.assertTrue(line.contains(rootMethod), "should only dump inline information for " + rootMethod); - } - } - } - } catch (IOException e) { - throw new Error("Failed to read " + logFile + " data: " + e, e); - } - Asserts.fail("Should have found inlinees"); - return inlinees; - } - - - @Override - public String getTestClass() { - return "compiler.ciReplay." + className; - } - - static class Entry { - String klass; - String method; - String reason; - - public Entry(String klass, String method, String reason) { - this.klass = klass; - this.method = method; - this.reason = reason; - } - - public boolean isNormalInline() { - return reason.equals("inline (hot)"); - } - - public boolean isForcedByReplay() { - return reason.equals("force inline by ciReplay"); - } - - public boolean isDisallowedByReplay() { - return reason.equals("disallowed by ciReplay"); - } - - public boolean isUnloadedSignatureClasses() { - return reason.equals("unloaded signature classes"); - } - - @Override - public boolean equals(Object other) { - if (other == this) { - return true; - } - - if (!(other instanceof Entry)) { - return false; - } - - Entry e = (Entry)other; - return klass.equals(e.klass) && method.equals(e.method); + Asserts.assertTrue(inlineesNormal.get(4).compare("compiler.ciReplay.InliningBar", "bar2", inlineesNormal.get(4).isNormalInline())); + Asserts.assertTrue(inlineesReplay.get(4).compare("compiler.ciReplay.InliningBar", "bar2", inlineesReplay.get(4).isForcedByReplay())); } } } diff --git a/test/hotspot/jtreg/compiler/codecache/CheckCodeCacheInfo.java b/test/hotspot/jtreg/compiler/codecache/CheckCodeCacheInfo.java new file mode 100644 index 0000000000000000000000000000000000000000..26f563788f847de6f5817917446f6a6bc72184bc --- /dev/null +++ b/test/hotspot/jtreg/compiler/codecache/CheckCodeCacheInfo.java @@ -0,0 +1,79 @@ +/* + * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test CheckCodeCacheInfo + * @bug 8005885 + * @summary Checks VM verbose information related to the code cache + * @library /test/lib + * @requires vm.debug + * + * @run driver jdk.test.lib.helpers.ClassFileInstaller + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * compiler.codecache.CheckCodeCacheInfo + */ + +package compiler.codecache; + +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; + +public class CheckCodeCacheInfo { + private static final String VERBOSE_REGEXP; + + static { + String entry = "\\d+K( \\(hdr \\d+K \\d+%, loc \\d+K \\d+%, code \\d+K \\d+%, stub \\d+K \\d+%, \\[oops \\d+K \\d+%, metadata \\d+K \\d+%, data \\d+K \\d+%, pcs \\d+K \\d+%\\]\\))?\\n"; + String pair = " #\\d+ live = " + entry + + " #\\d+ dead = " + entry; + + VERBOSE_REGEXP = "nmethod blobs per compilation level:\\n" + + "none:\\n" + + pair + + "simple:\\n" + + pair + + "limited profile:\\n" + + pair + + "full profile:\\n" + + pair + + "full optimization:\\n" + + pair + + "Non-nmethod blobs:\\n" + + " #\\d+ runtime = " + entry + + " #\\d+ uncommon trap = " + entry + + " #\\d+ deoptimization = " + entry + + " #\\d+ adapter = " + entry + + " #\\d+ buffer blob = " + entry + + " #\\d+ other = " + entry; + } + + public static void main(String[] args) throws Exception { + ProcessBuilder pb; + + pb = ProcessTools.createJavaProcessBuilder("-XX:+PrintCodeCache", + "-XX:+Verbose", + "-version"); + OutputAnalyzer out = new OutputAnalyzer(pb.start()); + out.shouldHaveExitValue(0); + out.stdoutShouldMatch(VERBOSE_REGEXP); + } +} diff --git a/test/hotspot/jtreg/compiler/codecache/CodeCacheFullCountTest.java b/test/hotspot/jtreg/compiler/codecache/CodeCacheFullCountTest.java new file mode 100644 index 0000000000000000000000000000000000000000..8646c5834c662f6bb2e8bebe12bceef494123543 --- /dev/null +++ b/test/hotspot/jtreg/compiler/codecache/CodeCacheFullCountTest.java @@ -0,0 +1,129 @@ +/* + * 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 java.net.URL; +import java.net.URLClassLoader; +import java.lang.reflect.Field; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; + +/* + * @test + * @bug 8276036 8277213 8277441 + * @summary test for the value of full_count in the message of insufficient codecache + * @library /test/lib + */ +public class CodeCacheFullCountTest { + public static void main(String args[]) throws Throwable { + if (args.length == 1) { + wasteCodeCache(); + } else { + runTest(); + } + } + + public static void wasteCodeCache() throws Exception { + URL url = CodeCacheFullCountTest.class.getProtectionDomain().getCodeSource().getLocation(); + + for (int i = 0; i < 500; i++) { + ClassLoader cl = new MyClassLoader(url); + refClass(cl.loadClass("SomeClass")); + } + } + + public static void runTest() throws Throwable { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-XX:ReservedCodeCacheSize=2496k", "-XX:-UseCodeCacheFlushing", "-XX:-MethodFlushing", "CodeCacheFullCountTest", "WasteCodeCache"); + OutputAnalyzer oa = ProcessTools.executeProcess(pb); + oa.shouldHaveExitValue(0); + String stdout = oa.getStdout(); + + Pattern pattern = Pattern.compile("full_count=(\\d)"); + Matcher stdoutMatcher = pattern.matcher(stdout); + if (stdoutMatcher.find()) { + int fullCount = Integer.parseInt(stdoutMatcher.group(1)); + if (fullCount == 0) { + throw new RuntimeException("the value of full_count is wrong."); + } + } else { + throw new RuntimeException("codecache shortage did not occur."); + } + } + + private static void refClass(Class clazz) throws Exception { + Field name = clazz.getDeclaredField("NAME"); + name.setAccessible(true); + name.get(null); + } + + private static class MyClassLoader extends URLClassLoader { + public MyClassLoader(URL url) { + super(new URL[]{url}, null); + } + protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { + try { + return super.loadClass(name, resolve); + } catch (ClassNotFoundException e) { + return Class.forName(name, resolve, CodeCacheFullCountTest.class.getClassLoader()); + } + } + } +} + +abstract class Foo { + public abstract int foo(); +} + +class Foo1 extends Foo { + private int a; + public int foo() { return a; } +} + +class Foo2 extends Foo { + private int a; + public int foo() { return a; } +} + +class Foo3 extends Foo { + private int a; + public int foo() { return a; } +} + +class Foo4 extends Foo { + private int a; + public int foo() { return a; } +} + +class SomeClass { + static final String NAME = "name"; + + static { + int res =0; + Foo[] foos = new Foo[] { new Foo1(), new Foo2(), new Foo3(), new Foo4() }; + for (int i = 0; i < 100000; i++) { + res = foos[i % foos.length].foo(); + } + } +} diff --git a/test/hotspot/jtreg/compiler/codecache/OverflowCodeCacheTest.java b/test/hotspot/jtreg/compiler/codecache/OverflowCodeCacheTest.java index 1dc02e25312292cef167b78215c84df82b90fdf1..cd69d0a31daaffd6d7b8f77d701f9bc44045510a 100644 --- a/test/hotspot/jtreg/compiler/codecache/OverflowCodeCacheTest.java +++ b/test/hotspot/jtreg/compiler/codecache/OverflowCodeCacheTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -23,7 +23,7 @@ /* * @test OverflowCodeCacheTest - * @bug 8059550 + * @bug 8059550 8279356 * @summary testing of code cache segments overflow * @library /test/lib * @modules java.base/jdk.internal.misc @@ -33,11 +33,14 @@ * @run driver jdk.test.lib.helpers.ClassFileInstaller sun.hotspot.WhiteBox * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:+WhiteBoxAPI -XX:CompileCommand=compileonly,null::* - * -XX:-SegmentedCodeCache - * compiler.codecache.OverflowCodeCacheTest + * -XX:-SegmentedCodeCache -Xmixed + * compiler.codecache.OverflowCodeCacheTest CompilationDisabled * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:+WhiteBoxAPI -XX:CompileCommand=compileonly,null::* - * -XX:+SegmentedCodeCache + * -XX:+SegmentedCodeCache -Xmixed + * compiler.codecache.OverflowCodeCacheTest CompilationDisabled + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:-SegmentedCodeCache -Xmixed * compiler.codecache.OverflowCodeCacheTest */ @@ -49,13 +52,21 @@ import sun.hotspot.code.BlobType; import sun.hotspot.code.CodeBlob; import java.lang.management.MemoryPoolMXBean; +import java.lang.reflect.Method; import java.util.ArrayList; import java.util.EnumSet; +class Helper { + // Uncommon signature to prevent sharing and force creation of a new adapter + public void method(float a, float b, float c, Object o) { } +} + public class OverflowCodeCacheTest { private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); + private static boolean COMPILATION_DISABLED = false; public static void main(String[] args) { + COMPILATION_DISABLED = args.length > 0; EnumSet<BlobType> blobTypes = BlobType.getAvailable(); for (BlobType type : blobTypes) { new OverflowCodeCacheTest(type).test(); @@ -74,6 +85,8 @@ public class OverflowCodeCacheTest { System.out.println("allocating till possible..."); ArrayList<Long> blobs = new ArrayList<>(); int compilationActivityMode = -1; + // Lock compilation to be able to better control code cache space + WHITE_BOX.lockCompilation(); try { long addr; int size = (int) (getHeapSize() >> 7); @@ -88,15 +101,43 @@ public class OverflowCodeCacheTest { } } /* now, remember compilationActivityMode to check it later, after freeing, since we - possibly have no free cache for futher work */ + possibly have no free cache for further work */ compilationActivityMode = WHITE_BOX.getCompilationActivityMode(); + + // Use smallest allocation size to make sure all of the available space + // is filled up. Don't free these below to put some pressure on the sweeper. + while ((addr = WHITE_BOX.allocateCodeBlob(1, type.id)) != 0) { } } finally { + try { + // Trigger creation of a new adapter for Helper::method + // which will fail because we are out of code cache space. + Helper helper = new Helper(); + } catch (VirtualMachineError e) { + // Expected + } + // Free code cache space for (Long blob : blobs) { WHITE_BOX.freeCodeBlob(blob); } + + // Convert some nmethods to zombie and then free them to re-enable compilation + WHITE_BOX.unlockCompilation(); + WHITE_BOX.forceNMethodSweep(); + WHITE_BOX.forceNMethodSweep(); + + // Trigger compilation of Helper::method which will hit an assert because + // adapter creation failed above due to a lack of code cache space. + Helper helper = new Helper(); + for (int i = 0; i < 100_000; i++) { + helper.method(0, 0, 0, null); + } + } + // Only check this if compilation is disabled, otherwise the sweeper might have + // freed enough nmethods to allow for re-enabling compilation. + if (COMPILATION_DISABLED) { + Asserts.assertNotEquals(compilationActivityMode, 1 /* run_compilation*/, + "Compilation must be disabled when CodeCache(CodeHeap) overflows"); } - Asserts.assertNotEquals(compilationActivityMode, 1 /* run_compilation*/, - "Compilation must be disabled when CodeCache(CodeHeap) overflows"); } private long getHeapSize() { diff --git a/test/hotspot/jtreg/compiler/codecache/cli/TestSegmentedCodeCacheOption.java b/test/hotspot/jtreg/compiler/codecache/cli/TestSegmentedCodeCacheOption.java index 294dc28f84afa36d8c8c311bdf15b701db05b43b..49fa9b013ef200fdc1d63db697f393c5f6b4b88b 100644 --- a/test/hotspot/jtreg/compiler/codecache/cli/TestSegmentedCodeCacheOption.java +++ b/test/hotspot/jtreg/compiler/codecache/cli/TestSegmentedCodeCacheOption.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -56,6 +56,9 @@ public class TestSegmentedCodeCacheOption { private static final String[] UNEXPECTED_MESSAGES = new String[] { ".*" + SEGMENTED_CODE_CACHE + ".*" }; + private static final String[] XINT_EXPECTED_MESSAGE = new String[] { + "SegmentedCodeCache has no meaningful effect with -Xint" + }; private static enum TestCase { @@ -86,10 +89,11 @@ public class TestSegmentedCodeCacheOption { // ... and even w/ Xint. testCaseExitCodeMessage = "It should be possible to use " + USE_SEGMENTED_CODE_CACHE + " in interpreted mode " - + "without any errors."; + + "but it produces a warning that it is ignored."; CommandLineOptionTest.verifyJVMStartup( - /* expected messages */ null, UNEXPECTED_MESSAGES, + XINT_EXPECTED_MESSAGE, + /* unexpected messages */ null, testCaseExitCodeMessage, testCaseWarningMessage, ExitCode.OK, false, INT_MODE, USE_SEGMENTED_CODE_CACHE); } @@ -117,14 +121,6 @@ public class TestSegmentedCodeCacheOption { CommandLineOptionTest.prepareNumericFlag( BlobType.All.sizeOptionName, BELOW_THRESHOLD_CC_SIZE)); - // SCC could be explicitly enabled w/ Xint - errorMessage = String.format("It should be possible to " - + "explicitly enable %s in interpreted mode.", - SEGMENTED_CODE_CACHE); - - CommandLineOptionTest.verifyOptionValue(SEGMENTED_CODE_CACHE, - "true", errorMessage, false, INT_MODE, - USE_SEGMENTED_CODE_CACHE); // SCC could be explicitly enabled w/o TieredCompilation and w/ // small ReservedCodeCacheSize value errorMessage = String.format("It should be possible to " diff --git a/test/hotspot/jtreg/compiler/codecache/cli/codeheapsize/TestCodeHeapSizeOptions.java b/test/hotspot/jtreg/compiler/codecache/cli/codeheapsize/TestCodeHeapSizeOptions.java index 9d27c90cfaa59da916408805051b0187be481f03..52cf28a196b359731e45071f61b8bae37fe50709 100644 --- a/test/hotspot/jtreg/compiler/codecache/cli/codeheapsize/TestCodeHeapSizeOptions.java +++ b/test/hotspot/jtreg/compiler/codecache/cli/codeheapsize/TestCodeHeapSizeOptions.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -63,15 +63,9 @@ public class TestCodeHeapSizeOptions extends CodeCacheCLITestBase { private TestCodeHeapSizeOptions() { super(CodeCacheCLITestBase.OPTIONS_SET, - new CodeCacheCLITestCase(CodeCacheCLITestCase - .CommonDescriptions.INT_MODE.description, - GENERIC_RUNNER), new CodeCacheCLITestCase(CodeCacheCLITestCase .CommonDescriptions.NON_TIERED.description, GENERIC_RUNNER), - new CodeCacheCLITestCase(CodeCacheCLITestCase - .CommonDescriptions.TIERED_LEVEL_0.description, - GENERIC_RUNNER), new CodeCacheCLITestCase(CodeCacheCLITestCase .CommonDescriptions.TIERED_LEVEL_1.description, GENERIC_RUNNER), diff --git a/test/hotspot/jtreg/compiler/codecache/cli/common/CodeCacheCLITestCase.java b/test/hotspot/jtreg/compiler/codecache/cli/common/CodeCacheCLITestCase.java index 1c28a1feac8195e1197a414bd6ee213d29de58d8..91736ca1442de8d6b0301b77c51881d3e7d36c7f 100644 --- a/test/hotspot/jtreg/compiler/codecache/cli/common/CodeCacheCLITestCase.java +++ b/test/hotspot/jtreg/compiler/codecache/cli/common/CodeCacheCLITestCase.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -66,9 +66,9 @@ public class CodeCacheCLITestCase { public enum CommonDescriptions { /** * Verifies that in interpreted mode PrintCodeCache output contains - * only NonNMethod code heap. + * the whole code cache. Int mode disables SegmentedCodeCache with a warning. */ - INT_MODE(ONLY_SEGMENTED, EnumSet.of(BlobType.NonNMethod), USE_INT_MODE), + INT_MODE(ONLY_SEGMENTED, EnumSet.of(BlobType.All), USE_INT_MODE), /** * Verifies that with disabled SegmentedCodeCache PrintCodeCache output * contains only CodeCache's entry. @@ -87,11 +87,11 @@ public class CodeCacheCLITestCase { false)), /** * Verifies that with TieredStopAtLevel=0 PrintCodeCache output will - * contain information about non-nmethods and non-profiled nmethods + * warn about SegmentedCodeCache and contain information about all * heaps only. */ TIERED_LEVEL_0(SEGMENTED_SERVER, - EnumSet.of(BlobType.NonNMethod, BlobType.MethodNonProfiled), + EnumSet.of(BlobType.All), CommandLineOptionTest.prepareBooleanFlag(TIERED_COMPILATION, true), CommandLineOptionTest.prepareNumericFlag(TIERED_STOP_AT, 0)), diff --git a/test/hotspot/jtreg/compiler/codecache/stress/ReturnBlobToWrongHeapTest.java b/test/hotspot/jtreg/compiler/codecache/stress/ReturnBlobToWrongHeapTest.java index 37d570e460f52f9995cac40d6e41020569beefbe..1ef65182a0e9b6d0f666e0cc3cae2a97a80494c6 100644 --- a/test/hotspot/jtreg/compiler/codecache/stress/ReturnBlobToWrongHeapTest.java +++ b/test/hotspot/jtreg/compiler/codecache/stress/ReturnBlobToWrongHeapTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -37,6 +37,7 @@ * -XX:+SegmentedCodeCache * -XX:ReservedCodeCacheSize=16M * -XX:CodeCacheMinBlockLength=1 + * -XX:CICompilerCount=2 * compiler.codecache.stress.ReturnBlobToWrongHeapTest */ diff --git a/test/hotspot/jtreg/compiler/codegen/Test6909839.java b/test/hotspot/jtreg/compiler/codegen/Test6909839.java index d6fa98d81554c007746c243a607cdec6f2253713..5fcd5ceaceece609d81606e79cc0e65851e2f866 100644 --- a/test/hotspot/jtreg/compiler/codegen/Test6909839.java +++ b/test/hotspot/jtreg/compiler/codegen/Test6909839.java @@ -241,7 +241,7 @@ public class Test6909839 { static void testp() { Object a = new Object(); - Object b = new Object();; + Object b = new Object(); int total = 0; for (int i = 0 ; i < 10000; i++) { total += ((i % 4 != 0) ? a : b).hashCode(); @@ -251,7 +251,7 @@ public class Test6909839 { static void testup() { Object a = new Object(); - Object b = new Object();; + Object b = new Object(); int total = 0; for (int i = 0 ; i < 10000; i++) { int v = i % 4; @@ -262,7 +262,7 @@ public class Test6909839 { static void testdp() { Object a = new Object(); - Object b = new Object();; + Object b = new Object(); int total = 0; for (int i = 0 ; i < 10000; i++) { int v = i % 4; @@ -272,7 +272,7 @@ public class Test6909839 { } static void testfp() { Object a = new Object(); - Object b = new Object();; + Object b = new Object(); int total = 0; for (int i = 0 ; i < 10000; i++) { int v = i % 4; diff --git a/test/hotspot/jtreg/compiler/codegen/Test8005033.java b/test/hotspot/jtreg/compiler/codegen/Test8005033.java index 84630ad01daee0fd35754bc90b73c661d45aace1..d96983537d986f35120b935fa0ecb27b31333956 100644 --- a/test/hotspot/jtreg/compiler/codegen/Test8005033.java +++ b/test/hotspot/jtreg/compiler/codegen/Test8005033.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2012 SAP SE. 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 @@ -27,7 +28,7 @@ * @summary On sparcv9, C2's intrinsic for Integer.bitCount(OV) returns wrong result if OV is the result of an operation with int overflow. * * @run main/othervm -Xcomp - * -XX:CompileCommand=compileony,compiler.codegen.Test8005033::testBitCount + * -XX:CompileCommand=compileonly,compiler.codegen.Test8005033::testBitCount * compiler.codegen.Test8005033 * @author Richard Reingruber richard DOT reingruber AT sap DOT com */ diff --git a/test/hotspot/jtreg/compiler/codegen/TestByteVect.java b/test/hotspot/jtreg/compiler/codegen/TestByteVect.java index 385ba2dc8ea888a55be474af0d0f013ddd889910..73a2028ac7c3718f68810ba97942b24aece74b8d 100644 --- a/test/hotspot/jtreg/compiler/codegen/TestByteVect.java +++ b/test/hotspot/jtreg/compiler/codegen/TestByteVect.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -54,6 +54,7 @@ public class TestByteVect { static int test() { byte[] a1 = new byte[ARRLEN]; byte[] a2 = new byte[ARRLEN]; + byte[] a3 = new byte[ARRLEN]; System.out.println("Warmup"); for (int i=0; i<ITERS; i++) { test_ci(a1); @@ -94,6 +95,16 @@ public class TestByteVect { test_cp_unalnsrc(a1, a2); test_2ci_unaln(a1, a2); test_2vi_unaln(a1, a2, (byte)123, (byte)103); + test_addImm127(a1, a2); + test_addImm(a1, a2, a3); + test_addImm256(a1, a2); + test_addImmNeg128(a1, a2); + test_addImmNeg129(a1, a2); + test_subImm(a1, a2, a3); + test_andImm21(a1, a2); + test_andImm7(a1, a2); + test_orImm(a1, a2); + test_xorImm(a1, a2, a3); } // Initialize for (int i=0; i<ARRLEN; i++) { @@ -487,6 +498,77 @@ public class TestByteVect { for (int i=ARRLEN-UNALIGN_OFF; i<ARRLEN; i++) { errn += verify("test_2vi_unaln_overlap: a1", i, a1[i], (byte)103); } + byte base = (byte) 10; + for (int i = 0; i < ARRLEN; i++) { + a1[i] = (byte) 10; + } + byte golden = (byte)(base + 127); + test_addImm127(a1, a2); + for (int i=0; i<ARRLEN; i++) { + errn += verify("test_addImm127: a2", i, a2[i], golden); + } + test_addImm(a1, a2, a3); + golden = (byte)(base + 8); + for (int i=0; i<ARRLEN; i++) { + errn += verify("test_addImm: a2", i, a2[i], golden); + } + golden = (byte) (base + 255); + for (int i=0; i<ARRLEN; i++) { + errn += verify("test_addImm: a3", i, a3[i], golden); + } + test_addImm256(a1, a2); + golden = (byte)(base + 256); + for (int i=0; i<ARRLEN; i++) { + errn += verify("test_addImm256: a3", i, a2[i], golden); + } + test_addImmNeg128(a1, a2); + golden = (byte)(base + (-128)); + for (int i=0; i<ARRLEN; i++) { + errn += verify("test_addImmNeg128: a2", i, a2[i], golden); + } + test_addImmNeg129(a1, a2); + golden = (byte)(base + (-129)); + for (int i=0; i<ARRLEN; i++) { + errn += verify("test_addImmNeg129: a2", i, a2[i], golden); + } + // Reset for sub test + base = (byte) 120; + for (int i = 0; i < ARRLEN; i++) { + a1[i] = (byte) 120; + } + test_subImm(a1, a2, a3); + golden = (byte) (base - 56); + for (int i=0; i<ARRLEN; i++) { + errn += verify("test_subImm: a2", i, a2[i], golden); + } + golden = (byte) (base - 256); + for (int i=0; i<ARRLEN; i++) { + errn += verify("test_subImm: a3", i, a3[i], golden); + } + test_andImm21(a1, a2); + golden = (byte) (base & 21); + for (int i=0; i<ARRLEN; i++) { + errn += verify("test_andImm21: a2", i, a2[i], golden); + } + test_andImm7(a1, a2); + golden = (byte) (base & 7); + for (int i=0; i<ARRLEN; i++) { + errn += verify("test_andImm7: a2", i, a2[i], golden); + } + test_orImm(a1, a2); + golden = (byte) (base | 3); + for (int i=0; i<ARRLEN; i++) { + errn += verify("test_orImm: a2", i, a2[i], golden); + } + test_xorImm(a1, a2, a3); + golden = (byte) (base ^ 127); + for (int i=0; i<ARRLEN; i++) { + errn += verify("test_xorImm: a2", i, a2[i], golden); + } + golden = (byte) (base ^ 255); + for (int i=0; i<ARRLEN; i++) { + errn += verify("test_xorImm: a3", i, a3[i], golden); + } } @@ -730,6 +812,59 @@ public class TestByteVect { } end = System.currentTimeMillis(); System.out.println("test_2vi_unaln: " + (end - start)); + start = System.currentTimeMillis(); + for (int i=0; i<ITERS; i++) { + test_addImm127(a1, a2); + } + end = System.currentTimeMillis(); + System.out.println("test_addImm127: " + (end - start)); + start = System.currentTimeMillis(); + for (int i=0; i<ITERS; i++) { + test_addImm(a1, a2, a3); + } + end = System.currentTimeMillis(); + System.out.println("test_addImm: " + (end - start)); + start = System.currentTimeMillis(); + for (int i=0; i<ITERS; i++) { + test_addImm256(a1, a2); + } + end = System.currentTimeMillis(); + System.out.println("test_addImm256: " + (end - start)); + start = System.currentTimeMillis(); + for (int i=0; i<ITERS; i++) { + test_addImmNeg128(a1, a2); + } + end = System.currentTimeMillis(); + System.out.println("test_addImmNeg128: " + (end - start)); + start = System.currentTimeMillis(); + for (int i=0; i<ITERS; i++) { + test_addImmNeg129(a1, a2); + } + end = System.currentTimeMillis(); + System.out.println("test_addImmNeg129: " + (end - start)); + start = System.currentTimeMillis(); + for (int i=0; i<ITERS; i++) { + test_subImm(a1, a2, a3); + } + end = System.currentTimeMillis(); + System.out.println("test_subImm: " + (end - start)); + start = System.currentTimeMillis(); + for (int i=0; i<ITERS; i++) { + test_andImm7(a1, a2); + } + end = System.currentTimeMillis(); + System.out.println("test_andImm7: " + (end - start)); + start = System.currentTimeMillis(); + for (int i=0; i<ITERS; i++) { + test_orImm(a1, a2); + } + end = System.currentTimeMillis(); + System.out.println("test_orImm: " + (end - start)); + start = System.currentTimeMillis(); + for (int i=0; i<ITERS; i++) { + test_xorImm(a1, a2, a3); + } + end = System.currentTimeMillis(); return errn; } @@ -945,6 +1080,59 @@ public class TestByteVect { b[i+UNALIGN_OFF] = d; } } + static void test_addImm127(byte[] a, byte[] b) { + for (int i = 0; i < a.length; i++) { + b[i] = (byte) (a[i] + 127); + } + } + static void test_addImm(byte[] a, byte[] b, byte[] c) { + for (int i = 0; i < a.length; i++) { + b[i] = (byte) (a[i] + 8); + c[i] = (byte) (a[i] + 255); + } + } + static void test_addImm256(byte[] a, byte[] b) { + for (int i = 0; i < a.length; i++) { + b[i] = (byte) (a[i] + 256); + } + } + static void test_addImmNeg128(byte[] a, byte[] b) { + for (int i = 0; i < a.length; i++) { + b[i] = (byte) (a[i] + (-128)); + } + } + static void test_addImmNeg129(byte[] a, byte[] b) { + for (int i = 0; i < a.length; i++) { + b[i] = (byte) (a[i] + (-129)); + } + } + static void test_subImm(byte[] a, byte[] b, byte[] c) { + for (int i = 0; i < a.length; i++) { + b[i] = (byte) (a[i] - 56); + c[i] = (byte) (a[i] - 256); + } + } + static void test_andImm21(byte[] a, byte[] b) { + for (int i = 0; i < a.length; i++) { + b[i] = (byte) (a[i] & 21); + } + } + static void test_andImm7(byte[] a, byte[] b) { + for (int i = 0; i < a.length; i++) { + b[i] = (byte) (a[i] & 7); + } + } + static void test_orImm(byte[] a, byte[] b) { + for (int i = 0; i < a.length; i++) { + b[i] = (byte) (a[i] | 3); + } + } + static void test_xorImm(byte[] a, byte[] b, byte[] c) { + for (int i = 0; i < a.length; i++) { + b[i] = (byte) (a[i] ^ 127); + c[i] = (byte) (a[i] ^ 255); + } + } static int verify(String text, int i, byte elem, byte val) { if (elem != val) { diff --git a/test/hotspot/jtreg/compiler/codegen/TestCharVect.java b/test/hotspot/jtreg/compiler/codegen/TestCharVect.java index 1cef590c15bc8aa122e334ab54c9eb9d9ae297e2..cd5d5df82f6dd282eb187210d0bf97de79440c83 100644 --- a/test/hotspot/jtreg/compiler/codegen/TestCharVect.java +++ b/test/hotspot/jtreg/compiler/codegen/TestCharVect.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -54,6 +54,7 @@ public class TestCharVect { static int test() { char[] a1 = new char[ARRLEN]; char[] a2 = new char[ARRLEN]; + char[] a3 = new char[ARRLEN]; System.out.println("Warmup"); for (int i=0; i<ITERS; i++) { test_ci(a1); @@ -94,6 +95,13 @@ public class TestCharVect { test_cp_unalnsrc(a1, a2); test_2ci_unaln(a1, a2); test_2vi_unaln(a1, a2, (char)123, (char)103); + test_addImm129(a1, a2); + test_addImm(a1, a2, a3); + test_subImm56(a1, a2); + test_subImm256(a1, a2); + test_andImm(a1, a2); + test_orImm(a1, a2); + test_xorImm(a1, a2); } // Initialize for (int i=0; i<ARRLEN; i++) { @@ -487,6 +495,56 @@ public class TestCharVect { for (int i=ARRLEN-UNALIGN_OFF; i<ARRLEN; i++) { errn += verify("test_2vi_unaln_overlap: a1", i, a1[i], (char)103); } + // Reset for binary operation with immediate. + char base = (char) 3; + for (int i = 0; i < ARRLEN; i++) { + a1[i] = (char) 3; + } + char golden = (char)(base + 129); + test_addImm129(a1, a2); + for (int i=0; i<ARRLEN; i++) { + errn += verify("test_addImm129: a2", i, a2[i], golden); + } + test_addImm(a1, a2, a3); + golden = (char)(base + 129); + for (int i=0; i<ARRLEN; i++) { + errn += verify("test_addImm: a2", i, a2[i], golden); + } + golden = (char) (base + 255); + for (int i=0; i<ARRLEN; i++) { + errn += verify("test_addImm: a3", i, a3[i], golden); + } + // Reset for sub operation test. + base = (char) 120; + for (int i = 0; i < ARRLEN; i++) { + a1[i] = (char) 120; + } + test_subImm56(a1, a2); + golden = (char) (base - 56); + for (int i=0; i<ARRLEN; i++) { + errn += verify("test_subImm56: a2", i, a2[i], golden); + } + test_subImm256(a1, a2); + golden = (char) (base - 256); + for (int i=0; i<ARRLEN; i++) { + errn += verify("test_subImm256: a2", i, a2[i], golden); + } + test_andImm(a1, a2); + golden = (char) (base & 0xfe); + for (int i=0; i<ARRLEN; i++) { + errn += verify("test_andImm: a2", i, a2[i], golden); + } + test_orImm(a1, a2); + golden = (char) (base | 0xff); + for (int i=0; i<ARRLEN; i++) { + errn += verify("test_orImm: a2", i, a2[i], golden); + } + test_xorImm(a1, a2); + golden = (char) (base ^ 0xc7); + for (int i=0; i<ARRLEN; i++) { + errn += verify("test_xorImm: a2", i, a2[i], golden); + } + } @@ -730,6 +788,49 @@ public class TestCharVect { } end = System.currentTimeMillis(); System.out.println("test_2vi_unaln: " + (end - start)); + start = System.currentTimeMillis(); + for (int i=0; i<ITERS; i++) { + test_addImm129(a1, a2); + } + end = System.currentTimeMillis(); + System.out.println("test_addImm129: " + (end - start)); + start = System.currentTimeMillis(); + for (int i=0; i<ITERS; i++) { + test_addImm(a1, a2, a3); + } + end = System.currentTimeMillis(); + System.out.println("test_addImm: " + (end - start)); + start = System.currentTimeMillis(); + for (int i=0; i<ITERS; i++) { + test_subImm56(a1, a2); + } + end = System.currentTimeMillis(); + System.out.println("test_subImm56: " + (end - start)); + start = System.currentTimeMillis(); + for (int i=0; i<ITERS; i++) { + test_subImm256(a1, a2); + } + end = System.currentTimeMillis(); + System.out.println("test_subImm256: " + (end - start)); + start = System.currentTimeMillis(); + for (int i=0; i<ITERS; i++) { + test_andImm(a1, a2); + } + end = System.currentTimeMillis(); + System.out.println("test_andImm: " + (end - start)); + start = System.currentTimeMillis(); + for (int i=0; i<ITERS; i++) { + test_orImm(a1, a2); + } + end = System.currentTimeMillis(); + System.out.println("test_orImm: " + (end - start)); + start = System.currentTimeMillis(); + for (int i=0; i<ITERS; i++) { + test_xorImm(a1, a2); + } + end = System.currentTimeMillis(); + System.out.println("test_xorImm: " + (end - start)); + return errn; } @@ -945,6 +1046,47 @@ public class TestCharVect { b[i+UNALIGN_OFF] = d; } } + static void test_addImm129(char[] a, char[] b) { + for (int i = 0; i < a.length; i++) { + b[i] = (char) (a[i] + 129); + } + } + static void test_addImm(char[] a, char[] b, char[] c) { + for (int i = 0; i < a.length; i++) { + b[i] = (char) (a[i] + 129); + c[i] = (char) (a[i] + 255); + } + } + + static void test_subImm56(char[] a, char[] b) { + for (int i = 0; i < a.length; i++) { + b[i] = (char) (a[i] - 56); + } + } + + static void test_subImm256(char[] a, char[] b) { + for (int i = 0; i < a.length; i++) { + b[i] = (char) (a[i] - 256); + } + } + + static void test_andImm(char[] a, char[] b) { + for (int i = 0; i < a.length; i++) { + b[i] = (char) (a[i] & 0xfe); + } + } + + static void test_orImm(char[] a, char[] b) { + for (int i = 0; i < a.length; i++) { + b[i] = (char) (a[i] | 0xff); + } + } + + static void test_xorImm(char[] a, char[] b) { + for (int i = 0; i < a.length; i++) { + b[i] = (char) (a[i] ^ 0xc7); + } + } static int verify(String text, int i, char elem, char val) { if (elem != val) { diff --git a/test/hotspot/jtreg/compiler/codegen/TestIntFloatVect.java b/test/hotspot/jtreg/compiler/codegen/TestIntFloatVect.java index 9074a699738291b0a47869a1c1e13fce6565619a..be8acc6cb29a908edbdf42f3c5332572342af701 100644 --- a/test/hotspot/jtreg/compiler/codegen/TestIntFloatVect.java +++ b/test/hotspot/jtreg/compiler/codegen/TestIntFloatVect.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -75,6 +75,8 @@ public class TestIntFloatVect { test_vi_unaln(a1, b1, (int)123, 103.f); test_cp_unalndst(a1, a2, b1, b2); test_cp_unalnsrc(a1, a2, b1, b2); + test_conv_i2f(a1, b1); + test_conv_f2i(a1, b1); } // Initialize for (int i=0; i<ARRLEN; i++) { @@ -338,6 +340,72 @@ public class TestIntFloatVect { errn += verify("test_cp_unalnsrc_overlap: a1", i, a1[i], (int)v); errn += verify("test_cp_unalnsrc_overlap: b1", i, b1[i], (float)v); } + // Reset to test conversion from int to float. + for (int i=0; i<ARRLEN; i++) { + a1[i] = (int)i; + } + test_conv_i2f(a1, b1); + for (int i=0; i<ARRLEN; i++) { + errn += verify("test_conv_i2f: a1", i, b1[i], (float)i); + } + // Reset to test conversion from float to int. + for (int i=0; i<ARRLEN; i++) { + b1[i] = (float)(i+1); + } + test_conv_f2i(a1, b1); + for (int i=0; i<ARRLEN; i++) { + errn += verify("test_conv_f2i: a1", i, a1[i], (i+1)); + } + // Reset to test NAN conversion from int to float. + for (int i=0; i<ARRLEN; i++) { + a1[i] = Integer.MIN_VALUE; + } + test_conv_i2f(a1, b1); + for (int i=0; i<ARRLEN; i++) { + errn += verify("test_conv_i2f: a1", i, b1[i], (float)Integer.MIN_VALUE); + } + for (int i=0; i<ARRLEN; i++) { + a1[i] = Integer.MAX_VALUE; + } + test_conv_i2f(a1, b1); + for (int i=0; i<ARRLEN; i++) { + errn += verify("test_conv_i2f: a1", i, b1[i], (float)Integer.MAX_VALUE); + } + for (int i=0; i<ARRLEN; i++) { + b1[i] = Float.NaN; + } + test_conv_f2i(a1, b1); + for (int i=0; i<ARRLEN; i++) { + errn += verify("test_conv_f2i: a1", i, a1[i], (int)Float.NaN); + } + for (int i=0; i<ARRLEN; i++) { + b1[i] = Float.POSITIVE_INFINITY; + } + test_conv_f2i(a1, b1); + for (int i=0; i<ARRLEN; i++) { + errn += verify("test_conv_f2i: a1", i, a1[i], (int)Float.POSITIVE_INFINITY); + } + for (int i=0; i<ARRLEN; i++) { + b1[i] = Float.NEGATIVE_INFINITY; + } + test_conv_f2i(a1, b1); + for (int i=0; i<ARRLEN; i++) { + errn += verify("test_conv_f2i: a1", i, a1[i], (int)Float.NEGATIVE_INFINITY); + } + for (int i=0; i<ARRLEN; i++) { + b1[i] = 0.0f; + } + test_conv_f2i(a1, b1); + for (int i=0; i<ARRLEN; i++) { + errn += verify("test_conv_f2i: a1", i, a1[i], (int)0.0); + } + for (int i=0; i<ARRLEN; i++) { + b1[i] = -0.0f; + } + test_conv_f2i(a1, b1); + for (int i=0; i<ARRLEN; i++) { + errn += verify("test_conv_f2i: a1", i, a1[i], (int)(-0.0)); + } } @@ -448,6 +516,18 @@ public class TestIntFloatVect { } end = System.currentTimeMillis(); System.out.println("test_cp_unalnsrc: " + (end - start)); + start = System.currentTimeMillis(); + for (int i=0; i<ITERS; i++) { + test_conv_i2f(a1, b1); + } + end = System.currentTimeMillis(); + System.out.println("test_conv_i2f: " + (end - start)); + start = System.currentTimeMillis(); + for (int i=0; i<ITERS; i++) { + test_conv_f2i(a1, b1); + } + end = System.currentTimeMillis(); + System.out.println("test_conv_f2i: " + (end - start)); return errn; } @@ -556,6 +636,16 @@ public class TestIntFloatVect { c[i] = d[i+UNALIGN_OFF]; } } + static void test_conv_i2f(int[] a, float[] b){ + for (int i = 0; i < a.length; i+=1) { + b[i] = (float)a[i]; + } + } + static void test_conv_f2i(int[] a, float[] b){ + for (int i = 0; i < a.length; i+=1) { + a[i] = (int)b[i]; + } + } static int verify(String text, int i, int elem, int val) { if (elem != val) { @@ -565,7 +655,7 @@ public class TestIntFloatVect { return 0; } static int verify(String text, int i, float elem, float val) { - if (elem != val) { + if (elem != val && !(Float.isNaN(elem) && Float.isNaN(val))) { System.err.println(text + "[" + i + "] = " + elem + " != " + val); return 1; } diff --git a/test/hotspot/jtreg/compiler/codegen/TestIntVect.java b/test/hotspot/jtreg/compiler/codegen/TestIntVect.java index 1eb4a980f4bdcf3475ff401c87acb179c878a361..f4040aafbbf3d7dd337f601a7e939753fdbc3e4a 100644 --- a/test/hotspot/jtreg/compiler/codegen/TestIntVect.java +++ b/test/hotspot/jtreg/compiler/codegen/TestIntVect.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -54,6 +54,7 @@ public class TestIntVect { static int test() { int[] a1 = new int[ARRLEN]; int[] a2 = new int[ARRLEN]; + int[] a3 = new int[ARRLEN]; System.out.println("Warmup"); for (int i=0; i<ITERS; i++) { test_ci(a1); @@ -94,6 +95,13 @@ public class TestIntVect { test_cp_unalnsrc(a1, a2); test_2ci_unaln(a1, a2); test_2vi_unaln(a1, a2, (int)123, (int)103); + test_addImm127(a1, a2); + test_addImm(a1, a2, a3); + test_addImm256(a1, a2); + test_subImm(a1, a2, a3); + test_andImm(a1, a2, a3); + test_orImm(a1, a2); + test_xorImm(a1, a2); } // Initialize for (int i=0; i<ARRLEN; i++) { @@ -487,6 +495,63 @@ public class TestIntVect { for (int i=ARRLEN-UNALIGN_OFF; i<ARRLEN; i++) { errn += verify("test_2vi_unaln_overlap: a1", i, a1[i], (int)103); } + // Reset for binary operation with immediate + int base = 10; + for (int i = 0; i < ARRLEN; i++) { + a1[i] = 10; + } + int golden = base + 127; + test_addImm127(a1, a2); + for (int i=0; i<ARRLEN; i++) { + errn += verify("test_addImm127: a2", i, a2[i], golden); + } + test_addImm(a1, a2, a3); + golden = base + 127; + for (int i=0; i<ARRLEN; i++) { + errn += verify("test_addImm: a2", i, a2[i], golden); + } + golden = base + 255; + for (int i=0; i<ARRLEN; i++) { + errn += verify("test_addImm: a3", i, a3[i], golden); + } + test_addImm256(a1, a2); + golden = base + 256; + for (int i=0; i<ARRLEN; i++) { + errn += verify("test_addImm256: a2", i, a2[i], golden); + } + // Reset for sub test + base = 10000; + for (int i = 0; i < ARRLEN; i++) { + a1[i] = 10000; + } + test_subImm(a1, a2, a3); + golden = base - 2304; + for (int i=0; i<ARRLEN; i++) { + errn += verify("test_subImm: a2", i, a2[i], golden); + } + golden = base - 65280; + for (int i=0; i<ARRLEN; i++) { + errn += verify("test_subImm: a3", i, a3[i], golden); + } + test_andImm(a1, a2, a3); + golden = base + 2560; + for (int i=0; i<ARRLEN; i++) { + errn += verify("test_andImm: a2", i, a2[i], golden); + } + golden = base & 516096; + for (int i=0; i<ARRLEN; i++) { + errn += verify("test_andImm: a3", i, a3[i], golden); + } + test_orImm(a1, a2); + golden = base | 8257536; + for (int i=0; i<ARRLEN; i++) { + errn += verify("test_orImm: a2", i, a2[i], golden); + } + test_xorImm(a1, a2); + golden = base ^ 2032; + for (int i=0; i<ARRLEN; i++) { + errn += verify("test_xorImm: a2", i, a2[i], golden); + } } @@ -730,6 +795,48 @@ public class TestIntVect { } end = System.currentTimeMillis(); System.out.println("test_2vi_unaln: " + (end - start)); + start = System.currentTimeMillis(); + for (int i=0; i<ITERS; i++) { + test_addImm127(a1, a2); + } + end = System.currentTimeMillis(); + System.out.println("test_addImm127: " + (end - start)); + start = System.currentTimeMillis(); + for (int i=0; i<ITERS; i++) { + test_addImm(a1, a2, a3); + } + end = System.currentTimeMillis(); + System.out.println("test_addImm: " + (end - start)); + start = System.currentTimeMillis(); + for (int i=0; i<ITERS; i++) { + test_addImm256(a1, a2); + } + end = System.currentTimeMillis(); + System.out.println("test_addImm256: " + (end - start)); + start = System.currentTimeMillis(); + for (int i=0; i<ITERS; i++) { + test_subImm(a1, a2, a3); + } + end = System.currentTimeMillis(); + System.out.println("test_subImm: " + (end - start)); + start = System.currentTimeMillis(); + for (int i=0; i<ITERS; i++) { + test_andImm(a1, a2, a3); + } + end = System.currentTimeMillis(); + System.out.println("test_andImm: " + (end - start)); + start = System.currentTimeMillis(); + for (int i=0; i<ITERS; i++) { + test_orImm(a1, a2); + } + end = System.currentTimeMillis(); + System.out.println("test_orImm: " + (end - start)); + start = System.currentTimeMillis(); + for (int i=0; i<ITERS; i++) { + test_xorImm(a1, a2); + } + end = System.currentTimeMillis(); + System.out.println("test_xorImm: " + (end - start)); return errn; } @@ -945,6 +1052,50 @@ public class TestIntVect { b[i+UNALIGN_OFF] = d; } } + static void test_addImm127(int[] a, int[] b) { + for (int i = 0; i < a.length; i++) { + b[i] = a[i] + 127; + } + } + static void test_addImm(int[] a, int[] b, int[] c) { + for (int i = 0; i < a.length; i++) { + b[i] = a[i] + 127; + c[i] = a[i] + 255; + } + } + static void test_addImm256(int[] a, int[] b) { + for (int i = 0; i < a.length; i++) { + b[i] = a[i] + 256; + } + } + static void test_subImm(int[] a, int[] b, int[] c) { + for (int i = 0; i < a.length; i++) { + b[i] = a[i] - 2304; + c[i] = a[i] - 65280; + } + } + static void test_andImm21(int[] a, int[] b) { + for (int i = 0; i < a.length; i++) { + b[i] = a[i] & 21; + } + } + static void test_andImm(int[] a, int[] b, int[] c) { + for (int i = 0; i < a.length; i++) { + b[i] = a[i] + 2560; + c[i] = a[i] & 516096; + } + } + static void test_orImm(int[] a, int[] b) { + for (int i = 0; i < a.length; i++) { + b[i] = a[i] | 8257536; + } + } + static void test_xorImm(int[] a, int[] b) { + for (int i = 0; i < a.length; i++) { + b[i] = a[i] ^ 2032; + } + } + static int verify(String text, int i, int elem, int val) { if (elem != val) { diff --git a/test/hotspot/jtreg/compiler/codegen/TestLongDoubleVect.java b/test/hotspot/jtreg/compiler/codegen/TestLongDoubleVect.java index 47517a19f8d42c06743b712bab8ce64b3eeb4cfb..b65e549ac143837fff0f6b2b137cbcff4b485d0c 100644 --- a/test/hotspot/jtreg/compiler/codegen/TestLongDoubleVect.java +++ b/test/hotspot/jtreg/compiler/codegen/TestLongDoubleVect.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -75,6 +75,8 @@ public class TestLongDoubleVect { test_vi_unaln(a1, b1, (long)123, 103.); test_cp_unalndst(a1, a2, b1, b2); test_cp_unalnsrc(a1, a2, b1, b2); + test_conv_l2d(a1, b1); + test_conv_d2l(a1, b1); } // Initialize for (int i=0; i<ARRLEN; i++) { @@ -338,6 +340,72 @@ public class TestLongDoubleVect { errn += verify("test_cp_unalnsrc_overlap: a1", i, a1[i], (long)v); errn += verify("test_cp_unalnsrc_overlap: b1", i, b1[i], (double)v); } + // Reset to test conversion from int to float. + for (int i=0; i<ARRLEN; i++) { + a1[i] = (long)i; + } + test_conv_l2d(a1, b1); + for (int i=0; i<ARRLEN; i++) { + errn += verify("test_conv_l2d: a1", i, b1[i], (double)i); + } + // Reset to test conversion from float to int. + for (int i=0; i<ARRLEN; i++) { + b1[i] = (double)(i+1); + } + test_conv_d2l(a1, b1); + for (int i=0; i<ARRLEN; i++) { + errn += verify("test_conv_d2l: a1", i, a1[i], (long)(i+1)); + } + // Reset to test special conversion from int to float. + for (int i=0; i<ARRLEN; i++) { + b1[i] = Double.NaN; + } + test_conv_d2l(a1, b1); + for (int i=0; i<ARRLEN; i++) { + errn += verify("test_conv_d2l: a1", i, a1[i], (long)Double.NaN); + } + for (int i=0; i<ARRLEN; i++) { + a1[i] = Long.MIN_VALUE; + } + test_conv_l2d(a1, b1); + for (int i=0; i<ARRLEN; i++) { + errn += verify("test_conv_l2d: a1", i, b1[i], (double)Long.MIN_VALUE); + } + for (int i=0; i<ARRLEN; i++) { + a1[i] = Long.MAX_VALUE; + } + test_conv_l2d(a1, b1); + for (int i=0; i<ARRLEN; i++) { + errn += verify("test_conv_l2d: a1", i, b1[i], (double)Long.MAX_VALUE); + } + for (int i=0; i<ARRLEN; i++) { + b1[i] = Double.POSITIVE_INFINITY; + } + test_conv_d2l(a1, b1); + for (int i=0; i<ARRLEN; i++) { + errn += verify("test_conv_d2l: a1", i, a1[i], (long)Double.POSITIVE_INFINITY); + } + for (int i=0; i<ARRLEN; i++) { + b1[i] = Double.NEGATIVE_INFINITY; + } + test_conv_d2l(a1, b1); + for (int i=0; i<ARRLEN; i++) { + errn += verify("test_conv_d2l: a1", i, a1[i], (long)Double.NEGATIVE_INFINITY); + } + for (int i=0; i<ARRLEN; i++) { + b1[i] = 0.0; + } + test_conv_d2l(a1, b1); + for (int i=0; i<ARRLEN; i++) { + errn += verify("test_conv_d2l: a1", i, a1[i], (long)0.0); + } + for (int i=0; i<ARRLEN; i++) { + b1[i] = -0.0; + } + test_conv_d2l(a1, b1); + for (int i=0; i<ARRLEN; i++) { + errn += verify("test_conv_d2l: a1", i, a1[i], (long)(-0.0)); + } } @@ -448,6 +516,18 @@ public class TestLongDoubleVect { } end = System.currentTimeMillis(); System.out.println("test_cp_unalnsrc: " + (end - start)); + start = System.currentTimeMillis(); + for (int i=0; i<ITERS; i++) { + test_conv_l2d(a1, b1); + } + end = System.currentTimeMillis(); + System.out.println("test_conv_l2d: " + (end - start)); + start = System.currentTimeMillis(); + for (int i=0; i<ITERS; i++) { + test_conv_d2l(a1, b1); + } + end = System.currentTimeMillis(); + System.out.println("test_conv_d2l: " + (end - start)); return errn; } @@ -556,6 +636,16 @@ public class TestLongDoubleVect { c[i] = d[i+UNALIGN_OFF]; } } + static void test_conv_l2d(long[] a, double[] b){ + for (int i = 0; i < a.length; i+=1) { + b[i] = (double)a[i]; + } + } + static void test_conv_d2l(long[] a, double[] b){ + for (int i = 0; i < a.length; i+=1) { + a[i] = (long)b[i]; + } + } static int verify(String text, int i, long elem, long val) { if (elem != val) { @@ -565,7 +655,7 @@ public class TestLongDoubleVect { return 0; } static int verify(String text, int i, double elem, double val) { - if (elem != val) { + if (elem != val && !(Double.isNaN(elem) && Double.isNaN(val))) { System.err.println(text + "[" + i + "] = " + elem + " != " + val); return 1; } diff --git a/test/hotspot/jtreg/compiler/codegen/TestLongVect.java b/test/hotspot/jtreg/compiler/codegen/TestLongVect.java index 512c2d6d13f48985de5e9673757d8008c4735998..55deee514cb28dcac83e9b6e7c1bc2843c889d72 100644 --- a/test/hotspot/jtreg/compiler/codegen/TestLongVect.java +++ b/test/hotspot/jtreg/compiler/codegen/TestLongVect.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -54,6 +54,7 @@ public class TestLongVect { static int test() { long[] a1 = new long[ARRLEN]; long[] a2 = new long[ARRLEN]; + long[] a3 = new long[ARRLEN]; System.out.println("Warmup"); for (int i=0; i<ITERS; i++) { test_ci(a1); @@ -94,6 +95,12 @@ public class TestLongVect { test_cp_unalnsrc(a1, a2); test_2ci_unaln(a1, a2); test_2vi_unaln(a1, a2, (long)123, (long)103); + test_addImm(a1, a2, a3); + test_subImm(a1, a2, a3); + test_subImm256(a1, a2); + test_andImm(a1, a2); + test_orImm(a1, a2); + test_xorImm(a1, a2); } // Initialize for (int i=0; i<ARRLEN; i++) { @@ -487,6 +494,53 @@ public class TestLongVect { for (int i=ARRLEN-UNALIGN_OFF; i<ARRLEN; i++) { errn += verify("test_2vi_unaln_overlap: a1", i, a1[i], (long)103); } + // Reset for binary operations with immediate. + for (int i=0; i<ARRLEN; i++) { + a1[i] = 10; + } + long base = 10; + test_addImm(a1, a2, a3); + long golden = base & 516097; + for (int i=0; i<ARRLEN; i++) { + errn += verify("test_addImm: a2", i, a2[i], golden); + } + golden = base + 65280; + for (int i=0; i<ARRLEN; i++) { + errn += verify("test_addImm: a3", i, a3[i], golden); + } + base = 120; + for (int i=0; i<ARRLEN; i++) { + a1[i] = 120; + } + test_subImm(a1, a2, a3); + golden = base + 65535; + for (int i=0; i<ARRLEN; i++) { + errn += verify("test_subImm: a2", i, a2[i], golden); + } + golden = base - 2147483647; + for (int i=0; i<ARRLEN; i++) { + errn += verify("test_subImm: a3", i, a3[i], golden); + } + test_subImm256(a1, a2); + golden = base - 256; + for (int i=0; i<ARRLEN; i++) { + errn += verify("test_subImm256: a2", i, a2[i], golden); + } + test_andImm(a1, a2); + golden = base & 132120576; + for (int i=0; i<ARRLEN; i++) { + errn += verify("test_andImm: a2", i, a2[i], golden); + } + test_orImm(a1, a2); + golden = base | 2113929216; + for (int i=0; i<ARRLEN; i++) { + errn += verify("test_orImm: a2", i, a2[i], golden); + } + test_xorImm(a1, a2); + golden = base ^ 516096; + for (int i=0; i<ARRLEN; i++) { + errn += verify("test_xorImm: a2", i, a2[i], golden); + } } @@ -730,6 +784,42 @@ public class TestLongVect { } end = System.currentTimeMillis(); System.out.println("test_2vi_unaln: " + (end - start)); + start = System.currentTimeMillis(); + for (int i=0; i<ITERS; i++) { + test_addImm(a1, a2, a3); + } + end = System.currentTimeMillis(); + System.out.println("test_addImm: " + (end - start)); + start = System.currentTimeMillis(); + for (int i=0; i<ITERS; i++) { + test_subImm(a1, a2, a3); + } + end = System.currentTimeMillis(); + System.out.println("test_subImm: " + (end - start)); + start = System.currentTimeMillis(); + for (int i=0; i<ITERS; i++) { + test_subImm256(a1, a2); + } + end = System.currentTimeMillis(); + System.out.println("test_subImm256: " + (end - start)); + start = System.currentTimeMillis(); + for (int i=0; i<ITERS; i++) { + test_andImm(a1, a2); + } + end = System.currentTimeMillis(); + System.out.println("test_andImm: " + (end - start)); + start = System.currentTimeMillis(); + for (int i=0; i<ITERS; i++) { + test_orImm(a1, a2); + } + end = System.currentTimeMillis(); + System.out.println("test_orImm: " + (end - start)); + start = System.currentTimeMillis(); + for (int i=0; i<ITERS; i++) { + test_xorImm(a1, a2); + } + end = System.currentTimeMillis(); + System.out.println("test_xorImm: " + (end - start)); return errn; } @@ -946,6 +1036,44 @@ public class TestLongVect { } } + static void test_addImm(long[] a, long[] b, long[] c) { + for (int i = 0; i < a.length; i++) { + b[i] = a[i] & 516097; + c[i] = a[i] + 65280; + } + } + + static void test_subImm(long[] a, long[] b, long[] c) { + for (int i = 0; i < a.length; i++) { + b[i] = a[i] + 65535; + c[i] = a[i] - 2147483647; + } + } + + static void test_subImm256(long[] a, long[] b) { + for (int i = 0; i < a.length; i++) { + b[i] = a[i] - 256; + } + } + + static void test_andImm(long[] a, long[] b) { + for (int i = 0; i < a.length; i++) { + b[i] = a[i] & 132120576; + } + } + + static void test_orImm(long[] a, long[] b) { + for (int i = 0; i < a.length; i++) { + b[i] = a[i] | 2113929216; + } + } + + static void test_xorImm(long[] a, long[] b) { + for (int i = 0; i < a.length; i++) { + b[i] = a[i] ^ 516096; + } + } + static int verify(String text, int i, long elem, long val) { if (elem != val) { System.err.println(text + "[" + i + "] = " + elem + " != " + val); diff --git a/test/hotspot/jtreg/compiler/codegen/TestShortVect.java b/test/hotspot/jtreg/compiler/codegen/TestShortVect.java index 03c0c9f8c36fdf35ec910ca08459e5030ccd7f9a..0fbb8a0631a6308646928ecb17817714007a9823 100644 --- a/test/hotspot/jtreg/compiler/codegen/TestShortVect.java +++ b/test/hotspot/jtreg/compiler/codegen/TestShortVect.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -54,6 +54,7 @@ public class TestShortVect { static int test() { short[] a1 = new short[ARRLEN]; short[] a2 = new short[ARRLEN]; + short[] a3 = new short[ARRLEN]; System.out.println("Warmup"); for (int i=0; i<ITERS; i++) { test_ci(a1); @@ -94,6 +95,13 @@ public class TestShortVect { test_cp_unalnsrc(a1, a2); test_2ci_unaln(a1, a2); test_2vi_unaln(a1, a2, (short)123, (short)103); + test_addImm129(a1, a2); + test_addImm(a1, a2, a3); + test_subImm56(a1, a2); + test_subImm256(a1, a2); + test_andImm(a1, a2); + test_orImm(a1, a2); + test_xorImm(a1, a2); } // Initialize for (int i=0; i<ARRLEN; i++) { @@ -487,6 +495,54 @@ public class TestShortVect { for (int i=ARRLEN-UNALIGN_OFF; i<ARRLEN; i++) { errn += verify("test_2vi_unaln_overlap: a1", i, a1[i], (short)103); } + short base = (short) 3; + for (int i = 0; i < ARRLEN; i++) { + a1[i] = (short) 3; + } + short golden = (short)(base + 129); + test_addImm129(a1, a2); + for (int i=0; i<ARRLEN; i++) { + errn += verify("test_addImm129: a2", i, a2[i], golden); + } + test_addImm(a1, a2, a3); + golden = (short)(base + 129); + for (int i=0; i<ARRLEN; i++) { + errn += verify("test_addImm: a2", i, a2[i], golden); + } + golden = (short) (base + 255); + for (int i=0; i<ARRLEN; i++) { + errn += verify("test_addImm: a3", i, a3[i], golden); + } + // Reset for sub test + base = (short) 120; + for (int i = 0; i < ARRLEN; i++) { + a1[i] = (short) 120; + } + test_subImm56(a1, a2); + golden = (short) (base - 56); + for (int i=0; i<ARRLEN; i++) { + errn += verify("test_subImm56: a2", i, a2[i], golden); + } + test_subImm256(a1, a2); + golden = (short) (base - 256); + for (int i=0; i<ARRLEN; i++) { + errn += verify("test_subImm256: a2", i, a2[i], golden); + } + test_andImm(a1, a2); + golden = (short) (base & 0xfe); + for (int i=0; i<ARRLEN; i++) { + errn += verify("test_andImm: a2", i, a2[i], golden); + } + test_orImm(a1, a2); + golden = (short) (base | 0xff); + for (int i=0; i<ARRLEN; i++) { + errn += verify("test_orImm: a2", i, a2[i], golden); + } + test_xorImm(a1, a2); + golden = (short) (base ^ 0xc7); + for (int i=0; i<ARRLEN; i++) { + errn += verify("test_xorImm: a2", i, a2[i], golden); + } } @@ -730,6 +786,48 @@ public class TestShortVect { } end = System.currentTimeMillis(); System.out.println("test_2vi_unaln: " + (end - start)); + start = System.currentTimeMillis(); + for (int i=0; i<ITERS; i++) { + test_addImm129(a1, a2); + } + end = System.currentTimeMillis(); + System.out.println("test_addImm129: " + (end - start)); + start = System.currentTimeMillis(); + for (int i=0; i<ITERS; i++) { + test_addImm(a1, a2, a3); + } + end = System.currentTimeMillis(); + System.out.println("test_addImm: " + (end - start)); + start = System.currentTimeMillis(); + for (int i=0; i<ITERS; i++) { + test_subImm56(a1, a2); + } + end = System.currentTimeMillis(); + System.out.println("test_subImm56: " + (end - start)); + start = System.currentTimeMillis(); + for (int i=0; i<ITERS; i++) { + test_subImm256(a1, a2); + } + end = System.currentTimeMillis(); + System.out.println("test_subImm256: " + (end - start)); + start = System.currentTimeMillis(); + for (int i=0; i<ITERS; i++) { + test_andImm(a1, a2); + } + end = System.currentTimeMillis(); + System.out.println("test_andImm: " + (end - start)); + start = System.currentTimeMillis(); + for (int i=0; i<ITERS; i++) { + test_orImm(a1, a2); + } + end = System.currentTimeMillis(); + System.out.println("test_orImm: " + (end - start)); + start = System.currentTimeMillis(); + for (int i=0; i<ITERS; i++) { + test_xorImm(a1, a2); + } + end = System.currentTimeMillis(); + System.out.println("test_xorImm: " + (end - start)); return errn; } @@ -945,6 +1043,43 @@ public class TestShortVect { b[i+UNALIGN_OFF] = d; } } + static void test_addImm129(short[] a, short[] b) { + for (int i = 0; i < a.length; i++) { + b[i] = (short) (a[i] + 129); + } + } + + static void test_addImm(short[] a, short[] b, short[] c) { + for (int i = 0; i < a.length; i++) { + b[i] = (short) (a[i] + 129); + c[i] = (short) (a[i] + 255); + } + } + static void test_subImm56(short[] a, short[] b) { + for (int i = 0; i < a.length; i++) { + b[i] = (short) (a[i] - 56); + } + } + static void test_subImm256(short[] a, short[] b) { + for (int i = 0; i < a.length; i++) { + b[i] = (short) (a[i] - 256); + } + } + static void test_andImm(short[] a, short[] b) { + for (int i = 0; i < a.length; i++) { + b[i] = (short) (a[i] & 0xfe); + } + } + static void test_orImm(short[] a, short[] b) { + for (int i = 0; i < a.length; i++) { + b[i] = (short) (a[i] | 0xff); + } + } + static void test_xorImm(short[] a, short[] b) { + for (int i = 0; i < a.length; i++) { + b[i] = (short) (a[i] ^ 0xc7); + } + } static int verify(String text, int i, short elem, short val) { if (elem != val) { diff --git a/test/hotspot/jtreg/compiler/compilercontrol/CompilationModeHighOnlyTest.java b/test/hotspot/jtreg/compiler/compilercontrol/CompilationModeHighOnlyTest.java index 8a4901613788ff29a3cbd152adb185f1a839d0bb..8eb00c08eaa266a9f623c00c57541c856d83c8c6 100644 --- a/test/hotspot/jtreg/compiler/compilercontrol/CompilationModeHighOnlyTest.java +++ b/test/hotspot/jtreg/compiler/compilercontrol/CompilationModeHighOnlyTest.java @@ -24,6 +24,7 @@ /* * @test * @bug 8233885 + * @requires (vm.opt.TieredStopAtLevel == null | vm.opt.TieredStopAtLevel == 4) * @summary CompLevel_initial_compile should be CompLevel_full_optimization for high-only mode * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -Xcomp -XX:CompilationMode=high-only * -XX:CompileCommand=compileonly,java.lang.Object::<init> diff --git a/test/hotspot/jtreg/compiler/escapeAnalysis/TestIterativeEA.java b/test/hotspot/jtreg/compiler/escapeAnalysis/TestIterativeEA.java new file mode 100644 index 0000000000000000000000000000000000000000..ef4db4635164f89216fd93babcf3ae23250126be --- /dev/null +++ b/test/hotspot/jtreg/compiler/escapeAnalysis/TestIterativeEA.java @@ -0,0 +1,93 @@ +/* + * 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. + */ + +/** + * @test + * @bug 8276455 + * @summary Test C2 iterative Escape Analysis + * @library /test/lib / + * + * @requires vm.flagless + * @requires vm.compiler2.enabled & vm.debug == true + * + * @run driver TestIterativeEA + */ + +import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.process.OutputAnalyzer; + +public class TestIterativeEA { + + public static void main(String[] args) throws Exception { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-server", "-XX:-TieredCompilation", "-Xbatch", "-XX:+PrintEliminateAllocations", + Launcher.class.getName()); + + OutputAnalyzer analyzer = new OutputAnalyzer(pb.start()); + + System.out.println(analyzer.getOutput()); + + analyzer.shouldHaveExitValue(0); + analyzer.shouldContain("++++ Eliminated: 26 Allocate"); + analyzer.shouldContain("++++ Eliminated: 48 Allocate"); + analyzer.shouldContain("++++ Eliminated: 78 Allocate"); + } + + static class A { + int i; + + public A(int i) { + this.i = i; + } + } + + static class B { + A a; + + public B(A a) { + this.a = a; + } + } + + static class C { + B b; + + public C(B b) { + this.b = b; + } + } + + static int test(int i) { + C c = new C(new B(new A(i))); + return c.b.a.i; + } + + static class Launcher { + public static void main(String[] args) { + for (int i = 0; i < 12000; ++i) { + int j = test(i); + } + } + } + +} diff --git a/test/hotspot/jtreg/compiler/exceptions/OptimizeImplicitExceptions.java b/test/hotspot/jtreg/compiler/exceptions/OptimizeImplicitExceptions.java new file mode 100644 index 0000000000000000000000000000000000000000..289353a38a240c992b95ab06f72c9d0b062a0d17 --- /dev/null +++ b/test/hotspot/jtreg/compiler/exceptions/OptimizeImplicitExceptions.java @@ -0,0 +1,275 @@ +/* + * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + /* + * @test + * @bug 8275908 + * @summary Record null_check traps for calls and array_check traps in the interpreter + * + * @requires vm.compiler2.enabled & vm.compMode != "Xcomp" + * + * @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 + * -Xbatch -XX:-UseOnStackReplacement -XX:-TieredCompilation + * -XX:CompileCommand=compileonly,compiler.exceptions.OptimizeImplicitExceptions::throwImplicitException + * compiler.exceptions.OptimizeImplicitExceptions + */ + +package compiler.exceptions; + +import java.lang.reflect.Method; +import java.util.HashMap; + +import jdk.test.lib.Asserts; +import jdk.test.whitebox.WhiteBox; + +public class OptimizeImplicitExceptions { + // ImplicitException represents the various implicit (aka. 'built-in') exceptions + // which can be thrown implicitely by the JVM when executing bytecodes. + public enum ImplicitException { + // NullPointerException during field access + NULL_POINTER_EXCEPTION("null_check"), + // NullPointerException during invoke + INVOKE_NULL_POINTER_EXCEPTION("null_check"), + ARITHMETIC_EXCEPTION("div0_check"), + ARRAY_INDEX_OUT_OF_BOUNDS_EXCEPTION("range_check"), + ARRAY_STORE_EXCEPTION("array_check"), + CLASS_CAST_EXCEPTION("class_check"); + private final String reason; + ImplicitException(String reason) { + this.reason = reason; + } + public String getReason() { + return reason; + } + } + // TestMode represents a specific combination of the OmitStackTraceInFastThrow command line options. + // They will be set up in 'setFlags(TestMode testMode)' before a new test run starts. + public enum TestMode { + OMIT_STACKTRACES_IN_FASTTHROW, + STACKTRACES_IN_FASTTHROW + } + + private static final WhiteBox WB = WhiteBox.getWhiteBox(); + // The number of deoptimizations after which a method will be made not-entrant + private static final int PerBytecodeTrapLimit = WB.getIntxVMFlag("PerBytecodeTrapLimit").intValue(); + // The number of interpreter invocations after which a decompiled method will be re-compiled. + private static final int Tier0InvokeNotifyFreq = (int)Math.pow(2, WB.getIntxVMFlag("Tier0InvokeNotifyFreqLog")); + // The following variables are used to track the value of the global deopt counters between the various test phases. + private static int oldDeoptCount = 0; + private static HashMap<String, Integer> oldDeoptCountReason = new HashMap<String, Integer>(ImplicitException.values().length); + // The following two objects are declared statically to simplify the test method. + private static String[] string_a = new String[1]; + private static final Object o = new Object(); + + // This is the main test method. It will repeatedly called with the same ImplicitException 'type' to + // JIT-compile it, deoptimized it, re-compile it again and do various checks on the way. + // This process will be repeated then for each kind of ImplicitException 'type'. + public static Object throwImplicitException(ImplicitException type, Object[] object_a) { + switch (type) { + case NULL_POINTER_EXCEPTION: { + return object_a.length; + } + case INVOKE_NULL_POINTER_EXCEPTION: { + return object_a.hashCode(); + } + case ARITHMETIC_EXCEPTION: { + return ((42 / (object_a.length - 1)) > 2) ? null : object_a[0]; + } + case ARRAY_INDEX_OUT_OF_BOUNDS_EXCEPTION: { + return object_a[5]; + } + case ARRAY_STORE_EXCEPTION: { + return (object_a[0] = o); + } + case CLASS_CAST_EXCEPTION: { + return (ImplicitException[])object_a; + } + } + return null; + } + + // Completely unload (i.e. make "not-entrant"->"zombie"->"unload/free") a JIT-compiled + // version of a method and clear the method's profiling counters. + private static void unloadAndClean(Method m) { + WB.deoptimizeMethod(m); // Makes the nmethod "not entrant". + WB.forceNMethodSweep(); // Makes all "not entrant" nmethods "zombie". This requires + WB.forceNMethodSweep(); // two sweeps, see 'nmethod::can_convert_to_zombie()' for why. + WB.forceNMethodSweep(); // Need third sweep to actually unload/free all "zombie" nmethods. + System.gc(); + WB.clearMethodState(m); + } + + // Set '-XX' flags according to 'TestMode' + private static void setFlags(TestMode testMode) { + if (testMode == TestMode.OMIT_STACKTRACES_IN_FASTTHROW) { + WB.setBooleanVMFlag("OmitStackTraceInFastThrow", true); + } else { + WB.setBooleanVMFlag("OmitStackTraceInFastThrow", false); + } + + System.out.println("=========================================================="); + System.out.println("testMode=" + testMode + + " OmitStackTraceInFastThrow=" + WB.getBooleanVMFlag("OmitStackTraceInFastThrow")); + System.out.println("=========================================================="); + } + + private static void printCounters(TestMode testMode, ImplicitException impExcp, Method throwImplicitException_m, int invocations) { + System.out.println("testMode=" + testMode + " exception=" + impExcp + " invocations=" + invocations + "\n" + + "decompilecount=" + WB.getMethodDecompileCount(throwImplicitException_m) + " " + + "trapCount=" + WB.getMethodTrapCount(throwImplicitException_m) + " " + + "trapCount(" + impExcp.getReason() + ")=" + + WB.getMethodTrapCount(throwImplicitException_m, impExcp.getReason()) + " " + + "globalDeoptCount=" + WB.getDeoptCount() + " " + + "globalDeoptCount(" + impExcp.getReason() + ")=" + WB.getDeoptCount(impExcp.getReason(), null)); + System.out.println("method compiled=" + WB.isMethodCompiled(throwImplicitException_m)); + } + + // Checks after the test method has been JIT-compiled but before the compiled version has been invoked. + private static void checkSimple(TestMode testMode, ImplicitException impExcp, Exception ex, Method throwImplicitException_m, int invocations) { + + printCounters(testMode, impExcp, throwImplicitException_m, invocations); + // At this point, throwImplicitException() has been compiled but the compiled version has not been invoked yet. + Asserts.assertEQ(WB.getMethodCompilationLevel(throwImplicitException_m), 4, "Method should be compiled at level 4."); + + int trapCount = WB.getMethodTrapCount(throwImplicitException_m); + int trapCountSpecific = WB.getMethodTrapCount(throwImplicitException_m, impExcp.getReason()); + Asserts.assertEQ(trapCount, invocations, "Trap count must much invocation count."); + Asserts.assertEQ(trapCountSpecific, invocations, "Trap count must much invocation count."); + Asserts.assertNotNull(ex.getMessage(), "Exceptions thrown in the interpreter should have a message."); + } + + // Checks after the JIT-compiled test method has been invoked 'invocations' times. + private static void check(TestMode testMode, ImplicitException impExcp, Exception ex, + Method throwImplicitException_m, int invocations, int totalInvocations) { + + printCounters(testMode, impExcp, throwImplicitException_m, totalInvocations); + // At this point, the compiled version of 'throwImplicitException()' has been invoked 'invocations' times. + Asserts.assertEQ(WB.getMethodCompilationLevel(throwImplicitException_m), 4, "Method should be compiled at level 4."); + int deoptCount = WB.getDeoptCount(); + int deoptCountReason = WB.getDeoptCount(impExcp.getReason(), null/*action*/); + if (testMode == TestMode.OMIT_STACKTRACES_IN_FASTTHROW) { + // No deoptimizations for '-XX:+OmitStackTraceInFastThrow' + Asserts.assertEQ(oldDeoptCount, deoptCount, "Wrong number of deoptimizations."); + Asserts.assertEQ(oldDeoptCountReason.get(impExcp.getReason()), deoptCountReason, "Wrong number of deoptimizations."); + // '-XX:+OmitStackTraceInFastThrow' never has message because it is using a global singleton exception. + Asserts.assertNull(ex.getMessage(), "Optimized exceptions have no message."); + } else if (testMode == TestMode.STACKTRACES_IN_FASTTHROW) { + // We always deoptimize for '-XX:-OmitStackTraceInFastThrow + Asserts.assertEQ(oldDeoptCount + invocations, deoptCount, "Wrong number of deoptimizations."); + Asserts.assertEQ(oldDeoptCountReason.get(impExcp.getReason()) + invocations, deoptCountReason, "Wrong number of deoptimizations."); + Asserts.assertNotNull(ex.getMessage(), "Exceptions thrown in the interpreter should have a message."); + } else { + Asserts.fail("Unknown test mode."); + } + oldDeoptCount = deoptCount; + oldDeoptCountReason.put(impExcp.getReason(), deoptCountReason); + } + + public static void main(String[] args) throws Exception { + + if (!WB.getBooleanVMFlag("ProfileTraps")) { + // The fast-throw optimzation only works if we're running with -XX:+ProfileTraps + return; + } + + // Initialize global deopt counts to zero. + for (ImplicitException impExcp : ImplicitException.values()) { + oldDeoptCountReason.put(impExcp.getReason(), 0); + } + // Get a handle of the test method for usage with the WhiteBox API. + Method throwImplicitException_m = OptimizeImplicitExceptions.class + .getDeclaredMethod("throwImplicitException", new Class[] { ImplicitException.class, Object[].class}); + + for (TestMode testMode : TestMode.values()) { + setFlags(testMode); + for (ImplicitException impExcp : ImplicitException.values()) { + int invocations = 0; + Exception lastException = null; + + // Warmup and compile, but don't invoke compiled code. + while(!WB.isMethodCompiled(throwImplicitException_m)) { + invocations++; + try { + throwImplicitException(impExcp, impExcp.getReason().equals("null_check") ? null : string_a); + } catch (Exception catchedExcp) { + lastException = catchedExcp; + continue; + } + throw new Exception("Should not happen"); + } + + checkSimple(testMode, impExcp, lastException, throwImplicitException_m, invocations); + + // Invoke compiled code 'PerBytecodeTrapLimit' times. + for (int i = 0; i < PerBytecodeTrapLimit; i++) { + invocations++; + try { + throwImplicitException(impExcp, impExcp.getReason().equals("null_check") ? null : string_a); + } catch (Exception catchedExcp) { + lastException = catchedExcp; + continue; + } + throw new Exception("Should not happen"); + } + + check(testMode, impExcp, lastException, throwImplicitException_m, PerBytecodeTrapLimit, invocations); + + // Invoke compiled code 'Tier0InvokeNotifyFreq' times. + // If the method was de-compiled before, this will re-compile it again. + for (int i = 0; i < Tier0InvokeNotifyFreq; i++) { + invocations++; + try { + throwImplicitException(impExcp, impExcp.getReason().equals("null_check") ? null : string_a); + } catch (Exception catchedExcp) { + lastException = catchedExcp; + continue; + } + throw new Exception("Should not happen"); + } + + check(testMode, impExcp, lastException, throwImplicitException_m, Tier0InvokeNotifyFreq, invocations); + + // Invoke compiled code 'PerBytecodeTrapLimit' times. + for (int i = 0; i < PerBytecodeTrapLimit; i++) { + invocations++; + try { + throwImplicitException(impExcp, impExcp.getReason().equals("null_check") ? null : string_a); + } catch (Exception catchedExcp) { + lastException = catchedExcp; + continue; + } + throw new Exception("Should not happen"); + } + + check(testMode, impExcp, lastException, throwImplicitException_m, PerBytecodeTrapLimit, invocations); + + System.out.println("------------------------------------------------------------------"); + + unloadAndClean(throwImplicitException_m); + } + } + } +} diff --git a/test/hotspot/jtreg/compiler/exceptions/TestLateMHInlineExceptions.java b/test/hotspot/jtreg/compiler/exceptions/TestLateMHInlineExceptions.java new file mode 100644 index 0000000000000000000000000000000000000000..6949c9948dfb5fe3eb8ead10a27163a75174369b --- /dev/null +++ b/test/hotspot/jtreg/compiler/exceptions/TestLateMHInlineExceptions.java @@ -0,0 +1,132 @@ +/* + * Copyright (c) 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. + */ + +/** + * @test + * @bug 8275638 8278966 + * @summary GraphKit::combine_exception_states fails with "matching stack sizes" assert + * + * @run main/othervm -XX:-BackgroundCompilation -XX:-UseOnStackReplacement -XX:CompileCommand=dontinline,TestLateMHInlineExceptions::m + * -XX:+IgnoreUnrecognizedVMOptions -XX:+AlwaysIncrementalInline TestLateMHInlineExceptions + * @run main/othervm -XX:-BackgroundCompilation -XX:-UseOnStackReplacements -XX:+IgnoreUnrecognizedVMOptions -XX:+AlwaysIncrementalInline + * TestLateMHInlineExceptions + * + */ + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; + +public class TestLateMHInlineExceptions { + public static void main(String[] args) throws Throwable { + TestLateMHInlineExceptions test = new TestLateMHInlineExceptions(); + for (int i = 0; i < 20_000; i++) { + test1(test); + try { + test1(null); + } catch (NullPointerException npe) { + } + test2(test); + test2(null); + test3(test); + try { + test3(null); + } catch (NullPointerException npe) { + } + test4(test); + test4(null); + test5(test); + try { + test5(null); + } catch (NullPointerException npe) { + } + test6(test); + try { + test6(null); + } catch (NullPointerException npe) { + } + } + } + + void m() { + } + + static void nothing(Throwable t) { + } + + static final MethodHandle mh; + static final MethodHandle mh_nothing; + static final MethodHandle mh2; + static final MethodHandle mh3; + + static { + MethodHandles.Lookup lookup = MethodHandles.lookup(); + try { + mh = lookup.findVirtual(TestLateMHInlineExceptions.class, "m", MethodType.methodType(void.class)); + mh_nothing = lookup.findStatic(TestLateMHInlineExceptions.class, "nothing", MethodType.methodType(void.class, Throwable.class)); + mh2 = MethodHandles.tryFinally(mh, mh_nothing); + mh3 = MethodHandles.catchException(mh, Throwable.class, mh_nothing); + } catch (NoSuchMethodException e) { + e.printStackTrace(); + throw new RuntimeException("Method handle lookup failed"); + } catch (IllegalAccessException e) { + e.printStackTrace(); + throw new RuntimeException("Method handle lookup failed"); + } + } + + private static void test1(TestLateMHInlineExceptions test) throws Throwable { + mh.invokeExact(test); + } + + private static void test2(TestLateMHInlineExceptions test) throws Throwable { + try { + mh.invokeExact(test); + } catch (NullPointerException npe) { + } + } + + private static void inlined(TestLateMHInlineExceptions test) throws Throwable { + mh.invokeExact(test); + } + + + private static void test3(TestLateMHInlineExceptions test) throws Throwable { + inlined(test); + } + + private static void test4(TestLateMHInlineExceptions test) throws Throwable { + try { + inlined(test); + } catch (NullPointerException npe) { + } + } + + private static void test5(TestLateMHInlineExceptions test) throws Throwable { + mh2.invokeExact(test); + } + + private static void test6(TestLateMHInlineExceptions test) throws Throwable { + mh3.invokeExact(test); + } +} diff --git a/test/hotspot/jtreg/compiler/inlining/ResolvedClassTest.java b/test/hotspot/jtreg/compiler/inlining/ResolvedClassTest.java new file mode 100644 index 0000000000000000000000000000000000000000..92263bf10cf3ea2fced44052cee7ae18f92fbce5 --- /dev/null +++ b/test/hotspot/jtreg/compiler/inlining/ResolvedClassTest.java @@ -0,0 +1,158 @@ +/* + * 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. + */ + +/** + * @test + * @bug 8279515 + * + * @requires vm.flagless & vm.compiler1.enabled & vm.compiler2.enabled + * @modules java.base/jdk.internal.misc + * @library /test/lib / + * + * @run driver compiler.jsr292.ResolvedClassTest + */ + +package compiler.jsr292; + +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; + +import java.io.IOException; + +public class ResolvedClassTest { + /* ======================================================================== */ + static void testStatic() throws IOException { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-XX:+IgnoreUnrecognizedVMOptions", "-showversion", + "-XX:+PrintCompilation", "-XX:+UnlockDiagnosticVMOptions", "-XX:+PrintInlining", + "-Xbatch", "-XX:CompileCommand=quiet", "-XX:CompileCommand=compileonly," + TestStatic.class.getName() + "::test", + TestStatic.class.getName()); + + OutputAnalyzer analyzer = new OutputAnalyzer(pb.start()); + + analyzer.shouldHaveExitValue(0); + + analyzer.shouldNotContain("TestStatic$A::m (1 bytes) not inlineable"); + analyzer.shouldNotContain("TestStatic$A::m (1 bytes) no static binding"); + + analyzer.shouldContain("TestStatic$A::m (1 bytes) inline"); + } + + static class TestStatic { + static class A { + static void m() {} + } + static class B extends A {} + + // @DontInline + static void test() { + B.m(); // invokestatic B "m" => A::m + } + + public static void main(String[] args) { + for (int i = 0; i < 20_000; i++) { + test(); + } + } + } + + /* ======================================================================== */ + static void testStaticInit() throws IOException { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-XX:+IgnoreUnrecognizedVMOptions", "-showversion", + "-XX:+PrintCompilation", "-XX:+UnlockDiagnosticVMOptions", "-XX:+PrintInlining", + "-Xbatch", "-XX:CompileCommand=quiet", "-XX:CompileCommand=compileonly," + TestStaticInit.class.getName() + "::test", + TestStaticInit.class.getName()); + + OutputAnalyzer analyzer = new OutputAnalyzer(pb.start()); + + analyzer.shouldHaveExitValue(0); + + analyzer.shouldContain("TestStaticInit$A::m (1 bytes) no static binding"); + } + + static class TestStaticInit { + static class A { + static { + for (int i = 0; i < 20_000; i++) { + TestStaticInit.test(); + } + } + + static void m() {} + } + static class B extends A {} + + // @DontInline + static void test() { + B.m(); // A::<clinit> => test() => A::m() + } + + public static void main(String[] args) { + A.m(); // trigger initialization of A + } + } + + /* ======================================================================== */ + static void testIndy() throws IOException { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-XX:+IgnoreUnrecognizedVMOptions", "-showversion", + "-XX:+PrintCompilation", "-XX:+UnlockDiagnosticVMOptions", "-XX:+PrintInlining", + "-Xbatch", "-XX:CompileCommand=quiet", "-XX:CompileCommand=compileonly," + TestIndy.class.getName() + "::test", + TestIndy.class.getName()); + + OutputAnalyzer analyzer = new OutputAnalyzer(pb.start()); + + analyzer.shouldHaveExitValue(0); + + analyzer.shouldNotMatch("java\\.lang\\.invoke\\..+::linkToTargetMethod \\(9 bytes\\) not inlineable"); + + analyzer.shouldMatch("java\\.lang\\.invoke\\..+::linkToTargetMethod \\(9 bytes\\) force inline by annotation"); + analyzer.shouldContain("java/lang/invoke/MethodHandle::invokeBasic (not loaded) not inlineable"); + } + + static class TestIndy { + static String str = ""; + + // @DontInline + static void test() { + String s1 = "" + str; // indy (linked) + + for (int i = 0; i < 200_000; i++) {} // trigger OSR compilation + + String s2 = "" + str; // indy (not linked) + } + + public static void main(String[] args) { + test(); + } + } + + /* ======================================================================== */ + + public static void main(String[] args) throws IOException { + testStatic(); + testStaticInit(); + testIndy(); + } +} diff --git a/test/hotspot/jtreg/compiler/interpreter/Custom.jasm b/test/hotspot/jtreg/compiler/interpreter/Custom.jasm new file mode 100644 index 0000000000000000000000000000000000000000..e52d513d2facfb221623b8cac01741fdb9d9f9e5 --- /dev/null +++ b/test/hotspot/jtreg/compiler/interpreter/Custom.jasm @@ -0,0 +1,63 @@ +/* + * 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. + */ + +package compiler/interpreter; + +/* JASM simplified from the following Java pattern: + * + * public class Custom { + * + * static void test(int v) { + * int i8 = 1; + * try { + * v += 1; + * } catch (ArithmeticException exc1) { + * } finally { + * for (; i8 < 100; i8++) { + * } + * } + * } + * + */ + +super public class Custom { + + public static Method test:"(I)V" stack 2 locals 3 { + iconst_1; + istore_1; + try t0; + iinc 0, 1; + endtry t0; +Loop: + iload_1; + bipush 100; + if_icmpge Lexit; + iinc 1, 1; + goto Loop; // deoptimize here on backwards branch + catch t0 java/lang/ArithmeticException; // unreachable block + astore_2; +Lexit: + return + } + +} diff --git a/test/hotspot/jtreg/compiler/interpreter/VerifyStackWithUnreachableBlock.java b/test/hotspot/jtreg/compiler/interpreter/VerifyStackWithUnreachableBlock.java new file mode 100644 index 0000000000000000000000000000000000000000..f8aace2b31bc354bb71d7aac735dca3a9f9f33c3 --- /dev/null +++ b/test/hotspot/jtreg/compiler/interpreter/VerifyStackWithUnreachableBlock.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 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. + * + */ + +/* + * @test VerifyStackWithUnreachableBlock + * @bug 8271055 + * @compile Custom.jasm VerifyStackWithUnreachableBlock.java + * @summary Using VerifyStack for method that contains unreachable basic blocks + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+VerifyStack compiler.interpreter.VerifyStackWithUnreachableBlock + */ + +package compiler.interpreter; + +public class VerifyStackWithUnreachableBlock { + public static void main(String[] strArr) { + for (int i = 0; i < 10000; i++) { + Custom.test(i); + } + } +} diff --git a/test/hotspot/jtreg/compiler/intrinsics/base64/TestBase64.java b/test/hotspot/jtreg/compiler/intrinsics/base64/TestBase64.java index 5c9d41cb794d55cef3a51c1651c4b95a5511e37b..16c6749900d37b4ef96f40d1c41d66a7ab7ff06b 100644 --- a/test/hotspot/jtreg/compiler/intrinsics/base64/TestBase64.java +++ b/test/hotspot/jtreg/compiler/intrinsics/base64/TestBase64.java @@ -48,6 +48,7 @@ import java.util.Base64.Decoder; import java.util.Base64.Encoder; import java.util.Objects; import java.util.Random; +import java.util.Arrays; import compiler.whitebox.CompilerWhiteBoxTest; import sun.hotspot.code.Compiler; @@ -79,9 +80,9 @@ public class TestBase64 { private static void warmup() { final int warmupCount = 20_000; - final int bufSize = 60; + final int bufSize = 15308; byte[] srcBuf = new byte[bufSize]; - byte[] encBuf = new byte[(bufSize / 3) * 4]; + byte[] encBuf = new byte[((bufSize + 2) / 3) * 4]; byte[] decBuf = new byte[bufSize]; ran.nextBytes(srcBuf); @@ -163,10 +164,13 @@ public class TestBase64 { assertEqual(resEncodeStr, encodedStr); // test int decode(byte[], byte[]) - resArr = new byte[srcArr.length]; + // JDK-8273108: Test for output buffer overrun + resArr = new byte[srcArr.length + 2]; + resArr[srcArr.length + 1] = (byte) 167; len = decoder.decode(encodedArr, resArr); assertEqual(len, srcArr.length); - assertEqual(resArr, srcArr); + assertEqual(Arrays.copyOfRange(resArr, 0, srcArr.length), srcArr); + assertEqual(resArr[srcArr.length + 1], (byte) 167); // test byte[] decode(byte[]) resArr = decoder.decode(encodedArr); diff --git a/test/hotspot/jtreg/compiler/intrinsics/bmi/verifycode/BzhiTestI2L.java b/test/hotspot/jtreg/compiler/intrinsics/bmi/verifycode/BzhiTestI2L.java index 93f54bdef73f57e944e47b9381d993d80e6db35f..08f83e1b8f044469ff8c89f42b230fb32fe714f9 100644 --- a/test/hotspot/jtreg/compiler/intrinsics/bmi/verifycode/BzhiTestI2L.java +++ b/test/hotspot/jtreg/compiler/intrinsics/bmi/verifycode/BzhiTestI2L.java @@ -31,6 +31,7 @@ * @build sun.hotspot.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller sun.hotspot.WhiteBox * @run main/bootclasspath/othervm -Xbatch -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+AbortVMOnCompilationFailure + * -XX:CompileCommand=compileonly,compiler.intrinsics.bmi.*::* * -XX:+IgnoreUnrecognizedVMOptions -XX:+UseBMI2Instructions * compiler.intrinsics.bmi.verifycode.BzhiTestI2L */ diff --git a/test/hotspot/jtreg/compiler/intrinsics/klass/TestIsPrimitive.java b/test/hotspot/jtreg/compiler/intrinsics/klass/TestIsPrimitive.java index 11a188959908740a605f1aeaafefe37dac10f5da..8fe3f5f5a3f0dd2082b5399e0f45dc5a0114625e 100644 --- a/test/hotspot/jtreg/compiler/intrinsics/klass/TestIsPrimitive.java +++ b/test/hotspot/jtreg/compiler/intrinsics/klass/TestIsPrimitive.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -30,7 +30,7 @@ * * @run main/othervm -ea -Diters=200 -Xint * compiler.intrinsics.klass.TestIsPrimitive - * @run main/othervm -ea -XX:-UseSharedSpaces -Diters=30000 -XX:TieredStopAtLevel=1 + * @run main/othervm -ea -Xshare:off -Diters=30000 -XX:TieredStopAtLevel=1 * compiler.intrinsics.klass.TestIsPrimitive * @run main/othervm -ea -Diters=30000 -XX:TieredStopAtLevel=4 * compiler.intrinsics.klass.TestIsPrimitive diff --git a/test/hotspot/jtreg/compiler/intrinsics/string/TestCountPositives.java b/test/hotspot/jtreg/compiler/intrinsics/string/TestCountPositives.java new file mode 100644 index 0000000000000000000000000000000000000000..afc308c37dd7a12a8d6ad93d394d50e3bd4095e2 --- /dev/null +++ b/test/hotspot/jtreg/compiler/intrinsics/string/TestCountPositives.java @@ -0,0 +1,130 @@ +/* + * 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. + */ + +package compiler.intrinsics.string; + +/* + * @test + * @bug 8999999 + * @summary Validates StringCoding.countPositives intrinsic with a small range of tests. + * @library /compiler/patches + * + * @build java.base/java.lang.Helper + * @run main compiler.intrinsics.string.TestCountPositives + */ + +public class TestCountPositives { + + private static byte[] tBa = new byte[4096 + 16]; + + /** + * Completely initialize the test array, preparing it for tests of the + * StringCoding.hasNegatives method with a given array segment offset, + * length, and number of negative bytes. + */ + public static void initialize(int off, int len, int neg) { + assert (len + off <= tBa.length); + // insert "canary" (negative) values before offset + for (int i = 0; i < off; ++i) { + tBa[i] = (byte) (((i + 15) & 0x7F) | 0x80); + } + // fill the array segment + for (int i = off; i < len + off; ++i) { + tBa[i] = (byte) (((i - off + 15) & 0x7F)); + } + if (neg != 0) { + // modify a number (neg) disparate array bytes inside + // segment to be negative. + int div = (neg > 1) ? (len - 1) / (neg - 1) : 0; + int idx; + for (int i = 0; i < neg; ++i) { + idx = off + (len - 1) - div * i; + tBa[idx] = (byte) (0x80 | tBa[idx]); + } + } + // insert "canary" negative values after array segment + for (int i = len + off; i < tBa.length; ++i) { + tBa[i] = (byte) (((i + 15) & 0x7F) | 0x80); + } + } + + /** Sizes of array segments to test. */ + private static int sizes[] = { 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 13, 17, 19, 23, 37, 61, 131, + 4099 }; + + /** + * Test different array segment sizes, offsets, and number of negative + * bytes. + */ + public static void test_countPositives() throws Exception { + int len, off; + int ng; + + for (ng = 0; ng < 57; ++ng) { // number of negatives in array segment + for (off = 0; off < 8; ++off) { // starting offset of array segment + for (int i = 0; i < sizes.length; ++i) { // array segment size + // choice + len = sizes[i]; + if (len + off > tBa.length) + continue; + initialize(off, len, ng); + int calculated = Helper.StringCodingCountPositives(tBa, off, len); + int expected = countPositives(tBa, off, len); + if (calculated != expected) { + if (expected != len && calculated >= 0 && calculated < expected) { + // allow intrinsics to return early with a lower value, + // but only if we're not expecting the full length (no + // negative bytes) + continue; + } + throw new Exception("Failed test countPositives " + "offset: " + off + " " + + "length: " + len + " " + "return: " + calculated + " expected: " + expected + " negatives: " + + ng); + } + } + } + } + } + + private static int countPositives(byte[] ba, int off, int len) { + int limit = off + len; + for (int i = off; i < limit; i++) { + if (ba[i] < 0) { + return i - off; + } + } + return len; + } + + public void run() throws Exception { + // iterate to eventually get intrinsic inlined + for (int j = 0; j < 1000; ++j) { + test_countPositives(); + } + } + + public static void main(String[] args) throws Exception { + (new TestCountPositives()).run(); + System.out.println("countPositives validated"); + } +} diff --git a/test/hotspot/jtreg/compiler/intrinsics/unsafe/ByteBufferTest.java b/test/hotspot/jtreg/compiler/intrinsics/unsafe/ByteBufferTest.java index 6294e90a8a9991b9c03ccf142f86182a1074c9c2..194ce17af7a677c29ccd511b221ed7c4c14b8a08 100644 --- a/test/hotspot/jtreg/compiler/intrinsics/unsafe/ByteBufferTest.java +++ b/test/hotspot/jtreg/compiler/intrinsics/unsafe/ByteBufferTest.java @@ -211,13 +211,22 @@ class MyByteBuffer { void ck(long x, long y) { if (x != y) { - throw new RuntimeException(" x = " + Long.toHexString(x) + ", y = " + Long.toHexString(y)); + throw new RuntimeException("expect x == y: x = " + Long.toHexString(x) + ", y = " + Long.toHexString(y)); } } void ck(double x, double y) { - if (x == x && y == y && x != y) { - ck(x, y); + // Check if x and y have identical values. + // Remember: NaN == x is false for ANY x, including if x is NaN (IEEE standard). + // Therefore, if x and y are NaN, x != y would return true, which is not what we want. + // We do not want an Exception if both are NaN. + // Double.compare takes care of these special cases + // including NaNs, and comparing -0.0 to 0.0 + if (Double.compare(x,y) != 0) { + throw new RuntimeException("expect x == y:" + + " x = " + Double.toString(x) + ", y = " + Double.toString(y) + + " (x = " + Long.toHexString(Double.doubleToRawLongBits(x)) + + ", y = " + Long.toHexString(Double.doubleToRawLongBits(y)) + ")"); } } diff --git a/test/hotspot/jtreg/compiler/jvmci/compilerToVM/CompileCodeTestCase.java b/test/hotspot/jtreg/compiler/jvmci/compilerToVM/CompileCodeTestCase.java index e15b151ec061ccdc1a3ed2f45a26a1b6ebe886d4..797bef95edcbec176417954fec7eb738369b196e 100644 --- a/test/hotspot/jtreg/compiler/jvmci/compilerToVM/CompileCodeTestCase.java +++ b/test/hotspot/jtreg/compiler/jvmci/compilerToVM/CompileCodeTestCase.java @@ -244,7 +244,7 @@ public class CompileCodeTestCase { } static { - Map<Class<?>, Object> map = new HashMap<>();; + Map<Class<?>, Object> map = new HashMap<>(); map.put(CompileCodeTestCase.DummyEx.class, new CompileCodeTestCase.DummyEx()); map.put(CompileCodeTestCase.Dummy.class, diff --git a/test/hotspot/jtreg/compiler/jvmci/compilerToVM/DisassembleCodeBlobTest.java b/test/hotspot/jtreg/compiler/jvmci/compilerToVM/DisassembleCodeBlobTest.java index 21c5e40da25c0032580a74ca988020b67ede15a6..ec5b9337b49bc64533110725cbb572628e23814f 100644 --- a/test/hotspot/jtreg/compiler/jvmci/compilerToVM/DisassembleCodeBlobTest.java +++ b/test/hotspot/jtreg/compiler/jvmci/compilerToVM/DisassembleCodeBlobTest.java @@ -83,6 +83,11 @@ public class DisassembleCodeBlobTest { + " : non-null return value for invalid installCode"); } + private void checkLineStart(CompileCodeTestCase testCase, String line, String match) { + Asserts.assertTrue(line.startsWith(match), + testCase + " : line \"" + line + "\" does not start with: \"" + match +"\""); + } + private void check(CompileCodeTestCase testCase) { System.out.println(testCase); // to have a clean state @@ -98,10 +103,33 @@ public class DisassembleCodeBlobTest { } // The very first call to the disassembler contains a string specifying the // architecture: [Disassembling for mach='i386:x86-64'] - // Therefore compare strings 2 and 3. + // so discard it and try again. String str2 = CompilerToVMHelper.disassembleCodeBlob(installedCode); - String str3 = CompilerToVMHelper.disassembleCodeBlob(installedCode); - Asserts.assertEQ(str2, str3, - testCase + " : 3nd invocation returned different value from 2nd"); + String[] strLines = str2.split("\\R"); + // Check some basic layout + int MIN_LINES = 5; + Asserts.assertTrue(strLines.length > 2, + testCase + " : read " + strLines.length + " lines, " + MIN_LINES + " expected"); + int l = 1; + checkLineStart(testCase, strLines[l++], "Compiled method "); // 2 + checkLineStart(testCase, strLines[l++], " total in heap "); // 3 + int foundDisassemblyLine = -1; + int foundEntryPointLine = -1; + for (; l < strLines.length; ++l) { + String line = strLines[l]; + if (line.equals("[Disassembly]") || line.equals("[MachCode]")) { + Asserts.assertTrue(foundDisassemblyLine == -1, + testCase + " : Duplicate disassembly section markers found at lines " + foundDisassemblyLine + " and " + l); + foundDisassemblyLine = l; + } + if (line.equals("[Entry Point]") || line.equals("[Verified Entry Point]")) { + Asserts.assertTrue(foundDisassemblyLine != -1, + testCase + " : entry point found but [Disassembly] section missing "); + foundEntryPointLine = l; + break; + } + } + Asserts.assertTrue(foundDisassemblyLine != -1, testCase + " : no disassembly section found"); + Asserts.assertTrue(foundEntryPointLine != -1, testCase + " : no entry point found"); } } diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/CodeInstallationTest.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/CodeInstallationTest.java index d7ecc7c04ef06493814d56dad0aa1457115ce04d..14478eb21949cef22b13c0dbc9dfed6ede9ce490 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/CodeInstallationTest.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/CodeInstallationTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -54,6 +54,7 @@ public class CodeInstallationTest { protected final TargetDescription target; protected final ConstantReflectionProvider constantReflection; protected final TestHotSpotVMConfig config; + protected final Architecture arch; public CodeInstallationTest() { JVMCIBackend backend = JVMCI.getRuntime().getHostJVMCIBackend(); @@ -61,7 +62,8 @@ public class CodeInstallationTest { codeCache = backend.getCodeCache(); target = backend.getTarget(); constantReflection = backend.getConstantReflection(); - config = new TestHotSpotVMConfig(HotSpotJVMCIRuntime.runtime().getConfigStore()); + arch = codeCache.getTarget().arch; + config = new TestHotSpotVMConfig(HotSpotJVMCIRuntime.runtime().getConfigStore(), arch); } protected interface TestCompiler { @@ -70,7 +72,6 @@ public class CodeInstallationTest { } private TestAssembler createAssembler() { - Architecture arch = codeCache.getTarget().arch; if (arch instanceof AMD64) { return new AMD64TestAssembler(codeCache, config); } else if (arch instanceof AArch64) { diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/TestHotSpotVMConfig.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/TestHotSpotVMConfig.java index c3c1ab25f5e9968fd05684fa7e27426aed759b63..9468027bc85b0c90aed812cc5ee8a7caf0e2d2b5 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/TestHotSpotVMConfig.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/TestHotSpotVMConfig.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -22,13 +22,16 @@ */ package jdk.vm.ci.code.test; +import jdk.vm.ci.aarch64.AArch64; +import jdk.vm.ci.code.Architecture; import jdk.vm.ci.hotspot.HotSpotVMConfigAccess; import jdk.vm.ci.hotspot.HotSpotVMConfigStore; public class TestHotSpotVMConfig extends HotSpotVMConfigAccess { - public TestHotSpotVMConfig(HotSpotVMConfigStore config) { + public TestHotSpotVMConfig(HotSpotVMConfigStore config, Architecture arch) { super(config); + ropProtection = (arch instanceof AArch64) ? getFieldValue("VM_Version::_rop_protection", Boolean.class) : false; } public final boolean useCompressedOops = getFlag("UseCompressedOops", Boolean.class); @@ -48,4 +51,6 @@ public class TestHotSpotVMConfig extends HotSpotVMConfigAccess { public final int maxOopMapStackOffset = getFieldValue("CompilerToVM::Data::_max_oop_map_stack_offset", Integer.class, "int"); public final int heapWordSize = getConstant("HeapWordSize", Integer.class); + + public final boolean ropProtection; } diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/aarch64/AArch64TestAssembler.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/aarch64/AArch64TestAssembler.java index 098095598ba696244441e5f8a28e4fbdec718c44..47feeac193895d314ec85a026d0234bed279b150 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/aarch64/AArch64TestAssembler.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/aarch64/AArch64TestAssembler.java @@ -1,6 +1,6 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2020, Arm Limited. All rights reserved. + * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2022, 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 @@ -254,6 +254,9 @@ public class AArch64TestAssembler extends TestAssembler { public void emitPrologue() { // Must be patchable by NativeJump::patch_verified_entry emitNop(); + if (config.ropProtection) { + code.emitInt(0xdac103be); // pacia x30, x29 + } code.emitInt(0xa9be7bfd); // stp x29, x30, [sp, #-32]! code.emitInt(0x910003fd); // mov x29, sp @@ -469,6 +472,9 @@ public class AArch64TestAssembler extends TestAssembler { emitMov(AArch64.r0, a); code.emitInt(0x910003bf); // mov sp, x29 code.emitInt(0xa8c27bfd); // ldp x29, x30, [sp], #32 + if (config.ropProtection) { + code.emitInt(0xdac113be); // autia x30, x29 + } code.emitInt(0xd65f03c0); // ret } @@ -477,6 +483,9 @@ public class AArch64TestAssembler extends TestAssembler { assert a == AArch64.v0 : "Unimplemented move " + a; code.emitInt(0x910003bf); // mov sp, x29 code.emitInt(0xa8c27bfd); // ldp x29, x30, [sp], #32 + if (config.ropProtection) { + code.emitInt(0xdac113be); // autia x30, x29 + } code.emitInt(0xd65f03c0); // ret } diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.hotspot.test/src/jdk/vm/ci/hotspot/test/TestTranslatedException.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.hotspot.test/src/jdk/vm/ci/hotspot/test/TestTranslatedException.java index ac2c220adb540f499655ac10eef69dc71721603d..57a505901a5b35baedf14fb0b4a6a9a25624cf30 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.hotspot.test/src/jdk/vm/ci/hotspot/test/TestTranslatedException.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.hotspot.test/src/jdk/vm/ci/hotspot/test/TestTranslatedException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -24,7 +24,8 @@ /* * @test * @requires vm.jvmci - * @modules jdk.internal.vm.ci/jdk.vm.ci.hotspot:open + * @modules jdk.internal.vm.ci/jdk.vm.ci.hotspot:+open + * java.base/jdk.internal.misc * @library /compiler/jvmci/jdk.vm.ci.hotspot.test/src * @run testng/othervm * -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI -XX:-UseJVMCICompiler @@ -41,6 +42,9 @@ import java.lang.reflect.Method; import org.testng.Assert; import org.testng.annotations.Test; +import jdk.internal.misc.Unsafe; +import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime; + public class TestTranslatedException { @SuppressWarnings("serial") public static class Untranslatable extends RuntimeException { @@ -56,7 +60,7 @@ public class TestTranslatedException { Class<?> translatedExceptionClass = Class.forName("jdk.vm.ci.hotspot.TranslatedException"); Method encode = translatedExceptionClass.getDeclaredMethod("encodeThrowable", Throwable.class); - Method decode = translatedExceptionClass.getDeclaredMethod("decodeThrowable", String.class); + Method decode = translatedExceptionClass.getDeclaredMethod("decodeThrowable", byte[].class); encode.setAccessible(true); decode.setAccessible(true); @@ -64,11 +68,50 @@ public class TestTranslatedException { for (int i = 0; i < 10; i++) { throwable = new ExceptionInInitializerError(new InvocationTargetException(new RuntimeException(String.valueOf(i), throwable), "invoke")); } - String encoding = (String) encode.invoke(null, throwable); + byte[] encoding = (byte[]) encode.invoke(null, throwable); Throwable decoded = (Throwable) decode.invoke(null, encoding); assertThrowableEquals(throwable, decoded); } + @SuppressWarnings("unchecked") + @Test + public void encodeDecodeTest2() throws Exception { + Unsafe unsafe = Unsafe.getUnsafe(); + int bufferSize = 512; + long buffer = 0L; + while (true) { + buffer = unsafe.allocateMemory(bufferSize); + try { + Throwable throwable = new ExceptionInInitializerError(new InvocationTargetException(new Untranslatable("test exception", new NullPointerException()), "invoke")); + for (int i = 0; i < 10; i++) { + throwable = new ExceptionInInitializerError(new InvocationTargetException(new RuntimeException(String.valueOf(i), throwable), "invoke")); + } + + Method encode = HotSpotJVMCIRuntime.class.getDeclaredMethod("encodeThrowable", Throwable.class, long.class, int.class); + Method decode = HotSpotJVMCIRuntime.class.getDeclaredMethod("decodeAndThrowThrowable", long.class); + encode.setAccessible(true); + decode.setAccessible(true); + + int res = (Integer) encode.invoke(null, throwable, buffer, bufferSize); + + if (res < 0) { + bufferSize = -res; + } else { + try { + decode.invoke(null, buffer); + throw new AssertionError("expected decodeAndThrowThrowable to throw an exception"); + } catch (InvocationTargetException e) { + Throwable decoded = e.getCause(); + assertThrowableEquals(throwable, decoded); + } + return; + } + } finally { + unsafe.freeMemory(buffer); + } + } + } + private static void assertThrowableEquals(Throwable original, Throwable decoded) { try { Assert.assertEquals(original == null, decoded == null); diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java index ec7a7b3bd702879648566461e87821ffa93990e9..d186e5ea7102fb73fc94be04e9fc39745052b7ad 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java @@ -42,6 +42,8 @@ import static java.lang.reflect.Modifier.isPrivate; import static java.lang.reflect.Modifier.isProtected; import static java.lang.reflect.Modifier.isPublic; import static java.lang.reflect.Modifier.isStatic; +import static jdk.vm.ci.meta.MetaUtil.internalNameToJava; +import static jdk.vm.ci.meta.MetaUtil.toInternalName; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -163,16 +165,15 @@ public class TestResolvedJavaType extends TypeUniverse { } @Test - public void internalNameTest() { - // Verify that the last slash in lambda types are not replaced with a '.' as they - // are part of the type name. + public void lambdaInternalNameTest() { + // Verify that the last dot in lambda types is properly handled when transitioning from internal name to java + // name and vice versa. Supplier<Runnable> lambda = () -> () -> System.out.println("run"); ResolvedJavaType lambdaType = metaAccess.lookupJavaType(lambda.getClass()); String typeName = lambdaType.getName(); - int typeNameLen = TestResolvedJavaType.class.getSimpleName().length(); - int index = typeName.indexOf(TestResolvedJavaType.class.getSimpleName()); - String suffix = typeName.substring(index + typeNameLen, typeName.length() - 1); - assertEquals(TestResolvedJavaType.class.getName() + suffix, lambdaType.toJavaName()); + String javaName = lambda.getClass().getName(); + assertEquals(typeName, toInternalName(javaName)); + assertEquals(javaName, internalNameToJava(typeName, true, true)); } @Test diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/IR.java b/test/hotspot/jtreg/compiler/lib/ir_framework/IR.java index 166bfe218673311b1a741112d6fee6f19b0a586a..37a26ff45efc93b011e805efc4a15b56420e1181 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/IR.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/IR.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -23,7 +23,7 @@ package compiler.lib.ir_framework; -import compiler.lib.ir_framework.driver.IRViolationException; +import compiler.lib.ir_framework.driver.irmatching.IRViolationException; import java.lang.annotation.Repeatable; import java.lang.annotation.Retention; @@ -58,8 +58,8 @@ import java.lang.annotation.RetentionPolicy; * If the specified preconditions fail, then the framework does not apply the IR rule. These preconditions can be * set with {@link #applyIf()}, {@link #applyIfNot()}, {@link #applyIfAnd()}, or {@link #applyIfOr()}. * <p> - * Examples on how to write tests with IR rules can be found in {@link jdk.test.lib.hotspot.ir_framework.examples.IRExample} - * and also as part of the internal testing in {@link jdk.test.lib.hotspot.ir_framework.tests.TestIRMatching}. + * Examples on how to write tests with IR rules can be found in {@link ir_framework.examples.IRExample} + * and also as part of the internal testing in {@link ir_framework.tests.TestIRMatching}. * * @see Test * @see IRNode diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java index a995cad3f2d49a68a65aa6d5487c28e4ed2bec44..033ed28d2e5c0e4e14007d01490495237234ff17 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -23,7 +23,7 @@ package compiler.lib.ir_framework; -import compiler.lib.ir_framework.driver.IRMatcher; +import compiler.lib.ir_framework.driver.irmatching.IRMatcher; import compiler.lib.ir_framework.shared.*; import jdk.test.lib.Platform; import sun.hotspot.WhiteBox; @@ -74,6 +74,7 @@ public class IRNode { public static final String STORE_D = START + "StoreD" + MID + END; public static final String STORE_P = START + "StoreP" + MID + END; public static final String STORE_N = START + "StoreN" + MID + END; + public static final String STORE_VECTOR = START + "StoreVector" + MID + END; public static final String STORE_OF_CLASS = COMPOSITE_PREFIX + START + "Store(B|C|S|I|L|F|D|P|N)" + MID + "@\\S*" + IS_REPLACED + STORE_OF_CLASS_POSTFIX; public static final String STORE_B_OF_CLASS = COMPOSITE_PREFIX + START + "StoreB" + MID + "@\\S*" + IS_REPLACED + STORE_OF_CLASS_POSTFIX; public static final String STORE_C_OF_CLASS = COMPOSITE_PREFIX + START + "StoreC" + MID + "@\\S*" + IS_REPLACED + STORE_OF_CLASS_POSTFIX; @@ -96,6 +97,7 @@ public class IRNode { public static final String LOAD_D = START + "LoadD" + MID + END; public static final String LOAD_P = START + "LoadP" + MID + END; public static final String LOAD_N = START + "LoadN" + MID + END; + public static final String LOAD_VECTOR = START + "LoadVector" + MID + END; public static final String LOAD_OF_CLASS = COMPOSITE_PREFIX + START + "Load(B|UB|S|US|I|L|F|D|P|N)" + MID + "@\\S*"+ IS_REPLACED + LOAD_OF_CLASS_POSTFIX; public static final String LOAD_B_OF_CLASS = COMPOSITE_PREFIX + START + "LoadB" + MID + "@\\S*" + IS_REPLACED + LOAD_OF_CLASS_POSTFIX; public static final String LOAD_UB_OF_CLASS = COMPOSITE_PREFIX + START + "LoadUB" + MID + "@\\S*" + IS_REPLACED + LOAD_OF_CLASS_POSTFIX; @@ -113,6 +115,8 @@ public class IRNode { public static final String LOOP = START + "Loop" + MID + END; public static final String COUNTEDLOOP = START + "CountedLoop\\b" + MID + END; public static final String COUNTEDLOOP_MAIN = START + "CountedLoop\\b" + MID + "main" + END; + public static final String OUTERSTRIPMINEDLOOP = START + "OuterStripMinedLoop\\b" + MID + END; + public static final String IF = START + "If\\b" + MID + END; public static final String CALL = START + "Call.*Java" + MID + END; public static final String CALL_OF_METHOD = COMPOSITE_PREFIX + START + "Call.*Java" + MID + IS_REPLACED + " " + END; @@ -127,11 +131,59 @@ public class IRNode { public static final String RANGE_CHECK_TRAP = START + "CallStaticJava" + MID + "uncommon_trap.*range_check" + END; public static final String UNHANDLED_TRAP = START + "CallStaticJava" + MID + "uncommon_trap.*unhandled" + END; public static final String INTRINSIC_TRAP = START + "CallStaticJava" + MID + "uncommon_trap.*intrinsic" + END; + public static final String DIV_BY_ZERO_TRAP = START + "CallStaticJava" + MID + "uncommon_trap.*div0_check" + END; // Does not work for VM builds without JVMCI like x86_32 (a rule containing this regex will be skipped without having JVMCI built). public static final String INTRINSIC_OR_TYPE_CHECKED_INLINING_TRAP = START + "CallStaticJava" + MID + "uncommon_trap.*intrinsic_or_type_checked_inlining" + END; public static final String SCOPE_OBJECT = "(.*# ScObj.*" + END; public static final String MEMBAR = START + "MemBar" + MID + END; + public static final String SAFEPOINT = START + "SafePoint" + MID + END; + + public static final String ABS_I = START + "AbsI" + MID + END; + public static final String ABS_L = START + "AbsL" + MID + END; + public static final String ABS_F = START + "AbsF" + MID + END; + public static final String ABS_D = START + "AbsD" + MID + END; + public static final String AND = START + "And(I|L)" + MID + END; + public static final String AND_I = START + "AndI" + MID + END; + public static final String AND_L = START + "AndL" + MID + END; + public static final String XOR_I = START + "XorI" + MID + END; + public static final String XOR_L = START + "XorL" + MID + END; + public static final String LSHIFT = START + "LShift(I|L)" + MID + END; + public static final String LSHIFT_I = START + "LShiftI" + MID + END; + public static final String LSHIFT_L = START + "LShiftL" + MID + END; + public static final String RSHIFT = START + "RShift(I|L)" + MID + END; + public static final String RSHIFT_I = START + "RShiftI" + MID + END; + public static final String RSHIFT_L = START + "RShiftL" + MID + END; + public static final String URSHIFT = START + "URShift(B|S|I|L)" + MID + END; + public static final String URSHIFT_I = START + "URShiftI" + MID + END; + public static final String URSHIFT_L = START + "URShiftL" + MID + END; + public static final String ADD = START + "Add(I|L|F|D|P)" + MID + END; + public static final String ADD_I = START + "AddI" + MID + END; + public static final String ADD_L = START + "AddL" + MID + END; + public static final String ADD_VD = START + "AddVD" + MID + END; + public static final String SUB = START + "Sub(I|L|F|D)" + MID + END; + public static final String SUB_I = START + "SubI" + MID + END; + public static final String SUB_L = START + "SubL" + MID + END; + public static final String SUB_F = START + "SubF" + MID + END; + public static final String SUB_D = START + "SubD" + MID + END; + public static final String MUL = START + "Mul(I|L|F|D)" + MID + END; + public static final String MUL_I = START + "MulI" + MID + END; + public static final String MUL_L = START + "MulL" + MID + END; + public static final String DIV = START + "Div(I|L|F|D)" + MID + END; + public static final String DIV_L = START + "DivL" + MID + END; + public static final String CONV_I2L = START + "ConvI2L" + MID + END; + public static final String CONV_L2I = START + "ConvL2I" + MID + END; + + public static final String VECTOR_CAST_B2X = START + "VectorCastB2X" + MID + END; + public static final String VECTOR_CAST_S2X = START + "VectorCastS2X" + MID + END; + public static final String VECTOR_CAST_I2X = START + "VectorCastI2X" + MID + END; + public static final String VECTOR_CAST_L2X = START + "VectorCastL2X" + MID + END; + public static final String VECTOR_CAST_F2X = START + "VectorCastF2X" + MID + END; + public static final String VECTOR_CAST_D2X = START + "VectorCastD2X" + MID + END; + public static final String VECTOR_UCAST_B2X = START + "VectorUCastB2X" + MID + END; + public static final String VECTOR_UCAST_S2X = START + "VectorUCastS2X" + MID + END; + public static final String VECTOR_UCAST_I2X = START + "VectorUCastI2X" + MID + END; + public static final String VECTOR_REINTERPRET = START + "VectorReinterpret" + MID + END; /** * Called by {@link IRMatcher} to merge special composite nodes together with additional user-defined input. diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/TestFramework.java b/test/hotspot/jtreg/compiler/lib/ir_framework/TestFramework.java index e669c674b78fe76c65699cc9b0ccafeeda4a67f1..fcda1053f254747dc4495eb5048ac63e6fb37726 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/TestFramework.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/TestFramework.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -24,6 +24,8 @@ package compiler.lib.ir_framework; import compiler.lib.ir_framework.driver.*; +import compiler.lib.ir_framework.driver.irmatching.IRMatcher; +import compiler.lib.ir_framework.driver.irmatching.IRViolationException; import compiler.lib.ir_framework.shared.*; import compiler.lib.ir_framework.test.*; import jdk.test.lib.Platform; @@ -603,11 +605,11 @@ public class TestFramework { // Print stack trace otherwise StringWriter errors = new StringWriter(); e.printStackTrace(new PrintWriter(errors)); - builder.append(errors.toString()); + builder.append(errors); } builder.append(System.lineSeparator()); } - System.err.println(builder.toString()); + System.err.println(builder); if (!VERBOSE && !REPORT_STDOUT && !TESTLIST && !EXCLUDELIST) { // Provide a hint to the user how to get additional output/debugging information. System.err.println(RERUN_HINT); diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/IRMatcher.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/IRMatcher.java deleted file mode 100644 index db297bfb26d2fa218f14c1c885ff5c1afb2d29d1..0000000000000000000000000000000000000000 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/IRMatcher.java +++ /dev/null @@ -1,504 +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. - */ - -package compiler.lib.ir_framework.driver; - -import compiler.lib.ir_framework.*; -import compiler.lib.ir_framework.shared.*; -import compiler.lib.ir_framework.test.*; - -import java.io.IOException; -import java.lang.reflect.Method; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.util.*; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * Parse the hotspot pid file of the test VM to match all @IR rules. - */ -public class IRMatcher { - public static final String SAFEPOINT_WHILE_PRINTING_MESSAGE = "<!-- safepoint while printing -->"; - - private static final boolean PRINT_IR_ENCODING = Boolean.parseBoolean(System.getProperty("PrintIREncoding", "false")); - private static final Pattern IR_ENCODING_PATTERN = - Pattern.compile("(?<=" + IREncodingPrinter.START + "\r?\n)[\\s\\S]*(?=" + IREncodingPrinter.END + ")"); - private static final Pattern COMPILE_ID_PATTERN = Pattern.compile("compile_id='(\\d+)'"); - - private final Map<String, IRMethod> compilations; - private final Class<?> testClass; - private final Map<Method, List<String>> fails; - private final Pattern compileIdPatternForTestClass; - private final String hotspotPidFileName; - private IRMethod irMethod; // Current IR method to which rules are applied - private Method method; // Current method to which rules are applied - private IR irAnno; // Current IR annotation that is processed. - private int irRuleIndex; // Current IR rule index; - - public IRMatcher(String hotspotPidFileName, String irEncoding, Class<?> testClass) { - this.compilations = new HashMap<>(); - this.fails = new HashMap<>(); - this.testClass = testClass; - this.compileIdPatternForTestClass = Pattern.compile("compile_id='(\\d+)'.*" + Pattern.quote(testClass.getCanonicalName()) - + " (\\S+)"); - this.hotspotPidFileName = hotspotPidFileName; - setupTestMethods(irEncoding); - if (TestFramework.VERBOSE || PRINT_IR_ENCODING) { - System.out.println("Read IR encoding from test VM:"); - System.out.println(irEncoding); - } - if (!compilations.isEmpty()) { - parseHotspotPidFile(); - applyRules(); - } - } - - /** - * Sets up a map testname -> IRMethod (containing the PrintIdeal and PrintOptoAssembly output for testname). - */ - private void setupTestMethods(String irEncoding) { - Map<String, int[]> irRulesMap = parseIREncoding(irEncoding); - for (Method m : testClass.getDeclaredMethods()) { - method = m; - IR[] irAnnos = m.getAnnotationsByType(IR.class); - if (irAnnos.length > 0) { - // Validation of legal @IR attributes and placement of the annotation was already done in Test VM. - int[] ids = irRulesMap.get(m.getName()); - TestFramework.check(ids != null, "Should find method name in validIrRulesMap for " + m); - TestFramework.check(ids.length > 0, "Did not find any rule indices for " + m); - TestFramework.check(ids[ids.length - 1] < irAnnos.length, "Invalid IR rule index found in validIrRulesMap for " + m); - if (ids[0] != IREncodingPrinter.NO_RULE_APPLIED) { - // If -1, than there was no matching IR rule for the given conditions. - compilations.put(m.getName(), new IRMethod(m, ids, irAnnos)); - } - } - } - } - - /** - * Read the IR encoding emitted by the test VM to decide if an @IR rule must be checked for a method. - */ - private Map<String, int[]> parseIREncoding(String irEncoding) { - Map<String, int[]> irRulesMap = new HashMap<>(); - Matcher matcher = IR_ENCODING_PATTERN.matcher(irEncoding); - TestFramework.check(matcher.find(), "Did not find IR encoding"); - String[] lines = matcher.group(0).split("\\R"); - - // Skip first line containing information about the format only - for (int i = 1; i < lines.length; i++) { - String line = lines[i].trim(); - String[] splitComma = line.split(","); - if (splitComma.length < 2) { - throw new TestFrameworkException("Invalid IR match rule encoding. No comma found: " + splitComma[0]); - } - String testName = splitComma[0]; - int[] irRulesIdx = new int[splitComma.length - 1]; - for (int j = 1; j < splitComma.length; j++) { - try { - irRulesIdx[j - 1] = Integer.parseInt(splitComma[j]); - } catch (NumberFormatException e) { - throw new TestFrameworkException("Invalid IR match rule encoding. No number found: " + splitComma[j]); - } - } - irRulesMap.put(testName, irRulesIdx); - } - return irRulesMap; - } - - /** - * Parse the hotspot_pid*.log file from the test VM. Read the PrintIdeal and PrintOptoAssembly entries for all - * methods of the test class that need to be IR matched (according to IR encoding). - */ - private void parseHotspotPidFile() { - Map<Integer, String> compileIdMap = new HashMap<>(); - try (var br = Files.newBufferedReader(Paths.get(hotspotPidFileName))) { - String line; - StringBuilder builder = new StringBuilder(); - boolean append = false; - String currentMethod = ""; - while ((line = br.readLine()) != null) { - if (append && line.startsWith("</")) { - flushOutput(line, builder, currentMethod); - append = false; - currentMethod = ""; - continue; - } else if (append) { - appendLine(builder, line); - continue; - } - - if (maybeTestEntry(line)) { - addTestMethodCompileId(compileIdMap, line); - } else if (isPrintIdealStart(line)) { - String methodName = getMethodName(compileIdMap, line); - if (methodName != null) { - currentMethod = methodName; - append = true; // Append all following lines until we hit the closing </ideal> tag. - } - } else if (isPrintOptoAssemblyStart(line)) { - String methodName = getMethodName(compileIdMap, line); - if (methodName != null) { - TestFramework.check(compilations.containsKey(methodName), "Must be second entry of " + methodName); - currentMethod = methodName; - append = true; // Append all following lines until we hit the closing </opto_assembly> tag. - } - } - } - } catch (IOException e) { - throw new TestFrameworkException("Error while reading " + hotspotPidFileName, e); - } - } - - /** - * Write the input to the IR method and reset the builder. - */ - private void flushOutput(String line, StringBuilder builder, String currentMethod) { - TestFramework.check(!currentMethod.isEmpty(), "current method must be set"); - IRMethod irMethod = compilations.get(currentMethod); - if (line.startsWith("</i")) { - // PrintIdeal - irMethod.setIdealOutput(builder.toString()); - } else { - // PrintOptoAssembly - irMethod.setOptoAssemblyOutput(builder.toString()); - } - builder.setLength(0); - } - - /** - * Only consider non-osr (no "compile_kind") and compilations with C2 (no "level") - */ - private boolean maybeTestEntry(String line) { - return line.startsWith("<task_queued") && !line.contains("compile_kind='") && !line.contains("level='"); - } - - /** - * Need to escape XML special characters. - */ - private static void appendLine(StringBuilder builder, String line) { - if (line.contains("&")) { - line = line.replace("<", "<"); - line = line.replace(">", ">"); - line = line.replace(""", "\""); - line = line.replace("'", "'"); - line = line.replace("&", "&"); - } - builder.append(line).append(System.lineSeparator()); - } - - private static int getCompileId(Matcher matcher) { - int compileId; - try { - compileId = Integer.parseInt(matcher.group(1)); - } catch (NumberFormatException e) { - throw new TestRunException("Could not parse compile id", e); - } - return compileId; - } - - /** - * Parse the compile id from this line if it belongs to a method that needs to be IR tested (part of test class - * and IR encoding from the test VM specifies that this method has @IR rules to be checked). - */ - private void addTestMethodCompileId(Map<Integer, String> compileIdMap, String line) { - Matcher matcher = compileIdPatternForTestClass.matcher(line); - if (matcher.find()) { - // Only care about test class entries. Might have non-class entries as well if user specified additional - // compile commands. Ignore these. - String methodName = matcher.group(2); - if (compilations.containsKey(methodName)) { - // We only care about methods that we are actually gonna IR match based on IR encoding. - int compileId = getCompileId(matcher); - TestRun.check(!methodName.isEmpty(), "method name cannot be empty"); - compileIdMap.put(compileId, methodName); - } - } - } - - /** - * Make sure that line does not contain compile_kind which is used for OSR compilations which we are not - * interested in. - */ - private static boolean isPrintIdealStart(String line) { - return line.startsWith("<ideal") && !line.contains("compile_kind='"); - } - - /** - * Make sure that line does not contain compile_kind which is used for OSR compilations which we are not - * interested in. - */ - private static boolean isPrintOptoAssemblyStart(String line) { - return line.startsWith("<opto_assembly") && !line.contains("compile_kind='"); - } - - /** - * Get method name for this line by looking up the compile id. - * Returns null if not an interesting method (i.e. from test class). - */ - private String getMethodName(Map<Integer, String> compileIdMap, String line) { - Matcher matcher = COMPILE_ID_PATTERN.matcher(line); - TestFramework.check(matcher.find(), "Is " + hotspotPidFileName + " corrupted?"); - int compileId = getCompileId(matcher); - return compileIdMap.get(compileId); - } - - /** - * Do an IR matching of all methods with appliable @IR rules fetched during parsing of the hotspot pid file. - */ - private void applyRules() { - compilations.values().forEach(this::applyRulesForMethod); - reportFailuresIfAny(); - } - - private void applyRulesForMethod(IRMethod irMethod) { - this.irMethod = irMethod; - method = irMethod.getMethod(); - String testOutput = irMethod.getOutput(); - if (testOutput.isEmpty()) { - String msg = "Method was not compiled. Did you specify any compiler directives preventing a compilation or used a " + - "@Run method in STANDALONE mode? In the latter case, make sure to always trigger a C2 compilation " + - "by invoking the test enough times."; - fails.computeIfAbsent(method, k -> new ArrayList<>()).add(msg); - return; - } - - if (TestFramework.VERBOSE) { - System.out.println("Output of " + method + ":"); - System.out.println(testOutput); - } - Arrays.stream(irMethod.getRuleIds()).forEach(this::applyIRRule); - } - - /** - * Apply a single @IR rule as part of a method. - */ - private void applyIRRule(int id) { - irAnno = irMethod.getIrAnno(id); - irRuleIndex = id; - StringBuilder failMsg = new StringBuilder(); - applyFailOn(failMsg); - try { - applyCounts(failMsg); - } catch (TestFormatException e) { - // Logged. Continue to check other rules. - } - if (!failMsg.isEmpty()) { - failMsg.insert(0, "@IR rule " + (id + 1) + ": \"" + irAnno + "\"" + System.lineSeparator()); - fails.computeIfAbsent(method, k -> new ArrayList<>()).add(failMsg.toString()); - } - } - - /** - * Apply the failOn regexes of the @IR rule. - */ - private void applyFailOn(StringBuilder failMsg) { - if (irAnno.failOn().length != 0) { - String failOnRegex = String.join("|", IRNode.mergeNodes(irAnno.failOn())); - Pattern pattern = Pattern.compile(failOnRegex); - Matcher matcher = pattern.matcher(irMethod.getOutput()); - long matchCount = matcher.results().count(); - if (matchCount > 0) { - addFailOnFailsForOutput(failMsg, pattern, matchCount); - } - } - } - - /** - * A failOn regex failed. Apply all regexes again to log the exact regex which failed. The failure is later reported - * to the user. - */ - private void addFailOnFailsForOutput(StringBuilder failMsg, Pattern pattern, long matchCount) { - long idealCount = pattern.matcher(irMethod.getIdealOutput()).results().count(); - long optoAssemblyCount = pattern.matcher(irMethod.getOptoAssemblyOutput()).results().count(); - if (matchCount != idealCount + optoAssemblyCount || (idealCount != 0 && optoAssemblyCount != 0)) { - // Report with Ideal and Opto Assembly - addFailOnFailsForOutput(failMsg, irMethod.getOutput()); - irMethod.needsAllOutput(); - } else if (optoAssemblyCount == 0) { - // Report with Ideal only - addFailOnFailsForOutput(failMsg, irMethod.getIdealOutput()); - irMethod.needsIdeal(); - } else { - // Report with Opto Assembly only - addFailOnFailsForOutput(failMsg, irMethod.getOptoAssemblyOutput()); - irMethod.needsOptoAssembly(); - } - } - - /** - * Apply the regexes to the testOutput and log the failures. - */ - private void addFailOnFailsForOutput(StringBuilder failMsg, String testOutput) { - List<String> failOnNodes = IRNode.mergeNodes(irAnno.failOn()); - Pattern pattern; - Matcher matcher; - failMsg.append("- failOn: Graph contains forbidden nodes:").append(System.lineSeparator()); - int nodeId = 1; - for (String nodeRegex : failOnNodes) { - pattern = Pattern.compile(nodeRegex); - matcher = pattern.matcher(testOutput); - long matchCount = matcher.results().count(); - if (matchCount > 0) { - matcher.reset(); - failMsg.append(" Regex ").append(nodeId).append(": ").append(nodeRegex).append(System.lineSeparator()); - failMsg.append(" Matched forbidden node").append(matchCount > 1 ? "s (" + matchCount + ")" : "") - .append(":").append(System.lineSeparator()); - matcher.results().forEach(r -> failMsg.append(" ").append(r.group()).append(System.lineSeparator())); - } - nodeId++; - } - } - - /** - * Apply the counts regexes of the @IR rule. - */ - private void applyCounts(StringBuilder failMsg) { - if (irAnno.counts().length != 0) { - boolean hasFails = false; - String testOutput = irMethod.getOutput(); - int countsId = 1; - final List<String> nodesWithCount = IRNode.mergeNodes(irAnno.counts()); - for (int i = 0; i < nodesWithCount.size(); i += 2) { - String node = nodesWithCount.get(i); - TestFormat.check(i + 1 < nodesWithCount.size(), "Missing count" + getPostfixErrorMsg(node)); - String countString = nodesWithCount.get(i + 1); - long expectedCount; - ParsedComparator<Long> parsedComparator; - try { - parsedComparator = ParsedComparator.parseComparator(countString); - expectedCount = Long.parseLong(parsedComparator.getStrippedString()); - } catch (NumberFormatException e) { - TestFormat.fail("Provided invalid count \"" + countString + "\"" + getPostfixErrorMsg(node)); - return; - } catch (CheckedTestFrameworkException e) { - TestFormat.fail("Invalid comparator \"" + e.getMessage() + "\" in \"" + countString + "\" for count" + getPostfixErrorMsg(node)); - return; - } catch (IndexOutOfBoundsException e) { - TestFormat.fail("Provided empty value" + getPostfixErrorMsg(node)); - return; - } - TestFormat.check(expectedCount >= 0,"Provided invalid negative count \"" + countString + "\"" + getPostfixErrorMsg(node)); - - Pattern pattern = Pattern.compile(node); - Matcher matcher = pattern.matcher(testOutput); - long actualCount = matcher.results().count(); - if (!parsedComparator.getPredicate().test(actualCount, expectedCount)) { - if (!hasFails) { - failMsg.append("- counts: Graph contains wrong number of nodes:").append(System.lineSeparator()); - hasFails = true; - } - addCountsFail(failMsg, node, pattern, expectedCount, actualCount, countsId); - } - countsId++; - } - } - } - - private String getPostfixErrorMsg(String node) { - return " for IR rule " + irRuleIndex + ", node \"" + node + "\" at " + method; - } - - /** - * A counts regex failed. Apply all regexes again to log the exact regex which failed. The failure is later reported - * to the user. - */ - private void addCountsFail(StringBuilder failMsg, String node, Pattern pattern, long expectedCount, long actualCount, int countsId) { - failMsg.append(" Regex ").append(countsId).append(": ").append(node).append(System.lineSeparator()); - failMsg.append(" Expected ").append(expectedCount).append(" but found ").append(actualCount); - - if (actualCount > 0) { - Matcher matcher = pattern.matcher(irMethod.getOutput()); - long idealCount = pattern.matcher(irMethod.getIdealOutput()).results().count(); - long optoAssemblyCount = pattern.matcher(irMethod.getOptoAssemblyOutput()).results().count(); - if (actualCount != idealCount + optoAssemblyCount || (idealCount != 0 && optoAssemblyCount != 0)) { - irMethod.needsAllOutput(); - } else if (optoAssemblyCount == 0) { - irMethod.needsIdeal(); - } else { - irMethod.needsOptoAssembly(); - } - failMsg.append(" node").append(actualCount > 1 ? "s" : "").append(":").append(System.lineSeparator()); - matcher.results().forEach(r -> failMsg.append(" ").append(r.group()).append(System.lineSeparator())); - } else { - irMethod.needsAllOutput(); - failMsg.append(" nodes.").append(System.lineSeparator()); - } - } - - /** - * Report all IR violations in a pretty format to the user. Depending on the failed regex, we only report - * PrintIdeal or PrintOptoAssembly if the match failed there. If there were failures that matched things - * in both outputs than the entire output is reported. Throws IRViolationException from which the compilation - * can be read and reported to the stdout separately. The exception message only includes the summary of the - * failures. - */ - private void reportFailuresIfAny() { - TestFormat.reportIfAnyFailures(); - if (!fails.isEmpty()) { - StringBuilder failuresBuilder = new StringBuilder(); - StringBuilder compilationsBuilder = new StringBuilder(); - int failures = 0; - for (Map.Entry<Method, List<String>> entry : fails.entrySet()) { - Method method = entry.getKey(); - compilationsBuilder.append(">>> Compilation of ").append(method).append(":").append(System.lineSeparator()); - IRMethod irMethod = compilations.get(method.getName()); - String output; - if (irMethod.usesIdeal() && irMethod.usesOptoAssembly()) { - output = irMethod.getOutput(); - } else if (irMethod.usesIdeal()) { - output = irMethod.getIdealOutput(); - } else if (irMethod.usesOptoAssembly()) { - output = irMethod.getOptoAssemblyOutput(); - } else { - output = "<empty>"; - } - compilationsBuilder.append(output).append(System.lineSeparator()).append(System.lineSeparator()); - List<String> list = entry.getValue(); - failuresBuilder.append("- Method \"").append(method).append("\":").append(System.lineSeparator()); - failures += list.size(); - list.forEach(s -> failuresBuilder.append(" * ") - .append(s.replace(System.lineSeparator(), - System.lineSeparator() + " ").trim()) - .append(System.lineSeparator())); - failuresBuilder.append(System.lineSeparator()); - } - failuresBuilder.insert(0, ("One or more @IR rules failed:" + System.lineSeparator() - + System.lineSeparator() + "Failed IR Rules (" + failures + ")" - + System.lineSeparator()) + "-----------------" - + "-".repeat(String.valueOf(failures).length()) + System.lineSeparator()); - failuresBuilder.append(">>> Check stdout for compilation output of the failed methods") - .append(System.lineSeparator()).append(System.lineSeparator()); - - // In some very rare cases, the VM output to regex match on contains "<!-- safepoint while printing -->" - // (emitted by ttyLocker::break_tty_for_safepoint) which might be the reason for a matching error. - // Do not throw an exception in this case (i.e. bailout). - String compilations = compilationsBuilder.toString(); - if (!compilations.contains(SAFEPOINT_WHILE_PRINTING_MESSAGE)) { - throw new IRViolationException(failuresBuilder.toString(), compilations); - } else { - System.out.println("Found " + SAFEPOINT_WHILE_PRINTING_MESSAGE + ", bail out of IR matching"); - } - } - } -} diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/TestVMProcess.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/TestVMProcess.java index 0bec4c0e5da6d4403cb3605c518904ba3f4961ba..d8e10e763157730b315bf1b146ae039f59fad003 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/TestVMProcess.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/TestVMProcess.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -194,13 +194,13 @@ public class TestVMProcess { if (!testListBuilder.isEmpty()) { System.out.println("Run flag defined test list"); System.out.println("--------------------------"); - System.out.println(testListBuilder.toString()); + System.out.println(testListBuilder); System.out.println(); } if (!messagesBuilder.isEmpty()) { System.out.println("Messages from Test VM"); System.out.println("---------------------"); - System.out.println(messagesBuilder.toString()); + System.out.println(messagesBuilder); } irEncoding = nonStdOutBuilder.toString(); } else { @@ -226,7 +226,7 @@ public class TestVMProcess { */ private void throwTestVMException() { String stdErr = oa.getStderr(); - if (stdErr.contains("TestFormat.reportIfAnyFailures")) { + if (stdErr.contains("TestFormat.throwIfAnyFailures")) { Pattern pattern = Pattern.compile("Violations \\(\\d+\\)[\\s\\S]*(?=/============/)"); Matcher matcher = pattern.matcher(stdErr); TestFramework.check(matcher.find(), "Must find violation matches"); diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/CompilationOutputBuilder.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/CompilationOutputBuilder.java new file mode 100644 index 0000000000000000000000000000000000000000..b93d238656432a8c7306cede28cb51a5d383cbb1 --- /dev/null +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/CompilationOutputBuilder.java @@ -0,0 +1,50 @@ +/* + * 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. + */ + +package compiler.lib.ir_framework.driver.irmatching; + +import compiler.lib.ir_framework.driver.irmatching.irmethod.IRMethodMatchResult; + +import java.util.List; + +/** + * Class to build the compilation output of IR matching failures. + * + * @see IRMethodMatchResult + */ +class CompilationOutputBuilder { + + public static String build(List<IRMethodMatchResult> results) { + StringBuilder compilationsBuilder = new StringBuilder(); + for (IRMethodMatchResult result : results) { + if (result.fail()) { + compilationsBuilder.append(buildMatchedCompilationMessage(result)); + } + } + return compilationsBuilder.toString(); + } + + private static String buildMatchedCompilationMessage(IRMethodMatchResult result) { + return result.getMatchedCompilationOutput() + System.lineSeparator() + System.lineSeparator(); + } +} diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/IRMatcher.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/IRMatcher.java new file mode 100644 index 0000000000000000000000000000000000000000..c39d68ab1279dbb584f3e7652dfb456deee03c6a --- /dev/null +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/IRMatcher.java @@ -0,0 +1,96 @@ +/* + * 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. + */ + +package compiler.lib.ir_framework.driver.irmatching; + +import compiler.lib.ir_framework.*; +import compiler.lib.ir_framework.driver.irmatching.irmethod.IRMethodMatchResult; +import compiler.lib.ir_framework.driver.irmatching.irmethod.IRMethod; +import compiler.lib.ir_framework.driver.irmatching.parser.IRMethodParser; + +import java.util.*; + +/** + * This class parses the hotspot_pid* file of the test VM to match all applicable @IR rules afterwards. + */ +public class IRMatcher { + public static final String SAFEPOINT_WHILE_PRINTING_MESSAGE = "<!-- safepoint while printing -->"; + + public IRMatcher(String hotspotPidFileName, String irEncoding, Class<?> testClass) { + IRMethodParser irMethodParser = new IRMethodParser(testClass); + Collection<IRMethod> irMethods = irMethodParser.parse(hotspotPidFileName, irEncoding); + if (irMethods != null) { + applyIRRules(irMethods); + } + } + + /** + * Do an IR matching of all methods with applicable @IR rules prepared with by the {@link IRMethodParser}. + */ + private void applyIRRules(Collection<IRMethod> irMethods) { + List<IRMethodMatchResult> results = new ArrayList<>(); + irMethods.forEach(irMethod -> applyIRRule(irMethod, results)); + if (!results.isEmpty()) { + reportFailures(results); + } + } + + private void applyIRRule(IRMethod irMethod, List<IRMethodMatchResult> results) { + if (TestFramework.VERBOSE) { + printMethodOutput(irMethod); + } + IRMethodMatchResult result = irMethod.applyIRRules(); + if (result.fail()) { + results.add(result); + } + } + + private void printMethodOutput(IRMethod irMethod) { + System.out.println("Output of " + irMethod.getOutput() + ":"); + System.out.println(irMethod.getOutput()); + } + + /** + * Report all IR violations in a pretty format to the user. Depending on the failed regex, we only report + * PrintIdeal or PrintOptoAssembly if the match failed there. If there were failures that matched things + * in both outputs then the entire output is reported. Throws IRViolationException from which the compilation + * can be read and reported to the stdout separately. The exception message only includes the summary of the + * failures. + */ + private void reportFailures(List<IRMethodMatchResult> results) { + Collections.sort(results); // Alphabetically + throwIfNoSafepointWhilePrinting(IRMatcherFailureMessageBuilder.build(results), + CompilationOutputBuilder.build(results)); + } + + // In some very rare cases, the VM output to regex match on contains "<!-- safepoint while printing -->" + // (emitted by ttyLocker::break_tty_for_safepoint) which might be the reason for a matching error. + // Do not throw an exception in this case (i.e. bailout). + private void throwIfNoSafepointWhilePrinting(String failures, String compilations) { + if (!compilations.contains(SAFEPOINT_WHILE_PRINTING_MESSAGE)) { + throw new IRViolationException(failures, compilations); + } else { + System.out.println("Found " + SAFEPOINT_WHILE_PRINTING_MESSAGE + ", bail out of IR matching"); + } + } +} diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/IRMatcherFailureMessageBuilder.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/IRMatcherFailureMessageBuilder.java new file mode 100644 index 0000000000000000000000000000000000000000..4cdff9a2aae137d1d88cd224b7aeb33d46ef9f87 --- /dev/null +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/IRMatcherFailureMessageBuilder.java @@ -0,0 +1,81 @@ +/* + * 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. + */ + +package compiler.lib.ir_framework.driver.irmatching; + +import compiler.lib.ir_framework.driver.irmatching.irmethod.IRMethodMatchResult; + +import java.util.List; + +/** + * Class to build the failure message output of IR matching failures. + * + * @see IRMethodMatchResult + */ +class IRMatcherFailureMessageBuilder { + + public static String build(List<IRMethodMatchResult> results) { + StringBuilder failuresBuilder = new StringBuilder(); + failuresBuilder.append(buildHeaderMessage(results)); + int failureNumber = 1; + for (IRMethodMatchResult irMethodResult : results) { + if (irMethodResult.fail()) { + failuresBuilder.append(buildIRMethodFailureMessage(failureNumber, irMethodResult)); + failureNumber++; + } + } + failuresBuilder.append(buildFooterMessage()); + return failuresBuilder.toString(); + } + + private static String buildHeaderMessage(List<IRMethodMatchResult> results) { + int failedIRRulesCount = getFailedIRRulesCount(results); + long failedMethodCount = getFailedMethodCount(results); + return "One or more @IR rules failed:" + System.lineSeparator() + System.lineSeparator() + + "Failed IR Rules (" + failedIRRulesCount + ") of Methods (" + failedMethodCount + ")" + + System.lineSeparator() + + "-".repeat(32 + digitCount(failedIRRulesCount) + digitCount(failedMethodCount)) + + System.lineSeparator(); + } + + private static int getFailedIRRulesCount(List<IRMethodMatchResult> results) { + return results.stream().map(IRMethodMatchResult::getFailedIRRuleCount).reduce(0, Integer::sum); + } + + private static long getFailedMethodCount(List<IRMethodMatchResult> results) { + return results.stream().filter(IRMethodMatchResult::fail).count(); + } + + private static int digitCount(long digit) { + return String.valueOf(digit).length(); + } + + private static String buildIRMethodFailureMessage(int failureNumber, IRMethodMatchResult result) { + return failureNumber + ")" + result.buildFailureMessage() + System.lineSeparator(); + } + + private static String buildFooterMessage() { + return ">>> Check stdout for compilation output of the failed methods" + System.lineSeparator() + System.lineSeparator(); + } + +} diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/IRViolationException.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/IRViolationException.java similarity index 94% rename from test/hotspot/jtreg/compiler/lib/ir_framework/driver/IRViolationException.java rename to test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/IRViolationException.java index bacf3536dada5568f72ccc5ffb4e21b0672c7fd7..c11de93df0609d59bdd93d9f4c5dcb5a4fd3eb46 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/IRViolationException.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/IRViolationException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -21,7 +21,7 @@ * questions. */ -package compiler.lib.ir_framework.driver; +package compiler.lib.ir_framework.driver.irmatching; import compiler.lib.ir_framework.IR; import compiler.lib.ir_framework.Test; diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/MatchResult.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/MatchResult.java new file mode 100644 index 0000000000000000000000000000000000000000..bc892505f879b9e8e9990250bae2c6d76a11db04 --- /dev/null +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/MatchResult.java @@ -0,0 +1,40 @@ +/* + * 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. + */ + +package compiler.lib.ir_framework.driver.irmatching; + +/** + * Interface used by all classes which represent a IR match result. A result should also provide a failure message + * in a pretty format to be used by the {@link IRMatcher}. + */ +public interface MatchResult { + /** + * Does this match result represent a failure? + */ + boolean fail(); + + /** + * Builds a failure message in a pretty format to be used by the IR matching failure reporting. + */ + String buildFailureMessage(); +} diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/OutputMatch.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/OutputMatch.java new file mode 100644 index 0000000000000000000000000000000000000000..85cc81725ed543b7eee0c954f7c67b13750affca --- /dev/null +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/OutputMatch.java @@ -0,0 +1,50 @@ +/* + * 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. + */ + +package compiler.lib.ir_framework.driver.irmatching; + +import compiler.lib.ir_framework.driver.irmatching.irrule.IRRuleMatchResult; + +/** + * Enum to describe what kind of compilation output that was matched for a method during IR matching. + * + * @see IRRuleMatchResult + */ +public enum OutputMatch { + /** + * There was no compilation output. Should not happen and results in a failure. + */ + NONE, + /** + * Matched on PrintIdeal. + */ + IDEAL, + /** + * Matched on PrintOptoAssembly. + */ + OPTO_ASSEMBLY, + /** + * Matched on PrintIdeal and PrintOptoAssembly. + */ + BOTH +} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/shared/CardGeneration.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irmethod/FailureMessageBuilder.java similarity index 64% rename from src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/shared/CardGeneration.java rename to test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irmethod/FailureMessageBuilder.java index 3d96d33d81e8974677bbfb23676689472da2c895..057a4cd8ce9301f9f581322212150d4c878b4a86 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/shared/CardGeneration.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irmethod/FailureMessageBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -19,22 +19,25 @@ * Please 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.shared; +package compiler.lib.ir_framework.driver.irmatching.irmethod; + +import compiler.lib.ir_framework.driver.irmatching.irrule.IRRuleMatchResult; -import sun.jvm.hotspot.debugger.*; +import java.util.List; -/** Class CardGeneration is a generation that is covered by a card - table, and uses a card-size block-offset array to implement - block_start. */ +/** + * Base class to build the failure message output for an IR method. + * + * @see IRMethodMatchResult + */ +abstract class FailureMessageBuilder { + protected final IRMethod irMethod; -public abstract class CardGeneration extends Generation { - public CardGeneration(Address addr) { - super(addr); - } + public FailureMessageBuilder(IRMethod irMethod) { + this.irMethod = irMethod; + } - // FIXME: not sure what I need to expose from here in order to have - // verification similar to that of the old RememberedSet + abstract public String build(); } diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/IRMethod.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irmethod/IRMethod.java similarity index 66% rename from test/hotspot/jtreg/compiler/lib/ir_framework/driver/IRMethod.java rename to test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irmethod/IRMethod.java index dbad17034afee3b81c157d70f95175c7eeb83f1d..3250f825e00196ca68db18429416b385eefa5fc9 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/IRMethod.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irmethod/IRMethod.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -21,30 +21,34 @@ * questions. */ -package compiler.lib.ir_framework.driver; +package compiler.lib.ir_framework.driver.irmatching.irmethod; import compiler.lib.ir_framework.IR; +import compiler.lib.ir_framework.TestFramework; +import compiler.lib.ir_framework.driver.irmatching.irrule.IRRule; +import compiler.lib.ir_framework.driver.irmatching.irrule.IRRuleMatchResult; import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; /** * Helper class to store information about a method that needs to be IR matched. */ -class IRMethod { +public class IRMethod { private final Method method; - private final int[] ruleIds; - private final IR[] irAnnos; + private final List<IRRule> irRules; private final StringBuilder outputBuilder; private String output; private String idealOutput; private String optoAssemblyOutput; - private boolean needsIdeal; - private boolean needsOptoAssembly; public IRMethod(Method method, int[] ruleIds, IR[] irAnnos) { this.method = method; - this.ruleIds = ruleIds; - this.irAnnos = irAnnos; + this.irRules = new ArrayList<>(); + for (int i : ruleIds) { + irRules.add(new IRRule(this, i, irAnnos[i - 1])); + } this.outputBuilder = new StringBuilder(); this.output = ""; this.idealOutput = ""; @@ -55,13 +59,6 @@ class IRMethod { return method; } - public int[] getRuleIds() { - return ruleIds; - } - - public IR getIrAnno(int idx) { - return irAnnos[idx]; - } /** * The Ideal output comes always before the Opto Assembly output. We might parse multiple C2 compilations of this method. @@ -94,24 +91,26 @@ class IRMethod { return optoAssemblyOutput; } - public void needsAllOutput() { - needsIdeal(); - needsOptoAssembly(); - } - - public void needsIdeal() { - needsIdeal = true; - } - - public boolean usesIdeal() { - return needsIdeal; - } - - public void needsOptoAssembly() { - needsOptoAssembly = true; + /** + * Apply all IR rules of this IR method. + */ + public IRMethodMatchResult applyIRRules() { + TestFramework.check(!irRules.isEmpty(), "IRMethod cannot be created if there are no IR rules to apply"); + List<IRRuleMatchResult> results = new ArrayList<>(); + if (!output.isEmpty()) { + return getNormalMatchResult(results); + } else { + return new MissingCompilationResult(this, irRules.size()); + } } - public boolean usesOptoAssembly() { - return needsOptoAssembly; + private NormalMatchResult getNormalMatchResult(List<IRRuleMatchResult> results) { + for (IRRule irRule : irRules) { + IRRuleMatchResult result = irRule.applyCheckAttribute(); + if (result.fail()) { + results.add(result); + } + } + return new NormalMatchResult(this, results); } } diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irmethod/IRMethodMatchResult.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irmethod/IRMethodMatchResult.java new file mode 100644 index 0000000000000000000000000000000000000000..78e4dec5fee3ce15d7bbb0954052baecbbab95ac --- /dev/null +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irmethod/IRMethodMatchResult.java @@ -0,0 +1,53 @@ +/* + * 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. + */ + +package compiler.lib.ir_framework.driver.irmatching.irmethod; + +import compiler.lib.ir_framework.driver.irmatching.MatchResult; +import compiler.lib.ir_framework.driver.irmatching.irrule.IRRuleMatchResult; + +/** + * This base class represents an IR matching result of all IR rules of a method. + * + * @see IRRuleMatchResult + * @see IRMethod + */ +abstract public class IRMethodMatchResult implements Comparable<IRMethodMatchResult>, MatchResult { + protected final IRMethod irMethod; + + IRMethodMatchResult(IRMethod irMethod) { + this.irMethod = irMethod; + } + + abstract public String getMatchedCompilationOutput(); + + abstract public int getFailedIRRuleCount(); + + /** + * Used to sort the failed IR methods alphabetically. + */ + @Override + public int compareTo(IRMethodMatchResult other) { + return this.irMethod.getMethod().getName().compareTo(other.irMethod.getMethod().getName()); + } +} diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irmethod/MatchedCompilationOutputBuilder.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irmethod/MatchedCompilationOutputBuilder.java new file mode 100644 index 0000000000000000000000000000000000000000..d58bdc1fd3634d0efe021e13df03de8e9674e267 --- /dev/null +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irmethod/MatchedCompilationOutputBuilder.java @@ -0,0 +1,77 @@ +/* + * 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. + */ + +package compiler.lib.ir_framework.driver.irmatching.irmethod; + +import compiler.lib.ir_framework.driver.irmatching.OutputMatch; +import compiler.lib.ir_framework.driver.irmatching.irrule.IRRuleMatchResult; +import compiler.lib.ir_framework.shared.TestFrameworkException; + +import java.util.List; + +/** + * Class to build the compilation output for an IR method. + * + * @see IRMethodMatchResult + */ +class MatchedCompilationOutputBuilder { + private final IRMethod irMethod; + private final OutputMatch outputMatch; + + public MatchedCompilationOutputBuilder(IRMethod irMethod, List<IRRuleMatchResult> irRulesMatchResults) { + this.irMethod = irMethod; + this.outputMatch = getOutputMatch(irRulesMatchResults); + } + + private OutputMatch getOutputMatch(List<IRRuleMatchResult> irRulesMatchResults) { + OutputMatch outputMatch; + if (allMatchesOn(irRulesMatchResults, OutputMatch.IDEAL)) { + outputMatch = OutputMatch.IDEAL; + } else if (allMatchesOn(irRulesMatchResults, OutputMatch.OPTO_ASSEMBLY)) { + outputMatch = OutputMatch.OPTO_ASSEMBLY; + } else { + outputMatch = OutputMatch.BOTH; + } + return outputMatch; + } + + private boolean allMatchesOn(List<IRRuleMatchResult> irRulesMatchResults, OutputMatch outputMatch) { + return irRulesMatchResults.stream().allMatch(r -> r.getOutputMatch() == outputMatch); + } + + public String build() { + StringBuilder builder = new StringBuilder(); + builder.append(getMethodLine()); + switch (outputMatch) { + case IDEAL -> builder.append(irMethod.getIdealOutput()); + case OPTO_ASSEMBLY -> builder.append(irMethod.getOptoAssemblyOutput()); + case BOTH -> builder.append(irMethod.getOutput()); + default -> throw new TestFrameworkException("found unexpected OutputMatch " + outputMatch.name()); + } + return builder.toString(); + } + + private String getMethodLine() { + return ">>> Compilation of " + irMethod.getMethod() + ":" + System.lineSeparator(); + } +} diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irmethod/MissingCompilationMessageBuilder.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irmethod/MissingCompilationMessageBuilder.java new file mode 100644 index 0000000000000000000000000000000000000000..7d3097640ebede3093e179fb4465c558d4809929 --- /dev/null +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irmethod/MissingCompilationMessageBuilder.java @@ -0,0 +1,54 @@ +/* + * 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. + */ + +package compiler.lib.ir_framework.driver.irmatching.irmethod; + +import compiler.lib.ir_framework.driver.irmatching.irrule.IRRuleMatchResult; + +import java.util.List; + +/** + * Class to build the failure message output for an IR method with a missing compilation output. + * + * @see IRMethodMatchResult + */ +class MissingCompilationMessageBuilder extends FailureMessageBuilder { + + public MissingCompilationMessageBuilder(IRMethod irMethod) { + super(irMethod); + } + + @Override + public String build() { + return getMethodLine() + getMissingCompilationMessage(); + } + + private String getMissingCompilationMessage() { + return " * Method was not compiled. Did you specify any compiler directives preventing a compilation " + + "or used a @Run method in STANDALONE mode? In the latter case, make sure to always trigger a C2 " + + "compilation by " + "invoking the test enough times."; + } + private String getMethodLine() { + return " Method \"" + irMethod.getMethod() + "\":" + System.lineSeparator(); + } +} diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irmethod/MissingCompilationResult.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irmethod/MissingCompilationResult.java new file mode 100644 index 0000000000000000000000000000000000000000..16e008f247a1d5b0b57e86664302986f4481ab26 --- /dev/null +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irmethod/MissingCompilationResult.java @@ -0,0 +1,68 @@ +/* + * 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. + */ + +package compiler.lib.ir_framework.driver.irmatching.irmethod; + +import compiler.lib.ir_framework.driver.irmatching.irrule.IRRuleMatchResult; + +/** + * This class represents an IR matching result where the compilation output was empty. + * + * @see IRRuleMatchResult + * @see IRMethod + */ +public class MissingCompilationResult extends IRMethodMatchResult { + private final int failedIRRules; + private final MissingCompilationMessageBuilder failureMessageBuilder; + + MissingCompilationResult(IRMethod irMethod, int failedIRRules) { + super(irMethod); + this.failedIRRules = failedIRRules; + this.failureMessageBuilder = new MissingCompilationMessageBuilder(irMethod); + } + + @Override + public boolean fail() { + return true; + } + + @Override + public String getMatchedCompilationOutput() { + return "<empty>"; + } + + @Override + public String buildFailureMessage() { + return failureMessageBuilder.build(); + } + + private String getMethodLine() { + return " Method \"" + irMethod.getMethod() + "\":" + System.lineSeparator(); + } + + @Override + public int getFailedIRRuleCount() { + return failedIRRules; + } + +} diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irmethod/NormalFailureMessageBuilder.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irmethod/NormalFailureMessageBuilder.java new file mode 100644 index 0000000000000000000000000000000000000000..a6d202407ef98cb1f3ea1d7f15701dbe1ec19eff --- /dev/null +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irmethod/NormalFailureMessageBuilder.java @@ -0,0 +1,64 @@ +/* + * 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. + */ + +package compiler.lib.ir_framework.driver.irmatching.irmethod; + +import compiler.lib.ir_framework.driver.irmatching.irrule.IRRuleMatchResult; + +import java.util.List; +import java.util.stream.Collectors; + +/** + * Class to build the failure message output for an IR method for failed IR rules. + * + * @see IRMethodMatchResult + */ +class NormalFailureMessageBuilder extends FailureMessageBuilder { + private final List<IRRuleMatchResult> irRulesMatchResults; + + public NormalFailureMessageBuilder(IRMethod irMethod, List<IRRuleMatchResult> irRulesMatchResults) { + super(irMethod); + this.irRulesMatchResults = irRulesMatchResults.stream() + .filter(IRRuleMatchResult::fail) + .collect(Collectors.toList()); + } + + @Override + public String build() { + return getMethodLine() + getIRRulesFailureMessage(); + } + + private String getMethodLine() { + int failures = irRulesMatchResults.size(); + return " Method \"" + irMethod.getMethod() + "\" - [Failed IR rules: " + failures + "]:" + + System.lineSeparator(); + } + + private String getIRRulesFailureMessage() { + StringBuilder failMsg = new StringBuilder(); + for (IRRuleMatchResult irRuleResult : irRulesMatchResults) { + failMsg.append(irRuleResult.buildFailureMessage()); + } + return failMsg.toString(); + } +} diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irmethod/NormalMatchResult.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irmethod/NormalMatchResult.java new file mode 100644 index 0000000000000000000000000000000000000000..280f2909fcff78312d532d2f0fc7e6bb9e987395 --- /dev/null +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irmethod/NormalMatchResult.java @@ -0,0 +1,67 @@ +/* + * 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. + */ + +package compiler.lib.ir_framework.driver.irmatching.irmethod; + +import compiler.lib.ir_framework.driver.irmatching.irrule.IRRuleMatchResult; + +import java.util.List; + +/** + * This class represents a normal IR matching result of all IR rules of a method. + * + * @see IRRuleMatchResult + * @see IRMethod + */ +class NormalMatchResult extends IRMethodMatchResult { + private final List<IRRuleMatchResult> irRulesMatchResults; + private final NormalFailureMessageBuilder failureMessageBuilder; + private final MatchedCompilationOutputBuilder matchedCompilationOutputBuilder; + + NormalMatchResult(IRMethod irMethod, List<IRRuleMatchResult> irRulesMatchResults) { + super(irMethod); + this.irRulesMatchResults = irRulesMatchResults; + this.failureMessageBuilder = new NormalFailureMessageBuilder(irMethod, irRulesMatchResults); + this.matchedCompilationOutputBuilder = new MatchedCompilationOutputBuilder(irMethod, irRulesMatchResults); + } + + @Override + public boolean fail() { + return !irRulesMatchResults.isEmpty(); + } + + @Override + public String getMatchedCompilationOutput() { + return matchedCompilationOutputBuilder.build(); + } + + @Override + public String buildFailureMessage() { + return failureMessageBuilder.build(); + } + + @Override + public int getFailedIRRuleCount() { + return irRulesMatchResults.size(); + } +} diff --git a/src/hotspot/share/gc/g1/g1EvacFailureObjectsSet.inline.hpp b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irrule/CheckAttribute.java similarity index 60% rename from src/hotspot/share/gc/g1/g1EvacFailureObjectsSet.inline.hpp rename to test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irrule/CheckAttribute.java index 86ed1adada28d3d33c7758afb8fd5c205fcb542a..a22a43a3871acb665301a233155029eac0be90d5 100644 --- a/src/hotspot/share/gc/g1/g1EvacFailureObjectsSet.inline.hpp +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irrule/CheckAttribute.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Huawei and/or its affiliates. All rights reserved. + * 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 @@ -19,22 +19,30 @@ * Please 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_G1_G1EVACFAILUREOBJECTSSET_INLINE_HPP -#define SHARE_GC_G1_G1EVACFAILUREOBJECTSSET_INLINE_HPP +package compiler.lib.ir_framework.driver.irmatching.irrule; -#include "gc/g1/g1EvacFailureObjectsSet.hpp" -#include "gc/g1/g1CollectedHeap.hpp" -#include "gc/g1/g1SegmentedArray.inline.hpp" -#include "gc/g1/heapRegion.inline.hpp" +import compiler.lib.ir_framework.IR; -void G1EvacFailureObjectsSet::record(oop obj) { - assert(obj != NULL, "must be"); - assert(_region_idx == G1CollectedHeap::heap()->heap_region_containing(obj)->hrm_index(), "must be"); - OffsetInRegion* e = _offsets.allocate(); - *e = to_offset(obj); -} +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; -#endif //SHARE_GC_G1_G1EVACFAILUREOBJECTSSET_INLINE_HPP +/** + * Base class representing a check attribute of an IR rule. + * + * @see IR + */ +abstract class CheckAttribute { + + abstract public CheckAttributeMatchResult apply(String compilation); + + protected List<String> getMatchedNodes(Matcher m) { + List<String> matches = new ArrayList<>(); + do { + matches.add(m.group()); + } while (m.find()); + return matches; + } +} diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irrule/CheckAttributeMatchResult.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irrule/CheckAttributeMatchResult.java new file mode 100644 index 0000000000000000000000000000000000000000..8307957a60cec3fb0f77b636c61d41b1a521310c --- /dev/null +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irrule/CheckAttributeMatchResult.java @@ -0,0 +1,59 @@ +/* + * 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. + */ + +package compiler.lib.ir_framework.driver.irmatching.irrule; + +import compiler.lib.ir_framework.IR; +import compiler.lib.ir_framework.driver.irmatching.MatchResult; + +import java.util.List; + +/** + * Base class representing a result of an applied check attribute of an IR rule. + * + * @see IR + */ +abstract class CheckAttributeMatchResult implements MatchResult { + protected List<RegexFailure> regexFailures = null; + + @Override + public boolean fail() { + return regexFailures != null; + } + + public int getMatchesCount() { + if (fail()) { + return regexFailures.stream().map(RegexFailure::getMatchesCount).reduce(0, Integer::sum); + } else { + return 0; + } + } + + protected String collectRegexFailureMessages() { + StringBuilder failMsg = new StringBuilder(); + for (RegexFailure regexFailure : regexFailures) { + failMsg.append(regexFailure.buildFailureMessage()); + } + return failMsg.toString(); + } +} diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irrule/Counts.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irrule/Counts.java new file mode 100644 index 0000000000000000000000000000000000000000..4bda941c887743dd4041f14492190cc75cf6866d --- /dev/null +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irrule/Counts.java @@ -0,0 +1,121 @@ +/* + * 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. + */ + +package compiler.lib.ir_framework.driver.irmatching.irrule; + +import compiler.lib.ir_framework.IR; +import compiler.lib.ir_framework.shared.Comparison; +import compiler.lib.ir_framework.shared.ComparisonConstraintParser; +import compiler.lib.ir_framework.shared.TestFormat; + +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Class representing a counts attribute of an IR rule. + * + * @see IR#counts() + */ +class Counts extends CheckAttribute { + public List<Constraint> constraints; + + private Counts(List<Constraint> constraints) { + this.constraints = constraints; + } + + public static Counts create(List<String> nodesWithCountConstraint, IRRule irRule) { + List<Constraint> constraints = new ArrayList<>(); + int nodeId = 1; + for (int i = 0; i < nodesWithCountConstraint.size(); i += 2, nodeId++) { + String node = nodesWithCountConstraint.get(i); + TestFormat.check(i + 1 < nodesWithCountConstraint.size(), + "Missing count " + getPostfixErrorMsg(irRule, node)); + String countConstraint = nodesWithCountConstraint.get(i + 1); + Comparison<Long> comparison = parseComparison(irRule, node, countConstraint); + constraints.add(new Constraint(node, comparison, nodeId)); + } + return new Counts(constraints); + } + + private static String getPostfixErrorMsg(IRRule irRule, String node) { + return "for IR rule " + irRule.getRuleId() + ", node \"" + node + "\" at " + irRule.getMethod(); + } + + private static Comparison<Long> parseComparison(IRRule irRule, String node, String constraint) { + String postfixErrorMsg = "in count constraint " + getPostfixErrorMsg(irRule, node); + return ComparisonConstraintParser.parse(constraint, Long::parseLong, postfixErrorMsg); + } + + @Override + public CheckAttributeMatchResult apply(String compilation) { + CountsMatchResult result = new CountsMatchResult(); + checkConstraints(result, compilation); + return result; + } + + private void checkConstraints(CountsMatchResult result, String compilation) { + for (Constraint constraint : constraints) { + checkConstraint(result, compilation, constraint); + } + } + + private void checkConstraint(CountsMatchResult result, String compilation, Constraint constraint) { + long foundCount = getFoundCount(compilation, constraint); + Comparison<Long> comparison = constraint.comparison; + if (!comparison.compare(foundCount)) { + result.addFailure(createRegexFailure(compilation, constraint, foundCount)); + } + } + + private long getFoundCount(String compilation, Constraint constraint) { + Pattern pattern = Pattern.compile(constraint.nodeRegex); + Matcher matcher = pattern.matcher(compilation); + return matcher.results().count(); + } + + private CountsRegexFailure createRegexFailure(String compilation, Constraint constraint, long foundCount) { + Pattern p = Pattern.compile(constraint.nodeRegex); + Matcher m = p.matcher(compilation); + List<String> matches; + if (m.find()) { + matches = getMatchedNodes(m); + } else { + matches = new ArrayList<>(); + } + return new CountsRegexFailure(constraint.nodeRegex, constraint.nodeId, foundCount, constraint.comparison, matches); + } + + static class Constraint { + final String nodeRegex; + final Comparison<Long> comparison; + private final int nodeId; + + Constraint(String nodeRegex, Comparison<Long> comparison, int nodeId) { + this.nodeRegex = nodeRegex; + this.comparison = comparison; + this.nodeId = nodeId; + } + } +} diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irrule/CountsMatchResult.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irrule/CountsMatchResult.java new file mode 100644 index 0000000000000000000000000000000000000000..4830bb1b46af92f8f298f78d193371b6b4d6489b --- /dev/null +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irrule/CountsMatchResult.java @@ -0,0 +1,49 @@ +/* + * 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. + */ + +package compiler.lib.ir_framework.driver.irmatching.irrule; + +import compiler.lib.ir_framework.IR; + +import java.util.ArrayList; + +/** + * Class representing a result of an applied counts attribute of an IR rule. + * + * @see IR#counts() + */ +class CountsMatchResult extends CheckAttributeMatchResult { + + public void addFailure(RegexFailure regexFailure) { + if (regexFailures == null) { + regexFailures = new ArrayList<>(); + } + regexFailures.add(regexFailure); + } + + @Override + public String buildFailureMessage() { + return " - counts: Graph contains wrong number of nodes:" + System.lineSeparator() + + collectRegexFailureMessages(); + } +} diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irrule/CountsRegexFailure.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irrule/CountsRegexFailure.java new file mode 100644 index 0000000000000000000000000000000000000000..ae7b235ffd0dac52a1f598d2b5c215d59361154f --- /dev/null +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irrule/CountsRegexFailure.java @@ -0,0 +1,73 @@ +/* + * 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. + */ + +package compiler.lib.ir_framework.driver.irmatching.irrule; + +import compiler.lib.ir_framework.shared.Comparison; + +import java.util.List; + +/** + * This class represents an IR matching failure of a regex of a counts attribute of an IR rule. + * + * @see Counts + */ +class CountsRegexFailure extends RegexFailure { + String failedComparison; + + public CountsRegexFailure(String nodeRegex, int nodeId, long foundValue, Comparison<Long> comparison, List<String> matches) { + super(nodeRegex, nodeId, matches); + this.failedComparison = "[found] " + foundValue + " " + comparison.getComparator() + " " + + comparison.getGivenValue() + " [given]"; + } + + @Override + public String buildFailureMessage() { + return getRegexLine() + + getFailedComparison() + + getMatchedNodesBlock(); + } + + private String getFailedComparison() { + return " - Failed comparison: " + failedComparison + System.lineSeparator(); + } + + @Override + protected String getMatchedNodesBlock() { + if (matches.isEmpty()) { + return getEmptyNodeMatchesLine(); + } else { + return super.getMatchedNodesBlock(); + } + } + + private String getEmptyNodeMatchesLine() { + return getMatchedNodesWhiteSpace() + "- No nodes matched!" + System.lineSeparator(); + } + + @Override + protected String getMatchedPrefix() { + return "Matched"; + } + +} diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irrule/FailOn.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irrule/FailOn.java new file mode 100644 index 0000000000000000000000000000000000000000..fa49a029ef9efbaef969e51f36139d2a3b8be9bc --- /dev/null +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irrule/FailOn.java @@ -0,0 +1,73 @@ +/* + * 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. + */ + +package compiler.lib.ir_framework.driver.irmatching.irrule; + +import compiler.lib.ir_framework.IR; + +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Class representing a failOn attribute of an IR rule. + * + * @see IR#failOn() + */ +class FailOn extends CheckAttribute { + private final Pattern quickPattern; + private final List<String> nodes; + + public FailOn(List<String> nodes) { + this.nodes = nodes; + this.quickPattern = Pattern.compile(String.join("|", nodes)); + } + + @Override + public CheckAttributeMatchResult apply(String compilation) { + FailOnMatchResult result = new FailOnMatchResult(); + Matcher matcher = quickPattern.matcher(compilation); + if (matcher.find()) { + result.setFailures(createFailOnFailures(compilation)); + } + return result; + } + + private List<RegexFailure> createFailOnFailures(String compilation) { + List<RegexFailure> regexFailures = new ArrayList<>(); + for (int i = 0; i < nodes.size(); i++) { + checkNode(regexFailures, compilation, nodes.get(i), i + 1); + } + return regexFailures; + } + + private void checkNode(List<RegexFailure> regexFailures, String compilation, String node, int nodeId) { + Pattern p = Pattern.compile(node); + Matcher m = p.matcher(compilation); + if (m.find()) { + List<String> matches = getMatchedNodes(m); + regexFailures.add(new FailOnRegexFailure(node, nodeId, matches)); + } + } +} diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irrule/FailOnMatchResult.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irrule/FailOnMatchResult.java new file mode 100644 index 0000000000000000000000000000000000000000..99c6312ee02b278312f06dcd1609b54e698dcf05 --- /dev/null +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irrule/FailOnMatchResult.java @@ -0,0 +1,45 @@ +/* + * 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. + */ + +package compiler.lib.ir_framework.driver.irmatching.irrule; + +import compiler.lib.ir_framework.IR; + +import java.util.List; + +/** + * Class representing a result of an applied failOn attribute of an IR rule. + * + * @see IR#failOn() + */ +class FailOnMatchResult extends CheckAttributeMatchResult { + public void setFailures(List<RegexFailure> regexFailures) { + this.regexFailures = regexFailures; + } + + @Override + public String buildFailureMessage() { + return " - failOn: Graph contains forbidden nodes:" + System.lineSeparator() + + collectRegexFailureMessages(); + } +} diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irrule/FailOnRegexFailure.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irrule/FailOnRegexFailure.java new file mode 100644 index 0000000000000000000000000000000000000000..24c96aef5e9a2029acb26489ab67450db3c538cc --- /dev/null +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irrule/FailOnRegexFailure.java @@ -0,0 +1,49 @@ +/* + * 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. + */ + +package compiler.lib.ir_framework.driver.irmatching.irrule; + +import java.util.List; + +/** + * This class represents an IR matching failure of a regex of a failOn attribute of an IR rule. + * + * @see FailOn + */ +class FailOnRegexFailure extends RegexFailure { + + public FailOnRegexFailure(String nodeRegex, int nodeId, List<String> matches) { + super(nodeRegex, nodeId, matches); + } + + @Override + public String buildFailureMessage() { + return getRegexLine() + + getMatchedNodesBlock(); + } + + @Override + protected String getMatchedPrefix() { + return "Matched forbidden"; + } +} diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irrule/IRRule.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irrule/IRRule.java new file mode 100644 index 0000000000000000000000000000000000000000..5b2e8c7718adc09012d8cea990b989f43cf5e54d --- /dev/null +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irrule/IRRule.java @@ -0,0 +1,149 @@ +/* + * 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. + */ + +package compiler.lib.ir_framework.driver.irmatching.irrule; + +import compiler.lib.ir_framework.IR; +import compiler.lib.ir_framework.IRNode; +import compiler.lib.ir_framework.driver.irmatching.irmethod.IRMethod; +import compiler.lib.ir_framework.driver.irmatching.OutputMatch; +import compiler.lib.ir_framework.shared.*; + +import java.lang.reflect.Method; +import java.util.function.Consumer; + +public class IRRule { + private final IRMethod irMethod; + private final int ruleId; + private final IR irAnno; + private final FailOn failOn; + private final Counts counts; + + public IRRule(IRMethod irMethod, int ruleId, IR irAnno) { + this.irMethod = irMethod; + this.ruleId = ruleId; + this.irAnno = irAnno; + this.failOn = initFailOn(irAnno); + this.counts = initCounts(irAnno); + } + + private Counts initCounts(IR irAnno) { + String[] countsConstraints = irAnno.counts(); + if (countsConstraints.length != 0) { + try { + return Counts.create(IRNode.mergeNodes(countsConstraints), this); + } catch (TestFormatException e) { + // Logged and reported later. Continue. + } + } + return null; + } + + private FailOn initFailOn(IR irAnno) { + String[] failOnNodes = irAnno.failOn(); + if (failOnNodes.length != 0) { + return new FailOn(IRNode.mergeNodes(failOnNodes)); + } + return null; + } + + public int getRuleId() { + return ruleId; + } + + public IR getIRAnno() { + return irAnno; + } + + public Method getMethod() { + return irMethod.getMethod(); + } + + /** + * Apply this IR rule by checking any failOn and counts attributes. + */ + public IRRuleMatchResult applyCheckAttribute() { + IRRuleMatchResult result = new IRRuleMatchResult(this); + if (failOn != null) { + applyCheckAttribute(failOn, result, result::setFailOnFailures); + } + if (counts != null) { + applyCheckAttribute(counts, result, result::setCountsFailures); + } + return result; + } + + private void applyCheckAttribute(CheckAttribute checkAttribute, IRRuleMatchResult result, + Consumer<CheckAttributeMatchResult> setFailures) { + CheckAttributeMatchResult checkAttributeResult = checkAttribute.apply(irMethod.getOutput()); + if (checkAttributeResult.fail()) { + setFailures.accept(checkAttributeResult); + result.updateOutputMatch(getOutputMatch(checkAttribute, checkAttributeResult)); + } + } + + /** + * Determine how the output was matched by reapplying the check attribute for the PrintIdeal and PrintOptoAssembly + * output separately. + */ + private OutputMatch getOutputMatch(CheckAttribute checkAttribute, CheckAttributeMatchResult checkAttributeResult) { + int totalMatches = checkAttributeResult.getMatchesCount(); + int idealFailuresCount = getMatchesCount(checkAttribute, irMethod.getIdealOutput()); + int optoAssemblyFailuresCount = getMatchesCount(checkAttribute, irMethod.getOptoAssemblyOutput()); + return findOutputMatch(totalMatches, idealFailuresCount, optoAssemblyFailuresCount); + } + + private int getMatchesCount(CheckAttribute checkAttribute, String compilation) { + CheckAttributeMatchResult result = checkAttribute.apply(compilation); + return result.getMatchesCount(); + } + + /** + * Compare different counts to find out, on what output a failure was matched. + */ + private OutputMatch findOutputMatch(int totalMatches, int idealFailuresCount, int optoAssemblyFailuresCount) { + if (totalMatches == 0 + || someRegexMatchOnlyEntireOutput(totalMatches, idealFailuresCount, optoAssemblyFailuresCount) + || anyMatchOnIdealAndOptoAssembly(idealFailuresCount, optoAssemblyFailuresCount)) { + return OutputMatch.BOTH; + } else if (optoAssemblyFailuresCount == 0) { + return OutputMatch.IDEAL; + } else { + return OutputMatch.OPTO_ASSEMBLY; + } + } + + /** + * Do we have a regex that is only matched on the entire ideal + opto assembly output? + */ + private boolean someRegexMatchOnlyEntireOutput(int totalCount, int idealFailuresCount, int optoAssemblyFailuresCount) { + return totalCount != idealFailuresCount + optoAssemblyFailuresCount; + } + + /** + * Do we have a match on ideal and opto assembly for this rule? + */ + private boolean anyMatchOnIdealAndOptoAssembly(int idealFailuresCount, int optoAssemblyFailuresCount) { + return idealFailuresCount > 0 && optoAssemblyFailuresCount > 0; + } +} diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irrule/IRRuleMatchResult.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irrule/IRRuleMatchResult.java new file mode 100644 index 0000000000000000000000000000000000000000..c7d44498d555fdc44c5cd1c2e507226dae80c8ba --- /dev/null +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irrule/IRRuleMatchResult.java @@ -0,0 +1,102 @@ +/* + * 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. + */ + +package compiler.lib.ir_framework.driver.irmatching.irrule; + +import compiler.lib.ir_framework.TestFramework; +import compiler.lib.ir_framework.driver.irmatching.MatchResult; +import compiler.lib.ir_framework.driver.irmatching.OutputMatch; + +/** + * This class represents an IR matching result of an IR rule. + * + * @see CheckAttributeMatchResult + * @see IRRule + */ +public class IRRuleMatchResult implements MatchResult { + private final IRRule irRule; + private CheckAttributeMatchResult failOnFailures = null; + private CheckAttributeMatchResult countsFailures = null; + private OutputMatch outputMatch; + + public IRRuleMatchResult(IRRule irRule) { + this.irRule = irRule; + this.outputMatch = OutputMatch.NONE; + } + + private boolean hasFailOnFailures() { + return failOnFailures != null; + } + + public void setFailOnFailures(CheckAttributeMatchResult failOnFailures) { + this.failOnFailures = failOnFailures; + } + + private boolean hasCountsFailures() { + return countsFailures != null; + } + + public void setCountsFailures(CheckAttributeMatchResult countsFailures) { + this.countsFailures = countsFailures; + } + + public OutputMatch getOutputMatch() { + return outputMatch; + } + + @Override + public boolean fail() { + return failOnFailures != null || countsFailures != null; + } + + public void updateOutputMatch(OutputMatch newOutputMatch) { + TestFramework.check(newOutputMatch != OutputMatch.NONE, "must be valid state"); + switch (outputMatch) { + case NONE -> outputMatch = newOutputMatch; + case IDEAL -> outputMatch = newOutputMatch != OutputMatch.IDEAL + ? OutputMatch.BOTH : OutputMatch.IDEAL; + case OPTO_ASSEMBLY -> outputMatch = newOutputMatch != OutputMatch.OPTO_ASSEMBLY + ? OutputMatch.BOTH : OutputMatch.OPTO_ASSEMBLY; + } + } + + /** + * Build a failure message based on the collected failures of this object. + */ + @Override + public String buildFailureMessage() { + StringBuilder failMsg = new StringBuilder(); + failMsg.append(getIRRuleLine()); + if (hasFailOnFailures()) { + failMsg.append(failOnFailures.buildFailureMessage()); + } + if (hasCountsFailures()) { + failMsg.append(countsFailures.buildFailureMessage()); + } + return failMsg.toString(); + } + + private String getIRRuleLine() { + return " * @IR rule " + irRule.getRuleId() + ": \"" + irRule.getIRAnno() + "\"" + System.lineSeparator(); + } +} diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irrule/RegexFailure.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irrule/RegexFailure.java new file mode 100644 index 0000000000000000000000000000000000000000..821da618fa699d2db4a0834a5288e4835e4162f1 --- /dev/null +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irrule/RegexFailure.java @@ -0,0 +1,90 @@ +/* + * 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. + */ + +package compiler.lib.ir_framework.driver.irmatching.irrule; + +import java.util.List; +import java.util.stream.Collectors; + +/** + * Base class representing an IR matching failure of a regex of a check attribute of an IR rule. + * + * @see CheckAttributeMatchResult + * @see CheckAttribute + * @see IRRule + */ +abstract class RegexFailure { + protected final String nodeRegex; + protected final int nodeId; + protected final List<String> matches; + + public RegexFailure(String nodeRegex, int nodeId, List<String> matches) { + this.nodeRegex = nodeRegex; + this.nodeId = nodeId; + this.matches = addWhiteSpacePrefixForEachLine(matches); + } + + private List<String> addWhiteSpacePrefixForEachLine(List<String> matches) { + return matches + .stream() + .map(s -> s.replaceAll(System.lineSeparator(), System.lineSeparator() + + getMatchedNodesItemWhiteSpace() + " ")) + .collect(Collectors.toList()); + } + + abstract public String buildFailureMessage(); + + public int getMatchesCount() { + return matches.size(); + } + + protected String getRegexLine() { + return " * Regex " + nodeId + ": " + nodeRegex + System.lineSeparator(); + } + + protected String getMatchedNodesBlock() { + return getMatchedNodesHeader() + getMatchesNodeLines(); + } + + protected String getMatchedNodesHeader() { + int matchCount = matches.size(); + return "" + getMatchedNodesWhiteSpace() + "- " + getMatchedPrefix() + " node" + + (matchCount != 1 ? "s (" + matchCount + ")" : "") + ":" + System.lineSeparator(); + } + + protected String getMatchedNodesWhiteSpace() { + return " "; + } + + abstract protected String getMatchedPrefix(); + + protected String getMatchesNodeLines() { + StringBuilder builder = new StringBuilder(); + matches.forEach(match -> builder.append(getMatchedNodesItemWhiteSpace()).append("* ").append(match).append(System.lineSeparator())); + return builder.toString(); + } + + private String getMatchedNodesItemWhiteSpace() { + return " "; + } +} diff --git a/test/jdk/sun/net/www/httptest/HttpCallback.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/AbstractLine.java similarity index 58% rename from test/jdk/sun/net/www/httptest/HttpCallback.java rename to test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/AbstractLine.java index 27af7b7aaf4ebbbe7cfec599d20305ec526db8ed..19bca4307099b1fa456bf8b25729cd84346c00e7 100644 --- a/test/jdk/sun/net/www/httptest/HttpCallback.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/AbstractLine.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -21,19 +21,31 @@ * questions. */ +package compiler.lib.ir_framework.driver.irmatching.parser; + +import java.io.BufferedReader; +import java.io.IOException; + /** - * This interface is implemented by classes that wish to handle incoming HTTP - * requests and generate responses. This could be a general purpose HTTP server - * or a test case that expects specific requests from a client. - * <p> - * The incoming request fields can be examined via the {@link HttpTransaction} - * object, and a response can also be generated and sent via the request object. + * Base class of a read line from the hotspot_pid* file. */ -public interface HttpCallback { +abstract class AbstractLine { + private final BufferedReader reader; + protected String line; + + public AbstractLine(BufferedReader reader) { + this.reader = reader; + } + + public String getLine() { + return line; + } + /** - * handle the given request and generate an appropriate response. - * @param msg the transaction containing the request from the - * client and used to send the response + * Read next line and return it. If we've reached the end of the file, return NULL instead. */ - void request (HttpTransaction msg); + public boolean readLine() throws IOException { + line = reader.readLine(); + return line != null; + } } diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/BlockLine.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/BlockLine.java new file mode 100644 index 0000000000000000000000000000000000000000..0fa91a43c5ed631757327f4d258a5306fd3e178e --- /dev/null +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/BlockLine.java @@ -0,0 +1,43 @@ +/* + * 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. + */ + +package compiler.lib.ir_framework.driver.irmatching.parser; + +import java.io.BufferedReader; + +/** + * Class representing a block line inside a PrintIdeal or PrintOptoAssembly output block read from the hotspot_pid* file. + */ +class BlockLine extends AbstractLine { + + public BlockLine(BufferedReader reader) { + super(reader); + } + + /** + * Is this line an end of a PrintIdeal or PrintOptoAssembly output block? + */ + public boolean isBlockEnd() { + return line.startsWith("</"); + } +} diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/BlockOutputReader.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/BlockOutputReader.java new file mode 100644 index 0000000000000000000000000000000000000000..da6acbdc1b0421002a34024eba0407f7acf9b37f --- /dev/null +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/BlockOutputReader.java @@ -0,0 +1,64 @@ +/* + * 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. + */ + +package compiler.lib.ir_framework.driver.irmatching.parser; + +import java.io.BufferedReader; +import java.io.IOException; + +/** + * Class to read all lines of a PrintIdeal or PrintOptoAssembly block. + */ +class BlockOutputReader { + private final BufferedReader reader; + + public BlockOutputReader(BufferedReader reader) { + this.reader = reader; + } + + /** + * Read all lines belonging to a PrintIdeal or PrintOptoAssembly output block. + */ + public String readBlock() throws IOException { + BlockLine line = new BlockLine(reader); + StringBuilder builder = new StringBuilder(); + while (line.readLine() && !line.isBlockEnd()) { + builder.append(escapeXML(line.getLine())).append(System.lineSeparator()); + } + return builder.toString(); + } + + /** + * Need to escape XML special characters. + */ + private static String escapeXML(String line) { + if (line.contains("&")) { + line = line.replace("<", "<"); + line = line.replace(">", ">"); + line = line.replace(""", "\""); + line = line.replace("'", "'"); + line = line.replace("&", "&"); + } + return line; + } +} diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/FileCorruptedException.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/FileCorruptedException.java new file mode 100644 index 0000000000000000000000000000000000000000..5681eb662ee99ae6b098bf63ed2dc6074f800f65 --- /dev/null +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/FileCorruptedException.java @@ -0,0 +1,33 @@ +/* + * 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. + */ + +package compiler.lib.ir_framework.driver.irmatching.parser; + +/** + * Exception thrown when facing an unexpected format during parsing of the hotspot-pid* file + */ +class FileCorruptedException extends RuntimeException { + public FileCorruptedException(String s) { + super(s); + } +} diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/HotSpotPidFileParser.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/HotSpotPidFileParser.java new file mode 100644 index 0000000000000000000000000000000000000000..2e5a1d334561c81b1075b303e61b7dcc1c41325e --- /dev/null +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/HotSpotPidFileParser.java @@ -0,0 +1,142 @@ +/* + * 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. + */ + +package compiler.lib.ir_framework.driver.irmatching.parser; + +import compiler.lib.ir_framework.TestFramework; +import compiler.lib.ir_framework.driver.irmatching.irmethod.IRMethod; +import compiler.lib.ir_framework.shared.TestFrameworkException; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Class to parse the PrintIdeal and PrintOptoAssembly outputs of the test class from the hotspot_pid* file and add them + * to the collection of {@link IRMethod} created by {@link IREncodingParser}. + * + * @see IRMethod + * @see IREncodingParser + */ +class HotSpotPidFileParser { + private static final Pattern COMPILE_ID_PATTERN = Pattern.compile("compile_id='(\\d+)'"); + + private final Pattern compileIdPatternForTestClass; + private Map<String, IRMethod> compilationsMap; + + public HotSpotPidFileParser(String testClass) { + this.compileIdPatternForTestClass = Pattern.compile("compile_id='(\\d+)'.*" + Pattern.quote(testClass) + " (\\S+)"); + } + + public void setCompilationsMap(Map<String, IRMethod> compilationsMap) { + this.compilationsMap = compilationsMap; + } + /** + * Parse the hotspot_pid*.log file from the test VM. Read the PrintIdeal and PrintOptoAssembly outputs for all + * methods of the test class that need to be IR matched (found in compilations map). + */ + public Collection<IRMethod> parseCompilations(String hotspotPidFileName) { + try { + processFileLines(hotspotPidFileName); + return compilationsMap.values(); + } catch (IOException e) { + throw new TestFrameworkException("Error while reading " + hotspotPidFileName, e); + } catch (FileCorruptedException e) { + throw new TestFrameworkException("Unexpected format of " + hotspotPidFileName, e); + } + } + + private void processFileLines(String hotspotPidFileName) throws IOException { + Map<Integer, IRMethod> compileIdMap = new HashMap<>(); + try (var reader = Files.newBufferedReader(Paths.get(hotspotPidFileName))) { + Line line = new Line(reader, compileIdPatternForTestClass); + BlockOutputReader blockOutputReader = new BlockOutputReader(reader); + while (line.readLine()) { + if (line.isTestClassCompilation()) { + parseTestMethodCompileId(compileIdMap, line.getLine()); + } else if (isTestMethodBlockStart(line, compileIdMap)) { + String blockOutput = blockOutputReader.readBlock(); + setIRMethodOutput(blockOutput, line, compileIdMap); + } + } + } + } + + private void parseTestMethodCompileId(Map<Integer, IRMethod> compileIdMap, String line) { + String methodName = parseMethodName(line); + if (isTestAnnotatedMethod(methodName)) { + int compileId = getCompileId(line); + compileIdMap.put(compileId, getIrMethod(methodName)); + } + } + + private String parseMethodName(String line) { + Matcher matcher = compileIdPatternForTestClass.matcher(line); + TestFramework.check(matcher.find(), "must find match"); + return matcher.group(2); + } + + private boolean isTestAnnotatedMethod(String testMethodName) { + return compilationsMap.containsKey(testMethodName); + } + + private IRMethod getIrMethod(String testMethodName) { + return compilationsMap.get(testMethodName); + } + + + + private int getCompileId(String line) { + Matcher matcher = COMPILE_ID_PATTERN.matcher(line); + if (!matcher.find()) { + throw new FileCorruptedException("Unexpected format found on this line: " + line); + } + return Integer.parseInt(matcher.group(1)); + } + + private boolean isTestMethodBlockStart(Line line, Map<Integer, IRMethod> compileIdMap) { + return line.isBlockStart() && isTestClassMethodBlock(line, compileIdMap); + } + + private boolean isTestClassMethodBlock(Line line, Map<Integer, IRMethod> compileIdMap) { + return compileIdMap.containsKey(getCompileId(line.getLine())); + } + + public void setIRMethodOutput(String blockOutput, Line blockStartLine, Map<Integer, IRMethod> compileIdMap) { + IRMethod irMethod = compileIdMap.get(getCompileId(blockStartLine.getLine())); + setIRMethodOutput(blockOutput, blockStartLine, irMethod); + } + + private void setIRMethodOutput(String blockOutput, Line blockStartLine, IRMethod irMethod) { + if (blockStartLine.isPrintIdealStart()) { + irMethod.setIdealOutput(blockOutput); + } else { + irMethod.setOptoAssemblyOutput(blockOutput); + } + } +} diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/IREncodingParser.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/IREncodingParser.java new file mode 100644 index 0000000000000000000000000000000000000000..5e539a25962dfbbe1417f2c6e89e4f87b5ed88e8 --- /dev/null +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/IREncodingParser.java @@ -0,0 +1,153 @@ +/* + * 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. + */ + +package compiler.lib.ir_framework.driver.irmatching.parser; + +import compiler.lib.ir_framework.IR; +import compiler.lib.ir_framework.TestFramework; +import compiler.lib.ir_framework.driver.irmatching.irmethod.IRMethod; +import compiler.lib.ir_framework.shared.TestFormat; +import compiler.lib.ir_framework.shared.TestFrameworkException; +import compiler.lib.ir_framework.test.IREncodingPrinter; + +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Class to parse the IR encoding emitted by the test VM and creating {@link IRMethod} objects for each entry. + * + * @see IRMethod + */ +class IREncodingParser { + + private static final boolean PRINT_IR_ENCODING = Boolean.parseBoolean(System.getProperty("PrintIREncoding", "false")); + private static final Pattern IR_ENCODING_PATTERN = + Pattern.compile("(?<=" + IREncodingPrinter.START + "\r?\n).*\\R([\\s\\S]*)(?=" + IREncodingPrinter.END + ")"); + + private final Map<String, IRMethod> compilations; + private final Class<?> testClass; + + public IREncodingParser(Class<?> testClass) { + this.testClass = testClass; + this.compilations = new HashMap<>(); + } + + public Map<String, IRMethod> parseIRMethods(String irEncoding) { + if (TestFramework.VERBOSE || PRINT_IR_ENCODING) { + System.out.println("Read IR encoding from test VM:"); + System.out.println(irEncoding); + } + createCompilationsMap(irEncoding, testClass); + // We could have found format errors in @IR annotations. Report them now with an exception. + TestFormat.throwIfAnyFailures(); + return compilations; + } + + /** + * Sets up a map testname -> IRMethod (containing the PrintIdeal and PrintOptoAssembly output for testname). + */ + private void createCompilationsMap(String irEncoding, Class<?> testClass) { + Map<String, int[]> irRulesMap = parseIREncoding(irEncoding); + createIRMethodsWithEncoding(testClass, irRulesMap); + } + + /** + * Read the IR encoding emitted by the test VM to decide if an @IR rule must be checked for a method. + */ + private Map<String, int[]> parseIREncoding(String irEncoding) { + Map<String, int[]> irRulesMap = new HashMap<>(); + String[] irEncodingLines = getIREncodingLines(irEncoding); + for (String s : irEncodingLines) { + String line = s.trim(); + String[] splitLine = line.split(","); + if (splitLine.length < 2) { + throw new TestFrameworkException("Invalid IR match rule encoding. No comma found: " + splitLine[0]); + } + String testName = splitLine[0]; + int[] irRulesIdx = getRuleIndexes(splitLine); + irRulesMap.put(testName, irRulesIdx); + } + return irRulesMap; + } + + /** + * Parse the IR encoding lines without header, explanation line and footer and return them in an array. + */ + private String[] getIREncodingLines(String irEncoding) { + Matcher matcher = IR_ENCODING_PATTERN.matcher(irEncoding); + TestFramework.check(matcher.find(), "Did not find IR encoding"); + String lines = matcher.group(1).trim(); + if (lines.isEmpty()) { + // Nothing to IR match. + return new String[0]; + } + return lines.split("\\R"); + } + + /** + * Parse rule indexes from IR encoding line of the format: <method,idx1,idx2,...> + */ + private int[] getRuleIndexes(String[] splitLine) { + int[] irRulesIdx = new int[splitLine.length - 1]; + for (int i = 1; i < splitLine.length; i++) { + try { + irRulesIdx[i - 1] = Integer.parseInt(splitLine[i]); + } catch (NumberFormatException e) { + throw new TestFrameworkException("Invalid IR match rule encoding. No number found: " + splitLine[i]); + } + } + return irRulesIdx; + } + + private void createIRMethodsWithEncoding(Class<?> testClass, Map<String, int[]> irRulesMap) { + for (Method m : testClass.getDeclaredMethods()) { + IR[] irAnnos = m.getAnnotationsByType(IR.class); + if (irAnnos.length > 0) { + // Validation of legal @IR attributes and placement of the annotation was already done in Test VM. + int[] irRuleIds = irRulesMap.get(m.getName()); + validateIRRuleIds(m, irAnnos, irRuleIds); + if (hasAnyApplicableIRRules(irRuleIds)) { + compilations.put(m.getName(), new IRMethod(m, irRuleIds, irAnnos)); + } + } + } + } + + private void validateIRRuleIds(Method m, IR[] irAnnos, int[] ids) { + TestFramework.check(ids != null, "Should find method name in validIrRulesMap for " + m); + TestFramework.check(ids.length > 0, "Did not find any rule indices for " + m); + TestFramework.check((ids[0] >= 1 || ids[0] == IREncodingPrinter.NO_RULE_APPLIED) + && ids[ids.length - 1] <= irAnnos.length, + "Invalid IR rule index found in validIrRulesMap for " + m); + } + + /** + * Does the list of IR rules contain any applicable IR rules for the given conditions? + */ + private boolean hasAnyApplicableIRRules(int[] irRuleIds) { + return irRuleIds[0] != IREncodingPrinter.NO_RULE_APPLIED; + } +} diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/IRMethodParser.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/IRMethodParser.java new file mode 100644 index 0000000000000000000000000000000000000000..332b88d96c6b87e9577205c33b997ee69223a6e8 --- /dev/null +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/IRMethodParser.java @@ -0,0 +1,58 @@ +/* + * 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. + */ + +package compiler.lib.ir_framework.driver.irmatching.parser; + +import compiler.lib.ir_framework.driver.irmatching.irmethod.IRMethod; + +import java.util.Collection; +import java.util.Map; + +/** + * Class to parse the PrintIdeal and PrintOptoAssembly outputs of the test class and store them into a collection + * of dedicated IRMethod objects used throughout IR matching. + * + * @see IRMethod + */ +public class IRMethodParser { + private final IREncodingParser irEncodingParser; + private final HotSpotPidFileParser hotSpotPidFileParser; + + public IRMethodParser(Class<?> testClass) { + this.irEncodingParser = new IREncodingParser(testClass); + this.hotSpotPidFileParser = new HotSpotPidFileParser(testClass.getName()); + } + + /** + * Parse the IR encoding and hotspot_pid* file to create a collection of {@link IRMethod} objects. + * Return null if there are no applicable @IR rules in any method of the test class. + */ + public Collection<IRMethod> parse(String hotspotPidFileName, String irEncoding) { + Map<String, IRMethod> compilationsMap = irEncodingParser.parseIRMethods(irEncoding); + if (!compilationsMap.isEmpty()) { + hotSpotPidFileParser.setCompilationsMap(compilationsMap); + return hotSpotPidFileParser.parseCompilations(hotspotPidFileName); + } + return null; + } +} diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/Line.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/Line.java new file mode 100644 index 0000000000000000000000000000000000000000..16ef31b719d9c5c193cf5bba5d4f7896e6688f20 --- /dev/null +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/Line.java @@ -0,0 +1,97 @@ +/* + * 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. + */ + +package compiler.lib.ir_framework.driver.irmatching.parser; + +import java.io.BufferedReader; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Class representing a normal line read from the hotspot_pid* file. + */ +class Line extends AbstractLine { + private final Pattern compileIdPatternForTestClass; + + public Line(BufferedReader reader, Pattern compileIdPatternForTestClass) { + super(reader); + this.compileIdPatternForTestClass = compileIdPatternForTestClass; + } + + /** + * Is this line a start of a @Test annotated method? We only care about test class entries. There might be non-class + * entries as well if user specified additional compile commands. Ignore these. + */ + public boolean isTestClassCompilation() { + if (isCompilation()) { + Matcher matcher = compileIdPatternForTestClass.matcher(line); + return matcher.find(); + } + return false; + } + + /** + * Is this header a C2 non-OSR compilation header entry? + */ + public boolean isCompilation() { + return line.startsWith("<task_queued") && notOSRCompilation() && notC2Compilation(); + } + + /** + * OSR compilations have compile_kind set. + */ + private boolean notOSRCompilation() { + return !line.contains("compile_kind='"); + } + + /** + * Non-C2 compilations have level set. + */ + private boolean notC2Compilation() { + return !line.contains("level='"); + } + + /** + * Is this line a start of a PrintIdeal or PrintOptoAssembly output block? + */ + public boolean isBlockStart() { + return isPrintIdealStart() || isPrintOptoAssemblyStart(); + } + + /** + * Is this line a start of a PrintIdeal output block? + */ + public boolean isPrintIdealStart() { + // Ignore OSR compilations which have compile_kind set. + return line.startsWith("<ideal") && notOSRCompilation(); + } + + /** + * Is this line a start of a PrintOptoAssembly output block? + */ + private boolean isPrintOptoAssemblyStart() { + // Ignore OSR compilations which have compile_kind set. + return line.startsWith("<opto_assembly") && notOSRCompilation(); + } +} + diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/shared/Comparison.java b/test/hotspot/jtreg/compiler/lib/ir_framework/shared/Comparison.java new file mode 100644 index 0000000000000000000000000000000000000000..ff21c2c3259acb23d67d7bea879226ae0f02bd16 --- /dev/null +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/shared/Comparison.java @@ -0,0 +1,57 @@ +/* + * 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. + */ + +package compiler.lib.ir_framework.shared; + +import java.util.function.BiPredicate; +import java.util.function.Function; + +/** + * Comparison result of parsing a constraint with {@link ComparisonConstraintParser#parse(String, Function, String)}. + */ +public class Comparison<T extends Comparable<T>> { + private final T givenValue; // Right hand side + private final BiPredicate<T, T> comparisonPredicate; + private final String comparator; + + public Comparison(T givenValue, String comparator, BiPredicate<T, T> comparisonPredicate) { + this.givenValue = givenValue; + this.comparator = comparator; + this.comparisonPredicate = comparisonPredicate; + } + + public T getGivenValue() { + return givenValue; + } + + public String getComparator() { + return comparator; + } + + /** + * Comparison: foundValue OP givenValue + */ + public boolean compare(T foundValue) { + return comparisonPredicate.test(foundValue, givenValue); + } +} diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/shared/ComparisonConstraintParser.java b/test/hotspot/jtreg/compiler/lib/ir_framework/shared/ComparisonConstraintParser.java new file mode 100644 index 0000000000000000000000000000000000000000..4848a32859fc47e0e7f8f0d0fb88638c05541069 --- /dev/null +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/shared/ComparisonConstraintParser.java @@ -0,0 +1,150 @@ +/* + * 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. + */ + +package compiler.lib.ir_framework.shared; + +import java.util.function.BiPredicate; +import java.util.function.Function; + +/** + * Utility class to parse a comparator either in the applyIf* or in the counts properties of an @IR rules. + */ +public class ComparisonConstraintParser<T extends Comparable<T>> { + + private enum Comparator { + ONE_CHAR, TWO_CHARS + } + + public static <T extends Comparable<T>> Comparison<T> parse(String constraint, Function<String, T> parseFunction, + String postfixErrorMsg) { + try { + return parseConstraintAndValue(constraint, parseFunction); + } catch (EmptyConstraintException e) { + TestFormat.fail("Provided empty value " + postfixErrorMsg); + throw new UnreachableCodeException(); + } catch (MissingConstraintValueException e) { + TestFormat.fail("Provided empty value after comparator \"" + e.getComparator() + "\" " + postfixErrorMsg); + throw new UnreachableCodeException(); + } catch (InvalidComparatorException e) { + TestFormat.fail("Provided invalid comparator \"" + e.getComparator() + "\" " + postfixErrorMsg); + throw new UnreachableCodeException(); + } catch (InvalidConstraintValueException e) { + String comparator = e.getComparator(); + if (!comparator.isEmpty()) { + comparator = " after comparator \"" + comparator + "\""; + } + TestFormat.fail("Provided invalid value \"" + e.getInvalidValue() + "\"" + + comparator + " " + postfixErrorMsg); + throw new UnreachableCodeException(); + } + } + + private static <T extends Comparable<T>> Comparison<T> parseConstraintAndValue(String constraint, + Function<String, T> parseFunction) throws + EmptyConstraintException, MissingConstraintValueException, + InvalidComparatorException, InvalidConstraintValueException { + ParsedResult<T> result = parse(constraint); + T givenValue = parseGivenValue(parseFunction, result); + return new Comparison<>(givenValue, result.comparator, result.comparisonPredicate); + } + + private static <T extends Comparable<T>> ParsedResult<T> parse(String constraint) throws + EmptyConstraintException, MissingConstraintValueException, InvalidComparatorException { + constraint = constraint.trim(); + if (constraint.isEmpty()) { + throw new EmptyConstraintException(); + } + switch (constraint.charAt(0)) { + case '<' -> { + throwIfNoValueAfterComparator(constraint, Comparator.ONE_CHAR); + if (constraint.charAt(1) == '=') { + throwIfNoValueAfterComparator(constraint, Comparator.TWO_CHARS); + return new ParsedResult<>(constraint.substring(2).trim(), "<=", (x, y) -> x.compareTo(y) <= 0); + } else { + return new ParsedResult<>(constraint.substring(1).trim(), "<", (x, y) -> x.compareTo(y) < 0); + } + } + case '>' -> { + throwIfNoValueAfterComparator(constraint, Comparator.ONE_CHAR); + if (constraint.charAt(1) == '=') { + throwIfNoValueAfterComparator(constraint, Comparator.TWO_CHARS); + return new ParsedResult<>(constraint.substring(2).trim(), ">=", (x, y) -> x.compareTo(y) >= 0); + } else { + return new ParsedResult<>(constraint.substring(1).trim(), ">", (x, y) -> x.compareTo(y) > 0); + } + } + case '!' -> { + throwIfNoValueAfterComparator(constraint, Comparator.ONE_CHAR); + if (constraint.charAt(1) != '=') { + throw new InvalidComparatorException("!"); + } + throwIfNoValueAfterComparator(constraint, Comparator.TWO_CHARS); + return new ParsedResult<>(constraint.substring(2).trim(), "!=", (x, y) -> x.compareTo(y) != 0); + } + case '=' -> { // Allowed syntax, equivalent to not using any symbol. + throwIfNoValueAfterComparator(constraint, Comparator.ONE_CHAR); + return new ParsedResult<>(constraint.substring(1).trim(), "=", (x, y) -> x.compareTo(y) == 0); + } + default -> { + return new ParsedResult<>(constraint.trim(), "=", (x, y) -> x.compareTo(y) == 0); + } + } + } + + private static void throwIfNoValueAfterComparator(String constraint, Comparator comparator) throws MissingConstraintValueException { + switch (comparator) { + case ONE_CHAR -> { + if (constraint.length() == 1) { + throw new MissingConstraintValueException(constraint); + } + } + case TWO_CHARS -> { + if (constraint.length() == 2) { + throw new MissingConstraintValueException(constraint); + } + } + } + } + + private static <T extends Comparable<T>> T parseGivenValue(Function<String, T> parseFunction, ParsedResult<T> result) + throws InvalidConstraintValueException { + try { + return parseFunction.apply(result.value); + } + catch (NumberFormatException e) { + throw new InvalidConstraintValueException(result.value, result.comparator); + } + } + + static class ParsedResult<T> { + public String value; + public BiPredicate<T, T> comparisonPredicate; + public String comparator; + + public ParsedResult(String value, String comparator,BiPredicate<T, T> comparisonPredicate) { + this.value = value; + this.comparator = comparator; + this.comparisonPredicate = comparisonPredicate; + } + } +} diff --git a/src/utils/IdealGraphVisualizer/BatikSVGProxy/src/main/java/com/sun/hotspot/igv/svg/package-info.java b/test/hotspot/jtreg/compiler/lib/ir_framework/shared/EmptyConstraintException.java similarity index 76% rename from src/utils/IdealGraphVisualizer/BatikSVGProxy/src/main/java/com/sun/hotspot/igv/svg/package-info.java rename to test/hotspot/jtreg/compiler/lib/ir_framework/shared/EmptyConstraintException.java index 272fc48e96f03d735cc94bd5ab76205e5a2b7644..6dfd31819ee13fc4b6afdfd6bd61df00ccaa47ac 100644 --- a/src/utils/IdealGraphVisualizer/BatikSVGProxy/src/main/java/com/sun/hotspot/igv/svg/package-info.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/shared/EmptyConstraintException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -19,11 +19,12 @@ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. - * */ + +package compiler.lib.ir_framework.shared; + /** - * This package is used to proxy the SVG export functionality of the BatikSVG library. Reflection is used such that the - * library is optional and need not be present at build time. + * Exception thrown when {@link ComparisonConstraintParser} cannot find a constraint. */ -package com.sun.hotspot.igv.svg; - +class EmptyConstraintException extends Exception { +} diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/shared/InvalidComparatorException.java b/test/hotspot/jtreg/compiler/lib/ir_framework/shared/InvalidComparatorException.java new file mode 100644 index 0000000000000000000000000000000000000000..4ab550e8be899dadb5643b57b0582b939be07d42 --- /dev/null +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/shared/InvalidComparatorException.java @@ -0,0 +1,39 @@ +/* + * 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. + */ + +package compiler.lib.ir_framework.shared; + +/** + * Exception threw when {@link ComparisonConstraintParser} parses an invalid comparator. + */ +public class InvalidComparatorException extends Exception { + private final String comparator; + + public InvalidComparatorException(String comparator) { + this.comparator = comparator; + } + + public String getComparator() { + return comparator; + } +} diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/shared/InvalidConstraintValueException.java b/test/hotspot/jtreg/compiler/lib/ir_framework/shared/InvalidConstraintValueException.java new file mode 100644 index 0000000000000000000000000000000000000000..a415ebf404645148482c61f4c23fea0112a3d49c --- /dev/null +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/shared/InvalidConstraintValueException.java @@ -0,0 +1,45 @@ +/* + * 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. + */ + +package compiler.lib.ir_framework.shared; + +/** + * Exception thrown when {@link ComparisonConstraintParser} parses an invalid value. + */ +class InvalidConstraintValueException extends Exception { + private final String invalidValue; + private final String comparator; + + public InvalidConstraintValueException(String invalidValue, String comparator) { + this.invalidValue = invalidValue; + this.comparator = comparator; + } + + public String getInvalidValue() { + return invalidValue; + } + + public String getComparator() { + return comparator; + } +} diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/shared/MissingConstraintValueException.java b/test/hotspot/jtreg/compiler/lib/ir_framework/shared/MissingConstraintValueException.java new file mode 100644 index 0000000000000000000000000000000000000000..12230f9219c2e04b245ad4387e7555ae60fdfd73 --- /dev/null +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/shared/MissingConstraintValueException.java @@ -0,0 +1,39 @@ +/* + * 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. + */ + +package compiler.lib.ir_framework.shared; + +/** + * Exception thrown when {@link ComparisonConstraintParser} cannot find a value in a constraint after a comparator. + */ +class MissingConstraintValueException extends Exception { + private final String comparator; + + public MissingConstraintValueException(String comparator) { + this.comparator = comparator; + } + + public String getComparator() { + return comparator; + } +} diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/shared/ParsedComparator.java b/test/hotspot/jtreg/compiler/lib/ir_framework/shared/ParsedComparator.java deleted file mode 100644 index 9d574bc50a4ac26f60aac91a34cab7aa78260cef..0000000000000000000000000000000000000000 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/shared/ParsedComparator.java +++ /dev/null @@ -1,104 +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. - */ - -package compiler.lib.ir_framework.shared; - -import java.util.function.BiPredicate; - -/** - * Utility class to parse a comparator either in the applyIf* or in the counts properties of an @IR rules. - */ -public class ParsedComparator<T extends Comparable<T>> { - private final String strippedString; - private final BiPredicate<T, T> predicate; - private final String comparator; - - public ParsedComparator(String strippedString, BiPredicate<T, T> predicate, String comparator) { - this.strippedString = strippedString; - this.predicate = predicate; - this.comparator = comparator; - } - - public String getStrippedString() { - return strippedString; - } - - public BiPredicate<T, T> getPredicate() { - return predicate; - } - - public String getComparator() { - return comparator; - } - - /** - * Return parsed comparator object which provides the predicate to perform the test. - * Allowed comparators: <, <=, >, =>, =, != - */ - public static <T extends Comparable<T>> ParsedComparator<T> parseComparator(String value) throws CheckedTestFrameworkException { - BiPredicate<T, T> comparison; - value = value.trim(); - String comparator = ""; - switch (value.charAt(0)) { - case '<': - if (value.charAt(1) == '=') { - comparator = "<="; - comparison = (x, y) -> x.compareTo(y) <= 0; - value = value.substring(2).trim(); - } else { - comparator = "<"; - comparison = (x, y) -> x.compareTo(y) < 0; - value = value.substring(1).trim(); - } - break; - case '>': - if (value.charAt(1) == '=') { - comparator = ">="; - comparison = (x, y) -> x.compareTo(y) >= 0; - value = value.substring(2).trim(); - } else { - comparator = ">"; - comparison = (x, y) -> x.compareTo(y) > 0; - value = value.substring(1).trim(); - } - break; - case '!': - if (value.charAt(1) != '=') { - throw new CheckedTestFrameworkException(value.substring(0, 1)); - } - comparator = "!="; - comparison = (x, y) -> x.compareTo(y) != 0; - value = value.substring(2).trim(); - break; - case '=': // Allowed syntax, equivalent to not using any symbol. - comparator = "="; - value = value.substring(1).trim(); - // Fall through - default: - comparison = (x, y) -> x.compareTo(y) == 0; - value = value.trim(); - break; - } - return new ParsedComparator<>(value, comparison, comparator); - } -} diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/shared/TestFormat.java b/test/hotspot/jtreg/compiler/lib/ir_framework/shared/TestFormat.java index 624753fee2faac5c41dc3c434e2be87932f79331..d7a93228a6b74e8e0e72edbfd0532fe23013275b 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/shared/TestFormat.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/shared/TestFormat.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -53,7 +53,7 @@ public class TestFormat { FAILURES.add(failureMessage); } - public static void reportIfAnyFailures() { + public static void throwIfAnyFailures() { if (FAILURES.isEmpty()) { // No format violation detected. return; diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/shared/UnreachableCodeException.java b/test/hotspot/jtreg/compiler/lib/ir_framework/shared/UnreachableCodeException.java new file mode 100644 index 0000000000000000000000000000000000000000..274b05dd32357aee8924b0f83938fdf477168338 --- /dev/null +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/shared/UnreachableCodeException.java @@ -0,0 +1,36 @@ +/* + * 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. + */ + +package compiler.lib.ir_framework.shared; + +/** + * The error reporting of the IR framework is throwing exceptions unconditionally in separate methods. The calling methods, + * however, do not see these exceptions. As a result, Java and/or some IDEs could complain about impossible states + * (e.g. uninitialized variables, null pointer dereferences etc. even though an exception will be thrown earlier). + * To avoid that, throw an instance of this class instead. + */ +class UnreachableCodeException extends RuntimeException { + public UnreachableCodeException() { + super("Unreachable code"); + } +} 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 dc3a2d304eb3f7588554a80cc84c8224264dfe5b..5f7438a36daa2e600c0453f3b504e1582a3d4968 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/test/IREncodingPrinter.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/test/IREncodingPrinter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -37,7 +37,7 @@ import java.util.function.Function; /** * Prints an encoding to the dedicated test framework socket whether @IR rules of @Test methods should be applied or not. * This is done during the execution of the test VM by checking the active VM flags. This encoding is eventually parsed - * and checked by the IRMatcher class in the driver VM after the termination of the test VM. + * and checked by the IRMatcher class in the driver VM after the termination of the test VM. IR rule indices start at 1. */ public class IREncodingPrinter { public static final String START = "##### IRMatchRulesEncoding - used by TestFramework #####"; @@ -73,7 +73,7 @@ public class IREncodingPrinter { ruleIndex = i + 1; try { if (shouldApplyIrRule(irAnno)) { - validRules.add(i); + validRules.add(ruleIndex); } } catch (TestFormatException e) { // Catch logged failure and continue to check other IR annotations. @@ -206,11 +206,11 @@ public class IREncodingPrinter { } actualFlagValue = LONG_GETTERS.stream().map(f -> f.apply(flag)).filter(Objects::nonNull).findAny().orElse(null); if (actualFlagValue != null) { - return checkLongFlag(flag, value, (Long) actualFlagValue); + return checkFlag(Long::parseLong, "integer", flag, value, (Long) actualFlagValue); } actualFlagValue = WHITE_BOX.getDoubleVMFlag(flag); if (actualFlagValue != null) { - return checkDoubleFlag(flag, value, (Double) actualFlagValue); + return checkFlag(Double::parseDouble, "floating point", flag, value, (Double) actualFlagValue); } actualFlagValue = WHITE_BOX.getStringVMFlag(flag); if (actualFlagValue != null) { @@ -242,60 +242,20 @@ public class IREncodingPrinter { return booleanValue == actualFlagValue; } - private boolean checkLongFlag(String flag, String value, long actualFlagValue) { - long longValue; - ParsedComparator<Long> parsedComparator; + private <T extends Comparable<T>> boolean checkFlag(Function<String, T> parseFunction, String kind, String flag, + String value, T actualFlagValue) { try { - parsedComparator = ParsedComparator.parseComparator(value); - } catch (CheckedTestFrameworkException e) { - TestFormat.failNoThrow("Invalid comparator in \"" + value + "\" for integer based flag " + flag + failAt()); - return false; - } catch (IndexOutOfBoundsException e) { - TestFormat.failNoThrow("Provided empty value for integer based flag " + flag + failAt()); - return false; - } - try { - longValue = Long.parseLong(parsedComparator.getStrippedString()); - } catch (NumberFormatException e) { - String comparator = parsedComparator.getComparator(); - if (!comparator.isEmpty()) { - comparator = "after comparator \"" + parsedComparator.getComparator() + "\""; - } - TestFormat.failNoThrow("Invalid value \"" + parsedComparator.getStrippedString() + "\" " - + comparator + " for integer based flag " + flag + failAt()); - return false; - } - return parsedComparator.getPredicate().test(actualFlagValue, longValue); - } - - private boolean checkDoubleFlag(String flag, String value, double actualFlagValue) { - double doubleValue; - ParsedComparator<Double> parsedComparator; - try { - parsedComparator = ParsedComparator.parseComparator(value); - } catch (CheckedTestFrameworkException e) { - TestFormat.failNoThrow("Invalid comparator in \"" + value + "\" for floating point based flag " + flag + failAt()); - return false; - } catch (IndexOutOfBoundsException e) { - TestFormat.failNoThrow("Provided empty value for floating point based flag " + flag + failAt()); - return false; - } - try { - doubleValue = Double.parseDouble(parsedComparator.getStrippedString()); - } catch (NumberFormatException e) { - String comparator = parsedComparator.getComparator(); - if (!comparator.isEmpty()) { - comparator = "after comparator \"" + parsedComparator.getComparator() + "\""; - } - TestFormat.failNoThrow("Invalid value \"" + parsedComparator.getStrippedString() + "\" " - + comparator + " for floating point based flag " + flag + failAt()); + String postFixErrorMsg = "for " + kind + " based flag \"" + flag + "\"" + failAt(); + Comparison<T> comparison = ComparisonConstraintParser.parse(value, parseFunction, postFixErrorMsg); + return comparison.compare(actualFlagValue); + } catch (TestFormatException e) { + // Format exception, do not apply rule. return false; } - return parsedComparator.getPredicate().test(actualFlagValue, doubleValue); } private String failAt() { - return " for @IR rule " + ruleIndex + " at " + method; + return " in @IR rule " + ruleIndex + " at " + method; } public void emit() { diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/test/TestVM.java b/test/hotspot/jtreg/compiler/lib/ir_framework/test/TestVM.java index 0ed89a1f633730a42343b72de34eb3369c33ef12..6a35b27cd44051b364057015347d52d8e9e37557 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/test/TestVM.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/test/TestVM.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -267,7 +267,7 @@ public class TestVM { if (PRINT_VALID_IR_RULES) { irMatchRulePrinter.emit(); } - TestFormat.reportIfAnyFailures(); + TestFormat.throwIfAnyFailures(); declaredTests.clear(); testMethodMap.clear(); } diff --git a/test/hotspot/jtreg/compiler/longcountedloops/TestIVPhiTypeIncorrectAfterCCP.java b/test/hotspot/jtreg/compiler/longcountedloops/TestIVPhiTypeIncorrectAfterCCP.java new file mode 100644 index 0000000000000000000000000000000000000000..0c22c12f06f6cf29c0441c787c863f974eddeba8 --- /dev/null +++ b/test/hotspot/jtreg/compiler/longcountedloops/TestIVPhiTypeIncorrectAfterCCP.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 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. + */ + +/** + * @test + * @bug 8277906 + * @summary Incorrect type for IV phi of long counted loops after CCP + * + * @run main/othervm -XX:-TieredCompilation -XX:CompileCommand=compileonly,TestIVPhiTypeIncorrectAfterCCP::test -XX:-BackgroundCompilation TestIVPhiTypeIncorrectAfterCCP + * + */ + +public class TestIVPhiTypeIncorrectAfterCCP { + + static int test() { + int array[] = new int[50]; + + float f = 0; + for (int i = 3; i < 49; i++) { + for (long l = 1; l < i; l++) { + array[(int)l] = i; + f += l; + } + } + int sum = 0; + for (int i = 0; i < array.length; i++) { + sum += array[i]; + } + return sum; + } + + public static void main(String[] args) { + long expected = test(); + for (int i = 0; i < 10_000; i++) { + int res = test(); + if (res != expected) { + throw new RuntimeException("Unexpected result: " + res + " != " + expected); + } + } + } +} diff --git a/test/hotspot/jtreg/compiler/loopopts/FillArrayWithUnsafe.java b/test/hotspot/jtreg/compiler/loopopts/FillArrayWithUnsafe.java new file mode 100644 index 0000000000000000000000000000000000000000..6e3b840987ae2d674d73608f45e423bb2363bf5e --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopopts/FillArrayWithUnsafe.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2022, 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. + */ + +/** + * @test + * @bug 8283408 + * @summary Fill a byte array with Java Unsafe API + * @run main/othervm -XX:+OptimizeFill compiler.loopopts.FillArrayWithUnsafe + */ + +package compiler.loopopts; + +import java.lang.reflect.Field; + +import sun.misc.Unsafe; + +public class FillArrayWithUnsafe { + + private static Unsafe unsafe; + + public static void main(String[] args) throws Exception { + Class klass = Unsafe.class; + Field field = klass.getDeclaredField("theUnsafe"); + field.setAccessible(true); + unsafe = (Unsafe) field.get(null); + + byte[] buffer; + // Make sure method newByteArray is compiled by C2 + for (int i = 0; i < 50000; i++) { + buffer = newByteArray(100, (byte) 0x80); + } + } + + public static byte[] newByteArray(int size, byte val) { + byte[] arr = new byte[size]; + int offset = unsafe.arrayBaseOffset(byte[].class); + for (int i = offset; i < offset + size; i++) { + unsafe.putByte(arr, i, val); + } + return arr; + } +} + diff --git a/test/hotspot/jtreg/compiler/loopopts/TestCastIIMakesMainLoopPhiDead.java b/test/hotspot/jtreg/compiler/loopopts/TestCastIIMakesMainLoopPhiDead.java new file mode 100644 index 0000000000000000000000000000000000000000..3c40761a77d4cab1d61a9059e90857bfac289da6 --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopopts/TestCastIIMakesMainLoopPhiDead.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 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. + */ + +/* + * @test + * bug 8280600 + * @summary C2: assert(!had_error) failed: bad dominance + * @run main/othervm -Xcomp -XX:CompileOnly=TestCastIIMakesMainLoopPhiDead TestCastIIMakesMainLoopPhiDead + */ + +public class TestCastIIMakesMainLoopPhiDead { + int iArr[] = new int[0]; + + void test() { + int x = 8; + try { + for (int i = 0; i < 8; i++) { + iArr[1] = 9; + for (int j = -400; 1 > j; j++) { + iArr[j] = 4; + x -= 2; + } + } + } catch (ArrayIndexOutOfBoundsException e) { + } + } + public static void main(String[] k) { + TestCastIIMakesMainLoopPhiDead t = new TestCastIIMakesMainLoopPhiDead(); + for (int i = 0; i < 3; i++) { + t.test(); + } + } +} diff --git a/test/hotspot/jtreg/compiler/loopopts/TestCastIIMakesMainLoopPhiDead2.java b/test/hotspot/jtreg/compiler/loopopts/TestCastIIMakesMainLoopPhiDead2.java new file mode 100644 index 0000000000000000000000000000000000000000..1aa233abe5f651212eb8eff69c8dc458fb06f683 --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopopts/TestCastIIMakesMainLoopPhiDead2.java @@ -0,0 +1,54 @@ +/* + * 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. + */ + +/* + * @test + * bug 8280600 + * @summary C2: assert(!had_error) failed: bad dominance + * @run main/othervm -Xcomp -XX:CompileOnly=TestCastIIMakesMainLoopPhiDead2 TestCastIIMakesMainLoopPhiDead2 + */ + +public class TestCastIIMakesMainLoopPhiDead2 { + static int zero = 0; + + public static void main(String[] args) { + for (int i = 0; i < 100000; i++) { + test(); + } + } + + static void test() { + int h[] = new int[zero]; + for (int m = 0; m < 5; m++) { + try { + for (int f = -400; f < 1; f++) { + h[f] = 1; // Out of bounds store. + } + } catch (ArrayIndexOutOfBoundsException i) { + // Expected + } + } + } +} + + diff --git a/test/hotspot/jtreg/compiler/loopopts/TestDeadPostLoopBecausePredicate.java b/test/hotspot/jtreg/compiler/loopopts/TestDeadPostLoopBecausePredicate.java new file mode 100644 index 0000000000000000000000000000000000000000..719de54204f2c8eba27f73fa6ee03ec3bf358787 --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopopts/TestDeadPostLoopBecausePredicate.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 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. + */ + +/** + * @test + * @bug 8275330 + * @summary C2: assert(n->is_Root() || n->is_Region() || n->is_Phi() || n->is_MachMerge() || def_block->dominates(block)) failed: uses must be dominated by definitions + * + * @run main/othervm -Xmx512m -XX:+UnlockDiagnosticVMOptions -Xcomp -XX:CompileOnly=TestDeadPostLoopBecausePredicate TestDeadPostLoopBecausePredicate + * + */ + + +public class TestDeadPostLoopBecausePredicate { + + public static final int N = 400; + + public static int iFld=54270; + public static int iFld1=-4; + public int iFld2=201; + + public int mainTest(String[] strArr1) { + + int i=0, i17=8052, i19=22380, i20=60894, iArr[]=new int[N]; + init(iArr, 4); + + i = 1; + do { + for (i17 = 5; i17 < 114; i17++) { + switch ((i17 % 7) + 126) { + case 126: + for (i19 = 2; i19 > i; i19 -= 3) { + try { + i20 = (iFld2 % TestDeadPostLoopBecausePredicate.iFld1); + i20 = (iArr[i19 - 1] % TestDeadPostLoopBecausePredicate.iFld); + TestDeadPostLoopBecausePredicate.iFld = (TestDeadPostLoopBecausePredicate.iFld1 % iArr[i19]); + } catch (ArithmeticException a_e) {} + } + break; + } + } + } while (++i < 220); + + return i20; + } + + public static void init(int[] a, int seed) { + for (int j = 0; j < a.length; j++) { + a[j] = (j % 2 == 0) ? seed + j : seed - j; + } + } + + public static void main(String[] strArr) { + TestDeadPostLoopBecausePredicate _instance = new TestDeadPostLoopBecausePredicate(); + for (int i = 0; i < 10; i++ ) { + _instance.mainTest(strArr); + } + } +} diff --git a/test/hotspot/jtreg/compiler/loopopts/TestDepBetweenLoopAndPredicate.java b/test/hotspot/jtreg/compiler/loopopts/TestDepBetweenLoopAndPredicate.java new file mode 100644 index 0000000000000000000000000000000000000000..674ae02f239d035c0c9419d3491c5993d9c73236 --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopopts/TestDepBetweenLoopAndPredicate.java @@ -0,0 +1,134 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8277529 + * @summary RangeCheck should not be moved out of a loop if a node on the data input chain for the bool is dependent + * on the projection into the loop (after the predicates). + * @run main/othervm -Xbatch -XX:CompileCommand=compileonly,compiler.loopopts.TestDepBetweenLoopAndPredicate::test* + * compiler.loopopts.TestDepBetweenLoopAndPredicate + */ + +package compiler.loopopts; + +public class TestDepBetweenLoopAndPredicate { + static int x, y, z; + static boolean flag; + static int[] iArrFld = new int[25]; + static int[] iArrFld2 = new int[5]; + static int limit = 5; + + public static void main(String[] args) { + for (int i = 0; i < 10000; i++) { + flag = !flag; + test(); + } + + for (int i = 0; i < 5000; i++) { + flag = !flag; + test2(); + test3(); + test4(); + test5(); + } + } + + public static void test() { + int[] iArr = new int[20]; + System.arraycopy(iArrFld, x, iArr, y, 18); + + if (flag) { + return; + } + + for (int i = 0; i < limit; i++) { + iArr[19]++; + } + } + + public static void test2() { + for (int i = 0; i < limit; i++) { + int[] iArr = new int[20]; + System.arraycopy(iArrFld, x, iArr, y, 18); + + if (flag) { + return; + } + + for (int j = i; j < limit; j++) { + x = iArrFld[iArr[19]]; // No new offset node created + iArr[19]++; + } + } + } + + public static void test3() { + for (int i = 0; i < limit; i++) { + int[] iArr = new int[20]; + System.arraycopy(iArrFld, x, iArr, y, 18); + + if (flag) { + return; + } + + for (int j = i + 1; j < limit; j++) { + x = iArrFld[iArr[19]]; // New offset node created + iArr[19]++; + } + } + } + + public static void test4() { + for (int i = 0; i < limit; i++) { + int[] iArr = new int[20]; + System.arraycopy(iArrFld, x, iArr, y, 18); + + if (flag) { + return; + } + + for (int j = i + 1 + z; j < limit; j++) { + x = iArrFld[iArr[19]]; // New offset node created + iArr[19]++; + } + } + } + + public static void test5() { + for (int i = 0; i < limit; i++) { + int[] iArr = new int[20]; + System.arraycopy(iArrFld, x, iArr, y, 18); + + if (flag) { + return; + } + + for (int j = i + 1 + z; j < limit; j++) { + x = iArrFld[iArr[19]]; // New offset node created + iArr[19]++; + y += iArrFld2[3]; // Range check removed because not dependent on projection into the loop + } + } + } +} diff --git a/test/hotspot/jtreg/compiler/loopopts/TestEliminateNullCheckWithSplitIf.java b/test/hotspot/jtreg/compiler/loopopts/TestEliminateNullCheckWithSplitIf.java new file mode 100644 index 0000000000000000000000000000000000000000..e83b23255b396f0d3b7538462a0a42f86b1e0e0b --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopopts/TestEliminateNullCheckWithSplitIf.java @@ -0,0 +1,102 @@ +/* + * 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. + * + */ + +/* + * @test + * @key stress randomness + * @bug 8275610 + * @summary Null check for field access of object floats above null check resulting in a segfault. + * @requires vm.compiler2.enabled + * @run main/othervm -Xbatch -XX:CompileCommand=compileonly,compiler.loopopts.TestEliminateNullCheckWithSplitIf::test + * -XX:+UnlockDiagnosticVMOptions -XX:+StressGCM -XX:StressSeed=42 compiler.loopopts.TestEliminateNullCheckWithSplitIf + * @run main/othervm -Xbatch -XX:CompileCommand=compileonly,compiler.loopopts.TestEliminateNullCheckWithSplitIf::test + * -XX:+UnlockDiagnosticVMOptions -XX:+StressGCM -XX:+StressIGVN compiler.loopopts.TestEliminateNullCheckWithSplitIf + */ + +package compiler.loopopts; + +public class TestEliminateNullCheckWithSplitIf { + public static int[] iArrFld = new int[20]; + public static int[] iArrFld2 = new int[20]; + public static int iFld = 10; + public static MyClass obj; + + public static void main(String[] strArr) { + for (int i = 0; i < 10000; i++) { + obj = (i % 100 == 0 ? null : new MyClass()); + test(); + } + } + + // The field access obj.iFld requires a null check NC3 and adds a not-null CastPP node on the succeeded projection. + // In the first IGVN after parsing, the null check NC3 can be subsumed by the explicit null check NC2. + // (done in IfNode::simple_subsuming()). The Bool node of NC2 is also shared with the same null check NC1 earlier. + // However, C2 cannot remove the null check NC2, yet, because the IR in between the two checks are too complex + // (IfNode::search_identical() fails). + // Now, loopopts are applied: + // (1) First, the split if optimization is done. It recognizes that NC1 and NC2 are back to back null checks and removes + // the null check NC2 by splitting it through the region R which is removed afterwards. In this process, control dependent + // data nodes on the out projections of NC2 end up at the new regions R1/R2 created for each projection for R. They get + // the last nodes of the if and else block as input. For this example, R1 is a control input to the CastPP node which + // will merge both true projections. + // (2) Later in loop opts, the loop L is transformed into normal code and y will become a constant 1. + // After loopopts, another round of IGVN is done: + // (These steps also depend on the order in which they are applied in order to trigger the bug) + // (1) The region R is removed because one path is dead (a result of the split if optimization). + // (2) The new If node added by the above split if optimization is also folded. This rewires the CastPP node to + // the last control node in the If block which is the true projection of range check RC2. Up until now, the CastPP + // is still after the null check NC1. + // (3) The range check RC2 is removed because the range check RC1 already covers this range (see RangeCheck::Ideal()). + // All data nodes which are control dependent on RC2 will be rewired to the dominating range check RC1, including + // the non-null CastPP node - which now has a control input above the null check NC1. This also means that the field + // load obj.iFld now has the same early control as the CastPP (CastPP -> AddP -> LoadI). Using StressGCM can + // now schedule the obj.iFld load before the null check NC1 because the early control allows it which leads to a + // segmentation fault if obj is null. + public static void test() { + int x = iArrFld[17]; // Emits range check RC1 + if (obj != null) { // Null check NC1 + int y = 0; + for (int i = 0; i < 1; i++) { // Loop L + y++; + } + // Use additional loop to keep the rangecheck for iArrFld[y] in before loopopts. + // y will become constant 1 but only once the loop above is removed in loopopts. + x = iArrFld[y]; // Emits range check RC2 + } else { + x = iArrFld2[18]; + } + // Region R merging the if and else paths above. + if (obj != null) { // Null check NC2 + x = iArrFld2[obj.iFld]; // Emits Null check NC3 for obj.iFld + } + } +} + +class MyClass { + int iFld; +} + + + + diff --git a/test/hotspot/jtreg/compiler/loopopts/TestIterationSplitWithRegionHead.java b/test/hotspot/jtreg/compiler/loopopts/TestIterationSplitWithRegionHead.java new file mode 100644 index 0000000000000000000000000000000000000000..7a29be60908949a710222cd7f3c635c6e5ed7346 --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopopts/TestIterationSplitWithRegionHead.java @@ -0,0 +1,82 @@ +/* + * 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. + */ + +/* + * @test + * @requires vm.compiler2.enabled + * @bug 8279837 + * @summary Tests infinite loop with region head in iteration split. + * @run main/othervm -Xcomp -XX:-TieredCompilation + * -XX:CompileCommand=compileonly,compiler.loopopts.TestIterationSplitWithRegionHead::test + * -XX:CompileCommand=dontinline,compiler.loopopts.TestIterationSplitWithRegionHead::* + * compiler.loopopts.TestIterationSplitWithRegionHead + */ + +package compiler.loopopts; + +public class TestIterationSplitWithRegionHead { + + static boolean flagFalse = false; + + public static void main(String[] args) { + test(); + } + + public static void test() { + // 1) The loop tree is built. We find that nested loop N2 is an infinite loop and add a NeverBranch + // to the inner loop to make it reachable. But the current loop tree does not have N2, yet. The + // resulting loop tree is: + // + // Loop: N0/N0 has_call has_sfpt + // Loop: N77/N121 has_call // N1 outer + // Loop: N77/N111 has_call sfpts={ 111 97 } // N1 inner + // + // 2) beautify_loops() finds that the outer loop head of N1 is shared and thus adds a new region + // in merge_many_backedges(). As a result, the loop tree is built again. This time, the NeverBranch + // in the inner loop of N2 allows that a loop tree can be built for it: + // + // Loop: N0/N0 has_call has_sfpt + // Loop: N216/N213 limit_check profile_predicated predicated has_call sfpts={ 111 97 } // N1 shared loop head + // Loop: N196/N201 sfpts={ 201 } // N2 inner loop now discovered with the new NeverBranch + // + // However, a LoopNode is only added by beautify_loops() which won't be called until the next iteration of loop opts. + // This means that we have a Region node (N196) as head in the loop tree which cannot be handled by iteration_split_impl() + // resulting in an assertion failure. + + // Nested loop N1 + while (flagFalse) { + while (dontInlineFalse()) { + } + } + dontInlineFalse(); + + // Nested loop N2 + while (flagFalse) { + while (true) ; // Detected as infinite inner loop by C2 -> NeverBranch added + } + } + + public static boolean dontInlineFalse() { + return false; + } +} diff --git a/test/hotspot/jtreg/compiler/loopopts/TestPredicateInputBelowLoopPredicate.java b/test/hotspot/jtreg/compiler/loopopts/TestPredicateInputBelowLoopPredicate.java new file mode 100644 index 0000000000000000000000000000000000000000..8ffa476ff26c6c798661ed2711f0338b922e587e --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopopts/TestPredicateInputBelowLoopPredicate.java @@ -0,0 +1,268 @@ +/* + * Copyright (c) 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. + */ + +/* + * @test + * bug 8280799 + * @summary С2: assert(false) failed: cyclic dependency prevents range check elimination + * @run main/othervm -XX:-BackgroundCompilation -XX:-UseCountedLoopSafepoints TestPredicateInputBelowLoopPredicate + */ + +public class TestPredicateInputBelowLoopPredicate { + private static final Object object = new Object(); + private static int fieldStop = 100; + private static int[] array = new int[200]; + private static int[] array2 = new int[200]; + private static int fieldStart = 0; + + public static void main(String[] args) { + for (int i = 0; i < 20_000; i++) { + test(true); + test(false); + } + } + + private static void test(boolean flag) { + if (array == null) { + } + int start = fieldStart; + int i = start; + for(;;) { + int j; + for (j = -10; j < 0; j++) { + } + int stop = fieldStop; + // bound check becomes candidate for predication once + // loop above is optimized out + array[stop - i + j] = 0; + + // A bunch of stuff to grow loop body size and prevent peeling: + array2[0] = 0; + array2[1] = 0; + array2[2] = 0; + array2[3] = 0; + array2[4] = 0; + array2[5] = 0; + array2[6] = 0; + array2[7] = 0; + array2[8] = 0; + array2[9] = 0; + array2[10] = 0; + array2[11] = 0; + array2[12] = 0; + array2[13] = 0; + array2[14] = 0; + array2[15] = 0; + array2[16] = 0; + array2[17] = 0; + array2[18] = 0; + array2[19] = 0; + array2[20] = 0; + array2[21] = 0; + array2[22] = 0; + array2[23] = 0; + array2[24] = 0; + array2[25] = 0; + array2[26] = 0; + array2[27] = 0; + array2[28] = 0; + array2[29] = 0; + array2[30] = 0; + array2[31] = 0; + array2[32] = 0; + array2[33] = 0; + array2[34] = 0; + array2[35] = 0; + array2[36] = 0; + array2[37] = 0; + array2[38] = 0; + array2[39] = 0; + array2[40] = 0; + array2[41] = 0; + array2[42] = 0; + array2[43] = 0; + array2[44] = 0; + array2[45] = 0; + array2[46] = 0; + array2[47] = 0; + array2[48] = 0; + array2[49] = 0; + array2[50] = 0; + array2[51] = 0; + array2[52] = 0; + array2[53] = 0; + array2[54] = 0; + array2[55] = 0; + array2[56] = 0; + array2[57] = 0; + array2[58] = 0; + array2[59] = 0; + array2[60] = 0; + array2[61] = 0; + array2[62] = 0; + array2[63] = 0; + array2[64] = 0; + array2[65] = 0; + array2[66] = 0; + array2[67] = 0; + array2[68] = 0; + array2[69] = 0; + array2[70] = 0; + array2[71] = 0; + array2[72] = 0; + array2[73] = 0; + array2[74] = 0; + array2[75] = 0; + array2[76] = 0; + array2[77] = 0; + array2[78] = 0; + array2[79] = 0; + array2[80] = 0; + array2[81] = 0; + array2[82] = 0; + array2[83] = 0; + array2[84] = 0; + array2[85] = 0; + array2[86] = 0; + array2[87] = 0; + array2[88] = 0; + array2[89] = 0; + array2[90] = 0; + array2[91] = 0; + array2[92] = 0; + array2[93] = 0; + array2[94] = 0; + array2[95] = 0; + array2[96] = 0; + array2[97] = 0; + array2[98] = 0; + array2[99] = 0; + + array2[100] = 0; + array2[101] = 0; + array2[102] = 0; + array2[103] = 0; + array2[104] = 0; + array2[105] = 0; + array2[106] = 0; + array2[107] = 0; + array2[108] = 0; + array2[109] = 0; + array2[110] = 0; + array2[111] = 0; + array2[112] = 0; + array2[113] = 0; + array2[114] = 0; + array2[115] = 0; + array2[116] = 0; + array2[117] = 0; + array2[118] = 0; + array2[119] = 0; + array2[120] = 0; + array2[121] = 0; + array2[122] = 0; + array2[123] = 0; + array2[124] = 0; + array2[125] = 0; + array2[126] = 0; + array2[127] = 0; + array2[128] = 0; + array2[129] = 0; + array2[130] = 0; + array2[131] = 0; + array2[132] = 0; + array2[133] = 0; + array2[134] = 0; + array2[135] = 0; + array2[136] = 0; + array2[137] = 0; + array2[138] = 0; + array2[139] = 0; + array2[140] = 0; + array2[141] = 0; + array2[142] = 0; + array2[143] = 0; + array2[144] = 0; + array2[145] = 0; + array2[146] = 0; + array2[147] = 0; + array2[148] = 0; + array2[149] = 0; + array2[150] = 0; + array2[151] = 0; + array2[152] = 0; + array2[153] = 0; + array2[154] = 0; + array2[155] = 0; + array2[156] = 0; + array2[157] = 0; + array2[158] = 0; + array2[159] = 0; + array2[160] = 0; + array2[161] = 0; + array2[162] = 0; + array2[163] = 0; + array2[164] = 0; + array2[165] = 0; + array2[166] = 0; + array2[167] = 0; + array2[168] = 0; + array2[169] = 0; + array2[170] = 0; + array2[171] = 0; + array2[172] = 0; + array2[173] = 0; + array2[174] = 0; + array2[175] = 0; + array2[176] = 0; + array2[177] = 0; + array2[178] = 0; + array2[179] = 0; + array2[180] = 0; + array2[181] = 0; + array2[182] = 0; + array2[183] = 0; + array2[184] = 0; + array2[185] = 0; + array2[186] = 0; + array2[187] = 0; + array2[188] = 0; + array2[189] = 0; + array2[190] = 0; + array2[191] = 0; + array2[192] = 0; + array2[193] = 0; + array2[194] = 0; + array2[195] = 0; + array2[196] = 0; + array2[197] = 0; + array2[198] = 0; + array2[199] = 0; + i++; + + if (i == stop) { // requires a loop limit predicate + break; + } + } + } +} diff --git a/test/hotspot/jtreg/compiler/loopopts/TestSkeletonPredicateNegation.java b/test/hotspot/jtreg/compiler/loopopts/TestSkeletonPredicateNegation.java index cbb82a07ea0ed8229b8938a2963c346b23835ad0..759503005840b306d23d7ff2875952f206808416 100644 --- a/test/hotspot/jtreg/compiler/loopopts/TestSkeletonPredicateNegation.java +++ b/test/hotspot/jtreg/compiler/loopopts/TestSkeletonPredicateNegation.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -49,11 +49,11 @@ public class TestSkeletonPredicateNegation { } public void mainTest (String[] args){ - long loa11[] = new long[1987]; + long loa11[] = new long[19]; for (long lo14 : loa11) { TestSkeletonPredicateNegation.in0 = -128; - for (int i18 = 0; i18 < 52; i18++) { + for (int i18 = 0; i18 < 13; i18++) { try { loa11[TestSkeletonPredicateNegation.in0] %= 2275269548L; Math.ceil(1374905370.2785515599); diff --git a/test/hotspot/jtreg/compiler/onSpinWait/TestOnSpinWaitAArch64.java b/test/hotspot/jtreg/compiler/onSpinWait/TestOnSpinWaitAArch64.java index 4a66246abe76c6e537ca6f424b501cdac192eca3..86f2d55e19fd6da4ada281185a1c51f145a42818 100644 --- a/test/hotspot/jtreg/compiler/onSpinWait/TestOnSpinWaitAArch64.java +++ b/test/hotspot/jtreg/compiler/onSpinWait/TestOnSpinWaitAArch64.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Amazon.com Inc. 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 diff --git a/test/hotspot/jtreg/compiler/onSpinWait/TestOnSpinWaitAArch64DefaultFlags.java b/test/hotspot/jtreg/compiler/onSpinWait/TestOnSpinWaitAArch64DefaultFlags.java new file mode 100644 index 0000000000000000000000000000000000000000..b6da173dda9d59cfe61ad818cf1086dc44f9d835 --- /dev/null +++ b/test/hotspot/jtreg/compiler/onSpinWait/TestOnSpinWaitAArch64DefaultFlags.java @@ -0,0 +1,98 @@ +/* + * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test TestOnSpinWaitAArch64DefaultFlags + * @summary Check default values of '-XX:OnSpinWaitInst' and '-XX:OnSpinWaitInstCount' for AArch64 implementations. + * @bug 8277137 + * @library /test/lib / + * + * @requires os.arch=="aarch64" + * + * @build sun.hotspot.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI + * compiler.onSpinWait.TestOnSpinWaitAArch64DefaultFlags + */ + +package compiler.onSpinWait; + +import java.util.Iterator; +import java.util.List; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; +import sun.hotspot.cpuinfo.CPUInfo; + +public class TestOnSpinWaitAArch64DefaultFlags { + private static boolean isCPUModelNeoverseN1(String cpuModel) { + return cpuModel.contains("0xd0c"); + } + + private static void checkFinalFlagsEqualTo(ProcessBuilder pb, String expectedOnSpinWaitInstValue, String expectedOnSpinWaitInstCountValue) throws Exception { + OutputAnalyzer analyzer = new OutputAnalyzer(pb.start()); + analyzer.shouldHaveExitValue(0); + + Iterator<String> iter = analyzer.asLines().listIterator(); + String line = null; + boolean hasExpectedOnSpinWaitInstValue = false; + boolean hasExpectedOnSpinWaitInstCountValue = false; + while (iter.hasNext()) { + line = iter.next(); + if (!hasExpectedOnSpinWaitInstValue && line.contains("ccstr OnSpinWaitInst")) { + hasExpectedOnSpinWaitInstValue = line.contains("= " + expectedOnSpinWaitInstValue); + } + + if (!hasExpectedOnSpinWaitInstCountValue && line.contains("uint OnSpinWaitInstCount")) { + hasExpectedOnSpinWaitInstCountValue = line.contains("= " + expectedOnSpinWaitInstCountValue); + } + } + if (!hasExpectedOnSpinWaitInstValue) { + System.out.println(analyzer.getOutput()); + throw new RuntimeException("OnSpinWaitInst with the expected value '" + expectedOnSpinWaitInstValue + "' not found."); + } + if (!hasExpectedOnSpinWaitInstCountValue) { + System.out.println(analyzer.getOutput()); + throw new RuntimeException("OnSpinWaitInstCount with the expected value '" + expectedOnSpinWaitInstCountValue + "' not found."); + } + } + + public static void main(String[] args) throws Exception { + List<String> cpuFeatures = CPUInfo.getFeatures(); + if (cpuFeatures.isEmpty()) { + System.out.println("Skip because no CPU features are available."); + return; + } + + final String cpuModel = cpuFeatures.get(0); + + if (isCPUModelNeoverseN1(cpuModel)) { + checkFinalFlagsEqualTo(ProcessTools.createJavaProcessBuilder("-XX:+UnlockDiagnosticVMOptions", "-XX:+PrintFlagsFinal", "-version"), + "isb", "1"); + checkFinalFlagsEqualTo(ProcessTools.createJavaProcessBuilder("-XX:+UnlockDiagnosticVMOptions", "-XX:OnSpinWaitInstCount=2", "-XX:+PrintFlagsFinal", "-version"), + "isb", "2"); + } else { + System.out.println("Skip because no defaults for CPU model: " + cpuModel); + } + } +} diff --git a/test/hotspot/jtreg/compiler/onSpinWait/TestOnSpinWaitNoneAArch64.java b/test/hotspot/jtreg/compiler/onSpinWait/TestOnSpinWaitNoneAArch64.java index 7b759f605a8aded319621d74d4612786deb0ae2d..7569d9d07a630c747e85d798fb690fc98bb04a6c 100644 --- a/test/hotspot/jtreg/compiler/onSpinWait/TestOnSpinWaitNoneAArch64.java +++ b/test/hotspot/jtreg/compiler/onSpinWait/TestOnSpinWaitNoneAArch64.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Amazon.com Inc. 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 diff --git a/test/hotspot/jtreg/compiler/oracle/PrintIdealPhaseTest.java b/test/hotspot/jtreg/compiler/oracle/PrintIdealPhaseTest.java new file mode 100644 index 0000000000000000000000000000000000000000..1c0ae79100446f051eab468297e1126fd37965a0 --- /dev/null +++ b/test/hotspot/jtreg/compiler/oracle/PrintIdealPhaseTest.java @@ -0,0 +1,154 @@ +/* + * 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. + */ + +/* + * @test PrintIdealPhaseTest + * @summary Checks that -XX:CompileCommand=PrintIdealPhase,... works + * @library /test/lib + * @modules java.base/jdk.internal.misc + * java.management + * @requires vm.debug == true & vm.compiler2.enabled & vm.compMode != "Xcomp" + * @run driver compiler.oracle.PrintIdealPhaseTest + */ + +package compiler.oracle; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import jdk.test.lib.Asserts; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; + +public class PrintIdealPhaseTest { + + public static void main(String[] args) throws Exception { + new PrintIdealPhaseTest(); + } + + PrintIdealPhaseTest() throws Exception { + // The Phases specified here will be exchanged for the enum Phase in compiler.lib.ir_framework when it's done + + // Test -XX:CompileCommand=PrintIdealPhase,*::test,CCP1 + List<String> expectedPhases = new ArrayList<String>(); + expectedPhases.add("CCP1"); + runTest("CCP1", expectedPhases, "hotspot_log_1.log", true); + runTest("FISH", expectedPhases, "hotspot_log_1f.log", false); + + // Test -XX:CompileCommand=PrintIdealPhase,*::test,MATCHING + expectedPhases.clear(); + expectedPhases.add("MATCHING"); + runTest("MATCHING", expectedPhases, "hotspot_log_2.log", true); + + // Test -XX:CompileCommand=PrintIdealPhase,*::test,CCP_1,AFTER_MATCHING + expectedPhases.add("CCP1"); + runTest("MATCHING,CCP1", expectedPhases, "hotspot_log_3.log", true); + } + + private void runTest(String cmdPhases, List<String> expectedPhases, String logFile, boolean valid) throws Exception { + List<String> options = new ArrayList<String>(); + options.add("-Xbatch"); + options.add("-XX:+PrintCompilation"); + options.add("-XX:LogFile="+logFile); + options.add("-XX:+IgnoreUnrecognizedVMOptions"); + options.add("-XX:CompileCommand=dontinline," + getTestClass() + "::test"); + options.add("-XX:CompileCommand=PrintIdealPhase," + getTestClass() + "::test," + cmdPhases); + options.add(getTestClass()); + + OutputAnalyzer oa = ProcessTools.executeTestJvm(options); + if (valid) { + oa.shouldHaveExitValue(0) + .shouldContain("CompileCommand: PrintIdealPhase compiler/oracle/PrintIdealPhaseTest$TestMain.test const char* PrintIdealPhase = '"+cmdPhases.replace(',', ' ')+"'") + .shouldNotContain("CompileCommand: An error occurred during parsing") + .shouldNotContain("Error: Unrecognized phase name in PrintIdealPhase:") + .shouldNotContain("# A fatal error has been detected by the Java Runtime Environment"); + + // Check that all the expected phases matches what can be found in the compilation log file + HashSet<String> loggedPhases = parseLogFile(logFile); + System.out.println("Logged phases:"); + for (String loggedPhase : loggedPhases) { + System.out.println("loggedPhase: "+ loggedPhase); + } + for (String expectedPhase : expectedPhases) { + System.out.println("Looking for phase: " + expectedPhase); + + Asserts.assertTrue(loggedPhases.contains(expectedPhase), "Must find specified phase: " + expectedPhase); + loggedPhases.remove(expectedPhase); + } + Asserts.assertTrue(loggedPhases.isEmpty(), "Expect no other phases"); + } else { + // Check that we don't pass even though bad phase names where given + oa.shouldHaveExitValue(0) + .shouldContain("CompileCommand: An error occurred during parsing") + .shouldContain("Error: Unrecognized phase name in PrintIdealPhase:"); + } + } + + private HashSet<String> parseLogFile(String logFile) { + String printIdealTag = "<ideal"; + Pattern compilePhasePattern = Pattern.compile("compile_phase='([a-zA-Z0-9 ]+)'"); + HashSet<String> phasesFound = new HashSet<>(); + + try (var br = Files.newBufferedReader(Paths.get(logFile))) { + String line; + while ((line = br.readLine()) != null) { + if (line.startsWith(printIdealTag)) { + Matcher matcher = compilePhasePattern.matcher(line); + if (matcher.find()) { + phasesFound.add(matcher.group(1)); + } else { + throw new Error("Failed to match compile_phase in file: " + logFile); + } + } + } + } catch (IOException e) { + throw new Error("Failed to read " + logFile + " data: " + e, e); + } + return phasesFound; + } + + // Test class that is invoked by the sub process + public String getTestClass() { + return TestMain.class.getName(); + } + + public static class TestMain { + public static void main(String[] args) { + for (int i = 0; i < 20_000; i++) { + test(i); + } + } + + static void test(int i) { + if ((i % 1000) == 0) { + System.out.println("Hello World!"); + } + } + } +} diff --git a/test/hotspot/jtreg/compiler/patches/java.base/java/lang/Helper.java b/test/hotspot/jtreg/compiler/patches/java.base/java/lang/Helper.java index ded4a58945d09e2337bbea37a0a416445b77377a..6d8b5be79bf84a30556901c98bf53768fd285fd6 100644 --- a/test/hotspot/jtreg/compiler/patches/java.base/java/lang/Helper.java +++ b/test/hotspot/jtreg/compiler/patches/java.base/java/lang/Helper.java @@ -32,6 +32,11 @@ public class Helper { return StringCoding.hasNegatives(ba, off, len); } + @jdk.internal.vm.annotation.ForceInline + public static int StringCodingCountPositives(byte[] ba, int off, int len) { + return StringCoding.countPositives(ba, off, len); + } + @jdk.internal.vm.annotation.ForceInline public static byte[] compressByte(byte[] src, int srcOff, int dstSize, int dstOff, int len) { byte[] dst = new byte[dstSize]; diff --git a/test/hotspot/jtreg/compiler/print/PrintInlining.java b/test/hotspot/jtreg/compiler/print/PrintInlining.java index deb1ae0aae0791be7a5202e10fafeae60d9945f8..4b45a32949f5773f46d2dca26a67da557403e243 100644 --- a/test/hotspot/jtreg/compiler/print/PrintInlining.java +++ b/test/hotspot/jtreg/compiler/print/PrintInlining.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -23,11 +23,14 @@ /* * @test - * @bug 8022585 + * @bug 8022585 8277055 * @summary VM crashes when ran with -XX:+PrintInlining * @run main/othervm -Xcomp -XX:+UnlockDiagnosticVMOptions -XX:+PrintInlining * compiler.print.PrintInlining - * + * @run main/othervm -Xcomp -XX:-TieredCompilation -XX:+UnlockDiagnosticVMOptions -XX:+PrintInlining + * compiler.print.PrintInlining + * @run main/othervm -Xcomp -XX:-TieredCompilation -XX:+UnlockDiagnosticVMOptions -XX:+PrintIntrinsics + * compiler.print.PrintInlining */ package compiler.print; diff --git a/test/hotspot/jtreg/compiler/profiling/TestSharedHeadExceptionBackedges.java b/test/hotspot/jtreg/compiler/profiling/TestSharedHeadExceptionBackedges.java new file mode 100644 index 0000000000000000000000000000000000000000..e02df36fa1cc52f7d47bd74794ea09bf9a7ba388 --- /dev/null +++ b/test/hotspot/jtreg/compiler/profiling/TestSharedHeadExceptionBackedges.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 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. + */ + +/* + * @test + * bug 8280842 + * @summary Access violation in ciTypeFlow::profiled_count + * @run main/othervm -XX:-BackgroundCompilation TestSharedHeadExceptionBackedges + */ + +public class TestSharedHeadExceptionBackedges { + public static void main(String[] args) { + for (int i = 0; i < 20_000; i++) { + test(); + } + } + + static class MyException extends Exception { + } + + private static void test() { + int i = 0; + while (i < 10) { + try { + int j = 0; + i++; + if (i % 2 == 0) { + throw new MyException(); + } + do { + j++; + } while (j < 100); + + throw new MyException(); + + } catch (MyException me) { + } + } + } +} diff --git a/test/hotspot/jtreg/compiler/profiling/spectrapredefineclass/Launcher.java b/test/hotspot/jtreg/compiler/profiling/spectrapredefineclass/Launcher.java index f248d1387e89f6b211cbc5345c5c4a041de3d8cb..85d5f2b96d5e7269785203e3de0ce11c6a896cbf 100644 --- a/test/hotspot/jtreg/compiler/profiling/spectrapredefineclass/Launcher.java +++ b/test/hotspot/jtreg/compiler/profiling/spectrapredefineclass/Launcher.java @@ -27,7 +27,7 @@ * @library /test/lib * @modules java.base/jdk.internal.misc * java.instrument - * @requires vm.jvmti + * @requires vm.jvmti & (vm.opt.TieredStopAtLevel == null | vm.opt.TieredStopAtLevel == 4) * @build compiler.profiling.spectrapredefineclass.Agent * @run driver jdk.test.lib.helpers.ClassFileInstaller compiler.profiling.spectrapredefineclass.Agent * @run driver compiler.profiling.spectrapredefineclass.Launcher diff --git a/test/hotspot/jtreg/compiler/profiling/spectrapredefineclass_classloaders/Launcher.java b/test/hotspot/jtreg/compiler/profiling/spectrapredefineclass_classloaders/Launcher.java index e5af0466932c6a93717d89d8efeab8ede5e4306b..2489e62bdb1861840004c5128e16ec575f1a337f 100644 --- a/test/hotspot/jtreg/compiler/profiling/spectrapredefineclass_classloaders/Launcher.java +++ b/test/hotspot/jtreg/compiler/profiling/spectrapredefineclass_classloaders/Launcher.java @@ -27,7 +27,7 @@ * @library /test/lib * @modules java.base/jdk.internal.misc * java.instrument - * @requires vm.jvmti + * @requires vm.jvmti & (vm.opt.TieredStopAtLevel == null | vm.opt.TieredStopAtLevel == 4) * @build compiler.profiling.spectrapredefineclass_classloaders.Agent * compiler.profiling.spectrapredefineclass_classloaders.Test * compiler.profiling.spectrapredefineclass_classloaders.A diff --git a/test/hotspot/jtreg/compiler/rangechecks/TestLongRangeCheck.java b/test/hotspot/jtreg/compiler/rangechecks/TestLongRangeCheck.java index 63a649b886b0a969fa8eb81e1ef3661571418cc3..1cd04523ba7c6d7be475957dd641d764cfd12f07 100644 --- a/test/hotspot/jtreg/compiler/rangechecks/TestLongRangeCheck.java +++ b/test/hotspot/jtreg/compiler/rangechecks/TestLongRangeCheck.java @@ -23,7 +23,7 @@ /** * @test - * @bug 8259609 + * @bug 8259609 8276116 * @summary C2: optimize long range checks in long counted loops * @requires vm.compiler2.enabled * @requires vm.compMode != "Xcomp" @@ -32,7 +32,7 @@ * @build sun.hotspot.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller sun.hotspot.WhiteBox * - * @run main/othervm -ea -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:-BackgroundCompilation TestLongRangeCheck + * @run main/othervm -ea -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:-BackgroundCompilation -XX:-UseOnStackReplacement TestLongRangeCheck * */ @@ -127,6 +127,73 @@ public class TestLongRangeCheck { assertIsNotCompiled(m); } + private static void testOverflow(String method, long start, long stop, long length, long offset0, long offset1) throws Exception { + Method m = newClassLoader().loadClass("TestLongRangeCheck").getDeclaredMethod(method, long.class, long.class, long.class, long.class); + m.invoke(null, start, stop, length, offset0); + compile(m); + + m.invoke(null, start, stop, length, offset0); + assertIsCompiled(m); + try { + m.invoke(null, start, stop, length, offset1); + throw new RuntimeException("should have thrown"); + } catch(InvocationTargetException e) { + if (!(e.getCause() instanceof IndexOutOfBoundsException)) { + throw new RuntimeException("unexpected exception"); + } + } + assertIsNotCompiled(m); + } + + private static void testConditional(String method, long start, long stop, long length, long offset0, long offset1, long start1, long stop1) throws Exception { + Method m; + + if (start1 != start) { + m = newClassLoader().loadClass("TestLongRangeCheck").getDeclaredMethod(method, long.class, long.class, long.class, long.class, long.class, long.class); + m.invoke(null, start, stop, length, offset0, start, stop); + compile(m); + + m.invoke(null, start, stop, length, offset0, start, stop); + assertIsCompiled(m); + try { + m.invoke(null, start, stop, length, offset1, start1-1, stop1); + throw new RuntimeException("should have thrown"); + } catch(InvocationTargetException e) { + if (!(e.getCause() instanceof IndexOutOfBoundsException)) { + throw new RuntimeException("unexpected exception"); + } + } + assertIsNotCompiled(m); + } + + if (stop1 != stop) { + m = newClassLoader().loadClass("TestLongRangeCheck").getDeclaredMethod(method, long.class, long.class, long.class, long.class, long.class, long.class); + m.invoke(null, start, stop, length, offset0, start, stop); + compile(m); + + m.invoke(null, start, stop, length, offset0, start, stop); + assertIsCompiled(m); + try { + m.invoke(null, start, stop, length, offset1, start1, stop1+1); + throw new RuntimeException("should have thrown"); + } catch(InvocationTargetException e) { + if (!(e.getCause() instanceof IndexOutOfBoundsException)) { + throw new RuntimeException("unexpected exception"); + } + } + assertIsNotCompiled(m); + } + + m = newClassLoader().loadClass("TestLongRangeCheck").getDeclaredMethod(method, long.class, long.class, long.class, long.class, long.class, long.class); + m.invoke(null, start, stop, length, offset0, start, stop); + compile(m); + + m.invoke(null, start, stop, length, offset0, start, stop); + assertIsCompiled(m); + + m.invoke(null, start, stop, length, offset1, start1, stop1); + assertIsCompiled(m); + } public static void main(String[] args) throws Exception { @@ -157,16 +224,100 @@ public class TestLongRangeCheck { test("testStridePosNotOneScaleNeg", -v, v, v * 2, v-1); // offset causes overflow + testOverflow("testStridePosScalePos", 0, 100, 100, 0, Long.MAX_VALUE - 50); + testOverflow("testStrideNegScaleNeg", 0, 100, 100, 100, Long.MIN_VALUE + 50); + testOverflow("testStrideNegScalePos", 0, 100, 100, 0, Long.MAX_VALUE - 50); + testOverflow("testStridePosScaleNeg", 0, 100, 100, 99, Long.MIN_VALUE + 50); + + // no spurious deopt if the range check doesn't fail because not executed + testConditional("testStridePosScalePosConditional", 0, 100, 100, 0, -50, 50, 100); + testConditional("testStridePosScalePosConditional", 0, 100, Long.MAX_VALUE, 0, Long.MAX_VALUE - 50, 0, 50); + testConditional("testStrideNegScaleNegConditional", 0, 100, 100, 100, 50, 0, 51); + testConditional("testStrideNegScaleNegConditional", 0, 100, Long.MAX_VALUE, 100, Long.MIN_VALUE + 50, 52, 100); + testConditional("testStrideNegScalePosConditional", 0, 100, 100, 0, -50, 50, 100); + testConditional("testStrideNegScalePosConditional", 0, 100, Long.MAX_VALUE, 100, Long.MAX_VALUE - 50, 0, 50); + testConditional("testStridePosScaleNegConditional", 0, 100, 100, 99, 50, 0, 51); + testConditional("testStridePosScaleNegConditional", 0, 100, Long.MAX_VALUE, 99, Long.MIN_VALUE + 50, 52, 100); + + test("testStridePosScalePosInIntLoop", 0, 100, 100, 0); + + test("testStrideNegScaleNegInIntLoop", 0, 100, 100, 100); + + test("testStrideNegScalePosInIntLoop", 0, 100, 100, 0); + + test("testStridePosScaleNegInIntLoop", 0, 100, 100, 99); + + test("testStridePosScalePosNotOneInIntLoop", 0, 100, 1090, 0); + + test("testStrideNegScaleNegNotOneInIntLoop", 0, 100, 1090, 1100); + + test("testStrideNegScalePosNotOneInIntLoop", 0, 100, 1090, 0); + + test("testStridePosScaleNegNotOneInIntLoop", 0, 100, 1090, 1089); + + v = ((long)Integer.MAX_VALUE / 10000) * 9999; + + test("testStridePosNotOneScalePosInIntLoop", -v, v, v * 4, 2 * v); + + test("testStrideNegNotOneScaleNegInIntLoop", -v, v, v * 4, 2 * v); + + test("testStrideNegNotOneScalePosInIntLoop", -v, v, v * 4, 2 * v); + + test("testStridePosNotOneScaleNegInIntLoop", -v, v, v * 4, 2 * v - 1); + + // offset causes overflow + testOverflow("testStridePosScalePosInIntLoop", 0, 100, 100, 0, Long.MAX_VALUE - 50); + testOverflow("testStrideNegScaleNegInIntLoop", 0, 100, 100, 100, Long.MIN_VALUE + 50); + testOverflow("testStrideNegScalePosInIntLoop", 0, 100, 100, 0, Long.MAX_VALUE - 50); + testOverflow("testStridePosScaleNegInIntLoop", 0, 100, 100, 99, Long.MIN_VALUE + 50); + // no spurious deopt if the range check doesn't fail because not executed + testConditional("testStridePosScalePosConditionalInIntLoop", 0, 100, 100, 0, -50, 50, 100); + testConditional("testStridePosScalePosConditionalInIntLoop", 0, 100, Long.MAX_VALUE, 0, Long.MAX_VALUE - 50, 0, 50); + testConditional("testStrideNegScaleNegConditionalInIntLoop", 0, 100, 100, 100, 50, 0, 51); + testConditional("testStrideNegScaleNegConditionalInIntLoop", 0, 100, Long.MAX_VALUE, 100, Long.MIN_VALUE + 50, 52, 100); + testConditional("testStrideNegScalePosConditionalInIntLoop", 0, 100, 100, 0, -50, 50, 100); + testConditional("testStrideNegScalePosConditionalInIntLoop", 0, 100, Long.MAX_VALUE, 100, Long.MAX_VALUE - 50, 0, 50); + testConditional("testStridePosScaleNegConditionalInIntLoop", 0, 100, 100, 99, 50, 0, 51); + testConditional("testStridePosScaleNegConditionalInIntLoop", 0, 100, Long.MAX_VALUE, 99, Long.MIN_VALUE + 50, 52, 100); + + test("testStridePosScalePosNotOneInIntLoop2", 0, 100, 1090, 0); + + test("testStrideNegScaleNegNotOneInIntLoop2", 0, 100, 1090, 1100); + + test("testStrideNegScalePosNotOneInIntLoop2", 0, 100, 1090, 0); + + test("testStridePosScaleNegNotOneInIntLoop2", 0, 100, 1090, 1089); { - Method m = newClassLoader().loadClass("TestLongRangeCheck").getDeclaredMethod("testStridePosScalePos", long.class, long.class, long.class, long.class); - m.invoke(null, 0, 100, 100, 0); + Method m = newClassLoader().loadClass("TestLongRangeCheck").getDeclaredMethod("testStridePosScalePosInIntLoopOverflow", long.class, long.class, long.class, long.class); + long stride = 1 << 14; + long scale = 1 << 15; + long offset = stride * scale * 4; + long length = offset + stride * scale * 3 + 1; + long stop = stride * 5; + + m.invoke(null, 0, stop, length, offset); compile(m); - m.invoke(null, 0, 100, 100, 0); - assertIsCompiled(m); + m.invoke(null, 0, stop, length, offset); + // deoptimizes even though no range check fails + } + { + Method m = newClassLoader().loadClass("TestLongRangeCheck").getDeclaredMethod("testStridePosScalePosInIntLoopOverflow", long.class, long.class, long.class, long.class); + long stride = 1 << 14; + long scale = 1 << 15; + long offset = stride * scale * 4; + long length = offset + stride * scale * 3 + 1; + long stop = stride * 5; + + m.invoke(null, 0, stop, length, offset); + compile(m); + + offset = 0; + stop = stride * 5; + try { - m.invoke(null, 0, 100, 100, Long.MAX_VALUE - 50); + m.invoke(null, 0, stop, length, offset); throw new RuntimeException("should have thrown"); } catch(InvocationTargetException e) { if (!(e.getCause() instanceof IndexOutOfBoundsException)) { @@ -175,24 +326,6 @@ public class TestLongRangeCheck { } assertIsNotCompiled(m); } - - // no spurious deopt if the range check doesn't fail because not executed - { - Method m = newClassLoader().loadClass("TestLongRangeCheck").getDeclaredMethod("testStridePosScalePosConditional", long.class, long.class, long.class, long.class, long.class, long.class); - m.invoke(null, 0, 100, 100, 0, 0, 100); - compile(m); - - m.invoke(null, 0, 100, 100, -50, 50, 100); - assertIsCompiled(m); - } - { - Method m = newClassLoader().loadClass("TestLongRangeCheck").getDeclaredMethod("testStridePosScalePosConditional", long.class, long.class, long.class, long.class, long.class, long.class); - m.invoke(null, 0, 100, 100, 0, 0, 100); - compile(m); - - m.invoke(null, 0, 100, Long.MAX_VALUE, Long.MAX_VALUE - 50, 0, 50); - assertIsCompiled(m); - } } public static void testStridePosScalePos(long start, long stop, long length, long offset) { @@ -301,4 +434,239 @@ public class TestLongRangeCheck { } } } + + public static void testStrideNegScaleNegConditional(long start, long stop, long length, long offset, long start2, long stop2) { + final long scale = -1; + final long stride = 1; + for (long i = stop; i > start; i -= stride) { + if (i >= start2 && i < stop2) { + Preconditions.checkIndex(scale * i + offset, length, null); + } + } + } + + public static void testStrideNegScalePosConditional(long start, long stop, long length, long offset, long start2, long stop2) { + final long scale = 1; + final long stride = 1; + for (long i = stop-1; i >= start; i -= stride) { + if (i >= start2 && i < stop2) { + Preconditions.checkIndex(scale * i + offset, length, null); + } + } + } + + public static void testStridePosScaleNegConditional(long start, long stop, long length, long offset, long start2, long stop2) { + final long scale = -1; + final long stride = 1; + for (long i = start; i < stop; i += stride) { + if (i >= start2 && i < stop2) { + Preconditions.checkIndex(scale * i + offset, length, null); + } + } + } + + private static void checkInputs(long... inputs) { + for (int i = 0; i < inputs.length; i++) { + if ((long)((int)inputs[i]) != inputs[i]) { + throw new RuntimeException("bad arguments"); + } + } + } + + public static void testStridePosScalePosInIntLoop(long start, long stop, long length, long offset) { + checkInputs(start, stop); + final long scale = 1; + final int stride = 1; + for (int i = (int)start; i < (int)stop; i += stride) { + Preconditions.checkIndex(scale * i + offset, length, null); + } + } + + public static void testStrideNegScaleNegInIntLoop(long start, long stop, long length, long offset) { + checkInputs(start, stop); + final long scale = -1; + final int stride = 1; + for (int i = (int)stop; i > (int)start; i -= stride) { + Preconditions.checkIndex(scale * i + offset, length, null); + } + } + + public static void testStrideNegScalePosInIntLoop(long start, long stop, long length, long offset) { + checkInputs(start, stop); + final long scale = 1; + final int stride = 1; + for (int i = (int)(stop-1); i >= (int)start; i -= stride) { + Preconditions.checkIndex(scale * i + offset, length, null); + } + } + + public static void testStridePosScaleNegInIntLoop(long start, long stop, long length, long offset) { + checkInputs(start, stop); + final long scale = -1; + final int stride = 1; + for (int i = (int)start; i < (int)stop; i += stride) { + Preconditions.checkIndex(scale * i + offset, length, null); + } + } + + public static void testStridePosScalePosNotOneInIntLoop(long start, long stop, long length, long offset) { + checkInputs(start, stop); + final long scale = 11; + final int stride = 1; + for (int i = (int)start; i < (int)stop; i += stride) { + Preconditions.checkIndex(scale * i + offset, length, null); + } + } + + public static void testStrideNegScaleNegNotOneInIntLoop(long start, long stop, long length, long offset) { + checkInputs(start, stop); + final long scale = -11; + final int stride = 1; + for (int i = (int)stop; i > (int)start; i -= stride) { + Preconditions.checkIndex(scale * i + offset, length, null); + } + } + + public static void testStrideNegScalePosNotOneInIntLoop(long start, long stop, long length, long offset) { + checkInputs(start, stop); + final long scale = 11; + final int stride = 1; + for (int i = (int)(stop-1); i >= (int)start; i -= stride) { + Preconditions.checkIndex(scale * i + offset, length, null); + } + } + + public static void testStridePosScaleNegNotOneInIntLoop(long start, long stop, long length, long offset) { + checkInputs(start, stop); + final long scale = -11; + final int stride = 1; + for (int i = (int)start; i < (int)stop; i += stride) { + Preconditions.checkIndex(scale * i + offset, length, null); + } + } + + public static void testStridePosNotOneScalePosInIntLoop(long start, long stop, long length, long offset) { + checkInputs(start, stop); + final long scale = 2; + final int stride = Integer.MAX_VALUE / 10000; + for (int i = (int)start; i < (int)stop; i += stride) { + Preconditions.checkIndex(scale * i + offset, length, null); + } + } + + public static void testStrideNegNotOneScaleNegInIntLoop(long start, long stop, long length, long offset) { + checkInputs(start, stop); + final long scale = -2; + final int stride = Integer.MAX_VALUE / 10000; + for (int i = (int)stop; i > (int)start; i -= stride) { + Preconditions.checkIndex(scale * i + offset, length, null); + } + } + + public static void testStrideNegNotOneScalePosInIntLoop(long start, long stop, long length, long offset) { + checkInputs(start, stop); + final long scale = 2; + final int stride = Integer.MAX_VALUE / 10000; + for (int i = (int)(stop-1); i >= (int)start; i -= stride) { + Preconditions.checkIndex(scale * i + offset, length, null); + } + } + + public static void testStridePosNotOneScaleNegInIntLoop(long start, long stop, long length, long offset) { + checkInputs(start, stop); + final long scale = -2; + final int stride = Integer.MAX_VALUE / 10000; + for (int i = (int)start; i < (int)stop; i += stride) { + Preconditions.checkIndex(scale * i + offset, length, null); + } + } + + public static void testStridePosScalePosConditionalInIntLoop(long start, long stop, long length, long offset, long start2, long stop2) { + checkInputs(start, stop, start2, stop2); + final long scale = 1; + final int stride = 1; + for (int i = (int)start; i < (int)stop; i += stride) { + if (i >= (int)start2 && i < (int)stop2) { + Preconditions.checkIndex(scale * i + offset, length, null); + } + } + } + + public static void testStrideNegScaleNegConditionalInIntLoop(long start, long stop, long length, long offset, long start2, long stop2) { + checkInputs(start, stop, start2, stop2); + final long scale = -1; + final int stride = 1; + for (int i = (int)stop; i > (int)start; i -= stride) { + if (i >= (int)start2 && i < (int)stop2) { + Preconditions.checkIndex(scale * i + offset, length, null); + } + } + } + + public static void testStrideNegScalePosConditionalInIntLoop(long start, long stop, long length, long offset, long start2, long stop2) { + checkInputs(start, stop, start2, stop2); + final long scale = 1; + final int stride = 1; + for (int i = (int)(stop-1); i >= (int)start; i -= stride) { + if (i >= (int)start2 && i < (int)stop2) { + Preconditions.checkIndex(scale * i + offset, length, null); + } + } + } + + public static void testStridePosScaleNegConditionalInIntLoop(long start, long stop, long length, long offset, long start2, long stop2) { + checkInputs(start, stop, start2, stop2); + final long scale = -1; + final int stride = 1; + for (int i = (int)start; i < (int)stop; i += stride) { + if (i >= (int)start2 && i < (int)stop2) { + Preconditions.checkIndex(scale * i + offset, length, null); + } + } + } + + public static void testStridePosScalePosNotOneInIntLoop2(long start, long stop, long length, long offset) { + checkInputs(start, stop); + final int scale = 11; + final int stride = 1; + for (int i = (int)start; i < (int)stop; i += stride) { + Preconditions.checkIndex(scale * i + offset, length, null); + } + } + + public static void testStrideNegScaleNegNotOneInIntLoop2(long start, long stop, long length, long offset) { + checkInputs(start, stop); + final int scale = -11; + final int stride = 1; + for (int i = (int)stop; i > (int)start; i -= stride) { + Preconditions.checkIndex(scale * i + offset, length, null); + } + } + + public static void testStrideNegScalePosNotOneInIntLoop2(long start, long stop, long length, long offset) { + checkInputs(start, stop); + final int scale = 11; + final int stride = 1; + for (int i = (int)(stop-1); i >= (int)start; i -= stride) { + Preconditions.checkIndex(scale * i + offset, length, null); + } + } + + public static void testStridePosScaleNegNotOneInIntLoop2(long start, long stop, long length, long offset) { + checkInputs(start, stop); + final int scale = -11; + final int stride = 1; + for (int i = (int)start; i < (int)stop; i += stride) { + Preconditions.checkIndex(scale * i + offset, length, null); + } + } + + public static void testStridePosScalePosInIntLoopOverflow(long start, long stop, long length, long offset) { + checkInputs(start, stop); + final int scale = 1 << 15; + final int stride = 1 << 14; + for (int i = (int)start; i < (int)stop; i += stride) { + Preconditions.checkIndex(scale * i + offset, length, null); + } + } } diff --git a/test/hotspot/jtreg/compiler/runtime/Test6826736.java b/test/hotspot/jtreg/compiler/runtime/Test6826736.java index 2f078506e55f3f5455873db3f68304302bc1ca9b..0b028947f7766b3628d438f4da9e68acfb64d5c7 100644 --- a/test/hotspot/jtreg/compiler/runtime/Test6826736.java +++ b/test/hotspot/jtreg/compiler/runtime/Test6826736.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 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 @@ -26,6 +26,7 @@ * @bug 6826736 * @summary CMS: core dump with -XX:+UseCompressedOops * + * @requires vm.bits == 64 * @run main/othervm/timeout=600 -XX:+IgnoreUnrecognizedVMOptions -Xbatch * -XX:+ScavengeALot -XX:+UseCompressedOops -XX:HeapBaseMinAddress=32g * -XX:CompileThreshold=100 -XX:-BlockLayoutRotateLoops diff --git a/test/hotspot/jtreg/compiler/runtime/Test8168712.java b/test/hotspot/jtreg/compiler/runtime/Test8168712.java index 00cffa3e75775912a637b10c8060e75063120b4a..e411dc21479ea59a1b2de96b662cdc699eed6438 100644 --- a/test/hotspot/jtreg/compiler/runtime/Test8168712.java +++ b/test/hotspot/jtreg/compiler/runtime/Test8168712.java @@ -22,11 +22,29 @@ */ /** - * @test + * @test id=with-dtrace * @requires vm.debug + * @requires vm.hasDTrace * @bug 8168712 * - * @run main/othervm -XX:CompileCommand=compileonly,Test8168712.* -XX:CompileCommand=compileonly,*Object.* -XX:+DTraceMethodProbes -XX:-UseOnStackReplacement -XX:+DeoptimizeRandom compiler.runtime.Test8168712 + * @run main/othervm -XX:CompileCommand=compileonly,Test8168712.* + * -XX:CompileCommand=compileonly,*Object.* + * -XX:+DTraceMethodProbes + * -XX:-UseOnStackReplacement + * -XX:+DeoptimizeRandom + * compiler.runtime.Test8168712 + */ + +/** + * @test id=without-dtrace + * @requires vm.debug + * @bug 8168712 + * + * @run main/othervm -XX:CompileCommand=compileonly,Test8168712.* + * -XX:CompileCommand=compileonly,*Object.* + * -XX:-UseOnStackReplacement + * -XX:+DeoptimizeRandom + * compiler.runtime.Test8168712 */ package compiler.runtime; diff --git a/test/hotspot/jtreg/compiler/runtime/TestConstantDynamic.java b/test/hotspot/jtreg/compiler/runtime/TestConstantDynamic.java new file mode 100644 index 0000000000000000000000000000000000000000..06604c5b9813bc30fd389e842846131ba6fb8de6 --- /dev/null +++ b/test/hotspot/jtreg/compiler/runtime/TestConstantDynamic.java @@ -0,0 +1,254 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8280473 + * @library /test/lib + * @modules java.base/jdk.internal.org.objectweb.asm + * + * @run main/othervm -XX:+TieredCompilation -XX:TieredStopAtLevel=1 + * -Xbatch -XX:CompileThreshold=100 -XX:CompileCommand=compileonly,*::test + * -XX:CompileCommand=quiet -XX:+PrintCompilation + * compiler.runtime.TestConstantDynamic + * @run main/othervm -XX:-TieredCompilation + * -Xbatch -XX:CompileThreshold=100 -XX:CompileCommand=compileonly,*::test + * -XX:CompileCommand=quiet -XX:+PrintCompilation + * compiler.runtime.TestConstantDynamic + */ + +package compiler.runtime; + +import jdk.internal.org.objectweb.asm.*; + +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.Serializable; +import java.lang.constant.ConstantDescs; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandleProxies; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.lang.reflect.Method; + +import static jdk.internal.org.objectweb.asm.ClassWriter.*; +import static jdk.internal.org.objectweb.asm.Opcodes.*; + +public class TestConstantDynamic { + static final Class<TestConstantDynamic> THIS_CLASS = TestConstantDynamic.class; + + static final String THIS_CLASS_NAME = THIS_CLASS.getName().replace('.', '/'); + static final String CLASS_NAME = THIS_CLASS_NAME + "$Test"; + + public interface Test { + Object run(boolean b); + } + + public static final String PATH = System.getProperty("test.classes", ".") + java.io.File.separator; + private static int ID = 0; + + /* =================================================================================================== */ + + static final String BSM_DESC = "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/Object;"; + static final Handle BSM = new Handle(H_INVOKESTATIC, THIS_CLASS_NAME, "bsm", BSM_DESC, false); + + static Object bsm(MethodHandles.Lookup lookup, String name, Class c) throws IllegalAccessException { + Object[] classData = MethodHandles.classData(lookup, ConstantDescs.DEFAULT_NAME, Object[].class); + Object value = classData[0]; + System.out.printf("BSM: lookup=%s name=\"%s\" class=%s => \"%s\"\n", lookup, name, c, classData[0]); + return value; + } + + static final Handle THROWING_BSM = new Handle(H_INVOKESTATIC, THIS_CLASS_NAME, "throwingBSM", BSM_DESC, false); + + static Object throwingBSM(MethodHandles.Lookup lookup, String name, Class c) throws IllegalAccessException { + Object[] classData = (Object[])MethodHandles.classData(lookup, ConstantDescs.DEFAULT_NAME, Object[].class); + Object value = classData[0]; + System.out.printf("BSM: lookup=%s name=\"%s\" class=%s value=\"%s\" => Exception\n", lookup, name, c, value); + throw new IllegalArgumentException(lookup.lookupClass().getName() + ": " + c.getName() + " " + name + " " + value); + } + + /* =================================================================================================== */ + + static byte[] generateClassFile(String suffix, String desc, int retOpcode, Handle bsm) throws IOException { + var cw = new ClassWriter(COMPUTE_MAXS | COMPUTE_FRAMES); + String name = CLASS_NAME + "_" + suffix + "_" + (++ID); + cw.visit(V19, ACC_PUBLIC | ACC_SUPER, name, null, "java/lang/Object", null); + + Handle localBSM = new Handle(H_INVOKESTATIC, name, "bsm", BSM_DESC, false); + + { + var mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "bsm", BSM_DESC, null, null); + + mv.visitLdcInsn(bsm); + mv.visitIntInsn(ALOAD, 0); + mv.visitIntInsn(ALOAD, 1); + mv.visitIntInsn(ALOAD, 2); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandle", "invokeExact", BSM_DESC, false); + mv.visitInsn(ARETURN); + mv.visitMaxs(0, 0); + } + + { + var mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "test", "(Z)" + desc, null, null); + mv.visitCode(); + + Label endL = new Label(); + Label falseL = new Label(); + + mv.visitIntInsn(ILOAD, 0); + mv.visitJumpInsn(Opcodes.IFNE, falseL); + + mv.visitLdcInsn(new ConstantDynamic("first", desc, localBSM)); // is resolved on b = false + + mv.visitJumpInsn(GOTO, endL); + + mv.visitLabel(falseL); + + mv.visitLdcInsn(new ConstantDynamic("second", desc, localBSM)); // is resolved on b = true + + mv.visitLabel(endL); + mv.visitInsn(retOpcode); + mv.visitMaxs(0, 0); + } + byte[] classFile = cw.toByteArray(); + + try (FileOutputStream fos = new FileOutputStream(PATH + name + ".class")) { + fos.write(classFile); + } + + return classFile; + } + + static Test generate(String desc, int retOpcode, Object value, Handle bsm, boolean shouldThrow) { + try { + byte[] classFile = generateClassFile("CD", desc, retOpcode, bsm); + Object[] classData = new Object[] { value }; + MethodHandles.Lookup testLookup = MethodHandles.lookup().defineHiddenClassWithClassData(classFile, classData, true); + Method testMethod = testLookup.lookupClass().getDeclaredMethod("test", boolean.class); + MethodHandle testMH = testLookup.unreflect(testMethod); + + if (shouldThrow) { + // Install empty handler for linkage errors, but throw an error on successful invocation. + // try { Test.test(b); throw AssertionError(); } catch (LinkageError e) { /* expected */ } + testMH = MethodHandles.filterReturnValue(testMH, + MethodHandles.dropArguments( + MethodHandles.insertArguments( + MethodHandles.throwException(testMH.type().returnType(), AssertionError.class), + 0, new AssertionError("no exception thrown")), + 0, testMH.type().returnType())); + + testMH = MethodHandles.catchException(testMH, LinkageError.class, + MethodHandles.empty(MethodType.methodType(testMH.type().returnType(), LinkageError.class))); + } else { + Class<?> type = testMH.type().returnType(); + testMH = MethodHandles.filterReturnValue(testMH, + MethodHandles.insertArguments(VALIDATE_MH, 0, value) + .asType(MethodType.methodType(type, type))); + } + + return MethodHandleProxies.asInterfaceInstance(Test.class, testMH); + } catch (Throwable e) { + throw new InternalError(e); + } + } + + static final MethodHandle VALIDATE_MH; + static { + try { + VALIDATE_MH = MethodHandles.lookup().findStatic(THIS_CLASS, "validateResult", + MethodType.methodType(Object.class, Object.class, Object.class)); + } catch (ReflectiveOperationException e) { + throw new InternalError(e); + } + } + static Object validateResult(Object expected, Object actual) { + if ((expected == null && actual != null) || + (expected != null && !expected.equals(actual))) { + throw new AssertionError(String.format("expected=%s != actual=%s", expected.toString(), actual.toString())); + } + return actual; + } + + private Handle bsm; + private boolean shouldThrow; + + TestConstantDynamic(Handle bsm, boolean shouldThrow) { + this.bsm = bsm; + this.shouldThrow = shouldThrow; + } + + static TestConstantDynamic shouldNotThrow() { + return new TestConstantDynamic(BSM, false); + } + + static TestConstantDynamic shouldThrow() { + return new TestConstantDynamic(THROWING_BSM, true); + } + + static void shouldThrow(Handle bsm, String desc, int retOpcode, Object value) { + (new TestConstantDynamic(bsm, true)).test(desc, retOpcode, value); + } + + void test(String desc, int retOpcode, Object value) { + Test test = generate(desc, retOpcode, value, bsm, shouldThrow); + + for (int i = 0; i < 200; i++) { + test.run(false); + } + for (int i = 0; i < 200; i++) { + test.run(true); + } + } + + static void run(TestConstantDynamic t) { + t.test("Z", IRETURN, Boolean.TRUE); + t.test("B", IRETURN, Byte.MAX_VALUE); + t.test("S", IRETURN, Short.MAX_VALUE); + t.test("C", IRETURN, Character.MAX_VALUE); + t.test("I", IRETURN, Integer.MAX_VALUE); + t.test("J", LRETURN, Long.MAX_VALUE); + t.test("F", FRETURN, Float.MAX_VALUE); + t.test("D", DRETURN, Double.MAX_VALUE); + + t.test("Ljava/lang/Object;", ARETURN, new Object()); + t.test("Ljava/lang/Object;", ARETURN, null); + + t.test("[Ljava/lang/Object;", ARETURN, new Object[0]); + t.test("[Ljava/lang/Object;", ARETURN, null); + + t.test("[I", ARETURN, new int[0]); + t.test("[I", ARETURN, null); + + t.test("Ljava/lang/Runnable;", ARETURN, (Runnable)(() -> {})); + t.test("Ljava/lang/Runnable;", ARETURN, null); + } + + public static void main(String[] args) { + run(shouldNotThrow()); + + run(shouldThrow()); // use error-throwing BSM + + shouldThrow(BSM, "Ljava/lang/Runnable;", ARETURN, new Object()); // not a Runnable + } +} diff --git a/test/hotspot/jtreg/compiler/runtime/TestConstantsInError.java b/test/hotspot/jtreg/compiler/runtime/TestConstantsInError.java new file mode 100644 index 0000000000000000000000000000000000000000..1c551b4efbdbcfcc275a80259f7e0eab820859b0 --- /dev/null +++ b/test/hotspot/jtreg/compiler/runtime/TestConstantsInError.java @@ -0,0 +1,285 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8279822 + * @requires vm.flagless + * @library /test/lib + * @modules java.base/jdk.internal.org.objectweb.asm + * + * @run main compiler.runtime.TestConstantsInError + */ +package compiler.runtime; + +import jdk.internal.org.objectweb.asm.*; +import jdk.test.lib.Platform; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; + +import java.io.FileOutputStream; +import java.io.IOException; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandleProxies; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.util.ArrayList; +import java.util.List; + +import static jdk.internal.org.objectweb.asm.ClassWriter.*; +import static jdk.internal.org.objectweb.asm.Opcodes.*; + +interface OutputProcessor { + default void process(OutputAnalyzer output, boolean isC1) {} +} + +public abstract class TestConstantsInError implements OutputProcessor { + static final String TEST_PREFIX = class2desc(TestConstantsInError.class) + "$Test"; + + public interface Test extends Runnable {} + + + interface Generator { + void generate(MethodVisitor mv); + } + + static String class2desc(Class<?> cls) { + return cls.getName().replace('.', '/'); + } + + public static final String PATH = System.getProperty("test.classes", ".") + java.io.File.separator; + + static byte[] generateClassFile(String suffix, Generator g) throws IOException { + var cw = new ClassWriter(COMPUTE_MAXS | COMPUTE_FRAMES); + String name = TEST_PREFIX + "_" + suffix; + cw.visit(V19, ACC_PUBLIC | ACC_SUPER, name, null, "java/lang/Object", null); + + { + var mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "test", "()V", null, null); + mv.visitCode(); + g.generate(mv); + mv.visitInsn(RETURN); + mv.visitMaxs(0, 0); + } + byte[] classFile = cw.toByteArray(); + + try (FileOutputStream fos = new FileOutputStream(PATH + name + ".class")) { + fos.write(classFile); + } + + return classFile; + } + + static Test generate(String suffix, Class<? extends LinkageError> expectedError, Generator g) { + try { + byte[] classFile = generateClassFile(suffix, g); + MethodHandles.Lookup testLookup = MethodHandles.lookup().defineHiddenClass(classFile, true); + MethodHandle testMH = testLookup.findStatic(testLookup.lookupClass(), "test", MethodType.methodType(void.class)); + + testMH = MethodHandles.filterReturnValue(testMH, + MethodHandles.insertArguments( + MethodHandles.throwException(void.class, AssertionError.class), + 0, new AssertionError("no exception thrown"))); + + // Install empty handler for linkage exceptions. + testMH = MethodHandles.catchException(testMH, expectedError, + MethodHandles.empty(MethodType.methodType(void.class, expectedError))); + + return MethodHandleProxies.asInterfaceInstance(Test.class, testMH); + } catch (Throwable e) { + throw new InternalError(e); + } + } + + static void run(String name, Class<? extends LinkageError> expectedError, Generator g) { + Test test = generate(name, expectedError, g); + for (int i = 0; i < 1000; i++) { + test.run(); + } + } + + static class TestConstantClass extends TestConstantsInError { + public static void main(String[] args) { + run("C1", NoClassDefFoundError.class, mv -> mv.visitLdcInsn(Type.getType("LUnknownClass;"))); // non-existent class + run("C2", IllegalAccessError.class, mv -> mv.visitLdcInsn(Type.getType("Ljava/lang/invoke/LambdaForm;"))); // inaccessible + + // class loader constraints? + } + + public void process(OutputAnalyzer results, boolean isC1) { + results.shouldMatch("Test_C1/.*::test \\(3 bytes\\)$") + .shouldMatch("Test_C2/.*::test \\(3 bytes\\)$"); + + if (isC1 && Platform.isAArch64()) { // no code patching + results.shouldMatch("Test_C1/.*::test \\(3 bytes\\) made not entrant") + .shouldMatch("Test_C2/.*::test \\(3 bytes\\) made not entrant"); + } else { + results.shouldNotContain("made not entrant"); + } + } + + public void processC2(OutputAnalyzer results) { + results.shouldNotContain("made not entrant"); + } + } + + static class TestConstantMethodHandle extends TestConstantsInError { + public static void main(String[] args) { + // Non-existent holder class + run("MH1", NoClassDefFoundError.class, + mv -> mv.visitLdcInsn(new Handle(H_INVOKESTATIC, "UnknownClass", "ignored", "()V", false))); + + // Inaccessible holder class + run("MH2", IllegalAccessError.class, + mv -> mv.visitLdcInsn(new Handle(H_INVOKESTATIC, "java/lang/invoke/LambdaForm", "ignored", "()V", false))); + + // Method vs InterfaceMethod mismatch + run("MH3", IncompatibleClassChangeError.class, + mv -> mv.visitLdcInsn(new Handle(H_INVOKESTATIC, "java/lang/Object", "ignored", "()V", true))); + + // Non-existent method + run("MH4", NoSuchMethodError.class, + mv -> mv.visitLdcInsn(new Handle(H_INVOKESTATIC, "java/lang/Object", "cast", "()V", false))); + } + + public void process(OutputAnalyzer results, boolean isC1) { + results.shouldMatch("Test_MH1/.*::test \\(3 bytes\\)$") + .shouldMatch("Test_MH2/.*::test \\(3 bytes\\)$") + .shouldMatch("Test_MH3/.*::test \\(3 bytes\\)$") + .shouldMatch("Test_MH4/.*::test \\(3 bytes\\)$"); + + if (isC1 && Platform.isAArch64()) { // no code patching + results.shouldMatch("Test_MH1/.*::test \\(3 bytes\\) made not entrant") + .shouldMatch("Test_MH2/.*::test \\(3 bytes\\) made not entrant") + .shouldMatch("Test_MH3/.*::test \\(3 bytes\\) made not entrant") + .shouldMatch("Test_MH4/.*::test \\(3 bytes\\) made not entrant"); + } else { + results.shouldNotContain("made not entrant"); + } + } + } + + static class TestConstantMethodType extends TestConstantsInError { + public static void main(String[] args) { + run("MT1", NoClassDefFoundError.class, + mv -> mv.visitLdcInsn(Type.getMethodType("(LUnknownClass;)V"))); + run("MT2", NoClassDefFoundError.class, + mv -> mv.visitLdcInsn(Type.getMethodType("()LUnknownClass;"))); + } + + public void process(OutputAnalyzer results, boolean isC1) { + results.shouldMatch("Test_MT1/.*::test \\(3 bytes\\)$") + .shouldMatch("Test_MT2/.*::test \\(3 bytes\\)$"); + + if (isC1 && Platform.isAArch64()) { // no code patching + results.shouldMatch("Test_MT1/.*::test \\(3 bytes\\) made not entrant") + .shouldMatch("Test_MT2/.*::test \\(3 bytes\\) made not entrant"); + } else { + results.shouldNotContain("made not entrant"); + } + } + } + + static class TestConstantDynamic extends TestConstantsInError { + static int bsm1() throws Exception { + throw new AssertionError("should not be invoked"); + } + + static int bsm2(MethodHandles.Lookup lookup, String name, Class c) throws Exception { + throw new Exception("expected"); + } + + static final Handle BSM1 = new Handle(H_INVOKESTATIC, class2desc(TestConstantDynamic.class), "bsm1", "()I", false); + static final Handle BSM2 = new Handle(H_INVOKESTATIC, class2desc(TestConstantDynamic.class), "bsm2", + "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Class;)I", + false); + + public static void main(String[] args) { + run("CD1", NoClassDefFoundError.class, + mv -> { + Handle bsm = new Handle(H_INVOKESTATIC, "UnknownClass", "unknown", "()LUnknownClass;", false); + mv.visitLdcInsn(new ConstantDynamic("tmp", "LUnknownClass;", bsm)); + }); + run("CD2", NoSuchMethodError.class, + mv -> { + Handle bsm = new Handle(H_INVOKESTATIC, class2desc(TestConstantDynamic.class), "unknown", "()I", false); + mv.visitLdcInsn(new ConstantDynamic("tmp", "LUnknownClass;", bsm)); + }); + run("CD3", BootstrapMethodError.class, mv -> mv.visitLdcInsn(new ConstantDynamic("tmp", "I", BSM1))); + run("CD4", BootstrapMethodError.class, mv -> mv.visitLdcInsn(new ConstantDynamic("tmp", "I", BSM2))); + } + + public void process(OutputAnalyzer results, boolean isC1) { + results.shouldMatch("Test_CD1.*::test \\(3 bytes\\)$") + .shouldMatch("Test_CD2.*::test \\(3 bytes\\)$") + .shouldMatch("Test_CD3.*::test \\(3 bytes\\)$") + .shouldMatch("Test_CD4.*::test \\(3 bytes\\)$"); + + if (isC1 && Platform.isAArch64()) { // no code patching + results.shouldMatch("Test_CD1.*::test \\(3 bytes\\) made not entrant") + .shouldMatch("Test_CD2.*::test \\(3 bytes\\) made not entrant") + .shouldMatch("Test_CD3.*::test \\(3 bytes\\) made not entrant") + .shouldMatch("Test_CD4.*::test \\(3 bytes\\) made not entrant"); + } else { + results.shouldNotContain("made not entrant"); + } + } + } + + static void run(TestConstantsInError test) throws Exception { + List<String> commonArgs = List.of( + "--add-exports", "java.base/jdk.internal.org.objectweb.asm=ALL-UNNAMED", + "-Xbatch", "-XX:CompileThreshold=100", + "-XX:CompileCommand=quiet", "-XX:CompileCommand=compileonly,*::test", + "-XX:+PrintCompilation", + "-XX:CompileCommand=print,*::test", + "-Dtest.classes=" + System.getProperty("test.classes", "."), + "-XX:+IgnoreUnrecognizedVMOptions", + test.getClass().getName()); + + ArrayList<String> c1Args = new ArrayList<>(); + c1Args.addAll(List.of("-XX:+TieredCompilation", "-XX:TieredStopAtLevel=1", "-XX:+TracePatching")); + c1Args.addAll(commonArgs); + + OutputAnalyzer outputC1 = ProcessTools.executeTestJvm(c1Args) + .shouldHaveExitValue(0); + + test.process(outputC1, true); + + ArrayList<String> c2Args = new ArrayList<>(); + c2Args.add("-XX:-TieredCompilation"); + c2Args.addAll(commonArgs); + + OutputAnalyzer outputC2 = ProcessTools.executeTestJvm(c2Args) + .shouldHaveExitValue(0); + + test.process(outputC2, false); + } + + public static void main(String[] args) throws Exception { + run(new TestConstantClass()); + run(new TestConstantMethodType()); + run(new TestConstantMethodHandle()); + run(new TestConstantDynamic()); + } +} diff --git a/test/hotspot/jtreg/compiler/testlibrary/sha/predicate/IntrinsicPredicates.java b/test/hotspot/jtreg/compiler/testlibrary/sha/predicate/IntrinsicPredicates.java index 00eb0e2d27234160408b12448ec55d50c5e9abc9..782ab6b9b46dcd773534a69e5449c23d15f90698 100644 --- a/test/hotspot/jtreg/compiler/testlibrary/sha/predicate/IntrinsicPredicates.java +++ b/test/hotspot/jtreg/compiler/testlibrary/sha/predicate/IntrinsicPredicates.java @@ -60,10 +60,11 @@ public class IntrinsicPredicates { }; public static final BooleanSupplier MD5_INSTRUCTION_AVAILABLE - = // x86 variants + = new OrPredicate(new CPUSpecificPredicate("aarch64.*", null, null), + // x86 variants new OrPredicate(new CPUSpecificPredicate("amd64.*", null, null), new OrPredicate(new CPUSpecificPredicate("i386.*", null, null), - new CPUSpecificPredicate("x86.*", null, null))); + new CPUSpecificPredicate("x86.*", null, null)))); public static final BooleanSupplier SHA1_INSTRUCTION_AVAILABLE = new OrPredicate(new CPUSpecificPredicate("aarch64.*", new String[] { "sha1" }, null), diff --git a/test/hotspot/jtreg/compiler/uncommontrap/Decompile.java b/test/hotspot/jtreg/compiler/uncommontrap/Decompile.java new file mode 100644 index 0000000000000000000000000000000000000000..3ea6bb5cb29da0910540bdb7abd0b4b19fedb93d --- /dev/null +++ b/test/hotspot/jtreg/compiler/uncommontrap/Decompile.java @@ -0,0 +1,167 @@ +/* + * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + /* + * @test + * @bug 8275908 + * @summary Quick test for the new WhiteBox methods of JDK-8275908 + * + * @requires vm.compiler2.enabled & vm.compMode != "Xcomp" + * + * @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 + * -Xbatch -XX:-UseOnStackReplacement -XX:-TieredCompilation + * -XX:CompileCommand=compileonly,compiler.uncommontrap.Decompile::uncommonTrap + * -XX:CompileCommand=inline,compiler.uncommontrap.Decompile*::foo + * compiler.uncommontrap.Decompile + */ + +package compiler.uncommontrap; + +import java.lang.reflect.Method; + +import jdk.test.lib.Asserts; +import jdk.test.whitebox.WhiteBox; + +public class Decompile { + + private static final WhiteBox WB = WhiteBox.getWhiteBox(); + // The number of deoptimizations after which a method will be made not-entrant + private static final int PerBytecodeTrapLimit = WB.getIntxVMFlag("PerBytecodeTrapLimit").intValue(); + // The number of interpreter invocations after which a decompiled method will be re-compiled. + private static final int Tier0InvokeNotifyFreq = (int)Math.pow(2, WB.getIntxVMFlag("Tier0InvokeNotifyFreqLog")); + // VM builds without JVMCI like x86_32 call the bimorphic inlining trap just 'bimorphic' + // while all the other builds with JVMCI call it 'bimorphic_or_optimized_type_check'. + // Only builds with JVMCI have the "EnableJVMCI" flag. + private static final boolean isJVMCISupported = (WB.getBooleanVMFlag("EnableJVMCI") != null); + private static final String bimorphicTrapName = isJVMCISupported ? "bimorphic_or_optimized_type_check" : "bimorphic"; + + static class Base { + void foo() {} + } + static class X extends Base { + void foo() {} + } + static class Y extends Base { + void foo() {} + } + + static void uncommonTrap(Base t) { + t.foo(); + } + + private static void printCounters(Method uncommonTrap_m, int invocations) { + System.out.println("-----------------------------------------------------------------"); + System.out.println("invocations=" + invocations + " " + + "method compiled=" + WB.isMethodCompiled(uncommonTrap_m) + " " + + "decompileCount=" + WB.getMethodDecompileCount(uncommonTrap_m) + "\n" + + "trapCount=" + WB.getMethodTrapCount(uncommonTrap_m) + " " + + "trapCount(class_check)=" + WB.getMethodTrapCount(uncommonTrap_m, "class_check") + " " + + "trapCount(" + bimorphicTrapName + ")=" + + WB.getMethodTrapCount(uncommonTrap_m, bimorphicTrapName) + "\n" + + "globalDeoptCount=" + WB.getDeoptCount() + " " + + "globalDeoptCount(class_check)=" + WB.getDeoptCount("class_check", null) + " " + + "globalDeoptCount(" + bimorphicTrapName + ")=" + + WB.getDeoptCount(bimorphicTrapName, null)); + System.out.println("-----------------------------------------------------------------"); + } + + private static void check(Method uncommonTrap_m, int invocations, boolean isCompiled, int decompileCount, + int trapCount, int trapCountClassCheck, int trapCountBimorphic, + int deoptCount, int deoptCountClassCheck, int deoptCountBimorphic) { + + printCounters(uncommonTrap_m, invocations); + + Asserts.assertEQ(isCompiled, WB.isMethodCompiled(uncommonTrap_m), + "Wrong compilation status."); + Asserts.assertEQ(decompileCount, WB.getMethodDecompileCount(uncommonTrap_m), + "Wrong number of decompilations."); + Asserts.assertEQ(trapCount, WB.getMethodTrapCount(uncommonTrap_m), + "Wrong number of traps."); + Asserts.assertEQ(trapCountClassCheck, WB.getMethodTrapCount(uncommonTrap_m, "class_check"), + "Wrong number of traps."); + Asserts.assertEQ(trapCountBimorphic, WB.getMethodTrapCount(uncommonTrap_m, bimorphicTrapName), + "Wrong number of traps."); + Asserts.assertEQ(deoptCount, WB.getDeoptCount(), + "Wrong number of deoptimizations."); + Asserts.assertEQ(deoptCountClassCheck, WB.getDeoptCount("class_check", null), + "Wrong number of class_check deoptimizations."); + Asserts.assertEQ(deoptCountBimorphic, WB.getDeoptCount(bimorphicTrapName, null), + "Wrong number of " + bimorphicTrapName + "deoptimizations."); + } + public static void main(String[] args) throws Exception { + + // Get a handle of the test method for usage with the WhiteBox API. + Method uncommonTrap_m = Decompile.class + .getDeclaredMethod("uncommonTrap", new Class[] { Base.class }); + + int invocations = 0; + Base b = new Base(); + // This is a little tricky :) We have to define 'x' already here otherwise + // the class 'X' won't be loaded and 'uncommonTrap()' will be compiled without + // a class check but a CHA dependency that class 'B' has no subtypes. + X x = new X(); + Y y = new Y(); + + // Warmup and compile with an object of type 'Base' as receiver, but don't invoke compiled code. + while(!WB.isMethodCompiled(uncommonTrap_m)) { + invocations++; + uncommonTrap(b); + } + check(uncommonTrap_m, invocations, true /* is_compiled */, 0 /* decompileCount */, + 0 /* trapCount */, 0 /* trapCountClassCheck */, 0 /* trapCountBimorphic */, + 0 /* deoptCount */, 0 /* deoptCountClassCheck */, 0 /* deoptCountBimorphic */); + + // Invoke compiled code 'PerBytecodeTrapLimit' times with an receiver object of type 'X'. + // This should deoptimize 'PerBytecodeTrapLimit' times and finally decompile the method. + for (int i = 0; i < PerBytecodeTrapLimit; i++) { + invocations++; + uncommonTrap(x); + } + check(uncommonTrap_m, invocations, false /* is_compiled */, 1 /* decompileCount */, + PerBytecodeTrapLimit /* trapCount */, PerBytecodeTrapLimit /* trapCountClassCheck */, 0 /* trapCountBimorphic */, + PerBytecodeTrapLimit /* deoptCount */, PerBytecodeTrapLimit /* deoptCountClassCheck */, 0 /* deoptCountBimorphic */); + + // Invoke the method 'Tier0InvokeNotifyFreq' more times with an receiver object of type 'X'. + // This should re-compile the method again with bimorphic inlining for receiver types 'Base' and 'X'. + for (int i = 0; i < Tier0InvokeNotifyFreq; i++) { + invocations++; + uncommonTrap(x); + } + check(uncommonTrap_m, invocations, true /* is_compiled */, 1 /* decompileCount */, + PerBytecodeTrapLimit /* trapCount */, PerBytecodeTrapLimit /* trapCountClassCheck */, 0 /* trapCountBimorphic */, + PerBytecodeTrapLimit /* deoptCount */, PerBytecodeTrapLimit /* deoptCountClassCheck */, 0 /* deoptCountBimorphic */); + + // Invoke compiled code 'PerBytecodeTrapLimit' times with an receiver object of type 'Y'. + // This should deoptimize 'PerBytecodeTrapLimit' times and finally decompile the method. + for (int i = 0; i < PerBytecodeTrapLimit; i++) { + invocations++; + uncommonTrap(y); + } + check(uncommonTrap_m, invocations, false /* is_compiled */, 2 /* decompileCount */, + 2*PerBytecodeTrapLimit /* trapCount */, PerBytecodeTrapLimit /* trapCountClassCheck */, PerBytecodeTrapLimit /* trapCountBimorphic */, + 2*PerBytecodeTrapLimit /* deoptCount */, PerBytecodeTrapLimit /* deoptCountClassCheck */, PerBytecodeTrapLimit /* deoptCountBimorphic */); + } +} \ No newline at end of file diff --git a/test/hotspot/jtreg/compiler/uncommontrap/TraceDeoptimizationNoRealloc.java b/test/hotspot/jtreg/compiler/uncommontrap/TraceDeoptimizationNoRealloc.java index 4a371a525b3889ce5bade9e0da2c087e70051f71..4cd10a1a63e9ede9950d16ed48f84eaac10d6d2e 100644 --- a/test/hotspot/jtreg/compiler/uncommontrap/TraceDeoptimizationNoRealloc.java +++ b/test/hotspot/jtreg/compiler/uncommontrap/TraceDeoptimizationNoRealloc.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -27,7 +27,7 @@ * @summary -XX:+TraceDeoptimization tries to print realloc'ed objects even when there are none * * @run main/othervm -XX:-BackgroundCompilation -XX:-UseOnStackReplacement - * -XX:+IgnoreUnrecognizedVMOptions -XX:+TraceDeoptimization + * -XX:+UnlockDiagnosticVMOptions -XX:+TraceDeoptimization * compiler.uncommontrap.TraceDeoptimizationNoRealloc */ diff --git a/test/hotspot/jtreg/compiler/unsafe/TestMisalignedUnsafeAccess.java b/test/hotspot/jtreg/compiler/unsafe/TestMisalignedUnsafeAccess.java index 10d766cf122df8fe5636930e2a76dd2c33e7b99c..84752a0ccf0069189bf4f63482432a7592c78c64 100644 --- a/test/hotspot/jtreg/compiler/unsafe/TestMisalignedUnsafeAccess.java +++ b/test/hotspot/jtreg/compiler/unsafe/TestMisalignedUnsafeAccess.java @@ -37,7 +37,7 @@ import jdk.test.lib.Asserts; public class TestMisalignedUnsafeAccess { - private static final Unsafe UNSAFE = Unsafe.getUnsafe();; + private static final Unsafe UNSAFE = Unsafe.getUnsafe(); private static short onHeapStaticMemory; // For static field testing private static final Object onHeapStaticMemoryBase; diff --git a/test/hotspot/jtreg/compiler/unsafe/UnsafeCopyMemory.java b/test/hotspot/jtreg/compiler/unsafe/UnsafeCopyMemory.java index 51cbb5e8c2fb79678b9c140f003232d87cbe1bf0..950fef40ec0f0a8881b65d49d6cfdf25d2ee00ac 100644 --- a/test/hotspot/jtreg/compiler/unsafe/UnsafeCopyMemory.java +++ b/test/hotspot/jtreg/compiler/unsafe/UnsafeCopyMemory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -36,11 +36,14 @@ package compiler.unsafe; import jdk.internal.misc.Unsafe; +import java.nio.ByteOrder; import static jdk.test.lib.Asserts.assertEQ; public class UnsafeCopyMemory { static private Unsafe UNSAFE = Unsafe.getUnsafe(); + static final boolean IS_BIG_ENDIAN = ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN; + // On-heap arrays static int[] srcArr = new int[1]; static int[] dstArr = new int[1]; @@ -104,8 +107,12 @@ public class UnsafeCopyMemory { srcArr [readIdx] = v1; dstArrL[writeIdx] = v2; + // On LE systems, low-order bytes of long and int overlap, but + // on BE systems, they differ by the size of an int. + long mismatchedOffset = Unsafe.ARRAY_LONG_BASE_OFFSET + (IS_BIG_ENDIAN ? 4 : 0); + UNSAFE.copyMemory(srcArr, Unsafe.ARRAY_INT_BASE_OFFSET, - dstArrL, Unsafe.ARRAY_LONG_BASE_OFFSET, 4); // mismatched + dstArrL, mismatchedOffset, 4); // mismatched long r = resArrL[0]; // snapshot srcArr[readIdx] = v3; @@ -156,6 +163,7 @@ public class UnsafeCopyMemory { Object srcArrLocal = (flag ? srcArrIntLocal : srcArrLongLocal); long srcOffset = (flag ? Unsafe.ARRAY_INT_BASE_OFFSET : Unsafe.ARRAY_LONG_BASE_OFFSET); + srcOffset += (!flag && IS_BIG_ENDIAN ? 4 : 0); srcArrIntLocal[0] = v1; srcArrLongLocal[0] = v1; @@ -179,6 +187,7 @@ public class UnsafeCopyMemory { Object dstArrLocal = (flag ? dstArrIntLocal : dstArrLongLocal); long dstOffset = (flag ? Unsafe.ARRAY_INT_BASE_OFFSET : Unsafe.ARRAY_LONG_BASE_OFFSET); + dstOffset += (!flag && IS_BIG_ENDIAN ? 4 : 0); srcArr[readIdx] = v1; dstArrIntLocal[0] = v2; diff --git a/test/hotspot/jtreg/compiler/vectorapi/Test8278948.java b/test/hotspot/jtreg/compiler/vectorapi/Test8278948.java new file mode 100644 index 0000000000000000000000000000000000000000..5218e10c4af6275bdafa725767f964e06046402c --- /dev/null +++ b/test/hotspot/jtreg/compiler/vectorapi/Test8278948.java @@ -0,0 +1,82 @@ +/* + * 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. + */ + +package compiler.vectorapi; + +import java.util.Random; +import jdk.incubator.vector.ByteVector; +import jdk.incubator.vector.DoubleVector; +import jdk.incubator.vector.ShortVector; +import jdk.test.lib.Asserts; +import jdk.test.lib.Utils; + +/* + * @test + * @bug 8278948 + * @summary Intermediate integer promotion vector length encoding is calculated incorrectly on x86 + * @modules jdk.incubator.vector + * @library /test/lib + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-TieredCompilation -XX:CompileThreshold=100 -XX:UseAVX=1 + * compiler.vectorapi.Test8278948 + */ +public class Test8278948 { + static final int INVOCATIONS = 10000; + + static final Random random = Utils.getRandomInstance(); + static final byte[] BYTES = new byte[8]; + static final short[] SHORTS = new short[4]; + static final double[] DOUBLES = new double[4]; + + + public static void main(String[] args) { + for (int i = 0; i < INVOCATIONS; i++) { + for (int j = 0; j < DOUBLES.length; j++) { + BYTES[j] = (byte)random.nextInt(); + } + bytesToDoubles(); + for (int j = 0; j < DOUBLES.length; j++) { + Asserts.assertEquals((double)BYTES[j], DOUBLES[j]); + } + + for (int j = 0; j < DOUBLES.length; j++) { + SHORTS[j] = (short)random.nextInt(); + } + shortsToDoubles(); + for (int j = 0; j < DOUBLES.length; j++) { + Asserts.assertEquals((double)SHORTS[j], DOUBLES[j]); + } + } + } + + static void bytesToDoubles() { + ((DoubleVector)ByteVector.fromArray(ByteVector.SPECIES_64, BYTES, 0) + .castShape(DoubleVector.SPECIES_256, 0)) + .intoArray(DOUBLES, 0); + } + + static void shortsToDoubles() { + ((DoubleVector)ShortVector.fromArray(ShortVector.SPECIES_64, SHORTS, 0) + .castShape(DoubleVector.SPECIES_256, 0)) + .intoArray(DOUBLES, 0); + } +} diff --git a/test/hotspot/jtreg/compiler/vectorapi/TestLongVectorNeg.java b/test/hotspot/jtreg/compiler/vectorapi/TestLongVectorNeg.java new file mode 100644 index 0000000000000000000000000000000000000000..92cc82b03a46d57b589c06a7c6c8cbc0bb8fd5a6 --- /dev/null +++ b/test/hotspot/jtreg/compiler/vectorapi/TestLongVectorNeg.java @@ -0,0 +1,51 @@ +/* + * 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. + */ + +package compiler.vectorapi; + +import jdk.incubator.vector.LongVector; + +/* + * @test + * @bug 8275643 + * @summary Test that LongVector.neg is properly handled by the _VectorUnaryOp C2 intrinsic + * @modules jdk.incubator.vector + * @requires vm.debug + * @run main/othervm -XX:-TieredCompilation -XX:+AlwaysIncrementalInline -Xbatch + * -XX:CompileCommand=dontinline,compiler.vectorapi.TestLongVectorNeg::test + * compiler.vectorapi.TestLongVectorNeg + */ +public class TestLongVectorNeg { + + static LongVector test(LongVector v) { + return v.neg(); + } + + public static void main(String[] args) { + LongVector v = LongVector.zero(LongVector.SPECIES_128); + for (int i = 0; i < 50_000; ++i) { + v.abs(); // Warmup to make sure the !VO_SPECIAL code path is taken as well + test(v); + } + } +} diff --git a/test/hotspot/jtreg/compiler/vectorapi/TestMaskedMacroLogicVector.java b/test/hotspot/jtreg/compiler/vectorapi/TestMaskedMacroLogicVector.java new file mode 100644 index 0000000000000000000000000000000000000000..0c303f8c39f0ed7fd05ea53b3cfce1f47418ff04 --- /dev/null +++ b/test/hotspot/jtreg/compiler/vectorapi/TestMaskedMacroLogicVector.java @@ -0,0 +1,841 @@ +/* + * 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. + */ + +/** + * @test + * @bug 8273322 + * @key randomness + * @summary Enhance macro logic optimization for masked logic operations. + * @modules jdk.incubator.vector + * @requires vm.compiler2.enabled + * @requires os.simpleArch == "x64" + * @library /test/lib / + * @run driver compiler.vectorapi.TestMaskedMacroLogicVector + */ + +package compiler.vectorapi; + +import java.util.concurrent.Callable; +import compiler.lib.ir_framework.*; +import jdk.test.lib.Utils; +import java.util.Random; + +import jdk.incubator.vector.*; + +public class TestMaskedMacroLogicVector { + boolean [] br; + boolean [] ba; + boolean [] bb; + + short [] sr; + char [] ca; + char [] cb; + + int [] r; + int [] a; + int [] b; + int [] c; + int [] d; + int [] e; + int [] f; + + long [] rl; + long [] al; + long [] bl; + long [] cl; + + boolean [] mask; + + static boolean booleanFunc1(boolean a, boolean b) { + return a & b; + } + + @Test + @IR(applyIf = {"UseAVX", "3"}, counts = {"MacroLogicV" , " > 0 "}) + public void testSubWordBoolean(boolean[] r, boolean[] a, boolean[] b) { + for (int i = 0; i < r.length; i++) { + r[i] = booleanFunc1(a[i], b[i]); + } + } + public void verifySubWordBoolean(boolean[] r, boolean[] a, boolean[] b) { + for (int i = 0; i < r.length; i++) { + boolean expected = booleanFunc1(a[i], b[i]); + if (r[i] != expected) { + throw new AssertionError( + String.format("at #%d: r=%b, expected = %b = booleanFunc1(%b,%b)", + i, r[i], expected, a[i], b[i])); + } + } + } + + + static short charFunc1(char a, char b) { + return (short)((a & b) & 1); + } + + @Test + @IR(applyIf = {"UseAVX", "3"}, counts = {"MacroLogicV" , " > 0 "}) + public void testSubWordChar(short[] r, char[] a, char[] b) { + for (int i = 0; i < r.length; i++) { + r[i] = charFunc1(a[i], b[i]); + } + } + public void verifySubWordChar(short[] r, char[] a, char[] b) { + for (int i = 0; i < r.length; i++) { + short expected = charFunc1(a[i], b[i]); + if (r[i] != expected) { + throw new AssertionError( + String.format("testSubWordChar: at #%d: r=%d, expected = %d = booleanFunc1(%d,%d)", + i, r[i], expected, (int)a[i], (int)b[i])); + } + } + } + + // Case 1): Unmasked expression tree. + // P_LOP + // L_LOP R_LOP + + static int intFunc1(int a, int b, int c) { + return (a & b) ^ (a & c); + } + + @ForceInline + public void testInt1Kernel(VectorSpecies SPECIES, int [] r, int [] a, int [] b, int [] c) { + for (int i = 0; i < SPECIES.loopBound(r.length); i += SPECIES.length()) { + IntVector va = IntVector.fromArray(SPECIES, a, i); + IntVector vb = IntVector.fromArray(SPECIES, b, i); + IntVector vc = IntVector.fromArray(SPECIES, c, i); + va.lanewise(VectorOperators.AND, vc) + .lanewise(VectorOperators.XOR, va.lanewise(VectorOperators.AND, vb)) + .intoArray(r, i); + } + } + + @Test + @IR(applyIf = {"UseAVX", "3"}, counts = {"MacroLogicV", " > 0 "}) + public void testInt1_Int128(int[] r, int[] a, int[] b, int[] c) { + testInt1Kernel(IntVector.SPECIES_128, r, a, b, c); + } + + @Test + @IR(applyIf = {"UseAVX", "3"}, counts = {"MacroLogicV", " > 0 "}) + public void testInt1_Int256(int[] r, int[] a, int[] b, int[] c) { + testInt1Kernel(IntVector.SPECIES_256, r, a, b, c); + } + + @Test + @IR(applyIf = {"UseAVX", "3"}, counts = {"MacroLogicV", " > 0 "}) + public void testInt1_Int512(int[] r, int[] a, int[] b, int[] c) { + testInt1Kernel(IntVector.SPECIES_512, r, a, b, c); + } + + public void verifyInt1(int[] r, int[] a, int[] b, int[] c) { + for (int i = 0; i < r.length; i++) { + int expected = intFunc1(a[i], b[i], c[i]); + if (r[i] != expected) { + throw new AssertionError(String.format("testInt1: at #%d: r=%d, expected = %d = intFunc1(%d,%d,%d)", + i, r[i], expected, a[i], b[i], c[i])); + } + } + } + + // Case 2): Only right child is masked. + // P_LOP + // L_LOP R_LOP(mask) + + static int intFunc2(int a, int b, int c, boolean mask) { + return (a & b) ^ (mask == true ? a & c : a); + } + + @ForceInline + public void testInt2Kernel(VectorSpecies SPECIES, int[] r, int[] a, int[] b, int[] c, boolean [] mask) { + for (int i = 0; i < SPECIES.loopBound(r.length); i += SPECIES.length()) { + VectorMask<Integer> vmask = VectorMask.fromArray(SPECIES, mask , i); + IntVector va = IntVector.fromArray(SPECIES, a, i); + IntVector vb = IntVector.fromArray(SPECIES, b, i); + IntVector vc = IntVector.fromArray(SPECIES, c, i); + va.lanewise(VectorOperators.AND, vb) + .lanewise(VectorOperators.XOR, + va.lanewise(VectorOperators.AND, vc, vmask)) + .intoArray(r, i); + } + } + + @Test + @IR(applyIf = {"UseAVX", "3"}, counts = {"MacroLogicV", " > 0 "}) + public void testInt2_Int128(int[] r, int[] a, int[] b, int[] c, boolean [] mask) { + testInt2Kernel(IntVector.SPECIES_128, r, a, b, c, mask); + } + @Test + @IR(applyIf = {"UseAVX", "3"}, counts = {"MacroLogicV", " > 0 "}) + public void testInt2_Int256(int[] r, int[] a, int[] b, int[] c, boolean [] mask) { + testInt2Kernel(IntVector.SPECIES_256, r, a, b, c, mask); + } + @Test + @IR(applyIf = {"UseAVX", "3"}, counts = {"MacroLogicV", " > 0 "}) + public void testInt2_Int512(int[] r, int[] a, int[] b, int[] c, boolean [] mask) { + testInt2Kernel(IntVector.SPECIES_512, r, a, b, c, mask); + } + + public void verifyInt2(int[] r, int[] a, int[] b, int[] c, boolean [] mask) { + for (int i = 0; i < r.length; i++) { + int expected = intFunc2(a[i], b[i], c[i], mask[i]); + if (r[i] != expected) { + throw new AssertionError(String.format("testInt2: at #%d: r=%d, expected = %d = intFunc2(%d,%d,%d,%b)", + i, r[i], expected, a[i], b[i], c[i], mask[i])); + } + } + } + + // Case 3): Only left child is masked. + // P_LOP + // L_LOP(mask) R_LOP + + static int intFunc3(int a, int b, int c, boolean mask) { + return (mask == true ? a & b : a) ^ (a & c); + } + + @ForceInline + public void testInt3Kernel(VectorSpecies SPECIES, int[] r, int[] a, int[] b, int[] c, boolean [] mask) { + for (int i = 0; i < SPECIES.loopBound(r.length); i += SPECIES.length()) { + VectorMask<Integer> vmask = VectorMask.fromArray(SPECIES, mask , i); + IntVector va = IntVector.fromArray(SPECIES, a, i); + IntVector vb = IntVector.fromArray(SPECIES, b, i); + IntVector vc = IntVector.fromArray(SPECIES, c, i); + va.lanewise(VectorOperators.AND, vb, vmask) + .lanewise(VectorOperators.XOR, + va.lanewise(VectorOperators.AND, vc)) + .intoArray(r, i); + } + } + + @Test + @IR(applyIf = {"UseAVX", "3"}, counts = {"MacroLogicV", " > 0 "}) + public void testInt3_Int128(int[] r, int[] a, int[] b, int[] c, boolean [] mask) { + testInt3Kernel(IntVector.SPECIES_128, r, a, b, c, mask); + } + @Test + @IR(applyIf = {"UseAVX", "3"}, counts = {"MacroLogicV", " > 0 "}) + public void testInt3_Int256(int[] r, int[] a, int[] b, int[] c, boolean [] mask) { + testInt3Kernel(IntVector.SPECIES_256, r, a, b, c, mask); + } + @Test + @IR(applyIf = {"UseAVX", "3"}, counts = {"MacroLogicV", " > 0 "}) + public void testInt3_Int512(int[] r, int[] a, int[] b, int[] c, boolean [] mask) { + testInt3Kernel(IntVector.SPECIES_512, r, a, b, c, mask); + } + + + @ForceInline + public void verifyInt3(int[] r, int[] a, int[] b, int[] c, boolean [] mask) { + for (int i = 0; i < r.length; i++) { + int expected = intFunc3(a[i], b[i], c[i], mask[i]); + if (r[i] != expected) { + throw new AssertionError(String.format("testInt3: at #%d: r=%d, expected = %d = intFunc3(%d,%d,%d,%b)", + i, r[i], expected, a[i], b[i], c[i], mask[i])); + } + } + } + + // Case 4): Both child nodes are masked. + // P_LOP + // L_LOP(mask) R_LOP(mask) + + static int intFunc4(int a, int b, int c, boolean mask) { + return (mask == true ? b & a : b) ^ (mask == true ? c & a : c); + } + + @ForceInline + public void testInt4Kernel(VectorSpecies SPECIES, int[] r, int[] a, int[] b, int[] c, boolean [] mask) { + for (int i = 0; i < SPECIES.loopBound(r.length); i += SPECIES.length()) { + VectorMask<Integer> vmask = VectorMask.fromArray(SPECIES, mask , i); + IntVector va = IntVector.fromArray(SPECIES, a, i); + IntVector vb = IntVector.fromArray(SPECIES, b, i); + IntVector vc = IntVector.fromArray(SPECIES, c, i); + vb.lanewise(VectorOperators.AND, va, vmask) + .lanewise(VectorOperators.XOR, + vc.lanewise(VectorOperators.AND, va, vmask)) + .intoArray(r, i); + } + } + + @Test + @IR(applyIf = {"UseAVX", "3"}, counts = {"AndV", " > 0 ", "XorV", " > 0 "}) + public void testInt4_Int128(int[] r, int[] a, int[] b, int[] c, boolean [] mask) { + testInt4Kernel(IntVector.SPECIES_128, r, a, b, c, mask); + } + @Test + @IR(applyIf = {"UseAVX", "3"}, counts = {"AndV", " > 0 ", "XorV", " > 0 "}) + public void testInt4_Int256(int[] r, int[] a, int[] b, int[] c, boolean [] mask) { + testInt4Kernel(IntVector.SPECIES_256, r, a, b, c, mask); + } + @Test + @IR(applyIf = {"UseAVX", "3"}, counts = {"AndV", " > 0 ", "XorV", " > 0 "}) + public void testInt4_Int512(int[] r, int[] a, int[] b, int[] c, boolean [] mask) { + testInt4Kernel(IntVector.SPECIES_512, r, a, b, c, mask); + } + + public void verifyInt4(int[] r, int[] a, int[] b, int[] c, boolean [] mask) { + for (int i = 0; i < r.length; i++) { + int expected = intFunc4(a[i], b[i], c[i], mask[i]); + if (r[i] != expected) { + throw new AssertionError(String.format("testInt4: at #%d: r=%d, expected = %d = intFunc4(%d,%d,%d,%b)", + i, r[i], expected, a[i], b[i], c[i], mask[i])); + } + } + } + + // Case 5): Parent is masked with unmasked child expressions. + // P_LOP(mask) + // L_LOP R_LOP + + static int intFunc5(int a, int b, int c, boolean mask) { + return mask == true ? ((a & b) ^ (a & c)) : (a & b); + } + + @ForceInline + public void testInt5Kernel(VectorSpecies SPECIES, int[] r, int[] a, int[] b, int[] c, boolean [] mask) { + for (int i = 0; i < SPECIES.loopBound(r.length); i += SPECIES.length()) { + VectorMask<Integer> vmask = VectorMask.fromArray(SPECIES, mask , i); + IntVector va = IntVector.fromArray(SPECIES, a, i); + IntVector vb = IntVector.fromArray(SPECIES, b, i); + IntVector vc = IntVector.fromArray(SPECIES, c, i); + va.lanewise(VectorOperators.AND, vb) + .lanewise(VectorOperators.XOR, + va.lanewise(VectorOperators.AND, vc), vmask) + .intoArray(r, i); + } + } + + @Test + @IR(applyIf = {"UseAVX", "3"}, counts = {"MacroLogicV", " > 0 "}) + public void testInt5_Int128(int[] r, int[] a, int[] b, int[] c, boolean [] mask) { + testInt5Kernel(IntVector.SPECIES_128, r, a, b, c, mask); + } + @Test + @IR(applyIf = {"UseAVX", "3"}, counts = {"MacroLogicV", " > 0 "}) + public void testInt5_Int256(int[] r, int[] a, int[] b, int[] c, boolean [] mask) { + testInt5Kernel(IntVector.SPECIES_256, r, a, b, c, mask); + } + @Test + @IR(applyIf = {"UseAVX", "3"}, counts = {"MacroLogicV", " > 0 "}) + public void testInt5_Int512(int[] r, int[] a, int[] b, int[] c, boolean [] mask) { + testInt5Kernel(IntVector.SPECIES_512, r, a, b, c, mask); + } + + @ForceInline + public void verifyInt5(int[] r, int[] a, int[] b, int[] c, boolean [] mask) { + for (int i = 0; i < r.length; i++) { + int expected = intFunc5(a[i], b[i], c[i], mask[i]); + if (r[i] != expected) { + throw new AssertionError(String.format("testInt5: at #%d: r=%d, expected = %d = intFunc5(%d,%d,%d,%b)", + i, r[i], expected, a[i], b[i], c[i], mask[i])); + } + } + } + + // Case 6): Parent and right child are masked. + // P_LOP(mask) + // L_LOP R_LOP(mask) + + static int intFunc6(int a, int b, int c, boolean mask) { + return mask == true ? ((a & b) ^ (mask == true ? a & c : a)) : (a & b); + } + + @ForceInline + public void testInt6Kernel(VectorSpecies SPECIES, int[] r, int[] a, int[] b, int[] c, boolean [] mask) { + for (int i = 0; i < SPECIES.loopBound(r.length); i += SPECIES.length()) { + VectorMask<Integer> vmask = VectorMask.fromArray(SPECIES, mask , i); + IntVector va = IntVector.fromArray(SPECIES, a, i); + IntVector vb = IntVector.fromArray(SPECIES, b, i); + IntVector vc = IntVector.fromArray(SPECIES, c, i); + va.lanewise(VectorOperators.AND, vb) + .lanewise(VectorOperators.XOR, + va.lanewise(VectorOperators.AND, vc, vmask), vmask) + .intoArray(r, i); + } + } + @Test + @IR(applyIf = {"UseAVX", "3"}, counts = {"MacroLogicV", " > 0 "}) + public void testInt6_Int128(int[] r, int[] a, int[] b, int[] c, boolean [] mask) { + testInt6Kernel(IntVector.SPECIES_128, r, a, b, c, mask); + } + @Test + @IR(applyIf = {"UseAVX", "3"}, counts = {"MacroLogicV", " > 0 "}) + public void testInt6_Int256(int[] r, int[] a, int[] b, int[] c, boolean [] mask) { + testInt6Kernel(IntVector.SPECIES_256, r, a, b, c, mask); + } + @Test + @IR(applyIf = {"UseAVX", "3"}, counts = {"MacroLogicV", " > 0 "}) + public void testInt6_Int512(int[] r, int[] a, int[] b, int[] c, boolean [] mask) { + testInt6Kernel(IntVector.SPECIES_512, r, a, b, c, mask); + } + + + public void verifyInt6(int[] r, int[] a, int[] b, int[] c, boolean [] mask) { + for (int i = 0; i < r.length; i++) { + int expected = intFunc6(a[i], b[i], c[i], mask[i]); + if (r[i] != expected) { + throw new AssertionError(String.format("testInt6: at #%d: r=%d, expected = %d = intFunc6(%d,%d,%d,%b)", + i, r[i], expected, a[i], b[i], c[i], mask[i])); + } + } + } + + // Case 7): Parent and left child are masked. + // P_LOP(mask) + // L_LOP(mask) R_LOP + + static int intFunc7(int a, int b, int c, boolean mask) { + return mask == true ? ((mask == true ? a & b : a) ^ (a & c)) : a; + } + + @ForceInline + public void testInt7Kernel(VectorSpecies SPECIES, int[] r, int[] a, int[] b, int[] c, boolean [] mask) { + for (int i = 0; i < SPECIES.loopBound(r.length); i += SPECIES.length()) { + VectorMask<Integer> vmask = VectorMask.fromArray(SPECIES, mask , i); + IntVector va = IntVector.fromArray(SPECIES, a, i); + IntVector vb = IntVector.fromArray(SPECIES, b, i); + IntVector vc = IntVector.fromArray(SPECIES, c, i); + va.lanewise(VectorOperators.AND, vb, vmask) + .lanewise(VectorOperators.XOR, + va.lanewise(VectorOperators.AND, vc), vmask) + .intoArray(r, i); + } + } + + @Test + @IR(applyIf = {"UseAVX", "3"}, counts = {"MacroLogicV", " > 0 "}) + public void testInt7_Int128(int[] r, int[] a, int[] b, int[] c, boolean [] mask) { + testInt7Kernel(IntVector.SPECIES_128, r, a, b, c, mask); + } + @Test + @IR(applyIf = {"UseAVX", "3"}, counts = {"MacroLogicV", " > 0 "}) + public void testInt7_Int256(int[] r, int[] a, int[] b, int[] c, boolean [] mask) { + testInt7Kernel(IntVector.SPECIES_256, r, a, b, c, mask); + } + @Test + @IR(applyIf = {"UseAVX", "3"}, counts = {"MacroLogicV", " > 0 "}) + public void testInt7_Int512(int[] r, int[] a, int[] b, int[] c, boolean [] mask) { + testInt7Kernel(IntVector.SPECIES_512, r, a, b, c, mask); + } + + public void verifyInt7(int[] r, int[] a, int[] b, int[] c, boolean [] mask) { + for (int i = 0; i < r.length; i++) { + int expected = intFunc7(a[i], b[i], c[i], mask[i]); + if (r[i] != expected) { + throw new AssertionError(String.format("testInt7: at #%d: r=%d, expected = %d = intFunc7(%d,%d,%d,%b)", + i, r[i], expected, a[i], b[i], c[i], mask[i])); + } + } + } + + // Case 8): Parent and both child expressions are masked. + // P_LOP(mask) + // L_LOP(mask) R_LOP (mask) + + static int intFunc8(int a, int b, int c, boolean mask) { + return mask == true ? ((mask == true ? b & a : b) ^ (mask == true ? c & a : c)) : b; + } + + @ForceInline + public void testInt8Kernel(VectorSpecies SPECIES, int[] r, int[] a, int[] b, int[] c, boolean [] mask) { + for (int i = 0; i < SPECIES.loopBound(r.length); i += SPECIES.length()) { + VectorMask<Integer> vmask = VectorMask.fromArray(SPECIES, mask , i); + IntVector va = IntVector.fromArray(SPECIES, a, i); + IntVector vb = IntVector.fromArray(SPECIES, b, i); + IntVector vc = IntVector.fromArray(SPECIES, c, i); + vb.lanewise(VectorOperators.AND, va, vmask) + .lanewise(VectorOperators.XOR, + vc.lanewise(VectorOperators.AND, va, vmask), vmask) + .intoArray(r, i); + } + } + + @Test + @IR(applyIf = {"UseAVX", "3"}, counts = {"MacroLogicV", " > 0 "}) + public void testInt8_Int128(int[] r, int[] a, int[] b, int[] c, boolean [] mask) { + testInt8Kernel(IntVector.SPECIES_128, r, a, b, c, mask); + } + @Test + @IR(applyIf = {"UseAVX", "3"}, counts = {"MacroLogicV", " > 0 "}) + public void testInt8_Int256(int[] r, int[] a, int[] b, int[] c, boolean [] mask) { + testInt8Kernel(IntVector.SPECIES_256, r, a, b, c, mask); + } + @Test + @IR(applyIf = {"UseAVX", "3"}, counts = {"MacroLogicV", " > 0 "}) + public void testInt8_Int512(int[] r, int[] a, int[] b, int[] c, boolean [] mask) { + testInt8Kernel(IntVector.SPECIES_512, r, a, b, c, mask); + } + + public void verifyInt8(int[] r, int[] a, int[] b, int[] c, boolean [] mask) { + for (int i = 0; i < r.length; i++) { + int expected = intFunc8(a[i], b[i], c[i], mask[i]); + if (r[i] != expected) { + throw new AssertionError(String.format("testInt8: at #%d: r=%d, expected = %d = intFunc8(%d,%d,%d,%b)", + i, r[i], expected, a[i], b[i], c[i], mask[i])); + } + } + } + + + // ===================================================== // + + static long longFunc(long a, long b, long c) { + long v1 = (a & b) ^ (a & c) ^ (b & c); + long v2 = (~a & b) | (~b & c) | (~c & a); + return v1 & v2; + } + + @ForceInline + public void testLongKernel(VectorSpecies SPECIES, long[] r, long[] a, long[] b, long[] c) { + for (int i = 0; i < SPECIES.loopBound(r.length); i += SPECIES.length()) { + LongVector va = LongVector.fromArray(SPECIES, a, i); + LongVector vb = LongVector.fromArray(SPECIES, b, i); + LongVector vc = LongVector.fromArray(SPECIES, c, i); + + va.lanewise(VectorOperators.AND, vb) + .lanewise(VectorOperators.XOR, va.lanewise(VectorOperators.AND, vc)) + .lanewise(VectorOperators.XOR, vb.lanewise(VectorOperators.AND, vc)) + .lanewise(VectorOperators.AND, + va.lanewise(VectorOperators.NOT).lanewise(VectorOperators.AND, vb) + .lanewise(VectorOperators.OR, vb.lanewise(VectorOperators.NOT).lanewise(VectorOperators.AND, vc)) + .lanewise(VectorOperators.OR, vc.lanewise(VectorOperators.NOT).lanewise(VectorOperators.AND, va))) + .intoArray(r, i); + } + } + + @Test + @IR(applyIf = {"UseAVX", "3"}, counts = {"MacroLogicV", " > 0 "}) + public void testLong_Long256(long[] r, long[] a, long[] b, long[] c) { + testLongKernel(LongVector.SPECIES_256, r, a, b, c); + } + @Test + @IR(applyIf = {"UseAVX", "3"}, counts = {"MacroLogicV", " > 0 "}) + public void testLong_Long512(long[] r, long[] a, long[] b, long[] c) { + testLongKernel(LongVector.SPECIES_512, r, a, b, c); + } + + public void verifyLong(long[] r, long[] a, long[] b, long[] c) { + for (int i = 0; i < r.length; i++) { + long expected = longFunc(a[i], b[i], c[i]); + if (r[i] != expected) { + throw new AssertionError( + String.format("testLong: at #%d: r=%d, expected = %d = longFunc(%d,%d,%d)", + i, r[i], expected, a[i], b[i], c[i])); + } + } + } + + // ===================================================== // + + private static final Random R = Utils.getRandomInstance(); + + static boolean[] fillBooleanRandom(Callable<boolean[]> factory) { + try { + boolean[] arr = factory.call(); + for (int i = 0; i < arr.length; i++) { + arr[i] = R.nextBoolean(); + } + return arr; + } catch (Exception e) { + throw new InternalError(e); + } + } + static char[] fillCharRandom(Callable<char[]> factory) { + try { + char[] arr = factory.call(); + for (int i = 0; i < arr.length; i++) { + arr[i] = (char)R.nextInt(); + } + return arr; + } catch (Exception e) { + throw new InternalError(e); + } + } + static int[] fillIntRandom(Callable<int[]> factory) { + try { + int[] arr = factory.call(); + for (int i = 0; i < arr.length; i++) { + arr[i] = R.nextInt(); + } + return arr; + } catch (Exception e) { + throw new InternalError(e); + } + } + static long[] fillLongRandom(Callable<long[]> factory) { + try { + long[] arr = factory.call(); + for (int i = 0; i < arr.length; i++) { + arr[i] = R.nextLong(); + } + return arr; + } catch (Exception e) { + throw new InternalError(e); + } + } + + // ===================================================== // + + static final int SIZE = 512; + + @Run(test = {"testInt4_Int128"}, mode = RunMode.STANDALONE) + public void kernel_testInt4_Int128() { + for (int i = 0; i < 10000; i++) { + testInt4_Int128(r, a, b, c, mask); + verifyInt4(r, a, b, c, mask); + } + } + @Run(test = {"testInt4_Int256"}, mode = RunMode.STANDALONE) + public void kernel_testInt4_Int256() { + for (int i = 0; i < 10000; i++) { + testInt4_Int256(r, a, b, c, mask); + verifyInt4(r, a, b, c, mask); + } + } + @Run(test = {"testInt4_Int512"}, mode = RunMode.STANDALONE) + public void kernel_testInt4_Int512() { + for (int i = 0; i < 10000; i++) { + testInt4_Int512(r, a, b, c, mask); + verifyInt4(r, a, b, c, mask); + } + } + + @Run(test = {"testSubWordBoolean"}, mode = RunMode.STANDALONE) + public void kernel_test_SubWordBoolean() { + for (int i = 0; i < 10000; i++) { + testSubWordBoolean(br, ba, bb); + verifySubWordBoolean(br, ba, bb); + } + } + + @Run(test = {"testSubWordChar"}, mode = RunMode.STANDALONE) + public void kernel_test_SubWordChar() { + for (int i = 0; i < 10000; i++) { + testSubWordChar(sr, ca, cb); + verifySubWordChar(sr, ca, cb); + } + } + + @Run(test = {"testInt1_Int128"}, mode = RunMode.STANDALONE) + public void kernel_testInt1_Int128() { + for (int i = 0; i < 10000; i++) { + testInt1_Int128(r, a, b, c); + verifyInt1(r, a, b, c); + } + } + @Run(test = {"testInt1_Int256"}, mode = RunMode.STANDALONE) + public void kernel_testInt1_Int256() { + for (int i = 0; i < 10000; i++) { + testInt1_Int256(r, a, b, c); + verifyInt1(r, a, b, c); + } + } + @Run(test = {"testInt1_Int512"}, mode = RunMode.STANDALONE) + public void kernel_testInt1_Int512() { + for (int i = 0; i < 10000; i++) { + testInt1_Int512(r, a, b, c); + verifyInt1(r, a, b, c); + } + } + + @Run(test = {"testInt2_Int128"}, mode = RunMode.STANDALONE) + public void kernel_testInt2_Int128() { + for (int i = 0; i < 10000; i++) { + testInt2_Int128(r, a, b, c, mask); + verifyInt2(r, a, b, c, mask); + } + } + @Run(test = {"testInt2_Int256"}, mode = RunMode.STANDALONE) + public void kernel_testInt2_Int256() { + for (int i = 0; i < 10000; i++) { + testInt2_Int256(r, a, b, c, mask); + verifyInt2(r, a, b, c, mask); + } + } + @Run(test = {"testInt2_Int512"}, mode = RunMode.STANDALONE) + public void kernel_testInt2_Int512() { + for (int i = 0; i < 10000; i++) { + testInt2_Int512(r, a, b, c, mask); + verifyInt2(r, a, b, c, mask); + } + } + + @Run(test = {"testInt3_Int128"}, mode = RunMode.STANDALONE) + public void kernel_testInt3_Int128() { + for (int i = 0; i < 10000; i++) { + testInt3_Int128(r, a, b, c, mask); + verifyInt3(r, a, b, c, mask); + } + } + @Run(test = {"testInt3_Int256"}, mode = RunMode.STANDALONE) + public void kernel_testInt3_Int256() { + for (int i = 0; i < 10000; i++) { + testInt3_Int256(r, a, b, c, mask); + verifyInt3(r, a, b, c, mask); + } + } + @Run(test = {"testInt3_Int512"}, mode = RunMode.STANDALONE) + public void kernel_testInt3_Int512() { + for (int i = 0; i < 10000; i++) { + testInt3_Int512(r, a, b, c, mask); + verifyInt3(r, a, b, c, mask); + } + } + + @Run(test = {"testInt5_Int128"}, mode = RunMode.STANDALONE) + public void kernel_testInt5_128() { + for (int i = 0; i < 10000; i++) { + testInt5_Int128(r, a, b, c, mask); + verifyInt5(r, a, b, c, mask); + } + } + @Run(test = {"testInt5_Int256"}, mode = RunMode.STANDALONE) + public void kernel_testInt5_256() { + for (int i = 0; i < 10000; i++) { + testInt5_Int256(r, a, b, c, mask); + verifyInt5(r, a, b, c, mask); + } + } + @Run(test = {"testInt5_Int512"}, mode = RunMode.STANDALONE) + public void kernel_testInt5_Int512() { + for (int i = 0; i < 10000; i++) { + testInt5_Int512(r, a, b, c, mask); + verifyInt5(r, a, b, c, mask); + } + } + + @Run(test = {"testInt6_Int128"}, mode = RunMode.STANDALONE) + public void kernel_testInt6_Int128() { + for (int i = 0; i < 10000; i++) { + testInt6_Int128(r, a, b, c, mask); + verifyInt6(r, a, b, c, mask); + } + } + @Run(test = {"testInt6_Int256"}, mode = RunMode.STANDALONE) + public void kernel_testInt6_Int256() { + for (int i = 0; i < 10000; i++) { + testInt6_Int256(r, a, b, c, mask); + verifyInt6(r, a, b, c, mask); + } + } + @Run(test = {"testInt6_Int512"}, mode = RunMode.STANDALONE) + public void kernel_testInt6_Int512() { + for (int i = 0; i < 10000; i++) { + testInt6_Int512(r, a, b, c, mask); + verifyInt6(r, a, b, c, mask); + } + } + + @Run(test = {"testInt7_Int128"}, mode = RunMode.STANDALONE) + public void kernel_testInt7_Int128() { + for (int i = 0; i < 10000; i++) { + testInt7_Int128(r, a, b, c, mask); + verifyInt7(r, a, b, c, mask); + } + } + @Run(test = {"testInt7_Int256"}, mode = RunMode.STANDALONE) + public void kernel_testInt7_Int256() { + for (int i = 0; i < 10000; i++) { + testInt7_Int256(r, a, b, c, mask); + verifyInt7(r, a, b, c, mask); + } + } + @Run(test = {"testInt7_Int512"}, mode = RunMode.STANDALONE) + public void kernel_testInt7_Int512() { + for (int i = 0; i < 10000; i++) { + testInt7_Int512(r, a, b, c, mask); + verifyInt7(r, a, b, c, mask); + } + } + + @Run(test = {"testInt8_Int128"}, mode = RunMode.STANDALONE) + public void kernel_testInt8_Int128() { + for (int i = 0; i < 10000; i++) { + testInt8_Int128(r, a, b, c, mask); + verifyInt8(r, a, b, c, mask); + } + } + @Run(test = {"testInt8_Int256"}, mode = RunMode.STANDALONE) + public void kernel_testInt8_Int256() { + for (int i = 0; i < 10000; i++) { + testInt8_Int256(r, a, b, c, mask); + verifyInt8(r, a, b, c, mask); + } + } + @Run(test = {"testInt8_Int512"}, mode = RunMode.STANDALONE) + public void kernel_testInt8_Int512() { + for (int i = 0; i < 10000; i++) { + testInt8_Int512(r, a, b, c, mask); + verifyInt8(r, a, b, c, mask); + } + } + + @Run(test = {"testLong_Long256"}, mode = RunMode.STANDALONE) + public void kernel_testLong_Long256() { + for (int i = 0; i < 10000; i++) { + testLong_Long256(rl, al, bl, cl); + verifyLong(rl, al, bl, cl); + } + } + @Run(test = {"testLong_Long512"}, mode = RunMode.STANDALONE) + public void kernel_testLong_Long512() { + for (int i = 0; i < 10000; i++) { + testLong_Long512(rl, al, bl, cl); + verifyLong(rl, al, bl, cl); + } + } + + public TestMaskedMacroLogicVector() { + br = new boolean[SIZE]; + ba = fillBooleanRandom((()-> new boolean[SIZE])); + bb = fillBooleanRandom((()-> new boolean[SIZE])); + + sr = new short[SIZE]; + ca = fillCharRandom((()-> new char[SIZE])); + cb = fillCharRandom((()-> new char[SIZE])); + + r = new int[SIZE]; + a = fillIntRandom(()-> new int[SIZE]); + b = fillIntRandom(()-> new int[SIZE]); + c = fillIntRandom(()-> new int[SIZE]); + d = fillIntRandom(()-> new int[SIZE]); + e = fillIntRandom(()-> new int[SIZE]); + f = fillIntRandom(()-> new int[SIZE]); + + rl = new long[SIZE]; + al = fillLongRandom(() -> new long[SIZE]); + bl = fillLongRandom(() -> new long[SIZE]); + cl = fillLongRandom(() -> new long[SIZE]); + + mask = fillBooleanRandom((()-> new boolean[SIZE])); + } + + public static void main(String[] args) { + TestFramework.runWithFlags("-XX:-TieredCompilation", + "-XX:UseAVX=3", + "--add-modules=jdk.incubator.vector", + "-XX:CompileThresholdScaling=0.3"); + } +} diff --git a/test/hotspot/jtreg/compiler/vectorapi/VectorMaskLoadStoreTest.java b/test/hotspot/jtreg/compiler/vectorapi/VectorMaskLoadStoreTest.java index 669608b824b6a2aae78d7e519e2846bba14bd3e6..655681f87a83cfa5e5daae9ecb71d063d79ae227 100644 --- a/test/hotspot/jtreg/compiler/vectorapi/VectorMaskLoadStoreTest.java +++ b/test/hotspot/jtreg/compiler/vectorapi/VectorMaskLoadStoreTest.java @@ -49,6 +49,18 @@ import org.testng.annotations.Test; * @run testng/othervm -XX:-TieredCompilation -XX:CompileThreshold=100 compiler.vectorapi.VectorMaskLoadStoreTest */ +/** + * @test + * @bug 8278584 + * @library /test/lib + * @summary Test the codegen for C2's VectorLongToMaskNode + * "-XX:DisableIntrinsic=_VectorMaskOp" is required to break "VectorMaskToLong (VectorLongToMask l) ==> l" opt. + * This is because when _VectorMaskOp is disabled, VectorMaskToLong won't be generated. + * @modules jdk.incubator.vector + * + * @run testng/othervm -XX:-TieredCompilation -XX:CompileThreshold=100 -XX:+UnlockDiagnosticVMOptions + * -XX:DisableIntrinsic=_VectorMaskOp compiler.vectorapi.VectorMaskLoadStoreTest + */ public class VectorMaskLoadStoreTest{ diff --git a/test/hotspot/jtreg/compiler/vectorapi/reshape/TestVectorCastAVX1.java b/test/hotspot/jtreg/compiler/vectorapi/reshape/TestVectorCastAVX1.java new file mode 100644 index 0000000000000000000000000000000000000000..a83364fa51cd8a029a80fdb2bad12089f28b5ab1 --- /dev/null +++ b/test/hotspot/jtreg/compiler/vectorapi/reshape/TestVectorCastAVX1.java @@ -0,0 +1,47 @@ +/* + * 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. + */ + +package compiler.vectorapi.reshape; + +import compiler.vectorapi.reshape.tests.TestVectorCast; +import compiler.vectorapi.reshape.utils.TestCastMethods; +import compiler.vectorapi.reshape.utils.VectorReshapeHelper; + +/* + * @test + * @bug 8259610 + * @modules jdk.incubator.vector + * @modules java.base/jdk.internal.misc + * @summary Test that vector cast intrinsics work as intended on avx1. + * @requires vm.cpu.features ~= ".*avx.*" + * @library /test/lib / + * @run driver compiler.vectorapi.reshape.TestVectorCastAVX1 + */ +public class TestVectorCastAVX1 { + public static void main(String[] args) { + VectorReshapeHelper.runMainHelper( + TestVectorCast.class, + TestCastMethods.AVX1_CAST_TESTS.stream(), + "-XX:UseAVX=1"); + } +} diff --git a/test/hotspot/jtreg/compiler/vectorapi/reshape/TestVectorCastAVX2.java b/test/hotspot/jtreg/compiler/vectorapi/reshape/TestVectorCastAVX2.java new file mode 100644 index 0000000000000000000000000000000000000000..1b50613598b2669b12b7aa2c43311d7d4d48a69e --- /dev/null +++ b/test/hotspot/jtreg/compiler/vectorapi/reshape/TestVectorCastAVX2.java @@ -0,0 +1,48 @@ +/* + * 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. + */ + +package compiler.vectorapi.reshape; + +import compiler.vectorapi.reshape.tests.TestVectorCast; +import compiler.vectorapi.reshape.utils.TestCastMethods; +import compiler.vectorapi.reshape.utils.VectorReshapeHelper; + +/* + * @test + * @bug 8259610 + * @modules jdk.incubator.vector + * @modules java.base/jdk.internal.misc + * @summary Test that vector cast intrinsics work as intended on avx2. + * @requires vm.cpu.features ~= ".*avx2.*" + * @library /test/lib / + * @run driver compiler.vectorapi.reshape.TestVectorCastAVX2 + */ +public class TestVectorCastAVX2 { + public static void main(String[] args) { + VectorReshapeHelper.runMainHelper( + TestVectorCast.class, + TestCastMethods.AVX2_CAST_TESTS.stream(), + "-XX:UseAVX=2"); + } +} + diff --git a/test/hotspot/jtreg/compiler/vectorapi/reshape/TestVectorCastAVX512.java b/test/hotspot/jtreg/compiler/vectorapi/reshape/TestVectorCastAVX512.java new file mode 100644 index 0000000000000000000000000000000000000000..749c6a21e06ef4c3d3f1bc01c59f644da12a134f --- /dev/null +++ b/test/hotspot/jtreg/compiler/vectorapi/reshape/TestVectorCastAVX512.java @@ -0,0 +1,48 @@ +/* + * 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. + */ + +package compiler.vectorapi.reshape; + +import compiler.vectorapi.reshape.tests.TestVectorCast; +import compiler.vectorapi.reshape.utils.TestCastMethods; +import compiler.vectorapi.reshape.utils.VectorReshapeHelper; + +/* + * @test + * @bug 8259610 + * @modules jdk.incubator.vector + * @modules java.base/jdk.internal.misc + * @summary Test that vector cast intrinsics work as intended on avx512. + * @requires vm.cpu.features ~= ".*avx512.*" + * @library /test/lib / + * @run driver compiler.vectorapi.reshape.TestVectorCastAVX512 + */ +public class TestVectorCastAVX512 { + public static void main(String[] args) { + VectorReshapeHelper.runMainHelper( + TestVectorCast.class, + TestCastMethods.AVX512_CAST_TESTS.stream(), + "-XX:UseAVX=3"); + } +} + diff --git a/test/hotspot/jtreg/compiler/vectorapi/reshape/TestVectorCastAVX512BW.java b/test/hotspot/jtreg/compiler/vectorapi/reshape/TestVectorCastAVX512BW.java new file mode 100644 index 0000000000000000000000000000000000000000..d9fbaf92d844c8595134fc5c295685973ae7bf5f --- /dev/null +++ b/test/hotspot/jtreg/compiler/vectorapi/reshape/TestVectorCastAVX512BW.java @@ -0,0 +1,48 @@ +/* + * 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. + */ + +package compiler.vectorapi.reshape; + +import compiler.vectorapi.reshape.tests.TestVectorCast; +import compiler.vectorapi.reshape.utils.TestCastMethods; +import compiler.vectorapi.reshape.utils.VectorReshapeHelper; + +/* + * @test + * @bug 8278623 + * @modules jdk.incubator.vector + * @modules java.base/jdk.internal.misc + * @summary Test that vector cast intrinsics work as intended on avx512bw. + * @requires vm.cpu.features ~= ".*avx512bw.*" + * @library /test/lib / + * @run driver compiler.vectorapi.reshape.TestVectorCastAVX512BW + */ +public class TestVectorCastAVX512BW { + public static void main(String[] args) { + VectorReshapeHelper.runMainHelper( + TestVectorCast.class, + TestCastMethods.AVX512BW_CAST_TESTS.stream(), + "-XX:UseAVX=3"); + } +} + diff --git a/test/hotspot/jtreg/compiler/vectorapi/reshape/TestVectorCastAVX512DQ.java b/test/hotspot/jtreg/compiler/vectorapi/reshape/TestVectorCastAVX512DQ.java new file mode 100644 index 0000000000000000000000000000000000000000..8799cccd918415912c378b4245bc680bbab0a280 --- /dev/null +++ b/test/hotspot/jtreg/compiler/vectorapi/reshape/TestVectorCastAVX512DQ.java @@ -0,0 +1,48 @@ +/* + * 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. + */ + +package compiler.vectorapi.reshape; + +import compiler.vectorapi.reshape.tests.TestVectorCast; +import compiler.vectorapi.reshape.utils.TestCastMethods; +import compiler.vectorapi.reshape.utils.VectorReshapeHelper; + +/* + * @test + * @bug 8259610 + * @modules jdk.incubator.vector + * @modules java.base/jdk.internal.misc + * @summary Test that vector cast intrinsics work as intended on avx512dq. + * @requires vm.cpu.features ~= ".*avx512dq.*" + * @library /test/lib / + * @run driver compiler.vectorapi.reshape.TestVectorCastAVX512DQ + */ +public class TestVectorCastAVX512DQ { + public static void main(String[] args) { + VectorReshapeHelper.runMainHelper( + TestVectorCast.class, + TestCastMethods.AVX512DQ_CAST_TESTS.stream(), + "-XX:UseAVX=3"); + } +} + diff --git a/test/hotspot/jtreg/compiler/vectorapi/reshape/TestVectorCastNeon.java b/test/hotspot/jtreg/compiler/vectorapi/reshape/TestVectorCastNeon.java new file mode 100644 index 0000000000000000000000000000000000000000..11777a3ccfcf8b211021285017fcb0d4f3f75de5 --- /dev/null +++ b/test/hotspot/jtreg/compiler/vectorapi/reshape/TestVectorCastNeon.java @@ -0,0 +1,49 @@ +/* + * 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. + */ + +package compiler.vectorapi.reshape; + +import compiler.vectorapi.reshape.tests.TestVectorCast; +import compiler.vectorapi.reshape.utils.TestCastMethods; +import compiler.vectorapi.reshape.utils.VectorReshapeHelper; + +/* + * @test + * @bug 8259610 + * @modules jdk.incubator.vector + * @modules java.base/jdk.internal.misc + * @summary Test that vector cast intrinsics work as intended on neon. + * @requires vm.cpu.features ~= ".*simd.*" + * @library /test/lib / + * @run driver compiler.vectorapi.reshape.TestVectorCastNeon + */ +public class TestVectorCastNeon { + public static void main(String[] args) { + VectorReshapeHelper.runMainHelper( + TestVectorCast.class, + TestCastMethods.NEON_CAST_TESTS.stream(), + "-XX:+UseNeon"); + } +} + + diff --git a/test/hotspot/jtreg/compiler/vectorapi/reshape/TestVectorCastSVE.java b/test/hotspot/jtreg/compiler/vectorapi/reshape/TestVectorCastSVE.java new file mode 100644 index 0000000000000000000000000000000000000000..614e8e870de43ae4a286258a6379f5f6f44bbde5 --- /dev/null +++ b/test/hotspot/jtreg/compiler/vectorapi/reshape/TestVectorCastSVE.java @@ -0,0 +1,49 @@ +/* + * 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. + */ + +package compiler.vectorapi.reshape; + +import compiler.vectorapi.reshape.tests.TestVectorCast; +import compiler.vectorapi.reshape.utils.TestCastMethods; +import compiler.vectorapi.reshape.utils.VectorReshapeHelper; + +/* + * @test + * @bug 8259610 + * @modules jdk.incubator.vector + * @modules java.base/jdk.internal.misc + * @summary Test that vector cast intrinsics work as intended on sve. + * @requires vm.cpu.features ~= ".*sve.*" + * @library /test/lib / + * @run driver compiler.vectorapi.reshape.TestVectorCastSVE + */ +public class TestVectorCastSVE { + public static void main(String[] args) { + VectorReshapeHelper.runMainHelper( + TestVectorCast.class, + TestCastMethods.SVE_CAST_TESTS.stream(), + "-XX:UseSVE=1"); + } +} + + diff --git a/test/hotspot/jtreg/compiler/vectorapi/reshape/TestVectorReinterpret.java b/test/hotspot/jtreg/compiler/vectorapi/reshape/TestVectorReinterpret.java new file mode 100644 index 0000000000000000000000000000000000000000..538736193ef25eea797e41b1628425e13ac9d90c --- /dev/null +++ b/test/hotspot/jtreg/compiler/vectorapi/reshape/TestVectorReinterpret.java @@ -0,0 +1,80 @@ +/* + * 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. + */ + +package compiler.vectorapi.reshape; + +import compiler.vectorapi.reshape.tests.TestVectorDoubleExpandShrink; +import compiler.vectorapi.reshape.tests.TestVectorExpandShrink; +import compiler.vectorapi.reshape.tests.TestVectorRebracket; +import compiler.vectorapi.reshape.utils.VectorReshapeHelper; +import compiler.vectorapi.reshape.utils.VectorSpeciesPair; +import java.util.List; +import jdk.incubator.vector.VectorShape; +import jdk.incubator.vector.VectorSpecies; + +/* + * @test + * @bug 8259610 + * @modules jdk.incubator.vector + * @modules java.base/jdk.internal.misc + * @summary Test that vector reinterpret intrinsics work as intended. + * @library /test/lib / + * @run driver compiler.vectorapi.reshape.TestVectorReinterpret + */ +public class TestVectorReinterpret { + private static final List<VectorShape> SHAPE_LIST = List.of(VectorShape.values()); + private static final List<Class<?>> ETYPE_LIST = List.of( + byte.class, short.class, int.class, long.class, float.class, double.class + ); + + public static void main(String[] args) { + VectorReshapeHelper.runMainHelper( + TestVectorExpandShrink.class, + SHAPE_LIST.stream() + .flatMap(s -> SHAPE_LIST.stream() + .filter(t -> t.vectorBitSize() != s.vectorBitSize()) + .map(t -> VectorSpeciesPair.makePair(VectorSpecies.of(byte.class, s), + VectorSpecies.of(byte.class, t)))) + ); + + VectorReshapeHelper.runMainHelper( + TestVectorDoubleExpandShrink.class, + SHAPE_LIST.stream() + .flatMap(s -> SHAPE_LIST.stream() + .filter(t -> t.vectorBitSize() != s.vectorBitSize()) + .map(t -> VectorSpeciesPair.makePair(VectorSpecies.of(byte.class, s), + VectorSpecies.of(byte.class, t)))) + ); + + VectorReshapeHelper.runMainHelper( + TestVectorRebracket.class, + SHAPE_LIST.stream() + .flatMap(shape -> ETYPE_LIST.stream() + .flatMap(etype -> ETYPE_LIST.stream() + .filter(ftype -> ftype != etype) + .map(ftype -> VectorSpeciesPair.makePair(VectorSpecies.of(etype, shape), + VectorSpecies.of(ftype, shape))))) + .filter(p -> p.isp().length() > 1 && p.osp().length() > 1) + ); + } +} diff --git a/test/hotspot/jtreg/compiler/vectorapi/reshape/tests/TestVectorCast.java b/test/hotspot/jtreg/compiler/vectorapi/reshape/tests/TestVectorCast.java new file mode 100644 index 0000000000000000000000000000000000000000..47dcbab8f71f6d6ae9d0fd906aff0954ab0966a7 --- /dev/null +++ b/test/hotspot/jtreg/compiler/vectorapi/reshape/tests/TestVectorCast.java @@ -0,0 +1,1629 @@ +/* + * 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. + */ + +package compiler.vectorapi.reshape.tests; + +import compiler.lib.ir_framework.IR; +import compiler.lib.ir_framework.Run; +import compiler.lib.ir_framework.Test; + +import static compiler.vectorapi.reshape.utils.VectorReshapeHelper.*; +import static jdk.incubator.vector.VectorOperators.*; + +/** + * This class contains all possible cast operations between different vector species. + * The methods only take into consideration the actual cast in C2, as the vectors are + * ofter shrunk or expanded before/after casting if the element numbers mismatch. + * + * We must load from/store to the exact type array since vector support for byte may be + * smaller than that for other types. Failing to intrinsify LoadVectorNode causes C2 + * compilation to stop, which results in non-compilable failure since we only have one + * chance of compilation before IR verification. + * + * In each cast, the VectorCastNode is expected to appear exactly once. + */ +public class TestVectorCast { + @Test + @IR(counts = {B2X_NODE, "1"}) + public static void testB64toS64(byte[] input, short[] output) { + vectorCast(B2S, BSPEC64, SSPEC64, input, output); + } + + @Run(test = "testB64toS64") + public static void runB64toS64() throws Throwable { + runCastHelper(B2S, BSPEC64, SSPEC64); + } + + @Test + @IR(counts = {B2X_NODE, "1"}) + public static void testB64toS128(byte[] input, short[] output) { + vectorCast(B2S, BSPEC64, SSPEC128, input, output); + } + + @Run(test = "testB64toS128") + public static void runB64toS128() throws Throwable { + runCastHelper(B2S, BSPEC64, SSPEC128); + } + + @Test + @IR(counts = {B2X_NODE, "1"}) + public static void testB128toS256(byte[] input, short[] output) { + vectorCast(B2S, BSPEC128, SSPEC256, input, output); + } + + @Run(test = "testB128toS256") + public static void runB128toS256() throws Throwable { + runCastHelper(B2S, BSPEC128, SSPEC256); + } + + @Test + @IR(counts = {B2X_NODE, "1"}) + public static void testB256toS512(byte[] input, short[] output) { + vectorCast(B2S, BSPEC256, SSPEC512, input, output); + } + + @Run(test = "testB256toS512") + public static void runB256toS512() throws Throwable { + runCastHelper(B2S, BSPEC256, SSPEC512); + } + + @Test + @IR(counts = {B2X_NODE, "1"}) + public static void testB64toI64(byte[] input, int[] output) { + vectorCast(B2I, BSPEC64, ISPEC64, input, output); + } + + @Run(test = "testB64toI64") + public static void runB64toI64() throws Throwable { + runCastHelper(B2I, BSPEC64, ISPEC64); + } + + @Test + @IR(counts = {B2X_NODE, "1"}) + public static void testB64toI128(byte[] input, int[] output) { + vectorCast(B2I, BSPEC64, ISPEC128, input, output); + } + + @Run(test = "testB64toI128") + public static void runB64toI128() throws Throwable { + runCastHelper(B2I, BSPEC64, ISPEC128); + } + + @Test + @IR(counts = {B2X_NODE, "1"}) + public static void testB64toI256(byte[] input, int[] output) { + vectorCast(B2I, BSPEC64, ISPEC256, input, output); + } + + @Run(test = "testB64toI256") + public static void runB64toI256() throws Throwable { + runCastHelper(B2I, BSPEC64, ISPEC256); + } + + @Test + @IR(counts = {B2X_NODE, "1"}) + public static void testB128toI512(byte[] input, int[] output) { + vectorCast(B2I, BSPEC128, ISPEC512, input, output); + } + + @Run(test = "testB128toI512") + public static void runB128toI512() throws Throwable { + runCastHelper(B2I, BSPEC128, ISPEC512); + } + + @Test + @IR(counts = {B2X_NODE, "1"}) + public static void testB64toL64(byte[] input, long[] output) { + vectorCast(B2L, BSPEC64, LSPEC64, input, output); + } + + @Run(test = "testB64toL64") + public static void runB64toL64() throws Throwable { + runCastHelper(B2L, BSPEC64, LSPEC64); + } + + @Test + @IR(counts = {B2X_NODE, "1"}) + public static void testB64toL128(byte[] input, long[] output) { + vectorCast(B2L, BSPEC64, LSPEC128, input, output); + } + + @Run(test = "testB64toL128") + public static void runB64toL128() throws Throwable { + runCastHelper(B2L, BSPEC64, LSPEC128); + } + + @Test + @IR(counts = {B2X_NODE, "1"}) + public static void testB64toL256(byte[] input, long[] output) { + vectorCast(B2L, BSPEC64, LSPEC256, input, output); + } + + @Run(test = "testB64toL256") + public static void runB64toL256() throws Throwable { + runCastHelper(B2L, BSPEC64, LSPEC256); + } + + @Test + @IR(counts = {B2X_NODE, "1"}) + public static void testB64toL512(byte[] input, long[] output) { + vectorCast(B2L, BSPEC64, LSPEC512, input, output); + } + + @Run(test = "testB64toL512") + public static void runB64toL512() throws Throwable { + runCastHelper(B2L, BSPEC64, LSPEC512); + } + + @Test + @IR(counts = {B2X_NODE, "1"}) + public static void testB64toF64(byte[] input, float[] output) { + vectorCast(B2F, BSPEC64, FSPEC64, input, output); + } + + @Run(test = "testB64toF64") + public static void runB64toF64() throws Throwable { + runCastHelper(B2F, BSPEC64, FSPEC64); + } + + @Test + @IR(counts = {B2X_NODE, "1"}) + public static void testB64toF128(byte[] input, float[] output) { + vectorCast(B2F, BSPEC64, FSPEC128, input, output); + } + + @Run(test = "testB64toF128") + public static void runB64toF128() throws Throwable { + runCastHelper(B2F, BSPEC64, FSPEC128); + } + + @Test + @IR(counts = {B2X_NODE, "1"}) + public static void testB64toF256(byte[] input, float[] output) { + vectorCast(B2F, BSPEC64, FSPEC256, input, output); + } + + @Run(test = "testB64toF256") + public static void runB64toF256() throws Throwable { + runCastHelper(B2F, BSPEC64, FSPEC256); + } + + @Test + @IR(counts = {B2X_NODE, "1"}) + public static void testB128toF512(byte[] input, float[] output) { + vectorCast(B2F, BSPEC128, FSPEC512, input, output); + } + + @Run(test = "testB128toF512") + public static void runB128toF512() throws Throwable { + runCastHelper(B2F, BSPEC128, FSPEC512); + } + + @Test + @IR(counts = {B2X_NODE, "1"}) + public static void testB64toD64(byte[] input, double[] output) { + vectorCast(B2D, BSPEC64, DSPEC64, input, output); + } + + @Run(test = "testB64toD64") + public static void runB64toD64() throws Throwable { + runCastHelper(B2D, BSPEC64, DSPEC64); + } + + @Test + @IR(counts = {B2X_NODE, "1"}) + public static void testB64toD128(byte[] input, double[] output) { + vectorCast(B2D, BSPEC64, DSPEC128, input, output); + } + + @Run(test = "testB64toD128") + public static void runB64toD128() throws Throwable { + runCastHelper(B2D, BSPEC64, DSPEC128); + } + + @Test + @IR(counts = {B2X_NODE, "1"}) + public static void testB64toD256(byte[] input, double[] output) { + vectorCast(B2D, BSPEC64, DSPEC256, input, output); + } + + @Run(test = "testB64toD256") + public static void runB64toD256() throws Throwable { + runCastHelper(B2D, BSPEC64, DSPEC256); + } + + @Test + @IR(counts = {B2X_NODE, "1"}) + public static void testB64toD512(byte[] input, double[] output) { + vectorCast(B2D, BSPEC64, DSPEC512, input, output); + } + + @Run(test = "testB64toD512") + public static void runB64toD512() throws Throwable { + runCastHelper(B2D, BSPEC64, DSPEC512); + } + + @Test + @IR(counts = {S2X_NODE, "1"}) + public static void testS64toB64(short[] input, byte[] output) { + vectorCast(S2B, SSPEC64, BSPEC64, input, output); + } + + @Run(test = "testS64toB64") + public static void runS64toB64() throws Throwable { + runCastHelper(S2B, SSPEC64, BSPEC64); + } + + @Test + @IR(counts = {S2X_NODE, "1"}) + public static void testS128toB64(short[] input, byte[] output) { + vectorCast(S2B, SSPEC128, BSPEC64, input, output); + } + + @Run(test = "testS128toB64") + public static void runS128toB64() throws Throwable { + runCastHelper(S2B, SSPEC128, BSPEC64); + } + + @Test + @IR(counts = {S2X_NODE, "1"}) + public static void testS256toB128(short[] input, byte[] output) { + vectorCast(S2B, SSPEC256, BSPEC128, input, output); + } + + @Run(test = "testS256toB128") + public static void runS256toB128() throws Throwable { + runCastHelper(S2B, SSPEC256, BSPEC128); + } + + @Test + @IR(counts = {S2X_NODE, "1"}) + public static void testS512toB256(short[] input, byte[] output) { + vectorCast(S2B, SSPEC512, BSPEC256, input, output); + } + + @Run(test = "testS512toB256") + public static void runS512toB256() throws Throwable { + runCastHelper(S2B, SSPEC512, BSPEC256); + } + + @Test + @IR(counts = {S2X_NODE, "1"}) + public static void testS64toI64(short[] input, int[] output) { + vectorCast(S2I, SSPEC64, ISPEC64, input, output); + } + + @Run(test = "testS64toI64") + public static void runS64toI64() throws Throwable { + runCastHelper(S2I, SSPEC64, ISPEC64); + } + + @Test + @IR(counts = {S2X_NODE, "1"}) + public static void testS64toI128(short[] input, int[] output) { + vectorCast(S2I, SSPEC64, ISPEC128, input, output); + } + + @Run(test = "testS64toI128") + public static void runS64toI128() throws Throwable { + runCastHelper(S2I, SSPEC64, ISPEC128); + } + + @Test + @IR(counts = {S2X_NODE, "1"}) + public static void testS128toI256(short[] input, int[] output) { + vectorCast(S2I, SSPEC128, ISPEC256, input, output); + } + + @Run(test = "testS128toI256") + public static void runS128toI256() throws Throwable { + runCastHelper(S2I, SSPEC128, ISPEC256); + } + + @Test + @IR(counts = {S2X_NODE, "1"}) + public static void testS256toI512(short[] input, int[] output) { + vectorCast(S2I, SSPEC256, ISPEC512, input, output); + } + + @Run(test = "testS256toI512") + public static void runS256toI512() throws Throwable { + runCastHelper(S2I, SSPEC256, ISPEC512); + } + + @Test + @IR(counts = {S2X_NODE, "1"}) + public static void testS64toL64(short[] input, long[] output) { + vectorCast(S2L, SSPEC64, LSPEC64, input, output); + } + + @Run(test = "testS64toL64") + public static void runS64toL64() throws Throwable { + runCastHelper(S2L, SSPEC64, LSPEC64); + } + + @Test + @IR(counts = {S2X_NODE, "1"}) + public static void testS64toL128(short[] input, long[] output) { + vectorCast(S2L, SSPEC64, LSPEC128, input, output); + } + + @Run(test = "testS64toL128") + public static void runS64toL128() throws Throwable { + runCastHelper(S2L, SSPEC64, LSPEC128); + } + + @Test + @IR(counts = {S2X_NODE, "1"}) + public static void testS64toL256(short[] input, long[] output) { + vectorCast(S2L, SSPEC64, LSPEC256, input, output); + } + + @Run(test = "testS64toL256") + public static void runS64toL256() throws Throwable { + runCastHelper(S2L, SSPEC64, LSPEC256); + } + + @Test + @IR(counts = {S2X_NODE, "1"}) + public static void testS128toL512(short[] input, long[] output) { + vectorCast(S2L, SSPEC128, LSPEC512, input, output); + } + + @Run(test = "testS128toL512") + public static void runS128toL512() throws Throwable { + runCastHelper(S2L, SSPEC128, LSPEC512); + } + + @Test + @IR(counts = {S2X_NODE, "1"}) + public static void testS64toF64(short[] input, float[] output) { + vectorCast(S2F, SSPEC64, FSPEC64, input, output); + } + + @Run(test = "testS64toF64") + public static void runS64toF64() throws Throwable { + runCastHelper(S2F, SSPEC64, FSPEC64); + } + + @Test + @IR(counts = {S2X_NODE, "1"}) + public static void testS64toF128(short[] input, float[] output) { + vectorCast(S2F, SSPEC64, FSPEC128, input, output); + } + + @Run(test = "testS64toF128") + public static void runS64toF128() throws Throwable { + runCastHelper(S2F, SSPEC64, FSPEC128); + } + + @Test + @IR(counts = {S2X_NODE, "1"}) + public static void testS128toF256(short[] input, float[] output) { + vectorCast(S2F, SSPEC128, FSPEC256, input, output); + } + + @Run(test = "testS128toF256") + public static void runS128toF256() throws Throwable { + runCastHelper(S2F, SSPEC128, FSPEC256); + } + + @Test + @IR(counts = {S2X_NODE, "1"}) + public static void testS256toF512(short[] input, float[] output) { + vectorCast(S2F, SSPEC256, FSPEC512, input, output); + } + + @Run(test = "testS256toF512") + public static void runS256toF512() throws Throwable { + runCastHelper(S2F, SSPEC256, FSPEC512); + } + + @Test + @IR(counts = {S2X_NODE, "1"}) + public static void testS64toD64(short[] input, double[] output) { + vectorCast(S2D, SSPEC64, DSPEC64, input, output); + } + + @Run(test = "testS64toD64") + public static void runS64toD64() throws Throwable { + runCastHelper(S2D, SSPEC64, DSPEC64); + } + + @Test + @IR(counts = {S2X_NODE, "1"}) + public static void testS64toD128(short[] input, double[] output) { + vectorCast(S2D, SSPEC64, DSPEC128, input, output); + } + + @Run(test = "testS64toD128") + public static void runS64toD128() throws Throwable { + runCastHelper(S2D, SSPEC64, DSPEC128); + } + + @Test + @IR(counts = {S2X_NODE, "1"}) + public static void testS64toD256(short[] input, double[] output) { + vectorCast(S2D, SSPEC64, DSPEC256, input, output); + } + + @Run(test = "testS64toD256") + public static void runS64toD256() throws Throwable { + runCastHelper(S2D, SSPEC64, DSPEC256); + } + + @Test + @IR(counts = {S2X_NODE, "1"}) + public static void testS128toD512(short[] input, double[] output) { + vectorCast(S2D, SSPEC128, DSPEC512, input, output); + } + + @Run(test = "testS128toD512") + public static void runS128toD512() throws Throwable { + runCastHelper(S2D, SSPEC128, DSPEC512); + } + + @Test + @IR(counts = {I2X_NODE, "1"}) + public static void testI64toB64(int[] input, byte[] output) { + vectorCast(I2B, ISPEC64, BSPEC64, input, output); + } + + @Run(test = "testI64toB64") + public static void runI64toB64() throws Throwable { + runCastHelper(I2B, ISPEC64, BSPEC64); + } + + @Test + @IR(counts = {I2X_NODE, "1"}) + public static void testI128toB64(int[] input, byte[] output) { + vectorCast(I2B, ISPEC128, BSPEC64, input, output); + } + + @Run(test = "testI128toB64") + public static void runI128toB64() throws Throwable { + runCastHelper(I2B, ISPEC128, BSPEC64); + } + + @Test + @IR(counts = {I2X_NODE, "1"}) + public static void testI256toB64(int[] input, byte[] output) { + vectorCast(I2B, ISPEC256, BSPEC64, input, output); + } + + @Run(test = "testI256toB64") + public static void runI256toB64() throws Throwable { + runCastHelper(I2B, ISPEC256, BSPEC64); + } + + @Test + @IR(counts = {I2X_NODE, "1"}) + public static void testI512toB128(int[] input, byte[] output) { + vectorCast(I2B, ISPEC512, BSPEC128, input, output); + } + + @Run(test = "testI512toB128") + public static void runI512toB128() throws Throwable { + runCastHelper(I2B, ISPEC512, BSPEC128); + } + + @Test + @IR(counts = {I2X_NODE, "1"}) + public static void testI64toS64(int[] input, short[] output) { + vectorCast(I2S, ISPEC64, SSPEC64, input, output); + } + + @Run(test = "testI64toS64") + public static void runI64toS64() throws Throwable { + runCastHelper(I2S, ISPEC64, SSPEC64); + } + + @Test + @IR(counts = {I2X_NODE, "1"}) + public static void testI128toS64(int[] input, short[] output) { + vectorCast(I2S, ISPEC128, SSPEC64, input, output); + } + + @Run(test = "testI128toS64") + public static void runI128toS64() throws Throwable { + runCastHelper(I2S, ISPEC128, SSPEC64); + } + + @Test + @IR(counts = {I2X_NODE, "1"}) + public static void testI256toS128(int[] input, short[] output) { + vectorCast(I2S, ISPEC256, SSPEC128, input, output); + } + + @Run(test = "testI256toS128") + public static void runI256toS128() throws Throwable { + runCastHelper(I2S, ISPEC256, SSPEC128); + } + + @Test + @IR(counts = {I2X_NODE, "1"}) + public static void testI512toS256(int[] input, short[] output) { + vectorCast(I2S, ISPEC512, SSPEC256, input, output); + } + + @Run(test = "testI512toS256") + public static void runI512toS256() throws Throwable { + runCastHelper(I2S, ISPEC512, SSPEC256); + } + + @Test + @IR(counts = {I2X_NODE, "1"}) + public static void testI64toL64(int[] input, long[] output) { + vectorCast(I2L, ISPEC64, LSPEC64, input, output); + } + + @Run(test = "testI64toL64") + public static void runI64toL64() throws Throwable { + runCastHelper(I2L, ISPEC64, LSPEC64); + } + + @Test + @IR(counts = {I2X_NODE, "1"}) + public static void testI64toL128(int[] input, long[] output) { + vectorCast(I2L, ISPEC64, LSPEC128, input, output); + } + + @Run(test = "testI64toL128") + public static void runI64toL128() throws Throwable { + runCastHelper(I2L, ISPEC64, LSPEC128); + } + + @Test + @IR(counts = {I2X_NODE, "1"}) + public static void testI128toL256(int[] input, long[] output) { + vectorCast(I2L, ISPEC128, LSPEC256, input, output); + } + + @Run(test = "testI128toL256") + public static void runI128toL256() throws Throwable { + runCastHelper(I2L, ISPEC128, LSPEC256); + } + + @Test + @IR(counts = {I2X_NODE, "1"}) + public static void testI256toL512(int[] input, long[] output) { + vectorCast(I2L, ISPEC256, LSPEC512, input, output); + } + + @Run(test = "testI256toL512") + public static void runI256toL512() throws Throwable { + runCastHelper(I2L, ISPEC256, LSPEC512); + } + + @Test + @IR(counts = {I2X_NODE, "1"}) + public static void testI64toF64(int[] input, float[] output) { + vectorCast(I2F, ISPEC64, FSPEC64, input, output); + } + + @Run(test = "testI64toF64") + public static void runI64toF64() throws Throwable { + runCastHelper(I2F, ISPEC64, FSPEC64); + } + + @Test + @IR(counts = {I2X_NODE, "1"}) + public static void testI128toF128(int[] input, float[] output) { + vectorCast(I2F, ISPEC128, FSPEC128, input, output); + } + + @Run(test = "testI128toF128") + public static void runI128toF128() throws Throwable { + runCastHelper(I2F, ISPEC128, FSPEC128); + } + + @Test + @IR(counts = {I2X_NODE, "1"}) + public static void testI256toF256(int[] input, float[] output) { + vectorCast(I2F, ISPEC256, FSPEC256, input, output); + } + + @Run(test = "testI256toF256") + public static void runI256toF256() throws Throwable { + runCastHelper(I2F, ISPEC256, FSPEC256); + } + + @Test + @IR(counts = {I2X_NODE, "1"}) + public static void testI512toF512(int[] input, float[] output) { + vectorCast(I2F, ISPEC512, FSPEC512, input, output); + } + + @Run(test = "testI512toF512") + public static void runI512toF512() throws Throwable { + runCastHelper(I2F, ISPEC512, FSPEC512); + } + + @Test + @IR(counts = {I2X_NODE, "1"}) + public static void testI64toD64(int[] input, double[] output) { + vectorCast(I2D, ISPEC64, DSPEC64, input, output); + } + + @Run(test = "testI64toD64") + public static void runI64toD64() throws Throwable { + runCastHelper(I2D, ISPEC64, DSPEC64); + } + + @Test + @IR(counts = {I2X_NODE, "1"}) + public static void testI64toD128(int[] input, double[] output) { + vectorCast(I2D, ISPEC64, DSPEC128, input, output); + } + + @Run(test = "testI64toD128") + public static void runI64toD128() throws Throwable { + runCastHelper(I2D, ISPEC64, DSPEC128); + } + + @Test + @IR(counts = {I2X_NODE, "1"}) + public static void testI128toD256(int[] input, double[] output) { + vectorCast(I2D, ISPEC128, DSPEC256, input, output); + } + + @Run(test = "testI128toD256") + public static void runI128toD256() throws Throwable { + runCastHelper(I2D, ISPEC128, DSPEC256); + } + + @Test + @IR(counts = {I2X_NODE, "1"}) + public static void testI256toD512(int[] input, double[] output) { + vectorCast(I2D, ISPEC256, DSPEC512, input, output); + } + + @Run(test = "testI256toD512") + public static void runI256toD512() throws Throwable { + runCastHelper(I2D, ISPEC256, DSPEC512); + } + + @Test + @IR(counts = {L2X_NODE, "1"}) + public static void testL64toB64(long[] input, byte[] output) { + vectorCast(L2B, LSPEC64, BSPEC64, input, output); + } + + @Run(test = "testL64toB64") + public static void runL64toB64() throws Throwable { + runCastHelper(L2B, LSPEC64, BSPEC64); + } + + @Test + @IR(counts = {L2X_NODE, "1"}) + public static void testL128toB64(long[] input, byte[] output) { + vectorCast(L2B, LSPEC128, BSPEC64, input, output); + } + + @Run(test = "testL128toB64") + public static void runL128toB64() throws Throwable { + runCastHelper(L2B, LSPEC128, BSPEC64); + } + + @Test + @IR(counts = {L2X_NODE, "1"}) + public static void testL256toB64(long[] input, byte[] output) { + vectorCast(L2B, LSPEC256, BSPEC64, input, output); + } + + @Run(test = "testL256toB64") + public static void runL256toB64() throws Throwable { + runCastHelper(L2B, LSPEC256, BSPEC64); + } + + @Test + @IR(counts = {L2X_NODE, "1"}) + public static void testL512toB64(long[] input, byte[] output) { + vectorCast(L2B, LSPEC512, BSPEC64, input, output); + } + + @Run(test = "testL512toB64") + public static void runL512toB64() throws Throwable { + runCastHelper(L2B, LSPEC512, BSPEC64); + } + + @Test + @IR(counts = {L2X_NODE, "1"}) + public static void testL64toS64(long[] input, short[] output) { + vectorCast(L2S, LSPEC64, SSPEC64, input, output); + } + + @Run(test = "testL64toS64") + public static void runL64toS64() throws Throwable { + runCastHelper(L2S, LSPEC64, SSPEC64); + } + + @Test + @IR(counts = {L2X_NODE, "1"}) + public static void testL128toS64(long[] input, short[] output) { + vectorCast(L2S, LSPEC128, SSPEC64, input, output); + } + + @Run(test = "testL128toS64") + public static void runL128toS64() throws Throwable { + runCastHelper(L2S, LSPEC128, SSPEC64); + } + + @Test + @IR(counts = {L2X_NODE, "1"}) + public static void testL256toS64(long[] input, short[] output) { + vectorCast(L2S, LSPEC256, SSPEC64, input, output); + } + + @Run(test = "testL256toS64") + public static void runL256toS64() throws Throwable { + runCastHelper(L2S, LSPEC256, SSPEC64); + } + + @Test + @IR(counts = {L2X_NODE, "1"}) + public static void testL512toS128(long[] input, short[] output) { + vectorCast(L2S, LSPEC512, SSPEC128, input, output); + } + + @Run(test = "testL512toS128") + public static void runL512toS128() throws Throwable { + runCastHelper(L2S, LSPEC512, SSPEC128); + } + + @Test + @IR(counts = {L2X_NODE, "1"}) + public static void testL64toI64(long[] input, int[] output) { + vectorCast(L2I, LSPEC64, ISPEC64, input, output); + } + + @Run(test = "testL64toI64") + public static void runL64toI64() throws Throwable { + runCastHelper(L2I, LSPEC64, ISPEC64); + } + + @Test + @IR(counts = {L2X_NODE, "1"}) + public static void testL128toI64(long[] input, int[] output) { + vectorCast(L2I, LSPEC128, ISPEC64, input, output); + } + + @Run(test = "testL128toI64") + public static void runL128toI64() throws Throwable { + runCastHelper(L2I, LSPEC128, ISPEC64); + } + + @Test + @IR(counts = {L2X_NODE, "1"}) + public static void testL256toI128(long[] input, int[] output) { + vectorCast(L2I, LSPEC256, ISPEC128, input, output); + } + + @Run(test = "testL256toI128") + public static void runL256toI128() throws Throwable { + runCastHelper(L2I, LSPEC256, ISPEC128); + } + + @Test + @IR(counts = {L2X_NODE, "1"}) + public static void testL512toI256(long[] input, int[] output) { + vectorCast(L2I, LSPEC512, ISPEC256, input, output); + } + + @Run(test = "testL512toI256") + public static void runL512toI256() throws Throwable { + runCastHelper(L2I, LSPEC512, ISPEC256); + } + + @Test + @IR(counts = {L2X_NODE, "1"}) + public static void testL64toF64(long[] input, float[] output) { + vectorCast(L2F, LSPEC64, FSPEC64, input, output); + } + + @Run(test = "testL64toF64") + public static void runL64toF64() throws Throwable { + runCastHelper(L2F, LSPEC64, FSPEC64); + } + + @Test + @IR(counts = {L2X_NODE, "1"}) + public static void testL128toF64(long[] input, float[] output) { + vectorCast(L2F, LSPEC128, FSPEC64, input, output); + } + + @Run(test = "testL128toF64") + public static void runL128toF64() throws Throwable { + runCastHelper(L2F, LSPEC128, FSPEC64); + } + + @Test + @IR(counts = {L2X_NODE, "1"}) + public static void testL256toF128(long[] input, float[] output) { + vectorCast(L2F, LSPEC256, FSPEC128, input, output); + } + + @Run(test = "testL256toF128") + public static void runL256toF128() throws Throwable { + runCastHelper(L2F, LSPEC256, FSPEC128); + } + + @Test + @IR(counts = {L2X_NODE, "1"}) + public static void testL512toF256(long[] input, float[] output) { + vectorCast(L2F, LSPEC512, FSPEC256, input, output); + } + + @Run(test = "testL512toF256") + public static void runL512toF256() throws Throwable { + runCastHelper(L2F, LSPEC512, FSPEC256); + } + + @Test + @IR(counts = {L2X_NODE, "1"}) + public static void testL64toD64(long[] input, double[] output) { + vectorCast(L2D, LSPEC64, DSPEC64, input, output); + } + + @Run(test = "testL64toD64") + public static void runL64toD64() throws Throwable { + runCastHelper(L2D, LSPEC64, DSPEC64); + } + + @Test + @IR(counts = {L2X_NODE, "1"}) + public static void testL128toD128(long[] input, double[] output) { + vectorCast(L2D, LSPEC128, DSPEC128, input, output); + } + + @Run(test = "testL128toD128") + public static void runL128toD128() throws Throwable { + runCastHelper(L2D, LSPEC128, DSPEC128); + } + + @Test + @IR(counts = {L2X_NODE, "1"}) + public static void testL256toD256(long[] input, double[] output) { + vectorCast(L2D, LSPEC256, DSPEC256, input, output); + } + + @Run(test = "testL256toD256") + public static void runL256toD256() throws Throwable { + runCastHelper(L2D, LSPEC256, DSPEC256); + } + + @Test + @IR(counts = {L2X_NODE, "1"}) + public static void testL512toD512(long[] input, double[] output) { + vectorCast(L2D, LSPEC512, DSPEC512, input, output); + } + + @Run(test = "testL512toD512") + public static void runL512toD512() throws Throwable { + runCastHelper(L2D, LSPEC512, DSPEC512); + } + + @Test + @IR(counts = {F2X_NODE, "1"}) + public static void testF64toB64(float[] input, byte[] output) { + vectorCast(F2B, FSPEC64, BSPEC64, input, output); + } + + @Run(test = "testF64toB64") + public static void runF64toB64() throws Throwable { + runCastHelper(F2B, FSPEC64, BSPEC64); + } + + @Test + @IR(counts = {F2X_NODE, "1"}) + public static void testF128toB64(float[] input, byte[] output) { + vectorCast(F2B, FSPEC128, BSPEC64, input, output); + } + + @Run(test = "testF128toB64") + public static void runF128toB64() throws Throwable { + runCastHelper(F2B, FSPEC128, BSPEC64); + } + + @Test + @IR(counts = {F2X_NODE, "1"}) + public static void testF256toB64(float[] input, byte[] output) { + vectorCast(F2B, FSPEC256, BSPEC64, input, output); + } + + @Run(test = "testF256toB64") + public static void runF256toB64() throws Throwable { + runCastHelper(F2B, FSPEC256, BSPEC64); + } + + @Test + @IR(counts = {F2X_NODE, "1"}) + public static void testF512toB128(float[] input, byte[] output) { + vectorCast(F2B, FSPEC512, BSPEC128, input, output); + } + + @Run(test = "testF512toB128") + public static void runF512toB128() throws Throwable { + runCastHelper(F2B, FSPEC512, BSPEC128); + } + + @Test + @IR(counts = {F2X_NODE, "1"}) + public static void testF64toS64(float[] input, short[] output) { + vectorCast(F2S, FSPEC64, SSPEC64, input, output); + } + + @Run(test = "testF64toS64") + public static void runF64toS64() throws Throwable { + runCastHelper(F2S, FSPEC64, SSPEC64); + } + + @Test + @IR(counts = {F2X_NODE, "1"}) + public static void testF128toS64(float[] input, short[] output) { + vectorCast(F2S, FSPEC128, SSPEC64, input, output); + } + + @Run(test = "testF128toS64") + public static void runF128toS64() throws Throwable { + runCastHelper(F2S, FSPEC128, SSPEC64); + } + + @Test + @IR(counts = {F2X_NODE, "1"}) + public static void testF256toS128(float[] input, short[] output) { + vectorCast(F2S, FSPEC256, SSPEC128, input, output); + } + + @Run(test = "testF256toS128") + public static void runF256toS128() throws Throwable { + runCastHelper(F2S, FSPEC256, SSPEC128); + } + + @Test + @IR(counts = {F2X_NODE, "1"}) + public static void testF512toS256(float[] input, short[] output) { + vectorCast(F2S, FSPEC512, SSPEC256, input, output); + } + + @Run(test = "testF512toS256") + public static void runF512toS256() throws Throwable { + runCastHelper(F2S, FSPEC512, SSPEC256); + } + + @Test + @IR(counts = {F2X_NODE, "1"}) + public static void testF64toI64(float[] input, int[] output) { + vectorCast(F2I, FSPEC64, ISPEC64, input, output); + } + + @Run(test = "testF64toI64") + public static void runF64toI64() throws Throwable { + runCastHelper(F2I, FSPEC64, ISPEC64); + } + + @Test + @IR(counts = {F2X_NODE, "1"}) + public static void testF128toI128(float[] input, int[] output) { + vectorCast(F2I, FSPEC128, ISPEC128, input, output); + } + + @Run(test = "testF128toI128") + public static void runF128toI128() throws Throwable { + runCastHelper(F2I, FSPEC128, ISPEC128); + } + + @Test + @IR(counts = {F2X_NODE, "1"}) + public static void testF256toI256(float[] input, int[] output) { + vectorCast(F2I, FSPEC256, ISPEC256, input, output); + } + + @Run(test = "testF256toI256") + public static void runF256toI256() throws Throwable { + runCastHelper(F2I, FSPEC256, ISPEC256); + } + + @Test + @IR(counts = {F2X_NODE, "1"}) + public static void testF512toI512(float[] input, int[] output) { + vectorCast(F2I, FSPEC512, ISPEC512, input, output); + } + + @Run(test = "testF512toI512") + public static void runF512toI512() throws Throwable { + runCastHelper(F2I, FSPEC512, ISPEC512); + } + + @Test + @IR(counts = {F2X_NODE, "1"}) + public static void testF64toL64(float[] input, long[] output) { + vectorCast(F2L, FSPEC64, LSPEC64, input, output); + } + + @Run(test = "testF64toL64") + public static void runF64toL64() throws Throwable { + runCastHelper(F2L, FSPEC64, LSPEC64); + } + + @Test + @IR(counts = {F2X_NODE, "1"}) + public static void testF64toL128(float[] input, long[] output) { + vectorCast(F2L, FSPEC64, LSPEC128, input, output); + } + + @Run(test = "testF64toL128") + public static void runF64toL128() throws Throwable { + runCastHelper(F2L, FSPEC64, LSPEC128); + } + + @Test + @IR(counts = {F2X_NODE, "1"}) + public static void testF128toL256(float[] input, long[] output) { + vectorCast(F2L, FSPEC128, LSPEC256, input, output); + } + + @Run(test = "testF128toL256") + public static void runF128toL256() throws Throwable { + runCastHelper(F2L, FSPEC128, LSPEC256); + } + + @Test + @IR(counts = {F2X_NODE, "1"}) + public static void testF256toL512(float[] input, long[] output) { + vectorCast(F2L, FSPEC256, LSPEC512, input, output); + } + + @Run(test = "testF256toL512") + public static void runF256toL512() throws Throwable { + runCastHelper(F2L, FSPEC256, LSPEC512); + } + + @Test + @IR(counts = {F2X_NODE, "1"}) + public static void testF64toD64(float[] input, double[] output) { + vectorCast(F2D, FSPEC64, DSPEC64, input, output); + } + + @Run(test = "testF64toD64") + public static void runF64toD64() throws Throwable { + runCastHelper(F2D, FSPEC64, DSPEC64); + } + + @Test + @IR(counts = {F2X_NODE, "1"}) + public static void testF64toD128(float[] input, double[] output) { + vectorCast(F2D, FSPEC64, DSPEC128, input, output); + } + + @Run(test = "testF64toD128") + public static void runF64toD128() throws Throwable { + runCastHelper(F2D, FSPEC64, DSPEC128); + } + + @Test + @IR(counts = {F2X_NODE, "1"}) + public static void testF128toD256(float[] input, double[] output) { + vectorCast(F2D, FSPEC128, DSPEC256, input, output); + } + + @Run(test = "testF128toD256") + public static void runF128toD256() throws Throwable { + runCastHelper(F2D, FSPEC128, DSPEC256); + } + + @Test + @IR(counts = {F2X_NODE, "1"}) + public static void testF256toD512(float[] input, double[] output) { + vectorCast(F2D, FSPEC256, DSPEC512, input, output); + } + + @Run(test = "testF256toD512") + public static void runF256toD512() throws Throwable { + runCastHelper(F2D, FSPEC256, DSPEC512); + } + + @Test + @IR(counts = {D2X_NODE, "1"}) + public static void testD64toB64(double[] input, byte[] output) { + vectorCast(D2B, DSPEC64, BSPEC64, input, output); + } + + @Run(test = "testD64toB64") + public static void runD64toB64() throws Throwable { + runCastHelper(D2B, DSPEC64, BSPEC64); + } + + @Test + @IR(counts = {D2X_NODE, "1"}) + public static void testD128toB64(double[] input, byte[] output) { + vectorCast(D2B, DSPEC128, BSPEC64, input, output); + } + + @Run(test = "testD128toB64") + public static void runD128toB64() throws Throwable { + runCastHelper(D2B, DSPEC128, BSPEC64); + } + + @Test + @IR(counts = {D2X_NODE, "1"}) + public static void testD256toB64(double[] input, byte[] output) { + vectorCast(D2B, DSPEC256, BSPEC64, input, output); + } + + @Run(test = "testD256toB64") + public static void runD256toB64() throws Throwable { + runCastHelper(D2B, DSPEC256, BSPEC64); + } + + @Test + @IR(counts = {D2X_NODE, "1"}) + public static void testD512toB64(double[] input, byte[] output) { + vectorCast(D2B, DSPEC512, BSPEC64, input, output); + } + + @Run(test = "testD512toB64") + public static void runD512toB64() throws Throwable { + runCastHelper(D2B, DSPEC512, BSPEC64); + } + + @Test + @IR(counts = {D2X_NODE, "1"}) + public static void testD64toS64(double[] input, short[] output) { + vectorCast(D2S, DSPEC64, SSPEC64, input, output); + } + + @Run(test = "testD64toS64") + public static void runD64toS64() throws Throwable { + runCastHelper(D2S, DSPEC64, SSPEC64); + } + + @Test + @IR(counts = {D2X_NODE, "1"}) + public static void testD128toS64(double[] input, short[] output) { + vectorCast(D2S, DSPEC128, SSPEC64, input, output); + } + + @Run(test = "testD128toS64") + public static void runD128toS64() throws Throwable { + runCastHelper(D2S, DSPEC128, SSPEC64); + } + + @Test + @IR(counts = {D2X_NODE, "1"}) + public static void testD256toS64(double[] input, short[] output) { + vectorCast(D2S, DSPEC256, SSPEC64, input, output); + } + + @Run(test = "testD256toS64") + public static void runD256toS64() throws Throwable { + runCastHelper(D2S, DSPEC256, SSPEC64); + } + + @Test + @IR(counts = {D2X_NODE, "1"}) + public static void testD512toS128(double[] input, short[] output) { + vectorCast(D2S, DSPEC512, SSPEC128, input, output); + } + + @Run(test = "testD512toS128") + public static void runD512toS128() throws Throwable { + runCastHelper(D2S, DSPEC512, SSPEC128); + } + + @Test + @IR(counts = {D2X_NODE, "1"}) + public static void testD64toI64(double[] input, int[] output) { + vectorCast(D2I, DSPEC64, ISPEC64, input, output); + } + + @Run(test = "testD64toI64") + public static void runD64toI64() throws Throwable { + runCastHelper(D2I, DSPEC64, ISPEC64); + } + + @Test + @IR(counts = {D2X_NODE, "1"}) + public static void testD128toI64(double[] input, int[] output) { + vectorCast(D2I, DSPEC128, ISPEC64, input, output); + } + + @Run(test = "testD128toI64") + public static void runD128toI64() throws Throwable { + runCastHelper(D2I, DSPEC128, ISPEC64); + } + + @Test + @IR(counts = {D2X_NODE, "1"}) + public static void testD256toI128(double[] input, int[] output) { + vectorCast(D2I, DSPEC256, ISPEC128, input, output); + } + + @Run(test = "testD256toI128") + public static void runD256toI128() throws Throwable { + runCastHelper(D2I, DSPEC256, ISPEC128); + } + + @Test + @IR(counts = {D2X_NODE, "1"}) + public static void testD512toI256(double[] input, int[] output) { + vectorCast(D2I, DSPEC512, ISPEC256, input, output); + } + + @Run(test = "testD512toI256") + public static void runD512toI256() throws Throwable { + runCastHelper(D2I, DSPEC512, ISPEC256); + } + + @Test + @IR(counts = {D2X_NODE, "1"}) + public static void testD64toL64(double[] input, long[] output) { + vectorCast(D2L, DSPEC64, LSPEC64, input, output); + } + + @Run(test = "testD64toL64") + public static void runD64toL64() throws Throwable { + runCastHelper(D2L, DSPEC64, LSPEC64); + } + + @Test + @IR(counts = {D2X_NODE, "1"}) + public static void testD128toL128(double[] input, long[] output) { + vectorCast(D2L, DSPEC128, LSPEC128, input, output); + } + + @Run(test = "testD128toL128") + public static void runD128toL128() throws Throwable { + runCastHelper(D2L, DSPEC128, LSPEC128); + } + + @Test + @IR(counts = {D2X_NODE, "1"}) + public static void testD256toL256(double[] input, long[] output) { + vectorCast(D2L, DSPEC256, LSPEC256, input, output); + } + + @Run(test = "testD256toL256") + public static void runD256toL256() throws Throwable { + runCastHelper(D2L, DSPEC256, LSPEC256); + } + + @Test + @IR(counts = {D2X_NODE, "1"}) + public static void testD512toL512(double[] input, long[] output) { + vectorCast(D2L, DSPEC512, LSPEC512, input, output); + } + + @Run(test = "testD512toL512") + public static void runD512toL512() throws Throwable { + runCastHelper(D2L, DSPEC512, LSPEC512); + } + + @Test + @IR(counts = {D2X_NODE, "1"}) + public static void testD64toF64(double[] input, float[] output) { + vectorCast(D2F, DSPEC64, FSPEC64, input, output); + } + + @Run(test = "testD64toF64") + public static void runD64toF64() throws Throwable { + runCastHelper(D2F, DSPEC64, FSPEC64); + } + + @Test + @IR(counts = {D2X_NODE, "1"}) + public static void testD128toF64(double[] input, float[] output) { + vectorCast(D2F, DSPEC128, FSPEC64, input, output); + } + + @Run(test = "testD128toF64") + public static void runD128toF64() throws Throwable { + runCastHelper(D2F, DSPEC128, FSPEC64); + } + + @Test + @IR(counts = {D2X_NODE, "1"}) + public static void testD256toF128(double[] input, float[] output) { + vectorCast(D2F, DSPEC256, FSPEC128, input, output); + } + + @Run(test = "testD256toF128") + public static void runD256toF128() throws Throwable { + runCastHelper(D2F, DSPEC256, FSPEC128); + } + + @Test + @IR(counts = {D2X_NODE, "1"}) + public static void testD512toF256(double[] input, float[] output) { + vectorCast(D2F, DSPEC512, FSPEC256, input, output); + } + + @Run(test = "testD512toF256") + public static void runD512toF256() throws Throwable { + runCastHelper(D2F, DSPEC512, FSPEC256); + } + + @Test + @IR(counts = {UB2X_NODE, "1"}) + public static void testUB64toS64(byte[] input, short[] output) { + vectorCast(ZERO_EXTEND_B2S, BSPEC64, SSPEC64, input, output); + } + + @Run(test = "testUB64toS64") + public static void runUB64toS64() throws Throwable { + runCastHelper(ZERO_EXTEND_B2S, BSPEC64, SSPEC64); + } + + @Test + @IR(counts = {UB2X_NODE, "1"}) + public static void testUB64toS128(byte[] input, short[] output) { + vectorCast(ZERO_EXTEND_B2S, BSPEC64, SSPEC128, input, output); + } + + @Run(test = "testUB64toS128") + public static void runUB64toS128() throws Throwable { + runCastHelper(ZERO_EXTEND_B2S, BSPEC64, SSPEC128); + } + + @Test + @IR(counts = {UB2X_NODE, "1"}) + public static void testUB128toS256(byte[] input, short[] output) { + vectorCast(ZERO_EXTEND_B2S, BSPEC128, SSPEC256, input, output); + } + + @Run(test = "testUB128toS256") + public static void runUB128toS256() throws Throwable { + runCastHelper(ZERO_EXTEND_B2S, BSPEC128, SSPEC256); + } + + @Test + @IR(counts = {UB2X_NODE, "1"}) + public static void testUB256toS512(byte[] input, short[] output) { + vectorCast(ZERO_EXTEND_B2S, BSPEC256, SSPEC512, input, output); + } + + @Run(test = "testUB256toS512") + public static void runUB256toS512() throws Throwable { + runCastHelper(ZERO_EXTEND_B2S, BSPEC256, SSPEC512); + } + + @Test + @IR(counts = {UB2X_NODE, "1"}) + public static void testUB64toI64(byte[] input, int[] output) { + vectorCast(ZERO_EXTEND_B2I, BSPEC64, ISPEC64, input, output); + } + + @Run(test = "testUB64toI64") + public static void runUB64toI64() throws Throwable { + runCastHelper(ZERO_EXTEND_B2I, BSPEC64, ISPEC64); + } + + @Test + @IR(counts = {UB2X_NODE, "1"}) + public static void testUB64toI128(byte[] input, int[] output) { + vectorCast(ZERO_EXTEND_B2I, BSPEC64, ISPEC128, input, output); + } + + @Run(test = "testUB64toI128") + public static void runUB64toI128() throws Throwable { + runCastHelper(ZERO_EXTEND_B2I, BSPEC64, ISPEC128); + } + + @Test + @IR(counts = {UB2X_NODE, "1"}) + public static void testUB64toI256(byte[] input, int[] output) { + vectorCast(ZERO_EXTEND_B2I, BSPEC64, ISPEC256, input, output); + } + + @Run(test = "testUB64toI256") + public static void runUB64toI256() throws Throwable { + runCastHelper(ZERO_EXTEND_B2I, BSPEC64, ISPEC256); + } + + @Test + @IR(counts = {UB2X_NODE, "1"}) + public static void testUB128toI512(byte[] input, int[] output) { + vectorCast(ZERO_EXTEND_B2I, BSPEC128, ISPEC512, input, output); + } + + @Run(test = "testUB128toI512") + public static void runUB128toI512() throws Throwable { + runCastHelper(ZERO_EXTEND_B2I, BSPEC128, ISPEC512); + } + + @Test + @IR(counts = {UB2X_NODE, "1"}) + public static void testUB64toL64(byte[] input, long[] output) { + vectorCast(ZERO_EXTEND_B2L, BSPEC64, LSPEC64, input, output); + } + + @Run(test = "testUB64toL64") + public static void runUB64toL64() throws Throwable { + runCastHelper(ZERO_EXTEND_B2L, BSPEC64, LSPEC64); + } + + @Test + @IR(counts = {UB2X_NODE, "1"}) + public static void testUB64toL128(byte[] input, long[] output) { + vectorCast(ZERO_EXTEND_B2L, BSPEC64, LSPEC128, input, output); + } + + @Run(test = "testUB64toL128") + public static void runUB64toL128() throws Throwable { + runCastHelper(ZERO_EXTEND_B2L, BSPEC64, LSPEC128); + } + + @Test + @IR(counts = {UB2X_NODE, "1"}) + public static void testUB64toL256(byte[] input, long[] output) { + vectorCast(ZERO_EXTEND_B2L, BSPEC64, LSPEC256, input, output); + } + + @Run(test = "testUB64toL256") + public static void runUB64toL256() throws Throwable { + runCastHelper(ZERO_EXTEND_B2L, BSPEC64, LSPEC256); + } + + @Test + @IR(counts = {UB2X_NODE, "1"}) + public static void testUB64toL512(byte[] input, long[] output) { + vectorCast(ZERO_EXTEND_B2L, BSPEC64, LSPEC512, input, output); + } + + @Run(test = "testUB64toL512") + public static void runUB64toL512() throws Throwable { + runCastHelper(ZERO_EXTEND_B2L, BSPEC64, LSPEC512); + } + + @Test + @IR(counts = {US2X_NODE, "1"}) + public static void testUS64toI64(short[] input, int[] output) { + vectorCast(ZERO_EXTEND_S2I, SSPEC64, ISPEC64, input, output); + } + + @Run(test = "testUS64toI64") + public static void runUS64toI64() throws Throwable { + runCastHelper(ZERO_EXTEND_S2I, SSPEC64, ISPEC64); + } + + @Test + @IR(counts = {US2X_NODE, "1"}) + public static void testUS64toI128(short[] input, int[] output) { + vectorCast(ZERO_EXTEND_S2I, SSPEC64, ISPEC128, input, output); + } + + @Run(test = "testUS64toI128") + public static void runUS64toI128() throws Throwable { + runCastHelper(ZERO_EXTEND_S2I, SSPEC64, ISPEC128); + } + + @Test + @IR(counts = {US2X_NODE, "1"}) + public static void testUS128toI256(short[] input, int[] output) { + vectorCast(ZERO_EXTEND_S2I, SSPEC128, ISPEC256, input, output); + } + + @Run(test = "testUS128toI256") + public static void runUS128toI256() throws Throwable { + runCastHelper(ZERO_EXTEND_S2I, SSPEC128, ISPEC256); + } + + @Test + @IR(counts = {US2X_NODE, "1"}) + public static void testUS256toI512(short[] input, int[] output) { + vectorCast(ZERO_EXTEND_S2I, SSPEC256, ISPEC512, input, output); + } + + @Run(test = "testUS256toI512") + public static void runUS256toI512() throws Throwable { + runCastHelper(ZERO_EXTEND_S2I, SSPEC256, ISPEC512); + } + + @Test + @IR(counts = {US2X_NODE, "1"}) + public static void testUS64toL64(short[] input, long[] output) { + vectorCast(ZERO_EXTEND_S2L, SSPEC64, LSPEC64, input, output); + } + + @Run(test = "testUS64toL64") + public static void runUS64toL64() throws Throwable { + runCastHelper(ZERO_EXTEND_S2L, SSPEC64, LSPEC64); + } + + @Test + @IR(counts = {US2X_NODE, "1"}) + public static void testUS64toL128(short[] input, long[] output) { + vectorCast(ZERO_EXTEND_S2L, SSPEC64, LSPEC128, input, output); + } + + @Run(test = "testUS64toL128") + public static void runUS64toL128() throws Throwable { + runCastHelper(ZERO_EXTEND_S2L, SSPEC64, LSPEC128); + } + + @Test + @IR(counts = {US2X_NODE, "1"}) + public static void testUS64toL256(short[] input, long[] output) { + vectorCast(ZERO_EXTEND_S2L, SSPEC64, LSPEC256, input, output); + } + + @Run(test = "testUS64toL256") + public static void runUS64toL256() throws Throwable { + runCastHelper(ZERO_EXTEND_S2L, SSPEC64, LSPEC256); + } + + @Test + @IR(counts = {US2X_NODE, "1"}) + public static void testUS128toL512(short[] input, long[] output) { + vectorCast(ZERO_EXTEND_S2L, SSPEC128, LSPEC512, input, output); + } + + @Run(test = "testUS128toL512") + public static void runUS128toL512() throws Throwable { + runCastHelper(ZERO_EXTEND_S2L, SSPEC128, LSPEC512); + } + + @Test + @IR(counts = {UI2X_NODE, "1"}) + public static void testUI64toL64(int[] input, long[] output) { + vectorCast(ZERO_EXTEND_I2L, ISPEC64, LSPEC64, input, output); + } + + @Run(test = "testUI64toL64") + public static void runUI64toL64() throws Throwable { + runCastHelper(ZERO_EXTEND_I2L, ISPEC64, LSPEC64); + } + + @Test + @IR(counts = {UI2X_NODE, "1"}) + public static void testUI64toL128(int[] input, long[] output) { + vectorCast(ZERO_EXTEND_I2L, ISPEC64, LSPEC128, input, output); + } + + @Run(test = "testUI64toL128") + public static void runUI64toL128() throws Throwable { + runCastHelper(ZERO_EXTEND_I2L, ISPEC64, LSPEC128); + } + + @Test + @IR(counts = {UI2X_NODE, "1"}) + public static void testUI128toL256(int[] input, long[] output) { + vectorCast(ZERO_EXTEND_I2L, ISPEC128, LSPEC256, input, output); + } + + @Run(test = "testUI128toL256") + public static void runUI128toL256() throws Throwable { + runCastHelper(ZERO_EXTEND_I2L, ISPEC128, LSPEC256); + } + + @Test + @IR(counts = {UI2X_NODE, "1"}) + public static void testUI256toL512(int[] input, long[] output) { + vectorCast(ZERO_EXTEND_I2L, ISPEC256, LSPEC512, input, output); + } + + @Run(test = "testUI256toL512") + public static void runUI256toL512() throws Throwable { + runCastHelper(ZERO_EXTEND_I2L, ISPEC256, LSPEC512); + } +} diff --git a/test/hotspot/jtreg/compiler/vectorapi/reshape/tests/TestVectorDoubleExpandShrink.java b/test/hotspot/jtreg/compiler/vectorapi/reshape/tests/TestVectorDoubleExpandShrink.java new file mode 100644 index 0000000000000000000000000000000000000000..1056cfedcfcdd038b4280695c8ed57793f7d87fd --- /dev/null +++ b/test/hotspot/jtreg/compiler/vectorapi/reshape/tests/TestVectorDoubleExpandShrink.java @@ -0,0 +1,170 @@ +/* + * 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. + */ + +package compiler.vectorapi.reshape.tests; + +import compiler.lib.ir_framework.IR; +import compiler.lib.ir_framework.Run; +import compiler.lib.ir_framework.Test; + +import static compiler.vectorapi.reshape.utils.VectorReshapeHelper.*; + +/** + * As spot in 8259353. We need to do a shrink and an expand together to not accidentally + * zero out elements in the physical registers that may not be zero in general cases. + * + * In some methods, 2 consecutive ReinterpretNodes may be optimized out. + */ +public class TestVectorDoubleExpandShrink { + @Test + @IR(failOn = REINTERPRET_NODE) + public static void testB64toB128(byte[] input, byte[] output) { + vectorDoubleExpandShrink(BSPEC64, BSPEC128, input, output); + } + + @Run(test = "testB64toB128") + public static void runB64toB128() throws Throwable { + runDoubleExpandShrinkHelper(BSPEC64, BSPEC128); + } + + @Test + @IR(failOn = REINTERPRET_NODE) + public static void testB64toB256(byte[] input, byte[] output) { + vectorDoubleExpandShrink(BSPEC64, BSPEC256, input, output); + } + + @Run(test = "testB64toB256") + public static void runB64toB256() throws Throwable { + runDoubleExpandShrinkHelper(BSPEC64, BSPEC256); + } + + @Test + @IR(failOn = REINTERPRET_NODE) + public static void testB64toB512(byte[] input, byte[] output) { + vectorDoubleExpandShrink(BSPEC64, BSPEC512, input, output); + } + + @Run(test = "testB64toB512") + public static void runB64toB512() throws Throwable { + runDoubleExpandShrinkHelper(BSPEC64, BSPEC512); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "2"}) + public static void testB128toB64(byte[] input, byte[] output) { + vectorDoubleExpandShrink(BSPEC128, BSPEC64, input, output); + } + + @Run(test = "testB128toB64") + public static void runB128toB64() throws Throwable { + runDoubleExpandShrinkHelper(BSPEC128, BSPEC64); + } + + @Test + @IR(failOn = REINTERPRET_NODE) + public static void testB128toB256(byte[] input, byte[] output) { + vectorDoubleExpandShrink(BSPEC128, BSPEC256, input, output); + } + + @Run(test = "testB128toB256") + public static void runB128toB256() throws Throwable { + runDoubleExpandShrinkHelper(BSPEC128, BSPEC256); + } + + @Test + @IR(failOn = REINTERPRET_NODE) + public static void testB128toB512(byte[] input, byte[] output) { + vectorDoubleExpandShrink(BSPEC128, BSPEC512, input, output); + } + + @Run(test = "testB128toB512") + public static void runB128toB512() throws Throwable { + runDoubleExpandShrinkHelper(BSPEC128, BSPEC512); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "2"}) + public static void testB256toB64(byte[] input, byte[] output) { + vectorDoubleExpandShrink(BSPEC256, BSPEC64, input, output); + } + + @Run(test = "testB256toB64") + public static void runB256toB64() throws Throwable { + runDoubleExpandShrinkHelper(BSPEC256, BSPEC64); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "2"}) + public static void testB256toB128(byte[] input, byte[] output) { + vectorDoubleExpandShrink(BSPEC256, BSPEC128, input, output); + } + + @Run(test = "testB256toB128") + public static void runB256toB128() throws Throwable { + runDoubleExpandShrinkHelper(BSPEC256, BSPEC128); + } + + @Test + @IR(failOn = REINTERPRET_NODE) + public static void testB256toB512(byte[] input, byte[] output) { + vectorDoubleExpandShrink(BSPEC256, BSPEC512, input, output); + } + + @Run(test = "testB256toB512") + public static void runB256toB512() throws Throwable { + runDoubleExpandShrinkHelper(BSPEC256, BSPEC512); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "2"}) + public static void testB512toB64(byte[] input, byte[] output) { + vectorDoubleExpandShrink(BSPEC512, BSPEC64, input, output); + } + + @Run(test = "testB512toB64") + public static void runB512toB64() throws Throwable { + runDoubleExpandShrinkHelper(BSPEC512, BSPEC64); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "2"}) + public static void testB512toB128(byte[] input, byte[] output) { + vectorDoubleExpandShrink(BSPEC512, BSPEC128, input, output); + } + + @Run(test = "testB512toB128") + public static void runB512toB128() throws Throwable { + runDoubleExpandShrinkHelper(BSPEC512, BSPEC128); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "2"}) + public static void testB512toB256(byte[] input, byte[] output) { + vectorDoubleExpandShrink(BSPEC512, BSPEC256, input, output); + } + + @Run(test = "testB512toB256") + public static void runB512toB256() throws Throwable { + runDoubleExpandShrinkHelper(BSPEC512, BSPEC256); + } +} diff --git a/test/hotspot/jtreg/compiler/vectorapi/reshape/tests/TestVectorExpandShrink.java b/test/hotspot/jtreg/compiler/vectorapi/reshape/tests/TestVectorExpandShrink.java new file mode 100644 index 0000000000000000000000000000000000000000..f975331cef08077df81729d784cbfdd2a25f5a2d --- /dev/null +++ b/test/hotspot/jtreg/compiler/vectorapi/reshape/tests/TestVectorExpandShrink.java @@ -0,0 +1,170 @@ +/* + * 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. + */ + +package compiler.vectorapi.reshape.tests; + +import compiler.lib.ir_framework.IR; +import compiler.lib.ir_framework.Run; +import compiler.lib.ir_framework.Test; + +import static compiler.vectorapi.reshape.utils.VectorReshapeHelper.*; + +/** + * This class contains method to ensure a resizing reinterpretation operations work as + * intended. + * + * In each test, the ReinterpretNode is expected to appear exactly once. + */ +public class TestVectorExpandShrink { + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testB64toB128(byte[] input, byte[] output) { + vectorExpandShrink(BSPEC64, BSPEC128, input, output); + } + + @Run(test = "testB64toB128") + public static void runB64toB128() throws Throwable { + runExpandShrinkHelper(BSPEC64, BSPEC128); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testB64toB256(byte[] input, byte[] output) { + vectorExpandShrink(BSPEC64, BSPEC256, input, output); + } + + @Run(test = "testB64toB256") + public static void runB64toB256() throws Throwable { + runExpandShrinkHelper(BSPEC64, BSPEC256); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testB64toB512(byte[] input, byte[] output) { + vectorExpandShrink(BSPEC64, BSPEC512, input, output); + } + + @Run(test = "testB64toB512") + public static void runB64toB512() throws Throwable { + runExpandShrinkHelper(BSPEC64, BSPEC512); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testB128toB64(byte[] input, byte[] output) { + vectorExpandShrink(BSPEC128, BSPEC64, input, output); + } + + @Run(test = "testB128toB64") + public static void runB128toB64() throws Throwable { + runExpandShrinkHelper(BSPEC128, BSPEC64); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testB128toB256(byte[] input, byte[] output) { + vectorExpandShrink(BSPEC128, BSPEC256, input, output); + } + + @Run(test = "testB128toB256") + public static void runB128toB256() throws Throwable { + runExpandShrinkHelper(BSPEC128, BSPEC256); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testB128toB512(byte[] input, byte[] output) { + vectorExpandShrink(BSPEC128, BSPEC512, input, output); + } + + @Run(test = "testB128toB512") + public static void runB128toB512() throws Throwable { + runExpandShrinkHelper(BSPEC128, BSPEC512); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testB256toB64(byte[] input, byte[] output) { + vectorExpandShrink(BSPEC256, BSPEC64, input, output); + } + + @Run(test = "testB256toB64") + public static void runB256toB64() throws Throwable { + runExpandShrinkHelper(BSPEC256, BSPEC64); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testB256toB128(byte[] input, byte[] output) { + vectorExpandShrink(BSPEC256, BSPEC128, input, output); + } + + @Run(test = "testB256toB128") + public static void runB256toB128() throws Throwable { + runExpandShrinkHelper(BSPEC256, BSPEC128); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testB256toB512(byte[] input, byte[] output) { + vectorExpandShrink(BSPEC256, BSPEC512, input, output); + } + + @Run(test = "testB256toB512") + public static void runB256toB512() throws Throwable { + runExpandShrinkHelper(BSPEC256, BSPEC512); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testB512toB64(byte[] input, byte[] output) { + vectorExpandShrink(BSPEC512, BSPEC64, input, output); + } + + @Run(test = "testB512toB64") + public static void runB512toB64() throws Throwable { + runExpandShrinkHelper(BSPEC512, BSPEC64); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testB512toB128(byte[] input, byte[] output) { + vectorExpandShrink(BSPEC512, BSPEC128, input, output); + } + + @Run(test = "testB512toB128") + public static void runB512toB128() throws Throwable { + runExpandShrinkHelper(BSPEC512, BSPEC128); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testB512toB256(byte[] input, byte[] output) { + vectorExpandShrink(BSPEC512, BSPEC256, input, output); + } + + @Run(test = "testB512toB256") + public static void runB512toB256() throws Throwable { + runExpandShrinkHelper(BSPEC512, BSPEC256); + } +} diff --git a/test/hotspot/jtreg/compiler/vectorapi/reshape/tests/TestVectorRebracket.java b/test/hotspot/jtreg/compiler/vectorapi/reshape/tests/TestVectorRebracket.java new file mode 100644 index 0000000000000000000000000000000000000000..2143eb3b500326f42aa99b22ec996849f71060c6 --- /dev/null +++ b/test/hotspot/jtreg/compiler/vectorapi/reshape/tests/TestVectorRebracket.java @@ -0,0 +1,1362 @@ +/* + * 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. + */ + +package compiler.vectorapi.reshape.tests; + +import compiler.lib.ir_framework.IR; +import compiler.lib.ir_framework.Run; +import compiler.lib.ir_framework.Test; + +import static compiler.vectorapi.reshape.utils.VectorReshapeHelper.*; + +/** + * This class contains methods to test for reinterpretation operations that reinterpret + * a vector as a similar vector with another element type. + * + * It is complicated to verify the IR in this case since a load/store with respect to + * byte array will result in additional ReinterpretNodes if the vector element type is + * not byte. As a result, arguments need to be arrays of the correct type. + * + * In each test, the ReinterpretNode is expected to appear exactly once. + */ +public class TestVectorRebracket { + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testB64toS64(byte[] input, short[] output) { + vectorRebracket(BSPEC64, SSPEC64, input, output); + } + + @Run(test = "testB64toS64") + public static void runB64toS64() throws Throwable { + runRebracketHelper(BSPEC64, SSPEC64); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testB64toI64(byte[] input, int[] output) { + vectorRebracket(BSPEC64, ISPEC64, input, output); + } + + @Run(test = "testB64toI64") + public static void runB64toI64() throws Throwable { + runRebracketHelper(BSPEC64, ISPEC64); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testB64toL64(byte[] input, long[] output) { + vectorRebracket(BSPEC64, LSPEC64, input, output); + } + + @Run(test = "testB64toL64") + public static void runB64toL64() throws Throwable { + runRebracketHelper(BSPEC64, LSPEC64); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testB64toF64(byte[] input, float[] output) { + vectorRebracket(BSPEC64, FSPEC64, input, output); + } + + @Run(test = "testB64toF64") + public static void runB64toF64() throws Throwable { + runRebracketHelper(BSPEC64, FSPEC64); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testB64toD64(byte[] input, double[] output) { + vectorRebracket(BSPEC64, DSPEC64, input, output); + } + + @Run(test = "testB64toD64") + public static void runB64toD64() throws Throwable { + runRebracketHelper(BSPEC64, DSPEC64); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testS64toB64(short[] input, byte[] output) { + vectorRebracket(SSPEC64, BSPEC64, input, output); + } + + @Run(test = "testS64toB64") + public static void runS64toB64() throws Throwable { + runRebracketHelper(SSPEC64, BSPEC64); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testS64toI64(short[] input, int[] output) { + vectorRebracket(SSPEC64, ISPEC64, input, output); + } + + @Run(test = "testS64toI64") + public static void runS64toI64() throws Throwable { + runRebracketHelper(SSPEC64, ISPEC64); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testS64toL64(short[] input, long[] output) { + vectorRebracket(SSPEC64, LSPEC64, input, output); + } + + @Run(test = "testS64toL64") + public static void runS64toL64() throws Throwable { + runRebracketHelper(SSPEC64, LSPEC64); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testS64toF64(short[] input, float[] output) { + vectorRebracket(SSPEC64, FSPEC64, input, output); + } + + @Run(test = "testS64toF64") + public static void runS64toF64() throws Throwable { + runRebracketHelper(SSPEC64, FSPEC64); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testS64toD64(short[] input, double[] output) { + vectorRebracket(SSPEC64, DSPEC64, input, output); + } + + @Run(test = "testS64toD64") + public static void runS64toD64() throws Throwable { + runRebracketHelper(SSPEC64, DSPEC64); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testI64toB64(int[] input, byte[] output) { + vectorRebracket(ISPEC64, BSPEC64, input, output); + } + + @Run(test = "testI64toB64") + public static void runI64toB64() throws Throwable { + runRebracketHelper(ISPEC64, BSPEC64); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testI64toS64(int[] input, short[] output) { + vectorRebracket(ISPEC64, SSPEC64, input, output); + } + + @Run(test = "testI64toS64") + public static void runI64toS64() throws Throwable { + runRebracketHelper(ISPEC64, SSPEC64); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testI64toL64(int[] input, long[] output) { + vectorRebracket(ISPEC64, LSPEC64, input, output); + } + + @Run(test = "testI64toL64") + public static void runI64toL64() throws Throwable { + runRebracketHelper(ISPEC64, LSPEC64); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testI64toF64(int[] input, float[] output) { + vectorRebracket(ISPEC64, FSPEC64, input, output); + } + + @Run(test = "testI64toF64") + public static void runI64toF64() throws Throwable { + runRebracketHelper(ISPEC64, FSPEC64); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testI64toD64(int[] input, double[] output) { + vectorRebracket(ISPEC64, DSPEC64, input, output); + } + + @Run(test = "testI64toD64") + public static void runI64toD64() throws Throwable { + runRebracketHelper(ISPEC64, DSPEC64); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testL64toB64(long[] input, byte[] output) { + vectorRebracket(LSPEC64, BSPEC64, input, output); + } + + @Run(test = "testL64toB64") + public static void runL64toB64() throws Throwable { + runRebracketHelper(LSPEC64, BSPEC64); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testL64toS64(long[] input, short[] output) { + vectorRebracket(LSPEC64, SSPEC64, input, output); + } + + @Run(test = "testL64toS64") + public static void runL64toS64() throws Throwable { + runRebracketHelper(LSPEC64, SSPEC64); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testL64toI64(long[] input, int[] output) { + vectorRebracket(LSPEC64, ISPEC64, input, output); + } + + @Run(test = "testL64toI64") + public static void runL64toI64() throws Throwable { + runRebracketHelper(LSPEC64, ISPEC64); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testL64toF64(long[] input, float[] output) { + vectorRebracket(LSPEC64, FSPEC64, input, output); + } + + @Run(test = "testL64toF64") + public static void runL64toF64() throws Throwable { + runRebracketHelper(LSPEC64, FSPEC64); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testL64toD64(long[] input, double[] output) { + vectorRebracket(LSPEC64, DSPEC64, input, output); + } + + @Run(test = "testL64toD64") + public static void runL64toD64() throws Throwable { + runRebracketHelper(LSPEC64, DSPEC64); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testF64toB64(float[] input, byte[] output) { + vectorRebracket(FSPEC64, BSPEC64, input, output); + } + + @Run(test = "testF64toB64") + public static void runF64toB64() throws Throwable { + runRebracketHelper(FSPEC64, BSPEC64); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testF64toS64(float[] input, short[] output) { + vectorRebracket(FSPEC64, SSPEC64, input, output); + } + + @Run(test = "testF64toS64") + public static void runF64toS64() throws Throwable { + runRebracketHelper(FSPEC64, SSPEC64); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testF64toI64(float[] input, int[] output) { + vectorRebracket(FSPEC64, ISPEC64, input, output); + } + + @Run(test = "testF64toI64") + public static void runF64toI64() throws Throwable { + runRebracketHelper(FSPEC64, ISPEC64); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testF64toL64(float[] input, long[] output) { + vectorRebracket(FSPEC64, LSPEC64, input, output); + } + + @Run(test = "testF64toL64") + public static void runF64toL64() throws Throwable { + runRebracketHelper(FSPEC64, LSPEC64); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testF64toD64(float[] input, double[] output) { + vectorRebracket(FSPEC64, DSPEC64, input, output); + } + + @Run(test = "testF64toD64") + public static void runF64toD64() throws Throwable { + runRebracketHelper(FSPEC64, DSPEC64); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testD64toB64(double[] input, byte[] output) { + vectorRebracket(DSPEC64, BSPEC64, input, output); + } + + @Run(test = "testD64toB64") + public static void runD64toB64() throws Throwable { + runRebracketHelper(DSPEC64, BSPEC64); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testD64toS64(double[] input, short[] output) { + vectorRebracket(DSPEC64, SSPEC64, input, output); + } + + @Run(test = "testD64toS64") + public static void runD64toS64() throws Throwable { + runRebracketHelper(DSPEC64, SSPEC64); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testD64toI64(double[] input, int[] output) { + vectorRebracket(DSPEC64, ISPEC64, input, output); + } + + @Run(test = "testD64toI64") + public static void runD64toI64() throws Throwable { + runRebracketHelper(DSPEC64, ISPEC64); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testD64toL64(double[] input, long[] output) { + vectorRebracket(DSPEC64, LSPEC64, input, output); + } + + @Run(test = "testD64toL64") + public static void runD64toL64() throws Throwable { + runRebracketHelper(DSPEC64, LSPEC64); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testD64toF64(double[] input, float[] output) { + vectorRebracket(DSPEC64, FSPEC64, input, output); + } + + @Run(test = "testD64toF64") + public static void runD64toF64() throws Throwable { + runRebracketHelper(DSPEC64, FSPEC64); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testB128toS128(byte[] input, short[] output) { + vectorRebracket(BSPEC128, SSPEC128, input, output); + } + + @Run(test = "testB128toS128") + public static void runB128toS128() throws Throwable { + runRebracketHelper(BSPEC128, SSPEC128); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testB128toI128(byte[] input, int[] output) { + vectorRebracket(BSPEC128, ISPEC128, input, output); + } + + @Run(test = "testB128toI128") + public static void runB128toI128() throws Throwable { + runRebracketHelper(BSPEC128, ISPEC128); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testB128toL128(byte[] input, long[] output) { + vectorRebracket(BSPEC128, LSPEC128, input, output); + } + + @Run(test = "testB128toL128") + public static void runB128toL128() throws Throwable { + runRebracketHelper(BSPEC128, LSPEC128); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testB128toF128(byte[] input, float[] output) { + vectorRebracket(BSPEC128, FSPEC128, input, output); + } + + @Run(test = "testB128toF128") + public static void runB128toF128() throws Throwable { + runRebracketHelper(BSPEC128, FSPEC128); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testB128toD128(byte[] input, double[] output) { + vectorRebracket(BSPEC128, DSPEC128, input, output); + } + + @Run(test = "testB128toD128") + public static void runB128toD128() throws Throwable { + runRebracketHelper(BSPEC128, DSPEC128); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testS128toB128(short[] input, byte[] output) { + vectorRebracket(SSPEC128, BSPEC128, input, output); + } + + @Run(test = "testS128toB128") + public static void runS128toB128() throws Throwable { + runRebracketHelper(SSPEC128, BSPEC128); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testS128toI128(short[] input, int[] output) { + vectorRebracket(SSPEC128, ISPEC128, input, output); + } + + @Run(test = "testS128toI128") + public static void runS128toI128() throws Throwable { + runRebracketHelper(SSPEC128, ISPEC128); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testS128toL128(short[] input, long[] output) { + vectorRebracket(SSPEC128, LSPEC128, input, output); + } + + @Run(test = "testS128toL128") + public static void runS128toL128() throws Throwable { + runRebracketHelper(SSPEC128, LSPEC128); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testS128toF128(short[] input, float[] output) { + vectorRebracket(SSPEC128, FSPEC128, input, output); + } + + @Run(test = "testS128toF128") + public static void runS128toF128() throws Throwable { + runRebracketHelper(SSPEC128, FSPEC128); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testS128toD128(short[] input, double[] output) { + vectorRebracket(SSPEC128, DSPEC128, input, output); + } + + @Run(test = "testS128toD128") + public static void runS128toD128() throws Throwable { + runRebracketHelper(SSPEC128, DSPEC128); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testI128toB128(int[] input, byte[] output) { + vectorRebracket(ISPEC128, BSPEC128, input, output); + } + + @Run(test = "testI128toB128") + public static void runI128toB128() throws Throwable { + runRebracketHelper(ISPEC128, BSPEC128); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testI128toS128(int[] input, short[] output) { + vectorRebracket(ISPEC128, SSPEC128, input, output); + } + + @Run(test = "testI128toS128") + public static void runI128toS128() throws Throwable { + runRebracketHelper(ISPEC128, SSPEC128); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testI128toL128(int[] input, long[] output) { + vectorRebracket(ISPEC128, LSPEC128, input, output); + } + + @Run(test = "testI128toL128") + public static void runI128toL128() throws Throwable { + runRebracketHelper(ISPEC128, LSPEC128); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testI128toF128(int[] input, float[] output) { + vectorRebracket(ISPEC128, FSPEC128, input, output); + } + + @Run(test = "testI128toF128") + public static void runI128toF128() throws Throwable { + runRebracketHelper(ISPEC128, FSPEC128); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testI128toD128(int[] input, double[] output) { + vectorRebracket(ISPEC128, DSPEC128, input, output); + } + + @Run(test = "testI128toD128") + public static void runI128toD128() throws Throwable { + runRebracketHelper(ISPEC128, DSPEC128); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testL128toB128(long[] input, byte[] output) { + vectorRebracket(LSPEC128, BSPEC128, input, output); + } + + @Run(test = "testL128toB128") + public static void runL128toB128() throws Throwable { + runRebracketHelper(LSPEC128, BSPEC128); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testL128toS128(long[] input, short[] output) { + vectorRebracket(LSPEC128, SSPEC128, input, output); + } + + @Run(test = "testL128toS128") + public static void runL128toS128() throws Throwable { + runRebracketHelper(LSPEC128, SSPEC128); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testL128toI128(long[] input, int[] output) { + vectorRebracket(LSPEC128, ISPEC128, input, output); + } + + @Run(test = "testL128toI128") + public static void runL128toI128() throws Throwable { + runRebracketHelper(LSPEC128, ISPEC128); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testL128toF128(long[] input, float[] output) { + vectorRebracket(LSPEC128, FSPEC128, input, output); + } + + @Run(test = "testL128toF128") + public static void runL128toF128() throws Throwable { + runRebracketHelper(LSPEC128, FSPEC128); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testL128toD128(long[] input, double[] output) { + vectorRebracket(LSPEC128, DSPEC128, input, output); + } + + @Run(test = "testL128toD128") + public static void runL128toD128() throws Throwable { + runRebracketHelper(LSPEC128, DSPEC128); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testF128toB128(float[] input, byte[] output) { + vectorRebracket(FSPEC128, BSPEC128, input, output); + } + + @Run(test = "testF128toB128") + public static void runF128toB128() throws Throwable { + runRebracketHelper(FSPEC128, BSPEC128); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testF128toS128(float[] input, short[] output) { + vectorRebracket(FSPEC128, SSPEC128, input, output); + } + + @Run(test = "testF128toS128") + public static void runF128toS128() throws Throwable { + runRebracketHelper(FSPEC128, SSPEC128); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testF128toI128(float[] input, int[] output) { + vectorRebracket(FSPEC128, ISPEC128, input, output); + } + + @Run(test = "testF128toI128") + public static void runF128toI128() throws Throwable { + runRebracketHelper(FSPEC128, ISPEC128); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testF128toL128(float[] input, long[] output) { + vectorRebracket(FSPEC128, LSPEC128, input, output); + } + + @Run(test = "testF128toL128") + public static void runF128toL128() throws Throwable { + runRebracketHelper(FSPEC128, LSPEC128); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testF128toD128(float[] input, double[] output) { + vectorRebracket(FSPEC128, DSPEC128, input, output); + } + + @Run(test = "testF128toD128") + public static void runF128toD128() throws Throwable { + runRebracketHelper(FSPEC128, DSPEC128); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testD128toB128(double[] input, byte[] output) { + vectorRebracket(DSPEC128, BSPEC128, input, output); + } + + @Run(test = "testD128toB128") + public static void runD128toB128() throws Throwable { + runRebracketHelper(DSPEC128, BSPEC128); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testD128toS128(double[] input, short[] output) { + vectorRebracket(DSPEC128, SSPEC128, input, output); + } + + @Run(test = "testD128toS128") + public static void runD128toS128() throws Throwable { + runRebracketHelper(DSPEC128, SSPEC128); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testD128toI128(double[] input, int[] output) { + vectorRebracket(DSPEC128, ISPEC128, input, output); + } + + @Run(test = "testD128toI128") + public static void runD128toI128() throws Throwable { + runRebracketHelper(DSPEC128, ISPEC128); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testD128toL128(double[] input, long[] output) { + vectorRebracket(DSPEC128, LSPEC128, input, output); + } + + @Run(test = "testD128toL128") + public static void runD128toL128() throws Throwable { + runRebracketHelper(DSPEC128, LSPEC128); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testD128toF128(double[] input, float[] output) { + vectorRebracket(DSPEC128, FSPEC128, input, output); + } + + @Run(test = "testD128toF128") + public static void runD128toF128() throws Throwable { + runRebracketHelper(DSPEC128, FSPEC128); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testB256toS256(byte[] input, short[] output) { + vectorRebracket(BSPEC256, SSPEC256, input, output); + } + + @Run(test = "testB256toS256") + public static void runB256toS256() throws Throwable { + runRebracketHelper(BSPEC256, SSPEC256); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testB256toI256(byte[] input, int[] output) { + vectorRebracket(BSPEC256, ISPEC256, input, output); + } + + @Run(test = "testB256toI256") + public static void runB256toI256() throws Throwable { + runRebracketHelper(BSPEC256, ISPEC256); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testB256toL256(byte[] input, long[] output) { + vectorRebracket(BSPEC256, LSPEC256, input, output); + } + + @Run(test = "testB256toL256") + public static void runB256toL256() throws Throwable { + runRebracketHelper(BSPEC256, LSPEC256); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testB256toF256(byte[] input, float[] output) { + vectorRebracket(BSPEC256, FSPEC256, input, output); + } + + @Run(test = "testB256toF256") + public static void runB256toF256() throws Throwable { + runRebracketHelper(BSPEC256, FSPEC256); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testB256toD256(byte[] input, double[] output) { + vectorRebracket(BSPEC256, DSPEC256, input, output); + } + + @Run(test = "testB256toD256") + public static void runB256toD256() throws Throwable { + runRebracketHelper(BSPEC256, DSPEC256); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testS256toB256(short[] input, byte[] output) { + vectorRebracket(SSPEC256, BSPEC256, input, output); + } + + @Run(test = "testS256toB256") + public static void runS256toB256() throws Throwable { + runRebracketHelper(SSPEC256, BSPEC256); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testS256toI256(short[] input, int[] output) { + vectorRebracket(SSPEC256, ISPEC256, input, output); + } + + @Run(test = "testS256toI256") + public static void runS256toI256() throws Throwable { + runRebracketHelper(SSPEC256, ISPEC256); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testS256toL256(short[] input, long[] output) { + vectorRebracket(SSPEC256, LSPEC256, input, output); + } + + @Run(test = "testS256toL256") + public static void runS256toL256() throws Throwable { + runRebracketHelper(SSPEC256, LSPEC256); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testS256toF256(short[] input, float[] output) { + vectorRebracket(SSPEC256, FSPEC256, input, output); + } + + @Run(test = "testS256toF256") + public static void runS256toF256() throws Throwable { + runRebracketHelper(SSPEC256, FSPEC256); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testS256toD256(short[] input, double[] output) { + vectorRebracket(SSPEC256, DSPEC256, input, output); + } + + @Run(test = "testS256toD256") + public static void runS256toD256() throws Throwable { + runRebracketHelper(SSPEC256, DSPEC256); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testI256toB256(int[] input, byte[] output) { + vectorRebracket(ISPEC256, BSPEC256, input, output); + } + + @Run(test = "testI256toB256") + public static void runI256toB256() throws Throwable { + runRebracketHelper(ISPEC256, BSPEC256); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testI256toS256(int[] input, short[] output) { + vectorRebracket(ISPEC256, SSPEC256, input, output); + } + + @Run(test = "testI256toS256") + public static void runI256toS256() throws Throwable { + runRebracketHelper(ISPEC256, SSPEC256); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testI256toL256(int[] input, long[] output) { + vectorRebracket(ISPEC256, LSPEC256, input, output); + } + + @Run(test = "testI256toL256") + public static void runI256toL256() throws Throwable { + runRebracketHelper(ISPEC256, LSPEC256); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testI256toF256(int[] input, float[] output) { + vectorRebracket(ISPEC256, FSPEC256, input, output); + } + + @Run(test = "testI256toF256") + public static void runI256toF256() throws Throwable { + runRebracketHelper(ISPEC256, FSPEC256); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testI256toD256(int[] input, double[] output) { + vectorRebracket(ISPEC256, DSPEC256, input, output); + } + + @Run(test = "testI256toD256") + public static void runI256toD256() throws Throwable { + runRebracketHelper(ISPEC256, DSPEC256); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testL256toB256(long[] input, byte[] output) { + vectorRebracket(LSPEC256, BSPEC256, input, output); + } + + @Run(test = "testL256toB256") + public static void runL256toB256() throws Throwable { + runRebracketHelper(LSPEC256, BSPEC256); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testL256toS256(long[] input, short[] output) { + vectorRebracket(LSPEC256, SSPEC256, input, output); + } + + @Run(test = "testL256toS256") + public static void runL256toS256() throws Throwable { + runRebracketHelper(LSPEC256, SSPEC256); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testL256toI256(long[] input, int[] output) { + vectorRebracket(LSPEC256, ISPEC256, input, output); + } + + @Run(test = "testL256toI256") + public static void runL256toI256() throws Throwable { + runRebracketHelper(LSPEC256, ISPEC256); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testL256toF256(long[] input, float[] output) { + vectorRebracket(LSPEC256, FSPEC256, input, output); + } + + @Run(test = "testL256toF256") + public static void runL256toF256() throws Throwable { + runRebracketHelper(LSPEC256, FSPEC256); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testL256toD256(long[] input, double[] output) { + vectorRebracket(LSPEC256, DSPEC256, input, output); + } + + @Run(test = "testL256toD256") + public static void runL256toD256() throws Throwable { + runRebracketHelper(LSPEC256, DSPEC256); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testF256toB256(float[] input, byte[] output) { + vectorRebracket(FSPEC256, BSPEC256, input, output); + } + + @Run(test = "testF256toB256") + public static void runF256toB256() throws Throwable { + runRebracketHelper(FSPEC256, BSPEC256); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testF256toS256(float[] input, short[] output) { + vectorRebracket(FSPEC256, SSPEC256, input, output); + } + + @Run(test = "testF256toS256") + public static void runF256toS256() throws Throwable { + runRebracketHelper(FSPEC256, SSPEC256); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testF256toI256(float[] input, int[] output) { + vectorRebracket(FSPEC256, ISPEC256, input, output); + } + + @Run(test = "testF256toI256") + public static void runF256toI256() throws Throwable { + runRebracketHelper(FSPEC256, ISPEC256); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testF256toL256(float[] input, long[] output) { + vectorRebracket(FSPEC256, LSPEC256, input, output); + } + + @Run(test = "testF256toL256") + public static void runF256toL256() throws Throwable { + runRebracketHelper(FSPEC256, LSPEC256); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testF256toD256(float[] input, double[] output) { + vectorRebracket(FSPEC256, DSPEC256, input, output); + } + + @Run(test = "testF256toD256") + public static void runF256toD256() throws Throwable { + runRebracketHelper(FSPEC256, DSPEC256); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testD256toB256(double[] input, byte[] output) { + vectorRebracket(DSPEC256, BSPEC256, input, output); + } + + @Run(test = "testD256toB256") + public static void runD256toB256() throws Throwable { + runRebracketHelper(DSPEC256, BSPEC256); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testD256toS256(double[] input, short[] output) { + vectorRebracket(DSPEC256, SSPEC256, input, output); + } + + @Run(test = "testD256toS256") + public static void runD256toS256() throws Throwable { + runRebracketHelper(DSPEC256, SSPEC256); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testD256toI256(double[] input, int[] output) { + vectorRebracket(DSPEC256, ISPEC256, input, output); + } + + @Run(test = "testD256toI256") + public static void runD256toI256() throws Throwable { + runRebracketHelper(DSPEC256, ISPEC256); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testD256toL256(double[] input, long[] output) { + vectorRebracket(DSPEC256, LSPEC256, input, output); + } + + @Run(test = "testD256toL256") + public static void runD256toL256() throws Throwable { + runRebracketHelper(DSPEC256, LSPEC256); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testD256toF256(double[] input, float[] output) { + vectorRebracket(DSPEC256, FSPEC256, input, output); + } + + @Run(test = "testD256toF256") + public static void runD256toF256() throws Throwable { + runRebracketHelper(DSPEC256, FSPEC256); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testB512toS512(byte[] input, short[] output) { + vectorRebracket(BSPEC512, SSPEC512, input, output); + } + + @Run(test = "testB512toS512") + public static void runB512toS512() throws Throwable { + runRebracketHelper(BSPEC512, SSPEC512); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testB512toI512(byte[] input, int[] output) { + vectorRebracket(BSPEC512, ISPEC512, input, output); + } + + @Run(test = "testB512toI512") + public static void runB512toI512() throws Throwable { + runRebracketHelper(BSPEC512, ISPEC512); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testB512toL512(byte[] input, long[] output) { + vectorRebracket(BSPEC512, LSPEC512, input, output); + } + + @Run(test = "testB512toL512") + public static void runB512toL512() throws Throwable { + runRebracketHelper(BSPEC512, LSPEC512); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testB512toF512(byte[] input, float[] output) { + vectorRebracket(BSPEC512, FSPEC512, input, output); + } + + @Run(test = "testB512toF512") + public static void runB512toF512() throws Throwable { + runRebracketHelper(BSPEC512, FSPEC512); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testB512toD512(byte[] input, double[] output) { + vectorRebracket(BSPEC512, DSPEC512, input, output); + } + + @Run(test = "testB512toD512") + public static void runB512toD512() throws Throwable { + runRebracketHelper(BSPEC512, DSPEC512); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testS512toB512(short[] input, byte[] output) { + vectorRebracket(SSPEC512, BSPEC512, input, output); + } + + @Run(test = "testS512toB512") + public static void runS512toB512() throws Throwable { + runRebracketHelper(SSPEC512, BSPEC512); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testS512toI512(short[] input, int[] output) { + vectorRebracket(SSPEC512, ISPEC512, input, output); + } + + @Run(test = "testS512toI512") + public static void runS512toI512() throws Throwable { + runRebracketHelper(SSPEC512, ISPEC512); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testS512toL512(short[] input, long[] output) { + vectorRebracket(SSPEC512, LSPEC512, input, output); + } + + @Run(test = "testS512toL512") + public static void runS512toL512() throws Throwable { + runRebracketHelper(SSPEC512, LSPEC512); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testS512toF512(short[] input, float[] output) { + vectorRebracket(SSPEC512, FSPEC512, input, output); + } + + @Run(test = "testS512toF512") + public static void runS512toF512() throws Throwable { + runRebracketHelper(SSPEC512, FSPEC512); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testS512toD512(short[] input, double[] output) { + vectorRebracket(SSPEC512, DSPEC512, input, output); + } + + @Run(test = "testS512toD512") + public static void runS512toD512() throws Throwable { + runRebracketHelper(SSPEC512, DSPEC512); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testI512toB512(int[] input, byte[] output) { + vectorRebracket(ISPEC512, BSPEC512, input, output); + } + + @Run(test = "testI512toB512") + public static void runI512toB512() throws Throwable { + runRebracketHelper(ISPEC512, BSPEC512); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testI512toS512(int[] input, short[] output) { + vectorRebracket(ISPEC512, SSPEC512, input, output); + } + + @Run(test = "testI512toS512") + public static void runI512toS512() throws Throwable { + runRebracketHelper(ISPEC512, SSPEC512); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testI512toL512(int[] input, long[] output) { + vectorRebracket(ISPEC512, LSPEC512, input, output); + } + + @Run(test = "testI512toL512") + public static void runI512toL512() throws Throwable { + runRebracketHelper(ISPEC512, LSPEC512); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testI512toF512(int[] input, float[] output) { + vectorRebracket(ISPEC512, FSPEC512, input, output); + } + + @Run(test = "testI512toF512") + public static void runI512toF512() throws Throwable { + runRebracketHelper(ISPEC512, FSPEC512); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testI512toD512(int[] input, double[] output) { + vectorRebracket(ISPEC512, DSPEC512, input, output); + } + + @Run(test = "testI512toD512") + public static void runI512toD512() throws Throwable { + runRebracketHelper(ISPEC512, DSPEC512); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testL512toB512(long[] input, byte[] output) { + vectorRebracket(LSPEC512, BSPEC512, input, output); + } + + @Run(test = "testL512toB512") + public static void runL512toB512() throws Throwable { + runRebracketHelper(LSPEC512, BSPEC512); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testL512toS512(long[] input, short[] output) { + vectorRebracket(LSPEC512, SSPEC512, input, output); + } + + @Run(test = "testL512toS512") + public static void runL512toS512() throws Throwable { + runRebracketHelper(LSPEC512, SSPEC512); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testL512toI512(long[] input, int[] output) { + vectorRebracket(LSPEC512, ISPEC512, input, output); + } + + @Run(test = "testL512toI512") + public static void runL512toI512() throws Throwable { + runRebracketHelper(LSPEC512, ISPEC512); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testL512toF512(long[] input, float[] output) { + vectorRebracket(LSPEC512, FSPEC512, input, output); + } + + @Run(test = "testL512toF512") + public static void runL512toF512() throws Throwable { + runRebracketHelper(LSPEC512, FSPEC512); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testL512toD512(long[] input, double[] output) { + vectorRebracket(LSPEC512, DSPEC512, input, output); + } + + @Run(test = "testL512toD512") + public static void runL512toD512() throws Throwable { + runRebracketHelper(LSPEC512, DSPEC512); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testF512toB512(float[] input, byte[] output) { + vectorRebracket(FSPEC512, BSPEC512, input, output); + } + + @Run(test = "testF512toB512") + public static void runF512toB512() throws Throwable { + runRebracketHelper(FSPEC512, BSPEC512); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testF512toS512(float[] input, short[] output) { + vectorRebracket(FSPEC512, SSPEC512, input, output); + } + + @Run(test = "testF512toS512") + public static void runF512toS512() throws Throwable { + runRebracketHelper(FSPEC512, SSPEC512); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testF512toI512(float[] input, int[] output) { + vectorRebracket(FSPEC512, ISPEC512, input, output); + } + + @Run(test = "testF512toI512") + public static void runF512toI512() throws Throwable { + runRebracketHelper(FSPEC512, ISPEC512); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testF512toL512(float[] input, long[] output) { + vectorRebracket(FSPEC512, LSPEC512, input, output); + } + + @Run(test = "testF512toL512") + public static void runF512toL512() throws Throwable { + runRebracketHelper(FSPEC512, LSPEC512); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testF512toD512(float[] input, double[] output) { + vectorRebracket(FSPEC512, DSPEC512, input, output); + } + + @Run(test = "testF512toD512") + public static void runF512toD512() throws Throwable { + runRebracketHelper(FSPEC512, DSPEC512); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testD512toB512(double[] input, byte[] output) { + vectorRebracket(DSPEC512, BSPEC512, input, output); + } + + @Run(test = "testD512toB512") + public static void runD512toB512() throws Throwable { + runRebracketHelper(DSPEC512, BSPEC512); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testD512toS512(double[] input, short[] output) { + vectorRebracket(DSPEC512, SSPEC512, input, output); + } + + @Run(test = "testD512toS512") + public static void runD512toS512() throws Throwable { + runRebracketHelper(DSPEC512, SSPEC512); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testD512toI512(double[] input, int[] output) { + vectorRebracket(DSPEC512, ISPEC512, input, output); + } + + @Run(test = "testD512toI512") + public static void runD512toI512() throws Throwable { + runRebracketHelper(DSPEC512, ISPEC512); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testD512toL512(double[] input, long[] output) { + vectorRebracket(DSPEC512, LSPEC512, input, output); + } + + @Run(test = "testD512toL512") + public static void runD512toL512() throws Throwable { + runRebracketHelper(DSPEC512, LSPEC512); + } + + @Test + @IR(counts = {REINTERPRET_NODE, "1"}) + public static void testD512toF512(double[] input, float[] output) { + vectorRebracket(DSPEC512, FSPEC512, input, output); + } + + @Run(test = "testD512toF512") + public static void runD512toF512() throws Throwable { + runRebracketHelper(DSPEC512, FSPEC512); + } +} diff --git a/test/hotspot/jtreg/compiler/vectorapi/reshape/utils/TestCastMethods.java b/test/hotspot/jtreg/compiler/vectorapi/reshape/utils/TestCastMethods.java new file mode 100644 index 0000000000000000000000000000000000000000..194295b2d2f5e8b3c32471b58bc98208404a9e59 --- /dev/null +++ b/test/hotspot/jtreg/compiler/vectorapi/reshape/utils/TestCastMethods.java @@ -0,0 +1,250 @@ +/* + * 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. + */ + +package compiler.vectorapi.reshape.utils; + +import java.util.List; +import java.util.stream.Stream; + +import static compiler.vectorapi.reshape.utils.VectorReshapeHelper.*; +import static compiler.vectorapi.reshape.utils.VectorSpeciesPair.makePair; + +/** + * The cast intrinsics implemented on each platform. + */ +public class TestCastMethods { + public static final List<VectorSpeciesPair> AVX1_CAST_TESTS = List.of( + makePair(BSPEC64, SSPEC64), + makePair(BSPEC64, SSPEC128), + makePair(BSPEC64, ISPEC128), + makePair(BSPEC64, FSPEC128), + makePair(BSPEC64, DSPEC256), + makePair(SSPEC64, BSPEC64), + makePair(SSPEC128, BSPEC64), + makePair(SSPEC64, ISPEC64), + makePair(SSPEC64, ISPEC128), + makePair(SSPEC64, LSPEC128), + makePair(SSPEC64, FSPEC64), + makePair(SSPEC64, FSPEC128), + makePair(SSPEC64, DSPEC128), + makePair(SSPEC64, DSPEC256), + makePair(ISPEC128, BSPEC64), + makePair(ISPEC64, SSPEC64), + makePair(ISPEC128, SSPEC64), + makePair(ISPEC64, LSPEC128), + makePair(ISPEC64, FSPEC64), + makePair(ISPEC128, FSPEC128), + makePair(ISPEC64, DSPEC128), + makePair(ISPEC128, DSPEC256), + makePair(LSPEC128, SSPEC64), + makePair(LSPEC128, ISPEC64), + makePair(FSPEC64, ISPEC64), + makePair(FSPEC128, ISPEC128), + makePair(FSPEC64, DSPEC128), + makePair(FSPEC128, DSPEC256), + makePair(DSPEC128, FSPEC64), + makePair(DSPEC256, FSPEC128), + makePair(BSPEC64, SSPEC64, true), + makePair(BSPEC64, SSPEC128, true), + makePair(BSPEC64, ISPEC128, true), + makePair(SSPEC64, ISPEC64, true), + makePair(SSPEC64, ISPEC128, true), + makePair(SSPEC64, LSPEC128, true), + makePair(ISPEC64, LSPEC128, true) + ); + + public static final List<VectorSpeciesPair> AVX2_CAST_TESTS = Stream.concat(AVX1_CAST_TESTS.stream(), Stream.of( + makePair(BSPEC128, SSPEC256), + makePair(BSPEC64, ISPEC256), + makePair(BSPEC64, LSPEC256), + makePair(BSPEC64, FSPEC256), + makePair(SSPEC256, BSPEC128), + makePair(SSPEC128, ISPEC256), + makePair(SSPEC64, LSPEC256), + makePair(SSPEC128, FSPEC256), + makePair(ISPEC256, BSPEC64), + makePair(ISPEC256, SSPEC128), + makePair(ISPEC128, LSPEC256), + makePair(ISPEC256, FSPEC256), + makePair(LSPEC256, BSPEC64), + makePair(LSPEC256, SSPEC64), + makePair(LSPEC256, ISPEC128), + makePair(FSPEC256, ISPEC256), + makePair(BSPEC128, SSPEC256, true), + makePair(BSPEC64, ISPEC256, true), + makePair(BSPEC64, LSPEC256, true), + makePair(SSPEC128, ISPEC256, true), + makePair(SSPEC64, LSPEC256, true), + makePair(ISPEC128, LSPEC256, true) + )).toList(); + + public static final List<VectorSpeciesPair> AVX512_CAST_TESTS = Stream.concat(AVX2_CAST_TESTS.stream(), Stream.of( + makePair(BSPEC128, ISPEC512), + makePair(BSPEC64, LSPEC512), + makePair(BSPEC128, FSPEC512), + makePair(BSPEC64, DSPEC512), + makePair(SSPEC256, ISPEC512), + makePair(SSPEC128, LSPEC512), + makePair(SSPEC256, FSPEC512), + makePair(SSPEC128, DSPEC512), + makePair(ISPEC512, BSPEC128), + makePair(ISPEC512, SSPEC256), + makePair(ISPEC256, LSPEC512), + makePair(ISPEC512, FSPEC512), + makePair(ISPEC256, DSPEC512), + makePair(LSPEC512, BSPEC64), + makePair(LSPEC512, SSPEC128), + makePair(LSPEC512, ISPEC256), + makePair(FSPEC512, ISPEC512), + makePair(FSPEC256, DSPEC512), + makePair(DSPEC512, FSPEC256), + makePair(BSPEC128, ISPEC512, true), + makePair(BSPEC64, LSPEC512, true), + makePair(SSPEC256, ISPEC512, true), + makePair(SSPEC128, LSPEC512, true), + makePair(ISPEC256, LSPEC512, true) + )).toList(); + + public static final List<VectorSpeciesPair> AVX512BW_CAST_TESTS = Stream.concat(AVX512_CAST_TESTS.stream(), Stream.of( + makePair(BSPEC256, SSPEC512), + makePair(SSPEC512, BSPEC256), + makePair(BSPEC256, SSPEC512, true) + )).toList(); + + public static final List<VectorSpeciesPair> AVX512DQ_CAST_TESTS = Stream.concat(AVX512_CAST_TESTS.stream(), Stream.of( + makePair(LSPEC128, DSPEC128), + makePair(LSPEC256, DSPEC256), + makePair(LSPEC512, DSPEC512), + makePair(DSPEC128, LSPEC128), + makePair(DSPEC256, LSPEC256), + makePair(DSPEC512, LSPEC512) + )).toList(); + + public static final List<VectorSpeciesPair> SVE_CAST_TESTS = List.of( + makePair(BSPEC64, SSPEC128), + makePair(BSPEC128, SSPEC256), + makePair(BSPEC256, SSPEC512), + makePair(BSPEC64, ISPEC256), + makePair(BSPEC128, ISPEC512), + makePair(BSPEC64, LSPEC512), + makePair(BSPEC64, FSPEC256), + makePair(BSPEC128, FSPEC512), + makePair(BSPEC64, DSPEC512), + makePair(SSPEC128, BSPEC64), + makePair(SSPEC256, BSPEC128), + makePair(SSPEC512, BSPEC256), + makePair(SSPEC64, ISPEC128), + makePair(SSPEC128, ISPEC256), + makePair(SSPEC256, ISPEC512), + makePair(SSPEC64, LSPEC256), + makePair(SSPEC128, LSPEC512), + makePair(SSPEC64, FSPEC128), + makePair(SSPEC128, FSPEC256), + makePair(SSPEC256, FSPEC512), + makePair(SSPEC64, DSPEC256), + makePair(SSPEC128, DSPEC512), + makePair(ISPEC256, BSPEC64), + makePair(ISPEC512, BSPEC128), + makePair(ISPEC128, SSPEC64), + makePair(ISPEC256, SSPEC128), + makePair(ISPEC512, SSPEC256), + makePair(ISPEC64, LSPEC128), + makePair(ISPEC128, LSPEC256), + makePair(ISPEC256, LSPEC512), + makePair(ISPEC64, FSPEC64), + makePair(ISPEC128, FSPEC128), + makePair(ISPEC256, FSPEC256), + makePair(ISPEC512, FSPEC512), + makePair(ISPEC64, DSPEC128), + makePair(ISPEC128, DSPEC256), + makePair(ISPEC256, DSPEC512), + makePair(LSPEC512, BSPEC64), + makePair(LSPEC256, SSPEC64), + makePair(LSPEC512, SSPEC128), + makePair(LSPEC128, ISPEC64), + makePair(LSPEC256, ISPEC128), + makePair(LSPEC512, ISPEC256), + makePair(LSPEC128, FSPEC64), + makePair(LSPEC256, FSPEC128), + makePair(LSPEC512, FSPEC256), + makePair(LSPEC128, DSPEC128), + makePair(LSPEC256, DSPEC256), + makePair(LSPEC512, DSPEC512), + makePair(FSPEC256, BSPEC64), + makePair(FSPEC512, BSPEC128), + makePair(FSPEC128, SSPEC64), + makePair(FSPEC256, SSPEC128), + makePair(FSPEC512, SSPEC256), + makePair(FSPEC64, ISPEC64), + makePair(FSPEC128, ISPEC128), + makePair(FSPEC256, ISPEC256), + makePair(FSPEC512, ISPEC512), + makePair(FSPEC64, LSPEC128), + makePair(FSPEC128, LSPEC256), + makePair(FSPEC256, LSPEC512), + makePair(FSPEC64, DSPEC128), + makePair(FSPEC128, DSPEC256), + makePair(FSPEC256, DSPEC512), + makePair(DSPEC512, BSPEC64), + makePair(DSPEC256, SSPEC64), + makePair(DSPEC512, SSPEC128), + makePair(DSPEC128, ISPEC64), + makePair(DSPEC256, ISPEC128), + makePair(DSPEC512, ISPEC256), + makePair(DSPEC128, LSPEC128), + makePair(DSPEC256, LSPEC256), + makePair(DSPEC512, LSPEC512), + makePair(DSPEC128, FSPEC64), + makePair(DSPEC256, FSPEC128), + makePair(DSPEC512, FSPEC256) + ); + + public static final List<VectorSpeciesPair> NEON_CAST_TESTS = List.of( + makePair(BSPEC64, SSPEC64), + makePair(BSPEC64, SSPEC128), + makePair(BSPEC64, ISPEC128), + makePair(BSPEC64, FSPEC128), + makePair(SSPEC64, BSPEC64), + makePair(SSPEC128, BSPEC64), + makePair(SSPEC64, ISPEC128), + makePair(SSPEC64, FSPEC128), + makePair(ISPEC128, BSPEC64), + makePair(ISPEC128, SSPEC64), + makePair(ISPEC64, LSPEC128), + makePair(ISPEC64, FSPEC64), + makePair(ISPEC128, FSPEC128), + makePair(ISPEC64, DSPEC128), + makePair(LSPEC128, ISPEC64), + makePair(LSPEC128, FSPEC64), + makePair(LSPEC128, DSPEC128), + makePair(FSPEC128, BSPEC64), + makePair(FSPEC128, SSPEC64), + makePair(FSPEC64, ISPEC64), + makePair(FSPEC128, ISPEC128), + makePair(FSPEC64, LSPEC128), + makePair(FSPEC64, DSPEC128), + makePair(DSPEC128, ISPEC64), + makePair(DSPEC128, LSPEC128), + makePair(DSPEC128, FSPEC64) + ); +} diff --git a/test/hotspot/jtreg/compiler/vectorapi/reshape/utils/UnsafeUtils.java b/test/hotspot/jtreg/compiler/vectorapi/reshape/utils/UnsafeUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..1f93ebe0c3dc198babef67fd5337a9d462e44794 --- /dev/null +++ b/test/hotspot/jtreg/compiler/vectorapi/reshape/utils/UnsafeUtils.java @@ -0,0 +1,87 @@ +/* + * 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. + */ + +package compiler.vectorapi.reshape.utils; + +import jdk.internal.misc.Unsafe; + +/** + * Unsafe to check for correctness of reinterpret operations. May be replaced with foreign API later. + */ +public class UnsafeUtils { + private static final Unsafe UNSAFE = Unsafe.getUnsafe(); + + public static long arrayBase(Class<?> etype) { + return UNSAFE.arrayBaseOffset(etype.arrayType()); + } + + public static byte getByte(Object o, long base, int i) { + // This technically leads to UB, what we need is UNSAFE.getByteUnaligned but they seem to be equivalent + return UNSAFE.getByte(o, base + (long)i * Unsafe.ARRAY_BYTE_INDEX_SCALE); + } + + public static void putByte(Object o, long base, int i, byte value) { + // This technically leads to UB, what we need is UNSAFE.putByteUnaligned but they seem to be equivalent + UNSAFE.putByte(o, base + (long)i * Unsafe.ARRAY_BYTE_INDEX_SCALE, value); + } + + public static short getShort(Object o, long base, int i) { + return UNSAFE.getShort(o, base + (long)i * Unsafe.ARRAY_SHORT_INDEX_SCALE); + } + + public static void putShort(Object o, long base, int i, short value) { + UNSAFE.putShort(o, base + (long)i * Unsafe.ARRAY_SHORT_INDEX_SCALE, value); + } + + public static int getInt(Object o, long base, int i) { + return UNSAFE.getInt(o, base + (long)i * Unsafe.ARRAY_INT_INDEX_SCALE); + } + + public static void putInt(Object o, long base, int i, int value) { + UNSAFE.putInt(o, base + (long)i * Unsafe.ARRAY_INT_INDEX_SCALE, value); + } + + public static long getLong(Object o, long base, int i) { + return UNSAFE.getLong(o, base + (long)i * Unsafe.ARRAY_LONG_INDEX_SCALE); + } + + public static void putLong(Object o, long base, int i, long value) { + UNSAFE.putLong(o, base + (long)i * Unsafe.ARRAY_LONG_INDEX_SCALE, value); + } + + public static float getFloat(Object o, long base, int i) { + return UNSAFE.getFloat(o, base + (long)i * Unsafe.ARRAY_FLOAT_INDEX_SCALE); + } + + public static void putFloat(Object o, long base, int i, float value) { + UNSAFE.putFloat(o, base + (long)i * Unsafe.ARRAY_FLOAT_INDEX_SCALE, value); + } + + public static double getDouble(Object o, long base, int i) { + return UNSAFE.getDouble(o, base + (long)i * Unsafe.ARRAY_DOUBLE_INDEX_SCALE); + } + + public static void putDouble(Object o, long base, int i, double value) { + UNSAFE.putDouble(o, base + (long)i * Unsafe.ARRAY_DOUBLE_INDEX_SCALE, value); + } +} diff --git a/test/hotspot/jtreg/compiler/vectorapi/reshape/utils/VectorReshapeHelper.java b/test/hotspot/jtreg/compiler/vectorapi/reshape/utils/VectorReshapeHelper.java new file mode 100644 index 0000000000000000000000000000000000000000..c769c14bde0b7a2fb508e09244a15490c026051e --- /dev/null +++ b/test/hotspot/jtreg/compiler/vectorapi/reshape/utils/VectorReshapeHelper.java @@ -0,0 +1,331 @@ +/* + * 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. + */ + +package compiler.vectorapi.reshape.utils; + +import compiler.lib.ir_framework.ForceInline; +import compiler.lib.ir_framework.IRNode; +import compiler.lib.ir_framework.TestFramework; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.lang.invoke.VarHandle; +import java.lang.reflect.Array; +import java.nio.ByteOrder; +import java.util.List; +import java.util.random.RandomGenerator; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import jdk.incubator.vector.*; +import jdk.test.lib.Asserts; + +public class VectorReshapeHelper { + public static final int INVOCATIONS = 10_000; + + public static final VectorSpecies<Byte> BSPEC64 = ByteVector.SPECIES_64; + public static final VectorSpecies<Short> SSPEC64 = ShortVector.SPECIES_64; + public static final VectorSpecies<Integer> ISPEC64 = IntVector.SPECIES_64; + public static final VectorSpecies<Long> LSPEC64 = LongVector.SPECIES_64; + public static final VectorSpecies<Float> FSPEC64 = FloatVector.SPECIES_64; + public static final VectorSpecies<Double> DSPEC64 = DoubleVector.SPECIES_64; + + public static final VectorSpecies<Byte> BSPEC128 = ByteVector.SPECIES_128; + public static final VectorSpecies<Short> SSPEC128 = ShortVector.SPECIES_128; + public static final VectorSpecies<Integer> ISPEC128 = IntVector.SPECIES_128; + public static final VectorSpecies<Long> LSPEC128 = LongVector.SPECIES_128; + public static final VectorSpecies<Float> FSPEC128 = FloatVector.SPECIES_128; + public static final VectorSpecies<Double> DSPEC128 = DoubleVector.SPECIES_128; + + public static final VectorSpecies<Byte> BSPEC256 = ByteVector.SPECIES_256; + public static final VectorSpecies<Short> SSPEC256 = ShortVector.SPECIES_256; + public static final VectorSpecies<Integer> ISPEC256 = IntVector.SPECIES_256; + public static final VectorSpecies<Long> LSPEC256 = LongVector.SPECIES_256; + public static final VectorSpecies<Float> FSPEC256 = FloatVector.SPECIES_256; + public static final VectorSpecies<Double> DSPEC256 = DoubleVector.SPECIES_256; + + public static final VectorSpecies<Byte> BSPEC512 = ByteVector.SPECIES_512; + public static final VectorSpecies<Short> SSPEC512 = ShortVector.SPECIES_512; + public static final VectorSpecies<Integer> ISPEC512 = IntVector.SPECIES_512; + public static final VectorSpecies<Long> LSPEC512 = LongVector.SPECIES_512; + public static final VectorSpecies<Float> FSPEC512 = FloatVector.SPECIES_512; + public static final VectorSpecies<Double> DSPEC512 = DoubleVector.SPECIES_512; + + public static final String B2X_NODE = IRNode.VECTOR_CAST_B2X; + public static final String S2X_NODE = IRNode.VECTOR_CAST_S2X; + public static final String I2X_NODE = IRNode.VECTOR_CAST_I2X; + public static final String L2X_NODE = IRNode.VECTOR_CAST_L2X; + public static final String F2X_NODE = IRNode.VECTOR_CAST_F2X; + public static final String D2X_NODE = IRNode.VECTOR_CAST_D2X; + public static final String UB2X_NODE = IRNode.VECTOR_UCAST_B2X; + public static final String US2X_NODE = IRNode.VECTOR_UCAST_S2X; + public static final String UI2X_NODE = IRNode.VECTOR_UCAST_I2X; + public static final String REINTERPRET_NODE = IRNode.VECTOR_REINTERPRET; + + public static void runMainHelper(Class<?> testClass, Stream<VectorSpeciesPair> testMethods, String... flags) { + var test = new TestFramework(testClass); + test.setDefaultWarmup(1); + test.addHelperClasses(VectorReshapeHelper.class); + test.addFlags("--add-modules=jdk.incubator.vector", "--add-exports=java.base/jdk.internal.misc=ALL-UNNAMED"); + test.addFlags(flags); + String testMethodNames = testMethods + .filter(p -> p.isp().length() <= VectorSpecies.ofLargestShape(p.isp().elementType()).length()) + .filter(p -> p.osp().length() <= VectorSpecies.ofLargestShape(p.osp().elementType()).length()) + .map(VectorSpeciesPair::format) + .collect(Collectors.joining(",")); + test.addFlags("-DTest=" + testMethodNames); + test.start(); + } + + @ForceInline + public static <T, U> void vectorCast(VectorOperators.Conversion<T, U> cop, + VectorSpecies<T> isp, VectorSpecies<U> osp, Object input, Object output) { + var outputVector = readVector(isp, input) + .convertShape(cop, osp, 0); + writeVector(osp, outputVector, output); + } + + public static <T, U> void runCastHelper(VectorOperators.Conversion<T, U> castOp, + VectorSpecies<T> isp, VectorSpecies<U> osp) throws Throwable { + var random = RandomGenerator.getDefault(); + boolean isUnsignedCast = castOp.name().startsWith("ZERO"); + String testMethodName = VectorSpeciesPair.makePair(isp, osp, isUnsignedCast).format(); + var caller = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE).getCallerClass(); + var testMethod = MethodHandles.lookup().findStatic(caller, + testMethodName, + MethodType.methodType(void.class, isp.elementType().arrayType(), osp.elementType().arrayType())) + .asType(MethodType.methodType(void.class, Object.class, Object.class)); + Object input = Array.newInstance(isp.elementType(), isp.length()); + Object output = Array.newInstance(osp.elementType(), osp.length()); + long ibase = UnsafeUtils.arrayBase(isp.elementType()); + long obase = UnsafeUtils.arrayBase(osp.elementType()); + for (int iter = 0; iter < INVOCATIONS; iter++) { + // We need to generate arrays with NaN or very large values occasionally + boolean normalArray = random.nextBoolean(); + var abnormalValue = List.of(Double.NaN, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, -1e30, 1e30); + for (int i = 0; i < isp.length(); i++) { + switch (isp.elementType().getName()) { + case "byte" -> UnsafeUtils.putByte(input, ibase, i, (byte)random.nextInt()); + case "short" -> UnsafeUtils.putShort(input, ibase, i, (short)random.nextInt()); + case "int" -> UnsafeUtils.putInt(input, ibase, i, random.nextInt()); + case "long" -> UnsafeUtils.putLong(input, ibase, i, random.nextLong()); + case "float" -> { + if (normalArray || random.nextBoolean()) { + UnsafeUtils.putFloat(input, ibase, i, random.nextFloat(Byte.MIN_VALUE, Byte.MAX_VALUE)); + } else { + UnsafeUtils.putFloat(input, ibase, i, abnormalValue.get(random.nextInt(abnormalValue.size())).floatValue()); + } + } + case "double" -> { + if (normalArray || random.nextBoolean()) { + UnsafeUtils.putDouble(input, ibase, i, random.nextDouble(Byte.MIN_VALUE, Byte.MAX_VALUE)); + } else { + UnsafeUtils.putDouble(input, ibase, i, abnormalValue.get(random.nextInt(abnormalValue.size()))); + } + } + default -> throw new AssertionError(); + } + } + + testMethod.invokeExact(input, output); + + for (int i = 0; i < osp.length(); i++) { + Number expected, actual; + if (i < isp.length()) { + Number initial = switch (isp.elementType().getName()) { + case "byte" -> UnsafeUtils.getByte(input, ibase, i); + case "short" -> UnsafeUtils.getShort(input, ibase, i); + case "int" -> UnsafeUtils.getInt(input, ibase, i); + case "long" -> UnsafeUtils.getLong(input, ibase, i); + case "float" -> UnsafeUtils.getFloat(input, ibase, i); + case "double" -> UnsafeUtils.getDouble(input, ibase, i); + default -> throw new AssertionError(); + }; + expected = switch (osp.elementType().getName()) { + case "byte" -> initial.byteValue(); + case "short" -> { + if (isUnsignedCast) { + yield (short) (initial.longValue() & ((1L << isp.elementSize()) - 1)); + } else { + yield initial.shortValue(); + } + } + case "int" -> { + if (isUnsignedCast) { + yield (int) (initial.longValue() & ((1L << isp.elementSize()) - 1)); + } else { + yield initial.intValue(); + } + } + case "long" -> { + if (isUnsignedCast) { + yield (long) (initial.longValue() & ((1L << isp.elementSize()) - 1)); + } else { + yield initial.longValue(); + } + } + case "float" -> initial.floatValue(); + case "double" -> initial.doubleValue(); + default -> throw new AssertionError(); + }; + } else { + expected = switch (osp.elementType().getName()) { + case "byte" -> (byte)0; + case "short" -> (short)0; + case "int" -> (int)0; + case "long" -> (long)0; + case "float" -> (float)0; + case "double" -> (double)0; + default -> throw new AssertionError(); + }; + } + actual = switch (osp.elementType().getName()) { + case "byte" -> UnsafeUtils.getByte(output, obase, i); + case "short" -> UnsafeUtils.getShort(output, obase, i); + case "int" -> UnsafeUtils.getInt(output, obase, i); + case "long" -> UnsafeUtils.getLong(output, obase, i); + case "float" -> UnsafeUtils.getFloat(output, obase, i); + case "double" -> UnsafeUtils.getDouble(output, obase, i); + default -> throw new AssertionError(); + }; + Asserts.assertEquals(expected, actual); + } + } + } + + @ForceInline + public static void vectorExpandShrink(VectorSpecies<Byte> isp, VectorSpecies<Byte> osp, byte[] input, byte[] output) { + isp.fromByteArray(input, 0, ByteOrder.nativeOrder()) + .reinterpretShape(osp, 0) + .intoByteArray(output, 0, ByteOrder.nativeOrder()); + } + + public static void runExpandShrinkHelper(VectorSpecies<Byte> isp, VectorSpecies<Byte> osp) throws Throwable { + var random = RandomGenerator.getDefault(); + String testMethodName = VectorSpeciesPair.makePair(isp, osp).format(); + var caller = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE).getCallerClass(); + var testMethod = MethodHandles.lookup().findStatic(caller, + testMethodName, + MethodType.methodType(void.class, byte.class.arrayType(), byte.class.arrayType())); + byte[] input = new byte[isp.vectorByteSize()]; + byte[] output = new byte[osp.vectorByteSize()]; + for (int iter = 0; iter < INVOCATIONS; iter++) { + random.nextBytes(input); + + testMethod.invokeExact(input, output); + + for (int i = 0; i < osp.vectorByteSize(); i++) { + int expected = i < isp.vectorByteSize() ? input[i] : 0; + int actual = output[i]; + Asserts.assertEquals(expected, actual); + } + } + } + + @ForceInline + public static void vectorDoubleExpandShrink(VectorSpecies<Byte> isp, VectorSpecies<Byte> osp, byte[] input, byte[] output) { + isp.fromByteArray(input, 0, ByteOrder.nativeOrder()) + .reinterpretShape(osp, 0) + .reinterpretShape(isp, 0) + .intoByteArray(output, 0, ByteOrder.nativeOrder()); + } + + public static void runDoubleExpandShrinkHelper(VectorSpecies<Byte> isp, VectorSpecies<Byte> osp) throws Throwable { + var random = RandomGenerator.getDefault(); + String testMethodName = VectorSpeciesPair.makePair(isp, osp).format(); + var caller = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE).getCallerClass(); + var testMethod = MethodHandles.lookup().findStatic(caller, + testMethodName, + MethodType.methodType(void.class, byte.class.arrayType(), byte.class.arrayType())); + byte[] input = new byte[isp.vectorByteSize()]; + byte[] output = new byte[isp.vectorByteSize()]; + for (int iter = 0; iter < INVOCATIONS; iter++) { + random.nextBytes(input); + + testMethod.invokeExact(input, output); + + for (int i = 0; i < isp.vectorByteSize(); i++) { + int expected = i < osp.vectorByteSize() ? input[i] : 0; + int actual = output[i]; + Asserts.assertEquals(expected, actual); + } + } + } + + @ForceInline + public static <T, U> void vectorRebracket(VectorSpecies<T> isp, VectorSpecies<U> osp, Object input, Object output) { + var outputVector = readVector(isp, input) + .reinterpretShape(osp, 0); + writeVector(osp, outputVector, output); + } + + public static <T, U> void runRebracketHelper(VectorSpecies<T> isp, VectorSpecies<U> osp) throws Throwable { + var random = RandomGenerator.getDefault(); + String testMethodName = VectorSpeciesPair.makePair(isp, osp).format(); + var caller = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE).getCallerClass(); + var testMethod = MethodHandles.lookup().findStatic(caller, + testMethodName, + MethodType.methodType(void.class, isp.elementType().arrayType(), osp.elementType().arrayType())) + .asType(MethodType.methodType(void.class, Object.class, Object.class)); + Object input = Array.newInstance(isp.elementType(), isp.length()); + Object output = Array.newInstance(osp.elementType(), osp.length()); + long ibase = UnsafeUtils.arrayBase(isp.elementType()); + long obase = UnsafeUtils.arrayBase(osp.elementType()); + for (int iter = 0; iter < INVOCATIONS; iter++) { + for (int i = 0; i < isp.vectorByteSize(); i++) { + UnsafeUtils.putByte(input, ibase, i, (byte)random.nextInt()); + } + + testMethod.invokeExact(input, output); + + for (int i = 0; i < osp.vectorByteSize(); i++) { + int expected = i < isp.vectorByteSize() ? UnsafeUtils.getByte(input, ibase, i) : 0; + int actual = UnsafeUtils.getByte(output, obase, i); + Asserts.assertEquals(expected, actual); + } + } + } + + @ForceInline + private static <T> Vector<T> readVector(VectorSpecies<T> isp, Object input) { + return isp.fromArray(input, 0); + } + + @ForceInline + private static <U> void writeVector(VectorSpecies<U> osp, Vector<U> vector, Object output) { + var otype = osp.elementType(); + if (otype == byte.class) { + ((ByteVector)vector).intoArray((byte[])output, 0); + } else if (otype == short.class) { + ((ShortVector)vector).intoArray((short[])output, 0); + } else if (otype == int.class) { + ((IntVector)vector).intoArray((int[])output, 0); + } else if (otype == long.class) { + ((LongVector)vector).intoArray((long[])output, 0); + } else if (otype == float.class) { + ((FloatVector)vector).intoArray((float[])output, 0); + } else if (otype == double.class) { + ((DoubleVector)vector).intoArray((double[])output, 0); + } else { + throw new AssertionError(); + } + } +} diff --git a/test/hotspot/jtreg/compiler/vectorapi/reshape/utils/VectorSpeciesPair.java b/test/hotspot/jtreg/compiler/vectorapi/reshape/utils/VectorSpeciesPair.java new file mode 100644 index 0000000000000000000000000000000000000000..74497f253abdc0bc84cb8518d20b9f78df6d7904 --- /dev/null +++ b/test/hotspot/jtreg/compiler/vectorapi/reshape/utils/VectorSpeciesPair.java @@ -0,0 +1,45 @@ +/* + * 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. + */ + +package compiler.vectorapi.reshape.utils; + +import jdk.incubator.vector.VectorSpecies; + +public record VectorSpeciesPair(VectorSpecies<?> isp, VectorSpecies<?> osp, boolean unsignedCast) { + public static VectorSpeciesPair makePair(VectorSpecies<?> isp, VectorSpecies<?> osp, boolean unsignedCast) { + return new VectorSpeciesPair(isp, osp, unsignedCast); + } + + public static VectorSpeciesPair makePair(VectorSpecies<?> isp, VectorSpecies<?> osp) { + return new VectorSpeciesPair(isp, osp, false); + } + + public String format() { + return String.format("test%s%c%dto%c%d", + unsignedCast() ? "U" : "", + Character.toUpperCase(isp().elementType().getName().charAt(0)), + isp().vectorBitSize(), + Character.toUpperCase(osp().elementType().getName().charAt(0)), + osp().vectorBitSize()); + } +} diff --git a/test/hotspot/jtreg/compiler/vectorization/TestPopCountVectorLong.java b/test/hotspot/jtreg/compiler/vectorization/TestPopCountVectorLong.java new file mode 100644 index 0000000000000000000000000000000000000000..49e3a428c303919355e95738d989c8e29c7de399 --- /dev/null +++ b/test/hotspot/jtreg/compiler/vectorization/TestPopCountVectorLong.java @@ -0,0 +1,77 @@ +/* + * 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. + */ + +/** +* @test +* @summary Test vectorization of popcount for Long +* @requires vm.compiler2.enabled +* @requires vm.cpu.features ~= ".*avx512bw.*" +* @requires os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64" +* @library /test/lib / +* @run driver compiler.vectorization.TestPopCountVectorLong +*/ + +package compiler.vectorization; +import compiler.lib.ir_framework.*; +import java.util.Random; + + +public class TestPopCountVectorLong { + private long[] input; + private int[] output; + private static final int LEN = 1024; + private Random rng; + + public static void main(String args[]) { + TestFramework.run(TestPopCountVectorLong.class); + } + + public TestPopCountVectorLong() { + input = new long[LEN]; + output = new int[LEN]; + rng = new Random(42); + for (int i = 0; i < LEN; ++i) { + input[i] = rng.nextLong(); + } + } + + @Test // needs to be run in (fast) debug mode + @Warmup(10000) + @IR(counts = {"PopCountVL", ">= 1"}) // Atleast one PopCountVL node is generated if vectorization is successful + public void vectorizeBitCount() { + for (int i = 0; i < LEN; ++i) { + output[i] = Long.bitCount(input[i]); + } + checkResult(); + } + + public void checkResult() { + for (int i = 0; i < LEN; ++i) { + int expected = Long.bitCount(input[i]); + if (output[i] != expected) { + throw new RuntimeException("Invalid result: output[" + i + "] = " + output[i] + " != " + expected); + } + } + } +} + diff --git a/test/hotspot/jtreg/containers/cgroup/PlainRead.java b/test/hotspot/jtreg/containers/cgroup/PlainRead.java index 3bd74d9437e26bc103579dc3f67b1f9b7cf98d09..d09383744090049da33810a43379235855b80e0e 100644 --- a/test/hotspot/jtreg/containers/cgroup/PlainRead.java +++ b/test/hotspot/jtreg/containers/cgroup/PlainRead.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -50,7 +50,7 @@ public class PlainRead { static final String good_value = "(\\d+|-1|-2|Unlimited)"; static final String bad_value = "(failed)"; - static final String[] variables = {"Memory Limit is:", "CPU Shares is:", "CPU Quota is:", "CPU Period is:", "active_processor_count:"}; + static final String[] variables = {"Memory Limit is:", "CPU Quota is:", "CPU Period is:", "active_processor_count:"}; static public void isContainer(OutputAnalyzer oa) { for (String v: variables) { diff --git a/test/hotspot/jtreg/containers/docker/TestCPUAwareness.java b/test/hotspot/jtreg/containers/docker/TestCPUAwareness.java index d8246bfc2c58ea36f5b69bbf453f542863a3f3c9..a72441182cd878923cbf2aa264ce1fc1c7dfd817 100644 --- a/test/hotspot/jtreg/containers/docker/TestCPUAwareness.java +++ b/test/hotspot/jtreg/containers/docker/TestCPUAwareness.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -100,6 +100,11 @@ public class TestCPUAwareness { String cpuSetStr = CPUSetsReader.readFromProcStatus("Cpus_allowed_list"); System.out.println("cpuSetStr = " + cpuSetStr); + // OLD = use the deprecated -XX:+UseContainerCpuShares flag, which + // will be removed in the next JDK release. See JDK-8281181. + boolean OLD = true; + boolean NEW = false; + if (cpuSetStr == null) { System.out.printf("The cpuset test cases are skipped"); } else { @@ -108,23 +113,32 @@ public class TestCPUAwareness { // Test subset of cpuset with one element if (cpuSet.size() >= 1) { String testCpuSet = CPUSetsReader.listToString(cpuSet, 1); - testAPCCombo(testCpuSet, 200*1000, 100*1000, 4*1024, true, 1); + testAPCCombo(OLD, testCpuSet, 200*1000, 100*1000, 4*1024, true, 1); + testAPCCombo(NEW, testCpuSet, 200*1000, 100*1000, 4*1024, true, 1); } // Test subset of cpuset with two elements if (cpuSet.size() >= 2) { String testCpuSet = CPUSetsReader.listToString(cpuSet, 2); - testAPCCombo(testCpuSet, 200*1000, 100*1000, 4*1024, true, 2); - testAPCCombo(testCpuSet, 200*1000, 100*1000, 1023, true, 2); - testAPCCombo(testCpuSet, 200*1000, 100*1000, 1023, false, 1); + testAPCCombo(OLD, testCpuSet, 200*1000, 100*1000, 4*1024, true, 2); + testAPCCombo(OLD, testCpuSet, 200*1000, 100*1000, 1023, true, 2); + testAPCCombo(OLD, testCpuSet, 200*1000, 100*1000, 1023, false,1); + + testAPCCombo(NEW, testCpuSet, 200*1000, 100*1000, 4*1024, true, 2); + testAPCCombo(NEW, testCpuSet, 200*1000, 100*1000, 1023, true, 2); + testAPCCombo(NEW, testCpuSet, 200*1000, 100*1000, 1023, false,2); } // Test subset of cpuset with three elements if (cpuSet.size() >= 3) { String testCpuSet = CPUSetsReader.listToString(cpuSet, 3); - testAPCCombo(testCpuSet, 100*1000, 100*1000, 2*1024, true, 1); - testAPCCombo(testCpuSet, 200*1000, 100*1000, 1023, true, 2); - testAPCCombo(testCpuSet, 200*1000, 100*1000, 1023, false, 1); + testAPCCombo(OLD, testCpuSet, 100*1000, 100*1000, 2*1024, true, 1); + testAPCCombo(OLD, testCpuSet, 200*1000, 100*1000, 1023, true, 2); + testAPCCombo(OLD, testCpuSet, 200*1000, 100*1000, 1023, false,1); + + testAPCCombo(NEW, testCpuSet, 100*1000, 100*1000, 2*1024, true, 1); + testAPCCombo(NEW, testCpuSet, 200*1000, 100*1000, 1023, true, 2); + testAPCCombo(NEW, testCpuSet, 200*1000, 100*1000, 1023, false,2); } } } @@ -181,8 +195,11 @@ public class TestCPUAwareness { } - // Test correctess of automatically selected active processor cound - private static void testAPCCombo(String cpuset, int quota, int period, int shares, + // Test correctess of automatically selected active processor count + // Note: when -XX:+UseContainerCpuShares is removed, + // useContainerCpuShares, shares, and usePreferContainerQuotaForCPUCount + // should also be removed. + private static void testAPCCombo(boolean useContainerCpuShares, String cpuset, int quota, int period, int shares, boolean usePreferContainerQuotaForCPUCount, int expectedAPC) throws Exception { Common.logNewTestCase("test APC Combo"); @@ -190,6 +207,7 @@ public class TestCPUAwareness { System.out.println("quota = " + quota); System.out.println("period = " + period); System.out.println("shares = " + shares); + System.out.println("useContainerCpuShares = " + useContainerCpuShares); System.out.println("usePreferContainerQuotaForCPUCount = " + usePreferContainerQuotaForCPUCount); System.out.println("expectedAPC = " + expectedAPC); @@ -201,13 +219,15 @@ public class TestCPUAwareness { .addDockerOpts("--cpu-quota=" + quota) .addDockerOpts("--cpu-shares=" + shares); - if (!usePreferContainerQuotaForCPUCount) opts.addJavaOpts("-XX:-PreferContainerQuotaForCPUCount"); + if (useContainerCpuShares) opts.addJavaOpts("-XX:+UseContainerCpuShares"); // deprecated + if (!usePreferContainerQuotaForCPUCount) opts.addJavaOpts("-XX:-PreferContainerQuotaForCPUCount"); // deprecated Common.run(opts) .shouldMatch("active_processor_count.*" + expectedAPC); } + // Note: when -XX:+UseContainerCpuShares is removed, this test should also be removed. private static void testCpuShares(int shares, int expectedAPC) throws Exception { Common.logNewTestCase("test cpu shares, shares = " + shares); System.out.println("expectedAPC = " + expectedAPC); @@ -216,6 +236,7 @@ public class TestCPUAwareness { DockerRunOptions opts = Common.newOpts(imageName) .addDockerOpts("--cpu-shares=" + shares); + opts.addJavaOpts("-XX:+UseContainerCpuShares"); // deprecated OutputAnalyzer out = Common.run(opts); // Cgroups v2 needs to do some scaling of raw shares values. Hence, // 256 CPU shares come back as 264. Raw value written to cpu.weight diff --git a/test/hotspot/jtreg/containers/docker/TestMisc.java b/test/hotspot/jtreg/containers/docker/TestMisc.java index e242bdf66321bd19fafeda53864686123ac36838..5625fe828bbb8db74c93ed882c8886b5054c0164 100644 --- a/test/hotspot/jtreg/containers/docker/TestMisc.java +++ b/test/hotspot/jtreg/containers/docker/TestMisc.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -56,6 +56,7 @@ public class TestMisc { testMinusContainerSupport(); testIsContainerized(); testPrintContainerInfo(); + testPrintContainerInfoActiveProcessorCount(); } finally { DockerTestUtils.removeDockerImage(imageName); } @@ -92,6 +93,15 @@ public class TestMisc { checkContainerInfo(Common.run(opts)); } + private static void testPrintContainerInfoActiveProcessorCount() throws Exception { + Common.logNewTestCase("Test print_container_info()"); + + DockerRunOptions opts = Common.newOpts(imageName, "PrintContainerInfo").addJavaOpts("-XX:ActiveProcessorCount=2"); + Common.addWhiteBoxOpts(opts); + + OutputAnalyzer out = Common.run(opts); + out.shouldContain("but overridden by -XX:ActiveProcessorCount 2"); + } private static void checkContainerInfo(OutputAnalyzer out) throws Exception { String[] expectedToContain = new String[] { diff --git a/test/hotspot/jtreg/gc/TestAllocateHeapAt.java b/test/hotspot/jtreg/gc/TestAllocateHeapAt.java index ed3ddc24a984a303479451c060a8daeae001da11..0c80e14635d3ef1cb51cd38a9a13cf4b0b834334 100644 --- a/test/hotspot/jtreg/gc/TestAllocateHeapAt.java +++ b/test/hotspot/jtreg/gc/TestAllocateHeapAt.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -31,11 +31,8 @@ package gc; * @run driver gc.TestAllocateHeapAt */ -import jdk.test.lib.JDKToolFinder; import jdk.test.lib.process.ProcessTools; import jdk.test.lib.process.OutputAnalyzer; -import java.util.ArrayList; -import java.util.Collections; public class TestAllocateHeapAt { public static void main(String args[]) throws Exception { diff --git a/test/hotspot/jtreg/gc/TestAllocateHeapAtMultiple.java b/test/hotspot/jtreg/gc/TestAllocateHeapAtMultiple.java index 5956889e4b6754e5f367fde4a5b78f7a2b07a01a..ddb2d9568e2065bc27894e9fbd7cbb07cc10c44d 100644 --- a/test/hotspot/jtreg/gc/TestAllocateHeapAtMultiple.java +++ b/test/hotspot/jtreg/gc/TestAllocateHeapAtMultiple.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -31,7 +31,6 @@ package gc; * @run driver/timeout=360 gc.TestAllocateHeapAtMultiple */ -import jdk.test.lib.JDKToolFinder; import jdk.test.lib.process.ProcessTools; import jdk.test.lib.process.OutputAnalyzer; import java.util.ArrayList; diff --git a/test/hotspot/jtreg/gc/TestCardTablePageCommits.java b/test/hotspot/jtreg/gc/TestCardTablePageCommits.java index 09678fdb586c53e7702ae7a1eefd0c43e8b584a1..ca14cfd71bec8c6311796a2596f5cf71be525892 100644 --- a/test/hotspot/jtreg/gc/TestCardTablePageCommits.java +++ b/test/hotspot/jtreg/gc/TestCardTablePageCommits.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -25,7 +25,6 @@ package gc; import jdk.test.lib.process.ProcessTools; import jdk.test.lib.process.OutputAnalyzer; -import jdk.test.lib.Platform; /* * @test TestCardTablePageCommits diff --git a/test/hotspot/jtreg/gc/TestSmallHeap.java b/test/hotspot/jtreg/gc/TestSmallHeap.java index a8fa9d61e9102bc671c13ada14b8cd17a2c1f0ce..99f75640e2d676f87620246c4eca3c3b21fa8ba4 100644 --- a/test/hotspot/jtreg/gc/TestSmallHeap.java +++ b/test/hotspot/jtreg/gc/TestSmallHeap.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -61,8 +61,6 @@ import jdk.test.lib.Asserts; import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.process.ProcessTools; -import java.util.LinkedList; - import jtreg.SkippedException; import sun.hotspot.WhiteBox; import sun.hotspot.gc.GC; diff --git a/test/hotspot/jtreg/gc/arguments/TestAggressiveHeap.java b/test/hotspot/jtreg/gc/arguments/TestAggressiveHeap.java index b929db3baa0bf1b3dfcc4952f6b9fccfef53bbd3..8eda52a20b3431272f14664b94d08d6c947df1b3 100644 --- a/test/hotspot/jtreg/gc/arguments/TestAggressiveHeap.java +++ b/test/hotspot/jtreg/gc/arguments/TestAggressiveHeap.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -39,7 +39,6 @@ import javax.management.MBeanServer; import javax.management.ObjectName; import jdk.test.lib.process.OutputAnalyzer; -import jdk.test.lib.process.ProcessTools; import jtreg.SkippedException; public class TestAggressiveHeap { diff --git a/test/hotspot/jtreg/gc/arguments/TestArrayAllocatorMallocLimit.java b/test/hotspot/jtreg/gc/arguments/TestArrayAllocatorMallocLimit.java index ca4d2d5d7ed51de85bbc668ff0b9a66a57fd7c07..163be84db03f45382b00544ea5184aa0d847225e 100644 --- a/test/hotspot/jtreg/gc/arguments/TestArrayAllocatorMallocLimit.java +++ b/test/hotspot/jtreg/gc/arguments/TestArrayAllocatorMallocLimit.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -37,7 +37,6 @@ package gc.arguments; import jdk.test.lib.Asserts; import jdk.test.lib.process.OutputAnalyzer; -import jdk.test.lib.process.ProcessTools; import java.math.BigInteger; public class TestArrayAllocatorMallocLimit { diff --git a/test/hotspot/jtreg/gc/arguments/TestCompressedClassFlags.java b/test/hotspot/jtreg/gc/arguments/TestCompressedClassFlags.java index 89708924f90885aaf058b9ece32474045bec1294..5e5bf97b7cff7068d600caf2895948feb9ea8eb5 100644 --- a/test/hotspot/jtreg/gc/arguments/TestCompressedClassFlags.java +++ b/test/hotspot/jtreg/gc/arguments/TestCompressedClassFlags.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -24,7 +24,6 @@ package gc.arguments; import jdk.test.lib.process.OutputAnalyzer; -import jdk.test.lib.process.ProcessTools; import jdk.test.lib.Platform; /* diff --git a/test/hotspot/jtreg/gc/arguments/TestG1ConcMarkStepDurationMillis.java b/test/hotspot/jtreg/gc/arguments/TestG1ConcMarkStepDurationMillis.java index b505cdbe3ba9efafd8c0d886839a445b00704ff2..d5a273b3d01630aa79085b8bdff4601004eea87f 100644 --- a/test/hotspot/jtreg/gc/arguments/TestG1ConcMarkStepDurationMillis.java +++ b/test/hotspot/jtreg/gc/arguments/TestG1ConcMarkStepDurationMillis.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -34,7 +34,6 @@ package gc.arguments; * @run driver gc.arguments.TestG1ConcMarkStepDurationMillis */ -import jdk.test.lib.process.ProcessTools; import jdk.test.lib.process.OutputAnalyzer; import java.util.*; import java.util.regex.*; diff --git a/test/hotspot/jtreg/gc/arguments/TestG1ConcRefinementThreads.java b/test/hotspot/jtreg/gc/arguments/TestG1ConcRefinementThreads.java index 55a1f188b6b3980ad1fc0122d3c3db99ad65acf3..750dfefd6c6e7a3f08e6b2676cdf91c8aec0ea99 100644 --- a/test/hotspot/jtreg/gc/arguments/TestG1ConcRefinementThreads.java +++ b/test/hotspot/jtreg/gc/arguments/TestG1ConcRefinementThreads.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -36,7 +36,6 @@ package gc.arguments; */ import jdk.test.lib.process.OutputAnalyzer; -import jdk.test.lib.process.ProcessTools; import java.util.*; import java.util.regex.*; diff --git a/test/hotspot/jtreg/gc/arguments/TestG1HeapRegionSize.java b/test/hotspot/jtreg/gc/arguments/TestG1HeapRegionSize.java index d571e2ae5b5ec8ac762bd4b9469aad3b39fc5244..e9132da19307921f38b7a18407f9ddb032faedb8 100644 --- a/test/hotspot/jtreg/gc/arguments/TestG1HeapRegionSize.java +++ b/test/hotspot/jtreg/gc/arguments/TestG1HeapRegionSize.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -43,7 +43,6 @@ import java.util.Arrays; import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.Platform; -import jdk.test.lib.process.ProcessTools; public class TestG1HeapRegionSize { diff --git a/test/hotspot/jtreg/gc/arguments/TestG1PercentageOptions.java b/test/hotspot/jtreg/gc/arguments/TestG1PercentageOptions.java index 651ace075201079c49f73e1403fbee5b1ca89594..873f22b874df48f71a4cb8e52b6159e68c7a48d9 100644 --- a/test/hotspot/jtreg/gc/arguments/TestG1PercentageOptions.java +++ b/test/hotspot/jtreg/gc/arguments/TestG1PercentageOptions.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -36,7 +36,6 @@ package gc.arguments; */ import jdk.test.lib.process.OutputAnalyzer; -import jdk.test.lib.process.ProcessTools; public class TestG1PercentageOptions { diff --git a/test/hotspot/jtreg/gc/arguments/TestG1RemSetFlags.java b/test/hotspot/jtreg/gc/arguments/TestG1RemSetFlags.java index 8f84319ba6468bfe18bf47041b497f3e95d39781..3f339d60162f5828fcd57b2119d21f13fb31a991 100644 --- a/test/hotspot/jtreg/gc/arguments/TestG1RemSetFlags.java +++ b/test/hotspot/jtreg/gc/arguments/TestG1RemSetFlags.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -34,14 +34,10 @@ package gc.arguments; * @run driver gc.arguments.TestG1RemSetFlags */ -import java.util.regex.Matcher; -import java.util.regex.Pattern; - import java.util.ArrayList; import java.util.Arrays; import jdk.test.lib.process.OutputAnalyzer; -import jdk.test.lib.process.ProcessTools; public class TestG1RemSetFlags { diff --git a/test/hotspot/jtreg/gc/arguments/TestHeapFreeRatio.java b/test/hotspot/jtreg/gc/arguments/TestHeapFreeRatio.java index 3247a7c5b3adee1954b90a9af5f4427b725b08b5..3842c55b6d30b6783251029f31a786fd05a69b6a 100644 --- a/test/hotspot/jtreg/gc/arguments/TestHeapFreeRatio.java +++ b/test/hotspot/jtreg/gc/arguments/TestHeapFreeRatio.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -35,7 +35,6 @@ package gc.arguments; */ import jdk.test.lib.process.OutputAnalyzer; -import jdk.test.lib.process.ProcessTools; public class TestHeapFreeRatio { diff --git a/test/hotspot/jtreg/gc/arguments/TestInitialTenuringThreshold.java b/test/hotspot/jtreg/gc/arguments/TestInitialTenuringThreshold.java index 4f8c88bc1b9ee4f39ffb64eec93d90db1a458dfb..784a69cd9ae16d203c1ea11199060927e803fe7f 100644 --- a/test/hotspot/jtreg/gc/arguments/TestInitialTenuringThreshold.java +++ b/test/hotspot/jtreg/gc/arguments/TestInitialTenuringThreshold.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -37,7 +37,6 @@ package gc.arguments; */ import jdk.test.lib.process.OutputAnalyzer; -import jdk.test.lib.process.ProcessTools; public class TestInitialTenuringThreshold { diff --git a/test/hotspot/jtreg/gc/arguments/TestMaxHeapSizeTools.java b/test/hotspot/jtreg/gc/arguments/TestMaxHeapSizeTools.java index ef4b963ed6993615b7b1270262545cea53d28737..3e05d27a8889db94c72f882aefb2c0bebb278d68 100644 --- a/test/hotspot/jtreg/gc/arguments/TestMaxHeapSizeTools.java +++ b/test/hotspot/jtreg/gc/arguments/TestMaxHeapSizeTools.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -28,7 +28,6 @@ import java.util.regex.Pattern; import java.util.ArrayList; import java.util.Arrays; -import jdk.test.lib.process.ProcessTools; import jdk.test.lib.process.OutputAnalyzer; import sun.hotspot.WhiteBox; diff --git a/test/hotspot/jtreg/gc/arguments/TestMaxMinHeapFreeRatioFlags.java b/test/hotspot/jtreg/gc/arguments/TestMaxMinHeapFreeRatioFlags.java index 591c0e4e3fce0f96d058416215d6b7cff1d509aa..3cf0034f1a767e4bb8999e811ee616346a7d2620 100644 --- a/test/hotspot/jtreg/gc/arguments/TestMaxMinHeapFreeRatioFlags.java +++ b/test/hotspot/jtreg/gc/arguments/TestMaxMinHeapFreeRatioFlags.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -38,7 +38,6 @@ import java.util.LinkedList; import java.util.Arrays; import java.util.Collections; import jdk.test.lib.process.OutputAnalyzer; -import jdk.test.lib.process.ProcessTools; import jdk.test.lib.Utils; import jdk.internal.misc.Unsafe; diff --git a/test/hotspot/jtreg/gc/arguments/TestMaxNewSize.java b/test/hotspot/jtreg/gc/arguments/TestMaxNewSize.java index 41ae94582347592e9c48e4b418de07302b9e89d8..03376308e3932e853d790c1e9154f1848d5c92fd 100644 --- a/test/hotspot/jtreg/gc/arguments/TestMaxNewSize.java +++ b/test/hotspot/jtreg/gc/arguments/TestMaxNewSize.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -74,7 +74,6 @@ import java.util.ArrayList; import java.util.Arrays; import jdk.test.lib.process.OutputAnalyzer; -import jdk.test.lib.process.ProcessTools; public class TestMaxNewSize { diff --git a/test/hotspot/jtreg/gc/arguments/TestMaxRAMFlags.java b/test/hotspot/jtreg/gc/arguments/TestMaxRAMFlags.java index 2acfc8d26a20dc5c12a98db9936ffc16b5993392..9e4ac2cc31d80d778c72afc5033fae24a23a4d90 100644 --- a/test/hotspot/jtreg/gc/arguments/TestMaxRAMFlags.java +++ b/test/hotspot/jtreg/gc/arguments/TestMaxRAMFlags.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -46,7 +46,6 @@ import java.util.ArrayList; import java.util.Arrays; import jdk.test.lib.process.OutputAnalyzer; -import jdk.test.lib.process.ProcessTools; public class TestMaxRAMFlags { diff --git a/test/hotspot/jtreg/gc/arguments/TestMinAndInitialSurvivorRatioFlags.java b/test/hotspot/jtreg/gc/arguments/TestMinAndInitialSurvivorRatioFlags.java index 6b7c340c227207d1fc7170cd19ab84321608f90c..adca8fd1aef843860090ceea82665d778b02c545 100644 --- a/test/hotspot/jtreg/gc/arguments/TestMinAndInitialSurvivorRatioFlags.java +++ b/test/hotspot/jtreg/gc/arguments/TestMinAndInitialSurvivorRatioFlags.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -40,7 +40,6 @@ import java.util.Arrays; import java.util.Collections; import java.util.LinkedList; import jdk.test.lib.process.OutputAnalyzer; -import jdk.test.lib.process.ProcessTools; import jdk.test.lib.Utils; import sun.hotspot.WhiteBox; diff --git a/test/hotspot/jtreg/gc/arguments/TestNewRatioFlag.java b/test/hotspot/jtreg/gc/arguments/TestNewRatioFlag.java index 36a69e4451a4310f6169e645134c0e0d74d4be48..35ae246d49173634e935e019e7df56096df09cfb 100644 --- a/test/hotspot/jtreg/gc/arguments/TestNewRatioFlag.java +++ b/test/hotspot/jtreg/gc/arguments/TestNewRatioFlag.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -40,7 +40,6 @@ package gc.arguments; import java.util.Arrays; import java.util.Collections; import java.util.LinkedList; -import jdk.test.lib.process.ProcessTools; import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.Utils; import sun.hotspot.WhiteBox; diff --git a/test/hotspot/jtreg/gc/arguments/TestNewSizeFlags.java b/test/hotspot/jtreg/gc/arguments/TestNewSizeFlags.java index 445af699934189f620fc94c858ff587c88534740..0e3840a89d905f349a42e7804072b01c1e82a509 100644 --- a/test/hotspot/jtreg/gc/arguments/TestNewSizeFlags.java +++ b/test/hotspot/jtreg/gc/arguments/TestNewSizeFlags.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -43,7 +43,6 @@ import java.util.Arrays; import java.util.Collections; import java.util.LinkedList; import jdk.test.lib.process.OutputAnalyzer; -import jdk.test.lib.process.ProcessTools; import jdk.test.lib.Utils; import sun.hotspot.WhiteBox; diff --git a/test/hotspot/jtreg/gc/arguments/TestNewSizeThreadIncrease.java b/test/hotspot/jtreg/gc/arguments/TestNewSizeThreadIncrease.java index 1f340de34d844b6b1e85b74ff09029f51d0aea5e..be69ff2c79b47e67b1648fb686343bb500b389df 100644 --- a/test/hotspot/jtreg/gc/arguments/TestNewSizeThreadIncrease.java +++ b/test/hotspot/jtreg/gc/arguments/TestNewSizeThreadIncrease.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -38,8 +38,6 @@ package gc.arguments; import jdk.test.lib.Platform; import jdk.test.lib.process.OutputAnalyzer; -import jdk.test.lib.process.ProcessTools; - // Range of NewSizeThreadIncrease is 0 ~ max_uintx. // Total of 5 threads will be created (1 GCTest thread and 4 TestThread). diff --git a/test/hotspot/jtreg/gc/arguments/TestObjectTenuringFlags.java b/test/hotspot/jtreg/gc/arguments/TestObjectTenuringFlags.java index 7baf3c85ee1aaf43750ee303d6e2a33c2c33825c..0a2c8c146da85e85c19461910ca736255d4c1ead 100644 --- a/test/hotspot/jtreg/gc/arguments/TestObjectTenuringFlags.java +++ b/test/hotspot/jtreg/gc/arguments/TestObjectTenuringFlags.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -37,7 +37,6 @@ package gc.arguments; */ import jdk.test.lib.process.OutputAnalyzer; -import jdk.test.lib.process.ProcessTools; import java.util.*; diff --git a/test/hotspot/jtreg/gc/arguments/TestParallelGCThreads.java b/test/hotspot/jtreg/gc/arguments/TestParallelGCThreads.java index c0de77475e89a524a3a404829b7d741ff5adc2c5..26ee75d467c44095038b3c1c69ad1244f035e94c 100644 --- a/test/hotspot/jtreg/gc/arguments/TestParallelGCThreads.java +++ b/test/hotspot/jtreg/gc/arguments/TestParallelGCThreads.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -40,7 +40,6 @@ import java.util.ArrayList; import java.util.List; import jdk.test.lib.Asserts; import jdk.test.lib.process.OutputAnalyzer; -import jdk.test.lib.process.ProcessTools; import jtreg.SkippedException; import sun.hotspot.gc.GC; @@ -116,15 +115,12 @@ public class TestParallelGCThreads { // 4294967295 == (unsigned int) -1 // So setting ParallelGCThreads=4294967295 should give back 4294967295 - // and setting ParallelGCThreads=4294967296 should give back 0. (SerialGC is ok with ParallelGCThreads=0) - for (long i = 4294967295L; i <= 4294967296L; i++) { - long count = getParallelGCThreadCount( - "-XX:+UseSerialGC", - "-XX:ParallelGCThreads=" + i, - "-XX:+PrintFlagsFinal", - "-version"); - Asserts.assertEQ(count, i % 4294967296L, "Specifying ParallelGCThreads=" + i + " does not set the thread count properly!"); - } + long count = getParallelGCThreadCount( + "-XX:+UseSerialGC", + "-XX:ParallelGCThreads=4294967295", + "-XX:+PrintFlagsFinal", + "-version"); + Asserts.assertEQ(count, 4294967295L, "Specifying ParallelGCThreads=4294967295 does not set the thread count properly!"); } public static long getParallelGCThreadCount(String... flags) throws Exception { diff --git a/test/hotspot/jtreg/gc/arguments/TestSelectDefaultGC.java b/test/hotspot/jtreg/gc/arguments/TestSelectDefaultGC.java index 0ec4718500e3acca74685fb719d7b85607f1e6b6..dfa3bbfb36443b903a25acd827e0dbd3701256f3 100644 --- a/test/hotspot/jtreg/gc/arguments/TestSelectDefaultGC.java +++ b/test/hotspot/jtreg/gc/arguments/TestSelectDefaultGC.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -36,7 +36,6 @@ package gc.arguments; */ import jdk.test.lib.process.OutputAnalyzer; -import jdk.test.lib.process.ProcessTools; public class TestSelectDefaultGC { public static void assertVMOption(OutputAnalyzer output, String option, boolean value) { diff --git a/test/hotspot/jtreg/gc/arguments/TestSmallInitialHeapWithLargePageAndNUMA.java b/test/hotspot/jtreg/gc/arguments/TestSmallInitialHeapWithLargePageAndNUMA.java index 30fb509db1e66b9e1ec96793d35879fb068603c7..24d28472bfbef4f414dcba828a5660372ad8f720 100644 --- a/test/hotspot/jtreg/gc/arguments/TestSmallInitialHeapWithLargePageAndNUMA.java +++ b/test/hotspot/jtreg/gc/arguments/TestSmallInitialHeapWithLargePageAndNUMA.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -38,7 +38,6 @@ package gc.arguments; * @run main/othervm -Xbootclasspath/a:. -XX:+UseHugeTLBFS -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI gc.arguments.TestSmallInitialHeapWithLargePageAndNUMA */ -import jdk.test.lib.process.ProcessTools; import jdk.test.lib.process.OutputAnalyzer; import sun.hotspot.WhiteBox; import jtreg.SkippedException; diff --git a/test/hotspot/jtreg/gc/arguments/TestSurvivorRatioFlag.java b/test/hotspot/jtreg/gc/arguments/TestSurvivorRatioFlag.java index 0512921d9cb0e8d3798ae705fd80c927ac470435..d99cf8b68049006a21b8b314a4651bc03ff397f9 100644 --- a/test/hotspot/jtreg/gc/arguments/TestSurvivorRatioFlag.java +++ b/test/hotspot/jtreg/gc/arguments/TestSurvivorRatioFlag.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -41,7 +41,6 @@ import java.util.Arrays; import java.util.Collections; import java.util.LinkedList; import jdk.test.lib.process.OutputAnalyzer; -import jdk.test.lib.process.ProcessTools; import jdk.test.lib.Utils; import sun.hotspot.WhiteBox; diff --git a/test/hotspot/jtreg/gc/arguments/TestUnrecognizedVMOptionsHandling.java b/test/hotspot/jtreg/gc/arguments/TestUnrecognizedVMOptionsHandling.java index cf8a0624849d05bd1df54c20f4fc20b7ab93f7a8..56bc49bd8f47ff8b48c28e06170106e328d23c3f 100644 --- a/test/hotspot/jtreg/gc/arguments/TestUnrecognizedVMOptionsHandling.java +++ b/test/hotspot/jtreg/gc/arguments/TestUnrecognizedVMOptionsHandling.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -35,7 +35,6 @@ package gc.arguments; */ import jdk.test.lib.process.OutputAnalyzer; -import jdk.test.lib.process.ProcessTools; public class TestUnrecognizedVMOptionsHandling { diff --git a/test/hotspot/jtreg/gc/arguments/TestUseCompressedOopsErgoTools.java b/test/hotspot/jtreg/gc/arguments/TestUseCompressedOopsErgoTools.java index 1040f23277e3c2058df07691cca7569dcfb8a9b2..236c95c3a80d09b5f206a9f71b03062172ef2cde 100644 --- a/test/hotspot/jtreg/gc/arguments/TestUseCompressedOopsErgoTools.java +++ b/test/hotspot/jtreg/gc/arguments/TestUseCompressedOopsErgoTools.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -32,7 +32,6 @@ import java.util.ArrayList; import java.util.Arrays; import jdk.test.lib.Asserts; -import jdk.test.lib.process.ProcessTools; import jdk.test.lib.process.OutputAnalyzer; import java.lang.management.ManagementFactory; import sun.hotspot.WhiteBox; diff --git a/test/hotspot/jtreg/gc/arguments/TestUseNUMAInterleaving.java b/test/hotspot/jtreg/gc/arguments/TestUseNUMAInterleaving.java index 9a88db28bc56f716715e3e6b699267b13f385b52..7f3857594b6dcf14c7309dc328a79f50c1d9f224 100644 --- a/test/hotspot/jtreg/gc/arguments/TestUseNUMAInterleaving.java +++ b/test/hotspot/jtreg/gc/arguments/TestUseNUMAInterleaving.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -35,7 +35,6 @@ package gc.arguments; * @run driver gc.arguments.TestUseNUMAInterleaving */ import jdk.test.lib.process.OutputAnalyzer; -import jdk.test.lib.process.ProcessTools; public class TestUseNUMAInterleaving { diff --git a/test/hotspot/jtreg/gc/arguments/TestVerifyBeforeAndAfterGCFlags.java b/test/hotspot/jtreg/gc/arguments/TestVerifyBeforeAndAfterGCFlags.java index 53aab7108bbbfd0552d5f53305daa365d8559574..94b9f2788214ed99adfdfd67aa42c392b92f59fd 100644 --- a/test/hotspot/jtreg/gc/arguments/TestVerifyBeforeAndAfterGCFlags.java +++ b/test/hotspot/jtreg/gc/arguments/TestVerifyBeforeAndAfterGCFlags.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -44,8 +44,6 @@ import java.util.Collections; import jdk.test.lib.Utils; import jdk.test.lib.process.OutputAnalyzer; -import jdk.test.lib.process.ProcessTools; - import sun.hotspot.WhiteBox; public class TestVerifyBeforeAndAfterGCFlags { diff --git a/test/hotspot/jtreg/gc/epsilon/TestClasses.java b/test/hotspot/jtreg/gc/epsilon/TestClasses.java index aa081eeaf65883f0f2849f7eb36d3c982f6cf693..53e1bab3f6f415da0f82f99cd5cc8e907e9ae361 100644 --- a/test/hotspot/jtreg/gc/epsilon/TestClasses.java +++ b/test/hotspot/jtreg/gc/epsilon/TestClasses.java @@ -40,11 +40,6 @@ package gc.epsilon; import jdk.internal.org.objectweb.asm.ClassWriter; import jdk.internal.org.objectweb.asm.Opcodes; -import java.util.*; -import java.io.*; -import java.nio.*; -import java.nio.file.*; - public class TestClasses { static final int CLASSES = 1024; diff --git a/test/hotspot/jtreg/gc/epsilon/TestMemoryMXBeans.java b/test/hotspot/jtreg/gc/epsilon/TestMemoryMXBeans.java index a9ff8d00ba09139d50ee3a502640f24d5efa3df1..1cb358e60dd896e9449261854318dc95ef0700d6 100644 --- a/test/hotspot/jtreg/gc/epsilon/TestMemoryMXBeans.java +++ b/test/hotspot/jtreg/gc/epsilon/TestMemoryMXBeans.java @@ -36,7 +36,7 @@ package gc.epsilon; * gc.epsilon.TestMemoryMXBeans * -1 256 * - * @run main/othervm -Xmx256m -Xmx256m + * @run main/othervm -Xms256m -Xmx256m * -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC * gc.epsilon.TestMemoryMXBeans * 256 256 diff --git a/test/hotspot/jtreg/gc/g1/TestEvacuationFailure.java b/test/hotspot/jtreg/gc/g1/TestEvacuationFailure.java index 82e5fbd5ef66b743ea5d0d93aa5d4a6b123c51ea..040730ac5d047961b330c8ea807fe9cb9b7cdde4 100644 --- a/test/hotspot/jtreg/gc/g1/TestEvacuationFailure.java +++ b/test/hotspot/jtreg/gc/g1/TestEvacuationFailure.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -38,7 +38,6 @@ package gc.g1; */ import jdk.test.lib.process.OutputAnalyzer; -import jdk.test.lib.Platform; import jdk.test.lib.process.ProcessTools; public class TestEvacuationFailure { diff --git a/test/hotspot/jtreg/gc/g1/TestG1SkipCompaction.java b/test/hotspot/jtreg/gc/g1/TestG1SkipCompaction.java index f5fadcbb8800f5bb420f76f64a3a00cab4a918d7..9824186c43c2179878aab2f174d553b4380100c8 100644 --- a/test/hotspot/jtreg/gc/g1/TestG1SkipCompaction.java +++ b/test/hotspot/jtreg/gc/g1/TestG1SkipCompaction.java @@ -21,6 +21,8 @@ * questions. */ +package gc.g1; + /* * @test TestG1SkipCompaction * @summary Test for JDK-8262068 Improve G1 Full GC by skipping compaction @@ -29,7 +31,7 @@ * @library /test/lib * @modules java.base/jdk.internal.misc * java.management - * @run main/othervm -Xms256m -Xmx256m TestG1SkipCompaction + * @run main/othervm -Xms256m -Xmx256m gc.g1.TestG1SkipCompaction */ import java.util.regex.Matcher; import java.util.regex.Pattern; diff --git a/test/hotspot/jtreg/gc/g1/TestGCLogMessages.java b/test/hotspot/jtreg/gc/g1/TestGCLogMessages.java index a9f347dbb073f0cd052002fae39615a12a26b982..3117b7a3077e8949f42758ccff503e82474a732f 100644 --- a/test/hotspot/jtreg/gc/g1/TestGCLogMessages.java +++ b/test/hotspot/jtreg/gc/g1/TestGCLogMessages.java @@ -142,6 +142,7 @@ public class TestGCLogMessages { new LogMessageWithLevel("Scanned Cards", Level.DEBUG), new LogMessageWithLevel("Scanned Blocks", Level.DEBUG), new LogMessageWithLevel("Claimed Chunks", Level.DEBUG), + new LogMessageWithLevel("Found Roots", Level.DEBUG), // Code Roots Scan new LogMessageWithLevel("Code Root Scan", Level.DEBUG), // Object Copy @@ -264,7 +265,8 @@ public class TestGCLogMessages { LogMessageWithLevel exhFailureMessages[] = new LogMessageWithLevel[] { new LogMessageWithLevel("Recalculate Used Memory", Level.DEBUG), new LogMessageWithLevel("Restore Preserved Marks", Level.DEBUG), - new LogMessageWithLevel("Remove Self Forwards", Level.DEBUG), + new LogMessageWithLevel("Restore Retained Regions", Level.DEBUG), + new LogMessageWithLevel("Evacuation Failure Regions", Level.DEBUG), }; private void testWithEvacuationFailureLogs() throws Exception { diff --git a/test/hotspot/jtreg/gc/g1/TestShrinkAuxiliaryData.java b/test/hotspot/jtreg/gc/g1/TestShrinkAuxiliaryData.java index 6c7b541741dcfb960ed5e5e3f43fd4c973dc5403..9950154aba37e4f2699e9e6ea4e90d157e1653cd 100644 --- a/test/hotspot/jtreg/gc/g1/TestShrinkAuxiliaryData.java +++ b/test/hotspot/jtreg/gc/g1/TestShrinkAuxiliaryData.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -30,7 +30,6 @@ import jdk.test.lib.process.ProcessTools; import jdk.test.lib.process.OutputAnalyzer; import jtreg.SkippedException; -import java.io.IOException; import java.lang.management.ManagementFactory; import java.lang.management.MemoryUsage; import java.text.DecimalFormat; diff --git a/test/hotspot/jtreg/gc/g1/TestShrinkAuxiliaryData30.java b/test/hotspot/jtreg/gc/g1/TestShrinkAuxiliaryData27.java similarity index 86% rename from test/hotspot/jtreg/gc/g1/TestShrinkAuxiliaryData30.java rename to test/hotspot/jtreg/gc/g1/TestShrinkAuxiliaryData27.java index 960fce63afa849a2d370eff6b763dffaab18848b..7324cad9f3c13b6b929bac60d02878c3893a1a92 100644 --- a/test/hotspot/jtreg/gc/g1/TestShrinkAuxiliaryData30.java +++ b/test/hotspot/jtreg/gc/g1/TestShrinkAuxiliaryData27.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -24,7 +24,7 @@ package gc.g1; /** - * @test TestShrinkAuxiliaryData30 + * @test TestShrinkAuxiliaryData27 * @key randomness * @bug 8038423 8061715 8078405 * @summary Checks that decommitment occurs for JVM with different @@ -36,11 +36,11 @@ package gc.g1; * java.management * @build sun.hotspot.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller sun.hotspot.WhiteBox - * @run main/timeout=720 gc.g1.TestShrinkAuxiliaryData30 + * @run main/timeout=720 gc.g1.TestShrinkAuxiliaryData27 */ -public class TestShrinkAuxiliaryData30 { +public class TestShrinkAuxiliaryData27 { public static void main(String[] args) throws Exception { - new TestShrinkAuxiliaryData(30).test(); + new TestShrinkAuxiliaryData(27).test(); } } diff --git a/test/hotspot/jtreg/gc/g1/TestSkipRebuildRemsetPhase.java b/test/hotspot/jtreg/gc/g1/TestSkipRebuildRemsetPhase.java index 60140ee0d3855ae864dbbfc3aa9f22273fac71e5..d679fe1f827f55e1a849e960d527b96d81c44266 100644 --- a/test/hotspot/jtreg/gc/g1/TestSkipRebuildRemsetPhase.java +++ b/test/hotspot/jtreg/gc/g1/TestSkipRebuildRemsetPhase.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -34,12 +34,8 @@ package gc.g1; * @run driver gc.g1.TestSkipRebuildRemsetPhase */ -import java.util.regex.Pattern; -import java.util.regex.Matcher; - import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.process.ProcessTools; -import jdk.test.lib.Asserts; import sun.hotspot.WhiteBox; public class TestSkipRebuildRemsetPhase { diff --git a/test/hotspot/jtreg/gc/g1/numa/TestG1NUMATouchRegions.java b/test/hotspot/jtreg/gc/g1/numa/TestG1NUMATouchRegions.java index 6cdbd2c797a7ec9815d52395719b84407a78875b..868e5b185f299576900e94e7436be0040ae0f480 100644 --- a/test/hotspot/jtreg/gc/g1/numa/TestG1NUMATouchRegions.java +++ b/test/hotspot/jtreg/gc/g1/numa/TestG1NUMATouchRegions.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -21,7 +21,7 @@ * questions. */ -package gc.g1; +package gc.g1.numa; /** * @test TestG1NUMATouchRegions @@ -33,7 +33,9 @@ package gc.g1; * java.management * @build sun.hotspot.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller sun.hotspot.WhiteBox - * @run main/othervm -XX:+UseG1GC -Xbootclasspath/a:. -XX:+UseNUMA -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI gc.g1.TestG1NUMATouchRegions + * @run main/othervm -XX:+UseG1GC -Xbootclasspath/a:. -XX:+UseNUMA + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * gc.g1.numa.TestG1NUMATouchRegions */ import java.util.LinkedList; diff --git a/test/hotspot/jtreg/gc/logging/TestPrintReferences.java b/test/hotspot/jtreg/gc/logging/TestPrintReferences.java index c3bf80a48a03c693b3dd9b1d7205c3f92d6adfce..6272f08e9943b86895e5fa044767f5930dcde38a 100644 --- a/test/hotspot/jtreg/gc/logging/TestPrintReferences.java +++ b/test/hotspot/jtreg/gc/logging/TestPrintReferences.java @@ -80,9 +80,11 @@ public class TestPrintReferences { private static String refRegex(String reftype) { String countRegex = "[0-9]+"; - return gcLogTimeRegex + indent(6) + reftype + ":\n" + - gcLogTimeRegex + indent(8) + "Discovered: " + countRegex + "\n" + - gcLogTimeRegex + indent(8) + "Cleared: " + countRegex + "\n"; + return gcLogTimeRegex + indent(6) + reftype + " " + + "Discovered: " + countRegex + ", " + + "Dropped: " + countRegex + ", " + + "Processed: " + countRegex + "\n" + ; } private static void checkRefsLogFormat(OutputAnalyzer output) { diff --git a/test/hotspot/jtreg/gc/shenandoah/compiler/TestBarrierAboveProj.java b/test/hotspot/jtreg/gc/shenandoah/compiler/TestBarrierAboveProj.java new file mode 100644 index 0000000000000000000000000000000000000000..560b6f34617056ea38a8f16bf5ad468a52e71b73 --- /dev/null +++ b/test/hotspot/jtreg/gc/shenandoah/compiler/TestBarrierAboveProj.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 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. + */ + +/* + * @test + * bug 8281811 + * @summary assert(_base == Tuple) failed: Not a Tuple after JDK-8280799 + * @requires vm.gc.Shenandoah + * @run main/othervm -XX:+UseShenandoahGC -XX:-BackgroundCompilation -XX:LoopMaxUnroll=1 TestBarrierAboveProj + */ + + +public class TestBarrierAboveProj { + private static C objField = new C(); + private static final Object[] arrayField = new Object[1000]; + private static volatile int volatileField; + + public static void main(String[] args) { + for (int i = 0; i < 20_000; i++) { + test1(); + test2(); + } + } + + private static float test1() { + float v = 1; + for (int i = 1; i < 1000; i++) { + if (objField == arrayField[i]) { + return v; + } + v *= 2; + } + return v; + } + + private static float test2() { + float v = 1; + volatileField = 0x42; + for (int i = 1; i < 1000; i++) { + if (objField == arrayField[i]) { + return v; + } + v *= 2; + } + return v; + } + + private static class C { + public float floatField; + } +} diff --git a/test/hotspot/jtreg/gc/shenandoah/compiler/TestLinkToNativeRBP.java b/test/hotspot/jtreg/gc/shenandoah/compiler/TestLinkToNativeRBP.java index 4d5203167d3df56ce847265ba3078fad93f5a840..a5ebe6f5de8a188238ebda319278aa0369bd557c 100644 --- a/test/hotspot/jtreg/gc/shenandoah/compiler/TestLinkToNativeRBP.java +++ b/test/hotspot/jtreg/gc/shenandoah/compiler/TestLinkToNativeRBP.java @@ -40,22 +40,19 @@ import jdk.incubator.foreign.CLinker; import jdk.incubator.foreign.FunctionDescriptor; import jdk.incubator.foreign.SymbolLookup; +import jdk.incubator.foreign.ValueLayout; import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodType; - -import static jdk.incubator.foreign.CLinker.C_INT; public class TestLinkToNativeRBP { static { System.loadLibrary("LinkToNativeRBP"); } - final static CLinker abi = CLinker.getInstance(); + final static CLinker abi = CLinker.systemCLinker(); static final SymbolLookup lookup = SymbolLookup.loaderLookup(); final static MethodHandle foo = abi.downcallHandle(lookup.lookup("foo").get(), - MethodType.methodType(int.class), - FunctionDescriptor.of(C_INT)); + FunctionDescriptor.of(ValueLayout.JAVA_INT)); static int foo() throws Throwable { return (int)foo.invokeExact(); diff --git a/test/hotspot/jtreg/gc/shenandoah/compiler/TestUnexpectedIUBarrierEA.java b/test/hotspot/jtreg/gc/shenandoah/compiler/TestUnexpectedIUBarrierEA.java new file mode 100644 index 0000000000000000000000000000000000000000..8662130c378770a5c179cdae52d83e4138d54be6 --- /dev/null +++ b/test/hotspot/jtreg/gc/shenandoah/compiler/TestUnexpectedIUBarrierEA.java @@ -0,0 +1,74 @@ +/* + * Copyright (c) 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. + */ + +/* + * @test + * bug 8280885 + * @summary Shenandoah: Some tests failed with "EA: missing allocation reference path" + * @requires vm.gc.Shenandoah + * + * @run main/othervm -XX:-BackgroundCompilation -XX:+UseShenandoahGC -XX:+UnlockExperimentalVMOptions -XX:ShenandoahGCMode=iu + * -XX:CompileCommand=dontinline,TestUnexpectedIUBarrierEA::notInlined TestUnexpectedIUBarrierEA + */ + +public class TestUnexpectedIUBarrierEA { + + private static Object field; + + public static void main(String[] args) { + for (int i = 0; i < 20_000; i++) { + test(false); + } + } + + private static void test(boolean flag) { + A a = new A(); + B b = new B(); + b.field = a; + notInlined(); + Object o = b.field; + if (!(o instanceof A)) { + + } + C c = new C(); + c.field = o; + if (flag) { + field = c.field; + } + } + + private static void notInlined() { + + } + + private static class A { + } + + private static class B { + public Object field; + } + + private static class C { + public Object field; + } +} diff --git a/test/hotspot/jtreg/gc/stress/gclocker/TestExcessGCLockerCollections.java b/test/hotspot/jtreg/gc/stress/gclocker/TestExcessGCLockerCollections.java index 6bbcc6bb9d9eae381156eb73feb20d038b0e0224..8b6326b1cae654aefba8bdd9f931348d982295e0 100644 --- a/test/hotspot/jtreg/gc/stress/gclocker/TestExcessGCLockerCollections.java +++ b/test/hotspot/jtreg/gc/stress/gclocker/TestExcessGCLockerCollections.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -44,7 +44,6 @@ import java.util.zip.Deflater; import java.util.ArrayList; import java.util.Arrays; -import jdk.test.lib.Asserts; import jdk.test.lib.process.ProcessTools; import jdk.test.lib.process.OutputAnalyzer; diff --git a/test/hotspot/jtreg/gc/stress/gclocker/TestGCLockerWithSerial.java b/test/hotspot/jtreg/gc/stress/gclocker/TestGCLockerWithSerial.java index e81a762212bc8af07a70de980c3f300cde326bb4..9de8fa88ca70868098c7aba02f5dd6177229c827 100644 --- a/test/hotspot/jtreg/gc/stress/gclocker/TestGCLockerWithSerial.java +++ b/test/hotspot/jtreg/gc/stress/gclocker/TestGCLockerWithSerial.java @@ -30,7 +30,7 @@ package gc.stress.gclocker; * @requires vm.gc.Serial * @requires vm.flavor != "minimal" * @summary Stress Serial's GC locker by calling GetPrimitiveArrayCritical while concurrently filling up old gen. - * @run main/native/othervm/timeout=200 -Xlog:gc*=info -Xmx1500m -Xmx1500m -XX:+UseSerialGC gc.stress.gclocker.TestGCLockerWithSerial + * @run main/native/othervm/timeout=200 -Xlog:gc*=info -Xms1500m -Xmx1500m -XX:+UseSerialGC gc.stress.gclocker.TestGCLockerWithSerial */ public class TestGCLockerWithSerial { public static void main(String[] args) { diff --git a/test/hotspot/jtreg/gc/z/TestGarbageCollectorMXBean.java b/test/hotspot/jtreg/gc/z/TestGarbageCollectorMXBean.java index e29d75b009c6eb7a8fdc65c5c62ded1e49bcb497..7a011edd8c9b6d77dbcaf77f8123f2ef5cb9cd68 100644 --- a/test/hotspot/jtreg/gc/z/TestGarbageCollectorMXBean.java +++ b/test/hotspot/jtreg/gc/z/TestGarbageCollectorMXBean.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -21,13 +21,15 @@ * questions. */ +package gc.z; + /** * @test TestGarbageCollectorMXBean * @requires vm.gc.Z * @summary Test ZGC garbage collector MXBean * @modules java.management - * @run main/othervm -XX:+UseZGC -Xms256M -Xmx512M -Xlog:gc TestGarbageCollectorMXBean 256 512 - * @run main/othervm -XX:+UseZGC -Xms512M -Xmx512M -Xlog:gc 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 47545d1bcf5ccbbc15a609b7734afe3d85bb1036..18c1898575926c5d32d7c6a6d199e9b15ef4f5a9 100644 --- a/test/hotspot/jtreg/gc/z/TestMemoryMXBean.java +++ b/test/hotspot/jtreg/gc/z/TestMemoryMXBean.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -21,13 +21,15 @@ * questions. */ +package gc.z; + /** * @test TestMemoryMXBean * @requires vm.gc.Z * @summary Test ZGC heap memory MXBean * @modules java.management - * @run main/othervm -XX:+UseZGC -Xms128M -Xmx256M -Xlog:gc* TestMemoryMXBean 128 256 - * @run main/othervm -XX:+UseZGC -Xms256M -Xmx256M -Xlog:gc* 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 a5c5c1367e7609a23f95bd70013ff412ba226d62..803201d576e538ed769e30d7b12b81be897788dc 100644 --- a/test/hotspot/jtreg/gc/z/TestMemoryManagerMXBean.java +++ b/test/hotspot/jtreg/gc/z/TestMemoryManagerMXBean.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -21,12 +21,14 @@ * questions. */ +package gc.z; + /** * @test TestMemoryManagerMXBean * @requires vm.gc.Z * @summary Test ZGC memory manager MXBean * @modules java.management - * @run main/othervm -XX:+UseZGC -Xmx128M TestMemoryManagerMXBean + * @run main/othervm -XX:+UseZGC -Xmx128M gc.z.TestMemoryManagerMXBean */ import java.lang.management.ManagementFactory; diff --git a/test/hotspot/jtreg/gtest/NMTGtests.java b/test/hotspot/jtreg/gtest/NMTGtests.java index b79f46395fbecc53a450ac57d5db13ff559cde07..57666680b6ba54a66bf29af2813f2586df2503bb 100644 --- a/test/hotspot/jtreg/gtest/NMTGtests.java +++ b/test/hotspot/jtreg/gtest/NMTGtests.java @@ -24,10 +24,15 @@ */ /* - * This tests NMT by running gtests with NMT enabled. - * - * To save time, we just run them for debug builds (where we would catch assertions) and only a selection of tests - * (namely, NMT tests themselves, and - for the detail statistics - os tests, since those reserve a lot and stress NMT) + * This tests NMT by running gtests with NMT enabled (only those which are relevant for NMT) + */ + +/* @test id=nmt-off + * @summary Run NMT-related gtests with NMT switched off + * @library /test/lib + * @modules java.base/jdk.internal.misc + * java.xml + * @run main/native GTestWrapper --gtest_filter=NMT*:os* -XX:NativeMemoryTracking=off */ /* @test id=nmt-summary @@ -35,8 +40,7 @@ * @library /test/lib * @modules java.base/jdk.internal.misc * java.xml - * @requires vm.debug - * @run main/native GTestWrapper --gtest_filter=NMT* -XX:NativeMemoryTracking=summary + * @run main/native GTestWrapper --gtest_filter=NMT*:os* -XX:NativeMemoryTracking=summary */ /* @test id=nmt-detail @@ -44,6 +48,5 @@ * @library /test/lib * @modules java.base/jdk.internal.misc * java.xml - * @requires vm.debug * @run main/native GTestWrapper --gtest_filter=NMT*:os* -XX:NativeMemoryTracking=detail */ diff --git a/test/hotspot/jtreg/resourcehogs/serviceability/sa/ClhsdbRegionDetailsScanOopsForG1.java b/test/hotspot/jtreg/resourcehogs/serviceability/sa/ClhsdbRegionDetailsScanOopsForG1.java index 9e04c9ac89aca7d5164a78f3c792026e3da342a7..5694d0fb528fb1c4185bba2e9dce38dc5cc97fb0 100644 --- a/test/hotspot/jtreg/resourcehogs/serviceability/sa/ClhsdbRegionDetailsScanOopsForG1.java +++ b/test/hotspot/jtreg/resourcehogs/serviceability/sa/ClhsdbRegionDetailsScanOopsForG1.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -63,7 +63,6 @@ public class ClhsdbRegionDetailsScanOopsForG1 { expStrMap.put("g1regiondetails", List.of( "Region", "Eden", - "Survivor", "StartsHumongous", "ContinuesHumongous", "Free")); diff --git a/test/hotspot/jtreg/resourcehogs/serviceability/sa/LingeredAppWithLargeArray.java b/test/hotspot/jtreg/resourcehogs/serviceability/sa/LingeredAppWithLargeArray.java index 44929f05b15213be690d35bdf6c068ed4f66b0e2..244f41873340e9ee8adcce270407083dc0f4e7ab 100644 --- a/test/hotspot/jtreg/resourcehogs/serviceability/sa/LingeredAppWithLargeArray.java +++ b/test/hotspot/jtreg/resourcehogs/serviceability/sa/LingeredAppWithLargeArray.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -23,9 +23,12 @@ import jdk.test.lib.apps.LingeredApp; +import java.lang.ref.Reference; + public class LingeredAppWithLargeArray extends LingeredApp { public static void main(String args[]) { int[] hugeArray = new int[Integer.MAX_VALUE/2]; LingeredApp.main(args); + Reference.reachabilityFence(hugeArray); } } diff --git a/test/hotspot/jtreg/resourcehogs/serviceability/sa/LingeredAppWithLargeStringArray.java b/test/hotspot/jtreg/resourcehogs/serviceability/sa/LingeredAppWithLargeStringArray.java index bc7aec91f99e6bab21fa2581df48c6b51e906d3b..adc81b1f46d52f91b014ce0e71918adb8f7daf13 100644 --- a/test/hotspot/jtreg/resourcehogs/serviceability/sa/LingeredAppWithLargeStringArray.java +++ b/test/hotspot/jtreg/resourcehogs/serviceability/sa/LingeredAppWithLargeStringArray.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -23,6 +23,8 @@ import jdk.test.lib.apps.LingeredApp; +import java.lang.ref.Reference; + public class LingeredAppWithLargeStringArray extends LingeredApp { public static void main(String args[]) { String[] hugeArray = new String[Integer.MAX_VALUE/8]; @@ -31,5 +33,6 @@ public class LingeredAppWithLargeStringArray extends LingeredApp { hugeArray[i] = new String(smallArray[i%3]); } LingeredApp.main(args); + Reference.reachabilityFence(hugeArray); } } diff --git a/test/hotspot/jtreg/runtime/8176717/TestInheritFD.java b/test/hotspot/jtreg/runtime/8176717/TestInheritFD.java index 04a739079f9f8d5b204c94cb4e26019438c5601c..c84bc7e0159918365d9daeed4533410565220e00 100644 --- a/test/hotspot/jtreg/runtime/8176717/TestInheritFD.java +++ b/test/hotspot/jtreg/runtime/8176717/TestInheritFD.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -21,6 +21,7 @@ * questions. */ +import static java.lang.Character.isDigit; import static java.lang.Long.parseLong; import static java.lang.System.getProperty; import static java.nio.file.Files.readAllBytes; @@ -40,6 +41,7 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.util.Collection; +import java.util.concurrent.TimeUnit; import java.util.Optional; import java.util.stream.Stream; @@ -60,17 +62,18 @@ import java.util.stream.Stream; * * This test is performed in three steps. The first VM starts a second VM with * gc logging enabled. The second VM starts a third VM and redirects the third - * VMs output to the first VM, it then exits and hopefully closes its log file. + * VMs output to the first VM. The second VM then exits and hopefully closes + * its log file. * - * The third VM waits for the second to exit and close its log file. After that, - * the third VM tries to rename the log file of the second VM. If it succeeds in - * doing so it means that the third VM did not inherit the open log file - * (windows can not rename opened files easily) + * The third VM waits for the second to exit and close its log file. + * On Windows, the third VM tries to rename the log file of the second VM. + * If it succeeds in doing so it means that the third VM did not inherit + * the open log file (windows cannot rename opened files easily). + * On unix like systems, the third VM uses "lsof" for verification. * - * The third VM communicates the success to rename the file by printing "CLOSED - * FD". The first VM checks that the string was printed by the third VM. - * - * On unix like systems "lsof" is used. + * The third VM communicates success by printing "RETAINS FD". The first VM + * waits for the third VM to exit and checks that the string was printed by + * the third VM. */ public class TestInheritFD { @@ -79,9 +82,146 @@ public class TestInheritFD { public static final String RETAINS_FD = "VM RESULT => RETAINS FD"; public static final String EXIT = "VM RESULT => VM EXIT"; public static final String LOG_SUFFIX = ".strangelogsuffixthatcanbecheckedfor"; + public static final String USER_DIR = System.getProperty("user.dir"); + public static final String LSOF_PID_PREFIX = " VM lsof pid="; + public static final String SECOND_VM_PID_PREFIX = "Second VM pid="; + public static final String THIRD_VM_PID_PREFIX = "Third VM pid="; + public static final String THIRD_VM_WAITING_PREFIX = "Third VM waiting for second VM pid="; + + public static float timeoutFactor = Float.parseFloat(System.getProperty("test.timeout.factor", "1.0")); + public static long subProcessTimeout = (long)(15L * timeoutFactor); + + // Extract a pid from the specified String at the specified start offset. + private static long extractPidFromStringOffset(String str, int start) { + int end; + for (end = start; end < str.length(); end++) { + if (!isDigit(str.charAt(end))) { + break; + } + } + if (start == end) { // no digits at all + return -1; + } + return parseLong(str.substring(start, end)); + } + + // Wait for the sub-process pids identified in commFile to finish executing. + // Returns true if RETAINS_FD was found in the commFile and false otherwise. + private static boolean waitForSubPids(File commFile) throws Exception { + String out = ""; + int sleepCnt = 0; + long secondVMPID = -1; + long secondVMlsofPID = -1; + long thirdVMPID = -1; + long thirdVMlsofPID = -1; + // Only have to gather info until the doneWithPattern shows up in the output: + String doneWithPattern; + if (isWindows()) { + doneWithPattern = THIRD_VM_PID_PREFIX; + } else { + doneWithPattern = "Third" + LSOF_PID_PREFIX; + } + do { + out = new String(readAllBytes(commFile.toPath())); + if (secondVMPID == -1) { + int ind = out.indexOf(SECOND_VM_PID_PREFIX); + if (ind != -1) { + int startPid = ind + SECOND_VM_PID_PREFIX.length(); + secondVMPID = extractPidFromStringOffset(out, startPid); + System.out.println("secondVMPID=" + secondVMPID); + } + } + if (!isWindows() && secondVMlsofPID == -1) { + String prefix = "Second" + LSOF_PID_PREFIX; + int ind = out.indexOf(prefix); + if (ind != -1) { + int startPid = ind + prefix.length(); + secondVMlsofPID = extractPidFromStringOffset(out, startPid); + System.out.println("secondVMlsofPID=" + secondVMlsofPID); + } + } + if (thirdVMPID == -1) { + int ind = out.indexOf(THIRD_VM_PID_PREFIX); + if (ind != -1) { + int startPid = ind + THIRD_VM_PID_PREFIX.length(); + thirdVMPID = extractPidFromStringOffset(out, startPid); + System.out.println("thirdVMPID=" + thirdVMPID); + } + } + if (!isWindows() && thirdVMlsofPID == -1) { + String prefix = "Third" + LSOF_PID_PREFIX; + int ind = out.indexOf(prefix); + if (ind != -1) { + int startPid = ind + prefix.length(); + thirdVMlsofPID = extractPidFromStringOffset(out, startPid); + System.out.println("thirdVMlsofPID=" + thirdVMlsofPID); + } + } + Thread.sleep(100); + sleepCnt++; + } while (!out.contains(doneWithPattern) && !out.contains(EXIT)); + + System.out.println("Called Thread.sleep(100) " + sleepCnt + " times."); + + long subPids[] = new long[4]; // At most 4 pids to check. + String subNames[] = new String[4]; // At most 4 names for those pids. + int ind = 0; + if (!isWindows() && secondVMlsofPID != -1) { + // The second VM's lsof cmd should be the first non-windows sub-process to finish: + subPids[ind] = secondVMlsofPID; + subNames[ind] = "second VM lsof"; + ind++; + } + // The second VM should the second non-windows or first windows sub-process to finish: + subPids[ind] = secondVMPID; + subNames[ind] = "second VM"; + ind++; + if (!isWindows() && thirdVMlsofPID != -1) { + // The third VM's lsof cmd should be the third non-windows sub-process to finish: + subPids[ind] = thirdVMlsofPID; + subNames[ind] = "third VM lsof"; + ind++; + } + // The third VM should the last sub-process to finish: + subPids[ind] = thirdVMPID; + subNames[ind] = "third VM"; + ind++; + if (isWindows()) { + // No lsof pids on windows so we use fewer array slots. + // Make sure they are marked as not used. + for (; ind < subPids.length; ind++) { + subPids[ind] = -1; + } + } + + try { + for (ind = 0; ind < subPids.length; ind++) { + if (subPids[ind] == -1) { + continue; + } + System.out.print("subs[" + ind + "]={pid=" + subPids[ind] + ", name=" + subNames[ind] + "}"); + ProcessHandle.of(subPids[ind]).ifPresent(handle -> handle.onExit().orTimeout(subProcessTimeout, TimeUnit.SECONDS).join()); + System.out.println(" finished."); + } + } catch (Exception e) { + // Terminate the "subs" line from above: + System.out.println(" Exception was thrown while trying to join() subPids: " + e.toString()); + throw e; + } finally { + // Reread to get everything in the commFile: + out = new String(readAllBytes(commFile.toPath())); + System.out.println("<BEGIN commFile contents>"); + System.out.println(out); + System.out.println("<END commFile contents>"); + } + + return out.contains(RETAINS_FD); + } // first VM public static void main(String[] args) throws Exception { + System.out.println("subProcessTimeout=" + subProcessTimeout + " seconds."); + System.out.println("First VM starts."); String logPath = Utils.createTempFile("logging", LOG_SUFFIX).toFile().getName(); File commFile = Utils.createTempFile("communication", ".txt").toFile(); @@ -98,24 +238,18 @@ public class TestInheritFD { pb.redirectOutput(commFile); // use temp file to communicate between processes pb.start(); - String out = ""; - do { - out = new String(readAllBytes(commFile.toPath())); - Thread.sleep(100); - System.out.println("SLEEP 100 millis"); - } while (!out.contains(EXIT)); - - System.out.println(out); - if (out.contains(RETAINS_FD)) { - System.out.println("Log file was not inherited by third VM"); + if (waitForSubPids(commFile)) { + System.out.println("Log file was not inherited by third VM."); } else { - throw new RuntimeException("could not match: " + RETAINS_FD); + throw new RuntimeException("Log file was leaked to the third VM."); } + System.out.println("First VM ends."); } static class VMStartedWithLogging { // second VM public static void main(String[] args) throws IOException, InterruptedException { + System.out.println(SECOND_VM_PID_PREFIX + ProcessHandle.current().pid()); ProcessBuilder pb = createJavaProcessBuilder( "-Dtest.jdk=" + getProperty("test.jdk"), VMShouldNotInheritFileDescriptors.class.getName(), @@ -125,30 +259,43 @@ public class TestInheritFD { pb.start(); if (!isWindows()) { - System.out.println("(Second VM) Open file descriptors:\n" + outputContainingFilenames().stream().collect(joining("\n"))); + System.out.println("(Second VM) Open file descriptors:\n" + outputContainingFilenames("Second").stream().collect(joining("\n"))); + } + if (false) { // Enable to simulate a timeout in the second VM. + Thread.sleep(300 * 1000); } + System.out.println("Second VM ends."); } } static class VMShouldNotInheritFileDescriptors { // third VM public static void main(String[] args) throws InterruptedException { + System.out.println(THIRD_VM_PID_PREFIX + ProcessHandle.current().pid()); try { File logFile = new File(args[0]); long parentPid = parseLong(args[1]); fakeLeakyJVM(false); // for debugging of test case + System.out.println(THIRD_VM_WAITING_PREFIX + parentPid); + ProcessHandle.of(parentPid).ifPresent(handle -> handle.onExit().orTimeout(subProcessTimeout, TimeUnit.SECONDS).join()); + if (isWindows()) { - windows(logFile, parentPid); + windows(logFile); } else { - Collection<String> output = outputContainingFilenames(); + Collection<String> output = outputContainingFilenames("Third"); System.out.println("(Third VM) Open file descriptors:\n" + output.stream().collect(joining("\n"))); System.out.println(findOpenLogFile(output) ? LEAKS_FD : RETAINS_FD); } + if (false) { // Enable to simulate a timeout in the third VM. + Thread.sleep(300 * 1000); + } } catch (Exception e) { - System.out.println(e.toString()); + System.out.println("Exception was thrown: " + e.toString()); + throw e; } finally { System.out.println(EXIT); + System.out.println("Third VM ends."); } } } @@ -164,9 +311,11 @@ public class TestInheritFD { } } - static Stream<String> run(String... args){ + static Stream<String> runLsof(String whichVM, String... args){ try { - return new BufferedReader(new InputStreamReader(new ProcessBuilder(args).start().getInputStream())).lines(); + Process lsof = new ProcessBuilder(args).start(); + System.out.println(whichVM + LSOF_PID_PREFIX + lsof.pid()); + return new BufferedReader(new InputStreamReader(lsof.getInputStream())).lines(); } catch (IOException e) { throw new RuntimeException(e); } @@ -185,12 +334,12 @@ public class TestInheritFD { return lsofCommandCache; } - static Collection<String> outputContainingFilenames() { + static Collection<String> outputContainingFilenames(String whichVM) { long pid = ProcessHandle.current().pid(); - String[] command = lsofCommand().orElseThrow(() -> new RuntimeException("lsof like command not found")); - System.out.println("using command: " + command[0] + " " + command[1]); - return run(command[0], command[1], "" + pid).collect(toList()); + // Only search the directory in which the VM is running (user.dir property). + System.out.println("using command: " + command[0] + " -a +d " + USER_DIR + " " + command[1] + " " + pid); + return runLsof(whichVM, command[0], "-a", "+d", USER_DIR, command[1], "" + pid).collect(toList()); } static boolean findOpenLogFile(Collection<String> fileNames) { @@ -207,9 +356,7 @@ public class TestInheritFD { .isPresent(); } - static void windows(File f, long parentPid) throws InterruptedException { - System.out.println("waiting for pid: " + parentPid); - ProcessHandle.of(parentPid).ifPresent(handle -> handle.onExit().join()); + static void windows(File f) throws InterruptedException { System.out.println("trying to rename file to the same name: " + f); System.out.println(f.renameTo(f) ? RETAINS_FD : LEAKS_FD); // this parts communicates a closed file descriptor by printing "VM RESULT => RETAINS FD" } diff --git a/test/hotspot/jtreg/runtime/BootClassAppendProp/GetBootClassPathAppendProp.java b/test/hotspot/jtreg/runtime/BootClassAppendProp/GetBootClassPathAppendProp.java new file mode 100644 index 0000000000000000000000000000000000000000..59d62e5615b015d3dcf97dba55e6ee71b4b6e9b7 --- /dev/null +++ b/test/hotspot/jtreg/runtime/BootClassAppendProp/GetBootClassPathAppendProp.java @@ -0,0 +1,53 @@ +/* + * 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. + */ + +/** + * @test + * @bug 8225093 + * @summary Check that JVMTI GetSystemProperty API returns the right values for + * property jdk.boot.class.path.append. + * @requires vm.jvmti + * @library /test/lib + * @run main/othervm/native -agentlib:GetBootClassPathAppendProp GetBootClassPathAppendProp + * @run main/othervm/native -Xbootclasspath/a:blah -agentlib:GetBootClassPathAppendProp GetBootClassPathAppendProp one_arg + * + */ + +public class GetBootClassPathAppendProp { + private static native String getSystemProperty(); + + public static void main(String[] args) throws Exception { + String path = getSystemProperty(); + if (args.length > 0) { + if (!path.equals("blah")) { + throw new RuntimeException("Wrong value returned for jdk.boot.class.path.append: " + + path); + } + } else { + if (path != null) { + throw new RuntimeException("Null value expected for jdk.boot.class.path.append: " + + path); + } + } + } +} diff --git a/test/hotspot/jtreg/runtime/BootClassAppendProp/libGetBootClassPathAppendProp.c b/test/hotspot/jtreg/runtime/BootClassAppendProp/libGetBootClassPathAppendProp.c new file mode 100644 index 0000000000000000000000000000000000000000..07f57cff267b4d2c24bae29e8e9bdaba4c88097a --- /dev/null +++ b/test/hotspot/jtreg/runtime/BootClassAppendProp/libGetBootClassPathAppendProp.c @@ -0,0 +1,62 @@ +/* + * 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 <stdio.h> +#include <string.h> +#include <jvmti.h> + +#ifdef __cplusplus +extern "C" { +#endif + +static jvmtiEnv *jvmti = NULL; + +JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) { + int err = (*jvm)->GetEnv(jvm, (void**) &jvmti, JVMTI_VERSION_9); + if (err != JNI_OK) { + return JNI_ERR; + } + return JNI_OK; +} + +JNIEXPORT jstring JNICALL +Java_GetBootClassPathAppendProp_getSystemProperty(JNIEnv *env, jclass cls) { + jvmtiError err; + char* prop_value; + + err = (*jvmti)->GetSystemProperty(jvmti, "jdk.boot.class.path.append", &prop_value); + if (err == JVMTI_ERROR_NOT_AVAILABLE) { + return NULL; + } + if (err != JVMTI_ERROR_NONE) { + char err_msg[50]; + snprintf(err_msg, 50, "Wrong JVM TI error code: %d", err); + return (*env)->NewStringUTF(env, err_msg); + } + + return (*env)->NewStringUTF(env, prop_value); +} + +#ifdef __cplusplus +} +#endif diff --git a/test/hotspot/jtreg/runtime/BootstrapMethod/BSMCalledTwice.java b/test/hotspot/jtreg/runtime/BootstrapMethod/BSMCalledTwice.java index bad675a40ffcc4d7f4c98c8f9232a9c0b90bf6dd..a8a8aa060bf038295d045cc2b39778245e37224c 100644 --- a/test/hotspot/jtreg/runtime/BootstrapMethod/BSMCalledTwice.java +++ b/test/hotspot/jtreg/runtime/BootstrapMethod/BSMCalledTwice.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -30,6 +30,16 @@ * @run main BSMCalledTwice */ +/* + * @test + * @bug 8262134 + * @library /test/lib + * @requires vm.debug + * @modules java.base/jdk.internal.org.objectweb.asm + * @compile -XDignore.symbol.file BSMCalledTwice.java + * @run main/othervm -Xcomp -XX:CompileCommand=compileonly,TestC::* -XX:+DeoptimizeALot -XX:+VerifyStack BSMCalledTwice + */ + import java.io.File; import java.io.FileOutputStream; import java.util.*; diff --git a/test/hotspot/jtreg/runtime/NMT/ShutdownTwice.java b/test/hotspot/jtreg/runtime/CommandLine/PrintClasses.java similarity index 58% rename from test/hotspot/jtreg/runtime/NMT/ShutdownTwice.java rename to test/hotspot/jtreg/runtime/CommandLine/PrintClasses.java index 600d57cc91fa345d0b14813e35f96415ab5b6583..7c45e2ea02f74583459fe3b125a49a8984b53ae6 100644 --- a/test/hotspot/jtreg/runtime/NMT/ShutdownTwice.java +++ b/test/hotspot/jtreg/runtime/CommandLine/PrintClasses.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 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 @@ -21,39 +21,31 @@ * questions. */ + /* * @test - * @summary Run shutdown twice + * @bug 8275775 + * @summary Test jcmd VM.classes * @library /test/lib - * @modules java.base/jdk.internal.misc - * java.management - * @run main/othervm -XX:NativeMemoryTracking=detail ShutdownTwice + * @run main/othervm PrintClasses */ -import jdk.test.lib.process.ProcessTools; import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.JDKToolFinder; -public class ShutdownTwice { - +public class PrintClasses { public static void main(String args[]) throws Exception { - // Grab my own PID - String pid = Long.toString(ProcessTools.getProcessId()); - OutputAnalyzer output; - - ProcessBuilder pb = new ProcessBuilder(); + var pid = Long.toString(ProcessHandle.current().pid()); + var pb = new ProcessBuilder(); - // Run 'jcmd <pid> VM.native_memory shutdown' - pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "shutdown"}); - output = new OutputAnalyzer(pb.start()); - - // Verify that jcmd reports that NMT is shutting down - output.shouldContain("Native memory tracking has been turned off"); + pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.classes"}); + var output = new OutputAnalyzer(pb.start()); + output.shouldNotContain("instance size"); + output.shouldContain(PrintClasses.class.getSimpleName()); - // Run shutdown again + pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.classes", "-verbose"}); output = new OutputAnalyzer(pb.start()); - - // Verify that jcmd reports that NMT has been shutdown already - output.shouldContain("Native memory tracking has been shutdown"); + output.shouldContain("instance size"); + output.shouldContain(PrintClasses.class.getSimpleName()); } } diff --git a/test/hotspot/jtreg/runtime/CommandLine/PrintTouchedMethodsJcmd.java b/test/hotspot/jtreg/runtime/CommandLine/PrintTouchedMethodsJcmd.java index f3188007941f385ba91c09c886ddf8152fda8633..26f0c3ca0dc2b221a9f403feac31e3ea0b43114c 100644 --- a/test/hotspot/jtreg/runtime/CommandLine/PrintTouchedMethodsJcmd.java +++ b/test/hotspot/jtreg/runtime/CommandLine/PrintTouchedMethodsJcmd.java @@ -41,10 +41,6 @@ public class PrintTouchedMethodsJcmd { var pb = new ProcessBuilder(); pb.command(new String[] {JDKToolFinder.getJDKTool("jcmd"), pid, "VM.print_touched_methods"}); var output = new OutputAnalyzer(pb.start()); - try { - output.shouldContain("PrintTouchedMethodsJcmd.main:([Ljava/lang/String;)V"); - } catch (RuntimeException e) { - output.shouldContain("Unknown diagnostic command"); - } - } + output.shouldContain("PrintTouchedMethodsJcmd.main:([Ljava/lang/String;)V"); + } } diff --git a/test/hotspot/jtreg/runtime/CommandLine/VMDeprecatedOptions.java b/test/hotspot/jtreg/runtime/CommandLine/VMDeprecatedOptions.java index 79f02e4368e59083c181bfc5d933702dae924f8d..ee93c740cf136f7d1670ea7b561db05752c4335b 100644 --- a/test/hotspot/jtreg/runtime/CommandLine/VMDeprecatedOptions.java +++ b/test/hotspot/jtreg/runtime/CommandLine/VMDeprecatedOptions.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -21,6 +21,10 @@ * questions. */ +import java.util.Arrays; +import java.util.ArrayList; + +import jdk.test.lib.Platform; import jdk.test.lib.process.ProcessTools; import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.cli.*; @@ -39,18 +43,30 @@ public class VMDeprecatedOptions { * each entry is {[0]: option name, [1]: value to set * (true/false/n/string)}. */ - public static final String[][] DEPRECATED_OPTIONS = { - // deprecated non-alias flags: - {"MaxGCMinorPauseMillis", "1032"}, - {"MaxRAMFraction", "8"}, - {"MinRAMFraction", "2"}, - {"InitialRAMFraction", "64"}, - {"TLABStats", "false"}, - {"AllowRedefinitionToAddDeleteMethods", "true"}, + public static final String[][] DEPRECATED_OPTIONS; + static { + // Use an ArrayList so platform-specific flags can be + // optionally added. + ArrayList<String[]> deprecated = new ArrayList( + Arrays.asList(new String[][] { + // deprecated non-alias flags: + {"MaxGCMinorPauseMillis", "1032"}, + {"MaxRAMFraction", "8"}, + {"MinRAMFraction", "2"}, + {"InitialRAMFraction", "64"}, + {"TLABStats", "false"}, + {"AllowRedefinitionToAddDeleteMethods", "true"}, - // deprecated alias flags (see also aliased_jvm_flags): - {"DefaultMaxRAMFraction", "4"}, - {"CreateMinidumpOnCrash", "false"} + // deprecated alias flags (see also aliased_jvm_flags): + {"DefaultMaxRAMFraction", "4"}, + {"CreateMinidumpOnCrash", "false"} + } + )); + if (Platform.isLinux()) { + deprecated.add(new String[] {"UseContainerCpuShares", "false"}); + deprecated.add(new String[] {"PreferContainerQuotaForCPUCount", "true"}); + } + DEPRECATED_OPTIONS = deprecated.toArray(new String[][]{}); }; static String getDeprecationString(String optionName) { diff --git a/test/hotspot/jtreg/runtime/CompressedOops/CompressedClassPointers.java b/test/hotspot/jtreg/runtime/CompressedOops/CompressedClassPointers.java index c46b32b220d9c76064b7ef8c6c8df64eb3e56d32..8e2033e73296273889d3c0797ff2c28b1cb24968 100644 --- a/test/hotspot/jtreg/runtime/CompressedOops/CompressedClassPointers.java +++ b/test/hotspot/jtreg/runtime/CompressedOops/CompressedClassPointers.java @@ -224,8 +224,8 @@ public class CompressedClassPointers { "-XX:+VerifyBeforeGC", "-version"); OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldContain("Narrow klass base: 0x0000000000000000"); - if (!Platform.isAArch64()) { - // Currently relax this test for Aarch64. + if (!Platform.isAArch64() && !Platform.isPPC()) { + // Currently relax this test for Aarch64 and ppc. output.shouldContain("Narrow klass shift: 0"); } output.shouldHaveExitValue(0); @@ -244,8 +244,8 @@ public class CompressedClassPointers { "-XX:+VerifyBeforeGC", "-version"); OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldContain("Narrow klass base: 0x0000000000000000"); - if (!Platform.isAArch64()) { - // Currently relax this test for Aarch64. + if (!Platform.isAArch64() && !Platform.isPPC()) { + // Currently relax this test for Aarch64 and ppc. output.shouldContain("Narrow klass shift: 0"); } output.shouldHaveExitValue(0); diff --git a/test/hotspot/jtreg/runtime/ErrorHandling/GenOutOfMemoryError.java b/test/hotspot/jtreg/runtime/ErrorHandling/GenOutOfMemoryError.java new file mode 100644 index 0000000000000000000000000000000000000000..79c3c37969fe3a7bc7fd1730d7c75cde47bd4d24 --- /dev/null +++ b/test/hotspot/jtreg/runtime/ErrorHandling/GenOutOfMemoryError.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2021, 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. + */ + + +/* + * @test + * @bug 8278125 + * @summary Test if OOME has proper stacktrace + * @library /test/lib + * @run main/othervm -Xmx100m -Xms100m GenOutOfMemoryError + */ + +import jdk.test.lib.Asserts; + +public class GenOutOfMemoryError { + private static int OOME_HAS_STACK_CNT = 0; + + private void badMethod(int n){ + try { + System.out.format("bad method was invoked %n", n); + // Try to allocate an array the same size as the heap - it will throw OOME without + // actually consuming available memory. + Integer[] array = new Integer[1000 * 1000 * 100]; + array.hashCode(); + } catch (Throwable t){ + StackTraceElement[] traces = t.getStackTrace(); + if (traces.length != 0) { + OOME_HAS_STACK_CNT++; + } + t.printStackTrace(); + } + } + + public static void main(String[] args) { + GenOutOfMemoryError genOutOfMemoryError = new GenOutOfMemoryError(); + + for (int i = 0; i < 7; i++) { + genOutOfMemoryError.badMethod(i + 1); + } + Asserts.assertTrue(4/*PreallocatedOutOfMemoryErrorCount defaults to 4*/ == OOME_HAS_STACK_CNT, "Some OOMEs do not have stacktraces"); + } +} diff --git a/test/hotspot/jtreg/runtime/HiddenClasses/InstantiateHiddenClass.java b/test/hotspot/jtreg/runtime/HiddenClasses/InstantiateHiddenClass.java index 773588b11f94311fb98f9777d249e10feb0734f8..cb8d59af2f7d4360a95ac64088384e82efb05b23 100644 --- a/test/hotspot/jtreg/runtime/HiddenClasses/InstantiateHiddenClass.java +++ b/test/hotspot/jtreg/runtime/HiddenClasses/InstantiateHiddenClass.java @@ -32,6 +32,7 @@ import java.lang.invoke.MethodType; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodHandles.Lookup; +import java.lang.invoke.MethodHandles.Lookup.ClassOption; import static java.lang.invoke.MethodHandles.Lookup.ClassOption.*; import jdk.test.lib.compiler.InMemoryJavaCompiler; @@ -44,12 +45,19 @@ public class InstantiateHiddenClass { " } } "); public static void main(String[] args) throws Throwable { + // This class is also used by the appcds/dynamicArchive/RegularHiddenClass.java + // test which will pass the "keep-alive" argument during dynamic CDS dump + // for preventing from being GC'ed prior to the dumping operation. + boolean keepAlive = false; + if (args.length == 1 && args[0].equals("keep-alive")) { + keepAlive = true; + } // Test that a hidden class cannot be found through its name. try { Lookup lookup = MethodHandles.lookup(); - Class<?> cl = lookup.defineHiddenClass(klassbuf, false, NESTMATE).lookupClass(); - Class.forName(cl.getName()).newInstance(); + Class<?> c0 = lookup.defineHiddenClass(klassbuf, false, NESTMATE).lookupClass(); + Class.forName(c0.getName()).newInstance(); throw new RuntimeException("Expected ClassNotFoundException not thrown"); } catch (ClassNotFoundException e ) { // Test passed @@ -60,8 +68,9 @@ public class InstantiateHiddenClass { // Verify that the references to these objects are different and references // to their classes are not equal either. Lookup lookup = MethodHandles.lookup(); - Class<?> c1 = lookup.defineHiddenClass(klassbuf, false, NESTMATE).lookupClass(); - Class<?> c2 = lookup.defineHiddenClass(klassbuf, false, NESTMATE).lookupClass(); + ClassOption classOption = keepAlive ? STRONG : NESTMATE; + Class<?> c1 = lookup.defineHiddenClass(klassbuf, false, classOption).lookupClass(); + Class<?> c2 = lookup.defineHiddenClass(klassbuf, false, classOption).lookupClass(); Object o1 = c1.newInstance(); Object o2 = c2.newInstance(); if (o1 == o2) { diff --git a/test/hotspot/jtreg/runtime/Metaspace/PrintMetaspaceDcmd.java b/test/hotspot/jtreg/runtime/Metaspace/PrintMetaspaceDcmd.java index 413a911e700b10088d9778b042d53e3c0b6f8551..d90a49a0adbcdea6038809f9854cb06d7764e2fc 100644 --- a/test/hotspot/jtreg/runtime/Metaspace/PrintMetaspaceDcmd.java +++ b/test/hotspot/jtreg/runtime/Metaspace/PrintMetaspaceDcmd.java @@ -168,6 +168,29 @@ public class PrintMetaspaceDcmd { output.shouldContain("Virtual space list"); output.shouldMatch("node.*reserved.*committed.*used.*"); + pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.metaspace", "chunkfreelist"}); + // Output should look somewhat like this... + // vvvvvvvvvvvvvvvv + // Chunk freelist details: + // Non-Class: + // cm non-class-space: 5 chunks, total word size: 402944. + // -- List[lv00]: empty + // -- List[lv01]: - <Chunk @0x00007f925c124090, state f, base 0x00007f9208600000, level lv01 (262144 words), used 0 words, committed 0 words.> - total : 1 chunks. + // -- List[lv02]: - <Chunk @0x00007f925c1240d8, state f, base 0x00007f9208500000, level lv02 (131072 words), used 0 words, committed 0 words.> - total : 1 chunks. + // -- List[lv03]: empty + // ..... + // + // total chunks: 5, total word size: 402944. + // ^^^^^^^^^^^^^^^^^ + // .... but the actual number of chunks in the freelist is difficult to predict and may be low or zero since + // no class unloading happened yet. + output = new OutputAnalyzer(pb.start()); + output.shouldHaveExitValue(0); + output.shouldContain("Chunk freelist details:"); + // ... but we should see at least one one chunk somewhere, the list should never be empty. + output.shouldMatch(".*-- List\\[lv00\\].*"); + output.shouldMatch(".*total chunks.*total word size.*"); + // Test with different scales pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.metaspace", "scale=G"}); output = new OutputAnalyzer(pb.start()); diff --git a/test/hotspot/jtreg/runtime/Metaspace/elastic/MetaspaceTestContext.java b/test/hotspot/jtreg/runtime/Metaspace/elastic/MetaspaceTestContext.java index 3a43d92c48d5ea3c841c1f91e2eeb8abf67cb21a..521bf75e974fd724aa9874878237830222fa1046 100644 --- a/test/hotspot/jtreg/runtime/Metaspace/elastic/MetaspaceTestContext.java +++ b/test/hotspot/jtreg/runtime/Metaspace/elastic/MetaspaceTestContext.java @@ -1,9 +1,7 @@ import sun.hotspot.WhiteBox; -import java.util.ArrayList; import java.util.HashSet; -import java.util.List; public class MetaspaceTestContext { @@ -140,6 +138,9 @@ public class MetaspaceTestContext { long usageMeasured = usedWords(); long committedMeasured = committedWords(); + System.out.println("context used words " + usageMeasured + ", committed words " + committedMeasured + + "."); + if (usageMeasured > committedMeasured) { throw new RuntimeException("Weirdness."); } diff --git a/test/hotspot/jtreg/runtime/Metaspace/elastic/MetaspaceTestManyArenasManyThreads.java b/test/hotspot/jtreg/runtime/Metaspace/elastic/MetaspaceTestManyArenasManyThreads.java index 3614fde13d384e65c443876079ef0deb04005a89..7e1c2678f4e7a0ead0d711ddcc0f492758c53ffa 100644 --- a/test/hotspot/jtreg/runtime/Metaspace/elastic/MetaspaceTestManyArenasManyThreads.java +++ b/test/hotspot/jtreg/runtime/Metaspace/elastic/MetaspaceTestManyArenasManyThreads.java @@ -83,6 +83,19 @@ public class MetaspaceTestManyArenasManyThreads extends MetaspaceTestWithThreads // Stop all threads. stopAllThreads(); + // At this point a large number of Arenas will have died (see above), but we probably still have + // some live arenas left. The chunk freelist will be full of free chunks. Maybe a bit fragmented, + // with a healthy mixture of larger and smaller chunks, since we still have live arenas. + // These chunks are all committed still, since we did nothing to reclaim the storage. We now purge + // the context manually to uncommit those chunks, in order to get a realistic number for + // committed words (see checkStatistics()). + // Note: In real metaspace, this happens as part of the same GC which removes class loaders and + // frees their metaspace arenas. All within CLDG::purge(). But since this test isolates the metaspace + // context and does test it separately, GC and CLDG are not involved here. We need to purge manually. + // + // Purging uncommits all free chunks >= 64K/16K (MetaspaceReclaimPolicy=standard/aggressive). + context.purge(); + context.updateTotals(); System.out.println(" ## Finished: " + context); diff --git a/test/hotspot/jtreg/runtime/Monitor/MonitorUsedDeflationThresholdTest.java b/test/hotspot/jtreg/runtime/Monitor/MonitorUsedDeflationThresholdTest.java index 6bae009a84dafac02a3e9e783fb991df436e32a7..5dd01e4262bcdadc251d3fea0c6d9aae6aa46aab 100644 --- a/test/hotspot/jtreg/runtime/Monitor/MonitorUsedDeflationThresholdTest.java +++ b/test/hotspot/jtreg/runtime/Monitor/MonitorUsedDeflationThresholdTest.java @@ -81,6 +81,11 @@ public class MonitorUsedDeflationThresholdTest { // of monitors for threads that call Object.wait(). "-XX:+UnlockDiagnosticVMOptions", "-XX:AvgMonitorsPerThreadEstimate=1", + // MonitorUsedDeflationThreshold == 10 means we'll request + // deflations when 10% of monitors are used rather than the + // default 90%. This should allow the test to tolerate a burst + // of used monitors by threads not under this test's control. + "-XX:MonitorUsedDeflationThreshold=10", // Enable monitorinflation logging so we can see that // MonitorUsedDeflationThreshold and // NoAsyncDeflationProgressMaxoption are working. @@ -89,8 +94,9 @@ public class MonitorUsedDeflationThresholdTest { "-Xlog:safepoint+cleanup=info", "-Xlog:safepoint+stats=debug", // Run the test with inflate_count == 33 since that - // reproduced the bug with JDK13. Anything above the - // in_use_list_ceiling will do the trick. + // reproduced the bug with JDK13. With inflate_count == 33, an + // initial ceiling == 12 and MonitorUsedDeflationThreshold == 10, + // we should hit NoAsyncDeflationProgressMax at least 3 times. "MonitorUsedDeflationThresholdTest", "33"); OutputAnalyzer output_detail = new OutputAnalyzer(pb.start()); @@ -111,6 +117,8 @@ public class MonitorUsedDeflationThresholdTest { throw new RuntimeException("Did not find too_many string in output.\n"); } System.out.println("too_many='" + too_many + "'"); + // Uncomment the following line for dumping test output in passing runs: + // output_detail.reportDiagnosticSummary(); System.out.println("PASSED."); return; diff --git a/test/hotspot/jtreg/runtime/NMT/JcmdWithNMTDisabled.java b/test/hotspot/jtreg/runtime/NMT/JcmdWithNMTDisabled.java index 5567a57b517db59a31bedccd8a6c363cf4589bee..da1dd4979759b772b67f0d563242e10c0092f082 100644 --- a/test/hotspot/jtreg/runtime/NMT/JcmdWithNMTDisabled.java +++ b/test/hotspot/jtreg/runtime/NMT/JcmdWithNMTDisabled.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -30,6 +30,7 @@ * @run driver JcmdWithNMTDisabled 1 */ +import jdk.test.lib.Platform; import jdk.test.lib.process.ProcessTools; import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.JDKToolFinder; @@ -47,10 +48,12 @@ public class JcmdWithNMTDisabled { OutputAnalyzer output; String testjdkPath = System.getProperty("test.jdk"); - // First run without enabling NMT - pb = ProcessTools.createJavaProcessBuilder("-Dtest.jdk=" + testjdkPath, "JcmdWithNMTDisabled"); - output = new OutputAnalyzer(pb.start()); - output.shouldHaveExitValue(0); + // First run without enabling NMT (not in debug, where NMT is by default on) + if (!Platform.isDebugBuild()) { + pb = ProcessTools.createJavaProcessBuilder("-Dtest.jdk=" + testjdkPath, "JcmdWithNMTDisabled"); + output = new OutputAnalyzer(pb.start()); + output.shouldHaveExitValue(0); + } // Then run with explicitly disabling NMT, should not be any difference pb = ProcessTools.createJavaProcessBuilder("-Dtest.jdk=" + testjdkPath, "-XX:NativeMemoryTracking=off", "JcmdWithNMTDisabled"); @@ -69,7 +72,6 @@ public class JcmdWithNMTDisabled { jcmdCommand("summary.diff"); jcmdCommand("detail.diff"); jcmdCommand("scale=GB"); - jcmdCommand("shutdown"); } // Helper method for invoking different jcmd calls, all should fail with the same message saying NMT is not enabled diff --git a/test/hotspot/jtreg/runtime/NMT/PrintNMTStatisticsWithNMTDisabled.java b/test/hotspot/jtreg/runtime/NMT/PrintNMTStatisticsWithNMTDisabled.java index 7e45c3f16d74998ba91931618aa47aeef92055a8..31ab2537fe1e9864e7210c612278ed7b529c0027 100644 --- a/test/hotspot/jtreg/runtime/NMT/PrintNMTStatisticsWithNMTDisabled.java +++ b/test/hotspot/jtreg/runtime/NMT/PrintNMTStatisticsWithNMTDisabled.java @@ -38,7 +38,7 @@ public class PrintNMTStatisticsWithNMTDisabled { public static void main(String args[]) throws Exception { ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( "-XX:+UnlockDiagnosticVMOptions", - "-XX:+PrintNMTStatistics", + "-XX:+PrintNMTStatistics", "-XX:NativeMemoryTracking=off", "-version"); OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldContain("warning: PrintNMTStatistics is disabled, because native memory tracking is not enabled"); diff --git a/test/hotspot/jtreg/runtime/NMT/SummaryAfterShutdown.java b/test/hotspot/jtreg/runtime/NMT/SummaryAfterShutdown.java deleted file mode 100644 index ab058fe8f0e7a06b5bf35056d7e27b0cb9dc1a6b..0000000000000000000000000000000000000000 --- a/test/hotspot/jtreg/runtime/NMT/SummaryAfterShutdown.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2013, 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. - */ - -/* - * @test - * @summary Verify that jcmd correctly reports that NMT is not enabled after a shutdown - * @library /test/lib - * @modules java.base/jdk.internal.misc - * java.management - * @run main/othervm -XX:NativeMemoryTracking=detail SummaryAfterShutdown - */ - -import jdk.test.lib.process.ProcessTools; -import jdk.test.lib.process.OutputAnalyzer; -import jdk.test.lib.JDKToolFinder; - -public class SummaryAfterShutdown { - - public static void main(String args[]) throws Exception { - OutputAnalyzer output; - // Grab my own PID - String pid = Long.toString(ProcessTools.getProcessId()); - ProcessBuilder pb = new ProcessBuilder(); - - // Run 'jcmd <pid> VM.native_memory shutdown' - pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "shutdown"}); - output = new OutputAnalyzer(pb.start()); - - // Verify that jcmd reports that NMT is shutting down - output.shouldContain("Native memory tracking has been turned off"); - - // Run 'jcmd <pid> VM.native_memory summary' - pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "summary"}); - output = new OutputAnalyzer(pb.start()); - - // Verify that jcmd reports that NMT has been shutdown - output.shouldContain("Native memory tracking has been shutdown"); - } -} diff --git a/test/hotspot/jtreg/runtime/Thread/StopAtExit.java b/test/hotspot/jtreg/runtime/Thread/StopAtExit.java index 2255009320210785d342686c566cbbb956a6d41d..b997890e3476a1ba02844c5c52b575e654562cdd 100644 --- a/test/hotspot/jtreg/runtime/Thread/StopAtExit.java +++ b/test/hotspot/jtreg/runtime/Thread/StopAtExit.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -23,11 +23,13 @@ /** * @test - * @bug 8167108 8266130 + * @bug 8167108 8266130 8282704 * @summary Stress test java.lang.Thread.stop() at thread exit. + * @modules java.base/java.lang:open * @run main/othervm StopAtExit */ +import java.lang.reflect.Method; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -38,6 +40,10 @@ public class StopAtExit extends Thread { public CountDownLatch exitSyncObj = new CountDownLatch(1); public CountDownLatch startSyncObj = new CountDownLatch(1); + public StopAtExit(ThreadGroup group, Runnable target) { + super(group, target); + } + @Override public void run() { try { @@ -72,11 +78,18 @@ public class StopAtExit extends Thread { System.out.println("About to execute for " + timeMax + " seconds."); long count = 0; + long manualDestroyCnt = 0; + long manualTerminateCnt = 0; long start_time = System.currentTimeMillis(); while (System.currentTimeMillis() < start_time + (timeMax * 1000)) { count++; - StopAtExit thread = new StopAtExit(); + // Use my own ThreadGroup so the thread count is known and make + // it a daemon ThreadGroup so it is automatically destroyed when + // the thread is terminated. + ThreadGroup myTG = new ThreadGroup("myTG-" + count); + myTG.setDaemon(true); + StopAtExit thread = new StopAtExit(myTG, null); thread.start(); try { // Wait for the worker thread to get going. @@ -107,9 +120,52 @@ public class StopAtExit extends Thread { } catch (InterruptedException e) { throw new Error("Unexpected: " + e); } + // This stop() call happens after the join() so it should do + // nothing, but let's make sure. thread.stop(); + + if (myTG.activeCount() != 0) { + // If the ThreadGroup still has a count, then the thread + // received the async exception while in exit() so we need + // to do a manual terminate. + manualTerminateCnt++; + try { + threadTerminated(myTG, thread); + } catch (Exception e) { + throw new Error("threadTerminated() threw unexpected: " + e); + } + int activeCount = myTG.activeCount(); + if (activeCount != 0) { + throw new Error("threadTerminated() did not clean up " + + "worker thread: count=" + activeCount); + } + if (!myTG.isDestroyed()) { + throw new Error("threadTerminated() did not destroy " + + myTG.getName()); + } + } else if (!myTG.isDestroyed()) { + // If the ThreadGroup does not have a count, but is not + // yet destroyed, then the thread received the async + // exception while the thread was in the later stages of + // its threadTerminated() call so we need to do a manual + // destroy. + manualDestroyCnt++; + try { + myTG.destroy(); + } catch (Exception e) { + throw new Error("myTG.destroy() threw unexpected: " + e); + } + } } + if (manualDestroyCnt != 0) { + System.out.println("Manually destroyed ThreadGroup " + + manualDestroyCnt + " times."); + } + if (manualTerminateCnt != 0) { + System.out.println("Manually terminated Thread " + + manualTerminateCnt + " times."); + } System.out.println("Executed " + count + " loops in " + timeMax + " seconds."); @@ -120,6 +176,13 @@ public class StopAtExit extends Thread { } } + static void threadTerminated(ThreadGroup group, Thread thread) throws Exception { + // ThreadGroup.threadTerminated() is package private: + Method method = ThreadGroup.class.getDeclaredMethod("threadTerminated", Thread.class); + method.setAccessible(true); + method.invoke(group, thread); + } + public static void usage() { System.err.println("Usage: " + PROG_NAME + " [time_max]"); System.err.println("where:"); diff --git a/test/hotspot/jtreg/runtime/Thread/TestSpinPause.java b/test/hotspot/jtreg/runtime/Thread/TestSpinPause.java new file mode 100644 index 0000000000000000000000000000000000000000..7226c8ed05819acec0a97c5881d148f6f5e9132c --- /dev/null +++ b/test/hotspot/jtreg/runtime/Thread/TestSpinPause.java @@ -0,0 +1,86 @@ +/* + * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test TestSpinPause + * @summary JVM runtime can use SpinPause function for synchronized statements. + * Check different implementations of JVM SpinPause don't crash JVM. + * @bug 8278241 + * @library /test/lib + * + * @requires os.arch=="aarch64" + * + * @run main/othervm TestSpinPause + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:OnSpinWaitInst=none TestSpinPause + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:OnSpinWaitInst=nop TestSpinPause + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:OnSpinWaitInst=isb TestSpinPause + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:OnSpinWaitInst=yield TestSpinPause + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:OnSpinWaitInst=nop -XX:OnSpinWaitInstCount=10 TestSpinPause + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:OnSpinWaitInst=isb -XX:OnSpinWaitInstCount=3 TestSpinPause + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:OnSpinWaitInst=yield -XX:OnSpinWaitInstCount=3 TestSpinPause + * @run main/othervm -Xint TestSpinPause + * @run main/othervm -Xint -XX:+UnlockDiagnosticVMOptions -XX:OnSpinWaitInst=none TestSpinPause + * @run main/othervm -Xint -XX:+UnlockDiagnosticVMOptions -XX:OnSpinWaitInst=nop TestSpinPause + * @run main/othervm -Xint -XX:+UnlockDiagnosticVMOptions -XX:OnSpinWaitInst=isb TestSpinPause + * @run main/othervm -Xint -XX:+UnlockDiagnosticVMOptions -XX:OnSpinWaitInst=yield TestSpinPause + * @run main/othervm -Xint -XX:+UnlockDiagnosticVMOptions -XX:OnSpinWaitInst=nop -XX:OnSpinWaitInstCount=10 TestSpinPause + * @run main/othervm -Xint -XX:+UnlockDiagnosticVMOptions -XX:OnSpinWaitInst=isb -XX:OnSpinWaitInstCount=3 TestSpinPause + * @run main/othervm -Xint -XX:+UnlockDiagnosticVMOptions -XX:OnSpinWaitInst=yield -XX:OnSpinWaitInstCount=3 TestSpinPause + * @run main/othervm -Xcomp TestSpinPause + * @run main/othervm -Xcomp -XX:+UnlockDiagnosticVMOptions -XX:OnSpinWaitInst=none TestSpinPause + * @run main/othervm -Xcomp -XX:+UnlockDiagnosticVMOptions -XX:OnSpinWaitInst=nop TestSpinPause + * @run main/othervm -Xcomp -XX:+UnlockDiagnosticVMOptions -XX:OnSpinWaitInst=isb TestSpinPause + * @run main/othervm -Xcomp -XX:+UnlockDiagnosticVMOptions -XX:OnSpinWaitInst=yield TestSpinPause + * @run main/othervm -Xcomp -XX:+UnlockDiagnosticVMOptions -XX:OnSpinWaitInst=nop -XX:OnSpinWaitInstCount=10 TestSpinPause + * @run main/othervm -Xcomp -XX:+UnlockDiagnosticVMOptions -XX:OnSpinWaitInst=isb -XX:OnSpinWaitInstCount=3 TestSpinPause + * @run main/othervm -Xcomp -XX:+UnlockDiagnosticVMOptions -XX:OnSpinWaitInst=yield -XX:OnSpinWaitInstCount=3 TestSpinPause + */ + +public class TestSpinPause { + private Integer[] valueHolder; + + private TestSpinPause () { + valueHolder = new Integer[] {Integer.valueOf(101)}; + } + + private void getSet() { + final int iterCount = 100; + for (int i = 0; i < iterCount; ++i) { + synchronized (valueHolder) { + Integer v = valueHolder[0]; + valueHolder[0] = Integer.reverse(v); + } + } + } + + public static void main(String[] args) throws Exception { + TestSpinPause test = new TestSpinPause(); + Thread t1 = new Thread(test::getSet); + Thread t2 = new Thread(test::getSet); + t1.start(); + t2.start(); + t1.join(); + t2.join(); + System.out.println("Done: " + test.valueHolder[0]); + } +} diff --git a/test/hotspot/jtreg/runtime/cds/DeterministicDump.java b/test/hotspot/jtreg/runtime/cds/DeterministicDump.java index 9cdba1fa922073290ee6c9da8e3e60ef44f71439..6e8ccffce278cf53267693eeb3527f3666708d3e 100644 --- a/test/hotspot/jtreg/runtime/cds/DeterministicDump.java +++ b/test/hotspot/jtreg/runtime/cds/DeterministicDump.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -54,6 +54,11 @@ public class DeterministicDump { baseArgs.add("-Xmx128M"); if (Platform.is64bit()) { + if (!compressed) { + System.out.println("CDS archives with uncompressed oops are still non-deterministic"); + System.out.println("See https://bugs.openjdk.java.net/browse/JDK-8282828"); + return; + } // These options are available only on 64-bit. String sign = (compressed) ? "+" : "-"; baseArgs.add("-XX:" + sign + "UseCompressedOops"); @@ -78,9 +83,12 @@ public class DeterministicDump { static String dump(ArrayList<String> args, String... more) throws Exception { String logName = "SharedArchiveFile" + (id++); String archiveName = logName + ".jsa"; + String mapName = logName + ".map"; CDSOptions opts = (new CDSOptions()) .addPrefix("-Xlog:cds=debug") + .addPrefix("-Xlog:cds+map=trace:file=" + mapName + ":none:filesize=0") .setArchiveName(archiveName) + .addSuffix(args) .addSuffix(more); CDSTestUtils.createArchiveAndCheck(opts); diff --git a/test/hotspot/jtreg/runtime/cds/SharedArchiveFile.java b/test/hotspot/jtreg/runtime/cds/SharedArchiveFile.java index d58bc0e888d0022605afb268311501b1f510ed91..83a1ce07bfcb1e7a669e5436f4ee5544d38c4add 100644 --- a/test/hotspot/jtreg/runtime/cds/SharedArchiveFile.java +++ b/test/hotspot/jtreg/runtime/cds/SharedArchiveFile.java @@ -45,12 +45,6 @@ public class SharedArchiveFile { .setArchiveName("./SharedArchiveFile.jsa"); CDSTestUtils.createArchiveAndCheck(opts); - // -XX:+DumpSharedSpaces should behave the same as -Xshare:dump - opts = (new CDSOptions()) - .addPrefix("-XX:+DumpSharedSpaces", "-Xlog:cds") - .setArchiveName("./SharedArchiveFile.jsa"); - CDSTestUtils.createArchiveAndCheck(opts); - opts = (new CDSOptions()) .setArchiveName("./SharedArchiveFile.jsa"); CDSTestUtils.run(opts) diff --git a/test/hotspot/jtreg/runtime/cds/SharedBaseAddress.java b/test/hotspot/jtreg/runtime/cds/SharedBaseAddress.java index 761b5a05d294ec94c211e250f1b8991074afb62b..a7f31cf1a082f3f74e5db9175c76728338aac652 100644 --- a/test/hotspot/jtreg/runtime/cds/SharedBaseAddress.java +++ b/test/hotspot/jtreg/runtime/cds/SharedBaseAddress.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -70,26 +70,31 @@ import jdk.test.lib.process.OutputAnalyzer; public class SharedBaseAddress { - // shared base address test table - private static final String[] testTable = { - "1g", "8g", "64g","512g", "4t", - "32t", "128t", "0", + // shared base address test table for {32, 64}bit VM + private static final String[] testTableShared = { + "1g", "0", "1", "64k", "64M", + "0xfff80000", // archive top wraps around 32-bit address space + "0xffffffff", // archive bottom wraps around 32-bit address space -- due to align_up() + "0" // always let OS pick the base address at runtime (ASLR for CDS archive) + }; + + // shared base address test table for 64bit VM only + private static final String[] testTable64 = { + "8g", "64g","512g", "4t", + "32t", "128t", "0x800001000", // Default base address + 1 page - probably valid but unaligned to metaspace alignment, see JDK 8247522 "0xfffffffffff00000", // archive top wraps around 64-bit address space - "0xfff80000", // archive top wraps around 32-bit address space "0xffffffffffffffff", // archive bottom wraps around 64-bit address space -- due to align_up() - "0xffffffff", // archive bottom wraps around 32-bit address space -- due to align_up() "0x00007ffffff00000", // end of archive will go past the end of user space on linux/x64 - "0x500000000", // (20g) below 32g at a 4g aligned address, but cannot be expressed with a logical + "0x500000000" // (20g) below 32g at a 4g aligned address, but cannot be expressed with a logical // immediate on aarch64 (0x5_0000_0000) (see JDK-8265705) - "0", // always let OS pick the base address at runtime (ASLR for CDS archive) }; // failed pattern private static String failedPattern = "os::release_memory\\(0x[0-9a-fA-F]*,\\s[0-9]*\\)\\sfailed"; - public static void main(String[] args) throws Exception { + public static void test(String[] args, String[] testTable) throws Exception { int mid = testTable.length / 2; int start = args[0].equals("0") ? 0 : mid; int end = args[0].equals("0") ? mid : testTable.length; @@ -134,4 +139,11 @@ public class SharedBaseAddress { } } } + + public static void main(String[] args) throws Exception { + test(args, testTableShared); + if (Platform.is64bit()) { + test(args, testTable64); + } + } } diff --git a/test/hotspot/jtreg/runtime/cds/appcds/ClassListWithCustomClassNoSource.java b/test/hotspot/jtreg/runtime/cds/appcds/ClassListWithCustomClassNoSource.java new file mode 100644 index 0000000000000000000000000000000000000000..4e5c52402a0705cef38c98d3fcc6cdc680fd0076 --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/ClassListWithCustomClassNoSource.java @@ -0,0 +1,85 @@ +/* + * 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. + * + */ + +import java.io.File; +import java.net.URL; +import java.net.URLClassLoader; +import java.security.ProtectionDomain; + + +public class ClassListWithCustomClassNoSource { + private static byte[] helloBytes; + private static final String HELLO = "Hello"; + static class CL extends ClassLoader { + private ProtectionDomain pd; + public CL(String name, ClassLoader parent, ProtectionDomain protD) { + super(name, parent); + pd = protD; + } + + @Override + protected Class<?> findClass(String name) throws ClassNotFoundException { + if (pd == null) { + pd = new ProtectionDomain(null, null); + } + return defineClass(name, helloBytes, 0, helloBytes.length, pd); + } + } + + public static void main(String[] args) throws Exception { + if (args.length != 1) { + throw new RuntimeException("Invalid arg, Use 1, 2, or 3"); + } + + ClassLoader thisLoader = ClassListWithCustomClassNoSource.class.getClassLoader(); + helloBytes = thisLoader.getResourceAsStream(HELLO + ".class").readAllBytes(); + + switch(args[0]) { + case "1": + Class<?> cls1 = (new CL("HelloLoader", null, null)).loadClass(HELLO); + System.out.println(HELLO + " was successfully loaded by " + cls1.getClassLoader().getName()); + break; + case "2": + ProtectionDomain p = ClassListWithCustomClassNoSource.class.getProtectionDomain(); + Class<?> cls2 = (new CL("HelloLoader", null, p)).loadClass(HELLO); + System.out.println(HELLO + " was successfully loaded by " + cls2.getClassLoader().getName()); + break; + case "3": + URL url = ClassListWithCustomClassNoSource.class.getProtectionDomain().getCodeSource().getLocation(); + URLClassLoader urlLoader = new URLClassLoader("HelloClassLoader", new URL[] {url}, null); + Class<?> cls = urlLoader.loadClass(HELLO); + if (cls != null) { + System.out.println(HELLO + " was loaded by " + cls.getClassLoader().getName()); + if (urlLoader != cls.getClassLoader()) { + System.out.println(HELLO + " was not loaded by " + urlLoader.getName()); + } + } else { + System.out.println(HELLO + " is not loaded"); + } + break; + default: + throw new RuntimeException("Should have one argument, 1, 2 or 3"); + } + } +} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/ClassSpecializerTestApp.java b/test/hotspot/jtreg/runtime/cds/appcds/ClassSpecializerTestApp.java new file mode 100644 index 0000000000000000000000000000000000000000..7b9363e8c8f0f849719086ad5c13fb0d9a2f9039 --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/ClassSpecializerTestApp.java @@ -0,0 +1,63 @@ +/* + * 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. + * + */ + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; + +// When this class is executed, the following classes will be generated by +// java.lang.invoke.ClassSpecializer with the code source +// "_ClassSpecializer_generateConcreteSpeciesCode". +// +// - java.lang.invoke.BoundMethodHandle$Species_LFDIIL +// - java.lang.invoke.BoundMethodHandle$Species_LFDIILJ +// - java.lang.invoke.BoundMethodHandle$Species_LFDIILJD +// - ... +// +// The TestDumpClassListSource test case checks that these classes are not +// written into the classlist, as they cannot be handled by -Xshare:dump +public class ClassSpecializerTestApp { + public static void main(String args[]) throws Throwable { + + MethodHandles.Lookup lookup = MethodHandles.lookup(); + MethodType mt = MethodType.methodType(void.class, float.class, double.class, int.class, + boolean.class, Object.class, long.class, double.class); + MethodHandle mh = lookup.findStatic(ClassSpecializerTestApp.class, "callme", mt); + invoke(mh, 4.0f, 5.0, 6, true, null, 7L, 8.0); + } + + private static Object invoke(MethodHandle mh, Object ... args) throws Throwable { + try { + for (Object o : args) { + mh = MethodHandles.insertArguments(mh, 0, o); + } + return mh.invoke(); + } catch (Throwable t) { + System.out.println("Failed to find, link and/or invoke " + mh.toString() + ": " + t.getMessage()); + throw t; + } + } + + private static void callme(float f, double d, int i, boolean b, Object o, long l, double d2) {} +} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/CommandLineFlagCombo.java b/test/hotspot/jtreg/runtime/cds/appcds/CommandLineFlagCombo.java index 045d286115b80805a5a42c783ad72befd4f3aef7..b0f18cd453e0c56612f4aef6f8bcfc9ea24e9ad5 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/CommandLineFlagCombo.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/CommandLineFlagCombo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -38,8 +38,11 @@ * @run main/othervm/timeout=240 -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. CommandLineFlagCombo */ +import java.io.File; + import jdk.test.lib.BuildHelper; import jdk.test.lib.Platform; +import jdk.test.lib.process.ProcessTools; import jdk.test.lib.process.OutputAnalyzer; import sun.hotspot.code.Compiler; @@ -47,6 +50,7 @@ import sun.hotspot.WhiteBox; public class CommandLineFlagCombo { + private static String HELLO_WORLD = "Hello World"; // shared base address test table private static final String[] testTable = { "-XX:+UseG1GC", "-XX:+UseSerialGC", "-XX:+UseParallelGC", @@ -83,7 +87,7 @@ public class CommandLineFlagCombo { if ((TestCommon.isDynamicArchive() && !testEntry.contains("ObjectAlignmentInBytes")) || !TestCommon.isDynamicArchive()) { OutputAnalyzer execOutput = TestCommon.exec(appJar, testEntry, "Hello"); - TestCommon.checkExec(execOutput, "Hello World"); + TestCommon.checkExec(execOutput, HELLO_WORLD); } } @@ -105,8 +109,10 @@ public class CommandLineFlagCombo { TestCommon.checkDump(dumpOutput, "Loading classes to share"); OutputAnalyzer execOutput = TestCommon.exec(appJar, run_g1Flag, run_serialFlag, "Hello"); - TestCommon.checkExec(execOutput, "Hello World"); + TestCommon.checkExec(execOutput, HELLO_WORLD); } + + testExtraCase(appJar, classList); } private static boolean skipTestCase(String testEntry) throws Exception { @@ -128,4 +134,41 @@ public class CommandLineFlagCombo { } return false; } + + // { -Xshare:dump, -XX:ArchiveClassesAtExit} x { -XX:DumpLoadedClassList } + private static void testExtraCase(String jarFile, String[] classList) throws Exception { + // 1. -Xshare:dump -XX:-XX:DumpLoadedClassFile + String dumpedListName = "tmpClassList.list"; + File listFile = new File(dumpedListName); + if (listFile.exists()) { + listFile.delete(); + } + OutputAnalyzer dumpOutput = TestCommon.dump(jarFile, classList, "-XX:DumpLoadedClassList=" + dumpedListName); + TestCommon.checkDump(dumpOutput, "Loading classes to share"); + if (!listFile.exists()) { + throw new RuntimeException("ClassList file " + dumpedListName + " should be created"); + } + + // 2. -XX:ArchiveClassesAtExit -XX:DumpLoadedClassFile + String dynName = "tmpDyn.jsa"; + File dynFile = new File(dynName); + if (dynFile.exists()) { + dynFile.delete(); + } + if (listFile.exists()) { + listFile.delete(); + } + String[] args = new String[] { + "-cp", jarFile, "-XX:ArchiveClassesAtExit=" + dynName, "-XX:DumpLoadedClassList=" + dumpedListName, "Hello"}; + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(args); + OutputAnalyzer output = TestCommon.executeAndLog(pb, "combo"); + output.shouldHaveExitValue(0) + .shouldContain(HELLO_WORLD); + if (!dynFile.exists()) { + throw new RuntimeException("Dynamic archive file " + dynName + " should be created"); + } + if (!listFile.exists()) { + throw new RuntimeException("ClassList file " + dumpedListName + " should be created"); + } + } } diff --git a/test/hotspot/jtreg/runtime/cds/appcds/DumpClassListWithLF.java b/test/hotspot/jtreg/runtime/cds/appcds/DumpClassListWithLF.java index a0a898989e1aad32d97bff58532b87e70ee6c300..b0851f46e9cbfa1e3940c8e8cfb7bb278a8f2f4b 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/DumpClassListWithLF.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/DumpClassListWithLF.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -33,7 +33,7 @@ */ public class DumpClassListWithLF extends ClassListFormatBase { - static final String REPLACE_OK = "Replaced class java/lang/invoke/DirectMethodHandle$Holder"; + static final String REPLACE_OK = "Regenerated class java/lang/invoke/DirectMethodHandle$Holder"; public static void main(String[] args) throws Throwable { String appJar = JarBuilder.getOrCreateHelloJar(); diff --git a/test/hotspot/jtreg/runtime/cds/appcds/DumpingWithNoCoops.java b/test/hotspot/jtreg/runtime/cds/appcds/DumpingWithNoCoops.java new file mode 100644 index 0000000000000000000000000000000000000000..93f37db692e6fde64be3bac547c677d528878a16 --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/DumpingWithNoCoops.java @@ -0,0 +1,129 @@ +/* + * 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. + * + */ + +/* + * @test + * @bug 8255495 + * @summary Test CDS with UseCompressedOops disable with various heap sizes. + * @requires vm.cds.write.archived.java.heap + * @requires vm.gc.G1 + * @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds + * @compile test-classes/Hello.java + * @run driver DumpingWithNoCoops + */ + +import java.util.ArrayList; +import java.util.List; + +import jdk.test.lib.process.OutputAnalyzer; + +public class DumpingWithNoCoops { + static class HeapArgs { + int initialSize, minSize, maxSize; + HeapArgs(int initial, int min, int max) { + initialSize = initial; + minSize = min; + maxSize = max; + } + String heapArgsString(HeapArgs ha) { + String heapArgs = ""; + if (ha.initialSize > 0) { + heapArgs += "-XX:InitialHeapSize=" + ha.initialSize + "g"; + } + if (ha.minSize > 0) { + if (heapArgs.length() > 0) { + heapArgs += " "; + } + heapArgs += "-XX:MinHeapSize=" + ha.minSize + "g"; + } + if (ha.maxSize > 0) { + if (heapArgs.length() > 0) { + heapArgs += " "; + } + heapArgs += "-XX:MaxHeapSize=" + ha.maxSize + "g"; + } + return heapArgs; + } + } + + static HeapArgs[] heapArgsCases = { + // InitialHeapSize, MinHeapSize, MaxHeapSize + // all sizes are in the unit of GB + // size of 0 means don't set the heap size + new HeapArgs( 0, 0, 0), + new HeapArgs( 5, 3, 5), + new HeapArgs( 3, 3, 5), + new HeapArgs( 5, 5, 5), + new HeapArgs( 2, 1, 33), + }; + + static void checkExpectedMessages(HeapArgs ha, OutputAnalyzer output) throws Exception { + final int DUMPTIME_MAX_HEAP = 4; // 4 GB + if (ha.minSize > DUMPTIME_MAX_HEAP) { + output.shouldContain("Setting MinHeapSize to 4G for CDS dumping"); + } + if (ha.initialSize > DUMPTIME_MAX_HEAP) { + output.shouldContain("Setting InitialHeapSize to 4G for CDS dumping"); + } + if (ha.maxSize > DUMPTIME_MAX_HEAP) { + output.shouldContain("Setting MaxHeapSize to 4G for CDS dumping"); + } + } + + public static void main(String[] args) throws Exception { + final String noCoops = "-XX:-UseCompressedOops"; + final String logArg = "-Xlog:gc+heap=trace,cds=debug"; + JarBuilder.getOrCreateHelloJar(); + String appJar = TestCommon.getTestJar("hello.jar"); + String appClasses[] = TestCommon.list("Hello"); + + for (HeapArgs ha : heapArgsCases) { + String heapArg = ha.heapArgsString(ha); + List<String> dumptimeArgs = new ArrayList<String>(); + // UseCompressedOops is ergonomically disabled for MaxHeapSize > 32g. + if (ha.maxSize < 32) { + dumptimeArgs.add(noCoops); + } + dumptimeArgs.add(logArg); + OutputAnalyzer output; + if (heapArg.length() == 0) { + System.out.println("\n Test without heap args\n"); + output = TestCommon.dump(appJar, appClasses, dumptimeArgs.toArray(new String[0])); + } else { + System.out.println("\n Test with heap args: " + heapArg + "\n"); + String[] heapSizes = heapArg.split(" "); + for (String heapSize : heapSizes) { + dumptimeArgs.add(heapSize); + } + output = TestCommon.dump(appJar, appClasses, dumptimeArgs.toArray(new String[0])); + checkExpectedMessages(ha, output); + } + + TestCommon.checkDump(output); + TestCommon.run("-cp", appJar, + logArg, "-Xlog:class+load", noCoops, "Hello") + .assertNormalExit("Hello source: shared objects file"); + } + } +} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/LambdaWithJavaAgent.java b/test/hotspot/jtreg/runtime/cds/appcds/LambdaWithJavaAgent.java new file mode 100644 index 0000000000000000000000000000000000000000..955c07ac7a6c7ca0c235d3b2ff5083f2fa3b283a --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/LambdaWithJavaAgent.java @@ -0,0 +1,95 @@ +/* + * 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. + * + */ + +/* + * @test + * @bug 8276126 + * @summary Test static dumping with java agent transforming a class loaded + * by the boot class loader. + * @requires vm.cds.write.archived.java.heap + * @requires vm.jvmti + * @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds/test-classes + * @compile test-classes/Hello.java + * @compile test-classes/TransformBootClass.java + * @run driver LambdaWithJavaAgent + */ + +import jdk.test.lib.cds.CDSOptions; +import jdk.test.lib.cds.CDSTestUtils; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.helpers.ClassFileInstaller; + +public class LambdaWithJavaAgent { + + public static String agentClasses[] = { + TransformBootClass.class.getName(), + }; + + public static void main(String[] args) throws Exception { + String mainClass = Hello.class.getName(); + String namePrefix = "lambda-with-java-agent"; + JarBuilder.build(namePrefix, mainClass); + + String appJar = TestCommon.getTestJar(namePrefix + ".jar"); + String classList = namePrefix + ".list"; + String archiveName = namePrefix + ".jsa"; + + String agentJar = + ClassFileInstaller.writeJar("TransformBootClass.jar", + ClassFileInstaller.Manifest.fromSourceFile("test-classes/TransformBootClass.mf"), + agentClasses); + String useJavaAgent = "-javaagent:" + agentJar + "=jdk/internal/math/FDBigInteger"; + + // dump class list + CDSTestUtils.dumpClassList(classList, "-cp", appJar, mainClass); + + // create archive with the class list + CDSOptions opts = (new CDSOptions()) + .addPrefix("-XX:ExtraSharedClassListFile=" + classList, + "-cp", appJar, + "-XX:+UnlockDiagnosticVMOptions", + "-XX:+AllowArchivingWithJavaAgent", + useJavaAgent, + "-Xlog:class+load,cds+class=debug,cds") + .setArchiveName(archiveName); + OutputAnalyzer output = CDSTestUtils.createArchiveAndCheck(opts); + output.shouldContain("CDS heap objects cannot be written because class jdk.internal.math.FDBigInteger maybe modified by ClassFileLoadHook") + .shouldContain("Skipping jdk/internal/math/FDBigInteger: Unsupported location") + .shouldMatch(".class.load.*jdk.internal.math.FDBigInteger.*source.*modules"); + + // run with archive + CDSOptions runOpts = (new CDSOptions()) + .addPrefix("-cp", appJar, "-Xlog:class+load,cds=debug", + "-XX:+UnlockDiagnosticVMOptions", + "-XX:+AllowArchivingWithJavaAgent", + useJavaAgent) + .setArchiveName(archiveName) + .setUseVersion(false) + .addSuffix(mainClass); + output = CDSTestUtils.runWithArchive(runOpts); + TestCommon.checkExecReturn(output, 0, true, + "Hello source: shared objects file"); + } +} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/MoveJDKTest.java b/test/hotspot/jtreg/runtime/cds/appcds/MoveJDKTest.java index c5ad8e53873a0e25c8f220b8c29e2b2136e00fb9..b127fec860461d7adb123b915cfe6b3faf62956b 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/MoveJDKTest.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/MoveJDKTest.java @@ -47,37 +47,39 @@ public class MoveJDKTest { public static void main(String[] args) throws Exception { String java_home_src = System.getProperty("java.home"); String java_home_dst = CDSTestUtils.getOutputDir() + File.separator + "moved_jdk"; + String homeJava = java_home_src + File.separator + "bin" + File.separator + "java"; + String dstJava = java_home_dst + File.separator + "bin" + File.separator + "java"; TestCommon.startNewArchiveName(); String jsaFile = TestCommon.getCurrentArchiveName(); String jsaOpt = "-XX:SharedArchiveFile=" + jsaFile; { - ProcessBuilder pb = makeBuilder(java_home_src + "/bin/java", "-Xshare:dump", jsaOpt); + ProcessBuilder pb = CDSTestUtils.makeBuilder(homeJava, "-Xshare:dump", jsaOpt); TestCommon.executeAndLog(pb, "dump") .shouldHaveExitValue(0); } { - ProcessBuilder pb = makeBuilder(java_home_src + "/bin/java", - "-Xshare:auto", - jsaOpt, - "-Xlog:class+path=info", - "-version"); + ProcessBuilder pb = CDSTestUtils.makeBuilder(homeJava, + "-Xshare:auto", + jsaOpt, + "-Xlog:class+path=info", + "-version"); OutputAnalyzer out = TestCommon.executeAndLog(pb, "exec-src"); out.shouldHaveExitValue(0); out.shouldNotContain("shared class paths mismatch"); out.shouldNotContain("BOOT classpath mismatch"); } - clone(new File(java_home_src), new File(java_home_dst)); + CDSTestUtils.clone(new File(java_home_src), new File(java_home_dst)); System.out.println("============== Cloned JDK at " + java_home_dst); // Test runtime with cloned JDK { - ProcessBuilder pb = makeBuilder(java_home_dst + "/bin/java", - "-Xshare:auto", - jsaOpt, - "-Xlog:class+path=info", - "-version"); + ProcessBuilder pb = CDSTestUtils.makeBuilder(dstJava, + "-Xshare:auto", + jsaOpt, + "-Xlog:class+path=info", + "-version"); OutputAnalyzer out = TestCommon.executeAndLog(pb, "exec-dst"); out.shouldHaveExitValue(0); out.shouldNotContain("shared class paths mismatch"); @@ -89,21 +91,21 @@ public class MoveJDKTest { String fake_modules = copyFakeModulesFromHelloJar(); String dumptimeBootAppendOpt = "-Xbootclasspath/a:" + fake_modules; { - ProcessBuilder pb = makeBuilder(java_home_src + "/bin/java", - "-Xshare:dump", - dumptimeBootAppendOpt, - jsaOpt); + ProcessBuilder pb = CDSTestUtils.makeBuilder(homeJava, + "-Xshare:dump", + dumptimeBootAppendOpt, + jsaOpt); TestCommon.executeAndLog(pb, "dump") .shouldHaveExitValue(0); } { String runtimeBootAppendOpt = dumptimeBootAppendOpt + System.getProperty("path.separator") + helloJar; - ProcessBuilder pb = makeBuilder(java_home_dst + "/bin/java", - "-Xshare:auto", - runtimeBootAppendOpt, - jsaOpt, - "-Xlog:class+path=info", - "-version"); + ProcessBuilder pb = CDSTestUtils.makeBuilder(dstJava, + "-Xshare:auto", + runtimeBootAppendOpt, + jsaOpt, + "-Xlog:class+path=info", + "-version"); OutputAnalyzer out = TestCommon.executeAndLog(pb, "exec-dst"); out.shouldHaveExitValue(0); out.shouldNotContain("shared class paths mismatch"); @@ -111,78 +113,17 @@ public class MoveJDKTest { } // Test with no modules image in the <java home>/lib directory - renameModulesFile(java_home_dst); + String locDir = java_home_dst + File.separator + "lib"; + CDSTestUtils.rename(new File(locDir + File.separator + "modules"), + new File(locDir + File.separator + "orig-modules")); { - ProcessBuilder pb = makeBuilder(java_home_dst + "/bin/java", - "-version"); + ProcessBuilder pb = CDSTestUtils.makeBuilder(dstJava, "-version"); OutputAnalyzer out = TestCommon.executeAndLog(pb, "exec-missing-modules"); out.shouldHaveExitValue(1); out.shouldContain("Failed setting boot class path."); } } - // Do a cheap clone of the JDK. Most files can be sym-linked. However, $JAVA_HOME/bin/java and $JAVA_HOME/lib/.../libjvm.so" - // must be copied, because the java.home property is derived from the canonicalized paths of these 2 files. - static void clone(File src, File dst) throws Exception { - if (dst.exists()) { - if (!dst.isDirectory()) { - throw new RuntimeException("Not a directory :" + dst); - } - } else { - if (!dst.mkdir()) { - throw new RuntimeException("Cannot create directory: " + dst); - } - } - final String jvmLib = System.mapLibraryName("jvm"); - for (String child : src.list()) { - if (child.equals(".") || child.equals("..")) { - continue; - } - - File child_src = new File(src, child); - File child_dst = new File(dst, child); - if (child_dst.exists()) { - throw new RuntimeException("Already exists: " + child_dst); - } - if (child_src.isFile()) { - if (child.equals(jvmLib) || child.equals("java")) { - Files.copy(child_src.toPath(), /* copy data to -> */ child_dst.toPath()); - } else { - Files.createSymbolicLink(child_dst.toPath(), /* link to -> */ child_src.toPath()); - } - } else { - clone(child_src, child_dst); - } - } - } - - static void renameModulesFile(String javaHome) throws Exception { - String modulesDir = javaHome + File.separator + "lib"; - File origModules = new File(modulesDir, "modules"); - if (!origModules.exists()) { - throw new RuntimeException("modules file not found"); - } - - File renamedModules = new File(modulesDir, "orig_modules"); - if (renamedModules.exists()) { - throw new RuntimeException("found orig_modules unexpectedly"); - } - - boolean success = origModules.renameTo(renamedModules); - if (!success) { - throw new RuntimeException("rename modules file failed"); - } - } - - static ProcessBuilder makeBuilder(String... args) throws Exception { - System.out.print("["); - for (String s : args) { - System.out.print(" " + s); - } - System.out.println(" ]"); - return new ProcessBuilder(args); - } - private static String copyFakeModulesFromHelloJar() throws Exception { String outDir = CDSTestUtils.getOutputDir(); String newFile = "hello.modules"; diff --git a/test/hotspot/jtreg/runtime/cds/appcds/NonExistClasspath.java b/test/hotspot/jtreg/runtime/cds/appcds/NonExistClasspath.java index a08f1c5ff150aebc791fb91b34eff5b88e7f8f33..7f2af4bdcab5e60ebc04239ef88bf647cb5cfeb9 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/NonExistClasspath.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/NonExistClasspath.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -40,6 +40,13 @@ import jdk.test.lib.cds.CDSTestUtils; import jdk.test.lib.process.OutputAnalyzer; public class NonExistClasspath { + static final String outDir = CDSTestUtils.getOutputDir(); + static final String newFile = "non-exist.jar"; + static final String nonExistPath = outDir + File.separator + newFile; + static final String emptyJarPath = outDir + File.separator + "empty.jar"; + static final String errorMessage1 = "Unable to use shared archive"; + static final String errorMessage2 = "shared class paths mismatch"; + public static void main(String[] args) throws Exception { String appJar = JarBuilder.getOrCreateHelloJar(); doTest(appJar, false); @@ -47,13 +54,7 @@ public class NonExistClasspath { } static void doTest(String appJar, boolean bootcp) throws Exception { - String outDir = CDSTestUtils.getOutputDir(); - String newFile = "non-exist.jar"; - String nonExistPath = outDir + File.separator + newFile; - final String errorMessage1 = "Unable to use shared archive"; - final String errorMessage2 = "shared class paths mismatch"; final String errorMessage3 = (bootcp ? "BOOT" : "APP") + " classpath mismatch"; - (new File(nonExistPath)).delete(); String classPath = nonExistPath + File.pathSeparator + appJar; @@ -100,6 +101,81 @@ public class NonExistClasspath { "-Xlog:class+path=trace", "Hello")) .assertAbnormalExit(errorMessage1, errorMessage2, errorMessage3); + + if (bootcp) { + doMoreBCPTests(appJar, errorMessage3); + } + } + + static void doMoreBCPTests(String appJar, String errorMessage3) throws Exception { + + // Dump an archive with non-existent boot class path. + (new File(nonExistPath)).delete(); + TestCommon.testDump("foobar", TestCommon.list("Hello"), make_args(true, nonExistPath, "-cp", appJar)); + + // Run with non-existent boot class path, test should pass. + TestCommon.run(make_args(true, + nonExistPath, + "-cp", appJar, + "-Xlog:class+path=trace", + "Hello")) + .assertNormalExit(); + + // Run with existent boot class path, test should fail. + TestCommon.run(make_args(true, + appJar, + "-cp", appJar, + "-Xlog:class+path=trace", + "Hello")) + .assertAbnormalExit(errorMessage1, errorMessage2, errorMessage3); + + // Dump an archive with existent boot class path. + TestCommon.testDump("foobar", TestCommon.list("Hello"), make_args(true, appJar)); + + // Run with non-existent boot class path, test should fail. + TestCommon.run(make_args(true, + nonExistPath, + "-Xlog:class+path=trace", + "Hello")) + .assertAbnormalExit(errorMessage1, errorMessage2, errorMessage3); + + // Run with existent boot class path, test should pass. + TestCommon.run(make_args(true, + appJar, + "-Xlog:class+path=trace", + "Hello")) + .assertNormalExit(); + + // Test with empty jar file. + (new File(emptyJarPath)).delete(); + (new File(emptyJarPath)).createNewFile(); + + // Dump an archive with an empty jar in the boot class path. + TestCommon.testDump("foobar", TestCommon.list("Hello"), make_args(true, emptyJarPath, "-cp", appJar)); + + // Run with an empty jar in boot class path, test should pass. + TestCommon.run(make_args(true, + emptyJarPath, + "-cp", appJar, + "-Xlog:class+path=trace", + "Hello")) + .assertNormalExit(); + + // Run with non-existent boot class path, test should pass. + TestCommon.run(make_args(true, + nonExistPath, + "-cp", appJar, + "-Xlog:class+path=trace", + "Hello")) + .assertNormalExit(); + + // Run with existent boot class path, test should fail. + TestCommon.run(make_args(true, + appJar, + "-cp", appJar, + "-Xlog:class+path=trace", + "Hello")) + .assertAbnormalExit(errorMessage1, errorMessage2, errorMessage3); } static String[] make_args(boolean bootcp, String cp, String... suffix) { diff --git a/test/hotspot/jtreg/runtime/cds/appcds/PrintSharedArchiveAndExit.java b/test/hotspot/jtreg/runtime/cds/appcds/PrintSharedArchiveAndExit.java index fc34e932dc450b50c2810b61c370cda806d83865..9a74dcb0d3b39c5469dedaf0eabf3cddbf1fc3c3 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/PrintSharedArchiveAndExit.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/PrintSharedArchiveAndExit.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -87,16 +87,16 @@ public class PrintSharedArchiveAndExit { TestCommon.run("-cp", cp, "-XX:+PrintSharedArchiveAndExit", "Hello") .ifNoMappingFailure(output -> check(output, 0, true, lastCheckMsg)); - log("Execution with simple errors -- with 'simple' errors like missing or modified\n" + - "JAR files, the VM should try to continue to print the remaining information.\n" + - "Use an invalid Boot CP -- all the JAR paths should be checked"); + log("Non-existent boot cp should be ignored, test should pass."); TestCommon.run( "-cp", cp, "-Xbootclasspath/a:foo.jar", "-XX:+PrintSharedArchiveAndExit") - .ifNoMappingFailure(output -> check(output, 1, true, lastCheckMsg, "[BOOT classpath mismatch, ")); + .ifNoMappingFailure(output -> check(output, 0, true, lastCheckMsg)); - log("Use an App CP shorter than the one at dump time -- all the JAR paths should be checked"); + log("Execution with simple errors -- with 'simple' errors like missing or modified\n" + + "JAR files, the VM should try to continue to print the remaining information.\n" + + "Use an App CP shorter than the one at dump time -- all the JAR paths should be checked"); TestCommon.run( "-cp", ".", "-XX:+PrintSharedArchiveAndExit") diff --git a/test/hotspot/jtreg/runtime/cds/appcds/SharedArchiveConsistency.java b/test/hotspot/jtreg/runtime/cds/appcds/SharedArchiveConsistency.java index 57086f343b375d14321bafde983d485c22060011..cec5b66a12ff8ecf98ee73a2accb69e29bb3b49f 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/SharedArchiveConsistency.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/SharedArchiveConsistency.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -43,6 +43,8 @@ public class SharedArchiveConsistency { public static boolean shareAuto; // true == -Xshare:auto // false == -Xshare:on + private static int genericHeaderMinVersion; // minimum supported CDS version + private static int currentCDSArchiveVersion; // current CDS version in java process // The following should be consistent with the enum in the C++ MetaspaceShared class public static String[] shared_region_name = { "rw", // ReadWrite @@ -78,6 +80,14 @@ public class SharedArchiveConsistency { OutputAnalyzer output = shareAuto ? TestCommon.execAuto(execArgs) : TestCommon.execCommon(execArgs); String stdtxt = output.getOutput(); System.out.println("Note: this test may fail in very rare occasions due to CRC32 checksum collision"); + for (String opt : execArgs) { + if (opt.equals("-XX:+VerifySharedSpaces")) { + // If VerifySharedSpaces is enabled, the VM should never crash even if the archive + // is corrupted (unless if we are so lucky that the corrupted archive ends up + // have the same checksum as recoreded in the header) + output.shouldNotContain("A fatal error has been detected by the Java Runtime Environment"); + } + } for (String message : matchMessages) { if (stdtxt.contains(message)) { // match any to return @@ -104,6 +114,9 @@ public class SharedArchiveConsistency { throw new RuntimeException("Arg must be 'on' or 'auto'"); } shareAuto = args[0].equals("auto"); + genericHeaderMinVersion = CDSArchiveUtils.getGenericHeaderMinVersion(); + currentCDSArchiveVersion = CDSArchiveUtils.getCurrentCDSArchiveVersion(); + String jarFile = JarBuilder.getOrCreateHelloJar(); // dump (appcds.jsa created) @@ -112,7 +125,8 @@ public class SharedArchiveConsistency { // test, should pass System.out.println("1. Normal, should pass but may fail\n"); - String[] execArgs = {"-Xlog:cds=debug", "-cp", jarFile, "Hello"}; + // disable VerifySharedSpaces, it may be turned on by jtreg args + String[] execArgs = {"-Xlog:cds=debug", "-XX:-VerifySharedSpaces", "-cp", jarFile, "Hello"}; // tests that corrupt contents of the archive need to run with // VerifySharedSpaces enabled to detect inconsistencies String[] verifyExecArgs = {"-Xlog:cds", "-XX:+VerifySharedSpaces", "-cp", jarFile, "Hello"}; @@ -157,7 +171,7 @@ public class SharedArchiveConsistency { } // modify _magic, test should fail - System.out.println("\n2c. Corrupt _magic, should fail\n"); + System.out.println("\n2b. Corrupt _magic, should fail\n"); String modMagic = startNewArchive("modify-magic"); copiedJsa = CDSArchiveUtils.copyArchiveFile(orgJsaFile, modMagic); CDSArchiveUtils.modifyHeaderIntField(copiedJsa, CDSArchiveUtils.offsetMagic(), -1); @@ -169,12 +183,24 @@ public class SharedArchiveConsistency { } // modify _version, test should fail - System.out.println("\n2d. Corrupt _version, should fail\n"); + System.out.println("\n2c. Corrupt _version, should fail\n"); String modVersion = startNewArchive("modify-version"); + int version = currentCDSArchiveVersion + 1; copiedJsa = CDSArchiveUtils.copyArchiveFile(orgJsaFile, modVersion); - CDSArchiveUtils.modifyHeaderIntField(copiedJsa, CDSArchiveUtils.offsetVersion(), 0x00000000); + CDSArchiveUtils.modifyHeaderIntField(copiedJsa, CDSArchiveUtils.offsetVersion(), version); + output = shareAuto ? TestCommon.execAuto(execArgs) : TestCommon.execCommon(execArgs); + output.shouldContain("The shared archive file version " + version + " does not match the required version " + currentCDSArchiveVersion); + if (shareAuto) { + output.shouldContain(HELLO_WORLD); + } + + System.out.println("\n2d. Corrupt _version, should fail\n"); + String modVersion2 = startNewArchive("modify-version2"); + copiedJsa = CDSArchiveUtils.copyArchiveFile(orgJsaFile, modVersion2); + version = genericHeaderMinVersion - 1; + CDSArchiveUtils.modifyHeaderIntField(copiedJsa, CDSArchiveUtils.offsetVersion(), version); output = shareAuto ? TestCommon.execAuto(execArgs) : TestCommon.execCommon(execArgs); - output.shouldContain("The shared archive file has the wrong version"); + output.shouldContain("Cannot handle shared archive file version " + version + ". Must be at least " + genericHeaderMinVersion); output.shouldNotContain("Checksum verification failed"); if (shareAuto) { output.shouldContain(HELLO_WORLD); diff --git a/test/hotspot/jtreg/runtime/cds/appcds/SharedBaseAddress.java b/test/hotspot/jtreg/runtime/cds/appcds/SharedBaseAddress.java index 5d981c017944c05890d6d33951b77caafd6fe415..2220fc52baabaea7e8bf0258f8608221a7cef3f9 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/SharedBaseAddress.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/SharedBaseAddress.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -33,19 +33,24 @@ * @run main/timeout=240 SharedBaseAddress */ +import jdk.test.lib.Platform; import jdk.test.lib.process.OutputAnalyzer; public class SharedBaseAddress { - // shared base address test table - private static final String[] testTable = { - "1g", "8g", "64g","512g", "4t", - "32t", "128t", "0", - "1", "64k", "64M", "320g", + // shared base address test table for {32, 64}bit VM + private static final String[] testTableShared = { + "1g", "0", "1", "64k", "64M" + }; + + // shared base address test table for 64bit VM only + private static final String[] testTable64 = { + "8g", "64g","512g", "4t", + "32t", "128t", "320g", "0x800001000" // Default base address + 1 page - probably valid but unaligned to metaspace alignment, see JDK 8247522 }; - public static void main(String[] args) throws Exception { + public static void test(String[] testTable) throws Exception { String appJar = JarBuilder.getOrCreateHelloJar(); for (String testEntry : testTable) { @@ -62,4 +67,11 @@ public class SharedBaseAddress { TestCommon.checkExec(execOutput, "Hello World"); } } + + public static void main(String[] args) throws Exception { + test(testTableShared); + if (Platform.is64bit()) { + test(testTable64); + } + } } diff --git a/test/hotspot/jtreg/runtime/cds/appcds/TestCommon.java b/test/hotspot/jtreg/runtime/cds/appcds/TestCommon.java index a90512f73fba7fafaecf61b17ad36b469612db43..55c10299ed6a437f454b0925dea2d8d643017d70 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/TestCommon.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/TestCommon.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -153,6 +153,19 @@ public class TestCommon extends CDSTestUtils { return out; } + public static OutputAnalyzer dumpBaseArchive(String baseArchiveName, String classList[], String ... cmdLineSuffix) + throws Exception + { + CDSOptions opts = new CDSOptions(); + opts.setArchiveName(baseArchiveName); + opts.setClassList(classList); + opts.addSuffix(cmdLineSuffix); + opts.addSuffix("-Djava.class.path="); + OutputAnalyzer out = CDSTestUtils.createArchive(opts); + CDSTestUtils.checkBaseDump(out); + return out; + } + // Create AppCDS archive using most common args - convenience method public static OutputAnalyzer createArchive(String appJar, String classList[], String... suffix) throws Exception { @@ -453,7 +466,7 @@ public class TestCommon extends CDSTestUtils { public static Result runWithoutCDS(String... suffix) throws Exception { AppCDSOptions opts = (new AppCDSOptions()); - opts.addSuffix(suffix).setXShareMode("off");; + opts.addSuffix(suffix).setXShareMode("off"); return new Result(opts, runWithArchive(opts)); } diff --git a/test/hotspot/jtreg/runtime/cds/appcds/TestDumpClassListSource.java b/test/hotspot/jtreg/runtime/cds/appcds/TestDumpClassListSource.java new file mode 100644 index 0000000000000000000000000000000000000000..647e44bc455760eece80dbb057c61ff27555e823 --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/TestDumpClassListSource.java @@ -0,0 +1,234 @@ +/* + * 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. + * + */ + +/* + * @test + * @key randomness + * @summary test dynamic dump meanwhile output loaded class list + * @bug 8279009 8275084 + * @requires vm.cds + * @requires vm.cds.custom.loaders + * @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds + * @compile test-classes/Hello.java ClassSpecializerTestApp.java ClassListWithCustomClassNoSource.java + * @run main/othervm TestDumpClassListSource + */ + +/* Test two senarios: + * 1. ClassSpecializerTestApp.java: + * Test case for bug 8275084, make sure the filtering of source class to + * dumped class list. + * 2. ClassListWithCustomClassNoSource: test custom class loader + * 2.1 class loaded without source. + * 2.2 class loaded with ProtectionDomain set as same as main class. + * 2.3 class loaded by custom loader from shared space. + */ + +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.File; + +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.cds.CDSTestUtils; + +public class TestDumpClassListSource { + private static final boolean EXPECT_MATCH = true; + private static final boolean EXPECT_NOMATCH = !EXPECT_MATCH; + + private static void checkMatch(String file, String regexp, boolean expectMatch, String exceptionMessage) throws Exception { + String listData = new String(Files.readAllBytes(Paths.get(file))); + Pattern pattern = Pattern.compile(regexp, Pattern.MULTILINE); + Matcher matcher = pattern.matcher(listData); + boolean found = matcher.find(); + if (expectMatch) { + if (!found) { + throw new RuntimeException(exceptionMessage); + } + } else { + if (found) { + throw new RuntimeException(exceptionMessage); + } + } + } + + static final String mainInvokeClass = "ClassSpecializerTestApp"; + static final String mainCutomClass = "ClassListWithCustomClassNoSource"; + static final String sourceTarget = "_ClassSpecializer_generateConcreteSpeciesCode"; + + private static void checkFileExistence(String type, File file) throws Exception { + if (!file.exists()) { + throw new RuntimeException(type + " file " + file.getName() + " should be created"); + } + } + + public static void main(String[] args) throws Exception { + String listFileName = "test-classlist.list"; + String archiveName = "test-dynamic.jsa"; + String jarFile = JarBuilder.build("test-hello", "ClassSpecializerTestApp", "ClassListWithCustomClassNoSource", + "ClassListWithCustomClassNoSource$CL", "Hello"); + // 1. Invoke lambda + File fileList = new File(listFileName); + if (fileList.exists()) { + fileList.delete(); + } + File fileArchive = new File(archiveName); + if (fileArchive.exists()) { + fileArchive.delete(); + } + String[] launchArgs = { + "-Xshare:auto", + "-XX:DumpLoadedClassList=" + listFileName, + "-XX:ArchiveClassesAtExit=" + archiveName, + "-Xlog:cds", + "-Xlog:cds+lambda", + "-cp", + jarFile, + mainInvokeClass}; + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(launchArgs); + OutputAnalyzer output = TestCommon.executeAndLog(pb, "invoke-class"); + + checkFileExistence("Archive", fileArchive); + checkFileExistence("ClassList", fileList); + + output.shouldHaveExitValue(0); + checkMatch(listFileName, sourceTarget, EXPECT_NOMATCH, "Failed to filter " + sourceTarget + " in class list file"); + + fileArchive.delete(); + fileList.delete(); + + // 2. Custom loaded class + // 2.1 test in memory class generation without source + launchArgs = new String[] { + "-Xshare:auto", + "-XX:DumpLoadedClassList=" + listFileName, + "-XX:ArchiveClassesAtExit=" + archiveName, + "-Xlog:cds", + "-Xlog:cds+lambda", + "-Xlog:class+path=info", + "-cp", + jarFile, + mainCutomClass, + "1"}; + pb = ProcessTools.createJavaProcessBuilder(launchArgs); + output = TestCommon.executeAndLog(pb, "custom-nosource"); + + checkFileExistence("Archive", fileArchive); + checkFileExistence("ClassList", fileList); + + output.shouldHaveExitValue(0); + checkMatch(listFileName, sourceTarget, EXPECT_NOMATCH, "Failed to filter " + sourceTarget + " in class list file"); + checkMatch(listFileName, "Hello", EXPECT_NOMATCH, "Hello should not be logged in class list file"); + + fileArchive.delete(); + fileList.delete(); + + // 2.2 test in memory class with ProtectionDomain as main class. + // "Hello" will be printed in list file and its source set as main class. + launchArgs = new String[] { + "-Xshare:auto", + "-XX:DumpLoadedClassList=" + listFileName, + "-XX:ArchiveClassesAtExit=" + archiveName, + "-Xlog:cds", + "-Xlog:cds+lambda", + "-Xlog:class+path=info", + "-cp", + jarFile, + mainCutomClass, + "2"}; + pb = ProcessTools.createJavaProcessBuilder(launchArgs); + output = TestCommon.executeAndLog(pb, "custom-nosource"); + + checkFileExistence("Archive", fileArchive); + checkFileExistence("ClassList", fileList); + + output.shouldHaveExitValue(0); + checkMatch(listFileName, sourceTarget, EXPECT_NOMATCH, "Failed to filter " + sourceTarget + " in class list file"); + checkMatch(listFileName, "Hello", EXPECT_MATCH, "Hello should be logged in class list file"); + + fileArchive.delete(); + fileList.delete(); + + // 2.3 class loaded by custom loader from shared space. + // 2.3.1 dump class list + launchArgs = new String[] { + "-XX:DumpLoadedClassList=" + listFileName, + "-cp", + jarFile, + mainCutomClass, + "3"}; + pb = ProcessTools.createJavaProcessBuilder(launchArgs); + output = TestCommon.executeAndLog(pb, "custom-dump-classlist"); + + checkFileExistence("ClassList", fileList); + + checkMatch(listFileName, "Hello id: [0-9]+ super: [0-9]+ source: .*/test-hello.jar", EXPECT_MATCH, + "Class Hello should be printed in classlist"); + // 2.3.2 dump shared archive based on listFileName + String archive = "test-hello.jsa"; + File archiveFile = new File(archive); + if (archiveFile.exists()) { + archiveFile.delete(); + } + launchArgs = new String[] { + "-Xshare:dump", + "-XX:SharedClassListFile=" + listFileName, + "-XX:SharedArchiveFile=" + archive, + "-cp", + jarFile, + mainCutomClass, + "3"}; + pb = ProcessTools.createJavaProcessBuilder(launchArgs); + output = TestCommon.executeAndLog(pb, "custom-dump"); + + checkFileExistence("Archive", archiveFile); + + // 2.3.3 run with the shared archive and -XX:DumpLoadedClassList + // Hello should not be printed out in class list file. + String classList = "new-test-list.list"; + File newFile = new File(classList); + if (newFile.exists()) { + newFile.delete(); + } + launchArgs = new String[] { + "-Xshare:on", + "-XX:SharedArchiveFile=" + archive, + "-XX:DumpLoadedClassList=" + classList, + "-cp", + jarFile, + mainCutomClass, + "3"}; + pb = ProcessTools.createJavaProcessBuilder(launchArgs); + output = TestCommon.executeAndLog(pb, "custom-share"); + + checkFileExistence("ClassList", newFile); + checkMatch(classList, "Hello id: ?", EXPECT_NOMATCH, "Failed to filter custom loaded class Hello from class list"); + } +} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/TestParallelGCWithCDS.java b/test/hotspot/jtreg/runtime/cds/appcds/TestParallelGCWithCDS.java new file mode 100644 index 0000000000000000000000000000000000000000..dd3f0fdcd564214bd551e91b59f2ea83b194afcd --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/TestParallelGCWithCDS.java @@ -0,0 +1,128 @@ +/* + * 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. + */ + +/* + * @test Loading CDS archived heap objects into ParallelGC + * @bug 8274788 + * @requires vm.cds + * @requires vm.gc.Parallel + * @requires vm.gc.G1 + * + * @comment don't run this test if any -XX::+Use???GC options are specified, since they will + * interfere with the the test. + * @requires vm.gc == null + * + * @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds + * @compile test-classes/Hello.java + * @run driver TestParallelGCWithCDS + */ + +import jdk.test.lib.Platform; +import jdk.test.lib.process.OutputAnalyzer; + +public class TestParallelGCWithCDS { + public final static String HELLO = "Hello World"; + static String helloJar; + + public static void main(String... args) throws Exception { + helloJar = JarBuilder.build("hello", "Hello"); + + // Check if we can use ParallelGC during dump time, or run time, or both. + test(false, true); + test(true, false); + test(true, true); + + // With G1 we usually have 2 heap regions. To increase test coverage, we can have 3 heap regions + // by using "-Xmx256m -XX:ObjectAlignmentInBytes=64" + if (Platform.is64bit()) test(false, true, true); + } + + final static String G1 = "-XX:+UseG1GC"; + final static String Parallel = "-XX:+UseParallelGC"; + + static void test(boolean dumpWithParallel, boolean execWithParallel) throws Exception { + test(dumpWithParallel, execWithParallel, false); + } + + static void test(boolean dumpWithParallel, boolean execWithParallel, boolean useSmallRegions) throws Exception { + String dumpGC = dumpWithParallel ? Parallel : G1; + String execGC = execWithParallel ? Parallel : G1; + String small1 = useSmallRegions ? "-Xmx256m" : "-showversion"; + String small2 = useSmallRegions ? "-XX:ObjectAlignmentInBytes=64" : "-showversion"; + OutputAnalyzer out; + + System.out.println("0. Dump with " + dumpGC); + out = TestCommon.dump(helloJar, + new String[] {"Hello"}, + dumpGC, + small1, + small2, + "-Xlog:cds"); + out.shouldContain("Dumping shared data to file:"); + out.shouldHaveExitValue(0); + + System.out.println("1. Exec with " + execGC); + out = TestCommon.exec(helloJar, + execGC, + small1, + small2, + "-Xlog:cds", + "Hello"); + out.shouldContain(HELLO); + out.shouldHaveExitValue(0); + + int n = 2; + if (!dumpWithParallel && execWithParallel) { + // We dumped with G1, so we have an archived heap. At exec time, try to load them into + // a small ParallelGC heap that may be too small. + String[] sizes = { + "4m", // usually this will success load the archived heap + "2m", // usually this will fail to load the archived heap, but app can launch + // or fail with "GC triggered before VM initialization completed" + "1m" // usually this will cause VM launch to fail with "Too small maximum heap" + }; + for (String sz : sizes) { + String xmx = "-Xmx" + sz; + System.out.println("=======\n" + n + ". Exec with " + execGC + " " + xmx); + out = TestCommon.exec(helloJar, + execGC, + small1, + small2, + xmx, + "-Xlog:cds", + "Hello"); + if (out.getExitValue() == 0) { + out.shouldContain(HELLO); + } else { + String output = out.getStdout() + out.getStderr(); + String exp1 = "Too small maximum heap"; + String exp2 = "GC triggered before VM initialization completed"; + if (!output.contains(exp1) && !output.contains(exp2)) { + throw new RuntimeException("Either '" + exp1 + "' or '" + exp2 + "' must be in stdout/stderr \n"); + } + } + n++; + } + } + } +} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/cacheObject/ArchivedEnumApp.java b/test/hotspot/jtreg/runtime/cds/appcds/cacheObject/ArchivedEnumApp.java new file mode 100644 index 0000000000000000000000000000000000000000..293bf726572cabe8b95cd770e1d41bedf604e91a --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/cacheObject/ArchivedEnumApp.java @@ -0,0 +1,95 @@ +/* + * 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. + * + */ + +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleDescriptor.Requires; +import java.lang.module.ModuleDescriptor.Requires.Modifier; +import java.util.Optional; + +public class ArchivedEnumApp { + public static void main(final String[] args) throws Exception { + // Validate the archiving of the synthetic Modifier.$VALUES field: + for (Modifier mod : Modifier.values()) { + check(mod); + } + if (Modifier.values().length != 4) { + throw new RuntimeException("Modifier.$VALUES.length expeced: 4, actual: " + Modifier.values().length); + } + + // All 4 enums must exist in synthetic Modifier.$VALUES + check_in_array(Modifier.MANDATED); + check_in_array(Modifier.STATIC); + check_in_array(Modifier.SYNTHETIC); + check_in_array(Modifier.TRANSITIVE); + + // Find this module from (archived) boot layer + String moduleName = "java.management"; + Optional<Module> module = ModuleLayer.boot().findModule(moduleName); + if (module.isEmpty()) { + throw new RuntimeException(moduleName + " module is missing in boot layer"); + } + ModuleDescriptor md = module.get().getDescriptor(); + System.out.println("Module: " + md); + for (Requires r : md.requires()) { + System.out.println("Requires: " + r); + for (Modifier mod : r.modifiers()) { + System.out.println(" modifier: " + mod); + check(mod); + } + } + + System.out.println("Success"); + } + + static void check(Modifier mod) { + // The archived Enum object must equal to one of the following + // four values. + if (mod != Modifier.MANDATED && + mod != Modifier.STATIC && + mod != Modifier.SYNTHETIC && + mod != Modifier.TRANSITIVE) { + + System.out.println("mod = " + info(mod)); + System.out.println("Modifier.MANDATED = " + info(Modifier.MANDATED)); + System.out.println("Modifier.STATIC = " + info(Modifier.STATIC)); + System.out.println("Modifier.SYNTHETIC = " + info(Modifier.SYNTHETIC)); + System.out.println("Modifier.TRANSITIVE = " + info(Modifier.TRANSITIVE)); + + throw new RuntimeException("Archived enum object does not match static fields in enum class: " + info(mod)); + } + } + + static void check_in_array(Modifier mod) { + for (Modifier m : Modifier.values()) { + if (mod == m) { + return; + } + } + throw new RuntimeException("Enum object is not in $VALUES array: " + info(mod)); + } + + static String info(Object o) { + return "@0x" + Integer.toHexString(System.identityHashCode(o)) + " " + o; + } +} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/cacheObject/ArchivedEnumTest.java b/test/hotspot/jtreg/runtime/cds/appcds/cacheObject/ArchivedEnumTest.java new file mode 100644 index 0000000000000000000000000000000000000000..ec1bd213834a9a7af2987ae95a73681d6b43183a --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/cacheObject/ArchivedEnumTest.java @@ -0,0 +1,56 @@ +/* + * 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. + * + */ + +/* + * @test + * @bug 8275731 + * @summary Enum objects that are stored in the archived module graph should match + * the static final fields in the Enum class. + * @modules java.management + * @requires vm.cds.write.archived.java.heap + * @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds + * @build ArchivedEnumApp + * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar ArchivedEnumApp.jar ArchivedEnumApp + * @run driver ArchivedEnumTest + */ + +import jdk.test.lib.helpers.ClassFileInstaller; +import jdk.test.lib.process.OutputAnalyzer; + +public class ArchivedEnumTest { + public static void main(String[] args) throws Exception { + String appJar = ClassFileInstaller.getJarPath("ArchivedEnumApp.jar"); + + OutputAnalyzer out = TestCommon.testDump(appJar, + TestCommon.list("ArchivedEnumApp")); + // Note: You can get the following line to fail by commenting out + // the ADD_EXCL(...) lines in cdsHeapVerifier.cpp + out.shouldNotContain("object points to a static field that may be reinitialized at runtime"); + + TestCommon.run("-cp", appJar, + "-Xlog:cds=debug", + "-Xlog:cds+heap", + "ArchivedEnumApp").assertNormalExit("Success"); + } +} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/cacheObject/DifferentHeapSizes.java b/test/hotspot/jtreg/runtime/cds/appcds/cacheObject/DifferentHeapSizes.java index 4afbb705c881bae6fc3462c6312d9f6f2037e675..fa9482abebd27b7d31fd3c609f6cfa1bc4d40cbf 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/cacheObject/DifferentHeapSizes.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/cacheObject/DifferentHeapSizes.java @@ -62,6 +62,8 @@ public class DifferentHeapSizes { JarBuilder.getOrCreateHelloJar(); String appJar = TestCommon.getTestJar("hello.jar"); String appClasses[] = TestCommon.list("Hello"); + WhiteBox wb = WhiteBox.getWhiteBox(); + boolean useCompressedOops = wb.getBooleanVMFlag("UseCompressedOops"); for (Scenario s : scenarios) { String dumpXmx = "-Xmx" + s.dumpSize + "m"; @@ -71,7 +73,7 @@ public class DifferentHeapSizes { String runXmx = "-Xmx" + runSize + "m"; CDSTestUtils.Result result = TestCommon.run("-cp", appJar, "-showversion", "-Xlog:cds", runXmx, DEDUP, "Hello"); - if (runSize < 32768) { + if (runSize < 32768 || !useCompressedOops) { result .assertNormalExit("Hello World") .assertNormalExit(out -> { @@ -88,7 +90,7 @@ public class DifferentHeapSizes { // Test various settings of -XX:HeapBaseMinAddress that would trigger // "CDS heap data need to be relocated because the desired range ... is outside of the heap" - long default_base = WhiteBox.getWhiteBox().getSizeTVMFlag("HeapBaseMinAddress").longValue(); + long default_base = wb.getSizeTVMFlag("HeapBaseMinAddress").longValue(); long M = 1024 * 1024; long bases[] = new long[] { /* dump xmx */ /* run xmx */ /* dump base */ /* run base */ diff --git a/test/hotspot/jtreg/runtime/cds/appcds/customLoader/SameNameInTwoLoadersTest.java b/test/hotspot/jtreg/runtime/cds/appcds/customLoader/SameNameInTwoLoadersTest.java index 72d62c64179afe4a76ceea0f9d1b548e7c6b9622..2aeb2d41559017de8a974aafc451403fe5812127 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/customLoader/SameNameInTwoLoadersTest.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/customLoader/SameNameInTwoLoadersTest.java @@ -54,7 +54,7 @@ public class SameNameInTwoLoadersTest { customJar = JarBuilder.build("SameNameInTwoLoadersTest_custom", "CustomLoadee", "CustomLoadee3"); useWbParam = "-Xbootclasspath/a:" + - JarBuilder.build(true, "WhiteBox", "sun/hotspot/WhiteBox");; + JarBuilder.build(true, "WhiteBox", "sun/hotspot/WhiteBox"); // ====== unrelated loaders executeTestCase(getClassList_FP(), diff --git a/test/hotspot/jtreg/runtime/cds/appcds/customLoader/test-classes/HelloUnload.java b/test/hotspot/jtreg/runtime/cds/appcds/customLoader/test-classes/HelloUnload.java index 0a6be28b10d7f9e58c44dd87ab0edc3376279314..5df55982f145141b9b2694740f2e7d4750e16e2c 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/customLoader/test-classes/HelloUnload.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/customLoader/test-classes/HelloUnload.java @@ -30,10 +30,12 @@ import jdk.test.lib.classloader.ClassUnloadCommon; public class HelloUnload { private static String className = "CustomLoadee"; + // Prevent the following class from being GC'ed too soon. + private static Class keptC = null; public static void main(String args[]) throws Exception { - if (args.length != 3) { - throw new RuntimeException("Unexpected number of arguments: expected 3, actual " + args.length); + if (args.length < 3) { + throw new RuntimeException("Unexpected number of arguments: expected at least 3, actual " + args.length); } String path = args[0]; @@ -62,9 +64,20 @@ public class HelloUnload { throw new RuntimeException("args[2] can only be either \"true\" or \"false\", actual " + args[1]); } + // The HelloDynamicCustom.java and PrintSharedArchiveAndExit.java tests + // under appcds/dynamicArchive pass the keep-alive argument for preventing + // the class from being GC'ed prior to dumping of the dynamic CDS archive. + boolean keepAlive = false; + if (args[args.length - 1].equals("keep-alive")) { + keepAlive = true; + } + URLClassLoader urlClassLoader = new URLClassLoader("HelloClassLoader", urls, null); Class c = Class.forName(className, true, urlClassLoader); + if (keepAlive) { + keptC = c; + } System.out.println(c); System.out.println(c.getClassLoader()); Object o = c.newInstance(); diff --git a/test/hotspot/jtreg/runtime/cds/appcds/customLoader/test-classes/OldClassApp.java b/test/hotspot/jtreg/runtime/cds/appcds/customLoader/test-classes/OldClassApp.java index a484018c90289d438fee19573d3dcf2c4d5fb100..51e21e1e82583f1df2aea13e7ff4ad22a58958fc 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/customLoader/test-classes/OldClassApp.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/customLoader/test-classes/OldClassApp.java @@ -25,9 +25,12 @@ import java.io.File; import java.net.URL; import java.net.URLClassLoader; +import java.util.HashMap; import sun.hotspot.WhiteBox; public class OldClassApp { + // Prevent the classes from being GC'ed too soon. + static HashMap<String, Class> clsMap = new HashMap<>(); public static void main(String args[]) throws Exception { String path = args[0]; URL url = new File(path).toURI().toURL(); @@ -44,13 +47,26 @@ public class OldClassApp { throw new RuntimeException("args[1] can only be either \"true\" or \"false\", actual " + args[1]); } + // The OldClassAndInf.java test under appcds/dynamicArchive passes the keep-alive + // argument for preventing the classes from being GC'ed prior to dumping of + // the dynamic CDS archive. + int startIdx = 2; + boolean keepAlive = false; + if (args[2].equals("keep-alive")) { + keepAlive = true; + startIdx = 3; + } + URLClassLoader urlClassLoader = new URLClassLoader("OldClassAppClassLoader", urls, null); - for (int i = 2; i < args.length; i++) { + for (int i = startIdx; i < args.length; i++) { Class c = urlClassLoader.loadClass(args[i]); System.out.println(c); System.out.println(c.getClassLoader()); + if (keepAlive) { + clsMap.put(args[i], c); + } // [1] Check that class is defined by the correct loader if (c.getClassLoader() != urlClassLoader) { diff --git a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/ArchiveConsistency.java b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/ArchiveConsistency.java index de723e6a13d37a0411b3b3fcd359b45ce0f9c36c..6b95e072a8704d1cd6b09d759c44cf8b02c2f8e7 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/ArchiveConsistency.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/ArchiveConsistency.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -30,7 +30,8 @@ * @build Hello sun.hotspot.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar hello.jar Hello * @run driver jdk.test.lib.helpers.ClassFileInstaller sun.hotspot.WhiteBox - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI ArchiveConsistency + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI ArchiveConsistency on + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI ArchiveConsistency auto */ import java.io.File; @@ -40,8 +41,15 @@ import jdk.test.lib.cds.CDSTestUtils; import jdk.test.lib.helpers.ClassFileInstaller; public class ArchiveConsistency extends DynamicArchiveTestBase { + private static final String HELLO_WORLD = "Hello World"; + private static boolean isAuto; public static void main(String[] args) throws Exception { + if (args.length != 1 || (!args[0].equals("on") && !args[0].equals("auto"))) { + throw new RuntimeException("Must have one arg either of \"on\" or \"auto\""); + } + isAuto = args[0].equals("auto"); + setAutoMode(isAuto); runTest(ArchiveConsistency::testCustomBase); } @@ -53,31 +61,39 @@ public class ArchiveConsistency extends DynamicArchiveTestBase { doTest(baseArchiveName, topArchiveName); } + static boolean VERIFY_CRC = false; + static void runTwo(String base, String top, - String jarName, String mainClassName, int exitValue, + String jarName, String mainClassName, int expectedExitValue, String ... checkMessages) throws Exception { CDSTestUtils.Result result = run2(base, top, "-Xlog:cds", "-Xlog:cds+dynamic=debug", - "-XX:+VerifySharedSpaces", + VERIFY_CRC ? "-XX:+VerifySharedSpaces" : "-XX:-VerifySharedSpaces", "-cp", jarName, mainClassName); - if (exitValue == 0) { + if (expectedExitValue == 0) { result.assertNormalExit( output -> { for (String s : checkMessages) { output.shouldContain(s); } + output.shouldContain(HELLO_WORLD); }); } else { result.assertAbnormalExit( output -> { for (String s : checkMessages) { output.shouldContain(s); } + output.shouldContain("Unable to use shared archive"); }); } } + private static void startTest(String str) { + System.out.println("\n" + str); + } + private static void doTest(String baseArchiveName, String topArchiveName) throws Exception { String appJar = ClassFileInstaller.getJarPath("hello.jar"); String mainClass = "Hello"; @@ -94,42 +110,36 @@ public class ArchiveConsistency extends DynamicArchiveTestBase { throw new IOException(jsa + " does not exist!"); } - // 1. Modify the CRC values in the header of the top archive. - System.out.println("\n1. Modify the CRC values in the header of the top archive"); + startTest("1. Modify the CRC values in the header of the top archive"); String modTop = getNewArchiveName("modTopRegionsCrc"); File copiedJsa = CDSArchiveUtils.copyArchiveFile(jsa, modTop); CDSArchiveUtils.modifyAllRegionsCrc(copiedJsa); + VERIFY_CRC = true; runTwo(baseArchiveName, modTop, - appJar, mainClass, 1, - new String[] {"Header checksum verification failed", - "Unable to use shared archive"}); + appJar, mainClass, isAuto ? 0 : 1, + "Header checksum verification failed"); + VERIFY_CRC = false; - // 2. Make header size larger than the archive size - System.out.println("\n2. Make header size larger than the archive size"); + startTest("2. Make header size larger than the archive size"); String largerHeaderSize = getNewArchiveName("largerHeaderSize"); copiedJsa = CDSArchiveUtils.copyArchiveFile(jsa, largerHeaderSize); CDSArchiveUtils.modifyHeaderIntField(copiedJsa, CDSArchiveUtils.offsetHeaderSize(), (int)copiedJsa.length() + 1024); runTwo(baseArchiveName, largerHeaderSize, - appJar, mainClass, 1, - new String[] {"_header_size should be equal to _base_archive_name_offset plus _base_archive_name_size", - "Unable to use shared archive"}); + appJar, mainClass, isAuto ? 0 : 1, + "Archive file header larger than archive file"); - // 3. Make base archive path offset beyond of header size - System.out.println("\n3. Make base archive path offset beyond of header size."); + startTest("3. Make base archive name offset beyond of header size."); String wrongBaseArchiveNameOffset = getNewArchiveName("wrongBaseArchiveNameOffset"); copiedJsa = CDSArchiveUtils.copyArchiveFile(jsa, wrongBaseArchiveNameOffset); int fileHeaderSize = (int)CDSArchiveUtils.fileHeaderSize(copiedJsa); int baseArchiveNameOffset = CDSArchiveUtils.baseArchiveNameOffset(copiedJsa); CDSArchiveUtils.modifyHeaderIntField(copiedJsa, CDSArchiveUtils.offsetBaseArchiveNameOffset(), baseArchiveNameOffset + 1024); runTwo(baseArchiveName, wrongBaseArchiveNameOffset, - appJar, mainClass, 1, - new String[] {"_header_size should be equal to _base_archive_name_offset plus _base_archive_name_size", - "The shared archive file has an incorrect header size", - "Unable to use shared archive"}); + appJar, mainClass, isAuto ? 0 : 1, + "Invalid base_archive_name offset/size (out of range)"); - // 4. Make base archive path offset points to middle of name size - System.out.println("\n4. Make base archive path offset points to middle of name size"); + startTest("4. Make base archive name offset points to middle of the base archive name"); String wrongBaseNameOffset = getNewArchiveName("wrongBaseNameOffset"); copiedJsa = CDSArchiveUtils.copyArchiveFile(jsa, wrongBaseNameOffset); int baseArchiveNameSize = CDSArchiveUtils.baseArchiveNameSize(copiedJsa); @@ -137,13 +147,10 @@ public class ArchiveConsistency extends DynamicArchiveTestBase { CDSArchiveUtils.modifyHeaderIntField(copiedJsa, baseArchiveNameOffset, baseArchiveNameOffset + baseArchiveNameSize/2); runTwo(baseArchiveName, wrongBaseNameOffset, - appJar, mainClass, 1, - new String[] {"An error has occurred while processing the shared archive file.", - "Header checksum verification failed", - "Unable to use shared archive"}); + appJar, mainClass, isAuto ? 0 : 1, + "Base archive name is damaged"); - // 5. Make base archive name not terminated with '\0' - System.out.println("\n5. Make base archive name not terminated with '\0'"); + startTest("5. Make base archive name not terminated with '\0'"); String wrongBaseName = getNewArchiveName("wrongBaseName"); copiedJsa = CDSArchiveUtils.copyArchiveFile(jsa, wrongBaseName); baseArchiveNameOffset = CDSArchiveUtils.baseArchiveNameOffset(copiedJsa); @@ -152,12 +159,10 @@ public class ArchiveConsistency extends DynamicArchiveTestBase { CDSArchiveUtils.writeData(copiedJsa, offset, new byte[] {(byte)'X'}); runTwo(baseArchiveName, wrongBaseName, - appJar, mainClass, 1, - new String[] {"Base archive name is damaged", - "Header checksum verification failed"}); + appJar, mainClass, isAuto ? 0 : 1, + "Base archive name is damaged"); - // 6. Modify base archive name to a file that doesn't exist. - System.out.println("\n6. Modify base archive name to a file that doesn't exist"); + startTest("6. Modify base archive name to a file that doesn't exist"); String wrongBaseName2 = getNewArchiveName("wrongBaseName2"); copiedJsa = CDSArchiveUtils.copyArchiveFile(jsa, wrongBaseName2); baseArchiveNameOffset = CDSArchiveUtils.baseArchiveNameOffset(copiedJsa); @@ -170,8 +175,59 @@ public class ArchiveConsistency extends DynamicArchiveTestBase { (new File(badName)).delete(); runTwo(baseArchiveName, wrongBaseName2, - appJar, mainClass, 1, - new String[] {"Base archive " + badName + " does not exist", - "Header checksum verification failed"}); + appJar, mainClass, isAuto ? 0 : 1, + "Base archive " + badName + " does not exist"); + + // Following three tests: + // -XX:SharedArchiveFile=non-exist-base.jsa:top.jsa + // -XX:SharedArchiveFile=base.jsa:non-exist-top.jsa + // -XX:SharedArchiveFile=non-exist-base.jsa:non-exist-top.jsa + startTest("7. Non-exist base archive"); + String nonExistBase = "non-exist-base.jsa"; + File nonExistBaseFile = new File(nonExistBase); + nonExistBaseFile.delete(); + runTwo(nonExistBase, topArchiveName, + appJar, mainClass, isAuto ? 0 : 1, + "Specified shared archive not found (" + nonExistBase + ")"); + + startTest("8. Non-exist top archive"); + String nonExistTop = "non-exist-top.jsa"; + File nonExistTopFile = new File(nonExistTop); + nonExistTopFile.delete(); + runTwo(baseArchiveName, nonExistTop, + appJar, mainClass, isAuto ? 0 : 1, + "Specified shared archive not found (" + nonExistTop + ")"); + + startTest("9. nost-exist-base and non-exist-top"); + runTwo(nonExistBase, nonExistTop, + appJar, mainClass, isAuto ? 0 : 1, + "Specified shared archive not found (" + nonExistBase + ")"); + + // following two tests: + // -Xshare:auto -XX:SharedArchiveFile=top.jsa, but base does not exist. + + if (!isUseSharedSpacesDisabled()) { + new File(baseArchiveName).delete(); + + startTest("10. -XX:+AutoCreateSharedArchive -XX:SharedArchiveFile=" + topArchiveName); + run(topArchiveName, + "-Xshare:auto", + "-XX:+AutoCreateSharedArchive", + "-cp", + appJar, mainClass) + .assertNormalExit(output -> { + output.shouldContain("warning: -XX:+AutoCreateSharedArchive is unsupported when base CDS archive is not loaded"); + }); + + startTest("11. -XX:SharedArchiveFile=" + topArchiveName + " -XX:ArchiveClassesAtExit=" + getNewArchiveName("top3")); + run(topArchiveName, + "-Xshare:auto", + "-XX:ArchiveClassesAtExit=" + getNewArchiveName("top3"), + "-cp", + appJar, mainClass) + .assertNormalExit(output -> { + output.shouldContain("VM warning: -XX:ArchiveClassesAtExit is unsupported when base CDS archive is not loaded"); + }); + } } } diff --git a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/CDSLambdaInvoker.java b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/CDSLambdaInvoker.java new file mode 100644 index 0000000000000000000000000000000000000000..ae0772427d4fae2b8176ce44df2cc06b17465d91 --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/CDSLambdaInvoker.java @@ -0,0 +1,58 @@ +/* + * 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. + * + */ + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; + +public class CDSLambdaInvoker { + public static void main(String args[]) throws Throwable { + invoke(MethodHandles.identity(double.class), 1.0); + invoke(MethodHandles.identity(long.class), 1); + invoke(MethodHandles.identity(int.class), 1); + invoke(MethodHandles.identity(float.class), 1.0f); + + MethodHandles.Lookup lookup = MethodHandles.lookup(); + MethodType mt = MethodType.methodType(void.class, float.class, double.class, int.class, + boolean.class, Object.class, long.class, double.class); + MethodHandle mh = lookup.findStatic(CDSLambdaInvoker.class, "callme", mt); + mh.invokeExact(4.0f, 5.0, 6, true, (Object)args, 7L, 8.0); + } + + private static Object invoke(MethodHandle mh, Object ... args) throws Throwable { + try { + for (Object o : args) { + mh = MethodHandles.insertArguments(mh, 0, o); + } + return mh.invoke(); + } catch (Throwable t) { + System.out.println("Failed to find, link and/or invoke " + mh.toString() + ": " + t.getMessage()); + throw t; + } + } + + private static void callme(float f, double d, int i, boolean b, Object o, long l, double d2) { + + } +} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/DumpToDefaultArchive.java b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/DumpToDefaultArchive.java new file mode 100644 index 0000000000000000000000000000000000000000..88692d1f26a487c4181212a0e87b6c89f866cf68 --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/DumpToDefaultArchive.java @@ -0,0 +1,58 @@ +/* + * 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. + * + */ + +/* + * @test + * @bug 8277100 + * @summary VM should exit with an error message if the specified dynamic archive + * is the same as the default CDS archive. + * @requires vm.cds + * @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds + * @build sun.hotspot.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. DumpToDefaultArchive + */ + +import jdk.test.lib.helpers.ClassFileInstaller; +import sun.hotspot.WhiteBox; + +public class DumpToDefaultArchive extends DynamicArchiveTestBase { + + public static void main(String[] args) throws Exception { + runTest(DumpToDefaultArchive::doTest); + } + + private static void doTest() throws Exception { + WhiteBox wb = WhiteBox.getWhiteBox(); + String topArchiveName = wb.getDefaultArchivePath(); + + dump(topArchiveName, + "-Xlog:cds", + "-version") + .assertAbnormalExit(output -> { + output.shouldContain("Cannot specify the default CDS archive for -XX:ArchiveClassesAtExit: " + + topArchiveName); + }); + } +} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/DynamicArchiveTestBase.java b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/DynamicArchiveTestBase.java index f6e25cfdeb8dd081d7854590aa37b0efed04a419..6cbfec37175116a681ed0c8deb0b108822aff694 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/DynamicArchiveTestBase.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/DynamicArchiveTestBase.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -36,8 +36,9 @@ import sun.hotspot.WhiteBox; */ class DynamicArchiveTestBase { private static boolean executedIn_run = false; - + private static boolean autoMode = false; // -Xshare:auto private static final WhiteBox WB = WhiteBox.getWhiteBox(); + private static String[] baseArchiveOptions = new String[] {}; public static interface DynamicArchiveTest { public void run() throws Exception; @@ -47,6 +48,7 @@ class DynamicArchiveTestBase { public void run(String args[]) throws Exception; } + public static void setAutoMode(boolean val) { autoMode = val; } /* * Tests for dynamic archives should be written using this pattern: @@ -94,6 +96,23 @@ class DynamicArchiveTestBase { return TestCommon.getNewArchiveName(stem); } + public static void setBaseArchiveOptions(String... opts) { + baseArchiveOptions = opts; + } + + /** + * Excute a JVM to dump a base archive by + * -Xshare:dump -XX:SharedArchiveFile=baseArchiveName + */ + public static Result dumpBaseArchive(String baseArchiveName, String... cmdLineSuffix) + throws Exception + { + OutputAnalyzer output = TestCommon.dumpBaseArchive(baseArchiveName, cmdLineSuffix); + CDSOptions opts = new CDSOptions(); + opts.setXShareMode("dump"); + return new Result(opts, output); + } + /** * Execute a JVM using the base archive (given by baseArchiveName) with the command line * (given by cmdLineSuffix). At JVM exit, dump all eligible classes into the top archive @@ -183,7 +202,7 @@ class DynamicArchiveTestBase { (topArchiveName == null) ? baseArchiveName : baseArchiveName + File.pathSeparator + topArchiveName; String[] cmdLine = TestCommon.concat( - "-Xshare:on", + autoMode ? "-Xshare:auto" : "-Xshare:on", "-XX:SharedArchiveFile=" + archiveFiles); cmdLine = TestCommon.concat(cmdLine, cmdLineSuffix); return execProcess("exec", null, cmdLine); @@ -202,7 +221,7 @@ class DynamicArchiveTestBase { (topArchiveName == null) ? baseArchiveName : baseArchiveName + File.pathSeparator + topArchiveName; String[] cmdLine = TestCommon.concat( - "-Xshare:on", + autoMode ? "-Xshare:auto" : "-Xshare:on", "-XX:SharedArchiveFile=" + archiveFiles); cmdLine = TestCommon.concat(cmdLine, cmdLineSuffix); return execProcess("exec", jarDir, cmdLine); @@ -272,16 +291,16 @@ class DynamicArchiveTestBase { private static String getTempBaseArchive() throws Exception { if (tempBaseArchive == null) { tempBaseArchive = getNewArchiveName("tempBaseArchive"); - TestCommon.dumpBaseArchive(tempBaseArchive); + TestCommon.dumpBaseArchive(tempBaseArchive, baseArchiveOptions); } return tempBaseArchive; } /** - * Return true if the UseSharedSpaces flag has been disabled. + * Return true if sharing has been disabled. * By default, the VM will be started with -Xshare:auto. - * The UseSharedSpaces flag will be disabled by the VM if there's some - * problem in using the default CDS archive. It could happen under some + * Sharing will be disabled by the VM if there's some problem + * in using the default CDS archive. It could happen under some * situations such as follows: * - the default CDS archive wasn't generated during build time because * the JDK was built via cross-compilation on a different platform; @@ -291,7 +310,7 @@ class DynamicArchiveTestBase { * UseCompressedClassPointers options. Those "compressed" options were * enabled when the default CDS archive was built. */ - private static boolean isUseSharedSpacesDisabled() { - return (WB.getBooleanVMFlag("UseSharedSpaces") == false); + public static boolean isUseSharedSpacesDisabled() { + return !WB.isSharingEnabled(); } } diff --git a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/HelloDynamicCustom.java b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/HelloDynamicCustom.java index 2c2c745027cd5c2993e6549cacc5bcb53be075e1..097162a17c14697645662085f999a3d03e17d9b9 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/HelloDynamicCustom.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/HelloDynamicCustom.java @@ -64,7 +64,7 @@ public class HelloDynamicCustom extends DynamicArchiveTestBase { "-Xlog:cds", "-Xlog:cds+dynamic=debug", "-cp", appJar, - mainAppClass, customJarPath, "false", "false") + mainAppClass, customJarPath, "false", "false", "keep-alive") .assertNormalExit(output -> { output.shouldContain("Written dynamic archive 0x") .shouldNotContain("klasses.*=.*CustomLoadee") diff --git a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/LambdaCustomLoader.java b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/LambdaCustomLoader.java index dc2c9f144d77379f1157fa38d6801a8191196ca1..df3122056e2299f48cfa98f2dfc1f9abb1510dec 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/LambdaCustomLoader.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/LambdaCustomLoader.java @@ -49,7 +49,7 @@ public class LambdaCustomLoader extends DynamicArchiveTestBase { // 1. Host class loaded by a custom loader is initialized during dump time. dump(topArchiveName, "-Xlog:class+load,cds=debug,cds+dynamic", - "-cp", appJar, mainClass, appJar, "init") + "-cp", appJar, mainClass, appJar, "init", "keep-alive") .assertNormalExit(output -> { output.shouldMatch("Skipping.LambHello[$][$]Lambda[$].*0x.*:.Hidden.class") .shouldHaveExitValue(0); @@ -67,7 +67,7 @@ public class LambdaCustomLoader extends DynamicArchiveTestBase { // 2. Host class loaded by a custom loader is NOT initialized during dump time. dump(topArchiveName, "-Xlog:class+load,cds=debug,cds+dynamic", - "-cp", appJar, mainClass, appJar) + "-cp", appJar, mainClass, appJar, "keep-alive") .assertNormalExit(output -> { output.shouldHaveExitValue(0); }); diff --git a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/LotsUnloadTest.java b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/LotsUnloadTest.java new file mode 100644 index 0000000000000000000000000000000000000000..7cde5683c22ef7b38103189294ed9ad9f82bc9a7 --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/LotsUnloadTest.java @@ -0,0 +1,82 @@ +/* + * 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. + * + */ + +/* + * @test + * @bug 8278602 + * @summary Lots of classes being unloaded while we try to dump a dynamic archive + * @requires vm.cds + * @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds + * /test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/test-classes + * @build sun.hotspot.WhiteBox + * @build LotsUnloadApp + * @run driver jdk.test.lib.helpers.ClassFileInstaller sun.hotspot.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar LotsUnloadApp.jar LotsUnloadApp DefinedAsHiddenKlass + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. LotsUnloadTest + */ + +// Note: for https://bugs.openjdk.java.net/browse/JDK-8278602, this test case does NOT +// reliably reproduce the problem. Reproduction requires patching ZGC. Please see +// the bug report for instructions. +// +// This test case is included so that it may find a similar bug under stress conditions +// in the CI runs. +import jdk.test.lib.helpers.ClassFileInstaller; + +public class LotsUnloadTest extends DynamicArchiveTestBase { + public static void main(String[] args) throws Exception { + runTest(LotsUnloadTest::test); + } + + static void test() throws Exception { + String topArchiveName = getNewArchiveName(); + String appJar = ClassFileInstaller.getJarPath("LotsUnloadApp.jar"); + String mainClass = "LotsUnloadApp"; + String logging; + + if (Boolean.getBoolean("verbose.LotsUnloadTest")) { + // class+unload logs may change GC timing and cause the bug to be + // less reproducible. + logging = "-Xlog:cds,class+unload"; + } else { + logging = "-Xlog:cds"; + } + + dump(topArchiveName, + logging, + "-Xmx64m", "-Xms32m", + "-cp", appJar, mainClass) + .assertNormalExit(output -> { + output.shouldHaveExitValue(0); + }); + + run(topArchiveName, + logging, + "-Xmx64m", "-Xms32m", + "-cp", appJar, mainClass) + .assertNormalExit(output -> { + output.shouldHaveExitValue(0); + }); + } +} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/ModulePath.java b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/ModulePath.java new file mode 100644 index 0000000000000000000000000000000000000000..2672225ee05d264584501b02f45d8dbc7ad4be97 --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/ModulePath.java @@ -0,0 +1,131 @@ +/* + * 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. + * + */ + +import java.io.File; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import jdk.test.lib.cds.CDSTestUtils; + +/* + * @test + * @summary Dyanmic archive with module path + * @requires vm.cds + * @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds /test/hotspot/jtreg/runtime/cds/appcds/test-classes + * @compile ../test-classes/Hello.java + * @build sun.hotspot.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar WhiteBox.jar sun.hotspot.WhiteBox + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:./WhiteBox.jar ModulePath + */ + +public class ModulePath extends DynamicArchiveTestBase { + private static final Path USER_DIR = Paths.get(CDSTestUtils.getOutputDir()); + + private static final String FS = File.separator; + private static final String TEST_SRC = System.getProperty("test.src") + + FS + ".." + FS + "jigsaw" + FS + "modulepath"; + + private static final Path SRC_DIR = Paths.get(TEST_SRC, "src"); + private static final Path MODS_DIR = Paths.get("mods"); + + // the module name of the test module + private static final String TEST_MODULE = "com.simple"; + + // the module main class + private static final String MAIN_CLASS = "com.simple.Main"; + + private static Path moduleDir = null; + private static Path srcJar = null; + + public static void buildTestModule() throws Exception { + + // javac -d mods/$TESTMODULE --module-path MOD_DIR src/$TESTMODULE/** + JarBuilder.compileModule(SRC_DIR.resolve(TEST_MODULE), + MODS_DIR.resolve(TEST_MODULE), + MODS_DIR.toString()); + + + moduleDir = Files.createTempDirectory(USER_DIR, "mlib"); + srcJar = moduleDir.resolve(TEST_MODULE + ".jar"); + String classes = MODS_DIR.resolve(TEST_MODULE).toString(); + JarBuilder.createModularJar(srcJar.toString(), classes, MAIN_CLASS); + } + + public static void main(String[] args) throws Exception { + runTest(ModulePath::test); + } + + static void test(String args[]) throws Exception { + String topArchiveName = getNewArchiveName("top"); + String baseArchiveName = getNewArchiveName("base"); + + String appJar = JarBuilder.getOrCreateHelloJar(); + String mainClass = "Hello"; + + // create a base archive with the --module-path option + buildTestModule(); + baseArchiveName = getNewArchiveName("base-with-module"); + String appClasses[] = {mainClass}; + TestCommon.dumpBaseArchive(baseArchiveName, + appClasses, + "-Xlog:class+load", + "-cp", appJar, + "--module-path", moduleDir.toString(), + "-m", TEST_MODULE); + + // Dumping of dynamic archive should be successful if the specified + // --module-path is the same as for the base archive. + topArchiveName = getNewArchiveName("top-with-module"); + dump2(baseArchiveName, topArchiveName, + "-Xlog:cds*", + "-Xlog:cds+dynamic=debug", + "-Xlog:class+path=info,class+load", + "-cp", appJar, + "--module-path", moduleDir.toString(), + "-m", TEST_MODULE, MAIN_CLASS) + .assertNormalExit(); + + // Load the Hello class from the base archive. + run2(baseArchiveName, topArchiveName, + "-Xlog:class+load", + "-Xlog:cds+dynamic=debug,cds=debug", + "-cp", appJar, mainClass) + .assertNormalExit(output -> { + output.shouldContain("Hello source: shared objects file") + .shouldHaveExitValue(0); + }); + + // Load the com.simple.Main class from the dynamic archive. + run2(baseArchiveName, topArchiveName, + "-Xlog:class+load", + "-Xlog:cds+dynamic=debug,cds=debug", + "-cp", appJar, + "--module-path", moduleDir.toString(), + "-m", TEST_MODULE, MAIN_CLASS) + .assertNormalExit(output -> { + output.shouldContain("com.simple.Main source: shared objects file (top)") + .shouldHaveExitValue(0); + }); + } +} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/OldClassAndInf.java b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/OldClassAndInf.java index 44b430eef6ab12e63f206541e57992e7035b883d..4508eefd82924e1c7adeb918e7600878ef775e55 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/OldClassAndInf.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/OldClassAndInf.java @@ -80,7 +80,7 @@ public class OldClassAndInf extends DynamicArchiveTestBase { "-Xlog:cds", "-Xlog:cds+dynamic=debug", "-cp", appJar, - mainAppClass, loadeesJar, inArchive), + mainAppClass, loadeesJar, inArchive, "keep-alive"), loadees)) .assertNormalExit(output -> { output.shouldContain("Written dynamic archive 0x") diff --git a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/PrintSharedArchiveAndExit.java b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/PrintSharedArchiveAndExit.java index 342aceff9372b9afa3357d8251613262e8b9f7fc..9ceb51c74b602db1aa3452e64ba147042b5f4c73 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/PrintSharedArchiveAndExit.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/PrintSharedArchiveAndExit.java @@ -64,7 +64,7 @@ public class PrintSharedArchiveAndExit extends DynamicArchiveTestBase { "-Xlog:cds", "-Xlog:cds+dynamic=debug", "-cp", appJar, - mainAppClass, customJarPath, "false", "false") + mainAppClass, customJarPath, "false", "false", "keep-alive") .assertNormalExit(output -> { output.shouldContain("Written dynamic archive 0x") .shouldNotContain("klasses.*=.*CustomLoadee") diff --git a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/RegularHiddenClass.java b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/RegularHiddenClass.java index 3729813e8fac011c17976bf5487d4954f2e57947..17c496bc14d6f6ef46cd89aee4de93df24b61d99 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/RegularHiddenClass.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/RegularHiddenClass.java @@ -54,7 +54,7 @@ public class RegularHiddenClass extends DynamicArchiveTestBase { dump(topArchiveName, "-Xlog:class+load=debug,cds+dynamic,cds=debug", - "-cp", appJar, mainClass) + "-cp", appJar, mainClass, "keep-alive") .assertNormalExit(output -> { output.shouldMatch("cds.*Skipping.TestClass.0x.*Hidden.class") .shouldNotMatch("cds.dynamic.*Archiving.hidden.TestClass.*") diff --git a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/SharedArchiveFileOption.java b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/SharedArchiveFileOption.java index d54b36854da77ead274636abfc42bb394a8cdcdc..d06bb8ef106b241ba6b6cd29a5ce7ab17416ce56 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/SharedArchiveFileOption.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/SharedArchiveFileOption.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -24,6 +24,7 @@ /* * @test + * @bug 8276787 * @summary Some negative tests for the SharedArchiveFile option * @requires vm.cds * @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds /test/hotspot/jtreg/runtime/cds/appcds/test-classes @@ -34,9 +35,10 @@ * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. SharedArchiveFileOption */ -import jdk.test.lib.helpers.ClassFileInstaller; - import java.io.File; +import jdk.test.lib.Asserts; +import jdk.test.lib.helpers.ClassFileInstaller; +import jtreg.SkippedException; public class SharedArchiveFileOption extends DynamicArchiveTestBase { public static void main(String[] args) throws Exception { @@ -53,12 +55,21 @@ public class SharedArchiveFileOption extends DynamicArchiveTestBase { doTest(baseArchiveName, topArchiveName); } + private static int testnum = 0; + private static void testcase(String s) { + System.out.println("\n\nTest #" + (++testnum) + " " + s); + } + + private interface MyRunnable { + public void run() throws Exception; + } + private static void doTest(String baseArchiveName, String topArchiveName) throws Exception { String appJar = ClassFileInstaller.getJarPath("hello.jar"); String mainClass = "Hello"; String dummyArchiveName = getNewArchiveName("dummy"); - // -Xshare:dump specified with -XX:ArchiveClassesAtExit + testcase("-Xshare:dump specified with -XX:ArchiveClassesAtExit"); dump2(dummyArchiveName, dummyArchiveName, "-Xlog:cds", "-Xlog:cds+dynamic=debug", @@ -68,8 +79,7 @@ public class SharedArchiveFileOption extends DynamicArchiveTestBase { output.shouldContain("-XX:ArchiveClassesAtExit cannot be used with -Xshare:dump"); }); - // more than 1 archive file specified in -XX:SharedArchiveFile during - // dynamic dumpgin + testcase("more than 1 archive file specified in -XX:SharedArchiveFile during dynamic dump"); String dummyArchives = dummyArchiveName + File.pathSeparator + dummyArchiveName; dump2(dummyArchives, dummyArchiveName, "-Xlog:cds", @@ -79,7 +89,7 @@ public class SharedArchiveFileOption extends DynamicArchiveTestBase { output.shouldContain("Cannot have more than 1 archive file specified in -XX:SharedArchiveFile during CDS dumping"); }); - // normal dynamic archive dumping + testcase("normal dynamic archive dumping"); dump2(baseArchiveName, topArchiveName, "-Xlog:cds", "-Xlog:cds+dynamic=debug", @@ -88,7 +98,7 @@ public class SharedArchiveFileOption extends DynamicArchiveTestBase { output.shouldContain("Written dynamic archive 0x"); }); - // same archive file specified for -XX:SharedArchiveFile and -XX:ArchiveClassesAtExit + testcase("same archive file specified for -XX:SharedArchiveFile and -XX:ArchiveClassesAtExit"); dump2(baseArchiveName, baseArchiveName, "-Xlog:cds", "-Xlog:cds+dynamic=debug", @@ -99,7 +109,7 @@ public class SharedArchiveFileOption extends DynamicArchiveTestBase { }); - // a top archive specified in the base archive position + testcase("a top archive specified in the base archive position"); run2(topArchiveName, baseArchiveName, "-Xlog:class+load", "-Xlog:cds+dynamic=debug,cds=debug", @@ -108,7 +118,7 @@ public class SharedArchiveFileOption extends DynamicArchiveTestBase { output.shouldMatch("Not a base shared archive:.*top.*.jsa"); }); - // a base archive specified in the top archive position + testcase("a base archive specified in the top archive position"); run2(baseArchiveName, baseArchiveName2, "-Xlog:class+load", "-Xlog:cds+dynamic=debug,cds=debug", @@ -117,7 +127,7 @@ public class SharedArchiveFileOption extends DynamicArchiveTestBase { output.shouldMatch("Not a top shared archive:.*base.*.jsa"); }); - // more than 2 archives specified in the -XX:ShareArchiveFile option + testcase("more than 2 archives specified in the -XX:ShareArchiveFile option"); String baseArchives = baseArchiveName + File.pathSeparator + baseArchiveName2; run2(baseArchives, topArchiveName, "-Xlog:class+load", @@ -128,7 +138,7 @@ public class SharedArchiveFileOption extends DynamicArchiveTestBase { "Cannot have more than 2 archive files specified in the -XX:SharedArchiveFile option"); }); - // base archive not specified + testcase("base archive not specified"); final String topArchive = File.pathSeparator + topArchiveName; run2(topArchive, null, "-Xlog:class+load", @@ -139,7 +149,7 @@ public class SharedArchiveFileOption extends DynamicArchiveTestBase { "Base archive was not specified: " + topArchive); }); - // top archive not specified + testcase("top archive not specified"); final String baseArchive = baseArchiveName + File.pathSeparator; run2(baseArchive, null, "-Xlog:class+load", @@ -149,5 +159,105 @@ public class SharedArchiveFileOption extends DynamicArchiveTestBase { output.shouldContain( "Top archive was not specified: " + baseArchive); }); + + + testcase("A dynamic archive is already loaded when -XX:SharedArchiveFile is specified"); + dump2(baseArchiveName /*this is overridden by -XX:SharedArchiveFile= below*/, + topArchiveName, + "-XX:SharedArchiveFile=" + topArchiveName, + "-cp", appJar, mainClass) + .assertAbnormalExit("-XX:ArchiveClassesAtExit is unsupported when a dynamic CDS archive is specified in -XX:SharedArchiveFile:"); + + testcase("A dynamic archive is already loaded when -XX:+RecordDynamicDumpInfo is specified"); + if (isUseSharedSpacesDisabled()) { + System.out.println("This test is not applicable when JTREG tests are executed with -Xshare:off, or if the JDK doesn't have a default archive."); + } else { + run2(null, topArchiveName, + "-XX:+RecordDynamicDumpInfo", + "-cp", appJar, mainClass) + .assertAbnormalExit("-XX:+RecordDynamicDumpInfo is unsupported when a dynamic CDS archive is specified in -XX:SharedArchiveFile:"); + } + + testcase("-XX:+RecordDynamicDumpInfo cannot be used with -XX:ArchiveClassesAtExit"); + dump2(baseArchiveName, + topArchiveName, + "-XX:+RecordDynamicDumpInfo", + "-cp", appJar, mainClass) + .assertAbnormalExit("-XX:+RecordDynamicDumpInfo cannot be used with -XX:ArchiveClassesAtExit"); + + testcase("Specifying -XX:+RecordDynamicDumpInfo should not cause dynamic dump"); + run2(baseArchiveName, null, + "-XX:+RecordDynamicDumpInfo", + "-Xlog:cds+dynamic=debug", + "-cp", appJar, mainClass) + .assertNormalExit(output -> { + output.shouldNotMatch("\\[cds,dynamic"); + }); + + { + String ERROR = "-XX:ArchiveClassesAtExit is unsupported when base CDS archive is not loaded"; + + testcase("-XX:ArchiveClassesAtExit with CDS disabled (-Xshare:off)"); + dump2(baseArchiveName, + topArchiveName, + "-Xshare:off", + "-Xlog:cds", + "-cp", appJar, mainClass) + .assertNormalExit(output -> { + output.shouldNotMatch("\\[cds,dynamic"); + output.shouldContain(ERROR); + }); + + testcase("-XX:ArchiveClassesAtExit with CDS disabled (Base archive cannot be mapped -- doesn't exist"); + dump2(baseArchiveName + ".notExist", + topArchiveName, + "-Xlog:cds", + "-Xshare:auto", + "-cp", appJar, mainClass) + .assertNormalExit(output -> { + output.shouldNotMatch("\\[cds,dynamic"); + output.shouldContain(ERROR); + }); + + testcase("-XX:ArchiveClassesAtExit with CDS disabled (incompatible VM options)"); + dump2(baseArchiveName, + topArchiveName, + "--patch-module", + "foo.bar=xxx", + "-Xshare:auto", + "-Xlog:cds", + "-cp", appJar, mainClass) + .assertAbnormalExit("Cannot use the following option when dumping the shared archive: --patch-module"); + } + + { + String ERROR = "-XX:+RecordDynamicDumpInfo is unsupported when base CDS archive is not loaded"; + + testcase("-XX:+RecordDynamicDumpInfo with CDS disabled (-Xshare:off)"); + run2(baseArchiveName, null, + "-XX:+RecordDynamicDumpInfo", + "-Xshare:off", + "-cp", appJar, mainClass) + .assertAbnormalExit(ERROR); + + testcase("-XX:+RecordDynamicDumpInfo with CDS disabled (Base archive cannot be mapped -- doesn't exist"); + run2(baseArchiveName + ".notExist", null, + "-XX:+RecordDynamicDumpInfo", + "-Xshare:auto", + "-Xlog:cds", + "-cp", appJar, mainClass) + .assertAbnormalExit(ERROR); + + testcase("-XX:+RecordDynamicDumpInfo with CDS disabled (incompatible VM options)"); + run2(baseArchiveName + ".notExist", null, + "-XX:+RecordDynamicDumpInfo", + "--patch-module", + "foo.bar=xxx", + "-Xshare:auto", + "-Xlog:cds", + "-cp", appJar, mainClass) + .assertAbnormalExit("CDS is disabled when the --patch-module option is specified", + ERROR); + } } } diff --git a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/TestAutoCreateSharedArchive.java b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/TestAutoCreateSharedArchive.java new file mode 100644 index 0000000000000000000000000000000000000000..e06a4c98c3789d6914c0ac68173a8023f4792ac7 --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/TestAutoCreateSharedArchive.java @@ -0,0 +1,697 @@ +/* + * 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. + * + */ + +/* + * @test + * @bug 8261455 + * @summary test -XX:+AutoCreateSharedArchive feature + * @requires vm.cds + * @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds /test/hotspot/jtreg/runtime/cds/appcds/test-classes + * @build Hello + * @build sun.hotspot.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar hello.jar Hello + * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar WhiteBox.jar sun.hotspot.WhiteBox + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:./WhiteBox.jar TestAutoCreateSharedArchive verifySharedSpacesOff + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:./WhiteBox.jar TestAutoCreateSharedArchive verifySharedSpacesOn + */ + +/* + * -XX:SharedArchiveFile can be specified in two styles: + * + * (A) Test with default base archive -XX:+SharedArchiveFile=<archive> + * (B) Test with the base archive specified: -XX:SharedArchiveFile=<base>:<top> + * all the following if not explained explicitly, run with flag -XX:+AutoCreateSharedArchive + * + * Note VerifySharedSpaces will affect output so the tests run twice: one with -XX:+VerifySharedSpaces and the other with -XX:-VerifySharedSpaces + * + * 10 Case (A) + * + * 10.01 run with non-existing archive should automatically create dynamic archive. + * If the JDK's default CDS archive cannot be loaded, print out warning, run continue without shared archive and no shared archive created at exit. + * 10.02 run with the created dynamic archive should pass. + * 10.03 run with the created dynamic archive and -XX:+AutoCreateSharedArchive should pass and no shared archive created at exit. + * + * 11 run with static archive. + * run with static archive should printout warning and continue, share or no share depends on the archive validation at exit, + * no shared archive (top) will be generated. + * + * 12 run with damaged magic should not regenerate dynamic archive. + * if magic is not expected, no shared archive will be regenerated at exit. + * + * 13 run with a bad versioned archive. + * 13.01 run with a bad versioned (< CDS_GENERIC_HEADER_SUPPORTED_MIN_VERSION) archive should not create dynamic archive at exit. + * 13.02 run with a bad versioned (> CDS_GENERIC_HEADER_SUPPORTED_MIN_VERSION) archive should create dynamic archive at exit. + * + * 14 run with an archive whose base name is not matched, no shared archive at exit. + * + * 15 run with an archive whose jvm_ident is corrupted should + * create dynamic archive at exit with -XX:-VerifySharedSpaces + * not create dynamic archive at exit with -XX:+VerifySharedSpaces + * + * 16 run with an archive only containing magic in the file (size of 4 bytes) + * the archive will be created at exit. + * + * 20 (case B) + * + * 20.01 dump base archive which will be used for dumping top archive. + * 20.02 dump top archive based on base archive obtained in 20.1. + * 20.03 run -XX:SharedArchiveFile=<base>:<top> to verify the archives. + * 20.04 run with -XX:SharedArchveFile=base:top (reversed) + * + * 21 Mismatched versions + * 21.01 if version of top archive is higher than CDS_GENERIC_HEADER_SUPPORTED_MIN_VERSION, the archive cannot be shared and will be + * regenerated at exit. + * 21.02 if version of top archive is lower than CDS_GENERIC_HEADER_SUPPORTED_MIN_VERSION, the archive cannot be shared and will be + * created at exit. + * + * 22 create an archive with dynamic magic number only + * archive will be created at exit if base can be shared. + * + * 23 mismatched jvm_indent in base/top archive + * 23.01 mismatched jvm_indent in top archive + * 23.02 mismatched jvm_indent in base archive + * + * 24 run with non-existing shared archives + * 24.01 run -Xshare:auto -XX:+AutoCreateSharedArchive -XX:SharedArchiveFile=base.jsa:non-exist-top.jsa + * The top archive will be regenerated. + * 24.02 run -Xshare:auto -XX:+AutoCreateSharedArchive -XX:SharedArchiveFile=non-exist-base.jsa:top.jsa + * top archive will not be shared if base archive failed to load. + */ + +import java.io.IOException; +import java.io.File; +import java.nio.file.attribute.FileTime; +import java.nio.file.Files; +import java.nio.file.Paths; + +import jdk.test.lib.cds.CDSTestUtils; +import jdk.test.lib.cds.CDSArchiveUtils; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.helpers.ClassFileInstaller; + +import jtreg.SkippedException; + +public class TestAutoCreateSharedArchive extends DynamicArchiveTestBase { + private static final String BASE_NAME = CDSTestUtils.getOutputFileName("base.jsa"); + private static final String TOP_NAME = CDSTestUtils.getOutputFileName("top.jsa"); + private static final String mainAppClass = "Hello"; + private static final String HELLO_SOURCE = "Hello source: shared objects file (top)"; + private static final String HELLO_WORLD = "Hello World"; + private static boolean verifyOn = false; + + private static int genericHeaderMinVersion = CDSArchiveUtils.getGenericHeaderMinVersion(); + private static int currentCDSVersion = CDSArchiveUtils.getCurrentCDSArchiveVersion(); + + public static void main(String[] args) throws Exception { + if (isUseSharedSpacesDisabled()) { + throw new SkippedException("Skipped -- This test is not applicable when JTREG tests are executed with -Xshare:off, or if the JDK doesn't have a default archive."); + } + if (args.length != 1 || (!args[0].equals("verifySharedSpacesOff") && !args[0].equals("verifySharedSpacesOn"))) { + throw new RuntimeException("Must run with verifySharedSpacesOff or verifySharedSpacesOn"); + } + verifyOn = args[0].equals("verifySharedSpacesOn"); + runTest(TestAutoCreateSharedArchive::testAutoCreateSharedArchive); + } + + public static void checkFileExists(String fileName) throws Exception { + File file = new File(fileName); + if (!file.exists()) { + throw new IOException("Archive " + fileName + " is not automatically created"); + } + } + + public static String startNewArchive(String testName) { + String newArchiveName = TestCommon.getNewArchiveName(testName); + TestCommon.setCurrentArchiveName(newArchiveName); + return newArchiveName; + } + + public static void print(String message) { + System.out.println(message); + } + + private static void testAutoCreateSharedArchive() throws Exception { + String appJar = ClassFileInstaller.getJarPath("hello.jar"); + boolean fileModified = false; + + String verifySharedSpaces = verifyOn ? "-XX:+VerifySharedSpaces" : "-XX:-VerifySharedSpaces"; + File archiveFile = new File(TOP_NAME); + if (archiveFile.exists()) { + archiveFile.delete(); + } + + // dump a static archive, used later. + // 0. Dump a static archive + print("0. dump a static archive " + BASE_NAME); + dumpBaseArchive(BASE_NAME, + "-Xlog:cds", + "-cp", appJar, + mainAppClass) + .assertNormalExit(output -> { + output.shouldHaveExitValue(0); + }); + checkFileExists(BASE_NAME); + + // The list numbers try to match JDK-8272331 (CSR for JDK-8261455) test items but not exactly matched. + + // 10 non-existing archive should automatically create dynamic archive based on default shared archive + // if base archive loaded. + print("10 Test with default base shared archive"); + print(" 10.01 run with non-existing archive should automatically create dynamic archive"); + File fileTop = new File(TOP_NAME); + if (fileTop.exists()) { + fileTop.delete(); + } + run(TOP_NAME, + "-Xshare:auto", + "-XX:+AutoCreateSharedArchive", + "-Xlog:cds", + "-cp", appJar, + mainAppClass) + .assertNormalExit(output -> { + output.shouldHaveExitValue(0) + .shouldContain(HELLO_WORLD) + .shouldContain("Dumping shared data to file:") + .shouldContain(TOP_NAME); + }); + checkFileExists(TOP_NAME); + + //10.02 run with the created dynamic archive should pass + print(" 10.02 run with the created dynamic archive should pass"); + run(TOP_NAME, + "-Xlog:cds", + "-Xlog:class+load", + "-cp", appJar, + mainAppClass) + .assertNormalExit(output -> { + output.shouldHaveExitValue(0) + .shouldContain(HELLO_WORLD) + .shouldContain(HELLO_SOURCE); + }); + // remember the FileTime + FileTime ft1 = Files.getLastModifiedTime(Paths.get(TOP_NAME)); + + // 10.03 run with the created dynamic archive with -XX:+AutoCreateSharedArchive should pass + // archive should not be created again. + print(" 10.03 run with the created dynamic archive with -XX:+AutoCreateSharedArchive should pass"); + run(TOP_NAME, + "-Xlog:cds", + "-Xlog:class+load", + "-Xlog:cds+dynamic=info", + "-XX:+AutoCreateSharedArchive", + "-cp", appJar, + mainAppClass) + .assertNormalExit(output -> { + output.shouldHaveExitValue(0) + .shouldContain(HELLO_WORLD) + .shouldContain(HELLO_SOURCE) + .shouldNotContain("Dumping shared data to file"); + }); + FileTime ft2 = Files.getLastModifiedTime(Paths.get(TOP_NAME)); + fileModified = !ft2.equals(ft1); + if (fileModified) { + throw new RuntimeException("Archive file " + TOP_NAME + " should not be updated"); + } + + // 11 run with static archive + print("11 run with static archive"); + ft1 = Files.getLastModifiedTime(Paths.get(BASE_NAME)); + run(BASE_NAME, + "-Xlog:cds", + "-Xlog:cds+dynamic=info", + "-Xshare:auto", + "-XX:+AutoCreateSharedArchive", + verifySharedSpaces, + "-cp", appJar, + mainAppClass) + .assertNormalExit(output -> { + output.shouldHaveExitValue(0) + .shouldContain(HELLO_WORLD) + .shouldContain("AutoCreateSharedArchive is ignored because " + BASE_NAME + " is a static archive") + .shouldNotContain("Dumping shared data to file"); + }); + ft2 = Files.getLastModifiedTime(Paths.get(BASE_NAME)); + fileModified = !ft1.equals(ft2); + if (fileModified) { + throw new RuntimeException("Run -XX:+AutoCreateSharedArchive on static archive create new archive"); + } + + // 12 run with damaged magic should not regenerate dynamic archive + print("12 run with damaged magic should not regenerate dynamic archive"); + String modMagic = startNewArchive("modify-magic"); + File copiedJsa = CDSArchiveUtils.copyArchiveFile(archiveFile, modMagic); + CDSArchiveUtils.modifyHeaderIntField(copiedJsa, CDSArchiveUtils.offsetMagic(), 0x1234); + ft1 = Files.getLastModifiedTime(Paths.get(modMagic)); + + run(modMagic, + "-Xshare:auto", + "-XX:+AutoCreateSharedArchive", + "-Xlog:cds", + "-Xlog:cds+dynamic=info", + verifySharedSpaces, + "-cp", appJar, + mainAppClass) + .assertNormalExit(output -> { + output.shouldHaveExitValue(0) + .shouldContain(HELLO_WORLD) + .shouldNotContain("Dumping shared data to file"); + }); + ft2 = Files.getLastModifiedTime(Paths.get(modMagic)); + fileModified = !ft1.equals(ft2); + if (fileModified) { + throw new RuntimeException("Shared archive " + modMagic + " should not automatically be generated"); + } + + // 13 run with a bad versioned (< genericHeaderMinVersion) archive + print("13 run with a bad versioned archive"); + print(" 13.01 run with a bad versioned (< genericHeaderMinVersion) archive should not create new archive"); + String modVersion = startNewArchive("modify-version-b"); + copiedJsa = CDSArchiveUtils.copyArchiveFile(archiveFile, modVersion); + final int version1 = genericHeaderMinVersion - 1; + CDSArchiveUtils.modifyHeaderIntField(copiedJsa, CDSArchiveUtils.offsetVersion(), version1); + ft1 = Files.getLastModifiedTime(Paths.get(modVersion)); + + run(modVersion, + "-Xshare:auto", + "-XX:+AutoCreateSharedArchive", + "-Xlog:cds", + "-Xlog:cds+dynamic=info", + verifySharedSpaces, + "-cp", appJar, + mainAppClass) + .assertNormalExit(output -> { + output.shouldHaveExitValue(0) + .shouldContain(HELLO_WORLD) + .shouldContain("Cannot handle shared archive file version " + version1 + ". Must be at least " + genericHeaderMinVersion) + .shouldContain("Unable to use shared archive: invalid archive") + .shouldNotContain("Dumping shared data to file"); + }); + ft2 = Files.getLastModifiedTime(Paths.get(modVersion)); + fileModified = !ft1.equals(ft2); + if (fileModified) { + throw new RuntimeException("Run -XX:+AutoCreateSharedArchive with lower version archive " + modVersion + " should not create new archive"); + } + // 13.02 run with a bad versioned (> currentCDSVersion) archive + print(" 13.02 run with a bad versioned (> currentCDSVersion) archive"); + modVersion = startNewArchive("modify-version-d"); + copiedJsa = CDSArchiveUtils.copyArchiveFile(archiveFile, modVersion); + final int version2 = currentCDSVersion + 1; + CDSArchiveUtils.modifyHeaderIntField(copiedJsa, CDSArchiveUtils.offsetVersion(), version2); + ft1 = Files.getLastModifiedTime(Paths.get(modVersion)); + + run(modVersion, + "-Xshare:auto", + "-XX:+AutoCreateSharedArchive", + "-Xlog:cds", + "-Xlog:cds+dynamic=info", + verifySharedSpaces, + "-cp", appJar, + mainAppClass) + .assertNormalExit(output -> { + output.shouldHaveExitValue(0) + .shouldContain(HELLO_WORLD) + .shouldContain("The shared archive file version " + version2 + " does not match the required version " + currentCDSVersion) + .shouldContain("UseSharedSpaces: The shared archive file has the wrong version") + .shouldContain("UseSharedSpaces: Initialize dynamic archive failed") + .shouldContain("Dumping shared data to file"); + }); + ft2 = Files.getLastModifiedTime(Paths.get(modVersion)); + fileModified = !ft1.equals(ft2); + if (!fileModified) { + throw new RuntimeException("Run -XX:+AutoCreateSharedArchive with higher version archive " + modVersion + " should create new archive"); + } + + // 14 run with an archive whose base name is not matched, no share + print("14 run with an archive whose base name is not matched, no share"); + String baseNameMismatch= startNewArchive("basename-mismatch"); + copiedJsa = CDSArchiveUtils.copyArchiveFile(archiveFile, baseNameMismatch); + int nameSize = CDSArchiveUtils.baseArchiveNameSize(copiedJsa); + int offset = CDSArchiveUtils.baseArchiveNameOffset(copiedJsa); + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < nameSize - 4; i++) { + sb.append('Z'); + } + sb.append(".jsa"); + sb.append('\0'); + String newName = sb.toString(); + CDSArchiveUtils.writeData(copiedJsa, offset, newName.getBytes()); + + ft1 = Files.getLastModifiedTime(Paths.get(baseNameMismatch)); + run(baseNameMismatch, + "-Xshare:auto", + "-XX:+AutoCreateSharedArchive", + "-Xlog:cds", + "-Xlog:cds+dynamic=info", + verifySharedSpaces, + "-cp", appJar, + mainAppClass) + .assertNormalExit(output -> { + output.shouldHaveExitValue(0) + .shouldContain(HELLO_WORLD) + .shouldNotContain("Dumping shared data to file"); + }); + ft2 = Files.getLastModifiedTime(Paths.get(baseNameMismatch)); + + fileModified = !ft1.equals(ft2); + if (fileModified) { + throw new RuntimeException("Shared archive " + baseNameMismatch+ " should not automatically be generated"); + } + + // 15 mismatched jvm_indent in archive, create (-VerifySharedSpaces) or not (-XX:+VerifySharedSpaces) create the new archive + print("15 mismatched jvm_indent in archive, " + (verifyOn ? "-XX:+VerifySharedSpaces not " : "-XX:-VerifySharedSpaces ") + "create new archive"); + String modJvmIdent = startNewArchive("modify-jvmident"); + copiedJsa = CDSArchiveUtils.copyArchiveFile(archiveFile, modJvmIdent); + CDSArchiveUtils.modifyHeaderIntField(copiedJsa, CDSArchiveUtils.offsetJvmIdent(), 0x65656565); + ft1 = Files.getLastModifiedTime(Paths.get(modJvmIdent)); + + run(modJvmIdent, + "-Xshare:auto", + "-XX:+AutoCreateSharedArchive", + "-Xlog:cds", + "-Xlog:cds+dynamic=info", + verifySharedSpaces, + "-cp", appJar, + mainAppClass) + .assertNormalExit(output -> { + output.shouldHaveExitValue(0); + if (verifyOn) { + output.shouldContain("UseSharedSpaces: Header checksum verification failed") + .shouldContain("Unable to use shared archive: invalid archive") + .shouldNotContain("Dumping shared data to file"); + } else { + output.shouldContain(HELLO_WORLD) + .shouldContain("Dumping shared data to file"); + } + }); + ft2 = Files.getLastModifiedTime(Paths.get(modJvmIdent)); + fileModified = !ft1.equals(ft2); + if (verifyOn) { + if (fileModified) { + throw new RuntimeException("Shared archive " + modJvmIdent + " should not be generated"); + } + + } else { + if (!fileModified) { + throw new RuntimeException("Shared archive " + modJvmIdent + " should be generated"); + } + } + + // 16 run with an archive of only containing dynamic magic (size of 4) will not create new archive at exit + print("16 run with an archive of only containing dynamic magic (size of 4) will not create new archive at exit"); + String magicOnly = startNewArchive("magic-only"); + copiedJsa = CDSArchiveUtils.createMagicOnlyFile(magicOnly, false/*dynamic*/); + ft1 = Files.getLastModifiedTime(Paths.get(magicOnly)); + run(magicOnly, + "-Xshare:auto", + "-XX:+AutoCreateSharedArchive", + "-Xlog:cds", + "-Xlog:cds+dynamic=info", + "-cp", appJar, + mainAppClass) + .assertNormalExit(output -> { + output.shouldHaveExitValue(0) + .shouldContain(HELLO_WORLD) + .shouldContain("Unable to read generic CDS file map header from shared archive") + .shouldNotContain("Dumping shared data to file:"); + }); + ft2 = Files.getLastModifiedTime(Paths.get(magicOnly)); + fileModified = !ft1.equals(ft2); + if (fileModified) { + throw new RuntimeException("Shared archive " + magicOnly + " should not automatically be generated"); + } + + // Do some base tests for -XX:SharedArchiveFile=base:top, they should be same as default archive as base. + // delete top archive + if (archiveFile.exists()) { + archiveFile.delete(); + } + // delete base archive + File baseFile = new File(BASE_NAME); + if (baseFile.exists()) { + baseFile.delete(); + } + + // 20 Testing with -XX:SharedArchiveFile=base:top + print("20 Testing with -XX:SharedArchiveFile=base:top"); + // 20.01 dump base archive and top archive + print(" 20.01 dump base archive " + BASE_NAME); + dumpBaseArchive(BASE_NAME, "-Xlog:cds") + .assertNormalExit(output -> { + output.shouldHaveExitValue(0); + }); + checkFileExists(BASE_NAME); + + // 20.02 dump top based on base + print(" 20.02 dump top based on base"); + dump2(BASE_NAME, TOP_NAME, + "-Xlog:cds", + "-cp", appJar, mainAppClass) + .assertNormalExit(output -> { + output.shouldHaveExitValue(0) + .shouldContain("Dumping shared data to file:") + .shouldContain(TOP_NAME); + }); + checkFileExists(TOP_NAME); + + // 20.03 run with -XX:SharedArchveFile=base:top + print(" 20.03 run with -XX:SharedArchveFile=base:top"); + run2(BASE_NAME, TOP_NAME, + "-Xlog:cds", + "-Xlog:cds+dynamic=info", + "-Xlog:class+load", + "-cp", appJar, + mainAppClass) + .assertNormalExit(output -> { + output.shouldHaveExitValue(0) + .shouldContain(HELLO_SOURCE); + }); + + // 20.04 run with -XX:SharedArchveFile=top:base (reversed) + print(" 20.04 run with -XX:SharedArchveFile=top:base (reversed)"); + run2(TOP_NAME, BASE_NAME, + "-Xlog:cds", + "-Xlog:cds+dynamic=info", + "-Xlog:class+load", + "-cp", appJar, + mainAppClass) + .assertAbnormalExit(output -> { + output.shouldHaveExitValue(1) + .shouldContain("Not a base shared archive: " + TOP_NAME) + .shouldContain("An error has occurred while processing the shared archive file") + .shouldNotContain(HELLO_WORLD); + }); + + // 21 Mismatched versions + print("21 Mismatched versions"); + // 21.01 top version is lower than CDS_GENERIC_HEADER_SUPPORTED_MIN_VERSION, regenerate top + print(" 21.01 top version is lower than CDS_GENERIC_HEADER_SUPPORTED_MIN_VERSION, regenerate top"); + String versionB = startNewArchive("modify-version-B"); + archiveFile = new File(TOP_NAME); + copiedJsa = CDSArchiveUtils.copyArchiveFile(archiveFile, versionB); + CDSArchiveUtils.modifyHeaderIntField(copiedJsa, CDSArchiveUtils.offsetVersion(), version1); + ft1 = Files.getLastModifiedTime(Paths.get(versionB)); + + run2(BASE_NAME, versionB, + "-Xshare:auto", + "-XX:+AutoCreateSharedArchive", + "-Xlog:cds", + "-Xlog:cds+dynamic=info", + verifySharedSpaces, + "-cp", appJar, + mainAppClass) + .assertNormalExit(output -> { + output.shouldHaveExitValue(0) + .shouldContain(HELLO_WORLD) + .shouldContain("Cannot handle shared archive file version " + version1) + .shouldContain(versionB) + .shouldContain("Dumping shared data to file:"); + }); + ft2 = Files.getLastModifiedTime(Paths.get(versionB)); + fileModified = !ft1.equals(ft2); + if (!fileModified) { + throw new RuntimeException("Shared archive " + versionB + " should automatically be generated"); + } + + // 21.02 top version is higher than CDS_GENERIC_HEADER_SUPPORTED_MIN_VERSION, no share for top, create archive at exit + print(" 21.02 top version is higher than CDS_GENERIC_HEADER_SUPPORTED_MIN_VERSION, no share for top, create archive at exit"); + String versionF = startNewArchive("versionF"); + copiedJsa = CDSArchiveUtils.copyArchiveFile(archiveFile, versionF); + CDSArchiveUtils.modifyHeaderIntField(copiedJsa, CDSArchiveUtils.offsetVersion(), version2); + ft1 = Files.getLastModifiedTime(Paths.get(versionF)); + run2(BASE_NAME, versionF, + "-Xshare:auto", + "-XX:+AutoCreateSharedArchive", + "-Xlog:cds", + "-Xlog:cds+dynamic=info", + verifySharedSpaces, + "-cp", appJar, + mainAppClass) + .assertNormalExit(output -> { + output.shouldContain("The shared archive file version " + version2 + " does not match the required version " + currentCDSVersion) + .shouldContain(HELLO_WORLD) + .shouldContain("Dumping shared data to file:"); + }); + ft2 = Files.getLastModifiedTime(Paths.get(versionB)); + fileModified = !ft1.equals(ft2); + if (!fileModified) { + throw new RuntimeException("Shared archive " + versionB + " should be created at exit"); + } + + // 22 create an archive with dynamic magic number only + // archive will be created at exit if base can be shared. + print("22 create an archive with dynamic magic number only"); + copiedJsa = CDSArchiveUtils.createMagicOnlyFile(magicOnly, false /*dynamic*/); + ft1 = Files.getLastModifiedTime(Paths.get(magicOnly)); + run2(BASE_NAME, magicOnly, + "-Xshare:auto", + "-XX:+AutoCreateSharedArchive", + "-Xlog:cds", + "-Xlog:cds+dynamic=info", + verifySharedSpaces, + "-cp", appJar, + mainAppClass) + .assertNormalExit(output -> { + output.shouldContain(HELLO_WORLD) + .shouldContain("Unable to read generic CDS file map header from shared archive") + .shouldContain("Dumping shared data to file:"); + }); + ft2 = Files.getLastModifiedTime(Paths.get(magicOnly)); + fileModified = !ft1.equals(ft2); + if (!fileModified) { + throw new RuntimeException("Shared archive " + magicOnly + " should be created at exit"); + } + + // 23 mismatched jvm_indent in top or base archive + // 23.01 mismatched jvm_indent in top archive + print(" 23.01 mismatched jvm_indent in top archive"); + String modJvmIdentTop = startNewArchive("modify-jvmident-top"); + copiedJsa = CDSArchiveUtils.copyArchiveFile(archiveFile, modJvmIdentTop); + CDSArchiveUtils.modifyHeaderIntField(copiedJsa, CDSArchiveUtils.offsetJvmIdent(), 0x65656565); + ft1 = Files.getLastModifiedTime(Paths.get(modJvmIdentTop)); + + run2(BASE_NAME, modJvmIdentTop, + "-Xshare:auto", + "-XX:+AutoCreateSharedArchive", + "-Xlog:cds", + "-Xlog:cds+dynamic=info", + verifySharedSpaces, + "-cp", appJar, + mainAppClass) + .assertNormalExit(output -> { + output.shouldHaveExitValue(0); + if (verifyOn) { + output.shouldContain("UseSharedSpaces: Header checksum verification failed"); + } + output.shouldContain(HELLO_WORLD) + .shouldContain("Dumping shared data to file"); + }); + ft2 = Files.getLastModifiedTime(Paths.get(modJvmIdentTop)); + fileModified = !ft1.equals(ft2); + if (!fileModified) { + throw new RuntimeException("Shared archive " + modJvmIdentTop + " should be generated"); + } + // 23.02 mismatched jvm_indent in base archive + print(" 23.02 mismatched jvm_indent in base archive"); + String modJvmIdentBase = startNewArchive("modify-jvmident-base"); + copiedJsa = CDSArchiveUtils.copyArchiveFile(new File(BASE_NAME), modJvmIdentBase); + CDSArchiveUtils.modifyHeaderIntField(copiedJsa, CDSArchiveUtils.offsetJvmIdent(), 0x65656565); + ft1 = Files.getLastModifiedTime(Paths.get(TOP_NAME)); + + run2(modJvmIdentBase, TOP_NAME, + "-Xshare:auto", + "-XX:+AutoCreateSharedArchive", + "-Xlog:cds", + "-Xlog:cds+dynamic=info", + verifySharedSpaces, + "-cp", appJar, + mainAppClass) + .assertNormalExit(output -> { + output.shouldHaveExitValue(0) + .shouldContain(HELLO_WORLD); + if (verifyOn) { + output.shouldContain("UseSharedSpaces: Header checksum verification failed"); + } + output.shouldContain("Unable to map shared spaces") + .shouldNotContain("Dumping shared data to file"); + }); + ft2 = Files.getLastModifiedTime(Paths.get(TOP_NAME)); + fileModified = !ft1.equals(ft2); + if (fileModified) { + throw new RuntimeException("Shared archive " + TOP_NAME + " should not be generated"); + } + + // 24 run with non-existing shared archives + print("24 run with non-existing shared archives"); + // 24.01 run -Xshare:auto -XX:+AutoCreateSharedArchive -XX:SharedArchiveFile=base.jsa:non-exist-top.jsa + print(" 24.01 run -Xshare:auto -XX:+AutoCreateSharedArchive -XX:SharedArchiveFile=base.jsa:non-exist-top.jsa"); + String nonExistTop = "non-existing-top.jsa"; + File fileNonExist = new File(nonExistTop); + if (fileNonExist.exists()) { + fileNonExist.delete(); + } + run2(BASE_NAME, nonExistTop, + "-Xshare:auto", + "-XX:+AutoCreateSharedArchive", + "-Xlog:cds", + "-Xlog:cds+dynamic=info", + verifySharedSpaces, + "-cp", appJar, + mainAppClass) + .assertNormalExit(output -> { + output.shouldContain("Specified shared archive not found (" + nonExistTop + ")") + .shouldContain(HELLO_WORLD) + .shouldContain("Dumping shared data to file:"); + }); + if (!fileNonExist.exists()) { + throw new RuntimeException("Shared archive " + nonExistTop + " should be created at exit"); + } + + // 24.02 run -Xshare:auto -XX:+AutoCreateSharedArchive -XX:SharedArchiveFile=non-exist-base.jsa:top.jsa + print(" 24.02 run -Xshare:auto -XX:+AutoCreateSharedArchive -XX:SharedArchiveFile=non-exist-base.jsa:top.jsa"); + String nonExistBase = "non-existing-base.jsa"; + fileNonExist = new File(nonExistBase); + if (fileNonExist.exists()) { + fileNonExist.delete(); + } + ft1 = Files.getLastModifiedTime(Paths.get(TOP_NAME)); + run2(nonExistBase, TOP_NAME, + "-Xshare:auto", + "-XX:+AutoCreateSharedArchive", + "-Xlog:cds", + "-Xlog:cds+dynamic=info", + verifySharedSpaces, + "-cp", appJar, + mainAppClass) + .assertNormalExit(output -> { + output.shouldContain("Specified shared archive not found (" + nonExistBase + ")") + .shouldContain(HELLO_WORLD) + .shouldNotContain("Dumping shared data to file:"); + }); + ft2 = Files.getLastModifiedTime(Paths.get(TOP_NAME)); + fileModified = !ft1.equals(ft2); + if (fileModified) { + throw new RuntimeException("Shared archive " + TOP_NAME + " should not be created at exit"); + } + } +} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/TestAutoCreateSharedArchiveNoDefaultArchive.java b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/TestAutoCreateSharedArchiveNoDefaultArchive.java new file mode 100644 index 0000000000000000000000000000000000000000..d2db4a3b2ad76fabca96b92914a3eb9db4ef8962 --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/TestAutoCreateSharedArchiveNoDefaultArchive.java @@ -0,0 +1,147 @@ +/* + * 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. + * + */ + +/* + * @test + * @summary Test -XX:+AutoCreateSharedArchive on a copied JDK without default shared archive + * @bug 8261455 + * @requires vm.cds + * @requires vm.flagless + * @comment This test doesn't work on Windows because it depends on symlinks + * @requires os.family != "windows" + * @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds + * @compile ../test-classes/Hello.java + * @run driver TestAutoCreateSharedArchiveNoDefaultArchive + */ + +import java.io.File; +import jdk.test.lib.cds.CDSTestUtils; +import jdk.test.lib.process.OutputAnalyzer; + +public class TestAutoCreateSharedArchiveNoDefaultArchive { + public static void main(String[] args) throws Exception { + String mainClass = "Hello"; + String java_home_src = System.getProperty("java.home"); + String java_home_dst = CDSTestUtils.getOutputDir() + File.separator + "moved_jdk"; + CDSTestUtils.clone(new File(java_home_src), new File(java_home_dst)); + System.out.println("======== Cloned JDK at " + java_home_dst); + + String homeJava = java_home_src + File.separator + "bin" + File.separator + "java"; + String dstJava = java_home_dst + File.separator + "bin" + File.separator + "java"; + + TestCommon.startNewArchiveName(); + String jsaFileName = TestCommon.getCurrentArchiveName(); + File jsaFile = new File(jsaFileName); + if (jsaFile.exists()) { + jsaFile.delete(); + } + + String jsaOpt = "-XX:SharedArchiveFile=" + jsaFileName; + String autoCreateArchive = "-XX:+AutoCreateSharedArchive"; + { + ProcessBuilder pb = CDSTestUtils.makeBuilder(homeJava, + "-Xshare:dump", + jsaOpt); + TestCommon.executeAndLog(pb, "dump") + .shouldHaveExitValue(0); + } + { + ProcessBuilder pb = CDSTestUtils.makeBuilder(homeJava, + "-Xshare:auto", + jsaOpt, + "-Xlog:class+path=info", + "-version"); + OutputAnalyzer out = TestCommon.executeAndLog(pb, "exec-src"); + out.shouldHaveExitValue(0); + out.shouldNotContain("shared class paths mismatch"); + out.shouldNotContain("BOOT classpath mismatch"); + } + + String helloJar = JarBuilder.getOrCreateHelloJar(); + + if (jsaFile.exists()) { + jsaFile.delete(); + } + // Test runtime with cloned JDK + System.out.println("======== run with cloned jdk to created dynamic shared archive at exit"); + { + ProcessBuilder pb = CDSTestUtils.makeBuilder(dstJava, + "-Xshare:auto", + autoCreateArchive, + jsaOpt, + "-Xlog:cds", + "-Xlog:class+path=info", + "-cp", helloJar, + mainClass); + OutputAnalyzer out = TestCommon.executeAndLog(pb, "exec-dst"); + out.shouldHaveExitValue(0); + out.shouldContain("Dumping shared data to file"); + if (!jsaFile.exists()) { + throw new RuntimeException("Shared archive " + jsaFileName + " should be created at exit"); + } + } + + // Now rename classes.jsa to old-classes.jsa + String dstDir = java_home_dst + File.separator + "lib" + File.separator + "server"; + CDSTestUtils.rename(new File(dstDir + File.separator + "classes.jsa"), + new File(dstDir + File.separator + "old-classes.jsa")); + System.out.println("======= renamed classes.jsa to old-classes.jsa"); + + { + ProcessBuilder pb = CDSTestUtils.makeBuilder(dstJava, + "-Xlog:cds", + "-version"); + TestCommon.executeAndLog(pb, "show-version") + .shouldHaveExitValue(0) + .shouldContain("UseSharedSpaces: Initialize static archive failed") + .shouldContain("UseSharedSpaces: Unable to map shared spaces") + .shouldContain("mixed mode") + .shouldNotContain("sharing"); + } + // delete existing jsa file + if (jsaFile.exists()) { + jsaFile.delete(); + } + System.out.println("======= run with no default shared archive should not create shared archive at exit"); + { + ProcessBuilder pb = CDSTestUtils.makeBuilder(dstJava, + "-Xshare:auto", + autoCreateArchive, + jsaOpt, + "-Xlog:cds", + "-Xlog:class+path=info", + "-cp", helloJar, + mainClass); + TestCommon.executeAndLog(pb, "no-default-archive") + .shouldHaveExitValue(0) + .shouldContain("UseSharedSpaces: Initialize static archive failed") + .shouldContain("UseSharedSpaces: Unable to map shared spaces") + .shouldNotContain("Dumping shared data to file"); + if (jsaFile.exists()) { + throw new RuntimeException("Archive file " + jsaFileName + " should not be created at exit"); + } + } + + } +} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/TestLambdaInvokers.java b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/TestLambdaInvokers.java new file mode 100644 index 0000000000000000000000000000000000000000..69a8d4219e22c844edcdd1b3145ef2766b58d346 --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/TestLambdaInvokers.java @@ -0,0 +1,73 @@ +/* + * 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. + * + */ + +/* + * @test + * @key randomness + * @summary test archive lambda invoker species type in dynamic dump + * @bug 8280767 + * @requires vm.cds + * @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds /test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive + * @compile CDSLambdaInvoker.java + * @build sun.hotspot.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar cds-test.jar CDSLambdaInvoker + * @run driver jdk.test.lib.helpers.ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. TestLambdaInvokers + */ + +public class TestLambdaInvokers extends DynamicArchiveTestBase { + private static final String mainClass = "CDSLambdaInvoker"; + private static final String jarFile = "cds-test.jar"; + private static void doTest(String topArchiveName) throws Exception { + dump(topArchiveName, + "-Xlog:cds", + "-Xlog:cds+dynamic=debug", + "-cp", + jarFile, + mainClass) + .assertNormalExit(output -> { + output.shouldContain("Skip regenerating for shared"); + }); + run(topArchiveName, + "-Xlog:cds", + "-Xlog:cds+dynamic=debug", + "-Xlog:class+load", + "-cp", + jarFile, + mainClass) + .assertNormalExit(output -> { + // java.lang.invoke.BoundMethodHandle$Species_JL is generated from CDSLambdaInvoker + output.shouldContain("java.lang.invoke.BoundMethodHandle$Species_JL source: shared objects file (top)"); + }); + } + + static void testWithDefaultBase() throws Exception { + String topArchiveName = getNewArchiveName("top"); + doTest(topArchiveName); + } + + public static void main(String[] args) throws Exception { + runTest(TestLambdaInvokers::testWithDefaultBase); + } +} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/UnsupportedBaseArchive.java b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/UnsupportedBaseArchive.java index a6027354e25fd55d0e7cdc3ebd5268ab42cbd587..6a34bcc31926c5dc8e08d6a8f6a5ae325233f59a 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/UnsupportedBaseArchive.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/UnsupportedBaseArchive.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -62,7 +62,7 @@ public class UnsupportedBaseArchive extends DynamicArchiveTestBase { "Dynamic archiving is disabled because base layer archive has appended boot classpath"; private static final String warningModulePath = - "Dynamic archiving is disabled because base layer archive has module path"; + "Dynamic archiving is disabled because base layer archive has a different module path"; public static void buildTestModule() throws Exception { @@ -104,22 +104,23 @@ public class UnsupportedBaseArchive extends DynamicArchiveTestBase { // create a base archive with the --module-path option buildTestModule(); baseArchiveName = getNewArchiveName("base-with-module"); + String appClasses[] = {mainClass}; TestCommon.dumpBaseArchive(baseArchiveName, - "-cp", srcJar.toString(), + appClasses, + "-Xlog:class+load", + "-cp", appJar, "--module-path", moduleDir.toString(), "-m", TEST_MODULE); - // dumping of dynamic archive should be disabled with a warning message - // if the base archive contains --module-path entries. - topArchiveName = getNewArchiveName("top-with-module"); + // Try to create a dynamic archive without specifying module path, + // dumping should fail. + topArchiveName = getNewArchiveName("top-with-module-failed"); dump2(baseArchiveName, topArchiveName, "-Xlog:cds*", "-Xlog:cds+dynamic=debug", - "-Xlog:class+path=info", - "-cp", srcJar.toString(), - "--module-path", moduleDir.toString(), - "-m", TEST_MODULE) + "-Xlog:class+path=info,class+load", + "-cp", appJar, + mainClass) .assertNormalExit(warningModulePath); - } } diff --git a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/test-classes/CustomLoaderApp.java b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/test-classes/CustomLoaderApp.java index ebc9350c57e8c3764bac3e245fec44ee48c6957f..37dcdbfdf1e31d41ccf55ce054dcf60148f871f9 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/test-classes/CustomLoaderApp.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/test-classes/CustomLoaderApp.java @@ -28,6 +28,8 @@ import java.net.URLClassLoader; public class CustomLoaderApp { private static String className = "LambHello"; + // Prevent the class from being GC'ed too soon. + private static Class keptC = null; public static void main(String args[]) throws Exception { String path = args[0]; @@ -37,13 +39,25 @@ public class CustomLoaderApp { System.out.println(url); boolean init = false; - if (args.length ==2 && args[1].equals("init")) { + if (args.length >= 2 && args[1].equals("init")) { init = true; } + // The dynamicArchive/LambdaCustomLoader.java test passes the keep-alive + // argument for preventing the class from being GC'ed prior to dumping of + // the dynamic CDS archive. + boolean keepAlive = false; + if (args[args.length - 1].equals("keep-alive")) { + keepAlive = true; + } + URLClassLoader urlClassLoader = new URLClassLoader("HelloClassLoader", urls, null); Class c = Class.forName(className, init, urlClassLoader); + if (keepAlive) { + keptC = c; + } + System.out.println(c); System.out.println(c.getClassLoader()); if (c.getClassLoader() != urlClassLoader) { diff --git a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/test-classes/LotsUnloadApp.java b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/test-classes/LotsUnloadApp.java new file mode 100644 index 0000000000000000000000000000000000000000..8ac9275af2c0fa954448844f31ba0b3a047634a9 --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/test-classes/LotsUnloadApp.java @@ -0,0 +1,84 @@ +/* + * 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 java.lang.invoke.MethodType; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodHandles.Lookup; +import static java.lang.invoke.MethodHandles.Lookup.ClassOption.*; + +public class LotsUnloadApp implements Runnable { + static byte[] classdata; + static int exitAfterNumClasses = 1024; + + public static void main(String args[]) throws Throwable { + String resname = DefinedAsHiddenKlass.class.getName() + ".class"; + classdata = LotsUnloadApp.class.getClassLoader().getResourceAsStream(resname).readAllBytes(); + + int numThreads = 4; + try { + numThreads = Integer.parseInt(args[0]); + } catch (Throwable t) {} + + try { + exitAfterNumClasses = Integer.parseInt(args[1]); + } catch (Throwable t) {} + + for (int i = 0; i < numThreads; i++) { + Thread t = new Thread(new LotsUnloadApp()); + t.start(); + } + } + + public void run() { + while (true) { + try { + Lookup lookup = MethodHandles.lookup(); + Class<?> cl = lookup.defineHiddenClass(classdata, false, NESTMATE).lookupClass(); + cl.newInstance(); + add(); + } catch (Throwable t) { + t.printStackTrace(); + } + } + } + + static int n; + static synchronized void add() { + n++; + if (n >= exitAfterNumClasses) { + System.exit(0); + } + } +} + +class DefinedAsHiddenKlass { + // ZGC region size is always a multiple of 2MB on x64. + // Make this slightly smaller than that. + static byte[] array = new byte[2 * 1024 * 1024 - 8 * 1024]; + static String x; + public DefinedAsHiddenKlass() { + // This will generate some lambda forms hidden classes for string concat. + x = "array size is " + array.length + " bytes "; + } +} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/javaldr/LockDuringDump.java b/test/hotspot/jtreg/runtime/cds/appcds/javaldr/LockDuringDump.java index 04652d2eb782a8f3a943b1e626d0383099f9ad02..391596160d6b65b530357af9fc106c508d793181 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/javaldr/LockDuringDump.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/javaldr/LockDuringDump.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -68,7 +68,7 @@ public class LockDuringDump { TestCommon.testDump(appJar, TestCommon.list(LockDuringDumpApp.class.getName()), "-XX:+UnlockDiagnosticVMOptions", agentArg, agentArg2); - if (i != 0) { + if (i != 0 && !out.getStdout().contains("LockDuringDumpAgent timeout")) { out.shouldContain("Let's hold the lock on the literal string"); } diff --git a/test/hotspot/jtreg/runtime/cds/appcds/javaldr/LockDuringDumpAgent.java b/test/hotspot/jtreg/runtime/cds/appcds/javaldr/LockDuringDumpAgent.java index 5e053d83efcf03158575d4db66cf6f31b9e9abd7..57db61e9335c2d19cdb8f62c2b2086aba2ba1312 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/javaldr/LockDuringDumpAgent.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/javaldr/LockDuringDumpAgent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -51,9 +51,21 @@ public class LockDuringDumpAgent implements Runnable { static void waitForThreadStart() { try { + long started = System.currentTimeMillis(); + long timeout = 10000; + synchronized (LITERAL) { + Thread.sleep(1); + } synchronized (lock) { while (!threadStarted) { - lock.wait(); + lock.wait(timeout); + long elapsed = System.currentTimeMillis() - started; + if (elapsed >= timeout) { + System.out.println("This JVM may decide to not launch any Java threads during -Xshare:dump."); + System.out.println("This is OK because no string objects could be in a locked state during heap dump."); + System.out.println("LockDuringDumpAgent timeout after " + elapsed + " ms"); + return; + } } System.out.println("Thread has started"); } diff --git a/test/hotspot/jtreg/runtime/cds/appcds/jcmd/JCmdTestDumpBase.java b/test/hotspot/jtreg/runtime/cds/appcds/jcmd/JCmdTestDumpBase.java index 75103a50ed491a12c3b049491d3eb3597511d3a7..5e56d3a96e8d983fee61acda6b75603dc204fc7b 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/jcmd/JCmdTestDumpBase.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/jcmd/JCmdTestDumpBase.java @@ -96,7 +96,7 @@ public abstract class JCmdTestDumpBase { } private static void checkCDSEnabled() throws Exception { - boolean cdsEnabled = WhiteBox.getWhiteBox().getBooleanVMFlag("UseSharedSpaces"); + boolean cdsEnabled = WhiteBox.getWhiteBox().isSharingEnabled(); if (!cdsEnabled) { throw new SkippedException("CDS is not available for this JDK."); } diff --git a/test/hotspot/jtreg/runtime/cds/appcds/jcmd/JCmdTestDynamicDump.java b/test/hotspot/jtreg/runtime/cds/appcds/jcmd/JCmdTestDynamicDump.java index febc70aea0e6be81298522a7a57096cf6645a20e..61ec63258549b2be6511fba3d2089b5e422d2b80 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/jcmd/JCmdTestDynamicDump.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/jcmd/JCmdTestDynamicDump.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -81,20 +81,13 @@ public class JCmdTestDynamicDump extends JCmdTestDumpBase { test(null, pid, noBoot, EXPECT_PASS, DYNAMIC_MESSAGES); app.stopApp(); - // Test dynamic dump with flags -XX:+RecordDynamicDumpInfo -XX:-DynamicDumpSharedSpaces. - print2ln(test_count++ + " Test dynamic dump with flags -XX:+RecordDynamicDumpInfo -XX:-DynamicDumpSharedSpaces."); - app = createLingeredApp("-cp", allJars, "-XX:+RecordDynamicDumpInfo", "-XX:-DynamicDumpSharedSpaces"); + // Test dynamic dump with flag -XX:+RecordDynamicDumpInfo + print2ln(test_count++ + " Test dynamic dump with flag -XX:+RecordDynamicDumpInfo."); + app = createLingeredApp("-cp", allJars, "-XX:+RecordDynamicDumpInfo"); pid = app.getPid(); test(null, pid, noBoot, EXPECT_PASS, DYNAMIC_MESSAGES); app.stopApp(); - // Test dynamic dump with flags -XX:-DynamicDumpSharedSpaces -XX:+RecordDynamicDumpInfo. - print2ln(test_count++ + " Test dynamic dump with flags -XX:-DynamicDumpSharedSpaces -XX:+RecordDynamicDumpInfo."); - app = createLingeredApp("-cp", allJars, "-XX:-DynamicDumpSharedSpaces", "-XX:+RecordDynamicDumpInfo"); - pid = app.getPid(); - test(null, pid, noBoot, EXPECT_PASS, DYNAMIC_MESSAGES); - app.stopApp(); - // Test dynamic with -Xbootclasspath/a:boot.jar print2ln(test_count++ + " Test dynamic with -Xbootclasspath/a:boot.jar"); app = createLingeredApp("-cp", testJar, "-Xbootclasspath/a:" + bootJar, "-XX:+RecordDynamicDumpInfo"); @@ -124,6 +117,17 @@ public class JCmdTestDynamicDump extends JCmdTestDumpBase { throw new RuntimeException("The JCmdTestLingeredApp should not start up!"); } } + // Test dynamic dump with -Xlog:cds to check lambda invoker class regeneration + print2ln(test_count++ + " Test dynamic dump with -Xlog:cds to check lambda invoker class regeneration"); + app = createLingeredApp("-cp", allJars, "-XX:+RecordDynamicDumpInfo", "-Xlog:cds", + "-XX:SharedArchiveFile=" + archiveFile); + pid = app.getPid(); + test(null, pid, noBoot, EXPECT_PASS, DYNAMIC_MESSAGES); + String stdout = app.getProcessStdout(); + if (stdout.contains("Regenerate MethodHandle Holder classes...")) { + throw new RuntimeException("jcmd VM.cds dynamic_dump should not regenerate MethodHandle Holder classes"); + } + app.stopApp(); } // Dump a static archive, not using TestCommon.dump(...), we do not take jtreg args. diff --git a/test/hotspot/jtreg/runtime/cds/appcds/jcmd/JCmdTestFileSafety.java b/test/hotspot/jtreg/runtime/cds/appcds/jcmd/JCmdTestFileSafety.java index e6312521d157d313cbc47d0da8382af357000b83..e5e2c676947d0a281f85397940c5bccde76921c1 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/jcmd/JCmdTestFileSafety.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/jcmd/JCmdTestFileSafety.java @@ -38,6 +38,9 @@ import java.io.File; import java.io.IOException; +import java.nio.file.attribute.FileTime; +import java.nio.file.Files; +import java.nio.file.Paths; import jdk.test.lib.cds.CDSTestUtils; import jdk.test.lib.apps.LingeredApp; import jdk.test.lib.Platform; @@ -61,6 +64,13 @@ public class JCmdTestFileSafety extends JCmdTestDumpBase { } } + private static void removeFile(String fileName) throws Exception { + File file = new File(fileName); + if (file.exists()) { + file.delete(); + } + } + static void test() throws Exception { buildJars(); @@ -75,6 +85,8 @@ public class JCmdTestFileSafety extends JCmdTestDumpBase { } outputDirFile.setWritable(true); String localFileName = subDir + File.separator + "MyStaticDump.jsa"; + removeFile(localFileName); + setIsStatic(true/*static*/); // Set target dir not writable, do static dump print2ln(test_count++ + " Set target dir not writable, do static dump"); @@ -82,10 +94,16 @@ public class JCmdTestFileSafety extends JCmdTestDumpBase { app = createLingeredApp("-cp", allJars); pid = app.getPid(); test(localFileName, pid, noBoot, EXPECT_PASS); + checkFileExistence(localFileName, true/*exist*/); + FileTime ft1 = Files.getLastModifiedTime(Paths.get(localFileName)); outputDirFile.setWritable(false); test(localFileName, pid, noBoot, EXPECT_FAIL); + FileTime ft2 = Files.getLastModifiedTime(Paths.get(localFileName)); + if (!ft2.equals(ft1)) { + throw new RuntimeException("Archive file " + localFileName + " should not be updated"); + } + removeFile(localFileName); outputDirFile.setWritable(true); - checkFileExistence(localFileName, true/*exist*/); // Illegal character in file name localFileName = "mystatic:.jsa"; @@ -103,18 +121,17 @@ public class JCmdTestFileSafety extends JCmdTestDumpBase { pid = app.getPid(); localFileName = subDir + File.separator + "MyDynamicDump.jsa"; test(localFileName, pid, noBoot, EXPECT_PASS); - app.stopApp(); - // cannot dynamically dump twice, restart - app = createLingeredApp("-cp", allJars, "-XX:+RecordDynamicDumpInfo"); - pid = app.getPid(); + checkFileExistence(localFileName, true/*exist*/); + ft1 = Files.getLastModifiedTime(Paths.get(localFileName)); outputDirFile.setWritable(false); test(localFileName, pid, noBoot, EXPECT_FAIL); - outputDirFile.setWritable(true); + ft2 = Files.getLastModifiedTime(Paths.get(localFileName)); + if (!ft2.equals(ft1)) { + throw new RuntimeException("Archive file " + localFileName + " should not be updated"); + } app.stopApp(); - // MyDynamicDump.jsa should exist - checkFileExistence(localFileName, true); - File rmFile = new File(localFileName); - rmFile.delete(); + removeFile(localFileName); + outputDirFile.setWritable(true); outputDirFile.delete(); } diff --git a/test/hotspot/jtreg/runtime/cds/appcds/jcmd/JCmdTestStaticDump.java b/test/hotspot/jtreg/runtime/cds/appcds/jcmd/JCmdTestStaticDump.java index 2ac55b824a9f48d21c47f8668c6f47b44c214fb1..d232f936a0cf9a8f0c20d081ab99907dfadb8259 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/jcmd/JCmdTestStaticDump.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/jcmd/JCmdTestStaticDump.java @@ -45,25 +45,19 @@ public class JCmdTestStaticDump extends JCmdTestDumpBase { "LingeredApp source: shared objects file", "Hello source: shared objects file"}; - // Those two flags will not create a successful LingeredApp. + // This flag will not create a successful LingeredApp. private static String[] noDumpFlags = - {"-XX:+DumpSharedSpaces", - "-Xshare:dump"}; + {"-Xshare:dump"}; // Those flags will be excluded in static dumping, // See src/java.base/share/classes/jdk/internal/misc/CDS.java private static String[] excludeFlags = { "-XX:DumpLoadedClassList=AnyFileName.classlist", - // this flag just dump archive, won't run app normally. - // "-XX:+DumpSharedSpaces", - "-XX:+DynamicDumpSharedSpaces", "-XX:+RecordDynamicDumpInfo", "-Xshare:on", "-Xshare:auto", "-XX:SharedClassListFile=non-exist.classlist", "-XX:SharedArchiveFile=non-exist.jsa", - "-XX:ArchiveClassesAtExit=tmp.jsa", - "-XX:+UseSharedSpaces", - "-XX:+RequireSharedSpaces"}; + "-XX:ArchiveClassesAtExit=tmp.jsa"}; // Times to dump cds against same process. private static final int ITERATION_TIMES = 2; 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 189559a46618dd2b72bd672f88ef164a640549ab..eecc218a71aa305d270596a5b3a8c03f7c4ad040 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/jigsaw/modulepath/OptimizeModuleHandlingTest.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/jigsaw/modulepath/OptimizeModuleHandlingTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -219,6 +219,16 @@ public class OptimizeModuleHandlingTest { "-Xbootclasspath/a:", ".", "--module-path", libsDir.toString(), MAIN_CLASS) + .assertAbnormalExit(out -> { + out.shouldNotContain(CLASS_FOUND_MESSAGE) + .shouldContain(OPTIMIZE_DISABLED) // mapping info + .shouldContain("Error: Could not find or load main class ."); + }); + tty("11. run with CDS on, --module-path, with -Xbootclasspath/a:."); + TestCommon.run("-Xlog:cds", + "-Xbootclasspath/a:.", + "--module-path", libsDir.toString(), + MAIN_CLASS) .assertAbnormalExit(out -> { out.shouldNotContain(CLASS_FOUND_MESSAGE) .shouldContain(OPTIMIZE_DISABLED) // mapping info diff --git a/test/hotspot/jtreg/runtime/cds/appcds/loaderConstraints/DynamicLoaderConstraintsTest.java b/test/hotspot/jtreg/runtime/cds/appcds/loaderConstraints/DynamicLoaderConstraintsTest.java index 9d194c288a34942acb13afdaf654150ce381b37d..67cc06e38ca03c7e73b079a56f06fe73257ad0d2 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/loaderConstraints/DynamicLoaderConstraintsTest.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/loaderConstraints/DynamicLoaderConstraintsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -130,7 +130,7 @@ public class DynamicLoaderConstraintsTest extends DynamicArchiveTestBase { static void doTest(boolean errorInDump) throws Exception { for (int i = 1; i <= 3; i++) { System.out.println("========================================"); - System.out.println("errorInDump: " + errorInDump + ", useCustomLoader: " + useCustomLoader + ", case: " + i); + System.out.println("errorInDump: " + errorInDump + ", useCustomLoader: " + useCustomLoader + ", useZGC: " + useZGC + ", case: " + i); System.out.println("========================================"); String topArchiveName = getNewArchiveName(); String testCase = Integer.toString(i); @@ -139,7 +139,7 @@ public class DynamicLoaderConstraintsTest extends DynamicArchiveTestBase { "java.base,jdk.httpserver", "--add-exports", "java.base/jdk.internal.misc=ALL-UNNAMED", - "-Xlog:class+load,class+loader+constraints", + "-Xlog:cds=debug,class+load,class+loader+constraints", }; if (useCustomLoader) { @@ -148,6 +148,7 @@ public class DynamicLoaderConstraintsTest extends DynamicArchiveTestBase { cmdLine = TestCommon.concat(cmdLine, "-cp", loaderJar, "-XX:+UseZGC", "-XX:ZCollectionInterval=0.01", loaderMainClass, appJar); + setBaseArchiveOptions("-XX:+UseZGC", "-Xlog:cds"); } else { cmdLine = TestCommon.concat(cmdLine, "-cp", loaderJar, loaderMainClass, appJar); diff --git a/test/hotspot/jtreg/runtime/cds/appcds/test-classes/TransformBootClass.java b/test/hotspot/jtreg/runtime/cds/appcds/test-classes/TransformBootClass.java new file mode 100644 index 0000000000000000000000000000000000000000..e13c768cc99dfd246130fabf3149cdc6f3c76982 --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/test-classes/TransformBootClass.java @@ -0,0 +1,62 @@ +/* + * 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 java.lang.instrument.ClassFileTransformer; +import java.lang.instrument.Instrumentation; +import java.lang.instrument.IllegalClassFormatException; +import java.security.ProtectionDomain; + +public class TransformBootClass implements ClassFileTransformer { + + static String targetClass = null; + + public byte[] transform(ClassLoader loader, String name, Class<?> classBeingRedefined, + ProtectionDomain pd, byte[] buffer) throws IllegalClassFormatException { + + if (name.equals(targetClass)) { + System.out.println("Transforming class " + name); + return buffer; + } + return null; + } + + private static Instrumentation savedInstrumentation; + + public static void premain(String agentArguments, Instrumentation instrumentation) { + System.out.println("TransformBootClass.premain() is called"); + instrumentation.addTransformer(new TransformBootClass(), /*canRetransform=*/true); + savedInstrumentation = instrumentation; + if (agentArguments != null) { + targetClass = agentArguments; + } + } + + public static Instrumentation getInstrumentation() { + return savedInstrumentation; + } + + public static void agentmain(String args, Instrumentation inst) throws Exception { + premain(args, inst); + } +} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/test-classes/TransformBootClass.mf b/test/hotspot/jtreg/runtime/cds/appcds/test-classes/TransformBootClass.mf new file mode 100644 index 0000000000000000000000000000000000000000..e9d472b02ba3f7b7d5451d0f65c20e02c64729cb --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/test-classes/TransformBootClass.mf @@ -0,0 +1,5 @@ +Manifest-Version: 1.0 +Premain-Class: TransformBootClass +Agent-Class: TransformBootClass +Can-Retransform-Classes: true +Can-Redefine-Classes: true diff --git a/test/hotspot/jtreg/runtime/classFileParserBug/TrailingSlashTest.java b/test/hotspot/jtreg/runtime/classFileParserBug/TrailingSlashTest.java new file mode 100644 index 0000000000000000000000000000000000000000..422b7357d2e6dadd5632ff1c2e7a320edeffbdf5 --- /dev/null +++ b/test/hotspot/jtreg/runtime/classFileParserBug/TrailingSlashTest.java @@ -0,0 +1,84 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8276241 + * @summary Throw ClassFormatError exception for an old class file whose name ends in a '/'. + * @run main/othervm -Xverify:remote TrailingSlashTest + */ + +public class TrailingSlashTest extends ClassLoader { + + @Override + public Class findClass(String fileName) throws ClassNotFoundException { + return defineClass(null, oldSlashClass, 0, oldSlashClass.length); + } + + public static void main(String args[]) throws Throwable { + try { + TrailingSlashTest cl = new TrailingSlashTest(); + cl.findClass("oldSlashClass"); + throw new RuntimeException("Expected exception not thrown"); + } catch (ClassFormatError e) { + if (!e.getMessage().contains("Illegal class name")) { + throw new RuntimeException("Wrong ClassFormatError exception: " + e.getMessage()); + } + } + } + + + // This byte array comprises the compiled bytes of the following class. Note that the class's + // name ends in a '/' and has a class file version of 45.3. + /* + package has; + public class slashe/ { } + */ + public static byte[] oldSlashClass = { + (byte) 0xca, (byte) 0xfe, (byte) 0xba, (byte) 0xbe, (byte) 0x0, (byte) 0x3, (byte) 0x0, (byte) 0x2d, + (byte) 0x0, (byte) 0xd, (byte) 0xa, (byte) 0x0, (byte) 0x2, (byte) 0x0, (byte) 0x3, (byte) 0x7, + (byte) 0x0, (byte) 0x4, (byte) 0xc, (byte) 0x0, (byte) 0x5, (byte) 0x0, (byte) 0x6, (byte) 0x1, + (byte) 0x0, (byte) 0x10, (byte) 0x6a, (byte) 0x61, (byte) 0x76, (byte) 0x61, (byte) 0x2f, (byte) 0x6c, + (byte) 0x61, (byte) 0x6e, (byte) 0x67, (byte) 0x2f, (byte) 0x4f, (byte) 0x62, (byte) 0x6a, (byte) 0x65, + (byte) 0x63, (byte) 0x74, (byte) 0x1, (byte) 0x0, (byte) 0x6, (byte) 0x3c, (byte) 0x69, (byte) 0x6e, + (byte) 0x69, (byte) 0x74, (byte) 0x3e, (byte) 0x1, (byte) 0x0, (byte) 0x3, (byte) 0x28, (byte) 0x29, + (byte) 0x56, (byte) 0x7, (byte) 0x0, (byte) 0x8, (byte) 0x1, (byte) 0x0, (byte) 0xb, (byte) 0x68, + (byte) 0x61, (byte) 0x73, (byte) 0x2f, (byte) 0x73, (byte) 0x6c, (byte) 0x61, (byte) 0x73, (byte) 0x68, + (byte) 0x65, (byte) 0x2f, (byte) 0x1, (byte) 0x0, (byte) 0x4, (byte) 0x43, (byte) 0x6f, (byte) 0x64, + (byte) 0x65, (byte) 0x1, (byte) 0x0, (byte) 0xf, (byte) 0x4c, (byte) 0x69, (byte) 0x6e, (byte) 0x65, + (byte) 0x4e, (byte) 0x75, (byte) 0x6d, (byte) 0x62, (byte) 0x65, (byte) 0x72, (byte) 0x54, (byte) 0x61, + (byte) 0x62, (byte) 0x6c, (byte) 0x65, (byte) 0x1, (byte) 0x0, (byte) 0xa, (byte) 0x53, (byte) 0x6f, + (byte) 0x75, (byte) 0x72, (byte) 0x63, (byte) 0x65, (byte) 0x46, (byte) 0x69, (byte) 0x6c, (byte) 0x65, + (byte) 0x1, (byte) 0x0, (byte) 0xc, (byte) 0x73, (byte) 0x6c, (byte) 0x61, (byte) 0x73, (byte) 0x68, + (byte) 0x65, (byte) 0x73, (byte) 0x2e, (byte) 0x6a, (byte) 0x61, (byte) 0x76, (byte) 0x61, (byte) 0x0, + (byte) 0x21, (byte) 0x0, (byte) 0x7, (byte) 0x0, (byte) 0x2, (byte) 0x0, (byte) 0x0, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0x1, (byte) 0x0, (byte) 0x1, (byte) 0x0, (byte) 0x5, (byte) 0x0, + (byte) 0x6, (byte) 0x0, (byte) 0x1, (byte) 0x0, (byte) 0x9, (byte) 0x0, (byte) 0x0, (byte) 0x0, + (byte) 0x1d, (byte) 0x0, (byte) 0x1, (byte) 0x0, (byte) 0x1, (byte) 0x0, (byte) 0x0, (byte) 0x0, + (byte) 0x5, (byte) 0x2a, (byte) 0xb7, (byte) 0x0, (byte) 0x1, (byte) 0xb1, (byte) 0x0, (byte) 0x0, + (byte) 0x0, (byte) 0x1, (byte) 0x0, (byte) 0xa, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x6, + (byte) 0x0, (byte) 0x1, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x3, (byte) 0x0, (byte) 0x1, + (byte) 0x0, (byte) 0xb, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x2, (byte) 0x0, (byte) 0xc, + }; + +} diff --git a/test/hotspot/jtreg/runtime/exceptionMsgs/AbstractMethodError/AbstractMethodErrorTest.java b/test/hotspot/jtreg/runtime/exceptionMsgs/AbstractMethodError/AbstractMethodErrorTest.java index e576de4e81f0047fe0572e03158a4b9222a5c342..5c88f1722f52e40fe5c5ef7a7610e6846f4245a2 100644 --- a/test/hotspot/jtreg/runtime/exceptionMsgs/AbstractMethodError/AbstractMethodErrorTest.java +++ b/test/hotspot/jtreg/runtime/exceptionMsgs/AbstractMethodError/AbstractMethodErrorTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2022, 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. * @@ -26,6 +26,7 @@ * @test * @summary Check that the verbose message of the AME is printed correctly. * @requires !(os.arch=="arm") & vm.flavor == "server" & !vm.emulatedClient & vm.compMode=="Xmixed" & !vm.graal.enabled & vm.opt.UseJVMCICompiler != true & (vm.opt.TieredStopAtLevel == null | vm.opt.TieredStopAtLevel==4) + * @requires vm.opt.DeoptimizeALot != true * @library /test/lib / * @build sun.hotspot.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller sun.hotspot.WhiteBox @@ -502,7 +503,7 @@ public class AbstractMethodErrorTest { // ------------------------------------------------------------------------- // This error should be detected interpreted. // -// Class hierachy: +// Class hierarchy: // // C // interface, defines aFunctionOfMyInterface() // | @@ -618,7 +619,7 @@ class AME1_E extends AME1_B implements AME1_C { // ------------------------------------------------------------------------- // This error should be detected interpreted. // -// Class hierachy: +// Class hierarchy: // // A // an interface declaring aFunctionOfMyInterface() // | @@ -664,7 +665,7 @@ class AME2_C extends AME2_B { // ----------------------------------------------------------------------- // Test AbstractMethod error shadowing existing implementation. // -// Class hierachy: +// Class hierarchy: // // A // a class implementing m() // | @@ -693,7 +694,7 @@ class AME3_C extends AME3_B { // Test AbstractMethod error shadowing existing implementation. In // this test there are several subclasses of the abstract class. // -// Class hierachy: +// Class hierarchy: // // A // A: a class implementing ma() // | @@ -733,7 +734,7 @@ class AME4_E extends AME4_B { // ------------------------------------------------------------------------- // This error should be detected while processing the vtable stub. // -// Class hierachy: +// Class hierarchy: // // A__ // abstract // /|\ \ @@ -811,7 +812,7 @@ class AME5_E extends AME5_A { // Test AbstractMethod error detected while processing // the itable stub. // -// Class hierachy: +// Class hierarchy: // // A__ (interface) // /|\ \ diff --git a/test/hotspot/jtreg/runtime/exceptionMsgs/IncompatibleClassChangeError/IncompatibleClassChangeErrorTest.java b/test/hotspot/jtreg/runtime/exceptionMsgs/IncompatibleClassChangeError/IncompatibleClassChangeErrorTest.java index dbeae9efce27483608c960c044eaa82f662aab32..179d7164241bf30cb563bdf9822172aaa5047668 100644 --- a/test/hotspot/jtreg/runtime/exceptionMsgs/IncompatibleClassChangeError/IncompatibleClassChangeErrorTest.java +++ b/test/hotspot/jtreg/runtime/exceptionMsgs/IncompatibleClassChangeError/IncompatibleClassChangeErrorTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2022, 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. * @@ -345,7 +345,7 @@ class ImplementsSomeInterfaces extends // Helper classes to test incompatible class change in itable stub. // -// Class hierachy: +// Class hierarchy: // // iA,iB (interfaces) // /|\ \ @@ -407,7 +407,7 @@ class ICC2_E implements ICC2_iA, ICC2_iB { // Helper classes to test error where class appears in implements statement. // -// Class hierachy: +// Class hierarchy: // // A Some Class. // | @@ -421,7 +421,7 @@ class ICC3_B extends ICC3_A { // Helper classes to test error where interface appears in extends statement. // -// Class hierachy: +// Class hierarchy: // // A Some Interface. // | diff --git a/test/hotspot/jtreg/runtime/exceptionMsgs/methodPrinting/TestPrintingMethods.java b/test/hotspot/jtreg/runtime/exceptionMsgs/methodPrinting/TestPrintingMethods.java index 5c413b07a69ef8e294de2b73a3bbe9d349de32f6..dbd089c5dc0649e8affb4c14f04ecd7c2a85bbbc 100644 --- a/test/hotspot/jtreg/runtime/exceptionMsgs/methodPrinting/TestPrintingMethods.java +++ b/test/hotspot/jtreg/runtime/exceptionMsgs/methodPrinting/TestPrintingMethods.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2019 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -101,7 +101,7 @@ public class TestPrintingMethods { // ----------------------------------------------------------------------- // Test AbstractMethod error shadowing existing implementation. // -// Class hierachy: +// Class hierarchy: // // A // A class implementing m() and similar. // | diff --git a/test/hotspot/jtreg/runtime/jni/checked/TestPrimitiveArrayCriticalWithBadParam.java b/test/hotspot/jtreg/runtime/jni/checked/TestPrimitiveArrayCriticalWithBadParam.java index a341c5be877dec1699ec9b61cf4a5241a93d295a..c64b21c7d1ba9461e398576478f99253f0c7e26f 100644 --- a/test/hotspot/jtreg/runtime/jni/checked/TestPrimitiveArrayCriticalWithBadParam.java +++ b/test/hotspot/jtreg/runtime/jni/checked/TestPrimitiveArrayCriticalWithBadParam.java @@ -55,6 +55,7 @@ public class TestPrimitiveArrayCriticalWithBadParam { private static void runTest() { List<String> pbArgs = new ArrayList<>(); + pbArgs.add("-XX:-CreateCoredumpOnCrash"); pbArgs.add("-Xcheck:jni"); pbArgs.add("-Djava.library.path=" + Utils.TEST_NATIVE_PATH); pbArgs.add(TestPrimitiveArrayCriticalWithBadParam.class.getName()); diff --git a/test/hotspot/jtreg/runtime/logging/ThreadLoggingTest.java b/test/hotspot/jtreg/runtime/logging/ThreadLoggingTest.java index 82a189a92cbe2abc1e05015af6dbbde1ff5fdd59..d98fc455319386c806d9722ed4d361b689d55d40 100644 --- a/test/hotspot/jtreg/runtime/logging/ThreadLoggingTest.java +++ b/test/hotspot/jtreg/runtime/logging/ThreadLoggingTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2016 SAP SE and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -24,7 +24,7 @@ /* * @test - * @bug 8149036 8150619 + * @bug 8149036 8150619 8277531 * @summary os+thread output should contain logging calls for thread start stop attaches detaches * @requires vm.flagless * @library /test/lib @@ -36,6 +36,7 @@ import java.io.File; import java.util.Map; +import jdk.test.lib.Platform; import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.process.ProcessTools; @@ -43,7 +44,11 @@ public class ThreadLoggingTest { static void analyzeOutputForInfoLevel(OutputAnalyzer output) throws Exception { output.shouldMatch("Thread .* started"); - output.shouldContain("Thread is alive"); + if (Platform.isWindows()) { + output.shouldMatch("Thread is alive \\(tid: [0-9]+, stacksize: [0-9]+k\\)"); + } else { + output.shouldContain("Thread is alive"); + } output.shouldContain("Thread finished"); output.shouldHaveExitValue(0); } diff --git a/test/hotspot/jtreg/runtime/modules/AccessCheck/MethodAccessReadTwice.java b/test/hotspot/jtreg/runtime/modules/AccessCheck/MethodAccessReadTwice.java index 29bbe7f39b0f0f29b3d5bb59d4fd639b76518692..d6b85ced2576be3fb576d7b804c27613cc72de04 100644 --- a/test/hotspot/jtreg/runtime/modules/AccessCheck/MethodAccessReadTwice.java +++ b/test/hotspot/jtreg/runtime/modules/AccessCheck/MethodAccessReadTwice.java @@ -29,8 +29,8 @@ * after the module read edge is added. * @compile ModuleLibrary.java * p2/c2.java - * p5/c5.java - * p7/c7.java + * p5/c5.jasm + * p7/c7.jasm * @run main/othervm MethodAccessReadTwice */ diff --git a/test/hotspot/jtreg/runtime/modules/AccessCheck/p5/c5.jasm b/test/hotspot/jtreg/runtime/modules/AccessCheck/p5/c5.jasm new file mode 100644 index 0000000000000000000000000000000000000000..b1178eaab6c1f2b50346695519ba46846983b0df --- /dev/null +++ b/test/hotspot/jtreg/runtime/modules/AccessCheck/p5/c5.jasm @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2021, Google LLC. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * Test input for the fix for JDK-8174954, which checks for an expected + * IllegalAccessError when the parameter type of an invokedynamic is + * inaccessible. + * + * The test assumes that given the string concatenation expression "" + param, + * javac generates an invokedynamic that uses the specific type of param. The + * fix for JDK-8273914 make javac eagerly convert param to a String before + * passing it to the invokedynamic call, which avoids the accessibility issue + * the test is trying to exercise. + * + * This jasm file contains the bytecode javac generated before the fix for + * JDK-8273914, to continue to exercise the invokedynamic behaviour that + * JDK-8174954 is testing. + */ + +package p5; + +super public class c5 + version 61:0 +{ + public Method "<init>":"()V" + stack 1 locals 1 + { + aload_0; + invokespecial Method java/lang/Object."<init>":"()V"; + return; + } + public Method method5:"(Lp2/c2;)V" + stack 2 locals 2 + { + getstatic Field java/lang/System.out:"Ljava/io/PrintStream;"; + aload_1; + invokedynamic InvokeDynamic REF_invokeStatic:Method java/lang/invoke/StringConcatFactory.makeConcatWithConstants:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;":makeConcatWithConstants:"(Lp2/c2;)Ljava/lang/String;" { + String "In c5\'s method5 with param = " + }; + invokevirtual Method java/io/PrintStream.println:"(Ljava/lang/String;)V"; + return; + } + public Method methodAddReadEdge:"(Ljava/lang/Module;)V" + stack 2 locals 2 + { + ldc class c5; + invokevirtual Method java/lang/Class.getModule:"()Ljava/lang/Module;"; + aload_1; + invokevirtual Method java/lang/Module.addReads:"(Ljava/lang/Module;)Ljava/lang/Module;"; + pop; + return; + } + + public static final InnerClass Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles; + +} // end Class c5 diff --git a/test/hotspot/jtreg/runtime/modules/AccessCheck/p7/c7.jasm b/test/hotspot/jtreg/runtime/modules/AccessCheck/p7/c7.jasm new file mode 100644 index 0000000000000000000000000000000000000000..6ca4e6850e3e031f8bcce0ea7e75c7f3034c2dea --- /dev/null +++ b/test/hotspot/jtreg/runtime/modules/AccessCheck/p7/c7.jasm @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2021, Google LLC. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * Test input for the fix for JDK-8174954, which checks for an expected + * IllegalAccessError when the parameter type of an invokedynamic is + * inaccessible. + * + * The test assumes that given the string concatenation expression "" + param, + * javac generates an invokedynamic that uses the specific type of param. The + * fix for JDK-8273914 make javac eagerly convert param to a String before + * passing it to the invokedynamic call, which avoids the accessibility issue + * the test is trying to exercise. + * + * This jasm file contains the bytecode javac generated before the fix for + * JDK-8273914, to continue to exercise the invokedynamic behaviour that + * JDK-8174954 is testing. + */ + +package p7; + +super public class c7 + version 61:0 +{ + public Method "<init>":"()V" + stack 1 locals 1 + { + aload_0; + invokespecial Method java/lang/Object."<init>":"()V"; + return; + } + public Method method7:"(Lp2/c2;Ljava/lang/Module;)V" + stack 3 locals 4 + { + try t0; + getstatic Field java/lang/System.out:"Ljava/io/PrintStream;"; + aload_1; + invokedynamic InvokeDynamic REF_invokeStatic:Method java/lang/invoke/StringConcatFactory.makeConcatWithConstants:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;":makeConcatWithConstants:"(Lp2/c2;)Ljava/lang/String;" { + String "In c7\'s method7 with param = " + }; + invokevirtual Method java/io/PrintStream.println:"(Ljava/lang/String;)V"; + new class java/lang/RuntimeException; + dup; + ldc String "c7 failed to throw expected IllegalAccessError"; + invokespecial Method java/lang/RuntimeException."<init>":"(Ljava/lang/String;)V"; + athrow; + endtry t0; + catch t0 java/lang/IllegalAccessError; + stack_frame_type stack1; + stack_map class java/lang/IllegalAccessError; + astore_3; + aload_0; + aload_2; + invokevirtual Method methodAddReadEdge:"(Ljava/lang/Module;)V"; + try t1; + getstatic Field java/lang/System.out:"Ljava/io/PrintStream;"; + aload_1; + invokedynamic InvokeDynamic REF_invokeStatic:Method java/lang/invoke/StringConcatFactory.makeConcatWithConstants:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;":makeConcatWithConstants:"(Lp2/c2;)Ljava/lang/String;" { + String "In c7\'s method7 with param = " + }; + invokevirtual Method java/io/PrintStream.println:"(Ljava/lang/String;)V"; + endtry t1; + goto L61; + catch t1 java/lang/IllegalAccessError; + stack_frame_type stack1; + stack_map class java/lang/IllegalAccessError; + astore_3; + new class java/lang/RuntimeException; + dup; + aload_3; + invokevirtual Method java/lang/IllegalAccessError.getMessage:"()Ljava/lang/String;"; + invokedynamic InvokeDynamic REF_invokeStatic:Method java/lang/invoke/StringConcatFactory.makeConcatWithConstants:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;":makeConcatWithConstants:"(Ljava/lang/String;)Ljava/lang/String;" { + String "Unexpected IllegalAccessError: " + }; + invokespecial Method java/lang/RuntimeException."<init>":"(Ljava/lang/String;)V"; + athrow; + L61: stack_frame_type same; + return; + } + public Method methodAddReadEdge:"(Ljava/lang/Module;)V" + stack 2 locals 2 + { + ldc class c7; + invokevirtual Method java/lang/Class.getModule:"()Ljava/lang/Module;"; + aload_1; + invokevirtual Method java/lang/Module.addReads:"(Ljava/lang/Module;)Ljava/lang/Module;"; + pop; + return; + } + + public static final InnerClass Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles; + +} // end Class c7 diff --git a/test/hotspot/jtreg/runtime/modules/LoadUnloadModuleStress.java b/test/hotspot/jtreg/runtime/modules/LoadUnloadModuleStress.java index 2d279856e523134b7f95e8e0b083a3ac560b82f4..0e1565cf6db6e0bb4b94f7863aea07887e3b2862 100644 --- a/test/hotspot/jtreg/runtime/modules/LoadUnloadModuleStress.java +++ b/test/hotspot/jtreg/runtime/modules/LoadUnloadModuleStress.java @@ -30,7 +30,7 @@ * @build sun.hotspot.WhiteBox * @compile/module=java.base java/lang/ModuleHelper.java * @run driver jdk.test.lib.helpers.ClassFileInstaller sun.hotspot.WhiteBox - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xmx64m -Xmx64m LoadUnloadModuleStress 15000 + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xms64m -Xmx64m LoadUnloadModuleStress 15000 */ import java.lang.ref.WeakReference; diff --git a/test/hotspot/jtreg/serviceability/7170638/SDTProbesGNULinuxTest.java b/test/hotspot/jtreg/serviceability/7170638/SDTProbesGNULinuxTest.java index 9ad10282d1bc457233aab623bcb1e9096c71765e..d4a4924790968500ba730c3ac37255ce4523a584 100644 --- a/test/hotspot/jtreg/serviceability/7170638/SDTProbesGNULinuxTest.java +++ b/test/hotspot/jtreg/serviceability/7170638/SDTProbesGNULinuxTest.java @@ -28,6 +28,7 @@ * @summary Test SDT probes available on GNU/Linux when DTRACE_ENABLED * @requires os.family == "linux" * @requires vm.flagless + * @requires vm.hasDTrace * * @library /test/lib * @run driver SDTProbesGNULinuxTest @@ -36,7 +37,6 @@ import jdk.test.lib.Utils; import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.process.ProcessTools; -import jtreg.SkippedException; import java.nio.file.Files; import java.nio.file.Path; @@ -44,17 +44,7 @@ import java.nio.file.Paths; public class SDTProbesGNULinuxTest { public static void main(String[] args) throws Throwable { - { - var pb = ProcessTools.createJavaProcessBuilder( - "-XX:+ExtendedDTraceProbes", - "-version"); - var oa = new OutputAnalyzer(pb.start()); - // This test only matters when build with DTRACE_ENABLED. - if (oa.getExitValue() != 0) { - throw new SkippedException("Not build using DTRACE_ENABLED"); - } - } - + // This test only matters when build with DTRACE_ENABLED. try (var libjvms = Files.walk(Paths.get(Utils.TEST_JDK))) { libjvms.filter(p -> "libjvm.so".equals(p.getFileName().toString())) .map(Path::toAbsolutePath) diff --git a/test/hotspot/jtreg/serviceability/HeapDump/DuplicateArrayClassesTest.java b/test/hotspot/jtreg/serviceability/HeapDump/DuplicateArrayClassesTest.java new file mode 100644 index 0000000000000000000000000000000000000000..50a3441a609ca75ef3c6716f441be25abd384bb1 --- /dev/null +++ b/test/hotspot/jtreg/serviceability/HeapDump/DuplicateArrayClassesTest.java @@ -0,0 +1,336 @@ +/* + * 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. + */ + +import java.io.BufferedInputStream; +import java.io.EOFException; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.lang.ref.Reference; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Hashtable; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +import jdk.test.lib.Asserts; +import jdk.test.lib.JDKToolLauncher; +import jdk.test.lib.apps.LingeredApp; +import jdk.test.lib.hprof.parser.PositionDataInputStream; +import jdk.test.lib.process.ProcessTools; + +/** + * @test + * @bug 8281267 + * @summary Verifies heap dump does not contain duplicate array classes + * @library /test/lib + * @run driver DuplicateArrayClassesTest + */ + +class DuplicateArrayClassesTarg extends LingeredApp { + public static void main(String[] args) { + // Initialize some array classes (for primitive type and object type). + int[][][] intArray = new int[0][][]; + String[][][] strArray = new String[0][][]; + LingeredApp.main(args); + Reference.reachabilityFence(intArray); + Reference.reachabilityFence(strArray); + } +} + + +public class DuplicateArrayClassesTest { + + public static void main(String[] args) throws Exception { + File dumpFile = new File("Myheapdump.hprof"); + createDump(dumpFile); + verifyDump(dumpFile); + } + + private static void createDump(File dumpFile) throws Exception { + LingeredApp theApp = null; + try { + theApp = new DuplicateArrayClassesTarg(); + + LingeredApp.startApp(theApp); + + //jcmd <pid> GC.heap_dump <file_path> + JDKToolLauncher launcher = JDKToolLauncher + .createUsingTestJDK("jcmd") + .addToolArg(Long.toString(theApp.getPid())) + .addToolArg("GC.heap_dump") + .addToolArg(dumpFile.getAbsolutePath()); + Process p = ProcessTools.startProcess("jcmd", new ProcessBuilder(launcher.getCommand())); + // If something goes wrong with heap dumping most likely we'll get crash of the target VM. + while (!p.waitFor(5, TimeUnit.SECONDS)) { + if (!theApp.getProcess().isAlive()) { + log("ERROR: target VM died, killing jcmd..."); + p.destroyForcibly(); + throw new Exception("Target VM died"); + } + } + + if (p.exitValue() != 0) { + throw new Exception("Jcmd exited with code " + p.exitValue()); + } + } finally { + LingeredApp.stopApp(theApp); + } + } + + private static final byte HPROF_UTF8 = 0x01; + private static final byte HPROF_LOAD_CLASS = 0x02; + private static final byte HPROF_HEAP_DUMP = 0x0c; + private static final byte HPROF_GC_CLASS_DUMP = 0x20; + private static final byte HPROF_HEAP_DUMP_SEGMENT = 0x1C; + private static final byte HPROF_HEAP_DUMP_END = 0x2C; + + private static void verifyDump(File dumpFile) throws IOException { + Asserts.assertTrue(dumpFile.exists(), "Heap dump file not found."); + + // HPROF_UTF8 records. + Map<Long, String> names = new HashMap<>(); + // Maps from HPROF_LOAD_CLASS records. + Map<Long, String> classId2Name = new Hashtable<>(); + Map<String, Long> className2Id = new Hashtable<>(); + // Duplicate HPROF_LOAD_CLASS records. + List<Long> duplicateLoadClassIDs = new LinkedList<>(); + // HPROF_GC_CLASS_DUMP records. + Set<Long> dumpClassIDs = new HashSet<>(); + // Duplicate HPROF_GC_CLASS_DUMP records. + List<Long> duplicateDumpClassIDs = new LinkedList<>(); + + try (DumpInputStream in = new DumpInputStream(dumpFile)) { + while (true) { + DumpRecord rec; + try { + rec = in.readRecord(); + } catch (EOFException ex) { + break; + } + long pos = in.position(); // save the current pos + + switch (rec.tag()) { + case HPROF_UTF8: + long id = in.readID(); + byte[] chars = new byte[(int) rec.size - in.idSize]; + in.readFully(chars); + names.put(id, new String(chars)); + break; + case HPROF_LOAD_CLASS: + long classSerialNo = in.readU4(); + long classID = in.readID(); + long stackTraceSerialNo = in.readU4(); + long classNameID = in.readID(); + // We expect all names are dumped before classes. + String className = names.get(classNameID); + + String prevName = classId2Name.putIfAbsent(classID, className); + if (prevName != null) { // there is a class with the same ID + if (!prevName.equals(className)) { + // Something is completely wrong. + throw new RuntimeException("Found new class with id=" + classID + + " and different name (" + className + ", was " + prevName + ")"); + } + duplicateLoadClassIDs.add(classID); + } + // It's ok if we have other class with the same name (may be from other classloader). + className2Id.putIfAbsent(className, classID); + break; + case HPROF_HEAP_DUMP: + case HPROF_HEAP_DUMP_SEGMENT: + // HPROF_GC_CLASS_DUMP records are dumped first (in the beginning of the dump). + long endOfRecordPos = pos + rec.size(); + + while (in.position() < endOfRecordPos) { + byte subTag = in.readU1(); + if (subTag != HPROF_GC_CLASS_DUMP) { + break; + } + // We don't know HPROF_GC_CLASS_DUMP size, so have to read it completely. + long dumpClassID = readClassDump(in); + + if (!dumpClassIDs.add(dumpClassID)) { + duplicateDumpClassIDs.add(dumpClassID); + } + } + break; + } + + // Skip bytes till end of the record. + long bytesRead = in.position() - pos; + if (bytesRead > rec.size()) { + throw new RuntimeException("Bad record," + + " record.size = " + rec.size() + ", read " + bytesRead); + } + in.skipNBytes(rec.size() - bytesRead); + } + + log("HPROF_LOAD_CLASS records: " + (classId2Name.size() + duplicateLoadClassIDs.size())); + log("HPROF_GC_CLASS_DUMP records: " + (dumpClassIDs.size() + duplicateDumpClassIDs.size())); + + // Verify we have array classes used by target app. + String[] expectedClasses = {"[I", "[[I", "[[[I", + "[Ljava/lang/String;", "[[Ljava/lang/String;", "[[[Ljava/lang/String;"}; + for (String className: expectedClasses) { + Long classId = className2Id.get(className); + if (classId == null) { + throw new RuntimeException("no HPROF_LOAD_CLASS record for class " + className); + } + // verify there is HPROF_GC_CLASS_DUMP record for the class + if (!dumpClassIDs.contains(classId)) { + throw new RuntimeException("no HPROF_GC_CLASS_DUMP for class " + className); + } + log("found " + className); + } + if (!duplicateLoadClassIDs.isEmpty() || !duplicateDumpClassIDs.isEmpty()) { + log("Duplicate(s) detected:"); + log("HPROF_LOAD_CLASS records (" + duplicateLoadClassIDs.size() + "):"); + duplicateLoadClassIDs.forEach(id -> log(" - id = " + id + ": " + classId2Name.get(id))); + log("HPROF_GC_CLASS_DUMP records (" + duplicateDumpClassIDs.size() + "):"); + duplicateDumpClassIDs.forEach(id -> log(" - id = " + id + ": " + classId2Name.get(id))); + throw new RuntimeException("duplicates detected"); + } + } + } + + // Reads the whole HPROF_GC_CLASS_DUMP record, returns class ID. + private static long readClassDump(DumpInputStream in) throws IOException { + long classID = in.readID(); + long stackTraceNum = in.readU4(); + long superClassId = in.readID(); + long loaderClassId = in.readID(); + long signerClassId = in.readID(); + long protectionDomainClassId = in.readID(); + long reserved1 = in.readID(); + long reserved2 = in.readID(); + long instanceSize = in.readU4(); + long cpSize = in.readU2(); + for (long i = 0; i < cpSize; i++) { + long cpIndex = in.readU2(); + byte type = in.readU1(); + in.skipNBytes(in.type2size(type)); // value + } + long staticNum = in.readU2(); + for (long i = 0; i < staticNum; i++) { + long nameId = in.readID(); + byte type = in.readU1(); + in.skipNBytes(in.type2size(type)); // value + } + long instanceNum = in.readU2(); + for (long i = 0; i < instanceNum; i++) { + long nameId = in.readID(); + byte type = in.readU1(); + } + return classID; + } + + private static void log(Object s) { + System.out.println(s); + } + + + private static record DumpRecord (byte tag, long size) {} + + private static class DumpInputStream extends PositionDataInputStream { + public final int idSize; + + public DumpInputStream(File f) throws IOException { + super(new BufferedInputStream(new FileInputStream(f))); + + // read header: + // header "JAVA PROFILE 1.0.2" (0-terminated) + // u4 size of identifiers. Identifiers are used to represent + // u4 high word + // u4 low word number of milliseconds since 0:00 GMT, 1/1/70 + String header = readStr(); + log("header: \"" + header + "\""); + Asserts.assertTrue(header.startsWith("JAVA PROFILE ")); + + idSize = readInt(); + if (idSize != 4 && idSize != 8) { + Asserts.fail("id size " + idSize + " is not supported"); + } + // ignore timestamp + readU4(); + readU4(); + } + + // Reads null-terminated string + public String readStr() throws IOException { + StringBuilder sb = new StringBuilder(); + for (char ch = (char)readByte(); ch != '\0'; ch = (char)readByte()) { + sb.append(ch); + } + return sb.toString(); + } + + public byte readU1() throws IOException { + return readByte(); + } + public int readU2() throws IOException { + return readUnsignedShort(); + } + public long readU4() throws IOException { + // keep the value positive + return ((long)readInt() & 0x0FFFFFFFFL); + } + + public long readID() throws IOException { + return idSize == 4 ? readU4() : readLong(); + } + + public DumpRecord readRecord() throws IOException { + byte tag = readU1(); + readU4(); // timestamp, ignore it + long size = readU4(); + return new DumpRecord(tag, size); + } + + public long type2size(byte type) { + switch (type) { + case 1: // array + case 2: // object + return idSize; + case 4: // boolean + case 8: // byte + return 1; + case 5: // char + case 9: // short + return 2; + case 6: // float + case 10: // int + return 4; + case 7: // double + case 11: // long + return 8; + } + throw new RuntimeException("unknown type: " + type); + } + + } + +} diff --git a/test/hotspot/jtreg/serviceability/dcmd/compiler/CodeHeapAnalyticsMethodNames.java b/test/hotspot/jtreg/serviceability/dcmd/compiler/CodeHeapAnalyticsMethodNames.java index da10be193b94b84a209535a970fd765d8f09506c..8733b3f9d12d4fb6261c4831cfa9f674a369f258 100644 --- a/test/hotspot/jtreg/serviceability/dcmd/compiler/CodeHeapAnalyticsMethodNames.java +++ b/test/hotspot/jtreg/serviceability/dcmd/compiler/CodeHeapAnalyticsMethodNames.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Amazon.com Inc. 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 diff --git a/test/hotspot/jtreg/serviceability/dtrace/DTraceOptionsTest.java b/test/hotspot/jtreg/serviceability/dtrace/DTraceOptionsTest.java new file mode 100644 index 0000000000000000000000000000000000000000..8822a9ed3784c73a149eae1cf8c155c8f89f47a4 --- /dev/null +++ b/test/hotspot/jtreg/serviceability/dtrace/DTraceOptionsTest.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 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. + */ + +/* + * @test id=enabled + * @bug 8281822 + * @summary Test DTrace options are accepted on suitable builds + * @requires vm.flagless + * @requires vm.hasDTrace + * + * @library /test/lib + * @run driver DTraceOptionsTest true + */ + +/* + * @test id=disabled + * @bug 8281822 + * @summary Test DTrace options are rejected on unsuitable builds + * @requires vm.flagless + * @requires !vm.hasDTrace + * + * @library /test/lib + * @run driver DTraceOptionsTest disabled + */ + +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; + +public class DTraceOptionsTest { + public static void main(String[] args) throws Throwable { + boolean dtraceEnabled; + if (args.length > 0) { + dtraceEnabled = Boolean.parseBoolean(args[0]); + } else { + throw new IllegalArgumentException("Should provide the argument"); + } + + String[] options = { + "ExtendedDTraceProbes", + "DTraceMethodProbes", + "DTraceAllocProbes", + "DTraceMonitorProbes", + }; + + for (String opt : options) { + var pb = ProcessTools.createJavaProcessBuilder("-XX:+" + opt, "-version"); + var oa = new OutputAnalyzer(pb.start()); + if (dtraceEnabled) { + oa.shouldHaveExitValue(0); + } else { + oa.shouldNotHaveExitValue(0); + oa.shouldContain(opt + " flag is not applicable for this configuration"); + } + } + } + +} diff --git a/test/hotspot/jtreg/serviceability/jvmti/FieldAccessWatch/FieldAccessWatch.java b/test/hotspot/jtreg/serviceability/jvmti/FieldAccessWatch/FieldAccessWatch.java index c3be30a014841dcbe5e333dc99838c0e6ddc318c..d4345af258638e5968262230a554aefc10e2f7e2 100644 --- a/test/hotspot/jtreg/serviceability/jvmti/FieldAccessWatch/FieldAccessWatch.java +++ b/test/hotspot/jtreg/serviceability/jvmti/FieldAccessWatch/FieldAccessWatch.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -57,7 +57,7 @@ public class FieldAccessWatch { throw ex; } - if (!initWatchers(MyList.class, MyList.class.getDeclaredField("items"))) { + if (!initWatchers(MyList.class, MyList.class.getDeclaredField("items"), Thread.currentThread())) { throw new RuntimeException("Watchers initializations error"); } @@ -131,7 +131,7 @@ public class FieldAccessWatch { log(descr + ": OK"); } - private static native boolean initWatchers(Class cls, Field field); + private static native boolean initWatchers(Class cls, Field field, Thread testThread); private static native boolean startTest(TestResult results); private static native void stopTest(); diff --git a/test/hotspot/jtreg/serviceability/jvmti/FieldAccessWatch/libFieldAccessWatch.c b/test/hotspot/jtreg/serviceability/jvmti/FieldAccessWatch/libFieldAccessWatch.c index fdc28961e894e71ecc76b2e0056a3bb75faa9fcf..9973f5eef759c63ac46efbf662fcab55dd22f79e 100644 --- a/test/hotspot/jtreg/serviceability/jvmti/FieldAccessWatch/libFieldAccessWatch.c +++ b/test/hotspot/jtreg/serviceability/jvmti/FieldAccessWatch/libFieldAccessWatch.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -37,6 +37,7 @@ static jvmtiEnv *jvmti = NULL; // valid while a test is executed static jobject testResultObject = NULL; static jclass testResultClass = NULL; +static jthread testThread = NULL; static void reportError(const char *msg, int err) { @@ -46,6 +47,7 @@ static void reportError(const char *msg, int err) { // logs the notification and updates currentTestResult static void handleNotification(JNIEnv *jni_env, + jthread thread, jmethodID method, jfieldID field, jclass field_klass, @@ -64,6 +66,10 @@ static void handleNotification(JNIEnv *jni_env, return; } + if (!(*jni_env)->IsSameObject(jni_env, thread, testThread)) { + return; // skip events from unexpected threads + } + err = (*jvmti)->GetFieldName(jvmti, field_klass, field, &name, NULL, NULL); if (err != JVMTI_ERROR_NONE) { reportError("GetFieldName failed", err); @@ -179,7 +185,7 @@ onFieldAccess(jvmtiEnv *jvmti_env, jobject object, jfieldID field) { - handleNotification(jni_env, method, field, field_klass, 0, location); + handleNotification(jni_env, thread, method, field, field_klass, 0, location); } @@ -195,7 +201,7 @@ onFieldModification(jvmtiEnv *jvmti_env, char signature_type, jvalue new_value) { - handleNotification(jni_env, method, field, field_klass, 1, location); + handleNotification(jni_env, thread, method, field, field_klass, 1, location); if (signature_type == 'L') { jobject newObject = new_value.l; @@ -251,7 +257,7 @@ Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) JNIEXPORT jboolean JNICALL -Java_FieldAccessWatch_initWatchers(JNIEnv *env, jclass thisClass, jclass cls, jobject field) +Java_FieldAccessWatch_initWatchers(JNIEnv *env, jclass thisClass, jclass cls, jobject field, jthread thread) { jfieldID fieldId; jvmtiError err; @@ -275,6 +281,8 @@ Java_FieldAccessWatch_initWatchers(JNIEnv *env, jclass thisClass, jclass cls, jo return JNI_FALSE; } + testThread = (jthread)(*env)->NewGlobalRef(env, thread); + return JNI_TRUE; } diff --git a/test/hotspot/jtreg/serviceability/jvmti/Heap/IterateHeapWithEscapeAnalysisEnabled.java b/test/hotspot/jtreg/serviceability/jvmti/Heap/IterateHeapWithEscapeAnalysisEnabled.java index 03e388df6c38bd8878b71c79b746b00275831d41..6b835ca7ac823dd42dafc3c1f469827c6e0ed744 100644 --- a/test/hotspot/jtreg/serviceability/jvmti/Heap/IterateHeapWithEscapeAnalysisEnabled.java +++ b/test/hotspot/jtreg/serviceability/jvmti/Heap/IterateHeapWithEscapeAnalysisEnabled.java @@ -590,7 +590,7 @@ public class IterateHeapWithEscapeAnalysisEnabled { // The new instance is an ArgEscape instance and escapes to the JVMTI agent // while the target thread is in the call to dontinline_endlessLoop(). At this // location there is no local variable that references the ArgEscape. - ((ABBox) dontinline_endlessLoop(new ABBox(this))).synchronizedSlowInc();; + ((ABBox) dontinline_endlessLoop(new ABBox(this))).synchronizedSlowInc(); } } diff --git a/test/hotspot/jtreg/serviceability/jvmti/SetBreakpoint/TestManyBreakpoints.java b/test/hotspot/jtreg/serviceability/jvmti/SetBreakpoint/TestManyBreakpoints.java new file mode 100644 index 0000000000000000000000000000000000000000..bc935ea99d19f619434f27417b0eeeab3debb14b --- /dev/null +++ b/test/hotspot/jtreg/serviceability/jvmti/SetBreakpoint/TestManyBreakpoints.java @@ -0,0 +1,82 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8144992 + * @requires vm.jvmti + * @modules java.base/jdk.internal.org.objectweb.asm + * @run main/othervm/native -agentlib:TestManyBreakpoints + * -Xlog:gc+metaspace + * -Xint + * -XX:MetaspaceSize=16K -XX:MaxMetaspaceSize=64M + * TestManyBreakpoints + */ + +import jdk.internal.org.objectweb.asm.ClassWriter; +import jdk.internal.org.objectweb.asm.Label; +import jdk.internal.org.objectweb.asm.MethodVisitor; +import jdk.internal.org.objectweb.asm.Opcodes; + +public class TestManyBreakpoints { + + static final int BATCHES = 50; + static final int METHODS = 1000; + + public static void main(String[] args) throws Exception { + for (int c = 0; c < BATCHES; c++) { + System.out.println("Batch " + c); + TestClassLoader loader = new TestClassLoader(); + Class.forName("Target", true, loader); + } + } + + private static class TestClassLoader extends ClassLoader implements Opcodes { + static byte[] TARGET_BYTES = generateTarget(); + + private static byte[] generateTarget() { + ClassWriter cw = new ClassWriter(0); + + cw.visit(52, ACC_SUPER | ACC_PUBLIC, "Target", null, "java/lang/Object", null); + for (int m = 0; m < METHODS; m++) { + MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "m" + m, "()V", null, null); + mv.visitCode(); + mv.visitInsn(RETURN); + mv.visitMaxs(0, 0); + mv.visitEnd(); + } + cw.visitEnd(); + return cw.toByteArray(); + } + + @Override + protected Class<?> findClass(String name) throws ClassNotFoundException { + if (name.equals("Target")) { + return defineClass(name, TARGET_BYTES, 0, TARGET_BYTES.length); + } else { + return super.findClass(name); + } + } + } + +} diff --git a/test/hotspot/jtreg/serviceability/jvmti/SetBreakpoint/libTestManyBreakpoints.cpp b/test/hotspot/jtreg/serviceability/jvmti/SetBreakpoint/libTestManyBreakpoints.cpp new file mode 100644 index 0000000000000000000000000000000000000000..dcb8f87ddd7566dfc9bd0143301e28da93c59871 --- /dev/null +++ b/test/hotspot/jtreg/serviceability/jvmti/SetBreakpoint/libTestManyBreakpoints.cpp @@ -0,0 +1,111 @@ +/* + * 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 <string.h> +#include <stdio.h> + +#include "jvmti.h" + +#define TARGET_CLASS_NAME "LTarget;" + +static jvmtiEnv *jvmti = NULL; + +static void +check_jvmti_status(JNIEnv* jni, jvmtiError err, const char* msg) { + if (err != JVMTI_ERROR_NONE) { + printf("check_jvmti_status: %s, JVMTI function returned error: %d\n", msg, err); + jni->FatalError(msg); + } +} + +void JNICALL classprepare(jvmtiEnv* jvmti_env, JNIEnv* jni_env, jthread thread, jclass klass) { + char* buf; + jvmtiError err; + + err = jvmti->GetClassSignature(klass, &buf, NULL); + check_jvmti_status(jni_env, err, "classprepare: GetClassSignature error"); + + if (strncmp(buf, TARGET_CLASS_NAME, strlen(TARGET_CLASS_NAME)) == 0) { + jint nMethods; + jmethodID* methods; + int i; + + err = jvmti->GetClassMethods(klass, &nMethods, &methods); + check_jvmti_status(jni_env, err, "classprepare: GetClassMethods error"); + printf("Setting breakpoints in %s\n", buf); + fflush(stdout); + for (i = 0; i < nMethods; i++) { + err = jvmti->SetBreakpoint(methods[i], 0); + check_jvmti_status(jni_env, err, "classprepare: SetBreakpoint error"); + } + } +} + + +void JNICALL breakpoint(jvmtiEnv* jvmti_env, JNIEnv* jni_env, jthread thread, jmethodID method, jlocation location) { + // Do nothing +} + +JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM* vm, char* options, void* reserved) { + jvmtiCapabilities capa; + jvmtiEventCallbacks cbs; + jint err; + + err = vm->GetEnv((void**)&jvmti, JVMTI_VERSION_1_0); + if (err != JNI_OK) { + printf("Agent_OnLoad: GetEnv error\n"); + return JNI_ERR; + } + + memset(&capa, 0, sizeof(capa)); + capa.can_generate_breakpoint_events = 1; + capa.can_generate_single_step_events = 1; + err = jvmti->AddCapabilities(&capa); + if (err != JNI_OK) { + printf("Agent_OnLoad: AddCapabilities error\n"); + return JNI_ERR; + } + + memset(&cbs, 0, sizeof(cbs)); + cbs.ClassPrepare = classprepare; + cbs.Breakpoint = breakpoint; + err = jvmti->SetEventCallbacks(&cbs, sizeof(cbs)); + if (err != JNI_OK) { + printf("Agent_OnLoad: SetEventCallbacks error\n"); + return JNI_ERR; + } + + err = jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_CLASS_PREPARE, NULL); + if (err != JNI_OK) { + printf("Agent_OnLoad: SetEventNotificationMode CLASS_PREPARE error\n"); + return JNI_ERR; + } + + err = jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_BREAKPOINT, NULL); + if (err != JNI_OK) { + printf("Agent_OnLoad: SetEventNotificationMode BREAKPOINT error\n"); + return JNI_ERR; + } + + return JNI_OK; +} diff --git a/test/hotspot/jtreg/serviceability/jvmti/VMObjectAlloc/VMObjectAllocTest.java b/test/hotspot/jtreg/serviceability/jvmti/VMObjectAlloc/VMObjectAllocTest.java new file mode 100644 index 0000000000000000000000000000000000000000..42e50b4e45dfbf6488cb743251cf7ad658168ce4 --- /dev/null +++ b/test/hotspot/jtreg/serviceability/jvmti/VMObjectAlloc/VMObjectAllocTest.java @@ -0,0 +1,53 @@ +/* + * 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. + */ + +/** + * @test + * @summary Verifies that a VMObjectAlloc event is generated for object created using MethodHandle + * @requires vm.jvmti + * @run main/othervm/native -agentlib:VMObjectAlloc VMObjectAllocTest + */ + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; + +public class VMObjectAllocTest { + + private static native int getNumberOfAllocation(); + + public VMObjectAllocTest(String str) { + } + + public static void main(String[] args) throws Throwable { + + MethodHandles.Lookup publicLookup = MethodHandles.publicLookup(); + MethodType mt = MethodType.methodType(void.class, String.class); + MethodHandle mh = publicLookup.findConstructor(VMObjectAllocTest.class, mt); + mh.invoke("str"); + + if (getNumberOfAllocation() != 1) { + throw new Exception("Number of allocation != 1"); + } + } +} diff --git a/test/hotspot/jtreg/serviceability/jvmti/VMObjectAlloc/libVMObjectAlloc.cpp b/test/hotspot/jtreg/serviceability/jvmti/VMObjectAlloc/libVMObjectAlloc.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fc5113f1aadc652d9dde8b8174c35336062f785e --- /dev/null +++ b/test/hotspot/jtreg/serviceability/jvmti/VMObjectAlloc/libVMObjectAlloc.cpp @@ -0,0 +1,91 @@ +/* + * 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 <string.h> +#include "jvmti.h" + +extern "C" { + +static int number_of_allocation = 0; + +extern JNIEXPORT void JNICALL +VMObjectAlloc(jvmtiEnv *jvmti, + JNIEnv* jni, + jthread thread, + jobject object, + jclass cls, + jlong size) { + char *signature = NULL; + jvmtiError err = jvmti->GetClassSignature(cls, &signature, NULL); + if (err != JVMTI_ERROR_NONE) { + jni->FatalError("Failed during the GetClassSignature call"); + } + + printf("VMObjectAlloc called for %s\n", signature); + + if (!strcmp(signature, "LVMObjectAllocTest;")) { + number_of_allocation++; + } +} + + +JNIEXPORT jint JNICALL +Java_VMObjectAllocTest_getNumberOfAllocation(JNIEnv *env, jclass cls) { + return number_of_allocation; +} + +extern JNIEXPORT jint JNICALL +Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) { + jvmtiEnv *jvmti; + jvmtiEventCallbacks callbacks; + jvmtiError err; + jvmtiCapabilities caps; + + if (jvm->GetEnv((void **) &jvmti, JVMTI_VERSION) != JNI_OK) { + return JNI_ERR; + } + + memset(&callbacks, 0, sizeof(callbacks)); + callbacks.VMObjectAlloc = &VMObjectAlloc; + memset(&caps, 0, sizeof(caps)); + caps.can_generate_vm_object_alloc_events = 1; + + err = jvmti->AddCapabilities( &caps); + if (err != JVMTI_ERROR_NONE) { + return JNI_ERR; + } + + err = jvmti->SetEventCallbacks(&callbacks, sizeof(jvmtiEventCallbacks)); + if (err != JVMTI_ERROR_NONE) { + return JNI_ERR; + } + + err = jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_VM_OBJECT_ALLOC , NULL); + if (err != JVMTI_ERROR_NONE) { + return JNI_ERR; + } + + return JNI_OK; +} + +} //extern "C" diff --git a/test/hotspot/jtreg/serviceability/sa/ClhsdbFindPC.java b/test/hotspot/jtreg/serviceability/sa/ClhsdbFindPC.java index 9990cca9a8158e8531993fde7fea609fc028aa32..4e86d42e5e990bdb77242a6978509c42675617ca 100644 --- a/test/hotspot/jtreg/serviceability/sa/ClhsdbFindPC.java +++ b/test/hotspot/jtreg/serviceability/sa/ClhsdbFindPC.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -35,6 +35,7 @@ import jtreg.SkippedException; * @test id=xcomp-process * @bug 8193124 * @summary Test the clhsdb 'findpc' command with Xcomp on live process + * @requires vm.compMode != "Xcomp" * @requires vm.hasSA * @requires vm.compiler1.enabled * @requires vm.opt.DeoptimizeALot != true @@ -49,6 +50,7 @@ import jtreg.SkippedException; * @requires vm.compMode != "Xcomp" * @requires vm.hasSA * @requires vm.compiler1.enabled + * @requires vm.opt.DeoptimizeALot != true * @library /test/lib * @run main/othervm/timeout=480 ClhsdbFindPC true true */ @@ -59,7 +61,6 @@ import jtreg.SkippedException; * @summary Test the clhsdb 'findpc' command w/o Xcomp on live process * @requires vm.hasSA * @requires vm.compiler1.enabled - * @requires vm.opt.DeoptimizeALot != true * @library /test/lib * @run main/othervm/timeout=480 ClhsdbFindPC false false */ @@ -68,7 +69,6 @@ import jtreg.SkippedException; * @test id=no-xcomp-core * @bug 8193124 * @summary Test the clhsdb 'findpc' command w/o Xcomp on core file - * @requires vm.compMode != "Xcomp" * @requires vm.hasSA * @requires vm.compiler1.enabled * @library /test/lib @@ -182,6 +182,28 @@ public class ClhsdbFindPC { methodAddr)); runTest(withCore, cmds, expStrMap); + // Rerun above findpc command, but this time using "whatis", which is an alias for "findpc". + cmdStr = "whatis " + methodAddr; + cmds = List.of(cmdStr); + expStrMap = new HashMap<>(); + expStrMap.put(cmdStr, List.of("Method ", + "LingeredApp.steadyState", + methodAddr)); + runTest(withCore, cmds, expStrMap); + + // Run "mem -v <addr>/30" on a Method*. The first line will look like: + // Address 0x0000152e30403530: Method jdk/test/lib/apps/LingeredApp.steadyState(Ljava/lang/Object;)V@0x0000152e30403530 + // Followed by lines displaying the memory contents, including interpretation + // of any contents that are addresses. + cmdStr = "mem -v " + methodAddr + "/30"; + cmds = List.of(cmdStr); + expStrMap = new HashMap<>(); + expStrMap.put(cmdStr, List.of("Method jdk/test/lib/apps/LingeredApp.steadyState", + methodAddr, + /* The following is from a field in the Method object. */ + "In interpreter codelet: method entry point")); + runTest(withCore, cmds, expStrMap); + // Run findpc on a JavaThread*. We can find one in the jstack output. // The tid for a thread is it's JavaThread*. For example: // "main" #1 prio=5 tid=0x00000080263398f0 nid=0x277e0 ... diff --git a/test/hotspot/jtreg/serviceability/sa/ClhsdbScanOops.java b/test/hotspot/jtreg/serviceability/sa/ClhsdbScanOops.java index c390fc61dca391f0682e48c2aa86e5ff64bd0cb7..c032b71a000f3746ead6bc8d412145034d3ea885 100644 --- a/test/hotspot/jtreg/serviceability/sa/ClhsdbScanOops.java +++ b/test/hotspot/jtreg/serviceability/sa/ClhsdbScanOops.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -47,6 +47,7 @@ import java.util.Map; import java.util.ArrayList; import jdk.test.lib.Utils; import jdk.test.lib.apps.LingeredApp; +import jdk.test.lib.process.OutputAnalyzer; import jtreg.SkippedException; public class ClhsdbScanOops { @@ -71,35 +72,54 @@ public class ClhsdbScanOops { Map<String, List<String>> expStrMap = new HashMap<>(); Map<String, List<String>> unExpStrMap = new HashMap<>(); - String startAddress = null; - String endAddress = null; - String[] snippets = null; + String startAddress; + String endAddress; + String[] snippets; + String[] words; + String cmd; + // Run scanoops on the old gen + if (gc.contains("UseParallelGC")) { + snippets = universeOutput.split("PSOldGen \\[ "); + } else { + snippets = universeOutput.split("old \\["); + } + words = snippets[1].split(","); + // Get the addresses for Old gen + startAddress = words[0].replace("[", ""); + endAddress = words[1]; + cmd = "scanoops " + startAddress + " " + endAddress; + String output1 = test.run(theApp.getPid(), List.of(cmd), null, null); + + // Run scanoops on the eden gen if (gc.contains("UseParallelGC")) { snippets = universeOutput.split("eden = "); } else { snippets = universeOutput.split("eden \\["); } - String[] words = snippets[1].split(","); - // Get the addresses from Eden + words = snippets[1].split(","); + // Get the addresses for Eden gen startAddress = words[0].replace("[", ""); endAddress = words[1]; - String cmd = "scanoops " + startAddress + " " + endAddress; - cmds.add(cmd); - - expStrMap.put(cmd, List.of - ("java/lang/Object", "java/lang/Class", "java/lang/Thread", - "java/lang/String", "\\[B", "\\[I")); + cmd = "scanoops " + startAddress + " " + endAddress; + String output2 = test.run(theApp.getPid(), List.of(cmd), null, null); + + // Look for expected types in the combined eden and old gens + OutputAnalyzer out = new OutputAnalyzer(output1 + output2); + List<String> expectStrs = List.of( + "java/lang/Object", "java/lang/Class", "java/lang/Thread", + "java/lang/String", "\\[B", "\\[I"); + for (String expectStr : expectStrs) { + out.shouldMatch(expectStr); + } - // Test the 'type' option also - // scanoops <start addr> <end addr> java/lang/String + // Test the 'type' option also: + // scanoops <start addr> <end addr> java/lang/String // Ensure that only the java/lang/String oops are printed. cmd = cmd + " java/lang/String"; - cmds.add(cmd); expStrMap.put(cmd, List.of("java/lang/String")); - unExpStrMap.put(cmd, List.of("java/lang/Thread")); - - test.run(theApp.getPid(), cmds, expStrMap, unExpStrMap); + unExpStrMap.put(cmd, List.of("java/lang/Thread", "java/lang/Class", "java/lang/Object")); + test.run(theApp.getPid(), List.of(cmd), expStrMap, unExpStrMap); } catch (SkippedException e) { throw e; } catch (Exception ex) { diff --git a/test/hotspot/jtreg/serviceability/sa/ClhsdbThreadContext.java b/test/hotspot/jtreg/serviceability/sa/ClhsdbThreadContext.java new file mode 100644 index 0000000000000000000000000000000000000000..e84ae52e92056aa8b787daa6738f692f96cc6c7f --- /dev/null +++ b/test/hotspot/jtreg/serviceability/sa/ClhsdbThreadContext.java @@ -0,0 +1,116 @@ +/* + * 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. + */ + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import jdk.test.lib.apps.LingeredApp; +import jdk.test.lib.Platform; +import jtreg.SkippedException; + +/** + * @test + * @summary Test clhsdb where command + * @requires vm.hasSA + * @library /test/lib + * @run main/othervm ClhsdbThreadContext + */ + +public class ClhsdbThreadContext { + public static void main(String[] args) throws Exception { + System.out.println("Starting ClhsdbThreadContext test"); + + LingeredApp theApp = null; + try { + ClhsdbLauncher test = new ClhsdbLauncher(); + theApp = LingeredApp.startApp(); + System.out.println("Started LingeredApp with pid " + theApp.getPid()); + + // Run threadcontext on all threads + String cmdStr = "threadcontext -a"; + List<String> cmds = List.of(cmdStr); + Map<String, List<String>> expStrMap = new HashMap<>(); + expStrMap.put(cmdStr, List.of( + "Thread \"Common-Cleaner\"", + "Thread \"Service Thread\"", + "Thread \"Finalizer\"", + "Thread \"SteadyStateThread\"", + "In java stack for thread \"SteadyStateThread\"")); + String cmdOutput = test.run(theApp.getPid(), cmds, expStrMap, null); + + // Run threadcontext on all threads in verbose mode + cmdStr = "threadcontext -v -a"; + cmds = List.of(cmdStr); + expStrMap = new HashMap<>(); + expStrMap.put(cmdStr, List.of( + "Thread \"Common-Cleaner\"", + "Thread \"Service Thread\"", + "Thread \"Finalizer\"", + "Thread \"SteadyStateThread\"")); + Map<String, List<String>> unexpStrMap = new HashMap<>(); + unexpStrMap.put(cmdStr, List.of( + "In java stack for thread \"SteadyStateThread\"")); + test.run(theApp.getPid(), cmds, expStrMap, unexpStrMap); + + // Look for a line like the following and parse the threadID out of it. + // Thread "SteadyStateThread" id=18010 Address=0x000014bf103eaf50 + String[] parts = cmdOutput.split("Thread \"SteadyStateThread\" id="); + String[] tokens = parts[1].split(" "); + String threadID = tokens[0]; + + // Run threadcontext on the SteadyStateThread in verbose mode + cmdStr = "threadcontext -v " + threadID; + cmds = List.of(cmdStr); + expStrMap = new HashMap<>(); + unexpStrMap = new HashMap<>(); + if (Platform.isWindows()) { + // On windows thread IDs are not guaranteed to be the same each time you attach, + // so the ID we gleaned above for SteadyStateThread may not actually be for + // SteadyStateThread when we attach for the next threadcontext command, so we + // choose not to check the result on Windows. + } else { + expStrMap.put(cmdStr, List.of( + "Thread \"SteadyStateThread\"", + "java.lang.Thread.State: BLOCKED", + "In java stack \\[0x\\p{XDigit}+,0x\\p{XDigit}+,0x\\p{XDigit}+\\] for thread")); + unexpStrMap.put(cmdStr, List.of( + "Thread \"Common-Cleaner\"", + "Thread \"Service Thread\"", + "Thread \"Finalizer\"")); + } + test.run(theApp.getPid(), cmds, expStrMap, unexpStrMap); + + // Run threadcontext on all threads in verbose mode + + } catch (SkippedException se) { + throw se; + } catch (Exception ex) { + throw new RuntimeException("Test ERROR " + ex, ex); + } finally { + LingeredApp.stopApp(theApp); + } + + System.out.println("Test PASSED"); + } +} diff --git a/test/hotspot/jtreg/serviceability/sa/ClhsdbVmStructsDump.java b/test/hotspot/jtreg/serviceability/sa/ClhsdbVmStructsDump.java index 680d9078d3bfcfb3d8feae542d7b44324455e2ef..050ec9c05d62b8ee82d9769d066931be0cd6f029 100644 --- a/test/hotspot/jtreg/serviceability/sa/ClhsdbVmStructsDump.java +++ b/test/hotspot/jtreg/serviceability/sa/ClhsdbVmStructsDump.java @@ -57,7 +57,7 @@ public class ClhsdbVmStructsDump { "field Klass _name Symbol*", "type ClassLoaderData* null", "field JavaThread _osthread OSThread*", - "type TenuredGeneration CardGeneration", + "type TenuredGeneration Generation", "type Universe null", "type ConstantPoolCache MetaspaceObj")); test.run(theApp.getPid(), cmds, expStrMap, null); diff --git a/test/hotspot/jtreg/serviceability/sa/LingeredAppWithLock.java b/test/hotspot/jtreg/serviceability/sa/LingeredAppWithLock.java index 9acf9d3bbb90c5c2e9f99db42300a7380a445417..4140a3e3381047ec954c970a25742acb8655c586 100644 --- a/test/hotspot/jtreg/serviceability/sa/LingeredAppWithLock.java +++ b/test/hotspot/jtreg/serviceability/sa/LingeredAppWithLock.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -47,6 +47,19 @@ public class LingeredAppWithLock extends LingeredApp { objectLock.start(); primitiveLock.start(); + // Wait until all threads have reached their blocked or timed wait state + while ((classLock1.getState() != Thread.State.BLOCKED && + classLock1.getState() != Thread.State.TIMED_WAITING) || + (classLock2.getState() != Thread.State.BLOCKED && + classLock2.getState() != Thread.State.TIMED_WAITING) || + (objectLock.getState() != Thread.State.TIMED_WAITING) || + (primitiveLock.getState() != Thread.State.TIMED_WAITING)) { + try { + Thread.sleep(100); + } catch (InterruptedException ex) { + } + } + LingeredApp.main(args); } } diff --git a/test/hotspot/jtreg/serviceability/sa/TestJmapCore.java b/test/hotspot/jtreg/serviceability/sa/TestJmapCore.java index 1c861f8c6015d4f379d89c0256978bc45a8975bb..1acb962c494802a6cb4f7b112957d93615132986 100644 --- a/test/hotspot/jtreg/serviceability/sa/TestJmapCore.java +++ b/test/hotspot/jtreg/serviceability/sa/TestJmapCore.java @@ -26,7 +26,7 @@ * @summary Test verifies that jhsdb jmap could generate heap dump from core when heap is full * @requires vm.hasSA * @library /test/lib - * @run driver/timeout=240 TestJmapCore run heap + * @run driver/timeout=480 TestJmapCore run heap */ import java.io.File; diff --git a/test/hotspot/jtreg/serviceability/sa/TestObjectMonitorIterate.java b/test/hotspot/jtreg/serviceability/sa/TestObjectMonitorIterate.java index 5f1e6c48f5f98e2bed92b705b9636eb939d90529..e2d79b1ce9df751fd5592f343067e977b95e4eda 100644 --- a/test/hotspot/jtreg/serviceability/sa/TestObjectMonitorIterate.java +++ b/test/hotspot/jtreg/serviceability/sa/TestObjectMonitorIterate.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2021, NTT DATA. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -59,8 +59,12 @@ public class TestObjectMonitorIterate { while (itr.hasNext()) { ObjectMonitor mon = (ObjectMonitor)itr.next(); - Oop oop = heap.newOop(mon.object()); - System.out.println("Monitor found: " + oop.getKlass().getName().asString()); + if (mon.object() == null) { + System.out.println("Monitor found: object is null"); + } else { + Oop oop = heap.newOop(mon.object()); + System.out.println("Monitor found: " + oop.getKlass().getName().asString()); + } } } finally { agent.detach(); diff --git a/test/hotspot/jtreg/serviceability/sa/TestType.java b/test/hotspot/jtreg/serviceability/sa/TestType.java index 1e4a9e56e575b9de43b59935862031cc96bc0ec4..4f71e42cd4e7c83eae6f2c03f24ea05bb5238fbc 100644 --- a/test/hotspot/jtreg/serviceability/sa/TestType.java +++ b/test/hotspot/jtreg/serviceability/sa/TestType.java @@ -62,7 +62,6 @@ public class TestType { "type ConstantPoolCache MetaspaceObj", "type ConstantPool Metadata", "type CompilerThread JavaThread", - "type CardGeneration Generation", "type ArrayKlass Klass", "type InstanceKlass Klass")); // String to check for in the output of "type InstanceKlass" diff --git a/test/hotspot/jtreg/serviceability/sa/sadebugd/SADebugDTest.java b/test/hotspot/jtreg/serviceability/sa/sadebugd/SADebugDTest.java index a0bbdbc809b0c4c5fc8f6fd8dfe4ffff122ed70e..49f90f7f9fd155515c6773dc6b4f3c840f01c7b2 100644 --- a/test/hotspot/jtreg/serviceability/sa/sadebugd/SADebugDTest.java +++ b/test/hotspot/jtreg/serviceability/sa/sadebugd/SADebugDTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -23,7 +23,7 @@ /** * @test - * @bug 8163805 8224252 8196751 + * @bug 8163805 8224252 8196751 8279351 * @summary Checks that the jshdb debugd utility successfully starts * and tries to attach to a running process * @requires vm.hasSA @@ -71,6 +71,16 @@ public class SADebugDTest { } } + private static boolean checkOutput(final String line, final boolean useRmiPort, final int rmiPort) { + if (!useRmiPort && line.contains(GOLDEN)) { + testResult = true; + } else if (useRmiPort && line.contains(RMI_CONNECTOR_IS_BOUND + rmiPort)) { + testResult = true; + } else if (line.contains(ADDRESS_ALREADY_IN_USE)) { + portInUse = true; + } + return (line.contains(GOLDEN) || portInUse); + } private static void testWithPid(final boolean useRmiPort, final boolean useRegistryPort, final boolean useHostName) throws Exception { LingeredApp app = null; @@ -95,9 +105,8 @@ public class SADebugDTest { jhsdbLauncher.addToolArg(Integer.toString(registryPort)); } - int rmiPort = -1; + final int rmiPort = useRmiPort ? Utils.findUnreservedFreePort(REGISTRY_DEFAULT_PORT, registryPort) : -1; if (useRmiPort) { - rmiPort = Utils.findUnreservedFreePort(REGISTRY_DEFAULT_PORT, registryPort); jhsdbLauncher.addToolArg("--rmiport"); jhsdbLauncher.addToolArg(Integer.toString(rmiPort)); } @@ -107,28 +116,16 @@ public class SADebugDTest { } ProcessBuilder pb = SATestUtils.createProcessBuilder(jhsdbLauncher); - final int finalRmiPort = rmiPort; - // The startProcess will block until the 'golden' string appears in either process' stdout or stderr // In case of timeout startProcess kills the debugd process - Process debugd = startProcess("debugd", pb, null, - l -> { - if (!useRmiPort && l.contains(GOLDEN)) { - testResult = true; - } else if (useRmiPort && l.contains(RMI_CONNECTOR_IS_BOUND + finalRmiPort)) { - testResult = true; - } else if (l.contains(ADDRESS_ALREADY_IN_USE)) { - portInUse = true; - } - return (l.contains(GOLDEN) || portInUse); - }, 20, TimeUnit.SECONDS); + Process debugd = startProcess("debugd", pb, null, l -> checkOutput(l, useRmiPort, rmiPort), 20, TimeUnit.SECONDS); // If we are here, this means we have received the golden line and the test has passed // The debugd remains running, we have to kill it debugd.destroy(); debugd.waitFor(); - if (!testResult) { + if (!testResult && !portInUse) { throw new RuntimeException("Expected message \"" + RMI_CONNECTOR_IS_BOUND + rmiPort + "\" is not found in the output."); } 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 187b86f6f3a1e078eff1b28b3bb03e3949429afc..2f0dca674270515806b7a4927d84fc899eafc811 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -93,7 +93,7 @@ public class CtwRunner { errors = new ArrayList<>(); if (start.endsWith("%") && stop.endsWith("%")) { - int startPercentage = Integer.parseInt(start.substring(0, start.length() - 1));; + int startPercentage = Integer.parseInt(start.substring(0, start.length() - 1)); int stopPercentage = Integer.parseInt(stop.substring(0, stop.length() - 1)); if (startPercentage < 0 || startPercentage > 100 || stopPercentage < 0 || stopPercentage > 100) { @@ -291,7 +291,7 @@ public class CtwRunner { "-XX:+StressIGVN", "-XX:+StressCCP", // StressSeed is uint - "-XX:StressSeed=" + Math.abs(rng.nextLong()), + "-XX:StressSeed=" + Math.abs(rng.nextInt()), // CTW entry point CompileTheWorld.class.getName(), target)); diff --git a/test/hotspot/jtreg/testlibrary_tests/ir_framework/examples/IRExample.java b/test/hotspot/jtreg/testlibrary_tests/ir_framework/examples/IRExample.java index 950cca3844fcae57d955eadac656460656fc0dad..9142d31307833a98dd141940f6647c0590cab368 100644 --- a/test/hotspot/jtreg/testlibrary_tests/ir_framework/examples/IRExample.java +++ b/test/hotspot/jtreg/testlibrary_tests/ir_framework/examples/IRExample.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -24,7 +24,7 @@ package ir_framework.examples; import compiler.lib.ir_framework.*; -import compiler.lib.ir_framework.driver.IRViolationException; +import compiler.lib.ir_framework.driver.irmatching.IRViolationException; /* * @test diff --git a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestCheckedTests.java b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestCheckedTests.java index 6a8d5c50c6acc0b89dc227329cbd1bcacb6e7ac6..c08635b14bc3cc008f09464c0e09e293a67eeebe 100644 --- a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestCheckedTests.java +++ b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestCheckedTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -24,7 +24,7 @@ package ir_framework.tests; import compiler.lib.ir_framework.*; -import compiler.lib.ir_framework.driver.IRViolationException; +import compiler.lib.ir_framework.driver.irmatching.IRViolationException; import compiler.lib.ir_framework.driver.TestVMException; import java.io.ByteArrayOutputStream; import java.io.PrintStream; diff --git a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestCompileThreshold.java b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestCompileThreshold.java index 76090b94efc746807558f37a5a85fd4fae71c5c8..145430f61f99b964825b4b31ee9e3d14e77f4f59 100644 --- a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestCompileThreshold.java +++ b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestCompileThreshold.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -24,7 +24,7 @@ package ir_framework.tests; import compiler.lib.ir_framework.*; -import compiler.lib.ir_framework.driver.IRViolationException; +import compiler.lib.ir_framework.driver.irmatching.IRViolationException; import jdk.test.lib.Asserts; /* diff --git a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestIRMatching.java b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestIRMatching.java index f4ce560d2f4d381d41761f44f07e57c6bcd8c2fd..c6c81d8c2042124706b646028aca262d424729e6 100644 --- a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestIRMatching.java +++ b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestIRMatching.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -24,7 +24,7 @@ package ir_framework.tests; import compiler.lib.ir_framework.*; -import compiler.lib.ir_framework.driver.IRViolationException; +import compiler.lib.ir_framework.driver.irmatching.IRViolationException; import jdk.test.lib.Asserts; import jdk.test.lib.Platform; import sun.hotspot.WhiteBox; @@ -60,7 +60,7 @@ public class TestIRMatching { private static void addException(Exception e) { System.out.flush(); System.err.flush(); - exceptions.put(e, baos.toString() + System.lineSeparator() + baosErr.toString()); + exceptions.put(e, baos + System.lineSeparator() + baosErr); } public static void main(String[] args) { @@ -285,20 +285,20 @@ public class TestIRMatching { runWithArguments(FlagComparisons.class, "-XX:TLABRefillWasteFraction=50"); System.out.flush(); String output = baos.toString(); - findIrIds(output, "testMatchAllIf50", 0, 21); + findIrIds(output, "testMatchAllIf50", 1, 22); findIrIds(output, "testMatchNoneIf50", -1, -1); runWithArguments(FlagComparisons.class, "-XX:TLABRefillWasteFraction=49"); System.out.flush(); output = baos.toString(); - findIrIds(output, "testMatchAllIf50", 4, 6, 13, 18); - findIrIds(output, "testMatchNoneIf50", 0, 3, 8, 10, 17, 22); + findIrIds(output, "testMatchAllIf50", 5, 7, 14, 19); + findIrIds(output, "testMatchNoneIf50", 1, 4, 9, 11, 18, 23); runWithArguments(FlagComparisons.class, "-XX:TLABRefillWasteFraction=51"); System.out.flush(); output = baos.toString(); - findIrIds(output, "testMatchAllIf50", 7, 12, 19, 21); - findIrIds(output, "testMatchNoneIf50", 4, 7, 11, 16, 20, 22); + findIrIds(output, "testMatchAllIf50", 8, 13, 20, 22); + findIrIds(output, "testMatchNoneIf50", 5, 8, 12, 17, 21, 23); System.setOut(oldOut); System.setErr(oldErr); @@ -395,7 +395,7 @@ public class TestIRMatching { } } if (!output.contains(builder.toString())) { - addException(new RuntimeException("Could not find encoding: \"" + builder.toString() + System.lineSeparator())); + addException(new RuntimeException("Could not find encoding: \"" + builder + System.lineSeparator())); } } } @@ -550,20 +550,20 @@ class MultipleFailOnBad { class FlagComparisons { // Applies all IR rules if TLABRefillWasteFraction=50 @Test - @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "50"}) // Index 0 + @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "50"}) // Index 1 @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "=50"}) @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "= 50"}) @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", " = 50"}) - @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "<=50"}) // Index 4 + @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "<=50"}) // Index 5 @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "<= 50"}) @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", " <= 50"}) - @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", ">=50"}) // Index 7 + @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", ">=50"}) // Index 8 @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", ">= 50"}) @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", " >= 50"}) @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", ">49"}) @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "> 49"}) @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", " > 49"}) - @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "<51"}) // Index 13 + @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "<51"}) // Index 14 @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "< 51"}) @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", " < 51"}) @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "!=51"}) @@ -571,34 +571,34 @@ class FlagComparisons { @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", " != 51"}) @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "!=49"}) @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "!= 49"}) - @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", " != 49"}) // Index 21 + @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", " != 49"}) // Index 22 public void testMatchAllIf50() {} // Applies no IR rules if TLABRefillWasteFraction=50 @Test - @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "49"}) // Index 0 + @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "49"}) // Index 1 @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "=49"}) @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "= 49"}) @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", " = 49"}) - @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "51"}) // Index 4 + @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "51"}) // Index 5 @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "=51"}) @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "= 51"}) @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", " = 51"}) - @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "<=49"}) // Index 8 + @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "<=49"}) // Index 9 @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "<= 49"}) @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", " <= 49"}) - @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", ">=51"}) // Index 11 + @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", ">=51"}) // Index 12 @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", ">= 51"}) @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", " >= 51"}) @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", ">50"}) @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "> 50"}) @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", " > 50"}) - @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "<50"}) // Index 17 + @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "<50"}) // Index 18 @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "< 50"}) @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", " < 50"}) @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "!=50"}) @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "!= 50"}) - @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", " != 50"}) // Index 22 + @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", " != 50"}) // Index 23 public void testMatchNoneIf50() {} } @@ -814,14 +814,14 @@ class BadCount { int iFld; int result; @Test - @IR(counts = {IRNode.LOAD, "!= 1"}) + @IR(counts = {IRNode.LOAD, "!= 1"}) // fail @IR(counts = {IRNode.STORE, "> 0"}) public void bad1() { result = iFld; } @Test - @IR(counts = {IRNode.LOAD, "1"}) + @IR(counts = {IRNode.LOAD, "1"}) // fail @IR(counts = {IRNode.STORE, "< 1"}) public void bad2() { result = iFld; @@ -829,8 +829,8 @@ class BadCount { @Test - @IR(counts = {IRNode.LOAD, "0"}) - @IR(counts = {IRNode.STORE, " <= 0"}) + @IR(counts = {IRNode.LOAD, "0"}) // fail + @IR(counts = {IRNode.STORE, " <= 0"}) // fail public void bad3() { result = iFld; } @@ -1514,7 +1514,7 @@ abstract class Constraint { } } } - Asserts.assertTrue(matched, toString() + " should have been matched"); + Asserts.assertTrue(matched, this + " should have been matched"); } abstract protected void checkIRRule(String irRule); @@ -1732,7 +1732,7 @@ class BadCountsConstraint extends RegexConstraint { private static List<String> getMatchesList(int foundCount, String[] matches, List<String> strings) { List<String> matchesList = new ArrayList<>(); - matchesList.add("but found " + foundCount); + matchesList.add("Failed comparison: [found] " + foundCount); if (matches != null) { matchesList.addAll(strings); } diff --git a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestRunTests.java b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestRunTests.java index 780075f50dded29eb2801434dba7d57baeb9e79e..d2c83edde7e8d3c0d0ca7fb38b743854f74f3818 100644 --- a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestRunTests.java +++ b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestRunTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -24,7 +24,7 @@ package ir_framework.tests; import compiler.lib.ir_framework.*; -import compiler.lib.ir_framework.driver.IRViolationException; +import compiler.lib.ir_framework.driver.irmatching.IRViolationException; import compiler.lib.ir_framework.shared.TestRunException; import jdk.test.lib.Asserts; diff --git a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/Utils.java b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/Utils.java index 2b4e76a680541bf593c75f64e67d0a47e4705607..10c104734570a9e10d4f1410fc0daa8c3c64ec76 100644 --- a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/Utils.java +++ b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/Utils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -24,8 +24,7 @@ package ir_framework.tests; import compiler.lib.ir_framework.Scenario; -import compiler.lib.ir_framework.driver.IRMatcher; -import compiler.lib.ir_framework.driver.TestVMProcess; +import compiler.lib.ir_framework.driver.irmatching.IRMatcher; import jdk.test.lib.Asserts; import java.util.Arrays; diff --git a/test/hotspot/jtreg/vmTestbase/gc/gctests/LoadUnloadGC/LoadUnloadGC.java b/test/hotspot/jtreg/vmTestbase/gc/gctests/LoadUnloadGC/LoadUnloadGC.java index edd65b81145d6b93171b6d3ac8c221d3e1f87ba3..9b79865462d6fd6d2aef0e092c2613b89f08cb6c 100644 --- a/test/hotspot/jtreg/vmTestbase/gc/gctests/LoadUnloadGC/LoadUnloadGC.java +++ b/test/hotspot/jtreg/vmTestbase/gc/gctests/LoadUnloadGC/LoadUnloadGC.java @@ -28,11 +28,11 @@ * @summary converted from VM Testbase gc/gctests/LoadUnloadGC. * VM Testbase keywords: [gc, stress, stressopt, nonconcurrent, monitoring] * VM Testbase readme: - * In this test a 1000 classes are loaded and unloaded in a loop. + * In this test 1000 classes are loaded and unloaded in a loop. * Class0 gets loaded which results in Class1 getting loaded and so on all - * the way uptill class1000. The classes should be unloaded whenever a + * the way up to class1000. The classes should be unloaded whenever a * garbage collection takes place because their classloader is made unreachable - * at the end of the each loop iteration. The loop is repeated 1000 times. + * at the end of each loop iteration. The loop is repeated 1000 times. * * @requires vm.opt.final.ClassUnloading * @library /vmTestbase @@ -45,6 +45,30 @@ * gc.gctests.LoadUnloadGC.LoadUnloadGC */ +/* + * @test + * @key stress + * + * @summary converted from VM Testbase gc/gctests/LoadUnloadGC. + * VM Testbase keywords: [gc, stress, stressopt, nonconcurrent, monitoring] + * VM Testbase readme: + * In this test 1000 classes are loaded and unloaded in a loop. + * Class0 gets loaded which results in Class1 getting loaded and so on all + * the way up to class1000. The classes should be unloaded whenever a + * garbage collection takes place because their classloader is made unreachable + * at the end of each loop iteration. The loop is repeated 1000 times. + * + * @requires vm.opt.final.ClassUnloading + * @library /vmTestbase + * /test/lib + * @build nsk.share.gc.ClassChain + * @run main/othervm + * -XX:MaxMetaspaceSize=64M + * -XX:MetaspaceSize=64M + * -XX:CompressedClassSpaceSize=32M + * gc.gctests.LoadUnloadGC.LoadUnloadGC + */ + package gc.gctests.LoadUnloadGC; import nsk.share.test.*; diff --git a/test/hotspot/jtreg/vmTestbase/jit/series/series.java b/test/hotspot/jtreg/vmTestbase/jit/series/series.java index c17e24427f90a7bc6f0d470c8231a1600e54978d..eef54c2c81a11109f246601b7f40f2b101b2cf8e 100644 --- a/test/hotspot/jtreg/vmTestbase/jit/series/series.java +++ b/test/hotspot/jtreg/vmTestbase/jit/series/series.java @@ -192,7 +192,7 @@ fres); { series patObj = new series(); if (patObj.runit()!=0) - throw new TestFailure("Test failed.");; + throw new TestFailure("Test failed."); series.goldChecker.check(); } } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/threadgroup/threadgroup002/threadgroup002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/threadgroup/threadgroup002/threadgroup002.java index cb8004643d3b7ec8232ed3d13def30043c0db52e..72bbf3584741d07130c3d4c9d1c9875e3667a3e0 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/threadgroup/threadgroup002/threadgroup002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/threadgroup/threadgroup002/threadgroup002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 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 @@ -29,11 +29,15 @@ * VM Testbase keywords: [jpda, jdb] * VM Testbase readme: * DECSRIPTION - * This is a test for jdb 'threadgroup <threadgroup_name>' command. + * This is a test for jdb 'threadgroup <threadgroup_name>' command and + * also for the 'threadgroup' command with no argument. * The main thread creates 3 threadgroups of 5 threads each. * All threads are locked in their 'run' method on a lock that the main - * thread holds. The test passes if jdb correctly switches between - * three user-defined threadgroups using 'threadgroup' command. + * thread holds. The test then makes sure jdb correctly switches between + * the three user-defined threadgroups using 'threadgroup' command. It then + * resets the current threadgroup back to the default top level threadgroup + * by using the 'threadgroup' command with no argument. It then tests that + * all 3 created threadgroups can be found in the 'threads' output. * COMMENTS * This test functionally equals to nsk/jdb/threadgroup/threadgroup001 * test and replaces it. @@ -45,6 +49,7 @@ * nsk.jdb.threadgroup.threadgroup002.threadgroup002 * -arch=${os.family}-${os.simpleArch} * -waittime=5 + * -verbose * -debugee.vmkind=java * -transport.address=dynamic * -jdb=${test.jdk}/bin/jdb @@ -100,6 +105,15 @@ public class threadgroup002 extends JdbTest { } } + // Test switching back to the default top level group. + reply = jdb.receiveReplyFor(JdbCommand.threadgroup); + reply = jdb.receiveReplyFor(JdbCommand.threads); + grep = new Paragrep(reply); + count = grep.find(threadgroup002a.THREADGROUP_NAME); + if (count != threadgroup002a.numThreadGroups) { + failure("jdb cannot switch to default top level threadgroup"); + } + jdb.contToExit(1); } } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/unmonitor/unmonitor001/unmonitor001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/unmonitor/unmonitor001/unmonitor001.java index 54a90a930f277064826f54926000716264371238..9fe8a7e57035d34b51ebe466894c026e9bee9aba 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/unmonitor/unmonitor001/unmonitor001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/unmonitor/unmonitor001/unmonitor001.java @@ -172,7 +172,7 @@ public class unmonitor001 extends JdbTest { private boolean checkCommands(String[] reply) { Paragrep grep; String found; - Vector v = new Vector();; + Vector v = new Vector(); boolean result = true; int count; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/BScenarios/multithrd/tc02x003.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/BScenarios/multithrd/tc02x003.java index 4fd48e21ff06ac70913a9fd55986ddd7cf7a1fab..79bb11fc70677ea36dfbd344263e340ab320b312 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/BScenarios/multithrd/tc02x003.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/BScenarios/multithrd/tc02x003.java @@ -146,7 +146,7 @@ public class tc02x003 { hitEvent(clsEvent); mthdReq = evm.createMethodEntryRequest(); - ReferenceType testedClass = clsEvent.referenceType();; + ReferenceType testedClass = clsEvent.referenceType(); mthdReq.addClassFilter(testedClass); mthdReq.enable(); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassObjectReference/reflectedType/reflectype002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassObjectReference/reflectedType/reflectype002.java index da528cee5b30ec49e7508bbabf91de7d53e1fe5a..46608d9b07d85447a9db4bf76600f9f9aa15f54a 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassObjectReference/reflectedType/reflectype002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassObjectReference/reflectedType/reflectype002.java @@ -166,7 +166,7 @@ public class reflectype002 extends Log { print_log_on_verbose ("--> reflectype002: getting ClassObjectReference object for loaded checked class..."); - ClassObjectReference class_obj_ref = refType.classObject();; + ClassObjectReference class_obj_ref = refType.classObject(); print_log_on_verbose("--> reflectype002: getting ClassObjectReference object - DONE!"); print_log_on_verbose diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/LocalVariable/isVisible/isvisible001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/LocalVariable/isVisible/isvisible001.java index 9d5dba92c757f8539672ed25f7da0b108846c0c4..5593aabe31b6caf9d5959f09ad6f48e0c74f399d 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/LocalVariable/isVisible/isvisible001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/LocalVariable/isVisible/isvisible001.java @@ -415,7 +415,7 @@ public class isvisible001 { expresult = returnCode1; } } catch ( IllegalArgumentException e ) { - log3("ERROR: IllegalArgumentException for i3 in stackFrame");; + log3("ERROR: IllegalArgumentException for i3 in stackFrame"); expresult = returnCode1; } } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ObjectReference/referringObjects/referringObjects002/referringObjects002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ObjectReference/referringObjects/referringObjects002/referringObjects002.java index 95d3edf1050fac1bf1ef2e24d2ee1276a0a5b153..f1a2432b573623f9a7b891916d57fa40b611341e 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ObjectReference/referringObjects/referringObjects002/referringObjects002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ObjectReference/referringObjects/referringObjects002/referringObjects002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 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 @@ -56,6 +56,8 @@ * @build nsk.jdi.ObjectReference.referringObjects.referringObjects002.referringObjects002 * nsk.jdi.ObjectReference.referringObjects.referringObjects002.referringObjects002a * nsk.share.jdi.TestClass1 + * @build sun.hotspot.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller sun.hotspot.WhiteBox * @run main/othervm/native * nsk.jdi.ObjectReference.referringObjects.referringObjects002.referringObjects002 * -verbose @@ -63,7 +65,8 @@ * -waittime=5 * -debugee.vmkind=java * -transport.address=dynamic - * -debugee.vmkeys="-Xmx256M ${test.vm.opts} ${test.java.opts}" + * -debugee.vmkeys="-Xmx256M -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI ${test.vm.opts} ${test.java.opts}" * -testClassPath ${test.class.path} */ @@ -97,6 +100,10 @@ public class referringObjects002 extends HeapwalkingDebugger { public void checkClassObjectReferrersCount(ClassObjectReference classObjectReference, int expectedCount) { int referrersCount = classObjectReference.referringObjects(0).size(); + log.display("References:"); + for (ObjectReference ref: classObjectReference.referringObjects(0)) { + log.display(ref); + } if (referrersCount != expectedCount) { setSuccess(false); @@ -137,7 +144,6 @@ public class referringObjects002 extends HeapwalkingDebugger { expectedReferrersCount = 3; checkClassObjectReferrersCount(classObjectReference, expectedReferrersCount); - // disable collection and try unload class object classObjectReference.disableCollection(); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ObjectReference/referringObjects/referringObjects002/referringObjects002a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ObjectReference/referringObjects/referringObjects002/referringObjects002a.java index 1e90e159b58ab7d185f43ff0ed61bcf2c6b0eb86..6a0489d62ead5d1ae469bd64fae68dd2ffc83ad8 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ObjectReference/referringObjects/referringObjects002/referringObjects002a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ObjectReference/referringObjects/referringObjects002/referringObjects002a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 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 @@ -29,6 +29,7 @@ import nsk.share.TestBug; import nsk.share.jdi.HeapwalkingDebuggee; import java.io.*; import java.util.*; +import sun.hotspot.WhiteBox; /* * Class create and save given number of class instances @@ -56,6 +57,8 @@ public class referringObjects002a extends HeapwalkingDebuggee { final static public String COMMAND_DELETE_CLASS_OBJECT_REFERRERS = "deleteClassObjectReferrers"; + private final WhiteBox WB = WhiteBox.getWhiteBox(); + public static void main(String args[]) { new referringObjects002a().doTest(args); } @@ -76,6 +79,9 @@ public class referringObjects002a extends HeapwalkingDebuggee { for (String referenceType : ObjectInstancesManager.allReferenceTypes) classReferrers.add(new ReferringObject(klass, referenceType)); + // force full GC with WB to ensure that weak refernces are collected + // j.l.i.MethodType has ConcurrentWeakInternSet which might contain references to TestClass1 + WB.fullGC(); } // delete all created references to class object diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadReference/frames/frames001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadReference/frames/frames001.java index cc75403caf611e00127581d27824aa4604c6d67a..2e361e65cab007b50721daedee2a70e71f4c2935 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadReference/frames/frames001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadReference/frames/frames001.java @@ -373,7 +373,7 @@ public class frames001 { log2(" getting new List of frames"); try { - frameList = thread2.frames();; + frameList = thread2.frames(); } catch ( IndexOutOfBoundsException e1 ) { log3("ERROR: IndexOutOfBoundsException"); expresult = returnCode1; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/TypeComponent/isSynthetic/issynthetic001a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/TypeComponent/isSynthetic/issynthetic001a.java index d65ae796b4e0410427e5aa27d76b215e47f7faca..0ccc8460a67388fb6eaa111927f3bf8fbe09a283 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/TypeComponent/isSynthetic/issynthetic001a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/TypeComponent/isSynthetic/issynthetic001a.java @@ -27,6 +27,7 @@ package nsk.jdi.TypeComponent.isSynthetic; import nsk.share.*; import nsk.share.jpda.*; import nsk.share.jdi.*; +import java.util.Objects; public class issynthetic001a { @@ -94,5 +95,10 @@ class ClassToCheck { protected Inter ER0, ER1[]={ER0}, ER2[][]={ER1}; transient Inter ET0, ET1[]={ET0}, ET2[][]={ET1}; volatile Inter EV0, EV1[]={EV0}, EV2[][]={EV1}; + + { + // access enclosing instance so this$0 field is generated + Objects.requireNonNull(ClassToCheck.this); + } } } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetThreadState/thrstat002/thrstat002.cpp b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetThreadState/thrstat002/thrstat002.cpp index 4840af81f3838f6dd59fd89f9d4ff67318320fc8..2b10a77c56caa8c3a616076733f7f9ce0f3b2623 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetThreadState/thrstat002/thrstat002.cpp +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetThreadState/thrstat002/thrstat002.cpp @@ -48,6 +48,107 @@ static jint state[] = { JVMTI_THREAD_STATE_IN_OBJECT_WAIT }; + +#if 1 // support for debug tracing + +#define LOG(...) \ + { \ + printf(__VA_ARGS__); \ + fflush(stdout); \ + } + +#define MAX_FRAME_COUNT_PRINT_STACK_TRACE 200 + +static void +check_jvmti_status(JNIEnv* jni, jvmtiError err, const char* msg) { + if (err != JVMTI_ERROR_NONE) { + LOG("check_jvmti_status: JVMTI function returned error: %s (%d)\n", TranslateError(err), err); + jni->FatalError(msg); + } +} + +static void +deallocate(jvmtiEnv *jvmti, JNIEnv* jni, void* ptr) { + jvmtiError err; + + err = jvmti->Deallocate((unsigned char*)ptr); + check_jvmti_status(jni, err, "deallocate: error in JVMTI Deallocate call"); +} + +static char* +get_method_class_name(jvmtiEnv *jvmti, JNIEnv* jni, jmethodID method) { + jclass klass = NULL; + char* cname = NULL; + char* result = NULL; + jvmtiError err; + + err = jvmti->GetMethodDeclaringClass(method, &klass); + check_jvmti_status(jni, err, "get_method_class_name: error in JVMTI GetMethodDeclaringClass"); + + err = jvmti->GetClassSignature(klass, &cname, NULL); + check_jvmti_status(jni, err, "get_method_class_name: error in JVMTI GetClassSignature"); + + size_t len = strlen(cname) - 2; // get rid of leading 'L' and trailing ';' + + err = jvmti->Allocate((jlong)(len + 1), (unsigned char**)&result); + check_jvmti_status(jni, err, "get_method_class_name: error in JVMTI Allocate"); + + strncpy(result, cname + 1, len); // skip leading 'L' + result[len] = '\0'; + deallocate(jvmti, jni, (void*)cname); + return result; +} + +static void +print_method(jvmtiEnv *jvmti, JNIEnv* jni, jmethodID method, jint depth) { + char* cname = NULL; + char* mname = NULL; + char* msign = NULL; + jvmtiError err; + + cname = get_method_class_name(jvmti, jni, method); + + err = jvmti->GetMethodName(method, &mname, &msign, NULL); + check_jvmti_status(jni, err, "print_method: error in JVMTI GetMethodName"); + + LOG("%2d: %s: %s%s\n", depth, cname, mname, msign); + fflush(0); + deallocate(jvmti, jni, (void*)cname); + deallocate(jvmti, jni, (void*)mname); + deallocate(jvmti, jni, (void*)msign); +} + +static char* +get_thread_name(jvmtiEnv *jvmti, JNIEnv* jni, jthread thread) { + jvmtiThreadInfo thr_info; + jvmtiError err; + + memset(&thr_info, 0, sizeof(thr_info)); + err = jvmti->GetThreadInfo(thread, &thr_info); + check_jvmti_status(jni, err, "get_thread_name: error in JVMTI GetThreadInfo call"); + + return thr_info.name == NULL ? (char*)"<Unnamed thread>" : thr_info.name; +} + +static void +print_stack_trace(jvmtiEnv *jvmti, JNIEnv* jni, jthread thread) { + jvmtiFrameInfo frames[MAX_FRAME_COUNT_PRINT_STACK_TRACE]; + char* tname = get_thread_name(jvmti, jni, thread); + jint count = 0; + jvmtiError err; + + err = jvmti->GetStackTrace(thread, 0, MAX_FRAME_COUNT_PRINT_STACK_TRACE, frames, &count); + check_jvmti_status(jni, err, "print_stack_trace: error in JVMTI GetStackTrace"); + + LOG("JVMTI Stack Trace for thread %s: frame count: %d\n", tname, count); + for (int depth = 0; depth < count; depth++) { + print_method(jvmti, jni, frames[depth].method, depth); + } + deallocate(jvmti, jni, (void*)tname); + LOG("\n"); +} +#endif // support for debug tracing + void printStateFlags(jint flags) { if (flags & JVMTI_THREAD_STATE_SUSPENDED) printf(" JVMTI_THREAD_STATE_SUSPENDED"); @@ -337,6 +438,9 @@ Java_nsk_jvmti_GetThreadState_thrstat002_checkStatus(JNIEnv *env, jclass cls, TranslateState(state[statInd]), state[statInd]); printf(" actual: %s (%d)\n", TranslateState(thrState), thrState); +#ifdef DBG + print_stack_trace(jvmti, env, thr_ptr); +#endif result = STATUS_FAILED; } if (suspState != JVMTI_THREAD_STATE_SUSPENDED) { diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/SuspendThread/suspendthrd003.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/SuspendThread/suspendthrd003.java index fd98b382d2a4a8898e342fa0480550b6633e6a67..e2a48a948e9c40050989b632682e10c5faf2be0c 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/SuspendThread/suspendthrd003.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/SuspendThread/suspendthrd003.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -88,6 +88,9 @@ public class suspendthrd003 extends DebugeeClass { int res = -1; long start_time = System.currentTimeMillis(); while (System.currentTimeMillis() < start_time + (timeMax * 1000)) { + // Start each loop with a clear log buffer so we only + // track the run that can potentially fail: + log.clearLogBuffer(); count++; // Original suspendthrd001 test block starts here: diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS201/hs201t002.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS201/hs201t002.java index e8a874f4c2758a4b1fbb2d2e0f059eb78f0c0457..c76a9b005d100efd194d306445910772db781dc9 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS201/hs201t002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS201/hs201t002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 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 @@ -24,6 +24,7 @@ package nsk.jvmti.scenarios.hotswap.HS201; import java.io.PrintStream; +import java.util.concurrent.CountDownLatch; import nsk.share.*; import nsk.share.jvmti.*; @@ -73,14 +74,23 @@ public class hs201t002 extends DebugeeClass { timeout = argHandler.getWaitTime() * 60 * 1000; // milliseconds log.display(">>> starting tested thread"); - Thread thread = new hs201t002Thread(); + hs201t002Thread thread = new hs201t002Thread(); // testing sync status = checkStatus(status); - setThread(thread); thread.start(); + // setThread(thread) enables JVMTI events, and that can only be done on a live thread, + // so wait until the thread has started. + try { + thread.ready.await(); + } catch (InterruptedException e) { + } + setThread(thread); + + thread.go.countDown(); + while (currentStep != 4) { try { Thread.sleep(100); @@ -114,6 +124,10 @@ public class hs201t002 extends DebugeeClass { } log.display("Thread suspended in a wrong moment. Retrying..."); + for (int i = 0; i < stackTrace.length; i++) { + log.display("\t" + i + ". " + stackTrace[i]); + } + log.display("Retrying..."); resumeThread(thread); suspendTry++; // Test thread will be suspended at the top of the loop. Let it run for a while. @@ -136,12 +150,20 @@ public class hs201t002 extends DebugeeClass { class hs201t002Thread extends Thread { + CountDownLatch ready = new CountDownLatch(1); + CountDownLatch go = new CountDownLatch(1); + hs201t002Thread() { setName("hs201t002Thread"); } public void run() { // run method + ready.countDown(); + try { + go.await(); + } catch (InterruptedException e) { + } try { throwException(); } catch (Exception e) { diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS201/hs201t002/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS201/hs201t002/TestDescription.java index e716d1b836c7648ce9151f6e3c6d3d162889c31f..07f9d2a6e9220343d382c88b4b4c3b30e19f9207 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS201/hs201t002/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS201/hs201t002/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -71,7 +71,7 @@ * newclass * * @run main/othervm/native - * -agentlib:hs201t002=pathToNewByteCode=./bin,-waittime=5 - * nsk.jvmti.scenarios.hotswap.HS201.hs201t002 + * -agentlib:hs201t002=pathToNewByteCode=./bin,-waittime=5,-verbose + * nsk.jvmti.scenarios.hotswap.HS201.hs201t002 -verbose */ diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS201/hs201t002/hs201t002.cpp b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS201/hs201t002/hs201t002.cpp index 29a8b7bbfa94e3994ee01257eaf9d42c77abf63d..8ceda496605aecc6dd43b7dc4e52482e9941631b 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS201/hs201t002/hs201t002.cpp +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS201/hs201t002/hs201t002.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 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 @@ -45,16 +45,18 @@ static jlong timeout = 0; #define PATH_TO_NEW_BYTECODE "pathToNewByteCode" static jint testStep; -static int redefineNumber; -static jint newClassSize; -static unsigned char* newClassBytes; static jthread testedThread; static jclass testClass; -char chbuffer[255]; -const char* getThreadName(JNIEnv* jni_env, jthread thread); +// callbackException (isCatch == false) and callbackExceptionCatch (isCatch == true) handler +void handleException(bool isCatch, + jvmtiEnv* jvmti_env, JNIEnv* jni_env, jthread thread, + jmethodID method, jlocation location, + jobject exception); + +const char* getThreadName(jvmtiEnv* jvmti_env, JNIEnv* jni_env, jthread thread); const char* getClassName(jvmtiEnv *jvmti_env, JNIEnv* jni_env, jobject object); -int readNewBytecode(jvmtiEnv* jvmti); +int readNewBytecode(jvmtiEnv* jvmti, jint *newClassSize, unsigned char* *newClassBytes); int getLocalVariableValue(jvmtiEnv *jvmti_env, jthread thread, jmethodID method); /* ============================================================================= */ @@ -99,17 +101,19 @@ void disableEvent(jvmtiEnv *jvmti_env, jvmtiEvent event, jthread thread) { void redefineClass(jvmtiEnv *jvmti_env, jclass klass) { jvmtiClassDefinition classDef; - char *className; + jint newClassSize; + unsigned char* newClassBytes; if (!NSK_JVMTI_VERIFY(jvmti_env->GetClassSignature(klass, &className, NULL))) { nsk_jvmti_setFailStatus(); return; } - if (!NSK_VERIFY(readNewBytecode(jvmti_env))) { + if (!NSK_VERIFY(readNewBytecode(jvmti_env, &newClassSize, &newClassBytes))) { NSK_COMPLAIN0("TEST FAILED: new bytecode could not be read\n"); nsk_jvmti_setFailStatus(); + jvmti_env->Deallocate((unsigned char*)className); return; } @@ -121,12 +125,14 @@ void redefineClass(jvmtiEnv *jvmti_env, jclass klass) { if (!NSK_JVMTI_VERIFY(jvmti_env->RedefineClasses(1, &classDef))) { NSK_COMPLAIN1("TEST FAILED: while redefining class %s\n", className); nsk_jvmti_setFailStatus(); - return; } if (!NSK_JVMTI_VERIFY(jvmti_env->Deallocate((unsigned char*)className))) { nsk_jvmti_setFailStatus(); } + if (!NSK_JVMTI_VERIFY(jvmti_env->Deallocate(newClassBytes))) { + nsk_jvmti_setFailStatus(); + } } @@ -136,7 +142,6 @@ void redefineClass(jvmtiEnv *jvmti_env, jclass klass) { static void JNICALL agentProc(jvmtiEnv* jvmti, JNIEnv* agentJNI, void* arg) { - redefineNumber = 1; jni = agentJNI; NSK_DISPLAY0("Waiting for debuggee to become ready\n"); @@ -144,7 +149,7 @@ agentProc(jvmtiEnv* jvmti, JNIEnv* agentJNI, void* arg) { return; testStep = 1; - NSK_DISPLAY0("\n\n>>>> Debugge started, waiting for class loading \n"); + NSK_DISPLAY0(">>>> Debugge started, waiting for class loading \n"); if (!nsk_jvmti_resumeSync()) return; @@ -183,27 +188,20 @@ callbackClassLoad(jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thread, jclass klass) { char *className; - char *generic; - if (!NSK_JVMTI_VERIFY(jvmti_env->GetClassSignature(klass, &className, &generic))) { + if (!NSK_JVMTI_VERIFY(jvmti_env->GetClassSignature(klass, &className, NULL))) { nsk_jvmti_setFailStatus(); return; } if (strcmp(className, EXPECTED_CLASS_SIGN) == 0) { - NSK_DISPLAY1("\n\n>>>> Class loaded: %s", className); - NSK_DISPLAY0(", activating breakpoint\n"); + NSK_DISPLAY1(">>>> Class loaded: %s, activating breakpoint\n", className); setBreakPoint(jvmti_env, jni_env, klass); } if (!NSK_JVMTI_VERIFY(jvmti_env->Deallocate((unsigned char*)className))) { nsk_jvmti_setFailStatus(); } - - if (generic != NULL) - if (!NSK_JVMTI_VERIFY(jvmti_env->Deallocate((unsigned char*)generic))) { - nsk_jvmti_setFailStatus(); - } } /* ============================================================================= */ @@ -216,7 +214,7 @@ JNIEXPORT void JNICALL callbackBreakpoint(jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thread, jmethodID method, jlocation location) { - NSK_DISPLAY0("\n\n>>>>Breakpoint fired, enabling SINGLE_STEP\n"); + NSK_DISPLAY0(">>>>Breakpoint fired, enabling SINGLE_STEP\n"); enableEvent(jvmti_env, JVMTI_EVENT_SINGLE_STEP, thread); } @@ -266,7 +264,7 @@ callbackSingleStep(jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thread, case 2: - NSK_DISPLAY1("\n\n>>>> Checking if redefined method is not obsolete\n", testStep); + NSK_DISPLAY1(">>>> Checking if redefined method is not obsolete\n", testStep); if (!NSK_JVMTI_VERIFY(jvmti->IsMethodObsolete(method, &is_obsolete))) { NSK_COMPLAIN0("TEST FAILED: unable to check method to be obsolete\n"); @@ -283,7 +281,7 @@ callbackSingleStep(jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thread, case 3: - NSK_DISPLAY1("\n\n>>>> Popping the currently executing frame\n", testStep); + NSK_DISPLAY1(">>>> Popping the currently executing frame\n", testStep); testStep++; setCurrentStep(jni_env, testStep); @@ -292,7 +290,7 @@ callbackSingleStep(jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thread, case 5: if (value < 10) { - NSK_DISPLAY1("\n\n>>>> Disabling single step\n", testStep); + NSK_DISPLAY1(">>>> Disabling single step\n", testStep); disableEvent(jvmti_env, JVMTI_EVENT_SINGLE_STEP, thread); setCurrentStep(jni_env, testStep); } @@ -302,7 +300,7 @@ callbackSingleStep(jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thread, } if (!NSK_JVMTI_VERIFY(jvmti_env->Deallocate((unsigned char*) declaringClassName))) { - NSK_COMPLAIN0("TEST FAILED: unable to deallocate memory pointed to method name\n\n"); + NSK_COMPLAIN0("TEST FAILED: unable to deallocate memory pointed to declaringClassName\n\n"); } } @@ -324,24 +322,7 @@ callbackException(jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thread, jmethodID method, jlocation location, jobject exception, jmethodID catch_method, jlocation catch_location) { - const char *className; - - className = getClassName(jvmti_env, jni_env, exception); - - if (strcmp(EXPECTED_CLASS_SIGN, className) == 0) { - jclass klass; - - NSK_DISPLAY2("\n\n>>>> Exception %s in thread - %s\n", - className, getThreadName(jni_env, thread)); - - testStep++; - if (!NSK_JNI_VERIFY(jni_env, (klass = jni_env->GetObjectClass(exception)) != NULL)) { - nsk_jvmti_setFailStatus(); - return; - } - - redefineClass(jvmti_env, klass); - } + handleException(false, jvmti_env, jni_env, thread, method, location, exception); } /* ============================================================================= */ @@ -355,15 +336,27 @@ callbackExceptionCatch(jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thread, jmethodID method, jlocation location, jobject exception) { - const char *className; + handleException(true, jvmti_env, jni_env, thread, method, location, exception); +} + +/* ============================================================================= */ - className = getClassName(jvmti_env, jni_env, exception); +void handleException(bool isCatch, + jvmtiEnv* jvmti_env, JNIEnv* jni_env, jthread thread, + jmethodID method, jlocation location, + jobject exception) { + const char* className = getClassName(jvmti_env, jni_env, exception); - if (strcmp(EXPECTED_CLASS_SIGN, className) == 0) { + if (className != NULL && strcmp(EXPECTED_CLASS_SIGN, className) == 0) { jclass klass; - NSK_DISPLAY2("\n\n>>>> Caught exception %s in thread - %s\n", - className, getThreadName(jni_env, thread)); + const char* threadName = getThreadName(jvmti_env, jni_env, thread); + NSK_DISPLAY3(">>>> %s %s in thread - %s\n", isCatch ? "Caught exception" : "Exception", + className, threadName != NULL ? threadName : "NULL"); + jvmti->Deallocate((unsigned char*)className); + if (threadName != NULL) { + jvmti->Deallocate((unsigned char*)threadName); + } testStep++; if (!NSK_JNI_VERIFY(jni_env, (klass = jni_env->GetObjectClass(exception)) != NULL)) { @@ -373,11 +366,11 @@ callbackExceptionCatch(jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thread, redefineClass(jvmti_env, klass); } + } -/* ============================================================================= */ -int readNewBytecode(jvmtiEnv* jvmti) { +int readNewBytecode(jvmtiEnv* jvmti, jint *newClassSize, unsigned char* *newClassBytes) { char filename[256]; FILE *bytecode; @@ -403,17 +396,19 @@ int readNewBytecode(jvmtiEnv* jvmti) { } fseek(bytecode, 0, SEEK_END); - newClassSize = ftell(bytecode); + *newClassSize = ftell(bytecode); rewind(bytecode); - if (!NSK_JVMTI_VERIFY(jvmti->Allocate(newClassSize, &newClassBytes))) { + if (!NSK_JVMTI_VERIFY(jvmti->Allocate(*newClassSize, newClassBytes))) { NSK_COMPLAIN0("buffer couldn't be allocated\n"); return NSK_FALSE; } - read_bytes = (jint) fread(newClassBytes, 1, newClassSize, bytecode); + read_bytes = (jint) fread(*newClassBytes, 1, *newClassSize, bytecode); fclose(bytecode); - if (read_bytes != newClassSize) { + if (read_bytes != *newClassSize) { NSK_COMPLAIN0("TEST FAILED: error reading file\n"); + jvmti->Deallocate(*newClassBytes); + *newClassBytes = NULL; return NSK_FALSE; } @@ -422,34 +417,41 @@ int readNewBytecode(jvmtiEnv* jvmti) { /* ============================================================================= */ -const char* getThreadName(JNIEnv* jni_env, jthread thread) { +const char* getThreadName(jvmtiEnv* jvmti_env, JNIEnv* jni_env, jthread thread) { jmethodID methodID; jclass klass; jstring jthreadName; + jsize jthreadNameLen; + unsigned char *result = NULL; const char *threadName; - strcpy(chbuffer, ""); - if (!NSK_JNI_VERIFY(jni_env, (klass = jni_env->GetObjectClass(thread)) != NULL)) { nsk_jvmti_setFailStatus(); - return chbuffer; + return NULL; } if (!NSK_JNI_VERIFY(jni_env, (methodID = jni_env->GetMethodID(klass, "getName", "()Ljava/lang/String;")) != NULL)) { nsk_jvmti_setFailStatus(); - return chbuffer; + return NULL; } jthreadName = (jstring) jni_env->CallObjectMethod(thread, methodID); + jthreadNameLen = jni_env->GetStringUTFLength(jthreadName); + + if (!NSK_JVMTI_VERIFY(jvmti_env->Allocate(jthreadNameLen + 1, &result))) { + NSK_COMPLAIN0("buffer couldn't be allocated\n"); + return NULL; + } + threadName = jni_env->GetStringUTFChars(jthreadName, 0); - strcpy(chbuffer, threadName); + memcpy(result, threadName, jthreadNameLen + 1); jni_env->ReleaseStringUTFChars(jthreadName, threadName); - return chbuffer; + return (char*)result; } /* ============================================================================= */ @@ -457,33 +459,19 @@ const char* getThreadName(JNIEnv* jni_env, jthread thread) { const char* getClassName(jvmtiEnv *jvmti_env, JNIEnv* jni_env, jobject object) { char *className; - char *generic; jclass klass; - strcpy(chbuffer, ""); - if (!NSK_JNI_VERIFY(jni_env, (klass = jni_env->GetObjectClass(object)) != NULL)) { nsk_jvmti_setFailStatus(); - return chbuffer; - } - - if (!NSK_JVMTI_VERIFY(jvmti_env->GetClassSignature(klass, &className, &generic))) { - nsk_jvmti_setFailStatus(); - return chbuffer; + return NULL; } - strcpy(chbuffer, className); - - if (!NSK_JVMTI_VERIFY(jvmti_env->Deallocate((unsigned char*)className))) { + if (!NSK_JVMTI_VERIFY(jvmti_env->GetClassSignature(klass, &className, NULL))) { nsk_jvmti_setFailStatus(); + return NULL; } - if (generic != NULL) - if (!NSK_JVMTI_VERIFY(jvmti_env->Deallocate((unsigned char*)generic))) { - nsk_jvmti_setFailStatus(); - } - - return chbuffer; + return className; } /* ============================================================================= */ @@ -546,6 +534,10 @@ Java_nsk_jvmti_scenarios_hotswap_HS201_hs201t002_setThread(JNIEnv *env, if (!NSK_JNI_VERIFY(env, (testedThread = env->NewGlobalRef(thread)) != NULL)) nsk_jvmti_setFailStatus(); + enableEvent(jvmti, JVMTI_EVENT_CLASS_LOAD, testedThread); + enableEvent(jvmti, JVMTI_EVENT_BREAKPOINT, testedThread); + enableEvent(jvmti, JVMTI_EVENT_EXCEPTION, testedThread); + enableEvent(jvmti, JVMTI_EVENT_EXCEPTION_CATCH, testedThread); } /* ============================================================================= */ @@ -665,11 +657,6 @@ jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) { NSK_DISPLAY0("Enable events\n"); - enableEvent(jvmti, JVMTI_EVENT_CLASS_LOAD, testedThread); - enableEvent(jvmti, JVMTI_EVENT_BREAKPOINT, testedThread); - enableEvent(jvmti, JVMTI_EVENT_EXCEPTION, testedThread); - enableEvent(jvmti, JVMTI_EVENT_EXCEPTION_CATCH, testedThread); - if (!NSK_VERIFY(nsk_jvmti_setAgentProc(agentProc, NULL))) return JNI_ERR; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS201/hs201t002/newclass/hs201t002a.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS201/hs201t002/newclass/hs201t002a.java index 3d5a7b946949dc646080a700b4e78dcca53a4128..f5d3d83e9c7aa1580345fbdebd122a083f26fa1f 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS201/hs201t002/newclass/hs201t002a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS201/hs201t002/newclass/hs201t002a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 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 @@ -26,6 +26,7 @@ package nsk.jvmti.scenarios.hotswap.HS201; public class hs201t002a extends Exception { public hs201t002a () { + System.out.println("Current step: " + hs201t002.currentStep); // Avoid calling classloader to find hs201t002 in doInit() doInit(); } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS203/hs203t002/hs203t002.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS203/hs203t002/hs203t002.java index f872a6dcba3f42ad329d441d988004abe341c944..d9dd4a88c80ff0e543e21c658a8b8df446b74bb3 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS203/hs203t002/hs203t002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS203/hs203t002/hs203t002.java @@ -79,7 +79,7 @@ public class hs203t002 extends RedefineAgent { Thread.sleep(10000); popThreadFrame(mt); resumeThread(mt); - while(!MyThread.resume2.get());; + while(!MyThread.resume2.get()); Thread.sleep(10000); suspendThread(mt); //mt.suspend(); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/ClassFileFinder.java b/test/hotspot/jtreg/vmTestbase/nsk/share/ClassFileFinder.java index 3024ae1d7a5325779e46b05c25ed6deba6faa177..e79430044ca860fdc4222d02458748aa7e80e450 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/share/ClassFileFinder.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/ClassFileFinder.java @@ -36,7 +36,7 @@ public class ClassFileFinder { * classpath. * * @param name a classname - * @param classPath @{link File.pathSeparator} separated directories + * @param classPath {@link File.pathSeparator} separated directories * @return an absolute path to the found classfile, or null if it cannot be * found */ diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/Log.java b/test/hotspot/jtreg/vmTestbase/nsk/share/Log.java index 109c3ddd8f7074a8fe6c7173cb8d5146420398db..e171f6daa82e93d873a64157ac2df561e3d84033 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/share/Log.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/Log.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -477,6 +477,13 @@ public class Log extends FinalizableObject { ///////////////////////////////////////////////////////////////// + /** + * Clear all messages from log buffer. + */ + public synchronized void clearLogBuffer() { + logBuffer.clear(); + } + /** * Print all messages from log buffer which were hidden because * of non-verbose mode, diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/jdb/Launcher.java b/test/hotspot/jtreg/vmTestbase/nsk/share/jdb/Launcher.java index d7aa6c30219aebfa31bd384d0ee300fdc73010a3..a78dabdbe25c5be7a30cc14b3ed83a026a636976 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/share/jdb/Launcher.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdb/Launcher.java @@ -184,7 +184,7 @@ public class Launcher extends DebugeeBinder { connect.append(argumentHandler.getConnectorName() + ":"); String connectorAddress; - String vmAddress = makeTransportAddress();; + String vmAddress = makeTransportAddress(); if (argumentHandler.isRawLaunchingConnector()) { diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/jvmti/agent_tools.cpp b/test/hotspot/jtreg/vmTestbase/nsk/share/jvmti/agent_tools.cpp index 660e2fc54e51bd8188077a4828e9c2bc2cb43d9e..2412bd630401ad267c298eb87f292a52c4d26632 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/share/jvmti/agent_tools.cpp +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jvmti/agent_tools.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -138,34 +138,25 @@ jvmtiEnv* nsk_jvmti_getAgentJVMTIEnv() { return jvmti_env; } -/* ============================================================================= */ -static void set_agent_thread_state(thread_state_t value) { - rawMonitorEnter(jvmti_env, agent_data.monitor); - agent_data.thread_state = value; - rawMonitorNotify(jvmti_env, agent_data.monitor); - rawMonitorExit(jvmti_env, agent_data.monitor); -} - /** Wrapper for user agent thread. */ static void JNICALL agentThreadWrapper(jvmtiEnv* jvmti_env, JNIEnv* agentJNI, void* arg) { jni_env = agentJNI; - /* run user agent proc */ - { - set_agent_thread_state(RUNNABLE); + rawMonitorEnter(jvmti_env, agent_data.monitor); + agent_data.thread_state = RUNNABLE; + rawMonitorNotify(jvmti_env, agent_data.monitor); + rawMonitorExit(jvmti_env, agent_data.monitor); - NSK_TRACE((*agentThreadProc)(jvmti_env, agentJNI, agentThreadArg)); + NSK_TRACE((*agentThreadProc)(jvmti_env, agentJNI, agentThreadArg)); - set_agent_thread_state(TERMINATED); - } + rawMonitorEnter(jvmti_env, agent_data.monitor); + agent_data.thread_state = TERMINATED; + agentJNI->DeleteGlobalRef(agentThread); + agentThread = NULL; + rawMonitorNotify(jvmti_env, agent_data.monitor); + rawMonitorExit(jvmti_env, agent_data.monitor); - /* finalize agent thread */ - { - /* gelete global ref for agent thread */ - agentJNI->DeleteGlobalRef(agentThread); - agentThread = NULL; - } } /** Start wrapper for user agent thread. */ diff --git a/test/hotspot/jtreg/vmTestbase/nsk/stress/stack/stack018.java b/test/hotspot/jtreg/vmTestbase/nsk/stress/stack/stack018.java index 48fe41a67faa5b6efc6b702e1e94e9ca9d99258f..b60309cc98f94e44dd88e98ba617399c381c5fc2 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/stress/stack/stack018.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/stress/stack/stack018.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -36,7 +36,7 @@ * invocations until stack overflow, and then tries to reproduce similar * stack overflows 10 times in each of 10 threads -- each time by trying * to invoke the same recursive method for the given fixed depth - * of invocations (which is 10 times that crucial depth just measured). + * of invocations (which is 100 times that crucial depth just measured). * The test is deemed passed, if VM have not crashed, and * if exception other than due to stack overflow was not * thrown. @@ -103,7 +103,7 @@ public class stack018 extends Thread { // Measure maximal recursion depth until stack overflow: // int maxDepth = 0; - for (depthToTry = 0; ; depthToTry += STEP) + for (depthToTry = 0; ; depthToTry += STEP) { try { invokeRecurse(depthToTry); maxDepth = depthToTry; @@ -117,6 +117,12 @@ public class stack018 extends Thread { throw (ThreadDeath) target; return 2; } + } + + if (maxDepth == 0) { + // The depth STEP was enough to cause StackOverflowError or OutOfMemoryError. + maxDepth = STEP; + } out.println("Maximal recursion depth: " + maxDepth); // diff --git a/test/hotspot/jtreg/vmTestbase/nsk/sysdict/share/GenClassesBuilder.java b/test/hotspot/jtreg/vmTestbase/nsk/sysdict/share/GenClassesBuilder.java index e48ff567aacf37e0427f909fac824d54b06a0535..6f3a2084083c66ccdde5a7501695194a5378f17a 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/sysdict/share/GenClassesBuilder.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/sysdict/share/GenClassesBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -71,6 +71,7 @@ public class GenClassesBuilder { moveJavaFiles(genSrcDir, prefix); JDKToolLauncher javac = JDKToolLauncher.create("javac") + .addToolArg("-J-Xmx1G") .addToolArg("-d") .addToolArg(classesDir.toString()) .addToolArg("-cp") diff --git a/test/hotspot/jtreg/vmTestbase/nsk/sysdict/share/SysDictTest.java b/test/hotspot/jtreg/vmTestbase/nsk/sysdict/share/SysDictTest.java index 043cbf8b80e9f8f7513d15ae31ee799d7c516c75..2b217a368c2524bcaa8cd79b954a4bf7a11f0081 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/sysdict/share/SysDictTest.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/sysdict/share/SysDictTest.java @@ -148,8 +148,8 @@ public abstract class SysDictTest extends ThreadedGCTest { // set name into public variable just to be sure // that class is loaded tmp = clz.getName(); - } catch (OutOfMemoryError | ClassNotFoundException e) { - // just ignore + } catch (OutOfMemoryError | ClassNotFoundException | NoClassDefFoundError e) { + // just ignore, note that CNFE and NCDFE can be caused by OOM exceptions. } catch (StackOverflowError soe) { // just ignore, chains could be too large // StackOverflowError could be in some sparcs diff --git a/test/hotspot/jtreg/vmTestbase/vm/mlvm/hiddenloader/stress/oome/heap/Test.java b/test/hotspot/jtreg/vmTestbase/vm/mlvm/hiddenloader/stress/oome/heap/Test.java index 9d0a25b00e433ea73fed914349a7884adfd547a6..ea59685dfd3df71a60874bfd24b03a0c3ff868f7 100644 --- a/test/hotspot/jtreg/vmTestbase/vm/mlvm/hiddenloader/stress/oome/heap/Test.java +++ b/test/hotspot/jtreg/vmTestbase/vm/mlvm/hiddenloader/stress/oome/heap/Test.java @@ -63,7 +63,7 @@ public class Test extends MlvmOOMTest { @Override protected void checkOOME(OutOfMemoryError oome) { String message = oome.getMessage(); - if (!"Java heap space".equals(message)) { + if (!message.startsWith("Java heap space")) { throw new RuntimeException("TEST FAIL : wrong OOME", oome); } } diff --git a/test/jaxp/javax/xml/jaxp/unittest/xpath/XPathFactoryDummyImpl.java b/test/jaxp/javax/xml/jaxp/unittest/xpath/XPathFactoryDummyImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..8eb75c225cdb248d370e35db726d9c1c2fc430d9 --- /dev/null +++ b/test/jaxp/javax/xml/jaxp/unittest/xpath/XPathFactoryDummyImpl.java @@ -0,0 +1,74 @@ +/* + * 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. + */ +package xpath; + +import javax.xml.xpath.XPath; +import javax.xml.xpath.XPathFactory; +import javax.xml.xpath.XPathFactoryConfigurationException; +import javax.xml.xpath.XPathFunctionResolver; +import javax.xml.xpath.XPathVariableResolver; + +/** + * A dummy implementation of the XPathFactory without implementing + * the setProperty/getProperty methods + */ +public class XPathFactoryDummyImpl extends XPathFactory { + + @Override + public boolean isObjectModelSupported(String objectModel) { + // support the default object model, W3C DOM + if (objectModel.equals(XPathFactory.DEFAULT_OBJECT_MODEL_URI)) { + return true; + } + + // no support + return false; + } + + + @Override + public void setFeature(String name, boolean value) throws XPathFactoryConfigurationException { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean getFeature(String name) throws XPathFactoryConfigurationException { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setXPathVariableResolver(XPathVariableResolver resolver) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setXPathFunctionResolver(XPathFunctionResolver resolver) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public XPath newXPath() { + throw new UnsupportedOperationException("Not supported yet."); + } + +} diff --git a/test/jaxp/javax/xml/jaxp/unittest/xpath/XPathTest.java b/test/jaxp/javax/xml/jaxp/unittest/xpath/XPathTest.java index 7f5c45dc12b96327b2316383453c00a3251a1208..82c4cc5b1f3a6ec918d2d0632c67690ac4a0ed72 100644 --- a/test/jaxp/javax/xml/jaxp/unittest/xpath/XPathTest.java +++ b/test/jaxp/javax/xml/jaxp/unittest/xpath/XPathTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -30,22 +30,77 @@ import javax.xml.xpath.XPath; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathFactory; +import org.testng.Assert; import org.testng.annotations.DataProvider; -import org.testng.annotations.Listeners; import org.testng.annotations.Test; import org.w3c.dom.Document; import org.w3c.dom.Node; /* * @test - * @bug 6376058 - * @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest - * @run testng/othervm -DrunSecMngr=true -Djava.security.manager=allow xpath.XPathTest + * @bug 6376058 8276141 + * @build xpath.XPathTest xpath.XPathFactoryDummyImpl * @run testng/othervm xpath.XPathTest * @summary Test XPath functions. See details for each test. */ -@Listeners({jaxp.library.BasePolicy.class}) public class XPathTest { + /* + * DataProvider for testXPathFactory + */ + @DataProvider(name = "xpath") + public Object[][] getXPathFactory() throws Exception { + return new Object[][]{ + {null}, + {"xpath.XPathFactoryDummyImpl"}, + }; + } + + /* + * @bug 8276141 + * Tests the setProperty/getProperty method for the XPathFactory. + */ + @Test(dataProvider = "xpath") + public void testXPathFactory(String factoryName) + throws Exception { + + XPathFactory xpf; + if (factoryName == null) { + xpf = XPathFactory.newInstance(); + } else { + xpf = XPathFactory.newInstance( + XPathFactory.DEFAULT_OBJECT_MODEL_URI, factoryName, null); + } + + // NPE + Assert.assertThrows(NullPointerException.class, + () -> setProperty(xpf, null, "value")); + Assert.assertThrows(NullPointerException.class, + () -> getProperty(xpf, null)); + + if (factoryName == null) { + // default factory impl + Assert.assertThrows(IllegalArgumentException.class, + () -> setProperty(xpf, "unknown", "value")); + Assert.assertThrows(IllegalArgumentException.class, + () -> getProperty(xpf, "unknown")); + } else { + // the DummyImpl does not implement the method + Assert.assertThrows(UnsupportedOperationException.class, + () -> setProperty(xpf, "unknown", "value")); + Assert.assertThrows(UnsupportedOperationException.class, + () -> getProperty(xpf, "unknown")); + } + } + + private void setProperty(XPathFactory xpf, String name, String value) + throws Exception { + xpf.setProperty(name, value); + } + + private void getProperty(XPathFactory xpf, String name) + throws Exception { + xpf.getProperty(name); + } /* @bug 6211561 diff --git a/test/jdk/ProblemList-Xcomp.txt b/test/jdk/ProblemList-Xcomp.txt index 77b61348af5b7161588fafbaeaa270627021a36a..31edd809cccb4df4355ea4a8be7ad8852f84eab3 100644 --- a/test/jdk/ProblemList-Xcomp.txt +++ b/test/jdk/ProblemList-Xcomp.txt @@ -28,4 +28,3 @@ ############################################################################# java/lang/invoke/MethodHandles/CatchExceptionTest.java 8146623 generic-all -java/util/stream/test/org/openjdk/tests/java/util/stream/SpliteratorTest.java 8256368 generic-all diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index ac8c37f502403a6ee8c7e4a834e6eee6c19f5bb3..25858d1cb7150b1d4ca660b475ecc64ef5313353 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -190,7 +190,7 @@ java/awt/Toolkit/RealSync/Test.java 6849383 linux-all java/awt/LightweightComponent/LightweightEventTest/LightweightEventTest.java 8159252 windows-all java/awt/EventDispatchThread/HandleExceptionOnEDT/HandleExceptionOnEDT.java 8072110 macosx-all java/awt/EventDispatchThread/LoopRobustness/LoopRobustness.java 8073636 macosx-all -java/awt/FullScreen/FullScreenInsets/FullScreenInsets.java 7019055,8266245 windows-all,linux-all,macosx-aarch64 +java/awt/FullScreen/FullScreenInsets/FullScreenInsets.java 7019055,8266245 windows-all,linux-all,macosx-all java/awt/Focus/8013611/JDK8013611.java 8175366 windows-all,macosx-all java/awt/Focus/6981400/Test1.java 8029675 windows-all,macosx-all java/awt/Focus/6981400/Test3.java 8173264 generic-all @@ -242,7 +242,6 @@ sun/awt/shell/ShellFolderMemoryLeak.java 8197794 windows-all sun/java2d/DirectX/OnScreenRenderingResizeTest/OnScreenRenderingResizeTest.java 8022403 generic-all sun/java2d/DirectX/OverriddenInsetsTest/OverriddenInsetsTest.java 8196102 generic-all sun/java2d/DirectX/RenderingToCachedGraphicsTest/RenderingToCachedGraphicsTest.java 8196180 windows-all,macosx-all -java/awt/Graphics2D/CopyAreaOOB.java 7001973 windows-all,macosx-all sun/java2d/SunGraphics2D/EmptyClipRenderingTest.java 8144029 macosx-all,linux-all sun/java2d/SunGraphics2D/DrawImageBilinear.java 8191406 generic-all sun/java2d/SunGraphics2D/PolyVertTest.java 6986565 generic-all @@ -489,7 +488,6 @@ java/awt/xembed/server/RunTestXEmbed.java 7034201 linux-all java/awt/Modal/ModalFocusTransferTests/FocusTransferDialogsDocModalTest.java 8164473 linux-all java/awt/im/memoryleak/InputContextMemoryLeakTest.java 8023814 linux-all java/awt/Frame/DisposeParentGC/DisposeParentGC.java 8079786 macosx-all -java/awt/FullScreen/NoResizeEventOnDMChangeTest/NoResizeEventOnDMChangeTest.java 8169468 macosx-all java/awt/GraphicsDevice/DisplayModes/CycleDMImage.java 7099223,8274106 macosx-aarch64,linux-all,windows-all java/awt/keyboard/AllKeyCode/AllKeyCode.java 8242930 macosx-all @@ -517,6 +515,8 @@ java/awt/KeyboardFocusmanager/TypeAhead/ButtonActionKeyTest/ButtonActionKeyTest. java/awt/Window/GetScreenLocation/GetScreenLocationTest.java 8225787 linux-x64 java/awt/Dialog/MakeWindowAlwaysOnTop/MakeWindowAlwaysOnTop.java 8266243 macosx-aarch64 +java/awt/dnd/BadSerializationTest/BadSerializationTest.java 8277817 linux-x64,windows-x64 +java/awt/GraphicsDevice/CheckDisplayModes.java 8266242 macosx-aarch64 ############################################################################ @@ -542,6 +542,7 @@ java/lang/invoke/LFCaching/LFMultiThreadCachingTest.java 8151492 generic- java/lang/invoke/LFCaching/LFGarbageCollectedTest.java 8078602 generic-all java/lang/invoke/lambda/LambdaFileEncodingSerialization.java 8249079 linux-x64 java/lang/invoke/RicochetTest.java 8251969 generic-all +java/lang/Enum/ConstantDirectoryOptimalCapacity.java 8282120 generic-all ############################################################################ @@ -597,7 +598,6 @@ java/net/MulticastSocket/SetGetNetworkInterfaceTest.java 8219083 windows- java/net/ServerSocket/AcceptInheritHandle.java 8211854 aix-ppc64 - ############################################################################ # jdk_nio @@ -606,6 +606,8 @@ java/nio/channels/DatagramChannel/Unref.java 8233519 generic- java/nio/channels/AsynchronousSocketChannel/StressLoopback.java 8211851 aix-ppc64 +java/nio/channels/DatagramChannel/ManySourcesAndTargets.java 8264385 macosx-aarch64 + ############################################################################ # jdk_rmi @@ -646,8 +648,6 @@ javax/net/ssl/DTLS/CipherSuite.java 8202059 macosx-x sun/security/provider/KeyStore/DKSTest.sh 8180266 windows-all -sun/security/pkcs11/KeyStore/SecretKeysBasic.java 8209398 generic-all - security/infra/java/security/cert/CertPathValidator/certification/ActalisCA.java 8224768 generic-all sun/security/smartcardio/TestChannel.java 8039280 generic-all @@ -671,6 +671,7 @@ javax/security/auth/kerberos/KerberosTixDateTest.java 8039280 generic- sun/security/provider/PolicyFile/GrantAllPermToExtWhenNoPolicy.java 8039280 generic-all sun/security/provider/PolicyParser/ExtDirsChange.java 8039280 generic-all sun/security/provider/PolicyParser/PrincipalExpansionError.java 8039280 generic-all +sun/security/ssl/SSLSessionImpl/NoInvalidateSocketException.java 8277970 linux-all,macosx-x64 ############################################################################ @@ -729,16 +730,26 @@ javax/swing/JRootPane/4670486/bug4670486.java 8042381 macosx-all javax/swing/JButton/8151303/PressedIconTest.java 8266246 macosx-aarch64 javax/swing/JMenuItem/ActionListenerCalledTwice/ActionListenerCalledTwiceTest.java 8273573 macosx-all -# Several tests which fail on some hidpi systems +# Several tests which fail on some hidpi systems/macosx12-aarch64 system java/awt/Window/8159168/SetShapeTest.java 8274106 macosx-aarch64 java/awt/image/multiresolution/MultiResolutionJOptionPaneIconTest.java 8274106 macosx-aarch64 javax/swing/JFrame/8175301/ScaledFrameBackgroundTest.java 8274106 macosx-aarch64 +javax/swing/text/html/StyleSheet/bug4936917.java 8277816 macosx-aarch64 +javax/swing/plaf/metal/MetalGradient/8163193/ButtonGradientTest.java 8277816 macosx-aarch64 +javax/swing/JInternalFrame/8160248/JInternalFrameDraggingTest.java 8277816 macosx-aarch64 +javax/swing/JInternalFrame/8069348/bug8069348.java 8277816 macosx-aarch64 +java/awt/Robot/HiDPIScreenCapture/ScreenCaptureTest.java 8277816 macosx-aarch64 +java/awt/Robot/CheckCommonColors/CheckCommonColors.java 8277816 macosx-aarch64 +java/awt/ColorClass/AlphaColorTest.java 8277816 macosx-aarch64 +java/awt/AlphaComposite/WindowAlphaCompositeTest.java 8277816 macosx-aarch64 + # macos12 failure javax/swing/JMenu/4515762/bug4515762.java 8276074 macosx-all sanity/client/SwingSet/src/ToolTipDemoTest.java 8225012 windows-all,macosx-all sanity/client/SwingSet/src/ScrollPaneDemoTest.java 8225013 linux-all sanity/client/SwingSet/src/ButtonDemoScreenshotTest.java 8265770 macosx-all +javax/swing/JTree/4908142/bug4908142.java 8278348 macosx-all ############################################################################ @@ -809,12 +820,13 @@ javax/script/Test7.java 8239361 generic- # jdk_jfr -jdk/jfr/event/runtime/TestNetworkUtilizationEvent.java 8228990 generic-all +jdk/jfr/event/runtime/TestNetworkUtilizationEvent.java 8228990 macosx-all,linux-all,windows-all jdk/jfr/event/compiler/TestCodeSweeper.java 8225209 generic-all jdk/jfr/event/os/TestThreadContextSwitches.java 8247776 windows-all jdk/jfr/startupargs/TestStartName.java 8214685 windows-x64 jdk/jfr/startupargs/TestStartDuration.java 8214685 windows-x64 -jdk/jfr/api/consumer/streaming/TestLatestEvent.java 8268297 windows-x64 +jdk/jfr/api/consumer/recordingstream/TestOnEvent.java 8255404 linux-x64 +jdk/jfr/jvm/TestWaste.java 8282427 generic-all ############################################################################ diff --git a/test/jdk/TEST.ROOT b/test/jdk/TEST.ROOT index 03552d41c15eef5725e907fe865c692ab716be5b..608facdf4b787c9dd03fa59e51e5f829041480cd 100644 --- a/test/jdk/TEST.ROOT +++ b/test/jdk/TEST.ROOT @@ -25,9 +25,7 @@ javax/management sun/awt sun/java2d javax/xml/jaxp/testng/validation java/lang/P # Tests that cannot run concurrently exclusiveAccess.dirs=java/math/BigInteger/largeMemory \ java/rmi/Naming java/util/prefs sun/management/jmxremote \ -sun/tools/jstatd sun/tools/jcmd \ -sun/tools/jinfo sun/tools/jmap sun/tools/jps sun/tools/jstack sun/tools/jstat \ -com/sun/tools/attach sun/security/mscapi java/util/Arrays/largeMemory \ +sun/tools/jstatd sun/security/mscapi java/util/Arrays/largeMemory \ java/util/BitSet/stream javax/rmi java/net/httpclient/websocket \ com/sun/net/httpserver/simpleserver diff --git a/test/jdk/TEST.groups b/test/jdk/TEST.groups index 37dafa2e73a27b50b0a57f39510770e7cf398ada..6092f604640b346318f9aeb42706b6c03d9fd7a9 100644 --- a/test/jdk/TEST.groups +++ b/test/jdk/TEST.groups @@ -74,7 +74,9 @@ tier3 = \ :build \ :jdk_vector \ :jdk_rmi \ - :jdk_jfr_tier3 + :jdk_svc \ + -:jdk_svc_sanity \ + -:svc_tools # Everything not in other tiers tier4 = \ @@ -283,9 +285,6 @@ jdk_tools = \ jdk_jfr = \ jdk/jfr -jdk_jfr_tier3 = \ - jdk/jfr/event/metadata/TestLookForUntestedEvents.java - # # Catch-all for other areas with a small number of tests # @@ -386,16 +385,33 @@ jdk_editpad = \ jdk/editpad jdk_desktop = \ - :jdk_awt \ - :jdk_2d \ - :jdk_beans \ + :jdk_desktop_part1 \ + :jdk_desktop_part2 \ + :jdk_desktop_part3 + +jdk_desktop_part1 = \ + :jdk_client_sanity \ :jdk_swing \ + :jdk_2d \ :jdk_sound \ :jdk_imageio \ - :jdk_accessibility \ + :jdk_editpad \ :jfc_demo \ - :jdk_client_sanity \ - :jdk_editpad + :jdk_accessibility \ + :jdk_beans + +jdk_desktop_part2 = \ + :jdk_awt \ + -java/awt/Component \ + -java/awt/Modal \ + -java/awt/datatransfer \ + -java/awt/Window + +jdk_desktop_part3 = \ + java/awt/Component \ + java/awt/Modal \ + java/awt/datatransfer \ + java/awt/Window # SwingSet3 tests. jdk_client_sanity = \ @@ -518,7 +534,23 @@ needs_g1gc = \ jdk/jfr/event/gc/objectcount/TestObjectCountAfterGCEventWithG1FullCollection.java \ jdk/jfr/event/gc/objectcount/TestObjectCountAfterGCEventWithG1ConcurrentMark.java \ jdk/jfr/event/gc/heapsummary/TestHeapSummaryEventG1.java - + +# This set of tests will be executed in an ipv6 only environment + +jdk_ipv6_only = \ + :jdk_net \ + :jdk_nio_networkchannel + +jdk_nio_networkchannel = \ + java/nio/channels/AsyncCloseAndInterrupt.java \ + java/nio/channels/AsynchronousServerSocketChannel \ + java/nio/channels/AsynchronousSocketChannel \ + java/nio/channels/DatagramChannel \ + java/nio/channels/ServerSocketChannel \ + java/nio/channels/SocketChannel \ + java/nio/channels/Selector \ + java/nio/channels/etc + jdk_core_manual = \ :jdk_core_manual_no_input \ :jdk_core_manual_no_input_security \ @@ -567,3 +599,8 @@ jdk_core_manual_requires_human_input = \ java/util/TimeZone/DefaultTimeZoneTest.java +# Test sets for running inside container environment +jdk_containers_extended = \ + :jdk_io \ + :jdk_nio \ + :jdk_svc diff --git a/test/jdk/build/AbsPathsInImage.java b/test/jdk/build/AbsPathsInImage.java index 3fd7dda239aedf4ce986ecbdfb8a6ad252dd8b02..0e4b6d8caff9f48967c7015690ad8f0b4ccf9e67 100644 --- a/test/jdk/build/AbsPathsInImage.java +++ b/test/jdk/build/AbsPathsInImage.java @@ -96,6 +96,13 @@ public class AbsPathsInImage { if (buildOutputRoot == null) { throw new Error("Could not find build output root, test cannot run"); } + // Validate the root paths + if (!Paths.get(buildWorkspaceRoot).isAbsolute()) { + throw new Error("Workspace root is not an absolute path: " + buildWorkspaceRoot); + } + if (!Paths.get(buildOutputRoot).isAbsolute()) { + throw new Error("Output root is not an absolute path: " + buildOutputRoot); + } List<byte[]> searchPatterns = new ArrayList<>(); expandPatterns(searchPatterns, buildWorkspaceRoot); diff --git a/test/jdk/com/sun/crypto/provider/Cipher/AEAD/GCMBufferTest.java b/test/jdk/com/sun/crypto/provider/Cipher/AEAD/GCMBufferTest.java index 2c0dcae280798a532ed42cfd16e57cb3c4980aea..dd414ad06daba3d0cd5692744eac34f3ead8c892 100644 --- a/test/jdk/com/sun/crypto/provider/Cipher/AEAD/GCMBufferTest.java +++ b/test/jdk/com/sun/crypto/provider/Cipher/AEAD/GCMBufferTest.java @@ -258,7 +258,7 @@ public class GCMBufferTest implements Cloneable { // If incrementalSegments is enabled, run through that test only if (incremental) { if (ops.size() < 2) { - throw new Exception("To do incrementalSegments you must" + + throw new Exception("To do incrementalSegments you must " + "have more that 1 dtype in the list"); } sizes = new int[ops.size()]; diff --git a/test/jdk/com/sun/crypto/provider/Cipher/AEAD/GCMShortBuffer.java b/test/jdk/com/sun/crypto/provider/Cipher/AEAD/GCMShortBuffer.java index 3cfaed9bd9d2e24d2dec1f3c7532403e2cf90941..73140c5a6682d947fc03cb923923f38ce9041f31 100644 --- a/test/jdk/com/sun/crypto/provider/Cipher/AEAD/GCMShortBuffer.java +++ b/test/jdk/com/sun/crypto/provider/Cipher/AEAD/GCMShortBuffer.java @@ -57,7 +57,7 @@ public class GCMShortBuffer { int r = c.doFinal(cipherText, 1, len, pt, 0); if (r != pt.length) { System.out.println( - "doFinal() return ( " + r + ") is not the same" + + "doFinal() return ( " + r + ") is not the same " + "as getOutputSize returned" + pt.length); error = true; } diff --git a/test/jdk/com/sun/crypto/provider/KeyAgreement/DHKeyAgreementPadding.java b/test/jdk/com/sun/crypto/provider/KeyAgreement/DHKeyAgreementPadding.java new file mode 100644 index 0000000000000000000000000000000000000000..dc963bf62677bca077a4d518790f83a4a2f05da6 --- /dev/null +++ b/test/jdk/com/sun/crypto/provider/KeyAgreement/DHKeyAgreementPadding.java @@ -0,0 +1,74 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8281628 + * @library /test/lib + * @summary ensure padding bytes are always added when generated secret + * is smaller than buffer size. + */ + +import javax.crypto.KeyAgreement; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.util.Arrays; +import java.util.HexFormat; + +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"); + + // 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); + KeyPair aliceKeyPair = keyPairGen.generateKeyPair(); + KeyPair bobKeyPair = keyPairGen.generateKeyPair(); + + // Different stale data + Arrays.fill(aliceSecret, (byte)'a'); + Arrays.fill(bobSecret, (byte)'b'); + + alice.init(aliceKeyPair.getPrivate()); + alice.doPhase(bobKeyPair.getPublic(), true); + int aliceLen = alice.generateSecret(aliceSecret, 0); + + bob.init(bobKeyPair.getPrivate()); + bob.doPhase(aliceKeyPair.getPublic(), true); + int bobLen = bob.generateSecret(bobSecret, 0); + + if (!Arrays.equals(aliceSecret, 0, aliceLen, bobSecret, 0, bobLen)) { + System.out.println(HexFormat.ofDelimiter(":").formatHex(aliceSecret, 0, aliceLen)); + System.out.println(HexFormat.ofDelimiter(":").formatHex(bobSecret, 0, bobLen)); + throw new RuntimeException("Different secrets observed at runs #" + i); + } + } + } +} diff --git a/test/jdk/com/sun/jdi/ConstantPoolInfo.java b/test/jdk/com/sun/jdi/ConstantPoolInfo.java index 097ab535cf241ad8f52d4d78e1c4bb535cff0ff5..5d5c2a6a5d9b6ebce7635ee781612d4ae594e68d 100644 --- a/test/jdk/com/sun/jdi/ConstantPoolInfo.java +++ b/test/jdk/com/sun/jdi/ConstantPoolInfo.java @@ -241,7 +241,7 @@ public class ConstantPoolInfo extends TestScaffold { if (magic != JAVA_MAGIC) { failure("fatal bad class file format"); } - expectedMinorVersion = in.readShort();; + expectedMinorVersion = in.readShort(); expectedMajorVersion = in.readShort(); expectedCpoolCount = in.readUnsignedShort(); in.close(); diff --git a/test/jdk/com/sun/jdi/GenericsTest.java b/test/jdk/com/sun/jdi/GenericsTest.java index 28a3d69a8d693f8e46df16e36a9ef7bb8e6dc966..f12a5f74322ae4ab0feb5030ae8681e4c0a0c0a6 100644 --- a/test/jdk/com/sun/jdi/GenericsTest.java +++ b/test/jdk/com/sun/jdi/GenericsTest.java @@ -40,7 +40,7 @@ import java.util.*; /********** target program **********/ class GenericsTarg { - static Gen1<String> genField = new Gen1<String>();; + static Gen1<String> genField = new Gen1<String>(); static Sub1 sub1Field = new Sub1(); String[] strArray = null; diff --git a/test/jdk/com/sun/jdi/JdbOptions.java b/test/jdk/com/sun/jdi/JdbOptions.java index a4e3bfd356fbadd2bd8ab25b0194a847a34dafb5..4a6c8550fc6e842943f5536d93204af0c064c019 100644 --- a/test/jdk/com/sun/jdi/JdbOptions.java +++ b/test/jdk/com/sun/jdi/JdbOptions.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -151,6 +151,22 @@ public class JdbOptions { .expectedArg("-XX:StartFlightRecording:dumponexit=true,maxsize=500M") .expectedArg("-XX:FlightRecorderOptions:repository=jfrrep"); + // -R is tested to see if options are passed through. + test("-R-Dprop1=val1", + "-R-Dprop2=val 2", + "-R-Xmixed", + "-R--add-modules", "-Rjdk.attach", + "-R-Xcheck:jni", + "-R--enable-preview", + "-connect", + "com.sun.jdi.CommandLineLaunch:vmexec=java,main=" + targ + " " + outFilename + " prop1 prop2") + .expectedProp("prop1", "val1") + .expectedProp("prop2", "val 2") + .expectedArg("-Xmixed") + .expectedArg("--add-modules=jdk.attach") + .expectedArg("-Xcheck:jni") + .expectedArg("--enable-preview"); + } private static class TestResult { diff --git a/test/jdk/com/sun/jdi/TestScaffold.java b/test/jdk/com/sun/jdi/TestScaffold.java index 18da0b4e9c75d26cb38577285b31eb94f61b0d8a..2d4885c90e7764315e29a8e59030630ef1bde2b9 100644 --- a/test/jdk/com/sun/jdi/TestScaffold.java +++ b/test/jdk/com/sun/jdi/TestScaffold.java @@ -535,16 +535,15 @@ abstract public class TestScaffold extends TargetAdapter { Location loc = ((Locatable)event).location(); ReferenceType rt = loc.declaringType(); String name = rt.name(); - if (name.startsWith("java.") && - !name.startsWith("sun.") && - !name.startsWith("com.")) { + if (name.startsWith("java.") + || name.startsWith("sun.") + || name.startsWith("com.") + || name.startsWith("jdk.")) { if (mainStartClass != null) { redefine(mainStartClass); } } else { - if (!name.startsWith("jdk.")) { - redefine(rt); - } + redefine(rt); } } } diff --git a/test/jdk/com/sun/jndi/ldap/LdapCBPropertiesTest.java b/test/jdk/com/sun/jndi/ldap/LdapCBPropertiesTest.java index 16b4400310a2d213a7433ec8442f214d5447c434..2f2ce50e8d6654d229c0ea56e44f8b31a80a9cc6 100644 --- a/test/jdk/com/sun/jndi/ldap/LdapCBPropertiesTest.java +++ b/test/jdk/com/sun/jndi/ldap/LdapCBPropertiesTest.java @@ -25,6 +25,7 @@ * @test * @bug 8245527 * @library lib/ /test/lib + * @modules java.base/sun.security.util * @run main/othervm LdapCBPropertiesTest true true com.sun.jndi.ldap.tls.cbtype tls-server-end-point * @run main/othervm LdapCBPropertiesTest false false com.sun.jndi.ldap.tls.cbtype tls-server-end-point * @run main/othervm LdapCBPropertiesTest true true com.sun.jndi.ldap.tls.cbtype tls-server-end-point com.sun.jndi.ldap.connect.timeout 2000 @@ -53,6 +54,8 @@ import javax.security.sasl.SaslException; import jdk.test.lib.net.URIBuilder; +import sun.security.util.ChannelBindingException; + public class LdapCBPropertiesTest { /* * Where do we find the keystores? @@ -187,7 +190,8 @@ public class LdapCBPropertiesTest { } } } - if (!shouldPass && ne.getRootCause() == null) { + Throwable rc = ne.getRootCause(); + if (!shouldPass && (rc == null || rc instanceof ChannelBindingException)) { // Expected exception caused by Channel Binding parameter inconsistency return true; } diff --git a/test/jdk/com/sun/jndi/ldap/LdapPoolTimeoutTest.java b/test/jdk/com/sun/jndi/ldap/LdapPoolTimeoutTest.java new file mode 100644 index 0000000000000000000000000000000000000000..7a5df545655b5b06588fd73de7f0238f0597be3b --- /dev/null +++ b/test/jdk/com/sun/jndi/ldap/LdapPoolTimeoutTest.java @@ -0,0 +1,139 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8277795 + * @summary Multi-threaded client timeout tests for ldap pool + * @library /test/lib + * lib/ + * @run testng/othervm LdapPoolTimeoutTest + */ + +import org.testng.Assert; +import org.testng.annotations.Test; + +import java.io.IOException; +import javax.naming.Context; +import javax.naming.NamingException; +import javax.naming.directory.InitialDirContext; +import java.util.ArrayList; +import java.util.Hashtable; +import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.TimeUnit; + +import static jdk.test.lib.Utils.adjustTimeout; +import static org.testng.Assert.assertTrue; +import static org.testng.Assert.expectThrows; + +public class LdapPoolTimeoutTest { + /* + * Practical representation of an infinite timeout. + */ + private static final long INFINITY_MILLIS = adjustTimeout(20_000); + /* + * The acceptable variation in timeout measurements. + */ + private static final long TOLERANCE = adjustTimeout( 3_500); + + private static final long CONNECT_MILLIS = adjustTimeout( 3_000); + private static final long READ_MILLIS = adjustTimeout(10_000); + + static { + // a series of checks to make sure this timeouts configuration is + // consistent and the timeouts do not overlap + + assert (TOLERANCE >= 0); + // context creation + assert (2 * CONNECT_MILLIS + TOLERANCE < READ_MILLIS); + // context creation immediately followed by search + assert (2 * CONNECT_MILLIS + READ_MILLIS + TOLERANCE < INFINITY_MILLIS); + } + + @Test + public void test() throws Exception { + List<Future<?>> futures = new ArrayList<>(); + ExecutorService executorService = Executors.newCachedThreadPool(); + + Hashtable<Object, Object> env = new Hashtable<>(); + env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); + env.put("com.sun.jndi.ldap.read.timeout", String.valueOf(READ_MILLIS)); + env.put("com.sun.jndi.ldap.connect.timeout", String.valueOf(CONNECT_MILLIS)); + env.put("com.sun.jndi.ldap.connect.pool", "true"); + env.put(Context.PROVIDER_URL, "ldap://example.com:1234"); + + try { + futures.add(executorService.submit(() -> { attemptConnect(env); return null; })); + futures.add(executorService.submit(() -> { attemptConnect(env); return null; })); + futures.add(executorService.submit(() -> { attemptConnect(env); return null; })); + futures.add(executorService.submit(() -> { attemptConnect(env); return null; })); + futures.add(executorService.submit(() -> { attemptConnect(env); return null; })); + futures.add(executorService.submit(() -> { attemptConnect(env); return null; })); + futures.add(executorService.submit(() -> { attemptConnect(env); return null; })); + futures.add(executorService.submit(() -> { attemptConnect(env); return null; })); + } finally { + executorService.shutdown(); + } + int failedCount = 0; + for (var f : futures) { + try { + f.get(); + } catch (ExecutionException e) { + failedCount++; + e.getCause().printStackTrace(System.out); + } + } + if (failedCount > 0) + throw new RuntimeException(failedCount + " (sub)tests failed"); + } + + private static void attemptConnect(Hashtable<Object, Object> env) throws Exception { + try { + LdapTimeoutTest.assertCompletion(CONNECT_MILLIS - 1000, + 2 * CONNECT_MILLIS + TOLERANCE, + () -> new InitialDirContext(env)); + } catch (RuntimeException e) { + String msg = e.getCause() == null ? e.getMessage() : e.getCause().getMessage(); + System.err.println("MSG RTE: " + msg); + // assertCompletion may wrap a CommunicationException in an RTE + assertTrue(msg != null && msg.contains("Network is unreachable")); + } catch (NamingException ex) { + String msg = ex.getCause() == null ? ex.getMessage() : ex.getCause().getMessage(); + System.err.println("MSG: " + msg); + assertTrue(msg != null && + (msg.contains("Network is unreachable") + || msg.contains("Timed out waiting for lock") + || msg.contains("Connect timed out") + || msg.contains("Timeout exceeded while waiting for a connection"))); + } catch (Throwable t) { + throw new RuntimeException(t); + } + } + +} + diff --git a/test/jdk/com/sun/net/httpserver/SANTest.java b/test/jdk/com/sun/net/httpserver/SANTest.java new file mode 100644 index 0000000000000000000000000000000000000000..db0fc0542d6f55758a164343a24faa60e18ac569 --- /dev/null +++ b/test/jdk/com/sun/net/httpserver/SANTest.java @@ -0,0 +1,202 @@ +/* + * 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. + */ + +/** + * @test + * @bug 8278312 + * @library /test/lib /test/jdk/java/net/httpclient /test/jdk/java/net/httpclient/http2/server + * @build jdk.test.lib.net.SimpleSSLContext HttpServerAdapters Http2Handler + * jdk.test.lib.net.IPSupport + * Http2TestExchange + * + * @modules java.net.http/jdk.internal.net.http.common + * java.net.http/jdk.internal.net.http.frame + * java.net.http/jdk.internal.net.http.hpack + * java.logging + * java.base/sun.net.www.http + * java.base/sun.net.www + * java.base/sun.net + * + * @run main/othervm SANTest + * @summary Update SimpleSSLContext keystore to use SANs for localhost IP addresses + */ + +import com.sun.net.httpserver.*; + +import java.util.concurrent.*; +import java.io.*; +import java.net.*; +import java.net.http.*; +import java.nio.charset.StandardCharsets; +import javax.net.ssl.*; +import jdk.test.lib.net.SimpleSSLContext; +import jdk.test.lib.net.URIBuilder; +import jdk.test.lib.net.IPSupport; + +/* + * Will fail if the testkeys file belonging to SimpleSSLContext + * does not have SAN entries for 127.0.0.1 or ::1 + */ +public class SANTest implements HttpServerAdapters { + + static SSLContext ctx; + + static HttpServer getHttpsServer(InetSocketAddress addr, Executor exec, SSLContext ctx) throws Exception { + HttpsServer server = HttpsServer.create(addr, 0); + server.setExecutor(exec); + server.setHttpsConfigurator(new HttpsConfigurator (ctx)); + return server; + } + + static final boolean hasIPv4 = IPSupport.hasIPv4(); + static final boolean hasIPv6 = IPSupport.hasIPv6(); + + static HttpTestServer initServer(boolean h2, InetAddress addr, SSLContext ctx, + String sni, ExecutorService e) throws Exception { + HttpTestServer s = null; + InetSocketAddress ia = new InetSocketAddress (addr, 0); + if ((addr instanceof Inet4Address) && !hasIPv4) + return null; + if ((addr instanceof Inet6Address) && !hasIPv6) + return null; + + if (!h2) { + s = HttpTestServer.of(getHttpsServer(ia, e, ctx)); + HttpTestHandler h = new HttpTestEchoHandler(); + s.addHandler(h, "/test1"); + s.start(); + return s; + } else { + s = HttpTestServer.of(new Http2TestServer(addr, sni, true, 0, e, + 10, null, ctx, false)); + HttpTestHandler h = new HttpTestEchoHandler(); + s.addHandler(h, "/test1"); + s.start(); + return s; + } + } + + public static void main (String[] args) throws Exception { + // Http/1.1 servers + HttpTestServer h1s1 = null; + HttpTestServer h1s2 = null; + + // Http/2 servers + HttpTestServer h2s1 = null; + HttpTestServer h2s2 = null; + + ExecutorService executor=null; + try { + System.out.print ("SANTest: "); + ctx = new SimpleSSLContext().get(); + executor = Executors.newCachedThreadPool(); + + InetAddress l1 = InetAddress.getByName("::1"); + InetAddress l2 = InetAddress.getByName("127.0.0.1"); + + h1s1 = initServer(false, l1, ctx, "::1", executor); + h1s2 = initServer(false, l2, ctx, "127.0.0.1", executor); + + h2s1 = initServer(true, l1, ctx, "::1", executor); + h2s2 = initServer(true, l2, ctx, "127.0.0.1", executor); + + test("127.0.0.1", h1s2); + test("::1", h1s1); + testNew("127.0.0.1", h2s2, executor); + testNew("::1", h2s1, executor); + System.out.println ("OK"); + } finally { + if (h1s1 != null) + h1s1.stop(); + if (h1s2 != null) + h1s2.stop(); + if (h2s1 != null) + h2s1.stop(); + if (h2s2 != null) + h2s2.stop(); + if (executor != null) + executor.shutdown (); + } + } + + static void test (String host, HttpTestServer server) throws Exception { + if (server == null) + return; + int port = server.getAddress().getPort(); + String body = "Yellow world"; + URL url = URIBuilder.newBuilder() + .scheme("https") + .host(host) + .port(port) + .path("/test1/foo.txt") + .toURL(); + System.out.println("URL = " + url); + HttpURLConnection urlc = (HttpURLConnection) url.openConnection(Proxy.NO_PROXY); + System.out.println("urlc = " + urlc); + if (urlc instanceof HttpsURLConnection) { + HttpsURLConnection urlcs = (HttpsURLConnection) urlc; + urlcs.setSSLSocketFactory (ctx.getSocketFactory()); + } + + urlc.setRequestMethod("POST"); + urlc.setDoOutput(true); + + OutputStream os = urlc.getOutputStream(); + os.write(body.getBytes(StandardCharsets.ISO_8859_1)); + os.close(); + InputStream is = urlc.getInputStream(); + byte[] vv = is.readAllBytes(); + String ff = new String(vv, StandardCharsets.ISO_8859_1); + System.out.println("resp = " + ff); + if (!ff.equals(body)) + throw new RuntimeException(); + is.close(); + } + + static void testNew (String host, HttpTestServer server, Executor exec) throws Exception { + if (server == null) + return; + int port = server.getAddress().getPort(); + String body = "Red and Yellow world"; + URI uri = URIBuilder.newBuilder() + .scheme("https") + .host(host) + .port(port) + .path("/test1/foo.txt") + .build(); + + HttpClient client = HttpClient.newBuilder() + .sslContext(ctx) + .executor(exec) + .build(); + HttpRequest req = HttpRequest.newBuilder(uri) + .version(HttpClient.Version.HTTP_2) + .POST(HttpRequest.BodyPublishers.ofString(body)) + .build(); + + HttpResponse<String> resp = client.send(req, HttpResponse.BodyHandlers.ofString()); + System.out.println("resp = " + resp.body()); + if (!resp.body().equals(body)) + throw new RuntimeException(); + } +} diff --git a/test/jdk/com/sun/net/httpserver/simpleserver/CommandLineNegativeTest.java b/test/jdk/com/sun/net/httpserver/simpleserver/CommandLineNegativeTest.java index a494d5961a31d10f8238139877bca4a2ca8522e9..3a22d54f36d046c07bea4bcb40b71a9f079f726c 100644 --- a/test/jdk/com/sun/net/httpserver/simpleserver/CommandLineNegativeTest.java +++ b/test/jdk/com/sun/net/httpserver/simpleserver/CommandLineNegativeTest.java @@ -23,7 +23,7 @@ /* * @test - * @summary Negative tests for simpleserver command-line tool + * @summary Negative tests for java -m jdk.httpserver command * @library /test/lib * @modules jdk.httpserver * @run testng/othervm CommandLineNegativeTest diff --git a/test/jdk/com/sun/net/httpserver/simpleserver/CommandLinePortNotSpecifiedTest.java b/test/jdk/com/sun/net/httpserver/simpleserver/CommandLinePortNotSpecifiedTest.java index 9e53d1008e4e34453eb020953c699ca011b2137f..ba414a9d0c1ac6f2fb2a8f9f42099ffeebe5a346 100644 --- a/test/jdk/com/sun/net/httpserver/simpleserver/CommandLinePortNotSpecifiedTest.java +++ b/test/jdk/com/sun/net/httpserver/simpleserver/CommandLinePortNotSpecifiedTest.java @@ -24,7 +24,7 @@ /* * @test * @bug 8276848 - * @summary Tests the command-line tool with port not specified + * @summary Tests the java -m jdk.httpserver command with port not specified * @modules jdk.httpserver * @library /test/lib * @run testng/othervm/manual CommandLinePortNotSpecifiedTest @@ -118,7 +118,8 @@ public class CommandLinePortNotSpecifiedTest { -d, --directory - Directory to serve. Default: current directory. -o, --output - Output format. none|info|verbose. Default: info. -p, --port - Port to listen on. Default: 8000. - -h, -?, --help - Print this help message. + -h, -?, --help - Prints this help message and exits. + -version, --version - Prints version information and exits. To stop the server, press Ctrl + C.""".formatted(LOOPBACK_ADDR); // The stdout/stderr output line to wait for when starting the simpleserver diff --git a/test/jdk/com/sun/net/httpserver/simpleserver/CommandLinePositiveTest.java b/test/jdk/com/sun/net/httpserver/simpleserver/CommandLinePositiveTest.java index c17b9e1b9732dbbad6d177799717ef0bfe733542..fce013460c1880358f46d8543c9b4e99f92b79ee 100644 --- a/test/jdk/com/sun/net/httpserver/simpleserver/CommandLinePositiveTest.java +++ b/test/jdk/com/sun/net/httpserver/simpleserver/CommandLinePositiveTest.java @@ -23,7 +23,7 @@ /* * @test - * @summary Positive tests for simpleserver command-line tool + * @summary Positive tests for java -m jdk.httpserver command * @library /test/lib * @modules jdk.httpserver * @run testng/othervm CommandLinePositiveTest @@ -46,6 +46,7 @@ import static java.lang.System.out; public class CommandLinePositiveTest { + static final String JAVA_VERSION = System.getProperty("java.version"); static final Path JAVA_HOME = Path.of(System.getProperty("java.home")); static final String JAVA = getJava(JAVA_HOME); static final Path CWD = Path.of(".").toAbsolutePath().normalize(); @@ -106,7 +107,8 @@ public class CommandLinePositiveTest { static final String USAGE_TEXT = """ Usage: java -m jdk.httpserver [-b bind address] [-p port] [-d directory] - [-o none|info|verbose] [-h to show options]"""; + [-o none|info|verbose] [-h to show options] + [-version to show version information]"""; static final String OPTIONS_TEXT = """ Options: @@ -115,7 +117,8 @@ public class CommandLinePositiveTest { -d, --directory - Directory to serve. Default: current directory. -o, --output - Output format. none|info|verbose. Default: info. -p, --port - Port to listen on. Default: 8000. - -h, -?, --help - Print this help message. + -h, -?, --help - Prints this help message and exits. + -version, --version - Prints version information and exits. To stop the server, press Ctrl + C.""".formatted(LOOPBACK_ADDR); @Test(dataProvider = "helpOptions") @@ -129,6 +132,18 @@ public class CommandLinePositiveTest { .shouldContain(OPTIONS_TEXT); } + @DataProvider + public Object[][] versionOptions() { return new Object[][] {{"-version"}, {"--version"}}; } + + @Test(dataProvider = "versionOptions") + public void testVersion(String opt) throws Throwable { + out.println("\n--- testVersion, opt=\"%s\" ".formatted(opt)); + simpleserver(WaitForLine.VERSION_STARTUP_LINE, + false, // do not explicitly destroy the process + JAVA, "-m", "jdk.httpserver", opt) + .shouldHaveExitValue(0); + } + @DataProvider public Object[][] bindOptions() { return new Object[][] {{"-b"}, {"--bind-address"}}; } @@ -207,11 +222,13 @@ public class CommandLinePositiveTest { static final String REGULAR_STARTUP_LINE1_STRING = "Serving"; static final String REGULAR_STARTUP_LINE2_STRING = "URL http://"; + static final String VERSION_STARTUP_LINE_STRING = "java " + JAVA_VERSION; // The stdout/stderr output line to wait for when starting the simpleserver enum WaitForLine { REGULAR_STARTUP_LINE (REGULAR_STARTUP_LINE2_STRING) , - HELP_STARTUP_LINE (OPTIONS_TEXT.lines().reduce((first, second) -> second).orElseThrow()); + HELP_STARTUP_LINE (OPTIONS_TEXT.lines().reduce((first, second) -> second).orElseThrow()), + VERSION_STARTUP_LINE (VERSION_STARTUP_LINE_STRING); final String value; WaitForLine(String value) { this.value = value; } diff --git a/test/jdk/com/sun/net/httpserver/simpleserver/CustomFileSystemTest.java b/test/jdk/com/sun/net/httpserver/simpleserver/CustomFileSystemTest.java index 0826ca259ae9e332ea3887d8f95273c5b7196710..d6ec3eb069550e38807831a5d2ec83a332089674 100644 --- a/test/jdk/com/sun/net/httpserver/simpleserver/CustomFileSystemTest.java +++ b/test/jdk/com/sun/net/httpserver/simpleserver/CustomFileSystemTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -74,6 +74,7 @@ import jdk.test.lib.net.URIBuilder; import org.testng.annotations.BeforeTest; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; +import org.testng.SkipException; import static java.net.http.HttpClient.Builder.NO_PROXY; import static java.nio.charset.StandardCharsets.UTF_8; import static java.nio.file.StandardOpenOption.CREATE; @@ -395,7 +396,7 @@ public class CustomFileSystemTest { var root = createDirectoryInCustomFs("testSymlinkGET"); var symlink = root.resolve("symlink"); var target = Files.writeString(root.resolve("target.txt"), "some text", CREATE); - Files.createSymbolicLink(symlink, target); + createSymLink(symlink, target); var server = SimpleFileServer.createFileServer(LOOPBACK_ADDR, root, OutputLevel.VERBOSE); server.start(); @@ -422,7 +423,7 @@ public class CustomFileSystemTest { var symlink = root.resolve("symlink"); var target = Files.createDirectory(root.resolve("target")); Files.writeString(target.resolve("aFile.txt"), "some text", CREATE); - Files.createSymbolicLink(symlink, target); + createSymLink(symlink, target); var server = SimpleFileServer.createFileServer(LOOPBACK_ADDR, root, OutputLevel.VERBOSE); server.start(); @@ -438,6 +439,16 @@ public class CustomFileSystemTest { } } + private void createSymLink(Path symlink, Path target) { + try { + Files.createSymbolicLink(symlink, target); + } catch (UnsupportedOperationException uoe) { + throw new SkipException("sym link creation not supported", uoe); + } catch (IOException ioe) { + throw new SkipException("probably insufficient privileges to create sym links (Windows)", ioe); + } + } + @Test public void testHiddenFileGET() throws Exception { var root = createDirectoryInCustomFs("testHiddenFileGET"); diff --git a/test/jdk/com/sun/net/httpserver/simpleserver/MapToPathTest.java b/test/jdk/com/sun/net/httpserver/simpleserver/MapToPathTest.java index d6e61da4073e283133d14746859560caf29b5afc..aa8f37acc1b45e613d2b2aa07791421c95abb681 100644 --- a/test/jdk/com/sun/net/httpserver/simpleserver/MapToPathTest.java +++ b/test/jdk/com/sun/net/httpserver/simpleserver/MapToPathTest.java @@ -137,19 +137,27 @@ public class MapToPathTest { var res3 = client.send(req3, BodyHandlers.ofString()); assertEquals(res3.statusCode(), 404); // not found - var req4 = HttpRequest.newBuilder(uri(server, "/foo/file:" + TEST_DIR.getParent())).build(); + var req4 = HttpRequest.newBuilder(uri(server, "/foo/bar/baz/c:.//")).build(); var res4 = client.send(req4, BodyHandlers.ofString()); assertEquals(res4.statusCode(), 404); // not found - var req5 = HttpRequest.newBuilder(uri(server, "/foo/bar/\\..\\../")).build(); + var req5 = HttpRequest.newBuilder(uri(server, "/foo/bar/baz/c:..//")).build(); var res5 = client.send(req5, BodyHandlers.ofString()); assertEquals(res5.statusCode(), 404); // not found - var req6 = HttpRequest.newBuilder(uri(server, "/foo")).build(); + var req6 = HttpRequest.newBuilder(uri(server, "/foo/file:" + TEST_DIR.getParent())).build(); var res6 = client.send(req6, BodyHandlers.ofString()); - assertEquals(res6.statusCode(), 301); // redirect - assertEquals(res6.headers().firstValue("content-length").get(), "0"); - assertEquals(res6.headers().firstValue("location").get(), "/foo/"); + assertEquals(res6.statusCode(), 404); // not found + + var req7 = HttpRequest.newBuilder(uri(server, "/foo/bar/\\..\\../")).build(); + var res7 = client.send(req7, BodyHandlers.ofString()); + assertEquals(res7.statusCode(), 404); // not found + + var req8 = HttpRequest.newBuilder(uri(server, "/foo")).build(); + var res8 = client.send(req8, BodyHandlers.ofString()); + assertEquals(res8.statusCode(), 301); // redirect + assertEquals(res8.headers().firstValue("content-length").get(), "0"); + assertEquals(res8.headers().firstValue("location").get(), "/foo/"); } finally { server.stop(0); } @@ -250,6 +258,29 @@ public class MapToPathTest { server.stop(0); } } + { + // Test that a request path segment that is a Windows root drive + // does not circumvent access restrictions. + // + // For example, given the test directory tree: + // + // |-- TEST_DIR + // |-- foo + // |-- bar ----->>> if hidden, itself and any of its subdirectories are not accessible + // |-- baz + // |-- file.txt + // ... + var handler = SimpleFileServer.createFileHandler(TEST_DIR); + var server = HttpServer.create(LOOPBACK_ADDR, 10, "/", handler, OUTPUT_FILTER); + server.start(); + try { + var req1 = HttpRequest.newBuilder(uri(server, "/foo/bar/c:/baz/")).build(); + var res1 = client.send(req1, BodyHandlers.ofString()); + assertEquals(res1.statusCode(), 404); // not found + } finally { + server.stop(0); + } + } } // Tests with a mixture of in-memory and file handlers. diff --git a/test/jdk/com/sun/net/httpserver/simpleserver/SimpleFileServerTest.java b/test/jdk/com/sun/net/httpserver/simpleserver/SimpleFileServerTest.java index 440e106c68276c9392f9822437b8b324cad2b484..b3134640925081351fd9be10a92ce60146cd84a8 100644 --- a/test/jdk/com/sun/net/httpserver/simpleserver/SimpleFileServerTest.java +++ b/test/jdk/com/sun/net/httpserver/simpleserver/SimpleFileServerTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -56,6 +56,7 @@ import org.testng.annotations.AfterTest; import org.testng.annotations.BeforeTest; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; +import org.testng.SkipException; import static java.net.http.HttpClient.Builder.NO_PROXY; import static java.nio.charset.StandardCharsets.UTF_8; import static java.nio.file.StandardOpenOption.CREATE; @@ -387,7 +388,7 @@ public class SimpleFileServerTest { var root = Files.createDirectory(TEST_DIR.resolve("testSymlinkGET")); var symlink = root.resolve("symlink"); var target = Files.writeString(root.resolve("target.txt"), "some text", CREATE); - Files.createSymbolicLink(symlink, target); + createSymLink(symlink, target); var server = SimpleFileServer.createFileServer(LOOPBACK_ADDR, root, OutputLevel.VERBOSE); server.start(); @@ -414,7 +415,7 @@ public class SimpleFileServerTest { var symlink = root.resolve("symlink"); var target = Files.createDirectory(root.resolve("target")); Files.writeString(target.resolve("aFile.txt"), "some text", CREATE); - Files.createSymbolicLink(symlink, target); + createSymLink(symlink, target); var server = SimpleFileServer.createFileServer(LOOPBACK_ADDR, root, OutputLevel.VERBOSE); server.start(); @@ -430,6 +431,16 @@ public class SimpleFileServerTest { } } + private void createSymLink(Path symlink, Path target) { + try { + Files.createSymbolicLink(symlink, target); + } catch (UnsupportedOperationException uoe) { + throw new SkipException("sym link creation not supported", uoe); + } catch (IOException ioe) { + throw new SkipException("probably insufficient privileges to create sym links (Windows)", ioe); + } + } + @Test public void testHiddenFileGET() throws Exception { var root = Files.createDirectory(TEST_DIR.resolve("testHiddenFileGET")); diff --git a/test/jdk/com/sun/net/httpserver/simpleserver/jwebserver/CommandLineNegativeTest.java b/test/jdk/com/sun/net/httpserver/simpleserver/jwebserver/CommandLineNegativeTest.java new file mode 100644 index 0000000000000000000000000000000000000000..77671d1e82df6e7734f567c5f54ebad6b5bbb37a --- /dev/null +++ b/test/jdk/com/sun/net/httpserver/simpleserver/jwebserver/CommandLineNegativeTest.java @@ -0,0 +1,245 @@ +/* + * 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. + */ + +/* + * @test + * @summary Negative tests for the jwebserver command-line tool + * @library /test/lib + * @modules jdk.httpserver + * @run testng/othervm CommandLineNegativeTest + */ + +import java.io.IOException; +import java.net.InetAddress; +import java.nio.file.Files; +import java.nio.file.Path; +import jdk.test.lib.Platform; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.util.FileUtils; +import org.testng.SkipException; +import org.testng.annotations.AfterTest; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import static java.lang.System.out; +import static org.testng.Assert.assertFalse; + +public class CommandLineNegativeTest { + + static final Path JAVA_HOME = Path.of(System.getProperty("java.home")); + static final String JWEBSERVER = getJwebserver(JAVA_HOME); + static final Path CWD = Path.of(".").toAbsolutePath().normalize(); + static final Path TEST_DIR = CWD.resolve("CommandLineNegativeTest"); + static final Path TEST_FILE = TEST_DIR.resolve("file.txt"); + static final String LOOPBACK_ADDR = InetAddress.getLoopbackAddress().getHostAddress(); + + @BeforeTest + public void setup() throws IOException { + if (Files.exists(TEST_DIR)) { + FileUtils.deleteFileTreeWithRetry(TEST_DIR); + } + Files.createDirectories(TEST_DIR); + Files.createFile(TEST_FILE); + } + + @DataProvider + public Object[][] unknownOption() { + return new Object[][] { + {"--unknownOption"}, + {"null"} + }; + } + + @Test(dataProvider = "unknownOption") + public void testBadOption(String opt) throws Throwable { + out.println("\n--- testUnknownOption, opt=\"%s\" ".formatted(opt)); + simpleserver(JWEBSERVER, opt) + .shouldNotHaveExitValue(0) + .shouldContain("Error: unknown option: " + opt); + } + + @DataProvider + public Object[][] tooManyOptionArgs() { + return new Object[][] { + {"-b", "localhost"}, + {"-d", "/some/path"}, + {"-o", "none"}, + {"-p", "0"}, + {"--bind-address", "localhost"}, + {"--directory", "/some/path"}, + {"--output", "none"}, + {"--port", "0"} + // doesn't fail for -h option + }; + } + + @Test(dataProvider = "tooManyOptionArgs") + public void testTooManyOptionArgs(String opt, String arg) throws Throwable { + out.println("\n--- testTooManyOptionArgs, opt=\"%s\" ".formatted(opt)); + simpleserver(JWEBSERVER, opt, arg, arg) + .shouldNotHaveExitValue(0) + .shouldContain("Error: unknown option: " + arg); + } + + @DataProvider + public Object[][] noArg() { + return new Object[][] { + {"-b", """ + -b, --bind-address - Address to bind to. Default: %s (loopback). + For all interfaces use "-b 0.0.0.0" or "-b ::".""".formatted(LOOPBACK_ADDR)}, + {"-d", "-d, --directory - Directory to serve. Default: current directory."}, + {"-o", "-o, --output - Output format. none|info|verbose. Default: info."}, + {"-p", "-p, --port - Port to listen on. Default: 8000."}, + {"--bind-address", """ + -b, --bind-address - Address to bind to. Default: %s (loopback). + For all interfaces use "-b 0.0.0.0" or "-b ::".""".formatted(LOOPBACK_ADDR)}, + {"--directory", "-d, --directory - Directory to serve. Default: current directory."}, + {"--output", "-o, --output - Output format. none|info|verbose. Default: info."}, + {"--port", "-p, --port - Port to listen on. Default: 8000."} + // doesn't fail for -h option + }; + } + + @Test(dataProvider = "noArg") + public void testNoArg(String opt, String msg) throws Throwable { + out.println("\n--- testNoArg, opt=\"%s\" ".formatted(opt)); + simpleserver(JWEBSERVER, opt) + .shouldNotHaveExitValue(0) + .shouldContain("Error: no value given for " + opt) + .shouldContain(msg); + } + + @DataProvider + public Object[][] invalidValue() { + return new Object[][] { + {"-b", "[127.0.0.1]"}, + {"-b", "badhost"}, + {"--bind-address", "192.168.1.220..."}, + + {"-o", "bad-output-level"}, + {"--output", "bad-output-level"}, + + {"-p", "+-"}, + {"--port", "+-"} + }; + } + + @Test(dataProvider = "invalidValue") + public void testInvalidValue(String opt, String val) throws Throwable { + out.println("\n--- testInvalidValue, opt=\"%s\" ".formatted(opt)); + simpleserver(JWEBSERVER, opt, val) + .shouldNotHaveExitValue(0) + .shouldContain("Error: invalid value given for " + opt + ": " + val); + } + + @DataProvider + public Object[][] portOptions() { return new Object[][] {{"-p"}, {"--port"}}; } + + @Test(dataProvider = "portOptions") + public void testPortOutOfRange(String opt) throws Throwable { + out.println("\n--- testPortOutOfRange, opt=\"%s\" ".formatted(opt)); + simpleserver(JWEBSERVER, opt, "65536") // range 0 to 65535 + .shouldNotHaveExitValue(0) + .shouldContain("Error: server config failed: " + "port out of range:65536"); + } + + @DataProvider + public Object[][] directoryOptions() { return new Object[][] {{"-d"}, {"--directory"}}; } + + @Test(dataProvider = "directoryOptions") + public void testRootNotAbsolute(String opt) throws Throwable { + out.println("\n--- testRootNotAbsolute, opt=\"%s\" ".formatted(opt)); + var root = Path.of("."); + assertFalse(root.isAbsolute()); + simpleserver(JWEBSERVER, opt, root.toString()) + .shouldNotHaveExitValue(0) + .shouldContain("Error: server config failed: " + "Path is not absolute:"); + } + + @Test(dataProvider = "directoryOptions") + public void testRootNotADirectory(String opt) throws Throwable { + out.println("\n--- testRootNotADirectory, opt=\"%s\" ".formatted(opt)); + var file = TEST_FILE.toString(); + assertFalse(Files.isDirectory(TEST_FILE)); + simpleserver(JWEBSERVER, opt, file) + .shouldNotHaveExitValue(0) + .shouldContain("Error: server config failed: " + "Path is not a directory: " + file); + } + + @Test(dataProvider = "directoryOptions") + public void testRootDoesNotExist(String opt) throws Throwable { + out.println("\n--- testRootDoesNotExist, opt=\"%s\" ".formatted(opt)); + Path root = TEST_DIR.resolve("not/existent/dir"); + assertFalse(Files.exists(root)); + simpleserver(JWEBSERVER, opt, root.toString()) + .shouldNotHaveExitValue(0) + .shouldContain("Error: server config failed: " + "Path does not exist: " + root.toString()); + } + + @Test(dataProvider = "directoryOptions") + public void testRootNotReadable(String opt) throws Throwable { + out.println("\n--- testRootNotReadable, opt=\"%s\" ".formatted(opt)); + if (Platform.isWindows()) { + // Not applicable to Windows. Reason: cannot revoke an owner's read + // access to a directory that was created by that owner + throw new SkipException("cannot run on Windows"); + } + Path root = Files.createDirectories(TEST_DIR.resolve("not/readable/dir")); + try { + root.toFile().setReadable(false, false); + assertFalse(Files.isReadable(root)); + simpleserver(JWEBSERVER, opt, root.toString()) + .shouldNotHaveExitValue(0) + .shouldContain("Error: server config failed: " + "Path is not readable: " + root.toString()); + } finally { + root.toFile().setReadable(true, false); + } + } + + @AfterTest + public void teardown() throws IOException { + if (Files.exists(TEST_DIR)) { + FileUtils.deleteFileTreeWithRetry(TEST_DIR); + } + } + + // --- infra --- + + static String getJwebserver(Path image) { + boolean isWindows = System.getProperty("os.name").startsWith("Windows"); + Path jwebserver = image.resolve("bin").resolve(isWindows ? "jwebserver.exe" : "jwebserver"); + if (Files.notExists(jwebserver)) + throw new RuntimeException(jwebserver + " not found"); + return jwebserver.toAbsolutePath().toString(); + } + + static OutputAnalyzer simpleserver(String... args) throws Throwable { + var pb = new ProcessBuilder(args) + .directory(TEST_DIR.toFile()); + var outputAnalyser = ProcessTools.executeCommand(pb) + .outputTo(System.out) + .errorTo(System.out); + return outputAnalyser; + } +} diff --git a/test/jdk/com/sun/net/httpserver/simpleserver/jwebserver/CommandLinePortNotSpecifiedTest.java b/test/jdk/com/sun/net/httpserver/simpleserver/jwebserver/CommandLinePortNotSpecifiedTest.java new file mode 100644 index 0000000000000000000000000000000000000000..4d850442b25e4580919f68fa2d356f6a499b5af8 --- /dev/null +++ b/test/jdk/com/sun/net/httpserver/simpleserver/jwebserver/CommandLinePortNotSpecifiedTest.java @@ -0,0 +1,154 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8276848 + * @summary Tests the jwebserver tool with port not specified + * @modules jdk.httpserver + * @library /test/lib + * @run testng/othervm/manual CommandLinePortNotSpecifiedTest + */ + +import java.io.IOException; +import java.net.InetAddress; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.concurrent.TimeUnit; +import jdk.test.lib.Platform; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.util.FileUtils; +import org.testng.annotations.AfterTest; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; +import static java.lang.System.out; + +public class CommandLinePortNotSpecifiedTest { + + static final Path JAVA_HOME = Path.of(System.getProperty("java.home")); + static final String JWEBSERVER = getJwebserver(JAVA_HOME); + static final Path CWD = Path.of(".").toAbsolutePath().normalize(); + static final Path TEST_DIR = CWD.resolve("CommandLinePortNotSpecifiedTest"); + static final Path TEST_FILE = TEST_DIR.resolve("file.txt"); + static final String TEST_DIR_STR = TEST_DIR.toString(); + static final String LOOPBACK_ADDR = InetAddress.getLoopbackAddress().getHostAddress(); + + @BeforeTest + public void setup() throws IOException { + if (Files.exists(TEST_DIR)) { + FileUtils.deleteFileTreeWithRetry(TEST_DIR); + } + Files.createDirectories(TEST_DIR); + Files.createFile(TEST_FILE); + } + + static final int SIGTERM = 15; + static final int NORMAL_EXIT_CODE = normalExitCode(); + + static int normalExitCode() { + if (Platform.isWindows()) { + return 1; // expected process destroy exit code + } else { + // signal terminated exit code on Unix is 128 + signal value + return 128 + SIGTERM; + } + } + + /** + * This is a manual test to confirm the command-line tool starts successfully + * in the case where the port is not specified. In this case the server uses + * the default port 8000. The test is manual to avoid a BindException in the + * unlikely but not impossible case that the port is already in use. + */ + @Test + public void testPortNotSpecified() throws Throwable { + out.println("\n--- testPortNotSpecified"); + simpleserver(JWEBSERVER) + .shouldHaveExitValue(NORMAL_EXIT_CODE) + .shouldContain("Binding to loopback by default. For all interfaces use \"-b 0.0.0.0\" or \"-b ::\".") + .shouldContain("Serving " + TEST_DIR_STR + " and subdirectories on " + LOOPBACK_ADDR + " port") + .shouldContain("URL http://" + LOOPBACK_ADDR); + } + + @AfterTest + public void teardown() throws IOException { + if (Files.exists(TEST_DIR)) { + FileUtils.deleteFileTreeWithRetry(TEST_DIR); + } + } + + // --- infra --- + + static String getJwebserver(Path image) { + boolean isWindows = System.getProperty("os.name").startsWith("Windows"); + Path jwebserver = image.resolve("bin").resolve(isWindows ? "jwebserver.exe" : "jwebserver"); + if (Files.notExists(jwebserver)) + throw new RuntimeException(jwebserver + " not found"); + return jwebserver.toAbsolutePath().toString(); + } + + static final String REGULAR_STARTUP_LINE1_STRING = "Serving"; + static final String REGULAR_STARTUP_LINE2_STRING = "URL http://"; + + static final String OPTIONS_TEXT = """ + Options: + -b, --bind-address - Address to bind to. Default: %s (loopback). + For all interfaces use "-b 0.0.0.0" or "-b ::". + -d, --directory - Directory to serve. Default: current directory. + -o, --output - Output format. none|info|verbose. Default: info. + -p, --port - Port to listen on. Default: 8000. + -h, -?, --help - Prints this help message and exits. + -version, --version - Prints version information and exits. + To stop the server, press Ctrl + C.""".formatted(LOOPBACK_ADDR); + + // The stdout/stderr output line to wait for when starting the simpleserver + enum WaitForLine { + REGULAR_STARTUP_LINE (REGULAR_STARTUP_LINE2_STRING) , + HELP_STARTUP_LINE (OPTIONS_TEXT.lines().reduce((first, second) -> second).orElseThrow()); + + final String value; + WaitForLine(String value) { this.value = value; } + } + + static OutputAnalyzer simpleserver(String... args) throws Throwable { + return simpleserver(WaitForLine.REGULAR_STARTUP_LINE, true, args); + } + + static OutputAnalyzer simpleserver(WaitForLine waitForLine, boolean destroy, String... args) throws Throwable { + StringBuffer sb = new StringBuffer(); // stdout & stderr + // start the process and await the waitForLine before returning + var p = ProcessTools.startProcess("simpleserver", + new ProcessBuilder(args).directory(TEST_DIR.toFile()), + line -> sb.append(line + "\n"), + line -> line.startsWith(waitForLine.value), + 30, // suitably high default timeout, not expected to timeout + TimeUnit.SECONDS); + if (destroy) { + p.destroy(); // SIGTERM on Unix + } + int ec = p.waitFor(); + var outputAnalyser = new OutputAnalyzer(sb.toString(), "", ec); + return outputAnalyser; + } +} diff --git a/test/jdk/com/sun/net/httpserver/simpleserver/jwebserver/CommandLinePositiveTest.java b/test/jdk/com/sun/net/httpserver/simpleserver/jwebserver/CommandLinePositiveTest.java new file mode 100644 index 0000000000000000000000000000000000000000..c3a63371828d11a409e3c7d3d4edfd9a676258b1 --- /dev/null +++ b/test/jdk/com/sun/net/httpserver/simpleserver/jwebserver/CommandLinePositiveTest.java @@ -0,0 +1,257 @@ +/* + * 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. + */ + +/* + * @test + * @summary Positive tests for the jwebserver command-line tool + * @library /test/lib + * @modules jdk.httpserver + * @run testng/othervm CommandLinePositiveTest + */ + +import java.io.IOException; +import java.net.InetAddress; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.concurrent.TimeUnit; +import jdk.test.lib.Platform; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.util.FileUtils; +import org.testng.annotations.AfterTest; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import static java.lang.System.out; + +public class CommandLinePositiveTest { + + static final String JAVA_VERSION = System.getProperty("java.version"); + static final Path JAVA_HOME = Path.of(System.getProperty("java.home")); + static final String JWEBSERVER = getJwebserver(JAVA_HOME); + static final Path CWD = Path.of(".").toAbsolutePath().normalize(); + static final Path TEST_DIR = CWD.resolve("CommandLinePositiveTest"); + static final Path TEST_FILE = TEST_DIR.resolve("file.txt"); + static final String TEST_DIR_STR = TEST_DIR.toString(); + static final String LOOPBACK_ADDR = InetAddress.getLoopbackAddress().getHostAddress(); + + @BeforeTest + public void setup() throws IOException { + if (Files.exists(TEST_DIR)) { + FileUtils.deleteFileTreeWithRetry(TEST_DIR); + } + Files.createDirectories(TEST_DIR); + Files.createFile(TEST_FILE); + } + + static final int SIGTERM = 15; + static final int NORMAL_EXIT_CODE = normalExitCode(); + + static int normalExitCode() { + if (Platform.isWindows()) { + return 1; // expected process destroy exit code + } else { + // signal terminated exit code on Unix is 128 + signal value + return 128 + SIGTERM; + } + } + + @DataProvider + public Object[][] directoryOptions() { return new Object[][] {{"-d"}, {"--directory"}}; } + + @Test(dataProvider = "directoryOptions") + public void testDirectory(String opt) throws Throwable { + out.println("\n--- testDirectory, opt=\"%s\" ".formatted(opt)); + simpleserver(JWEBSERVER, "-p", "0", opt, TEST_DIR_STR) + .shouldHaveExitValue(NORMAL_EXIT_CODE) + .shouldContain("Binding to loopback by default. For all interfaces use \"-b 0.0.0.0\" or \"-b ::\".") + .shouldContain("Serving " + TEST_DIR_STR + " and subdirectories on " + LOOPBACK_ADDR + " port") + .shouldContain("URL http://" + LOOPBACK_ADDR); + } + + @DataProvider + public Object[][] portOptions() { return new Object[][] {{"-p"}, {"--port"}}; } + + @Test(dataProvider = "portOptions") + public void testPort(String opt) throws Throwable { + out.println("\n--- testPort, opt=\"%s\" ".formatted(opt)); + simpleserver(JWEBSERVER, opt, "0") + .shouldHaveExitValue(NORMAL_EXIT_CODE) + .shouldContain("Binding to loopback by default. For all interfaces use \"-b 0.0.0.0\" or \"-b ::\".") + .shouldContain("Serving " + TEST_DIR_STR + " and subdirectories on " + LOOPBACK_ADDR + " port") + .shouldContain("URL http://" + LOOPBACK_ADDR); + } + + @DataProvider + public Object[][] helpOptions() { return new Object[][] {{"-h"}, {"-?"}, {"--help"}}; } + + static final String USAGE_TEXT = """ + Usage: jwebserver [-b bind address] [-p port] [-d directory] + [-o none|info|verbose] [-h to show options] + [-version to show version information]"""; + + static final String OPTIONS_TEXT = """ + Options: + -b, --bind-address - Address to bind to. Default: %s (loopback). + For all interfaces use "-b 0.0.0.0" or "-b ::". + -d, --directory - Directory to serve. Default: current directory. + -o, --output - Output format. none|info|verbose. Default: info. + -p, --port - Port to listen on. Default: 8000. + -h, -?, --help - Prints this help message and exits. + -version, --version - Prints version information and exits. + To stop the server, press Ctrl + C.""".formatted(LOOPBACK_ADDR); + + @Test(dataProvider = "helpOptions") + public void testHelp(String opt) throws Throwable { + out.println("\n--- testHelp, opt=\"%s\" ".formatted(opt)); + simpleserver(WaitForLine.HELP_STARTUP_LINE, + false, // do not explicitly destroy the process + JWEBSERVER, opt) + .shouldHaveExitValue(0) + .shouldContain(USAGE_TEXT) + .shouldContain(OPTIONS_TEXT); + } + + @DataProvider + public Object[][] versionOptions() { return new Object[][] {{"-version"}, {"--version"}}; } + + @Test(dataProvider = "versionOptions") + public void testVersion(String opt) throws Throwable { + out.println("\n--- testVersion, opt=\"%s\" ".formatted(opt)); + simpleserver(WaitForLine.VERSION_STARTUP_LINE, + false, // do not explicitly destroy the process + JWEBSERVER, opt) + .shouldHaveExitValue(0); + } + + @DataProvider + public Object[][] bindOptions() { return new Object[][] {{"-b"}, {"--bind-address"}}; } + + @Test(dataProvider = "bindOptions") + public void testBindAllInterfaces(String opt) throws Throwable { + out.println("\n--- testBindAllInterfaces, opt=\"%s\" ".formatted(opt)); + simpleserver(JWEBSERVER, "-p", "0", opt, "0.0.0.0") + .shouldHaveExitValue(NORMAL_EXIT_CODE) + .shouldContain("Serving " + TEST_DIR_STR + " and subdirectories on 0.0.0.0 (all interfaces) port") + .shouldContain("URL http://" + InetAddress.getLocalHost().getHostAddress()); + simpleserver(JWEBSERVER, opt, "::0") + .shouldHaveExitValue(NORMAL_EXIT_CODE) + .shouldContain("Serving " + TEST_DIR_STR + " and subdirectories on 0.0.0.0 (all interfaces) port") + .shouldContain("URL http://" + InetAddress.getLocalHost().getHostAddress()); + } + + @Test(dataProvider = "bindOptions") + public void testLastOneWinsBindAddress(String opt) throws Throwable { + out.println("\n--- testLastOneWinsBindAddress, opt=\"%s\" ".formatted(opt)); + simpleserver(JWEBSERVER, "-p", "0", opt, "123.4.5.6", opt, LOOPBACK_ADDR) + .shouldHaveExitValue(NORMAL_EXIT_CODE) + .shouldContain("Serving " + TEST_DIR_STR + " and subdirectories on " + LOOPBACK_ADDR + " port") + .shouldContain("URL http://" + LOOPBACK_ADDR); + + } + + @Test(dataProvider = "directoryOptions") + public void testLastOneWinsDirectory(String opt) throws Throwable { + out.println("\n--- testLastOneWinsDirectory, opt=\"%s\" ".formatted(opt)); + simpleserver(JWEBSERVER, "-p", "0", opt, TEST_DIR_STR, opt, TEST_DIR_STR) + .shouldHaveExitValue(NORMAL_EXIT_CODE) + .shouldContain("Binding to loopback by default. For all interfaces use \"-b 0.0.0.0\" or \"-b ::\".") + .shouldContain("Serving " + TEST_DIR_STR + " and subdirectories on " + LOOPBACK_ADDR + " port") + .shouldContain("URL http://" + LOOPBACK_ADDR); + } + + @DataProvider + public Object[][] outputOptions() { return new Object[][] {{"-o"}, {"--output"}}; } + + @Test(dataProvider = "outputOptions") + public void testLastOneWinsOutput(String opt) throws Throwable { + out.println("\n--- testLastOneWinsOutput, opt=\"%s\" ".formatted(opt)); + simpleserver(JWEBSERVER, "-p", "0", opt, "none", opt, "verbose") + .shouldHaveExitValue(NORMAL_EXIT_CODE) + .shouldContain("Binding to loopback by default. For all interfaces use \"-b 0.0.0.0\" or \"-b ::\".") + .shouldContain("Serving " + TEST_DIR_STR + " and subdirectories on " + LOOPBACK_ADDR + " port") + .shouldContain("URL http://" + LOOPBACK_ADDR); + } + + @Test(dataProvider = "portOptions") + public void testLastOneWinsPort(String opt) throws Throwable { + out.println("\n--- testLastOneWinsPort, opt=\"%s\" ".formatted(opt)); + simpleserver(JWEBSERVER, opt, "-999", opt, "0") + .shouldHaveExitValue(NORMAL_EXIT_CODE) + .shouldContain("Binding to loopback by default. For all interfaces use \"-b 0.0.0.0\" or \"-b ::\".") + .shouldContain("Serving " + TEST_DIR_STR + " and subdirectories on " + LOOPBACK_ADDR + " port") + .shouldContain("URL http://" + LOOPBACK_ADDR); + } + + @AfterTest + public void teardown() throws IOException { + if (Files.exists(TEST_DIR)) { + FileUtils.deleteFileTreeWithRetry(TEST_DIR); + } + } + + // --- infra --- + + static String getJwebserver(Path image) { + boolean isWindows = System.getProperty("os.name").startsWith("Windows"); + Path jwebserver = image.resolve("bin").resolve(isWindows ? "jwebserver.exe" : "jwebserver"); + if (Files.notExists(jwebserver)) + throw new RuntimeException(jwebserver + " not found"); + return jwebserver.toAbsolutePath().toString(); + } + + static final String REGULAR_STARTUP_LINE1_STRING = "Serving"; + static final String REGULAR_STARTUP_LINE2_STRING = "URL http://"; + static final String VERSION_STARTUP_LINE_STRING = "jwebserver " + JAVA_VERSION; + + // The stdout/stderr output line to wait for when starting the simpleserver + enum WaitForLine { + REGULAR_STARTUP_LINE (REGULAR_STARTUP_LINE2_STRING) , + HELP_STARTUP_LINE (OPTIONS_TEXT.lines().reduce((first, second) -> second).orElseThrow()), + VERSION_STARTUP_LINE (VERSION_STARTUP_LINE_STRING); + + final String value; + WaitForLine(String value) { this.value = value; } + } + + static OutputAnalyzer simpleserver(String... args) throws Throwable { + return simpleserver(WaitForLine.REGULAR_STARTUP_LINE, true, args); + } + + static OutputAnalyzer simpleserver(WaitForLine waitForLine, boolean destroy, String... args) throws Throwable { + StringBuffer sb = new StringBuffer(); // stdout & stderr + // start the process and await the waitForLine before returning + var p = ProcessTools.startProcess("simpleserver", + new ProcessBuilder(args).directory(TEST_DIR.toFile()), + line -> sb.append(line + "\n"), + line -> line.startsWith(waitForLine.value), + 30, // suitably high default timeout, not expected to timeout + TimeUnit.SECONDS); + if (destroy) { + p.destroy(); // SIGTERM on Unix + } + int ec = p.waitFor(); + var outputAnalyser = new OutputAnalyzer(sb.toString(), "", ec); + return outputAnalyser; + } +} diff --git a/test/jdk/com/sun/net/httpserver/simpleserver/jwebserver/MaxRequestTimeTest.java b/test/jdk/com/sun/net/httpserver/simpleserver/jwebserver/MaxRequestTimeTest.java new file mode 100644 index 0000000000000000000000000000000000000000..e530c9805657ce54fdd855b1dd95e8c8491c4103 --- /dev/null +++ b/test/jdk/com/sun/net/httpserver/simpleserver/jwebserver/MaxRequestTimeTest.java @@ -0,0 +1,207 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8278398 + * @summary Tests the jwebserver's maximum request time + * @modules jdk.httpserver + * @library /test/lib + * @run testng/othervm MaxRequestTimeTest + */ + +import java.io.IOException; +import java.net.InetAddress; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLException; +import jdk.test.lib.Platform; +import jdk.test.lib.net.SimpleSSLContext; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.util.FileUtils; +import org.testng.annotations.AfterTest; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; +import static java.lang.System.out; +import static java.net.http.HttpClient.Builder.NO_PROXY; +import static org.testng.Assert.*; + +/** + * This test confirms that the jwebserver does not wait indefinitely for + * a request to arrive. + * + * The jwebserver has a maximum request time of 5 seconds, which is set with the + * "sun.net.httpserver.maxReqTime" system property. If this threshold is + * reached, for example in the case of an HTTPS request where the server keeps + * waiting for a plaintext request, the server closes the connection. Subsequent + * requests are expected to be handled as normal. + * + * The test checks in the following order that: + * 1. an HTTP request is handled successfully, + * 2. an HTTPS request fails due to the server closing the connection + * 3. another HTTP request is handled successfully. + */ +public class MaxRequestTimeTest { + static final Path JAVA_HOME = Path.of(System.getProperty("java.home")); + static final String JWEBSERVER = getJwebserver(JAVA_HOME); + static final Path CWD = Path.of(".").toAbsolutePath().normalize(); + static final Path TEST_DIR = CWD.resolve("MaxRequestTimeTest"); + static final String LOOPBACK_ADDR = InetAddress.getLoopbackAddress().getHostAddress(); + static final AtomicInteger PORT = new AtomicInteger(); + + static SSLContext sslContext; + + @BeforeTest + public void setup() throws IOException { + if (Files.exists(TEST_DIR)) { + FileUtils.deleteFileTreeWithRetry(TEST_DIR); + } + Files.createDirectories(TEST_DIR); + + sslContext = new SimpleSSLContext().get(); + if (sslContext == null) + throw new AssertionError("Unexpected null sslContext"); + } + + @Test + public void testMaxRequestTime() throws Throwable { + final var sb = new StringBuffer(); // stdout & stderr + final var p = startProcess("jwebserver", sb); + try { + sendHTTPSRequest(); // server expected to terminate connection + sendHTTPRequest(); // server expected to respond successfully + sendHTTPSRequest(); // server expected to terminate connection + sendHTTPRequest(); // server expected to respond successfully + } finally { + p.destroy(); + int exitCode = p.waitFor(); + checkOutput(sb, exitCode); + } + } + + static String expectedBody = """ + <!DOCTYPE html> + <html> + <head> + <meta charset="utf-8"/> + </head> + <body> + <h1>Directory listing for /</h1> + <ul> + </ul> + </body> + </html> + """; + + void sendHTTPRequest() throws IOException, InterruptedException { + out.println("\n--- sendHTTPRequest"); + var client = HttpClient.newBuilder() + .proxy(NO_PROXY) + .build(); + var request = HttpRequest.newBuilder(URI.create("http://localhost:" + PORT.get() + "/")).build(); + var response = client.send(request, HttpResponse.BodyHandlers.ofString()); + assertEquals(response.body(), expectedBody); + } + + void sendHTTPSRequest() throws IOException, InterruptedException { + out.println("\n--- sendHTTPSRequest"); + var client = HttpClient.newBuilder() + .sslContext(sslContext) + .proxy(NO_PROXY) + .build(); + var request = HttpRequest.newBuilder(URI.create("https://localhost:" + PORT.get() + "/")).build(); + try { + client.send(request, HttpResponse.BodyHandlers.ofString()); + throw new RuntimeException("Expected SSLException not thrown"); + } catch (SSLException expected) { // server closes connection when max request time is reached + expected.printStackTrace(System.out); + } + } + + @AfterTest + public void teardown() throws IOException { + if (Files.exists(TEST_DIR)) { + FileUtils.deleteFileTreeWithRetry(TEST_DIR); + } + } + + // --- infra --- + + static String getJwebserver(Path image) { + boolean isWindows = System.getProperty("os.name").startsWith("Windows"); + Path jwebserver = image.resolve("bin").resolve(isWindows ? "jwebserver.exe" : "jwebserver"); + if (Files.notExists(jwebserver)) + throw new RuntimeException(jwebserver + " not found"); + return jwebserver.toAbsolutePath().toString(); + } + + // The stdout/stderr output line to wait for when starting the jwebserver + static final String REGULAR_STARTUP_LINE_STRING_1 = "URL http://"; + static final String REGULAR_STARTUP_LINE_STRING_2 = "Serving "; + + static void parseAndSetPort(String line) { + PORT.set(Integer.parseInt(line.split(" port ")[1])); + } + + static Process startProcess(String name, StringBuffer sb) throws Throwable { + // starts the process, parses the port and awaits startup line before sending requests + return ProcessTools.startProcess(name, + new ProcessBuilder(JWEBSERVER, "-p", "0").directory(TEST_DIR.toFile()), + line -> { + if (line.startsWith(REGULAR_STARTUP_LINE_STRING_2)) { parseAndSetPort(line); } + sb.append(line + "\n"); + }, + line -> line.startsWith(REGULAR_STARTUP_LINE_STRING_1), + 30, // suitably high default timeout, not expected to timeout + TimeUnit.SECONDS); + } + + static final int SIGTERM = 15; + static final int NORMAL_EXIT_CODE = normalExitCode(); + + static int normalExitCode() { + if (Platform.isWindows()) { + return 1; // expected process destroy exit code + } else { + // signal terminated exit code on Unix is 128 + signal value + return 128 + SIGTERM; + } + } + + static void checkOutput(StringBuffer sb, int exitCode) { + out.println("\n--- server output: \n" + sb); + var outputAnalyser = new OutputAnalyzer(sb.toString(), "", exitCode); + outputAnalyser.shouldHaveExitValue(NORMAL_EXIT_CODE) + .shouldContain("Binding to loopback by default. For all interfaces use \"-b 0.0.0.0\" or \"-b ::\".") + .shouldContain("Serving " + TEST_DIR + " and subdirectories on " + LOOPBACK_ADDR + " port " + PORT) + .shouldContain("URL http://" + LOOPBACK_ADDR); + } +} diff --git a/test/jdk/java/awt/Choice/ChoiceKeyEventReaction/ChoiceKeyEventReaction.java b/test/jdk/java/awt/Choice/ChoiceKeyEventReaction/ChoiceKeyEventReaction.java index 4b835b11063e59b34247d43c9588cf0651460c07..84e5b4d62e45b639da2d97db179a9ba90b8ba935 100644 --- a/test/jdk/java/awt/Choice/ChoiceKeyEventReaction/ChoiceKeyEventReaction.java +++ b/test/jdk/java/awt/Choice/ChoiceKeyEventReaction/ChoiceKeyEventReaction.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -131,7 +131,7 @@ public class ChoiceKeyEventReaction if (toolkit.equals("sun.awt.X11.XToolkit") && keyTypedOnTextField) { - throw new RuntimeException("Test failed. (XToolkit/MToolkit). KeyEvent was addressed to TextField."); + throw new RuntimeException("Test failed. (XToolkit). KeyEvent was addressed to TextField."); } System.out.println("Test passed. Unfocusable Choice doesn't react on keys."); diff --git a/test/jdk/java/awt/ColorClass/AlphaColorTest.java b/test/jdk/java/awt/ColorClass/AlphaColorTest.java index e3478c961fc02fca6d2a65e864cebe443c14d3ee..62d5ca4da327e4d01876e829bd40a092e60e6f0c 100644 --- a/test/jdk/java/awt/ColorClass/AlphaColorTest.java +++ b/test/jdk/java/awt/ColorClass/AlphaColorTest.java @@ -24,7 +24,7 @@ /** * @test * @key headful - * @bug 8204931 8227392 8224825 8233910 + * @bug 8204931 8227392 8224825 8233910 8275843 * @summary test alpha colors are blended with background. */ diff --git a/test/jdk/java/awt/ColorClass/XRenderTranslucentColorDrawTest.java b/test/jdk/java/awt/ColorClass/XRenderTranslucentColorDrawTest.java index 7754c4125cb71b3e12ea042f03b87df920643277..eab4a91308d5568a5ad716febfecdfa3f8fcb069 100644 --- a/test/jdk/java/awt/ColorClass/XRenderTranslucentColorDrawTest.java +++ b/test/jdk/java/awt/ColorClass/XRenderTranslucentColorDrawTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -21,14 +21,15 @@ * questions. */ + /* * @test * @key headful - * @bug 8176795 + * @bug 8176795 8275843 * @summary Test verifies that we get proper color when we draw translucent * color over an opaque color using X Render extension in Linux. - * @requires (os.family == "linux") - * @run main XRenderTranslucentColorDrawTest -Dsun.java2d.xrender=true + * @run main/othervm XRenderTranslucentColorDrawTest + * @run main/othervm -Dsun.java2d.xrender=true XRenderTranslucentColorDrawTest */ import java.awt.Color; @@ -36,30 +37,28 @@ import java.awt.Graphics2D; import java.awt.GraphicsConfiguration; import java.awt.GraphicsDevice; import java.awt.GraphicsEnvironment; +import java.awt.Transparency; import java.awt.image.BufferedImage; import java.awt.image.VolatileImage; public class XRenderTranslucentColorDrawTest { - public static void main(String[] args) throws Exception { - GraphicsEnvironment env = GraphicsEnvironment. - getLocalGraphicsEnvironment(); - GraphicsConfiguration translucentGC = null; - SCREENS: for (GraphicsDevice screen : env.getScreenDevices()) { + public static void main(String[] args) { + var env = GraphicsEnvironment.getLocalGraphicsEnvironment(); + for (GraphicsDevice screen : env.getScreenDevices()) { for (GraphicsConfiguration gc : screen.getConfigurations()) { - if (gc.isTranslucencyCapable()) { - translucentGC = gc; - break SCREENS; - } + test(gc, Transparency.OPAQUE); + test(gc, Transparency.BITMASK); + test(gc, Transparency.TRANSLUCENT); } } - if (translucentGC == null) { - throw new RuntimeException("No suitable gc found."); - } + } + + private static void test(GraphicsConfiguration gc, int transparency) { int width = 10; int height = 10; - VolatileImage image = translucentGC. - createCompatibleVolatileImage(width, height); + VolatileImage image = gc.createCompatibleVolatileImage(width, height, + transparency); Graphics2D g = image.createGraphics(); // draw opaque black color g.setColor(new Color(0xff000000, true)); @@ -72,10 +71,10 @@ public class XRenderTranslucentColorDrawTest { BufferedImage snapshot = image.getSnapshot(); int argb = snapshot.getRGB(width / 2, height / 2); // we expect the resultant rgb hex value to be ff808080 - if (!(Integer.toHexString(argb).equals("ff808080"))) { - throw new RuntimeException("Using X Render extension for drawing" - + " translucent color is not giving expected results."); + String actual = Integer.toHexString(argb); + if (!(actual.equals("ff808080"))) { + throw new RuntimeException("Drawing translucent color is not " + + "giving expected results: " + actual); } } -} - +} \ No newline at end of file diff --git a/test/jdk/java/awt/Component/CompEventOnHiddenComponent/CompEventOnHiddenComponent.java b/test/jdk/java/awt/Component/CompEventOnHiddenComponent/CompEventOnHiddenComponent.java index c643aae1f002d7d61fb5234d8e533bfae3d68947..0c1734cb1ccd120e9a0bdbb1c1a83f12276c7cdb 100644 --- a/test/jdk/java/awt/Component/CompEventOnHiddenComponent/CompEventOnHiddenComponent.java +++ b/test/jdk/java/awt/Component/CompEventOnHiddenComponent/CompEventOnHiddenComponent.java @@ -86,7 +86,7 @@ public class CompEventOnHiddenComponent EventQueue.invokeLater(new Runnable() { public void run() { JFrame parentWindow = new JFrame("JFrame 1"); - JButton component = new JButton("JButton 1");; + JButton component = new JButton("JButton 1"); JButton smallButton = new JButton("Small Button"); diff --git a/test/jdk/java/awt/Desktop/DesktopEventsExceptions/DesktopEventsExceptions.java b/test/jdk/java/awt/Desktop/DesktopEventsExceptions/DesktopEventsExceptions.java index 2a1b88d7d73365dd327521ce6471e6f575d86699..83a35b71a120f33f5b3a727017a605e212dba499 100644 --- a/test/jdk/java/awt/Desktop/DesktopEventsExceptions/DesktopEventsExceptions.java +++ b/test/jdk/java/awt/Desktop/DesktopEventsExceptions/DesktopEventsExceptions.java @@ -45,7 +45,7 @@ import java.util.List; * @test * @bug 8203224 * @summary tests that the correct exceptions are thrown by the events classes - * in {code java.awt.desktop} package + * in {@code java.awt.desktop} package * @run main/othervm DesktopEventsExceptions * @run main/othervm -Djava.awt.headless=true DesktopEventsExceptions */ diff --git a/test/jdk/java/awt/Dialog/MakeWindowAlwaysOnTop/MakeWindowAlwaysOnTop.java b/test/jdk/java/awt/Dialog/MakeWindowAlwaysOnTop/MakeWindowAlwaysOnTop.java index b6e17a88f075b989dc2b848c2a3202fceab61c2b..63d3463f981db918968ed718e2c3702557987cf8 100644 --- a/test/jdk/java/awt/Dialog/MakeWindowAlwaysOnTop/MakeWindowAlwaysOnTop.java +++ b/test/jdk/java/awt/Dialog/MakeWindowAlwaysOnTop/MakeWindowAlwaysOnTop.java @@ -46,6 +46,10 @@ public class MakeWindowAlwaysOnTop private static Frame f; private static Dialog d; + // move away from cursor + private final static int OFFSET_X = -20; + private final static int OFFSET_Y = -20; + public static void main(String[] args) throws Exception { Robot r = Util.createRobot(); @@ -101,7 +105,7 @@ public class MakeWindowAlwaysOnTop Util.waitForIdle(r); - Color c = r.getPixelColor(p.x + f.getWidth() / 2, p.y + f.getHeight() / 2); + Color c = r.getPixelColor(p.x + f.getWidth() / 2 - OFFSET_X, p.y + f.getHeight() / 2 - OFFSET_Y); System.out.println("Color = " + c); String exceptionMessage = null; diff --git a/test/jdk/java/awt/EmbeddedFrame/EmbeddedFrameGrabTest/EmbeddedFrameGrabTest.java b/test/jdk/java/awt/EmbeddedFrame/EmbeddedFrameGrabTest/EmbeddedFrameGrabTest.java index e186e7ac1320a2e9f3d1f4081159d725bcc6fd9c..535e6c68aa545f30eac55905c7a5d0d984c92efe 100644 --- a/test/jdk/java/awt/EmbeddedFrame/EmbeddedFrameGrabTest/EmbeddedFrameGrabTest.java +++ b/test/jdk/java/awt/EmbeddedFrame/EmbeddedFrameGrabTest/EmbeddedFrameGrabTest.java @@ -81,7 +81,7 @@ public class EmbeddedFrameGrabTest { = clazz.getConstructor(new Class[]{long.class}); final Frame embedded_frame = (Frame) constructor.newInstance(new Object[]{ - new Long(hwnd)});; + new Long(hwnd)}); final JComboBox<String> combo = new JComboBox<>(new String[]{ "Item 1", "Item 2" }); diff --git a/test/jdk/java/awt/Focus/ActualFocusedWindowTest/ActualFocusedWindowBlockingTest.java b/test/jdk/java/awt/Focus/ActualFocusedWindowTest/ActualFocusedWindowBlockingTest.java index a87b59a9388faa644adf15d2fd3f8550e7d0523a..1e5b27892087c9268e7440b7997365c08c9c0d63 100644 --- a/test/jdk/java/awt/Focus/ActualFocusedWindowTest/ActualFocusedWindowBlockingTest.java +++ b/test/jdk/java/awt/Focus/ActualFocusedWindowTest/ActualFocusedWindowBlockingTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 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 @@ -69,11 +69,6 @@ public class ActualFocusedWindowBlockingTest { } public void start() { - if ("sun.awt.motif.MToolkit".equals(Toolkit.getDefaultToolkit().getClass().getName())) { - System.out.println("No testing on Motif. Test passed."); - return; - } - System.out.println("\nTest started:\n"); // Test 1. diff --git a/test/jdk/java/awt/Focus/AutoRequestFocusTest/AutoRequestFocusSetVisibleTest.java b/test/jdk/java/awt/Focus/AutoRequestFocusTest/AutoRequestFocusSetVisibleTest.java index 0a7a1afff619d3e7e952bb025faeb57f879531b3..45914e0670bba2e3c3977aaafc2489fb913daf6c 100644 --- a/test/jdk/java/awt/Focus/AutoRequestFocusTest/AutoRequestFocusSetVisibleTest.java +++ b/test/jdk/java/awt/Focus/AutoRequestFocusTest/AutoRequestFocusSetVisibleTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 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 @@ -293,43 +293,39 @@ public class AutoRequestFocusSetVisibleTest { // 6. Show unblocking modal Dialog. /////////////////////////////////// - if ("sun.awt.motif.MToolkit".equals(toolkitClassName)) { - System.out.println("Stage 6 - Skiping."); - } else { - System.out.println("Stage 6 in progress..."); + System.out.println("Stage 6 in progress..."); - // --- - // Testing the bug of activating invisible modal Dialog (awt_Window::SetAndActivateModalBlocker). - // Having some window not excluded from modality, so that it would be blocked. - Frame f = new Frame("Aux. Frame"); - f.setSize(100, 100); - setVisible(f, true); - // --- + // --- + // Testing the bug of activating invisible modal Dialog (awt_Window::SetAndActivateModalBlocker). + // Having some window not excluded from modality, so that it would be blocked. + Frame f = new Frame("Aux. Frame"); + f.setSize(100, 100); + setVisible(f, true); + // --- - setVisible(focusedFrame, true); + setVisible(focusedFrame, true); + if (!focusOwner.hasFocus()) { + Util.clickOnComp(focusOwner, robot); + Util.waitForIdle(robot); if (!focusOwner.hasFocus()) { - Util.clickOnComp(focusOwner, robot); - Util.waitForIdle(robot); - if (!focusOwner.hasFocus()) { - throw new Error("Test error: the frame couldn't be focused."); - } + throw new Error("Test error: the frame couldn't be focused."); } + } - dialog.setModal(true); - dialog.setAutoRequestFocus(false); - focusedFrame.setModalExclusionType(Dialog.ModalExclusionType.APPLICATION_EXCLUDE); + dialog.setModal(true); + dialog.setAutoRequestFocus(false); + focusedFrame.setModalExclusionType(Dialog.ModalExclusionType.APPLICATION_EXCLUDE); - TestHelper.invokeLaterAndWait(new Runnable() { - public void run() { - dialog.setVisible(true); - } - }, robot); + TestHelper.invokeLaterAndWait(new Runnable() { + public void run() { + dialog.setVisible(true); + } + }, robot); - if (dialog.isFocused()) { - throw new TestFailedException("the unblocking dialog shouldn't gain focus but it did!"); - } - setVisible(dialog, false); + if (dialog.isFocused()) { + throw new TestFailedException("the unblocking dialog shouldn't gain focus but it did!"); } + setVisible(dialog, false); System.out.println("Test passed."); } diff --git a/test/jdk/java/awt/Focus/AutoRequestFocusTest/AutoRequestFocusToFrontTest.java b/test/jdk/java/awt/Focus/AutoRequestFocusTest/AutoRequestFocusToFrontTest.java index 8ca4d4d6f7b1112d794331a646a548e83189ba2c..b1b8b8458ff0885db76bd56df844e86a87453cd5 100644 --- a/test/jdk/java/awt/Focus/AutoRequestFocusTest/AutoRequestFocusToFrontTest.java +++ b/test/jdk/java/awt/Focus/AutoRequestFocusTest/AutoRequestFocusToFrontTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 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 @@ -202,26 +202,22 @@ public class AutoRequestFocusToFrontTest { // Focused frame is excluded from modality. //////////////////////////////////////////////// - if (!"sun.awt.motif.MToolkit".equals(toolkitClassName)) { - recreateGUI(); - auxFrame.setModalExclusionType(Dialog.ModalExclusionType.APPLICATION_EXCLUDE); + recreateGUI(); + auxFrame.setModalExclusionType(Dialog.ModalExclusionType.APPLICATION_EXCLUDE); - Test.setWindows(modalDialog, modalDialog, new Window[] {modalDialog, frame3}); - Test.test("Test stage 6.1 in progress", modalDlgButton); - } + Test.setWindows(modalDialog, modalDialog, new Window[] {modalDialog, frame3}); + Test.test("Test stage 6.1 in progress", modalDlgButton); // 6.2. Owner Frame (with owned modal Dialog). // Focused frame is excluded from modality. //////////////////////////////////////////////// - if (!"sun.awt.motif.MToolkit".equals(toolkitClassName)) { - recreateGUI(); - auxFrame.setModalExclusionType(Dialog.ModalExclusionType.APPLICATION_EXCLUDE); + recreateGUI(); + auxFrame.setModalExclusionType(Dialog.ModalExclusionType.APPLICATION_EXCLUDE); - Test.setWindows(frame3, modalDialog, new Window[] {modalDialog, frame3}); - Test.test("Test stage 6.2 in progress", modalDlgButton, true); - } + Test.setWindows(frame3, modalDialog, new Window[] {modalDialog, frame3}); + Test.test("Test stage 6.2 in progress", modalDlgButton, true); /////////////////////////////////////////////////// // 7. Calling setVisible(true) for the shown Frame. @@ -422,4 +418,3 @@ class TestFailedException extends RuntimeException { super("Test failed: " + msg); } } - diff --git a/test/jdk/java/awt/Focus/ModalBlockedStealsFocusTest/ModalBlockedStealsFocusTest.java b/test/jdk/java/awt/Focus/ModalBlockedStealsFocusTest/ModalBlockedStealsFocusTest.java index 9a0d476133badf25515c8a9056fd1a615e5f9914..27be25773f2b382e688a0174b31ee8ec26979b69 100644 --- a/test/jdk/java/awt/Focus/ModalBlockedStealsFocusTest/ModalBlockedStealsFocusTest.java +++ b/test/jdk/java/awt/Focus/ModalBlockedStealsFocusTest/ModalBlockedStealsFocusTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 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 @@ -47,11 +47,6 @@ public class ModalBlockedStealsFocusTest { } public void start() { - if ("sun.awt.motif.MToolkit".equals(Toolkit.getDefaultToolkit().getClass().getName())) { - System.out.println("The test is not for MToolkit."); - return; - } - dialog.setBounds(800, 0, 200, 100); frame.setBounds(800, 150, 200, 100); diff --git a/test/jdk/java/awt/Focus/ModalExcludedWindowClickTest/ModalExcludedWindowClickTest.java b/test/jdk/java/awt/Focus/ModalExcludedWindowClickTest/ModalExcludedWindowClickTest.java index 0ee37cbce69f10abd136156af4c7f7ffc3c6236a..7cfe66834bc4a826deef50935c8be22fbe4f2eb0 100644 --- a/test/jdk/java/awt/Focus/ModalExcludedWindowClickTest/ModalExcludedWindowClickTest.java +++ b/test/jdk/java/awt/Focus/ModalExcludedWindowClickTest/ModalExcludedWindowClickTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -57,12 +57,6 @@ public class ModalExcludedWindowClickTest { } public void start() { - - if ("sun.awt.motif.MToolkit".equals(Toolkit.getDefaultToolkit().getClass().getName())) { - System.out.println("No testing on MToolkit."); - return; - } - button.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { actionPerformed = true; diff --git a/test/jdk/java/awt/Focus/NonFocusableBlockedOwnerTest/NonFocusableBlockedOwnerTest.java b/test/jdk/java/awt/Focus/NonFocusableBlockedOwnerTest/NonFocusableBlockedOwnerTest.java index b6d4c962efa4d32f42cc44bafb4ec995f3d70f09..abf8d57cecdbcebaf745fe952b9d0df0ee5ad186 100644 --- a/test/jdk/java/awt/Focus/NonFocusableBlockedOwnerTest/NonFocusableBlockedOwnerTest.java +++ b/test/jdk/java/awt/Focus/NonFocusableBlockedOwnerTest/NonFocusableBlockedOwnerTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -56,12 +56,6 @@ public class NonFocusableBlockedOwnerTest { } public void start() { - - if ("sun.awt.motif.MToolkit".equals(Toolkit.getDefaultToolkit().getClass().getName())) { - System.out.println("No testing on MToolkit."); - return; - } - try { EventQueue.invokeLater(new Runnable() { public void run() { diff --git a/test/jdk/java/awt/Focus/SimpleWindowActivationTest/SimpleWindowActivationTest.java b/test/jdk/java/awt/Focus/SimpleWindowActivationTest/SimpleWindowActivationTest.java index a63d8194714fa46040d93741ddfa55a802382940..212d5274a8910ee51cf7f118156abb09029d0568 100644 --- a/test/jdk/java/awt/Focus/SimpleWindowActivationTest/SimpleWindowActivationTest.java +++ b/test/jdk/java/awt/Focus/SimpleWindowActivationTest/SimpleWindowActivationTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -47,12 +47,6 @@ public class SimpleWindowActivationTest { private static Robot robot; public static void main(String[] args) throws Exception { - - if ("sun.awt.motif.MToolkit".equals(Toolkit.getDefaultToolkit().getClass().getName())) { - System.out.println("No testing on Motif. Test passed."); - return; - } - robot = new Robot(); robot.setAutoDelay(50); diff --git a/test/jdk/java/awt/Focus/WindowUpdateFocusabilityTest/WindowUpdateFocusabilityTest.java b/test/jdk/java/awt/Focus/WindowUpdateFocusabilityTest/WindowUpdateFocusabilityTest.java index 962f6b4665cdf55f4f8709c0ba6f3fdf567d3551..6a6cfc9393926aff6934a7b43c06d13bac1e29aa 100644 --- a/test/jdk/java/awt/Focus/WindowUpdateFocusabilityTest/WindowUpdateFocusabilityTest.java +++ b/test/jdk/java/awt/Focus/WindowUpdateFocusabilityTest/WindowUpdateFocusabilityTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -63,11 +63,6 @@ public class WindowUpdateFocusabilityTest { } public void start() { - if ("sun.awt.motif.MToolkit".equals(Toolkit.getDefaultToolkit().getClass().getName())) { - System.out.println("No testing on Motif."); - return; - } - test(new Frame("Frame owner")); Frame dialog_owner = new Frame("dialog's owner"); test(new Dialog(dialog_owner)); diff --git a/test/jdk/java/awt/Frame/SetMinimumSizeTest/SetMinimumSizeTest1.java b/test/jdk/java/awt/Frame/SetMinimumSizeTest/SetMinimumSizeTest1.java new file mode 100644 index 0000000000000000000000000000000000000000..f6560d7e66f5b2f90f6b2f55f3539c57bf200262 --- /dev/null +++ b/test/jdk/java/awt/Frame/SetMinimumSizeTest/SetMinimumSizeTest1.java @@ -0,0 +1,88 @@ +/* + * 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. + */ + +/* + * @test + * @key headful + * @summary Verify that increase in Frame's minimumSize gets reflected in the subsequent getSize call + * @run main SetMinimumSizeTest1 + */ + +import java.awt.Button; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Robot; + +public class SetMinimumSizeTest1 { + + private static Frame frame; + private static volatile Dimension dimension; + private static volatile Dimension actualDimension; + + public static void createGUI() { + frame = new Frame(); + frame.add(new Button("Button")); + frame.setSize(140, 140); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } + + public static void doTest() throws Exception { + try { + EventQueue.invokeAndWait(() -> createGUI()); + + Robot robot = new Robot(); + robot.setAutoDelay(100); + robot.waitForIdle(); + + EventQueue.invokeAndWait(() -> { + dimension = frame.getSize(); + dimension.width += 20; + dimension.height += 20; + frame.setMinimumSize(dimension); + frame.invalidate(); + frame.validate(); + }); + + robot.waitForIdle(); + + EventQueue.invokeAndWait(() -> { + actualDimension = frame.getSize(); + }); + + if (!actualDimension.equals(dimension)) { + throw new RuntimeException("Test Failed\n" + + "expected dimension:(" + dimension.width + "," + dimension.height +")\n" + + "actual dimension:(" + actualDimension.width + "," + actualDimension.height + ")"); + } + } finally { + EventQueue.invokeAndWait(() -> frame.dispose()); + } + } + + public static void main(String[] args) throws Exception { + doTest(); + } +} + diff --git a/test/jdk/java/awt/Frame/SetMinimumSizeTest/SetMinimumSizeTest2.java b/test/jdk/java/awt/Frame/SetMinimumSizeTest/SetMinimumSizeTest2.java new file mode 100644 index 0000000000000000000000000000000000000000..ca0763e19fad453732349d4762055df46a31f397 --- /dev/null +++ b/test/jdk/java/awt/Frame/SetMinimumSizeTest/SetMinimumSizeTest2.java @@ -0,0 +1,97 @@ +/* + * 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. + */ + +/* + * @test + * @key headful + * @summary Verify frame resizes back to minimumSize on calling pack + * @run main SetMinimumSizeTest2 + */ + +import java.awt.Button; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Robot; + +public class SetMinimumSizeTest2 { + + private static Frame frame; + private static volatile Dimension dimension; + private static volatile Dimension actualDimension; + + public static void createGUI() { + frame = new Frame(); + frame.add(new Button("Button")); + frame.setMinimumSize(new Dimension(140, 140)); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } + + public static void doTest() throws Exception { + try { + EventQueue.invokeAndWait(() -> createGUI()); + + Robot robot = new Robot(); + robot.setAutoDelay(100); + robot.waitForIdle(); + + EventQueue.invokeAndWait(() -> { + dimension = frame.getSize(); + }); + + EventQueue.invokeAndWait(() -> { + frame.setSize(dimension.width + 20, dimension.height + 20); + frame.invalidate(); + frame.validate(); + }); + + robot.waitForIdle(); + + EventQueue.invokeAndWait(() -> { + frame.pack(); + frame.invalidate(); + frame.validate(); + }); + + robot.waitForIdle(); + + EventQueue.invokeAndWait(() -> { + actualDimension = frame.getSize(); + }); + + if (!actualDimension.equals(dimension)) { + throw new RuntimeException("Test Failed\n" + + "expected dimension:(" + dimension.width + "," + dimension.height +")\n" + + "actual dimension:(" + actualDimension.width + "," + actualDimension.height + ")"); + } + } finally { + EventQueue.invokeAndWait(() -> frame.dispose()); + } + } + + public static void main(String[] args) throws Exception { + doTest(); + } +} + diff --git a/test/jdk/java/awt/FullScreen/NoResizeEventOnDMChangeTest/NoResizeEventOnDMChangeTest.java b/test/jdk/java/awt/FullScreen/NoResizeEventOnDMChangeTest/NoResizeEventOnDMChangeTest.java index a6e635e08ced661030bbc6a0752d53833c50f50f..455ad2f2b0a3eb5d9e1f3145226cd23559a4ef6c 100644 --- a/test/jdk/java/awt/FullScreen/NoResizeEventOnDMChangeTest/NoResizeEventOnDMChangeTest.java +++ b/test/jdk/java/awt/FullScreen/NoResizeEventOnDMChangeTest/NoResizeEventOnDMChangeTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 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 @@ -26,7 +26,6 @@ * @bug 6646411 * @summary Tests that full screen window and its children receive resize event when display mode changes - * @author Dmitri.Trembovetski@sun.com: area=Graphics * @run main/othervm NoResizeEventOnDMChangeTest * @run main/othervm -Dsun.java2d.d3d=false NoResizeEventOnDMChangeTest */ @@ -151,9 +150,22 @@ public class NoResizeEventOnDMChangeTest { System.err.printf("----------- Setting DM %dx%d:\n", dm1.getWidth(), dm1.getHeight()); try { + Frame f = fsWin instanceof Frame ? (Frame) fsWin : (Frame) fsWin.getOwner(); + DisplayMode oldMode = f.getGraphicsConfiguration().getDevice().getDisplayMode(); gd.setDisplayMode(dm1); - r1.incDmChanges(); - r2.incDmChanges(); + sleep(2000); + // Check if setting new display mode actually results in frame being + // placed onto display with different resolution. + DisplayMode newMode = f.getGraphicsConfiguration().getDevice().getDisplayMode(); + if (oldMode.getWidth() != newMode.getWidth() + || oldMode.getHeight() != newMode.getHeight()) { + r1.incDmChanges(); + r2.incDmChanges(); + } else { + System.out.println("Skipping this iteration. Details:"); + System.out.println("Requested device = " + gd); + System.out.println("Actual device = " + f.getGraphicsConfiguration().getDevice()); + } } catch (IllegalArgumentException iae) {} } }); @@ -166,6 +178,7 @@ public class NoResizeEventOnDMChangeTest { fsWin.removeComponentListener(r1); c.removeComponentListener(r2); } + try { EventQueue.invokeAndWait(new Runnable() { public void run() { @@ -191,10 +204,14 @@ public class NoResizeEventOnDMChangeTest { } static void sleep(long ms) { - try { - Thread.sleep(ms); - } catch (InterruptedException ex) {} + long targetTime = System.currentTimeMillis() + ms; + do { + try { + Thread.sleep(targetTime - System.currentTimeMillis()); + } catch (InterruptedException ex) {} + } while (System.currentTimeMillis() < targetTime); } + static class ResizeEventChecker extends ComponentAdapter { int dmChanges; int resizes; diff --git a/test/jdk/java/awt/Graphics/TextAAHintsTest.java b/test/jdk/java/awt/Graphics/TextAAHintsTest.java index 46fa6c28c9b20e3c84ae93a6f9bf84e6d8708b72..15fd5a63464d5fc08ee8881e286faa7ef01591c0 100644 --- a/test/jdk/java/awt/Graphics/TextAAHintsTest.java +++ b/test/jdk/java/awt/Graphics/TextAAHintsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 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 @@ -21,21 +21,44 @@ * questions. */ -/** +/* * @test * @bug 6263951 * @summary Text should be B&W, grayscale, and LCD. - * @run main/manual=yesno TextAAHintsTest + * @requires (os.family != "mac") + * @run main/manual TextAAHintsTest */ -import java.awt.*; -import java.awt.geom.*; -import java.awt.image.*; + +import java.awt.AWTException; +import java.awt.BorderLayout; +import java.awt.Button; +import java.awt.Color; +import java.awt.Component; +import java.awt.Dialog; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.ImageCapabilities; +import java.awt.Panel; +import java.awt.RenderingHints; +import java.awt.TextArea; +import java.awt.image.BufferedImage; +import java.awt.image.VolatileImage; +import java.lang.reflect.InvocationTargetException; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; public class TextAAHintsTest extends Component { - String black = "This text should be solid black"; - String gray = "This text should be gray scale anti-aliased"; - String lcd = "This text should be LCD sub-pixel text (coloured)."; + private static final String black = "This text should be solid black"; + private static final String gray = "This text should be gray scale anti-aliased"; + private static final String lcd = "This text should be LCD sub-pixel text (coloured)."; + private static final CountDownLatch countDownLatch = new CountDownLatch(1); + private static volatile String failureReason; + private static volatile boolean testPassed = false; + private static Frame frame; public void paint(Graphics g) { @@ -63,28 +86,24 @@ public class TextAAHintsTest extends Component { RenderingHints.VALUE_TEXT_ANTIALIAS_OFF); g2d.drawString(black, 10, 20); - g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, - RenderingHints.VALUE_TEXT_ANTIALIAS_GASP); - g2d.drawString(black, 10, 35); - g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_DEFAULT); - g2d.drawString(gray, 10, 50); + g2d.drawString(gray, 10, 35); g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); - g2d.drawString(gray, 10, 65); + g2d.drawString(gray, 10, 50); /* For visual comparison, render grayscale with graphics AA off */ g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF); - g2d.drawString(gray, 10, 80); + g2d.drawString(gray, 10, 65); g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB); - g2d.drawString(lcd, 10, 95); + g2d.drawString(lcd, 10, 80); } public void bufferedImageText(Graphics g) { @@ -139,11 +158,80 @@ public class TextAAHintsTest extends Component { return new Dimension(500,300); } - public static void main(String[] args) throws Exception { + public static void createTestUI() { + frame = new Frame("Composite and Text Test"); + TextAAHintsTest textAAHintsTestObject = new TextAAHintsTest(); + frame.add(textAAHintsTestObject, BorderLayout.NORTH); + + String instructions = """ + Note: Texts are rendered with different TEXT_ANTIALIASING & + VALUE_TEXT_ANTIALIAS. Text should be B&W, grayscale, and LCD. + Note: The results may be visually the same. + 1. Verify that first set of text are rendered correctly. + 2. Second set of text are created using BufferedImage of the first text. + 3. Third set of text are created using VolatileImage of the first text. + """; + TextArea instructionTextArea = new TextArea(instructions, 8, 50); + instructionTextArea.setEditable(false); + frame.add(instructionTextArea, BorderLayout.CENTER); + + Panel controlPanel = new Panel(); + Button passButton = new Button("Pass"); + passButton.addActionListener(e -> { + testPassed = true; + countDownLatch.countDown(); + frame.dispose(); + }); + Button failButton = new Button("Fail"); + failButton.addActionListener(e -> { + getFailureReason(); + testPassed = false; + countDownLatch.countDown(); + frame.dispose(); + }); + controlPanel.add(passButton); + controlPanel.add(failButton); + frame.add(controlPanel, BorderLayout.SOUTH); + frame.pack(); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } + + public static void getFailureReason() { + // Show dialog to read why the testcase was failed and append the + // testcase failure reason to the output + final Dialog dialog = new Dialog(frame, "TestCase" + + " failure reason", true); + TextArea textArea = new TextArea("", 5, 60, TextArea.SCROLLBARS_BOTH); + dialog.add(textArea, BorderLayout.CENTER); + + Button okButton = new Button("OK"); + okButton.addActionListener(e1 -> { + failureReason = textArea.getText(); + dialog.dispose(); + }); + Panel ctlPanel = new Panel(); + ctlPanel.add(okButton); + dialog.add(ctlPanel, BorderLayout.SOUTH); + dialog.setLocationRelativeTo(null); + dialog.pack(); + dialog.setVisible(true); + } + + public static void main(String[] args) throws InterruptedException, InvocationTargetException { + EventQueue.invokeAndWait(TextAAHintsTest::createTestUI); + if (!countDownLatch.await(2, TimeUnit.MINUTES)) { + EventQueue.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + throw new RuntimeException("Timeout : No action was taken on the test."); + } - Frame f = new Frame("Composite and Text Test"); - f.add(new TextAAHintsTest(), BorderLayout.CENTER); - f.pack(); - f.setVisible(true); + if (!testPassed) { + throw new RuntimeException("Test failed : Reason : " + failureReason); + } } } + diff --git a/test/jdk/java/awt/Graphics2D/CopyAreaOOB.java b/test/jdk/java/awt/Graphics2D/CopyAreaOOB.java index d4f9533f09680af0411f14119c4cc5242926313f..8d218d9f18919d8e3f812b63ff79261b85056f9a 100644 --- a/test/jdk/java/awt/Graphics2D/CopyAreaOOB.java +++ b/test/jdk/java/awt/Graphics2D/CopyAreaOOB.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -36,15 +36,9 @@ import java.awt.image.*; public class CopyAreaOOB extends Canvas { - private static boolean done; + private static Robot robot = null; public void paint(Graphics g) { - synchronized (this) { - if (done) { - return; - } - } - int w = getWidth(); int h = getHeight(); @@ -64,10 +58,23 @@ public class CopyAreaOOB extends Canvas { Toolkit.getDefaultToolkit().sync(); - synchronized (this) { - done = true; - notifyAll(); + BufferedImage capture = null; + try { + Thread.sleep(500); + if (robot == null) robot = new Robot(); + Point pt1 = getLocationOnScreen(); + Rectangle rect = new Rectangle(pt1.x, pt1.y, 400, 400); + capture = robot.createScreenCapture(rect); + } catch (Exception e) { + throw new RuntimeException("Problems handling Robot"); } + // Test pixels + testRegion(capture, "green", 0, 0, 400, 10, 0xff00ff00); + testRegion(capture, "original red", 0, 10, 50, 400, 0xffff0000); + testRegion(capture, "background", 50, 10, 60, 400, 0xff000000); + testRegion(capture, "in-between", 60, 10, 110, 20, 0xff000000); + testRegion(capture, "copied red", 60, 20, 110, 400, 0xffff0000); + testRegion(capture, "background", 110, 10, 400, 400, 0xff000000); } public Dimension getPreferredSize() { @@ -105,42 +112,11 @@ public class CopyAreaOOB extends Canvas { frame.setLocationRelativeTo(null); frame.setVisible(true); - // Wait until the component's been painted - synchronized (test) { - while (!done) { - try { - test.wait(); - } catch (InterruptedException e) { - throw new RuntimeException("Failed: Interrupted"); - } - } - } - try { - Thread.sleep(2000); + Thread.sleep(3000); } catch (InterruptedException ex) {} - - // Grab the screen region - BufferedImage capture = null; - try { - Robot robot = new Robot(); - Point pt1 = test.getLocationOnScreen(); - Rectangle rect = new Rectangle(pt1.x, pt1.y, 400, 400); - capture = robot.createScreenCapture(rect); - } catch (Exception e) { - throw new RuntimeException("Problems creating Robot"); - } finally { - if (!show) { - frame.dispose(); - } + if (!show) { + frame.dispose(); } - - // Test pixels - testRegion(capture, "green", 0, 0, 400, 10, 0xff00ff00); - testRegion(capture, "original red", 0, 10, 50, 400, 0xffff0000); - testRegion(capture, "background", 50, 10, 60, 400, 0xff000000); - testRegion(capture, "in-between", 60, 10, 110, 20, 0xff000000); - testRegion(capture, "copied red", 60, 20, 110, 400, 0xffff0000); - testRegion(capture, "background", 110, 10, 400, 400, 0xff000000); } } diff --git a/test/jdk/java/awt/Mouse/MouseModifiersUnitTest/ExtraButtonDrag.java b/test/jdk/java/awt/Mouse/MouseModifiersUnitTest/ExtraButtonDrag.java index 29b90c9d4302dd2d22c57c2637b3c0efbe881cd2..3f8eeb17b38f68c9cdc1673019a2487993c9af6e 100644 --- a/test/jdk/java/awt/Mouse/MouseModifiersUnitTest/ExtraButtonDrag.java +++ b/test/jdk/java/awt/Mouse/MouseModifiersUnitTest/ExtraButtonDrag.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 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 @@ -105,7 +105,7 @@ public class ExtraButtonDrag extends Frame { //XToolkit: extra buttons should report MOVED events only //WToolkit: extra buttons should report DRAGGED events only if (i > 2){ //extra buttons only - if (tk.equals("sun.awt.X11.XToolkit") || tk.equals("sun.awt.motif.MToolkit")) { + if (tk.equals("sun.awt.X11.XToolkit")) { if (!moved || dragged) { throw new RuntimeException("Test failed."+ tk +" Button = " +(i+1) + " moved = "+moved +" : dragged = " +dragged); } @@ -152,4 +152,3 @@ public class ExtraButtonDrag extends Frame { } } - diff --git a/test/jdk/java/awt/PrintJob/PrintArcTest/PrintArcTest.java b/test/jdk/java/awt/PrintJob/PrintArcTest/PrintArcTest.java index 15cf121607ce81e3f169a4aba19efcb6b32c8e7d..7e9023b1afcf09e67df27c7360ae03e5ec784f9c 100644 --- a/test/jdk/java/awt/PrintJob/PrintArcTest/PrintArcTest.java +++ b/test/jdk/java/awt/PrintJob/PrintArcTest/PrintArcTest.java @@ -65,7 +65,7 @@ public class PrintArcTest extends Panel implements ActionListener { } private Frame getFrame() { - Container cont = getParent();; + Container cont = getParent(); while ( !(cont instanceof Frame ) ) { cont = cont.getParent(); diff --git a/test/jdk/java/awt/Robot/AcceptExtraMouseButtons/AcceptExtraMouseButtons.java b/test/jdk/java/awt/Robot/AcceptExtraMouseButtons/AcceptExtraMouseButtons.java index 3ab3ba3ff877ec30044fbb9bc74a83261772ba8e..ee83a328f0fc2aad8ec5aaa46dc16736517e2846 100644 --- a/test/jdk/java/awt/Robot/AcceptExtraMouseButtons/AcceptExtraMouseButtons.java +++ b/test/jdk/java/awt/Robot/AcceptExtraMouseButtons/AcceptExtraMouseButtons.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 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 @@ -57,7 +57,7 @@ public class AcceptExtraMouseButtons extends Frame { //MouseInfo.getNumberOfButtons() reports two more buttons on XToolkit //as they reserved for wheel (both directions). - if (tk.equals("sun.awt.X11.XToolkit") || tk.equals("sun.awt.motif.MToolkit")) { + if (tk.equals("sun.awt.X11.XToolkit")) { buttonsNum = buttonsNum - 2; } System.out.println("Number Of Buttons = "+ buttonsNum); diff --git a/test/jdk/java/awt/Robot/CheckCommonColors/CheckCommonColors.java b/test/jdk/java/awt/Robot/CheckCommonColors/CheckCommonColors.java index 57419b0ac5aa9d81a84d84afb9c219b229c8761f..55d9b4358af85171204b66590d01928984415e93 100644 --- a/test/jdk/java/awt/Robot/CheckCommonColors/CheckCommonColors.java +++ b/test/jdk/java/awt/Robot/CheckCommonColors/CheckCommonColors.java @@ -42,6 +42,8 @@ import javax.imageio.ImageIO; * @key headful * @bug 8215105 8211999 * @summary tests that Robot can capture the common colors without artifacts + * @run main/othervm CheckCommonColors + * @run main/othervm -Xcheck:jni CheckCommonColors */ public final class CheckCommonColors { diff --git a/test/jdk/java/awt/Robot/HiDPIScreenCapture/HiDPIRobotScreenCaptureTest.java b/test/jdk/java/awt/Robot/HiDPIScreenCapture/HiDPIRobotScreenCaptureTest.java index 85378f00ad6765d238fb3ffd742bbdf4cd6b02ec..db34b1714b533000f8a0077d65be09643657b92c 100644 --- a/test/jdk/java/awt/Robot/HiDPIScreenCapture/HiDPIRobotScreenCaptureTest.java +++ b/test/jdk/java/awt/Robot/HiDPIScreenCapture/HiDPIRobotScreenCaptureTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -27,20 +27,26 @@ import java.awt.Color; import java.awt.Frame; import java.awt.Graphics; import java.awt.Panel; +import java.awt.Point; import java.awt.Rectangle; import java.awt.Robot; import java.awt.image.BufferedImage; import javax.swing.UIManager; +import javax.imageio.ImageIO; +import java.io.File; +import java.io.IOException; /** * @test * @key headful - * @bug 8073320 - * @summary Windows HiDPI support + * @bug 8073320 8280861 + * @summary Linux and Windows HiDPI support * @author Alexander Scherbatiy * @requires (os.family == "linux" | os.family == "windows") * @run main/othervm -Dsun.java2d.win.uiScaleX=3 -Dsun.java2d.win.uiScaleY=2 * HiDPIRobotScreenCaptureTest + * @run main/othervm -Dsun.java2d.uiScale=1 HiDPIRobotScreenCaptureTest + * @run main/othervm -Dsun.java2d.uiScale=2 HiDPIRobotScreenCaptureTest */ public class HiDPIRobotScreenCaptureTest { @@ -60,7 +66,14 @@ public class HiDPIRobotScreenCaptureTest { } Frame frame = new Frame(); - frame.setBounds(40, 30, 400, 300); + // Position the frame on prime number coordinates (mind OFFSET) + // to avoid them being multiple of the desktop scale; this tests Linux + // color picker better. + // Also, the position should be far enough from the top left + // corner of the screen to reduce the chance of being repositioned + // by the system because that area's occupied by the global + // menu bar and such. + frame.setBounds(78, 92, 100, 100); frame.setUndecorated(true); Panel panel = new Panel(new BorderLayout()); @@ -86,11 +99,12 @@ public class HiDPIRobotScreenCaptureTest { frame.setVisible(true); Robot robot = new Robot(); robot.waitForIdle(); - Thread.sleep(200); + robot.delay(500); Rectangle rect = canvas.getBounds(); rect.setLocation(canvas.getLocationOnScreen()); + System.out.println("Creating screen capture of " + rect); BufferedImage image = robot.createScreenCapture(rect); frame.dispose(); @@ -101,20 +115,38 @@ public class HiDPIRobotScreenCaptureTest { throw new RuntimeException("Wrong image size!"); } - if (image.getRGB(w / 4, h / 4) != COLORS[0].getRGB()) { - throw new RuntimeException("Wrong image color!"); - } - - if (image.getRGB(3 * w / 4, h / 4) != COLORS[1].getRGB()) { - throw new RuntimeException("Wrong image color!"); - } + checkRectColor(image, new Rectangle(0, 0, w / 2, h / 2), COLORS[0]); + checkRectColor(image, new Rectangle(w / 2, 0, w / 2, h / 2), COLORS[1]); + checkRectColor(image, new Rectangle(0, h / 2, w / 2, h / 2), COLORS[2]); + checkRectColor(image, new Rectangle(w / 2, h / 2, w / 2, h / 2), COLORS[3]); + } - if (image.getRGB(w / 4, 3 * h / 4) != COLORS[2].getRGB()) { - throw new RuntimeException("Wrong image color!"); - } + private static final int OFFSET = 5; + static void checkRectColor(BufferedImage image, Rectangle rect, Color expectedColor) { + System.out.println("Checking rectangle " + rect + " to have color " + expectedColor); + final Point[] pointsToCheck = new Point[] { + new Point(rect.x + OFFSET, rect.y + OFFSET), // top left corner + new Point(rect.x + rect.width - OFFSET, rect.y + OFFSET), // top right corner + new Point(rect.x + rect.width / 2, rect.y + rect.height / 2), // center + new Point(rect.x + OFFSET, rect.y + rect.height - OFFSET), // bottom left corner + new Point(rect.x + rect.width - OFFSET, rect.y + rect.height - OFFSET) // bottom right corner + }; - if (image.getRGB(3 * w / 4, 3 * h / 4) != COLORS[3].getRGB()) { - throw new RuntimeException("Wrong image color!"); + for (final var point : pointsToCheck) { + System.out.print("Checking color at " + point + " to be equal to " + expectedColor); + final int actualColor = image.getRGB(point.x, point.y); + if (actualColor != expectedColor.getRGB()) { + System.out.println("... Mismatch: found " + new Color(actualColor) + " instead. Check image.png."); + try { + ImageIO.write(image, "png", new File("image.png")); + } catch(IOException e) { + System.out.println("failed to save image.png."); + e.printStackTrace(); + } + throw new RuntimeException("Wrong image color!"); + } else { + System.out.println("... OK"); + } } } -} \ No newline at end of file +} diff --git a/test/jdk/java/awt/Robot/HiDPIScreenCapture/ScreenCaptureGtkTest.java b/test/jdk/java/awt/Robot/HiDPIScreenCapture/ScreenCaptureGtkTest.java new file mode 100644 index 0000000000000000000000000000000000000000..6ba5ec18e0a90519496fa9ac2377c9afda0b3c4d --- /dev/null +++ b/test/jdk/java/awt/Robot/HiDPIScreenCapture/ScreenCaptureGtkTest.java @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, JetBrains s.r.o.. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.BorderLayout; +import java.awt.Canvas; +import java.awt.Color; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Panel; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.image.BufferedImage; +import javax.swing.UIManager; +import javax.imageio.ImageIO; +import java.io.File; +import java.io.IOException; + + +/** + * @test + * @key headful + * @bug 8280861 + * @summary Verifies Robot screen capture capabilities with different + * Gtk backends and presence of UI scaling + * @requires os.family == "linux" + * @run main/othervm -Djdk.gtk.version=2 -Dsun.java2d.uiScale=1 ScreenCaptureGtkTest + * @run main/othervm -Djdk.gtk.version=3 -Dsun.java2d.uiScale=1 ScreenCaptureGtkTest + */ + +public class ScreenCaptureGtkTest { + private static final Color[] COLORS = { + Color.GREEN, Color.BLUE, Color.ORANGE, Color.RED}; + + public static void main(String[] args) throws Exception { + final int topOffset = 50; + final int leftOffset = 50; + + Frame frame = new Frame(); + // Position the frame such that color picker will work with + // prime number coordinates (mind the offset) to avoid them being + // multiple of the desktop scale; this tests Linux color picker better. + // Also, the position should be far enough from the top left + // corner of the screen to reduce the chance of being repositioned + // by the system because that area's occupied by the global + // menu bar and such. + frame.setBounds(89, 99, 100, 100); + frame.setUndecorated(true); + + Panel panel = new Panel(new BorderLayout()); + Canvas canvas = new Canvas() { + @Override + public void paint(Graphics g) { + super.paint(g); + int w = getWidth(); + int h = getHeight(); + g.setColor(COLORS[0]); + g.fillRect(0, 0, w, h); + // Paint several distinct pixels next to one another + // in order to test color picker's precision. + for (int i = 1; i < COLORS.length; i++) { + g.setColor(COLORS[i]); + g.fillRect(leftOffset + i, topOffset, 1, 1); + } + } + }; + + panel.add(canvas); + frame.add(panel); + frame.setVisible(true); + Robot robot = new Robot(); + robot.waitForIdle(); + robot.delay(500); + + captureImageOf(frame, robot); + + final Point screenLocation = frame.getLocationOnScreen(); + try { + checkPixelColors(robot, screenLocation.x + leftOffset, + screenLocation.y + topOffset); + } finally { + robot.delay(100); + frame.dispose(); + } + } + + static void checkPixelColors(Robot robot, int x, int y) { + for (int i = 0; i < COLORS.length; i++) { + final Color actualColor = robot.getPixelColor(x + i, y); + System.out.print("Checking color at " + (x + i) + ", " + y + " to be equal to " + COLORS[i]); + if (!actualColor.equals(COLORS[i])) { + System.out.println("... Mismatch: found " + actualColor + " instead"); + saveImage(); + throw new RuntimeException("Wrong screen pixel color"); + + } else { + System.out.println("... OK"); + } + } + } + + private static BufferedImage image; + + static void captureImageOf(Frame frame, Robot robot) { + Rectangle rect = frame.getBounds(); + rect.setLocation(frame.getLocationOnScreen()); + + System.out.println("Creating screen capture of " + rect); + image = robot.createScreenCapture(rect); + } + + static void saveImage() { + System.out.println("Check image.png"); + try { + ImageIO.write(image, "png", new File("image.png")); + } catch(IOException e) { + System.out.println("failed to save image.png."); + e.printStackTrace(); + } + } +} diff --git a/test/jdk/java/awt/Scrollbar/AquaLFScrollbarTest/ScrollBarBorderTest.java b/test/jdk/java/awt/Scrollbar/AquaLFScrollbarTest/ScrollBarBorderTest.java new file mode 100644 index 0000000000000000000000000000000000000000..9fbea551b832fee9758ff768bc1ec8df52724f02 --- /dev/null +++ b/test/jdk/java/awt/Scrollbar/AquaLFScrollbarTest/ScrollBarBorderTest.java @@ -0,0 +1,194 @@ +/* + * 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. + */ + +import java.awt.Color; +import java.awt.Component; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Insets; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; +import javax.imageio.ImageIO; +import javax.swing.JScrollBar; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import javax.swing.UnsupportedLookAndFeelException; +import javax.swing.border.Border; + +import static java.awt.image.BufferedImage.TYPE_INT_ARGB; + +/* + * @test + * @bug 8190264 + * @summary JScrollBar ignores its border when using macOS Mac OS X Aqua look and feel + * @run main ScrollBarBorderTest + */ +public class ScrollBarBorderTest { + private static JScrollBar scrollBar; + public static final int BORDER_WIDTH = 150; + public static final int WIDTH = BORDER_WIDTH + 200; + public static final int HEIGHT = 20; + + public static void main(String[] args) throws Exception { + for (UIManager.LookAndFeelInfo laf : UIManager.getInstalledLookAndFeels()) { + SwingUtilities.invokeAndWait(() -> setLookAndFeel(laf)); + SwingUtilities.invokeAndWait(ScrollBarBorderTest::testHorizontal); + SwingUtilities.invokeAndWait(ScrollBarBorderTest::testVertical); + } + } + + public static void testHorizontal() { + // create scroll bar + scrollBar = new JScrollBar(JScrollBar.HORIZONTAL); + scrollBar.setSize(WIDTH, HEIGHT); + scrollBar.setBorder(new HorizontalCustomBorder()); + + // paint image with thumb set to default value + BufferedImage image1 = new BufferedImage(WIDTH, HEIGHT, TYPE_INT_ARGB); + Graphics2D graphics2D = image1.createGraphics(); + scrollBar.paint(graphics2D); + graphics2D.dispose(); + + // paint image with thumb set to max value + scrollBar.setValue(Integer.MAX_VALUE); + BufferedImage image2 = new BufferedImage(WIDTH, HEIGHT, TYPE_INT_ARGB); + Graphics2D graphics2D2 = image2.createGraphics(); + scrollBar.paint(graphics2D2); + graphics2D2.dispose(); + + // check border for thumb + for (int x = WIDTH - BORDER_WIDTH; x < WIDTH; x++) { + for (int y = 0; y < HEIGHT; y++) { + int c1 = image1.getRGB(x, y); + int c2 = image2.getRGB(x, y); + if (c1 != c2) { + System.out.println(x + " " + y + " " + "Color1: " + + Integer.toHexString(c1)); + System.out.println(x + " " + y + " " + "Color2: " + + Integer.toHexString(c2)); + saveImage(image1, "himage1.png"); + saveImage(image2, "himage2.png"); + throw new RuntimeException("Horizontal border has a thumb in it"); + } + } + } + } + + public static void testVertical() { + // create scroll bar + scrollBar = new JScrollBar(JScrollBar.VERTICAL); + scrollBar.setSize(HEIGHT, WIDTH); + scrollBar.setBorder(new VerticalCustomBorder()); + + // paint image with thumb set to 0 + scrollBar.setValue(0); + BufferedImage image1 = new BufferedImage(HEIGHT, WIDTH, TYPE_INT_ARGB); + Graphics2D graphics2D = image1.createGraphics(); + scrollBar.paint(graphics2D); + graphics2D.dispose(); + + // paint image with thumb set to max value + scrollBar.setValue(Integer.MAX_VALUE); + BufferedImage image2 = new BufferedImage(HEIGHT, WIDTH, TYPE_INT_ARGB); + Graphics2D graphics2D2 = image2.createGraphics(); + scrollBar.paint(graphics2D2); + graphics2D2.dispose(); + + // check border for thumb + for (int y = WIDTH - BORDER_WIDTH; y < WIDTH; y++) { + for (int x = 0; x < HEIGHT; x++) { + int c1 = image1.getRGB(x, y); + int c2 = image2.getRGB(x, y); + if (c1 != c2) { + System.out.println(x + " " + y + " " + "Color1: " + + Integer.toHexString(c1)); + System.out.println(x + " " + y + " " + "Color2: " + + Integer.toHexString(c2)); + saveImage(image1, "vimage1.png"); + saveImage(image2, "vimage2.png"); + throw new RuntimeException("Vertical border has a thumb in it"); + } + } + } + } + + private static void setLookAndFeel(UIManager.LookAndFeelInfo laf) { + try { + UIManager.setLookAndFeel(laf.getClassName()); + System.out.println(laf.getName()); + } catch (UnsupportedLookAndFeelException ignored){ + System.out.println("Unsupported LookAndFeel: " + laf.getClassName()); + } catch (ClassNotFoundException | InstantiationException | + IllegalAccessException e) { + throw new RuntimeException(e); + } + } + + private static void saveImage(BufferedImage image, String filename) { + try { + ImageIO.write(image, "png", new File(filename)); + } catch (IOException e) { + // Don't propagate the exception + e.printStackTrace(); + } + } + + // custom border + private static class HorizontalCustomBorder implements Border { + @Override + public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) { + g.setColor(new Color(255, 0, 0, 100)); + g.fillRect(width - BORDER_WIDTH, y, width, height); + } + + @Override + public Insets getBorderInsets(Component c) { + return new Insets(0, 0, 0, BORDER_WIDTH); + } + + @Override + public boolean isBorderOpaque() { + return true; + } + } + + // custom border + private static class VerticalCustomBorder implements Border { + @Override + public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) { + g.setColor(new Color(255, 0, 0, 100)); + g.fillRect(x, height - BORDER_WIDTH, width, height); + } + + @Override + public Insets getBorderInsets(Component c) { + return new Insets(0, 0, BORDER_WIDTH, 0); + } + + @Override + public boolean isBorderOpaque() { + return true; + } + } +} diff --git a/test/jdk/java/awt/SplashScreen/GenerateTestImage.java b/test/jdk/java/awt/SplashScreen/GenerateTestImage.java index 93def3347568f7b6ce7042417ca25eaf3d959434..ddde69ca295da3acd5c560a1d32bab7d42ce30a7 100644 --- a/test/jdk/java/awt/SplashScreen/GenerateTestImage.java +++ b/test/jdk/java/awt/SplashScreen/GenerateTestImage.java @@ -43,7 +43,7 @@ public class GenerateTestImage { Graphics2D graphics2D = image.createGraphics(); graphics2D.setColor(Color.red); graphics2D.fillOval(0, 0, IMAGE_SIZE, IMAGE_SIZE); - graphics2D.dispose();; + graphics2D.dispose(); ImageIO.write(image, "png", file); } diff --git a/test/jdk/java/awt/Window/GrabSequence/GrabSequence.java b/test/jdk/java/awt/Window/GrabSequence/GrabSequence.java index 686cae28010639243386695df2aa55136f25bc36..da419e10ef1d5c7ab2ba4cf6a54cc5ccffcc2170 100644 --- a/test/jdk/java/awt/Window/GrabSequence/GrabSequence.java +++ b/test/jdk/java/awt/Window/GrabSequence/GrabSequence.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -40,11 +40,6 @@ public class GrabSequence { private static void init() { - String toolkit = Toolkit.getDefaultToolkit().getClass().getName(); - if ( toolkit.equals("sun.awt.motif.MToolkit")){ - System.out.println("This test is for XToolkit and WToolkit only. Now using " + toolkit + ". Automatically passed."); - return; - } Frame frame = new Frame("Frame"); frame.setBackground(Color.green); frame.setForeground(Color.green); diff --git a/test/jdk/java/awt/Window/TranslucentShapedFrameTest/TranslucentShapedFrameTest.form b/test/jdk/java/awt/Window/TranslucentShapedFrameTest/TranslucentShapedFrameTest.form index 4291e0eeaac0f55d3bc8da1c10531ab47e5c8c6b..6735391ad3810cd16aaaa7ef4323929416f86545 100644 --- a/test/jdk/java/awt/Window/TranslucentShapedFrameTest/TranslucentShapedFrameTest.form +++ b/test/jdk/java/awt/Window/TranslucentShapedFrameTest/TranslucentShapedFrameTest.form @@ -158,7 +158,7 @@ <Properties> <Property name="columns" type="int" value="20"/> <Property name="rows" type="int" value="5"/> - <Property name="text" type="java.lang.String" value="Create translucent and/or shaped, or non-opaque frame. Make sure it behaves correctly (no artifacts left on the screen when dragging - if dragging is possible). Click "Passed" if the test behaves correctly, "Falied" otherwise."/> + <Property name="text" type="java.lang.String" value="Create translucent and/or shaped, or non-opaque frame. Make sure it behaves correctly (no artifacts left on the screen when dragging - if dragging is possible). Click "Passed" if the test behaves correctly, "Failed" otherwise."/> </Properties> </Component> </SubComponents> diff --git a/test/jdk/java/awt/Window/TranslucentShapedFrameTest/TranslucentShapedFrameTest.java b/test/jdk/java/awt/Window/TranslucentShapedFrameTest/TranslucentShapedFrameTest.java index bdcf99c3a3c0dcd26927284bd676c3bd16a8a555..b87c44d907859dc8fea727ea7f2ef06c1b9c0118 100644 --- a/test/jdk/java/awt/Window/TranslucentShapedFrameTest/TranslucentShapedFrameTest.java +++ b/test/jdk/java/awt/Window/TranslucentShapedFrameTest/TranslucentShapedFrameTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 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 @@ -122,7 +122,7 @@ public class TranslucentShapedFrameTest extends javax.swing.JFrame { jTextArea1.setColumns(20); jTextArea1.setRows(5); - jTextArea1.setText("Create translucent and/or shaped, or\nnon-opaque frame. Make sure it behaves\ncorrectly (no artifacts left on the screen\nwhen dragging - if dragging is possible).\nClick \"Passed\" if the test behaves correctly,\n\"Falied\" otherwise."); + jTextArea1.setText("Create translucent and/or shaped, or\nnon-opaque frame. Make sure it behaves\ncorrectly (no artifacts left on the screen\nwhen dragging - if dragging is possible).\nClick \"Passed\" if the test behaves correctly,\n\"Failed\" otherwise."); jScrollPane1.setViewportView(jTextArea1); jLabel2.setText("Instructions:"); diff --git a/test/jdk/java/awt/Window/WindowResizingOnDPIChanging/WindowResizingOnMovingToAnotherDisplay.java b/test/jdk/java/awt/Window/WindowResizingOnDPIChanging/WindowResizingOnMovingToAnotherDisplay.java index 7c0035f4274d994f1a7778977e8f58e1dc3e47d1..7acf4aa1b61e44ba3b53bb3229c44f44b4d2b96e 100644 --- a/test/jdk/java/awt/Window/WindowResizingOnDPIChanging/WindowResizingOnMovingToAnotherDisplay.java +++ b/test/jdk/java/awt/Window/WindowResizingOnDPIChanging/WindowResizingOnMovingToAnotherDisplay.java @@ -53,7 +53,7 @@ import javax.swing.JTextArea; import javax.swing.SwingUtilities; /* @test - * @bug 8147440 8147016 + * @bug 8147440 8147016 8270874 * @summary HiDPI (Windows): Swing components have incorrect sizes after * changing display resolution * @run main/manual/othervm WindowResizingOnMovingToAnotherDisplay diff --git a/test/jdk/java/awt/a11y/AccessibleActionsTest.java b/test/jdk/java/awt/a11y/AccessibleActionsTest.java new file mode 100644 index 0000000000000000000000000000000000000000..b8f6e5d28f9b8c2ce4df3fef1479f907c2f7631b --- /dev/null +++ b/test/jdk/java/awt/a11y/AccessibleActionsTest.java @@ -0,0 +1,183 @@ +/* + * Copyright (c) 2021, 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. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8281338 + * @summary Test for an element that has more than one Accessibility Action + * @author Artem.Semenov@jetbrains.com + * @run main/manual AccessibleActionsTest + * @requires (os.family == "mac") + */ + +import javax.accessibility.Accessible; +import javax.accessibility.AccessibleAction; +import javax.accessibility.AccessibleContext; +import javax.swing.*; +import javax.swing.tree.TreeModel; +import javax.swing.tree.TreePath; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.Hashtable; +import java.util.concurrent.CountDownLatch; + +public class AccessibleActionsTest extends AccessibleComponentTest { + + @Override + public CountDownLatch createCountDownLatch() { + return new CountDownLatch(1); + } + + void createTest() { + INSTRUCTIONS = "INSTRUCTIONS:\n" + + "Check a11y actions.\n\n" + + "Turn screen reader on, and Tab to the label.\n\n" + + "Perform the VO action \"Press\" (VO+space)\n" + + "Perform the VO action \"Show menu\" (VO+m)\n\n" + + "If after the first action the text of the label has changed, and after the second action the menu appears tab further and press PASS, otherwise press FAIL."; + + exceptionString = "AccessibleAction test failed!"; + super.createUI(new AccessibleActionsTestFrame(), "AccessibleActionsTest"); + } + + void createTree() { + INSTRUCTIONS = "INSTRUCTIONS:\n" + + "Check a11y actions.\n\n" + + "Turn screen reader on, and Tab to the label.\n\n" + + "Perform the VO action \"Press\" (VO+space) on tree nodes\n\n" + + "If after press the tree node is expanded tab further and press PASS, otherwise press FAIL."; + + String root = "Root"; + String[] nodes = new String[] {"One node", "Two node"}; + String[][] leafs = new String[][]{{"leaf 1.1", "leaf 1.2", "leaf 1.3", "leaf 1.4"}, + {"leaf 2.1", "leaf 2.2", "leaf 2.3", "leaf 2.4"}}; + + Hashtable<String, String[]> data = new Hashtable<String, String[]>(); + for (int i = 0; i < nodes.length; i++) { + data.put(nodes[i], leafs[i]); + } + + JTree tree = new JTree(data); + tree.setRootVisible(true); + + JPanel panel = new JPanel(); + panel.setLayout(new FlowLayout()); + JScrollPane scrollPane = new JScrollPane(tree); + panel.add(scrollPane); + panel.setFocusable(false); + + exceptionString = "AccessibleAction test failed!"; + super.createUI(panel, "AccessibleActionsTest"); + } + + public static void main(String[] args) throws Exception { + AccessibleActionsTest test = new AccessibleActionsTest(); + + countDownLatch = test.createCountDownLatch(); + SwingUtilities.invokeLater(test::createTest); + countDownLatch.await(); + + if (!testResult) { + throw new RuntimeException(a11yTest.exceptionString); + } + + countDownLatch = test.createCountDownLatch(); + SwingUtilities.invokeLater(test::createTree); + countDownLatch.await(); + + if (!testResult) { + throw new RuntimeException(a11yTest.exceptionString); + } + } + + private class AccessibleActionsTestFrame extends JPanel { + + public AccessibleActionsTestFrame() { + MyLabel label = new MyLabel("I'm waiting for the push"); + label.setComponentPopupMenu(createPopup()); + label.setFocusable(true); + add(label); + setLayout(new FlowLayout()); + } + + private static class MyLabel extends JLabel { + public MyLabel(String text) { + super(text); + } + + @Override + public AccessibleContext getAccessibleContext() { + if (accessibleContext == null) { + accessibleContext = new MyAccessibleJLabel(); + } + return accessibleContext; + } + + private class MyAccessibleJLabel extends JLabel.AccessibleJLabel { + @Override + public AccessibleAction getAccessibleAction() { + return new AccessibleAction() { + @Override + public int getAccessibleActionCount() { + return 2; + } + + @Override + public String getAccessibleActionDescription(int i) { + if (i == 0) { + return AccessibleAction.CLICK; + } + return AccessibleAction.TOGGLE_POPUP; + } + + @Override + public boolean doAccessibleAction(int i) { + if (i == 0) { + changeText(MyLabel.this, "label is pressed"); + return true; + } + JPopupMenu popup = createPopup(); + popup.show(MyLabel.this, 0, 0); + return true; + } + }; + } + } + } + + private static JPopupMenu createPopup() { + JPopupMenu popup = new JPopupMenu("MENU"); + popup.add("One"); + popup.add("Two"); + popup.add("Three"); + return popup; + } + + private static void changeText(JLabel label, String text) { + label.setText(text); + } + + } +} diff --git a/test/jdk/java/awt/color/ICC_ColorSpace/SetTagDataValidation.java b/test/jdk/java/awt/color/ICC_ColorSpace/SetTagDataValidation.java new file mode 100644 index 0000000000000000000000000000000000000000..92faced75ba0d0a9da86ad589e968345a433eedd --- /dev/null +++ b/test/jdk/java/awt/color/ICC_ColorSpace/SetTagDataValidation.java @@ -0,0 +1,75 @@ +/* + * 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. + */ + +/** + * @test + * @bug 8282577 + * @summary Verify setting data for a tag doesn't invalidate the profile. + */ + +import java.awt.color.ColorSpace; +import java.awt.color.ICC_ColorSpace; +import java.awt.color.ICC_Profile; + +public final class SetTagDataValidation { + + public static void main(String[] args) throws Exception { + + ICC_Profile srgb = ICC_Profile.getInstance(ColorSpace.CS_sRGB); + // Create a new profile, using the srgb data but private to us. + ICC_Profile icc = ICC_Profile.getInstance(srgb.getData()); + + // Get data for some tag, which one isn't important so long as it exists + int tag = ICC_Profile.icSigBlueColorantTag; + byte[] tagData = icc.getData(tag); + if (tagData == null) { + throw new RuntimeException("No data for tag"); + } + // Set the data to be the SAME data which ought to be a harmless no-op + icc.setData(tag, tagData); + + // Perform a color conversion - from rgb to rgb but it doesn't matter + // we just need to verify the op is applied and results are sane. + + ColorSpace cs = new ICC_ColorSpace(icc); + float[] in = new float[3]; + in[0] = 0.4f; + in[1] = 0.5f; + in[2] = 0.6f; + + // the toRGB op previously threw an exception - or crashed + float[] out = cs.toRGB(in); + // If we get this far let's validate the results. + if (out == null || out.length !=3) { + throw new RuntimeException("out array invalid"); + } + for (int i=0;i<out.length;i++) { + System.out.println(out[i]); + } + for (int i=0;i<out.length;i++) { + if ((Math.abs(in[i]-out[i]) > 0.01)) { + throw new RuntimeException("Inaccurate no-op conversion"); + } + } + } +} diff --git a/test/jdk/java/awt/color/ICC_Profile/MTGetData.java b/test/jdk/java/awt/color/ICC_Profile/MTGetData.java index 5b2572e14f1c82ed29a1289c95569ec239e6b745..7d634cb0f4a507e56cc5936d778fd5f86cbc428a 100644 --- a/test/jdk/java/awt/color/ICC_Profile/MTGetData.java +++ b/test/jdk/java/awt/color/ICC_Profile/MTGetData.java @@ -23,6 +23,7 @@ import java.awt.color.ColorSpace; import java.awt.color.ICC_Profile; +import java.awt.color.CMMException; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.ArrayList; @@ -103,6 +104,7 @@ public final class MTGetData { icc.setData(tag, data2); } } catch (IllegalArgumentException ignored) { + System.err.println("Ignoring " + ignored); } catch (Throwable throwable) { throwable.printStackTrace(); failed = true; diff --git a/test/jdk/java/awt/datatransfer/UnicodeTransferTest/UnicodeTransferTest.java b/test/jdk/java/awt/datatransfer/UnicodeTransferTest/UnicodeTransferTest.java index 3a7ea0c59951ca01a5f1cf6a2ad2692c3a873abb..7dba15b5a1f56469604725e2227ff29ea1e048e2 100644 --- a/test/jdk/java/awt/datatransfer/UnicodeTransferTest/UnicodeTransferTest.java +++ b/test/jdk/java/awt/datatransfer/UnicodeTransferTest/UnicodeTransferTest.java @@ -25,7 +25,7 @@ /* @test @key headful - @bug 4718897 + @bug 4718897 8278908 @summary tests that a Unicode string can be transferred between JVMs. @author das@sparc.spb.su area=datatransfer @library ../../regtesthelpers/process @@ -35,7 +35,6 @@ import java.awt.datatransfer.*; import java.awt.*; -import java.text.Normalizer; import test.java.awt.regtesthelpers.process.ProcessResults; import test.java.awt.regtesthelpers.process.ProcessCommunicator; @@ -77,10 +76,7 @@ class Util { buf.append(0x20); } } - // On OS X the unicode string is normalized but the clipboard, - // so we need to use normalized strings as well to be able to - // check the result - testString = Normalizer.normalize(buf.toString(), Normalizer.Form.NFC); + testString = buf.toString(); } public static String getTestString() { diff --git a/test/jdk/java/awt/event/HierarchyEvent/AncestorResized/AncestorResized.java b/test/jdk/java/awt/event/HierarchyEvent/AncestorResized/AncestorResized.java index dafa0ead939f69d5d27b254f1d81d1c9be207d8c..156f3f75db5ed74e83b08b0cc51b40230d920859 100644 --- a/test/jdk/java/awt/event/HierarchyEvent/AncestorResized/AncestorResized.java +++ b/test/jdk/java/awt/event/HierarchyEvent/AncestorResized/AncestorResized.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 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 @@ -21,37 +21,30 @@ * questions. */ -/* - @test - @key headful - @bug 6533330 - @summary ANCESTOR_RESIZED is not sent while resizing a frame. Regression caused by 6500477. - @author anthony.petrov: area=awt.toplevel - @library ../../../regtesthelpers - @build Util - @run main AncestorResized -*/ - +import java.awt.Button; +import java.awt.Component; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Insets; +import java.awt.Label; +import java.awt.Panel; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.event.HierarchyBoundsListener; +import java.awt.event.HierarchyEvent; +import java.awt.event.InputEvent; /** - * AncestorResized.java - * - * summary: After fixing the 6500477, the ANCESTOR_RESIZED event stoped - * firing while resizing a frame. This was a regression. - * The test checks whether the event starts dispatching as it - * was before fixing the 6500477. + * @test + * @key headful + * @bug 6533330 + * @summary ANCESTOR_RESIZED is not sent while resizing a frame. Regression + * caused by 6500477. */ +public class AncestorResized { -import java.awt.*; -import java.awt.event.*; -import test.java.awt.regtesthelpers.Util; - - -public class AncestorResized -{ public static volatile int ancestorResizedCounter = 0; - static class HierarchyBoundsListenerImpl implements HierarchyBoundsListener { public void ancestorMoved(HierarchyEvent ce) { // ANCESTOR_MOVED seems to work OK. @@ -61,8 +54,7 @@ public class AncestorResized } } - private static void init() - { + public static void main(String[] args) throws Exception { Frame frame; Panel panel; Button button; @@ -83,17 +75,17 @@ public class AncestorResized frame.setSize(300, 300); frame.setVisible(true); - Robot robot = Util.createRobot(); - robot.setAutoDelay(20); + Robot robot = new Robot(); + robot.setAutoDelay(50); // To ensure the window is shown and packed - Util.waitForIdle(robot); + robot.waitForIdle(); Insets insets = frame.getInsets(); if (insets.right == 0 || insets.bottom == 0) { + frame.dispose(); // Because we want to catch the "size-grip" of the frame. System.out.println("The test environment must have non-zero right & bottom insets! The current insets are: " + insets); - pass(); return; } @@ -112,177 +104,12 @@ public class AncestorResized // ... and start resizing robot.mousePress( InputEvent.BUTTON1_MASK ); robot.mouseMove(bounds.x + bounds.width + 20, bounds.y + bounds.height + 15); - Util.waitForIdle(robot); + robot.mouseRelease(InputEvent.BUTTON1_MASK); + robot.waitForIdle(); + frame.dispose(); if (ancestorResizedCounter == 0) { - robot.mouseRelease( InputEvent.BUTTON1_MASK ); - AncestorResized.fail("No ANCESTOR_RESIZED events received."); - return; - } - - robot.mouseRelease( InputEvent.BUTTON1_MASK ); - - AncestorResized.pass(); - }//End init() - - - - /***************************************************** - * Standard Test Machinery Section - * DO NOT modify anything in this section -- it's a - * standard chunk of code which has all of the - * synchronisation necessary for the test harness. - * By keeping it the same in all tests, it is easier - * to read and understand someone else's test, as - * well as insuring that all tests behave correctly - * with the test harness. - * There is a section following this for test- - * classes - ******************************************************/ - private static boolean theTestPassed = false; - private static boolean testGeneratedInterrupt = false; - private static String failureMessage = ""; - - private static Thread mainThread = null; - - private static int sleepTime = 300000; - - // Not sure about what happens if multiple of this test are - // instantiated in the same VM. Being static (and using - // static vars), it aint gonna work. Not worrying about - // it for now. - public static void main( String args[] ) throws InterruptedException - { - mainThread = Thread.currentThread(); - try - { - init(); - } - catch( TestPassedException e ) - { - //The test passed, so just return from main and harness will - // interepret this return as a pass - return; + throw new RuntimeException("No ANCESTOR_RESIZED events received."); } - //At this point, neither test pass nor test fail has been - // called -- either would have thrown an exception and ended the - // test, so we know we have multiple threads. - - //Test involves other threads, so sleep and wait for them to - // called pass() or fail() - try - { - Thread.sleep( sleepTime ); - //Timed out, so fail the test - throw new RuntimeException( "Timed out after " + sleepTime/1000 + " seconds" ); - } - catch (InterruptedException e) - { - //The test harness may have interrupted the test. If so, rethrow the exception - // so that the harness gets it and deals with it. - if( ! testGeneratedInterrupt ) throw e; - - //reset flag in case hit this code more than once for some reason (just safety) - testGeneratedInterrupt = false; - - if ( theTestPassed == false ) - { - throw new RuntimeException( failureMessage ); - } - } - - }//main - - public static synchronized void setTimeoutTo( int seconds ) - { - sleepTime = seconds * 1000; - } - - public static synchronized void pass() - { - System.out.println( "The test passed." ); - System.out.println( "The test is over, hit Ctl-C to stop Java VM" ); - //first check if this is executing in main thread - if ( mainThread == Thread.currentThread() ) - { - //Still in the main thread, so set the flag just for kicks, - // and throw a test passed exception which will be caught - // and end the test. - theTestPassed = true; - throw new TestPassedException(); - } - theTestPassed = true; - testGeneratedInterrupt = true; - mainThread.interrupt(); - }//pass() - - public static synchronized void fail() - { - //test writer didn't specify why test failed, so give generic - fail( "it just plain failed! :-)" ); } - - public static synchronized void fail( String whyFailed ) - { - System.out.println( "The test failed: " + whyFailed ); - System.out.println( "The test is over, hit Ctl-C to stop Java VM" ); - //check if this called from main thread - if ( mainThread == Thread.currentThread() ) - { - //If main thread, fail now 'cause not sleeping - throw new RuntimeException( whyFailed ); - } - theTestPassed = false; - testGeneratedInterrupt = true; - failureMessage = whyFailed; - mainThread.interrupt(); - }//fail() - -}// class AncestorResized - -//This exception is used to exit from any level of call nesting -// when it's determined that the test has passed, and immediately -// end the test. -class TestPassedException extends RuntimeException -{ } - -//*********** End Standard Test Machinery Section ********** - - -//************ Begin classes defined for the test **************** - -// if want to make listeners, here is the recommended place for them, then instantiate -// them in init() - -/* Example of a class which may be written as part of a test -class NewClass implements anInterface - { - static int newVar = 0; - - public void eventDispatched(AWTEvent e) - { - //Counting events to see if we get enough - eventCount++; - - if( eventCount == 20 ) - { - //got enough events, so pass - - AncestorResized.pass(); - } - else if( tries == 20 ) - { - //tried too many times without getting enough events so fail - - AncestorResized.fail(); - } - - }// eventDispatched() - - }// NewClass class - -*/ - - -//************** End classes defined for the test ******************* diff --git a/test/jdk/java/awt/font/GlyphVector/MultiSlotFontTest.java b/test/jdk/java/awt/font/GlyphVector/MultiSlotFontTest.java new file mode 100644 index 0000000000000000000000000000000000000000..65acd420345b8839b6d38847039ca92faa7e357a --- /dev/null +++ b/test/jdk/java/awt/font/GlyphVector/MultiSlotFontTest.java @@ -0,0 +1,136 @@ +/* + * 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. + */ + +/** + * @test + * @bug 8240756 + * @summary Non-English characters are printed with wrong glyphs on MacOS + * @modules java.desktop/sun.java2d java.desktop/sun.java2d.loops java.desktop/sun.font + * @requires os.family == "mac" + * @run main MultiSlotFontTest + */ + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.Graphics; +import java.awt.Image; +import java.awt.RenderingHints; +import java.awt.font.FontRenderContext; +import java.awt.font.GlyphVector; +import java.awt.image.BufferedImage; +import sun.font.StandardGlyphVector; +import sun.java2d.OSXOffScreenSurfaceData; +import sun.java2d.SunGraphics2D; +import sun.java2d.SurfaceData; +import sun.java2d.loops.SurfaceType; + +public class MultiSlotFontTest { + + private static final int WIDTH = 100; + private static final int HEIGHT = 60; + + private static final String TEST_STR = "\u3042\u3044\u3046\u3048\u304Aabc"; + private static final int EXPECTED_HEIGHT = 10; + private static final int EXPECTED_WIDTH = 77; + private static final int LIMIT_DIFF_HEIGHT = 3; + private static final int LIMIT_DIFF_WIDTH = 15; + + public static void main(String[] args) throws Exception { + MultiSlotFontTest test = new MultiSlotFontTest(); + } + + public MultiSlotFontTest() { + BufferedImage img = createImage(); + + SurfaceData sd = OSXOffScreenSurfaceData.createDataIC(img, + SurfaceType.IntRgb); + SunGraphics2D g2d = new SunGraphics2D(sd, + Color.BLACK, Color.WHITE, null); + Font font = g2d.getFont(); + + if (font.canDisplayUpTo(TEST_STR) != -1) { + System.out.println("There is no capable font. Skipping the test."); + System.out.println("Font: " + font); + return; + } + + FontRenderContext frc = new FontRenderContext(null, false, false); + StandardGlyphVector gv = new StandardGlyphVector(font, TEST_STR, frc); + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_OFF); + g2d.drawGlyphVector(gv, 0.0f, (float)(HEIGHT - 5)); + g2d.dispose(); + + Dimension d = getBounds(img); + + if (Math.abs(d.height - EXPECTED_HEIGHT) > LIMIT_DIFF_HEIGHT || + Math.abs(d.width - EXPECTED_WIDTH) > LIMIT_DIFF_WIDTH) { + debugOut(img); + throw new RuntimeException( + "Incorrect GlyphVector shape " + d + "," + gv); + } + } + + private static BufferedImage createImage() { + BufferedImage image = new BufferedImage(WIDTH, HEIGHT, + BufferedImage.TYPE_INT_RGB); + Graphics g = image.createGraphics(); + g.setColor(Color.WHITE); + g.fillRect(0, 0, WIDTH, HEIGHT); + g.dispose(); + return image; + } + + private Dimension getBounds(BufferedImage img) { + int top = HEIGHT; + int left = WIDTH; + int right = 0; + int bottom = 0; + for (int y = 0; y < HEIGHT; y++) { + for (int x = 0; x < WIDTH; x++) { + if ((img.getRGB(x, y) & 0xFFFFFF) == 0) { + if (top > y) top = y; + if (bottom < y) bottom = y; + if (left > x) left = x; + if (right < x) right = x; + } + } + } + return new Dimension(right - left, bottom - top); + } + + private void debugOut(BufferedImage img) { + for (int y = 0; y < HEIGHT; y++) { + for (int x = 0; x < WIDTH; x++) { + int c = img.getRGB(x, y) & 0xFFFFFF; + if (c == 0) { + System.out.print("*"); + } else { + System.out.print(" "); + } + } + System.out.println(); + } + } +} diff --git a/test/jdk/java/awt/font/JNICheck/JNICheck.sh b/test/jdk/java/awt/font/JNICheck/JNICheck.sh index 4244b510b232e94a1275be03056e8186e3ec4f18..cc019e72d5620db01b383d33d1897546c3500ccd 100644 --- a/test/jdk/java/awt/font/JNICheck/JNICheck.sh +++ b/test/jdk/java/awt/font/JNICheck/JNICheck.sh @@ -49,7 +49,7 @@ else fi $JAVA_HOME/bin/java ${TESTVMOPTS} \ - -cp "${CP}" -Xcheck:jni JNICheck | grep -v SIG | grep -v Signal | grep -v CallStatic > "${CP}"/log.txt + -cp "${CP}" -Xcheck:jni JNICheck | grep -v SIG | grep -v Signal | grep -v Handler | grep -v jsig | grep -v CallStatic > "${CP}"/log.txt # any messages logged may indicate a failure. if [ -s "${CP}"/log.txt ]; then diff --git a/test/jdk/java/awt/image/ColorModel/DrawCustomColorModel.java b/test/jdk/java/awt/image/ColorModel/DrawCustomColorModel.java new file mode 100644 index 0000000000000000000000000000000000000000..a438048f1cee46b6ed052ceea39a4c6bdbd1b329 --- /dev/null +++ b/test/jdk/java/awt/image/ColorModel/DrawCustomColorModel.java @@ -0,0 +1,79 @@ +/* + * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.AlphaComposite; +import java.awt.Frame; +import java.awt.Graphics2D; +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; +import java.awt.Image; +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.DataBufferInt; +import java.awt.image.DirectColorModel; +import java.awt.image.WritableRaster; +import java.util.Arrays; + +/** + * @test + * @bug 8275843 + * @key headful + * @summary No exception or errors should occur. + */ +public final class DrawCustomColorModel { + + public static void main(String[] args) { + var ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); + for (GraphicsDevice gd : ge.getScreenDevices()) { + GraphicsConfiguration[] gcs = gd.getConfigurations(); + for (GraphicsConfiguration gc : gcs) { + test(gc); + } + } + } + + private static void test(GraphicsConfiguration gc) { + Frame frame = new Frame(gc); + frame.setUndecorated(true); + frame.pack(); + frame.setSize(15, 15); + ColorModel cm = new DirectColorModel(32, + 0xff000000, // Red + 0x00ff0000, // Green + 0x0000ff00, // Blue + 0x000000FF // Alpha + ); + WritableRaster wr = cm.createCompatibleWritableRaster(16, 16); + DataBufferInt buff = (DataBufferInt) wr.getDataBuffer(); + int[] data = buff.getData(); + Arrays.fill(data, -1); // more chance to reproduce + Image image = new BufferedImage(cm, wr, false, null); + + Graphics2D graphics = (Graphics2D) frame.getGraphics(); + graphics.setComposite(AlphaComposite.Src); + graphics.drawImage(image, 0, 0, null); + graphics.dispose(); + frame.dispose(); + } +} diff --git a/test/jdk/java/awt/image/DrawImage/ByteIndexedDitherTest.java b/test/jdk/java/awt/image/DrawImage/ByteIndexedDitherTest.java new file mode 100644 index 0000000000000000000000000000000000000000..0c0aa49eb4356eeaadcd5bd8e1812aeb5f8720d4 --- /dev/null +++ b/test/jdk/java/awt/image/DrawImage/ByteIndexedDitherTest.java @@ -0,0 +1,83 @@ +/* + * 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. + */ + +/** + * @test + * @bug 8280964 + * @summary Tests that drawing to a ByteIndexed image dithers correctly. + */ + +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.image.BufferedImage; + +public class ByteIndexedDitherTest { + + public static void main(String[] args) { + BufferedImage bgr = createBGRImage(); + BufferedImage indexed = createIndexedImage(bgr); + checkImage(indexed); + } + + static BufferedImage createBGRImage() { + + int sz = 8; + BufferedImage img; + img = new BufferedImage(sz, sz, BufferedImage.TYPE_3BYTE_BGR); + Graphics2D g = img.createGraphics(); + Color c = new Color(0, 0, 254); + g.setColor(c); + g.fillRect(0, 0, sz, sz); + g.dispose(); + + return img; + } + + static BufferedImage createIndexedImage(BufferedImage srcImage) { + + int w = srcImage.getWidth(null); + int h = srcImage.getHeight(null); + BufferedImage + indexedImg = new BufferedImage(w, h, BufferedImage.TYPE_BYTE_INDEXED); + Graphics2D g = indexedImg.createGraphics(); + g.drawImage(srcImage, 0, 0, w, h, null); + g.dispose(); + return indexedImg; + } + + static void checkImage(BufferedImage image) { + int wid = image.getWidth(); + int hgt = image.getHeight(); + for (int y=0; y<hgt; y++) { + for (int x=0; x<wid; x++) { + int v = image.getRGB(x, y); + if ((v & 0x00ffff00) != 0) { + System.err.println("("+x+","+y+") = " + + Integer.toHexString(v)); + throw new RuntimeException("Unexpected Red or Green"); + } + } + } + } +} + diff --git a/test/jdk/java/awt/image/DrawImage/TiledImage.java b/test/jdk/java/awt/image/DrawImage/TiledImage.java new file mode 100644 index 0000000000000000000000000000000000000000..8faca3aec6ab938bd50aaf8360b721455be7fe84 --- /dev/null +++ b/test/jdk/java/awt/image/DrawImage/TiledImage.java @@ -0,0 +1,225 @@ +/* + * 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. + */ + +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.geom.AffineTransform; +import java.awt.image.BandedSampleModel; +import java.awt.image.BufferedImage; +import java.awt.image.Raster; +import java.awt.image.ColorModel; +import java.awt.image.DataBuffer; +import java.awt.image.DataBufferByte; +import java.awt.image.RenderedImage; +import java.awt.image.SampleModel; +import java.awt.image.WritableRaster; +import java.util.Objects; +import java.util.Vector; + + +/** + * @test + * @bug 8275345 + * @summary RasterFormatException when drawing a tiled image made of non-writable rasters. + * + * Test drawing a tiled image made of non-writable {@link Raster} tiles. + * Drawing works when tiles are instances of {@link WritableRaster}. + * But if tiles are instances of {@link Raster} only, then the following + * exception is thrown: + * + * Exception in thread "main" java.awt.image.RasterFormatException: (parentX + width) is outside raster + * at java.desktop/java.awt.image.WritableRaster.createWritableChild(WritableRaster.java:228) + * at java.desktop/sun.java2d.SunGraphics2D.drawTranslatedRenderedImage(SunGraphics2D.java:2852) + * at java.desktop/sun.java2d.SunGraphics2D.drawRenderedImage(SunGraphics2D.java:2711) + * + * The bug is demonstrated by drawing the same image twice: + * once with {@link WritableRaster} tiles (which succeed), + * then the same operation but with {@link Raster} tiles. + * + * The bug is caused by the following code in {@code SunGraphics2D}: + * + * // Create a WritableRaster containing the tile + * WritableRaster wRaster = null; + * if (raster instanceof WritableRaster) { + * wRaster = (WritableRaster)raster; + * } else { + * // Create a WritableRaster in the same coordinate system + * // as the original raster. + * wRaster = + * Raster.createWritableRaster(raster.getSampleModel(), + * raster.getDataBuffer(), + * null); + * } + * // Translate wRaster to start at (0, 0) and to contain + * // only the relevant portion of the tile + * wRaster = wRaster.createWritableChild(tileRect.x, tileRect.y, + * tileRect.width, + * tileRect.height, + * 0, 0, + * null); + * + * If {@code raster} is not an instance of {@link WritableRaster}, + * then a new {@link WritableRaster} is created wrapping the same + * buffer <strong>but with a location of (0,0)</strong>, because + * the {@code location} argument of {@code createWritableRaster} + * is null. Consequently the call to {@code createWritableChild} + * shall not be done in that case, because the raster is already + * translated. The current code applies translation twice. + * + * This bug is largely unnoticed because most {@code Raster.create} + * methods actually create {@link WritableRaster} instances, even + * when the user did not asked for writable raster. To make this + * bug apparent, we need to invoke {@code Raster.createRaster(…)} + * with a sample model for which no optimization is provided. + */ +public class TiledImage implements RenderedImage { + /** + * Run the test using writable tiles first, then read-only tiles. + */ + public static void main(String[] args) { + draw(true); // Pass. + draw(false); // Fail if 8275345 is not fixed. + } + + private static final int NUM_X_TILES = 2, NUM_Y_TILES = 3; + + private static final int TILE_WIDTH = 16, TILE_HEIGHT = 12; + + /** + * Tests rendering a tiled image. + * + * @param writable whether the image shall use writable raster. + */ + private static void draw(final boolean writable) { + final BufferedImage target = new BufferedImage( + TILE_WIDTH * NUM_X_TILES, + TILE_HEIGHT * NUM_Y_TILES, + BufferedImage.TYPE_BYTE_GRAY); + + final RenderedImage source = new TiledImage(writable, + target.getColorModel()); + + Graphics2D g = target.createGraphics(); + g.drawRenderedImage(source, new AffineTransform()); + g.dispose(); + } + + private final ColorModel colorModel; + + private final Raster[] tiles; + + /** + * Creates a tiled image. The image is empty, + * but pixel values are not the purpose of this test. + * + * @param writable whether the image shall use writable raster. + */ + private TiledImage(boolean writable, ColorModel cm) { + /* + * We need a sample model class for which Raster.createRaster + * do not provide a special case. That method has optimizations + * for most SampleModel sub-types, except BandedSampleModel. + */ + SampleModel sm = new BandedSampleModel(DataBuffer.TYPE_BYTE, TILE_WIDTH, TILE_HEIGHT, 1); + tiles = new Raster[NUM_X_TILES * NUM_Y_TILES]; + final Point location = new Point(); + for (int tileY = 0; tileY < NUM_Y_TILES; tileY++) { + for (int tileX = 0; tileX < NUM_X_TILES; tileX++) { + location.x = tileX * TILE_WIDTH; + location.y = tileY * TILE_HEIGHT; + DataBufferByte db = new DataBufferByte(TILE_WIDTH * TILE_HEIGHT); + Raster r; + if (writable) { + r = Raster.createWritableRaster(sm, db, location); + } else { + // Case causing RasterFormatException later. + r = Raster.createRaster(sm, db, location); + } + tiles[tileX + tileY * NUM_X_TILES] = r; + } + } + colorModel = cm; + } + + @Override + public ColorModel getColorModel() { + return colorModel; + } + + @Override + public SampleModel getSampleModel() { + return tiles[0].getSampleModel(); + } + + @Override + public Vector<RenderedImage> getSources() { + return new Vector<>(); + } + + @Override + public Object getProperty(String key) { + return Image.UndefinedProperty; + } + + @Override + public String[] getPropertyNames() { + return null; + } + + @Override public int getMinX() {return 0;} + @Override public int getMinY() {return 0;} + @Override public int getMinTileX() {return 0;} + @Override public int getMinTileY() {return 0;} + @Override public int getTileGridXOffset() {return 0;} + @Override public int getTileGridYOffset() {return 0;} + @Override public int getNumXTiles() {return NUM_X_TILES;} + @Override public int getNumYTiles() {return NUM_Y_TILES;} + @Override public int getTileWidth() {return TILE_WIDTH;} + @Override public int getTileHeight() {return TILE_HEIGHT;} + @Override public int getWidth() {return TILE_WIDTH * NUM_X_TILES;} + @Override public int getHeight() {return TILE_HEIGHT * NUM_Y_TILES;} + + @Override + public Raster getTile(final int tileX, final int tileY) { + Objects.checkIndex(tileX, NUM_X_TILES); + Objects.checkIndex(tileY, NUM_Y_TILES); + return tiles[tileX + tileY * NUM_X_TILES]; + } + + @Override + public Raster getData() { + throw new UnsupportedOperationException("Not needed for this test."); + } + + @Override + public Raster getData(Rectangle rect) { + throw new UnsupportedOperationException("Not needed for this test."); + } + + @Override + public WritableRaster copyData(WritableRaster raster) { + throw new UnsupportedOperationException("Not needed for this test."); + } +} diff --git a/test/jdk/java/awt/print/PrinterJob/InitToBlack.java b/test/jdk/java/awt/print/PrinterJob/InitToBlack.java index 783320829b632d658349195ae14aa5a37a857bfc..a4d7dd0a9589c5c3fb1d605cd7df927d5da1f5e5 100644 --- a/test/jdk/java/awt/print/PrinterJob/InitToBlack.java +++ b/test/jdk/java/awt/print/PrinterJob/InitToBlack.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 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 @@ -22,21 +22,57 @@ */ /** + * @test * @bug 4184565 * @summary Confirm that the default foreground color on a printer * graphics object is black so that rendering will appear * without having to execute setColor first. - * @run applet/manual=yesno InitToBlack.html + * @run main/manual InitToBlack */ -import java.awt.*; -import java.awt.print.*; -import java.applet.Applet; +import java.awt.BorderLayout; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.print.Book; +import java.awt.print.PageFormat; +import java.awt.print.Printable; +import java.awt.print.PrinterException; +import java.awt.print.PrinterJob; +import java.lang.reflect.InvocationTargetException; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import javax.swing.JButton; +import javax.swing.JDialog; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JTextArea; +import javax.swing.SwingUtilities; -public class InitToBlack extends Applet implements Printable { +public class InitToBlack implements Printable { - public void init() { + private static volatile JFrame frame; + private static volatile boolean testResult = false; + private static volatile CountDownLatch printButtonCountDownLatch = + new CountDownLatch(1); + private static volatile CountDownLatch CountDownLatch = + new CountDownLatch(1); + private static volatile String failureReason; + + @Override + public int print(Graphics graphics, PageFormat pageFormat, int pageIndex) throws PrinterException { + Graphics2D g2d = (Graphics2D) graphics; + g2d.translate(pageFormat.getImageableX(), pageFormat.getImageableY()); + graphics.drawString("Test Passes", 200, 200); + return PAGE_EXISTS; + } + + private void test() { PrinterJob pjob = PrinterJob.getPrinterJob(); + if (pjob.getPrintService() == null) { + System.out.println("There is no printer configured on this system"); + return; + } Book book = new Book(); book.append(this, pjob.defaultPage()); @@ -49,17 +85,97 @@ public class InitToBlack extends Applet implements Printable { } } - public int print(Graphics g, PageFormat pf, int pageIndex) { - Graphics2D g2d = (Graphics2D) g; - g2d.translate(pf.getImageableX(), pf.getImageableY()); + private static void createTestUI() { + frame = new JFrame("Test InitToBlack"); + String INSTRUCTION = """ + Aim: This test checks whether the default foreground color on a printer + graphics object is black so that rendering will appear without having + to execute setColor. + Step: + 1) Click on the "Print" button. Check whether page is printed on the printer. + 2) Check whether "Test Passes" is printed on the page and it should be in + black color. If yes then press "Pass" button else press "Fail" button. + """; + JTextArea instructionTextArea = new JTextArea(INSTRUCTION, 4, 40); + instructionTextArea.setEditable(false); - g.drawString("Test Passes", 200, 200); + JPanel buttonPanel = new JPanel(); + JButton printButton = new JButton("Print"); + printButton.addActionListener((ae) -> { + InitToBlack initToBlack = new InitToBlack(); + initToBlack.test(); + printButtonCountDownLatch.countDown(); + }); - return PAGE_EXISTS; + JButton passButton = new JButton("Pass"); + passButton.addActionListener((ae) -> { + testResult = true; + CountDownLatch.countDown(); + frame.dispose(); + }); + JButton failButton = new JButton("Fail"); + failButton.addActionListener((ae) -> { + getFailureReason(); + frame.dispose(); + }); + buttonPanel.add(printButton); + buttonPanel.add(passButton); + buttonPanel.add(failButton); + + JPanel panel = new JPanel(new BorderLayout()); + panel.add(instructionTextArea, BorderLayout.CENTER); + panel.add(buttonPanel, BorderLayout.SOUTH); + + frame.add(panel); + frame.setLocationRelativeTo(null); + frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + frame.pack(); + frame.setVisible(true); + } + + public static void getFailureReason() { + final JDialog dialog = new JDialog(); + dialog.setTitle("Read testcase failure reason"); + JPanel jPanel = new JPanel(new BorderLayout()); + JTextArea jTextArea = new JTextArea(5, 20); + + JButton okButton = new JButton("Ok"); + okButton.addActionListener((ae) -> { + failureReason = jTextArea.getText(); + testResult = false; + CountDownLatch.countDown(); + dialog.dispose(); + }); + + jPanel.add(new JLabel("Enter the testcase failed reason below and " + + "click OK button", JLabel.CENTER), BorderLayout.NORTH); + jPanel.add(jTextArea, BorderLayout.CENTER); + + JPanel okayBtnPanel = new JPanel(); + okayBtnPanel.add(okButton); + + jPanel.add(okayBtnPanel, BorderLayout.SOUTH); + dialog.add(jPanel); + dialog.setLocationRelativeTo(null); + dialog.pack(); + dialog.setVisible(true); } - public static void main(String[] args) { - new InitToBlack().init(); - System.exit(0); + public static void main(String[] args) throws InterruptedException, InvocationTargetException { + SwingUtilities.invokeAndWait(InitToBlack::createTestUI); + if (!printButtonCountDownLatch.await(2, TimeUnit.MINUTES)) { + throw new RuntimeException("Timeout: User did not perform action " + + "on Print button."); + } + if (!CountDownLatch.await(2, TimeUnit.MINUTES)) { + throw new RuntimeException("Timeout : User did not decide " + + "whether test passed or failed"); + } + + if (!testResult) { + throw new RuntimeException("Test failed : " + failureReason); + } else { + System.out.println("Test Passed"); + } } } diff --git a/test/jdk/java/awt/print/PrinterJob/PrtException.java b/test/jdk/java/awt/print/PrinterJob/PrtException.java index 152fe70d485a960edab6974c8a0200fbcad6e793..bb590fd6cd97557c77a7f56471d9d0deef00b4b0 100644 --- a/test/jdk/java/awt/print/PrinterJob/PrtException.java +++ b/test/jdk/java/awt/print/PrinterJob/PrtException.java @@ -50,7 +50,7 @@ public class PrtException implements Printable { } System.out.println("PrintService found : "+defService); - pj = PrinterJob.getPrinterJob();; + pj = PrinterJob.getPrinterJob(); pj.setPrintService(defService); //pj.setPrintable(this); // commenting this line should not result in PrinterException pj.print(); diff --git a/test/jdk/java/awt/regtesthelpers/Util.java b/test/jdk/java/awt/regtesthelpers/Util.java index dde65574460417b75558d4488b6545989063456e..af1cafe42974970b1eb143ebf0d88e2532588dcc 100644 --- a/test/jdk/java/awt/regtesthelpers/Util.java +++ b/test/jdk/java/awt/regtesthelpers/Util.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 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 @@ -405,8 +405,7 @@ public final class Util { } /* - * The values directly map to the ones of - * sun.awt.X11.XWM & sun.awt.motif.MToolkit classes. + * The values directly map to the ones of sun.awt.X11.XWM class. */ public final static int UNDETERMINED_WM = 1, @@ -433,8 +432,6 @@ public final class Util { try { if ("sun.awt.X11.XToolkit".equals(Toolkit.getDefaultToolkit().getClass().getName())) { clazz = Class.forName("sun.awt.X11.XWM"); - } else if ("sun.awt.motif.MToolkit".equals(Toolkit.getDefaultToolkit().getClass().getName())) { - clazz = Class.forName("sun.awt.motif.MToolkit"); } } catch (ClassNotFoundException cnfe) { cnfe.printStackTrace(); @@ -446,7 +443,6 @@ public final class Util { try { final Class _clazz = clazz; Method m_addExports = Class.forName("java.awt.Helper").getDeclaredMethod("addExports", String.class, java.lang.Module.class); - // No MToolkit anymore: nothing to do about it. // We may be called from non-X11 system, and this permission cannot be delegated to a test. m_addExports.invoke(null, "sun.awt.X11", Util.class.getModule()); Method m_getWMID = (Method)AccessController.doPrivileged(new PrivilegedAction() { diff --git a/test/jdk/java/awt/regtesthelpers/process/ProcessCommunicator.java b/test/jdk/java/awt/regtesthelpers/process/ProcessCommunicator.java index 60a5952b32c03b12bc7217af83df0fa56c8451c0..474a23717ea91f8020602144b1d96aaafbd54686 100644 --- a/test/jdk/java/awt/regtesthelpers/process/ProcessCommunicator.java +++ b/test/jdk/java/awt/regtesthelpers/process/ProcessCommunicator.java @@ -76,7 +76,7 @@ public class ProcessCommunicator { } /** - * Executes child {code Process} + * Executes child {@code Process} * * @param classToExecute class to be executed as a child java process * @param args args to be passed in to the child process diff --git a/test/jdk/java/beans/Introspector/MethodOrderException.java b/test/jdk/java/beans/Introspector/MethodOrderException.java index d6c79b5d768501f99de5e7474818bf6756812a24..b69981002e686e4c4a5e3ba6344ca96acafc828e 100644 --- a/test/jdk/java/beans/Introspector/MethodOrderException.java +++ b/test/jdk/java/beans/Introspector/MethodOrderException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -35,40 +35,1553 @@ import java.util.RandomAccess; /** * @test - * @bug 8211147 + * @bug 8211147 8280132 * @modules java.desktop/com.sun.beans.introspect:open */ public final class MethodOrderException { public static void main(final String[] args) throws Exception { - // Public API, fails rarely - testPublicAPI(); - // Test using internal API, fails always - testPrivateAPI(); + for (Class<?> beanClass : List.of(D.class, X.class, A_258.class)) { + // Public API, fails rarely + testPublicAPI(beanClass); + // Test using internal API, fails always + testPrivateAPI(beanClass); + } } - private static void testPublicAPI() throws Exception { - Introspector.getBeanInfo(X.class); + private static void testPublicAPI(Class<?> beanClass) throws Exception { + Introspector.getBeanInfo(beanClass); } - private static void testPrivateAPI() throws Exception { + private static void testPrivateAPI(Class<?> beanClass) throws Exception { Class<?> name = Class.forName( "com.sun.beans.introspect.MethodInfo$MethodOrder"); Field instance = name.getDeclaredField("instance"); instance.setAccessible(true); Comparator<Method> o = (Comparator) instance.get(name); - List<Method> methods = List.of(X.class.getDeclaredMethods()); + List<Method> methods = List.of(beanClass.getDeclaredMethods()); methods.forEach(m1 -> { methods.forEach(m2 -> { if (o.compare(m1, m2) != -o.compare(m2, m1)) { - System.err.println("Method1 = "+ m1); - System.err.println("Method2 = "+ m2); + System.err.println("Method1 = " + m1); + System.err.println("Method2 = " + m2); throw new RuntimeException("Broken contract!"); } + methods.forEach(m3 -> { + if (o.compare(m1, m2) < 0 && o.compare(m2, m3) < 0) { + if (o.compare(m1, m3) >= 0) { + System.err.println("Method1 = " + m1); + System.err.println("Method2 = " + m2); + System.err.println("Method3 = " + m3); + throw new RuntimeException("Broken contract!"); + } + } + }); }); }); } + interface C1 { + C1 foo0(); + } + interface C2 { + C2 foo0(); + } + interface C3 extends C1 { + C3 foo0(); + } + interface D extends C3, C2, C1 { + D foo0(); + } + public interface A_239 { + } + public interface A_240 { + } + public interface A_000 { + } + public interface A_238<T> { + } + public interface A_035 extends A_195, A_106, A_240 { + A_035 a_040(); + A_035 a_000(); + A_035 a_018(); + } + public static class A_258 implements A_053, A_196, A_200, A_070, A_106, + A_057, A_094, A_098, A_105, A_107, A_097, A_093, A_214, A_215, + A_210, A_129, A_067, A_180, A_108, A_184, A_110, A_111, A_082, + A_221, A_172, A_171, A_168, A_139, A_143, A_140, A_075, A_081, + A_080, A_163, A_165, A_164, A_159, A_161, A_155, A_158, A_157, + A_156, A_195, A_197, A_114, A_213, A_236, A_220, A_201, A_035, + A_136, A_135, A_226, A_227, A_005, A_054, A_203, A_202, A_071, + A_115, A_113, A_112, A_058, A_095, A_096, A_099, A_100, A_237, + A_091, A_092, A_217, A_218, A_216, A_211, A_130, A_063, A_062, + A_064, A_065, A_066, A_061, A_060, A_181, A_208, A_207, A_209, + A_185, A_186, A_083, A_173, A_176, A_222, A_223, A_174, A_169, + A_153, A_154, A_194, A_190, A_104, A_132, A_141, A_142, A_166, + A_167, A_160, A_162, A_076, A_077, A_078, A_079, A_074, A_085, + A_192, A_188, A_134, A_138, A_137, A_228 { + @Override + public A_258 a_052() { + return null; + } + @Override + public A_258 a_071() { + return null; + } + @Override + public A_258 a_029() { + return null; + } + @Override + public A_258 a_046() { + return null; + } + @Override + public A_258 a_045() { + return null; + } + @Override + public A_258 a_047() { + return null; + } + @Override + public A_258 a_048() { + return null; + } + @Override + public A_258 a_049() { + return null; + } + @Override + public A_258 a_044() { + return null; + } + @Override + public A_258 a_043() { + return null; + } + @Override + public A_258 a_026() { + return null; + } + @Override + public A_258 a_027() { + return null; + } + @Override + public A_258 a_074() { + return null; + } + @Override + public A_258 a_079() { + return null; + } + @Override + public A_258 a_012() { + return null; + } + @Override + public A_258 a_100() { + return null; + } + @Override + public A_258 a_085() { + return null; + } + @Override + public A_258 a_084() { + return null; + } + @Override + public A_258 a_011() { + return null; + } + @Override + public A_258 a_059() { + return null; + } + @Override + public A_258 a_058() { + return null; + } + @Override + public A_258 a_080() { + return null; + } + @Override + public A_258 a_030() { + return null; + } + @Override + public A_258 a_031() { + return null; + } + @Override + public A_258 a_081() { + return null; + } + @Override + public A_258 a_077() { + return null; + } + @Override + public A_258 a_036() { + return null; + } + @Override + public A_258 a_056() { + return null; + } + @Override + public A_258 a_078() { + return null; + } + @Override + public A_258 a_076() { + return null; + } + @Override + public A_258 a_057() { + return null; + } + @Override + public A_258 a_005() { + return null; + } + @Override + public A_258 a_089() { + return null; + } + @Override + public A_258 a_088() { + return null; + } + @Override + public A_258 a_090() { + return null; + } + @Override + public A_258 a_072() { + return null; + } + @Override + public A_258 a_002() { + return null; + } + @Override + public A_258 a_040() { + return null; + } + @Override + public A_258 a_060() { + return null; + } + @Override + public A_258 a_061() { + return null; + } + @Override + public A_258 a_039() { + return null; + } + @Override + public A_258 a_032() { + return null; + } + @Override + public A_258 a_033() { + return null; + } + @Override + public A_258 a_000() { + return null; + } + @Override + public A_258 a_037() { + return null; + } + @Override + public A_258 a_014() { + return null; + } + @Override + public A_258 a_015() { + return null; + } + @Override + public A_258 a_016() { + return null; + } + @Override + public A_258 a_017() { + return null; + } + @Override + public A_258 a_091() { + return null; + } + @Override + public A_258 a_065() { + return null; + } + @Override + public A_258 a_066() { + return null; + } + @Override + public A_258 a_018() { + return null; + } + @Override + public A_258 a_093() { + return null; + } + @Override + public A_258 a_092() { + return null; + } + @Override + public A_258 a_095() { + return null; + } + @Override + public A_258 a_096() { + return null; + } + @Override + public A_258 a_069() { + return null; + } + } + public interface A_250 extends A_239 { + A_250 a_094(); + } + public interface A_253 extends A_239 { + A_253 a_000(); + } + public interface A_256 extends A_239 { + A_256 a_009(); + } + public interface A_248 extends A_239 { + A_248 a_022(); + } + public interface A_255 extends A_239 { + A_255 a_007(); + } + public interface A_241 extends A_248, A_250, A_251, A_249, A_239 { + } + public interface A_254 extends A_239 { + A_254 a_008(); + } + public interface A_251 extends A_239 { + A_251 a_097(); + } + public interface A_252 extends A_241, A_255, A_253, A_257, A_254, A_256, + A_239 { + A_252 a_022(); + A_252 a_094(); + A_252 a_097(); + A_252 a_087(); + } + public interface A_229 extends A_239 { + A_229 a_000(); + } + public interface A_232 extends A_239 { + } + public interface A_249 extends A_239 { + A_249 a_087(); + } + public interface A_230 extends A_239 { + } + public interface A_234 extends A_239 { + A_234 a_026(); + } + public interface A_037 extends A_239 { + A_037 a_013(); + } + public interface A_233 extends A_239 { + A_233 a_018(); + } + public interface A_231 extends A_239 { + A_231 a_007(); + } + public interface A_049 extends A_239 { + A_049 a_068(); + } + public interface A_257 extends A_239 { + A_257 a_018(); + } + public interface A_235 extends A_239 { + } + public interface A_040 extends A_239 { + A_040 a_025(); + } + public interface A_133 extends A_000, A_005, A_134, A_240 { + A_133 a_040(); + A_133 a_057(); + } + public interface A_001 extends A_239 { + A_001 a_020(); + } + public interface A_031 extends A_239 { + } + public interface A_089 extends A_239 { + A_089 a_098(); + } + public interface A_166 extends A_239 { + A_166 a_065(); + } + public interface A_054 extends A_239 { + A_054 a_000(); + } + public interface A_190 extends A_239 { + A_190 a_077(); + } + public interface A_169 extends A_239 { + A_169 a_037(); + } + public interface A_217 extends A_239 { + A_217 a_093(); + } + public interface A_078 extends A_239 { + A_078 a_016(); + } + public interface A_192 extends A_239 { + } + public interface A_222 extends A_239 { + A_222 a_095(); + } + public interface A_112 extends A_239 { + A_112 a_033(); + } + public interface A_066 extends A_239 { + A_066 a_049(); + } + public interface A_074 extends A_239 { + A_074 a_012(); + } + public interface A_003 extends A_239 { + A_003 a_039(); + } + public interface A_083 extends A_239 { + } + public interface A_050 extends A_239 { + A_050 a_070(); + } + public interface A_087 extends A_239 { + } + public interface A_058 extends A_239 { + } + public interface A_128 extends A_239 { + } + public interface A_092 extends A_239 { + } + public interface A_004 extends A_240 { + A_004 a_040(); + } + public interface A_115 extends A_239 { + A_115 a_039(); + } + public interface A_176 extends A_239 { + A_176 a_071(); + } + public interface A_162 extends A_239 { + } + public interface A_132 extends A_239 { + A_132 a_056(); + } + public interface A_064 extends A_239 { + A_064 a_047(); + } + public interface A_021 extends A_239 { + } + public interface A_160 extends A_239 { + } + public interface A_141 extends A_239 { + A_141 a_060(); + } + public interface A_091 extends A_239 { + A_091 a_026(); + } + public interface A_034 extends A_239 { + A_034 a_084(); + } + public interface A_151 extends A_239 { + } + public interface A_026 extends A_239 { + A_026 a_026(); + } + public interface A_130 extends A_239 { + A_130 a_052(); + } + public interface A_242 extends A_239 { + A_242 a_001(); + } + public interface A_205 extends A_239 { + A_205 a_086(); + } + public interface A_048 extends A_239 { + A_048 a_065(); + } + public interface A_044 extends A_240 { + A_044 a_040(); + } + public interface A_023 extends A_239 { + } + public interface A_027 extends A_239 { + } + public interface A_138 extends A_239 { + A_138 a_059(); + } + public interface A_024 extends A_239 { + A_024 a_011(); + } + public interface A_038 extends A_239 { + A_038 a_021(); + } + public interface A_016 extends A_239 { + } + public interface A_118 extends A_239 { + A_118 a_045(); + } + public interface A_071 extends A_239 { + A_071 a_011(); + } + public interface A_203 extends A_239 { + A_203 a_084(); + } + public interface A_137 extends A_239 { + } + public interface A_119 extends A_239 { + A_119 a_046(); + } + public interface A_145 extends A_239 { + } + public interface A_045 extends A_239 { + A_045 a_041(); + } + public interface A_069 extends A_239 { + A_069 a_010(); + } + public interface A_150 extends A_239 { + } + public interface A_047 extends A_239 { + A_047 a_057(); + } + public interface A_179 extends A_239 { + } + public interface A_207 extends A_239 { + A_207 a_088(); + } + public interface A_228 extends A_239 { + A_228 a_100(); + } + public interface A_005 extends A_240 { + A_005 a_040(); + } + public interface A_030 extends A_239 { + A_030 a_039(); + } + public interface A_173 extends A_239 { + A_173 a_069(); + } + public interface A_060 extends A_239 { + A_060 a_043(); + } + public interface A_245 extends A_239 { + A_245 a_009(); + } + public interface A_042 extends A_239 { + A_042 a_035(); + } + public interface A_209 extends A_239 { + A_209 a_090(); + } + public interface A_216 extends A_239 { + } + public interface A_142 extends A_239 { + } + public interface A_246 extends A_239 { + A_246 a_019(); + } + public interface A_223 extends A_239 { + } + public interface A_211 extends A_239 { + A_211 a_091(); + } + public interface A_244 extends A_239 { + A_244 a_008(); + } + public interface A_019 extends A_239 { + A_019 a_050(); + } + public interface A_041 extends A_239 { + A_041 a_034(); + } + public interface A_208 extends A_239 { + A_208 a_089(); + } + public interface A_065 extends A_239 { + } + public interface A_127 extends A_239 { + A_127 a_083(); + } + public interface A_033 extends A_239 { + } + public interface A_153 extends A_239 { + } + public interface A_079 extends A_239 { + } + public interface A_025 extends A_239 { + } + public interface A_046 extends A_239 { + A_046 a_042(); + } + public interface A_002 extends A_239 { + } + public interface A_154 extends A_239 { + } + public interface A_077 extends A_239 { + A_077 a_015(); + } + public interface A_121 extends A_239 { + A_121 a_053(); + } + public interface A_036 extends A_239 { + A_036 a_003(); + } + public interface A_225 extends A_239 { + A_225 a_054(); + } + public interface A_181 extends A_239 { + A_181 a_005(); + } + public interface A_134 extends A_239 { + A_134 a_057(); + } + public interface A_017 extends A_239 { + } + public interface A_194 extends A_239 { + A_194 a_081(); + } + public interface A_243 extends A_239 { + A_243 a_006(); + } + public interface A_015 extends A_239 { + A_015 a_004(); + } + public interface A_028 extends A_239 { + A_028 a_032(); + } + public interface A_218 extends A_239 { + } + public interface A_174 extends A_239 { + } + public interface A_039 extends A_239 { + A_039 a_023(); + } + public interface A_029 extends A_239 { + } + public interface A_095 extends A_239 { + A_095 a_029(); + } + public interface A_096 extends A_239 { + } + public interface A_124 extends A_239 { + A_124 a_028(); + } + public interface A_202 extends A_239 { + A_202 a_085(); + } + public interface A_186 extends A_239 { + } + public interface A_120 extends A_239 { + } + public interface A_076 extends A_239 { + A_076 a_014(); + } + public interface A_052 extends A_239 { + A_052 a_099(); + } + public interface A_056 extends A_239 { + } + public interface A_020 extends A_239 { + A_020 a_062(); + } + public interface A_018 extends A_239 { + A_018 a_045(); + } + public interface A_149 extends A_239 { + A_149 a_051(); + } + public interface A_022 extends A_239 { + A_022 a_075(); + } + public interface A_063 extends A_239 { + A_063 a_046(); + } + public interface A_043 extends A_239 { + A_043 a_038(); + } + public interface A_167 extends A_239 { + } + public interface A_085 extends A_239 { + A_085 a_018(); + } + public interface A_032 extends A_239 { + } + public interface A_188 extends A_239 { + A_188 a_076(); + } + public interface A_126 extends A_239 { + } + public interface A_113 extends A_239 { + A_113 a_032(); + } + public interface A_051 extends A_239 { + A_051 a_082(); + } + public interface A_185 extends A_239 { + A_185 a_074(); + } + public interface A_099 extends A_239 { + } + public interface A_062 extends A_239 { + A_062 a_045(); + } + public interface A_237 extends A_239 { + A_237 a_027(); + } + public interface A_100 extends A_239 { + } + public interface A_189 extends A_000, A_005, A_190, A_240 { + A_189 a_040(); + A_189 a_077(); + } + public interface A_061 extends A_239 { + A_061 a_044(); + } + public interface A_104 extends A_239 { + A_104 a_036(); + } + public interface A_084 extends A_000, A_005, A_085, A_240 { + A_084 a_040(); + A_084 a_018(); + } + public interface A_129 extends A_000, A_005, A_130, A_240 { + A_129 a_040(); + A_129 a_052(); + } + public interface A_086 extends A_000, A_005, A_087, A_089, A_240 { + A_086 a_040(); + A_086 a_024(); + A_086 a_098(); + } + public interface A_125 extends A_239 { + } + public interface A_212 extends A_053, A_084, A_005, A_054, A_085, A_217, + A_218, A_240 { + A_212 a_040(); + A_212 a_000(); + A_212 a_018(); + A_212 a_093(); + } + public interface A_171 extends A_170, A_175, A_005, A_173, A_176, A_174, + A_240 { + A_171 a_040(); + A_171 a_069(); + A_171 a_071(); + A_171 a_072(); + } + public interface A_247 extends A_239 { + } + public interface A_183 extends A_053, A_084, A_005, A_054, A_085, A_185, + A_186, A_240 { + A_183 a_040(); + A_183 a_000(); + A_183 a_018(); + A_183 a_074(); + } + public interface A_198 extends A_053, A_196, A_070, A_131, A_005, A_054, + A_203, A_071, A_132, A_240 { + A_198 a_040(); + A_198 a_000(); + A_198 a_084(); + A_198 a_011(); + A_198 a_056(); + } + public interface A_070 extends A_000, A_005, A_071, A_240 { + A_070 a_040(); + A_070 a_011(); + } + public interface A_109 extends A_106, A_212, A_005, A_115, A_113, A_112, + A_054, A_085, A_217, A_218, A_240 { + A_109 a_040(); + A_109 a_039(); + A_109 a_032(); + A_109 a_033(); + A_109 a_000(); + A_109 a_018(); + A_109 a_093(); + } + public interface A_158 extends A_159, A_161, A_152, A_005, A_054, A_160, + A_162, A_153, A_154, A_240 { + A_158 a_040(); + A_158 a_000(); + A_158 a_079(); + } + public interface A_110 extends A_106, A_212, A_183, A_005, A_054, A_085, + A_115, A_113, A_112, A_217, A_218, A_185, A_186, A_240 { + A_110 a_040(); + A_110 a_000(); + A_110 a_018(); + A_110 a_039(); + A_110 a_032(); + A_110 a_033(); + A_110 a_093(); + A_110 a_074(); + } + public interface A_200 extends A_000, A_005, A_202, A_240 { + A_200 a_040(); + A_200 a_085(); + } + public interface A_161 extends A_053, A_005, A_054, A_162, A_240 { + A_161 a_040(); + A_161 a_000(); + } + public interface A_175 extends A_000, A_005, A_176, A_240 { + A_175 a_040(); + A_175 a_071(); + } + public interface A_103 extends A_000, A_084, A_005, A_085, A_104, A_240 { + A_103 a_040(); + A_103 a_018(); + A_103 a_036(); + } + public interface A_093 extends A_090, A_152, A_005, A_054, A_085, A_091, + A_092, A_153, A_154, A_240 { + A_093 a_040(); + A_093 a_000(); + A_093 a_018(); + A_093 a_026(); + A_093 a_079(); + A_093 a_027(); + } + public interface A_204 extends A_000, A_005, A_205, A_240 { + A_204 a_040(); + A_204 a_086(); + } + public interface A_067 extends A_059, A_152, A_005, A_054, A_085, A_063, + A_062, A_064, A_065, A_066, A_061, A_060, A_153, A_154, A_240 { + A_067 a_040(); + A_067 a_000(); + A_067 a_018(); + A_067 a_046(); + A_067 a_045(); + A_067 a_047(); + A_067 a_049(); + A_067 a_044(); + A_067 a_043(); + A_067 a_079(); + } + public interface A_101 extends A_070, A_005, A_071, A_240 { + A_101 a_040(); + A_101 a_011(); + } + public interface A_224 extends A_000, A_225, A_240 { + A_224 a_054(); + A_224 a_040(); + } + public interface A_156 extends A_053, A_084, A_155, A_059, A_005, A_054, + A_085, A_160, A_162, A_063, A_062, A_064, A_065, A_066, A_061, + A_060, A_240 { + A_156 a_040(); + A_156 a_000(); + A_156 a_018(); + A_156 a_046(); + A_156 a_045(); + A_156 a_047(); + A_156 a_049(); + A_156 a_044(); + A_156 a_043(); + } + public interface A_122 extends A_116, A_152, A_005, A_054, A_085, A_121, + A_119, A_118, A_120, A_153, A_154, A_240 { + A_122 a_040(); + A_122 a_000(); + A_122 a_018(); + A_122 a_053(); + A_122 a_046(); + A_122 a_045(); + A_122 a_048(); + A_122 a_079(); + A_122 a_080(); + } + public interface A_184 extends A_183, A_152, A_005, A_054, A_085, A_185, + A_186, A_153, A_154, A_240 { + A_184 a_040(); + A_184 a_000(); + A_184 a_018(); + A_184 a_074(); + A_184 a_079(); + } + public interface A_180 extends A_000, A_181, A_240 { + A_180 a_005(); + A_180 a_040(); + } + public interface A_191 extends A_000, A_005, A_192, A_240 { + A_191 a_040(); + A_191 a_078(); + } + public interface A_107 extends A_106, A_094, A_005, A_115, A_113, A_112, + A_095, A_096, A_240 { + A_107 a_040(); + A_107 a_039(); + A_107 a_032(); + A_107 a_033(); + A_107 a_029(); + A_107 a_000(); + A_107 a_018(); + } + public interface A_102 extends A_196, A_005, A_203, A_240 { + A_102 a_040(); + A_102 a_084(); + } + public interface A_177 extends A_000, A_005, A_179, A_240 { + A_177 a_040(); + } + public interface A_123 extends A_195, A_005, A_054, A_124, A_127, A_128, + A_126, A_125, A_240 { + A_123 a_040(); + A_123 a_000(); + A_123 a_028(); + A_123 a_083(); + A_123 a_064(); + A_123 a_055(); + A_123 a_018(); + A_123 a_079(); + A_123 a_080(); + A_123 a_081(); + A_123 a_077(); + A_123 a_036(); + A_123 a_056(); + A_123 a_012(); + A_123 a_078(); + A_123 a_076(); + A_123 a_057(); + } + public interface A_088 extends A_106, A_086, A_240 { + A_088 a_040(); + A_088 a_039(); + A_088 a_032(); + A_088 a_033(); + A_088 a_000(); + A_088 a_018(); + A_088 a_024(); + A_088 a_098(); + } + public interface A_094 extends A_084, A_005, A_085, A_095, A_096, A_240 { + A_094 a_040(); + A_094 a_018(); + A_094 a_029(); + } + public interface A_105 extends A_098, A_236, A_005, A_085, A_153, A_074, + A_099, A_100, A_240 { + A_105 a_040(); + A_105 a_018(); + A_105 a_079(); + A_105 a_012(); + A_105 a_030(); + A_105 a_031(); + A_105 a_000(); + A_105 a_081(); + A_105 a_077(); + A_105 a_036(); + A_105 a_056(); + A_105 a_078(); + A_105 a_076(); + A_105 a_057(); + } + public interface A_199 extends A_196, A_090, A_005, A_054, A_085, A_091, + A_092, A_203, A_240 { + A_199 a_040(); + A_199 a_000(); + A_199 a_018(); + A_199 a_026(); + A_199 a_084(); + A_199 a_027(); + } + public interface A_080 extends A_075, A_236, A_005, A_085, A_153, A_074, + A_076, A_077, A_078, A_079, A_240 { + A_080 a_040(); + A_080 a_018(); + A_080 a_079(); + A_080 a_012(); + A_080 a_014(); + A_080 a_015(); + A_080 a_016(); + A_080 a_000(); + A_080 a_080(); + A_080 a_081(); + A_080 a_077(); + A_080 a_036(); + A_080 a_056(); + A_080 a_078(); + A_080 a_076(); + A_080 a_057(); + } + public interface A_172 extends A_170, A_219, A_005, A_054, A_085, A_173, + A_222, A_223, A_174, A_240 { + A_172 a_040(); + A_172 a_000(); + A_172 a_018(); + A_172 a_069(); + A_172 a_095(); + A_172 a_072(); + } + public interface A_108 extends A_106, A_180, A_206, A_005, A_115, A_113, + A_112, A_181, A_208, A_207, A_209, A_240 { + A_108 a_040(); + A_108 a_039(); + A_108 a_032(); + A_108 a_033(); + A_108 a_005(); + A_108 a_089(); + A_108 a_088(); + A_108 a_090(); + A_108 a_000(); + A_108 a_018(); + } + public interface A_195 extends A_053, A_084, A_152, A_193, A_189, A_103, + A_131, A_073, A_191, A_187, A_133, A_005, A_054, A_085, A_153, + A_154, A_194, A_190, A_104, A_132, A_074, A_192, A_188, A_134, + A_240 { + A_195 a_040(); + A_195 a_000(); + A_195 a_018(); + A_195 a_079(); + A_195 a_080(); + A_195 a_081(); + A_195 a_077(); + A_195 a_036(); + A_195 a_056(); + A_195 a_012(); + A_195 a_078(); + A_195 a_076(); + A_195 a_057(); + } + public interface A_220 extends A_219, A_236, A_005, A_085, A_153, A_074, + A_240 { + A_220 a_040(); + A_220 a_018(); + A_220 a_079(); + A_220 a_012(); + A_220 a_000(); + A_220 a_095(); + A_220 a_080(); + A_220 a_081(); + A_220 a_077(); + A_220 a_036(); + A_220 a_056(); + A_220 a_078(); + A_220 a_076(); + A_220 a_057(); + } + public interface A_146 extends A_000, A_005, A_151, A_150, A_149, A_240 { + A_146 a_040(); + A_146 a_073(); + A_146 a_051(); + } + public interface A_090 extends A_000, A_053, A_084, A_005, A_054, A_085, + A_237, A_091, A_092, A_240 { + A_090 a_040(); + A_090 a_000(); + A_090 a_018(); + A_090 a_027(); + A_090 a_026(); + } + public interface A_057 extends A_106, A_058, A_240 { + A_057 a_002(); + A_057 a_040(); + A_057 a_039(); + A_057 a_032(); + A_057 a_033(); + A_057 a_000(); + A_057 a_018(); + } + public interface A_098 extends A_084, A_005, A_085, A_099, A_100, A_240 { + } + public interface A_136 extends A_084, A_005, A_085, A_138, A_137, A_240 { + } + public interface A_116 extends A_053, A_084, A_005, A_054, A_085, A_121, + A_119, A_118, A_120, A_240 { + A_116 a_040(); + A_116 a_000(); + A_116 a_018(); + A_116 a_053(); + A_116 a_046(); + A_116 a_045(); + A_116 a_048(); + } + public interface A_159 extends A_053, A_005, A_054, A_160, A_240 { + A_159 a_040(); + A_159 a_000(); + } + public interface A_140 extends A_139, A_236, A_005, A_085, A_153, A_074, + A_141, A_142, A_240 { + A_140 a_040(); + A_140 a_018(); + A_140 a_079(); + A_140 a_012(); + A_140 a_060(); + A_140 a_061(); + A_140 a_000(); + A_140 a_080(); + A_140 a_081(); + A_140 a_077(); + A_140 a_036(); + A_140 a_056(); + A_140 a_078(); + A_140 a_076(); + A_140 a_057(); + } + public interface A_178 extends A_177, A_144, A_005, A_179, A_145, A_240 { + A_178 a_040(); + } + public interface A_139 extends A_053, A_005, A_054, A_141, A_142, A_240 { + A_139 a_040(); + A_139 a_000(); + A_139 a_060(); + A_139 a_061(); + } + public interface A_165 extends A_163, A_152, A_005, A_054, A_166, A_167, + A_153, A_154, A_240 { + A_165 a_040(); + A_165 a_000(); + A_165 a_065(); + A_165 a_066(); + A_165 a_079(); + A_165 a_080(); + } + public interface A_053 extends A_000, A_238<Long>, A_005, A_054, A_240 { + A_053 a_040(); + A_053 a_000(); + } + public interface A_135 extends A_136, A_236, A_005, A_085, A_153, A_074, + A_138, A_137, A_240 { + A_135 a_040(); + A_135 a_018(); + A_135 a_079(); + A_135 a_012(); + A_135 a_059(); + A_135 a_058(); + A_135 a_000(); + A_135 a_081(); + A_135 a_077(); + A_135 a_036(); + A_135 a_056(); + A_135 a_078(); + A_135 a_076(); + A_135 a_057(); + } + public interface A_148 extends A_146, A_236, A_005, A_085, A_153, A_074, + A_240 { + A_148 a_040(); + A_148 a_018(); + A_148 a_079(); + A_148 a_012(); + A_148 a_051(); + A_148 a_000(); + A_148 a_081(); + A_148 a_077(); + A_148 a_036(); + A_148 a_056(); + A_148 a_078(); + A_148 a_076(); + A_148 a_057(); + } + public interface A_206 extends A_000, A_005, A_208, A_207, A_209, A_240 { + A_206 a_040(); + A_206 a_089(); + A_206 a_088(); + A_206 a_090(); + } + public interface A_215 extends A_000, A_005, A_216, A_240 { + A_215 a_040(); + A_215 a_092(); + } + public interface A_117 extends A_116, A_090, A_005, A_054, A_085, A_121, + A_119, A_118, A_120, A_091, A_092, A_240 { + A_117 a_040(); + A_117 a_000(); + A_117 a_018(); + A_117 a_053(); + A_117 a_046(); + A_117 a_045(); + A_117 a_048(); + A_117 a_026(); + A_117 a_027(); + } + public interface A_082 extends A_000, A_005, A_083, A_240 { + A_082 a_040(); + } + public interface A_182 extends A_053, A_084, A_152, A_193, A_189, A_005, + A_054, A_085, A_153, A_154, A_194, A_190, A_240 { + A_182 a_040(); + A_182 a_000(); + A_182 a_018(); + A_182 a_079(); + A_182 a_080(); + A_182 a_081(); + A_182 a_077(); + } + public interface A_055 extends A_000, A_005, A_056, A_240 { + } + public interface A_193 extends A_000, A_005, A_194, A_240 { + A_193 a_040(); + A_193 a_081(); + } + public interface A_214 extends A_212, A_152, A_005, A_054, A_085, A_217, + A_218, A_153, A_154, A_240 { + A_214 a_040(); + A_214 a_000(); + A_214 a_018(); + A_214 a_093(); + A_214 a_079(); + } + public interface A_059 extends A_053, A_084, A_005, A_054, A_085, A_063, + A_062, A_064, A_065, A_066, A_061, A_060, A_240 { + A_059 a_040(); + A_059 a_000(); + A_059 a_018(); + A_059 a_046(); + A_059 a_045(); + A_059 a_047(); + A_059 a_048(); + A_059 a_049(); + A_059 a_044(); + A_059 a_043(); + } + public interface A_226 extends A_000, A_228, A_240 { + A_226 a_100(); + A_226 a_040(); + } + public interface A_210 extends A_053, A_005, A_054, A_211, A_240 { + A_210 a_040(); + A_210 a_000(); + A_210 a_091(); + } + public interface A_073 extends A_000, A_005, A_074, A_240 { + A_073 a_040(); + A_073 a_012(); + } + public interface A_157 extends A_155, A_236, A_005, A_085, A_153, A_074, + A_160, A_162, A_240 { + A_157 a_040(); + A_157 a_018(); + A_157 a_079(); + A_157 a_012(); + A_157 a_000(); + A_157 a_081(); + A_157 a_077(); + A_157 a_036(); + A_157 a_056(); + A_157 a_078(); + A_157 a_076(); + A_157 a_057(); + } + public interface A_131 extends A_053, A_005, A_054, A_132, A_240 { + A_131 a_040(); + A_131 a_000(); + A_131 a_056(); + } + public interface A_152 extends A_053, A_005, A_054, A_153, A_154, A_240 { + A_152 a_040(); + A_152 a_000(); + A_152 a_079(); + } + public interface A_106 extends A_053, A_084, A_005, A_115, A_113, A_112, + A_240 { + A_106 a_040(); + A_106 a_039(); + A_106 a_032(); + A_106 a_033(); + A_106 a_000(); + A_106 a_018(); + } + public interface A_147 extends A_106, A_236, A_005, A_085, A_153, A_074, + A_240 { + A_147 a_040(); + A_147 a_018(); + A_147 a_012(); + A_147 a_039(); + A_147 a_032(); + A_147 a_033(); + A_147 a_000(); + A_147 a_081(); + A_147 a_077(); + A_147 a_036(); + A_147 a_056(); + A_147 a_078(); + A_147 a_076(); + A_147 a_057(); + } + public interface A_081 extends A_075, A_152, A_005, A_054, A_076, A_077, + A_078, A_079, A_153, A_154, A_240 { + A_081 a_040(); + A_081 a_000(); + A_081 a_014(); + A_081 a_015(); + A_081 a_016(); + A_081 a_079(); + A_081 a_080(); + } + public interface A_197 extends A_196, A_070, A_236, A_005, A_085, A_153, + A_074, A_203, A_071, A_240 { + A_197 a_040(); + A_197 a_018(); + A_197 a_079(); + A_197 a_012(); + A_197 a_084(); + A_197 a_011(); + A_197 a_000(); + A_197 a_081(); + A_197 a_077(); + A_197 a_036(); + A_197 a_056(); + A_197 a_078(); + A_197 a_076(); + A_197 a_057(); + } + public interface A_213 extends A_212, A_215, A_236, A_005, A_085, A_153, + A_074, A_240 { + A_213 a_040(); + A_213 a_018(); + A_213 a_079(); + A_213 a_012(); + A_213 a_000(); + A_213 a_093(); + A_213 a_092(); + A_213 a_081(); + A_213 a_077(); + A_213 a_036(); + A_213 a_056(); + A_213 a_078(); + A_213 a_076(); + A_213 a_057(); + } + public interface A_143 extends A_139, A_152, A_005, A_141, A_142, A_153, + A_154, A_240 { + A_143 a_040(); + A_143 a_060(); + A_143 a_061(); + A_143 a_079(); + A_143 a_080(); + A_143 a_000(); + } + public interface A_221 extends A_219, A_152, A_005, A_054, A_085, A_222, + A_223, A_153, A_154, A_240 { + A_221 a_040(); + A_221 a_000(); + A_221 a_018(); + A_221 a_095(); + A_221 a_079(); + A_221 a_080(); + } + public interface A_196 extends A_000, A_005, A_203, A_240 { + A_196 a_040(); + A_196 a_084(); + } + public interface A_155 extends A_159, A_161, A_005, A_054, A_160, A_162, + A_240 { + A_155 a_040(); + A_155 a_000(); + } + public interface A_097 extends A_094, A_152, A_005, A_085, A_095, A_096, + A_153, A_154, A_240 { + A_097 a_040(); + A_097 a_018(); + A_097 a_029(); + A_097 a_079(); + A_097 a_000(); + } + public interface A_219 extends A_053, A_084, A_005, A_054, A_085, A_222, + A_223, A_240 { + A_219 a_040(); + A_219 a_000(); + A_219 a_018(); + A_219 a_095(); + A_219 a_096(); + } + public interface A_068 extends A_053, A_005, A_054, A_069, A_240 { + A_068 a_040(); + A_068 a_000(); + A_068 a_010(); + } + public interface A_114 extends A_106, A_236, A_005, A_085, A_153, A_074, + A_115, A_113, A_240 { + A_114 a_040(); + A_114 a_018(); + A_114 a_079(); + A_114 a_012(); + A_114 a_039(); + A_114 a_032(); + A_114 a_033(); + A_114 a_000(); + A_114 a_080(); + A_114 a_081(); + A_114 a_077(); + A_114 a_036(); + A_114 a_056(); + A_114 a_078(); + A_114 a_076(); + A_114 a_057(); + } + public interface A_163 extends A_053, A_005, A_054, A_166, A_167, A_240 { + A_163 a_040(); + A_163 a_000(); + A_163 a_065(); + A_163 a_066(); + } + public interface A_187 extends A_000, A_005, A_188, A_240 { + A_187 a_040(); + A_187 a_076(); + } + public interface A_144 extends A_000, A_005, A_145, A_240 { + A_144 a_040(); + } + public interface A_111 extends A_106, A_212, A_219, A_170, A_005, A_054, + A_085, A_115, A_113, A_112, A_217, A_218, A_222, A_223, A_173, + A_240 { + A_111 a_040(); + A_111 a_000(); + A_111 a_018(); + A_111 a_039(); + A_111 a_032(); + A_111 a_033(); + A_111 a_093(); + A_111 a_095(); + A_111 a_069(); + } + public interface A_168 extends A_000, A_053, A_005, A_054, A_169, A_240 { + A_168 a_040(); + A_168 a_000(); + A_168 a_037(); + } + public interface A_227 extends A_226, A_236, A_005, A_085, A_153, A_074, + A_228, A_240 { + A_227 a_040(); + A_227 a_018(); + A_227 a_079(); + A_227 a_012(); + A_227 a_100(); + A_227 a_000(); + A_227 a_081(); + A_227 a_077(); + A_227 a_036(); + A_227 a_056(); + A_227 a_078(); + A_227 a_076(); + A_227 a_057(); + } + public interface A_075 extends A_053, A_005, A_054, A_076, A_077, A_078, + A_079, A_240 { + A_075 a_040(); + A_075 a_000(); + A_075 a_014(); + A_075 a_015(); + A_075 a_016(); + A_075 a_017(); + } + public interface A_008 extends A_239 { + A_008 a_040(); + } + public interface A_072 extends A_070, A_090, A_005, A_054, A_085, A_091, + A_092, A_071, A_240 { + A_072 a_040(); + A_072 a_000(); + A_072 a_018(); + A_072 a_026(); + A_072 a_011(); + A_072 a_027(); + } + public interface A_170 extends A_000, A_005, A_173, A_174, A_240 { + A_170 a_040(); + A_170 a_069(); + A_170 a_072(); + } + public interface A_012 extends A_239 { + A_012 a_063(); + } + public interface A_164 extends A_163, A_236, A_005, A_085, A_153, A_074, + A_166, A_167, A_240 { + A_164 a_040(); + A_164 a_018(); + A_164 a_079(); + A_164 a_012(); + A_164 a_065(); + A_164 a_066(); + A_164 a_000(); + A_164 a_080(); + A_164 a_081(); + A_164 a_077(); + A_164 a_036(); + A_164 a_056(); + A_164 a_078(); + A_164 a_076(); + A_164 a_057(); + } + public interface A_006 extends A_239 { + A_006 a_004(); + } + public interface A_007 extends A_239 { + } + public interface A_201 extends A_200, A_236, A_005, A_085, A_153, A_074, + A_240 { + A_201 a_040(); + A_201 a_018(); + A_201 a_079(); + A_201 a_012(); + A_201 a_085(); + A_201 a_000(); + A_201 a_081(); + A_201 a_077(); + A_201 a_036(); + A_201 a_056(); + A_201 a_078(); + A_201 a_076(); + A_201 a_057(); + } + public interface A_011 extends A_239 { + A_011 a_062(); + } + public interface A_014 extends A_239 { + A_014 a_075(); + } + public interface A_009 extends A_239 { + A_009 a_045(); + } + public interface A_010 extends A_239 { + A_010 a_050(); + } + public interface A_013 extends A_239 { + A_013 a_067(); + } + public interface A_236 extends A_195, A_005, A_085, A_153, A_074, A_240 { + A_236 a_040(); + A_236 a_018(); + A_236 a_079(); + A_236 a_012(); + A_236 a_000(); + A_236 a_081(); + A_236 a_077(); + A_236 a_036(); + A_236 a_056(); + A_236 a_078(); + A_236 a_076(); + A_236 a_057(); + } + interface X_1 { AbstractList x_8(); diff --git a/test/jdk/java/foreign/CallGeneratorHelper.java b/test/jdk/java/foreign/CallGeneratorHelper.java index 9a795525e1f323304e17bae4b8ed2aa2f6dc462b..a69fe1a5d81b99b71a65d6efbd5e1513e516a201 100644 --- a/test/jdk/java/foreign/CallGeneratorHelper.java +++ b/test/jdk/java/foreign/CallGeneratorHelper.java @@ -22,14 +22,19 @@ * */ +import jdk.incubator.foreign.Addressable; +import jdk.incubator.foreign.CLinker; +import jdk.incubator.foreign.FunctionDescriptor; import jdk.incubator.foreign.GroupLayout; import jdk.incubator.foreign.MemoryAddress; import jdk.incubator.foreign.MemoryLayout; import jdk.incubator.foreign.MemorySegment; +import jdk.incubator.foreign.NativeSymbol; import jdk.incubator.foreign.ResourceScope; import jdk.incubator.foreign.SegmentAllocator; import jdk.incubator.foreign.ValueLayout; +import java.lang.invoke.MethodHandle; import java.lang.invoke.VarHandle; import java.util.ArrayList; import java.util.List; @@ -40,12 +45,13 @@ import java.util.stream.IntStream; import org.testng.annotations.*; -import static jdk.incubator.foreign.CLinker.*; import static org.testng.Assert.*; public class CallGeneratorHelper extends NativeTestHelper { - static SegmentAllocator IMPLICIT_ALLOCATOR = (size, align) -> MemorySegment.allocateNative(size, align, ResourceScope.newImplicitScope()); + static SegmentAllocator THROWING_ALLOCATOR = (size, align) -> { + throw new UnsupportedOperationException(); + }; static final int SAMPLE_FACTOR = Integer.parseInt((String)System.getProperties().getOrDefault("generator.sample.factor", "-1")); @@ -58,7 +64,7 @@ public class CallGeneratorHelper extends NativeTestHelper { GroupLayout g = (GroupLayout) layout; for (MemoryLayout field : g.memberLayouts()) { if (field instanceof ValueLayout) { - VarHandle vh = g.varHandle(vhCarrier(field), MemoryLayout.PathElement.groupElement(field.name().orElseThrow())); + VarHandle vh = g.varHandle(MemoryLayout.PathElement.groupElement(field.name().orElseThrow())); assertEquals(vh.get(actual), vh.get(expected)); } } @@ -410,12 +416,9 @@ public class CallGeneratorHelper extends NativeTestHelper { static void initStruct(MemorySegment str, GroupLayout g, List<Consumer<Object>> checks, boolean check) throws ReflectiveOperationException { for (MemoryLayout l : g.memberLayouts()) { if (l.isPadding()) continue; - VarHandle accessor = g.varHandle(structFieldCarrier(l), MemoryLayout.PathElement.groupElement(l.name().get())); + VarHandle accessor = g.varHandle(MemoryLayout.PathElement.groupElement(l.name().get())); List<Consumer<Object>> fieldsCheck = new ArrayList<>(); Object value = makeArg(l, fieldsCheck, check); - if (isPointer(l)) { - value = ((MemoryAddress)value).toRawLongValue(); - } //set value accessor.set(str, value); //add check @@ -424,11 +427,7 @@ public class CallGeneratorHelper extends NativeTestHelper { checks.add(o -> { MemorySegment actual = (MemorySegment)o; try { - if (isPointer(l)) { - fieldsCheck.get(0).accept(MemoryAddress.ofLong((long)accessor.get(actual))); - } else { - fieldsCheck.get(0).accept(accessor.get(actual)); - } + fieldsCheck.get(0).accept(accessor.get(actual)); } catch (Throwable ex) { throw new IllegalStateException(ex); } @@ -437,37 +436,23 @@ public class CallGeneratorHelper extends NativeTestHelper { } } - static Class<?> structFieldCarrier(MemoryLayout layout) { - if (isPointer(layout)) { - return long.class; - } else if (layout instanceof ValueLayout) { - if (isIntegral(layout)) { - return int.class; - } else if (layout.bitSize() == 32) { - return float.class; - } else { - return double.class; - } - } else { - throw new IllegalStateException("Unexpected layout: " + layout); - } - } - - static Class<?> paramCarrier(MemoryLayout layout) { + static Class<?> carrier(MemoryLayout layout, boolean param) { if (layout instanceof GroupLayout) { return MemorySegment.class; } if (isPointer(layout)) { - return MemoryAddress.class; - } else if (layout instanceof ValueLayout) { - if (isIntegral(layout)) { - return int.class; - } else if (layout.bitSize() == 32) { - return float.class; - } else { - return double.class; - } + return param ? Addressable.class : MemoryAddress.class; + } else if (layout instanceof ValueLayout valueLayout) { + return valueLayout.carrier(); } else { throw new IllegalStateException("Unexpected layout: " + layout); } } + + MethodHandle downcallHandle(CLinker abi, NativeSymbol symbol, SegmentAllocator allocator, FunctionDescriptor descriptor) { + MethodHandle mh = abi.downcallHandle(symbol, descriptor); + if (descriptor.returnLayout().isPresent() && descriptor.returnLayout().get() instanceof GroupLayout) { + mh = mh.bindTo(allocator); + } + return mh; + } } diff --git a/test/jdk/java/foreign/NativeTestHelper.java b/test/jdk/java/foreign/NativeTestHelper.java index 9b57beac732eef0dd5e0bc2a836fb79837078c73..ca789f984f8142ddb0afcd610b5d237ab9acc983 100644 --- a/test/jdk/java/foreign/NativeTestHelper.java +++ b/test/jdk/java/foreign/NativeTestHelper.java @@ -22,58 +22,90 @@ * */ +import jdk.incubator.foreign.Addressable; import jdk.incubator.foreign.CLinker; +import jdk.incubator.foreign.FunctionDescriptor; +import jdk.incubator.foreign.MemoryAddress; import jdk.incubator.foreign.MemoryLayout; import jdk.incubator.foreign.MemorySegment; import jdk.incubator.foreign.ResourceScope; import jdk.incubator.foreign.SegmentAllocator; +import jdk.incubator.foreign.ValueLayout; + +import java.lang.invoke.MethodHandle; public class NativeTestHelper { - static CLinker.TypeKind kind(MemoryLayout layout) { - return (CLinker.TypeKind)layout.attribute(CLinker.TypeKind.ATTR_NAME).orElseThrow( - () -> new IllegalStateException("Unexpected value layout: could not determine ABI class")); + public static boolean isIntegral(MemoryLayout layout) { + return layout instanceof ValueLayout valueLayout && isIntegral(valueLayout.carrier()); } - public static boolean isIntegral(MemoryLayout layout) { - return kind(layout).isIntegral(); + static boolean isIntegral(Class<?> clazz) { + return clazz == byte.class || clazz == char.class || clazz == short.class + || clazz == int.class || clazz == long.class; } public static boolean isPointer(MemoryLayout layout) { - return kind(layout).isPointer(); + return layout instanceof ValueLayout valueLayout && valueLayout.carrier() == MemoryAddress.class; } - public static class NativeScope implements SegmentAllocator, AutoCloseable { - final ResourceScope resourceScope; - final ResourceScope.Handle scopeHandle; - final SegmentAllocator allocator; + // the constants below are useful aliases for C types. The type/carrier association is only valid for 64-bit platforms. - long allocatedBytes = 0; + /** + * The layout for the {@code bool} C type + */ + public static final ValueLayout.OfBoolean C_BOOL = ValueLayout.JAVA_BOOLEAN; + /** + * The layout for the {@code char} C type + */ + public static final ValueLayout.OfByte C_CHAR = ValueLayout.JAVA_BYTE; + /** + * The layout for the {@code short} C type + */ + public static final ValueLayout.OfShort C_SHORT = ValueLayout.JAVA_SHORT.withBitAlignment(16); + /** + * The layout for the {@code int} C type + */ + public static final ValueLayout.OfInt C_INT = ValueLayout.JAVA_INT.withBitAlignment(32); - public NativeScope() { - this.resourceScope = ResourceScope.newConfinedScope(); - this.scopeHandle = resourceScope.acquire(); - this.allocator = SegmentAllocator.arenaAllocator(resourceScope); - } + /** + * The layout for the {@code long long} C type. + */ + public static final ValueLayout.OfLong C_LONG_LONG = ValueLayout.JAVA_LONG.withBitAlignment(64); + /** + * The layout for the {@code float} C type + */ + public static final ValueLayout.OfFloat C_FLOAT = ValueLayout.JAVA_FLOAT.withBitAlignment(32); + /** + * The layout for the {@code double} C type + */ + public static final ValueLayout.OfDouble C_DOUBLE = ValueLayout.JAVA_DOUBLE.withBitAlignment(64); + /** + * The {@code T*} native type. + */ + public static final ValueLayout.OfAddress C_POINTER = ValueLayout.ADDRESS.withBitAlignment(64); - @Override - public MemorySegment allocate(long bytesSize, long bytesAlignment) { - allocatedBytes += bytesSize; - return allocator.allocate(bytesSize, bytesAlignment); - } + private static CLinker LINKER = CLinker.systemCLinker(); - public ResourceScope scope() { - return resourceScope; - } + private static final MethodHandle FREE = LINKER.downcallHandle( + LINKER.lookup("free").get(), FunctionDescriptor.ofVoid(ValueLayout.ADDRESS)); - public long allocatedBytes() { - return allocatedBytes; + private static final MethodHandle MALLOC = LINKER.downcallHandle( + LINKER.lookup("malloc").get(), FunctionDescriptor.of(ValueLayout.ADDRESS, ValueLayout.JAVA_LONG)); + + public static void freeMemory(Addressable address) { + try { + FREE.invokeExact(address); + } catch (Throwable ex) { + throw new IllegalStateException(ex); } + } - @Override - public void close() { - resourceScope.release(scopeHandle); - resourceScope.close(); + public static MemoryAddress allocateMemory(long size) { + try { + return (MemoryAddress)MALLOC.invokeExact(size); + } catch (Throwable ex) { + throw new IllegalStateException(ex); } } } diff --git a/test/jdk/java/foreign/SafeFunctionAccessTest.java b/test/jdk/java/foreign/SafeFunctionAccessTest.java index b6801ad8888072fba063f14d31a986e4bd88e930..5c45f42cc2635d49c7d451b42a7a941c0267b112 100644 --- a/test/jdk/java/foreign/SafeFunctionAccessTest.java +++ b/test/jdk/java/foreign/SafeFunctionAccessTest.java @@ -27,27 +27,31 @@ * @run testng/othervm --enable-native-access=ALL-UNNAMED SafeFunctionAccessTest */ +import jdk.incubator.foreign.Addressable; import jdk.incubator.foreign.CLinker; import jdk.incubator.foreign.FunctionDescriptor; +import jdk.incubator.foreign.NativeSymbol; import jdk.incubator.foreign.SymbolLookup; -import jdk.incubator.foreign.MemoryAddress; import jdk.incubator.foreign.MemoryLayout; import jdk.incubator.foreign.MemorySegment; import jdk.incubator.foreign.ResourceScope; import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; +import jdk.incubator.foreign.VaList; import org.testng.annotations.*; + import static org.testng.Assert.*; -public class SafeFunctionAccessTest { +public class SafeFunctionAccessTest extends NativeTestHelper { static { System.loadLibrary("SafeAccess"); } static MemoryLayout POINT = MemoryLayout.structLayout( - CLinker.C_INT, CLinker.C_INT + C_INT, C_INT ); static final SymbolLookup LOOKUP = SymbolLookup.loaderLookup(); @@ -59,26 +63,135 @@ public class SafeFunctionAccessTest { segment = MemorySegment.allocateNative(POINT, scope); } assertFalse(segment.scope().isAlive()); - MethodHandle handle = CLinker.getInstance().downcallHandle( + MethodHandle handle = CLinker.systemCLinker().downcallHandle( LOOKUP.lookup("struct_func").get(), - MethodType.methodType(void.class, MemorySegment.class), FunctionDescriptor.ofVoid(POINT)); handle.invokeExact(segment); } + @Test + public void testClosedStructAddr_6() throws Throwable { + MethodHandle handle = CLinker.systemCLinker().downcallHandle( + LOOKUP.lookup("addr_func_6").get(), + FunctionDescriptor.ofVoid(C_POINTER, C_POINTER, C_POINTER, C_POINTER, C_POINTER, C_POINTER)); + for (int i = 0 ; i < 6 ; i++) { + MemorySegment[] segments = new MemorySegment[]{ + MemorySegment.allocateNative(POINT, ResourceScope.newImplicitScope()), + MemorySegment.allocateNative(POINT, ResourceScope.newImplicitScope()), + MemorySegment.allocateNative(POINT, ResourceScope.newImplicitScope()), + MemorySegment.allocateNative(POINT, ResourceScope.newImplicitScope()), + MemorySegment.allocateNative(POINT, ResourceScope.newImplicitScope()), + MemorySegment.allocateNative(POINT, ResourceScope.newImplicitScope()) + }; + // check liveness + segments[i].scope().close(); + for (int j = 0 ; j < 6 ; j++) { + if (i == j) { + assertFalse(segments[j].scope().isAlive()); + } else { + assertTrue(segments[j].scope().isAlive()); + } + } + try { + handle.invokeWithArguments(segments); + fail(); + } catch (IllegalStateException ex) { + assertTrue(ex.getMessage().contains("Already closed")); + } + for (int j = 0 ; j < 6 ; j++) { + if (i != j) { + segments[j].scope().close(); // should succeed! + } + } + } + } + @Test(expectedExceptions = IllegalStateException.class) - public void testClosedPointer() throws Throwable { - MemoryAddress address; + public void testClosedVaList() throws Throwable { + VaList list; try (ResourceScope scope = ResourceScope.newConfinedScope()) { - address = MemorySegment.allocateNative(POINT, scope).address(); + list = VaList.make(b -> b.addVarg(C_INT, 42), scope); } - assertFalse(address.scope().isAlive()); - MethodHandle handle = CLinker.getInstance().downcallHandle( + assertFalse(list.scope().isAlive()); + MethodHandle handle = CLinker.systemCLinker().downcallHandle( LOOKUP.lookup("addr_func").get(), - MethodType.methodType(void.class, MemoryAddress.class), - FunctionDescriptor.ofVoid(CLinker.C_POINTER)); + FunctionDescriptor.ofVoid(C_POINTER)); - handle.invokeExact(address); + handle.invokeExact((Addressable)list); + } + + @Test(expectedExceptions = IllegalStateException.class) + public void testClosedUpcall() throws Throwable { + NativeSymbol upcall; + try (ResourceScope scope = ResourceScope.newConfinedScope()) { + MethodHandle dummy = MethodHandles.lookup().findStatic(SafeFunctionAccessTest.class, "dummy", MethodType.methodType(void.class)); + upcall = CLinker.systemCLinker().upcallStub(dummy, FunctionDescriptor.ofVoid(), scope); + } + assertFalse(upcall.scope().isAlive()); + MethodHandle handle = CLinker.systemCLinker().downcallHandle( + LOOKUP.lookup("addr_func").get(), + FunctionDescriptor.ofVoid(C_POINTER)); + + handle.invokeExact((Addressable)upcall); + } + + static void dummy() { } + + @Test + public void testClosedVaListCallback() throws Throwable { + MethodHandle handle = CLinker.systemCLinker().downcallHandle( + LOOKUP.lookup("addr_func_cb").get(), + FunctionDescriptor.ofVoid(C_POINTER, C_POINTER)); + + try (ResourceScope scope = ResourceScope.newConfinedScope()) { + VaList list = VaList.make(b -> b.addVarg(C_INT, 42), scope); + handle.invoke(list, scopeChecker(scope)); + } + } + + @Test + public void testClosedStructCallback() throws Throwable { + MethodHandle handle = CLinker.systemCLinker().downcallHandle( + LOOKUP.lookup("addr_func_cb").get(), + FunctionDescriptor.ofVoid(C_POINTER, C_POINTER)); + + try (ResourceScope scope = ResourceScope.newConfinedScope()) { + MemorySegment segment = MemorySegment.allocateNative(POINT, scope); + handle.invoke(segment, scopeChecker(scope)); + } + } + + @Test + public void testClosedUpcallCallback() throws Throwable { + MethodHandle handle = CLinker.systemCLinker().downcallHandle( + LOOKUP.lookup("addr_func_cb").get(), + FunctionDescriptor.ofVoid(C_POINTER, C_POINTER)); + + try (ResourceScope scope = ResourceScope.newConfinedScope()) { + MethodHandle dummy = MethodHandles.lookup().findStatic(SafeFunctionAccessTest.class, "dummy", MethodType.methodType(void.class)); + NativeSymbol upcall = CLinker.systemCLinker().upcallStub(dummy, FunctionDescriptor.ofVoid(), scope); + handle.invoke(upcall, scopeChecker(scope)); + } + } + + NativeSymbol scopeChecker(ResourceScope scope) { + try { + MethodHandle handle = MethodHandles.lookup().findStatic(SafeFunctionAccessTest.class, "checkScope", + MethodType.methodType(void.class, ResourceScope.class)); + handle = handle.bindTo(scope); + return CLinker.systemCLinker().upcallStub(handle, FunctionDescriptor.ofVoid(), ResourceScope.newImplicitScope()); + } catch (Throwable ex) { + throw new AssertionError(ex); + } + } + + static void checkScope(ResourceScope scope) { + try { + scope.close(); + fail("Scope closed unexpectedly!"); + } catch (IllegalStateException ex) { + assertTrue(ex.getMessage().contains("kept alive")); //if acquired, fine + } } } diff --git a/test/jdk/java/foreign/StdLibTest.java b/test/jdk/java/foreign/StdLibTest.java index 4495ed159211aaf9ef365b77f5864c5ce6631a66..1246a260b1d7299f3070f9e904452cf8b511fa2f 100644 --- a/test/jdk/java/foreign/StdLibTest.java +++ b/test/jdk/java/foreign/StdLibTest.java @@ -39,7 +39,6 @@ import java.util.Arrays; import java.util.Collections; import java.util.LinkedHashSet; import java.util.List; -import java.util.Optional; import java.util.Set; import java.util.function.BiConsumer; import java.util.function.Function; @@ -48,17 +47,14 @@ import java.util.stream.Stream; import jdk.incubator.foreign.*; -import static jdk.incubator.foreign.MemoryAccess.*; - import org.testng.annotations.*; -import static jdk.incubator.foreign.CLinker.*; import static org.testng.Assert.*; @Test -public class StdLibTest { +public class StdLibTest extends NativeTestHelper { - final static CLinker abi = CLinker.getInstance(); + final static CLinker abi = CLinker.systemCLinker(); private StdLibHelper stdLibHelper = new StdLibHelper(); @@ -155,45 +151,36 @@ public class StdLibTest { static class StdLibHelper { - static final SymbolLookup LOOKUP = CLinker.systemLookup(); - - final static MethodHandle strcat = abi.downcallHandle(LOOKUP.lookup("strcat").get(), - MethodType.methodType(MemoryAddress.class, MemoryAddress.class, MemoryAddress.class), - FunctionDescriptor.of(C_POINTER, C_POINTER, C_POINTER)); + final static MethodHandle strcat = abi.downcallHandle(abi.lookup("strcat").get(), + FunctionDescriptor.of(C_POINTER, C_POINTER, C_POINTER)) + .asType(MethodType.methodType(MemoryAddress.class, MemorySegment.class, MemorySegment.class)); // exact signature match - final static MethodHandle strcmp = abi.downcallHandle(LOOKUP.lookup("strcmp").get(), - MethodType.methodType(int.class, MemoryAddress.class, MemoryAddress.class), + final static MethodHandle strcmp = abi.downcallHandle(abi.lookup("strcmp").get(), FunctionDescriptor.of(C_INT, C_POINTER, C_POINTER)); - final static MethodHandle puts = abi.downcallHandle(LOOKUP.lookup("puts").get(), - MethodType.methodType(int.class, MemoryAddress.class), + final static MethodHandle puts = abi.downcallHandle(abi.lookup("puts").get(), FunctionDescriptor.of(C_INT, C_POINTER)); - final static MethodHandle strlen = abi.downcallHandle(LOOKUP.lookup("strlen").get(), - MethodType.methodType(int.class, MemoryAddress.class), + final static MethodHandle strlen = abi.downcallHandle(abi.lookup("strlen").get(), FunctionDescriptor.of(C_INT, C_POINTER)); - final static MethodHandle gmtime = abi.downcallHandle(LOOKUP.lookup("gmtime").get(), - MethodType.methodType(MemoryAddress.class, MemoryAddress.class), + final static MethodHandle gmtime = abi.downcallHandle(abi.lookup("gmtime").get(), FunctionDescriptor.of(C_POINTER, C_POINTER)); - final static MethodHandle qsort = abi.downcallHandle(LOOKUP.lookup("qsort").get(), - MethodType.methodType(void.class, MemoryAddress.class, long.class, long.class, MemoryAddress.class), + final static MethodHandle qsort = abi.downcallHandle(abi.lookup("qsort").get(), FunctionDescriptor.ofVoid(C_POINTER, C_LONG_LONG, C_LONG_LONG, C_POINTER)); final static FunctionDescriptor qsortComparFunction = FunctionDescriptor.of(C_INT, C_POINTER, C_POINTER); final static MethodHandle qsortCompar; - final static MethodHandle rand = abi.downcallHandle(LOOKUP.lookup("rand").get(), - MethodType.methodType(int.class), + final static MethodHandle rand = abi.downcallHandle(abi.lookup("rand").get(), FunctionDescriptor.of(C_INT)); - final static MethodHandle vprintf = abi.downcallHandle(LOOKUP.lookup("vprintf").get(), - MethodType.methodType(int.class, MemoryAddress.class, VaList.class), - FunctionDescriptor.of(C_INT, C_POINTER, C_VA_LIST)); + final static MethodHandle vprintf = abi.downcallHandle(abi.lookup("vprintf").get(), + FunctionDescriptor.of(C_INT, C_POINTER, C_POINTER)); - final static MemoryAddress printfAddr = LOOKUP.lookup("printf").get(); + final static NativeSymbol printfAddr = abi.lookup("printf").get(); final static FunctionDescriptor printfBase = FunctionDescriptor.of(C_INT, C_POINTER); @@ -201,7 +188,7 @@ public class StdLibTest { try { //qsort upcall handle qsortCompar = MethodHandles.lookup().findStatic(StdLibTest.StdLibHelper.class, "qsortCompare", - MethodType.methodType(int.class, MemorySegment.class, MemoryAddress.class, MemoryAddress.class)); + CLinker.upcallType(qsortComparFunction)); } catch (ReflectiveOperationException ex) { throw new IllegalStateException(ex); } @@ -209,44 +196,44 @@ public class StdLibTest { String strcat(String s1, String s2) throws Throwable { try (ResourceScope scope = ResourceScope.newConfinedScope()) { - MemorySegment buf = MemorySegment.allocateNative(s1.length() + s2.length() + 1, scope); - MemorySegment other = toCString(s2, scope); - char[] chars = s1.toCharArray(); - for (long i = 0 ; i < chars.length ; i++) { - setByteAtOffset(buf, i, (byte)chars[(int)i]); - } - setByteAtOffset(buf, chars.length, (byte)'\0'); - return toJavaString(((MemoryAddress)strcat.invokeExact(buf.address(), other.address()))); + var malloc = SegmentAllocator.nativeAllocator(scope); + MemorySegment buf = malloc.allocate(s1.length() + s2.length() + 1); + buf.setUtf8String(0, s1); + MemorySegment other = malloc.allocateUtf8String(s2); + return ((MemoryAddress)strcat.invokeExact(buf, other)).getUtf8String(0); } } int strcmp(String s1, String s2) throws Throwable { try (ResourceScope scope = ResourceScope.newConfinedScope()) { - MemorySegment ns1 = toCString(s1, scope); - MemorySegment ns2 = toCString(s2, scope); - return (int)strcmp.invokeExact(ns1.address(), ns2.address()); + var malloc = SegmentAllocator.nativeAllocator(scope); + MemorySegment ns1 = malloc.allocateUtf8String(s1); + MemorySegment ns2 = malloc.allocateUtf8String(s2); + return (int)strcmp.invoke(ns1, ns2); } } int puts(String msg) throws Throwable { try (ResourceScope scope = ResourceScope.newConfinedScope()) { - MemorySegment s = toCString(msg, scope); - return (int)puts.invokeExact(s.address()); + var malloc = SegmentAllocator.nativeAllocator(scope); + MemorySegment s = malloc.allocateUtf8String(msg); + return (int)puts.invoke(s); } } int strlen(String msg) throws Throwable { try (ResourceScope scope = ResourceScope.newConfinedScope()) { - MemorySegment s = toCString(msg, scope); - return (int)strlen.invokeExact(s.address()); + var malloc = SegmentAllocator.nativeAllocator(scope); + MemorySegment s = malloc.allocateUtf8String(msg); + return (int)strlen.invoke(s); } } Tm gmtime(long arg) throws Throwable { try (ResourceScope scope = ResourceScope.newConfinedScope()) { MemorySegment time = MemorySegment.allocateNative(8, scope); - setLong(time, arg); - return new Tm((MemoryAddress)gmtime.invokeExact(time.address())); + time.set(C_LONG_LONG, 0, arg); + return new Tm((MemoryAddress)gmtime.invoke(time)); } } @@ -258,58 +245,57 @@ public class StdLibTest { static final long SIZE = 56; Tm(MemoryAddress addr) { - this.base = addr.asSegment(SIZE, ResourceScope.globalScope()); + this.base = MemorySegment.ofAddress(addr, SIZE, ResourceScope.globalScope()); } int sec() { - return getIntAtOffset(base, 0); + return base.get(C_INT, 0); } int min() { - return getIntAtOffset(base, 4); + return base.get(C_INT, 4); } int hour() { - return getIntAtOffset(base, 8); + return base.get(C_INT, 8); } int mday() { - return getIntAtOffset(base, 12); + return base.get(C_INT, 12); } int mon() { - return getIntAtOffset(base, 16); + return base.get(C_INT, 16); } int year() { - return getIntAtOffset(base, 20); + return base.get(C_INT, 20); } int wday() { - return getIntAtOffset(base, 24); + return base.get(C_INT, 24); } int yday() { - return getIntAtOffset(base, 28); + return base.get(C_INT, 28); } boolean isdst() { - byte b = getByteAtOffset(base, 32); - return b != 0; + return base.get(C_BOOL, 32); } } int[] qsort(int[] arr) throws Throwable { //init native array try (ResourceScope scope = ResourceScope.newConfinedScope()) { - SegmentAllocator allocator = SegmentAllocator.ofScope(scope); - MemorySegment nativeArr = allocator.allocateArray(C_INT, arr); + var malloc = SegmentAllocator.nativeAllocator(scope); + MemorySegment nativeArr = malloc.allocateArray(C_INT, arr); //call qsort - MemoryAddress qsortUpcallStub = abi.upcallStub(qsortCompar.bindTo(nativeArr), qsortComparFunction, scope); + NativeSymbol qsortUpcallStub = abi.upcallStub(qsortCompar, qsortComparFunction, scope); - qsort.invokeExact(nativeArr.address(), (long)arr.length, C_INT.byteSize(), qsortUpcallStub); + qsort.invoke(nativeArr, (long)arr.length, C_INT.byteSize(), qsortUpcallStub); //convert back to Java array - return nativeArr.toIntArray(); + return nativeArr.toArray(C_INT); } } - static int qsortCompare(MemorySegment base, MemoryAddress addr1, MemoryAddress addr2) { - return getIntAtOffset(base, addr1.segmentOffset(base)) - - getIntAtOffset(base, addr2.segmentOffset(base)); + static int qsortCompare(MemoryAddress addr1, MemoryAddress addr2) { + return addr1.get(C_INT, 0) - + addr2.get(C_INT, 0); } int rand() throws Throwable { @@ -318,17 +304,19 @@ public class StdLibTest { int printf(String format, List<PrintfArg> args) throws Throwable { try (ResourceScope scope = ResourceScope.newConfinedScope()) { - MemorySegment formatStr = toCString(format, scope); - return (int)specializedPrintf(args).invokeExact(formatStr.address(), + var malloc = SegmentAllocator.nativeAllocator(scope); + MemorySegment formatStr = malloc.allocateUtf8String(format); + return (int)specializedPrintf(args).invoke(formatStr, args.stream().map(a -> a.nativeValue(scope)).toArray()); } } int vprintf(String format, List<PrintfArg> args) throws Throwable { try (ResourceScope scope = ResourceScope.newConfinedScope()) { - MemorySegment formatStr = toCString(format, scope); + var malloc = SegmentAllocator.nativeAllocator(scope); + MemorySegment formatStr = malloc.allocateUtf8String(format); VaList vaList = VaList.make(b -> args.forEach(a -> a.accept(b, scope)), scope); - return (int)vprintf.invokeExact(formatStr.address(), vaList); + return (int)vprintf.invoke(formatStr, vaList); } } @@ -336,11 +324,13 @@ public class StdLibTest { //method type MethodType mt = MethodType.methodType(int.class, MemoryAddress.class); FunctionDescriptor fd = printfBase; + List<MemoryLayout> variadicLayouts = new ArrayList<>(args.size()); for (PrintfArg arg : args) { mt = mt.appendParameterTypes(arg.carrier); - fd = fd.withAppendedArgumentLayouts(arg.layout); + variadicLayouts.add(arg.layout); } - MethodHandle mh = abi.downcallHandle(printfAddr, mt, fd); + MethodHandle mh = abi.downcallHandle(printfAddr, + fd.asVariadic(variadicLayouts.toArray(new MemoryLayout[args.size()]))); return mh.asSpreader(1, Object[].class, args.size()); } } @@ -401,10 +391,14 @@ public class StdLibTest { enum PrintfArg implements BiConsumer<VaList.Builder, ResourceScope> { - INTEGRAL(int.class, asVarArg(C_INT), "%d", scope -> 42, 42, VaList.Builder::vargFromInt), - STRING(MemoryAddress.class, asVarArg(C_POINTER), "%s", scope -> toCString("str", scope).address(), "str", VaList.Builder::vargFromAddress), - CHAR(byte.class, asVarArg(C_CHAR), "%c", scope -> (byte) 'h', 'h', (builder, layout, value) -> builder.vargFromInt(C_INT, (int)value)), - DOUBLE(double.class, asVarArg(C_DOUBLE), "%.4f", scope ->1.2345d, 1.2345d, VaList.Builder::vargFromDouble); + INTEGRAL(int.class, C_INT, "%d", scope -> 42, 42, VaList.Builder::addVarg), + STRING(MemoryAddress.class, C_POINTER, "%s", scope -> { + var segment = MemorySegment.allocateNative(4, scope); + segment.setUtf8String(0, "str"); + return segment.address(); + }, "str", VaList.Builder::addVarg), + CHAR(byte.class, C_CHAR, "%c", scope -> (byte) 'h', 'h', (builder, layout, value) -> builder.addVarg(C_INT, (int)value)), + DOUBLE(double.class, C_DOUBLE, "%.4f", scope ->1.2345d, 1.2345d, VaList.Builder::addVarg); final Class<?> carrier; final ValueLayout layout; @@ -414,7 +408,7 @@ public class StdLibTest { @SuppressWarnings("rawtypes") final VaListBuilderCall builderCall; - <Z> PrintfArg(Class<?> carrier, ValueLayout layout, String format, Function<ResourceScope, Z> nativeValueFactory, Object javaValue, VaListBuilderCall<Z> builderCall) { + <Z, L extends ValueLayout> PrintfArg(Class<?> carrier, L layout, String format, Function<ResourceScope, Z> nativeValueFactory, Object javaValue, VaListBuilderCall<Z, L> builderCall) { this.carrier = carrier; this.layout = layout; this.format = format; @@ -429,8 +423,8 @@ public class StdLibTest { builderCall.build(builder, layout, nativeValueFactory.apply(scope)); } - interface VaListBuilderCall<V> { - void build(VaList.Builder builder, ValueLayout layout, V value); + interface VaListBuilderCall<V, L> { + void build(VaList.Builder builder, L layout, V value); } public Object nativeValue(ResourceScope scope) { diff --git a/test/jdk/java/foreign/TestAdaptVarHandles.java b/test/jdk/java/foreign/TestAdaptVarHandles.java index de88626948a6841cf7f2624f25fe37371f4b36f9..9c0e6c0e5543027a8a8b937c232d02266bcc8998 100644 --- a/test/jdk/java/foreign/TestAdaptVarHandles.java +++ b/test/jdk/java/foreign/TestAdaptVarHandles.java @@ -32,7 +32,6 @@ import jdk.incubator.foreign.MemoryHandles; import jdk.incubator.foreign.MemoryLayout; -import jdk.incubator.foreign.MemoryLayouts; import jdk.incubator.foreign.MemorySegment; import jdk.incubator.foreign.ResourceScope; import jdk.incubator.foreign.ValueLayout; @@ -86,18 +85,18 @@ public class TestAdaptVarHandles { } } - static final VarHandle intHandleIndexed = MemoryLayout.sequenceLayout(MemoryLayouts.JAVA_INT) - .varHandle(int.class, MemoryLayout.PathElement.sequenceElement()); + static final VarHandle intHandleIndexed = MemoryLayout.sequenceLayout(ValueLayout.JAVA_INT) + .varHandle(MemoryLayout.PathElement.sequenceElement()); - static final VarHandle intHandle = MemoryLayouts.JAVA_INT.varHandle(int.class); + static final VarHandle intHandle = ValueLayout.JAVA_INT.varHandle(); - static final VarHandle floatHandle = MemoryLayouts.JAVA_FLOAT.varHandle(float.class); + static final VarHandle floatHandle = ValueLayout.JAVA_FLOAT.varHandle(); @Test public void testFilterValue() throws Throwable { - ValueLayout layout = MemoryLayouts.JAVA_INT; + ValueLayout layout = ValueLayout.JAVA_INT; MemorySegment segment = MemorySegment.allocateNative(layout, ResourceScope.newImplicitScope()); - VarHandle intHandle = layout.varHandle(int.class); + VarHandle intHandle = layout.varHandle(); VarHandle i2SHandle = MemoryHandles.filterValue(intHandle, S2I, I2S); i2SHandle.set(segment, "1"); String oldValue = (String)i2SHandle.getAndAdd(segment, "42"); @@ -114,9 +113,9 @@ public class TestAdaptVarHandles { @Test public void testFilterValueComposite() throws Throwable { - ValueLayout layout = MemoryLayouts.JAVA_INT; + ValueLayout layout = ValueLayout.JAVA_INT; MemorySegment segment = MemorySegment.allocateNative(layout, ResourceScope.newImplicitScope()); - VarHandle intHandle = layout.varHandle(int.class); + VarHandle intHandle = layout.varHandle(); MethodHandle CTX_S2I = MethodHandles.dropArguments(S2I, 0, String.class, String.class); VarHandle i2SHandle = MemoryHandles.filterValue(intHandle, CTX_S2I, CTX_I2S); i2SHandle = MemoryHandles.insertCoordinates(i2SHandle, 1, "a", "b"); @@ -135,9 +134,9 @@ public class TestAdaptVarHandles { @Test public void testFilterValueLoose() throws Throwable { - ValueLayout layout = MemoryLayouts.JAVA_INT; + ValueLayout layout = ValueLayout.JAVA_INT; MemorySegment segment = MemorySegment.allocateNative(layout, ResourceScope.newImplicitScope()); - VarHandle intHandle = layout.varHandle(int.class); + VarHandle intHandle = layout.varHandle(); VarHandle i2SHandle = MemoryHandles.filterValue(intHandle, O2I, I2O); i2SHandle.set(segment, "1"); String oldValue = (String)i2SHandle.getAndAdd(segment, "42"); @@ -159,19 +158,19 @@ public class TestAdaptVarHandles { @Test(expectedExceptions = IllegalArgumentException.class) public void testBadFilterUnboxArity() { - VarHandle floatHandle = MemoryLayouts.JAVA_INT.varHandle(int.class); + VarHandle floatHandle = ValueLayout.JAVA_INT.varHandle(); MemoryHandles.filterValue(floatHandle, S2I.bindTo(""), I2S); } @Test(expectedExceptions = IllegalArgumentException.class) public void testBadFilterBoxArity() { - VarHandle intHandle = MemoryLayouts.JAVA_INT.varHandle(int.class); + VarHandle intHandle = ValueLayout.JAVA_INT.varHandle(); MemoryHandles.filterValue(intHandle, S2I, I2S.bindTo(42)); } @Test(expectedExceptions = IllegalArgumentException.class) public void testBadFilterBoxPrefixCoordinates() { - VarHandle intHandle = MemoryLayouts.JAVA_INT.varHandle(int.class); + VarHandle intHandle = ValueLayout.JAVA_INT.varHandle(); MemoryHandles.filterValue(intHandle, MethodHandles.dropArguments(S2I, 1, int.class), MethodHandles.dropArguments(I2S, 1, long.class)); @@ -179,31 +178,40 @@ public class TestAdaptVarHandles { @Test(expectedExceptions = IllegalArgumentException.class) public void testBadFilterBoxException() { - VarHandle intHandle = MemoryLayouts.JAVA_INT.varHandle(int.class); + VarHandle intHandle = ValueLayout.JAVA_INT.varHandle(); MemoryHandles.filterValue(intHandle, I2S, S2L_EX); } @Test(expectedExceptions = IllegalArgumentException.class) public void testBadFilterUnboxException() { - VarHandle intHandle = MemoryLayouts.JAVA_INT.varHandle(int.class); + VarHandle intHandle = ValueLayout.JAVA_INT.varHandle(); MemoryHandles.filterValue(intHandle, S2L_EX, I2S); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test(expectedExceptions = IllegalStateException.class) public void testBadFilterBoxHandleException() { - VarHandle intHandle = MemoryLayouts.JAVA_INT.varHandle(int.class); - MemoryHandles.filterValue(intHandle, S2I, I2S_EX); + VarHandle intHandle = ValueLayout.JAVA_INT.varHandle(); + VarHandle vh = MemoryHandles.filterValue(intHandle, S2I, I2S_EX); + try (ResourceScope scope = ResourceScope.newConfinedScope()) { + MemorySegment seg = MemorySegment.allocateNative(ValueLayout.JAVA_INT, scope); + vh.set(seg, "42"); + String x = (String) vh.get(seg); // should throw + } } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test(expectedExceptions = IllegalStateException.class) public void testBadFilterUnboxHandleException() { - VarHandle intHandle = MemoryLayouts.JAVA_INT.varHandle(int.class); - MemoryHandles.filterValue(intHandle, S2I_EX, I2S); + VarHandle intHandle = ValueLayout.JAVA_INT.varHandle(); + VarHandle vh = MemoryHandles.filterValue(intHandle, S2I_EX, I2S); + try (ResourceScope scope = ResourceScope.newConfinedScope()) { + MemorySegment seg = MemorySegment.allocateNative(ValueLayout.JAVA_INT, scope); + vh.set(seg, "42"); // should throw + } } @Test public void testFilterCoordinates() throws Throwable { - ValueLayout layout = MemoryLayouts.JAVA_INT; + ValueLayout layout = ValueLayout.JAVA_INT; MemorySegment segment = MemorySegment.allocateNative(layout, ResourceScope.newImplicitScope()); VarHandle intHandle_longIndex = MemoryHandles.filterCoordinates(intHandleIndexed, 0, BASE_ADDR, S2L); intHandle_longIndex.set(segment, "0", 1); @@ -246,7 +254,7 @@ public class TestAdaptVarHandles { @Test public void testInsertCoordinates() throws Throwable { - ValueLayout layout = MemoryLayouts.JAVA_INT; + ValueLayout layout = ValueLayout.JAVA_INT; MemorySegment segment = MemorySegment.allocateNative(layout, ResourceScope.newImplicitScope()); VarHandle intHandle_longIndex = MemoryHandles.insertCoordinates(intHandleIndexed, 0, segment, 0L); intHandle_longIndex.set(1); @@ -284,7 +292,7 @@ public class TestAdaptVarHandles { @Test public void testPermuteCoordinates() throws Throwable { - ValueLayout layout = MemoryLayouts.JAVA_INT; + ValueLayout layout = ValueLayout.JAVA_INT; MemorySegment segment = MemorySegment.allocateNative(layout, ResourceScope.newImplicitScope()); VarHandle intHandle_swap = MemoryHandles.permuteCoordinates(intHandleIndexed, List.of(long.class, MemorySegment.class), 1, 0); @@ -323,7 +331,7 @@ public class TestAdaptVarHandles { @Test public void testCollectCoordinates() throws Throwable { - ValueLayout layout = MemoryLayouts.JAVA_INT; + ValueLayout layout = ValueLayout.JAVA_INT; MemorySegment segment = MemorySegment.allocateNative(layout, ResourceScope.newImplicitScope()); VarHandle intHandle_sum = MemoryHandles.collectCoordinates(intHandleIndexed, 1, SUM_OFFSETS); intHandle_sum.set(segment, -2L, 2L, 1); @@ -366,7 +374,7 @@ public class TestAdaptVarHandles { @Test public void testDropCoordinates() throws Throwable { - ValueLayout layout = MemoryLayouts.JAVA_INT; + ValueLayout layout = ValueLayout.JAVA_INT; MemorySegment segment = MemorySegment.allocateNative(layout, ResourceScope.newImplicitScope()); VarHandle intHandle_dummy = MemoryHandles.dropCoordinates(intHandleIndexed, 1, float.class, String.class); intHandle_dummy.set(segment, 1f, "hello", 0L, 1); diff --git a/test/jdk/java/foreign/TestAddressHandle.java b/test/jdk/java/foreign/TestAddressHandle.java deleted file mode 100644 index de9bde07a5b26cdfb94fe181dc2733da07332154..0000000000000000000000000000000000000000 --- a/test/jdk/java/foreign/TestAddressHandle.java +++ /dev/null @@ -1,160 +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. - * - */ - -/* - * @test - * @run testng/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=true -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=false -Xverify:all TestAddressHandle - * @run testng/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=true -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true -Xverify:all TestAddressHandle - * @run testng/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=false -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=false -Xverify:all TestAddressHandle - * @run testng/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=false -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true -Xverify:all TestAddressHandle - */ - -import java.lang.invoke.*; -import java.nio.ByteOrder; -import jdk.incubator.foreign.*; - -import org.testng.annotations.*; -import static org.testng.Assert.*; - -public class TestAddressHandle { - - static final MethodHandle INT_TO_BOOL; - static final MethodHandle BOOL_TO_INT; - static final MethodHandle INT_TO_STRING; - static final MethodHandle STRING_TO_INT; - - static { - try { - INT_TO_BOOL = MethodHandles.lookup().findStatic(TestAddressHandle.class, "intToBool", - MethodType.methodType(boolean.class, int.class)); - BOOL_TO_INT = MethodHandles.lookup().findStatic(TestAddressHandle.class, "boolToInt", - MethodType.methodType(int.class, boolean.class)); - INT_TO_STRING = MethodHandles.lookup().findStatic(TestAddressHandle.class, "intToString", - MethodType.methodType(String.class, int.class)); - STRING_TO_INT = MethodHandles.lookup().findStatic(TestAddressHandle.class, "stringToInt", - MethodType.methodType(int.class, String.class)); - } catch (Throwable ex) { - throw new ExceptionInInitializerError(ex); - } - } - - @Test(dataProvider = "addressHandles") - public void testAddressHandle(VarHandle addrHandle, int byteSize) { - VarHandle longHandle = MemoryLayouts.JAVA_LONG.varHandle(long.class); - try (ResourceScope scope = ResourceScope.newConfinedScope()) { - MemorySegment segment = MemorySegment.allocateNative(8, scope); - MemorySegment target = ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN ? - segment.asSlice(8 - byteSize) : - segment; - longHandle.set(segment, 42L); - MemoryAddress address = (MemoryAddress)addrHandle.get(target); - assertEquals(address.toRawLongValue(), 42L); - addrHandle.set(target, address.addOffset(1)); - long result = (long)longHandle.get(segment); - assertEquals(43L, result); - } - } - - @Test(dataProvider = "addressHandles") - public void testNull(VarHandle addrHandle, int byteSize) { - VarHandle longHandle = MemoryLayouts.JAVA_LONG.varHandle(long.class); - try (ResourceScope scope = ResourceScope.newConfinedScope()) { - MemorySegment segment = MemorySegment.allocateNative(8, scope); - longHandle.set(segment, 0L); - MemoryAddress address = (MemoryAddress)addrHandle.get(segment); - assertTrue(address == MemoryAddress.NULL); - } - } - - @Test(expectedExceptions = IllegalArgumentException.class) - public void testBadAdaptFloat() { - VarHandle floatHandle = MemoryLayouts.JAVA_FLOAT.varHandle(float.class); - MemoryHandles.asAddressVarHandle(floatHandle); - } - - @Test(expectedExceptions = IllegalArgumentException.class) - public void testBadAdaptDouble() { - VarHandle doubleHandle = MemoryLayouts.JAVA_DOUBLE.varHandle(double.class); - MemoryHandles.asAddressVarHandle(doubleHandle); - } - - @Test(expectedExceptions = IllegalArgumentException.class) - public void testBadAdaptBoolean() { - VarHandle intHandle = MemoryLayouts.JAVA_INT.varHandle(int.class); - VarHandle boolHandle = MemoryHandles.filterValue(intHandle, BOOL_TO_INT, INT_TO_BOOL); - MemoryHandles.asAddressVarHandle(boolHandle); - } - - @Test(expectedExceptions = IllegalArgumentException.class) - public void testBadAdaptString() { - VarHandle intHandle = MemoryLayouts.JAVA_INT.varHandle(int.class); - VarHandle stringHandle = MemoryHandles.filterValue(intHandle, STRING_TO_INT, INT_TO_STRING); - MemoryHandles.asAddressVarHandle(stringHandle); - } - - @DataProvider(name = "addressHandles") - static Object[][] addressHandles() { - return new Object[][] { - // long - { MemoryHandles.asAddressVarHandle(at(MemoryHandles.varHandle(long.class, ByteOrder.nativeOrder()), 0)), 8 }, - { MemoryHandles.asAddressVarHandle(MemoryLayouts.JAVA_LONG.varHandle(long.class)), 8 }, - - // int - { MemoryHandles.asAddressVarHandle(at(MemoryHandles.varHandle(int.class, ByteOrder.nativeOrder()), 0)), 4 }, - { MemoryHandles.asAddressVarHandle(MemoryLayouts.JAVA_INT.varHandle(int.class)), 4 }, - - // short - { MemoryHandles.asAddressVarHandle(at(MemoryHandles.varHandle(short.class, ByteOrder.nativeOrder()), 0)), 2 }, - { MemoryHandles.asAddressVarHandle(MemoryLayouts.JAVA_SHORT.varHandle(short.class)), 2 }, - - // char - { MemoryHandles.asAddressVarHandle(at(MemoryHandles.varHandle(char.class, ByteOrder.nativeOrder()), 0)), 2 }, - { MemoryHandles.asAddressVarHandle(MemoryLayouts.JAVA_CHAR.varHandle(char.class)), 2 }, - - // byte - { MemoryHandles.asAddressVarHandle(at(MemoryHandles.varHandle(byte.class, ByteOrder.nativeOrder()), 0)), 1 }, - { MemoryHandles.asAddressVarHandle(MemoryLayouts.JAVA_BYTE.varHandle(byte.class)), 1 } - }; - } - - static VarHandle at(VarHandle handle, long offset) { - return MemoryHandles.insertCoordinates(handle, 1, offset); - } - - static int boolToInt(boolean value) { - return value ? 1 : 0; - } - - static boolean intToBool(int value) { - return value != 0; - } - - static int stringToInt(String value) { - return value.length(); - } - - static String intToString(int value) { - return String.valueOf(value); - } -} diff --git a/test/jdk/java/foreign/TestArrayCopy.java b/test/jdk/java/foreign/TestArrayCopy.java new file mode 100644 index 0000000000000000000000000000000000000000..e45fcf395f7c4712f0e130c413d27585484422fc --- /dev/null +++ b/test/jdk/java/foreign/TestArrayCopy.java @@ -0,0 +1,554 @@ +/* + * 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. + */ + +/* + * @test + * @run testng TestArrayCopy + */ + +import static jdk.incubator.foreign.ValueLayout.JAVA_BYTE; +import static jdk.incubator.foreign.ValueLayout.JAVA_INT; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.fail; + +import java.lang.invoke.VarHandle; +import java.nio.ByteOrder; +import java.util.ArrayList; +import java.util.List; + +import jdk.incubator.foreign.MemoryLayout; +import jdk.incubator.foreign.MemorySegment; + +import jdk.incubator.foreign.ValueLayout; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +/** + * These tests exercise the MemoryCopy copyFromArray(...) and copyToArray(...). + * To make these tests more challenging the segment is a view of the given array, + * which makes the copy operations overlapping self-copies. Thus, this checks the claim: + * + * <p>If the source (destination) segment is actually a view of the destination (source) array, + * and if the copy region of the source overlaps with the copy region of the destination, + * the copy of the overlapping region is performed as if the data in the overlapping region + * were first copied into a temporary segment before being copied to the destination.</p> + */ +public class TestArrayCopy { + private static final ByteOrder NATIVE_ORDER = ByteOrder.nativeOrder(); + private static final ByteOrder NON_NATIVE_ORDER = NATIVE_ORDER == ByteOrder.LITTLE_ENDIAN + ? ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN; + + private static final int SEG_LENGTH_BYTES = 32; + private static final int SEG_OFFSET_BYTES = 8; + + @Test(dataProvider = "copyModesAndHelpers") + public void testSelfCopy(CopyMode mode, CopyHelper<Object, ValueLayout> helper, String helperDebugString) { + int bytesPerElement = (int)helper.elementLayout.byteSize(); + int indexShifts = SEG_OFFSET_BYTES / bytesPerElement; + MemorySegment base = srcSegment(SEG_LENGTH_BYTES); + MemorySegment truth = truthSegment(base, helper, indexShifts, mode); + ByteOrder bo = mode.swap ? NON_NATIVE_ORDER : NATIVE_ORDER; + //CopyFrom + Object srcArr = helper.toArray(base); + int srcIndex = mode.direction ? 0 : indexShifts; + int srcCopyLen = helper.length(srcArr) - indexShifts; + MemorySegment dstSeg = helper.fromArray(srcArr); + long dstOffsetBytes = mode.direction ? SEG_OFFSET_BYTES : 0; + helper.copyFromArray(srcArr, srcIndex, srcCopyLen, dstSeg, dstOffsetBytes, bo); + assertEquals(truth.mismatch(dstSeg), -1); + //CopyTo + long srcOffsetBytes = mode.direction ? 0 : SEG_OFFSET_BYTES; + Object dstArr = helper.toArray(base); + MemorySegment srcSeg = helper.fromArray(dstArr).asReadOnly(); + int dstIndex = mode.direction ? indexShifts : 0; + int dstCopyLen = helper.length(dstArr) - indexShifts; + helper.copyToArray(srcSeg, srcOffsetBytes, dstArr, dstIndex, dstCopyLen, bo); + MemorySegment result = helper.fromArray(dstArr); + assertEquals(truth.mismatch(result), -1); + } + + @Test(dataProvider = "copyModesAndHelpers") + public void testUnalignedCopy(CopyMode mode, CopyHelper<Object, ValueLayout> helper, String helperDebugString) { + int bytesPerElement = (int)helper.elementLayout.byteSize(); + int indexShifts = SEG_OFFSET_BYTES / bytesPerElement; + MemorySegment base = srcSegment(SEG_LENGTH_BYTES); + ByteOrder bo = mode.swap ? NON_NATIVE_ORDER : NATIVE_ORDER; + //CopyFrom + Object srcArr = helper.toArray(base); + int srcIndex = mode.direction ? 0 : indexShifts; + int srcCopyLen = helper.length(srcArr) - indexShifts; + MemorySegment dstSeg = helper.fromArray(srcArr); + long dstOffsetBytes = mode.direction ? (SEG_OFFSET_BYTES - 1) : 0; + helper.copyFromArray(srcArr, srcIndex, srcCopyLen, dstSeg, dstOffsetBytes, bo); + //CopyTo + long srcOffsetBytes = mode.direction ? 0 : (SEG_OFFSET_BYTES - 1); + Object dstArr = helper.toArray(base); + MemorySegment srcSeg = helper.fromArray(dstArr).asReadOnly(); + int dstIndex = mode.direction ? indexShifts : 0; + int dstCopyLen = helper.length(dstArr) - indexShifts; + helper.copyToArray(srcSeg, srcOffsetBytes, dstArr, dstIndex, dstCopyLen, bo); + } + + @Test(dataProvider = "copyModesAndHelpers") + public void testCopyOobLength(CopyMode mode, CopyHelper<Object, ValueLayout> helper, String helperDebugString) { + int bytesPerElement = (int)helper.elementLayout.byteSize(); + MemorySegment base = srcSegment(SEG_LENGTH_BYTES); + //CopyFrom + Object srcArr = helper.toArray(base); + MemorySegment dstSeg = helper.fromArray(srcArr); + try { + helper.copyFromArray(srcArr, 0, (SEG_LENGTH_BYTES / bytesPerElement) * 2, dstSeg, 0, ByteOrder.nativeOrder()); + fail(); + } catch (IndexOutOfBoundsException ex) { + //ok + } + //CopyTo + Object dstArr = helper.toArray(base); + MemorySegment srcSeg = helper.fromArray(dstArr).asReadOnly(); + try { + helper.copyToArray(srcSeg, 0, dstArr, 0, (SEG_LENGTH_BYTES / bytesPerElement) * 2, ByteOrder.nativeOrder()); + fail(); + } catch (IndexOutOfBoundsException ex) { + //ok + } + } + + @Test(dataProvider = "copyModesAndHelpers") + public void testCopyNegativeIndices(CopyMode mode, CopyHelper<Object, ValueLayout> helper, String helperDebugString) { + int bytesPerElement = (int)helper.elementLayout.byteSize(); + MemorySegment base = srcSegment(SEG_LENGTH_BYTES); + //CopyFrom + Object srcArr = helper.toArray(base); + MemorySegment dstSeg = helper.fromArray(srcArr); + try { + helper.copyFromArray(srcArr, -1, SEG_LENGTH_BYTES / bytesPerElement, dstSeg, 0, ByteOrder.nativeOrder()); + fail(); + } catch (IndexOutOfBoundsException ex) { + //ok + } + //CopyTo + Object dstArr = helper.toArray(base); + MemorySegment srcSeg = helper.fromArray(dstArr).asReadOnly(); + try { + helper.copyToArray(srcSeg, 0, dstArr, -1, SEG_LENGTH_BYTES / bytesPerElement, ByteOrder.nativeOrder()); + fail(); + } catch (IndexOutOfBoundsException ex) { + //ok + } + } + + @Test(dataProvider = "copyModesAndHelpers") + public void testCopyNegativeOffsets(CopyMode mode, CopyHelper<Object, ValueLayout> helper, String helperDebugString) { + int bytesPerElement = (int)helper.elementLayout.byteSize(); + MemorySegment base = srcSegment(SEG_LENGTH_BYTES); + //CopyFrom + Object srcArr = helper.toArray(base); + MemorySegment dstSeg = helper.fromArray(srcArr); + try { + helper.copyFromArray(srcArr, 0, SEG_LENGTH_BYTES / bytesPerElement, dstSeg, -1, ByteOrder.nativeOrder()); + fail(); + } catch (IndexOutOfBoundsException ex) { + //ok + } + //CopyTo + Object dstArr = helper.toArray(base); + MemorySegment srcSeg = helper.fromArray(dstArr).asReadOnly(); + try { + helper.copyToArray(srcSeg, -1, dstArr, 0, SEG_LENGTH_BYTES / bytesPerElement, ByteOrder.nativeOrder()); + fail(); + } catch (IndexOutOfBoundsException ex) { + //ok + } + } + + @Test(dataProvider = "copyModesAndHelpers") + public void testCopyOobIndices(CopyMode mode, CopyHelper<Object, ValueLayout> helper, String helperDebugString) { + int bytesPerElement = (int)helper.elementLayout.byteSize(); + MemorySegment base = srcSegment(SEG_LENGTH_BYTES); + //CopyFrom + Object srcArr = helper.toArray(base); + MemorySegment dstSeg = helper.fromArray(srcArr); + try { + helper.copyFromArray(srcArr, helper.length(srcArr) + 1, SEG_LENGTH_BYTES / bytesPerElement, dstSeg, 0, ByteOrder.nativeOrder()); + fail(); + } catch (IndexOutOfBoundsException ex) { + //ok + } + //CopyTo + Object dstArr = helper.toArray(base); + MemorySegment srcSeg = helper.fromArray(dstArr).asReadOnly(); + try { + helper.copyToArray(srcSeg, 0, dstArr, helper.length(dstArr) + 1, SEG_LENGTH_BYTES / bytesPerElement, ByteOrder.nativeOrder()); + fail(); + } catch (IndexOutOfBoundsException ex) { + //ok + } + } + + @Test(dataProvider = "copyModesAndHelpers") + public void testCopyOobOffsets(CopyMode mode, CopyHelper<Object, ValueLayout> helper, String helperDebugString) { + int bytesPerElement = (int)helper.elementLayout.byteSize(); + MemorySegment base = srcSegment(SEG_LENGTH_BYTES); + //CopyFrom + Object srcArr = helper.toArray(base); + MemorySegment dstSeg = helper.fromArray(srcArr); + try { + helper.copyFromArray(srcArr, 0, SEG_LENGTH_BYTES / bytesPerElement, dstSeg, SEG_LENGTH_BYTES + 1, ByteOrder.nativeOrder()); + fail(); + } catch (IndexOutOfBoundsException ex) { + //ok + } + //CopyTo + Object dstArr = helper.toArray(base); + MemorySegment srcSeg = helper.fromArray(dstArr).asReadOnly(); + try { + helper.copyToArray(srcSeg, SEG_OFFSET_BYTES + 1, dstArr, 0, SEG_LENGTH_BYTES / bytesPerElement, ByteOrder.nativeOrder()); + fail(); + } catch (IndexOutOfBoundsException ex) { + //ok + } + } + + @Test(expectedExceptions = IllegalArgumentException.class) + public void testNotAnArraySrc() { + MemorySegment segment = MemorySegment.ofArray(new int[] {1, 2, 3, 4}); + MemorySegment.copy(segment, JAVA_BYTE, 0, new String[] { "hello" }, 0, 4); + } + + @Test(expectedExceptions = IllegalArgumentException.class) + public void testNotAnArrayDst() { + MemorySegment segment = MemorySegment.ofArray(new int[] {1, 2, 3, 4}); + MemorySegment.copy(new String[] { "hello" }, 0, segment, JAVA_BYTE, 0, 4); + } + + @Test(expectedExceptions = IllegalArgumentException.class) + public void testCarrierMismatchSrc() { + MemorySegment segment = MemorySegment.ofArray(new int[] {1, 2, 3, 4}); + MemorySegment.copy(segment, JAVA_INT, 0, new byte[] { 1, 2, 3, 4 }, 0, 4); + } + + @Test(expectedExceptions = IllegalArgumentException.class) + public void testCarrierMismatchDst() { + MemorySegment segment = MemorySegment.ofArray(new int[] {1, 2, 3, 4}); + MemorySegment.copy(new byte[] { 1, 2, 3, 4 }, 0, segment, JAVA_INT, 0, 4); + } + + @Test(expectedExceptions = IllegalArgumentException.class) + public void testHyperAlignedSrc() { + MemorySegment segment = MemorySegment.ofArray(new byte[] {1, 2, 3, 4}); + MemorySegment.copy(new byte[] { 1, 2, 3, 4 }, 0, segment, JAVA_BYTE.withBitAlignment(16), 0, 4); + } + + @Test(expectedExceptions = IllegalArgumentException.class) + public void testHyperAlignedDst() { + MemorySegment segment = MemorySegment.ofArray(new byte[] {1, 2, 3, 4}); + MemorySegment.copy(segment, JAVA_BYTE.withBitAlignment(16), 0, new byte[] { 1, 2, 3, 4 }, 0, 4); + } + + /***** Utilities *****/ + + public static MemorySegment srcSegment(int bytesLength) { + byte[] arr = new byte[bytesLength]; + for (int i = 0; i < arr.length; i++) { + arr[i] = (byte)i; + } + return MemorySegment.ofArray(arr); + } + + public static MemorySegment truthSegment(MemorySegment srcSeg, CopyHelper<?, ?> helper, int indexShifts, CopyMode mode) { + VarHandle indexedHandleNO = MemoryLayout.sequenceLayout(helper.elementLayout.withOrder(NATIVE_ORDER)) + .varHandle(MemoryLayout.PathElement.sequenceElement()); + VarHandle indexedHandleNNO = MemoryLayout.sequenceLayout(helper.elementLayout.withOrder(NON_NATIVE_ORDER)) + .varHandle(MemoryLayout.PathElement.sequenceElement()); + MemorySegment dstSeg = MemorySegment.ofArray(srcSeg.toArray(JAVA_BYTE)); + int indexLength = (int) dstSeg.byteSize() / (int)helper.elementLayout.byteSize(); + if (mode.direction) { + if (mode.swap) { + for (int i = indexLength - 1; i >= indexShifts; i--) { + Object v = indexedHandleNNO.get(dstSeg, i - indexShifts); + indexedHandleNO.set(dstSeg, i, v); + } + } else { + for (int i = indexLength - 1; i >= indexShifts; i--) { + Object v = indexedHandleNO.get(dstSeg, i - indexShifts); + indexedHandleNO.set(dstSeg, i, v); + } + } + } else { //down + if (mode.swap) { + for (int i = indexShifts; i < indexLength; i++) { + Object v = indexedHandleNNO.get(dstSeg, i); + indexedHandleNO.set(dstSeg, i - indexShifts, v); + } + } else { + for (int i = indexShifts; i < indexLength; i++) { + Object v = indexedHandleNO.get(dstSeg, i); + indexedHandleNO.set(dstSeg, i - indexShifts, v); + } + } + } + return dstSeg; + } + + enum CopyMode { + UP_NO_SWAP(true, false), + UP_SWAP(true, true), + DOWN_NO_SWAP(false, false), + DOWN_SWAP(false, true); + + final boolean direction; + final boolean swap; + + CopyMode(boolean direction, boolean swap) { + this.direction = direction; + this.swap = swap; + } + } + + abstract static class CopyHelper<X, L extends ValueLayout> { + + final L elementLayout; + final Class<?> carrier; + + public CopyHelper(L elementLayout, Class<X> carrier) { + this.elementLayout = elementLayout; + this.carrier = carrier; + } + + abstract void copyFromArray(X srcArr, int srcIndex, int srcCopyLen, MemorySegment dstSeg, long dstOffsetBytes, ByteOrder bo); + abstract void copyToArray(MemorySegment srcSeg, long srcOffsetBytes, X dstArr, int dstIndex, int dstCopyLen, ByteOrder bo); + abstract X toArray(MemorySegment segment); + abstract MemorySegment fromArray(X array); + abstract int length(X arr); + + @Override + public String toString() { + return "CopyHelper{" + + "elementLayout=" + elementLayout + + ", carrier=" + carrier.getName() + + '}'; + } + + static final CopyHelper<byte[], ValueLayout.OfByte> BYTE = new CopyHelper<>(JAVA_BYTE, byte[].class) { + @Override + void copyFromArray(byte[] srcArr, int srcIndex, int srcCopyLen, MemorySegment dstSeg, long dstOffsetBytes, ByteOrder bo) { + MemorySegment.copy(srcArr, srcIndex, dstSeg, elementLayout.withOrder(bo), dstOffsetBytes, srcCopyLen); + } + + @Override + void copyToArray(MemorySegment srcSeg, long srcOffsetBytes, byte[] dstArr, int dstIndex, int dstCopyLen, ByteOrder bo) { + MemorySegment.copy(srcSeg, elementLayout.withOrder(bo), srcOffsetBytes, dstArr, dstIndex, dstCopyLen); + } + + @Override + byte[] toArray(MemorySegment segment) { + return segment.toArray(elementLayout); + } + + @Override + MemorySegment fromArray(byte[] array) { + return MemorySegment.ofArray(array); + } + + @Override + int length(byte[] arr) { + return arr.length; + } + }; + + static final CopyHelper<char[], ValueLayout.OfChar> CHAR = new CopyHelper<>(ValueLayout.JAVA_CHAR, char[].class) { + @Override + void copyFromArray(char[] srcArr, int srcIndex, int srcCopyLen, MemorySegment dstSeg, long dstOffsetBytes, ByteOrder bo) { + MemorySegment.copy(srcArr, srcIndex, dstSeg, elementLayout.withOrder(bo), dstOffsetBytes, srcCopyLen); + } + + @Override + void copyToArray(MemorySegment srcSeg, long srcOffsetBytes, char[] dstArr, int dstIndex, int dstCopyLen, ByteOrder bo) { + MemorySegment.copy(srcSeg, elementLayout.withOrder(bo), srcOffsetBytes, dstArr, dstIndex, dstCopyLen); + } + + @Override + char[] toArray(MemorySegment segment) { + return segment.toArray(elementLayout); + } + + @Override + MemorySegment fromArray(char[] array) { + return MemorySegment.ofArray(array); + } + + @Override + int length(char[] arr) { + return arr.length; + } + }; + + static final CopyHelper<short[], ValueLayout.OfShort> SHORT = new CopyHelper<>(ValueLayout.JAVA_SHORT, short[].class) { + @Override + void copyFromArray(short[] srcArr, int srcIndex, int srcCopyLen, MemorySegment dstSeg, long dstOffsetBytes, ByteOrder bo) { + MemorySegment.copy(srcArr, srcIndex, dstSeg, elementLayout.withOrder(bo), dstOffsetBytes, srcCopyLen); + } + + @Override + void copyToArray(MemorySegment srcSeg, long srcOffsetBytes, short[] dstArr, int dstIndex, int dstCopyLen, ByteOrder bo) { + MemorySegment.copy(srcSeg, elementLayout.withOrder(bo), srcOffsetBytes, dstArr, dstIndex, dstCopyLen); + } + + @Override + short[] toArray(MemorySegment segment) { + return segment.toArray(elementLayout); + } + + @Override + MemorySegment fromArray(short[] array) { + return MemorySegment.ofArray(array); + } + + @Override + int length(short[] arr) { + return arr.length; + } + }; + + static final CopyHelper<int[], ValueLayout.OfInt> INT = new CopyHelper<>(ValueLayout.JAVA_INT, int[].class) { + @Override + void copyFromArray(int[] srcArr, int srcIndex, int srcCopyLen, MemorySegment dstSeg, long dstOffsetBytes, ByteOrder bo) { + MemorySegment.copy(srcArr, srcIndex, dstSeg, elementLayout.withOrder(bo), dstOffsetBytes, srcCopyLen); + } + + @Override + void copyToArray(MemorySegment srcSeg, long srcOffsetBytes, int[] dstArr, int dstIndex, int dstCopyLen, ByteOrder bo) { + MemorySegment.copy(srcSeg, elementLayout.withOrder(bo), srcOffsetBytes, dstArr, dstIndex, dstCopyLen); + } + + @Override + int[] toArray(MemorySegment segment) { + return segment.toArray(elementLayout); + } + + @Override + MemorySegment fromArray(int[] array) { + return MemorySegment.ofArray(array); + } + + @Override + int length(int[] arr) { + return arr.length; + } + }; + + static final CopyHelper<float[], ValueLayout.OfFloat> FLOAT = new CopyHelper<>(ValueLayout.JAVA_FLOAT, float[].class) { + @Override + void copyFromArray(float[] srcArr, int srcIndex, int srcCopyLen, MemorySegment dstSeg, long dstOffsetBytes, ByteOrder bo) { + MemorySegment.copy(srcArr, srcIndex, dstSeg, elementLayout.withOrder(bo), dstOffsetBytes, srcCopyLen); + } + + @Override + void copyToArray(MemorySegment srcSeg, long srcOffsetBytes, float[] dstArr, int dstIndex, int dstCopyLen, ByteOrder bo) { + MemorySegment.copy(srcSeg, elementLayout.withOrder(bo), srcOffsetBytes, dstArr, dstIndex, dstCopyLen); + } + + @Override + float[] toArray(MemorySegment segment) { + return segment.toArray(elementLayout); + } + + @Override + MemorySegment fromArray(float[] array) { + return MemorySegment.ofArray(array); + } + + @Override + int length(float[] arr) { + return arr.length; + } + }; + + static final CopyHelper<long[], ValueLayout.OfLong> LONG = new CopyHelper<>(ValueLayout.JAVA_LONG, long[].class) { + @Override + void copyFromArray(long[] srcArr, int srcIndex, int srcCopyLen, MemorySegment dstSeg, long dstOffsetBytes, ByteOrder bo) { + MemorySegment.copy(srcArr, srcIndex, dstSeg, elementLayout.withOrder(bo), dstOffsetBytes, srcCopyLen); + } + + @Override + void copyToArray(MemorySegment srcSeg, long srcOffsetBytes, long[] dstArr, int dstIndex, int dstCopyLen, ByteOrder bo) { + MemorySegment.copy(srcSeg, elementLayout.withOrder(bo), srcOffsetBytes, dstArr, dstIndex, dstCopyLen); + } + + @Override + long[] toArray(MemorySegment segment) { + return segment.toArray(elementLayout); + } + + @Override + MemorySegment fromArray(long[] array) { + return MemorySegment.ofArray(array); + } + + @Override + int length(long[] arr) { + return arr.length; + } + }; + + static final CopyHelper<double[], ValueLayout.OfDouble> DOUBLE = new CopyHelper<>(ValueLayout.JAVA_DOUBLE, double[].class) { + @Override + void copyFromArray(double[] srcArr, int srcIndex, int srcCopyLen, MemorySegment dstSeg, long dstOffsetBytes, ByteOrder bo) { + MemorySegment.copy(srcArr, srcIndex, dstSeg, elementLayout.withOrder(bo), dstOffsetBytes, srcCopyLen); + } + + @Override + void copyToArray(MemorySegment srcSeg, long srcOffsetBytes, double[] dstArr, int dstIndex, int dstCopyLen, ByteOrder bo) { + MemorySegment.copy(srcSeg, elementLayout.withOrder(bo), srcOffsetBytes, dstArr, dstIndex, dstCopyLen); + } + + @Override + double[] toArray(MemorySegment segment) { + return segment.toArray(elementLayout); + } + + @Override + MemorySegment fromArray(double[] array) { + return MemorySegment.ofArray(array); + } + + @Override + int length(double[] arr) { + return arr.length; + } + }; + } + + @DataProvider + Object[][] copyModesAndHelpers() { + CopyHelper<?, ?>[] helpers = { CopyHelper.BYTE, CopyHelper.CHAR, CopyHelper.SHORT, CopyHelper.INT, + CopyHelper.FLOAT, CopyHelper.LONG, CopyHelper.DOUBLE }; + List<Object[]> results = new ArrayList<>(); + for (CopyHelper<?, ?> helper : helpers) { + for (CopyMode mode : CopyMode.values()) { + results.add(new Object[] { mode, helper, helper.toString() }); + } + } + return results.stream().toArray(Object[][]::new); + } +} diff --git a/test/jdk/java/foreign/TestArrays.java b/test/jdk/java/foreign/TestArrays.java index 451beeb4544dc89b3b609ad207e6082ab745e66e..ca412554cb4271347d3175972b28bfbf438693f2 100644 --- a/test/jdk/java/foreign/TestArrays.java +++ b/test/jdk/java/foreign/TestArrays.java @@ -30,7 +30,6 @@ import jdk.incubator.foreign.MemoryAddress; import jdk.incubator.foreign.MemoryLayout; import jdk.incubator.foreign.MemoryLayout.PathElement; -import jdk.incubator.foreign.MemoryLayouts; import jdk.incubator.foreign.MemorySegment; import jdk.incubator.foreign.ResourceScope; import jdk.incubator.foreign.SequenceLayout; @@ -43,45 +42,52 @@ import java.util.function.Function; import org.testng.annotations.*; +import static jdk.incubator.foreign.ValueLayout.JAVA_BYTE; +import static jdk.incubator.foreign.ValueLayout.JAVA_CHAR; +import static jdk.incubator.foreign.ValueLayout.JAVA_DOUBLE; +import static jdk.incubator.foreign.ValueLayout.JAVA_FLOAT; +import static jdk.incubator.foreign.ValueLayout.JAVA_INT; +import static jdk.incubator.foreign.ValueLayout.JAVA_LONG; +import static jdk.incubator.foreign.ValueLayout.JAVA_SHORT; import static org.testng.Assert.*; public class TestArrays { static SequenceLayout bytes = MemoryLayout.sequenceLayout(100, - MemoryLayouts.JAVA_BYTE + JAVA_BYTE ); static SequenceLayout chars = MemoryLayout.sequenceLayout(100, - MemoryLayouts.JAVA_CHAR + JAVA_CHAR ); static SequenceLayout shorts = MemoryLayout.sequenceLayout(100, - MemoryLayouts.JAVA_SHORT + JAVA_SHORT ); static SequenceLayout ints = MemoryLayout.sequenceLayout(100, - MemoryLayouts.JAVA_INT + JAVA_INT ); static SequenceLayout floats = MemoryLayout.sequenceLayout(100, - MemoryLayouts.JAVA_FLOAT + JAVA_FLOAT ); static SequenceLayout longs = MemoryLayout.sequenceLayout(100, - MemoryLayouts.JAVA_LONG + JAVA_LONG ); static SequenceLayout doubles = MemoryLayout.sequenceLayout(100, - MemoryLayouts.JAVA_DOUBLE + JAVA_DOUBLE ); - static VarHandle byteHandle = bytes.varHandle(byte.class, PathElement.sequenceElement()); - static VarHandle charHandle = chars.varHandle(char.class, PathElement.sequenceElement()); - static VarHandle shortHandle = shorts.varHandle(short.class, PathElement.sequenceElement()); - static VarHandle intHandle = ints.varHandle(int.class, PathElement.sequenceElement()); - static VarHandle floatHandle = floats.varHandle(float.class, PathElement.sequenceElement()); - static VarHandle longHandle = longs.varHandle(long.class, PathElement.sequenceElement()); - static VarHandle doubleHandle = doubles.varHandle(double.class, PathElement.sequenceElement()); + static VarHandle byteHandle = bytes.varHandle(PathElement.sequenceElement()); + static VarHandle charHandle = chars.varHandle(PathElement.sequenceElement()); + static VarHandle shortHandle = shorts.varHandle(PathElement.sequenceElement()); + static VarHandle intHandle = ints.varHandle(PathElement.sequenceElement()); + static VarHandle floatHandle = floats.varHandle(PathElement.sequenceElement()); + static VarHandle longHandle = longs.varHandle(PathElement.sequenceElement()); + static VarHandle doubleHandle = doubles.varHandle(PathElement.sequenceElement()); static void initBytes(MemorySegment base, SequenceLayout seq, BiConsumer<MemorySegment, Long> handleSetter) { for (long i = 0; i < seq.elementCount().getAsLong() ; i++) { @@ -112,7 +118,7 @@ public class TestArrays { public void testTooBigForArray(MemoryLayout layout, Function<MemorySegment, Object> arrayFactory) { MemoryLayout seq = MemoryLayout.sequenceLayout((Integer.MAX_VALUE * layout.byteSize()) + 1, layout); //do not really allocate here, as it's way too much memory - MemorySegment segment = MemoryAddress.NULL.asSegment(seq.byteSize(), ResourceScope.globalScope()); + MemorySegment segment = MemorySegment.ofAddress(MemoryAddress.NULL, seq.byteSize(), ResourceScope.globalScope()); arrayFactory.apply(segment); } @@ -152,19 +158,19 @@ public class TestArrays { (base) -> initBytes(base, doubles, (addr, pos) -> doubleHandle.set(addr, pos, (double)(long)pos)); Consumer<MemorySegment> byteChecker = - (base) -> checkBytes(base, bytes, MemorySegment::toByteArray, (addr, pos) -> (byte)byteHandle.get(addr, pos)); + (base) -> checkBytes(base, bytes, s -> s.toArray(JAVA_BYTE), (addr, pos) -> (byte)byteHandle.get(addr, pos)); Consumer<MemorySegment> shortChecker = - (base) -> checkBytes(base, shorts, MemorySegment::toShortArray, (addr, pos) -> (short)shortHandle.get(addr, pos)); + (base) -> checkBytes(base, shorts, s -> s.toArray(JAVA_SHORT), (addr, pos) -> (short)shortHandle.get(addr, pos)); Consumer<MemorySegment> charChecker = - (base) -> checkBytes(base, chars, MemorySegment::toCharArray, (addr, pos) -> (char)charHandle.get(addr, pos)); + (base) -> checkBytes(base, chars, s -> s.toArray(JAVA_CHAR), (addr, pos) -> (char)charHandle.get(addr, pos)); Consumer<MemorySegment> intChecker = - (base) -> checkBytes(base, ints, MemorySegment::toIntArray, (addr, pos) -> (int)intHandle.get(addr, pos)); + (base) -> checkBytes(base, ints, s -> s.toArray(JAVA_INT), (addr, pos) -> (int)intHandle.get(addr, pos)); Consumer<MemorySegment> floatChecker = - (base) -> checkBytes(base, floats, MemorySegment::toFloatArray, (addr, pos) -> (float)floatHandle.get(addr, pos)); + (base) -> checkBytes(base, floats, s -> s.toArray(JAVA_FLOAT), (addr, pos) -> (float)floatHandle.get(addr, pos)); Consumer<MemorySegment> longChecker = - (base) -> checkBytes(base, longs, MemorySegment::toLongArray, (addr, pos) -> (long)longHandle.get(addr, pos)); + (base) -> checkBytes(base, longs, s -> s.toArray(JAVA_LONG), (addr, pos) -> (long)longHandle.get(addr, pos)); Consumer<MemorySegment> doubleChecker = - (base) -> checkBytes(base, doubles, MemorySegment::toDoubleArray, (addr, pos) -> (double)doubleHandle.get(addr, pos)); + (base) -> checkBytes(base, doubles, s -> s.toArray(JAVA_DOUBLE), (addr, pos) -> (double)doubleHandle.get(addr, pos)); return new Object[][]{ {byteInitializer, byteChecker, bytes}, @@ -180,13 +186,13 @@ public class TestArrays { @DataProvider(name = "elemLayouts") public Object[][] elemLayouts() { return new Object[][] { - { MemoryLayouts.JAVA_BYTE, (Function<MemorySegment, Object>) MemorySegment::toByteArray }, - { MemoryLayouts.JAVA_SHORT, (Function<MemorySegment, Object>) MemorySegment::toShortArray }, - { MemoryLayouts.JAVA_CHAR, (Function<MemorySegment, Object>) MemorySegment::toCharArray }, - { MemoryLayouts.JAVA_INT, (Function<MemorySegment, Object>) MemorySegment::toIntArray }, - { MemoryLayouts.JAVA_FLOAT, (Function<MemorySegment, Object>) MemorySegment::toFloatArray }, - { MemoryLayouts.JAVA_LONG, (Function<MemorySegment, Object>) MemorySegment::toLongArray }, - { MemoryLayouts.JAVA_DOUBLE, (Function<MemorySegment, Object>) MemorySegment::toDoubleArray } + { JAVA_BYTE, (Function<MemorySegment, Object>)s -> s.toArray(JAVA_BYTE)}, + { JAVA_SHORT, (Function<MemorySegment, Object>) s -> s.toArray(JAVA_SHORT)}, + { JAVA_CHAR, (Function<MemorySegment, Object>) s -> s.toArray(JAVA_CHAR)}, + { JAVA_INT, (Function<MemorySegment, Object>)s -> s.toArray(JAVA_INT)}, + { JAVA_FLOAT, (Function<MemorySegment, Object>)s -> s.toArray(JAVA_FLOAT)}, + { JAVA_LONG, (Function<MemorySegment, Object>)s -> s.toArray(JAVA_LONG)}, + { JAVA_DOUBLE, (Function<MemorySegment, Object>)s -> s.toArray(JAVA_DOUBLE)} }; } } diff --git a/test/jdk/java/foreign/TestByteBuffer.java b/test/jdk/java/foreign/TestByteBuffer.java index cdc9addb38132ba361e4d1939294a334c940d8ca..ce5f55efb0d6344743524ef59c670678454611a9 100644 --- a/test/jdk/java/foreign/TestByteBuffer.java +++ b/test/jdk/java/foreign/TestByteBuffer.java @@ -28,8 +28,6 @@ * @run testng/othervm --enable-native-access=ALL-UNNAMED TestByteBuffer */ -import jdk.incubator.foreign.MemoryAccess; -import jdk.incubator.foreign.MemoryLayouts; import jdk.incubator.foreign.MemoryLayout; import jdk.incubator.foreign.MemoryAddress; import jdk.incubator.foreign.MemorySegment; @@ -82,6 +80,13 @@ import org.testng.SkipException; import org.testng.annotations.*; import sun.nio.ch.DirectBuffer; +import static jdk.incubator.foreign.ValueLayout.JAVA_BYTE; +import static jdk.incubator.foreign.ValueLayout.JAVA_CHAR; +import static jdk.incubator.foreign.ValueLayout.JAVA_DOUBLE; +import static jdk.incubator.foreign.ValueLayout.JAVA_FLOAT; +import static jdk.incubator.foreign.ValueLayout.JAVA_INT; +import static jdk.incubator.foreign.ValueLayout.JAVA_LONG; +import static jdk.incubator.foreign.ValueLayout.JAVA_SHORT; import static org.testng.Assert.*; public class TestByteBuffer { @@ -102,40 +107,40 @@ public class TestByteBuffer { static SequenceLayout tuples = MemoryLayout.sequenceLayout(500, MemoryLayout.structLayout( - MemoryLayouts.BITS_32_BE.withName("index"), - MemoryLayouts.BITS_32_BE.withName("value") + JAVA_INT.withOrder(ByteOrder.BIG_ENDIAN).withName("index"), + JAVA_FLOAT.withOrder(ByteOrder.BIG_ENDIAN).withName("value") )); static SequenceLayout bytes = MemoryLayout.sequenceLayout(100, - MemoryLayouts.BITS_8_BE + JAVA_BYTE ); static SequenceLayout chars = MemoryLayout.sequenceLayout(100, - MemoryLayouts.BITS_16_BE + JAVA_CHAR.withOrder(ByteOrder.BIG_ENDIAN) ); static SequenceLayout shorts = MemoryLayout.sequenceLayout(100, - MemoryLayouts.BITS_16_BE + JAVA_SHORT.withOrder(ByteOrder.BIG_ENDIAN) ); static SequenceLayout ints = MemoryLayout.sequenceLayout(100, - MemoryLayouts.BITS_32_BE + JAVA_INT.withOrder(ByteOrder.BIG_ENDIAN) ); static SequenceLayout floats = MemoryLayout.sequenceLayout(100, - MemoryLayouts.BITS_32_BE + JAVA_FLOAT.withOrder(ByteOrder.BIG_ENDIAN) ); static SequenceLayout longs = MemoryLayout.sequenceLayout(100, - MemoryLayouts.BITS_64_BE + JAVA_LONG.withOrder(ByteOrder.BIG_ENDIAN) ); static SequenceLayout doubles = MemoryLayout.sequenceLayout(100, - MemoryLayouts.BITS_64_BE + JAVA_DOUBLE.withOrder(ByteOrder.BIG_ENDIAN) ); - static VarHandle indexHandle = tuples.varHandle(int.class, PathElement.sequenceElement(), PathElement.groupElement("index")); - static VarHandle valueHandle = tuples.varHandle(float.class, PathElement.sequenceElement(), PathElement.groupElement("value")); + static VarHandle indexHandle = tuples.varHandle(PathElement.sequenceElement(), PathElement.groupElement("index")); + static VarHandle valueHandle = tuples.varHandle(PathElement.sequenceElement(), PathElement.groupElement("value")); static void initTuples(MemorySegment base, long count) { for (long i = 0; i < count ; i++) { @@ -263,7 +268,7 @@ public class TestByteBuffer { } } - @Test(dataProvider = "mappedOps", expectedExceptions = UnsupportedOperationException.class) + @Test(dataProvider = "mappedOps", expectedExceptions = IllegalStateException.class) public void testMappedSegmentOperations(MappedSegmentOp mappedBufferOp) throws Throwable { File f = new File("test3.out"); f.createNewFile(); @@ -324,6 +329,9 @@ public class TestByteBuffer { segment.isLoaded(); segment.unload(); segment.isLoaded(); + } catch(IOException e) { + if (e.getMessage().equals("Function not implemented")) + throw new SkipException(e.getMessage(), e); } } @@ -361,7 +369,7 @@ public class TestByteBuffer { Throwable cause = ex.getCause(); if (cause instanceof IllegalStateException) { //all get/set buffer operation should fail because of the scope check - assertTrue(ex.getCause().getMessage().contains("Already closed")); + assertTrue(ex.getCause().getMessage().contains("already closed")); } else { //all other exceptions were unexpected - fail fail("Unexpected exception", cause); @@ -398,7 +406,7 @@ public class TestByteBuffer { handle.invoke(e.getValue()); fail(); } catch (IllegalStateException ex) { - assertTrue(ex.getMessage().contains("Already closed")); + assertTrue(ex.getMessage().contains("already closed")); } catch (UnsupportedOperationException ex) { //skip } catch (Throwable ex) { @@ -480,7 +488,7 @@ public class TestByteBuffer { @Test(expectedExceptions = IllegalStateException.class) public void testTooBigForByteBuffer() { - MemorySegment segment = MemoryAddress.NULL.asSegment(Integer.MAX_VALUE + 10L, ResourceScope.globalScope()); + MemorySegment segment = MemorySegment.ofAddress(MemoryAddress.NULL, Integer.MAX_VALUE + 10L, ResourceScope.newImplicitScope()); segment.asByteBuffer(); } @@ -511,7 +519,7 @@ public class TestByteBuffer { try (ResourceScope scope = ResourceScope.newConfinedScope()) { MemorySegment segment = MemorySegment.mapFile(f.toPath(), 0, SIZE, FileChannel.MapMode.READ_WRITE, scope); for (byte offset = 0; offset < SIZE; offset++) { - MemoryAccess.setByteAtOffset(segment, offset, offset); + segment.set(JAVA_BYTE, offset, offset); } segment.force(); } @@ -519,7 +527,7 @@ public class TestByteBuffer { for (int offset = 0 ; offset < SIZE ; offset++) { try (ResourceScope scope = ResourceScope.newConfinedScope()) { MemorySegment segment = MemorySegment.mapFile(f.toPath(), offset, SIZE - offset, FileChannel.MapMode.READ_ONLY, scope); - assertEquals(MemoryAccess.getByte(segment), offset); + assertEquals(segment.get(JAVA_BYTE, 0), offset); } } } @@ -636,13 +644,13 @@ public class TestByteBuffer { @Test(expectedExceptions = IllegalStateException.class) public void testDeadAccessOnClosedBufferSegment() { - MemorySegment s1 = MemorySegment.allocateNative(MemoryLayouts.JAVA_INT, ResourceScope.newConfinedScope()); + MemorySegment s1 = MemorySegment.allocateNative(JAVA_INT, ResourceScope.newConfinedScope()); MemorySegment s2 = MemorySegment.ofByteBuffer(s1.asByteBuffer()); // memory freed s1.scope().close(); - MemoryAccess.setInt(s2, 10); // Dead access! + s2.set(JAVA_INT, 0, 10); // Dead access! } @Test(dataProvider = "allScopes") @@ -654,7 +662,7 @@ public class TestByteBuffer { ResourceScope scp = closeableScopeOrNull(scope = scopeSupplier.get())) { MemorySegment segment = MemorySegment.allocateNative(10, 1, scope); for (int i = 0; i < 10; i++) { - MemoryAccess.setByteAtOffset(segment, i, (byte) i); + segment.set(JAVA_BYTE, i, (byte) i); } ByteBuffer bb = segment.asByteBuffer(); assertEquals(channel.write(bb), 10); @@ -674,7 +682,7 @@ public class TestByteBuffer { try (FileChannel channel = FileChannel.open(tmp.toPath(), StandardOpenOption.READ, StandardOpenOption.WRITE)) { MemorySegment segment = MemorySegment.allocateNative(10, scopeSupplier.get()); for (int i = 0; i < 10; i++) { - MemoryAccess.setByteAtOffset(segment, i, (byte) i); + segment.set(JAVA_BYTE, i, (byte) i); } ByteBuffer bb = segment.asByteBuffer(); segment.scope().close(); @@ -694,7 +702,7 @@ public class TestByteBuffer { int newSize = 8; var slice = segment.asSlice(4, newSize); - var bytes = slice.toByteArray(); + var bytes = slice.toArray(JAVA_BYTE); assertEquals(newSize, bytes.length); var buffer = slice.asByteBuffer(); @@ -719,6 +727,7 @@ public class TestByteBuffer { public static Object[][] segments() throws Throwable { return new Object[][] { { (Supplier<MemorySegment>) () -> MemorySegment.allocateNative(16, ResourceScope.newImplicitScope()) }, + { (Supplier<MemorySegment>) () -> MemorySegment.allocateNative(16, ResourceScope.newConfinedScope()) }, { (Supplier<MemorySegment>) () -> MemorySegment.ofArray(new byte[16]) } }; } @@ -729,27 +738,20 @@ public class TestByteBuffer { { (Supplier<ResourceScope>) () -> ResourceScope.newSharedScope() }, { (Supplier<ResourceScope>) () -> ResourceScope.newConfinedScope() }, { (Supplier<ResourceScope>) () -> ResourceScope.newSharedScope(Cleaner.create()) }, - { (Supplier<ResourceScope>) () -> ResourceScope.newConfinedScope(Cleaner.create()) } - }; - } - - @DataProvider(name = "implicitScopes") - public static Object[][] implicitScopes() { - return new Object[][] { - { (Supplier<ResourceScope>) ResourceScope::newImplicitScope }, - { (Supplier<ResourceScope>) ResourceScope::globalScope }, + { (Supplier<ResourceScope>) () -> ResourceScope.newConfinedScope(Cleaner.create()) }, + { (Supplier<ResourceScope>) () -> ResourceScope.newImplicitScope() } }; } @DataProvider(name = "allScopes") public static Object[][] allScopes() { - return Stream.of(implicitScopes(), closeableScopes()) + return Stream.of(new Object[][] { { (Supplier<ResourceScope>)ResourceScope::globalScope } }, closeableScopes()) .flatMap(Arrays::stream) .toArray(Object[][]::new); } static ResourceScope closeableScopeOrNull(ResourceScope scope) { - if (scope.isImplicit()) + if (scope == ResourceScope.globalScope()) return null; return scope; } @@ -812,34 +814,34 @@ public class TestByteBuffer { @DataProvider(name = "resizeOps") public Object[][] resizeOps() { Consumer<MemorySegment> byteInitializer = - (base) -> initBytes(base, bytes, (addr, pos) -> MemoryAccess.setByteAtOffset(addr, pos, (byte)(long)pos)); + (base) -> initBytes(base, bytes, (addr, pos) -> addr.set(JAVA_BYTE, pos, (byte)(long)pos)); Consumer<MemorySegment> charInitializer = - (base) -> initBytes(base, chars, (addr, pos) -> MemoryAccess.setCharAtIndex(addr, pos, ByteOrder.BIG_ENDIAN, (char)(long)pos)); + (base) -> initBytes(base, chars, (addr, pos) -> addr.setAtIndex(JAVA_CHAR.withOrder(ByteOrder.BIG_ENDIAN), pos, (char)(long)pos)); Consumer<MemorySegment> shortInitializer = - (base) -> initBytes(base, shorts, (addr, pos) -> MemoryAccess.setShortAtIndex(addr, pos, ByteOrder.BIG_ENDIAN, (short)(long)pos)); + (base) -> initBytes(base, shorts, (addr, pos) -> addr.setAtIndex(JAVA_SHORT.withOrder(ByteOrder.BIG_ENDIAN), pos, (short)(long)pos)); Consumer<MemorySegment> intInitializer = - (base) -> initBytes(base, ints, (addr, pos) -> MemoryAccess.setIntAtIndex(addr, pos, ByteOrder.BIG_ENDIAN, (int)(long)pos)); + (base) -> initBytes(base, ints, (addr, pos) -> addr.setAtIndex(JAVA_INT.withOrder(ByteOrder.BIG_ENDIAN), pos, (int)(long)pos)); Consumer<MemorySegment> floatInitializer = - (base) -> initBytes(base, floats, (addr, pos) -> MemoryAccess.setFloatAtIndex(addr, pos, ByteOrder.BIG_ENDIAN, (float)(long)pos)); + (base) -> initBytes(base, floats, (addr, pos) -> addr.setAtIndex(JAVA_FLOAT.withOrder(ByteOrder.BIG_ENDIAN), pos, (float)(long)pos)); Consumer<MemorySegment> longInitializer = - (base) -> initBytes(base, longs, (addr, pos) -> MemoryAccess.setLongAtIndex(addr, pos, ByteOrder.BIG_ENDIAN, (long)pos)); + (base) -> initBytes(base, longs, (addr, pos) -> addr.setAtIndex(JAVA_LONG.withOrder(ByteOrder.BIG_ENDIAN), pos, (long)pos)); Consumer<MemorySegment> doubleInitializer = - (base) -> initBytes(base, doubles, (addr, pos) -> MemoryAccess.setDoubleAtIndex(addr, pos, ByteOrder.BIG_ENDIAN, (double)(long)pos)); + (base) -> initBytes(base, doubles, (addr, pos) -> addr.setAtIndex(JAVA_DOUBLE.withOrder(ByteOrder.BIG_ENDIAN), pos, (double)(long)pos)); Consumer<MemorySegment> byteChecker = - (base) -> checkBytes(base, bytes, Function.identity(), (addr, pos) -> MemoryAccess.getByteAtOffset(addr, pos), ByteBuffer::get); + (base) -> checkBytes(base, bytes, Function.identity(), (addr, pos) -> addr.get(JAVA_BYTE, pos), ByteBuffer::get); Consumer<MemorySegment> charChecker = - (base) -> checkBytes(base, chars, ByteBuffer::asCharBuffer, (addr, pos) -> MemoryAccess.getCharAtIndex(addr, pos, ByteOrder.BIG_ENDIAN), CharBuffer::get); + (base) -> checkBytes(base, chars, ByteBuffer::asCharBuffer, (addr, pos) -> addr.getAtIndex(JAVA_CHAR.withOrder(ByteOrder.BIG_ENDIAN), pos), CharBuffer::get); Consumer<MemorySegment> shortChecker = - (base) -> checkBytes(base, shorts, ByteBuffer::asShortBuffer, (addr, pos) -> MemoryAccess.getShortAtIndex(addr, pos, ByteOrder.BIG_ENDIAN), ShortBuffer::get); + (base) -> checkBytes(base, shorts, ByteBuffer::asShortBuffer, (addr, pos) -> addr.getAtIndex(JAVA_SHORT.withOrder(ByteOrder.BIG_ENDIAN), pos), ShortBuffer::get); Consumer<MemorySegment> intChecker = - (base) -> checkBytes(base, ints, ByteBuffer::asIntBuffer, (addr, pos) -> MemoryAccess.getIntAtIndex(addr, pos, ByteOrder.BIG_ENDIAN), IntBuffer::get); + (base) -> checkBytes(base, ints, ByteBuffer::asIntBuffer, (addr, pos) -> addr.getAtIndex(JAVA_INT.withOrder(ByteOrder.BIG_ENDIAN), pos), IntBuffer::get); Consumer<MemorySegment> floatChecker = - (base) -> checkBytes(base, floats, ByteBuffer::asFloatBuffer, (addr, pos) -> MemoryAccess.getFloatAtIndex(addr, pos, ByteOrder.BIG_ENDIAN), FloatBuffer::get); + (base) -> checkBytes(base, floats, ByteBuffer::asFloatBuffer, (addr, pos) -> addr.getAtIndex(JAVA_FLOAT.withOrder(ByteOrder.BIG_ENDIAN), pos), FloatBuffer::get); Consumer<MemorySegment> longChecker = - (base) -> checkBytes(base, longs, ByteBuffer::asLongBuffer, (addr, pos) -> MemoryAccess.getLongAtIndex(addr, pos, ByteOrder.BIG_ENDIAN), LongBuffer::get); + (base) -> checkBytes(base, longs, ByteBuffer::asLongBuffer, (addr, pos) -> addr.getAtIndex(JAVA_LONG.withOrder(ByteOrder.BIG_ENDIAN), pos), LongBuffer::get); Consumer<MemorySegment> doubleChecker = - (base) -> checkBytes(base, doubles, ByteBuffer::asDoubleBuffer, (addr, pos) -> MemoryAccess.getDoubleAtIndex(addr, pos, ByteOrder.BIG_ENDIAN), DoubleBuffer::get); + (base) -> checkBytes(base, doubles, ByteBuffer::asDoubleBuffer, (addr, pos) -> addr.getAtIndex(JAVA_DOUBLE.withOrder(ByteOrder.BIG_ENDIAN), pos), DoubleBuffer::get); return new Object[][]{ {byteChecker, byteInitializer, bytes}, diff --git a/test/jdk/java/foreign/TestCircularInit1.java b/test/jdk/java/foreign/TestCircularInit1.java deleted file mode 100644 index 46a98bd23f8d808104d1a22c7e7196de32507c6e..0000000000000000000000000000000000000000 --- a/test/jdk/java/foreign/TestCircularInit1.java +++ /dev/null @@ -1,45 +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. - */ - -/* - * @test - * @requires ((os.arch == "amd64" | os.arch == "x86_64") & sun.arch.data.model == "64") | os.arch == "aarch64" - * @modules jdk.incubator.foreign/jdk.internal.foreign - * @run testng/othervm TestCircularInit1 - */ - -import jdk.incubator.foreign.CLinker; -import jdk.internal.foreign.PlatformLayouts; -import org.testng.annotations.Test; - -import static org.testng.Assert.assertNotNull; - -public class TestCircularInit1 { - - @Test - public void testCircularInit() { - System.out.println(PlatformLayouts.Win64.C_CHAR); // trigger clinit - assertNotNull(CLinker.C_CHAR); // should not be null - } - -} diff --git a/test/jdk/java/foreign/TestCircularInit2.java b/test/jdk/java/foreign/TestCircularInit2.java deleted file mode 100644 index 0eeed8184cf84d2eed124dfbaa2cffa05688d6cb..0000000000000000000000000000000000000000 --- a/test/jdk/java/foreign/TestCircularInit2.java +++ /dev/null @@ -1,47 +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. - */ - -/* - * @test - * @requires ((os.arch == "amd64" | os.arch == "x86_64") & sun.arch.data.model == "64") | os.arch == "aarch64" - * @modules jdk.incubator.foreign/jdk.internal.foreign - * @run testng/othervm TestCircularInit2 - */ - -import jdk.incubator.foreign.CLinker; -import jdk.internal.foreign.PlatformLayouts; -import org.testng.annotations.Test; - -import static org.testng.Assert.assertNotNull; - -public class TestCircularInit2 { - - @Test - public void testCircularInit() { - System.out.println(CLinker.C_CHAR); // trigger clinit - assertNotNull(PlatformLayouts.Win64.C_CHAR); - assertNotNull(PlatformLayouts.SysV.C_CHAR); - assertNotNull(PlatformLayouts.AArch64.C_CHAR); - } - -} diff --git a/test/jdk/java/foreign/TestCondy.java b/test/jdk/java/foreign/TestCondy.java index 0f262214799d0d4298f1b7cb6efde318597b72f7..42191dd4a2491f508bd50d53bcfc542c726d2333 100644 --- a/test/jdk/java/foreign/TestCondy.java +++ b/test/jdk/java/foreign/TestCondy.java @@ -39,7 +39,15 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import static jdk.incubator.foreign.CLinker.*; +import static jdk.incubator.foreign.ValueLayout.ADDRESS; +import static jdk.incubator.foreign.ValueLayout.JAVA_BOOLEAN; +import static jdk.incubator.foreign.ValueLayout.JAVA_BYTE; +import static jdk.incubator.foreign.ValueLayout.JAVA_CHAR; +import static jdk.incubator.foreign.ValueLayout.JAVA_DOUBLE; +import static jdk.incubator.foreign.ValueLayout.JAVA_FLOAT; +import static jdk.incubator.foreign.ValueLayout.JAVA_INT; +import static jdk.incubator.foreign.ValueLayout.JAVA_LONG; +import static jdk.incubator.foreign.ValueLayout.JAVA_SHORT; import static org.testng.Assert.assertEquals; public class TestCondy { @@ -53,14 +61,15 @@ public class TestCondy { private static final MemoryLayout[] constants = { - C_CHAR, - C_SHORT, - C_INT, - C_LONG, - C_LONG_LONG, - C_FLOAT, - C_DOUBLE, - C_POINTER + JAVA_BOOLEAN, + JAVA_CHAR, + JAVA_BYTE, + JAVA_SHORT, + JAVA_INT, + JAVA_FLOAT, + JAVA_LONG, + JAVA_DOUBLE, + ADDRESS }; @DataProvider @@ -78,7 +87,7 @@ public class TestCondy { } testValues.add(FunctionDescriptor.ofVoid(constants)); - testValues.add(FunctionDescriptor.of(C_CHAR, constants)); + testValues.add(FunctionDescriptor.of(JAVA_BYTE, constants)); return testValues.stream().map(e -> new Object[] { e }).toArray(Object[][]::new); } diff --git a/test/jdk/java/foreign/TestDowncall.java b/test/jdk/java/foreign/TestDowncall.java index 8a78a20e1fbaad627781914b482136c32ebb4cda..ee7ec2fa01b2b21e331aa48a4bb1593b582f79f3 100644 --- a/test/jdk/java/foreign/TestDowncall.java +++ b/test/jdk/java/foreign/TestDowncall.java @@ -31,10 +31,17 @@ * @run testng/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyDependencies * --enable-native-access=ALL-UNNAMED -Dgenerator.sample.factor=17 * TestDowncall + * + * @run testng/othervm -Xint -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyDependencies + * --enable-native-access=ALL-UNNAMED -Dgenerator.sample.factor=100000 + * TestDowncall */ +import jdk.incubator.foreign.Addressable; import jdk.incubator.foreign.CLinker; import jdk.incubator.foreign.FunctionDescriptor; +import jdk.incubator.foreign.NativeSymbol; +import jdk.incubator.foreign.ResourceScope; import jdk.incubator.foreign.SymbolLookup; import jdk.incubator.foreign.MemoryAddress; import jdk.incubator.foreign.MemoryLayout; @@ -52,7 +59,7 @@ import static org.testng.Assert.*; public class TestDowncall extends CallGeneratorHelper { - static CLinker abi = CLinker.getInstance(); + static CLinker abi = CLinker.systemCLinker(); static { System.loadLibrary("TestDowncall"); } @@ -62,64 +69,37 @@ public class TestDowncall extends CallGeneratorHelper { @Test(dataProvider="functions", dataProviderClass=CallGeneratorHelper.class) public void testDowncall(int count, String fName, Ret ret, List<ParamType> paramTypes, List<StructFieldType> fields) throws Throwable { List<Consumer<Object>> checks = new ArrayList<>(); - MemoryAddress addr = LOOKUP.lookup(fName).get(); + NativeSymbol addr = LOOKUP.lookup(fName).get(); MethodType mt = methodType(ret, paramTypes, fields); FunctionDescriptor descriptor = function(ret, paramTypes, fields); Object[] args = makeArgs(paramTypes, fields, checks); - try (NativeScope scope = new NativeScope()) { + try (ResourceScope scope = ResourceScope.newSharedScope()) { boolean needsScope = mt.returnType().equals(MemorySegment.class); - Object res = doCall(addr, scope, mt, descriptor, args); + SegmentAllocator allocator = needsScope ? + SegmentAllocator.newNativeArena(scope) : + THROWING_ALLOCATOR; + Object res = doCall(addr, allocator, descriptor, args); if (ret == Ret.NON_VOID) { checks.forEach(c -> c.accept(res)); if (needsScope) { // check that return struct has indeed been allocated in the native scope - assertEquals(((MemorySegment) res).scope(), scope.scope()); - assertEquals(scope.allocatedBytes(), descriptor.returnLayout().get().byteSize()); - } else { - // if here, there should be no allocation through the scope! - assertEquals(scope.allocatedBytes(), 0L); - } - } else { - // if here, there should be no allocation through the scope! - assertEquals(scope.allocatedBytes(), 0L); - } - } - } - - @Test(dataProvider="functions", dataProviderClass=CallGeneratorHelper.class) - public void testDowncallNoScope(int count, String fName, Ret ret, List<ParamType> paramTypes, List<StructFieldType> fields) throws Throwable { - List<Consumer<Object>> checks = new ArrayList<>(); - MemoryAddress addr = LOOKUP.lookup(fName).get(); - MethodType mt = methodType(ret, paramTypes, fields); - FunctionDescriptor descriptor = function(ret, paramTypes, fields); - Object[] args = makeArgs(paramTypes, fields, checks); - boolean needsScope = mt.returnType().equals(MemorySegment.class); - Object res = doCall(addr, IMPLICIT_ALLOCATOR, mt, descriptor, args); - if (ret == Ret.NON_VOID) { - checks.forEach(c -> c.accept(res)); - if (needsScope) { - // check that return struct has indeed been allocated in the default scope - try { - ((MemorySegment)res).scope().close(); // should throw - fail("Expected exception!"); - } catch (UnsupportedOperationException ex) { - // ok + assertEquals(((MemorySegment) res).scope(), scope); } } } } - Object doCall(MemoryAddress addr, SegmentAllocator allocator, MethodType type, FunctionDescriptor descriptor, Object[] args) throws Throwable { - MethodHandle mh = abi.downcallHandle(addr, allocator, type, descriptor); + Object doCall(NativeSymbol symbol, SegmentAllocator allocator, FunctionDescriptor descriptor, Object[] args) throws Throwable { + MethodHandle mh = downcallHandle(abi, symbol, allocator, descriptor); Object res = mh.invokeWithArguments(args); return res; } static MethodType methodType(Ret ret, List<ParamType> params, List<StructFieldType> fields) { MethodType mt = ret == Ret.VOID ? - MethodType.methodType(void.class) : MethodType.methodType(paramCarrier(params.get(0).layout(fields))); + MethodType.methodType(void.class) : MethodType.methodType(carrier(params.get(0).layout(fields), false)); for (ParamType p : params) { - mt = mt.appendParameterTypes(paramCarrier(p.layout(fields))); + mt = mt.appendParameterTypes(carrier(p.layout(fields), true)); } return mt; } diff --git a/test/jdk/java/foreign/TestFree.java b/test/jdk/java/foreign/TestFree.java index ad26e1eb5715bf630ca8408aa7f3dc682b2219bf..b009cee0ac4e57594982942bd3b2fe4a26b79b39 100644 --- a/test/jdk/java/foreign/TestFree.java +++ b/test/jdk/java/foreign/TestFree.java @@ -29,18 +29,16 @@ * @run testng/othervm --enable-native-access=ALL-UNNAMED TestFree */ -import jdk.incubator.foreign.MemoryAccess; import jdk.incubator.foreign.MemoryAddress; import jdk.incubator.foreign.MemoryLayout; import jdk.incubator.foreign.MemorySegment; import jdk.incubator.foreign.ResourceScope; -import static jdk.incubator.foreign.CLinker.*; import static org.testng.Assert.assertEquals; -public class TestFree { +public class TestFree extends NativeTestHelper { private static MemorySegment asArray(MemoryAddress addr, MemoryLayout layout, int numElements) { - return addr.asSegment(numElements * layout.byteSize(), ResourceScope.globalScope()); + return MemorySegment.ofAddress(addr, numElements * layout.byteSize(), ResourceScope.globalScope()); } public void test() throws Throwable { @@ -48,8 +46,8 @@ public class TestFree { MemoryAddress addr = allocateMemory(str.length() + 1); MemorySegment seg = asArray(addr, C_CHAR, str.length() + 1); seg.copyFrom(MemorySegment.ofArray(str.getBytes())); - MemoryAccess.setByteAtOffset(seg, str.length(), (byte)0); - assertEquals(str, toJavaString(seg)); + seg.set(C_CHAR, str.length(), (byte)0); + assertEquals(str, seg.getUtf8String(0)); freeMemory(addr); } } diff --git a/test/jdk/java/foreign/TestFunctionDescriptor.java b/test/jdk/java/foreign/TestFunctionDescriptor.java index d8b82254dafcd34a37222ed2ea6b7420bf78532d..7f6eb908744f3ade366d87e0e77fb65ea115318b 100644 --- a/test/jdk/java/foreign/TestFunctionDescriptor.java +++ b/test/jdk/java/foreign/TestFunctionDescriptor.java @@ -25,27 +25,21 @@ /* * @test * @requires ((os.arch == "amd64" | os.arch == "x86_64") & sun.arch.data.model == "64") | os.arch == "aarch64" - * @run testng TestFunctionDescriptor + * @run testng/othervm --enable-native-access=ALL-UNNAMED TestFunctionDescriptor */ import jdk.incubator.foreign.FunctionDescriptor; import jdk.incubator.foreign.MemoryLayout; import org.testng.annotations.Test; -import java.lang.constant.Constable; import java.util.List; import java.util.Optional; -import java.util.stream.Collectors; -import static jdk.incubator.foreign.CLinker.C_DOUBLE; -import static jdk.incubator.foreign.CLinker.C_INT; -import static jdk.incubator.foreign.CLinker.C_LONG_LONG; -import static jdk.incubator.foreign.CLinker.C_POINTER; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertFalse; import static org.testng.Assert.assertTrue; -public class TestFunctionDescriptor { +public class TestFunctionDescriptor extends NativeTestHelper { static final String DUMMY_ATTR = "dummy"; @@ -68,56 +62,35 @@ public class TestFunctionDescriptor { assertFalse(returnLayoutOp.isPresent()); } - @Test - public void testAttribute() { - FunctionDescriptor fd = FunctionDescriptor.of(C_INT, C_DOUBLE, C_LONG_LONG); - fd = fd.withAttribute(DUMMY_ATTR, true); - - assertEquals(fd.argumentLayouts(), List.of(C_DOUBLE, C_LONG_LONG)); - Optional<MemoryLayout> returnLayoutOp = fd.returnLayout(); - assertTrue(returnLayoutOp.isPresent()); - assertEquals(returnLayoutOp.get(), C_INT); - assertEquals(fd.attributes().collect(Collectors.toList()), List.of(DUMMY_ATTR)); - Optional<Constable> attr = fd.attribute(DUMMY_ATTR); - assertTrue(attr.isPresent()); - assertEquals(attr.get(), true); - } - @Test public void testAppendArgumentLayouts() { - FunctionDescriptor fd = FunctionDescriptor.of(C_INT, C_DOUBLE, C_LONG_LONG) - .withAttribute(DUMMY_ATTR, true); - fd = fd.withAppendedArgumentLayouts(C_POINTER); + FunctionDescriptor fd = FunctionDescriptor.of(C_INT, C_DOUBLE, C_LONG_LONG); + fd = fd.appendArgumentLayouts(C_POINTER); assertEquals(fd.argumentLayouts(), List.of(C_DOUBLE, C_LONG_LONG, C_POINTER)); Optional<MemoryLayout> returnLayoutOp = fd.returnLayout(); assertTrue(returnLayoutOp.isPresent()); assertEquals(returnLayoutOp.get(), C_INT); - assertEquals(fd.attributes().collect(Collectors.toList()), List.of(DUMMY_ATTR)); } @Test public void testChangeReturnLayout() { - FunctionDescriptor fd = FunctionDescriptor.of(C_INT, C_DOUBLE, C_LONG_LONG) - .withAttribute(DUMMY_ATTR, true); - fd = fd.withReturnLayout(C_INT); + FunctionDescriptor fd = FunctionDescriptor.of(C_INT, C_DOUBLE, C_LONG_LONG); + fd = fd.changeReturnLayout(C_INT); assertEquals(fd.argumentLayouts(), List.of(C_DOUBLE, C_LONG_LONG)); Optional<MemoryLayout> returnLayoutOp = fd.returnLayout(); assertTrue(returnLayoutOp.isPresent()); assertEquals(returnLayoutOp.get(), C_INT); - assertEquals(fd.attributes().collect(Collectors.toList()), List.of(DUMMY_ATTR)); } @Test public void testDropReturnLayout() { - FunctionDescriptor fd = FunctionDescriptor.of(C_INT, C_DOUBLE, C_LONG_LONG) - .withAttribute(DUMMY_ATTR, true); - fd = fd.withVoidReturnLayout(); + FunctionDescriptor fd = FunctionDescriptor.of(C_INT, C_DOUBLE, C_LONG_LONG); + fd = fd.dropReturnLayout(); assertEquals(fd.argumentLayouts(), List.of(C_DOUBLE, C_LONG_LONG)); Optional<MemoryLayout> returnLayoutOp = fd.returnLayout(); assertFalse(returnLayoutOp.isPresent()); - assertEquals(fd.attributes().collect(Collectors.toList()), List.of(DUMMY_ATTR)); } } diff --git a/test/jdk/java/foreign/TestHandshake.java b/test/jdk/java/foreign/TestHandshake.java index ee9b739459465ed1e65d9099c0ed1c2b0f1437ff..94fdd8cbf1828aacc2b4e2c262bdcd9de315836b 100644 --- a/test/jdk/java/foreign/TestHandshake.java +++ b/test/jdk/java/foreign/TestHandshake.java @@ -31,7 +31,6 @@ * @run testng/othervm -XX:-TieredCompilation TestHandshake */ -import jdk.incubator.foreign.MemoryAccess; import jdk.incubator.foreign.MemorySegment; import java.lang.invoke.MethodHandles; @@ -48,6 +47,8 @@ import java.util.concurrent.atomic.AtomicLong; import jdk.incubator.foreign.ResourceScope; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; + +import static jdk.incubator.foreign.ValueLayout.JAVA_BYTE; import static org.testng.Assert.*; public class TestHandshake { @@ -150,7 +151,7 @@ public class TestHandshake { void doAccess() { int sum = 0; for (int i = 0; i < segment.byteSize(); i++) { - sum += MemoryAccess.getByteAtOffset(segment, i); + sum += segment.get(JAVA_BYTE, i); } } } @@ -193,7 +194,7 @@ public class TestHandshake { super(id, segment); this.copy = MemorySegment.allocateNative(SEGMENT_SIZE, 1, segment.scope()); copy.copyFrom(segment); - MemoryAccess.setByteAtOffset(copy, ThreadLocalRandom.current().nextInt(SEGMENT_SIZE), (byte)42); + copy.set(JAVA_BYTE, ThreadLocalRandom.current().nextInt(SEGMENT_SIZE), (byte)42); } @Override diff --git a/test/jdk/java/foreign/TestHeapAlignment.java b/test/jdk/java/foreign/TestHeapAlignment.java new file mode 100644 index 0000000000000000000000000000000000000000..3395a686f38e7114e7b1c0a7505b8eb99263cfc1 --- /dev/null +++ b/test/jdk/java/foreign/TestHeapAlignment.java @@ -0,0 +1,131 @@ +/* + * 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. + * + */ + +/* + * @test + * @requires ((os.arch == "amd64" | os.arch == "x86_64") & sun.arch.data.model == "64") | os.arch == "aarch64" + * @run testng/othervm --enable-native-access=ALL-UNNAMED TestHeapAlignment + */ + +import jdk.incubator.foreign.MemoryAddress; +import jdk.incubator.foreign.MemoryLayout; +import jdk.incubator.foreign.MemorySegment; +import jdk.incubator.foreign.ResourceScope; +import jdk.incubator.foreign.ValueLayout; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Function; + +import static org.testng.Assert.fail; + +public class TestHeapAlignment { + + @Test(dataProvider = "layouts") + public void testHeapAlignment(MemorySegment segment, int align, Object val, Object arr, ValueLayout layout, Function<Object, MemorySegment> segmentFactory) { + assertAligned(align, layout, () -> layout.varHandle().get(segment)); + assertAligned(align, layout, () -> layout.varHandle().set(segment, val)); + MemoryLayout seq = MemoryLayout.sequenceLayout(10, layout); + assertAligned(align, layout, () -> seq.varHandle(MemoryLayout.PathElement.sequenceElement()).get(segment, 0L)); + assertAligned(align, layout, () -> seq.varHandle(MemoryLayout.PathElement.sequenceElement()).set(segment, 0L, val)); + assertAligned(align, layout, () -> segment.spliterator(layout)); + if (arr != null) { + assertAligned(align, layout, () -> MemorySegment.copy(arr, 0, segment, layout, 0, 1)); + assertAligned(align, layout, () -> MemorySegment.copy(segment, layout, 0, arr, 0, 1)); + assertAligned(align, layout, () -> { + MemorySegment other = segmentFactory.apply(arr); + MemorySegment.copy(other, layout, 0, segment, layout, 0, 1); + }); + MemorySegment other = segmentFactory.apply(arr); + assertAligned(align, layout, () -> { + MemorySegment.copy(segment, layout, 0, other, layout, 0, 1); + }); + assertAligned(align, layout, () -> { + MemorySegment.copy(other, layout, 0, segment, layout, 0, 1); + }); + } + } + + static void assertAligned(int align, ValueLayout layout, Runnable runnable) { + boolean shouldFail = layout.byteAlignment() > align && align != -1; + try { + runnable.run(); + if (shouldFail) { + fail("Should not get here!"); + } + } catch (IllegalArgumentException ex) { + if (!shouldFail) { + fail("Should not get here!"); + } else if (!ex.getMessage().contains("alignment") && !ex.getMessage().contains("Misaligned")) { + fail("Unexpected exception: " + ex); + } + } + } + + static final ValueLayout.OfChar JAVA_CHAR_ALIGNED = ValueLayout.JAVA_CHAR.withBitAlignment(16); + static final ValueLayout.OfShort JAVA_SHORT_ALIGNED = ValueLayout.JAVA_SHORT.withBitAlignment(16); + static final ValueLayout.OfInt JAVA_INT_ALIGNED = ValueLayout.JAVA_INT.withBitAlignment(32); + static final ValueLayout.OfFloat JAVA_FLOAT_ALIGNED = ValueLayout.JAVA_FLOAT.withBitAlignment(32); + static final ValueLayout.OfLong JAVA_LONG_ALIGNED = ValueLayout.JAVA_LONG.withBitAlignment(64); + static final ValueLayout.OfDouble JAVA_DOUBLE_ALIGNED = ValueLayout.JAVA_DOUBLE.withBitAlignment(64); + static final ValueLayout.OfAddress ADDRESS_ALIGNED = ValueLayout.ADDRESS.withBitAlignment(ValueLayout.ADDRESS.bitSize()); + + enum SegmentAndAlignment { + HEAP_BYTE(MemorySegment.ofArray(new byte[8]), 1), + HEAP_SHORT(MemorySegment.ofArray(new short[4]), 2), + HEAP_CHAR(MemorySegment.ofArray(new char[4]), 2), + HEAP_INT(MemorySegment.ofArray(new int[2]), 4), + HEAP_FLOAT(MemorySegment.ofArray(new float[2]), 4), + HEAP_LONG(MemorySegment.ofArray(new long[1]), 8), + HEAP_DOUBLE(MemorySegment.ofArray(new double[1]), 8), + NATIVE(MemorySegment.allocateNative(8, ResourceScope.newImplicitScope()), -1); + + final MemorySegment segment; + final int align; + + SegmentAndAlignment(MemorySegment segment, int align) { + this.segment = segment; + this.align = align; + } + } + + @DataProvider + public static Object[][] layouts() { + List<Object[]> layouts = new ArrayList<>(); + for (SegmentAndAlignment testCase : SegmentAndAlignment.values()) { + layouts.add(new Object[] { testCase.segment, testCase.align, (byte) 42, new byte[]{42}, ValueLayout.JAVA_BYTE, (Function<byte[], MemorySegment>)MemorySegment::ofArray }); + layouts.add(new Object[] { testCase.segment, testCase.align, true, null, ValueLayout.JAVA_BOOLEAN, null }); + layouts.add(new Object[] { testCase.segment, testCase.align, (char) 42, new char[]{42}, JAVA_CHAR_ALIGNED, (Function<char[], MemorySegment>)MemorySegment::ofArray }); + layouts.add(new Object[] { testCase.segment, testCase.align, (short) 42, new short[]{42}, JAVA_SHORT_ALIGNED, (Function<short[], MemorySegment>)MemorySegment::ofArray }); + layouts.add(new Object[] { testCase.segment, testCase.align, 42, new int[]{42}, JAVA_INT_ALIGNED, (Function<int[], MemorySegment>)MemorySegment::ofArray }); + layouts.add(new Object[] { testCase.segment, testCase.align, 42f, new float[]{42}, JAVA_FLOAT_ALIGNED, (Function<float[], MemorySegment>)MemorySegment::ofArray }); + layouts.add(new Object[] { testCase.segment, testCase.align, 42L, new long[]{42}, JAVA_LONG_ALIGNED, (Function<long[], MemorySegment>)MemorySegment::ofArray }); + layouts.add(new Object[] { testCase.segment, testCase.align, 42d, new double[]{42}, JAVA_DOUBLE_ALIGNED, (Function<double[], MemorySegment>)MemorySegment::ofArray }); + layouts.add(new Object[] { testCase.segment, testCase.align, MemoryAddress.ofLong(42), null, ADDRESS_ALIGNED, null }); + } + return layouts.toArray(new Object[0][]); + } +} diff --git a/test/jdk/java/foreign/TestIllegalLink.java b/test/jdk/java/foreign/TestIllegalLink.java index f63019bc4ffb99e301a8c7c2707af7962ba84386..7afa01689bc5a851eae1669c3aecb524a41c7ebe 100644 --- a/test/jdk/java/foreign/TestIllegalLink.java +++ b/test/jdk/java/foreign/TestIllegalLink.java @@ -32,26 +32,23 @@ import jdk.incubator.foreign.CLinker; import jdk.incubator.foreign.FunctionDescriptor; import jdk.incubator.foreign.MemoryAddress; import jdk.incubator.foreign.MemoryLayout; -import jdk.incubator.foreign.MemoryLayouts; -import jdk.incubator.foreign.MemorySegment; +import jdk.incubator.foreign.NativeSymbol; +import jdk.incubator.foreign.ResourceScope; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; -import java.lang.invoke.MethodType; - -import static jdk.incubator.foreign.CLinker.C_INT; import static org.testng.Assert.assertTrue; import static org.testng.Assert.fail; -public class TestIllegalLink { +public class TestIllegalLink extends NativeTestHelper { - private static final MemoryAddress DUMMY_TARGET = MemoryAddress.ofLong(1); - private static final CLinker ABI = CLinker.getInstance(); + private static final NativeSymbol DUMMY_TARGET = NativeSymbol.ofAddress("dummy", MemoryAddress.ofLong(1), ResourceScope.globalScope()); + private static final CLinker ABI = CLinker.systemCLinker(); @Test(dataProvider = "types") - public void testTypeMismatch(MethodType mt, FunctionDescriptor desc, String expectedExceptionMessage) { + public void testTypeMismatch(FunctionDescriptor desc, String expectedExceptionMessage) { try { - ABI.downcallHandle(DUMMY_TARGET, mt, desc); + ABI.downcallHandle(DUMMY_TARGET, desc); fail("Expected IllegalArgumentException was not thrown"); } catch (IllegalArgumentException e) { assertTrue(e.getMessage().contains(expectedExceptionMessage)); @@ -62,49 +59,20 @@ public class TestIllegalLink { public static Object[][] types() { return new Object[][]{ { - MethodType.methodType(void.class), - FunctionDescriptor.of(C_INT), - "Return type mismatch" - }, - { - MethodType.methodType(void.class), - FunctionDescriptor.ofVoid(C_INT), - "Arity mismatch" + FunctionDescriptor.of(MemoryLayout.paddingLayout(64)), + "Unsupported layout: x64" }, { - MethodType.methodType(void.class, int.class), - FunctionDescriptor.ofVoid(MemoryLayout.paddingLayout(32)), - "Expected a ValueLayout" - }, - { - MethodType.methodType(void.class, boolean.class), - FunctionDescriptor.ofVoid(MemoryLayouts.BITS_8_LE), - "Unsupported carrier" - }, - { - MethodType.methodType(void.class, int.class), - FunctionDescriptor.ofVoid(MemoryLayouts.BITS_64_LE), - "Carrier size mismatch" - }, - { - MethodType.methodType(void.class, MemoryAddress.class), FunctionDescriptor.ofVoid(MemoryLayout.paddingLayout(64)), - "Expected a ValueLayout" - }, - { - MethodType.methodType(void.class, MemoryAddress.class), - FunctionDescriptor.ofVoid(MemoryLayouts.BITS_16_LE), - "Address size mismatch" + "Unsupported layout: x64" }, { - MethodType.methodType(void.class, MemorySegment.class), - FunctionDescriptor.ofVoid(MemoryLayouts.BITS_64_LE), - "Expected a GroupLayout" + FunctionDescriptor.of(MemoryLayout.sequenceLayout(C_INT)), + "Unsupported layout: [:b32]" }, { - MethodType.methodType(void.class, String.class), - FunctionDescriptor.ofVoid(MemoryLayouts.BITS_64_LE), - "Unsupported carrier" + FunctionDescriptor.ofVoid(MemoryLayout.sequenceLayout(C_INT)), + "Unsupported layout: [:b32]" }, }; } diff --git a/test/jdk/java/foreign/TestIntrinsics.java b/test/jdk/java/foreign/TestIntrinsics.java index 98e6829e4b2bef3f62a777d454834b56a7b78ac6..1d4afce2289898eec968075bf9e53fcd241ffecb 100644 --- a/test/jdk/java/foreign/TestIntrinsics.java +++ b/test/jdk/java/foreign/TestIntrinsics.java @@ -40,19 +40,18 @@ import java.lang.invoke.MethodType; import java.util.ArrayList; import java.util.List; -import jdk.incubator.foreign.MemoryAddress; import jdk.incubator.foreign.MemoryLayout; +import jdk.incubator.foreign.NativeSymbol; import jdk.incubator.foreign.SymbolLookup; import org.testng.annotations.*; import static java.lang.invoke.MethodType.methodType; -import static jdk.incubator.foreign.CLinker.*; -import static jdk.incubator.foreign.FunctionDescriptor.TRIVIAL_ATTRIBUTE_NAME; +import static jdk.incubator.foreign.ValueLayout.JAVA_CHAR; import static org.testng.Assert.assertEquals; -public class TestIntrinsics { +public class TestIntrinsics extends NativeTestHelper { - static final CLinker abi = CLinker.getInstance(); + static final CLinker abi = CLinker.systemCLinker(); static { System.loadLibrary("Intrinsics"); } @@ -88,52 +87,48 @@ public class TestIntrinsics { } AddIdentity addIdentity = (name, carrier, layout, arg) -> { - MemoryAddress ma = LOOKUP.lookup(name).get(); + NativeSymbol ma = LOOKUP.lookup(name).get(); MethodType mt = methodType(carrier, carrier); FunctionDescriptor fd = FunctionDescriptor.of(layout, layout); - tests.add(abi.downcallHandle(ma, mt, fd), arg, arg); - tests.add(abi.downcallHandle(ma, mt, fd.withAttribute(TRIVIAL_ATTRIBUTE_NAME, true)), arg, arg); - tests.add(abi.downcallHandle(mt, fd), arg, ma, arg); + tests.add(abi.downcallHandle(ma, fd), arg, arg); + tests.add(abi.downcallHandle(fd), arg, ma, arg); }; { // empty - MemoryAddress ma = LOOKUP.lookup("empty").get(); + NativeSymbol ma = LOOKUP.lookup("empty").get(); MethodType mt = methodType(void.class); FunctionDescriptor fd = FunctionDescriptor.ofVoid(); - tests.add(abi.downcallHandle(ma, mt, fd), null); - tests.add(abi.downcallHandle(ma, mt, fd.withAttribute(TRIVIAL_ATTRIBUTE_NAME, true)), null); + tests.add(abi.downcallHandle(ma, fd), null); } - addIdentity.add("identity_char", byte.class, C_CHAR, (byte) 10); - addIdentity.add("identity_short", short.class, C_SHORT, (short) 10); - addIdentity.add("identity_int", int.class, C_INT, 10); - addIdentity.add("identity_long", long.class, C_LONG_LONG, 10L); - addIdentity.add("identity_float", float.class, C_FLOAT, 10F); - addIdentity.add("identity_double", double.class, C_DOUBLE, 10D); + addIdentity.add("identity_bool", boolean.class, C_BOOL, true); + addIdentity.add("identity_char", byte.class, C_CHAR, (byte) 10); + addIdentity.add("identity_short", short.class, C_SHORT, (short) 10); + addIdentity.add("identity_int", int.class, C_INT, 10); + addIdentity.add("identity_long", long.class, C_LONG_LONG, 10L); + addIdentity.add("identity_float", float.class, C_FLOAT, 10F); + addIdentity.add("identity_double", double.class, C_DOUBLE, 10D); { // identity_va - MemoryAddress ma = LOOKUP.lookup("identity_va").get(); + NativeSymbol ma = LOOKUP.lookup("identity_va").get(); MethodType mt = methodType(int.class, int.class, double.class, int.class, float.class, long.class); - FunctionDescriptor fd = FunctionDescriptor.of(C_INT, C_INT, asVarArg(C_DOUBLE), - asVarArg(C_INT), asVarArg(C_FLOAT), asVarArg(C_LONG_LONG)); - tests.add(abi.downcallHandle(ma, mt, fd), 1, 1, 10D, 2, 3F, 4L); - tests.add(abi.downcallHandle(ma, mt, fd.withAttribute(TRIVIAL_ATTRIBUTE_NAME, true)), 1, 1, 10D, 2, 3F, 4L); + FunctionDescriptor fd = FunctionDescriptor.of(C_INT, C_INT).asVariadic(C_DOUBLE, C_INT, C_FLOAT, C_LONG_LONG); + tests.add(abi.downcallHandle(ma, fd), 1, 1, 10D, 2, 3F, 4L); } { // high_arity MethodType baseMT = methodType(void.class, int.class, double.class, long.class, float.class, byte.class, short.class, char.class); FunctionDescriptor baseFD = FunctionDescriptor.ofVoid(C_INT, C_DOUBLE, C_LONG_LONG, C_FLOAT, C_CHAR, - C_SHORT, C_SHORT); + C_SHORT, JAVA_CHAR); Object[] args = {1, 10D, 2L, 3F, (byte) 0, (short) 13, 'a'}; for (int i = 0; i < args.length; i++) { - MemoryAddress ma = LOOKUP.lookup("invoke_high_arity" + i).get(); + NativeSymbol ma = LOOKUP.lookup("invoke_high_arity" + i).get(); MethodType mt = baseMT.changeReturnType(baseMT.parameterType(i)); - FunctionDescriptor fd = baseFD.withReturnLayout(baseFD.argumentLayouts().get(i)); + FunctionDescriptor fd = baseFD.changeReturnLayout(baseFD.argumentLayouts().get(i)); Object expected = args[i]; - tests.add(abi.downcallHandle(ma, mt, fd), expected, args); - tests.add(abi.downcallHandle(ma, mt, fd.withAttribute(TRIVIAL_ATTRIBUTE_NAME, true)), expected, args); + tests.add(abi.downcallHandle(ma, fd), expected, args); } } diff --git a/test/jdk/java/foreign/TestLayoutAttributes.java b/test/jdk/java/foreign/TestLayoutAttributes.java deleted file mode 100644 index 9def5a3b8237f6a02379be8bf20f58f2e8388a5d..0000000000000000000000000000000000000000 --- a/test/jdk/java/foreign/TestLayoutAttributes.java +++ /dev/null @@ -1,82 +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. - */ - -/* - * @test - * @run testng TestLayoutAttributes - */ - -import jdk.incubator.foreign.MemoryLayout; -import jdk.incubator.foreign.MemoryLayouts; -import org.testng.annotations.Test; - -import java.util.List; -import java.util.stream.Collectors; - -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertTrue; - -public class TestLayoutAttributes { - - @Test - public void testAttribute() { - MemoryLayout ml = MemoryLayouts.BITS_32_LE - .withAttribute("MyAttribute", 10L); - assertEquals((long) ml.attribute("MyAttribute").orElseThrow(), 10L); - } - - @Test - public void testAttributeOverwrite() { - MemoryLayout ml = MemoryLayouts.BITS_32_LE - .withAttribute("MyAttribute", 10L); - assertEquals((long) ml.attribute("MyAttribute").orElseThrow(), 10L); - ml = ml.withAttribute("MyAttribute", 11L); - assertEquals((long) ml.attribute("MyAttribute").orElseThrow(), 11L); - } - - @Test - public void testAttributeNonExistent() { - MemoryLayout ml = MemoryLayouts.BITS_32_LE - .withAttribute("MyAttribute", 10L); - assertTrue(ml.attribute("Foo").isEmpty()); - } - - @Test - public void testNameAttribute() { - MemoryLayout ml = MemoryLayouts.BITS_32_LE - .withName("foo"); - assertEquals(ml.name().orElseThrow(), "foo"); - assertEquals(ml.attribute(MemoryLayout.LAYOUT_NAME).orElseThrow(), "foo"); - } - - @Test - public void testAttributesStream() { - MemoryLayout ml = MemoryLayouts.BITS_32_LE - .withName("foo") - .withAttribute("MyAttribute", 10L); - List<String> attribs = ml.attributes().collect(Collectors.toList()); - assertEquals(attribs.size(), 2); - assertTrue(attribs.contains("MyAttribute")); - assertTrue(attribs.contains(MemoryLayout.LAYOUT_NAME)); - } -} diff --git a/test/jdk/java/foreign/TestLayoutConstants.java b/test/jdk/java/foreign/TestLayoutConstants.java index 2ea2967923448e5d1a7e4e1c28faa69e433f0dd9..59d26ca2700b749435a9293c3fd780042e829a7c 100644 --- a/test/jdk/java/foreign/TestLayoutConstants.java +++ b/test/jdk/java/foreign/TestLayoutConstants.java @@ -27,11 +27,12 @@ */ import jdk.incubator.foreign.FunctionDescriptor; -import jdk.incubator.foreign.MemoryLayouts; import jdk.incubator.foreign.MemoryLayout; import java.lang.invoke.MethodHandles; +import java.nio.ByteOrder; +import jdk.incubator.foreign.ValueLayout; import org.testng.annotations.*; import static org.testng.Assert.*; @@ -66,49 +67,48 @@ public class TestLayoutConstants { public Object[][] createLayouts() { return new Object[][] { //padding - { MemoryLayouts.PAD_32 }, - { MemoryLayout.sequenceLayout(MemoryLayouts.PAD_32) }, - { MemoryLayout.sequenceLayout(5, MemoryLayouts.PAD_32) }, - { MemoryLayout.structLayout(MemoryLayouts.PAD_32, MemoryLayouts.PAD_32) }, - { MemoryLayout.unionLayout(MemoryLayouts.PAD_32, MemoryLayouts.PAD_32) }, + {MemoryLayout.paddingLayout(32)}, + { MemoryLayout.sequenceLayout(MemoryLayout.paddingLayout(32)) }, + { MemoryLayout.sequenceLayout(5, MemoryLayout.paddingLayout(32)) }, + { MemoryLayout.structLayout(MemoryLayout.paddingLayout(32), MemoryLayout.paddingLayout(32)) }, + { MemoryLayout.unionLayout(MemoryLayout.paddingLayout(32), MemoryLayout.paddingLayout(32)) }, //values, big endian - { MemoryLayouts.BITS_32_BE }, + { ValueLayout.JAVA_INT.withOrder(ByteOrder.BIG_ENDIAN) }, { MemoryLayout.structLayout( - MemoryLayouts.BITS_32_BE, - MemoryLayouts.BITS_32_BE) }, + ValueLayout.JAVA_INT.withOrder(ByteOrder.BIG_ENDIAN), + ValueLayout.JAVA_INT.withOrder(ByteOrder.BIG_ENDIAN)) }, { MemoryLayout.unionLayout( - MemoryLayouts.BITS_32_BE, - MemoryLayouts.BITS_32_BE) }, + ValueLayout.JAVA_INT.withOrder(ByteOrder.BIG_ENDIAN), + ValueLayout.JAVA_INT.withOrder(ByteOrder.BIG_ENDIAN)) }, //values, little endian - { MemoryLayouts.BITS_32_LE }, + { ValueLayout.JAVA_INT.withOrder(ByteOrder.LITTLE_ENDIAN) }, { MemoryLayout.structLayout( - MemoryLayouts.BITS_32_LE, - MemoryLayouts.BITS_32_LE) }, + ValueLayout.JAVA_INT.withOrder(ByteOrder.LITTLE_ENDIAN), + ValueLayout.JAVA_INT.withOrder(ByteOrder.LITTLE_ENDIAN)) }, { MemoryLayout.unionLayout( - MemoryLayouts.BITS_32_LE, - MemoryLayouts.BITS_32_LE) }, + ValueLayout.JAVA_INT.withOrder(ByteOrder.LITTLE_ENDIAN), + ValueLayout.JAVA_INT.withOrder(ByteOrder.LITTLE_ENDIAN)) }, //deeply nested { MemoryLayout.structLayout( - MemoryLayouts.PAD_16, + MemoryLayout.paddingLayout(16), MemoryLayout.structLayout( - MemoryLayouts.PAD_8, - MemoryLayouts.BITS_32_BE)) }, + MemoryLayout.paddingLayout(8), + ValueLayout.JAVA_INT.withOrder(ByteOrder.BIG_ENDIAN))) }, { MemoryLayout.unionLayout( - MemoryLayouts.PAD_16, + MemoryLayout.paddingLayout(16), MemoryLayout.structLayout( - MemoryLayouts.PAD_8, - MemoryLayouts.BITS_32_BE)) }, + MemoryLayout.paddingLayout(8), + ValueLayout.JAVA_INT.withOrder(ByteOrder.BIG_ENDIAN))) }, { MemoryLayout.sequenceLayout( MemoryLayout.structLayout( - MemoryLayouts.PAD_8, - MemoryLayouts.BITS_32_BE)) }, + MemoryLayout.paddingLayout(8), + ValueLayout.JAVA_INT.withOrder(ByteOrder.BIG_ENDIAN))) }, { MemoryLayout.sequenceLayout(5, MemoryLayout.structLayout( - MemoryLayouts.PAD_8, - MemoryLayouts.BITS_32_BE)) }, - { MemoryLayouts.BITS_32_LE.withName("myInt") }, - { MemoryLayouts.BITS_32_LE.withBitAlignment(8) }, - { MemoryLayouts.BITS_32_LE.withAttribute("xyz", "abc") }, + MemoryLayout.paddingLayout(8), + ValueLayout.JAVA_INT.withOrder(ByteOrder.BIG_ENDIAN))) }, + { ValueLayout.JAVA_INT.withOrder(ByteOrder.LITTLE_ENDIAN).withName("myInt") }, + { ValueLayout.JAVA_INT.withOrder(ByteOrder.LITTLE_ENDIAN).withBitAlignment(8) }, }; } diff --git a/test/jdk/java/foreign/TestLayoutEquality.java b/test/jdk/java/foreign/TestLayoutEquality.java index 8eb59ec340ee0d069a260bccb55dae930fc9e8a1..7a4d3124f0b865fb7c6da9d0d7f21953da057d29 100644 --- a/test/jdk/java/foreign/TestLayoutEquality.java +++ b/test/jdk/java/foreign/TestLayoutEquality.java @@ -29,7 +29,7 @@ * @run testng TestLayoutEquality */ -import jdk.incubator.foreign.MemoryLayout; +import jdk.incubator.foreign.MemoryAddress; import jdk.incubator.foreign.ValueLayout; import jdk.internal.foreign.PlatformLayouts; import org.testng.annotations.DataProvider; @@ -39,23 +39,32 @@ import java.lang.reflect.Field; import java.util.ArrayList; import java.util.List; +import static jdk.incubator.foreign.ValueLayout.ADDRESS; +import static jdk.incubator.foreign.ValueLayout.JAVA_BOOLEAN; +import static jdk.incubator.foreign.ValueLayout.JAVA_BYTE; +import static jdk.incubator.foreign.ValueLayout.JAVA_CHAR; +import static jdk.incubator.foreign.ValueLayout.JAVA_DOUBLE; +import static jdk.incubator.foreign.ValueLayout.JAVA_FLOAT; +import static jdk.incubator.foreign.ValueLayout.JAVA_INT; +import static jdk.incubator.foreign.ValueLayout.JAVA_LONG; +import static jdk.incubator.foreign.ValueLayout.JAVA_SHORT; import static org.testng.Assert.*; public class TestLayoutEquality { @Test(dataProvider = "layoutConstants") public void testReconstructedEquality(ValueLayout layout) { - ValueLayout newLayout = MemoryLayout.valueLayout(layout.bitSize(), layout.order()); + ValueLayout newLayout = valueLayoutForCarrier(layout.carrier()); + newLayout = newLayout.withBitAlignment(layout.bitAlignment()); + newLayout = newLayout.withOrder(layout.order()); // properties should be equal assertEquals(newLayout.bitSize(), layout.bitSize()); assertEquals(newLayout.bitAlignment(), layout.bitAlignment()); assertEquals(newLayout.name(), layout.name()); - assertEquals(newLayout.attributes().toArray().length, 0); - assertEquals(layout.attributes().toArray().length, 1); - // but equals should return false, because one is a ValueLayout with a CLinker kind - assertNotEquals(newLayout, layout); + // layouts should be equals + assertEquals(newLayout, layout); } @DataProvider @@ -76,4 +85,27 @@ public class TestLayoutEquality { } } + static ValueLayout valueLayoutForCarrier(Class<?> carrier) { + if (carrier == boolean.class) { + return JAVA_BOOLEAN; + } else if (carrier == char.class) { + return JAVA_CHAR; + } else if (carrier == byte.class) { + return JAVA_BYTE; + } else if (carrier == short.class) { + return JAVA_SHORT; + } else if (carrier == int.class) { + return JAVA_INT; + } else if (carrier == long.class) { + return JAVA_LONG; + } else if (carrier == float.class) { + return JAVA_FLOAT; + } else if (carrier == double.class) { + return JAVA_DOUBLE; + } else if (carrier == MemoryAddress.class) { + return ADDRESS; + } else { + throw new UnsupportedOperationException(); + } + } } diff --git a/test/jdk/java/foreign/TestLayoutPaths.java b/test/jdk/java/foreign/TestLayoutPaths.java index 1cf3798c249f18d501140ff00d2fb337d4fd6179..438dc86ada6ae7cab6575127ae8cf375bf42cc79 100644 --- a/test/jdk/java/foreign/TestLayoutPaths.java +++ b/test/jdk/java/foreign/TestLayoutPaths.java @@ -28,24 +28,23 @@ */ import jdk.incubator.foreign.GroupLayout; -import jdk.incubator.foreign.MemoryLayouts; import jdk.incubator.foreign.MemoryLayout; import jdk.incubator.foreign.MemoryLayout.PathElement; import jdk.incubator.foreign.MemorySegment; import jdk.incubator.foreign.ResourceScope; import jdk.incubator.foreign.SequenceLayout; +import jdk.incubator.foreign.ValueLayout; import org.testng.SkipException; import org.testng.annotations.*; import java.lang.invoke.MethodHandle; -import java.nio.ByteOrder; import java.util.ArrayList; import java.util.List; import static jdk.incubator.foreign.MemoryLayout.PathElement.groupElement; import static jdk.incubator.foreign.MemoryLayout.PathElement.sequenceElement; -import static jdk.incubator.foreign.MemoryLayouts.JAVA_INT; +import static jdk.incubator.foreign.ValueLayout.JAVA_INT; import static org.testng.Assert.*; public class TestLayoutPaths { @@ -153,7 +152,7 @@ public class TestLayoutPaths { @Test(expectedExceptions = IllegalArgumentException.class) public void testIncompleteAccess() { SequenceLayout seq = MemoryLayout.sequenceLayout(5, MemoryLayout.structLayout(JAVA_INT)); - seq.varHandle(int.class, sequenceElement()); + seq.varHandle(sequenceElement()); } @Test(expectedExceptions = IllegalArgumentException.class) @@ -221,7 +220,7 @@ public class TestLayoutPaths { throw new AssertionError(ex); // should be ok! } try { - g.varHandle(int.class, groupElement("foo")); //ok + g.varHandle(groupElement("foo")); //ok assertTrue(false); //should fail! } catch (UnsupportedOperationException ex) { //ok @@ -232,7 +231,7 @@ public class TestLayoutPaths { @Test public void testBadAlignOffset() { - GroupLayout g = MemoryLayout.structLayout(MemoryLayouts.PAD_8, JAVA_INT.withBitAlignment(16).withName("foo")); + GroupLayout g = MemoryLayout.structLayout(MemoryLayout.paddingLayout(8), JAVA_INT.withBitAlignment(16).withName("foo")); try { g.bitOffset(groupElement("foo")); g.byteOffset(groupElement("foo")); @@ -240,7 +239,7 @@ public class TestLayoutPaths { throw new AssertionError(ex); // should be ok! } try { - g.varHandle(int.class, groupElement("foo")); //ok + g.varHandle(groupElement("foo")); //ok assertTrue(false); //should fail! } catch (UnsupportedOperationException ex) { //ok @@ -299,10 +298,10 @@ public class TestLayoutPaths { public void testStructPaths() { long[] offsets = { 0, 8, 24, 56 }; GroupLayout g = MemoryLayout.structLayout( - MemoryLayouts.JAVA_BYTE.withName("1"), - MemoryLayouts.JAVA_CHAR.withName("2"), - MemoryLayouts.JAVA_FLOAT.withName("3"), - MemoryLayouts.JAVA_LONG.withName("4") + ValueLayout.JAVA_BYTE.withName("1"), + ValueLayout.JAVA_CHAR.withName("2"), + ValueLayout.JAVA_FLOAT.withName("3"), + ValueLayout.JAVA_LONG.withName("4") ); // test select @@ -324,11 +323,11 @@ public class TestLayoutPaths { // test map for (int i = 1 ; i <= 4 ; i++) { - GroupLayout g2 = (GroupLayout)g.map(l -> MemoryLayouts.JAVA_DOUBLE, groupElement(String.valueOf(i))); + GroupLayout g2 = (GroupLayout)g.map(l -> ValueLayout.JAVA_DOUBLE, groupElement(String.valueOf(i))); assertTrue(g2.isStruct()); for (int j = 0 ; j < 4 ; j++) { if (j == i - 1) { - assertEquals(g2.memberLayouts().get(j), MemoryLayouts.JAVA_DOUBLE); + assertEquals(g2.memberLayouts().get(j), ValueLayout.JAVA_DOUBLE); } else { assertEquals(g2.memberLayouts().get(j), g.memberLayouts().get(j)); } @@ -340,10 +339,10 @@ public class TestLayoutPaths { public void testUnionPaths() { long[] offsets = { 0, 0, 0, 0 }; GroupLayout g = MemoryLayout.unionLayout( - MemoryLayouts.JAVA_BYTE.withName("1"), - MemoryLayouts.JAVA_CHAR.withName("2"), - MemoryLayouts.JAVA_FLOAT.withName("3"), - MemoryLayouts.JAVA_LONG.withName("4") + ValueLayout.JAVA_BYTE.withName("1"), + ValueLayout.JAVA_CHAR.withName("2"), + ValueLayout.JAVA_FLOAT.withName("3"), + ValueLayout.JAVA_LONG.withName("4") ); // test select @@ -365,11 +364,11 @@ public class TestLayoutPaths { // test map for (int i = 1 ; i <= 4 ; i++) { - GroupLayout g2 = (GroupLayout)g.map(l -> MemoryLayouts.JAVA_DOUBLE, groupElement(String.valueOf(i))); + GroupLayout g2 = (GroupLayout)g.map(l -> ValueLayout.JAVA_DOUBLE, groupElement(String.valueOf(i))); assertTrue(g2.isUnion()); for (int j = 0 ; j < 4 ; j++) { if (j == i - 1) { - assertEquals(g2.memberLayouts().get(j), MemoryLayouts.JAVA_DOUBLE); + assertEquals(g2.memberLayouts().get(j), ValueLayout.JAVA_DOUBLE); } else { assertEquals(g2.memberLayouts().get(j), g.memberLayouts().get(j)); } @@ -380,12 +379,12 @@ public class TestLayoutPaths { @Test public void testSequencePaths() { long[] offsets = { 0, 8, 16, 24 }; - SequenceLayout g = MemoryLayout.sequenceLayout(4, MemoryLayouts.JAVA_BYTE); + SequenceLayout g = MemoryLayout.sequenceLayout(4, ValueLayout.JAVA_BYTE); // test select MemoryLayout selected = g.select(sequenceElement()); - assertTrue(selected == MemoryLayouts.JAVA_BYTE); + assertTrue(selected == ValueLayout.JAVA_BYTE); // test offset @@ -398,8 +397,8 @@ public class TestLayoutPaths { // test map - SequenceLayout seq2 = (SequenceLayout)g.map(l -> MemoryLayouts.JAVA_DOUBLE, sequenceElement()); - assertTrue(seq2.elementLayout() == MemoryLayouts.JAVA_DOUBLE); + SequenceLayout seq2 = (SequenceLayout)g.map(l -> ValueLayout.JAVA_DOUBLE, sequenceElement()); + assertTrue(seq2.elementLayout() == ValueLayout.JAVA_DOUBLE); } @Test(dataProvider = "testLayouts") @@ -506,26 +505,16 @@ public class TestLayoutPaths { try (ResourceScope scope = ResourceScope.newConfinedScope()) { MemorySegment segment = MemorySegment.allocateNative(layout, scope); MemorySegment slice = (MemorySegment) sliceHandle.invokeExact(segment, indexes); - assertEquals(slice.address().segmentOffset(segment), expectedBitOffset / 8); + assertEquals(slice.address().toRawLongValue() - segment.address().toRawLongValue(), expectedBitOffset / 8); assertEquals(slice.byteSize(), selected.byteSize()); } } - @Test(expectedExceptions = UnsupportedOperationException.class) - public void testSliceHandleUOEInvalidSize() { - MemoryLayout layout = MemoryLayout.structLayout( - MemoryLayout.valueLayout(32, ByteOrder.nativeOrder()).withName("x"), - MemoryLayout.valueLayout(31, ByteOrder.nativeOrder()).withName("y") // size not a multiple of 8 - ); - - layout.sliceHandle(groupElement("y")); // should throw - } - @Test(expectedExceptions = UnsupportedOperationException.class) public void testSliceHandleUOEInvalidOffsetEager() throws Throwable { MemoryLayout layout = MemoryLayout.structLayout( MemoryLayout.paddingLayout(5), - MemoryLayout.valueLayout(32, ByteOrder.nativeOrder()).withName("y") // offset not a multiple of 8 + JAVA_INT.withName("y") // offset not a multiple of 8 ); layout.sliceHandle(groupElement("y")); // should throw @@ -536,7 +525,7 @@ public class TestLayoutPaths { MemoryLayout layout = MemoryLayout.sequenceLayout(3, MemoryLayout.structLayout( MemoryLayout.paddingLayout(4), - MemoryLayout.valueLayout(32, ByteOrder.nativeOrder()).withName("y") // offset not a multiple of 8 + JAVA_INT.withName("y") // offset not a multiple of 8 ) ); diff --git a/test/jdk/java/foreign/TestLayouts.java b/test/jdk/java/foreign/TestLayouts.java index 006163d3d503a2d44e160e927b2f2580ead9c660..6d54bef722d2b8ac2d9e25cc347dca3275e6dc88 100644 --- a/test/jdk/java/foreign/TestLayouts.java +++ b/test/jdk/java/foreign/TestLayouts.java @@ -34,15 +34,15 @@ import java.util.function.LongFunction; import java.util.stream.Stream; import org.testng.annotations.*; + +import static jdk.incubator.foreign.ValueLayout.JAVA_BYTE; +import static jdk.incubator.foreign.ValueLayout.JAVA_INT; +import static jdk.incubator.foreign.ValueLayout.JAVA_LONG; +import static jdk.incubator.foreign.ValueLayout.JAVA_SHORT; import static org.testng.Assert.*; public class TestLayouts { - @Test(dataProvider = "badLayoutSizes", expectedExceptions = IllegalArgumentException.class) - public void testBadLayoutSize(SizedLayoutFactory factory, long size) { - factory.make(size); - } - @Test(dataProvider = "badAlignments", expectedExceptions = IllegalArgumentException.class) public void testBadLayoutAlignment(MemoryLayout layout, long alignment) { layout.withBitAlignment(alignment); @@ -51,12 +51,12 @@ public class TestLayouts { @Test public void testVLAInStruct() { MemoryLayout layout = MemoryLayout.structLayout( - MemoryLayouts.JAVA_INT.withName("size"), + ValueLayout.JAVA_INT.withName("size"), MemoryLayout.paddingLayout(32), - MemoryLayout.sequenceLayout(MemoryLayouts.JAVA_DOUBLE).withName("arr")); + MemoryLayout.sequenceLayout(ValueLayout.JAVA_DOUBLE).withName("arr")); assertFalse(layout.hasSize()); - VarHandle size_handle = layout.varHandle(int.class, MemoryLayout.PathElement.groupElement("size")); - VarHandle array_elem_handle = layout.varHandle(double.class, + VarHandle size_handle = layout.varHandle(MemoryLayout.PathElement.groupElement("size")); + VarHandle array_elem_handle = layout.varHandle( MemoryLayout.PathElement.groupElement("arr"), MemoryLayout.PathElement.sequenceElement()); try (ResourceScope scope = ResourceScope.newConfinedScope()) { @@ -77,12 +77,12 @@ public class TestLayouts { @Test public void testVLAInSequence() { MemoryLayout layout = MemoryLayout.structLayout( - MemoryLayouts.JAVA_INT.withName("size"), + ValueLayout.JAVA_INT.withName("size"), MemoryLayout.paddingLayout(32), - MemoryLayout.sequenceLayout(1, MemoryLayout.sequenceLayout(MemoryLayouts.JAVA_DOUBLE)).withName("arr")); + MemoryLayout.sequenceLayout(1, MemoryLayout.sequenceLayout(ValueLayout.JAVA_DOUBLE)).withName("arr")); assertFalse(layout.hasSize()); - VarHandle size_handle = layout.varHandle(int.class, MemoryLayout.PathElement.groupElement("size")); - VarHandle array_elem_handle = layout.varHandle(double.class, + VarHandle size_handle = layout.varHandle(MemoryLayout.PathElement.groupElement("size")); + VarHandle array_elem_handle = layout.varHandle( MemoryLayout.PathElement.groupElement("arr"), MemoryLayout.PathElement.sequenceElement(0), MemoryLayout.PathElement.sequenceElement()); @@ -103,17 +103,17 @@ public class TestLayouts { @Test public void testIndexedSequencePath() { - MemoryLayout seq = MemoryLayout.sequenceLayout(10, MemoryLayouts.JAVA_INT); + MemoryLayout seq = MemoryLayout.sequenceLayout(10, ValueLayout.JAVA_INT); try (ResourceScope scope = ResourceScope.newConfinedScope()) { MemorySegment segment = MemorySegment.allocateNative(seq, scope); - VarHandle indexHandle = seq.varHandle(int.class, MemoryLayout.PathElement.sequenceElement()); + VarHandle indexHandle = seq.varHandle(MemoryLayout.PathElement.sequenceElement()); // init segment for (int i = 0 ; i < 10 ; i++) { indexHandle.set(segment, (long)i, i); } //check statically indexed handles for (int i = 0 ; i < 10 ; i++) { - VarHandle preindexHandle = seq.varHandle(int.class, MemoryLayout.PathElement.sequenceElement(i)); + VarHandle preindexHandle = seq.varHandle(MemoryLayout.PathElement.sequenceElement(i)); int expected = (int)indexHandle.get(segment, (long)i); int found = (int)preindexHandle.get(segment); assertEquals(expected, found); @@ -143,13 +143,13 @@ public class TestLayouts { @Test(expectedExceptions = IllegalArgumentException.class) public void testBadUnboundSequenceLayoutResize() { - SequenceLayout seq = MemoryLayout.sequenceLayout(MemoryLayouts.JAVA_INT); + SequenceLayout seq = MemoryLayout.sequenceLayout(ValueLayout.JAVA_INT); seq.withElementCount(-1); } @Test(expectedExceptions = IllegalArgumentException.class) public void testBadBoundSequenceLayoutResize() { - SequenceLayout seq = MemoryLayout.sequenceLayout(10, MemoryLayouts.JAVA_INT); + SequenceLayout seq = MemoryLayout.sequenceLayout(10, ValueLayout.JAVA_INT); seq.withElementCount(-1); } @@ -168,13 +168,13 @@ public class TestLayouts { public void testStructSizeAndAlign() { MemoryLayout struct = MemoryLayout.structLayout( MemoryLayout.paddingLayout(8), - MemoryLayouts.JAVA_BYTE, - MemoryLayouts.JAVA_CHAR, - MemoryLayouts.JAVA_INT, - MemoryLayouts.JAVA_LONG + ValueLayout.JAVA_BYTE, + ValueLayout.JAVA_CHAR, + ValueLayout.JAVA_INT, + ValueLayout.JAVA_LONG ); assertEquals(struct.byteSize(), 1 + 1 + 2 + 4 + 8); - assertEquals(struct.byteAlignment(), MemoryLayouts.ADDRESS.byteAlignment()); + assertEquals(struct.byteAlignment(), ValueLayout.ADDRESS.byteAlignment()); } @Test(dataProvider="basicLayouts") @@ -199,13 +199,13 @@ public class TestLayouts { @Test public void testUnionSizeAndAlign() { MemoryLayout struct = MemoryLayout.unionLayout( - MemoryLayouts.JAVA_BYTE, - MemoryLayouts.JAVA_CHAR, - MemoryLayouts.JAVA_INT, - MemoryLayouts.JAVA_LONG + ValueLayout.JAVA_BYTE, + ValueLayout.JAVA_CHAR, + ValueLayout.JAVA_INT, + ValueLayout.JAVA_LONG ); assertEquals(struct.byteSize(), 8); - assertEquals(struct.byteAlignment(), MemoryLayouts.ADDRESS.byteAlignment()); + assertEquals(struct.byteAlignment(), ValueLayout.ADDRESS.byteAlignment()); } @Test(dataProvider = "layoutKinds") @@ -224,31 +224,19 @@ public class TestLayouts { } } - @DataProvider(name = "badLayoutSizes") - public Object[][] factoriesAndSizes() { - return new Object[][] { - { SizedLayoutFactory.VALUE_BE, 0 }, - { SizedLayoutFactory.VALUE_BE, -1 }, - { SizedLayoutFactory.VALUE_LE, 0 }, - { SizedLayoutFactory.VALUE_LE, -1 }, - { SizedLayoutFactory.PADDING, 0 }, - { SizedLayoutFactory.PADDING, -1 }, - { SizedLayoutFactory.SEQUENCE, -1 } - }; - } - @DataProvider(name = "unboundLayouts") public Object[][] unboundLayouts() { + ValueLayout alignedInt = JAVA_INT.withBitAlignment(32); return new Object[][] { - { MemoryLayout.sequenceLayout(MemoryLayouts.JAVA_INT), 32 }, - { MemoryLayout.sequenceLayout(MemoryLayout.sequenceLayout(MemoryLayouts.JAVA_INT)), 32 }, - { MemoryLayout.sequenceLayout(4, MemoryLayout.sequenceLayout(MemoryLayouts.JAVA_INT)), 32 }, - { MemoryLayout.structLayout(MemoryLayout.sequenceLayout(MemoryLayouts.JAVA_INT)), 32 }, - { MemoryLayout.structLayout(MemoryLayout.sequenceLayout(MemoryLayout.sequenceLayout(MemoryLayouts.JAVA_INT))), 32 }, - { MemoryLayout.structLayout(MemoryLayout.sequenceLayout(4, MemoryLayout.sequenceLayout(MemoryLayouts.JAVA_INT))), 32 }, - { MemoryLayout.unionLayout(MemoryLayout.sequenceLayout(MemoryLayouts.JAVA_INT)), 32 }, - { MemoryLayout.unionLayout(MemoryLayout.sequenceLayout(MemoryLayout.sequenceLayout(MemoryLayouts.JAVA_INT))), 32 }, - { MemoryLayout.unionLayout(MemoryLayout.sequenceLayout(4, MemoryLayout.sequenceLayout(MemoryLayouts.JAVA_INT))), 32 }, + { MemoryLayout.sequenceLayout(alignedInt), 32 }, + { MemoryLayout.sequenceLayout(MemoryLayout.sequenceLayout(alignedInt)), 32 }, + { MemoryLayout.sequenceLayout(4, MemoryLayout.sequenceLayout(alignedInt)), 32 }, + { MemoryLayout.structLayout(MemoryLayout.sequenceLayout(alignedInt)), 32 }, + { MemoryLayout.structLayout(MemoryLayout.sequenceLayout(MemoryLayout.sequenceLayout(alignedInt))), 32 }, + { MemoryLayout.structLayout(MemoryLayout.sequenceLayout(4, MemoryLayout.sequenceLayout(alignedInt))), 32 }, + { MemoryLayout.unionLayout(MemoryLayout.sequenceLayout(alignedInt)), 32 }, + { MemoryLayout.unionLayout(MemoryLayout.sequenceLayout(MemoryLayout.sequenceLayout(alignedInt))), 32 }, + { MemoryLayout.unionLayout(MemoryLayout.sequenceLayout(4, MemoryLayout.sequenceLayout(alignedInt))), 32 }, }; } @@ -271,10 +259,10 @@ public class TestLayouts { } enum SizedLayoutFactory { - VALUE_LE(size -> MemoryLayout.valueLayout(size, ByteOrder.LITTLE_ENDIAN)), - VALUE_BE(size -> MemoryLayout.valueLayout(size, ByteOrder.BIG_ENDIAN)), + VALUE_LE(size -> valueLayoutForSize((int)size).withOrder(ByteOrder.LITTLE_ENDIAN)), + VALUE_BE(size -> valueLayoutForSize((int)size).withOrder(ByteOrder.BIG_ENDIAN)), PADDING(MemoryLayout::paddingLayout), - SEQUENCE(size -> MemoryLayout.sequenceLayout(size, MemoryLayouts.PAD_8)); + SEQUENCE(size -> MemoryLayout.sequenceLayout(size, MemoryLayout.paddingLayout(8))); private final LongFunction<MemoryLayout> factory; @@ -287,13 +275,22 @@ public class TestLayouts { } } + static ValueLayout valueLayoutForSize(int size) { + return switch (size) { + case 1 -> JAVA_BYTE; + case 2 -> JAVA_SHORT; + case 4 -> JAVA_INT; + case 8 -> JAVA_LONG; + default -> throw new UnsupportedOperationException(); + }; + } + enum LayoutKind { - VALUE_LE(MemoryLayouts.BITS_8_LE), - VALUE_BE(MemoryLayouts.BITS_8_BE), - PADDING(MemoryLayouts.PAD_8), - SEQUENCE(MemoryLayout.sequenceLayout(1, MemoryLayouts.PAD_8)), - STRUCT(MemoryLayout.structLayout(MemoryLayouts.PAD_8, MemoryLayouts.PAD_8)), - UNION(MemoryLayout.unionLayout(MemoryLayouts.PAD_8, MemoryLayouts.PAD_8)); + VALUE(ValueLayout.JAVA_BYTE), + PADDING(MemoryLayout.paddingLayout(8)), + SEQUENCE(MemoryLayout.sequenceLayout(1, MemoryLayout.paddingLayout(8))), + STRUCT(MemoryLayout.structLayout(MemoryLayout.paddingLayout(8), MemoryLayout.paddingLayout(8))), + UNION(MemoryLayout.unionLayout(MemoryLayout.paddingLayout(8), MemoryLayout.paddingLayout(8))); final MemoryLayout layout; @@ -333,12 +330,12 @@ public class TestLayouts { } static MemoryLayout[] basicLayouts = { - MemoryLayouts.JAVA_BYTE, - MemoryLayouts.JAVA_CHAR, - MemoryLayouts.JAVA_SHORT, - MemoryLayouts.JAVA_INT, - MemoryLayouts.JAVA_FLOAT, - MemoryLayouts.JAVA_LONG, - MemoryLayouts.JAVA_DOUBLE, + ValueLayout.JAVA_BYTE, + ValueLayout.JAVA_CHAR, + ValueLayout.JAVA_SHORT, + ValueLayout.JAVA_INT, + ValueLayout.JAVA_FLOAT, + ValueLayout.JAVA_LONG, + ValueLayout.JAVA_DOUBLE, }; } diff --git a/test/jdk/java/foreign/TestMemoryAccess.java b/test/jdk/java/foreign/TestMemoryAccess.java index d843c7b0b3921dbf023fd2a4b3fbfc66a519a8b2..7eade5f8147d4822292ba0e989d4b3c5e241f8d7 100644 --- a/test/jdk/java/foreign/TestMemoryAccess.java +++ b/test/jdk/java/foreign/TestMemoryAccess.java @@ -30,7 +30,7 @@ */ import jdk.incubator.foreign.GroupLayout; -import jdk.incubator.foreign.MemoryLayouts; +import jdk.incubator.foreign.MemoryAddress; import jdk.incubator.foreign.MemoryLayout; import jdk.incubator.foreign.MemoryLayout.PathElement; import jdk.incubator.foreign.MemorySegment; @@ -39,6 +39,7 @@ import jdk.incubator.foreign.SequenceLayout; import jdk.incubator.foreign.ValueLayout; import java.lang.invoke.VarHandle; +import java.nio.ByteOrder; import java.util.function.Function; import org.testng.annotations.*; @@ -47,39 +48,39 @@ import static org.testng.Assert.*; public class TestMemoryAccess { @Test(dataProvider = "elements") - public void testAccess(Function<MemorySegment, MemorySegment> viewFactory, ValueLayout elemLayout, Class<?> carrier, Checker checker) { + public void testAccess(Function<MemorySegment, MemorySegment> viewFactory, ValueLayout elemLayout, Checker checker) { ValueLayout layout = elemLayout.withName("elem"); - testAccessInternal(viewFactory, layout, layout.varHandle(carrier), checker); + testAccessInternal(viewFactory, layout, layout.varHandle(), checker); } @Test(dataProvider = "elements") - public void testPaddedAccessByName(Function<MemorySegment, MemorySegment> viewFactory, MemoryLayout elemLayout, Class<?> carrier, Checker checker) { + public void testPaddedAccessByName(Function<MemorySegment, MemorySegment> viewFactory, MemoryLayout elemLayout, Checker checker) { GroupLayout layout = MemoryLayout.structLayout(MemoryLayout.paddingLayout(elemLayout.bitSize()), elemLayout.withName("elem")); - testAccessInternal(viewFactory, layout, layout.varHandle(carrier, PathElement.groupElement("elem")), checker); + testAccessInternal(viewFactory, layout, layout.varHandle(PathElement.groupElement("elem")), checker); } @Test(dataProvider = "elements") - public void testPaddedAccessByIndexSeq(Function<MemorySegment, MemorySegment> viewFactory, MemoryLayout elemLayout, Class<?> carrier, Checker checker) { + public void testPaddedAccessByIndexSeq(Function<MemorySegment, MemorySegment> viewFactory, MemoryLayout elemLayout, Checker checker) { SequenceLayout layout = MemoryLayout.sequenceLayout(2, elemLayout); - testAccessInternal(viewFactory, layout, layout.varHandle(carrier, PathElement.sequenceElement(1)), checker); + testAccessInternal(viewFactory, layout, layout.varHandle(PathElement.sequenceElement(1)), checker); } @Test(dataProvider = "arrayElements") - public void testArrayAccess(Function<MemorySegment, MemorySegment> viewFactory, MemoryLayout elemLayout, Class<?> carrier, ArrayChecker checker) { + public void testArrayAccess(Function<MemorySegment, MemorySegment> viewFactory, MemoryLayout elemLayout, ArrayChecker checker) { SequenceLayout seq = MemoryLayout.sequenceLayout(10, elemLayout.withName("elem")); - testArrayAccessInternal(viewFactory, seq, seq.varHandle(carrier, PathElement.sequenceElement()), checker); + testArrayAccessInternal(viewFactory, seq, seq.varHandle(PathElement.sequenceElement()), checker); } @Test(dataProvider = "arrayElements") - public void testPaddedArrayAccessByName(Function<MemorySegment, MemorySegment> viewFactory, MemoryLayout elemLayout, Class<?> carrier, ArrayChecker checker) { + public void testPaddedArrayAccessByName(Function<MemorySegment, MemorySegment> viewFactory, MemoryLayout elemLayout, ArrayChecker checker) { SequenceLayout seq = MemoryLayout.sequenceLayout(10, MemoryLayout.structLayout(MemoryLayout.paddingLayout(elemLayout.bitSize()), elemLayout.withName("elem"))); - testArrayAccessInternal(viewFactory, seq, seq.varHandle(carrier, MemoryLayout.PathElement.sequenceElement(), MemoryLayout.PathElement.groupElement("elem")), checker); + testArrayAccessInternal(viewFactory, seq, seq.varHandle(MemoryLayout.PathElement.sequenceElement(), MemoryLayout.PathElement.groupElement("elem")), checker); } @Test(dataProvider = "arrayElements") - public void testPaddedArrayAccessByIndexSeq(Function<MemorySegment, MemorySegment> viewFactory, MemoryLayout elemLayout, Class<?> carrier, ArrayChecker checker) { + public void testPaddedArrayAccessByIndexSeq(Function<MemorySegment, MemorySegment> viewFactory, MemoryLayout elemLayout, ArrayChecker checker) { SequenceLayout seq = MemoryLayout.sequenceLayout(10, MemoryLayout.sequenceLayout(2, elemLayout)); - testArrayAccessInternal(viewFactory, seq, seq.varHandle(carrier, PathElement.sequenceElement(), MemoryLayout.PathElement.sequenceElement(1)), checker); + testArrayAccessInternal(viewFactory, seq, seq.varHandle(PathElement.sequenceElement(), MemoryLayout.PathElement.sequenceElement(1)), checker); } private void testAccessInternal(Function<MemorySegment, MemorySegment> viewFactory, MemoryLayout layout, VarHandle handle, Checker checker) { @@ -149,40 +150,33 @@ public class TestMemoryAccess { } @Test(dataProvider = "matrixElements") - public void testMatrixAccess(Function<MemorySegment, MemorySegment> viewFactory, MemoryLayout elemLayout, Class<?> carrier, MatrixChecker checker) { + public void testMatrixAccess(Function<MemorySegment, MemorySegment> viewFactory, MemoryLayout elemLayout, MatrixChecker checker) { SequenceLayout seq = MemoryLayout.sequenceLayout(20, MemoryLayout.sequenceLayout(10, elemLayout.withName("elem"))); - testMatrixAccessInternal(viewFactory, seq, seq.varHandle(carrier, + testMatrixAccessInternal(viewFactory, seq, seq.varHandle( PathElement.sequenceElement(), PathElement.sequenceElement()), checker); } @Test(dataProvider = "matrixElements") - public void testPaddedMatrixAccessByName(Function<MemorySegment, MemorySegment> viewFactory, MemoryLayout elemLayout, Class<?> carrier, MatrixChecker checker) { + public void testPaddedMatrixAccessByName(Function<MemorySegment, MemorySegment> viewFactory, MemoryLayout elemLayout, MatrixChecker checker) { SequenceLayout seq = MemoryLayout.sequenceLayout(20, MemoryLayout.sequenceLayout(10, MemoryLayout.structLayout(MemoryLayout.paddingLayout(elemLayout.bitSize()), elemLayout.withName("elem")))); testMatrixAccessInternal(viewFactory, seq, - seq.varHandle(carrier, + seq.varHandle( PathElement.sequenceElement(), PathElement.sequenceElement(), PathElement.groupElement("elem")), checker); } @Test(dataProvider = "matrixElements") - public void testPaddedMatrixAccessByIndexSeq(Function<MemorySegment, MemorySegment> viewFactory, MemoryLayout elemLayout, Class<?> carrier, MatrixChecker checker) { + public void testPaddedMatrixAccessByIndexSeq(Function<MemorySegment, MemorySegment> viewFactory, MemoryLayout elemLayout, MatrixChecker checker) { SequenceLayout seq = MemoryLayout.sequenceLayout(20, MemoryLayout.sequenceLayout(10, MemoryLayout.sequenceLayout(2, elemLayout))); testMatrixAccessInternal(viewFactory, seq, - seq.varHandle(carrier, + seq.varHandle( PathElement.sequenceElement(), PathElement.sequenceElement(), PathElement.sequenceElement(1)), checker); } - @Test(dataProvider = "badCarriers", - expectedExceptions = IllegalArgumentException.class) - public void testBadCarriers(Class<?> carrier) { - ValueLayout l = MemoryLayouts.BITS_32_LE.withName("elem"); - l.varHandle(carrier); - } - private void testMatrixAccessInternal(Function<MemorySegment, MemorySegment> viewFactory, SequenceLayout seq, VarHandle handle, MatrixChecker checker) { MemorySegment outer_segment; try (ResourceScope scope = ResourceScope.newConfinedScope()) { @@ -227,37 +221,37 @@ public class TestMemoryAccess { public Object[][] createData() { return new Object[][] { //BE, RW - { ID, MemoryLayouts.BITS_8_BE, byte.class, Checker.BYTE }, - { ID, MemoryLayouts.BITS_16_BE, short.class, Checker.SHORT }, - { ID, MemoryLayouts.BITS_16_BE, char.class, Checker.CHAR }, - { ID, MemoryLayouts.BITS_32_BE, int.class, Checker.INT }, - { ID, MemoryLayouts.BITS_64_BE, long.class, Checker.LONG }, - { ID, MemoryLayouts.BITS_32_BE, float.class, Checker.FLOAT }, - { ID, MemoryLayouts.BITS_64_BE, double.class, Checker.DOUBLE }, + { ID, ValueLayout.JAVA_BYTE, Checker.BYTE }, + { ID, ValueLayout.JAVA_SHORT.withOrder(ByteOrder.BIG_ENDIAN), Checker.SHORT }, + { ID, ValueLayout.JAVA_CHAR.withOrder(ByteOrder.BIG_ENDIAN), Checker.CHAR }, + { ID, ValueLayout.JAVA_INT.withOrder(ByteOrder.BIG_ENDIAN), Checker.INT }, + { ID, ValueLayout.JAVA_LONG.withOrder(ByteOrder.BIG_ENDIAN), Checker.LONG }, + { ID, ValueLayout.JAVA_FLOAT.withOrder(ByteOrder.BIG_ENDIAN), Checker.FLOAT }, + { ID, ValueLayout.JAVA_DOUBLE.withOrder(ByteOrder.BIG_ENDIAN), Checker.DOUBLE }, //BE, RO - { IMMUTABLE, MemoryLayouts.BITS_8_BE, byte.class, Checker.BYTE }, - { IMMUTABLE, MemoryLayouts.BITS_16_BE, short.class, Checker.SHORT }, - { IMMUTABLE, MemoryLayouts.BITS_16_BE, char.class, Checker.CHAR }, - { IMMUTABLE, MemoryLayouts.BITS_32_BE, int.class, Checker.INT }, - { IMMUTABLE, MemoryLayouts.BITS_64_BE, long.class, Checker.LONG }, - { IMMUTABLE, MemoryLayouts.BITS_32_BE, float.class, Checker.FLOAT }, - { IMMUTABLE, MemoryLayouts.BITS_64_BE, double.class, Checker.DOUBLE }, + { IMMUTABLE, ValueLayout.JAVA_BYTE, Checker.BYTE }, + { IMMUTABLE, ValueLayout.JAVA_SHORT.withOrder(ByteOrder.BIG_ENDIAN), Checker.SHORT }, + { IMMUTABLE, ValueLayout.JAVA_CHAR.withOrder(ByteOrder.BIG_ENDIAN), Checker.CHAR }, + { IMMUTABLE, ValueLayout.JAVA_INT.withOrder(ByteOrder.BIG_ENDIAN), Checker.INT }, + { IMMUTABLE, ValueLayout.JAVA_LONG.withOrder(ByteOrder.BIG_ENDIAN), Checker.LONG }, + { IMMUTABLE, ValueLayout.JAVA_FLOAT.withOrder(ByteOrder.BIG_ENDIAN), Checker.FLOAT }, + { IMMUTABLE, ValueLayout.JAVA_DOUBLE.withOrder(ByteOrder.BIG_ENDIAN), Checker.DOUBLE }, //LE, RW - { ID, MemoryLayouts.BITS_8_LE, byte.class, Checker.BYTE }, - { ID, MemoryLayouts.BITS_16_LE, short.class, Checker.SHORT }, - { ID, MemoryLayouts.BITS_16_LE, char.class, Checker.CHAR }, - { ID, MemoryLayouts.BITS_32_LE, int.class, Checker.INT }, - { ID, MemoryLayouts.BITS_64_LE, long.class, Checker.LONG }, - { ID, MemoryLayouts.BITS_32_LE, float.class, Checker.FLOAT }, - { ID, MemoryLayouts.BITS_64_LE, double.class, Checker.DOUBLE }, + { ID, ValueLayout.JAVA_BYTE, Checker.BYTE }, + { ID, ValueLayout.JAVA_SHORT.withOrder(ByteOrder.LITTLE_ENDIAN), Checker.SHORT }, + { ID, ValueLayout.JAVA_CHAR.withOrder(ByteOrder.LITTLE_ENDIAN), Checker.CHAR }, + { ID, ValueLayout.JAVA_INT.withOrder(ByteOrder.LITTLE_ENDIAN), Checker.INT }, + { ID, ValueLayout.JAVA_LONG.withOrder(ByteOrder.LITTLE_ENDIAN), Checker.LONG }, + { ID, ValueLayout.JAVA_FLOAT.withOrder(ByteOrder.LITTLE_ENDIAN), Checker.FLOAT }, + { ID, ValueLayout.JAVA_DOUBLE.withOrder(ByteOrder.LITTLE_ENDIAN), Checker.DOUBLE }, //LE, RO - { IMMUTABLE, MemoryLayouts.BITS_8_LE, byte.class, Checker.BYTE }, - { IMMUTABLE, MemoryLayouts.BITS_16_LE, short.class, Checker.SHORT }, - { IMMUTABLE, MemoryLayouts.BITS_16_LE, char.class, Checker.CHAR }, - { IMMUTABLE, MemoryLayouts.BITS_32_LE, int.class, Checker.INT }, - { IMMUTABLE, MemoryLayouts.BITS_64_LE, long.class, Checker.LONG }, - { IMMUTABLE, MemoryLayouts.BITS_32_LE, float.class, Checker.FLOAT }, - { IMMUTABLE, MemoryLayouts.BITS_64_LE, double.class, Checker.DOUBLE }, + { IMMUTABLE, ValueLayout.JAVA_BYTE, Checker.BYTE }, + { IMMUTABLE, ValueLayout.JAVA_SHORT.withOrder(ByteOrder.LITTLE_ENDIAN), Checker.SHORT }, + { IMMUTABLE, ValueLayout.JAVA_CHAR.withOrder(ByteOrder.LITTLE_ENDIAN), Checker.CHAR }, + { IMMUTABLE, ValueLayout.JAVA_INT.withOrder(ByteOrder.LITTLE_ENDIAN), Checker.INT }, + { IMMUTABLE, ValueLayout.JAVA_LONG.withOrder(ByteOrder.LITTLE_ENDIAN), Checker.LONG }, + { IMMUTABLE, ValueLayout.JAVA_FLOAT.withOrder(ByteOrder.LITTLE_ENDIAN), Checker.FLOAT }, + { IMMUTABLE, ValueLayout.JAVA_DOUBLE.withOrder(ByteOrder.LITTLE_ENDIAN), Checker.DOUBLE }, }; } @@ -304,37 +298,37 @@ public class TestMemoryAccess { public Object[][] createArrayData() { return new Object[][] { //BE, RW - { ID, MemoryLayouts.BITS_8_BE, byte.class, ArrayChecker.BYTE }, - { ID, MemoryLayouts.BITS_16_BE, short.class, ArrayChecker.SHORT }, - { ID, MemoryLayouts.BITS_16_BE, char.class, ArrayChecker.CHAR }, - { ID, MemoryLayouts.BITS_32_BE, int.class, ArrayChecker.INT }, - { ID, MemoryLayouts.BITS_64_BE, long.class, ArrayChecker.LONG }, - { ID, MemoryLayouts.BITS_32_BE, float.class, ArrayChecker.FLOAT }, - { ID, MemoryLayouts.BITS_64_BE, double.class, ArrayChecker.DOUBLE }, + { ID, ValueLayout.JAVA_BYTE, ArrayChecker.BYTE }, + { ID, ValueLayout.JAVA_SHORT.withOrder(ByteOrder.BIG_ENDIAN), ArrayChecker.SHORT }, + { ID, ValueLayout.JAVA_CHAR.withOrder(ByteOrder.BIG_ENDIAN), ArrayChecker.CHAR }, + { ID, ValueLayout.JAVA_INT.withOrder(ByteOrder.BIG_ENDIAN), ArrayChecker.INT }, + { ID, ValueLayout.JAVA_LONG.withOrder(ByteOrder.BIG_ENDIAN), ArrayChecker.LONG }, + { ID, ValueLayout.JAVA_FLOAT.withOrder(ByteOrder.BIG_ENDIAN), ArrayChecker.FLOAT }, + { ID, ValueLayout.JAVA_DOUBLE.withOrder(ByteOrder.BIG_ENDIAN), ArrayChecker.DOUBLE }, //BE, RO - { IMMUTABLE, MemoryLayouts.BITS_8_BE, byte.class, ArrayChecker.BYTE }, - { IMMUTABLE, MemoryLayouts.BITS_16_BE, short.class, ArrayChecker.SHORT }, - { IMMUTABLE, MemoryLayouts.BITS_16_BE, char.class, ArrayChecker.CHAR }, - { IMMUTABLE, MemoryLayouts.BITS_32_BE, int.class, ArrayChecker.INT }, - { IMMUTABLE, MemoryLayouts.BITS_64_BE, long.class, ArrayChecker.LONG }, - { IMMUTABLE, MemoryLayouts.BITS_32_BE, float.class, ArrayChecker.FLOAT }, - { IMMUTABLE, MemoryLayouts.BITS_64_BE, double.class, ArrayChecker.DOUBLE }, + { IMMUTABLE, ValueLayout.JAVA_BYTE, ArrayChecker.BYTE }, + { IMMUTABLE, ValueLayout.JAVA_SHORT.withOrder(ByteOrder.BIG_ENDIAN), ArrayChecker.SHORT }, + { IMMUTABLE, ValueLayout.JAVA_CHAR.withOrder(ByteOrder.BIG_ENDIAN), ArrayChecker.CHAR }, + { IMMUTABLE, ValueLayout.JAVA_INT.withOrder(ByteOrder.BIG_ENDIAN), ArrayChecker.INT }, + { IMMUTABLE, ValueLayout.JAVA_LONG.withOrder(ByteOrder.BIG_ENDIAN), ArrayChecker.LONG }, + { IMMUTABLE, ValueLayout.JAVA_FLOAT.withOrder(ByteOrder.BIG_ENDIAN), ArrayChecker.FLOAT }, + { IMMUTABLE, ValueLayout.JAVA_DOUBLE.withOrder(ByteOrder.BIG_ENDIAN), ArrayChecker.DOUBLE }, //LE, RW - { ID, MemoryLayouts.BITS_8_LE, byte.class, ArrayChecker.BYTE }, - { ID, MemoryLayouts.BITS_16_LE, short.class, ArrayChecker.SHORT }, - { ID, MemoryLayouts.BITS_16_LE, char.class, ArrayChecker.CHAR }, - { ID, MemoryLayouts.BITS_32_LE, int.class, ArrayChecker.INT }, - { ID, MemoryLayouts.BITS_64_LE, long.class, ArrayChecker.LONG }, - { ID, MemoryLayouts.BITS_32_LE, float.class, ArrayChecker.FLOAT }, - { ID, MemoryLayouts.BITS_64_LE, double.class, ArrayChecker.DOUBLE }, + { ID, ValueLayout.JAVA_BYTE, ArrayChecker.BYTE }, + { ID, ValueLayout.JAVA_SHORT.withOrder(ByteOrder.LITTLE_ENDIAN), ArrayChecker.SHORT }, + { ID, ValueLayout.JAVA_CHAR.withOrder(ByteOrder.LITTLE_ENDIAN), ArrayChecker.CHAR }, + { ID, ValueLayout.JAVA_INT.withOrder(ByteOrder.LITTLE_ENDIAN), ArrayChecker.INT }, + { ID, ValueLayout.JAVA_LONG.withOrder(ByteOrder.LITTLE_ENDIAN), ArrayChecker.LONG }, + { ID, ValueLayout.JAVA_FLOAT.withOrder(ByteOrder.LITTLE_ENDIAN), ArrayChecker.FLOAT }, + { ID, ValueLayout.JAVA_DOUBLE.withOrder(ByteOrder.LITTLE_ENDIAN), ArrayChecker.DOUBLE }, //LE, RO - { IMMUTABLE, MemoryLayouts.BITS_8_LE, byte.class, ArrayChecker.BYTE }, - { IMMUTABLE, MemoryLayouts.BITS_16_LE, short.class, ArrayChecker.SHORT }, - { IMMUTABLE, MemoryLayouts.BITS_16_LE, char.class, ArrayChecker.CHAR }, - { IMMUTABLE, MemoryLayouts.BITS_32_LE, int.class, ArrayChecker.INT }, - { IMMUTABLE, MemoryLayouts.BITS_64_LE, long.class, ArrayChecker.LONG }, - { IMMUTABLE, MemoryLayouts.BITS_32_LE, float.class, ArrayChecker.FLOAT }, - { IMMUTABLE, MemoryLayouts.BITS_64_LE, double.class, ArrayChecker.DOUBLE }, + { IMMUTABLE, ValueLayout.JAVA_BYTE, ArrayChecker.BYTE }, + { IMMUTABLE, ValueLayout.JAVA_SHORT.withOrder(ByteOrder.LITTLE_ENDIAN), ArrayChecker.SHORT }, + { IMMUTABLE, ValueLayout.JAVA_CHAR.withOrder(ByteOrder.LITTLE_ENDIAN), ArrayChecker.CHAR }, + { IMMUTABLE, ValueLayout.JAVA_INT.withOrder(ByteOrder.LITTLE_ENDIAN), ArrayChecker.INT }, + { IMMUTABLE, ValueLayout.JAVA_LONG.withOrder(ByteOrder.LITTLE_ENDIAN), ArrayChecker.LONG }, + { IMMUTABLE, ValueLayout.JAVA_FLOAT.withOrder(ByteOrder.LITTLE_ENDIAN), ArrayChecker.FLOAT }, + { IMMUTABLE, ValueLayout.JAVA_DOUBLE.withOrder(ByteOrder.LITTLE_ENDIAN), ArrayChecker.DOUBLE }, }; } @@ -381,37 +375,45 @@ public class TestMemoryAccess { public Object[][] createMatrixData() { return new Object[][] { //BE, RW - { ID, MemoryLayouts.BITS_8_BE, byte.class, MatrixChecker.BYTE }, - { ID, MemoryLayouts.BITS_16_BE, short.class, MatrixChecker.SHORT }, - { ID, MemoryLayouts.BITS_16_BE, char.class, MatrixChecker.CHAR }, - { ID, MemoryLayouts.BITS_32_BE, int.class, MatrixChecker.INT }, - { ID, MemoryLayouts.BITS_64_BE, long.class, MatrixChecker.LONG }, - { ID, MemoryLayouts.BITS_32_BE, float.class, MatrixChecker.FLOAT }, - { ID, MemoryLayouts.BITS_64_BE, double.class, MatrixChecker.DOUBLE }, + { ID, ValueLayout.JAVA_BYTE, MatrixChecker.BYTE }, + { ID, ValueLayout.JAVA_BOOLEAN, MatrixChecker.BOOLEAN }, + { ID, ValueLayout.JAVA_SHORT.withOrder(ByteOrder.BIG_ENDIAN), MatrixChecker.SHORT }, + { ID, ValueLayout.JAVA_CHAR.withOrder(ByteOrder.BIG_ENDIAN), MatrixChecker.CHAR }, + { ID, ValueLayout.JAVA_INT.withOrder(ByteOrder.BIG_ENDIAN), MatrixChecker.INT }, + { ID, ValueLayout.JAVA_LONG.withOrder(ByteOrder.BIG_ENDIAN), MatrixChecker.LONG }, + { ID, ValueLayout.ADDRESS.withOrder(ByteOrder.BIG_ENDIAN), MatrixChecker.ADDR }, + { ID, ValueLayout.JAVA_FLOAT.withOrder(ByteOrder.BIG_ENDIAN), MatrixChecker.FLOAT }, + { ID, ValueLayout.JAVA_DOUBLE.withOrder(ByteOrder.BIG_ENDIAN), MatrixChecker.DOUBLE }, //BE, RO - { IMMUTABLE, MemoryLayouts.BITS_8_BE, byte.class, MatrixChecker.BYTE }, - { IMMUTABLE, MemoryLayouts.BITS_16_BE, short.class, MatrixChecker.SHORT }, - { IMMUTABLE, MemoryLayouts.BITS_16_BE, char.class, MatrixChecker.CHAR }, - { IMMUTABLE, MemoryLayouts.BITS_32_BE, int.class, MatrixChecker.INT }, - { IMMUTABLE, MemoryLayouts.BITS_64_BE, long.class, MatrixChecker.LONG }, - { IMMUTABLE, MemoryLayouts.BITS_32_BE, float.class, MatrixChecker.FLOAT }, - { IMMUTABLE, MemoryLayouts.BITS_64_BE, double.class, MatrixChecker.DOUBLE }, + { IMMUTABLE, ValueLayout.JAVA_BYTE, MatrixChecker.BYTE }, + { IMMUTABLE, ValueLayout.JAVA_BOOLEAN, MatrixChecker.BOOLEAN }, + { IMMUTABLE, ValueLayout.JAVA_SHORT.withOrder(ByteOrder.BIG_ENDIAN), MatrixChecker.SHORT }, + { IMMUTABLE, ValueLayout.JAVA_CHAR.withOrder(ByteOrder.BIG_ENDIAN), MatrixChecker.CHAR }, + { IMMUTABLE, ValueLayout.JAVA_INT.withOrder(ByteOrder.BIG_ENDIAN), MatrixChecker.INT }, + { IMMUTABLE, ValueLayout.JAVA_LONG.withOrder(ByteOrder.BIG_ENDIAN), MatrixChecker.LONG }, + { IMMUTABLE, ValueLayout.ADDRESS.withOrder(ByteOrder.BIG_ENDIAN), MatrixChecker.ADDR }, + { IMMUTABLE, ValueLayout.JAVA_FLOAT.withOrder(ByteOrder.BIG_ENDIAN), MatrixChecker.FLOAT }, + { IMMUTABLE, ValueLayout.JAVA_DOUBLE.withOrder(ByteOrder.BIG_ENDIAN), MatrixChecker.DOUBLE }, //LE, RW - { ID, MemoryLayouts.BITS_8_LE, byte.class, MatrixChecker.BYTE }, - { ID, MemoryLayouts.BITS_16_LE, short.class, MatrixChecker.SHORT }, - { ID, MemoryLayouts.BITS_16_LE, char.class, MatrixChecker.CHAR }, - { ID, MemoryLayouts.BITS_32_LE, int.class, MatrixChecker.INT }, - { ID, MemoryLayouts.BITS_64_LE, long.class, MatrixChecker.LONG }, - { ID, MemoryLayouts.BITS_32_LE, float.class, MatrixChecker.FLOAT }, - { ID, MemoryLayouts.BITS_64_LE, double.class, MatrixChecker.DOUBLE }, + { ID, ValueLayout.JAVA_BYTE, MatrixChecker.BYTE }, + { ID, ValueLayout.JAVA_BOOLEAN, MatrixChecker.BOOLEAN }, + { ID, ValueLayout.JAVA_SHORT.withOrder(ByteOrder.LITTLE_ENDIAN), MatrixChecker.SHORT }, + { ID, ValueLayout.JAVA_CHAR.withOrder(ByteOrder.LITTLE_ENDIAN), MatrixChecker.CHAR }, + { ID, ValueLayout.JAVA_INT.withOrder(ByteOrder.LITTLE_ENDIAN), MatrixChecker.INT }, + { ID, ValueLayout.JAVA_LONG.withOrder(ByteOrder.LITTLE_ENDIAN), MatrixChecker.LONG }, + { ID, ValueLayout.ADDRESS.withOrder(ByteOrder.LITTLE_ENDIAN), MatrixChecker.ADDR }, + { ID, ValueLayout.JAVA_FLOAT.withOrder(ByteOrder.LITTLE_ENDIAN), MatrixChecker.FLOAT }, + { ID, ValueLayout.JAVA_DOUBLE.withOrder(ByteOrder.LITTLE_ENDIAN), MatrixChecker.DOUBLE }, //LE, RO - { IMMUTABLE, MemoryLayouts.BITS_8_LE, byte.class, MatrixChecker.BYTE }, - { IMMUTABLE, MemoryLayouts.BITS_16_LE, short.class, MatrixChecker.SHORT }, - { IMMUTABLE, MemoryLayouts.BITS_16_LE, char.class, MatrixChecker.CHAR }, - { IMMUTABLE, MemoryLayouts.BITS_32_LE, int.class, MatrixChecker.INT }, - { IMMUTABLE, MemoryLayouts.BITS_64_LE, long.class, MatrixChecker.LONG }, - { IMMUTABLE, MemoryLayouts.BITS_32_LE, float.class, MatrixChecker.FLOAT }, - { IMMUTABLE, MemoryLayouts.BITS_64_LE, double.class, MatrixChecker.DOUBLE }, + { IMMUTABLE, ValueLayout.JAVA_BYTE, MatrixChecker.BYTE }, + { IMMUTABLE, ValueLayout.JAVA_BOOLEAN, MatrixChecker.BOOLEAN }, + { IMMUTABLE, ValueLayout.JAVA_SHORT.withOrder(ByteOrder.LITTLE_ENDIAN), MatrixChecker.SHORT }, + { IMMUTABLE, ValueLayout.JAVA_CHAR.withOrder(ByteOrder.LITTLE_ENDIAN), MatrixChecker.CHAR }, + { IMMUTABLE, ValueLayout.JAVA_INT.withOrder(ByteOrder.LITTLE_ENDIAN), MatrixChecker.INT }, + { IMMUTABLE, ValueLayout.JAVA_LONG.withOrder(ByteOrder.LITTLE_ENDIAN), MatrixChecker.LONG }, + { IMMUTABLE, ValueLayout.ADDRESS.withOrder(ByteOrder.LITTLE_ENDIAN), MatrixChecker.ADDR }, + { IMMUTABLE, ValueLayout.JAVA_FLOAT.withOrder(ByteOrder.LITTLE_ENDIAN), MatrixChecker.FLOAT }, + { IMMUTABLE, ValueLayout.JAVA_DOUBLE.withOrder(ByteOrder.LITTLE_ENDIAN), MatrixChecker.DOUBLE }, }; } @@ -423,6 +425,11 @@ public class TestMemoryAccess { assertEquals(r + c, (byte)handle.get(segment, r, c)); }; + MatrixChecker BOOLEAN = (handle, segment, r, c) -> { + handle.set(segment, r, c, (r + c) != 0); + assertEquals((r + c) != 0, (boolean)handle.get(segment, r, c)); + }; + MatrixChecker SHORT = (handle, segment, r, c) -> { handle.set(segment, r, c, (short)(r + c)); assertEquals(r + c, (short)handle.get(segment, r, c)); @@ -443,6 +450,11 @@ public class TestMemoryAccess { assertEquals(r + c, (long)handle.get(segment, r, c)); }; + MatrixChecker ADDR = (handle, segment, r, c) -> { + handle.set(segment, r, c, MemoryAddress.ofLong(r + c)); + assertEquals(MemoryAddress.ofLong(r + c), (MemoryAddress)handle.get(segment, r, c)); + }; + MatrixChecker FLOAT = (handle, segment, r, c) -> { handle.set(segment, r, c, (float)(r + c)); assertEquals((float)(r + c), (float)handle.get(segment, r, c)); @@ -453,14 +465,4 @@ public class TestMemoryAccess { assertEquals((double)(r + c), (double)handle.get(segment, r, c)); }; } - - @DataProvider(name = "badCarriers") - public Object[][] createBadCarriers() { - return new Object[][] { - { void.class }, - { boolean.class }, - { Object.class }, - { int[].class } - }; - } } diff --git a/test/jdk/java/foreign/TestMemoryAccessInstance.java b/test/jdk/java/foreign/TestMemoryAccessInstance.java new file mode 100644 index 0000000000000000000000000000000000000000..83daa11ce4ea984478229f7f0cc91a6ae5bc5815 --- /dev/null +++ b/test/jdk/java/foreign/TestMemoryAccessInstance.java @@ -0,0 +1,336 @@ +/* + * 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. + */ + +/* + * @test + * @run testng/othervm --enable-native-access=ALL-UNNAMED TestMemoryAccessInstance + */ + +import jdk.incubator.foreign.MemoryAddress; +import jdk.incubator.foreign.MemorySegment; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.function.Function; + +import jdk.incubator.foreign.ResourceScope; +import jdk.incubator.foreign.ValueLayout; +import org.testng.SkipException; +import org.testng.annotations.*; +import static org.testng.Assert.*; + +public class TestMemoryAccessInstance { + + static class Accessor<T, X, L extends ValueLayout> { + + interface SegmentGetter<T, X, L> { + X get(T buffer, L layout, long offset); + } + + interface SegmentSetter<T, X, L> { + void set(T buffer, L layout, long offset, X o); + } + + interface BufferGetter<X> { + X get(ByteBuffer segment, int offset); + } + + interface BufferSetter<X> { + void set(ByteBuffer buffer, int offset, X o); + } + + final X value; + final L layout; + final Function<MemorySegment, T> transform; + final SegmentGetter<T, X, L> segmentGetter; + final SegmentSetter<T, X, L> segmentSetter; + final BufferGetter<X> bufferGetter; + final BufferSetter<X> bufferSetter; + + Accessor(Function<MemorySegment, T> transform, L layout, X value, + SegmentGetter<T, X, L> segmentGetter, SegmentSetter<T, X, L> segmentSetter, + BufferGetter<X> bufferGetter, BufferSetter<X> bufferSetter) { + this.transform = transform; + this.layout = layout; + this.value = value; + this.segmentGetter = segmentGetter; + this.segmentSetter = segmentSetter; + this.bufferGetter = bufferGetter; + this.bufferSetter = bufferSetter; + } + + void test() { + try (ResourceScope scope = ResourceScope.newConfinedScope()) { + MemorySegment segment = MemorySegment.allocateNative(64, scope); + ByteBuffer buffer = segment.asByteBuffer(); + T t = transform.apply(segment); + segmentSetter.set(t, layout, 4, value); + assertEquals(bufferGetter.get(buffer, 4), value); + bufferSetter.set(buffer, 4, value); + assertEquals(value, segmentGetter.get(t, layout, 4)); + } + } + + @SuppressWarnings("unchecked") + void testHyperAligned() { + try (ResourceScope scope = ResourceScope.newConfinedScope()) { + MemorySegment segment = MemorySegment.allocateNative(64, scope); + T t = transform.apply(segment); + L alignedLayout = (L)layout.withBitAlignment(layout.byteSize() * 8 * 2); + try { + segmentSetter.set(t, alignedLayout, 0, value); + fail(); + } catch (IllegalArgumentException exception) { + assertTrue(exception.getMessage().contains("greater")); + } + try { + segmentGetter.get(t, alignedLayout, 0); + fail(); + } catch (IllegalArgumentException exception) { + assertTrue(exception.getMessage().contains("greater")); + } + } + } + + static <L extends ValueLayout, X> Accessor<MemorySegment, X, L> ofSegment(L layout, X value, + SegmentGetter<MemorySegment, X, L> segmentGetter, SegmentSetter<MemorySegment, X, L> segmentSetter, + BufferGetter<X> bufferGetter, BufferSetter<X> bufferSetter) { + return new Accessor<>(Function.identity(), layout, value, segmentGetter, segmentSetter, bufferGetter, bufferSetter); + } + + static <L extends ValueLayout, X> Accessor<MemoryAddress, X, L> ofAddress(L layout, X value, + SegmentGetter<MemoryAddress, X, L> segmentGetter, SegmentSetter<MemoryAddress, X, L> segmentSetter, + BufferGetter<X> bufferGetter, BufferSetter<X> bufferSetter) { + return new Accessor<>(MemorySegment::address, layout, value, segmentGetter, segmentSetter, bufferGetter, bufferSetter); + } + } + + @Test(dataProvider = "segmentAccessors") + public void testSegmentAccess(String testName, Accessor<?, ?, ?> accessor) { + accessor.test(); + } + + @Test(dataProvider = "addressAccessors") + public void testAddressAccess(String testName, Accessor<?, ?, ?> accessor) { + accessor.test(); + } + + @Test(dataProvider = "segmentAccessors") + public void testSegmentAccessHyper(String testName, Accessor<?, ?, ?> accessor) { + if (testName.contains("index")) { + accessor.testHyperAligned(); + } else { + throw new SkipException("Skipping"); + } + } + + @Test(dataProvider = "addressAccessors") + public void testAddressAccessHyper(String testName, Accessor<?, ?, ?> accessor) { + if (testName.contains("index")) { + accessor.testHyperAligned(); + } else { + throw new SkipException("Skipping"); + } + } + + static final ByteOrder NE = ByteOrder.nativeOrder(); + + @DataProvider(name = "segmentAccessors") + static Object[][] segmentAccessors() { + return new Object[][]{ + + {"byte", Accessor.ofSegment(ValueLayout.JAVA_BYTE, (byte) 42, + MemorySegment::get, MemorySegment::set, + ByteBuffer::get, ByteBuffer::put) + }, + {"bool", Accessor.ofSegment(ValueLayout.JAVA_BOOLEAN, false, + MemorySegment::get, MemorySegment::set, + (bb, pos) -> bb.get(pos) != 0, (bb, pos, v) -> bb.put(pos, v ? (byte)1 : (byte)0)) + }, + {"char", Accessor.ofSegment(ValueLayout.JAVA_CHAR, (char) 42, + MemorySegment::get, MemorySegment::set, + (bb, pos) -> bb.order(NE).getChar(pos), (bb, pos, v) -> bb.order(NE).putChar(pos, v)) + }, + {"int", Accessor.ofSegment(ValueLayout.JAVA_INT, 42, + MemorySegment::get, MemorySegment::set, + (bb, pos) -> bb.order(NE).getInt(pos), (bb, pos, v) -> bb.order(NE).putInt(pos, v)) + }, + {"float", Accessor.ofSegment(ValueLayout.JAVA_FLOAT, 42f, + MemorySegment::get, MemorySegment::set, + (bb, pos) -> bb.order(NE).getFloat(pos), (bb, pos, v) -> bb.order(NE).putFloat(pos, v)) + }, + {"long", Accessor.ofSegment(ValueLayout.JAVA_LONG, 42L, + MemorySegment::get, MemorySegment::set, + (bb, pos) -> bb.order(NE).getLong(pos), (bb, pos, v) -> bb.order(NE).putLong(pos, v)) + }, + {"double", Accessor.ofSegment(ValueLayout.JAVA_DOUBLE, 42d, + MemorySegment::get, MemorySegment::set, + (bb, pos) -> bb.order(NE).getDouble(pos), (bb, pos, v) -> bb.order(NE).putDouble(pos, v)) + }, + { "address", Accessor.ofSegment(ValueLayout.ADDRESS, MemoryAddress.ofLong(42), + MemorySegment::get, MemorySegment::set, + (bb, pos) -> { + ByteBuffer nb = bb.order(NE); + long addr = ValueLayout.ADDRESS.byteSize() == 8 ? + nb.getLong(pos) : nb.getInt(pos); + return MemoryAddress.ofLong(addr); + }, + (bb, pos, v) -> { + ByteBuffer nb = bb.order(NE); + if (ValueLayout.ADDRESS.byteSize() == 8) { + nb.putLong(pos, v.toRawLongValue()); + } else { + nb.putInt(pos, (int)v.toRawLongValue()); + } + }) + }, + + {"char/index", Accessor.ofSegment(ValueLayout.JAVA_CHAR, (char) 42, + MemorySegment::getAtIndex, MemorySegment::setAtIndex, + (bb, pos) -> bb.order(NE).getChar(pos * 2), (bb, pos, v) -> bb.order(NE).putChar(pos * 2, v)) + }, + {"int/index", Accessor.ofSegment(ValueLayout.JAVA_INT, 42, + MemorySegment::getAtIndex, MemorySegment::setAtIndex, + (bb, pos) -> bb.order(NE).getInt(pos * 4), (bb, pos, v) -> bb.order(NE).putInt(pos * 4, v)) + }, + {"float/index", Accessor.ofSegment(ValueLayout.JAVA_FLOAT, 42f, + MemorySegment::getAtIndex, MemorySegment::setAtIndex, + (bb, pos) -> bb.order(NE).getFloat(pos * 4), (bb, pos, v) -> bb.order(NE).putFloat(pos * 4, v)) + }, + {"long/index", Accessor.ofSegment(ValueLayout.JAVA_LONG, 42L, + MemorySegment::getAtIndex, MemorySegment::setAtIndex, + (bb, pos) -> bb.order(NE).getLong(pos * 8), (bb, pos, v) -> bb.order(NE).putLong(pos * 8, v)) + }, + {"double/index", Accessor.ofSegment(ValueLayout.JAVA_DOUBLE, 42d, + MemorySegment::getAtIndex, MemorySegment::setAtIndex, + (bb, pos) -> bb.order(NE).getDouble(pos * 8), (bb, pos, v) -> bb.order(NE).putDouble(pos * 8, v)) + }, + { "address/index", Accessor.ofSegment(ValueLayout.ADDRESS, MemoryAddress.ofLong(42), + MemorySegment::getAtIndex, MemorySegment::setAtIndex, + (bb, pos) -> { + ByteBuffer nb = bb.order(NE); + long addr = ValueLayout.ADDRESS.byteSize() == 8 ? + nb.getLong(pos * 8) : nb.getInt(pos * 4); + return MemoryAddress.ofLong(addr); + }, + (bb, pos, v) -> { + ByteBuffer nb = bb.order(NE); + if (ValueLayout.ADDRESS.byteSize() == 8) { + nb.putLong(pos * 8, v.toRawLongValue()); + } else { + nb.putInt(pos * 4, (int)v.toRawLongValue()); + } + }) + }, + }; + } + + @DataProvider(name = "addressAccessors") + static Object[][] addressAccessors() { + return new Object[][]{ + + {"byte", Accessor.ofAddress(ValueLayout.JAVA_BYTE, (byte) 42, + MemoryAddress::get, MemoryAddress::set, + ByteBuffer::get, ByteBuffer::put) + }, + {"bool", Accessor.ofAddress(ValueLayout.JAVA_BOOLEAN, false, + MemoryAddress::get, MemoryAddress::set, + (bb, pos) -> bb.get(pos) != 0, (bb, pos, v) -> bb.put(pos, v ? (byte)1 : (byte)0)) + }, + {"char", Accessor.ofAddress(ValueLayout.JAVA_CHAR, (char) 42, + MemoryAddress::get, MemoryAddress::set, + (bb, pos) -> bb.order(NE).getChar(pos), (bb, pos, v) -> bb.order(NE).putChar(pos, v)) + }, + {"int", Accessor.ofAddress(ValueLayout.JAVA_INT, 42, + MemoryAddress::get, MemoryAddress::set, + (bb, pos) -> bb.order(NE).getInt(pos), (bb, pos, v) -> bb.order(NE).putInt(pos, v)) + }, + {"float", Accessor.ofAddress(ValueLayout.JAVA_FLOAT, 42f, + MemoryAddress::get, MemoryAddress::set, + (bb, pos) -> bb.order(NE).getFloat(pos), (bb, pos, v) -> bb.order(NE).putFloat(pos, v)) + }, + {"long", Accessor.ofAddress(ValueLayout.JAVA_LONG, 42L, + MemoryAddress::get, MemoryAddress::set, + (bb, pos) -> bb.order(NE).getLong(pos), (bb, pos, v) -> bb.order(NE).putLong(pos, v)) + }, + {"double", Accessor.ofAddress(ValueLayout.JAVA_DOUBLE, 42d, + MemoryAddress::get, MemoryAddress::set, + (bb, pos) -> bb.order(NE).getDouble(pos), (bb, pos, v) -> bb.order(NE).putDouble(pos, v)) + }, + { "address", Accessor.ofAddress(ValueLayout.ADDRESS, MemoryAddress.ofLong(42), + MemoryAddress::get, MemoryAddress::set, + (bb, pos) -> { + ByteBuffer nb = bb.order(NE); + long addr = ValueLayout.ADDRESS.byteSize() == 8 ? + nb.getLong(pos) : nb.getInt(pos); + return MemoryAddress.ofLong(addr); + }, + (bb, pos, v) -> { + ByteBuffer nb = bb.order(NE); + if (ValueLayout.ADDRESS.byteSize() == 8) { + nb.putLong(pos, v.toRawLongValue()); + } else { + nb.putInt(pos, (int)v.toRawLongValue()); + } + }) + }, + {"char/index", Accessor.ofAddress(ValueLayout.JAVA_CHAR, (char) 42, + MemoryAddress::getAtIndex, MemoryAddress::setAtIndex, + (bb, pos) -> bb.order(NE).getChar(pos * 2), (bb, pos, v) -> bb.order(NE).putChar(pos * 2, v)) + }, + {"int/index", Accessor.ofAddress(ValueLayout.JAVA_INT, 42, + MemoryAddress::getAtIndex, MemoryAddress::setAtIndex, + (bb, pos) -> bb.order(NE).getInt(pos * 4), (bb, pos, v) -> bb.order(NE).putInt(pos * 4, v)) + }, + {"float/index", Accessor.ofAddress(ValueLayout.JAVA_FLOAT, 42f, + MemoryAddress::getAtIndex, MemoryAddress::setAtIndex, + (bb, pos) -> bb.order(NE).getFloat(pos * 4), (bb, pos, v) -> bb.order(NE).putFloat(pos * 4, v)) + }, + {"long/index", Accessor.ofAddress(ValueLayout.JAVA_LONG, 42L, + MemoryAddress::getAtIndex, MemoryAddress::setAtIndex, + (bb, pos) -> bb.order(NE).getLong(pos * 8), (bb, pos, v) -> bb.order(NE).putLong(pos * 8, v)) + }, + {"double/index", Accessor.ofAddress(ValueLayout.JAVA_DOUBLE, 42d, + MemoryAddress::getAtIndex, MemoryAddress::setAtIndex, + (bb, pos) -> bb.order(NE).getDouble(pos * 8), (bb, pos, v) -> bb.order(NE).putDouble(pos * 8, v)) + }, + { "address/index", Accessor.ofAddress(ValueLayout.ADDRESS, MemoryAddress.ofLong(42), + MemoryAddress::getAtIndex, MemoryAddress::setAtIndex, + (bb, pos) -> { + ByteBuffer nb = bb.order(NE); + long addr = ValueLayout.ADDRESS.byteSize() == 8 ? + nb.getLong(pos * 8) : nb.getInt(pos * 4); + return MemoryAddress.ofLong(addr); + }, + (bb, pos, v) -> { + ByteBuffer nb = bb.order(NE); + if (ValueLayout.ADDRESS.byteSize() == 8) { + nb.putLong(pos * 8, v.toRawLongValue()); + } else { + nb.putInt(pos * 4, (int)v.toRawLongValue()); + } + }) + } + }; + } +} diff --git a/test/jdk/java/foreign/TestMemoryAccessStatics.java b/test/jdk/java/foreign/TestMemoryAccessStatics.java deleted file mode 100644 index 4115bf58146a1c37e7392420d231d6481775b7d6..0000000000000000000000000000000000000000 --- a/test/jdk/java/foreign/TestMemoryAccessStatics.java +++ /dev/null @@ -1,364 +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. - */ - -/* - * @test - * @run testng TestMemoryAccessStatics - */ - -import jdk.incubator.foreign.MemoryAccess; -import jdk.incubator.foreign.MemoryAddress; -import jdk.incubator.foreign.MemoryLayouts; -import jdk.incubator.foreign.MemorySegment; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; - -import org.testng.annotations.*; -import static org.testng.Assert.*; - -public class TestMemoryAccessStatics { - - static class Accessor<X> { - - interface SegmentGetter<X> { - X get(MemorySegment segment); - } - - interface SegmentSetter<X> { - void set(MemorySegment segment, X o); - } - - interface BufferGetter<X> { - X get(ByteBuffer segment); - } - - interface BufferSetter<X> { - void set(ByteBuffer buffer, X o); - } - - final X value; - final SegmentGetter<X> segmentGetter; - final SegmentSetter<X> segmentSetter; - final BufferGetter<X> bufferGetter; - final BufferSetter<X> bufferSetter; - - Accessor(X value, - SegmentGetter<X> segmentGetter, SegmentSetter<X> segmentSetter, - BufferGetter<X> bufferGetter, BufferSetter<X> bufferSetter) { - this.value = value; - this.segmentGetter = segmentGetter; - this.segmentSetter = segmentSetter; - this.bufferGetter = bufferGetter; - this.bufferSetter = bufferSetter; - } - - void test() { - MemorySegment segment = MemorySegment.ofArray(new byte[32]); - ByteBuffer buffer = segment.asByteBuffer(); - segmentSetter.set(segment, value); - assertEquals(bufferGetter.get(buffer), value); - bufferSetter.set(buffer, value); - assertEquals(value, segmentGetter.get(segment)); - } - - <Z> Accessor<Z> of(Z value, - SegmentGetter<Z> segmentGetter, SegmentSetter<Z> segmentSetter, - BufferGetter<Z> bufferGetter, BufferSetter<Z> bufferSetter) { - return new Accessor<>(value, segmentGetter, segmentSetter, bufferGetter, bufferSetter); - } - } - - @Test(dataProvider = "accessors") - public void testMemoryAccess(String testName, Accessor<?> accessor) { - accessor.test(); - } - - static final ByteOrder BE = ByteOrder.BIG_ENDIAN; - static final ByteOrder LE = ByteOrder.LITTLE_ENDIAN; - static final ByteOrder NE = ByteOrder.nativeOrder(); - - @DataProvider(name = "accessors") - static Object[][] accessors() { - return new Object[][]{ - - {"byte", new Accessor<>((byte) 42, - MemoryAccess::getByte, MemoryAccess::setByte, - (bb) -> bb.get(0), (bb, v) -> bb.put(0, v)) - }, - {"char", new Accessor<>((char) 42, - MemoryAccess::getChar, MemoryAccess::setChar, - (bb) -> bb.order(NE).getChar(0), (bb, v) -> bb.order(NE).putChar(0, v)) - }, - {"char/LE", new Accessor<>((char) 42, - s -> MemoryAccess.getChar(s, LE), (s, x) -> MemoryAccess.setChar(s, LE, x), - (bb) -> bb.order(LE).getChar(0), (bb, v) -> bb.order(LE).putChar(0, v)) - }, - {"char/BE", new Accessor<>((char) 42, - s -> MemoryAccess.getChar(s, BE), (s, x) -> MemoryAccess.setChar(s, BE, x), - (bb) -> bb.order(BE).getChar(0), (bb, v) -> bb.order(BE).putChar(0, v)) - }, - {"short", new Accessor<>((short) 42, - MemoryAccess::getShort, MemoryAccess::setShort, - (bb) -> bb.order(NE).getShort(0), (bb, v) -> bb.order(NE).putShort(0, v)) - }, - {"short/LE", new Accessor<>((short) 42, - s -> MemoryAccess.getShort(s, LE), (s, x) -> MemoryAccess.setShort(s, LE, x), - (bb) -> bb.order(LE).getShort(0), (bb, v) -> bb.order(LE).putShort(0, v)) - }, - {"short/BE", new Accessor<>((short) 42, - s -> MemoryAccess.getShort(s, BE), (s, x) -> MemoryAccess.setShort(s, BE, x), - (bb) -> bb.order(BE).getShort(0), (bb, v) -> bb.order(BE).putShort(0, v)) - }, - {"int", new Accessor<>(42, - MemoryAccess::getInt, MemoryAccess::setInt, - (bb) -> bb.order(NE).getInt(0), (bb, v) -> bb.order(NE).putInt(0, v)) - }, - {"int/LE", new Accessor<>(42, - s -> MemoryAccess.getInt(s, LE), (s, x) -> MemoryAccess.setInt(s, LE, x), - (bb) -> bb.order(LE).getInt(0), (bb, v) -> bb.order(LE).putInt(0, v)) - }, - {"int/BE", new Accessor<>(42, - s -> MemoryAccess.getInt(s, BE), (s, x) -> MemoryAccess.setInt(s, BE, x), - (bb) -> bb.order(BE).getInt(0), (bb, v) -> bb.order(BE).putInt(0, v)) - }, - // float, no offset - {"float", new Accessor<>(42f, - MemoryAccess::getFloat, MemoryAccess::setFloat, - (bb) -> bb.order(NE).getFloat(0), (bb, v) -> bb.order(NE).putFloat(0, v)) - }, - {"float/LE", new Accessor<>(42f, - s -> MemoryAccess.getFloat(s, LE), (s, x) -> MemoryAccess.setFloat(s, LE, x), - (bb) -> bb.order(LE).getFloat(0), (bb, v) -> bb.order(LE).putFloat(0, v)) - }, - {"float/BE", new Accessor<>(42f, - s -> MemoryAccess.getFloat(s, BE), (s, x) -> MemoryAccess.setFloat(s, BE, x), - (bb) -> bb.order(BE).getFloat(0), (bb, v) -> bb.order(BE).putFloat(0, v)) - }, - // double, no offset - {"double", new Accessor<>(42d, - MemoryAccess::getDouble, MemoryAccess::setDouble, - (bb) -> bb.order(NE).getDouble(0), (bb, v) -> bb.order(NE).putDouble(0, v)) - }, - {"double/LE", new Accessor<>(42d, - s -> MemoryAccess.getDouble(s, LE), (s, x) -> MemoryAccess.setDouble(s, LE, x), - (bb) -> bb.order(LE).getDouble(0), (bb, v) -> bb.order(LE).putDouble(0, v)) - }, - {"double/BE", new Accessor<>(42d, - s -> MemoryAccess.getDouble(s, BE), (s, x) -> MemoryAccess.setDouble(s, BE, x), - (bb) -> bb.order(BE).getDouble(0), (bb, v) -> bb.order(BE).putDouble(0, v)) - }, - - - // byte, offset - {"byte/offset", new Accessor<>((byte) 42, - s -> MemoryAccess.getByteAtOffset(s, 4), (s, x) -> MemoryAccess.setByteAtOffset(s, 4, x), - (bb) -> bb.get(4), (bb, v) -> bb.put(4, v)) - }, - // char, offset - {"char/offset", new Accessor<>((char) 42, - s -> MemoryAccess.getCharAtOffset(s, 4), (s, x) -> MemoryAccess.setCharAtOffset(s, 4, x), - (bb) -> bb.order(NE).getChar(4), (bb, v) -> bb.order(NE).putChar(4, v)) - }, - {"char/offset/LE", new Accessor<>((char) 42, - s -> MemoryAccess.getCharAtOffset(s, 4, LE), (s, x) -> MemoryAccess.setCharAtOffset(s, 4, LE, x), - (bb) -> bb.order(LE).getChar(4), (bb, v) -> bb.order(LE).putChar(4, v)) - }, - {"char/offset/BE", new Accessor<>((char) 42, - s -> MemoryAccess.getCharAtOffset(s, 4, BE), (s, x) -> MemoryAccess.setCharAtOffset(s, 4, BE, x), - (bb) -> bb.order(BE).getChar(4), (bb, v) -> bb.order(BE).putChar(4, v)) - }, - // short, offset - {"short/offset", new Accessor<>((short) 42, - s -> MemoryAccess.getShortAtOffset(s, 4), (s, x) -> MemoryAccess.setShortAtOffset(s, 4, x), - (bb) -> bb.order(NE).getShort(4), (bb, v) -> bb.order(NE).putShort(4, v)) - }, - {"short/offset/LE", new Accessor<>((short) 42, - s -> MemoryAccess.getShortAtOffset(s, 4, LE), (s, x) -> MemoryAccess.setShortAtOffset(s, 4, LE, x), - (bb) -> bb.order(LE).getShort(4), (bb, v) -> bb.order(LE).putShort(4, v)) - }, - {"short/offset/BE", new Accessor<>((short) 42, - s -> MemoryAccess.getShortAtOffset(s, 4, BE), (s, x) -> MemoryAccess.setShortAtOffset(s, 4, BE, x), - (bb) -> bb.order(BE).getShort(4), (bb, v) -> bb.order(BE).putShort(4, v)) - }, - // int, offset - {"int/offset", new Accessor<>(42, - s -> MemoryAccess.getIntAtOffset(s, 4), (s, x) -> MemoryAccess.setIntAtOffset(s, 4, x), - (bb) -> bb.order(NE).getInt(4), (bb, v) -> bb.order(NE).putInt(4, v)) - }, - {"int/offset/LE", new Accessor<>(42, - s -> MemoryAccess.getIntAtOffset(s, 4, LE), (s, x) -> MemoryAccess.setIntAtOffset(s, 4, LE, x), - (bb) -> bb.order(LE).getInt(4), (bb, v) -> bb.order(LE).putInt(4, v)) - }, - {"int/offset/BE", new Accessor<>(42, - s -> MemoryAccess.getIntAtOffset(s, 4, BE), (s, x) -> MemoryAccess.setIntAtOffset(s, 4, BE, x), - (bb) -> bb.order(BE).getInt(4), (bb, v) -> bb.order(BE).putInt(4, v)) - }, - // float, offset - {"float/offset", new Accessor<>(42f, - s -> MemoryAccess.getFloatAtOffset(s, 4), (s, x) -> MemoryAccess.setFloatAtOffset(s, 4, x), - (bb) -> bb.order(NE).getFloat(4), (bb, v) -> bb.order(NE).putFloat(4, v)) - }, - {"float/offset/LE", new Accessor<>(42f, - s -> MemoryAccess.getFloatAtOffset(s, 4, LE), (s, x) -> MemoryAccess.setFloatAtOffset(s, 4, LE, x), - (bb) -> bb.order(LE).getFloat(4), (bb, v) -> bb.order(LE).putFloat(4, v)) - }, - {"float/offset/BE", new Accessor<>(42f, - s -> MemoryAccess.getFloatAtOffset(s, 4, BE), (s, x) -> MemoryAccess.setFloatAtOffset(s, 4, BE, x), - (bb) -> bb.order(BE).getFloat(4), (bb, v) -> bb.order(BE).putFloat(4, v)) - }, - // double, offset - {"double/offset", new Accessor<>(42d, - s -> MemoryAccess.getDoubleAtOffset(s, 4), (s, x) -> MemoryAccess.setDoubleAtOffset(s, 4, x), - (bb) -> bb.order(NE).getDouble(4), (bb, v) -> bb.order(NE).putDouble(4, v)) - }, - {"double/offset/LE", new Accessor<>(42d, - s -> MemoryAccess.getDoubleAtOffset(s, 4, LE), (s, x) -> MemoryAccess.setDoubleAtOffset(s, 4, LE, x), - (bb) -> bb.order(LE).getDouble(4), (bb, v) -> bb.order(LE).putDouble(4, v)) - }, - {"double/offset/BE", new Accessor<>(42d, - s -> MemoryAccess.getDoubleAtOffset(s, 4, BE), (s, x) -> MemoryAccess.setDoubleAtOffset(s, 4, BE, x), - (bb) -> bb.order(BE).getDouble(4), (bb, v) -> bb.order(BE).putDouble(4, v)) - }, - - - // char, index - {"char/index", new Accessor<>((char) 42, - s -> MemoryAccess.getCharAtIndex(s, 2), (s, x) -> MemoryAccess.setCharAtIndex(s, 2, x), - (bb) -> bb.order(NE).asCharBuffer().get(2), (bb, v) -> bb.order(NE).asCharBuffer().put(2, v)) - }, - {"char/index/LE", new Accessor<>((char) 42, - s -> MemoryAccess.getCharAtIndex(s, 2, LE), (s, x) -> MemoryAccess.setCharAtIndex(s, 2, LE, x), - (bb) -> bb.order(LE).asCharBuffer().get(2), (bb, v) -> bb.order(LE).asCharBuffer().put(2, v)) - }, - {"char/index/BE", new Accessor<>((char) 42, - s -> MemoryAccess.getCharAtIndex(s, 2, BE), (s, x) -> MemoryAccess.setCharAtIndex(s, 2, BE, x), - (bb) -> bb.order(BE).asCharBuffer().get(2), (bb, v) -> bb.order(BE).asCharBuffer().put(2, v)) - }, - // short, index - {"short/index", new Accessor<>((short) 42, - s -> MemoryAccess.getShortAtIndex(s, 2), (s, x) -> MemoryAccess.setShortAtIndex(s, 2, x), - (bb) -> bb.order(NE).asShortBuffer().get(2), (bb, v) -> bb.order(NE).asShortBuffer().put(2, v)) - }, - {"short/index/LE", new Accessor<>((short) 42, - s -> MemoryAccess.getShortAtIndex(s, 2, LE), (s, x) -> MemoryAccess.setShortAtIndex(s, 2, LE, x), - (bb) -> bb.order(LE).asShortBuffer().get(2), (bb, v) -> bb.order(LE).asShortBuffer().put(2, v)) - }, - {"short/index/BE", new Accessor<>((short) 42, - s -> MemoryAccess.getShortAtIndex(s, 2, BE), (s, x) -> MemoryAccess.setShortAtIndex(s, 2, BE, x), - (bb) -> bb.order(BE).asShortBuffer().get(2), (bb, v) -> bb.order(BE).asShortBuffer().put(2, v)) - }, - {"int/index", new Accessor<>(42, - s -> MemoryAccess.getIntAtIndex(s, 2), (s, x) -> MemoryAccess.setIntAtIndex(s, 2, x), - (bb) -> bb.order(NE).asIntBuffer().get(2), (bb, v) -> bb.order(NE).asIntBuffer().put(2, v)) - }, - {"int/index/LE", new Accessor<>(42, - s -> MemoryAccess.getIntAtIndex(s, 2, LE), (s, x) -> MemoryAccess.setIntAtIndex(s, 2, LE, x), - (bb) -> bb.order(LE).asIntBuffer().get(2), (bb, v) -> bb.order(LE).asIntBuffer().put(2, v)) - }, - {"int/index/BE", new Accessor<>(42, - s -> MemoryAccess.getIntAtIndex(s, 2, BE), (s, x) -> MemoryAccess.setIntAtIndex(s, 2, BE, x), - (bb) -> bb.order(BE).asIntBuffer().get(2), (bb, v) -> bb.order(BE).asIntBuffer().put(2, v)) - }, - {"float/index", new Accessor<>(42f, - s -> MemoryAccess.getFloatAtIndex(s, 2), (s, x) -> MemoryAccess.setFloatAtIndex(s, 2, x), - (bb) -> bb.order(NE).asFloatBuffer().get(2), (bb, v) -> bb.order(NE).asFloatBuffer().put(2, v)) - }, - {"float/index/LE", new Accessor<>(42f, - s -> MemoryAccess.getFloatAtIndex(s, 2, LE), (s, x) -> MemoryAccess.setFloatAtIndex(s, 2, LE, x), - (bb) -> bb.order(LE).asFloatBuffer().get(2), (bb, v) -> bb.order(LE).asFloatBuffer().put(2, v)) - }, - {"float/index/BE", new Accessor<>(42f, - s -> MemoryAccess.getFloatAtIndex(s, 2, BE), (s, x) -> MemoryAccess.setFloatAtIndex(s, 2, BE, x), - (bb) -> bb.order(BE).asFloatBuffer().get(2), (bb, v) -> bb.order(BE).asFloatBuffer().put(2, v)) - }, - {"double/index", new Accessor<>(42d, - s -> MemoryAccess.getDoubleAtIndex(s, 2), (s, x) -> MemoryAccess.setDoubleAtIndex(s, 2, x), - (bb) -> bb.order(NE).asDoubleBuffer().get(2), (bb, v) -> bb.order(NE).asDoubleBuffer().put(2, v)) - }, - {"double/index/LE", new Accessor<>(42d, - s -> MemoryAccess.getDoubleAtIndex(s, 2, LE), (s, x) -> MemoryAccess.setDoubleAtIndex(s, 2, LE, x), - (bb) -> bb.order(LE).asDoubleBuffer().get(2), (bb, v) -> bb.order(LE).asDoubleBuffer().put(2, v)) - }, - {"double/index/BE", new Accessor<>(42d, - s -> MemoryAccess.getDoubleAtIndex(s, 2, BE), (s, x) -> MemoryAccess.setDoubleAtIndex(s, 2, BE, x), - (bb) -> bb.order(BE).asDoubleBuffer().get(2), (bb, v) -> bb.order(BE).asDoubleBuffer().put(2, v)) - }, - - { "address", new Accessor<>(MemoryAddress.ofLong(42), - MemoryAccess::getAddress, MemoryAccess::setAddress, - (bb) -> { - ByteBuffer nb = bb.order(NE); - long addr = MemoryLayouts.ADDRESS.byteSize() == 8 ? - nb.getLong(0) : nb.getInt(0); - return MemoryAddress.ofLong(addr); - }, - (bb, v) -> { - ByteBuffer nb = bb.order(NE); - if (MemoryLayouts.ADDRESS.byteSize() == 8) { - nb.putLong(0, v.toRawLongValue()); - } else { - nb.putInt(0, (int)v.toRawLongValue()); - } - }) - }, - { "address/offset", new Accessor<>(MemoryAddress.ofLong(42), - s -> MemoryAccess.getAddressAtOffset(s, 4), (s, x) -> MemoryAccess.setAddressAtOffset(s, 4, x), - (bb) -> { - ByteBuffer nb = bb.order(NE); - long addr = MemoryLayouts.ADDRESS.byteSize() == 8 ? - nb.getLong(4) : nb.getInt(4); - return MemoryAddress.ofLong(addr); - }, - (bb, v) -> { - ByteBuffer nb = bb.order(NE); - if (MemoryLayouts.ADDRESS.byteSize() == 8) { - nb.putLong(4, v.toRawLongValue()); - } else { - nb.putInt(4, (int)v.toRawLongValue()); - } - }) - }, - { "address/index", new Accessor<>(MemoryAddress.ofLong(42), - s -> MemoryAccess.getAddressAtIndex(s, 2), (s, x) -> MemoryAccess.setAddressAtIndex(s, 2, x), - (bb) -> { - ByteBuffer nb = bb.order(NE); - long addr = MemoryLayouts.ADDRESS.byteSize() == 8 ? - nb.asLongBuffer().get(2) : nb.asIntBuffer().get(2); - return MemoryAddress.ofLong(addr); - }, - (bb, v) -> { - ByteBuffer nb = bb.order(NE); - if (MemoryLayouts.ADDRESS.byteSize() == 8) { - nb.asLongBuffer().put(2, v.toRawLongValue()); - } else { - nb.asIntBuffer().put(2, (int)v.toRawLongValue()); - } - }) - }, - }; - } -} diff --git a/test/jdk/java/foreign/TestMemoryAlignment.java b/test/jdk/java/foreign/TestMemoryAlignment.java index 93f218245c8d1ab080e70acc42dccf6759d1f3eb..2726fd6d91eee0abe6d28f93ea346ed0adb19dfb 100644 --- a/test/jdk/java/foreign/TestMemoryAlignment.java +++ b/test/jdk/java/foreign/TestMemoryAlignment.java @@ -26,7 +26,6 @@ * @run testng TestMemoryAlignment */ -import jdk.incubator.foreign.MemoryLayouts; import jdk.incubator.foreign.MemoryLayout; import jdk.incubator.foreign.GroupLayout; @@ -36,6 +35,7 @@ import jdk.incubator.foreign.ResourceScope; import jdk.incubator.foreign.SequenceLayout; import jdk.incubator.foreign.ValueLayout; import java.lang.invoke.VarHandle; +import java.nio.ByteOrder; import java.util.stream.LongStream; import org.testng.annotations.*; @@ -45,11 +45,13 @@ public class TestMemoryAlignment { @Test(dataProvider = "alignments") public void testAlignedAccess(long align) { - ValueLayout layout = MemoryLayouts.BITS_32_BE; + ValueLayout layout = ValueLayout.JAVA_INT + .withBitAlignment(32) + .withOrder(ByteOrder.BIG_ENDIAN); assertEquals(layout.bitAlignment(), 32); ValueLayout aligned = layout.withBitAlignment(align); assertEquals(aligned.bitAlignment(), align); //unreasonable alignment here, to make sure access throws - VarHandle vh = aligned.varHandle(int.class); + VarHandle vh = aligned.varHandle(); try (ResourceScope scope = ResourceScope.newConfinedScope()) { MemorySegment segment = MemorySegment.allocateNative(aligned, scope); vh.set(segment, -42); @@ -60,28 +62,30 @@ public class TestMemoryAlignment { @Test(dataProvider = "alignments") public void testUnalignedAccess(long align) { - ValueLayout layout = MemoryLayouts.BITS_32_BE; + ValueLayout layout = ValueLayout.JAVA_INT + .withBitAlignment(32) + .withOrder(ByteOrder.BIG_ENDIAN); assertEquals(layout.bitAlignment(), 32); ValueLayout aligned = layout.withBitAlignment(align); - MemoryLayout alignedGroup = MemoryLayout.structLayout(MemoryLayouts.PAD_8, aligned); + MemoryLayout alignedGroup = MemoryLayout.structLayout(MemoryLayout.paddingLayout(8), aligned); assertEquals(alignedGroup.bitAlignment(), align); - VarHandle vh = aligned.varHandle(int.class); + VarHandle vh = aligned.varHandle(); try (ResourceScope scope = ResourceScope.newConfinedScope()) { MemorySegment segment = MemorySegment.allocateNative(alignedGroup, scope); vh.set(segment.asSlice(1L), -42); assertEquals(align, 8); //this is the only case where access is aligned - } catch (IllegalStateException ex) { + } catch (IllegalArgumentException ex) { assertNotEquals(align, 8); //if align != 8, access is always unaligned } } @Test(dataProvider = "alignments") public void testUnalignedPath(long align) { - MemoryLayout layout = MemoryLayouts.BITS_32_BE; + MemoryLayout layout = ValueLayout.JAVA_INT.withOrder(ByteOrder.BIG_ENDIAN); MemoryLayout aligned = layout.withBitAlignment(align).withName("value"); - GroupLayout alignedGroup = MemoryLayout.structLayout(MemoryLayouts.PAD_8, aligned); + GroupLayout alignedGroup = MemoryLayout.structLayout(MemoryLayout.paddingLayout(8), aligned); try { - alignedGroup.varHandle(int.class, PathElement.groupElement("value")); + alignedGroup.varHandle(PathElement.groupElement("value")); assertEquals(align, 8); //this is the only case where path is aligned } catch (UnsupportedOperationException ex) { assertNotEquals(align, 8); //if align != 8, path is always unaligned @@ -90,9 +94,9 @@ public class TestMemoryAlignment { @Test(dataProvider = "alignments") public void testUnalignedSequence(long align) { - SequenceLayout layout = MemoryLayout.sequenceLayout(5, MemoryLayouts.BITS_32_BE.withBitAlignment(align)); + SequenceLayout layout = MemoryLayout.sequenceLayout(5, ValueLayout.JAVA_INT.withOrder(ByteOrder.BIG_ENDIAN).withBitAlignment(align)); try { - VarHandle vh = layout.varHandle(int.class, PathElement.sequenceElement()); + VarHandle vh = layout.varHandle(PathElement.sequenceElement()); try (ResourceScope scope = ResourceScope.newConfinedScope()) { MemorySegment segment = MemorySegment.allocateNative(layout, scope); for (long i = 0 ; i < 5 ; i++) { @@ -106,17 +110,17 @@ public class TestMemoryAlignment { @Test public void testPackedAccess() { - ValueLayout vChar = MemoryLayouts.BITS_8_BE; - ValueLayout vShort = MemoryLayouts.BITS_16_BE; - ValueLayout vInt = MemoryLayouts.BITS_32_BE; + ValueLayout vChar = ValueLayout.JAVA_BYTE; + ValueLayout vShort = ValueLayout.JAVA_SHORT.withOrder(ByteOrder.BIG_ENDIAN); + ValueLayout vInt = ValueLayout.JAVA_INT.withOrder(ByteOrder.BIG_ENDIAN); //mimic pragma pack(1) GroupLayout g = MemoryLayout.structLayout(vChar.withBitAlignment(8).withName("a"), vShort.withBitAlignment(8).withName("b"), vInt.withBitAlignment(8).withName("c")); assertEquals(g.bitAlignment(), 8); - VarHandle vh_c = g.varHandle(byte.class, PathElement.groupElement("a")); - VarHandle vh_s = g.varHandle(short.class, PathElement.groupElement("b")); - VarHandle vh_i = g.varHandle(int.class, PathElement.groupElement("c")); + VarHandle vh_c = g.varHandle(PathElement.groupElement("a")); + VarHandle vh_s = g.varHandle(PathElement.groupElement("b")); + VarHandle vh_i = g.varHandle(PathElement.groupElement("c")); try (ResourceScope scope = ResourceScope.newConfinedScope()) { MemorySegment segment = MemorySegment.allocateNative(g, scope); vh_c.set(segment, Byte.MIN_VALUE); diff --git a/test/jdk/java/foreign/TestMemoryCopy.java b/test/jdk/java/foreign/TestMemoryCopy.java deleted file mode 100644 index cba9186f124ac28e635ba64d175734fc25c5cd76..0000000000000000000000000000000000000000 --- a/test/jdk/java/foreign/TestMemoryCopy.java +++ /dev/null @@ -1,121 +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. - * - */ - -/* - * @test - * @run testng TestMemoryCopy - */ - -import jdk.incubator.foreign.MemoryLayouts; -import jdk.incubator.foreign.MemorySegment; -import jdk.incubator.foreign.ResourceScope; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; - -import java.lang.invoke.VarHandle; -import java.util.ArrayList; -import java.util.List; -import java.util.function.IntFunction; - -import static org.testng.Assert.*; - -public class TestMemoryCopy { - - final static VarHandle BYTE_HANDLE = MemoryLayouts.JAVA_BYTE.varHandle(byte.class); - - @Test(dataProvider = "slices") - public void testCopy(SegmentSlice s1, SegmentSlice s2) { - int size = Math.min(s1.size(), s2.size()); - //prepare source and target segments - for (int i = 0 ; i < size ; i++) { - BYTE_HANDLE.set(s2.segment.asSlice(i), (byte)0); - } - for (int i = 0 ; i < size ; i++) { - BYTE_HANDLE.set(s1.segment.asSlice(i), (byte) i); - } - //perform copy - s2.segment.copyFrom(s1.segment.asSlice(0, size)); - //check that copy actually worked - for (int i = 0 ; i < size ; i++) { - assertEquals((byte)i, BYTE_HANDLE.get(s2.segment.asSlice(i))); - } - } - - static class SegmentSlice { - - enum Kind { - NATIVE(i -> MemorySegment.allocateNative(i, ResourceScope.newImplicitScope())), - ARRAY(i -> MemorySegment.ofArray(new byte[i])); - - final IntFunction<MemorySegment> segmentFactory; - - Kind(IntFunction<MemorySegment> segmentFactory) { - this.segmentFactory = segmentFactory; - } - - MemorySegment makeSegment(int elems) { - return segmentFactory.apply(elems); - } - } - - final Kind kind; - final int first; - final int last; - final MemorySegment segment; - - public SegmentSlice(Kind kind, int first, int last, MemorySegment segment) { - this.kind = kind; - this.first = first; - this.last = last; - this.segment = segment; - } - - int size() { - return last - first + 1; - } - } - - @DataProvider(name = "slices") - static Object[][] slices() { - int[] sizes = { 16, 8, 4, 2, 1 }; - List<SegmentSlice> slices = new ArrayList<>(); - for (SegmentSlice.Kind kind : SegmentSlice.Kind.values()) { - MemorySegment segment = kind.makeSegment(16); - //compute all slices - for (int size : sizes) { - for (int index = 0 ; index < 16 ; index += size) { - MemorySegment slice = segment.asSlice(index, size); - slices.add(new SegmentSlice(kind, index, index + size - 1, slice)); - } - } - } - Object[][] sliceArray = new Object[slices.size() * slices.size()][]; - for (int i = 0 ; i < slices.size() ; i++) { - for (int j = 0 ; j < slices.size() ; j++) { - sliceArray[i * slices.size() + j] = new Object[] { slices.get(i), slices.get(j) }; - } - } - return sliceArray; - } -} diff --git a/test/jdk/java/foreign/TestMemoryDereference.java b/test/jdk/java/foreign/TestMemoryDereference.java new file mode 100644 index 0000000000000000000000000000000000000000..c62380cc355dcc7be599cfa5887cb80acff5a824 --- /dev/null +++ b/test/jdk/java/foreign/TestMemoryDereference.java @@ -0,0 +1,217 @@ +/* + * 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. + */ + +/* + * @test + * @run testng TestMemoryDereference + */ + +import jdk.incubator.foreign.MemoryAddress; +import jdk.incubator.foreign.MemorySegment; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +import jdk.incubator.foreign.ValueLayout; +import org.testng.annotations.*; + +import static jdk.incubator.foreign.ValueLayout.ADDRESS; +import static jdk.incubator.foreign.ValueLayout.JAVA_BOOLEAN; +import static jdk.incubator.foreign.ValueLayout.JAVA_BYTE; +import static jdk.incubator.foreign.ValueLayout.JAVA_CHAR; +import static jdk.incubator.foreign.ValueLayout.JAVA_DOUBLE; +import static jdk.incubator.foreign.ValueLayout.JAVA_FLOAT; +import static jdk.incubator.foreign.ValueLayout.JAVA_INT; +import static jdk.incubator.foreign.ValueLayout.JAVA_SHORT; +import static org.testng.Assert.*; + +public class TestMemoryDereference { + + static class Accessor<X> { + + interface SegmentGetter<X> { + X get(MemorySegment segment); + } + + interface SegmentSetter<X> { + void set(MemorySegment segment, X o); + } + + interface BufferGetter<X> { + X get(ByteBuffer segment); + } + + interface BufferSetter<X> { + void set(ByteBuffer buffer, X o); + } + + final X value; + final SegmentGetter<X> segmentGetter; + final SegmentSetter<X> segmentSetter; + final BufferGetter<X> bufferGetter; + final BufferSetter<X> bufferSetter; + + Accessor(X value, + SegmentGetter<X> segmentGetter, SegmentSetter<X> segmentSetter, + BufferGetter<X> bufferGetter, BufferSetter<X> bufferSetter) { + this.value = value; + this.segmentGetter = segmentGetter; + this.segmentSetter = segmentSetter; + this.bufferGetter = bufferGetter; + this.bufferSetter = bufferSetter; + } + + void test() { + MemorySegment segment = MemorySegment.ofArray(new byte[32]); + ByteBuffer buffer = segment.asByteBuffer(); + segmentSetter.set(segment, value); + assertEquals(bufferGetter.get(buffer), value); + bufferSetter.set(buffer, value); + assertEquals(value, segmentGetter.get(segment)); + } + + <Z> Accessor<Z> of(Z value, + SegmentGetter<Z> segmentGetter, SegmentSetter<Z> segmentSetter, + BufferGetter<Z> bufferGetter, BufferSetter<Z> bufferSetter) { + return new Accessor<>(value, segmentGetter, segmentSetter, bufferGetter, bufferSetter); + } + } + + @Test(dataProvider = "accessors") + public void testMemoryAccess(String testName, Accessor<?> accessor) { + accessor.test(); + } + + static final ByteOrder BE = ByteOrder.BIG_ENDIAN; + static final ByteOrder LE = ByteOrder.LITTLE_ENDIAN; + static final ByteOrder NE = ByteOrder.nativeOrder(); + + @DataProvider(name = "accessors") + static Object[][] accessors() { + return new Object[][]{ + + // byte, offset + {"byte/offset", new Accessor<>((byte) 42, + s -> s.get(JAVA_BYTE, 8), (s, x) -> s.set(JAVA_BYTE, 8, x), + (bb) -> bb.get(8), (bb, v) -> bb.put(8, v)) + }, + // bool, offset + {"bool", new Accessor<>(false, + s -> s.get(JAVA_BOOLEAN, 8), (s, x) -> s.set(JAVA_BOOLEAN, 8, x), + (bb) -> bb.get(8) != 0, (bb, v) -> bb.put(8, v ? (byte)1 : (byte)0)) + }, + // char, offset + {"char/offset", new Accessor<>((char) 42, + s -> s.get(JAVA_CHAR, 8), (s, x) -> s.set(JAVA_CHAR, 8, x), + (bb) -> bb.order(NE).getChar(8), (bb, v) -> bb.order(NE).putChar(8, v)) + }, + {"char/offset/LE", new Accessor<>((char) 42, + s -> s.get(JAVA_CHAR.withOrder(ByteOrder.LITTLE_ENDIAN), 8), + (s, x) -> s.set(JAVA_CHAR.withOrder(ByteOrder.LITTLE_ENDIAN), 8, x), + (bb) -> bb.order(LE).getChar(8), (bb, v) -> bb.order(LE).putChar(8, v)) + }, + {"char/offset/BE", new Accessor<>((char) 42, + s -> s.get(JAVA_CHAR.withOrder(ByteOrder.BIG_ENDIAN), 8), + (s, x) -> s.set(JAVA_CHAR.withOrder(ByteOrder.BIG_ENDIAN), 8, x), + (bb) -> bb.order(BE).getChar(8), (bb, v) -> bb.order(BE).putChar(8, v)) + }, + // short, offset + {"short/offset", new Accessor<>((short) 42, + s -> s.get(JAVA_SHORT, 8), (s, x) -> s.set(JAVA_SHORT, 8, x), + (bb) -> bb.order(NE).getShort(8), (bb, v) -> bb.order(NE).putShort(8, v)) + }, + {"short/offset/LE", new Accessor<>((short) 42, + s -> s.get(JAVA_SHORT.withOrder(ByteOrder.LITTLE_ENDIAN), 8), + (s, x) -> s.set(JAVA_SHORT.withOrder(ByteOrder.LITTLE_ENDIAN), 8, x), + (bb) -> bb.order(LE).getShort(8), (bb, v) -> bb.order(LE).putShort(8, v)) + }, + {"short/offset/BE", new Accessor<>((short) 42, + s -> s.get(JAVA_SHORT.withOrder(ByteOrder.BIG_ENDIAN), 8), + (s, x) -> s.set(JAVA_SHORT.withOrder(ByteOrder.BIG_ENDIAN), 8, x), + (bb) -> bb.order(BE).getShort(8), (bb, v) -> bb.order(BE).putShort(8, v)) + }, + // int, offset + {"int/offset", new Accessor<>(42, + s -> s.get(JAVA_INT, 8), (s, x) -> s.set(JAVA_INT, 8, x), + (bb) -> bb.order(NE).getInt(8), (bb, v) -> bb.order(NE).putInt(8, v)) + }, + {"int/offset/LE", new Accessor<>(42, + s -> s.get(JAVA_INT.withOrder(ByteOrder.LITTLE_ENDIAN), 8), + (s, x) -> s.set(JAVA_INT.withOrder(ByteOrder.LITTLE_ENDIAN), 8, x), + (bb) -> bb.order(LE).getInt(8), (bb, v) -> bb.order(LE).putInt(8, v)) + }, + {"int/offset/BE", new Accessor<>(42, + s -> s.get(JAVA_INT.withOrder(ByteOrder.BIG_ENDIAN), 8), + (s, x) -> s.set(JAVA_INT.withOrder(ByteOrder.BIG_ENDIAN), 8, x), + (bb) -> bb.order(BE).getInt(8), (bb, v) -> bb.order(BE).putInt(8, v)) + }, + // float, offset + {"float/offset", new Accessor<>(42f, + s -> s.get(JAVA_FLOAT, 8), (s, x) -> s.set(JAVA_FLOAT, 8, x), + (bb) -> bb.order(NE).getFloat(8), (bb, v) -> bb.order(NE).putFloat(8, v)) + }, + {"float/offset/LE", new Accessor<>(42f, + s -> s.get(ValueLayout.JAVA_FLOAT.withOrder(ByteOrder.LITTLE_ENDIAN), 8), + (s, x) -> s.set(ValueLayout.JAVA_FLOAT.withOrder(ByteOrder.LITTLE_ENDIAN), 8, x), + (bb) -> bb.order(LE).getFloat(8), (bb, v) -> bb.order(LE).putFloat(8, v)) + }, + {"float/offset/BE", new Accessor<>(42f, + s -> s.get(ValueLayout.JAVA_FLOAT.withOrder(ByteOrder.BIG_ENDIAN), 8), + (s, x) -> s.set(ValueLayout.JAVA_FLOAT.withOrder(ByteOrder.BIG_ENDIAN), 8, x), + (bb) -> bb.order(BE).getFloat(8), (bb, v) -> bb.order(BE).putFloat(8, v)) + }, + // double, offset + {"double/offset", new Accessor<>(42d, + s -> s.get(JAVA_DOUBLE, 8), (s, x) -> s.set(JAVA_DOUBLE, 8, x), + (bb) -> bb.order(NE).getDouble(8), (bb, v) -> bb.order(NE).putDouble(8, v)) + }, + {"double/offset/LE", new Accessor<>(42d, + s -> s.get(ValueLayout.JAVA_DOUBLE.withOrder(ByteOrder.LITTLE_ENDIAN), 8), + (s, x) -> s.set(ValueLayout.JAVA_DOUBLE.withOrder(ByteOrder.LITTLE_ENDIAN), 8, x), + (bb) -> bb.order(LE).getDouble(8), (bb, v) -> bb.order(LE).putDouble(8, v)) + }, + {"double/offset/BE", new Accessor<>(42d, + s -> s.get(ValueLayout.JAVA_DOUBLE.withOrder(ByteOrder.BIG_ENDIAN), 8), + (s, x) -> s.set(ValueLayout.JAVA_DOUBLE.withOrder(ByteOrder.BIG_ENDIAN), 8, x), + (bb) -> bb.order(BE).getDouble(8), (bb, v) -> bb.order(BE).putDouble(8, v)) + }, + { "address/offset", new Accessor<>(MemoryAddress.ofLong(42), + s -> s.get(ADDRESS, 8), (s, x) -> s.set(ADDRESS, 8, x), + (bb) -> { + ByteBuffer nb = bb.order(NE); + long addr = ValueLayout.ADDRESS.byteSize() == 8 ? + nb.getLong(8) : nb.getInt(8); + return MemoryAddress.ofLong(addr); + }, + (bb, v) -> { + ByteBuffer nb = bb.order(NE); + if (ValueLayout.ADDRESS.byteSize() == 8) { + nb.putLong(8, v.toRawLongValue()); + } else { + nb.putInt(8, (int)v.toRawLongValue()); + } + }) + }, + }; + } +} diff --git a/test/jdk/java/foreign/TestMemoryHandleAsUnsigned.java b/test/jdk/java/foreign/TestMemoryHandleAsUnsigned.java index d4a6e536234a87f8bdb72e0ba5fa3a828068683c..71ef6fe2999ecee5f0ef9b12a4fd10e88d45afee 100644 --- a/test/jdk/java/foreign/TestMemoryHandleAsUnsigned.java +++ b/test/jdk/java/foreign/TestMemoryHandleAsUnsigned.java @@ -25,14 +25,15 @@ import jdk.incubator.foreign.MemoryHandles; import jdk.incubator.foreign.MemoryLayout; import jdk.incubator.foreign.MemoryLayout.PathElement; -import jdk.incubator.foreign.MemoryLayouts; import jdk.incubator.foreign.MemorySegment; import java.lang.invoke.VarHandle; +import java.nio.ByteOrder; import java.util.Arrays; import java.util.stream.IntStream; import java.util.stream.LongStream; import jdk.incubator.foreign.ResourceScope; +import jdk.incubator.foreign.ValueLayout; import org.testng.annotations.*; import static java.nio.ByteOrder.BIG_ENDIAN; import static org.testng.Assert.*; @@ -54,8 +55,8 @@ public class TestMemoryHandleAsUnsigned { public void testUnsignedIntToByte(int intValue) { byte byteValue = (byte) (intValue & 0xFF); - MemoryLayout layout = MemoryLayouts.BITS_8_BE; - VarHandle byteHandle = layout.varHandle(byte.class); + MemoryLayout layout = ValueLayout.JAVA_BYTE; + VarHandle byteHandle = layout.varHandle(); VarHandle intHandle = MemoryHandles.asUnsigned(byteHandle, int.class); try (ResourceScope scope = ResourceScope.newConfinedScope()) { @@ -77,8 +78,8 @@ public class TestMemoryHandleAsUnsigned { public void testUnsignedLongToByte(long longValue) { byte byteValue = (byte) (longValue & 0xFFL); - MemoryLayout layout = MemoryLayouts.BITS_8_BE; - VarHandle byteHandle = layout.varHandle(byte.class); + MemoryLayout layout = ValueLayout.JAVA_BYTE; + VarHandle byteHandle = layout.varHandle(); VarHandle longHandle = MemoryHandles.asUnsigned(byteHandle, long.class); try (ResourceScope scope = ResourceScope.newConfinedScope()) { @@ -100,8 +101,8 @@ public class TestMemoryHandleAsUnsigned { public void testUnsignedIntToShort(int intValue) { short shortValue = (short) (intValue & 0xFFFF); - MemoryLayout layout = MemoryLayouts.BITS_16_BE; - VarHandle shortHandle = layout.varHandle(short.class); + MemoryLayout layout = ValueLayout.JAVA_SHORT.withOrder(ByteOrder.BIG_ENDIAN); + VarHandle shortHandle = layout.varHandle(); VarHandle intHandle = MemoryHandles.asUnsigned(shortHandle, int.class); try (ResourceScope scope = ResourceScope.newConfinedScope()) { @@ -123,8 +124,8 @@ public class TestMemoryHandleAsUnsigned { public void testUnsignedLongToShort(long longValue) { short shortValue = (short) (longValue & 0xFFFFL); - MemoryLayout layout = MemoryLayouts.BITS_16_BE; - VarHandle shortHandle = layout.varHandle(short.class); + MemoryLayout layout = ValueLayout.JAVA_SHORT.withOrder(ByteOrder.BIG_ENDIAN); + VarHandle shortHandle = layout.varHandle(); VarHandle longHandle = MemoryHandles.asUnsigned(shortHandle, long.class); try (ResourceScope scope = ResourceScope.newConfinedScope()) { @@ -150,8 +151,8 @@ public class TestMemoryHandleAsUnsigned { public void testUnsignedLongToInt(long longValue) { int intValue = (int) (longValue & 0xFFFF_FFFFL); - MemoryLayout layout = MemoryLayouts.BITS_32_BE; - VarHandle intHandle = layout.varHandle(int.class); + MemoryLayout layout = ValueLayout.JAVA_INT.withOrder(ByteOrder.BIG_ENDIAN); + VarHandle intHandle = layout.varHandle(); VarHandle longHandle = MemoryHandles.asUnsigned(intHandle, long.class); try (ResourceScope scope = ResourceScope.newConfinedScope()) { @@ -165,8 +166,8 @@ public class TestMemoryHandleAsUnsigned { @Test public void testCoordinatesSequenceLayout() { - MemoryLayout layout = MemoryLayout.sequenceLayout(2, MemoryLayouts.BITS_8_BE); - VarHandle byteHandle = layout.varHandle(byte.class, PathElement.sequenceElement()); + MemoryLayout layout = MemoryLayout.sequenceLayout(2, ValueLayout.JAVA_BYTE); + VarHandle byteHandle = layout.varHandle(PathElement.sequenceElement()); VarHandle intHandle = MemoryHandles.asUnsigned(byteHandle, int.class); try (ResourceScope scope = ResourceScope.newConfinedScope()) { @@ -184,14 +185,14 @@ public class TestMemoryHandleAsUnsigned { MemorySegment segment = MemorySegment.ofArray(arr); { - VarHandle byteHandle = MemoryLayout.sequenceLayout(MemoryLayouts.JAVA_BYTE) - .varHandle(byte.class, PathElement.sequenceElement()); + VarHandle byteHandle = MemoryLayout.sequenceLayout(ValueLayout.JAVA_BYTE) + .varHandle(PathElement.sequenceElement()); VarHandle intHandle = MemoryHandles.asUnsigned(byteHandle, int.class); assertEquals((int) intHandle.get(segment, 2L), 129); } { - VarHandle byteHandle = MemoryLayout.sequenceLayout(MemoryLayouts.JAVA_BYTE) - .varHandle(byte.class, PathElement.sequenceElement()); + VarHandle byteHandle = MemoryLayout.sequenceLayout(ValueLayout.JAVA_BYTE) + .varHandle(PathElement.sequenceElement()); VarHandle intHandle = MemoryHandles.asUnsigned(byteHandle, int.class); assertEquals((int) intHandle.get(segment, 2L), 129); } @@ -201,7 +202,7 @@ public class TestMemoryHandleAsUnsigned { @Test public void testNull() { - VarHandle handle = MemoryHandles.varHandle(byte.class, BIG_ENDIAN); + VarHandle handle = MemoryHandles.varHandle(ValueLayout.JAVA_BYTE.withOrder(BIG_ENDIAN)); assertThrows(NPE, () -> MemoryHandles.asUnsigned(handle, null)); assertThrows(NPE, () -> MemoryHandles.asUnsigned(null, short.class)); assertThrows(NPE, () -> MemoryHandles.asUnsigned(null, null)); @@ -209,22 +210,22 @@ public class TestMemoryHandleAsUnsigned { static final Class<IllegalArgumentException> IAE = IllegalArgumentException.class; - static void assertIllegalArgumentExceptionIllegalCarrier(Class<?> carrier, Class<?> adaptedType) { - var vh = MemoryHandles.varHandle(carrier, BIG_ENDIAN); + static void assertIllegalArgumentExceptionIllegalCarrier(ValueLayout layout, Class<?> adaptedType) { + var vh = MemoryHandles.varHandle(layout.withOrder(BIG_ENDIAN)); var exception = expectThrows(IAE, () -> MemoryHandles.asUnsigned(vh, adaptedType)); var msg = exception.getMessage(); assertTrue(msg.contains("illegal carrier"), "Expected \"illegal carrier\" in:[" + msg +"]"); } - static void assertIllegalArgumentExceptionIllegalAdapter(Class<?> carrier, Class<?> adaptedType) { - var vh = MemoryHandles.varHandle(carrier, BIG_ENDIAN); + static void assertIllegalArgumentExceptionIllegalAdapter(ValueLayout layout, Class<?> adaptedType) { + var vh = MemoryHandles.varHandle(layout.withOrder(BIG_ENDIAN)); var exception = expectThrows(IAE, () -> MemoryHandles.asUnsigned(vh, adaptedType)); var msg = exception.getMessage(); assertTrue(msg.contains("illegal adapter type"), "Expected \"illegal adapter type\" in:[" + msg +"]"); } - static void assertIllegalArgumentExceptionIsNotWiderThan(Class<?> carrier, Class<?> adaptedType) { - var vh = MemoryHandles.varHandle(carrier, BIG_ENDIAN); + static void assertIllegalArgumentExceptionIsNotWiderThan(ValueLayout layout, Class<?> adaptedType) { + var vh = MemoryHandles.varHandle(layout.withOrder(BIG_ENDIAN)); var exception = expectThrows(IAE, () -> MemoryHandles.asUnsigned(vh, adaptedType)); var msg = exception.getMessage(); assertTrue(msg.contains("is not wider than"), "Expected \"is not wider than\" in:[" + msg +"]"); @@ -232,25 +233,25 @@ public class TestMemoryHandleAsUnsigned { @Test public void testIllegalArgumentException() { - assertIllegalArgumentExceptionIllegalCarrier(char.class, long.class); - assertIllegalArgumentExceptionIllegalCarrier(double.class, long.class); - assertIllegalArgumentExceptionIllegalCarrier(float.class, long.class); - assertIllegalArgumentExceptionIllegalCarrier(long.class, long.class); - - assertIllegalArgumentExceptionIllegalAdapter(byte.class, void.class); - assertIllegalArgumentExceptionIllegalAdapter(byte.class, byte.class); - assertIllegalArgumentExceptionIllegalAdapter(byte.class, short.class); - assertIllegalArgumentExceptionIllegalAdapter(byte.class, char.class); - assertIllegalArgumentExceptionIllegalAdapter(byte.class, double.class); - assertIllegalArgumentExceptionIllegalAdapter(byte.class, float.class); - assertIllegalArgumentExceptionIllegalAdapter(byte.class, Object.class); - assertIllegalArgumentExceptionIllegalAdapter(byte.class, Integer.class); - assertIllegalArgumentExceptionIllegalAdapter(byte.class, Long.class); - assertIllegalArgumentExceptionIllegalAdapter(byte.class, long[].class); - assertIllegalArgumentExceptionIllegalAdapter(byte.class, int[].class); - assertIllegalArgumentExceptionIllegalAdapter(byte.class, Integer[].class); - assertIllegalArgumentExceptionIllegalAdapter(byte.class, Long[].class); - - assertIllegalArgumentExceptionIsNotWiderThan(int.class, int.class); + assertIllegalArgumentExceptionIllegalCarrier(ValueLayout.JAVA_CHAR, long.class); + assertIllegalArgumentExceptionIllegalCarrier(ValueLayout.JAVA_DOUBLE, long.class); + assertIllegalArgumentExceptionIllegalCarrier(ValueLayout.JAVA_FLOAT, long.class); + assertIllegalArgumentExceptionIllegalCarrier(ValueLayout.JAVA_LONG, long.class); + + assertIllegalArgumentExceptionIllegalAdapter(ValueLayout.JAVA_BYTE, void.class); + assertIllegalArgumentExceptionIllegalAdapter(ValueLayout.JAVA_BYTE, byte.class); + assertIllegalArgumentExceptionIllegalAdapter(ValueLayout.JAVA_BYTE, short.class); + assertIllegalArgumentExceptionIllegalAdapter(ValueLayout.JAVA_BYTE, char.class); + assertIllegalArgumentExceptionIllegalAdapter(ValueLayout.JAVA_BYTE, double.class); + assertIllegalArgumentExceptionIllegalAdapter(ValueLayout.JAVA_BYTE, float.class); + assertIllegalArgumentExceptionIllegalAdapter(ValueLayout.JAVA_BYTE, Object.class); + assertIllegalArgumentExceptionIllegalAdapter(ValueLayout.JAVA_BYTE, Integer.class); + assertIllegalArgumentExceptionIllegalAdapter(ValueLayout.JAVA_BYTE, Long.class); + assertIllegalArgumentExceptionIllegalAdapter(ValueLayout.JAVA_BYTE, long[].class); + assertIllegalArgumentExceptionIllegalAdapter(ValueLayout.JAVA_BYTE, int[].class); + assertIllegalArgumentExceptionIllegalAdapter(ValueLayout.JAVA_BYTE, Integer[].class); + assertIllegalArgumentExceptionIllegalAdapter(ValueLayout.JAVA_BYTE, Long[].class); + + assertIllegalArgumentExceptionIsNotWiderThan(ValueLayout.JAVA_INT, int.class); } } diff --git a/test/jdk/java/foreign/TestMismatch.java b/test/jdk/java/foreign/TestMismatch.java index 5f4dd4c3195c31fed7df8abe96714dc6244b49aa..a399a20d9b82bb6a3a1ea66f7a3864798bd1336b 100644 --- a/test/jdk/java/foreign/TestMismatch.java +++ b/test/jdk/java/foreign/TestMismatch.java @@ -32,9 +32,9 @@ import java.util.List; import java.util.concurrent.atomic.AtomicReference; import java.util.function.IntFunction; -import jdk.incubator.foreign.MemoryLayouts; import jdk.incubator.foreign.MemorySegment; import jdk.incubator.foreign.ResourceScope; +import jdk.incubator.foreign.ValueLayout; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import static java.lang.System.out; @@ -43,7 +43,7 @@ import static org.testng.Assert.assertThrows; public class TestMismatch { - final static VarHandle BYTE_HANDLE = MemoryLayouts.JAVA_BYTE.varHandle(byte.class); + final static VarHandle BYTE_HANDLE = ValueLayout.JAVA_BYTE.varHandle(); // stores a increasing sequence of values into the memory of the given segment static MemorySegment initializeSegment(MemorySegment segment) { @@ -112,7 +112,7 @@ public class TestMismatch { @Test public void testLarge() { // skip if not on 64 bits - if (MemoryLayouts.ADDRESS.byteSize() > 32) { + if (ValueLayout.ADDRESS.byteSize() > 32) { try (ResourceScope scope = ResourceScope.newConfinedScope()) { var s1 = MemorySegment.allocateNative((long) Integer.MAX_VALUE + 10L, 8, scope); var s2 = MemorySegment.allocateNative((long) Integer.MAX_VALUE + 10L, 8, scope); diff --git a/test/jdk/java/foreign/TestNULLAddress.java b/test/jdk/java/foreign/TestNULLAddress.java index 7ea4cbb974faa3cd59c7d7a467c5f6b8f298c47f..14aec5fb757665e3e88a5c855e6cb772481b1697 100644 --- a/test/jdk/java/foreign/TestNULLAddress.java +++ b/test/jdk/java/foreign/TestNULLAddress.java @@ -34,39 +34,37 @@ import jdk.incubator.foreign.Addressable; import jdk.incubator.foreign.CLinker; import jdk.incubator.foreign.FunctionDescriptor; import jdk.incubator.foreign.MemoryAddress; +import jdk.incubator.foreign.NativeSymbol; +import jdk.incubator.foreign.ResourceScope; import org.testng.annotations.Test; import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodType; -import java.nio.charset.Charset; public class TestNULLAddress { - static final CLinker LINKER = CLinker.getInstance(); + static final CLinker LINKER = CLinker.systemCLinker(); @Test(expectedExceptions = IllegalArgumentException.class) public void testNULLLinking() { LINKER.downcallHandle( - MemoryAddress.NULL, - MethodType.methodType(void.class), + NativeSymbol.ofAddress("nullAddress", MemoryAddress.NULL, ResourceScope.globalScope()), FunctionDescriptor.ofVoid()); } @Test(expectedExceptions = IllegalArgumentException.class) public void testNULLVirtual() throws Throwable { MethodHandle mh = LINKER.downcallHandle( - MethodType.methodType(void.class), FunctionDescriptor.ofVoid()); - mh.invokeExact((Addressable) MemoryAddress.NULL); + mh.invokeExact(NativeSymbol.ofAddress("null", MemoryAddress.NULL, ResourceScope.globalScope())); } @Test(expectedExceptions = IllegalArgumentException.class) - public void testNULLtoJavaString() { - CLinker.toJavaString(MemoryAddress.NULL); + public void testNULLgetString() { + MemoryAddress.NULL.getUtf8String(0); } @Test(expectedExceptions = IllegalArgumentException.class) - public void testNULLfreeMemory() { - CLinker.freeMemory(MemoryAddress.NULL); + public void testNULLsetString() { + MemoryAddress.NULL.setUtf8String(0, "hello"); } } diff --git a/test/jdk/java/foreign/TestNative.java b/test/jdk/java/foreign/TestNative.java index 443c13b11d5060e2e6a7568c0123f51193538249..0b6a6cdfb8d3719e280ef2e557bc2b6d37535bfc 100644 --- a/test/jdk/java/foreign/TestNative.java +++ b/test/jdk/java/foreign/TestNative.java @@ -29,15 +29,13 @@ * @run testng/othervm --enable-native-access=ALL-UNNAMED TestNative */ -import jdk.incubator.foreign.CLinker; -import jdk.incubator.foreign.MemoryAccess; import jdk.incubator.foreign.MemoryAddress; import jdk.incubator.foreign.MemoryLayout; import jdk.incubator.foreign.MemoryLayout.PathElement; -import jdk.incubator.foreign.MemoryLayouts; import jdk.incubator.foreign.MemorySegment; import jdk.incubator.foreign.ResourceScope; import jdk.incubator.foreign.SequenceLayout; +import jdk.incubator.foreign.ValueLayout; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; @@ -56,45 +54,46 @@ import java.util.function.BiFunction; import java.util.function.Consumer; import java.util.function.Function; +import static jdk.incubator.foreign.ValueLayout.JAVA_INT; import static org.testng.Assert.*; -public class TestNative { +public class TestNative extends NativeTestHelper { static SequenceLayout bytes = MemoryLayout.sequenceLayout(100, - MemoryLayouts.JAVA_BYTE.withOrder(ByteOrder.nativeOrder()) + ValueLayout.JAVA_BYTE.withOrder(ByteOrder.nativeOrder()) ); static SequenceLayout chars = MemoryLayout.sequenceLayout(100, - MemoryLayouts.JAVA_CHAR.withOrder(ByteOrder.nativeOrder()) + ValueLayout.JAVA_CHAR.withOrder(ByteOrder.nativeOrder()) ); static SequenceLayout shorts = MemoryLayout.sequenceLayout(100, - MemoryLayouts.JAVA_SHORT.withOrder(ByteOrder.nativeOrder()) + ValueLayout.JAVA_SHORT.withOrder(ByteOrder.nativeOrder()) ); static SequenceLayout ints = MemoryLayout.sequenceLayout(100, - MemoryLayouts.JAVA_INT.withOrder(ByteOrder.nativeOrder()) + JAVA_INT.withOrder(ByteOrder.nativeOrder()) ); static SequenceLayout floats = MemoryLayout.sequenceLayout(100, - MemoryLayouts.JAVA_FLOAT.withOrder(ByteOrder.nativeOrder()) + ValueLayout.JAVA_FLOAT.withOrder(ByteOrder.nativeOrder()) ); static SequenceLayout longs = MemoryLayout.sequenceLayout(100, - MemoryLayouts.JAVA_LONG.withOrder(ByteOrder.nativeOrder()) + ValueLayout.JAVA_LONG.withOrder(ByteOrder.nativeOrder()) ); static SequenceLayout doubles = MemoryLayout.sequenceLayout(100, - MemoryLayouts.JAVA_DOUBLE.withOrder(ByteOrder.nativeOrder()) + ValueLayout.JAVA_DOUBLE.withOrder(ByteOrder.nativeOrder()) ); - static VarHandle byteHandle = bytes.varHandle(byte.class, PathElement.sequenceElement()); - static VarHandle charHandle = chars.varHandle(char.class, PathElement.sequenceElement()); - static VarHandle shortHandle = shorts.varHandle(short.class, PathElement.sequenceElement()); - static VarHandle intHandle = ints.varHandle(int.class, PathElement.sequenceElement()); - static VarHandle floatHandle = floats.varHandle(float.class, PathElement.sequenceElement()); - static VarHandle longHandle = doubles.varHandle(long.class, PathElement.sequenceElement()); - static VarHandle doubleHandle = longs.varHandle(double.class, PathElement.sequenceElement()); + static VarHandle byteHandle = bytes.varHandle(PathElement.sequenceElement()); + static VarHandle charHandle = chars.varHandle(PathElement.sequenceElement()); + static VarHandle shortHandle = shorts.varHandle(PathElement.sequenceElement()); + static VarHandle intHandle = ints.varHandle(PathElement.sequenceElement()); + static VarHandle floatHandle = floats.varHandle(PathElement.sequenceElement()); + static VarHandle longHandle = longs.varHandle(PathElement.sequenceElement()); + static VarHandle doubleHandle = doubles.varHandle(PathElement.sequenceElement()); static void initBytes(MemorySegment base, SequenceLayout seq, BiConsumer<MemorySegment, Long> handleSetter) { for (long i = 0; i < seq.elementCount().getAsLong() ; i++) { @@ -144,14 +143,6 @@ public class TestNative { public static native long getCapacity(Buffer buffer); - public static MemoryAddress allocate(int size) { - return CLinker.allocateMemory(size); - } - - public static void free(MemoryAddress addr) { - CLinker.freeMemory(addr); - } - @Test(dataProvider="nativeAccessOps") public void testNativeAccess(Consumer<MemorySegment> checker, Consumer<MemorySegment> initializer, SequenceLayout seq) { try (ResourceScope scope = ResourceScope.newConfinedScope()) { @@ -176,25 +167,21 @@ public class TestNative { @Test public void testDefaultAccessModes() { - MemoryAddress addr = allocate(12); + MemoryAddress addr = allocateMemory(12); try (ResourceScope scope = ResourceScope.newConfinedScope()) { - MemorySegment mallocSegment = addr.asSegment(12, () -> free(addr), scope); + scope.addCloseAction(() -> freeMemory(addr)); + MemorySegment mallocSegment = MemorySegment.ofAddress(addr, 12, scope); assertFalse(mallocSegment.isReadOnly()); } } - @Test - public void testDefaultAccessModesEverthing() { - MemorySegment everything = MemorySegment.globalNativeSegment(); - assertFalse(everything.isReadOnly()); - } - @Test public void testMallocSegment() { - MemoryAddress addr = allocate(12); + MemoryAddress addr = allocateMemory(12); MemorySegment mallocSegment = null; try (ResourceScope scope = ResourceScope.newConfinedScope()) { - mallocSegment = addr.asSegment(12, () -> free(addr), scope); + scope.addCloseAction(() -> freeMemory(addr)); + mallocSegment = MemorySegment.ofAddress(addr, 12, scope); assertEquals(mallocSegment.byteSize(), 12); //free here } @@ -202,19 +189,18 @@ public class TestNative { } @Test - public void testEverythingSegment() { - MemoryAddress addr = allocate(4); - MemorySegment everything = MemorySegment.globalNativeSegment(); - MemoryAccess.setIntAtOffset(everything, addr.toRawLongValue(), 42); - assertEquals(MemoryAccess.getIntAtOffset(everything, addr.toRawLongValue()), 42); - free(addr); + public void testAddressAccess() { + MemoryAddress addr = allocateMemory(4); + addr.set(JAVA_INT, 0, 42); + assertEquals(addr.get(JAVA_INT, 0), 42); + freeMemory(addr); } @Test(expectedExceptions = IllegalArgumentException.class) public void testBadResize() { try (ResourceScope scope = ResourceScope.newConfinedScope()) { MemorySegment segment = MemorySegment.allocateNative(4, 1, scope); - segment.address().asSegment(0, ResourceScope.globalScope()); + MemorySegment.ofAddress(segment.address(), 0, ResourceScope.globalScope()); } } diff --git a/test/jdk/java/foreign/TestNoForeignUnsafeOverride.java b/test/jdk/java/foreign/TestNoForeignUnsafeOverride.java index ac47ea3113f051b50f575e6ca725e1e641eef7fe..d5aa76dc5413a73e1db1bb9200bd98d78f0f4178 100644 --- a/test/jdk/java/foreign/TestNoForeignUnsafeOverride.java +++ b/test/jdk/java/foreign/TestNoForeignUnsafeOverride.java @@ -28,7 +28,7 @@ import jdk.incubator.foreign.*; public class PanamaMain { public static void main(String[] args) { System.out.println("Trying to get CLinker"); - CLinker.getInstance(); + CLinker.systemCLinker(); System.out.println("Got CLinker"); } } diff --git a/test/jdk/java/foreign/TestNulls.java b/test/jdk/java/foreign/TestNulls.java index ccb27a61d35d5af741f977f642d96346bce0e2ca..7f57108b5d2a68078e241dc54d8d3687575c6a09 100644 --- a/test/jdk/java/foreign/TestNulls.java +++ b/test/jdk/java/foreign/TestNulls.java @@ -60,6 +60,8 @@ import java.util.function.UnaryOperator; import java.util.stream.Collectors; import java.util.stream.Stream; +import static jdk.incubator.foreign.ValueLayout.JAVA_INT; +import static jdk.incubator.foreign.ValueLayout.JAVA_LONG; import static org.testng.Assert.*; import static org.testng.Assert.fail; @@ -82,27 +84,43 @@ public class TestNulls { MemoryLayout.PathElement.class, SequenceLayout.class, ValueLayout.class, + ValueLayout.OfBoolean.class, + ValueLayout.OfByte.class, + ValueLayout.OfChar.class, + ValueLayout.OfShort.class, + ValueLayout.OfInt.class, + ValueLayout.OfFloat.class, + ValueLayout.OfLong.class, + ValueLayout.OfDouble.class, + ValueLayout.OfAddress.class, GroupLayout.class, Addressable.class, SymbolLookup.class, - MemoryAccess.class, - MemoryLayouts.class, MemoryHandles.class, CLinker.class, - CLinker.VaList.class, - CLinker.VaList.Builder.class, + VaList.class, + VaList.Builder.class, FunctionDescriptor.class, SegmentAllocator.class, - ResourceScope.class + ResourceScope.class, + NativeSymbol.class }; static final Set<String> EXCLUDE_LIST = Set.of( + "jdk.incubator.foreign.ResourceScope/newConfinedScope(java.lang.ref.Cleaner)/0/0", + "jdk.incubator.foreign.ResourceScope/newSharedScope(java.lang.ref.Cleaner)/0/0", "jdk.incubator.foreign.MemoryLayout/withAttribute(java.lang.String,java.lang.constant.Constable)/1/0", - "jdk.incubator.foreign.MemoryAddress/asSegment(long,java.lang.Runnable,java.lang.Object)/1/0", - "jdk.incubator.foreign.MemoryAddress/asSegment(long,java.lang.Runnable,java.lang.Object)/2/0", - "jdk.incubator.foreign.MemoryAddress/asSegment(long,java.lang.Runnable,jdk.incubator.foreign.ResourceScope)/1/0", "jdk.incubator.foreign.SequenceLayout/withAttribute(java.lang.String,java.lang.constant.Constable)/1/0", "jdk.incubator.foreign.ValueLayout/withAttribute(java.lang.String,java.lang.constant.Constable)/1/0", + "jdk.incubator.foreign.ValueLayout$OfAddress/withAttribute(java.lang.String,java.lang.constant.Constable)/1/0", + "jdk.incubator.foreign.ValueLayout$OfBoolean/withAttribute(java.lang.String,java.lang.constant.Constable)/1/0", + "jdk.incubator.foreign.ValueLayout$OfByte/withAttribute(java.lang.String,java.lang.constant.Constable)/1/0", + "jdk.incubator.foreign.ValueLayout$OfChar/withAttribute(java.lang.String,java.lang.constant.Constable)/1/0", + "jdk.incubator.foreign.ValueLayout$OfShort/withAttribute(java.lang.String,java.lang.constant.Constable)/1/0", + "jdk.incubator.foreign.ValueLayout$OfInt/withAttribute(java.lang.String,java.lang.constant.Constable)/1/0", + "jdk.incubator.foreign.ValueLayout$OfFloat/withAttribute(java.lang.String,java.lang.constant.Constable)/1/0", + "jdk.incubator.foreign.ValueLayout$OfLong/withAttribute(java.lang.String,java.lang.constant.Constable)/1/0", + "jdk.incubator.foreign.ValueLayout$OfDouble/withAttribute(java.lang.String,java.lang.constant.Constable)/1/0", "jdk.incubator.foreign.GroupLayout/withAttribute(java.lang.String,java.lang.constant.Constable)/1/0", "jdk.incubator.foreign.MemoryHandles/insertCoordinates(java.lang.invoke.VarHandle,int,java.lang.Object[])/2/1", "jdk.incubator.foreign.FunctionDescriptor/withAttribute(java.lang.String,java.lang.constant.Constable)/1/0" @@ -139,7 +157,7 @@ public class TestNulls { addDefaultMapping(Class.class, String.class); addDefaultMapping(Runnable.class, () -> {}); addDefaultMapping(Object.class, new Object()); - addDefaultMapping(VarHandle.class, MemoryHandles.varHandle(int.class, ByteOrder.nativeOrder())); + addDefaultMapping(VarHandle.class, MemoryHandles.varHandle(JAVA_INT)); addDefaultMapping(MethodHandle.class, MethodHandles.identity(int.class)); addDefaultMapping(List.class, List.of()); addDefaultMapping(Charset.class, Charset.defaultCharset()); @@ -147,32 +165,41 @@ public class TestNulls { addDefaultMapping(MethodType.class, MethodType.methodType(void.class)); addDefaultMapping(MemoryAddress.class, MemoryAddress.ofLong(1)); addDefaultMapping(Addressable.class, MemoryAddress.ofLong(1)); - addDefaultMapping(MemoryLayout.class, MemoryLayouts.JAVA_INT); - addDefaultMapping(ValueLayout.class, MemoryLayouts.JAVA_INT); - addDefaultMapping(GroupLayout.class, MemoryLayout.structLayout(MemoryLayouts.JAVA_INT)); - addDefaultMapping(SequenceLayout.class, MemoryLayout.sequenceLayout(MemoryLayouts.JAVA_INT)); + addDefaultMapping(MemoryLayout.class, ValueLayout.JAVA_INT); + addDefaultMapping(ValueLayout.class, ValueLayout.JAVA_INT); + addDefaultMapping(ValueLayout.OfAddress.class, ValueLayout.ADDRESS); + addDefaultMapping(ValueLayout.OfByte.class, ValueLayout.JAVA_BYTE); + addDefaultMapping(ValueLayout.OfBoolean.class, ValueLayout.JAVA_BOOLEAN); + addDefaultMapping(ValueLayout.OfChar.class, ValueLayout.JAVA_CHAR); + addDefaultMapping(ValueLayout.OfShort.class, ValueLayout.JAVA_SHORT); + addDefaultMapping(ValueLayout.OfInt.class, ValueLayout.JAVA_INT); + addDefaultMapping(ValueLayout.OfFloat.class, ValueLayout.JAVA_FLOAT); + addDefaultMapping(ValueLayout.OfLong.class, JAVA_LONG); + addDefaultMapping(ValueLayout.OfDouble.class, ValueLayout.JAVA_DOUBLE); + addDefaultMapping(GroupLayout.class, MemoryLayout.structLayout(ValueLayout.JAVA_INT)); + addDefaultMapping(SequenceLayout.class, MemoryLayout.sequenceLayout(ValueLayout.JAVA_INT)); addDefaultMapping(MemorySegment.class, MemorySegment.ofArray(new byte[10])); addDefaultMapping(FunctionDescriptor.class, FunctionDescriptor.ofVoid()); - addDefaultMapping(CLinker.class, CLinker.getInstance()); - addDefaultMapping(CLinker.VaList.class, VaListHelper.vaList); - addDefaultMapping(CLinker.VaList.Builder.class, VaListHelper.vaListBuilder); - addDefaultMapping(ResourceScope.class, ResourceScope.newImplicitScope()); - addDefaultMapping(SegmentAllocator.class, (size, align) -> null); + addDefaultMapping(CLinker.class, CLinker.systemCLinker()); + addDefaultMapping(VaList.class, VaListHelper.vaList); + addDefaultMapping(VaList.Builder.class, VaListHelper.vaListBuilder); + addDefaultMapping(ResourceScope.class, ResourceScope.newSharedScope()); + addDefaultMapping(SegmentAllocator.class, SegmentAllocator.prefixAllocator(MemorySegment.ofArray(new byte[10]))); addDefaultMapping(Supplier.class, () -> null); - addDefaultMapping(ResourceScope.Handle.class, ResourceScope.globalScope().acquire()); addDefaultMapping(ClassLoader.class, TestNulls.class.getClassLoader()); - addDefaultMapping(SymbolLookup.class, CLinker.systemLookup()); + addDefaultMapping(SymbolLookup.class, CLinker.systemCLinker()); + addDefaultMapping(NativeSymbol.class, NativeSymbol.ofAddress("dummy", MemoryAddress.ofLong(1), ResourceScope.globalScope())); } static class VaListHelper { - static final CLinker.VaList vaList; - static final CLinker.VaList.Builder vaListBuilder; + static final VaList vaList; + static final VaList.Builder vaListBuilder; static { - AtomicReference<CLinker.VaList.Builder> builderRef = new AtomicReference<>(); - vaList = CLinker.VaList.make(b -> { + AtomicReference<VaList.Builder> builderRef = new AtomicReference<>(); + vaList = VaList.make(b -> { builderRef.set(b); - b.vargFromLong(CLinker.C_LONG_LONG, 42L); + b.addVarg(JAVA_LONG, 42L); }, ResourceScope.newImplicitScope()); vaListBuilder = builderRef.get(); } diff --git a/test/jdk/java/foreign/TestReshape.java b/test/jdk/java/foreign/TestReshape.java index dc53e83ee0f09d9dcaaf8af9f19096f186221a84..4fcfb5eb2103e0cf2c41b519522fe99781dadf63 100644 --- a/test/jdk/java/foreign/TestReshape.java +++ b/test/jdk/java/foreign/TestReshape.java @@ -27,7 +27,6 @@ */ import jdk.incubator.foreign.MemoryLayout; -import jdk.incubator.foreign.MemoryLayouts; import jdk.incubator.foreign.SequenceLayout; import java.util.ArrayList; @@ -35,6 +34,7 @@ import java.util.Iterator; import java.util.List; import java.util.stream.LongStream; +import jdk.incubator.foreign.ValueLayout; import org.testng.annotations.*; import static org.testng.Assert.*; @@ -54,43 +54,43 @@ public class TestReshape { @Test(expectedExceptions = IllegalArgumentException.class) public void testInvalidReshape() { - SequenceLayout seq = MemoryLayout.sequenceLayout(4, MemoryLayouts.JAVA_INT); + SequenceLayout seq = MemoryLayout.sequenceLayout(4, ValueLayout.JAVA_INT); seq.reshape(3, 2); } @Test(expectedExceptions = IllegalArgumentException.class) public void testBadReshapeInference() { - SequenceLayout seq = MemoryLayout.sequenceLayout(4, MemoryLayouts.JAVA_INT); + SequenceLayout seq = MemoryLayout.sequenceLayout(4, ValueLayout.JAVA_INT); seq.reshape(-1, -1); } @Test(expectedExceptions = IllegalArgumentException.class) public void testBadReshapeParameterZero() { - SequenceLayout seq = MemoryLayout.sequenceLayout(4, MemoryLayouts.JAVA_INT); + SequenceLayout seq = MemoryLayout.sequenceLayout(4, ValueLayout.JAVA_INT); seq.reshape(0, 4); } @Test(expectedExceptions = IllegalArgumentException.class) public void testBadReshapeParameterNegative() { - SequenceLayout seq = MemoryLayout.sequenceLayout(4, MemoryLayouts.JAVA_INT); + SequenceLayout seq = MemoryLayout.sequenceLayout(4, ValueLayout.JAVA_INT); seq.reshape(-2, 2); } @Test(expectedExceptions = UnsupportedOperationException.class) public void testReshapeOnUnboundSequence() { - SequenceLayout seq = MemoryLayout.sequenceLayout(MemoryLayouts.JAVA_INT); + SequenceLayout seq = MemoryLayout.sequenceLayout(ValueLayout.JAVA_INT); seq.reshape(3, 2); } @Test(expectedExceptions = UnsupportedOperationException.class) public void testFlattenOnUnboundSequence() { - SequenceLayout seq = MemoryLayout.sequenceLayout(MemoryLayouts.JAVA_INT); + SequenceLayout seq = MemoryLayout.sequenceLayout(ValueLayout.JAVA_INT); seq.flatten(); } @Test(expectedExceptions = UnsupportedOperationException.class) public void testFlattenOnUnboundNestedSequence() { - SequenceLayout seq = MemoryLayout.sequenceLayout(4, MemoryLayout.sequenceLayout(MemoryLayouts.JAVA_INT)); + SequenceLayout seq = MemoryLayout.sequenceLayout(4, MemoryLayout.sequenceLayout(ValueLayout.JAVA_INT)); seq.flatten(); } @@ -125,61 +125,61 @@ public class TestReshape { } static MemoryLayout POINT = MemoryLayout.structLayout( - MemoryLayouts.JAVA_INT, - MemoryLayouts.JAVA_INT + ValueLayout.JAVA_INT, + ValueLayout.JAVA_INT ); @DataProvider(name = "shapes") Object[][] shapes() { return new Object[][] { - { MemoryLayouts.JAVA_BYTE, new long[] { 256 } }, - { MemoryLayouts.JAVA_BYTE, new long[] { 16, 16 } }, - { MemoryLayouts.JAVA_BYTE, new long[] { 4, 4, 4, 4 } }, - { MemoryLayouts.JAVA_BYTE, new long[] { 2, 8, 16 } }, - { MemoryLayouts.JAVA_BYTE, new long[] { 16, 8, 2 } }, - { MemoryLayouts.JAVA_BYTE, new long[] { 8, 16, 2 } }, - - { MemoryLayouts.JAVA_SHORT, new long[] { 256 } }, - { MemoryLayouts.JAVA_SHORT, new long[] { 16, 16 } }, - { MemoryLayouts.JAVA_SHORT, new long[] { 4, 4, 4, 4 } }, - { MemoryLayouts.JAVA_SHORT, new long[] { 2, 8, 16 } }, - { MemoryLayouts.JAVA_SHORT, new long[] { 16, 8, 2 } }, - { MemoryLayouts.JAVA_SHORT, new long[] { 8, 16, 2 } }, - - { MemoryLayouts.JAVA_CHAR, new long[] { 256 } }, - { MemoryLayouts.JAVA_CHAR, new long[] { 16, 16 } }, - { MemoryLayouts.JAVA_CHAR, new long[] { 4, 4, 4, 4 } }, - { MemoryLayouts.JAVA_CHAR, new long[] { 2, 8, 16 } }, - { MemoryLayouts.JAVA_CHAR, new long[] { 16, 8, 2 } }, - { MemoryLayouts.JAVA_CHAR, new long[] { 8, 16, 2 } }, - - { MemoryLayouts.JAVA_INT, new long[] { 256 } }, - { MemoryLayouts.JAVA_INT, new long[] { 16, 16 } }, - { MemoryLayouts.JAVA_INT, new long[] { 4, 4, 4, 4 } }, - { MemoryLayouts.JAVA_INT, new long[] { 2, 8, 16 } }, - { MemoryLayouts.JAVA_INT, new long[] { 16, 8, 2 } }, - { MemoryLayouts.JAVA_INT, new long[] { 8, 16, 2 } }, - - { MemoryLayouts.JAVA_LONG, new long[] { 256 } }, - { MemoryLayouts.JAVA_LONG, new long[] { 16, 16 } }, - { MemoryLayouts.JAVA_LONG, new long[] { 4, 4, 4, 4 } }, - { MemoryLayouts.JAVA_LONG, new long[] { 2, 8, 16 } }, - { MemoryLayouts.JAVA_LONG, new long[] { 16, 8, 2 } }, - { MemoryLayouts.JAVA_LONG, new long[] { 8, 16, 2 } }, - - { MemoryLayouts.JAVA_FLOAT, new long[] { 256 } }, - { MemoryLayouts.JAVA_FLOAT, new long[] { 16, 16 } }, - { MemoryLayouts.JAVA_FLOAT, new long[] { 4, 4, 4, 4 } }, - { MemoryLayouts.JAVA_FLOAT, new long[] { 2, 8, 16 } }, - { MemoryLayouts.JAVA_FLOAT, new long[] { 16, 8, 2 } }, - { MemoryLayouts.JAVA_FLOAT, new long[] { 8, 16, 2 } }, - - { MemoryLayouts.JAVA_DOUBLE, new long[] { 256 } }, - { MemoryLayouts.JAVA_DOUBLE, new long[] { 16, 16 } }, - { MemoryLayouts.JAVA_DOUBLE, new long[] { 4, 4, 4, 4 } }, - { MemoryLayouts.JAVA_DOUBLE, new long[] { 2, 8, 16 } }, - { MemoryLayouts.JAVA_DOUBLE, new long[] { 16, 8, 2 } }, - { MemoryLayouts.JAVA_DOUBLE, new long[] { 8, 16, 2 } }, + { ValueLayout.JAVA_BYTE, new long[] { 256 } }, + { ValueLayout.JAVA_BYTE, new long[] { 16, 16 } }, + { ValueLayout.JAVA_BYTE, new long[] { 4, 4, 4, 4 } }, + { ValueLayout.JAVA_BYTE, new long[] { 2, 8, 16 } }, + { ValueLayout.JAVA_BYTE, new long[] { 16, 8, 2 } }, + { ValueLayout.JAVA_BYTE, new long[] { 8, 16, 2 } }, + + { ValueLayout.JAVA_SHORT, new long[] { 256 } }, + { ValueLayout.JAVA_SHORT, new long[] { 16, 16 } }, + { ValueLayout.JAVA_SHORT, new long[] { 4, 4, 4, 4 } }, + { ValueLayout.JAVA_SHORT, new long[] { 2, 8, 16 } }, + { ValueLayout.JAVA_SHORT, new long[] { 16, 8, 2 } }, + { ValueLayout.JAVA_SHORT, new long[] { 8, 16, 2 } }, + + { ValueLayout.JAVA_CHAR, new long[] { 256 } }, + { ValueLayout.JAVA_CHAR, new long[] { 16, 16 } }, + { ValueLayout.JAVA_CHAR, new long[] { 4, 4, 4, 4 } }, + { ValueLayout.JAVA_CHAR, new long[] { 2, 8, 16 } }, + { ValueLayout.JAVA_CHAR, new long[] { 16, 8, 2 } }, + { ValueLayout.JAVA_CHAR, new long[] { 8, 16, 2 } }, + + { ValueLayout.JAVA_INT, new long[] { 256 } }, + { ValueLayout.JAVA_INT, new long[] { 16, 16 } }, + { ValueLayout.JAVA_INT, new long[] { 4, 4, 4, 4 } }, + { ValueLayout.JAVA_INT, new long[] { 2, 8, 16 } }, + { ValueLayout.JAVA_INT, new long[] { 16, 8, 2 } }, + { ValueLayout.JAVA_INT, new long[] { 8, 16, 2 } }, + + { ValueLayout.JAVA_LONG, new long[] { 256 } }, + { ValueLayout.JAVA_LONG, new long[] { 16, 16 } }, + { ValueLayout.JAVA_LONG, new long[] { 4, 4, 4, 4 } }, + { ValueLayout.JAVA_LONG, new long[] { 2, 8, 16 } }, + { ValueLayout.JAVA_LONG, new long[] { 16, 8, 2 } }, + { ValueLayout.JAVA_LONG, new long[] { 8, 16, 2 } }, + + { ValueLayout.JAVA_FLOAT, new long[] { 256 } }, + { ValueLayout.JAVA_FLOAT, new long[] { 16, 16 } }, + { ValueLayout.JAVA_FLOAT, new long[] { 4, 4, 4, 4 } }, + { ValueLayout.JAVA_FLOAT, new long[] { 2, 8, 16 } }, + { ValueLayout.JAVA_FLOAT, new long[] { 16, 8, 2 } }, + { ValueLayout.JAVA_FLOAT, new long[] { 8, 16, 2 } }, + + { ValueLayout.JAVA_DOUBLE, new long[] { 256 } }, + { ValueLayout.JAVA_DOUBLE, new long[] { 16, 16 } }, + { ValueLayout.JAVA_DOUBLE, new long[] { 4, 4, 4, 4 } }, + { ValueLayout.JAVA_DOUBLE, new long[] { 2, 8, 16 } }, + { ValueLayout.JAVA_DOUBLE, new long[] { 16, 8, 2 } }, + { ValueLayout.JAVA_DOUBLE, new long[] { 8, 16, 2 } }, { POINT, new long[] { 256 } }, { POINT, new long[] { 16, 16 } }, diff --git a/test/jdk/java/foreign/TestResourceScope.java b/test/jdk/java/foreign/TestResourceScope.java index bb126abbe8a6b27f540da8b4d0ca21e8b58dd7dc..77c436bca89912792bb7ac5fcf3816632f2bb6b0 100644 --- a/test/jdk/java/foreign/TestResourceScope.java +++ b/test/jdk/java/foreign/TestResourceScope.java @@ -39,6 +39,7 @@ import static org.testng.Assert.*; import java.util.ArrayList; import java.util.List; +import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Supplier; @@ -157,15 +158,14 @@ public class TestResourceScope { } } - @Test(dataProvider = "cleaners") - public void testLockSingleThread(Supplier<Cleaner> cleanerSupplier) { - Cleaner cleaner = cleanerSupplier.get(); - ResourceScope scope = cleaner != null ? - ResourceScope.newConfinedScope(cleaner) : - ResourceScope.newConfinedScope(); - List<ResourceScope.Handle> handles = new ArrayList<>(); + @Test + public void testLockSingleThread() { + ResourceScope scope = ResourceScope.newConfinedScope(); + List<ResourceScope> handles = new ArrayList<>(); for (int i = 0 ; i < N_THREADS ; i++) { - handles.add(scope.acquire()); + ResourceScope handle = ResourceScope.newConfinedScope(); + handle.keepAlive(scope); + handles.add(handle); } while (true) { @@ -175,31 +175,24 @@ public class TestResourceScope { break; } catch (IllegalStateException ex) { assertTrue(handles.size() > 0); - ResourceScope.Handle handle = handles.remove(0); - scope.release(handle); - scope.release(handle); // make sure it's idempotent - scope.release(handle); // make sure it's idempotent + ResourceScope handle = handles.remove(0); + handle.close(); } } } - @Test(dataProvider = "cleaners") - public void testLockSharedMultiThread(Supplier<Cleaner> cleanerSupplier) { - Cleaner cleaner = cleanerSupplier.get(); - ResourceScope scope = cleaner != null ? - ResourceScope.newSharedScope(cleaner) : - ResourceScope.newSharedScope(); + @Test + public void testLockSharedMultiThread() { + ResourceScope scope = ResourceScope.newSharedScope(); AtomicInteger lockCount = new AtomicInteger(); for (int i = 0 ; i < N_THREADS ; i++) { new Thread(() -> { - try { - ResourceScope.Handle handle = scope.acquire(); // this can throw if segment has been closed + try (ResourceScope handle = ResourceScope.newConfinedScope()) { + handle.keepAlive(scope); lockCount.incrementAndGet(); waitSomeTime(); lockCount.decrementAndGet(); - scope.release(handle); // cannot throw (acquired segments cannot be closed) - scope.release(handle); // cannot throw (idempotent) - scope.release(handle); // cannot throw (idempotent) + handle.close(); } catch (IllegalStateException ex) { // might be already closed - do nothing } @@ -230,13 +223,12 @@ public class TestResourceScope { @Test public void testCloseConfinedLock() { ResourceScope scope = ResourceScope.newConfinedScope(); - ResourceScope.Handle handle = scope.acquire(); + ResourceScope handle = ResourceScope.newConfinedScope(); + handle.keepAlive(scope); AtomicReference<Throwable> failure = new AtomicReference<>(); Thread t = new Thread(() -> { try { - scope.release(handle); - scope.release(handle); // make sure it's idempotent - scope.release(handle); // make sure it's idempotent + handle.close(); } catch (Throwable ex) { failure.set(ex); } @@ -255,24 +247,85 @@ public class TestResourceScope { public void testScopeHandles(Supplier<ResourceScope> scopeFactory) { ResourceScope scope = scopeFactory.get(); acquireRecursive(scope, 5); - if (!scope.isImplicit()) { + if (scope != ResourceScope.globalScope()) { scope.close(); } } + @Test(dataProvider = "scopes", expectedExceptions = IllegalArgumentException.class) + public void testAcquireSelf(Supplier<ResourceScope> scopeSupplier) { + ResourceScope scope = scopeSupplier.get(); + scope.keepAlive(scope); + } + private void acquireRecursive(ResourceScope scope, int acquireCount) { - ResourceScope.Handle handle = scope.acquire(); - assertEquals(handle.scope(), scope); - if (acquireCount > 0) { - // recursive acquire - acquireRecursive(scope, acquireCount - 1); + try (ResourceScope handle = ResourceScope.newConfinedScope()) { + handle.keepAlive(scope); + if (acquireCount > 0) { + // recursive acquire + acquireRecursive(scope, acquireCount - 1); + } + if (scope != ResourceScope.globalScope()) { + assertThrows(IllegalStateException.class, scope::close); + } } - if (!scope.isImplicit()) { - assertThrows(IllegalStateException.class, scope::close); + } + + @Test + public void testConfinedScopeWithImplicitDependency() { + ResourceScope root = ResourceScope.newConfinedScope(); + // Create many implicit scopes which depend on 'root', and let them become unreachable. + for (int i = 0; i < N_THREADS; i++) { + ResourceScope.newConfinedScope(Cleaner.create()).keepAlive(root); } - scope.release(handle); - scope.release(handle); // make sure it's idempotent - scope.release(handle); // make sure it's idempotent + // Now let's keep trying to close 'root' until we succeed. This is trickier than it seems: cleanup action + // might be called from another thread (the Cleaner thread), so that the confined scope lock count is updated racily. + // If that happens, the loop below never terminates. + while (true) { + try { + root.close(); + break; // success! + } catch (IllegalStateException ex) { + kickGC(); + for (int i = 0 ; i < N_THREADS ; i++) { // add more races from current thread + try (ResourceScope scope = ResourceScope.newConfinedScope()) { + scope.keepAlive(root); + // dummy + } + } + // try again + } + } + } + + @Test + public void testConfinedScopeWithSharedDependency() { + ResourceScope root = ResourceScope.newConfinedScope(); + List<Thread> threads = new ArrayList<>(); + // Create many implicit scopes which depend on 'root', and let them become unreachable. + for (int i = 0; i < N_THREADS; i++) { + ResourceScope scope = ResourceScope.newSharedScope(); // create scope inside same thread! + scope.keepAlive(root); + Thread t = new Thread(scope::close); // close from another thread! + threads.add(t); + t.start(); + } + for (int i = 0 ; i < N_THREADS ; i++) { // add more races from current thread + try (ResourceScope scope = ResourceScope.newConfinedScope()) { + scope.keepAlive(root); + // dummy + } + } + threads.forEach(t -> { + try { + t.join(); + } catch (InterruptedException ex) { + // ok + } + }); + // Now let's close 'root'. This is trickier than it seems: releases of the confined scope happen in different + // threads, so that the confined scope lock count is updated racily. If that happens, the following close will blow up. + root.close(); } private void waitSomeTime() { diff --git a/test/jdk/java/foreign/TestRestricted.java b/test/jdk/java/foreign/TestRestricted.java index 68d23b6eb237e34b01c7fadda1dbc17386a00ff0..8667ffe1f471008adb82abb994f9d927b194c92c 100644 --- a/test/jdk/java/foreign/TestRestricted.java +++ b/test/jdk/java/foreign/TestRestricted.java @@ -21,6 +21,7 @@ * questions. */ +import jdk.incubator.foreign.CLinker; import jdk.incubator.foreign.MemoryAddress; import jdk.incubator.foreign.MemorySegment; import jdk.incubator.foreign.ResourceScope; @@ -38,37 +39,37 @@ import java.lang.reflect.InvocationTargetException; public class TestRestricted { @Test(expectedExceptions = InvocationTargetException.class) public void testReflection() throws Throwable { - Method method = MemorySegment.class.getDeclaredMethod("globalNativeSegment"); + Method method = CLinker.class.getDeclaredMethod("systemCLinker"); method.invoke(null); } @Test(expectedExceptions = IllegalCallerException.class) public void testInvoke() throws Throwable { - var mh = MethodHandles.lookup().findStatic(MemorySegment.class, - "globalNativeSegment", MethodType.methodType(MemorySegment.class)); - var seg = (MemorySegment)mh.invokeExact(); + var mh = MethodHandles.lookup().findStatic(CLinker.class, + "systemCLinker", MethodType.methodType(CLinker.class)); + var seg = (CLinker)mh.invokeExact(); } @Test(expectedExceptions = IllegalCallerException.class) public void testDirectAccess() throws Throwable { - MemorySegment.globalNativeSegment(); + CLinker.systemCLinker(); } @Test(expectedExceptions = InvocationTargetException.class) public void testReflection2() throws Throwable { - Method method = MemoryAddress.class.getDeclaredMethod("asSegment", long.class, ResourceScope.class); - method.invoke(MemoryAddress.NULL, 4000L, ResourceScope.globalScope()); + Method method = MemorySegment.class.getDeclaredMethod("ofAddress", MemoryAddress.class, long.class, ResourceScope.class); + method.invoke(null, MemoryAddress.NULL, 4000L, ResourceScope.globalScope()); } @Test(expectedExceptions = IllegalCallerException.class) public void testInvoke2() throws Throwable { - var mh = MethodHandles.lookup().findVirtual(MemoryAddress.class, "asSegment", - MethodType.methodType(MemorySegment.class, long.class, ResourceScope.class)); + var mh = MethodHandles.lookup().findStatic(MemorySegment.class, "ofAddress", + MethodType.methodType(MemorySegment.class, MemoryAddress.class, long.class, ResourceScope.class)); var seg = (MemorySegment)mh.invokeExact(MemoryAddress.NULL, 4000L, ResourceScope.globalScope()); } @Test(expectedExceptions = IllegalCallerException.class) public void testDirectAccess2() throws Throwable { - MemoryAddress.NULL.asSegment(4000L, ResourceScope.globalScope()); + MemorySegment.ofAddress(MemoryAddress.NULL, 4000, ResourceScope.globalScope()); } } diff --git a/test/jdk/java/foreign/TestScopedOperations.java b/test/jdk/java/foreign/TestScopedOperations.java index 9254a9e5b3a79698aab7852fea7cca24f8bcf476..7384693481c20c246508f3b037c08ad3199b9149 100644 --- a/test/jdk/java/foreign/TestScopedOperations.java +++ b/test/jdk/java/foreign/TestScopedOperations.java @@ -27,13 +27,14 @@ * @run testng/othervm --enable-native-access=ALL-UNNAMED TestScopedOperations */ -import jdk.incubator.foreign.CLinker; import jdk.incubator.foreign.MemoryAddress; import jdk.incubator.foreign.MemoryLayout; -import jdk.incubator.foreign.MemoryLayouts; import jdk.incubator.foreign.MemorySegment; +import jdk.incubator.foreign.NativeSymbol; import jdk.incubator.foreign.ResourceScope; import jdk.incubator.foreign.SegmentAllocator; +import jdk.incubator.foreign.VaList; +import jdk.incubator.foreign.ValueLayout; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; @@ -47,6 +48,9 @@ import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; import java.util.function.Function; +import static jdk.incubator.foreign.ValueLayout.JAVA_BYTE; +import static jdk.incubator.foreign.ValueLayout.JAVA_INT; +import static jdk.incubator.foreign.ValueLayout.JAVA_LONG; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertTrue; @@ -67,11 +71,12 @@ public class TestScopedOperations { } @Test(dataProvider = "scopedOperations") - public void testOpAfterClose(String name, ScopedOperation scopedOperation) { + public <Z> void testOpAfterClose(String name, ScopedOperation<Z> scopedOperation) { ResourceScope scope = ResourceScope.newConfinedScope(); + Z obj = scopedOperation.apply(scope); scope.close(); try { - scopedOperation.accept(scope); + scopedOperation.accept(obj); fail(); } catch (IllegalStateException ex) { assertTrue(ex.getMessage().contains("closed")); @@ -79,12 +84,13 @@ public class TestScopedOperations { } @Test(dataProvider = "scopedOperations") - public void testOpOutsideConfinement(String name, ScopedOperation scopedOperation) { + public <Z> void testOpOutsideConfinement(String name, ScopedOperation<Z> scopedOperation) { try (ResourceScope scope = ResourceScope.newConfinedScope()) { + Z obj = scopedOperation.apply(scope); AtomicReference<Throwable> failed = new AtomicReference<>(); Thread t = new Thread(() -> { try { - scopedOperation.accept(scope); + scopedOperation.accept(obj); } catch (Throwable ex) { failed.set(ex); } @@ -106,9 +112,10 @@ public class TestScopedOperations { ScopedOperation.ofScope(scope -> scope.addCloseAction(() -> { }), "ResourceScope::addOnClose"); ScopedOperation.ofScope(scope -> { - ResourceScope.Handle handle = scope.acquire(); - scope.release(handle); - }, "ResourceScope::lock"); + ResourceScope scope2 = ResourceScope.newConfinedScope(); + scope2.keepAlive(scope); + scope2.close(); + }, "ResourceScope::keepAlive"); ScopedOperation.ofScope(scope -> MemorySegment.allocateNative(100, scope), "MemorySegment::allocateNative"); ScopedOperation.ofScope(scope -> { try { @@ -117,54 +124,46 @@ public class TestScopedOperations { fail(); } }, "MemorySegment::mapFromFile"); - ScopedOperation.ofScope(scope -> CLinker.VaList.make(b -> {}, scope), "VaList::make"); - ScopedOperation.ofScope(scope -> CLinker.VaList.ofAddress(MemoryAddress.ofLong(42), scope), "VaList::make"); - ScopedOperation.ofScope(scope -> CLinker.toCString("Hello", scope), "CLinker::toCString"); - ScopedOperation.ofScope(SegmentAllocator::arenaAllocator, "SegmentAllocator::arenaAllocator"); + ScopedOperation.ofScope(scope -> VaList.make(b -> b.addVarg(JAVA_INT, 42), scope), "VaList::make"); + ScopedOperation.ofScope(scope -> VaList.ofAddress(MemoryAddress.ofLong(42), scope), "VaList::make"); + ScopedOperation.ofScope(SegmentAllocator::newNativeArena, "SegmentAllocator::arenaAllocator"); // segment operations - ScopedOperation.ofSegment(MemorySegment::toByteArray, "MemorySegment::toByteArray"); - ScopedOperation.ofSegment(MemorySegment::toCharArray, "MemorySegment::toCharArray"); - ScopedOperation.ofSegment(MemorySegment::toShortArray, "MemorySegment::toShortArray"); - ScopedOperation.ofSegment(MemorySegment::toIntArray, "MemorySegment::toIntArray"); - ScopedOperation.ofSegment(MemorySegment::toFloatArray, "MemorySegment::toFloatArray"); - ScopedOperation.ofSegment(MemorySegment::toLongArray, "MemorySegment::toLongArray"); - ScopedOperation.ofSegment(MemorySegment::toDoubleArray, "MemorySegment::toDoubleArray"); + ScopedOperation.ofSegment(s -> s.toArray(JAVA_BYTE), "MemorySegment::toArray(BYTE)"); ScopedOperation.ofSegment(MemorySegment::address, "MemorySegment::address"); - ScopedOperation.ofSegment(s -> MemoryLayout.sequenceLayout(s.byteSize(), MemoryLayouts.JAVA_BYTE), "MemorySegment::spliterator"); ScopedOperation.ofSegment(s -> s.copyFrom(s), "MemorySegment::copyFrom"); ScopedOperation.ofSegment(s -> s.mismatch(s), "MemorySegment::mismatch"); ScopedOperation.ofSegment(s -> s.fill((byte) 0), "MemorySegment::fill"); - // address operations - ScopedOperation.ofAddress(a -> a.toRawLongValue(), "MemoryAddress::toRawLongValue"); - ScopedOperation.ofAddress(a -> a.asSegment(100, ResourceScope.globalScope()), "MemoryAddress::asSegment"); // valist operations - ScopedOperation.ofVaList(CLinker.VaList::address, "VaList::address"); - ScopedOperation.ofVaList(CLinker.VaList::copy, "VaList::copy"); - ScopedOperation.ofVaList(list -> list.vargAsAddress(MemoryLayouts.ADDRESS), "VaList::vargAsAddress"); - ScopedOperation.ofVaList(list -> list.vargAsInt(MemoryLayouts.JAVA_INT), "VaList::vargAsInt"); - ScopedOperation.ofVaList(list -> list.vargAsLong(MemoryLayouts.JAVA_LONG), "VaList::vargAsLong"); - ScopedOperation.ofVaList(list -> list.vargAsDouble(MemoryLayouts.JAVA_DOUBLE), "VaList::vargAsDouble"); - ScopedOperation.ofVaList(CLinker.VaList::skip, "VaList::skip"); - ScopedOperation.ofVaList(list -> list.vargAsSegment(MemoryLayout.structLayout(MemoryLayouts.JAVA_INT), ResourceScope.newImplicitScope()), "VaList::vargAsSegment/1"); + ScopedOperation.ofVaList(VaList::address, "VaList::address"); + ScopedOperation.ofVaList(VaList::copy, "VaList::copy"); + ScopedOperation.ofVaList(list -> list.nextVarg(ValueLayout.ADDRESS), "VaList::nextVarg/address"); + ScopedOperation.ofVaList(list -> list.nextVarg(ValueLayout.JAVA_INT), "VaList::nextVarg/int"); + ScopedOperation.ofVaList(list -> list.nextVarg(ValueLayout.JAVA_LONG), "VaList::nextVarg/long"); + ScopedOperation.ofVaList(list -> list.nextVarg(ValueLayout.JAVA_DOUBLE), "VaList::nextVarg/double"); + ScopedOperation.ofVaList(VaList::skip, "VaList::skip"); + ScopedOperation.ofVaList(list -> list.nextVarg(MemoryLayout.structLayout(ValueLayout.JAVA_INT), + SegmentAllocator.prefixAllocator(MemorySegment.ofArray(new byte[4]))), "VaList::nextVargs/segment"); // allocator operations ScopedOperation.ofAllocator(a -> a.allocate(1), "NativeAllocator::allocate/size"); ScopedOperation.ofAllocator(a -> a.allocate(1, 1), "NativeAllocator::allocate/size/align"); - ScopedOperation.ofAllocator(a -> a.allocate(MemoryLayouts.JAVA_BYTE), "NativeAllocator::allocate/layout"); - ScopedOperation.ofAllocator(a -> a.allocate(MemoryLayouts.JAVA_BYTE, (byte) 0), "NativeAllocator::allocate/byte"); - ScopedOperation.ofAllocator(a -> a.allocate(MemoryLayouts.JAVA_CHAR, (char) 0), "NativeAllocator::allocate/char"); - ScopedOperation.ofAllocator(a -> a.allocate(MemoryLayouts.JAVA_SHORT, (short) 0), "NativeAllocator::allocate/short"); - ScopedOperation.ofAllocator(a -> a.allocate(MemoryLayouts.JAVA_INT, 0), "NativeAllocator::allocate/int"); - ScopedOperation.ofAllocator(a -> a.allocate(MemoryLayouts.JAVA_FLOAT, 0f), "NativeAllocator::allocate/float"); - ScopedOperation.ofAllocator(a -> a.allocate(MemoryLayouts.JAVA_LONG, 0L), "NativeAllocator::allocate/long"); - ScopedOperation.ofAllocator(a -> a.allocate(MemoryLayouts.JAVA_DOUBLE, 0d), "NativeAllocator::allocate/double"); - ScopedOperation.ofAllocator(a -> a.allocateArray(MemoryLayouts.JAVA_BYTE, 1L), "NativeAllocator::allocateArray/size"); - ScopedOperation.ofAllocator(a -> a.allocateArray(MemoryLayouts.JAVA_BYTE, new byte[]{0}), "NativeAllocator::allocateArray/byte"); - ScopedOperation.ofAllocator(a -> a.allocateArray(MemoryLayouts.JAVA_CHAR, new char[]{0}), "NativeAllocator::allocateArray/char"); - ScopedOperation.ofAllocator(a -> a.allocateArray(MemoryLayouts.JAVA_SHORT, new short[]{0}), "NativeAllocator::allocateArray/short"); - ScopedOperation.ofAllocator(a -> a.allocateArray(MemoryLayouts.JAVA_INT, new int[]{0}), "NativeAllocator::allocateArray/int"); - ScopedOperation.ofAllocator(a -> a.allocateArray(MemoryLayouts.JAVA_FLOAT, new float[]{0}), "NativeAllocator::allocateArray/float"); - ScopedOperation.ofAllocator(a -> a.allocateArray(MemoryLayouts.JAVA_LONG, new long[]{0}), "NativeAllocator::allocateArray/long"); - ScopedOperation.ofAllocator(a -> a.allocateArray(MemoryLayouts.JAVA_DOUBLE, new double[]{0}), "NativeAllocator::allocateArray/double"); + ScopedOperation.ofAllocator(a -> a.allocate(JAVA_BYTE), "NativeAllocator::allocate/layout"); + ScopedOperation.ofAllocator(a -> a.allocate(JAVA_BYTE, (byte) 0), "NativeAllocator::allocate/byte"); + ScopedOperation.ofAllocator(a -> a.allocate(ValueLayout.JAVA_CHAR, (char) 0), "NativeAllocator::allocate/char"); + ScopedOperation.ofAllocator(a -> a.allocate(ValueLayout.JAVA_SHORT, (short) 0), "NativeAllocator::allocate/short"); + ScopedOperation.ofAllocator(a -> a.allocate(ValueLayout.JAVA_INT, 0), "NativeAllocator::allocate/int"); + ScopedOperation.ofAllocator(a -> a.allocate(ValueLayout.JAVA_FLOAT, 0f), "NativeAllocator::allocate/float"); + ScopedOperation.ofAllocator(a -> a.allocate(ValueLayout.JAVA_LONG, 0L), "NativeAllocator::allocate/long"); + ScopedOperation.ofAllocator(a -> a.allocate(ValueLayout.JAVA_DOUBLE, 0d), "NativeAllocator::allocate/double"); + ScopedOperation.ofAllocator(a -> a.allocateArray(JAVA_BYTE, 1L), "NativeAllocator::allocateArray/size"); + ScopedOperation.ofAllocator(a -> a.allocateArray(JAVA_BYTE, new byte[]{0}), "NativeAllocator::allocateArray/byte"); + ScopedOperation.ofAllocator(a -> a.allocateArray(ValueLayout.JAVA_CHAR, new char[]{0}), "NativeAllocator::allocateArray/char"); + ScopedOperation.ofAllocator(a -> a.allocateArray(ValueLayout.JAVA_SHORT, new short[]{0}), "NativeAllocator::allocateArray/short"); + ScopedOperation.ofAllocator(a -> a.allocateArray(ValueLayout.JAVA_INT, new int[]{0}), "NativeAllocator::allocateArray/int"); + ScopedOperation.ofAllocator(a -> a.allocateArray(ValueLayout.JAVA_FLOAT, new float[]{0}), "NativeAllocator::allocateArray/float"); + ScopedOperation.ofAllocator(a -> a.allocateArray(ValueLayout.JAVA_LONG, new long[]{0}), "NativeAllocator::allocateArray/long"); + ScopedOperation.ofAllocator(a -> a.allocateArray(ValueLayout.JAVA_DOUBLE, new double[]{0}), "NativeAllocator::allocateArray/double"); + // native symbol + ScopedOperation.of(scope -> NativeSymbol.ofAddress("", MemoryAddress.NULL, scope), NativeSymbol::address, "NativeSymbol::address"); }; @DataProvider(name = "scopedOperations") @@ -172,56 +171,56 @@ public class TestScopedOperations { return scopedOperations.stream().map(op -> new Object[] { op.name, op }).toArray(Object[][]::new); } - static class ScopedOperation implements Consumer<ResourceScope> { + static class ScopedOperation<X> implements Consumer<X>, Function<ResourceScope, X> { - final Consumer<ResourceScope> scopeConsumer; + final Function<ResourceScope, X> factory; + final Consumer<X> operation; final String name; - private ScopedOperation(Consumer<ResourceScope> scopeConsumer, String name) { - this.scopeConsumer = scopeConsumer; + private ScopedOperation(Function<ResourceScope, X> factory, Consumer<X> operation, String name) { + this.factory = factory; + this.operation = operation; this.name = name; } @Override - public void accept(ResourceScope scope) { - scopeConsumer.accept(scope); + public void accept(X obj) { + operation.accept(obj); } - static void ofScope(Consumer<ResourceScope> scopeConsumer, String name) { - scopedOperations.add(new ScopedOperation(scopeConsumer::accept, name)); + @Override + public X apply(ResourceScope scope) { + return factory.apply(scope); } - static void ofVaList(Consumer<CLinker.VaList> vaListConsumer, String name) { - scopedOperations.add(new ScopedOperation(scope -> { - CLinker.VaList vaList = CLinker.VaList.make((builder) -> {}, scope); - vaListConsumer.accept(vaList); - }, name)); + static <Z> void of(Function<ResourceScope, Z> factory, Consumer<Z> consumer, String name) { + scopedOperations.add(new ScopedOperation<>(factory, consumer, name)); } - static void ofSegment(Consumer<MemorySegment> segmentConsumer, String name) { - for (SegmentFactory segmentFactory : SegmentFactory.values()) { - scopedOperations.add(new ScopedOperation(scope -> { - MemorySegment segment = segmentFactory.segmentFactory.apply(scope); - segmentConsumer.accept(segment); - }, segmentFactory.name() + "/" + name)); - } + static void ofScope(Consumer<ResourceScope> scopeConsumer, String name) { + scopedOperations.add(new ScopedOperation<>(Function.identity(), scopeConsumer, name)); + } + + static void ofVaList(Consumer<VaList> vaListConsumer, String name) { + scopedOperations.add(new ScopedOperation<>(scope -> VaList.make(builder -> builder.addVarg(JAVA_LONG, 42), scope), + vaListConsumer, name)); } - static void ofAddress(Consumer<MemoryAddress> addressConsumer, String name) { + static void ofSegment(Consumer<MemorySegment> segmentConsumer, String name) { for (SegmentFactory segmentFactory : SegmentFactory.values()) { - scopedOperations.add(new ScopedOperation(scope -> { - MemoryAddress segment = segmentFactory.segmentFactory.apply(scope).address(); - addressConsumer.accept(segment); - }, segmentFactory.name() + "/" + name)); + scopedOperations.add(new ScopedOperation<>( + segmentFactory.segmentFactory, + segmentConsumer, + segmentFactory.name() + "/" + name)); } } static void ofAllocator(Consumer<SegmentAllocator> allocatorConsumer, String name) { for (AllocatorFactory allocatorFactory : AllocatorFactory.values()) { - scopedOperations.add(new ScopedOperation(scope -> { - SegmentAllocator allocator = allocatorFactory.allocatorFactory.apply(scope); - allocatorConsumer.accept(allocator); - }, allocatorFactory.name() + "/" + name)); + scopedOperations.add(new ScopedOperation<>( + allocatorFactory.allocatorFactory, + allocatorConsumer, + allocatorFactory.name() + "/" + name)); } } @@ -235,7 +234,7 @@ public class TestScopedOperations { throw new AssertionError(ex); } }), - UNSAFE(scope -> MemoryAddress.NULL.asSegment(10, scope)); + UNSAFE(scope -> MemorySegment.ofAddress(MemoryAddress.NULL, 10, scope)); static { try { @@ -255,13 +254,8 @@ public class TestScopedOperations { } enum AllocatorFactory { - ARENA_BOUNDED(scope -> SegmentAllocator.arenaAllocator(1000, scope)), - ARENA_UNBOUNDED(SegmentAllocator::arenaAllocator), - FROM_SEGMENT(scope -> { - MemorySegment segment = MemorySegment.allocateNative(10, scope); - return SegmentAllocator.ofSegment(segment); - }), - FROM_SCOPE(SegmentAllocator::ofScope); + ARENA_BOUNDED(scope -> SegmentAllocator.newNativeArena(1000, scope)), + ARENA_UNBOUNDED(SegmentAllocator::newNativeArena); final Function<ResourceScope, SegmentAllocator> allocatorFactory; diff --git a/test/jdk/java/foreign/TestSegmentAllocators.java b/test/jdk/java/foreign/TestSegmentAllocators.java index 3d2538ad897a21e42fc2a2b21da8f9a4bbe44285..aa269191a23312f9714ef089d1c4fe60576de63e 100644 --- a/test/jdk/java/foreign/TestSegmentAllocators.java +++ b/test/jdk/java/foreign/TestSegmentAllocators.java @@ -34,6 +34,7 @@ import org.testng.annotations.*; import java.lang.invoke.VarHandle; import java.nio.ByteBuffer; import java.nio.ByteOrder; +import java.nio.CharBuffer; import java.nio.DoubleBuffer; import java.nio.FloatBuffer; import java.nio.IntBuffer; @@ -51,17 +52,19 @@ import static org.testng.Assert.*; public class TestSegmentAllocators { final static int ELEMS = 128; - final static Class<?> ADDRESS_CARRIER = MemoryLayouts.ADDRESS.bitSize() == 64 ? long.class : int.class; + final static Class<?> ADDRESS_CARRIER = ValueLayout.ADDRESS.bitSize() == 64 ? long.class : int.class; @Test(dataProvider = "nativeScopes") - public <Z> void testAllocation(Z value, AllocationFactory allocationFactory, ValueLayout layout, AllocationFunction<Z> allocationFunction, Function<MemoryLayout, VarHandle> handleFactory) { - ValueLayout[] layouts = { + @SuppressWarnings("unchecked") + public <Z, L extends ValueLayout> void testAllocation(Z value, AllocationFactory allocationFactory, L layout, AllocationFunction<Z, L> allocationFunction, Function<MemoryLayout, VarHandle> handleFactory) { + layout = (L)layout.withBitAlignment(layout.bitSize()); + L[] layouts = (L[])new ValueLayout[] { layout, layout.withBitAlignment(layout.bitAlignment() * 2), layout.withBitAlignment(layout.bitAlignment() * 4), layout.withBitAlignment(layout.bitAlignment() * 8) }; - for (ValueLayout alignedLayout : layouts) { + for (L alignedLayout : layouts) { List<MemorySegment> addressList = new ArrayList<>(); int elems = ELEMS / ((int)alignedLayout.byteAlignment() / (int)layout.byteAlignment()); ResourceScope[] scopes = { @@ -80,16 +83,18 @@ public class TestSegmentAllocators { } boolean isBound = allocationFactory.isBound(); try { - allocationFunction.allocate(allocator, alignedLayout, value); //too much, should fail if bound + allocationFunction.allocate(allocator, alignedLayout, value); assertFalse(isBound); } catch (OutOfMemoryError ex) { //failure is expected if bound assertTrue(isBound); } } - // addresses should be invalid now - for (MemorySegment address : addressList) { - assertFalse(address.scope().isAlive()); + if (allocationFactory != AllocationFactory.IMPLICIT_ALLOCATOR) { + // addresses should be invalid now + for (MemorySegment address : addressList) { + assertFalse(address.scope().isAlive()); + } } } } @@ -100,7 +105,7 @@ public class TestSegmentAllocators { @Test public void testBigAllocationInUnboundedScope() { try (ResourceScope scope = ResourceScope.newConfinedScope()) { - SegmentAllocator allocator = SegmentAllocator.arenaAllocator(scope); + SegmentAllocator allocator = SegmentAllocator.newNativeArena(scope); for (int i = 8 ; i < SIZE_256M ; i *= 8) { MemorySegment address = allocator.allocate(i, i); //check size @@ -111,24 +116,30 @@ public class TestSegmentAllocators { } } - @Test(expectedExceptions = OutOfMemoryError.class) + @Test public void testTooBigForBoundedArena() { try (ResourceScope scope = ResourceScope.newConfinedScope()) { - SegmentAllocator allocator = SegmentAllocator.arenaAllocator(10, scope); - allocator.allocate(12); + SegmentAllocator allocator = SegmentAllocator.newNativeArena(10, scope); + assertThrows(OutOfMemoryError.class, () -> allocator.allocate(12)); + allocator.allocate(5); // ok } } @Test public void testBiggerThanBlockForBoundedArena() { try (ResourceScope scope = ResourceScope.newConfinedScope()) { - SegmentAllocator allocator = SegmentAllocator.arenaAllocator(4 * 1024 * 2, scope); + SegmentAllocator allocator = SegmentAllocator.newNativeArena(4 * 1024 * 2, scope); allocator.allocate(4 * 1024 + 1); // should be ok } } + @Test(expectedExceptions = IllegalArgumentException.class) + public void testBadUnboundedArenaSize() { + SegmentAllocator.newNativeArena( -1, ResourceScope.globalScope()); + } + @Test(dataProvider = "arrayScopes") - public <Z> void testArray(AllocationFactory allocationFactory, ValueLayout layout, AllocationFunction<Object> allocationFunction, ToArrayHelper<Z> arrayHelper) { + public <Z> void testArray(AllocationFactory allocationFactory, ValueLayout layout, AllocationFunction<Object, ValueLayout> allocationFunction, ToArrayHelper<Z> arrayHelper) { Z arr = arrayHelper.array(); ResourceScope[] scopes = { ResourceScope.newConfinedScope(), @@ -146,221 +157,142 @@ public class TestSegmentAllocators { @DataProvider(name = "nativeScopes") static Object[][] nativeScopes() { - return new Object[][] { - { (byte)42, AllocationFactory.BOUNDED, MemoryLayouts.BITS_8_BE, - (AllocationFunction<Byte>) SegmentAllocator::allocate, - (Function<MemoryLayout, VarHandle>)l -> l.varHandle(byte.class) }, - { (short)42, AllocationFactory.BOUNDED, MemoryLayouts.BITS_16_BE, - (AllocationFunction<Short>) SegmentAllocator::allocate, - (Function<MemoryLayout, VarHandle>)l -> l.varHandle(short.class) }, - { (char)42, AllocationFactory.BOUNDED, MemoryLayouts.BITS_16_BE, - (AllocationFunction<Character>) SegmentAllocator::allocate, - (Function<MemoryLayout, VarHandle>)l -> l.varHandle(char.class) }, - { 42, AllocationFactory.BOUNDED, - MemoryLayouts.BITS_32_BE, - (AllocationFunction<Integer>) SegmentAllocator::allocate, - (Function<MemoryLayout, VarHandle>)l -> l.varHandle(int.class) }, - { 42f, AllocationFactory.BOUNDED, MemoryLayouts.BITS_32_BE, - (AllocationFunction<Float>) SegmentAllocator::allocate, - (Function<MemoryLayout, VarHandle>)l -> l.varHandle(float.class) }, - { 42L, AllocationFactory.BOUNDED, MemoryLayouts.BITS_64_BE, - (AllocationFunction<Long>) SegmentAllocator::allocate, - (Function<MemoryLayout, VarHandle>)l -> l.varHandle(long.class) }, - { 42d, AllocationFactory.BOUNDED, MemoryLayouts.BITS_64_BE, - (AllocationFunction<Double>) SegmentAllocator::allocate, - (Function<MemoryLayout, VarHandle>)l -> l.varHandle(double.class) }, - { MemoryAddress.ofLong(42), AllocationFactory.BOUNDED, MemoryLayouts.ADDRESS.withOrder(ByteOrder.BIG_ENDIAN), - (AllocationFunction<MemoryAddress>) SegmentAllocator::allocate, - (Function<MemoryLayout, VarHandle>)l -> MemoryHandles.asAddressVarHandle(l.varHandle(ADDRESS_CARRIER)) }, - - { (byte)42, AllocationFactory.BOUNDED, MemoryLayouts.BITS_8_LE, - (AllocationFunction<Byte>) SegmentAllocator::allocate, - (Function<MemoryLayout, VarHandle>)l -> l.varHandle(byte.class) }, - { (short)42, AllocationFactory.BOUNDED, MemoryLayouts.BITS_16_LE, - (AllocationFunction<Short>) SegmentAllocator::allocate, - (Function<MemoryLayout, VarHandle>)l -> l.varHandle(short.class) }, - { (char)42, AllocationFactory.BOUNDED, MemoryLayouts.BITS_16_LE, - (AllocationFunction<Character>) SegmentAllocator::allocate, - (Function<MemoryLayout, VarHandle>)l -> l.varHandle(char.class) }, - { 42, AllocationFactory.BOUNDED, - MemoryLayouts.BITS_32_LE, - (AllocationFunction<Integer>) SegmentAllocator::allocate, - (Function<MemoryLayout, VarHandle>)l -> l.varHandle(int.class) }, - { 42f, AllocationFactory.BOUNDED, MemoryLayouts.BITS_32_LE, - (AllocationFunction<Float>) SegmentAllocator::allocate, - (Function<MemoryLayout, VarHandle>)l -> l.varHandle(float.class) }, - { 42L, AllocationFactory.BOUNDED, MemoryLayouts.BITS_64_LE, - (AllocationFunction<Long>) SegmentAllocator::allocate, - (Function<MemoryLayout, VarHandle>)l -> l.varHandle(long.class) }, - { 42d, AllocationFactory.BOUNDED, MemoryLayouts.BITS_64_LE, - (AllocationFunction<Double>) SegmentAllocator::allocate, - (Function<MemoryLayout, VarHandle>)l -> l.varHandle(double.class) }, - { MemoryAddress.ofLong(42), AllocationFactory.BOUNDED, MemoryLayouts.ADDRESS.withOrder(ByteOrder.LITTLE_ENDIAN), - (AllocationFunction<MemoryAddress>) SegmentAllocator::allocate, - (Function<MemoryLayout, VarHandle>)l -> MemoryHandles.asAddressVarHandle(l.varHandle(ADDRESS_CARRIER)) }, - - { (byte)42, AllocationFactory.UNBOUNDED, MemoryLayouts.BITS_8_BE, - (AllocationFunction<Byte>) SegmentAllocator::allocate, - (Function<MemoryLayout, VarHandle>)l -> l.varHandle(byte.class) }, - { (short)42, AllocationFactory.UNBOUNDED, MemoryLayouts.BITS_16_BE, - (AllocationFunction<Short>) SegmentAllocator::allocate, - (Function<MemoryLayout, VarHandle>)l -> l.varHandle(short.class) }, - { (char)42, AllocationFactory.UNBOUNDED, MemoryLayouts.BITS_16_BE, - (AllocationFunction<Character>) SegmentAllocator::allocate, - (Function<MemoryLayout, VarHandle>)l -> l.varHandle(char.class) }, - { 42, AllocationFactory.UNBOUNDED, - MemoryLayouts.BITS_32_BE, - (AllocationFunction<Integer>) SegmentAllocator::allocate, - (Function<MemoryLayout, VarHandle>)l -> l.varHandle(int.class) }, - { 42f, AllocationFactory.UNBOUNDED, MemoryLayouts.BITS_32_BE, - (AllocationFunction<Float>) SegmentAllocator::allocate, - (Function<MemoryLayout, VarHandle>)l -> l.varHandle(float.class) }, - { 42L, AllocationFactory.UNBOUNDED, MemoryLayouts.BITS_64_BE, - (AllocationFunction<Long>) SegmentAllocator::allocate, - (Function<MemoryLayout, VarHandle>)l -> l.varHandle(long.class) }, - { 42d, AllocationFactory.UNBOUNDED, MemoryLayouts.BITS_64_BE, - (AllocationFunction<Double>) SegmentAllocator::allocate, - (Function<MemoryLayout, VarHandle>)l -> l.varHandle(double.class) }, - { MemoryAddress.ofLong(42), AllocationFactory.UNBOUNDED, MemoryLayouts.ADDRESS.withOrder(ByteOrder.BIG_ENDIAN), - (AllocationFunction<MemoryAddress>) SegmentAllocator::allocate, - (Function<MemoryLayout, VarHandle>)l -> MemoryHandles.asAddressVarHandle(l.varHandle(ADDRESS_CARRIER)) }, - - { (byte)42, AllocationFactory.UNBOUNDED, MemoryLayouts.BITS_8_LE, - (AllocationFunction<Byte>) SegmentAllocator::allocate, - (Function<MemoryLayout, VarHandle>)l -> l.varHandle(byte.class) }, - { (short)42, AllocationFactory.UNBOUNDED, MemoryLayouts.BITS_16_LE, - (AllocationFunction<Short>) SegmentAllocator::allocate, - (Function<MemoryLayout, VarHandle>)l -> l.varHandle(short.class) }, - { (char)42, AllocationFactory.UNBOUNDED, MemoryLayouts.BITS_16_LE, - (AllocationFunction<Character>) SegmentAllocator::allocate, - (Function<MemoryLayout, VarHandle>)l -> l.varHandle(char.class) }, - { 42, AllocationFactory.UNBOUNDED, - MemoryLayouts.BITS_32_LE, - (AllocationFunction<Integer>) SegmentAllocator::allocate, - (Function<MemoryLayout, VarHandle>)l -> l.varHandle(int.class) }, - { 42f, AllocationFactory.UNBOUNDED, MemoryLayouts.BITS_32_LE, - (AllocationFunction<Float>) SegmentAllocator::allocate, - (Function<MemoryLayout, VarHandle>)l -> l.varHandle(float.class) }, - { 42L, AllocationFactory.UNBOUNDED, MemoryLayouts.BITS_64_LE, - (AllocationFunction<Long>) SegmentAllocator::allocate, - (Function<MemoryLayout, VarHandle>)l -> l.varHandle(long.class) }, - { 42d, AllocationFactory.UNBOUNDED, MemoryLayouts.BITS_64_LE, - (AllocationFunction<Double>) SegmentAllocator::allocate, - (Function<MemoryLayout, VarHandle>)l -> l.varHandle(double.class) }, - { MemoryAddress.ofLong(42), AllocationFactory.UNBOUNDED, MemoryLayouts.ADDRESS.withOrder(ByteOrder.LITTLE_ENDIAN), - (AllocationFunction<MemoryAddress>) SegmentAllocator::allocate, - (Function<MemoryLayout, VarHandle>)l -> MemoryHandles.asAddressVarHandle(l.varHandle(ADDRESS_CARRIER)) }, - }; + List<Object[]> nativeScopes = new ArrayList<>(); + for (AllocationFactory factory : AllocationFactory.values()) { + nativeScopes.add(new Object[] { (byte)42, factory, ValueLayout.JAVA_BYTE, + (AllocationFunction.OfByte) SegmentAllocator::allocate, + (Function<MemoryLayout, VarHandle>)l -> l.varHandle() }); + nativeScopes.add(new Object[] { (short)42, factory, ValueLayout.JAVA_SHORT.withOrder(ByteOrder.BIG_ENDIAN), + (AllocationFunction.OfShort) SegmentAllocator::allocate, + (Function<MemoryLayout, VarHandle>)l -> l.varHandle() }); + nativeScopes.add(new Object[] { (char)42, factory, ValueLayout.JAVA_CHAR.withOrder(ByteOrder.BIG_ENDIAN), + (AllocationFunction.OfChar) SegmentAllocator::allocate, + (Function<MemoryLayout, VarHandle>)l -> l.varHandle() }); + nativeScopes.add(new Object[] { 42, factory, + ValueLayout.JAVA_INT.withOrder(ByteOrder.BIG_ENDIAN), + (AllocationFunction.OfInt) SegmentAllocator::allocate, + (Function<MemoryLayout, VarHandle>)l -> l.varHandle() }); + nativeScopes.add(new Object[] { 42f, factory, ValueLayout.JAVA_FLOAT.withOrder(ByteOrder.BIG_ENDIAN), + (AllocationFunction.OfFloat) SegmentAllocator::allocate, + (Function<MemoryLayout, VarHandle>)l -> l.varHandle() }); + nativeScopes.add(new Object[] { 42L, factory, ValueLayout.JAVA_LONG.withOrder(ByteOrder.BIG_ENDIAN), + (AllocationFunction.OfLong) SegmentAllocator::allocate, + (Function<MemoryLayout, VarHandle>)l -> l.varHandle() }); + nativeScopes.add(new Object[] { 42d, factory, ValueLayout.JAVA_DOUBLE.withOrder(ByteOrder.BIG_ENDIAN), + (AllocationFunction.OfDouble) SegmentAllocator::allocate, + (Function<MemoryLayout, VarHandle>)l -> l.varHandle() }); + nativeScopes.add(new Object[] { MemoryAddress.ofLong(42), factory, ValueLayout.ADDRESS.withOrder(ByteOrder.BIG_ENDIAN), + (AllocationFunction.OfAddress) SegmentAllocator::allocate, + (Function<MemoryLayout, VarHandle>)l -> l.varHandle() }); + + nativeScopes.add(new Object[] { (short)42, factory, ValueLayout.JAVA_SHORT.withOrder(ByteOrder.LITTLE_ENDIAN), + (AllocationFunction.OfShort) SegmentAllocator::allocate, + (Function<MemoryLayout, VarHandle>)l -> l.varHandle() }); + nativeScopes.add(new Object[] { (char)42, factory, ValueLayout.JAVA_CHAR.withOrder(ByteOrder.LITTLE_ENDIAN), + (AllocationFunction.OfChar) SegmentAllocator::allocate, + (Function<MemoryLayout, VarHandle>)l -> l.varHandle() }); + nativeScopes.add(new Object[] { 42, factory, + ValueLayout.JAVA_INT.withOrder(ByteOrder.LITTLE_ENDIAN), + (AllocationFunction.OfInt) SegmentAllocator::allocate, + (Function<MemoryLayout, VarHandle>)l -> l.varHandle() }); + nativeScopes.add(new Object[] { 42f, factory, ValueLayout.JAVA_FLOAT.withOrder(ByteOrder.LITTLE_ENDIAN), + (AllocationFunction.OfFloat) SegmentAllocator::allocate, + (Function<MemoryLayout, VarHandle>)l -> l.varHandle() }); + nativeScopes.add(new Object[] { 42L, factory, ValueLayout.JAVA_LONG.withOrder(ByteOrder.LITTLE_ENDIAN), + (AllocationFunction.OfLong) SegmentAllocator::allocate, + (Function<MemoryLayout, VarHandle>)l -> l.varHandle() }); + nativeScopes.add(new Object[] { 42d, factory, ValueLayout.JAVA_DOUBLE.withOrder(ByteOrder.LITTLE_ENDIAN), + (AllocationFunction.OfDouble) SegmentAllocator::allocate, + (Function<MemoryLayout, VarHandle>)l -> l.varHandle() }); + nativeScopes.add(new Object[] { MemoryAddress.ofLong(42), factory, ValueLayout.ADDRESS.withOrder(ByteOrder.BIG_ENDIAN), + (AllocationFunction.OfAddress) SegmentAllocator::allocate, + (Function<MemoryLayout, VarHandle>)l -> l.varHandle() }); + } + return nativeScopes.toArray(Object[][]::new); } @DataProvider(name = "arrayScopes") static Object[][] arrayScopes() { - return new Object[][] { - { AllocationFactory.BOUNDED, MemoryLayouts.BITS_8_LE, - (AllocationFunction<byte[]>) SegmentAllocator::allocateArray, - ToArrayHelper.toByteArray }, - { AllocationFactory.BOUNDED, MemoryLayouts.BITS_16_LE, - (AllocationFunction<short[]>) SegmentAllocator::allocateArray, - ToArrayHelper.toShortArray }, - { AllocationFactory.BOUNDED, - MemoryLayouts.BITS_32_LE, - (AllocationFunction<int[]>) SegmentAllocator::allocateArray, - ToArrayHelper.toIntArray }, - { AllocationFactory.BOUNDED, MemoryLayouts.BITS_32_LE, - (AllocationFunction<float[]>) SegmentAllocator::allocateArray, - ToArrayHelper.toFloatArray }, - { AllocationFactory.BOUNDED, MemoryLayouts.BITS_64_LE, - (AllocationFunction<long[]>) SegmentAllocator::allocateArray, - ToArrayHelper.toLongArray }, - { AllocationFactory.BOUNDED, MemoryLayouts.BITS_64_LE, - (AllocationFunction<double[]>) SegmentAllocator::allocateArray, - ToArrayHelper.toDoubleArray }, - { AllocationFactory.BOUNDED, MemoryLayouts.ADDRESS.withOrder(ByteOrder.LITTLE_ENDIAN), - (AllocationFunction<MemoryAddress[]>) SegmentAllocator::allocateArray, - ToArrayHelper.toAddressArray }, - - - { AllocationFactory.BOUNDED, MemoryLayouts.BITS_8_BE, - (AllocationFunction<byte[]>) SegmentAllocator::allocateArray, - ToArrayHelper.toByteArray }, - { AllocationFactory.BOUNDED, MemoryLayouts.BITS_16_BE, - (AllocationFunction<short[]>) SegmentAllocator::allocateArray, - ToArrayHelper.toShortArray }, - { AllocationFactory.BOUNDED, - MemoryLayouts.BITS_32_BE, - (AllocationFunction<int[]>) SegmentAllocator::allocateArray, - ToArrayHelper.toIntArray }, - { AllocationFactory.BOUNDED, MemoryLayouts.BITS_32_BE, - (AllocationFunction<float[]>) SegmentAllocator::allocateArray, - ToArrayHelper.toFloatArray }, - { AllocationFactory.BOUNDED, MemoryLayouts.BITS_64_BE, - (AllocationFunction<long[]>) SegmentAllocator::allocateArray, - ToArrayHelper.toLongArray }, - { AllocationFactory.BOUNDED, MemoryLayouts.BITS_64_BE, - (AllocationFunction<double[]>) SegmentAllocator::allocateArray, - ToArrayHelper.toDoubleArray }, - { AllocationFactory.BOUNDED, MemoryLayouts.ADDRESS.withOrder(ByteOrder.BIG_ENDIAN), - (AllocationFunction<MemoryAddress[]>) SegmentAllocator::allocateArray, - ToArrayHelper.toAddressArray }, - - { AllocationFactory.UNBOUNDED, MemoryLayouts.BITS_8_LE, - (AllocationFunction<byte[]>) SegmentAllocator::allocateArray, - ToArrayHelper.toByteArray }, - { AllocationFactory.UNBOUNDED, MemoryLayouts.BITS_16_LE, - (AllocationFunction<short[]>) SegmentAllocator::allocateArray, - ToArrayHelper.toShortArray }, - { AllocationFactory.UNBOUNDED, - MemoryLayouts.BITS_32_LE, - (AllocationFunction<int[]>) SegmentAllocator::allocateArray, - ToArrayHelper.toIntArray }, - { AllocationFactory.UNBOUNDED, MemoryLayouts.BITS_32_LE, - (AllocationFunction<float[]>) SegmentAllocator::allocateArray, - ToArrayHelper.toFloatArray }, - { AllocationFactory.UNBOUNDED, MemoryLayouts.BITS_64_LE, - (AllocationFunction<long[]>) SegmentAllocator::allocateArray, - ToArrayHelper.toLongArray }, - { AllocationFactory.UNBOUNDED, MemoryLayouts.BITS_64_LE, - (AllocationFunction<double[]>) SegmentAllocator::allocateArray, - ToArrayHelper.toDoubleArray }, - { AllocationFactory.UNBOUNDED, MemoryLayouts.ADDRESS.withOrder(ByteOrder.LITTLE_ENDIAN), - (AllocationFunction<MemoryAddress[]>) SegmentAllocator::allocateArray, - ToArrayHelper.toAddressArray }, - - - { AllocationFactory.UNBOUNDED, MemoryLayouts.BITS_8_BE, - (AllocationFunction<byte[]>) SegmentAllocator::allocateArray, - ToArrayHelper.toByteArray }, - { AllocationFactory.UNBOUNDED, MemoryLayouts.BITS_16_BE, - (AllocationFunction<short[]>) SegmentAllocator::allocateArray, - ToArrayHelper.toShortArray }, - { AllocationFactory.UNBOUNDED, - MemoryLayouts.BITS_32_BE, - (AllocationFunction<int[]>) SegmentAllocator::allocateArray, - ToArrayHelper.toIntArray }, - { AllocationFactory.UNBOUNDED, MemoryLayouts.BITS_32_BE, - (AllocationFunction<float[]>) SegmentAllocator::allocateArray, - ToArrayHelper.toFloatArray }, - { AllocationFactory.UNBOUNDED, MemoryLayouts.BITS_64_BE, - (AllocationFunction<long[]>) SegmentAllocator::allocateArray, - ToArrayHelper.toLongArray }, - { AllocationFactory.UNBOUNDED, MemoryLayouts.BITS_64_BE, - (AllocationFunction<double[]>) SegmentAllocator::allocateArray, - ToArrayHelper.toDoubleArray }, - { AllocationFactory.UNBOUNDED, MemoryLayouts.ADDRESS.withOrder(ByteOrder.BIG_ENDIAN), - (AllocationFunction<MemoryAddress[]>) SegmentAllocator::allocateArray, - ToArrayHelper.toAddressArray }, + List<Object[]> arrayScopes = new ArrayList<>(); + for (AllocationFactory factory : AllocationFactory.values()) { + arrayScopes.add(new Object[] { factory, ValueLayout.JAVA_BYTE, + (AllocationFunction.OfByteArray) SegmentAllocator::allocateArray, + ToArrayHelper.toByteArray }); + arrayScopes.add(new Object[] { factory, ValueLayout.JAVA_CHAR.withOrder(ByteOrder.LITTLE_ENDIAN), + (AllocationFunction.OfCharArray) SegmentAllocator::allocateArray, + ToArrayHelper.toCharArray }); + arrayScopes.add(new Object[] { factory, ValueLayout.JAVA_SHORT.withOrder(ByteOrder.LITTLE_ENDIAN), + (AllocationFunction.OfShortArray) SegmentAllocator::allocateArray, + ToArrayHelper.toShortArray }); + arrayScopes.add(new Object[] { factory, + ValueLayout.JAVA_INT.withOrder(ByteOrder.LITTLE_ENDIAN), + (AllocationFunction.OfIntArray) SegmentAllocator::allocateArray, + ToArrayHelper.toIntArray }); + arrayScopes.add(new Object[] { factory, ValueLayout.JAVA_FLOAT.withOrder(ByteOrder.LITTLE_ENDIAN), + (AllocationFunction.OfFloatArray) SegmentAllocator::allocateArray, + ToArrayHelper.toFloatArray }); + arrayScopes.add(new Object[] { factory, ValueLayout.JAVA_LONG.withOrder(ByteOrder.LITTLE_ENDIAN), + (AllocationFunction.OfLongArray) SegmentAllocator::allocateArray, + ToArrayHelper.toLongArray }); + arrayScopes.add(new Object[] { factory, ValueLayout.JAVA_DOUBLE.withOrder(ByteOrder.LITTLE_ENDIAN), + (AllocationFunction.OfDoubleArray) SegmentAllocator::allocateArray, + ToArrayHelper.toDoubleArray }); + + arrayScopes.add(new Object[] { factory, ValueLayout.JAVA_CHAR.withOrder(ByteOrder.BIG_ENDIAN), + (AllocationFunction.OfCharArray) SegmentAllocator::allocateArray, + ToArrayHelper.toCharArray }); + arrayScopes.add(new Object[] { factory, ValueLayout.JAVA_SHORT.withOrder(ByteOrder.BIG_ENDIAN), + (AllocationFunction.OfShortArray) SegmentAllocator::allocateArray, + ToArrayHelper.toShortArray }); + arrayScopes.add(new Object[] { factory, + ValueLayout.JAVA_INT.withOrder(ByteOrder.BIG_ENDIAN), + (AllocationFunction.OfIntArray) SegmentAllocator::allocateArray, + ToArrayHelper.toIntArray }); + arrayScopes.add(new Object[] { factory, ValueLayout.JAVA_FLOAT.withOrder(ByteOrder.BIG_ENDIAN), + (AllocationFunction.OfFloatArray) SegmentAllocator::allocateArray, + ToArrayHelper.toFloatArray }); + arrayScopes.add(new Object[] { factory, ValueLayout.JAVA_LONG.withOrder(ByteOrder.BIG_ENDIAN), + (AllocationFunction.OfLongArray) SegmentAllocator::allocateArray, + ToArrayHelper.toLongArray }); + arrayScopes.add(new Object[] { factory, ValueLayout.JAVA_DOUBLE.withOrder(ByteOrder.BIG_ENDIAN), + (AllocationFunction.OfDoubleArray) SegmentAllocator::allocateArray, + ToArrayHelper.toDoubleArray }); }; + return arrayScopes.toArray(Object[][]::new); } - interface AllocationFunction<X> { - MemorySegment allocate(SegmentAllocator allocator, ValueLayout layout, X value); + interface AllocationFunction<X, L extends ValueLayout> { + MemorySegment allocate(SegmentAllocator allocator, L layout, X value); + + interface OfByte extends AllocationFunction<Byte, ValueLayout.OfByte> { } + interface OfBoolean extends AllocationFunction<Boolean, ValueLayout.OfBoolean> { } + interface OfChar extends AllocationFunction<Character, ValueLayout.OfChar> { } + interface OfShort extends AllocationFunction<Short, ValueLayout.OfShort> { } + interface OfInt extends AllocationFunction<Integer, ValueLayout.OfInt> { } + interface OfFloat extends AllocationFunction<Float, ValueLayout.OfFloat> { } + interface OfLong extends AllocationFunction<Long, ValueLayout.OfLong> { } + interface OfDouble extends AllocationFunction<Double, ValueLayout.OfDouble> { } + interface OfAddress extends AllocationFunction<MemoryAddress, ValueLayout.OfAddress> { } + + interface OfByteArray extends AllocationFunction<byte[], ValueLayout.OfByte> { } + interface OfCharArray extends AllocationFunction<char[], ValueLayout.OfChar> { } + interface OfShortArray extends AllocationFunction<short[], ValueLayout.OfShort> { } + interface OfIntArray extends AllocationFunction<int[], ValueLayout.OfInt> { } + interface OfFloatArray extends AllocationFunction<float[], ValueLayout.OfFloat> { } + interface OfLongArray extends AllocationFunction<long[], ValueLayout.OfLong> { } + interface OfDoubleArray extends AllocationFunction<double[], ValueLayout.OfDouble> { } } - static class AllocationFactory { + enum AllocationFactory { + ARENA_BOUNDED(true, SegmentAllocator::newNativeArena), + ARENA_UNBOUNDED(false, (size, scope) -> SegmentAllocator.newNativeArena(scope)), + NATIVE_ALLOCATOR(false, (size, scope) -> SegmentAllocator.nativeAllocator(scope)), + IMPLICIT_ALLOCATOR(false, (size, scope) -> SegmentAllocator.implicitAllocator()); + private final boolean isBound; private final BiFunction<Long, ResourceScope, SegmentAllocator> factory; - private AllocationFactory(boolean isBound, BiFunction<Long, ResourceScope, SegmentAllocator> factory) { + AllocationFactory(boolean isBound, BiFunction<Long, ResourceScope, SegmentAllocator> factory) { this.isBound = isBound; this.factory = factory; } @@ -372,9 +304,6 @@ public class TestSegmentAllocators { public boolean isBound() { return isBound; } - - static AllocationFactory BOUNDED = new AllocationFactory(true, SegmentAllocator::arenaAllocator); - static AllocationFactory UNBOUNDED = new AllocationFactory(false, (size, scope) -> SegmentAllocator.arenaAllocator(scope)); } interface ToArrayHelper<T> { @@ -396,6 +325,21 @@ public class TestSegmentAllocators { } }; + ToArrayHelper<char[]> toCharArray = new ToArrayHelper<>() { + @Override + public char[] array() { + return new char[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + } + + @Override + public char[] toArray(MemorySegment segment, ValueLayout layout) { + CharBuffer buffer = segment.asByteBuffer().order(layout.order()).asCharBuffer(); + char[] found = new char[buffer.limit()]; + buffer.get(found); + return found; + } + }; + ToArrayHelper<short[]> toShortArray = new ToArrayHelper<>() { @Override public short[] array() { @@ -474,7 +418,7 @@ public class TestSegmentAllocators { ToArrayHelper<MemoryAddress[]> toAddressArray = new ToArrayHelper<>() { @Override public MemoryAddress[] array() { - return switch ((int)MemoryLayouts.ADDRESS.byteSize()) { + return switch ((int) ValueLayout.ADDRESS.byteSize()) { case 4 -> wrap(toIntArray.array()); case 8 -> wrap(toLongArray.array()); default -> throw new IllegalStateException("Cannot get here"); diff --git a/test/jdk/java/foreign/TestSegmentCopy.java b/test/jdk/java/foreign/TestSegmentCopy.java new file mode 100644 index 0000000000000000000000000000000000000000..1185f4360271072a0b03661f66d58719f47e326e --- /dev/null +++ b/test/jdk/java/foreign/TestSegmentCopy.java @@ -0,0 +1,219 @@ +/* + * 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. + * + */ + +/* + * @test + * @run testng TestSegmentCopy + */ + +import jdk.incubator.foreign.MemoryHandles; +import jdk.incubator.foreign.MemorySegment; +import jdk.incubator.foreign.ResourceScope; +import jdk.incubator.foreign.ValueLayout; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +import java.lang.invoke.VarHandle; +import java.nio.ByteOrder; +import java.util.ArrayList; +import java.util.List; +import java.util.function.IntFunction; + +import static jdk.incubator.foreign.ValueLayout.JAVA_BYTE; +import static org.testng.Assert.*; + +public class TestSegmentCopy { + + @Test(dataProvider = "slices") + public void testByteCopy(SegmentSlice s1, SegmentSlice s2) { + int size = Math.min(s1.byteSize(), s2.byteSize()); + //prepare source and target segments + for (int i = 0 ; i < size ; i++) { + Type.BYTE.set(s2, i, 0); + } + for (int i = 0 ; i < size ; i++) { + Type.BYTE.set(s1, i, i); + } + //perform copy + MemorySegment.copy(s1.segment, 0, s2.segment, 0, size); + //check that copy actually worked + for (int i = 0 ; i < size ; i++) { + Type.BYTE.check(s2, i, i); + } + } + + @Test(dataProvider = "slices") + public void testElementCopy(SegmentSlice s1, SegmentSlice s2) { + if (s1.type.carrier != s2.type.carrier) return; + int size = Math.min(s1.elementSize(), s2.elementSize()); + //prepare source and target segments + for (int i = 0 ; i < size ; i++) { + s2.set(i, 0); + } + for (int i = 0 ; i < size ; i++) { + s1.set(i, i); + } + //perform copy + MemorySegment.copy(s1.segment, s1.type.layout, 0, s2.segment, s2.type.layout, 0, size); + //check that copy actually worked + for (int i = 0; i < size; i++) { + s2.check(i, i); + } + } + + @Test(expectedExceptions = IllegalArgumentException.class) + public void testHyperAlignedSrc() { + MemorySegment segment = MemorySegment.ofArray(new byte[] {1, 2, 3, 4}); + MemorySegment.copy(segment, 0, segment, JAVA_BYTE.withBitAlignment(16), 0, 4); + } + + @Test(expectedExceptions = IllegalArgumentException.class) + public void testHyperAlignedDst() { + MemorySegment segment = MemorySegment.ofArray(new byte[] {1, 2, 3, 4}); + MemorySegment.copy(segment, JAVA_BYTE.withBitAlignment(16), 0, segment, 0, 4); + } + + enum Type { + // Byte + BYTE(byte.class, ValueLayout.JAVA_BYTE, i -> (byte)i), + //LE + SHORT_LE(short.class, ValueLayout.JAVA_SHORT.withOrder(ByteOrder.LITTLE_ENDIAN), i -> (short)i), + CHAR_LE(char.class, ValueLayout.JAVA_CHAR.withOrder(ByteOrder.LITTLE_ENDIAN), i -> (char)i), + INT_LE(int.class, ValueLayout.JAVA_INT.withOrder(ByteOrder.LITTLE_ENDIAN), i -> i), + FLOAT_LE(float.class, ValueLayout.JAVA_FLOAT.withOrder(ByteOrder.LITTLE_ENDIAN), i -> (float)i), + LONG_LE(long.class, ValueLayout.JAVA_LONG.withOrder(ByteOrder.LITTLE_ENDIAN), i -> (long)i), + DOUBLE_LE(double.class, ValueLayout.JAVA_DOUBLE.withOrder(ByteOrder.LITTLE_ENDIAN), i -> (double)i), + //BE + SHORT_BE(short.class, ValueLayout.JAVA_SHORT.withOrder(ByteOrder.BIG_ENDIAN), i -> (short)i), + CHAR_BE(char.class, ValueLayout.JAVA_CHAR.withOrder(ByteOrder.BIG_ENDIAN), i -> (char)i), + INT_BE(int.class, ValueLayout.JAVA_INT.withOrder(ByteOrder.BIG_ENDIAN), i -> i), + FLOAT_BE(float.class, ValueLayout.JAVA_FLOAT.withOrder(ByteOrder.BIG_ENDIAN), i -> (float)i), + LONG_BE(long.class, ValueLayout.JAVA_LONG.withOrder(ByteOrder.BIG_ENDIAN), i -> (long)i), + DOUBLE_BE(double.class, ValueLayout.JAVA_DOUBLE.withOrder(ByteOrder.BIG_ENDIAN), i -> (double)i); + + final ValueLayout layout; + final IntFunction<Object> valueConverter; + final Class<?> carrier; + + @SuppressWarnings("unchecked") + <Z> Type(Class<Z> carrier, ValueLayout layout, IntFunction<Z> valueConverter) { + this.carrier = carrier; + this.layout = layout; + this.valueConverter = (IntFunction<Object>)valueConverter; + } + + int size() { + return (int)layout.byteSize(); + } + + VarHandle handle() { + return MemoryHandles.varHandle(layout); + } + + void set(SegmentSlice slice, int index, int val) { + handle().set(slice.segment, index * size(), valueConverter.apply(val)); + } + + void check(SegmentSlice slice, int index, int val) { + assertEquals(handle().get(slice.segment, index * size()), valueConverter.apply(val)); + } + } + + static class SegmentSlice { + + enum Kind { + NATIVE(i -> MemorySegment.allocateNative(i, ResourceScope.newImplicitScope())), + ARRAY(i -> MemorySegment.ofArray(new byte[i])); + + final IntFunction<MemorySegment> segmentFactory; + + Kind(IntFunction<MemorySegment> segmentFactory) { + this.segmentFactory = segmentFactory; + } + + MemorySegment makeSegment(int elems) { + return segmentFactory.apply(elems); + } + } + + final Kind kind; + final Type type; + final int first; + final int last; + final MemorySegment segment; + + public SegmentSlice(Kind kind, Type type, int first, int last, MemorySegment segment) { + this.kind = kind; + this.type = type; + this.first = first; + this.last = last; + this.segment = segment; + } + + void set(int index, int val) { + type.set(this, index, val); + } + + void check(int index, int val) { + type.check(this, index, val); + } + + int byteSize() { + return last - first + 1; + } + + int elementSize() { + return byteSize() / type.size(); + } + + @Override + public String toString() { + return String.format("SegmentSlice{%s, %d, %d}", type, first, last); + } + } + + @DataProvider(name = "slices") + static Object[][] elementSlices() { + List<SegmentSlice> slices = new ArrayList<>(); + for (SegmentSlice.Kind kind : SegmentSlice.Kind.values()) { + MemorySegment segment = kind.makeSegment(16); + //compute all slices + for (Type type : Type.values()) { + for (int index = 0; index < 16; index += type.size()) { + MemorySegment first = segment.asSlice(0, index); + slices.add(new SegmentSlice(kind, type, 0, index - 1, first)); + MemorySegment second = segment.asSlice(index); + slices.add(new SegmentSlice(kind, type, index, 15, second)); + } + } + } + Object[][] sliceArray = new Object[slices.size() * slices.size()][]; + for (int i = 0 ; i < slices.size() ; i++) { + for (int j = 0 ; j < slices.size() ; j++) { + sliceArray[i * slices.size() + j] = new Object[] { slices.get(i), slices.get(j) }; + } + } + return sliceArray; + } +} diff --git a/test/jdk/java/foreign/TestRebase.java b/test/jdk/java/foreign/TestSegmentOffset.java similarity index 68% rename from test/jdk/java/foreign/TestRebase.java rename to test/jdk/java/foreign/TestSegmentOffset.java index 0396523c8a55882994166d85728bfcdf3acf2637..b9149f2471f43e69f31b90bef3d7e657fd32632f 100644 --- a/test/jdk/java/foreign/TestRebase.java +++ b/test/jdk/java/foreign/TestSegmentOffset.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -16,60 +16,58 @@ * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * Please 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 - * @run testng TestRebase + * @run testng TestSegmentOffset */ -import jdk.incubator.foreign.MemoryAccess; -import jdk.incubator.foreign.MemoryAddress; import jdk.incubator.foreign.MemorySegment; import jdk.incubator.foreign.ResourceScope; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; - import java.util.ArrayList; import java.util.List; import java.util.function.IntFunction; - +import static java.lang.System.out; +import static jdk.incubator.foreign.ValueLayout.JAVA_BYTE; import static org.testng.Assert.*; -public class TestRebase { +public class TestSegmentOffset { @Test(dataProvider = "slices") - public void testRebase(SegmentSlice s1, SegmentSlice s2) { + public void testOffset(SegmentSlice s1, SegmentSlice s2) { if (s1.contains(s2)) { - //check that an address and its rebased counterpart point to same element - MemoryAddress base = s2.segment.address(); - long offset = base.segmentOffset(s1.segment); + // check that a segment and its overlapping segment point to same elements + long offset = s1.segment.segmentOffset(s2.segment); for (int i = 0; i < s2.size(); i++) { - int expected = MemoryAccess.getByteAtOffset(s2.segment, i); - int found = (int)MemoryAccess.getByteAtOffset(s1.segment, i + offset); + out.format("testOffset s1:%s, s2:%s, offset:%d, i:%s\n", s1, s2, offset, i); + byte expected = s2.segment.get(JAVA_BYTE, i); + byte found = s1.segment.get(JAVA_BYTE, i + offset); assertEquals(found, expected); } } else if (s1.kind != s2.kind) { - // check that rebase s1 to s2 fails + // check that offset from s1 to s2 fails try { - s1.segment.address().segmentOffset(s2.segment); - fail("Rebase unexpectedly passed!"); - } catch (IllegalArgumentException ex) { - assertTrue(true); + long offset = s1.segment.segmentOffset(s2.segment); + out.format("testOffset s1:%s, s2:%s, offset:%d\n", s1, s2, offset); + fail("offset unexpectedly passed!"); + } catch (UnsupportedOperationException ex) { + assertTrue(ex.getMessage().contains("Cannot compute offset from native to heap (or vice versa).")); } } else if (!s2.contains(s1)) { - //disjoint segments - check that rebased address is out of bounds - MemoryAddress base = s2.segment.address(); - long offset = base.segmentOffset(s1.segment); + // disjoint segments - check that offset is out of bounds + long offset = s1.segment.segmentOffset(s2.segment); for (int i = 0; i < s2.size(); i++) { - MemoryAccess.getByteAtOffset(s2.segment, i); + out.format("testOffset s1:%s, s2:%s, offset:%d, i:%s\n", s1, s2, offset, i); + s2.segment.get(JAVA_BYTE, i); try { - MemoryAccess.getByteAtOffset(s1.segment, i + offset); - fail("Rebased address on a disjoint segment is not out of bounds!"); + s1.segment.get(JAVA_BYTE, i + offset); + fail("Offset on a disjoint segment is not out of bounds!"); } catch (IndexOutOfBoundsException ex) { assertTrue(true); } @@ -80,7 +78,7 @@ public class TestRebase { static class SegmentSlice { enum Kind { - NATIVE(i -> MemorySegment.allocateNative(i, ResourceScope.newImplicitScope())), + NATIVE(i -> MemorySegment.allocateNative(i, ResourceScope.newConfinedScope())), ARRAY(i -> MemorySegment.ofArray(new byte[i])); final IntFunction<MemorySegment> segmentFactory; @@ -122,12 +120,12 @@ public class TestRebase { int[] sizes = { 16, 8, 4, 2, 1 }; List<SegmentSlice> slices = new ArrayList<>(); for (SegmentSlice.Kind kind : SegmentSlice.Kind.values()) { - //init root segment + // init root segment MemorySegment segment = kind.makeSegment(16); for (int i = 0 ; i < 16 ; i++) { - MemoryAccess.setByteAtOffset(segment, i, (byte)i); + segment.set(JAVA_BYTE, i, (byte)i); } - //compute all slices + // compute all slices for (int size : sizes) { for (int index = 0 ; index < 16 ; index += size) { MemorySegment slice = segment.asSlice(index, size); diff --git a/test/jdk/java/foreign/TestSegmentOverlap.java b/test/jdk/java/foreign/TestSegmentOverlap.java new file mode 100644 index 0000000000000000000000000000000000000000..fb55e92dedb9046d8b743ec77fba9ea43af05cfd --- /dev/null +++ b/test/jdk/java/foreign/TestSegmentOverlap.java @@ -0,0 +1,142 @@ +/* + * 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. + */ + +/* + * @test + * @run testng/othervm TestSegmentOverlap + */ + +import java.io.File; +import java.io.IOException; +import java.nio.channels.FileChannel; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; +import java.util.List; +import java.util.function.Supplier; +import jdk.incubator.foreign.MemorySegment; +import jdk.incubator.foreign.ResourceScope; +import org.testng.annotations.Test; +import org.testng.annotations.DataProvider; +import static java.lang.System.out; +import static org.testng.Assert.*; + +public class TestSegmentOverlap { + + static Path tempPath; + + static { + try { + File file = File.createTempFile("buffer", "txt"); + file.deleteOnExit(); + tempPath = file.toPath(); + Files.write(file.toPath(), new byte[16], StandardOpenOption.WRITE); + + } catch (IOException ex) { + throw new ExceptionInInitializerError(ex); + } + } + + @DataProvider(name = "segmentFactories") + public Object[][] segmentFactories() { + List<Supplier<MemorySegment>> l = List.of( + () -> MemorySegment.allocateNative(16, ResourceScope.newConfinedScope()), + () -> { + try { + return MemorySegment.mapFile(tempPath, 0L, 16, FileChannel.MapMode.READ_WRITE, ResourceScope.newConfinedScope()); + } catch (IOException e) { + throw new RuntimeException(e); + } + }, + () -> MemorySegment.ofArray(new byte[] { 0x00, 0x01, 0x02, 0x03 } ), + () -> MemorySegment.ofArray(new char[] {'a', 'b', 'c', 'd' } ), + () -> MemorySegment.ofArray(new double[] { 1d, 2d, 3d, 4d} ), + () -> MemorySegment.ofArray(new float[] { 1.0f, 2.0f, 3.0f, 4.0f } ), + () -> MemorySegment.ofArray(new int[] { 1, 2, 3, 4 }), + () -> MemorySegment.ofArray(new long[] { 1L, 2L, 3L, 4L } ), + () -> MemorySegment.ofArray(new short[] { 1, 2, 3, 4 } ) + ); + return l.stream().map(s -> new Object[] { s }).toArray(Object[][]::new); + } + + @Test(dataProvider="segmentFactories") + public void testBasic(Supplier<MemorySegment> segmentSupplier) { + var s1 = segmentSupplier.get(); + var s2 = segmentSupplier.get(); + var sOther = s1.isNative() ? OtherSegmentFactory.HEAP.factory.get() + : OtherSegmentFactory.NATIVE.factory.get(); + out.format("testBasic s1:%s, s2:%s, sOther:%s\n", s1, s2, sOther); + assertNull(s1.asOverlappingSlice(s2)); + assertNull(s2.asOverlappingSlice(s1)); + assertNull(s1.asOverlappingSlice(sOther)); + } + + @Test(dataProvider="segmentFactories") + public void testIdentical(Supplier<MemorySegment> segmentSupplier) { + var s1 = segmentSupplier.get(); + var s2 = s1.asReadOnly(); + out.format("testIdentical s1:%s, s2:%s\n", s1, s2); + assertEquals(s1.asOverlappingSlice(s2).byteSize(), s1.byteSize()); + assertEquals(s1.asOverlappingSlice(s2).scope(), s1.scope()); + + assertEquals(s2.asOverlappingSlice(s1).byteSize(), s2.byteSize()); + assertEquals(s2.asOverlappingSlice(s1).scope(), s2.scope()); + + if (s1.isNative()) { + assertEquals(s1.asOverlappingSlice(s2).address(), s1.address()); + assertEquals(s2.asOverlappingSlice(s1).address(), s2.address()); + } + } + + @Test(dataProvider="segmentFactories") + public void testSlices(Supplier<MemorySegment> segmentSupplier) { + MemorySegment s1 = segmentSupplier.get(); + MemorySegment s2 = segmentSupplier.get(); + for (int offset = 0 ; offset < 4 ; offset++) { + MemorySegment slice = s1.asSlice(offset); + out.format("testSlices s1:%s, s2:%s, slice:%s, offset:%d\n", s1, s2, slice, offset); + assertEquals(s1.asOverlappingSlice(slice).byteSize(), s1.byteSize() - offset); + assertEquals(s1.asOverlappingSlice(slice).scope(), s1.scope()); + + assertEquals(slice.asOverlappingSlice(s1).byteSize(), slice.byteSize()); + assertEquals(slice.asOverlappingSlice(s1).scope(), slice.scope()); + + if (s1.isNative()) { + assertEquals(s1.asOverlappingSlice(slice).address(), s1.address().addOffset(offset)); + assertEquals(slice.asOverlappingSlice(s1).address(), slice.address()); + } + assertNull(s2.asOverlappingSlice(slice)); + } + } + + enum OtherSegmentFactory { + NATIVE(() -> MemorySegment.allocateNative(16, ResourceScope.newConfinedScope())), + HEAP(() -> MemorySegment.ofArray(new byte[]{16})); + + final Supplier<MemorySegment> factory; + + OtherSegmentFactory(Supplier<MemorySegment> segmentFactory) { + this.factory = segmentFactory; + } + } +} diff --git a/test/jdk/java/foreign/TestSegments.java b/test/jdk/java/foreign/TestSegments.java index beadf1618ac076e22c0c94f201bc8abe15bef7f2..fdf373448230ae6bfe7f508a77e8dd9a772c6b14 100644 --- a/test/jdk/java/foreign/TestSegments.java +++ b/test/jdk/java/foreign/TestSegments.java @@ -27,23 +27,21 @@ * @run testng/othervm -Xmx4G -XX:MaxDirectMemorySize=1M TestSegments */ -import jdk.incubator.foreign.MemoryAccess; import jdk.incubator.foreign.MemoryLayout; -import jdk.incubator.foreign.MemoryLayouts; import jdk.incubator.foreign.MemorySegment; import jdk.incubator.foreign.ResourceScope; +import jdk.incubator.foreign.ValueLayout; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import java.lang.invoke.VarHandle; import java.nio.ByteBuffer; -import java.nio.ByteOrder; import java.util.List; import java.util.concurrent.atomic.AtomicReference; import java.util.function.IntFunction; -import java.util.function.LongFunction; import java.util.function.Supplier; +import static jdk.incubator.foreign.ValueLayout.JAVA_INT; import static org.testng.Assert.*; public class TestSegments { @@ -53,11 +51,6 @@ public class TestSegments { MemorySegment.allocateNative(size, align, ResourceScope.newImplicitScope()); } - @Test(dataProvider = "badLayouts", expectedExceptions = UnsupportedOperationException.class) - public void testBadAllocateLayout(MemoryLayout layout) { - MemorySegment.allocateNative(layout, ResourceScope.newImplicitScope()); - } - @Test(expectedExceptions = { OutOfMemoryError.class, IllegalArgumentException.class }) public void testAllocateTooBig() { @@ -71,8 +64,8 @@ public class TestSegments { @Test public void testNativeSegmentIsZeroed() { - VarHandle byteHandle = MemoryLayout.sequenceLayout(MemoryLayouts.JAVA_BYTE) - .varHandle(byte.class, MemoryLayout.PathElement.sequenceElement()); + VarHandle byteHandle = MemoryLayout.sequenceLayout(ValueLayout.JAVA_BYTE) + .varHandle(MemoryLayout.PathElement.sequenceElement()); try (ResourceScope scope = ResourceScope.newConfinedScope()) { MemorySegment segment = MemorySegment.allocateNative(1000, 1, scope); for (long i = 0 ; i < segment.byteSize() ; i++) { @@ -83,8 +76,8 @@ public class TestSegments { @Test public void testSlices() { - VarHandle byteHandle = MemoryLayout.sequenceLayout(MemoryLayouts.JAVA_BYTE) - .varHandle(byte.class, MemoryLayout.PathElement.sequenceElement()); + VarHandle byteHandle = MemoryLayout.sequenceLayout(ValueLayout.JAVA_BYTE) + .varHandle(MemoryLayout.PathElement.sequenceElement()); try (ResourceScope scope = ResourceScope.newConfinedScope()) { MemorySegment segment = MemorySegment.allocateNative(10, 1, scope); //init @@ -107,14 +100,14 @@ public class TestSegments { public void testSmallSegmentMax() { long offset = (long)Integer.MAX_VALUE + (long)Integer.MAX_VALUE + 2L + 6L; // overflows to 6 when casted to int MemorySegment memorySegment = MemorySegment.allocateNative(10, ResourceScope.newImplicitScope()); - MemoryAccess.getIntAtOffset(memorySegment, offset); + memorySegment.get(JAVA_INT, offset); } @Test(expectedExceptions = IndexOutOfBoundsException.class) public void testSmallSegmentMin() { long offset = ((long)Integer.MIN_VALUE * 2L) + 6L; // underflows to 6 when casted to int MemorySegment memorySegment = MemorySegment.allocateNative(10, ResourceScope.newImplicitScope()); - MemoryAccess.getIntAtOffset(memorySegment, offset); + memorySegment.get(JAVA_INT, offset); } @Test(dataProvider = "segmentFactories") @@ -125,7 +118,7 @@ public class TestSegments { } static void tryClose(MemorySegment segment) { - if (!segment.scope().isImplicit()) { + if (segment.scope() != ResourceScope.globalScope()) { segment.scope().close(); } } @@ -142,10 +135,10 @@ public class TestSegments { () -> MemorySegment.ofArray(new short[] { 1, 2, 3, 4 } ), () -> MemorySegment.allocateNative(4, ResourceScope.newImplicitScope()), () -> MemorySegment.allocateNative(4, 8, ResourceScope.newImplicitScope()), - () -> MemorySegment.allocateNative(MemoryLayout.valueLayout(32, ByteOrder.nativeOrder()), ResourceScope.newImplicitScope()), - () -> MemorySegment.allocateNative(4, ResourceScope.newConfinedScope()), - () -> MemorySegment.allocateNative(4, 8, ResourceScope.newConfinedScope()), - () -> MemorySegment.allocateNative(MemoryLayout.valueLayout(32, ByteOrder.nativeOrder()), ResourceScope.newConfinedScope()) + () -> MemorySegment.allocateNative(JAVA_INT, ResourceScope.newImplicitScope()), + () -> MemorySegment.allocateNative(4, ResourceScope.newImplicitScope()), + () -> MemorySegment.allocateNative(4, 8, ResourceScope.newImplicitScope()), + () -> MemorySegment.allocateNative(JAVA_INT, ResourceScope.newImplicitScope()) ); return l.stream().map(s -> new Object[] { s }).toArray(Object[][]::new); @@ -153,8 +146,8 @@ public class TestSegments { @Test(dataProvider = "segmentFactories") public void testFill(Supplier<MemorySegment> memorySegmentSupplier) { - VarHandle byteHandle = MemoryLayout.sequenceLayout(MemoryLayouts.JAVA_BYTE) - .varHandle(byte.class, MemoryLayout.PathElement.sequenceElement()); + VarHandle byteHandle = MemoryLayout.sequenceLayout(ValueLayout.JAVA_BYTE) + .varHandle(MemoryLayout.PathElement.sequenceElement()); for (byte value : new byte[] {(byte) 0xFF, (byte) 0x00, (byte) 0x45}) { MemorySegment segment = memorySegmentSupplier.get(); @@ -193,15 +186,13 @@ public class TestSegments { } @Test(dataProvider = "segmentFactories") - public void testNativeSegments(Supplier<MemorySegment> memorySegmentSupplier) throws Exception { + public void testNativeSegments(Supplier<MemorySegment> memorySegmentSupplier) { MemorySegment segment = memorySegmentSupplier.get(); try { - segment.address().toRawLongValue(); + segment.address(); assertTrue(segment.isNative()); - assertTrue(segment.address().isNative()); } catch (UnsupportedOperationException exception) { assertFalse(segment.isNative()); - assertFalse(segment.address().isNative()); } tryClose(segment); } @@ -262,33 +253,6 @@ public class TestSegments { }; } - @DataProvider(name = "badLayouts") - public Object[][] layouts() { - SizedLayoutFactory[] layoutFactories = SizedLayoutFactory.values(); - Object[][] values = new Object[layoutFactories.length * 2][2]; - for (int i = 0; i < layoutFactories.length ; i++) { - values[i * 2] = new Object[] { MemoryLayout.structLayout(layoutFactories[i].make(7), MemoryLayout.paddingLayout(9)) }; // good size, bad align - values[(i * 2) + 1] = new Object[] { layoutFactories[i].make(15).withBitAlignment(16) }; // bad size, good align - } - return values; - } - - enum SizedLayoutFactory { - VALUE_BE(size -> MemoryLayout.valueLayout(size, ByteOrder.BIG_ENDIAN)), - VALUE_LE(size -> MemoryLayout.valueLayout(size, ByteOrder.LITTLE_ENDIAN)), - PADDING(MemoryLayout::paddingLayout); - - private final LongFunction<MemoryLayout> factory; - - SizedLayoutFactory(LongFunction<MemoryLayout> factory) { - this.factory = factory; - } - - MemoryLayout make(long size) { - return factory.apply(size); - } - } - @DataProvider(name = "heapFactories") public Object[][] heapFactories() { return new Object[][] { diff --git a/test/jdk/java/foreign/TestSharedAccess.java b/test/jdk/java/foreign/TestSharedAccess.java index b5b5f717b46e53b371c69e9e61be36338dc05ed1..346d92acef7cac6db97c5b4e82df92ca0b111067 100644 --- a/test/jdk/java/foreign/TestSharedAccess.java +++ b/test/jdk/java/foreign/TestSharedAccess.java @@ -43,11 +43,11 @@ import static org.testng.Assert.*; public class TestSharedAccess { - static final VarHandle intHandle = MemoryLayouts.JAVA_INT.varHandle(int.class); + static final VarHandle intHandle = ValueLayout.JAVA_INT.varHandle(); @Test public void testShared() throws Throwable { - SequenceLayout layout = MemoryLayout.sequenceLayout(1024, MemoryLayouts.JAVA_INT); + SequenceLayout layout = MemoryLayout.sequenceLayout(1024, ValueLayout.JAVA_INT); try (ResourceScope scope = ResourceScope.newSharedScope()) { MemorySegment s = MemorySegment.allocateNative(layout, scope); for (int i = 0 ; i < layout.elementCount().getAsLong() ; i++) { @@ -98,7 +98,7 @@ public class TestSharedAccess { setInt(s, 42); assertEquals(getInt(s), 42); List<Thread> threads = new ArrayList<>(); - MemorySegment sharedSegment = s.address().asSegment(s.byteSize(), scope); + MemorySegment sharedSegment = MemorySegment.ofAddress(s.address(), s.byteSize(), scope); for (int i = 0 ; i < 1000 ; i++) { threads.add(new Thread(() -> { assertEquals(getInt(sharedSegment), 42); @@ -121,7 +121,7 @@ public class TestSharedAccess { CountDownLatch b = new CountDownLatch(1); CompletableFuture<?> r; try (ResourceScope scope = ResourceScope.newConfinedScope()) { - MemorySegment s1 = MemorySegment.allocateNative(MemoryLayout.sequenceLayout(2, MemoryLayouts.JAVA_INT), scope); + MemorySegment s1 = MemorySegment.allocateNative(MemoryLayout.sequenceLayout(2, ValueLayout.JAVA_INT), scope); r = CompletableFuture.runAsync(() -> { try { ByteBuffer bb = s1.asByteBuffer(); diff --git a/test/jdk/java/foreign/TestSlices.java b/test/jdk/java/foreign/TestSlices.java index da9ad9135b1cadfae73fbbc2632dce1d416a2420..0cdc392cd93a9244493ab3b32ecdcdb8b703cdc0 100644 --- a/test/jdk/java/foreign/TestSlices.java +++ b/test/jdk/java/foreign/TestSlices.java @@ -23,12 +23,12 @@ */ import jdk.incubator.foreign.MemoryLayout; -import jdk.incubator.foreign.MemoryLayouts; import jdk.incubator.foreign.MemorySegment; import java.lang.invoke.VarHandle; import jdk.incubator.foreign.ResourceScope; +import jdk.incubator.foreign.ValueLayout; import org.testng.annotations.*; import static org.testng.Assert.*; @@ -39,9 +39,9 @@ import static org.testng.Assert.*; public class TestSlices { static MemoryLayout LAYOUT = MemoryLayout.sequenceLayout(2, - MemoryLayout.sequenceLayout(5, MemoryLayouts.JAVA_INT)); + MemoryLayout.sequenceLayout(5, ValueLayout.JAVA_INT)); - static VarHandle VH_ALL = LAYOUT.varHandle(int.class, + static VarHandle VH_ALL = LAYOUT.varHandle( MemoryLayout.PathElement.sequenceElement(), MemoryLayout.PathElement.sequenceElement()); @Test(dataProvider = "slices") @@ -76,16 +76,16 @@ public class TestSlices { // x { VH_ALL, 2, 5, new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 } }, // x[0::2] - { LAYOUT.varHandle(int.class, MemoryLayout.PathElement.sequenceElement(), + { LAYOUT.varHandle(MemoryLayout.PathElement.sequenceElement(), MemoryLayout.PathElement.sequenceElement(0, 2)), 2, 3, new int[] { 1, 3, 5, 6, 8, 10 } }, // x[1::2] - { LAYOUT.varHandle(int.class, MemoryLayout.PathElement.sequenceElement(), + { LAYOUT.varHandle(MemoryLayout.PathElement.sequenceElement(), MemoryLayout.PathElement.sequenceElement(1, 2)), 2, 2, new int[] { 2, 4, 7, 9 } }, // x[4::-2] - { LAYOUT.varHandle(int.class, MemoryLayout.PathElement.sequenceElement(), + { LAYOUT.varHandle(MemoryLayout.PathElement.sequenceElement(), MemoryLayout.PathElement.sequenceElement(4, -2)), 2, 3, new int[] { 5, 3, 1, 10, 8, 6 } }, // x[3::-2] - { LAYOUT.varHandle(int.class, MemoryLayout.PathElement.sequenceElement(), + { LAYOUT.varHandle(MemoryLayout.PathElement.sequenceElement(), MemoryLayout.PathElement.sequenceElement(3, -2)), 2, 2, new int[] { 4, 2, 9, 7 } }, }; } diff --git a/test/jdk/java/foreign/TestSpliterator.java b/test/jdk/java/foreign/TestSpliterator.java index d8c3fe24e0a9ac213f3ca5548af8a9cb6ba20171..7fcd6a16d3628d4a06b6e2dca5b041231c567942 100644 --- a/test/jdk/java/foreign/TestSpliterator.java +++ b/test/jdk/java/foreign/TestSpliterator.java @@ -27,7 +27,6 @@ */ import jdk.incubator.foreign.MemoryLayout; -import jdk.incubator.foreign.MemoryLayouts; import jdk.incubator.foreign.MemorySegment; import jdk.incubator.foreign.ResourceScope; import jdk.incubator.foreign.SequenceLayout; @@ -40,22 +39,22 @@ import java.util.concurrent.CountedCompleter; import java.util.concurrent.RecursiveTask; import java.util.concurrent.atomic.AtomicLong; import java.util.stream.LongStream; -import java.util.stream.StreamSupport; +import jdk.incubator.foreign.ValueLayout; import org.testng.annotations.*; import static org.testng.Assert.*; public class TestSpliterator { - static final VarHandle INT_HANDLE = MemoryLayout.sequenceLayout(MemoryLayouts.JAVA_INT) - .varHandle(int.class, MemoryLayout.PathElement.sequenceElement()); + static final VarHandle INT_HANDLE = MemoryLayout.sequenceLayout(ValueLayout.JAVA_INT) + .varHandle(MemoryLayout.PathElement.sequenceElement()); final static int CARRIER_SIZE = 4; @Test(dataProvider = "splits") public void testSum(int size, int threshold) { - SequenceLayout layout = MemoryLayout.sequenceLayout(size, MemoryLayouts.JAVA_INT); + SequenceLayout layout = MemoryLayout.sequenceLayout(size, ValueLayout.JAVA_INT); //setup try (ResourceScope scope = ResourceScope.newSharedScope()) { @@ -82,7 +81,7 @@ public class TestSpliterator { @Test public void testSumSameThread() { - SequenceLayout layout = MemoryLayout.sequenceLayout(1024, MemoryLayouts.JAVA_INT); + SequenceLayout layout = MemoryLayout.sequenceLayout(1024, ValueLayout.JAVA_INT); //setup MemorySegment segment = MemorySegment.allocateNative(layout, ResourceScope.newImplicitScope()); @@ -100,32 +99,37 @@ public class TestSpliterator { @Test(expectedExceptions = IllegalArgumentException.class) public void testBadSpliteratorElementSizeTooBig() { - MemorySegment.ofArray(new byte[2]).spliterator(MemoryLayouts.JAVA_INT); + MemorySegment.ofArray(new byte[2]).spliterator(ValueLayout.JAVA_INT); } @Test(expectedExceptions = IllegalArgumentException.class) public void testBadStreamElementSizeTooBig() { - MemorySegment.ofArray(new byte[2]).elements(MemoryLayouts.JAVA_INT); + MemorySegment.ofArray(new byte[2]).elements(ValueLayout.JAVA_INT); } @Test(expectedExceptions = IllegalArgumentException.class) public void testBadSpliteratorElementSizeNotMultiple() { - MemorySegment.ofArray(new byte[7]).spliterator(MemoryLayouts.JAVA_INT); + MemorySegment.ofArray(new byte[7]).spliterator(ValueLayout.JAVA_INT); } @Test(expectedExceptions = IllegalArgumentException.class) public void testBadStreamElementSizeNotMultiple() { - MemorySegment.ofArray(new byte[7]).elements(MemoryLayouts.JAVA_INT); + MemorySegment.ofArray(new byte[7]).elements(ValueLayout.JAVA_INT); } @Test(expectedExceptions = IllegalArgumentException.class) public void testBadSpliteratorElementSizeZero() { - MemorySegment.ofArray(new byte[7]).spliterator(MemoryLayout.sequenceLayout(0, MemoryLayouts.JAVA_INT)); + MemorySegment.ofArray(new byte[7]).spliterator(MemoryLayout.sequenceLayout(0, ValueLayout.JAVA_INT)); } @Test(expectedExceptions = IllegalArgumentException.class) public void testBadStreamElementSizeZero() { - MemorySegment.ofArray(new byte[7]).elements(MemoryLayout.sequenceLayout(0, MemoryLayouts.JAVA_INT)); + MemorySegment.ofArray(new byte[7]).elements(MemoryLayout.sequenceLayout(0, ValueLayout.JAVA_INT)); + } + + @Test(expectedExceptions = IllegalArgumentException.class) + public void testHyperAligned() { + MemorySegment.ofArray(new byte[8]).elements(MemoryLayout.sequenceLayout(2, ValueLayout.JAVA_INT.withBitAlignment(64))); } static long sumSingle(long acc, MemorySegment segment) { diff --git a/test/jdk/java/foreign/TestStringEncoding.java b/test/jdk/java/foreign/TestStringEncoding.java index 90fae756ada7fd17488f3650c28ca7b291d1d0f8..baa14db9d9bb475ef81e18e6724d4e0943511d2e 100644 --- a/test/jdk/java/foreign/TestStringEncoding.java +++ b/test/jdk/java/foreign/TestStringEncoding.java @@ -22,10 +22,10 @@ * */ -import jdk.incubator.foreign.CLinker; import jdk.incubator.foreign.MemorySegment; import jdk.incubator.foreign.ResourceScope; +import jdk.incubator.foreign.SegmentAllocator; import org.testng.annotations.*; import static org.testng.Assert.*; @@ -40,11 +40,12 @@ public class TestStringEncoding { @Test(dataProvider = "strings") public void testStrings(String testString, int expectedByteLength) { try (ResourceScope scope = ResourceScope.newConfinedScope()) { - MemorySegment text = CLinker.toCString(testString, scope); + SegmentAllocator allocator = SegmentAllocator.newNativeArena(expectedByteLength, scope); + MemorySegment text = allocator.allocateUtf8String(testString); assertEquals(text.byteSize(), expectedByteLength); - String roundTrip = CLinker.toJavaString(text); + String roundTrip = text.getUtf8String(0); assertEquals(roundTrip, testString); } } diff --git a/test/jdk/java/foreign/TestSymbolLookup.java b/test/jdk/java/foreign/TestSymbolLookup.java index 1cc537d5261e63fd8b9b01338767d31e95c0663c..fa76aa89ce3f78ba3193d2cc227698dfaaefb584 100644 --- a/test/jdk/java/foreign/TestSymbolLookup.java +++ b/test/jdk/java/foreign/TestSymbolLookup.java @@ -29,12 +29,12 @@ */ import jdk.incubator.foreign.SymbolLookup; -import jdk.incubator.foreign.MemoryAccess; -import jdk.incubator.foreign.MemoryLayouts; import jdk.incubator.foreign.MemorySegment; import jdk.incubator.foreign.ResourceScope; +import jdk.incubator.foreign.ValueLayout; import org.testng.annotations.Test; +import static jdk.incubator.foreign.ValueLayout.JAVA_BYTE; import static org.testng.Assert.*; // FYI this test is run on 64-bit platforms only for now, @@ -61,7 +61,7 @@ public class TestSymbolLookup { @Test public void testVariableSymbolLookup() { - MemorySegment segment = LOOKUP.lookup("c").get().asSegment(MemoryLayouts.JAVA_INT.byteSize(), ResourceScope.globalScope()); - assertEquals(MemoryAccess.getInt(segment), 42); + MemorySegment segment = MemorySegment.ofAddress(LOOKUP.lookup("c").get().address(), ValueLayout.JAVA_INT.byteSize(), ResourceScope.globalScope()); + assertEquals(segment.get(JAVA_BYTE, 0), 42); } } diff --git a/test/jdk/java/foreign/TestTypeAccess.java b/test/jdk/java/foreign/TestTypeAccess.java index 9683f58987f4af25a19eb63005eb1b58d0896a2b..dc3ee8434bdc9d3065d6af475ebf91b412535a28 100644 --- a/test/jdk/java/foreign/TestTypeAccess.java +++ b/test/jdk/java/foreign/TestTypeAccess.java @@ -27,10 +27,9 @@ * @run testng TestTypeAccess */ -import jdk.incubator.foreign.MemoryHandles; import jdk.incubator.foreign.MemorySegment; -import jdk.incubator.foreign.MemoryLayouts; import jdk.incubator.foreign.ResourceScope; +import jdk.incubator.foreign.ValueLayout; import org.testng.annotations.*; import java.lang.invoke.VarHandle; @@ -38,24 +37,17 @@ import java.lang.invoke.WrongMethodTypeException; public class TestTypeAccess { - static final VarHandle INT_HANDLE = MemoryLayouts.JAVA_INT.varHandle(int.class); - - static final VarHandle ADDR_HANDLE = MemoryHandles.asAddressVarHandle(INT_HANDLE); + static final VarHandle INT_HANDLE = ValueLayout.JAVA_INT.varHandle(); + static final VarHandle ADDR_HANDLE = ValueLayout.ADDRESS.varHandle(); @Test(expectedExceptions=ClassCastException.class) public void testMemoryAddressCoordinateAsString() { - try (ResourceScope scope = ResourceScope.newConfinedScope()) { - MemorySegment s = MemorySegment.allocateNative(8, 8, scope); - int v = (int)INT_HANDLE.get("string"); - } + int v = (int)INT_HANDLE.get("string"); } @Test(expectedExceptions=WrongMethodTypeException.class) public void testMemoryCoordinatePrimitive() { - try (ResourceScope scope = ResourceScope.newConfinedScope()) { - MemorySegment s = MemorySegment.allocateNative(8, 8, scope); - int v = (int)INT_HANDLE.get(1); - } + int v = (int)INT_HANDLE.get(1); } @Test(expectedExceptions=ClassCastException.class) diff --git a/test/jdk/java/foreign/TestUnsupportedPlatform.java b/test/jdk/java/foreign/TestUnsupportedPlatform.java index 478cac72e33b88a7f2ae0a52c8bc798fa1a25441..eb1b5cf53a4154469bc0d4819faf133739827410 100644 --- a/test/jdk/java/foreign/TestUnsupportedPlatform.java +++ b/test/jdk/java/foreign/TestUnsupportedPlatform.java @@ -39,7 +39,7 @@ public class TestUnsupportedPlatform { @Test(expectedExceptions = ExceptionInInitializerError.class) public void testNoInitialization() { - CLinker.getInstance(); // trigger initialization + CLinker.systemCLinker(); // trigger initialization } } diff --git a/test/jdk/java/foreign/TestUpcall.java b/test/jdk/java/foreign/TestUpcall.java index 2b679e8539647f4c0e97e068698620ba0f4d8c38..c6959d7d131c2e0d4fe0f4e83496de6819e1acff 100644 --- a/test/jdk/java/foreign/TestUpcall.java +++ b/test/jdk/java/foreign/TestUpcall.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -23,24 +23,51 @@ */ /* - * @test + * @test id=scope * @requires ((os.arch == "amd64" | os.arch == "x86_64") & sun.arch.data.model == "64") | os.arch == "aarch64" * @modules jdk.incubator.foreign/jdk.internal.foreign * @build NativeTestHelper CallGeneratorHelper TestUpcall * * @run testng/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyDependencies * --enable-native-access=ALL-UNNAMED -Dgenerator.sample.factor=17 + * -DUPCALL_TEST_TYPE=SCOPE + * TestUpcall + */ + +/* + * @test id=no_scope + * @requires ((os.arch == "amd64" | os.arch == "x86_64") & sun.arch.data.model == "64") | os.arch == "aarch64" + * @modules jdk.incubator.foreign/jdk.internal.foreign + * @build NativeTestHelper CallGeneratorHelper TestUpcall + * + * @run testng/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyDependencies + * --enable-native-access=ALL-UNNAMED -Dgenerator.sample.factor=17 + * -DUPCALL_TEST_TYPE=NO_SCOPE + * TestUpcall + */ + +/* + * @test id=async + * @requires ((os.arch == "amd64" | os.arch == "x86_64") & sun.arch.data.model == "64") | os.arch == "aarch64" + * @modules jdk.incubator.foreign/jdk.internal.foreign + * @build NativeTestHelper CallGeneratorHelper TestUpcall + * + * @run testng/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyDependencies + * --enable-native-access=ALL-UNNAMED -Dgenerator.sample.factor=17 + * -DUPCALL_TEST_TYPE=ASYNC * TestUpcall */ import jdk.incubator.foreign.CLinker; import jdk.incubator.foreign.FunctionDescriptor; +import jdk.incubator.foreign.NativeSymbol; +import jdk.incubator.foreign.SegmentAllocator; import jdk.incubator.foreign.SymbolLookup; -import jdk.incubator.foreign.MemoryAddress; import jdk.incubator.foreign.MemoryLayout; import jdk.incubator.foreign.MemorySegment; import jdk.incubator.foreign.ResourceScope; +import org.testng.SkipException; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; @@ -48,22 +75,32 @@ import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; import java.util.stream.Collectors; import static java.lang.invoke.MethodHandles.insertArguments; -import static jdk.incubator.foreign.CLinker.C_POINTER; import static org.testng.Assert.assertEquals; public class TestUpcall extends CallGeneratorHelper { + private enum TestType { + SCOPE, + NO_SCOPE, + ASYNC + } + + private static final TestType UPCALL_TEST_TYPE = TestType.valueOf(System.getProperty("UPCALL_TEST_TYPE")); + static { System.loadLibrary("TestUpcall"); + System.loadLibrary("AsyncInvokers"); } - static CLinker abi = CLinker.getInstance(); + static CLinker abi = CLinker.systemCLinker(); static final SymbolLookup LOOKUP = SymbolLookup.loaderLookup(); @@ -80,22 +117,29 @@ public class TestUpcall extends CallGeneratorHelper { } } - static MemoryAddress dummyStub; + static NativeSymbol dummyStub; @BeforeClass void setup() { dummyStub = abi.upcallStub(DUMMY, FunctionDescriptor.ofVoid(), ResourceScope.newImplicitScope()); } + private static void checkSelected(TestType type) { + if (UPCALL_TEST_TYPE != type) + throw new SkipException("Skipping tests that were not selected"); + } + @Test(dataProvider="functions", dataProviderClass=CallGeneratorHelper.class) public void testUpcalls(int count, String fName, Ret ret, List<ParamType> paramTypes, List<StructFieldType> fields) throws Throwable { + checkSelected(TestType.SCOPE); + List<Consumer<Object>> returnChecks = new ArrayList<>(); List<Consumer<Object[]>> argChecks = new ArrayList<>(); - MemoryAddress addr = LOOKUP.lookup(fName).get(); - MethodType mtype = methodType(ret, paramTypes, fields); - try (NativeScope scope = new NativeScope()) { - MethodHandle mh = abi.downcallHandle(addr, scope, mtype, function(ret, paramTypes, fields)); - Object[] args = makeArgs(scope.scope(), ret, paramTypes, fields, returnChecks, argChecks); + NativeSymbol addr = LOOKUP.lookup(fName).get(); + try (ResourceScope scope = ResourceScope.newConfinedScope()) { + SegmentAllocator allocator = SegmentAllocator.newNativeArena(scope); + MethodHandle mh = downcallHandle(abi, addr, allocator, function(ret, paramTypes, fields)); + Object[] args = makeArgs(scope, ret, paramTypes, fields, returnChecks, argChecks); Object[] callArgs = args; Object res = mh.invokeWithArguments(callArgs); argChecks.forEach(c -> c.accept(args)); @@ -106,29 +150,57 @@ public class TestUpcall extends CallGeneratorHelper { } @Test(dataProvider="functions", dataProviderClass=CallGeneratorHelper.class) - public void testUpcallsNoScope(int count, String fName, Ret ret, List<ParamType> paramTypes, List<StructFieldType> fields) throws Throwable { + public void testUpcallsAsync(int count, String fName, Ret ret, List<ParamType> paramTypes, List<StructFieldType> fields) throws Throwable { + checkSelected(TestType.ASYNC); List<Consumer<Object>> returnChecks = new ArrayList<>(); List<Consumer<Object[]>> argChecks = new ArrayList<>(); - MemoryAddress addr = LOOKUP.lookup(fName).get(); - MethodType mtype = methodType(ret, paramTypes, fields); - MethodHandle mh = abi.downcallHandle(addr, IMPLICIT_ALLOCATOR, mtype, function(ret, paramTypes, fields)); - Object[] args = makeArgs(ResourceScope.newImplicitScope(), ret, paramTypes, fields, returnChecks, argChecks); - Object[] callArgs = args; - Object res = mh.invokeWithArguments(callArgs); - argChecks.forEach(c -> c.accept(args)); - if (ret == Ret.NON_VOID) { - returnChecks.forEach(c -> c.accept(res)); + NativeSymbol addr = LOOKUP.lookup(fName).get(); + try (ResourceScope scope = ResourceScope.newSharedScope()) { + SegmentAllocator allocator = SegmentAllocator.newNativeArena(scope); + FunctionDescriptor descriptor = function(ret, paramTypes, fields); + MethodHandle mh = downcallHandle(abi, addr, allocator, descriptor); + Object[] args = makeArgs(ResourceScope.newImplicitScope(), ret, paramTypes, fields, returnChecks, argChecks); + + mh = mh.asSpreader(Object[].class, args.length); + mh = MethodHandles.insertArguments(mh, 0, (Object) args); + FunctionDescriptor callbackDesc = descriptor.returnLayout() + .map(FunctionDescriptor::of) + .orElse(FunctionDescriptor.ofVoid()); + NativeSymbol callback = abi.upcallStub(mh.asType(CLinker.upcallType(callbackDesc)), callbackDesc, scope); + + MethodHandle invoker = asyncInvoker(ret, ret == Ret.VOID ? null : paramTypes.get(0), fields); + + Object res = invoker.type().returnType() == MemorySegment.class + ? invoker.invoke(allocator, callback) + : invoker.invoke(callback); + argChecks.forEach(c -> c.accept(args)); + if (ret == Ret.NON_VOID) { + returnChecks.forEach(c -> c.accept(res)); + } } } - static MethodType methodType(Ret ret, List<ParamType> params, List<StructFieldType> fields) { - MethodType mt = ret == Ret.VOID ? - MethodType.methodType(void.class) : MethodType.methodType(paramCarrier(params.get(0).layout(fields))); - for (ParamType p : params) { - mt = mt.appendParameterTypes(paramCarrier(p.layout(fields))); + private static final Map<String, MethodHandle> INVOKERS = new HashMap<>(); + + private MethodHandle asyncInvoker(Ret ret, ParamType returnType, List<StructFieldType> fields) { + if (ret == Ret.VOID) { + String name = "call_async_V"; + return INVOKERS.computeIfAbsent(name, symbol -> + abi.downcallHandle( + LOOKUP.lookup(symbol).orElseThrow(), + FunctionDescriptor.ofVoid(C_POINTER))); } - mt = mt.appendParameterTypes(MemoryAddress.class); //the callback - return mt; + + String name = "call_async_" + returnType.name().charAt(0) + + (returnType == ParamType.STRUCT ? "_" + sigCode(fields) : ""); + + return INVOKERS.computeIfAbsent(name, symbol -> { + NativeSymbol invokerSymbol = LOOKUP.lookup(symbol).orElseThrow(); + MemoryLayout returnLayout = returnType.layout(fields); + FunctionDescriptor desc = FunctionDescriptor.of(returnLayout, C_POINTER); + + return abi.downcallHandle(invokerSymbol, desc); + }); } static FunctionDescriptor function(Ret ret, List<ParamType> params, List<StructFieldType> fields) { @@ -150,9 +222,9 @@ public class TestUpcall extends CallGeneratorHelper { } @SuppressWarnings("unchecked") - static MemoryAddress makeCallback(ResourceScope scope, Ret ret, List<ParamType> params, List<StructFieldType> fields, List<Consumer<Object>> checks, List<Consumer<Object[]>> argChecks) { + static NativeSymbol makeCallback(ResourceScope scope, Ret ret, List<ParamType> params, List<StructFieldType> fields, List<Consumer<Object>> checks, List<Consumer<Object[]>> argChecks) { if (params.isEmpty()) { - return dummyStub.address(); + return dummyStub; } AtomicReference<Object[]> box = new AtomicReference<>(); @@ -162,7 +234,7 @@ public class TestUpcall extends CallGeneratorHelper { for (int i = 0; i < params.size(); i++) { ParamType pt = params.get(i); MemoryLayout layout = pt.layout(fields); - Class<?> carrier = paramCarrier(layout); + Class<?> carrier = carrier(layout, false); mh = mh.asType(mh.type().changeParameterType(i, carrier)); final int finalI = i; @@ -175,7 +247,7 @@ public class TestUpcall extends CallGeneratorHelper { ParamType firstParam = params.get(0); MemoryLayout firstlayout = firstParam.layout(fields); - Class<?> firstCarrier = paramCarrier(firstlayout); + Class<?> firstCarrier = carrier(firstlayout, true); if (firstCarrier == MemorySegment.class) { checks.add(o -> assertStructEquals((MemorySegment) box.get()[0], (MemorySegment) o, firstlayout)); diff --git a/test/jdk/java/foreign/TestUpcallException.java b/test/jdk/java/foreign/TestUpcallException.java index d6630a74d77ce41a714760130a1d229cc509ef84..900b9c58513c3bc0f5050784d7d7589c371bf541 100644 --- a/test/jdk/java/foreign/TestUpcallException.java +++ b/test/jdk/java/foreign/TestUpcallException.java @@ -33,9 +33,6 @@ * TestUpcallException */ -import jdk.incubator.foreign.CLinker; -import jdk.incubator.foreign.FunctionDescriptor; -import jdk.incubator.foreign.ResourceScope; import jdk.test.lib.Utils; import org.testng.annotations.Test; @@ -54,17 +51,17 @@ public class TestUpcallException { @Test public void testExceptionInterpreted() throws InterruptedException, IOException { - boolean useSpec = false; - run(useSpec); + run(/* useSpec = */ false, /* isVoid = */ true); + run(/* useSpec = */ false, /* isVoid = */ false); } @Test public void testExceptionSpecialized() throws IOException, InterruptedException { - boolean useSpec = true; - run(useSpec); + run(/* useSpec = */ true, /* isVoid = */ true); + run(/* useSpec = */ true, /* isVoid = */ false); } - private void run(boolean useSpec) throws IOException, InterruptedException { + private void run(boolean useSpec, boolean isVoid) throws IOException, InterruptedException { Process process = new ProcessBuilder() .command( Paths.get(Utils.TEST_JDK) @@ -77,7 +74,8 @@ public class TestUpcallException { "-Djava.library.path=" + System.getProperty("java.library.path"), "-Djdk.internal.foreign.ProgrammableUpcallHandler.USE_SPEC=" + useSpec, "-cp", Utils.TEST_CLASS_PATH, - "ThrowingUpcall") + "ThrowingUpcall", + isVoid ? "void" : "non-void") .start(); int result = process.waitFor(); diff --git a/test/jdk/java/foreign/TestUpcallHighArity.java b/test/jdk/java/foreign/TestUpcallHighArity.java index dfe819c97e22fe385a9c6b7c7f0db6563539d28e..b025de9ed4ad4c5b311a89b47f1acbff9e75e9e9 100644 --- a/test/jdk/java/foreign/TestUpcallHighArity.java +++ b/test/jdk/java/foreign/TestUpcallHighArity.java @@ -33,8 +33,10 @@ * TestUpcallHighArity */ +import jdk.incubator.foreign.Addressable; import jdk.incubator.foreign.CLinker; import jdk.incubator.foreign.FunctionDescriptor; +import jdk.incubator.foreign.NativeSymbol; import jdk.incubator.foreign.SymbolLookup; import jdk.incubator.foreign.MemoryAddress; import jdk.incubator.foreign.MemoryLayout; @@ -49,13 +51,12 @@ import java.lang.invoke.MethodType; import java.util.List; import java.util.concurrent.atomic.AtomicReference; -import static jdk.incubator.foreign.CLinker.*; import static org.testng.Assert.assertEquals; public class TestUpcallHighArity extends CallGeneratorHelper { static final MethodHandle MH_do_upcall; static final MethodHandle MH_passAndSave; - static final CLinker LINKER = CLinker.getInstance(); + static final CLinker LINKER = CLinker.systemCLinker(); // struct S_PDI { void* p0; double p1; int p2; }; static final MemoryLayout S_PDI_LAYOUT = MemoryLayout.structLayout( @@ -70,12 +71,7 @@ public class TestUpcallHighArity extends CallGeneratorHelper { SymbolLookup lookup = SymbolLookup.loaderLookup(); MH_do_upcall = LINKER.downcallHandle( lookup.lookup("do_upcall").get(), - MethodType.methodType(void.class, MemoryAddress.class, - MemorySegment.class, int.class, double.class, MemoryAddress.class, - MemorySegment.class, int.class, double.class, MemoryAddress.class, - MemorySegment.class, int.class, double.class, MemoryAddress.class, - MemorySegment.class, int.class, double.class, MemoryAddress.class), - FunctionDescriptor.ofVoid(C_POINTER, + FunctionDescriptor.ofVoid(C_POINTER, S_PDI_LAYOUT, C_INT, C_DOUBLE, C_POINTER, S_PDI_LAYOUT, C_INT, C_DOUBLE, C_POINTER, S_PDI_LAYOUT, C_INT, C_DOUBLE, C_POINTER, @@ -108,9 +104,9 @@ public class TestUpcallHighArity extends CallGeneratorHelper { .asCollector(Object[].class, upcallType.parameterCount()) .asType(upcallType); try (ResourceScope scope = ResourceScope.newConfinedScope()) { - MemoryAddress upcallStub = LINKER.upcallStub(target, upcallDescriptor, scope); + NativeSymbol upcallStub = LINKER.upcallStub(target, upcallDescriptor, scope); Object[] args = new Object[upcallType.parameterCount() + 1]; - args[0] = upcallStub.address(); + args[0] = upcallStub; List<MemoryLayout> argLayouts = upcallDescriptor.argumentLayouts(); for (int i = 1; i < args.length; i++) { args[i] = makeArg(argLayouts.get(i - 1), null, false); @@ -123,7 +119,7 @@ public class TestUpcallHighArity extends CallGeneratorHelper { if (upcallType.parameterType(i) == MemorySegment.class) { assertStructEquals((MemorySegment) capturedArgsArr[i], (MemorySegment) args[i + 1], argLayouts.get(i)); } else { - assertEquals(capturedArgsArr[i], args[i + 1]); + assertEquals(capturedArgsArr[i], args[i + 1], "For index " + i); } } } diff --git a/test/jdk/java/foreign/TestUpcallStructScope.java b/test/jdk/java/foreign/TestUpcallStructScope.java index 72bb1eafb9f09fb25bed6862e4098482bf995473..045d6191a9d50582d3cbaa441d08ad4640bac07f 100644 --- a/test/jdk/java/foreign/TestUpcallStructScope.java +++ b/test/jdk/java/foreign/TestUpcallStructScope.java @@ -37,8 +37,10 @@ * TestUpcallStructScope */ +import jdk.incubator.foreign.Addressable; import jdk.incubator.foreign.CLinker; import jdk.incubator.foreign.FunctionDescriptor; +import jdk.incubator.foreign.NativeSymbol; import jdk.incubator.foreign.SymbolLookup; import jdk.incubator.foreign.MemoryAddress; import jdk.incubator.foreign.MemoryLayout; @@ -52,14 +54,11 @@ import java.lang.invoke.MethodType; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; -import static jdk.incubator.foreign.CLinker.C_DOUBLE; -import static jdk.incubator.foreign.CLinker.C_INT; -import static jdk.incubator.foreign.CLinker.C_POINTER; import static org.testng.Assert.assertFalse; -public class TestUpcallStructScope { +public class TestUpcallStructScope extends NativeTestHelper { static final MethodHandle MH_do_upcall; - static final CLinker LINKER = CLinker.getInstance(); + static final CLinker LINKER = CLinker.systemCLinker(); static final MethodHandle MH_Consumer_accept; // struct S_PDI { void* p0; double p1; int p2; }; @@ -74,8 +73,7 @@ public class TestUpcallStructScope { SymbolLookup lookup = SymbolLookup.loaderLookup(); MH_do_upcall = LINKER.downcallHandle( lookup.lookup("do_upcall").get(), - MethodType.methodType(void.class, MemoryAddress.class, MemorySegment.class), - FunctionDescriptor.ofVoid(C_POINTER, S_PDI_LAYOUT) + FunctionDescriptor.ofVoid(C_POINTER, S_PDI_LAYOUT) ); try { @@ -96,9 +94,9 @@ public class TestUpcallStructScope { MethodHandle target = methodHandle(capturedSegment::set); FunctionDescriptor upcallDesc = FunctionDescriptor.ofVoid(S_PDI_LAYOUT); try (ResourceScope scope = ResourceScope.newConfinedScope()) { - MemoryAddress upcallStub = LINKER.upcallStub(target, upcallDesc, scope); + NativeSymbol upcallStub = LINKER.upcallStub(target, upcallDesc, scope); MemorySegment argSegment = MemorySegment.allocateNative(S_PDI_LAYOUT, scope); - MH_do_upcall.invokeExact(upcallStub.address(), argSegment); + MH_do_upcall.invoke(upcallStub, argSegment); } MemorySegment captured = capturedSegment.get(); diff --git a/test/jdk/java/foreign/TestVarArgs.java b/test/jdk/java/foreign/TestVarArgs.java index 40ccea4e6845c828fbc0e405925fa15cc695c5ef..0efc22d7514601eaf78929bd8392b08ae065fea9 100644 --- a/test/jdk/java/foreign/TestVarArgs.java +++ b/test/jdk/java/foreign/TestVarArgs.java @@ -33,6 +33,7 @@ import jdk.incubator.foreign.FunctionDescriptor; import jdk.incubator.foreign.MemoryAddress; import jdk.incubator.foreign.MemoryLayout; import jdk.incubator.foreign.MemorySegment; +import jdk.incubator.foreign.NativeSymbol; import jdk.incubator.foreign.ResourceScope; import jdk.incubator.foreign.SymbolLookup; import jdk.incubator.foreign.ValueLayout; @@ -45,27 +46,26 @@ import java.lang.invoke.VarHandle; import java.util.ArrayList; import java.util.List; -import static jdk.incubator.foreign.CLinker.*; import static jdk.incubator.foreign.MemoryLayout.PathElement.*; import static org.testng.Assert.assertEquals; -public class TestVarArgs { +public class TestVarArgs extends NativeTestHelper { static final MemoryLayout ML_CallInfo = MemoryLayout.structLayout( C_POINTER.withName("writeback"), // writeback C_POINTER.withName("argIDs")); // arg ids - static final VarHandle VH_CallInfo_writeback = ML_CallInfo.varHandle(long.class, groupElement("writeback")); - static final VarHandle VH_CallInfo_argIDs = ML_CallInfo.varHandle(long.class, groupElement("argIDs")); + static final VarHandle VH_CallInfo_writeback = ML_CallInfo.varHandle(groupElement("writeback")); + static final VarHandle VH_CallInfo_argIDs = ML_CallInfo.varHandle(groupElement("argIDs")); - static final VarHandle VH_IntArray = MemoryLayout.sequenceLayout(C_INT).varHandle(int.class, sequenceElement()); + static final VarHandle VH_IntArray = MemoryLayout.sequenceLayout(C_INT).varHandle(sequenceElement()); - static final CLinker abi = CLinker.getInstance(); + static final CLinker abi = CLinker.systemCLinker(); static { System.loadLibrary("VarArgs"); } - static final MemoryAddress VARARGS_ADDR = + static final NativeSymbol VARARGS_ADDR = SymbolLookup.loaderLookup() .lookup("varargs").get(); @@ -80,8 +80,8 @@ public class TestVarArgs { MemoryAddress callInfoPtr = callInfo.address(); - VH_CallInfo_writeback.set(callInfo, writeBack.address().toRawLongValue()); - VH_CallInfo_argIDs.set(callInfo, argIDs.address().toRawLongValue()); + VH_CallInfo_writeback.set(callInfo, writeBack.address()); + VH_CallInfo_argIDs.set(callInfo, argIDs.address()); for (int i = 0; i < args.size(); i++) { VH_IntArray.set(argIDs, (long) i, args.get(i).id.ordinal()); @@ -90,9 +90,9 @@ public class TestVarArgs { List<MemoryLayout> argLayouts = new ArrayList<>(); argLayouts.add(C_POINTER); // call info argLayouts.add(C_INT); // size - args.forEach(a -> argLayouts.add(asVarArg(a.layout))); - FunctionDescriptor desc = FunctionDescriptor.ofVoid(argLayouts.toArray(MemoryLayout[]::new)); + FunctionDescriptor desc = FunctionDescriptor.ofVoid(argLayouts.stream().toArray(MemoryLayout[]::new)) + .asVariadic(args.stream().map(a -> a.layout).toArray(MemoryLayout[]::new)); List<Class<?>> carriers = new ArrayList<>(); carriers.add(MemoryAddress.class); // call info @@ -101,7 +101,7 @@ public class TestVarArgs { MethodType mt = MethodType.methodType(void.class, carriers); - MethodHandle downcallHandle = abi.downcallHandle(VARARGS_ADDR, mt, desc); + MethodHandle downcallHandle = abi.downcallHandle(VARARGS_ADDR, desc); List<Object> argValues = new ArrayList<>(); argValues.add(callInfoPtr); // call info @@ -140,7 +140,7 @@ public class TestVarArgs { this.value = value; this.layout = layout; this.carrier = carrier; - this.vh = layout.varHandle(carrier); + this.vh = layout.varHandle(); } static VarArg intArg(int value) { diff --git a/test/jdk/java/foreign/TestVarHandleCombinators.java b/test/jdk/java/foreign/TestVarHandleCombinators.java index 2090c31fdd9add38cde22a4e460cf66dc3f369fc..e2c9d0bcfc2833d094d4c0348fe3c70e0db420d0 100644 --- a/test/jdk/java/foreign/TestVarHandleCombinators.java +++ b/test/jdk/java/foreign/TestVarHandleCombinators.java @@ -29,6 +29,7 @@ import jdk.incubator.foreign.MemoryHandles; import jdk.incubator.foreign.ResourceScope; +import jdk.incubator.foreign.ValueLayout; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; @@ -43,16 +44,16 @@ public class TestVarHandleCombinators { @Test public void testElementAccess() { - VarHandle vh = MemoryHandles.varHandle(byte.class, ByteOrder.nativeOrder()); + VarHandle vh = MemoryHandles.varHandle(ValueLayout.JAVA_BYTE); byte[] arr = { 0, 0, -1, 0 }; MemorySegment segment = MemorySegment.ofArray(arr); assertEquals((byte) vh.get(segment, 2), (byte) -1); } - @Test(expectedExceptions = IllegalStateException.class) + @Test(expectedExceptions = IllegalArgumentException.class) public void testUnalignedElement() { - VarHandle vh = MemoryHandles.varHandle(byte.class, 4, ByteOrder.nativeOrder()); + VarHandle vh = MemoryHandles.varHandle(ValueLayout.JAVA_BYTE.withBitAlignment(32)); MemorySegment segment = MemorySegment.ofArray(new byte[4]); vh.get(segment, 2L); //should throw //FIXME: the VH only checks the alignment of the segment, which is fine if the VH is derived from layouts, @@ -60,19 +61,9 @@ public class TestVarHandleCombinators { //FIXME: at least until the VM is fixed } - @Test(expectedExceptions = IllegalArgumentException.class) - public void testAlignNotPowerOf2() { - VarHandle vh = MemoryHandles.varHandle(byte.class, 3, ByteOrder.nativeOrder()); - } - - @Test(expectedExceptions = IllegalArgumentException.class) - public void testAlignNegative() { - VarHandle vh = MemoryHandles.varHandle(byte.class, -1, ByteOrder.nativeOrder()); - } - @Test public void testAlign() { - VarHandle vh = MemoryHandles.varHandle(byte.class, 2, ByteOrder.nativeOrder()); + VarHandle vh = MemoryHandles.varHandle(ValueLayout.JAVA_BYTE.withBitAlignment(16)); MemorySegment segment = MemorySegment.allocateNative(1, 2, ResourceScope.newImplicitScope()); vh.set(segment, 0L, (byte) 10); // fine, memory region is aligned @@ -81,7 +72,7 @@ public class TestVarHandleCombinators { @Test public void testByteOrderLE() { - VarHandle vh = MemoryHandles.varHandle(short.class, 2, ByteOrder.LITTLE_ENDIAN); + VarHandle vh = MemoryHandles.varHandle(ValueLayout.JAVA_SHORT.withOrder(ByteOrder.LITTLE_ENDIAN)); byte[] arr = new byte[2]; MemorySegment segment = MemorySegment.ofArray(arr); vh.set(segment, 0L, (short) 0xFF); @@ -91,7 +82,7 @@ public class TestVarHandleCombinators { @Test public void testByteOrderBE() { - VarHandle vh = MemoryHandles.varHandle(short.class, 2, ByteOrder.BIG_ENDIAN); + VarHandle vh = MemoryHandles.varHandle(ValueLayout.JAVA_SHORT.withOrder(ByteOrder.BIG_ENDIAN)); byte[] arr = new byte[2]; MemorySegment segment = MemorySegment.ofArray(arr); vh.set(segment, 0L, (short) 0xFF); @@ -106,7 +97,7 @@ public class TestVarHandleCombinators { //[10 : [5 : [x32 i32]]] - VarHandle vh = MemoryHandles.varHandle(int.class, ByteOrder.nativeOrder()); + VarHandle vh = MemoryHandles.varHandle(ValueLayout.JAVA_INT.withBitAlignment(32)); int count = 0; try (ResourceScope scope = ResourceScope.newConfinedScope()) { MemorySegment segment = MemorySegment.allocateNative(inner_size * outer_size * 8, 4, scope); @@ -121,21 +112,4 @@ public class TestVarHandleCombinators { } } } - - @Test(dataProvider = "badCarriers", expectedExceptions = IllegalArgumentException.class) - public void testBadCarrier(Class<?> carrier) { - MemoryHandles.varHandle(carrier, ByteOrder.nativeOrder()); - } - - @DataProvider(name = "badCarriers") - public Object[][] createBadCarriers() { - return new Object[][] { - { void.class }, - { boolean.class }, - { Object.class }, - { int[].class }, - { MemorySegment.class } - }; - } - } diff --git a/test/jdk/java/foreign/ThrowingUpcall.java b/test/jdk/java/foreign/ThrowingUpcall.java index 405a89fc2f4c6e31a8189d1f8d0afd14856a6905..9efbf68565c35e9f840e159e0dacdc68dd09b679 100644 --- a/test/jdk/java/foreign/ThrowingUpcall.java +++ b/test/jdk/java/foreign/ThrowingUpcall.java @@ -23,29 +23,30 @@ import jdk.incubator.foreign.CLinker; import jdk.incubator.foreign.FunctionDescriptor; -import jdk.incubator.foreign.MemoryAddress; +import jdk.incubator.foreign.NativeSymbol; import jdk.incubator.foreign.ResourceScope; import jdk.incubator.foreign.SymbolLookup; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; -import java.security.Permission; -import static jdk.incubator.foreign.CLinker.C_POINTER; +public class ThrowingUpcall extends NativeTestHelper { -public class ThrowingUpcall { - - private static final MethodHandle downcall; + private static final MethodHandle downcallVoid; + private static final MethodHandle downcallNonVoid; public static final MethodHandle MH_throwException; static { System.loadLibrary("TestUpcall"); SymbolLookup lookup = SymbolLookup.loaderLookup(); - downcall = CLinker.getInstance().downcallHandle( + downcallVoid = CLinker.systemCLinker().downcallHandle( lookup.lookup("f0_V__").orElseThrow(), - MethodType.methodType(void.class, MemoryAddress.class), - FunctionDescriptor.ofVoid(C_POINTER) + FunctionDescriptor.ofVoid(C_POINTER) + ); + downcallNonVoid = CLinker.systemCLinker().downcallHandle( + lookup.lookup("f10_I_I_").orElseThrow(), + FunctionDescriptor.of(C_INT, C_INT, C_POINTER) ); try { @@ -61,18 +62,35 @@ public class ThrowingUpcall { } public static void main(String[] args) throws Throwable { - test(); + if (args[0].equals("void")) { + testVoid(); + } else { + testNonVoid(); + } } - public static void test() throws Throwable { + public static void testVoid() throws Throwable { MethodHandle handle = MH_throwException; MethodHandle invoker = MethodHandles.exactInvoker(MethodType.methodType(void.class)); handle = MethodHandles.insertArguments(invoker, 0, handle); try (ResourceScope scope = ResourceScope.newConfinedScope()) { - MemoryAddress stub = CLinker.getInstance().upcallStub(handle, FunctionDescriptor.ofVoid(), scope); + NativeSymbol stub = CLinker.systemCLinker().upcallStub(handle, FunctionDescriptor.ofVoid(), scope); + + downcallVoid.invoke(stub); // should call Shutdown.exit(1); + } + } + + public static void testNonVoid() throws Throwable { + MethodHandle handle = MethodHandles.identity(int.class); + handle = MethodHandles.collectArguments(handle, 0, MH_throwException); + MethodHandle invoker = MethodHandles.exactInvoker(MethodType.methodType(int.class, int.class)); + handle = MethodHandles.insertArguments(invoker, 0, handle); + + try (ResourceScope scope = ResourceScope.newConfinedScope()) { + NativeSymbol stub = CLinker.systemCLinker().upcallStub(handle, FunctionDescriptor.of(C_INT, C_INT), scope); - downcall.invokeExact(stub); // should call Shutdown.exit(1); + downcallNonVoid.invoke(42, stub); // should call Shutdown.exit(1); } } diff --git a/test/jdk/java/foreign/callarranger/TestAarch64CallArranger.java b/test/jdk/java/foreign/callarranger/TestAarch64CallArranger.java index eef17a4aad18d808b599338c1bd5443cc42c68a3..382b303f89b89c42b96742216dcba10d52c1e61f 100644 --- a/test/jdk/java/foreign/callarranger/TestAarch64CallArranger.java +++ b/test/jdk/java/foreign/callarranger/TestAarch64CallArranger.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -56,7 +56,7 @@ public class TestAarch64CallArranger extends CallArrangerTestBase { public void testEmpty() { MethodType mt = MethodType.methodType(void.class); FunctionDescriptor fd = FunctionDescriptor.ofVoid(); - CallArranger.Bindings bindings = CallArranger.getBindings(mt, fd, false); + CallArranger.Bindings bindings = CallArranger.LINUX.getBindings(mt, fd, false); assertFalse(bindings.isInMemoryReturn); CallingSequence callingSequence = bindings.callingSequence; @@ -78,7 +78,7 @@ public class TestAarch64CallArranger extends CallArrangerTestBase { C_INT, C_INT, C_INT, C_INT, C_INT, C_INT, C_INT, C_INT, C_INT, C_INT); - CallArranger.Bindings bindings = CallArranger.getBindings(mt, fd, false); + CallArranger.Bindings bindings = CallArranger.LINUX.getBindings(mt, fd, false); assertFalse(bindings.isInMemoryReturn); CallingSequence callingSequence = bindings.callingSequence; @@ -103,11 +103,11 @@ public class TestAarch64CallArranger extends CallArrangerTestBase { @Test public void testTwoIntTwoFloat() { - MethodType mt = MethodType.methodType(void.class, + MethodType mt = MethodType.methodType(void.class, int.class, int.class, float.class, float.class); FunctionDescriptor fd = FunctionDescriptor.ofVoid( C_INT, C_INT, C_FLOAT, C_FLOAT); - CallArranger.Bindings bindings = CallArranger.getBindings(mt, fd, false); + CallArranger.Bindings bindings = CallArranger.LINUX.getBindings(mt, fd, false); assertFalse(bindings.isInMemoryReturn); CallingSequence callingSequence = bindings.callingSequence; @@ -128,7 +128,7 @@ public class TestAarch64CallArranger extends CallArrangerTestBase { public void testStruct(MemoryLayout struct, Binding[] expectedBindings) { MethodType mt = MethodType.methodType(void.class, MemorySegment.class); FunctionDescriptor fd = FunctionDescriptor.ofVoid(struct); - CallArranger.Bindings bindings = CallArranger.getBindings(mt, fd, false); + CallArranger.Bindings bindings = CallArranger.LINUX.getBindings(mt, fd, false); assertFalse(bindings.isInMemoryReturn); CallingSequence callingSequence = bindings.callingSequence; @@ -157,8 +157,7 @@ public class TestAarch64CallArranger extends CallArrangerTestBase { // struct s { int32_t a, b; double c; int32_t d }; { struct2, new Binding[] { copy(struct2), - baseAddress(), - unboxAddress(), + unboxAddress(MemorySegment.class), vmStore(r0, long.class) }}, // struct s { int32_t a[2]; float b[2] }; @@ -188,7 +187,7 @@ public class TestAarch64CallArranger extends CallArrangerTestBase { MethodType mt = MethodType.methodType(void.class, MemorySegment.class, MemorySegment.class, int.class); FunctionDescriptor fd = FunctionDescriptor.ofVoid(struct1, struct2, C_INT); - CallArranger.Bindings bindings = CallArranger.getBindings(mt, fd, false); + CallArranger.Bindings bindings = CallArranger.LINUX.getBindings(mt, fd, false); assertFalse(bindings.isInMemoryReturn); CallingSequence callingSequence = bindings.callingSequence; @@ -198,14 +197,12 @@ public class TestAarch64CallArranger extends CallArrangerTestBase { checkArgumentBindings(callingSequence, new Binding[][]{ { copy(struct1), - baseAddress(), - unboxAddress(), + unboxAddress(MemorySegment.class), vmStore(r0, long.class) }, { copy(struct2), - baseAddress(), - unboxAddress(), + unboxAddress(MemorySegment.class), vmStore(r1, long.class) }, { vmStore(r2, int.class) } @@ -220,7 +217,7 @@ public class TestAarch64CallArranger extends CallArrangerTestBase { MethodType mt = MethodType.methodType(MemorySegment.class); FunctionDescriptor fd = FunctionDescriptor.of(struct); - CallArranger.Bindings bindings = CallArranger.getBindings(mt, fd, false); + CallArranger.Bindings bindings = CallArranger.LINUX.getBindings(mt, fd, false); assertTrue(bindings.isInMemoryReturn); CallingSequence callingSequence = bindings.callingSequence; @@ -243,7 +240,7 @@ public class TestAarch64CallArranger extends CallArrangerTestBase { MethodType mt = MethodType.methodType(MemorySegment.class); FunctionDescriptor fd = FunctionDescriptor.of(struct); - CallArranger.Bindings bindings = CallArranger.getBindings(mt, fd, false); + CallArranger.Bindings bindings = CallArranger.LINUX.getBindings(mt, fd, false); assertFalse(bindings.isInMemoryReturn); CallingSequence callingSequence = bindings.callingSequence; @@ -269,7 +266,7 @@ public class TestAarch64CallArranger extends CallArrangerTestBase { MethodType mt = MethodType.methodType(MemorySegment.class, float.class, int.class, MemorySegment.class); FunctionDescriptor fd = FunctionDescriptor.of(hfa, C_FLOAT, C_INT, hfa); - CallArranger.Bindings bindings = CallArranger.getBindings(mt, fd, false); + CallArranger.Bindings bindings = CallArranger.LINUX.getBindings(mt, fd, false); assertFalse(bindings.isInMemoryReturn); CallingSequence callingSequence = bindings.callingSequence; @@ -305,7 +302,7 @@ public class TestAarch64CallArranger extends CallArrangerTestBase { MethodType mt = MethodType.methodType(void.class, MemorySegment.class, MemorySegment.class, MemorySegment.class); FunctionDescriptor fd = FunctionDescriptor.ofVoid(struct, struct, struct); - CallArranger.Bindings bindings = CallArranger.getBindings(mt, fd, false); + CallArranger.Bindings bindings = CallArranger.LINUX.getBindings(mt, fd, false); assertFalse(bindings.isInMemoryReturn); CallingSequence callingSequence = bindings.callingSequence; @@ -358,7 +355,7 @@ public class TestAarch64CallArranger extends CallArrangerTestBase { int.class, int.class, int.class, int.class, MemorySegment.class, int.class); FunctionDescriptor fd = FunctionDescriptor.ofVoid( struct, struct, C_INT, C_INT, C_INT, C_INT, C_INT, C_INT, struct, C_INT); - CallArranger.Bindings bindings = CallArranger.getBindings(mt, fd, false); + CallArranger.Bindings bindings = CallArranger.LINUX.getBindings(mt, fd, false); assertFalse(bindings.isInMemoryReturn); CallingSequence callingSequence = bindings.callingSequence; @@ -366,18 +363,60 @@ public class TestAarch64CallArranger extends CallArrangerTestBase { assertEquals(callingSequence.functionDesc(), fd); checkArgumentBindings(callingSequence, new Binding[][]{ - { copy(struct), baseAddress(), unboxAddress(), vmStore(r0, long.class) }, - { copy(struct), baseAddress(), unboxAddress(), vmStore(r1, long.class) }, + { copy(struct), unboxAddress(MemorySegment.class), vmStore(r0, long.class) }, + { copy(struct), unboxAddress(MemorySegment.class), vmStore(r1, long.class) }, { vmStore(r2, int.class) }, { vmStore(r3, int.class) }, { vmStore(r4, int.class) }, { vmStore(r5, int.class) }, { vmStore(r6, int.class) }, { vmStore(r7, int.class) }, - { copy(struct), baseAddress(), unboxAddress(), vmStore(stackStorage(0), long.class) }, + { copy(struct), unboxAddress(MemorySegment.class), vmStore(stackStorage(0), long.class) }, { vmStore(stackStorage(1), int.class) }, }); checkReturnBindings(callingSequence, new Binding[]{}); } + + @Test + public void testVarArgsInRegs() { + MethodType mt = MethodType.methodType(void.class, int.class, int.class, float.class); + FunctionDescriptor fd = FunctionDescriptor.ofVoid(C_INT).asVariadic(C_INT, C_FLOAT); + CallArranger.Bindings bindings = CallArranger.LINUX.getBindings(mt, fd, false); + + assertFalse(bindings.isInMemoryReturn); + CallingSequence callingSequence = bindings.callingSequence; + assertEquals(callingSequence.methodType(), mt); + assertEquals(callingSequence.functionDesc(), fd); + + // This is identical to the non-variadic calling sequence + checkArgumentBindings(callingSequence, new Binding[][]{ + { vmStore(r0, int.class) }, + { vmStore(r1, int.class) }, + { vmStore(v0, float.class) }, + }); + + checkReturnBindings(callingSequence, new Binding[]{}); + } + + @Test + public void testVarArgsOnStack() { + MethodType mt = MethodType.methodType(void.class, int.class, int.class, float.class); + FunctionDescriptor fd = FunctionDescriptor.ofVoid(C_INT).asVariadic(C_INT, C_FLOAT); + CallArranger.Bindings bindings = CallArranger.MACOS.getBindings(mt, fd, false); + + assertFalse(bindings.isInMemoryReturn); + CallingSequence callingSequence = bindings.callingSequence; + assertEquals(callingSequence.methodType(), mt); + assertEquals(callingSequence.functionDesc(), fd); + + // The two variadic arguments should be allocated on the stack + checkArgumentBindings(callingSequence, new Binding[][]{ + { vmStore(r0, int.class) }, + { vmStore(stackStorage(0), int.class) }, + { vmStore(stackStorage(1), float.class) }, + }); + + checkReturnBindings(callingSequence, new Binding[]{}); + } } diff --git a/test/jdk/java/foreign/callarranger/TestSysVCallArranger.java b/test/jdk/java/foreign/callarranger/TestSysVCallArranger.java index 668132bc1defab4ce01ae801bfe29a76da25c4a5..ea1382e4a2e27c9abd63232ce8d91aac940a28cb 100644 --- a/test/jdk/java/foreign/callarranger/TestSysVCallArranger.java +++ b/test/jdk/java/foreign/callarranger/TestSysVCallArranger.java @@ -62,7 +62,7 @@ public class TestSysVCallArranger extends CallArrangerTestBase { assertFalse(bindings.isInMemoryReturn); CallingSequence callingSequence = bindings.callingSequence; assertEquals(callingSequence.methodType(), mt.appendParameterTypes(long.class)); - assertEquals(callingSequence.functionDesc(), fd.withAppendedArgumentLayouts(C_LONG)); + assertEquals(callingSequence.functionDesc(), fd.appendArgumentLayouts(C_LONG)); checkArgumentBindings(callingSequence, new Binding[][]{ { vmStore(rax, long.class) } @@ -89,7 +89,7 @@ public class TestSysVCallArranger extends CallArrangerTestBase { assertFalse(bindings.isInMemoryReturn); CallingSequence callingSequence = bindings.callingSequence; assertEquals(callingSequence.methodType(), mt.appendParameterTypes(long.class)); - assertEquals(callingSequence.functionDesc(), fd.withAppendedArgumentLayouts(C_LONG)); + assertEquals(callingSequence.functionDesc(), fd.appendArgumentLayouts(C_LONG)); checkArgumentBindings(callingSequence, new Binding[][]{ { dup(), bufferLoad(0, long.class), vmStore(rdi, long.class), @@ -119,7 +119,7 @@ public class TestSysVCallArranger extends CallArrangerTestBase { assertFalse(bindings.isInMemoryReturn); CallingSequence callingSequence = bindings.callingSequence; assertEquals(callingSequence.methodType(), mt.appendParameterTypes(long.class)); - assertEquals(callingSequence.functionDesc(), fd.withAppendedArgumentLayouts(C_LONG)); + assertEquals(callingSequence.functionDesc(), fd.appendArgumentLayouts(C_LONG)); checkArgumentBindings(callingSequence, new Binding[][]{ { dup(), bufferLoad(0, long.class), vmStore(rdi, long.class), @@ -148,7 +148,7 @@ public class TestSysVCallArranger extends CallArrangerTestBase { assertFalse(bindings.isInMemoryReturn); CallingSequence callingSequence = bindings.callingSequence; assertEquals(callingSequence.methodType(), mt.appendParameterTypes(long.class)); - assertEquals(callingSequence.functionDesc(), fd.withAppendedArgumentLayouts(C_LONG)); + assertEquals(callingSequence.functionDesc(), fd.appendArgumentLayouts(C_LONG)); checkArgumentBindings(callingSequence, new Binding[][]{ { dup(), bufferLoad(0, long.class), vmStore(stackStorage(0), long.class), @@ -177,7 +177,7 @@ public class TestSysVCallArranger extends CallArrangerTestBase { assertFalse(bindings.isInMemoryReturn); CallingSequence callingSequence = bindings.callingSequence; assertEquals(callingSequence.methodType(), mt.appendParameterTypes(long.class)); - assertEquals(callingSequence.functionDesc(), fd.withAppendedArgumentLayouts(C_LONG)); + assertEquals(callingSequence.functionDesc(), fd.appendArgumentLayouts(C_LONG)); checkArgumentBindings(callingSequence, new Binding[][]{ { dup(), bufferLoad(0, long.class), vmStore(stackStorage(0), long.class), @@ -201,7 +201,7 @@ public class TestSysVCallArranger extends CallArrangerTestBase { assertFalse(bindings.isInMemoryReturn); CallingSequence callingSequence = bindings.callingSequence; assertEquals(callingSequence.methodType(), mt.appendParameterTypes(long.class)); - assertEquals(callingSequence.functionDesc(), fd.withAppendedArgumentLayouts(C_LONG)); + assertEquals(callingSequence.functionDesc(), fd.appendArgumentLayouts(C_LONG)); checkArgumentBindings(callingSequence, new Binding[][]{ { vmStore(rdi, int.class) }, @@ -231,7 +231,7 @@ public class TestSysVCallArranger extends CallArrangerTestBase { assertFalse(bindings.isInMemoryReturn); CallingSequence callingSequence = bindings.callingSequence; assertEquals(callingSequence.methodType(), mt.appendParameterTypes(long.class)); - assertEquals(callingSequence.functionDesc(), fd.withAppendedArgumentLayouts(C_LONG)); + assertEquals(callingSequence.functionDesc(), fd.appendArgumentLayouts(C_LONG)); checkArgumentBindings(callingSequence, new Binding[][]{ { vmStore(xmm0, double.class) }, @@ -265,7 +265,7 @@ public class TestSysVCallArranger extends CallArrangerTestBase { assertFalse(bindings.isInMemoryReturn); CallingSequence callingSequence = bindings.callingSequence; assertEquals(callingSequence.methodType(), mt.appendParameterTypes(long.class)); - assertEquals(callingSequence.functionDesc(), fd.withAppendedArgumentLayouts(C_LONG)); + assertEquals(callingSequence.functionDesc(), fd.appendArgumentLayouts(C_LONG)); checkArgumentBindings(callingSequence, new Binding[][]{ { vmStore(rdi, long.class) }, @@ -321,7 +321,7 @@ public class TestSysVCallArranger extends CallArrangerTestBase { assertFalse(bindings.isInMemoryReturn); CallingSequence callingSequence = bindings.callingSequence; assertEquals(callingSequence.methodType(), mt.appendParameterTypes(long.class)); - assertEquals(callingSequence.functionDesc(), fd.withAppendedArgumentLayouts(C_LONG)); + assertEquals(callingSequence.functionDesc(), fd.appendArgumentLayouts(C_LONG)); checkArgumentBindings(callingSequence, new Binding[][]{ { vmStore(rdi, int.class) }, @@ -363,7 +363,7 @@ public class TestSysVCallArranger extends CallArrangerTestBase { assertFalse(bindings.isInMemoryReturn); CallingSequence callingSequence = bindings.callingSequence; assertEquals(callingSequence.methodType(), mt.appendParameterTypes(long.class)); - assertEquals(callingSequence.functionDesc(), fd.withAppendedArgumentLayouts(C_LONG)); + assertEquals(callingSequence.functionDesc(), fd.appendArgumentLayouts(C_LONG)); checkArgumentBindings(callingSequence, new Binding[][]{ { unboxAddress(), vmStore(rdi, long.class) }, @@ -384,7 +384,7 @@ public class TestSysVCallArranger extends CallArrangerTestBase { assertFalse(bindings.isInMemoryReturn); CallingSequence callingSequence = bindings.callingSequence; assertEquals(callingSequence.methodType(), mt.appendParameterTypes(long.class)); - assertEquals(callingSequence.functionDesc(), fd.withAppendedArgumentLayouts(C_LONG)); + assertEquals(callingSequence.functionDesc(), fd.appendArgumentLayouts(C_LONG)); checkArgumentBindings(callingSequence, new Binding[][]{ expectedBindings, @@ -442,7 +442,7 @@ public class TestSysVCallArranger extends CallArrangerTestBase { assertFalse(bindings.isInMemoryReturn); CallingSequence callingSequence = bindings.callingSequence; assertEquals(callingSequence.methodType(), mt.appendParameterTypes(long.class)); - assertEquals(callingSequence.functionDesc(), fd.withAppendedArgumentLayouts(C_LONG)); + assertEquals(callingSequence.functionDesc(), fd.appendArgumentLayouts(C_LONG)); checkArgumentBindings(callingSequence, new Binding[][]{ { vmStore(rax, long.class) } diff --git a/test/jdk/java/foreign/callarranger/TestWindowsCallArranger.java b/test/jdk/java/foreign/callarranger/TestWindowsCallArranger.java index cb85c6f55e8a5a38d8075133d4882b21b098f568..98ad5f4befbcc90fba7be0ac219dbd1476923522 100644 --- a/test/jdk/java/foreign/callarranger/TestWindowsCallArranger.java +++ b/test/jdk/java/foreign/callarranger/TestWindowsCallArranger.java @@ -156,8 +156,7 @@ public class TestWindowsCallArranger extends CallArrangerTestBase { { vmStore(rdx, int.class) }, { copy(structLayout), - baseAddress(), - unboxAddress(), + unboxAddress(MemorySegment.class), vmStore(r8, long.class) }, { vmStore(r9, int.class) }, @@ -178,7 +177,7 @@ public class TestWindowsCallArranger extends CallArrangerTestBase { MethodType mt = MethodType.methodType(void.class, int.class, double.class, int.class, double.class, double.class); FunctionDescriptor fd = FunctionDescriptor.ofVoid( - C_INT, C_DOUBLE, asVarArg(C_INT), asVarArg(C_DOUBLE), asVarArg(C_DOUBLE)); + C_INT, C_DOUBLE).asVariadic(C_INT, C_DOUBLE, C_DOUBLE); CallArranger.Bindings bindings = CallArranger.getBindings(mt, fd, false); assertFalse(bindings.isInMemoryReturn); @@ -251,8 +250,7 @@ public class TestWindowsCallArranger extends CallArrangerTestBase { checkArgumentBindings(callingSequence, new Binding[][]{ { copy(struct), - baseAddress(), - unboxAddress(), + unboxAddress(MemorySegment.class), vmStore(rcx, long.class) } }); @@ -350,19 +348,19 @@ public class TestWindowsCallArranger extends CallArrangerTestBase { assertEquals(callingSequence.functionDesc(), fd); checkArgumentBindings(callingSequence, new Binding[][]{ - { copy(struct), baseAddress(), unboxAddress(), vmStore(rcx, long.class) }, + { copy(struct), unboxAddress(MemorySegment.class), vmStore(rcx, long.class) }, { vmStore(rdx, int.class) }, { vmStore(xmm2, double.class) }, { unboxAddress(), vmStore(r9, long.class) }, - { copy(struct), baseAddress(), unboxAddress(), vmStore(stackStorage(0), long.class) }, + { copy(struct), unboxAddress(MemorySegment.class), vmStore(stackStorage(0), long.class) }, { vmStore(stackStorage(1), int.class) }, { vmStore(stackStorage(2), double.class) }, { unboxAddress(), vmStore(stackStorage(3), long.class) }, - { copy(struct), baseAddress(), unboxAddress(), vmStore(stackStorage(4), long.class) }, + { copy(struct), unboxAddress(MemorySegment.class), vmStore(stackStorage(4), long.class) }, { vmStore(stackStorage(5), int.class) }, { vmStore(stackStorage(6), double.class) }, { unboxAddress(), vmStore(stackStorage(7), long.class) }, - { copy(struct), baseAddress(), unboxAddress(), vmStore(stackStorage(8), long.class) }, + { copy(struct), unboxAddress(MemorySegment.class), vmStore(stackStorage(8), long.class) }, { vmStore(stackStorage(9), int.class) }, { vmStore(stackStorage(10), double.class) }, { unboxAddress(), vmStore(stackStorage(11), long.class) }, diff --git a/test/jdk/java/foreign/channels/AbstractChannelsTest.java b/test/jdk/java/foreign/channels/AbstractChannelsTest.java index 81c6f0bf1932cb2ac74f7697bb45cee87ce95f8e..be0fb0afe8b2ee9409c797b7c2006ad44f49e369 100644 --- a/test/jdk/java/foreign/channels/AbstractChannelsTest.java +++ b/test/jdk/java/foreign/channels/AbstractChannelsTest.java @@ -22,18 +22,19 @@ */ import java.io.IOException; -import java.lang.ref.Cleaner; import java.nio.ByteBuffer; import java.util.Arrays; import java.util.Random; import java.util.concurrent.ExecutionException; import java.util.function.Supplier; import java.util.stream.Stream; -import jdk.incubator.foreign.MemoryAccess; + import jdk.incubator.foreign.MemorySegment; import jdk.incubator.foreign.ResourceScope; import jdk.test.lib.RandomFactory; import org.testng.annotations.*; + +import static jdk.incubator.foreign.ValueLayout.JAVA_BYTE; import static org.testng.Assert.*; /** @@ -51,7 +52,7 @@ public class AbstractChannelsTest { } static ResourceScope closeableScopeOrNull(ResourceScope scope) { - if (scope.isImplicit()) + if (scope == ResourceScope.globalScope()) return null; return scope; } @@ -75,7 +76,7 @@ public class AbstractChannelsTest { static ByteBuffer segmentBufferOfSize(ResourceScope scope, int size) { var segment = MemorySegment.allocateNative(size, 1, scope); for (int i = 0; i < size; i++) { - MemoryAccess.setByteAtOffset(segment, i, ((byte)RANDOM.nextInt())); + segment.set(JAVA_BYTE, i, ((byte)RANDOM.nextInt())); } return segment.asByteBuffer(); } @@ -129,7 +130,6 @@ public class AbstractChannelsTest { public static Object[][] confinedScopes() { return new Object[][] { { ScopeSupplier.NEW_CONFINED }, - { ScopeSupplier.NEW_CONFINED_EXPLICIT }, }; } @@ -137,7 +137,6 @@ public class AbstractChannelsTest { public static Object[][] sharedScopes() { return new Object[][] { { ScopeSupplier.NEW_SHARED }, - { ScopeSupplier.NEW_SHARED_EXPLICIT }, }; } @@ -151,7 +150,6 @@ public class AbstractChannelsTest { @DataProvider(name = "implicitScopes") public static Object[][] implicitScopes() { return new Object[][] { - { ScopeSupplier.NEW_IMPLICIT }, { ScopeSupplier.GLOBAL }, }; } @@ -174,26 +172,20 @@ public class AbstractChannelsTest { public static Object[][] sharedScopesAndTimeouts() { return new Object[][] { { ScopeSupplier.NEW_SHARED , 0 }, - { ScopeSupplier.NEW_SHARED_EXPLICIT , 0 }, { ScopeSupplier.NEW_SHARED , 30 }, - { ScopeSupplier.NEW_SHARED_EXPLICIT , 30 }, }; } static class ScopeSupplier implements Supplier<ResourceScope> { static final Supplier<ResourceScope> NEW_CONFINED = - new ScopeSupplier(() -> ResourceScope.newConfinedScope(), "newConfinedScope()"); - static final Supplier<ResourceScope> NEW_CONFINED_EXPLICIT = - new ScopeSupplier(() -> ResourceScope.newConfinedScope(Cleaner.create()), "newConfinedScope(Cleaner)"); + new ScopeSupplier(ResourceScope::newConfinedScope, "newConfinedScope()"); static final Supplier<ResourceScope> NEW_SHARED = - new ScopeSupplier(() -> ResourceScope.newSharedScope(), "newSharedScope()"); - static final Supplier<ResourceScope> NEW_SHARED_EXPLICIT = - new ScopeSupplier(() -> ResourceScope.newSharedScope(Cleaner.create()), "newSharedScope(Cleaner)"); + new ScopeSupplier(ResourceScope::newSharedScope, "newSharedScope()"); static final Supplier<ResourceScope> NEW_IMPLICIT = - new ScopeSupplier(() -> ResourceScope.newImplicitScope(), "newImplicitScope()"); + new ScopeSupplier(ResourceScope::newImplicitScope, "newImplicitScope()"); static final Supplier<ResourceScope> GLOBAL = - new ScopeSupplier(() -> ResourceScope.globalScope(), "globalScope()"); + new ScopeSupplier(ResourceScope::globalScope, "globalScope()"); private final Supplier<ResourceScope> supplier; private final String str; diff --git a/test/jdk/java/foreign/channels/TestAsyncSocketChannels.java b/test/jdk/java/foreign/channels/TestAsyncSocketChannels.java index 1189600ddfe6de44c51e45965480c6b151c7d72d..f3d4a2cee4666e673167bc2d4eff5cf02d1129e6 100644 --- a/test/jdk/java/foreign/channels/TestAsyncSocketChannels.java +++ b/test/jdk/java/foreign/channels/TestAsyncSocketChannels.java @@ -48,12 +48,13 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; import java.util.function.Supplier; -import jdk.incubator.foreign.MemoryAccess; + import jdk.incubator.foreign.MemorySegment; import jdk.incubator.foreign.ResourceScope; import org.testng.annotations.*; import static java.lang.System.out; import static java.util.concurrent.TimeUnit.SECONDS; +import static jdk.incubator.foreign.ValueLayout.JAVA_BYTE; import static org.testng.Assert.*; /** @@ -162,7 +163,7 @@ public class TestAsyncSocketChannels extends AbstractChannelsTest { MemorySegment segment1 = MemorySegment.allocateNative(10, 1, scope); MemorySegment segment2 = MemorySegment.allocateNative(10, 1, scope); for (int i = 0; i < 10; i++) { - MemoryAccess.setByteAtOffset(segment1, i, (byte) i); + segment1.set(JAVA_BYTE, i, (byte) i); } { // Future variants ByteBuffer bb1 = segment1.asByteBuffer(); @@ -221,7 +222,7 @@ public class TestAsyncSocketChannels extends AbstractChannelsTest { ioOp.accept(handler); assertFalse(handler.isDone()); assertTrue(scope.isAlive()); - assertMessage(expectThrows(ISE, () -> scope.close()), "Scope is acquired by"); + assertMessage(expectThrows(ISE, () -> scope.close()), "Scope is kept alive by"); // write to allow the blocking read complete, which will // in turn unlock the scope and allow it to be closed. @@ -270,7 +271,7 @@ public class TestAsyncSocketChannels extends AbstractChannelsTest { // give time for socket buffer to fill up. awaitNoFurtherWrites(bytesWritten); - assertMessage(expectThrows(ISE, () -> scope.close()), "Scope is acquired by"); + assertMessage(expectThrows(ISE, () -> scope.close()), "Scope is kept alive by"); assertTrue(scope.isAlive()); // signal handler to stop further writing diff --git a/test/jdk/java/foreign/channels/TestSocketChannels.java b/test/jdk/java/foreign/channels/TestSocketChannels.java index 3ca3e2dc11aa7a8212ec76432a6244387bf75e97..7cbb624fd87522021ae648769c37d986f5af9840 100644 --- a/test/jdk/java/foreign/channels/TestSocketChannels.java +++ b/test/jdk/java/foreign/channels/TestSocketChannels.java @@ -40,10 +40,12 @@ import java.util.List; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Supplier; import java.util.stream.Stream; -import jdk.incubator.foreign.MemoryAccess; + import jdk.incubator.foreign.MemorySegment; import jdk.incubator.foreign.ResourceScope; import org.testng.annotations.*; + +import static jdk.incubator.foreign.ValueLayout.JAVA_BYTE; import static org.testng.Assert.*; /** @@ -101,7 +103,7 @@ public class TestSocketChannels extends AbstractChannelsTest { MemorySegment segment1 = MemorySegment.allocateNative(10, 1, scope); MemorySegment segment2 = MemorySegment.allocateNative(10, 1, scope); for (int i = 0; i < 10; i++) { - MemoryAccess.setByteAtOffset(segment1, i, (byte) i); + segment1.set(JAVA_BYTE, i, (byte) i); } ByteBuffer bb1 = segment1.asByteBuffer(); ByteBuffer bb2 = segment2.asByteBuffer(); @@ -119,7 +121,7 @@ public class TestSocketChannels extends AbstractChannelsTest { var segment1 = MemorySegment.ofArray(new byte[10]); var segment2 = MemorySegment.ofArray(new byte[10]); for (int i = 0; i < 10; i++) { - MemoryAccess.setByteAtOffset(segment1, i, (byte) i); + segment1.set(JAVA_BYTE, i, (byte) i); } ByteBuffer bb1 = segment1.asByteBuffer(); ByteBuffer bb2 = segment2.asByteBuffer(); diff --git a/test/jdk/java/foreign/enablenativeaccess/org/openjdk/foreigntest/PanamaMainUnnamedModule.java b/test/jdk/java/foreign/enablenativeaccess/org/openjdk/foreigntest/PanamaMainUnnamedModule.java index bf32954eee3aea956deb9da736aa62f9e6aa1de7..789d70b139782d411f6d64419b75dc99042d33fd 100644 --- a/test/jdk/java/foreign/enablenativeaccess/org/openjdk/foreigntest/PanamaMainUnnamedModule.java +++ b/test/jdk/java/foreign/enablenativeaccess/org/openjdk/foreigntest/PanamaMainUnnamedModule.java @@ -32,26 +32,26 @@ import java.lang.reflect.Method; public class PanamaMainUnnamedModule { @Test public void testReflection() throws Throwable { - Method method = CLinker.class.getDeclaredMethod("getInstance"); + Method method = CLinker.class.getDeclaredMethod("systemCLinker"); method.invoke(null); } @Test public void testSetAccessible() throws Throwable { - Method method = CLinker.class.getDeclaredMethod("getInstance"); + Method method = CLinker.class.getDeclaredMethod("systemCLinker"); method.setAccessible(true); method.invoke(null); } @Test public void testInvoke() throws Throwable { - var mh = MethodHandles.lookup().findStatic(CLinker.class, "getInstance", + var mh = MethodHandles.lookup().findStatic(CLinker.class, "systemCLinker", MethodType.methodType(CLinker.class)); var linker = (CLinker)mh.invokeExact(); } @Test public void testDirectAccess() throws Throwable { - CLinker.getInstance(); + CLinker.systemCLinker(); } } diff --git a/test/jdk/java/foreign/enablenativeaccess/panama_module/org/openjdk/foreigntest/PanamaMain.java b/test/jdk/java/foreign/enablenativeaccess/panama_module/org/openjdk/foreigntest/PanamaMain.java index b4416f87808f0c204823ca36ce858fcf06351760..82c1e5008539914ea769b5570a01114cc42d4431 100644 --- a/test/jdk/java/foreign/enablenativeaccess/panama_module/org/openjdk/foreigntest/PanamaMain.java +++ b/test/jdk/java/foreign/enablenativeaccess/panama_module/org/openjdk/foreigntest/PanamaMain.java @@ -28,7 +28,7 @@ import jdk.incubator.foreign.*; public class PanamaMain { public static void main(String[] args) { System.out.println("Trying to get CLinker"); - CLinker.getInstance(); + CLinker.systemCLinker(); System.out.println("Got CLinker"); } } diff --git a/test/jdk/java/foreign/enablenativeaccess/panama_module/org/openjdk/foreigntest/PanamaMainInvoke.java b/test/jdk/java/foreign/enablenativeaccess/panama_module/org/openjdk/foreigntest/PanamaMainInvoke.java index 6a5a2bd4a92300cb44f3e5c402163ba45f561da3..46bf5a2c8d2ea1c7c42526ceb4225b6072308e01 100644 --- a/test/jdk/java/foreign/enablenativeaccess/panama_module/org/openjdk/foreigntest/PanamaMainInvoke.java +++ b/test/jdk/java/foreign/enablenativeaccess/panama_module/org/openjdk/foreigntest/PanamaMainInvoke.java @@ -28,7 +28,7 @@ import jdk.incubator.foreign.*; public class PanamaMainInvoke { public static void main(String[] args) throws Throwable { - var mh = MethodHandles.lookup().findStatic(CLinker.class, "getInstance", + var mh = MethodHandles.lookup().findStatic(CLinker.class, "systemCLinker", MethodType.methodType(CLinker.class)); var linker = (CLinker)mh.invokeExact(); } diff --git a/test/jdk/java/foreign/enablenativeaccess/panama_module/org/openjdk/foreigntest/PanamaMainReflection.java b/test/jdk/java/foreign/enablenativeaccess/panama_module/org/openjdk/foreigntest/PanamaMainReflection.java index 0ddd28b97ee1e51f402d2b095fc12f947838aa84..8206aab123bae670f74228164b5b814871944ff7 100644 --- a/test/jdk/java/foreign/enablenativeaccess/panama_module/org/openjdk/foreigntest/PanamaMainReflection.java +++ b/test/jdk/java/foreign/enablenativeaccess/panama_module/org/openjdk/foreigntest/PanamaMainReflection.java @@ -28,7 +28,7 @@ import java.lang.reflect.Method; public class PanamaMainReflection { public static void main(String[] args) throws Throwable { - Method method = CLinker.class.getDeclaredMethod("getInstance"); + Method method = CLinker.class.getDeclaredMethod("systemCLinker"); method.invoke(null); } } diff --git a/test/jdk/java/foreign/handles/invoker_module/handle/invoker/MethodHandleInvoker.java b/test/jdk/java/foreign/handles/invoker_module/handle/invoker/MethodHandleInvoker.java index bad4d441a48de1ec97911de05899560b0d94a3b3..c9ffe911be6d8ebc9481bbaa1d55c9e816d30034 100644 --- a/test/jdk/java/foreign/handles/invoker_module/handle/invoker/MethodHandleInvoker.java +++ b/test/jdk/java/foreign/handles/invoker_module/handle/invoker/MethodHandleInvoker.java @@ -28,10 +28,11 @@ import jdk.incubator.foreign.CLinker; import jdk.incubator.foreign.FunctionDescriptor; import jdk.incubator.foreign.MemoryAddress; import jdk.incubator.foreign.MemoryLayout; -import jdk.incubator.foreign.MemoryLayouts; +import jdk.incubator.foreign.MemorySegment; import jdk.incubator.foreign.ResourceScope; import jdk.incubator.foreign.SegmentAllocator; import jdk.incubator.foreign.SymbolLookup; +import jdk.incubator.foreign.ValueLayout; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; @@ -52,7 +53,7 @@ public class MethodHandleInvoker { throw new AssertionError("Caller module is not lookup_module!"); } } catch (Throwable ex) { - throw new AssertionError("Call to restricted method did not fail as expected!"); + throw new AssertionError("Call to restricted method did not fail as expected!", ex); } } @@ -63,8 +64,7 @@ public class MethodHandleInvoker { } static { - addDefaultMapping(CLinker.class, CLinker.getInstance()); - addDefaultMapping(long.class, 0L); + addDefaultMapping(CLinker.class, CLinker.systemCLinker()); addDefaultMapping(Path.class, Path.of("nonExistent")); addDefaultMapping(String.class, "Hello!"); addDefaultMapping(Runnable.class, () -> {}); @@ -73,11 +73,28 @@ public class MethodHandleInvoker { addDefaultMapping(MethodType.class, MethodType.methodType(void.class)); addDefaultMapping(MemoryAddress.class, MemoryAddress.NULL); addDefaultMapping(Addressable.class, MemoryAddress.NULL); - addDefaultMapping(MemoryLayout.class, MemoryLayouts.JAVA_INT); + addDefaultMapping(MemoryLayout.class, ValueLayout.JAVA_INT); addDefaultMapping(FunctionDescriptor.class, FunctionDescriptor.ofVoid()); addDefaultMapping(SymbolLookup.class, SymbolLookup.loaderLookup()); addDefaultMapping(ResourceScope.class, ResourceScope.newImplicitScope()); - addDefaultMapping(SegmentAllocator.class, (size, align) -> null); + addDefaultMapping(SegmentAllocator.class, SegmentAllocator.prefixAllocator(MemorySegment.ofArray(new byte[10]))); + addDefaultMapping(ValueLayout.OfByte.class, ValueLayout.JAVA_BYTE); + addDefaultMapping(ValueLayout.OfBoolean.class, ValueLayout.JAVA_BOOLEAN); + addDefaultMapping(ValueLayout.OfChar.class, ValueLayout.JAVA_CHAR); + addDefaultMapping(ValueLayout.OfShort.class, ValueLayout.JAVA_SHORT); + addDefaultMapping(ValueLayout.OfInt.class, ValueLayout.JAVA_INT); + addDefaultMapping(ValueLayout.OfFloat.class, ValueLayout.JAVA_FLOAT); + addDefaultMapping(ValueLayout.OfLong.class, ValueLayout.JAVA_LONG); + addDefaultMapping(ValueLayout.OfDouble.class, ValueLayout.JAVA_DOUBLE); + addDefaultMapping(ValueLayout.OfAddress.class, ValueLayout.ADDRESS); + addDefaultMapping(byte.class, (byte)0); + addDefaultMapping(boolean.class, true); + addDefaultMapping(char.class, (char)0); + addDefaultMapping(short.class, (short)0); + addDefaultMapping(int.class, 0); + addDefaultMapping(float.class, 0f); + addDefaultMapping(long.class, 0L); + addDefaultMapping(double.class, 0d); } static Object[] makeArgs(MethodType type) { diff --git a/test/jdk/java/foreign/handles/lookup_module/handle/lookup/MethodHandleLookup.java b/test/jdk/java/foreign/handles/lookup_module/handle/lookup/MethodHandleLookup.java index 20f092057c4e2ee5b0cf4f94516118d863da86f8..8755d40e6b173b2975c4ff52c241537e4a67287c 100644 --- a/test/jdk/java/foreign/handles/lookup_module/handle/lookup/MethodHandleLookup.java +++ b/test/jdk/java/foreign/handles/lookup_module/handle/lookup/MethodHandleLookup.java @@ -23,24 +23,20 @@ package handle.lookup; -import jdk.incubator.foreign.Addressable; import jdk.incubator.foreign.CLinker; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; -import java.nio.charset.Charset; -import java.nio.file.Path; -import java.util.Optional; -import jdk.incubator.foreign.FunctionDescriptor; +import jdk.incubator.foreign.Addressable; import jdk.incubator.foreign.SymbolLookup; import jdk.incubator.foreign.MemoryAddress; -import jdk.incubator.foreign.MemoryLayout; import jdk.incubator.foreign.MemorySegment; import jdk.incubator.foreign.ResourceScope; -import jdk.incubator.foreign.SegmentAllocator; +import jdk.incubator.foreign.VaList; +import jdk.incubator.foreign.ValueLayout; import org.testng.annotations.*; public class MethodHandleLookup { @@ -54,38 +50,77 @@ public class MethodHandleLookup { static Object[][] restrictedMethods() { try { return new Object[][]{ - { MethodHandles.lookup().findStatic(CLinker.class, "getInstance", - MethodType.methodType(CLinker.class)), "CLinker::getInstance" }, - { MethodHandles.lookup().findStatic(CLinker.class, "toJavaString", - MethodType.methodType(String.class, MemoryAddress.class)), - "CLinker::toJavaString" }, - { MethodHandles.lookup().findStatic(CLinker.class, "allocateMemory", - MethodType.methodType(MemoryAddress.class, long.class)), - "CLinker::allocateMemory" }, - { MethodHandles.lookup().findStatic(CLinker.class, "freeMemory", - MethodType.methodType(void.class, MemoryAddress.class)), - "CLinker::freeMemory" }, - { MethodHandles.lookup().findStatic(CLinker.VaList.class, "ofAddress", - MethodType.methodType(CLinker.VaList.class, MemoryAddress.class)), + { MethodHandles.lookup().findStatic(CLinker.class, "systemCLinker", + MethodType.methodType(CLinker.class)), "ForeignLinker::systemCLinker" }, + { MethodHandles.lookup().findStatic(VaList.class, "ofAddress", + MethodType.methodType(VaList.class, MemoryAddress.class, ResourceScope.class)), "VaList::ofAddress/1" }, - { MethodHandles.lookup().findStatic(CLinker.VaList.class, "ofAddress", - MethodType.methodType(CLinker.VaList.class, MemoryAddress.class, ResourceScope.class)), - "VaList::ofAddress/2" }, - { MethodHandles.lookup().findStatic(CLinker.class, "systemLookup", - MethodType.methodType(SymbolLookup.class)), - "CLinker::systemLookup" }, { MethodHandles.lookup().findStatic(SymbolLookup.class, "loaderLookup", MethodType.methodType(SymbolLookup.class)), "SymbolLookup::loaderLookup" }, - { MethodHandles.lookup().findVirtual(MemoryAddress.class, "asSegment", - MethodType.methodType(MemorySegment.class, long.class, ResourceScope.class)), - "MemoryAddress::asSegment/1" }, - { MethodHandles.lookup().findVirtual(MemoryAddress.class, "asSegment", - MethodType.methodType(MemorySegment.class, long.class, Runnable.class, ResourceScope.class)), - "MemoryAddress::asSegment/2" }, - { MethodHandles.lookup().findStatic(MemorySegment.class, "globalNativeSegment", - MethodType.methodType(MemorySegment.class)), - "MemoryAddress::globalNativeSegment" } + { MethodHandles.lookup().findStatic(MemorySegment.class, "ofAddress", + MethodType.methodType(MemorySegment.class, MemoryAddress.class, long.class, ResourceScope.class)), + "MemorySegment::ofAddress" }, + { MethodHandles.lookup().findVirtual(MemoryAddress.class, "getUtf8String", + MethodType.methodType(String.class, long.class)), + "MemoryAddress::getUtf8String" }, + { MethodHandles.lookup().findVirtual(MemoryAddress.class, "setUtf8String", + MethodType.methodType(void.class, long.class, String.class)), + "MemoryAddress::setUtf8String" }, + { MethodHandles.lookup().findVirtual(MemoryAddress.class, "get", + MethodType.methodType(byte.class, ValueLayout.OfByte.class, long.class)), + "MemoryAddress::get/byte" }, + { MethodHandles.lookup().findVirtual(MemoryAddress.class, "get", + MethodType.methodType(boolean.class, ValueLayout.OfBoolean.class, long.class)), + "MemoryAddress::get/boolean" }, + { MethodHandles.lookup().findVirtual(MemoryAddress.class, "get", + MethodType.methodType(char.class, ValueLayout.OfChar.class, long.class)), + "MemoryAddress::get/char" }, + { MethodHandles.lookup().findVirtual(MemoryAddress.class, "get", + MethodType.methodType(short.class, ValueLayout.OfShort.class, long.class)), + "MemoryAddress::get/short" }, + { MethodHandles.lookup().findVirtual(MemoryAddress.class, "get", + MethodType.methodType(int.class, ValueLayout.OfInt.class, long.class)), + "MemoryAddress::get/int" }, + { MethodHandles.lookup().findVirtual(MemoryAddress.class, "get", + MethodType.methodType(float.class, ValueLayout.OfFloat.class, long.class)), + "MemoryAddress::get/float" }, + { MethodHandles.lookup().findVirtual(MemoryAddress.class, "get", + MethodType.methodType(long.class, ValueLayout.OfLong.class, long.class)), + "MemoryAddress::get/long" }, + { MethodHandles.lookup().findVirtual(MemoryAddress.class, "get", + MethodType.methodType(double.class, ValueLayout.OfDouble.class, long.class)), + "MemoryAddress::get/double" }, + { MethodHandles.lookup().findVirtual(MemoryAddress.class, "get", + MethodType.methodType(MemoryAddress.class, ValueLayout.OfAddress.class, long.class)), + "MemoryAddress::get/address" }, + { MethodHandles.lookup().findVirtual(MemoryAddress.class, "set", + MethodType.methodType(void.class, ValueLayout.OfByte.class, long.class, byte.class)), + "MemoryAddress::set/byte" }, + { MethodHandles.lookup().findVirtual(MemoryAddress.class, "set", + MethodType.methodType(void.class, ValueLayout.OfBoolean.class, long.class, boolean.class)), + "MemoryAddress::set/boolean" }, + { MethodHandles.lookup().findVirtual(MemoryAddress.class, "set", + MethodType.methodType(void.class, ValueLayout.OfChar.class, long.class, char.class)), + "MemoryAddress::set/char" }, + { MethodHandles.lookup().findVirtual(MemoryAddress.class, "set", + MethodType.methodType(void.class, ValueLayout.OfShort.class, long.class, short.class)), + "MemoryAddress::set/short" }, + { MethodHandles.lookup().findVirtual(MemoryAddress.class, "set", + MethodType.methodType(void.class, ValueLayout.OfInt.class, long.class, int.class)), + "MemoryAddress::set/int" }, + { MethodHandles.lookup().findVirtual(MemoryAddress.class, "set", + MethodType.methodType(void.class, ValueLayout.OfFloat.class, long.class, float.class)), + "MemoryAddress::set/float" }, + { MethodHandles.lookup().findVirtual(MemoryAddress.class, "set", + MethodType.methodType(void.class, ValueLayout.OfLong.class, long.class, long.class)), + "MemoryAddress::set/long" }, + { MethodHandles.lookup().findVirtual(MemoryAddress.class, "set", + MethodType.methodType(void.class, ValueLayout.OfDouble.class, long.class, double.class)), + "MemoryAddress::set/double" }, + { MethodHandles.lookup().findVirtual(MemoryAddress.class, "set", + MethodType.methodType(void.class, ValueLayout.OfAddress.class, long.class, Addressable.class)), + "MemoryAddress::set/address" }, }; } catch (Throwable ex) { throw new ExceptionInInitializerError((ex)); diff --git a/test/jdk/java/foreign/libAsyncInvokers.cpp b/test/jdk/java/foreign/libAsyncInvokers.cpp new file mode 100644 index 0000000000000000000000000000000000000000..775e2c3c81439eb1c9a26f13d16c35ea4dff2e0f --- /dev/null +++ b/test/jdk/java/foreign/libAsyncInvokers.cpp @@ -0,0 +1,146 @@ +/* + * 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 <thread> + +#include "libTestUpcall.h" +#ifdef __clang__ +#pragma clang optimize off +#elif defined __GNUC__ +#pragma GCC optimize ("O0") +#elif defined _MSC_BUILD +#pragma optimize( "", off ) +#endif + +template<typename CB> +void launch_v(CB cb) { + std::thread thrd(cb); + thrd.join(); +} + +template<typename O, typename CB> +void start(O& out, CB cb) { + out = cb(); +} + +template<typename O, typename CB> +O launch(CB cb) { + O result; + std::thread thrd(&start<O, CB>, std::ref(result), cb); + thrd.join(); + return result; +} + +extern "C" { +EXPORT void call_async_V(void (*cb)(void)) { launch_v(cb); } + +EXPORT int call_async_I(int (*cb)(void)) { return launch<int>(cb); } +EXPORT float call_async_F(float (*cb)(void)) { return launch<float>(cb); } +EXPORT double call_async_D(double (*cb)(void)) { return launch<double>(cb); } +EXPORT void* call_async_P(void* (*cb)(void)) { return launch<void*>(cb); } + +EXPORT struct S_I call_async_S_I(struct S_I (*cb)(void)) { return launch<struct S_I>(cb); } +EXPORT struct S_F call_async_S_F(struct S_F (*cb)(void)) { return launch<struct S_F>(cb); } +EXPORT struct S_D call_async_S_D(struct S_D (*cb)(void)) { return launch<struct S_D>(cb); } +EXPORT struct S_P call_async_S_P(struct S_P (*cb)(void)) { return launch<struct S_P>(cb); } +EXPORT struct S_II call_async_S_II(struct S_II (*cb)(void)) { return launch<struct S_II>(cb); } +EXPORT struct S_IF call_async_S_IF(struct S_IF (*cb)(void)) { return launch<struct S_IF>(cb); } +EXPORT struct S_ID call_async_S_ID(struct S_ID (*cb)(void)) { return launch<struct S_ID>(cb); } +EXPORT struct S_IP call_async_S_IP(struct S_IP (*cb)(void)) { return launch<struct S_IP>(cb); } +EXPORT struct S_FI call_async_S_FI(struct S_FI (*cb)(void)) { return launch<struct S_FI>(cb); } +EXPORT struct S_FF call_async_S_FF(struct S_FF (*cb)(void)) { return launch<struct S_FF>(cb); } +EXPORT struct S_FD call_async_S_FD(struct S_FD (*cb)(void)) { return launch<struct S_FD>(cb); } +EXPORT struct S_FP call_async_S_FP(struct S_FP (*cb)(void)) { return launch<struct S_FP>(cb); } +EXPORT struct S_DI call_async_S_DI(struct S_DI (*cb)(void)) { return launch<struct S_DI>(cb); } +EXPORT struct S_DF call_async_S_DF(struct S_DF (*cb)(void)) { return launch<struct S_DF>(cb); } +EXPORT struct S_DD call_async_S_DD(struct S_DD (*cb)(void)) { return launch<struct S_DD>(cb); } +EXPORT struct S_DP call_async_S_DP(struct S_DP (*cb)(void)) { return launch<struct S_DP>(cb); } +EXPORT struct S_PI call_async_S_PI(struct S_PI (*cb)(void)) { return launch<struct S_PI>(cb); } +EXPORT struct S_PF call_async_S_PF(struct S_PF (*cb)(void)) { return launch<struct S_PF>(cb); } +EXPORT struct S_PD call_async_S_PD(struct S_PD (*cb)(void)) { return launch<struct S_PD>(cb); } +EXPORT struct S_PP call_async_S_PP(struct S_PP (*cb)(void)) { return launch<struct S_PP>(cb); } +EXPORT struct S_III call_async_S_III(struct S_III (*cb)(void)) { return launch<struct S_III>(cb); } +EXPORT struct S_IIF call_async_S_IIF(struct S_IIF (*cb)(void)) { return launch<struct S_IIF>(cb); } +EXPORT struct S_IID call_async_S_IID(struct S_IID (*cb)(void)) { return launch<struct S_IID>(cb); } +EXPORT struct S_IIP call_async_S_IIP(struct S_IIP (*cb)(void)) { return launch<struct S_IIP>(cb); } +EXPORT struct S_IFI call_async_S_IFI(struct S_IFI (*cb)(void)) { return launch<struct S_IFI>(cb); } +EXPORT struct S_IFF call_async_S_IFF(struct S_IFF (*cb)(void)) { return launch<struct S_IFF>(cb); } +EXPORT struct S_IFD call_async_S_IFD(struct S_IFD (*cb)(void)) { return launch<struct S_IFD>(cb); } +EXPORT struct S_IFP call_async_S_IFP(struct S_IFP (*cb)(void)) { return launch<struct S_IFP>(cb); } +EXPORT struct S_IDI call_async_S_IDI(struct S_IDI (*cb)(void)) { return launch<struct S_IDI>(cb); } +EXPORT struct S_IDF call_async_S_IDF(struct S_IDF (*cb)(void)) { return launch<struct S_IDF>(cb); } +EXPORT struct S_IDD call_async_S_IDD(struct S_IDD (*cb)(void)) { return launch<struct S_IDD>(cb); } +EXPORT struct S_IDP call_async_S_IDP(struct S_IDP (*cb)(void)) { return launch<struct S_IDP>(cb); } +EXPORT struct S_IPI call_async_S_IPI(struct S_IPI (*cb)(void)) { return launch<struct S_IPI>(cb); } +EXPORT struct S_IPF call_async_S_IPF(struct S_IPF (*cb)(void)) { return launch<struct S_IPF>(cb); } +EXPORT struct S_IPD call_async_S_IPD(struct S_IPD (*cb)(void)) { return launch<struct S_IPD>(cb); } +EXPORT struct S_IPP call_async_S_IPP(struct S_IPP (*cb)(void)) { return launch<struct S_IPP>(cb); } +EXPORT struct S_FII call_async_S_FII(struct S_FII (*cb)(void)) { return launch<struct S_FII>(cb); } +EXPORT struct S_FIF call_async_S_FIF(struct S_FIF (*cb)(void)) { return launch<struct S_FIF>(cb); } +EXPORT struct S_FID call_async_S_FID(struct S_FID (*cb)(void)) { return launch<struct S_FID>(cb); } +EXPORT struct S_FIP call_async_S_FIP(struct S_FIP (*cb)(void)) { return launch<struct S_FIP>(cb); } +EXPORT struct S_FFI call_async_S_FFI(struct S_FFI (*cb)(void)) { return launch<struct S_FFI>(cb); } +EXPORT struct S_FFF call_async_S_FFF(struct S_FFF (*cb)(void)) { return launch<struct S_FFF>(cb); } +EXPORT struct S_FFD call_async_S_FFD(struct S_FFD (*cb)(void)) { return launch<struct S_FFD>(cb); } +EXPORT struct S_FFP call_async_S_FFP(struct S_FFP (*cb)(void)) { return launch<struct S_FFP>(cb); } +EXPORT struct S_FDI call_async_S_FDI(struct S_FDI (*cb)(void)) { return launch<struct S_FDI>(cb); } +EXPORT struct S_FDF call_async_S_FDF(struct S_FDF (*cb)(void)) { return launch<struct S_FDF>(cb); } +EXPORT struct S_FDD call_async_S_FDD(struct S_FDD (*cb)(void)) { return launch<struct S_FDD>(cb); } +EXPORT struct S_FDP call_async_S_FDP(struct S_FDP (*cb)(void)) { return launch<struct S_FDP>(cb); } +EXPORT struct S_FPI call_async_S_FPI(struct S_FPI (*cb)(void)) { return launch<struct S_FPI>(cb); } +EXPORT struct S_FPF call_async_S_FPF(struct S_FPF (*cb)(void)) { return launch<struct S_FPF>(cb); } +EXPORT struct S_FPD call_async_S_FPD(struct S_FPD (*cb)(void)) { return launch<struct S_FPD>(cb); } +EXPORT struct S_FPP call_async_S_FPP(struct S_FPP (*cb)(void)) { return launch<struct S_FPP>(cb); } +EXPORT struct S_DII call_async_S_DII(struct S_DII (*cb)(void)) { return launch<struct S_DII>(cb); } +EXPORT struct S_DIF call_async_S_DIF(struct S_DIF (*cb)(void)) { return launch<struct S_DIF>(cb); } +EXPORT struct S_DID call_async_S_DID(struct S_DID (*cb)(void)) { return launch<struct S_DID>(cb); } +EXPORT struct S_DIP call_async_S_DIP(struct S_DIP (*cb)(void)) { return launch<struct S_DIP>(cb); } +EXPORT struct S_DFI call_async_S_DFI(struct S_DFI (*cb)(void)) { return launch<struct S_DFI>(cb); } +EXPORT struct S_DFF call_async_S_DFF(struct S_DFF (*cb)(void)) { return launch<struct S_DFF>(cb); } +EXPORT struct S_DFD call_async_S_DFD(struct S_DFD (*cb)(void)) { return launch<struct S_DFD>(cb); } +EXPORT struct S_DFP call_async_S_DFP(struct S_DFP (*cb)(void)) { return launch<struct S_DFP>(cb); } +EXPORT struct S_DDI call_async_S_DDI(struct S_DDI (*cb)(void)) { return launch<struct S_DDI>(cb); } +EXPORT struct S_DDF call_async_S_DDF(struct S_DDF (*cb)(void)) { return launch<struct S_DDF>(cb); } +EXPORT struct S_DDD call_async_S_DDD(struct S_DDD (*cb)(void)) { return launch<struct S_DDD>(cb); } +EXPORT struct S_DDP call_async_S_DDP(struct S_DDP (*cb)(void)) { return launch<struct S_DDP>(cb); } +EXPORT struct S_DPI call_async_S_DPI(struct S_DPI (*cb)(void)) { return launch<struct S_DPI>(cb); } +EXPORT struct S_DPF call_async_S_DPF(struct S_DPF (*cb)(void)) { return launch<struct S_DPF>(cb); } +EXPORT struct S_DPD call_async_S_DPD(struct S_DPD (*cb)(void)) { return launch<struct S_DPD>(cb); } +EXPORT struct S_DPP call_async_S_DPP(struct S_DPP (*cb)(void)) { return launch<struct S_DPP>(cb); } +EXPORT struct S_PII call_async_S_PII(struct S_PII (*cb)(void)) { return launch<struct S_PII>(cb); } +EXPORT struct S_PIF call_async_S_PIF(struct S_PIF (*cb)(void)) { return launch<struct S_PIF>(cb); } +EXPORT struct S_PID call_async_S_PID(struct S_PID (*cb)(void)) { return launch<struct S_PID>(cb); } +EXPORT struct S_PIP call_async_S_PIP(struct S_PIP (*cb)(void)) { return launch<struct S_PIP>(cb); } +EXPORT struct S_PFI call_async_S_PFI(struct S_PFI (*cb)(void)) { return launch<struct S_PFI>(cb); } +EXPORT struct S_PFF call_async_S_PFF(struct S_PFF (*cb)(void)) { return launch<struct S_PFF>(cb); } +EXPORT struct S_PFD call_async_S_PFD(struct S_PFD (*cb)(void)) { return launch<struct S_PFD>(cb); } +EXPORT struct S_PFP call_async_S_PFP(struct S_PFP (*cb)(void)) { return launch<struct S_PFP>(cb); } +EXPORT struct S_PDI call_async_S_PDI(struct S_PDI (*cb)(void)) { return launch<struct S_PDI>(cb); } +EXPORT struct S_PDF call_async_S_PDF(struct S_PDF (*cb)(void)) { return launch<struct S_PDF>(cb); } +EXPORT struct S_PDD call_async_S_PDD(struct S_PDD (*cb)(void)) { return launch<struct S_PDD>(cb); } +EXPORT struct S_PDP call_async_S_PDP(struct S_PDP (*cb)(void)) { return launch<struct S_PDP>(cb); } +EXPORT struct S_PPI call_async_S_PPI(struct S_PPI (*cb)(void)) { return launch<struct S_PPI>(cb); } +EXPORT struct S_PPF call_async_S_PPF(struct S_PPF (*cb)(void)) { return launch<struct S_PPF>(cb); } +EXPORT struct S_PPD call_async_S_PPD(struct S_PPD (*cb)(void)) { return launch<struct S_PPD>(cb); } +EXPORT struct S_PPP call_async_S_PPP(struct S_PPP (*cb)(void)) { return launch<struct S_PPP>(cb); } +} diff --git a/test/jdk/java/foreign/libIntrinsics.c b/test/jdk/java/foreign/libIntrinsics.c index 5b6923cbbd780cff7c4974b71984270cb96900d6..89d0a09c7b608d7983ff565450214b3b3e7f888d 100644 --- a/test/jdk/java/foreign/libIntrinsics.c +++ b/test/jdk/java/foreign/libIntrinsics.c @@ -22,6 +22,8 @@ * */ +#include <stdbool.h> + #ifdef _WIN64 #define EXPORT __declspec(dllexport) #else @@ -31,6 +33,10 @@ EXPORT void empty() { } +EXPORT bool identity_bool(bool x) { + return x; +} + EXPORT char identity_char(char x) { return x; } diff --git a/test/jdk/java/foreign/libSafeAccess.c b/test/jdk/java/foreign/libSafeAccess.c index a5bcbe0e892dfc1e6b00d294940e0e28e700cff1..3a640329aa1264f4618d486b1f4ea2326920469e 100644 --- a/test/jdk/java/foreign/libSafeAccess.c +++ b/test/jdk/java/foreign/libSafeAccess.c @@ -36,3 +36,9 @@ struct Point { EXPORT void struct_func(struct Point p) { } EXPORT void addr_func(struct Point* p) { } + +EXPORT void addr_func_6(struct Point* p1, struct Point* p2, struct Point* p3, struct Point* p4, struct Point* p5, struct Point* p6) { } + +EXPORT void addr_func_cb(void* p, void (*callback)()) { + callback(); +} diff --git a/test/jdk/java/foreign/loaderLookup/TestLoaderLookup.java b/test/jdk/java/foreign/loaderLookup/TestLoaderLookup.java new file mode 100644 index 0000000000000000000000000000000000000000..3d83ba044edef321b8249d38d8562131fe7dc810 --- /dev/null +++ b/test/jdk/java/foreign/loaderLookup/TestLoaderLookup.java @@ -0,0 +1,70 @@ +/* + * 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. + */ + +/* + * @test + * @requires ((os.arch == "amd64" | os.arch == "x86_64") & sun.arch.data.model == "64") | os.arch == "aarch64" + * @compile --add-modules jdk.incubator.foreign lookup/Lookup.java + * @compile --add-modules jdk.incubator.foreign invoker/Invoker.java + * @run main/othervm --enable-native-access=ALL-UNNAMED TestLoaderLookup + */ + +import java.lang.reflect.*; +import jdk.incubator.foreign.*; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; +import java.nio.file.Paths; + +public class TestLoaderLookup { + public static void main(String[] args) throws ReflectiveOperationException { + ClassLoader loader1 = newClassLoader("lookup"); + Class<?> lookup = loader1.loadClass("lookup.Lookup"); + Method fooSymbol = lookup.getDeclaredMethod("fooSymbol"); + NativeSymbol foo = (NativeSymbol)fooSymbol.invoke(null); + + ClassLoader loader2 = newClassLoader("invoker"); + Class<?> invoker = loader2.loadClass("invoker.Invoker"); + Method invoke = invoker.getDeclaredMethod("invoke", NativeSymbol.class); + invoke.invoke(null, foo); + + loader1 = null; + lookup = null; + fooSymbol = null; + // Make sure that the loader is kept reachable + for (int i = 0 ; i < 1000 ; i++) { + invoke.invoke(null, foo); // might crash if loader1 is GC'ed + System.gc(); + } + } + + public static ClassLoader newClassLoader(String path) { + try { + return new URLClassLoader(new URL[] { + Paths.get(System.getProperty("test.classes", path)).toUri().toURL(), + }, null); + } catch (MalformedURLException e){ + throw new RuntimeException("Unexpected URL conversion failure", e); + } + } +} diff --git a/test/jdk/java/foreign/loaderLookup/invoker/Invoker.java b/test/jdk/java/foreign/loaderLookup/invoker/Invoker.java new file mode 100644 index 0000000000000000000000000000000000000000..fab39a25498137158e35ca7d716027ded22458d2 --- /dev/null +++ b/test/jdk/java/foreign/loaderLookup/invoker/Invoker.java @@ -0,0 +1,34 @@ +/* + * 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. + */ + +package invoker; + +import jdk.incubator.foreign.*; + +public class Invoker { + public static void invoke(NativeSymbol symbol) throws Throwable { + var linker = CLinker.systemCLinker(); + var handle = linker.downcallHandle(symbol, FunctionDescriptor.ofVoid()); + handle.invokeExact(); + } +} \ No newline at end of file diff --git a/src/hotspot/cpu/s390/register_definitions_s390.cpp b/test/jdk/java/foreign/loaderLookup/lookup/Lookup.java similarity index 65% rename from src/hotspot/cpu/s390/register_definitions_s390.cpp rename to test/jdk/java/foreign/loaderLookup/lookup/Lookup.java index 2378d513799fe1f5222aae56b30749e3d7a60e20..087a91dcdc2b8c0e68fe4c4dcf6a5a84ba38bbd8 100644 --- a/src/hotspot/cpu/s390/register_definitions_s390.cpp +++ b/test/jdk/java/foreign/loaderLookup/lookup/Lookup.java @@ -1,6 +1,5 @@ /* - * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2016, 2017 SAP SE. All rights reserved. + * 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 @@ -20,20 +19,20 @@ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. - * */ -// Make sure the defines don't screw up the declarations later on in this file. -#define DONT_USE_REGISTER_DEFINES +package lookup; -#include "precompiled.hpp" -#include "asm/assembler.hpp" -#include "asm/register.hpp" -#include "register_s390.hpp" -#include "interp_masm_s390.hpp" +import jdk.incubator.foreign.*; -REGISTER_DEFINITION(Register, noreg); +public class Lookup { + static { + System.loadLibrary("Foo"); + } -REGISTER_DEFINITION(FloatRegister, fnoreg); + static SymbolLookup lookup = SymbolLookup.loaderLookup(); -REGISTER_DEFINITION(VectorRegister, vnoreg); + public static NativeSymbol fooSymbol() { + return lookup.lookup("foo").get(); + } +} \ No newline at end of file diff --git a/test/jdk/java/foreign/loaderLookup/lookup/libFoo.c b/test/jdk/java/foreign/loaderLookup/lookup/libFoo.c new file mode 100644 index 0000000000000000000000000000000000000000..68525215b9345254dc8bbdfcb286729749930c72 --- /dev/null +++ b/test/jdk/java/foreign/loaderLookup/lookup/libFoo.c @@ -0,0 +1,34 @@ +/* + * 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 <stdio.h> + +#ifdef _WIN64 +#define EXPORT __declspec(dllexport) +#else +#define EXPORT +#endif + +EXPORT void foo(void) { + // do nothing +} diff --git a/test/jdk/java/foreign/malloc/TestMixedMallocFree.java b/test/jdk/java/foreign/malloc/TestMixedMallocFree.java index 41c7616c5f97f688091248db93305fc2c6c2932e..1603fd83ee392091224084d18859bdb01fff7aed 100644 --- a/test/jdk/java/foreign/malloc/TestMixedMallocFree.java +++ b/test/jdk/java/foreign/malloc/TestMixedMallocFree.java @@ -23,13 +23,13 @@ /* * @test + * @library ../ * @requires ((os.arch == "amd64" | os.arch == "x86_64") & sun.arch.data.model == "64") | os.arch == "aarch64" * @run testng/othervm --enable-native-access=ALL-UNNAMED TestMixedMallocFree */ import jdk.incubator.foreign.CLinker; import jdk.incubator.foreign.FunctionDescriptor; -import jdk.incubator.foreign.MemoryAccess; import jdk.incubator.foreign.MemoryAddress; import jdk.incubator.foreign.MemorySegment; import jdk.incubator.foreign.ResourceScope; @@ -37,12 +37,11 @@ import jdk.incubator.foreign.SymbolLookup; import org.testng.annotations.Test; import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodType; -import static jdk.incubator.foreign.CLinker.*; +import static jdk.incubator.foreign.ValueLayout.JAVA_INT; import static org.testng.Assert.assertEquals; -public class TestMixedMallocFree { +public class TestMixedMallocFree extends NativeTestHelper { static final MethodHandle MH_my_malloc; @@ -50,21 +49,20 @@ public class TestMixedMallocFree { System.loadLibrary("Malloc"); SymbolLookup MALLOC = SymbolLookup.loaderLookup(); - MH_my_malloc = CLinker.getInstance().downcallHandle( + MH_my_malloc = CLinker.systemCLinker().downcallHandle( MALLOC.lookup("my_malloc").orElseThrow(), - MethodType.methodType(MemoryAddress.class, long.class), - FunctionDescriptor.of(C_POINTER, C_LONG_LONG)); + FunctionDescriptor.of(C_POINTER, C_LONG_LONG)); } @Test public void testMalloc() throws Throwable { MemoryAddress ma = (MemoryAddress) MH_my_malloc.invokeExact(4L); - MemorySegment seg = ma.asSegment(4L, ResourceScope.newImplicitScope()); - MemoryAccess.setInt(seg, 42); - assertEquals(MemoryAccess.getInt(seg), 42); + MemorySegment seg = MemorySegment.ofAddress(ma, 4L, ResourceScope.newImplicitScope()); + seg.set(JAVA_INT, 0, 42); + assertEquals(seg.get(JAVA_INT, 0), 42); // Test if this free crashes the VM, which might be the case if we load the wrong default library // and end up mixing two allocators together. - CLinker.freeMemory(ma); + freeMemory(ma); } } diff --git a/test/jdk/java/foreign/stackwalk/TestAsyncStackWalk.java b/test/jdk/java/foreign/stackwalk/TestAsyncStackWalk.java index b56231230fdf430580848809a0da23a8ebb07475..9c9de5e0305392a7095d2c555fe3779e638bb072 100644 --- a/test/jdk/java/foreign/stackwalk/TestAsyncStackWalk.java +++ b/test/jdk/java/foreign/stackwalk/TestAsyncStackWalk.java @@ -25,6 +25,7 @@ * @test id=default_gc * @requires ((os.arch == "amd64" | os.arch == "x86_64") & sun.arch.data.model == "64") | os.arch == "aarch64" * @library /test/lib + * @library ../ * @build sun.hotspot.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller sun.hotspot.WhiteBox * @@ -52,6 +53,7 @@ * @requires (((os.arch == "amd64" | os.arch == "x86_64") & sun.arch.data.model == "64") | os.arch == "aarch64") * @requires vm.gc.Z * @library /test/lib + * @library ../ * @build sun.hotspot.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller sun.hotspot.WhiteBox * @@ -80,6 +82,7 @@ * @requires (((os.arch == "amd64" | os.arch == "x86_64") & sun.arch.data.model == "64") | os.arch == "aarch64") * @requires vm.gc.Shenandoah * @library /test/lib + * @library ../ * @build sun.hotspot.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller sun.hotspot.WhiteBox * @@ -106,6 +109,7 @@ import jdk.incubator.foreign.CLinker; import jdk.incubator.foreign.FunctionDescriptor; +import jdk.incubator.foreign.NativeSymbol; import jdk.incubator.foreign.SymbolLookup; import jdk.incubator.foreign.MemoryAddress; @@ -116,13 +120,12 @@ import jdk.incubator.foreign.ResourceScope; import sun.hotspot.WhiteBox; import static java.lang.invoke.MethodHandles.lookup; -import static jdk.incubator.foreign.CLinker.C_POINTER; import static jdk.test.lib.Asserts.assertTrue; -public class TestAsyncStackWalk { +public class TestAsyncStackWalk extends NativeTestHelper { static final WhiteBox WB = WhiteBox.getWhiteBox(); - static final CLinker linker = CLinker.getInstance(); + static final CLinker linker = CLinker.systemCLinker(); static final MethodHandle MH_asyncStackWalk; static final MethodHandle MH_m; @@ -133,7 +136,6 @@ public class TestAsyncStackWalk { SymbolLookup lookup = SymbolLookup.loaderLookup(); MH_asyncStackWalk = linker.downcallHandle( lookup.lookup("asyncStackWalk").get(), - MethodType.methodType(void.class, MemoryAddress.class), FunctionDescriptor.ofVoid(C_POINTER)); MH_m = lookup().findStatic(TestAsyncStackWalk.class, "m", MethodType.methodType(void.class)); } catch (ReflectiveOperationException e) { @@ -146,7 +148,7 @@ public class TestAsyncStackWalk { public static void main(String[] args) throws Throwable { try (ResourceScope scope = ResourceScope.newConfinedScope()) { - MemoryAddress stub = linker.upcallStub(MH_m, FunctionDescriptor.ofVoid(), scope); + NativeSymbol stub = linker.upcallStub(MH_m, FunctionDescriptor.ofVoid(), scope); MemoryAddress stubAddress = stub.address(); invocations = 0; didStackWalk = false; @@ -156,7 +158,7 @@ public class TestAsyncStackWalk { } static void payload(MemoryAddress cb) throws Throwable { - MH_asyncStackWalk.invokeExact(cb); + MH_asyncStackWalk.invoke(cb); } static void m() { diff --git a/test/jdk/java/foreign/stackwalk/TestStackWalk.java b/test/jdk/java/foreign/stackwalk/TestStackWalk.java index 5d220cce25c72deaa6e7e759424cbeb73837b02a..07cc0e83df66bba7a6e1ee3be9587a573a36ace5 100644 --- a/test/jdk/java/foreign/stackwalk/TestStackWalk.java +++ b/test/jdk/java/foreign/stackwalk/TestStackWalk.java @@ -25,6 +25,7 @@ * @test id=default_gc * @requires ((os.arch == "amd64" | os.arch == "x86_64") & sun.arch.data.model == "64") | os.arch == "aarch64" * @library /test/lib + * @library ../ * @build sun.hotspot.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller sun.hotspot.WhiteBox * @@ -52,6 +53,7 @@ * @requires (((os.arch == "amd64" | os.arch == "x86_64") & sun.arch.data.model == "64") | os.arch == "aarch64") * @requires vm.gc.Z * @library /test/lib + * @library ../ * @build sun.hotspot.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller sun.hotspot.WhiteBox * @@ -80,6 +82,7 @@ * @requires (((os.arch == "amd64" | os.arch == "x86_64") & sun.arch.data.model == "64") | os.arch == "aarch64") * @requires vm.gc.Shenandoah * @library /test/lib + * @library ../ * @build sun.hotspot.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller sun.hotspot.WhiteBox * @@ -106,6 +109,7 @@ import jdk.incubator.foreign.CLinker; import jdk.incubator.foreign.FunctionDescriptor; +import jdk.incubator.foreign.NativeSymbol; import jdk.incubator.foreign.SymbolLookup; import jdk.incubator.foreign.MemoryAddress; @@ -117,12 +121,11 @@ import jdk.incubator.foreign.ResourceScope; import sun.hotspot.WhiteBox; import static java.lang.invoke.MethodHandles.lookup; -import static jdk.incubator.foreign.CLinker.C_POINTER; -public class TestStackWalk { +public class TestStackWalk extends NativeTestHelper { static final WhiteBox WB = WhiteBox.getWhiteBox(); - static final CLinker linker = CLinker.getInstance(); + static final CLinker linker = CLinker.systemCLinker(); static final MethodHandle MH_foo; static final MethodHandle MH_m; @@ -133,7 +136,6 @@ public class TestStackWalk { SymbolLookup lookup = SymbolLookup.loaderLookup(); MH_foo = linker.downcallHandle( lookup.lookup("foo").get(), - MethodType.methodType(void.class, MemoryAddress.class), FunctionDescriptor.ofVoid(C_POINTER)); MH_m = lookup().findStatic(TestStackWalk.class, "m", MethodType.methodType(void.class)); } catch (ReflectiveOperationException e) { @@ -145,7 +147,7 @@ public class TestStackWalk { public static void main(String[] args) throws Throwable { try (ResourceScope scope = ResourceScope.newConfinedScope()) { - MemoryAddress stub = linker.upcallStub(MH_m, FunctionDescriptor.ofVoid(), scope); + NativeSymbol stub = linker.upcallStub(MH_m, FunctionDescriptor.ofVoid(), scope); MemoryAddress stubAddress = stub.address(); armed = false; for (int i = 0; i < 20_000; i++) { @@ -158,7 +160,7 @@ public class TestStackWalk { } static void payload(MemoryAddress cb) throws Throwable { - MH_foo.invokeExact(cb); + MH_foo.invoke(cb); Reference.reachabilityFence(cb); // keep oop alive across call } diff --git a/test/jdk/java/foreign/upcalldeopt/TestUpcallDeopt.java b/test/jdk/java/foreign/upcalldeopt/TestUpcallDeopt.java new file mode 100644 index 0000000000000000000000000000000000000000..a8a09420344e6dfc61e1305dce9a0453d2e05087 --- /dev/null +++ b/test/jdk/java/foreign/upcalldeopt/TestUpcallDeopt.java @@ -0,0 +1,112 @@ +/* + * 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. + */ + +/* + * @test id=default_gc + * @bug 8277602 + * @requires ((os.arch == "amd64" | os.arch == "x86_64") & sun.arch.data.model == "64") | os.arch == "aarch64" + * @library /test/lib + * @library ../ + * @build sun.hotspot.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller sun.hotspot.WhiteBox + * + * @run main/othervm + * -Xbootclasspath/a:. + * -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI + * --enable-native-access=ALL-UNNAMED + * -Xbatch + * TestUpcallDeopt + */ + +import jdk.incubator.foreign.Addressable; +import jdk.incubator.foreign.CLinker; +import jdk.incubator.foreign.FunctionDescriptor; +import jdk.incubator.foreign.NativeSymbol; +import jdk.incubator.foreign.SymbolLookup; +import jdk.incubator.foreign.MemoryAddress; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodType; +import java.lang.ref.Reference; + +import jdk.incubator.foreign.ResourceScope; +import sun.hotspot.WhiteBox; + +import static java.lang.invoke.MethodHandles.lookup; + +public class TestUpcallDeopt extends NativeTestHelper { + static final WhiteBox WB = WhiteBox.getWhiteBox(); + + static final CLinker linker = CLinker.systemCLinker(); + + static final MethodHandle MH_foo; + static final MethodHandle MH_m; + + static { + try { + System.loadLibrary("UpcallDeopt"); + SymbolLookup lookup = SymbolLookup.loaderLookup(); + MH_foo = linker.downcallHandle( + lookup.lookup("foo").orElseThrow(), + FunctionDescriptor.ofVoid(C_POINTER, C_INT, C_INT, C_INT, C_INT)); + MH_m = lookup().findStatic(TestUpcallDeopt.class, "m", + MethodType.methodType(void.class, int.class, int.class, int.class, int.class)); + } catch (ReflectiveOperationException e) { + throw new RuntimeException(e); + } + } + + static boolean armed; + + // we need to deoptimize through an uncommon trap in the callee of the optimized upcall stub + // that is created when calling upcallStub below + public static void main(String[] args) throws Throwable { + try (ResourceScope scope = ResourceScope.newConfinedScope()) { + NativeSymbol stub = linker.upcallStub(MH_m, FunctionDescriptor.ofVoid(C_INT, C_INT, C_INT, C_INT), scope); + armed = false; + for (int i = 0; i < 20_000; i++) { + payload(stub); // warmup + } + + armed = true; + payload(stub); // test + } + } + + static void payload(NativeSymbol cb) throws Throwable { + MH_foo.invokeExact((Addressable) cb, 0, 1, 2, 3); + Reference.reachabilityFence(cb); // keep oop alive across call + } + + // Takes a bunch of arguments, even though unused, to test + // if the caller's frame is extended enough to spill these arguments. + static void m(int a0, int a1, int a2, int a3) { + if (armed) { + // Trigger uncommon trap from this frame + WB.verifyFrames(/*log=*/true, /*updateRegisterMap=*/true); + WB.verifyFrames(/*log=*/true, /*updateRegisterMap=*/false); // triggers different code paths + } + } + +} diff --git a/test/jdk/java/foreign/upcalldeopt/libUpcallDeopt.c b/test/jdk/java/foreign/upcalldeopt/libUpcallDeopt.c new file mode 100644 index 0000000000000000000000000000000000000000..ae2a8dc01731bd6a098bdaa8273eeef4165351ee --- /dev/null +++ b/test/jdk/java/foreign/upcalldeopt/libUpcallDeopt.c @@ -0,0 +1,32 @@ +/* + * 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. + */ + +#ifdef _WIN64 +#define EXPORT __declspec(dllexport) +#else +#define EXPORT +#endif + +EXPORT void foo(void (*cb)(int, int, int, int), int a0, int a1, int a2, int a3) { + cb(a0, a1, a2, a3); +} diff --git a/test/jdk/java/foreign/valist/VaListTest.java b/test/jdk/java/foreign/valist/VaListTest.java index b2aac7d6dc8f6e4ab6c571ab95b446a6789448c2..9b48d361ed8f1b192d7cae0431b5002e5764a528 100644 --- a/test/jdk/java/foreign/valist/VaListTest.java +++ b/test/jdk/java/foreign/valist/VaListTest.java @@ -36,7 +36,7 @@ */ import jdk.incubator.foreign.*; -import jdk.incubator.foreign.CLinker.VaList; +import jdk.incubator.foreign.VaList; import jdk.internal.foreign.abi.aarch64.linux.LinuxAArch64Linker; import jdk.internal.foreign.abi.aarch64.macos.MacOsAArch64Linker; import jdk.internal.foreign.abi.x64.sysv.SysVx64Linker; @@ -55,59 +55,65 @@ import java.util.function.Function; import java.util.stream.DoubleStream; import java.util.stream.IntStream; -import static jdk.incubator.foreign.CLinker.C_DOUBLE; -import static jdk.incubator.foreign.CLinker.C_FLOAT; -import static jdk.incubator.foreign.CLinker.C_INT; -import static jdk.incubator.foreign.CLinker.C_LONG; -import static jdk.incubator.foreign.CLinker.C_LONG_LONG; -import static jdk.incubator.foreign.CLinker.C_POINTER; -import static jdk.incubator.foreign.CLinker.C_VA_LIST; import static jdk.incubator.foreign.MemoryLayout.PathElement.groupElement; -import static jdk.incubator.foreign.MemoryLayouts.JAVA_INT; +import static jdk.incubator.foreign.ValueLayout.JAVA_DOUBLE; +import static jdk.incubator.foreign.ValueLayout.JAVA_INT; +import static jdk.incubator.foreign.ValueLayout.JAVA_LONG; import static jdk.internal.foreign.PlatformLayouts.*; import static org.testng.Assert.*; public class VaListTest extends NativeTestHelper { - private static final CLinker abi = CLinker.getInstance(); + private static final CLinker abi = CLinker.systemCLinker(); static { System.loadLibrary("VaList"); } static final SymbolLookup LOOKUP = SymbolLookup.loaderLookup(); - private static final MethodHandle MH_sumInts = link("sumInts", - MethodType.methodType(int.class, int.class, VaList.class), - FunctionDescriptor.of(C_INT, C_INT, C_VA_LIST)); - private static final MethodHandle MH_sumDoubles = link("sumDoubles", - MethodType.methodType(double.class, int.class, VaList.class), - FunctionDescriptor.of(C_DOUBLE, C_INT, C_VA_LIST)); - private static final MethodHandle MH_getInt = link("getInt", - MethodType.methodType(int.class, VaList.class), - FunctionDescriptor.of(C_INT, C_VA_LIST)); - private static final MethodHandle MH_sumStruct = link("sumStruct", - MethodType.methodType(int.class, VaList.class), - FunctionDescriptor.of(C_INT, C_VA_LIST)); - private static final MethodHandle MH_sumBigStruct = link("sumBigStruct", - MethodType.methodType(long.class, VaList.class), - FunctionDescriptor.of(C_LONG_LONG, C_VA_LIST)); - private static final MethodHandle MH_sumHugeStruct = link("sumHugeStruct", - MethodType.methodType(long.class, VaList.class), - FunctionDescriptor.of(C_LONG_LONG, C_VA_LIST)); - private static final MethodHandle MH_sumFloatStruct = link("sumFloatStruct", - MethodType.methodType(float.class, VaList.class), - FunctionDescriptor.of(C_FLOAT, C_VA_LIST)); - private static final MethodHandle MH_sumStack = link("sumStack", - MethodType.methodType(void.class, MemoryAddress.class, MemoryAddress.class, VaList.class), - FunctionDescriptor.ofVoid(C_POINTER, C_POINTER, C_VA_LIST)); - - private static MethodHandle link(String symbol, MethodType mt, FunctionDescriptor fd) { - return abi.downcallHandle(LOOKUP.lookup(symbol).get(), mt, fd); + private static final MethodHandle ADDRESS_TO_VALIST; + + static { + try { + ADDRESS_TO_VALIST = MethodHandles.lookup().findStatic(VaList.class, "ofAddress", MethodType.methodType(VaList.class, MemoryAddress.class, ResourceScope.class)); + } catch (Throwable ex) { + throw new ExceptionInInitializerError(ex); + } + } + + + private static final MethodHandle MH_sumInts = linkVaList("sumInts", + FunctionDescriptor.of(C_INT, C_INT, C_POINTER)); + private static final MethodHandle MH_sumDoubles = linkVaList("sumDoubles", + FunctionDescriptor.of(C_DOUBLE, C_INT, C_POINTER)); + private static final MethodHandle MH_getInt = linkVaList("getInt", + FunctionDescriptor.of(C_INT, C_POINTER)); + private static final MethodHandle MH_sumStruct = linkVaList("sumStruct", + FunctionDescriptor.of(C_INT, C_POINTER)); + private static final MethodHandle MH_sumBigStruct = linkVaList("sumBigStruct", + FunctionDescriptor.of(C_LONG_LONG, C_POINTER)); + private static final MethodHandle MH_sumHugeStruct = linkVaList("sumHugeStruct", + FunctionDescriptor.of(C_LONG_LONG, C_POINTER)); + private static final MethodHandle MH_sumFloatStruct = linkVaList("sumFloatStruct", + FunctionDescriptor.of(C_FLOAT, C_POINTER)); + private static final MethodHandle MH_sumStack = linkVaList("sumStack", + FunctionDescriptor.ofVoid(C_POINTER, C_POINTER, C_POINTER)); + + private static MethodHandle link(String symbol, FunctionDescriptor fd) { + return linkInternal(symbol, fd); + } + + private static MethodHandle linkVaList(String symbol, FunctionDescriptor fd) { + return linkInternal(symbol, fd); + } + + + private static MethodHandle linkInternal(String symbol, FunctionDescriptor fd) { + return abi.downcallHandle(LOOKUP.lookup(symbol).get(), fd); } private static MethodHandle linkVaListCB(String symbol) { return link(symbol, - MethodType.methodType(void.class, MemoryAddress.class), FunctionDescriptor.ofVoid(C_POINTER)); } @@ -123,22 +129,22 @@ public class VaListTest extends NativeTestHelper { private static final Function<Consumer<VaList.Builder>, VaList> platformVaListFactory = (builder) -> VaList.make(builder, ResourceScope.newConfinedScope()); - private static final BiFunction<Consumer<VaList.Builder>, NativeScope, VaList> winVaListScopedFactory - = (builder, scope) -> Windowsx64Linker.newVaList(builder, scope.scope()); - private static final BiFunction<Consumer<VaList.Builder>, NativeScope, VaList> sysvVaListScopedFactory - = (builder, scope) -> SysVx64Linker.newVaList(builder, scope.scope()); - private static final BiFunction<Consumer<VaList.Builder>, NativeScope, VaList> linuxAArch64VaListScopedFactory - = (builder, scope) -> LinuxAArch64Linker.newVaList(builder, scope.scope()); - private static final BiFunction<Consumer<VaList.Builder>, NativeScope, VaList> macAArch64VaListScopedFactory - = (builder, scope) -> MacOsAArch64Linker.newVaList(builder, scope.scope()); - private static final BiFunction<Consumer<VaList.Builder>, NativeScope, VaList> platformVaListScopedFactory - = (builder, scope) -> VaList.make(builder, scope.scope()); + private static final BiFunction<Consumer<VaList.Builder>, ResourceScope, VaList> winVaListScopedFactory + = (builder, scope) -> Windowsx64Linker.newVaList(builder, scope); + private static final BiFunction<Consumer<VaList.Builder>, ResourceScope, VaList> sysvVaListScopedFactory + = (builder, scope) -> SysVx64Linker.newVaList(builder, scope); + private static final BiFunction<Consumer<VaList.Builder>, ResourceScope, VaList> linuxAArch64VaListScopedFactory + = (builder, scope) -> LinuxAArch64Linker.newVaList(builder, scope); + private static final BiFunction<Consumer<VaList.Builder>, ResourceScope, VaList> macAArch64VaListScopedFactory + = (builder, scope) -> MacOsAArch64Linker.newVaList(builder, scope); + private static final BiFunction<Consumer<VaList.Builder>, ResourceScope, VaList> platformVaListScopedFactory + = (builder, scope) -> VaList.make(builder, scope); @DataProvider @SuppressWarnings("unchecked") public static Object[][] sumInts() { - Function<MemoryLayout, BiFunction<Integer, VaList, Integer>> sumIntsJavaFact = layout -> - (num, list) -> IntStream.generate(() -> list.vargAsInt(layout)).limit(num).sum(); + Function<ValueLayout.OfInt, BiFunction<Integer, VaList, Integer>> sumIntsJavaFact = layout -> + (num, list) -> IntStream.generate(() -> list.nextVarg(layout)).limit(num).sum(); BiFunction<Integer, VaList, Integer> sumIntsNative = MethodHandleProxies.asInterfaceInstance(BiFunction.class, MH_sumInts); return new Object[][]{ @@ -153,11 +159,11 @@ public class VaListTest extends NativeTestHelper { @Test(dataProvider = "sumInts") public void testIntSum(Function<Consumer<VaList.Builder>, VaList> vaListFactory, BiFunction<Integer, VaList, Integer> sumInts, - ValueLayout intLayout) { + ValueLayout.OfInt intLayout) { VaList vaList = vaListFactory.apply(b -> - b.vargFromInt(intLayout, 10) - .vargFromInt(intLayout, 15) - .vargFromInt(intLayout, 20)); + b.addVarg(intLayout, 10) + .addVarg(intLayout, 15) + .addVarg(intLayout, 20)); int x = sumInts.apply(3, vaList); assertEquals(x, 45); vaList.scope().close(); @@ -166,8 +172,8 @@ public class VaListTest extends NativeTestHelper { @DataProvider @SuppressWarnings("unchecked") public static Object[][] sumDoubles() { - Function<MemoryLayout, BiFunction<Integer, VaList, Double>> sumDoublesJavaFact = layout -> - (num, list) -> DoubleStream.generate(() -> list.vargAsDouble(layout)).limit(num).sum(); + Function<ValueLayout.OfDouble, BiFunction<Integer, VaList, Double>> sumDoublesJavaFact = layout -> + (num, list) -> DoubleStream.generate(() -> list.nextVarg(layout)).limit(num).sum(); BiFunction<Integer, VaList, Double> sumDoublesNative = MethodHandleProxies.asInterfaceInstance(BiFunction.class, MH_sumDoubles); return new Object[][]{ @@ -182,11 +188,11 @@ public class VaListTest extends NativeTestHelper { @Test(dataProvider = "sumDoubles") public void testDoubleSum(Function<Consumer<VaList.Builder>, VaList> vaListFactory, BiFunction<Integer, VaList, Double> sumDoubles, - ValueLayout doubleLayout) { + ValueLayout.OfDouble doubleLayout) { VaList vaList = vaListFactory.apply(b -> - b.vargFromDouble(doubleLayout, 3.0D) - .vargFromDouble(doubleLayout, 4.0D) - .vargFromDouble(doubleLayout, 5.0D)); + b.addVarg(doubleLayout, 3.0D) + .addVarg(doubleLayout, 4.0D) + .addVarg(doubleLayout, 5.0D)); double x = sumDoubles.apply(3, vaList); assertEquals(x, 12.0D); vaList.scope().close(); @@ -195,10 +201,10 @@ public class VaListTest extends NativeTestHelper { @DataProvider @SuppressWarnings("unchecked") public static Object[][] pointers() { - Function<MemoryLayout, Function<VaList, Integer>> getIntJavaFact = layout -> + Function<ValueLayout.OfAddress, Function<VaList, Integer>> getIntJavaFact = layout -> list -> { - MemoryAddress ma = list.vargAsAddress(layout); - return MemoryAccess.getIntAtOffset(MemorySegment.globalNativeSegment(), ma.toRawLongValue()); + MemoryAddress ma = list.nextVarg(layout); + return ma.get(JAVA_INT, 0); }; Function<VaList, Integer> getIntNative = MethodHandleProxies.asInterfaceInstance(Function.class, MH_getInt); return new Object[][]{ @@ -213,11 +219,11 @@ public class VaListTest extends NativeTestHelper { @Test(dataProvider = "pointers") public void testVaListMemoryAddress(Function<Consumer<VaList.Builder>, VaList> vaListFactory, Function<VaList, Integer> getFromPointer, - ValueLayout pointerLayout) { + ValueLayout.OfAddress pointerLayout) { try (ResourceScope scope = ResourceScope.newConfinedScope()) { MemorySegment msInt = MemorySegment.allocateNative(JAVA_INT, scope); - MemoryAccess.setInt(msInt, 10); - VaList vaList = vaListFactory.apply(b -> b.vargFromAddress(pointerLayout, msInt.address())); + msInt.set(JAVA_INT, 0, 10); + VaList vaList = vaListFactory.apply(b -> b.addVarg(pointerLayout, msInt.address())); int x = getFromPointer.apply(vaList); assertEquals(x, 10); vaList.scope().close(); @@ -231,28 +237,29 @@ public class VaListTest extends NativeTestHelper { @DataProvider @SuppressWarnings("unchecked") public static Object[][] structs() { - TriFunction<MemoryLayout, VarHandle, VarHandle, Function<VaList, Integer>> sumStructJavaFact + TriFunction<GroupLayout, VarHandle, VarHandle, Function<VaList, Integer>> sumStructJavaFact = (pointLayout, VH_Point_x, VH_Point_y) -> list -> { - MemorySegment struct = list.vargAsSegment(pointLayout, ResourceScope.newImplicitScope()); + MemorySegment struct = MemorySegment.allocateNative(pointLayout, ResourceScope.newImplicitScope()); + list.nextVarg(pointLayout, SegmentAllocator.prefixAllocator(struct)); int x = (int) VH_Point_x.get(struct); int y = (int) VH_Point_y.get(struct); return x + y; }; - TriFunction<MemoryLayout, VarHandle, VarHandle, Function<VaList, Integer>> sumStructNativeFact + TriFunction<GroupLayout, VarHandle, VarHandle, Function<VaList, Integer>> sumStructNativeFact = (pointLayout, VH_Point_x, VH_Point_y) -> MethodHandleProxies.asInterfaceInstance(Function.class, MH_sumStruct); TriFunction<Function<Consumer<VaList.Builder>, VaList>, MemoryLayout, - TriFunction<MemoryLayout, VarHandle, VarHandle, Function<VaList, Integer>>, Object[]> argsFact + TriFunction<GroupLayout, VarHandle, VarHandle, Function<VaList, Integer>>, Object[]> argsFact = (vaListFact, intLayout, sumStructFact) -> { GroupLayout pointLayout = MemoryLayout.structLayout( intLayout.withName("x"), intLayout.withName("y") ); - VarHandle VH_Point_x = pointLayout.varHandle(int.class, groupElement("x")); - VarHandle VH_Point_y = pointLayout.varHandle(int.class, groupElement("y")); + VarHandle VH_Point_x = pointLayout.varHandle(groupElement("x")); + VarHandle VH_Point_y = pointLayout.varHandle(groupElement("y")); return new Object[] { vaListFact, sumStructFact.apply(pointLayout, VH_Point_x, VH_Point_y), pointLayout, VH_Point_x, VH_Point_y }; }; @@ -274,7 +281,7 @@ public class VaListTest extends NativeTestHelper { VH_Point_x.set(struct, 5); VH_Point_y.set(struct, 10); - VaList vaList = vaListFactory.apply(b -> b.vargFromSegment(Point_LAYOUT, struct)); + VaList vaList = vaListFactory.apply(b -> b.addVarg(Point_LAYOUT, struct)); int sum = sumStruct.apply(vaList); assertEquals(sum, 15); vaList.scope().close(); @@ -284,28 +291,29 @@ public class VaListTest extends NativeTestHelper { @DataProvider @SuppressWarnings("unchecked") public static Object[][] bigStructs() { - TriFunction<MemoryLayout, VarHandle, VarHandle, Function<VaList, Long>> sumStructJavaFact + TriFunction<GroupLayout, VarHandle, VarHandle, Function<VaList, Long>> sumStructJavaFact = (BigPoint_LAYOUT, VH_BigPoint_x, VH_BigPoint_y) -> list -> { - MemorySegment struct = list.vargAsSegment(BigPoint_LAYOUT, ResourceScope.newImplicitScope()); + MemorySegment struct = MemorySegment.allocateNative(BigPoint_LAYOUT, ResourceScope.newImplicitScope()); + list.nextVarg(BigPoint_LAYOUT, SegmentAllocator.prefixAllocator(struct)); long x = (long) VH_BigPoint_x.get(struct); long y = (long) VH_BigPoint_y.get(struct); return x + y; }; - TriFunction<MemoryLayout, VarHandle, VarHandle, Function<VaList, Long>> sumStructNativeFact + TriFunction<GroupLayout, VarHandle, VarHandle, Function<VaList, Long>> sumStructNativeFact = (pointLayout, VH_BigPoint_x, VH_BigPoint_y) -> MethodHandleProxies.asInterfaceInstance(Function.class, MH_sumBigStruct); TriFunction<Function<Consumer<VaList.Builder>, VaList>, MemoryLayout, - TriFunction<MemoryLayout, VarHandle, VarHandle, Function<VaList, Long>>, Object[]> argsFact + TriFunction<GroupLayout, VarHandle, VarHandle, Function<VaList, Long>>, Object[]> argsFact = (vaListFact, longLongLayout, sumBigStructFact) -> { GroupLayout BigPoint_LAYOUT = MemoryLayout.structLayout( longLongLayout.withName("x"), longLongLayout.withName("y") ); - VarHandle VH_BigPoint_x = BigPoint_LAYOUT.varHandle(long.class, groupElement("x")); - VarHandle VH_BigPoint_y = BigPoint_LAYOUT.varHandle(long.class, groupElement("y")); + VarHandle VH_BigPoint_x = BigPoint_LAYOUT.varHandle(groupElement("x")); + VarHandle VH_BigPoint_y = BigPoint_LAYOUT.varHandle(groupElement("y")); return new Object[] { vaListFact, sumBigStructFact.apply(BigPoint_LAYOUT, VH_BigPoint_x, VH_BigPoint_y), BigPoint_LAYOUT, VH_BigPoint_x, VH_BigPoint_y }; }; @@ -327,7 +335,7 @@ public class VaListTest extends NativeTestHelper { VH_BigPoint_x.set(struct, 5); VH_BigPoint_y.set(struct, 10); - VaList vaList = vaListFactory.apply(b -> b.vargFromSegment(BigPoint_LAYOUT, struct)); + VaList vaList = vaListFactory.apply(b -> b.addVarg(BigPoint_LAYOUT, struct)); long sum = sumBigStruct.apply(vaList); assertEquals(sum, 15); vaList.scope().close(); @@ -337,28 +345,29 @@ public class VaListTest extends NativeTestHelper { @DataProvider @SuppressWarnings("unchecked") public static Object[][] floatStructs() { - TriFunction<MemoryLayout, VarHandle, VarHandle, Function<VaList, Float>> sumStructJavaFact + TriFunction<GroupLayout, VarHandle, VarHandle, Function<VaList, Float>> sumStructJavaFact = (FloatPoint_LAYOUT, VH_FloatPoint_x, VH_FloatPoint_y) -> list -> { - MemorySegment struct = list.vargAsSegment(FloatPoint_LAYOUT, ResourceScope.newImplicitScope()); + MemorySegment struct = MemorySegment.allocateNative(FloatPoint_LAYOUT, ResourceScope.newImplicitScope()); + list.nextVarg(FloatPoint_LAYOUT, SegmentAllocator.prefixAllocator(struct)); float x = (float) VH_FloatPoint_x.get(struct); float y = (float) VH_FloatPoint_y.get(struct); return x + y; }; - TriFunction<MemoryLayout, VarHandle, VarHandle, Function<VaList, Float>> sumStructNativeFact + TriFunction<GroupLayout, VarHandle, VarHandle, Function<VaList, Float>> sumStructNativeFact = (pointLayout, VH_FloatPoint_x, VH_FloatPoint_y) -> MethodHandleProxies.asInterfaceInstance(Function.class, MH_sumFloatStruct); TriFunction<Function<Consumer<VaList.Builder>, VaList>, MemoryLayout, - TriFunction<MemoryLayout, VarHandle, VarHandle, Function<VaList, Float>>, Object[]> argsFact + TriFunction<GroupLayout, VarHandle, VarHandle, Function<VaList, Float>>, Object[]> argsFact = (vaListFact, floatLayout, sumFloatStructFact) -> { GroupLayout FloatPoint_LAYOUT = MemoryLayout.structLayout( floatLayout.withName("x"), floatLayout.withName("y") ); - VarHandle VH_FloatPoint_x = FloatPoint_LAYOUT.varHandle(float.class, groupElement("x")); - VarHandle VH_FloatPoint_y = FloatPoint_LAYOUT.varHandle(float.class, groupElement("y")); + VarHandle VH_FloatPoint_x = FloatPoint_LAYOUT.varHandle(groupElement("x")); + VarHandle VH_FloatPoint_y = FloatPoint_LAYOUT.varHandle(groupElement("y")); return new Object[] { vaListFact, sumFloatStructFact.apply(FloatPoint_LAYOUT, VH_FloatPoint_x, VH_FloatPoint_y), FloatPoint_LAYOUT, VH_FloatPoint_x, VH_FloatPoint_y }; }; @@ -381,7 +390,7 @@ public class VaListTest extends NativeTestHelper { VH_FloatPoint_x.set(struct, 1.234f); VH_FloatPoint_y.set(struct, 3.142f); - VaList vaList = vaListFactory.apply(b -> b.vargFromSegment(FloatPoint_LAYOUT, struct)); + VaList vaList = vaListFactory.apply(b -> b.addVarg(FloatPoint_LAYOUT, struct)); float sum = sumFloatStruct.apply(vaList); assertEquals(sum, 4.376f, 0.00001f); vaList.scope().close(); @@ -395,31 +404,32 @@ public class VaListTest extends NativeTestHelper { @DataProvider @SuppressWarnings("unchecked") public static Object[][] hugeStructs() { - QuadFunc<MemoryLayout, VarHandle, VarHandle, VarHandle, Function<VaList, Long>> sumStructJavaFact + QuadFunc<GroupLayout, VarHandle, VarHandle, VarHandle, Function<VaList, Long>> sumStructJavaFact = (HugePoint_LAYOUT, VH_HugePoint_x, VH_HugePoint_y, VH_HugePoint_z) -> list -> { - MemorySegment struct = list.vargAsSegment(HugePoint_LAYOUT, ResourceScope.newImplicitScope()); + MemorySegment struct = MemorySegment.allocateNative(HugePoint_LAYOUT, ResourceScope.newImplicitScope()); + list.nextVarg(HugePoint_LAYOUT, SegmentAllocator.prefixAllocator(struct)); long x = (long) VH_HugePoint_x.get(struct); long y = (long) VH_HugePoint_y.get(struct); long z = (long) VH_HugePoint_z.get(struct); return x + y + z; }; - QuadFunc<MemoryLayout, VarHandle, VarHandle, VarHandle, Function<VaList, Long>> sumStructNativeFact + QuadFunc<GroupLayout, VarHandle, VarHandle, VarHandle, Function<VaList, Long>> sumStructNativeFact = (pointLayout, VH_HugePoint_x, VH_HugePoint_y, VH_HugePoint_z) -> MethodHandleProxies.asInterfaceInstance(Function.class, MH_sumHugeStruct); TriFunction<Function<Consumer<VaList.Builder>, VaList>, MemoryLayout, - QuadFunc<MemoryLayout, VarHandle, VarHandle, VarHandle, Function<VaList, Long>>, Object[]> argsFact + QuadFunc<GroupLayout, VarHandle, VarHandle, VarHandle, Function<VaList, Long>>, Object[]> argsFact = (vaListFact, longLongLayout, sumBigStructFact) -> { GroupLayout HugePoint_LAYOUT = MemoryLayout.structLayout( longLongLayout.withName("x"), longLongLayout.withName("y"), longLongLayout.withName("z") ); - VarHandle VH_HugePoint_x = HugePoint_LAYOUT.varHandle(long.class, groupElement("x")); - VarHandle VH_HugePoint_y = HugePoint_LAYOUT.varHandle(long.class, groupElement("y")); - VarHandle VH_HugePoint_z = HugePoint_LAYOUT.varHandle(long.class, groupElement("z")); + VarHandle VH_HugePoint_x = HugePoint_LAYOUT.varHandle(groupElement("x")); + VarHandle VH_HugePoint_y = HugePoint_LAYOUT.varHandle(groupElement("y")); + VarHandle VH_HugePoint_z = HugePoint_LAYOUT.varHandle(groupElement("z")); return new Object[] { vaListFact, sumBigStructFact.apply(HugePoint_LAYOUT, VH_HugePoint_x, VH_HugePoint_y, VH_HugePoint_z), HugePoint_LAYOUT, VH_HugePoint_x, VH_HugePoint_y, VH_HugePoint_z }; @@ -446,7 +456,7 @@ public class VaListTest extends NativeTestHelper { VH_HugePoint_y.set(struct, 2); VH_HugePoint_z.set(struct, 3); - VaList vaList = vaListFactory.apply(b -> b.vargFromSegment(HugePoint_LAYOUT, struct)); + VaList vaList = vaListFactory.apply(b -> b.addVarg(HugePoint_LAYOUT, struct)); long sum = sumHugeStruct.apply(vaList); assertEquals(sum, 6); vaList.scope().close(); @@ -459,22 +469,22 @@ public class VaListTest extends NativeTestHelper { @DataProvider public static Object[][] sumStack() { - BiFunction<MemoryLayout, MemoryLayout, SumStackFunc> sumStackJavaFact = (longLayout, doubleLayout) -> + BiFunction<ValueLayout.OfLong, ValueLayout.OfDouble, SumStackFunc> sumStackJavaFact = (longLayout, doubleLayout) -> (longSum, doubleSum, list) -> { long lSum = 0L; for (int i = 0; i < 16; i++) { - lSum += list.vargAsLong(longLayout); + lSum += list.nextVarg(longLayout); } - MemoryAccess.setLong(longSum, lSum); + longSum.set(JAVA_LONG, 0, lSum); double dSum = 0D; for (int i = 0; i < 16; i++) { - dSum += list.vargAsDouble(doubleLayout); + dSum += list.nextVarg(doubleLayout); } - MemoryAccess.setDouble(doubleSum, dSum); + doubleSum.set(JAVA_DOUBLE, 0, dSum); }; SumStackFunc sumStackNative = (longSum, doubleSum, list) -> { try { - MH_sumStack.invokeExact(longSum.address(), doubleSum.address(), list); + MH_sumStack.invoke(longSum, doubleSum, list); } catch (Throwable ex) { throw new AssertionError(ex); } @@ -491,20 +501,20 @@ public class VaListTest extends NativeTestHelper { @Test(dataProvider = "sumStack") public void testStack(Function<Consumer<VaList.Builder>, VaList> vaListFactory, SumStackFunc sumStack, - ValueLayout longLayout, - ValueLayout doubleLayout) { + ValueLayout.OfLong longLayout, + ValueLayout.OfDouble doubleLayout) { try (ResourceScope scope = ResourceScope.newConfinedScope()) { MemorySegment longSum = MemorySegment.allocateNative(longLayout, scope); MemorySegment doubleSum = MemorySegment.allocateNative(doubleLayout, scope); - MemoryAccess.setLong(longSum, 0L); - MemoryAccess.setDouble(doubleSum, 0D); + longSum.set(JAVA_LONG, 0, 0L); + doubleSum.set(JAVA_DOUBLE, 0, 0D); VaList list = vaListFactory.apply(b -> { for (long l = 1; l <= 16L; l++) { - b.vargFromLong(longLayout, l); + b.addVarg(longLayout, l); } for (double d = 1; d <= 16D; d++) { - b.vargFromDouble(doubleLayout, d); + b.addVarg(doubleLayout, d); } }); @@ -514,8 +524,8 @@ public class VaListTest extends NativeTestHelper { list.scope().close(); } - long lSum = MemoryAccess.getLong(longSum); - double dSum = MemoryAccess.getDouble(doubleSum); + long lSum = longSum.get(JAVA_LONG, 0); + double dSum = doubleSum.get(JAVA_DOUBLE, 0); assertEquals(lSum, 136L); assertEquals(dSum, 136D); @@ -524,10 +534,10 @@ public class VaListTest extends NativeTestHelper { @Test(dataProvider = "upcalls") public void testUpcall(MethodHandle target, MethodHandle callback) throws Throwable { - FunctionDescriptor desc = FunctionDescriptor.ofVoid(C_VA_LIST); + FunctionDescriptor desc = FunctionDescriptor.ofVoid(C_POINTER); try (ResourceScope scope = ResourceScope.newConfinedScope()) { - MemoryAddress stub = abi.upcallStub(callback, desc, scope); - target.invokeExact(stub.address()); + NativeSymbol stub = abi.upcallStub(callback, desc, scope); + target.invoke(stub); } } @@ -555,8 +565,8 @@ public class VaListTest extends NativeTestHelper { @DataProvider @SuppressWarnings("unchecked") public static Object[][] sumIntsScoped() { - Function<MemoryLayout, BiFunction<Integer, VaList, Integer>> sumIntsJavaFact = layout -> - (num, list) -> IntStream.generate(() -> list.vargAsInt(layout)).limit(num).sum(); + Function<ValueLayout.OfInt, BiFunction<Integer, VaList, Integer>> sumIntsJavaFact = layout -> + (num, list) -> IntStream.generate(() -> list.nextVarg(layout)).limit(num).sum(); BiFunction<Integer, VaList, Integer> sumIntsNative = MethodHandleProxies.asInterfaceInstance(BiFunction.class, MH_sumInts); return new Object[][]{ @@ -569,14 +579,13 @@ public class VaListTest extends NativeTestHelper { } @Test(dataProvider = "sumIntsScoped") - public void testScopedVaList(BiFunction<Consumer<VaList.Builder>, NativeScope, VaList> vaListFactory, + public void testScopedVaList(BiFunction<Consumer<VaList.Builder>, ResourceScope, VaList> vaListFactory, BiFunction<Integer, VaList, Integer> sumInts, - ValueLayout intLayout) { + ValueLayout.OfInt intLayout) { VaList listLeaked; - try (NativeScope scope = new NativeScope()) { - VaList list = vaListFactory.apply(b -> b.vargFromInt(intLayout, 4) - .vargFromInt(intLayout, 8), - scope); + try (ResourceScope scope = ResourceScope.newConfinedScope()) { + VaList list = vaListFactory.apply(b -> b.addVarg(intLayout, 4) + .addVarg(intLayout, 8), scope); int x = sumInts.apply(2, list); assertEquals(x, 12); listLeaked = list; @@ -589,13 +598,14 @@ public class VaListTest extends NativeTestHelper { Function<VaList, Integer> sumStruct, // ignored GroupLayout Point_LAYOUT, VarHandle VH_Point_x, VarHandle VH_Point_y) { MemorySegment pointOut; - try (NativeScope scope = new NativeScope()) { + try (ResourceScope scope = ResourceScope.newConfinedScope()) { try (ResourceScope innerScope = ResourceScope.newConfinedScope()) { MemorySegment pointIn = MemorySegment.allocateNative(Point_LAYOUT, innerScope); VH_Point_x.set(pointIn, 3); VH_Point_y.set(pointIn, 6); - VaList list = vaListFactory.apply(b -> b.vargFromSegment(Point_LAYOUT, pointIn)); - pointOut = list.vargAsSegment(Point_LAYOUT, scope); + VaList list = vaListFactory.apply(b -> b.addVarg(Point_LAYOUT, pointIn)); + pointOut = MemorySegment.allocateNative(Point_LAYOUT, scope); + list.nextVarg(Point_LAYOUT, SegmentAllocator.prefixAllocator(pointOut)); assertEquals((int) VH_Point_x.get(pointOut), 3); assertEquals((int) VH_Point_y.get(pointOut), 6); list.scope().close(); @@ -617,12 +627,12 @@ public class VaListTest extends NativeTestHelper { } @Test(dataProvider = "copy") - public void testCopy(Function<Consumer<VaList.Builder>, VaList> vaListFactory, ValueLayout intLayout) { - VaList list = vaListFactory.apply(b -> b.vargFromInt(intLayout, 4) - .vargFromInt(intLayout, 8)); + public void testCopy(Function<Consumer<VaList.Builder>, VaList> vaListFactory, ValueLayout.OfInt intLayout) { + VaList list = vaListFactory.apply(b -> b.addVarg(intLayout, 4) + .addVarg(intLayout, 8)); VaList copy = list.copy(); - assertEquals(copy.vargAsInt(intLayout), 4); - assertEquals(copy.vargAsInt(intLayout), 8); + assertEquals(copy.nextVarg(intLayout), 4); + assertEquals(copy.nextVarg(intLayout), 8); // try { // this logic only works on Windows! // int x = copy.vargAsInt(intLayout); @@ -631,21 +641,21 @@ public class VaListTest extends NativeTestHelper { // // ok - we exhausted the list // } - assertEquals(list.vargAsInt(intLayout), 4); - assertEquals(list.vargAsInt(intLayout), 8); + assertEquals(list.nextVarg(intLayout), 4); + assertEquals(list.nextVarg(intLayout), 8); list.scope().close(); } @Test(dataProvider = "copy", expectedExceptions = IllegalStateException.class) public void testCopyUnusableAfterOriginalClosed(Function<Consumer<VaList.Builder>, VaList> vaListFactory, - ValueLayout intLayout) { - VaList list = vaListFactory.apply(b -> b.vargFromInt(intLayout, 4) - .vargFromInt(intLayout, 8)); + ValueLayout.OfInt intLayout) { + VaList list = vaListFactory.apply(b -> b.addVarg(intLayout, 4) + .addVarg(intLayout, 8)); VaList copy = list.copy(); list.scope().close(); - copy.vargAsInt(intLayout); // should throw + copy.nextVarg(intLayout); // should throw } @DataProvider @@ -654,38 +664,40 @@ public class VaListTest extends NativeTestHelper { C_LONG_LONG.withName("x"), C_LONG_LONG.withName("y") ); - VarHandle VH_BigPoint_x = BigPoint_LAYOUT.varHandle(long.class, groupElement("x")); - VarHandle VH_BigPoint_y = BigPoint_LAYOUT.varHandle(long.class, groupElement("y")); + VarHandle VH_BigPoint_x = BigPoint_LAYOUT.varHandle(groupElement("x")); + VarHandle VH_BigPoint_y = BigPoint_LAYOUT.varHandle(groupElement("y")); GroupLayout Point_LAYOUT = MemoryLayout.structLayout( C_INT.withName("x"), C_INT.withName("y") ); - VarHandle VH_Point_x = Point_LAYOUT.varHandle(int.class, groupElement("x")); - VarHandle VH_Point_y = Point_LAYOUT.varHandle(int.class, groupElement("y")); + VarHandle VH_Point_x = Point_LAYOUT.varHandle(groupElement("x")); + VarHandle VH_Point_y = Point_LAYOUT.varHandle(groupElement("y")); GroupLayout FloatPoint_LAYOUT = MemoryLayout.structLayout( C_FLOAT.withName("x"), C_FLOAT.withName("y") ); - VarHandle VH_FloatPoint_x = FloatPoint_LAYOUT.varHandle(float.class, groupElement("x")); - VarHandle VH_FloatPoint_y = FloatPoint_LAYOUT.varHandle(float.class, groupElement("y")); + VarHandle VH_FloatPoint_x = FloatPoint_LAYOUT.varHandle(groupElement("x")); + VarHandle VH_FloatPoint_y = FloatPoint_LAYOUT.varHandle(groupElement("y")); GroupLayout HugePoint_LAYOUT = MemoryLayout.structLayout( C_LONG_LONG.withName("x"), C_LONG_LONG.withName("y"), C_LONG_LONG.withName("z") ); - VarHandle VH_HugePoint_x = HugePoint_LAYOUT.varHandle(long.class, groupElement("x")); - VarHandle VH_HugePoint_y = HugePoint_LAYOUT.varHandle(long.class, groupElement("y")); - VarHandle VH_HugePoint_z = HugePoint_LAYOUT.varHandle(long.class, groupElement("z")); + VarHandle VH_HugePoint_x = HugePoint_LAYOUT.varHandle(groupElement("x")); + VarHandle VH_HugePoint_y = HugePoint_LAYOUT.varHandle(groupElement("y")); + VarHandle VH_HugePoint_z = HugePoint_LAYOUT.varHandle(groupElement("z")); return new Object[][]{ { linkVaListCB("upcallBigStruct"), VaListConsumer.mh(vaList -> { - MemorySegment struct = vaList.vargAsSegment(BigPoint_LAYOUT, ResourceScope.newImplicitScope()); + MemorySegment struct = MemorySegment.allocateNative(BigPoint_LAYOUT, ResourceScope.newImplicitScope()); + vaList.nextVarg(BigPoint_LAYOUT, SegmentAllocator.prefixAllocator(struct)); assertEquals((long) VH_BigPoint_x.get(struct), 8); assertEquals((long) VH_BigPoint_y.get(struct), 16); })}, { linkVaListCB("upcallBigStruct"), VaListConsumer.mh(vaList -> { VaList copy = vaList.copy(); - MemorySegment struct = vaList.vargAsSegment(BigPoint_LAYOUT, ResourceScope.newImplicitScope()); + MemorySegment struct = MemorySegment.allocateNative(BigPoint_LAYOUT, ResourceScope.newImplicitScope()); + vaList.nextVarg(BigPoint_LAYOUT, SegmentAllocator.prefixAllocator(struct)); assertEquals((long) VH_BigPoint_x.get(struct), 8); assertEquals((long) VH_BigPoint_y.get(struct), 16); @@ -693,84 +705,91 @@ public class VaListTest extends NativeTestHelper { VH_BigPoint_y.set(struct, 0); // should be independent - struct = copy.vargAsSegment(BigPoint_LAYOUT, ResourceScope.newImplicitScope()); + copy.nextVarg(BigPoint_LAYOUT, SegmentAllocator.prefixAllocator(struct)); assertEquals((long) VH_BigPoint_x.get(struct), 8); assertEquals((long) VH_BigPoint_y.get(struct), 16); })}, { linkVaListCB("upcallBigStructPlusScalar"), VaListConsumer.mh(vaList -> { - MemorySegment struct = vaList.vargAsSegment(BigPoint_LAYOUT, ResourceScope.newImplicitScope()); + MemorySegment struct = MemorySegment.allocateNative(BigPoint_LAYOUT, ResourceScope.newImplicitScope()); + vaList.nextVarg(BigPoint_LAYOUT, SegmentAllocator.prefixAllocator(struct)); assertEquals((long) VH_BigPoint_x.get(struct), 8); assertEquals((long) VH_BigPoint_y.get(struct), 16); - assertEquals(vaList.vargAsLong(C_LONG_LONG), 42); + assertEquals(vaList.nextVarg(C_LONG_LONG), 42); })}, { linkVaListCB("upcallBigStructPlusScalar"), VaListConsumer.mh(vaList -> { vaList.skip(BigPoint_LAYOUT); - assertEquals(vaList.vargAsLong(C_LONG_LONG), 42); + assertEquals(vaList.nextVarg(C_LONG_LONG), 42); })}, { linkVaListCB("upcallStruct"), VaListConsumer.mh(vaList -> { - MemorySegment struct = vaList.vargAsSegment(Point_LAYOUT, ResourceScope.newImplicitScope()); + MemorySegment struct = MemorySegment.allocateNative(Point_LAYOUT, ResourceScope.newImplicitScope()); + vaList.nextVarg(Point_LAYOUT, SegmentAllocator.prefixAllocator(struct)); assertEquals((int) VH_Point_x.get(struct), 5); assertEquals((int) VH_Point_y.get(struct), 10); })}, { linkVaListCB("upcallHugeStruct"), VaListConsumer.mh(vaList -> { - MemorySegment struct = vaList.vargAsSegment(HugePoint_LAYOUT, ResourceScope.newImplicitScope()); + MemorySegment struct = MemorySegment.allocateNative(HugePoint_LAYOUT, ResourceScope.newImplicitScope()); + vaList.nextVarg(HugePoint_LAYOUT, SegmentAllocator.prefixAllocator(struct)); assertEquals((long) VH_HugePoint_x.get(struct), 1); assertEquals((long) VH_HugePoint_y.get(struct), 2); assertEquals((long) VH_HugePoint_z.get(struct), 3); })}, { linkVaListCB("upcallFloatStruct"), VaListConsumer.mh(vaList -> { - MemorySegment struct = vaList.vargAsSegment(FloatPoint_LAYOUT, ResourceScope.newImplicitScope()); + MemorySegment struct = MemorySegment.allocateNative(FloatPoint_LAYOUT, ResourceScope.newImplicitScope()); + vaList.nextVarg(FloatPoint_LAYOUT, SegmentAllocator.prefixAllocator(struct)); assertEquals((float) VH_FloatPoint_x.get(struct), 1.0f); assertEquals((float) VH_FloatPoint_y.get(struct), 2.0f); })}, { linkVaListCB("upcallMemoryAddress"), VaListConsumer.mh(vaList -> { - MemoryAddress intPtr = vaList.vargAsAddress(C_POINTER); - MemorySegment ms = intPtr.asSegment(C_INT.byteSize(), ResourceScope.globalScope()); - int x = MemoryAccess.getInt(ms); + MemoryAddress intPtr = vaList.nextVarg(C_POINTER); + MemorySegment ms = MemorySegment.ofAddress(intPtr, C_INT.byteSize(), ResourceScope.globalScope()); + int x = ms.get(JAVA_INT, 0); assertEquals(x, 10); })}, { linkVaListCB("upcallDoubles"), VaListConsumer.mh(vaList -> { - assertEquals(vaList.vargAsDouble(C_DOUBLE), 3.0); - assertEquals(vaList.vargAsDouble(C_DOUBLE), 4.0); - assertEquals(vaList.vargAsDouble(C_DOUBLE), 5.0); + assertEquals(vaList.nextVarg(C_DOUBLE), 3.0); + assertEquals(vaList.nextVarg(C_DOUBLE), 4.0); + assertEquals(vaList.nextVarg(C_DOUBLE), 5.0); })}, { linkVaListCB("upcallInts"), VaListConsumer.mh(vaList -> { - assertEquals(vaList.vargAsInt(C_INT), 10); - assertEquals(vaList.vargAsInt(C_INT), 15); - assertEquals(vaList.vargAsInt(C_INT), 20); + assertEquals(vaList.nextVarg(C_INT), 10); + assertEquals(vaList.nextVarg(C_INT), 15); + assertEquals(vaList.nextVarg(C_INT), 20); })}, { linkVaListCB("upcallStack"), VaListConsumer.mh(vaList -> { // skip all registers for (long l = 1; l <= 16; l++) { - assertEquals(vaList.vargAsLong(C_LONG_LONG), l); + assertEquals(vaList.nextVarg(C_LONG_LONG), l); } for (double d = 1; d <= 16; d++) { - assertEquals(vaList.vargAsDouble(C_DOUBLE), d); + assertEquals(vaList.nextVarg(C_DOUBLE), d); } // test some arbitrary values on the stack - assertEquals((byte) vaList.vargAsInt(C_INT), (byte) 1); - assertEquals((char) vaList.vargAsInt(C_INT), 'a'); - assertEquals((short) vaList.vargAsInt(C_INT), (short) 3); - assertEquals(vaList.vargAsInt(C_INT), 4); - assertEquals(vaList.vargAsLong(C_LONG_LONG), 5L); - assertEquals((float) vaList.vargAsDouble(C_DOUBLE), 6.0F); - assertEquals(vaList.vargAsDouble(C_DOUBLE), 7.0D); - assertEquals((byte) vaList.vargAsInt(C_INT), (byte) 8); - assertEquals((char) vaList.vargAsInt(C_INT), 'b'); - assertEquals((short) vaList.vargAsInt(C_INT), (short) 10); - assertEquals(vaList.vargAsInt(C_INT), 11); - assertEquals(vaList.vargAsLong(C_LONG_LONG), 12L); - assertEquals((float) vaList.vargAsDouble(C_DOUBLE), 13.0F); - assertEquals(vaList.vargAsDouble(C_DOUBLE), 14.0D); - - MemorySegment point = vaList.vargAsSegment(Point_LAYOUT, ResourceScope.newImplicitScope()); + assertEquals((byte) vaList.nextVarg(C_INT), (byte) 1); + assertEquals((char) vaList.nextVarg(C_INT), 'a'); + assertEquals((short) vaList.nextVarg(C_INT), (short) 3); + assertEquals(vaList.nextVarg(C_INT), 4); + assertEquals(vaList.nextVarg(C_LONG_LONG), 5L); + assertEquals((float) vaList.nextVarg(C_DOUBLE), 6.0F); + assertEquals(vaList.nextVarg(C_DOUBLE), 7.0D); + assertEquals((byte) vaList.nextVarg(C_INT), (byte) 8); + assertEquals((char) vaList.nextVarg(C_INT), 'b'); + assertEquals((short) vaList.nextVarg(C_INT), (short) 10); + assertEquals(vaList.nextVarg(C_INT), 11); + assertEquals(vaList.nextVarg(C_LONG_LONG), 12L); + assertEquals((float) vaList.nextVarg(C_DOUBLE), 13.0F); + assertEquals(vaList.nextVarg(C_DOUBLE), 14.0D); + + MemorySegment buffer = MemorySegment.allocateNative(BigPoint_LAYOUT, ResourceScope.newImplicitScope()); + SegmentAllocator bufferAllocator = SegmentAllocator.prefixAllocator(buffer); + + MemorySegment point = vaList.nextVarg(Point_LAYOUT, bufferAllocator); assertEquals((int) VH_Point_x.get(point), 5); assertEquals((int) VH_Point_y.get(point), 10); VaList copy = vaList.copy(); - MemorySegment bigPoint = vaList.vargAsSegment(BigPoint_LAYOUT, ResourceScope.newImplicitScope()); + MemorySegment bigPoint = vaList.nextVarg(BigPoint_LAYOUT, bufferAllocator); assertEquals((long) VH_BigPoint_x.get(bigPoint), 15); assertEquals((long) VH_BigPoint_y.get(bigPoint), 20); @@ -778,20 +797,20 @@ public class VaListTest extends NativeTestHelper { VH_BigPoint_y.set(bigPoint, 0); // should be independent - MemorySegment struct = copy.vargAsSegment(BigPoint_LAYOUT, ResourceScope.newImplicitScope()); + MemorySegment struct = copy.nextVarg(BigPoint_LAYOUT, bufferAllocator); assertEquals((long) VH_BigPoint_x.get(struct), 15); assertEquals((long) VH_BigPoint_y.get(struct), 20); })}, // test skip { linkVaListCB("upcallStack"), VaListConsumer.mh(vaList -> { vaList.skip(C_LONG_LONG, C_LONG_LONG, C_LONG_LONG, C_LONG_LONG); - assertEquals(vaList.vargAsLong(C_LONG_LONG), 5L); + assertEquals(vaList.nextVarg(C_LONG_LONG), 5L); vaList.skip(C_LONG_LONG, C_LONG_LONG, C_LONG_LONG, C_LONG_LONG); - assertEquals(vaList.vargAsLong(C_LONG_LONG), 10L); + assertEquals(vaList.nextVarg(C_LONG_LONG), 10L); vaList.skip(C_LONG_LONG, C_LONG_LONG, C_LONG_LONG, C_LONG_LONG, C_LONG_LONG, C_LONG_LONG); - assertEquals(vaList.vargAsDouble(C_DOUBLE), 1.0D); + assertEquals(vaList.nextVarg(C_DOUBLE), 1.0D); vaList.skip(C_DOUBLE, C_DOUBLE, C_DOUBLE, C_DOUBLE); - assertEquals(vaList.vargAsDouble(C_DOUBLE), 6.0D); + assertEquals(vaList.nextVarg(C_DOUBLE), 6.0D); })}, }; } @@ -801,8 +820,10 @@ public class VaListTest extends NativeTestHelper { static MethodHandle mh(VaListConsumer instance) { try { - return MethodHandles.lookup().findVirtual(VaListConsumer.class, "accept", + MethodHandle handle = MethodHandles.lookup().findVirtual(VaListConsumer.class, "accept", MethodType.methodType(void.class, VaList.class)).bindTo(instance); + return MethodHandles.filterArguments(handle, 0, + MethodHandles.insertArguments(ADDRESS_TO_VALIST, 1, ResourceScope.newConfinedScope())); } catch (ReflectiveOperationException e) { throw new InternalError(e); } diff --git a/test/jdk/java/foreign/virtual/TestVirtualCalls.java b/test/jdk/java/foreign/virtual/TestVirtualCalls.java index 39f80bdce1d0fdcb161fa27d53c785f338b9435f..70eecd151ceb4129863ed414d512ee2ddf16f574 100644 --- a/test/jdk/java/foreign/virtual/TestVirtualCalls.java +++ b/test/jdk/java/foreign/virtual/TestVirtualCalls.java @@ -24,6 +24,7 @@ /* * @test * @requires os.arch=="amd64" | os.arch=="x86_64" | os.arch=="aarch64" + * @library ../ * @run testng/othervm * --enable-native-access=ALL-UNNAMED * TestVirtualCalls @@ -34,28 +35,26 @@ import jdk.incubator.foreign.CLinker; import jdk.incubator.foreign.FunctionDescriptor; import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodType; +import jdk.incubator.foreign.NativeSymbol; import jdk.incubator.foreign.SymbolLookup; import jdk.incubator.foreign.MemoryAddress; import org.testng.annotations.*; -import static jdk.incubator.foreign.CLinker.*; import static org.testng.Assert.assertEquals; -public class TestVirtualCalls { +public class TestVirtualCalls extends NativeTestHelper { - static final CLinker abi = CLinker.getInstance(); + static final CLinker abi = CLinker.systemCLinker(); static final MethodHandle func; - static final MemoryAddress funcA; - static final MemoryAddress funcB; - static final MemoryAddress funcC; + static final NativeSymbol funcA; + static final NativeSymbol funcB; + static final NativeSymbol funcC; static { func = abi.downcallHandle( - MethodType.methodType(int.class), - FunctionDescriptor.of(C_INT)); + FunctionDescriptor.of(C_INT)); System.loadLibrary("Virtual"); SymbolLookup lookup = SymbolLookup.loaderLookup(); @@ -66,14 +65,14 @@ public class TestVirtualCalls { @Test public void testVirtualCalls() throws Throwable { - assertEquals((int) func.invokeExact((Addressable) funcA), 1); - assertEquals((int) func.invokeExact((Addressable) funcB), 2); - assertEquals((int) func.invokeExact((Addressable) funcC), 3); + assertEquals((int) func.invokeExact(funcA), 1); + assertEquals((int) func.invokeExact(funcB), 2); + assertEquals((int) func.invokeExact(funcC), 3); } @Test(expectedExceptions = NullPointerException.class) public void testNullTarget() throws Throwable { - int x = (int) func.invokeExact((Addressable) null); + int x = (int) func.invokeExact((NativeSymbol) null); } } diff --git a/test/jdk/java/io/ClassCache/ContinuousGCTest.java b/test/jdk/java/io/ClassCache/ContinuousGCTest.java new file mode 100644 index 0000000000000000000000000000000000000000..681663029e40dc73c8098e58cd5e0c3518eae40e --- /dev/null +++ b/test/jdk/java/io/ClassCache/ContinuousGCTest.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 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. + */ + +import java.io.NameClassCache; + +/** + * @test + * @bug 8280041 + * @summary Sanity test for ClassCache under continuous GC + * @compile/module=java.base java/io/NameClassCache.java + * @run main ContinuousGCTest + */ +public class ContinuousGCTest { + static final NameClassCache CACHE = new NameClassCache(); + static final String VALUE = "ClassCache-ContinuousGCTest"; + + public static void main(String... args) throws Throwable { + for (int c = 0; c < 1000; c++) { + test(); + System.gc(); + } + } + + public static void test() { + String cached = CACHE.get(ContinuousGCTest.class); + if (!cached.equals(VALUE)) { + throw new IllegalStateException("Cache failure, got: " + cached); + } + } +} diff --git a/test/jdk/java/io/ClassCache/NullValueTest.java b/test/jdk/java/io/ClassCache/NullValueTest.java new file mode 100644 index 0000000000000000000000000000000000000000..22b41fa071d163c55f58ccabca3a13fd01aac8ad --- /dev/null +++ b/test/jdk/java/io/ClassCache/NullValueTest.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 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. + */ + +import java.io.NullClassCache; + +/** + * @test + * @bug 8280041 + * @summary Test that ClassCache throws on trying to pass null value + * @compile/module=java.base java/io/NullClassCache.java + * @run main NullValueTest + */ +public class NullValueTest { + public static void main(String... args) throws Throwable { + try { + new NullClassCache().get(Object.class); + throw new IllegalStateException("Should have failed"); + } catch (NullPointerException npe) { + // Expected + } + } +} diff --git a/test/jdk/java/io/ClassCache/java.base/java/io/NameClassCache.java b/test/jdk/java/io/ClassCache/java.base/java/io/NameClassCache.java new file mode 100644 index 0000000000000000000000000000000000000000..ff2149fc6a28158a38cac54566aa17d391aa875a --- /dev/null +++ b/test/jdk/java/io/ClassCache/java.base/java/io/NameClassCache.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 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. + */ + +package java.io; + +public class NameClassCache extends ClassCache<String> { + protected String computeValue(Class<?> cl) { + // Return string that is not interned and specific to class + return "ClassCache-" + cl.getName(); + } + + public String get(Class<?> cl) { + return super.get(cl); + } +} diff --git a/test/jdk/java/io/ClassCache/java.base/java/io/NullClassCache.java b/test/jdk/java/io/ClassCache/java.base/java/io/NullClassCache.java new file mode 100644 index 0000000000000000000000000000000000000000..58c92ef139906fdda469242fa609b0343c158f21 --- /dev/null +++ b/test/jdk/java/io/ClassCache/java.base/java/io/NullClassCache.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 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. + */ + +package java.io; + +public class NullClassCache extends ClassCache<Object> { + protected Object computeValue(Class<?> cl) { + return null; + } + + public Object get(Class<?> cl) { + return super.get(cl); + } +} diff --git a/test/jdk/java/io/File/GetXSpace.java b/test/jdk/java/io/File/GetXSpace.java index eacc75652272a453f8c7026301518f131f7f37d6..d53b246994e5fb112d51d48e7edb0cc50ce65dbc 100644 --- a/test/jdk/java/io/File/GetXSpace.java +++ b/test/jdk/java/io/File/GetXSpace.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -34,7 +34,6 @@ import java.io.BufferedReader; import java.io.File; -import java.io.FilePermission; import java.io.InputStreamReader; import java.io.IOException; import java.nio.file.Files; @@ -108,8 +107,8 @@ public class GetXSpace { Space(String total, String free, String name) { try { - this.total = Long.valueOf(total) * KSIZE; - this.free = Long.valueOf(free) * KSIZE; + this.total = Long.parseLong(total) * KSIZE; + this.free = Long.parseLong(free) * KSIZE; } catch (NumberFormatException x) { throw new RuntimeException("the regex should have caught this", x); } @@ -155,9 +154,9 @@ public class GetXSpace { // cygwin's df lists windows path as FileSystem (1st group) name = Platform.isWindows() ? m.group(1) : m.group(4); } - al.add(new Space(m.group(2), m.group(3), name));; + al.add(new Space(m.group(2), m.group(3), name)); } - j = m.end() + 1; + j = m.end(); } else { throw new RuntimeException("unrecognized df output format: " + "charAt(" + j + ") = '" @@ -227,7 +226,7 @@ public class GetXSpace { // On Linux, ignore the NSFE if the path is one of the // /run/user/$UID mounts created by pam_systemd(8) as it // might be deleted during the test - if (!Platform.isLinux() || s.name().indexOf("/run/user") == -1) + if (!Platform.isLinux() || !s.name().contains("/run/user")) throw new RuntimeException(nsfe); } catch (IOException e) { throw new RuntimeException(e); diff --git a/test/jdk/java/io/File/LastModifiedTest.java b/test/jdk/java/io/File/LastModifiedTest.java index 62e88baa6ea07732288d473a9936244229d8bfd6..52c7d390401478634da4e8d5ce65d5792b615e8c 100644 --- a/test/jdk/java/io/File/LastModifiedTest.java +++ b/test/jdk/java/io/File/LastModifiedTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Amazon 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 diff --git a/test/jdk/java/io/File/createTempFile/NameTooLong.java b/test/jdk/java/io/File/createTempFile/NameTooLong.java index 75d604b81e10a3f14bc5ed5ad31e02095e110548..fe7bd03f95e9c4ba650c5a5b04350fd2ba15ed66 100644 --- a/test/jdk/java/io/File/createTempFile/NameTooLong.java +++ b/test/jdk/java/io/File/createTempFile/NameTooLong.java @@ -54,7 +54,7 @@ public class NameTooLong { if (ps[1].startsWith(".") && !s.contains(ps[1].substring(0, 4))) { System.err.printf("%s did not contain %s%n", s, - ps[1].substring(0, 4));; + ps[1].substring(0, 4)); failures++; } } catch (IOException e) { diff --git a/test/jdk/java/io/ObjectStreamClass/ObjectStreamClassCaching.java b/test/jdk/java/io/ObjectStreamClass/ObjectStreamClassCaching.java new file mode 100644 index 0000000000000000000000000000000000000000..74c21c540d8649c84144af451a7096b06f7dddc0 --- /dev/null +++ b/test/jdk/java/io/ObjectStreamClass/ObjectStreamClassCaching.java @@ -0,0 +1,83 @@ +/* + * 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 java.lang.ref.Reference; +import java.lang.ref.WeakReference; +import java.io.ObjectStreamClass; +import java.io.Serializable; +import java.util.ArrayList; +import org.testng.annotations.Test; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertTrue; + +/* @test + * @bug 8277072 + * @library /test/lib/ + * @summary ObjectStreamClass caches keep ClassLoaders alive + * @run testng/othervm -Xmx10m -XX:SoftRefLRUPolicyMSPerMB=1 ObjectStreamClassCaching + */ +public class ObjectStreamClassCaching { + + @Test + public void testCachingEffectiveness() throws Exception { + var ref = lookupObjectStreamClass(TestClass.class); + System.gc(); + Thread.sleep(100L); + // to trigger any ReferenceQueue processing... + lookupObjectStreamClass(AnotherTestClass.class); + assertFalse(ref.refersTo(null), + "Cache lost entry although memory was not under pressure"); + } + + @Test + public void testCacheReleaseUnderMemoryPressure() throws Exception { + var ref = lookupObjectStreamClass(TestClass.class); + pressMemoryHard(ref); + System.gc(); + Thread.sleep(100L); + assertTrue(ref.refersTo(null), + "Cache still has entry although memory was pressed hard"); + } + + // separate method so that the looked-up ObjectStreamClass is not kept on stack + private static WeakReference<?> lookupObjectStreamClass(Class<?> cl) { + return new WeakReference<>(ObjectStreamClass.lookup(cl)); + } + + private static void pressMemoryHard(Reference<?> ref) { + try { + var list = new ArrayList<>(); + while (!ref.refersTo(null)) { + list.add(new byte[1024 * 1024 * 64]); // 64 MiB chunks + } + } catch (OutOfMemoryError e) { + // release + } + } +} + +class TestClass implements Serializable { +} + +class AnotherTestClass implements Serializable { +} diff --git a/test/jdk/java/io/ObjectStreamClass/TestOSCClassLoaderLeak.java b/test/jdk/java/io/ObjectStreamClass/TestOSCClassLoaderLeak.java new file mode 100644 index 0000000000000000000000000000000000000000..3a99760bb6ebb6798feddeddf833e52663435ce3 --- /dev/null +++ b/test/jdk/java/io/ObjectStreamClass/TestOSCClassLoaderLeak.java @@ -0,0 +1,108 @@ +/* + * 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 java.lang.ref.WeakReference; +import java.lang.reflect.Constructor; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.io.ObjectStreamClass; +import java.io.ObjectStreamField; +import java.io.Serializable; +import java.util.Arrays; +import org.testng.annotations.Test; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; + +import jdk.test.lib.util.ForceGC; + +/* @test + * @bug 8277072 + * @library /test/lib/ + * @build jdk.test.lib.util.ForceGC + * @summary ObjectStreamClass caches keep ClassLoaders alive + * @run testng TestOSCClassLoaderLeak + */ +public class TestOSCClassLoaderLeak { + + @Test + public void testClassLoaderLeak() throws Exception { + TestClassLoader myOwnClassLoader = new TestClassLoader(); + Class<?> loadClass = myOwnClassLoader.loadClass("ObjectStreamClass_MemoryLeakExample"); + Constructor con = loadClass.getConstructor(); + con.setAccessible(true); + Object objectStreamClass_MemoryLeakExample = con.newInstance(); + objectStreamClass_MemoryLeakExample.toString(); + + WeakReference<Object> myOwnClassLoaderWeakReference = new WeakReference<>(myOwnClassLoader); + assertNotNull(myOwnClassLoaderWeakReference.get()); + objectStreamClass_MemoryLeakExample = null; + myOwnClassLoader = null; + loadClass = null; + con = null; + assertNotNull(myOwnClassLoaderWeakReference.get()); + + ForceGC gc = new ForceGC(); + assertTrue(gc.await(() -> myOwnClassLoaderWeakReference.get() == null)); + } +} + +class ObjectStreamClass_MemoryLeakExample { + private static final ObjectStreamField[] fields = ObjectStreamClass.lookup(TestClass.class).getFields(); + public ObjectStreamClass_MemoryLeakExample() { + } + + @Override + public String toString() { + return Arrays.toString(fields); + } +} + +class TestClassLoader extends ClassLoader { + + @Override + public Class<?> loadClass(String name) throws ClassNotFoundException { + if (name.equals("TestClass") || name.equals("ObjectStreamClass_MemoryLeakExample")) { + byte[] bt = loadClassData(name); + return defineClass(name, bt, 0, bt.length); + } else { + return super.loadClass(name); + } + } + + private static byte[] loadClassData(String className) { + ByteArrayOutputStream byteSt = new ByteArrayOutputStream(); + try (InputStream is = TestClassLoader.class.getClassLoader().getResourceAsStream(className.replace(".", "/") + ".class")) { + int len = 0; + while ((len = is.read()) != -1) { + byteSt.write(len); + } + } catch (java.io.IOException e) { + e.printStackTrace(); + } + return byteSt.toByteArray(); + } +} + +class TestClass implements Serializable { + public String x; +} diff --git a/test/jdk/java/io/OutputStreamWriter/WriteAfterClose.java b/test/jdk/java/io/OutputStreamWriter/WriteAfterClose.java index 0982df62a6de6a9b20e6b72a9a7e47e86276891d..d2bdd362065197bf3f4829256f96e614e9ae4aa0 100644 --- a/test/jdk/java/io/OutputStreamWriter/WriteAfterClose.java +++ b/test/jdk/java/io/OutputStreamWriter/WriteAfterClose.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -74,7 +74,7 @@ public class WriteAfterClose { try { wtr.write("a", 0, 1); - System.out.println("FALIED: Allows string buf write on a closed stream"); + System.out.println("FAILED: Allows string buf write on a closed stream"); failed = true; } catch (Exception e) { } diff --git a/test/jdk/java/io/PrintStream/InheritEncodingTest.java b/test/jdk/java/io/PrintStream/InheritEncodingTest.java new file mode 100644 index 0000000000000000000000000000000000000000..e31404114a05e96ff493305a264f7e1e6244f566 --- /dev/null +++ b/test/jdk/java/io/PrintStream/InheritEncodingTest.java @@ -0,0 +1,107 @@ +/* + * 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 org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import static org.testng.Assert.assertEquals; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.io.PrintStream; +import java.io.PrintWriter; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; + +/** + * @test + * @bug 8276970 + * @summary Test to verify the charset in PrintStream is inherited + * in the OutputStreamWriter/PrintWriter + * @run testng InheritEncodingTest + */ +@Test +public class InheritEncodingTest { + + private static final String testString = "\u00e9\u3042"; // "éあ" + + @DataProvider + public Object[][] encodings() { + return new Object[][]{ + {StandardCharsets.ISO_8859_1}, + {StandardCharsets.US_ASCII}, + {StandardCharsets.UTF_8}, + {StandardCharsets.UTF_16}, + {StandardCharsets.UTF_16BE}, + {StandardCharsets.UTF_16LE}, + }; + } + + @Test (dataProvider = "encodings") + public void testOutputStreamWriter(Charset stdCharset) throws IOException { + var ba = new ByteArrayOutputStream(); + var ps = new PrintStream(ba, true, stdCharset); + var expected = new String(testString.getBytes(stdCharset), stdCharset); + + // tests OutputStreamWriter's encoding explicitly + var osw = new OutputStreamWriter(ps); + assertEquals(Charset.forName(osw.getEncoding()), stdCharset); + + // tests roundtrip result + osw.write(testString); + osw.flush(); + var result = ba.toString(stdCharset); + assertEquals(result, expected); + } + + @Test (dataProvider = "encodings") + public void testPrintWriter(Charset stdCharset) throws IOException { + var ba = new ByteArrayOutputStream(); + var ps = new PrintStream(ba, true, stdCharset); + var expected = new String(testString.getBytes(stdCharset), stdCharset); + + // tests roundtrip result + var pw = new PrintWriter(ps); + pw.write(testString); + pw.flush(); + var result = ba.toString(stdCharset); + assertEquals(result, expected); + } + + @Test (dataProvider = "encodings") + public void testPrintStream(Charset stdCharset) throws IOException { + var ba = new ByteArrayOutputStream(); + var ps = new PrintStream(ba, true, stdCharset); + var expected = new String(testString.getBytes(stdCharset), stdCharset); + + // tests PrintStream's charset explicitly + var psWrapper = new PrintStream(ps); + assertEquals(psWrapper.charset(), stdCharset); + + // tests roundtrip result + psWrapper.print(testString); + psWrapper.flush(); + var result = ba.toString(stdCharset); + assertEquals(result, expected); + } +} diff --git a/test/jdk/java/io/RandomAccessFile/WriteBytesChars.java b/test/jdk/java/io/RandomAccessFile/WriteBytesChars.java index cc89709b7e79590b6f7ca25cc3c9ff27cdd584e5..7b564bc633a509fef1c7eb94b8883ebacd92b44d 100644 --- a/test/jdk/java/io/RandomAccessFile/WriteBytesChars.java +++ b/test/jdk/java/io/RandomAccessFile/WriteBytesChars.java @@ -37,7 +37,7 @@ public class WriteBytesChars { byte[] b = new byte[80]; File fn = new File("x.WriteBytesChars"); - RandomAccessFile raf = new RandomAccessFile(fn , "rw");; + RandomAccessFile raf = new RandomAccessFile(fn , "rw"); try { for (int i = 0; i < 80; i++) { buf[i] = 'a'; diff --git a/test/jdk/java/io/Serializable/GetField/ReadFieldsCNF.java b/test/jdk/java/io/Serializable/GetField/ReadFieldsCNF.java new file mode 100644 index 0000000000000000000000000000000000000000..7b91222d737e7e7b34ece765525f6f272a5677d4 --- /dev/null +++ b/test/jdk/java/io/Serializable/GetField/ReadFieldsCNF.java @@ -0,0 +1,190 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8273660 + * @summary Verify that ObjectInputStream ReadFields correctly reports ClassNotFoundException + * while getting the field value. The test uses Vector that calls ReadFields from its readObject. + * @library /test/lib + * @run testng ReadFieldsCNF + * @run testng/othervm -Djdk.serialGetFieldCnfeReturnsNull=true ReadFieldsCNF + */ + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.io.StreamCorruptedException; +import java.nio.charset.StandardCharsets; +import java.util.Vector; + +import org.testng.annotations.Test; +import org.testng.Assert; + +import jdk.test.lib.hexdump.HexPrinter; +import jdk.test.lib.hexdump.ObjectStreamPrinter; + +public class ReadFieldsCNF { + + private static final boolean GETFIELD_CNFE_RETURNS_NULL = + Boolean.getBoolean("jdk.serialGetFieldCnfeReturnsNull"); + + + /** + * Test a Vector holding a reference to a class instance that will not be found. + * @throws IOException If any other exception occurs + */ + @Test + private static void testVectorWithRole() throws IOException { + System.out.println("Property GETFIELD_CNFE_RETURNS_NULL: " + GETFIELD_CNFE_RETURNS_NULL); + + Role role = new Role(); + Vector<Role> vector = new Vector<>(); + vector.add(role); + + // Modify the byte stream to change the classname to be deserialized to + // XeadFieldsCNF$Role. + byte[] bytes = writeObject(vector); + + // Locate the name of the class to be deserialize + String s = new String(bytes, StandardCharsets.ISO_8859_1); // Map bytes to chars + int off = s.indexOf(Role.class.getName()); + System.out.printf("Role offset: %d (0x%x) : %s%n", off, off, Role.class.getName()); + if (off < 0) { + HexPrinter.simple().formatter(ObjectStreamPrinter.formatter()).format(bytes); + Assert.fail("classname not found"); + } + + bytes[off] = (byte) 'X'; // replace R with X -> Class not found + + // Deserialize the Vector expecting a ClassNotFoundException + ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(bytes)); + try { + Object obj = in.readObject(); + System.out.println("Read: " + obj); + Assert.fail("Should not reach here, an exception should always occur"); + } catch (ClassNotFoundException cnfe) { + // Expected ClassNotFoundException + String expected = "XeadFieldsCNF$Role"; + Assert.assertEquals(expected, cnfe.getMessage(), "Wrong classname"); + if (GETFIELD_CNFE_RETURNS_NULL) { + Assert.fail("Expected IOException got ClassNotFoundException", cnfe); + } + System.out.println("Normal: OIS.readObject: " + cnfe); + } catch (StreamCorruptedException ioe) { + if (!GETFIELD_CNFE_RETURNS_NULL) { + Assert.fail("Expected ClassNotFoundException got StreamCorruptedException ", ioe); + } + System.out.println("Normal: " + ioe); + } + // Other exceptions cause the test to fail + } + + /** + * For an object holding a reference to a class that will not be found. + * @throws IOException If any other exception occurs + */ + @Test + private static void testHolderWithRole() throws IOException { + System.out.println("Property GETFIELD_CNFE_RETURNS_NULL: " + GETFIELD_CNFE_RETURNS_NULL); + Role role = new Role(); + Holder holder = new Holder(role); + + // Modify the byte stream to change the classname to be deserialized to + // XeadFieldsCNF$Role. + byte[] bytes = writeObject(holder); + + String s = new String(bytes, StandardCharsets.ISO_8859_1); // Map bytes to chars + int off = s.indexOf(Role.class.getName(), 0); + off = s.indexOf(Role.class.getName(), off + 1); // 2nd occurrence of classname + System.out.printf("Role offset: %d (0x%x)%n", off, off); + if (off < 0) { + HexPrinter.simple().formatter(ObjectStreamPrinter.formatter()).format(bytes); + Assert.fail("classname found at index: " + off + " (0x" + Integer.toHexString(off) + ")"); + } + + bytes[off] = (byte) 'X'; // replace R with X -> Class not found + + // Deserialize the Vector expecting a ClassNotFoundException + ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(bytes)); + try { + Holder obj = (Holder)in.readObject(); + System.out.println("Read: " + obj); + Assert.fail("Should not reach here, an exception should always occur"); + } catch (ClassNotFoundException cnfe) { + // Expected ClassNotFoundException + String expected = "XeadFieldsCNF$Role"; + Assert.assertEquals(expected, cnfe.getMessage(), "Wrong classname"); + System.out.println("Normal: OIS.readObject: " + cnfe); + } catch (StreamCorruptedException ioe) { + if (!GETFIELD_CNFE_RETURNS_NULL) { + Assert.fail("Expected ClassNotFoundException got StreamCorruptedException ", ioe); + } + System.out.println("Normal: " + ioe); + } + // Other exceptions cause the test to fail + } + + private static byte[] writeObject(Object o) throws IOException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try (ObjectOutputStream os = new ObjectOutputStream(baos)) { + os.writeObject(o); + } + return baos.toByteArray(); + } + + static class Role implements Serializable { + private static final long serialVersionUID = 0L; + + Role() {} + } + + static class Holder implements Serializable { + private static final long serialVersionUID = 1L; + + Role role; + + Holder(Role role) { + this.role = role; + } + + private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { + ObjectInputStream.GetField fields = ois.readFields(); + try { + Object repl = new Object(); + role = (Role)fields.get("role", repl); + System.out.println("Holder.readObject Role: " + role); + } catch (Exception ex) { + // Catch CNFE and ignore it; check elsewhere that CNFE is thrown from OIS.readObject + System.out.println("Normal: exception in Holder.readObject, ignoring: " + ex); + } + } + + public String toString() { + return "role: " + role; + } + } +} diff --git a/test/jdk/java/io/Serializable/InvalidClassException/TestIceConstructors.java b/test/jdk/java/io/Serializable/InvalidClassException/TestIceConstructors.java new file mode 100644 index 0000000000000000000000000000000000000000..991ec32ec8f215f9557d4b7558e947234c5791f9 --- /dev/null +++ b/test/jdk/java/io/Serializable/InvalidClassException/TestIceConstructors.java @@ -0,0 +1,58 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8282696 + * @summary Verify message and cause handling of InvalidClassException + */ +import java.io.*; +import java.util.Objects; + +public class TestIceConstructors { + public static void main(String... args) { + String reason = "reason"; + Throwable cause = new RuntimeException(); + + testException(new InvalidClassException(reason), + reason, null); + testException(new InvalidClassException(reason, cause), + reason, cause); + testException(new InvalidClassException("prefix", reason, cause), + "prefix" + "; " + reason, cause); + } + + private static void testException(InvalidClassException ice, + String expectedMessage, + Throwable expectedCause) { + var message = ice.getMessage(); + if (!Objects.equals(message, expectedMessage)) { + throw new RuntimeException("Unexpected message " + message); + } + + var cause = ice.getCause(); + if (cause != expectedCause) { + throw new RuntimeException("Unexpected cause"); + } + } +} diff --git a/test/jdk/java/io/Serializable/InvalidObjectException/TestIoeConstructors.java b/test/jdk/java/io/Serializable/InvalidObjectException/TestIoeConstructors.java new file mode 100644 index 0000000000000000000000000000000000000000..d3a952e62df1846e13cab77a4b4df3be3d7a279b --- /dev/null +++ b/test/jdk/java/io/Serializable/InvalidObjectException/TestIoeConstructors.java @@ -0,0 +1,56 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8282696 + * @summary Verify message and cause handling of InvalidObjectException + */ +import java.io.*; +import java.util.Objects; + +public class TestIoeConstructors { + public static void main(String... args) { + String reason = "reason"; + Throwable cause = new RuntimeException(); + + testException(new InvalidObjectException(reason), + reason, null); + testException(new InvalidObjectException(reason, cause), + reason, cause); + } + + private static void testException(InvalidObjectException ioe, + String expectedMessage, + Throwable expectedCause) { + var message = ioe.getMessage(); + if (!Objects.equals(message, expectedMessage)) { + throw new RuntimeException("Unexpected message " + message); + } + + var cause = ioe.getCause(); + if (cause != expectedCause) { + throw new RuntimeException("Unexpected cause"); + } + } +} diff --git a/test/jdk/java/io/Serializable/oldTests/WritePrimitive.java b/test/jdk/java/io/Serializable/oldTests/WritePrimitive.java index f2bd28d75f73a06b3065cc8bf6d0a9732526c89f..e6b841e7a49751d02ebd6db06884c6fa11af63d1 100644 --- a/test/jdk/java/io/Serializable/oldTests/WritePrimitive.java +++ b/test/jdk/java/io/Serializable/oldTests/WritePrimitive.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -22,6 +22,7 @@ */ /* @test + * @bug 8276806 8278463 * @summary it is a new version of an old test which was * /src/share/test/serialization/piotest.java * Test of serialization/deserialization of @@ -32,28 +33,27 @@ */ import java.io.*; +import java.util.Arrays; public class WritePrimitive { public static void main (String argv[]) throws IOException { System.err.println("\nRegression test for testing of " + "serialization/deserialization of primitives \n"); + int i = 123456; + byte b = 12; + short s = 45; + char c = 'A'; + long l = 1234567890000L; + float f = 3.14159f; + double d = f * 2; + boolean z = true; + String string = "The String"; + PrimitivesTest prim = new PrimitivesTest(); + byte[] ba = {1, 2, 3, 4, 5, 6, 7}; // byte array to write - FileInputStream istream = null; - FileOutputStream ostream = null; - try { - int i = 123456; - byte b = 12; - short s = 45; - char c = 'A'; - long l = 1234567890000L; - float f = 3.14159f; - double d = f*2; - boolean z = true; - String string = "The String"; - PrimitivesTest prim = new PrimitivesTest(); - - ostream = new FileOutputStream("piotest1.tmp"); - ObjectOutputStream p = new ObjectOutputStream(ostream); + byte[] bytes; + try (ByteArrayOutputStream ostream = new ByteArrayOutputStream(); + ObjectOutputStream p = new ObjectOutputStream(ostream)) { p.writeInt(i); p.writeByte(b); @@ -63,14 +63,20 @@ public class WritePrimitive { p.writeFloat(f); p.writeDouble(d); p.writeBoolean(z); + p.write(ba); // for simple read(byte[]) + p.write(ba); // for readFully(byte[]) + p.write(ba, 0, ba.length - 2); // for readFully(byte[], 0, 7) p.writeUTF(string); p.writeObject(string); p.writeObject(prim); p.flush(); + bytes = ostream.toByteArray(); + + } - istream = new FileInputStream("piotest1.tmp"); - ObjectInputStream q = new ObjectInputStream(istream); + ByteArrayInputStream istream = new ByteArrayInputStream(bytes); + try (ObjectInputStream q = new ObjectInputStream(istream);) { int i_u = q.readInt(); byte b_u = q.readByte(); @@ -80,6 +86,12 @@ public class WritePrimitive { float f_u = q.readFloat(); double d_u = q.readDouble(); boolean z_u = q.readBoolean(); + byte[] ba_readBuf = new byte[ba.length]; + int ba_readLen = q.read(ba_readBuf); + byte[] ba_readFullyBuf = new byte[ba.length]; + int ba_readFullyLen = q.read(ba_readFullyBuf); + byte[] ba_readFullySizedBuf = new byte[ba.length]; + int ba_readFullySizedLen = q.read(ba_readFullySizedBuf, 0, ba.length - 2); String string_utf = q.readUTF(); String string_u = (String)q.readObject(); if (i != i_u) { @@ -120,6 +132,10 @@ public class WritePrimitive { z_u); throw new Error(); } + checkArray("read(byte[])", ba, ba.length, ba_readBuf, ba_readLen); + checkArray("readFully(byte[])", ba, ba.length, ba_readFullyBuf, ba_readFullyLen); + checkArray("readFully(byte[], off, len)", ba, ba.length - 2, ba_readFullySizedBuf, ba_readFullySizedLen); + if (!string.equals(string_utf)) { System.err.println("\nString: expected " + string + " actual " + string_utf); @@ -144,20 +160,26 @@ public class WritePrimitive { System.err.print("TEST FAILED: "); e.printStackTrace(); - System.err.println("\nInput remaining"); + System.err.println("\nBytes read: " + (bytes.length - istream.available()) + + ", Input remaining: " + istream.available()); int ch; try { while ((ch = istream.read()) != -1) { System.err.print("\n " + Integer.toString(ch, 16)+ " "); } System.out.println("\n "); - } catch (Exception f) { + } catch (Exception fex) { throw new Error(); } throw new Error(); - } finally { - if (istream != null) istream.close(); - if (ostream != null) ostream.close(); + } + } + + static void checkArray(String label, byte[] expected, int expectedLen, byte[] actual, int actualLen) { + int mismatch = Arrays.mismatch(expected, 0, expectedLen, actual, 0, actualLen); + if (actualLen != expectedLen || mismatch >= 0) { + System.err.println("\n" + label + ": expected " + expectedLen + " actual " + actualLen + ", mismatch: " + mismatch); + throw new Error(); } } } diff --git a/test/jdk/java/io/Serializable/serialFilter/InvalidGlobalFilterTest.java b/test/jdk/java/io/Serializable/serialFilter/InvalidGlobalFilterTest.java index a00f42f65653d1198c83a998326a19f7fc8cbf03..a017354b103d2a534136c066f0a521bacfb091ed 100644 --- a/test/jdk/java/io/Serializable/serialFilter/InvalidGlobalFilterTest.java +++ b/test/jdk/java/io/Serializable/serialFilter/InvalidGlobalFilterTest.java @@ -21,67 +21,100 @@ * questions. */ -import jdk.test.lib.process.OutputAnalyzer; -import jdk.test.lib.process.ProcessTools; +import org.testng.Assert; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; -import java.io.File; +import java.io.ByteArrayInputStream; +import java.io.IOException; import java.io.ObjectInputFilter; +import java.io.ObjectInputStream; +import java.util.Map; /* * @test - * @bug 8269336 + * @bug 8278087 * @summary Test that an invalid pattern value for the jdk.serialFilter system property causes an - * exception to be thrown in the class initialization of java.io.ObjectInputFilter.Config class - * @library /test/lib - * @run driver InvalidGlobalFilterTest + * exception to be thrown when an attempt is made to use the filter or deserialize. + * A subset of invalid filter patterns is tested. + * @run testng/othervm -Djdk.serialFilter=.* InvalidGlobalFilterTest + * @run testng/othervm -Djdk.serialFilter=! InvalidGlobalFilterTest + * @run testng/othervm -Djdk.serialFilter=/ InvalidGlobalFilterTest + * */ +@Test public class InvalidGlobalFilterTest { private static final String serialPropName = "jdk.serialFilter"; + private static final String serialFilter = System.getProperty(serialPropName); + + static { + // Enable logging + System.setProperty("java.util.logging.config.file", + System.getProperty("test.src", ".") + "/logging.properties"); + } /** - * Launches multiple instances of a Java program by passing each instance an invalid value - * for the {@code jdk.serialFilter} system property. The launched program then triggers the - * class initialization of {@code ObjectInputFilter.Config} class to have it parse the (invalid) - * value of the system property. The launched program is expected to propagate the exception - * raised by the {@code ObjectInputFilter.Config} initialization and the test asserts that the - * launched program did indeed fail with this expected exception. + * Map of invalid patterns to the expected exception message. */ - public static void main(final String[] args) throws Exception { - final String[] invalidPatterns = {".*", ".**", "!", "/java.util.Hashtable", "java.base/", "/"}; - for (final String invalidPattern : invalidPatterns) { - final ProcessBuilder processBuilder = ProcessTools.createJavaProcessBuilder( - "-D" + serialPropName + "=" + invalidPattern, - "-Djava.util.logging.config.file=" + System.getProperty("test.src") - + File.separator + "logging.properties", - ObjectInputFilterConfigLoader.class.getName()); - // launch a process by passing it an invalid value for -Djdk.serialFilter - final OutputAnalyzer outputAnalyzer = ProcessTools.executeProcess(processBuilder); - try { - // we expect the JVM launch to fail - outputAnalyzer.shouldNotHaveExitValue(0); - // do an additional check to be sure it failed for the right reason - outputAnalyzer.stderrShouldContain("java.lang.ExceptionInInitializerError"); - } finally { - // fail or pass, we print out the generated output from the launched program - // for any debugging - System.err.println("Diagnostics from process " + outputAnalyzer.pid() + ":"); - // print out any stdout/err that was generated in the launched program - outputAnalyzer.reportDiagnosticSummary(); - } + private static final Map<String, String> invalidMessages = + Map.of(".*", "Invalid jdk.serialFilter: package missing in: \".*\"", + ".**", "Invalid jdk.serialFilter: package missing in: \".**\"", + "!", "Invalid jdk.serialFilter: class or package missing in: \"!\"", + "/java.util.Hashtable", "Invalid jdk.serialFilter: module name is missing in: \"/java.util.Hashtable\"", + "java.base/", "Invalid jdk.serialFilter: class or package missing in: \"java.base/\"", + "/", "Invalid jdk.serialFilter: module name is missing in: \"/\""); + + @DataProvider(name = "MethodsToCall") + private Object[][] cases() { + return new Object[][] { + {serialFilter, "getSerialFilter", (Assert.ThrowingRunnable) () -> ObjectInputFilter.Config.getSerialFilter()}, + {serialFilter, "setSerialFilter", (Assert.ThrowingRunnable) () -> ObjectInputFilter.Config.setSerialFilter(new NoopFilter())}, + {serialFilter, "new ObjectInputStream(is)", (Assert.ThrowingRunnable) () -> new ObjectInputStream(new ByteArrayInputStream(new byte[0]))}, + {serialFilter, "new OISSubclass()", (Assert.ThrowingRunnable) () -> new OISSubclass()}, + }; + } + + /** + * Test each method that should throw IllegalStateException based on + * the invalid arguments it was launched with. + */ + @Test(dataProvider = "MethodsToCall") + public void initFaultTest(String pattern, String method, Assert.ThrowingRunnable runnable) { + + IllegalStateException ex = Assert.expectThrows(IllegalStateException.class, + runnable); + + String expected = invalidMessages.get(serialFilter); + if (expected == null) { + Assert.fail("No expected message for filter: " + serialFilter); } + System.out.println(ex.getMessage()); + Assert.assertEquals(ex.getMessage(), expected, "wrong message"); } - // A main() class which just triggers the class initialization of ObjectInputFilter.Config - private static final class ObjectInputFilterConfigLoader { + private static class NoopFilter implements ObjectInputFilter { + /** + * Returns UNDECIDED. + * + * @param filter the FilterInfo + * @return Status.UNDECIDED + */ + public ObjectInputFilter.Status checkInput(FilterInfo filter) { + return ObjectInputFilter.Status.UNDECIDED; + } - public static void main(final String[] args) throws Exception { - System.out.println("JVM was launched with " + serialPropName - + " system property set to " + System.getProperty(serialPropName)); - // this call is expected to fail and we aren't interested in the result. - // we just let the exception propagate out of this call and fail the - // launched program. The test which launched this main, then asserts - // that the exception was indeed thrown. - ObjectInputFilter.Config.getSerialFilter(); + public String toString() { + return "NoopFilter"; } } + + /** + * Subclass of ObjectInputStream to test subclassing constructor. + */ + private static class OISSubclass extends ObjectInputStream { + + protected OISSubclass() throws IOException { + } + } + } diff --git a/test/jdk/java/io/Serializable/serialFilter/SerialFactoryFaults.java b/test/jdk/java/io/Serializable/serialFilter/SerialFactoryFaults.java index 30d35aa888e5e3c39d984bdf4877e1f9450e3a1e..1d35306a42683f9da9f3494828e2da18a5d7d9f4 100644 --- a/test/jdk/java/io/Serializable/serialFilter/SerialFactoryFaults.java +++ b/test/jdk/java/io/Serializable/serialFilter/SerialFactoryFaults.java @@ -22,10 +22,14 @@ */ import org.testng.Assert; +import org.testng.annotations.DataProvider; import org.testng.annotations.Test; +import java.io.ByteArrayInputStream; +import java.io.IOException; import java.io.ObjectInputFilter; import java.io.ObjectInputFilter.Config; +import java.io.ObjectInputStream; import java.util.function.BinaryOperator; /* @test @@ -39,33 +43,47 @@ import java.util.function.BinaryOperator; @Test public class SerialFactoryFaults { + // Sample the serial factory class name + private static final String factoryName = System.getProperty("jdk.serialFilterFactory"); + static { // Enable logging System.setProperty("java.util.logging.config.file", System.getProperty("test.src", ".") + "/logging.properties"); } - public void initFaultTest() { - String factoryName = System.getProperty("jdk.serialFilterFactory"); - ExceptionInInitializerError ex = Assert.expectThrows(ExceptionInInitializerError.class, - () -> Config.getSerialFilterFactory()); - Throwable cause = ex.getCause(); + @DataProvider(name = "MethodsToCall") + private Object[][] cases() { + return new Object[][] { + {"getSerialFilterFactory", (Assert.ThrowingRunnable) () -> Config.getSerialFilterFactory()}, + {"setSerialFilterFactory", (Assert.ThrowingRunnable) () -> Config.setSerialFilterFactory(new NoopFactory())}, + {"new ObjectInputStream(is)", (Assert.ThrowingRunnable) () -> new ObjectInputStream(new ByteArrayInputStream(new byte[0]))}, + {"new OISSubclass()", (Assert.ThrowingRunnable) () -> new OISSubclass()}, + }; + } + + /** + * Test each method that should throw IllegalStateException based on + * the invalid arguments it was launched with. + */ + @Test(dataProvider = "MethodsToCall") + public void initFaultTest(String name, Assert.ThrowingRunnable runnable) { + IllegalStateException ex = Assert.expectThrows(IllegalStateException.class, + runnable); + final String msg = ex.getMessage(); if (factoryName.equals("ForcedError_NoSuchClass")) { - Assert.assertEquals(cause.getClass(), - ClassNotFoundException.class, "wrong exception"); + Assert.assertEquals(msg, + "invalid jdk.serialFilterFactory: ForcedError_NoSuchClass: java.lang.ClassNotFoundException: ForcedError_NoSuchClass", "wrong exception"); } else if (factoryName.equals("SerialFactoryFaults$NoPublicConstructor")) { - Assert.assertEquals(cause.getClass(), - NoSuchMethodException.class, "wrong exception"); + Assert.assertEquals(msg, + "invalid jdk.serialFilterFactory: SerialFactoryFaults$NoPublicConstructor: java.lang.NoSuchMethodException: SerialFactoryFaults$NoPublicConstructor.<init>()", "wrong exception"); } else if (factoryName.equals("SerialFactoryFaults$ConstructorThrows")) { - Assert.assertEquals(cause.getClass(), - IllegalStateException.class, "wrong exception"); + Assert.assertEquals(msg, + "invalid jdk.serialFilterFactory: SerialFactoryFaults$ConstructorThrows: java.lang.RuntimeException: constructor throwing a runtime exception", "wrong exception"); } else if (factoryName.equals("SerialFactoryFaults$FactorySetsFactory")) { - Assert.assertEquals(cause.getClass(), - IllegalStateException.class, "wrong exception"); - Assert.assertEquals(cause.getMessage(), - "Cannot replace filter factory: initialization incomplete", - "wrong message"); + Assert.assertEquals(msg, + "invalid jdk.serialFilterFactory: SerialFactoryFaults$FactorySetsFactory: java.lang.IllegalStateException: Serial filter factory initialization incomplete", "wrong exception"); } else { Assert.fail("No test for filter factory: " + factoryName); } @@ -90,7 +108,7 @@ public class SerialFactoryFaults { public static final class ConstructorThrows implements BinaryOperator<ObjectInputFilter> { public ConstructorThrows() { - throw new IllegalStateException("SerialFactoryFaults$ConstructorThrows"); + throw new RuntimeException("constructor throwing a runtime exception"); } public ObjectInputFilter apply(ObjectInputFilter curr, ObjectInputFilter next) { @@ -112,4 +130,21 @@ public class SerialFactoryFaults { } } + public static final class NoopFactory implements BinaryOperator<ObjectInputFilter> { + public NoopFactory() {} + + public ObjectInputFilter apply(ObjectInputFilter curr, ObjectInputFilter next) { + throw new RuntimeException("NYI"); + } + } + + /** + * Subclass of ObjectInputStream to test subclassing constructor. + */ + private static class OISSubclass extends ObjectInputStream { + + protected OISSubclass() throws IOException { + } + } + } diff --git a/test/jdk/java/lang/Character/UnicodeBlock/NumberEntities.java b/test/jdk/java/lang/Character/UnicodeBlock/NumberEntities.java new file mode 100644 index 0000000000000000000000000000000000000000..a2a2312d6e30143a15d782a0f3437c647b7a075a --- /dev/null +++ b/test/jdk/java/lang/Character/UnicodeBlock/NumberEntities.java @@ -0,0 +1,50 @@ +/* + * 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. + */ + +/** + * @test + * @bug 8080535 8191410 8215194 8221431 8239383 8268081 8283465 + * @summary Check if the NUM_ENTITIES field reflects the correct number + * of Character.UnicodeBlock constants. + * @modules java.base/java.lang:open + * @run testng NumberEntities + */ + +import static org.testng.Assert.assertEquals; +import org.testng.annotations.Test; + +import java.lang.reflect.Field; +import java.util.Map; + +@Test +public class NumberEntities { + public void test_NumberEntities() throws Throwable { + // The number of entries in Character.UnicodeBlock.map. + // See src/java.base/share/classes/java/lang/Character.java + Field n = Character.UnicodeBlock.class.getDeclaredField("NUM_ENTITIES"); + Field m = Character.UnicodeBlock.class.getDeclaredField("map"); + n.setAccessible(true); + m.setAccessible(true); + assertEquals(((Map)m.get(null)).size(), n.getInt(null)); + } +} diff --git a/test/jdk/java/lang/Character/UnicodeBlock/OptimalMapSize.java b/test/jdk/java/lang/Character/UnicodeBlock/OptimalMapSize.java deleted file mode 100644 index 8883f0d8263296b52ec6111ece22a043cb745b3d..0000000000000000000000000000000000000000 --- a/test/jdk/java/lang/Character/UnicodeBlock/OptimalMapSize.java +++ /dev/null @@ -1,72 +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. - */ - -/** - * @test - * @bug 8080535 8191410 8215194 8221431 8239383 - * @summary Expected size of Character.UnicodeBlock.map is not optimal - * @library /test/lib - * @modules java.base/java.lang:open - * java.base/java.util:open - * @build jdk.test.lib.util.OptimalCapacity - * @run main OptimalMapSize - */ - -import java.lang.reflect.Field; -import jdk.test.lib.util.OptimalCapacity; - -// What will be the number of the Unicode blocks in the future. -// -// According to http://www.unicode.org/versions/Unicode7.0.0/ , -// in Unicode 7 there will be added 32 new blocks (96 with aliases). -// According to http://www.unicode.org/versions/beta-8.0.0.html , -// in Unicode 8 there will be added 10 more blocks (30 with aliases). -// -// After implementing support of Unicode 9 and 10 in Java, there will -// be 638 entries in Character.UnicodeBlock.map. -// -// As of Unicode 11, 667 entries are expected. -// As of Unicode 12.1, 676 entries are expected. -// As of Unicode 13.0, 684 entries are expected. -// -// Initialization of the map and this test will have to be adjusted -// accordingly then. -// -// Note that HashMap's implementation aligns the initial capacity to -// a power of two size, so it will end up 1024 (and thus succeed) in -// cases, such as 638, 667, 676, and 684. - -public class OptimalMapSize { - public static void main(String[] args) throws Throwable { - // The initial size of Character.UnicodeBlock.map. - // See src/java.base/share/classes/java/lang/Character.java - Field f = Character.UnicodeBlock.class.getDeclaredField("NUM_ENTITIES"); - f.setAccessible(true); - int num_entities = f.getInt(null); - assert num_entities == 684; - int initialCapacity = (int)(num_entities / 0.75f + 1.0f); - - OptimalCapacity.ofHashMap(Character.UnicodeBlock.class, - "map", initialCapacity); - } -} diff --git a/src/hotspot/share/gc/shared/cardGeneration.inline.hpp b/test/jdk/java/lang/Class/ArrayType.java similarity index 54% rename from src/hotspot/share/gc/shared/cardGeneration.inline.hpp rename to test/jdk/java/lang/Class/ArrayType.java index bd8285af679de0b6640abee295b683562e2d079d..9764dd0b36680a123c59c03b4c4b26a6e85fe8ce 100644 --- a/src/hotspot/share/gc/shared/cardGeneration.inline.hpp +++ b/test/jdk/java/lang/Class/ArrayType.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -19,38 +19,31 @@ * Please 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_SHARED_CARDGENERATION_INLINE_HPP -#define SHARE_GC_SHARED_CARDGENERATION_INLINE_HPP - -#include "gc/shared/cardGeneration.hpp" - -#include "gc/shared/space.hpp" - -inline size_t CardGeneration::capacity() const { - return space()->capacity(); -} - -inline size_t CardGeneration::used() const { - return space()->used(); -} - -inline size_t CardGeneration::free() const { - return space()->free(); -} - -inline MemRegion CardGeneration::used_region() const { - return space()->used_region(); -} - -inline bool CardGeneration::is_in(const void* p) const { - return space()->is_in(p); -} +/* + * @test + * @bug 8268250 + * @summary Check exceptional behavior of Class.arrayType + */ -inline CompactibleSpace* CardGeneration::first_compaction_space() const { - return space(); +import java.lang.reflect.*; +import java.util.function.*; + +public class ArrayType { + public static void main(String... args) { + expectException(() -> Void.TYPE); + expectException(() -> Array.newInstance(int.class, new int[255]) + .getClass()); + } + + private static void expectException(Supplier<Class<?>> arrayTypeArg) { + try { + Class<?> arrayClazz = arrayTypeArg.get().arrayType(); + throw new RuntimeException("Expected exception not thrown: " + + arrayClazz); + } catch (UnsupportedOperationException uoe) { + ; // Expected + } + } } - -#endif // SHARE_GC_SHARED_CARDGENERATION_INLINE_HPP diff --git a/test/jdk/java/lang/Class/NameTest.java b/test/jdk/java/lang/Class/NameTest.java new file mode 100644 index 0000000000000000000000000000000000000000..b8d6e2125b8237432da6a64f5e5e79845cfa9893 --- /dev/null +++ b/test/jdk/java/lang/Class/NameTest.java @@ -0,0 +1,101 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8281671 + * @summary Checks on various "getFooName" methods of java.lang.Class + */ + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +public class NameTest { + public static void main(String... args) { + testCanonicalName(); + testSimpleName(); + } + + private static void testCanonicalName() { + class LocalClass {} // Local class; no canonical name + Object o = new Object() {}; // Anonymous class; no canonical name + Object[] objectArray = {}; + + Map<Class<?>, String> expectedCanonicalName = new HashMap<>(); + + expectedCanonicalName.put(LocalClass.class, null); + expectedCanonicalName.put(o.getClass(), null); + + // If a component type doesn't have a canonical name, neither + // does an array of that type. + expectedCanonicalName.put(LocalClass.class.arrayType(), null); + expectedCanonicalName.put(o.getClass().arrayType(), null); + + expectedCanonicalName.put(int.class, "int"); + expectedCanonicalName.put(Object.class, "java.lang.Object"); + expectedCanonicalName.put(objectArray.getClass(), "java.lang.Object[]"); + + for (var entry : expectedCanonicalName.entrySet()) { + var key = entry.getKey(); + var expectedName = entry.getValue(); + String canonicalName = key.getCanonicalName(); + if (!Objects.equals(canonicalName, expectedName)) { + System.err.println("Unexpected canonical name '" + + canonicalName + "' found for " + + key + ", expected " + expectedName); + throw new RuntimeException(); + } + } + } + + private static void testSimpleName() { + class ALocalClass {} // Local class + Object o = new Object() {}; // Anonymous class, empty simple name + Object[] objectArray = {}; + + Map<Class<?>, String> expectedSimpleName = new HashMap<>(); + + expectedSimpleName.put(ALocalClass.class, "ALocalClass"); + expectedSimpleName.put(o.getClass(), ""); + + expectedSimpleName.put(ALocalClass.class.arrayType(), "ALocalClass[]"); + expectedSimpleName.put(o.getClass().arrayType(), "[]"); + + expectedSimpleName.put(int.class, "int"); + expectedSimpleName.put(Object.class, "Object"); + expectedSimpleName.put(objectArray.getClass(), "Object[]"); + + for (var entry : expectedSimpleName.entrySet()) { + var key = entry.getKey(); + var expectedName = entry.getValue(); + String simpleName = key.getSimpleName(); + if (!Objects.equals(simpleName, expectedName)) { + System.err.println("Unexpected simple name '" + + simpleName + "' found for " + + key + ", expected " + expectedName); + throw new RuntimeException(); + } + } + } +} diff --git a/test/jdk/java/lang/ClassLoader/BadRegisterAsParallelCapableCaller.java b/test/jdk/java/lang/ClassLoader/BadRegisterAsParallelCapableCaller.java new file mode 100644 index 0000000000000000000000000000000000000000..8b1c8d24d5e50edac0ce7d5851211761dfd5dea4 --- /dev/null +++ b/test/jdk/java/lang/ClassLoader/BadRegisterAsParallelCapableCaller.java @@ -0,0 +1,57 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8281000 + * @summary Test ClassLoader.isRegisteredAsParallelCapable() method with an + * invalid caller (non-JNI cases). This test uses reflection and opens + * the java.base module so it runs separate from behavior tests of + * isRegisteredParallelCapable to avoid side effects. + * @modules java.base/java.lang:open + * @run main/othervm BadRegisterAsParallelCapableCaller + */ + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +public class BadRegisterAsParallelCapableCaller { + + public static void main(String[] args) throws Exception { + + Throwable thrown = null; + final Method m = ClassLoader.class.getDeclaredMethod("registerAsParallelCapable"); + m.setAccessible(true); + try { + m.invoke(null); + } catch (InvocationTargetException ite) { + thrown = ite.getCause(); + } + if (! (thrown instanceof IllegalCallerException)) { + throw new RuntimeException("Didn't get expected IllegalCallerException, got "+ thrown); + } else { + System.out.println("Invalid caller threw IllegalCallerException as expected"); + } + } + +} diff --git a/test/jdk/java/lang/ClassLoader/exeNullCallerClassLoaderTest/NullCallerClassLoaderTest.java b/test/jdk/java/lang/ClassLoader/exeNullCallerClassLoaderTest/NullCallerClassLoaderTest.java new file mode 100644 index 0000000000000000000000000000000000000000..52427f01e6e4858d61adf8f2e6f54dee9e163ba7 --- /dev/null +++ b/test/jdk/java/lang/ClassLoader/exeNullCallerClassLoaderTest/NullCallerClassLoaderTest.java @@ -0,0 +1,71 @@ +/* + * 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. + * + */ + +/** + * @test + * @bug 8281000 + * @summary Test uses custom launcher that starts VM using JNI that verifies + * ClassLoader.registerAsParallelCapable with null caller class + * throws an IllegalCallerException. + * @library /test/lib + * @requires os.family != "aix" + * @run main/native NullCallerClassLoaderTest + */ + +// Test disabled on AIX since we cannot invoke the JVM on the primordial thread. + +import java.io.File; +import java.util.Map; +import jdk.test.lib.Platform; +import jdk.test.lib.process.OutputAnalyzer; + +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; + +public class NullCallerClassLoaderTest { + public static void main(String[] args) throws IOException { + Path launcher = Path.of(System.getProperty("test.nativepath"), "NullCallerClassLoaderTest"); + ProcessBuilder pb = new ProcessBuilder(launcher.toString()); + Map<String, String> env = pb.environment(); + + String libDir = Platform.libDir().toString(); + String vmDir = Platform.jvmLibDir().toString(); + + // set up shared library path + String sharedLibraryPathEnvName = Platform.sharedLibraryPathVariableName(); + env.compute(sharedLibraryPathEnvName, + (k, v) -> (v == null) ? libDir : v + File.pathSeparator + libDir); + env.compute(sharedLibraryPathEnvName, + (k, v) -> (v == null) ? vmDir : v + File.pathSeparator + vmDir); + + System.out.println("Launching: " + launcher + " shared library path: " + + env.get(sharedLibraryPathEnvName)); + new OutputAnalyzer(pb.start()) + .outputTo(System.out) + .errorTo(System.err) + .shouldHaveExitValue(0); + } +} + diff --git a/test/jdk/java/lang/ClassLoader/exeNullCallerClassLoaderTest/exeNullCallerClassLoaderTest.c b/test/jdk/java/lang/ClassLoader/exeNullCallerClassLoaderTest/exeNullCallerClassLoaderTest.c new file mode 100644 index 0000000000000000000000000000000000000000..d488c74bf6c1de0f83d6645843641dd31b34e268 --- /dev/null +++ b/test/jdk/java/lang/ClassLoader/exeNullCallerClassLoaderTest/exeNullCallerClassLoaderTest.c @@ -0,0 +1,76 @@ +/* + * 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 <stdio.h> +#include <stdlib.h> + +#include "jni.h" +#include "assert.h" + +static jclass class_IllegalCallerException; + +int checkAndClearIllegalCallerExceptionThrown(JNIEnv *env) { + jthrowable t = (*env)->ExceptionOccurred(env); + if ((*env)->IsInstanceOf(env, t, class_IllegalCallerException) == JNI_TRUE) { + (*env)->ExceptionClear(env); + return JNI_TRUE; + } + return JNI_FALSE; +} + +int main(int argc, char** args) { + JavaVM *jvm; + JNIEnv *env; + JavaVMInitArgs vm_args; + JavaVMOption options[1]; + jint rc; + + + vm_args.version = JNI_VERSION_1_2; + vm_args.nOptions = 0; + vm_args.options = options; + + if ((rc = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args)) != JNI_OK) { + printf("ERROR: cannot create VM.\n"); + exit(-1); + } + class_IllegalCallerException = (*env)->FindClass(env, "java/lang/IllegalCallerException"); + assert (class_IllegalCallerException != NULL); + + // call ClassLoader.registerAsParallelCapable() + jclass class_ClassLoader = (*env)->FindClass(env, "java/lang/ClassLoader"); + assert(class_ClassLoader != NULL); + jmethodID mid_ClassLoader_registerAsParallelCapable = (*env)->GetStaticMethodID(env, class_ClassLoader, "registerAsParallelCapable", "()Z" ); + assert(mid_ClassLoader_registerAsParallelCapable != NULL); + jboolean b = (*env)->CallStaticBooleanMethod(env, class_ClassLoader, mid_ClassLoader_registerAsParallelCapable ); + if ((rc = checkAndClearIllegalCallerExceptionThrown(env)) != JNI_TRUE) { + printf("ERROR: Didn't get the expected IllegalCallerException.\n"); + exit(-1); + } + + printf("Expected IllegalCallerException was thrown\n"); + + (*jvm)->DestroyJavaVM(jvm); + return 0; +} + diff --git a/test/jdk/java/lang/Math/Atan2Tests.java b/test/jdk/java/lang/Math/Atan2Tests.java index d6ff8605dddc154e6d24b06491cef00927e2cc65..7e5dca17f1b5033b0a5e6c761284622141854b10 100644 --- a/test/jdk/java/lang/Math/Atan2Tests.java +++ b/test/jdk/java/lang/Math/Atan2Tests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 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 @@ -25,7 +25,6 @@ * @test * @bug 4984407 * @summary Tests for {Math, StrictMath}.atan2 - * @author Joseph D. Darcy */ public class Atan2Tests { @@ -33,10 +32,8 @@ public class Atan2Tests { static int testAtan2Case(double input1, double input2, double expected) { int failures = 0; - failures += Tests.test("StrictMath.atan2(double, double)", input1, input2, - StrictMath.atan2(input1, input2), expected); - failures += Tests.test("Math.atan2(double, double)", input1, input2, - Math.atan2(input1, input2), expected); + failures += Tests.test("StrictMath.atan2", input1, input2, StrictMath::atan2, expected); + failures += Tests.test("Math.atan2", input1, input2, Math::atan2, expected); return failures; } @@ -55,7 +52,7 @@ public class Atan2Tests { return failures; } - public static void main(String [] argv) { + public static void main(String... argv) { int failures = 0; failures += testAtan2(); diff --git a/test/jdk/java/lang/Math/CeilAndFloorTests.java b/test/jdk/java/lang/Math/CeilAndFloorTests.java index d4508f839c8d329719c3caabc7a49dc1fc63b758..6b75b2a8dcb663712145361753f57a0d1dff1324 100644 --- a/test/jdk/java/lang/Math/CeilAndFloorTests.java +++ b/test/jdk/java/lang/Math/CeilAndFloorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 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 @@ -30,15 +30,15 @@ public class CeilAndFloorTests { private static int testCeilCase(double input, double expected) { int failures = 0; - failures += Tests.test("Math.ceil", input, Math.ceil(input), expected); - failures += Tests.test("StrictMath.ceil", input, StrictMath.ceil(input), expected); + failures += Tests.test("Math.ceil", input, Math::ceil, expected); + failures += Tests.test("StrictMath.ceil", input, StrictMath::ceil, expected); return failures; } private static int testFloorCase(double input, double expected) { int failures = 0; - failures += Tests.test("Math.floor", input, Math.floor(input), expected); - failures += Tests.test("StrictMath.floor", input, StrictMath.floor(input), expected); + failures += Tests.test("Math.floor", input, Math::floor, expected); + failures += Tests.test("StrictMath.floor", input, StrictMath::floor, expected); return failures; } diff --git a/test/jdk/java/lang/Math/CubeRootTests.java b/test/jdk/java/lang/Math/CubeRootTests.java index 53ef270377fffacb2005939cff18f7d0a7808c62..a6350702d90baa9645e64603a3fcfd8dcfa1598b 100644 --- a/test/jdk/java/lang/Math/CubeRootTests.java +++ b/test/jdk/java/lang/Math/CubeRootTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -28,7 +28,6 @@ * @run main CubeRootTests * @bug 4347132 4939441 8078672 * @summary Tests for {Math, StrictMath}.cbrt (use -Dseed=X to set PRNG seed) - * @author Joseph D. Darcy * @key randomness */ @@ -46,17 +45,10 @@ public class CubeRootTests { static int testCubeRootCase(double input, double expected) { int failures=0; - double minus_input = -input; - double minus_expected = -expected; - - failures+=Tests.test("Math.cbrt(double)", input, - Math.cbrt(input), expected); - failures+=Tests.test("Math.cbrt(double)", minus_input, - Math.cbrt(minus_input), minus_expected); - failures+=Tests.test("StrictMath.cbrt(double)", input, - StrictMath.cbrt(input), expected); - failures+=Tests.test("StrictMath.cbrt(double)", minus_input, - StrictMath.cbrt(minus_input), minus_expected); + failures+=Tests.test("Math.cbrt", input, Math::cbrt, expected); + failures+=Tests.test("Math.cbrt", -input, Math::cbrt, -expected); + failures+=Tests.test("StrictMath.cbrt", input, StrictMath::cbrt, expected); + failures+=Tests.test("StrictMath.cbrt", -input, StrictMath::cbrt, -expected); return failures; } @@ -324,7 +316,7 @@ public class CubeRootTests { return failures; } - public static void main(String argv[]) { + public static void main(String... argv) { int failures = 0; failures += testCubeRoot(); diff --git a/test/jdk/java/lang/Math/ExpCornerCaseTests.java b/test/jdk/java/lang/Math/ExpCornerCaseTests.java index 16168254378ec1cb224e3f262fea7aad6968faaf..e48f31beb9106ac77dddbccde046280c7b542006 100644 --- a/test/jdk/java/lang/Math/ExpCornerCaseTests.java +++ b/test/jdk/java/lang/Math/ExpCornerCaseTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 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 @@ -61,8 +61,8 @@ public class ExpCornerCaseTests { private static int testExp(double input, double expected) { int failures = 0; - failures += Tests.test("StrictMath.exp", input, StrictMath.exp(input), expected); - failures += Tests.test("Math.exp", input, Math.exp(input), expected); + failures += Tests.test("StrictMath.exp", input, StrictMath::exp, expected); + failures += Tests.test("Math.exp", input, Math::exp, expected); return failures; } } diff --git a/test/jdk/java/lang/Math/Expm1Tests.java b/test/jdk/java/lang/Math/Expm1Tests.java index 5bf267d15fd23f0985d156283db078c9030b8afc..204fe44ef15813529e5f01056fae59c7fb61d695 100644 --- a/test/jdk/java/lang/Math/Expm1Tests.java +++ b/test/jdk/java/lang/Math/Expm1Tests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -25,7 +25,6 @@ * @test * @bug 4851638 4900189 4939441 * @summary Tests for {Math, StrictMath}.expm1 - * @author Joseph D. Darcy */ /* @@ -214,7 +213,7 @@ public class Expm1Tests { return failures; } - public static void main(String argv[]) { + public static void main(String... argv) { int failures = 0; failures += testExpm1(); diff --git a/test/jdk/java/lang/Math/FusedMultiplyAddTests.java b/test/jdk/java/lang/Math/FusedMultiplyAddTests.java index 03e164c2198842a85ab4b8c531b31ace32d3d367..61a3bfb0de171ebaea1a06d2e09465945053a700 100644 --- a/test/jdk/java/lang/Math/FusedMultiplyAddTests.java +++ b/test/jdk/java/lang/Math/FusedMultiplyAddTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -365,16 +365,12 @@ public class FusedMultiplyAddTests { private static int testFusedMacCase(double input1, double input2, double input3, double expected) { int failures = 0; - failures += Tests.test("Math.fma(double)", input1, input2, input3, - Math.fma(input1, input2, input3), expected); - failures += Tests.test("StrictMath.fma(double)", input1, input2, input3, - StrictMath.fma(input1, input2, input3), expected); + failures += Tests.test("Math.fma", input1, input2, input3, Math::fma, expected); + failures += Tests.test("StrictMath.fma", input1, input2, input3, StrictMath::fma, expected); // Permute first two inputs - failures += Tests.test("Math.fma(double)", input2, input1, input3, - Math.fma(input2, input1, input3), expected); - failures += Tests.test("StrictMath.fma(double)", input2, input1, input3, - StrictMath.fma(input2, input1, input3), expected); + failures += Tests.test("Math.fma", input2, input1, input3, Math::fma, expected); + failures += Tests.test("StrictMath.fma", input2, input1, input3, StrictMath::fma, expected); return failures; } diff --git a/test/jdk/java/lang/Math/HyperbolicTests.java b/test/jdk/java/lang/Math/HyperbolicTests.java index 0df493698fe1c4f6069000068e4fa741ac7cdf34..8309606f63d745c7a2678bfc6b7e0249ae842e08 100644 --- a/test/jdk/java/lang/Math/HyperbolicTests.java +++ b/test/jdk/java/lang/Math/HyperbolicTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -25,7 +25,6 @@ * @test * @bug 4851625 4900189 4939441 * @summary Tests for {Math, StrictMath}.{sinh, cosh, tanh} - * @author Joseph D. Darcy */ public class HyperbolicTests { @@ -33,6 +32,20 @@ public class HyperbolicTests { static final double NaNd = Double.NaN; + public static void main(String... argv) { + int failures = 0; + + failures += testSinh(); + failures += testCosh(); + failures += testTanh(); + + if (failures > 0) { + System.err.println("Testing the hyperbolic functions incurred " + + failures + " failures."); + throw new RuntimeException(); + } + } + /** * Test accuracy of {Math, StrictMath}.sinh. The specified * accuracy is 2.5 ulps. @@ -355,19 +368,11 @@ public class HyperbolicTests { double expected, double tolerance) { int failures = 0; - failures += Tests.testTolerance("Math.sinh(double)", - input, Math.sinh(input), - expected, tolerance); - failures += Tests.testTolerance("Math.sinh(double)", - -input, Math.sinh(-input), - -expected, tolerance); + failures += Tests.testTolerance("Math.sinh", input, Math::sinh, expected, tolerance); + failures += Tests.testTolerance("Math.sinh", -input, Math::sinh, -expected, tolerance); - failures += Tests.testTolerance("StrictMath.sinh(double)", - input, StrictMath.sinh(input), - expected, tolerance); - failures += Tests.testTolerance("StrictMath.sinh(double)", - -input, StrictMath.sinh(-input), - -expected, tolerance); + failures += Tests.testTolerance("StrictMath.sinh", input, StrictMath::sinh, expected, tolerance); + failures += Tests.testTolerance("StrictMath.sinh", -input, StrictMath::sinh, -expected, tolerance); return failures; } @@ -375,23 +380,14 @@ public class HyperbolicTests { double expected, double ulps) { int failures = 0; - failures += Tests.testUlpDiff("Math.sinh(double)", - input, Math.sinh(input), - expected, ulps); - failures += Tests.testUlpDiff("Math.sinh(double)", - -input, Math.sinh(-input), - -expected, ulps); - - failures += Tests.testUlpDiff("StrictMath.sinh(double)", - input, StrictMath.sinh(input), - expected, ulps); - failures += Tests.testUlpDiff("StrictMath.sinh(double)", - -input, StrictMath.sinh(-input), - -expected, ulps); + failures += Tests.testUlpDiff("Math.sinh", input, Math::sinh, expected, ulps); + failures += Tests.testUlpDiff("Math.sinh", -input, Math::sinh, -expected, ulps); + + failures += Tests.testUlpDiff("StrictMath.sinh", input, StrictMath::sinh, expected, ulps); + failures += Tests.testUlpDiff("StrictMath.sinh", -input, StrictMath::sinh, -expected, ulps); return failures; } - /** * Test accuracy of {Math, StrictMath}.cosh. The specified * accuracy is 2.5 ulps. @@ -594,7 +590,6 @@ public class HyperbolicTests { 3.0); } - double [][] specialTestCases = { {0.0, 1.0}, {NaNd, NaNd}, @@ -733,23 +728,14 @@ public class HyperbolicTests { double expected, double ulps) { int failures = 0; - failures += Tests.testUlpDiff("Math.cosh(double)", - input, Math.cosh(input), - expected, ulps); - failures += Tests.testUlpDiff("Math.cosh(double)", - -input, Math.cosh(-input), - expected, ulps); - - failures += Tests.testUlpDiff("StrictMath.cosh(double)", - input, StrictMath.cosh(input), - expected, ulps); - failures += Tests.testUlpDiff("StrictMath.cosh(double)", - -input, StrictMath.cosh(-input), - expected, ulps); + failures += Tests.testUlpDiff("Math.cosh", input, Math::cosh, expected, ulps); + failures += Tests.testUlpDiff("Math.cosh", -input, Math::cosh, expected, ulps); + + failures += Tests.testUlpDiff("StrictMath.cosh", input, StrictMath::cosh, expected, ulps); + failures += Tests.testUlpDiff("StrictMath.cosh", -input, StrictMath::cosh, expected, ulps); return failures; } - /** * Test accuracy of {Math, StrictMath}.tanh. The specified * accuracy is 2.5 ulps. @@ -952,7 +938,6 @@ public class HyperbolicTests { 3.0); } - double [][] specialTestCases = { {0.0, 0.0}, {NaNd, NaNd}, @@ -1007,19 +992,11 @@ public class HyperbolicTests { double expected, double tolerance) { int failures = 0; - failures += Tests.testTolerance("Math.tanh(double", - input, Math.tanh(input), - expected, tolerance); - failures += Tests.testTolerance("Math.tanh(double", - -input, Math.tanh(-input), - -expected, tolerance); + failures += Tests.testTolerance("Math.tanh", input, Math::tanh, expected, tolerance); + failures += Tests.testTolerance("Math.tanh", -input, Math::tanh, -expected, tolerance); - failures += Tests.testTolerance("StrictMath.tanh(double", - input, StrictMath.tanh(input), - expected, tolerance); - failures += Tests.testTolerance("StrictMath.tanh(double", - -input, StrictMath.tanh(-input), - -expected, tolerance); + failures += Tests.testTolerance("StrictMath.tanh", input, StrictMath::tanh, expected, tolerance); + failures += Tests.testTolerance("StrictMath.tanh", -input, StrictMath::tanh, -expected, tolerance); return failures; } @@ -1028,35 +1005,11 @@ public class HyperbolicTests { double ulps) { int failures = 0; - failures += Tests.testUlpDiffWithAbsBound("Math.tanh(double)", - input, Math.tanh(input), - expected, ulps, 1.0); - failures += Tests.testUlpDiffWithAbsBound("Math.tanh(double)", - -input, Math.tanh(-input), - -expected, ulps, 1.0); - - failures += Tests.testUlpDiffWithAbsBound("StrictMath.tanh(double)", - input, StrictMath.tanh(input), - expected, ulps, 1.0); - failures += Tests.testUlpDiffWithAbsBound("StrictMath.tanh(double)", - -input, StrictMath.tanh(-input), - -expected, ulps, 1.0); - return failures; - } - - - public static void main(String argv[]) { - int failures = 0; + failures += Tests.testUlpDiffWithAbsBound("Math.tanh", input, Math::tanh, expected, ulps, 1.0); + failures += Tests.testUlpDiffWithAbsBound("Math.tanh", -input, Math::tanh, -expected, ulps, 1.0); - failures += testSinh(); - failures += testCosh(); - failures += testTanh(); - - if (failures > 0) { - System.err.println("Testing the hyperbolic functions incurred " - + failures + " failures."); - throw new RuntimeException(); - } + failures += Tests.testUlpDiffWithAbsBound("StrictMath.tanh", input, StrictMath::tanh, expected, ulps, 1.0); + failures += Tests.testUlpDiffWithAbsBound("StrictMath.tanh", -input, StrictMath::tanh, -expected, ulps, 1.0); + return failures; } - } diff --git a/test/jdk/java/lang/Math/HypotTests.java b/test/jdk/java/lang/Math/HypotTests.java index d7e562ca5fd27cde31f2d4409534306fe77786cd..e09799e34a4f3e3c1c00991bbd4bbc7c9c9b5f8d 100644 --- a/test/jdk/java/lang/Math/HypotTests.java +++ b/test/jdk/java/lang/Math/HypotTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -28,7 +28,6 @@ * @run main HypotTests * @bug 4851638 4939441 8078672 8240632 * @summary Tests for {Math, StrictMath}.hypot (use -Dseed=X to set PRNG seed) - * @author Joseph D. Darcy * @key randomness */ @@ -51,7 +50,6 @@ public class HypotTests { long N = n; long result[] = new long[3]; - result[0] = Math.abs(M*M - N*N); result[1] = Math.abs(2*M*N); result[2] = Math.abs(M*M + N*N); @@ -188,13 +186,11 @@ public class HypotTests { pcNeighborsStrictHypot[j+1] ); } - } } } - return failures; } @@ -221,26 +217,22 @@ public class HypotTests { // each input negated singly, and both inputs negated. Also // test inputs in reversed order. - for(int i = -1; i <= 1; i+=2) { - for(int j = -1; j <= 1; j+=2) { + for(int i = -1; i <= 1; i += 2) { + for(int j = -1; j <= 1; j += 2) { double x = i * input1; double y = j * input2; - failures += Tests.testUlpDiff("Math.hypot", x, y, - Math.hypot(x, y), expected, ulps); - failures += Tests.testUlpDiff("Math.hypot", y, x, - Math.hypot(y, x ), expected, ulps); - - failures += Tests.testUlpDiff("StrictMath.hypot", x, y, - StrictMath.hypot(x, y), expected, ulps); - failures += Tests.testUlpDiff("StrictMath.hypot", y, x, - StrictMath.hypot(y, x), expected, ulps); + failures += Tests.testUlpDiff("Math.hypot", x, y, Math::hypot, expected, ulps); + failures += Tests.testUlpDiff("Math.hypot", y, x, Math::hypot, expected, ulps); + + failures += Tests.testUlpDiff("StrictMath.hypot", x, y, StrictMath::hypot, expected, ulps); + failures += Tests.testUlpDiff("StrictMath.hypot", y, x, StrictMath::hypot, expected, ulps); } } return failures; } - public static void main(String argv[]) { + public static void main(String... argv) { int failures = 0; failures += testHypot(); @@ -252,5 +244,4 @@ public class HypotTests { throw new RuntimeException(); } } - } diff --git a/test/jdk/java/lang/Math/Ieee754SpecialCaseTests.java b/test/jdk/java/lang/Math/Ieee754SpecialCaseTests.java index d8192f2fee36d088bddd15e09b01eb33be562555..f53f231464760b2ce93f146915e69b0e77f8c91b 100644 --- a/test/jdk/java/lang/Math/Ieee754SpecialCaseTests.java +++ b/test/jdk/java/lang/Math/Ieee754SpecialCaseTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 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 @@ -62,8 +62,8 @@ public class Ieee754SpecialCaseTests { private static int testCosCase(double input, double expected) { int failures = 0; - failures += Tests.test("Math.cos", input, Math.cos(input), expected); - failures += Tests.test("StrictMath.cos", input, StrictMath.cos(input), expected); + failures += Tests.test("Math.cos", input, Math::cos, expected); + failures += Tests.test("StrictMath.cos", input, StrictMath::cos, expected); return failures; } @@ -82,8 +82,8 @@ public class Ieee754SpecialCaseTests { private static int testAcosCase(double input, double expected) { int failures = 0; - failures += Tests.test("Math.acos", input, Math.acos(input), expected); - failures += Tests.test("StrictMath.acos", input, StrictMath.acos(input), expected); + failures += Tests.test("Math.acos", input, Math::acos, expected); + failures += Tests.test("StrictMath.acos", input, StrictMath::acos, expected); return failures; } @@ -103,8 +103,8 @@ public class Ieee754SpecialCaseTests { private static int testAtanCase(double input, double expected) { int failures = 0; - failures += Tests.test("Math.atan", input, Math.atan(input), expected); - failures += Tests.test("StrictMath.atan", input, StrictMath.atan(input), expected); + failures += Tests.test("Math.atan", input, Math::atan, expected); + failures += Tests.test("StrictMath.atan", input, StrictMath::atan, expected); return failures; } @@ -123,8 +123,8 @@ public class Ieee754SpecialCaseTests { private static int testLogCase(double input, double expected) { int failures = 0; - failures += Tests.test("Math.log", input, Math.log(input), expected); - failures += Tests.test("StrictMath.log", input, StrictMath.log(input), expected); + failures += Tests.test("Math.log", input, Math::log, expected); + failures += Tests.test("StrictMath.log", input, StrictMath::log, expected); return failures; } } diff --git a/test/jdk/java/lang/Math/IeeeRecommendedTests.java b/test/jdk/java/lang/Math/IeeeRecommendedTests.java index 830b16d765a45e48588a1d32c0512d514a13d27a..8570508ff446f6e0204f6aa11fdfdcd559f72035 100644 --- a/test/jdk/java/lang/Math/IeeeRecommendedTests.java +++ b/test/jdk/java/lang/Math/IeeeRecommendedTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -28,7 +28,6 @@ * @run main IeeeRecommendedTests * @bug 4860891 4826732 4780454 4939441 4826652 8078672 * @summary Tests for IEEE 754[R] recommended functions and similar methods (use -Dseed=X to set PRNG seed) - * @author Joseph D. Darcy * @key randomness */ @@ -364,14 +363,14 @@ public class IeeeRecommendedTests { double minus_expected = -expected; failures+=Tests.test("Math.nextAfter(double,double)", start, direction, - Math.nextAfter(start, direction), expected); + Math::nextAfter, expected); failures+=Tests.test("Math.nextAfter(double,double)", minus_start, minus_direction, - Math.nextAfter(minus_start, minus_direction), minus_expected); + Math::nextAfter, minus_expected); failures+=Tests.test("StrictMath.nextAfter(double,double)", start, direction, - StrictMath.nextAfter(start, direction), expected); + StrictMath::nextAfter, expected); failures+=Tests.test("StrictMath.nextAfter(double,double)", minus_start, minus_direction, - StrictMath.nextAfter(minus_start, minus_direction), minus_expected); + StrictMath::nextAfter, minus_expected); return failures; } @@ -586,10 +585,10 @@ public class IeeeRecommendedTests { for(int i = 0; i < testCases.length; i++) { failures+=Tests.test("Math.nextUp(double)", - testCases[i][0], Math.nextUp(testCases[i][0]), testCases[i][1]); + testCases[i][0], Math::nextUp, testCases[i][1]); failures+=Tests.test("StrictMath.nextUp(double)", - testCases[i][0], StrictMath.nextUp(testCases[i][0]), testCases[i][1]); + testCases[i][0], StrictMath::nextUp, testCases[i][1]); } return failures; @@ -665,10 +664,10 @@ public class IeeeRecommendedTests { for(int i = 0; i < testCases.length; i++) { failures+=Tests.test("Math.nextDown(double)", - testCases[i][0], Math.nextDown(testCases[i][0]), testCases[i][1]); + testCases[i][0], Math::nextDown, testCases[i][1]); failures+=Tests.test("StrictMath.nextDown(double)", - testCases[i][0], StrictMath.nextDown(testCases[i][0]), testCases[i][1]); + testCases[i][0], StrictMath::nextDown, testCases[i][1]); } return failures; @@ -906,12 +905,12 @@ public class IeeeRecommendedTests { // copySign(magnitude, sign) failures+=Tests.test("MathcopySign(double,double)", testCases[i][m],testCases[j][n], - Math.copySign(testCases[i][m], testCases[j][n]), + Math::copySign, (j==0?1.0f:-1.0f)*Math.abs(testCases[i][m]) ); failures+=Tests.test("StrictMath.copySign(double,double)", testCases[i][m],testCases[j][n], - StrictMath.copySign(testCases[i][m], testCases[j][n]), + StrictMath::copySign, (j==0?1.0f:-1.0f)*Math.abs(testCases[i][m]) ); } } @@ -932,7 +931,7 @@ public class IeeeRecommendedTests { failures+=Tests.test("StrictMath.copySign(double,double)", testCases[i][m], NaNs[j], - StrictMath.copySign(testCases[i][m], NaNs[j]), + StrictMath::copySign, Math.abs(testCases[i][m]) ); } } @@ -1384,13 +1383,13 @@ public class IeeeRecommendedTests { int failures=0; failures+=Tests.test("Math.ulp(double)", d, - Math.ulp(d), expected); + Math::ulp, expected); failures+=Tests.test("Math.ulp(double)", minus_d, - Math.ulp(minus_d), expected); + Math::ulp, expected); failures+=Tests.test("StrictMath.ulp(double)", d, - StrictMath.ulp(d), expected); + StrictMath::ulp, expected); failures+=Tests.test("StrictMath.ulp(double)", minus_d, - StrictMath.ulp(minus_d), expected); + StrictMath::ulp, expected); return failures; } @@ -1664,16 +1663,16 @@ public class IeeeRecommendedTests { for(int i = 0; i < testCases.length; i++) { failures+=Tests.test("Math.signum(double)", - testCases[i][0], Math.signum(testCases[i][0]), testCases[i][1]); + testCases[i][0], Math::signum, testCases[i][1]); failures+=Tests.test("StrictMath.signum(double)", - testCases[i][0], StrictMath.signum(testCases[i][0]), testCases[i][1]); + testCases[i][0], StrictMath::signum, testCases[i][1]); } return failures; } - public static void main(String argv[]) { + public static void main(String... argv) { int failures = 0; failures += testFloatGetExponent(); diff --git a/test/jdk/java/lang/Math/Log10Tests.java b/test/jdk/java/lang/Math/Log10Tests.java index 7bc75644f2b155c953b761af836e9e31272d8261..dbdd7c141794f98dc8ba5a4e8ca7107fab32f846 100644 --- a/test/jdk/java/lang/Math/Log10Tests.java +++ b/test/jdk/java/lang/Math/Log10Tests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -25,7 +25,6 @@ * @test * @bug 4074599 4939441 * @summary Tests for {Math, StrictMath}.log10 - * @author Joseph D. Darcy */ public class Log10Tests { @@ -41,11 +40,8 @@ public class Log10Tests { static int testLog10Case(double input, double expected) { int failures=0; - failures+=Tests.test("Math.log10(double)", input, - Math.log10(input), expected); - - failures+=Tests.test("StrictMath.log10(double)", input, - StrictMath.log10(input), expected); + failures+=Tests.test("Math.log10", input, Math::log10, expected); + failures+=Tests.test("StrictMath.log10", input, StrictMath::log10, expected); return failures; } @@ -121,8 +117,6 @@ public class Log10Tests { "log(input)/log(10): log10(input) = " + result + "\tlog(input)/log(10) = " + expected); } - - } } } @@ -205,7 +199,7 @@ public class Log10Tests { return failures; } - public static void main(String argv[]) { + public static void main(String... argv) { int failures = 0; failures += testLog10(); @@ -216,5 +210,4 @@ public class Log10Tests { throw new RuntimeException(); } } - } diff --git a/test/jdk/java/lang/Math/Log1pTests.java b/test/jdk/java/lang/Math/Log1pTests.java index 021a651ed1870727609d5f38fb34b40e7665210f..2fa7ddec4429d353b5cfac8b4cf47879dfa35d82 100644 --- a/test/jdk/java/lang/Math/Log1pTests.java +++ b/test/jdk/java/lang/Math/Log1pTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -28,7 +28,6 @@ * @run main Log1pTests * @bug 4851638 4939441 8078672 * @summary Tests for {Math, StrictMath}.log1p (use -Dseed=X to set PRNG seed) - * @author Joseph D. Darcy * @key randomness */ @@ -167,9 +166,7 @@ public class Log1pTests { pcNeighborsStrictLog1p[j+1] ); } - } - } } @@ -185,16 +182,12 @@ public class Log1pTests { double expected, double ulps) { int failures = 0; - failures += Tests.testUlpDiff("Math.lop1p(double", - input, Math.log1p(input), - expected, ulps); - failures += Tests.testUlpDiff("StrictMath.log1p(double", - input, StrictMath.log1p(input), - expected, ulps); + failures += Tests.testUlpDiff("Math.lop1p", input, Math::log1p, expected, ulps); + failures += Tests.testUlpDiff("StrictMath.log1p", input, StrictMath::log1p, expected, ulps); return failures; } - public static void main(String argv[]) { + public static void main(String... argv) { int failures = 0; failures += testLog1p(); diff --git a/test/jdk/java/lang/Math/PowTests.java b/test/jdk/java/lang/Math/PowTests.java index 88221c5415a4eb76ed321dd71d92c1173b2770c4..8f8ea098bdaef20ace6fd930b28cb770dbbab8ab 100644 --- a/test/jdk/java/lang/Math/PowTests.java +++ b/test/jdk/java/lang/Math/PowTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 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 @@ -25,7 +25,6 @@ * @test * @bug 4984407 5033578 8134795 * @summary Tests for {Math, StrictMath}.pow - * @author Joseph D. Darcy */ public class PowTests { @@ -35,35 +34,29 @@ public class PowTests { static int testPowCase(double input1, double input2, double expected) { int failures = 0; - failures += Tests.test("StrictMath.pow(double, double)", input1, input2, - StrictMath.pow(input1, input2), expected); - failures += Tests.test("Math.pow(double, double)", input1, input2, - Math.pow(input1, input2), expected); + failures += Tests.test("StrictMath.pow", input1, input2, StrictMath::pow, expected); + failures += Tests.test("Math.pow", input1, input2, Math::pow, expected); return failures; } - static int testStrictPowCase(double input1, double input2, double expected) { int failures = 0; - failures += Tests.test("StrictMath.pow(double, double)", input1, input2, - StrictMath.pow(input1, input2), expected); + failures += Tests.test("StrictMath.pow", input1, input2, + StrictMath::pow, expected); return failures; } static int testNonstrictPowCase(double input1, double input2, double expected) { int failures = 0; - failures += Tests.test("Math.pow(double, double)", input1, input2, - Math.pow(input1, input2), expected); + failures += Tests.test("Math.pow", input1, input2, + Math::pow, expected); return failures; } static int testStrictVsNonstrictPowCase(double input1, double input2) { - double smResult = StrictMath.pow(input1, input2); - double mResult = Math.pow(input1, input2); return Tests.testUlpDiff( "StrictMath.pow(double, double) vs Math.pow(double, double)", - input1, input2, mResult, smResult, 2.0 - ); + input1, input2, Math::pow, StrictMath.pow(input1, input2), 2.0); } /* @@ -313,7 +306,7 @@ public class PowTests { } } - public static void main(String [] argv) { + public static void main(String... argv) { int failures = 0; failures += testPow(); diff --git a/test/jdk/java/lang/Math/Rint.java b/test/jdk/java/lang/Math/Rint.java index 53e4d26b13134887e8cf924649af15c1db1230e0..a9c6952b90b1227906f2e3c78fa03da20e611447 100644 --- a/test/jdk/java/lang/Math/Rint.java +++ b/test/jdk/java/lang/Math/Rint.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -32,17 +32,14 @@ public class Rint { static int testRintCase(double input, double expected) { int failures = 0; double result; - failures += Tests.test("Math.rint", input, Math.rint(input), expected); - failures += Tests.test("Math.rint", -input, Math.rint(-input), -expected); - failures += Tests.test("StrictMath.rint", - input, StrictMath.rint(input), expected); - failures += Tests.test("StrictMath.rint", -input, - StrictMath.rint(-input), -expected); + failures += Tests.test("Math.rint", input, Math::rint, expected); + failures += Tests.test("Math.rint", -input, Math::rint, -expected); + failures += Tests.test("StrictMath.rint", input, StrictMath::rint, expected); + failures += Tests.test("StrictMath.rint", -input, StrictMath::rint, -expected); return failures; } - - public static void main(String args[]) { + public static void main(String... args) { int failures = 0; double twoToThe52 = Math.scalb(1.0, 52); // 2^52 @@ -97,7 +94,6 @@ public class Rint { }; - for(int i = 0; i < testCases.length; i++) { failures += testRintCase(testCases[i][0], testCases[i][1]); } diff --git a/test/jdk/java/lang/Math/RoundTests.java b/test/jdk/java/lang/Math/RoundTests.java index cae190f9770218e9f924f5fd8aabc447245527d8..0a51b426386b8ded5d75a43dfaefa84759430a33 100644 --- a/test/jdk/java/lang/Math/RoundTests.java +++ b/test/jdk/java/lang/Math/RoundTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 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 @@ -64,8 +64,8 @@ public class RoundTests { private static int testNearHalfCases(double input, double expected) { int failures = 0; - failures += Tests.test("Math.round", input, Math.round(input), expected); - failures += Tests.test("StrictMath.round", input, StrictMath.round(input), expected); + failures += Tests.test("Math.round", input, Math::round, expected); + failures += Tests.test("StrictMath.round", input, StrictMath::round, expected); return failures; } @@ -145,20 +145,14 @@ public class RoundTests { failures += Tests.test("Math.round", -Float.MIN_VALUE, Math.round(-Float.MIN_VALUE), 0.0F); - failures += Tests.test("Math.round", Double.NaN, Math.round(Double.NaN), 0.0); - failures += Tests.test("Math.round", Double.POSITIVE_INFINITY, - Math.round(Double.POSITIVE_INFINITY), Long.MAX_VALUE); - failures += Tests.test("Math.round", Double.NEGATIVE_INFINITY, - Math.round(Double.NEGATIVE_INFINITY), Long.MIN_VALUE); - failures += Tests.test("Math.round", -(double)Long.MIN_VALUE, - Math.round(-(double)Long.MIN_VALUE), Long.MAX_VALUE); - failures += Tests.test("Math.round", (double) Long.MIN_VALUE, - Math.round((double) Long.MIN_VALUE), Long.MIN_VALUE); - failures += Tests.test("Math.round", 0, Math.round(0), 0.0); - failures += Tests.test("Math.round", Double.MIN_VALUE, - Math.round(Double.MIN_VALUE), 0.0); - failures += Tests.test("Math.round", -Double.MIN_VALUE, - Math.round(-Double.MIN_VALUE), 0.0); + failures += Tests.test("Math.round", Double.NaN, Math::round, 0.0); + failures += Tests.test("Math.round", Double.POSITIVE_INFINITY, Math::round, Long.MAX_VALUE); + failures += Tests.test("Math.round", Double.NEGATIVE_INFINITY, Math::round, Long.MIN_VALUE); + failures += Tests.test("Math.round", -(double)Long.MIN_VALUE, Math::round, Long.MAX_VALUE); + failures += Tests.test("Math.round", (double) Long.MIN_VALUE, Math::round, Long.MIN_VALUE); + failures += Tests.test("Math.round", 0, Math::round, 0.0); + failures += Tests.test("Math.round", Double.MIN_VALUE, Math::round, 0.0); + failures += Tests.test("Math.round", -Double.MIN_VALUE, Math::round, 0.0); return failures; } diff --git a/test/jdk/java/lang/Math/SinCosCornerCasesTests.java b/test/jdk/java/lang/Math/SinCosCornerCasesTests.java index e144857443f9916b9fe10ea3cb19645113e58a69..225cdaebf0ef08a1be94cc1bbfba78794f097d26 100644 --- a/test/jdk/java/lang/Math/SinCosCornerCasesTests.java +++ b/test/jdk/java/lang/Math/SinCosCornerCasesTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 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 @@ -28,7 +28,6 @@ * @build Tests * @build SinCosCornerCasesTests * @run main SinCosCornerCasesTests - * @author Vivek Deshpande */ public class SinCosCornerCasesTests { @@ -1502,7 +1501,7 @@ public class SinCosCornerCasesTests { private static int testSinCase(double input, double bound1, double bound2) { int failures = 0; - failures += Tests.testBounds("Math.sin", input, Math.sin(input), bound1, bound2); + failures += Tests.testBounds("Math.sin", input, Math::sin, bound1, bound2); return failures; } @@ -2921,7 +2920,7 @@ public class SinCosCornerCasesTests { private static int testCosCase(double input, double bound1, double bound2) { int failures = 0; - failures += Tests.testBounds("Math.cos", input, Math.cos(input), bound1, bound2); + failures += Tests.testBounds("Math.cos", input, Math::cos, bound1, bound2); return failures; } } diff --git a/test/jdk/java/lang/Math/TanTests.java b/test/jdk/java/lang/Math/TanTests.java index f4ad1872238f3ce3f179d7ce15c2d92a937911ee..04ed7d47ed1ca0f055973b9a3f0dc488d5be06a3 100644 --- a/test/jdk/java/lang/Math/TanTests.java +++ b/test/jdk/java/lang/Math/TanTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 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 @@ -25,7 +25,6 @@ * @test * @bug 5033578 * @summary Tests for {Math, StrictMath}.tan - * @author Joseph D. Darcy */ public class TanTests { @@ -33,10 +32,8 @@ public class TanTests { static int testTanCase(double input, double expected, double ulps) { int failures = 0; - failures += Tests.testUlpDiff("StrictMath.tan(double, double)", input, - StrictMath.tan(input), expected, ulps); - failures += Tests.testUlpDiff("Math.tan(double, double)", input, - Math.tan(input), expected, ulps); + failures += Tests.testUlpDiff("StrictMath.tan", input, StrictMath::tan, expected, ulps); + failures += Tests.testUlpDiff("Math.tan", input, Math::tan, expected, ulps); return failures; } @@ -173,7 +170,7 @@ public class TanTests { return failures; } - public static void main(String [] argv) { + public static void main(String... argv) { int failures = 0; failures += testTan(); diff --git a/test/jdk/java/lang/Math/Tests.java b/test/jdk/java/lang/Math/Tests.java index 98821142fc971f085b60ca0a8edca6d9a0f411f7..f1de6319a9ed3438a64ac2969ab37a3b483a7c78 100644 --- a/test/jdk/java/lang/Math/Tests.java +++ b/test/jdk/java/lang/Math/Tests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -21,6 +21,10 @@ * questions. */ +import java.util.function.DoubleBinaryOperator; +import java.util.function.DoubleUnaryOperator; +import java.util.function.DoubleToIntFunction; + /* * Shared static test methods for numerical tests. Sharing these * helper test methods avoids repeated functions in the various test @@ -235,9 +239,9 @@ public class Tests { "\texpected " + expected + "\n" + "\tgot " + result + ")."); return 1; - } - else + } else { return 0; + } } public static int test(String testName, double input, @@ -248,9 +252,9 @@ public class Tests { "\texpected " + expected + "\n" + "\tgot " + result + ")."); return 1; - } - else + } else { return 0; + } } public static int test(String testName, float input1, float input2, @@ -291,6 +295,13 @@ public class Tests { return 0; } + public static int test(String testName, + double input, + DoubleToIntFunction func, + int expected) { + return test(testName, input, func.applyAsInt(input), expected); + } + public static int test(String testName, double input, int result, int expected) { if (expected != result) { @@ -299,9 +310,9 @@ public class Tests { "\texpected " + expected + "\n" + "\tgot " + result + ")."); return 1; - } - else + } else { return 0; + } } public static int test(String testName, float input, @@ -312,11 +323,17 @@ public class Tests { "\texpected " + expected + "\t(" + toHexString(expected) + ")\n" + "\tgot " + result + "\t(" + toHexString(result) + ")."); return 1; - } - else + } else { return 0; + } } + public static int test(String testName, + double input, + DoubleUnaryOperator func, + double expected) { + return test(testName, input, func.applyAsDouble(input), expected); + } public static int test(String testName, double input, double result, double expected) { @@ -326,9 +343,9 @@ public class Tests { "\texpected " + expected + "\t(" + toHexString(expected) + ")\n" + "\tgot " + result + "\t(" + toHexString(result) + ")."); return 1; - } - else + } else { return 0; + } } public static int test(String testName, @@ -341,9 +358,16 @@ public class Tests { "\texpected " + expected + "\t(" + toHexString(expected) + ")\n" + "\tgot " + result + "\t(" + toHexString(result) + ")."); return 1; - } - else + } else { return 0; + } + } + + public static int test(String testName, + double input1, double input2, + DoubleBinaryOperator func, + double expected) { + return test(testName, input1, input2, func.applyAsDouble(input1, input2), expected); } public static int test(String testName, @@ -356,9 +380,9 @@ public class Tests { "\texpected " + expected + "\t(" + toHexString(expected) + ")\n" + "\tgot " + result + "\t(" + toHexString(result) + ")."); return 1; - } - else + } else { return 0; + } } public static int test(String testName, @@ -371,9 +395,9 @@ public class Tests { "\texpected " + expected + "\t(" + toHexString(expected) + ")\n" + "\tgot " + result + "\t(" + toHexString(result) + ")."); return 1; - } - else + } else { return 0; + } } public static int test(String testName, @@ -386,9 +410,9 @@ public class Tests { "\texpected " + expected + "\t(" + toHexString(expected) + ")\n" + "\tgot " + result + "\t(" + toHexString(result) + ")."); return 1; - } - else + } else { return 0; + } } public static int test(String testName, @@ -402,9 +426,21 @@ public class Tests { "\texpected " + expected + "\t(" + toHexString(expected) + ")\n" + "\tgot " + result + "\t(" + toHexString(result) + ")."); return 1; - } - else + } else { return 0; + } + } + + @FunctionalInterface + public interface DoubleTernaryOperator { + double applyAsDouble(double input1, double input2, double input3); + } + + public static int test(String testName, + double input1, double input2, double input3, + DoubleTernaryOperator func, double expected) { + return test(testName, input1, input2, input3, func.applyAsDouble(input1, input2, input3), expected); + } public static int test(String testName, @@ -418,9 +454,9 @@ public class Tests { "\texpected " + expected + "\t(" + toHexString(expected) + ")\n" + "\tgot " + result + "\t(" + toHexString(result) + ")."); return 1; - } - else + } else { return 0; + } } static int testUlpCore(double result, double expected, double ulps) { @@ -442,14 +478,19 @@ public class Tests { // fail if greater than or unordered !(Math.abs( difference/Math.ulp(expected) ) <= Math.abs(ulps)) ) { return 1; - } - else + } else { return 0; + } } } } // One input argument. + public static int testUlpDiff(String testName, double input, + DoubleUnaryOperator func, double expected, double ulps) { + return testUlpDiff(testName, input, func.applyAsDouble(input), expected, ulps); + } + public static int testUlpDiff(String testName, double input, double result, double expected, double ulps) { int code = testUlpCore(result, expected, ulps); @@ -464,6 +505,11 @@ public class Tests { } // Two input arguments. + public static int testUlpDiff(String testName, double input1, double input2, + DoubleBinaryOperator func, double expected, double ulps) { + return testUlpDiff(testName, input1, input2, func.applyAsDouble(input1, input2), expected, ulps); + } + public static int testUlpDiff(String testName, double input1, double input2, double result, double expected, double ulps) { int code = testUlpCore(result, expected, ulps); @@ -481,6 +527,14 @@ public class Tests { // For a successful test, the result must be within the ulp bound of // expected AND the result must have absolute value less than or // equal to absBound. + public static int testUlpDiffWithAbsBound(String testName, double input, + DoubleUnaryOperator func, double expected, + double ulps, double absBound) { + return testUlpDiffWithAbsBound(testName, input, + func.applyAsDouble(input), expected, + ulps, absBound); + } + public static int testUlpDiffWithAbsBound(String testName, double input, double result, double expected, double ulps, double absBound) { @@ -506,6 +560,14 @@ public class Tests { // For a successful test, the result must be within the ulp bound of // expected AND the result must have absolute value greater than // or equal to the lowerBound. + public static int testUlpDiffWithLowerBound(String testName, double input, + DoubleUnaryOperator func, double expected, + double ulps, double lowerBound) { + return testUlpDiffWithLowerBound(testName, input, + func.applyAsDouble(input), expected, + ulps, lowerBound); + } + public static int testUlpDiffWithLowerBound(String testName, double input, double result, double expected, double ulps, double lowerBound) { @@ -513,8 +575,9 @@ public class Tests { if (!(result >= lowerBound) && !Double.isNaN(expected)) { code = 1; - } else + } else { code = testUlpCore(result, expected, ulps); + } if (code == 1) { System.err.println("Failure for " + testName + @@ -528,6 +591,11 @@ public class Tests { return code; } + public static int testTolerance(String testName, double input, + DoubleUnaryOperator func, double expected, double tolerance) { + return testTolerance(testName, input, func.applyAsDouble(input), expected, tolerance); + + } public static int testTolerance(String testName, double input, double result, double expected, double tolerance) { if (Double.compare(expected, result ) != 0) { @@ -544,13 +612,18 @@ public class Tests { return 1; } return 0; - } - else + } else { return 0; + } } // For a successful test, the result must be within the upper and // lower bounds. + public static int testBounds(String testName, double input, DoubleUnaryOperator func, + double bound1, double bound2) { + return testBounds(testName, input, func.applyAsDouble(input), bound1, bound2); + } + public static int testBounds(String testName, double input, double result, double bound1, double bound2) { if ((result >= bound1 && result <= bound2) || diff --git a/test/jdk/java/lang/Math/WorstCaseTests.java b/test/jdk/java/lang/Math/WorstCaseTests.java index be98d977aabbc926df801d6debf56f13ce7fac0f..2cffa8fabfc0deec5c5137d4250f177de2b7db09 100644 --- a/test/jdk/java/lang/Math/WorstCaseTests.java +++ b/test/jdk/java/lang/Math/WorstCaseTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 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 @@ -29,7 +29,6 @@ * @build WorstCaseTests * @run main WorstCaseTests * @run main/othervm -Xcomp WorstCaseTests - * @author Joseph D. Darcy */ /** @@ -126,8 +125,8 @@ public class WorstCaseTests { private static int testExpCase(double input, double expected) { int failures = 0; double out = Tests.nextOut(expected); - failures += Tests.testBounds("Math.exp", input, Math.exp(input), expected, out); - failures += Tests.testBounds("StrictMath.exp", input, StrictMath.exp(input), expected, out); + failures += Tests.testBounds("Math.exp", input, Math::exp, expected, out); + failures += Tests.testBounds("StrictMath.exp", input, StrictMath::exp, expected, out); return failures; } @@ -158,8 +157,8 @@ public class WorstCaseTests { private static int testLogCase(double input, double expected) { int failures = 0; double out = Tests.nextOut(expected); - failures += Tests.testBounds("Math.log", input, Math.log(input), expected, out); - failures += Tests.testBounds("StrictMath.log", input, StrictMath.log(input), expected, out); + failures += Tests.testBounds("Math.log", input, Math::log, expected, out); + failures += Tests.testBounds("StrictMath.log", input, StrictMath::log, expected, out); return failures; } @@ -191,8 +190,8 @@ public class WorstCaseTests { private static int testSinCase(double input, double expected) { int failures = 0; double out = Tests.nextOut(expected); - failures += Tests.testBounds("Math.sin", input, Math.sin(input), expected, out); - failures += Tests.testBounds("StrictMath.sin", input, StrictMath.sin(input), expected, out); + failures += Tests.testBounds("Math.sin", input, Math::sin, expected, out); + failures += Tests.testBounds("StrictMath.sin", input, StrictMath::sin, expected, out); return failures; } @@ -223,8 +222,8 @@ public class WorstCaseTests { private static int testAsinCase(double input, double expected) { int failures = 0; double out = Tests.nextOut(expected); - failures += Tests.testBounds("Math.asin", input, Math.asin(input), expected, out); - failures += Tests.testBounds("StrictMath.asin", input, StrictMath.asin(input), expected, out); + failures += Tests.testBounds("Math.asin", input, Math::asin, expected, out); + failures += Tests.testBounds("StrictMath.asin", input, StrictMath::asin, expected, out); return failures; } @@ -256,8 +255,8 @@ public class WorstCaseTests { private static int testCosCase(double input, double expected) { int failures = 0; double out = Tests.nextOut(expected); - failures += Tests.testBounds("Math.cos", input, Math.cos(input), expected, out); - failures += Tests.testBounds("StrictMath.cos", input, StrictMath.cos(input), expected, out); + failures += Tests.testBounds("Math.cos", input, Math::cos, expected, out); + failures += Tests.testBounds("StrictMath.cos", input, StrictMath::cos, expected, out); return failures; } @@ -280,8 +279,8 @@ public class WorstCaseTests { private static int testAcosCase(double input, double expected) { int failures = 0; double out = Tests.nextOut(expected); - failures += Tests.testBounds("Math.acos", input, Math.acos(input), expected, out); - failures += Tests.testBounds("StrictMath.acos", input, StrictMath.acos(input), expected, out); + failures += Tests.testBounds("Math.acos", input, Math::acos, expected, out); + failures += Tests.testBounds("StrictMath.acos", input, StrictMath::acos, expected, out); return failures; } @@ -309,8 +308,8 @@ public class WorstCaseTests { private static int testTanCase(double input, double expected) { int failures = 0; double out = Tests.nextOut(expected); - failures += Tests.testBounds("Math.tan", input, Math.tan(input), expected, out); - failures += Tests.testBounds("StrictMath.tan", input, StrictMath.tan(input), expected, out); + failures += Tests.testBounds("Math.tan", input, Math::tan, expected, out); + failures += Tests.testBounds("StrictMath.tan", input, StrictMath::tan, expected, out); return failures; } @@ -341,8 +340,8 @@ public class WorstCaseTests { private static int testAtanCase(double input, double expected) { int failures = 0; double out = Tests.nextOut(expected); - failures += Tests.testBounds("Math.atan", input, Math.atan(input), expected, out); - failures += Tests.testBounds("StrictMath.atan", input, StrictMath.atan(input), expected, out); + failures += Tests.testBounds("Math.atan", input, Math::atan, expected, out); + failures += Tests.testBounds("StrictMath.atan", input, StrictMath::atan, expected, out); return failures; } @@ -367,8 +366,8 @@ public class WorstCaseTests { private static int testPow2Case(double input, double expected) { int failures = 0; double out = Tests.nextOut(expected); - failures += Tests.testBounds("Math.pow2", input, Math.pow(2, input), expected, out); - failures += Tests.testBounds("StrictMath.pow2", input, StrictMath.pow(2, input), expected, out); + failures += Tests.testBounds("Math.pow2", input, d -> Math.pow(2, d), expected, out); + failures += Tests.testBounds("StrictMath.pow2", input, d -> StrictMath.pow(2, d), expected, out); return failures; } @@ -400,8 +399,8 @@ public class WorstCaseTests { private static int testSinhCase(double input, double expected) { int failures = 0; double out = Tests.nextOut(expected); - failures += Tests.testBounds("Math.sinh", input, Math.sinh(input), expected, out); - failures += Tests.testBounds("StrictMath.sinh", input, StrictMath.sinh(input), expected, out); + failures += Tests.testBounds("Math.sinh", input, Math::sinh, expected, out); + failures += Tests.testBounds("StrictMath.sinh", input, StrictMath::sinh, expected, out); return failures; } @@ -428,8 +427,8 @@ public class WorstCaseTests { private static int testCoshCase(double input, double expected) { int failures = 0; double out = Tests.nextOut(expected); - failures += Tests.testBounds("Math.cosh", input, Math.cosh(input), expected, out); - failures += Tests.testBounds("StrictMath.cosh", input, StrictMath.cosh(input), expected, out); + failures += Tests.testBounds("Math.cosh", input, Math::cosh, expected, out); + failures += Tests.testBounds("StrictMath.cosh", input, StrictMath::cosh, expected, out); return failures; } } diff --git a/test/jdk/java/lang/Object/FinalizationOption.java b/test/jdk/java/lang/Object/FinalizationOption.java new file mode 100644 index 0000000000000000000000000000000000000000..7d50412e26f07a0d21b067ad7bf1b4e8dced9216 --- /dev/null +++ b/test/jdk/java/lang/Object/FinalizationOption.java @@ -0,0 +1,122 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8276422 + * @summary add command-line option to disable finalization + * @run main/othervm FinalizationOption yes + * @run main/othervm --finalization=enabled FinalizationOption yes + * @run main/othervm --finalization=disabled FinalizationOption no + */ +public class FinalizationOption { + static volatile boolean finalizerWasCalled = false; + + @SuppressWarnings("deprecation") + protected void finalize() { + finalizerWasCalled = true; + } + + static void create() { + new FinalizationOption(); + } + + /** + * Checks whether the finalizer thread is or is not running. The finalizer thread + * is a thread in the root thread group whose named is "Finalizer". + * @param expected boolean indicating whether a finalizer thread should exist + * @return boolean indicating whether the expectation was met + */ + static boolean checkFinalizerThread(boolean expected) { + ThreadGroup root = Thread.currentThread().getThreadGroup(); + for (ThreadGroup parent = root; + parent != null; + root = parent, parent = root.getParent()) + ; + + int nt = 100; + Thread[] threads; + while (true) { + threads = new Thread[nt]; + nt = root.enumerate(threads); + if (nt < threads.length) + break; + threads = new Thread[nt + 100]; + } + + Thread ft = null; + for (int i = 0; i < nt; i++) { + if ("Finalizer".equals(threads[i].getName())) { + ft = threads[i]; + break; + } + } + + String msg = (ft == null) ? "(none)" : ft.toString(); + boolean passed = (ft != null) == expected; + System.out.printf("Finalizer thread. Expected: %s Actual: %s %s%n", + expected, msg, passed ? "Passed." : "FAILED!"); + return passed; + } + + /** + * Checks whether there was a call to the finalize() method. + * @param expected boolean whether finalize() should be called + * @return boolean indicating whether the expecation was met + */ + static boolean checkFinalizerCalled(boolean expected) { + create(); + for (int i = 0; i < 100; i++) { + System.gc(); + try { + Thread.sleep(10L); + } catch (InterruptedException ie) { + Thread.currentThread().interrupt(); + } + if (finalizerWasCalled) { + break; + } + } + boolean passed = (expected == finalizerWasCalled); + System.out.printf("Call to finalize(). Expected: %s Actual: %s %s%n", + expected, finalizerWasCalled, + passed ? "Passed." : "FAILED!"); + return passed; + } + + public static void main(String[] args) { + boolean finalizationEnabled = switch (args[0]) { + case "yes" -> true; + case "no" -> false; + default -> { + throw new AssertionError("usage: FinalizationOption yes|no"); + } + }; + + boolean threadPass = checkFinalizerThread(finalizationEnabled); + boolean calledPass = checkFinalizerCalled(finalizationEnabled); + + if (!threadPass || !calledPass) + throw new AssertionError("Test failed."); + } +} diff --git a/test/jdk/java/lang/Object/InvalidFinalizationOption.java b/test/jdk/java/lang/Object/InvalidFinalizationOption.java new file mode 100644 index 0000000000000000000000000000000000000000..c5cca549ead095f62a251d65cfb80ae78799d201 --- /dev/null +++ b/test/jdk/java/lang/Object/InvalidFinalizationOption.java @@ -0,0 +1,52 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8276422 + * @summary Invalid/missing values for the finalization option should be rejected + * @library /test/lib + * @run driver InvalidFinalizationOption + */ + +import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.process.OutputAnalyzer; + +public class InvalidFinalizationOption { + public static void main(String[] args) throws Exception { + record TestData(String arg, String expected) { } + + TestData[] testData = { + new TestData("--finalization", "Unrecognized option"), + new TestData("--finalization=", "Invalid finalization value"), + new TestData("--finalization=azerty", "Invalid finalization value") + }; + + for (var data : testData) { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(data.arg); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldContain(data.expected); + output.shouldHaveExitValue(1); + } + } +} diff --git a/test/jdk/java/lang/ProcessBuilder/Basic.java b/test/jdk/java/lang/ProcessBuilder/Basic.java index fcf2edb7b79a706e999769133fcb19661eb37249..f27d83e0c44ba525eeb8e2c87d439985da723607 100644 --- a/test/jdk/java/lang/ProcessBuilder/Basic.java +++ b/test/jdk/java/lang/ProcessBuilder/Basic.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -27,7 +27,7 @@ * 5026830 5023243 5070673 4052517 4811767 6192449 6397034 6413313 * 6464154 6523983 6206031 4960438 6631352 6631966 6850957 6850958 * 4947220 7018606 7034570 4244896 5049299 8003488 8054494 8058464 - * 8067796 8224905 8263729 8265173 8272600 8231297 + * 8067796 8224905 8263729 8265173 8272600 8231297 8282219 * @key intermittent * @summary Basic tests for Process and Environment Variable code * @modules java.base/java.lang:open @@ -1870,6 +1870,8 @@ public class Basic { String[] envpOth = {"=ExitValue=3", "=C:=\\"}; if (Windows.is()) { envp = envpWin; + } else if (AIX.is()) { + envp = new String[] {"=ExitValue=3", "=C:=\\", "LIBPATH=" + libpath}; } else { envp = envpOth; } @@ -1918,6 +1920,9 @@ public class Basic { String[] envp; if (Windows.is()) { envp = envpWin; + } else if (AIX.is()) { + envp = new String[] {"LC_ALL=C\u0000\u0000", // Yuck! + "FO\u0000=B\u0000R", "LIBPATH=" + libpath}; } else { envp = envpOth; } diff --git a/test/jdk/java/lang/RuntimeTests/Version/Basic.java b/test/jdk/java/lang/RuntimeTests/Version/Basic.java index 3979c696622b1f7f9a3ed91b684c52143ecfa14e..d8dd9f1a0dda1c765e2bf63d62ea1ed19906ab0f 100644 --- a/test/jdk/java/lang/RuntimeTests/Version/Basic.java +++ b/test/jdk/java/lang/RuntimeTests/Version/Basic.java @@ -249,7 +249,7 @@ public class Basic { } Optional<String> javaVerPre - = (ver.length == 2) + = (ver.length >= 2) ? Optional.ofNullable(ver[1]) : Optional.empty(); if (!javaVerPre.equals(current.pre())) { diff --git a/test/jdk/java/lang/StrictMath/CubeRootTests.java b/test/jdk/java/lang/StrictMath/CubeRootTests.java index f4a3978075d4ad1dee36c1fbfe885c1dce4d3f95..0423f1ff087532a1ff3c7291501d651e8d8af0cc 100644 --- a/test/jdk/java/lang/StrictMath/CubeRootTests.java +++ b/test/jdk/java/lang/StrictMath/CubeRootTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -32,7 +32,6 @@ * @build CubeRootTests * @run main CubeRootTests * @summary Tests specifically for StrictMath.cbrt - * @author Joseph D. Darcy */ import jdk.test.lib.RandomFactory; @@ -71,9 +70,9 @@ public class CubeRootTests { double minus_expected = -expected; failures+=Tests.test("StrictMath.cbrt(double)", input, - StrictMath.cbrt(input), expected); + StrictMath::cbrt, expected); failures+=Tests.test("StrictMath.cbrt(double)", minus_input, - StrictMath.cbrt(minus_input), minus_expected); + StrictMath::cbrt, minus_expected); return failures; } diff --git a/test/jdk/java/lang/StrictMath/Expm1Tests.java b/test/jdk/java/lang/StrictMath/Expm1Tests.java index 368d1025993c42c5a6fb412a304e28613c80b67d..e7d9696535d9b9033abc075b5bc86f9c250e8434 100644 --- a/test/jdk/java/lang/StrictMath/Expm1Tests.java +++ b/test/jdk/java/lang/StrictMath/Expm1Tests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -25,7 +25,8 @@ * @test * @bug 4851638 * @summary Tests for StrictMath.expm1 - * @author Joseph D. Darcy + * @compile -Xdiags:verbose Expm1Tests.java + * @run main Expm1Tests */ /** @@ -44,7 +45,7 @@ public class Expm1Tests { static int testExpm1Case(double input, double expected) { return Tests.test("StrictMath.expm1(double)", input, - StrictMath.expm1(input), expected); + StrictMath::expm1, expected); } static int testExpm1() { diff --git a/test/jdk/java/lang/StrictMath/HyperbolicTests.java b/test/jdk/java/lang/StrictMath/HyperbolicTests.java index 37b851dd795e85b366bd4ad7c4bf903e71b5b049..4dfc7596d38d40fa1b2f5d0e4960c42d5ab19cf1 100644 --- a/test/jdk/java/lang/StrictMath/HyperbolicTests.java +++ b/test/jdk/java/lang/StrictMath/HyperbolicTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -25,7 +25,6 @@ * @test * @bug 4851625 * @summary Tests for StrictMath.{sinh, cosh, tanh} - * @author Joseph D. Darcy */ /** @@ -45,17 +44,17 @@ public class HyperbolicTests { static int testSinhCase(double input, double expected) { return Tests.test("StrictMath.sinh(double)", input, - StrictMath.sinh(input), expected); + StrictMath::sinh, expected); } static int testCoshCase(double input, double expected) { return Tests.test("StrictMath.cosh(double)", input, - StrictMath.cosh(input), expected); + StrictMath::cosh, expected); } static int testTanhCase(double input, double expected) { return Tests.test("StrictMath.tanh(double)", input, - StrictMath.tanh(input), expected); + StrictMath::tanh, expected); } static int testSinh() { diff --git a/test/jdk/java/lang/StrictMath/HypotTests.java b/test/jdk/java/lang/StrictMath/HypotTests.java index 0b1dd41691fda3a90c5a553d09cf3f00d84750e5..c714dcf1499dd76f7b2c74c2b19e1e54cea29b76 100644 --- a/test/jdk/java/lang/StrictMath/HypotTests.java +++ b/test/jdk/java/lang/StrictMath/HypotTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -32,7 +32,6 @@ * @build FdlibmTranslit * @build HypotTests * @run main HypotTests - * @author Joseph D. Darcy */ import jdk.test.lib.RandomFactory; @@ -72,28 +71,28 @@ public class HypotTests { static int testHypotCase(double input1, double input2, double expected) { int failures = 0; failures += Tests.test("StrictMath.hypot(double)", input1, input2, - StrictMath.hypot(input1, input2), expected); + StrictMath::hypot, expected); failures += Tests.test("StrictMath.hypot(double)", input2, input1, - StrictMath.hypot(input2, input1), expected); + StrictMath::hypot, expected); failures += Tests.test("StrictMath.hypot(double)", -input1, input2, - StrictMath.hypot(-input1, input2), expected); + StrictMath::hypot, expected); failures += Tests.test("StrictMath.hypot(double)", input2, -input1, - StrictMath.hypot(input2, -input1), expected); + StrictMath::hypot, expected); failures += Tests.test("StrictMath.hypot(double)", input1, -input2, - StrictMath.hypot(input1, -input2), expected); + StrictMath::hypot, expected); failures += Tests.test("StrictMath.hypot(double)", -input2, input1, - StrictMath.hypot(-input2, input1), expected); + StrictMath::hypot, expected); failures += Tests.test("StrictMath.hypot(double)", -input1, -input2, - StrictMath.hypot(-input1, -input2), expected); + StrictMath::hypot, expected); failures += Tests.test("StrictMath.hypot(double)", -input2, -input1, - StrictMath.hypot(-input2, -input1), expected); + StrictMath::hypot, expected); return failures; } diff --git a/test/jdk/java/lang/StrictMath/Log10Tests.java b/test/jdk/java/lang/StrictMath/Log10Tests.java index af07eac7e66f084478c51526ac0769bbd4e8c772..eed6e8a510637c89297b6a8f813f6ffe1c3a8076 100644 --- a/test/jdk/java/lang/StrictMath/Log10Tests.java +++ b/test/jdk/java/lang/StrictMath/Log10Tests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -25,7 +25,6 @@ * @test * @bug 4074599 * @summary Tests for StrictMath.log10 - * @author Joseph D. Darcy */ @@ -45,7 +44,7 @@ public class Log10Tests { static int testLog10Case(double input, double expected) { return Tests.test("StrictMath.log10(double)", input, - StrictMath.log10(input), expected); + StrictMath::log10, expected); } static int testLog10() { diff --git a/test/jdk/java/lang/StrictMath/Log1pTests.java b/test/jdk/java/lang/StrictMath/Log1pTests.java index 91b0835222c88553c650895053c05f3a7818add3..9cd03d3306af62f71c452418699aeef324bf73fe 100644 --- a/test/jdk/java/lang/StrictMath/Log1pTests.java +++ b/test/jdk/java/lang/StrictMath/Log1pTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -25,7 +25,6 @@ * @test * @bug 4851638 * @summary Tests for StrictMath.log1p - * @author Joseph D. Darcy */ /** @@ -44,7 +43,7 @@ public class Log1pTests { static int testLog1pCase(double input, double expected) { return Tests.test("StrictMath.log1p(double)", input, - StrictMath.log1p(input), expected); + StrictMath::log1p, expected); } static int testLog1p() { diff --git a/test/jdk/java/lang/StrictMath/PowTests.java b/test/jdk/java/lang/StrictMath/PowTests.java index 338cf42d54c8736f9d1fc23f50c4ccc2145b38a4..2936dfdf247087c0988f24c3df25a1bc101fa343 100644 --- a/test/jdk/java/lang/StrictMath/PowTests.java +++ b/test/jdk/java/lang/StrictMath/PowTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -25,7 +25,6 @@ * @test * @bug 8136874 * @summary Tests for StrictMath.pow - * @author Joseph D. Darcy */ /** @@ -295,7 +294,7 @@ public class PowTests { private static int testPowCase(double input1, double input2, double expected) { int failures = 0; failures += Tests.test("StrictMath.pow(double)", input1, input2, - StrictMath.pow(input1, input2), expected); + StrictMath::pow, expected); return failures; } } diff --git a/test/jdk/java/lang/StrictMath/Tests.java b/test/jdk/java/lang/StrictMath/Tests.java index 0513cb70d1e82fc11267d227cbf5eb4879dba087..a675b2e961719e3c9d60c9ce3a2de7700ac0f95c 100644 --- a/test/jdk/java/lang/StrictMath/Tests.java +++ b/test/jdk/java/lang/StrictMath/Tests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -21,33 +21,48 @@ * questions. */ +import java.util.function.DoubleBinaryOperator; +import java.util.function.DoubleUnaryOperator; + /* - * - * * Shared static test method for StrictMath tests. */ - public class Tests { private Tests(){} - static int test(String testName, - double input, - double result, - double expected) { + public static int test(String testName, + double input, + DoubleUnaryOperator func, + double expected) { + return test(testName, input, func.applyAsDouble(input), expected); + } + + public static int test(String testName, + double input, + double result, + double expected) { if (Double.compare(expected, result ) != 0) { System.err.println("Failure for " + testName + ":\n" + "\tFor input " + input + "\t(" + Double.toHexString(input) + ")\n" + "\texpected " + expected + "\t(" + Double.toHexString(expected) + ")\n" + "\tgot " + result + "\t(" + Double.toHexString(result) + ")."); return 1; - } - else + } else { return 0; + } + } + + public static int test(String testName, + double input1, + double input2, + DoubleBinaryOperator func, + double expected) { + return test(testName, input1, input2, func.applyAsDouble(input1, input2), expected); } - static int test(String testName, double input1, double input2, - double result, double expected) { + public static int test(String testName, double input1, double input2, + double result, double expected) { if (Double.compare(expected, result ) != 0) { System.err.println("Failure for " + testName + ":\n" + "\tFor input " + input1 + "\t(" + Double.toHexString(input1) + "), " + @@ -55,9 +70,9 @@ public class Tests { "\texpected " + expected + "\t(" + Double.toHexString(expected) + ")\n" + "\tgot " + result + "\t(" + Double.toHexString(result) + ")."); return 1; - } - else + } else { return 0; + } } /** diff --git a/test/jdk/java/lang/StringBuffer/HugeCapacity.java b/test/jdk/java/lang/StringBuffer/HugeCapacity.java index d30d2d945b5f404525be91459a6c6047a7e6383e..e3c98496c50c80fc59ed25ee09b0ad350554a3dd 100644 --- a/test/jdk/java/lang/StringBuffer/HugeCapacity.java +++ b/test/jdk/java/lang/StringBuffer/HugeCapacity.java @@ -26,8 +26,8 @@ * @bug 8218227 * @summary StringBuilder/StringBuffer constructor throws confusing * NegativeArraySizeException - * @requires (sun.arch.data.model == "64" & os.maxMemory >= 6G) - * @run main/othervm -Xms5G -Xmx5G HugeCapacity + * @requires (sun.arch.data.model == "64" & os.maxMemory >= 8G) + * @run main/othervm -Xms6G -Xmx6G HugeCapacity */ public class HugeCapacity { diff --git a/test/jdk/java/lang/StringBuilder/HugeCapacity.java b/test/jdk/java/lang/StringBuilder/HugeCapacity.java index 9f1617a9dd241e956da6670cb5af95350d8cb576..a584ce1f07a9d25dfa0f32f042b96c0a799c8fc4 100644 --- a/test/jdk/java/lang/StringBuilder/HugeCapacity.java +++ b/test/jdk/java/lang/StringBuilder/HugeCapacity.java @@ -26,9 +26,9 @@ * @bug 8149330 8218227 * @summary Capacity should not get close to Integer.MAX_VALUE unless * necessary - * @requires (sun.arch.data.model == "64" & os.maxMemory >= 6G) - * @run main/othervm -Xms5G -Xmx5G -XX:+CompactStrings HugeCapacity true - * @run main/othervm -Xms5G -Xmx5G -XX:-CompactStrings HugeCapacity false + * @requires (sun.arch.data.model == "64" & os.maxMemory >= 8G) + * @run main/othervm -Xms6G -Xmx6G -XX:+CompactStrings HugeCapacity true + * @run main/othervm -Xms6G -Xmx6G -XX:-CompactStrings HugeCapacity false */ public class HugeCapacity { diff --git a/test/jdk/java/lang/System/FileEncodingTest.java b/test/jdk/java/lang/System/FileEncodingTest.java index 5e5d600bf2bd23818cb7b5919b442c5a304b83ed..6bff90ccb8b2b6d093a63d42d94d55bf1306c7aa 100644 --- a/test/jdk/java/lang/System/FileEncodingTest.java +++ b/test/jdk/java/lang/System/FileEncodingTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -23,7 +23,7 @@ /* * @test - * @bug 8260265 + * @bug 8260265 8282042 * @summary Test file.encoding system property * @library /test/lib * @build jdk.test.lib.process.* @@ -40,7 +40,7 @@ import org.testng.annotations.DataProvider; import org.testng.annotations.Test; public class FileEncodingTest { - private static final boolean IS_WINDOWS = System.getProperty("os.name").startsWith("Windows"); + private static final String OS_NAME = System.getProperty("os.name"); @DataProvider public Object[][] fileEncodingToDefault() { @@ -56,7 +56,7 @@ public class FileEncodingTest { @Test(dataProvider = "fileEncodingToDefault") public void testFileEncodingToDefault(String fileEncoding, String expected) throws Exception { if (fileEncoding.equals("COMPAT")) { - if (IS_WINDOWS) { + if (OS_NAME.startsWith("Windows")) { // Only tests on English locales if (Locale.getDefault().getLanguage().equals("en")) { expected = "windows-1252"; @@ -64,6 +64,8 @@ public class FileEncodingTest { System.out.println("Tests only run on Windows with English locales"); return; } + } else if (OS_NAME.startsWith("AIX")) { + expected = "ISO-8859-1"; } else { expected = "US-ASCII"; } diff --git a/test/jdk/java/lang/System/LoggerFinder/internal/LoggerFinderLoaderTest/LoggerFinderLoaderTest.java b/test/jdk/java/lang/System/LoggerFinder/internal/LoggerFinderLoaderTest/LoggerFinderLoaderTest.java index 8f1ce47fb07e6f13361bade127b84495465621eb..d7ac228667859c9cfb5e8c460f9ba1799aecff72 100644 --- a/test/jdk/java/lang/System/LoggerFinder/internal/LoggerFinderLoaderTest/LoggerFinderLoaderTest.java +++ b/test/jdk/java/lang/System/LoggerFinder/internal/LoggerFinderLoaderTest/LoggerFinderLoaderTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -53,7 +53,7 @@ import java.util.concurrent.atomic.AtomicReference; /** * @test - * @bug 8140364 8189291 + * @bug 8140364 8189291 8283049 * @summary JDK implementation specific unit test for LoggerFinderLoader. * Tests the behavior of LoggerFinderLoader with respect to the * value of the internal diagnosability switches. Also test the @@ -230,7 +230,7 @@ public class LoggerFinderLoaderTest { throw new RuntimeException("Expected message not found. Error stream contained: " + warning); } } else if (singleton) { - if (!warning.contains("java.util.ServiceConfigurationError: More than on LoggerFinder implementation")) { + if (!warning.contains("java.util.ServiceConfigurationError: More than one LoggerFinder implementation")) { throw new RuntimeException("Expected message not found. Error stream contained: " + warning); } } diff --git a/test/jdk/java/lang/annotation/AnnotationToStringTest.java b/test/jdk/java/lang/annotation/AnnotationToStringTest.java index e9fcf57014e4702fd8f7606702e61c60d116b964..71551193a3f0851d2f25e98704eb7d90ab255045 100644 --- a/test/jdk/java/lang/annotation/AnnotationToStringTest.java +++ b/test/jdk/java/lang/annotation/AnnotationToStringTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -31,7 +31,8 @@ // test/langtools/tools/javac/processing/model/element/AnnotationToStringTest.java import java.lang.annotation.*; -import java.lang.reflect.*; +import java.lang.reflect.Field; +import javax.lang.model.element.Modifier; import java.util.*; /** @@ -160,6 +161,11 @@ public class AnnotationToStringTest { } static class ArrayAnnotationHost { + @ExpectedString( + "@EnumValue(NON_SEALED)") // toString and name differ + @EnumValue(Modifier.NON_SEALED) + public int f00; + @ExpectedString( "@BooleanArray({true, false, true})") @BooleanArray({true, false, true}) @@ -213,8 +219,8 @@ public class AnnotationToStringTest { public Class<?>[] f9; @ExpectedString( - "@EnumArray({SOURCE})") - @EnumArray({RetentionPolicy.SOURCE}) + "@EnumArray({SEALED, NON_SEALED, PUBLIC})") + @EnumArray({Modifier.SEALED, Modifier.NON_SEALED, Modifier.PUBLIC}) public RetentionPolicy[] f10; } } @@ -223,6 +229,11 @@ public class AnnotationToStringTest { class Obj {} +@Retention(RetentionPolicy.RUNTIME) +@interface EnumValue { + Modifier value(); +} + @Retention(RetentionPolicy.RUNTIME) @interface ExpectedString { String value(); @@ -285,7 +296,7 @@ class Obj {} @Retention(RetentionPolicy.RUNTIME) @interface EnumArray { - RetentionPolicy[] value(); + Modifier[] value(); } @Retention(RetentionPolicy.RUNTIME) diff --git a/test/jdk/java/lang/annotation/AnnotationTypeMismatchException/EnumTypeMismatchTest.java b/test/jdk/java/lang/annotation/AnnotationTypeMismatchException/EnumTypeMismatchTest.java index dd787e727b44c5b6d97934bd63e02ccbce0b515d..5000aa0ee65fae0000088e117f1ff4db56f3c332 100644 --- a/test/jdk/java/lang/annotation/AnnotationTypeMismatchException/EnumTypeMismatchTest.java +++ b/test/jdk/java/lang/annotation/AnnotationTypeMismatchException/EnumTypeMismatchTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -61,7 +61,7 @@ public class EnumTypeMismatchTest { } catch (AnnotationTypeMismatchException e) { if (!e.element().getName().equals("value")) { throw new IllegalStateException("Unexpected element: " + e.element()); - } else if (!e.foundType().equals("@" + AnAnnotation.class.getName() + "(" + AnEnum.VALUE.name() + ")")) { + } else if (!e.foundType().equals("@" + AnAnnotation.class.getCanonicalName() + "(" + AnEnum.VALUE.name() + ")")) { throw new IllegalStateException("Unexpected type: " + e.foundType()); } } diff --git a/test/jdk/java/lang/annotation/TestConstructorParameterAnnotations.java b/test/jdk/java/lang/annotation/TestConstructorParameterAnnotations.java index f36474ef3b7826cd99599005d22a57230975bdbe..3e39cdb6e8d867ba3d82e0493239d1a1b241bfe3 100644 --- a/test/jdk/java/lang/annotation/TestConstructorParameterAnnotations.java +++ b/test/jdk/java/lang/annotation/TestConstructorParameterAnnotations.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -129,21 +129,21 @@ public class TestConstructorParameterAnnotations { @ExpectedGetParameterAnnotations( "[[], " + - "[@TestConstructorParameterAnnotations$MarkerAnnotation(1)]]") + "[@TestConstructorParameterAnnotations.MarkerAnnotation(1)]]") @ExpectedParameterAnnotations({ "null", - "@TestConstructorParameterAnnotations$MarkerAnnotation(1)"}) + "@TestConstructorParameterAnnotations.MarkerAnnotation(1)"}) public class NestedClass1 { public NestedClass1(@MarkerAnnotation(1) int parameter) {} } @ExpectedGetParameterAnnotations( "[[], " + - "[@TestConstructorParameterAnnotations$MarkerAnnotation(2)], " + + "[@TestConstructorParameterAnnotations.MarkerAnnotation(2)], " + "[]]") @ExpectedParameterAnnotations({ "null", - "@TestConstructorParameterAnnotations$MarkerAnnotation(2)", + "@TestConstructorParameterAnnotations.MarkerAnnotation(2)", "null"}) public class NestedClass2 { public NestedClass2(@MarkerAnnotation(2) int parameter1, @@ -152,11 +152,11 @@ public class TestConstructorParameterAnnotations { @ExpectedGetParameterAnnotations( "[[], " + - "[@TestConstructorParameterAnnotations$MarkerAnnotation(3)], " + + "[@TestConstructorParameterAnnotations.MarkerAnnotation(3)], " + "[]]") @ExpectedParameterAnnotations({ "null", - "@TestConstructorParameterAnnotations$MarkerAnnotation(3)", + "@TestConstructorParameterAnnotations.MarkerAnnotation(3)", "null"}) public class NestedClass3 { public <P> NestedClass3(@MarkerAnnotation(3) P parameter1, @@ -165,11 +165,11 @@ public class TestConstructorParameterAnnotations { @ExpectedGetParameterAnnotations( "[[], " + - "[@TestConstructorParameterAnnotations$MarkerAnnotation(4)], " + + "[@TestConstructorParameterAnnotations.MarkerAnnotation(4)], " + "[]]") @ExpectedParameterAnnotations({ "null", - "@TestConstructorParameterAnnotations$MarkerAnnotation(4)", + "@TestConstructorParameterAnnotations.MarkerAnnotation(4)", "null"}) public class NestedClass4 { public <P, Q> NestedClass4(@MarkerAnnotation(4) P parameter1, @@ -183,18 +183,18 @@ public class TestConstructorParameterAnnotations { } @ExpectedGetParameterAnnotations( - "[[@TestConstructorParameterAnnotations$MarkerAnnotation(1)]]") + "[[@TestConstructorParameterAnnotations.MarkerAnnotation(1)]]") @ExpectedParameterAnnotations({ - "@TestConstructorParameterAnnotations$MarkerAnnotation(1)"}) + "@TestConstructorParameterAnnotations.MarkerAnnotation(1)"}) public static class StaticNestedClass1 { public StaticNestedClass1(@MarkerAnnotation(1) int parameter) {} } @ExpectedGetParameterAnnotations( - "[[@TestConstructorParameterAnnotations$MarkerAnnotation(2)], " + + "[[@TestConstructorParameterAnnotations.MarkerAnnotation(2)], " + "[]]") @ExpectedParameterAnnotations({ - "@TestConstructorParameterAnnotations$MarkerAnnotation(2)", + "@TestConstructorParameterAnnotations.MarkerAnnotation(2)", "null"}) public static class StaticNestedClass2 { public StaticNestedClass2(@MarkerAnnotation(2) int parameter1, @@ -202,10 +202,10 @@ public class TestConstructorParameterAnnotations { } @ExpectedGetParameterAnnotations( - "[[@TestConstructorParameterAnnotations$MarkerAnnotation(3)], " + + "[[@TestConstructorParameterAnnotations.MarkerAnnotation(3)], " + "[]]") @ExpectedParameterAnnotations({ - "@TestConstructorParameterAnnotations$MarkerAnnotation(3)", + "@TestConstructorParameterAnnotations.MarkerAnnotation(3)", "null"}) public static class StaticNestedClass3 { public <P> StaticNestedClass3(@MarkerAnnotation(3) P parameter1, @@ -213,10 +213,10 @@ public class TestConstructorParameterAnnotations { } @ExpectedGetParameterAnnotations( - "[[@TestConstructorParameterAnnotations$MarkerAnnotation(4)], " + + "[[@TestConstructorParameterAnnotations.MarkerAnnotation(4)], " + "[]]") @ExpectedParameterAnnotations({ - "@TestConstructorParameterAnnotations$MarkerAnnotation(4)", + "@TestConstructorParameterAnnotations.MarkerAnnotation(4)", "null"}) public static class StaticNestedClass4 { public <P, Q> StaticNestedClass4(@MarkerAnnotation(4) P parameter1, diff --git a/test/jdk/java/lang/annotation/TypeAnnotationReflection.java b/test/jdk/java/lang/annotation/TypeAnnotationReflection.java index 64234ccc215ff48deb78e6c9cf696648e3827ccf..9c0a101c2b6af872f8f7856a984ab67677b4ea69 100644 --- a/test/jdk/java/lang/annotation/TypeAnnotationReflection.java +++ b/test/jdk/java/lang/annotation/TypeAnnotationReflection.java @@ -39,7 +39,8 @@ public class TypeAnnotationReflection { testReturnType(); testNested(); testArray(); - testRunException(); + testRunException(TestClassException.class.getDeclaredMethod("foo", (Class<?>[])null)); + testRunException(Outer2.TestClassException2.class.getDeclaredConstructor(Outer2.class)); testClassTypeVarBounds(); testMethodTypeVarBounds(); testFields(); @@ -142,9 +143,8 @@ public class TypeAnnotationReflection { check(((TypeAnno)annos[0]).value().equals("return4")); } - private static void testRunException() throws Exception { - Method m = TestClassException.class.getDeclaredMethod("foo", (Class<?>[])null); - AnnotatedType[] ts = m.getAnnotatedExceptionTypes(); + private static void testRunException(Executable e) throws Exception { + AnnotatedType[] ts = e.getAnnotatedExceptionTypes(); check(ts.length == 3); AnnotatedType t; @@ -624,6 +624,15 @@ abstract class TestClassException { } } +class Outer2 { + abstract class TestClassException2 { + public TestClassException2() throws + @TypeAnno("RE") @TypeAnno2("RE2") RuntimeException, + NullPointerException, + @TypeAnno("AIOOBE") ArrayIndexOutOfBoundsException {} + } +} + abstract class TestClassTypeVarAndField <T extends @TypeAnno("Object1") Object & @TypeAnno("Runnable1") @TypeAnno2("Runnable2") Runnable, @TypeAnno("EE")EE extends @TypeAnno2("EEBound") Runnable, V > { diff --git a/test/jdk/java/lang/annotation/UnitTest.java b/test/jdk/java/lang/annotation/UnitTest.java index c9f9ea51ee8fab3d3b88456625386b6959237a13..776c575eef3578b8215773ce8dcf7f9c93d6f510 100644 --- a/test/jdk/java/lang/annotation/UnitTest.java +++ b/test/jdk/java/lang/annotation/UnitTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -1299,9 +1299,9 @@ public class UnitTest { // *** TESTS FOR ANNOTATION INHERITANCE AND ENUMERATING DECLARED ANNOTATIONS // Inheritance tests - checkInheritence(Grandpa.class, true, true); - checkInheritence(Dad.class, true, false); - checkInheritence(Son.class, true, true); + checkInheritance(Grandpa.class, true, true); + checkInheritance(Dad.class, true, false); + checkInheritance(Son.class, true, true); // Declared annotations tests checkDeclaredAnnotations(Grandpa.class, true, true); @@ -3531,7 +3531,7 @@ public class UnitTest { } // Verification method for inheritance test - static void checkInheritence(AnnotatedElement e, boolean shouldHaveFoo, boolean shouldHaveBar) { + static void checkInheritance(AnnotatedElement e, boolean shouldHaveFoo, boolean shouldHaveBar) { numTests++; try { boolean hasFoo = e.isAnnotationPresent(Foo.class); diff --git a/test/jdk/java/lang/annotation/typeAnnotations/GetAnnotatedNestedSuperclass.java b/test/jdk/java/lang/annotation/typeAnnotations/GetAnnotatedNestedSuperclass.java index a667a2e2c23977863ea467c5ecc07116fd8246a8..8603b7f9f198bd52bffa49869ec545a956333f8c 100644 --- a/test/jdk/java/lang/annotation/typeAnnotations/GetAnnotatedNestedSuperclass.java +++ b/test/jdk/java/lang/annotation/typeAnnotations/GetAnnotatedNestedSuperclass.java @@ -64,31 +64,31 @@ public class GetAnnotatedNestedSuperclass { public static void main(String[] args) throws Exception { AnnotatedType x = Y.class.getAnnotatedSuperclass(); - assertEquals(Arrays.toString(x.getAnnotations()), "[@GetAnnotatedNestedSuperclass$A()]"); + assertEquals(Arrays.toString(x.getAnnotations()), "[@GetAnnotatedNestedSuperclass.A()]"); AnnotatedParameterizedType xpt = (AnnotatedParameterizedType) x; { AnnotatedType arg = xpt.getAnnotatedActualTypeArguments()[0]; assertEquals( - Arrays.toString(arg.getAnnotations()), "[@GetAnnotatedNestedSuperclass$B()]"); + Arrays.toString(arg.getAnnotations()), "[@GetAnnotatedNestedSuperclass.B()]"); } { AnnotatedType arg = xpt.getAnnotatedActualTypeArguments()[1]; assertEquals( - Arrays.toString(arg.getAnnotations()), "[@GetAnnotatedNestedSuperclass$C()]"); + Arrays.toString(arg.getAnnotations()), "[@GetAnnotatedNestedSuperclass.C()]"); } { AnnotatedType arg = xpt.getAnnotatedActualTypeArguments()[2]; assertEquals( - Arrays.toString(arg.getAnnotations()), "[@GetAnnotatedNestedSuperclass$D()]"); + Arrays.toString(arg.getAnnotations()), "[@GetAnnotatedNestedSuperclass.D()]"); AnnotatedType nestedArg = ((AnnotatedParameterizedType) arg).getAnnotatedActualTypeArguments()[0]; assertEquals( Arrays.toString(nestedArg.getAnnotations()), - "[@GetAnnotatedNestedSuperclass$E()]"); + "[@GetAnnotatedNestedSuperclass.E()]"); } } - private static void assertEquals(Object expected, Object actual) { + private static void assertEquals(Object actual, Object expected) { if (!Objects.equals(expected, actual)) { throw new AssertionError("expected: " + expected + "; actual=" + actual); } diff --git a/test/jdk/java/lang/annotation/typeAnnotations/TestConstructorParameterTypeAnnotations.java b/test/jdk/java/lang/annotation/typeAnnotations/TestConstructorParameterTypeAnnotations.java index 21934b3247d20f2138dd2bcc6e19bc00065872c5..a90aa36ba092c654a2b5aa2dbed9b75641be200d 100644 --- a/test/jdk/java/lang/annotation/typeAnnotations/TestConstructorParameterTypeAnnotations.java +++ b/test/jdk/java/lang/annotation/typeAnnotations/TestConstructorParameterTypeAnnotations.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -128,7 +128,7 @@ public class TestConstructorParameterTypeAnnotations { @ExpectedGetParameterAnnotations("[[], []]") @ExpectedParameterTypeAnnotations({ "null", - "@TestConstructorParameterTypeAnnotations$MarkerTypeAnnotation(1)"}) + "@TestConstructorParameterTypeAnnotations.MarkerTypeAnnotation(1)"}) public class NestedClass1 { public NestedClass1(@MarkerTypeAnnotation(1) int parameter) {} } @@ -136,7 +136,7 @@ public class TestConstructorParameterTypeAnnotations { @ExpectedGetParameterAnnotations("[[], [], []]") @ExpectedParameterTypeAnnotations({ "null", - "@TestConstructorParameterTypeAnnotations$MarkerTypeAnnotation(2)", + "@TestConstructorParameterTypeAnnotations.MarkerTypeAnnotation(2)", "null"}) public class NestedClass2 { public NestedClass2(@MarkerTypeAnnotation(2) int parameter1, @@ -146,7 +146,7 @@ public class TestConstructorParameterTypeAnnotations { @ExpectedGetParameterAnnotations("[[], [], []]") @ExpectedParameterTypeAnnotations({ "null", - "@TestConstructorParameterTypeAnnotations$MarkerTypeAnnotation(3)", + "@TestConstructorParameterTypeAnnotations.MarkerTypeAnnotation(3)", "null"}) public class NestedClass3 { public <P> NestedClass3(@MarkerTypeAnnotation(3) P parameter1, @@ -156,7 +156,7 @@ public class TestConstructorParameterTypeAnnotations { @ExpectedGetParameterAnnotations("[[], [], []]") @ExpectedParameterTypeAnnotations({ "null", - "@TestConstructorParameterTypeAnnotations$MarkerTypeAnnotation(4)", + "@TestConstructorParameterTypeAnnotations.MarkerTypeAnnotation(4)", "null"}) public class NestedClass4 { public <P, Q> NestedClass4(@MarkerTypeAnnotation(4) P parameter1, @@ -171,14 +171,14 @@ public class TestConstructorParameterTypeAnnotations { @ExpectedGetParameterAnnotations("[[]]") @ExpectedParameterTypeAnnotations({ - "@TestConstructorParameterTypeAnnotations$MarkerTypeAnnotation(1)"}) + "@TestConstructorParameterTypeAnnotations.MarkerTypeAnnotation(1)"}) public static class StaticNestedClass1 { public StaticNestedClass1(@MarkerTypeAnnotation(1) int parameter) {} } @ExpectedGetParameterAnnotations("[[], []]") @ExpectedParameterTypeAnnotations({ - "@TestConstructorParameterTypeAnnotations$MarkerTypeAnnotation(2)", + "@TestConstructorParameterTypeAnnotations.MarkerTypeAnnotation(2)", "null"}) public static class StaticNestedClass2 { public StaticNestedClass2(@MarkerTypeAnnotation(2) int parameter1, @@ -187,7 +187,7 @@ public class TestConstructorParameterTypeAnnotations { @ExpectedGetParameterAnnotations("[[], []]") @ExpectedParameterTypeAnnotations({ - "@TestConstructorParameterTypeAnnotations$MarkerTypeAnnotation(3)", + "@TestConstructorParameterTypeAnnotations.MarkerTypeAnnotation(3)", "null"}) public static class StaticNestedClass3 { public <P> StaticNestedClass3(@MarkerTypeAnnotation(3) P parameter1, @@ -196,7 +196,7 @@ public class TestConstructorParameterTypeAnnotations { @ExpectedGetParameterAnnotations("[[], []]") @ExpectedParameterTypeAnnotations({ - "@TestConstructorParameterTypeAnnotations$MarkerTypeAnnotation(4)", + "@TestConstructorParameterTypeAnnotations.MarkerTypeAnnotation(4)", "null"}) public static class StaticNestedClass4 { public <P, Q> StaticNestedClass4(@MarkerTypeAnnotation(4) P parameter1, diff --git a/test/jdk/java/lang/annotation/typeAnnotations/TestObjectMethods.java b/test/jdk/java/lang/annotation/typeAnnotations/TestObjectMethods.java index dea8f42db6a2e37b6d92b97e6b25767910da8f7b..8349d48af72460ed3b38d981eb67e04ad4545f83 100644 --- a/test/jdk/java/lang/annotation/typeAnnotations/TestObjectMethods.java +++ b/test/jdk/java/lang/annotation/typeAnnotations/TestObjectMethods.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -177,7 +177,7 @@ public class TestObjectMethods { } } - private static final Pattern annotationRegex = Pattern.compile("@TestObjectMethods\\$AnnotType\\((\\p{Digit})+\\)"); + private static final Pattern annotationRegex = Pattern.compile("@TestObjectMethods\\.AnnotType\\((\\p{Digit})+\\)"); static void testGetAnnotations(Class<?> clazz, boolean annotationsExpectedOnMethods) { System.err.println("Testing getAnnotations on methods of class " + clazz.getName()); diff --git a/test/jdk/java/lang/constant/ClassDescTest.java b/test/jdk/java/lang/constant/ClassDescTest.java index 32cf19b4fb4cf4f101344d3ba3f35810ee38ba94..81104e92c49ac47d26fa4229099f3e022d7b4dd7 100644 --- a/test/jdk/java/lang/constant/ClassDescTest.java +++ b/test/jdk/java/lang/constant/ClassDescTest.java @@ -42,7 +42,7 @@ import static org.testng.Assert.fail; /** * @test - * @bug 8215510 + * @bug 8215510 8283075 * @compile ClassDescTest.java * @run testng ClassDescTest * @summary unit tests for java.lang.constant.ClassDesc @@ -184,6 +184,19 @@ public class ClassDescTest extends SymbolicDescTest { } } + private void testArrayRankOverflow() { + ClassDesc TwoDArrayDesc = + String.class.describeConstable().get().arrayType().arrayType(); + + try { + TwoDArrayDesc.arrayType(Integer.MAX_VALUE); + fail(""); + } catch (IllegalArgumentException iae) { + // Expected + } + } + + public void testArrayClassDesc() throws ReflectiveOperationException { for (String d : basicDescs) { ClassDesc a0 = ClassDesc.ofDescriptor(d); @@ -218,6 +231,7 @@ public class ClassDescTest extends SymbolicDescTest { testBadArrayRank(ConstantDescs.CD_int); testBadArrayRank(ConstantDescs.CD_String); testBadArrayRank(ClassDesc.of("Bar")); + testArrayRankOverflow(); } } diff --git a/test/jdk/java/lang/instrument/GetObjectSizeIntrinsicsTest.java b/test/jdk/java/lang/instrument/GetObjectSizeIntrinsicsTest.java index 1417eb427a00d3dd3235f3c29a64311b3d247da4..a4fdab2ec4709fe58e444445a671338d2f115108 100644 --- a/test/jdk/java/lang/instrument/GetObjectSizeIntrinsicsTest.java +++ b/test/jdk/java/lang/instrument/GetObjectSizeIntrinsicsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Red Hat, Inc. All rights reserved. + * Copyright (c) 2020, 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 @@ -264,6 +264,36 @@ * -javaagent:basicAgent.jar GetObjectSizeIntrinsicsTest GetObjectSizeIntrinsicsTest */ +/* + * @test + * @summary Test for fInst.getObjectSize with large arrays + * @library /test/lib + * @requires vm.bits == 64 + * @requires vm.debug + * @requires os.maxMemory >= 10G + * + * @build sun.hotspot.WhiteBox + * @run build GetObjectSizeIntrinsicsTest + * @run shell MakeJAR.sh basicAgent + * + * @run driver jdk.test.lib.helpers.ClassFileInstaller sun.hotspot.WhiteBox + * + * @run main/othervm -Xmx8g + * -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xint + * -javaagent:basicAgent.jar GetObjectSizeIntrinsicsTest GetObjectSizeIntrinsicsTest large + * + * @run main/othervm -Xmx8g + * -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch -XX:TieredStopAtLevel=1 + * -javaagent:basicAgent.jar GetObjectSizeIntrinsicsTest GetObjectSizeIntrinsicsTest large + * + * @run main/othervm -Xmx8g + * -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch -XX:-TieredCompilation + * -javaagent:basicAgent.jar GetObjectSizeIntrinsicsTest GetObjectSizeIntrinsicsTest large + */ + import java.util.*; import jdk.test.lib.Platform; @@ -271,18 +301,27 @@ import sun.hotspot.WhiteBox; public class GetObjectSizeIntrinsicsTest extends ASimpleInstrumentationTestCase { - static final Boolean compressedOops = WhiteBox.getWhiteBox().getBooleanVMFlag("UseCompressedOops"); - static final int REF_SIZE = (compressedOops == null || compressedOops == true) ? 4 : 8; + static final Boolean COMPRESSED_OOPS = WhiteBox.getWhiteBox().getBooleanVMFlag("UseCompressedOops"); + static final long REF_SIZE = (COMPRESSED_OOPS == null || COMPRESSED_OOPS == true) ? 4 : 8; static final Long align = WhiteBox.getWhiteBox().getIntxVMFlag("ObjectAlignmentInBytes"); static final int OBJ_ALIGN = (align == null ? 8 : align.intValue()); - public GetObjectSizeIntrinsicsTest(String name) { + static final int SMALL_ARRAY_SIZE = 1024; + + // These should overflow 4G size boundary + static final int LARGE_INT_ARRAY_SIZE = 1024*1024*1024 + 1024; + static final int LARGE_OBJ_ARRAY_SIZE = (4096/(int)REF_SIZE)*1024*1024 + 1024; + + final String mode; + + public GetObjectSizeIntrinsicsTest(String name, String mode) { super(name); + this.mode = mode; } public static void main(String[] args)throws Throwable { - new GetObjectSizeIntrinsicsTest(args[0]).runTest(); + new GetObjectSizeIntrinsicsTest(args[0], (args.length >= 2 ? args[1] : "")).runTest(); } public static final int ITERS = 200_000; @@ -312,30 +351,35 @@ public class GetObjectSizeIntrinsicsTest extends ASimpleInstrumentationTestCase testSize_localObject(); testSize_fieldObject(); - testSize_newSmallByteArray(); - testSize_localSmallByteArray(); - testSize_fieldSmallByteArray(); + testSize_newSmallIntArray(); + testSize_localSmallIntArray(); + testSize_fieldSmallIntArray(); testSize_newSmallObjArray(); testSize_localSmallObjArray(); testSize_fieldSmallObjArray(); + if (mode.equals("large")) { + testSize_localLargeIntArray(); + testSize_localLargeObjArray(); + } + testNulls(); } - private static int roundUp(int v, int a) { + private static long roundUp(long v, long a) { return (v + a - 1) / a * a; } private void testSize_newObject() { - int expected = roundUp(Platform.is64bit() ? 16 : 8, OBJ_ALIGN); + long expected = roundUp(Platform.is64bit() ? 16 : 8, OBJ_ALIGN); for (int c = 0; c < ITERS; c++) { assertEquals(expected, fInst.getObjectSize(new Object())); } } private void testSize_localObject() { - int expected = roundUp(Platform.is64bit() ? 16 : 8, OBJ_ALIGN); + long expected = roundUp(Platform.is64bit() ? 16 : 8, OBJ_ALIGN); Object o = new Object(); for (int c = 0; c < ITERS; c++) { assertEquals(expected, fInst.getObjectSize(o)); @@ -345,60 +389,76 @@ public class GetObjectSizeIntrinsicsTest extends ASimpleInstrumentationTestCase static Object staticO = new Object(); private void testSize_fieldObject() { - int expected = roundUp(Platform.is64bit() ? 16 : 8, OBJ_ALIGN); + long expected = roundUp(Platform.is64bit() ? 16 : 8, OBJ_ALIGN); for (int c = 0; c < ITERS; c++) { assertEquals(expected, fInst.getObjectSize(staticO)); } } - private void testSize_newSmallByteArray() { - int expected = roundUp(1024 + 16, OBJ_ALIGN); + private void testSize_newSmallIntArray() { + long expected = roundUp(4L*SMALL_ARRAY_SIZE + 16, OBJ_ALIGN); for (int c = 0; c < ITERS; c++) { - assertEquals(expected, fInst.getObjectSize(new byte[1024])); + assertEquals(expected, fInst.getObjectSize(new int[SMALL_ARRAY_SIZE])); } } - private void testSize_localSmallByteArray() { - byte[] arr = new byte[1024]; - int expected = roundUp(arr.length + 16, OBJ_ALIGN); + private void testSize_localSmallIntArray() { + int[] arr = new int[SMALL_ARRAY_SIZE]; + long expected = roundUp(4L*SMALL_ARRAY_SIZE + 16, OBJ_ALIGN); for (int c = 0; c < ITERS; c++) { assertEquals(expected, fInst.getObjectSize(arr)); } } - static byte[] smallArr = new byte[1024]; + static int[] smallArr = new int[SMALL_ARRAY_SIZE]; - private void testSize_fieldSmallByteArray() { - int expected = roundUp(smallArr.length + 16, OBJ_ALIGN); + private void testSize_fieldSmallIntArray() { + long expected = roundUp(4L*SMALL_ARRAY_SIZE + 16, OBJ_ALIGN); for (int c = 0; c < ITERS; c++) { assertEquals(expected, fInst.getObjectSize(smallArr)); } } private void testSize_newSmallObjArray() { - int expected = roundUp(1024*REF_SIZE + 16, OBJ_ALIGN); + long expected = roundUp(REF_SIZE*SMALL_ARRAY_SIZE + 16, OBJ_ALIGN); for (int c = 0; c < ITERS; c++) { - assertEquals(expected, fInst.getObjectSize(new Object[1024])); + assertEquals(expected, fInst.getObjectSize(new Object[SMALL_ARRAY_SIZE])); } } private void testSize_localSmallObjArray() { - Object[] arr = new Object[1024]; - int expected = roundUp(arr.length*REF_SIZE + 16, OBJ_ALIGN); + Object[] arr = new Object[SMALL_ARRAY_SIZE]; + long expected = roundUp(REF_SIZE*SMALL_ARRAY_SIZE + 16, OBJ_ALIGN); for (int c = 0; c < ITERS; c++) { assertEquals(expected, fInst.getObjectSize(arr)); } } - static Object[] smallObjArr = new Object[1024]; + static Object[] smallObjArr = new Object[SMALL_ARRAY_SIZE]; private void testSize_fieldSmallObjArray() { - int expected = roundUp(smallArr.length*REF_SIZE + 16, OBJ_ALIGN); + long expected = roundUp(REF_SIZE*SMALL_ARRAY_SIZE + 16, OBJ_ALIGN); for (int c = 0; c < ITERS; c++) { assertEquals(expected, fInst.getObjectSize(smallObjArr)); } } + private void testSize_localLargeIntArray() { + int[] arr = new int[LARGE_INT_ARRAY_SIZE]; + long expected = roundUp(4L*LARGE_INT_ARRAY_SIZE + 16, OBJ_ALIGN); + for (int c = 0; c < ITERS; c++) { + assertEquals(expected, fInst.getObjectSize(arr)); + } + } + + private void testSize_localLargeObjArray() { + Object[] arr = new Object[LARGE_OBJ_ARRAY_SIZE]; + long expected = roundUp(REF_SIZE*LARGE_OBJ_ARRAY_SIZE + 16, OBJ_ALIGN); + for (int c = 0; c < ITERS; c++) { + assertEquals(expected, fInst.getObjectSize(arr)); + } + } + private void testNulls() { for (int c = 0; c < ITERS; c++) { try { diff --git a/test/jdk/java/lang/instrument/RetransformWithMethodParametersTest.java b/test/jdk/java/lang/instrument/RetransformWithMethodParametersTest.java new file mode 100644 index 0000000000000000000000000000000000000000..74be14f33cf40ef463c1882bddcc632ed3049d91 --- /dev/null +++ b/test/jdk/java/lang/instrument/RetransformWithMethodParametersTest.java @@ -0,0 +1,256 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8240908 + * + * @library /test/lib + * @run compile -g -parameters RetransformWithMethodParametersTest.java + * @run shell MakeJAR.sh retransformAgent + * + * @run main/othervm -javaagent:retransformAgent.jar RetransformWithMethodParametersTest + */ + +import java.io.File; +import java.io.FileOutputStream; +import java.lang.instrument.ClassFileTransformer; +import java.lang.reflect.Executable; +import java.lang.reflect.Parameter; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.security.ProtectionDomain; +import java.util.Arrays; + +import jdk.test.lib.JDKToolLauncher; +import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.util.ClassTransformer; + +/* + * The test verifies Instrumentation.retransformClasses() (and JVMTI function RetransformClasses) + * correctly handles MethodParameter attribute: + * 1) classfile bytes passed to transformers (and JVMTI ClassFileLoadHook event callback) contain the attribute; + * 2) the attribute is updated if new version has the attribute with different values; + * 3) the attribute is removed if new version doesn't contain the attribute. + */ + +// See ClassTransformer.transform(int) comment for @1 tag explanations. +class MethodParametersTarget { + // The class contains the only method, so we don't have issue with method sorting + // and ClassFileReconstituter should restore the same bytes as original classbytes. + // This method should be ctor, otherwise default ctor will be implicitly declared. + public MethodParametersTarget( + int intParam1, String stringParam1 // @1 commentout + // @1 uncomment int intParam2, String stringParam2 + ) + { + // @1 uncomment System.out.println(stringParam2); // change CP + } +} + +public class RetransformWithMethodParametersTest extends ATransformerManagementTestCase { + + public static void main (String[] args) throws Throwable { + ATestCaseScaffold test = new RetransformWithMethodParametersTest(); + test.runTest(); + } + + private String targetClassName = "MethodParametersTarget"; + private String classFileName = targetClassName + ".class"; + private String sourceFileName = "RetransformWithMethodParametersTest.java"; + private Class targetClass; + private byte[] originalClassBytes; + + private byte[] seenClassBytes; + private byte[] newClassBytes; + + public RetransformWithMethodParametersTest() throws Throwable { + super("RetransformWithMethodParametersTest"); + + File origClassFile = new File(System.getProperty("test.classes", "."), classFileName); + log("Reading test class from " + origClassFile); + originalClassBytes = Files.readAllBytes(origClassFile.toPath()); + log("Read " + originalClassBytes.length + " bytes."); + } + + private void log(Object o) { + System.out.println(String.valueOf(o)); + } + + private Parameter[] getTargetMethodParameters() throws ClassNotFoundException { + Class cls = Class.forName(targetClassName); + // the class contains 1 method (ctor) + Executable method = cls.getDeclaredConstructors()[0]; + Parameter[] params = method.getParameters(); + log("Params of " + method.getName() + " method (" + params.length + "):"); + for (int i = 0; i < params.length; i++) { + log(" " + i + ": " + params[i].getName() + + " (" + (params[i].isNamePresent() ? "present" : "absent") + ")"); + } + return params; + } + + // Verifies MethodParameters attribute is present and contains the expected values. + private void verifyPresentMethodParams(String... expectedNames) throws Throwable { + Parameter[] params = getTargetMethodParameters(); + assertEquals(expectedNames.length, params.length); + for (int i = 0; i < params.length; i++) { + assertTrue(params[i].isNamePresent()); + assertEquals(expectedNames[i], params[i].getName()); + } + } + + // Verifies MethodParameters attribute is absent. + private void verifyAbsentMethodParams() throws Throwable { + Parameter[] params = getTargetMethodParameters(); + for (int i = 0; i < params.length; i++) { + assertTrue(!params[i].isNamePresent()); + } + } + + // Retransforms target class using provided class bytes; + // Returns class bytes passed to the transformer. + private byte[] retransform(byte[] classBytes) throws Throwable { + seenClassBytes = null; + newClassBytes = classBytes; + fInst.retransformClasses(targetClass); + assertTrue(targetClassName + " was not seen by transform()", seenClassBytes != null); + return seenClassBytes; + } + + // Prints dissassembled class bytes. + private void printDisassembled(String description, byte[] bytes) throws Exception { + log(description + " -------------------"); + + File f = new File(classFileName); + try (FileOutputStream fos = new FileOutputStream(f)) { + fos.write(bytes); + } + JDKToolLauncher javap = JDKToolLauncher.create("javap") + .addToolArg("-verbose") + .addToolArg("-p") // Shows all classes and members. + //.addToolArg("-c") // Prints out disassembled code + //.addToolArg("-s") // Prints internal type signatures. + .addToolArg(f.toString()); + ProcessBuilder pb = new ProcessBuilder(javap.getCommand()); + OutputAnalyzer out = ProcessTools.executeProcess(pb); + out.shouldHaveExitValue(0); + try { + Files.delete(f.toPath()); + } catch (Exception ex) { + // ignore + } + out.asLines().forEach(s -> log(s)); + log("=========================================="); + } + + // Verifies class bytes are equal. + private void compareClassBytes(byte[] expected, byte[] actual) throws Exception { + + int pos = Arrays.mismatch(expected, actual); + if (pos < 0) { + log("Class bytes are identical."); + return; + } + log("Class bytes are different."); + printDisassembled("expected", expected); + printDisassembled("actual", actual); + fail(targetClassName + " did not match .class file"); + } + + protected final void doRunTest() throws Throwable { + beVerbose(); + + ClassLoader loader = getClass().getClassLoader(); + targetClass = loader.loadClass(targetClassName); + // sanity check + assertEquals(targetClassName, targetClass.getName()); + // sanity check + verifyPresentMethodParams("intParam1", "stringParam1"); + + addTransformerToManager(fInst, new Transformer(), true); + + { + log("Testcase 1: ensure ClassFileReconstituter restores MethodParameters attribute"); + + byte[] classBytes = retransform(null); + compareClassBytes(originalClassBytes, classBytes); + + log(""); + } + + { + log("Testcase 2: redefine class with changed parameter names"); + + byte[] classBytes = Files.readAllBytes(Paths.get( + ClassTransformer.fromTestSource(sourceFileName) + .transform(1, targetClassName, "-g", "-parameters"))); + retransform(classBytes); + // MethodParameters attribute should be updated. + verifyPresentMethodParams("intParam2", "stringParam2"); + + log(""); + } + + { + log("Testcase 3: redefine class with no parameter names"); + // compile without "-parameters" + byte[] classBytes = Files.readAllBytes(Paths.get( + ClassTransformer.fromTestSource(sourceFileName) + .transform(1, targetClassName, "-g"))); + retransform(classBytes); + // MethodParameters attribute should be dropped. + verifyAbsentMethodParams(); + + log(""); + } + } + + + public class Transformer implements ClassFileTransformer { + public Transformer() { + } + + public String toString() { + return Transformer.this.getClass().getName(); + } + + public byte[] transform(ClassLoader loader, String className, + Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) { + + if (className.equals(targetClassName)) { + log(this + ".transform() sees '" + className + + "' of " + classfileBuffer.length + " bytes."); + seenClassBytes = classfileBuffer; + if (newClassBytes != null) { + log(this + ".transform() sets new classbytes for '" + className + + "' of " + newClassBytes.length + " bytes."); + } + return newClassBytes; + } + + return null; + } + } +} diff --git a/test/jdk/java/lang/invoke/8022701/BogoLoader.java b/test/jdk/java/lang/invoke/8022701/BogoLoader.java index e8c579a27c84f8d52241b621694841c96b0b36af..568ff62089eba7ccd60beb67e8263dd61a0f581d 100644 --- a/test/jdk/java/lang/invoke/8022701/BogoLoader.java +++ b/test/jdk/java/lang/invoke/8022701/BogoLoader.java @@ -120,7 +120,7 @@ public class BogoLoader extends ClassLoader { if (verbose) { System.err.println("Loading classloader class " + name); } - byte[] classData = getClass(name);; + byte[] classData = getClass(name); boolean expanded = false; if (!noReplace && replaced.containsKey(name)) { if (verbose) { diff --git a/test/jdk/java/lang/invoke/MethodHandleProxies/Driver.java b/test/jdk/java/lang/invoke/MethodHandleProxies/Driver.java new file mode 100644 index 0000000000000000000000000000000000000000..6acd4fb30e1d9c444ef67a3bc36e09bb42eaf6f8 --- /dev/null +++ b/test/jdk/java/lang/invoke/MethodHandleProxies/Driver.java @@ -0,0 +1,32 @@ +/* + * 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. + */ + +/** + * @test + * @bug 8280377 + * @build m1/* m2/* Unnamed + * @run testng/othervm m1/p1.Main + * @run testng/othervm Unnamed + * @summary Test MethodHandleProxies::asInterfaceInstance with a default + * method with varargs + */ diff --git a/test/jdk/java/lang/invoke/MethodHandlesProxiesTest.java b/test/jdk/java/lang/invoke/MethodHandleProxies/MethodHandlesProxiesTest.java similarity index 100% rename from test/jdk/java/lang/invoke/MethodHandlesProxiesTest.java rename to test/jdk/java/lang/invoke/MethodHandleProxies/MethodHandlesProxiesTest.java diff --git a/test/jdk/java/lang/invoke/MethodHandleProxies/Unnamed.java b/test/jdk/java/lang/invoke/MethodHandleProxies/Unnamed.java new file mode 100644 index 0000000000000000000000000000000000000000..f42071f04275f3488efc5f2015cb2b9928a74328 --- /dev/null +++ b/test/jdk/java/lang/invoke/MethodHandleProxies/Unnamed.java @@ -0,0 +1,45 @@ +/* + * 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. + */ + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandleProxies; +import java.lang.invoke.MethodHandles; +import java.lang.reflect.Method; + +import static org.testng.Assert.*; + +/* + * Test MethodHandleProxies::asInterfaceInstance with an inaccessible interface + */ +public class Unnamed { + public static void main(String... args) throws Throwable { + MethodHandle target = MethodHandles.constant(String.class, "test"); + Class<?> intf = Class.forName("p2.TestIntf"); + Object t = MethodHandleProxies.asInterfaceInstance(intf, target); + + // verify that the caller has no access to the proxy created on an + // inaccessible interface + Method m = intf.getMethod("test", Object[].class); + assertFalse(m.canAccess(null)); + } +} diff --git a/test/jdk/java/lang/invoke/MethodHandleProxies/m1/module-info.java b/test/jdk/java/lang/invoke/MethodHandleProxies/m1/module-info.java new file mode 100644 index 0000000000000000000000000000000000000000..1bdeddce28fd6bb01ddbf7f6c71c5c13f8999585 --- /dev/null +++ b/test/jdk/java/lang/invoke/MethodHandleProxies/m1/module-info.java @@ -0,0 +1,27 @@ +/* + * 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. + */ +module m1 { + requires m2; + requires org.testng; + exports p1; +} diff --git a/test/jdk/java/lang/invoke/MethodHandleProxies/m1/p1/Main.java b/test/jdk/java/lang/invoke/MethodHandleProxies/m1/p1/Main.java new file mode 100644 index 0000000000000000000000000000000000000000..df71809996b3838ff43f753b48385893296eaabf --- /dev/null +++ b/test/jdk/java/lang/invoke/MethodHandleProxies/m1/p1/Main.java @@ -0,0 +1,80 @@ +/* + * 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. + */ + +package p1; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandleProxies; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.util.Arrays; +import java.util.stream.Collectors; + +import p2.TestIntf; + +import org.testng.annotations.Test; + +import static org.testng.Assert.*; + +public class Main { + public interface A { + default String aConcat(Object... objs) { return Arrays.deepToString(objs); } + } + + public interface B { + default String bConcat(Object[] objs) { return Arrays.deepToString(objs); } + } + + public interface C extends A, B { + String c(Object... objs); + } + + private static String concat(Object... objs) { + return Arrays.stream(objs).map(Object::toString).collect(Collectors.joining()); + } + + /* + * Test the invocation of default methods with varargs + */ + @Test + public static void testVarargsMethods() throws Throwable { + MethodHandle target = MethodHandles.lookup().findStatic(Main.class, + "concat", MethodType.methodType(String.class, Object[].class)); + C proxy = MethodHandleProxies.asInterfaceInstance(C.class, target); + + assertEquals(proxy.c("a", "b", "c"), "abc"); + assertEquals(proxy.aConcat("a", "b", "c"), "[a, b, c]"); + assertEquals(proxy.aConcat(new Object[] { "a", "b", "c" }), "[a, b, c]"); + assertEquals(proxy.bConcat(new Object[] { "a", "b", "c" }), "[a, b, c]"); + } + + /* + * Test the invocation of a default method of an accessible interface + */ + @Test + public static void modulePrivateInterface() { + MethodHandle target = MethodHandles.constant(String.class, "test"); + TestIntf t = MethodHandleProxies.asInterfaceInstance(TestIntf.class, target); + assertEquals(t.test(), "test"); + } +} diff --git a/test/jdk/java/lang/invoke/MethodHandleProxies/m2/module-info.java b/test/jdk/java/lang/invoke/MethodHandleProxies/m2/module-info.java new file mode 100644 index 0000000000000000000000000000000000000000..1015757fc9c34eb90d6ae679be62bdf36c0f7699 --- /dev/null +++ b/test/jdk/java/lang/invoke/MethodHandleProxies/m2/module-info.java @@ -0,0 +1,25 @@ +/* + * 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. + */ +module m2 { + exports p2 to m1; +} diff --git a/test/jdk/java/lang/invoke/MethodHandleProxies/m2/p2/TestIntf.java b/test/jdk/java/lang/invoke/MethodHandleProxies/m2/p2/TestIntf.java new file mode 100644 index 0000000000000000000000000000000000000000..a87d248e0c8efbae08b47cacaa5ecd2765031ed5 --- /dev/null +++ b/test/jdk/java/lang/invoke/MethodHandleProxies/m2/p2/TestIntf.java @@ -0,0 +1,27 @@ +/* + * 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. + */ +package p2; + +public interface TestIntf { + String test(); +} diff --git a/test/jdk/java/lang/invoke/MethodHandles/exeNullCallerLookup/NullCallerLookupTest.java b/test/jdk/java/lang/invoke/MethodHandles/exeNullCallerLookup/NullCallerLookupTest.java new file mode 100644 index 0000000000000000000000000000000000000000..cda0b2bc7af9dcd72cb93d9fbbde00745abd9432 --- /dev/null +++ b/test/jdk/java/lang/invoke/MethodHandles/exeNullCallerLookup/NullCallerLookupTest.java @@ -0,0 +1,69 @@ +/* + * 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. + * + */ + +/** + * @test + * @bug 8281003 + * @summary Test uses custom launcher that starts VM using JNI that verifies + * MethodHandles::lookup with null caller class throws an IllegalCallerException. + * @library /test/lib + * @requires os.family != "aix" + * @run main/native NullCallerLookupTest + */ + +// Test disabled on AIX since we cannot invoke the JVM on the primordial thread. + +import java.io.File; +import java.util.Map; +import jdk.test.lib.Platform; +import jdk.test.lib.process.OutputAnalyzer; + +import java.io.IOException; +import java.nio.file.Path; + +public class NullCallerLookupTest { + public static void main(String[] args) throws IOException { + Path launcher = Path.of(System.getProperty("test.nativepath"), "NullCallerLookupTest"); + ProcessBuilder pb = new ProcessBuilder(launcher.toString()); + Map<String, String> env = pb.environment(); + + String libDir = Platform.libDir().toString(); + String vmDir = Platform.jvmLibDir().toString(); + + // set up shared library path + String sharedLibraryPathEnvName = Platform.sharedLibraryPathVariableName(); + env.compute(sharedLibraryPathEnvName, + (k, v) -> (v == null) ? libDir : v + File.pathSeparator + libDir); + env.compute(sharedLibraryPathEnvName, + (k, v) -> (v == null) ? vmDir : v + File.pathSeparator + vmDir); + + System.out.println("Launching: " + launcher + " shared library path: " + + env.get(sharedLibraryPathEnvName)); + new OutputAnalyzer(pb.start()) + .outputTo(System.out) + .errorTo(System.err) + .shouldHaveExitValue(0); + } +} + diff --git a/test/jdk/java/lang/invoke/MethodHandles/exeNullCallerLookup/exeNullCallerLookupTest.c b/test/jdk/java/lang/invoke/MethodHandles/exeNullCallerLookup/exeNullCallerLookupTest.c new file mode 100644 index 0000000000000000000000000000000000000000..3abe15ce96c701953785e3ffe8926b8c7507ba36 --- /dev/null +++ b/test/jdk/java/lang/invoke/MethodHandles/exeNullCallerLookup/exeNullCallerLookupTest.c @@ -0,0 +1,76 @@ +/* + * 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 <stdio.h> +#include <stdlib.h> + +#include "jni.h" +#include "assert.h" + +static jclass class_IllegalCallerException; + +int checkAndClearIllegalCallerExceptionThrown(JNIEnv *env) { + jthrowable t = (*env)->ExceptionOccurred(env); + if ((*env)->IsInstanceOf(env, t, class_IllegalCallerException) == JNI_TRUE) { + (*env)->ExceptionClear(env); + return JNI_TRUE; + } + return JNI_FALSE; +} + +int main(int argc, char** args) { + JavaVM *jvm; + JNIEnv *env; + JavaVMInitArgs vm_args; + JavaVMOption options[1]; + jint rc; + + + vm_args.version = JNI_VERSION_1_2; + vm_args.nOptions = 0; + vm_args.options = options; + + if ((rc = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args)) != JNI_OK) { + printf("ERROR: cannot create VM.\n"); + exit(-1); + } + class_IllegalCallerException = (*env)->FindClass(env, "java/lang/IllegalCallerException"); + assert (class_IllegalCallerException != NULL); + + // call MethodHandles.lookup() + jclass methodHandlesClass = (*env)->FindClass(env, "java/lang/invoke/MethodHandles"); + assert(methodHandlesClass != NULL); + jmethodID mid_MethodHandles_lookup = (*env)->GetStaticMethodID(env, methodHandlesClass, "lookup", "()Ljava/lang/invoke/MethodHandles$Lookup;" ); + assert(mid_MethodHandles_lookup != NULL); + jobject l = (*env)->CallStaticObjectMethod(env, methodHandlesClass, mid_MethodHandles_lookup ); + if ((rc = checkAndClearIllegalCallerExceptionThrown(env)) != JNI_TRUE) { + printf("ERROR: Didn't get the expected IllegalCallerException.\n"); + exit(-1); + } + + printf("Expected IllegalCallerException was thrown\n"); + + (*jvm)->DestroyJavaVM(jvm); + return 0; +} + diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestExact.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestExact.java index 6c14c885a2410e33b9b94f185365e190b4361faa..bd1d1b58b6f3f264c78f6ab1bf9add838adb8cdc 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestExact.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestExact.java @@ -47,6 +47,7 @@ */ import jdk.incubator.foreign.MemoryHandles; +import jdk.incubator.foreign.MemoryLayout; import jdk.incubator.foreign.MemorySegment; import jdk.incubator.foreign.ResourceScope; import jdk.internal.access.foreign.MemorySegmentProxy; @@ -170,7 +171,7 @@ public class VarHandleTestExact { @Test(dataProvider = "dataSetMemorySegment") public void testExactSegmentSet(Class<?> carrier, Object testValue, SetSegmentX setter) { - VarHandle vh = MemoryHandles.varHandle(carrier, ByteOrder.nativeOrder()); + VarHandle vh = MemoryHandles.varHandle(MemoryLayout.valueLayout(carrier, ByteOrder.nativeOrder())); try (ResourceScope scope = ResourceScope.newConfinedScope()) { MemorySegment seg = MemorySegment.allocateNative(8, scope); doTest(vh, diff --git a/test/jdk/java/lang/invoke/accessProtectedSuper/BogoLoader.java b/test/jdk/java/lang/invoke/accessProtectedSuper/BogoLoader.java index a129ea254a4d8193fd5b2b3921f2632e795e8ca5..b4d19fe8a0588635ae6540de77f15eb3156300aa 100644 --- a/test/jdk/java/lang/invoke/accessProtectedSuper/BogoLoader.java +++ b/test/jdk/java/lang/invoke/accessProtectedSuper/BogoLoader.java @@ -121,7 +121,7 @@ public class BogoLoader extends ClassLoader { if (verbose) { System.err.println("Loading classloader class " + name); } - byte[] classData = getClass(name);; + byte[] classData = getClass(name); boolean expanded = false; if (!noReplace && replaced.containsKey(name)) { if (verbose) { diff --git a/test/jdk/java/lang/management/RuntimeMXBean/GetSystemProperties.java b/test/jdk/java/lang/management/RuntimeMXBean/GetSystemProperties.java index 5f6923526ab6810e7839ccb4360f0208418a652f..ac6de886b25b18810087078ac803d81e3f1d7f8a 100644 --- a/test/jdk/java/lang/management/RuntimeMXBean/GetSystemProperties.java +++ b/test/jdk/java/lang/management/RuntimeMXBean/GetSystemProperties.java @@ -40,7 +40,7 @@ public class GetSystemProperties { // system properties to be omitted private static final String KEY3 = "test.property.key3"; - private static final Long VALUE3 = new Long(0);; + private static final Long VALUE3 = new Long(0); private static final Object KEY4 = new Object(); private static final String VALUE4 = "test.property.value4"; diff --git a/test/jdk/java/lang/management/ThreadMXBean/ThreadLists.java b/test/jdk/java/lang/management/ThreadMXBean/ThreadLists.java index 433a3f54c0d158328562f09dc3280e388d502de6..cadfff1097cbc9dd7bcbefad9542dc6c12e04b78 100644 --- a/test/jdk/java/lang/management/ThreadMXBean/ThreadLists.java +++ b/test/jdk/java/lang/management/ThreadMXBean/ThreadLists.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 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 @@ -23,9 +23,11 @@ /* * @test - * @bug 5047639 + * @bug 5047639 8132785 * @summary Check that the "java-level" APIs provide a consistent view of * the thread list + * @comment Must run in othervm mode to avoid interference from other tests. + * @run main/othervm ThreadLists */ import java.lang.management.ManagementFactory; import java.lang.management.ThreadMXBean; @@ -50,6 +52,19 @@ public class ThreadLists { // get the thread count int activeCount = top.activeCount(); + // Now enumerate to see if we find any extras yet. + // Ensure the array is big enough for a few extras. + Thread[] threads = new Thread[activeCount * 2]; + int newCount = top.enumerate(threads); + if (newCount != activeCount) { + System.out.println("Found different threads after enumeration:"); + } else { + System.out.println("Initial set of enumerated threads:"); + } + for (int i = 0; i < newCount; i++) { + System.out.println(" - Thread: " + threads[i].getName()); + } + Map<Thread, StackTraceElement[]> stackTraces = Thread.getAllStackTraces(); ThreadMXBean threadBean = ManagementFactory.getThreadMXBean(); @@ -68,6 +83,11 @@ public class ThreadLists { if (activeCount != threadIds.length) failed = true; if (failed) { + System.out.println("Set of stack-traced threads:"); + for (Thread t : stackTraces.keySet()) { + System.out.println(" - Thread: " + + (t != null ? t.getName() : "null!")); + } throw new RuntimeException("inconsistent results"); } } diff --git a/test/jdk/java/lang/module/ClassFileVersionsTest.java b/test/jdk/java/lang/module/ClassFileVersionsTest.java index 6e9b19a09bca0957bb15ce86b4d39b30508398a7..9d723662b24ee00307af9f38b83d4df26a4218b6 100644 --- a/test/jdk/java/lang/module/ClassFileVersionsTest.java +++ b/test/jdk/java/lang/module/ClassFileVersionsTest.java @@ -43,74 +43,65 @@ import org.testng.annotations.Test; import static org.testng.Assert.*; public class ClassFileVersionsTest { + private static final int FEATURE; + static { + FEATURE = Runtime.version().feature(); + assert FEATURE >= 10; + } // major, minor, modifiers for requires java.base @DataProvider(name = "supported") public Object[][] supported() { - return new Object[][]{ - { 53, 0, Set.of() }, // JDK 9 - { 53, 0, Set.of(STATIC) }, - { 53, 0, Set.of(TRANSITIVE) }, - { 53, 0, Set.of(STATIC, TRANSITIVE) }, - - { 54, 0, Set.of() }, // JDK 10 - { 55, 0, Set.of() }, // JDK 11 - { 56, 0, Set.of() }, // JDK 12 - { 57, 0, Set.of() }, // JDK 13 - { 58, 0, Set.of() }, // JDK 14 - { 59, 0, Set.of() }, // JDK 15 - { 60, 0, Set.of() }, // JDK 16 - { 61, 0, Set.of() }, // JDK 17 - { 62, 0, Set.of() }, // JDK 18 - }; + /* + * There are four test cases for JDK 9 and then one test case + * for each subsequent JDK version from JDK 10 to the current + * feature release for a total of (4 + (FEATURE - 9) ) => + * (feature - 5) rows. + */ + Object[][] result = new Object[(FEATURE - 5)][]; + + // Class file version of JDK 9 is 53.0 + result[0] = new Object[]{ 53, 0, Set.of()}; + result[1] = new Object[]{ 53, 0, Set.of(STATIC) }; + result[2] = new Object[]{ 53, 0, Set.of(TRANSITIVE) }; + result[3] = new Object[]{ 53, 0, Set.of(STATIC, TRANSITIVE) }; + + // Major class file version of JDK N is 44 + n. Create rows + // for JDK 10 through FEATURE. + for (int i = 4; i < (FEATURE - 5) ; i++) { + result[i] = new Object[]{i + 50, 0, Set.of()}; + } + + return result; } // major, minor, modifiers for requires java.base @DataProvider(name = "unsupported") public Object[][] unsupported() { - return new Object[][]{ - { 50, 0, Set.of()}, // JDK 6 - { 51, 0, Set.of()}, // JDK 7 - { 52, 0, Set.of()}, // JDK 8 - - { 54, 0, Set.of(STATIC) }, // JDK 10 - { 54, 0, Set.of(TRANSITIVE) }, - { 54, 0, Set.of(STATIC, TRANSITIVE) }, - - { 55, 0, Set.of(STATIC) }, // JDK 11 - { 55, 0, Set.of(TRANSITIVE) }, - { 55, 0, Set.of(STATIC, TRANSITIVE) }, - - { 56, 0, Set.of(STATIC) }, // JDK 12 - { 56, 0, Set.of(TRANSITIVE) }, - { 56, 0, Set.of(STATIC, TRANSITIVE) }, - - { 57, 0, Set.of(STATIC) }, // JDK 13 - { 57, 0, Set.of(TRANSITIVE) }, - { 57, 0, Set.of(STATIC, TRANSITIVE) }, - - { 58, 0, Set.of(STATIC) }, // JDK 14 - { 58, 0, Set.of(TRANSITIVE) }, - { 58, 0, Set.of(STATIC, TRANSITIVE) }, - - { 59, 0, Set.of(STATIC) }, // JDK 15 - { 59, 0, Set.of(TRANSITIVE) }, - { 59, 0, Set.of(STATIC, TRANSITIVE) }, - - { 60, 0, Set.of(STATIC) }, // JDK 16 - { 60, 0, Set.of(TRANSITIVE) }, - { 60, 0, Set.of(STATIC, TRANSITIVE) }, - - { 61, 0, Set.of(STATIC) }, // JDK 17 - { 61, 0, Set.of(TRANSITIVE) }, - { 61, 0, Set.of(STATIC, TRANSITIVE) }, - - { 62, 0, Set.of(STATIC) }, // JDK 18 - { 62, 0, Set.of(TRANSITIVE) }, - { 62, 0, Set.of(STATIC, TRANSITIVE) }, - - { 63, 0, Set.of()}, // JDK 19 - }; + /* + * There are three test cases for releases prior to JDK 9, + * three test cases for each JDK version from JDK 10 to the + * current feature release, plus one addition test case for + * the next release for a total of (3 + (FEATURE - 9) * 3 + 1) + * rows. + */ + int unsupportedCount = 3 + (FEATURE - 9)*3 + 1; + Object[][] result = new Object[unsupportedCount][]; + + result[0] = new Object[]{50, 0, Set.of()}; // JDK 6 + result[1] = new Object[]{51, 0, Set.of()}; // JDK 7 + result[2] = new Object[]{52, 0, Set.of()}; // JDK 8 + + for (int i = 10; i <= FEATURE ; i++) { + int base = 3 + (i-10)*3; + // Major class file version of JDK N is 44+n + result[base] = new Object[]{i + 44, 0, Set.of(STATIC)}; + result[base + 1] = new Object[]{i + 44, 0, Set.of(TRANSITIVE)}; + result[base + 2] = new Object[]{i + 44, 0, Set.of(STATIC, TRANSITIVE)}; + } + + result[unsupportedCount - 1] = new Object[]{FEATURE+1+44, 0, Set.of()}; + return result; } @Test(dataProvider = "supported") diff --git a/test/jdk/java/lang/module/customfs/ModulesInCustomFileSystem.java b/test/jdk/java/lang/module/customfs/ModulesInCustomFileSystem.java index 48c95e493c2cf5f24192800cbc98b61f4dfe7f87..6861c7588df3bb46a86d264f61e1f8147728509a 100644 --- a/test/jdk/java/lang/module/customfs/ModulesInCustomFileSystem.java +++ b/test/jdk/java/lang/module/customfs/ModulesInCustomFileSystem.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -23,6 +23,7 @@ /** * @test + * @bug 8178380 8282444 * @modules jdk.zipfs * @library /test/lib * @build ModulesInCustomFileSystem m1/* m2/* diff --git a/test/jdk/java/lang/module/customfs/m1/p/Main.java b/test/jdk/java/lang/module/customfs/m1/p/Main.java index 65e45a8dac9032ed95d9d57746c8fb5f84099ef3..b8c31374280591a95476335439334c7fd2ef496c 100644 --- a/test/jdk/java/lang/module/customfs/m1/p/Main.java +++ b/test/jdk/java/lang/module/customfs/m1/p/Main.java @@ -25,6 +25,6 @@ package p; public class Main { public static void main(String[] args) { - q.Hello.hello(); + q.r.Hello.hello(); } } diff --git a/test/jdk/java/lang/module/customfs/m2/module-info.java b/test/jdk/java/lang/module/customfs/m2/module-info.java index 72b35d933cf8cfb88fc1e8acae477e9ab80dcb05..92560aa20f13335c4fd51f7509e224fab627f62e 100644 --- a/test/jdk/java/lang/module/customfs/m2/module-info.java +++ b/test/jdk/java/lang/module/customfs/m2/module-info.java @@ -22,5 +22,5 @@ */ module m2 { - exports q; + exports q.r; } diff --git a/test/jdk/java/lang/module/customfs/m2/q/Hello.java b/test/jdk/java/lang/module/customfs/m2/q/r/Hello.java similarity index 98% rename from test/jdk/java/lang/module/customfs/m2/q/Hello.java rename to test/jdk/java/lang/module/customfs/m2/q/r/Hello.java index 5f912cd51ad208526d780ede9b96db1890a9e00a..1e6ce808a567a0e7b99be0666f99ac1a28e5a09a 100644 --- a/test/jdk/java/lang/module/customfs/m2/q/Hello.java +++ b/test/jdk/java/lang/module/customfs/m2/q/r/Hello.java @@ -21,7 +21,7 @@ * questions. */ -package q; +package q.r; public class Hello { public static void hello() { diff --git a/test/jdk/java/lang/reflect/Field/NegativeTest.java b/test/jdk/java/lang/reflect/Field/NegativeTest.java new file mode 100644 index 0000000000000000000000000000000000000000..c8a08beadb455fab3938201af9d8ed7e35a645cb --- /dev/null +++ b/test/jdk/java/lang/reflect/Field/NegativeTest.java @@ -0,0 +1,582 @@ +/* + * 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. + */ + +/** + * @test + * @bug 8277451 + * @run testng/othervm -Djdk.reflect.useDirectMethodHandle=true NegativeTest + * @run testng/othervm -Djdk.reflect.useDirectMethodHandle=false NegativeTest + * @summary Test exception thrown due to bad receiver and bad value on + * Field with and without setAccessible(true) + */ + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; + +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import static org.testng.Assert.*; + +public class NegativeTest { + static class Fields { + public static int si; + public static char sc; + public static byte sb; + public static short ss; + public static long sl; + public static double sd; + public static float sf; + public static boolean sz; + public static String so; + + public static final int sfi = 10; + public static final char sfc = 'a'; + public static final byte sfb = 1; + public static final short sfs = 2; + public static final long sfl = 1000L; + public static final double sfd = 1.0; + public static final float sff = 2.0f; + public static final boolean sfz = true; + public static final String sfo = "abc"; + + public int i; + public char c; + public byte b; + public short s; + public long l; + public double d; + public float f; + public boolean z; + public String o; + + public final int fi = 10; + public final char fc = 'a'; + public final byte fb = 1; + public final short fs = 2; + public final long fl = 1000L; + public final double fd = 1.0; + public final float ff = 2.0f; + public final boolean fz = true; + public final String fo = "abc"; + } + + static final Field i_field = field("i", false); + static final Field c_field = field("c", false); + static final Field b_field = field("b", false); + static final Field s_field = field("s", false); + static final Field l_field = field("l", false); + static final Field d_field = field("d", false); + static final Field f_field = field("f", false); + static final Field z_field = field("z", false); + static final Field o_field = field("o", false); + static final Field fi_field = field("fi", false); + static final Field fc_field = field("fc", false); + static final Field fb_field = field("fb", false); + static final Field fs_field = field("fs", false); + static final Field fl_field = field("fl", false); + static final Field fd_field = field("fd", false); + static final Field ff_field = field("ff", false); + static final Field fz_field = field("fz", false); + static final Field fo_field = field("fo", false); + + static final Field override_i_field = field("i", true); + static final Field override_c_field = field("c", true); + static final Field override_b_field = field("b", true); + static final Field override_s_field = field("s", true); + static final Field override_l_field = field("l", true); + static final Field override_d_field = field("d", true); + static final Field override_f_field = field("f", true); + static final Field override_z_field = field("z", true); + static final Field override_o_field = field("o", true); + static final Field override_fi_field = field("fi", true); + static final Field override_fc_field = field("fc", true); + static final Field override_fb_field = field("fb", true); + static final Field override_fs_field = field("fs", true); + static final Field override_fl_field = field("fl", true); + static final Field override_fd_field = field("fd", true); + static final Field override_ff_field = field("ff", true); + static final Field override_fz_field = field("fz", true); + static final Field override_fo_field = field("fo", true); + + static final Field si_field = field("si", false); + static final Field sc_field = field("sc", false); + static final Field sb_field = field("sb", false); + static final Field ss_field = field("ss", false); + static final Field sl_field = field("sl", false); + static final Field sd_field = field("sd", false); + static final Field sf_field = field("sf", false); + static final Field sz_field = field("sz", false); + static final Field so_field = field("so", false); + static final Field sfi_field = field("sfi", false); + static final Field sfc_field = field("sfc", false); + static final Field sfb_field = field("sfb", false); + static final Field sfs_field = field("sfs", false); + static final Field sfl_field = field("sfl", false); + static final Field sfd_field = field("sfd", false); + static final Field sff_field = field("sff", false); + static final Field sfz_field = field("sfz", false); + static final Field sfo_field = field("sfo", false); + + static final Field override_si_field = field("si", true); + static final Field override_sc_field = field("sc", true); + static final Field override_sb_field = field("sb", true); + static final Field override_ss_field = field("ss", true); + static final Field override_sl_field = field("sl", true); + static final Field override_sd_field = field("sd", true); + static final Field override_sf_field = field("sf", true); + static final Field override_sz_field = field("sz", true); + static final Field override_so_field = field("so", true); + static final Field override_sfi_field = field("sfi", true); + static final Field override_sfc_field = field("sfc", true); + static final Field override_sfb_field = field("sfb", true); + static final Field override_sfs_field = field("sfs", true); + static final Field override_sfl_field = field("sfl", true); + static final Field override_sfd_field = field("sfd", true); + static final Field override_sff_field = field("sff", true); + static final Field override_sfz_field = field("sfz", true); + static final Field override_sfo_field = field("sfo", true); + + private static Field field(String name, boolean suppressAccessCheck) { + try { + Field f = Fields.class.getDeclaredField(name); + if (suppressAccessCheck) { + f.setAccessible(true); + } + return f; + } catch (ReflectiveOperationException e) { + throw new RuntimeException(e); + } + } + + @DataProvider(name = "instanceFields") + private Object[][] instanceFields() { + return new Object[][]{ + new Object[]{i_field}, + new Object[]{c_field}, + new Object[]{b_field}, + new Object[]{s_field}, + new Object[]{l_field}, + new Object[]{d_field}, + new Object[]{f_field}, + new Object[]{z_field}, + new Object[]{o_field}, + new Object[]{override_i_field}, + new Object[]{override_c_field}, + new Object[]{override_b_field}, + new Object[]{override_s_field}, + new Object[]{override_l_field}, + new Object[]{override_d_field}, + new Object[]{override_f_field}, + new Object[]{override_z_field}, + new Object[]{override_o_field}, + // final instance fields + new Object[]{fi_field}, + new Object[]{fc_field}, + new Object[]{fb_field}, + new Object[]{fs_field}, + new Object[]{fl_field}, + new Object[]{fd_field}, + new Object[]{ff_field}, + new Object[]{fz_field}, + new Object[]{fo_field}, + new Object[]{override_fi_field}, + new Object[]{override_fc_field}, + new Object[]{override_fb_field}, + new Object[]{override_fs_field}, + new Object[]{override_fl_field}, + new Object[]{override_fd_field}, + new Object[]{override_ff_field}, + new Object[]{override_fz_field}, + new Object[]{override_fo_field}, + }; + } + private static Fields INSTANCE = new Fields(); + + /* + * Test Field::get on a good receiver, a bad receiver and null. + * + * IllegalArgumentException is thrown if the receiver is of + * a bad type. NullPointerException is thrown if the receiver is null. + */ + @Test(dataProvider = "instanceFields") + public void testReceiver(Field f) throws ReflectiveOperationException { + f.get(INSTANCE); // good receiver + + testBadReceiver(f); + testNullReceiver(f); + } + + /* + * IllegalArgumentException should be thrown for bad receiver type + */ + private void testBadReceiver(Field f) throws ReflectiveOperationException { + assertFalse(Modifier.isStatic(f.getModifiers())); // instance field + Object badObj = new NegativeTest(); + try { + f.get(badObj); + fail("expected IllegalArgumentException"); + } catch (IllegalArgumentException e) { + // expected + } + Class<?> fType = f.getType(); + if (fType.isPrimitive()) { + try { + switch (fType.descriptorString()) { + case "B" -> f.getByte(badObj); + case "C" -> f.getChar(badObj); + case "D" -> f.getDouble(badObj); + case "F" -> f.getFloat(badObj); + case "I" -> f.getInt(badObj); + case "J" -> f.getLong(badObj); + case "S" -> f.getShort(badObj); + case "Z" -> f.getBoolean(badObj); + } + fail("expected IllegalArgumentException"); + } catch (IllegalArgumentException e) { + // expected + } + } + } + + /* + * NullPointerException should be thrown for null receiver + */ + private void testNullReceiver(Field f) throws ReflectiveOperationException { + assertFalse(Modifier.isStatic(f.getModifiers())); // instance field + try { + f.get(null); + fail("expected NullPointerException"); + } catch (NullPointerException e) { + // expected + } + + Class<?> fType = f.getType(); + if (fType.isPrimitive()) { + try { + switch (fType.descriptorString()) { + case "B" -> f.getByte(null); + case "C" -> f.getChar(null); + case "D" -> f.getDouble(null); + case "F" -> f.getFloat(null); + case "I" -> f.getInt(null); + case "J" -> f.getLong(null); + case "S" -> f.getShort(null); + case "Z" -> f.getBoolean(null); + } + fail("expected NullPointerException"); + } catch (NullPointerException e) { + // expected + } + } + } + + @DataProvider(name = "writeableFields") + private Object[][] writeableFields() { + Fields obj = new Fields(); + return new Object[][]{ + // instance fields with and without setAccessible(true) + new Object[]{i_field, obj, Integer.valueOf(10)}, + new Object[]{c_field, obj, Character.valueOf('c')}, + new Object[]{b_field, obj, Byte.valueOf((byte)1)}, + new Object[]{s_field, obj, Short.valueOf((short)2)}, + new Object[]{l_field, obj, Long.valueOf(1000)}, + new Object[]{d_field, obj, Double.valueOf(1.2)}, + new Object[]{f_field, obj, Float.valueOf(2.5f)}, + new Object[]{z_field, obj, Boolean.valueOf(true)}, + new Object[]{o_field, obj, "good-value"}, + new Object[]{override_i_field, obj, Integer.valueOf(10)}, + new Object[]{override_c_field, obj, Character.valueOf('c')}, + new Object[]{override_b_field, obj, Byte.valueOf((byte)1)}, + new Object[]{override_s_field, obj, Short.valueOf((short)2)}, + new Object[]{override_l_field, obj, Long.valueOf(1000)}, + new Object[]{override_d_field, obj, Double.valueOf(1.2)}, + new Object[]{override_f_field, obj, Float.valueOf(2.5f)}, + new Object[]{override_z_field, obj, Boolean.valueOf(true)}, + new Object[]{override_o_field, obj, "good-value"}, + // instance final fields with setAccessible(true) + new Object[]{override_fi_field, obj, Integer.valueOf(10)}, + new Object[]{override_fc_field, obj, Character.valueOf('c')}, + new Object[]{override_fb_field, obj, Byte.valueOf((byte)1)}, + new Object[]{override_fs_field, obj, Short.valueOf((short)2)}, + new Object[]{override_fl_field, obj, Long.valueOf(1000)}, + new Object[]{override_fd_field, obj, Double.valueOf(1.2)}, + new Object[]{override_ff_field, obj, Float.valueOf(2.5f)}, + new Object[]{override_fz_field, obj, Boolean.valueOf(true)}, + new Object[]{override_fo_field, obj, "good-value"}, + // static fields with and without setAccessible(true) + new Object[]{si_field, null, Integer.valueOf(10)}, + new Object[]{sc_field, null, Character.valueOf('c')}, + new Object[]{sb_field, null, Byte.valueOf((byte)1)}, + new Object[]{ss_field, null, Short.valueOf((short)2)}, + new Object[]{sl_field, null, Long.valueOf(1000)}, + new Object[]{sd_field, null, Double.valueOf(1.2)}, + new Object[]{sf_field, null, Float.valueOf(2.5f)}, + new Object[]{sz_field, null, Boolean.valueOf(true)}, + new Object[]{so_field, null, "good-value"}, + new Object[]{override_si_field, null, Integer.valueOf(10)}, + new Object[]{override_sc_field, null, Character.valueOf('c')}, + new Object[]{override_sb_field, null, Byte.valueOf((byte)1)}, + new Object[]{override_ss_field, null, Short.valueOf((short)2)}, + new Object[]{override_sl_field, null, Long.valueOf(1000)}, + new Object[]{override_sd_field, null, Double.valueOf(1.2)}, + new Object[]{override_sf_field, null, Float.valueOf(2.5f)}, + new Object[]{override_sz_field, null, Boolean.valueOf(true)}, + new Object[]{override_so_field, null, "good-value"}, + }; + } + + /* + * Test Field::set with a good and bad value. + * Test setting to null if the field type is primitive. + * + * IllegalArgumentException is thrown if the value is of a bad type or null. + * NullPointerException is thrown if the receiver of an instance field is null. + * The receiver is checked + */ + @Test(dataProvider = "writeableFields") + public void testSetValue(Field f, Object obj, Object value) throws IllegalAccessException { + f.set(obj, value); + Class<?> fType = f.getType(); + if (fType.isPrimitive()) { + switch (fType.descriptorString()) { + case "B" -> f.setByte(obj, ((Byte) value).byteValue()); + case "C" -> f.setChar(obj, ((Character) value).charValue()); + case "D" -> f.setDouble(obj, ((Double) value).doubleValue()); + case "F" -> f.setFloat(obj, ((Float) value).floatValue()); + case "I" -> f.setInt(obj, ((Integer) value).intValue()); + case "J" -> f.setLong(obj, ((Long) value).longValue()); + case "S" -> f.setShort(obj, ((Short) value).shortValue()); + case "Z" -> f.setBoolean(obj, ((Boolean) value).booleanValue()); + } + + // test null value only if it's primitive type + try { + f.set(obj, null); + fail("expected IllegalArgumentException"); + } catch (IllegalArgumentException e) { + // expected + } + } + + Object badValue = new NegativeTest(); + try { + f.set(obj, badValue); + fail("expected IllegalArgumentException"); + } catch (IllegalArgumentException e) { + // expected + } + } + + @DataProvider(name = "readOnlyFinalFields") + private Object[][] readOnlyFinalFields() { + Object obj = INSTANCE; + return new Object[][]{ + // instance final fields + new Object[]{fi_field, obj, Integer.valueOf(10)}, + new Object[]{fc_field, obj, Character.valueOf('c')}, + new Object[]{fb_field, obj, Byte.valueOf((byte)1)}, + new Object[]{fs_field, obj, Short.valueOf((short)2)}, + new Object[]{fl_field, obj, Long.valueOf(1000)}, + new Object[]{fd_field, obj, Double.valueOf(1.2)}, + new Object[]{ff_field, obj, Float.valueOf(2.5f)}, + new Object[]{fz_field, obj, Boolean.valueOf(true)}, + new Object[]{fo_field, obj, "good-value"}, + // static final fields + new Object[]{sfi_field, null, Integer.valueOf(10)}, + new Object[]{sfc_field, null, Character.valueOf('c')}, + new Object[]{sfb_field, null, Byte.valueOf((byte)1)}, + new Object[]{sfs_field, null, Short.valueOf((short)2)}, + new Object[]{sfl_field, null, Long.valueOf(1000)}, + new Object[]{sfd_field, null, Double.valueOf(1.2)}, + new Object[]{sff_field, null, Float.valueOf(2.5f)}, + new Object[]{sfz_field, null, Boolean.valueOf(true)}, + new Object[]{sfo_field, null, "good-value"}, + new Object[]{override_sfi_field, null, Integer.valueOf(10)}, + new Object[]{override_sfc_field, null, Character.valueOf('c')}, + new Object[]{override_sfb_field, null, Byte.valueOf((byte)1)}, + new Object[]{override_sfs_field, null, Short.valueOf((short)2)}, + new Object[]{override_sfl_field, null, Long.valueOf(1000)}, + new Object[]{override_sfd_field, null, Double.valueOf(1.2)}, + new Object[]{override_sff_field, null, Float.valueOf(2.5f)}, + new Object[]{override_sfz_field, null, Boolean.valueOf(true)}, + new Object[]{override_sfo_field, null, "good-value"}, + }; + } + + /* + * Test Field::set on a read-only final field. + * IllegalAccessException is thrown regardless of whether the value + * is of a bad type or not. + */ + @Test(dataProvider = "readOnlyFinalFields") + public void testSetValueOnFinalField(Field f, Object obj, Object value) { + assertTrue(Modifier.isFinal(f.getModifiers())); + try { + f.set(obj, value); + fail("expected IllegalAccessException"); + } catch (IllegalAccessException e) { + // expected + } + + Class<?> fType = f.getType(); + if (fType.isPrimitive()) { + try { + switch (fType.descriptorString()) { + case "B" -> f.setByte(obj, ((Byte)value).byteValue()); + case "C" -> f.setChar(obj, ((Character)value).charValue()); + case "D" -> f.setDouble(obj, ((Double)value).doubleValue()); + case "F" -> f.setFloat(obj, ((Float)value).floatValue()); + case "I" -> f.setInt(obj, ((Integer)value).intValue()); + case "J" -> f.setLong(obj, ((Long)value).longValue()); + case "S" -> f.setShort(obj, ((Short)value).shortValue()); + case "Z" -> f.setBoolean(obj, ((Boolean)value).booleanValue()); + } + fail("expected IllegalAccessException"); + } catch (IllegalAccessException e) { + // expected + } + + // test null value only if it's primitive type + try { + f.set(obj, null); + fail("expected IllegalAccessException"); + } catch (IllegalAccessException e) { + // expected + } + } + + Object badValue = new NegativeTest(); + try { + f.set(obj, badValue); + fail("expected IllegalAccessException"); + } catch (IllegalAccessException e) { + // expected + } + } + + + + @DataProvider(name = "finalInstanceFields") + private Object[][] finalInstanceFields() { + return new Object[][]{ + new Object[]{fi_field, Integer.valueOf(10)}, + new Object[]{fc_field, Character.valueOf('c')}, + new Object[]{fb_field, Byte.valueOf((byte) 1)}, + new Object[]{fs_field, Short.valueOf((short) 2)}, + new Object[]{fl_field, Long.valueOf(1000)}, + new Object[]{fd_field, Double.valueOf(1.2)}, + new Object[]{ff_field, Float.valueOf(2.5f)}, + new Object[]{fz_field, Boolean.valueOf(true)}, + new Object[]{fo_field, "good-value"}, + }; + } + + /* + * Test Field::set on a final instance field with either a bad receiver + * or null. IllegalArgumentException is thrown if the receiver is of + * a bad type. NullPointerException is thrown if the receiver is null. + * The receiver is checked before the access check is performed and + * also before the value is checked. + */ + @Test(dataProvider = "finalInstanceFields") + public void testReceiverOnFinalField(Field f, Object value) { + assertTrue(Modifier.isFinal(f.getModifiers())); + Object badReceiver = new NegativeTest(); + // set the field with a bad receiver with a good value + try { + f.set(badReceiver, value); + fail("expected IllegalArgumentException"); + } catch (IllegalArgumentException e) { + // expected + } catch (IllegalAccessException e) { + throw new RuntimeException("Expected IllegalArgumentException but got: " + e.getMessage(), e); + } + + // set the field with a bad receiver with a bad value + Object badValue = new NegativeTest(); + try { + f.set(badReceiver, badValue); + fail("expected IllegalArgumentException"); + } catch (IllegalArgumentException e) { + // expected + } catch (IllegalAccessException e) { + throw new RuntimeException("Expected IllegalArgumentException but got: " + e.getMessage(), e); + } + + // set the field with a null receiver with a good value + try { + f.set(null, value); + fail("expected NullPointerException"); + } catch (NullPointerException e) { + // expected + } catch (IllegalAccessException e) { + throw new RuntimeException("Expected NullPointerException but got: " + e.getMessage(), e); + } + // set the field with a null receiver with a bad value + try { + f.set(null, badValue); + fail("expected NullPointerException"); + } catch (NullPointerException e) { + // expected + } catch (IllegalAccessException e) { + throw new RuntimeException("Expected NullPointerException but got: " + e.getMessage(), e); + } + + Class<?> fType = f.getType(); + if (fType.isPrimitive()) { + // test bad receiver + try { + switch (fType.descriptorString()) { + case "B" -> f.setByte(badReceiver, ((Byte) value).byteValue()); + case "C" -> f.setChar(badReceiver, ((Character) value).charValue()); + case "D" -> f.setDouble(badReceiver, ((Double) value).doubleValue()); + case "F" -> f.setFloat(badReceiver, ((Float) value).floatValue()); + case "I" -> f.setInt(badReceiver, ((Integer) value).intValue()); + case "J" -> f.setLong(badReceiver, ((Long) value).longValue()); + case "S" -> f.setShort(badReceiver, ((Short) value).shortValue()); + case "Z" -> f.setBoolean(badReceiver, ((Boolean) value).booleanValue()); + } + } catch (IllegalArgumentException e) { + } catch (IllegalAccessException e) { + throw new RuntimeException("Expected IllegalArgumentException but got: " + e.getMessage(), e); + } + // test null receiver + try { + switch (fType.descriptorString()) { + case "B" -> f.setByte(null, ((Byte) value).byteValue()); + case "C" -> f.setChar(null, ((Character) value).charValue()); + case "D" -> f.setDouble(null, ((Double) value).doubleValue()); + case "F" -> f.setFloat(null, ((Float) value).floatValue()); + case "I" -> f.setInt(null, ((Integer) value).intValue()); + case "J" -> f.setLong(null, ((Long) value).longValue()); + case "S" -> f.setShort(null, ((Short) value).shortValue()); + case "Z" -> f.setBoolean(null, ((Boolean) value).booleanValue()); + } + } catch (NullPointerException e) { + // expected + } catch (IllegalAccessException e) { + throw new RuntimeException("Expected NullPointerException but got: " + e.getMessage(), e); + } + } + } +} diff --git a/test/jdk/java/lang/reflect/IllegalArgumentsTest.java b/test/jdk/java/lang/reflect/IllegalArgumentsTest.java new file mode 100644 index 0000000000000000000000000000000000000000..0d699485f9103ad21711b9aeff195698c0f1c134 --- /dev/null +++ b/test/jdk/java/lang/reflect/IllegalArgumentsTest.java @@ -0,0 +1,111 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8277964 + * @summary Test IllegalArgumentException be thrown when an argument is invalid + * @run testng/othervm IllegalArgumentsTest + */ + +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import org.testng.annotations.Test; + +public class IllegalArgumentsTest { + static class T { + public T(int i) {} + + public static void m(int i) {} + + public void m1(String s) {} + } + + @Test + public void wrongArgumentType() throws ReflectiveOperationException { + for (int i = 0; i < 100_000; ++i) { + try { + Constructor<T> ctor = T.class.getConstructor(int.class); + ctor.newInstance(int.class); // wrong argument type + throw new RuntimeException("Expected IAE not thrown"); + } catch (IllegalArgumentException e) {} + } + + for (int i = 0; i < 100_000; ++i) { + try { + Method method = T.class.getMethod("m", int.class); + method.invoke(null, int.class); // wrong argument type + throw new RuntimeException("Expected IAE not thrown"); + } catch (IllegalArgumentException e) {} + } + } + + @Test + public void nullArguments() throws ReflectiveOperationException { + for (int i = 0; i < 100_000; ++i) { + try { + Constructor<T> ctor = T.class.getConstructor(int.class); + ctor.newInstance(new Object[] {null}); + throw new RuntimeException("Expected IAE not thrown"); + } catch (IllegalArgumentException e) {} + } + + for (int i = 0; i < 100_000; ++i) { + try { + Method method = T.class.getMethod("m", int.class); + method.invoke(null, new Object[] {null}); + throw new RuntimeException("Expected IAE not thrown"); + } catch (IllegalArgumentException e) {} + } + } + + @Test + public void illegalArguments() throws ReflectiveOperationException { + for (int i = 0; i < 100_000; ++i) { + try { + Constructor<T> ctor = T.class.getConstructor(int.class); + ctor.newInstance(new Object[] { 10, 20}); + throw new RuntimeException("Expected IAE not thrown"); + } catch (IllegalArgumentException e) {} + } + + for (int i = 0; i < 100_000; ++i) { + try { + Method method = T.class.getMethod("m", int.class); + method.invoke(null, new Object[] { 10, 20}); + throw new RuntimeException("Expected IAE not thrown"); + } catch (IllegalArgumentException e) {} + } + } + + @Test + public void wrongReceiver() throws ReflectiveOperationException { + for (int i = 0; i < 100_000; ++i) { + try { + Method method = T.class.getMethod("m1", String.class); + method.invoke(this, "bad receiver"); + throw new RuntimeException("Expected IAE not thrown"); + } catch (IllegalArgumentException e) {} + } + } +} diff --git a/test/jdk/java/lang/reflect/MethodHandleAccessorsTest.java b/test/jdk/java/lang/reflect/MethodHandleAccessorsTest.java index 3b702edc5f37bab3ca124046c1d5608e64f0530b..1636bd704451b97757925534263407bf3b3c525e 100644 --- a/test/jdk/java/lang/reflect/MethodHandleAccessorsTest.java +++ b/test/jdk/java/lang/reflect/MethodHandleAccessorsTest.java @@ -115,6 +115,8 @@ public class MethodHandleAccessorsTest { public static final int STATIC_FINAL = 1; private final int i; private final String s; + private static String name = "name"; + private byte b = 9; public Public() { this.i = 0; @@ -130,6 +132,11 @@ public class MethodHandleAccessorsTest { this.i = 0; this.s = s; } + public Public(byte b) { + this.b = b; + this.i = 0; + this.s = null; + } public Public(int first, int... rest) { this(varargs_primitive(first, rest)); @@ -162,6 +169,7 @@ public class MethodHandleAccessorsTest { return "Public{" + "i=" + i + ", s='" + s + '\'' + + ", b=" + b + '}'; } } @@ -385,11 +393,14 @@ public class MethodHandleAccessorsTest { new IllegalArgumentException("argument type mismatch"), new IllegalArgumentException("object is not an instance of declaring class"), }; - private static final Throwable[] cannot_get_final_field = new Throwable[] { - new IllegalArgumentException("Can not get final") + private static final Throwable[] cannot_get_field = new Throwable[] { + new IllegalArgumentException("Can not get") + }; + private static final Throwable[] cannot_set_field = new Throwable[] { + new IllegalArgumentException("Can not set") }; - private static final Throwable[] cannot_set_final_field = new Throwable[] { - new IllegalArgumentException("Can not set final") + private static final Throwable[] mismatched_field_type = new Throwable[] { + new IllegalArgumentException("Can not set") }; private static final Throwable[] wrong_argument_count_no_details = new Throwable[] { new IllegalArgumentException("wrong number of arguments") @@ -592,23 +603,30 @@ public class MethodHandleAccessorsTest { @DataProvider(name = "readAccess") private Object[][] readAccess() { boolean newImpl = Boolean.getBoolean("jdk.reflect.useDirectMethodHandle"); + String wrongInst = new String(); return new Object[][]{ new Object[]{"i", new Public(100), 100, noException}, new Object[]{"s", new Public("test"), "test", noException}, - new Object[]{"s", new Object(), "test", - newImpl ? cannot_get_final_field : cannot_set_final_field}, new Object[]{"s", null, "test", null_target}, + new Object[]{"s", wrongInst, "test", + newImpl ? cannot_get_field : cannot_set_field}, + new Object[]{"b", wrongInst, 0, + newImpl ? cannot_get_field : cannot_set_field}, }; } @DataProvider(name = "writeAccess") private Object[][] writeAccess() { + Object o = new Object(); + byte b = 1; return new Object[][]{ new Object[]{"i", new Public(100), 100, 200, noException}, + new Object[]{"i", new Public(100), 100, Integer.valueOf(10), noException}, new Object[]{"s", new Public("test"), "test", "newValue", noException}, - // ## no exception thrown - // new Object[]{"i", new Public(100), 100, new Object(), cannot_set_final_field}, - new Object[]{"s", new Object(), "test", "dummy", cannot_set_final_field}, new Object[]{"s", null, "test", "dummy", null_target}, + new Object[]{"b", new Public(b), b, null, mismatched_field_type}, + new Object[]{"b", new Public(b), b, Long.valueOf(10), mismatched_field_type}, + new Object[]{"name", null, "name", o, mismatched_field_type}, + new Object[]{"i", new Public(100), 100, o, mismatched_field_type}, }; } diff --git a/test/jdk/java/lang/reflect/exeCallerAccessTest/CallerAccessTest.java b/test/jdk/java/lang/reflect/exeCallerAccessTest/CallerAccessTest.java index 9f625a34a93302b51770b31f1bdb05e79e338b62..85ee270244db8cffcbae9e0367a334a0a515339c 100644 --- a/test/jdk/java/lang/reflect/exeCallerAccessTest/CallerAccessTest.java +++ b/test/jdk/java/lang/reflect/exeCallerAccessTest/CallerAccessTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -24,7 +24,7 @@ /** * @test - * @bug 8221530 + * @bug 8221530 8221642 * @summary Test uses custom launcher that starts VM using JNI that verifies * reflection API with null caller class * @library /test/lib @@ -61,7 +61,10 @@ public class CallerAccessTest { System.out.println("Launching: " + launcher + " shared library path: " + env.get(sharedLibraryPathEnvName)); - new OutputAnalyzer(pb.start()).shouldHaveExitValue(0); + new OutputAnalyzer(pb.start()) + .outputTo(System.out) + .errorTo(System.err) + .shouldHaveExitValue(0); } } diff --git a/test/jdk/java/lang/reflect/exeCallerAccessTest/exeCallerAccessTest.c b/test/jdk/java/lang/reflect/exeCallerAccessTest/exeCallerAccessTest.c index c38a0cb094eb0f89793b56b030ef446ce36b4473..31710138aaca5cd11d607a780d5d657732cf15c6 100644 --- a/test/jdk/java/lang/reflect/exeCallerAccessTest/exeCallerAccessTest.c +++ b/test/jdk/java/lang/reflect/exeCallerAccessTest/exeCallerAccessTest.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -32,9 +32,15 @@ static jclass iaeClass; static jmethodID mid_Class_forName; static jmethodID mid_Class_getField; static jmethodID mid_Field_get; +static jmethodID mid_Field_canAccess; +static jmethodID mid_Field_trySetAccessible; +static jmethodID mid_Field_setAccessible; int getField(JNIEnv *env, char* declaringClass_name, char* field_name); int checkAndClearIllegalAccessExceptionThrown(JNIEnv *env); +int setAccessible(JNIEnv *env, char* declaringClass_name, char* field_name); +int trySetAccessible(JNIEnv *env, char* declaringClass_name, char* field_name, jboolean canAccess); +int checkAccess(JNIEnv *env, char* declaringClass_name, char* field_name, jboolean canAccess); int main(int argc, char** args) { JavaVM *jvm; @@ -65,6 +71,12 @@ int main(int argc, char** args) { jclass fieldClass = (*env)->FindClass(env, "java/lang/reflect/Field"); mid_Field_get = (*env)->GetMethodID(env, fieldClass, "get", "(Ljava/lang/Object;)Ljava/lang/Object;"); assert(mid_Class_getField != NULL); + mid_Field_canAccess = (*env)->GetMethodID(env, fieldClass, "canAccess", "(Ljava/lang/Object;)Z"); + assert(mid_Field_canAccess != NULL); + mid_Field_setAccessible = (*env)->GetMethodID(env, fieldClass, "setAccessible", "(Z)V"); + assert(mid_Field_setAccessible != NULL); + mid_Field_trySetAccessible = (*env)->GetMethodID(env, fieldClass, "trySetAccessible", "()Z"); + assert(mid_Field_trySetAccessible != NULL); // can access to public member of an exported type if ((rc = getField(env, "java.lang.Integer", "TYPE")) != 0) { @@ -92,6 +104,32 @@ int main(int argc, char** args) { exit(-1); } + // expect IAE to jdk.internal.misc.Unsafe class + if ((rc = setAccessible(env, "jdk.internal.misc.Unsafe", "INVALID_FIELD_OFFSET")) == 0) { + printf("ERROR: IAE not thrown\n"); + exit(-1); + } + if (checkAndClearIllegalAccessExceptionThrown(env) != JNI_TRUE) { + printf("ERROR: exception is not an instance of IAE\n"); + exit(-1); + } + + if ((rc = trySetAccessible(env, "java.lang.reflect.Modifier", "PUBLIC", JNI_TRUE)) != 0) { + printf("ERROR: unexpected result from trySetAccessible on Modifier::PUBLIC field\n"); + exit(-1); + } + if ((rc = trySetAccessible(env, "jdk.internal.misc.Unsafe", "INVALID_FIELD_OFFSET", JNI_FALSE)) != 0) { + printf("ERROR: unexpected result from trySetAccessible on Unsafe public field\n"); + exit(-1); + } + + if ((rc = checkAccess(env, "java.lang.reflect.Modifier", "PUBLIC", JNI_TRUE)) != 0) { + printf("ERROR: unexpected result from trySetAccessible on Modifier::PUBLIC field\n"); + exit(-1); + } + if ((rc = checkAccess(env, "jdk.internal.misc.Unsafe", "INVALID_FIELD_OFFSET", JNI_FALSE)) != 0) { + printf("ERROR: unexpected result from trySetAccessible on Unsafe public field\n"); + } (*jvm)->DestroyJavaVM(jvm); return 0; } @@ -127,3 +165,74 @@ int getField(JNIEnv *env, char* declaringClass_name, char* field_name) { return 0; } +int setAccessible(JNIEnv *env, char* declaringClass_name, char* field_name) { + jobject c = (*env)->CallStaticObjectMethod(env, classClass, mid_Class_forName, + (*env)->NewStringUTF(env, declaringClass_name)); + if ((*env)->ExceptionOccurred(env) != NULL) { + (*env)->ExceptionDescribe(env); + return 1; + } + + jobject f = (*env)->CallObjectMethod(env, c, mid_Class_getField, (*env)->NewStringUTF(env, field_name)); + if ((*env)->ExceptionOccurred(env) != NULL) { + (*env)->ExceptionDescribe(env); + return 2; + } + + (*env)->CallVoidMethod(env, f, mid_Field_setAccessible, JNI_TRUE); + if ((*env)->ExceptionOccurred(env) != NULL) { + (*env)->ExceptionDescribe(env); + return 3; + } + return 0; +} + +int trySetAccessible(JNIEnv *env, char* declaringClass_name, char* field_name, jboolean canAccess) { + jobject c = (*env)->CallStaticObjectMethod(env, classClass, mid_Class_forName, + (*env)->NewStringUTF(env, declaringClass_name)); + if ((*env)->ExceptionOccurred(env) != NULL) { + (*env)->ExceptionDescribe(env); + return 1; + } + + jobject f = (*env)->CallObjectMethod(env, c, mid_Class_getField, (*env)->NewStringUTF(env, field_name)); + if ((*env)->ExceptionOccurred(env) != NULL) { + (*env)->ExceptionDescribe(env); + return 2; + } + + jboolean rc = (*env)->CallBooleanMethod(env, f, mid_Field_trySetAccessible); + if ((*env)->ExceptionOccurred(env) != NULL) { + (*env)->ExceptionDescribe(env); + return 3; + } + if (rc != canAccess) { + return 4; + } + return 0; +} + +int checkAccess(JNIEnv *env, char* declaringClass_name, char* field_name, jboolean canAccess) { + jobject c = (*env)->CallStaticObjectMethod(env, classClass, mid_Class_forName, + (*env)->NewStringUTF(env, declaringClass_name)); + if ((*env)->ExceptionOccurred(env) != NULL) { + (*env)->ExceptionDescribe(env); + return 1; + } + + jobject f = (*env)->CallObjectMethod(env, c, mid_Class_getField, (*env)->NewStringUTF(env, field_name)); + if ((*env)->ExceptionOccurred(env) != NULL) { + (*env)->ExceptionDescribe(env); + return 2; + } + + jboolean rc = (*env)->CallBooleanMethod(env, f, mid_Field_canAccess, NULL); + if ((*env)->ExceptionOccurred(env) != NULL) { + (*env)->ExceptionDescribe(env); + return 3; + } + if (rc != canAccess) { + return 4; + } + return 0; +} diff --git a/test/jdk/java/lang/reflect/records/RecordReflectionTest.java b/test/jdk/java/lang/reflect/records/RecordReflectionTest.java index 5968b4813ea8fa5baa3a428ee192d0512a065a31..23b707663a9be983e4874e371d2f7bb0dfa6dca9 100644 --- a/test/jdk/java/lang/reflect/records/RecordReflectionTest.java +++ b/test/jdk/java/lang/reflect/records/RecordReflectionTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -162,7 +162,7 @@ public class RecordReflectionTest { RecordComponent rc = recordClass.getRecordComponents()[0]; Annotation[] annos = rc.getAnnotations(); assertEquals(annos.length, 1); - assertEquals(annos[0].toString(), "@RecordReflectionTest$RCA()"); + assertEquals(annos[0].toString(), "@RecordReflectionTest.RCA()"); Field f = recordClass.getDeclaredField("i"); assertEquals(f.getAnnotations().length, 1); @@ -181,7 +181,7 @@ public class RecordReflectionTest { AnnotatedType at = rc.getAnnotatedType(); Annotation[] annos = at.getAnnotations(); assertEquals(annos.length, 1); - assertEquals(annos[0].toString(), "@RecordReflectionTest$TYPE_USE()"); + assertEquals(annos[0].toString(), "@RecordReflectionTest.TYPE_USE()"); Field f = recordClass.getDeclaredField("i"); assertEquals(f.getAnnotatedType().getAnnotations().length, 1); diff --git a/test/jdk/java/lang/runtime/ObjectMethodsTest.java b/test/jdk/java/lang/runtime/ObjectMethodsTest.java index dba92eb32ff77092053c52e542ef393eb865e4dd..0a7741c02e1788cd1ffb653bd90c727edbe88e2b 100644 --- a/test/jdk/java/lang/runtime/ObjectMethodsTest.java +++ b/test/jdk/java/lang/runtime/ObjectMethodsTest.java @@ -166,6 +166,7 @@ public class ObjectMethodsTest { assertThrows(NPE, () -> ObjectMethods.bootstrap(LOOKUP, npt.mn(), npt.mt(), null, "x;y", C.ACCESSORS)); assertThrows(NPE, () -> ObjectMethods.bootstrap(LOOKUP, npt.mn(), null, C.class, "x;y", C.ACCESSORS)); assertThrows(NPE, () -> ObjectMethods.bootstrap(LOOKUP, null, npt.mt(), C.class, "x;y", C.ACCESSORS)); + assertThrows(NPE, () -> ObjectMethods.bootstrap(null, npt.mn(), npt.mt(), C.class, "x;y", C.ACCESSORS)); } } diff --git a/test/jdk/java/math/BigInteger/BigIntegerParallelMultiplyTest.java b/test/jdk/java/math/BigInteger/BigIntegerParallelMultiplyTest.java new file mode 100644 index 0000000000000000000000000000000000000000..1396ae06d962d3e4c6302fb1d58598ecd22925d0 --- /dev/null +++ b/test/jdk/java/math/BigInteger/BigIntegerParallelMultiplyTest.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 1998, 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. + */ + +/* + * @test + * @run main BigIntegerParallelMultiplyTest + * @summary tests parallelMultiply() method in BigInteger + * @author Heinz Kabutz heinz@javaspecialists.eu + */ + +import java.math.BigInteger; +import java.util.function.BinaryOperator; + +/** + * This is a simple test class created to ensure that the results + * of multiply() are the same as multiplyParallel(). We calculate + * the Fibonacci numbers using Dijkstra's sum of squares to get + * very large numbers (hundreds of thousands of bits). + * + * @author Heinz Kabutz, heinz@javaspecialists.eu + */ +public class BigIntegerParallelMultiplyTest { + public static BigInteger fibonacci(int n, BinaryOperator<BigInteger> multiplyOperator) { + if (n == 0) return BigInteger.ZERO; + if (n == 1) return BigInteger.ONE; + + int half = (n + 1) / 2; + BigInteger f0 = fibonacci(half - 1, multiplyOperator); + BigInteger f1 = fibonacci(half, multiplyOperator); + if (n % 2 == 1) { + BigInteger b0 = multiplyOperator.apply(f0, f0); + BigInteger b1 = multiplyOperator.apply(f1, f1); + return b0.add(b1); + } else { + BigInteger b0 = f0.shiftLeft(1).add(f1); + return multiplyOperator.apply(b0, f1); + } + } + + public static void main(String[] args) throws Exception { + compare(1000, 324); + compare(10_000, 3473); + compare(100_000, 34883); + compare(1_000_000, 347084); + } + + private static void compare(int n, int expectedBitCount) { + BigInteger multiplyResult = fibonacci(n, BigInteger::multiply); + BigInteger parallelMultiplyResult = fibonacci(n, BigInteger::parallelMultiply); + checkBitCount(n, expectedBitCount, multiplyResult); + checkBitCount(n, expectedBitCount, parallelMultiplyResult); + if (!multiplyResult.equals(parallelMultiplyResult)) + throw new AssertionError("multiply() and parallelMultiply() give different results"); + } + + private static void checkBitCount(int n, int expectedBitCount, BigInteger number) { + if (number.bitCount() != expectedBitCount) + throw new AssertionError( + "bitCount of fibonacci(" + n + ") was expected to be " + expectedBitCount + + " but was " + number.bitCount()); + } +} diff --git a/test/jdk/java/net/DatagramSocket/SendDatagramToBadAddress.java b/test/jdk/java/net/DatagramSocket/SendDatagramToBadAddress.java index 0656dca908393a54a98e4b23e09ff88c4c258aae..b0c0afdbd61188bc36e7ff0884d31672535e5f3a 100644 --- a/test/jdk/java/net/DatagramSocket/SendDatagramToBadAddress.java +++ b/test/jdk/java/net/DatagramSocket/SendDatagramToBadAddress.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -28,7 +28,7 @@ * * @summary DatagramSocket.send should throw exception when connected * to an invalid destination (on platforms that support it). - * @run main/othervm SendDatagramToBadAddress + * @run main/othervm SendDatagramToBadAddress -d */ import java.net.*; @@ -70,6 +70,8 @@ public class SendDatagramToBadAddress { for (int i=0; i<loop; i++) { try { server.receive (pack); + print("received data from address " + pack.getAddress() + + " port " + pack.getPort()); } catch (Exception e) { if (expectError) { print ("Got expected error: " + e); @@ -116,12 +118,15 @@ public class SendDatagramToBadAddress { DatagramPacket p; byte[] buf; int port = serversock.getLocalPort (); + print("tests will be run against destination address " + addr + " port " + port); final int loop = 5; Server s = new Server (serversock); int i; print ("Checking send to connected address ..."); sock.connect(addr, port); + print("socket is locally bound to address " + sock.getLocalAddress() + + " port " + sock.getLocalPort()); for (i = 0; i < loop; i++) { try { @@ -170,6 +175,8 @@ public class SendDatagramToBadAddress { sock.send(p); p = new DatagramPacket(buf, buf.length, addr, port); sock.receive (p); + print("(unexpectedly) received data from address " + p.getAddress() + + " port " + p.getPort() + " on attempt " + i); } catch (InterruptedIOException ex) { print ("socket timeout"); } catch (Exception ex) { diff --git a/test/jdk/java/net/ProxySelector/LoopbackAddresses.java b/test/jdk/java/net/ProxySelector/LoopbackAddresses.java index cd5eb919b97d615e2c4fdb0d379f222baead82ed..8e27185d5186f876761cb4c1f9b2790e96d8da89 100644 --- a/test/jdk/java/net/ProxySelector/LoopbackAddresses.java +++ b/test/jdk/java/net/ProxySelector/LoopbackAddresses.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -27,15 +27,25 @@ * @summary PIT: Can no launch jnlp application via 127.0.0.1 address on the web server. * This test might fail intermittently as it needs a server that * binds to the wildcard address. - * @modules java.base/sun.net.www - * @library ../../../sun/net/www/httptest/ /test/lib - * @build ClosedChannelList TestHttpServer HttpTransaction HttpCallback + * @library /test/lib * @compile LoopbackAddresses.java * @run main/othervm LoopbackAddresses */ -import java.net.*; -import java.io.*; +import java.io.IOException; +import java.io.PrintWriter; +import java.net.HttpURLConnection; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.URL; +import java.nio.charset.Charset; +import java.util.concurrent.Executors; + +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpHandler; +import com.sun.net.httpserver.HttpServer; import jdk.test.lib.net.URIBuilder; /** @@ -43,17 +53,8 @@ import jdk.test.lib.net.URIBuilder; * addresses when selecting proxies. This is the existing behaviour. */ -public class LoopbackAddresses implements HttpCallback { - static TestHttpServer server; - - public void request (HttpTransaction req) { - req.setResponseEntityBody ("Hello ."); - try { - req.sendResponse (200, "Ok"); - req.orderlyClose(); - } catch (IOException e) { - } - } +public class LoopbackAddresses { + static HttpServer server; public static void main(String[] args) { try { @@ -63,15 +64,17 @@ public class LoopbackAddresses implements HttpCallback { // to answer both for the loopback and "localhost". // Though "localhost" usually point to the loopback there is no // hard guarantee. - server = new TestHttpServer (new LoopbackAddresses(), 1, 10, 0); - ProxyServer pserver = new ProxyServer(InetAddress.getByName("localhost"), server.getLocalPort()); + server = HttpServer.create(new InetSocketAddress(loopback, 0), 10, "/", new LoopbackAddressesHandler()); + server.setExecutor(Executors.newSingleThreadExecutor()); + server.start(); + ProxyServer pserver = new ProxyServer(InetAddress.getByName("localhost"), server.getAddress().getPort()); // start proxy server new Thread(pserver).start(); System.setProperty("http.proxyHost", loopback.getHostAddress()); System.setProperty("http.proxyPort", pserver.getPort()+""); - URL url = new URL("http://localhost:"+server.getLocalPort()); + URL url = new URL("http://localhost:"+server.getAddress().getPort()); try { HttpURLConnection urlc = (HttpURLConnection)url.openConnection (); @@ -85,7 +88,7 @@ public class LoopbackAddresses implements HttpCallback { url = URIBuilder.newBuilder() .scheme("http") .host(loopback.getHostAddress()) - .port(server.getLocalPort()) + .port(server.getAddress().getPort()) .toURL(); HttpURLConnection urlc = (HttpURLConnection)url.openConnection (); int respCode = urlc.getResponseCode(); @@ -97,7 +100,7 @@ public class LoopbackAddresses implements HttpCallback { throw new RuntimeException(e); } finally { if (server != null) { - server.terminate(); + server.stop(1); } } @@ -151,3 +154,18 @@ public class LoopbackAddresses implements HttpCallback { } } } + +class LoopbackAddressesHandler implements HttpHandler { + + @Override + public void handle(HttpExchange exchange) throws IOException { + try { + exchange.sendResponseHeaders(200, 0); + } catch (IOException e) { + e.printStackTrace(); + } + try(PrintWriter pw = new PrintWriter(exchange.getResponseBody(), false, Charset.forName("UTF-8"))) { + pw.print("Hello ."); + } + } +} diff --git a/test/jdk/java/net/ProxySelector/ProxyTest.java b/test/jdk/java/net/ProxySelector/ProxyTest.java index 8debe931469cacc1e36b343b41d814db56134a1c..179cc886c00891c5e366c5cd7aea219f8ff0c179 100644 --- a/test/jdk/java/net/ProxySelector/ProxyTest.java +++ b/test/jdk/java/net/ProxySelector/ProxyTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -25,33 +25,37 @@ * @test * @bug 4696512 * @summary HTTP client: Improve proxy server configuration and selection - * @modules java.base/sun.net.www - * @library ../../../sun/net/www/httptest/ /test/lib - * @build ClosedChannelList TestHttpServer HttpTransaction HttpCallback + * @library /test/lib * @compile ProxyTest.java * @run main/othervm -Dhttp.proxyHost=inexistant -Dhttp.proxyPort=8080 ProxyTest */ -import java.net.*; -import java.io.*; +import java.io.IOException; +import java.io.InputStream; +import java.io.PrintWriter; +import java.net.HttpURLConnection; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.Proxy; +import java.net.ProxySelector; +import java.net.SocketAddress; +import java.net.URI; +import java.net.URL; +import java.nio.charset.Charset; import java.util.List; +import java.util.concurrent.Executors; + +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpHandler; +import com.sun.net.httpserver.HttpServer; import jdk.test.lib.net.URIBuilder; -public class ProxyTest implements HttpCallback { - static TestHttpServer server; +public class ProxyTest { + static HttpServer server; public ProxyTest() { } - public void request(HttpTransaction req) { - req.setResponseEntityBody("Hello ."); - try { - req.sendResponse(200, "Ok"); - req.orderlyClose(); - } catch (IOException e) { - } - } - static public class MyProxySelector extends ProxySelector { private static volatile URI lastURI; private final static List<Proxy> NO_PROXY = List.of(Proxy.NO_PROXY); @@ -75,11 +79,13 @@ public class ProxyTest implements HttpCallback { ProxySelector.setDefault(new MyProxySelector()); try { InetAddress loopback = InetAddress.getLoopbackAddress(); - server = new TestHttpServer(new ProxyTest(), 1, 10, loopback, 0); + server = HttpServer.create(new InetSocketAddress(loopback, 0), 10, "/", new ProxyTestHandler()); + server.setExecutor(Executors.newSingleThreadExecutor()); + server.start(); URL url = URIBuilder.newBuilder() .scheme("http") .loopback() - .port(server.getLocalPort()) + .port(server.getAddress().getPort()) .toURL(); System.out.println("client opening connection to: " + url); HttpURLConnection urlc = (HttpURLConnection)url.openConnection(); @@ -93,8 +99,23 @@ public class ProxyTest implements HttpCallback { throw new RuntimeException(e); } finally { if (server != null) { - server.terminate(); + server.stop(1); } } } } + +class ProxyTestHandler implements HttpHandler { + + @Override + public void handle(HttpExchange exchange) throws IOException { + try { + exchange.sendResponseHeaders(200, 0); + } catch (IOException e) { + e.printStackTrace(); + } + try(PrintWriter pw = new PrintWriter(exchange.getResponseBody(), false, Charset.forName("UTF-8"))) { + pw.print("Hello ."); + } + } +} diff --git a/test/jdk/java/net/ServerSocket/IsClosedAfterAsyncClose.java b/test/jdk/java/net/ServerSocket/IsClosedAfterAsyncClose.java new file mode 100644 index 0000000000000000000000000000000000000000..1b77793290091ff6b2f9967ef279e8ecbe52606b --- /dev/null +++ b/test/jdk/java/net/ServerSocket/IsClosedAfterAsyncClose.java @@ -0,0 +1,81 @@ +/* + * 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. + */ + +/** + * @test + * @bug 8278339 + * @summary Test that ServerSocket::isClosed returns true after async close + */ + +import java.io.IOException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.ServerSocket; +import java.net.Socket; + +public class IsClosedAfterAsyncClose { + + private static final int ITERATIONS = 100; + + public static void main(String[] args) throws Exception { + for (int i = 0; i < ITERATIONS; i++) { + System.out.printf("Test %d...%n", i); + + // create listener bound to the loopback address + ServerSocket listener = new ServerSocket(); + InetAddress loopback = InetAddress.getLoopbackAddress(); + listener.bind(new InetSocketAddress(loopback, 0)); + + // task to close listener after a delay + Runnable closeListener = () -> { + try { + Thread.sleep(100); + listener.close(); + } catch (Exception e) { + e.printStackTrace(); + } + }; + + // main thread blocks in accept. When listener is closed then accept + // should wakeup with an IOException and isClosed should be true. + try (listener) { + Thread closer = new Thread(closeListener); + closer.start(); + try { + while (true) { + Socket s = listener.accept(); + // close spurious connection + s.close(); + } + } catch (IOException ioe) { + if (!listener.isClosed()) { + throw new RuntimeException("isClosed returned false!!"); + } + } finally { + closer.join(); + } + } + } + } +} + diff --git a/test/jdk/java/net/SocketException/TestSocketExceptionCtor.java b/test/jdk/java/net/SocketException/TestSocketExceptionCtor.java new file mode 100644 index 0000000000000000000000000000000000000000..18611924bec151e4edd40f7ff76c35d75e2eed27 --- /dev/null +++ b/test/jdk/java/net/SocketException/TestSocketExceptionCtor.java @@ -0,0 +1,54 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8282686 + * @summary Verify cause and message handling of SocketException + */ +import java.net.SocketException; +import java.util.Objects; + +public class TestSocketExceptionCtor { + public static void main(String... args) { + String message = "message"; + Throwable cause = new RuntimeException(); + + testException(new SocketException(cause), cause.toString(), cause); + testException(new SocketException(message, cause), message, cause); + } + + private static void testException(SocketException se, + String expectedMessage, + Throwable expectedCause) { + var message = se.getMessage(); + if (!Objects.equals(message, expectedMessage)) { + throw new RuntimeException("Unexpected message " + message); + } + + var cause = se.getCause(); + if (cause != expectedCause) { + throw new RuntimeException("Unexpected cause"); + } + } +} diff --git a/test/jdk/java/net/URL/PerConnectionProxy.java b/test/jdk/java/net/URL/PerConnectionProxy.java index 6ce25b9a50eae019fbd01ab45bb1dc86b8955cf9..1877e7cef2877844250a10b285377a98133ef8a4 100644 --- a/test/jdk/java/net/URL/PerConnectionProxy.java +++ b/test/jdk/java/net/URL/PerConnectionProxy.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -24,42 +24,47 @@ /* @test * @bug 4920526 * @summary Needs per connection proxy support for URLs - * @modules java.base/sun.net.www - * @library ../../../sun/net/www/httptest/ /test/lib - * @build ClosedChannelList TestHttpServer HttpTransaction HttpCallback + * @library /test/lib * @compile PerConnectionProxy.java * @run main/othervm -Dhttp.proxyHost=inexistant -Dhttp.proxyPort=8080 PerConnectionProxy */ -import java.net.*; -import java.io.*; - +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.PrintWriter; +import java.net.HttpURLConnection; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.Proxy; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.URL; +import java.nio.charset.Charset; +import java.util.concurrent.Executors; + +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpHandler; +import com.sun.net.httpserver.HttpServer; import jdk.test.lib.net.URIBuilder; -public class PerConnectionProxy implements HttpCallback { - static TestHttpServer server; - - public void request (HttpTransaction req) { - req.setResponseEntityBody ("Hello ."); - try { - req.sendResponse (200, "Ok"); - req.orderlyClose(); - } catch (IOException e) { - } - } +public class PerConnectionProxy { + static HttpServer server; public static void main(String[] args) { try { InetAddress loopbackAddress = InetAddress.getLoopbackAddress(); - server = new TestHttpServer(new PerConnectionProxy(), 1, 10, loopbackAddress, 0); - ProxyServer pserver = new ProxyServer(loopbackAddress, server.getLocalPort()); + server = HttpServer.create(new InetSocketAddress(loopbackAddress, 0), 10, "/", new PerConnectionProxyHandler()); + server.setExecutor(Executors.newSingleThreadExecutor()); + server.start(); + ProxyServer pserver = new ProxyServer(loopbackAddress, server.getAddress().getPort()); // start proxy server new Thread(pserver).start(); URL url = URIBuilder.newBuilder() .scheme("http") .loopback() - .port(server.getLocalPort()) + .port(server.getAddress().getPort()) .toURLUnchecked(); // for non existing proxy expect an IOException @@ -73,7 +78,6 @@ public class PerConnectionProxy implements HttpCallback { } catch (IOException ioex) { // expected } - // for NO_PROXY, expect direct connection try { HttpURLConnection urlc = (HttpURLConnection)url.openConnection (Proxy.NO_PROXY); @@ -82,7 +86,6 @@ public class PerConnectionProxy implements HttpCallback { } catch (IOException ioex) { throw new RuntimeException("direct connection should succeed :"+ioex.getMessage()); } - // for a normal proxy setting expect to see connection // goes through that proxy try { @@ -101,10 +104,9 @@ public class PerConnectionProxy implements HttpCallback { throw new RuntimeException(e); } finally { if (server != null) { - server.terminate(); + server.stop(1); } } - } static class ProxyServer extends Thread { @@ -145,7 +147,6 @@ public class PerConnectionProxy implements HttpCallback { private void processRequests() throws Exception { // connection set to the tunneling mode - Socket serverSocket = new Socket(serverInetAddr, serverPort); ProxyTunnel clientToServer = new ProxyTunnel( clientSocket, serverSocket); @@ -161,7 +162,6 @@ public class PerConnectionProxy implements HttpCallback { clientToServer.close(); serverToClient.close(); - } /** @@ -221,6 +221,20 @@ public class PerConnectionProxy implements HttpCallback { } catch (IOException ignored) { } } } + } +} +class PerConnectionProxyHandler implements HttpHandler { + + @Override + public void handle(HttpExchange exchange) throws IOException { + try { + exchange.sendResponseHeaders(200, 0); + } catch (IOException e) { + } + try(PrintWriter pw = new PrintWriter(exchange.getResponseBody(), false, Charset.forName("UTF-8"))) { + pw.print("Hello ."); + } } } + diff --git a/test/jdk/java/net/URLConnection/B5052093.java b/test/jdk/java/net/URLConnection/B5052093.java index f5434f9528b96ad2f8e6d83dd2cdba109f0588d9..c93098f2de89e1252fe5cbd68a42e143f14011de 100644 --- a/test/jdk/java/net/URLConnection/B5052093.java +++ b/test/jdk/java/net/URLConnection/B5052093.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 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 @@ -23,21 +23,31 @@ /* * @test + * @modules java.base/sun.net.www.protocol.file * @bug 5052093 - * @modules java.base/sun.net.www java.base/sun.net.www.protocol.file - * @library ../../../sun/net/www/httptest/ - * @build HttpCallback TestHttpServer ClosedChannelList HttpTransaction - * @run main B5052093 + * @library /test/lib + * @run main/othervm B5052093 * @summary URLConnection doesn't support large files */ -import java.net.*; -import java.io.*; -import sun.net.www.protocol.file.FileURLConnection; + +import java.io.File; +import java.io.IOException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.URL; +import java.net.URLConnection; +import java.util.concurrent.Executors; + +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpHandler; +import com.sun.net.httpserver.HttpServer; import static java.net.Proxy.NO_PROXY; +import jdk.test.lib.net.URIBuilder; +import sun.net.www.protocol.file.FileURLConnection; -public class B5052093 implements HttpCallback { - private static TestHttpServer server; - private static long testSize = ((long) (Integer.MAX_VALUE)) + 2; +public class B5052093 { + private static HttpServer server; + static long testSize = ((long) (Integer.MAX_VALUE)) + 2; public static class LargeFile extends File { public LargeFile() { @@ -55,20 +65,18 @@ public class B5052093 implements HttpCallback { } } - public void request(HttpTransaction req) { - try { - req.setResponseHeader("content-length", Long.toString(testSize)); - req.sendResponse(200, "OK"); - } catch (IOException e) { - e.printStackTrace(); - } - } - public static void main(String[] args) throws Exception { InetAddress loopback = InetAddress.getLoopbackAddress(); - server = new TestHttpServer(new B5052093(), 1, 10, loopback, 0); + server = HttpServer.create(new InetSocketAddress(loopback, 0), 10, "/", new B5052093Handler()); + server.setExecutor(Executors.newSingleThreadExecutor()); + server.start(); try { - URL url = new URL("http://" + server.getAuthority() + "/foo"); + URL url = URIBuilder.newBuilder() + .scheme("http") + .loopback() + .port(server.getAddress().getPort()) + .path("/foo") + .build().toURL(); URLConnection conn = url.openConnection(NO_PROXY); int i = conn.getContentLength(); long l = conn.getContentLengthLong(); @@ -89,7 +97,20 @@ public class B5052093 implements HttpCallback { throw new RuntimeException("Wrong content-length from file"); } } finally { - server.terminate(); + server.stop(1); + } + } +} + +class B5052093Handler implements HttpHandler { + @Override + public void handle(HttpExchange exchange) throws IOException { + try { + exchange.getResponseHeaders().set("content-length", Long.toString(B5052093.testSize)); + exchange.sendResponseHeaders(200, 0); + exchange.close(); + } catch (IOException e) { + e.printStackTrace(); } } } diff --git a/test/jdk/java/net/httpclient/AggregateRequestBodyTest.java b/test/jdk/java/net/httpclient/AggregateRequestBodyTest.java index 05d27547a15f2bd54956106ca17b2a43b0c1b1e9..60a35a42a0687d4c469fdcc19c1cd914c7f816d7 100644 --- a/test/jdk/java/net/httpclient/AggregateRequestBodyTest.java +++ b/test/jdk/java/net/httpclient/AggregateRequestBodyTest.java @@ -485,7 +485,7 @@ public class AggregateRequestBodyTest implements HttpServerAdapters { subscriber.subscriptionCF.thenAccept(s -> s.request(1)); List<ByteBuffer> result = subscriber.resultCF.join(); assertEquals(result, List.of()); - assertTrue(subscriber.items.isEmpty());; + assertTrue(subscriber.items.isEmpty()); } // verifies that error emitted by upstream publishers are propagated downstream. diff --git a/test/jdk/java/net/httpclient/CancelRequestTest.java b/test/jdk/java/net/httpclient/CancelRequestTest.java index de48316a25b01030b32749c8058c7730d4e3f006..95d56fdbcce2e0918a38c39b231c5cf2f0d826b1 100644 --- a/test/jdk/java/net/httpclient/CancelRequestTest.java +++ b/test/jdk/java/net/httpclient/CancelRequestTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -23,7 +23,7 @@ /* * @test - * @bug 8245462 8229822 + * @bug 8245462 8229822 8254786 * @summary Tests cancelling the request. * @library /test/lib http2/server * @key randomness diff --git a/test/jdk/java/net/httpclient/CookieHeaderTest.java b/test/jdk/java/net/httpclient/CookieHeaderTest.java index f5c9b57d376628748ac3b0cb142bdd0fee8bcd02..ae0957337de2f89d6b08dbe8ff3b1b01ecdfdf84 100644 --- a/test/jdk/java/net/httpclient/CookieHeaderTest.java +++ b/test/jdk/java/net/httpclient/CookieHeaderTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -331,8 +331,8 @@ public class CookieHeaderTest implements HttpServerAdapters { (new RuntimeException(msg)).printStackTrace(); t.sendResponseHeaders(500, -1); os.write(msg.getBytes(UTF_8)); - } else if (cookie.size() == 2 && !cookie.get(1).equals("ORDER=BISCUITS")) { - String msg = "Incorrect cookie header value:[" + cookie.get(0) + "]"; + } else if (cookie.size() > 1 && !cookie.get(1).equals("ORDER=BISCUITS")) { + String msg = "Incorrect cookie header value:[" + cookie.get(1) + "]"; (new RuntimeException(msg)).printStackTrace(); t.sendResponseHeaders(500, -1); os.write(msg.getBytes(UTF_8)); diff --git a/test/jdk/java/net/httpclient/HeadTest.java b/test/jdk/java/net/httpclient/HeadTest.java index 30fb5741d5ddc2a7da1a08a3cb79ffc37e67da1d..fe8af5545c347e529cac729c760e32b22a52b9e5 100644 --- a/test/jdk/java/net/httpclient/HeadTest.java +++ b/test/jdk/java/net/httpclient/HeadTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -23,7 +23,7 @@ /* * @test - * @bug 8203433 + * @bug 8203433 8276559 * @summary (httpclient) Add tests for HEAD and 304 responses. * @modules java.base/sun.net.www.http * java.net.http/jdk.internal.net.http.common @@ -48,43 +48,20 @@ import org.testng.annotations.BeforeTest; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; -import javax.net.ServerSocketFactory; import javax.net.ssl.SSLContext; import java.io.IOException; import java.io.InputStream; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.io.PrintWriter; -import java.io.Writer; import java.net.InetAddress; import java.net.InetSocketAddress; -import java.net.ServerSocket; -import java.net.Socket; import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpClient.Redirect; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.net.http.HttpResponse.BodyHandlers; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.StringTokenizer; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.concurrent.atomic.AtomicLong; -import java.util.stream.Collectors; -import java.util.stream.Stream; import static java.lang.System.out; -import static java.nio.charset.StandardCharsets.UTF_8; -import static java.net.HttpURLConnection.HTTP_OK; import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertTrue; public class HeadTest implements HttpServerAdapters { @@ -98,8 +75,6 @@ public class HeadTest implements HttpServerAdapters { String http2URI; String https2URI; - static final String MESSAGE = "Basic HeadTest message body"; - static final int ITERATIONS = 3; static final String CONTENT_LEN = "300"; /* @@ -133,27 +108,38 @@ public class HeadTest implements HttpServerAdapters { }; } - static final AtomicLong requestCounter = new AtomicLong(); - @Test(dataProvider = "positive") void test(String uriString, String method, int expResp, HttpClient.Version version) throws Exception { out.printf("%n---- starting (%s) ----%n", uriString); - HttpClient client = HttpClient.newBuilder() - .followRedirects(Redirect.ALWAYS) - .sslContext(sslContext) - .build(); - URI uri = URI.create(uriString); - HttpRequest.Builder requestBuilder = HttpRequest .newBuilder(uri) .method(method, HttpRequest.BodyPublishers.noBody()); - if (version != null) { requestBuilder.version(version); } - HttpRequest request = requestBuilder.build(); + doTest(requestBuilder.build(), expResp); + // repeat the test this time by building the request using convenience + // GET and HEAD methods + requestBuilder = HttpRequest.newBuilder(uri); + if (version != null) { + requestBuilder.version(version); + } + switch (method) { + case "GET" -> requestBuilder.GET(); + case "HEAD" -> requestBuilder.HEAD(); + default -> throw new IllegalArgumentException("Unexpected method " + method); + } + doTest(requestBuilder.build(), expResp); + } + + // issue a request with no body and verify the response code is the expected response code + private void doTest(HttpRequest request, int expResp) throws Exception { + HttpClient client = HttpClient.newBuilder() + .followRedirects(Redirect.ALWAYS) + .sslContext(sslContext) + .build(); out.println("Initial request: " + request.uri()); HttpResponse<String> response = client.send(request, BodyHandlers.ofString()); diff --git a/test/jdk/java/net/httpclient/HttpRequestBuilderTest.java b/test/jdk/java/net/httpclient/HttpRequestBuilderTest.java index a3134397bcf40f48841c8e98d21a156ea98f77c0..a0c74048503fbb6be95ad7cf43e9052b13814805 100644 --- a/test/jdk/java/net/httpclient/HttpRequestBuilderTest.java +++ b/test/jdk/java/net/httpclient/HttpRequestBuilderTest.java @@ -36,7 +36,7 @@ import static java.net.http.HttpRequest.BodyPublishers.noBody; /** * @test - * @bug 8170064 + * @bug 8170064 8276559 * @summary HttpRequest[.Builder] API and behaviour checks */ public class HttpRequestBuilderTest { @@ -156,6 +156,7 @@ public class HttpRequestBuilderTest { IllegalArgumentException.class); test0("DELETE", () -> HttpRequest.newBuilder(TEST_URI).DELETE().build(), null); + test0("HEAD", () -> HttpRequest.newBuilder(TEST_URI).HEAD().build(), null); builder = test1("POST", builder, builder::POST, noBody(), null); @@ -254,7 +255,9 @@ public class HttpRequestBuilderTest { () -> HttpRequest.newBuilder(TEST_URI).GET().DELETE(), "DELETE"); - + method("newBuilder(TEST_URI).HEAD().build().method() == HEAD", + () -> HttpRequest.newBuilder(TEST_URI).HEAD(), + "HEAD"); } diff --git a/test/jdk/java/net/httpclient/HttpRequestNewBuilderTest.java b/test/jdk/java/net/httpclient/HttpRequestNewBuilderTest.java index c1c7e3432b615184f67d5166d66ba5532c4eeb9f..eab9ecfc2c723525ded3f76c9835fac18408767f 100644 --- a/test/jdk/java/net/httpclient/HttpRequestNewBuilderTest.java +++ b/test/jdk/java/net/httpclient/HttpRequestNewBuilderTest.java @@ -1,5 +1,5 @@ /* -* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. +* 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 @@ -51,7 +51,7 @@ import static org.testng.Assert.fail; /** * @test -* @bug 8252304 +* @bug 8252304 8276559 * @summary HttpRequest.newBuilder(HttpRequest) API and behaviour checks * @run testng/othervm HttpRequestNewBuilderTest */ @@ -120,6 +120,7 @@ public class HttpRequestNewBuilderTest { .headers("testName1", "y") .headers("testName1", "z").build() }, // dedicated method + { HttpRequest.newBuilder(URI.create("https://method-0/")).HEAD().build() }, { HttpRequest.newBuilder(URI.create("https://method-1/")).GET().build() }, { HttpRequest.newBuilder(URI.create("https://method-2/")).DELETE().build() }, { HttpRequest.newBuilder(URI.create("https://method-3/")).POST(HttpRequest.BodyPublishers.ofString("testData")).build() }, diff --git a/test/jdk/java/net/httpclient/LineBodyHandlerTest.java b/test/jdk/java/net/httpclient/LineBodyHandlerTest.java index 601f1ad408022e3af8ef814ce4e716d417e93882..10717a848bd40b0a2aa35f1f438cb03edee89fda 100644 --- a/test/jdk/java/net/httpclient/LineBodyHandlerTest.java +++ b/test/jdk/java/net/httpclient/LineBodyHandlerTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -84,7 +84,7 @@ import static org.testng.Assert.assertTrue; * java.logging * jdk.httpserver * @library /test/lib http2/server - * @build Http2TestServer LineBodyHandlerTest HttpServerAdapters + * @build Http2TestServer LineBodyHandlerTest HttpServerAdapters ReferenceTracker * @build jdk.test.lib.net.SimpleSSLContext * @run testng/othervm -XX:+UnlockDiagnosticVMOptions -XX:DiagnoseSyncOnValueBasedClasses=1 LineBodyHandlerTest */ @@ -101,6 +101,10 @@ public class LineBodyHandlerTest implements HttpServerAdapters { String http2URI; String https2URI; + final ReferenceTracker TRACKER = ReferenceTracker.INSTANCE; + final AtomicInteger clientCount = new AtomicInteger(); + HttpClient sharedClient; + @DataProvider(name = "uris") public Object[][] variants() { return new Object[][]{ @@ -189,10 +193,14 @@ public class LineBodyHandlerTest implements HttpServerAdapters { } HttpClient newClient() { - return HttpClient.newBuilder() + if (sharedClient != null) { + return sharedClient; + } + clientCount.incrementAndGet(); + return sharedClient = TRACKER.track(HttpClient.newBuilder() .sslContext(sslContext) .proxy(Builder.NO_PROXY) - .build(); + .build()); } @Test(dataProvider = "uris") @@ -695,10 +703,21 @@ public class LineBodyHandlerTest implements HttpServerAdapters { @AfterTest public void teardown() throws Exception { + sharedClient = null; + try { + System.gc(); + Thread.sleep(200); + } catch (InterruptedException io) { + // don't care; + } + AssertionError fail = TRACKER.check(500); + System.out.printf("Tear down: %s client created.%n", clientCount.get()); + System.err.printf("Tear down: %s client created.%n", clientCount.get()); httpTestServer.stop(); httpsTestServer.stop(); http2TestServer.stop(); https2TestServer.stop(); + if (fail != null) throw fail; } static void printBytes(PrintStream out, String prefix, byte[] bytes) { diff --git a/test/jdk/java/net/httpclient/ManyRequests.java b/test/jdk/java/net/httpclient/ManyRequests.java index f79d565162ad8e18730855e886c70d1d363406f6..296377441a73faa12e9ba10a5452c8602bda7169 100644 --- a/test/jdk/java/net/httpclient/ManyRequests.java +++ b/test/jdk/java/net/httpclient/ManyRequests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -32,13 +32,13 @@ * @compile ../../../com/sun/net/httpserver/LogFilter.java * @compile ../../../com/sun/net/httpserver/EchoHandler.java * @compile ../../../com/sun/net/httpserver/FileServerHandler.java - * @run main/othervm/timeout=40 -Djdk.httpclient.HttpClient.log=ssl ManyRequests - * @run main/othervm/timeout=40 -Dtest.insertDelay=true ManyRequests - * @run main/othervm/timeout=40 -Dtest.chunkSize=64 ManyRequests - * @run main/othervm/timeout=40 -Dtest.insertDelay=true -Dtest.chunkSize=64 ManyRequests + * @run main/othervm/timeout=40 -Djdk.httpclient.HttpClient.log=ssl,channel ManyRequests + * @run main/othervm/timeout=40 -Djdk.httpclient.HttpClient.log=channel -Dtest.insertDelay=true ManyRequests + * @run main/othervm/timeout=40 -Djdk.httpclient.HttpClient.log=channel -Dtest.chunkSize=64 ManyRequests + * @run main/othervm/timeout=40 -Djdk.httpclient.HttpClient.log=channel -Dtest.insertDelay=true -Dtest.chunkSize=64 ManyRequests * @summary Send a large number of requests asynchronously */ - // * @run main/othervm/timeout=40 -Djdk.httpclient.HttpClient.log=ssl ManyRequests + // * @run main/othervm/timeout=40 -Djdk.httpclient.HttpClient.log=ssl,channel ManyRequests import com.sun.net.httpserver.HttpsConfigurator; import com.sun.net.httpserver.HttpsParameters; @@ -47,6 +47,7 @@ import com.sun.net.httpserver.HttpExchange; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.net.ConnectException; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.URI; @@ -54,13 +55,18 @@ import java.net.http.HttpClient; import java.net.http.HttpClient.Builder; import java.net.http.HttpRequest; import java.net.http.HttpRequest.BodyPublishers; +import java.net.http.HttpResponse; import java.net.http.HttpResponse.BodyHandlers; import java.time.Duration; import java.util.Arrays; import java.util.Formatter; import java.util.HashMap; import java.util.LinkedList; +import java.util.Map; import java.util.Random; +import java.util.concurrent.CompletionException; +import java.util.concurrent.CompletionStage; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ThreadFactory; @@ -68,17 +74,27 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.logging.Logger; import java.util.logging.Level; import java.util.concurrent.CompletableFuture; +import java.util.stream.Stream; import javax.net.ssl.SSLContext; + +import jdk.test.lib.Platform; +import jdk.test.lib.RandomFactory; import jdk.test.lib.net.SimpleSSLContext; +import jdk.test.lib.net.URIBuilder; public class ManyRequests { - volatile static int counter = 0; + static final int MAX_COUNT = 20; + static final int MAX_LIMIT = 40; + static final AtomicInteger COUNT = new AtomicInteger(); + static final AtomicInteger LIMIT = new AtomicInteger(MAX_LIMIT); + static final Random RANDOM = RandomFactory.getRandom(); public static void main(String[] args) throws Exception { Logger logger = Logger.getLogger("com.sun.net.httpserver"); logger.setLevel(Level.ALL); logger.info("TEST"); + Stream.of(Logger.getLogger("").getHandlers()).forEach((h) -> h.setLevel(Level.ALL)); System.out.println("Sending " + REQUESTS + " requests; delay=" + INSERT_DELAY + ", chunks=" + CHUNK_SIZE @@ -106,14 +122,14 @@ public class ManyRequests { } //static final int REQUESTS = 1000; - static final int REQUESTS = 20; + static final int REQUESTS = MAX_COUNT; static final boolean INSERT_DELAY = Boolean.getBoolean("test.insertDelay"); static final int CHUNK_SIZE = Math.max(0, Integer.parseInt(System.getProperty("test.chunkSize", "0"))); static final boolean XFIXED = Boolean.getBoolean("test.XFixed"); static class TestEchoHandler extends EchoHandler { - final Random rand = jdk.test.lib.RandomFactory.getRandom(); + final Random rand = RANDOM; @Override public void handle(HttpExchange e) throws IOException { System.out.println("Server: received " + e.getRequestURI()); @@ -139,60 +155,126 @@ public class ManyRequests { } } + static String now(long start) { + long elapsed = System.nanoTime() - start; + long ms = elapsed / 1000_000L; + long s = ms / 1000L; + if (s == 0) return ms + "ms: "; + return s + "s, " + (ms - s * 1000L) + "ms: "; + } + + static String failure(Throwable t) { + String s = "\n\t failed: " + t; + for (t = t.getCause(); t != null ; t = t.getCause()) { + s = s + "\n\t\t Caused by: " + t; + } + return s; + } + static void test(HttpsServer server, HttpClient client) throws Exception { int port = server.getAddress().getPort(); - URI baseURI = new URI("https://localhost:" + port + "/foo/x"); + + URI baseURI = URIBuilder.newBuilder() + .scheme("https") + .host(InetAddress.getLoopbackAddress().getHostName()) + .port(port) + .path("/foo/x").build(); server.createContext("/foo", new TestEchoHandler()); server.start(); - RequestLimiter limiter = new RequestLimiter(40); - Random rand = new Random(); - CompletableFuture<?>[] results = new CompletableFuture<?>[REQUESTS]; - HashMap<HttpRequest,byte[]> bodies = new HashMap<>(); - - for (int i=0; i<REQUESTS; i++) { - byte[] buf = new byte[(i+1)*CHUNK_SIZE+i+1]; // different size bodies - rand.nextBytes(buf); - URI uri = new URI(baseURI.toString() + String.valueOf(i+1)); - HttpRequest r = HttpRequest.newBuilder(uri) - .header("XFixed", "true") - .POST(BodyPublishers.ofByteArray(buf)) - .build(); - bodies.put(r, buf); - - results[i] = - limiter.whenOkToSend() - .thenCompose((v) -> { - System.out.println("Client: sendAsync: " + r.uri()); - return client.sendAsync(r, BodyHandlers.ofByteArray()); - }) - .thenCompose((resp) -> { - limiter.requestComplete(); - if (resp.statusCode() != 200) { - String s = "Expected 200, got: " + resp.statusCode(); - System.out.println(s + " from " - + resp.request().uri().getPath()); - return completedWithIOException(s); - } else { - counter++; - System.out.println("Result (" + counter + ") from " - + resp.request().uri().getPath()); - } - return CompletableFuture.completedStage(resp.body()) - .thenApply((b) -> new Pair<>(resp, b)); - }) - .thenAccept((pair) -> { - HttpRequest request = pair.t.request(); - byte[] requestBody = bodies.get(request); - check(Arrays.equals(requestBody, pair.u), - "bodies not equal:[" + bytesToHexString(requestBody) - + "] [" + bytesToHexString(pair.u) + "]"); - - }); - } + // This loop implements a retry mechanism to work around an issue + // on some systems (observed on Windows 10) that seem to be trying to + // throttle the number of connections that can be made concurrently by + // rejecting connection attempts. + // On the first iteration of this loop, we will attempt 20 concurrent + // requests. If this fails with ConnectException, we will retry the + // 20 requests, but limiting the concurrency to 10 (LIMIT <- 10). + // If this fails again, the test will fail. + boolean done = false; + LOOP: do { + RequestLimiter limiter = new RequestLimiter(LIMIT.get()); + Random rand = RANDOM; + CompletableFuture<?>[] results = new CompletableFuture<?>[REQUESTS]; + Map<HttpRequest,byte[]> bodies = new ConcurrentHashMap<>(); + + long start = System.nanoTime(); + + for (int i = 0; i < REQUESTS; i++) { + byte[] buf = new byte[(i + 1) * CHUNK_SIZE + i + 1]; // different size bodies + rand.nextBytes(buf); + URI uri = new URI(baseURI.toString() + String.valueOf(i + 1)); + HttpRequest r = HttpRequest.newBuilder(uri) + .header("XFixed", "true") + .POST(BodyPublishers.ofByteArray(buf)) + .build(); + bodies.put(r, buf); + + results[i] = + limiter.whenOkToSend() + .thenCompose((v) -> { + System.out.println("Client: sendAsync: " + r.uri()); + return client.sendAsync(r, BodyHandlers.ofByteArray()); + }) + .handle((resp, t) -> { + limiter.requestComplete(); + CompletionStage<Pair<HttpResponse<byte[]>, byte[]>> res; + String now = now(start); + if (t == null) { + if (resp.statusCode() != 200) { + String s = "Expected 200, got: " + resp.statusCode(); + System.out.println(now + s + " from " + + resp.request().uri().getPath()); + res = completedWithIOException(s); + return res; + } else { + int counter = COUNT.incrementAndGet(); + System.out.println(now + "Result (" + counter + ") from " + + resp.request().uri().getPath()); + } + res = CompletableFuture.completedStage(resp.body()) + .thenApply((b) -> new Pair<>(resp, b)); + return res; + } else { + int counter = COUNT.incrementAndGet(); + System.out.println(now + "Result (" + counter + ") from " + + r.uri().getPath() + + failure(t)); + res = CompletableFuture.failedFuture(t); + return res; + } + }) + .thenCompose(c -> c) + .thenAccept((pair) -> { + HttpRequest request = pair.t.request(); + byte[] requestBody = bodies.get(request); + check(Arrays.equals(requestBody, pair.u), + "bodies not equal:[" + bytesToHexString(requestBody) + + "] [" + bytesToHexString(pair.u) + "]"); + + }); + } + + // wait for them all to complete and throw exception in case of err + try { + CompletableFuture.allOf(results).join(); + done = true; + } catch (CompletionException e) { + if (!Platform.isWindows()) throw e; + if (LIMIT.get() < REQUESTS) throw e; + Throwable cause = e; + while ((cause = cause.getCause()) != null) { + if (cause instanceof ConnectException) { + // try again, limit concurrency by half + COUNT.set(0); + LIMIT.set(REQUESTS/2); + System.out.println("*** Retrying due to " + cause); + continue LOOP; + } + } + throw e; + } + } while (!done); - // wait for them all to complete and throw exception in case of error - CompletableFuture.allOf(results).join(); } static <T> CompletableFuture<T> completedWithIOException(String message) { @@ -213,13 +295,7 @@ public class ManyRequests { return sb.toString(); } - static final class Pair<T,U> { - Pair(T t, U u) { - this.t = t; this.u = u; - } - T t; - U u; - } + record Pair<T,U>(T t, U u) { } /** * A simple limiter for controlling the number of requests to be run in diff --git a/test/jdk/java/net/httpclient/ManyRequests2.java b/test/jdk/java/net/httpclient/ManyRequests2.java index b0eee6e3be413b3be44dbf858635928958989009..49e7f758f7c14cee5916a8041df775bcdb33069e 100644 --- a/test/jdk/java/net/httpclient/ManyRequests2.java +++ b/test/jdk/java/net/httpclient/ManyRequests2.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -33,10 +33,14 @@ * @compile ../../../com/sun/net/httpserver/EchoHandler.java * @compile ../../../com/sun/net/httpserver/FileServerHandler.java * @build ManyRequests ManyRequests2 - * @run main/othervm/timeout=40 -Dtest.XFixed=true ManyRequests2 - * @run main/othervm/timeout=40 -Dtest.XFixed=true -Dtest.insertDelay=true ManyRequests2 - * @run main/othervm/timeout=40 -Dtest.XFixed=true -Dtest.chunkSize=64 ManyRequests2 + * @run main/othervm/timeout=40 -Dtest.XFixed=true + * -Djdk.httpclient.HttpClient.log=channel ManyRequests2 + * @run main/othervm/timeout=40 -Dtest.XFixed=true -Dtest.insertDelay=true + * -Djdk.httpclient.HttpClient.log=channel ManyRequests2 + * @run main/othervm/timeout=40 -Dtest.XFixed=true -Dtest.chunkSize=64 + * -Djdk.httpclient.HttpClient.log=channel ManyRequests2 * @run main/othervm/timeout=40 -Djdk.internal.httpclient.debug=true + * -Djdk.httpclient.HttpClient.log=channel * -Dtest.XFixed=true -Dtest.insertDelay=true * -Dtest.chunkSize=64 ManyRequests2 * @summary Send a large number of requests asynchronously. diff --git a/test/jdk/java/net/httpclient/ManyRequestsLegacy.java b/test/jdk/java/net/httpclient/ManyRequestsLegacy.java index b8d296087b9584cd37c1eb97c37e0487942f158a..0e9aba5deafa7df8dba718ae3db84ab184f7c7c7 100644 --- a/test/jdk/java/net/httpclient/ManyRequestsLegacy.java +++ b/test/jdk/java/net/httpclient/ManyRequestsLegacy.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -43,6 +43,7 @@ import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.HostnameVerifier; + import com.sun.net.httpserver.HttpsConfigurator; import com.sun.net.httpserver.HttpsParameters; import com.sun.net.httpserver.HttpsServer; @@ -50,12 +51,18 @@ import com.sun.net.httpserver.HttpExchange; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.net.ConnectException; import java.net.HttpURLConnection; import java.net.InetAddress; import java.net.URI; import java.net.URLConnection; +import java.util.Map; import java.util.Optional; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionException; +import java.util.concurrent.CompletionStage; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSession; @@ -73,12 +80,20 @@ import java.util.LinkedList; import java.util.Random; import java.util.logging.Logger; import java.util.logging.Level; + +import jdk.test.lib.Platform; +import jdk.test.lib.RandomFactory; import jdk.test.lib.net.SimpleSSLContext; import static java.net.Proxy.NO_PROXY; public class ManyRequestsLegacy { - volatile static int counter = 0; + static final int MAX_COUNT = 20; + static final int MAX_LIMIT = 40; + static final AtomicInteger COUNT = new AtomicInteger(); + static final AtomicInteger LIMIT = new AtomicInteger(MAX_LIMIT); + static final Random RANDOM = RandomFactory.getRandom(); + public static void main(String[] args) throws Exception { Logger logger = Logger.getLogger("com.sun.net.httpserver"); @@ -110,7 +125,7 @@ public class ManyRequestsLegacy { } //static final int REQUESTS = 1000; - static final int REQUESTS = 20; + static final int REQUESTS = MAX_COUNT; static final boolean INSERT_DELAY = Boolean.getBoolean("test.insertDelay"); static final int CHUNK_SIZE = Math.max(0, Integer.parseInt(System.getProperty("test.chunkSize", "0"))); @@ -194,7 +209,7 @@ public class ManyRequestsLegacy { } static class TestEchoHandler extends EchoHandler { - final Random rand = new Random(); + final Random rand = RANDOM; @Override public void handle(HttpExchange e) throws IOException { System.out.println("Server: received " + e.getRequestURI()); @@ -220,60 +235,119 @@ public class ManyRequestsLegacy { } } + static String now(long start) { + long elapsed = System.nanoTime() - start; + long ms = elapsed / 1000_000L; + long s = ms / 1000L; + if (s == 0) return ms + "ms: "; + return s + "s, " + (ms - s * 1000L) + "ms: "; + } + + static String failure(Throwable t) { + String s = "\n\t failed: " + t; + for (t = t.getCause(); t != null ; t = t.getCause()) { + s = s + "\n\t\t Caused by: " + t; + } + return s; + } + static void test(HttpsServer server, LegacyHttpClient client) throws Exception { int port = server.getAddress().getPort(); URI baseURI = new URI("https://localhost:" + port + "/foo/x"); server.createContext("/foo", new TestEchoHandler()); server.start(); - RequestLimiter limiter = new RequestLimiter(40); - Random rand = new Random(); - CompletableFuture<?>[] results = new CompletableFuture<?>[REQUESTS]; - HashMap<HttpRequest,byte[]> bodies = new HashMap<>(); - - for (int i=0; i<REQUESTS; i++) { - byte[] buf = new byte[(i+1)*CHUNK_SIZE+i+1]; // different size bodies - rand.nextBytes(buf); - URI uri = new URI(baseURI.toString() + String.valueOf(i+1)); - HttpRequest r = HttpRequest.newBuilder(uri) - .header("XFixed", "true") - .POST(BodyPublishers.ofByteArray(buf)) - .build(); - bodies.put(r, buf); - - results[i] = - limiter.whenOkToSend() - .thenCompose((v) -> { - System.out.println("Client: sendAsync: " + r.uri()); - return client.sendAsync(r, buf); - }) - .thenCompose((resp) -> { - limiter.requestComplete(); - if (resp.statusCode() != 200) { - String s = "Expected 200, got: " + resp.statusCode(); - System.out.println(s + " from " - + resp.request().uri().getPath()); - return completedWithIOException(s); - } else { - counter++; - System.out.println("Result (" + counter + ") from " - + resp.request().uri().getPath()); - } - return CompletableFuture.completedStage(resp.body()) - .thenApply((b) -> new Pair<>(resp, b)); - }) - .thenAccept((pair) -> { - HttpRequest request = pair.t.request(); - byte[] requestBody = bodies.get(request); - check(Arrays.equals(requestBody, pair.u), - "bodies not equal:[" + bytesToHexString(requestBody) - + "] [" + bytesToHexString(pair.u) + "]"); - - }); - } + // This loop implements a retry mechanism to work around an issue + // on some systems (observed on Windows 10) that seem to be trying to + // throttle the number of connections that can be made concurrently by + // rejecting connection attempts. + // On the first iteration of this loop, we will attempt 20 concurrent + // requests. If this fails with ConnectException, we will retry the + // 20 requests, but limiting the concurrency to 10 (LIMIT <- 10). + // If this fails again, the test will fail. + boolean done = false; + LOOP: do { + RequestLimiter limiter = new RequestLimiter(LIMIT.get()); + Random rand = RANDOM; + CompletableFuture<?>[] results = new CompletableFuture<?>[REQUESTS]; + Map<HttpRequest,byte[]> bodies = new ConcurrentHashMap<>(); + long start = System.nanoTime(); + + for (int i = 0; i < REQUESTS; i++) { + byte[] buf = new byte[(i + 1) * CHUNK_SIZE + i + 1]; // different size bodies + rand.nextBytes(buf); + URI uri = new URI(baseURI.toString() + String.valueOf(i + 1)); + HttpRequest r = HttpRequest.newBuilder(uri) + .header("XFixed", "true") + .POST(BodyPublishers.ofByteArray(buf)) + .build(); + bodies.put(r, buf); + + results[i] = + limiter.whenOkToSend() + .thenCompose((v) -> { + System.out.println("Client: sendAsync: " + r.uri()); + return client.sendAsync(r, buf); + }) + .handle((resp, t) -> { + limiter.requestComplete(); + CompletionStage<Pair<HttpResponse<byte[]>, byte[]>> res; + String now = now(start); + if (t == null) { + if (resp.statusCode() != 200) { + String s = "Expected 200, got: " + resp.statusCode(); + System.out.println(now + s + " from " + + resp.request().uri().getPath()); + res = completedWithIOException(s); + return res; + } else { + int counter = COUNT.incrementAndGet(); + System.out.println(now + "Result (" + counter + ") from " + + resp.request().uri().getPath()); + } + res = CompletableFuture.completedStage(resp.body()) + .thenApply((b) -> new Pair<>(resp, b)); + return res; + } else { + int counter = COUNT.incrementAndGet(); + System.out.println(now + "Result (" + counter + ") from " + + r.uri().getPath() + + failure(t)); + res = CompletableFuture.failedFuture(t); + return res; + } + }) + .thenCompose(c -> c) + .thenAccept((pair) -> { + HttpRequest request = pair.t.request(); + byte[] requestBody = bodies.get(request); + check(Arrays.equals(requestBody, pair.u), + "bodies not equal:[" + bytesToHexString(requestBody) + + "] [" + bytesToHexString(pair.u) + "]"); + + }); + } - // wait for them all to complete and throw exception in case of error - CompletableFuture.allOf(results).join(); + try { + // wait for them all to complete and throw exception in case of error + CompletableFuture.allOf(results).join(); + done = true; + } catch (CompletionException e) { + if (!Platform.isWindows()) throw e; + if (LIMIT.get() < REQUESTS) throw e; + Throwable cause = e; + while ((cause = cause.getCause()) != null) { + if (cause instanceof ConnectException) { + // try again, limit concurrency by half + COUNT.set(0); + LIMIT.set(REQUESTS/2); + System.out.println("*** Retrying due to " + cause); + continue LOOP; + } + } + throw e; + } + } while (!done); } static <T> CompletableFuture<T> completedWithIOException(String message) { @@ -294,13 +368,7 @@ public class ManyRequestsLegacy { return sb.toString(); } - static final class Pair<T,U> { - Pair(T t, U u) { - this.t = t; this.u = u; - } - T t; - U u; - } + record Pair<T,U>(T t, U u) { } /** * A simple limiter for controlling the number of requests to be run in diff --git a/test/jdk/java/net/httpclient/RequestBuilderTest.java b/test/jdk/java/net/httpclient/RequestBuilderTest.java index 440014f1dd0e4dd943d5be74eb070a59a690c31f..991b6f9d2d91242524406f0d98270727c3a9ea9d 100644 --- a/test/jdk/java/net/httpclient/RequestBuilderTest.java +++ b/test/jdk/java/net/httpclient/RequestBuilderTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -23,6 +23,7 @@ /* * @test + * @bug 8276559 * @summary HttpRequest[.Builder] API and behaviour checks * @run testng RequestBuilderTest */ @@ -160,6 +161,10 @@ public class RequestBuilderTest { assertEquals(request.method(), "DELETE"); assertTrue(!request.bodyPublisher().isPresent()); + request = newBuilder(uri).HEAD().build(); + assertEquals(request.method(), "HEAD"); + assertFalse(request.bodyPublisher().isPresent()); + request = newBuilder(uri).GET().POST(BodyPublishers.ofString("")).build(); assertEquals(request.method(), "POST"); assertTrue(request.bodyPublisher().isPresent()); diff --git a/test/jdk/java/net/httpclient/UserCookieTest.java b/test/jdk/java/net/httpclient/UserCookieTest.java new file mode 100644 index 0000000000000000000000000000000000000000..9c1c6cc139f079334560ee1d89546d484256aac0 --- /dev/null +++ b/test/jdk/java/net/httpclient/UserCookieTest.java @@ -0,0 +1,573 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8276774 + * @summary Test that user-supplied cookies are appended to + * server-cookies for HTTP/2 vs HTTP/1.1 + * @modules java.base/sun.net.www.http + * java.net.http/jdk.internal.net.http.common + * java.net.http/jdk.internal.net.http.frame + * java.net.http/jdk.internal.net.http.hpack + * java.logging + * jdk.httpserver + * @library /test/lib http2/server + * @build Http2TestServer + * @build jdk.test.lib.net.SimpleSSLContext + * @run testng/othervm + * -Djdk.tls.acknowledgeCloseNotify=true + * -Djdk.httpclient.HttpClient.log=trace,headers,requests + * UserCookieTest + */ + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.io.Writer; +import java.net.CookieHandler; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpClient.Redirect; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.net.http.HttpResponse.BodyHandlers; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.StringTokenizer; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.atomic.AtomicLong; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import javax.net.ServerSocketFactory; +import javax.net.ssl.SSLContext; + +import com.sun.net.httpserver.HttpServer; +import com.sun.net.httpserver.HttpsConfigurator; +import com.sun.net.httpserver.HttpsServer; +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.lang.System.out; +import static java.nio.charset.StandardCharsets.UTF_8; +import static org.testng.Assert.assertEquals; + +public class UserCookieTest implements HttpServerAdapters { + + SSLContext sslContext; + HttpTestServer httpTestServer; // HTTP/1.1 [ 6 servers ] + HttpTestServer httpsTestServer; // HTTPS/1.1 + HttpTestServer http2TestServer; // HTTP/2 ( h2c ) + HttpTestServer https2TestServer; // HTTP/2 ( h2 ) + DummyServer httpDummyServer; + DummyServer httpsDummyServer; + String httpURI; + String httpsURI; + String http2URI; + String https2URI; + String httpDummy; + String httpsDummy; + + static final String MESSAGE = "Basic CookieHeaderTest message body"; + static final int ITERATIONS = 3; + static final long start = System.nanoTime(); + public static String now() { + long now = System.nanoTime() - start; + long secs = now / 1000_000_000; + long mill = (now % 1000_000_000) / 1000_000; + long nan = now % 1000_000; + return String.format("[%d s, %d ms, %d ns] ", secs, mill, nan); + } + + @DataProvider(name = "positive") + public Object[][] positive() { + return new Object[][] { + { httpURI, HttpClient.Version.HTTP_1_1 }, + { httpsURI, HttpClient.Version.HTTP_1_1 }, + { httpDummy, HttpClient.Version.HTTP_1_1 }, + { httpsDummy, HttpClient.Version.HTTP_1_1 }, + { httpURI, HttpClient.Version.HTTP_2 }, + { httpsURI, HttpClient.Version.HTTP_2 }, + { httpDummy, HttpClient.Version.HTTP_2 }, + { httpsDummy, HttpClient.Version.HTTP_2 }, + { http2URI, null }, + { https2URI, null }, + }; + } + + static final AtomicLong requestCounter = new AtomicLong(); + + @Test(dataProvider = "positive") + void test(String uriString, HttpClient.Version version) throws Exception { + out.printf("%n---- starting (%s) ----%n", uriString); + ConcurrentHashMap<String, List<String>> cookieHeaders + = new ConcurrentHashMap<>(); + CookieHandler cookieManager = new TestCookieHandler(cookieHeaders); + HttpClient client = HttpClient.newBuilder() + .followRedirects(Redirect.ALWAYS) + .cookieHandler(cookieManager) + .sslContext(sslContext) + .build(); + assert client.cookieHandler().isPresent(); + + URI uri = URI.create(uriString); + List<String> cookies = new ArrayList<>(); + cookies.add("CUSTOMER=ARTHUR_DENT"); + cookies.add("LOCATION=TR\u0100IN_STATION"); + cookies.add("LOC\u0100TION=TRAIN_STATION"); + cookies.add("ORDER=BISCUITS"); + cookieHeaders.put("Cookie", cookies); + String userCookie = "PRICE=42"; + List<String> expectedCookies = + Stream.concat(cookies.stream(), Stream.of(userCookie)).toList(); + + + + HttpRequest.Builder requestBuilder = HttpRequest.newBuilder(uri) + .header("X-uuid", "uuid-" + requestCounter.incrementAndGet()) + .header("Cookie", userCookie); + if (version != null) { + requestBuilder.version(version); + } + HttpRequest request = requestBuilder.build(); + out.println("Initial request: " + request.uri()); + + for (int i=0; i< ITERATIONS; i++) { + out.println("iteration: " + i); + HttpResponse<String> response = client.send(request, BodyHandlers.ofString()); + + out.println(" Got response: " + response); + out.println(" Got body Path: " + response.body()); + + assertEquals(response.statusCode(), 200); + assertEquals(response.body(), MESSAGE); + assertEquals(response.headers().allValues("X-Request-Cookie"), + expectedCookies.stream() + .filter(s -> !s.startsWith("LOC")) + .toList()); + requestBuilder = HttpRequest.newBuilder(uri) + .header("X-uuid", "uuid-" + requestCounter.incrementAndGet()) + .header("Cookie", userCookie); + if (version != null) { + requestBuilder.version(version); + } + request = requestBuilder.build(); + } + } + + // -- Infrastructure + + @BeforeTest + public void setup() throws Exception { + sslContext = new SimpleSSLContext().get(); + if (sslContext == null) + throw new AssertionError("Unexpected null sslContext"); + + InetSocketAddress sa = new InetSocketAddress(InetAddress.getLoopbackAddress(), 0); + + httpTestServer = HttpTestServer.of(HttpServer.create(sa, 0)); + httpTestServer.addHandler(new CookieValidationHandler(), "/http1/cookie/"); + httpURI = "http://" + httpTestServer.serverAuthority() + "/http1/cookie/retry"; + HttpsServer httpsServer = HttpsServer.create(sa, 0); + httpsServer.setHttpsConfigurator(new HttpsConfigurator(sslContext)); + httpsTestServer = HttpTestServer.of(httpsServer); + httpsTestServer.addHandler(new CookieValidationHandler(),"/https1/cookie/"); + httpsURI = "https://" + httpsTestServer.serverAuthority() + "/https1/cookie/retry"; + + http2TestServer = HttpTestServer.of(new Http2TestServer("localhost", false, 0)); + http2TestServer.addHandler(new CookieValidationHandler(), "/http2/cookie/"); + http2URI = "http://" + http2TestServer.serverAuthority() + "/http2/cookie/retry"; + https2TestServer = HttpTestServer.of(new Http2TestServer("localhost", true, sslContext)); + https2TestServer.addHandler(new CookieValidationHandler(), "/https2/cookie/"); + https2URI = "https://" + https2TestServer.serverAuthority() + "/https2/cookie/retry"; + + + // DummyServer + httpDummyServer = DummyServer.create(sa); + httpsDummyServer = DummyServer.create(sa, sslContext); + httpDummy = "http://" + httpDummyServer.serverAuthority() + "/http1/dummy/x"; + httpsDummy = "https://" + httpsDummyServer.serverAuthority() + "/https1/dummy/x"; + + httpTestServer.start(); + httpsTestServer.start(); + http2TestServer.start(); + https2TestServer.start(); + httpDummyServer.start(); + httpsDummyServer.start(); + } + + @AfterTest + public void teardown() throws Exception { + httpTestServer.stop(); + httpsTestServer.stop(); + http2TestServer.stop(); + https2TestServer.stop(); + httpsDummyServer.stopServer(); + httpsDummyServer.stopServer(); + } + + static class TestCookieHandler extends CookieHandler { + + final ConcurrentHashMap<String, List<String>> cookies; + TestCookieHandler(ConcurrentHashMap<String, List<String>> map) { + this.cookies = map; + } + + @java.lang.Override + public Map<String, List<String>> get(URI uri, Map<String, List<String>> requestHeaders) + throws IOException + { + return cookies; + } + + @java.lang.Override + public void put(URI uri, Map<String, List<String>> responseHeaders) + throws IOException + { + // do nothing + } + } + + static class CookieValidationHandler implements HttpTestHandler { + ConcurrentHashMap<String,String> closedRequests = new ConcurrentHashMap<>(); + + @java.lang.Override + public void handle(HttpTestExchange t) throws IOException { + System.out.println("CookieValidationHandler for: " + t.getRequestURI()); + + List<String> uuids = t.getRequestHeaders().get("X-uuid"); + if (uuids == null || uuids.size() != 1) { + readAllRequestData(t); + try (OutputStream os = t.getResponseBody()) { + String msg = "Incorrect uuid header values:[" + uuids + "]"; + (new RuntimeException(msg)).printStackTrace(); + t.sendResponseHeaders(500, -1); + os.write(msg.getBytes(UTF_8)); + } + return; + } + + String uuid = uuids.get(0); + // retrying + if (closedRequests.putIfAbsent(uuid, t.getRequestURI().toString()) == null) { + if (t.getExchangeVersion() == HttpClient.Version.HTTP_1_1) { + // Throwing an exception here only causes a retry + // with HTTP_1_1 - where it forces the server to close + // the connection. + // For HTTP/2 then throwing an IOE would cause the server + // to close the stream, and throwing anything else would + // cause it to close the connection, but neither would + // cause the client to retry. + // So we simply do not try to retry with HTTP/2 and just verify + // we have received the expected cookie + throw new IOException("Closing on first request"); + } + } + + // Check whether this request was upgraded. + // An upgraded request will have a version of HTTP_2 and + // an Upgrade: h2c header + HttpClient.Version version = t.getExchangeVersion(); + List<String> upgrade = t.getRequestHeaders().get("Upgrade"); + if (upgrade == null) upgrade = List.of(); + boolean upgraded = version == HttpClient.Version.HTTP_2 + && upgrade.stream().anyMatch("h2c"::equalsIgnoreCase); + + // not retrying + readAllRequestData(t); + try (OutputStream os = t.getResponseBody()) { + List<String> cookie = t.getRequestHeaders().get("Cookie"); + if (cookie != null) { + if (version == HttpClient.Version.HTTP_1_1 || upgraded) { + if (cookie.size() == 1) { + cookie = List.of(cookie.get(0).split("; ")); + } else if (cookie.size() > 1) { + String msg = "Found multiple 'Cookie:' lines for version=%s (upgraded=%s): %s"; + msg = String.format(msg, version, upgraded, cookie); + (new RuntimeException(msg)).printStackTrace(); + t.sendResponseHeaders(500, -1); + os.write(msg.getBytes(UTF_8)); + return; + } + } + Collections.sort(cookie = new ArrayList<String>(cookie)); + } + if (cookie == null || cookie.size() == 0) { + String msg = "No cookie header present"; + (new RuntimeException(msg)).printStackTrace(); + t.sendResponseHeaders(500, -1); + os.write(msg.getBytes(UTF_8)); + } else if (!cookie.get(0).equals("CUSTOMER=ARTHUR_DENT")) { + String msg = "Incorrect cookie header value:[" + cookie.get(0) + "]"; + (new RuntimeException(msg)).printStackTrace(); + t.sendResponseHeaders(500, -1); + os.write(msg.getBytes(UTF_8)); + } else if (cookie.size() > 1 && !cookie.get(1).equals("ORDER=BISCUITS")) { + String msg = "Incorrect cookie header value:[" + cookie.get(1) + "]"; + (new RuntimeException(msg)).printStackTrace(); + t.sendResponseHeaders(500, -1); + os.write(msg.getBytes(UTF_8)); + } else if (cookie.size() > 2 && !cookie.get(2).equals("PRICE=42")) { + String msg = "Incorrect cookie header value:[" + cookie.get(2) + "]"; + (new RuntimeException(msg)).printStackTrace(); + t.sendResponseHeaders(500, -1); + os.write(msg.getBytes(UTF_8)); + } else if (cookie.size() != 3) { + String msg = "Incorrect cookie header values:[" + cookie + "]"; + (new RuntimeException(msg)).printStackTrace(); + t.sendResponseHeaders(500, -1); + os.write(msg.getBytes(UTF_8)); + } else { + assert cookie.get(0).equals("CUSTOMER=ARTHUR_DENT"); + byte[] bytes = MESSAGE.getBytes(UTF_8); + for (String value : cookie) { + t.getResponseHeaders().addHeader("X-Request-Cookie", value); + } + t.sendResponseHeaders(200, bytes.length); + os.write(bytes); + } + } finally { + closedRequests.remove(uuid); + } + + } + } + + static void readAllRequestData(HttpTestExchange t) throws IOException { + try (InputStream is = t.getRequestBody()) { + is.readAllBytes(); + } + } + + static class DummyServer extends Thread { + final ServerSocket ss; + final boolean secure; + ConcurrentLinkedQueue<Socket> connections = new ConcurrentLinkedQueue<>(); + volatile boolean stopped; + DummyServer(ServerSocket ss, boolean secure) { + super("DummyServer[" + ss.getLocalPort()+"]"); + this.secure = secure; + this.ss = ss; + } + + // This is a bit shaky. It doesn't handle continuation + // lines, but our client shouldn't send any. + // Read a line from the input stream, swallowing the final + // \r\n sequence. Stops at the first \n, doesn't complain + // if it wasn't preceded by '\r'. + // + String readLine(InputStream r) throws IOException { + StringBuilder b = new StringBuilder(); + int c; + while ((c = r.read()) != -1) { + if (c == '\n') break; + b.appendCodePoint(c); + } + if (b.codePointAt(b.length() -1) == '\r') { + b.delete(b.length() -1, b.length()); + } + return b.toString(); + } + + @java.lang.Override + public void run() { + try { + while(!stopped) { + Socket clientConnection = ss.accept(); + connections.add(clientConnection); + System.out.println(now() + getName() + ": Client accepted"); + StringBuilder headers = new StringBuilder(); + Socket targetConnection = null; + InputStream ccis = clientConnection.getInputStream(); + OutputStream ccos = clientConnection.getOutputStream(); + Writer w = new OutputStreamWriter( + clientConnection.getOutputStream(), "UTF-8"); + PrintWriter pw = new PrintWriter(w); + System.out.println(now() + getName() + ": Reading request line"); + String requestLine = readLine(ccis); + System.out.println(now() + getName() + ": Request line: " + requestLine); + + StringTokenizer tokenizer = new StringTokenizer(requestLine); + String method = tokenizer.nextToken(); + assert method.equalsIgnoreCase("POST") || method.equalsIgnoreCase("GET"); + String path = tokenizer.nextToken(); + URI uri; + try { + String hostport = serverAuthority(); + uri = new URI((secure ? "https" : "http") +"://" + hostport + path); + } catch (Throwable x) { + System.err.printf("Bad target address: \"%s\" in \"%s\"%n", + path, requestLine); + clientConnection.close(); + continue; + } + + // Read all headers until we find the empty line that + // signals the end of all headers. + String line = requestLine; + String cookies = null; + while (!line.equals("")) { + System.out.println(now() + getName() + ": Reading header: " + + (line = readLine(ccis))); + if (line.startsWith("Cookie:")) { + if (cookies == null) cookies = line; + else cookies = cookies + "\n" + line; + } + headers.append(line).append("\r\n"); + } + + StringBuilder response = new StringBuilder(); + StringBuilder xheaders = new StringBuilder(); + + int index = headers.toString() + .toLowerCase(Locale.US) + .indexOf("content-length: "); + if (index >= 0) { + index = index + "content-length: ".length(); + String cl = headers.toString().substring(index); + StringTokenizer tk = new StringTokenizer(cl); + int len = Integer.parseInt(tk.nextToken()); + System.out.println(now() + getName() + + ": received body: " + + new String(ccis.readNBytes(len), UTF_8)); + } + String resp = MESSAGE; + String status = "200 OK"; + if (cookies == null) { + resp = "No cookies found in headers"; + status = "500 Internal Server Error"; + } else if (cookies.contains("\n")) { + resp = "More than one 'Cookie:' line found: " + + Arrays.asList(cookies.split("\n")); + status = "500 Internal Server Error"; + } else { + List<String> values = + Stream.of(cookies.substring("Cookie:".length()).trim().split("; ")) + .map(String::trim) + .collect(Collectors.toList()); + Collections.sort(values); + if (values.size() != 3) { + resp = "Bad cookie list: " + values; + status = "500 Internal Server Error"; + } else if (!values.get(0).equals("CUSTOMER=ARTHUR_DENT")) { + resp = "Unexpected cookie: " + values.get(0) + " in " + values; + status = "500 Internal Server Error"; + } else if (!values.get(1).equals("ORDER=BISCUITS")) { + resp = "Unexpected cookie: " + values.get(1) + " in " + values; + status = "500 Internal Server Error"; + } else if (!values.get(2).equals("PRICE=42")) { + resp = "Unexpected cookie: " + values.get(1) + " in " + values; + status = "500 Internal Server Error"; + } else { + for (String cookie : values) { + xheaders.append("X-Request-Cookie: ") + .append(cookie) + .append("\r\n"); + } + } + } + byte[] b = resp.getBytes(UTF_8); + System.out.println(now() + + getName() + ": sending back " + uri); + + response.append("HTTP/1.1 ") + .append(status) + .append("\r\nContent-Length: ") + .append(b.length) + .append("\r\n") + .append(xheaders) + .append("\r\n"); + + // Then send the 200 OK response to the client + System.out.println(now() + getName() + ": Sending " + + response); + pw.print(response); + pw.flush(); + ccos.write(b); + ccos.flush(); + ccos.close(); + connections.remove(clientConnection); + clientConnection.close(); + } + } catch (Throwable t) { + if (!stopped) { + System.out.println(now() + getName() + ": failed: " + t); + t.printStackTrace(); + try { + stopServer(); + } catch (Throwable e) { + + } + } + } finally { + System.out.println(now() + getName() + ": exiting"); + } + } + + void close(Socket s) { + try { + s.close(); + } catch(Throwable t) { + + } + } + public void stopServer() throws IOException { + stopped = true; + ss.close(); + connections.forEach(this::close); + } + + public String serverAuthority() { + return InetAddress.getLoopbackAddress().getHostName() + ":" + + ss.getLocalPort(); + } + + static DummyServer create(InetSocketAddress sa) throws IOException { + ServerSocket ss = ServerSocketFactory.getDefault() + .createServerSocket(sa.getPort(), -1, sa.getAddress()); + return new DummyServer(ss, false); + } + + static DummyServer create(InetSocketAddress sa, SSLContext sslContext) throws IOException { + ServerSocket ss = sslContext.getServerSocketFactory() + .createServerSocket(sa.getPort(), -1, sa.getAddress()); + return new DummyServer(ss, true); + } + + + } +} diff --git a/test/jdk/java/net/httpclient/http2/server/Http2TestServer.java b/test/jdk/java/net/httpclient/http2/server/Http2TestServer.java index 33e5ade4f8340d89c7c5a81a278b0faef65b49cf..f8592272588781d37dac70a26600d8ac6f5b5239 100644 --- a/test/jdk/java/net/httpclient/http2/server/Http2TestServer.java +++ b/test/jdk/java/net/httpclient/http2/server/Http2TestServer.java @@ -124,6 +124,20 @@ public class Http2TestServer implements AutoCloseable { this(serverName, secure, port, exec, backlog, properties, context, false); } + public Http2TestServer(String serverName, + boolean secure, + int port, + ExecutorService exec, + int backlog, + Properties properties, + SSLContext context, + boolean supportsHTTP11) + throws Exception + { + this(InetAddress.getLoopbackAddress(), serverName, secure, port, exec, + backlog, properties, context, supportsHTTP11); + } + /** * Create a Http2Server listening on the given port. Currently needs * to know in advance whether incoming connections are plain TCP "h2c" @@ -134,6 +148,7 @@ public class Http2TestServer implements AutoCloseable { * "X-Magic", "HTTP/1.1 request received by HTTP/2 server", * "X-Received-Body", <the request body>); * + * @param localAddr local address to bind to * @param serverName SNI servername * @param secure https or http * @param port listen port @@ -146,7 +161,8 @@ public class Http2TestServer implements AutoCloseable { * connection without the h2 ALPN. Otherwise, false to operate in * HTTP/2 mode exclusively. */ - public Http2TestServer(String serverName, + public Http2TestServer(InetAddress localAddr, + String serverName, boolean secure, int port, ExecutorService exec, @@ -163,7 +179,7 @@ public class Http2TestServer implements AutoCloseable { this.sslContext = context; else this.sslContext = SSLContext.getDefault(); - server = initSecure(port, backlog); + server = initSecure(localAddr, port, backlog); } else { this.sslContext = context; server = initPlaintext(port, backlog); @@ -236,14 +252,14 @@ public class Http2TestServer implements AutoCloseable { } - final ServerSocket initSecure(int port, int backlog) throws Exception { + final ServerSocket initSecure(InetAddress localAddr, int port, int backlog) throws Exception { ServerSocketFactory fac; SSLParameters sslp = null; fac = sslContext.getServerSocketFactory(); sslp = sslContext.getSupportedSSLParameters(); SSLServerSocket se = (SSLServerSocket) fac.createServerSocket(); se.setReuseAddress(false); - se.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0), backlog); + se.bind(new InetSocketAddress(localAddr, 0), backlog); if (supportsHTTP11) { sslp.setApplicationProtocols(new String[]{"h2", "http/1.1"}); } else { diff --git a/test/jdk/java/net/httpclient/reactivestreams-tck/org/reactivestreams/tck/flow/support/PublisherVerificationRules.java b/test/jdk/java/net/httpclient/reactivestreams-tck/org/reactivestreams/tck/flow/support/PublisherVerificationRules.java index 823a5174652c5fe03b6d232e658c70ea91037892..3af007cb9e1a190617ee5ecbf6a726ce6d008893 100644 --- a/test/jdk/java/net/httpclient/reactivestreams-tck/org/reactivestreams/tck/flow/support/PublisherVerificationRules.java +++ b/test/jdk/java/net/httpclient/reactivestreams-tck/org/reactivestreams/tck/flow/support/PublisherVerificationRules.java @@ -126,7 +126,7 @@ public interface PublisherVerificationRules { * <p> * The test is not executed if {@link org.reactivestreams.tck.PublisherVerification#maxElementsFromPublisher()} is less than 10. * <p> - * Note that this test is probabilistic, that is, may not capture any concurrent invocation in a {code Publisher} implementation. + * Note that this test is probabilistic, that is, may not capture any concurrent invocation in a {@code Publisher} implementation. * Note also that this test is sensitive to cases when a {@code request()} call in {@code onSubscribe()} triggers an asynchronous * call to the other {@code onXXX} methods. In contrast, the test allows synchronous call chain of * {@code onSubscribe -> request -> onNext}. diff --git a/test/jdk/java/nio/channels/AsynchronousFileChannel/Basic.java b/test/jdk/java/nio/channels/AsynchronousFileChannel/Basic.java index 55de744c0dbed3e93c25d62fa29d45b8869dab90..0beffac0ed515a5c41185fb96ac11a45bcccef44 100644 --- a/test/jdk/java/nio/channels/AsynchronousFileChannel/Basic.java +++ b/test/jdk/java/nio/channels/AsynchronousFileChannel/Basic.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 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 @@ -22,18 +22,37 @@ */ /* @test - * @bug 4607272 6822643 6830721 6842687 + * @bug 4607272 5041655 6822643 6830721 6842687 * @summary Unit test for AsynchronousFileChannel * @key randomness */ -import java.nio.file.*; -import java.nio.channels.*; -import java.nio.ByteBuffer; import java.io.File; import java.io.IOException; -import java.util.*; -import java.util.concurrent.*; +import java.nio.ByteBuffer; +import java.nio.channels.AsynchronousCloseException; +import java.nio.channels.AsynchronousFileChannel; +import java.nio.channels.ClosedChannelException; +import java.nio.channels.CompletionHandler; +import java.nio.channels.FileLock; +import java.nio.channels.NonWritableChannelException; +import java.nio.channels.OverlappingFileLockException; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; +import java.util.ArrayList; +import java.util.EnumSet; +import java.util.List; +import java.util.Random; +import java.util.Set; +import java.util.concurrent.CancellationException; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executors; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.TimeoutException;; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; import static java.nio.file.StandardOpenOption.*; @@ -176,7 +195,12 @@ public class Basic { // test 1 - acquire lock and check that tryLock throws // OverlappingFileLockException try { - fl = ch.lock().get(); + long pos = rand.nextInt(Integer.MAX_VALUE); + fl = ch.lock(pos, 0, false).get(); + long expectedSize = Long.MAX_VALUE - pos; + if(fl.size() != expectedSize) + throw new RuntimeException("Lock size " + fl.size() + + " != " + expectedSize + " for position " + pos); } catch (ExecutionException x) { throw new RuntimeException(x); } catch (InterruptedException x) { @@ -192,7 +216,12 @@ public class Basic { fl.release(); // test 2 - acquire try and check that lock throws OverlappingFileLockException - fl = ch.tryLock(); + long pos = rand.nextInt(Integer.MAX_VALUE); + fl = ch.tryLock(pos, 0, false); + long expectedSize = Long.MAX_VALUE - pos; + if(fl.size() != expectedSize) + throw new RuntimeException("Lock size " + fl.size() + " != " + + expectedSize + " for position " + pos); if (fl == null) throw new RuntimeException("Unable to acquire lock"); try { diff --git a/test/jdk/java/nio/channels/Channels/ReadXBytes.java b/test/jdk/java/nio/channels/Channels/ReadXBytes.java index 1f36d4031fd09f9af4a490c9182a8f51efd8cad5..f146d629da189e4812d6e9212daaab99c82c66d1 100644 --- a/test/jdk/java/nio/channels/Channels/ReadXBytes.java +++ b/test/jdk/java/nio/channels/Channels/ReadXBytes.java @@ -25,12 +25,12 @@ * @test * @bug 8268435 8274780 * @summary Verify ChannelInputStream methods readAllBytes and readNBytes - * @requires vm.bits == 64 + * @requires (sun.arch.data.model == "64" & os.maxMemory >= 16g) * @library .. * @library /test/lib * @build jdk.test.lib.RandomFactory * @modules java.base/jdk.internal.util - * @run testng/othervm/timeout=900 -Xmx8G ReadXBytes + * @run testng/othervm/timeout=900 -Xmx12G ReadXBytes * @key randomness */ import java.io.File; @@ -38,7 +38,7 @@ import java.io.FileInputStream; import java.io.FilterInputStream; import java.io.InputStream; import java.io.IOException; -import java.io.RandomAccessFile; +import java.nio.ByteBuffer; import java.nio.channels.Channel; import java.nio.channels.Channels; import java.nio.channels.FileChannel; @@ -46,11 +46,12 @@ import java.nio.channels.ReadableByteChannel; import java.nio.channels.SeekableByteChannel; import java.nio.file.Files; import java.nio.file.Path; -import static java.nio.file.StandardOpenOption.READ; import java.util.List; import java.util.Random; import jdk.internal.util.ArraysSupport; +import static java.nio.file.StandardOpenOption.*; + import jdk.test.lib.RandomFactory; import org.testng.Assert; @@ -72,30 +73,51 @@ public class ReadXBytes { // A length greater than a 32-bit integer can accommodate private static final long HUGE_LENGTH = Integer.MAX_VALUE + 27L; + // Current directory + private static final Path DIR = Path.of(System.getProperty("test.dir", ".")); + // --- Framework --- + // Create a temporary file path + static Path createFilePath() { + String name = String.format("ReadXBytes%d.tmp", System.nanoTime()); + return DIR.resolve(name); + } + // Creates a temporary file of a specified length with undefined content static Path createFile(long length) throws IOException { - File file = File.createTempFile("foo", ".bar"); - file.deleteOnExit(); - try (RandomAccessFile raf = new RandomAccessFile(file, "rw")) { - raf.setLength(length); + Path path = createFilePath(); + path.toFile().deleteOnExit(); + try (FileChannel fc = FileChannel.open(path, CREATE_NEW, SPARSE, WRITE)) { + if (length > 0) { + fc.position(length - 1); + fc.write(ByteBuffer.wrap(new byte[] {27})); + } } - return file.toPath(); + return path; } // Creates a temporary file of a specified length with random content static Path createFileWithRandomContent(long length) throws IOException { Path file = createFile(length); - try (RandomAccessFile raf = new RandomAccessFile(file.toFile(), "rw")) { - long written = 0L; - int bufLength = Math.min(32768, (int)Math.min(length, BIG_LENGTH)); + try (FileChannel fc = FileChannel.open(file, WRITE);) { + long pos = 0L; + // if the length exceeds 2 GB, skip the first 2 GB - 1 MB bytes + if (length >= 2L*1024*1024*1024) { + // write the last (length - 2GB - 1MB) bytes + pos = 2047L*1024*1024; + } else if (length > 0) { + // write either the first or last bytes only + long p = Math.min(Math.abs(RAND.nextLong()), length - 1); + pos = RAND.nextBoolean() ? p : length - 1 - p; + } + fc.position(pos); + int bufLength = Math.min(32768, (int)Math.min(length - pos, BIG_LENGTH)); byte[] buf = new byte[bufLength]; - while (written < length) { + while (pos < length) { RAND.nextBytes(buf); - int len = (int)Math.min(bufLength, length - written); - raf.write(buf, 0, len); - written += len; + int len = (int)Math.min(bufLength, length - pos); + pos += fc.write(ByteBuffer.wrap(buf, 0, len)); } } return file; diff --git a/test/jdk/java/nio/channels/Channels/SocketChannelStreams.java b/test/jdk/java/nio/channels/Channels/SocketChannelStreams.java new file mode 100644 index 0000000000000000000000000000000000000000..57142fb03d74b6fb368907aa6dd594887bdae48a --- /dev/null +++ b/test/jdk/java/nio/channels/Channels/SocketChannelStreams.java @@ -0,0 +1,480 @@ +/* + * 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. + */ + +/* @test + * @bug 8279339 + * @run testng SocketChannelStreams + * @summary Exercise InputStream/OutputStream returned by Channels.newXXXStream + * when channel is a SocketChannel + */ + +import java.io.Closeable; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.nio.channels.Channels; +import java.nio.channels.IllegalBlockingModeException; +import java.nio.channels.ServerSocketChannel; +import java.nio.channels.SocketChannel; +import java.util.Objects; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +import org.testng.annotations.*; +import static org.testng.Assert.*; + +@Test +public class SocketChannelStreams { + private ScheduledExecutorService executor; + + @BeforeClass() + public void init() { + executor = Executors.newSingleThreadScheduledExecutor(); + } + + @AfterClass + public void finish() { + executor.shutdown(); + } + + /** + * Test read when bytes are available. + */ + public void testRead1() throws Exception { + withConnection((sc, peer) -> { + write(peer, 99); + int n = Channels.newInputStream(sc).read(); + assertEquals(n, 99); + }); + } + + /** + * Test read blocking before bytes are available. + */ + public void testRead2() throws Exception { + withConnection((sc, peer) -> { + scheduleWrite(peer, 99, 1000); + int n = Channels.newInputStream(sc).read(); + assertEquals(n, 99); + }); + } + + /** + * Test read after peer has closed connection. + */ + public void testRead3() throws Exception { + withConnection((sc, peer) -> { + peer.close(); + int n = Channels.newInputStream(sc).read(); + assertEquals(n, -1); + }); + } + + /** + * Test read blocking before peer closes connection. + */ + public void testRead4() throws Exception { + withConnection((sc, peer) -> { + scheduleClose(peer, 1000); + int n = Channels.newInputStream(sc).read(); + assertEquals(n, -1); + }); + } + + /** + * Test async close of channel when thread blocked in read. + */ + public void testRead5() throws Exception { + withConnection((sc, peer) -> { + scheduleClose(sc, 2000); + InputStream in = Channels.newInputStream(sc); + expectThrows(IOException.class, () -> in.read()); + }); + } + + /** + * Test async close of input stream, when thread blocked in read. + */ + public void testRead6() throws Exception { + withConnection((sc, peer) -> { + InputStream in = Channels.newInputStream(sc); + scheduleClose(in, 2000); + expectThrows(IOException.class, () -> in.read()); + }); + } + + /** + * Test interrupt status set before read. + */ + public void testRead7() throws Exception { + withConnection((sc, peer) -> { + Thread.currentThread().interrupt(); + try { + InputStream in = Channels.newInputStream(sc); + expectThrows(IOException.class, () -> in.read()); + } finally { + Thread.interrupted(); // clear interrupt + } + assertFalse(sc.isOpen()); + }); + } + + /** + * Test interrupt of thread blocked in read. + */ + public void testRead8() throws Exception { + withConnection((sc, peer) -> { + Future<?> interrupter = scheduleInterrupt(Thread.currentThread(), 2000); + try { + InputStream in = Channels.newInputStream(sc); + expectThrows(IOException.class, () -> in.read()); + } finally { + interrupter.cancel(true); + Thread.interrupted(); // clear interrupt + } + assertFalse(sc.isOpen()); + }); + } + + /** + * Test that read is untimed when SO_TIMEOUT is set on the Socket adaptor. + */ + public void testRead9() throws Exception { + withConnection((sc, peer) -> { + sc.socket().setSoTimeout(100); + scheduleWrite(peer, 99, 2000); + // read should block until bytes are available + int b = Channels.newInputStream(sc).read(); + assertTrue(b == 99); + }); + } + + /** + * Test write. + */ + public void testWrite1() throws Exception { + withConnection((sc, peer) -> { + OutputStream out = Channels.newOutputStream(sc); + out.write(99); + int n = read(peer); + assertEquals(n, 99); + }); + } + + /** + * Test async close of channel when thread blocked in write. + */ + public void testWrite2() throws Exception { + withConnection((sc, peer) -> { + scheduleClose(sc, 2000); + expectThrows(IOException.class, () -> { + OutputStream out = Channels.newOutputStream(sc); + byte[] data = new byte[64*1000]; + while (true) { + out.write(data); + } + }); + }); + } + + /** + * Test async close of output stream when thread blocked in write. + */ + public void testWrite3() throws Exception { + withConnection((sc, peer) -> { + OutputStream out = Channels.newOutputStream(sc); + scheduleClose(out, 2000); + expectThrows(IOException.class, () -> { + byte[] data = new byte[64*1000]; + while (true) { + out.write(data); + } + }); + }); + } + + /** + * Test interrupt status set before write. + */ + public void testWrite4() throws Exception { + withConnection((sc, peer) -> { + Thread.currentThread().interrupt(); + try { + OutputStream out = Channels.newOutputStream(sc); + expectThrows(IOException.class, () -> out.write(99)); + } finally { + Thread.interrupted(); // clear interrupt + } + assertFalse(sc.isOpen()); + }); + } + + /** + * Test interrupt of thread blocked in write. + */ + public void testWrite5() throws Exception { + withConnection((sc, peer) -> { + Future<?> interrupter = scheduleInterrupt(Thread.currentThread(), 2000); + try { + expectThrows(IOException.class, () -> { + OutputStream out = Channels.newOutputStream(sc); + byte[] data = new byte[64*1000]; + while (true) { + out.write(data); + } + }); + } finally { + interrupter.cancel(true); + Thread.interrupted(); // clear interrupt + } + assertFalse(sc.isOpen()); + }); + } + + /** + * Test read when another thread is blocked in write. The read should + * complete immediately. + */ + public void testConcurrentReadWrite1() throws Exception { + withConnection((sc, peer) -> { + InputStream in = Channels.newInputStream(sc); + OutputStream out = Channels.newOutputStream(sc); + + // block thread in write + fork(() -> { + var data = new byte[64*1024]; + for (;;) { + out.write(data); + } + }); + Thread.sleep(1000); // give writer time to block + + // test read, should not be blocked by writer thread + write(peer, 99); + int n = in.read(); + assertEquals(n, 99); + }); + } + + /** + * Test read when another thread is blocked in write. The read should + * block until bytes are available. + */ + public void testConcurrentReadWrite2() throws Exception { + withConnection((sc, peer) -> { + InputStream in = Channels.newInputStream(sc); + OutputStream out = Channels.newOutputStream(sc); + + // block thread in write + fork(() -> { + var data = new byte[64*1024]; + for (;;) { + out.write(data); + } + }); + Thread.sleep(1000); // give writer time to block + + // test read, should not be blocked by writer thread + scheduleWrite(peer, 99, 500); + int n = in.read(); + assertEquals(n, 99); + }); + } + + /** + * Test writing when another thread is blocked in read. + */ + public void testConcurrentReadWrite3() throws Exception { + withConnection((sc, peer) -> { + InputStream in = Channels.newInputStream(sc); + OutputStream out = Channels.newOutputStream(sc); + + // block thread in read + fork(() -> { + in.read(); + }); + Thread.sleep(100); // give reader time to block + + // test write, should not be blocked by reader thread + out.write(99); + int n = read(peer); + assertEquals(n, 99); + }); + } + + /** + * Test read/write when channel configured non-blocking. + */ + public void testIllegalBlockingMode() throws Exception { + withConnection((sc, peer) -> { + InputStream in = Channels.newInputStream(sc); + OutputStream out = Channels.newOutputStream(sc); + + sc.configureBlocking(false); + expectThrows(IllegalBlockingModeException.class, () -> in.read()); + expectThrows(IllegalBlockingModeException.class, () -> out.write(99)); + }); + } + + /** + * Test NullPointerException. + */ + public void testNullPointerException() throws Exception { + withConnection((sc, peer) -> { + InputStream in = Channels.newInputStream(sc); + OutputStream out = Channels.newOutputStream(sc); + + expectThrows(NullPointerException.class, () -> in.read(null)); + expectThrows(NullPointerException.class, () -> in.read(null, 0, 0)); + + expectThrows(NullPointerException.class, () -> out.write(null)); + expectThrows(NullPointerException.class, () -> out.write(null, 0, 0)); + }); + } + + /** + * Test IndexOutOfBoundsException. + */ + public void testIndexOutOfBoundsException() throws Exception { + withConnection((sc, peer) -> { + InputStream in = Channels.newInputStream(sc); + OutputStream out = Channels.newOutputStream(sc); + byte[] ba = new byte[100]; + + expectThrows(IndexOutOfBoundsException.class, () -> in.read(ba, -1, 1)); + expectThrows(IndexOutOfBoundsException.class, () -> in.read(ba, 0, -1)); + expectThrows(IndexOutOfBoundsException.class, () -> in.read(ba, 0, 1000)); + expectThrows(IndexOutOfBoundsException.class, () -> in.read(ba, 1, 100)); + + expectThrows(IndexOutOfBoundsException.class, () -> out.write(ba, -1, 1)); + expectThrows(IndexOutOfBoundsException.class, () -> out.write(ba, 0, -1)); + expectThrows(IndexOutOfBoundsException.class, () -> out.write(ba, 0, 1000)); + expectThrows(IndexOutOfBoundsException.class, () -> out.write(ba, 1, 100)); + }); + } + + // -- test infrastructure -- + + private interface ThrowingTask { + void run() throws Exception; + } + + private interface ThrowingBiConsumer<T, U> { + void accept(T t, U u) throws Exception; + } + + /** + * Invokes the consumer with a connected pair of socket channels. + */ + private static void withConnection(ThrowingBiConsumer<SocketChannel, SocketChannel> consumer) + throws Exception + { + var loopback = InetAddress.getLoopbackAddress(); + try (ServerSocketChannel listener = ServerSocketChannel.open()) { + listener.bind(new InetSocketAddress(loopback, 0)); + try (SocketChannel sc = SocketChannel.open(listener.getLocalAddress())) { + try (SocketChannel peer = listener.accept()) { + consumer.accept(sc, peer); + } + } + } + } + + /** + * Forks a thread to execute the given task. + */ + private Future<?> fork(ThrowingTask task) { + ExecutorService pool = Executors.newFixedThreadPool(1); + try { + return pool.submit(() -> { + task.run(); + return null; + }); + } finally { + pool.shutdown(); + } + } + + /** + * Read a byte from the given socket channel. + */ + private int read(SocketChannel sc) throws IOException { + return sc.socket().getInputStream().read(); + } + + /** + * Write a byte to the given socket channel. + */ + private void write(SocketChannel sc, int b) throws IOException { + sc.socket().getOutputStream().write(b); + } + + /** + * Writes the given data to the socket channel after a delay. + */ + private Future<?> scheduleWrite(SocketChannel sc, byte[] data, long delay) { + return schedule(() -> { + try { + sc.socket().getOutputStream().write(data); + } catch (IOException ioe) { } + }, delay); + } + + /** + * Writes a byte to the socket channel after a delay. + */ + private Future<?> scheduleWrite(SocketChannel sc, int b, long delay) { + return scheduleWrite(sc, new byte[] { (byte)b }, delay); + } + + /** + * Closes the given object after a delay. + */ + private Future<?> scheduleClose(Closeable c, long delay) { + return schedule(() -> { + try { + c.close(); + } catch (IOException ioe) { } + }, delay); + } + + /** + * Interrupts the given Thread after a delay. + */ + private Future<?> scheduleInterrupt(Thread t, long delay) { + return schedule(() -> t.interrupt(), delay); + } + + /** + * Schedules the given task to run after a delay. + */ + private Future<?> schedule(Runnable task, long delay) { + return executor.schedule(task, delay, TimeUnit.MILLISECONDS); + } +} diff --git a/test/jdk/java/nio/channels/Channels/TransferTo.java b/test/jdk/java/nio/channels/Channels/TransferTo.java index 792419c2ff3ac762857d9c4ded819d8eff81ceb9..e7fa169788c3bb57847df5ea115b442d9b5b5d3e 100644 --- a/test/jdk/java/nio/channels/Channels/TransferTo.java +++ b/test/jdk/java/nio/channels/Channels/TransferTo.java @@ -23,16 +23,25 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; -import java.io.IOException; import java.io.InputStream; +import java.io.IOException; import java.io.OutputStream; +import java.nio.ByteBuffer; import java.nio.channels.Channels; import java.nio.channels.FileChannel; +import java.nio.channels.IllegalBlockingModeException; +import java.nio.channels.Pipe; +import java.nio.channels.ReadableByteChannel; +import java.nio.channels.SelectableChannel; +import java.nio.channels.WritableByteChannel; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardOpenOption; import java.util.Arrays; import java.util.Random; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; import java.util.function.Supplier; @@ -43,6 +52,7 @@ import org.testng.annotations.Test; import jdk.test.lib.RandomFactory; import static java.lang.String.format; +import static java.nio.file.StandardOpenOption.*; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertThrows; @@ -54,8 +64,8 @@ import static org.testng.Assert.assertTrue; * @build jdk.test.lib.RandomFactory * @run testng/othervm/timeout=180 TransferTo * @bug 8265891 - * @summary tests whether sun.nio.ChannelInputStream.transferTo conforms to the - * InputStream.transferTo contract defined in the javadoc + * @summary Tests whether sun.nio.ChannelInputStream.transferTo conforms to the + * InputStream.transferTo specification * @key randomness */ public class TransferTo { @@ -64,14 +74,17 @@ public class TransferTo { private static final int ITERATIONS = 10; - private static final int NUM_WRITES = 3 * 1024; - private static final int BYTES_PER_WRITE = 1024 * 1024; - private static final long BYTES_WRITTEN = (long) NUM_WRITES * BYTES_PER_WRITE; + private static final int NUM_WRITES = 3*1024; + private static final int BYTES_PER_WRITE = 1024*1024; + private static final long BYTES_WRITTEN = (long) NUM_WRITES*BYTES_PER_WRITE; private static final Random RND = RandomFactory.getRandom(); + private static final Path CWD = Path.of("."); + /* - * Provides test scenarios, i. e. combinations of input and output streams to be tested. + * Provides test scenarios, i.e., combinations of input and output streams + * to be tested. */ @DataProvider public static Object[][] streamCombinations() throws Exception { @@ -79,13 +92,22 @@ public class TransferTo { // tests FileChannel.transferTo(FileChannel) optimized case { fileChannelInput(), fileChannelOutput() }, + // tests FileChannel.transferTo(SelectableChannelOutput) + // optimized case + { fileChannelInput(), selectableChannelOutput() }, + + // tests FileChannel.transferTo(WritableChannelOutput) + // optimized case + { fileChannelInput(), writableByteChannelOutput() }, + // tests InputStream.transferTo(OutputStream) default case { readableByteChannelInput(), defaultOutput() } }; } /* - * Testing API compliance: Input stream must throw NullPointerException when parameter "out" is null. + * Testing API compliance: input stream must throw NullPointerException + * when parameter "out" is null. */ @Test(dataProvider = "streamCombinations") public void testNullPointerException(InputStreamProvider inputStreamProvider, @@ -101,7 +123,8 @@ public class TransferTo { } /* - * Testing API compliance: Complete content of input stream must be transferred to output stream. + * Testing API compliance: complete content of input stream must be + * transferred to output stream. */ @Test(dataProvider = "streamCombinations") public void testStreamContents(InputStreamProvider inputStreamProvider, @@ -112,10 +135,12 @@ public class TransferTo { // tests input stream with a length between 1k and 4k checkTransferredContents(inputStreamProvider, outputStreamProvider, createRandomBytes(1024, 4096)); - // tests input stream with several data chunks, as 16k is more than a single chunk can hold + // tests input stream with several data chunks, as 16k is more than a + // single chunk can hold checkTransferredContents(inputStreamProvider, outputStreamProvider, createRandomBytes(16384, 16384)); - // tests randomly chosen starting positions within source and target stream + // tests randomly chosen starting positions within source and + // target stream for (int i = 0; i < ITERATIONS; i++) { byte[] inBytes = createRandomBytes(MIN_SIZE, MAX_SIZE_INCR); int posIn = RND.nextInt(inBytes.length); @@ -131,34 +156,60 @@ public class TransferTo { } /* - * Special test for file-to-file transfer of more than two GB. - * This test covers multiple iterations of FileChannel.transerTo(FileChannel), - * which ChannelInputStream.transferTo() only applies in this particular case, - * and cannot get tested using a single byte[] due to size limitation of arrays. + * Special test for file-to-file transfer of more than 2 GB. This test + * covers multiple iterations of FileChannel.transerTo(FileChannel), + * which ChannelInputStream.transferTo() only applies in this particular + * case, and cannot get tested using a single byte[] due to size limitation + * of arrays. */ @Test public void testMoreThanTwoGB() throws IOException { - Path sourceFile = Files.createTempFile("test2GBSource", null); + // prepare two temporary files to be compared at the end of the test + // set the source file name + String sourceName = String.format("test3GBSource%s.tmp", + String.valueOf(RND.nextInt(Integer.MAX_VALUE))); + Path sourceFile = CWD.resolve(sourceName); + try { - // preparing two temporary files which will be compared at the end of the test - Path targetFile = Files.createTempFile("test2GBtarget", null); + // set the target file name + String targetName = String.format("test3GBTarget%s.tmp", + String.valueOf(RND.nextInt(Integer.MAX_VALUE))); + Path targetFile = CWD.resolve(targetName); + try { - // writing 3 GB of random bytes into source file - for (int i = 0; i < NUM_WRITES; i++) - Files.write(sourceFile, createRandomBytes(BYTES_PER_WRITE, 0), StandardOpenOption.APPEND); + // calculate initial position to be just short of 2GB + final long initPos = 2047*BYTES_PER_WRITE; + + // create the source file with a hint to be sparse + try (FileChannel fc = FileChannel.open(sourceFile, CREATE_NEW, SPARSE, WRITE, APPEND);) { + // set initial position to avoid writing nearly 2GB + fc.position(initPos); + + // fill the remainder of the file with random bytes + int nw = (int)(NUM_WRITES - initPos/BYTES_PER_WRITE); + for (int i = 0; i < nw; i++) { + byte[] rndBytes = createRandomBytes(BYTES_PER_WRITE, 0); + ByteBuffer src = ByteBuffer.wrap(rndBytes); + fc.write(src); + } + } - // performing actual transfer, effectively by multiple invocations of Filechannel.transferTo(FileChannel) - long count; - try (InputStream inputStream = Channels.newInputStream(FileChannel.open(sourceFile)); - OutputStream outputStream = Channels - .newOutputStream(FileChannel.open(targetFile, StandardOpenOption.WRITE))) { - count = inputStream.transferTo(outputStream); + // create the target file with a hint to be sparse + try (FileChannel fc = FileChannel.open(targetFile, CREATE_NEW, WRITE, SPARSE);) { } - // comparing reported transferred bytes, must be 3 GB - assertEquals(count, BYTES_WRITTEN); + // perform actual transfer, effectively by multiple invocations + // of Filechannel.transferTo(FileChannel) + try (InputStream inputStream = Channels.newInputStream(FileChannel.open(sourceFile)); + OutputStream outputStream = Channels.newOutputStream(FileChannel.open(targetFile, WRITE))) { + long count = inputStream.transferTo(outputStream); - // comparing content of both files, failing in case of any difference + // compare reported transferred bytes, must be 3 GB + // less the value of the initial position + assertEquals(count, BYTES_WRITTEN - initPos); + } + + // compare content of both files, failing if different assertEquals(Files.mismatch(sourceFile, targetFile), -1); } finally { @@ -170,9 +221,45 @@ public class TransferTo { } /* - * Asserts that the transferred content is correct, i. e. compares the actually transferred bytes - * to the expected assumption. The position of the input and output stream before the transfer is - * the start of stream (BOF). + * Special test of whether selectable channel based transfer throws blocking + * mode exception. + */ + @Test + public void testIllegalBlockingMode() throws IOException { + Pipe pipe = Pipe.open(); + try { + // testing arbitrary input (here: empty file) to non-blocking + // selectable output + try (FileChannel fc = FileChannel.open(Files.createTempFile(CWD, "testIllegalBlockingMode", null)); + InputStream is = Channels.newInputStream(fc); + SelectableChannel sc = pipe.sink().configureBlocking(false); + OutputStream os = Channels.newOutputStream((WritableByteChannel) sc)) { + + // IllegalBlockingMode must be thrown when trying to perform + // a transfer + assertThrows(IllegalBlockingModeException.class, () -> is.transferTo(os)); + } + + // testing non-blocking selectable input to arbitrary output + // (here: byte array) + try (SelectableChannel sc = pipe.source().configureBlocking(false); + InputStream is = Channels.newInputStream((ReadableByteChannel) sc); + OutputStream os = new ByteArrayOutputStream()) { + + // IllegalBlockingMode must be thrown when trying to perform + // a transfer + assertThrows(IllegalBlockingModeException.class, () -> is.transferTo(os)); + } + } finally { + pipe.source().close(); + pipe.sink().close(); + } + } + + /* + * Asserts that the transferred content is correct, i.e., compares the bytes + * actually transferred to those expected. The position of the input and + * output streams before the transfer are zero (BOF). */ private static void checkTransferredContents(InputStreamProvider inputStreamProvider, OutputStreamProvider outputStreamProvider, byte[] inBytes) throws Exception { @@ -180,16 +267,16 @@ public class TransferTo { } /* - * Asserts that the transferred content is correct, i. e. compares the actually transferred bytes - * to the expected assumption. The position of the input and output stream before the transfer is - * provided by the caller. + * Asserts that the transferred content is correct, i. e. compares the bytes + * actually transferred to those expected. The positions of the input and + * output streams before the transfer are provided by the caller. */ private static void checkTransferredContents(InputStreamProvider inputStreamProvider, OutputStreamProvider outputStreamProvider, byte[] inBytes, int posIn, int posOut) throws Exception { AtomicReference<Supplier<byte[]>> recorder = new AtomicReference<>(); try (InputStream in = inputStreamProvider.input(inBytes); - OutputStream out = outputStreamProvider.output(recorder::set)) { - // skip bytes till starting position + OutputStream out = outputStreamProvider.output(recorder::set)) { + // skip bytes until starting position in.skipNBytes(posIn); out.write(new byte[posOut]); @@ -205,7 +292,8 @@ public class TransferTo { } /* - * Creates an array of random size (between min and min + maxRandomAdditive) filled with random bytes + * Creates an array of random size (between min and min + maxRandomAdditive) + * filled with random bytes */ private static byte[] createRandomBytes(int min, int maxRandomAdditive) { byte[] bytes = new byte[min + (maxRandomAdditive == 0 ? 0 : RND.nextInt(maxRandomAdditive))]; @@ -242,7 +330,7 @@ public class TransferTo { return new InputStreamProvider() { @Override public InputStream input(byte... bytes) throws Exception { - Path path = Files.createTempFile(null, null); + Path path = Files.createTempFile(CWD, "fileChannelInput", null); Files.write(path, bytes); FileChannel fileChannel = FileChannel.open(path); return Channels.newInputStream(fileChannel); @@ -251,7 +339,8 @@ public class TransferTo { } /* - * Creates a provider for an input stream which wraps a readable byte channel but is not a file channel + * Creates a provider for an input stream which wraps a readable byte + * channel but is not a file channel */ private static InputStreamProvider readableByteChannelInput() { return new InputStreamProvider() { @@ -268,8 +357,8 @@ public class TransferTo { private static OutputStreamProvider fileChannelOutput() { return new OutputStreamProvider() { public OutputStream output(Consumer<Supplier<byte[]>> spy) throws Exception { - Path path = Files.createTempFile(null, null); - FileChannel fileChannel = FileChannel.open(path, StandardOpenOption.WRITE); + Path path = Files.createTempFile(CWD, "fileChannelOutput", null); + FileChannel fileChannel = FileChannel.open(path, WRITE); spy.accept(() -> { try { return Files.readAllBytes(path); @@ -282,4 +371,39 @@ public class TransferTo { }; } + private static OutputStreamProvider selectableChannelOutput() throws IOException { + return new OutputStreamProvider() { + public OutputStream output(Consumer<Supplier<byte[]>> spy) throws Exception { + Pipe pipe = Pipe.open(); + Future<byte[]> bytes = CompletableFuture.supplyAsync(() -> { + try { + InputStream is = Channels.newInputStream(pipe.source()); + return is.readAllBytes(); + } catch (IOException e) { + throw new AssertionError("Exception while asserting content", e); + } + }); + final OutputStream os = Channels.newOutputStream(pipe.sink()); + spy.accept(() -> { + try { + os.close(); + return bytes.get(); + } catch (IOException | InterruptedException | ExecutionException e) { + throw new AssertionError("Exception while asserting content", e); + } + }); + return os; + } + }; + } + + private static OutputStreamProvider writableByteChannelOutput() { + return new OutputStreamProvider() { + public OutputStream output(Consumer<Supplier<byte[]>> spy) throws Exception { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + spy.accept(outputStream::toByteArray); + return Channels.newOutputStream(Channels.newChannel(outputStream)); + } + }; + } } diff --git a/test/jdk/java/nio/channels/FileChannel/BlockDeviceSize.java b/test/jdk/java/nio/channels/FileChannel/BlockDeviceSize.java index aafe4192d3241b93f7a54c1660813f85ff1d6036..496312256beb5632ecb76710a75616403321be40 100644 --- a/test/jdk/java/nio/channels/FileChannel/BlockDeviceSize.java +++ b/test/jdk/java/nio/channels/FileChannel/BlockDeviceSize.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -23,6 +23,7 @@ /* @test * @bug 8054029 + * @requires (os.family == "linux") * @summary Block devices should not report size=0 on Linux */ diff --git a/test/jdk/java/nio/channels/FileChannel/Lock.java b/test/jdk/java/nio/channels/FileChannel/Lock.java index 8dee478ea822be1561d64322795590f0b5117be7..7a055a6d107748439fd8c5835fa1203158ceb676 100644 --- a/test/jdk/java/nio/channels/FileChannel/Lock.java +++ b/test/jdk/java/nio/channels/FileChannel/Lock.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -22,12 +22,19 @@ */ /* @test - * @bug 4429043 4493595 6332756 6709457 7146506 + * @bug 4429043 4493595 5041655 6332756 6709457 7146506 * @summary Test FileChannel file locking */ -import java.io.*; -import java.nio.channels.*; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileOutputStream; +import java.io.InputStreamReader; +import java.io.RandomAccessFile; +import java.nio.channels.FileChannel; +import java.nio.channels.FileLock; +import java.nio.channels.OverlappingFileLockException; +import java.util.Random; import static java.nio.file.StandardOpenOption.*; /** @@ -126,12 +133,23 @@ public class Lock { static void test2(File blah, boolean b) throws Exception { try (RandomAccessFile raf = new RandomAccessFile(blah, "rw")) { FileChannel channel = raf.getChannel(); - FileLock lock; - if (b) - lock = channel.lock(); - else - lock = channel.tryLock(); - lock.release(); + try (FileLock lock = b ? channel.lock() : channel.tryLock()) { + } + + Random rnd = new Random(System.currentTimeMillis()); + long position = rnd.nextInt(Integer.MAX_VALUE); + long expectedSize = Long.MAX_VALUE - position; + + for (boolean shared : new boolean[] {false, true}) { + try (FileLock lock = b ? channel.lock(position, 0, false) : + channel.tryLock(position, 0, false)) { + if(lock.size() != expectedSize) + throw new RuntimeException("Lock size " + lock.size() + + " != " + expectedSize + + " for position " + position + " of " + + (shared ? "exclusive" : "shared") + " lock"); + } + } } } diff --git a/test/jdk/java/nio/channels/FileLock/Overlaps.java b/test/jdk/java/nio/channels/FileLock/Overlaps.java new file mode 100644 index 0000000000000000000000000000000000000000..64293e2996db6a6be22594f360634d28cbd7f55c --- /dev/null +++ b/test/jdk/java/nio/channels/FileLock/Overlaps.java @@ -0,0 +1,95 @@ +/* + * 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. + */ + +/* + * @test + * @bug 5041655 + * @summary Verify FileLock.overlaps + * @run testng Overlaps + */ +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; +import java.nio.channels.FileLock; +import java.nio.file.Files; +import java.nio.file.Path; + +import static java.lang.Boolean.*; +import static java.nio.file.StandardOpenOption.*; + +import static org.testng.Assert.assertEquals; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +public class Overlaps { + private static final long POS = 27; + private static final long SIZE = 42; + + private static FileChannel fc; + + @BeforeClass + public void before() throws IOException { + Path path = Files.createTempFile(Path.of("."), "foo", ".bar"); + fc = FileChannel.open(path, CREATE, WRITE, DELETE_ON_CLOSE); + fc.position(POS); + fc.write(ByteBuffer.wrap(new byte[(int)SIZE])); + } + + @AfterClass + public void after() throws IOException { + fc.close(); + } + + @DataProvider + public Object[][] ranges() { + return new Object[][] { + {POS, SIZE, -1,-1, FALSE}, + {POS, SIZE, 0, -1, FALSE}, + {POS, SIZE, POS - 1, -1, FALSE}, + {POS, SIZE, POS + SIZE/2, -1, FALSE}, + {POS, SIZE, POS + SIZE, -1, FALSE}, + {POS, SIZE, -1, POS, FALSE}, + {POS, SIZE, -1, POS + SIZE/2, TRUE}, + {POS, SIZE, POS - 2, 1, FALSE}, + {POS, SIZE, POS + 1, 1, TRUE}, + {POS, SIZE, POS + SIZE/2, 0, TRUE}, + {POS, SIZE, Long.MAX_VALUE, 2, FALSE}, + {POS, SIZE, POS + SIZE / 2, Long.MAX_VALUE, TRUE}, + {POS, SIZE, 0, 0, TRUE}, + {Long.MAX_VALUE - SIZE/2, 0, 0, SIZE, FALSE}, + {Long.MAX_VALUE - SIZE/2, 0, Long.MAX_VALUE - SIZE/4, SIZE, TRUE}, + {Long.MAX_VALUE - SIZE/2, 0, Long.MAX_VALUE - SIZE, 0, TRUE}, + {Long.MAX_VALUE - SIZE, 0, Long.MAX_VALUE - SIZE/2, 0, TRUE} + }; + } + + @Test(dataProvider = "ranges") + public void overlaps(long lockPos, long lockSize, long pos, long size, + boolean overlaps) throws IOException { + try (FileLock lock = fc.lock(lockPos, lockSize, false)) { + assertEquals(lock.overlaps(pos, size), overlaps); + } + } +} diff --git a/test/jdk/java/nio/channels/Selector/CustomFileSystem.java b/test/jdk/java/nio/channels/Selector/CustomFileSystem.java new file mode 100644 index 0000000000000000000000000000000000000000..8113a7169105af14a1dcc2adb3a2b83c30233760 --- /dev/null +++ b/test/jdk/java/nio/channels/Selector/CustomFileSystem.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2021, 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. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 Verifies that an attempt to call Selector.open() on a non-default + * file system succeeds. + * @build CustomFileSystem CustomFileSystemProvider + * @run main/othervm -Djava.nio.file.spi.DefaultFileSystemProvider=CustomFileSystemProvider CustomFileSystem + */ + +public class CustomFileSystem { + public static void main(String args[]) throws java.io.IOException { + java.nio.channels.Selector.open(); + } +} diff --git a/test/jdk/java/nio/channels/Selector/CustomFileSystemProvider.java b/test/jdk/java/nio/channels/Selector/CustomFileSystemProvider.java new file mode 100644 index 0000000000000000000000000000000000000000..f3e876e08a7447ccc061ac6cc1985f5fc89f5408 --- /dev/null +++ b/test/jdk/java/nio/channels/Selector/CustomFileSystemProvider.java @@ -0,0 +1,204 @@ +/* + * Copyright (c) 2021, 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. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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.net.URI; +import java.nio.channels.FileChannel; +import java.nio.channels.SeekableByteChannel; +import java.nio.file.AccessMode; +import java.nio.file.CopyOption; +import java.nio.file.DirectoryStream; +import java.nio.file.FileStore; +import java.nio.file.FileSystem; +import java.nio.file.LinkOption; +import java.nio.file.OpenOption; +import java.nio.file.Path; +import java.nio.file.ReadOnlyFileSystemException; +import java.nio.file.attribute.BasicFileAttributes; +import java.nio.file.attribute.FileAttribute; +import java.nio.file.attribute.FileAttributeView; +import java.nio.file.attribute.UserPrincipalLookupService; +import java.nio.file.spi.FileSystemProvider; +import java.util.Collections; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +public class CustomFileSystemProvider extends FileSystemProvider { + + private final FileSystemProvider defaultProvider; + + public CustomFileSystemProvider(FileSystemProvider defaultProvider) { + this.defaultProvider = defaultProvider; + } + + FileSystemProvider defaultProvider() { + return defaultProvider; + } + + @Override + public String getScheme() { + return "file"; + } + + @Override + public FileSystem newFileSystem(URI uri, Map<String,?> env) throws IOException { + return defaultProvider.newFileSystem(uri, env); + } + + @Override + public FileSystem getFileSystem(URI uri) { + return defaultProvider.getFileSystem(uri); + } + + @Override + public Path getPath(URI uri) { + return defaultProvider.getPath(uri); + } + + @Override + public void setAttribute(Path file, String attribute, Object value, + LinkOption... options) + throws IOException + { + throw new RuntimeException("not implemented"); + } + + @Override + public Map<String,Object> readAttributes(Path file, String attributes, + LinkOption... options) + throws IOException + { + throw new RuntimeException("not implemented"); + } + + @Override + public <A extends BasicFileAttributes> A readAttributes(Path file, + Class<A> type, + LinkOption... options) + throws IOException + { + throw new RuntimeException("not implemented"); + } + + @Override + public <V extends FileAttributeView> V getFileAttributeView(Path file, + Class<V> type, + LinkOption... options) + { + throw new RuntimeException("not implemented"); + } + + @Override + public boolean isHidden(Path file) throws IOException { + throw new ReadOnlyFileSystemException(); + } + + @Override + public boolean isSameFile(Path file, Path other) throws IOException { + throw new RuntimeException("not implemented"); + } + + @Override + public void checkAccess(Path file, AccessMode... modes) + throws IOException + { + throw new RuntimeException("not implemented"); + } + + @Override + public void copy(Path source, Path target, CopyOption... options) + throws IOException + { + throw new RuntimeException("not implemented"); + } + + @Override + public void move(Path source, Path target, CopyOption... options) + throws IOException + { + throw new RuntimeException("not implemented"); + } + + @Override + public void delete(Path file) throws IOException { + throw new RuntimeException("not implemented"); + } + + @Override + public void createSymbolicLink(Path link, Path target, FileAttribute<?>... attrs) + throws IOException + { + throw new RuntimeException("not implemented"); + } + + @Override + public void createLink(Path link, Path existing) throws IOException { + throw new RuntimeException("not implemented"); + } + + @Override + public Path readSymbolicLink(Path link) throws IOException { + throw new RuntimeException("not implemented"); + } + + @Override + public void createDirectory(Path dir, FileAttribute<?>... attrs) + throws IOException + { + throw new RuntimeException("not implemented"); + } + + @Override + public DirectoryStream<Path> newDirectoryStream(Path dir, + DirectoryStream.Filter<? super Path> filter) + throws IOException + { + throw new RuntimeException("not implemented"); + } + + @Override + public SeekableByteChannel newByteChannel(Path file, + Set<? extends OpenOption> options, + FileAttribute<?>... attrs) + throws IOException + { + throw new RuntimeException("not implemented"); + } + + @Override + public FileChannel newFileChannel(Path file, + Set<? extends OpenOption> options, + FileAttribute<?>... attrs) + throws IOException + { + throw new RuntimeException("not implemented"); + } + + @Override + public FileStore getFileStore(Path file) throws IOException { + throw new RuntimeException("not implemented"); + } +} diff --git a/test/jdk/java/nio/channels/SocketChannel/CloseTimeoutChannel.java b/test/jdk/java/nio/channels/SocketChannel/CloseTimeoutChannel.java index 10fdcaaaea6bd6c6b7b4bfe1f0d4b3d4c4a280f0..c715cad8c7c3f20ccda3e591a9eb524b0b51263e 100644 --- a/test/jdk/java/nio/channels/SocketChannel/CloseTimeoutChannel.java +++ b/test/jdk/java/nio/channels/SocketChannel/CloseTimeoutChannel.java @@ -102,7 +102,7 @@ public class CloseTimeoutChannel { System.out.println(INDENT+"Listening on port "+ _listener.socket().getLocalPort()); ByteBuffer buf=ByteBuffer.allocate(5); - Socket client=_listener.accept().socket();; + Socket client=_listener.accept().socket(); System.out.println(INDENT+"Accepted client"); OutputStream out=client.getOutputStream(); diff --git a/test/jdk/java/nio/charset/CharsetDecoder/ASCIIDecode.java b/test/jdk/java/nio/charset/CharsetDecoder/ASCIIDecode.java new file mode 100644 index 0000000000000000000000000000000000000000..330c2c49a0705da9a36a71162c46bebf0f8e5c4c --- /dev/null +++ b/test/jdk/java/nio/charset/CharsetDecoder/ASCIIDecode.java @@ -0,0 +1,55 @@ +/* + * 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. + */ + +/* @test + * @bug 8283325 + * @summary Ensure that decoding to ASCII from a stream with a non-ASCII + * character correctly decodes up until the byte in error. + */ + +import java.nio.*; +import java.nio.charset.*; +import java.util.Arrays; + +public class ASCIIDecode { + + public static void main(String[] args) throws Exception { + final Charset ascii = Charset.forName("US-ASCII"); + final CharsetDecoder decoder = ascii.newDecoder(); + + byte[] ba = new byte[] { 0x60, 0x60, 0x60, (byte)0xFF }; + + // Repeat enough times to test that interpreter and JIT:ed versions + // behave the same (without the patch for 8283325 this fails within + // 50 000 iterations on the system used for verification) + for (int i = 0; i < 100_000; i++) { + ByteBuffer bb = ByteBuffer.wrap(ba); + char[] ca = new char[4]; + CharBuffer cb = CharBuffer.wrap(ca); + CoderResult buf = decoder.decode(bb, cb, true); + if (ca[0] != 0x60 || ca[1] != 0x60 || ca[2] != 0x60) { + throw new RuntimeException("Unexpected output on iteration " + i); + } + } + } +} diff --git a/test/jdk/java/nio/file/FileStore/Basic.java b/test/jdk/java/nio/file/FileStore/Basic.java index 329a483dbd685c73021c57fdc9b3e7734036db3f..4a6bbabdc52f91c2ef46ec7719a48de1a938a69b 100644 --- a/test/jdk/java/nio/file/FileStore/Basic.java +++ b/test/jdk/java/nio/file/FileStore/Basic.java @@ -145,6 +145,16 @@ public class Basic { // reflect whether the space attributes would be accessible // were access to be permitted System.err.format("%s is inaccessible\n", store); + } catch (FileSystemException fse) { + // On Linux, ignore the FSE if the path is one of the + // /run/user/$UID mounts created by pam_systemd(8) as it + // might be mounted as a fuse.portal filesystem and + // its access attempt might fail with EPERM + if (!Platform.isLinux() || store.toString().indexOf("/run/user") == -1) { + throw new RuntimeException(fse); + } else { + System.err.format("%s error: %s\n", store, fse); + } } // two distinct FileStores should not be equal diff --git a/test/jdk/java/nio/file/Files/CopyAndMove.java b/test/jdk/java/nio/file/Files/CopyAndMove.java index 981fb332fc0c4cd109dc7f3c479e2caab61682bc..e91f3e3713b742fb109409df56536e6ab9bc8740 100644 --- a/test/jdk/java/nio/file/Files/CopyAndMove.java +++ b/test/jdk/java/nio/file/Files/CopyAndMove.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 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 @@ -22,7 +22,7 @@ */ /* @test - * @bug 4313887 6838333 6917021 7006126 6950237 8006645 8201407 + * @bug 4313887 6838333 6917021 7006126 6950237 8006645 8201407 8267820 * @summary Unit test for java.nio.file.Files copy and move methods (use -Dseed=X to set PRNG seed) * @library .. /test/lib * @build jdk.test.lib.Platform jdk.test.lib.RandomFactory @@ -672,16 +672,15 @@ public class CopyAndMove { checkBasicAttributes(basicAttributes, readAttributes(source, BasicFileAttributes.class, linkOptions)); + // check POSIX attributes are copied + if (!Platform.isWindows() && testPosixAttributes) { + checkPosixAttributes( + readAttributes(source, PosixFileAttributes.class, linkOptions), + readAttributes(target, PosixFileAttributes.class, linkOptions)); + } + // verify other attributes when same provider if (source.getFileSystem().provider() == target.getFileSystem().provider()) { - - // check POSIX attributes are copied - if (!Platform.isWindows() && testPosixAttributes) { - checkPosixAttributes( - readAttributes(source, PosixFileAttributes.class, linkOptions), - readAttributes(target, PosixFileAttributes.class, linkOptions)); - } - // check DOS attributes are copied if (Platform.isWindows()) { checkDosAttributes( diff --git a/test/jdk/java/nio/file/Files/probeContentType/Basic.java b/test/jdk/java/nio/file/Files/probeContentType/Basic.java index 0812f886c30bcb4b8b14bb7082fb231ea8d662d3..74e4cd5ab39e5eb51310cebd12ff8cc1af7ace92 100644 --- a/test/jdk/java/nio/file/Files/probeContentType/Basic.java +++ b/test/jdk/java/nio/file/Files/probeContentType/Basic.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 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 @@ -110,8 +110,8 @@ public class Basic { + " cannot be determined"); failures++; } else if (!expectedTypes.contains(type)) { - System.err.printf("Content type: %s; expected: %s%n", - type, expectedTypes); + System.err.printf("For extension %s we got content type: %s; expected: %s%n", + extension, type, expectedTypes); failures++; } } finally { @@ -155,30 +155,30 @@ public class Basic { // Verify that certain extensions are mapped to the correct type. var exTypes = new ExType[] { new ExType("adoc", List.of("text/plain")), - new ExType("bz2", List.of("application/bz2", "application/x-bzip2")), + new ExType("bz2", List.of("application/bz2", "application/x-bzip2", "application/x-bzip")), new ExType("css", List.of("text/css")), new ExType("csv", List.of("text/csv")), new ExType("doc", List.of("application/msword")), new ExType("docx", List.of("application/vnd.openxmlformats-officedocument.wordprocessingml.document")), new ExType("gz", List.of("application/gzip", "application/x-gzip")), - new ExType("jar", List.of("application/java-archive", "application/x-java-archive")), + new ExType("jar", List.of("application/java-archive", "application/x-java-archive", "application/jar")), new ExType("jpg", List.of("image/jpeg")), new ExType("js", List.of("text/javascript", "application/javascript")), new ExType("json", List.of("application/json")), new ExType("markdown", List.of("text/markdown")), - new ExType("md", List.of("text/markdown")), + new ExType("md", List.of("text/markdown", "application/x-genesis-rom")), new ExType("mp3", List.of("audio/mpeg")), new ExType("mp4", List.of("video/mp4")), new ExType("odp", List.of("application/vnd.oasis.opendocument.presentation")), new ExType("ods", List.of("application/vnd.oasis.opendocument.spreadsheet")), new ExType("odt", List.of("application/vnd.oasis.opendocument.text")), new ExType("pdf", List.of("application/pdf")), - new ExType("php", List.of("text/plain", "text/php")), + new ExType("php", List.of("text/plain", "text/php", "application/x-php")), new ExType("png", List.of("image/png")), new ExType("ppt", List.of("application/vnd.ms-powerpoint")), new ExType("pptx",List.of("application/vnd.openxmlformats-officedocument.presentationml.presentation")), new ExType("py", List.of("text/plain", "text/x-python", "text/x-python-script")), - new ExType("rar", List.of("application/rar", "application/vnd.rar")), + new ExType("rar", List.of("application/rar", "application/vnd.rar", "application/x-rar")), new ExType("rtf", List.of("application/rtf", "text/rtf")), new ExType("webm", List.of("video/webm")), new ExType("webp", List.of("image/webp")), diff --git a/test/jdk/java/nio/file/attribute/UserDefinedFileAttributeView/Basic.java b/test/jdk/java/nio/file/attribute/UserDefinedFileAttributeView/Basic.java index bc47b8719f28ccd984698f0d00eb6dc6abbfb67d..00ab4670ba6d6d9b34a0a07c4bc9721639da6eb1 100644 --- a/test/jdk/java/nio/file/attribute/UserDefinedFileAttributeView/Basic.java +++ b/test/jdk/java/nio/file/attribute/UserDefinedFileAttributeView/Basic.java @@ -242,7 +242,7 @@ public class Basic { // We need to run up to MAX_PATH for directories, // but not quite go over it. - int MAX_PATH = 247; + int MAX_PATH = 250; int requiredLen = MAX_PATH - len - 2; // Create a really long directory name. @@ -252,11 +252,15 @@ public class Basic { Files.createDirectory(longPath); try { - // Try to set absolute path as extended attribute; expect IAE + System.out.println("Testing " + longPath); + + // Try to set absolute path as extended attribute; + // expect IAE tryCatch(IllegalArgumentException.class, new Task() { public void run() throws IOException { setEA(longPath, "user:C:\\"); - }}); + } + }); // Try to set an extended attribute on it. setEA(longPath, "user:short"); diff --git a/test/jdk/java/rmi/dgc/dgcImplInsulation/DGCImplInsulation.java b/test/jdk/java/rmi/dgc/dgcImplInsulation/DGCImplInsulation.java index c4a15b28bb1cb3e3f40445898bcfc80afcc221e1..9a0490beb0ff3bde0c8e97656a5a39d46fde6051 100644 --- a/test/jdk/java/rmi/dgc/dgcImplInsulation/DGCImplInsulation.java +++ b/test/jdk/java/rmi/dgc/dgcImplInsulation/DGCImplInsulation.java @@ -68,7 +68,7 @@ public class DGCImplInsulation implements java.rmi.Remote { new ProtectionDomain( new CodeSource(null, (Certificate[]) null), perms) }); - Remote impl = new DGCImplInsulation();; + Remote impl = new DGCImplInsulation(); try { Remote stub = (Remote) java.security.AccessController.doPrivileged( diff --git a/test/jdk/java/rmi/server/RMIClassLoader/loadProxyClasses/LoadProxyClasses.java b/test/jdk/java/rmi/server/RMIClassLoader/loadProxyClasses/LoadProxyClasses.java index 9b8ed213160787cc8e9344e8024bc4f7e5dd40c1..568eeb1e6bedf14986d60d42a990c6b8d7ed6751 100644 --- a/test/jdk/java/rmi/server/RMIClassLoader/loadProxyClasses/LoadProxyClasses.java +++ b/test/jdk/java/rmi/server/RMIClassLoader/loadProxyClasses/LoadProxyClasses.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -22,7 +22,7 @@ */ /* @test - * + * @bug 8280642 * @summary functional test for RMIClassLoader.loadProxyClass; test * ensures that the default RMI class loader provider implements * RMIClassLoader.loadProxyClass correctly. @@ -48,6 +48,7 @@ import java.rmi.MarshalledObject; import java.net.URL; import java.net.URLClassLoader; import java.io.Serializable; +import java.io.InvalidClassException; import java.io.IOException; import java.util.Arrays; @@ -205,20 +206,20 @@ public class LoadProxyClasses { currentThread.getContextClassLoader(); currentThread.setContextClassLoader(nonpublicLoaderB); - IllegalAccessError illegal = null; + InvalidClassException invalid = null; try { unmarshalProxyClass(proxy4, fnnLoader2, nonpublicLoaderB, 4, null); - } catch (IllegalAccessError e) { - illegal = e; + } catch (InvalidClassException e) { + invalid = e; } - if (illegal == null) { - TestLibrary.bomb("case4: IllegalAccessError not thrown " + + if (invalid == null) { + TestLibrary.bomb("case4: InvalidClassException not thrown " + "when multiple nonpublic interfaces have \n" + "different class loaders"); } else { - System.err.println("\ncase4: IllegalAccessError correctly " + + System.err.println("\ncase4: InvalidClassException correctly " + "thrown \n when trying to load proxy " + "with multiple nonpublic interfaces in \n" + " different class loaders"); diff --git a/test/jdk/java/security/KeyFactory/KeyFactoryGetKeySpecForInvalidSpec.java b/test/jdk/java/security/KeyFactory/KeyFactoryGetKeySpecForInvalidSpec.java index e5c4c5457f3b11c9c0549096a32747a39132adc4..e72d5c8decc3fa8b82b7d84f2bca41712ed229db 100644 --- a/test/jdk/java/security/KeyFactory/KeyFactoryGetKeySpecForInvalidSpec.java +++ b/test/jdk/java/security/KeyFactory/KeyFactoryGetKeySpecForInvalidSpec.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Amazon.com, Inc. 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 diff --git a/test/jdk/java/security/KeyStore/PKCS12/UnmodifiableAttributes.java b/test/jdk/java/security/KeyStore/PKCS12/UnmodifiableAttributes.java new file mode 100644 index 0000000000000000000000000000000000000000..ae38a6af71ec578970d1107aa405d5ca7115ae80 --- /dev/null +++ b/test/jdk/java/security/KeyStore/PKCS12/UnmodifiableAttributes.java @@ -0,0 +1,64 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8278744 + * @summary KeyStore:getAttributes() not returning unmodifiable Set + * @library /test/lib + */ + +import jdk.test.lib.SecurityTools; +import jdk.test.lib.Utils; + +import java.io.File; +import java.security.KeyStore; + +public class UnmodifiableAttributes { + public static final void main(String[] args) throws Exception { + + var oneAttr = new KeyStore.Entry.Attribute() { + @Override + public String getName() { + return "1.2.3"; + } + + @Override + public String getValue() { + return "testVal"; + } + }; + char[] pass = "changeit".toCharArray(); + + SecurityTools.keytool("-keystore ks -storepass changeit -genkeypair -alias a -dname CN=A -keyalg EC") + .shouldHaveExitValue(0); + + KeyStore ks = KeyStore.getInstance(new File("ks"), pass); + + var attrs = ks.getAttributes("a"); + Utils.runAndCheckException(() -> attrs.add(oneAttr), UnsupportedOperationException.class); + + var attrs2 = ks.getEntry("a", new KeyStore.PasswordProtection(pass)).getAttributes(); + Utils.runAndCheckException(() -> attrs2.add(oneAttr), UnsupportedOperationException.class); + } +} diff --git a/test/jdk/java/security/MessageDigest/ThreadSafetyTest.java b/test/jdk/java/security/MessageDigest/ThreadSafetyTest.java index 41ecbca2677b5188f05d0ce15ad771ae5859ca38..594e9926eabbf7ea83b8c03d48bd6324eb187ff9 100644 --- a/test/jdk/java/security/MessageDigest/ThreadSafetyTest.java +++ b/test/jdk/java/security/MessageDigest/ThreadSafetyTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Azul Systems, Inc. All rights reserved. + * Copyright (c) 2020, 2021, Azul Systems, 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 @@ -23,9 +23,9 @@ /* * @test - * @bug 8241960 + * @bug 8241960 8277353 * @summary Confirm that java.security.MessageDigest is thread-safe after clone. - * @run main/othervm ThreadSafetyTest 5 4 + * @run main ThreadSafetyTest 4 2 */ import java.security.MessageDigest; @@ -56,7 +56,7 @@ public class ThreadSafetyTest { duration = Integer.parseInt(args[1]); } int nProcessors = Runtime.getRuntime().availableProcessors(); - int nTasks = nProcessors * threadsFactor; + int nTasks = Math.min(nProcessors, 4) * threadsFactor; System.out.println("Testing with " + nTasks + " threads on " + nProcessors + " processors for " + duration + diff --git a/test/jdk/java/security/Provider/CaseSensitiveServices.java b/test/jdk/java/security/Provider/CaseSensitiveServices.java index 2a6676b4f582b3c2d160ca80495e158eab5f3348..d9b8d315bd033e8cebb553716b44b43737462eb8 100644 --- a/test/jdk/java/security/Provider/CaseSensitiveServices.java +++ b/test/jdk/java/security/Provider/CaseSensitiveServices.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 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 @@ -23,7 +23,7 @@ /* * @test - * @bug 5097015 8130181 + * @bug 5097015 8130181 8279222 * @summary make sure we correctly treat Provider string entries as case insensitive * @author Andreas Sterbenz */ @@ -36,9 +36,12 @@ public class CaseSensitiveServices extends Provider { super("Foo", "1.0", null); put("MessageDigest.Foo", "com.Foo"); put("mESSAGEdIGEST.fOO xYz", "aBc"); - put("ALg.aliaS.MESSAGEdigest.Fu", "FoO"); + // first assign the DEF alias to algorithm Foo + put("ALg.aliaS.MESSAGEdigest.DEF", "FoO"); put("messageDigest.Bar", "com.Bar"); put("MESSAGEDIGEST.BAZ", "com.Baz"); + // reassign the DEF alias to algorithm Bar + put("ALg.aliaS.MESSAGEdigest.DEF", "Bar"); } public static void main(String[] args) throws Exception { @@ -47,12 +50,21 @@ public class CaseSensitiveServices extends Provider { if (p.getServices().size() != 3) { throw new Exception("services.size() should be 3"); } + Service s = testService(p, "MessageDigest", "fOO"); String val = s.getAttribute("Xyz"); if ("aBc".equals(val) == false) { throw new Exception("Wrong value: " + val); } - testService(p, "MessageDigest", "fU"); + if (s.toString().indexOf("DEF") != -1) { + throw new Exception("Old alias DEF should be removed"); + } + + // test Service alias DEF and its associated impl is Bar + s = testService(p, "MessageDigest", "DeF"); + if (s.getAttribute("Xyz") != null) { + throw new Exception("DEF mapped to the wrong impl"); + } testService(p, "MessageDigest", "BAR"); testService(p, "MessageDigest", "baz"); System.out.println("OK"); diff --git a/test/jdk/java/security/SignedJar/CustomClassLoader.java b/test/jdk/java/security/SignedJar/CustomClassLoader.java new file mode 100644 index 0000000000000000000000000000000000000000..99242f3a877071cfbc0b7a7fb0ff6d51eebec8c3 --- /dev/null +++ b/test/jdk/java/security/SignedJar/CustomClassLoader.java @@ -0,0 +1,43 @@ +/* + * 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. + */ + +import java.io.IOException; +import java.io.InputStream; + +public class CustomClassLoader extends ClassLoader { + + public CustomClassLoader(ClassLoader parent) { + super(parent); + } + + @Override + public Class<?> findClass(String name) throws ClassNotFoundException { + try (InputStream is = getClass().getClassLoader() + .getResourceAsStream(name + ".class")) { + byte[] buf = is.readAllBytes(); + return defineClass(name, buf, 0, buf.length); + } catch (IOException e) { + throw new ClassNotFoundException(e.getMessage()); + } + } +} diff --git a/test/jdk/java/security/SignedJar/SignedJarWithCustomClassLoader.java b/test/jdk/java/security/SignedJar/SignedJarWithCustomClassLoader.java new file mode 100644 index 0000000000000000000000000000000000000000..1f335c87f14950a2f312ce0500b5c4c3960cefd9 --- /dev/null +++ b/test/jdk/java/security/SignedJar/SignedJarWithCustomClassLoader.java @@ -0,0 +1,94 @@ +/* + * 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. + */ + +/** + * @test + * @bug 8280890 + * @library /test/lib + * @build SignedJarWithCustomClassLoader CustomClassLoader + * @run main/othervm SignedJarWithCustomClassLoader + * @summary Make sure java.system.class.loader property can be used when custom + * class loader is inside signed jar + */ + +import java.nio.file.Path; +import java.nio.file.Paths; + +import jdk.test.lib.SecurityTools; +import jdk.test.lib.compiler.InMemoryJavaCompiler; +import jdk.test.lib.helpers.ClassFileInstaller; +import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.util.JarUtils; + +public class SignedJarWithCustomClassLoader { + + public static void main(String[] args) throws Exception { + + // compile the Main program + String main = """ + public class Main { + public static void main(String[] args) {} + } + """; + String testClasses = System.getProperty("test.classes", ""); + ClassFileInstaller.writeClassToDisk("Main", + InMemoryJavaCompiler.compile("Main", main), + testClasses); + + // create the jar file + Path classes = Paths.get(testClasses); + JarUtils.createJarFile(Paths.get("test.jar"), classes, + classes.resolve("CustomClassLoader.class"), + classes.resolve("Main.class")); + + // create signer's keypair + SecurityTools.keytool("-genkeypair -keyalg RSA -keystore ks " + + "-storepass changeit -dname CN=test -alias test") + .shouldHaveExitValue(0); + + // sign jar + SecurityTools.jarsigner("-keystore ks -storepass changeit " + + "-signedjar signed.jar test.jar test") + .shouldHaveExitValue(0); + + // run app with system class loader set to custom classloader + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-cp", "signed.jar", + "-Djava.system.class.loader=CustomClassLoader", "Main"); + ProcessTools.executeProcess(pb) + .shouldHaveExitValue(0); + + // sign jar again, but this time with SHA-1 which is disabled + SecurityTools.jarsigner("-keystore ks -storepass changeit " + + "-digestalg SHA-1 -sigalg SHA1withRSA " + + "-signedjar signed.jar test.jar test") + .shouldHaveExitValue(0); + + // run app again, should still succeed even though SHA-1 is disabled + pb = ProcessTools.createJavaProcessBuilder( + "-cp", "signed.jar", + "-Djava.system.class.loader=CustomClassLoader", "Main"); + ProcessTools.executeProcess(pb) + .shouldHaveExitValue(0); + } +} diff --git a/test/jdk/java/security/misc/Versions.java b/test/jdk/java/security/misc/Versions.java index 6c14b2bc212ddbb096378ddbca77e5fc90314a45..ebfe9a13a88faf27295af114805cfca1cb026dd4 100644 --- a/test/jdk/java/security/misc/Versions.java +++ b/test/jdk/java/security/misc/Versions.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -51,7 +51,7 @@ public class Versions { "src/java.xml.crypto/share/legal/santuario.md", Pattern.compile("## Apache Santuario v(?<n>\\S+)"), "java.xml.crypto/santuario.md"}, - {"make/data/publicsuffixlist/VERSION", + {"src/java.base/share/data/publicsuffixlist/VERSION", Pattern.compile("list/(?<n>[0-9a-f]+)/public_suffix_list.dat"), "src/java.base/share/legal/public_suffix.md", Pattern.compile("list/(?<n>[0-9a-f]+)/public_suffix_list.dat"), diff --git a/test/jdk/java/security/spec/IsAssignableFromOrder.java b/test/jdk/java/security/spec/IsAssignableFromOrder.java new file mode 100644 index 0000000000000000000000000000000000000000..db2b765283094498fa377504264a59fbe501160e --- /dev/null +++ b/test/jdk/java/security/spec/IsAssignableFromOrder.java @@ -0,0 +1,117 @@ +/* + * 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. + */ + +import sun.security.util.CurveDB; + +import javax.crypto.SecretKeyFactory; +import javax.crypto.spec.DESKeySpec; +import javax.crypto.spec.DESedeKeySpec; +import javax.crypto.spec.DHParameterSpec; +import javax.crypto.spec.GCMParameterSpec; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.OAEPParameterSpec; +import javax.crypto.spec.PBEKeySpec; +import javax.crypto.spec.PBEParameterSpec; +import javax.crypto.spec.RC2ParameterSpec; +import javax.crypto.spec.SecretKeySpec; +import java.math.BigInteger; +import java.nio.charset.StandardCharsets; +import java.security.AlgorithmParameters; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.DSAParameterSpec; +import java.security.spec.ECGenParameterSpec; +import java.security.spec.ECParameterSpec; +import java.security.spec.KeySpec; +import java.security.spec.PSSParameterSpec; + +/** + * @test + * @bug 8279800 + * @modules java.base/sun.security.util + * @summary isAssignableFrom checks in AlgorithmParametersSpi.engineGetParameterSpec appear to be backwards + */ + +public class IsAssignableFromOrder { + + public static void main(String[] args) throws Exception { + + // AlgorithmParameters + testAlgSpec("AES", new IvParameterSpec(new byte[16])); + testAlgSpec("ChaCha20-Poly1305", new IvParameterSpec(new byte[12])); + testAlgSpec("DiffieHellman", new DHParameterSpec(BigInteger.ONE, BigInteger.TWO)); + testAlgSpec("GCM", new GCMParameterSpec(96, new byte[16])); + testAlgSpec("OAEP", OAEPParameterSpec.DEFAULT); + testAlgSpec("PBEWithSHA1AndDESede", new PBEParameterSpec( + "saltsalt".getBytes(StandardCharsets.UTF_8), 10000)); + testAlgSpec("PBEWithHmacSHA256AndAES_256", new PBEParameterSpec( + "saltsalt".getBytes(StandardCharsets.UTF_8), 10000, + new IvParameterSpec(new byte[16]))); + testAlgSpec("RC2", new RC2ParameterSpec(256, new byte[32])); + testAlgSpec("DSA", new DSAParameterSpec( + BigInteger.ONE, BigInteger.TWO, BigInteger.TEN)); + testAlgSpec("RSASSA-PSS", PSSParameterSpec.DEFAULT); + testAlgSpec("EC", new ECGenParameterSpec("secp256r1")); + testAlgSpec("EC", CurveDB.lookup("secp256r1"), + ECParameterSpec.class, AlgorithmParameterSpec.class); + + // SecretKeyFactory + var spec = new PBEKeySpec( + "password".toCharArray(), + "saltsalt".getBytes(StandardCharsets.UTF_8), + 10000, + 32); + + testKeySpec("PBE", spec, PBEKeySpec.class); + testKeySpec("PBEWithHmacSHA256AndAES_256", spec, PBEKeySpec.class); + testKeySpec("PBKDF2WithHmacSHA1", spec, PBEKeySpec.class); + + testKeySpec("DES", new SecretKeySpec(new byte[8], "DES"), DESKeySpec.class); + testKeySpec("DESede", new SecretKeySpec(new byte[24], "DESede"), DESedeKeySpec.class); + } + + + static void testAlgSpec(String algorithm, AlgorithmParameterSpec spec, + Class<? extends AlgorithmParameterSpec>... classes) throws Exception { + System.out.println(algorithm); + var ap1 = AlgorithmParameters.getInstance(algorithm); + ap1.init(spec); + var ap2 = AlgorithmParameters.getInstance(algorithm); + ap2.init(ap1.getEncoded()); + if (classes.length == 0) { + classes = new Class[]{spec.getClass(), AlgorithmParameterSpec.class}; + } + for (var c : classes) { + ap1.getParameterSpec(c); + ap2.getParameterSpec(c); + } + } + + static void testKeySpec(String algorithm, KeySpec spec, Class<?> clazz) + throws Exception { + System.out.println(algorithm); + var kf = SecretKeyFactory.getInstance(algorithm); + var key = kf.generateSecret(spec); + kf.getKeySpec(key, KeySpec.class); + kf.getKeySpec(key, clazz); + } +} diff --git a/test/jdk/java/text/Format/CompactNumberFormat/TestCompactPatternsValidity.java b/test/jdk/java/text/Format/CompactNumberFormat/TestCompactPatternsValidity.java index 6ca1f25ea9055a220c86813b0eb210a91a5e2c3f..8476b568ba019da9c8689268cb63f66d099899ef 100644 --- a/test/jdk/java/text/Format/CompactNumberFormat/TestCompactPatternsValidity.java +++ b/test/jdk/java/text/Format/CompactNumberFormat/TestCompactPatternsValidity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -22,7 +22,7 @@ */ /* * @test - * @bug 8177552 8217254 8251499 + * @bug 8177552 8217254 8251499 8281317 * @summary Checks the validity of compact number patterns specified through * CompactNumberFormat constructor * @run testng/othervm TestCompactPatternsValidity @@ -101,8 +101,9 @@ public class TestCompactPatternsValidity { {COMPACT_PATTERN5, List.of(100, 1000, 30000), List.of("100", "1K", "K3")}, {COMPACT_PATTERN6, List.of(20.99, 1000, 30000), List.of("21", ".1K", ".30K")}, {COMPACT_PATTERN7, List.of(100, 1000, new BigInteger("12345678987654321")), List.of("100", "1K,", "12345678987654K,")}, - {COMPACT_PATTERN8, List.of(new BigInteger("223565686837667632"), new BigDecimal("12322456774334.89766"), 30000, 3456.78), - List.of("223566T", "12T", "30K", "3K")}, + {COMPACT_PATTERN8, List.of(new BigInteger("223565686837667632"), new BigDecimal("12322456774334.89766"), 30000, 3456.78, + new BigInteger("999999999999"), new BigDecimal("999999999999.0"), 999_999, 999_999_999), + List.of("223566T", "12T", "30K", "3K", "1T", "1T", "1M", "1B")}, {COMPACT_PATTERN9, List.of(new BigInteger("223566000000000000"), new BigDecimal("12345678987654567"), 30000, 3000), List.of("223,566,000,000,000,000", "12,345,678,987,654,567", "30,000", "3,000")}, {COMPACT_PATTERN10, List.of(new BigInteger("100000000000000000"), new BigInteger("10000000000000000000"), new BigDecimal("555555555555555555555.89766"), 30000), @@ -110,7 +111,8 @@ public class TestCompactPatternsValidity { {COMPACT_PATTERN11, List.of(20.99, -20.99, 1000, -1000, 30000, -30000, new BigInteger("12345678987654321"), new BigInteger("-12345678987654321")), List.of("21", "-21", "elfu 1", "elfu -1", "elfu 30", "elfu -30", "milioni 12345678988", "milioni -12345678988")}, {COMPACT_PATTERN12, List.of(0, 500, -500, 30000, -3000, 5000000), List.of("0", "H5H", "H-5H", "30K", "3K-", "H50G")}, - {COMPACT_PATTERN13, List.of(1000, new BigInteger("10000000000000000000")), List.of("Thousand", "BeyondLong")}, + {COMPACT_PATTERN13, List.of(1000, new BigInteger("10000000000000000000"), new BigDecimal("9999999999999999999.9")), + List.of("Thousand", "BeyondLong", "BeyondLong")}, }; } diff --git a/test/jdk/java/text/Format/DateFormat/DateFormatTest.java b/test/jdk/java/text/Format/DateFormat/DateFormatTest.java index 43c73ac37786c9766ddfd661ef66e602ecfae1c2..5be792d1cd798a192d2dac6f87745ff0df6b9972 100644 --- a/test/jdk/java/text/Format/DateFormat/DateFormatTest.java +++ b/test/jdk/java/text/Format/DateFormat/DateFormatTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -24,7 +24,7 @@ /** * @test * @bug 4052223 4089987 4469904 4326988 4486735 8008577 8045998 8140571 - * 8216969 + * 8190748 8216969 * @summary test DateFormat and SimpleDateFormat. * @library /java/text/testlib * @modules jdk.localedata @@ -342,7 +342,7 @@ public class DateFormatTest extends IntlTest // Test pattern with runs things together public void TestRunTogetherPattern985() { - String format = "yyyyMMddHHmmssSSS"; + String format = "yyyyMMddHHmmssSSSzzzz"; String now, then; SimpleDateFormat formatter = new SimpleDateFormat(format); diff --git a/test/jdk/java/text/Format/DateFormat/NonGregorianFormatTest.java b/test/jdk/java/text/Format/DateFormat/NonGregorianFormatTest.java index 93e2a9ffeee4ca3abc5ebf27b5db2b3a68111d9f..613687eb910f48b4f37be2f0b13dd7d89531c03a 100644 --- a/test/jdk/java/text/Format/DateFormat/NonGregorianFormatTest.java +++ b/test/jdk/java/text/Format/DateFormat/NonGregorianFormatTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -23,12 +23,13 @@ /* * @test - * @bug 4833268 6253991 8008577 + * @bug 4833268 6253991 8008577 8190748 * @summary Test formatting and parsing with non-Gregorian calendars * @modules jdk.localedata * @run main/othervm -Djava.locale.providers=COMPAT,SPI NonGregorianFormatTest */ +import java.time.ZoneId; import java.util.*; import java.text.*; import static java.util.Calendar.*; @@ -160,10 +161,15 @@ public class NonGregorianFormatTest { private static void testRoundTrip(DateFormat df, Date orig) { try { + var defZone = ZoneId.systemDefault(); + if (defZone.getRules().getTransition(orig.toInstant().atZone(defZone).toLocalDateTime()) != null) { + System.out.println("At the offset transition. Round trip test skipped."); + return; + } String s = df.format(orig); Date parsed = df.parse(s); if (!orig.equals(parsed)) { - error("testRoundTrip: bad date: origianl: '%s', parsed '%s'%n", orig, parsed); + error("testRoundTrip: bad date: original: '%s', parsed '%s'%n", orig, parsed); } } catch (Exception e) { error("Unexpected exception: %s%n", e); diff --git a/test/jdk/java/text/Format/DecimalFormat/ToLocalizedPatternTest.java b/test/jdk/java/text/Format/DecimalFormat/ToLocalizedPatternTest.java new file mode 100644 index 0000000000000000000000000000000000000000..6d8ab9c9a0cd4953d97c5473e6e66f4390f424bb --- /dev/null +++ b/test/jdk/java/text/Format/DecimalFormat/ToLocalizedPatternTest.java @@ -0,0 +1,61 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8282929 + * @summary Verifies that toLocalizedPattern() method correctly returns + * monetary symbols in a currency formatter + * @run testng ToLocalizedPatternTest + */ + +import static org.testng.Assert.assertEquals; +import org.testng.annotations.Test; + +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; +import java.util.Locale; + +@Test +public class ToLocalizedPatternTest { + private static final char MONETARY_GROUPING = 'g'; + private static final char MONETARY_DECIMAL = 'd'; + + public void testToLocalizedPattern() { + var dfs = new DecimalFormatSymbols(Locale.US); + + // Customize the decimal format symbols + dfs.setMonetaryGroupingSeparator(MONETARY_GROUPING); + dfs.setMonetaryDecimalSeparator(MONETARY_DECIMAL); + + // create a currency formatter + var cf = (DecimalFormat)DecimalFormat.getCurrencyInstance(Locale.US); + cf.setDecimalFormatSymbols(dfs); + + // check + assertEquals(cf.toLocalizedPattern(), + cf.toPattern() + .replace(',', MONETARY_GROUPING) + .replace('.', MONETARY_DECIMAL)); + } +} diff --git a/test/jdk/java/text/Format/NumberFormat/IntlTestDecimalFormatSymbols.java b/test/jdk/java/text/Format/NumberFormat/IntlTestDecimalFormatSymbols.java index cd19fee1e35110f74ef9655c573c3a56fdae8384..30905ee46f16c1359995d610e3d37615dce35131 100644 --- a/test/jdk/java/text/Format/NumberFormat/IntlTestDecimalFormatSymbols.java +++ b/test/jdk/java/text/Format/NumberFormat/IntlTestDecimalFormatSymbols.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -23,6 +23,7 @@ /* * @test + * @bug 8282625 * @library /java/text/testlib * @summary test International Decimal Format Symbols */ @@ -60,6 +61,14 @@ public class IntlTestDecimalFormatSymbols extends IntlTest // just do some VERY basic tests to make sure that get/set work + if (!fr.getLocale().equals(Locale.FRENCH)) { + errln("ERROR: French DecimalFormatSymbols not Locale.FRENCH"); + } + + if (!en.getLocale().equals(Locale.ENGLISH)) { + errln("ERROR: English DecimalFormatSymbols not Locale.ENGLISH"); + } + char zero = en.getZeroDigit(); fr.setZeroDigit(zero); if(fr.getZeroDigit() != en.getZeroDigit()) { diff --git a/test/jdk/java/time/tck/java/time/zone/TCKZoneRules.java b/test/jdk/java/time/tck/java/time/zone/TCKZoneRules.java index 3f6c17b277a4bf5fc9a08b82e0deb7fe131bbac7..d44216b69b56e92de8a93a5f35113f846c058d3b 100644 --- a/test/jdk/java/time/tck/java/time/zone/TCKZoneRules.java +++ b/test/jdk/java/time/tck/java/time/zone/TCKZoneRules.java @@ -1072,7 +1072,7 @@ public class TCKZoneRules { ); OffsetDateTime before_time_of_stdOffsetTransition1 = OffsetDateTime.of(time_of_stdOffsetTransition1, stdOffset1).minusSeconds(1); - OffsetDateTime after_time_of_stdOffsetTransition1 = OffsetDateTime.of(time_of_stdOffsetTransition1, stdOffset1).plusSeconds(1);; + OffsetDateTime after_time_of_stdOffsetTransition1 = OffsetDateTime.of(time_of_stdOffsetTransition1, stdOffset1).plusSeconds(1); assertEquals(zoneRule.getStandardOffset(before_time_of_stdOffsetTransition1.toInstant()), stdOffset1); assertEquals(zoneRule.getStandardOffset(after_time_of_stdOffsetTransition1.toInstant()), stdOffset2); diff --git a/test/jdk/java/time/test/java/time/format/Skeletons_en_US.properties b/test/jdk/java/time/test/java/time/format/Skeletons_en_US.properties new file mode 100644 index 0000000000000000000000000000000000000000..8e55398051e4f7ebc95ea5246a19ae6799d15e7e --- /dev/null +++ b/test/jdk/java/time/test/java/time/format/Skeletons_en_US.properties @@ -0,0 +1,51 @@ +H=15 +h=3 PM +j=3 PM +C=3 PM +Hm=15:32 +hm=3:32 PM +jm=3:32 PM +Cm=3:32 PM +Hms=15:32:39 +hms=3:32:39 PM +jms=3:32:39 PM +Cms=3:32:39 PM +Hmv=15:32 PT +hmv=3:32 PM PT +jmv=3:32 PM PT +Cmv=3:32 PM PT +Hmsv=15:32:39 PT +hmsv=3:32:39 PM PT +jmsv=3:32:39 PM PT +Cmsv=3:32:39 PM PT +Bh=3 in the afternoon +Bj=3 in the afternoon +BC=3 in the afternoon +Bhm=3:32 in the afternoon +Bjm=3:32 in the afternoon +BCm=3:32 in the afternoon +Bhms=3:32:39 in the afternoon +Bjms=3:32:39 in the afternoon +BCms=3:32:39 in the afternoon + +M=1 +MMM=Jan +MEd=Wed, 1/26 +MMMMEd=Wed, Jan 26 +d=26 +y=2022 +yM=1/2022 +yMEd=Wed, 1/26/2022 +yMMM=Jan 2022 +yMMMMEd=Wed, Jan 26, 2022 +GyM=Jan 2022 AD +GyMEd=Wed, Jan 26, 2022 AD +GyMMM=Jan 2022 AD +GyMMMMEd=Wed, Jan 26, 2022 AD +yQQQ=Q1 2022 +yQQQQ=1st quarter 2022 + +MMMMEdBh=Wed, Jan 26 at 3 in the afternoon +MMMMdBh=January 26 at 3 in the afternoon +MMMdBh=Jan 26, 3 in the afternoon +MdBh=1/26, 3 in the afternoon diff --git a/test/jdk/java/time/test/java/time/format/Skeletons_ja.properties b/test/jdk/java/time/test/java/time/format/Skeletons_ja.properties new file mode 100644 index 0000000000000000000000000000000000000000..1b8823d369e842a5633494debb8e4381aa98e938 --- /dev/null +++ b/test/jdk/java/time/test/java/time/format/Skeletons_ja.properties @@ -0,0 +1,43 @@ +H=15時 +h=午後3時 +j=15時 +C=15時 +Hm=15:32 +hm=午後3:32 +jm=15:32 +Cm=15:32 +Hms=15:32:39 +hms=午後3:32:39 +jms=15:32:39 +Cms=15:32:39 +Hmv=15:32 PT +hmv=午後3:32 PT +jmv=15:32 PT +Cmv=15:32 PT +Hmsv=15:32:39 PT +hmsv=午後3:32:39 PT +jmsv=15:32:39 PT +Cmsv=15:32:39 PT +Bh=昼3時 +Bhm=昼3:32 +Bhms=昼3:32:39 + +M=1月 +MMM=1月 +MEd=1/26(水) +MMMMEd=1月26日(水) +d=26日 +y=4年 +yM=4/1 +yMEd=4/1/26(水) +yMMM=4年1月 +yMMMMEd=4年1月26日(水) +GyM=令和4年1月 +GyMEd=令和4年1月26日(水) +GyMMM=令和4年1月 +GyMMMMEd=令和4年1月26日(水) + +MMMMEdBh=1月26日(水) 昼3時 +MMMMdBh=1月26日 昼3時 +MMMdBh=1月26日 昼3時 +MdBh=1/26 昼3時 diff --git a/test/jdk/java/time/test/java/time/format/TestDateTimeFormatterBuilder.java b/test/jdk/java/time/test/java/time/format/TestDateTimeFormatterBuilder.java index 6dd54ad6880dbffc11bc67a41eb177dc39a9b758..567b331b004a483f89de71a61a65b670ca356510 100644 --- a/test/jdk/java/time/test/java/time/format/TestDateTimeFormatterBuilder.java +++ b/test/jdk/java/time/test/java/time/format/TestDateTimeFormatterBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -1051,7 +1051,7 @@ public class TestDateTimeFormatterBuilder { {"d", "Value(DayOfMonth)"}, {"dd", "Value(DayOfMonth,2)"}, - {"F", "Value(AlignedDayOfWeekInMonth)"}, + {"F", "Value(AlignedWeekOfMonth)"}, {"Q", "Value(QuarterOfYear)"}, {"QQ", "Value(QuarterOfYear,2)"}, diff --git a/test/jdk/java/time/test/java/time/format/TestLocalizedPattern.java b/test/jdk/java/time/test/java/time/format/TestLocalizedPattern.java new file mode 100644 index 0000000000000000000000000000000000000000..49005d55434f374ca83ce267ded9eb7f78759147 --- /dev/null +++ b/test/jdk/java/time/test/java/time/format/TestLocalizedPattern.java @@ -0,0 +1,105 @@ +/* + * 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. + */ +package test.java.time.format; + +import static org.testng.Assert.assertEquals; + +import java.time.DateTimeException; +import java.time.ZonedDateTime; +import java.time.ZoneId; +import java.time.chrono.IsoChronology; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeFormatterBuilder; +import java.util.List; +import java.util.Locale; +import java.util.ResourceBundle; + +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +/** + * Test DateTimeFormatter.ofLocalizedPattern() related methods. + * @bug 8176706 + */ +@Test +public class TestLocalizedPattern { + + private static final ZonedDateTime ZDT = + ZonedDateTime.of(2022, 1, 26, 15, 32, 39, 0, ZoneId.of("America/Los_Angeles")); + + private final static List<Locale> SAMPLE_LOCALES = List.of( + Locale.US, + Locale.forLanguageTag("ja-JP-u-ca-japanese") + ); + + @DataProvider(name = "validSkeletons") + Object[][] data_validSkeletons() { + return SAMPLE_LOCALES.stream() + .flatMap(l -> { + var rb = ResourceBundle.getBundle("test.java.time.format.Skeletons", l); + return rb.keySet().stream().map(key -> new Object[]{key, rb.getString(key), l}); + }) + .toList() + .toArray(new Object[0][0]); + } + + @DataProvider(name = "invalidSkeletons") + Object[][] data_invalidSkeletons() { + return new Object[][] { + {"afo"}, {"hB"}, {"uMMM"}, {"MMMMMM"}, {"BhmsyMMM"}, + }; + } + + @DataProvider(name = "unavailableSkeletons") + Object[][] data_unavailableSkeletons() { + return new Object[][] { + {"yyyyyy"}, {"BBh"}, {"yMMMMEdBBh"}, + }; + } + + @Test(dataProvider = "validSkeletons") + public void test_ofLocalizedPattern(String skeleton, String expected, Locale l) { + var dtf = DateTimeFormatter.ofLocalizedPattern(skeleton).localizedBy(l); + assertEquals(dtf.format(ZDT), expected); + } + + @Test(dataProvider = "invalidSkeletons", expectedExceptions = IllegalArgumentException.class) + public void test_ofLocalizedPattern_invalid(String skeleton) { + DateTimeFormatter.ofLocalizedPattern(skeleton); + } + + @Test(dataProvider = "invalidSkeletons", expectedExceptions = IllegalArgumentException.class) + public void test_appendLocalized_invalid(String skeleton) { + new DateTimeFormatterBuilder().appendLocalized(skeleton); + } + + @Test(dataProvider = "unavailableSkeletons", expectedExceptions = DateTimeException.class) + public void test_ofLocalizedPattern_unavailable(String skeleton) { + DateTimeFormatter.ofLocalizedPattern(skeleton).format(ZDT); + } + + @Test(dataProvider = "unavailableSkeletons", expectedExceptions = DateTimeException.class) + public void test_getLocalizedDateTimePattern_unavailable(String skeleton) { + DateTimeFormatterBuilder.getLocalizedDateTimePattern(skeleton, IsoChronology.INSTANCE, Locale.US); + } +} diff --git a/test/jdk/java/time/test/java/time/format/TestZoneTextPrinterParser.java b/test/jdk/java/time/test/java/time/format/TestZoneTextPrinterParser.java index 77ccf37ad5673fd02ee18ad509e1d1ee961d2595..2686ea02b25ef0d84e2497292b8e74f8573fc3e6 100644 --- a/test/jdk/java/time/test/java/time/format/TestZoneTextPrinterParser.java +++ b/test/jdk/java/time/test/java/time/format/TestZoneTextPrinterParser.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -24,10 +24,12 @@ package test.java.time.format; import static org.testng.Assert.assertEquals; +import static org.testng.Assert.fail; import java.text.DateFormatSymbols; import java.time.ZoneId; import java.time.ZonedDateTime; +import java.time.format.DateTimeParseException; import java.time.format.DecimalStyle; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatterBuilder; @@ -49,7 +51,7 @@ import org.testng.annotations.Test; /* * @test - * @bug 8081022 8151876 8166875 8189784 8206980 + * @bug 8081022 8151876 8166875 8177819 8189784 8206980 8277049 8278434 * @key randomness */ @@ -59,6 +61,11 @@ import org.testng.annotations.Test; @Test public class TestZoneTextPrinterParser extends AbstractTestPrinterParser { + private static final Locale[] SAMPLE_LOCALES = { + Locale.US, Locale.UK, Locale.FRANCE, Locale.GERMANY, Locale.ITALY, Locale.forLanguageTag("es"), + Locale.forLanguageTag("pt-BR"), Locale.forLanguageTag("ru"), + Locale.CHINA, Locale.TAIWAN, Locale.JAPAN, Locale.KOREA, Locale.ROOT}; + protected static DateTimeFormatter getFormatter(Locale locale, TextStyle style) { return new DateTimeFormatterBuilder().appendZoneText(style) .toFormatter(locale) @@ -68,7 +75,6 @@ public class TestZoneTextPrinterParser extends AbstractTestPrinterParser { public void test_printText() { Random r = RandomFactory.getRandom(); int N = 8; - Locale[] locales = Locale.getAvailableLocales(); Set<String> zids = ZoneRulesProvider.getAvailableZoneIds(); ZonedDateTime zdt = ZonedDateTime.now(); @@ -83,7 +89,7 @@ public class TestZoneTextPrinterParser extends AbstractTestPrinterParser { zdt = zdt.withZoneSameLocal(ZoneId.of(zid)); TimeZone tz = TimeZone.getTimeZone(zid); boolean isDST = tz.inDaylightTime(new Date(zdt.toInstant().toEpochMilli())); - for (Locale locale : locales) { + for (Locale locale : SAMPLE_LOCALES) { String longDisplayName = tz.getDisplayName(isDST, TimeZone.LONG, locale); String shortDisplayName = tz.getDisplayName(isDST, TimeZone.SHORT, locale); if ((longDisplayName.startsWith("GMT+") && shortDisplayName.startsWith("GMT+")) @@ -116,9 +122,8 @@ public class TestZoneTextPrinterParser extends AbstractTestPrinterParser { } public void test_ParseText() { - Locale[] locales = new Locale[] { Locale.ENGLISH, Locale.JAPANESE, Locale.FRENCH }; Set<String> zids = ZoneRulesProvider.getAvailableZoneIds(); - for (Locale locale : locales) { + for (Locale locale : SAMPLE_LOCALES) { parseText(zids, locale, TextStyle.FULL, false); parseText(zids, locale, TextStyle.FULL, true); parseText(zids, locale, TextStyle.SHORT, false); @@ -236,4 +241,37 @@ public class TestZoneTextPrinterParser extends AbstractTestPrinterParser { .withDecimalStyle(DecimalStyle.of(locale)); } + @DataProvider(name="roundTripAtOverlap") + Object[][] data_roundTripAtOverlap() { + return new Object[][] { + {"yyyy-MM-dd HH:mm:ss.SSS z", "2021-10-31 02:30:00.000 CET"}, + {"yyyy-MM-dd HH:mm:ss.SSS z", "2021-10-31 02:30:00.000 CEST"}, + {"yyyy-MM-dd HH:mm:ss.SSS z", "2021-11-07 01:30:00.000 EST"}, + {"yyyy-MM-dd HH:mm:ss.SSS z", "2021-11-07 01:30:00.000 EDT"}, + {"yyyy-MM-dd HH:mm:ss.SSS zzzz", "2021-10-31 02:30:00.000 Central European Standard Time"}, + {"yyyy-MM-dd HH:mm:ss.SSS zzzz", "2021-10-31 02:30:00.000 Central European Summer Time"}, + {"yyyy-MM-dd HH:mm:ss.SSS zzzz", "2021-11-07 01:30:00.000 Eastern Standard Time"}, + {"yyyy-MM-dd HH:mm:ss.SSS zzzz", "2021-11-07 01:30:00.000 Eastern Daylight Time"}, + + {"yyyy-MM-dd HH:mm:ss.SSS v", "2021-10-31 02:30:00.000 CET"}, + {"yyyy-MM-dd HH:mm:ss.SSS v", "2021-11-07 01:30:00.000 ET"}, + {"yyyy-MM-dd HH:mm:ss.SSS vvvv", "2021-10-31 02:30:00.000 Central European Time"}, + {"yyyy-MM-dd HH:mm:ss.SSS vvvv", "2021-11-07 01:30:00.000 Eastern Time"}, + }; + } + + @Test(dataProvider="roundTripAtOverlap") + public void test_roundTripAtOverlap(String pattern, String input) { + var dtf = DateTimeFormatter.ofPattern(pattern); + assertEquals(dtf.format(ZonedDateTime.parse(input, dtf)), input); + var lc = input.toLowerCase(Locale.ROOT); + try { + ZonedDateTime.parse(lc, dtf); + fail("Should throw DateTimeParseException"); + } catch (DateTimeParseException ignore) {} + + dtf = new DateTimeFormatterBuilder().parseCaseInsensitive().appendPattern(pattern).toFormatter(); + assertEquals(dtf.format(ZonedDateTime.parse(input, dtf)), input); + assertEquals(dtf.format(ZonedDateTime.parse(lc, dtf)), input); + } } diff --git a/test/jdk/java/util/Currency/CurrencyTest.java b/test/jdk/java/util/Currency/CurrencyTest.java index ad7c596485bbd815eb4592db03ec6140ec65ad80..f82b032e2f818adee64f1f3db3e9ac83486b5c89 100644 --- a/test/jdk/java/util/Currency/CurrencyTest.java +++ b/test/jdk/java/util/Currency/CurrencyTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 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 @@ -139,7 +139,7 @@ public class CurrencyTest { /* * check currency changes - * In current implementation, there is no data of old currency and transition date at jdk/make/data/currency/CurrencyData.properties. + * In current implementation, there is no data of old currency and transition date at jdk/src/java.base/share/data/currency/CurrencyData.properties. * So, all the switch data arrays are empty. In the future, if data of old currency and transition date are necessary for any country, the * arrays here can be updated so that the program can check the currency switch. */ diff --git a/test/jdk/java/util/Currency/ValidateISO4217.java b/test/jdk/java/util/Currency/ValidateISO4217.java index 40bb55cfd1f9ff61f4130ed3bba89593123f393e..a0f09842ffe2cc3ca120fca5dc48406467e8c6c7 100644 --- a/test/jdk/java/util/Currency/ValidateISO4217.java +++ b/test/jdk/java/util/Currency/ValidateISO4217.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 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 @@ -24,7 +24,7 @@ * @test * @bug 4691089 4819436 4942982 5104960 6544471 6627549 7066203 7195759 * 8039317 8074350 8074351 8145952 8187946 8193552 8202026 8204269 - * 8208746 8209775 8264792 8274658 + * 8208746 8209775 8264792 8274658 8283277 * @summary Validate ISO 4217 data for Currency class. * @modules java.base/java.util:open * jdk.localedata @@ -101,7 +101,7 @@ public class ValidateISO4217 { static final String otherCodes = "ADP-AFA-ATS-AYM-AZM-BEF-BGL-BOV-BYB-BYR-CHE-CHW-CLF-COU-CUC-CYP-" + "DEM-EEK-ESP-FIM-FRF-GHC-GRD-GWP-IEP-ITL-LTL-LUF-LVL-MGF-MRO-MTL-MXV-MZM-NLG-" - + "PTE-ROL-RUR-SDD-SIT-SKK-SRG-STD-TMM-TPE-TRL-VEF-UYI-USN-USS-VEB-VED-" + + "PTE-ROL-RUR-SDD-SIT-SLL-SKK-SRG-STD-TMM-TPE-TRL-VEF-UYI-USN-USS-VEB-VED-" + "XAG-XAU-XBA-XBB-XBC-XBD-XDR-XFO-XFU-XPD-XPT-XSU-XTS-XUA-XXX-" + "YUM-ZMK-ZWD-ZWN-ZWR"; diff --git a/test/jdk/java/util/Currency/tablea1.txt b/test/jdk/java/util/Currency/tablea1.txt index 7716863419fc454d186443de5aedc8e63e6ce6a7..62d71c8c94b6d2ba5ebe7cdbc7c843bbee30bd53 100644 --- a/test/jdk/java/util/Currency/tablea1.txt +++ b/test/jdk/java/util/Currency/tablea1.txt @@ -1,12 +1,12 @@ # # -# Amendments up until ISO 4217 AMENDMENT NUMBER 170 -# (As of 1 Oct 2021) +# Amendments up until ISO 4217 AMENDMENT NUMBER 171 +# (As of 16 Mar 2022) # # Version FILEVERSION=3 -DATAVERSION=170 +DATAVERSION=171 # ISO 4217 currency data AF AFN 971 2 @@ -218,7 +218,7 @@ RS RSD 941 2 CS CSD 891 2 #CS EUR 978 2 SC SCR 690 2 -SL SLL 694 2 +SL SLE 925 2 SG SGD 702 2 SK EUR 978 2 # MA 131 diff --git a/test/jdk/java/util/HashMap/WhiteBoxResizeTest.java b/test/jdk/java/util/HashMap/WhiteBoxResizeTest.java index e7374dff5cd2dacd23da144607f72b1665aa5112..ad02b3000e218c8f0f4b02e6bca2efc6610f32a4 100644 --- a/test/jdk/java/util/HashMap/WhiteBoxResizeTest.java +++ b/test/jdk/java/util/HashMap/WhiteBoxResizeTest.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2018, Red Hat, Inc. All rights reserved. + * 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 @@ -21,113 +22,299 @@ * questions. */ +import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; import java.lang.invoke.VarHandle; +import java.util.AbstractMap; +import java.util.AbstractSet; +import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; +import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import java.util.concurrent.ThreadLocalRandom; +import java.util.Set; +import java.util.WeakHashMap; +import java.util.function.Consumer; import java.util.function.Supplier; -import java.util.stream.IntStream; -import static java.util.stream.Collectors.toMap; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNull; /* * @test - * @bug 8210280 + * @bug 8210280 8281631 * @modules java.base/java.util:open - * @summary White box tests for HashMap internals around table resize + * @summary White box tests for HashMap-related internals around table sizing * @run testng WhiteBoxResizeTest - * @key randomness */ public class WhiteBoxResizeTest { - final ThreadLocalRandom rnd = ThreadLocalRandom.current(); + final MethodHandle TABLE_SIZE_FOR; - final VarHandle THRESHOLD; - final VarHandle TABLE; + final VarHandle HM_TABLE; + final VarHandle WHM_TABLE; public WhiteBoxResizeTest() throws ReflectiveOperationException { - Class<?> mClass = HashMap.class; - String nodeClassName = mClass.getName() + "$Node"; - Class<?> nodeArrayClass = Class.forName("[L" + nodeClassName + ";"); - MethodHandles.Lookup lookup = MethodHandles.privateLookupIn(mClass, MethodHandles.lookup()); - TABLE = lookup.findVarHandle(mClass, "table", nodeArrayClass); - this.TABLE_SIZE_FOR = lookup.findStatic( - mClass, "tableSizeFor", - MethodType.methodType(int.class, int.class)); - this.THRESHOLD = lookup.findVarHandle(mClass, "threshold", int.class); + MethodHandles.Lookup hmlookup = MethodHandles.privateLookupIn(HashMap.class, MethodHandles.lookup()); + TABLE_SIZE_FOR = hmlookup.findStatic( + HashMap.class, "tableSizeFor", MethodType.methodType(int.class, int.class)); + HM_TABLE = hmlookup.unreflectVarHandle(HashMap.class.getDeclaredField("table")); + + MethodHandles.Lookup whmlookup = MethodHandles.privateLookupIn(WeakHashMap.class, MethodHandles.lookup()); + WHM_TABLE = whmlookup.unreflectVarHandle(WeakHashMap.class.getDeclaredField("table")); } + /* + * utility methods + */ + int tableSizeFor(int n) { try { return (int) TABLE_SIZE_FOR.invoke(n); - } catch (Throwable t) { throw new AssertionError(t); } + } catch (Throwable t) { + throw new AssertionError(t); + } } - Object[] table(HashMap map) { + Object[] table(Map<?, ?> map) { try { - return (Object[]) TABLE.get(map); - } catch (Throwable t) { throw new AssertionError(t); } + VarHandle vh = map instanceof WeakHashMap ? WHM_TABLE : HM_TABLE; + return (Object[]) vh.get(map); + } catch (Throwable t) { + throw new AssertionError(t); + } } - int capacity(HashMap map) { + int capacity(Map<?, ?> map) { return table(map).length; } - @Test - public void testTableSizeFor() { - assertEquals(tableSizeFor(0), 1); - assertEquals(tableSizeFor(1), 1); - assertEquals(tableSizeFor(2), 2); - assertEquals(tableSizeFor(3), 4); - assertEquals(tableSizeFor(15), 16); - assertEquals(tableSizeFor(16), 16); - assertEquals(tableSizeFor(17), 32); - int maxSize = 1 << 30; - assertEquals(tableSizeFor(maxSize - 1), maxSize); - assertEquals(tableSizeFor(maxSize), maxSize); - assertEquals(tableSizeFor(maxSize + 1), maxSize); - assertEquals(tableSizeFor(Integer.MAX_VALUE), maxSize); + // creates a map with size mappings + Map<String, String> makeMap(int size) { + Map<String, String> map = new HashMap<>(); + putN(map, size); + return map; + } + + // creates a "fake" map: size() returns the given size, but + // the entrySet iterator returns only one entry + Map<String, String> fakeMap(int size) { + return new AbstractMap<>() { + public Set<Map.Entry<String, String>> entrySet() { + return new AbstractSet<Map.Entry<String, String>>() { + public int size() { + return size; + } + + public Iterator<Map.Entry<String, String>> iterator() { + return Set.of(Map.entry("1", "1")).iterator(); + } + }; + } + }; + } + + void putN(Map<String, String> map, int n) { + for (int i = 0; i < n; i++) { + String string = Integer.toString(i); + map.put(string, string); + } + } + + /* + * tests of tableSizeFor + */ + + @DataProvider(name = "tableSizeFor") + public Object[][] tableSizeForCases() { + final int MAX = 1 << 30; + return new Object[][] { + // tableSizeFor(arg), expected + { 0, 1 }, + { 1, 1 }, + { 2, 2 }, + { 3, 4 }, + { 4, 4 }, + { 5, 8 }, + { 15, 16 }, + { 16, 16 }, + { 17, 32 }, + { MAX-1, MAX }, + { MAX, MAX }, + { MAX+1, MAX }, + { Integer.MAX_VALUE, MAX } + }; + } + + @Test(dataProvider = "tableSizeFor") + public void tableSizeFor(int arg, int expected) { + assertEquals(tableSizeFor(arg), expected); } - @Test - public void capacityTestDefaultConstructor() { - capacityTestDefaultConstructor(new HashMap<>()); - capacityTestDefaultConstructor(new LinkedHashMap<>()); + /* + * tests for lazy table allocation + */ + + @DataProvider(name = "lazy") + public Object[][] lazyTableAllocationCases() { + return new Object[][]{ + {new HashMap<>()}, + // { new WeakHashMap<>() }, // WHM doesn't allocate lazily + {new LinkedHashMap<>()} + }; } - void capacityTestDefaultConstructor(HashMap<Integer, Integer> map) { + @Test(dataProvider = "lazy") + public void lazyTableAllocation(Map<?, ?> map) { assertNull(table(map)); + } - map.put(1, 1); - assertEquals(capacity(map), 16); // default initial capacity + /* + * tests for default capacity (no-arg constructor) + */ - map.putAll(IntStream.range(0, 64).boxed().collect(toMap(i -> i, i -> i))); - assertEquals(capacity(map), 128); + @DataProvider(name = "defaultCapacity") + public Object[][] defaultCapacityCases() { + return new Supplier<?>[][]{ + {() -> new HashMap<>()}, + {() -> new LinkedHashMap<>()}, + {() -> new WeakHashMap<>()} + }; } - @Test - public void capacityTestInitialCapacity() { - int initialCapacity = rnd.nextInt(2, 128); - List<Supplier<HashMap<Integer, Integer>>> suppliers = List.of( - () -> new HashMap<>(initialCapacity), - () -> new HashMap<>(initialCapacity, 0.75f), - () -> new LinkedHashMap<>(initialCapacity), - () -> new LinkedHashMap<>(initialCapacity, 0.75f)); + @Test(dataProvider = "defaultCapacity") + public void defaultCapacity(Supplier<Map<String, String>> s) { + Map<String, String> map = s.get(); + map.put("", ""); + assertEquals(capacity(map), 16); + } - for (Supplier<HashMap<Integer, Integer>> supplier : suppliers) { - HashMap<Integer, Integer> map = supplier.get(); - assertNull(table(map)); + /* + * tests for requested capacity (int and int+float constructors) + */ - map.put(1, 1); - assertEquals(capacity(map), tableSizeFor(initialCapacity)); + @DataProvider(name = "requestedCapacity") + public Iterator<Object[]> requestedCapacityCases() { + ArrayList<Object[]> cases = new ArrayList<>(); + for (int i = 2; i < 128; i++) { + int cap = i; + cases.add(new Object[]{"rhm1", cap, (Supplier<Map<String, String>>) () -> new HashMap<>(cap)}); + cases.add(new Object[]{"rhm2", cap, (Supplier<Map<String, String>>) () -> new HashMap<>(cap, 0.75f)}); + cases.add(new Object[]{"rlm1", cap, (Supplier<Map<String, String>>) () -> new LinkedHashMap<>(cap)}); + cases.add(new Object[]{"rlm2", cap, (Supplier<Map<String, String>>) () -> new LinkedHashMap<>(cap, 0.75f)}); + cases.add(new Object[]{"rwm1", cap, (Supplier<Map<String, String>>) () -> new WeakHashMap<>(cap)}); + cases.add(new Object[]{"rwm2", cap, (Supplier<Map<String, String>>) () -> new WeakHashMap<>(cap, 0.75f)}); } + return cases.iterator(); + } + + @Test(dataProvider = "requestedCapacity") + public void requestedCapacity(String label, int cap, Supplier<Map<String, String>> s) { + Map<String, String> map = s.get(); + map.put("", ""); + assertEquals(capacity(map), tableSizeFor(cap)); + } + + /* + * Tests for capacity after map is populated with a given number N of mappings. + * Maps are populated using a copy constructor on a map with N mappings, + * other constructors followed by N put() calls, and other constructors followed + * by putAll() on a map with N mappings. + * + * String labels encode the test case for ease of diagnosis if one of the test cases fails. + * For example, "plm2pn" is "populated LinkedHashMap, 2-arg constructor, followed by putN". + */ + + // helper method for one populated capacity case, to provide target types for lambdas + Object[] pcc(String label, + int size, + int expectedCapacity, + Supplier<Map<String, String>> supplier, + Consumer<Map<String, String>> consumer) { + return new Object[]{label, size, expectedCapacity, supplier, consumer}; + } + + List<Object[]> genPopulatedCapacityCases(int size, int cap) { + return Arrays.asList( + pcc("phmcpy", size, cap, () -> new HashMap<>(makeMap(size)), map -> { }), + pcc("phm0pn", size, cap, () -> new HashMap<>(), map -> { putN(map, size); }), + pcc("phm1pn", size, cap, () -> new HashMap<>(cap), map -> { putN(map, size); }), + pcc("phm2pn", size, cap, () -> new HashMap<>(cap, 0.75f), map -> { putN(map, size); }), + pcc("phm0pa", size, cap, () -> new HashMap<>(), map -> { map.putAll(makeMap(size)); }), + pcc("phm1pa", size, cap, () -> new HashMap<>(cap), map -> { map.putAll(makeMap(size)); }), + pcc("phm2pa", size, cap, () -> new HashMap<>(cap, 0.75f), map -> { map.putAll(makeMap(size)); }), + + pcc("plmcpy", size, cap, () -> new LinkedHashMap<>(makeMap(size)), map -> { }), + pcc("plm0pn", size, cap, () -> new LinkedHashMap<>(), map -> { putN(map, size); }), + pcc("plm1pn", size, cap, () -> new LinkedHashMap<>(cap), map -> { putN(map, size); }), + pcc("plm2pn", size, cap, () -> new LinkedHashMap<>(cap, 0.75f), map -> { putN(map, size); }), + pcc("plm0pa", size, cap, () -> new LinkedHashMap<>(), map -> { map.putAll(makeMap(size)); }), + pcc("plm1pa", size, cap, () -> new LinkedHashMap<>(cap), map -> { map.putAll(makeMap(size)); }), + pcc("plm2pa", size, cap, () -> new LinkedHashMap<>(cap, 0.75f), map -> { map.putAll(makeMap(size)); }), + + pcc("pwmcpy", size, cap, () -> new WeakHashMap<>(makeMap(size)), map -> { }), + pcc("pwm0pn", size, cap, () -> new WeakHashMap<>(), map -> { putN(map, size); }), + pcc("pwm1pn", size, cap, () -> new WeakHashMap<>(cap), map -> { putN(map, size); }), + pcc("pwm2pn", size, cap, () -> new WeakHashMap<>(cap, 0.75f), map -> { putN(map, size); }), + pcc("pwm0pa", size, cap, () -> new WeakHashMap<>(), map -> { map.putAll(makeMap(size)); }), + pcc("pwm1pa", size, cap, () -> new WeakHashMap<>(cap), map -> { map.putAll(makeMap(size)); }), + pcc("pwm2pa", size, cap, () -> new WeakHashMap<>(cap, 0.75f), map -> { map.putAll(makeMap(size)); }) + ); + } + + List<Object[]> genFakePopulatedCapacityCases(int size, int cap) { + return Arrays.asList( + pcc("fhmcpy", size, cap, () -> new HashMap<>(fakeMap(size)), map -> { }), + pcc("fhm0pa", size, cap, () -> new HashMap<>(), map -> { map.putAll(fakeMap(size)); }), + pcc("fhm1pa", size, cap, () -> new HashMap<>(cap), map -> { map.putAll(fakeMap(size)); }), + pcc("fhm2pa", size, cap, () -> new HashMap<>(cap, 0.75f), map -> { map.putAll(fakeMap(size)); }), + + pcc("flmcpy", size, cap, () -> new LinkedHashMap<>(fakeMap(size)), map -> { }), + pcc("flm0pa", size, cap, () -> new LinkedHashMap<>(), map -> { map.putAll(fakeMap(size)); }), + pcc("flm1pa", size, cap, () -> new LinkedHashMap<>(cap), map -> { map.putAll(fakeMap(size)); }), + pcc("flm2pa", size, cap, () -> new LinkedHashMap<>(cap, 0.75f), map -> { map.putAll(fakeMap(size)); }), + + pcc("fwmcpy", size, cap, () -> new WeakHashMap<>(fakeMap(size)), map -> { }), + // pcc("fwm0pa", size, cap, () -> new WeakHashMap<>(), map -> { map.putAll(fakeMap(size)); }), // see note + pcc("fwm1pa", size, cap, () -> new WeakHashMap<>(cap), map -> { map.putAll(fakeMap(size)); }), + pcc("fwm2pa", size, cap, () -> new WeakHashMap<>(cap, 0.75f), map -> { map.putAll(fakeMap(size)); }) + ); + + // Test case "fwm0pa" is commented out because WeakHashMap uses a different allocation + // policy from the other map implementations: it deliberately under-allocates in this case. + } + + @DataProvider(name = "populatedCapacity") + public Iterator<Object[]> populatedCapacityCases() { + ArrayList<Object[]> cases = new ArrayList<>(); + cases.addAll(genPopulatedCapacityCases(11, 16)); + cases.addAll(genPopulatedCapacityCases(12, 16)); + cases.addAll(genPopulatedCapacityCases(13, 32)); + cases.addAll(genPopulatedCapacityCases(64, 128)); + + // numbers in this range are truncated by a float computation with 0.75f + // but can get an exact result with a double computation with 0.75d + cases.addAll(genFakePopulatedCapacityCases(25165824, 33554432)); + cases.addAll(genFakePopulatedCapacityCases(25165825, 67108864)); + cases.addAll(genFakePopulatedCapacityCases(25165826, 67108864)); + + return cases.iterator(); } + + @Test(dataProvider = "populatedCapacity") + public void populatedCapacity(String label, // unused, included for diagnostics + int size, // unused, included for diagnostics + int expectedCapacity, + Supplier<Map<String, String>> s, + Consumer<Map<String, String>> c) { + Map<String, String> map = s.get(); + c.accept(map); + assertEquals(capacity(map), expectedCapacity); + } + } diff --git a/test/jdk/java/util/Hashtable/DeserializedLength.java b/test/jdk/java/util/Hashtable/DeserializedLength.java index 376c1f026d0ebc1f03bebf83d77de6cbe4334e8e..d515878fd3600208cced4a6e8cf1ff935ecbb110 100644 --- a/test/jdk/java/util/Hashtable/DeserializedLength.java +++ b/test/jdk/java/util/Hashtable/DeserializedLength.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -100,7 +100,7 @@ public class DeserializedLength { ); for (int elements : new int[]{10, 50, 500, 5000}) { - for (float loadFactor : new float[]{0.15f, 0.5f, 0.75f, 1.0f, 2.5f}) { + for (float loadFactor : new float[]{0.25f, 0.5f, 0.75f, 1.0f, 2.5f}) { ok &= testDeserializedLength(elements, loadFactor); } } diff --git a/test/jdk/java/util/Locale/Bug7069824.java b/test/jdk/java/util/Locale/Bug7069824.java index 0eb1f21c2756f0a1aec8cfa6cd865d1a9796b872..905cde17d50202deab7760de47dbfea529e34f95 100644 --- a/test/jdk/java/util/Locale/Bug7069824.java +++ b/test/jdk/java/util/Locale/Bug7069824.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -23,7 +23,7 @@ /* * @test - * @bug 7069824 8042360 8032842 8175539 8210443 8242010 + * @bug 7069824 8042360 8032842 8175539 8210443 8242010 8276302 * @summary Verify implementation for Locale matching. * @run testng/othervm Bug7069824 */ @@ -208,27 +208,61 @@ public class Bug7069824 { Object[][] LFilterTagsData() { return new Object[][] { // Range, LanguageTags, FilteringMode, Expected language tags + {"fr-FR, fr-BG;q=0.8, *;q=0.5, en;q=0", "en-US, fr-FR, fr-CA, fr-BG", + null, "fr-FR, fr-BG, fr-CA"}, + {"fr-FR, fr-*-BG;q=0.8, *;q=0.5, en;q=0", "en-US, fr-FR, fr-CA, fr-BG", + null, "fr-FR, fr-BG, fr-CA"}, + {"en;q=0.2, *;q=0.6, ja", "de-DE, en, ja-JP-hepburn, fr-JP, he", - null, "de-DE, en, ja-JP-hepburn, fr-JP, he"}, + null, "ja-JP-hepburn, de-DE, en, fr-JP, he"}, {"en;q=0.2, ja-JP, fr-JP", "de-DE, en, ja-JP-hepburn, fr, he", null, "ja-JP-hepburn, en"}, {"en;q=0.2, ja-JP, fr-JP, iw", "de-DE, he, en, ja-JP-hepburn, fr, he-IL", null, "ja-JP-hepburn, he, he-IL, en"}, {"en;q=0.2, ja-JP, fr-JP, he", "de-DE, en, ja-JP-hepburn, fr, iw-IL", null, "ja-JP-hepburn, iw-IL, en"}, + {"de-DE", "de-DE, de-de, de-Latn-DE, de-Latf-DE, de-DE-x-goethe, " + "de-Latn-DE-1996, de-Deva-DE, de, de-x-DE, de-Deva", - MAP_EXTENDED_RANGES, "de-DE, de-DE-x-goethe"}, + null, "de-DE, de-DE-x-goethe"}, + {"de-*-DE", "de-DE, de-de, de-Latn-DE, de-Latf-DE, de-DE-x-goethe, " + + "de-Latn-DE-1996, de-Deva-DE, de, de-x-DE, de-Deva", + null, + "de-DE, de-Latn-DE, de-Latf-DE, de-DE-x-goethe, " + + "de-Latn-DE-1996, de-Deva-DE"}, + {"de-DE", "de-DE, de-de, de-Latn-DE, de-Latf-DE, de-DE-x-goethe, " + "de-Latn-DE-1996, de-Deva-DE, de, de-x-DE, de-Deva", EXTENDED_FILTERING, "de-DE, de-Latn-DE, de-Latf-DE, de-DE-x-goethe, " - + "de-Latn-DE-1996, de-Deva-DE"}, + + "de-Latn-DE-1996, de-Deva-DE"}, {"de-*-DE", "de-DE, de-de, de-Latn-DE, de-Latf-DE, de-DE-x-goethe, " + "de-Latn-DE-1996, de-Deva-DE, de, de-x-DE, de-Deva", EXTENDED_FILTERING, "de-DE, de-Latn-DE, de-Latf-DE, de-DE-x-goethe, " - + "de-Latn-DE-1996, de-Deva-DE"}, + + "de-Latn-DE-1996, de-Deva-DE"}, + + {"de-DE", "de-DE, de-de, de-Latn-DE, de-Latf-DE, de-DE-x-goethe, " + + "de-Latn-DE-1996, de-Deva-DE, de, de-x-DE, de-Deva", + IGNORE_EXTENDED_RANGES, + "de-DE, de-DE-x-goethe"}, + {"de-*-DE", "de-DE, de-de, de-Latn-DE, de-Latf-DE, de-DE-x-goethe, " + + "de-Latn-DE-1996, de-Deva-DE, de, de-x-DE, de-Deva", + IGNORE_EXTENDED_RANGES, + ""}, + + {"de-DE", "de-DE, de-de, de-Latn-DE, de-Latf-DE, de-DE-x-goethe, " + + "de-Latn-DE-1996, de-Deva-DE, de, de-x-DE, de-Deva", + MAP_EXTENDED_RANGES, "de-DE, de-DE-x-goethe"}, + {"de-*-DE", "de-DE, de-de, de-Latn-DE, de-Latf-DE, de-DE-x-goethe, " + + "de-Latn-DE-1996, de-Deva-DE, de, de-x-DE, de-Deva", + MAP_EXTENDED_RANGES, "de-DE, de-DE-x-goethe"}, + + {"de-DE", "de-DE, de-de, de-Latn-DE, de-Latf-DE, de-DE-x-goethe, " + + "de-Latn-DE-1996, de-Deva-DE, de, de-x-DE, de-Deva", + REJECT_EXTENDED_RANGES, "de-DE, de-DE-x-goethe"}, + + // The next test in this chain is in testLFilterTagsIAE. }; } @@ -380,6 +414,15 @@ public class Bug7069824 { ranges, tags, expectedTags, actualTags)); } + @Test(expectedExceptions = IllegalArgumentException.class) + public void testLFilterTagsIAE() { + String ranges = "de-*-DE"; + String tags = "de-DE, de-de, de-Latn-DE, de-Latf-DE, de-DE-x-goethe, " + + "de-Latn-DE-1996, de-Deva-DE, de, de-x-DE, de-Deva"; + List<LanguageRange> priorityList = LanguageRange.parse(ranges); + showLanguageTags(Locale.filterTags(priorityList, generateLanguageTags(tags), REJECT_EXTENDED_RANGES)); + } + @Test(dataProvider = "LLookupData") public void testLLookup(String ranges, String tags, String expectedLocale) { List<LanguageRange> priorityList = LanguageRange.parse(ranges); diff --git a/test/jdk/java/util/Locale/LSRDataTest.java b/test/jdk/java/util/Locale/LSRDataTest.java index 81edf48b9b0466cc84512c53c8deda24b7123fa6..f32642981b5230d0d411cd72637e85398c7019d7 100644 --- a/test/jdk/java/util/Locale/LSRDataTest.java +++ b/test/jdk/java/util/Locale/LSRDataTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -52,11 +52,11 @@ public class LSRDataTest { private static final Map<String, List<String>> multiLangEquivsMap = new HashMap<>(); private static final Map<String, String> regionVariantEquivMap = new HashMap<>(); - // path to the lsr file from the make folder, this test relies on the - // relative path to the file in the make folder, considering - // test and make will always exist in the same jdk layout + // path to the lsr file from the data folder, this test relies on the + // relative path to the file in the data folder, considering + // test and src/.../data will always exist in the same jdk layout private static final String LSR_FILE_PATH = System.getProperty("test.src", ".") - + "/../../../../../make/data/lsrdata/language-subtag-registry.txt"; + + "/../../../../../src/java.base/share/data/lsrdata/language-subtag-registry.txt"; public static void main(String[] args) throws IOException { diff --git a/test/jdk/java/util/Objects/BasicObjectsTest.java b/test/jdk/java/util/Objects/BasicObjectsTest.java index a7636ef11d52b91b99e0af2c9a888955c30b40fe..51268d4cbaf4c0a236dc6b74358faca3f7905d40 100644 --- a/test/jdk/java/util/Objects/BasicObjectsTest.java +++ b/test/jdk/java/util/Objects/BasicObjectsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 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 @@ -23,9 +23,8 @@ /* * @test - * @bug 6797535 6889858 6891113 8013712 8011800 8014365 + * @bug 6797535 6889858 6891113 8013712 8011800 8014365 8280168 * @summary Basic tests for methods in java.util.Objects - * @author Joseph D. Darcy */ import java.util.*; @@ -40,6 +39,7 @@ public class BasicObjectsTest { errors += testHash(); errors += testToString(); errors += testToString2(); + errors += testToIdentityString(); errors += testCompare(); errors += testRequireNonNull(); errors += testIsNull(); @@ -134,6 +134,37 @@ public class BasicObjectsTest { return errors; } + private static int testToIdentityString() { + int errors = 0; + // Test null behavior + try { + Objects.toIdentityString(null); + errors++; + } catch (NullPointerException npe) { + ; // Expected + } + // Behavior on typical objects + Object o = new Object(){}; + errors += (Objects.toIdentityString(o).equals(o.toString()))? 0 : 1; + // Verify object's toString *not* called + Object badToString = new Object() { + @Override + public String toString() { + throw new RuntimeException(); + } + }; + Objects.toIdentityString(badToString); + // Verify object's hashCode *not* called + Object badHashCode = new Object() { + @Override + public int hashCode() { + throw new RuntimeException("0xDEADBEFF"); + } + }; + Objects.toIdentityString(badHashCode); + return errors; + } + private static int testCompare() { int errors = 0; String[] values = {"e. e. cummings", "zzz"}; diff --git a/test/jdk/java/util/Properties/PropertiesStoreTest.java b/test/jdk/java/util/Properties/PropertiesStoreTest.java index da2be3b7cb57c3bae386809de855add9156f6b94..ab58ea789035dbebbbf25734304709fca97e3c07 100644 --- a/test/jdk/java/util/Properties/PropertiesStoreTest.java +++ b/test/jdk/java/util/Properties/PropertiesStoreTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -37,21 +37,28 @@ import java.time.format.DateTimeParseException; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; +import java.util.HashSet; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Properties; import java.util.Set; import java.util.TreeSet; +import java.util.stream.Collectors; /* * @test * @summary tests the order in which the Properties.store() method writes out the properties - * @bug 8231640 - * @run testng PropertiesStoreTest + * @bug 8231640 8282023 + * @run testng/othervm PropertiesStoreTest */ public class PropertiesStoreTest { private static final String DATE_FORMAT_PATTERN = "EEE MMM dd HH:mm:ss zzz uuuu"; + // use a neutral locale, since when the date comment was written by Properties.store(...), + // it internally calls the Date.toString() which always writes in a locale insensitive manner + private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern(DATE_FORMAT_PATTERN, Locale.ROOT); + private static final Locale PREV_LOCALE = Locale.getDefault(); @DataProvider(name = "propsProvider") private Object[][] createProps() { @@ -91,6 +98,26 @@ public class PropertiesStoreTest { }; } + /** + * Returns a {@link Locale} to use for testing + */ + @DataProvider(name = "localeProvider") + private Object[][] provideLocales() { + // pick a non-english locale for testing + Set<Locale> locales = Arrays.stream(Locale.getAvailableLocales()) + .filter(l -> !l.getLanguage().isEmpty() && !l.getLanguage().equals("en")) + .limit(1) + .collect(Collectors.toCollection(HashSet::new)); + locales.add(Locale.getDefault()); // always test the default locale + locales.add(Locale.US); // guaranteed to be present + locales.add(Locale.ROOT); // guaranteed to be present + + // return the chosen locales + return locales.stream() + .map(m -> new Locale[] {m}) + .toArray(n -> new Object[n][0]); + } + /** * Tests that the {@link Properties#store(Writer, String)} API writes out the properties * in the expected order @@ -153,29 +180,45 @@ public class PropertiesStoreTest { /** * Tests that {@link Properties#store(Writer, String)} writes out a proper date comment */ - @Test - public void testStoreWriterDateComment() throws Exception { - final Properties props = new Properties(); - props.setProperty("a", "b"); - final Path tmpFile = Files.createTempFile("8231640", "props"); - try (final Writer writer = Files.newBufferedWriter(tmpFile)) { - props.store(writer, null); + @Test(dataProvider = "localeProvider") + public void testStoreWriterDateComment(final Locale testLocale) throws Exception { + // switch the default locale to the one being tested + Locale.setDefault(testLocale); + System.out.println("Using locale: " + testLocale + " for Properties#store(Writer) test"); + try { + final Properties props = new Properties(); + props.setProperty("a", "b"); + final Path tmpFile = Files.createTempFile("8231640", "props"); + try (final Writer writer = Files.newBufferedWriter(tmpFile)) { + props.store(writer, null); + } + testDateComment(tmpFile); + } finally { + // reset to the previous one + Locale.setDefault(PREV_LOCALE); } - testDateComment(tmpFile); } /** * Tests that {@link Properties#store(OutputStream, String)} writes out a proper date comment */ - @Test - public void testStoreOutputStreamDateComment() throws Exception { - final Properties props = new Properties(); - props.setProperty("a", "b"); - final Path tmpFile = Files.createTempFile("8231640", "props"); - try (final Writer writer = Files.newBufferedWriter(tmpFile)) { - props.store(writer, null); + @Test(dataProvider = "localeProvider") + public void testStoreOutputStreamDateComment(final Locale testLocale) throws Exception { + // switch the default locale to the one being tested + Locale.setDefault(testLocale); + System.out.println("Using locale: " + testLocale + " for Properties#store(OutputStream) test"); + try { + final Properties props = new Properties(); + props.setProperty("a", "b"); + final Path tmpFile = Files.createTempFile("8231640", "props"); + try (final Writer writer = Files.newBufferedWriter(tmpFile)) { + props.store(writer, null); + } + testDateComment(tmpFile); + } finally { + // reset to the previous one + Locale.setDefault(PREV_LOCALE); } - testDateComment(tmpFile); } /** @@ -199,7 +242,7 @@ public class PropertiesStoreTest { Assert.fail("No comment line found in the stored properties file " + file); } try { - DateTimeFormatter.ofPattern(DATE_FORMAT_PATTERN).parse(comment); + FORMATTER.parse(comment); } catch (DateTimeParseException pe) { Assert.fail("Unexpected date comment: " + comment, pe); } diff --git a/test/jdk/java/util/Properties/StoreReproducibilityTest.java b/test/jdk/java/util/Properties/StoreReproducibilityTest.java index 5f865c29328239d3f3ddb537913b9214a57ac699..c4b1853a1d6abb715f95c50c25987237e370367a 100644 --- a/test/jdk/java/util/Properties/StoreReproducibilityTest.java +++ b/test/jdk/java/util/Properties/StoreReproducibilityTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -44,7 +44,7 @@ import java.util.TimeZone; /* * @test * @summary Tests that the Properties.store() APIs generate output that is reproducible - * @bug 8231640 + * @bug 8231640 8282023 * @library /test/lib * @run driver StoreReproducibilityTest */ @@ -52,8 +52,8 @@ public class StoreReproducibilityTest { private static final String DATE_FORMAT_PATTERN = "EEE MMM dd HH:mm:ss zzz uuuu"; private static final String SYS_PROP_JAVA_PROPERTIES_DATE = "java.properties.date"; - private static final DateTimeFormatter reproducibleDateTimeFormatter = DateTimeFormatter.ofPattern(DATE_FORMAT_PATTERN) - .withLocale(Locale.ROOT).withZone(ZoneOffset.UTC); + private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern(DATE_FORMAT_PATTERN, Locale.ROOT) + .withZone(ZoneOffset.UTC); public static void main(final String[] args) throws Exception { // no security manager enabled @@ -88,7 +88,7 @@ public class StoreReproducibilityTest { */ private static void testWithoutSecurityManager() throws Exception { final List<Path> storedFiles = new ArrayList<>(); - final String sysPropVal = reproducibleDateTimeFormatter.format(Instant.ofEpochSecond(243535322)); + final String sysPropVal = FORMATTER.format(Instant.ofEpochSecond(243535322)); for (int i = 0; i < 5; i++) { final Path tmpFile = Files.createTempFile("8231640", ".props"); storedFiles.add(tmpFile); @@ -130,7 +130,7 @@ public class StoreReproducibilityTest { }; """)); final List<Path> storedFiles = new ArrayList<>(); - final String sysPropVal = reproducibleDateTimeFormatter.format(Instant.ofEpochSecond(1234342423)); + final String sysPropVal = FORMATTER.format(Instant.ofEpochSecond(1234342423)); for (int i = 0; i < 5; i++) { final Path tmpFile = Files.createTempFile("8231640", ".props"); storedFiles.add(tmpFile); @@ -174,7 +174,7 @@ public class StoreReproducibilityTest { }; """)); final List<Path> storedFiles = new ArrayList<>(); - final String sysPropVal = reproducibleDateTimeFormatter.format(Instant.ofEpochSecond(1234342423)); + final String sysPropVal = FORMATTER.format(Instant.ofEpochSecond(1234342423)); for (int i = 0; i < 5; i++) { final Path tmpFile = Files.createTempFile("8231640", ".props"); storedFiles.add(tmpFile); @@ -425,10 +425,10 @@ public class StoreReproducibilityTest { System.out.println("Found date comment " + dateComment + " in file " + destFile); final Date parsedDate; try { - Instant instant = Instant.from(DateTimeFormatter.ofPattern(DATE_FORMAT_PATTERN).parse(dateComment)); + Instant instant = Instant.from(FORMATTER.parse(dateComment)); parsedDate = new Date(instant.toEpochMilli()); } catch (DateTimeParseException pe) { - throw new RuntimeException("Unexpected date " + dateComment + " in stored properties " + destFile); + throw new RuntimeException("Unexpected date " + dateComment + " in stored properties " + destFile, pe); } if (!parsedDate.after(date)) { throw new RuntimeException("Expected date comment " + dateComment + " to be after " + date diff --git a/test/jdk/java/util/Random/RandomNextDoubleBoundary.java b/test/jdk/java/util/Random/RandomNextDoubleBoundary.java new file mode 100644 index 0000000000000000000000000000000000000000..f913d22ab02482dbee350273de0fd524653246c2 --- /dev/null +++ b/test/jdk/java/util/Random/RandomNextDoubleBoundary.java @@ -0,0 +1,94 @@ +/* + * 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. + */ + +/* + * @test + * @summary Verify nextDouble stays within range + * @bug 8280550 8280950 8281183 + */ + +import java.util.SplittableRandom; +import java.util.random.RandomGenerator; + +public class RandomNextDoubleBoundary { + public static void main(String... args) { + negativeBounds(); + positiveBounds(); + } + + private static void negativeBounds() { + // Both bounds are negative + double lowerBound = -1.0000000000000002; + double upperBound = -1.0; + var sr = new SplittableRandom(42L); + var r = sr.nextDouble(lowerBound, upperBound); + + if (r >= upperBound) { + System.err.println("r = " + r + "\t" + Double.toHexString(r)); + System.err.println("ub = " + upperBound + "\t" + Double.toHexString(upperBound)); + throw new RuntimeException("Greater than upper bound"); + } + + if (r < lowerBound) { + System.err.println("r = " + r + "\t" + Double.toHexString(r)); + System.err.println("lb = " + lowerBound + "\t" + Double.toHexString(lowerBound)); + throw new RuntimeException("Less than lower bound"); + } + } + + private static void positiveBounds() { + double[][] originAndBounds = {{10, 100}, + {12345, 123456}, + {5432167.234, 54321678.1238}}; + for (double[] originAndBound : originAndBounds) { + nextDoublesWithRange(originAndBound[0], originAndBound[1]); + } + } + + public static void nextDoublesWithRange(double origin, double bound) { + RandomGenerator rg = new RandomGenerator() { + @Override + public double nextDouble() { + return Double.MAX_VALUE; + } + + @Override + public long nextLong() { + return 0; + } + }; + double value = rg.nextDouble(origin, bound); + + if (bound > 0) { + value = rg.nextDouble(bound); // Equivalent to nextDouble(0.0, bound) + assertTrue(value >= 0.0); + assertTrue(value < bound); + } + } + + public static void assertTrue(boolean condition) { + if (!condition) { + throw new AssertionError(); + } + } +} diff --git a/test/jdk/java/util/Random/T8282144.java b/test/jdk/java/util/Random/T8282144.java new file mode 100644 index 0000000000000000000000000000000000000000..4a0218602f27ec84b3510ec3f761a9df828626c7 --- /dev/null +++ b/test/jdk/java/util/Random/T8282144.java @@ -0,0 +1,71 @@ +/* + * 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. + */ + +import java.util.random.*; +import jdk.internal.util.random.RandomSupport; + +/** + * @test + * @summary RandomSupport.convertSeedBytesToLongs sign extension overwrites previous bytes. + * @bug 8282144 + * @modules java.base/jdk.internal.util.random + * @run main T8282144 + * @key randomness + */ + + +public class T8282144 { + public static void main(String[] args) { + RandomGenerator rng = RandomGeneratorFactory.of("L64X128MixRandom").create(42); + + for (int i = 1; i < 8; i++) { + byte[] seed = new byte[i]; + + for (int j = 0; j < 10; j++) { + rng.nextBytes(seed); + + long[] existing = RandomSupport.convertSeedBytesToLongs(seed, 1, 1); + long[] testing = convertSeedBytesToLongsFixed(seed, 1, 1); + + for (int k = 0; k < existing.length; k++) { + if (existing[k] != testing[k]) { + throw new RuntimeException("convertSeedBytesToLongs incorrect"); + } + } + } + } + } + + + public static long[] convertSeedBytesToLongsFixed(byte[] seed, int n, int z) { + final long[] result = new long[n]; + final int m = Math.min(seed.length, n << 3); + + // Distribute seed bytes into the words to be formed. + for (int j = 0; j < m; j++) { + result[j >> 3] = (result[j >> 3] << 8) | (seed[j] & 0xff); + } + + return result; + } +} diff --git a/test/jdk/java/util/ResourceBundle/exeNullCallerResourceBundle/NullCallerResourceBundle.java b/test/jdk/java/util/ResourceBundle/exeNullCallerResourceBundle/NullCallerResourceBundle.java new file mode 100644 index 0000000000000000000000000000000000000000..edbcf3ba3164b3a9a1793c8bff8d8fe525f203b8 --- /dev/null +++ b/test/jdk/java/util/ResourceBundle/exeNullCallerResourceBundle/NullCallerResourceBundle.java @@ -0,0 +1,83 @@ +/* + * 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. + * + */ + +/** + * @test + * @bug 8280902 + * @summary Test uses custom launcher that starts VM using JNI that verifies + * ResourceBundle::getBundle with null caller class functions properly + * using the system class loader unnamed module. The custom launcher + * creates a properties file and passes the VM option to the JNI + * functionality for the resource lookup. + * @library /test/lib + * @requires os.family != "aix" + * @run main/native NullCallerResourceBundle + */ + +// Test disabled on AIX since we cannot invoke the JVM on the primordial thread. + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Properties; +import jdk.test.lib.Platform; +import jdk.test.lib.process.OutputAnalyzer; + +public class NullCallerResourceBundle { + public static void main(String[] args) throws IOException { + + // build a properties file for the native test + var propPath = Path.of(System.getProperty("test.classes"), "NullCallerResource.properties"); + try (var stream = Files.newOutputStream(propPath)) { + var props = new Properties(); + props.put("message", "Hello!"); + props.save(stream, "Test property list"); + } + + var launcher = Path.of(System.getProperty("test.nativepath"), "NullCallerResourceBundle"); + var classpathAppend = "-Djava.class.path=" + System.getProperty("test.classes"); + var pb = new ProcessBuilder(launcher.toString(), classpathAppend); + var env = pb.environment(); + + var libDir = Platform.libDir().toString(); + var vmDir = Platform.jvmLibDir().toString(); + + // set up shared library path + var sharedLibraryPathEnvName = Platform.sharedLibraryPathVariableName(); + env.compute(sharedLibraryPathEnvName, + (k, v) -> (v == null) ? libDir : v + File.pathSeparator + libDir); + env.compute(sharedLibraryPathEnvName, + (k, v) -> (v == null) ? vmDir : v + File.pathSeparator + vmDir); + + System.out.println("Launching: " + launcher + " shared library path: " + + env.get(sharedLibraryPathEnvName)); + new OutputAnalyzer(pb.start()) + .outputTo(System.out) + .errorTo(System.err) + .shouldHaveExitValue(0); + } + +} + diff --git a/test/jdk/java/util/ResourceBundle/exeNullCallerResourceBundle/exeNullCallerResourceBundle.c b/test/jdk/java/util/ResourceBundle/exeNullCallerResourceBundle/exeNullCallerResourceBundle.c new file mode 100644 index 0000000000000000000000000000000000000000..309873df795866cd9a0303143a94002a60282a63 --- /dev/null +++ b/test/jdk/java/util/ResourceBundle/exeNullCallerResourceBundle/exeNullCallerResourceBundle.c @@ -0,0 +1,102 @@ +/* + * 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 <stdio.h> +#include <stdlib.h> + +#include "jni.h" +#undef NDEBUG +#include "assert.h" +#include "string.h" + + +/* + * The java test running this native test passes in an argument to provide as + * an option for the configuration of the JVM. The system classpath has the + * classpath of the java test appended so it can pick up the resource that + * was created by the java part of the test. + */ +int main(int argc, char** args) { + JavaVM *jvm; + JNIEnv *env; + JavaVMInitArgs vm_args; + JavaVMOption options[1]; + jint rc; + + assert(argc == 2); + options[0].optionString = args[1]; + + vm_args.version = JNI_VERSION_1_2; + vm_args.nOptions = 1; + vm_args.options = options; + + if ((rc = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args)) != JNI_OK) { + printf("ERROR: cannot create VM.\n"); + exit(-1); + } + + // b = ResourceBundle.getBundle("NullCallerResource"); + jclass class_ResourceBundle = (*env)->FindClass(env, "java/util/ResourceBundle"); + assert(class_ResourceBundle != NULL); + jmethodID mid_ResourceBundle_getBundle = (*env)->GetStaticMethodID(env, class_ResourceBundle, "getBundle", "(Ljava/lang/String;)Ljava/util/ResourceBundle;" ); + assert(mid_ResourceBundle_getBundle != NULL); + jobject resourceName = (*env)->NewStringUTF(env, "NullCallerResource"); + assert(resourceName != NULL); + jobject b = (*env)->CallStaticObjectMethod(env, class_ResourceBundle, mid_ResourceBundle_getBundle, resourceName); + if ((*env)->ExceptionOccurred(env) != NULL) { + printf("ERROR: Exception was thrown calling ResourceBundle::getBundle.\n"); + (*env)->ExceptionDescribe(env); + exit(-1); + } + + // msg = b.getString("message"); + jmethodID mid_ResourceBundle_getString = (*env)->GetMethodID(env, class_ResourceBundle, "getString", "(Ljava/lang/String;)Ljava/lang/String;" ); + assert(mid_ResourceBundle_getString != NULL); + jobject key = (*env)->NewStringUTF(env, "message"); + jobject msg =(*env)->CallObjectMethod(env, b, mid_ResourceBundle_getString, key); + if ((*env)->ExceptionOccurred(env) != NULL) { + printf("ERROR: Exception was thrown calling ResourceBundle::getString.\n"); + (*env)->ExceptionDescribe(env); + exit(-1); + } + assert(msg != NULL); + + // check the message + const char* cstr = (*env)->GetStringUTFChars(env, msg, NULL); + assert(cstr != NULL); + assert(strcmp(cstr,"Hello!") == 0); + + // ResourceBundle.clearCache() + jmethodID mid_ResourceBundle_clearCache = (*env)->GetStaticMethodID(env, class_ResourceBundle, "clearCache", "()V" ); + assert(mid_ResourceBundle_clearCache != NULL); + (*env)->CallStaticVoidMethod(env, class_ResourceBundle, mid_ResourceBundle_clearCache); + if ((*env)->ExceptionOccurred(env) != NULL) { + printf("ERROR: Exception was thrown calling ResourceBundle::clearCache.\n"); + (*env)->ExceptionDescribe(env); + exit(-1); + } + + (*jvm)->DestroyJavaVM(jvm); + return 0; +} + diff --git a/test/jdk/java/util/concurrent/ConcurrentHashMap/MapLoops.java b/test/jdk/java/util/concurrent/ConcurrentHashMap/MapLoops.java index 0f52bc67f085a115d4c4d3ffdddab360fc4e9816..922b18836dd877a36090f4cc0a601c2bec6b4a1b 100644 --- a/test/jdk/java/util/concurrent/ConcurrentHashMap/MapLoops.java +++ b/test/jdk/java/util/concurrent/ConcurrentHashMap/MapLoops.java @@ -45,6 +45,14 @@ * @run main/timeout=1600 MapLoops */ +/* + * @test + * @summary Exercise multithreaded maps, using only heavy monitors. + * @requires os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64" | os.arch=="aarch64" | os.arch == "ppc64" | os.arch == "ppc64le" + * @library /test/lib + * @run main/othervm/timeout=1600 -XX:+IgnoreUnrecognizedVMOptions -XX:+UseHeavyMonitors -XX:+VerifyHeavyMonitors MapLoops + */ + import static java.util.concurrent.TimeUnit.MILLISECONDS; import java.util.List; diff --git a/test/jdk/java/util/logging/TestAppletLoggerContext.java b/test/jdk/java/util/logging/TestAppletLoggerContext.java index 6fbe975b5e4339f80cce8575ae28ef6947110abb..b69497a626e4a7cba705642d8dd31031fbaddfe1 100644 --- a/test/jdk/java/util/logging/TestAppletLoggerContext.java +++ b/test/jdk/java/util/logging/TestAppletLoggerContext.java @@ -447,7 +447,7 @@ public class TestAppletLoggerContext { Logger logger4b = manager.getLogger(Logger.GLOBAL_LOGGER_NAME); assertNotNull(logger4); assertNotNull(logger4b); - expected = (System.getSecurityManager() == null ? global : global2);; + expected = (System.getSecurityManager() == null ? global : global2); assertEquals(logger4, expected); assertEquals(logger4b, expected); diff --git a/test/jdk/java/util/regex/RegExTest.java b/test/jdk/java/util/regex/RegExTest.java index 370b0d9696b406476176c2b4a934578709ac13df..39c454ce4f446f2468f3dad079a2414a12749d16 100644 --- a/test/jdk/java/util/regex/RegExTest.java +++ b/test/jdk/java/util/regex/RegExTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -35,7 +35,7 @@ * 8151481 4867170 7080302 6728861 6995635 6736245 4916384 6328855 6192895 * 6345469 6988218 6693451 7006761 8140212 8143282 8158482 8176029 8184706 * 8194667 8197462 8184692 8221431 8224789 8228352 8230829 8236034 8235812 - * 8216332 8214245 8237599 8241055 8247546 8258259 8037397 8269753 + * 8216332 8214245 8237599 8241055 8247546 8258259 8037397 8269753 8276694 * * @library /test/lib * @library /lib/testlibrary/java/lang @@ -4538,4 +4538,55 @@ public class RegExTest { var sep = System.lineSeparator(); assertTrue(e.getMessage().contains(sep + "\t ^")); } + + //This test is for 8276694 + @Test + public static void unescapedBackslash() { + String pattern = "\\"; + var e = expectThrows(PatternSyntaxException.class, () -> + Pattern.compile(pattern)); + assertTrue(e.getMessage().contains("Unescaped trailing backslash")); + } + + //This test is for 8280403 + @Test + public static void badIntersectionSyntax() { + String pattern = "[˜\\H +F&&]"; + var e = expectThrows(PatternSyntaxException.class, () -> + Pattern.compile(pattern)); + assertTrue(e.getMessage().contains("Bad intersection syntax")); + } + + //This test is for 8281560 + @Test + public static void prematureHitEndInNFCCharProperty() { + var testInput = "a1a1"; + var pat1 = "(a+|1+)"; + var pat2 = "([a]+|[1]+)"; + + var matcher1 = Pattern.compile(pat1, Pattern.CANON_EQ).matcher(testInput); + var matcher2 = Pattern.compile(pat2, Pattern.CANON_EQ).matcher(testInput); + + ArrayList<Boolean> results1 = new ArrayList<>(); + ArrayList<Boolean> results2 = new ArrayList<>(); + + while (matcher1.find()) { + results1.add(matcher1.hitEnd()); + } + + while (matcher2.find()) { + results2.add(matcher2.hitEnd()); + } + + assertEquals(results1, results2); + } + + //This test is for 8281315 + @Test + public static void iOOBForCIBackrefs(){ + String line = "\ud83d\udc95\ud83d\udc95\ud83d\udc95"; + var pattern2 = Pattern.compile("(?i)(.)\\1{2,}"); + assertTrue(pattern2.matcher(line).find()); + } } + diff --git a/test/jdk/java/util/stream/test/org/openjdk/tests/java/util/stream/SegmentTestDataProvider.java b/test/jdk/java/util/stream/test/org/openjdk/tests/java/util/stream/SegmentTestDataProvider.java index 772e112b23d87f04488e3801b06637452c5a0ec5..7a4d16dff13efef836e441a141e75190dda5312c 100644 --- a/test/jdk/java/util/stream/test/org/openjdk/tests/java/util/stream/SegmentTestDataProvider.java +++ b/test/jdk/java/util/stream/test/org/openjdk/tests/java/util/stream/SegmentTestDataProvider.java @@ -23,9 +23,7 @@ package org.openjdk.tests.java.util.stream; -import jdk.incubator.foreign.MemoryAccess; import jdk.incubator.foreign.MemoryLayout; -import jdk.incubator.foreign.MemoryLayouts; import jdk.incubator.foreign.MemorySegment; import java.lang.invoke.VarHandle; @@ -36,12 +34,13 @@ import java.util.function.Consumer; import java.util.function.Function; import java.util.stream.Collectors; +import jdk.incubator.foreign.ValueLayout; import org.testng.annotations.DataProvider; public class SegmentTestDataProvider { static boolean compareSegmentsByte(Collection<MemorySegment> segments1, Collection<MemorySegment> segments2, boolean isOrdered) { - Function<MemorySegment, Byte> mapper = MemoryAccess::getByte; + Function<MemorySegment, Byte> mapper = s -> s.get(ValueLayout.JAVA_BYTE, 0); List<Byte> list1 = segments1.stream() .map(mapper) .collect(Collectors.toList()); @@ -52,7 +51,7 @@ public class SegmentTestDataProvider { } static boolean compareSegmentsChar(Collection<MemorySegment> segments1, Collection<MemorySegment> segments2, boolean isOrdered) { - Function<MemorySegment, Character> mapper = MemoryAccess::getChar; + Function<MemorySegment, Character> mapper = s -> s.get(ValueLayout.JAVA_CHAR, 0); List<Character> list1 = segments1.stream() .map(mapper) .collect(Collectors.toList()); @@ -63,7 +62,7 @@ public class SegmentTestDataProvider { } static boolean compareSegmentsShort(Collection<MemorySegment> segments1, Collection<MemorySegment> segments2, boolean isOrdered) { - Function<MemorySegment, Short> mapper = MemoryAccess::getShort; + Function<MemorySegment, Short> mapper = s -> s.get(ValueLayout.JAVA_SHORT, 0); List<Short> list1 = segments1.stream() .map(mapper) .collect(Collectors.toList()); @@ -74,7 +73,7 @@ public class SegmentTestDataProvider { } static boolean compareSegmentsInt(Collection<MemorySegment> segments1, Collection<MemorySegment> segments2, boolean isOrdered) { - Function<MemorySegment, Integer> mapper = MemoryAccess::getInt; + Function<MemorySegment, Integer> mapper = s -> s.get(ValueLayout.JAVA_INT, 0); List<Integer> list1 = segments1.stream() .map(mapper) .collect(Collectors.toList()); @@ -85,7 +84,7 @@ public class SegmentTestDataProvider { } static boolean compareSegmentsLong(Collection<MemorySegment> segments1, Collection<MemorySegment> segments2, boolean isOrdered) { - Function<MemorySegment, Long> mapper = MemoryAccess::getLong; + Function<MemorySegment, Long> mapper = s-> s.get(ValueLayout.JAVA_LONG, 0); List<Long> list1 = segments1.stream() .map(mapper) .collect(Collectors.toList()); @@ -96,7 +95,7 @@ public class SegmentTestDataProvider { } static boolean compareSegmentsFloat(Collection<MemorySegment> segments1, Collection<MemorySegment> segments2, boolean isOrdered) { - Function<MemorySegment, Float> mapper = MemoryAccess::getFloat; + Function<MemorySegment, Float> mapper = s -> s.get(ValueLayout.JAVA_FLOAT, 0); List<Float> list1 = segments1.stream() .map(mapper) .collect(Collectors.toList()); @@ -115,7 +114,7 @@ public class SegmentTestDataProvider { } static boolean compareSegmentsDouble(Collection<MemorySegment> segments1, Collection<MemorySegment> segments2, boolean isOrdered) { - Function<MemorySegment, Double> mapper = MemoryAccess::getDouble; + Function<MemorySegment, Double> mapper = s -> s.get(ValueLayout.JAVA_DOUBLE, 0); List<Double> list1 = segments1.stream() .map(mapper) .collect(Collectors.toList()); @@ -127,18 +126,18 @@ public class SegmentTestDataProvider { static void initSegment(MemorySegment segment) { for (int i = 0 ; i < segment.byteSize() ; i++) { - MemoryAccess.setByte(segment, (byte)i); + segment.set(ValueLayout.JAVA_BYTE, 0, (byte)i); } } static Object[][] spliteratorTestData = { - { "bytes", MemoryLayout.sequenceLayout(1024, MemoryLayouts.JAVA_BYTE), (SpliteratorTestHelper.ContentAsserter<MemorySegment>)SegmentTestDataProvider::compareSegmentsByte }, - { "chars", MemoryLayout.sequenceLayout(1024, MemoryLayouts.JAVA_CHAR), (SpliteratorTestHelper.ContentAsserter<MemorySegment>)SegmentTestDataProvider::compareSegmentsChar }, - { "shorts", MemoryLayout.sequenceLayout(1024, MemoryLayouts.JAVA_SHORT), (SpliteratorTestHelper.ContentAsserter<MemorySegment>)SegmentTestDataProvider::compareSegmentsShort }, - { "ints", MemoryLayout.sequenceLayout(1024, MemoryLayouts.JAVA_INT), (SpliteratorTestHelper.ContentAsserter<MemorySegment>)SegmentTestDataProvider::compareSegmentsInt }, - { "longs", MemoryLayout.sequenceLayout(1024, MemoryLayouts.JAVA_LONG), (SpliteratorTestHelper.ContentAsserter<MemorySegment>)SegmentTestDataProvider::compareSegmentsLong }, - { "floats", MemoryLayout.sequenceLayout(1024, MemoryLayouts.JAVA_FLOAT), (SpliteratorTestHelper.ContentAsserter<MemorySegment>)SegmentTestDataProvider::compareSegmentsFloat }, - { "doubles", MemoryLayout.sequenceLayout(1024, MemoryLayouts.JAVA_DOUBLE), (SpliteratorTestHelper.ContentAsserter<MemorySegment>)SegmentTestDataProvider::compareSegmentsDouble }, + { "bytes", MemoryLayout.sequenceLayout(1024, ValueLayout.JAVA_BYTE), (SpliteratorTestHelper.ContentAsserter<MemorySegment>)SegmentTestDataProvider::compareSegmentsByte }, + { "chars", MemoryLayout.sequenceLayout(1024, ValueLayout.JAVA_CHAR), (SpliteratorTestHelper.ContentAsserter<MemorySegment>)SegmentTestDataProvider::compareSegmentsChar }, + { "shorts", MemoryLayout.sequenceLayout(1024, ValueLayout.JAVA_SHORT), (SpliteratorTestHelper.ContentAsserter<MemorySegment>)SegmentTestDataProvider::compareSegmentsShort }, + { "ints", MemoryLayout.sequenceLayout(1024, ValueLayout.JAVA_INT), (SpliteratorTestHelper.ContentAsserter<MemorySegment>)SegmentTestDataProvider::compareSegmentsInt }, + { "longs", MemoryLayout.sequenceLayout(1024, ValueLayout.JAVA_LONG), (SpliteratorTestHelper.ContentAsserter<MemorySegment>)SegmentTestDataProvider::compareSegmentsLong }, + { "floats", MemoryLayout.sequenceLayout(1024, ValueLayout.JAVA_FLOAT), (SpliteratorTestHelper.ContentAsserter<MemorySegment>)SegmentTestDataProvider::compareSegmentsFloat }, + { "doubles", MemoryLayout.sequenceLayout(1024, ValueLayout.JAVA_DOUBLE), (SpliteratorTestHelper.ContentAsserter<MemorySegment>)SegmentTestDataProvider::compareSegmentsDouble }, }; // returns an array of (String name, Supplier<Spliterator<MemorySegment>>, ContentAsserter<MemorySegment>) diff --git a/test/jdk/java/util/zip/CloseInflaterDeflaterTest.java b/test/jdk/java/util/zip/CloseInflaterDeflaterTest.java new file mode 100644 index 0000000000000000000000000000000000000000..4f0fafc8dbeddab48f98ab5618ab46dd513106b3 --- /dev/null +++ b/test/jdk/java/util/zip/CloseInflaterDeflaterTest.java @@ -0,0 +1,208 @@ +/* + * 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. + */ + +/** + * @test + * @bug 8193682 8278794 + * @summary Test Infinite loop while writing on closed Deflater and Inflater. + * @run testng CloseInflaterDeflaterTest + */ +import java.io.*; +import java.util.Random; +import java.util.jar.JarOutputStream; +import java.util.zip.DeflaterInputStream; +import java.util.zip.DeflaterOutputStream; +import java.util.zip.GZIPOutputStream; +import java.util.zip.InflaterOutputStream; +import java.util.zip.ZipOutputStream; +import java.util.zip.ZipEntry; + +import org.testng.annotations.BeforeTest; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import static org.testng.Assert.assertThrows; + + +public class CloseInflaterDeflaterTest { + + // Number of bytes to write/read from Deflater/Inflater + private static final int INPUT_LENGTH= 512; + // OutputStream that will throw an exception during a write operation + private static OutputStream outStream = new OutputStream() { + @Override + public void write(byte[] b, int off, int len) throws IOException { + throw new IOException(); + } + @Override + public void write(byte[] b) throws IOException {} + @Override + public void write(int b) throws IOException {} + }; + // InputStream that will throw an exception during a read operation + private static InputStream inStream = new InputStream() { + @Override + public int read(byte[] b, int off, int len) throws IOException { + throw new IOException(); + } + @Override + public int read(byte[] b) throws IOException { throw new IOException();} + @Override + public int read() throws IOException { throw new IOException();} + }; + // Input bytes for read/write operation + private static byte[] inputBytes = new byte[INPUT_LENGTH]; + // Random function to add bytes to inputBytes + private static Random rand = new Random(); + + /** + * DataProvider to specify whether to use close() or finish() of OutputStream + * + * @return Entry object indicating which method to use for closing OutputStream + */ + @DataProvider + public Object[][] testOutputStreams() { + return new Object[][] { + { true }, + { false }, + }; + } + + /** + * DataProvider to specify on which outputstream closeEntry() has to be called + * + * @return Entry object returning either JarOutputStream or ZipOutputStream + */ + @DataProvider + public Object[][] testZipAndJar() throws IOException{ + return new Object[][] { + { new JarOutputStream(outStream)}, + { new ZipOutputStream(outStream)}, + }; + } + + /** + * Add inputBytes array with random bytes to write into OutputStream + */ + @BeforeTest + public void before_test() + { + rand.nextBytes(inputBytes); + } + + /** + * Test for infinite loop by writing bytes to closed GZIPOutputStream + * + * @param useCloseMethod indicates whether to use Close() or finish() method + * @throws IOException if an error occurs + */ + @Test(dataProvider = "testOutputStreams") + public void testGZip(boolean useCloseMethod) throws IOException { + GZIPOutputStream gzip = new GZIPOutputStream(outStream); + gzip.write(inputBytes, 0, INPUT_LENGTH); + assertThrows(IOException.class, () -> { + // Close GZIPOutputStream + if (useCloseMethod) { + gzip.close(); + } else { + gzip.finish(); + } + }); + // Write on a closed GZIPOutputStream, closed Deflater IOException expected + assertThrows(NullPointerException.class , () -> gzip.write(inputBytes, 0, INPUT_LENGTH)); + } + + /** + * Test for infinite loop by writing bytes to closed DeflaterOutputStream + * + * @param useCloseMethod indicates whether to use Close() or finish() method + * @throws IOException if an error occurs + */ + @Test(dataProvider = "testOutputStreams") + public void testDeflaterOutputStream(boolean useCloseMethod) throws IOException { + DeflaterOutputStream def = new DeflaterOutputStream(outStream); + assertThrows(IOException.class , () -> def.write(inputBytes, 0, INPUT_LENGTH)); + assertThrows(IOException.class, () -> { + // Close DeflaterOutputStream + if (useCloseMethod) { + def.close(); + } else { + def.finish(); + } + }); + // Write on a closed DeflaterOutputStream, 'Deflater has been closed' NPE is expected + assertThrows(NullPointerException.class , () -> def.write(inputBytes, 0, INPUT_LENGTH)); + } + + /** + * Test for infinite loop by reading bytes from closed DeflaterInputStream + * + * @throws IOException if an error occurs + */ + @Test + public void testDeflaterInputStream() throws IOException { + DeflaterInputStream def = new DeflaterInputStream(inStream); + assertThrows(IOException.class , () -> def.read(inputBytes, 0, INPUT_LENGTH)); + // Close DeflaterInputStream + def.close(); + // Read from a closed DeflaterInputStream, closed Deflater IOException expected + assertThrows(IOException.class , () -> def.read(inputBytes, 0, INPUT_LENGTH)); + } + + /** + * Test for infinite loop by writing bytes to closed InflaterOutputStream + * + * @param useCloseMethod indicates whether to use Close() or finish() method + * @throws IOException if an error occurs + */ + @Test(dataProvider = "testOutputStreams") + public void testInflaterOutputStream(boolean useCloseMethod) throws IOException { + InflaterOutputStream inf = new InflaterOutputStream(outStream); + assertThrows(IOException.class , () -> inf.write(inputBytes, 0, INPUT_LENGTH)); + assertThrows(IOException.class , () -> { + // Close InflaterOutputStream + if (useCloseMethod) { + inf.close(); + } else { + inf.finish(); + } + }); + // Write on a closed InflaterOutputStream , closed Inflater IOException expected + assertThrows(IOException.class , () -> inf.write(inputBytes, 0, INPUT_LENGTH)); + } + + /** + * Test for infinite loop by writing bytes to closed ZipOutputStream/JarOutputStream + * + * @param zip will be the instance of either JarOutputStream or ZipOutputStream + * @throws IOException if an error occurs + */ + @Test(dataProvider = "testZipAndJar") + public void testZipCloseEntry(ZipOutputStream zip) throws IOException { + assertThrows(IOException.class , () -> zip.putNextEntry(new ZipEntry(""))); + zip.write(inputBytes, 0, INPUT_LENGTH); + assertThrows(IOException.class , () -> zip.closeEntry()); + // Write on a closed ZipOutputStream , 'Deflater has been closed' NPE is expected + assertThrows(NullPointerException.class , () -> zip.write(inputBytes, 0, INPUT_LENGTH)); + } + +} diff --git a/test/jdk/java/util/zip/ZipFile/GetInputStreamNPETest.java b/test/jdk/java/util/zip/ZipFile/GetInputStreamNPETest.java new file mode 100644 index 0000000000000000000000000000000000000000..ec7f0fc7d454d3f64f6ec6a93a989a75e159f498 --- /dev/null +++ b/test/jdk/java/util/zip/ZipFile/GetInputStreamNPETest.java @@ -0,0 +1,1055 @@ +/* + * 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. + * + */ + +import org.testng.annotations.AfterTest; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Arrays; +import java.util.Formatter; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; + +import static org.testng.Assert.*; + +/** + * @test + * @bug 8280409 + * @summary Validate that Zip/JarFile::getInputStream will throw a NullPointerException + * @run testng/othervm GetInputStreamNPETest + */ +public class GetInputStreamNPETest { + // Name used to create a JAR with an invalid entry name + public static final Path INVALID_ENTRY_NAME_JAR = + Path.of("Invalid-EntryName.jar"); + // Name used to create a JAR with a valid entry name + public static final Path VALID_ENTRY_NAME_JAR = + Path.of("Valid-EntryName.jar"); + // Name used to create a JAR with an invalid entry name + public static final Path SIGNED_INVALID_ENTRY_NAME_JAR = + Path.of("Signed-Invalid-EntryName.jar"); + // Name used to create a JAR with a valid entry name + public static final Path SIGNED_VALID_ENTRY_NAME_JAR = + Path.of("Signed-Valid-EntryName.jar"); + // Value to change the "S" in "Singleton.class" to + public static final byte INVALID_UTF8_BYTE = (byte) 0x13; + // CEN offset to where "Singleton.class" filename starts + public static final int SINGLETON_CEN_FILENAME_OFFSET = 37; + // CEN filename which will be modified to validate a ZipException is thrown + public static final String CEN_FILENAME_TO_MODIFY = "javax/inject/Singleton.class"; + // Zip Entry name that does not exist within the JarFile + public static final String ZIP_ENTRY_THAT_DOES_NOT_EXIST = "org/gotham/Batcave.class"; + + /** + * Byte array representing a valid jar file prior modifying a filename in the + * CEN. + * The "Valid-EntryName.jar" jar file was created via: + * <pre> + * {@code + * jar cvf Valid-EntryName.jar javax/inject/Singleton.class + * added manifest + * adding: javax/inject/Singleton.class(in = 359) (out= 221)(deflated 38%) + * } + * </pre> + * Its contents are: + * <pre> + * {@code + * jar tvf Valid-EntryName.jar + * 0 Wed Jan 26 14:27:26 EST 2022 META-INF/ + * 66 Wed Jan 26 14:27:26 EST 2022 META-INF/MANIFEST.MF + * 359 Mon Jan 24 22:11:24 EST 2011 javax/inject/Singleton.class + * } + * </pre> + * The ByteArray was created by: + * <pre> + * {@code + * var jar = Files.readAllBytes("Valid-EntryName.jar"); + * var validEntryName = createByteArray(fooJar, "VALID_ENTRY_NAME"); + * } + * </pre> + */ + public static byte[] VALID_ENTRY_NAME = { + (byte) 0x50, (byte) 0x4b, (byte) 0x3, (byte) 0x4, (byte) 0x14, + (byte) 0x0, (byte) 0x8, (byte) 0x8, (byte) 0x8, (byte) 0x0, + (byte) 0x6d, (byte) 0x73, (byte) 0x3a, (byte) 0x54, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, + (byte) 0x0, (byte) 0x9, (byte) 0x0, (byte) 0x4, (byte) 0x0, + (byte) 0x4d, (byte) 0x45, (byte) 0x54, (byte) 0x41, (byte) 0x2d, + (byte) 0x49, (byte) 0x4e, (byte) 0x46, (byte) 0x2f, (byte) 0xfe, + (byte) 0xca, (byte) 0x0, (byte) 0x0, (byte) 0x3, (byte) 0x0, + (byte) 0x50, (byte) 0x4b, (byte) 0x7, (byte) 0x8, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x2, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, + (byte) 0x0, (byte) 0x50, (byte) 0x4b, (byte) 0x3, (byte) 0x4, + (byte) 0x14, (byte) 0x0, (byte) 0x8, (byte) 0x8, (byte) 0x8, + (byte) 0x0, (byte) 0x6d, (byte) 0x73, (byte) 0x3a, (byte) 0x54, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0x14, (byte) 0x0, (byte) 0x0, + (byte) 0x0, (byte) 0x4d, (byte) 0x45, (byte) 0x54, (byte) 0x41, + (byte) 0x2d, (byte) 0x49, (byte) 0x4e, (byte) 0x46, (byte) 0x2f, + (byte) 0x4d, (byte) 0x41, (byte) 0x4e, (byte) 0x49, (byte) 0x46, + (byte) 0x45, (byte) 0x53, (byte) 0x54, (byte) 0x2e, (byte) 0x4d, + (byte) 0x46, (byte) 0xf3, (byte) 0x4d, (byte) 0xcc, (byte) 0xcb, + (byte) 0x4c, (byte) 0x4b, (byte) 0x2d, (byte) 0x2e, (byte) 0xd1, + (byte) 0xd, (byte) 0x4b, (byte) 0x2d, (byte) 0x2a, (byte) 0xce, + (byte) 0xcc, (byte) 0xcf, (byte) 0xb3, (byte) 0x52, (byte) 0x30, + (byte) 0xd4, (byte) 0x33, (byte) 0xe0, (byte) 0xe5, (byte) 0x72, + (byte) 0x2e, (byte) 0x4a, (byte) 0x4d, (byte) 0x2c, (byte) 0x49, + (byte) 0x4d, (byte) 0xd1, (byte) 0x75, (byte) 0xaa, (byte) 0x4, + (byte) 0xa, (byte) 0x98, (byte) 0xe8, (byte) 0x19, (byte) 0xe8, + (byte) 0x19, (byte) 0x2a, (byte) 0x68, (byte) 0xf8, (byte) 0x17, + (byte) 0x25, (byte) 0x26, (byte) 0xe7, (byte) 0xa4, (byte) 0x2a, + (byte) 0x38, (byte) 0xe7, (byte) 0x17, (byte) 0x15, (byte) 0xe4, + (byte) 0x17, (byte) 0x25, (byte) 0x96, (byte) 0x0, (byte) 0x15, + (byte) 0x6b, (byte) 0xf2, (byte) 0x72, (byte) 0xf1, (byte) 0x72, + (byte) 0x1, (byte) 0x0, (byte) 0x50, (byte) 0x4b, (byte) 0x7, + (byte) 0x8, (byte) 0xf4, (byte) 0x59, (byte) 0xdc, (byte) 0xa6, + (byte) 0x42, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x42, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x50, (byte) 0x4b, + (byte) 0x3, (byte) 0x4, (byte) 0x14, (byte) 0x0, (byte) 0x8, + (byte) 0x8, (byte) 0x8, (byte) 0x0, (byte) 0x6c, (byte) 0xb1, + (byte) 0x38, (byte) 0x3e, (byte) 0x0, (byte) 0x0, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x1c, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x6a, (byte) 0x61, + (byte) 0x76, (byte) 0x61, (byte) 0x78, (byte) 0x2f, (byte) 0x69, + (byte) 0x6e, (byte) 0x6a, (byte) 0x65, (byte) 0x63, (byte) 0x74, + (byte) 0x2f, (byte) 0x53, (byte) 0x69, (byte) 0x6e, (byte) 0x67, + (byte) 0x6c, (byte) 0x65, (byte) 0x74, (byte) 0x6f, (byte) 0x6e, + (byte) 0x2e, (byte) 0x63, (byte) 0x6c, (byte) 0x61, (byte) 0x73, + (byte) 0x73, (byte) 0x85, (byte) 0x90, (byte) 0x4d, (byte) 0x4b, + (byte) 0x82, (byte) 0x41, (byte) 0x10, (byte) 0xc7, (byte) 0xff, + (byte) 0xa3, (byte) 0xd9, (byte) 0x63, (byte) 0x56, (byte) 0xe6, + (byte) 0x21, (byte) 0x5, (byte) 0x4f, (byte) 0xda, (byte) 0xc5, + (byte) 0x63, (byte) 0x4b, (byte) 0xe7, (byte) 0x4e, (byte) 0x41, + (byte) 0x6, (byte) 0x81, (byte) 0xa5, (byte) 0x3c, (byte) 0x5a, + (byte) 0xf7, (byte) 0x75, (byte) 0x1b, (byte) 0x64, (byte) 0x65, + (byte) 0xdd, (byte) 0x8d, (byte) 0xdc, (byte) 0x47, (byte) 0xea, + (byte) 0xab, (byte) 0x79, (byte) 0xe8, (byte) 0x3, (byte) 0xf4, + (byte) 0xa1, (byte) 0xc4, (byte) 0xd9, (byte) 0xe, (byte) 0x4a, + (byte) 0x20, (byte) 0x34, (byte) 0x30, (byte) 0x2f, (byte) 0xcc, + (byte) 0xfc, (byte) 0x66, (byte) 0x98, (byte) 0x99, (byte) 0x9f, + (byte) 0xcd, (byte) 0xfa, (byte) 0x1b, (byte) 0xc0, (byte) 0xd, + (byte) 0x1a, (byte) 0x84, (byte) 0x2c, (byte) 0x7f, (byte) 0x79, + (byte) 0x9e, (byte) 0x3c, (byte) 0x3e, (byte) 0xf5, (byte) 0x9, + (byte) 0x8d, (byte) 0xb9, (byte) 0x5e, (byte) 0x69, (byte) 0xe5, + (byte) 0xb4, (byte) 0x9f, (byte) 0xa9, (byte) 0xe1, (byte) 0x74, + (byte) 0xce, (byte) 0x26, (byte) 0x12, (byte) 0x3a, (byte) 0xfb, + (byte) 0x94, (byte) 0xf6, (byte) 0x3e, (byte) 0x44, (byte) 0x1d, + (byte) 0x6d, (byte) 0xf0, (byte) 0xea, (byte) 0x6e, (byte) 0x17, + (byte) 0x12, (byte) 0x5a, (byte) 0x89, (byte) 0xf8, (byte) 0x54, + (byte) 0xd6, (byte) 0xa7, (byte) 0x6, (byte) 0x35, (byte) 0xb6, + (byte) 0x7e, (byte) 0xe6, (byte) 0x38, (byte) 0xa6, (byte) 0x42, + (byte) 0x65, (byte) 0xa5, (byte) 0x5d, (byte) 0xc1, (byte) 0x19, + (byte) 0x4a, (byte) 0x19, (byte) 0xca, (byte) 0x19, (byte) 0x8e, + (byte) 0x8, (byte) 0x57, (byte) 0x83, (byte) 0x83, (byte) 0xc3, + (byte) 0xee, (byte) 0x83, (byte) 0x29, (byte) 0x16, (byte) 0xec, + (byte) 0x23, (byte) 0xbf, (byte) 0xdd, (byte) 0x12, (byte) 0xba, + (byte) 0x87, (byte) 0x99, (byte) 0x9c, (byte) 0xa3, (byte) 0x10, + (byte) 0x12, (byte) 0x9, (byte) 0xd2, (byte) 0xfb, (byte) 0x7, + (byte) 0x19, (byte) 0x5, (byte) 0x67, (byte) 0xcd, (byte) 0x97, + (byte) 0x80, (byte) 0x97, (byte) 0x83, (byte) 0xbf, (byte) 0xab, + (byte) 0x99, (byte) 0xf0, (byte) 0xce, (byte) 0x92, (byte) 0x6e, + (byte) 0xe7, (byte) 0x85, (byte) 0x70, (byte) 0xb, (byte) 0x7e, + (byte) 0xb5, (byte) 0x4b, (byte) 0x3b, (byte) 0x75, (byte) 0xbc, + (byte) 0xbf, (byte) 0x65, (byte) 0x49, (byte) 0xa8, (byte) 0xef, + (byte) 0xf6, (byte) 0xbf, (byte) 0x4e, (byte) 0xbd, (byte) 0x84, + (byte) 0xda, (byte) 0x38, (byte) 0x14, (byte) 0x1f, (byte) 0x86, + (byte) 0x1f, (byte) 0xac, (byte) 0xe3, (byte) 0x1e, (byte) 0xa1, + (byte) 0x8a, (byte) 0x63, (byte) 0xc8, (byte) 0xc3, (byte) 0x90, + (byte) 0xa4, (byte) 0x84, (byte) 0x8b, (byte) 0x5f, (byte) 0x5b, + (byte) 0xc7, (byte) 0xb9, (byte) 0xf8, (byte) 0x26, (byte) 0xca, + (byte) 0x38, (byte) 0x13, (byte) 0x7f, (byte) 0x22, (byte) 0x5a, + (byte) 0x13, (byte) 0xa6, (byte) 0xc2, (byte) 0x38, (byte) 0x5, + (byte) 0x6d, (byte) 0x1, (byte) 0x50, (byte) 0x4b, (byte) 0x7, + (byte) 0x8, (byte) 0x5a, (byte) 0xf1, (byte) 0x0, (byte) 0x98, + (byte) 0xdd, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x67, + (byte) 0x1, (byte) 0x0, (byte) 0x0, (byte) 0x50, (byte) 0x4b, + (byte) 0x1, (byte) 0x2, (byte) 0x14, (byte) 0x0, (byte) 0x14, + (byte) 0x0, (byte) 0x8, (byte) 0x8, (byte) 0x8, (byte) 0x0, + (byte) 0x6d, (byte) 0x73, (byte) 0x3a, (byte) 0x54, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x2, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, + (byte) 0x0, (byte) 0x9, (byte) 0x0, (byte) 0x4, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x4d, + (byte) 0x45, (byte) 0x54, (byte) 0x41, (byte) 0x2d, (byte) 0x49, + (byte) 0x4e, (byte) 0x46, (byte) 0x2f, (byte) 0xfe, (byte) 0xca, + (byte) 0x0, (byte) 0x0, (byte) 0x50, (byte) 0x4b, (byte) 0x1, + (byte) 0x2, (byte) 0x14, (byte) 0x0, (byte) 0x14, (byte) 0x0, + (byte) 0x8, (byte) 0x8, (byte) 0x8, (byte) 0x0, (byte) 0x6d, + (byte) 0x73, (byte) 0x3a, (byte) 0x54, (byte) 0xf4, (byte) 0x59, + (byte) 0xdc, (byte) 0xa6, (byte) 0x42, (byte) 0x0, (byte) 0x0, + (byte) 0x0, (byte) 0x42, (byte) 0x0, (byte) 0x0, (byte) 0x0, + (byte) 0x14, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x3d, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x4d, (byte) 0x45, + (byte) 0x54, (byte) 0x41, (byte) 0x2d, (byte) 0x49, (byte) 0x4e, + (byte) 0x46, (byte) 0x2f, (byte) 0x4d, (byte) 0x41, (byte) 0x4e, + (byte) 0x49, (byte) 0x46, (byte) 0x45, (byte) 0x53, (byte) 0x54, + (byte) 0x2e, (byte) 0x4d, (byte) 0x46, (byte) 0x50, (byte) 0x4b, + (byte) 0x1, (byte) 0x2, (byte) 0x14, (byte) 0x0, (byte) 0x14, + (byte) 0x0, (byte) 0x8, (byte) 0x8, (byte) 0x8, (byte) 0x0, + (byte) 0x6c, (byte) 0xb1, (byte) 0x38, (byte) 0x3e, (byte) 0x5a, + (byte) 0xf1, (byte) 0x0, (byte) 0x98, (byte) 0xdd, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0x67, (byte) 0x1, (byte) 0x0, + (byte) 0x0, (byte) 0x1c, (byte) 0x0, (byte) 0x0, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, + (byte) 0xc1, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x6a, + (byte) 0x61, (byte) 0x76, (byte) 0x61, (byte) 0x78, (byte) 0x2f, + (byte) 0x69, (byte) 0x6e, (byte) 0x6a, (byte) 0x65, (byte) 0x63, + // We will modify 0x53, "S" within the CEN filename entry + (byte) 0x74, (byte) 0x2f, (byte) 0x53, (byte) 0x69, (byte) 0x6e, + (byte) 0x67, (byte) 0x6c, (byte) 0x65, (byte) 0x74, (byte) 0x6f, + (byte) 0x6e, (byte) 0x2e, (byte) 0x63, (byte) 0x6c, (byte) 0x61, + (byte) 0x73, (byte) 0x73, (byte) 0x50, (byte) 0x4b, (byte) 0x5, + (byte) 0x6, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, + (byte) 0x3, (byte) 0x0, (byte) 0x3, (byte) 0x0, (byte) 0xc7, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0xe8, (byte) 0x1, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, + }; + + /** + * Byte array representing a valid signed jar file prior modifying a filename + * in the CEN. + * The "Valid-EntryName.jar" jar file was signed via: + * <pre> + * {@code + * keytool -genkey -keyalg RSA -alias myFirstKey -keystore myKeystore -storepass changeit -keypass changeit + * jarsigner -keystore myKeystore -verbose Valid-EntryName.jar -signedjar Signed-Valid-EntryName.jar myFirstKey + * } + * </pre> + * The ByteArray was created by: + * <pre> + * {@code + * var signedJar = Files.readAllBytes("Signed-Valid-EntryName.jar"); + * var signedValidEntryName = createByteArray(fooJar, "SIGNED_VALID_ENTRY_NAME"); + * } + * </pre> + */ + public static byte[] SIGNED_VALID_ENTRY_NAME = { + (byte) 0x50, (byte) 0x4b, (byte) 0x3, (byte) 0x4, (byte) 0x14, + (byte) 0x0, (byte) 0x8, (byte) 0x8, (byte) 0x8, (byte) 0x0, + (byte) 0x17, (byte) 0x71, (byte) 0x3b, (byte) 0x54, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, + (byte) 0x0, (byte) 0x14, (byte) 0x0, (byte) 0x0, (byte) 0x0, + (byte) 0x4d, (byte) 0x45, (byte) 0x54, (byte) 0x41, (byte) 0x2d, + (byte) 0x49, (byte) 0x4e, (byte) 0x46, (byte) 0x2f, (byte) 0x4d, + (byte) 0x41, (byte) 0x4e, (byte) 0x49, (byte) 0x46, (byte) 0x45, + (byte) 0x53, (byte) 0x54, (byte) 0x2e, (byte) 0x4d, (byte) 0x46, + (byte) 0x15, (byte) 0xcd, (byte) 0xbb, (byte) 0xe, (byte) 0x82, + (byte) 0x30, (byte) 0x18, (byte) 0x40, (byte) 0xe1, (byte) 0x9d, + (byte) 0x84, (byte) 0x77, (byte) 0xe8, (byte) 0xa8, (byte) 0x43, + (byte) 0xb, (byte) 0x28, (byte) 0x10, (byte) 0x42, (byte) 0xe2, + (byte) 0xc0, (byte) 0x45, (byte) 0xc1, (byte) 0x41, (byte) 0x31, + (byte) 0x21, (byte) 0x3a, (byte) 0xb8, (byte) 0x95, (byte) 0xfa, + (byte) 0xb, (byte) 0xad, (byte) 0xd8, (byte) 0x6a, (byte) 0xa9, + (byte) 0x17, (byte) 0xde, (byte) 0x5e, (byte) 0x5c, (byte) 0x4f, + (byte) 0x4e, (byte) 0xf2, (byte) 0xed, (byte) 0xa8, (byte) 0xe4, + (byte) 0x57, (byte) 0x18, (byte) 0xc, (byte) 0x3e, (byte) 0x81, + (byte) 0x1e, (byte) 0xb8, (byte) 0x92, (byte) 0x31, (byte) 0xf2, + (byte) 0x88, (byte) 0x6b, (byte) 0x5b, (byte) 0x99, (byte) 0x6, + (byte) 0x6a, (byte) 0xe0, (byte) 0x82, (byte) 0xd3, (byte) 0x71, + (byte) 0xa, (byte) 0x3e, (byte) 0x71, (byte) 0x89, (byte) 0x87, + (byte) 0x66, (byte) 0x95, (byte) 0xa6, (byte) 0xac, (byte) 0x7, + (byte) 0x94, (byte) 0x29, (byte) 0xfd, (byte) 0x50, (byte) 0x9a, + (byte) 0x9a, (byte) 0x69, (byte) 0x9e, (byte) 0xdb, (byte) 0x96, + (byte) 0x6d, (byte) 0xed, (byte) 0xe9, (byte) 0x1d, (byte) 0x62, + (byte) 0x24, (byte) 0xe8, (byte) 0x9b, (byte) 0x7e, (byte) 0x1d, + (byte) 0x2e, (byte) 0x5, (byte) 0x30, (byte) 0xe3, (byte) 0xd4, + (byte) 0x5c, (byte) 0xb6, (byte) 0x3d, (byte) 0x18, (byte) 0x25, + (byte) 0x9, (byte) 0xeb, (byte) 0xe9, (byte) 0x30, (byte) 0xd8, + (byte) 0x56, (byte) 0x5d, (byte) 0x26, (byte) 0x78, (byte) 0x11, + (byte) 0x84, (byte) 0x38, (byte) 0xe7, (byte) 0xed, (byte) 0x64, + (byte) 0xc5, (byte) 0x48, (byte) 0xb9, (byte) 0x7, (byte) 0xf0, + (byte) 0x97, (byte) 0x51, (byte) 0x1d, (byte) 0xe8, (byte) 0xcd, + (byte) 0xb3, (byte) 0x39, (byte) 0x46, (byte) 0x1f, (byte) 0x91, + (byte) 0xa4, (byte) 0x41, (byte) 0xb3, (byte) 0xbe, (byte) 0xf1, + (byte) 0x17, (byte) 0x1b, (byte) 0x4b, (byte) 0xd1, (byte) 0x55, + (byte) 0x45, (byte) 0x27, (byte) 0xf3, (byte) 0x73, (byte) 0xd1, + (byte) 0x9, (byte) 0x8, (byte) 0xc3, (byte) 0xed, (byte) 0xea, + (byte) 0x6f, (byte) 0xfc, (byte) 0x0, (byte) 0x50, (byte) 0x4b, + (byte) 0x7, (byte) 0x8, (byte) 0xc1, (byte) 0xfa, (byte) 0x9d, + (byte) 0xe2, (byte) 0x9e, (byte) 0x0, (byte) 0x0, (byte) 0x0, + (byte) 0xa6, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x50, + (byte) 0x4b, (byte) 0x3, (byte) 0x4, (byte) 0x14, (byte) 0x0, + (byte) 0x8, (byte) 0x8, (byte) 0x8, (byte) 0x0, (byte) 0x17, + (byte) 0x71, (byte) 0x3b, (byte) 0x54, (byte) 0x0, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, + (byte) 0x14, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x4d, + (byte) 0x45, (byte) 0x54, (byte) 0x41, (byte) 0x2d, (byte) 0x49, + (byte) 0x4e, (byte) 0x46, (byte) 0x2f, (byte) 0x4d, (byte) 0x59, + (byte) 0x46, (byte) 0x49, (byte) 0x52, (byte) 0x53, (byte) 0x54, + (byte) 0x4b, (byte) 0x2e, (byte) 0x53, (byte) 0x46, (byte) 0x75, + (byte) 0x8d, (byte) 0xcb, (byte) 0x6e, (byte) 0x82, (byte) 0x40, + (byte) 0x18, (byte) 0x46, (byte) 0xf7, (byte) 0x24, (byte) 0xbc, + (byte) 0xc3, (byte) 0x2c, (byte) 0xdb, (byte) 0x10, (byte) 0xee, + (byte) 0xa8, (byte) 0x29, (byte) 0x49, (byte) 0x17, (byte) 0x23, + (byte) 0x2a, (byte) 0x4a, (byte) 0x41, (byte) 0xdb, (byte) 0x62, + (byte) 0x6d, (byte) 0xc2, (byte) 0x6e, (byte) 0x3a, (byte) 0x8c, + (byte) 0x64, (byte) 0x44, (byte) 0x67, (byte) 0xe8, (byte) 0xcc, + (byte) 0x2f, (byte) 0x5e, (byte) 0x9e, (byte) 0xbe, (byte) 0xa4, + (byte) 0xcb, (byte) 0x26, (byte) 0xdd, (byte) 0x9d, (byte) 0x7c, + (byte) 0xf9, (byte) 0x72, (byte) 0x4e, (byte) 0xc9, (byte) 0x1b, + (byte) 0x41, (byte) 0xe0, (byte) 0xac, (byte) 0x98, (byte) 0xbd, + (byte) 0x63, (byte) 0x4a, (byte) 0x73, (byte) 0x29, (byte) 0x62, + (byte) 0xe4, (byte) 0x3b, (byte) 0x9e, (byte) 0x69, (byte) 0x24, + (byte) 0x8a, (byte) 0x11, (byte) 0x60, (byte) 0xb5, (byte) 0x3d, + (byte) 0xbd, (byte) 0xd, (byte) 0x43, (byte) 0xe4, (byte) 0x78, + (byte) 0x8e, (byte) 0x8f, (byte) 0x1e, (byte) 0x36, (byte) 0x8a, + (byte) 0xd0, (byte) 0x23, (byte) 0x43, (byte) 0x89, (byte) 0x54, + (byte) 0x9d, (byte) 0x54, (byte) 0x4, (byte) 0x86, (byte) 0xf3, + (byte) 0xa3, (byte) 0x69, (byte) 0x94, (byte) 0x4b, (byte) 0x6c, + (byte) 0x7, (byte) 0xa3, (byte) 0xb1, (byte) 0x3d, (byte) 0xe3, + (byte) 0xd, (byte) 0xd3, (byte) 0x60, (byte) 0x17, (byte) 0x44, + (byte) 0xf0, (byte) 0xfd, (byte) 0x0, (byte) 0x31, (byte) 0xda, + (byte) 0xeb, (byte) 0xd9, (byte) 0xc6, (byte) 0xad, (byte) 0x2c, + (byte) 0xab, (byte) 0x29, (byte) 0xb2, (byte) 0x57, (byte) 0xbc, + (byte) 0xfb, (byte) 0x8, (byte) 0x57, (byte) 0xa3, (byte) 0x2e, + (byte) 0x97, (byte) 0x3d, (byte) 0xe0, (byte) 0x4d, (byte) 0x48, + (byte) 0xb3, (byte) 0xa0, (byte) 0x4d, (byte) 0x73, (byte) 0xd7, + (byte) 0xf3, (byte) 0x83, (byte) 0xa0, (byte) 0xbf, (byte) 0x15, + (byte) 0x8b, (byte) 0xba, (byte) 0x78, (byte) 0xfe, (byte) 0x57, + (byte) 0x33, (byte) 0x0, (byte) 0x17, (byte) 0x36, (byte) 0x6, + (byte) 0x50, (byte) 0xfc, (byte) 0xeb, (byte) 0xc, (byte) 0x4c, + (byte) 0xc7, (byte) 0x28, (byte) 0xa4, (byte) 0x55, (byte) 0xb6, + (byte) 0x8e, (byte) 0x40, (byte) 0x94, (byte) 0xf7, (byte) 0x76, + (byte) 0x4b, (byte) 0xd2, (byte) 0xc8, (byte) 0x67, (byte) 0xb, + (byte) 0xa8, (byte) 0x93, (byte) 0xc9, (byte) 0x64, (byte) 0x3a, + (byte) 0x29, (byte) 0x96, (byte) 0xe3, (byte) 0xd6, (byte) 0x6a, + (byte) 0x4d, (byte) 0x3, (byte) 0x9d, (byte) 0xe7, (byte) 0xdd, + (byte) 0xf5, (byte) 0x6e, (byte) 0x61, (byte) 0x39, (byte) 0xbf, + (byte) 0xd6, (byte) 0x74, (byte) 0x30, (byte) 0x9b, (byte) 0xc6, + (byte) 0x9a, (byte) 0x9c, (byte) 0x58, (byte) 0x8c, (byte) 0xe, + (byte) 0xa4, (byte) 0x27, (byte) 0x57, (byte) 0x97, (byte) 0x8b, + (byte) 0x3, (byte) 0xa3, (byte) 0xe0, (byte) 0x96, (byte) 0x5c, + (byte) 0x34, (byte) 0x47, (byte) 0x6, (byte) 0x52, (byte) 0x38, + (byte) 0xf4, (byte) 0x48, (byte) 0xb4, (byte) 0xfe, (byte) 0xdb, + (byte) 0x8f, (byte) 0xd1, (byte) 0x28, (byte) 0xf4, (byte) 0xab, + (byte) 0xd5, (byte) 0xc9, (byte) 0xc5, (byte) 0x51, (byte) 0xe2, + (byte) 0xdf, (byte) 0x29, (byte) 0x93, (byte) 0x5b, (byte) 0xac, + (byte) 0x32, (byte) 0xef, (byte) 0xe9, (byte) 0x70, (byte) 0xc9, + (byte) 0xd3, (byte) 0xf7, (byte) 0x6f, (byte) 0xae, (byte) 0x39, + (byte) 0x81, (byte) 0xf4, (byte) 0xd, (byte) 0x7f, (byte) 0x36, + (byte) 0x51, (byte) 0xc7, (byte) 0x9b, (byte) 0x17, (byte) 0xef, + (byte) 0xb7, (byte) 0xf1, (byte) 0x3, (byte) 0x50, (byte) 0x4b, + (byte) 0x7, (byte) 0x8, (byte) 0x8b, (byte) 0xcb, (byte) 0xd5, + (byte) 0xea, (byte) 0x3, (byte) 0x1, (byte) 0x0, (byte) 0x0, + (byte) 0x48, (byte) 0x1, (byte) 0x0, (byte) 0x0, (byte) 0x50, + (byte) 0x4b, (byte) 0x3, (byte) 0x4, (byte) 0x14, (byte) 0x0, + (byte) 0x8, (byte) 0x8, (byte) 0x8, (byte) 0x0, (byte) 0x17, + (byte) 0x71, (byte) 0x3b, (byte) 0x54, (byte) 0x0, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, + (byte) 0x15, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x4d, + (byte) 0x45, (byte) 0x54, (byte) 0x41, (byte) 0x2d, (byte) 0x49, + (byte) 0x4e, (byte) 0x46, (byte) 0x2f, (byte) 0x4d, (byte) 0x59, + (byte) 0x46, (byte) 0x49, (byte) 0x52, (byte) 0x53, (byte) 0x54, + (byte) 0x4b, (byte) 0x2e, (byte) 0x52, (byte) 0x53, (byte) 0x41, + (byte) 0x33, (byte) 0x68, (byte) 0x62, (byte) 0xd, (byte) 0x61, + (byte) 0xe3, (byte) 0xd4, (byte) 0x6a, (byte) 0xf3, (byte) 0x68, + (byte) 0xfb, (byte) 0xce, (byte) 0xcb, (byte) 0xc8, (byte) 0xce, + (byte) 0xb4, (byte) 0xa0, (byte) 0x89, (byte) 0xd5, (byte) 0xd5, + (byte) 0xa0, (byte) 0x89, (byte) 0xd5, (byte) 0x91, (byte) 0x89, + (byte) 0x91, (byte) 0xd1, (byte) 0x90, (byte) 0xdf, (byte) 0x80, + (byte) 0x97, (byte) 0x8d, (byte) 0x33, (byte) 0xa1, (byte) 0xcd, + (byte) 0x83, (byte) 0x31, (byte) 0x95, (byte) 0x99, (byte) 0x85, + (byte) 0x89, (byte) 0x91, (byte) 0x95, (byte) 0xc1, (byte) 0x80, + (byte) 0x1b, (byte) 0xa1, (byte) 0x90, (byte) 0x71, (byte) 0x41, + (byte) 0x13, (byte) 0x73, (byte) 0x85, (byte) 0x41, (byte) 0x13, + (byte) 0x73, (byte) 0x89, (byte) 0x41, (byte) 0x13, (byte) 0x53, + (byte) 0xcc, (byte) 0x2, (byte) 0x66, (byte) 0x26, (byte) 0x46, + (byte) 0x26, (byte) 0x26, (byte) 0x4e, (byte) 0x86, (byte) 0xcd, + (byte) 0xbc, (byte) 0x81, (byte) 0x6c, (byte) 0xf9, (byte) 0x5b, + (byte) 0xf6, (byte) 0xaa, (byte) 0x82, (byte) 0xf4, (byte) 0x41, + (byte) 0x15, (byte) 0x32, (byte) 0x72, (byte) 0x3, (byte) 0xf5, + (byte) 0x65, (byte) 0x18, (byte) 0x72, (byte) 0x1b, (byte) 0x70, + (byte) 0xb2, (byte) 0x31, (byte) 0x87, (byte) 0xb2, (byte) 0xb0, + (byte) 0x9, (byte) 0x33, (byte) 0x85, (byte) 0x6, (byte) 0xc3, + (byte) 0x38, (byte) 0x1c, (byte) 0xc2, (byte) 0x4c, (byte) 0xbe, + (byte) 0x8e, (byte) 0x86, (byte) 0xc2, (byte) 0x6, (byte) 0x82, + (byte) 0x20, (byte) 0xe, (byte) 0xbb, (byte) 0x30, (byte) 0x97, + (byte) 0x53, (byte) 0x7e, (byte) 0x45, (byte) 0x52, (byte) 0x7e, + (byte) 0x51, (byte) 0x7e, (byte) 0x69, (byte) 0x7a, (byte) 0x6, + (byte) 0xd8, (byte) 0x66, (byte) 0xa0, (byte) 0x20, (byte) 0x97, + (byte) 0x30, (byte) 0x9b, (byte) 0x7f, (byte) 0x51, (byte) 0x62, + (byte) 0x72, (byte) 0x4e, (byte) 0xaa, (byte) 0x21, (byte) 0x2f, + (byte) 0xd0, (byte) 0x6e, (byte) 0xa0, (byte) 0x0, (byte) 0xb7, + (byte) 0x30, (byte) 0x8b, (byte) 0x57, (byte) 0x62, (byte) 0x59, + (byte) 0xa2, (byte) 0xa1, (byte) 0xb8, (byte) 0x81, (byte) 0x28, + (byte) 0x88, (byte) 0xcb, (byte) 0x2c, (byte) 0xcc, (byte) 0xe7, + (byte) 0x93, (byte) 0x98, (byte) 0x97, (byte) 0x9c, (byte) 0xaa, + (byte) 0xe0, (byte) 0x98, (byte) 0x97, (byte) 0x92, (byte) 0x5a, + (byte) 0x54, (byte) 0x9c, (byte) 0x9a, (byte) 0x67, (byte) 0x20, + (byte) 0x27, (byte) 0xce, (byte) 0x6b, (byte) 0x64, (byte) 0x64, + (byte) 0x60, (byte) 0x68, (byte) 0x64, (byte) 0x6e, (byte) 0x68, + (byte) 0x69, (byte) 0x60, (byte) 0x6a, (byte) 0x60, (byte) 0x19, + (byte) 0x5, (byte) 0xe6, (byte) 0x9a, (byte) 0xc0, (byte) 0xb9, + (byte) 0x74, (byte) 0x74, (byte) 0x49, (byte) 0x13, (byte) 0xa3, + (byte) 0x12, (byte) 0x72, (byte) 0x30, (byte) 0x0, (byte) 0x83, + (byte) 0x8f, (byte) 0xb9, (byte) 0x89, (byte) 0x91, (byte) 0x9f, + (byte) 0x1, (byte) 0x28, (byte) 0xce, (byte) 0xc5, (byte) 0xd4, + (byte) 0xc4, (byte) 0xc8, (byte) 0xc8, (byte) 0x30, (byte) 0xd7, + (byte) 0xef, (byte) 0xf5, (byte) 0x1c, (byte) 0x99, (byte) 0x95, + (byte) 0xf7, (byte) 0xca, (byte) 0x4e, (byte) 0xff, (byte) 0x75, + (byte) 0x49, (byte) 0xe4, (byte) 0xa9, (byte) 0x8e, (byte) 0xb8, + (byte) 0x91, (byte) 0xe1, (byte) 0xb5, (byte) 0xf3, (byte) 0xca, + (byte) 0xc1, (byte) 0xe9, (byte) 0x6e, (byte) 0xcd, (byte) 0x97, + (byte) 0xef, (byte) 0x28, (byte) 0x25, (byte) 0xc7, (byte) 0x89, + (byte) 0x6d, (byte) 0xf2, (byte) 0xb, (byte) 0x10, (byte) 0xf0, + (byte) 0x7f, (byte) 0x63, (byte) 0xb8, (byte) 0x91, (byte) 0xfb, + (byte) 0xff, (byte) 0x6b, (byte) 0xfd, (byte) 0x85, (byte) 0x17, + (byte) 0x96, (byte) 0x67, (byte) 0x79, (byte) 0xfd, (byte) 0xa8, + (byte) 0x7b, (byte) 0xbf, (byte) 0x75, (byte) 0xad, (byte) 0x77, + (byte) 0xc0, (byte) 0x4e, (byte) 0x9f, (byte) 0xb6, (byte) 0x9e, + (byte) 0xee, (byte) 0xd, (byte) 0xcb, (byte) 0xf8, (byte) 0xd7, + (byte) 0xc9, (byte) 0xdc, (byte) 0x2c, (byte) 0xee, (byte) 0x4d, + (byte) 0x91, (byte) 0x2e, (byte) 0xb0, (byte) 0x48, (byte) 0xd8, + (byte) 0xb2, (byte) 0x63, (byte) 0xcb, (byte) 0x91, (byte) 0x8f, + (byte) 0x89, (byte) 0x69, (byte) 0x7a, (byte) 0x53, (byte) 0x6f, + (byte) 0x6d, (byte) 0x59, (byte) 0xa3, (byte) 0xd3, (byte) 0xfb, + (byte) 0xab, (byte) 0xa0, (byte) 0xe6, (byte) 0xab, (byte) 0x24, + (byte) 0x73, (byte) 0xd0, (byte) 0x32, (byte) 0xc6, (byte) 0x2c, + (byte) 0x1, (byte) 0x29, (byte) 0xf5, (byte) 0xa3, (byte) 0x1a, + (byte) 0x62, (byte) 0xc5, (byte) 0x4f, (byte) 0xce, (byte) 0xda, + (byte) 0xed, (byte) 0x54, (byte) 0x8b, (byte) 0xfb, (byte) 0x26, + (byte) 0x1b, (byte) 0xba, (byte) 0xe0, (byte) 0xb1, (byte) 0x76, + (byte) 0xb9, (byte) 0x75, (byte) 0xcb, (byte) 0x67, (byte) 0x27, + (byte) 0xa6, (byte) 0xd2, (byte) 0xdb, (byte) 0xb9, (byte) 0x7, + (byte) 0x5, (byte) 0x3e, (byte) 0xee, (byte) 0x9c, (byte) 0x64, + (byte) 0x74, (byte) 0xdc, (byte) 0xad, (byte) 0x80, (byte) 0x8d, + (byte) 0xeb, (byte) 0xe5, (byte) 0xb3, (byte) 0x15, (byte) 0x9b, + (byte) 0x33, (byte) 0xf, (byte) 0x1f, (byte) 0xf7, (byte) 0x34, + (byte) 0x9a, (byte) 0xf5, (byte) 0xf2, (byte) 0xc3, (byte) 0x14, + (byte) 0xd3, (byte) 0x48, (byte) 0x11, (byte) 0xa1, (byte) 0xea, + (byte) 0xe7, (byte) 0xea, (byte) 0x95, (byte) 0x95, (byte) 0x32, + (byte) 0x37, (byte) 0x15, (byte) 0xfa, (byte) 0x2, (byte) 0xfe, + (byte) 0xbd, (byte) 0x61, (byte) 0x17, (byte) 0xb2, (byte) 0xcc, + (byte) 0x9c, (byte) 0xf3, (byte) 0x6e, (byte) 0x9a, (byte) 0x57, + (byte) 0xce, (byte) 0x54, (byte) 0x55, (byte) 0x33, (byte) 0x96, + (byte) 0x64, (byte) 0xde, (byte) 0x2b, (byte) 0x6b, (byte) 0x39, + (byte) 0xfe, (byte) 0x76, (byte) 0xe7, (byte) 0xdc, (byte) 0xb2, + (byte) 0xb3, (byte) 0xbe, (byte) 0xed, (byte) 0x52, (byte) 0x7b, + (byte) 0xb9, (byte) 0x90, (byte) 0xd9, (byte) 0x85, (byte) 0xd9, + (byte) 0xed, (byte) 0xbb, (byte) 0x57, (byte) 0x35, (byte) 0xcf, + (byte) 0xe6, (byte) 0x87, (byte) 0xf3, (byte) 0x4f, (byte) 0x4, + (byte) 0x54, (byte) 0x7b, (byte) 0x95, (byte) 0x5c, (byte) 0xd0, + (byte) 0x9d, (byte) 0x7a, (byte) 0xbd, (byte) 0xb7, (byte) 0x6f, + (byte) 0xe9, (byte) 0x6f, (byte) 0x8f, (byte) 0x86, (byte) 0x93, + (byte) 0x5b, (byte) 0x97, (byte) 0xec, (byte) 0xfe, (byte) 0xd5, + (byte) 0x78, (byte) 0xc2, (byte) 0xd6, (byte) 0xa7, (byte) 0x46, + (byte) 0x8d, (byte) 0x89, (byte) 0xb9, (byte) 0x57, (byte) 0xab, + (byte) 0xb5, (byte) 0x75, (byte) 0xab, (byte) 0xcd, (byte) 0x9d, + (byte) 0x43, (byte) 0x9c, (byte) 0xde, (byte) 0x17, (byte) 0x2b, + (byte) 0x3e, (byte) 0xfa, (byte) 0xbb, (byte) 0x4c, (byte) 0x96, + (byte) 0x9c, (byte) 0x73, (byte) 0xe3, (byte) 0x64, (byte) 0xb4, + (byte) 0xcc, (byte) 0xcb, (byte) 0xfd, (byte) 0x4c, (byte) 0xcc, + (byte) 0x8c, (byte) 0xc, (byte) 0x8c, (byte) 0x8b, (byte) 0x15, + (byte) 0xd, (byte) 0xe4, (byte) 0xd, (byte) 0x64, (byte) 0x81, + (byte) 0x1, (byte) 0x28, (byte) 0xcb, (byte) 0xc7, (byte) 0x22, + (byte) 0xc6, (byte) 0x22, (byte) 0xf2, (byte) 0xb0, (byte) 0xe4, + (byte) 0x67, (byte) 0x69, (byte) 0xfa, (byte) 0xd5, (byte) 0x12, + (byte) 0xdf, (byte) 0x8c, (byte) 0xdf, (byte) 0x21, (byte) 0xd5, + (byte) 0x9f, (byte) 0x17, (byte) 0x8b, (byte) 0xfa, (byte) 0x68, + (byte) 0x9, (byte) 0xf1, (byte) 0xcb, (byte) 0xa0, (byte) 0xa5, + (byte) 0x25, (byte) 0x66, (byte) 0x50, (byte) 0xd8, (byte) 0xf5, + (byte) 0x73, (byte) 0xfc, (byte) 0xf9, (byte) 0xaf, (byte) 0x12, + (byte) 0xbf, (byte) 0x42, (byte) 0xbb, (byte) 0x41, (byte) 0xe0, + (byte) 0xb6, (byte) 0x91, (byte) 0xfc, (byte) 0xbc, (byte) 0xe3, + (byte) 0xf3, (byte) 0x39, (byte) 0x1c, (byte) 0x1b, (byte) 0xf3, + (byte) 0xd8, (byte) 0x2f, (byte) 0x7c, (byte) 0xe9, (byte) 0x7b, + (byte) 0xd2, (byte) 0x1a, (byte) 0xf0, (byte) 0xb3, (byte) 0x52, + (byte) 0x61, (byte) 0xb5, (byte) 0xbf, (byte) 0xde, (byte) 0x31, + (byte) 0xf6, (byte) 0x17, (byte) 0xe7, (byte) 0x5a, (byte) 0x9b, + (byte) 0x9f, (byte) 0x6f, (byte) 0xf5, (byte) 0x94, (byte) 0x4b, + (byte) 0x6d, (byte) 0x31, (byte) 0x2e, (byte) 0x56, (byte) 0x37, + (byte) 0x5c, (byte) 0x64, (byte) 0x32, (byte) 0xc1, (byte) 0xef, + (byte) 0x75, (byte) 0xcf, (byte) 0xe9, (byte) 0x8c, (byte) 0xcc, + (byte) 0xcf, (byte) 0x9d, (byte) 0xdf, (byte) 0x34, (byte) 0x1b, + (byte) 0xf4, (byte) 0xe4, (byte) 0x75, (byte) 0xac, (byte) 0xff, + (byte) 0xbf, (byte) 0x5b, (byte) 0xaf, (byte) 0xfa, (byte) 0x98, + (byte) 0x5f, (byte) 0x22, (byte) 0x75, (byte) 0xf5, (byte) 0xd5, + (byte) 0x8c, (byte) 0xd3, (byte) 0xae, (byte) 0x17, (byte) 0xab, + (byte) 0xad, (byte) 0xb9, (byte) 0x6a, (byte) 0x17, (byte) 0x84, + (byte) 0xf8, (byte) 0xf9, (byte) 0x72, (byte) 0xf5, (byte) 0x7b, + (byte) 0xad, (byte) 0x5b, (byte) 0xd3, (byte) 0xd0, (byte) 0x5f, + (byte) 0x71, (byte) 0x29, (byte) 0xa0, (byte) 0xa3, (byte) 0x2c, + (byte) 0xfc, (byte) 0x73, (byte) 0xc2, (byte) 0x3f, (byte) 0xd6, + (byte) 0xf4, (byte) 0x9c, (byte) 0xbe, (byte) 0xa9, (byte) 0x2c, + (byte) 0xf5, (byte) 0x7e, (byte) 0x17, (byte) 0xdf, (byte) 0x95, + (byte) 0xb2, (byte) 0xdd, (byte) 0x29, (byte) 0x33, (byte) 0xb8, + (byte) 0x66, (byte) 0x56, (byte) 0x55, (byte) 0xcc, (byte) 0xba, + (byte) 0x6a, (byte) 0x5d, (byte) 0x92, (byte) 0xeb, (byte) 0xe7, + (byte) 0x7e, (byte) 0x2f, (byte) 0x67, (byte) 0x99, (byte) 0xa2, + (byte) 0xb, (byte) 0xda, (byte) 0x7d, (byte) 0xa7, (byte) 0x73, + (byte) 0x2b, (byte) 0xb6, (byte) 0x5f, (byte) 0x7e, (byte) 0x3b, + (byte) 0x45, (byte) 0xce, (byte) 0xdc, (byte) 0x28, (byte) 0xed, + (byte) 0xed, (byte) 0xf2, (byte) 0x84, (byte) 0xf0, (byte) 0xc2, + (byte) 0x8d, (byte) 0x62, (byte) 0xbc, (byte) 0xe, (byte) 0xac, + (byte) 0x29, (byte) 0x33, (byte) 0xe3, (byte) 0xdd, (byte) 0xb6, + (byte) 0x33, (byte) 0x98, (byte) 0x15, (byte) 0x54, (byte) 0x4f, + (byte) 0x6f, (byte) 0x8d, (byte) 0xba, (byte) 0x11, (byte) 0xf9, + (byte) 0xeb, (byte) 0xd1, (byte) 0x7e, (byte) 0x3, (byte) 0x13, + (byte) 0xd6, (byte) 0xf6, (byte) 0xea, (byte) 0xee, (byte) 0xc8, + (byte) 0xa5, (byte) 0x7c, (byte) 0xf, (byte) 0x14, (byte) 0x1d, + (byte) 0xae, (byte) 0xfc, (byte) 0xb4, (byte) 0xfb, (byte) 0x2a, + (byte) 0xa4, (byte) 0xf7, (byte) 0xd0, (byte) 0x7b, (byte) 0x53, + (byte) 0x73, (byte) 0xc6, (byte) 0x8b, (byte) 0x6d, (byte) 0xc7, + (byte) 0xac, (byte) 0x8f, (byte) 0x68, (byte) 0x5e, (byte) 0x95, + (byte) 0x7a, (byte) 0x34, (byte) 0xd7, (byte) 0x4e, (byte) 0x5b, + (byte) 0x35, (byte) 0xd3, (byte) 0xe1, (byte) 0xe3, (byte) 0xd7, + (byte) 0x94, (byte) 0x60, (byte) 0xd3, (byte) 0xa4, (byte) 0x93, + (byte) 0x7a, (byte) 0x86, (byte) 0x3f, (byte) 0x35, (byte) 0x58, + (byte) 0x1e, (byte) 0x88, (byte) 0x5d, (byte) 0x7e, (byte) 0xd0, + (byte) 0xf6, (byte) 0x63, (byte) 0xf3, (byte) 0xe3, (byte) 0xd4, + (byte) 0xf, (byte) 0x3b, (byte) 0xd5, (byte) 0xaf, (byte) 0x98, + (byte) 0xfc, (byte) 0x6c, (byte) 0x3e, (byte) 0x66, (byte) 0x1e, + (byte) 0xe5, (byte) 0xe6, (byte) 0x60, (byte) 0x55, (byte) 0x7e, + (byte) 0x78, (byte) 0x45, (byte) 0x89, (byte) 0x86, (byte) 0xde, + (byte) 0xc6, (byte) 0x4f, (byte) 0x86, (byte) 0x4d, (byte) 0x8c, + (byte) 0xb, (byte) 0x80, (byte) 0x9, (byte) 0x69, (byte) 0xe, + (byte) 0x30, (byte) 0x93, (byte) 0x1a, (byte) 0x94, (byte) 0xd2, + (byte) 0x2f, (byte) 0x4d, (byte) 0xa3, (byte) 0xe5, (byte) 0x70, + (byte) 0xe4, (byte) 0x92, (byte) 0x1, (byte) 0x35, (byte) 0xa5, + (byte) 0xb3, (byte) 0x34, (byte) 0x31, (byte) 0x32, (byte) 0xf4, + (byte) 0xa, (byte) 0x9c, (byte) 0xb0, (byte) 0x9d, (byte) 0x61, + (byte) 0x3e, (byte) 0x53, (byte) 0x78, (byte) 0xce, (byte) 0x42, + (byte) 0xb7, (byte) 0x7, (byte) 0x9b, (byte) 0xcb, (byte) 0x95, + (byte) 0xb6, (byte) 0x74, (byte) 0xe8, (byte) 0x16, (byte) 0x8, + (byte) 0xfe, (byte) 0x3c, (byte) 0x74, (byte) 0xe1, (byte) 0xe, + (byte) 0x87, (byte) 0xf6, (byte) 0x3a, (byte) 0xeb, (byte) 0x45, + (byte) 0xfb, (byte) 0x97, (byte) 0x71, (byte) 0xbf, (byte) 0xaa, + (byte) 0x13, (byte) 0x89, (byte) 0x78, (byte) 0x1e, (byte) 0x74, + (byte) 0xe4, (byte) 0x97, (byte) 0x69, (byte) 0xf2, (byte) 0xe5, + (byte) 0xd, (byte) 0x22, (byte) 0xa, (byte) 0x73, (byte) 0xf7, + (byte) 0x5e, (byte) 0xd1, (byte) 0x92, (byte) 0xdb, (byte) 0x25, + (byte) 0x72, (byte) 0xf0, (byte) 0xdb, (byte) 0x34, (byte) 0xc3, + (byte) 0x79, (byte) 0xcb, (byte) 0xaa, (byte) 0xcb, (byte) 0xc, + (byte) 0xd4, (byte) 0xd3, (byte) 0xd6, (byte) 0x9e, (byte) 0xb8, + (byte) 0xa9, (byte) 0xf3, (byte) 0x71, (byte) 0xa5, (byte) 0x48, + (byte) 0x4a, (byte) 0xe2, (byte) 0x57, (byte) 0xbb, (byte) 0xb6, + (byte) 0xe5, (byte) 0xaf, (byte) 0x5e, (byte) 0x4, (byte) 0x48, + (byte) 0xd6, (byte) 0xd5, (byte) 0x71, (byte) 0xc8, (byte) 0xaf, + (byte) 0x34, (byte) 0xe0, (byte) 0xae, (byte) 0x5e, (byte) 0x1a, + (byte) 0xbe, (byte) 0xb5, (byte) 0xc3, (byte) 0xbc, (byte) 0xa9, + (byte) 0xfc, (byte) 0x51, (byte) 0xc, (byte) 0x73, (byte) 0xef, + (byte) 0x83, (byte) 0x47, (byte) 0x3e, (byte) 0x72, (byte) 0x3b, + (byte) 0xce, (byte) 0xbe, (byte) 0xfd, (byte) 0xb4, (byte) 0x41, + (byte) 0x20, (byte) 0x54, (byte) 0xf2, (byte) 0x47, (byte) 0x45, + (byte) 0x69, (byte) 0xb8, (byte) 0xcd, (byte) 0x59, (byte) 0xbb, + (byte) 0x8e, (byte) 0xf2, (byte) 0xc3, (byte) 0x86, (byte) 0xea, + (byte) 0x32, (byte) 0x1f, (byte) 0xbf, (byte) 0x4, (byte) 0x6b, + (byte) 0xda, (byte) 0xaa, (byte) 0x2b, (byte) 0x33, (byte) 0x7d, + (byte) 0x54, (byte) 0xf2, (byte) 0x9, (byte) 0x16, (byte) 0x16, + (byte) 0xfa, (byte) 0x5b, (byte) 0xb6, (byte) 0x6d, (byte) 0x42, + (byte) 0xaa, (byte) 0x9e, (byte) 0x9e, (byte) 0x16, (byte) 0x73, + (byte) 0xc0, (byte) 0x6a, (byte) 0xf7, (byte) 0xbf, (byte) 0x13, + (byte) 0xf9, (byte) 0xbc, (byte) 0xfc, (byte) 0x79, (byte) 0xcc, + (byte) 0x84, (byte) 0x6a, (byte) 0x9f, (byte) 0x9c, (byte) 0x88, + (byte) 0xcd, (byte) 0xb3, (byte) 0xb3, (byte) 0x98, (byte) 0xc0, + (byte) 0xf3, (byte) 0xf0, (byte) 0xc4, (byte) 0x86, (byte) 0x6f, + (byte) 0x86, (byte) 0xd1, (byte) 0x97, (byte) 0x53, (byte) 0x4b, + (byte) 0x6b, (byte) 0xb9, (byte) 0xbe, (byte) 0xca, (byte) 0xde, + (byte) 0xd8, (byte) 0x23, (byte) 0x58, (byte) 0xee, (byte) 0x92, + (byte) 0xcc, (byte) 0x7f, (byte) 0xa7, (byte) 0xe7, (byte) 0xbc, + (byte) 0xff, (byte) 0x84, (byte) 0x93, (byte) 0x13, (byte) 0xcc, + (byte) 0x94, (byte) 0xe, (byte) 0x73, (byte) 0x9b, (byte) 0x2c, + (byte) 0x9d, (byte) 0xfa, (byte) 0x62, (byte) 0x75, (byte) 0x98, + (byte) 0x6f, (byte) 0x70, (byte) 0xf1, (byte) 0x97, (byte) 0xaa, + (byte) 0xe5, (byte) 0x9b, (byte) 0xa6, (byte) 0xac, (byte) 0x4e, + (byte) 0x7f, (byte) 0xbb, (byte) 0xc2, (byte) 0x34, (byte) 0xec, + (byte) 0xe2, (byte) 0xbe, (byte) 0xc0, (byte) 0x99, (byte) 0x1d, + (byte) 0x9f, (byte) 0xb8, (byte) 0xa5, (byte) 0x6b, (byte) 0xb8, + (byte) 0x4, (byte) 0xf7, (byte) 0x2d, (byte) 0x11, (byte) 0x9a, + (byte) 0x56, (byte) 0xb1, (byte) 0xa9, (byte) 0xbd, (byte) 0xb4, + (byte) 0x8f, (byte) 0x57, (byte) 0x60, (byte) 0xcf, (byte) 0xb3, + (byte) 0xab, (byte) 0xad, (byte) 0x86, (byte) 0xea, (byte) 0x46, + (byte) 0xbb, (byte) 0x7b, (byte) 0xf7, (byte) 0xfe, (byte) 0xe8, + (byte) 0xd6, (byte) 0xd2, (byte) 0x9d, (byte) 0x3, (byte) 0x0, + (byte) 0x50, (byte) 0x4b, (byte) 0x7, (byte) 0x8, (byte) 0xba, + (byte) 0x40, (byte) 0x24, (byte) 0x13, (byte) 0x4c, (byte) 0x4, + (byte) 0x0, (byte) 0x0, (byte) 0x58, (byte) 0x5, (byte) 0x0, + (byte) 0x0, (byte) 0x50, (byte) 0x4b, (byte) 0x3, (byte) 0x4, + (byte) 0x14, (byte) 0x0, (byte) 0x8, (byte) 0x8, (byte) 0x8, + (byte) 0x0, (byte) 0x6d, (byte) 0x73, (byte) 0x3a, (byte) 0x54, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0x9, (byte) 0x0, (byte) 0x4, + (byte) 0x0, (byte) 0x4d, (byte) 0x45, (byte) 0x54, (byte) 0x41, + (byte) 0x2d, (byte) 0x49, (byte) 0x4e, (byte) 0x46, (byte) 0x2f, + (byte) 0xfe, (byte) 0xca, (byte) 0x0, (byte) 0x0, (byte) 0x3, + (byte) 0x0, (byte) 0x50, (byte) 0x4b, (byte) 0x7, (byte) 0x8, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x2, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0x50, (byte) 0x4b, (byte) 0x3, + (byte) 0x4, (byte) 0x14, (byte) 0x0, (byte) 0x8, (byte) 0x8, + (byte) 0x8, (byte) 0x0, (byte) 0x6c, (byte) 0xb1, (byte) 0x38, + (byte) 0x3e, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x1c, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0x6a, (byte) 0x61, (byte) 0x76, + (byte) 0x61, (byte) 0x78, (byte) 0x2f, (byte) 0x69, (byte) 0x6e, + (byte) 0x6a, (byte) 0x65, (byte) 0x63, (byte) 0x74, (byte) 0x2f, + (byte) 0x53, (byte) 0x69, (byte) 0x6e, (byte) 0x67, (byte) 0x6c, + (byte) 0x65, (byte) 0x74, (byte) 0x6f, (byte) 0x6e, (byte) 0x2e, + (byte) 0x63, (byte) 0x6c, (byte) 0x61, (byte) 0x73, (byte) 0x73, + (byte) 0x85, (byte) 0x90, (byte) 0x4d, (byte) 0x4b, (byte) 0x82, + (byte) 0x41, (byte) 0x10, (byte) 0xc7, (byte) 0xff, (byte) 0xa3, + (byte) 0xd9, (byte) 0x63, (byte) 0x56, (byte) 0xe6, (byte) 0x21, + (byte) 0x5, (byte) 0x4f, (byte) 0xda, (byte) 0xc5, (byte) 0x63, + (byte) 0x4b, (byte) 0xe7, (byte) 0x4e, (byte) 0x41, (byte) 0x6, + (byte) 0x81, (byte) 0xa5, (byte) 0x3c, (byte) 0x5a, (byte) 0xf7, + (byte) 0x75, (byte) 0x1b, (byte) 0x64, (byte) 0x65, (byte) 0xdd, + (byte) 0x8d, (byte) 0xdc, (byte) 0x47, (byte) 0xea, (byte) 0xab, + (byte) 0x79, (byte) 0xe8, (byte) 0x3, (byte) 0xf4, (byte) 0xa1, + (byte) 0xc4, (byte) 0xd9, (byte) 0xe, (byte) 0x4a, (byte) 0x20, + (byte) 0x34, (byte) 0x30, (byte) 0x2f, (byte) 0xcc, (byte) 0xfc, + (byte) 0x66, (byte) 0x98, (byte) 0x99, (byte) 0x9f, (byte) 0xcd, + (byte) 0xfa, (byte) 0x1b, (byte) 0xc0, (byte) 0xd, (byte) 0x1a, + (byte) 0x84, (byte) 0x2c, (byte) 0x7f, (byte) 0x79, (byte) 0x9e, + (byte) 0x3c, (byte) 0x3e, (byte) 0xf5, (byte) 0x9, (byte) 0x8d, + (byte) 0xb9, (byte) 0x5e, (byte) 0x69, (byte) 0xe5, (byte) 0xb4, + (byte) 0x9f, (byte) 0xa9, (byte) 0xe1, (byte) 0x74, (byte) 0xce, + (byte) 0x26, (byte) 0x12, (byte) 0x3a, (byte) 0xfb, (byte) 0x94, + (byte) 0xf6, (byte) 0x3e, (byte) 0x44, (byte) 0x1d, (byte) 0x6d, + (byte) 0xf0, (byte) 0xea, (byte) 0x6e, (byte) 0x17, (byte) 0x12, + (byte) 0x5a, (byte) 0x89, (byte) 0xf8, (byte) 0x54, (byte) 0xd6, + (byte) 0xa7, (byte) 0x6, (byte) 0x35, (byte) 0xb6, (byte) 0x7e, + (byte) 0xe6, (byte) 0x38, (byte) 0xa6, (byte) 0x42, (byte) 0x65, + (byte) 0xa5, (byte) 0x5d, (byte) 0xc1, (byte) 0x19, (byte) 0x4a, + (byte) 0x19, (byte) 0xca, (byte) 0x19, (byte) 0x8e, (byte) 0x8, + (byte) 0x57, (byte) 0x83, (byte) 0x83, (byte) 0xc3, (byte) 0xee, + (byte) 0x83, (byte) 0x29, (byte) 0x16, (byte) 0xec, (byte) 0x23, + (byte) 0xbf, (byte) 0xdd, (byte) 0x12, (byte) 0xba, (byte) 0x87, + (byte) 0x99, (byte) 0x9c, (byte) 0xa3, (byte) 0x10, (byte) 0x12, + (byte) 0x9, (byte) 0xd2, (byte) 0xfb, (byte) 0x7, (byte) 0x19, + (byte) 0x5, (byte) 0x67, (byte) 0xcd, (byte) 0x97, (byte) 0x80, + (byte) 0x97, (byte) 0x83, (byte) 0xbf, (byte) 0xab, (byte) 0x99, + (byte) 0xf0, (byte) 0xce, (byte) 0x92, (byte) 0x6e, (byte) 0xe7, + (byte) 0x85, (byte) 0x70, (byte) 0xb, (byte) 0x7e, (byte) 0xb5, + (byte) 0x4b, (byte) 0x3b, (byte) 0x75, (byte) 0xbc, (byte) 0xbf, + (byte) 0x65, (byte) 0x49, (byte) 0xa8, (byte) 0xef, (byte) 0xf6, + (byte) 0xbf, (byte) 0x4e, (byte) 0xbd, (byte) 0x84, (byte) 0xda, + (byte) 0x38, (byte) 0x14, (byte) 0x1f, (byte) 0x86, (byte) 0x1f, + (byte) 0xac, (byte) 0xe3, (byte) 0x1e, (byte) 0xa1, (byte) 0x8a, + (byte) 0x63, (byte) 0xc8, (byte) 0xc3, (byte) 0x90, (byte) 0xa4, + (byte) 0x84, (byte) 0x8b, (byte) 0x5f, (byte) 0x5b, (byte) 0xc7, + (byte) 0xb9, (byte) 0xf8, (byte) 0x26, (byte) 0xca, (byte) 0x38, + (byte) 0x13, (byte) 0x7f, (byte) 0x22, (byte) 0x5a, (byte) 0x13, + (byte) 0xa6, (byte) 0xc2, (byte) 0x38, (byte) 0x5, (byte) 0x6d, + (byte) 0x1, (byte) 0x50, (byte) 0x4b, (byte) 0x7, (byte) 0x8, + (byte) 0x5a, (byte) 0xf1, (byte) 0x0, (byte) 0x98, (byte) 0xdd, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x67, (byte) 0x1, + (byte) 0x0, (byte) 0x0, (byte) 0x50, (byte) 0x4b, (byte) 0x1, + (byte) 0x2, (byte) 0x14, (byte) 0x0, (byte) 0x14, (byte) 0x0, + (byte) 0x8, (byte) 0x8, (byte) 0x8, (byte) 0x0, (byte) 0x17, + (byte) 0x71, (byte) 0x3b, (byte) 0x54, (byte) 0xc1, (byte) 0xfa, + (byte) 0x9d, (byte) 0xe2, (byte) 0x9e, (byte) 0x0, (byte) 0x0, + (byte) 0x0, (byte) 0xa6, (byte) 0x0, (byte) 0x0, (byte) 0x0, + (byte) 0x14, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x4d, (byte) 0x45, + (byte) 0x54, (byte) 0x41, (byte) 0x2d, (byte) 0x49, (byte) 0x4e, + (byte) 0x46, (byte) 0x2f, (byte) 0x4d, (byte) 0x41, (byte) 0x4e, + (byte) 0x49, (byte) 0x46, (byte) 0x45, (byte) 0x53, (byte) 0x54, + (byte) 0x2e, (byte) 0x4d, (byte) 0x46, (byte) 0x50, (byte) 0x4b, + (byte) 0x1, (byte) 0x2, (byte) 0x14, (byte) 0x0, (byte) 0x14, + (byte) 0x0, (byte) 0x8, (byte) 0x8, (byte) 0x8, (byte) 0x0, + (byte) 0x17, (byte) 0x71, (byte) 0x3b, (byte) 0x54, (byte) 0x8b, + (byte) 0xcb, (byte) 0xd5, (byte) 0xea, (byte) 0x3, (byte) 0x1, + (byte) 0x0, (byte) 0x0, (byte) 0x48, (byte) 0x1, (byte) 0x0, + (byte) 0x0, (byte) 0x14, (byte) 0x0, (byte) 0x0, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, + (byte) 0xe0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x4d, + (byte) 0x45, (byte) 0x54, (byte) 0x41, (byte) 0x2d, (byte) 0x49, + (byte) 0x4e, (byte) 0x46, (byte) 0x2f, (byte) 0x4d, (byte) 0x59, + (byte) 0x46, (byte) 0x49, (byte) 0x52, (byte) 0x53, (byte) 0x54, + (byte) 0x4b, (byte) 0x2e, (byte) 0x53, (byte) 0x46, (byte) 0x50, + (byte) 0x4b, (byte) 0x1, (byte) 0x2, (byte) 0x14, (byte) 0x0, + (byte) 0x14, (byte) 0x0, (byte) 0x8, (byte) 0x8, (byte) 0x8, + (byte) 0x0, (byte) 0x17, (byte) 0x71, (byte) 0x3b, (byte) 0x54, + (byte) 0xba, (byte) 0x40, (byte) 0x24, (byte) 0x13, (byte) 0x4c, + (byte) 0x4, (byte) 0x0, (byte) 0x0, (byte) 0x58, (byte) 0x5, + (byte) 0x0, (byte) 0x0, (byte) 0x15, (byte) 0x0, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, + (byte) 0x0, (byte) 0x25, (byte) 0x2, (byte) 0x0, (byte) 0x0, + (byte) 0x4d, (byte) 0x45, (byte) 0x54, (byte) 0x41, (byte) 0x2d, + (byte) 0x49, (byte) 0x4e, (byte) 0x46, (byte) 0x2f, (byte) 0x4d, + (byte) 0x59, (byte) 0x46, (byte) 0x49, (byte) 0x52, (byte) 0x53, + (byte) 0x54, (byte) 0x4b, (byte) 0x2e, (byte) 0x52, (byte) 0x53, + (byte) 0x41, (byte) 0x50, (byte) 0x4b, (byte) 0x1, (byte) 0x2, + (byte) 0x14, (byte) 0x0, (byte) 0x14, (byte) 0x0, (byte) 0x8, + (byte) 0x8, (byte) 0x8, (byte) 0x0, (byte) 0x6d, (byte) 0x73, + (byte) 0x3a, (byte) 0x54, (byte) 0x0, (byte) 0x0, (byte) 0x0, + (byte) 0x0, (byte) 0x2, (byte) 0x0, (byte) 0x0, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x9, + (byte) 0x0, (byte) 0x4, (byte) 0x0, (byte) 0x0, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0xb4, (byte) 0x6, + (byte) 0x0, (byte) 0x0, (byte) 0x4d, (byte) 0x45, (byte) 0x54, + (byte) 0x41, (byte) 0x2d, (byte) 0x49, (byte) 0x4e, (byte) 0x46, + (byte) 0x2f, (byte) 0xfe, (byte) 0xca, (byte) 0x0, (byte) 0x0, + (byte) 0x50, (byte) 0x4b, (byte) 0x1, (byte) 0x2, (byte) 0x14, + (byte) 0x0, (byte) 0x14, (byte) 0x0, (byte) 0x8, (byte) 0x8, + (byte) 0x8, (byte) 0x0, (byte) 0x6c, (byte) 0xb1, (byte) 0x38, + (byte) 0x3e, (byte) 0x5a, (byte) 0xf1, (byte) 0x0, (byte) 0x98, + (byte) 0xdd, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x67, + (byte) 0x1, (byte) 0x0, (byte) 0x0, (byte) 0x1c, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0xf1, (byte) 0x6, (byte) 0x0, + (byte) 0x0, (byte) 0x6a, (byte) 0x61, (byte) 0x76, (byte) 0x61, + (byte) 0x78, (byte) 0x2f, (byte) 0x69, (byte) 0x6e, (byte) 0x6a, + // We will modify 0x53, "S", within the CEN filename entry + (byte) 0x65, (byte) 0x63, (byte) 0x74, (byte) 0x2f, (byte) 0x53, + (byte) 0x69, (byte) 0x6e, (byte) 0x67, (byte) 0x6c, (byte) 0x65, + (byte) 0x74, (byte) 0x6f, (byte) 0x6e, (byte) 0x2e, (byte) 0x63, + (byte) 0x6c, (byte) 0x61, (byte) 0x73, (byte) 0x73, (byte) 0x50, + (byte) 0x4b, (byte) 0x5, (byte) 0x6, (byte) 0x0, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0x5, (byte) 0x0, (byte) 0x5, + (byte) 0x0, (byte) 0x4c, (byte) 0x1, (byte) 0x0, (byte) 0x0, + (byte) 0x18, (byte) 0x8, (byte) 0x0, (byte) 0x0, (byte) 0x0, + (byte) 0x0, + }; + + /** + * DataProvider used to specify valid jars and whether to verify them + * + * @return Entry object indicating the jar file and whether it will be verified + */ + @DataProvider + public Object[][] validJars() { + return new Object[][]{ + {SIGNED_VALID_ENTRY_NAME_JAR, true}, + {SIGNED_VALID_ENTRY_NAME_JAR, false}, + {VALID_ENTRY_NAME_JAR, true}, + {VALID_ENTRY_NAME_JAR, false}, + }; + } + + /** + * DataProvider used to specify invalid jars and whether to verify them + * + * @return Entry object indicating the jar file and whether it will be verified + */ + @DataProvider + public Object[][] inValidJars() { + return new Object[][]{ + {SIGNED_INVALID_ENTRY_NAME_JAR, true}, + {SIGNED_INVALID_ENTRY_NAME_JAR, false}, + {INVALID_ENTRY_NAME_JAR, true}, + {INVALID_ENTRY_NAME_JAR, false}, + }; + } + + /** + * Create Jar files used by the tests. + * + * The {@code byte} arrays {@code VALID_ENTRY_NAME_JAR} and + * {@code SIGNED-VALID_ENTRY_NAME_JAR} are written to disk to create the jar + * files: {@code Valid-EntryName.jar} and {@code Signed-Valid-EntryName.jar}. + * + * The jar files {@code Invalid-EntryName.jar} and + * {@code Signed-Invalid-EntryName.jar} are created by copying the + * {@code byte} arrays {@code VALID_ENTRY_NAME} and + * {@code SIGNED-VALID_ENTRY_NAME} and modifying + * the CEN filename entry, "javax/inject/Singleton.class", changing the + * first character from {@code 0x53}, "S", to the {@code 0x13}. + * + * @throws IOException If an error occurs + * + */ + @BeforeTest + public static void setup() throws IOException { + + // Create valid jar + Files.deleteIfExists(VALID_ENTRY_NAME_JAR); + Files.write(VALID_ENTRY_NAME_JAR, VALID_ENTRY_NAME); + + // Create valid signed jar + Files.deleteIfExists(SIGNED_VALID_ENTRY_NAME_JAR); + Files.write(SIGNED_VALID_ENTRY_NAME_JAR, SIGNED_VALID_ENTRY_NAME); + + // Create a JAR file with the invalid entry name + Files.deleteIfExists(INVALID_ENTRY_NAME_JAR); + // Make a copy of the byte array containing the valid entry name + byte[] invalid_bytes = Arrays.copyOf(VALID_ENTRY_NAME, VALID_ENTRY_NAME.length); + // Change from 0x53, "S", to an invalid UTF8 character, 0x13 + invalid_bytes[VALID_ENTRY_NAME.length - SINGLETON_CEN_FILENAME_OFFSET] = + INVALID_UTF8_BYTE; + Files.write(INVALID_ENTRY_NAME_JAR, invalid_bytes); + + // Create a signed JAR file with the invalid entry name + Files.deleteIfExists(SIGNED_INVALID_ENTRY_NAME_JAR); + // Make a copy of the byte array containing the valid entry name + invalid_bytes = Arrays.copyOf(SIGNED_VALID_ENTRY_NAME, + SIGNED_VALID_ENTRY_NAME.length); + // Change from 0x53, "S", to an invalid UTF8 character, 0x13 + invalid_bytes[SIGNED_VALID_ENTRY_NAME.length - SINGLETON_CEN_FILENAME_OFFSET] = + INVALID_UTF8_BYTE; + Files.write(SIGNED_INVALID_ENTRY_NAME_JAR, invalid_bytes); + } + + /** + * Clean up after the test run + * + * @throws IOException If an error occurs + */ + @AfterTest + public static void cleanup() throws IOException { + Files.deleteIfExists(VALID_ENTRY_NAME_JAR); + Files.deleteIfExists(SIGNED_VALID_ENTRY_NAME_JAR); + Files.deleteIfExists(INVALID_ENTRY_NAME_JAR); + Files.deleteIfExists(SIGNED_INVALID_ENTRY_NAME_JAR); + } + + /** + * Validate that the CEN filename to be modified can be accessed in + * the original jar when the file is opened using JarFile and accessed via + * a ZipEntry + * + * @param jar the jar file to be used + * @param verify indicates whether the jar should be verified + * @throws Exception if an error occurs + */ + @Test(dataProvider = "validJars") + public static void validJarFileZipEntryTest(Path jar, boolean verify) throws Exception { + try (JarFile jf = new JarFile(jar.toFile(), verify)) { + ZipEntry ze = jf.getEntry(CEN_FILENAME_TO_MODIFY); + var is = jf.getInputStream(ze); + byte[] cnt = is.readAllBytes(); + assertNotNull(cnt); + } + } + + /** + * Validate that the CEN filename to be modified can be accessed in + * the original jar when the file is opened using JarFile and accessed via + * a JarEntry + * + * @param jar the jar file to be used + * @param verify indicates whether the jar should be verified + * @throws Exception if an error occurs + */ + @Test(dataProvider = "validJars") + public static void validJarFileJarEntryTest(Path jar, boolean verify) throws Exception { + try (JarFile jf = new JarFile(jar.toFile(), verify)) { + ZipEntry ze = jf.getEntry(CEN_FILENAME_TO_MODIFY); + var is = jf.getInputStream(ze); + byte[] cnt = is.readAllBytes(); + assertNotNull(cnt); + } + } + + /** + * Validate that the CEN filename to be modified can be accessed in + * the original jar when the file is opened using ZipFile + * + * @param jar the jar file to be used + * @param verify indicates whether the jar should be verified(not used) + * @throws Exception if an error occurs + */ + @Test(dataProvider = "validJars") + public static void validZipFileZipEntryTest(Path jar, boolean verify) throws Exception { + try (ZipFile jf = new ZipFile(jar.toFile())) { + ZipEntry ze = jf.getEntry(CEN_FILENAME_TO_MODIFY); + var is = jf.getInputStream(ze); + byte[] cnt = is.readAllBytes(); + assertNotNull(cnt); + } + } + + /** + * Validate that a NullPointerException is thrown by JarFile::getInputStream + * when the specified ZipEntry is null. + * + * @param jar the jar file to be used + * @param verify indicates whether the jar should be verified(not used) + * @throws Exception if an error occurs + */ + @Test(dataProvider = "inValidJars") + public static void invalidJarFileZipEntry(Path jar, boolean verify) throws Exception { + try (JarFile jf = new JarFile(jar.toFile(), verify)) { + // The entry will not be found resulting in the ZipEntry being null + ZipEntry ze = jf.getEntry(CEN_FILENAME_TO_MODIFY); + var ex= expectThrows(NullPointerException.class, + () -> jf.getInputStream(ze) ); + // Validate that we receive the expected message from Objects.requireNonNull + assertTrue( ex != null && ex.getMessage().equals("ze")); + } + } + + /** + * Validate that a NullPointerException is thrown by ZipFile::getInputStream + * when the specified ZipEntry is null. + * @param jar the jar file to be used + * @param verify indicates whether the jar should be verified(not used) + * @throws IOException if an error occurs + */ + @Test(dataProvider = "inValidJars") + public static void invalidZipFileZipEntry(Path jar, boolean verify) throws Exception { + try (ZipFile jf = new ZipFile(jar.toFile())) { + // The entry will not be found resulting in the ZipEntry being null + ZipEntry ze = jf.getEntry(CEN_FILENAME_TO_MODIFY); + var ex= expectThrows(NullPointerException.class, + () -> jf.getInputStream(ze) ); + // Validate that we receive the expected message from Objects.requireNonNull + assertTrue( ex != null && ex.getMessage().equals("entry")); + } + } + + /** + * Validate that JarFile::getInputStream will return null when the specified + * ZipEntry does not exist in the Jar file + * + * @param jar the jar file to be used + * @param verify indicates whether the jar should be verified + * @throws Exception if an error occurs + */ + @Test(dataProvider = "validJars") + public static void JarFileZipEntryDoesNotExistGetInputStreamTest( + Path jar, boolean verify) throws Exception { + + try (JarFile jf = new JarFile(jar.toFile(), verify)) { + var ze = new ZipEntry(ZIP_ENTRY_THAT_DOES_NOT_EXIST); + var is = jf.getInputStream(ze); + // As the ZipEntry cannot be found, the returned InputStream is null + assertNull(is); + } + } + + /** + * Validate that ZipFile::getInputStream will return null when the specified + * ZipEntry does not exist in the Jar file + * @param jar the jar file to be used + * @param verify indicates whether the jar should be verified(not used) + * @throws Exception if an error occurs + */ + @Test(dataProvider = "validJars") + public static void ZipFileZipEntryDoesNotExistGetInputStreamTest( + Path jar, boolean verify) throws Exception { + try (ZipFile jf = new ZipFile(jar.toFile())) { + var ze = new ZipEntry(ZIP_ENTRY_THAT_DOES_NOT_EXIST); + var is = jf.getInputStream(ze); + // As the ZipEntry cannot be found, the returned InputStream is null + assertNull(is); + } + } + + /** + * Validate that JarFile::getInputStream will return null when the specified + * JarEntry does not exist in the Jar file + * @param jar the jar file to be used + * @param verify indicates whether the jar should be verified + * @throws Exception if an error occurs + */ + @Test(dataProvider = "validJars") + public static void JarFileJarEntryEntryDoesNotExistGetInputStreamTest ( + Path jar, boolean verify) throws Exception { + try (JarFile jf = new JarFile(jar.toFile(), verify)) { + var je = new JarEntry(ZIP_ENTRY_THAT_DOES_NOT_EXIST); + var is = jf.getInputStream(je); + // As the JarEntry cannot be found, the returned InputStream is null + assertNull(is); + } + } + + /** + * Validate that JarFile::getInputStream will return null when validating + * a signed jar and the ZipEntry passed as a parameter returns null + * when ZipEntry::getName is invoked. + * @param jar the jar file to be used + * @param verify indicates whether the jar should be verified + * @throws Exception if an error occurs + */ + @Test(dataProvider = "validJars") + public static void JarFileZipEntryGetNameNullTest(Path jar, boolean verify) throws Exception { + + // Signed Jar is used for the next checks + try (JarFile jf = new JarFile(jar.toFile(), verify)) { + var ze = new InvalidZipEntry(CEN_FILENAME_TO_MODIFY); + var is = jf.getInputStream(ze); + // As the ZipEntry cannot be found, the returned InputStream is null + assertNull(is); + } + } + + /** + * Utility method which takes a byte array and converts to byte array + * declaration. For example: + * <pre> + * {@code + * var fooJar = Files.readAllBytes(Path.of("foo.jar")); + * var result = createByteArray(fooJar, "FOO_BYTES"); + * } + * </pre> + * + * @param bytes A byte array used to create a byte array declaration + * @param name Name to be used in the byte array declaration + * @return The formatted byte array declaration + */ + public static String createByteArray(byte[] bytes, String name) { + StringBuilder sb = new StringBuilder(bytes.length * 5); + Formatter fmt = new Formatter(sb); + fmt.format(" public static byte[] %s = {", name); + final int length = 5; + for (int i = 0; i < bytes.length; i++) { + if (i % length == 0) { + fmt.format("%n "); + } + fmt.format(" (byte) 0x%x,", bytes[i] & 0xff); + } + fmt.format("%n };%n"); + return sb.toString(); + } + + /** + * Overridden ZipEntry class which specifies an invalid name for the + * ZipEntry and will always return null for the Zip entry name + */ + public static class InvalidZipEntry extends ZipEntry { + public InvalidZipEntry(String name) { + super(ZIP_ENTRY_THAT_DOES_NOT_EXIST); + } + public String getName() { + return null; + } + } +} diff --git a/test/jdk/java/util/zip/ZipFile/InvalidCommentLengthTest.java b/test/jdk/java/util/zip/ZipFile/InvalidCommentLengthTest.java new file mode 100644 index 0000000000000000000000000000000000000000..1910107f0d39bd1d6e18ef47181b9f9782c5c85a --- /dev/null +++ b/test/jdk/java/util/zip/ZipFile/InvalidCommentLengthTest.java @@ -0,0 +1,345 @@ +/* + * 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. + * + */ + +import org.testng.annotations.AfterTest; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Arrays; +import java.util.jar.JarFile; +import java.util.zip.ZipEntry; +import java.util.zip.ZipException; +import java.util.zip.ZipFile; + +import static org.testng.Assert.*; + +/** + * @test + * @bug 8280404 + * @summary Validate that Zip/JarFile will throw a ZipException when the CEN + * comment length field contains an incorrect value + * @run testng/othervm InvalidCommentLengthTest + */ +public class InvalidCommentLengthTest { + + // Name used to create a JAR with an invalid comment length + public static final Path INVALID_CEN_COMMENT_LENGTH_JAR = + Path.of("Invalid-CEN-Comment-Length.jar"); + // Name used to create a JAR with a valid comment length + public static final Path VALID_CEN_COMMENT_LENGTH_JAR = + Path.of("Valid-CEN-Comment-Length.jar"); + // Zip/Jar CEN file header entry that will be modified + public static final String META_INF_MANIFEST_MF = "META-INF/MANIFEST.MF"; + // Expected ZipException message when the comment length corrupts the + // Zip/Jar file + public static final String INVALID_CEN_HEADER_BAD_ENTRY_NAME_OR_COMMENT = + "invalid CEN header (bad entry name or comment)"; + + /** + * Byte array representing a valid jar file prior modifying the comment length + * entry in a CEN file header. + * The "Valid-CEN-Comment-Length.jar" jar file was created via: + * <pre> + * {@code + * jar cvf Valid-CEN-Comment-Length.jar Hello.txt Tennis.txt BruceWayne.txt + * added manifest + * adding: Hello.txt(in = 12) (out= 14)(deflated -16%) + * adding: Tennis.txt(in = 53) (out= 53)(deflated 0%) + * adding: BruceWayne.txt(in = 12) (out= 14)(deflated -16%) + * } + * </pre> + * Its contents are: + * <pre> + * {@code + * jar tvf Valid-CEN-Comment-Length.jar + * 0 Wed Mar 02 06:39:24 EST 2022 META-INF/ + * 66 Wed Mar 02 06:39:24 EST 2022 META-INF/MANIFEST.MF + * 12 Wed Mar 02 06:39:06 EST 2022 Hello.txt + * 53 Wed Mar 02 13:04:48 EST 2022 Tennis.txt + * 12 Wed Mar 02 15:15:34 EST 2022 BruceWayne.txt + * } + * </pre> + * The ByteArray was created by: + * <pre> + * {@code + * var jar = Files.readAllBytes("Valid-CEN-Comment-Length.jar"); + * var validEntryName = createByteArray(fooJar, + * "VALID_ZIP_WITH_NO_COMMENTS_BYTES"); + * } + * </pre> + */ + public static byte[] VALID_ZIP_WITH_NO_COMMENTS_BYTES = { + (byte) 0x50, (byte) 0x4b, (byte) 0x3, (byte) 0x4, (byte) 0x14, + (byte) 0x0, (byte) 0x8, (byte) 0x8, (byte) 0x8, (byte) 0x0, + (byte) 0xec, (byte) 0x34, (byte) 0x62, (byte) 0x54, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, + (byte) 0x0, (byte) 0x9, (byte) 0x0, (byte) 0x4, (byte) 0x0, + (byte) 0x4d, (byte) 0x45, (byte) 0x54, (byte) 0x41, (byte) 0x2d, + (byte) 0x49, (byte) 0x4e, (byte) 0x46, (byte) 0x2f, (byte) 0xfe, + (byte) 0xca, (byte) 0x0, (byte) 0x0, (byte) 0x3, (byte) 0x0, + (byte) 0x50, (byte) 0x4b, (byte) 0x7, (byte) 0x8, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x2, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, + (byte) 0x0, (byte) 0x50, (byte) 0x4b, (byte) 0x3, (byte) 0x4, + (byte) 0x14, (byte) 0x0, (byte) 0x8, (byte) 0x8, (byte) 0x8, + (byte) 0x0, (byte) 0xec, (byte) 0x34, (byte) 0x62, (byte) 0x54, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0x14, (byte) 0x0, (byte) 0x0, + (byte) 0x0, (byte) 0x4d, (byte) 0x45, (byte) 0x54, (byte) 0x41, + (byte) 0x2d, (byte) 0x49, (byte) 0x4e, (byte) 0x46, (byte) 0x2f, + (byte) 0x4d, (byte) 0x41, (byte) 0x4e, (byte) 0x49, (byte) 0x46, + (byte) 0x45, (byte) 0x53, (byte) 0x54, (byte) 0x2e, (byte) 0x4d, + (byte) 0x46, (byte) 0xf3, (byte) 0x4d, (byte) 0xcc, (byte) 0xcb, + (byte) 0x4c, (byte) 0x4b, (byte) 0x2d, (byte) 0x2e, (byte) 0xd1, + (byte) 0xd, (byte) 0x4b, (byte) 0x2d, (byte) 0x2a, (byte) 0xce, + (byte) 0xcc, (byte) 0xcf, (byte) 0xb3, (byte) 0x52, (byte) 0x30, + (byte) 0xd4, (byte) 0x33, (byte) 0xe0, (byte) 0xe5, (byte) 0x72, + (byte) 0x2e, (byte) 0x4a, (byte) 0x4d, (byte) 0x2c, (byte) 0x49, + (byte) 0x4d, (byte) 0xd1, (byte) 0x75, (byte) 0xaa, (byte) 0x4, + (byte) 0xa, (byte) 0x98, (byte) 0xe8, (byte) 0x19, (byte) 0xe8, + (byte) 0x19, (byte) 0x2a, (byte) 0x68, (byte) 0xf8, (byte) 0x17, + (byte) 0x25, (byte) 0x26, (byte) 0xe7, (byte) 0xa4, (byte) 0x2a, + (byte) 0x38, (byte) 0xe7, (byte) 0x17, (byte) 0x15, (byte) 0xe4, + (byte) 0x17, (byte) 0x25, (byte) 0x96, (byte) 0x0, (byte) 0x15, + (byte) 0x6b, (byte) 0xf2, (byte) 0x72, (byte) 0xf1, (byte) 0x72, + (byte) 0x1, (byte) 0x0, (byte) 0x50, (byte) 0x4b, (byte) 0x7, + (byte) 0x8, (byte) 0xf4, (byte) 0x59, (byte) 0xdc, (byte) 0xa6, + (byte) 0x42, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x42, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x50, (byte) 0x4b, + (byte) 0x3, (byte) 0x4, (byte) 0x14, (byte) 0x0, (byte) 0x8, + (byte) 0x8, (byte) 0x8, (byte) 0x0, (byte) 0xe3, (byte) 0x34, + (byte) 0x62, (byte) 0x54, (byte) 0x0, (byte) 0x0, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x9, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x48, (byte) 0x65, + (byte) 0x6c, (byte) 0x6c, (byte) 0x6f, (byte) 0x2e, (byte) 0x74, + (byte) 0x78, (byte) 0x74, (byte) 0xf3, (byte) 0x48, (byte) 0xcd, + (byte) 0xc9, (byte) 0xc9, (byte) 0x57, (byte) 0x28, (byte) 0xcf, + (byte) 0x2f, (byte) 0xca, (byte) 0x49, (byte) 0xe1, (byte) 0x2, + (byte) 0x0, (byte) 0x50, (byte) 0x4b, (byte) 0x7, (byte) 0x8, + (byte) 0xd5, (byte) 0xe0, (byte) 0x39, (byte) 0xb7, (byte) 0xe, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0xc, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0x50, (byte) 0x4b, (byte) 0x3, + (byte) 0x4, (byte) 0x14, (byte) 0x0, (byte) 0x8, (byte) 0x8, + (byte) 0x8, (byte) 0x0, (byte) 0x98, (byte) 0x68, (byte) 0x62, + (byte) 0x54, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0xa, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0x54, (byte) 0x65, (byte) 0x6e, + (byte) 0x6e, (byte) 0x69, (byte) 0x73, (byte) 0x2e, (byte) 0x74, + (byte) 0x78, (byte) 0x74, (byte) 0x73, (byte) 0xf2, (byte) 0xb, + (byte) 0x50, (byte) 0x8, (byte) 0x48, (byte) 0x2c, (byte) 0xca, + (byte) 0x4c, (byte) 0x4a, (byte) 0x2c, (byte) 0x56, (byte) 0xf0, + (byte) 0x2f, (byte) 0x48, (byte) 0xcd, (byte) 0x53, (byte) 0xc8, + (byte) 0x2c, (byte) 0x56, (byte) 0x48, (byte) 0x54, (byte) 0x48, + (byte) 0x2b, (byte) 0xcd, (byte) 0x53, (byte) 0x8, (byte) 0x49, + (byte) 0xcd, (byte) 0xcb, (byte) 0x3, (byte) 0x72, (byte) 0x42, + (byte) 0xf2, (byte) 0x4b, (byte) 0x8b, (byte) 0xf2, (byte) 0x12, + (byte) 0x73, (byte) 0x53, (byte) 0xf3, (byte) 0x4a, (byte) 0x14, + (byte) 0x4a, (byte) 0xf2, (byte) 0x15, (byte) 0xca, (byte) 0x13, + (byte) 0x4b, (byte) 0x92, (byte) 0x33, (byte) 0xb8, (byte) 0x0, + (byte) 0x50, (byte) 0x4b, (byte) 0x7, (byte) 0x8, (byte) 0xaa, + (byte) 0xad, (byte) 0x14, (byte) 0xd, (byte) 0x35, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0x35, (byte) 0x0, (byte) 0x0, + (byte) 0x0, (byte) 0x50, (byte) 0x4b, (byte) 0x3, (byte) 0x4, + (byte) 0x14, (byte) 0x0, (byte) 0x8, (byte) 0x8, (byte) 0x8, + (byte) 0x0, (byte) 0xf1, (byte) 0x79, (byte) 0x62, (byte) 0x54, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0xe, (byte) 0x0, (byte) 0x0, + (byte) 0x0, (byte) 0x42, (byte) 0x72, (byte) 0x75, (byte) 0x63, + (byte) 0x65, (byte) 0x57, (byte) 0x61, (byte) 0x79, (byte) 0x6e, + (byte) 0x65, (byte) 0x2e, (byte) 0x74, (byte) 0x78, (byte) 0x74, + (byte) 0xf3, (byte) 0x54, (byte) 0x48, (byte) 0xcc, (byte) 0x55, + (byte) 0x70, (byte) 0x4a, (byte) 0x2c, (byte) 0xc9, (byte) 0x4d, + (byte) 0xcc, (byte) 0xe3, (byte) 0x2, (byte) 0x0, (byte) 0x50, + (byte) 0x4b, (byte) 0x7, (byte) 0x8, (byte) 0x6c, (byte) 0x70, + (byte) 0x60, (byte) 0xbd, (byte) 0xe, (byte) 0x0, (byte) 0x0, + (byte) 0x0, (byte) 0xc, (byte) 0x0, (byte) 0x0, (byte) 0x0, + (byte) 0x50, (byte) 0x4b, (byte) 0x1, (byte) 0x2, (byte) 0x14, + (byte) 0x0, (byte) 0x14, (byte) 0x0, (byte) 0x8, (byte) 0x8, + (byte) 0x8, (byte) 0x0, (byte) 0xec, (byte) 0x34, (byte) 0x62, + (byte) 0x54, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, + (byte) 0x2, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x9, (byte) 0x0, + (byte) 0x4, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, + (byte) 0x0, (byte) 0x4d, (byte) 0x45, (byte) 0x54, (byte) 0x41, + (byte) 0x2d, (byte) 0x49, (byte) 0x4e, (byte) 0x46, (byte) 0x2f, + (byte) 0xfe, (byte) 0xca, (byte) 0x0, (byte) 0x0, (byte) 0x50, + (byte) 0x4b, (byte) 0x1, (byte) 0x2, (byte) 0x14, (byte) 0x0, + (byte) 0x14, (byte) 0x0, (byte) 0x8, (byte) 0x8, (byte) 0x8, + (byte) 0x0, (byte) 0xec, (byte) 0x34, (byte) 0x62, (byte) 0x54, + (byte) 0xf4, (byte) 0x59, (byte) 0xdc, (byte) 0xa6, (byte) 0x42, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x42, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0x14, (byte) 0x0, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, + (byte) 0x0, (byte) 0x3d, (byte) 0x0, (byte) 0x0, (byte) 0x0, + (byte) 0x4d, (byte) 0x45, (byte) 0x54, (byte) 0x41, (byte) 0x2d, + (byte) 0x49, (byte) 0x4e, (byte) 0x46, (byte) 0x2f, (byte) 0x4d, + (byte) 0x41, (byte) 0x4e, (byte) 0x49, (byte) 0x46, (byte) 0x45, + (byte) 0x53, (byte) 0x54, (byte) 0x2e, (byte) 0x4d, (byte) 0x46, + (byte) 0x50, (byte) 0x4b, (byte) 0x1, (byte) 0x2, (byte) 0x14, + (byte) 0x0, (byte) 0x14, (byte) 0x0, (byte) 0x8, (byte) 0x8, + (byte) 0x8, (byte) 0x0, (byte) 0xe3, (byte) 0x34, (byte) 0x62, + (byte) 0x54, (byte) 0xd5, (byte) 0xe0, (byte) 0x39, (byte) 0xb7, + (byte) 0xe, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0xc, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x9, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0xc1, (byte) 0x0, (byte) 0x0, + (byte) 0x0, (byte) 0x48, (byte) 0x65, (byte) 0x6c, (byte) 0x6c, + (byte) 0x6f, (byte) 0x2e, (byte) 0x74, (byte) 0x78, (byte) 0x74, + (byte) 0x50, (byte) 0x4b, (byte) 0x1, (byte) 0x2, (byte) 0x14, + (byte) 0x0, (byte) 0x14, (byte) 0x0, (byte) 0x8, (byte) 0x8, + (byte) 0x8, (byte) 0x0, (byte) 0x98, (byte) 0x68, (byte) 0x62, + (byte) 0x54, (byte) 0xaa, (byte) 0xad, (byte) 0x14, (byte) 0xd, + (byte) 0x35, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x35, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0xa, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0x6, (byte) 0x1, (byte) 0x0, + (byte) 0x0, (byte) 0x54, (byte) 0x65, (byte) 0x6e, (byte) 0x6e, + (byte) 0x69, (byte) 0x73, (byte) 0x2e, (byte) 0x74, (byte) 0x78, + (byte) 0x74, (byte) 0x50, (byte) 0x4b, (byte) 0x1, (byte) 0x2, + (byte) 0x14, (byte) 0x0, (byte) 0x14, (byte) 0x0, (byte) 0x8, + (byte) 0x8, (byte) 0x8, (byte) 0x0, (byte) 0xf1, (byte) 0x79, + (byte) 0x62, (byte) 0x54, (byte) 0x6c, (byte) 0x70, (byte) 0x60, + (byte) 0xbd, (byte) 0xe, (byte) 0x0, (byte) 0x0, (byte) 0x0, + (byte) 0xc, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0xe, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x73, (byte) 0x1, + (byte) 0x0, (byte) 0x0, (byte) 0x42, (byte) 0x72, (byte) 0x75, + (byte) 0x63, (byte) 0x65, (byte) 0x57, (byte) 0x61, (byte) 0x79, + (byte) 0x6e, (byte) 0x65, (byte) 0x2e, (byte) 0x74, (byte) 0x78, + (byte) 0x74, (byte) 0x50, (byte) 0x4b, (byte) 0x5, (byte) 0x6, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x5, + (byte) 0x0, (byte) 0x5, (byte) 0x0, (byte) 0x28, (byte) 0x1, + (byte) 0x0, (byte) 0x0, (byte) 0xbd, (byte) 0x1, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0x0, + }; + + /** + * Create Jar files used by the tests. + * The {@code byte} array {@code VALID_ZIP_WITH_NO_COMMENTS_BYTES} is written + * to disk to create the jar file: {@code Valid-CEN-Comment-Length.jar}. + * + * The jar file {@code InValid-CEN-Comment-Length.jar} is created by copying + * the {@code byte} array {@code VALID_ZIP_WITH_NO_COMMENTS_BYTES} and modifying + * the CEN file header comment length entry for "META-INF/MANIFEST.MF" so that + * new comment length will forward the CEN to a subsequent CEN file header + * entry. + * + * For {@code InValid-CEN-Comment-Length.jar}, the comment length is changed + * from {@code 0x0} to the {@code 0x37}. + * + * @throws IOException If an error occurs + */ + @BeforeTest + public void setup() throws IOException { + Files.deleteIfExists(VALID_CEN_COMMENT_LENGTH_JAR); + Files.deleteIfExists(INVALID_CEN_COMMENT_LENGTH_JAR); + // Create the valid jar + Files.write(VALID_CEN_COMMENT_LENGTH_JAR, VALID_ZIP_WITH_NO_COMMENTS_BYTES); + // Now create an invalid jar + byte[] invalid_bytes = Arrays.copyOf(VALID_ZIP_WITH_NO_COMMENTS_BYTES, + VALID_ZIP_WITH_NO_COMMENTS_BYTES.length); + // Change CEN file Header comment length so that the length will + // result in the offset pointing to a subsequent CEN file header + // resulting in an invalid comment + invalid_bytes[536] = 55; + Files.write(INVALID_CEN_COMMENT_LENGTH_JAR, invalid_bytes); + } + + /** + * Clean up after the test run + * + * @throws IOException If an error occurs + */ + @AfterTest + public static void cleanup() throws IOException { + Files.deleteIfExists(VALID_CEN_COMMENT_LENGTH_JAR); + Files.deleteIfExists(INVALID_CEN_COMMENT_LENGTH_JAR); + } + + /** + * Validate that the original(valid) Jar file can be opened by {@code ZipFile} + * and the expected Zip entry can be found + * @throws IOException If an error occurs + */ + @Test + public static void ZipFileValidCommentLengthTest() throws IOException { + try (ZipFile jf = new ZipFile(VALID_CEN_COMMENT_LENGTH_JAR.toFile())) { + ZipEntry ze = jf.getEntry(META_INF_MANIFEST_MF); + assertNotNull(ze); + assertEquals(ze.getName(), META_INF_MANIFEST_MF); + } + } + + /** + * Validate that the original(valid) Jar file can be opened by {@code JarFile} + * and the expected Zip entry can be found + * @throws IOException If an error occurs + */ + @Test + public static void JarFileValidCommentLengthTest() throws IOException { + try (JarFile jf = new JarFile(VALID_CEN_COMMENT_LENGTH_JAR.toFile())) { + ZipEntry ze = jf.getEntry(META_INF_MANIFEST_MF); + assertNotNull(ze); + assertEquals(ze.getName(), META_INF_MANIFEST_MF); + } + } + + /** + * Validate that a ZipException is thrown when the CEN file header comment + * length is non-zero and the CEN entry does not contain a comment when + * the Jar file is opened by {@code ZipFile} + */ + @Test + public static void ZipFileInValidCommentLengthTest() { + var ex= expectThrows(ZipException.class, + () -> new ZipFile(INVALID_CEN_COMMENT_LENGTH_JAR.toFile())); + assertEquals(ex.getMessage(), INVALID_CEN_HEADER_BAD_ENTRY_NAME_OR_COMMENT); + } + + /** + * Validate that a ZipException is thrown when the CEN file header comment + * length is non-zero and the CEN entry does not contain a comment when + * the Jar file is opened by {@code JarFile} + */ + @Test + public static void JarFileInValidCommentLengthTest() { + var ex= expectThrows(ZipException.class, + () -> new JarFile(INVALID_CEN_COMMENT_LENGTH_JAR.toFile())); + assertEquals(ex.getMessage(), INVALID_CEN_HEADER_BAD_ENTRY_NAME_OR_COMMENT); + } +} diff --git a/test/jdk/java/util/zip/ZipFile/TestTooManyEntries.java b/test/jdk/java/util/zip/ZipFile/TestTooManyEntries.java new file mode 100644 index 0000000000000000000000000000000000000000..07ed760c1b76af5917b6bcd4c9aae693dcd0b927 --- /dev/null +++ b/test/jdk/java/util/zip/ZipFile/TestTooManyEntries.java @@ -0,0 +1,89 @@ +/* + * 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. + */ + +/* @test + * @bug 8272746 + * @summary ZipFile can't open big file (NegativeArraySizeException) + * @requires (sun.arch.data.model == "64" & os.maxMemory > 8g) + * @run testng/manual/othervm -Xmx8g TestTooManyEntries + */ + +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; + +import java.io.File; +import java.io.BufferedOutputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.zip.ZipEntry; +import java.util.zip.ZipException; +import java.util.zip.ZipFile; +import java.util.zip.ZipOutputStream; +import java.util.UUID; + +import static org.testng.Assert.assertThrows; + +public class TestTooManyEntries { + // Number of directories in the zip file + private static final int DIR_COUNT = 25000; + // Number of entries per directory + private static final int ENTRIES_IN_DIR = 1000; + + // Zip file to create for testing + private File hugeZipFile; + + /** + * Create a zip file and add entries that exceed the CEN limit. + * @throws IOException if an error occurs creating the ZIP File + */ + @BeforeTest + public void setup() throws IOException { + hugeZipFile = File.createTempFile("hugeZip", ".zip", new File(".")); + hugeZipFile.deleteOnExit(); + long startTime = System.currentTimeMillis(); + try (ZipOutputStream zip = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(hugeZipFile)))) { + for (int dirN = 0; dirN < DIR_COUNT; dirN++) { + String dirName = UUID.randomUUID() + "/"; + for (int fileN = 0; fileN < ENTRIES_IN_DIR; fileN++) { + ZipEntry entry = new ZipEntry(dirName + UUID.randomUUID()); + zip.putNextEntry(entry); + zip.closeEntry(); // all files are empty + } + if ((dirN + 1) % 1000 == 0) { + System.out.printf("%s / %s of entries written, file size is %sMb (%ss)%n", + (dirN + 1) * ENTRIES_IN_DIR, DIR_COUNT * ENTRIES_IN_DIR, hugeZipFile.length() / 1024 / 1024, + (System.currentTimeMillis() - startTime) / 1000); + } + } + } + } + + /** + * Validates that the ZipException is thrown when the ZipFile class + * is initialized with a zip file whose entries exceed the CEN limit. + */ + @Test + public void test() { + assertThrows(ZipException.class, () -> new ZipFile(hugeZipFile)); + } +} diff --git a/test/jdk/java/util/zip/ZipOutputStream/EmptyComment.java b/test/jdk/java/util/zip/ZipOutputStream/EmptyComment.java new file mode 100644 index 0000000000000000000000000000000000000000..0f52844f3f6b0724b73ebc6a88a9e3edaef260f8 --- /dev/null +++ b/test/jdk/java/util/zip/ZipOutputStream/EmptyComment.java @@ -0,0 +1,111 @@ +/* + * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.ByteArrayOutputStream; +import java.util.function.Consumer; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; +import java.util.zip.ZipOutputStream; + +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +import static org.testng.Assert.assertThrows; + +/** + * @test + * @bug 8277087 + * @summary Verifies various use cases when the zip comment should be empty + * @run testng EmptyComment + */ +public final class EmptyComment { + + @DataProvider() + Object[][] longLengths() { + return new Object[][]{{0xFFFF + 1}, {0xFFFF + 2}, {0xFFFF * 2}}; + } + + /** + * Overflow, the text is too long to be stored as a comment. + */ + @Test(dataProvider = "longLengths") + void testOverflow(int length) throws Exception { + test(zos -> assertThrows(IllegalArgumentException.class, () -> { + zos.setComment("X".repeat(length)); + })); + } + + /** + * Simple cases where the comment is set to the empty text. + */ + @Test + void testSimpleCases() throws Exception { + test(zos -> {/* do nothing */}); + test(zos -> zos.setComment(null)); + test(zos -> zos.setComment("")); + test(zos -> { + zos.setComment(""); + zos.setComment(null); + }); + test(zos -> { + zos.setComment(null); + zos.setComment(""); + }); + test(zos -> { + zos.setComment("Comment"); + zos.setComment(null); + }); + test(zos -> { + zos.setComment("Comment"); + zos.setComment(""); + }); + } + + private static void test(Consumer<ZipOutputStream> test) throws Exception { + try (ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ZipOutputStream zos = new ZipOutputStream(baos)) { + + test.accept(zos); + + zos.putNextEntry(new ZipEntry("x")); + zos.finish(); + + byte[] data = baos.toByteArray(); + + if (data.length > 0xFFFF) { // just in case + throw new RuntimeException("data is too big: " + data.length); + } + int pk = data.length - ZipFile.ENDHDR; + if (data[pk] != 'P' || data[pk + 1] != 'K') { + throw new RuntimeException("PK is not found"); + } + // Since the comment is empty this will be two last bytes + int pos = data.length - ZipFile.ENDHDR + ZipFile.ENDCOM; + + int len = (data[pos] & 0xFF) + ((data[pos + 1] & 0xFF) << 8); + if (len != 0) { + throw new RuntimeException("zip comment is not empty: " + len); + } + } + } +} diff --git a/test/jdk/javax/accessibility/4715503/AccessibleJTableCellBoundingRectangleTest.java b/test/jdk/javax/accessibility/4715503/AccessibleJTableCellBoundingRectangleTest.java new file mode 100644 index 0000000000000000000000000000000000000000..716925a51e66dd79abde28407048032746beffdc --- /dev/null +++ b/test/jdk/javax/accessibility/4715503/AccessibleJTableCellBoundingRectangleTest.java @@ -0,0 +1,91 @@ +/* + * 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. + */ + +/* + * @test + * @key headful + * @bug 4715503 + * @summary AccessibleTable cannot get the Bounding Rectangle of Table Header Cells. + * @run main AccessibleJTableCellBoundingRectangleTest + */ + +import java.awt.Rectangle; +import java.awt.Robot; + +import javax.swing.JFrame; +import javax.swing.JTable; +import javax.swing.SwingUtilities; + +public class AccessibleJTableCellBoundingRectangleTest { + private static JTable jTable; + private static JFrame jFrame; + + private static Object[][] rowData = { { "01", "02", "03", "04", "05" }, + { "11", "12", "13", "14", "15" }, { "21", "22", "23", "24", "25" }, + { "31", "32", "33", "34", "35" }, { "41", "42", "43", "44", "45" } }; + + private static Object[] colNames = { "1", "2", "3", "4", "5" }; + + private static void doTest() throws Exception { + try { + SwingUtilities.invokeAndWait(() -> createGUI()); + Robot robot = new Robot(); + robot.setAutoDelay(500); + robot.waitForIdle(); + + for (int i = 0; i <= colNames.length - 1; i++) { + try { + Rectangle bounds = + jTable.getTableHeader().getAccessibleContext().getAccessibleChild(i) + .getAccessibleContext().getAccessibleComponent().getBounds(); + + if (bounds != null) { + System.out.println("Column " + i + " Bounds: " + bounds); + } else { + throw new RuntimeException( + "Bounding Rectangles getting bounding rectangle for table header cells is null"); + } + } catch (Exception e) { + throw new RuntimeException("Bounding Rectangles getting bounding rectangle for " + + "table header cells threw an exception:\n" + e); + } + } + } finally { + SwingUtilities.invokeAndWait(() -> jFrame.dispose()); + } + } + + private static void createGUI() { + jTable = new JTable(rowData, colNames); + jFrame = new JFrame(); + jFrame.setBounds(100, 100, 300, 300); + jFrame.getContentPane().add(jTable); + jFrame.setVisible(true); + } + + public static void main(String args[]) throws Exception { + doTest(); + System.out.println("Test Passed"); + } +} + diff --git a/test/jdk/javax/accessibility/JTable/BooleanRendererHasAccessibleActionTest.java b/test/jdk/javax/accessibility/JTable/BooleanRendererHasAccessibleActionTest.java new file mode 100644 index 0000000000000000000000000000000000000000..79f16e3c3660489e729af80d0c859e1e237ec008 --- /dev/null +++ b/test/jdk/javax/accessibility/JTable/BooleanRendererHasAccessibleActionTest.java @@ -0,0 +1,192 @@ +/* + * 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. + */ + +/* @test + @bug 8277922 + @key headful + @summary TableCellRenderer of JTable cell with Boolean data should not + support any AccessibleAction. + */ + +import java.awt.AWTException; +import java.awt.BorderLayout; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Robot; +import java.lang.reflect.InvocationTargetException; +import javax.accessibility.Accessible; +import javax.accessibility.AccessibleAction; +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleTable; +import javax.swing.JFrame; +import javax.swing.JScrollPane; +import javax.swing.JTable; +import javax.swing.SwingUtilities; +import javax.swing.table.DefaultTableModel; +import javax.swing.table.TableCellRenderer; + +public class BooleanRendererHasAccessibleActionTest { + private volatile JFrame frame; + private volatile JTable table; + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException, AWTException { + final BooleanRendererHasAccessibleActionTest test = + new BooleanRendererHasAccessibleActionTest(); + + try { + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + test.createGUI(); + } + }); + Robot robot = new Robot(); + robot.waitForIdle(); + + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + test.runTest(); + } + }); + } finally { + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + test.dispose(); + } + }); + } + } + + private void createGUI() { + frame = new JFrame("BooleanRendererHasAccessibleActionTest"); + frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + Container content = frame.getContentPane(); + content.setLayout(new BorderLayout()); + + String[] tblColNames = {"Column 1", "Column 2", "Column 3"}; + Object[][] tblData = { + {Boolean.TRUE, "Text 1", Boolean.FALSE}, + {Boolean.FALSE, "Text 2", Boolean.TRUE} + }; + final DefaultTableModel tblModel = new DefaultTableModel( + tblData, tblColNames) { + @Override + public Class<?> getColumnClass(int column) { + return getValueAt(0, column).getClass(); + } + }; + table = new JTable(tblModel); + table.setPreferredScrollableViewportSize(new Dimension(400, 100)); + + JScrollPane tblScroller = new JScrollPane(table); + tblScroller.setHorizontalScrollBarPolicy( + JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); + tblScroller.setVerticalScrollBarPolicy( + JScrollPane.VERTICAL_SCROLLBAR_ALWAYS + ); + content.add(tblScroller, BorderLayout.CENTER); + + frame.pack(); + frame.setVisible(true); + } + + private void dispose() { + if (frame != null) { + frame.dispose(); + frame = null; + } + } + + private void runTest() { + if (table == null) { + throw new RuntimeException("'table' should not be null"); + } + + testAccessibleActionInCellRenderer(0, 0, true); + testAccessibleActionInCellRenderer(1, 0, true); + testAccessibleActionInCellRenderer(0, 2, true); + testAccessibleActionInCellRenderer(1, 2, true); + + testAccessibleActionInCell(0, 0, true); + testAccessibleActionInCell(1, 0, true); + testAccessibleActionInCell(0, 2, true); + testAccessibleActionInCell(1, 2, true); + + System.out.println("Test passed."); + } + + private void testAccessibleActionInCellRenderer(int row, int column, + boolean shouldBeNull) { + System.out.println(String.format( + "testAccessibleActionInCellRenderer():" + + " row='%d', column='%d', shouldBeNull='%b'", + row, column, shouldBeNull)); + + TableCellRenderer cellRenderer = table.getCellRenderer(row, column); + if (!(cellRenderer instanceof Accessible)) { + throw new RuntimeException("'cellRenderer' is not Accessible"); + } + + AccessibleContext cellRendererAc = + ((Accessible) cellRenderer).getAccessibleContext(); + if (cellRendererAc == null) { + throw new RuntimeException("'cellRendererAc' should not be null"); + } + + AccessibleAction cellRendererAa = cellRendererAc.getAccessibleAction(); + if ((shouldBeNull && (cellRendererAa != null)) || + (!shouldBeNull && (cellRendererAa == null))) { + throw new RuntimeException( + "Test failed. 'cellRendererAa' is not as should be"); + } + } + + private void testAccessibleActionInCell(int row, int column, + boolean shouldBeNull) { + System.out.println(String.format("testAccessibleActionInCell():" + + " row='%d', column='%d', shouldBeNull='%b'", + row, column, shouldBeNull)); + + AccessibleContext tblAc = table.getAccessibleContext(); + AccessibleTable accessibleTbl = tblAc.getAccessibleTable(); + if (accessibleTbl == null) { + throw new RuntimeException("'accessibleTbl' should not be null"); + } + + Accessible cellAccessible = accessibleTbl.getAccessibleAt(row, column); + AccessibleContext cellAc = cellAccessible.getAccessibleContext(); + if (cellAc == null) { + throw new RuntimeException("'cellAc' should not be null"); + } + + AccessibleAction cellAa = cellAc.getAccessibleAction(); + if ((shouldBeNull && (cellAa != null)) || + (!shouldBeNull && (cellAa == null))) { + throw new RuntimeException( + "Test failed. 'cellAa' is not as should be"); + } + } +} diff --git a/test/jdk/javax/accessibility/manual/ButtonDemo.html b/test/jdk/javax/accessibility/manual/ButtonDemo.html new file mode 100644 index 0000000000000000000000000000000000000000..c815fad3a9e2233ecc1791ea0ad87b00d9c7b4f6 --- /dev/null +++ b/test/jdk/javax/accessibility/manual/ButtonDemo.html @@ -0,0 +1,80 @@ +<!-- +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. +--> +<!DOCTYPE html> +<html> +<head> + <style> + table, th, td { + border: 1px solid black; +} + + </style> +</head> +<body> + + +<table> + <tr> + <th style="background-color:rgb(204,255,255); font-weight:bold; width:5%;">S.No</th> + <th style="background-color:rgb(204,255,255); font-weight:bold; width:25%;">Test</th> + <th style="background-color:rgb(204,255,255); font-weight:bold; width:75%;">Scenario</th> + </tr> + <tr> + <td>1</td> + <td>Button Demo</td> + <td> + <ol> + <li> Tab until the Button Demo icon <img src="./resource/rbtn.png"> has focus. Press 'space' to + choose.<br> + <li> Tab until the "Button Demo" tab has focus. Press 'space'. Press 'tab'.<br> + <li> Use the arrow keys to navigate between "Buttons", "Radio Buttons", and "Check Boxes".<br> + <li> Tab to enter the demo pane. Tab & Shift-Tab to move between each button.<br> + <li> Press 'space' to trigger (i.e. "press") a button.<br> + <li> Repeat steps 1 through 5 for the <b>Radio Button</b> & <b>Check Boxes</b> tabs.<br> + </ol> + </td> + </td> + </tr> + <tr> + <td style="Width:100%;" colspan="3"><b>Expected Result</b></td> + </tr> + <tr> + <td style="Width:100%;" colspan="3"> + <ol> + <li>Verify that as you navigate, the focus is shown, e.g.</li> + <img src="./resource/btn.png"> + <li>As you press 'space' to trigger each button, verify that you see each button visually depress. + e.g.: + </li> + <img src="./resource/dep.png"> + </ol> + </td> + </tr> + <tr> + <td style="Width:100%;" colspan="3"><b>Note: actual component appearence may vary depending on look and + feel.</b></td> + </tr> +</table> +</body> +</html> + diff --git a/test/jdk/javax/accessibility/manual/ButtonDemo.java b/test/jdk/javax/accessibility/manual/ButtonDemo.java new file mode 100644 index 0000000000000000000000000000000000000000..0c352ebf906b587f4987cacefa8d2f152e8f21e4 --- /dev/null +++ b/test/jdk/javax/accessibility/manual/ButtonDemo.java @@ -0,0 +1,28 @@ +/* + * 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. + */ +/* +@test +@key headful +@summary manual test for accessibility button demo +@run main/manual SwingSetTest ButtonDemo +*/ diff --git a/test/jdk/javax/accessibility/manual/ComboBoxDemo.html b/test/jdk/javax/accessibility/manual/ComboBoxDemo.html new file mode 100644 index 0000000000000000000000000000000000000000..aeb6e8f681a87294c95cfb6781c9ffbbd72417b5 --- /dev/null +++ b/test/jdk/javax/accessibility/manual/ComboBoxDemo.html @@ -0,0 +1,75 @@ +<!-- +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. +--> +<!DOCTYPE html> +<html> +<head> + <style> + table, th, td { + border: 1px solid black; +} + + </style> +</head> +<body> + + +<table> + <tr> + <th style="background-color:rgb(204,255,255); font-weight:bold; width:5%;">S.No</th> + <th style="background-color:rgb(204,255,255); font-weight:bold; width:25%;">Test</th> + <th style="background-color:rgb(204,255,255); font-weight:bold; width:75%;">Scenario</th> + </tr> + <tr> + <td>1</td> + <td>ComboBox Demo</td> + <td> + <ol> + <li> Tab until ComboBox icon<img src="./resource/cmb.png"> has focus. Press 'Space' to choose.</li> + <li>Tab until the "ComboBox Demo" tab has focus. Press 'space'. Press 'tab'.</li> + <li> Use Tab and Shift-Tab to move between the four ComboBox widgets. + <li>Use the space and down arrow keys to bring up the drop-down list.</li> + <li> Use the up and down arrows to navigate up and down the list.</li> + <li>Use the 'space' key to make a the selection.</li> + <li> Repeat 4,5 but hit Esc key to cancel the drop-down.</li> + </ol> + </td> + </td> + </tr> + <tr> + <td style="Width:100%;" colspan="3"><b>Expected Result</b></td> + </tr> + <tr> + <td style="Width:100%;" colspan="3"> + <ol> + <li>Verify that space and down arrow bring up the drop-down list.</li> + <img src="./resource/list.png"> + <li>Verify that up and down arrows move up and down the list.</li> + <li>Verify that 'space' makes the selection (the drop-down list should collapse).</li> + </ol> + </td> + </tr> +</table> +</body> +</html> + + \ No newline at end of file diff --git a/test/jdk/javax/accessibility/manual/ComboBoxDemo.java b/test/jdk/javax/accessibility/manual/ComboBoxDemo.java new file mode 100644 index 0000000000000000000000000000000000000000..0522d3caa77f650c919e0847832915c52c14ce50 --- /dev/null +++ b/test/jdk/javax/accessibility/manual/ComboBoxDemo.java @@ -0,0 +1,28 @@ +/* + * 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. + */ +/* +@test +@key headful +@summary manual test for accessibility button demo +@run main/manual SwingSetTest ComboBoxDemo +*/ diff --git a/test/jdk/javax/accessibility/manual/DemoSelection.html b/test/jdk/javax/accessibility/manual/DemoSelection.html new file mode 100644 index 0000000000000000000000000000000000000000..7f9a28b05a9cd1241953d2c253eb9a7d08343ce1 --- /dev/null +++ b/test/jdk/javax/accessibility/manual/DemoSelection.html @@ -0,0 +1,66 @@ +<!-- +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. +--> +<!DOCTYPE html> +<html> +<head> + <style> + table, th, td { + border: 1px solid black; +} + + </style> +</head> +<body> + + +<table> + <tr> + <th style="background-color:rgb(204,255,255); font-weight:bold; width:5%;">S.No</th> + <th style="background-color:rgb(204,255,255); font-weight:bold; width:25%;">Test</th> + <th style="background-color:rgb(204,255,255); font-weight:bold; width:75%;">Scenario</th> + </tr> + <tr> + <td>1</td> + <td>Demo Selection</td> + <td>Move between demos with 'tab' and 'shift-tab', and left and right arrows. Type 'space' to activate a demo. + <img src="./resource/dms.png"> + </td> + </td> + </tr> + <tr> + <td style="Width:100%;" colspan="3"><b>Expected Result</b></td> + </tr> + <tr> + <td style="Width:100%;" colspan="3"> + Verify that there is visible focus as you tab (or arrow) between demo icons. Typing 'space' should change + the selected demo. + </td> + </tr> + <tr> + <td style="Width:100%;" colspan="3"><b>Note: actual component appearence may vary depending on look and + feel.</b></td> + </tr> +</table> +</body> +</html> + diff --git a/test/jdk/javax/accessibility/manual/DemoSelection.java b/test/jdk/javax/accessibility/manual/DemoSelection.java new file mode 100644 index 0000000000000000000000000000000000000000..f3e31aa88ecf6c93a1616edc51113868040b3291 --- /dev/null +++ b/test/jdk/javax/accessibility/manual/DemoSelection.java @@ -0,0 +1,28 @@ +/* + * 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. + */ +/* +@test +@key headful +@summary manual test for accessibility button demo +@run main/manual SwingSetTest DemoSelection +*/ diff --git a/test/jdk/javax/accessibility/manual/OptionPaneDemo.html b/test/jdk/javax/accessibility/manual/OptionPaneDemo.html new file mode 100644 index 0000000000000000000000000000000000000000..23693043b5d21b7911f8c99060358e731e95ff26 --- /dev/null +++ b/test/jdk/javax/accessibility/manual/OptionPaneDemo.html @@ -0,0 +1,78 @@ +<!-- +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. +--> +<!DOCTYPE html> +<html> +<head> + <style> + table, th, td { + border: 1px solid black; +} + + </style> +</head> +<body> + + +<table> + <tr> + <th style="background-color:rgb(204,255,255); font-weight:bold; width:5%;">S.No</th> + <th style="background-color:rgb(204,255,255); font-weight:bold; width:25%;">Test</th> + <th style="background-color:rgb(204,255,255); font-weight:bold; width:75%;">Scenario</th> + </tr> + <tr> + <td>1</td> + <td>OptionPane Demo</td> + <td> + <ol> + <li>Tab until the OptionPane icon <img src="./resource/op.png">has focus. Press 'space' to choose. + <li>Tab until the "OptionPane Demo" tab has focus. Press 'space'. Press 'tab'. The 'Show Input Dialog' + button should have focus. + <li>Press 'space'. An Input dialog should pop up. Type some text, and hit return. The dialog should + change to a Message dialog with text saying "That was a pretty good movie!" Press return. + <li>Bring up the dialog again (space). Press 'esc' and confirm that the dialog goes away without the + Message from above. + <li>Press Tab to move down through the buttons, and select "Component Dialog Example" (press space). A + dialog should appear. Tab to ensure that you can navigate through all the components:<br> + a. Textfield<br> + b. ComboBox<br> + c. All 4 buttons: "Cancel", "Probably", "Maybe", "No", "Yes".<br> + d. Press 'esc' to cancel the dialog.<br> + </ol> + </td> + </tr> + <tr> + <td style="Width:100%;" colspan="3"> + <b>Expected Result</b> + </td> + </tr> + <tr> + <td style="Width:100%;" colspan="3"> + When a popup window is created, focus must be on the popup window; when the window is closed, focus must + return to the previous focus point. + </td> + </tr> +</table> +</body> +</html> + + \ No newline at end of file diff --git a/test/jdk/javax/accessibility/manual/OptionPaneDemo.java b/test/jdk/javax/accessibility/manual/OptionPaneDemo.java new file mode 100644 index 0000000000000000000000000000000000000000..42d3bade5297d2c094ff7084b4abc39e3ef3a361 --- /dev/null +++ b/test/jdk/javax/accessibility/manual/OptionPaneDemo.java @@ -0,0 +1,29 @@ +/* + * 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. + */ +/* +@test +@key headful +@summary manual test for accessibility button demo +@run main/manual SwingSetTest OptionPaneDemo +*/ + diff --git a/test/jdk/javax/accessibility/manual/README.md b/test/jdk/javax/accessibility/manual/README.md new file mode 100644 index 0000000000000000000000000000000000000000..3b96515c6326f34dac82c0521cca8cfd74f3ce07 --- /dev/null +++ b/test/jdk/javax/accessibility/manual/README.md @@ -0,0 +1,79 @@ +<!-- +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. +--> + +# Manual javax.accessibility test suite + +## Configure environment + +### Swing Set 2 + +Prepare an appropriate version of Swing Set 2 from JDK demos. + +### Acessibility frameworks + +Testing can be performed without an accessibility framework or with one of these frameworks: + +1. Windows + 1. JAWS + 2. NVDA +2. Mac OS X + 1. Voice over + +## Executing a test run + +* Start the required accessibility framework, if necessary +* Swing Set 2 jar default location is +<code><tested jdk>/demo/jfc/SwingSet2/SwingSet2.jar</code> +* To override Swing Set 2 jar use <code>SWINGSET2_JAR</code> environment variable: + + + jtreg ... -e:SWINGSET2_JAR=<file location> -m .../javax/accessibility/manual/... + + +## Performing tests + +When a test a started, a UI appears consisting of two frames: test framework frame and Swing Set 2 frame. Test framework +frame will contain a name of the test in the title and detailed instructions. + +1. Follow the test instructions +2. If everything goes as expected + 1. Push "Pass" + 2. UI for this test closes +3. If something goes not accordding to the instructions: + 1. Push "Fail" + 2. A screenshot is taken automatically + 3. Describe the problem + 4. Retake the screenshot, if necessary + 1. Interract with the Swing Set 2 UI to make it showing the failure. Hit "Retake screenshot" + 2. If to demonstrate the failure the UI need to be in a state which prevents using test framework UI, such as model dialogs need to be opened or menu expanded + 1. Enter delay (in seconds) + 2. Push "Retake screenshot" + 3. Prepare the UI + 4. Wait for the screenshot to be retaken + 5. Push "Fail" button again + 6. Screenshot and the description are saved for further analysis + 7. Test UI closes + +**Wasning: Do not close any window directly, all windows will be closed once the test is finished as passed or failed.** + +**Note: Keyboard navigation is supported throughout the test framework UI.** diff --git a/test/jdk/javax/accessibility/manual/SwingSetTest.java b/test/jdk/javax/accessibility/manual/SwingSetTest.java new file mode 100644 index 0000000000000000000000000000000000000000..33bc2ff430a50f34d977ef39a8d73ac0a39feade --- /dev/null +++ b/test/jdk/javax/accessibility/manual/SwingSetTest.java @@ -0,0 +1,59 @@ +/** + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + */ + +import lib.ManualTestFrame; +import lib.TestResult; + +import javax.imageio.ImageIO; +import java.io.File; +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.net.URL; +import java.net.URLClassLoader; +import java.nio.file.Files; +import java.util.function.Supplier; + +import static java.io.File.separator; + +public class SwingSetTest { + + public static void main(String[] args) throws IOException, InterruptedException, + ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException { + System.out.println("test image " + System.getenv("TEST_IMAGE_DIR")); + Supplier<TestResult> resultSupplier = ManualTestFrame.showUI(args[0], + "Wait for SwingSet2 to load, follow the instructions, select pass or fail. " + + "Do not close windows manually.", + SwingSetTest.class.getResource(args[0] + ".html")); + String swingSetJar = System.getenv("SWINGSET2_JAR"); + if (swingSetJar == null) { + swingSetJar = "file://" + System.getProperty("java.home") + + separator + "demo" + + separator + "jfc" + + separator + "SwingSet2" + + separator + "SwingSet2.jar"; + } + System.out.println("Loading SwingSet2 from " + swingSetJar); + ClassLoader ss = new URLClassLoader(new URL[]{new URL(swingSetJar)}); + ss.loadClass("SwingSet2").getMethod("main", String[].class).invoke(null, (Object)new String[0]); + //this will block until user decision to pass or fail the test + TestResult result = resultSupplier.get(); + if (result != null) { + System.err.println("Failure reason: \n" + result.getFailureDescription()); + if (result.getScreenCapture() != null) { + File screenDump = new File(System.getProperty("test.classes") + separator + args[0] + ".png"); + System.err.println("Saving screen image to " + screenDump.getAbsolutePath()); + ImageIO.write(result.getScreenCapture(), "png", screenDump); + } + Throwable e = result.getException(); + if (e != null) { + throw new RuntimeException(e); + } else { + if (!result.getStatus()) throw new RuntimeException("Test failed!"); + } + } else { + throw new RuntimeException("No result returned!"); + } + } +} \ No newline at end of file diff --git a/test/jdk/javax/accessibility/manual/TableDemo.html b/test/jdk/javax/accessibility/manual/TableDemo.html new file mode 100644 index 0000000000000000000000000000000000000000..1f0b821b410c0e4979dd7dba1b735399d1e3fafa --- /dev/null +++ b/test/jdk/javax/accessibility/manual/TableDemo.html @@ -0,0 +1,81 @@ +<!-- +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. +--> +<!DOCTYPE html> +<html> +<head> + <style> + table, th, td { + border: 1px solid black; +} + + </style> +</head> +<body> + + +<table> + <tr> + <th style="background-color:rgb(204,255,255); font-weight:bold; width:5%;">S.No</th> + <th style="background-color:rgb(204,255,255); font-weight:bold; width:25%;">Test</th> + <th style="background-color:rgb(204,255,255); font-weight:bold; width:75%;">Scenario</th> + </tr> + <tr> + <td>1</td> + <td>Table Demo (tests table navigation, as well as textfield input)</td> + <td> + <ol> + <li>Tab until the Table icon <img src="./resource/tbld.png"> has focus. Press 'space' to choose. + <li>Tab until the "Table Demo" tab has focus. Press 'space'. Press 'tab'. "Reordering allowed" should + have focus. + <li>Tab to the Printing/Header textfield. Verify that you can type in some text. + <li>Continue tabbing until focus moves to the table. The table should show focus. + <li>Press the down arrow. "Mike Albers" should have focus. + <li>Use the right and left arrow keys to navigate between cells. + <li>Set focus to a text cell (e.g. someone's first name). Press space to edit. Type some text. Hit + 'enter' and verify the text has been changed. After editing a text cell and hitting 'enter', the + focus could remain on the current cell or go to the next line. + <li>Press the 'Page Up' and 'Page Down' keys (if available on your keyboard); verify that the Table + scrolls up and down, page by page. + <ol><br> + <img src="./resource/tbl.png"> + </td> + </tr> + <tr> + <td style="Width:100%;" colspan="3"> + <b>Expected Result</b> + </td> + </tr> + <tr> + <td style="Width:100%;" colspan="3"> + See above test description. + </td> + </tr> + <tr> + <td style="Width:100%;" colspan="3"><b>Note: actual component appearence may vary depending on look and + feel.</b></td> + </tr> +</table> +</body> +</html> + + \ No newline at end of file diff --git a/test/jdk/javax/accessibility/manual/TableDemo.java b/test/jdk/javax/accessibility/manual/TableDemo.java new file mode 100644 index 0000000000000000000000000000000000000000..ff56bcec4e8dcff58c69d4a67d369d2f0f3a5499 --- /dev/null +++ b/test/jdk/javax/accessibility/manual/TableDemo.java @@ -0,0 +1,28 @@ +/* + * 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. + */ +/* +@test +@key headful +@summary manual test for accessibility button demo +@run main/manual SwingSetTest TableDemo +*/ diff --git a/test/jdk/javax/accessibility/manual/TabsDemo.html b/test/jdk/javax/accessibility/manual/TabsDemo.html new file mode 100644 index 0000000000000000000000000000000000000000..06a055d0229374d4a4a0c6bf8fd99a4b354366a6 --- /dev/null +++ b/test/jdk/javax/accessibility/manual/TabsDemo.html @@ -0,0 +1,67 @@ +<!-- +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. +--> +<!DOCTYPE html> +<html> +<head> + <style> + table, th, td { + border: 1px solid black; +} + + </style> +</head> +<body> + + +<table> + <tr> + <th style="background-color:rgb(204,255,255); font-weight:bold; width:5%;">S.No</th> + <th style="background-color:rgb(204,255,255); font-weight:bold; width:25%;">Test</th> + <th style="background-color:rgb(204,255,255); font-weight:bold; width:75%;">Scenario</th> + </tr> + <tr> + <td>1</td> + <td>Tabs within demos (tests table navigation, as well as textfield input)</td> + <td> + Continue tabbing to enter a demo's pane. When the top demo tabs have focus, the left and right arrow keys + move between tabs.<br> + <img src="./resource/ifm.png"> + </td> + </tr> + <tr> + <td style="Width:100%;" colspan="3"> + <b>Expected Result</b> + </td> + </tr> + <tr> + <td style="Width:100%;" colspan="3"> + Verify that the selected tab changes, e.g. between 'Internal Frame Demo' and "Source Code'. + </td> + </tr> + <tr> + <td style="Width:100%;" colspan="3"><b>Note: actual component appearence may vary depending on look and + feel.</b></td> + </tr> +</table> +</body> +</html> \ No newline at end of file diff --git a/test/jdk/javax/accessibility/manual/TabsDemo.java b/test/jdk/javax/accessibility/manual/TabsDemo.java new file mode 100644 index 0000000000000000000000000000000000000000..35fad6abf825fd504b6cf4d5bc520a6566d77d9c --- /dev/null +++ b/test/jdk/javax/accessibility/manual/TabsDemo.java @@ -0,0 +1,29 @@ +/* + * 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. + */ +/* +@test +@key headful +@summary manual test for accessibility button demo +@run main/manual SwingSetTest TabsDemo +*/ + diff --git a/test/jdk/javax/accessibility/manual/TreeDemo.html b/test/jdk/javax/accessibility/manual/TreeDemo.html new file mode 100644 index 0000000000000000000000000000000000000000..c418b3e54048850e42dfc79bac00cb9336dd51a5 --- /dev/null +++ b/test/jdk/javax/accessibility/manual/TreeDemo.html @@ -0,0 +1,65 @@ +<!-- +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. +--> +<!DOCTYPE html> +<html> +<head> + <style> + table, th, td { + border: 1px solid black; +} + + </style> +</head> +<body> + + +<table> + <tr> + <th style="background-color:rgb(204,255,255); font-weight:bold; width:5%;">S.No</th> + <th style="background-color:rgb(204,255,255); font-weight:bold; width:25%;">Test</th> + <th style="background-color:rgb(204,255,255); font-weight:bold; width:75%;">Scenario</th> + </tr> + <tr> + <td>1</td> + <td>Tree Demo</td> + <td> + Tab until the Tree icon <img src="./resource/tree.png"> has focus. Press 'space' to choose. + Tab until the "Tree Demo" tab has focus. Press 'space'. Press 'tab'. Press the down arrow. "Music" should + have focus. + Navigate up and down the tree using the up and down arrow keys. + Expand and collapse folders using the right and left arrow keys. + </td> + </tr> + <tr> + <td style="Width:100%;" colspan="3"> + <b>Expected Result</b> + </td> + </tr> + <tr> + <td style="Width:100%;" colspan="3"> + See above test description. + </td> + </tr> +</table> +</body> +</html> \ No newline at end of file diff --git a/test/jdk/javax/accessibility/manual/TreeDemo.java b/test/jdk/javax/accessibility/manual/TreeDemo.java new file mode 100644 index 0000000000000000000000000000000000000000..1f38f9e9f73b8e10261e27cc59252c9d03ba7927 --- /dev/null +++ b/test/jdk/javax/accessibility/manual/TreeDemo.java @@ -0,0 +1,28 @@ +/* + * 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. + */ +/* +@test +@key headful +@summary manual test for accessibility button demo +@run main/manual SwingSetTest TreeDemo +*/ diff --git a/test/jdk/javax/accessibility/manual/lib/DescriptionPane.java b/test/jdk/javax/accessibility/manual/lib/DescriptionPane.java new file mode 100644 index 0000000000000000000000000000000000000000..bdd0e23e78896a556d9b80fb3792d01d0bc4f9f3 --- /dev/null +++ b/test/jdk/javax/accessibility/manual/lib/DescriptionPane.java @@ -0,0 +1,53 @@ +/* + * 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. + */ +package lib; + +import javax.swing.JEditorPane; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.io.IOException; +import java.net.URL; + +/** + * Displays instructions provided through a URL. + */ +class DescriptionPane extends JPanel { + + DescriptionPane(URL instructions) throws IOException { + JEditorPane editorPane = new JEditorPane(); + editorPane.setFocusable(false); + editorPane.setContentType("text/html"); + editorPane.setPage(instructions); + editorPane.setEditable(false); + + JScrollPane esp = new JScrollPane(editorPane); + esp.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); + esp.setPreferredSize(new Dimension(250, 350)); + + setLayout(new BorderLayout()); + + add(esp); + } +} diff --git a/test/jdk/javax/accessibility/manual/lib/FailureReasonPane.java b/test/jdk/javax/accessibility/manual/lib/FailureReasonPane.java new file mode 100644 index 0000000000000000000000000000000000000000..b1cfc0d32cbba7e87280237a0efdf9894f87873b --- /dev/null +++ b/test/jdk/javax/accessibility/manual/lib/FailureReasonPane.java @@ -0,0 +1,73 @@ +/* + * 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. + */ +package lib; + +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JTextArea; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import java.awt.BorderLayout; +import java.util.function.Consumer; + +import static java.awt.BorderLayout.CENTER; +import static java.awt.BorderLayout.NORTH; + +/** + * Allows to enter reason for the test failure. + */ +class FailureReasonPane extends JPanel { + + private final JTextArea text; + + FailureReasonPane(Consumer<String> listener) { + setLayout(new BorderLayout(10, 10)); + add(new JLabel("Failure reason:"), NORTH); + text = new JTextArea(3, 10); + text.getDocument().addDocumentListener(new DocumentListener() { + @Override + public void insertUpdate(DocumentEvent e) { + listener.accept(text.getText()); + } + + @Override + public void removeUpdate(DocumentEvent e) { + listener.accept(text.getText()); + } + + @Override + public void changedUpdate(DocumentEvent e) { + listener.accept(text.getText()); + } + }); + add(text, CENTER); + } + + public String getReason() { + return text.getText(); + } + + public void requestFocus() { + text.requestFocus(); + } +} diff --git a/test/jdk/javax/accessibility/manual/lib/ManualTestFrame.java b/test/jdk/javax/accessibility/manual/lib/ManualTestFrame.java new file mode 100644 index 0000000000000000000000000000000000000000..57117790b57980e25e4bf653c76eb3f0e13cb654 --- /dev/null +++ b/test/jdk/javax/accessibility/manual/lib/ManualTestFrame.java @@ -0,0 +1,159 @@ +/* + * 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. + */ +package lib; + +import javax.swing.BorderFactory; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JSplitPane; +import javax.swing.JTextArea; +import javax.swing.border.BevelBorder; +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.GridLayout; +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.net.URL; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Consumer; +import java.util.function.Supplier; + +import static java.awt.BorderLayout.*; +import static javax.swing.SwingUtilities.invokeAndWait; + +/** + * A frame which can be used to display manual test descriptions as well as, in case of a failure, + * enter failure reason and capture the screen. + */ +public class ManualTestFrame extends JFrame { + + private boolean alreadyFailed = false; + + private ManualTestFrame(String testName, String headerText, URL instructions, Consumer<TestResult> listener) throws IOException { + + super(testName); + + JLabel statusLabel = new JLabel("Follow test description, select \"Pass\" or \"Fail\""); + statusLabel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); + + JSplitPane split = new JSplitPane(JSplitPane.VERTICAL_SPLIT); + PassFailPane[] passFail = new PassFailPane[1]; + FailureReasonPane failureReason = new FailureReasonPane(reason -> { + passFail[0].setFailEnabled(!reason.isEmpty()); + }); + ScreenImagePane image = new ScreenImagePane(e -> { + listener.accept(new TestResult(e)); + dispose(); + }); + + JPanel failureInfoPane = new JPanel(); + failureInfoPane.setLayout(new GridLayout(1, 2, 10, 10)); + failureInfoPane.add(failureReason); + failureInfoPane.add(image); + failureInfoPane.setVisible(false); + + JPanel main = new JPanel(); + main.setLayout(new BorderLayout(10, 10)); + DescriptionPane description = new DescriptionPane(instructions); + main.add(description, CENTER); + passFail[0] = new PassFailPane((status) -> { + if (status) { + listener.accept(new TestResult()); + dispose(); + } else { + if (!alreadyFailed) { + alreadyFailed = true; + split.setDividerLocation(.5); + failureInfoPane.setVisible(true); + pack(); + image.capture(); + failureReason.requestFocus(); + statusLabel.setText("Enter failure reason, re-take screenshot, push \"Fail\""); + } else { + listener.accept(new TestResult(failureReason.getReason(), image.getImage())); + dispose(); + } + } + }); + main.add(passFail[0], SOUTH); + + split.setLeftComponent(main); + split.setRightComponent(failureInfoPane); + split.setDividerLocation(1.); + + getContentPane().setLayout(new BorderLayout()); + + if (headerText != null) { + JTextArea warningLabel = new JTextArea(headerText); + warningLabel.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED)); + warningLabel.setEditable(false); + warningLabel.setFocusable(false); + getContentPane().add(warningLabel, NORTH); + } + + getContentPane().add(statusLabel, SOUTH); + getContentPane().add(split, CENTER); + + setPreferredSize(new Dimension(800, 600)); + pack(); + setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); + setVisible(true); + } + + /** + * Show a test control frame which allows a user to either pass or fail the test. + * @param testName + * @param headerText + * @param instructions + * @return Returning supplier blocks till the test is passed or failed by the user. + * @throws InterruptedException + * @throws InvocationTargetException + */ + public static Supplier<TestResult> showUI(String testName, String headerText, URL instructions) + throws InterruptedException, InvocationTargetException { + AtomicReference<TestResult> resultContainer = new AtomicReference<>(); + CountDownLatch latch = new CountDownLatch(1); + invokeAndWait(() -> { + try { + new ManualTestFrame(testName, headerText, instructions, (status) -> { + resultContainer.set(status); + latch.countDown(); + }); + } catch (IOException e) { + resultContainer.set(new TestResult(e)); + e.printStackTrace(); + } + }); + return () -> { + try { + latch.await(); + } catch (InterruptedException e) { + return new TestResult(e); + } + return resultContainer.get(); + }; + } + +} diff --git a/test/jdk/javax/accessibility/manual/lib/PassFailPane.java b/test/jdk/javax/accessibility/manual/lib/PassFailPane.java new file mode 100644 index 0000000000000000000000000000000000000000..0cc99353ef199819d77c0e950e3195f723b4da8c --- /dev/null +++ b/test/jdk/javax/accessibility/manual/lib/PassFailPane.java @@ -0,0 +1,74 @@ +/* + * 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. + */ +package lib; + +import javax.swing.JButton; +import javax.swing.JPanel; +import java.awt.HeadlessException; +import java.io.IOException; +import java.util.function.Consumer; + +/** + * Allows to chose if a test fails or passes. It is a multi-use component. A chosen answer can be confirmed later + * upon providing additional information. + */ +class PassFailPane extends JPanel { + private final Consumer<Boolean> listener; + + private final JButton btnPass = new JButton("Pass"); + private final JButton btnFail = new JButton("Fail"); + + /** + * @param listener gets called with true (pass) or false (fail). + * @throws HeadlessException + */ + PassFailPane(Consumer<Boolean> listener) + throws HeadlessException, IOException { + this.listener = listener; + + add(btnPass); + add(btnFail); + + btnPass.requestFocus(); + + btnPass.addActionListener((e) -> { + disableButtons(); + listener.accept(true); + }); + + btnFail.addActionListener((e) -> { + disableButtons(); + listener.accept(false); + }); + } + + private void disableButtons() { + btnFail.setEnabled(false); + btnPass.setEnabled(false); + } + + public void setFailEnabled(boolean enabled) { + btnFail.setEnabled(enabled); + } + +} diff --git a/test/jdk/javax/accessibility/manual/lib/ScreenImagePane.java b/test/jdk/javax/accessibility/manual/lib/ScreenImagePane.java new file mode 100644 index 0000000000000000000000000000000000000000..1d35b740dad9c49cc168e89021d94b015cbd9bd1 --- /dev/null +++ b/test/jdk/javax/accessibility/manual/lib/ScreenImagePane.java @@ -0,0 +1,124 @@ +/* + * 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. + */ +package lib; + +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JFormattedTextField; +import javax.swing.JLabel; +import javax.swing.JPanel; +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.Image; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.Toolkit; +import java.awt.image.BufferedImage; +import java.text.NumberFormat; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Consumer; + +import static java.awt.BorderLayout.CENTER; +import static java.awt.BorderLayout.NORTH; +import static java.lang.String.format; +import static javax.swing.SwingUtilities.invokeAndWait; +import static javax.swing.SwingUtilities.invokeLater; + +/** + * Allows ti take screenshot, possible with a delay to preapare the UI. + */ +class ScreenImagePane extends JPanel { + private final JPanel imagePanel; + private final JLabel imageLabel; + private final AtomicReference<BufferedImage> image = new AtomicReference<>(); + private final Rectangle screenRect; + private final JFormattedTextField delayField; + private final Consumer<Throwable> exceptionHandler; + + /** + * + * @param handler should an exception appear on other threads + */ + ScreenImagePane(Consumer<Throwable> handler) { + exceptionHandler = handler; + Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); + screenRect = new Rectangle(0, 0, screenSize.width, screenSize.height); + JPanel controls = new JPanel(); + delayField = new JFormattedTextField(NumberFormat.getNumberInstance()); + delayField.setText("0"); + delayField.setColumns(3); + JButton capture = new JButton("Retake screenshot"); + controls.add(new JLabel("in ")); + controls.add(delayField); + controls.add(new JLabel(" seconds ")); + controls.add(capture); + capture.addActionListener((e) -> capture()); + imagePanel = new JPanel(); + imageLabel = new JLabel(); + imagePanel.add(imageLabel); + + setLayout(new BorderLayout()); + add(controls, NORTH); + add(imagePanel, CENTER); + } + + public void capture() { + new Thread(() -> { + try { + int delay = Integer.parseInt(delayField.getText()); + invokeAndWait(() -> imageLabel.setIcon(null)); + while (delay > 0) { + String message = format("Retaking screenshot in %d seconds", delay); + invokeLater(() -> imageLabel.setText(message)); + delay--; + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + } + } + BufferedImage image = new Robot().createScreenCapture(screenRect); + ScreenImagePane.this.image.set(image); + int newWidth = imagePanel.getWidth(); + int newHeight = imagePanel.getHeight(); + float xratio = (float) newWidth / (float) image.getWidth(); + float yratio = (float) newHeight / (float) image.getHeight(); + if (xratio < yratio) { + newHeight = (int) (image.getHeight() * xratio); + } else { + newWidth = (int) (image.getWidth() * yratio); + } + Image scaled = image.getScaledInstance(newWidth, newHeight, Image.SCALE_FAST); + invokeAndWait(() -> { + imageLabel.setText(null); + imageLabel.setIcon(new ImageIcon(scaled)); + }); + } catch (Throwable e) { + exceptionHandler.accept(e); + } + }).start(); + } + + public BufferedImage getImage() { + return image.get(); + } +} diff --git a/test/jdk/javax/accessibility/manual/lib/TestResult.java b/test/jdk/javax/accessibility/manual/lib/TestResult.java new file mode 100644 index 0000000000000000000000000000000000000000..42e5c72a49e6e85aeb6dcfcf88f8f40f0cd37315 --- /dev/null +++ b/test/jdk/javax/accessibility/manual/lib/TestResult.java @@ -0,0 +1,79 @@ +/* + * 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. + */ +package lib; + +import java.awt.image.BufferedImage; + +public final class TestResult { + private final boolean status; + private final String failureDescription; + private final BufferedImage screenCapture; + private final Throwable exception; + + /** + * Failed due to an exception. + */ + public TestResult(Throwable exception) { + status = false; + failureDescription = exception.getMessage(); + screenCapture = null; + this.exception = exception; + } + + /** + * Failed by used decision. + */ + public TestResult(String description, BufferedImage capture) { + status = false; + failureDescription = description; + screenCapture = capture; + exception = null; + } + + /** + * Passed. + */ + public TestResult() { + this.status = true; + failureDescription = null; + screenCapture = null; + exception = null; + } + + /** + * true - pass, false - no pass. + */ + public boolean getStatus() { + return status; + } + + public String getFailureDescription() { + return failureDescription; + } + + public BufferedImage getScreenCapture() { + return screenCapture; + } + + public Throwable getException() {return exception;} +} diff --git a/test/jdk/javax/accessibility/manual/resource/btn.png b/test/jdk/javax/accessibility/manual/resource/btn.png new file mode 100644 index 0000000000000000000000000000000000000000..0523db95125a121f77cbc2918a38b5937bb9a368 Binary files /dev/null and b/test/jdk/javax/accessibility/manual/resource/btn.png differ diff --git a/test/jdk/javax/accessibility/manual/resource/cmb.png b/test/jdk/javax/accessibility/manual/resource/cmb.png new file mode 100644 index 0000000000000000000000000000000000000000..02d989660c06976f12e982ad726f3a82d3014981 Binary files /dev/null and b/test/jdk/javax/accessibility/manual/resource/cmb.png differ diff --git a/test/jdk/javax/accessibility/manual/resource/dep.png b/test/jdk/javax/accessibility/manual/resource/dep.png new file mode 100644 index 0000000000000000000000000000000000000000..89d15e2b5dbde4c621ed8b6611f89f1a87ab7648 Binary files /dev/null and b/test/jdk/javax/accessibility/manual/resource/dep.png differ diff --git a/test/jdk/javax/accessibility/manual/resource/dms.png b/test/jdk/javax/accessibility/manual/resource/dms.png new file mode 100644 index 0000000000000000000000000000000000000000..63809383c5e7aa7a1595b4ed2dbaaeea3567d7bd Binary files /dev/null and b/test/jdk/javax/accessibility/manual/resource/dms.png differ diff --git a/test/jdk/javax/accessibility/manual/resource/hc.jpg b/test/jdk/javax/accessibility/manual/resource/hc.jpg new file mode 100644 index 0000000000000000000000000000000000000000..773ca040dcb8439dcbb23ea6dc42dcd30d0154d1 Binary files /dev/null and b/test/jdk/javax/accessibility/manual/resource/hc.jpg differ diff --git a/test/jdk/javax/accessibility/manual/resource/if.png b/test/jdk/javax/accessibility/manual/resource/if.png new file mode 100644 index 0000000000000000000000000000000000000000..3c978d685eb325db0809048d882fe2c9c1b75888 Binary files /dev/null and b/test/jdk/javax/accessibility/manual/resource/if.png differ diff --git a/test/jdk/javax/accessibility/manual/resource/ifm.png b/test/jdk/javax/accessibility/manual/resource/ifm.png new file mode 100644 index 0000000000000000000000000000000000000000..483ae7c76e33c94c56cd0914a59e75926274d598 Binary files /dev/null and b/test/jdk/javax/accessibility/manual/resource/ifm.png differ diff --git a/test/jdk/javax/accessibility/manual/resource/list.png b/test/jdk/javax/accessibility/manual/resource/list.png new file mode 100644 index 0000000000000000000000000000000000000000..1e026e83b2b2111de4c1018a5bad977c4d2e520d Binary files /dev/null and b/test/jdk/javax/accessibility/manual/resource/list.png differ diff --git a/test/jdk/javax/accessibility/manual/resource/op.png b/test/jdk/javax/accessibility/manual/resource/op.png new file mode 100644 index 0000000000000000000000000000000000000000..82ff0253d6eb107b46e81ceab768ac3f2e13f882 Binary files /dev/null and b/test/jdk/javax/accessibility/manual/resource/op.png differ diff --git a/test/jdk/javax/accessibility/manual/resource/rbtn.png b/test/jdk/javax/accessibility/manual/resource/rbtn.png new file mode 100644 index 0000000000000000000000000000000000000000..807f29b58c14b69d2140ddbf5346d414cdd9fabb Binary files /dev/null and b/test/jdk/javax/accessibility/manual/resource/rbtn.png differ diff --git a/test/jdk/javax/accessibility/manual/resource/tbl.png b/test/jdk/javax/accessibility/manual/resource/tbl.png new file mode 100644 index 0000000000000000000000000000000000000000..f2eef6a2fb47cbb6be93d50926e32faa2a9db97a Binary files /dev/null and b/test/jdk/javax/accessibility/manual/resource/tbl.png differ diff --git a/test/jdk/javax/accessibility/manual/resource/tbld.png b/test/jdk/javax/accessibility/manual/resource/tbld.png new file mode 100644 index 0000000000000000000000000000000000000000..8e2a3b77d1a2387f57054bed52f0d663ad278ac0 Binary files /dev/null and b/test/jdk/javax/accessibility/manual/resource/tbld.png differ diff --git a/test/jdk/javax/accessibility/manual/resource/tree.png b/test/jdk/javax/accessibility/manual/resource/tree.png new file mode 100644 index 0000000000000000000000000000000000000000..9e7f1daa06466e7dd30e675ef5a9d95defb0606c Binary files /dev/null and b/test/jdk/javax/accessibility/manual/resource/tree.png differ diff --git a/test/jdk/javax/imageio/plugins/wbmp/WBMPStreamTruncateTest.java b/test/jdk/javax/imageio/plugins/wbmp/WBMPStreamTruncateTest.java new file mode 100644 index 0000000000000000000000000000000000000000..36b8d4a72e0fd992d08fad2d0008109e7f8494a8 --- /dev/null +++ b/test/jdk/javax/imageio/plugins/wbmp/WBMPStreamTruncateTest.java @@ -0,0 +1,118 @@ +/* + * 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. + */ + +/** + * @test + * @bug 8266435 + * @summary Test verifies that WBMPImageReader doesnt truncate + * the stream and reads it fully + * @run main WBMPStreamTruncateTest + */ + +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.RandomAccessFile; +import javax.imageio.ImageIO; +import javax.imageio.stream.ImageInputStreamImpl; + +public class WBMPStreamTruncateTest +{ + static final int LIMIT = 100; + static final int width = 100; + 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(); + g.setBackground(Color.WHITE); + g.fillRect(0, 0, srcImage.getWidth(), srcImage.getHeight()); + g.dispose(); + // create WBMP image + File imageFile = File. + createTempFile("test", ".wbmp", new File(filePath)); + imageFile.deleteOnExit(); + ImageIO.write(srcImage, "wbmp", imageFile); + BufferedImage testImg = + ImageIO.read(new LimitedImageInputStream(imageFile, LIMIT)); + for (int x = 0; x < testImg.getWidth(); ++x) + { + for (int y = 0; y < testImg.getHeight(); ++y) + { + int i1 = testImg.getRGB(x, y); + int i2 = srcImage.getRGB(x, y); + if (i1 != i2) + { + throw new RuntimeException("Stream is decoded only until " + + "the limit specified"); + } + } + } + } + + static class LimitedImageInputStream extends ImageInputStreamImpl + { + private final RandomAccessFile raf; + private final int limit; + + public LimitedImageInputStream(File file, int limit) + throws FileNotFoundException + { + raf = new RandomAccessFile(file, "r"); + this.limit = limit; + } + + @Override + public int read() throws IOException + { + return raf.read(); + } + + @Override + public int read(byte[] b, int off, int len) throws IOException + { + return raf.read(b, off, Math.min(limit, len)); + } + + @Override + public void close() throws IOException + { + super.close(); + raf.close(); + } + + @Override + public void seek(long pos) throws IOException + { + super.seek(pos); + raf.seek(pos); + } + } +} diff --git a/test/jdk/javax/management/remote/mandatory/connection/DefaultAgentFilterTest.java b/test/jdk/javax/management/remote/mandatory/connection/DefaultAgentFilterTest.java index 1c688b2252431401f00419d0079c4f8930b26311..41028039b7835e59021a86264bbdb232324b8ca2 100644 --- a/test/jdk/javax/management/remote/mandatory/connection/DefaultAgentFilterTest.java +++ b/test/jdk/javax/management/remote/mandatory/connection/DefaultAgentFilterTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -43,6 +43,7 @@ import java.rmi.registry.LocateRegistry; import java.rmi.registry.Registry; import java.util.ArrayList; import java.util.Arrays; +import java.util.concurrent.TimeUnit; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -110,17 +111,21 @@ public class DefaultAgentFilterTest { try { AtomicBoolean error = new AtomicBoolean(false); AtomicBoolean bindError = new AtomicBoolean(false); + // The predicate below tries to recognise failures. On a port clash, it sees e.g. + // Error: Exception thrown by the agent : java.rmi.server.ExportException: Port already in use: 46481; nested exception is: + // ...and will never see "main enter" from TestApp. p = ProcessTools.startProcess( TEST_APP_NAME + "{" + name + "}", pb, (line) -> { - if (line.toLowerCase().contains("exception") - || line.toLowerCase().contains("error")) { + if (line.contains("Exception")) { error.set(true); + bindError.set(line.toLowerCase().contains("port already in use")); + return true; // On Exception, app will never start } - bindError.set(line.toLowerCase().contains("bindexception")); - return true; - }); + return line.contains("main enter"); + }, + 60, TimeUnit.SECONDS); if (bindError.get()) { throw new BindException("Process could not be started"); } else if (error.get()) { @@ -164,9 +169,25 @@ public class DefaultAgentFilterTest { } private static final String TEST_APP_NAME = "TestApp"; + private static final int FREE_PORT_ATTEMPTS = 10; private static void testDefaultAgent(String propertyFile) throws Exception { - int port = Utils.getFreePort(); + for (int i = 1; i <= FREE_PORT_ATTEMPTS; i++) { + int port = Utils.getFreePort(); + System.out.println("Attempting testDefaultAgent(" + propertyFile + ") with port: " + port); + try { + testDefaultAgent(propertyFile, port); + break; // return succesfully + } catch (BindException b) { + // Retry with new port. Throw if last iteration: + if (i == FREE_PORT_ATTEMPTS) { + throw(b); + } + } + } + } + + private static void testDefaultAgent(String propertyFile, int port) throws Exception { String propFile = System.getProperty("test.src") + File.separator + propertyFile; List<String> pbArgs = new ArrayList<>(Arrays.asList( "-cp", @@ -235,53 +256,32 @@ public class DefaultAgentFilterTest { public static void main(String[] args) throws Exception { System.out.println("---" + DefaultAgentFilterTest.class.getName() + "-main: starting ..."); - boolean retry = false; - do { - try { - // filter DefaultAgentFilterTest$MyTestObject - testDefaultAgent("mgmt1.properties"); - System.out.println("----\tTest FAILED !!"); - throw new RuntimeException("---" + DefaultAgentFilterTest.class.getName() + " - No exception reported"); - } catch (Exception ex) { - if (ex instanceof InvocationTargetException) { - if (ex.getCause() instanceof BindException - || ex.getCause() instanceof java.rmi.ConnectException) { - System.out.println("Failed to allocate ports. Retrying ..."); - retry = true; - } - } else if (ex instanceof InvalidClassException) { - System.out.println("----\tTest PASSED !!"); - } else if (ex instanceof UnmarshalException - && ((UnmarshalException) ex).getCause() instanceof InvalidClassException) { - System.out.println("----\tTest PASSED !!"); - } else { - System.out.println(ex); - System.out.println("----\tTest FAILED !!"); - throw ex; - } - } - } while (retry); - retry = false; - do { - try { - // filter non-existent class - testDefaultAgent("mgmt2.properties"); + try { + // filter DefaultAgentFilterTest$MyTestObject + testDefaultAgent("mgmt1.properties"); + System.out.println("----\tTest FAILED !!"); + throw new RuntimeException("---" + DefaultAgentFilterTest.class.getName() + " - No exception reported"); + } catch (Exception ex) { + if (ex instanceof InvalidClassException) { System.out.println("----\tTest PASSED !!"); - } catch (Exception ex) { - if (ex instanceof InvocationTargetException) { - if (ex.getCause() instanceof BindException - || ex.getCause() instanceof java.rmi.ConnectException) { - System.out.println("Failed to allocate ports. Retrying ..."); - retry = true; - } - } else { - System.out.println(ex); - System.out.println("----\tTest FAILED !!"); - throw ex; - } + } else if (ex instanceof UnmarshalException + && ((UnmarshalException) ex).getCause() instanceof InvalidClassException) { + System.out.println("----\tTest PASSED !!"); + } else { + System.out.println(ex); + System.out.println("----\tTest FAILED !!"); + throw ex; } - } while (retry); - + } + try { + // filter non-existent class + testDefaultAgent("mgmt2.properties"); + System.out.println("----\tTest PASSED !!"); + } catch (Exception ex) { + System.out.println(ex); + System.out.println("----\tTest FAILED !!"); + throw ex; + } System.out.println("---" + DefaultAgentFilterTest.class.getName() + "-main: finished ..."); } diff --git a/test/jdk/javax/net/ssl/ALPN/SSLServerSocketAlpnTest.java b/test/jdk/javax/net/ssl/ALPN/SSLServerSocketAlpnTest.java index a9373ed09f9da803f4d522b283bdcc1db5524715..2752649dc74e41e4e4fb48dd5a1430a92c113fce 100644 --- a/test/jdk/javax/net/ssl/ALPN/SSLServerSocketAlpnTest.java +++ b/test/jdk/javax/net/ssl/ALPN/SSLServerSocketAlpnTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -484,7 +484,7 @@ public class SSLServerSocketAlpnTest { */ if ((local != null) && (remote != null)) { // If both failed, return the curthread's exception. - local.initCause(remote); + local.addSuppressed(remote); exception = local; } else if (local != null) { exception = local; diff --git a/test/jdk/javax/net/ssl/ALPN/SSLSocketAlpnTest.java b/test/jdk/javax/net/ssl/ALPN/SSLSocketAlpnTest.java index ef72474f4177e35dce3844b79ce2ed8b6f3f9151..172eecd46089b7c035b2d8baa21efa1468a80d4d 100644 --- a/test/jdk/javax/net/ssl/ALPN/SSLSocketAlpnTest.java +++ b/test/jdk/javax/net/ssl/ALPN/SSLSocketAlpnTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -480,7 +480,7 @@ public class SSLSocketAlpnTest { */ if ((local != null) && (remote != null)) { // If both failed, return the curthread's exception. - local.initCause(remote); + local.addSuppressed(remote); exception = local; } else if (local != null) { exception = local; diff --git a/test/jdk/javax/net/ssl/DTLS/CipherSuite.java b/test/jdk/javax/net/ssl/DTLS/CipherSuite.java index 773fb08d3176e05f8ddb247e4fb619e19d7648e1..1c4b1c6d84f0269d1410e2e3c4308e969ff6cd5f 100644 --- a/test/jdk/javax/net/ssl/DTLS/CipherSuite.java +++ b/test/jdk/javax/net/ssl/DTLS/CipherSuite.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -51,6 +51,9 @@ import javax.net.ssl.SSLEngine; import java.security.Security; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; /** * Test common DTLS cipher suites. @@ -59,10 +62,12 @@ public class CipherSuite extends DTLSOverDatagram { // use the specific cipher suite volatile static String cipherSuite; + private static boolean reenable; public static void main(String[] args) throws Exception { if (args.length > 1 && "re-enable".equals(args[1])) { Security.setProperty("jdk.tls.disabledAlgorithms", ""); + reenable = true; } cipherSuite = args[0]; @@ -77,6 +82,11 @@ public class CipherSuite extends DTLSOverDatagram { if (isClient) { engine.setEnabledCipherSuites(new String[]{cipherSuite}); + } else if (reenable) { + List<String> cipherSuites = + new ArrayList(Arrays.asList(engine.getEnabledCipherSuites())); + cipherSuites.add(cipherSuite); + engine.setEnabledCipherSuites(cipherSuites.toArray(new String[0])); } return engine; diff --git a/test/jdk/javax/net/ssl/DTLS/DTLSSignatureSchemes.java b/test/jdk/javax/net/ssl/DTLS/DTLSSignatureSchemes.java new file mode 100644 index 0000000000000000000000000000000000000000..5dd897b1bd7d1b8afd35acf58c8224256ee7a983 --- /dev/null +++ b/test/jdk/javax/net/ssl/DTLS/DTLSSignatureSchemes.java @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2022 THL A29 Limited, a Tencent company. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +// SunJSSE does not support dynamic system properties, no way to re-use +// system properties in samevm/agentvm mode. + +/* + * @test + * @bug 8280494 + * @summary (D)TLS signature schemes + * @modules java.base/sun.security.util + * @library /test/lib + * @build DTLSOverDatagram + * @run main/othervm DTLSSignatureSchemes + */ + +import javax.net.ssl.SSLEngine; +import javax.net.ssl.SSLParameters; +import java.security.Security; + +/** + * Test DTLS client authentication. + */ +public class DTLSSignatureSchemes extends DTLSOverDatagram { + private final String[] serverSignatureSchemes; + private final String[] clientSignatureSchemes; + + public DTLSSignatureSchemes(String[] serverSignatureSchemes, + String[] clientSignatureSchemes) { + this.serverSignatureSchemes = serverSignatureSchemes; + this.clientSignatureSchemes = clientSignatureSchemes; + } + + @Override + SSLEngine createSSLEngine(boolean isClient) throws Exception { + SSLEngine engine = super.createSSLEngine(isClient); + + SSLParameters sslParameters = engine.getSSLParameters(); + if (isClient) { + sslParameters.setSignatureSchemes(clientSignatureSchemes); + } else { + sslParameters.setSignatureSchemes(serverSignatureSchemes); + } + engine.setSSLParameters(sslParameters); + + return engine; + } + + public static void main(String[] args) throws Exception { + Security.setProperty("jdk.tls.disabledAlgorithms", ""); + + runTest(new String[] { + "ecdsa_secp256r1_sha256", + "ed25519" + }, + new String[] { + "ecdsa_secp256r1_sha256", + "ed25519" + }, + false); + runTest(new String[] { + "ecdsa_secp256r1_sha256" + }, + new String[] { + "ecdsa_secp256r1_sha256" + }, + false); + runTest(null, + new String[] { + "ecdsa_secp256r1_sha256" + }, + false); + runTest(new String[] { + "ecdsa_secp256r1_sha256" + }, + null, + false); + runTest(new String[0], + new String[] { + "ecdsa_secp256r1_sha256" + }, + true); + runTest(new String[] { + "ecdsa_secp256r1_sha256" + }, + new String[0], + true); + runTest(new String[] { + "ecdsa_secp256r1_shaNA" + }, + new String[] { + "ecdsa_secp256r1_sha256" + }, + true); + } + + private static void runTest(String[] serverSignatureSchemes, + String[] clientSignatureSchemes, + boolean exceptionExpected) throws Exception { + DTLSSignatureSchemes testCase = new DTLSSignatureSchemes( + serverSignatureSchemes, clientSignatureSchemes); + try { + testCase.runTest(testCase); + } catch (Exception e) { + if (!exceptionExpected) { + throw e; + } else { // Otherwise, swallow the expected exception and return. + return; + } + } + + if (exceptionExpected) { + throw new RuntimeException("Unexpected success!"); + } + } +} + diff --git a/test/jdk/javax/net/ssl/SSLException/CheckSSLHandshakeException.java b/test/jdk/javax/net/ssl/SSLException/CheckSSLHandshakeException.java new file mode 100644 index 0000000000000000000000000000000000000000..4c8aba3de44d0e24d02bd771d47fc6f9474ada54 --- /dev/null +++ b/test/jdk/javax/net/ssl/SSLException/CheckSSLHandshakeException.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2022 THL A29 Limited, a Tencent company. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8282723 + * @summary Add constructors taking a cause to JSSE exceptions + */ +import javax.net.ssl.SSLHandshakeException; +import java.util.Objects; + +public class CheckSSLHandshakeException { + private static String exceptionMessage = "message"; + private static Throwable exceptionCause = new RuntimeException(); + + public static void main(String[] args) throws Exception { + testException( + new SSLHandshakeException(exceptionMessage, exceptionCause)); + } + + private static void testException(Exception ex) { + if (!Objects.equals(ex.getMessage(), exceptionMessage)) { + throw new RuntimeException("Unexpected exception message"); + } + + if (ex.getCause() != exceptionCause) { + throw new RuntimeException("Unexpected exception cause"); + } + } +} diff --git a/test/jdk/javax/net/ssl/SSLException/CheckSSLKeyException.java b/test/jdk/javax/net/ssl/SSLException/CheckSSLKeyException.java new file mode 100644 index 0000000000000000000000000000000000000000..dcd62fcf8e7d367504e2b43a6a34ad720d0f40ec --- /dev/null +++ b/test/jdk/javax/net/ssl/SSLException/CheckSSLKeyException.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2022 THL A29 Limited, a Tencent company. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8282723 + * @summary Add constructors taking a cause to JSSE exceptions + */ +import javax.net.ssl.SSLKeyException; +import java.util.Objects; + +public class CheckSSLKeyException { + private static String exceptionMessage = "message"; + private static Throwable exceptionCause = new RuntimeException(); + + public static void main(String[] args) throws Exception { + testException( + new SSLKeyException(exceptionMessage, exceptionCause)); + } + + private static void testException(Exception ex) { + if (!Objects.equals(ex.getMessage(), exceptionMessage)) { + throw new RuntimeException("Unexpected exception message"); + } + + if (ex.getCause() != exceptionCause) { + throw new RuntimeException("Unexpected exception cause"); + } + } +} diff --git a/test/jdk/javax/net/ssl/SSLException/CheckSSLPeerUnverifiedException.java b/test/jdk/javax/net/ssl/SSLException/CheckSSLPeerUnverifiedException.java new file mode 100644 index 0000000000000000000000000000000000000000..04184e99306bc7838bdbdad8cf5a021f75b36752 --- /dev/null +++ b/test/jdk/javax/net/ssl/SSLException/CheckSSLPeerUnverifiedException.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2022 THL A29 Limited, a Tencent company. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8282723 + * @summary Add constructors taking a cause to JSSE exceptions + */ +import javax.net.ssl.SSLPeerUnverifiedException; +import java.util.Objects; + +public class CheckSSLPeerUnverifiedException { + private static String exceptionMessage = "message"; + private static Throwable exceptionCause = new RuntimeException(); + + public static void main(String[] args) throws Exception { + testException( + new SSLPeerUnverifiedException(exceptionMessage, exceptionCause)); + } + + private static void testException(Exception ex) { + if (!Objects.equals(ex.getMessage(), exceptionMessage)) { + throw new RuntimeException("Unexpected exception message"); + } + + if (ex.getCause() != exceptionCause) { + throw new RuntimeException("Unexpected exception cause"); + } + } +} diff --git a/test/jdk/javax/net/ssl/SSLException/CheckSSLProtocolException.java b/test/jdk/javax/net/ssl/SSLException/CheckSSLProtocolException.java new file mode 100644 index 0000000000000000000000000000000000000000..3f62fac8f771bba2521155b22975d2510fee3fe2 --- /dev/null +++ b/test/jdk/javax/net/ssl/SSLException/CheckSSLProtocolException.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2022 THL A29 Limited, a Tencent company. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8282723 + * @summary Add constructors taking a cause to JSSE exceptions + */ +import javax.net.ssl.SSLProtocolException; +import java.util.Objects; + +public class CheckSSLProtocolException { + private static String exceptionMessage = "message"; + private static Throwable exceptionCause = new RuntimeException(); + + public static void main(String[] args) throws Exception { + testException( + new SSLProtocolException(exceptionMessage, exceptionCause)); + } + + private static void testException(Exception ex) { + if (!Objects.equals(ex.getMessage(), exceptionMessage)) { + throw new RuntimeException("Unexpected exception message"); + } + + if (ex.getCause() != exceptionCause) { + throw new RuntimeException("Unexpected exception cause"); + } + } +} diff --git a/test/jdk/javax/net/ssl/SSLParameters/SignatureSchemes.java b/test/jdk/javax/net/ssl/SSLParameters/SignatureSchemes.java new file mode 100644 index 0000000000000000000000000000000000000000..7dadeff5703138593b7603a78b2020c3e87e03ee --- /dev/null +++ b/test/jdk/javax/net/ssl/SSLParameters/SignatureSchemes.java @@ -0,0 +1,147 @@ +/* + * Copyright (C) 2022 THL A29 Limited, a Tencent company. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +// SunJSSE does not support dynamic system properties, no way to re-use +// system properties in samevm/agentvm mode. + +/* + * @test + * @bug 8280494 + * @summary (D)TLS signature schemes + * @library /javax/net/ssl/templates + * @run main/othervm SignatureSchemes + */ + +import javax.net.ssl.SSLParameters; +import javax.net.ssl.SSLServerSocket; +import javax.net.ssl.SSLSocket; +import java.security.Security; + +public class SignatureSchemes extends SSLSocketTemplate { + private final String[] serverSignatureSchemes; + private final String[] clientSignatureSchemes; + private final boolean exceptionExpected; + + public SignatureSchemes(String[] serverSignatureSchemes, + String[] clientSignatureSchemes, + boolean exceptionExpected) { + this.serverSignatureSchemes = serverSignatureSchemes; + this.clientSignatureSchemes = clientSignatureSchemes; + this.exceptionExpected = exceptionExpected; + } + + @Override + protected void configureServerSocket(SSLServerSocket sslServerSocket) { + SSLParameters sslParameters = sslServerSocket.getSSLParameters(); + sslParameters.setSignatureSchemes(serverSignatureSchemes); + sslServerSocket.setSSLParameters(sslParameters); + } + + @Override + protected void configureClientSocket(SSLSocket socket) { + SSLParameters sslParameters = socket.getSSLParameters(); + sslParameters.setSignatureSchemes(clientSignatureSchemes); + socket.setSSLParameters(sslParameters); + } + + @Override + protected void runServerApplication(SSLSocket socket) throws Exception { + try { + super.runServerApplication(socket); + } catch (Exception ex) { + // Just ignore, let the client handle the failure information. + } + } + + @Override + protected void runClientApplication(SSLSocket sslSocket) throws Exception { + try { + super.runClientApplication(sslSocket); + } catch (Exception ex) { + if (!exceptionExpected) { + throw ex; + } else { // Otherwise, swallow the exception and return. + return; + } + } + + if (exceptionExpected) { + throw new RuntimeException("Unexpected success!"); + } + } + + public static void main(String[] args) throws Exception { + Security.setProperty("jdk.tls.disabledAlgorithms", ""); + + runTest(new String[] { + "ecdsa_secp256r1_sha256", + "ed25519" + }, + new String[] { + "ecdsa_secp256r1_sha256", + "ed25519" + }, + false); + runTest(new String[] { + "ecdsa_secp256r1_sha256" + }, + new String[] { + "ecdsa_secp256r1_sha256" + }, + false); + runTest(null, + new String[] { + "ecdsa_secp256r1_sha256" + }, + false); + runTest(new String[] { + "ecdsa_secp256r1_sha256" + }, + null, + false); + runTest(new String[0], + new String[] { + "ecdsa_secp256r1_sha256" + }, + true); + runTest(new String[] { + "ecdsa_secp256r1_sha256" + }, + new String[0], + true); + runTest(new String[] { + "ecdsa_secp256r1_shaNA" + }, + new String[] { + "ecdsa_secp256r1_sha256" + }, + true); + } + + private static void runTest(String[] serverSignatureSchemes, + String[] clientSignatureSchemes, + boolean exceptionExpected) throws Exception { + new SignatureSchemes(serverSignatureSchemes, + clientSignatureSchemes, exceptionExpected).run(); + } +} diff --git a/test/jdk/javax/net/ssl/SSLSession/ResumeTLS13withSNI.java b/test/jdk/javax/net/ssl/SSLSession/ResumeTLS13withSNI.java index f5455cc918e172f3460cc2ef3003b3fb9b311d3c..fbb62441e1c053db6ff335a4647fa0ab98bbda6a 100644 --- a/test/jdk/javax/net/ssl/SSLSession/ResumeTLS13withSNI.java +++ b/test/jdk/javax/net/ssl/SSLSession/ResumeTLS13withSNI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -26,7 +26,7 @@ /* * @test - * @bug 8211806 + * @bug 8211806 8277881 * @summary TLS 1.3 handshake server name indication is missing on a session resume * @run main/othervm ResumeTLS13withSNI */ @@ -338,6 +338,9 @@ public class ResumeTLS13withSNI { // Get the legacy session length and skip that many bytes int sessIdLen = Byte.toUnsignedInt(resCliHello.get()); + if (sessIdLen == 0) { + throw new Exception("SessionID field empty"); + } resCliHello.position(resCliHello.position() + sessIdLen); // Skip over all the cipher suites diff --git a/test/jdk/javax/net/ssl/ServerName/EndingDotHostname.java b/test/jdk/javax/net/ssl/ServerName/EndingDotHostname.java new file mode 100644 index 0000000000000000000000000000000000000000..bac110aa0338bd295911c33d9b0df947787bb3ca --- /dev/null +++ b/test/jdk/javax/net/ssl/ServerName/EndingDotHostname.java @@ -0,0 +1,251 @@ +/* + * Copyright (C) 2022 THL A29 Limited, a Tencent company. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8065422 + * @summary Trailing dot in hostname causes TLS handshake to fail + * @library /javax/net/ssl/templates + * @run main/othervm --add-opens java.base/sun.security.ssl=ALL-UNNAMED + * -Djdk.net.hosts.file=hostsForExample EndingDotHostname + */ + +import javax.net.ssl.*; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.*; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +public class EndingDotHostname { + public static void main(String[] args) throws Exception { + System.setProperty("jdk.net.hosts.file", "hostsForExample"); + (new EndingDotHostname()).run(); + } + + public void run() throws Exception { + bootUp(); + } + + // ================================================= + // Stuffs to boot up the client-server mode testing. + private Thread serverThread = null; + private volatile Exception serverException = null; + private volatile Exception clientException = null; + + // Is the server ready to serve? + protected final CountDownLatch serverCondition = new CountDownLatch(1); + + // Is the client ready to handshake? + protected final CountDownLatch clientCondition = new CountDownLatch(1); + + // What's the server port? Use any free port by default + protected volatile int serverPort = 0; + + // Boot up the testing, used to drive remainder of the test. + private void bootUp() throws Exception { + Exception startException = null; + try { + startServer(); + startClient(); + } catch (Exception e) { + startException = e; + } + + // Wait for other side to close down. + if (serverThread != null) { + serverThread.join(); + } + + // The test is pretty much over. Which side threw an exception? + Exception local = clientException; + Exception remote = serverException; + + Exception exception = null; + + // Check various exception conditions. + if ((local != null) && (remote != null)) { + // If both failed, return the curthread's exception. + local.initCause(remote); + exception = local; + } else if (local != null) { + exception = local; + } else if (remote != null) { + exception = remote; + } else if (startException != null) { + exception = startException; + } + + // If there was an exception *AND* a startException, output it. + if (exception != null) { + if (exception != startException && startException != null) { + exception.addSuppressed(startException); + } + throw exception; + } + + // Fall-through: no exception to throw! + } + + private void startServer() { + serverThread = new Thread(() -> { + try { + doServerSide(); + } catch (Exception e) { + // Our server thread just died. Release the client, + // if not active already... + serverException = e; + } + }); + + serverThread.start(); + } + + private void startClient() { + try { + doClientSide(); + } catch (Exception e) { + clientException = e; + } + } + + protected void doServerSide() throws Exception { + // kick off the server side service + SSLContext context = SSLExampleCert.createServerSSLContext(); + SSLServerSocketFactory sslssf = context.getServerSocketFactory(); + + SSLServerSocket sslServerSocket = + (SSLServerSocket)sslssf.createServerSocket(); + sslServerSocket.bind(new InetSocketAddress( + InetAddress.getLoopbackAddress(), 0)); + serverPort = sslServerSocket.getLocalPort(); + + // Signal the client, the server is ready to accept connection. + serverCondition.countDown(); + + // Try to accept a connection in 30 seconds. + SSLSocket sslSocket; + try { + sslServerSocket.setSoTimeout(30000); + sslSocket = (SSLSocket)sslServerSocket.accept(); + } catch (SocketTimeoutException ste) { + // Ignore the test case if no connection within 30 seconds. + System.out.println( + "No incoming client connection in 30 seconds. " + + "Ignore in server side."); + return; + } finally { + sslServerSocket.close(); + } + + // handle the connection + try { + // Is it the expected client connection? + // + // Naughty test cases or third party routines may try to + // connection to this server port unintentionally. In + // order to mitigate the impact of unexpected client + // connections and avoid intermittent failure, it should + // be checked that the accepted connection is really linked + // to the expected client. + boolean clientIsReady = + clientCondition.await(30L, TimeUnit.SECONDS); + + if (clientIsReady) { + // Run the application in server side. + runServerApplication(sslSocket); + } else { // Otherwise, ignore + // We don't actually care about plain socket connections + // for TLS communication testing generally. Just ignore + // the test if the accepted connection is not linked to + // the expected client or the client connection timeout + // in 30 seconds. + System.out.println( + "The client is not the expected one or timeout. " + + "Ignore in server side."); + } + } finally { + sslSocket.close(); + } + } + + // Define the server side application of the test for the specified socket. + protected void runServerApplication(SSLSocket socket) throws Exception { + // here comes the test logic + InputStream sslIS = socket.getInputStream(); + OutputStream sslOS = socket.getOutputStream(); + + sslIS.read(); + sslOS.write(85); + sslOS.flush(); + } + + protected void doClientSide() throws Exception { + // Wait for server to get started. + // + // The server side takes care of the issue if the server cannot + // get started in 90 seconds. The client side would just ignore + // the test case if the serer is not ready. + boolean serverIsReady = + serverCondition.await(90L, TimeUnit.SECONDS); + if (!serverIsReady) { + System.out.println( + "The server is not ready yet in 90 seconds. " + + "Ignore in client side."); + return; + } + + SSLContext context = SSLExampleCert.createClientSSLContext(); + SSLSocketFactory sslsf = context.getSocketFactory(); + + try (SSLSocket sslSocket = (SSLSocket)sslsf.createSocket( + "www.example.com.", serverPort)) { + // OK, here the client and server get connected. + SSLParameters sslParameters = sslSocket.getSSLParameters(); + sslParameters.setEndpointIdentificationAlgorithm("HTTPS"); + sslSocket.setSSLParameters(sslParameters); + + // Signal the server, the client is ready to communicate. + clientCondition.countDown(); + + // There is still a chance in theory that the server thread may + // wait client-ready timeout and then quit. The chance should + // be really rare so we don't consider it until it becomes a + // real problem. + + // Run the application in client side. + runClientApplication(sslSocket); + } + } + + // Define the client side application of the test for the specified socket. + protected void runClientApplication(SSLSocket socket) throws Exception { + InputStream sslIS = socket.getInputStream(); + OutputStream sslOS = socket.getOutputStream(); + + sslOS.write(280); + sslOS.flush(); + sslIS.read(); + } +} + diff --git a/test/jdk/javax/net/ssl/ServerName/SSLSocketExplorer.java b/test/jdk/javax/net/ssl/ServerName/SSLSocketExplorer.java index 4992553eba93b95329a73cc30d3f1b5f4e2987c3..3ae2e777810f7a584b47d837cd682ee52753625d 100644 --- a/test/jdk/javax/net/ssl/ServerName/SSLSocketExplorer.java +++ b/test/jdk/javax/net/ssl/ServerName/SSLSocketExplorer.java @@ -134,7 +134,7 @@ public class SSLSocketExplorer { position += n; } - capabilities = SSLExplorer.explore(buffer, 0, recordLength);; + capabilities = SSLExplorer.explore(buffer, 0, recordLength); if (capabilities != null) { System.out.println("Record version: " + capabilities.getRecordVersion()); diff --git a/test/jdk/javax/net/ssl/ServerName/SSLSocketExplorerFailure.java b/test/jdk/javax/net/ssl/ServerName/SSLSocketExplorerFailure.java index 00d00001d871c4e8059d76277a029497fc059675..7193fcaf136fbb830b088157b012d3fd877c718c 100644 --- a/test/jdk/javax/net/ssl/ServerName/SSLSocketExplorerFailure.java +++ b/test/jdk/javax/net/ssl/ServerName/SSLSocketExplorerFailure.java @@ -135,7 +135,7 @@ public class SSLSocketExplorerFailure { position += n; } - capabilities = SSLExplorer.explore(buffer, 0, recordLength);; + capabilities = SSLExplorer.explore(buffer, 0, recordLength); if (capabilities != null) { System.out.println("Record version: " + capabilities.getRecordVersion()); diff --git a/test/jdk/javax/net/ssl/ServerName/SSLSocketExplorerMatchedSNI.java b/test/jdk/javax/net/ssl/ServerName/SSLSocketExplorerMatchedSNI.java index 724a37e1a80d2f25d931da15d54c1101e7098a97..0cea7323b8373eb8f505c2d935e3e878d5570555 100644 --- a/test/jdk/javax/net/ssl/ServerName/SSLSocketExplorerMatchedSNI.java +++ b/test/jdk/javax/net/ssl/ServerName/SSLSocketExplorerMatchedSNI.java @@ -138,7 +138,7 @@ public class SSLSocketExplorerMatchedSNI { position += n; } - capabilities = SSLExplorer.explore(buffer, 0, recordLength);; + capabilities = SSLExplorer.explore(buffer, 0, recordLength); if (capabilities != null) { System.out.println("Record version: " + capabilities.getRecordVersion()); diff --git a/test/jdk/javax/net/ssl/ServerName/SSLSocketExplorerUnmatchedSNI.java b/test/jdk/javax/net/ssl/ServerName/SSLSocketExplorerUnmatchedSNI.java index 732e0cf3097566a4d367937f9a738c9af8f0e4b1..619a997eda293191bdce8719b0d5b596a877ef68 100644 --- a/test/jdk/javax/net/ssl/ServerName/SSLSocketExplorerUnmatchedSNI.java +++ b/test/jdk/javax/net/ssl/ServerName/SSLSocketExplorerUnmatchedSNI.java @@ -130,7 +130,7 @@ public class SSLSocketExplorerUnmatchedSNI { position += n; } - capabilities = SSLExplorer.explore(buffer, 0, recordLength);; + capabilities = SSLExplorer.explore(buffer, 0, recordLength); if (capabilities != null) { System.out.println("Record version: " + capabilities.getRecordVersion()); diff --git a/test/jdk/javax/net/ssl/ServerName/SSLSocketExplorerWithCliSNI.java b/test/jdk/javax/net/ssl/ServerName/SSLSocketExplorerWithCliSNI.java index 8f2b78168649e6bf702e39947e553289b2ae6d3a..8451b44f0bf00e6633bfae3fe40503ccfa477a55 100644 --- a/test/jdk/javax/net/ssl/ServerName/SSLSocketExplorerWithCliSNI.java +++ b/test/jdk/javax/net/ssl/ServerName/SSLSocketExplorerWithCliSNI.java @@ -129,7 +129,7 @@ public class SSLSocketExplorerWithCliSNI { position += n; } - capabilities = SSLExplorer.explore(buffer, 0, recordLength);; + capabilities = SSLExplorer.explore(buffer, 0, recordLength); if (capabilities != null) { System.out.println("Record version: " + capabilities.getRecordVersion()); diff --git a/test/jdk/javax/net/ssl/ServerName/SSLSocketExplorerWithSrvSNI.java b/test/jdk/javax/net/ssl/ServerName/SSLSocketExplorerWithSrvSNI.java index f026f32e781a2787f24b9f979c7af755546b25dd..8b891e804e44f94bb23c87d28ec987ed98670fd0 100644 --- a/test/jdk/javax/net/ssl/ServerName/SSLSocketExplorerWithSrvSNI.java +++ b/test/jdk/javax/net/ssl/ServerName/SSLSocketExplorerWithSrvSNI.java @@ -129,7 +129,7 @@ public class SSLSocketExplorerWithSrvSNI { position += n; } - capabilities = SSLExplorer.explore(buffer, 0, recordLength);; + capabilities = SSLExplorer.explore(buffer, 0, recordLength); if (capabilities != null) { System.out.println("Record version: " + capabilities.getRecordVersion()); diff --git a/test/jdk/javax/net/ssl/TLS/TestJSSE.java b/test/jdk/javax/net/ssl/TLS/TestJSSE.java index 2c5a2c6274d9d38079fa4d065a2ddf8c3dc145f8..29631064011df583680f1511a8314dd1c6d155eb 100644 --- a/test/jdk/javax/net/ssl/TLS/TestJSSE.java +++ b/test/jdk/javax/net/ssl/TLS/TestJSSE.java @@ -21,12 +21,13 @@ * questions. */ +import java.net.InetAddress; import java.security.Provider; import java.security.Security; public class TestJSSE { - private static final String LOCAL_IP = "127.0.0.1"; + private static final String LOCAL_IP = InetAddress.getLoopbackAddress().getHostAddress(); public static void main(String... args) throws Exception { // reset the security property to make sure that the algorithms diff --git a/test/jdk/javax/net/ssl/ciphersuites/DisabledAlgorithms.java b/test/jdk/javax/net/ssl/ciphersuites/DisabledAlgorithms.java index 7bb3e2c8d2b50e37262fd0ee2bac37a14e3957a0..441f6bdff483bd5ffb77f2685db64ab02b044a89 100644 --- a/test/jdk/javax/net/ssl/ciphersuites/DisabledAlgorithms.java +++ b/test/jdk/javax/net/ssl/ciphersuites/DisabledAlgorithms.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -23,7 +23,7 @@ /* * @test - * @bug 8076221 8211883 + * @bug 8076221 8211883 8163327 * @summary Check if weak cipher suites are disabled * @modules jdk.crypto.ec * @run main/othervm DisabledAlgorithms default @@ -60,9 +60,10 @@ public class DisabledAlgorithms { System.getProperty("test.src", "./") + "/" + pathToStores + "/" + trustStoreFile; - // supported RC4, NULL, and anon cipher suites + // supported 3DES, DES, RC4, NULL, and anon cipher suites // it does not contain KRB5 cipher suites because they need a KDC - private static final String[] rc4_null_anon_ciphersuites = new String[] { + private static final String[] desede_des_rc4_null_anon_ciphersuites + = new String[] { "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA", "TLS_ECDHE_RSA_WITH_RC4_128_SHA", "SSL_RSA_WITH_RC4_128_SHA", @@ -90,11 +91,25 @@ public class DisabledAlgorithms { "TLS_DH_anon_WITH_AES_256_CBC_SHA", "TLS_DH_anon_WITH_AES_256_CBC_SHA256", "TLS_DH_anon_WITH_AES_256_GCM_SHA384", + "SSL_RSA_WITH_DES_CBC_SHA", + "SSL_DHE_RSA_WITH_DES_CBC_SHA", + "SSL_DHE_DSS_WITH_DES_CBC_SHA", + "SSL_RSA_EXPORT_WITH_DES40_CBC_SHA", + "SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA", + "SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA", + "SSL_RSA_EXPORT_WITH_RC4_40_MD5", "TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA", "TLS_ECDH_anon_WITH_AES_128_CBC_SHA", "TLS_ECDH_anon_WITH_AES_256_CBC_SHA", "TLS_ECDH_anon_WITH_NULL_SHA", - "TLS_ECDH_anon_WITH_RC4_128_SHA" + "TLS_ECDH_anon_WITH_RC4_128_SHA", + "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA", + "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA", + "SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA", + "SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA", + "TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA", + "TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA", + "SSL_RSA_WITH_3DES_EDE_CBC_SHA" }; public static void main(String[] args) throws Exception { @@ -113,19 +128,25 @@ public class DisabledAlgorithms { System.out.println("jdk.tls.disabledAlgorithms = " + Security.getProperty("jdk.tls.disabledAlgorithms")); - // check if RC4, NULL, and anon cipher suites + // check if 3DES, DES, RC4, NULL, and anon cipher suites // can't be used by default - checkFailure(rc4_null_anon_ciphersuites); + checkFailure(desede_des_rc4_null_anon_ciphersuites); break; case "empty": // reset jdk.tls.disabledAlgorithms Security.setProperty("jdk.tls.disabledAlgorithms", ""); System.out.println("jdk.tls.disabledAlgorithms = " + Security.getProperty("jdk.tls.disabledAlgorithms")); - - // check if RC4, NULL, and anon cipher suites can be used - // if jdk.tls.disabledAlgorithms is empty - checkSuccess(rc4_null_anon_ciphersuites); + // reset jdk.certpath.disabledAlgorithms. This is necessary + // to allow the RSA_EXPORT suites to pass which use an RSA 512 + // bit key which violates the default certpath constraints. + Security.setProperty("jdk.certpath.disabledAlgorithms", ""); + System.out.println("jdk.certpath.disabledAlgorithms = " + + Security.getProperty("jdk.certpath.disabledAlgorithms")); + + // check if 3DES, DES, RC4, NULL, and anon cipher suites + // can be used if jdk.{tls,certpath}.disabledAlgorithms is empty + checkSuccess(desede_des_rc4_null_anon_ciphersuites); break; default: throw new RuntimeException("Wrong parameter: " + args[0]); diff --git a/test/jdk/javax/net/ssl/sanity/interop/JSSEClient.java b/test/jdk/javax/net/ssl/sanity/interop/JSSEClient.java index 2207749302d909dfb53f44af6ad43e4f37b598fd..21416f0aaef21dcf0a2f16cf34314e6df5900bd5 100644 --- a/test/jdk/javax/net/ssl/sanity/interop/JSSEClient.java +++ b/test/jdk/javax/net/ssl/sanity/interop/JSSEClient.java @@ -23,6 +23,7 @@ import java.io.InputStream; import java.io.OutputStream; +import java.net.InetAddress; import java.security.cert.Certificate; import javax.net.ssl.KeyManager; @@ -52,7 +53,8 @@ class JSSEClient extends CipherTest.Client { new TrustManager[] { CipherTest.trustManager }, CipherTest.secureRandom); SSLSocketFactory factory = (SSLSocketFactory)sslContext.getSocketFactory(); - socket = (SSLSocket)factory.createSocket("127.0.0.1", CipherTest.serverPort); + socket = (SSLSocket)factory.createSocket( + InetAddress.getLoopbackAddress().getHostAddress(), CipherTest.serverPort); socket.setSoTimeout(CipherTest.TIMEOUT); socket.setEnabledCipherSuites(new String[] { params.cipherSuite.name() }); socket.setEnabledProtocols(new String[] { params.protocol.name }); diff --git a/test/jdk/javax/net/ssl/templates/SSLExampleCert.java b/test/jdk/javax/net/ssl/templates/SSLExampleCert.java new file mode 100644 index 0000000000000000000000000000000000000000..0b82aed3b7bd841c6f86b7caf481fa2e6f5b1be8 --- /dev/null +++ b/test/jdk/javax/net/ssl/templates/SSLExampleCert.java @@ -0,0 +1,414 @@ +/* + * Copyright (C) 2022 THL A29 Limited, a Tencent company. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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.net.ssl.*; +import java.io.*; +import java.lang.reflect.Field; +import java.net.InetAddress; +import java.security.KeyFactory; +import java.security.KeyStore; +import java.security.PrivateKey; +import java.security.cert.Certificate; +import java.security.cert.CertificateFactory; +import java.security.cert.PKIXBuilderParameters; +import java.security.spec.PKCS8EncodedKeySpec; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Base64; +import java.util.Date; + +/** + * A template to use "www.example.com" as the server name. The caller should + * set a virtual hosts file with System Property, "jdk.net.hosts.file". This + * class will map the loopback address to "www.example.com", and write to + * the specified hosts file. + * + * Commands used: + * # Root CA + * > openssl req -new -config openssl.cnf -out root-ca.csr \ + * -keyout private/root-ca.key -days 7300 -newkey rsa:2048 + * > openssl ca -selfsign -config openssl.cnf -in root-ca.csr \ + * -out certs/root-ca.crt -extensions v3_ca + * -keyfile private/root-ca.key -days 7300 + * + * # www.example.com + * > openssl req -new -keyout private/example.key \ + * -out example.csr -days 7299 -newkey rsa:2048 + * > openssl ca -config openssl.cnf -in example.csr \ + * -out certs/example.crt -extensions usr_cert + * -keyfile private/root-ca.key -days 7299 + * + * # Client + * > openssl req -new -keyout private/client.key \ + * -out client.csr -days 7299 -newkey rsa:2048 + * > openssl ca -config openssl.cnf -in client.csr \ + * -out certs/client.crt -extensions usr_cert + * -keyfile private/root-ca.key -days 7299 + * + * The key files should be in PKCS8 format: + * > openssl pkcs8 -topk8 -inform PEM -outform pem \ + * -in private/example.key -out private/example-pkcs.key -nocrypt + */ +public enum SSLExampleCert { + // Version: 3 (0x2) + // Serial Number: 4097 (0x1001) + // Signature Algorithm: sha256WithRSAEncryption + // Issuer: C = US, ST = California, O = Example, OU = Test + // Validity + // Not Before: Feb 25 20:12:04 2022 GMT + // Not After : Feb 20 20:12:04 2042 GMT + // Subject: C = US, ST = California, O = Example, OU = Test + // Subject Public Key Info: + // Public Key Algorithm: rsaEncryption + // RSA Public-Key: (2048 bit) + CA_RSA("RSA", + """ + -----BEGIN CERTIFICATE----- + MIIDtDCCApygAwIBAgICEAEwDQYJKoZIhvcNAQELBQAwQzELMAkGA1UEBhMCVVMx + EzARBgNVBAgTCkNhbGlmb3JuaWExEDAOBgNVBAoTB0V4YW1wbGUxDTALBgNVBAsT + BFRlc3QwHhcNMjIwMjI1MjAxMjA0WhcNNDIwMjIwMjAxMjA0WjBDMQswCQYDVQQG + EwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEQMA4GA1UEChMHRXhhbXBsZTENMAsG + A1UECxMEVGVzdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKOGhEDj + lZ5R6o20kJdgrIRcY1he4qKLWQ4vU0thqAg4mEcKCZZn4/NL05UgJCFLwYaxMZZe + etb/WaTRvQpDDFh7AhsMR24m6zKKJVk9E/e/8ur7sGDIVq8hZOBTq85ZdxPj/zKW + wB1BR/RcY4DsGno1USlkV7TVeZc1qpJHTPImesevzH7zX8nhnFlf4TTQbpQt6RxU + cr+udWpMOyP9xMerIyp7jpPy79tIaGP2x7ryt2BB9FU4RwPk4DcdfOkmdS86md1c + GI9H5qM5rUzyqey0J8wMRLj+E0Vx0F1XELZeTtyulbIbhrBhu/KOXZG2zNIeK+2F + XxDlx9tD+bbcJfUCAwEAAaOBsTCBrjAdBgNVHQ4EFgQULjM9fwJnC3Tp1QYM8HNL + y60btl0wbAYDVR0jBGUwY4AULjM9fwJnC3Tp1QYM8HNLy60btl2hR6RFMEMxCzAJ + BgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRAwDgYDVQQKEwdFeGFtcGxl + MQ0wCwYDVQQLEwRUZXN0ggIQATAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQE + AwIBBjANBgkqhkiG9w0BAQsFAAOCAQEAR0Mk+2X/rr4kYYfHsQUIsROwDZSQhQr3 + QOeLc7fyTjkM96OHXN2dKVoOcpzgKi1goHW7lh8vVmKRQk2wfFqRZV9/kQBFK/gz + QtN5gp+pA8Wk912Uj5gD0loiPcRf5bDElvLnr2iwt4VdKkvGIYa9Eu9CYbkf1x3t + ahVLmrZLBkqvKxo4MG4KGYXkqtII3M6clM4ScFa/0rR1nGZOgZyqG7AMMHc01csA + oLlEZx2hUcpJbz+sfCGUWYaF2uKJvuWMNFbGSDhfs8pOMGgelMOHaKVtgOEfEASN + TSqzqn0vzjJ78Mi6mN7/6L/onDKzROxClw0hc6L+PIhIHftD1ckvVQ== + -----END CERTIFICATE-----""", + + """ + MIIFHDBOBgkqhkiG9w0BBQ0wQTApBgkqhkiG9w0BBQwwHAQIn/uWtEzLDK8CAggA + MAwGCCqGSIb3DQIJBQAwFAYIKoZIhvcNAwcECIk7+JC4ErMDBIIEyA3yvNhMm/Oj + ZdkN0HSzPyLv9bOfUyyx4NA121kizZIq/FkUjn8pGxzU63rzMk2vU1hmp2/O3ymr + vmV7gzXRp4ULZCjFwn4cLxi9ieKgBOr9MmgTlRc1oZ9P/Y8eWhmjGxA2CU3fy7Kv + DyzftqAetV8YzTelk8xqxLrGevB16O3zDbFj4dcmG7a0i75kqlI8QyQklJ9uyE10 + SELWFlV6w+3GD82YrbR/8v4fE5KP/nAPbtN4h4C7MY3kJQL+apHr5B3Jst+6N62t + JzmxGS5z3ZVT3Bn3mxi8awo8/XS8s+ZOSnH6nHvz83NBUQwSkVbtujlg+yMD2jg4 + Nt3LWfLnF8Q6n4oAQ1ZP9KJyVIh8+PN12txIRoWq1pF74hJmbfVfiCSR/tMrw6lr + XqlkG1Mi7RmpTCz9ScTUBWY/dyScYFITenv/WE+UnfQ+DXBC+78lkmL36M0Rx/ip + S4O1Tgy/z/MIv1s+ZpAFsRRczlpo9lbVEMuSGEWWTIQJCRPFV8Y1NKHmWUgeZpl3 + 2YUjpHNyQt/a1s1h1g5w9+UNuABt/3cUUnlA7psueb6l4x6M92QFBOpe1xUDL51D + RpaipVl1luFWvE84hqgCIv8Kh9EbkAlclmK8CIOkMQAabk0GmhCfEdm+PCW61Cao + rfCMwZ9Bx6zAcXGRrvl0sK35z8C3r8wLftaS/5xF6RTJBy6XY2iiFW6D44qZDFbh + 0rWV8zDtCf2+OZtEvPkeUn3sjevDW78TM6F7HBjXAeIFrNyJGVe2CTlEJLoZi5pX + W1blhMJ93N1mLiDYisILANmJRBfGMt0tYE/pGcJRlkuqG0qylnqRojjL83CTQvFy + 46q/obR36enRDvCZPvQrX2dB7Vkgpkz/drZ6+avmKdQcTjY/ycCd3DclwexhgUoX + QDntZuJQLp7C4tFfHRy2uh4DOEjzMP6a/NQ3q7p6vc6BTNTFZRUAdyNwcEDIzSLM + nZSPFBiz+gukhtNSCO28kLc8OX1hYsSAMgzbImcMtAiQHG3bFAJ0cs0jF4U9VrJt + 4/97kiDBuCgGb2b5t0+uDqipE6G4B6494IGm5KoIPAPbXMJQstmuzjTJt95UTF+p + e60AnWIXcvEOouIIMzC7gH2g23St5Bo6NixfxcmVfkFa92TDlCTxEz5Z5mnma06k + Pao4Km1eJkYS/QaCDnCZs/yCAMhINUTTDd0/7Y9YE3Dmd5B1s2wOa+ovESSL3Mdv + dZoxh91QR+6hQuz3iYztC/BszMtATH8MznAoco0QFAhKi56Wppe+p1ATLWFMqk4W + elX9vtw5XLucKy5cMkQYh144SnrerlPJTAOGy0XXKunj8ceZfEN6zcS9Us9IN5aF + iENMFHjPsscrrKFhKypaMIn67PuIhVhw4PnGrWejr6TM1gUx+zOcRCwT+5ka2L7U + aqmgS8cDg5ZfAHcbig7No9kku/OSk+5QzkVKca2TZQHm++60oQTzRl3/NWiELO+e + Sl6r8i7dS0Kv3bB/AbLfIHtDgebxUh78qXMel/OUWd58ezxBS74rZ4AQTpYcdTbR + jKHploWi8h5yXYn/YdEZG1vW/zYseFNb7QKT5Cznucl8O/+lNZIOVw63Pq368dTD + tG1GZkIlwM+jlJjRew05YQ== + """), + + // Version: 3 (0x2) + // Serial Number: 4098 (0x1002) + // Signature Algorithm: sha256WithRSAEncryption + // Issuer: C = US, ST = California, O = Example, OU = Test + // Validity + // Not Before: Feb 25 20:31:29 2022 GMT + // Not After : Feb 19 20:31:29 2042 GMT + // Subject: C = US, ST = California, O = Example, OU = Test, CN = www.example.com + // Subject Public Key Info: + // Public Key Algorithm: rsaEncryption + // RSA Public-Key: (2048 bit) + SERVER_EXAMPLE_RSA("RSA", + """ + -----BEGIN CERTIFICATE----- + MIIDaTCCAlGgAwIBAgICEAIwDQYJKoZIhvcNAQELBQAwQzELMAkGA1UEBhMCVVMx + EzARBgNVBAgTCkNhbGlmb3JuaWExEDAOBgNVBAoTB0V4YW1wbGUxDTALBgNVBAsT + BFRlc3QwHhcNMjIwMjI1MjAzMTI5WhcNNDIwMjE5MjAzMTI5WjBdMQswCQYDVQQG + EwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEQMA4GA1UECgwHRXhhbXBsZTENMAsG + A1UECwwEVGVzdDEYMBYGA1UEAwwPd3d3LmV4YW1wbGUuY29tMIIBIjANBgkqhkiG + 9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3crcRzecIV08Muh6kA0CuVKnPkU2bLC+6bpV + 7/iBZ4D3qMwO8Q02+gP71pPNoAQ1nsifxR4k9mBVYOjar35RVpuFmLRRVMargrxg + 4WWDfVgLMhOeCy8+Tl4Mp/yRL3nkr0MJd57RCOPcPE84J/1Crq1Luy2+hsXSj25L + VJKx2o6LE0tfwPWnufdNUHzHRuNoBR83OpqIT0uXH15THZS+0ZcQwrJMcKYe4JWl + 6oXWcsWbtTG+r7QLIRKck2IG7jjHFpE83Q6Iv2HkhctgGZofwSTZyMmJ8eClovva + WFLDaLL2WuI3NwZM//knjMyfsEWtWsILXayCn5NTT74ClQjWQQIDAQABo00wSzAJ + BgNVHRMEAjAAMB0GA1UdDgQWBBQ9nPjenO4PMLtMTBddNiIDsPywjzAfBgNVHSME + GDAWgBQuMz1/AmcLdOnVBgzwc0vLrRu2XTANBgkqhkiG9w0BAQsFAAOCAQEAVOvM + fMDOxOCkWB244cx7J+f2qZU6/1qGlJUiL0WRLRj1XEmB8AYSZEb6Os1suF8sotka + nA9Aw1SFA/wNyrSKazXNlOKo0In1mu/OjHU7n6XYVAyDmFGziYY8zTqG1h8ZPrI7 + oAkNgnNDwmwy7uCAvMj+Q4QQ0Q4YxTHV/i3X1HuEwThRgz9cJGdDRIAsimRHDSDO + 5hsIJo6VASz0ISrYMxNZQ1og+XktdNssPK616bPf+APwXXnsWSuGkIdGDU059DII + cTSsLTbWkTWDXAAQo+sfDZUrvqopCK000eoywEmPQrTf7O8oAQdRvTsyxwMvOONd + EWQ9pDW9+RC8l5DtRA== + -----END CERTIFICATE-----""", + + """ + MIIEwAIBADANBgkqhkiG9w0BAQEFAASCBKowggSmAgEAAoIBAQDdytxHN5whXTwy + 6HqQDQK5Uqc+RTZssL7pulXv+IFngPeozA7xDTb6A/vWk82gBDWeyJ/FHiT2YFVg + 6NqvflFWm4WYtFFUxquCvGDhZYN9WAsyE54LLz5OXgyn/JEveeSvQwl3ntEI49w8 + Tzgn/UKurUu7Lb6GxdKPbktUkrHajosTS1/A9ae5901QfMdG42gFHzc6mohPS5cf + XlMdlL7RlxDCskxwph7glaXqhdZyxZu1Mb6vtAshEpyTYgbuOMcWkTzdDoi/YeSF + y2AZmh/BJNnIyYnx4KWi+9pYUsNosvZa4jc3Bkz/+SeMzJ+wRa1awgtdrIKfk1NP + vgKVCNZBAgMBAAECggEBAMUMAtJe7J6Tx/TuqF0swfvGHAHt2eGM0cCzpMATh1xe + rylPSgMNG4faXDcSj4AX3U+ZrKCjHHGruo7jsc5yqm8IsxOtOAjajOwU0vnNh5mn + zCKMXUBQk8lqM1JXyOFmKS8wnsug1NRSJIuMUjbtAf5QxlSg2oHAZUa61cBoqAyk + KXbw9uBYnM4n8WGXdax/LLPuonjnz2Sc35CC1LhRAF/K7oyjg7KvScnphIFRaLiU + X4tFH0nLpcao5de0fP5eUEkbUZ3hE6MEZvOsxn5CFkjH2VdtZ9D5dc3ArV3UMe26 + +3swdenriYZ73HNJDiLAdeIVh9IrGVxhH9UowF9psIUCgYEA/Ldlx4vTTlM7URFn + luqK7D8WH9x4JiCLEGxU80nJxxIgF8eqhOFzsQemytTrf4o1xAkyyPIweHzwApCA + lBdwC4Mc44DjoLFVdTET9hEq7E/UK81znc0mD4v8Hz2JI6h3f2sQrcEAPBvjBwtc + TpS9WlSBKSO3NOb3Hlucq7COVKcCgYEA4KyZ+dOyKVLyGjd0g22v4YW7VC016Hql + uQ7SN1vuI3zQMa2rZfEv5z2L7olJKrDFcmqk8W1tfElrMaSsuohm8khhx0lPtHMw + 4Su/tci/3rEUl+DPrQExdjrrDXCqpUunOAlMP9qElsNBGdkrQ6QlMnSVVi2v8Vf1 + f86Mey2UEtcCgYEAqcOlmqPigfZFnZLcjLPoOQW0HhkjmTE5WgH8GybRZmpVpsPZ + V8R/zEeAkzbvMFEvBw7Kz9RqHTaIoKBjz5fjC8i7ClVWFGesKbqbVyx3MiH6PKaa + aUIbtEvsRSw4SPztsWnB3YcOWlK9csj97Efc36Zu0a0NcHtLPFh8aZWEN3cCgYEA + oQFv8oWPlmeXkcwN1iWjtfT1EtS3XhuOaXjCkuNxW8MVG5S+UHawAoGrpsyBP3Og + e2cLPuxRWpDunYvKMH6Rb60JTRwvXzxxWdvVLbtoLHkwLcrwaKWDQZvlWCNWVtBJ + TDH1j4jUHYpdO93SUE3wTiEX58Mj48tJ5kYpjBhUlc8CgYEA7PG3ORGqZtfCiNmj + CxvPtQiFC+ogf+v8cMQtrKVTgpnI2pxzG+cSXYvL4cnyY2JnwqarWorUic8JU2e2 + EhW53PWUg7VpITlLsqOpATIDiviFAN4qOOxgDt5v0C1PyB3aXe2B5VA3IgczssyR + OLy7p/DhOpu2bqnpKyIkAuzZgFc= + """), + + + // Version: 3 (0x2) + // Serial Number: 4099 (0x1003) + // Signature Algorithm: sha256WithRSAEncryption + // Issuer: C = US, ST = California, O = Example, OU = Test + // Validity + // Not Before: Feb 25 20:33:59 2022 GMT + // Not After : Feb 19 20:33:59 2042 GMT + // Subject: C = US, ST = California, O = Example, OU = Test, CN = Do-Not-Reply + // Subject Public Key Info: + // Public Key Algorithm: rsaEncryption + // RSA Public-Key: (2048 bit) + CLIENT_EXAMPLE_RSA("RSA", + """ + -----BEGIN CERTIFICATE----- + MIIDZjCCAk6gAwIBAgICEAMwDQYJKoZIhvcNAQELBQAwQzELMAkGA1UEBhMCVVMx + EzARBgNVBAgTCkNhbGlmb3JuaWExEDAOBgNVBAoTB0V4YW1wbGUxDTALBgNVBAsT + BFRlc3QwHhcNMjIwMjI1MjAzMzU5WhcNNDIwMjE5MjAzMzU5WjBaMQswCQYDVQQG + EwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEQMA4GA1UECgwHRXhhbXBsZTENMAsG + A1UECwwEVGVzdDEVMBMGA1UEAwwMRG8tTm90LVJlcGx5MIIBIjANBgkqhkiG9w0B + AQEFAAOCAQ8AMIIBCgKCAQEA2yJgm3Lthr+97vdEWTb4zaNuLTa/DkCXdmVNIQk9 + kVn2hjZrPc+JghBCaWpohGVTQ+zxplIJXk+QVZ0ePEimE7ahBClz4MlAgMpt1uxy + mYYUAsSZDCaFUI9Cpx1f0BiSWu330196K/AfRIoT+/SOZucnpbepxyrt+Az5SKrH + TJR/OSqeX4XKGPoRI96pKxDOV8pY5/I9h9yKGuxfufbpOdVODngVLcMKgBAkiD+2 + sguEHM+iGLx970+W6yycu1dFY1CAgWLUF3evUxe8avwePgx7lTFXnNueYt96Ny9v + L1o/WzoBe3z1mTl5Qb//3tYbXn8vdiDYm0dT8wImpDbpvwIDAQABo00wSzAJBgNV + HRMEAjAAMB0GA1UdDgQWBBSXqW/B1BVjNgowSwa3MBiHMkzp6zAfBgNVHSMEGDAW + gBQuMz1/AmcLdOnVBgzwc0vLrRu2XTANBgkqhkiG9w0BAQsFAAOCAQEABIMAjT5T + lZDV/1wmdKCyJQJ7WUjA44N5/yBGtEmpAJ0VM7/COnk8lqiYxrk50wK7lt0tiklX + 4aLqbAgnDc27z9AQGHOqB69dZprGQT9PsTByjK6i7KPGs30ygyND41j0rju/GM2e + 3xprZbusODENRyL196QV4ai0WVe1hEvv0wTMIcnXYmZHMP8ArdVRHWaDQF6zW0Mh + QbFqklt5W0ZIl2ZmC8z7z2Z6jv/BYyDo3U96LfdCWsEKxSKiX/PGHqZu4D3A4VSE + 0+fE7cX61kgRdGvZJgFjtYxtfkXd1HlyJ48Dqilzl+rvgvR5XA68zijjN0khPhml + wZhPIOCIaWMZYw== + -----END CERTIFICATE-----""", + + """ + MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDbImCbcu2Gv73u + 90RZNvjNo24tNr8OQJd2ZU0hCT2RWfaGNms9z4mCEEJpamiEZVND7PGmUgleT5BV + nR48SKYTtqEEKXPgyUCAym3W7HKZhhQCxJkMJoVQj0KnHV/QGJJa7ffTX3or8B9E + ihP79I5m5yelt6nHKu34DPlIqsdMlH85Kp5fhcoY+hEj3qkrEM5Xyljn8j2H3Ioa + 7F+59uk51U4OeBUtwwqAECSIP7ayC4Qcz6IYvH3vT5brLJy7V0VjUICBYtQXd69T + F7xq/B4+DHuVMVec255i33o3L28vWj9bOgF7fPWZOXlBv//e1htefy92INibR1Pz + AiakNum/AgMBAAECggEAW0WxWW4AMyzwDnWdWU+FSBm3TUvNPkF3FNBS1NzFcSI4 + hWRrPJ6R1sOw9blleSe/C77IVA89abPYGWDM9C0KR5G89T/SzSDmJf6qy2dGwF1R + PmnmmWH+CzTwfSzF+KYTZ55QqBDPkTd9vo2Ij1woaAIFyId8RsHBxpyYxESlqGY4 + C6IzEqxFQ0obHXasNR+dP4iOWS4ONhxeUHixcrDHxbmoqmHt0WuJwXhlOjxHgr+i + lUPTe5y+Y2B1gVNYrN4KlDTJqJ6lu4n6MFQ46jhfddzTk3uiEOTVWK6nE8Cf0NM7 + djTzTcR8xAVpoY5XDlk0aBfEd8Np7TLSjV4vU3J04QKBgQD6scazH/H9Yu9ZbR7w + EeN/k7uDDlgahWg8/93syzdFtSNIRGvdalNMhTfM/zXaM/Cl63gvZilWxC+56Uvg + 6QC+rBUwzZrm7ryb6hT6Zyoo4w72bw3jGOJ3e2/bclSLrAcJnL/1Gq87J3CS16wl + NIHrlOlY8orToEdki+6HaagyEQKBgQDfxZz4Uqsa+jDO/rEm959+nz2RkaXYu1Ld + DhYONxmlw69/BbwzOvzr88qKNbd+b+oIK8kpm7Lvpc2/cuqItTFdehmw+tGhMWYo + XizKCeKeCByFTjXI2/PEPUHMy0D8M68Tx/Hq0NbIYqCyzkaamHhXpuJGftxGfd3/ + U0NB4WGOzwKBgQDgnyN7YfcwY1I0XUqoLk8aA2Oy5MpaUQh6B4RwZBENO2T2np/L + TzZ9zKuX2WAGOB26fMY+KhqGLNjaike7qOpK7eM6zC6sFmMWjGHpj0A+TFwewJi/ + z48zIX2zMbjBQQ05NqLkWdmCdi8u02HiIC78x3thgEiVn/n4BE1gNXJIEQKBgEdr + dfcXw36/vZZDWd07CU/LmUX9u3YaC498MHPnCCuM8lVTSkb7m7/fNpS4IlGbfJGR + EApUpF6yh6GEFvD9C71u/AYtd3zAHH/j1t3BG/AeXKP7W1U5RmsqtfacJKiaAlYI + 6eBtOTAJsop/Ja+v3DD1laC0Wq+w+orEU2ISgiWnAoGBAK9/9m3RCYPNYzS/PQ2B + AgE2FQRuY8FXxHegZo2tBBwIojPeVHO1OoThYVNgiQfW9k27dFkRwXVAtt6Jqgax + fvOby8rWRStXH2qHVyvHicceL7iXs6v2bX20Szsy44eMkoFfAImea6ZdErLdVWvI + fxlYpTIVpBt3Nu2BRJn28ili + """); + + final String keyAlgo; + final String certStr; + final String privateKeyStr; + + // Trusted certificate + private final static SSLExampleCert[] TRUSTED_CERTS = { + SSLExampleCert.CA_RSA + }; + + // Server certificate. + private final static SSLExampleCert[] SERVER_CERTS = { + SSLExampleCert.SERVER_EXAMPLE_RSA + }; + + // Client certificate. + private final static SSLExampleCert[] CLIENT_CERTS = { + SSLExampleCert.CLIENT_EXAMPLE_RSA + }; + + // Set "www.example.com" to loopback address. + static { + String hostsFileName = System.getProperty("jdk.net.hosts.file"); + String loopbackHostname = + InetAddress.getLoopbackAddress().getHostAddress() + + " " + "www.example.com www.example.com.\n"; + try (FileWriter writer= new FileWriter(hostsFileName, false)) { + writer.write(loopbackHostname); + } catch (IOException ioe) { + // ignore + } + } + + SSLExampleCert(String keyAlgo, String certStr, String privateKeyStr) { + this.keyAlgo = keyAlgo; + this.certStr = certStr; + this.privateKeyStr = privateKeyStr; + } + + public static SSLContext createClientSSLContext() throws Exception { + return createSSLContext(TRUSTED_CERTS, CLIENT_CERTS); + } + + public static SSLContext createServerSSLContext() throws Exception { + return createSSLContext(TRUSTED_CERTS, SERVER_CERTS); + } + + private static SSLContext createSSLContext( + SSLExampleCert[] trustedCerts, + SSLExampleCert[] endEntityCerts) throws Exception { + char[] passphrase = "passphrase".toCharArray(); + + // Generate certificate from cert string. + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + + // Import the trusted certs. + KeyStore ts = null; // trust store + if (trustedCerts != null && trustedCerts.length != 0) { + ts = KeyStore.getInstance("PKCS12"); + ts.load(null, null); + + Certificate[] trustedCert = new Certificate[trustedCerts.length]; + for (int i = 0; i < trustedCerts.length; i++) { + try (ByteArrayInputStream is = new ByteArrayInputStream( + trustedCerts[i].certStr.getBytes())) { + trustedCert[i] = cf.generateCertificate(is); + } + + ts.setCertificateEntry("trusted-cert-" + + trustedCerts[i].name(), trustedCert[i]); + } + } + + // Import the key materials. + KeyStore ks = null; // trust store + if (endEntityCerts != null && endEntityCerts.length != 0) { + ks = KeyStore.getInstance("PKCS12"); + ks.load(null, null); + + for (SSLExampleCert endEntityCert : endEntityCerts) { + // generate the private key. + PKCS8EncodedKeySpec priKeySpec = new PKCS8EncodedKeySpec( + Base64.getMimeDecoder() + .decode(endEntityCert.privateKeyStr)); + KeyFactory kf = + KeyFactory.getInstance( + endEntityCert.keyAlgo); + PrivateKey priKey = kf.generatePrivate(priKeySpec); + + // generate certificate chain + Certificate keyCert; + try (ByteArrayInputStream is = new ByteArrayInputStream( + endEntityCert.certStr.getBytes())) { + keyCert = cf.generateCertificate(is); + } + + Certificate[] chain = new Certificate[]{keyCert}; + + // import the key entry. + ks.setKeyEntry("end-entity-cert-" + + endEntityCert.name(), + priKey, passphrase, chain); + } + } + + // Set the date for the verifying of certificates. + DateFormat df = new SimpleDateFormat("MM/dd/yyyy"); + Date verifyingDate = df.parse("02/02/2023"); + + // Create an SSLContext object. + TrustManagerFactory tmf = + TrustManagerFactory.getInstance("PKIX"); + if (ts != null) { + PKIXBuilderParameters pkixParams = + new PKIXBuilderParameters(ts, null); + pkixParams.setDate(verifyingDate); + pkixParams.setRevocationEnabled(false); + ManagerFactoryParameters managerFactoryParameters = + new CertPathTrustManagerParameters(pkixParams); + tmf.init(managerFactoryParameters); + } else { + tmf.init((KeyStore)null); + } + + SSLContext context = SSLContext.getInstance("TLS"); + if (endEntityCerts != null && endEntityCerts.length != 0) { + KeyManagerFactory kmf = + KeyManagerFactory.getInstance("NewSunX509"); + kmf.init(ks, passphrase); + + KeyManager[] kms = kmf.getKeyManagers(); + if (kms != null && kms.length != 0) { + KeyManager km = kms[0]; + Field verificationDateField = + km.getClass().getDeclaredField("verificationDate"); + verificationDateField.setAccessible(true); + verificationDateField.set(km, verifyingDate); + } + + context.init(kms, tmf.getTrustManagers(), null); + } else { + context.init(null, tmf.getTrustManagers(), null); + } + + return context; + } +} diff --git a/test/jdk/javax/net/ssl/templates/SSLSocketSSLEngineTemplate.java b/test/jdk/javax/net/ssl/templates/SSLSocketSSLEngineTemplate.java index 54b4e3c68407208023d54c04ec4c163ccb914fc6..cbb42ee1a699bc0a2f2e91e6c26bee587451fcc9 100644 --- a/test/jdk/javax/net/ssl/templates/SSLSocketSSLEngineTemplate.java +++ b/test/jdk/javax/net/ssl/templates/SSLSocketSSLEngineTemplate.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 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 @@ -349,13 +349,13 @@ public class SSLSocketSSLEngineTemplate { } finally { if (serverException != null) { if (clientException != null) { - serverException.initCause(clientException); + serverException.addSuppressed(clientException); } throw serverException; } if (clientException != null) { if (serverException != null) { - clientException.initCause(serverException); + clientException.addSuppressed(serverException); } throw clientException; } diff --git a/test/jdk/javax/net/ssl/templates/SSLSocketTemplate.java b/test/jdk/javax/net/ssl/templates/SSLSocketTemplate.java index ce2e3ee121be403a8b5c3ad0f9f73ea0794c2212..f200752d2a79985906378cdd82b37becfff9d97d 100644 --- a/test/jdk/javax/net/ssl/templates/SSLSocketTemplate.java +++ b/test/jdk/javax/net/ssl/templates/SSLSocketTemplate.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -544,7 +544,7 @@ public class SSLSocketTemplate { */ if ((local != null) && (remote != null)) { // If both failed, return the curthread's exception. - local.initCause(remote); + local.addSuppressed(remote); exception = local; } else if (local != null) { exception = local; diff --git a/test/jdk/javax/print/PrintServiceLookup/FlushCustomClassLoader.java b/test/jdk/javax/print/PrintServiceLookup/FlushCustomClassLoader.java index 6e0a25a69d0a56beb09b5edb5186f50475b1e29f..4ec95fb75354e0e83651a5ec089e90d67e0be58b 100644 --- a/test/jdk/javax/print/PrintServiceLookup/FlushCustomClassLoader.java +++ b/test/jdk/javax/print/PrintServiceLookup/FlushCustomClassLoader.java @@ -34,6 +34,9 @@ import javax.print.PrintServiceLookup; * @test * @bug 8273831 * @summary Tests custom class loader cleanup + * @library /javax/swing/regtesthelpers + * @build Util + * @run main/timeout=60/othervm -mx32m FlushCustomClassLoader */ public final class FlushCustomClassLoader { @@ -42,12 +45,8 @@ public final class FlushCustomClassLoader { int attempt = 0; while (loader.get() != null) { - if (++attempt > 10) { - throw new RuntimeException("Too many attempts: " + attempt); - } - System.gc(); - Thread.sleep(1000); - System.out.println("Not freed, attempt: " + attempt); + Util.generateOOME(); + System.out.println("Not freed, attempt: " + attempt++); } } diff --git a/test/jdk/javax/print/attribute/StreamServiceAttributeTest.java b/test/jdk/javax/print/attribute/StreamServiceAttributeTest.java new file mode 100644 index 0000000000000000000000000000000000000000..093bbfd747cb0333f5f8b9376c17772eb0b55ca2 --- /dev/null +++ b/test/jdk/javax/print/attribute/StreamServiceAttributeTest.java @@ -0,0 +1,94 @@ +/* + * 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. + */ + +/* + * @test + * @bug 4884570 + * @summary Attribute support reporting should be consistent +*/ + +import java.io.ByteArrayOutputStream; +import java.io.OutputStream; + +import javax.print.DocFlavor; +import javax.print.StreamPrintService; +import javax.print.StreamPrintServiceFactory; +import javax.print.attribute.Attribute; +import javax.print.attribute.standard.Chromaticity; +import javax.print.attribute.standard.Media; +import javax.print.attribute.standard.OrientationRequested; +import javax.print.attribute.standard.SheetCollate; +import javax.print.attribute.standard.Sides; + +public class StreamServiceAttributeTest { + + private static boolean allSupported = true; + private static Class[] attrClasses = { + Chromaticity.class, + Media.class, + OrientationRequested.class, + SheetCollate.class, + Sides.class, + }; + + public static void main(String args[]) { + + StreamPrintServiceFactory[] fact = + StreamPrintServiceFactory.lookupStreamPrintServiceFactories( + null, null); + + if (fact.length == 0) { + return; + } + OutputStream out = new ByteArrayOutputStream(); + StreamPrintService sps = fact[0].getPrintService(out); + for (Class<? extends Attribute> ac : attrClasses) { + test(sps, ac); + } + + if (!allSupported) { + throw new RuntimeException("Inconsistent support reported"); + } + } + + private static void test(StreamPrintService sps, + Class<? extends Attribute> ac) { + if (!sps.isAttributeCategorySupported(ac)) { + return; + } + DocFlavor[] dfs = sps.getSupportedDocFlavors(); + for (DocFlavor f : dfs) { + Attribute[] attrs = (Attribute[]) + sps.getSupportedAttributeValues(ac, f, null); + if (attrs == null) { + continue; + } + for (Attribute a : attrs) { + if (!sps.isAttributeValueSupported(a, f, null)) { + allSupported = false; + System.out.println("Unsupported : " + f + " " + a); + } + } + } + } +} diff --git a/test/jdk/javax/sound/midi/Gervill/ModelIdentifier/NewModelIdentifierStringStringInt.java b/test/jdk/javax/sound/midi/Gervill/ModelIdentifier/NewModelIdentifierStringStringInt.java index 348012f54bfccdcdd5515f2d92ca3ef4a64506cf..fdd6e542440970e3fe75f021ded039de75cf52c3 100644 --- a/test/jdk/javax/sound/midi/Gervill/ModelIdentifier/NewModelIdentifierStringStringInt.java +++ b/test/jdk/javax/sound/midi/Gervill/ModelIdentifier/NewModelIdentifierStringStringInt.java @@ -37,7 +37,7 @@ import com.sun.media.sound.*; public class NewModelIdentifierStringStringInt { public static void main(String[] args) throws Exception { - ModelIdentifier id = new ModelIdentifier("test","a",1);; + ModelIdentifier id = new ModelIdentifier("test","a",1); if(!id.getObject().equals("test")) throw new RuntimeException("id.getObject() doesn't return \"test\"!"); if(!id.getVariable().equals("a")) diff --git a/test/jdk/javax/sound/midi/Gervill/SoftChannel/NoteOff.java b/test/jdk/javax/sound/midi/Gervill/SoftChannel/NoteOff.java index 0330628c8b61fe479bb17abaff61ac79bc0e52cb..eaff35c2c3cef03355497a48fe52f098e796a8a8 100644 --- a/test/jdk/javax/sound/midi/Gervill/SoftChannel/NoteOff.java +++ b/test/jdk/javax/sound/midi/Gervill/SoftChannel/NoteOff.java @@ -56,7 +56,7 @@ public class NoteOff { assertEquals(v[0].active, true); channel.noteOff(60); soft.read(1); - v = soft.synth.getVoiceStatus();; + v = soft.synth.getVoiceStatus(); assertEquals(v[0].active, false); soft.close(); diff --git a/test/jdk/javax/sound/midi/Gervill/SoftChannel/NoteOff2.java b/test/jdk/javax/sound/midi/Gervill/SoftChannel/NoteOff2.java index 71172a049daaecdf8728cb1983b5e820fa9bc95e..8143ee846a5537f6c09d5fd22cc82be5ade3c2fa 100644 --- a/test/jdk/javax/sound/midi/Gervill/SoftChannel/NoteOff2.java +++ b/test/jdk/javax/sound/midi/Gervill/SoftChannel/NoteOff2.java @@ -56,7 +56,7 @@ public class NoteOff2 { assertEquals(v[0].active, true); channel.noteOff(60); soft.read(1); - v = soft.synth.getVoiceStatus();; + v = soft.synth.getVoiceStatus(); assertEquals(v[0].active, false); soft.close(); diff --git a/test/jdk/javax/sound/sampled/Clip/DataPusherThreadCheck.java b/test/jdk/javax/sound/sampled/Clip/DataPusherThreadCheck.java new file mode 100644 index 0000000000000000000000000000000000000000..733a317ab37cebeac6ab265310e5295997a476b6 --- /dev/null +++ b/test/jdk/javax/sound/sampled/Clip/DataPusherThreadCheck.java @@ -0,0 +1,89 @@ +/* + * 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. + */ + +import static javax.sound.sampled.AudioFormat.Encoding.PCM_SIGNED; +import static javax.sound.sampled.AudioSystem.NOT_SPECIFIED; + +import javax.sound.sampled.AudioFileFormat; +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioInputStream; +import javax.sound.sampled.AudioSystem; +import java.applet.AudioClip; +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.InputStream; +import java.nio.file.Files; + +/* + * @test + * @key headful + * @bug 8279673 + * @summary Verify no NPE creating threads + * @run main/othervm DataPusherThreadCheck + */ +public class DataPusherThreadCheck { + + public static void main(String[] args) throws Exception { + // Prepare the audio file + File file = new File("audio.wav"); + try { + AudioFormat format = + new AudioFormat(PCM_SIGNED, 44100, 8, 1, 1, 44100, false); + int dataSize = 6000*1000 * format.getFrameSize(); + InputStream in = new ByteArrayInputStream(new byte[dataSize]); + AudioInputStream audioStream = new AudioInputStream(in, format, NOT_SPECIFIED); + AudioSystem.write(audioStream, AudioFileFormat.Type.WAVE, file); + } catch (Exception ignored) { + return; // the test is not applicable + } + try { + checkThread(file); + } finally { + Files.delete(file.toPath()); + } + } + + private static void checkThread(File file) throws Exception { + AudioClip clip = (AudioClip) file.toURL().getContent(); + clip.loop(); + try { + Thread.sleep(2000); + } catch (InterruptedException ignored) { + } + boolean found = isDataPushedThreadExist(); + clip.stop(); + if (!found) { + throw new RuntimeException("Thread 'DataPusher' isn't found"); + } + } + + private static boolean isDataPushedThreadExist() { + for (Thread t : Thread.getAllStackTraces().keySet()) { + if (t.getName().equals("DataPusher")) { + return true; + } + } + return false; + } + +} diff --git a/test/jdk/javax/sound/sampled/Clip/SetPositionHang.java b/test/jdk/javax/sound/sampled/Clip/SetPositionHang.java index e6d924a7505f1cd37baf121169656a06cdc5318c..0805dfc45a03a89e1d69da9bcc92f283a4bdd104 100644 --- a/test/jdk/javax/sound/sampled/Clip/SetPositionHang.java +++ b/test/jdk/javax/sound/sampled/Clip/SetPositionHang.java @@ -28,7 +28,7 @@ import javax.sound.sampled.LineUnavailableException; /** * @test - * @bug 8266421 + * @bug 8266421 8269091 * @summary Tests that Clip.setFramePosition/setMicrosecondPosition do not hang. */ public final class SetPositionHang implements Runnable { diff --git a/test/jdk/javax/sql/testng/test/rowset/BaseRowSetTests.java b/test/jdk/javax/sql/testng/test/rowset/BaseRowSetTests.java index 95883556a057ead3ec21c4201219494b9c93960e..c1d2d9a2ed018754ad16160d817226ab012b1f29 100644 --- a/test/jdk/javax/sql/testng/test/rowset/BaseRowSetTests.java +++ b/test/jdk/javax/sql/testng/test/rowset/BaseRowSetTests.java @@ -355,7 +355,7 @@ public class BaseRowSetTests extends CommonRowSetTests { Blob aBlob = new SerialBlob(new StubBlob()); Clob aClob = new SerialClob(new StubClob()); Reader rdr = new StringReader(query); - InputStream is = new StringBufferInputStream(query);; + InputStream is = new StringBufferInputStream(query); brs = new StubBaseRowSet(); brs.setBytes(1, bytes); brs.setAsciiStream(2, is, query.length()); diff --git a/test/jdk/javax/sql/testng/test/rowset/serial/SQLInputImplTests.java b/test/jdk/javax/sql/testng/test/rowset/serial/SQLInputImplTests.java index a6756a13a4ad40f623d93c1164171ac1e2a7ef52..95cc508828a08f918c04f6ac858b9d64e6a0d22c 100644 --- a/test/jdk/javax/sql/testng/test/rowset/serial/SQLInputImplTests.java +++ b/test/jdk/javax/sql/testng/test/rowset/serial/SQLInputImplTests.java @@ -183,7 +183,7 @@ public class SQLInputImplTests extends BaseTest { */ @Test(enabled = true) public void test10() throws Exception { - URL u = new URL("http://www.oracle.com/");; + URL u = new URL("http://www.oracle.com/"); Object[] values = {u}; SQLInputImpl sqli = new SQLInputImpl(values, map); URL u2 = sqli.readURL(); diff --git a/test/jdk/javax/sql/testng/test/rowset/serial/SerialArrayTests.java b/test/jdk/javax/sql/testng/test/rowset/serial/SerialArrayTests.java index 077ce43da85f38f2601eb1d58c5b299b4578bbd1..345315b7f05faead6506bb53b62e84bfe3b154cc 100644 --- a/test/jdk/javax/sql/testng/test/rowset/serial/SerialArrayTests.java +++ b/test/jdk/javax/sql/testng/test/rowset/serial/SerialArrayTests.java @@ -230,7 +230,7 @@ public class SerialArrayTests extends BaseTest { @Test public void test18() throws Exception { SerialArray sa = new SerialArray(a); - SerialArray sa1 = serializeDeserializeObject(sa);; + SerialArray sa1 = serializeDeserializeObject(sa); assertTrue(sa.equals(sa1)); } } diff --git a/test/jdk/javax/sql/testng/test/rowset/serial/SerialExceptionTests.java b/test/jdk/javax/sql/testng/test/rowset/serial/SerialExceptionTests.java index ff963ae7ba84db25d1c9148c13e397c308192c2f..8ef215584a94bdbac29cc2da00099e1e2d8a1c59 100644 --- a/test/jdk/javax/sql/testng/test/rowset/serial/SerialExceptionTests.java +++ b/test/jdk/javax/sql/testng/test/rowset/serial/SerialExceptionTests.java @@ -108,6 +108,6 @@ public class SerialExceptionTests extends BaseTest { assertTrue(ex1.getMessage().equals(reason) && ex1.getSQLState() == null && ex1.getCause() == null - && ex1.getErrorCode() == 0);; + && ex1.getErrorCode() == 0); } } diff --git a/test/jdk/javax/sql/testng/test/rowset/serial/SerialStructTests.java b/test/jdk/javax/sql/testng/test/rowset/serial/SerialStructTests.java index 84a0ff2aaaf73904b15aeb0014a993e62ea5f98b..79ac2421c9aca44037d254dd187cb3ad40806a47 100644 --- a/test/jdk/javax/sql/testng/test/rowset/serial/SerialStructTests.java +++ b/test/jdk/javax/sql/testng/test/rowset/serial/SerialStructTests.java @@ -134,7 +134,7 @@ public class SerialStructTests extends BaseTest { @Test public void test08() throws Exception { SerialStruct ss = new SerialStruct(struct, map); - SerialStruct ss1 = serializeDeserializeObject(ss);; + SerialStruct ss1 = serializeDeserializeObject(ss); assertTrue(ss.equals(ss1)); } } diff --git a/test/jdk/javax/swing/DefaultButtonModel/DefaultButtonModelCrashTest.java b/test/jdk/javax/swing/DefaultButtonModel/DefaultButtonModelCrashTest.java index efcf335a54d0cdbdbf8e85f79b4952f00ecd4d40..14190ce65d304f65da3bb0582f4dfe7b8853a700 100644 --- a/test/jdk/javax/swing/DefaultButtonModel/DefaultButtonModelCrashTest.java +++ b/test/jdk/javax/swing/DefaultButtonModel/DefaultButtonModelCrashTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -21,23 +21,21 @@ * questions. */ -/** +/* * @test * @bug 8182577 - * @summary Verifies if moving focus via custom ButtonModel causes crash + * @summary Verifies if moving focus to JToggleButton with DefaultButtonModel + * that is added to a ButtonGroup doesn't throw ClassCastException * @key headful * @run main DefaultButtonModelCrashTest */ import java.awt.BorderLayout; -import java.awt.Container; -import java.awt.Point; import java.awt.Robot; import java.awt.event.KeyEvent; import javax.swing.ButtonModel; import javax.swing.DefaultButtonModel; import javax.swing.JCheckBox; -import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JTextField; @@ -45,8 +43,6 @@ import javax.swing.SwingUtilities; public class DefaultButtonModelCrashTest { private JFrame frame = null; - private JPanel panel; - private volatile Point p = null; public static void main(String[] args) throws Exception { new DefaultButtonModelCrashTest(); @@ -58,29 +54,34 @@ public class DefaultButtonModelCrashTest { robot.setAutoDelay(200); SwingUtilities.invokeAndWait(() -> go()); robot.waitForIdle(); + robot.delay(1000); robot.keyPress(KeyEvent.VK_TAB); robot.keyRelease(KeyEvent.VK_TAB); robot.delay(100); robot.keyPress(KeyEvent.VK_TAB); robot.keyRelease(KeyEvent.VK_TAB); } finally { - if (frame != null) { SwingUtilities.invokeAndWait(()->frame.dispose()); } + SwingUtilities.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); } } private void go() { - frame = new JFrame(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); - Container contentPane = frame.getContentPane(); - ButtonModel model = new DefaultButtonModel(); + ButtonModel model = new DefaultButtonModel(); JCheckBox check = new JCheckBox("a bit broken"); check.setModel(model); - panel = new JPanel(new BorderLayout()); + + JPanel panel = new JPanel(new BorderLayout()); panel.add(new JTextField("Press Tab (twice?)"), BorderLayout.NORTH); panel.add(check); - contentPane.add(panel); + + frame.getContentPane().add(panel); frame.setLocationRelativeTo(null); frame.pack(); frame.setVisible(true); diff --git a/test/jdk/javax/swing/JButton/4659800/EnterKeyActivatesButton.java b/test/jdk/javax/swing/JButton/4659800/EnterKeyActivatesButton.java new file mode 100644 index 0000000000000000000000000000000000000000..9bbb794fdbe886bd758f0d080d6cc7a09e2776d5 --- /dev/null +++ b/test/jdk/javax/swing/JButton/4659800/EnterKeyActivatesButton.java @@ -0,0 +1,124 @@ +/* + * 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. + */ + +import java.awt.event.KeyEvent; +import java.awt.Robot; +import java.util.Arrays; +import java.util.List; + +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import javax.swing.UnsupportedLookAndFeelException; + +import static java.util.stream.Collectors.toList; + +/* + * @test + * @key headful + * @requires (os.family == "windows") + * @bug 4659800 + * @summary Check whether pressing <Enter> key generates + * ActionEvent on focused Button or not. This is applicable only for + * WindowsLookAndFeel and WindowsClassicLookAndFeel. + * @run main EnterKeyActivatesButton + */ +public class EnterKeyActivatesButton { + private static volatile boolean buttonPressed; + private static JFrame frame; + + public static void main(String[] s) throws Exception { + runTest(); + } + + private static void setLookAndFeel(String lafName) { + try { + UIManager.setLookAndFeel(lafName); + } catch (UnsupportedLookAndFeelException ignored) { + System.out.println("Ignoring Unsupported L&F: " + lafName); + } catch (ClassNotFoundException | InstantiationException + | IllegalAccessException e) { + throw new RuntimeException(e); + } + } + + private static void disposeFrame() { + if (frame != null) { + frame.dispose(); + frame = null; + } + } + + private static void createUI() { + frame = new JFrame(); + JPanel panel = new JPanel(); + JButton focusedButton = new JButton("Button1"); + focusedButton.addActionListener(e -> buttonPressed = true); + panel.add(focusedButton); + panel.add(new JButton("Button2")); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + frame.add(panel); + frame.pack(); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + focusedButton.requestFocusInWindow(); + } + + public static void runTest() throws Exception { + Robot robot = new Robot(); + robot.setAutoDelay(100); + // Consider only Windows and Windows Classic LnFs. + List<String> winlafs = Arrays.stream(UIManager.getInstalledLookAndFeels()) + .filter(laf -> laf.getName().startsWith("Windows")) + .map(laf -> laf.getClassName()) + .collect(toList()); + + for (String laf : winlafs) { + try { + buttonPressed = false; + System.out.println("Testing L&F: " + laf); + SwingUtilities.invokeAndWait(() -> { + setLookAndFeel(laf); + createUI(); + }); + + robot.waitForIdle(); + robot.keyPress(KeyEvent.VK_ENTER); + robot.keyRelease(KeyEvent.VK_ENTER); + robot.waitForIdle(); + + if (buttonPressed) { + System.out.println("Test Passed for L&F: " + laf); + } else { + throw new RuntimeException("Test Failed, button not pressed for L&F: " + laf); + } + + } finally { + SwingUtilities.invokeAndWait(EnterKeyActivatesButton::disposeFrame); + } + } + + } +} diff --git a/test/jdk/javax/swing/JButton/4659800/SpaceKeyActivatesButton.java b/test/jdk/javax/swing/JButton/4659800/SpaceKeyActivatesButton.java new file mode 100644 index 0000000000000000000000000000000000000000..a54c97993a097f6a7968789e8f42a4078e0bb791 --- /dev/null +++ b/test/jdk/javax/swing/JButton/4659800/SpaceKeyActivatesButton.java @@ -0,0 +1,152 @@ +/* + * 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. + */ + +import java.awt.Robot; +import java.awt.event.FocusAdapter; +import java.awt.event.FocusEvent; +import java.awt.event.KeyEvent; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import javax.swing.UnsupportedLookAndFeelException; + + +import static java.util.stream.Collectors.toList; + +/* + * @test + * @key headful + * @bug 8281738 + * @summary Check whether pressing <Space> key generates + * ActionEvent on focused Button or not. + * @run main SpaceKeyActivatesButton + */ +public class SpaceKeyActivatesButton { + + private static volatile boolean buttonPressed; + private static JFrame frame; + private static JButton focusedButton; + private static CountDownLatch buttonGainedFocusLatch; + + public static void main(String[] s) throws Exception { + runTest(); + } + + public static void runTest() throws Exception { + Robot robot = new Robot(); + robot.setAutoDelay(100); + robot.setAutoWaitForIdle(true); + + List<String> lafs = Arrays.stream(UIManager.getInstalledLookAndFeels()) + .map(laf -> laf.getClassName()) + .collect(toList()); + for (String laf : lafs) { + buttonGainedFocusLatch = new CountDownLatch(1); + try { + buttonPressed = false; + System.out.println("Testing laf : " + laf); + AtomicBoolean lafSetSuccess = new AtomicBoolean(false); + SwingUtilities.invokeAndWait(() -> { + lafSetSuccess.set(setLookAndFeel(laf)); + // Call createUI() only if setting laf succeeded + if (lafSetSuccess.get()) { + createUI(); + } + }); + // If setting laf failed, then just get next laf and continue + if (!lafSetSuccess.get()) { + continue; + } + robot.waitForIdle(); + + // Wait until the button2 gains focus. + if (!buttonGainedFocusLatch.await(3, TimeUnit.SECONDS)) { + throw new RuntimeException("Test Failed, waited too long, " + + "but the button can't gain focus for laf : " + laf); + } + + robot.keyPress(KeyEvent.VK_SPACE); + robot.keyRelease(KeyEvent.VK_SPACE); + + if (buttonPressed) { + System.out.println("Test Passed for laf : " + laf); + } else { + throw new RuntimeException("Test Failed, button not pressed for laf : " + laf); + } + + } finally { + SwingUtilities.invokeAndWait(SpaceKeyActivatesButton::disposeFrame); + } + } + + } + + private static boolean setLookAndFeel(String lafName) { + try { + UIManager.setLookAndFeel(lafName); + } catch (UnsupportedLookAndFeelException ignored) { + System.out.println("Ignoring Unsupported laf : " + lafName); + return false; + } catch (ClassNotFoundException | InstantiationException + | IllegalAccessException e) { + throw new RuntimeException(e); + } + return true; + } + + private static void createUI() { + frame = new JFrame(); + JPanel panel = new JPanel(); + panel.add(new JButton("Button1")); + focusedButton = new JButton("Button2"); + focusedButton.addActionListener(e -> buttonPressed = true); + focusedButton.addFocusListener(new FocusAdapter() { + @Override + public void focusGained(FocusEvent e) { + buttonGainedFocusLatch.countDown(); + } + }); + panel.add(focusedButton); + + frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + frame.add(panel); + frame.pack(); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + focusedButton.requestFocusInWindow(); + } + + private static void disposeFrame() { + if (frame != null) { + frame.dispose(); + frame = null; + } + } +} diff --git a/test/jdk/javax/swing/JButton/8151303/PressedIconTest.java b/test/jdk/javax/swing/JButton/8151303/PressedIconTest.java index 5a3f2a7066deec9c0eddedbea44cf2e7e507c41c..d5bbebc4bc1b761867530824bf63128568655226 100644 --- a/test/jdk/javax/swing/JButton/8151303/PressedIconTest.java +++ b/test/jdk/javax/swing/JButton/8151303/PressedIconTest.java @@ -26,7 +26,9 @@ import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Point; +import java.awt.Rectangle; import java.awt.Robot; +import java.awt.Toolkit; import java.awt.event.InputEvent; import java.awt.image.BaseMultiResolutionImage; import java.awt.image.BufferedImage; @@ -56,37 +58,56 @@ public class PressedIconTest { private static volatile double scale = -1; private static volatile int centerX; private static volatile int centerY; + private static volatile Point location; + // move away from cursor + private final static int OFFSET_X = -20; + private final static int OFFSET_Y = -20; public static void main(String[] args) throws Exception { Robot robot = new Robot(); - robot.setAutoDelay(50); + robot.setAutoDelay(100); SwingUtilities.invokeAndWait(() -> createAndShowGUI()); robot.waitForIdle(); + robot.delay(1000); SwingUtilities.invokeAndWait(() -> { scale = frame.getGraphicsConfiguration().getDefaultTransform() .getScaleX(); - Point location = frame.getLocation(); + location = frame.getLocation(); Dimension size = frame.getSize(); centerX = location.x + size.width / 2; centerY = location.y + size.height / 2; }); robot.waitForIdle(); + System.out.println("scale " + scale); + robot.mouseMove(centerX, centerY); - robot.mousePress(InputEvent.BUTTON1_MASK); robot.waitForIdle(); - Thread.sleep(100); - Color color = robot.getPixelColor(centerX, centerY); - robot.mouseRelease(InputEvent.BUTTON1_MASK); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.waitForIdle(); + Color color = robot.getPixelColor(centerX - OFFSET_X, centerY - OFFSET_Y); + + Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); + Rectangle screen = new Rectangle(0, 0, (int) screenSize.getWidth(), (int) screenSize.getHeight()); + BufferedImage img = robot.createScreenCapture(screen); + javax.imageio.ImageIO.write(img, "png", new java.io.File("image.png")); + + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + SwingUtilities.invokeAndWait(() -> frame.dispose()); - if ((scale == 1 && !similar(color, COLOR_1X)) - || (scale == 2 && !similar(color, COLOR_2X))) { - throw new RuntimeException("Colors are different!"); + if (scale == 1 && !similar(color, COLOR_1X)) { + System.out.println("color " + color + " COLOR_1X " + COLOR_1X); + throw new RuntimeException("Colors is different for scale=1!"); + } + if (scale == 2 && !similar(color, COLOR_2X)) { + System.out.println("color " + color + " COLOR_2X " + COLOR_2X); + throw new RuntimeException("Colors is different for scale=2!"); } + System.out.println("Test Passed"); } private static void createAndShowGUI() { @@ -108,6 +129,8 @@ public class PressedIconTest { panel.add(button, BorderLayout.CENTER); frame.getContentPane().add(panel); + frame.setUndecorated(true); + frame.setLocationRelativeTo(null); frame.setVisible(true); } diff --git a/test/jdk/javax/swing/JButton/HtmlButtonImageTest/HtmlButtonImageTest.java b/test/jdk/javax/swing/JButton/HtmlButtonImageTest/HtmlButtonImageTest.java new file mode 100644 index 0000000000000000000000000000000000000000..b7fed2cff030d6b527b0174281e20b194cc7442b --- /dev/null +++ b/test/jdk/javax/swing/JButton/HtmlButtonImageTest/HtmlButtonImageTest.java @@ -0,0 +1,115 @@ +/* + * 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. +*/ + +/* + * @test + * @bug 8015854 + * @requires (os.family == "mac") + * @summary Tests HTML image as JButton text for unwanted padding on macOS Aqua LAF + * @run main HtmlButtonImageTest + */ + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics2D; +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.JButton; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; + +import static java.awt.image.BufferedImage.TYPE_INT_ARGB; + +public final class HtmlButtonImageTest { + private static JButton button; + private static Path testDir; + private static BufferedImage image; + + private static final int BUTTON_HEIGHT = 37; + private static final int BUTTON_WIDTH = 37; + private static final int SQUARE_HEIGHT = 19; + private static final int SQUARE_WIDTH = 19; + private static final int centerX = BUTTON_WIDTH / 2; + private static final int centerY = BUTTON_HEIGHT / 2; + private static final int minX = centerX - (SQUARE_WIDTH / 2); + private static final int minY = centerY - (SQUARE_HEIGHT / 2); + private static final int maxX = centerX + (SQUARE_WIDTH / 2); + private static final int maxY = centerY + (SQUARE_HEIGHT / 2); + + public static void main(String[] args) throws Exception { + UIManager.setLookAndFeel("com.apple.laf.AquaLookAndFeel"); + testDir = Path.of(System.getProperty("test.classes", ".")); + generateRedSquare(); + + SwingUtilities.invokeAndWait(HtmlButtonImageTest::createButton); + SwingUtilities.invokeAndWait(HtmlButtonImageTest::paintButton); + + testImageCentering(image.getRGB(centerX, centerY), + image.getRGB(minX, minY), + image.getRGB(minX, maxY), + image.getRGB(maxX, minY), + image.getRGB(maxX, maxY)); + } + + private static void generateRedSquare() throws IOException { + BufferedImage bImg = new BufferedImage(SQUARE_WIDTH, SQUARE_HEIGHT, + TYPE_INT_ARGB); + Graphics2D cg = bImg.createGraphics(); + cg.setColor(Color.RED); + cg.fillRect(0, 0, SQUARE_WIDTH, SQUARE_HEIGHT); + ImageIO.write(bImg, "png", new File(testDir + "/red_square.png")); + } + + private static void createButton() { + button = new JButton(); + button.setSize(new Dimension(BUTTON_WIDTH, BUTTON_HEIGHT)); + button.setText("<html><img src='" + + testDir.resolve("red_square.png").toUri() + "'></html>"); + } + + private static void paintButton() { + image = new BufferedImage(BUTTON_HEIGHT, BUTTON_WIDTH, TYPE_INT_ARGB); + Graphics2D graphics2D = image.createGraphics(); + button.paint(graphics2D); + graphics2D.dispose(); + } + + private static boolean checkRedColor(int rgb) { + return (rgb == Color.RED.getRGB()); + } + + private static void testImageCentering(int... colors) throws IOException { + for (int c : colors) { + if (!checkRedColor(c)) { + ImageIO.write(image, "png", + new File(testDir + "/fail_image.png")); + throw new RuntimeException("HTML image not centered in button"); + } + } + System.out.println("Passed"); + } +} diff --git a/test/jdk/javax/swing/JCheckBox/ImageCheckboxFocus/ImageCheckboxTest.java b/test/jdk/javax/swing/JCheckBox/ImageCheckboxFocus/ImageCheckboxTest.java index b63973229a209642cbe8fa5fa5833614afe5caa4..844692bf45442779d46d883b29e656083a8d9076 100644 --- a/test/jdk/javax/swing/JCheckBox/ImageCheckboxFocus/ImageCheckboxTest.java +++ b/test/jdk/javax/swing/JCheckBox/ImageCheckboxFocus/ImageCheckboxTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -23,18 +23,19 @@ import java.awt.Color; import java.awt.Component; -import java.awt.Dimension; import java.awt.Graphics; import java.awt.image.BufferedImage; import java.io.File; import javax.imageio.ImageIO; import javax.swing.Icon; import javax.swing.JCheckBox; +import javax.swing.UIManager; +import javax.swing.UnsupportedLookAndFeelException; /* * @test * @key headful - * @bug 8216358 + * @bug 8216358 8279586 * @summary [macos] The focus is invisible when tab to "Image Radio Buttons" and "Image CheckBoxes" * @library ../../regtesthelpers/ * @build Util @@ -43,16 +44,45 @@ import javax.swing.JCheckBox; public class ImageCheckboxTest { public static void main(String[] args) throws Exception { - new ImageCheckboxTest().performTest(); + ImageCheckboxTest test = new ImageCheckboxTest(); + boolean passed = true; + // There are bugs found in various LaFs that needs to be fixed + // to enable testing there + String[] skip = { + "GTK+", // JDK-8281580 + "Nimbus" // JDK-8281581 + }; + testloop: + for (UIManager.LookAndFeelInfo laf : UIManager.getInstalledLookAndFeels()) { + for (String s : skip) { + if (s.equals(laf.getName())) { + continue testloop; + } + } + passed = passed && test.performTest(laf); + } + + if(!passed) { + throw new RuntimeException("Test failed"); + } } - public void performTest() throws Exception { + public boolean performTest(UIManager.LookAndFeelInfo laf) throws Exception { BufferedImage imageNoFocus = new BufferedImage(100, 50, BufferedImage.TYPE_INT_ARGB); BufferedImage imageFocus = new BufferedImage(100, 50, BufferedImage.TYPE_INT_ARGB); + BufferedImage imageFocusNotPainted = new BufferedImage(100, 50, + BufferedImage.TYPE_INT_ARGB); + boolean success = true; + try { + UIManager.setLookAndFeel(laf.getClassName()); + } catch (UnsupportedLookAndFeelException ulaf) { + return true; + } CustomCheckBox checkbox = new CustomCheckBox("Test", new MyIcon(Color.GREEN)); + checkbox.setFocusPainted(true); checkbox.setSize(100, 50); checkbox.setFocused(false); checkbox.paint(imageNoFocus.createGraphics()); @@ -60,10 +90,32 @@ public class ImageCheckboxTest { checkbox.paint(imageFocus.createGraphics()); if (Util.compareBufferedImages(imageFocus, imageNoFocus)) { - ImageIO.write(imageFocus, "png", new File("imageFocus.png")); - ImageIO.write(imageNoFocus, "png", new File("imageNoFocus.png")); - throw new Exception("Changing focus is not visualized"); + File folder = new File(laf.getName()); + if (!folder.exists()) { + folder.mkdir(); + } + ImageIO.write(imageFocus, "png", new File(folder, "/imageFocus.png")); + ImageIO.write(imageNoFocus, "png", new File(folder, "/imageNoFocus.png")); + System.err.println(laf.getName() + ": Changing of focus is not visualized"); + success = false; + } + + checkbox.setFocusPainted(false); + checkbox.paint(imageFocusNotPainted.createGraphics()); + + if (!Util.compareBufferedImages(imageFocusNotPainted, imageNoFocus)) { + File folder = new File(laf.getName()); + if (!folder.exists()) { + folder.mkdir(); + } + ImageIO.write(imageFocusNotPainted, "png", + new File(folder,"imageFocusNotPainted.png")); + ImageIO.write(imageFocus, "png", new File(folder, "imageFocus.png")); + ImageIO.write(imageNoFocus, "png", new File(folder, "imageNoFocus.png")); + System.err.println(laf.getName() + ": setFocusPainted(false) is ignored"); + success = false; } + return success; } class MyIcon implements Icon { diff --git a/test/jdk/javax/swing/JComboBox/4231298/JComboBoxPrototypeDisplayValueTest.java b/test/jdk/javax/swing/JComboBox/4231298/JComboBoxPrototypeDisplayValueTest.java new file mode 100644 index 0000000000000000000000000000000000000000..bd71c4fabacee90ce5679fe9c76416c533383613 --- /dev/null +++ b/test/jdk/javax/swing/JComboBox/4231298/JComboBoxPrototypeDisplayValueTest.java @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2003, 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. + */ + +import java.awt.Color; +import java.awt.Component; +import java.awt.Robot; +import java.util.Arrays; +import java.util.List; +import java.util.Vector; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.stream.Collectors; +import java.util.stream.IntStream; +import javax.swing.JButton; +import javax.swing.JComboBox; +import javax.swing.JFrame; +import javax.swing.JList; +import javax.swing.JPanel; +import javax.swing.ListCellRenderer; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import javax.swing.UIManager.LookAndFeelInfo; +import javax.swing.UnsupportedLookAndFeelException; + +import static javax.swing.UIManager.getInstalledLookAndFeels; + +/* + * @test + * @key headful + * @bug 4231298 + * @summary This testcase tests the RFE 4231298 request, JComboBox Custom + * Renderer should not be called for non displaying elements if + * setPrototypeDisplayValue() has been invoked. + * @run main JComboBoxPrototypeDisplayValueTest + */ +public class JComboBoxPrototypeDisplayValueTest { + + private static Robot robot; + private static JFrame frame; + private static JComboBox buttonComboBox; + private static volatile int count; + + public static void main(String[] args) throws Exception { + robot = new Robot(); + robot.setAutoWaitForIdle(true); + robot.setAutoDelay(200); + List<String> lafs = Arrays.stream(getInstalledLookAndFeels()) + .map(LookAndFeelInfo::getClassName) + .collect(Collectors.toList()); + for (final String laf : lafs) { + try { + count = 0; + AtomicBoolean lafSetSuccess = new AtomicBoolean(false); + SwingUtilities.invokeAndWait(() -> { + lafSetSuccess.set(setLookAndFeel(laf)); + if (lafSetSuccess.get()) { + createUI(); + } + }); + if (!lafSetSuccess.get()) { + continue; + } + robot.waitForIdle(); + + SwingUtilities + .invokeAndWait(() -> buttonComboBox.getPreferredSize()); + + robot.waitForIdle(); + if (count > 6) { + System.out.println("Test Failed"); + throw new RuntimeException( + "Custom Renderer got called " + count + " times, " + + "even after calling setPrototypeDisplayValue(), " + + "but the expected maximum is 6 times for " + laf); + } else { + System.out.println("Test Passed for " + laf); + } + } finally { + SwingUtilities.invokeAndWait( + JComboBoxPrototypeDisplayValueTest::disposeFrame); + } + } + } + + public static void createUI() { + Vector data = new Vector(IntStream.rangeClosed(1, 100).boxed() + .map(i -> new JButton("" + i)) + .collect(Collectors.toList())); + buttonComboBox = new JComboBox(data); + ButtonRenderer renderer = new ButtonRenderer(); + buttonComboBox.setRenderer(renderer); + buttonComboBox.setMaximumRowCount(25); + + // New method introduced in Java 1.4 + buttonComboBox.setPrototypeDisplayValue(new JButton("111111111")); + + frame = new JFrame(); + JPanel panel = new JPanel(); + panel.add(buttonComboBox); + frame.getContentPane().add(panel); + frame.setSize(200, 100); + frame.setLocationRelativeTo(null); + frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + frame.setVisible(true); + } + + private static boolean setLookAndFeel(String lafName) { + try { + UIManager.setLookAndFeel(lafName); + } catch (UnsupportedLookAndFeelException ignored) { + System.out.println("Ignoring Unsupported L&F: " + lafName); + return false; + } catch (ClassNotFoundException | InstantiationException + | IllegalAccessException e) { + throw new RuntimeException(e); + } + return true; + } + + private static void disposeFrame() { + if (frame != null) { + frame.dispose(); + frame = null; + } + } + + /** + * Custom ListCellRenderer used for the drop down portion and the text + * portion of the ComboBox. + */ + private static class ButtonRenderer implements ListCellRenderer { + private final Color selectedBackground; + private final Color selectedForeground; + private final Color background; + private final Color foreground; + + public ButtonRenderer() { + selectedBackground = Color.BLUE; + selectedForeground = Color.YELLOW; + background = Color.GRAY; + foreground = Color.RED; + } + + public Component getListCellRendererComponent(JList list, Object value, + int index, + boolean isSelected, + boolean cellHasFocus) { + JButton button = (JButton) value; + System.out.println( + "getListCellRendererComponent index = " + index + ", " + + "isSelected = " + isSelected + ", cellHasFocus = " + + cellHasFocus); + + button.setBackground(isSelected ? selectedBackground : background); + button.setForeground(isSelected ? selectedForeground : foreground); + + count++; + System.out.println("Value of the Counter is " + count); + + return button; + } + + } + +} diff --git a/test/jdk/javax/swing/JEditorPane/4330998/JEditorPaneSetTextNullTest.java b/test/jdk/javax/swing/JEditorPane/4330998/JEditorPaneSetTextNullTest.java new file mode 100644 index 0000000000000000000000000000000000000000..5b543894ef6c613e4361c843088a2f9e700867b4 --- /dev/null +++ b/test/jdk/javax/swing/JEditorPane/4330998/JEditorPaneSetTextNullTest.java @@ -0,0 +1,45 @@ + /* + * Copyright (c) 2013, 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. + */ + + import javax.swing.JEditorPane; + import javax.swing.SwingUtilities; + + /* + * @test + * @bug 4330998 + * @summary Verifies that JEditorPane.setText(null) doesn't throw NullPointerException. + * @run main JEditorPaneSetTextNullTest + */ + public class JEditorPaneSetTextNullTest { + + public static void main(String[] args) throws Exception { + try { + SwingUtilities.invokeAndWait(() -> new JEditorPane().setText(null)); + System.out.println("Test passed"); + } catch (Exception e) { + throw new RuntimeException("Test failed, caught Exception " + e + + " when calling JEditorPane.setText(null)"); + } + } + + } diff --git a/test/jdk/javax/swing/JEditorPane/4666101/JEditorPaneNavigationTest.java b/test/jdk/javax/swing/JEditorPane/4666101/JEditorPaneNavigationTest.java new file mode 100644 index 0000000000000000000000000000000000000000..c88e284556e69f802cc3fde23235f5486c040d58 --- /dev/null +++ b/test/jdk/javax/swing/JEditorPane/4666101/JEditorPaneNavigationTest.java @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2002, 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. + */ + +import java.awt.Dimension; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.Toolkit; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import java.io.File; +import java.io.IOException; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicReference; +import java.util.stream.Collectors; +import javax.imageio.ImageIO; +import javax.swing.JEditorPane; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import javax.swing.UIManager.LookAndFeelInfo; +import javax.swing.UnsupportedLookAndFeelException; + +import static javax.swing.UIManager.getInstalledLookAndFeels; + +/* + * @test + * @key headful + * @bug 4666101 + * @summary Verifies that in a JEditorPane, the down arrow is honoured after you + add text on a line preceding a blank line. + * @run main JEditorPaneNavigationTest + */ +public class JEditorPaneNavigationTest { + + private static volatile int caretPos; + private static JEditorPane jep; + private static JFrame frame; + private static Robot robot; + + public static void main(String[] args) throws Exception { + robot = new Robot(); + robot.setAutoWaitForIdle(true); + robot.setAutoDelay(100); + + List<String> lafs = Arrays.stream(getInstalledLookAndFeels()) + .map(LookAndFeelInfo::getClassName) + .collect(Collectors.toList()); + for (final String laf : lafs) { + try { + AtomicBoolean lafSetSuccess = new AtomicBoolean(false); + SwingUtilities.invokeAndWait(() -> { + lafSetSuccess.set(setLookAndFeel(laf)); + if (lafSetSuccess.get()) { + createUI(); + } + }); + if (!lafSetSuccess.get()) { + continue; + } + robot.waitForIdle(); + + AtomicReference<Point> pt = new AtomicReference<>(); + SwingUtilities.invokeAndWait(() -> pt.set(jep.getLocationOnScreen())); + caretPos = 0; + final Point jEditorLoc = pt.get(); + + // Click on JEditorPane + robot.mouseMove(jEditorLoc.x + 50, jEditorLoc.y + 50); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + + keyType(KeyEvent.VK_ENTER); + keyType(KeyEvent.VK_ENTER); + + typeSomeText(); + + keyType(KeyEvent.VK_UP); + keyType(KeyEvent.VK_UP); + + typeSomeText(); + + keyType(KeyEvent.VK_DOWN); + + System.out.println(" test1 caret pos = " + caretPos); + + // Check whether the caret position is at the expected value 5 + if (caretPos != 5) { + captureScreen(); + throw new RuntimeException("Test Failed in " + laf + + " expected initial caret position is 5, but actual is " + caretPos); + } + + keyType(KeyEvent.VK_DOWN); + + System.out.println(" test2 caret pos = " + caretPos); + + // Check whether the caret position is at the expected value 10 + if (caretPos != 10) { + captureScreen(); + throw new RuntimeException("Test Failed in " + laf + + " expected final caret position is 10, but actual is " + caretPos); + } + + System.out.println("Test Passed in " + laf); + + } finally { + SwingUtilities.invokeAndWait(JEditorPaneNavigationTest::disposeFrame); + } + } + } + + private static void captureScreen() { + Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); + try { + ImageIO.write( + robot.createScreenCapture(new Rectangle(0, 0, screenSize.width, screenSize.height)), + "png", + new File("JEditorPaneNavigationTest.png") + ); + } catch (IOException ignore) { + } + } + + private static void typeSomeText() { + keyType(KeyEvent.VK_T); + keyType(KeyEvent.VK_E); + keyType(KeyEvent.VK_X); + keyType(KeyEvent.VK_T); + } + + private static void keyType(int keyCode) { + robot.keyPress(keyCode); + robot.keyRelease(keyCode); + } + + + private static void createUI() { + frame = new JFrame(); + jep = new JEditorPane(); + jep.setPreferredSize(new Dimension(100, 100)); + jep.addCaretListener(e -> caretPos = jep.getCaretPosition()); + jep.setEditable(true); + JPanel panel = new JPanel(); + panel.add(jep); + frame.add(panel); + frame.setLocationRelativeTo(null); + frame.setAlwaysOnTop(true); + frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + frame.pack(); + frame.setVisible(true); + } + + private static boolean setLookAndFeel(String lafName) { + try { + UIManager.setLookAndFeel(lafName); + } catch (UnsupportedLookAndFeelException ignored) { + System.out.println("Ignoring Unsupported laf : " + lafName); + return false; + } catch (ClassNotFoundException | InstantiationException + | IllegalAccessException e) { + throw new RuntimeException(e); + } + return true; + } + + private static void disposeFrame() { + if (frame != null) { + frame.dispose(); + frame = null; + } + } + +} diff --git a/test/jdk/javax/swing/JFileChooser/8277463/UNCFileChooserTest.java b/test/jdk/javax/swing/JFileChooser/8277463/UNCFileChooserTest.java new file mode 100644 index 0000000000000000000000000000000000000000..738b5da762edada9faa13f6774b6c60a86c99ca7 --- /dev/null +++ b/test/jdk/javax/swing/JFileChooser/8277463/UNCFileChooserTest.java @@ -0,0 +1,124 @@ +/* + * 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. + */ + +/* @test + @bug 8277463 + @requires (os.family == "windows") + @summary JFileChooser with Metal L&F doesn't show non-canonical UNC path in - Look in + @run main/manual UNCFileChooserTest +*/ + +import javax.swing.JButton; +import javax.swing.JFileChooser; +import javax.swing.JFrame; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JTextArea; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import javax.swing.WindowConstants; +import java.awt.BorderLayout; +import java.awt.FlowLayout; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +public class UNCFileChooserTest { + private static volatile CountDownLatch countDownLatch; + private static JFrame instructionFrame; + private static JFrame testFrame; + private static volatile boolean testPassed = false; + + private static boolean validatePlatform() { + String osName = System.getProperty("os.name"); + if (osName == null) { + throw new RuntimeException("Name of the current OS could not be" + + " retrieved."); + } + return osName.startsWith("Windows"); + } + + private static void createInstructionUI() throws Exception { + UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel"); + String instructions = + "1. Enter the non-canonical UNC path of the directory to test\n" + + "example: \\\\pc-name\\dir\\..\n" + + "2. An \"Open File\" file chooser dialog pops up\n" + + "3. Check the \"Look in\" Combobox at the top for quickly changing directory is not empty\n" + + "4. Close the file chooser Dialog\n" + + "5. If the \"Look in\" Combobox is not empty then press PASS else press FAIL\n"; + instructionFrame = new JFrame("InstructionFrame"); + JTextArea textArea = new JTextArea(instructions); + textArea.setEditable(false); + final JButton passButton = new JButton("PASS"); + passButton.addActionListener((e) -> { + testPassed = true; + instructionFrame.dispose(); + countDownLatch.countDown(); + }); + final JButton failButton = new JButton("FAIL"); + failButton.addActionListener((e) -> { + instructionFrame.dispose(); + countDownLatch.countDown(); + }); + + JPanel mainPanel = new JPanel(new BorderLayout()); + mainPanel.add(textArea, BorderLayout.CENTER); + + JPanel buttonPanel = new JPanel(new FlowLayout()); + buttonPanel.add(passButton); + buttonPanel.add(failButton); + mainPanel.add(buttonPanel, BorderLayout.SOUTH); + instructionFrame.setDefaultCloseOperation( + WindowConstants.DISPOSE_ON_CLOSE); + instructionFrame.setBounds(0,0,500,500); + instructionFrame.add(mainPanel); + instructionFrame.pack(); + instructionFrame.setVisible(true); + } + + private static void showOpenDialog() throws Exception { + String path = JOptionPane.showInputDialog(testFrame, "Enter the non-canonical UNC path of the directory to test.\nexample: \\\\pc-name\\dir\\.."); + if (path == null) { + throw new RuntimeException("Enter the directory path to test."); + } + new JFileChooser(path).showOpenDialog(null); + } + + public static void main(String[] args) throws Exception { + if (!validatePlatform()) { + System.out.println("This test is only for MS Windows OS."); + return; + } + countDownLatch = new CountDownLatch(1); + UNCFileChooserTest uncFileChooserTest = + new UNCFileChooserTest(); + + uncFileChooserTest.createInstructionUI(); + uncFileChooserTest.showOpenDialog(); + countDownLatch.await(15, TimeUnit.MINUTES); + + if(!testPassed) { + throw new RuntimeException("Test failed!"); + } + } +} diff --git a/test/jdk/javax/swing/JFileChooser/FileSystemView/ShellFolderStackOverflow.java b/test/jdk/javax/swing/JFileChooser/FileSystemView/ShellFolderStackOverflow.java new file mode 100644 index 0000000000000000000000000000000000000000..52bc51bd3f6d1242005ca456d64d76dcd6a39da3 --- /dev/null +++ b/test/jdk/javax/swing/JFileChooser/FileSystemView/ShellFolderStackOverflow.java @@ -0,0 +1,39 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8277299 + * @requires (os.family == "windows") + * @summary STACK_OVERFLOW in Java_sun_awt_shell_Win32ShellFolder2_getIconBits + * @run main/othervm -Xss320k ShellFolderStackOverflow + */ +import javax.swing.UIManager; + +public class ShellFolderStackOverflow { + public static void main(final String... args) throws Exception { + UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel"); + // With default stack size for 32-bit VM next call will cause VM crash + UIManager.getIcon("Tree.openIcon"); + } +} diff --git a/test/jdk/javax/swing/JFrame/NSTexturedJFrame/NSTexturedJFrame.java b/test/jdk/javax/swing/JFrame/NSTexturedJFrame/NSTexturedJFrame.java index e82d1f5360ea43997e6585a76a139fa50ce8d74a..a5521fa179c928fce34bad9b2a997fba0c421b28 100644 --- a/test/jdk/javax/swing/JFrame/NSTexturedJFrame/NSTexturedJFrame.java +++ b/test/jdk/javax/swing/JFrame/NSTexturedJFrame/NSTexturedJFrame.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -36,7 +36,7 @@ import jdk.test.lib.Platform; * @key headful * @bug 7124513 * @requires (os.family == "mac") - * @summary We should support NSTexturedBackgroundWindowMask style on OSX. + * @summary We should support NSWindowStyleMaskTexturedBackground style on OSX. * @library /test/lib * /lib/client * @build ExtendedRobot jdk.test.lib.Platform diff --git a/test/jdk/javax/swing/JInternalFrame/8020708/bug8020708.java b/test/jdk/javax/swing/JInternalFrame/8020708/bug8020708.java index efd13ff768680e536696719131b35452787776d6..8f78178ada62ec971628c779396b84db6ea1c98b 100644 --- a/test/jdk/javax/swing/JInternalFrame/8020708/bug8020708.java +++ b/test/jdk/javax/swing/JInternalFrame/8020708/bug8020708.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -41,7 +41,7 @@ import javax.swing.UIManager; * @summary NLS: mnemonics missing in SwingSet2/JInternalFrame demo * @library ../../regtesthelpers * @build Util - * @run main bug8020708 + * @run main/timeout=300 bug8020708 */ public class bug8020708 { @@ -68,6 +68,7 @@ public class bug8020708 { public static void main(String[] args) throws Exception { for (Locale locale : SUPPORTED_LOCALES) { + System.out.println("locale: " + locale); for (String laf : LOOK_AND_FEELS) { Locale.setDefault(locale); if (!installLookAndFeel(laf)) { @@ -80,7 +81,7 @@ public class bug8020708 { static void testInternalFrameMnemonic(Locale locale) throws Exception { Robot robot = new Robot(); - robot.setAutoDelay(250); + robot.setAutoDelay(100); robot.setAutoWaitForIdle(true); SwingUtilities.invokeAndWait(new Runnable() { @@ -142,6 +143,7 @@ public class bug8020708 { UIManager.LookAndFeelInfo[] infos = UIManager.getInstalledLookAndFeels(); for (UIManager.LookAndFeelInfo info : infos) { if (info.getClassName().contains(lafName)) { + System.out.println("LookAndFeel: " + info.getClassName()); UIManager.setLookAndFeel(info.getClassName()); return true; } diff --git a/test/jdk/javax/swing/JInternalFrame/8069348/bug8069348.java b/test/jdk/javax/swing/JInternalFrame/8069348/bug8069348.java index 939a3da2ce68075f82221d322856706457531b5c..ac253b6ccf56b93d95ed76c075e4d0f7aa6b20b5 100644 --- a/test/jdk/javax/swing/JInternalFrame/8069348/bug8069348.java +++ b/test/jdk/javax/swing/JInternalFrame/8069348/bug8069348.java @@ -23,9 +23,12 @@ import java.awt.BorderLayout; import java.awt.Color; +import java.awt.Dimension; import java.awt.Graphics; import java.awt.Rectangle; import java.awt.Robot; +import java.awt.Toolkit; +import java.awt.image.BufferedImage; import java.awt.event.InputEvent; import javax.swing.JDesktopPane; import javax.swing.JFrame; @@ -52,6 +55,10 @@ public class bug8069348 { private static final Color DESKTOPPANE_COLOR = Color.YELLOW; private static final Color FRAME_COLOR = Color.ORANGE; + // move away from cursor + private final static int OFFSET_X = -20; + private final static int OFFSET_Y = -20; + private static JFrame frame; private static JInternalFrame internalFrame; @@ -66,7 +73,7 @@ public class bug8069348 { SwingUtilities.invokeAndWait(bug8069348::createAndShowGUI); Robot robot = new Robot(); - robot.setAutoDelay(50); + robot.setAutoDelay(100); robot.waitForIdle(); Rectangle screenBounds = getInternalFrameScreenBounds(); @@ -79,27 +86,43 @@ public class bug8069348 { robot.mouseMove(x, y); robot.waitForIdle(); - robot.mousePress(InputEvent.BUTTON1_MASK); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); robot.mouseMove(x + dx, y + dy); - robot.mouseRelease(InputEvent.BUTTON1_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); robot.waitForIdle(); int cx = screenBounds.x + screenBounds.width + dx / 2; int cy = screenBounds.y + screenBounds.height + dy / 2; robot.mouseMove(cx, cy); - if (!FRAME_COLOR.equals(robot.getPixelColor(cx, cy))) { + robot.waitForIdle(); + Color color = robot.getPixelColor(cx - OFFSET_X, cy - OFFSET_Y); + + if (!FRAME_COLOR.equals(color)) { + System.out.println("cx " + cx + " cy " + cy); + System.err.println("FRAME_COLOR Red: " + FRAME_COLOR.getRed() + "; Green: " + FRAME_COLOR.getGreen() + "; Blue: " + FRAME_COLOR.getBlue()); + System.err.println("Pixel color Red: " + color.getRed() + "; Green: " + color.getGreen() + "; Blue: " + color.getBlue()); + + Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); + Rectangle screen = new Rectangle(0, 0, (int) screenSize.getWidth(), (int) screenSize.getHeight()); + BufferedImage img = robot.createScreenCapture(screen); + javax.imageio.ImageIO.write(img, "png", new java.io.File("image.png")); + throw new RuntimeException("Internal frame is not correctly dragged!"); } } finally { - if (frame != null) { - frame.dispose(); - } + SwingUtilities.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); } + System.out.println("Test Passed"); } private static boolean isSupported() { String d3d = System.getProperty("sun.java2d.d3d"); + System.out.println("d3d " + d3d); return !Boolean.getBoolean(d3d) || getOSType() == OSType.WINDOWS; } @@ -138,6 +161,7 @@ public class bug8069348 { panel.add(desktopPane, BorderLayout.CENTER); frame.add(panel); frame.setSize(WIN_WIDTH, WIN_HEIGHT); + frame.setLocationRelativeTo(null); frame.setVisible(true); frame.requestFocus(); } diff --git a/test/jdk/javax/swing/JList/4618767/JListSelectedElementTest.java b/test/jdk/javax/swing/JList/4618767/JListSelectedElementTest.java new file mode 100644 index 0000000000000000000000000000000000000000..5eca0f3232ef655e1a5915768035bc89ad38d1a5 --- /dev/null +++ b/test/jdk/javax/swing/JList/4618767/JListSelectedElementTest.java @@ -0,0 +1,222 @@ +/* + * Copyright (c) 2002, 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. + */ + +import java.awt.Robot; +import java.awt.event.FocusAdapter; +import java.awt.event.FocusEvent; +import java.awt.event.KeyEvent; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicReference; +import java.util.stream.Collectors; +import javax.swing.JFrame; +import javax.swing.JList; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import javax.swing.UIManager.LookAndFeelInfo; +import javax.swing.UnsupportedLookAndFeelException; +import javax.swing.event.MenuEvent; +import javax.swing.event.MenuListener; + + +import static javax.swing.UIManager.getInstalledLookAndFeels; + +/* + * @test + * @key headful + * @bug 4618767 + * @summary This test confirms that typing a letter while a JList has focus now makes the selection + * not jump to the item whose text starts with that letter if that typed letter is accompanied + * by modifier keys such as ALT or CTRL(eg: ALT+F). + * @run main JListSelectedElementTest + */ +public class JListSelectedElementTest { + + private static final int FILE_MENU = KeyEvent.VK_F; + private static JFrame frame; + private static JList<String> list; + private static Robot robot; + private static CountDownLatch listGainedFocusLatch; + private static CountDownLatch menuSelectedEventLatch; + + public static void main(String[] args) throws Exception { + runTest(); + } + + public static void runTest() throws Exception { + robot = new Robot(); + robot.setAutoWaitForIdle(true); + robot.setAutoDelay(200); + + final boolean isMac = System.getProperty("os.name") + .toLowerCase() + .contains("os x"); + + List<String> lafs = Arrays.stream(getInstalledLookAndFeels()) + .map(LookAndFeelInfo::getClassName) + .collect(Collectors.toList()); + for (final String laf : lafs) { + listGainedFocusLatch = new CountDownLatch(1); + menuSelectedEventLatch = new CountDownLatch(1); + try { + AtomicBoolean lafSetSuccess = new AtomicBoolean(false); + SwingUtilities.invokeAndWait(() -> { + lafSetSuccess.set(setLookAndFeel(laf)); + if (lafSetSuccess.get()) { + createUI(); + } + }); + if (!lafSetSuccess.get()) { + continue; + } + robot.waitForIdle(); + + // Wait until the list gains focus. + if (!listGainedFocusLatch.await(3, TimeUnit.SECONDS)) { + throw new RuntimeException("Waited too long, but can't gain focus for list"); + } + + // Select element named as 'bill' + hitKeys(KeyEvent.VK_B); + + // Assertion check to verify that the selected node is 'bill' + AtomicReference<String> elementSel = new AtomicReference<>(); + SwingUtilities.invokeAndWait(() -> elementSel.set(list.getSelectedValue())); + final String elementSelBefore = elementSel.get(); + if (!"bill".equals(elementSelBefore)) { + throw new RuntimeException("Test failed for " + laf + + " as the list element selected: " + elementSel + + " is not the expected one 'bill'" + ); + } + + // Now operate Menu using Mnemonics, different key combinations for different OSes. + // For most OSes it's ALT+F; on macOS it's ALT+CNTRL+F except for Nimbus LaF. + if (isMac && !laf.contains("Nimbus")) { + hitKeys(KeyEvent.VK_ALT, KeyEvent.VK_CONTROL, FILE_MENU); + } else { + hitKeys(KeyEvent.VK_ALT, FILE_MENU); + } + + // Wait until the menu got selected. + if (!menuSelectedEventLatch.await(3, TimeUnit.SECONDS)) { + throw new RuntimeException("Waited too long, but can't select menu using mnemonics for " + laf); + } + + hitKeys(KeyEvent.VK_ENTER); + + AtomicReference<String> elementSelAfter = new AtomicReference<>(); + SwingUtilities.invokeAndWait(() -> elementSelAfter.set(list.getSelectedValue())); + + // As per the fix of BugID 4618767, the list element selection should not change + if (!elementSelBefore.equals(elementSelAfter.get())) { + throw new RuntimeException("Test failed for " + laf + + " as list.getSelectedValue() before = " + elementSel + + " not equal to list.getSelectedValue() after pressing Enter = " + elementSelAfter + ); + } + System.out.println("Test passed for laf: " + laf); + + } finally { + SwingUtilities.invokeAndWait(JListSelectedElementTest::disposeFrame); + } + } + } + + private static void hitKeys(int... keys) { + for (int key : keys) { + robot.keyPress(key); + } + + for (int i = keys.length - 1; i >= 0; i--) { + robot.keyRelease(keys[i]); + } + } + + private static void createUI() { + frame = new JFrame(); + list = new JList<>(new String[]{"anaheim", "bill", "chicago", "dingo", "ernie", "freak"}); + list.addFocusListener(new FocusAdapter() { + @Override + public void focusGained(FocusEvent e) { + listGainedFocusLatch.countDown(); + } + }); + JMenu menu = new JMenu("File"); + menu.setMnemonic(FILE_MENU); + JMenuItem menuItem = new JMenuItem("Dummy"); + menu.add(menuItem); + menu.addMenuListener(new MenuListener() { + @Override + public void menuSelected(MenuEvent e) { + menuSelectedEventLatch.countDown(); + } + + @Override + public void menuDeselected(MenuEvent e) { + } + + @Override + public void menuCanceled(MenuEvent e) { + } + }); + + JMenuBar menuBar = new JMenuBar(); + menuBar.add(menu); + + frame.setJMenuBar(menuBar); + frame.setContentPane(list); + frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + frame.pack(); + frame.setAlwaysOnTop(true); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } + + private static boolean setLookAndFeel(String lafName) { + try { + UIManager.setLookAndFeel(lafName); + } catch (UnsupportedLookAndFeelException ignored) { + System.out.println("Ignoring Unsupported L&F: " + lafName); + return false; + } catch (ClassNotFoundException | InstantiationException + | IllegalAccessException e) { + throw new RuntimeException(e); + } + return true; + } + + private static void disposeFrame() { + if (frame != null) { + frame.dispose(); + frame = null; + } + } + +} diff --git a/test/jdk/javax/swing/JMenuBar/MenuBarRTLBug.java b/test/jdk/javax/swing/JMenuBar/MenuBarRTLBug.java new file mode 100644 index 0000000000000000000000000000000000000000..454ae03b126d118c8544b4442818bc4dd2c876b3 --- /dev/null +++ b/test/jdk/javax/swing/JMenuBar/MenuBarRTLBug.java @@ -0,0 +1,178 @@ +/* + * 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. + */ +import java.awt.BorderLayout; +import java.awt.ComponentOrientation; +import java.awt.Point; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import java.awt.Robot; + +import javax.swing.JFrame; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import javax.swing.event.MenuEvent; +import javax.swing.event.MenuListener; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import javax.swing.UnsupportedLookAndFeelException; + +/* + * @test + * @key headful + * @bug 8277369 + * @summary Verifies arrow traversal in RTL orientation in JMenuBar + */ +public class MenuBarRTLBug { + + static JFrame frame; + static JMenuBar menuBar; + static JMenu firstMenu; + static JMenuItem a; + static JMenuItem b; + static JMenu secondMenu; + static JMenuItem c; + static JMenuItem d; + static JMenu thirdMenu; + static JMenuItem e; + static JMenuItem f; + static JMenu forthMenu; + static JMenu fifthMenu; + + static Point p; + static int width; + static int height; + + static volatile boolean passed = false; + + private static void setLookAndFeel(UIManager.LookAndFeelInfo laf) { + try { + UIManager.setLookAndFeel(laf.getClassName()); + } catch (UnsupportedLookAndFeelException ignored) { + System.out.println("Unsupported L&F: " + laf.getClassName()); + } catch (ClassNotFoundException | InstantiationException + | IllegalAccessException e) { + throw new RuntimeException(e); + } + } + + public static void main(String[] args) throws Exception { + + for (UIManager.LookAndFeelInfo laf : UIManager.getInstalledLookAndFeels()) { + System.out.println("Testing L&F: " + laf.getClassName()); + passed = false; + SwingUtilities.invokeAndWait(() -> setLookAndFeel(laf)); + try { + SwingUtilities.invokeAndWait(() -> { + frame = new JFrame(); + frame.setLayout(new BorderLayout()); + + firstMenu = new JMenu("first"); + a = new JMenuItem("a"); + b = new JMenuItem("b"); + firstMenu.add(a); + firstMenu.add(b); + + secondMenu = new JMenu("second"); + c = new JMenuItem("c"); + d = new JMenuItem("d"); + secondMenu.add(c); + secondMenu.add(d); + secondMenu.addMenuListener(new MenuListener() { + @Override + public void menuSelected(MenuEvent e) { + passed = true; + } + @Override + public void menuDeselected(MenuEvent e) { + } + + @Override + public void menuCanceled(MenuEvent e) { + } + }); + + thirdMenu = new JMenu("third"); + e = new JMenuItem("e"); + f = new JMenuItem("f"); + thirdMenu.add(e); + thirdMenu.add(f); + + forthMenu = new JMenu("fourth"); + e = new JMenuItem("e"); + f = new JMenuItem("f"); + forthMenu.add(e); + forthMenu.add(f); + + fifthMenu = new JMenu("fifth"); + e = new JMenuItem("e"); + f = new JMenuItem("f"); + fifthMenu.add(e); + fifthMenu.add(f); + + menuBar = new JMenuBar(); + menuBar.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT); + menuBar.add(firstMenu); + menuBar.add(secondMenu); + menuBar.add(thirdMenu); + menuBar.add(forthMenu); + menuBar.add(fifthMenu); + frame.setJMenuBar(menuBar); + + frame.setLocationRelativeTo(null); + frame.pack(); + frame.setVisible(true); + }); + Robot robot = new Robot(); + robot.setAutoDelay(100); + robot.waitForIdle(); + robot.delay(1000); + SwingUtilities.invokeAndWait(() -> { + p = thirdMenu.getLocationOnScreen(); + width = thirdMenu.getWidth(); + height = thirdMenu.getHeight(); + }); + robot.mouseMove(p.x + width / 2, p.y + height / 2); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.delay(1000); + robot.keyPress(KeyEvent.VK_RIGHT); + robot.keyRelease(KeyEvent.VK_RIGHT); + robot.delay(1000); + if (!passed) { + throw new RuntimeException("Arrow traversal order not correct in RTL orientation"); + } + } finally { + SwingUtilities.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + } + } +} diff --git a/test/jdk/javax/swing/JPasswordField/TestSelectedTextBackgroundColor.java b/test/jdk/javax/swing/JPasswordField/TestSelectedTextBackgroundColor.java index fc5bbd3e183635bb571c787477928e0eb39d5d69..b4b527eaf0a4d15a997faa31d527151f3078ff73 100644 --- a/test/jdk/javax/swing/JPasswordField/TestSelectedTextBackgroundColor.java +++ b/test/jdk/javax/swing/JPasswordField/TestSelectedTextBackgroundColor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -103,7 +103,7 @@ public class TestSelectedTextBackgroundColor { panel.add(passwordField, BorderLayout.CENTER); frame = new JFrame("TestSelectedTextBackgroundColor"); frame.add(panel); - frame.setSize(200, 200); + frame.setSize(400, 400); frame.setAlwaysOnTop(true); frame.setLocationRelativeTo(null); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); diff --git a/test/jdk/javax/swing/JProgressBar/TestJProgressBarHighlightColor.java b/test/jdk/javax/swing/JProgressBar/TestJProgressBarHighlightColor.java index c3c37d06123dc34e3baafffa14da50ba15107b61..731e30841807563770bbe33a051362666f0da7bc 100644 --- a/test/jdk/javax/swing/JProgressBar/TestJProgressBarHighlightColor.java +++ b/test/jdk/javax/swing/JProgressBar/TestJProgressBarHighlightColor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -103,7 +103,7 @@ public class TestJProgressBarHighlightColor { panel.add(progressBar, BorderLayout.CENTER); frame = new JFrame("TestSelectedTextBackgroundColor"); frame.add(panel); - frame.setSize(200, 200); + frame.setSize(400, 400); frame.setAlwaysOnTop(true); frame.setLocationRelativeTo(null); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); diff --git a/test/jdk/javax/swing/JRadioButton/8033699/bug8033699.java b/test/jdk/javax/swing/JRadioButton/8033699/bug8033699.java index 06622f718197d21a5ebcd1b96fea9c2384d91a2d..9365e6ba45b252071d818bb322c3bac01fb81a22 100644 --- a/test/jdk/javax/swing/JRadioButton/8033699/bug8033699.java +++ b/test/jdk/javax/swing/JRadioButton/8033699/bug8033699.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -21,11 +21,9 @@ * questions. */ - /* +/* * @test * @key headful - * @library ../../regtesthelpers - * @build Util * @bug 8033699 8154043 8167160 8208640 8226892 * @summary Incorrect radio button behavior when pressing tab key * @run main bug8033699 @@ -34,8 +32,7 @@ import java.awt.KeyboardFocusManager; import java.awt.Robot; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; -import java.util.logging.Level; -import java.util.logging.Logger; + import javax.swing.BorderFactory; import javax.swing.BoxLayout; import javax.swing.ButtonGroup; @@ -45,7 +42,6 @@ import javax.swing.JPanel; import javax.swing.JRadioButton; import javax.swing.SwingUtilities; import javax.swing.UIManager; -import javax.swing.UnsupportedLookAndFeelException; public class bug8033699 { @@ -59,7 +55,7 @@ public class bug8033699 { private static JRadioButton radioBtn3; private static JRadioButton radioBtnSingle; - public static void main(String args[]) throws Throwable { + public static void main(String[] args) throws Throwable { SwingUtilities.invokeAndWait(() -> { changeLAF(); createAndShowGUI(); @@ -67,6 +63,7 @@ public class bug8033699 { robot = new Robot(); Thread.sleep(100); + robot.waitForIdle(); robot.setAutoDelay(100); @@ -76,7 +73,7 @@ public class bug8033699 { // tab key test non-grouped radio button runTest2(); - // shift tab key test grouped and non grouped radio button + // shift tab key test grouped and non-grouped radio button runTest3(); // left/up key test in grouped radio button @@ -152,16 +149,16 @@ public class bug8033699 { mainFrame.setLayout(new BoxLayout(mainFrame.getContentPane(), BoxLayout.Y_AXIS)); mainFrame.setSize(300, 300); - mainFrame.setLocation(200, 200); + mainFrame.setLocationRelativeTo(null); mainFrame.setVisible(true); mainFrame.toFront(); } // Radio button Group as a single component when traversing through tab key private static void runTest1() throws Exception { - hitKey(robot, KeyEvent.VK_TAB); - hitKey(robot, KeyEvent.VK_TAB); - hitKey(robot, KeyEvent.VK_TAB); + hitKey(KeyEvent.VK_TAB); + hitKey(KeyEvent.VK_TAB); + hitKey(KeyEvent.VK_TAB); SwingUtilities.invokeAndWait(() -> { if (KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner() != radioBtnSingle) { @@ -173,7 +170,7 @@ public class bug8033699 { // Non-Grouped Radio button as a single component when traversing through tab key private static void runTest2() throws Exception { - hitKey(robot, KeyEvent.VK_TAB); + hitKey(KeyEvent.VK_TAB); SwingUtilities.invokeAndWait(() -> { if (KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner() != btnEnd) { System.out.println("Non Grouped Radio Button Go To Next Component through Tab Key failed"); @@ -184,9 +181,9 @@ public class bug8033699 { // Non-Grouped Radio button and Group Radio button as a single component when traversing through shift-tab key private static void runTest3() throws Exception { - hitKey(robot, KeyEvent.VK_SHIFT, KeyEvent.VK_TAB); - hitKey(robot, KeyEvent.VK_SHIFT, KeyEvent.VK_TAB); - hitKey(robot, KeyEvent.VK_SHIFT, KeyEvent.VK_TAB); + hitKey(KeyEvent.VK_SHIFT, KeyEvent.VK_TAB); + hitKey(KeyEvent.VK_SHIFT, KeyEvent.VK_TAB); + hitKey(KeyEvent.VK_SHIFT, KeyEvent.VK_TAB); SwingUtilities.invokeAndWait(() -> { if (KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner() != radioBtn1) { System.out.println("Radio button Group/Non Grouped Radio Button SHIFT-Tab Key Test failed"); @@ -197,8 +194,8 @@ public class bug8033699 { // Using arrow key to move focus in radio button group private static void runTest4() throws Exception { - hitKey(robot, KeyEvent.VK_DOWN); - hitKey(robot, KeyEvent.VK_RIGHT); + hitKey(KeyEvent.VK_DOWN); + hitKey(KeyEvent.VK_RIGHT); SwingUtilities.invokeAndWait(() -> { if (KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner() != radioBtn3) { System.out.println("Radio button Group UP/LEFT Arrow Key Move Focus Failed"); @@ -208,8 +205,8 @@ public class bug8033699 { } private static void runTest5() throws Exception { - hitKey(robot, KeyEvent.VK_UP); - hitKey(robot, KeyEvent.VK_LEFT); + hitKey(KeyEvent.VK_UP); + hitKey(KeyEvent.VK_LEFT); SwingUtilities.invokeAndWait(() -> { if (KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner() != radioBtn1) { System.out.println("Radio button Group Left/Up Arrow Key Move Focus Failed"); @@ -219,8 +216,8 @@ public class bug8033699 { } private static void runTest6() throws Exception { - hitKey(robot, KeyEvent.VK_UP); - hitKey(robot, KeyEvent.VK_UP); + hitKey(KeyEvent.VK_UP); + hitKey(KeyEvent.VK_UP); SwingUtilities.invokeAndWait(() -> { if (KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner() != radioBtn2) { System.out.println("Radio button Group Circle Back To First Button Test"); @@ -230,7 +227,7 @@ public class bug8033699 { } private static void runTest7() throws Exception { - hitKey(robot, KeyEvent.VK_TAB); + hitKey(KeyEvent.VK_TAB); SwingUtilities.invokeAndWait(() -> { if (KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner() != btnMiddle) { System.out.println("Separate Component added in button group layout"); @@ -240,7 +237,7 @@ public class bug8033699 { } private static void runTest8() throws Exception { - hitKey(robot, KeyEvent.VK_TAB); + hitKey(KeyEvent.VK_TAB); SwingUtilities.invokeAndWait(() -> { if (KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner() != radioBtnSingle) { System.out.println("Separate Component added in button group layout"); @@ -249,9 +246,9 @@ public class bug8033699 { }); } - private static Boolean actRB1 = false; - private static Boolean actRB2 = false; - private static Boolean actRB3 = false; + private static boolean actRB1 = false; + private static boolean actRB2 = false; + private static boolean actRB3 = false; // JDK-8226892: Verify that ActionListener is called when a RadioButton is selected using arrow key. private static void runTest9() throws Exception { @@ -268,9 +265,9 @@ public class bug8033699 { radioBtn2.addActionListener(actLrRB2); radioBtn3.addActionListener(actLrRB3); - hitKey(robot, KeyEvent.VK_DOWN); - hitKey(robot, KeyEvent.VK_DOWN); - hitKey(robot, KeyEvent.VK_DOWN); + hitKey(KeyEvent.VK_DOWN); + hitKey(KeyEvent.VK_DOWN); + hitKey(KeyEvent.VK_DOWN); String failMessage = "ActionListener not invoked when selected using arrow key."; if (!actRB2) { @@ -288,13 +285,13 @@ public class bug8033699 { radioBtn3.removeActionListener(actLrRB3); } - private static void hitKey(Robot robot, int keycode) { + private static void hitKey(int keycode) { robot.keyPress(keycode); robot.keyRelease(keycode); robot.waitForIdle(); } - private static void hitKey(Robot robot, int mode, int keycode) { + private static void hitKey(int mode, int keycode) { robot.keyPress(mode); robot.keyPress(keycode); robot.keyRelease(keycode); diff --git a/test/jdk/javax/swing/JRadioButton/8075609/bug8075609.java b/test/jdk/javax/swing/JRadioButton/8075609/bug8075609.java index 31c99206b7a9b4d882b5696da5acffe26137099c..4c29a33ffa0040c936fd3fdde44c7c93c6afff52 100644 --- a/test/jdk/javax/swing/JRadioButton/8075609/bug8075609.java +++ b/test/jdk/javax/swing/JRadioButton/8075609/bug8075609.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -21,44 +21,49 @@ * questions. */ - /* +/* * @test * @key headful - * @library ../../regtesthelpers - * @build Util * @bug 8075609 * @summary IllegalArgumentException when transferring focus from JRadioButton using tab - * @author Vivi An * @run main bug8075609 */ - -import javax.swing.*; -import javax.swing.event.*; -import java.awt.event.*; -import java.awt.*; +import java.awt.BorderLayout; +import java.awt.Robot; +import java.awt.event.KeyEvent; + +import javax.swing.ButtonGroup; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JRadioButton; +import javax.swing.JTextField; +import javax.swing.LayoutFocusTraversalPolicy; +import javax.swing.SwingUtilities; public class bug8075609 { private static Robot robot; private static JTextField textField; private static JFrame mainFrame; - public static void main(String args[]) throws Throwable { + public static void main(String[] args) throws Throwable { try { - SwingUtilities.invokeAndWait(new Runnable() { - public void run() { - createAndShowGUI(); - } - }); + SwingUtilities.invokeAndWait(bug8075609::createAndShowGUI); robot = new Robot(); Thread.sleep(100); + robot.waitForIdle(); robot.setAutoDelay(100); // Radio button group tab key test runTest1(); } finally { - if (mainFrame != null) SwingUtilities.invokeAndWait(() -> mainFrame.dispose()); + SwingUtilities.invokeAndWait(() -> { + if (mainFrame != null) { + mainFrame.dispose(); + } + }); } } @@ -91,26 +96,25 @@ public class bug8075609 { mainFrame.add(rootPanel); mainFrame.pack(); + mainFrame.setLocationRelativeTo(null); mainFrame.setVisible(true); mainFrame.toFront(); } // Radio button Group as a single component when traversing through tab key - private static void runTest1() throws Exception{ - hitKey(robot, KeyEvent.VK_TAB); - - robot.delay(1000 ); - SwingUtilities.invokeAndWait(new Runnable() { - public void run() { - if (!textField.hasFocus()) { - System.out.println("Radio Button Group Go To Next Component through Tab Key failed"); - throw new RuntimeException("Focus is not on textField as Expected"); - } + private static void runTest1() throws Exception { + hitKey(KeyEvent.VK_TAB); + + robot.delay(1000); + SwingUtilities.invokeAndWait(() -> { + if (!textField.hasFocus()) { + System.out.println("Radio Button Group Go To Next Component through Tab Key failed"); + throw new RuntimeException("Focus is not on textField as Expected"); } }); } - private static void hitKey(Robot robot, int keycode) { + private static void hitKey(int keycode) { robot.keyPress(keycode); robot.keyRelease(keycode); robot.waitForIdle(); diff --git a/test/jdk/javax/swing/JRootPane/DefaultButtonTest.java b/test/jdk/javax/swing/JRootPane/DefaultButtonTest.java new file mode 100644 index 0000000000000000000000000000000000000000..cff2ea73c93164824b0db0e0979e3e1d70d3a5d8 --- /dev/null +++ b/test/jdk/javax/swing/JRootPane/DefaultButtonTest.java @@ -0,0 +1,111 @@ +/* + * 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. + */ + +import java.awt.Robot; +import java.awt.event.KeyEvent; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JTextField; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import javax.swing.UnsupportedLookAndFeelException; + +/* + * @test + * @key headful + * @bug 8280913 + * @summary Check whether the default button is honored when <Enter> key is pressed. + * @run main DefaultButtonTest + */ +public class DefaultButtonTest { + private volatile boolean buttonPressed; + private JFrame frame; + + public static void main(String[] s) throws Exception { + DefaultButtonTest test = new DefaultButtonTest(); + test.runTest(); + } + + private static void setLookAndFeel(String lafName) { + try { + UIManager.setLookAndFeel(lafName); + } catch (UnsupportedLookAndFeelException ignored) { + System.out.println("Ignoring Unsupported L&F: " + lafName); + } catch (ClassNotFoundException | InstantiationException + | IllegalAccessException e) { + throw new RuntimeException(e); + } + } + + private void disposeFrame() { + if (frame != null) { + frame.dispose(); + frame = null; + } + } + + private void createUI() { + frame = new JFrame("Default Button Test"); + JPanel panel = new JPanel(); + panel.add(new JTextField("Text field")); + JButton button1 = new JButton("Default"); + button1.addActionListener(e -> buttonPressed = true); + panel.add(button1); + panel.add(new JButton("Button2")); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + frame.add(panel); + frame.pack(); + frame.setLocationRelativeTo(null); + frame.getRootPane().setDefaultButton(button1); + frame.setVisible(true); + } + + public void runTest() throws Exception { + Robot robot = new Robot(); + robot.setAutoDelay(100); + for (UIManager.LookAndFeelInfo laf : UIManager.getInstalledLookAndFeels()) { + try { + buttonPressed = false; + String lafName = laf.getClassName(); + System.out.println("Testing L&F: " + lafName); + SwingUtilities.invokeAndWait(() -> { + setLookAndFeel(lafName); + createUI(); + }); + robot.waitForIdle(); + robot.keyPress(KeyEvent.VK_ENTER); + robot.keyRelease(KeyEvent.VK_ENTER); + robot.waitForIdle(); + + if (buttonPressed) { + System.out.println("Test Passed for L&F: " + lafName); + } else { + throw new RuntimeException("Test Failed, Default Button not pressed for L&F: " + lafName); + } + } finally { + SwingUtilities.invokeAndWait(this::disposeFrame); + } + } + } +} diff --git a/test/jdk/javax/swing/JScrollPane/TestMouseWheelScroll.java b/test/jdk/javax/swing/JScrollPane/TestMouseWheelScroll.java new file mode 100644 index 0000000000000000000000000000000000000000..180a697a3f385b3ae380320b18d15d6e04eb3083 --- /dev/null +++ b/test/jdk/javax/swing/JScrollPane/TestMouseWheelScroll.java @@ -0,0 +1,127 @@ +/* + * 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. + */ +import java.awt.Point; +import java.awt.Robot; +import java.awt.event.InputEvent; +import javax.swing.DefaultListModel; +import javax.swing.ListModel; +import javax.swing.JScrollPane; +import javax.swing.JFrame; +import javax.swing.JList; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import javax.swing.UnsupportedLookAndFeelException; + +/* + * @test + * @key headful + * @requires (os.family != "mac") + * @bug 6911375 + * @summary Verifies mouseWheel effect on JList without scrollBar + */ +public class TestMouseWheelScroll { + + static JFrame frame; + static JScrollPane scrollPane; + static volatile Point p; + static volatile int width; + static volatile int height; + static volatile Point viewPosition; + static volatile Point newPosition; + + private static void setLookAndFeel(UIManager.LookAndFeelInfo laf) { + try { + UIManager.setLookAndFeel(laf.getClassName()); + } catch (UnsupportedLookAndFeelException ignored) { + System.out.println("Unsupported L&F: " + laf.getClassName()); + } catch (ClassNotFoundException | InstantiationException + | IllegalAccessException e) { + throw new RuntimeException(e); + } + } + + public static void main(String[] args) throws Exception { + + for (UIManager.LookAndFeelInfo laf : UIManager.getInstalledLookAndFeels()) { + System.out.println("Testing L&F: " + laf.getClassName()); + SwingUtilities.invokeAndWait(() -> setLookAndFeel(laf)); + Robot robot = new Robot(); + robot.setAutoDelay(100); + + try { + SwingUtilities.invokeAndWait(() -> { + frame = new JFrame(); + JList list = new JList(createListModel()); + // disable list bindings + list.getInputMap().getParent().clear(); + scrollPane = new JScrollPane(list); + + scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER); + frame.add(scrollPane); + frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + frame.setSize(200,200); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + }); + robot.waitForIdle(); + robot.delay(1000); + SwingUtilities.invokeAndWait(() -> { + p = frame.getLocationOnScreen(); + width = frame.getWidth(); + height = frame.getHeight(); + }); + robot.mouseMove(p.x + width / 2, p.y + height / 2); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.waitForIdle(); + SwingUtilities.invokeAndWait(() -> { + viewPosition = scrollPane.getViewport().getViewPosition(); + }); + robot.delay(1000); + robot.mouseWheel(1); + robot.delay(500); + SwingUtilities.invokeAndWait(() -> { + newPosition = scrollPane.getViewport().getViewPosition(); + }); + robot.delay(1000); + if (newPosition.equals(viewPosition)) { + throw new RuntimeException("Mouse wheel not handled"); + } + } finally { + SwingUtilities.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + } + } + + private static ListModel createListModel() { + DefaultListModel model = new DefaultListModel(); + for (int i = 0; i < 100; i++) { + model.addElement("element " + i); + } + return model; + } +} diff --git a/test/jdk/javax/swing/JSlider/TestJSliderRendering.java b/test/jdk/javax/swing/JSlider/TestJSliderRendering.java index ebf12021ced8652e3bc672c1612f7a6af294b609..5ece0a8852ea1ed8cd67de11acb53e86439205cd 100644 --- a/test/jdk/javax/swing/JSlider/TestJSliderRendering.java +++ b/test/jdk/javax/swing/JSlider/TestJSliderRendering.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -101,7 +101,7 @@ public class TestJSliderRendering { panel.add(slider); frame = new JFrame("TestJSliderRendering"); frame.add(panel); - frame.setSize(200, 200); + frame.setSize(400, 400); frame.setAlwaysOnTop(true); frame.setLocationRelativeTo(null); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); diff --git a/test/jdk/javax/swing/JSpinner/4515999/JSpinnerMouseAndKeyPressTest.java b/test/jdk/javax/swing/JSpinner/4515999/JSpinnerMouseAndKeyPressTest.java new file mode 100644 index 0000000000000000000000000000000000000000..49a237a1e27f2bcb0b433648c3f2cfc8a1cde0ba --- /dev/null +++ b/test/jdk/javax/swing/JSpinner/4515999/JSpinnerMouseAndKeyPressTest.java @@ -0,0 +1,203 @@ +/* + * 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. + */ + +import java.awt.ComponentOrientation; +import java.awt.Point; +import java.awt.Robot; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import java.util.Arrays; +import java.util.Calendar; +import java.util.Date; +import java.util.List; +import java.util.stream.Collectors; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JSpinner; +import javax.swing.SpinnerDateModel; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; + + +import static javax.swing.UIManager.getInstalledLookAndFeels; + +/* + * @test + * @key headful + * @bug 4515999 + * @summary Check whether incrementing dates via the keyboard (up/down) gives + * the same results as using mouse press on the arrow buttons in a JSpinner. + * @run main JSpinnerMouseAndKeyPressTest + */ +public class JSpinnerMouseAndKeyPressTest { + // 2 days in milliseconds + private static final int EXPECTED_VALUE_2_DAYS = 2 * 24 * 60 * 60 * 1000; + + private static JFrame frame; + private static JSpinner spinner; + private static volatile Point spinnerUpButtonCenter; + private static volatile Point spinnerDownButtonCenter; + private static volatile Date spinnerValue; + + public static void main(String[] s) throws Exception { + runTest(); + } + + private static void setLookAndFeel(final String laf) { + try { + UIManager.setLookAndFeel(laf); + System.out.println("LookAndFeel: " + laf); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private static void createUI() { + frame = new JFrame(); + JPanel panel = new JPanel(); + spinner = new JSpinner(); + spinner.setModel(new DateModel()); + JSpinner.DateEditor editor = new JSpinner.DateEditor(spinner, "dd/MM/yy"); + spinner.setEditor(editor); + spinner.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT); + panel.add(spinner); + frame.add(panel); + frame.setUndecorated(true); + frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + frame.pack(); + frame.setAlwaysOnTop(true); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } + + + public static void runTest() throws Exception { + Robot robot = new Robot(); + robot.setAutoWaitForIdle(true); + robot.setAutoDelay(100); + List<String> lafs = Arrays.stream(getInstalledLookAndFeels()) + .map(UIManager.LookAndFeelInfo::getClassName) + .collect(Collectors.toList()); + for (final String laf : lafs) { + try { + SwingUtilities.invokeAndWait(() -> { + setLookAndFeel(laf); + createUI(); + }); + robot.waitForIdle(); + + SwingUtilities.invokeAndWait(() -> { + Point loc = spinner.getLocationOnScreen(); + int editorWidth = spinner.getEditor().getWidth(); + int buttonWidth = spinner.getWidth() - editorWidth; + int quarterHeight = spinner.getHeight() / 4; + + spinnerUpButtonCenter = new Point(loc.x + editorWidth + + (buttonWidth / 2), + loc.y + quarterHeight); + spinnerDownButtonCenter = new Point(spinnerUpButtonCenter.x, + loc.y + (3 * quarterHeight)); + }); + + // Mouse press use-case + // Move Mouse pointer to UP button center and click it + robot.mouseMove(spinnerUpButtonCenter.x, spinnerUpButtonCenter.y); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + + updateSpinnerValue(); + long upValue = spinnerValue.getTime(); + + // Move Mouse pointer to DOWN button center and click it + robot.mouseMove(spinnerDownButtonCenter.x, spinnerDownButtonCenter.y); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + + updateSpinnerValue(); + long downValue = spinnerValue.getTime(); + + long mouseIncrement = upValue - downValue; + + // Key press use-case + // Up Key press + robot.keyPress(KeyEvent.VK_UP); + robot.keyRelease(KeyEvent.VK_UP); + + updateSpinnerValue(); + upValue = spinnerValue.getTime(); + + // Down Key press + robot.keyPress(KeyEvent.VK_DOWN); + robot.keyRelease(KeyEvent.VK_DOWN); + + updateSpinnerValue(); + downValue = spinnerValue.getTime(); + + long keyIncrement = upValue - downValue; + + if ((keyIncrement == EXPECTED_VALUE_2_DAYS) && + (mouseIncrement == EXPECTED_VALUE_2_DAYS)) { + System.out.println("Test passed"); + } else { + throw new RuntimeException("Test failed because keyIncrement: " + + keyIncrement + " and mouseIncrement: " + + mouseIncrement + " should match with the expected value " + + EXPECTED_VALUE_2_DAYS + " for LnF " + laf); + } + + } finally { + SwingUtilities.invokeAndWait(JSpinnerMouseAndKeyPressTest::disposeFrame); + } + } + } + + private static void updateSpinnerValue() throws Exception { + SwingUtilities.invokeAndWait(() -> spinnerValue = (Date) spinner.getValue()); + } + + private static void disposeFrame() { + if (frame != null) { + frame.dispose(); + frame = null; + } + } + + private static class DateModel extends SpinnerDateModel { + + private final Calendar cal = Calendar.getInstance(); + + @Override + public Object getNextValue() { + cal.setTime(getDate()); + cal.add(Calendar.DAY_OF_MONTH, 2); // Increment two days + return cal.getTime(); + } + + @Override + public Object getPreviousValue() { + cal.setTime(getDate()); + cal.add(Calendar.DAY_OF_MONTH, -2); // Decrement two days + return cal.getTime(); + } + } +} diff --git a/test/jdk/javax/swing/JSpinner/4670051/DateFieldUnderCursorTest.java b/test/jdk/javax/swing/JSpinner/4670051/DateFieldUnderCursorTest.java new file mode 100644 index 0000000000000000000000000000000000000000..c0346700699891affc4272c7b3ff3105479f151e --- /dev/null +++ b/test/jdk/javax/swing/JSpinner/4670051/DateFieldUnderCursorTest.java @@ -0,0 +1,282 @@ +/* + * Copyright (c) 2002, 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. + */ + +import java.awt.ComponentOrientation; +import java.awt.Point; +import java.awt.Robot; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import java.util.Arrays; +import java.util.Calendar; +import java.util.Date; +import java.util.List; +import java.util.stream.Collectors; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JSpinner; +import javax.swing.SpinnerDateModel; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; + +import static javax.swing.UIManager.getInstalledLookAndFeels; + +/* + * @test + * @key headful + * @bug 4670051 + * @summary Checks whether JSpinner with a SpinnerDateModel + * spins the field where cursor is located. + * @run main DateFieldUnderCursorTest + */ +public class DateFieldUnderCursorTest { + + private static final Calendar expected = Calendar.getInstance(); + private static final Calendar actual = Calendar.getInstance(); + private static Robot robot; + private static JSpinner spinner; + private static Date initValue; + private static Date upValue; + private static Date downValue; + private static JFrame frame; + private static boolean passed = true; + private static volatile Point spinnerUpButtonCenter; + private static volatile Point spinnerDownButtonCenter; + private static volatile Date spinnerValue; + + public static void main(String[] s) throws Exception { + runTest(); + } + + public static void runTest() throws Exception { + robot = new Robot(); + robot.setAutoWaitForIdle(true); + robot.setAutoDelay(100); + List<String> lafs = Arrays.stream(getInstalledLookAndFeels()) + .map(UIManager.LookAndFeelInfo::getClassName) + .collect(Collectors.toList()); + for (final String laf : lafs) { + try { + SwingUtilities.invokeAndWait(() -> { + setLookAndFeel(laf); + createUI(); + }); + SwingUtilities.invokeAndWait(() -> { + Point loc = spinner.getLocationOnScreen(); + int editorWidth = spinner.getEditor().getWidth(); + int buttonWidth = spinner.getWidth() - editorWidth; + int quarterHeight = spinner.getHeight() / 4; + + spinnerUpButtonCenter = new Point(loc.x + editorWidth + + (buttonWidth / 2), + loc.y + quarterHeight); + spinnerDownButtonCenter = new Point(spinnerUpButtonCenter.x, + loc.y + (3 * quarterHeight)); + }); + + // Cursor at Day field. + // Increment Day + initValue = getSpinnerValue(); + mousePressOnUpButton(); + upValue = getSpinnerValue(); + verifyDayIncrement(); + // Decrement Day + initValue = getSpinnerValue(); + mousePressOnDownButton(); + downValue = getSpinnerValue(); + verifyDayDecrement(); + + // Cursor at Month Field + pressRightArrowKey(); + // Increment Month + initValue = getSpinnerValue(); + mousePressOnUpButton(); + upValue = getSpinnerValue(); + verifyMonthIncrement(); + // Decrement Month + initValue = getSpinnerValue(); + mousePressOnDownButton(); + downValue = getSpinnerValue(); + verifyMonthDecrement(); + + // Cursor at Year Field + pressRightArrowKey(); + // Increment Year + initValue = getSpinnerValue(); + mousePressOnUpButton(); + upValue = getSpinnerValue(); + verifyYearIncrement(); + // Decrement Year + initValue = getSpinnerValue(); + mousePressOnDownButton(); + downValue = getSpinnerValue(); + verifyYearDecrement(); + + if (passed) { + System.out.println("Test Passed"); + } else { + throw new RuntimeException("Test Failed as one or more cases failed"); + } + } finally { + SwingUtilities.invokeAndWait(DateFieldUnderCursorTest::disposeFrame); + } + } + } + + private static Date getSpinnerValue() throws Exception { + SwingUtilities.invokeAndWait(() -> spinnerValue = (Date) spinner.getValue()); + return spinnerValue; + } + + public static void pressRightArrowKey() { + robot.keyPress(KeyEvent.VK_RIGHT); + robot.keyRelease(KeyEvent.VK_RIGHT); + } + + public static void mousePressOnUpButton() { + robot.mouseMove(spinnerUpButtonCenter.x, spinnerUpButtonCenter.y); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + } + + public static void mousePressOnDownButton() { + robot.mouseMove(spinnerDownButtonCenter.x, spinnerDownButtonCenter.y); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + } + + + public static boolean compareDates() { + return (expected.get(Calendar.DATE) == actual.get(Calendar.DATE)) + && (expected.get(Calendar.MONTH) == actual.get(Calendar.MONTH)) + && (expected.get(Calendar.YEAR) == actual.get(Calendar.YEAR)); + } + + private static void checkResult() { + if (compareDates()) { + System.out.println(" Case Passed"); + } else { + passed = false; + System.out.println(" Case Failed because the expected: " + expected.getTime() + + " and actual: " + actual.getTime() + " outputs do not match."); + } + } + + private static void updateCalendarObjects(Date finalValue) { + expected.setTime(initValue); + actual.setTime(finalValue); + } + + /** + * Verifying that JSpinner increments the date field when cursor is on date field + */ + private static void verifyDayIncrement() { + System.out.print("verifyDateIncrement"); + updateCalendarObjects(upValue); + expected.add(Calendar.DATE, 1); + checkResult(); + } + + /** + * Verifying that JSpinner decrements the date field when cursor is on date field + */ + private static void verifyDayDecrement() { + System.out.print("verifyDateDecrement"); + updateCalendarObjects(downValue); + expected.add(Calendar.DATE, -1); + checkResult(); + } + + /** + * Verifying that JSpinner increments the month field when cursor is on month field + */ + private static void verifyMonthIncrement() { + System.out.print("verifyMonthIncrement"); + updateCalendarObjects(upValue); + expected.add(Calendar.MONTH, 1); + checkResult(); + } + + /** + * Verifying that JSpinner decrements the month field when cursor is on month field + */ + private static void verifyMonthDecrement() { + System.out.print("verifyMonthDecrement"); + updateCalendarObjects(downValue); + expected.add(Calendar.MONTH, -1); + checkResult(); + } + + /** + * Verifying that, JSpinner decrements the year field when the cursor is on year field. + */ + private static void verifyYearDecrement() { + System.out.print("verifyYearDecrement"); + updateCalendarObjects(downValue); + expected.add(Calendar.YEAR, -1); + checkResult(); + } + + /** + * Verifying that JSpinner increments the year field when cursor is on year field + */ + private static void verifyYearIncrement() { + System.out.print("verifyYearIncrement"); + updateCalendarObjects(upValue); + expected.add(Calendar.YEAR, 1); + checkResult(); + } + + private static void createUI() { + frame = new JFrame(); + JPanel panel = new JPanel(); + spinner = new JSpinner(new SpinnerDateModel()); + JSpinner.DateEditor editor = new JSpinner.DateEditor(spinner, " dd/MM/yy "); + spinner.setEditor(editor); + spinner.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT); + panel.add(spinner); + + frame.add(panel); + frame.setUndecorated(true); + frame.pack(); + frame.setAlwaysOnTop(true); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } + + private static void setLookAndFeel(final String laf) { + try { + UIManager.setLookAndFeel(laf); + System.out.println("LookAndFeel: " + laf); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private static void disposeFrame() { + if (frame != null) { + frame.dispose(); + frame = null; + } + } + +} diff --git a/test/jdk/javax/swing/JSpinner/TestSelectedTextBackgroundColor.java b/test/jdk/javax/swing/JSpinner/TestSelectedTextBackgroundColor.java index 300c8fed80ea0291bb8b1f8f52155b2c997410bb..16f19feb60791182b2b19d6436c2435ae6f0f76f 100644 --- a/test/jdk/javax/swing/JSpinner/TestSelectedTextBackgroundColor.java +++ b/test/jdk/javax/swing/JSpinner/TestSelectedTextBackgroundColor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -119,7 +119,7 @@ public class TestSelectedTextBackgroundColor { panel.add(listModelSpinner, BorderLayout.CENTER); frame = new JFrame("TestSelectedTextBackgroundColor"); frame.add(panel); - frame.setSize(200, 200); + frame.setSize(400, 400); frame.setAlwaysOnTop(true); frame.setLocationRelativeTo(null); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); diff --git a/test/jdk/javax/swing/JSplitPane/4164779/JSplitPaneKeyboardNavigationTest.java b/test/jdk/javax/swing/JSplitPane/4164779/JSplitPaneKeyboardNavigationTest.java new file mode 100644 index 0000000000000000000000000000000000000000..ced7410bf0664827a72a8c9384a0ccec8565a265 --- /dev/null +++ b/test/jdk/javax/swing/JSplitPane/4164779/JSplitPaneKeyboardNavigationTest.java @@ -0,0 +1,220 @@ +/* + * Copyright (c) 2002, 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. + */ + +import java.awt.BorderLayout; +import java.awt.Point; +import java.awt.Robot; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicReference; +import java.util.stream.Collectors; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JSplitPane; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import javax.swing.UIManager.LookAndFeelInfo; +import javax.swing.UnsupportedLookAndFeelException; + +import static javax.swing.UIManager.getInstalledLookAndFeels; + +/* + * @test + * @key headful + * @bug 4164779 + * @summary This test confirms that JSplitPane keyboard navigation supports F6 and Ctrl+Tab. + * @run main JSplitPaneKeyboardNavigationTest + */ +public class JSplitPaneKeyboardNavigationTest { + + private static final StringBuffer failedVerifiers = new StringBuffer(); + private static JPanel panel; + private static JButton leftButton; + private static JButton rightButton1; + private static JButton rightButton2; + private static JButton topButton; + private static JButton bottomButton; + private static Robot robot; + private static JFrame frame; + + public static void main(String[] s) throws Exception { + robot = new Robot(); + robot.setAutoWaitForIdle(true); + robot.setAutoDelay(200); + List<String> lafs = Arrays.stream(getInstalledLookAndFeels()) + .map(LookAndFeelInfo::getClassName) + .collect(Collectors.toList()); + for (final String laf : lafs) { + try { + AtomicBoolean lafSetSuccess = new AtomicBoolean(false); + SwingUtilities.invokeAndWait(() -> { + lafSetSuccess.set(setLookAndFeel(laf)); + if (lafSetSuccess.get()) { + createUI(); + } + }); + if (!lafSetSuccess.get()) { + continue; + } + robot.waitForIdle(); + + // Press Right button 1 and move focus to it. + pressButton(rightButton1); + hitKeys(KeyEvent.VK_F6); + + // Verifier1 - Verifies that, F6 transfers focus to the right/bottom side of the splitpane + if (isFocusOwner(rightButton2)) { + System.out.println("Verifier 1 passed"); + } else { + failedVerifiers.append("1,"); + System.out.println("Verifier 1 failed, rightButton2 is not focus owner," + + "F6 doesn't transfer focus to the right/bottom side of the splitpane"); + } + + // Press Right button 2 and move focus to it. + pressButton(rightButton2); + hitKeys(KeyEvent.VK_F6); + + // Verifier2 - Verifies that, F6 transfers focus to the left side of the parent splitpane, + // if the right/bottom side of splitpane already has focus, and it is contained within another splitpane + if (isFocusOwner(leftButton)) { + System.out.println("Verifier 2 passed"); + } else { + failedVerifiers.append("2,"); + System.out.println("Verifier 2 failed, leftButton is not focus owner, " + + "F6 doesn't transfer focus to the left side of the splitpane"); + } + + // Press Left button and move focus to it. + pressButton(leftButton); + hitKeys(KeyEvent.VK_CONTROL, KeyEvent.VK_TAB); + // Verifier3 - Verifies that, CTRL-TAB navigates forward outside the JSplitPane + if (isFocusOwner(bottomButton)) { + System.out.println("Verifier 3 passed"); + } else { + failedVerifiers.append("3,"); + System.out.println("Verifier 3 failed, bottomButton is not focus owner, " + + "CTRL-TAB doesn't navigate forward outside the JSplitPane"); + } + + // Press Left button and move focus to it. + pressButton(leftButton); + hitKeys(KeyEvent.VK_CONTROL, KeyEvent.VK_SHIFT, KeyEvent.VK_TAB); + + // Verifier4 - Verifies that, CTRL-SHIFT-TAB navigates backward outside the JSplitPane + if (isFocusOwner(topButton)) { + System.out.println("Verifier 4 passed"); + } else { + failedVerifiers.append("4"); + System.out.println("Verifier 4 failed, topButton is not focus owner, " + + "CTRL-SHIFT-TAB doesn't navigate backward outside the JSplitPane"); + } + + if (failedVerifiers.toString().isEmpty()) { + System.out.println("Test passed, All verifiers succeeded for " + laf); + } else { + throw new RuntimeException("Test failed, verifiers " + failedVerifiers.toString() + " failed for " + laf); + } + } finally { + SwingUtilities.invokeAndWait(JSplitPaneKeyboardNavigationTest::disposeFrame); + } + } + } + + private static boolean isFocusOwner(JButton button) throws Exception { + final AtomicBoolean isFocusOwner = new AtomicBoolean(false); + SwingUtilities.invokeAndWait(() -> { + isFocusOwner.set(button.isFocusOwner()); + }); + return isFocusOwner.get(); + } + + private static void pressButton(JButton button) throws Exception { + final AtomicReference<Point> loc = new AtomicReference<>(); + SwingUtilities.invokeAndWait(() -> { + loc.set(button.getLocationOnScreen()); + }); + final Point buttonLoc = loc.get(); + robot.mouseMove(buttonLoc.x + 8, buttonLoc.y + 8); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + } + + public static void createUI() { + frame = new JFrame(); + panel = new JPanel(); + panel.setLayout(new BorderLayout()); + leftButton = new JButton("Left Button"); + rightButton1 = new JButton("Right Button 1"); + rightButton2 = new JButton("Right Button 2"); + topButton = new JButton("Top Button"); + bottomButton = new JButton("Bottom Button"); + panel.add(topButton, BorderLayout.NORTH); + panel.add(bottomButton, BorderLayout.SOUTH); + final JSplitPane splitPane2 = new JSplitPane(JSplitPane.VERTICAL_SPLIT, true, rightButton1, rightButton2); + final JSplitPane splitPane1 = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, leftButton, splitPane2); + panel.add(splitPane1, BorderLayout.CENTER); + frame.setContentPane(panel); + frame.setSize(200, 200); + frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + frame.pack(); + frame.setAlwaysOnTop(true); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } + + private static void hitKeys(int... keys) { + for (int key : keys) { + robot.keyPress(key); + } + + for (int i = keys.length - 1; i >= 0; i--) { + robot.keyRelease(keys[i]); + } + } + + private static boolean setLookAndFeel(String lafName) { + try { + UIManager.setLookAndFeel(lafName); + } catch (UnsupportedLookAndFeelException ignored) { + System.out.println("Ignoring Unsupported L&F: " + lafName); + return false; + } catch (ClassNotFoundException | InstantiationException + | IllegalAccessException e) { + throw new RuntimeException(e); + } + return true; + } + + private static void disposeFrame() { + if (frame != null) { + frame.dispose(); + frame = null; + } + } + +} diff --git a/test/jdk/javax/swing/JSplitPane/4820080/JSplitPaneDragColorTest.java b/test/jdk/javax/swing/JSplitPane/4820080/JSplitPaneDragColorTest.java new file mode 100644 index 0000000000000000000000000000000000000000..7e107f1265c75437af370e97b4bc27b47fc06778 --- /dev/null +++ b/test/jdk/javax/swing/JSplitPane/4820080/JSplitPaneDragColorTest.java @@ -0,0 +1,205 @@ +/* + * Copyright (c) 2003, 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. + */ + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.Toolkit; +import java.awt.event.InputEvent; +import java.io.File; +import java.io.IOException; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicReference; +import java.util.stream.Collectors; +import javax.imageio.ImageIO; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JSplitPane; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import javax.swing.UIManager.LookAndFeelInfo; +import javax.swing.UnsupportedLookAndFeelException; + +import static javax.swing.UIManager.getInstalledLookAndFeels; + +/* + * @test + * @key headful + * @bug 4820080 + * @summary This test confirms that the Drag color of JSplitPane divider should + * be the user specified one(Red here). + * @run main JSplitPaneDragColorTest + */ +public class JSplitPaneDragColorTest { + + // Tolerance is set inorder to negate small differences in pixel color values, + // especially in Mac machines. + private final static int COLOR_TOLERANCE = 9; + private static final Color EXPECTED_DRAG_COLOR = Color.RED; + private static JFrame frame; + private static JSplitPane pane; + private static Robot robot; + + public static void main(String[] args) throws Exception { + + robot = new Robot(); + robot.setAutoWaitForIdle(true); + robot.setAutoDelay(200); + // Skipping NimbusLookAndFeel & GTKLookAndFeel, + // as both are not supported for this feature - JDK-8075914, JDK-8075608 + List<String> lafs = Arrays.stream(getInstalledLookAndFeels()) + .filter(laf -> !(laf.getName().contains("GTK") + || laf.getName().contains("Nimbus"))) + .map(LookAndFeelInfo::getClassName) + .collect(Collectors.toList()); + for (final String laf : lafs) { + try { + AtomicBoolean lafSetSuccess = new AtomicBoolean(false); + SwingUtilities.invokeAndWait(() -> { + lafSetSuccess.set(setLookAndFeel(laf)); + if (lafSetSuccess.get()) { + createUI(); + } + }); + if (!lafSetSuccess.get()) { + continue; + } + robot.waitForIdle(); + + Rectangle dividerRect = getDividerRect(); + + // Mouse click and right drag split pane divider + robot.mouseMove(dividerRect.x + 5, dividerRect.y + 36); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseMove(dividerRect.x + 15, dividerRect.y + 36); + robot.mouseMove(dividerRect.x + 5, dividerRect.y + 36); + + // Get the color of one of the pixels of the splitpane divider + // after the drag has started. Ideally it should be the + // SplitPaneDivider.draggingColor set by user, otherwise the test fails + final Color actualDragColor = robot.getPixelColor(dividerRect.x + 2, + dividerRect.y + 2); + if (checkDragColor(actualDragColor)) { + System.out.println("Test passed in " + laf); + } else { + System.out.print("Expected pixel color = "); + System.out.printf("%X", EXPECTED_DRAG_COLOR.getRGB()); + System.out.print(", but actual color = "); + System.out.printf("%X", actualDragColor.getRGB()); + System.out.println(); + captureScreen(); + throw new RuntimeException("Test failed, drag color is wrong in " + + laf); + } + } finally { + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + SwingUtilities.invokeAndWait(JSplitPaneDragColorTest::disposeFrame); + } + } + } + + private static boolean checkDragColor(Color actualDragColor) { + int actualRed = actualDragColor.getRed(); + int actualGreen = actualDragColor.getGreen(); + int actualBlue = actualDragColor.getBlue(); + int expectedRed = EXPECTED_DRAG_COLOR.getRed(); + int expectedGreen = EXPECTED_DRAG_COLOR.getGreen(); + int expectedBlue = EXPECTED_DRAG_COLOR.getBlue(); + + final double tolerance = Math.sqrt( + (actualRed - expectedRed) * (actualRed - expectedRed) + + (actualGreen - expectedGreen) * (actualGreen - expectedGreen) + + (actualBlue - expectedBlue) * (actualBlue - expectedBlue)); + return (tolerance <= COLOR_TOLERANCE); + } + + private static Rectangle getDividerRect() { + final AtomicReference<Rectangle> rect = new AtomicReference<>(); + SwingUtilities.invokeLater(() -> { + javax.swing.plaf.basic.BasicSplitPaneUI ui = + (javax.swing.plaf.basic.BasicSplitPaneUI) pane.getUI(); + + javax.swing.plaf.basic.BasicSplitPaneDivider divider = ui.getDivider(); + Point dividerLoc = divider.getLocationOnScreen(); + rect.set(new Rectangle(dividerLoc.x, dividerLoc.y, divider.getWidth(), + divider.getHeight())); + }); + robot.waitForIdle(); + return rect.get(); + } + + private static void captureScreen() { + Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); + try { + ImageIO.write( + robot.createScreenCapture(new Rectangle(0, 0, + screenSize.width, + screenSize.height)), + "png", + new File("screen1.png") + ); + } catch (IOException ignore) { + } + } + + private static void createUI() { + frame = new JFrame(); + UIManager.put("SplitPaneDivider.draggingColor", EXPECTED_DRAG_COLOR); + JLabel l1 = new JLabel("LEFT LABEL", JLabel.CENTER); + JLabel l2 = new JLabel("RIGHT LABEL", JLabel.CENTER); + pane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, l1, l2); + frame.setSize(400, 400); + pane.setDividerSize(15); + pane.setDividerLocation(frame.getSize().width / 2); + frame.getContentPane().add(pane, BorderLayout.CENTER); + frame.setLocationRelativeTo(null); + frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + frame.setVisible(true); + } + + private static boolean setLookAndFeel(String lafName) { + try { + UIManager.setLookAndFeel(lafName); + } catch (UnsupportedLookAndFeelException ignored) { + System.out.println("Ignoring Unsupported L&F: " + lafName); + return false; + } catch (ClassNotFoundException | InstantiationException + | IllegalAccessException e) { + throw new RuntimeException(e); + } + return true; + } + + private static void disposeFrame() { + if (frame != null) { + frame.dispose(); + frame = null; + } + } + +} diff --git a/test/jdk/javax/swing/JTable/8236907/LastVisibleRow.java b/test/jdk/javax/swing/JTable/8236907/LastVisibleRow.java new file mode 100644 index 0000000000000000000000000000000000000000..6ca33c9635631628d1a160d99dd91f276702c72b --- /dev/null +++ b/test/jdk/javax/swing/JTable/8236907/LastVisibleRow.java @@ -0,0 +1,221 @@ +/* + * 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. + */ +/* + * @test + * @key headful + * @bug 8236907 + * @summary Verifies if JTable last row is visible. + * @run main LastVisibleRow + */ + +import java.awt.BorderLayout; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.event.InputEvent; +import java.awt.image.BufferedImage; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Robot; +import java.lang.reflect.InvocationTargetException; + +import javax.print.attribute.HashPrintRequestAttributeSet; +import javax.print.attribute.PrintRequestAttributeSet; + +import javax.swing.BorderFactory; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JTable; +import javax.swing.SwingUtilities; +import javax.swing.WindowConstants; + +public class LastVisibleRow { + static JFrame frame; + static JTable table; + static Robot testRobot; + + public static void main(String[] args) throws Exception { + Point clkPoint; + try { + testRobot = new Robot(); + + SwingUtilities.invokeAndWait(new Runnable() { + + public void run() { + createAndShowGUI(); + } + }); + testRobot.delay(1000); + testRobot.waitForIdle(); + BufferedImage bufferedImageBefore = testRobot.createScreenCapture(getCaptureRect()); + testRobot.delay(1000); + testRobot.waitForIdle(); + clkPoint = getMousePosition(); + mouseEvents(clkPoint); + testRobot.waitForIdle(); + clearSelect(); + testRobot.waitForIdle(); + BufferedImage bufferedImageAfter = testRobot.createScreenCapture(getCaptureRect()); + testRobot.delay(1000); + + if (!compare(bufferedImageBefore, bufferedImageAfter)) { + throw new RuntimeException("Test Case Failed!!"); + } + } finally { + if (frame != null) SwingUtilities.invokeAndWait(() -> frame.dispose()); + } + } + + /* + * + * Get clickable screen point for particular row and column of a table + * param row Row Number + * param column Column Number + * return Point + */ + private static Point getCellClickPoint(final int row, final int column) { + Point result; + + Rectangle rect = table.getCellRect(row, column, false); + Point point = new Point(rect.x + rect.width / 2, + rect.y + rect.height / 2); + SwingUtilities.convertPointToScreen(point, table); + result = point; + + return result; + } + + private static void createAndShowGUI() { + final PrintRequestAttributeSet printReqAttr = new HashPrintRequestAttributeSet(); + printReqAttr.add(javax.print.attribute.standard.OrientationRequested.LANDSCAPE); + frame = new JFrame(); + frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); + Container contentPane = frame.getContentPane(); + JPanel centerPane = new JPanel(new BorderLayout()); + centerPane.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); + JPanel tablePaneContainer = new JPanel(new BorderLayout()); + JPanel tablePane = new JPanel(new BorderLayout()); + table = new JTable(new Object[][]{{"row_1_col_1", "row_1_col_2", "row_1_col_3"}, {"row_2_col_1", "row_2_col_2", "row_2_col_3"}, {"row_3_col_1", "row_3_col_2", "row_3_col_3"}, {"row_4_col_1", "row_4_col_2", "row_4_col_3"}}, new String[]{"Col1", "Col2", "Col3"}); + table.setPreferredSize(new Dimension(0, (table.getRowHeight() * 3))); + + tablePane.add(table.getTableHeader(), BorderLayout.NORTH); + tablePane.add(table, BorderLayout.CENTER); + tablePaneContainer.add(tablePane, BorderLayout.CENTER); + centerPane.add(tablePaneContainer, BorderLayout.NORTH); + contentPane.add(centerPane, BorderLayout.CENTER); + frame.setSize(400, 120); + frame.setVisible(true); + frame.setLocationRelativeTo(null); + + } + + /* + * + * mouseEvents for last row click + */ + + private static void mouseEvents(Point clkPnt) { + testRobot.mouseMove(clkPnt.x, clkPnt.y); + testRobot.delay(50); + testRobot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + testRobot.delay(50); + testRobot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + testRobot.delay(50); + } + /* + * + * getMousePosition Actions for last row click + * returns Point + * throws Exception + */ + + private static Point getMousePosition() throws Exception { + final Point[] clickPoint = new Point[1]; + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + clickPoint[0] = getCellClickPoint(2, 0); + } + }); + return clickPoint[0]; + } + + /* + * + * Clears the selected table row + * throws Exception + */ + + private static void clearSelect() throws Exception { + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + table.getSelectionModel().clearSelection(); + table.setFocusable(false); + } + }); + } + + /* + * getCaptureRect Method - To Compute the Rectangle for + * Screen Capturing the Last Row for comparison + * return Rectangle + */ + + private static Rectangle getCaptureRect() throws InterruptedException, InvocationTargetException { + final Rectangle[] captureRect = new Rectangle[1]; + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + Rectangle cellRect = table.getCellRect(2, 0, true); + Point point = new Point(cellRect.x, cellRect.y); + SwingUtilities.convertPointToScreen(point, table); + + captureRect[0] = new Rectangle(point.x, point.y, table.getColumnCount() * cellRect.width, cellRect.height); + } + }); + return captureRect[0]; + } + + /* + * Compare method - to compare two images. + * param bufferedImage1 Buffered Image Before click + * param bufferedImage2 Buffered Image After click + * return Boolean + */ + + static Boolean compare(BufferedImage bufferedImage1, BufferedImage bufferedImage2) { + if (bufferedImage1.getWidth() == bufferedImage2.getWidth() + && bufferedImage1.getHeight() == bufferedImage2.getHeight()) { + for (int x = 0; x < bufferedImage1.getWidth(); x++) { + for (int y = 0; y < bufferedImage1.getHeight(); y++) { + if (bufferedImage1.getRGB(x, y) != bufferedImage2.getRGB(x, y)) { + return false; + } + } + } + } else { + return false; + } + return true; + } +} diff --git a/test/jdk/javax/swing/JTableHeader/8016524/JTHeaderBorderTest.java b/test/jdk/javax/swing/JTableHeader/8016524/JTHeaderBorderTest.java new file mode 100644 index 0000000000000000000000000000000000000000..0187abbb918a90e38fac0331248c601b2967da6a --- /dev/null +++ b/test/jdk/javax/swing/JTableHeader/8016524/JTHeaderBorderTest.java @@ -0,0 +1,123 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8016524 + * @requires (os.family=="mac") + * @key headful + * @summary Tests whether the bottom line of JTableHeader border is visible for MacOS default LAF + * @run main JTHeaderBorderTest + */ + +import java.awt.Graphics2D; +import javax.imageio.ImageIO; +import javax.swing.JFrame; +import javax.swing.JTable; +import javax.swing.JScrollPane; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import javax.swing.UnsupportedLookAndFeelException; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; + +import static java.awt.image.BufferedImage.TYPE_INT_ARGB; + +public class JTHeaderBorderTest { + + private static JFrame frame; + private static JTable table; + private static JScrollPane scrollableTable; + + private static final int FRAME_HT = 300; + private static final int FRAME_WT = 300; + private static final int TABLE_COLS = 3; + private static final int TABLE_ROWS = 2; + private static final int Y_OFFSET_START = 30; + private static final int Y_OFFSET_END = 55; + private static final int X_OFFSET = 25; + + public static void main(String[] args) throws Exception { + + try { + try { + UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + } catch (ClassNotFoundException | InstantiationException | IllegalAccessException + | UnsupportedLookAndFeelException e) { + throw new RuntimeException("Unsupported Look&Feel Class"); + } + + SwingUtilities.invokeAndWait(() -> { + table = new JTable(TABLE_ROWS, TABLE_COLS); + scrollableTable = new JScrollPane(table); + + frame = new JFrame(); + frame.getContentPane().add(scrollableTable); + frame.setSize(FRAME_WT, FRAME_HT); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + + // paint JFrame to BufferedImage + BufferedImage image = new BufferedImage(FRAME_WT, FRAME_HT, TYPE_INT_ARGB); + Graphics2D graphics2D = image.createGraphics(); + frame.paint(graphics2D); + graphics2D.dispose(); + + int tableColor = table.getBackground().getRGB(); + int headerColor = table.getTableHeader().getBackground().getRGB(); + //at start pixelColor initialized to table header background color + int pixelColor = headerColor; + boolean isBottomLineVisible = false; + + // scan table header region to check if bottom border of JTableHeader is visible + for (int y = Y_OFFSET_START; y <= Y_OFFSET_END; y++) { + pixelColor = image.getRGB(X_OFFSET, y); + System.out.println("Y offset: "+ y + " Color: "+ (Integer.toHexString(image.getRGB(X_OFFSET, y)))); + if (pixelColor != tableColor || pixelColor != headerColor) { + isBottomLineVisible = true; + break; + } + } + // throw Runtime Exception if border is not visible in the scanned region + if (!isBottomLineVisible) { + saveImage(image, "JTableHeader.png"); + throw new RuntimeException("JTableHeader Bottom Border not visible"); + } + }); + } finally { + if (frame != null) { + SwingUtilities.invokeAndWait(()-> frame.dispose()); + } + } + } + // to save the BufferedImage as .png in the event the test fails (for debugging purpose) + private static void saveImage(BufferedImage image, String filename) { + try { + ImageIO.write(image, "png", new File(filename)); + } catch (IOException e) { + e.printStackTrace(); + } + } +} diff --git a/test/jdk/javax/swing/JTextArea/4514331/TabShiftsFocusToNextComponent.java b/test/jdk/javax/swing/JTextArea/4514331/TabShiftsFocusToNextComponent.java new file mode 100644 index 0000000000000000000000000000000000000000..88e123aed54fbe10819e62a102c9c80a5e7aa53e --- /dev/null +++ b/test/jdk/javax/swing/JTextArea/4514331/TabShiftsFocusToNextComponent.java @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2002, 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. + */ + +import java.awt.Point; +import java.awt.Robot; +import java.awt.event.FocusAdapter; +import java.awt.event.FocusEvent; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicReference; +import java.util.stream.Collectors; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JTextArea; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import javax.swing.UnsupportedLookAndFeelException; + + +import static javax.swing.UIManager.getInstalledLookAndFeels; + +/* + * @test + * @key headful + * @bug 4514331 + * @summary Check whether pressing <Tab> key always shift focus to next component, + * even though the current focus is in JTextArea and some text is already selected. + * @run main TabShiftsFocusToNextComponent + */ +public class TabShiftsFocusToNextComponent { + + private static JFrame frame; + private static JTextArea textArea; + private static Robot robot; + private static CountDownLatch textAreaGainedFocusLatch; + private static CountDownLatch buttonGainedFocusLatch; + + public static void main(String[] s) throws Exception { + runTest(); + } + + public static void runTest() throws Exception { + robot = new Robot(); + robot.setAutoWaitForIdle(true); + robot.setAutoDelay(200); + List<String> lafs = Arrays.stream(getInstalledLookAndFeels()) + .map(UIManager.LookAndFeelInfo::getClassName) + .collect(Collectors.toList()); + for (final String laf : lafs) { + textAreaGainedFocusLatch = new CountDownLatch(1); + buttonGainedFocusLatch = new CountDownLatch(1); + try { + AtomicBoolean lafSetSuccess = new AtomicBoolean(false); + SwingUtilities.invokeAndWait(() -> { + lafSetSuccess.set(setLookAndFeel(laf)); + if (lafSetSuccess.get()) { + createUI(); + } + }); + if (!lafSetSuccess.get()) { + continue; + } + robot.waitForIdle(); + + SwingUtilities.invokeAndWait(() -> textArea.requestFocusInWindow()); + + // Waits until the textArea gains focus. + if (!textAreaGainedFocusLatch.await(3, TimeUnit.SECONDS)) { + throw new RuntimeException("Test Failed, waited for long, " + + "but the JTextArea can't gain focus for L&F: " + laf); + } + + AtomicReference<Point> textAreaLoc = new AtomicReference<Point>(); + SwingUtilities.invokeAndWait(() -> { + textAreaLoc.set(textArea.getLocationOnScreen()); + }); + + final int x = textAreaLoc.get().x; + final int y = textAreaLoc.get().y; + robot.mouseMove(x + 5, y + 5); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseMove(x + 20, y + 5); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.keyPress(KeyEvent.VK_TAB); + robot.keyRelease(KeyEvent.VK_TAB); + + // Waits until the button gains focus. + if (!buttonGainedFocusLatch.await(3, TimeUnit.SECONDS)) { + throw new RuntimeException("Test Failed, waited for long, " + + "but the Button can't gain focus when 'Tab' key pressed for L&F: " + laf); + } else { + System.out.println(" Test passed for " + laf); + } + } finally { + SwingUtilities.invokeAndWait(TabShiftsFocusToNextComponent::disposeFrame); + } + } + } + + + private static void createUI() { + frame = new JFrame(); + JPanel panel = new JPanel(); + textArea = new JTextArea("I am a JTextArea"); + textArea.addFocusListener(new FocusAdapter() { + @Override + public void focusGained(FocusEvent e) { + textAreaGainedFocusLatch.countDown(); + } + }); + textArea.setEditable(false); + panel.add(textArea); + JButton button = new JButton("Button"); + panel.add(button); + button.addFocusListener(new FocusAdapter() { + @Override + public void focusGained(FocusEvent e) { + buttonGainedFocusLatch.countDown(); + } + }); + + frame.add(panel); + frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + frame.setUndecorated(true); + frame.pack(); + frame.setAlwaysOnTop(true); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } + + private static boolean setLookAndFeel(String lafName) { + try { + UIManager.setLookAndFeel(lafName); + } catch (UnsupportedLookAndFeelException ignored) { + System.out.println("Ignoring Unsupported L&F: " + lafName); + return false; + } catch (ClassNotFoundException | InstantiationException + | IllegalAccessException e) { + throw new RuntimeException(e); + } + return true; + } + + private static void disposeFrame() { + if (frame != null) { + frame.dispose(); + frame = null; + } + } +} diff --git a/test/jdk/javax/swing/JTextField/4532513/DefaultCaretRequestsFocusTest.java b/test/jdk/javax/swing/JTextField/4532513/DefaultCaretRequestsFocusTest.java new file mode 100644 index 0000000000000000000000000000000000000000..b2fec6d9f94a33bbbed894e69ebe04ec2aa5dd1d --- /dev/null +++ b/test/jdk/javax/swing/JTextField/4532513/DefaultCaretRequestsFocusTest.java @@ -0,0 +1,193 @@ +/* + * Copyright (c) 2002, 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. + */ + +import java.awt.GridLayout; +import java.awt.Point; +import java.awt.Robot; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicReference; +import java.util.stream.Collectors; +import javax.swing.InputVerifier; +import javax.swing.JComponent; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JTextField; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import javax.swing.UIManager.LookAndFeelInfo; +import javax.swing.UnsupportedLookAndFeelException; + +import static javax.swing.UIManager.getInstalledLookAndFeels; + +/* + * @test + * @key headful + * @bug 4532513 + * @summary Verifies that DefaultCaret doesn't requests focus in mouseClick and mousePressed + * causing the associated input verifier to fire twice. + * @run main DefaultCaretRequestsFocusTest + */ +public class DefaultCaretRequestsFocusTest { + + private static JTextField jTextField1; + private static JTextField jTextField2; + private static JTextField jTextField3; + private static JFrame frame; + private static Robot robot; + private static volatile int shouldYieldFocusCount; + + public static void main(String[] args) throws Exception { + runTest(); + } + + public static void runTest() throws Exception { + robot = new Robot(); + robot.setAutoWaitForIdle(true); + robot.setAutoDelay(200); + + List<String> lafs = Arrays.stream(getInstalledLookAndFeels()) + .map(LookAndFeelInfo::getClassName) + .collect(Collectors.toList()); + for (final String laf : lafs) { + try { + AtomicBoolean lafSetSuccess = new AtomicBoolean(false); + SwingUtilities.invokeAndWait(() -> { + lafSetSuccess.set(setLookAndFeel(laf)); + if (lafSetSuccess.get()) { + createUI(); + } + }); + if (!lafSetSuccess.get()) { + continue; + } + robot.waitForIdle(); + + AtomicReference<Point> jTextField1LocRef = new AtomicReference<>(); + AtomicReference<Point> jTextField2LocRef = new AtomicReference<>(); + SwingUtilities.invokeAndWait(() -> { + jTextField1LocRef.set(jTextField1.getLocationOnScreen()); + jTextField2LocRef.set(jTextField2.getLocationOnScreen()); + }); + final Point jTextField1Loc = jTextField1LocRef.get(); + final Point jTextField2Loc = jTextField2LocRef.get(); + + shouldYieldFocusCount = 0; + + // Click on TextField2 + robot.mouseMove(jTextField2Loc.x + 5, jTextField2Loc.y + 5); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + + typeSomeText(); + + // Click on TextField1 + robot.mouseMove(jTextField1Loc.x + 5, jTextField1Loc.y + 5); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + + typeSomeText(); + + if (shouldYieldFocusCount == 1) { + System.out.println("Test passed for " + laf); + } else { + throw new RuntimeException("Test failed for " + laf + + " as InputVerifier.shouldYieldFocus() was called " + shouldYieldFocusCount + + " times on jTextField2, but it is expected to be called only once."); + } + + } finally { + SwingUtilities.invokeAndWait(DefaultCaretRequestsFocusTest::disposeFrame); + } + } + } + + private static void typeSomeText() { + robot.keyPress(KeyEvent.VK_T); + robot.keyRelease(KeyEvent.VK_T); + robot.keyPress(KeyEvent.VK_E); + robot.keyRelease(KeyEvent.VK_E); + robot.keyPress(KeyEvent.VK_X); + robot.keyRelease(KeyEvent.VK_X); + robot.keyPress(KeyEvent.VK_T); + robot.keyRelease(KeyEvent.VK_T); + } + + private static void createUI() { + frame = new JFrame(); + jTextField1 = new JTextField(6); + jTextField2 = new JTextField(6); + jTextField3 = new JTextField(6); + JPanel panel = new JPanel(); + panel.setLayout(new GridLayout(3, 1)); + panel.add(jTextField1); + panel.add(jTextField2); + panel.add(jTextField3); + + InputVerifier iv = new InputVerifier() { + public boolean verify(JComponent input) { + System.out.println("InputVerifier.verify() called"); + return false; + } + + public boolean shouldYieldFocus(JComponent input) { + ++shouldYieldFocusCount; + System.out.println("InputVerifier.shouldYieldFocus() called " + shouldYieldFocusCount); + return false; + } + }; + + jTextField2.setInputVerifier(iv); + + frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + frame.add(panel); + frame.pack(); + frame.setAlwaysOnTop(true); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } + + private static boolean setLookAndFeel(String lafName) { + try { + UIManager.setLookAndFeel(lafName); + } catch (UnsupportedLookAndFeelException ignored) { + System.out.println("Ignoring Unsupported laf : " + lafName); + return false; + } catch (ClassNotFoundException | InstantiationException + | IllegalAccessException e) { + throw new RuntimeException(e); + } + return true; + } + + private static void disposeFrame() { + if (frame != null) { + frame.dispose(); + frame = null; + } + } + +} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/DynamicFlag.java b/test/jdk/javax/swing/JTextField/SwingUnicodeTest.java similarity index 64% rename from test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/DynamicFlag.java rename to test/jdk/javax/swing/JTextField/SwingUnicodeTest.java index d505ddbbb9a70af2ec93711fe53ec9e7dfdbe525..94053602de5ffcf18e8f07115c39f8116f02db38 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/DynamicFlag.java +++ b/test/jdk/javax/swing/JTextField/SwingUnicodeTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -19,21 +19,20 @@ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. - * */ +import javax.swing.SwingUtilities; +import javax.swing.JTextField; /* * @test - * @summary The DynamicDumpShareSpaces flag is internal, setting it at the command line should have no effect. - * @requires vm.cds - * @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds - * @compile ../test-classes/Hello.java - * @run driver DynamicFlag + * @bug 8037965 + * @summary Verifies NPE in TextLayout.getBaselineFromGraphic() for invalid + * Unicode characters */ - -public class DynamicFlag { - public static void main(String[] args) throws Exception { - TestCommon.test(JarBuilder.getOrCreateHelloJar(), - TestCommon.list("Hello"), "-XX:+DynamicDumpSharedSpaces", "Hello"); - } +public class SwingUnicodeTest { + public static void main(String[] args) throws Exception { + SwingUtilities.invokeAndWait(() -> + new JTextField(new StringBuilder().appendCodePoint(0xFFFF). + appendCodePoint(0x10000).toString())); + } } diff --git a/test/jdk/javax/swing/JTextPane/TestJTextPaneBackgroundColor.java b/test/jdk/javax/swing/JTextPane/TestJTextPaneBackgroundColor.java index 99bc3a43f8ab9b119cf64c0e79b5c4ef5e5ed59e..67ceb534da07391bdc18229b06268a5c0238d522 100644 --- a/test/jdk/javax/swing/JTextPane/TestJTextPaneBackgroundColor.java +++ b/test/jdk/javax/swing/JTextPane/TestJTextPaneBackgroundColor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -96,7 +96,7 @@ public class TestJTextPaneBackgroundColor { panel.add(textPane, BorderLayout.CENTER); frame = new JFrame("TestJTextPaneBackgroundColor"); frame.add(panel); - frame.setSize(200, 200); + frame.setSize(400, 400); frame.setAlwaysOnTop(true); frame.setLocationRelativeTo(null); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); diff --git a/test/jdk/javax/swing/JToolTip/TestTooltipBackgroundColor.java b/test/jdk/javax/swing/JToolTip/TestTooltipBackgroundColor.java index 678bbbc4c7723f5b7637a73513a51232cc12f096..eb52a27d108926e49be3f7ebbd271b1e1a4deda8 100644 --- a/test/jdk/javax/swing/JToolTip/TestTooltipBackgroundColor.java +++ b/test/jdk/javax/swing/JToolTip/TestTooltipBackgroundColor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -134,7 +134,7 @@ public class TestTooltipBackgroundColor { panel.add(label, BorderLayout.CENTER); frame = new JFrame("TestTooltipBackgroundColor"); frame.add(panel); - frame.setSize(200, 200); + frame.setSize(400, 400); frame.setAlwaysOnTop(true); frame.setLocationRelativeTo(null); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); diff --git a/test/jdk/javax/swing/JTree/4518432/JTreeNodeCopyPasteTest.java b/test/jdk/javax/swing/JTree/4518432/JTreeNodeCopyPasteTest.java new file mode 100644 index 0000000000000000000000000000000000000000..7ca69edfa228bc60862bc573ebb204357d1d371e --- /dev/null +++ b/test/jdk/javax/swing/JTree/4518432/JTreeNodeCopyPasteTest.java @@ -0,0 +1,217 @@ +/* + * Copyright (c) 2002, 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. + */ + +import java.awt.Dimension; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicReference; +import java.util.stream.Collectors; +import javax.swing.JFrame; +import javax.swing.JTree; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import javax.swing.UIManager.LookAndFeelInfo; +import javax.swing.UnsupportedLookAndFeelException; + +import static javax.swing.UIManager.getInstalledLookAndFeels; + +/* + * @test + * @key headful + * @bug 4518432 + * @summary Verifies that Copying from JTree node and then changing the data in the component that was copied from, + * is not causing the pastes to use the new edited data instead of the original copied data. + * @run main JTreeNodeCopyPasteTest + */ +public class JTreeNodeCopyPasteTest { + + private static JFrame frame; + private static JTree tree; + private static Robot robot; + private static boolean isMac; + + public static void main(String[] args) throws Exception { + runTest(); + } + + private static void runTest() throws Exception { + isMac = System.getProperty("os.name").toLowerCase().contains("os x"); + robot = new Robot(); + robot.setAutoDelay(100); + robot.setAutoWaitForIdle(true); + + // Filter out Motif laf, as it doesn't support copy-paste in JTree. + List<String> lafs = Arrays.stream(getInstalledLookAndFeels()) + .filter(laf -> !laf.getName().contains("Motif")) + .map(LookAndFeelInfo::getClassName) + .collect(Collectors.toList()); + for (final String laf : lafs) { + try { + AtomicBoolean lafSetSuccess = new AtomicBoolean(false); + SwingUtilities.invokeAndWait(() -> { + lafSetSuccess.set(setLookAndFeel(laf)); + if (lafSetSuccess.get()) { + createUI(); + } + }); + if (!lafSetSuccess.get()) { + continue; + } + + robot.waitForIdle(); + + // Select the node named as 'colors' + Point pt = getNodeLocation(1); + robot.mouseMove(pt.x, pt.y); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + + String expectedNodeName = getCurrentNodeName(); + + // Copy the contents of that node + copyOrPaste(KeyEvent.VK_C, laf); + + // Edit the Contents of that cell + mouseTripleClick(); + + typeSomeText(); + + robot.keyPress(KeyEvent.VK_ENTER); + robot.keyRelease(KeyEvent.VK_ENTER); + + // Select next node + pt = getNodeLocation(2); + robot.mouseMove(pt.x, pt.y); + + // Edit the Contents of that cell + mouseTripleClick(); + + // paste the content copied earlier + copyOrPaste(KeyEvent.VK_V, laf); + + robot.keyPress(KeyEvent.VK_ENTER); + robot.keyRelease(KeyEvent.VK_ENTER); + + // Now get the node contents of second node + String actualNodeName = getCurrentNodeName(); + + if (expectedNodeName.equals(actualNodeName)) { + System.out.println("Test Passed in " + laf); + } else { + throw new RuntimeException("Test Failed in " + laf + ", Expected : " + expectedNodeName + + ", but actual : " + actualNodeName); + } + } finally { + SwingUtilities.invokeAndWait(JTreeNodeCopyPasteTest::disposeFrame); + } + } + } + + private static String getCurrentNodeName() throws Exception { + AtomicReference<String> nodeName = new AtomicReference<>(); + SwingUtilities.invokeAndWait(() -> { + nodeName.set(tree.getLastSelectedPathComponent().toString().trim()); + }); + return nodeName.get(); + } + + private static Point getNodeLocation(int rowCount) throws Exception { + AtomicReference<Point> treeNodeLoc = new AtomicReference<>(); + SwingUtilities.invokeAndWait(() -> { + final Point locationOnScreen = tree.getLocationOnScreen(); + Rectangle rt = tree.getPathBounds(tree.getPathForRow(rowCount)); + locationOnScreen.translate((int) (rt.getX() + rt.getWidth() / 2), (int) (rt.getY() + rt.getHeight() / 2)); + treeNodeLoc.set(locationOnScreen); + }); + return treeNodeLoc.get(); + } + + private static void copyOrPaste(int keyCode, String laf) { + // For AquaLookAndFeel in Mac, the key combination for copy/paste is META + (C or V) + // For other OSes and other lafs, the key combination is CONTROL + (C or V) + robot.keyPress(isMac && laf.contains("Aqua") ? KeyEvent.VK_META : KeyEvent.VK_CONTROL); + robot.keyPress(keyCode); + robot.keyRelease(keyCode); + robot.keyRelease(isMac && laf.contains("Aqua") ? KeyEvent.VK_META : KeyEvent.VK_CONTROL); + } + + private static void mouseTripleClick() { + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + } + + private static void typeSomeText() { + robot.keyPress(KeyEvent.VK_T); + robot.keyRelease(KeyEvent.VK_T); + robot.keyPress(KeyEvent.VK_E); + robot.keyRelease(KeyEvent.VK_E); + robot.keyPress(KeyEvent.VK_X); + robot.keyRelease(KeyEvent.VK_X); + robot.keyPress(KeyEvent.VK_T); + robot.keyRelease(KeyEvent.VK_T); + } + + private static void createUI() { + frame = new JFrame(); + tree = new JTree(); + tree.setEditable(true); + frame.setContentPane(tree); + frame.setSize(new Dimension(200, 200)); + frame.setAlwaysOnTop(true); + frame.setLocationRelativeTo(null); + frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + frame.toFront(); + frame.setVisible(true); + } + + private static boolean setLookAndFeel(String lafName) { + try { + UIManager.setLookAndFeel(lafName); + } catch (UnsupportedLookAndFeelException ignored) { + System.out.println("Ignoring Unsupported laf : " + lafName); + return false; + } catch (ClassNotFoundException | InstantiationException + | IllegalAccessException e) { + throw new RuntimeException(e); + } + return true; + } + + private static void disposeFrame() { + if (frame != null) { + frame.dispose(); + frame = null; + } + } + +} diff --git a/test/jdk/javax/swing/JTree/4618767/JTreeSelectedElementTest.java b/test/jdk/javax/swing/JTree/4618767/JTreeSelectedElementTest.java new file mode 100644 index 0000000000000000000000000000000000000000..19b00c05d37570e6b94580c234600b48018bbd97 --- /dev/null +++ b/test/jdk/javax/swing/JTree/4618767/JTreeSelectedElementTest.java @@ -0,0 +1,226 @@ +/* + * Copyright (c) 2002, 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. + */ + +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicReference; +import java.util.stream.Collectors; +import javax.swing.JFrame; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.JTree; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import javax.swing.UIManager.LookAndFeelInfo; +import javax.swing.UnsupportedLookAndFeelException; +import javax.swing.event.MenuEvent; +import javax.swing.event.MenuListener; + +import static javax.swing.UIManager.getInstalledLookAndFeels; + +/* + * @test + * @key headful + * @bug 4618767 + * @summary This test confirms that typing a letter while a JTree has focus now makes the selection + * not jump to the item whose text starts with that letter if that typed letter is accompanied + * by modifier keys such as ALT or CTRL(eg: ALT+F). + * @run main JTreeSelectedElementTest + */ +public class JTreeSelectedElementTest { + + private static final int FILE_MENU = KeyEvent.VK_F; + private static JFrame frame; + private static JTree tree; + private static Robot robot; + private static CountDownLatch menuSelectedEventLatch; + + public static void main(String[] args) throws Exception { + robot = new Robot(); + robot.setAutoWaitForIdle(true); + robot.setAutoDelay(200); + + final boolean isMac = System.getProperty("os.name") + .toLowerCase() + .contains("os x"); + + List<String> lafs = Arrays.stream(getInstalledLookAndFeels()) + .map(LookAndFeelInfo::getClassName) + .collect(Collectors.toList()); + for (final String laf : lafs) { + menuSelectedEventLatch = new CountDownLatch(1); + try { + AtomicBoolean lafSetSuccess = new AtomicBoolean(false); + SwingUtilities.invokeAndWait(() -> { + lafSetSuccess.set(setLookAndFeel(laf)); + if (lafSetSuccess.get()) { + createUI(); + } + }); + if (!lafSetSuccess.get()) { + continue; + } + robot.waitForIdle(); + + // Select the node named as 'colors' + Point pt = getNodeLocation(1); + robot.mouseMove(pt.x, pt.y); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + + // Assertion check to verify that the selected node is 'colors' + final String elementSelBefore = getCurrentNodeName(); + if (!"colors".equals(elementSelBefore)) { + throw new RuntimeException("Test failed for " + laf + + " as the tree node selected: " + elementSelBefore + + " is not the expected one 'colors'" + ); + } + + // Now operate Menu using Mnemonics, different key combinations for different OSes. + // For most OSes it's ALT+F; on macOS it's ALT+CNTRL+F except for Nimbus LaF. + if (isMac && !laf.contains("Nimbus")) { + hitKeys(KeyEvent.VK_ALT, KeyEvent.VK_CONTROL, FILE_MENU); + } else { + hitKeys(KeyEvent.VK_ALT, FILE_MENU); + } + + // Wait until the menu got selected. + if (!menuSelectedEventLatch.await(3, TimeUnit.SECONDS)) { + throw new RuntimeException("Waited too long, but can't select menu using mnemonics for " + laf); + } + + hitKeys(KeyEvent.VK_ENTER); + + String elementSelAfter = getCurrentNodeName(); + + // As per the fix of BugID 4618767, the tree element selection should not change + if (!elementSelBefore.equals(elementSelAfter)) { + throw new RuntimeException("Test failed for " + laf + + " as tree.getLastSelectedPathComponent() before: " + elementSelBefore + + " not same as tree.getLastSelectedPathComponent() after pressing Enter: " + + elementSelAfter + ); + } + + System.out.println("Test passed for laf: " + laf); + + } finally { + SwingUtilities.invokeAndWait(JTreeSelectedElementTest::disposeFrame); + } + } + } + + private static void hitKeys(int... keys) { + for (int key : keys) { + robot.keyPress(key); + } + + for (int i = keys.length - 1; i >= 0; i--) { + robot.keyRelease(keys[i]); + } + } + + private static String getCurrentNodeName() throws Exception { + AtomicReference<String> nodeName = new AtomicReference<>(); + SwingUtilities.invokeAndWait(() -> { + nodeName.set(tree.getLastSelectedPathComponent().toString().trim()); + }); + return nodeName.get(); + } + + private static Point getNodeLocation(int rowCount) throws Exception { + AtomicReference<Point> treeNodeLoc = new AtomicReference<>(); + SwingUtilities.invokeAndWait(() -> { + final Point locationOnScreen = tree.getLocationOnScreen(); + Rectangle rt = tree.getPathBounds(tree.getPathForRow(rowCount)); + locationOnScreen.translate(rt.x + rt.width / 2, rt.y + rt.height / 2); + treeNodeLoc.set(locationOnScreen); + }); + return treeNodeLoc.get(); + } + + private static void createUI() { + frame = new JFrame(); + tree = new JTree(); + JMenu menu = new JMenu("File"); + menu.setMnemonic(FILE_MENU); + JMenuItem menuItem = new JMenuItem("Dummy"); + menu.add(menuItem); + menu.addMenuListener(new MenuListener() { + @Override + public void menuSelected(MenuEvent e) { + menuSelectedEventLatch.countDown(); + } + + @Override + public void menuDeselected(MenuEvent e) { + } + + @Override + public void menuCanceled(MenuEvent e) { + } + }); + + JMenuBar menuBar = new JMenuBar(); + menuBar.add(menu); + + frame.setJMenuBar(menuBar); + frame.setContentPane(tree); + frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + frame.pack(); + frame.setAlwaysOnTop(true); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } + + private static boolean setLookAndFeel(String lafName) { + try { + UIManager.setLookAndFeel(lafName); + } catch (UnsupportedLookAndFeelException ignored) { + System.out.println("Ignoring Unsupported L&F: " + lafName); + return false; + } catch (ClassNotFoundException | InstantiationException + | IllegalAccessException e) { + throw new RuntimeException(e); + } + return true; + } + + private static void disposeFrame() { + if (frame != null) { + frame.dispose(); + frame = null; + } + } + +} diff --git a/test/jdk/javax/swing/JTree/4908142/bug4908142.java b/test/jdk/javax/swing/JTree/4908142/bug4908142.java index 671af8abd2db5f4af0522edbc1068c03876aef77..784feda153d676a6083193ee5529bb90638ebb3f 100644 --- a/test/jdk/javax/swing/JTree/4908142/bug4908142.java +++ b/test/jdk/javax/swing/JTree/4908142/bug4908142.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 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 @@ -60,6 +60,7 @@ public class bug4908142 { }); robot.waitForIdle(); + robot.delay(1000); SwingUtilities.invokeAndWait(new Runnable() { @@ -70,12 +71,14 @@ public class bug4908142 { }); robot.waitForIdle(); - + robot.delay(500); robot.keyPress(KeyEvent.VK_A); robot.keyRelease(KeyEvent.VK_A); + robot.waitForIdle(); robot.keyPress(KeyEvent.VK_A); robot.keyRelease(KeyEvent.VK_A); + robot.waitForIdle(); robot.keyPress(KeyEvent.VK_D); robot.keyRelease(KeyEvent.VK_D); robot.waitForIdle(); @@ -114,6 +117,7 @@ public class bug4908142 { JScrollPane sp = new JScrollPane(tree); fr.getContentPane().add(sp); + fr.setLocationRelativeTo(null); fr.setSize(200, 200); fr.setVisible(true); } diff --git a/test/jdk/javax/swing/plaf/aqua/JInternalFrameBorderTest.java b/test/jdk/javax/swing/plaf/aqua/JInternalFrameBorderTest.java new file mode 100644 index 0000000000000000000000000000000000000000..ef6c517fe3cbdf86bc0a0499a8ae12e97c8977aa --- /dev/null +++ b/test/jdk/javax/swing/plaf/aqua/JInternalFrameBorderTest.java @@ -0,0 +1,143 @@ +/* + * 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. + */ + +/* + * @test + * @key headful + * @bug 8139173 + * @requires (os.family == "mac") + * @summary Verify JInternalFrame's border + * @run main JInternalFrameBorderTest + */ + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Graphics; +import java.awt.Insets; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Robot; +import javax.swing.JDesktopPane; +import javax.swing.JFrame; +import javax.swing.JInternalFrame; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; + +public class JInternalFrameBorderTest { + + private static JFrame frame; + private static JDesktopPane desktopPane; + private static JInternalFrame internalFrame; + private static final int LIMIT = 100; + private static Robot robot; + private static Point pos; + private static Rectangle rect; + private static Insets insets; + + public static void main(String[] args) throws Exception { + robot = new Robot(); + createUI(); + robot.waitForIdle(); + robot.delay(1000); + + SwingUtilities.invokeAndWait(() -> { + pos = internalFrame.getLocationOnScreen(); + rect = internalFrame.getBounds(); + insets = internalFrame.getInsets(); + }); + robot.waitForIdle(); + + // bottom + int x = pos.x + rect.x + rect.width/2; + int y = pos.y + rect.y + rect.height - insets.bottom + 1; + Color colorBottom = robot.getPixelColor(x, y); + + // left + x = pos.x + rect.x + insets.left - 1; + y = pos.y + rect.y + rect.height/2; + Color colorLeft = robot.getPixelColor(x, y); + + // right + x = pos.x + rect.x + rect.width - insets.left + 1; + y = pos.y + rect.y + rect.height/2; + Color colorRight = robot.getPixelColor(x, y); + + robot.waitForIdle(); + cleanUp(); + + int diff = getDiff(colorLeft, colorBottom); + if (diff > LIMIT) { + throw new RuntimeException("Unexpected border bottom=" + + colorBottom + " left=" + colorLeft); + } + diff = getDiff(colorRight, colorBottom); + if (diff > LIMIT) { + throw new RuntimeException("Unexpected border bottom=" + + colorBottom + " right=" + colorRight); + } + } + + private static void createUI() throws Exception { + SwingUtilities.invokeAndWait(() -> { + try { + UIManager.setLookAndFeel("com.apple.laf.AquaLookAndFeel"); + } catch (Exception e) { + throw new RuntimeException("Cannot initialize Aqua L&F"); + } + desktopPane = new JDesktopPane() { + @Override + protected void paintComponent(Graphics g) { + super.paintComponent(g); + g.setColor(Color.BLUE); + g.fillRect(0, 0, getWidth(), getHeight()); + } + }; + internalFrame = new JInternalFrame(); + frame = new JFrame(); + internalFrame.setSize(500, 200); + internalFrame.setVisible(true); + desktopPane.add(internalFrame); + + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + frame.getContentPane().setLayout(new BorderLayout()); + frame.getContentPane().add(desktopPane, "Center"); + frame.setSize(500, 500); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + frame.toFront(); + }); + } + + private static int getDiff(Color c1, Color c2) { + int r = Math.abs(c1.getRed() - c2.getRed()); + int g = Math.abs(c1.getGreen() - c2.getGreen()); + int b = Math.abs(c1.getBlue() - c2.getBlue()); + return r + g + b; + } + + private static void cleanUp() throws Exception { + SwingUtilities.invokeAndWait(() -> { + frame.dispose(); + }); + } +} diff --git a/test/jdk/javax/swing/plaf/synth/SynthButtonUI/6276188/bug6276188.java b/test/jdk/javax/swing/plaf/synth/SynthButtonUI/6276188/bug6276188.java index 4664325db2112e43c4be88ef26e89ed915d16a97..be9c9457fff890e98317e853a55e863782d1ac59 100644 --- a/test/jdk/javax/swing/plaf/synth/SynthButtonUI/6276188/bug6276188.java +++ b/test/jdk/javax/swing/plaf/synth/SynthButtonUI/6276188/bug6276188.java @@ -37,46 +37,67 @@ import java.awt.event.*; import javax.swing.*; import javax.swing.plaf.synth.*; -public class bug6276188 extends JFrame { +public class bug6276188 { private static JButton button; private static Point p; + private static JFrame testFrame; + + // move away from cursor + private final static int OFFSET_X = -20; + private final static int OFFSET_Y = -20; public static void main(String[] args) throws Throwable { - SynthLookAndFeel lookAndFeel = new SynthLookAndFeel(); - lookAndFeel.load(bug6276188.class.getResourceAsStream("bug6276188.xml"), bug6276188.class); + try { + Robot robot = new Robot(); + robot.setAutoDelay(100); - UIManager.setLookAndFeel(lookAndFeel); - SwingUtilities.invokeAndWait(new Runnable() { - public void run() { - JFrame testFrame = new JFrame(); - testFrame.setLayout(new BorderLayout()); - testFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); - testFrame.add(BorderLayout.CENTER, button = new JButton()); + SynthLookAndFeel lookAndFeel = new SynthLookAndFeel(); + lookAndFeel.load(bug6276188.class.getResourceAsStream("bug6276188.xml"), bug6276188.class); + UIManager.setLookAndFeel(lookAndFeel); - testFrame.setSize(new Dimension(320, 200)); - testFrame.setVisible(true); - } - }); + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + testFrame = new JFrame(); + testFrame.setLayout(new BorderLayout()); + testFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + testFrame.add(BorderLayout.CENTER, button = new JButton()); - Robot robot = new Robot(); - robot.setAutoDelay(50); - robot.waitForIdle(); - robot.delay(200); + testFrame.setSize(new Dimension(320, 200)); + testFrame.setLocationRelativeTo(null); + testFrame.setVisible(true); + } + }); - p = Util.getCenterPoint(button); + robot.waitForIdle(); + robot.delay(1000); - robot.mouseMove(p.x , p.y); - robot.mousePress(InputEvent.BUTTON1_MASK); - robot.waitForIdle(); - robot.delay(1000); + p = Util.getCenterPoint(button); + System.out.println("Button center point: " + p); - Color color = robot.getPixelColor(p.x, p.y); - robot.mouseRelease(InputEvent.BUTTON1_MASK); - boolean red = color.getRed() > 0 && color.getGreen() == 0 && color.getBlue() == 0; - if (!red) { - System.err.println("Red: " + color.getRed() + "; Green: " + color.getGreen() + "; Blue: " + color.getBlue()); - throw new RuntimeException("Synth ButtonUI does not handle PRESSED & MOUSE_OVER state"); + robot.mouseMove(p.x , p.y); + robot.waitForIdle(); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.waitForIdle(); + + Color color = robot.getPixelColor(p.x - OFFSET_X, p.y - OFFSET_Y); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.waitForIdle(); + boolean red = color.getRed() > 0 && color.getGreen() == 0 && color.getBlue() == 0; + if (!red) { + System.err.println("Red: " + color.getRed() + "; Green: " + color.getGreen() + "; Blue: " + color.getBlue()); + Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); + Rectangle screen = new Rectangle(0, 0, (int) screenSize.getWidth(), (int) screenSize.getHeight()); + BufferedImage img = robot.createScreenCapture(screen); + javax.imageio.ImageIO.write(img, "png", new java.io.File("image.png")); + throw new RuntimeException("Synth ButtonUI does not handle PRESSED & MOUSE_OVER state"); + } + } finally { + SwingUtilities.invokeAndWait(() -> { + if (testFrame != null) { + testFrame.dispose(); + } + }); } } } diff --git a/test/jdk/javax/xml/crypto/dsig/BadXPointer.java b/test/jdk/javax/xml/crypto/dsig/BadXPointer.java new file mode 100644 index 0000000000000000000000000000000000000000..ba985b6c568893e9bcdfc5728751efa535c6dc21 --- /dev/null +++ b/test/jdk/javax/xml/crypto/dsig/BadXPointer.java @@ -0,0 +1,60 @@ +/* + * 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 jdk.test.lib.Asserts; +import jdk.test.lib.Utils; +import jdk.test.lib.security.XMLUtils; + +import javax.xml.crypto.URIReferenceException; +import javax.xml.crypto.dsig.XMLSignatureException; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.spec.ECGenParameterSpec; + +/** + * @test + * @bug 8278186 + * @summary reject malformed xpointer(id('a')) gracefully + * @library /test/lib + * @modules java.xml.crypto + */ +public class BadXPointer { + + public static void main(String[] args) throws Exception { + + KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC"); + kpg.initialize(new ECGenParameterSpec("secp256r1")); + KeyPair kp = kpg.generateKeyPair(); + + var signer = XMLUtils.signer(kp.getPrivate(), kp.getPublic()); + var doc = XMLUtils.string2doc("<root/>"); + + // No enclosing ' for id + Utils.runAndCheckException( + () -> signer.signEnveloping(doc, "a", "#xpointer(id('a))"), + ex -> Asserts.assertTrue(ex instanceof XMLSignatureException + && ex.getCause() instanceof URIReferenceException + && ex.getMessage().contains("Could not find a resolver"), + ex.toString())); + } +} diff --git a/test/jdk/jdk/incubator/vector/Byte128VectorTests.java b/test/jdk/jdk/incubator/vector/Byte128VectorTests.java index db2140d223ef0bffc29d821fa1db26eb04a26cdb..e7e97452b1660318177af74aec6a5199a071abe5 100644 --- a/test/jdk/jdk/incubator/vector/Byte128VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Byte128VectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -226,10 +226,10 @@ public class Byte128VectorTests extends AbstractVectorTest { } } - static void assertInsertArraysEquals(byte[] r, byte[] a, byte element, int index) { - int i = 0; + static void assertInsertArraysEquals(byte[] r, byte[] a, byte element, int index, int start, int end) { + int i = start; try { - for (; i < a.length; i += 1) { + for (; i < end; i += 1) { if(i%SPECIES.length() == index) { Assert.assertEquals(r[i], element); } else { @@ -1201,6 +1201,10 @@ public class Byte128VectorTests extends AbstractVectorTest { return Byte.compareUnsigned(a, b) >= 0; } + static byte firstNonZero(byte a, byte b) { + return Byte.compare(a, (byte) 0) != 0 ? a : b; + } + @Test static void smokeTest1() { ByteVector three = ByteVector.broadcast(SPECIES, (byte)-3); @@ -3216,7 +3220,7 @@ public class Byte128VectorTests extends AbstractVectorTest { static byte MINReduce(byte[] a, int idx) { byte res = Byte.MAX_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (byte)Math.min(res, a[i]); + res = (byte) Math.min(res, a[i]); } return res; @@ -3224,8 +3228,8 @@ public class Byte128VectorTests extends AbstractVectorTest { static byte MINReduceAll(byte[] a) { byte res = Byte.MAX_VALUE; - for (int i = 0; i < a.length; i++) { - res = (byte)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (byte) Math.min(res, MINReduce(a, i)); } return res; @@ -3247,7 +3251,7 @@ public class Byte128VectorTests extends AbstractVectorTest { ra = Byte.MAX_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte)Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + ra = (byte) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); } } @@ -3257,8 +3261,8 @@ public class Byte128VectorTests extends AbstractVectorTest { static byte MINReduceMasked(byte[] a, int idx, boolean[] mask) { byte res = Byte.MAX_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (byte)Math.min(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (byte) Math.min(res, a[i]); } return res; @@ -3266,9 +3270,8 @@ public class Byte128VectorTests extends AbstractVectorTest { static byte MINReduceAllMasked(byte[] a, boolean[] mask) { byte res = Byte.MAX_VALUE; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (byte)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (byte) Math.min(res, MINReduceMasked(a, i, mask)); } return res; @@ -3292,7 +3295,7 @@ public class Byte128VectorTests extends AbstractVectorTest { ra = Byte.MAX_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte)Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + ra = (byte) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); } } @@ -3302,7 +3305,7 @@ public class Byte128VectorTests extends AbstractVectorTest { static byte MAXReduce(byte[] a, int idx) { byte res = Byte.MIN_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (byte)Math.max(res, a[i]); + res = (byte) Math.max(res, a[i]); } return res; @@ -3310,8 +3313,8 @@ public class Byte128VectorTests extends AbstractVectorTest { static byte MAXReduceAll(byte[] a) { byte res = Byte.MIN_VALUE; - for (int i = 0; i < a.length; i++) { - res = (byte)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (byte) Math.max(res, MAXReduce(a, i)); } return res; @@ -3333,7 +3336,7 @@ public class Byte128VectorTests extends AbstractVectorTest { ra = Byte.MIN_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte)Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + ra = (byte) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); } } @@ -3343,8 +3346,8 @@ public class Byte128VectorTests extends AbstractVectorTest { static byte MAXReduceMasked(byte[] a, int idx, boolean[] mask) { byte res = Byte.MIN_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (byte)Math.max(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (byte) Math.max(res, a[i]); } return res; @@ -3352,9 +3355,8 @@ public class Byte128VectorTests extends AbstractVectorTest { static byte MAXReduceAllMasked(byte[] a, boolean[] mask) { byte res = Byte.MIN_VALUE; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (byte)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (byte) Math.max(res, MAXReduceMasked(a, i, mask)); } return res; @@ -3378,13 +3380,98 @@ public class Byte128VectorTests extends AbstractVectorTest { ra = Byte.MIN_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte)Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + ra = (byte) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); } } assertReductionArraysEqualsMasked(r, ra, a, mask, Byte128VectorTests::MAXReduceMasked, Byte128VectorTests::MAXReduceAllMasked); } + static byte FIRST_NONZEROReduce(byte[] a, int idx) { + byte res = (byte) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + res = firstNonZero(res, a[i]); + } + + return res; + } + + static byte FIRST_NONZEROReduceAll(byte[] a) { + byte res = (byte) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); + } + + return res; + } + @Test(dataProvider = "byteUnaryOpProvider") + static void FIRST_NONZEROReduceByte128VectorTests(IntFunction<byte[]> fa) { + byte[] a = fa.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + byte ra = (byte) 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); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (byte) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + } + } + + assertReductionArraysEquals(r, ra, a, + Byte128VectorTests::FIRST_NONZEROReduce, Byte128VectorTests::FIRST_NONZEROReduceAll); + } + static byte FIRST_NONZEROReduceMasked(byte[] a, int idx, boolean[] mask) { + byte res = (byte) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + if (mask[i % SPECIES.length()]) + res = firstNonZero(res, a[i]); + } + + return res; + } + + static byte FIRST_NONZEROReduceAllMasked(byte[] a, boolean[] mask) { + byte res = (byte) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); + } + + return res; + } + @Test(dataProvider = "byteUnaryOpMaskProvider") + static void FIRST_NONZEROReduceByte128VectorTestsMasked(IntFunction<byte[]> fa, IntFunction<boolean[]> fm) { + byte[] a = fa.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask<Byte> vmask = VectorMask.fromArray(SPECIES, mask, 0); + byte ra = (byte) 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); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (byte) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + } + } + + assertReductionArraysEqualsMasked(r, ra, a, mask, + Byte128VectorTests::FIRST_NONZEROReduceMasked, Byte128VectorTests::FIRST_NONZEROReduceAllMasked); + } static boolean anyTrue(boolean[] a, int idx) { boolean res = false; @@ -3444,13 +3531,16 @@ public class Byte128VectorTests extends AbstractVectorTest { byte[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { - for (int i = 0; i < a.length; i += SPECIES.length()) { + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - av.withLane(0, (byte)4).intoArray(r, i); + av.withLane((j++ & (SPECIES.length()-1)), (byte)(65535+i)).intoArray(r, i); } } - assertInsertArraysEquals(r, a, (byte)4, 0); + + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { + assertInsertArraysEquals(r, a, (byte)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); + } } static boolean testIS_DEFAULT(byte a) { return bits(a)==0; @@ -3474,19 +3564,21 @@ public class Byte128VectorTests extends AbstractVectorTest { } @Test(dataProvider = "byteTestOpMaskProvider") - static void IS_DEFAULTMaskedByte128VectorTestsSmokeTest(IntFunction<byte[]> fa, + static void IS_DEFAULTMaskedByte128VectorTests(IntFunction<byte[]> fa, IntFunction<boolean[]> fm) { byte[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Byte> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - VectorMask<Byte> mv = av.test(VectorOperators.IS_DEFAULT, vmask); + 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); + VectorMask<Byte> mv = av.test(VectorOperators.IS_DEFAULT, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_DEFAULT(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_DEFAULT(a[i + j])); + } } } } @@ -3512,19 +3604,21 @@ public class Byte128VectorTests extends AbstractVectorTest { } @Test(dataProvider = "byteTestOpMaskProvider") - static void IS_NEGATIVEMaskedByte128VectorTestsSmokeTest(IntFunction<byte[]> fa, + static void IS_NEGATIVEMaskedByte128VectorTests(IntFunction<byte[]> fa, IntFunction<boolean[]> fm) { byte[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Byte> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - VectorMask<Byte> mv = av.test(VectorOperators.IS_NEGATIVE, vmask); + 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); + VectorMask<Byte> mv = av.test(VectorOperators.IS_NEGATIVE, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_NEGATIVE(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_NEGATIVE(a[i + j])); + } } } } @@ -5512,7 +5606,7 @@ public class Byte128VectorTests extends AbstractVectorTest { static void maskFromToLongByte128VectorTestsSmokeTest(long inputLong) { var vmask = VectorMask.fromLong(SPECIES, inputLong); long outputLong = vmask.toLong(); - Assert.assertEquals(outputLong, inputLong & (((1L << (SPECIES.length() - 1)) << 1) - 1)); + Assert.assertEquals(outputLong, (inputLong & (((0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length())))))); } @DataProvider @@ -5614,5 +5708,12 @@ public class Byte128VectorTests extends AbstractVectorTest { VectorSpecies species = av.species().withShape(vsh); assert(species.equals(SPECIES)); } + + @Test + static void MaskAllTrueByte128VectorTestsSmokeTest() { + for (int ic = 0; ic < INVOC_COUNT; ic++) { + Assert.assertEquals(SPECIES.maskAll(true).toLong(), -1L >>> (64 - SPECIES.length())); + } + } } diff --git a/test/jdk/jdk/incubator/vector/Byte256VectorTests.java b/test/jdk/jdk/incubator/vector/Byte256VectorTests.java index b980f61df8c4e77218188b19b048b8881f834c36..aa14ff55a6d34ccfe224aa3d0c178da71fdcedf8 100644 --- a/test/jdk/jdk/incubator/vector/Byte256VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Byte256VectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -226,10 +226,10 @@ public class Byte256VectorTests extends AbstractVectorTest { } } - static void assertInsertArraysEquals(byte[] r, byte[] a, byte element, int index) { - int i = 0; + static void assertInsertArraysEquals(byte[] r, byte[] a, byte element, int index, int start, int end) { + int i = start; try { - for (; i < a.length; i += 1) { + for (; i < end; i += 1) { if(i%SPECIES.length() == index) { Assert.assertEquals(r[i], element); } else { @@ -1201,6 +1201,10 @@ public class Byte256VectorTests extends AbstractVectorTest { return Byte.compareUnsigned(a, b) >= 0; } + static byte firstNonZero(byte a, byte b) { + return Byte.compare(a, (byte) 0) != 0 ? a : b; + } + @Test static void smokeTest1() { ByteVector three = ByteVector.broadcast(SPECIES, (byte)-3); @@ -3216,7 +3220,7 @@ public class Byte256VectorTests extends AbstractVectorTest { static byte MINReduce(byte[] a, int idx) { byte res = Byte.MAX_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (byte)Math.min(res, a[i]); + res = (byte) Math.min(res, a[i]); } return res; @@ -3224,8 +3228,8 @@ public class Byte256VectorTests extends AbstractVectorTest { static byte MINReduceAll(byte[] a) { byte res = Byte.MAX_VALUE; - for (int i = 0; i < a.length; i++) { - res = (byte)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (byte) Math.min(res, MINReduce(a, i)); } return res; @@ -3247,7 +3251,7 @@ public class Byte256VectorTests extends AbstractVectorTest { ra = Byte.MAX_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte)Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + ra = (byte) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); } } @@ -3257,8 +3261,8 @@ public class Byte256VectorTests extends AbstractVectorTest { static byte MINReduceMasked(byte[] a, int idx, boolean[] mask) { byte res = Byte.MAX_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (byte)Math.min(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (byte) Math.min(res, a[i]); } return res; @@ -3266,9 +3270,8 @@ public class Byte256VectorTests extends AbstractVectorTest { static byte MINReduceAllMasked(byte[] a, boolean[] mask) { byte res = Byte.MAX_VALUE; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (byte)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (byte) Math.min(res, MINReduceMasked(a, i, mask)); } return res; @@ -3292,7 +3295,7 @@ public class Byte256VectorTests extends AbstractVectorTest { ra = Byte.MAX_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte)Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + ra = (byte) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); } } @@ -3302,7 +3305,7 @@ public class Byte256VectorTests extends AbstractVectorTest { static byte MAXReduce(byte[] a, int idx) { byte res = Byte.MIN_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (byte)Math.max(res, a[i]); + res = (byte) Math.max(res, a[i]); } return res; @@ -3310,8 +3313,8 @@ public class Byte256VectorTests extends AbstractVectorTest { static byte MAXReduceAll(byte[] a) { byte res = Byte.MIN_VALUE; - for (int i = 0; i < a.length; i++) { - res = (byte)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (byte) Math.max(res, MAXReduce(a, i)); } return res; @@ -3333,7 +3336,7 @@ public class Byte256VectorTests extends AbstractVectorTest { ra = Byte.MIN_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte)Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + ra = (byte) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); } } @@ -3343,8 +3346,8 @@ public class Byte256VectorTests extends AbstractVectorTest { static byte MAXReduceMasked(byte[] a, int idx, boolean[] mask) { byte res = Byte.MIN_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (byte)Math.max(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (byte) Math.max(res, a[i]); } return res; @@ -3352,9 +3355,8 @@ public class Byte256VectorTests extends AbstractVectorTest { static byte MAXReduceAllMasked(byte[] a, boolean[] mask) { byte res = Byte.MIN_VALUE; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (byte)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (byte) Math.max(res, MAXReduceMasked(a, i, mask)); } return res; @@ -3378,13 +3380,98 @@ public class Byte256VectorTests extends AbstractVectorTest { ra = Byte.MIN_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte)Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + ra = (byte) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); } } assertReductionArraysEqualsMasked(r, ra, a, mask, Byte256VectorTests::MAXReduceMasked, Byte256VectorTests::MAXReduceAllMasked); } + static byte FIRST_NONZEROReduce(byte[] a, int idx) { + byte res = (byte) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + res = firstNonZero(res, a[i]); + } + + return res; + } + + static byte FIRST_NONZEROReduceAll(byte[] a) { + byte res = (byte) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); + } + + return res; + } + @Test(dataProvider = "byteUnaryOpProvider") + static void FIRST_NONZEROReduceByte256VectorTests(IntFunction<byte[]> fa) { + byte[] a = fa.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + byte ra = (byte) 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); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (byte) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + } + } + + assertReductionArraysEquals(r, ra, a, + Byte256VectorTests::FIRST_NONZEROReduce, Byte256VectorTests::FIRST_NONZEROReduceAll); + } + static byte FIRST_NONZEROReduceMasked(byte[] a, int idx, boolean[] mask) { + byte res = (byte) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + if (mask[i % SPECIES.length()]) + res = firstNonZero(res, a[i]); + } + + return res; + } + + static byte FIRST_NONZEROReduceAllMasked(byte[] a, boolean[] mask) { + byte res = (byte) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); + } + + return res; + } + @Test(dataProvider = "byteUnaryOpMaskProvider") + static void FIRST_NONZEROReduceByte256VectorTestsMasked(IntFunction<byte[]> fa, IntFunction<boolean[]> fm) { + byte[] a = fa.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask<Byte> vmask = VectorMask.fromArray(SPECIES, mask, 0); + byte ra = (byte) 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); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (byte) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + } + } + + assertReductionArraysEqualsMasked(r, ra, a, mask, + Byte256VectorTests::FIRST_NONZEROReduceMasked, Byte256VectorTests::FIRST_NONZEROReduceAllMasked); + } static boolean anyTrue(boolean[] a, int idx) { boolean res = false; @@ -3444,13 +3531,16 @@ public class Byte256VectorTests extends AbstractVectorTest { byte[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { - for (int i = 0; i < a.length; i += SPECIES.length()) { + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - av.withLane(0, (byte)4).intoArray(r, i); + av.withLane((j++ & (SPECIES.length()-1)), (byte)(65535+i)).intoArray(r, i); } } - assertInsertArraysEquals(r, a, (byte)4, 0); + + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { + assertInsertArraysEquals(r, a, (byte)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); + } } static boolean testIS_DEFAULT(byte a) { return bits(a)==0; @@ -3474,19 +3564,21 @@ public class Byte256VectorTests extends AbstractVectorTest { } @Test(dataProvider = "byteTestOpMaskProvider") - static void IS_DEFAULTMaskedByte256VectorTestsSmokeTest(IntFunction<byte[]> fa, + static void IS_DEFAULTMaskedByte256VectorTests(IntFunction<byte[]> fa, IntFunction<boolean[]> fm) { byte[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Byte> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - VectorMask<Byte> mv = av.test(VectorOperators.IS_DEFAULT, vmask); + 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); + VectorMask<Byte> mv = av.test(VectorOperators.IS_DEFAULT, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_DEFAULT(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_DEFAULT(a[i + j])); + } } } } @@ -3512,19 +3604,21 @@ public class Byte256VectorTests extends AbstractVectorTest { } @Test(dataProvider = "byteTestOpMaskProvider") - static void IS_NEGATIVEMaskedByte256VectorTestsSmokeTest(IntFunction<byte[]> fa, + static void IS_NEGATIVEMaskedByte256VectorTests(IntFunction<byte[]> fa, IntFunction<boolean[]> fm) { byte[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Byte> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - VectorMask<Byte> mv = av.test(VectorOperators.IS_NEGATIVE, vmask); + 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); + VectorMask<Byte> mv = av.test(VectorOperators.IS_NEGATIVE, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_NEGATIVE(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_NEGATIVE(a[i + j])); + } } } } @@ -5512,7 +5606,7 @@ public class Byte256VectorTests extends AbstractVectorTest { static void maskFromToLongByte256VectorTestsSmokeTest(long inputLong) { var vmask = VectorMask.fromLong(SPECIES, inputLong); long outputLong = vmask.toLong(); - Assert.assertEquals(outputLong, inputLong & (((1L << (SPECIES.length() - 1)) << 1) - 1)); + Assert.assertEquals(outputLong, (inputLong & (((0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length())))))); } @DataProvider @@ -5614,5 +5708,12 @@ public class Byte256VectorTests extends AbstractVectorTest { VectorSpecies species = av.species().withShape(vsh); assert(species.equals(SPECIES)); } + + @Test + static void MaskAllTrueByte256VectorTestsSmokeTest() { + for (int ic = 0; ic < INVOC_COUNT; ic++) { + Assert.assertEquals(SPECIES.maskAll(true).toLong(), -1L >>> (64 - SPECIES.length())); + } + } } diff --git a/test/jdk/jdk/incubator/vector/Byte512VectorTests.java b/test/jdk/jdk/incubator/vector/Byte512VectorTests.java index 2ec4e8b2c539ec20c13edef959c1164406756337..c16f5d7d29668c70667b453032d64342fe8e9fe8 100644 --- a/test/jdk/jdk/incubator/vector/Byte512VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Byte512VectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -226,10 +226,10 @@ public class Byte512VectorTests extends AbstractVectorTest { } } - static void assertInsertArraysEquals(byte[] r, byte[] a, byte element, int index) { - int i = 0; + static void assertInsertArraysEquals(byte[] r, byte[] a, byte element, int index, int start, int end) { + int i = start; try { - for (; i < a.length; i += 1) { + for (; i < end; i += 1) { if(i%SPECIES.length() == index) { Assert.assertEquals(r[i], element); } else { @@ -1201,6 +1201,10 @@ public class Byte512VectorTests extends AbstractVectorTest { return Byte.compareUnsigned(a, b) >= 0; } + static byte firstNonZero(byte a, byte b) { + return Byte.compare(a, (byte) 0) != 0 ? a : b; + } + @Test static void smokeTest1() { ByteVector three = ByteVector.broadcast(SPECIES, (byte)-3); @@ -3216,7 +3220,7 @@ public class Byte512VectorTests extends AbstractVectorTest { static byte MINReduce(byte[] a, int idx) { byte res = Byte.MAX_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (byte)Math.min(res, a[i]); + res = (byte) Math.min(res, a[i]); } return res; @@ -3224,8 +3228,8 @@ public class Byte512VectorTests extends AbstractVectorTest { static byte MINReduceAll(byte[] a) { byte res = Byte.MAX_VALUE; - for (int i = 0; i < a.length; i++) { - res = (byte)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (byte) Math.min(res, MINReduce(a, i)); } return res; @@ -3247,7 +3251,7 @@ public class Byte512VectorTests extends AbstractVectorTest { ra = Byte.MAX_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte)Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + ra = (byte) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); } } @@ -3257,8 +3261,8 @@ public class Byte512VectorTests extends AbstractVectorTest { static byte MINReduceMasked(byte[] a, int idx, boolean[] mask) { byte res = Byte.MAX_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (byte)Math.min(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (byte) Math.min(res, a[i]); } return res; @@ -3266,9 +3270,8 @@ public class Byte512VectorTests extends AbstractVectorTest { static byte MINReduceAllMasked(byte[] a, boolean[] mask) { byte res = Byte.MAX_VALUE; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (byte)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (byte) Math.min(res, MINReduceMasked(a, i, mask)); } return res; @@ -3292,7 +3295,7 @@ public class Byte512VectorTests extends AbstractVectorTest { ra = Byte.MAX_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte)Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + ra = (byte) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); } } @@ -3302,7 +3305,7 @@ public class Byte512VectorTests extends AbstractVectorTest { static byte MAXReduce(byte[] a, int idx) { byte res = Byte.MIN_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (byte)Math.max(res, a[i]); + res = (byte) Math.max(res, a[i]); } return res; @@ -3310,8 +3313,8 @@ public class Byte512VectorTests extends AbstractVectorTest { static byte MAXReduceAll(byte[] a) { byte res = Byte.MIN_VALUE; - for (int i = 0; i < a.length; i++) { - res = (byte)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (byte) Math.max(res, MAXReduce(a, i)); } return res; @@ -3333,7 +3336,7 @@ public class Byte512VectorTests extends AbstractVectorTest { ra = Byte.MIN_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte)Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + ra = (byte) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); } } @@ -3343,8 +3346,8 @@ public class Byte512VectorTests extends AbstractVectorTest { static byte MAXReduceMasked(byte[] a, int idx, boolean[] mask) { byte res = Byte.MIN_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (byte)Math.max(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (byte) Math.max(res, a[i]); } return res; @@ -3352,9 +3355,8 @@ public class Byte512VectorTests extends AbstractVectorTest { static byte MAXReduceAllMasked(byte[] a, boolean[] mask) { byte res = Byte.MIN_VALUE; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (byte)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (byte) Math.max(res, MAXReduceMasked(a, i, mask)); } return res; @@ -3378,13 +3380,98 @@ public class Byte512VectorTests extends AbstractVectorTest { ra = Byte.MIN_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte)Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + ra = (byte) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); } } assertReductionArraysEqualsMasked(r, ra, a, mask, Byte512VectorTests::MAXReduceMasked, Byte512VectorTests::MAXReduceAllMasked); } + static byte FIRST_NONZEROReduce(byte[] a, int idx) { + byte res = (byte) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + res = firstNonZero(res, a[i]); + } + + return res; + } + + static byte FIRST_NONZEROReduceAll(byte[] a) { + byte res = (byte) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); + } + + return res; + } + @Test(dataProvider = "byteUnaryOpProvider") + static void FIRST_NONZEROReduceByte512VectorTests(IntFunction<byte[]> fa) { + byte[] a = fa.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + byte ra = (byte) 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); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (byte) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + } + } + + assertReductionArraysEquals(r, ra, a, + Byte512VectorTests::FIRST_NONZEROReduce, Byte512VectorTests::FIRST_NONZEROReduceAll); + } + static byte FIRST_NONZEROReduceMasked(byte[] a, int idx, boolean[] mask) { + byte res = (byte) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + if (mask[i % SPECIES.length()]) + res = firstNonZero(res, a[i]); + } + + return res; + } + + static byte FIRST_NONZEROReduceAllMasked(byte[] a, boolean[] mask) { + byte res = (byte) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); + } + + return res; + } + @Test(dataProvider = "byteUnaryOpMaskProvider") + static void FIRST_NONZEROReduceByte512VectorTestsMasked(IntFunction<byte[]> fa, IntFunction<boolean[]> fm) { + byte[] a = fa.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask<Byte> vmask = VectorMask.fromArray(SPECIES, mask, 0); + byte ra = (byte) 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); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (byte) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + } + } + + assertReductionArraysEqualsMasked(r, ra, a, mask, + Byte512VectorTests::FIRST_NONZEROReduceMasked, Byte512VectorTests::FIRST_NONZEROReduceAllMasked); + } static boolean anyTrue(boolean[] a, int idx) { boolean res = false; @@ -3444,13 +3531,16 @@ public class Byte512VectorTests extends AbstractVectorTest { byte[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { - for (int i = 0; i < a.length; i += SPECIES.length()) { + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - av.withLane(0, (byte)4).intoArray(r, i); + av.withLane((j++ & (SPECIES.length()-1)), (byte)(65535+i)).intoArray(r, i); } } - assertInsertArraysEquals(r, a, (byte)4, 0); + + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { + assertInsertArraysEquals(r, a, (byte)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); + } } static boolean testIS_DEFAULT(byte a) { return bits(a)==0; @@ -3474,19 +3564,21 @@ public class Byte512VectorTests extends AbstractVectorTest { } @Test(dataProvider = "byteTestOpMaskProvider") - static void IS_DEFAULTMaskedByte512VectorTestsSmokeTest(IntFunction<byte[]> fa, + static void IS_DEFAULTMaskedByte512VectorTests(IntFunction<byte[]> fa, IntFunction<boolean[]> fm) { byte[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Byte> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - VectorMask<Byte> mv = av.test(VectorOperators.IS_DEFAULT, vmask); + 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); + VectorMask<Byte> mv = av.test(VectorOperators.IS_DEFAULT, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_DEFAULT(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_DEFAULT(a[i + j])); + } } } } @@ -3512,19 +3604,21 @@ public class Byte512VectorTests extends AbstractVectorTest { } @Test(dataProvider = "byteTestOpMaskProvider") - static void IS_NEGATIVEMaskedByte512VectorTestsSmokeTest(IntFunction<byte[]> fa, + static void IS_NEGATIVEMaskedByte512VectorTests(IntFunction<byte[]> fa, IntFunction<boolean[]> fm) { byte[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Byte> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - VectorMask<Byte> mv = av.test(VectorOperators.IS_NEGATIVE, vmask); + 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); + VectorMask<Byte> mv = av.test(VectorOperators.IS_NEGATIVE, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_NEGATIVE(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_NEGATIVE(a[i + j])); + } } } } @@ -5512,7 +5606,7 @@ public class Byte512VectorTests extends AbstractVectorTest { static void maskFromToLongByte512VectorTestsSmokeTest(long inputLong) { var vmask = VectorMask.fromLong(SPECIES, inputLong); long outputLong = vmask.toLong(); - Assert.assertEquals(outputLong, inputLong & (((1L << (SPECIES.length() - 1)) << 1) - 1)); + Assert.assertEquals(outputLong, (inputLong & (((0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length())))))); } @DataProvider @@ -5614,5 +5708,12 @@ public class Byte512VectorTests extends AbstractVectorTest { VectorSpecies species = av.species().withShape(vsh); assert(species.equals(SPECIES)); } + + @Test + static void MaskAllTrueByte512VectorTestsSmokeTest() { + for (int ic = 0; ic < INVOC_COUNT; ic++) { + Assert.assertEquals(SPECIES.maskAll(true).toLong(), -1L >>> (64 - SPECIES.length())); + } + } } diff --git a/test/jdk/jdk/incubator/vector/Byte64VectorTests.java b/test/jdk/jdk/incubator/vector/Byte64VectorTests.java index 7ca7543a992a4701f8986694cfc712cc09006ee5..b47c7be7ed7e441c7f380d03f9178188990a480d 100644 --- a/test/jdk/jdk/incubator/vector/Byte64VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Byte64VectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -226,10 +226,10 @@ public class Byte64VectorTests extends AbstractVectorTest { } } - static void assertInsertArraysEquals(byte[] r, byte[] a, byte element, int index) { - int i = 0; + static void assertInsertArraysEquals(byte[] r, byte[] a, byte element, int index, int start, int end) { + int i = start; try { - for (; i < a.length; i += 1) { + for (; i < end; i += 1) { if(i%SPECIES.length() == index) { Assert.assertEquals(r[i], element); } else { @@ -1201,6 +1201,10 @@ public class Byte64VectorTests extends AbstractVectorTest { return Byte.compareUnsigned(a, b) >= 0; } + static byte firstNonZero(byte a, byte b) { + return Byte.compare(a, (byte) 0) != 0 ? a : b; + } + @Test static void smokeTest1() { ByteVector three = ByteVector.broadcast(SPECIES, (byte)-3); @@ -3216,7 +3220,7 @@ public class Byte64VectorTests extends AbstractVectorTest { static byte MINReduce(byte[] a, int idx) { byte res = Byte.MAX_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (byte)Math.min(res, a[i]); + res = (byte) Math.min(res, a[i]); } return res; @@ -3224,8 +3228,8 @@ public class Byte64VectorTests extends AbstractVectorTest { static byte MINReduceAll(byte[] a) { byte res = Byte.MAX_VALUE; - for (int i = 0; i < a.length; i++) { - res = (byte)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (byte) Math.min(res, MINReduce(a, i)); } return res; @@ -3247,7 +3251,7 @@ public class Byte64VectorTests extends AbstractVectorTest { ra = Byte.MAX_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte)Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + ra = (byte) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); } } @@ -3257,8 +3261,8 @@ public class Byte64VectorTests extends AbstractVectorTest { static byte MINReduceMasked(byte[] a, int idx, boolean[] mask) { byte res = Byte.MAX_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (byte)Math.min(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (byte) Math.min(res, a[i]); } return res; @@ -3266,9 +3270,8 @@ public class Byte64VectorTests extends AbstractVectorTest { static byte MINReduceAllMasked(byte[] a, boolean[] mask) { byte res = Byte.MAX_VALUE; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (byte)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (byte) Math.min(res, MINReduceMasked(a, i, mask)); } return res; @@ -3292,7 +3295,7 @@ public class Byte64VectorTests extends AbstractVectorTest { ra = Byte.MAX_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte)Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + ra = (byte) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); } } @@ -3302,7 +3305,7 @@ public class Byte64VectorTests extends AbstractVectorTest { static byte MAXReduce(byte[] a, int idx) { byte res = Byte.MIN_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (byte)Math.max(res, a[i]); + res = (byte) Math.max(res, a[i]); } return res; @@ -3310,8 +3313,8 @@ public class Byte64VectorTests extends AbstractVectorTest { static byte MAXReduceAll(byte[] a) { byte res = Byte.MIN_VALUE; - for (int i = 0; i < a.length; i++) { - res = (byte)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (byte) Math.max(res, MAXReduce(a, i)); } return res; @@ -3333,7 +3336,7 @@ public class Byte64VectorTests extends AbstractVectorTest { ra = Byte.MIN_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte)Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + ra = (byte) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); } } @@ -3343,8 +3346,8 @@ public class Byte64VectorTests extends AbstractVectorTest { static byte MAXReduceMasked(byte[] a, int idx, boolean[] mask) { byte res = Byte.MIN_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (byte)Math.max(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (byte) Math.max(res, a[i]); } return res; @@ -3352,9 +3355,8 @@ public class Byte64VectorTests extends AbstractVectorTest { static byte MAXReduceAllMasked(byte[] a, boolean[] mask) { byte res = Byte.MIN_VALUE; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (byte)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (byte) Math.max(res, MAXReduceMasked(a, i, mask)); } return res; @@ -3378,13 +3380,98 @@ public class Byte64VectorTests extends AbstractVectorTest { ra = Byte.MIN_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte)Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + ra = (byte) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); } } assertReductionArraysEqualsMasked(r, ra, a, mask, Byte64VectorTests::MAXReduceMasked, Byte64VectorTests::MAXReduceAllMasked); } + static byte FIRST_NONZEROReduce(byte[] a, int idx) { + byte res = (byte) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + res = firstNonZero(res, a[i]); + } + + return res; + } + + static byte FIRST_NONZEROReduceAll(byte[] a) { + byte res = (byte) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); + } + + return res; + } + @Test(dataProvider = "byteUnaryOpProvider") + static void FIRST_NONZEROReduceByte64VectorTests(IntFunction<byte[]> fa) { + byte[] a = fa.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + byte ra = (byte) 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); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (byte) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + } + } + + assertReductionArraysEquals(r, ra, a, + Byte64VectorTests::FIRST_NONZEROReduce, Byte64VectorTests::FIRST_NONZEROReduceAll); + } + static byte FIRST_NONZEROReduceMasked(byte[] a, int idx, boolean[] mask) { + byte res = (byte) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + if (mask[i % SPECIES.length()]) + res = firstNonZero(res, a[i]); + } + + return res; + } + + static byte FIRST_NONZEROReduceAllMasked(byte[] a, boolean[] mask) { + byte res = (byte) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); + } + + return res; + } + @Test(dataProvider = "byteUnaryOpMaskProvider") + static void FIRST_NONZEROReduceByte64VectorTestsMasked(IntFunction<byte[]> fa, IntFunction<boolean[]> fm) { + byte[] a = fa.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask<Byte> vmask = VectorMask.fromArray(SPECIES, mask, 0); + byte ra = (byte) 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); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (byte) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + } + } + + assertReductionArraysEqualsMasked(r, ra, a, mask, + Byte64VectorTests::FIRST_NONZEROReduceMasked, Byte64VectorTests::FIRST_NONZEROReduceAllMasked); + } static boolean anyTrue(boolean[] a, int idx) { boolean res = false; @@ -3444,13 +3531,16 @@ public class Byte64VectorTests extends AbstractVectorTest { byte[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { - for (int i = 0; i < a.length; i += SPECIES.length()) { + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - av.withLane(0, (byte)4).intoArray(r, i); + av.withLane((j++ & (SPECIES.length()-1)), (byte)(65535+i)).intoArray(r, i); } } - assertInsertArraysEquals(r, a, (byte)4, 0); + + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { + assertInsertArraysEquals(r, a, (byte)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); + } } static boolean testIS_DEFAULT(byte a) { return bits(a)==0; @@ -3474,19 +3564,21 @@ public class Byte64VectorTests extends AbstractVectorTest { } @Test(dataProvider = "byteTestOpMaskProvider") - static void IS_DEFAULTMaskedByte64VectorTestsSmokeTest(IntFunction<byte[]> fa, + static void IS_DEFAULTMaskedByte64VectorTests(IntFunction<byte[]> fa, IntFunction<boolean[]> fm) { byte[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Byte> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - VectorMask<Byte> mv = av.test(VectorOperators.IS_DEFAULT, vmask); + 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); + VectorMask<Byte> mv = av.test(VectorOperators.IS_DEFAULT, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_DEFAULT(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_DEFAULT(a[i + j])); + } } } } @@ -3512,19 +3604,21 @@ public class Byte64VectorTests extends AbstractVectorTest { } @Test(dataProvider = "byteTestOpMaskProvider") - static void IS_NEGATIVEMaskedByte64VectorTestsSmokeTest(IntFunction<byte[]> fa, + static void IS_NEGATIVEMaskedByte64VectorTests(IntFunction<byte[]> fa, IntFunction<boolean[]> fm) { byte[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Byte> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - VectorMask<Byte> mv = av.test(VectorOperators.IS_NEGATIVE, vmask); + 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); + VectorMask<Byte> mv = av.test(VectorOperators.IS_NEGATIVE, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_NEGATIVE(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_NEGATIVE(a[i + j])); + } } } } @@ -5512,7 +5606,7 @@ public class Byte64VectorTests extends AbstractVectorTest { static void maskFromToLongByte64VectorTestsSmokeTest(long inputLong) { var vmask = VectorMask.fromLong(SPECIES, inputLong); long outputLong = vmask.toLong(); - Assert.assertEquals(outputLong, inputLong & (((1L << (SPECIES.length() - 1)) << 1) - 1)); + Assert.assertEquals(outputLong, (inputLong & (((0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length())))))); } @DataProvider @@ -5614,5 +5708,12 @@ public class Byte64VectorTests extends AbstractVectorTest { VectorSpecies species = av.species().withShape(vsh); assert(species.equals(SPECIES)); } + + @Test + static void MaskAllTrueByte64VectorTestsSmokeTest() { + for (int ic = 0; ic < INVOC_COUNT; ic++) { + Assert.assertEquals(SPECIES.maskAll(true).toLong(), -1L >>> (64 - SPECIES.length())); + } + } } diff --git a/test/jdk/jdk/incubator/vector/ByteMaxVectorTests.java b/test/jdk/jdk/incubator/vector/ByteMaxVectorTests.java index 422dd249a8d4ca1580bd175f0b85ffc8e9fbf141..7499c29fd50926e6fe0422c0dd250cf792ba6012 100644 --- a/test/jdk/jdk/incubator/vector/ByteMaxVectorTests.java +++ b/test/jdk/jdk/incubator/vector/ByteMaxVectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -231,10 +231,10 @@ public class ByteMaxVectorTests extends AbstractVectorTest { } } - static void assertInsertArraysEquals(byte[] r, byte[] a, byte element, int index) { - int i = 0; + static void assertInsertArraysEquals(byte[] r, byte[] a, byte element, int index, int start, int end) { + int i = start; try { - for (; i < a.length; i += 1) { + for (; i < end; i += 1) { if(i%SPECIES.length() == index) { Assert.assertEquals(r[i], element); } else { @@ -1206,6 +1206,10 @@ public class ByteMaxVectorTests extends AbstractVectorTest { return Byte.compareUnsigned(a, b) >= 0; } + static byte firstNonZero(byte a, byte b) { + return Byte.compare(a, (byte) 0) != 0 ? a : b; + } + @Test static void smokeTest1() { ByteVector three = ByteVector.broadcast(SPECIES, (byte)-3); @@ -3221,7 +3225,7 @@ public class ByteMaxVectorTests extends AbstractVectorTest { static byte MINReduce(byte[] a, int idx) { byte res = Byte.MAX_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (byte)Math.min(res, a[i]); + res = (byte) Math.min(res, a[i]); } return res; @@ -3229,8 +3233,8 @@ public class ByteMaxVectorTests extends AbstractVectorTest { static byte MINReduceAll(byte[] a) { byte res = Byte.MAX_VALUE; - for (int i = 0; i < a.length; i++) { - res = (byte)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (byte) Math.min(res, MINReduce(a, i)); } return res; @@ -3252,7 +3256,7 @@ public class ByteMaxVectorTests extends AbstractVectorTest { ra = Byte.MAX_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte)Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + ra = (byte) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); } } @@ -3262,8 +3266,8 @@ public class ByteMaxVectorTests extends AbstractVectorTest { static byte MINReduceMasked(byte[] a, int idx, boolean[] mask) { byte res = Byte.MAX_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (byte)Math.min(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (byte) Math.min(res, a[i]); } return res; @@ -3271,9 +3275,8 @@ public class ByteMaxVectorTests extends AbstractVectorTest { static byte MINReduceAllMasked(byte[] a, boolean[] mask) { byte res = Byte.MAX_VALUE; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (byte)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (byte) Math.min(res, MINReduceMasked(a, i, mask)); } return res; @@ -3297,7 +3300,7 @@ public class ByteMaxVectorTests extends AbstractVectorTest { ra = Byte.MAX_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte)Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + ra = (byte) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); } } @@ -3307,7 +3310,7 @@ public class ByteMaxVectorTests extends AbstractVectorTest { static byte MAXReduce(byte[] a, int idx) { byte res = Byte.MIN_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (byte)Math.max(res, a[i]); + res = (byte) Math.max(res, a[i]); } return res; @@ -3315,8 +3318,8 @@ public class ByteMaxVectorTests extends AbstractVectorTest { static byte MAXReduceAll(byte[] a) { byte res = Byte.MIN_VALUE; - for (int i = 0; i < a.length; i++) { - res = (byte)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (byte) Math.max(res, MAXReduce(a, i)); } return res; @@ -3338,7 +3341,7 @@ public class ByteMaxVectorTests extends AbstractVectorTest { ra = Byte.MIN_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte)Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + ra = (byte) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); } } @@ -3348,8 +3351,8 @@ public class ByteMaxVectorTests extends AbstractVectorTest { static byte MAXReduceMasked(byte[] a, int idx, boolean[] mask) { byte res = Byte.MIN_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (byte)Math.max(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (byte) Math.max(res, a[i]); } return res; @@ -3357,9 +3360,8 @@ public class ByteMaxVectorTests extends AbstractVectorTest { static byte MAXReduceAllMasked(byte[] a, boolean[] mask) { byte res = Byte.MIN_VALUE; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (byte)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (byte) Math.max(res, MAXReduceMasked(a, i, mask)); } return res; @@ -3383,13 +3385,98 @@ public class ByteMaxVectorTests extends AbstractVectorTest { ra = Byte.MIN_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte)Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + ra = (byte) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); } } assertReductionArraysEqualsMasked(r, ra, a, mask, ByteMaxVectorTests::MAXReduceMasked, ByteMaxVectorTests::MAXReduceAllMasked); } + static byte FIRST_NONZEROReduce(byte[] a, int idx) { + byte res = (byte) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + res = firstNonZero(res, a[i]); + } + + return res; + } + + static byte FIRST_NONZEROReduceAll(byte[] a) { + byte res = (byte) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); + } + + return res; + } + @Test(dataProvider = "byteUnaryOpProvider") + static void FIRST_NONZEROReduceByteMaxVectorTests(IntFunction<byte[]> fa) { + byte[] a = fa.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + byte ra = (byte) 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); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (byte) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + } + } + + assertReductionArraysEquals(r, ra, a, + ByteMaxVectorTests::FIRST_NONZEROReduce, ByteMaxVectorTests::FIRST_NONZEROReduceAll); + } + static byte FIRST_NONZEROReduceMasked(byte[] a, int idx, boolean[] mask) { + byte res = (byte) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + if (mask[i % SPECIES.length()]) + res = firstNonZero(res, a[i]); + } + + return res; + } + + static byte FIRST_NONZEROReduceAllMasked(byte[] a, boolean[] mask) { + byte res = (byte) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); + } + + return res; + } + @Test(dataProvider = "byteUnaryOpMaskProvider") + static void FIRST_NONZEROReduceByteMaxVectorTestsMasked(IntFunction<byte[]> fa, IntFunction<boolean[]> fm) { + byte[] a = fa.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask<Byte> vmask = VectorMask.fromArray(SPECIES, mask, 0); + byte ra = (byte) 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); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (byte) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + } + } + + assertReductionArraysEqualsMasked(r, ra, a, mask, + ByteMaxVectorTests::FIRST_NONZEROReduceMasked, ByteMaxVectorTests::FIRST_NONZEROReduceAllMasked); + } static boolean anyTrue(boolean[] a, int idx) { boolean res = false; @@ -3449,13 +3536,16 @@ public class ByteMaxVectorTests extends AbstractVectorTest { byte[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { - for (int i = 0; i < a.length; i += SPECIES.length()) { + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - av.withLane(0, (byte)4).intoArray(r, i); + av.withLane((j++ & (SPECIES.length()-1)), (byte)(65535+i)).intoArray(r, i); } } - assertInsertArraysEquals(r, a, (byte)4, 0); + + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { + assertInsertArraysEquals(r, a, (byte)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); + } } static boolean testIS_DEFAULT(byte a) { return bits(a)==0; @@ -3479,19 +3569,21 @@ public class ByteMaxVectorTests extends AbstractVectorTest { } @Test(dataProvider = "byteTestOpMaskProvider") - static void IS_DEFAULTMaskedByteMaxVectorTestsSmokeTest(IntFunction<byte[]> fa, + static void IS_DEFAULTMaskedByteMaxVectorTests(IntFunction<byte[]> fa, IntFunction<boolean[]> fm) { byte[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Byte> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - VectorMask<Byte> mv = av.test(VectorOperators.IS_DEFAULT, vmask); + 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); + VectorMask<Byte> mv = av.test(VectorOperators.IS_DEFAULT, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_DEFAULT(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_DEFAULT(a[i + j])); + } } } } @@ -3517,19 +3609,21 @@ public class ByteMaxVectorTests extends AbstractVectorTest { } @Test(dataProvider = "byteTestOpMaskProvider") - static void IS_NEGATIVEMaskedByteMaxVectorTestsSmokeTest(IntFunction<byte[]> fa, + static void IS_NEGATIVEMaskedByteMaxVectorTests(IntFunction<byte[]> fa, IntFunction<boolean[]> fm) { byte[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Byte> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - VectorMask<Byte> mv = av.test(VectorOperators.IS_NEGATIVE, vmask); + 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); + VectorMask<Byte> mv = av.test(VectorOperators.IS_NEGATIVE, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_NEGATIVE(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_NEGATIVE(a[i + j])); + } } } } @@ -5603,5 +5697,12 @@ public class ByteMaxVectorTests extends AbstractVectorTest { VectorSpecies species = av.species().withShape(vsh); assert(species.equals(SPECIES)); } + + @Test + static void MaskAllTrueByteMaxVectorTestsSmokeTest() { + for (int ic = 0; ic < INVOC_COUNT; ic++) { + Assert.assertEquals(SPECIES.maskAll(true).toLong(), -1L >>> (64 - SPECIES.length())); + } + } } diff --git a/test/jdk/jdk/incubator/vector/Double128VectorTests.java b/test/jdk/jdk/incubator/vector/Double128VectorTests.java index a2dd0d44720a91bd5f24a1fe3748af3030df1a6b..15a55af00c0762964b9d08b2781c6ce07c113601 100644 --- a/test/jdk/jdk/incubator/vector/Double128VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Double128VectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -226,10 +226,10 @@ public class Double128VectorTests extends AbstractVectorTest { } } - static void assertInsertArraysEquals(double[] r, double[] a, double element, int index) { - int i = 0; + static void assertInsertArraysEquals(double[] r, double[] a, double element, int index, int start, int end) { + int i = start; try { - for (; i < a.length; i += 1) { + for (; i < end; i += 1) { if(i%SPECIES.length() == index) { Assert.assertEquals(r[i], element); } else { @@ -1299,6 +1299,10 @@ public class Double128VectorTests extends AbstractVectorTest { } + static double firstNonZero(double a, double b) { + return Double.compare(a, (double) 0) != 0 ? a : b; + } + @Test static void smokeTest1() { DoubleVector three = DoubleVector.broadcast(SPECIES, (byte)-3); @@ -2277,7 +2281,7 @@ public class Double128VectorTests extends AbstractVectorTest { static double MINReduce(double[] a, int idx) { double res = Double.POSITIVE_INFINITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (double)Math.min(res, a[i]); + res = (double) Math.min(res, a[i]); } return res; @@ -2285,8 +2289,8 @@ public class Double128VectorTests extends AbstractVectorTest { static double MINReduceAll(double[] a) { double res = Double.POSITIVE_INFINITY; - for (int i = 0; i < a.length; i++) { - res = (double)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (double) Math.min(res, MINReduce(a, i)); } return res; @@ -2308,7 +2312,7 @@ public class Double128VectorTests extends AbstractVectorTest { ra = Double.POSITIVE_INFINITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = (double)Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + ra = (double) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); } } @@ -2318,8 +2322,8 @@ public class Double128VectorTests extends AbstractVectorTest { static double MINReduceMasked(double[] a, int idx, boolean[] mask) { double res = Double.POSITIVE_INFINITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (double)Math.min(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (double) Math.min(res, a[i]); } return res; @@ -2327,9 +2331,8 @@ public class Double128VectorTests extends AbstractVectorTest { static double MINReduceAllMasked(double[] a, boolean[] mask) { double res = Double.POSITIVE_INFINITY; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (double)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (double) Math.min(res, MINReduceMasked(a, i, mask)); } return res; @@ -2353,7 +2356,7 @@ public class Double128VectorTests extends AbstractVectorTest { ra = Double.POSITIVE_INFINITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = (double)Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + ra = (double) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); } } @@ -2363,7 +2366,7 @@ public class Double128VectorTests extends AbstractVectorTest { static double MAXReduce(double[] a, int idx) { double res = Double.NEGATIVE_INFINITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (double)Math.max(res, a[i]); + res = (double) Math.max(res, a[i]); } return res; @@ -2371,8 +2374,8 @@ public class Double128VectorTests extends AbstractVectorTest { static double MAXReduceAll(double[] a) { double res = Double.NEGATIVE_INFINITY; - for (int i = 0; i < a.length; i++) { - res = (double)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (double) Math.max(res, MAXReduce(a, i)); } return res; @@ -2394,7 +2397,7 @@ public class Double128VectorTests extends AbstractVectorTest { ra = Double.NEGATIVE_INFINITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = (double)Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + ra = (double) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); } } @@ -2404,8 +2407,8 @@ public class Double128VectorTests extends AbstractVectorTest { static double MAXReduceMasked(double[] a, int idx, boolean[] mask) { double res = Double.NEGATIVE_INFINITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (double)Math.max(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (double) Math.max(res, a[i]); } return res; @@ -2413,9 +2416,8 @@ public class Double128VectorTests extends AbstractVectorTest { static double MAXReduceAllMasked(double[] a, boolean[] mask) { double res = Double.NEGATIVE_INFINITY; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (double)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (double) Math.max(res, MAXReduceMasked(a, i, mask)); } return res; @@ -2439,13 +2441,98 @@ public class Double128VectorTests extends AbstractVectorTest { ra = Double.NEGATIVE_INFINITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = (double)Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + ra = (double) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); } } assertReductionArraysEqualsMasked(r, ra, a, mask, Double128VectorTests::MAXReduceMasked, Double128VectorTests::MAXReduceAllMasked); } + static double FIRST_NONZEROReduce(double[] a, int idx) { + double res = (double) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + res = firstNonZero(res, a[i]); + } + + return res; + } + + static double FIRST_NONZEROReduceAll(double[] a) { + double res = (double) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); + } + + return res; + } + @Test(dataProvider = "doubleUnaryOpProvider") + static void FIRST_NONZEROReduceDouble128VectorTests(IntFunction<double[]> fa) { + double[] a = fa.apply(SPECIES.length()); + double[] r = fr.apply(SPECIES.length()); + double ra = (double) 0; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (double) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + } + } + + assertReductionArraysEquals(r, ra, a, + Double128VectorTests::FIRST_NONZEROReduce, Double128VectorTests::FIRST_NONZEROReduceAll); + } + static double FIRST_NONZEROReduceMasked(double[] a, int idx, boolean[] mask) { + double res = (double) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + if (mask[i % SPECIES.length()]) + res = firstNonZero(res, a[i]); + } + + return res; + } + + static double FIRST_NONZEROReduceAllMasked(double[] a, boolean[] mask) { + double res = (double) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); + } + + return res; + } + @Test(dataProvider = "doubleUnaryOpMaskProvider") + static void FIRST_NONZEROReduceDouble128VectorTestsMasked(IntFunction<double[]> fa, IntFunction<boolean[]> fm) { + double[] a = fa.apply(SPECIES.length()); + double[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask<Double> vmask = VectorMask.fromArray(SPECIES, mask, 0); + double ra = (double) 0; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (double) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + } + } + + assertReductionArraysEqualsMasked(r, ra, a, mask, + Double128VectorTests::FIRST_NONZEROReduceMasked, Double128VectorTests::FIRST_NONZEROReduceAllMasked); + } @@ -2457,13 +2544,16 @@ public class Double128VectorTests extends AbstractVectorTest { double[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { - for (int i = 0; i < a.length; i += SPECIES.length()) { + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - av.withLane(0, (double)4).intoArray(r, i); + av.withLane((j++ & (SPECIES.length()-1)), (double)(65535+i)).intoArray(r, i); } } - assertInsertArraysEquals(r, a, (double)4, 0); + + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { + assertInsertArraysEquals(r, a, (double)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); + } } static boolean testIS_DEFAULT(double a) { return bits(a)==0; @@ -2487,19 +2577,21 @@ public class Double128VectorTests extends AbstractVectorTest { } @Test(dataProvider = "doubleTestOpMaskProvider") - static void IS_DEFAULTMaskedDouble128VectorTestsSmokeTest(IntFunction<double[]> fa, + static void IS_DEFAULTMaskedDouble128VectorTests(IntFunction<double[]> fa, IntFunction<boolean[]> fm) { double[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Double> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - VectorMask<Double> mv = av.test(VectorOperators.IS_DEFAULT, vmask); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); + VectorMask<Double> mv = av.test(VectorOperators.IS_DEFAULT, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_DEFAULT(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_DEFAULT(a[i + j])); + } } } } @@ -2525,19 +2617,21 @@ public class Double128VectorTests extends AbstractVectorTest { } @Test(dataProvider = "doubleTestOpMaskProvider") - static void IS_NEGATIVEMaskedDouble128VectorTestsSmokeTest(IntFunction<double[]> fa, + static void IS_NEGATIVEMaskedDouble128VectorTests(IntFunction<double[]> fa, IntFunction<boolean[]> fm) { double[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Double> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - VectorMask<Double> mv = av.test(VectorOperators.IS_NEGATIVE, vmask); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); + VectorMask<Double> mv = av.test(VectorOperators.IS_NEGATIVE, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_NEGATIVE(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_NEGATIVE(a[i + j])); + } } } } @@ -2564,19 +2658,21 @@ public class Double128VectorTests extends AbstractVectorTest { } @Test(dataProvider = "doubleTestOpMaskProvider") - static void IS_FINITEMaskedDouble128VectorTestsSmokeTest(IntFunction<double[]> fa, + static void IS_FINITEMaskedDouble128VectorTests(IntFunction<double[]> fa, IntFunction<boolean[]> fm) { double[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Double> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - VectorMask<Double> mv = av.test(VectorOperators.IS_FINITE, vmask); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); + VectorMask<Double> mv = av.test(VectorOperators.IS_FINITE, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_FINITE(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_FINITE(a[i + j])); + } } } } @@ -2604,19 +2700,21 @@ public class Double128VectorTests extends AbstractVectorTest { } @Test(dataProvider = "doubleTestOpMaskProvider") - static void IS_NANMaskedDouble128VectorTestsSmokeTest(IntFunction<double[]> fa, + static void IS_NANMaskedDouble128VectorTests(IntFunction<double[]> fa, IntFunction<boolean[]> fm) { double[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Double> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - VectorMask<Double> mv = av.test(VectorOperators.IS_NAN, vmask); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); + VectorMask<Double> mv = av.test(VectorOperators.IS_NAN, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_NAN(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_NAN(a[i + j])); + } } } } @@ -2644,19 +2742,21 @@ public class Double128VectorTests extends AbstractVectorTest { } @Test(dataProvider = "doubleTestOpMaskProvider") - static void IS_INFINITEMaskedDouble128VectorTestsSmokeTest(IntFunction<double[]> fa, + static void IS_INFINITEMaskedDouble128VectorTests(IntFunction<double[]> fa, IntFunction<boolean[]> fm) { double[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Double> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - VectorMask<Double> mv = av.test(VectorOperators.IS_INFINITE, vmask); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); + VectorMask<Double> mv = av.test(VectorOperators.IS_INFINITE, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_INFINITE(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_INFINITE(a[i + j])); + } } } } @@ -4891,7 +4991,7 @@ public class Double128VectorTests extends AbstractVectorTest { static void maskFromToLongDouble128VectorTestsSmokeTest(long inputLong) { var vmask = VectorMask.fromLong(SPECIES, inputLong); long outputLong = vmask.toLong(); - Assert.assertEquals(outputLong, inputLong & (((1L << (SPECIES.length() - 1)) << 1) - 1)); + Assert.assertEquals(outputLong, (inputLong & (((0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length())))))); } @DataProvider @@ -4993,5 +5093,12 @@ public class Double128VectorTests extends AbstractVectorTest { VectorSpecies species = av.species().withShape(vsh); assert(species.equals(SPECIES)); } + + @Test + static void MaskAllTrueDouble128VectorTestsSmokeTest() { + for (int ic = 0; ic < INVOC_COUNT; ic++) { + Assert.assertEquals(SPECIES.maskAll(true).toLong(), -1L >>> (64 - SPECIES.length())); + } + } } diff --git a/test/jdk/jdk/incubator/vector/Double256VectorTests.java b/test/jdk/jdk/incubator/vector/Double256VectorTests.java index c7be717ef5f72851f3055b43038904b53deb1fbc..6a9e85129c24aae3242e45b6abb6e3860fd53394 100644 --- a/test/jdk/jdk/incubator/vector/Double256VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Double256VectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -226,10 +226,10 @@ public class Double256VectorTests extends AbstractVectorTest { } } - static void assertInsertArraysEquals(double[] r, double[] a, double element, int index) { - int i = 0; + static void assertInsertArraysEquals(double[] r, double[] a, double element, int index, int start, int end) { + int i = start; try { - for (; i < a.length; i += 1) { + for (; i < end; i += 1) { if(i%SPECIES.length() == index) { Assert.assertEquals(r[i], element); } else { @@ -1299,6 +1299,10 @@ public class Double256VectorTests extends AbstractVectorTest { } + static double firstNonZero(double a, double b) { + return Double.compare(a, (double) 0) != 0 ? a : b; + } + @Test static void smokeTest1() { DoubleVector three = DoubleVector.broadcast(SPECIES, (byte)-3); @@ -2277,7 +2281,7 @@ public class Double256VectorTests extends AbstractVectorTest { static double MINReduce(double[] a, int idx) { double res = Double.POSITIVE_INFINITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (double)Math.min(res, a[i]); + res = (double) Math.min(res, a[i]); } return res; @@ -2285,8 +2289,8 @@ public class Double256VectorTests extends AbstractVectorTest { static double MINReduceAll(double[] a) { double res = Double.POSITIVE_INFINITY; - for (int i = 0; i < a.length; i++) { - res = (double)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (double) Math.min(res, MINReduce(a, i)); } return res; @@ -2308,7 +2312,7 @@ public class Double256VectorTests extends AbstractVectorTest { ra = Double.POSITIVE_INFINITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = (double)Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + ra = (double) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); } } @@ -2318,8 +2322,8 @@ public class Double256VectorTests extends AbstractVectorTest { static double MINReduceMasked(double[] a, int idx, boolean[] mask) { double res = Double.POSITIVE_INFINITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (double)Math.min(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (double) Math.min(res, a[i]); } return res; @@ -2327,9 +2331,8 @@ public class Double256VectorTests extends AbstractVectorTest { static double MINReduceAllMasked(double[] a, boolean[] mask) { double res = Double.POSITIVE_INFINITY; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (double)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (double) Math.min(res, MINReduceMasked(a, i, mask)); } return res; @@ -2353,7 +2356,7 @@ public class Double256VectorTests extends AbstractVectorTest { ra = Double.POSITIVE_INFINITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = (double)Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + ra = (double) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); } } @@ -2363,7 +2366,7 @@ public class Double256VectorTests extends AbstractVectorTest { static double MAXReduce(double[] a, int idx) { double res = Double.NEGATIVE_INFINITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (double)Math.max(res, a[i]); + res = (double) Math.max(res, a[i]); } return res; @@ -2371,8 +2374,8 @@ public class Double256VectorTests extends AbstractVectorTest { static double MAXReduceAll(double[] a) { double res = Double.NEGATIVE_INFINITY; - for (int i = 0; i < a.length; i++) { - res = (double)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (double) Math.max(res, MAXReduce(a, i)); } return res; @@ -2394,7 +2397,7 @@ public class Double256VectorTests extends AbstractVectorTest { ra = Double.NEGATIVE_INFINITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = (double)Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + ra = (double) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); } } @@ -2404,8 +2407,8 @@ public class Double256VectorTests extends AbstractVectorTest { static double MAXReduceMasked(double[] a, int idx, boolean[] mask) { double res = Double.NEGATIVE_INFINITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (double)Math.max(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (double) Math.max(res, a[i]); } return res; @@ -2413,9 +2416,8 @@ public class Double256VectorTests extends AbstractVectorTest { static double MAXReduceAllMasked(double[] a, boolean[] mask) { double res = Double.NEGATIVE_INFINITY; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (double)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (double) Math.max(res, MAXReduceMasked(a, i, mask)); } return res; @@ -2439,13 +2441,98 @@ public class Double256VectorTests extends AbstractVectorTest { ra = Double.NEGATIVE_INFINITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = (double)Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + ra = (double) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); } } assertReductionArraysEqualsMasked(r, ra, a, mask, Double256VectorTests::MAXReduceMasked, Double256VectorTests::MAXReduceAllMasked); } + static double FIRST_NONZEROReduce(double[] a, int idx) { + double res = (double) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + res = firstNonZero(res, a[i]); + } + + return res; + } + + static double FIRST_NONZEROReduceAll(double[] a) { + double res = (double) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); + } + + return res; + } + @Test(dataProvider = "doubleUnaryOpProvider") + static void FIRST_NONZEROReduceDouble256VectorTests(IntFunction<double[]> fa) { + double[] a = fa.apply(SPECIES.length()); + double[] r = fr.apply(SPECIES.length()); + double ra = (double) 0; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (double) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + } + } + + assertReductionArraysEquals(r, ra, a, + Double256VectorTests::FIRST_NONZEROReduce, Double256VectorTests::FIRST_NONZEROReduceAll); + } + static double FIRST_NONZEROReduceMasked(double[] a, int idx, boolean[] mask) { + double res = (double) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + if (mask[i % SPECIES.length()]) + res = firstNonZero(res, a[i]); + } + + return res; + } + + static double FIRST_NONZEROReduceAllMasked(double[] a, boolean[] mask) { + double res = (double) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); + } + + return res; + } + @Test(dataProvider = "doubleUnaryOpMaskProvider") + static void FIRST_NONZEROReduceDouble256VectorTestsMasked(IntFunction<double[]> fa, IntFunction<boolean[]> fm) { + double[] a = fa.apply(SPECIES.length()); + double[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask<Double> vmask = VectorMask.fromArray(SPECIES, mask, 0); + double ra = (double) 0; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (double) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + } + } + + assertReductionArraysEqualsMasked(r, ra, a, mask, + Double256VectorTests::FIRST_NONZEROReduceMasked, Double256VectorTests::FIRST_NONZEROReduceAllMasked); + } @@ -2457,13 +2544,16 @@ public class Double256VectorTests extends AbstractVectorTest { double[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { - for (int i = 0; i < a.length; i += SPECIES.length()) { + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - av.withLane(0, (double)4).intoArray(r, i); + av.withLane((j++ & (SPECIES.length()-1)), (double)(65535+i)).intoArray(r, i); } } - assertInsertArraysEquals(r, a, (double)4, 0); + + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { + assertInsertArraysEquals(r, a, (double)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); + } } static boolean testIS_DEFAULT(double a) { return bits(a)==0; @@ -2487,19 +2577,21 @@ public class Double256VectorTests extends AbstractVectorTest { } @Test(dataProvider = "doubleTestOpMaskProvider") - static void IS_DEFAULTMaskedDouble256VectorTestsSmokeTest(IntFunction<double[]> fa, + static void IS_DEFAULTMaskedDouble256VectorTests(IntFunction<double[]> fa, IntFunction<boolean[]> fm) { double[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Double> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - VectorMask<Double> mv = av.test(VectorOperators.IS_DEFAULT, vmask); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); + VectorMask<Double> mv = av.test(VectorOperators.IS_DEFAULT, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_DEFAULT(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_DEFAULT(a[i + j])); + } } } } @@ -2525,19 +2617,21 @@ public class Double256VectorTests extends AbstractVectorTest { } @Test(dataProvider = "doubleTestOpMaskProvider") - static void IS_NEGATIVEMaskedDouble256VectorTestsSmokeTest(IntFunction<double[]> fa, + static void IS_NEGATIVEMaskedDouble256VectorTests(IntFunction<double[]> fa, IntFunction<boolean[]> fm) { double[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Double> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - VectorMask<Double> mv = av.test(VectorOperators.IS_NEGATIVE, vmask); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); + VectorMask<Double> mv = av.test(VectorOperators.IS_NEGATIVE, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_NEGATIVE(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_NEGATIVE(a[i + j])); + } } } } @@ -2564,19 +2658,21 @@ public class Double256VectorTests extends AbstractVectorTest { } @Test(dataProvider = "doubleTestOpMaskProvider") - static void IS_FINITEMaskedDouble256VectorTestsSmokeTest(IntFunction<double[]> fa, + static void IS_FINITEMaskedDouble256VectorTests(IntFunction<double[]> fa, IntFunction<boolean[]> fm) { double[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Double> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - VectorMask<Double> mv = av.test(VectorOperators.IS_FINITE, vmask); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); + VectorMask<Double> mv = av.test(VectorOperators.IS_FINITE, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_FINITE(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_FINITE(a[i + j])); + } } } } @@ -2604,19 +2700,21 @@ public class Double256VectorTests extends AbstractVectorTest { } @Test(dataProvider = "doubleTestOpMaskProvider") - static void IS_NANMaskedDouble256VectorTestsSmokeTest(IntFunction<double[]> fa, + static void IS_NANMaskedDouble256VectorTests(IntFunction<double[]> fa, IntFunction<boolean[]> fm) { double[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Double> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - VectorMask<Double> mv = av.test(VectorOperators.IS_NAN, vmask); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); + VectorMask<Double> mv = av.test(VectorOperators.IS_NAN, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_NAN(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_NAN(a[i + j])); + } } } } @@ -2644,19 +2742,21 @@ public class Double256VectorTests extends AbstractVectorTest { } @Test(dataProvider = "doubleTestOpMaskProvider") - static void IS_INFINITEMaskedDouble256VectorTestsSmokeTest(IntFunction<double[]> fa, + static void IS_INFINITEMaskedDouble256VectorTests(IntFunction<double[]> fa, IntFunction<boolean[]> fm) { double[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Double> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - VectorMask<Double> mv = av.test(VectorOperators.IS_INFINITE, vmask); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); + VectorMask<Double> mv = av.test(VectorOperators.IS_INFINITE, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_INFINITE(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_INFINITE(a[i + j])); + } } } } @@ -4891,7 +4991,7 @@ public class Double256VectorTests extends AbstractVectorTest { static void maskFromToLongDouble256VectorTestsSmokeTest(long inputLong) { var vmask = VectorMask.fromLong(SPECIES, inputLong); long outputLong = vmask.toLong(); - Assert.assertEquals(outputLong, inputLong & (((1L << (SPECIES.length() - 1)) << 1) - 1)); + Assert.assertEquals(outputLong, (inputLong & (((0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length())))))); } @DataProvider @@ -4993,5 +5093,12 @@ public class Double256VectorTests extends AbstractVectorTest { VectorSpecies species = av.species().withShape(vsh); assert(species.equals(SPECIES)); } + + @Test + static void MaskAllTrueDouble256VectorTestsSmokeTest() { + for (int ic = 0; ic < INVOC_COUNT; ic++) { + Assert.assertEquals(SPECIES.maskAll(true).toLong(), -1L >>> (64 - SPECIES.length())); + } + } } diff --git a/test/jdk/jdk/incubator/vector/Double512VectorTests.java b/test/jdk/jdk/incubator/vector/Double512VectorTests.java index ed7a2e470cb5660fbbafdfa4d9700bb7a32a69a1..7d6d280d744cb6c7f0115ddee880d86994af17a4 100644 --- a/test/jdk/jdk/incubator/vector/Double512VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Double512VectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -226,10 +226,10 @@ public class Double512VectorTests extends AbstractVectorTest { } } - static void assertInsertArraysEquals(double[] r, double[] a, double element, int index) { - int i = 0; + static void assertInsertArraysEquals(double[] r, double[] a, double element, int index, int start, int end) { + int i = start; try { - for (; i < a.length; i += 1) { + for (; i < end; i += 1) { if(i%SPECIES.length() == index) { Assert.assertEquals(r[i], element); } else { @@ -1299,6 +1299,10 @@ public class Double512VectorTests extends AbstractVectorTest { } + static double firstNonZero(double a, double b) { + return Double.compare(a, (double) 0) != 0 ? a : b; + } + @Test static void smokeTest1() { DoubleVector three = DoubleVector.broadcast(SPECIES, (byte)-3); @@ -2277,7 +2281,7 @@ public class Double512VectorTests extends AbstractVectorTest { static double MINReduce(double[] a, int idx) { double res = Double.POSITIVE_INFINITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (double)Math.min(res, a[i]); + res = (double) Math.min(res, a[i]); } return res; @@ -2285,8 +2289,8 @@ public class Double512VectorTests extends AbstractVectorTest { static double MINReduceAll(double[] a) { double res = Double.POSITIVE_INFINITY; - for (int i = 0; i < a.length; i++) { - res = (double)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (double) Math.min(res, MINReduce(a, i)); } return res; @@ -2308,7 +2312,7 @@ public class Double512VectorTests extends AbstractVectorTest { ra = Double.POSITIVE_INFINITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = (double)Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + ra = (double) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); } } @@ -2318,8 +2322,8 @@ public class Double512VectorTests extends AbstractVectorTest { static double MINReduceMasked(double[] a, int idx, boolean[] mask) { double res = Double.POSITIVE_INFINITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (double)Math.min(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (double) Math.min(res, a[i]); } return res; @@ -2327,9 +2331,8 @@ public class Double512VectorTests extends AbstractVectorTest { static double MINReduceAllMasked(double[] a, boolean[] mask) { double res = Double.POSITIVE_INFINITY; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (double)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (double) Math.min(res, MINReduceMasked(a, i, mask)); } return res; @@ -2353,7 +2356,7 @@ public class Double512VectorTests extends AbstractVectorTest { ra = Double.POSITIVE_INFINITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = (double)Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + ra = (double) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); } } @@ -2363,7 +2366,7 @@ public class Double512VectorTests extends AbstractVectorTest { static double MAXReduce(double[] a, int idx) { double res = Double.NEGATIVE_INFINITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (double)Math.max(res, a[i]); + res = (double) Math.max(res, a[i]); } return res; @@ -2371,8 +2374,8 @@ public class Double512VectorTests extends AbstractVectorTest { static double MAXReduceAll(double[] a) { double res = Double.NEGATIVE_INFINITY; - for (int i = 0; i < a.length; i++) { - res = (double)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (double) Math.max(res, MAXReduce(a, i)); } return res; @@ -2394,7 +2397,7 @@ public class Double512VectorTests extends AbstractVectorTest { ra = Double.NEGATIVE_INFINITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = (double)Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + ra = (double) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); } } @@ -2404,8 +2407,8 @@ public class Double512VectorTests extends AbstractVectorTest { static double MAXReduceMasked(double[] a, int idx, boolean[] mask) { double res = Double.NEGATIVE_INFINITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (double)Math.max(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (double) Math.max(res, a[i]); } return res; @@ -2413,9 +2416,8 @@ public class Double512VectorTests extends AbstractVectorTest { static double MAXReduceAllMasked(double[] a, boolean[] mask) { double res = Double.NEGATIVE_INFINITY; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (double)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (double) Math.max(res, MAXReduceMasked(a, i, mask)); } return res; @@ -2439,13 +2441,98 @@ public class Double512VectorTests extends AbstractVectorTest { ra = Double.NEGATIVE_INFINITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = (double)Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + ra = (double) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); } } assertReductionArraysEqualsMasked(r, ra, a, mask, Double512VectorTests::MAXReduceMasked, Double512VectorTests::MAXReduceAllMasked); } + static double FIRST_NONZEROReduce(double[] a, int idx) { + double res = (double) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + res = firstNonZero(res, a[i]); + } + + return res; + } + + static double FIRST_NONZEROReduceAll(double[] a) { + double res = (double) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); + } + + return res; + } + @Test(dataProvider = "doubleUnaryOpProvider") + static void FIRST_NONZEROReduceDouble512VectorTests(IntFunction<double[]> fa) { + double[] a = fa.apply(SPECIES.length()); + double[] r = fr.apply(SPECIES.length()); + double ra = (double) 0; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (double) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + } + } + + assertReductionArraysEquals(r, ra, a, + Double512VectorTests::FIRST_NONZEROReduce, Double512VectorTests::FIRST_NONZEROReduceAll); + } + static double FIRST_NONZEROReduceMasked(double[] a, int idx, boolean[] mask) { + double res = (double) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + if (mask[i % SPECIES.length()]) + res = firstNonZero(res, a[i]); + } + + return res; + } + + static double FIRST_NONZEROReduceAllMasked(double[] a, boolean[] mask) { + double res = (double) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); + } + + return res; + } + @Test(dataProvider = "doubleUnaryOpMaskProvider") + static void FIRST_NONZEROReduceDouble512VectorTestsMasked(IntFunction<double[]> fa, IntFunction<boolean[]> fm) { + double[] a = fa.apply(SPECIES.length()); + double[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask<Double> vmask = VectorMask.fromArray(SPECIES, mask, 0); + double ra = (double) 0; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (double) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + } + } + + assertReductionArraysEqualsMasked(r, ra, a, mask, + Double512VectorTests::FIRST_NONZEROReduceMasked, Double512VectorTests::FIRST_NONZEROReduceAllMasked); + } @@ -2457,13 +2544,16 @@ public class Double512VectorTests extends AbstractVectorTest { double[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { - for (int i = 0; i < a.length; i += SPECIES.length()) { + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - av.withLane(0, (double)4).intoArray(r, i); + av.withLane((j++ & (SPECIES.length()-1)), (double)(65535+i)).intoArray(r, i); } } - assertInsertArraysEquals(r, a, (double)4, 0); + + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { + assertInsertArraysEquals(r, a, (double)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); + } } static boolean testIS_DEFAULT(double a) { return bits(a)==0; @@ -2487,19 +2577,21 @@ public class Double512VectorTests extends AbstractVectorTest { } @Test(dataProvider = "doubleTestOpMaskProvider") - static void IS_DEFAULTMaskedDouble512VectorTestsSmokeTest(IntFunction<double[]> fa, + static void IS_DEFAULTMaskedDouble512VectorTests(IntFunction<double[]> fa, IntFunction<boolean[]> fm) { double[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Double> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - VectorMask<Double> mv = av.test(VectorOperators.IS_DEFAULT, vmask); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); + VectorMask<Double> mv = av.test(VectorOperators.IS_DEFAULT, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_DEFAULT(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_DEFAULT(a[i + j])); + } } } } @@ -2525,19 +2617,21 @@ public class Double512VectorTests extends AbstractVectorTest { } @Test(dataProvider = "doubleTestOpMaskProvider") - static void IS_NEGATIVEMaskedDouble512VectorTestsSmokeTest(IntFunction<double[]> fa, + static void IS_NEGATIVEMaskedDouble512VectorTests(IntFunction<double[]> fa, IntFunction<boolean[]> fm) { double[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Double> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - VectorMask<Double> mv = av.test(VectorOperators.IS_NEGATIVE, vmask); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); + VectorMask<Double> mv = av.test(VectorOperators.IS_NEGATIVE, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_NEGATIVE(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_NEGATIVE(a[i + j])); + } } } } @@ -2564,19 +2658,21 @@ public class Double512VectorTests extends AbstractVectorTest { } @Test(dataProvider = "doubleTestOpMaskProvider") - static void IS_FINITEMaskedDouble512VectorTestsSmokeTest(IntFunction<double[]> fa, + static void IS_FINITEMaskedDouble512VectorTests(IntFunction<double[]> fa, IntFunction<boolean[]> fm) { double[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Double> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - VectorMask<Double> mv = av.test(VectorOperators.IS_FINITE, vmask); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); + VectorMask<Double> mv = av.test(VectorOperators.IS_FINITE, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_FINITE(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_FINITE(a[i + j])); + } } } } @@ -2604,19 +2700,21 @@ public class Double512VectorTests extends AbstractVectorTest { } @Test(dataProvider = "doubleTestOpMaskProvider") - static void IS_NANMaskedDouble512VectorTestsSmokeTest(IntFunction<double[]> fa, + static void IS_NANMaskedDouble512VectorTests(IntFunction<double[]> fa, IntFunction<boolean[]> fm) { double[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Double> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - VectorMask<Double> mv = av.test(VectorOperators.IS_NAN, vmask); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); + VectorMask<Double> mv = av.test(VectorOperators.IS_NAN, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_NAN(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_NAN(a[i + j])); + } } } } @@ -2644,19 +2742,21 @@ public class Double512VectorTests extends AbstractVectorTest { } @Test(dataProvider = "doubleTestOpMaskProvider") - static void IS_INFINITEMaskedDouble512VectorTestsSmokeTest(IntFunction<double[]> fa, + static void IS_INFINITEMaskedDouble512VectorTests(IntFunction<double[]> fa, IntFunction<boolean[]> fm) { double[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Double> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - VectorMask<Double> mv = av.test(VectorOperators.IS_INFINITE, vmask); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); + VectorMask<Double> mv = av.test(VectorOperators.IS_INFINITE, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_INFINITE(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_INFINITE(a[i + j])); + } } } } @@ -4891,7 +4991,7 @@ public class Double512VectorTests extends AbstractVectorTest { static void maskFromToLongDouble512VectorTestsSmokeTest(long inputLong) { var vmask = VectorMask.fromLong(SPECIES, inputLong); long outputLong = vmask.toLong(); - Assert.assertEquals(outputLong, inputLong & (((1L << (SPECIES.length() - 1)) << 1) - 1)); + Assert.assertEquals(outputLong, (inputLong & (((0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length())))))); } @DataProvider @@ -4993,5 +5093,12 @@ public class Double512VectorTests extends AbstractVectorTest { VectorSpecies species = av.species().withShape(vsh); assert(species.equals(SPECIES)); } + + @Test + static void MaskAllTrueDouble512VectorTestsSmokeTest() { + for (int ic = 0; ic < INVOC_COUNT; ic++) { + Assert.assertEquals(SPECIES.maskAll(true).toLong(), -1L >>> (64 - SPECIES.length())); + } + } } diff --git a/test/jdk/jdk/incubator/vector/Double64VectorTests.java b/test/jdk/jdk/incubator/vector/Double64VectorTests.java index 20e70d70cc0ed35495cd85a7189c98623a596aaf..35bf2ec0465fe2813e52200f1701300a313ec509 100644 --- a/test/jdk/jdk/incubator/vector/Double64VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Double64VectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -226,10 +226,10 @@ public class Double64VectorTests extends AbstractVectorTest { } } - static void assertInsertArraysEquals(double[] r, double[] a, double element, int index) { - int i = 0; + static void assertInsertArraysEquals(double[] r, double[] a, double element, int index, int start, int end) { + int i = start; try { - for (; i < a.length; i += 1) { + for (; i < end; i += 1) { if(i%SPECIES.length() == index) { Assert.assertEquals(r[i], element); } else { @@ -1299,6 +1299,10 @@ public class Double64VectorTests extends AbstractVectorTest { } + static double firstNonZero(double a, double b) { + return Double.compare(a, (double) 0) != 0 ? a : b; + } + @Test static void smokeTest1() { DoubleVector three = DoubleVector.broadcast(SPECIES, (byte)-3); @@ -2277,7 +2281,7 @@ public class Double64VectorTests extends AbstractVectorTest { static double MINReduce(double[] a, int idx) { double res = Double.POSITIVE_INFINITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (double)Math.min(res, a[i]); + res = (double) Math.min(res, a[i]); } return res; @@ -2285,8 +2289,8 @@ public class Double64VectorTests extends AbstractVectorTest { static double MINReduceAll(double[] a) { double res = Double.POSITIVE_INFINITY; - for (int i = 0; i < a.length; i++) { - res = (double)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (double) Math.min(res, MINReduce(a, i)); } return res; @@ -2308,7 +2312,7 @@ public class Double64VectorTests extends AbstractVectorTest { ra = Double.POSITIVE_INFINITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = (double)Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + ra = (double) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); } } @@ -2318,8 +2322,8 @@ public class Double64VectorTests extends AbstractVectorTest { static double MINReduceMasked(double[] a, int idx, boolean[] mask) { double res = Double.POSITIVE_INFINITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (double)Math.min(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (double) Math.min(res, a[i]); } return res; @@ -2327,9 +2331,8 @@ public class Double64VectorTests extends AbstractVectorTest { static double MINReduceAllMasked(double[] a, boolean[] mask) { double res = Double.POSITIVE_INFINITY; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (double)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (double) Math.min(res, MINReduceMasked(a, i, mask)); } return res; @@ -2353,7 +2356,7 @@ public class Double64VectorTests extends AbstractVectorTest { ra = Double.POSITIVE_INFINITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = (double)Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + ra = (double) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); } } @@ -2363,7 +2366,7 @@ public class Double64VectorTests extends AbstractVectorTest { static double MAXReduce(double[] a, int idx) { double res = Double.NEGATIVE_INFINITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (double)Math.max(res, a[i]); + res = (double) Math.max(res, a[i]); } return res; @@ -2371,8 +2374,8 @@ public class Double64VectorTests extends AbstractVectorTest { static double MAXReduceAll(double[] a) { double res = Double.NEGATIVE_INFINITY; - for (int i = 0; i < a.length; i++) { - res = (double)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (double) Math.max(res, MAXReduce(a, i)); } return res; @@ -2394,7 +2397,7 @@ public class Double64VectorTests extends AbstractVectorTest { ra = Double.NEGATIVE_INFINITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = (double)Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + ra = (double) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); } } @@ -2404,8 +2407,8 @@ public class Double64VectorTests extends AbstractVectorTest { static double MAXReduceMasked(double[] a, int idx, boolean[] mask) { double res = Double.NEGATIVE_INFINITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (double)Math.max(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (double) Math.max(res, a[i]); } return res; @@ -2413,9 +2416,8 @@ public class Double64VectorTests extends AbstractVectorTest { static double MAXReduceAllMasked(double[] a, boolean[] mask) { double res = Double.NEGATIVE_INFINITY; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (double)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (double) Math.max(res, MAXReduceMasked(a, i, mask)); } return res; @@ -2439,13 +2441,98 @@ public class Double64VectorTests extends AbstractVectorTest { ra = Double.NEGATIVE_INFINITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = (double)Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + ra = (double) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); } } assertReductionArraysEqualsMasked(r, ra, a, mask, Double64VectorTests::MAXReduceMasked, Double64VectorTests::MAXReduceAllMasked); } + static double FIRST_NONZEROReduce(double[] a, int idx) { + double res = (double) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + res = firstNonZero(res, a[i]); + } + + return res; + } + + static double FIRST_NONZEROReduceAll(double[] a) { + double res = (double) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); + } + + return res; + } + @Test(dataProvider = "doubleUnaryOpProvider") + static void FIRST_NONZEROReduceDouble64VectorTests(IntFunction<double[]> fa) { + double[] a = fa.apply(SPECIES.length()); + double[] r = fr.apply(SPECIES.length()); + double ra = (double) 0; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (double) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + } + } + + assertReductionArraysEquals(r, ra, a, + Double64VectorTests::FIRST_NONZEROReduce, Double64VectorTests::FIRST_NONZEROReduceAll); + } + static double FIRST_NONZEROReduceMasked(double[] a, int idx, boolean[] mask) { + double res = (double) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + if (mask[i % SPECIES.length()]) + res = firstNonZero(res, a[i]); + } + + return res; + } + + static double FIRST_NONZEROReduceAllMasked(double[] a, boolean[] mask) { + double res = (double) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); + } + + return res; + } + @Test(dataProvider = "doubleUnaryOpMaskProvider") + static void FIRST_NONZEROReduceDouble64VectorTestsMasked(IntFunction<double[]> fa, IntFunction<boolean[]> fm) { + double[] a = fa.apply(SPECIES.length()); + double[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask<Double> vmask = VectorMask.fromArray(SPECIES, mask, 0); + double ra = (double) 0; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (double) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + } + } + + assertReductionArraysEqualsMasked(r, ra, a, mask, + Double64VectorTests::FIRST_NONZEROReduceMasked, Double64VectorTests::FIRST_NONZEROReduceAllMasked); + } @@ -2457,13 +2544,16 @@ public class Double64VectorTests extends AbstractVectorTest { double[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { - for (int i = 0; i < a.length; i += SPECIES.length()) { + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - av.withLane(0, (double)4).intoArray(r, i); + av.withLane((j++ & (SPECIES.length()-1)), (double)(65535+i)).intoArray(r, i); } } - assertInsertArraysEquals(r, a, (double)4, 0); + + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { + assertInsertArraysEquals(r, a, (double)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); + } } static boolean testIS_DEFAULT(double a) { return bits(a)==0; @@ -2487,19 +2577,21 @@ public class Double64VectorTests extends AbstractVectorTest { } @Test(dataProvider = "doubleTestOpMaskProvider") - static void IS_DEFAULTMaskedDouble64VectorTestsSmokeTest(IntFunction<double[]> fa, + static void IS_DEFAULTMaskedDouble64VectorTests(IntFunction<double[]> fa, IntFunction<boolean[]> fm) { double[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Double> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - VectorMask<Double> mv = av.test(VectorOperators.IS_DEFAULT, vmask); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); + VectorMask<Double> mv = av.test(VectorOperators.IS_DEFAULT, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_DEFAULT(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_DEFAULT(a[i + j])); + } } } } @@ -2525,19 +2617,21 @@ public class Double64VectorTests extends AbstractVectorTest { } @Test(dataProvider = "doubleTestOpMaskProvider") - static void IS_NEGATIVEMaskedDouble64VectorTestsSmokeTest(IntFunction<double[]> fa, + static void IS_NEGATIVEMaskedDouble64VectorTests(IntFunction<double[]> fa, IntFunction<boolean[]> fm) { double[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Double> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - VectorMask<Double> mv = av.test(VectorOperators.IS_NEGATIVE, vmask); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); + VectorMask<Double> mv = av.test(VectorOperators.IS_NEGATIVE, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_NEGATIVE(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_NEGATIVE(a[i + j])); + } } } } @@ -2564,19 +2658,21 @@ public class Double64VectorTests extends AbstractVectorTest { } @Test(dataProvider = "doubleTestOpMaskProvider") - static void IS_FINITEMaskedDouble64VectorTestsSmokeTest(IntFunction<double[]> fa, + static void IS_FINITEMaskedDouble64VectorTests(IntFunction<double[]> fa, IntFunction<boolean[]> fm) { double[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Double> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - VectorMask<Double> mv = av.test(VectorOperators.IS_FINITE, vmask); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); + VectorMask<Double> mv = av.test(VectorOperators.IS_FINITE, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_FINITE(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_FINITE(a[i + j])); + } } } } @@ -2604,19 +2700,21 @@ public class Double64VectorTests extends AbstractVectorTest { } @Test(dataProvider = "doubleTestOpMaskProvider") - static void IS_NANMaskedDouble64VectorTestsSmokeTest(IntFunction<double[]> fa, + static void IS_NANMaskedDouble64VectorTests(IntFunction<double[]> fa, IntFunction<boolean[]> fm) { double[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Double> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - VectorMask<Double> mv = av.test(VectorOperators.IS_NAN, vmask); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); + VectorMask<Double> mv = av.test(VectorOperators.IS_NAN, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_NAN(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_NAN(a[i + j])); + } } } } @@ -2644,19 +2742,21 @@ public class Double64VectorTests extends AbstractVectorTest { } @Test(dataProvider = "doubleTestOpMaskProvider") - static void IS_INFINITEMaskedDouble64VectorTestsSmokeTest(IntFunction<double[]> fa, + static void IS_INFINITEMaskedDouble64VectorTests(IntFunction<double[]> fa, IntFunction<boolean[]> fm) { double[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Double> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - VectorMask<Double> mv = av.test(VectorOperators.IS_INFINITE, vmask); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); + VectorMask<Double> mv = av.test(VectorOperators.IS_INFINITE, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_INFINITE(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_INFINITE(a[i + j])); + } } } } @@ -4891,7 +4991,7 @@ public class Double64VectorTests extends AbstractVectorTest { static void maskFromToLongDouble64VectorTestsSmokeTest(long inputLong) { var vmask = VectorMask.fromLong(SPECIES, inputLong); long outputLong = vmask.toLong(); - Assert.assertEquals(outputLong, inputLong & (((1L << (SPECIES.length() - 1)) << 1) - 1)); + Assert.assertEquals(outputLong, (inputLong & (((0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length())))))); } @DataProvider @@ -4993,5 +5093,12 @@ public class Double64VectorTests extends AbstractVectorTest { VectorSpecies species = av.species().withShape(vsh); assert(species.equals(SPECIES)); } + + @Test + static void MaskAllTrueDouble64VectorTestsSmokeTest() { + for (int ic = 0; ic < INVOC_COUNT; ic++) { + Assert.assertEquals(SPECIES.maskAll(true).toLong(), -1L >>> (64 - SPECIES.length())); + } + } } diff --git a/test/jdk/jdk/incubator/vector/DoubleMaxVectorTests.java b/test/jdk/jdk/incubator/vector/DoubleMaxVectorTests.java index ee136b9b32bbf33d955770d57ea37d8b861f7a8f..102749b7ca036f29afcbcaf8be54e98b3da75e5c 100644 --- a/test/jdk/jdk/incubator/vector/DoubleMaxVectorTests.java +++ b/test/jdk/jdk/incubator/vector/DoubleMaxVectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -231,10 +231,10 @@ public class DoubleMaxVectorTests extends AbstractVectorTest { } } - static void assertInsertArraysEquals(double[] r, double[] a, double element, int index) { - int i = 0; + static void assertInsertArraysEquals(double[] r, double[] a, double element, int index, int start, int end) { + int i = start; try { - for (; i < a.length; i += 1) { + for (; i < end; i += 1) { if(i%SPECIES.length() == index) { Assert.assertEquals(r[i], element); } else { @@ -1304,6 +1304,10 @@ public class DoubleMaxVectorTests extends AbstractVectorTest { } + static double firstNonZero(double a, double b) { + return Double.compare(a, (double) 0) != 0 ? a : b; + } + @Test static void smokeTest1() { DoubleVector three = DoubleVector.broadcast(SPECIES, (byte)-3); @@ -2282,7 +2286,7 @@ public class DoubleMaxVectorTests extends AbstractVectorTest { static double MINReduce(double[] a, int idx) { double res = Double.POSITIVE_INFINITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (double)Math.min(res, a[i]); + res = (double) Math.min(res, a[i]); } return res; @@ -2290,8 +2294,8 @@ public class DoubleMaxVectorTests extends AbstractVectorTest { static double MINReduceAll(double[] a) { double res = Double.POSITIVE_INFINITY; - for (int i = 0; i < a.length; i++) { - res = (double)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (double) Math.min(res, MINReduce(a, i)); } return res; @@ -2313,7 +2317,7 @@ public class DoubleMaxVectorTests extends AbstractVectorTest { ra = Double.POSITIVE_INFINITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = (double)Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + ra = (double) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); } } @@ -2323,8 +2327,8 @@ public class DoubleMaxVectorTests extends AbstractVectorTest { static double MINReduceMasked(double[] a, int idx, boolean[] mask) { double res = Double.POSITIVE_INFINITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (double)Math.min(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (double) Math.min(res, a[i]); } return res; @@ -2332,9 +2336,8 @@ public class DoubleMaxVectorTests extends AbstractVectorTest { static double MINReduceAllMasked(double[] a, boolean[] mask) { double res = Double.POSITIVE_INFINITY; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (double)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (double) Math.min(res, MINReduceMasked(a, i, mask)); } return res; @@ -2358,7 +2361,7 @@ public class DoubleMaxVectorTests extends AbstractVectorTest { ra = Double.POSITIVE_INFINITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = (double)Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + ra = (double) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); } } @@ -2368,7 +2371,7 @@ public class DoubleMaxVectorTests extends AbstractVectorTest { static double MAXReduce(double[] a, int idx) { double res = Double.NEGATIVE_INFINITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (double)Math.max(res, a[i]); + res = (double) Math.max(res, a[i]); } return res; @@ -2376,8 +2379,8 @@ public class DoubleMaxVectorTests extends AbstractVectorTest { static double MAXReduceAll(double[] a) { double res = Double.NEGATIVE_INFINITY; - for (int i = 0; i < a.length; i++) { - res = (double)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (double) Math.max(res, MAXReduce(a, i)); } return res; @@ -2399,7 +2402,7 @@ public class DoubleMaxVectorTests extends AbstractVectorTest { ra = Double.NEGATIVE_INFINITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = (double)Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + ra = (double) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); } } @@ -2409,8 +2412,8 @@ public class DoubleMaxVectorTests extends AbstractVectorTest { static double MAXReduceMasked(double[] a, int idx, boolean[] mask) { double res = Double.NEGATIVE_INFINITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (double)Math.max(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (double) Math.max(res, a[i]); } return res; @@ -2418,9 +2421,8 @@ public class DoubleMaxVectorTests extends AbstractVectorTest { static double MAXReduceAllMasked(double[] a, boolean[] mask) { double res = Double.NEGATIVE_INFINITY; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (double)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (double) Math.max(res, MAXReduceMasked(a, i, mask)); } return res; @@ -2444,13 +2446,98 @@ public class DoubleMaxVectorTests extends AbstractVectorTest { ra = Double.NEGATIVE_INFINITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = (double)Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + ra = (double) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); } } assertReductionArraysEqualsMasked(r, ra, a, mask, DoubleMaxVectorTests::MAXReduceMasked, DoubleMaxVectorTests::MAXReduceAllMasked); } + static double FIRST_NONZEROReduce(double[] a, int idx) { + double res = (double) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + res = firstNonZero(res, a[i]); + } + + return res; + } + + static double FIRST_NONZEROReduceAll(double[] a) { + double res = (double) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); + } + + return res; + } + @Test(dataProvider = "doubleUnaryOpProvider") + static void FIRST_NONZEROReduceDoubleMaxVectorTests(IntFunction<double[]> fa) { + double[] a = fa.apply(SPECIES.length()); + double[] r = fr.apply(SPECIES.length()); + double ra = (double) 0; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (double) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + } + } + + assertReductionArraysEquals(r, ra, a, + DoubleMaxVectorTests::FIRST_NONZEROReduce, DoubleMaxVectorTests::FIRST_NONZEROReduceAll); + } + static double FIRST_NONZEROReduceMasked(double[] a, int idx, boolean[] mask) { + double res = (double) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + if (mask[i % SPECIES.length()]) + res = firstNonZero(res, a[i]); + } + + return res; + } + + static double FIRST_NONZEROReduceAllMasked(double[] a, boolean[] mask) { + double res = (double) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); + } + + return res; + } + @Test(dataProvider = "doubleUnaryOpMaskProvider") + static void FIRST_NONZEROReduceDoubleMaxVectorTestsMasked(IntFunction<double[]> fa, IntFunction<boolean[]> fm) { + double[] a = fa.apply(SPECIES.length()); + double[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask<Double> vmask = VectorMask.fromArray(SPECIES, mask, 0); + double ra = (double) 0; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (double) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + } + } + + assertReductionArraysEqualsMasked(r, ra, a, mask, + DoubleMaxVectorTests::FIRST_NONZEROReduceMasked, DoubleMaxVectorTests::FIRST_NONZEROReduceAllMasked); + } @@ -2462,13 +2549,16 @@ public class DoubleMaxVectorTests extends AbstractVectorTest { double[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { - for (int i = 0; i < a.length; i += SPECIES.length()) { + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - av.withLane(0, (double)4).intoArray(r, i); + av.withLane((j++ & (SPECIES.length()-1)), (double)(65535+i)).intoArray(r, i); } } - assertInsertArraysEquals(r, a, (double)4, 0); + + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { + assertInsertArraysEquals(r, a, (double)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); + } } static boolean testIS_DEFAULT(double a) { return bits(a)==0; @@ -2492,19 +2582,21 @@ public class DoubleMaxVectorTests extends AbstractVectorTest { } @Test(dataProvider = "doubleTestOpMaskProvider") - static void IS_DEFAULTMaskedDoubleMaxVectorTestsSmokeTest(IntFunction<double[]> fa, + static void IS_DEFAULTMaskedDoubleMaxVectorTests(IntFunction<double[]> fa, IntFunction<boolean[]> fm) { double[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Double> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - VectorMask<Double> mv = av.test(VectorOperators.IS_DEFAULT, vmask); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); + VectorMask<Double> mv = av.test(VectorOperators.IS_DEFAULT, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_DEFAULT(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_DEFAULT(a[i + j])); + } } } } @@ -2530,19 +2622,21 @@ public class DoubleMaxVectorTests extends AbstractVectorTest { } @Test(dataProvider = "doubleTestOpMaskProvider") - static void IS_NEGATIVEMaskedDoubleMaxVectorTestsSmokeTest(IntFunction<double[]> fa, + static void IS_NEGATIVEMaskedDoubleMaxVectorTests(IntFunction<double[]> fa, IntFunction<boolean[]> fm) { double[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Double> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - VectorMask<Double> mv = av.test(VectorOperators.IS_NEGATIVE, vmask); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); + VectorMask<Double> mv = av.test(VectorOperators.IS_NEGATIVE, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_NEGATIVE(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_NEGATIVE(a[i + j])); + } } } } @@ -2569,19 +2663,21 @@ public class DoubleMaxVectorTests extends AbstractVectorTest { } @Test(dataProvider = "doubleTestOpMaskProvider") - static void IS_FINITEMaskedDoubleMaxVectorTestsSmokeTest(IntFunction<double[]> fa, + static void IS_FINITEMaskedDoubleMaxVectorTests(IntFunction<double[]> fa, IntFunction<boolean[]> fm) { double[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Double> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - VectorMask<Double> mv = av.test(VectorOperators.IS_FINITE, vmask); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); + VectorMask<Double> mv = av.test(VectorOperators.IS_FINITE, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_FINITE(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_FINITE(a[i + j])); + } } } } @@ -2609,19 +2705,21 @@ public class DoubleMaxVectorTests extends AbstractVectorTest { } @Test(dataProvider = "doubleTestOpMaskProvider") - static void IS_NANMaskedDoubleMaxVectorTestsSmokeTest(IntFunction<double[]> fa, + static void IS_NANMaskedDoubleMaxVectorTests(IntFunction<double[]> fa, IntFunction<boolean[]> fm) { double[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Double> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - VectorMask<Double> mv = av.test(VectorOperators.IS_NAN, vmask); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); + VectorMask<Double> mv = av.test(VectorOperators.IS_NAN, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_NAN(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_NAN(a[i + j])); + } } } } @@ -2649,19 +2747,21 @@ public class DoubleMaxVectorTests extends AbstractVectorTest { } @Test(dataProvider = "doubleTestOpMaskProvider") - static void IS_INFINITEMaskedDoubleMaxVectorTestsSmokeTest(IntFunction<double[]> fa, + static void IS_INFINITEMaskedDoubleMaxVectorTests(IntFunction<double[]> fa, IntFunction<boolean[]> fm) { double[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Double> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - VectorMask<Double> mv = av.test(VectorOperators.IS_INFINITE, vmask); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); + VectorMask<Double> mv = av.test(VectorOperators.IS_INFINITE, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_INFINITE(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_INFINITE(a[i + j])); + } } } } @@ -4982,5 +5082,12 @@ public class DoubleMaxVectorTests extends AbstractVectorTest { VectorSpecies species = av.species().withShape(vsh); assert(species.equals(SPECIES)); } + + @Test + static void MaskAllTrueDoubleMaxVectorTestsSmokeTest() { + for (int ic = 0; ic < INVOC_COUNT; ic++) { + Assert.assertEquals(SPECIES.maskAll(true).toLong(), -1L >>> (64 - SPECIES.length())); + } + } } diff --git a/test/jdk/jdk/incubator/vector/Float128VectorTests.java b/test/jdk/jdk/incubator/vector/Float128VectorTests.java index 7e01f848864c754af9e486744ba0b87d64066dde..114ac299f3ee557d063331a223cb089b30b2b597 100644 --- a/test/jdk/jdk/incubator/vector/Float128VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Float128VectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -226,10 +226,10 @@ public class Float128VectorTests extends AbstractVectorTest { } } - static void assertInsertArraysEquals(float[] r, float[] a, float element, int index) { - int i = 0; + static void assertInsertArraysEquals(float[] r, float[] a, float element, int index, int start, int end) { + int i = start; try { - for (; i < a.length; i += 1) { + for (; i < end; i += 1) { if(i%SPECIES.length() == index) { Assert.assertEquals(r[i], element); } else { @@ -1309,6 +1309,10 @@ public class Float128VectorTests extends AbstractVectorTest { } + static float firstNonZero(float a, float b) { + return Float.compare(a, (float) 0) != 0 ? a : b; + } + @Test static void smokeTest1() { FloatVector three = FloatVector.broadcast(SPECIES, (byte)-3); @@ -2287,7 +2291,7 @@ public class Float128VectorTests extends AbstractVectorTest { static float MINReduce(float[] a, int idx) { float res = Float.POSITIVE_INFINITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (float)Math.min(res, a[i]); + res = (float) Math.min(res, a[i]); } return res; @@ -2295,8 +2299,8 @@ public class Float128VectorTests extends AbstractVectorTest { static float MINReduceAll(float[] a) { float res = Float.POSITIVE_INFINITY; - for (int i = 0; i < a.length; i++) { - res = (float)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (float) Math.min(res, MINReduce(a, i)); } return res; @@ -2318,7 +2322,7 @@ public class Float128VectorTests extends AbstractVectorTest { ra = Float.POSITIVE_INFINITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = (float)Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + ra = (float) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); } } @@ -2328,8 +2332,8 @@ public class Float128VectorTests extends AbstractVectorTest { static float MINReduceMasked(float[] a, int idx, boolean[] mask) { float res = Float.POSITIVE_INFINITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (float)Math.min(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (float) Math.min(res, a[i]); } return res; @@ -2337,9 +2341,8 @@ public class Float128VectorTests extends AbstractVectorTest { static float MINReduceAllMasked(float[] a, boolean[] mask) { float res = Float.POSITIVE_INFINITY; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (float)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (float) Math.min(res, MINReduceMasked(a, i, mask)); } return res; @@ -2363,7 +2366,7 @@ public class Float128VectorTests extends AbstractVectorTest { ra = Float.POSITIVE_INFINITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = (float)Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + ra = (float) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); } } @@ -2373,7 +2376,7 @@ public class Float128VectorTests extends AbstractVectorTest { static float MAXReduce(float[] a, int idx) { float res = Float.NEGATIVE_INFINITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (float)Math.max(res, a[i]); + res = (float) Math.max(res, a[i]); } return res; @@ -2381,8 +2384,8 @@ public class Float128VectorTests extends AbstractVectorTest { static float MAXReduceAll(float[] a) { float res = Float.NEGATIVE_INFINITY; - for (int i = 0; i < a.length; i++) { - res = (float)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (float) Math.max(res, MAXReduce(a, i)); } return res; @@ -2404,7 +2407,7 @@ public class Float128VectorTests extends AbstractVectorTest { ra = Float.NEGATIVE_INFINITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = (float)Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + ra = (float) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); } } @@ -2414,8 +2417,8 @@ public class Float128VectorTests extends AbstractVectorTest { static float MAXReduceMasked(float[] a, int idx, boolean[] mask) { float res = Float.NEGATIVE_INFINITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (float)Math.max(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (float) Math.max(res, a[i]); } return res; @@ -2423,9 +2426,8 @@ public class Float128VectorTests extends AbstractVectorTest { static float MAXReduceAllMasked(float[] a, boolean[] mask) { float res = Float.NEGATIVE_INFINITY; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (float)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (float) Math.max(res, MAXReduceMasked(a, i, mask)); } return res; @@ -2449,13 +2451,98 @@ public class Float128VectorTests extends AbstractVectorTest { ra = Float.NEGATIVE_INFINITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = (float)Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + ra = (float) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); } } assertReductionArraysEqualsMasked(r, ra, a, mask, Float128VectorTests::MAXReduceMasked, Float128VectorTests::MAXReduceAllMasked); } + static float FIRST_NONZEROReduce(float[] a, int idx) { + float res = (float) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + res = firstNonZero(res, a[i]); + } + + return res; + } + + static float FIRST_NONZEROReduceAll(float[] a) { + float res = (float) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); + } + + return res; + } + @Test(dataProvider = "floatUnaryOpProvider") + static void FIRST_NONZEROReduceFloat128VectorTests(IntFunction<float[]> fa) { + float[] a = fa.apply(SPECIES.length()); + float[] r = fr.apply(SPECIES.length()); + float ra = (float) 0; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + FloatVector av = FloatVector.fromArray(SPECIES, a, i); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (float) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + FloatVector av = FloatVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + } + } + + assertReductionArraysEquals(r, ra, a, + Float128VectorTests::FIRST_NONZEROReduce, Float128VectorTests::FIRST_NONZEROReduceAll); + } + static float FIRST_NONZEROReduceMasked(float[] a, int idx, boolean[] mask) { + float res = (float) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + if (mask[i % SPECIES.length()]) + res = firstNonZero(res, a[i]); + } + + return res; + } + + static float FIRST_NONZEROReduceAllMasked(float[] a, boolean[] mask) { + float res = (float) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); + } + + return res; + } + @Test(dataProvider = "floatUnaryOpMaskProvider") + static void FIRST_NONZEROReduceFloat128VectorTestsMasked(IntFunction<float[]> fa, IntFunction<boolean[]> fm) { + float[] a = fa.apply(SPECIES.length()); + float[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask<Float> vmask = VectorMask.fromArray(SPECIES, mask, 0); + float ra = (float) 0; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + FloatVector av = FloatVector.fromArray(SPECIES, a, i); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (float) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + FloatVector av = FloatVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + } + } + + assertReductionArraysEqualsMasked(r, ra, a, mask, + Float128VectorTests::FIRST_NONZEROReduceMasked, Float128VectorTests::FIRST_NONZEROReduceAllMasked); + } @@ -2467,13 +2554,16 @@ public class Float128VectorTests extends AbstractVectorTest { float[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { - for (int i = 0; i < a.length; i += SPECIES.length()) { + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - av.withLane(0, (float)4).intoArray(r, i); + av.withLane((j++ & (SPECIES.length()-1)), (float)(65535+i)).intoArray(r, i); } } - assertInsertArraysEquals(r, a, (float)4, 0); + + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { + assertInsertArraysEquals(r, a, (float)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); + } } static boolean testIS_DEFAULT(float a) { return bits(a)==0; @@ -2497,19 +2587,21 @@ public class Float128VectorTests extends AbstractVectorTest { } @Test(dataProvider = "floatTestOpMaskProvider") - static void IS_DEFAULTMaskedFloat128VectorTestsSmokeTest(IntFunction<float[]> fa, + static void IS_DEFAULTMaskedFloat128VectorTests(IntFunction<float[]> fa, IntFunction<boolean[]> fm) { float[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Float> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - VectorMask<Float> mv = av.test(VectorOperators.IS_DEFAULT, vmask); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + FloatVector av = FloatVector.fromArray(SPECIES, a, i); + VectorMask<Float> mv = av.test(VectorOperators.IS_DEFAULT, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_DEFAULT(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_DEFAULT(a[i + j])); + } } } } @@ -2535,19 +2627,21 @@ public class Float128VectorTests extends AbstractVectorTest { } @Test(dataProvider = "floatTestOpMaskProvider") - static void IS_NEGATIVEMaskedFloat128VectorTestsSmokeTest(IntFunction<float[]> fa, + static void IS_NEGATIVEMaskedFloat128VectorTests(IntFunction<float[]> fa, IntFunction<boolean[]> fm) { float[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Float> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - VectorMask<Float> mv = av.test(VectorOperators.IS_NEGATIVE, vmask); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + FloatVector av = FloatVector.fromArray(SPECIES, a, i); + VectorMask<Float> mv = av.test(VectorOperators.IS_NEGATIVE, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_NEGATIVE(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_NEGATIVE(a[i + j])); + } } } } @@ -2574,19 +2668,21 @@ public class Float128VectorTests extends AbstractVectorTest { } @Test(dataProvider = "floatTestOpMaskProvider") - static void IS_FINITEMaskedFloat128VectorTestsSmokeTest(IntFunction<float[]> fa, + static void IS_FINITEMaskedFloat128VectorTests(IntFunction<float[]> fa, IntFunction<boolean[]> fm) { float[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Float> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - VectorMask<Float> mv = av.test(VectorOperators.IS_FINITE, vmask); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + FloatVector av = FloatVector.fromArray(SPECIES, a, i); + VectorMask<Float> mv = av.test(VectorOperators.IS_FINITE, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_FINITE(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_FINITE(a[i + j])); + } } } } @@ -2614,19 +2710,21 @@ public class Float128VectorTests extends AbstractVectorTest { } @Test(dataProvider = "floatTestOpMaskProvider") - static void IS_NANMaskedFloat128VectorTestsSmokeTest(IntFunction<float[]> fa, + static void IS_NANMaskedFloat128VectorTests(IntFunction<float[]> fa, IntFunction<boolean[]> fm) { float[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Float> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - VectorMask<Float> mv = av.test(VectorOperators.IS_NAN, vmask); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + FloatVector av = FloatVector.fromArray(SPECIES, a, i); + VectorMask<Float> mv = av.test(VectorOperators.IS_NAN, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_NAN(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_NAN(a[i + j])); + } } } } @@ -2654,19 +2752,21 @@ public class Float128VectorTests extends AbstractVectorTest { } @Test(dataProvider = "floatTestOpMaskProvider") - static void IS_INFINITEMaskedFloat128VectorTestsSmokeTest(IntFunction<float[]> fa, + static void IS_INFINITEMaskedFloat128VectorTests(IntFunction<float[]> fa, IntFunction<boolean[]> fm) { float[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Float> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - VectorMask<Float> mv = av.test(VectorOperators.IS_INFINITE, vmask); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + FloatVector av = FloatVector.fromArray(SPECIES, a, i); + VectorMask<Float> mv = av.test(VectorOperators.IS_INFINITE, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_INFINITE(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_INFINITE(a[i + j])); + } } } } @@ -4869,7 +4969,7 @@ public class Float128VectorTests extends AbstractVectorTest { static void maskFromToLongFloat128VectorTestsSmokeTest(long inputLong) { var vmask = VectorMask.fromLong(SPECIES, inputLong); long outputLong = vmask.toLong(); - Assert.assertEquals(outputLong, inputLong & (((1L << (SPECIES.length() - 1)) << 1) - 1)); + Assert.assertEquals(outputLong, (inputLong & (((0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length())))))); } @DataProvider @@ -4971,5 +5071,12 @@ public class Float128VectorTests extends AbstractVectorTest { VectorSpecies species = av.species().withShape(vsh); assert(species.equals(SPECIES)); } + + @Test + static void MaskAllTrueFloat128VectorTestsSmokeTest() { + for (int ic = 0; ic < INVOC_COUNT; ic++) { + Assert.assertEquals(SPECIES.maskAll(true).toLong(), -1L >>> (64 - SPECIES.length())); + } + } } diff --git a/test/jdk/jdk/incubator/vector/Float256VectorTests.java b/test/jdk/jdk/incubator/vector/Float256VectorTests.java index 3ff38daa0a8c671f4ff4ea6ec00c0178aa607b1f..8011f3a686912b16d02c26f0950d141cb58c7967 100644 --- a/test/jdk/jdk/incubator/vector/Float256VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Float256VectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -226,10 +226,10 @@ public class Float256VectorTests extends AbstractVectorTest { } } - static void assertInsertArraysEquals(float[] r, float[] a, float element, int index) { - int i = 0; + static void assertInsertArraysEquals(float[] r, float[] a, float element, int index, int start, int end) { + int i = start; try { - for (; i < a.length; i += 1) { + for (; i < end; i += 1) { if(i%SPECIES.length() == index) { Assert.assertEquals(r[i], element); } else { @@ -1309,6 +1309,10 @@ public class Float256VectorTests extends AbstractVectorTest { } + static float firstNonZero(float a, float b) { + return Float.compare(a, (float) 0) != 0 ? a : b; + } + @Test static void smokeTest1() { FloatVector three = FloatVector.broadcast(SPECIES, (byte)-3); @@ -2287,7 +2291,7 @@ public class Float256VectorTests extends AbstractVectorTest { static float MINReduce(float[] a, int idx) { float res = Float.POSITIVE_INFINITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (float)Math.min(res, a[i]); + res = (float) Math.min(res, a[i]); } return res; @@ -2295,8 +2299,8 @@ public class Float256VectorTests extends AbstractVectorTest { static float MINReduceAll(float[] a) { float res = Float.POSITIVE_INFINITY; - for (int i = 0; i < a.length; i++) { - res = (float)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (float) Math.min(res, MINReduce(a, i)); } return res; @@ -2318,7 +2322,7 @@ public class Float256VectorTests extends AbstractVectorTest { ra = Float.POSITIVE_INFINITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = (float)Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + ra = (float) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); } } @@ -2328,8 +2332,8 @@ public class Float256VectorTests extends AbstractVectorTest { static float MINReduceMasked(float[] a, int idx, boolean[] mask) { float res = Float.POSITIVE_INFINITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (float)Math.min(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (float) Math.min(res, a[i]); } return res; @@ -2337,9 +2341,8 @@ public class Float256VectorTests extends AbstractVectorTest { static float MINReduceAllMasked(float[] a, boolean[] mask) { float res = Float.POSITIVE_INFINITY; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (float)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (float) Math.min(res, MINReduceMasked(a, i, mask)); } return res; @@ -2363,7 +2366,7 @@ public class Float256VectorTests extends AbstractVectorTest { ra = Float.POSITIVE_INFINITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = (float)Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + ra = (float) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); } } @@ -2373,7 +2376,7 @@ public class Float256VectorTests extends AbstractVectorTest { static float MAXReduce(float[] a, int idx) { float res = Float.NEGATIVE_INFINITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (float)Math.max(res, a[i]); + res = (float) Math.max(res, a[i]); } return res; @@ -2381,8 +2384,8 @@ public class Float256VectorTests extends AbstractVectorTest { static float MAXReduceAll(float[] a) { float res = Float.NEGATIVE_INFINITY; - for (int i = 0; i < a.length; i++) { - res = (float)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (float) Math.max(res, MAXReduce(a, i)); } return res; @@ -2404,7 +2407,7 @@ public class Float256VectorTests extends AbstractVectorTest { ra = Float.NEGATIVE_INFINITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = (float)Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + ra = (float) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); } } @@ -2414,8 +2417,8 @@ public class Float256VectorTests extends AbstractVectorTest { static float MAXReduceMasked(float[] a, int idx, boolean[] mask) { float res = Float.NEGATIVE_INFINITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (float)Math.max(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (float) Math.max(res, a[i]); } return res; @@ -2423,9 +2426,8 @@ public class Float256VectorTests extends AbstractVectorTest { static float MAXReduceAllMasked(float[] a, boolean[] mask) { float res = Float.NEGATIVE_INFINITY; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (float)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (float) Math.max(res, MAXReduceMasked(a, i, mask)); } return res; @@ -2449,13 +2451,98 @@ public class Float256VectorTests extends AbstractVectorTest { ra = Float.NEGATIVE_INFINITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = (float)Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + ra = (float) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); } } assertReductionArraysEqualsMasked(r, ra, a, mask, Float256VectorTests::MAXReduceMasked, Float256VectorTests::MAXReduceAllMasked); } + static float FIRST_NONZEROReduce(float[] a, int idx) { + float res = (float) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + res = firstNonZero(res, a[i]); + } + + return res; + } + + static float FIRST_NONZEROReduceAll(float[] a) { + float res = (float) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); + } + + return res; + } + @Test(dataProvider = "floatUnaryOpProvider") + static void FIRST_NONZEROReduceFloat256VectorTests(IntFunction<float[]> fa) { + float[] a = fa.apply(SPECIES.length()); + float[] r = fr.apply(SPECIES.length()); + float ra = (float) 0; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + FloatVector av = FloatVector.fromArray(SPECIES, a, i); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (float) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + FloatVector av = FloatVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + } + } + + assertReductionArraysEquals(r, ra, a, + Float256VectorTests::FIRST_NONZEROReduce, Float256VectorTests::FIRST_NONZEROReduceAll); + } + static float FIRST_NONZEROReduceMasked(float[] a, int idx, boolean[] mask) { + float res = (float) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + if (mask[i % SPECIES.length()]) + res = firstNonZero(res, a[i]); + } + + return res; + } + + static float FIRST_NONZEROReduceAllMasked(float[] a, boolean[] mask) { + float res = (float) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); + } + + return res; + } + @Test(dataProvider = "floatUnaryOpMaskProvider") + static void FIRST_NONZEROReduceFloat256VectorTestsMasked(IntFunction<float[]> fa, IntFunction<boolean[]> fm) { + float[] a = fa.apply(SPECIES.length()); + float[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask<Float> vmask = VectorMask.fromArray(SPECIES, mask, 0); + float ra = (float) 0; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + FloatVector av = FloatVector.fromArray(SPECIES, a, i); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (float) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + FloatVector av = FloatVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + } + } + + assertReductionArraysEqualsMasked(r, ra, a, mask, + Float256VectorTests::FIRST_NONZEROReduceMasked, Float256VectorTests::FIRST_NONZEROReduceAllMasked); + } @@ -2467,13 +2554,16 @@ public class Float256VectorTests extends AbstractVectorTest { float[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { - for (int i = 0; i < a.length; i += SPECIES.length()) { + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - av.withLane(0, (float)4).intoArray(r, i); + av.withLane((j++ & (SPECIES.length()-1)), (float)(65535+i)).intoArray(r, i); } } - assertInsertArraysEquals(r, a, (float)4, 0); + + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { + assertInsertArraysEquals(r, a, (float)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); + } } static boolean testIS_DEFAULT(float a) { return bits(a)==0; @@ -2497,19 +2587,21 @@ public class Float256VectorTests extends AbstractVectorTest { } @Test(dataProvider = "floatTestOpMaskProvider") - static void IS_DEFAULTMaskedFloat256VectorTestsSmokeTest(IntFunction<float[]> fa, + static void IS_DEFAULTMaskedFloat256VectorTests(IntFunction<float[]> fa, IntFunction<boolean[]> fm) { float[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Float> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - VectorMask<Float> mv = av.test(VectorOperators.IS_DEFAULT, vmask); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + FloatVector av = FloatVector.fromArray(SPECIES, a, i); + VectorMask<Float> mv = av.test(VectorOperators.IS_DEFAULT, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_DEFAULT(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_DEFAULT(a[i + j])); + } } } } @@ -2535,19 +2627,21 @@ public class Float256VectorTests extends AbstractVectorTest { } @Test(dataProvider = "floatTestOpMaskProvider") - static void IS_NEGATIVEMaskedFloat256VectorTestsSmokeTest(IntFunction<float[]> fa, + static void IS_NEGATIVEMaskedFloat256VectorTests(IntFunction<float[]> fa, IntFunction<boolean[]> fm) { float[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Float> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - VectorMask<Float> mv = av.test(VectorOperators.IS_NEGATIVE, vmask); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + FloatVector av = FloatVector.fromArray(SPECIES, a, i); + VectorMask<Float> mv = av.test(VectorOperators.IS_NEGATIVE, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_NEGATIVE(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_NEGATIVE(a[i + j])); + } } } } @@ -2574,19 +2668,21 @@ public class Float256VectorTests extends AbstractVectorTest { } @Test(dataProvider = "floatTestOpMaskProvider") - static void IS_FINITEMaskedFloat256VectorTestsSmokeTest(IntFunction<float[]> fa, + static void IS_FINITEMaskedFloat256VectorTests(IntFunction<float[]> fa, IntFunction<boolean[]> fm) { float[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Float> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - VectorMask<Float> mv = av.test(VectorOperators.IS_FINITE, vmask); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + FloatVector av = FloatVector.fromArray(SPECIES, a, i); + VectorMask<Float> mv = av.test(VectorOperators.IS_FINITE, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_FINITE(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_FINITE(a[i + j])); + } } } } @@ -2614,19 +2710,21 @@ public class Float256VectorTests extends AbstractVectorTest { } @Test(dataProvider = "floatTestOpMaskProvider") - static void IS_NANMaskedFloat256VectorTestsSmokeTest(IntFunction<float[]> fa, + static void IS_NANMaskedFloat256VectorTests(IntFunction<float[]> fa, IntFunction<boolean[]> fm) { float[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Float> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - VectorMask<Float> mv = av.test(VectorOperators.IS_NAN, vmask); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + FloatVector av = FloatVector.fromArray(SPECIES, a, i); + VectorMask<Float> mv = av.test(VectorOperators.IS_NAN, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_NAN(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_NAN(a[i + j])); + } } } } @@ -2654,19 +2752,21 @@ public class Float256VectorTests extends AbstractVectorTest { } @Test(dataProvider = "floatTestOpMaskProvider") - static void IS_INFINITEMaskedFloat256VectorTestsSmokeTest(IntFunction<float[]> fa, + static void IS_INFINITEMaskedFloat256VectorTests(IntFunction<float[]> fa, IntFunction<boolean[]> fm) { float[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Float> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - VectorMask<Float> mv = av.test(VectorOperators.IS_INFINITE, vmask); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + FloatVector av = FloatVector.fromArray(SPECIES, a, i); + VectorMask<Float> mv = av.test(VectorOperators.IS_INFINITE, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_INFINITE(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_INFINITE(a[i + j])); + } } } } @@ -4869,7 +4969,7 @@ public class Float256VectorTests extends AbstractVectorTest { static void maskFromToLongFloat256VectorTestsSmokeTest(long inputLong) { var vmask = VectorMask.fromLong(SPECIES, inputLong); long outputLong = vmask.toLong(); - Assert.assertEquals(outputLong, inputLong & (((1L << (SPECIES.length() - 1)) << 1) - 1)); + Assert.assertEquals(outputLong, (inputLong & (((0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length())))))); } @DataProvider @@ -4971,5 +5071,12 @@ public class Float256VectorTests extends AbstractVectorTest { VectorSpecies species = av.species().withShape(vsh); assert(species.equals(SPECIES)); } + + @Test + static void MaskAllTrueFloat256VectorTestsSmokeTest() { + for (int ic = 0; ic < INVOC_COUNT; ic++) { + Assert.assertEquals(SPECIES.maskAll(true).toLong(), -1L >>> (64 - SPECIES.length())); + } + } } diff --git a/test/jdk/jdk/incubator/vector/Float512VectorTests.java b/test/jdk/jdk/incubator/vector/Float512VectorTests.java index e7d9e3fa53212c58083c63e686d188a6f66dbd4c..f6fa6ecc6f0c422774e9cb189806453beac99ac7 100644 --- a/test/jdk/jdk/incubator/vector/Float512VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Float512VectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -226,10 +226,10 @@ public class Float512VectorTests extends AbstractVectorTest { } } - static void assertInsertArraysEquals(float[] r, float[] a, float element, int index) { - int i = 0; + static void assertInsertArraysEquals(float[] r, float[] a, float element, int index, int start, int end) { + int i = start; try { - for (; i < a.length; i += 1) { + for (; i < end; i += 1) { if(i%SPECIES.length() == index) { Assert.assertEquals(r[i], element); } else { @@ -1309,6 +1309,10 @@ public class Float512VectorTests extends AbstractVectorTest { } + static float firstNonZero(float a, float b) { + return Float.compare(a, (float) 0) != 0 ? a : b; + } + @Test static void smokeTest1() { FloatVector three = FloatVector.broadcast(SPECIES, (byte)-3); @@ -2287,7 +2291,7 @@ public class Float512VectorTests extends AbstractVectorTest { static float MINReduce(float[] a, int idx) { float res = Float.POSITIVE_INFINITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (float)Math.min(res, a[i]); + res = (float) Math.min(res, a[i]); } return res; @@ -2295,8 +2299,8 @@ public class Float512VectorTests extends AbstractVectorTest { static float MINReduceAll(float[] a) { float res = Float.POSITIVE_INFINITY; - for (int i = 0; i < a.length; i++) { - res = (float)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (float) Math.min(res, MINReduce(a, i)); } return res; @@ -2318,7 +2322,7 @@ public class Float512VectorTests extends AbstractVectorTest { ra = Float.POSITIVE_INFINITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = (float)Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + ra = (float) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); } } @@ -2328,8 +2332,8 @@ public class Float512VectorTests extends AbstractVectorTest { static float MINReduceMasked(float[] a, int idx, boolean[] mask) { float res = Float.POSITIVE_INFINITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (float)Math.min(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (float) Math.min(res, a[i]); } return res; @@ -2337,9 +2341,8 @@ public class Float512VectorTests extends AbstractVectorTest { static float MINReduceAllMasked(float[] a, boolean[] mask) { float res = Float.POSITIVE_INFINITY; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (float)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (float) Math.min(res, MINReduceMasked(a, i, mask)); } return res; @@ -2363,7 +2366,7 @@ public class Float512VectorTests extends AbstractVectorTest { ra = Float.POSITIVE_INFINITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = (float)Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + ra = (float) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); } } @@ -2373,7 +2376,7 @@ public class Float512VectorTests extends AbstractVectorTest { static float MAXReduce(float[] a, int idx) { float res = Float.NEGATIVE_INFINITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (float)Math.max(res, a[i]); + res = (float) Math.max(res, a[i]); } return res; @@ -2381,8 +2384,8 @@ public class Float512VectorTests extends AbstractVectorTest { static float MAXReduceAll(float[] a) { float res = Float.NEGATIVE_INFINITY; - for (int i = 0; i < a.length; i++) { - res = (float)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (float) Math.max(res, MAXReduce(a, i)); } return res; @@ -2404,7 +2407,7 @@ public class Float512VectorTests extends AbstractVectorTest { ra = Float.NEGATIVE_INFINITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = (float)Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + ra = (float) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); } } @@ -2414,8 +2417,8 @@ public class Float512VectorTests extends AbstractVectorTest { static float MAXReduceMasked(float[] a, int idx, boolean[] mask) { float res = Float.NEGATIVE_INFINITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (float)Math.max(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (float) Math.max(res, a[i]); } return res; @@ -2423,9 +2426,8 @@ public class Float512VectorTests extends AbstractVectorTest { static float MAXReduceAllMasked(float[] a, boolean[] mask) { float res = Float.NEGATIVE_INFINITY; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (float)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (float) Math.max(res, MAXReduceMasked(a, i, mask)); } return res; @@ -2449,13 +2451,98 @@ public class Float512VectorTests extends AbstractVectorTest { ra = Float.NEGATIVE_INFINITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = (float)Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + ra = (float) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); } } assertReductionArraysEqualsMasked(r, ra, a, mask, Float512VectorTests::MAXReduceMasked, Float512VectorTests::MAXReduceAllMasked); } + static float FIRST_NONZEROReduce(float[] a, int idx) { + float res = (float) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + res = firstNonZero(res, a[i]); + } + + return res; + } + + static float FIRST_NONZEROReduceAll(float[] a) { + float res = (float) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); + } + + return res; + } + @Test(dataProvider = "floatUnaryOpProvider") + static void FIRST_NONZEROReduceFloat512VectorTests(IntFunction<float[]> fa) { + float[] a = fa.apply(SPECIES.length()); + float[] r = fr.apply(SPECIES.length()); + float ra = (float) 0; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + FloatVector av = FloatVector.fromArray(SPECIES, a, i); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (float) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + FloatVector av = FloatVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + } + } + + assertReductionArraysEquals(r, ra, a, + Float512VectorTests::FIRST_NONZEROReduce, Float512VectorTests::FIRST_NONZEROReduceAll); + } + static float FIRST_NONZEROReduceMasked(float[] a, int idx, boolean[] mask) { + float res = (float) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + if (mask[i % SPECIES.length()]) + res = firstNonZero(res, a[i]); + } + + return res; + } + + static float FIRST_NONZEROReduceAllMasked(float[] a, boolean[] mask) { + float res = (float) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); + } + + return res; + } + @Test(dataProvider = "floatUnaryOpMaskProvider") + static void FIRST_NONZEROReduceFloat512VectorTestsMasked(IntFunction<float[]> fa, IntFunction<boolean[]> fm) { + float[] a = fa.apply(SPECIES.length()); + float[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask<Float> vmask = VectorMask.fromArray(SPECIES, mask, 0); + float ra = (float) 0; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + FloatVector av = FloatVector.fromArray(SPECIES, a, i); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (float) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + FloatVector av = FloatVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + } + } + + assertReductionArraysEqualsMasked(r, ra, a, mask, + Float512VectorTests::FIRST_NONZEROReduceMasked, Float512VectorTests::FIRST_NONZEROReduceAllMasked); + } @@ -2467,13 +2554,16 @@ public class Float512VectorTests extends AbstractVectorTest { float[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { - for (int i = 0; i < a.length; i += SPECIES.length()) { + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - av.withLane(0, (float)4).intoArray(r, i); + av.withLane((j++ & (SPECIES.length()-1)), (float)(65535+i)).intoArray(r, i); } } - assertInsertArraysEquals(r, a, (float)4, 0); + + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { + assertInsertArraysEquals(r, a, (float)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); + } } static boolean testIS_DEFAULT(float a) { return bits(a)==0; @@ -2497,19 +2587,21 @@ public class Float512VectorTests extends AbstractVectorTest { } @Test(dataProvider = "floatTestOpMaskProvider") - static void IS_DEFAULTMaskedFloat512VectorTestsSmokeTest(IntFunction<float[]> fa, + static void IS_DEFAULTMaskedFloat512VectorTests(IntFunction<float[]> fa, IntFunction<boolean[]> fm) { float[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Float> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - VectorMask<Float> mv = av.test(VectorOperators.IS_DEFAULT, vmask); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + FloatVector av = FloatVector.fromArray(SPECIES, a, i); + VectorMask<Float> mv = av.test(VectorOperators.IS_DEFAULT, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_DEFAULT(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_DEFAULT(a[i + j])); + } } } } @@ -2535,19 +2627,21 @@ public class Float512VectorTests extends AbstractVectorTest { } @Test(dataProvider = "floatTestOpMaskProvider") - static void IS_NEGATIVEMaskedFloat512VectorTestsSmokeTest(IntFunction<float[]> fa, + static void IS_NEGATIVEMaskedFloat512VectorTests(IntFunction<float[]> fa, IntFunction<boolean[]> fm) { float[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Float> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - VectorMask<Float> mv = av.test(VectorOperators.IS_NEGATIVE, vmask); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + FloatVector av = FloatVector.fromArray(SPECIES, a, i); + VectorMask<Float> mv = av.test(VectorOperators.IS_NEGATIVE, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_NEGATIVE(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_NEGATIVE(a[i + j])); + } } } } @@ -2574,19 +2668,21 @@ public class Float512VectorTests extends AbstractVectorTest { } @Test(dataProvider = "floatTestOpMaskProvider") - static void IS_FINITEMaskedFloat512VectorTestsSmokeTest(IntFunction<float[]> fa, + static void IS_FINITEMaskedFloat512VectorTests(IntFunction<float[]> fa, IntFunction<boolean[]> fm) { float[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Float> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - VectorMask<Float> mv = av.test(VectorOperators.IS_FINITE, vmask); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + FloatVector av = FloatVector.fromArray(SPECIES, a, i); + VectorMask<Float> mv = av.test(VectorOperators.IS_FINITE, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_FINITE(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_FINITE(a[i + j])); + } } } } @@ -2614,19 +2710,21 @@ public class Float512VectorTests extends AbstractVectorTest { } @Test(dataProvider = "floatTestOpMaskProvider") - static void IS_NANMaskedFloat512VectorTestsSmokeTest(IntFunction<float[]> fa, + static void IS_NANMaskedFloat512VectorTests(IntFunction<float[]> fa, IntFunction<boolean[]> fm) { float[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Float> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - VectorMask<Float> mv = av.test(VectorOperators.IS_NAN, vmask); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + FloatVector av = FloatVector.fromArray(SPECIES, a, i); + VectorMask<Float> mv = av.test(VectorOperators.IS_NAN, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_NAN(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_NAN(a[i + j])); + } } } } @@ -2654,19 +2752,21 @@ public class Float512VectorTests extends AbstractVectorTest { } @Test(dataProvider = "floatTestOpMaskProvider") - static void IS_INFINITEMaskedFloat512VectorTestsSmokeTest(IntFunction<float[]> fa, + static void IS_INFINITEMaskedFloat512VectorTests(IntFunction<float[]> fa, IntFunction<boolean[]> fm) { float[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Float> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - VectorMask<Float> mv = av.test(VectorOperators.IS_INFINITE, vmask); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + FloatVector av = FloatVector.fromArray(SPECIES, a, i); + VectorMask<Float> mv = av.test(VectorOperators.IS_INFINITE, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_INFINITE(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_INFINITE(a[i + j])); + } } } } @@ -4869,7 +4969,7 @@ public class Float512VectorTests extends AbstractVectorTest { static void maskFromToLongFloat512VectorTestsSmokeTest(long inputLong) { var vmask = VectorMask.fromLong(SPECIES, inputLong); long outputLong = vmask.toLong(); - Assert.assertEquals(outputLong, inputLong & (((1L << (SPECIES.length() - 1)) << 1) - 1)); + Assert.assertEquals(outputLong, (inputLong & (((0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length())))))); } @DataProvider @@ -4971,5 +5071,12 @@ public class Float512VectorTests extends AbstractVectorTest { VectorSpecies species = av.species().withShape(vsh); assert(species.equals(SPECIES)); } + + @Test + static void MaskAllTrueFloat512VectorTestsSmokeTest() { + for (int ic = 0; ic < INVOC_COUNT; ic++) { + Assert.assertEquals(SPECIES.maskAll(true).toLong(), -1L >>> (64 - SPECIES.length())); + } + } } diff --git a/test/jdk/jdk/incubator/vector/Float64VectorTests.java b/test/jdk/jdk/incubator/vector/Float64VectorTests.java index e4c646623bb93b219abde2ece7c25f7da218acb1..d0edf33f34050aad22461c938d5a09aa4524c55c 100644 --- a/test/jdk/jdk/incubator/vector/Float64VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Float64VectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -226,10 +226,10 @@ public class Float64VectorTests extends AbstractVectorTest { } } - static void assertInsertArraysEquals(float[] r, float[] a, float element, int index) { - int i = 0; + static void assertInsertArraysEquals(float[] r, float[] a, float element, int index, int start, int end) { + int i = start; try { - for (; i < a.length; i += 1) { + for (; i < end; i += 1) { if(i%SPECIES.length() == index) { Assert.assertEquals(r[i], element); } else { @@ -1309,6 +1309,10 @@ public class Float64VectorTests extends AbstractVectorTest { } + static float firstNonZero(float a, float b) { + return Float.compare(a, (float) 0) != 0 ? a : b; + } + @Test static void smokeTest1() { FloatVector three = FloatVector.broadcast(SPECIES, (byte)-3); @@ -2287,7 +2291,7 @@ public class Float64VectorTests extends AbstractVectorTest { static float MINReduce(float[] a, int idx) { float res = Float.POSITIVE_INFINITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (float)Math.min(res, a[i]); + res = (float) Math.min(res, a[i]); } return res; @@ -2295,8 +2299,8 @@ public class Float64VectorTests extends AbstractVectorTest { static float MINReduceAll(float[] a) { float res = Float.POSITIVE_INFINITY; - for (int i = 0; i < a.length; i++) { - res = (float)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (float) Math.min(res, MINReduce(a, i)); } return res; @@ -2318,7 +2322,7 @@ public class Float64VectorTests extends AbstractVectorTest { ra = Float.POSITIVE_INFINITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = (float)Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + ra = (float) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); } } @@ -2328,8 +2332,8 @@ public class Float64VectorTests extends AbstractVectorTest { static float MINReduceMasked(float[] a, int idx, boolean[] mask) { float res = Float.POSITIVE_INFINITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (float)Math.min(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (float) Math.min(res, a[i]); } return res; @@ -2337,9 +2341,8 @@ public class Float64VectorTests extends AbstractVectorTest { static float MINReduceAllMasked(float[] a, boolean[] mask) { float res = Float.POSITIVE_INFINITY; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (float)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (float) Math.min(res, MINReduceMasked(a, i, mask)); } return res; @@ -2363,7 +2366,7 @@ public class Float64VectorTests extends AbstractVectorTest { ra = Float.POSITIVE_INFINITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = (float)Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + ra = (float) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); } } @@ -2373,7 +2376,7 @@ public class Float64VectorTests extends AbstractVectorTest { static float MAXReduce(float[] a, int idx) { float res = Float.NEGATIVE_INFINITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (float)Math.max(res, a[i]); + res = (float) Math.max(res, a[i]); } return res; @@ -2381,8 +2384,8 @@ public class Float64VectorTests extends AbstractVectorTest { static float MAXReduceAll(float[] a) { float res = Float.NEGATIVE_INFINITY; - for (int i = 0; i < a.length; i++) { - res = (float)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (float) Math.max(res, MAXReduce(a, i)); } return res; @@ -2404,7 +2407,7 @@ public class Float64VectorTests extends AbstractVectorTest { ra = Float.NEGATIVE_INFINITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = (float)Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + ra = (float) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); } } @@ -2414,8 +2417,8 @@ public class Float64VectorTests extends AbstractVectorTest { static float MAXReduceMasked(float[] a, int idx, boolean[] mask) { float res = Float.NEGATIVE_INFINITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (float)Math.max(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (float) Math.max(res, a[i]); } return res; @@ -2423,9 +2426,8 @@ public class Float64VectorTests extends AbstractVectorTest { static float MAXReduceAllMasked(float[] a, boolean[] mask) { float res = Float.NEGATIVE_INFINITY; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (float)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (float) Math.max(res, MAXReduceMasked(a, i, mask)); } return res; @@ -2449,13 +2451,98 @@ public class Float64VectorTests extends AbstractVectorTest { ra = Float.NEGATIVE_INFINITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = (float)Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + ra = (float) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); } } assertReductionArraysEqualsMasked(r, ra, a, mask, Float64VectorTests::MAXReduceMasked, Float64VectorTests::MAXReduceAllMasked); } + static float FIRST_NONZEROReduce(float[] a, int idx) { + float res = (float) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + res = firstNonZero(res, a[i]); + } + + return res; + } + + static float FIRST_NONZEROReduceAll(float[] a) { + float res = (float) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); + } + + return res; + } + @Test(dataProvider = "floatUnaryOpProvider") + static void FIRST_NONZEROReduceFloat64VectorTests(IntFunction<float[]> fa) { + float[] a = fa.apply(SPECIES.length()); + float[] r = fr.apply(SPECIES.length()); + float ra = (float) 0; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + FloatVector av = FloatVector.fromArray(SPECIES, a, i); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (float) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + FloatVector av = FloatVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + } + } + + assertReductionArraysEquals(r, ra, a, + Float64VectorTests::FIRST_NONZEROReduce, Float64VectorTests::FIRST_NONZEROReduceAll); + } + static float FIRST_NONZEROReduceMasked(float[] a, int idx, boolean[] mask) { + float res = (float) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + if (mask[i % SPECIES.length()]) + res = firstNonZero(res, a[i]); + } + + return res; + } + + static float FIRST_NONZEROReduceAllMasked(float[] a, boolean[] mask) { + float res = (float) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); + } + + return res; + } + @Test(dataProvider = "floatUnaryOpMaskProvider") + static void FIRST_NONZEROReduceFloat64VectorTestsMasked(IntFunction<float[]> fa, IntFunction<boolean[]> fm) { + float[] a = fa.apply(SPECIES.length()); + float[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask<Float> vmask = VectorMask.fromArray(SPECIES, mask, 0); + float ra = (float) 0; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + FloatVector av = FloatVector.fromArray(SPECIES, a, i); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (float) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + FloatVector av = FloatVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + } + } + + assertReductionArraysEqualsMasked(r, ra, a, mask, + Float64VectorTests::FIRST_NONZEROReduceMasked, Float64VectorTests::FIRST_NONZEROReduceAllMasked); + } @@ -2467,13 +2554,16 @@ public class Float64VectorTests extends AbstractVectorTest { float[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { - for (int i = 0; i < a.length; i += SPECIES.length()) { + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - av.withLane(0, (float)4).intoArray(r, i); + av.withLane((j++ & (SPECIES.length()-1)), (float)(65535+i)).intoArray(r, i); } } - assertInsertArraysEquals(r, a, (float)4, 0); + + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { + assertInsertArraysEquals(r, a, (float)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); + } } static boolean testIS_DEFAULT(float a) { return bits(a)==0; @@ -2497,19 +2587,21 @@ public class Float64VectorTests extends AbstractVectorTest { } @Test(dataProvider = "floatTestOpMaskProvider") - static void IS_DEFAULTMaskedFloat64VectorTestsSmokeTest(IntFunction<float[]> fa, + static void IS_DEFAULTMaskedFloat64VectorTests(IntFunction<float[]> fa, IntFunction<boolean[]> fm) { float[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Float> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - VectorMask<Float> mv = av.test(VectorOperators.IS_DEFAULT, vmask); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + FloatVector av = FloatVector.fromArray(SPECIES, a, i); + VectorMask<Float> mv = av.test(VectorOperators.IS_DEFAULT, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_DEFAULT(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_DEFAULT(a[i + j])); + } } } } @@ -2535,19 +2627,21 @@ public class Float64VectorTests extends AbstractVectorTest { } @Test(dataProvider = "floatTestOpMaskProvider") - static void IS_NEGATIVEMaskedFloat64VectorTestsSmokeTest(IntFunction<float[]> fa, + static void IS_NEGATIVEMaskedFloat64VectorTests(IntFunction<float[]> fa, IntFunction<boolean[]> fm) { float[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Float> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - VectorMask<Float> mv = av.test(VectorOperators.IS_NEGATIVE, vmask); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + FloatVector av = FloatVector.fromArray(SPECIES, a, i); + VectorMask<Float> mv = av.test(VectorOperators.IS_NEGATIVE, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_NEGATIVE(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_NEGATIVE(a[i + j])); + } } } } @@ -2574,19 +2668,21 @@ public class Float64VectorTests extends AbstractVectorTest { } @Test(dataProvider = "floatTestOpMaskProvider") - static void IS_FINITEMaskedFloat64VectorTestsSmokeTest(IntFunction<float[]> fa, + static void IS_FINITEMaskedFloat64VectorTests(IntFunction<float[]> fa, IntFunction<boolean[]> fm) { float[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Float> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - VectorMask<Float> mv = av.test(VectorOperators.IS_FINITE, vmask); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + FloatVector av = FloatVector.fromArray(SPECIES, a, i); + VectorMask<Float> mv = av.test(VectorOperators.IS_FINITE, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_FINITE(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_FINITE(a[i + j])); + } } } } @@ -2614,19 +2710,21 @@ public class Float64VectorTests extends AbstractVectorTest { } @Test(dataProvider = "floatTestOpMaskProvider") - static void IS_NANMaskedFloat64VectorTestsSmokeTest(IntFunction<float[]> fa, + static void IS_NANMaskedFloat64VectorTests(IntFunction<float[]> fa, IntFunction<boolean[]> fm) { float[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Float> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - VectorMask<Float> mv = av.test(VectorOperators.IS_NAN, vmask); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + FloatVector av = FloatVector.fromArray(SPECIES, a, i); + VectorMask<Float> mv = av.test(VectorOperators.IS_NAN, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_NAN(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_NAN(a[i + j])); + } } } } @@ -2654,19 +2752,21 @@ public class Float64VectorTests extends AbstractVectorTest { } @Test(dataProvider = "floatTestOpMaskProvider") - static void IS_INFINITEMaskedFloat64VectorTestsSmokeTest(IntFunction<float[]> fa, + static void IS_INFINITEMaskedFloat64VectorTests(IntFunction<float[]> fa, IntFunction<boolean[]> fm) { float[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Float> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - VectorMask<Float> mv = av.test(VectorOperators.IS_INFINITE, vmask); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + FloatVector av = FloatVector.fromArray(SPECIES, a, i); + VectorMask<Float> mv = av.test(VectorOperators.IS_INFINITE, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_INFINITE(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_INFINITE(a[i + j])); + } } } } @@ -4869,7 +4969,7 @@ public class Float64VectorTests extends AbstractVectorTest { static void maskFromToLongFloat64VectorTestsSmokeTest(long inputLong) { var vmask = VectorMask.fromLong(SPECIES, inputLong); long outputLong = vmask.toLong(); - Assert.assertEquals(outputLong, inputLong & (((1L << (SPECIES.length() - 1)) << 1) - 1)); + Assert.assertEquals(outputLong, (inputLong & (((0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length())))))); } @DataProvider @@ -4971,5 +5071,12 @@ public class Float64VectorTests extends AbstractVectorTest { VectorSpecies species = av.species().withShape(vsh); assert(species.equals(SPECIES)); } + + @Test + static void MaskAllTrueFloat64VectorTestsSmokeTest() { + for (int ic = 0; ic < INVOC_COUNT; ic++) { + Assert.assertEquals(SPECIES.maskAll(true).toLong(), -1L >>> (64 - SPECIES.length())); + } + } } diff --git a/test/jdk/jdk/incubator/vector/FloatMaxVectorTests.java b/test/jdk/jdk/incubator/vector/FloatMaxVectorTests.java index 23f01dcdb95ba05917fc601d39e5330e92b196db..4f8711e8b1c9ce03b313286e1b414472f7b6cea6 100644 --- a/test/jdk/jdk/incubator/vector/FloatMaxVectorTests.java +++ b/test/jdk/jdk/incubator/vector/FloatMaxVectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -231,10 +231,10 @@ public class FloatMaxVectorTests extends AbstractVectorTest { } } - static void assertInsertArraysEquals(float[] r, float[] a, float element, int index) { - int i = 0; + static void assertInsertArraysEquals(float[] r, float[] a, float element, int index, int start, int end) { + int i = start; try { - for (; i < a.length; i += 1) { + for (; i < end; i += 1) { if(i%SPECIES.length() == index) { Assert.assertEquals(r[i], element); } else { @@ -1314,6 +1314,10 @@ public class FloatMaxVectorTests extends AbstractVectorTest { } + static float firstNonZero(float a, float b) { + return Float.compare(a, (float) 0) != 0 ? a : b; + } + @Test static void smokeTest1() { FloatVector three = FloatVector.broadcast(SPECIES, (byte)-3); @@ -2292,7 +2296,7 @@ public class FloatMaxVectorTests extends AbstractVectorTest { static float MINReduce(float[] a, int idx) { float res = Float.POSITIVE_INFINITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (float)Math.min(res, a[i]); + res = (float) Math.min(res, a[i]); } return res; @@ -2300,8 +2304,8 @@ public class FloatMaxVectorTests extends AbstractVectorTest { static float MINReduceAll(float[] a) { float res = Float.POSITIVE_INFINITY; - for (int i = 0; i < a.length; i++) { - res = (float)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (float) Math.min(res, MINReduce(a, i)); } return res; @@ -2323,7 +2327,7 @@ public class FloatMaxVectorTests extends AbstractVectorTest { ra = Float.POSITIVE_INFINITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = (float)Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + ra = (float) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); } } @@ -2333,8 +2337,8 @@ public class FloatMaxVectorTests extends AbstractVectorTest { static float MINReduceMasked(float[] a, int idx, boolean[] mask) { float res = Float.POSITIVE_INFINITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (float)Math.min(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (float) Math.min(res, a[i]); } return res; @@ -2342,9 +2346,8 @@ public class FloatMaxVectorTests extends AbstractVectorTest { static float MINReduceAllMasked(float[] a, boolean[] mask) { float res = Float.POSITIVE_INFINITY; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (float)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (float) Math.min(res, MINReduceMasked(a, i, mask)); } return res; @@ -2368,7 +2371,7 @@ public class FloatMaxVectorTests extends AbstractVectorTest { ra = Float.POSITIVE_INFINITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = (float)Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + ra = (float) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); } } @@ -2378,7 +2381,7 @@ public class FloatMaxVectorTests extends AbstractVectorTest { static float MAXReduce(float[] a, int idx) { float res = Float.NEGATIVE_INFINITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (float)Math.max(res, a[i]); + res = (float) Math.max(res, a[i]); } return res; @@ -2386,8 +2389,8 @@ public class FloatMaxVectorTests extends AbstractVectorTest { static float MAXReduceAll(float[] a) { float res = Float.NEGATIVE_INFINITY; - for (int i = 0; i < a.length; i++) { - res = (float)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (float) Math.max(res, MAXReduce(a, i)); } return res; @@ -2409,7 +2412,7 @@ public class FloatMaxVectorTests extends AbstractVectorTest { ra = Float.NEGATIVE_INFINITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = (float)Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + ra = (float) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); } } @@ -2419,8 +2422,8 @@ public class FloatMaxVectorTests extends AbstractVectorTest { static float MAXReduceMasked(float[] a, int idx, boolean[] mask) { float res = Float.NEGATIVE_INFINITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (float)Math.max(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (float) Math.max(res, a[i]); } return res; @@ -2428,9 +2431,8 @@ public class FloatMaxVectorTests extends AbstractVectorTest { static float MAXReduceAllMasked(float[] a, boolean[] mask) { float res = Float.NEGATIVE_INFINITY; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (float)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (float) Math.max(res, MAXReduceMasked(a, i, mask)); } return res; @@ -2454,13 +2456,98 @@ public class FloatMaxVectorTests extends AbstractVectorTest { ra = Float.NEGATIVE_INFINITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = (float)Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + ra = (float) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); } } assertReductionArraysEqualsMasked(r, ra, a, mask, FloatMaxVectorTests::MAXReduceMasked, FloatMaxVectorTests::MAXReduceAllMasked); } + static float FIRST_NONZEROReduce(float[] a, int idx) { + float res = (float) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + res = firstNonZero(res, a[i]); + } + + return res; + } + + static float FIRST_NONZEROReduceAll(float[] a) { + float res = (float) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); + } + + return res; + } + @Test(dataProvider = "floatUnaryOpProvider") + static void FIRST_NONZEROReduceFloatMaxVectorTests(IntFunction<float[]> fa) { + float[] a = fa.apply(SPECIES.length()); + float[] r = fr.apply(SPECIES.length()); + float ra = (float) 0; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + FloatVector av = FloatVector.fromArray(SPECIES, a, i); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (float) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + FloatVector av = FloatVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + } + } + + assertReductionArraysEquals(r, ra, a, + FloatMaxVectorTests::FIRST_NONZEROReduce, FloatMaxVectorTests::FIRST_NONZEROReduceAll); + } + static float FIRST_NONZEROReduceMasked(float[] a, int idx, boolean[] mask) { + float res = (float) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + if (mask[i % SPECIES.length()]) + res = firstNonZero(res, a[i]); + } + + return res; + } + + static float FIRST_NONZEROReduceAllMasked(float[] a, boolean[] mask) { + float res = (float) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); + } + + return res; + } + @Test(dataProvider = "floatUnaryOpMaskProvider") + static void FIRST_NONZEROReduceFloatMaxVectorTestsMasked(IntFunction<float[]> fa, IntFunction<boolean[]> fm) { + float[] a = fa.apply(SPECIES.length()); + float[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask<Float> vmask = VectorMask.fromArray(SPECIES, mask, 0); + float ra = (float) 0; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + FloatVector av = FloatVector.fromArray(SPECIES, a, i); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (float) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + FloatVector av = FloatVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + } + } + + assertReductionArraysEqualsMasked(r, ra, a, mask, + FloatMaxVectorTests::FIRST_NONZEROReduceMasked, FloatMaxVectorTests::FIRST_NONZEROReduceAllMasked); + } @@ -2472,13 +2559,16 @@ public class FloatMaxVectorTests extends AbstractVectorTest { float[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { - for (int i = 0; i < a.length; i += SPECIES.length()) { + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - av.withLane(0, (float)4).intoArray(r, i); + av.withLane((j++ & (SPECIES.length()-1)), (float)(65535+i)).intoArray(r, i); } } - assertInsertArraysEquals(r, a, (float)4, 0); + + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { + assertInsertArraysEquals(r, a, (float)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); + } } static boolean testIS_DEFAULT(float a) { return bits(a)==0; @@ -2502,19 +2592,21 @@ public class FloatMaxVectorTests extends AbstractVectorTest { } @Test(dataProvider = "floatTestOpMaskProvider") - static void IS_DEFAULTMaskedFloatMaxVectorTestsSmokeTest(IntFunction<float[]> fa, + static void IS_DEFAULTMaskedFloatMaxVectorTests(IntFunction<float[]> fa, IntFunction<boolean[]> fm) { float[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Float> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - VectorMask<Float> mv = av.test(VectorOperators.IS_DEFAULT, vmask); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + FloatVector av = FloatVector.fromArray(SPECIES, a, i); + VectorMask<Float> mv = av.test(VectorOperators.IS_DEFAULT, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_DEFAULT(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_DEFAULT(a[i + j])); + } } } } @@ -2540,19 +2632,21 @@ public class FloatMaxVectorTests extends AbstractVectorTest { } @Test(dataProvider = "floatTestOpMaskProvider") - static void IS_NEGATIVEMaskedFloatMaxVectorTestsSmokeTest(IntFunction<float[]> fa, + static void IS_NEGATIVEMaskedFloatMaxVectorTests(IntFunction<float[]> fa, IntFunction<boolean[]> fm) { float[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Float> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - VectorMask<Float> mv = av.test(VectorOperators.IS_NEGATIVE, vmask); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + FloatVector av = FloatVector.fromArray(SPECIES, a, i); + VectorMask<Float> mv = av.test(VectorOperators.IS_NEGATIVE, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_NEGATIVE(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_NEGATIVE(a[i + j])); + } } } } @@ -2579,19 +2673,21 @@ public class FloatMaxVectorTests extends AbstractVectorTest { } @Test(dataProvider = "floatTestOpMaskProvider") - static void IS_FINITEMaskedFloatMaxVectorTestsSmokeTest(IntFunction<float[]> fa, + static void IS_FINITEMaskedFloatMaxVectorTests(IntFunction<float[]> fa, IntFunction<boolean[]> fm) { float[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Float> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - VectorMask<Float> mv = av.test(VectorOperators.IS_FINITE, vmask); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + FloatVector av = FloatVector.fromArray(SPECIES, a, i); + VectorMask<Float> mv = av.test(VectorOperators.IS_FINITE, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_FINITE(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_FINITE(a[i + j])); + } } } } @@ -2619,19 +2715,21 @@ public class FloatMaxVectorTests extends AbstractVectorTest { } @Test(dataProvider = "floatTestOpMaskProvider") - static void IS_NANMaskedFloatMaxVectorTestsSmokeTest(IntFunction<float[]> fa, + static void IS_NANMaskedFloatMaxVectorTests(IntFunction<float[]> fa, IntFunction<boolean[]> fm) { float[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Float> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - VectorMask<Float> mv = av.test(VectorOperators.IS_NAN, vmask); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + FloatVector av = FloatVector.fromArray(SPECIES, a, i); + VectorMask<Float> mv = av.test(VectorOperators.IS_NAN, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_NAN(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_NAN(a[i + j])); + } } } } @@ -2659,19 +2757,21 @@ public class FloatMaxVectorTests extends AbstractVectorTest { } @Test(dataProvider = "floatTestOpMaskProvider") - static void IS_INFINITEMaskedFloatMaxVectorTestsSmokeTest(IntFunction<float[]> fa, + static void IS_INFINITEMaskedFloatMaxVectorTests(IntFunction<float[]> fa, IntFunction<boolean[]> fm) { float[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Float> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - VectorMask<Float> mv = av.test(VectorOperators.IS_INFINITE, vmask); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + FloatVector av = FloatVector.fromArray(SPECIES, a, i); + VectorMask<Float> mv = av.test(VectorOperators.IS_INFINITE, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_INFINITE(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_INFINITE(a[i + j])); + } } } } @@ -4960,5 +5060,12 @@ public class FloatMaxVectorTests extends AbstractVectorTest { VectorSpecies species = av.species().withShape(vsh); assert(species.equals(SPECIES)); } + + @Test + static void MaskAllTrueFloatMaxVectorTestsSmokeTest() { + for (int ic = 0; ic < INVOC_COUNT; ic++) { + Assert.assertEquals(SPECIES.maskAll(true).toLong(), -1L >>> (64 - SPECIES.length())); + } + } } diff --git a/test/jdk/jdk/incubator/vector/Int128VectorTests.java b/test/jdk/jdk/incubator/vector/Int128VectorTests.java index 0493494d1c02f2b25fce70cdd62fae6b297a87d8..4de0a1b30446553b4d5c9499e11b45d500dfb3a8 100644 --- a/test/jdk/jdk/incubator/vector/Int128VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Int128VectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -226,10 +226,10 @@ public class Int128VectorTests extends AbstractVectorTest { } } - static void assertInsertArraysEquals(int[] r, int[] a, int element, int index) { - int i = 0; + static void assertInsertArraysEquals(int[] r, int[] a, int element, int index, int start, int end) { + int i = start; try { - for (; i < a.length; i += 1) { + for (; i < end; i += 1) { if(i%SPECIES.length() == index) { Assert.assertEquals(r[i], element); } else { @@ -1161,6 +1161,10 @@ public class Int128VectorTests extends AbstractVectorTest { return Integer.compareUnsigned(a, b) >= 0; } + static int firstNonZero(int a, int b) { + return Integer.compare(a, (int) 0) != 0 ? a : b; + } + @Test static void smokeTest1() { IntVector three = IntVector.broadcast(SPECIES, (byte)-3); @@ -3181,7 +3185,7 @@ public class Int128VectorTests extends AbstractVectorTest { static int MINReduce(int[] a, int idx) { int res = Integer.MAX_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (int)Math.min(res, a[i]); + res = (int) Math.min(res, a[i]); } return res; @@ -3189,8 +3193,8 @@ public class Int128VectorTests extends AbstractVectorTest { static int MINReduceAll(int[] a) { int res = Integer.MAX_VALUE; - for (int i = 0; i < a.length; i++) { - res = (int)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (int) Math.min(res, MINReduce(a, i)); } return res; @@ -3212,7 +3216,7 @@ public class Int128VectorTests extends AbstractVectorTest { ra = Integer.MAX_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int)Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + ra = (int) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); } } @@ -3222,8 +3226,8 @@ public class Int128VectorTests extends AbstractVectorTest { static int MINReduceMasked(int[] a, int idx, boolean[] mask) { int res = Integer.MAX_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (int)Math.min(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (int) Math.min(res, a[i]); } return res; @@ -3231,9 +3235,8 @@ public class Int128VectorTests extends AbstractVectorTest { static int MINReduceAllMasked(int[] a, boolean[] mask) { int res = Integer.MAX_VALUE; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (int)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (int) Math.min(res, MINReduceMasked(a, i, mask)); } return res; @@ -3257,7 +3260,7 @@ public class Int128VectorTests extends AbstractVectorTest { ra = Integer.MAX_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int)Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + ra = (int) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); } } @@ -3267,7 +3270,7 @@ public class Int128VectorTests extends AbstractVectorTest { static int MAXReduce(int[] a, int idx) { int res = Integer.MIN_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (int)Math.max(res, a[i]); + res = (int) Math.max(res, a[i]); } return res; @@ -3275,8 +3278,8 @@ public class Int128VectorTests extends AbstractVectorTest { static int MAXReduceAll(int[] a) { int res = Integer.MIN_VALUE; - for (int i = 0; i < a.length; i++) { - res = (int)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (int) Math.max(res, MAXReduce(a, i)); } return res; @@ -3298,7 +3301,7 @@ public class Int128VectorTests extends AbstractVectorTest { ra = Integer.MIN_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int)Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + ra = (int) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); } } @@ -3308,8 +3311,8 @@ public class Int128VectorTests extends AbstractVectorTest { static int MAXReduceMasked(int[] a, int idx, boolean[] mask) { int res = Integer.MIN_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (int)Math.max(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (int) Math.max(res, a[i]); } return res; @@ -3317,9 +3320,8 @@ public class Int128VectorTests extends AbstractVectorTest { static int MAXReduceAllMasked(int[] a, boolean[] mask) { int res = Integer.MIN_VALUE; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (int)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (int) Math.max(res, MAXReduceMasked(a, i, mask)); } return res; @@ -3343,13 +3345,98 @@ public class Int128VectorTests extends AbstractVectorTest { ra = Integer.MIN_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int)Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + ra = (int) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); } } assertReductionArraysEqualsMasked(r, ra, a, mask, Int128VectorTests::MAXReduceMasked, Int128VectorTests::MAXReduceAllMasked); } + static int FIRST_NONZEROReduce(int[] a, int idx) { + int res = (int) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + res = firstNonZero(res, a[i]); + } + + return res; + } + + static int FIRST_NONZEROReduceAll(int[] a) { + int res = (int) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); + } + + return res; + } + @Test(dataProvider = "intUnaryOpProvider") + static void FIRST_NONZEROReduceInt128VectorTests(IntFunction<int[]> fa) { + int[] a = fa.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + int ra = (int) 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); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (int) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + } + } + + assertReductionArraysEquals(r, ra, a, + Int128VectorTests::FIRST_NONZEROReduce, Int128VectorTests::FIRST_NONZEROReduceAll); + } + static int FIRST_NONZEROReduceMasked(int[] a, int idx, boolean[] mask) { + int res = (int) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + if (mask[i % SPECIES.length()]) + res = firstNonZero(res, a[i]); + } + + return res; + } + + static int FIRST_NONZEROReduceAllMasked(int[] a, boolean[] mask) { + int res = (int) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); + } + + return res; + } + @Test(dataProvider = "intUnaryOpMaskProvider") + static void FIRST_NONZEROReduceInt128VectorTestsMasked(IntFunction<int[]> fa, IntFunction<boolean[]> fm) { + int[] a = fa.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask<Integer> vmask = VectorMask.fromArray(SPECIES, mask, 0); + int ra = (int) 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); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (int) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + } + } + + assertReductionArraysEqualsMasked(r, ra, a, mask, + Int128VectorTests::FIRST_NONZEROReduceMasked, Int128VectorTests::FIRST_NONZEROReduceAllMasked); + } static boolean anyTrue(boolean[] a, int idx) { boolean res = false; @@ -3409,13 +3496,16 @@ public class Int128VectorTests extends AbstractVectorTest { int[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { - for (int i = 0; i < a.length; i += SPECIES.length()) { + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - av.withLane(0, (int)4).intoArray(r, i); + av.withLane((j++ & (SPECIES.length()-1)), (int)(65535+i)).intoArray(r, i); } } - assertInsertArraysEquals(r, a, (int)4, 0); + + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { + assertInsertArraysEquals(r, a, (int)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); + } } static boolean testIS_DEFAULT(int a) { return bits(a)==0; @@ -3439,19 +3529,21 @@ public class Int128VectorTests extends AbstractVectorTest { } @Test(dataProvider = "intTestOpMaskProvider") - static void IS_DEFAULTMaskedInt128VectorTestsSmokeTest(IntFunction<int[]> fa, + static void IS_DEFAULTMaskedInt128VectorTests(IntFunction<int[]> fa, IntFunction<boolean[]> fm) { int[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Integer> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - VectorMask<Integer> mv = av.test(VectorOperators.IS_DEFAULT, vmask); + 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); + VectorMask<Integer> mv = av.test(VectorOperators.IS_DEFAULT, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_DEFAULT(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_DEFAULT(a[i + j])); + } } } } @@ -3477,19 +3569,21 @@ public class Int128VectorTests extends AbstractVectorTest { } @Test(dataProvider = "intTestOpMaskProvider") - static void IS_NEGATIVEMaskedInt128VectorTestsSmokeTest(IntFunction<int[]> fa, + static void IS_NEGATIVEMaskedInt128VectorTests(IntFunction<int[]> fa, IntFunction<boolean[]> fm) { int[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Integer> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - VectorMask<Integer> mv = av.test(VectorOperators.IS_NEGATIVE, vmask); + 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); + VectorMask<Integer> mv = av.test(VectorOperators.IS_NEGATIVE, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_NEGATIVE(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_NEGATIVE(a[i + j])); + } } } } @@ -5466,7 +5560,7 @@ public class Int128VectorTests extends AbstractVectorTest { static void maskFromToLongInt128VectorTestsSmokeTest(long inputLong) { var vmask = VectorMask.fromLong(SPECIES, inputLong); long outputLong = vmask.toLong(); - Assert.assertEquals(outputLong, inputLong & (((1L << (SPECIES.length() - 1)) << 1) - 1)); + Assert.assertEquals(outputLong, (inputLong & (((0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length())))))); } @DataProvider @@ -5568,5 +5662,12 @@ public class Int128VectorTests extends AbstractVectorTest { VectorSpecies species = av.species().withShape(vsh); assert(species.equals(SPECIES)); } + + @Test + static void MaskAllTrueInt128VectorTestsSmokeTest() { + for (int ic = 0; ic < INVOC_COUNT; ic++) { + Assert.assertEquals(SPECIES.maskAll(true).toLong(), -1L >>> (64 - SPECIES.length())); + } + } } diff --git a/test/jdk/jdk/incubator/vector/Int256VectorTests.java b/test/jdk/jdk/incubator/vector/Int256VectorTests.java index 9b1872f33d1e09a731afd5ce033e5095016147a4..597d5c6fdbbb28f707d54281995f29e36db4b70c 100644 --- a/test/jdk/jdk/incubator/vector/Int256VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Int256VectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -226,10 +226,10 @@ public class Int256VectorTests extends AbstractVectorTest { } } - static void assertInsertArraysEquals(int[] r, int[] a, int element, int index) { - int i = 0; + static void assertInsertArraysEquals(int[] r, int[] a, int element, int index, int start, int end) { + int i = start; try { - for (; i < a.length; i += 1) { + for (; i < end; i += 1) { if(i%SPECIES.length() == index) { Assert.assertEquals(r[i], element); } else { @@ -1161,6 +1161,10 @@ public class Int256VectorTests extends AbstractVectorTest { return Integer.compareUnsigned(a, b) >= 0; } + static int firstNonZero(int a, int b) { + return Integer.compare(a, (int) 0) != 0 ? a : b; + } + @Test static void smokeTest1() { IntVector three = IntVector.broadcast(SPECIES, (byte)-3); @@ -3181,7 +3185,7 @@ public class Int256VectorTests extends AbstractVectorTest { static int MINReduce(int[] a, int idx) { int res = Integer.MAX_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (int)Math.min(res, a[i]); + res = (int) Math.min(res, a[i]); } return res; @@ -3189,8 +3193,8 @@ public class Int256VectorTests extends AbstractVectorTest { static int MINReduceAll(int[] a) { int res = Integer.MAX_VALUE; - for (int i = 0; i < a.length; i++) { - res = (int)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (int) Math.min(res, MINReduce(a, i)); } return res; @@ -3212,7 +3216,7 @@ public class Int256VectorTests extends AbstractVectorTest { ra = Integer.MAX_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int)Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + ra = (int) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); } } @@ -3222,8 +3226,8 @@ public class Int256VectorTests extends AbstractVectorTest { static int MINReduceMasked(int[] a, int idx, boolean[] mask) { int res = Integer.MAX_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (int)Math.min(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (int) Math.min(res, a[i]); } return res; @@ -3231,9 +3235,8 @@ public class Int256VectorTests extends AbstractVectorTest { static int MINReduceAllMasked(int[] a, boolean[] mask) { int res = Integer.MAX_VALUE; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (int)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (int) Math.min(res, MINReduceMasked(a, i, mask)); } return res; @@ -3257,7 +3260,7 @@ public class Int256VectorTests extends AbstractVectorTest { ra = Integer.MAX_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int)Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + ra = (int) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); } } @@ -3267,7 +3270,7 @@ public class Int256VectorTests extends AbstractVectorTest { static int MAXReduce(int[] a, int idx) { int res = Integer.MIN_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (int)Math.max(res, a[i]); + res = (int) Math.max(res, a[i]); } return res; @@ -3275,8 +3278,8 @@ public class Int256VectorTests extends AbstractVectorTest { static int MAXReduceAll(int[] a) { int res = Integer.MIN_VALUE; - for (int i = 0; i < a.length; i++) { - res = (int)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (int) Math.max(res, MAXReduce(a, i)); } return res; @@ -3298,7 +3301,7 @@ public class Int256VectorTests extends AbstractVectorTest { ra = Integer.MIN_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int)Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + ra = (int) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); } } @@ -3308,8 +3311,8 @@ public class Int256VectorTests extends AbstractVectorTest { static int MAXReduceMasked(int[] a, int idx, boolean[] mask) { int res = Integer.MIN_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (int)Math.max(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (int) Math.max(res, a[i]); } return res; @@ -3317,9 +3320,8 @@ public class Int256VectorTests extends AbstractVectorTest { static int MAXReduceAllMasked(int[] a, boolean[] mask) { int res = Integer.MIN_VALUE; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (int)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (int) Math.max(res, MAXReduceMasked(a, i, mask)); } return res; @@ -3343,13 +3345,98 @@ public class Int256VectorTests extends AbstractVectorTest { ra = Integer.MIN_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int)Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + ra = (int) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); } } assertReductionArraysEqualsMasked(r, ra, a, mask, Int256VectorTests::MAXReduceMasked, Int256VectorTests::MAXReduceAllMasked); } + static int FIRST_NONZEROReduce(int[] a, int idx) { + int res = (int) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + res = firstNonZero(res, a[i]); + } + + return res; + } + + static int FIRST_NONZEROReduceAll(int[] a) { + int res = (int) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); + } + + return res; + } + @Test(dataProvider = "intUnaryOpProvider") + static void FIRST_NONZEROReduceInt256VectorTests(IntFunction<int[]> fa) { + int[] a = fa.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + int ra = (int) 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); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (int) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + } + } + + assertReductionArraysEquals(r, ra, a, + Int256VectorTests::FIRST_NONZEROReduce, Int256VectorTests::FIRST_NONZEROReduceAll); + } + static int FIRST_NONZEROReduceMasked(int[] a, int idx, boolean[] mask) { + int res = (int) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + if (mask[i % SPECIES.length()]) + res = firstNonZero(res, a[i]); + } + + return res; + } + + static int FIRST_NONZEROReduceAllMasked(int[] a, boolean[] mask) { + int res = (int) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); + } + + return res; + } + @Test(dataProvider = "intUnaryOpMaskProvider") + static void FIRST_NONZEROReduceInt256VectorTestsMasked(IntFunction<int[]> fa, IntFunction<boolean[]> fm) { + int[] a = fa.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask<Integer> vmask = VectorMask.fromArray(SPECIES, mask, 0); + int ra = (int) 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); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (int) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + } + } + + assertReductionArraysEqualsMasked(r, ra, a, mask, + Int256VectorTests::FIRST_NONZEROReduceMasked, Int256VectorTests::FIRST_NONZEROReduceAllMasked); + } static boolean anyTrue(boolean[] a, int idx) { boolean res = false; @@ -3409,13 +3496,16 @@ public class Int256VectorTests extends AbstractVectorTest { int[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { - for (int i = 0; i < a.length; i += SPECIES.length()) { + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - av.withLane(0, (int)4).intoArray(r, i); + av.withLane((j++ & (SPECIES.length()-1)), (int)(65535+i)).intoArray(r, i); } } - assertInsertArraysEquals(r, a, (int)4, 0); + + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { + assertInsertArraysEquals(r, a, (int)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); + } } static boolean testIS_DEFAULT(int a) { return bits(a)==0; @@ -3439,19 +3529,21 @@ public class Int256VectorTests extends AbstractVectorTest { } @Test(dataProvider = "intTestOpMaskProvider") - static void IS_DEFAULTMaskedInt256VectorTestsSmokeTest(IntFunction<int[]> fa, + static void IS_DEFAULTMaskedInt256VectorTests(IntFunction<int[]> fa, IntFunction<boolean[]> fm) { int[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Integer> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - VectorMask<Integer> mv = av.test(VectorOperators.IS_DEFAULT, vmask); + 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); + VectorMask<Integer> mv = av.test(VectorOperators.IS_DEFAULT, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_DEFAULT(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_DEFAULT(a[i + j])); + } } } } @@ -3477,19 +3569,21 @@ public class Int256VectorTests extends AbstractVectorTest { } @Test(dataProvider = "intTestOpMaskProvider") - static void IS_NEGATIVEMaskedInt256VectorTestsSmokeTest(IntFunction<int[]> fa, + static void IS_NEGATIVEMaskedInt256VectorTests(IntFunction<int[]> fa, IntFunction<boolean[]> fm) { int[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Integer> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - VectorMask<Integer> mv = av.test(VectorOperators.IS_NEGATIVE, vmask); + 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); + VectorMask<Integer> mv = av.test(VectorOperators.IS_NEGATIVE, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_NEGATIVE(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_NEGATIVE(a[i + j])); + } } } } @@ -5466,7 +5560,7 @@ public class Int256VectorTests extends AbstractVectorTest { static void maskFromToLongInt256VectorTestsSmokeTest(long inputLong) { var vmask = VectorMask.fromLong(SPECIES, inputLong); long outputLong = vmask.toLong(); - Assert.assertEquals(outputLong, inputLong & (((1L << (SPECIES.length() - 1)) << 1) - 1)); + Assert.assertEquals(outputLong, (inputLong & (((0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length())))))); } @DataProvider @@ -5568,5 +5662,12 @@ public class Int256VectorTests extends AbstractVectorTest { VectorSpecies species = av.species().withShape(vsh); assert(species.equals(SPECIES)); } + + @Test + static void MaskAllTrueInt256VectorTestsSmokeTest() { + for (int ic = 0; ic < INVOC_COUNT; ic++) { + Assert.assertEquals(SPECIES.maskAll(true).toLong(), -1L >>> (64 - SPECIES.length())); + } + } } diff --git a/test/jdk/jdk/incubator/vector/Int512VectorTests.java b/test/jdk/jdk/incubator/vector/Int512VectorTests.java index 52dcf43e31b5411a967be4c7d89c30fe6eb6e9e7..075450c6adb06b35d70c8e4252802811347d6ca8 100644 --- a/test/jdk/jdk/incubator/vector/Int512VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Int512VectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -226,10 +226,10 @@ public class Int512VectorTests extends AbstractVectorTest { } } - static void assertInsertArraysEquals(int[] r, int[] a, int element, int index) { - int i = 0; + static void assertInsertArraysEquals(int[] r, int[] a, int element, int index, int start, int end) { + int i = start; try { - for (; i < a.length; i += 1) { + for (; i < end; i += 1) { if(i%SPECIES.length() == index) { Assert.assertEquals(r[i], element); } else { @@ -1161,6 +1161,10 @@ public class Int512VectorTests extends AbstractVectorTest { return Integer.compareUnsigned(a, b) >= 0; } + static int firstNonZero(int a, int b) { + return Integer.compare(a, (int) 0) != 0 ? a : b; + } + @Test static void smokeTest1() { IntVector three = IntVector.broadcast(SPECIES, (byte)-3); @@ -3181,7 +3185,7 @@ public class Int512VectorTests extends AbstractVectorTest { static int MINReduce(int[] a, int idx) { int res = Integer.MAX_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (int)Math.min(res, a[i]); + res = (int) Math.min(res, a[i]); } return res; @@ -3189,8 +3193,8 @@ public class Int512VectorTests extends AbstractVectorTest { static int MINReduceAll(int[] a) { int res = Integer.MAX_VALUE; - for (int i = 0; i < a.length; i++) { - res = (int)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (int) Math.min(res, MINReduce(a, i)); } return res; @@ -3212,7 +3216,7 @@ public class Int512VectorTests extends AbstractVectorTest { ra = Integer.MAX_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int)Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + ra = (int) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); } } @@ -3222,8 +3226,8 @@ public class Int512VectorTests extends AbstractVectorTest { static int MINReduceMasked(int[] a, int idx, boolean[] mask) { int res = Integer.MAX_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (int)Math.min(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (int) Math.min(res, a[i]); } return res; @@ -3231,9 +3235,8 @@ public class Int512VectorTests extends AbstractVectorTest { static int MINReduceAllMasked(int[] a, boolean[] mask) { int res = Integer.MAX_VALUE; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (int)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (int) Math.min(res, MINReduceMasked(a, i, mask)); } return res; @@ -3257,7 +3260,7 @@ public class Int512VectorTests extends AbstractVectorTest { ra = Integer.MAX_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int)Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + ra = (int) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); } } @@ -3267,7 +3270,7 @@ public class Int512VectorTests extends AbstractVectorTest { static int MAXReduce(int[] a, int idx) { int res = Integer.MIN_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (int)Math.max(res, a[i]); + res = (int) Math.max(res, a[i]); } return res; @@ -3275,8 +3278,8 @@ public class Int512VectorTests extends AbstractVectorTest { static int MAXReduceAll(int[] a) { int res = Integer.MIN_VALUE; - for (int i = 0; i < a.length; i++) { - res = (int)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (int) Math.max(res, MAXReduce(a, i)); } return res; @@ -3298,7 +3301,7 @@ public class Int512VectorTests extends AbstractVectorTest { ra = Integer.MIN_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int)Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + ra = (int) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); } } @@ -3308,8 +3311,8 @@ public class Int512VectorTests extends AbstractVectorTest { static int MAXReduceMasked(int[] a, int idx, boolean[] mask) { int res = Integer.MIN_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (int)Math.max(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (int) Math.max(res, a[i]); } return res; @@ -3317,9 +3320,8 @@ public class Int512VectorTests extends AbstractVectorTest { static int MAXReduceAllMasked(int[] a, boolean[] mask) { int res = Integer.MIN_VALUE; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (int)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (int) Math.max(res, MAXReduceMasked(a, i, mask)); } return res; @@ -3343,13 +3345,98 @@ public class Int512VectorTests extends AbstractVectorTest { ra = Integer.MIN_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int)Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + ra = (int) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); } } assertReductionArraysEqualsMasked(r, ra, a, mask, Int512VectorTests::MAXReduceMasked, Int512VectorTests::MAXReduceAllMasked); } + static int FIRST_NONZEROReduce(int[] a, int idx) { + int res = (int) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + res = firstNonZero(res, a[i]); + } + + return res; + } + + static int FIRST_NONZEROReduceAll(int[] a) { + int res = (int) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); + } + + return res; + } + @Test(dataProvider = "intUnaryOpProvider") + static void FIRST_NONZEROReduceInt512VectorTests(IntFunction<int[]> fa) { + int[] a = fa.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + int ra = (int) 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); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (int) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + } + } + + assertReductionArraysEquals(r, ra, a, + Int512VectorTests::FIRST_NONZEROReduce, Int512VectorTests::FIRST_NONZEROReduceAll); + } + static int FIRST_NONZEROReduceMasked(int[] a, int idx, boolean[] mask) { + int res = (int) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + if (mask[i % SPECIES.length()]) + res = firstNonZero(res, a[i]); + } + + return res; + } + + static int FIRST_NONZEROReduceAllMasked(int[] a, boolean[] mask) { + int res = (int) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); + } + + return res; + } + @Test(dataProvider = "intUnaryOpMaskProvider") + static void FIRST_NONZEROReduceInt512VectorTestsMasked(IntFunction<int[]> fa, IntFunction<boolean[]> fm) { + int[] a = fa.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask<Integer> vmask = VectorMask.fromArray(SPECIES, mask, 0); + int ra = (int) 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); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (int) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + } + } + + assertReductionArraysEqualsMasked(r, ra, a, mask, + Int512VectorTests::FIRST_NONZEROReduceMasked, Int512VectorTests::FIRST_NONZEROReduceAllMasked); + } static boolean anyTrue(boolean[] a, int idx) { boolean res = false; @@ -3409,13 +3496,16 @@ public class Int512VectorTests extends AbstractVectorTest { int[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { - for (int i = 0; i < a.length; i += SPECIES.length()) { + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - av.withLane(0, (int)4).intoArray(r, i); + av.withLane((j++ & (SPECIES.length()-1)), (int)(65535+i)).intoArray(r, i); } } - assertInsertArraysEquals(r, a, (int)4, 0); + + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { + assertInsertArraysEquals(r, a, (int)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); + } } static boolean testIS_DEFAULT(int a) { return bits(a)==0; @@ -3439,19 +3529,21 @@ public class Int512VectorTests extends AbstractVectorTest { } @Test(dataProvider = "intTestOpMaskProvider") - static void IS_DEFAULTMaskedInt512VectorTestsSmokeTest(IntFunction<int[]> fa, + static void IS_DEFAULTMaskedInt512VectorTests(IntFunction<int[]> fa, IntFunction<boolean[]> fm) { int[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Integer> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - VectorMask<Integer> mv = av.test(VectorOperators.IS_DEFAULT, vmask); + 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); + VectorMask<Integer> mv = av.test(VectorOperators.IS_DEFAULT, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_DEFAULT(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_DEFAULT(a[i + j])); + } } } } @@ -3477,19 +3569,21 @@ public class Int512VectorTests extends AbstractVectorTest { } @Test(dataProvider = "intTestOpMaskProvider") - static void IS_NEGATIVEMaskedInt512VectorTestsSmokeTest(IntFunction<int[]> fa, + static void IS_NEGATIVEMaskedInt512VectorTests(IntFunction<int[]> fa, IntFunction<boolean[]> fm) { int[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Integer> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - VectorMask<Integer> mv = av.test(VectorOperators.IS_NEGATIVE, vmask); + 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); + VectorMask<Integer> mv = av.test(VectorOperators.IS_NEGATIVE, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_NEGATIVE(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_NEGATIVE(a[i + j])); + } } } } @@ -5466,7 +5560,7 @@ public class Int512VectorTests extends AbstractVectorTest { static void maskFromToLongInt512VectorTestsSmokeTest(long inputLong) { var vmask = VectorMask.fromLong(SPECIES, inputLong); long outputLong = vmask.toLong(); - Assert.assertEquals(outputLong, inputLong & (((1L << (SPECIES.length() - 1)) << 1) - 1)); + Assert.assertEquals(outputLong, (inputLong & (((0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length())))))); } @DataProvider @@ -5568,5 +5662,12 @@ public class Int512VectorTests extends AbstractVectorTest { VectorSpecies species = av.species().withShape(vsh); assert(species.equals(SPECIES)); } + + @Test + static void MaskAllTrueInt512VectorTestsSmokeTest() { + for (int ic = 0; ic < INVOC_COUNT; ic++) { + Assert.assertEquals(SPECIES.maskAll(true).toLong(), -1L >>> (64 - SPECIES.length())); + } + } } diff --git a/test/jdk/jdk/incubator/vector/Int64VectorTests.java b/test/jdk/jdk/incubator/vector/Int64VectorTests.java index 9d9fffcf246e8d29eaae382ce379c5ad3a10c86c..0d2346215d142e5eb2d734af17b8891d4ca8e0d4 100644 --- a/test/jdk/jdk/incubator/vector/Int64VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Int64VectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -226,10 +226,10 @@ public class Int64VectorTests extends AbstractVectorTest { } } - static void assertInsertArraysEquals(int[] r, int[] a, int element, int index) { - int i = 0; + static void assertInsertArraysEquals(int[] r, int[] a, int element, int index, int start, int end) { + int i = start; try { - for (; i < a.length; i += 1) { + for (; i < end; i += 1) { if(i%SPECIES.length() == index) { Assert.assertEquals(r[i], element); } else { @@ -1161,6 +1161,10 @@ public class Int64VectorTests extends AbstractVectorTest { return Integer.compareUnsigned(a, b) >= 0; } + static int firstNonZero(int a, int b) { + return Integer.compare(a, (int) 0) != 0 ? a : b; + } + @Test static void smokeTest1() { IntVector three = IntVector.broadcast(SPECIES, (byte)-3); @@ -3181,7 +3185,7 @@ public class Int64VectorTests extends AbstractVectorTest { static int MINReduce(int[] a, int idx) { int res = Integer.MAX_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (int)Math.min(res, a[i]); + res = (int) Math.min(res, a[i]); } return res; @@ -3189,8 +3193,8 @@ public class Int64VectorTests extends AbstractVectorTest { static int MINReduceAll(int[] a) { int res = Integer.MAX_VALUE; - for (int i = 0; i < a.length; i++) { - res = (int)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (int) Math.min(res, MINReduce(a, i)); } return res; @@ -3212,7 +3216,7 @@ public class Int64VectorTests extends AbstractVectorTest { ra = Integer.MAX_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int)Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + ra = (int) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); } } @@ -3222,8 +3226,8 @@ public class Int64VectorTests extends AbstractVectorTest { static int MINReduceMasked(int[] a, int idx, boolean[] mask) { int res = Integer.MAX_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (int)Math.min(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (int) Math.min(res, a[i]); } return res; @@ -3231,9 +3235,8 @@ public class Int64VectorTests extends AbstractVectorTest { static int MINReduceAllMasked(int[] a, boolean[] mask) { int res = Integer.MAX_VALUE; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (int)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (int) Math.min(res, MINReduceMasked(a, i, mask)); } return res; @@ -3257,7 +3260,7 @@ public class Int64VectorTests extends AbstractVectorTest { ra = Integer.MAX_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int)Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + ra = (int) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); } } @@ -3267,7 +3270,7 @@ public class Int64VectorTests extends AbstractVectorTest { static int MAXReduce(int[] a, int idx) { int res = Integer.MIN_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (int)Math.max(res, a[i]); + res = (int) Math.max(res, a[i]); } return res; @@ -3275,8 +3278,8 @@ public class Int64VectorTests extends AbstractVectorTest { static int MAXReduceAll(int[] a) { int res = Integer.MIN_VALUE; - for (int i = 0; i < a.length; i++) { - res = (int)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (int) Math.max(res, MAXReduce(a, i)); } return res; @@ -3298,7 +3301,7 @@ public class Int64VectorTests extends AbstractVectorTest { ra = Integer.MIN_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int)Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + ra = (int) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); } } @@ -3308,8 +3311,8 @@ public class Int64VectorTests extends AbstractVectorTest { static int MAXReduceMasked(int[] a, int idx, boolean[] mask) { int res = Integer.MIN_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (int)Math.max(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (int) Math.max(res, a[i]); } return res; @@ -3317,9 +3320,8 @@ public class Int64VectorTests extends AbstractVectorTest { static int MAXReduceAllMasked(int[] a, boolean[] mask) { int res = Integer.MIN_VALUE; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (int)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (int) Math.max(res, MAXReduceMasked(a, i, mask)); } return res; @@ -3343,13 +3345,98 @@ public class Int64VectorTests extends AbstractVectorTest { ra = Integer.MIN_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int)Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + ra = (int) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); } } assertReductionArraysEqualsMasked(r, ra, a, mask, Int64VectorTests::MAXReduceMasked, Int64VectorTests::MAXReduceAllMasked); } + static int FIRST_NONZEROReduce(int[] a, int idx) { + int res = (int) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + res = firstNonZero(res, a[i]); + } + + return res; + } + + static int FIRST_NONZEROReduceAll(int[] a) { + int res = (int) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); + } + + return res; + } + @Test(dataProvider = "intUnaryOpProvider") + static void FIRST_NONZEROReduceInt64VectorTests(IntFunction<int[]> fa) { + int[] a = fa.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + int ra = (int) 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); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (int) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + } + } + + assertReductionArraysEquals(r, ra, a, + Int64VectorTests::FIRST_NONZEROReduce, Int64VectorTests::FIRST_NONZEROReduceAll); + } + static int FIRST_NONZEROReduceMasked(int[] a, int idx, boolean[] mask) { + int res = (int) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + if (mask[i % SPECIES.length()]) + res = firstNonZero(res, a[i]); + } + + return res; + } + + static int FIRST_NONZEROReduceAllMasked(int[] a, boolean[] mask) { + int res = (int) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); + } + + return res; + } + @Test(dataProvider = "intUnaryOpMaskProvider") + static void FIRST_NONZEROReduceInt64VectorTestsMasked(IntFunction<int[]> fa, IntFunction<boolean[]> fm) { + int[] a = fa.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask<Integer> vmask = VectorMask.fromArray(SPECIES, mask, 0); + int ra = (int) 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); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (int) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + } + } + + assertReductionArraysEqualsMasked(r, ra, a, mask, + Int64VectorTests::FIRST_NONZEROReduceMasked, Int64VectorTests::FIRST_NONZEROReduceAllMasked); + } static boolean anyTrue(boolean[] a, int idx) { boolean res = false; @@ -3409,13 +3496,16 @@ public class Int64VectorTests extends AbstractVectorTest { int[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { - for (int i = 0; i < a.length; i += SPECIES.length()) { + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - av.withLane(0, (int)4).intoArray(r, i); + av.withLane((j++ & (SPECIES.length()-1)), (int)(65535+i)).intoArray(r, i); } } - assertInsertArraysEquals(r, a, (int)4, 0); + + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { + assertInsertArraysEquals(r, a, (int)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); + } } static boolean testIS_DEFAULT(int a) { return bits(a)==0; @@ -3439,19 +3529,21 @@ public class Int64VectorTests extends AbstractVectorTest { } @Test(dataProvider = "intTestOpMaskProvider") - static void IS_DEFAULTMaskedInt64VectorTestsSmokeTest(IntFunction<int[]> fa, + static void IS_DEFAULTMaskedInt64VectorTests(IntFunction<int[]> fa, IntFunction<boolean[]> fm) { int[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Integer> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - VectorMask<Integer> mv = av.test(VectorOperators.IS_DEFAULT, vmask); + 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); + VectorMask<Integer> mv = av.test(VectorOperators.IS_DEFAULT, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_DEFAULT(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_DEFAULT(a[i + j])); + } } } } @@ -3477,19 +3569,21 @@ public class Int64VectorTests extends AbstractVectorTest { } @Test(dataProvider = "intTestOpMaskProvider") - static void IS_NEGATIVEMaskedInt64VectorTestsSmokeTest(IntFunction<int[]> fa, + static void IS_NEGATIVEMaskedInt64VectorTests(IntFunction<int[]> fa, IntFunction<boolean[]> fm) { int[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Integer> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - VectorMask<Integer> mv = av.test(VectorOperators.IS_NEGATIVE, vmask); + 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); + VectorMask<Integer> mv = av.test(VectorOperators.IS_NEGATIVE, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_NEGATIVE(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_NEGATIVE(a[i + j])); + } } } } @@ -5466,7 +5560,7 @@ public class Int64VectorTests extends AbstractVectorTest { static void maskFromToLongInt64VectorTestsSmokeTest(long inputLong) { var vmask = VectorMask.fromLong(SPECIES, inputLong); long outputLong = vmask.toLong(); - Assert.assertEquals(outputLong, inputLong & (((1L << (SPECIES.length() - 1)) << 1) - 1)); + Assert.assertEquals(outputLong, (inputLong & (((0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length())))))); } @DataProvider @@ -5568,5 +5662,12 @@ public class Int64VectorTests extends AbstractVectorTest { VectorSpecies species = av.species().withShape(vsh); assert(species.equals(SPECIES)); } + + @Test + static void MaskAllTrueInt64VectorTestsSmokeTest() { + for (int ic = 0; ic < INVOC_COUNT; ic++) { + Assert.assertEquals(SPECIES.maskAll(true).toLong(), -1L >>> (64 - SPECIES.length())); + } + } } diff --git a/test/jdk/jdk/incubator/vector/IntMaxVectorTests.java b/test/jdk/jdk/incubator/vector/IntMaxVectorTests.java index d226226cac269527fca667b4d291c0542724c53b..eb735c101e77368fd900a829d43d7f7e6f6ae13e 100644 --- a/test/jdk/jdk/incubator/vector/IntMaxVectorTests.java +++ b/test/jdk/jdk/incubator/vector/IntMaxVectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -231,10 +231,10 @@ public class IntMaxVectorTests extends AbstractVectorTest { } } - static void assertInsertArraysEquals(int[] r, int[] a, int element, int index) { - int i = 0; + static void assertInsertArraysEquals(int[] r, int[] a, int element, int index, int start, int end) { + int i = start; try { - for (; i < a.length; i += 1) { + for (; i < end; i += 1) { if(i%SPECIES.length() == index) { Assert.assertEquals(r[i], element); } else { @@ -1166,6 +1166,10 @@ public class IntMaxVectorTests extends AbstractVectorTest { return Integer.compareUnsigned(a, b) >= 0; } + static int firstNonZero(int a, int b) { + return Integer.compare(a, (int) 0) != 0 ? a : b; + } + @Test static void smokeTest1() { IntVector three = IntVector.broadcast(SPECIES, (byte)-3); @@ -3186,7 +3190,7 @@ public class IntMaxVectorTests extends AbstractVectorTest { static int MINReduce(int[] a, int idx) { int res = Integer.MAX_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (int)Math.min(res, a[i]); + res = (int) Math.min(res, a[i]); } return res; @@ -3194,8 +3198,8 @@ public class IntMaxVectorTests extends AbstractVectorTest { static int MINReduceAll(int[] a) { int res = Integer.MAX_VALUE; - for (int i = 0; i < a.length; i++) { - res = (int)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (int) Math.min(res, MINReduce(a, i)); } return res; @@ -3217,7 +3221,7 @@ public class IntMaxVectorTests extends AbstractVectorTest { ra = Integer.MAX_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int)Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + ra = (int) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); } } @@ -3227,8 +3231,8 @@ public class IntMaxVectorTests extends AbstractVectorTest { static int MINReduceMasked(int[] a, int idx, boolean[] mask) { int res = Integer.MAX_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (int)Math.min(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (int) Math.min(res, a[i]); } return res; @@ -3236,9 +3240,8 @@ public class IntMaxVectorTests extends AbstractVectorTest { static int MINReduceAllMasked(int[] a, boolean[] mask) { int res = Integer.MAX_VALUE; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (int)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (int) Math.min(res, MINReduceMasked(a, i, mask)); } return res; @@ -3262,7 +3265,7 @@ public class IntMaxVectorTests extends AbstractVectorTest { ra = Integer.MAX_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int)Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + ra = (int) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); } } @@ -3272,7 +3275,7 @@ public class IntMaxVectorTests extends AbstractVectorTest { static int MAXReduce(int[] a, int idx) { int res = Integer.MIN_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (int)Math.max(res, a[i]); + res = (int) Math.max(res, a[i]); } return res; @@ -3280,8 +3283,8 @@ public class IntMaxVectorTests extends AbstractVectorTest { static int MAXReduceAll(int[] a) { int res = Integer.MIN_VALUE; - for (int i = 0; i < a.length; i++) { - res = (int)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (int) Math.max(res, MAXReduce(a, i)); } return res; @@ -3303,7 +3306,7 @@ public class IntMaxVectorTests extends AbstractVectorTest { ra = Integer.MIN_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int)Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + ra = (int) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); } } @@ -3313,8 +3316,8 @@ public class IntMaxVectorTests extends AbstractVectorTest { static int MAXReduceMasked(int[] a, int idx, boolean[] mask) { int res = Integer.MIN_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (int)Math.max(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (int) Math.max(res, a[i]); } return res; @@ -3322,9 +3325,8 @@ public class IntMaxVectorTests extends AbstractVectorTest { static int MAXReduceAllMasked(int[] a, boolean[] mask) { int res = Integer.MIN_VALUE; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (int)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (int) Math.max(res, MAXReduceMasked(a, i, mask)); } return res; @@ -3348,13 +3350,98 @@ public class IntMaxVectorTests extends AbstractVectorTest { ra = Integer.MIN_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int)Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + ra = (int) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); } } assertReductionArraysEqualsMasked(r, ra, a, mask, IntMaxVectorTests::MAXReduceMasked, IntMaxVectorTests::MAXReduceAllMasked); } + static int FIRST_NONZEROReduce(int[] a, int idx) { + int res = (int) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + res = firstNonZero(res, a[i]); + } + + return res; + } + + static int FIRST_NONZEROReduceAll(int[] a) { + int res = (int) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); + } + + return res; + } + @Test(dataProvider = "intUnaryOpProvider") + static void FIRST_NONZEROReduceIntMaxVectorTests(IntFunction<int[]> fa) { + int[] a = fa.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + int ra = (int) 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); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (int) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + } + } + + assertReductionArraysEquals(r, ra, a, + IntMaxVectorTests::FIRST_NONZEROReduce, IntMaxVectorTests::FIRST_NONZEROReduceAll); + } + static int FIRST_NONZEROReduceMasked(int[] a, int idx, boolean[] mask) { + int res = (int) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + if (mask[i % SPECIES.length()]) + res = firstNonZero(res, a[i]); + } + + return res; + } + + static int FIRST_NONZEROReduceAllMasked(int[] a, boolean[] mask) { + int res = (int) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); + } + + return res; + } + @Test(dataProvider = "intUnaryOpMaskProvider") + static void FIRST_NONZEROReduceIntMaxVectorTestsMasked(IntFunction<int[]> fa, IntFunction<boolean[]> fm) { + int[] a = fa.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask<Integer> vmask = VectorMask.fromArray(SPECIES, mask, 0); + int ra = (int) 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); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (int) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + } + } + + assertReductionArraysEqualsMasked(r, ra, a, mask, + IntMaxVectorTests::FIRST_NONZEROReduceMasked, IntMaxVectorTests::FIRST_NONZEROReduceAllMasked); + } static boolean anyTrue(boolean[] a, int idx) { boolean res = false; @@ -3414,13 +3501,16 @@ public class IntMaxVectorTests extends AbstractVectorTest { int[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { - for (int i = 0; i < a.length; i += SPECIES.length()) { + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - av.withLane(0, (int)4).intoArray(r, i); + av.withLane((j++ & (SPECIES.length()-1)), (int)(65535+i)).intoArray(r, i); } } - assertInsertArraysEquals(r, a, (int)4, 0); + + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { + assertInsertArraysEquals(r, a, (int)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); + } } static boolean testIS_DEFAULT(int a) { return bits(a)==0; @@ -3444,19 +3534,21 @@ public class IntMaxVectorTests extends AbstractVectorTest { } @Test(dataProvider = "intTestOpMaskProvider") - static void IS_DEFAULTMaskedIntMaxVectorTestsSmokeTest(IntFunction<int[]> fa, + static void IS_DEFAULTMaskedIntMaxVectorTests(IntFunction<int[]> fa, IntFunction<boolean[]> fm) { int[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Integer> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - VectorMask<Integer> mv = av.test(VectorOperators.IS_DEFAULT, vmask); + 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); + VectorMask<Integer> mv = av.test(VectorOperators.IS_DEFAULT, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_DEFAULT(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_DEFAULT(a[i + j])); + } } } } @@ -3482,19 +3574,21 @@ public class IntMaxVectorTests extends AbstractVectorTest { } @Test(dataProvider = "intTestOpMaskProvider") - static void IS_NEGATIVEMaskedIntMaxVectorTestsSmokeTest(IntFunction<int[]> fa, + static void IS_NEGATIVEMaskedIntMaxVectorTests(IntFunction<int[]> fa, IntFunction<boolean[]> fm) { int[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Integer> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - VectorMask<Integer> mv = av.test(VectorOperators.IS_NEGATIVE, vmask); + 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); + VectorMask<Integer> mv = av.test(VectorOperators.IS_NEGATIVE, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_NEGATIVE(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_NEGATIVE(a[i + j])); + } } } } @@ -5557,5 +5651,12 @@ public class IntMaxVectorTests extends AbstractVectorTest { VectorSpecies species = av.species().withShape(vsh); assert(species.equals(SPECIES)); } + + @Test + static void MaskAllTrueIntMaxVectorTestsSmokeTest() { + for (int ic = 0; ic < INVOC_COUNT; ic++) { + Assert.assertEquals(SPECIES.maskAll(true).toLong(), -1L >>> (64 - SPECIES.length())); + } + } } diff --git a/test/jdk/jdk/incubator/vector/Long128VectorTests.java b/test/jdk/jdk/incubator/vector/Long128VectorTests.java index 03d163a8a4c607fc752e0d51cb23c774c9d84b9e..da8c3fc802219bfbf4292c2904533eeb68cb9054 100644 --- a/test/jdk/jdk/incubator/vector/Long128VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Long128VectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -183,10 +183,10 @@ public class Long128VectorTests extends AbstractVectorTest { } } - static void assertInsertArraysEquals(long[] r, long[] a, long element, int index) { - int i = 0; + static void assertInsertArraysEquals(long[] r, long[] a, long element, int index, int start, int end) { + int i = start; try { - for (; i < a.length; i += 1) { + for (; i < end; i += 1) { if(i%SPECIES.length() == index) { Assert.assertEquals(r[i], element); } else { @@ -1183,6 +1183,10 @@ public class Long128VectorTests extends AbstractVectorTest { return Long.compareUnsigned(a, b) >= 0; } + static long firstNonZero(long a, long b) { + return Long.compare(a, (long) 0) != 0 ? a : b; + } + @Test static void smokeTest1() { LongVector three = LongVector.broadcast(SPECIES, (byte)-3); @@ -3203,7 +3207,7 @@ public class Long128VectorTests extends AbstractVectorTest { static long MINReduce(long[] a, int idx) { long res = Long.MAX_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (long)Math.min(res, a[i]); + res = (long) Math.min(res, a[i]); } return res; @@ -3211,8 +3215,8 @@ public class Long128VectorTests extends AbstractVectorTest { static long MINReduceAll(long[] a) { long res = Long.MAX_VALUE; - for (int i = 0; i < a.length; i++) { - res = (long)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (long) Math.min(res, MINReduce(a, i)); } return res; @@ -3234,7 +3238,7 @@ public class Long128VectorTests extends AbstractVectorTest { ra = Long.MAX_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long)Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + ra = (long) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); } } @@ -3244,8 +3248,8 @@ public class Long128VectorTests extends AbstractVectorTest { static long MINReduceMasked(long[] a, int idx, boolean[] mask) { long res = Long.MAX_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (long)Math.min(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (long) Math.min(res, a[i]); } return res; @@ -3253,9 +3257,8 @@ public class Long128VectorTests extends AbstractVectorTest { static long MINReduceAllMasked(long[] a, boolean[] mask) { long res = Long.MAX_VALUE; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (long)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (long) Math.min(res, MINReduceMasked(a, i, mask)); } return res; @@ -3279,7 +3282,7 @@ public class Long128VectorTests extends AbstractVectorTest { ra = Long.MAX_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long)Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + ra = (long) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); } } @@ -3289,7 +3292,7 @@ public class Long128VectorTests extends AbstractVectorTest { static long MAXReduce(long[] a, int idx) { long res = Long.MIN_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (long)Math.max(res, a[i]); + res = (long) Math.max(res, a[i]); } return res; @@ -3297,8 +3300,8 @@ public class Long128VectorTests extends AbstractVectorTest { static long MAXReduceAll(long[] a) { long res = Long.MIN_VALUE; - for (int i = 0; i < a.length; i++) { - res = (long)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (long) Math.max(res, MAXReduce(a, i)); } return res; @@ -3320,7 +3323,7 @@ public class Long128VectorTests extends AbstractVectorTest { ra = Long.MIN_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long)Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + ra = (long) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); } } @@ -3330,8 +3333,8 @@ public class Long128VectorTests extends AbstractVectorTest { static long MAXReduceMasked(long[] a, int idx, boolean[] mask) { long res = Long.MIN_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (long)Math.max(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (long) Math.max(res, a[i]); } return res; @@ -3339,9 +3342,8 @@ public class Long128VectorTests extends AbstractVectorTest { static long MAXReduceAllMasked(long[] a, boolean[] mask) { long res = Long.MIN_VALUE; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (long)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (long) Math.max(res, MAXReduceMasked(a, i, mask)); } return res; @@ -3365,13 +3367,98 @@ public class Long128VectorTests extends AbstractVectorTest { ra = Long.MIN_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long)Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + ra = (long) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); } } assertReductionArraysEqualsMasked(r, ra, a, mask, Long128VectorTests::MAXReduceMasked, Long128VectorTests::MAXReduceAllMasked); } + static long FIRST_NONZEROReduce(long[] a, int idx) { + long res = (long) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + res = firstNonZero(res, a[i]); + } + + return res; + } + + static long FIRST_NONZEROReduceAll(long[] a) { + long res = (long) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); + } + + return res; + } + @Test(dataProvider = "longUnaryOpProvider") + static void FIRST_NONZEROReduceLong128VectorTests(IntFunction<long[]> fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + long ra = (long) 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); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (long) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + } + } + + assertReductionArraysEquals(r, ra, a, + Long128VectorTests::FIRST_NONZEROReduce, Long128VectorTests::FIRST_NONZEROReduceAll); + } + static long FIRST_NONZEROReduceMasked(long[] a, int idx, boolean[] mask) { + long res = (long) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + if (mask[i % SPECIES.length()]) + res = firstNonZero(res, a[i]); + } + + return res; + } + + static long FIRST_NONZEROReduceAllMasked(long[] a, boolean[] mask) { + long res = (long) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); + } + + return res; + } + @Test(dataProvider = "longUnaryOpMaskProvider") + static void FIRST_NONZEROReduceLong128VectorTestsMasked(IntFunction<long[]> fa, IntFunction<boolean[]> fm) { + long[] a = fa.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask<Long> vmask = VectorMask.fromArray(SPECIES, mask, 0); + long ra = (long) 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); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (long) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + } + } + + assertReductionArraysEqualsMasked(r, ra, a, mask, + Long128VectorTests::FIRST_NONZEROReduceMasked, Long128VectorTests::FIRST_NONZEROReduceAllMasked); + } static boolean anyTrue(boolean[] a, int idx) { boolean res = false; @@ -3431,13 +3518,16 @@ public class Long128VectorTests extends AbstractVectorTest { long[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { - for (int i = 0; i < a.length; i += SPECIES.length()) { + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - av.withLane(0, (long)4).intoArray(r, i); + av.withLane((j++ & (SPECIES.length()-1)), (long)(65535+i)).intoArray(r, i); } } - assertInsertArraysEquals(r, a, (long)4, 0); + + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { + assertInsertArraysEquals(r, a, (long)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); + } } static boolean testIS_DEFAULT(long a) { return bits(a)==0; @@ -3461,19 +3551,21 @@ public class Long128VectorTests extends AbstractVectorTest { } @Test(dataProvider = "longTestOpMaskProvider") - static void IS_DEFAULTMaskedLong128VectorTestsSmokeTest(IntFunction<long[]> fa, + static void IS_DEFAULTMaskedLong128VectorTests(IntFunction<long[]> fa, IntFunction<boolean[]> fm) { long[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Long> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - VectorMask<Long> mv = av.test(VectorOperators.IS_DEFAULT, vmask); + 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); + VectorMask<Long> mv = av.test(VectorOperators.IS_DEFAULT, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_DEFAULT(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_DEFAULT(a[i + j])); + } } } } @@ -3499,19 +3591,21 @@ public class Long128VectorTests extends AbstractVectorTest { } @Test(dataProvider = "longTestOpMaskProvider") - static void IS_NEGATIVEMaskedLong128VectorTestsSmokeTest(IntFunction<long[]> fa, + static void IS_NEGATIVEMaskedLong128VectorTests(IntFunction<long[]> fa, IntFunction<boolean[]> fm) { long[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Long> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - VectorMask<Long> mv = av.test(VectorOperators.IS_NEGATIVE, vmask); + 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); + VectorMask<Long> mv = av.test(VectorOperators.IS_NEGATIVE, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_NEGATIVE(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_NEGATIVE(a[i + j])); + } } } } @@ -5350,7 +5444,7 @@ public class Long128VectorTests extends AbstractVectorTest { static void maskFromToLongLong128VectorTestsSmokeTest(long inputLong) { var vmask = VectorMask.fromLong(SPECIES, inputLong); long outputLong = vmask.toLong(); - Assert.assertEquals(outputLong, inputLong & (((1L << (SPECIES.length() - 1)) << 1) - 1)); + Assert.assertEquals(outputLong, (inputLong & (((0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length())))))); } @DataProvider @@ -5452,5 +5546,12 @@ public class Long128VectorTests extends AbstractVectorTest { VectorSpecies species = av.species().withShape(vsh); assert(species.equals(SPECIES)); } + + @Test + static void MaskAllTrueLong128VectorTestsSmokeTest() { + for (int ic = 0; ic < INVOC_COUNT; ic++) { + Assert.assertEquals(SPECIES.maskAll(true).toLong(), -1L >>> (64 - SPECIES.length())); + } + } } diff --git a/test/jdk/jdk/incubator/vector/Long256VectorTests.java b/test/jdk/jdk/incubator/vector/Long256VectorTests.java index 91a41519bb43610d527da5b8b6bdf802be6e16d6..6e291fc3c100ba8e85df7e26b072afd9b438696a 100644 --- a/test/jdk/jdk/incubator/vector/Long256VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Long256VectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -183,10 +183,10 @@ public class Long256VectorTests extends AbstractVectorTest { } } - static void assertInsertArraysEquals(long[] r, long[] a, long element, int index) { - int i = 0; + static void assertInsertArraysEquals(long[] r, long[] a, long element, int index, int start, int end) { + int i = start; try { - for (; i < a.length; i += 1) { + for (; i < end; i += 1) { if(i%SPECIES.length() == index) { Assert.assertEquals(r[i], element); } else { @@ -1183,6 +1183,10 @@ public class Long256VectorTests extends AbstractVectorTest { return Long.compareUnsigned(a, b) >= 0; } + static long firstNonZero(long a, long b) { + return Long.compare(a, (long) 0) != 0 ? a : b; + } + @Test static void smokeTest1() { LongVector three = LongVector.broadcast(SPECIES, (byte)-3); @@ -3203,7 +3207,7 @@ public class Long256VectorTests extends AbstractVectorTest { static long MINReduce(long[] a, int idx) { long res = Long.MAX_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (long)Math.min(res, a[i]); + res = (long) Math.min(res, a[i]); } return res; @@ -3211,8 +3215,8 @@ public class Long256VectorTests extends AbstractVectorTest { static long MINReduceAll(long[] a) { long res = Long.MAX_VALUE; - for (int i = 0; i < a.length; i++) { - res = (long)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (long) Math.min(res, MINReduce(a, i)); } return res; @@ -3234,7 +3238,7 @@ public class Long256VectorTests extends AbstractVectorTest { ra = Long.MAX_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long)Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + ra = (long) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); } } @@ -3244,8 +3248,8 @@ public class Long256VectorTests extends AbstractVectorTest { static long MINReduceMasked(long[] a, int idx, boolean[] mask) { long res = Long.MAX_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (long)Math.min(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (long) Math.min(res, a[i]); } return res; @@ -3253,9 +3257,8 @@ public class Long256VectorTests extends AbstractVectorTest { static long MINReduceAllMasked(long[] a, boolean[] mask) { long res = Long.MAX_VALUE; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (long)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (long) Math.min(res, MINReduceMasked(a, i, mask)); } return res; @@ -3279,7 +3282,7 @@ public class Long256VectorTests extends AbstractVectorTest { ra = Long.MAX_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long)Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + ra = (long) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); } } @@ -3289,7 +3292,7 @@ public class Long256VectorTests extends AbstractVectorTest { static long MAXReduce(long[] a, int idx) { long res = Long.MIN_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (long)Math.max(res, a[i]); + res = (long) Math.max(res, a[i]); } return res; @@ -3297,8 +3300,8 @@ public class Long256VectorTests extends AbstractVectorTest { static long MAXReduceAll(long[] a) { long res = Long.MIN_VALUE; - for (int i = 0; i < a.length; i++) { - res = (long)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (long) Math.max(res, MAXReduce(a, i)); } return res; @@ -3320,7 +3323,7 @@ public class Long256VectorTests extends AbstractVectorTest { ra = Long.MIN_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long)Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + ra = (long) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); } } @@ -3330,8 +3333,8 @@ public class Long256VectorTests extends AbstractVectorTest { static long MAXReduceMasked(long[] a, int idx, boolean[] mask) { long res = Long.MIN_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (long)Math.max(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (long) Math.max(res, a[i]); } return res; @@ -3339,9 +3342,8 @@ public class Long256VectorTests extends AbstractVectorTest { static long MAXReduceAllMasked(long[] a, boolean[] mask) { long res = Long.MIN_VALUE; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (long)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (long) Math.max(res, MAXReduceMasked(a, i, mask)); } return res; @@ -3365,13 +3367,98 @@ public class Long256VectorTests extends AbstractVectorTest { ra = Long.MIN_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long)Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + ra = (long) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); } } assertReductionArraysEqualsMasked(r, ra, a, mask, Long256VectorTests::MAXReduceMasked, Long256VectorTests::MAXReduceAllMasked); } + static long FIRST_NONZEROReduce(long[] a, int idx) { + long res = (long) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + res = firstNonZero(res, a[i]); + } + + return res; + } + + static long FIRST_NONZEROReduceAll(long[] a) { + long res = (long) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); + } + + return res; + } + @Test(dataProvider = "longUnaryOpProvider") + static void FIRST_NONZEROReduceLong256VectorTests(IntFunction<long[]> fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + long ra = (long) 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); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (long) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + } + } + + assertReductionArraysEquals(r, ra, a, + Long256VectorTests::FIRST_NONZEROReduce, Long256VectorTests::FIRST_NONZEROReduceAll); + } + static long FIRST_NONZEROReduceMasked(long[] a, int idx, boolean[] mask) { + long res = (long) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + if (mask[i % SPECIES.length()]) + res = firstNonZero(res, a[i]); + } + + return res; + } + + static long FIRST_NONZEROReduceAllMasked(long[] a, boolean[] mask) { + long res = (long) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); + } + + return res; + } + @Test(dataProvider = "longUnaryOpMaskProvider") + static void FIRST_NONZEROReduceLong256VectorTestsMasked(IntFunction<long[]> fa, IntFunction<boolean[]> fm) { + long[] a = fa.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask<Long> vmask = VectorMask.fromArray(SPECIES, mask, 0); + long ra = (long) 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); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (long) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + } + } + + assertReductionArraysEqualsMasked(r, ra, a, mask, + Long256VectorTests::FIRST_NONZEROReduceMasked, Long256VectorTests::FIRST_NONZEROReduceAllMasked); + } static boolean anyTrue(boolean[] a, int idx) { boolean res = false; @@ -3431,13 +3518,16 @@ public class Long256VectorTests extends AbstractVectorTest { long[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { - for (int i = 0; i < a.length; i += SPECIES.length()) { + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - av.withLane(0, (long)4).intoArray(r, i); + av.withLane((j++ & (SPECIES.length()-1)), (long)(65535+i)).intoArray(r, i); } } - assertInsertArraysEquals(r, a, (long)4, 0); + + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { + assertInsertArraysEquals(r, a, (long)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); + } } static boolean testIS_DEFAULT(long a) { return bits(a)==0; @@ -3461,19 +3551,21 @@ public class Long256VectorTests extends AbstractVectorTest { } @Test(dataProvider = "longTestOpMaskProvider") - static void IS_DEFAULTMaskedLong256VectorTestsSmokeTest(IntFunction<long[]> fa, + static void IS_DEFAULTMaskedLong256VectorTests(IntFunction<long[]> fa, IntFunction<boolean[]> fm) { long[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Long> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - VectorMask<Long> mv = av.test(VectorOperators.IS_DEFAULT, vmask); + 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); + VectorMask<Long> mv = av.test(VectorOperators.IS_DEFAULT, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_DEFAULT(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_DEFAULT(a[i + j])); + } } } } @@ -3499,19 +3591,21 @@ public class Long256VectorTests extends AbstractVectorTest { } @Test(dataProvider = "longTestOpMaskProvider") - static void IS_NEGATIVEMaskedLong256VectorTestsSmokeTest(IntFunction<long[]> fa, + static void IS_NEGATIVEMaskedLong256VectorTests(IntFunction<long[]> fa, IntFunction<boolean[]> fm) { long[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Long> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - VectorMask<Long> mv = av.test(VectorOperators.IS_NEGATIVE, vmask); + 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); + VectorMask<Long> mv = av.test(VectorOperators.IS_NEGATIVE, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_NEGATIVE(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_NEGATIVE(a[i + j])); + } } } } @@ -5350,7 +5444,7 @@ public class Long256VectorTests extends AbstractVectorTest { static void maskFromToLongLong256VectorTestsSmokeTest(long inputLong) { var vmask = VectorMask.fromLong(SPECIES, inputLong); long outputLong = vmask.toLong(); - Assert.assertEquals(outputLong, inputLong & (((1L << (SPECIES.length() - 1)) << 1) - 1)); + Assert.assertEquals(outputLong, (inputLong & (((0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length())))))); } @DataProvider @@ -5452,5 +5546,12 @@ public class Long256VectorTests extends AbstractVectorTest { VectorSpecies species = av.species().withShape(vsh); assert(species.equals(SPECIES)); } + + @Test + static void MaskAllTrueLong256VectorTestsSmokeTest() { + for (int ic = 0; ic < INVOC_COUNT; ic++) { + Assert.assertEquals(SPECIES.maskAll(true).toLong(), -1L >>> (64 - SPECIES.length())); + } + } } diff --git a/test/jdk/jdk/incubator/vector/Long512VectorTests.java b/test/jdk/jdk/incubator/vector/Long512VectorTests.java index 53fa4592fc64baac7da7628fd71f57a4e6a14545..8b0e64d5ae4fa8789076bd40aacf6691563e952f 100644 --- a/test/jdk/jdk/incubator/vector/Long512VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Long512VectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -183,10 +183,10 @@ public class Long512VectorTests extends AbstractVectorTest { } } - static void assertInsertArraysEquals(long[] r, long[] a, long element, int index) { - int i = 0; + static void assertInsertArraysEquals(long[] r, long[] a, long element, int index, int start, int end) { + int i = start; try { - for (; i < a.length; i += 1) { + for (; i < end; i += 1) { if(i%SPECIES.length() == index) { Assert.assertEquals(r[i], element); } else { @@ -1183,6 +1183,10 @@ public class Long512VectorTests extends AbstractVectorTest { return Long.compareUnsigned(a, b) >= 0; } + static long firstNonZero(long a, long b) { + return Long.compare(a, (long) 0) != 0 ? a : b; + } + @Test static void smokeTest1() { LongVector three = LongVector.broadcast(SPECIES, (byte)-3); @@ -3203,7 +3207,7 @@ public class Long512VectorTests extends AbstractVectorTest { static long MINReduce(long[] a, int idx) { long res = Long.MAX_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (long)Math.min(res, a[i]); + res = (long) Math.min(res, a[i]); } return res; @@ -3211,8 +3215,8 @@ public class Long512VectorTests extends AbstractVectorTest { static long MINReduceAll(long[] a) { long res = Long.MAX_VALUE; - for (int i = 0; i < a.length; i++) { - res = (long)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (long) Math.min(res, MINReduce(a, i)); } return res; @@ -3234,7 +3238,7 @@ public class Long512VectorTests extends AbstractVectorTest { ra = Long.MAX_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long)Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + ra = (long) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); } } @@ -3244,8 +3248,8 @@ public class Long512VectorTests extends AbstractVectorTest { static long MINReduceMasked(long[] a, int idx, boolean[] mask) { long res = Long.MAX_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (long)Math.min(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (long) Math.min(res, a[i]); } return res; @@ -3253,9 +3257,8 @@ public class Long512VectorTests extends AbstractVectorTest { static long MINReduceAllMasked(long[] a, boolean[] mask) { long res = Long.MAX_VALUE; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (long)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (long) Math.min(res, MINReduceMasked(a, i, mask)); } return res; @@ -3279,7 +3282,7 @@ public class Long512VectorTests extends AbstractVectorTest { ra = Long.MAX_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long)Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + ra = (long) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); } } @@ -3289,7 +3292,7 @@ public class Long512VectorTests extends AbstractVectorTest { static long MAXReduce(long[] a, int idx) { long res = Long.MIN_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (long)Math.max(res, a[i]); + res = (long) Math.max(res, a[i]); } return res; @@ -3297,8 +3300,8 @@ public class Long512VectorTests extends AbstractVectorTest { static long MAXReduceAll(long[] a) { long res = Long.MIN_VALUE; - for (int i = 0; i < a.length; i++) { - res = (long)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (long) Math.max(res, MAXReduce(a, i)); } return res; @@ -3320,7 +3323,7 @@ public class Long512VectorTests extends AbstractVectorTest { ra = Long.MIN_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long)Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + ra = (long) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); } } @@ -3330,8 +3333,8 @@ public class Long512VectorTests extends AbstractVectorTest { static long MAXReduceMasked(long[] a, int idx, boolean[] mask) { long res = Long.MIN_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (long)Math.max(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (long) Math.max(res, a[i]); } return res; @@ -3339,9 +3342,8 @@ public class Long512VectorTests extends AbstractVectorTest { static long MAXReduceAllMasked(long[] a, boolean[] mask) { long res = Long.MIN_VALUE; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (long)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (long) Math.max(res, MAXReduceMasked(a, i, mask)); } return res; @@ -3365,13 +3367,98 @@ public class Long512VectorTests extends AbstractVectorTest { ra = Long.MIN_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long)Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + ra = (long) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); } } assertReductionArraysEqualsMasked(r, ra, a, mask, Long512VectorTests::MAXReduceMasked, Long512VectorTests::MAXReduceAllMasked); } + static long FIRST_NONZEROReduce(long[] a, int idx) { + long res = (long) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + res = firstNonZero(res, a[i]); + } + + return res; + } + + static long FIRST_NONZEROReduceAll(long[] a) { + long res = (long) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); + } + + return res; + } + @Test(dataProvider = "longUnaryOpProvider") + static void FIRST_NONZEROReduceLong512VectorTests(IntFunction<long[]> fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + long ra = (long) 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); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (long) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + } + } + + assertReductionArraysEquals(r, ra, a, + Long512VectorTests::FIRST_NONZEROReduce, Long512VectorTests::FIRST_NONZEROReduceAll); + } + static long FIRST_NONZEROReduceMasked(long[] a, int idx, boolean[] mask) { + long res = (long) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + if (mask[i % SPECIES.length()]) + res = firstNonZero(res, a[i]); + } + + return res; + } + + static long FIRST_NONZEROReduceAllMasked(long[] a, boolean[] mask) { + long res = (long) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); + } + + return res; + } + @Test(dataProvider = "longUnaryOpMaskProvider") + static void FIRST_NONZEROReduceLong512VectorTestsMasked(IntFunction<long[]> fa, IntFunction<boolean[]> fm) { + long[] a = fa.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask<Long> vmask = VectorMask.fromArray(SPECIES, mask, 0); + long ra = (long) 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); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (long) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + } + } + + assertReductionArraysEqualsMasked(r, ra, a, mask, + Long512VectorTests::FIRST_NONZEROReduceMasked, Long512VectorTests::FIRST_NONZEROReduceAllMasked); + } static boolean anyTrue(boolean[] a, int idx) { boolean res = false; @@ -3431,13 +3518,16 @@ public class Long512VectorTests extends AbstractVectorTest { long[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { - for (int i = 0; i < a.length; i += SPECIES.length()) { + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - av.withLane(0, (long)4).intoArray(r, i); + av.withLane((j++ & (SPECIES.length()-1)), (long)(65535+i)).intoArray(r, i); } } - assertInsertArraysEquals(r, a, (long)4, 0); + + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { + assertInsertArraysEquals(r, a, (long)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); + } } static boolean testIS_DEFAULT(long a) { return bits(a)==0; @@ -3461,19 +3551,21 @@ public class Long512VectorTests extends AbstractVectorTest { } @Test(dataProvider = "longTestOpMaskProvider") - static void IS_DEFAULTMaskedLong512VectorTestsSmokeTest(IntFunction<long[]> fa, + static void IS_DEFAULTMaskedLong512VectorTests(IntFunction<long[]> fa, IntFunction<boolean[]> fm) { long[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Long> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - VectorMask<Long> mv = av.test(VectorOperators.IS_DEFAULT, vmask); + 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); + VectorMask<Long> mv = av.test(VectorOperators.IS_DEFAULT, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_DEFAULT(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_DEFAULT(a[i + j])); + } } } } @@ -3499,19 +3591,21 @@ public class Long512VectorTests extends AbstractVectorTest { } @Test(dataProvider = "longTestOpMaskProvider") - static void IS_NEGATIVEMaskedLong512VectorTestsSmokeTest(IntFunction<long[]> fa, + static void IS_NEGATIVEMaskedLong512VectorTests(IntFunction<long[]> fa, IntFunction<boolean[]> fm) { long[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Long> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - VectorMask<Long> mv = av.test(VectorOperators.IS_NEGATIVE, vmask); + 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); + VectorMask<Long> mv = av.test(VectorOperators.IS_NEGATIVE, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_NEGATIVE(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_NEGATIVE(a[i + j])); + } } } } @@ -5350,7 +5444,7 @@ public class Long512VectorTests extends AbstractVectorTest { static void maskFromToLongLong512VectorTestsSmokeTest(long inputLong) { var vmask = VectorMask.fromLong(SPECIES, inputLong); long outputLong = vmask.toLong(); - Assert.assertEquals(outputLong, inputLong & (((1L << (SPECIES.length() - 1)) << 1) - 1)); + Assert.assertEquals(outputLong, (inputLong & (((0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length())))))); } @DataProvider @@ -5452,5 +5546,12 @@ public class Long512VectorTests extends AbstractVectorTest { VectorSpecies species = av.species().withShape(vsh); assert(species.equals(SPECIES)); } + + @Test + static void MaskAllTrueLong512VectorTestsSmokeTest() { + for (int ic = 0; ic < INVOC_COUNT; ic++) { + Assert.assertEquals(SPECIES.maskAll(true).toLong(), -1L >>> (64 - SPECIES.length())); + } + } } diff --git a/test/jdk/jdk/incubator/vector/Long64VectorTests.java b/test/jdk/jdk/incubator/vector/Long64VectorTests.java index c8f9c31e4994e537091dbd7042f8abed9a398fee..f3134e72b21ededb385908052774779a470cb05c 100644 --- a/test/jdk/jdk/incubator/vector/Long64VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Long64VectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -183,10 +183,10 @@ public class Long64VectorTests extends AbstractVectorTest { } } - static void assertInsertArraysEquals(long[] r, long[] a, long element, int index) { - int i = 0; + static void assertInsertArraysEquals(long[] r, long[] a, long element, int index, int start, int end) { + int i = start; try { - for (; i < a.length; i += 1) { + for (; i < end; i += 1) { if(i%SPECIES.length() == index) { Assert.assertEquals(r[i], element); } else { @@ -1183,6 +1183,10 @@ public class Long64VectorTests extends AbstractVectorTest { return Long.compareUnsigned(a, b) >= 0; } + static long firstNonZero(long a, long b) { + return Long.compare(a, (long) 0) != 0 ? a : b; + } + @Test static void smokeTest1() { LongVector three = LongVector.broadcast(SPECIES, (byte)-3); @@ -3203,7 +3207,7 @@ public class Long64VectorTests extends AbstractVectorTest { static long MINReduce(long[] a, int idx) { long res = Long.MAX_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (long)Math.min(res, a[i]); + res = (long) Math.min(res, a[i]); } return res; @@ -3211,8 +3215,8 @@ public class Long64VectorTests extends AbstractVectorTest { static long MINReduceAll(long[] a) { long res = Long.MAX_VALUE; - for (int i = 0; i < a.length; i++) { - res = (long)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (long) Math.min(res, MINReduce(a, i)); } return res; @@ -3234,7 +3238,7 @@ public class Long64VectorTests extends AbstractVectorTest { ra = Long.MAX_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long)Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + ra = (long) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); } } @@ -3244,8 +3248,8 @@ public class Long64VectorTests extends AbstractVectorTest { static long MINReduceMasked(long[] a, int idx, boolean[] mask) { long res = Long.MAX_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (long)Math.min(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (long) Math.min(res, a[i]); } return res; @@ -3253,9 +3257,8 @@ public class Long64VectorTests extends AbstractVectorTest { static long MINReduceAllMasked(long[] a, boolean[] mask) { long res = Long.MAX_VALUE; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (long)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (long) Math.min(res, MINReduceMasked(a, i, mask)); } return res; @@ -3279,7 +3282,7 @@ public class Long64VectorTests extends AbstractVectorTest { ra = Long.MAX_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long)Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + ra = (long) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); } } @@ -3289,7 +3292,7 @@ public class Long64VectorTests extends AbstractVectorTest { static long MAXReduce(long[] a, int idx) { long res = Long.MIN_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (long)Math.max(res, a[i]); + res = (long) Math.max(res, a[i]); } return res; @@ -3297,8 +3300,8 @@ public class Long64VectorTests extends AbstractVectorTest { static long MAXReduceAll(long[] a) { long res = Long.MIN_VALUE; - for (int i = 0; i < a.length; i++) { - res = (long)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (long) Math.max(res, MAXReduce(a, i)); } return res; @@ -3320,7 +3323,7 @@ public class Long64VectorTests extends AbstractVectorTest { ra = Long.MIN_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long)Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + ra = (long) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); } } @@ -3330,8 +3333,8 @@ public class Long64VectorTests extends AbstractVectorTest { static long MAXReduceMasked(long[] a, int idx, boolean[] mask) { long res = Long.MIN_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (long)Math.max(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (long) Math.max(res, a[i]); } return res; @@ -3339,9 +3342,8 @@ public class Long64VectorTests extends AbstractVectorTest { static long MAXReduceAllMasked(long[] a, boolean[] mask) { long res = Long.MIN_VALUE; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (long)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (long) Math.max(res, MAXReduceMasked(a, i, mask)); } return res; @@ -3365,13 +3367,98 @@ public class Long64VectorTests extends AbstractVectorTest { ra = Long.MIN_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long)Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + ra = (long) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); } } assertReductionArraysEqualsMasked(r, ra, a, mask, Long64VectorTests::MAXReduceMasked, Long64VectorTests::MAXReduceAllMasked); } + static long FIRST_NONZEROReduce(long[] a, int idx) { + long res = (long) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + res = firstNonZero(res, a[i]); + } + + return res; + } + + static long FIRST_NONZEROReduceAll(long[] a) { + long res = (long) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); + } + + return res; + } + @Test(dataProvider = "longUnaryOpProvider") + static void FIRST_NONZEROReduceLong64VectorTests(IntFunction<long[]> fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + long ra = (long) 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); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (long) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + } + } + + assertReductionArraysEquals(r, ra, a, + Long64VectorTests::FIRST_NONZEROReduce, Long64VectorTests::FIRST_NONZEROReduceAll); + } + static long FIRST_NONZEROReduceMasked(long[] a, int idx, boolean[] mask) { + long res = (long) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + if (mask[i % SPECIES.length()]) + res = firstNonZero(res, a[i]); + } + + return res; + } + + static long FIRST_NONZEROReduceAllMasked(long[] a, boolean[] mask) { + long res = (long) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); + } + + return res; + } + @Test(dataProvider = "longUnaryOpMaskProvider") + static void FIRST_NONZEROReduceLong64VectorTestsMasked(IntFunction<long[]> fa, IntFunction<boolean[]> fm) { + long[] a = fa.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask<Long> vmask = VectorMask.fromArray(SPECIES, mask, 0); + long ra = (long) 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); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (long) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + } + } + + assertReductionArraysEqualsMasked(r, ra, a, mask, + Long64VectorTests::FIRST_NONZEROReduceMasked, Long64VectorTests::FIRST_NONZEROReduceAllMasked); + } static boolean anyTrue(boolean[] a, int idx) { boolean res = false; @@ -3431,13 +3518,16 @@ public class Long64VectorTests extends AbstractVectorTest { long[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { - for (int i = 0; i < a.length; i += SPECIES.length()) { + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - av.withLane(0, (long)4).intoArray(r, i); + av.withLane((j++ & (SPECIES.length()-1)), (long)(65535+i)).intoArray(r, i); } } - assertInsertArraysEquals(r, a, (long)4, 0); + + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { + assertInsertArraysEquals(r, a, (long)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); + } } static boolean testIS_DEFAULT(long a) { return bits(a)==0; @@ -3461,19 +3551,21 @@ public class Long64VectorTests extends AbstractVectorTest { } @Test(dataProvider = "longTestOpMaskProvider") - static void IS_DEFAULTMaskedLong64VectorTestsSmokeTest(IntFunction<long[]> fa, + static void IS_DEFAULTMaskedLong64VectorTests(IntFunction<long[]> fa, IntFunction<boolean[]> fm) { long[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Long> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - VectorMask<Long> mv = av.test(VectorOperators.IS_DEFAULT, vmask); + 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); + VectorMask<Long> mv = av.test(VectorOperators.IS_DEFAULT, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_DEFAULT(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_DEFAULT(a[i + j])); + } } } } @@ -3499,19 +3591,21 @@ public class Long64VectorTests extends AbstractVectorTest { } @Test(dataProvider = "longTestOpMaskProvider") - static void IS_NEGATIVEMaskedLong64VectorTestsSmokeTest(IntFunction<long[]> fa, + static void IS_NEGATIVEMaskedLong64VectorTests(IntFunction<long[]> fa, IntFunction<boolean[]> fm) { long[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Long> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - VectorMask<Long> mv = av.test(VectorOperators.IS_NEGATIVE, vmask); + 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); + VectorMask<Long> mv = av.test(VectorOperators.IS_NEGATIVE, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_NEGATIVE(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_NEGATIVE(a[i + j])); + } } } } @@ -5350,7 +5444,7 @@ public class Long64VectorTests extends AbstractVectorTest { static void maskFromToLongLong64VectorTestsSmokeTest(long inputLong) { var vmask = VectorMask.fromLong(SPECIES, inputLong); long outputLong = vmask.toLong(); - Assert.assertEquals(outputLong, inputLong & (((1L << (SPECIES.length() - 1)) << 1) - 1)); + Assert.assertEquals(outputLong, (inputLong & (((0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length())))))); } @DataProvider @@ -5452,5 +5546,12 @@ public class Long64VectorTests extends AbstractVectorTest { VectorSpecies species = av.species().withShape(vsh); assert(species.equals(SPECIES)); } + + @Test + static void MaskAllTrueLong64VectorTestsSmokeTest() { + for (int ic = 0; ic < INVOC_COUNT; ic++) { + Assert.assertEquals(SPECIES.maskAll(true).toLong(), -1L >>> (64 - SPECIES.length())); + } + } } diff --git a/test/jdk/jdk/incubator/vector/LongMaxVectorTests.java b/test/jdk/jdk/incubator/vector/LongMaxVectorTests.java index e5cd61eca7477ddd1bf44d4b04913946ca3e295e..749ec641d3d59d80e6f95fece7057e6424dc6349 100644 --- a/test/jdk/jdk/incubator/vector/LongMaxVectorTests.java +++ b/test/jdk/jdk/incubator/vector/LongMaxVectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -188,10 +188,10 @@ public class LongMaxVectorTests extends AbstractVectorTest { } } - static void assertInsertArraysEquals(long[] r, long[] a, long element, int index) { - int i = 0; + static void assertInsertArraysEquals(long[] r, long[] a, long element, int index, int start, int end) { + int i = start; try { - for (; i < a.length; i += 1) { + for (; i < end; i += 1) { if(i%SPECIES.length() == index) { Assert.assertEquals(r[i], element); } else { @@ -1188,6 +1188,10 @@ public class LongMaxVectorTests extends AbstractVectorTest { return Long.compareUnsigned(a, b) >= 0; } + static long firstNonZero(long a, long b) { + return Long.compare(a, (long) 0) != 0 ? a : b; + } + @Test static void smokeTest1() { LongVector three = LongVector.broadcast(SPECIES, (byte)-3); @@ -3208,7 +3212,7 @@ public class LongMaxVectorTests extends AbstractVectorTest { static long MINReduce(long[] a, int idx) { long res = Long.MAX_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (long)Math.min(res, a[i]); + res = (long) Math.min(res, a[i]); } return res; @@ -3216,8 +3220,8 @@ public class LongMaxVectorTests extends AbstractVectorTest { static long MINReduceAll(long[] a) { long res = Long.MAX_VALUE; - for (int i = 0; i < a.length; i++) { - res = (long)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (long) Math.min(res, MINReduce(a, i)); } return res; @@ -3239,7 +3243,7 @@ public class LongMaxVectorTests extends AbstractVectorTest { ra = Long.MAX_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long)Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + ra = (long) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); } } @@ -3249,8 +3253,8 @@ public class LongMaxVectorTests extends AbstractVectorTest { static long MINReduceMasked(long[] a, int idx, boolean[] mask) { long res = Long.MAX_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (long)Math.min(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (long) Math.min(res, a[i]); } return res; @@ -3258,9 +3262,8 @@ public class LongMaxVectorTests extends AbstractVectorTest { static long MINReduceAllMasked(long[] a, boolean[] mask) { long res = Long.MAX_VALUE; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (long)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (long) Math.min(res, MINReduceMasked(a, i, mask)); } return res; @@ -3284,7 +3287,7 @@ public class LongMaxVectorTests extends AbstractVectorTest { ra = Long.MAX_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long)Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + ra = (long) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); } } @@ -3294,7 +3297,7 @@ public class LongMaxVectorTests extends AbstractVectorTest { static long MAXReduce(long[] a, int idx) { long res = Long.MIN_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (long)Math.max(res, a[i]); + res = (long) Math.max(res, a[i]); } return res; @@ -3302,8 +3305,8 @@ public class LongMaxVectorTests extends AbstractVectorTest { static long MAXReduceAll(long[] a) { long res = Long.MIN_VALUE; - for (int i = 0; i < a.length; i++) { - res = (long)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (long) Math.max(res, MAXReduce(a, i)); } return res; @@ -3325,7 +3328,7 @@ public class LongMaxVectorTests extends AbstractVectorTest { ra = Long.MIN_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long)Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + ra = (long) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); } } @@ -3335,8 +3338,8 @@ public class LongMaxVectorTests extends AbstractVectorTest { static long MAXReduceMasked(long[] a, int idx, boolean[] mask) { long res = Long.MIN_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (long)Math.max(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (long) Math.max(res, a[i]); } return res; @@ -3344,9 +3347,8 @@ public class LongMaxVectorTests extends AbstractVectorTest { static long MAXReduceAllMasked(long[] a, boolean[] mask) { long res = Long.MIN_VALUE; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (long)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (long) Math.max(res, MAXReduceMasked(a, i, mask)); } return res; @@ -3370,13 +3372,98 @@ public class LongMaxVectorTests extends AbstractVectorTest { ra = Long.MIN_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long)Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + ra = (long) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); } } assertReductionArraysEqualsMasked(r, ra, a, mask, LongMaxVectorTests::MAXReduceMasked, LongMaxVectorTests::MAXReduceAllMasked); } + static long FIRST_NONZEROReduce(long[] a, int idx) { + long res = (long) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + res = firstNonZero(res, a[i]); + } + + return res; + } + + static long FIRST_NONZEROReduceAll(long[] a) { + long res = (long) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); + } + + return res; + } + @Test(dataProvider = "longUnaryOpProvider") + static void FIRST_NONZEROReduceLongMaxVectorTests(IntFunction<long[]> fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + long ra = (long) 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); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (long) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + } + } + + assertReductionArraysEquals(r, ra, a, + LongMaxVectorTests::FIRST_NONZEROReduce, LongMaxVectorTests::FIRST_NONZEROReduceAll); + } + static long FIRST_NONZEROReduceMasked(long[] a, int idx, boolean[] mask) { + long res = (long) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + if (mask[i % SPECIES.length()]) + res = firstNonZero(res, a[i]); + } + + return res; + } + + static long FIRST_NONZEROReduceAllMasked(long[] a, boolean[] mask) { + long res = (long) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); + } + + return res; + } + @Test(dataProvider = "longUnaryOpMaskProvider") + static void FIRST_NONZEROReduceLongMaxVectorTestsMasked(IntFunction<long[]> fa, IntFunction<boolean[]> fm) { + long[] a = fa.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask<Long> vmask = VectorMask.fromArray(SPECIES, mask, 0); + long ra = (long) 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); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (long) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + } + } + + assertReductionArraysEqualsMasked(r, ra, a, mask, + LongMaxVectorTests::FIRST_NONZEROReduceMasked, LongMaxVectorTests::FIRST_NONZEROReduceAllMasked); + } static boolean anyTrue(boolean[] a, int idx) { boolean res = false; @@ -3436,13 +3523,16 @@ public class LongMaxVectorTests extends AbstractVectorTest { long[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { - for (int i = 0; i < a.length; i += SPECIES.length()) { + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - av.withLane(0, (long)4).intoArray(r, i); + av.withLane((j++ & (SPECIES.length()-1)), (long)(65535+i)).intoArray(r, i); } } - assertInsertArraysEquals(r, a, (long)4, 0); + + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { + assertInsertArraysEquals(r, a, (long)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); + } } static boolean testIS_DEFAULT(long a) { return bits(a)==0; @@ -3466,19 +3556,21 @@ public class LongMaxVectorTests extends AbstractVectorTest { } @Test(dataProvider = "longTestOpMaskProvider") - static void IS_DEFAULTMaskedLongMaxVectorTestsSmokeTest(IntFunction<long[]> fa, + static void IS_DEFAULTMaskedLongMaxVectorTests(IntFunction<long[]> fa, IntFunction<boolean[]> fm) { long[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Long> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - VectorMask<Long> mv = av.test(VectorOperators.IS_DEFAULT, vmask); + 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); + VectorMask<Long> mv = av.test(VectorOperators.IS_DEFAULT, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_DEFAULT(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_DEFAULT(a[i + j])); + } } } } @@ -3504,19 +3596,21 @@ public class LongMaxVectorTests extends AbstractVectorTest { } @Test(dataProvider = "longTestOpMaskProvider") - static void IS_NEGATIVEMaskedLongMaxVectorTestsSmokeTest(IntFunction<long[]> fa, + static void IS_NEGATIVEMaskedLongMaxVectorTests(IntFunction<long[]> fa, IntFunction<boolean[]> fm) { long[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Long> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - VectorMask<Long> mv = av.test(VectorOperators.IS_NEGATIVE, vmask); + 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); + VectorMask<Long> mv = av.test(VectorOperators.IS_NEGATIVE, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_NEGATIVE(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_NEGATIVE(a[i + j])); + } } } } @@ -5441,5 +5535,12 @@ public class LongMaxVectorTests extends AbstractVectorTest { VectorSpecies species = av.species().withShape(vsh); assert(species.equals(SPECIES)); } + + @Test + static void MaskAllTrueLongMaxVectorTestsSmokeTest() { + for (int ic = 0; ic < INVOC_COUNT; ic++) { + Assert.assertEquals(SPECIES.maskAll(true).toLong(), -1L >>> (64 - SPECIES.length())); + } + } } diff --git a/test/jdk/jdk/incubator/vector/Short128VectorTests.java b/test/jdk/jdk/incubator/vector/Short128VectorTests.java index 88eca9e1d9a0fe31357661d7150a5a9a7557655a..e933c0eaac539c734d5f48d4f42368684b12c8db 100644 --- a/test/jdk/jdk/incubator/vector/Short128VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Short128VectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -226,10 +226,10 @@ public class Short128VectorTests extends AbstractVectorTest { } } - static void assertInsertArraysEquals(short[] r, short[] a, short element, int index) { - int i = 0; + static void assertInsertArraysEquals(short[] r, short[] a, short element, int index, int start, int end) { + int i = start; try { - for (; i < a.length; i += 1) { + for (; i < end; i += 1) { if(i%SPECIES.length() == index) { Assert.assertEquals(r[i], element); } else { @@ -1191,6 +1191,10 @@ public class Short128VectorTests extends AbstractVectorTest { return Short.compareUnsigned(a, b) >= 0; } + static short firstNonZero(short a, short b) { + return Short.compare(a, (short) 0) != 0 ? a : b; + } + @Test static void smokeTest1() { ShortVector three = ShortVector.broadcast(SPECIES, (byte)-3); @@ -3206,7 +3210,7 @@ public class Short128VectorTests extends AbstractVectorTest { static short MINReduce(short[] a, int idx) { short res = Short.MAX_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (short)Math.min(res, a[i]); + res = (short) Math.min(res, a[i]); } return res; @@ -3214,8 +3218,8 @@ public class Short128VectorTests extends AbstractVectorTest { static short MINReduceAll(short[] a) { short res = Short.MAX_VALUE; - for (int i = 0; i < a.length; i++) { - res = (short)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (short) Math.min(res, MINReduce(a, i)); } return res; @@ -3237,7 +3241,7 @@ public class Short128VectorTests extends AbstractVectorTest { ra = Short.MAX_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short)Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + ra = (short) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); } } @@ -3247,8 +3251,8 @@ public class Short128VectorTests extends AbstractVectorTest { static short MINReduceMasked(short[] a, int idx, boolean[] mask) { short res = Short.MAX_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (short)Math.min(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (short) Math.min(res, a[i]); } return res; @@ -3256,9 +3260,8 @@ public class Short128VectorTests extends AbstractVectorTest { static short MINReduceAllMasked(short[] a, boolean[] mask) { short res = Short.MAX_VALUE; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (short)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (short) Math.min(res, MINReduceMasked(a, i, mask)); } return res; @@ -3282,7 +3285,7 @@ public class Short128VectorTests extends AbstractVectorTest { ra = Short.MAX_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short)Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + ra = (short) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); } } @@ -3292,7 +3295,7 @@ public class Short128VectorTests extends AbstractVectorTest { static short MAXReduce(short[] a, int idx) { short res = Short.MIN_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (short)Math.max(res, a[i]); + res = (short) Math.max(res, a[i]); } return res; @@ -3300,8 +3303,8 @@ public class Short128VectorTests extends AbstractVectorTest { static short MAXReduceAll(short[] a) { short res = Short.MIN_VALUE; - for (int i = 0; i < a.length; i++) { - res = (short)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (short) Math.max(res, MAXReduce(a, i)); } return res; @@ -3323,7 +3326,7 @@ public class Short128VectorTests extends AbstractVectorTest { ra = Short.MIN_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short)Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + ra = (short) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); } } @@ -3333,8 +3336,8 @@ public class Short128VectorTests extends AbstractVectorTest { static short MAXReduceMasked(short[] a, int idx, boolean[] mask) { short res = Short.MIN_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (short)Math.max(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (short) Math.max(res, a[i]); } return res; @@ -3342,9 +3345,8 @@ public class Short128VectorTests extends AbstractVectorTest { static short MAXReduceAllMasked(short[] a, boolean[] mask) { short res = Short.MIN_VALUE; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (short)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (short) Math.max(res, MAXReduceMasked(a, i, mask)); } return res; @@ -3368,13 +3370,98 @@ public class Short128VectorTests extends AbstractVectorTest { ra = Short.MIN_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short)Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + ra = (short) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); } } assertReductionArraysEqualsMasked(r, ra, a, mask, Short128VectorTests::MAXReduceMasked, Short128VectorTests::MAXReduceAllMasked); } + static short FIRST_NONZEROReduce(short[] a, int idx) { + short res = (short) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + res = firstNonZero(res, a[i]); + } + + return res; + } + + static short FIRST_NONZEROReduceAll(short[] a) { + short res = (short) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); + } + + return res; + } + @Test(dataProvider = "shortUnaryOpProvider") + static void FIRST_NONZEROReduceShort128VectorTests(IntFunction<short[]> fa) { + short[] a = fa.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + short ra = (short) 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); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (short) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + } + } + + assertReductionArraysEquals(r, ra, a, + Short128VectorTests::FIRST_NONZEROReduce, Short128VectorTests::FIRST_NONZEROReduceAll); + } + static short FIRST_NONZEROReduceMasked(short[] a, int idx, boolean[] mask) { + short res = (short) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + if (mask[i % SPECIES.length()]) + res = firstNonZero(res, a[i]); + } + + return res; + } + + static short FIRST_NONZEROReduceAllMasked(short[] a, boolean[] mask) { + short res = (short) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); + } + + return res; + } + @Test(dataProvider = "shortUnaryOpMaskProvider") + static void FIRST_NONZEROReduceShort128VectorTestsMasked(IntFunction<short[]> fa, IntFunction<boolean[]> fm) { + short[] a = fa.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask<Short> vmask = VectorMask.fromArray(SPECIES, mask, 0); + short ra = (short) 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); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (short) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + } + } + + assertReductionArraysEqualsMasked(r, ra, a, mask, + Short128VectorTests::FIRST_NONZEROReduceMasked, Short128VectorTests::FIRST_NONZEROReduceAllMasked); + } static boolean anyTrue(boolean[] a, int idx) { boolean res = false; @@ -3434,13 +3521,16 @@ public class Short128VectorTests extends AbstractVectorTest { short[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { - for (int i = 0; i < a.length; i += SPECIES.length()) { + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - av.withLane(0, (short)4).intoArray(r, i); + av.withLane((j++ & (SPECIES.length()-1)), (short)(65535+i)).intoArray(r, i); } } - assertInsertArraysEquals(r, a, (short)4, 0); + + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { + assertInsertArraysEquals(r, a, (short)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); + } } static boolean testIS_DEFAULT(short a) { return bits(a)==0; @@ -3464,19 +3554,21 @@ public class Short128VectorTests extends AbstractVectorTest { } @Test(dataProvider = "shortTestOpMaskProvider") - static void IS_DEFAULTMaskedShort128VectorTestsSmokeTest(IntFunction<short[]> fa, + static void IS_DEFAULTMaskedShort128VectorTests(IntFunction<short[]> fa, IntFunction<boolean[]> fm) { short[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Short> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - VectorMask<Short> mv = av.test(VectorOperators.IS_DEFAULT, vmask); + 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); + VectorMask<Short> mv = av.test(VectorOperators.IS_DEFAULT, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_DEFAULT(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_DEFAULT(a[i + j])); + } } } } @@ -3502,19 +3594,21 @@ public class Short128VectorTests extends AbstractVectorTest { } @Test(dataProvider = "shortTestOpMaskProvider") - static void IS_NEGATIVEMaskedShort128VectorTestsSmokeTest(IntFunction<short[]> fa, + static void IS_NEGATIVEMaskedShort128VectorTests(IntFunction<short[]> fa, IntFunction<boolean[]> fm) { short[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Short> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - VectorMask<Short> mv = av.test(VectorOperators.IS_NEGATIVE, vmask); + 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); + VectorMask<Short> mv = av.test(VectorOperators.IS_NEGATIVE, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_NEGATIVE(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_NEGATIVE(a[i + j])); + } } } } @@ -5491,7 +5585,7 @@ public class Short128VectorTests extends AbstractVectorTest { static void maskFromToLongShort128VectorTestsSmokeTest(long inputLong) { var vmask = VectorMask.fromLong(SPECIES, inputLong); long outputLong = vmask.toLong(); - Assert.assertEquals(outputLong, inputLong & (((1L << (SPECIES.length() - 1)) << 1) - 1)); + Assert.assertEquals(outputLong, (inputLong & (((0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length())))))); } @DataProvider @@ -5593,5 +5687,12 @@ public class Short128VectorTests extends AbstractVectorTest { VectorSpecies species = av.species().withShape(vsh); assert(species.equals(SPECIES)); } + + @Test + static void MaskAllTrueShort128VectorTestsSmokeTest() { + for (int ic = 0; ic < INVOC_COUNT; ic++) { + Assert.assertEquals(SPECIES.maskAll(true).toLong(), -1L >>> (64 - SPECIES.length())); + } + } } diff --git a/test/jdk/jdk/incubator/vector/Short256VectorTests.java b/test/jdk/jdk/incubator/vector/Short256VectorTests.java index bc33a302cec9357d5df243c3bb4dbf750482a18d..75f7129e14bbfaf4fe9b3ad1c6920c27a5c07478 100644 --- a/test/jdk/jdk/incubator/vector/Short256VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Short256VectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -226,10 +226,10 @@ public class Short256VectorTests extends AbstractVectorTest { } } - static void assertInsertArraysEquals(short[] r, short[] a, short element, int index) { - int i = 0; + static void assertInsertArraysEquals(short[] r, short[] a, short element, int index, int start, int end) { + int i = start; try { - for (; i < a.length; i += 1) { + for (; i < end; i += 1) { if(i%SPECIES.length() == index) { Assert.assertEquals(r[i], element); } else { @@ -1191,6 +1191,10 @@ public class Short256VectorTests extends AbstractVectorTest { return Short.compareUnsigned(a, b) >= 0; } + static short firstNonZero(short a, short b) { + return Short.compare(a, (short) 0) != 0 ? a : b; + } + @Test static void smokeTest1() { ShortVector three = ShortVector.broadcast(SPECIES, (byte)-3); @@ -3206,7 +3210,7 @@ public class Short256VectorTests extends AbstractVectorTest { static short MINReduce(short[] a, int idx) { short res = Short.MAX_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (short)Math.min(res, a[i]); + res = (short) Math.min(res, a[i]); } return res; @@ -3214,8 +3218,8 @@ public class Short256VectorTests extends AbstractVectorTest { static short MINReduceAll(short[] a) { short res = Short.MAX_VALUE; - for (int i = 0; i < a.length; i++) { - res = (short)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (short) Math.min(res, MINReduce(a, i)); } return res; @@ -3237,7 +3241,7 @@ public class Short256VectorTests extends AbstractVectorTest { ra = Short.MAX_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short)Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + ra = (short) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); } } @@ -3247,8 +3251,8 @@ public class Short256VectorTests extends AbstractVectorTest { static short MINReduceMasked(short[] a, int idx, boolean[] mask) { short res = Short.MAX_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (short)Math.min(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (short) Math.min(res, a[i]); } return res; @@ -3256,9 +3260,8 @@ public class Short256VectorTests extends AbstractVectorTest { static short MINReduceAllMasked(short[] a, boolean[] mask) { short res = Short.MAX_VALUE; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (short)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (short) Math.min(res, MINReduceMasked(a, i, mask)); } return res; @@ -3282,7 +3285,7 @@ public class Short256VectorTests extends AbstractVectorTest { ra = Short.MAX_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short)Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + ra = (short) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); } } @@ -3292,7 +3295,7 @@ public class Short256VectorTests extends AbstractVectorTest { static short MAXReduce(short[] a, int idx) { short res = Short.MIN_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (short)Math.max(res, a[i]); + res = (short) Math.max(res, a[i]); } return res; @@ -3300,8 +3303,8 @@ public class Short256VectorTests extends AbstractVectorTest { static short MAXReduceAll(short[] a) { short res = Short.MIN_VALUE; - for (int i = 0; i < a.length; i++) { - res = (short)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (short) Math.max(res, MAXReduce(a, i)); } return res; @@ -3323,7 +3326,7 @@ public class Short256VectorTests extends AbstractVectorTest { ra = Short.MIN_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short)Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + ra = (short) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); } } @@ -3333,8 +3336,8 @@ public class Short256VectorTests extends AbstractVectorTest { static short MAXReduceMasked(short[] a, int idx, boolean[] mask) { short res = Short.MIN_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (short)Math.max(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (short) Math.max(res, a[i]); } return res; @@ -3342,9 +3345,8 @@ public class Short256VectorTests extends AbstractVectorTest { static short MAXReduceAllMasked(short[] a, boolean[] mask) { short res = Short.MIN_VALUE; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (short)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (short) Math.max(res, MAXReduceMasked(a, i, mask)); } return res; @@ -3368,13 +3370,98 @@ public class Short256VectorTests extends AbstractVectorTest { ra = Short.MIN_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short)Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + ra = (short) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); } } assertReductionArraysEqualsMasked(r, ra, a, mask, Short256VectorTests::MAXReduceMasked, Short256VectorTests::MAXReduceAllMasked); } + static short FIRST_NONZEROReduce(short[] a, int idx) { + short res = (short) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + res = firstNonZero(res, a[i]); + } + + return res; + } + + static short FIRST_NONZEROReduceAll(short[] a) { + short res = (short) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); + } + + return res; + } + @Test(dataProvider = "shortUnaryOpProvider") + static void FIRST_NONZEROReduceShort256VectorTests(IntFunction<short[]> fa) { + short[] a = fa.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + short ra = (short) 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); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (short) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + } + } + + assertReductionArraysEquals(r, ra, a, + Short256VectorTests::FIRST_NONZEROReduce, Short256VectorTests::FIRST_NONZEROReduceAll); + } + static short FIRST_NONZEROReduceMasked(short[] a, int idx, boolean[] mask) { + short res = (short) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + if (mask[i % SPECIES.length()]) + res = firstNonZero(res, a[i]); + } + + return res; + } + + static short FIRST_NONZEROReduceAllMasked(short[] a, boolean[] mask) { + short res = (short) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); + } + + return res; + } + @Test(dataProvider = "shortUnaryOpMaskProvider") + static void FIRST_NONZEROReduceShort256VectorTestsMasked(IntFunction<short[]> fa, IntFunction<boolean[]> fm) { + short[] a = fa.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask<Short> vmask = VectorMask.fromArray(SPECIES, mask, 0); + short ra = (short) 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); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (short) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + } + } + + assertReductionArraysEqualsMasked(r, ra, a, mask, + Short256VectorTests::FIRST_NONZEROReduceMasked, Short256VectorTests::FIRST_NONZEROReduceAllMasked); + } static boolean anyTrue(boolean[] a, int idx) { boolean res = false; @@ -3434,13 +3521,16 @@ public class Short256VectorTests extends AbstractVectorTest { short[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { - for (int i = 0; i < a.length; i += SPECIES.length()) { + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - av.withLane(0, (short)4).intoArray(r, i); + av.withLane((j++ & (SPECIES.length()-1)), (short)(65535+i)).intoArray(r, i); } } - assertInsertArraysEquals(r, a, (short)4, 0); + + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { + assertInsertArraysEquals(r, a, (short)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); + } } static boolean testIS_DEFAULT(short a) { return bits(a)==0; @@ -3464,19 +3554,21 @@ public class Short256VectorTests extends AbstractVectorTest { } @Test(dataProvider = "shortTestOpMaskProvider") - static void IS_DEFAULTMaskedShort256VectorTestsSmokeTest(IntFunction<short[]> fa, + static void IS_DEFAULTMaskedShort256VectorTests(IntFunction<short[]> fa, IntFunction<boolean[]> fm) { short[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Short> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - VectorMask<Short> mv = av.test(VectorOperators.IS_DEFAULT, vmask); + 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); + VectorMask<Short> mv = av.test(VectorOperators.IS_DEFAULT, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_DEFAULT(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_DEFAULT(a[i + j])); + } } } } @@ -3502,19 +3594,21 @@ public class Short256VectorTests extends AbstractVectorTest { } @Test(dataProvider = "shortTestOpMaskProvider") - static void IS_NEGATIVEMaskedShort256VectorTestsSmokeTest(IntFunction<short[]> fa, + static void IS_NEGATIVEMaskedShort256VectorTests(IntFunction<short[]> fa, IntFunction<boolean[]> fm) { short[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Short> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - VectorMask<Short> mv = av.test(VectorOperators.IS_NEGATIVE, vmask); + 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); + VectorMask<Short> mv = av.test(VectorOperators.IS_NEGATIVE, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_NEGATIVE(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_NEGATIVE(a[i + j])); + } } } } @@ -5491,7 +5585,7 @@ public class Short256VectorTests extends AbstractVectorTest { static void maskFromToLongShort256VectorTestsSmokeTest(long inputLong) { var vmask = VectorMask.fromLong(SPECIES, inputLong); long outputLong = vmask.toLong(); - Assert.assertEquals(outputLong, inputLong & (((1L << (SPECIES.length() - 1)) << 1) - 1)); + Assert.assertEquals(outputLong, (inputLong & (((0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length())))))); } @DataProvider @@ -5593,5 +5687,12 @@ public class Short256VectorTests extends AbstractVectorTest { VectorSpecies species = av.species().withShape(vsh); assert(species.equals(SPECIES)); } + + @Test + static void MaskAllTrueShort256VectorTestsSmokeTest() { + for (int ic = 0; ic < INVOC_COUNT; ic++) { + Assert.assertEquals(SPECIES.maskAll(true).toLong(), -1L >>> (64 - SPECIES.length())); + } + } } diff --git a/test/jdk/jdk/incubator/vector/Short512VectorTests.java b/test/jdk/jdk/incubator/vector/Short512VectorTests.java index b33134d622534369d61eea65111ec7cbbce048b6..af7eea3b2c8dc40186a8d2a58e347a07eef8b466 100644 --- a/test/jdk/jdk/incubator/vector/Short512VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Short512VectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -226,10 +226,10 @@ public class Short512VectorTests extends AbstractVectorTest { } } - static void assertInsertArraysEquals(short[] r, short[] a, short element, int index) { - int i = 0; + static void assertInsertArraysEquals(short[] r, short[] a, short element, int index, int start, int end) { + int i = start; try { - for (; i < a.length; i += 1) { + for (; i < end; i += 1) { if(i%SPECIES.length() == index) { Assert.assertEquals(r[i], element); } else { @@ -1191,6 +1191,10 @@ public class Short512VectorTests extends AbstractVectorTest { return Short.compareUnsigned(a, b) >= 0; } + static short firstNonZero(short a, short b) { + return Short.compare(a, (short) 0) != 0 ? a : b; + } + @Test static void smokeTest1() { ShortVector three = ShortVector.broadcast(SPECIES, (byte)-3); @@ -3206,7 +3210,7 @@ public class Short512VectorTests extends AbstractVectorTest { static short MINReduce(short[] a, int idx) { short res = Short.MAX_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (short)Math.min(res, a[i]); + res = (short) Math.min(res, a[i]); } return res; @@ -3214,8 +3218,8 @@ public class Short512VectorTests extends AbstractVectorTest { static short MINReduceAll(short[] a) { short res = Short.MAX_VALUE; - for (int i = 0; i < a.length; i++) { - res = (short)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (short) Math.min(res, MINReduce(a, i)); } return res; @@ -3237,7 +3241,7 @@ public class Short512VectorTests extends AbstractVectorTest { ra = Short.MAX_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short)Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + ra = (short) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); } } @@ -3247,8 +3251,8 @@ public class Short512VectorTests extends AbstractVectorTest { static short MINReduceMasked(short[] a, int idx, boolean[] mask) { short res = Short.MAX_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (short)Math.min(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (short) Math.min(res, a[i]); } return res; @@ -3256,9 +3260,8 @@ public class Short512VectorTests extends AbstractVectorTest { static short MINReduceAllMasked(short[] a, boolean[] mask) { short res = Short.MAX_VALUE; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (short)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (short) Math.min(res, MINReduceMasked(a, i, mask)); } return res; @@ -3282,7 +3285,7 @@ public class Short512VectorTests extends AbstractVectorTest { ra = Short.MAX_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short)Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + ra = (short) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); } } @@ -3292,7 +3295,7 @@ public class Short512VectorTests extends AbstractVectorTest { static short MAXReduce(short[] a, int idx) { short res = Short.MIN_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (short)Math.max(res, a[i]); + res = (short) Math.max(res, a[i]); } return res; @@ -3300,8 +3303,8 @@ public class Short512VectorTests extends AbstractVectorTest { static short MAXReduceAll(short[] a) { short res = Short.MIN_VALUE; - for (int i = 0; i < a.length; i++) { - res = (short)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (short) Math.max(res, MAXReduce(a, i)); } return res; @@ -3323,7 +3326,7 @@ public class Short512VectorTests extends AbstractVectorTest { ra = Short.MIN_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short)Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + ra = (short) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); } } @@ -3333,8 +3336,8 @@ public class Short512VectorTests extends AbstractVectorTest { static short MAXReduceMasked(short[] a, int idx, boolean[] mask) { short res = Short.MIN_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (short)Math.max(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (short) Math.max(res, a[i]); } return res; @@ -3342,9 +3345,8 @@ public class Short512VectorTests extends AbstractVectorTest { static short MAXReduceAllMasked(short[] a, boolean[] mask) { short res = Short.MIN_VALUE; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (short)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (short) Math.max(res, MAXReduceMasked(a, i, mask)); } return res; @@ -3368,13 +3370,98 @@ public class Short512VectorTests extends AbstractVectorTest { ra = Short.MIN_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short)Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + ra = (short) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); } } assertReductionArraysEqualsMasked(r, ra, a, mask, Short512VectorTests::MAXReduceMasked, Short512VectorTests::MAXReduceAllMasked); } + static short FIRST_NONZEROReduce(short[] a, int idx) { + short res = (short) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + res = firstNonZero(res, a[i]); + } + + return res; + } + + static short FIRST_NONZEROReduceAll(short[] a) { + short res = (short) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); + } + + return res; + } + @Test(dataProvider = "shortUnaryOpProvider") + static void FIRST_NONZEROReduceShort512VectorTests(IntFunction<short[]> fa) { + short[] a = fa.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + short ra = (short) 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); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (short) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + } + } + + assertReductionArraysEquals(r, ra, a, + Short512VectorTests::FIRST_NONZEROReduce, Short512VectorTests::FIRST_NONZEROReduceAll); + } + static short FIRST_NONZEROReduceMasked(short[] a, int idx, boolean[] mask) { + short res = (short) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + if (mask[i % SPECIES.length()]) + res = firstNonZero(res, a[i]); + } + + return res; + } + + static short FIRST_NONZEROReduceAllMasked(short[] a, boolean[] mask) { + short res = (short) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); + } + + return res; + } + @Test(dataProvider = "shortUnaryOpMaskProvider") + static void FIRST_NONZEROReduceShort512VectorTestsMasked(IntFunction<short[]> fa, IntFunction<boolean[]> fm) { + short[] a = fa.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask<Short> vmask = VectorMask.fromArray(SPECIES, mask, 0); + short ra = (short) 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); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (short) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + } + } + + assertReductionArraysEqualsMasked(r, ra, a, mask, + Short512VectorTests::FIRST_NONZEROReduceMasked, Short512VectorTests::FIRST_NONZEROReduceAllMasked); + } static boolean anyTrue(boolean[] a, int idx) { boolean res = false; @@ -3434,13 +3521,16 @@ public class Short512VectorTests extends AbstractVectorTest { short[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { - for (int i = 0; i < a.length; i += SPECIES.length()) { + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - av.withLane(0, (short)4).intoArray(r, i); + av.withLane((j++ & (SPECIES.length()-1)), (short)(65535+i)).intoArray(r, i); } } - assertInsertArraysEquals(r, a, (short)4, 0); + + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { + assertInsertArraysEquals(r, a, (short)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); + } } static boolean testIS_DEFAULT(short a) { return bits(a)==0; @@ -3464,19 +3554,21 @@ public class Short512VectorTests extends AbstractVectorTest { } @Test(dataProvider = "shortTestOpMaskProvider") - static void IS_DEFAULTMaskedShort512VectorTestsSmokeTest(IntFunction<short[]> fa, + static void IS_DEFAULTMaskedShort512VectorTests(IntFunction<short[]> fa, IntFunction<boolean[]> fm) { short[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Short> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - VectorMask<Short> mv = av.test(VectorOperators.IS_DEFAULT, vmask); + 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); + VectorMask<Short> mv = av.test(VectorOperators.IS_DEFAULT, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_DEFAULT(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_DEFAULT(a[i + j])); + } } } } @@ -3502,19 +3594,21 @@ public class Short512VectorTests extends AbstractVectorTest { } @Test(dataProvider = "shortTestOpMaskProvider") - static void IS_NEGATIVEMaskedShort512VectorTestsSmokeTest(IntFunction<short[]> fa, + static void IS_NEGATIVEMaskedShort512VectorTests(IntFunction<short[]> fa, IntFunction<boolean[]> fm) { short[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Short> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - VectorMask<Short> mv = av.test(VectorOperators.IS_NEGATIVE, vmask); + 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); + VectorMask<Short> mv = av.test(VectorOperators.IS_NEGATIVE, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_NEGATIVE(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_NEGATIVE(a[i + j])); + } } } } @@ -5491,7 +5585,7 @@ public class Short512VectorTests extends AbstractVectorTest { static void maskFromToLongShort512VectorTestsSmokeTest(long inputLong) { var vmask = VectorMask.fromLong(SPECIES, inputLong); long outputLong = vmask.toLong(); - Assert.assertEquals(outputLong, inputLong & (((1L << (SPECIES.length() - 1)) << 1) - 1)); + Assert.assertEquals(outputLong, (inputLong & (((0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length())))))); } @DataProvider @@ -5593,5 +5687,12 @@ public class Short512VectorTests extends AbstractVectorTest { VectorSpecies species = av.species().withShape(vsh); assert(species.equals(SPECIES)); } + + @Test + static void MaskAllTrueShort512VectorTestsSmokeTest() { + for (int ic = 0; ic < INVOC_COUNT; ic++) { + Assert.assertEquals(SPECIES.maskAll(true).toLong(), -1L >>> (64 - SPECIES.length())); + } + } } diff --git a/test/jdk/jdk/incubator/vector/Short64VectorTests.java b/test/jdk/jdk/incubator/vector/Short64VectorTests.java index af7dd74ac0e39d78f5d4383cdc8b550071a814be..100bc4e3243aa2a9874ff56534919d4b6d239b39 100644 --- a/test/jdk/jdk/incubator/vector/Short64VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Short64VectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -226,10 +226,10 @@ public class Short64VectorTests extends AbstractVectorTest { } } - static void assertInsertArraysEquals(short[] r, short[] a, short element, int index) { - int i = 0; + static void assertInsertArraysEquals(short[] r, short[] a, short element, int index, int start, int end) { + int i = start; try { - for (; i < a.length; i += 1) { + for (; i < end; i += 1) { if(i%SPECIES.length() == index) { Assert.assertEquals(r[i], element); } else { @@ -1191,6 +1191,10 @@ public class Short64VectorTests extends AbstractVectorTest { return Short.compareUnsigned(a, b) >= 0; } + static short firstNonZero(short a, short b) { + return Short.compare(a, (short) 0) != 0 ? a : b; + } + @Test static void smokeTest1() { ShortVector three = ShortVector.broadcast(SPECIES, (byte)-3); @@ -3206,7 +3210,7 @@ public class Short64VectorTests extends AbstractVectorTest { static short MINReduce(short[] a, int idx) { short res = Short.MAX_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (short)Math.min(res, a[i]); + res = (short) Math.min(res, a[i]); } return res; @@ -3214,8 +3218,8 @@ public class Short64VectorTests extends AbstractVectorTest { static short MINReduceAll(short[] a) { short res = Short.MAX_VALUE; - for (int i = 0; i < a.length; i++) { - res = (short)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (short) Math.min(res, MINReduce(a, i)); } return res; @@ -3237,7 +3241,7 @@ public class Short64VectorTests extends AbstractVectorTest { ra = Short.MAX_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short)Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + ra = (short) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); } } @@ -3247,8 +3251,8 @@ public class Short64VectorTests extends AbstractVectorTest { static short MINReduceMasked(short[] a, int idx, boolean[] mask) { short res = Short.MAX_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (short)Math.min(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (short) Math.min(res, a[i]); } return res; @@ -3256,9 +3260,8 @@ public class Short64VectorTests extends AbstractVectorTest { static short MINReduceAllMasked(short[] a, boolean[] mask) { short res = Short.MAX_VALUE; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (short)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (short) Math.min(res, MINReduceMasked(a, i, mask)); } return res; @@ -3282,7 +3285,7 @@ public class Short64VectorTests extends AbstractVectorTest { ra = Short.MAX_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short)Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + ra = (short) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); } } @@ -3292,7 +3295,7 @@ public class Short64VectorTests extends AbstractVectorTest { static short MAXReduce(short[] a, int idx) { short res = Short.MIN_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (short)Math.max(res, a[i]); + res = (short) Math.max(res, a[i]); } return res; @@ -3300,8 +3303,8 @@ public class Short64VectorTests extends AbstractVectorTest { static short MAXReduceAll(short[] a) { short res = Short.MIN_VALUE; - for (int i = 0; i < a.length; i++) { - res = (short)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (short) Math.max(res, MAXReduce(a, i)); } return res; @@ -3323,7 +3326,7 @@ public class Short64VectorTests extends AbstractVectorTest { ra = Short.MIN_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short)Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + ra = (short) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); } } @@ -3333,8 +3336,8 @@ public class Short64VectorTests extends AbstractVectorTest { static short MAXReduceMasked(short[] a, int idx, boolean[] mask) { short res = Short.MIN_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (short)Math.max(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (short) Math.max(res, a[i]); } return res; @@ -3342,9 +3345,8 @@ public class Short64VectorTests extends AbstractVectorTest { static short MAXReduceAllMasked(short[] a, boolean[] mask) { short res = Short.MIN_VALUE; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (short)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (short) Math.max(res, MAXReduceMasked(a, i, mask)); } return res; @@ -3368,13 +3370,98 @@ public class Short64VectorTests extends AbstractVectorTest { ra = Short.MIN_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short)Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + ra = (short) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); } } assertReductionArraysEqualsMasked(r, ra, a, mask, Short64VectorTests::MAXReduceMasked, Short64VectorTests::MAXReduceAllMasked); } + static short FIRST_NONZEROReduce(short[] a, int idx) { + short res = (short) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + res = firstNonZero(res, a[i]); + } + + return res; + } + + static short FIRST_NONZEROReduceAll(short[] a) { + short res = (short) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); + } + + return res; + } + @Test(dataProvider = "shortUnaryOpProvider") + static void FIRST_NONZEROReduceShort64VectorTests(IntFunction<short[]> fa) { + short[] a = fa.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + short ra = (short) 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); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (short) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + } + } + + assertReductionArraysEquals(r, ra, a, + Short64VectorTests::FIRST_NONZEROReduce, Short64VectorTests::FIRST_NONZEROReduceAll); + } + static short FIRST_NONZEROReduceMasked(short[] a, int idx, boolean[] mask) { + short res = (short) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + if (mask[i % SPECIES.length()]) + res = firstNonZero(res, a[i]); + } + + return res; + } + + static short FIRST_NONZEROReduceAllMasked(short[] a, boolean[] mask) { + short res = (short) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); + } + + return res; + } + @Test(dataProvider = "shortUnaryOpMaskProvider") + static void FIRST_NONZEROReduceShort64VectorTestsMasked(IntFunction<short[]> fa, IntFunction<boolean[]> fm) { + short[] a = fa.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask<Short> vmask = VectorMask.fromArray(SPECIES, mask, 0); + short ra = (short) 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); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (short) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + } + } + + assertReductionArraysEqualsMasked(r, ra, a, mask, + Short64VectorTests::FIRST_NONZEROReduceMasked, Short64VectorTests::FIRST_NONZEROReduceAllMasked); + } static boolean anyTrue(boolean[] a, int idx) { boolean res = false; @@ -3434,13 +3521,16 @@ public class Short64VectorTests extends AbstractVectorTest { short[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { - for (int i = 0; i < a.length; i += SPECIES.length()) { + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - av.withLane(0, (short)4).intoArray(r, i); + av.withLane((j++ & (SPECIES.length()-1)), (short)(65535+i)).intoArray(r, i); } } - assertInsertArraysEquals(r, a, (short)4, 0); + + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { + assertInsertArraysEquals(r, a, (short)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); + } } static boolean testIS_DEFAULT(short a) { return bits(a)==0; @@ -3464,19 +3554,21 @@ public class Short64VectorTests extends AbstractVectorTest { } @Test(dataProvider = "shortTestOpMaskProvider") - static void IS_DEFAULTMaskedShort64VectorTestsSmokeTest(IntFunction<short[]> fa, + static void IS_DEFAULTMaskedShort64VectorTests(IntFunction<short[]> fa, IntFunction<boolean[]> fm) { short[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Short> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - VectorMask<Short> mv = av.test(VectorOperators.IS_DEFAULT, vmask); + 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); + VectorMask<Short> mv = av.test(VectorOperators.IS_DEFAULT, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_DEFAULT(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_DEFAULT(a[i + j])); + } } } } @@ -3502,19 +3594,21 @@ public class Short64VectorTests extends AbstractVectorTest { } @Test(dataProvider = "shortTestOpMaskProvider") - static void IS_NEGATIVEMaskedShort64VectorTestsSmokeTest(IntFunction<short[]> fa, + static void IS_NEGATIVEMaskedShort64VectorTests(IntFunction<short[]> fa, IntFunction<boolean[]> fm) { short[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Short> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - VectorMask<Short> mv = av.test(VectorOperators.IS_NEGATIVE, vmask); + 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); + VectorMask<Short> mv = av.test(VectorOperators.IS_NEGATIVE, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_NEGATIVE(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_NEGATIVE(a[i + j])); + } } } } @@ -5491,7 +5585,7 @@ public class Short64VectorTests extends AbstractVectorTest { static void maskFromToLongShort64VectorTestsSmokeTest(long inputLong) { var vmask = VectorMask.fromLong(SPECIES, inputLong); long outputLong = vmask.toLong(); - Assert.assertEquals(outputLong, inputLong & (((1L << (SPECIES.length() - 1)) << 1) - 1)); + Assert.assertEquals(outputLong, (inputLong & (((0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length())))))); } @DataProvider @@ -5593,5 +5687,12 @@ public class Short64VectorTests extends AbstractVectorTest { VectorSpecies species = av.species().withShape(vsh); assert(species.equals(SPECIES)); } + + @Test + static void MaskAllTrueShort64VectorTestsSmokeTest() { + for (int ic = 0; ic < INVOC_COUNT; ic++) { + Assert.assertEquals(SPECIES.maskAll(true).toLong(), -1L >>> (64 - SPECIES.length())); + } + } } diff --git a/test/jdk/jdk/incubator/vector/ShortMaxVectorTests.java b/test/jdk/jdk/incubator/vector/ShortMaxVectorTests.java index 04681e6985dab62805a50cdb1212a55be84c7665..bd71da2ab8e568e0f7e3f61791b5b17fe911ee61 100644 --- a/test/jdk/jdk/incubator/vector/ShortMaxVectorTests.java +++ b/test/jdk/jdk/incubator/vector/ShortMaxVectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -231,10 +231,10 @@ public class ShortMaxVectorTests extends AbstractVectorTest { } } - static void assertInsertArraysEquals(short[] r, short[] a, short element, int index) { - int i = 0; + static void assertInsertArraysEquals(short[] r, short[] a, short element, int index, int start, int end) { + int i = start; try { - for (; i < a.length; i += 1) { + for (; i < end; i += 1) { if(i%SPECIES.length() == index) { Assert.assertEquals(r[i], element); } else { @@ -1196,6 +1196,10 @@ public class ShortMaxVectorTests extends AbstractVectorTest { return Short.compareUnsigned(a, b) >= 0; } + static short firstNonZero(short a, short b) { + return Short.compare(a, (short) 0) != 0 ? a : b; + } + @Test static void smokeTest1() { ShortVector three = ShortVector.broadcast(SPECIES, (byte)-3); @@ -3211,7 +3215,7 @@ public class ShortMaxVectorTests extends AbstractVectorTest { static short MINReduce(short[] a, int idx) { short res = Short.MAX_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (short)Math.min(res, a[i]); + res = (short) Math.min(res, a[i]); } return res; @@ -3219,8 +3223,8 @@ public class ShortMaxVectorTests extends AbstractVectorTest { static short MINReduceAll(short[] a) { short res = Short.MAX_VALUE; - for (int i = 0; i < a.length; i++) { - res = (short)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (short) Math.min(res, MINReduce(a, i)); } return res; @@ -3242,7 +3246,7 @@ public class ShortMaxVectorTests extends AbstractVectorTest { ra = Short.MAX_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short)Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + ra = (short) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); } } @@ -3252,8 +3256,8 @@ public class ShortMaxVectorTests extends AbstractVectorTest { static short MINReduceMasked(short[] a, int idx, boolean[] mask) { short res = Short.MAX_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (short)Math.min(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (short) Math.min(res, a[i]); } return res; @@ -3261,9 +3265,8 @@ public class ShortMaxVectorTests extends AbstractVectorTest { static short MINReduceAllMasked(short[] a, boolean[] mask) { short res = Short.MAX_VALUE; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (short)Math.min(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (short) Math.min(res, MINReduceMasked(a, i, mask)); } return res; @@ -3287,7 +3290,7 @@ public class ShortMaxVectorTests extends AbstractVectorTest { ra = Short.MAX_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short)Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + ra = (short) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); } } @@ -3297,7 +3300,7 @@ public class ShortMaxVectorTests extends AbstractVectorTest { static short MAXReduce(short[] a, int idx) { short res = Short.MIN_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = (short)Math.max(res, a[i]); + res = (short) Math.max(res, a[i]); } return res; @@ -3305,8 +3308,8 @@ public class ShortMaxVectorTests extends AbstractVectorTest { static short MAXReduceAll(short[] a) { short res = Short.MIN_VALUE; - for (int i = 0; i < a.length; i++) { - res = (short)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (short) Math.max(res, MAXReduce(a, i)); } return res; @@ -3328,7 +3331,7 @@ public class ShortMaxVectorTests extends AbstractVectorTest { ra = Short.MIN_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short)Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + ra = (short) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); } } @@ -3338,8 +3341,8 @@ public class ShortMaxVectorTests extends AbstractVectorTest { static short MAXReduceMasked(short[] a, int idx, boolean[] mask) { short res = Short.MIN_VALUE; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = (short)Math.max(res, a[i]); + if (mask[i % SPECIES.length()]) + res = (short) Math.max(res, a[i]); } return res; @@ -3347,9 +3350,8 @@ public class ShortMaxVectorTests extends AbstractVectorTest { static short MAXReduceAllMasked(short[] a, boolean[] mask) { short res = Short.MIN_VALUE; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = (short)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = (short) Math.max(res, MAXReduceMasked(a, i, mask)); } return res; @@ -3373,13 +3375,98 @@ public class ShortMaxVectorTests extends AbstractVectorTest { ra = Short.MIN_VALUE; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short)Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + ra = (short) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); } } assertReductionArraysEqualsMasked(r, ra, a, mask, ShortMaxVectorTests::MAXReduceMasked, ShortMaxVectorTests::MAXReduceAllMasked); } + static short FIRST_NONZEROReduce(short[] a, int idx) { + short res = (short) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + res = firstNonZero(res, a[i]); + } + + return res; + } + + static short FIRST_NONZEROReduceAll(short[] a) { + short res = (short) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); + } + + return res; + } + @Test(dataProvider = "shortUnaryOpProvider") + static void FIRST_NONZEROReduceShortMaxVectorTests(IntFunction<short[]> fa) { + short[] a = fa.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + short ra = (short) 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); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (short) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + } + } + + assertReductionArraysEquals(r, ra, a, + ShortMaxVectorTests::FIRST_NONZEROReduce, ShortMaxVectorTests::FIRST_NONZEROReduceAll); + } + static short FIRST_NONZEROReduceMasked(short[] a, int idx, boolean[] mask) { + short res = (short) 0; + for (int i = idx; i < (idx + SPECIES.length()); i++) { + if (mask[i % SPECIES.length()]) + res = firstNonZero(res, a[i]); + } + + return res; + } + + static short FIRST_NONZEROReduceAllMasked(short[] a, boolean[] mask) { + short res = (short) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); + } + + return res; + } + @Test(dataProvider = "shortUnaryOpMaskProvider") + static void FIRST_NONZEROReduceShortMaxVectorTestsMasked(IntFunction<short[]> fa, IntFunction<boolean[]> fm) { + short[] a = fa.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask<Short> vmask = VectorMask.fromArray(SPECIES, mask, 0); + short ra = (short) 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); + r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + } + } + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = (short) 0; + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + } + } + + assertReductionArraysEqualsMasked(r, ra, a, mask, + ShortMaxVectorTests::FIRST_NONZEROReduceMasked, ShortMaxVectorTests::FIRST_NONZEROReduceAllMasked); + } static boolean anyTrue(boolean[] a, int idx) { boolean res = false; @@ -3439,13 +3526,16 @@ public class ShortMaxVectorTests extends AbstractVectorTest { short[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { - for (int i = 0; i < a.length; i += SPECIES.length()) { + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - av.withLane(0, (short)4).intoArray(r, i); + av.withLane((j++ & (SPECIES.length()-1)), (short)(65535+i)).intoArray(r, i); } } - assertInsertArraysEquals(r, a, (short)4, 0); + + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { + assertInsertArraysEquals(r, a, (short)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); + } } static boolean testIS_DEFAULT(short a) { return bits(a)==0; @@ -3469,19 +3559,21 @@ public class ShortMaxVectorTests extends AbstractVectorTest { } @Test(dataProvider = "shortTestOpMaskProvider") - static void IS_DEFAULTMaskedShortMaxVectorTestsSmokeTest(IntFunction<short[]> fa, + static void IS_DEFAULTMaskedShortMaxVectorTests(IntFunction<short[]> fa, IntFunction<boolean[]> fm) { short[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Short> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - VectorMask<Short> mv = av.test(VectorOperators.IS_DEFAULT, vmask); + 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); + VectorMask<Short> mv = av.test(VectorOperators.IS_DEFAULT, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_DEFAULT(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_DEFAULT(a[i + j])); + } } } } @@ -3507,19 +3599,21 @@ public class ShortMaxVectorTests extends AbstractVectorTest { } @Test(dataProvider = "shortTestOpMaskProvider") - static void IS_NEGATIVEMaskedShortMaxVectorTestsSmokeTest(IntFunction<short[]> fa, + static void IS_NEGATIVEMaskedShortMaxVectorTests(IntFunction<short[]> fa, IntFunction<boolean[]> fm) { short[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<Short> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - VectorMask<Short> mv = av.test(VectorOperators.IS_NEGATIVE, vmask); + 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); + VectorMask<Short> mv = av.test(VectorOperators.IS_NEGATIVE, vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_NEGATIVE(a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && testIS_NEGATIVE(a[i + j])); + } } } } @@ -5582,5 +5676,12 @@ public class ShortMaxVectorTests extends AbstractVectorTest { VectorSpecies species = av.species().withShape(vsh); assert(species.equals(SPECIES)); } + + @Test + static void MaskAllTrueShortMaxVectorTestsSmokeTest() { + for (int ic = 0; ic < INVOC_COUNT; ic++) { + Assert.assertEquals(SPECIES.maskAll(true).toLong(), -1L >>> (64 - SPECIES.length())); + } + } } diff --git a/test/jdk/jdk/incubator/vector/VectorMaxConversionTests.java b/test/jdk/jdk/incubator/vector/VectorMaxConversionTests.java index bab60cc684a4cb34f0c31382da74988278d79a57..6b45043cc629701fa51b8d7f71daf3785e82655f 100644 --- a/test/jdk/jdk/incubator/vector/VectorMaxConversionTests.java +++ b/test/jdk/jdk/incubator/vector/VectorMaxConversionTests.java @@ -40,6 +40,18 @@ import java.util.List; * VectorMaxConversionTests */ +/* + * @test + * @bug 8281544 + * @summary Test that ZGC and vectorapi with KNL work together. + * @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:+IgnoreUnrecognizedVMOptions + * VectorMaxConversionTests + */ + @Test public class VectorMaxConversionTests extends AbstractVectorConversionTest { diff --git a/test/jdk/jdk/incubator/vector/VectorReshapeTests.java b/test/jdk/jdk/incubator/vector/VectorReshapeTests.java index 01dcc4caf85a0858a533934143150b403d5fd82f..36306706037317a4c639983d4eb272ae41222dd0 100644 --- a/test/jdk/jdk/incubator/vector/VectorReshapeTests.java +++ b/test/jdk/jdk/incubator/vector/VectorReshapeTests.java @@ -39,7 +39,7 @@ import jdk.incubator.vector.VectorSpecies; * @test * @modules jdk.incubator.vector * @modules java.base/jdk.internal.vm.annotation - * @run testng/othervm --add-opens jdk.incubator.vector/jdk.incubator.vector=ALL-UNNAMED + * @run testng/othervm/timeout=240 --add-opens jdk.incubator.vector/jdk.incubator.vector=ALL-UNNAMED * -XX:-TieredCompilation VectorReshapeTests */ @@ -3334,6 +3334,327 @@ public class VectorReshapeTests { } } + @ForceInline + static + void testVectorUCastByteToShort(VectorSpecies<Byte> a, VectorSpecies<Short> b, byte[] input, short[] output) { + assert(input.length == a.length()); + assert(output.length == b.length()); + + ByteVector av = ByteVector.fromArray(a, input, 0); + ShortVector bv = (ShortVector) av.convertShape(VectorOperators.ZERO_EXTEND_B2S, b, 0); + bv.intoArray(output, 0); + + for (int i = 0; i < Math.min(input.length, output.length); i++) { + Assert.assertEquals(output[i], Byte.toUnsignedLong(input[i])); + } + for(int i = input.length; i < output.length; i++) { + Assert.assertEquals(output[i], (short)0); + } + } + + @ForceInline + static + void testVectorUCastByteToInt(VectorSpecies<Byte> a, VectorSpecies<Integer> b, byte[] input, int[] output) { + assert(input.length == a.length()); + assert(output.length == b.length()); + + ByteVector av = ByteVector.fromArray(a, input, 0); + IntVector bv = (IntVector) av.convertShape(VectorOperators.ZERO_EXTEND_B2I, b, 0); + bv.intoArray(output, 0); + + for (int i = 0; i < Math.min(input.length, output.length); i++) { + Assert.assertEquals(output[i], Byte.toUnsignedLong(input[i])); + } + for(int i = input.length; i < output.length; i++) { + Assert.assertEquals(output[i], (int)0); + } + } + + @ForceInline + static + void testVectorUCastByteToLong(VectorSpecies<Byte> a, VectorSpecies<Long> b, byte[] input, long[] output) { + assert(input.length == a.length()); + assert(output.length == b.length()); + + ByteVector av = ByteVector.fromArray(a, input, 0); + LongVector bv = (LongVector) av.convertShape(VectorOperators.ZERO_EXTEND_B2L, b, 0); + bv.intoArray(output, 0); + + for (int i = 0; i < Math.min(input.length, output.length); i++) { + Assert.assertEquals(output[i], Byte.toUnsignedLong(input[i])); + } + for(int i = input.length; i < output.length; i++) { + Assert.assertEquals(output[i], (long)0); + } + } + + @ForceInline + static + void testVectorUCastShortToInt(VectorSpecies<Short> a, VectorSpecies<Integer> b, short[] input, int[] output) { + assert(input.length == a.length()); + assert(output.length == b.length()); + + ShortVector av = ShortVector.fromArray(a, input, 0); + IntVector bv = (IntVector) av.convertShape(VectorOperators.ZERO_EXTEND_S2I, b, 0); + bv.intoArray(output, 0); + + for (int i = 0; i < Math.min(input.length, output.length); i++) { + Assert.assertEquals(output[i], Short.toUnsignedLong(input[i])); + } + for(int i = input.length; i < output.length; i++) { + Assert.assertEquals(output[i], (int)0); + } + } + + @ForceInline + static + void testVectorUCastShortToLong(VectorSpecies<Short> a, VectorSpecies<Long> b, short[] input, long[] output) { + assert(input.length == a.length()); + assert(output.length == b.length()); + + ShortVector av = ShortVector.fromArray(a, input, 0); + LongVector bv = (LongVector) av.convertShape(VectorOperators.ZERO_EXTEND_S2L, b, 0); + bv.intoArray(output, 0); + + for (int i = 0; i < Math.min(input.length, output.length); i++) { + Assert.assertEquals(output[i], Short.toUnsignedLong(input[i])); + } + for(int i = input.length; i < output.length; i++) { + Assert.assertEquals(output[i], (long)0); + } + } + + @ForceInline + static + void testVectorUCastIntToLong(VectorSpecies<Integer> a, VectorSpecies<Long> b, int[] input, long[] output) { + assert(input.length == a.length()); + assert(output.length == b.length()); + + IntVector av = IntVector.fromArray(a, input, 0); + LongVector bv = (LongVector) av.convertShape(VectorOperators.ZERO_EXTEND_I2L, b, 0); + bv.intoArray(output, 0); + + for (int i = 0; i < Math.min(input.length, output.length); i++) { + Assert.assertEquals(output[i], Integer.toUnsignedLong(input[i])); + } + for(int i = input.length; i < output.length; i++) { + Assert.assertEquals(output[i], (long)0); + } + } + + @Test(dataProvider = "byteUnaryOpProvider") + static void testUCastFromByte(IntFunction<byte[]> fa) { + byte[] bin64 = fa.apply(bspec64.length()); + byte[] bin128 = fa.apply(bspec128.length()); + byte[] bin256 = fa.apply(bspec256.length()); + byte[] bin512 = fa.apply(bspec512.length()); + + short[] sout64 = new short[sspec64.length()]; + short[] sout128 = new short[sspec128.length()]; + short[] sout256 = new short[sspec256.length()]; + short[] sout512 = new short[sspec512.length()]; + + int[] iout64 = new int[ispec64.length()]; + int[] iout128 = new int[ispec128.length()]; + int[] iout256 = new int[ispec256.length()]; + int[] iout512 = new int[ispec512.length()]; + + long[] lout64 = new long[lspec64.length()]; + long[] lout128 = new long[lspec128.length()]; + long[] lout256 = new long[lspec256.length()]; + long[] lout512 = new long[lspec512.length()]; + + for (int i = 0; i < NUM_ITER; i++) { + // B2S exact fit + testVectorUCastByteToShort(bspec64, sspec128, bin64, sout128); + testVectorUCastByteToShort(bspec128, sspec256, bin128, sout256); + testVectorUCastByteToShort(bspec256, sspec512, bin256, sout512); + + // B2S expansion + testVectorUCastByteToShort(bspec64, sspec64, bin64, sout64); + testVectorUCastByteToShort(bspec128, sspec128, bin128, sout128); + testVectorUCastByteToShort(bspec256, sspec256, bin256, sout256); + testVectorUCastByteToShort(bspec512, sspec512, bin512, sout512); + + testVectorUCastByteToShort(bspec128, sspec64, bin128, sout64); + testVectorUCastByteToShort(bspec256, sspec128, bin256, sout128); + testVectorUCastByteToShort(bspec512, sspec256, bin512, sout256); + + testVectorUCastByteToShort(bspec256, sspec64, bin256, sout64); + testVectorUCastByteToShort(bspec512, sspec128, bin512, sout128); + + testVectorUCastByteToShort(bspec512, sspec64, bin512, sout64); + + // B2S contraction + testVectorUCastByteToShort(bspec64, sspec256, bin64, sout256); + testVectorUCastByteToShort(bspec128, sspec512, bin128, sout512); + + testVectorUCastByteToShort(bspec64, sspec512, bin64, sout512); + + // B2I exact fit + testVectorUCastByteToInt(bspec64, ispec256, bin64, iout256); + testVectorUCastByteToInt(bspec128, ispec512, bin128, iout512); + + // B2I expansion + testVectorUCastByteToInt(bspec64, ispec128, bin64, iout128); + testVectorUCastByteToInt(bspec128, ispec256, bin128, iout256); + testVectorUCastByteToInt(bspec256, ispec512, bin256, iout512); + + testVectorUCastByteToInt(bspec64, ispec64, bin64, iout64); + testVectorUCastByteToInt(bspec128, ispec128, bin128, iout128); + testVectorUCastByteToInt(bspec256, ispec256, bin256, iout256); + testVectorUCastByteToInt(bspec512, ispec512, bin512, iout512); + + testVectorUCastByteToInt(bspec128, ispec64, bin128, iout64); + testVectorUCastByteToInt(bspec256, ispec128, bin256, iout128); + testVectorUCastByteToInt(bspec512, ispec256, bin512, iout256); + + testVectorUCastByteToInt(bspec256, ispec64, bin256, iout64); + testVectorUCastByteToInt(bspec512, ispec128, bin512, iout128); + + testVectorUCastByteToInt(bspec512, ispec64, bin512, iout64); + + // B2I contraction + testVectorUCastByteToInt(bspec64, ispec512, bin64, iout512); + + // B2L exact fit + testVectorUCastByteToLong(bspec64, lspec512, bin64, lout512); + + // B2L expansion + testVectorUCastByteToLong(bspec64, lspec256, bin64, lout256); + testVectorUCastByteToLong(bspec128, lspec512, bin128, lout512); + + testVectorUCastByteToLong(bspec64, lspec128, bin64, lout128); + testVectorUCastByteToLong(bspec128, lspec256, bin128, lout256); + testVectorUCastByteToLong(bspec256, lspec512, bin256, lout512); + + testVectorUCastByteToLong(bspec64, lspec64, bin64, lout64); + testVectorUCastByteToLong(bspec128, lspec128, bin128, lout128); + testVectorUCastByteToLong(bspec256, lspec256, bin256, lout256); + testVectorUCastByteToLong(bspec512, lspec512, bin512, lout512); + + testVectorUCastByteToLong(bspec128, lspec64, bin128, lout64); + testVectorUCastByteToLong(bspec256, lspec128, bin256, lout128); + testVectorUCastByteToLong(bspec512, lspec256, bin512, lout256); + + testVectorUCastByteToLong(bspec256, lspec64, bin256, lout64); + testVectorUCastByteToLong(bspec512, lspec128, bin512, lout128); + + testVectorUCastByteToLong(bspec512, lspec64, bin512, lout64); + } + } + + @Test(dataProvider = "shortUnaryOpProvider") + static void testUCastFromShort(IntFunction<short[]> fa) { + short[] sin64 = fa.apply(sspec64.length()); + short[] sin128 = fa.apply(sspec128.length()); + short[] sin256 = fa.apply(sspec256.length()); + short[] sin512 = fa.apply(sspec512.length()); + + int[] iout64 = new int[ispec64.length()]; + int[] iout128 = new int[ispec128.length()]; + int[] iout256 = new int[ispec256.length()]; + int[] iout512 = new int[ispec512.length()]; + + long[] lout64 = new long[lspec64.length()]; + long[] lout128 = new long[lspec128.length()]; + long[] lout256 = new long[lspec256.length()]; + long[] lout512 = new long[lspec512.length()]; + + for (int i = 0; i < NUM_ITER; i++) { + // S2I exact fit + testVectorUCastShortToInt(sspec64, ispec128, sin64, iout128); + testVectorUCastShortToInt(sspec128, ispec256, sin128, iout256); + testVectorUCastShortToInt(sspec256, ispec512, sin256, iout512); + + // S2I expansion + testVectorUCastShortToInt(sspec64, ispec64, sin64, iout64); + testVectorUCastShortToInt(sspec128, ispec128, sin128, iout128); + testVectorUCastShortToInt(sspec256, ispec256, sin256, iout256); + testVectorUCastShortToInt(sspec512, ispec512, sin512, iout512); + + testVectorUCastShortToInt(sspec128, ispec64, sin128, iout64); + testVectorUCastShortToInt(sspec256, ispec128, sin256, iout128); + testVectorUCastShortToInt(sspec512, ispec256, sin512, iout256); + + testVectorUCastShortToInt(sspec256, ispec64, sin256, iout64); + testVectorUCastShortToInt(sspec512, ispec128, sin512, iout128); + + testVectorUCastShortToInt(sspec512, ispec64, sin512, iout64); + + // S2I contraction + testVectorUCastShortToInt(sspec64, ispec256, sin64, iout256); + testVectorUCastShortToInt(sspec128, ispec512, sin128, iout512); + + testVectorUCastShortToInt(sspec64, ispec512, sin64, iout512); + + // S2L exact fit + testVectorUCastShortToLong(sspec64, lspec256, sin64, lout256); + testVectorUCastShortToLong(sspec128, lspec512, sin128, lout512); + + // S2L expansion + testVectorUCastShortToLong(sspec64, lspec128, sin64, lout128); + testVectorUCastShortToLong(sspec128, lspec256, sin128, lout256); + testVectorUCastShortToLong(sspec256, lspec512, sin256, lout512); + + testVectorUCastShortToLong(sspec64, lspec64, sin64, lout64); + testVectorUCastShortToLong(sspec128, lspec128, sin128, lout128); + testVectorUCastShortToLong(sspec256, lspec256, sin256, lout256); + testVectorUCastShortToLong(sspec512, lspec512, sin512, lout512); + + testVectorUCastShortToLong(sspec128, lspec64, sin128, lout64); + testVectorUCastShortToLong(sspec256, lspec128, sin256, lout128); + testVectorUCastShortToLong(sspec512, lspec256, sin512, lout256); + + testVectorUCastShortToLong(sspec256, lspec64, sin256, lout64); + testVectorUCastShortToLong(sspec512, lspec128, sin512, lout128); + + testVectorUCastShortToLong(sspec512, lspec64, sin512, lout64); + + // S2L contraction + testVectorUCastShortToLong(sspec64, lspec512, sin64, lout512); + } + } + + @Test(dataProvider = "intUnaryOpProvider") + static void testUCastFromInt(IntFunction<int[]> fa) { + int[] iin64 = fa.apply(ispec64.length()); + int[] iin128 = fa.apply(ispec128.length()); + int[] iin256 = fa.apply(ispec256.length()); + int[] iin512 = fa.apply(ispec512.length()); + + long[] lout64 = new long[lspec64.length()]; + long[] lout128 = new long[lspec128.length()]; + long[] lout256 = new long[lspec256.length()]; + long[] lout512 = new long[lspec512.length()]; + + // I2L exact fit + testVectorUCastIntToLong(ispec64, lspec128, iin64, lout128); + testVectorUCastIntToLong(ispec128, lspec256, iin128, lout256); + testVectorUCastIntToLong(ispec256, lspec512, iin256, lout512); + + // I2L expansion + testVectorUCastIntToLong(ispec64, lspec64, iin64, lout64); + testVectorUCastIntToLong(ispec128, lspec128, iin128, lout128); + testVectorUCastIntToLong(ispec256, lspec256, iin256, lout256); + testVectorUCastIntToLong(ispec512, lspec512, iin512, lout512); + + testVectorUCastIntToLong(ispec128, lspec64, iin128, lout64); + testVectorUCastIntToLong(ispec256, lspec128, iin256, lout128); + testVectorUCastIntToLong(ispec512, lspec256, iin512, lout256); + + testVectorUCastIntToLong(ispec256, lspec64, iin256, lout64); + testVectorUCastIntToLong(ispec512, lspec128, iin512, lout128); + + testVectorUCastIntToLong(ispec512, lspec64, iin512, lout64); + + // I2L contraction + testVectorUCastIntToLong(ispec64, lspec256, iin64, lout256); + testVectorUCastIntToLong(ispec128, lspec512, iin128, lout512); + + testVectorUCastIntToLong(ispec64, lspec512, iin64, lout512); + } + static void testVectorCastByteMaxToByte(VectorSpecies<Byte> a, VectorSpecies<Byte> b, byte[] input, byte[] output) { diff --git a/test/jdk/jdk/incubator/vector/clean.sh b/test/jdk/jdk/incubator/vector/clean.sh index f889a9136238330a6b43263f707e802717a75b88..7c177d800164b7df1372eac7793ab09e4f1c73de 100644 --- a/test/jdk/jdk/incubator/vector/clean.sh +++ b/test/jdk/jdk/incubator/vector/clean.sh @@ -1,6 +1,6 @@ #!/bin/bash # -# Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. +# 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 @@ -24,4 +24,4 @@ # questions. # -rm -rf *.class build.log test-output +rm -rf build.log diff --git a/test/jdk/jdk/incubator/vector/config.sh b/test/jdk/jdk/incubator/vector/config.sh index c1447b2e9fdc13f08b0301c435f17542451812cc..15bfe647c3a441b1b88b29c13b6fdf9b0d500a80 100644 --- a/test/jdk/jdk/incubator/vector/config.sh +++ b/test/jdk/jdk/incubator/vector/config.sh @@ -1,6 +1,6 @@ #!/bin/bash # -# Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. +# 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 @@ -35,9 +35,6 @@ SPP_CLASSNAME="build.tools.spp.Spp" SEPARATOR=":" TYPEPREFIX="" TEMPLATE_FILE="unit_tests.template" -TESTNG_JAR="${TESTNG_PLUGIN}/plugins/org.testng.source_6.13.1.r201712040515.jar" -TESTNG_RUN_JAR="${TESTNG_PLUGIN}/plugins/org.testng_6.13.1.r201712040515.jar" -JCOMMANDER_JAR="${TESTNG_PLUGIN}/plugins/com.beust.jcommander_1.72.0.jar" TEST_ITER_COUNT=100 PERF_TEMPLATE_FILE="perf_tests.template" diff --git a/test/jdk/jdk/incubator/vector/gen-template.sh b/test/jdk/jdk/incubator/vector/gen-template.sh index 544cd0dc317fe6e022377a77084b70e4de08cadf..51fb155fd84cd60219e93c5d3b2c487c836fcda7 100644 --- a/test/jdk/jdk/incubator/vector/gen-template.sh +++ b/test/jdk/jdk/incubator/vector/gen-template.sh @@ -55,17 +55,13 @@ compare_template="Compare" compare_masked_template="Compare-Masked" compare_broadcast_template="Compare-Broadcast" reduction_scalar="Reduction-Scalar-op" -reduction_scalar_min="Reduction-Scalar-Min-op" -reduction_scalar_max="Reduction-Scalar-Max-op" +reduction_scalar_func="Reduction-Scalar-op-func" reduction_scalar_masked="Reduction-Scalar-Masked-op" -reduction_scalar_min_masked="Reduction-Scalar-Masked-Min-op" -reduction_scalar_max_masked="Reduction-Scalar-Masked-Max-op" +reduction_scalar_masked_func="Reduction-Scalar-Masked-op-func" reduction_op="Reduction-op" -reduction_op_min="Reduction-Min-op" -reduction_op_max="Reduction-Max-op" +reduction_op_func="Reduction-op-func" reduction_op_masked="Reduction-Masked-op" -reduction_op_min_masked="Reduction-Masked-Min-op" -reduction_op_max_masked="Reduction-Masked-Max-op" +reduction_op_masked_func="Reduction-Masked-op-func" unary_math_template="Unary-op-math" binary_math_template="Binary-op-math" binary_math_broadcast_template="Binary-Broadcast-op-math" @@ -337,20 +333,12 @@ function gen_reduction_op { gen_op_tmpl $reduction_op_masked "$@" } -function gen_reduction_op_min { +function gen_reduction_op_func { echo "Generating reduction op $1 ($2)..." - gen_op_tmpl $reduction_scalar_min "$@" - gen_op_tmpl $reduction_op_min "$@" - gen_op_tmpl $reduction_scalar_min_masked "$@" - gen_op_tmpl $reduction_op_min_masked "$@" -} - -function gen_reduction_op_max { - echo "Generating reduction op $1 ($2)..." - gen_op_tmpl $reduction_scalar_max "$@" - gen_op_tmpl $reduction_op_max "$@" - gen_op_tmpl $reduction_scalar_max_masked "$@" - gen_op_tmpl $reduction_op_max_masked "$@" + gen_op_tmpl $reduction_scalar_func "$@" + gen_op_tmpl $reduction_op_func "$@" + gen_op_tmpl $reduction_scalar_masked_func "$@" + gen_op_tmpl $reduction_op_masked_func "$@" } function gen_bool_reduction_op { @@ -462,9 +450,9 @@ gen_reduction_op "OR" "|" "BITWISE" "0" gen_reduction_op "XOR" "^" "BITWISE" "0" gen_reduction_op "ADD" "+" "" "0" gen_reduction_op "MUL" "*" "" "1" -gen_reduction_op_min "MIN" "" "" "\$Wideboxtype\$.\$MaxValue\$" -gen_reduction_op_max "MAX" "" "" "\$Wideboxtype\$.\$MinValue\$" -#gen_reduction_op "reduce_FIRST_NONZERO" "lanewise_FIRST_NONZERO" "{#if[FP]?Double.doubleToLongBits}(a)=0?a:b" "" "1" +gen_reduction_op_func "MIN" "(\$type\$) Math.min" "" "\$Wideboxtype\$.\$MaxValue\$" +gen_reduction_op_func "MAX" "(\$type\$) Math.max" "" "\$Wideboxtype\$.\$MinValue\$" +gen_reduction_op_func "FIRST_NONZERO" "firstNonZero" "" "(\$type\$) 0" # Boolean reductions. gen_bool_reduction_op "anyTrue" "|" "BITWISE" "false" diff --git a/test/jdk/jdk/incubator/vector/gen-tests.sh b/test/jdk/jdk/incubator/vector/gen-tests.sh index 0056f54868d6913e67dd2d0813b43373c4874553..d02f0c519fe8fe593635b35e617bf2da4b0c6b61 100644 --- a/test/jdk/jdk/incubator/vector/gen-tests.sh +++ b/test/jdk/jdk/incubator/vector/gen-tests.sh @@ -1,6 +1,6 @@ #!/bin/bash # -# Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. +# 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 @@ -28,20 +28,10 @@ # You can regenerate the source files, # and you can clean them up. # FIXME: Move this script under $REPO/make/gensrc/ -list_mech_gen() { - ( # List MG files physically present - grep -il 'mechanically generated.*do not edit' $(find * -name \*.java -print) - # List MG files currently deleted (via --clean) - hg status -nd . - ) | egrep '(^|/)(Byte|Short|Int|Long|Float|Double)(Scalar|([0-9Max]+Vector)).*\.java$' -} case $* in '') CLASS_FILTER='*';; --generate*) CLASS_FILTER=${2-'*'};; ---clean) MG=$(list_mech_gen); set -x; rm -f $MG; exit;; ---revert) MG=$(list_mech_gen); set -x; hg revert $MG; exit;; ---list) list_mech_gen; exit;; ---help|*) echo "Usage: $0 [--generate [file] | --clean | --revert | --list]"; exit 1;; +--help|*) echo "Usage: $0 [--generate [file]]"; exit 1;; esac . config.sh diff --git a/test/jdk/jdk/incubator/vector/run-tests.sh b/test/jdk/jdk/incubator/vector/run-tests.sh deleted file mode 100644 index 0669a97c2e6bbe63c3690ba95b864e10b7b802fb..0000000000000000000000000000000000000000 --- a/test/jdk/jdk/incubator/vector/run-tests.sh +++ /dev/null @@ -1,86 +0,0 @@ -#!/bin/bash -# -# 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. 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. -# - -. config.sh - -POSITIONAL=() -while [[ $# -gt 0 ]] -do -key="$1" - -TESTS="" -DISABLE_VECTOR_INTRINSICS=false -case $key in - -t|--tests) - TESTS="$2" - echo "Tests set to $TESTS" - shift # past argument - shift # past value - ;; - -d|--disable-vector-intrinsics) - DISABLE_VECTOR_INTRINSICS=true - echo "Warning: Disabling Vector intrinsics..." - shift # past argument - ;; - *) # unknown option - POSITIONAL+=("$1") # save it in an array for later - shift # past argument - ;; -esac -done -set -- "${POSITIONAL[@]}" # restore positional parameters - - -if [ "$TESTS" == "" ]; then - # Run all the tests by default. - TESTS="Byte64VectorTests,Byte128VectorTests,Byte256VectorTests,Byte512VectorTests," - TESTS+="Int64VectorTests,Int128VectorTests,Int256VectorTests,Int512VectorTests," - TESTS+="Long64VectorTests,Long128VectorTests,Long256VectorTests,Long512VectorTests," - TESTS+="Short64VectorTests,Short128VectorTests,Short256VectorTests,Short512VectorTests," - TESTS+="Double64VectorTests,Double128VectorTests,Double256VectorTests,Double512VectorTests," - TESTS+="Float64VectorTests,Float128VectorTests,Float256VectorTests,Float512VectorTests" -fi - -# Get Java flags. -JAVA_FLAGS="-XX:-TieredCompilation" -if [ "$DISABLE_VECTOR_INTRINSICS" == "true" ]; then - JAVA_FLAGS+=" -XX:-UseVectorApiIntrinsics" -fi - -LogRun false "Running tests $(date)\n" -LogRun true "Running the following tests:\n" -LogRun true "${TESTS}\n" -LogRun false "${JAVA} -cp \"${VECTORTESTS_HOME_CP}${SEPARATOR}${TESTNG_RUN_JAR}${SEPARATOR}${JCOMMANDER_JAR}\" ${JAVA_FLAGS} --add-modules jdk.incubator.vector --add-opens jdk.incubator.vector/jdk.incubator.vector=ALL-UNNAMED org.testng.TestNG -testclass $TESTS" - -# Actual TestNG run. -time ${JAVA} -cp "${VECTORTESTS_HOME_CP}${SEPARATOR}${TESTNG_RUN_JAR}${SEPARATOR}${JCOMMANDER_JAR}" \ - ${JAVA_FLAGS} \ - --add-modules jdk.incubator.vector \ - --add-opens jdk.incubator.vector/jdk.incubator.vector=ALL-UNNAMED \ - -Djdk.incubator.vector.test.loop-iterations=${TEST_ITER_COUNT} \ - org.testng.TestNG -testclass $TESTS -LogRun true "Tests run complete. Please look at test-output/index.html to visualize the results.\n" - diff --git a/test/jdk/jdk/incubator/vector/templates/Kernel-Reduction-Masked-Max-op.template b/test/jdk/jdk/incubator/vector/templates/Kernel-Reduction-Masked-Max-op.template deleted file mode 100644 index d317aaf4f8a5f911dac058afe85692e88066f508..0000000000000000000000000000000000000000 --- a/test/jdk/jdk/incubator/vector/templates/Kernel-Reduction-Masked-Max-op.template +++ /dev/null @@ -1,21 +0,0 @@ - $type$[] a = fa.apply(SPECIES.length()); - $type$[] r = fr.apply(SPECIES.length()); - boolean[] mask = fm.apply(SPECIES.length()); - VectorMask<$Wideboxtype$> vmask = VectorMask.fromArray(SPECIES, mask, 0); - $type$ ra = [[TEST_INIT]]; - - 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); - r[i] = av.reduceLanes(VectorOperators.[[TEST]], vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = [[TEST_INIT]]; - for (int i = 0; i < a.length; i += SPECIES.length()) { - $abstractvectortype$ av = $abstractvectortype$.fromArray(SPECIES, a, i); - ra = ($type$)Math.max(ra, av.reduceLanes(VectorOperators.[[TEST]], vmask)); - } - } - diff --git a/test/jdk/jdk/incubator/vector/templates/Kernel-Reduction-Masked-Min-op.template b/test/jdk/jdk/incubator/vector/templates/Kernel-Reduction-Masked-op-func.template similarity index 90% rename from test/jdk/jdk/incubator/vector/templates/Kernel-Reduction-Masked-Min-op.template rename to test/jdk/jdk/incubator/vector/templates/Kernel-Reduction-Masked-op-func.template index 041b61da0e17f7f8fe580bf616abcb9f49194417..bf03a4d043059d86d22a68e7b940955973c124e6 100644 --- a/test/jdk/jdk/incubator/vector/templates/Kernel-Reduction-Masked-Min-op.template +++ b/test/jdk/jdk/incubator/vector/templates/Kernel-Reduction-Masked-op-func.template @@ -15,7 +15,7 @@ ra = [[TEST_INIT]]; for (int i = 0; i < a.length; i += SPECIES.length()) { $abstractvectortype$ av = $abstractvectortype$.fromArray(SPECIES, a, i); - ra = ($type$)Math.min(ra, av.reduceLanes(VectorOperators.[[TEST]], vmask)); + ra = [[TEST_OP]](ra, av.reduceLanes(VectorOperators.[[TEST]], vmask)); } } diff --git a/test/jdk/jdk/incubator/vector/templates/Kernel-Reduction-Min-op.template b/test/jdk/jdk/incubator/vector/templates/Kernel-Reduction-Min-op.template deleted file mode 100644 index d6d53e4ef21fdf81286d3bde0b8ad38873ecdf5e..0000000000000000000000000000000000000000 --- a/test/jdk/jdk/incubator/vector/templates/Kernel-Reduction-Min-op.template +++ /dev/null @@ -1,19 +0,0 @@ - $type$[] a = fa.apply(SPECIES.length()); - $type$[] r = fr.apply(SPECIES.length()); - $type$ ra = [[TEST_INIT]]; - - 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); - r[i] = av.reduceLanes(VectorOperators.[[TEST]]); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = [[TEST_INIT]]; - for (int i = 0; i < a.length; i += SPECIES.length()) { - $abstractvectortype$ av = $abstractvectortype$.fromArray(SPECIES, a, i); - ra = ($type$)Math.min(ra, av.reduceLanes(VectorOperators.[[TEST]])); - } - } - diff --git a/test/jdk/jdk/incubator/vector/templates/Kernel-Reduction-Max-op.template b/test/jdk/jdk/incubator/vector/templates/Kernel-Reduction-op-func.template similarity index 89% rename from test/jdk/jdk/incubator/vector/templates/Kernel-Reduction-Max-op.template rename to test/jdk/jdk/incubator/vector/templates/Kernel-Reduction-op-func.template index 3af5b8cfde9e727da0b7bc0fca707dba2d6bb1c5..7082ff0795e81afe08dfc3c5c595de06cc7b4cbb 100644 --- a/test/jdk/jdk/incubator/vector/templates/Kernel-Reduction-Max-op.template +++ b/test/jdk/jdk/incubator/vector/templates/Kernel-Reduction-op-func.template @@ -13,7 +13,7 @@ ra = [[TEST_INIT]]; for (int i = 0; i < a.length; i += SPECIES.length()) { $abstractvectortype$ av = $abstractvectortype$.fromArray(SPECIES, a, i); - ra = ($type$)Math.max(ra, av.reduceLanes(VectorOperators.[[TEST]])); + ra = [[TEST_OP]](ra, av.reduceLanes(VectorOperators.[[TEST]])); } } diff --git a/test/jdk/jdk/incubator/vector/templates/Kernel-With-Op.template b/test/jdk/jdk/incubator/vector/templates/Kernel-With-Op.template index 11bdbf234cf415bf91898eae57044e1c0b06bdce..95d74b848601224f9294a67fe3bf23f1cbadecc7 100644 --- a/test/jdk/jdk/incubator/vector/templates/Kernel-With-Op.template +++ b/test/jdk/jdk/incubator/vector/templates/Kernel-With-Op.template @@ -2,9 +2,9 @@ $type$[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { - for (int i = 0; i < a.length; i += SPECIES.length()) { + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { $abstractvectortype$ av = $abstractvectortype$.fromArray(SPECIES, a, i); - av.withLane(0, ($type$)4).intoArray(r, i); + av.withLane((j++ \& (SPECIES.length()-1)), ($type$)(65535+i)).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 a75a6842bd316fe558854d1fe6dda651453c5a06..d72ce5bd0858d8061f3d457fa92d28b0d13d99e8 100644 --- a/test/jdk/jdk/incubator/vector/templates/Unit-Miscellaneous.template +++ b/test/jdk/jdk/incubator/vector/templates/Unit-Miscellaneous.template @@ -499,7 +499,7 @@ static void maskFromToLong$vectorteststype$SmokeTest(long inputLong) { var vmask = VectorMask.fromLong(SPECIES, inputLong); long outputLong = vmask.toLong(); - Assert.assertEquals(outputLong, inputLong & (((1L << (SPECIES.length() - 1)) << 1) - 1)); + Assert.assertEquals(outputLong, (inputLong & (((0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length())))))); } #end[!MaxBit] @@ -602,3 +602,10 @@ VectorSpecies species = av.species().withShape(vsh); assert(species.equals(SPECIES)); } + + @Test + static void MaskAllTrue$vectorteststype$SmokeTest() { + for (int ic = 0; ic < INVOC_COUNT; ic++) { + Assert.assertEquals(SPECIES.maskAll(true).toLong(), -1L >>> (64 - SPECIES.length())); + } + } diff --git a/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-Masked-Min-op.template b/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-Masked-Min-op.template deleted file mode 100644 index 70ffa79bf6fbd050211d7ced2dc90b8eb79dd90c..0000000000000000000000000000000000000000 --- a/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-Masked-Min-op.template +++ /dev/null @@ -1,6 +0,0 @@ - @Test(dataProvider = "$type$UnaryOpMaskProvider") - static void [[TEST]]Reduce$vectorteststype$Masked(IntFunction<$type$[]> fa, IntFunction<boolean[]> fm) { -[[KERNEL]] - assertReductionArraysEqualsMasked(r, ra, a, mask, - $vectorteststype$::[[TEST]]ReduceMasked, $vectorteststype$::[[TEST]]ReduceAllMasked); - } diff --git a/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-Masked-Max-op.template b/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-Masked-op-func.template similarity index 100% rename from test/jdk/jdk/incubator/vector/templates/Unit-Reduction-Masked-Max-op.template rename to test/jdk/jdk/incubator/vector/templates/Unit-Reduction-Masked-op-func.template diff --git a/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-Min-op.template b/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-Min-op.template deleted file mode 100644 index b86248f3f09f65cddf068ea5a54b9706db4bddf9..0000000000000000000000000000000000000000 --- a/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-Min-op.template +++ /dev/null @@ -1,6 +0,0 @@ - @Test(dataProvider = "$type$UnaryOpProvider") - static void [[TEST]]Reduce$vectorteststype$(IntFunction<$type$[]> fa) { -[[KERNEL]] - assertReductionArraysEquals(r, ra, a, - $vectorteststype$::[[TEST]]Reduce, $vectorteststype$::[[TEST]]ReduceAll); - } diff --git a/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-Scalar-Masked-Min-op.template b/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-Scalar-Masked-Min-op.template deleted file mode 100644 index 6a491c0573478ff4ff1ab75027316407ea9b7537..0000000000000000000000000000000000000000 --- a/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-Scalar-Masked-Min-op.template +++ /dev/null @@ -1,19 +0,0 @@ - static $type$ [[TEST]]ReduceMasked($type$[] a, int idx, boolean[] mask) { - $type$ res = [[TEST_INIT]]; - for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = ($type$)Math.min(res, a[i]); - } - - return res; - } - - static $type$ [[TEST]]ReduceAllMasked($type$[] a, boolean[] mask) { - $type$ res = [[TEST_INIT]]; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = ($type$)Math.min(res, a[i]); - } - - return res; - } diff --git a/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-Scalar-Masked-Max-op.template b/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-Scalar-Masked-op-func.template similarity index 60% rename from test/jdk/jdk/incubator/vector/templates/Unit-Reduction-Scalar-Masked-Max-op.template rename to test/jdk/jdk/incubator/vector/templates/Unit-Reduction-Scalar-Masked-op-func.template index b4a2c764b84d6d632858d99d300501a77c16afbd..00b8ed390bcf79fa27459d07b0400b04272ffa99 100644 --- a/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-Scalar-Masked-Max-op.template +++ b/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-Scalar-Masked-op-func.template @@ -1,8 +1,8 @@ static $type$ [[TEST]]ReduceMasked($type$[] a, int idx, boolean[] mask) { $type$ res = [[TEST_INIT]]; for (int i = idx; i < (idx + SPECIES.length()); i++) { - if(mask[i % SPECIES.length()]) - res = ($type$)Math.max(res, a[i]); + if (mask[i % SPECIES.length()]) + res = [[TEST_OP]](res, a[i]); } return res; @@ -10,9 +10,8 @@ static $type$ [[TEST]]ReduceAllMasked($type$[] a, boolean[] mask) { $type$ res = [[TEST_INIT]]; - for (int i = 0; i < a.length; i++) { - if(mask[i % SPECIES.length()]) - res = ($type$)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = [[TEST_OP]](res, [[TEST]]ReduceMasked(a, i, mask)); } return res; diff --git a/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-Scalar-Min-op.template b/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-Scalar-Min-op.template deleted file mode 100644 index 9e84bd13034132247e5b0ba2cf120457839f60c7..0000000000000000000000000000000000000000 --- a/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-Scalar-Min-op.template +++ /dev/null @@ -1,17 +0,0 @@ - static $type$ [[TEST]]Reduce($type$[] a, int idx) { - $type$ res = [[TEST_INIT]]; - for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = ($type$)Math.min(res, a[i]); - } - - return res; - } - - static $type$ [[TEST]]ReduceAll($type$[] a) { - $type$ res = [[TEST_INIT]]; - for (int i = 0; i < a.length; i++) { - res = ($type$)Math.min(res, a[i]); - } - - return res; - } diff --git a/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-Scalar-Max-op.template b/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-Scalar-op-func.template similarity index 65% rename from test/jdk/jdk/incubator/vector/templates/Unit-Reduction-Scalar-Max-op.template rename to test/jdk/jdk/incubator/vector/templates/Unit-Reduction-Scalar-op-func.template index 528f4ddb5f32c3b5642e392ecdd91c6b56c8a201..2abdcd295b4431b28ee5a9528d01fc478c7b12b5 100644 --- a/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-Scalar-Max-op.template +++ b/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-Scalar-op-func.template @@ -1,7 +1,7 @@ static $type$ [[TEST]]Reduce($type$[] a, int idx) { $type$ res = [[TEST_INIT]]; for (int i = idx; i < (idx + SPECIES.length()); i++) { - res = ($type$)Math.max(res, a[i]); + res = [[TEST_OP]](res, a[i]); } return res; @@ -9,8 +9,8 @@ static $type$ [[TEST]]ReduceAll($type$[] a) { $type$ res = [[TEST_INIT]]; - for (int i = 0; i < a.length; i++) { - res = ($type$)Math.max(res, a[i]); + for (int i = 0; i < a.length; i += SPECIES.length()) { + res = [[TEST_OP]](res, [[TEST]]Reduce(a, i)); } return res; diff --git a/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-Max-op.template b/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-op-func.template similarity index 100% rename from test/jdk/jdk/incubator/vector/templates/Unit-Reduction-Max-op.template rename to test/jdk/jdk/incubator/vector/templates/Unit-Reduction-op-func.template diff --git a/test/jdk/jdk/incubator/vector/templates/Unit-Test.template b/test/jdk/jdk/incubator/vector/templates/Unit-Test.template index 03cb5a48733d6ec7181294acb738edc22bcc7163..c91be6191d24d78f2496c7afc7f6113919fee8c9 100644 --- a/test/jdk/jdk/incubator/vector/templates/Unit-Test.template +++ b/test/jdk/jdk/incubator/vector/templates/Unit-Test.template @@ -20,19 +20,21 @@ } @Test(dataProvider = "$type$TestOpMaskProvider") - static void [[TEST]]Masked$vectorteststype$SmokeTest(IntFunction<$type$[]> fa, + static void [[TEST]]Masked$vectorteststype$(IntFunction<$type$[]> fa, IntFunction<boolean[]> fm) { $type$[] a = fa.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<$Wideboxtype$> vmask = VectorMask.fromArray(SPECIES, mask, 0); - for (int i = 0; i < a.length; i += SPECIES.length()) { - $abstractvectortype$ av = $abstractvectortype$.fromArray(SPECIES, a, i); - VectorMask<$Wideboxtype$> mv = av.test(VectorOperators.[[TEST]], vmask); + 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); + VectorMask<$Wideboxtype$> mv = av.test(VectorOperators.[[TEST]], vmask); - // Check results as part of computation. - for (int j = 0; j < SPECIES.length(); j++) { - Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && test[[TEST]](a[i + j])); + // Check results as part of computation. + for (int j = 0; j < SPECIES.length(); j++) { + Assert.assertEquals(mv.laneIsSet(j), vmask.laneIsSet(j) && test[[TEST]](a[i + j])); + } } } } diff --git a/test/jdk/jdk/incubator/vector/templates/Unit-With-Op.template b/test/jdk/jdk/incubator/vector/templates/Unit-With-Op.template index cb44361c094a73612b2b602f7efdac0ba696b20d..c41bd05f20e69b0f1809f16829f78e7e951d7974 100644 --- a/test/jdk/jdk/incubator/vector/templates/Unit-With-Op.template +++ b/test/jdk/jdk/incubator/vector/templates/Unit-With-Op.template @@ -2,5 +2,8 @@ @Test(dataProvider = "$type$UnaryOpProvider") static void with$vectorteststype$(IntFunction<$type$ []> fa) { [[KERNEL]] - assertInsertArraysEquals(r, a, ($type$)4, 0); + + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { + assertInsertArraysEquals(r, a, ($type$)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); + } } diff --git a/test/jdk/jdk/incubator/vector/templates/Unit-header.template b/test/jdk/jdk/incubator/vector/templates/Unit-header.template index 0cbb3447340b2a05fe81089e9be17150d3455466..e010bb7268b6aed8d696bce772fb96a033af7ba8 100644 --- a/test/jdk/jdk/incubator/vector/templates/Unit-header.template +++ b/test/jdk/jdk/incubator/vector/templates/Unit-header.template @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -257,10 +257,10 @@ public class $vectorteststype$ extends AbstractVectorTest { } } - static void assertInsertArraysEquals($type$[] r, $type$[] a, $type$ element, int index) { - int i = 0; + static void assertInsertArraysEquals($type$[] r, $type$[] a, $type$ element, int index, int start, int end) { + int i = start; try { - for (; i < a.length; i += 1) { + for (; i < end; i += 1) { if(i%SPECIES.length() == index) { Assert.assertEquals(r[i], element); } else { @@ -1451,6 +1451,10 @@ public class $vectorteststype$ extends AbstractVectorTest { } #end[!FP] + static $type$ firstNonZero($type$ a, $type$ b) { + return $Boxtype$.compare(a, ($type$) 0) != 0 ? a : b; + } + @Test static void smokeTest1() { $abstractvectortype$ three = $abstractvectortype$.broadcast(SPECIES, (byte)-3); diff --git a/test/jdk/jdk/internal/loader/NativeLibraries/Main.java b/test/jdk/jdk/internal/loader/NativeLibraries/Main.java index 6db9100a8e870bb4733fe8d6ddf9d33aee1ab405..638047c33e0682227f396ee24b9e13a650004fda 100644 --- a/test/jdk/jdk/internal/loader/NativeLibraries/Main.java +++ b/test/jdk/jdk/internal/loader/NativeLibraries/Main.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -23,14 +23,13 @@ /* * @test - * @bug 8240975 + * @bug 8240975 8281335 * @modules java.base/jdk.internal.loader * @build java.base/* p.Test Main * @run main/othervm/native -Xcheck:jni Main * @summary Test loading and unloading of native libraries */ -import jdk.internal.loader.*; import jdk.internal.loader.NativeLibrariesTest; import java.io.IOException; @@ -42,6 +41,7 @@ public class Main { public static void main(String... args) throws Exception { setup(); + // Verify a native library from test.nativepath NativeLibrariesTest test = new NativeLibrariesTest(); test.runTest(); @@ -53,10 +53,14 @@ public class Main { test.unload(); System.loadLibrary(NativeLibrariesTest.LIB_NAME); - // expect NativeLibraries to fail since the library has been loaded by System::loadLibrary - try { - test.load(false); - } catch (UnsatisfiedLinkError e) { e.printStackTrace(); } + // expect NativeLibraries to succeed even the library has been loaded by System::loadLibrary + test.loadTestLibrary(); + + // load zip library from JDK + test.load(System.mapLibraryName("zip"), true /* succeed */); + + // load non-existent library + test.load(System.mapLibraryName("NotExist"), false /* fail to load */); } /* * move p/Test.class out from classpath to the scratch directory diff --git a/test/jdk/jdk/internal/loader/NativeLibraries/java.base/jdk/internal/loader/NativeLibrariesTest.java b/test/jdk/jdk/internal/loader/NativeLibraries/java.base/jdk/internal/loader/NativeLibrariesTest.java index 1c4ad3dcae7ebd09a8a6575f6e46c817682132d6..a0560624929bea9190b8f61aaddd574cea9a67fe 100644 --- a/test/jdk/jdk/internal/loader/NativeLibraries/java.base/jdk/internal/loader/NativeLibrariesTest.java +++ b/test/jdk/jdk/internal/loader/NativeLibraries/java.base/jdk/internal/loader/NativeLibrariesTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -23,10 +23,12 @@ package jdk.internal.loader; +import java.lang.invoke.MethodHandles; import java.lang.reflect.Constructor; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; +import java.nio.file.Path; import java.nio.file.Paths; public class NativeLibrariesTest implements Runnable { @@ -49,21 +51,28 @@ public class NativeLibrariesTest implements Runnable { unloadedCount++; } - private final NativeLibraries nativeLibraries; + private final RawNativeLibraries nativeLibraries; + public NativeLibrariesTest() { - this.nativeLibraries = NativeLibraries.rawNativeLibraries(NativeLibraries.class, true); + this.nativeLibraries = RawNativeLibraries.newInstance(MethodHandles.lookup()); } /* * Invoke by p.Test to load the same native library from different class loader */ public void run() { - load(true); // expect loading of native library succeed + loadTestLibrary(); // expect loading of native library succeed + } + + static Path libraryPath() { + Path lib = Path.of(System.getProperty("test.nativepath")); + return lib.resolve(System.mapLibraryName(LIB_NAME)); } public void runTest() throws Exception { - NativeLibrary nl1 = nativeLibraries.loadLibrary(LIB_NAME); - NativeLibrary nl2 = nativeLibraries.loadLibrary(LIB_NAME); + Path lib = libraryPath(); + NativeLibrary nl1 = nativeLibraries.load(lib); + NativeLibrary nl2 = nativeLibraries.load(lib); assertTrue(nl1 != null && nl2 != null, "fail to load library"); assertTrue(nl1 == nl2, nl1 + " != " + nl2); assertTrue(loadedCount == 0, "Native library loaded. Expected: JNI_OnUnload not invoked"); @@ -77,7 +86,7 @@ public class NativeLibrariesTest implements Runnable { assertTrue(unloadedCount == 0, "Native library unloaded. Expected: JNI_OnUnload not invoked"); // reload the native library and expect new NativeLibrary instance - NativeLibrary nl3 = nativeLibraries.loadLibrary(LIB_NAME); + NativeLibrary nl3 = nativeLibraries.load(lib); assertTrue(nl1 != nl3, nl1 + " == " + nl3); assertTrue(loadedCount == 0, "Native library loaded. Expected: JNI_OnUnload not invoked"); @@ -86,18 +95,23 @@ public class NativeLibrariesTest implements Runnable { } public void unload() { - NativeLibrary nl = nativeLibraries.loadLibrary(LIB_NAME); + NativeLibrary nl = nativeLibraries.load(libraryPath()); // unload the native library nativeLibraries.unload(nl); assertTrue(unloadedCount == 0, "Native library unloaded. Expected: JNI_OnUnload not invoked"); } - public void load(boolean succeed) { - NativeLibrary nl = nativeLibraries.loadLibrary(LIB_NAME); + public void loadTestLibrary() { + NativeLibrary nl = nativeLibraries.load(libraryPath()); + assertTrue(nl != null, "fail to load " + libraryPath()); + } + + public void load(String pathname, boolean succeed) { + NativeLibrary nl = nativeLibraries.load(pathname); if (succeed) { - assertTrue(nl != null, "fail to load library"); + assertTrue(nl != null, "fail to load " + pathname); } else { - assertTrue(nl == null, "load library should fail"); + assertTrue(nl == null, "expect to return null for " + pathname); } } diff --git a/test/jdk/jdk/internal/platform/docker/GetFreeSwapSpaceSize.java b/test/jdk/jdk/internal/platform/docker/GetFreeSwapSpaceSize.java index efb6a39e4790469747a29ad985b9fee55c93b08b..92b8cf282b784f1f9256c3b8774665a61d0c7100 100644 --- a/test/jdk/jdk/internal/platform/docker/GetFreeSwapSpaceSize.java +++ b/test/jdk/jdk/internal/platform/docker/GetFreeSwapSpaceSize.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. + * Copyright (C) 2020, 2022 THL A29 Limited, a Tencent company. All rights reserved. * 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,36 @@ import com.sun.management.OperatingSystemMXBean; import java.lang.management.ManagementFactory; +// Usage: +// GetFreeSwapSpaceSize <memoryAlloc> <expectedMemory> <memorySwapAlloc> <expectedSwap> public class GetFreeSwapSpaceSize { public static void main(String[] args) { - System.out.println("TestGetFreeSwapSpaceSize"); + if (args.length != 4) { + throw new RuntimeException("Unexpected arguments. Expected 4, got " + args.length); + } + String memoryAlloc = args[0]; + long expectedMemory = Long.parseLong(args[1]); + String memorySwapAlloc = args[2]; + long expectedSwap = Long.parseLong(args[3]); + System.out.println("TestGetFreeSwapSpaceSize (memory=" + memoryAlloc + ", memorySwap=" + memorySwapAlloc + ")"); + if (expectedSwap != 0) { + throw new RuntimeException("Precondition of test not met: Expected swap size of 0, got: " + expectedSwap); + } OperatingSystemMXBean osBean = (OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean(); + long osBeanTotalSwap = osBean.getTotalSwapSpaceSize(); + // Premise of this test is to test on a system where --memory and --memory-swap are set to + // the same amount via the container engine (i.e. no swap). In that case the OSBean must + // not report negative values for free swap space. Assert this precondition. + if (osBeanTotalSwap != expectedSwap) { + throw new RuntimeException("OperatingSystemMXBean.getTotalSwapSpaceSize() reported " + osBeanTotalSwap + " expected " + expectedSwap); + } + System.out.println("TestGetFreeSwapSpaceSize precondition met, osBeanTotalSwap = " + expectedSwap + ". Running test... "); for (int i = 0; i < 100; i++) { long size = osBean.getFreeSwapSpaceSize(); if (size < 0) { - System.out.println("Error: getFreeSwapSpaceSize returns " + size); - System.exit(-1); + throw new RuntimeException("Test failed! getFreeSwapSpaceSize returns " + size); } } + System.out.println("TestGetFreeSwapSpaceSize PASSED." ); } } diff --git a/test/jdk/jdk/internal/platform/docker/TestGetFreeSwapSpaceSize.java b/test/jdk/jdk/internal/platform/docker/TestGetFreeSwapSpaceSize.java index 319c55ab518e2be5dcbd7213966b22dcd4e94497..92f3364da10b002025e3b68a7ed6503842c1f55a 100644 --- a/test/jdk/jdk/internal/platform/docker/TestGetFreeSwapSpaceSize.java +++ b/test/jdk/jdk/internal/platform/docker/TestGetFreeSwapSpaceSize.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. + * Copyright (C) 2020, 2022 THL A29 Limited, a Tencent company. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,7 +36,7 @@ import jdk.test.lib.containers.docker.DockerTestUtils; import jdk.test.lib.process.OutputAnalyzer; public class TestGetFreeSwapSpaceSize { - private static final String imageName = Common.imageName("memory"); + private static final String imageName = Common.imageName("osbeanSwapSpace"); public static void main(String[] args) throws Exception { if (!DockerTestUtils.canTestDocker()) { @@ -58,17 +58,18 @@ public class TestGetFreeSwapSpaceSize { } private static void testGetFreeSwapSpaceSize(String memoryAllocation, String expectedMemory, - String swapAllocation, String expectedSwap) throws Exception { + String memorySwapAllocation, String expectedSwap) throws Exception { Common.logNewTestCase("TestGetFreeSwapSpaceSize"); DockerRunOptions opts = Common.newOpts(imageName, "GetFreeSwapSpaceSize") + .addClassOptions(memoryAllocation, expectedMemory, memorySwapAllocation, expectedSwap) .addDockerOpts( "--memory", memoryAllocation, - "--memory-swap", swapAllocation + "--memory-swap", memorySwapAllocation ); OutputAnalyzer out = DockerTestUtils.dockerRunJava(opts); out.shouldHaveExitValue(0) - .shouldContain("TestGetFreeSwapSpaceSize"); + .shouldContain("TestGetFreeSwapSpaceSize PASSED."); } } diff --git a/test/jdk/jdk/jfr/api/consumer/TestHiddenMethod.java b/test/jdk/jdk/jfr/api/consumer/TestHiddenMethod.java index 7a5bf1e42c42f6c38577a3e17dc4161501dc1acc..f1eeac58362d12f12fc01516bd8382ac1a3e929a 100644 --- a/test/jdk/jdk/jfr/api/consumer/TestHiddenMethod.java +++ b/test/jdk/jdk/jfr/api/consumer/TestHiddenMethod.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -51,10 +51,10 @@ import jdk.test.lib.jfr.Events; */ public final class TestHiddenMethod { - public static void main(String[] args) throws Throwable { - try (Recording recording = new Recording()) { - recording.enable(MyEvent.class).withThreshold(Duration.ofMillis(0)); - recording.start(); + // Must call in separate thread because JTREG uses reflection + // to invoke main method, which uses hidden methods. + public static class TestThread extends Thread { + public void run() { // doPrivileged calls a method that has the @Hidden // annotation AccessController.doPrivileged(new PrivilegedAction<Void>() { @@ -65,8 +65,19 @@ public final class TestHiddenMethod { return null; } }); + MyEvent event = new MyEvent(); event.commit(); + } + } + + public static void main(String[] args) throws Throwable { + try (Recording recording = new Recording()) { + recording.enable(MyEvent.class).withThreshold(Duration.ofMillis(0)); + recording.start(); + Thread t = new TestThread(); + t.start(); + t.join(); recording.stop(); List<RecordedEvent> events = Events.fromRecording(recording); @@ -78,9 +89,7 @@ public final class TestHiddenMethod { System.out.println("visibleEvent:" + visibleEvent); assertTrue(hasHiddenStackFrame(hiddenEvent), "No hidden frame in hidden event: " + hiddenEvent); - - // Temporary disable this test until JDK-8272064 is resolved. - // assertFalse(hasHiddenStackFrame(visibleEvent), "Hidden frame in visible event: " + visibleEvent); + assertFalse(hasHiddenStackFrame(visibleEvent), "Hidden frame in visible event: " + visibleEvent); } } diff --git a/test/jdk/jdk/jfr/api/consumer/TestRecordedFullStackTrace.java b/test/jdk/jdk/jfr/api/consumer/TestRecordedFullStackTrace.java index 1487d2e0258f1f7516d306a6e748273db0562734..6993fe3100178c4b909566160c7e7cd13f665fb8 100644 --- a/test/jdk/jdk/jfr/api/consumer/TestRecordedFullStackTrace.java +++ b/test/jdk/jdk/jfr/api/consumer/TestRecordedFullStackTrace.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -119,7 +119,7 @@ public class TestRecordedFullStackTrace { if (!isEventFound[i]) { // no assertion, let's retry. // Could be race condition, i.e safe point during Thread.sleep - System.out.println("Falied to validate all threads, will retry."); + System.out.println("Failed to validate all threads, will retry."); return false; } } diff --git a/test/jdk/jdk/jfr/api/consumer/TestRecordingFile.java b/test/jdk/jdk/jfr/api/consumer/TestRecordingFile.java index 923895447c733304eb1fbe349bd9cb30f38f18c1..a81262f9405c82cfadf2e32d73056c13ac2fd23f 100644 --- a/test/jdk/jdk/jfr/api/consumer/TestRecordingFile.java +++ b/test/jdk/jdk/jfr/api/consumer/TestRecordingFile.java @@ -194,11 +194,11 @@ public class TestRecordingFile { rotator.stop(); } r2.stop(); - r2.dump(twoEventTypes);; + r2.dump(twoEventTypes); } FlightRecorder.register(Event3.class); r1.stop(); - r1.dump(threeEventTypes);; + r1.dump(threeEventTypes); } try (RecordingFile f = new RecordingFile(twoEventTypes)) { List<EventType> types = f.readEventTypes(); diff --git a/test/jdk/jdk/jfr/api/consumer/TestRecordingFileSanitization.java b/test/jdk/jdk/jfr/api/consumer/TestRecordingFileSanitization.java new file mode 100644 index 0000000000000000000000000000000000000000..75e01f82cd403b18d921ee6e151a05b3fe9aec55 --- /dev/null +++ b/test/jdk/jdk/jfr/api/consumer/TestRecordingFileSanitization.java @@ -0,0 +1,121 @@ +/* + * 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. + */ + +package jdk.jfr.api.consumer; + +import jdk.jfr.Recording; +import jdk.jfr.consumer.RecordingFile; +import jdk.jfr.Name; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +import jdk.jfr.Event; + +/** + * @test + * @summary Verifies that all traces of sensitive data is removed + * @key jfr + * @requires vm.hasJFR + * @library /test/lib + * @run main/othervm jdk.jfr.api.consumer.TestRecordingFileSanitization + */ +public class TestRecordingFileSanitization { + // Less than 16 characters, stored in event + private final static String SHORT_PASSWORD = "abcde123"; + // More than 16 characters, stored in constant pool + private final static String LONG_PASSWORD = "abcdefghijklmnopqrstuvxyz1234567890"; + + @Name("Sensitive") + public static class SensitiveEvent extends Event { + String shortPassword; + String longPassword; + } + + public static void main(String[] args) throws Throwable { + Path sensitive = Path.of("sensitive.jfr"); + Path sanitized = Path.of("sanitized.jfr"); + try (Recording r = new Recording()) { + r.start(); + SensitiveEvent e = new SensitiveEvent(); + e.shortPassword = SHORT_PASSWORD; + e.longPassword = LONG_PASSWORD; + e.commit(); + r.stop(); + r.dump(sensitive); + } + try (RecordingFile r = new RecordingFile(sensitive)) { + r.write(sanitized, e -> !e.getEventType().getName().equals("Sensitive")); + } + + expect(sensitive, SHORT_PASSWORD); + expect(sensitive, LONG_PASSWORD); + missing(sanitized, SHORT_PASSWORD); + missing(sanitized, LONG_PASSWORD); + } + + private static void expect(Path file, String text) throws IOException { + if (!find(file, text)) { + throw new AssertionError("Expected to find '" + text +"' in " + file); + } + System.out.println("OK, found '" + text + "' in " + file ); + } + + private static void missing(Path file, String text) throws IOException { + if (find(file, text)) { + throw new AssertionError("Didn't expect to find '" + text +"' in " + file); + } + System.out.println("OK, missing '" + text + "' in " + file); + } + + private static boolean find(Path file, String text) throws IOException { + byte[] textBytes = stringToBytes(text); + byte[] fileBytes = Files.readAllBytes(file); + for (int i = 0; i < fileBytes.length - textBytes.length; i++) { + if (find(fileBytes, i, textBytes)) { + return true; + } + } + return false; + } + + private static boolean find(byte[] haystack, int start, byte[] needle) { + for (int i = 0; i < needle.length; i++) { + if (haystack[start + i] != needle[i]) { + return false; + } + } + return true; + } + + private static byte[] stringToBytes(String text) { + byte[] bytes = new byte[text.length()]; + for (int i = 0; i < text.length(); i++) { + if (text.charAt(i) > 127) { + throw new Error("Test only allows characters that becomes one byte with LEB128"); + } + bytes[i] = (byte)(text.charAt(i)); + } + return bytes; + } +} diff --git a/test/jdk/jdk/jfr/api/consumer/TestRecordingFileWrite.java b/test/jdk/jdk/jfr/api/consumer/TestRecordingFileWrite.java new file mode 100644 index 0000000000000000000000000000000000000000..f4cf5a20805fd5f8b41dfb95720590cb9a9fea20 --- /dev/null +++ b/test/jdk/jdk/jfr/api/consumer/TestRecordingFileWrite.java @@ -0,0 +1,126 @@ +/* + * 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. + */ + +package jdk.jfr.api.consumer; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayDeque; +import java.util.Queue; +import java.util.Random; + +import jdk.jfr.Configuration; +import jdk.jfr.Event; +import jdk.jfr.Recording; +import jdk.jfr.consumer.RecordingFile; + +/** + * @test + * @summary Tests RecordingFile::write(Path, Predicate<RecordedEvent>) + * @key jfr + * @requires vm.hasJFR + * @library /test/lib + * @run main/othervm jdk.jfr.api.consumer.TestRecordingFileWrite + */ +public class TestRecordingFileWrite { + + static class ScrubEvent extends Event { + long id; + String message; + } + + public static void main(String... args) throws Exception { + Path scrubbed = Paths.get("scrubbed.jfr"); + Path original = Paths.get("original.jfr"); + + createRecording(original); + Queue<String> ids = scrubRecording(original, scrubbed); + System.out.println("Original size: " + Files.size(original)); + System.out.println("Scrubbed size: " + Files.size(scrubbed)); + System.out.println("Scrubbed event count: " + ids.size()); + if (ids.size() < 50_000) { + throw new AssertionError("Expected at least 50 000 events to be included"); + } + verify(scrubbed, ids); + } + + private static void verify(Path scrubbed, Queue<String> events) throws Exception { + try (RecordingFile rf = new RecordingFile(scrubbed)) { + while (rf.hasMoreEvents()) { + String event = rf.readEvent().toString(); + String expected = events.poll(); + if (!event.equals(expected)) { + System.out.println("Found:"); + System.out.println(event); + System.out.println("Expected:"); + System.out.println(expected); + throw new Exception("Found event that should not be there. See log"); + } + } + } + if (!events.isEmpty()) { + throw new AssertionError("Missing events " + events); + } + } + + private static Queue<String> scrubRecording(Path original, Path scrubbed) throws IOException { + Queue<String> events = new ArrayDeque<>(150_000); + Random random = new Random(); + try (RecordingFile rf = new RecordingFile(original)) { + rf.write(scrubbed, event -> { + boolean keep = random.nextInt(10) == 0; + if (event.getEventType().getName().equals("jdk.OldObjectSample")) { + System.out.println(event); + keep = true; + } + if (keep) { + events.add(event.toString()); + } + return keep; + }); + } + return events; + } + + private static void createRecording(Path file) throws Exception { + // Use profile configuration so more complex data structures + // are serialized + Configuration c = Configuration.getConfiguration("profile"); + try (Recording r = new Recording(c)) { + r.start(); + String s = "A"; + // Generate sufficient number of events to provoke + // chunk rotations + for (int i = 0; i < 1_000_000; i++) { + ScrubEvent event = new ScrubEvent(); + event.message = s.repeat(i % 30); + event.id = i; + event.commit(); + } + r.stop(); + r.dump(file); + } + } +} diff --git a/test/jdk/jdk/jfr/api/consumer/filestream/TestReuse.java b/test/jdk/jdk/jfr/api/consumer/filestream/TestReuse.java index 3d7d143f44cdcededb793a6ea7565575f3409205..3dbe26eea16f3933c2f3316baae5aec5a088408a 100644 --- a/test/jdk/jdk/jfr/api/consumer/filestream/TestReuse.java +++ b/test/jdk/jdk/jfr/api/consumer/filestream/TestReuse.java @@ -89,7 +89,7 @@ public class TestReuse { es.setReuse(true); es.onEvent(e -> { if(events.containsKey(e)) { - success.set(true);; + success.set(true); es.close(); } events.put(e,e); diff --git a/test/jdk/jdk/jfr/api/consumer/streaming/TestJVMCrash.java b/test/jdk/jdk/jfr/api/consumer/streaming/TestJVMCrash.java index 3c6620b8caf4f32ef452231736993d2be0eff134..c1594462a80305b6b97af1e5ab1638b576ac6d12 100644 --- a/test/jdk/jdk/jfr/api/consumer/streaming/TestJVMCrash.java +++ b/test/jdk/jdk/jfr/api/consumer/streaming/TestJVMCrash.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -36,7 +36,7 @@ import jdk.jfr.consumer.EventStream; * @library /test/lib /test/jdk * @modules jdk.jfr jdk.attach java.base/jdk.internal.misc * - * @run main/othervm jdk.jfr.api.consumer.streaming.TestJVMCrash + * @run main/othervm -Dsun.tools.attach.attachTimeout=100000 jdk.jfr.api.consumer.streaming.TestJVMCrash */ public class TestJVMCrash { diff --git a/test/jdk/jdk/jfr/api/consumer/streaming/TestJVMExit.java b/test/jdk/jdk/jfr/api/consumer/streaming/TestJVMExit.java index c4bdfdf6402d60f45dbd010ef0b30a250ee3f408..5b30a52e4b757f5ea9c91902b0f64c7aa0d768a1 100644 --- a/test/jdk/jdk/jfr/api/consumer/streaming/TestJVMExit.java +++ b/test/jdk/jdk/jfr/api/consumer/streaming/TestJVMExit.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -35,7 +35,7 @@ import jdk.jfr.consumer.EventStream; * @library /test/lib /test/jdk * @modules jdk.jfr jdk.attach java.base/jdk.internal.misc * - * @run main/othervm jdk.jfr.api.consumer.streaming.TestJVMExit + * @run main/othervm -Dsun.tools.attach.attachTimeout=100000 jdk.jfr.api.consumer.streaming.TestJVMExit */ public class TestJVMExit { diff --git a/test/jdk/jdk/jfr/api/consumer/streaming/TestLatestEvent.java b/test/jdk/jdk/jfr/api/consumer/streaming/TestLatestEvent.java index 4190d97eaaf3dabaf6798692024b0d2a8368d8ee..4515ae9832a01452c287a754cfee258486e7d9b1 100644 --- a/test/jdk/jdk/jfr/api/consumer/streaming/TestLatestEvent.java +++ b/test/jdk/jdk/jfr/api/consumer/streaming/TestLatestEvent.java @@ -23,8 +23,12 @@ package jdk.jfr.api.consumer.streaming; +import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.Comparator; +import java.util.List; +import java.util.ArrayList; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; @@ -34,6 +38,7 @@ import jdk.jfr.FlightRecorder; import jdk.jfr.Name; import jdk.jfr.Recording; import jdk.jfr.consumer.EventStream; +import jdk.jfr.consumer.RecordingFile; import jdk.jfr.consumer.RecordingStream; /** @@ -65,7 +70,8 @@ public class TestLatestEvent { CountDownLatch beginChunks = new CountDownLatch(1); try (RecordingStream r = new RecordingStream()) { - r.onEvent("MakeChunks", event-> { + r.setMaxSize(1_000_000_000); + r.onEvent("MakeChunks", event -> { System.out.println(event); beginChunks.countDown(); }); @@ -100,13 +106,25 @@ public class TestLatestEvent { // This latch ensures thatNotLatest has been // flushed and a new valid position has been written // to the chunk header - notLatestEvent.await(80, TimeUnit.SECONDS); + boolean timeout = notLatestEvent.await(80, TimeUnit.SECONDS); if (notLatestEvent.getCount() != 0) { + System.out.println("timeout = " + timeout); + Path repo = Path.of(System.getProperty("jdk.jfr.repository")); + System.out.println("repo = " + repo); + List<Path> files = new ArrayList<>(Files.list(repo).toList()); + files.sort(Comparator.comparing(Path::toString)); + for (Path f : files) { + System.out.println("------------"); + System.out.println("File: " + f); + for (var event : RecordingFile.readAllEvents(f)) { + System.out.println(event); + } + } Recording rec = FlightRecorder.getFlightRecorder().takeSnapshot(); Path p = Paths.get("error-not-latest.jfr").toAbsolutePath(); rec.dump(p); System.out.println("Dumping repository as a file for inspection at " + p); - throw new Exception("Timeout 80 s. Expected 6 event, but got " + notLatestEvent.getCount()); + throw new Exception("Timeout 80 s. Expected 6 event, but got " + (6 - notLatestEvent.getCount())); } try (EventStream s = EventStream.openRepository()) { diff --git a/test/jdk/jdk/jfr/api/recording/event/TestEventTime.java b/test/jdk/jdk/jfr/api/recording/event/TestEventTime.java index af740a6e559718b38e9ceec64aef914968a0a786..7ee9748520a7925ae025113d8b65070bf0aaac5b 100644 --- a/test/jdk/jdk/jfr/api/recording/event/TestEventTime.java +++ b/test/jdk/jdk/jfr/api/recording/event/TestEventTime.java @@ -101,7 +101,7 @@ public class TestEventTime { MyEvent event = new MyEvent(id); event.begin(); if (!CommonHelper.hasFastTimeEnabled()) { - CommonHelper.waitForSystemCurrentMillisToChange();; + CommonHelper.waitForSystemCurrentMillisToChange(); } actualOrder.add(new TimeEvent(id, true)); return event; @@ -110,7 +110,7 @@ public class TestEventTime { private static void endEvent(MyEvent event) throws Exception { event.end(); if (!CommonHelper.hasFastTimeEnabled()) { - CommonHelper.waitForSystemCurrentMillisToChange();; + CommonHelper.waitForSystemCurrentMillisToChange(); } event.commit(); actualOrder.add(new TimeEvent(event.id, false)); diff --git a/test/jdk/jdk/jfr/event/allocation/TestObjectAllocationInNewTLABEvent.java b/test/jdk/jdk/jfr/event/allocation/TestObjectAllocationInNewTLABEvent.java index d4078a65ecd71db0aad79ad6d6f1b1f00f01d326..6dbd51b1386fed6e18d94feaf376e196f41d8b1e 100644 --- a/test/jdk/jdk/jfr/event/allocation/TestObjectAllocationInNewTLABEvent.java +++ b/test/jdk/jdk/jfr/event/allocation/TestObjectAllocationInNewTLABEvent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -30,6 +30,8 @@ import jdk.jfr.consumer.RecordedEvent; import jdk.test.lib.jfr.EventNames; import jdk.test.lib.jfr.Events; import jdk.test.lib.Asserts; +import jdk.test.lib.Platform; +import sun.hotspot.WhiteBox; /** * @test @@ -37,8 +39,16 @@ import jdk.test.lib.Asserts; * @key jfr * @requires vm.hasJFR * @library /test/lib - * @run main/othervm -XX:+UseTLAB -XX:TLABSize=100k -XX:-ResizeTLAB -XX:TLABRefillWasteFraction=1 jdk.jfr.event.allocation.TestObjectAllocationInNewTLABEvent - * @run main/othervm -XX:+UseTLAB -XX:TLABSize=100k -XX:-ResizeTLAB -XX:TLABRefillWasteFraction=1 -Xint jdk.jfr.event.allocation.TestObjectAllocationInNewTLABEvent + * @build sun.hotspot.WhiteBox + * + * @run driver jdk.test.lib.helpers.ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -XX:+UseTLAB -XX:TLABSize=100k -XX:-ResizeTLAB -XX:TLABRefillWasteFraction=1 + * jdk.jfr.event.allocation.TestObjectAllocationInNewTLABEvent + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -XX:+UseTLAB -XX:TLABSize=100k -XX:-ResizeTLAB -XX:TLABRefillWasteFraction=1 + * -Xint + * jdk.jfr.event.allocation.TestObjectAllocationInNewTLABEvent */ /** @@ -46,17 +56,19 @@ import jdk.test.lib.Asserts; * an event will be triggered. The test is done for default and interpreted mode (-Xint). * * To force objects to be allocated in a new TLAB: - * the size of TLAB is set to 100k (-XX:TLABSize=100k); - * the size of allocated objects is set to 100k minus 16 bytes overhead; + * the initial size of TLAB is set to 100k (-XX:TLABSize=100k); + * the size of allocated objects is set to 128k; * max TLAB waste at refill is set to minimum (-XX:TLABRefillWasteFraction=1), * to provoke a new TLAB creation. */ public class TestObjectAllocationInNewTLABEvent { private final static String EVENT_NAME = EventNames.ObjectAllocationInNewTLAB; - private static final int BYTE_ARRAY_OVERHEAD = 16; // Extra bytes used by a byte array. - private static final int OBJECT_SIZE = 100 * 1024; - private static final int OBJECT_SIZE_ALT = OBJECT_SIZE + 8; // Object size in case of disabled CompressedOops. + private static final Boolean COMPRESSED_CLASS_PTRS = WhiteBox.getWhiteBox().getBooleanVMFlag("UseCompressedClassPointers"); + + private static final int BYTE_ARRAY_OVERHEAD = (Platform.is64bit() && !COMPRESSED_CLASS_PTRS) ? 24 : 16; + private static final int OBJECT_SIZE = 128 * 1024; + private static final int OBJECTS_TO_ALLOCATE = 100; private static final String BYTE_ARRAY_CLASS_NAME = new byte[0].getClass().getName(); private static final int INITIAL_TLAB_SIZE = 100 * 1024; @@ -112,9 +124,9 @@ public class TestObjectAllocationInNewTLABEvent { long allocationSize = Events.assertField(event, "allocationSize").atLeast(1L).getValue(); long tlabSize = Events.assertField(event, "tlabSize").atLeast(allocationSize).getValue(); String className = Events.assertField(event, "objectClass.name").notEmpty().getValue(); - if (className.equals(BYTE_ARRAY_CLASS_NAME) && (allocationSize == OBJECT_SIZE || allocationSize == OBJECT_SIZE_ALT)) { + if (className.equals(BYTE_ARRAY_CLASS_NAME) && (allocationSize == OBJECT_SIZE)) { countAllTlabs++; - if (tlabSize == INITIAL_TLAB_SIZE + OBJECT_SIZE || tlabSize == INITIAL_TLAB_SIZE + OBJECT_SIZE_ALT) { + if (tlabSize == INITIAL_TLAB_SIZE + OBJECT_SIZE) { countFullTlabs++; } } diff --git a/test/jdk/jdk/jfr/event/allocation/TestObjectAllocationOutsideTLABEvent.java b/test/jdk/jdk/jfr/event/allocation/TestObjectAllocationOutsideTLABEvent.java index 466a0062ac9d37e6dfff8d753337d62f14619728..87c3b29af4277f412f543e45be7b092e762fcaf4 100644 --- a/test/jdk/jdk/jfr/event/allocation/TestObjectAllocationOutsideTLABEvent.java +++ b/test/jdk/jdk/jfr/event/allocation/TestObjectAllocationOutsideTLABEvent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -30,6 +30,8 @@ import jdk.jfr.consumer.RecordedEvent; import jdk.test.lib.jfr.EventNames; import jdk.test.lib.jfr.Events; import jdk.test.lib.Asserts; +import jdk.test.lib.Platform; +import sun.hotspot.WhiteBox; /** * @test @@ -37,8 +39,16 @@ import jdk.test.lib.Asserts; * @key jfr * @requires vm.hasJFR * @library /test/lib - * @run main/othervm -XX:+UseTLAB -XX:TLABSize=90k -XX:-ResizeTLAB -XX:TLABRefillWasteFraction=256 jdk.jfr.event.allocation.TestObjectAllocationOutsideTLABEvent - * @run main/othervm -XX:+UseTLAB -XX:TLABSize=90k -XX:-ResizeTLAB -XX:TLABRefillWasteFraction=256 -Xint jdk.jfr.event.allocation.TestObjectAllocationOutsideTLABEvent + * @build sun.hotspot.WhiteBox + * + * @run driver jdk.test.lib.helpers.ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -XX:+UseTLAB -XX:TLABSize=90k -XX:-ResizeTLAB -XX:TLABRefillWasteFraction=256 + * jdk.jfr.event.allocation.TestObjectAllocationOutsideTLABEvent + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -XX:+UseTLAB -XX:TLABSize=90k -XX:-ResizeTLAB -XX:TLABRefillWasteFraction=256 + * -Xint + * jdk.jfr.event.allocation.TestObjectAllocationOutsideTLABEvent */ /** @@ -46,17 +56,19 @@ import jdk.test.lib.Asserts; * Thread Local Allocation Buffer (TLAB). The test is done for default interpreted mode (-Xint). * * To force objects to be allocated outside TLAB: - * the size of TLAB is set to 90k (-XX:TLABSize=90k); - * the size of allocated objects is set to 100k. + * the initial size of TLAB is set to 90k (-XX:TLABSize=90k); + * the size of allocated objects is set to 128k; * max TLAB waste at refill is set to 256 (-XX:TLABRefillWasteFraction=256), * to prevent a new TLAB creation. */ public class TestObjectAllocationOutsideTLABEvent { private static final String EVENT_NAME = EventNames.ObjectAllocationOutsideTLAB; - private static final int BYTE_ARRAY_OVERHEAD = 16; // Extra bytes used by a byte array - private static final int OBJECT_SIZE = 100 * 1024; - private static final int OBJECT_SIZE_ALT = OBJECT_SIZE + 8; // Object size in case of disabled CompressedOops + private static final Boolean COMPRESSED_CLASS_PTRS = WhiteBox.getWhiteBox().getBooleanVMFlag("UseCompressedClassPointers"); + + private static final int BYTE_ARRAY_OVERHEAD = (Platform.is64bit() && !COMPRESSED_CLASS_PTRS) ? 24 : 16; + private static final int OBJECT_SIZE = 128 * 1024; + private static final int OBJECTS_TO_ALLOCATE = 100; private static final String BYTE_ARRAY_CLASS_NAME = new byte[0].getClass().getName(); private static int eventCount; @@ -94,7 +106,7 @@ public class TestObjectAllocationOutsideTLABEvent { } long allocationSize = Events.assertField(event, "allocationSize").atLeast(1L).getValue(); String className = Events.assertField(event, "objectClass.name").notEmpty().getValue(); - if (className.equals(BYTE_ARRAY_CLASS_NAME) && (allocationSize == OBJECT_SIZE || allocationSize == OBJECT_SIZE_ALT)) { + if (className.equals(BYTE_ARRAY_CLASS_NAME) && (allocationSize == OBJECT_SIZE)) { ++eventCount; } } diff --git a/test/jdk/jdk/jfr/event/allocation/TestObjectAllocationSampleEventThrottling.java b/test/jdk/jdk/jfr/event/allocation/TestObjectAllocationSampleEventThrottling.java index 22d03ce57baeb5cf975d8b8b175b0d820a1a60af..5049acc229caddb60c197095b8e63bba114e9015 100644 --- a/test/jdk/jdk/jfr/event/allocation/TestObjectAllocationSampleEventThrottling.java +++ b/test/jdk/jdk/jfr/event/allocation/TestObjectAllocationSampleEventThrottling.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -32,6 +32,8 @@ import jdk.jfr.consumer.RecordedEvent; import jdk.test.lib.jfr.EventNames; import jdk.test.lib.jfr.Events; import jdk.test.lib.Asserts; +import jdk.test.lib.Platform; +import sun.hotspot.WhiteBox; /** * @test @@ -39,15 +41,22 @@ import jdk.test.lib.Asserts; * @key jfr * @requires vm.hasJFR * @library /test/lib -* @run main/othervm -XX:+UseTLAB -XX:TLABSize=2k -XX:-ResizeTLAB jdk.jfr.event.allocation.TestObjectAllocationSampleEventThrottling + * @build sun.hotspot.WhiteBox + * + * @run driver jdk.test.lib.helpers.ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -XX:+UseTLAB -XX:TLABSize=2k -XX:-ResizeTLAB + * jdk.jfr.event.allocation.TestObjectAllocationSampleEventThrottling */ public class TestObjectAllocationSampleEventThrottling { private static final String EVENT_NAME = EventNames.ObjectAllocationSample; - private static final int BYTE_ARRAY_OVERHEAD = 16; // Extra bytes used by a byte array - private static final int OBJECT_SIZE = 100 * 1024; - private static final int OBJECT_SIZE_ALT = OBJECT_SIZE + 8; // Object size in case of disabled CompressedOops + private static final Boolean COMPRESSED_CLASS_PTRS = WhiteBox.getWhiteBox().getBooleanVMFlag("UseCompressedClassPointers"); + + private static final int BYTE_ARRAY_OVERHEAD = (Platform.is64bit() && !COMPRESSED_CLASS_PTRS) ? 24 : 16; + private static final int OBJECT_SIZE = 128 * 1024; + private static final int OBJECTS_TO_ALLOCATE = 100; private static final String BYTE_ARRAY_CLASS_NAME = new byte[0].getClass().getName(); private static int eventCount; diff --git a/test/jdk/jdk/jfr/event/gc/collection/TestG1ParallelPhases.java b/test/jdk/jdk/jfr/event/gc/collection/TestG1ParallelPhases.java index b41b6779ac88312e5454f9711390a161e2ce3633..80f060633ccf117442be7bd1ea29110bbbeb2cbc 100644 --- a/test/jdk/jdk/jfr/event/gc/collection/TestG1ParallelPhases.java +++ b/test/jdk/jdk/jfr/event/gc/collection/TestG1ParallelPhases.java @@ -126,7 +126,7 @@ public class TestG1ParallelPhases { // since we can not reliably guarantee that they occur (or not). Set<String> optPhases = of( // The following two phases only occur on evacuation failure. - "RemoveSelfForwardingPtr", + "RestoreRetainedRegions", "RestorePreservedMarks", "OptScanHR", diff --git a/test/jdk/jdk/jfr/event/gc/collection/TestGCCauseWithG1ConcurrentMark.java b/test/jdk/jdk/jfr/event/gc/collection/TestGCCauseWithG1ConcurrentMark.java index 730a3b700c6e80bc960efa444a4bba60fea65e99..d98fdb76e92bad3a2b965ddd9baa18e765627c16 100644 --- a/test/jdk/jdk/jfr/event/gc/collection/TestGCCauseWithG1ConcurrentMark.java +++ b/test/jdk/jdk/jfr/event/gc/collection/TestGCCauseWithG1ConcurrentMark.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -40,7 +40,8 @@ public class TestGCCauseWithG1ConcurrentMark { String testID = "G1ConcurrentMark"; String[] vmFlags = {"-XX:+UseG1GC", "-XX:+ExplicitGCInvokesConcurrent"}; String[] gcNames = {GCHelper.gcG1New, GCHelper.gcG1Old, GCHelper.gcG1Full}; - String[] gcCauses = {"G1 Evacuation Pause", "G1 Preventive Collection", "G1 Compaction Pause", "System.gc()"}; + String[] gcCauses = {"GCLocker Initiated GC", "G1 Evacuation Pause", "G1 Preventive Collection", + "G1 Compaction Pause", "System.gc()"}; GCGarbageCollectionUtil.test(testID, vmFlags, gcNames, gcCauses); } } diff --git a/test/jdk/jdk/jfr/event/gc/collection/TestGCCauseWithG1FullCollection.java b/test/jdk/jdk/jfr/event/gc/collection/TestGCCauseWithG1FullCollection.java index 67650dc3ba8a3d24161af3ab835df2e90793ed7b..737b94aa197977bd94bea05301b1821dce2b1e8f 100644 --- a/test/jdk/jdk/jfr/event/gc/collection/TestGCCauseWithG1FullCollection.java +++ b/test/jdk/jdk/jfr/event/gc/collection/TestGCCauseWithG1FullCollection.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -40,7 +40,8 @@ public class TestGCCauseWithG1FullCollection { String testID = "G1FullCollection"; String[] vmFlags = {"-XX:+UseG1GC"}; String[] gcNames = {GCHelper.gcG1New, GCHelper.gcG1Old, GCHelper.gcG1Full}; - String[] gcCauses = {"G1 Evacuation Pause", "G1 Preventive Collection", "G1 Compaction Pause", "System.gc()"}; + String[] gcCauses = {"GCLocker Initiated GC", "G1 Evacuation Pause", "G1 Preventive Collection", + "G1 Compaction Pause", "System.gc()"}; GCGarbageCollectionUtil.test(testID, vmFlags, gcNames, gcCauses); } } diff --git a/test/jdk/jdk/jfr/event/profiling/TestFullStackTrace.java b/test/jdk/jdk/jfr/event/profiling/TestFullStackTrace.java index 3306f5c0d31fb313b4297b91c1103bffb765e320..b9f23ebed86229834a8c6dceeac3f167ae88ae5f 100644 --- a/test/jdk/jdk/jfr/event/profiling/TestFullStackTrace.java +++ b/test/jdk/jdk/jfr/event/profiling/TestFullStackTrace.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -111,7 +111,7 @@ public class TestFullStackTrace { if(!isEventFound[i]) { // no assertion, let's retry. // Could be race condition, i.e safe point during Thread.sleep - System.out.println("Falied to validate all threads, will retry."); + System.out.println("Failed to validate all threads, will retry."); return false; } } diff --git a/test/jdk/jdk/jfr/event/runtime/TestActiveSettingEvent.java b/test/jdk/jdk/jfr/event/runtime/TestActiveSettingEvent.java index 5be87e78e10b1a793c550ef1c6fa5933f6def9ea..7f6f7be79d2752ccbca94d0b4c7edf8218857c87 100644 --- a/test/jdk/jdk/jfr/event/runtime/TestActiveSettingEvent.java +++ b/test/jdk/jdk/jfr/event/runtime/TestActiveSettingEvent.java @@ -58,8 +58,8 @@ public final class TestActiveSettingEvent { private static final String ACTIVE_SETTING_EVENT_NAME = EventNames.ActiveSetting; public static void main(String[] args) throws Throwable { - testDefaultSettings();; - testProfileSettings();; + testDefaultSettings(); + testProfileSettings(); testNewSettings(); testChangedSetting(); testUnregistered(); diff --git a/test/jdk/jdk/jfr/event/runtime/TestFinalizerStatisticsEvent.java b/test/jdk/jdk/jfr/event/runtime/TestFinalizerStatisticsEvent.java index ecec7c383fb7bc46fa9dc6bf9c3f9f420dce7030..8256a62b5712b62dce068da4ae9742003990ec12 100644 --- a/test/jdk/jdk/jfr/event/runtime/TestFinalizerStatisticsEvent.java +++ b/test/jdk/jdk/jfr/event/runtime/TestFinalizerStatisticsEvent.java @@ -34,17 +34,20 @@ import jdk.test.lib.jfr.TestClassLoader; /** * @test + * @bug 8266936 8276422 * @summary The test verifies that classes overriding finalize() are represented as events. * @key jfr * @requires vm.hasJFR * @library /test/lib /test/jdk * @run main/othervm -Xlog:class+unload,finalizer -Xmx16m jdk.jfr.event.runtime.TestFinalizerStatisticsEvent + * @run main/othervm -Xlog:class+unload,finalizer -Xmx16m --finalization=disabled jdk.jfr.event.runtime.TestFinalizerStatisticsEvent disabled */ public final class TestFinalizerStatisticsEvent { private final static String TEST_CLASS_NAME = "jdk.jfr.event.runtime.TestFinalizerStatisticsEvent$TestClassOverridingFinalize"; private final static String TEST_CLASS_UNLOAD_NAME = "jdk.jfr.event.runtime.TestFinalizerStatisticsEvent$TestClassUnloadOverridingFinalize"; private final static String EVENT_PATH = EventNames.FinalizerStatistics; + private static boolean disabled = false; // Declare as public static to prevent the compiler from optimizing away all unread writes public static TestClassLoader unloadableClassLoader; @@ -52,6 +55,10 @@ public final class TestFinalizerStatisticsEvent { public static Object overridingInstance; public static void main(String[] args) throws Throwable { + if (args.length > 0 && "disabled".equals(args[0])) { + disabled = true; + System.out.println("Testing with finalization disabled"); + } Recording recording1 = new Recording(); recording1.enable(EVENT_PATH); Recording recording2 = new Recording(); @@ -69,8 +76,12 @@ public final class TestFinalizerStatisticsEvent { recording1.stop(); // rotation writes an event for TEST_CLASS_NAME into recording1 which now has 4 events reflecting this test case (3 chunks + 1 unload) try { - verify(recording2); - verify(recording1); + if (disabled) { + verifyDisabled(recording1); + } else { + verifyEnabled(recording2); + verifyEnabled(recording1); + } } finally { recording2.close(); @@ -84,7 +95,8 @@ public final class TestFinalizerStatisticsEvent { System.gc(); } - private static void verify(Recording recording) throws Throwable { + /* Verify correct operation with finalization enabled */ + private static void verifyEnabled(Recording recording) throws Throwable { boolean foundTestClassName = false; boolean foundTestClassUnloadName = false; List<RecordedEvent> events = Events.fromRecording(recording); @@ -108,6 +120,19 @@ public final class TestFinalizerStatisticsEvent { Asserts.assertTrue(foundTestClassUnloadName, "The class: " + TEST_CLASS_UNLOAD_NAME + " overriding finalize() is not found"); } + /* Verify no jdk.FinalizerStatistics events with finalization disabled */ + private static void verifyDisabled(Recording recording) throws Throwable { + int f10nEvents = 0; + List<RecordedEvent> events = Events.fromRecording(recording); + for (RecordedEvent event : events) { + System.out.println("Event:" + event); + if ("jdk.FinalizerStatistics".equals(event.getEventType().getName())) { + f10nEvents++; + } + } + Asserts.assertEquals(f10nEvents, 0, "Finalization disabled, but recorded " + f10nEvents + " jdk.FinalizerStatistics events"); + } + static public class TestClassOverridingFinalize { public boolean finalized = false; diff --git a/test/jdk/jdk/jfr/event/runtime/TestNativeLibrariesEvent.java b/test/jdk/jdk/jfr/event/runtime/TestNativeLibrariesEvent.java index f32998209250e4cc0ca1fbc6d3fc01c1b8ae5203..77eb03628416b2db2d9205886316ac76a6d8add1 100644 --- a/test/jdk/jdk/jfr/event/runtime/TestNativeLibrariesEvent.java +++ b/test/jdk/jdk/jfr/event/runtime/TestNativeLibrariesEvent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -77,7 +77,10 @@ public class TestNativeLibrariesEvent { libTemplate = "lib%s.dylib"; } else if (Platform.isLinux()) { libTemplate = "lib%s.so"; + } else if (Platform.isAix()) { + libTemplate = "lib%s.so"; } + if (libTemplate == null) { throw new Exception("Unsupported OS"); } diff --git a/test/jdk/jdk/jfr/javaagent/EventEmitterAgent.java b/test/jdk/jdk/jfr/javaagent/EventEmitterAgent.java index 5a4cd4f534f5f372804a6e67a52b1dc0ba231661..ee829a412ed7470f76a31aee6a948af513f0f96c 100644 --- a/test/jdk/jdk/jfr/javaagent/EventEmitterAgent.java +++ b/test/jdk/jdk/jfr/javaagent/EventEmitterAgent.java @@ -24,6 +24,7 @@ package jdk.jfr.javaagent; import java.lang.instrument.Instrumentation; +import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -31,6 +32,7 @@ import jdk.jfr.Configuration; import jdk.jfr.Event; import jdk.jfr.Name; import jdk.jfr.Recording; +import jdk.jfr.consumer.RecordedEvent; import jdk.jfr.consumer.RecordingFile; import jdk.test.lib.Asserts; import jdk.test.lib.jfr.EventNames; @@ -38,7 +40,7 @@ import jdk.test.lib.jfr.EventNames; // Java agent that emits events public class EventEmitterAgent { - private static final long EVENTS = 150_000; + private static final long EVENTS = 15_000; private static final Path DUMP_PATH = Paths.get("dump.jfr").toAbsolutePath(); // Called when agent is loaded from command line @@ -88,10 +90,21 @@ public class EventEmitterAgent { } public static void validateRecording() throws Exception { - long testEventCount = RecordingFile.readAllEvents(DUMP_PATH) - .stream() - .filter(e -> e.getEventType().getName().equals("Test")) - .count(); + long testEventCount = 0; + try (RecordingFile rf = new RecordingFile(DUMP_PATH)) { + while (rf.hasMoreEvents()) { + RecordedEvent e = rf.readEvent(); + switch (e.getEventType().getName()) { + case "Test": + testEventCount++; + break; + case "jdk.DataLoss": + System.out.println(e); + break; + } + } + } + System.out.println("File size: " + Files.size(DUMP_PATH)); Asserts.assertEquals(testEventCount, EVENTS, "Mismatch in TestEvent count"); } } diff --git a/test/jdk/jdk/jfr/jcmd/TestJcmdConfigure.java b/test/jdk/jdk/jfr/jcmd/TestJcmdConfigure.java index a43e0da065abd3c28990cc7c06fd979bab2a4ddd..aa76f5014831bf267dff77fb53f982c230f4fea7 100644 --- a/test/jdk/jdk/jfr/jcmd/TestJcmdConfigure.java +++ b/test/jdk/jdk/jfr/jcmd/TestJcmdConfigure.java @@ -52,7 +52,6 @@ public class TestJcmdConfigure { private static final String GLOBAL_BUFFER_SIZE = "globalbuffersize"; private static final String THREAD_BUFFER_SIZE = "thread_buffer_size"; private static final String MAX_CHUNK_SIZE = "maxchunksize"; - private static final String SAMPLE_THREADS = "samplethreads"; private static final String UNSUPPORTED_OPTION = "unsupportedoption"; private static final String REPOSITORYPATH_1 = "." + File.pathSeparator + "repo1"; @@ -80,8 +79,6 @@ public class TestJcmdConfigure { test(GLOBAL_BUFFER_SIZE, 6); test(THREAD_BUFFER_SIZE, 5); test(MAX_CHUNK_SIZE, 14 * 1000 * 1000); - test(SAMPLE_THREADS, false); - test(SAMPLE_THREADS, true); testNegative(UNSUPPORTED_OPTION, 100000); testNegative(MAX_CHUNK_SIZE, -500); @@ -125,7 +122,6 @@ public class TestJcmdConfigure { case GLOBAL_BUFFER_SIZE: return Options.getGlobalBufferSize(); case THREAD_BUFFER_SIZE: return Options.getThreadBufferSize(); case MAX_CHUNK_SIZE: return Options.getMaxChunkSize(); - case SAMPLE_THREADS: return Options.getSampleThreads(); default: throw new RuntimeException("Unknown option " + name); } } diff --git a/test/jdk/jdk/jfr/jcmd/TestJcmdConfigureReadOnly.java b/test/jdk/jdk/jfr/jcmd/TestJcmdConfigureReadOnly.java new file mode 100644 index 0000000000000000000000000000000000000000..6ddf3a752342d04952ffda1df0933f226a2a88b4 --- /dev/null +++ b/test/jdk/jdk/jfr/jcmd/TestJcmdConfigureReadOnly.java @@ -0,0 +1,49 @@ +/* + * 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. + */ + +package jdk.jfr.jcmd; + +import jdk.test.lib.process.OutputAnalyzer; + +/** + * @test + * @summary The test verifies JFR.configure command can only set certain options before JFR is started. + * @key jfr + * @requires vm.hasJFR + * @library /test/lib /test/jdk + * @run main/othervm jdk.jfr.jcmd.TestJcmdConfigureReadOnly + */ +public class TestJcmdConfigureReadOnly { + public static void main(String[] args) throws Exception { + // Set an option before initializing JFR. + OutputAnalyzer output = JcmdHelper.jcmd("JFR.configure", "stackdepth=" + 128); + output.shouldContain("Stack depth: 128"); + // JFR.start will initialize JFR. + output = JcmdHelper.jcmd("JFR.start"); + JcmdAsserts.assertRecordingHasStarted(output); + // Attempt to set a new value after JFR initialization. + output = JcmdHelper.jcmd("JFR.configure", "stackdepth=" + 256); + // After initialization, the option is considered read-only. + output.shouldContain("Stack depth: 128"); + } +} diff --git a/test/jdk/jdk/jfr/jmx/streaming/TestMaxSize.java b/test/jdk/jdk/jfr/jmx/streaming/TestMaxSize.java index af7493212caed8d6a7732e18856d805c91436f05..7bf389c75ad8546565f927a2279f60a244aba627 100644 --- a/test/jdk/jdk/jfr/jmx/streaming/TestMaxSize.java +++ b/test/jdk/jdk/jfr/jmx/streaming/TestMaxSize.java @@ -70,12 +70,17 @@ public class TestMaxSize { while (directorySize(dir) < 50_000_000) { emitEvents(500_000); } + System.out.println("Before setMaxSize(1_000_000)"); + fileCount(dir); e.setMaxSize(1_000_000); + System.out.println("After setMaxSize(1_000_000)"); long count = fileCount(dir); - if (count > 2) { - // Two chunks can happen when header of new chunk is written and previous - // chunk is not finalized. - throw new Exception("Expected only one or two chunks with setMaxSize(1_000_000). Found " + count); + if (count > 3) { + // Three files can happen when: + // File 1: Header of new chunk is written to disk + // File 2: Previous chunk is not yet finalized and added to list of DiskChunks + // File 3: Previous previous file is in the list of DiskChunks. + throw new Exception("Expected at most three chunks with setMaxSize(1_000_000). Found " + count); } finished.set(true); } @@ -94,21 +99,24 @@ public class TestMaxSize { System.out.println("Files:"); AtomicInteger count = new AtomicInteger(); Files.list(dir).forEach(p -> { - System.out.println(p); + System.out.println(p + " " + fileSize(p)); count.incrementAndGet(); }); return count.get(); } private static long directorySize(Path dir) throws IOException { - long p = Files.list(dir).mapToLong(f -> { - try { - return Files.size(f); - } catch (IOException e) { - return 0; - } - }).sum(); + long p = Files.list(dir).mapToLong(f -> fileSize(f)).sum(); System.out.println("Directory size: " + p); return p; } + + private static long fileSize(Path p) { + try { + return Files.size(p); + } catch (IOException e) { + System.out.println("Could not determine file size for " + p); + return 0; + } + } } diff --git a/test/jdk/jdk/jfr/jvm/TestDumpOnCrash.java b/test/jdk/jdk/jfr/jvm/TestDumpOnCrash.java index 3869509b2426ec6233eacd34f592453776f55b5d..5cd1f435bfd7e496eb9b96204ee3d3f0868c5797 100644 --- a/test/jdk/jdk/jfr/jvm/TestDumpOnCrash.java +++ b/test/jdk/jdk/jfr/jvm/TestDumpOnCrash.java @@ -26,6 +26,7 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.ArrayList; import java.util.List; import jdk.internal.misc.Unsafe; @@ -74,22 +75,42 @@ public class TestDumpOnCrash { } public static void main(String[] args) throws Exception { + // Test without dumppath test(CrasherIllegalAccess.class, "", true); test(CrasherIllegalAccess.class, "", false); test(CrasherHalt.class, "", true); test(CrasherHalt.class, "", false); + // Test with dumppath + Path dumppath = Files.createTempDirectory(null); + try { + test(CrasherIllegalAccess.class, "", true, dumppath.toString()); + test(CrasherIllegalAccess.class, "", false, dumppath.toString()); + test(CrasherHalt.class, "", true, dumppath.toString()); + test(CrasherHalt.class, "", false, dumppath.toString()); + } finally { + dumppath.toFile().delete(); + } + // Test is excluded until 8219680 is fixed // @ignore 8219680 // test(CrasherSig.class, "FPE", true); } private static void test(Class<?> crasher, String signal, boolean disk) throws Exception { + test(crasher, signal, disk, null); + } + + private static void test(Class<?> crasher, String signal, boolean disk, String dumppath) throws Exception { + test(crasher, signal, disk, dumppath, dumppath); + } + + private static void test(Class<?> crasher, String signal, boolean disk, String dumppath, String expectedPath) throws Exception { // The JVM may be in a state it can't recover from, so try three times // before concluding functionality is not working. for (int attempt = 0; attempt < ATTEMPTS; attempt++) { try { - verify(runProcess(crasher, signal, disk)); + verify(runProcess(crasher, signal, disk, dumppath), expectedPath); return; } catch (Exception e) { System.out.println("Attempt " + attempt + ". Verification failed:"); @@ -105,17 +126,19 @@ public class TestDumpOnCrash { throw new Exception(ATTEMPTS + " attempts with failure!"); } - private static long runProcess(Class<?> crasher, String signal, boolean disk) throws Exception { + private static long runProcess(Class<?> crasher, String signal, boolean disk, String dumppath) throws Exception { System.out.println("Test case for crasher " + crasher.getName()); - final String flightRecordingOptions = "dumponexit=true,disk=" + Boolean.toString(disk); - Process p = ProcessTools.createTestJvm( - "-Xmx64m", - "-XX:-CreateCoredumpOnCrash", - "--add-exports=java.base/jdk.internal.misc=ALL-UNNAMED", - "-XX:StartFlightRecording:" + flightRecordingOptions, - crasher.getName(), - signal) - .start(); + List<String> options = new ArrayList<>(); + options.add("-Xmx64m"); + options.add("-XX:-CreateCoredumpOnCrash"); + options.add("--add-exports=java.base/jdk.internal.misc=ALL-UNNAMED"); + options.add("-XX:StartFlightRecording:dumponexit=true,disk=" + Boolean.toString(disk)); + if (dumppath != null) { + options.add("-XX:FlightRecorderOptions=dumppath=" + dumppath); + } + options.add(crasher.getName()); + options.add(signal); + Process p = ProcessTools.createTestJvm(options).start(); OutputAnalyzer output = new OutputAnalyzer(p); System.out.println("========== Crasher process output:"); @@ -125,9 +148,10 @@ public class TestDumpOnCrash { return p.pid(); } - private static void verify(long pid) throws IOException { + private static void verify(long pid, String dumppath) throws IOException { String fileName = "hs_err_pid" + pid + ".jfr"; - Path file = Paths.get(fileName).toAbsolutePath().normalize(); + Path file = (dumppath == null) ? Paths.get(fileName) : Paths.get(dumppath, fileName); + file = file.toAbsolutePath().normalize(); Asserts.assertTrue(Files.exists(file), "No emergency jfr recording file " + file + " exists"); Asserts.assertNotEquals(Files.size(file), 0L, "File length 0. Should at least be some bytes"); diff --git a/test/jdk/jdk/jfr/jvm/TestWaste.java b/test/jdk/jdk/jfr/jvm/TestWaste.java new file mode 100644 index 0000000000000000000000000000000000000000..0cc1010765eb633cbba83d77deb2b5e9195f83ee --- /dev/null +++ b/test/jdk/jdk/jfr/jvm/TestWaste.java @@ -0,0 +1,128 @@ +/* + * 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. + */ + +package jdk.jfr.jvm; + +import jdk.jfr.Recording; +import jdk.jfr.Event; +import jdk.jfr.consumer.RecordingFile; +import jdk.jfr.internal.test.WhiteBox; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.text.ParseException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Random; + +import jdk.jfr.Configuration; + +/** + * @test + * @key jfr + * @requires vm.hasJFR + * @library /test/lib /test/jdk + * @modules jdk.jfr/jdk.jfr.internal.test + * @run main/othervm -XX:TLABSize=2k jdk.jfr.jvm.TestWaste + */ +public class TestWaste { + static List<Object> list = new LinkedList<>(); + static Random random = new Random(); + + public static void main(String... args) throws Exception { + WhiteBox.setWriteAllObjectSamples(true); + Configuration c = Configuration.getConfiguration("profile"); + Path file = Path.of("recording.jfr"); + Path scrubbed = Path.of("scrubbed.jfr"); + try (Recording r = new Recording(c)) { + // Old objects that are cleared out should not create waste + r.enable("jdk.OldObjectSample") + .with("cutoff", "infinity") + .withStackTrace(); + // No stack trace waste from allocation sample + r.enable("jdk.ObjectAllocationSample") + .with("throttle", "1000/s") + .withoutStackTrace(); + // Unused threads should not create unreasonable amount of waste + r.disable("jdk.ThreadStart"); + r.disable("jdk.ThreadStop"); + // jdk.GCPhaseParallel can often, but not always, take up a very + // large part of the recording. Disable to make test more stable + r.disable("jdk.GCPhaseParallel"); + r.start(); + // Generate data + for (int i = 0; i < 5_000_000; i++) { + foo(50); + if (i % 3_000_000 == 0) { + System.gc(); + } + if (i % 10_000 == 0) { + Thread t = new Thread(); + t.start(); + } + } + r.stop(); + r.dump(file); + final Map<String, Long> histogram = new HashMap<>(); + try (RecordingFile rf = new RecordingFile(file)) { + rf.write(scrubbed, event -> { + String key = event.getEventType().getName(); + histogram.merge(key, 1L, (x, y) -> x + y); + return true; + }); + } + for (var entry : histogram.entrySet()) { + System.out.println(entry.getKey() + " " + entry.getValue()); + } + float fileSize = Files.size(file); + System.out.printf("File size: %.2f MB\n", fileSize / (1024 * 1024)); + float scrubbedSize = Files.size(scrubbed); + System.out.printf("Scrubbed size: %.2f MB\n", scrubbedSize / (1024 * 1024)); + float waste = 1 - scrubbedSize / fileSize; + System.out.printf("Waste: %.2f%%\n", 100 * waste); + if (waste > 0.10) { + throw new AssertionError("Found more than 10% waste"); + } + } + } + + static void foo(int depth) { + bar(depth - 1); + } + + static void bar(int depth) { + if (depth > 1) { + if (random.nextBoolean()) { + foo(depth); + } else { + bar(depth - 1); + } + } else { + list.add(new String("hello")); + } + } +} diff --git a/test/jdk/jdk/jfr/tool/TestPrintXML.java b/test/jdk/jdk/jfr/tool/TestPrintXML.java index 4480c23c7887bda5b64d79a41abab71b0ac2eff1..dd53955e40174f859b1c9ab2fd5d26349e2355f2 100644 --- a/test/jdk/jdk/jfr/tool/TestPrintXML.java +++ b/test/jdk/jdk/jfr/tool/TestPrintXML.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -47,6 +47,7 @@ import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; import org.xml.sax.XMLReader; +import org.xml.sax.Locator; import org.xml.sax.helpers.DefaultHandler; import jdk.jfr.Timespan; @@ -105,7 +106,14 @@ public class TestPrintXML { System.out.println(); System.out.println("Was (XML)"); System.out.println("----------------------"); - System.out.println(xmlEvent); + if (xmlEvent.begin > 0 && xmlEvent.end > 0) { + String lines[] = xml.split("\\r?\\n"); + for (int i = xmlEvent.begin - 1; i < xmlEvent.end; i++) { + System.out.println(i + " " + lines[i]); + } + } else { + System.out.println("Could not locate XML position"); + } System.out.println(); throw new Exception("Event doesn't match"); } @@ -164,6 +172,8 @@ public class TestPrintXML { static class XMLEvent { String name; private Map<String, Object> values = new HashMap<>(); + private int begin = -1; + private int end = -1; XMLEvent(String name) { this.name = name; @@ -172,10 +182,15 @@ public class TestPrintXML { public static final class RecordingHandler extends DefaultHandler { + private Locator locator; private Stack<Object> objects = new Stack<>(); private Stack<SimpleEntry<String, String>> elements = new Stack<>(); private List<XMLEvent> events = new ArrayList<>(); + public void setDocumentLocator(Locator locator) { + this.locator = locator; + } + @Override public void startElement(String uri, String localName, String qName, Attributes attrs) throws SAXException { elements.push(new SimpleEntry<>(attrs.getValue("name"), attrs.getValue("index"))); @@ -187,7 +202,9 @@ public class TestPrintXML { switch (qName) { case "event": - objects.push(new XMLEvent(attrs.getValue("type"))); + XMLEvent event = new XMLEvent(attrs.getValue("type")); + event.begin = locator.getLineNumber(); + objects.push(event); break; case "struct": objects.push(new HashMap<String, Object>()); @@ -223,7 +240,9 @@ public class TestPrintXML { String name = element.getKey(); Object value = objects.pop(); if (objects.isEmpty()) { - events.add((XMLEvent) value); + XMLEvent event = (XMLEvent) value; + event.end = locator.getLineNumber(); + events.add(event); return; } if (value instanceof StringBuilder) { diff --git a/test/jdk/jdk/jfr/tool/TestScrub.java b/test/jdk/jdk/jfr/tool/TestScrub.java new file mode 100644 index 0000000000000000000000000000000000000000..32b1767cf7d5ef7af6d6935f275e22171e6b5e57 --- /dev/null +++ b/test/jdk/jdk/jfr/tool/TestScrub.java @@ -0,0 +1,313 @@ +/* + * 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. + */ + +package jdk.jfr.tool; + +import java.io.FileWriter; +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import jdk.test.lib.Utils; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.jfr.Name; +import jdk.jfr.Recording; +import jdk.jfr.Category; +import jdk.jfr.Event; +import jdk.jfr.consumer.RecordedEvent; +import jdk.jfr.consumer.RecordingFile; + +/** + * @test + * @summary Test jfr scrub + * @key jfr + * @requires vm.hasJFR + * @library /test/lib /test/jdk + * @run main/othervm jdk.jfr.tool.TestScrub + */ +public class TestScrub { + + @Name("example.Tiger") + @Category("Mammal") + private static class TigerEvent extends Event { + } + + @Name("example.Zebra") + @Category("Mammal") + + private static class ZebraEvent extends Event { + } + + @Name("example.Tigerfish") + @Category("Fish") + private static class TigerfishEvent extends Event { + } + + public static void main(String[] args) throws Throwable { + Path file = Path.of("recording.jfr"); + Path autogenerated = Path.of("recording-scrubbed.jfr"); + + try (Recording r = new Recording()) { + r.start(); + emit(100, "India", TigerEvent.class); + emit(100, "Namibia", ZebraEvent.class); + emit(10000, "Lake Tanganyika", TigerfishEvent.class); + r.stop(); + r.dump(file); + } + testAutogeneratedFilename(file, autogenerated); + + testEventInclude(file); + testEventExclude(file); + testEventMixedIncludeExclude(file); + + testCategoryExclude(file); + testCategoryInclude(file); + + testThreadExclude(file); + testThreadInclude(file); + } + + private static void testAutogeneratedFilename(Path file, Path autogenerated) throws Throwable { + List<String> arguments = new ArrayList<>(); + arguments.add("scrub"); + arguments.add(file.toAbsolutePath().toString()); + ExecuteHelper.jfr(arguments.toArray(String[]::new)); + + if (!Files.exists(autogenerated)) { + throw new AssertionError("Expected to find auto-generated file " + autogenerated); + } + Files.delete(autogenerated); + } + + private static void testEventInclude(Path file) throws Throwable { + for (var event : scrub(file, "--include-events", "Zebra")) { + assertEvent(event, "Zebra"); + assertNotEvent(event, "Tiger", "Tigerfish"); + } + for (var event : scrub(file, "--include-events", "Tiger*")) { + assertEvent(event, "Tiger", "Tigerfish"); + assertNotEvent(event, "Zebra"); + } + for (var event : scrub(file, "--include-events", "Tiger,Zebra")) { + assertEvent(event, "Tiger", "Zebra"); + assertNotEvent(event, "Tigerfish"); + } + for (var event : scrub(file, "--include-events", "Tiger", "--include-events", "Zebra")) { + assertEvent(event, "Tiger", "Zebra"); + assertNotEvent(event, "Tigerfish"); + } + } + + private static void testEventExclude(Path file) throws Throwable { + for (var event : scrub(file, "--exclude-events", "Zebra")) { + assertNotEvent(event, "Zebra"); + assertEvent(event, "Tiger", "Tigerfish"); + } + for (var event : scrub(file, "--exclude-events", "Tiger*")) { + assertEvent(event, "Zebra"); + assertNotEvent(event, "Tiger", "Tigerfish"); + } + for (var event : scrub(file, "--exclude-events", "Tiger,Zebra")) { + assertEvent(event, "Tigerfish"); + assertNotEvent(event, "Tiger", "Zebra"); + } + + for (var event : scrub(file, "--exclude-events", "Tiger", "--exclude-events", "Zebra")) { + assertEvent(event, "Tigerfish"); + assertNotEvent(event, "Tiger", "Zebra"); + } + } + + private static void testEventMixedIncludeExclude(Path file) throws Throwable { + for (var event : scrub(file, "--include-events", "Tiger*", "--exclude-events", "Tigerfish")) { + assertNotEvent(event, "Zebra", "Tigerfish"); + assertEvent(event, "Tiger"); + } + for (var event : scrub(file, "--exclude-events", "Tiger*", "--include-events", "Tiger")) { + assertEvent(event, "Zebra", "Tiger"); + assertNotEvent(event, "Tigerfish"); + } + for (var event : scrub(file, "--exclude-events", "example.*", "--include-events", "example.*")) { + assertNotEvent(event, "Tigerfish", "Tiger", "Zebra"); + } + for (var event : scrub(file, "--include-events", "example.*", "--exclude-events", "example.*")) { + assertNotEvent(event, "Tigerfish", "Tiger", "Zebra"); + } + } + + private static void testCategoryInclude(Path file) throws Throwable { + for (var event : scrub(file, "--include-categories", "Mammal")) { + assertEvent(event, "Zebra", "Tiger"); + assertNotEvent(event, "Tigerfish"); + } + for (var event : scrub(file, "--include-categories", "Sahara")) { + assertNotEvent(event, "Tiger", "Tigerfish", "Zebra"); + } + for (var event : scrub(file, "--include-categories", "Fish,Mammal")) { + assertEvent(event, "Tiger", "Zebra", "Tigerfish"); + } + for (var event : scrub(file, "--include-categories", "Mammal", "--include-categories", "Fish")) { + assertEvent(event, "Tiger", "Zebra", "Tigerfish"); + } + } + + private static void testCategoryExclude(Path file) throws Throwable { + for (var event : scrub(file, "--exclude-categories", "Mammal")) { + assertNotEvent(event, "Zebra", "Tiger"); + assertEvent(event, "Tigerfish"); + } + for (var event : scrub(file, "--exclude-categories", "Mammal,Fish")) { + assertNotEvent(event, "Zebra", "Tiger", "Tigerfish"); + } + for (var event : scrub(file, "--exclude-categories", "Mammal")) { + assertNotEvent(event, "Zebra", "Tiger"); + assertEvent(event, "Tigerfish"); + } + for (var event : scrub(file, "--exclude-categories", "Mammal")) { + assertNotEvent(event, "Zebra", "Tiger"); + assertEvent(event, "Tigerfish"); + } + } + + private static void testThreadInclude(Path file) throws Throwable { + for (var event : scrub(file, "--include-threads", "Namibia")) { + assertThread(event, "Namibia"); + assertNotThread(event, "India", "Lake Tanganyika"); + } + + for (var event : scrub(file, "--include-threads", "Nam*")) { + assertThread(event, "Namibia"); + assertNotThread(event, "Lake Tanganyika", "India"); + } + + for (var event : scrub(file, "--include-threads", "Namibia,Lake")) { + assertThread(event, "Namibia", "Lake Tanganyika"); + assertNotThread(event, "India"); + } + + for (var event : scrub(file, "--include-threads", "India", "--include-threads", "Lake Tanganyika")) { + assertThread(event, "India", "Lake Tanganyika"); + assertNotThread(event, "Namibia"); + } + } + + private static void testThreadExclude(Path file) throws Throwable { + for (var event : scrub(file, "--exclude-threads", "Namibia")) { + assertThread(event, "India", "Lake Tanganyika"); + assertNotThread(event, "Namibia"); + } + + for (var event : scrub(file, "--exclude-threads", "Nam*")) { + assertThread(event, "Lake Tanganyika", "India"); + assertNotThread(event, "Namibia"); + } + + for (var event : scrub(file, "--exclude-threads", "Namibia,Lake Tanganyika")) { + assertThread(event, "India"); + assertNotThread(event, "Namibia", "Lake Tanganyika"); + } + + for (var event : scrub(file, "--exclude-events", "India", "--include-events", "Lake Tanganyika")) { + assertThread(event, "Namibia"); + assertNotThread(event, "India", "Lake Tanganyika"); + } + } + + private static void assertNotThread(RecordedEvent event, String... threadNames) { + String s = event.getThread().getJavaName(); + for (String threadName : threadNames) { + if (threadName.equals(s)) { + throw new AssertionError("Found unexpected thread" + threadName); + } + } + } + + private static void assertThread(RecordedEvent event, String... threadNames) { + String s = event.getThread().getJavaName(); + for (String threadName : threadNames) { + if (threadName.equals(s)) { + return; + } + } + throw new AssertionError("Found unexpected thread" + s); + } + + private static void assertNotEvent(RecordedEvent event, String... eventNames) { + String s = event.getEventType().getName(); + for (String eventName : eventNames) { + String n = "example." + eventName; + if (n.equals(s)) { + throw new AssertionError("Found unexpected " + eventName + " event"); + } + } + } + + private static void assertEvent(RecordedEvent event, String... eventNames) { + String s = event.getEventType().getName(); + for (String eventName : eventNames) { + String n = "example." + eventName; + if (n.equals(s)) { + return; + } + } + throw new AssertionError("Found unexpected " + s + " event"); + } + + private static List<RecordedEvent> scrub(Path input, String... options) throws Throwable { + Path output = Path.of("scrubbed.jfr"); + List<String> arguments = new ArrayList<>(); + arguments.add("scrub"); + arguments.addAll(Arrays.asList(options)); + arguments.add(input.toAbsolutePath().toString()); + arguments.add(output.toAbsolutePath().toString()); + + var outp = ExecuteHelper.jfr(arguments.toArray(String[]::new)); + System.out.println(outp.getStderr()); + System.out.println(outp.getStdout()); + List<RecordedEvent> events = RecordingFile.readAllEvents(output); + Files.delete(output); + return events; + } + + private static void emit(int count, String threadName, Class<? extends Event> eventClass) throws Throwable { + Thread t = new Thread(() -> emitEvents(count, eventClass), threadName); + t.start(); + t.join(); + } + + private static void emitEvents(int count, Class<? extends Event> eventClass) { + for (int i = 0; i < count; i++) { + try { + Event event = eventClass.getDeclaredConstructor().newInstance(); + event.commit(); + } catch (Exception e) { + e.printStackTrace(); + } + } + } +} diff --git a/test/jdk/jdk/nio/zipfs/TestPosix.java b/test/jdk/jdk/nio/zipfs/TestPosix.java index 2be70758fbc99cba17c0a58b054043c4b6c6ae22..f629dfef2225d050cb1cb3685471b94964fc3fbd 100644 --- a/test/jdk/jdk/nio/zipfs/TestPosix.java +++ b/test/jdk/jdk/nio/zipfs/TestPosix.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, SAP SE. All rights reserved. + * Copyright (c) 2019, 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 @@ -69,11 +69,11 @@ import static org.testng.Assert.fail; /** * @test * @bug 8213031 8273935 + * @summary Test POSIX ZIP file operations. * @modules jdk.zipfs * jdk.jartool * @run testng TestPosix * @run testng/othervm/java.security.policy=test.policy.posix TestPosix - * @summary Test POSIX zip file operations. */ public class TestPosix { private static final ToolProvider JAR_TOOL = ToolProvider.findFirst("jar") @@ -528,9 +528,11 @@ public class TestPosix { } // check entries on copied zipfs - no permission data should exist - try (FileSystem zip = FileSystems.newFileSystem(ZIP_FILE_COPY, ENV_DEFAULT)) { - checkEntries(zip, checkExpects.noPermDataInZip); - } + if (System.getProperty("os.name").toLowerCase().contains("windows")) + try (FileSystem zip = FileSystems.newFileSystem(ZIP_FILE_COPY, + ENV_DEFAULT)) { + checkEntries(zip, checkExpects.noPermDataInZip); + } } /** diff --git a/test/jdk/jdk/nio/zipfs/ZipFSOutputStreamTest.java b/test/jdk/jdk/nio/zipfs/ZipFSOutputStreamTest.java index fe59857879b3daeff8a19910de8a93bd46e2a9db..77f866e9fdfdff4bab60eacfd71f280e3bd3387e 100644 --- a/test/jdk/jdk/nio/zipfs/ZipFSOutputStreamTest.java +++ b/test/jdk/jdk/nio/zipfs/ZipFSOutputStreamTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -35,15 +35,15 @@ import java.nio.file.FileSystem; import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.Path; +import java.util.Arrays; import java.util.Map; -import java.util.Random; /** * @test * @summary Verify that the outputstream created for zip file entries, through the ZipFileSystem * works fine for varying sizes of the zip file entries - * @bug 8190753 8011146 + * @bug 8190753 8011146 8279536 * @run testng/timeout=300 ZipFSOutputStreamTest */ public class ZipFSOutputStreamTest { @@ -87,7 +87,9 @@ public class ZipFSOutputStreamTest { @Test(dataProvider = "zipFSCreationEnv") public void testOutputStream(final Map<String, ?> env) throws Exception { final byte[] chunk = new byte[1024]; - new Random().nextBytes(chunk); + // fill it with some fixed content (the fixed content will later on help ease + // the verification of the content written out) + Arrays.fill(chunk, (byte) 42); try (final FileSystem zipfs = FileSystems.newFileSystem(ZIP_FILE, env)) { // create the zip with varying sized entries for (final Map.Entry<String, Long> entry : ZIP_ENTRIES.entrySet()) { @@ -95,9 +97,12 @@ public class ZipFSOutputStreamTest { if (entryPath.getParent() != null) { Files.createDirectories(entryPath.getParent()); } + long start = System.currentTimeMillis(); try (final OutputStream os = Files.newOutputStream(entryPath)) { writeAsChunks(os, chunk, entry.getValue()); } + System.out.println("Wrote entry " + entryPath + " of bytes " + entry.getValue() + + " in " + (System.currentTimeMillis() - start) + " milli seconds"); } } // now verify the written content @@ -108,15 +113,15 @@ public class ZipFSOutputStreamTest { final byte[] buf = new byte[chunk.length]; int numRead; long totalRead = 0; + long start = System.currentTimeMillis(); while ((numRead = is.read(buf)) != -1) { totalRead += numRead; // verify the content - for (int i = 0, chunkoffset = (int) ((totalRead - numRead) % chunk.length); - i < numRead; i++, chunkoffset++) { - Assert.assertEquals(buf[i], chunk[chunkoffset % chunk.length], - "Unexpected content in " + entryPath); - } + Assert.assertEquals(Arrays.mismatch(buf, chunk), -1, + "Unexpected content in " + entryPath); } + System.out.println("Read entry " + entryPath + " of bytes " + totalRead + + " in " + (System.currentTimeMillis() - start) + " milli seconds"); Assert.assertEquals(totalRead, (long) entry.getValue(), "Unexpected number of bytes read from zip entry " + entryPath); } diff --git a/test/jdk/jdk/nio/zipfs/ZipFSTester.java b/test/jdk/jdk/nio/zipfs/ZipFSTester.java index 48244bfc46b06e824ca1cdb5e178a4e59f5f8a93..08c998ca221854bf84c51abe12bce026594857ea 100644 --- a/test/jdk/jdk/nio/zipfs/ZipFSTester.java +++ b/test/jdk/jdk/nio/zipfs/ZipFSTester.java @@ -73,7 +73,7 @@ import static java.nio.file.StandardCopyOption.*; * @test * @bug 6990846 7009092 7009085 7015391 7014948 7005986 7017840 7007596 * 7157656 8002390 7012868 7012856 8015728 8038500 8040059 8069211 - * 8131067 8034802 8210899 8273961 + * 8131067 8034802 8210899 8273961 8271079 * @summary Test Zip filesystem provider * @modules jdk.zipfs * @run main ZipFSTester diff --git a/test/jdk/jdk/nio/zipfs/jarfs/JFSTester.java b/test/jdk/jdk/nio/zipfs/jarfs/JFSTester.java index 5b912c239bd0104eaa6f6b385499af73432a2493..82505e24e6cfc7304743368ebb51cf1c00e70ec7 100644 --- a/test/jdk/jdk/nio/zipfs/jarfs/JFSTester.java +++ b/test/jdk/jdk/nio/zipfs/jarfs/JFSTester.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8164389 8222440 + * @bug 8164389 8222440 8271079 * @summary walk entries in a multi-release jar file via jdk.zipfs * @modules jdk.jartool * jdk.zipfs @@ -146,4 +146,58 @@ public class JFSTester { throw new UncheckedIOException(x); } } + + @Test + public void testToUri() throws IOException { + // treat multi-release jar as unversioned + Map<String, String> env = new HashMap<>(); + Set<String> contents = doTestUri(env); + Set<String> expectedContents = Set.of( + "!/root/dir1/leaf1.txt", + "!/root/dir1/leaf2.txt", + "!/root/dir2/leaf3.txt", + "!/root/dir2/leaf4.txt" + ); + Assert.assertEquals(contents, expectedContents); + + // open file as multi-release for version 9 + env.put("multi-release", "9"); + contents = doTestUri(env); + expectedContents = Set.of( + "!/root/dir1/leaf1.txt", + "!/root/dir1/leaf2.txt", + "!/META-INF/versions/9/root/dir2/leaf3.txt", + "!/META-INF/versions/9/root/dir2/leaf4.txt", + "!/META-INF/versions/9/root/dir3/leaf5.txt", + "!/META-INF/versions/9/root/dir3/leaf6.txt" + ); + Assert.assertEquals(contents, expectedContents); + + // open file as multi-release for version 10 + env.put("multi-release", "10"); + contents = doTestUri(env); + expectedContents = Set.of( + "!/root/dir1/leaf1.txt", + "!/root/dir1/leaf2.txt", + "!/META-INF/versions/9/root/dir2/leaf3.txt", + "!/META-INF/versions/9/root/dir2/leaf4.txt", + "!/META-INF/versions/10/root/dir3/leaf5.txt", + "!/META-INF/versions/10/root/dir3/leaf6.txt" + ); + Assert.assertEquals(contents, expectedContents); + } + + private Set<String> doTestUri(Map<String,String> env) throws IOException { + Set<String> contents; + try (FileSystem fs = FileSystems.newFileSystem(jarURI, env)) { + Path root = fs.getPath("root"); + int prefix = root.toUri().toString().indexOf('!'); + contents = Files.walk(root) + .filter(p -> !Files.isDirectory(p)) + .map(p -> p.toUri().toString().substring(prefix)) + .sorted() + .collect(Collectors.toSet()); + } + return contents; + } } diff --git a/test/jdk/jdk/nio/zipfs/test.policy b/test/jdk/jdk/nio/zipfs/test.policy index 1e91f1f8dcf9174a84cd1e70fb965621042c15c5..d0492d0fc7a142212a436f84d1080221d6649e9e 100644 --- a/test/jdk/jdk/nio/zipfs/test.policy +++ b/test/jdk/jdk/nio/zipfs/test.policy @@ -3,4 +3,5 @@ grant { permission java.util.PropertyPermission "test.jdk","read"; permission java.util.PropertyPermission "test.src","read"; permission java.util.PropertyPermission "user.dir","read"; + permission java.lang.RuntimePermission "accessUserInformation"; }; diff --git a/test/jdk/jdk/nio/zipfs/test.policy.posix b/test/jdk/jdk/nio/zipfs/test.policy.posix index 601ef439ab4af23a4e5d0d449c0427cdc8971a1b..77415b0f4ba13d5651b9e5d29b53ed541a44302d 100644 --- a/test/jdk/jdk/nio/zipfs/test.policy.posix +++ b/test/jdk/jdk/nio/zipfs/test.policy.posix @@ -5,4 +5,5 @@ grant { permission java.util.PropertyPermission "test.src","read"; permission java.util.PropertyPermission "user.dir","read"; permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.module"; + permission java.lang.RuntimePermission "accessUserInformation"; }; diff --git a/test/jdk/jdk/security/jarsigner/JarWithOneNonDisabledDigestAlg.java b/test/jdk/jdk/security/jarsigner/JarWithOneNonDisabledDigestAlg.java new file mode 100644 index 0000000000000000000000000000000000000000..899500672ad4d56bc3be1f119f52b2b3bb7f5561 --- /dev/null +++ b/test/jdk/jdk/security/jarsigner/JarWithOneNonDisabledDigestAlg.java @@ -0,0 +1,169 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8278851 + * @summary Check that jar entry with at least one non-disabled digest + * algorithm in manifest is treated as signed + * @modules java.base/sun.security.tools.keytool + * @library /test/lib + * @build jdk.test.lib.util.JarUtils + * jdk.test.lib.security.SecurityUtils + * @run main/othervm JarWithOneNonDisabledDigestAlg + */ + +import java.io.InputStream; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.security.CodeSigner; +import java.security.KeyStore; +import java.util.Enumeration; +import java.util.List; +import java.util.Locale; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import java.util.zip.ZipFile; +import jdk.security.jarsigner.JarSigner; + +import jdk.test.lib.util.JarUtils; +import jdk.test.lib.security.SecurityUtils; + +public class JarWithOneNonDisabledDigestAlg { + + private static final String PASS = "changeit"; + private static final String TESTFILE1 = "testfile1"; + private static final String TESTFILE2 = "testfile2"; + + public static void main(String[] args) throws Exception { + SecurityUtils.removeFromDisabledAlgs("jdk.jar.disabledAlgorithms", + List.of("SHA1")); + Files.write(Path.of(TESTFILE1), TESTFILE1.getBytes()); + JarUtils.createJarFile(Path.of("unsigned.jar"), Path.of("."), + Path.of(TESTFILE1)); + + genkeypair("-alias SHA1 -sigalg SHA1withRSA"); + genkeypair("-alias SHA256 -sigalg SHA256withRSA"); + + KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); + try (FileInputStream fis = new FileInputStream("keystore")) { + ks.load(fis, PASS.toCharArray()); + } + + // Sign JAR twice with same signer but different digest algorithms + // so that each entry in manifest file contains two digest values. + signJarFile(ks, "SHA1", "MD5", "unsigned.jar", "signed.jar"); + signJarFile(ks, "SHA1", "SHA1", "signed.jar", "signed2.jar"); + checkThatJarIsSigned("signed2.jar", false); + + // add another file to the JAR + Files.write(Path.of(TESTFILE2), "testFile2".getBytes()); + JarUtils.updateJarFile(Path.of("signed2.jar"), Path.of("."), + Path.of(TESTFILE2)); + + // Sign again with different signer (SHA256) and SHA-1 digestalg. + // TESTFILE1 should have two signers and TESTFILE2 should have one + // signer. + signJarFile(ks, "SHA256", "SHA1", "signed2.jar", "multi-signed.jar"); + + checkThatJarIsSigned("multi-signed.jar", true); + } + + private static KeyStore.PrivateKeyEntry getEntry(KeyStore ks, String alias) + throws Exception { + + return (KeyStore.PrivateKeyEntry) + ks.getEntry(alias, + new KeyStore.PasswordProtection(PASS.toCharArray())); + } + + private static void genkeypair(String cmd) throws Exception { + cmd = "-genkeypair -keystore keystore -storepass " + PASS + + " -keypass " + PASS + " -keyalg rsa -dname CN=Duke " + cmd; + sun.security.tools.keytool.Main.main(cmd.split(" ")); + } + + private static void signJarFile(KeyStore ks, String alias, + String digestAlg, String inputFile, String outputFile) + throws Exception { + + JarSigner signer = new JarSigner.Builder(getEntry(ks, alias)) + .digestAlgorithm(digestAlg) + .signerName(alias) + .build(); + + try (ZipFile in = new ZipFile(inputFile); + FileOutputStream out = new FileOutputStream(outputFile)) { + signer.sign(in, out); + } + } + + private static void checkThatJarIsSigned(String jarFile, boolean multi) + throws Exception { + + try (JarFile jf = new JarFile(jarFile, true)) { + Enumeration<JarEntry> entries = jf.entries(); + while (entries.hasMoreElements()) { + JarEntry entry = entries.nextElement(); + if (entry.isDirectory() || isSigningRelated(entry.getName())) { + continue; + } + InputStream is = jf.getInputStream(entry); + while (is.read() != -1); + CodeSigner[] signers = entry.getCodeSigners(); + if (signers == null) { + throw new Exception("JarEntry " + entry.getName() + + " is not signed"); + } else if (multi) { + if (entry.getName().equals(TESTFILE1) && + signers.length != 2) { + throw new Exception("Unexpected number of signers " + + "for " + entry.getName() + ": " + signers.length); + } else if (entry.getName().equals(TESTFILE2) && + signers.length != 1) { + throw new Exception("Unexpected number of signers " + + "for " + entry.getName() + ": " + signers.length); + } + } + } + } + } + + private static boolean isSigningRelated(String name) { + name = name.toUpperCase(Locale.ENGLISH); + if (!name.startsWith("META-INF/")) { + return false; + } + name = name.substring(9); + if (name.indexOf('/') != -1) { + return false; + } + return name.endsWith(".SF") + || name.endsWith(".DSA") + || name.endsWith(".RSA") + || name.endsWith(".EC") + || name.equals("MANIFEST.MF"); + } +} diff --git a/test/jdk/lib/testlibrary/java/lang/UCDFiles.java b/test/jdk/lib/testlibrary/java/lang/UCDFiles.java index 10c6243f6150f7780b5f80a5664f020b27aae0cf..83054c5c0fb05bd12c9b3fc7ae63b59d34b7e39c 100644 --- a/test/jdk/lib/testlibrary/java/lang/UCDFiles.java +++ b/test/jdk/lib/testlibrary/java/lang/UCDFiles.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -23,16 +23,15 @@ /** * Holds the file paths to the Unicode Character Database source files. - * Paths to the source files in the "make" directory are relative, and - * subject to change due to future repository structure re-org. + * Paths to the source files in the "data" directory are relative. */ import java.nio.file.Path; import java.nio.file.Paths; public class UCDFiles { - public static Path UCD_DIR = Paths.get( - System.getProperty("test.root"), "..", "..", "make", "data", "unicodedata"); + public static Path UCD_DIR = Paths.get(System.getProperty("test.root"), + "../../src/java.base/share/data/unicodedata"); public static Path BLOCKS = UCD_DIR.resolve("Blocks.txt"); diff --git a/test/jdk/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/tooltip/ToolTipDemo.java b/test/jdk/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/tooltip/ToolTipDemo.java index 724a16715bb2d48f577f50d8502aa6e17dee035a..105160237ccef5c203929a869cc8ba759403bf16 100644 --- a/test/jdk/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/tooltip/ToolTipDemo.java +++ b/test/jdk/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/tooltip/ToolTipDemo.java @@ -58,9 +58,9 @@ public class ToolTipDemo extends JPanel { public static final String DEMO_TITLE = ToolTipDemo.class.getAnnotation(DemoProperties.class).value(); private final static ResourceManager resourceManager = new ResourceManager(ToolTipDemo.class); - public static final String PLAIN_TOOLTIP_COMP_TITLE = resourceManager.getString("ToolTipDemo.plain");; + public static final String PLAIN_TOOLTIP_COMP_TITLE = resourceManager.getString("ToolTipDemo.plain"); public static final String PLAIN_TOOLTIP_TEXT = "A simple one line tip."; - public static final String HTML_TOOLTIP_COMP_TITLE = resourceManager.getString("ToolTipDemo.html");; + public static final String HTML_TOOLTIP_COMP_TITLE = resourceManager.getString("ToolTipDemo.html"); public static final String HTML_TOOLTIP_TEXT = "<html><body bgcolor=\"#AABBFF\">In case you thought that tooltips had to be<p>" + "boring, one line descriptions, the <font color=blue size=+2>Swing!</font> team<p>" + "is happy to shatter your illusions.<p>" + diff --git a/test/jdk/sun/java2d/DirectX/MultiPaintEventTest/MultiPaintEventTest.java b/test/jdk/sun/java2d/DirectX/MultiPaintEventTest/MultiPaintEventTest.java new file mode 100644 index 0000000000000000000000000000000000000000..27d54af6a0be703f5b7f323045aa458bfaba7635 --- /dev/null +++ b/test/jdk/sun/java2d/DirectX/MultiPaintEventTest/MultiPaintEventTest.java @@ -0,0 +1,86 @@ +/* + * 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. + */ + +/* + * @test + * @key headful + * @bug 8275715 + * @summary Tests that paint method is not called twice + * @run main/othervm MultiPaintEventTest + */ + +import java.awt.*; + +public class MultiPaintEventTest extends Canvas { + + private int count = 0; + private final Object lock = new Object(); + + public void paint(Graphics g) { + synchronized(lock) { + count++; + } + + int w = getWidth(); + int h = getHeight(); + + Graphics2D g2d = (Graphics2D)g; + if (count % 2 == 1) { + g2d.setColor(Color.green); + } else { + g2d.setColor(Color.red); + } + g2d.fillRect(0, 0, w, h); + } + + public int getCount() { + synchronized(lock) { + return count; + } + } + + public Dimension getPreferredSize() { + return new Dimension(400, 400); + } + + public static void main(String[] args) { + MultiPaintEventTest test = new MultiPaintEventTest(); + Frame frame = new Frame(); + frame.setUndecorated(true); + frame.add(test); + frame.pack(); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + + try { + Thread.sleep(2000); + if (test.getCount() > 1) { + throw new RuntimeException("Processed unnecessary paint()."); + } + } catch (InterruptedException ex) { + throw new RuntimeException("Failed: Interrupted"); + } finally { + frame.dispose(); + } + } +} diff --git a/test/jdk/sun/java2d/cmm/ColorConvertOp/ImageFactory.java b/test/jdk/sun/java2d/cmm/ColorConvertOp/ImageFactory.java index a16f37f1236503c2fa140b9a2733aee2837c2615..62cc0f527206ca36bcc9b2b9fdab05cb1e7de399 100644 --- a/test/jdk/sun/java2d/cmm/ColorConvertOp/ImageFactory.java +++ b/test/jdk/sun/java2d/cmm/ColorConvertOp/ImageFactory.java @@ -258,7 +258,7 @@ public class ImageFactory { for (int j = 0; j < HEIGHT; j++) { pixel[0] = (i/255.0)*(cs.getMaxValue(0) - cs.getMinValue(0)) + - cs.getMinValue(0);; + cs.getMinValue(0); sm.setPixel(i, j, pixel, data); } } @@ -268,7 +268,7 @@ public class ImageFactory { for (int j = 0; j < HEIGHT; j++) { pixel[0] = (i/255.0f)*(cs.getMaxValue(0) - cs.getMinValue(0)) + - cs.getMinValue(0);; + cs.getMinValue(0); sm.setPixel(i, j, pixel, data); } } diff --git a/test/jdk/sun/jvmstat/monitor/HostIdentifier/HostIdentifierCreate.java b/test/jdk/sun/jvmstat/monitor/HostIdentifier/HostIdentifierCreate.java index 98b6781a5c8ddd45816c59478f22025f439a496f..2f4f61df018f7a0406dd55f2b73bbe76dd206a26 100644 --- a/test/jdk/sun/jvmstat/monitor/HostIdentifier/HostIdentifierCreate.java +++ b/test/jdk/sun/jvmstat/monitor/HostIdentifier/HostIdentifierCreate.java @@ -23,7 +23,7 @@ /* * @test - * @bug 4990825 + * @bug 4990825 8251155 * @summary test that HostIdentifier objects get created as expected * * @modules java.xml diff --git a/test/jdk/sun/jvmstat/monitor/HostIdentifier/testcases b/test/jdk/sun/jvmstat/monitor/HostIdentifier/testcases index 28dff2cdc02dc24cf57be7e3b817db2736239a93..804ab14938bdfbe9f8ea48a40a3fc582f2399a5d 100644 --- a/test/jdk/sun/jvmstat/monitor/HostIdentifier/testcases +++ b/test/jdk/sun/jvmstat/monitor/HostIdentifier/testcases @@ -218,4 +218,18 @@ special syntax - not a valid URI, but allowed by HostIdentifier <HostIdentifier> rmi://10.0.0.1:1234 </HostIdentifier> </testcase> +<testcase id="31" HostIdentifierInput="12345"> +<description> +Purely numeric +</description> +<HostIdentifier> //12345 </HostIdentifier> +</testcase> + +<testcase id="32" HostIdentifierInput="12345:123"> +<description> +Purely numeric +</description> +<HostIdentifier> //12345:123 </HostIdentifier> +</testcase> + </HostIdentifierTests> diff --git a/test/jdk/sun/management/PlatformMBeanProviderConstructorCheck.java b/test/jdk/sun/management/PlatformMBeanProviderConstructorCheck.java index b7b4edc8c98061b1230aff09536f710e3fff722c..16fee912a7c29d9b6fbb8544f138a23aaf90a5fe 100644 --- a/test/jdk/sun/management/PlatformMBeanProviderConstructorCheck.java +++ b/test/jdk/sun/management/PlatformMBeanProviderConstructorCheck.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -21,63 +21,79 @@ * questions. */ -import java.security.AccessControlException; -import java.security.Permission; -import java.security.Policy; -import java.security.ProtectionDomain; +import java.lang.management.ManagementFactory; +import java.lang.management.RuntimeMXBean; import java.util.List; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; + +import static jdk.test.lib.Asserts.*; + /* * @test - * @bug 8042901 - * @summary Check permission for PlatformMBeanProvider Constructor + * @library /test/lib + * @build jdk.test.lib.Asserts + * @bug 8042901 8283092 + * @summary Check encapsulation of PlatformMBeanProvider Constructor * @modules java.management/sun.management.spi - * @author Shanliang Jiang - * @run main/othervm -Djava.security.manager=allow PlatformMBeanProviderConstructorCheck + * @run main PlatformMBeanProviderConstructorCheck */ public class PlatformMBeanProviderConstructorCheck { - public static void main(String[] args) throws Exception { - Policy origPolicy = Policy.getPolicy(); - SecurityManager origSM = System.getSecurityManager(); - try { - System.out.println("---PlatformMBeanProviderConstructorCheck starting..."); - Policy.setPolicy(new MyPolicy()); - System.setSecurityManager(new SecurityManager()); + /** + * jtreg invokes this test with module arguments that permit compilation + * of the MyProvider class, which extends PlatformMBeanProvider. + * First check we can invoke that class, then re-invoke ourself without + * those module arguments, and expect a failure calling MyProvider. + */ + public static void main(String[] args) throws Exception { + System.out.println("---PlatformMBeanProviderConstructorCheck:"); + boolean expectedFail = false; - System.out.println("---PlatformMBeanProviderConstructorCheck Testing without permission..."); - try { - new MyProvider(); - throw new RuntimeException("Does not get expected AccessControlException!"); - } catch (AccessControlException ace) { - System.out.println("---PlatformMBeanProviderConstructorCheck got the expected exception: " - + ace); + // Recognise argument to signify we were re-invoked, and MyProvider should fail: + if (args.length == 1) { + if (args[0].equals("--nomoduleargs")) { + expectedFail = true; + verifyNoModuleArguments(); + } else { + throw new RuntimeException("unknown argument: '" + args[0] + "'"); } - - System.out.println("---PlatformMBeanProviderConstructorCheck Testing with permission..."); - MyPolicy.allowed = true; + } + System.out.println("---PlatformMBeanProviderConstructorCheck: invoke MyProvider with expectedFail = " + expectedFail); + Throwable e = null; + try { new MyProvider(); - - System.out.println("---PlatformMBeanProviderConstructorCheck PASSED!"); - } finally { - System.setSecurityManager(origSM); - Policy.setPolicy(origPolicy); + } catch (IllegalAccessError iae) { + System.out.println("---PlatformMBeanProviderConstructorCheck got exception: " + iae); + e = iae; } - } - private static class MyPolicy extends Policy { - private static String permName = "sun.management.spi.PlatformMBeanProvider.subclass"; - private static boolean allowed = false; + if (!expectedFail) { + // This was the first invocation, should have worked OK: + assertNull(e); + System.out.println("---PlatformMBeanProviderConstructorCheck PASSED (1) (expectedFail = " + expectedFail + ")"); - @Override - public boolean implies(ProtectionDomain domain, Permission permission) { - if (permName.equals(permission.getName())) { - System.out.println("---MyPolicy-implies checks permission for " - +permName+" and returns "+allowed); + // Re-invoke this test to check failure: + System.out.println("---PlatformMBeanProviderConstructorCheck: re-invoke without --add-modules or --add-exports"); + OutputAnalyzer output = ProcessTools.executeTestJava("PlatformMBeanProviderConstructorCheck", "--nomoduleargs"); + output.reportDiagnosticSummary(); + output.shouldContain("java.lang.IllegalAccessError: superclass access check failed:"); + output.shouldContain(" module java.management does not export sun.management.spi to "); + output.shouldNotContain("MyProvider constructor."); + } else { + // This was the re-invocation without module access, should fail: + assertNotNull(e); + System.out.println("---PlatformMBeanProviderConstructorCheck PASSED (2) (expectedFail = " + expectedFail + ")"); + } + } - return allowed; - } else { - return true; + private static void verifyNoModuleArguments() { + RuntimeMXBean mxbean = ManagementFactory.getRuntimeMXBean(); + for (String s : mxbean.getInputArguments()) { + if (s.startsWith("--add-modules") || s.startsWith("--add-exports")) { + System.out.println("arg: " + s); + throw new RuntimeException("argument list contains: " + s); } } } @@ -85,6 +101,7 @@ public class PlatformMBeanProviderConstructorCheck { private static class MyProvider extends sun.management.spi.PlatformMBeanProvider { @Override public List<PlatformComponent<?>> getPlatformComponentList() { + System.out.println("MyProvider constructor."); return null; } } diff --git a/test/jdk/sun/management/jmxremote/LocalRMIServerSocketFactoryTest.java b/test/jdk/sun/management/jmxremote/LocalRMIServerSocketFactoryTest.java index 223d252686f32d50bf3b39d2a30f2653165c9bea..3b51f32c99eb97199ed4beee5507f65e1008b1db 100644 --- a/test/jdk/sun/management/jmxremote/LocalRMIServerSocketFactoryTest.java +++ b/test/jdk/sun/management/jmxremote/LocalRMIServerSocketFactoryTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 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 @@ -64,17 +64,17 @@ public class LocalRMIServerSocketFactoryTest { } - // case of 6674166: this is very unlikely to happen, even if - // both 6674166 and 6774170 aren't fixed. If it happens + // case of 6774166: this is very unlikely to happen, even if + // both 6774166 and 6774170 aren't fixed. If it happens // however, it might indicate that neither defects are fixed. if (x instanceof NullPointerException) { throw new Exception(message + " - " + - "Congratulations! it seems you have triggered 6674166. " + - "Neither 6674166 nor 6774170 seem to be fixed: " + x, x); + "Congratulations! it seems you have triggered 6774166. " + + "Neither 6774166 nor 6774170 seem to be fixed: " + x, x); } else if (x instanceof IOException) { throw new Exception(message + " - " + - "Unexpected IOException. Maybe you triggered 6674166? " + + "Unexpected IOException. Maybe you triggered 6774166? " + x, x); } else if (x != null) { throw new Exception(message + " - " + diff --git a/test/jdk/sun/net/www/AuthHeaderTest.java b/test/jdk/sun/net/www/AuthHeaderTest.java index 53852aab8f176e6a88e08cf722fd1310442ad5f5..ba1729cb7e6e7884de97559ce55fd8383e9859df 100644 --- a/test/jdk/sun/net/www/AuthHeaderTest.java +++ b/test/jdk/sun/net/www/AuthHeaderTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -24,53 +24,31 @@ /** * @test * @bug 4804309 - * @modules java.base/sun.net.www - * @library ../../../sun/net/www/httptest/ - * @build HttpCallback TestHttpServer ClosedChannelList HttpTransaction - * @run main AuthHeaderTest + * @library /test/lib + * @run main/othervm AuthHeaderTest * @summary AuthHeaderTest bug */ -import java.io.*; -import java.net.*; - -public class AuthHeaderTest implements HttpCallback { - - static int count = 0; - static String authstring; - - void errorReply (HttpTransaction req, String reply) throws IOException { - req.addResponseHeader ("Connection", "close"); - req.addResponseHeader ("Www-authenticate", reply); - req.sendResponse (401, "Unauthorized"); - req.orderlyClose(); - } - - void okReply (HttpTransaction req) throws IOException { - req.setResponseEntityBody ("Hello ."); - req.sendResponse (200, "Ok"); - req.orderlyClose(); - } - - public void request (HttpTransaction req) { - try { - authstring = req.getRequestHeader ("Authorization"); - System.out.println (authstring); - switch (count) { - case 0: - errorReply (req, "Basic realm=\"wallyworld\""); - break; - case 1: - /* client stores a username/pw for wallyworld - */ - okReply (req); - break; - } - count ++; - } catch (IOException e) { - e.printStackTrace(); - } - } +import java.io.IOException; +import java.io.InputStream; +import java.io.PrintWriter; +import java.net.Authenticator; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.PasswordAuthentication; +import java.net.Proxy; +import java.net.URL; +import java.net.URLConnection; +import java.nio.charset.Charset; +import java.util.concurrent.Executors; + +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpHandler; +import com.sun.net.httpserver.HttpServer; +import jdk.test.lib.net.URIBuilder; + +public class AuthHeaderTest { + static HttpServer server; static void read (InputStream is) throws IOException { int c; @@ -91,19 +69,27 @@ public class AuthHeaderTest implements HttpCallback { is.close(); } - static TestHttpServer server; - public static void main (String[] args) throws Exception { MyAuthenticator auth = new MyAuthenticator (); Authenticator.setDefault (auth); InetAddress loopback = InetAddress.getLoopbackAddress(); try { - server = new TestHttpServer (new AuthHeaderTest(), 1, 10, loopback, 0); - System.out.println ("Server: listening on port: " + server.getAuthority()); - client ("http://" + server.getAuthority() + "/d1/foo.html"); + server = HttpServer.create(new InetSocketAddress(loopback, 0), 10, "/", new AuthHeaderTestHandler()); + server.setExecutor(Executors.newSingleThreadExecutor()); + server.start(); + System.out.println ("Server: listening on port: " + server.getAddress().getPort()); + + String serverURL = URIBuilder.newBuilder() + .scheme("http") + .loopback() + .port(server.getAddress().getPort()) + .path("/") + .build() + .toString(); + client (serverURL + "d1/foo.html"); } catch (Exception e) { if (server != null) { - server.terminate(); + server.stop(1); } throw e; } @@ -111,11 +97,11 @@ public class AuthHeaderTest implements HttpCallback { if (f != 1) { except ("Authenticator was called "+f+" times. Should be 1"); } - server.terminate(); + server.stop(1); } public static void except (String s) { - server.terminate(); + server.stop(1); throw new RuntimeException (s); } @@ -138,3 +124,45 @@ public class AuthHeaderTest implements HttpCallback { } } } + +class AuthHeaderTestHandler implements HttpHandler { + static int count = 0; + static String authstring; + + void errorReply (HttpExchange req, String reply) throws IOException { + req.getResponseHeaders().set("Connection", "close"); + req.getResponseHeaders().set("Www-authenticate", reply); + req.sendResponseHeaders(401, -1); + } + + void okReply (HttpExchange req) throws IOException { + req.sendResponseHeaders (200, 0); + try(PrintWriter pw = new PrintWriter(req.getResponseBody(), false, Charset.forName("UTF-8"))) { + pw.print("Hello ."); + } + } + + @Override + public void handle(HttpExchange exchange) throws IOException { + try { + if(exchange.getRequestHeaders().get("Authorization") != null) { + authstring = exchange.getRequestHeaders().get("Authorization").get(0); + System.out.println (authstring); + } + + switch (count) { + case 0: + errorReply (exchange, "Basic realm=\"wallyworld\""); + break; + case 1: + /* client stores a username/pw for wallyworld + */ + okReply (exchange); + break; + } + count ++; + } catch (IOException e) { + e.printStackTrace(); + } + } +} \ No newline at end of file diff --git a/test/jdk/sun/net/www/B8185898.java b/test/jdk/sun/net/www/B8185898.java index a50c6f93c7e65cc1ebeeb6eec6cb0f0d30b78df4..cfa54e15a521c65e098671e620d71bd0b198c629 100644 --- a/test/jdk/sun/net/www/B8185898.java +++ b/test/jdk/sun/net/www/B8185898.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -23,7 +23,7 @@ /** * @test - * @bug 8185898 + * @bug 8185898 8163921 * @modules java.base/sun.net.www * @library /test/lib * @run main/othervm B8185898 @@ -143,32 +143,32 @@ public class B8185898 { // {{inputString1, expectedToString1, expectedPrint1}, {...}} String[][] strings = { {"HTTP/1.1 200 OK\r\n" - + "Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2\r\n" + + "Accept: */*\r\n" + "Connection: keep-alive\r\n" + "Host: 127.0.0.1:12345\r\n" + "User-agent: Java/12\r\n\r\nfoooo", "pairs: {null: HTTP/1.1 200 OK}" - + "{Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2}" + + "{Accept: */*}" + "{Connection: keep-alive}" + "{Host: 127.0.0.1:12345}" + "{User-agent: Java/12}", - "Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2\r\n" + "Accept: */*\r\n" + "Connection: keep-alive\r\n" + "Host: 127.0.0.1:12345\r\n" + "User-agent: Java/12\r\n\r\n"}, {"HTTP/1.1 200 OK\r\n" - + "Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2\r\n" + + "Accept: */*\r\n" + "Connection: keep-alive\r\n" + "Host: 127.0.0.1:12345\r\n" + "User-agent: Java/12\r\n" + "X-Header:\r\n\r\n", "pairs: {null: HTTP/1.1 200 OK}" - + "{Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2}" + + "{Accept: */*}" + "{Connection: keep-alive}" + "{Host: 127.0.0.1:12345}" + "{User-agent: Java/12}" + "{X-Header: }", - "Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2\r\n" + "Accept: */*\r\n" + "Connection: keep-alive\r\n" + "Host: 127.0.0.1:12345\r\n" + "User-agent: Java/12\r\n" diff --git a/test/jdk/sun/net/www/http/HttpClient/ProxyFromCache.java b/test/jdk/sun/net/www/http/HttpClient/ProxyFromCache.java index f8885c637ed0e56538f03e3c392e03c413152252..6d2eaac126151b9f537a5bbe658fe29f5e3139c4 100644 --- a/test/jdk/sun/net/www/http/HttpClient/ProxyFromCache.java +++ b/test/jdk/sun/net/www/http/HttpClient/ProxyFromCache.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 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 @@ -25,14 +25,22 @@ * @test * @bug 6498566 * @summary URL.openConnection(Proxy.NO_PROXY) may connect through a proxy. - * @modules java.base/sun.net.www * @library /test/lib * @run main/othervm ProxyFromCache */ -import java.net.*; -import java.io.*; -import sun.net.www.MessageHeader; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.HttpURLConnection; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.Proxy; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.URL; + +import jdk.test.lib.net.HttpHeaderParser; import jdk.test.lib.net.URIBuilder; /* Creates a simple proxy and http server that just return 200 OK. @@ -135,15 +143,12 @@ class SimpleServer extends Thread connectionCount++; InputStream is = sock.getInputStream(); OutputStream os = sock.getOutputStream(); - - MessageHeader headers = new MessageHeader (is); + HttpHeaderParser httpHeaderParser = new HttpHeaderParser(is); os.write(replyOK.getBytes("UTF-8")); - - headers = new MessageHeader (is); + httpHeaderParser = new HttpHeaderParser(is); // If we get here then we received a second request. connectionCount++; os.write(replyOK.getBytes("UTF-8")); - sock.close(); } catch (Exception e) { //e.printStackTrace(); diff --git a/test/jdk/sun/net/www/http/HttpClient/RequestURI.java b/test/jdk/sun/net/www/http/HttpClient/RequestURI.java index 667a0778abf60b0807fc8762a41dba215d86e07e..a5b55989b12b9fb973c1762d704f737cc599b008 100644 --- a/test/jdk/sun/net/www/http/HttpClient/RequestURI.java +++ b/test/jdk/sun/net/www/http/HttpClient/RequestURI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 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 @@ -25,13 +25,14 @@ * @test * @bug 6469663 * @summary HTTP Request-URI contains fragment when connecting through proxy - * @modules java.base/sun.net.www + * @library /test/lib * @run main/othervm RequestURI */ import java.net.*; import java.io.*; -import sun.net.www.MessageHeader; + +import jdk.test.lib.net.HttpHeaderParser; // Create a Server listening on port 5001 to act as the proxy. Requests // never need to be forwared from it. We are only interested in the @@ -91,8 +92,8 @@ class RequestURIServer extends Thread InputStream is = sock.getInputStream(); OutputStream os = sock.getOutputStream(); - MessageHeader headers = new MessageHeader (is); - String requestLine = headers.getValue(0); + HttpHeaderParser headers = new HttpHeaderParser (is); + String requestLine = headers.getRequestDetails(); int first = requestLine.indexOf(' '); int second = requestLine.lastIndexOf(' '); diff --git a/test/jdk/sun/net/www/http/KeepAliveCache/B5045306.java b/test/jdk/sun/net/www/http/KeepAliveCache/B5045306.java index d624741bc2ccd16be21bed6782fea29094f72b1c..ebfb550b8263406595fe0aafebc24b24350f0259 100644 --- a/test/jdk/sun/net/www/http/KeepAliveCache/B5045306.java +++ b/test/jdk/sun/net/www/http/KeepAliveCache/B5045306.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -24,19 +24,30 @@ /* * @test * @bug 5045306 6356004 6993490 8255124 - * @modules java.base/sun.net.www - * java.management - * @library ../../httptest/ - * @build HttpCallback TestHttpServer HttpTransaction + * @library /test/lib * @run main/othervm B5045306 * @summary Http keep-alive implementation is not efficient */ -import java.net.*; -import java.io.*; -import java.lang.management.*; +import java.io.IOException; +import java.io.InputStream; +import java.io.PrintWriter; +import java.lang.management.ManagementFactory; +import java.lang.management.ThreadInfo; +import java.lang.management.ThreadMXBean; +import java.net.HttpURLConnection; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.Proxy; +import java.net.URL; +import java.nio.charset.Charset; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.Executors; + +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpHandler; +import com.sun.net.httpserver.HttpServer; /* Part 1: * The http client makes a connection to a URL whos content contains a lot of @@ -51,20 +62,19 @@ import java.util.List; * Content-length header. */ -public class B5045306 -{ - static SimpleHttpTransaction httpTrans; - static TestHttpServer server; +public class B5045306 { + static HttpServer server; - public static void main(String[] args) throws Exception { + public static void main(String[] args) { startHttpServer(); clientHttpCalls(); } public static void startHttpServer() { try { - httpTrans = new SimpleHttpTransaction(); - server = new TestHttpServer(httpTrans, 1, 10, InetAddress.getLocalHost(), 0); + server = HttpServer.create(new InetSocketAddress(InetAddress.getLocalHost(), 0), 10, "/", new SimpleHttpTransactionHandler()); + server.setExecutor(Executors.newSingleThreadExecutor()); + server.start(); } catch (IOException e) { e.printStackTrace(); } @@ -76,10 +86,10 @@ public class B5045306 uncaught.add(ex); }); try { - System.out.println("http server listen on: " + server.getLocalPort()); + System.out.println("http server listen on: " + server.getAddress().getPort()); String hostAddr = InetAddress.getLocalHost().getHostAddress(); if (hostAddr.indexOf(':') > -1) hostAddr = "[" + hostAddr + "]"; - String baseURLStr = "http://" + hostAddr + ":" + server.getLocalPort() + "/"; + String baseURLStr = "http://" + hostAddr + ":" + server.getAddress().getPort() + "/"; URL bigDataURL = new URL (baseURLStr + "firstCall"); URL smallDataURL = new URL (baseURLStr + "secondCall"); @@ -98,7 +108,7 @@ public class B5045306 uc = (HttpURLConnection)smallDataURL.openConnection(Proxy.NO_PROXY); uc.getResponseCode(); - if (SimpleHttpTransaction.failed) + if (SimpleHttpTransactionHandler.failed) throw new RuntimeException("Failed: Initial Keep Alive Connection is not being reused"); // Part 2 @@ -137,7 +147,7 @@ public class B5045306 } catch (IOException e) { e.printStackTrace(); } finally { - server.terminate(); + server.stop(1); } if (!uncaught.isEmpty()) { throw new RuntimeException("Unhandled exception:", uncaught.get(0)); @@ -145,9 +155,9 @@ public class B5045306 } } -class SimpleHttpTransaction implements HttpCallback +class SimpleHttpTransactionHandler implements HttpHandler { - static boolean failed = false; + static volatile boolean failed = false; // Need to have enough data here that is too large for the socket buffer to hold. // Also http.KeepAlive.remainingData must be greater than this value, default is 256K. @@ -155,48 +165,46 @@ class SimpleHttpTransaction implements HttpCallback int port1; - public void request(HttpTransaction trans) { + public void handle(HttpExchange trans) { try { String path = trans.getRequestURI().getPath(); if (path.equals("/firstCall")) { - port1 = trans.channel().socket().getPort(); + port1 = trans.getLocalAddress().getPort(); System.out.println("First connection on client port = " + port1); byte[] responseBody = new byte[RESPONSE_DATA_LENGTH]; for (int i=0; i<responseBody.length; i++) responseBody[i] = 0x41; - trans.setResponseEntityBody (responseBody, responseBody.length); - trans.sendResponse(200, "OK"); + trans.sendResponseHeaders(200, 0); + try(PrintWriter pw = new PrintWriter(trans.getResponseBody(), false, Charset.forName("UTF-8"))) { + pw.print(responseBody); + } } else if (path.equals("/secondCall")) { - int port2 = trans.channel().socket().getPort(); + int port2 = trans.getLocalAddress().getPort(); System.out.println("Second connection on client port = " + port2); if (port1 != port2) failed = true; - trans.setResponseHeader ("Content-length", Integer.toString(0)); - /* Force the server to not respond for more that the timeout * set by the keepalive cleaner (5000 millis). This ensures the * timeout is correctly resets the default read timeout, * infinity. See 6993490. */ System.out.println("server sleeping..."); try {Thread.sleep(6000); } catch (InterruptedException e) {} - - trans.sendResponse(200, "OK"); + trans.sendResponseHeaders(200, -1); } else if(path.equals("/part2")) { System.out.println("Call to /part2"); byte[] responseBody = new byte[RESPONSE_DATA_LENGTH]; for (int i=0; i<responseBody.length; i++) responseBody[i] = 0x41; - trans.setResponseEntityBody (responseBody, responseBody.length); - // override the Content-length header to be greater than the actual response body - trans.setResponseHeader("Content-length", Integer.toString(responseBody.length+1)); - trans.sendResponse(200, "OK"); - + trans.sendResponseHeaders(200, responseBody.length+1); + try(PrintWriter pw = new PrintWriter(trans.getResponseBody(), false, Charset.forName("UTF-8"))) { + pw.print(responseBody); + } // now close the socket - trans.channel().socket().close(); + trans.close(); } } catch (Exception e) { e.printStackTrace(); diff --git a/test/jdk/sun/net/www/http/KeepAliveCache/KeepAliveProperty.java b/test/jdk/sun/net/www/http/KeepAliveCache/KeepAliveProperty.java new file mode 100644 index 0000000000000000000000000000000000000000..b0d6b0d1c1a63230b0bc0d34159f8bc05a01da5a --- /dev/null +++ b/test/jdk/sun/net/www/http/KeepAliveCache/KeepAliveProperty.java @@ -0,0 +1,178 @@ +/* + * 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. + */ + +/* + * @test + * @library /test/lib + * @bug 8278067 + * @run main/othervm -Dhttp.keepAlive.time.server=30 KeepAliveProperty long + * @run main/othervm -Dhttp.keepAlive.time.server=1 KeepAliveProperty short + * @run main/othervm -ea -Dhttp.keepAlive.time.server=0 KeepAliveProperty short + */ + +import java.net.*; +import java.io.*; +import java.nio.charset.*; +import java.util.logging.*; +import jdk.test.lib.net.URIBuilder; +import static java.net.Proxy.NO_PROXY; + +public class KeepAliveProperty { + + static volatile boolean pass = false; + + static class Server extends Thread { + final ServerSocket server; + + Server (ServerSocket server) { + super (); + this.server = server; + } + + void readAll (Socket s) throws IOException { + byte[] buf = new byte [128]; + int c; + String request = ""; + InputStream is = s.getInputStream (); + while ((c=is.read(buf)) > 0) { + request += new String(buf, 0, c, StandardCharsets.US_ASCII); + if (request.contains("\r\n\r\n")) { + return; + } + } + if (c == -1) + throw new IOException("Socket closed"); + } + + Socket s = null; + String BODY; + String CLEN; + PrintStream out; + + public void run() { + try { + s = server.accept(); + readAll(s); + + BODY = "Hello world"; + CLEN = "Content-Length: " + BODY.length() + "\r\n"; + out = new PrintStream(new BufferedOutputStream(s.getOutputStream() )); + + /* send the header */ + out.print("HTTP/1.1 200 OK\r\n"); + out.print("Content-Type: text/plain; charset=iso-8859-1\r\n"); + out.print(CLEN); + out.print("\r\n"); + out.print(BODY); + out.flush(); + } catch (Exception e) { + pass = false; + try { + if (s != null) + s.close(); + server.close(); + } catch (IOException unused) {} + return; + } + + // second request may legitimately fail + + try (Socket s2 = s; ServerSocket server2 = server; PrintStream out2 = out) { + // wait for second request. + readAll(s2); + + BODY = "Goodbye world"; + CLEN = "Content-Length: " + BODY.length() + "\r\n"; + + /* send the header */ + out2.print("HTTP/1.1 200 OK\r\n"); + out2.print("Content-Type: text/plain; charset=iso-8859-1\r\n"); + out2.print(CLEN); + out2.print("\r\n"); + out2.print(BODY); + out2.flush(); + pass = !expectClose; + if (!pass) System.out.println("Failed: expected close"); + } catch (Exception e) { + pass = expectClose; + if (!pass) System.out.println("Failed: did not expect close"); + } + } + } + + static String fetch(URL url) throws Exception { + InputStream in = url.openConnection(NO_PROXY).getInputStream(); + String s = ""; + byte b[] = new byte[128]; + int n; + do { + n = in.read(b); + if (n > 0) + s += new String(b, 0, n, StandardCharsets.US_ASCII); + } while (n > 0); + in.close(); + return s; + } + + static volatile boolean expectClose; + + public static void main(String args[]) throws Exception { + // exercise the logging code + Logger logger = Logger.getLogger("sun.net.www.protocol.http.HttpURLConnection"); + logger.setLevel(Level.FINEST); + ConsoleHandler h = new ConsoleHandler(); + h.setLevel(Level.FINEST); + logger.addHandler(h); + + expectClose = args[0].equals("short"); + InetAddress loopback = InetAddress.getLoopbackAddress(); + ServerSocket ss = new ServerSocket(); + ss.bind(new InetSocketAddress(loopback, 0)); + Server s = new Server(ss); + s.start(); + + URL url = URIBuilder.newBuilder() + .scheme("http") + .loopback() + .port(ss.getLocalPort()) + .toURL(); + System.out.println("URL: " + url); + + if (!fetch(url).equals("Hello world")) + throw new RuntimeException("Failed on first request"); + + // Wait a while to see if connection is closed + Thread.sleep(3 * 1000); + + try { + if (!fetch(url).equals("Goodbye world")) + throw new RuntimeException("Failed on second request"); + } catch (Exception e) { + if (!expectClose) + throw e; + } + + if (!pass) + throw new RuntimeException("Failed in server"); + } +} diff --git a/test/jdk/sun/net/www/httptest/AbstractCallback.java b/test/jdk/sun/net/www/httptest/AbstractCallback.java deleted file mode 100644 index 4fc60def96aea7f02774c292a66e590ef059b285..0000000000000000000000000000000000000000 --- a/test/jdk/sun/net/www/httptest/AbstractCallback.java +++ /dev/null @@ -1,82 +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.net.*; -import java.util.*; -import java.io.IOException; - -/** - * This class provides a partial implementation of the HttpCallback - * interface. Use this class if you want to use the requestURI as a means - * of tracking multiple invocations of a request (on the server). - * In this case, you implement the modified request() method, which includes - * an integer count parameter. This parameter indicates the number of times - * (starting at zero) the request URI has been received. - */ - -public abstract class AbstractCallback implements HttpCallback { - - Map requests; - - static class Request { - URI uri; - int count; - - Request (URI u) { - uri = u; - count = 0; - } - } - - AbstractCallback () { - requests = Collections.synchronizedMap (new HashMap()); - } - - /** - * handle the given request and generate an appropriate response. - * @param msg the transaction containing the request from the - * client and used to send the response - */ - public void request (HttpTransaction msg) { - URI uri = msg.getRequestURI(); - Request req = (Request) requests.get (uri); - if (req == null) { - req = new Request (uri); - requests.put (uri, req); - } - request (msg, req.count++); - } - - /** - * Same as HttpCallback interface except that the integer n - * is provided to indicate sequencing of repeated requests using - * the same request URI. n starts at zero and is incremented - * for each successive call. - * - * @param msg the transaction containing the request from the - * client and used to send the response - * @param n value is 0 at first call, and is incremented by 1 for - * each subsequent call using the same request URI. - */ - abstract public void request (HttpTransaction msg, int n); -} diff --git a/test/jdk/sun/net/www/httptest/ClosedChannelList.java b/test/jdk/sun/net/www/httptest/ClosedChannelList.java deleted file mode 100644 index dd7a07f7a423ec8536e3f085aba770254e097d09..0000000000000000000000000000000000000000 --- a/test/jdk/sun/net/www/httptest/ClosedChannelList.java +++ /dev/null @@ -1,77 +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.io.*; -import java.nio.channels.*; -import java.util.*; - -class ClosedChannelList { - - static final long TIMEOUT = 10 * 1000; /* 10 sec */ - - static class Element { - long expiry; - SelectionKey key; - Element (long l, SelectionKey key) { - expiry = l; - this.key = key; - } - } - - LinkedList list; - - public ClosedChannelList () { - list = new LinkedList (); - } - - /* close chan after TIMEOUT milliseconds */ - - public synchronized void add (SelectionKey key) { - long exp = System.currentTimeMillis () + TIMEOUT; - list.add (new Element (exp, key)); - } - - public synchronized void check () { - check (false); - } - - public synchronized void terminate () { - check (true); - } - - public synchronized void check (boolean forceClose) { - Iterator iter = list.iterator (); - long now = System.currentTimeMillis(); - while (iter.hasNext ()) { - Element elm = (Element)iter.next(); - if (forceClose || elm.expiry <= now) { - SelectionKey k = elm.key; - try { - k.channel().close (); - } catch (IOException e) {} - k.cancel(); - iter.remove(); - } - } - } -} diff --git a/test/jdk/sun/net/www/httptest/HttpTransaction.java b/test/jdk/sun/net/www/httptest/HttpTransaction.java deleted file mode 100644 index 781aacaff5b308fb28967d1a2842deb12e384d35..0000000000000000000000000000000000000000 --- a/test/jdk/sun/net/www/httptest/HttpTransaction.java +++ /dev/null @@ -1,330 +0,0 @@ -/* - * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -import java.io.*; -import java.nio.*; -import java.nio.channels.*; -import java.net.*; -import sun.net.www.MessageHeader; - -/** - * This class encapsulates a HTTP request received and a response to be - * generated in one transaction. It provides methods for examaining the - * request from the client, and for building and sending a reply. - */ - -public class HttpTransaction { - - String command; - URI requesturi; - TestHttpServer.Server server; - MessageHeader reqheaders, reqtrailers; - String reqbody; - byte[] rspbody; - MessageHeader rspheaders, rsptrailers; - SelectionKey key; - int rspbodylen; - boolean rspchunked; - - HttpTransaction (TestHttpServer.Server server, String command, - URI requesturi, MessageHeader headers, - String body, MessageHeader trailers, SelectionKey key) { - this.command = command; - this.requesturi = requesturi; - this.reqheaders = headers; - this.reqbody = body; - this.reqtrailers = trailers; - this.key = key; - this.server = server; - } - - /** - * Get the value of a request header whose name is specified by the - * String argument. - * - * @param key the name of the request header - * @return the value of the header or null if it does not exist - */ - public String getRequestHeader (String key) { - return reqheaders.findValue (key); - } - - /** - * Get the value of a response header whose name is specified by the - * String argument. - * - * @param key the name of the response header - * @return the value of the header or null if it does not exist - */ - public String getResponseHeader (String key) { - return rspheaders.findValue (key); - } - - /** - * Get the request URI - * - * @return the request URI - */ - public URI getRequestURI () { - return requesturi; - } - - public String toString () { - StringBuffer buf = new StringBuffer(); - buf.append ("Request from: ").append (key.channel().toString()).append("\r\n"); - buf.append ("Command: ").append (command).append("\r\n"); - buf.append ("Request URI: ").append (requesturi).append("\r\n"); - buf.append ("Headers: ").append("\r\n"); - buf.append (reqheaders.toString()).append("\r\n"); - buf.append ("Body: ").append (reqbody).append("\r\n"); - buf.append ("---------Response-------\r\n"); - buf.append ("Headers: ").append("\r\n"); - if (rspheaders != null) { - buf.append (rspheaders.toString()).append("\r\n"); - } - String rbody = rspbody == null? "": new String (rspbody); - buf.append ("Body: ").append (rbody).append("\r\n"); - return new String (buf); - } - - /** - * Get the value of a request trailer whose name is specified by - * the String argument. - * - * @param key the name of the request trailer - * @return the value of the trailer or null if it does not exist - */ - public String getRequestTrailer (String key) { - return reqtrailers.findValue (key); - } - - /** - * Add a response header to the response. Multiple calls with the same - * key value result in multiple header lines with the same key identifier - * @param key the name of the request header to add - * @param val the value of the header - */ - public void addResponseHeader (String key, String val) { - if (rspheaders == null) - rspheaders = new MessageHeader (); - rspheaders.add (key, val); - } - - /** - * Set a response header. Searches for first header with named key - * and replaces its value with val - * @param key the name of the request header to add - * @param val the value of the header - */ - public void setResponseHeader (String key, String val) { - if (rspheaders == null) - rspheaders = new MessageHeader (); - rspheaders.set (key, val); - } - - /** - * Add a response trailer to the response. Multiple calls with the same - * key value result in multiple trailer lines with the same key identifier - * @param key the name of the request trailer to add - * @param val the value of the trailer - */ - public void addResponseTrailer (String key, String val) { - if (rsptrailers == null) - rsptrailers = new MessageHeader (); - rsptrailers.add (key, val); - } - - /** - * Get the request method - * - * @return the request method - */ - public String getRequestMethod (){ - return command; - } - - /** - * Perform an orderly close of the TCP connection associated with this - * request. This method guarantees that any response already sent will - * not be reset (by this end). The implementation does a shutdownOutput() - * of the TCP connection and for a period of time consumes and discards - * data received on the reading side of the connection. This happens - * in the background. After the period has expired the - * connection is completely closed. - */ - - public void orderlyClose () { - try { - server.orderlyCloseChannel (key); - } catch (IOException e) { - System.out.println (e); - } - } - - /** - * Do an immediate abortive close of the TCP connection associated - * with this request. - */ - public void abortiveClose () { - try { - server.abortiveCloseChannel(key); - } catch (IOException e) { - System.out.println (e); - } - } - - /** - * Get the SocketChannel associated with this request - * - * @return the socket channel - */ - public SocketChannel channel() { - return (SocketChannel) key.channel(); - } - - /** - * Get the request entity body associated with this request - * as a single String. - * - * @return the entity body in one String - */ - public String getRequestEntityBody (){ - return reqbody; - } - - /** - * Set the entity response body with the given string - * The content length is set to the length of the string - * @param body the string to send in the response - */ - public void setResponseEntityBody (String body){ - rspbody = body.getBytes(); - rspbodylen = body.length(); - rspchunked = false; - addResponseHeader ("Content-length", Integer.toString (rspbodylen)); - } - /** - * Set the entity response body with the given byte[] - * The content length is set to the gven length - * @param body the string to send in the response - */ - public void setResponseEntityBody (byte[] body, int len){ - rspbody = body; - rspbodylen = len; - rspchunked = false; - addResponseHeader ("Content-length", Integer.toString (rspbodylen)); - } - - - /** - * Set the entity response body by reading the given inputstream - * - * @param is the inputstream from which to read the body - */ - public void setResponseEntityBody (InputStream is) throws IOException { - byte[] buf = new byte [2048]; - byte[] total = new byte [2048]; - int total_len = 2048; - int c, len=0; - while ((c=is.read (buf)) != -1) { - if (len+c > total_len) { - byte[] total1 = new byte [total_len * 2]; - System.arraycopy (total, 0, total1, 0, len); - total = total1; - total_len = total_len * 2; - } - System.arraycopy (buf, 0, total, len, c); - len += c; - } - setResponseEntityBody (total, len); - } - - /* chunked */ - - /** - * Set the entity response body with the given array of strings - * The content encoding is set to "chunked" and each array element - * is sent as one chunk. - * @param body the array of string chunks to send in the response - */ - public void setResponseEntityBody (String[] body) { - StringBuffer buf = new StringBuffer (); - int len = 0; - for (int i=0; i<body.length; i++) { - String chunklen = Integer.toHexString (body[i].length()); - len += body[i].length(); - buf.append (chunklen).append ("\r\n"); - buf.append (body[i]).append ("\r\n"); - } - buf.append ("0\r\n"); - rspbody = new String (buf).getBytes(); - rspbodylen = rspbody.length; - rspchunked = true; - addResponseHeader ("Transfer-encoding", "chunked"); - } - - /** - * Send the response with the current set of response parameters - * but using the response code and string tag line as specified - * @param rCode the response code to send - * @param rTag the response string to send with the response code - */ - public void sendResponse (int rCode, String rTag) throws IOException { - OutputStream os = new TestHttpServer.NioOutputStream(channel()); - PrintStream ps = new PrintStream (os); - ps.print ("HTTP/1.1 " + rCode + " " + rTag + "\r\n"); - if (rspheaders != null) { - rspheaders.print (ps); - } else { - ps.print ("\r\n"); - } - ps.flush (); - if (rspbody != null) { - os.write (rspbody, 0, rspbodylen); - os.flush(); - } - if (rsptrailers != null) { - rsptrailers.print (ps); - } else if (rspchunked) { - ps.print ("\r\n"); - } - ps.flush(); - } - - /* sends one byte less than intended */ - - public void sendPartialResponse (int rCode, String rTag)throws IOException { - OutputStream os = new TestHttpServer.NioOutputStream(channel()); - PrintStream ps = new PrintStream (os); - ps.print ("HTTP/1.1 " + rCode + " " + rTag + "\r\n"); - ps.flush(); - if (rspbody != null) { - os.write (rspbody, 0, rspbodylen-1); - os.flush(); - } - if (rsptrailers != null) { - rsptrailers.print (ps); - } - ps.flush(); - } -} diff --git a/test/jdk/sun/net/www/httptest/TestHttpServer.java b/test/jdk/sun/net/www/httptest/TestHttpServer.java deleted file mode 100644 index b29e6b8c7f56b40f9f9ea4f81eae1fa80077fd44..0000000000000000000000000000000000000000 --- a/test/jdk/sun/net/www/httptest/TestHttpServer.java +++ /dev/null @@ -1,797 +0,0 @@ -/* - * Copyright (c) 2002, 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. - */ - -import java.net.*; -import java.io.*; -import java.nio.*; -import java.nio.channels.*; -import sun.net.www.MessageHeader; -import java.util.*; - -/** - * This class implements a simple HTTP server. It uses multiple threads to - * handle connections in parallel, and also multiple connections/requests - * can be handled per thread. - * <p> - * It must be instantiated with a {@link HttpCallback} object to which - * requests are given and must be handled. - * <p> - * Simple synchronization between the client(s) and server can be done - * using the {@link #waitForCondition(String)}, {@link #setCondition(String)} and - * {@link #rendezvous(String,int)} methods. - * - * NOTE NOTE NOTE NOTE NOTE NOTE NOTE - * - * If changes are made here, please sure they are propagated to - * the HTTPS equivalent in the JSSE regression test suite. - * - * NOTE NOTE NOTE NOTE NOTE NOTE NOTE - */ - -public class TestHttpServer { - - ServerSocketChannel schan; - int threads; - int cperthread; - HttpCallback cb; - Server[] servers; - - /** - * Create a <code>TestHttpServer<code> instance with the specified callback object - * for handling requests. One thread is created to handle requests, - * and up to ten TCP connections will be handled simultaneously. - * @param cb the callback object which is invoked to handle each - * incoming request - */ - - public TestHttpServer (HttpCallback cb) throws IOException { - this (cb, 1, 10, 0); - } - - /** - * Create a <code>TestHttpServer<code> instance with the specified callback object - * for handling requests. One thread is created to handle requests, - * and up to ten TCP connections will be handled simultaneously. - * @param cb the callback object which is invoked to handle each - * incoming request - * @param address the address to bind the server to. <code>Null</code> - * means bind to the wildcard address. - * @param port the port number to bind the server to. <code>Zero</code> - * means choose any free port. - */ - - public TestHttpServer (HttpCallback cb, InetAddress address, int port) throws IOException { - this (cb, 1, 10, address, 0); - } - - /** - * Create a <code>TestHttpServer<code> instance with the specified number of - * threads and maximum number of connections per thread. This functions - * the same as the 4 arg constructor, where the port argument is set to zero. - * @param cb the callback object which is invoked to handle each - * incoming request - * @param threads the number of threads to create to handle requests - * in parallel - * @param cperthread the number of simultaneous TCP connections to - * handle per thread - */ - - public TestHttpServer (HttpCallback cb, int threads, int cperthread) - throws IOException { - this (cb, threads, cperthread, 0); - } - - /** - * Create a <code>TestHttpServer<code> instance with the specified number - * of threads and maximum number of connections per thread and running on - * the specified port. The specified number of threads are created to - * handle incoming requests, and each thread is allowed - * to handle a number of simultaneous TCP connections. - * @param cb the callback object which is invoked to handle - * each incoming request - * @param threads the number of threads to create to handle - * requests in parallel - * @param cperthread the number of simultaneous TCP connections - * to handle per thread - * @param port the port number to bind the server to. <code>Zero</code> - * means choose any free port. - */ - - public TestHttpServer (HttpCallback cb, int threads, int cperthread, int port) - throws IOException { - this(cb, threads, cperthread, null, port); - } - - /** - * Create a <code>TestHttpServer<code> instance with the specified number - * of threads and maximum number of connections per thread and running on - * the specified port. The specified number of threads are created to - * handle incoming requests, and each thread is allowed - * to handle a number of simultaneous TCP connections. - * @param cb the callback object which is invoked to handle - * each incoming request - * @param threads the number of threads to create to handle - * requests in parallel - * @param cperthread the number of simultaneous TCP connections - * to handle per thread - * @param address the address to bind the server to. <code>Null</code> - * means bind to the wildcard address. - * @param port the port number to bind the server to. <code>Zero</code> - * means choose any free port. - */ - - public TestHttpServer (HttpCallback cb, int threads, int cperthread, - InetAddress address, int port) - throws IOException { - schan = ServerSocketChannel.open (); - InetSocketAddress addr = new InetSocketAddress (address, port); - schan.socket().bind (addr); - this.threads = threads; - this.cb = cb; - this.cperthread = cperthread; - servers = new Server [threads]; - for (int i=0; i<threads; i++) { - servers[i] = new Server (cb, schan, cperthread); - servers[i].start(); - } - } - - /** - * Tell all threads in the server to exit within 5 seconds. - * This is an abortive termination. Just prior to the thread exiting - * all channels in that thread waiting to be closed are forceably closed. - * @throws InterruptedException - */ - - public void terminate () { - for (int i=0; i<threads; i++) { - servers[i].terminate (); - } - - for (int i = 0; i < threads; i++) { - try { - servers[i].join(); - } catch (InterruptedException e) { - System.err.println("Unexpected InterruptedException during terminating server"); - throw new RuntimeException(e); - } - } - } - - /** - * return the local port number to which the server is bound. - * @return the local port number - */ - - public int getLocalPort () { - return schan.socket().getLocalPort (); - } - - public String getAuthority() { - InetAddress address = schan.socket().getInetAddress(); - String hostaddr = address.getHostAddress(); - if (address.isAnyLocalAddress()) hostaddr = "localhost"; - if (hostaddr.indexOf(':') > -1) hostaddr = "[" + hostaddr + "]"; - return hostaddr + ":" + getLocalPort(); - } - - static class Server extends Thread { - - ServerSocketChannel schan; - Selector selector; - SelectionKey listenerKey; - SelectionKey key; /* the current key being processed */ - HttpCallback cb; - ByteBuffer consumeBuffer; - int maxconn; - int nconn; - ClosedChannelList clist; - volatile boolean shutdown; - - Server (HttpCallback cb, ServerSocketChannel schan, int maxconn) { - this.schan = schan; - this.maxconn = maxconn; - this.cb = cb; - nconn = 0; - consumeBuffer = ByteBuffer.allocate (512); - clist = new ClosedChannelList (); - try { - selector = Selector.open (); - schan.configureBlocking (false); - listenerKey = schan.register (selector, SelectionKey.OP_ACCEPT); - } catch (IOException e) { - System.err.println ("Server could not start: " + e); - throw new RuntimeException("Server could not start: " + e, e); - } - } - - /* Stop the thread as soon as possible */ - public void terminate () { - shutdown = true; - } - - public void run () { - try { - while (true) { - selector.select(1000); - Set<SelectionKey> selected = selector.selectedKeys(); - Iterator<SelectionKey> iter = selected.iterator(); - while (iter.hasNext()) { - key = iter.next(); - if (key.equals (listenerKey)) { - SocketChannel sock = schan.accept (); - if (sock == null) { - /* false notification */ - iter.remove(); - continue; - } - sock.configureBlocking (false); - sock.register (selector, SelectionKey.OP_READ); - nconn ++; - System.out.println("SERVER: new connection. chan[" + sock + "]"); - if (nconn == maxconn) { - /* deregister */ - listenerKey.cancel (); - listenerKey = null; - } - } else { - if (key.isReadable()) { - boolean closed; - SocketChannel chan = (SocketChannel) key.channel(); - System.out.println("SERVER: connection readable. chan[" + chan + "]"); - if (key.attachment() != null) { - System.out.println("Server: consume"); - closed = consume (chan); - } else { - closed = read (chan, key); - } - if (closed) { - chan.close (); - key.cancel (); - if (nconn == maxconn) { - listenerKey = schan.register (selector, SelectionKey.OP_ACCEPT); - } - nconn --; - } - } - } - iter.remove(); - } - clist.check(); - if (shutdown) { - System.out.println("Force to Shutdown"); - SelectionKey sKey = schan.keyFor(selector); - if (sKey != null) { - sKey.cancel(); - } - - clist.terminate (); - selector.close(); - schan.socket().close(); - schan.close(); - return; - } - } - } catch (IOException e) { - System.out.println ("Server exception: " + e); - // TODO finish - } - } - - /* read all the data off the channel without looking at it - * return true if connection closed - */ - boolean consume (SocketChannel chan) { - try { - consumeBuffer.clear (); - int c = chan.read (consumeBuffer); - if (c == -1) - return true; - } catch (IOException e) { - return true; - } - return false; - } - - /* return true if the connection is closed, false otherwise */ - - private boolean read (SocketChannel chan, SelectionKey key) { - HttpTransaction msg; - boolean res; - try { - InputStream is = new BufferedInputStream (new NioInputStream (chan)); - String requestline = readLine (is); - MessageHeader mhead = new MessageHeader (is); - String clen = mhead.findValue ("Content-Length"); - String trferenc = mhead.findValue ("Transfer-Encoding"); - String data = null; - if (trferenc != null && trferenc.equals ("chunked")) - data = new String (readChunkedData (is)); - else if (clen != null) - data = new String (readNormalData (is, Integer.parseInt (clen))); - String[] req = requestline.split (" "); - if (req.length < 2) { - /* invalid request line */ - return false; - } - String cmd = req[0]; - URI uri = null; - try { - uri = new URI (req[1]); - msg = new HttpTransaction (this, cmd, uri, mhead, data, null, key); - cb.request (msg); - } catch (URISyntaxException e) { - System.err.println ("Invalid URI: " + e); - msg = new HttpTransaction (this, cmd, null, null, null, null, key); - msg.sendResponse (501, "Whatever"); - } - res = false; - } catch (IOException e) { - res = true; - } - return res; - } - - byte[] readNormalData (InputStream is, int len) throws IOException { - byte [] buf = new byte [len]; - int c, off=0, remain=len; - while (remain > 0 && ((c=is.read (buf, off, remain))>0)) { - remain -= c; - off += c; - } - return buf; - } - - private void readCRLF(InputStream is) throws IOException { - int cr = is.read(); - int lf = is.read(); - - if (((cr & 0xff) != 0x0d) || - ((lf & 0xff) != 0x0a)) { - throw new IOException( - "Expected <CR><LF>: got '" + cr + "/" + lf + "'"); - } - } - - byte[] readChunkedData (InputStream is) throws IOException { - LinkedList l = new LinkedList (); - int total = 0; - for (int len=readChunkLen(is); len!=0; len=readChunkLen(is)) { - l.add (readNormalData(is, len)); - total += len; - readCRLF(is); // CRLF at end of chunk - } - readCRLF(is); // CRLF at end of Chunked Stream. - byte[] buf = new byte [total]; - Iterator i = l.iterator(); - int x = 0; - while (i.hasNext()) { - byte[] b = (byte[])i.next(); - System.arraycopy (b, 0, buf, x, b.length); - x += b.length; - } - return buf; - } - - private int readChunkLen (InputStream is) throws IOException { - int c, len=0; - boolean done=false, readCR=false; - while (!done) { - c = is.read (); - if (c == '\n' && readCR) { - done = true; - } else { - if (c == '\r' && !readCR) { - readCR = true; - } else { - int x=0; - if (c >= 'a' && c <= 'f') { - x = c - 'a' + 10; - } else if (c >= 'A' && c <= 'F') { - x = c - 'A' + 10; - } else if (c >= '0' && c <= '9') { - x = c - '0'; - } - len = len * 16 + x; - } - } - } - return len; - } - - private String readLine (InputStream is) throws IOException { - boolean done=false, readCR=false; - byte[] b = new byte [512]; - int c, l = 0; - - while (!done) { - c = is.read (); - if (c == '\n' && readCR) { - done = true; - } else { - if (c == '\r' && !readCR) { - readCR = true; - } else { - b[l++] = (byte)c; - } - } - } - return new String (b); - } - - /** close the channel associated with the current key by: - * 1. shutdownOutput (send a FIN) - * 2. mark the key so that incoming data is to be consumed and discarded - * 3. After a period, close the socket - */ - - synchronized void orderlyCloseChannel (SelectionKey key) throws IOException { - SocketChannel ch = (SocketChannel)key.channel (); - System.out.println("SERVER: orderlyCloseChannel chan[" + ch + "]"); - ch.socket().shutdownOutput(); - key.attach (this); - clist.add (key); - } - - synchronized void abortiveCloseChannel (SelectionKey key) throws IOException { - SocketChannel ch = (SocketChannel)key.channel (); - System.out.println("SERVER: abortiveCloseChannel chan[" + ch + "]"); - - Socket s = ch.socket (); - s.setSoLinger (true, 0); - ch.close(); - } - } - - - /** - * Implements blocking reading semantics on top of a non-blocking channel - */ - - static class NioInputStream extends InputStream { - SocketChannel channel; - Selector selector; - ByteBuffer chanbuf; - SelectionKey key; - int available; - byte[] one; - boolean closed; - ByteBuffer markBuf; /* reads may be satisifed from this buffer */ - boolean marked; - boolean reset; - int readlimit; - - public NioInputStream (SocketChannel chan) throws IOException { - this.channel = chan; - selector = Selector.open(); - chanbuf = ByteBuffer.allocate (1024); - key = chan.register (selector, SelectionKey.OP_READ); - available = 0; - one = new byte[1]; - closed = marked = reset = false; - } - - public synchronized int read (byte[] b) throws IOException { - return read (b, 0, b.length); - } - - public synchronized int read () throws IOException { - return read (one, 0, 1); - } - - public synchronized int read (byte[] b, int off, int srclen) throws IOException { - - int canreturn, willreturn; - - if (closed) - return -1; - - if (reset) { /* satisfy from markBuf */ - canreturn = markBuf.remaining (); - willreturn = canreturn>srclen ? srclen : canreturn; - markBuf.get(b, off, willreturn); - if (canreturn == willreturn) { - reset = false; - } - } else { /* satisfy from channel */ - canreturn = available(); - if (canreturn == 0) { - block (); - canreturn = available(); - } - willreturn = canreturn>srclen ? srclen : canreturn; - chanbuf.get(b, off, willreturn); - available -= willreturn; - - if (marked) { /* copy into markBuf */ - try { - markBuf.put (b, off, willreturn); - } catch (BufferOverflowException e) { - marked = false; - } - } - } - return willreturn; - } - - public synchronized int available () throws IOException { - if (closed) - throw new IOException ("Stream is closed"); - - if (reset) - return markBuf.remaining(); - - if (available > 0) - return available; - - chanbuf.clear (); - available = channel.read (chanbuf); - if (available > 0) - chanbuf.flip(); - else if (available == -1) - throw new IOException ("Stream is closed"); - return available; - } - - /** - * block() only called when available==0 and buf is empty - */ - private synchronized void block () throws IOException { - //assert available == 0; - int n = selector.select (); - //assert n == 1; - selector.selectedKeys().clear(); - available (); - } - - public void close () throws IOException { - if (closed) - return; - channel.close (); - closed = true; - } - - public synchronized void mark (int readlimit) { - if (closed) - return; - this.readlimit = readlimit; - markBuf = ByteBuffer.allocate (readlimit); - marked = true; - reset = false; - } - - public synchronized void reset () throws IOException { - if (closed ) - return; - if (!marked) - throw new IOException ("Stream not marked"); - marked = false; - reset = true; - markBuf.flip (); - } - } - - static class NioOutputStream extends OutputStream { - SocketChannel channel; - ByteBuffer buf; - SelectionKey key; - Selector selector; - boolean closed; - byte[] one; - - public NioOutputStream (SocketChannel channel) throws IOException { - this.channel = channel; - selector = Selector.open (); - key = channel.register (selector, SelectionKey.OP_WRITE); - closed = false; - one = new byte [1]; - } - - public synchronized void write (int b) throws IOException { - one[0] = (byte)b; - write (one, 0, 1); - } - - public synchronized void write (byte[] b) throws IOException { - write (b, 0, b.length); - } - - public synchronized void write (byte[] b, int off, int len) throws IOException { - if (closed) - throw new IOException ("stream is closed"); - - buf = ByteBuffer.allocate (len); - buf.put (b, off, len); - buf.flip (); - int n; - while ((n = channel.write (buf)) < len) { - len -= n; - if (len == 0) - return; - selector.select (); - selector.selectedKeys().clear (); - } - } - - public void close () throws IOException { - if (closed) - return; - channel.close (); - closed = true; - } - } - - /** - * Utilities for synchronization. A condition is - * identified by a string name, and is initialized - * upon first use (ie. setCondition() or waitForCondition()). Threads - * are blocked until some thread calls (or has called) setCondition() for the same - * condition. - * <P> - * A rendezvous built on a condition is also provided for synchronizing - * N threads. - */ - - private static HashMap conditions = new HashMap(); - - /* - * Modifiable boolean object - */ - private static class BValue { - boolean v; - } - - /* - * Modifiable int object - */ - private static class IValue { - int v; - IValue (int i) { - v =i; - } - } - - - private static BValue getCond (String condition) { - synchronized (conditions) { - BValue cond = (BValue) conditions.get (condition); - if (cond == null) { - cond = new BValue(); - conditions.put (condition, cond); - } - return cond; - } - } - - /** - * Set the condition to true. Any threads that are currently blocked - * waiting on the condition, will be unblocked and allowed to continue. - * Threads that subsequently call waitForCondition() will not block. - * If the named condition did not exist prior to the call, then it is created - * first. - */ - - public static void setCondition (String condition) { - BValue cond = getCond (condition); - synchronized (cond) { - if (cond.v) { - return; - } - cond.v = true; - cond.notifyAll(); - } - } - - /** - * If the named condition does not exist, then it is created and initialized - * to false. If the condition exists or has just been created and its value - * is false, then the thread blocks until another thread sets the condition. - * If the condition exists and is already set to true, then this call returns - * immediately without blocking. - */ - - public static void waitForCondition (String condition) { - BValue cond = getCond (condition); - synchronized (cond) { - if (!cond.v) { - try { - cond.wait(); - } catch (InterruptedException e) {} - } - } - } - - /* conditions must be locked when accessing this */ - static HashMap rv = new HashMap(); - - /** - * Force N threads to rendezvous (ie. wait for each other) before proceeding. - * The first thread(s) to call are blocked until the last - * thread makes the call. Then all threads continue. - * <p> - * All threads that call with the same condition name, must use the same value - * for N (or the results may be not be as expected). - * <P> - * Obviously, if fewer than N threads make the rendezvous then the result - * will be a hang. - */ - - public static void rendezvous (String condition, int N) { - BValue cond; - IValue iv; - String name = "RV_"+condition; - - /* get the condition */ - - synchronized (conditions) { - cond = (BValue)conditions.get (name); - if (cond == null) { - /* we are first caller */ - if (N < 2) { - throw new RuntimeException ("rendezvous must be called with N >= 2"); - } - cond = new BValue (); - conditions.put (name, cond); - iv = new IValue (N-1); - rv.put (name, iv); - } else { - /* already initialised, just decrement the counter */ - iv = (IValue) rv.get (name); - iv.v --; - } - } - - if (iv.v > 0) { - waitForCondition (name); - } else { - setCondition (name); - synchronized (conditions) { - clearCondition (name); - rv.remove (name); - } - } - } - - /** - * If the named condition exists and is set then remove it, so it can - * be re-initialized and used again. If the condition does not exist, or - * exists but is not set, then the call returns without doing anything. - * Note, some higher level synchronization - * may be needed between clear and the other operations. - */ - - public static void clearCondition(String condition) { - BValue cond; - synchronized (conditions) { - cond = (BValue) conditions.get (condition); - if (cond == null) { - return; - } - synchronized (cond) { - if (cond.v) { - conditions.remove (condition); - } - } - } - } -} diff --git a/test/jdk/sun/net/www/protocol/http/CloseOptionHeader.java b/test/jdk/sun/net/www/protocol/http/CloseOptionHeader.java index bc1ec86fee456a8d91ebaf8f00316a80b26d89f9..28bb8af30cd3b3ef32b373c77d8488e09d7abe27 100644 --- a/test/jdk/sun/net/www/protocol/http/CloseOptionHeader.java +++ b/test/jdk/sun/net/www/protocol/http/CloseOptionHeader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 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 @@ -24,16 +24,23 @@ /** * @test * @bug 6189206 - * @modules java.base/sun.net.www * @library /test/lib * @run main/othervm -Dhttp.keepAlive=false CloseOptionHeader * @summary HTTP client should set "Connection: close" header in request when keepalive is disabled */ -import java.net.*; -import java.util.*; -import java.io.*; -import sun.net.www.MessageHeader; +import java.io.BufferedOutputStream; +import java.io.InputStream; +import java.io.PrintStream; +import java.net.HttpURLConnection; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.URL; +import java.util.List; + +import jdk.test.lib.net.HttpHeaderParser; import jdk.test.lib.net.URIBuilder; public class CloseOptionHeader implements Runnable { @@ -49,10 +56,15 @@ public class CloseOptionHeader implements Runnable { /* check the request to find close connection option header */ InputStream is = s.getInputStream (); - MessageHeader mh = new MessageHeader(is); - String connHeader = mh.findValue("Connection"); - if (connHeader != null && connHeader.equalsIgnoreCase("close")) { - hasCloseHeader = true; + HttpHeaderParser mh = new HttpHeaderParser(is); + List <String> connHeader = mh.getHeaderValue("Connection"); + if (connHeader != null) { + for(String value : connHeader) { + if (value.equalsIgnoreCase("close")) { + hasCloseHeader = true; + break; + } + } } PrintStream out = new PrintStream( diff --git a/test/jdk/sun/net/www/protocol/http/HttpHeaderParserTest.java b/test/jdk/sun/net/www/protocol/http/HttpHeaderParserTest.java new file mode 100644 index 0000000000000000000000000000000000000000..245cd49d518f881dc0eb1785c40182d71e5989e6 --- /dev/null +++ b/test/jdk/sun/net/www/protocol/http/HttpHeaderParserTest.java @@ -0,0 +1,498 @@ + + +/* + * 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. + */ + +/* @test + * @bug 8061729 + * @library /test/lib + * @summary Sanity check that HttpHeaderParser works same as MessageHeader + * @modules java.base/sun.net.www java.base/sun.net.www.protocol.http:open + * @run testng/othervm HttpHeaderParserTest + */ + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; + +import static java.lang.String.format; +import static java.nio.charset.StandardCharsets.ISO_8859_1; +import static java.nio.charset.StandardCharsets.US_ASCII; +import jdk.test.lib.net.HttpHeaderParser; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import sun.net.www.MessageHeader; + +public class HttpHeaderParserTest { + @DataProvider(name = "responses") + public Object[][] responses() { + List<String> responses = new ArrayList<>(); + + String[] basic = + { "HTTP/1.1 200 OK\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" + + "Connection: close\r\n" + + "Content-Type: text/html; charset=iso-8859-1\r\n" + + "Content-Length: 10\r\n\r\n" + + "123456789", + + "HTTP/1.1 200 OK\r\n" + + "Content-Length: 9\r\n" + + "Content-Type: text/html; charset=UTF-8\r\n\r\n" + + "XXXXX", + + "HTTP/1.1 200 OK\r\n" + + "X-Header: U\u00ffU\r\n" + // value with U+00FF - Extended Latin-1 + "Content-Length: 9\r\n" + + "Content-Type: text/html; charset=UTF-8\r\n\r\n" + + "XXXXX", + + "HTTP/1.1 200 OK\r\n" + + "Content-Length: 9\r\n" + + "Content-Type: text/html; charset=UTF-8\r\n\r\n" + // more than one SP after ':' + "XXXXX", + + "HTTP/1.1 200 OK\r\n" + + "Content-Length:\t10\r\n" + + "Content-Type:\ttext/html; charset=UTF-8\r\n\r\n" + // HT separator + "XXXXX", + + "HTTP/1.1 200 OK\r\n" + + "Content-Length:\t\t10\r\n" + + "Content-Type:\t\ttext/html; charset=UTF-8\r\n\r\n" + // more than one HT after ':' + "XXXXX", + + "HTTP/1.1 407 Proxy Authorization Required\r\n" + + "Proxy-Authenticate: Basic realm=\"a fake realm\"\r\n\r\n", + + "HTTP/1.1 401 Unauthorized\r\n" + + "WWW-Authenticate: Digest realm=\"wally land\" domain=/ " + + "nonce=\"2B7F3A2B\" qop=\"auth\"\r\n\r\n", + + "HTTP/1.1 200 OK\r\n" + + "X-Foo:\r\n\r\n", // no value + + "HTTP/1.1 200 OK\r\n" + + "X-Foo:\r\n\r\n" + // no value, with response body + "Some Response Body", + + "HTTP/1.1 200 OK\r\n" + + "X-Foo:\r\n" + // no value, followed by another header + "Content-Length: 10\r\n\r\n" + + "Some Response Body", + + "HTTP/1.1 200 OK\r\n" + + "X-Foo:\r\n" + // no value, followed by another header, with response body + "Content-Length: 10\r\n\r\n", + + "HTTP/1.1 200 OK\r\n" + + "X-Foo: chegar\r\n" + + "X-Foo: dfuchs\r\n" + // same header appears multiple times + "Content-Length: 0\r\n" + + "X-Foo: michaelm\r\n" + + "X-Foo: prappo\r\n\r\n", + + "HTTP/1.1 200 OK\r\n" + + "X-Foo:\r\n" + // no value, same header appears multiple times + "X-Foo: dfuchs\r\n" + + "Content-Length: 0\r\n" + + "X-Foo: michaelm\r\n" + + "X-Foo: prappo\r\n\r\n", + + "HTTP/1.1 200 OK\r\n" + + "Accept-Ranges: bytes\r\n" + + "Cache-control: max-age=0, no-cache=\"set-cookie\"\r\n" + + "Content-Length: 132868\r\n" + + "Content-Type: text/html; charset=UTF-8\r\n" + + "Date: Sun, 05 Nov 2017 22:24:03 GMT\r\n" + + "Server: Apache/2.4.6 (Red Hat Enterprise Linux) OpenSSL/1.0.1e-fips Communique/4.2.2\r\n" + + "Set-Cookie: AWSELB=AF7927F5100F4202119876ED2436B5005EE;PATH=/;MAX-AGE=900\r\n" + + "Vary: Host,Accept-Encoding,User-Agent\r\n" + + "X-Mod-Pagespeed: 1.12.34.2-0\r\n" + + "Connection: keep-alive\r\n\r\n" + }; + Arrays.stream(basic).forEach(responses::add); + // add some tests where some of the CRLF are replaced + // by a single LF + Arrays.stream(basic) + .map(HttpHeaderParserTest::mixedCRLF) + .forEach(responses::add); + + String[] foldingTemplate = + { "HTTP/1.1 200 OK\r\n" + + "Content-Length: 9\r\n" + + "Content-Type: text/html;$NEWLINE" + // folding field-value with '\n'|'\r' + " charset=UTF-8\r\n" + // one preceding SP + "Connection: close\r\n\r\n" + + "XXYYZZAABBCCDDEE", + + "HTTP/1.1 200 OK\r\n" + + "Content-Length: 19\r\n" + + "Content-Type: text/html;$NEWLINE" + // folding field-value with '\n'|'\r + " charset=UTF-8\r\n" + // more than one preceding SP + "Connection: keep-alive\r\n\r\n" + + "XXYYZZAABBCCDDEEFFGG", + + "HTTP/1.1 200 OK\r\n" + + "Content-Length: 999\r\n" + + "Content-Type: text/html;$NEWLINE" + // folding field-value with '\n'|'\r + "\tcharset=UTF-8\r\n" + // one preceding HT + "Connection: close\r\n\r\n" + + "XXYYZZAABBCCDDEE", + + "HTTP/1.1 200 OK\r\n" + + "Content-Length: 54\r\n" + + "Content-Type: text/html;$NEWLINE" + // folding field-value with '\n'|'\r + "\t\t\tcharset=UTF-8\r\n" + // more than one preceding HT + "Connection: keep-alive\r\n\r\n" + + "XXYYZZAABBCCDDEEFFGG", + + "HTTP/1.1 200 OK\r\n" + + "Content-Length: -1\r\n" + + "Content-Type: text/html;$NEWLINE" + // folding field-value with '\n'|'\r + "\t \t \tcharset=UTF-8\r\n" + // mix of preceding HT and SP + "Connection: keep-alive\r\n\r\n" + + "XXYYZZAABBCCDDEEFFGGHH", + + "HTTP/1.1 200 OK\r\n" + + "Content-Length: 65\r\n" + + "Content-Type: text/html;$NEWLINE" + // folding field-value with '\n'|'\r + " \t \t charset=UTF-8\r\n" + // mix of preceding SP and HT + "Connection: keep-alive\r\n\r\n" + + "XXYYZZAABBCCDDEEFFGGHHII", + + "HTTP/1.1 401 Unauthorized\r\n" + + "WWW-Authenticate: Digest realm=\"wally land\"," + +"$NEWLINE domain=/," + +"$NEWLINE nonce=\"2B7F3A2B\"," + +"$NEWLINE\tqop=\"auth\"\r\n\r\n", + + }; + for (String newLineChar : new String[] { "\n", "\r", "\r\n" }) { + for (String template : foldingTemplate) + responses.add(template.replace("$NEWLINE", newLineChar)); + } + // add some tests where some of the CRLF are replaced + // by a single LF + for (String newLineChar : new String[] { "\n", "\r", "\r\n" }) { + for (String template : foldingTemplate) + responses.add(mixedCRLF(template).replace("$NEWLINE", newLineChar)); + } + + String[] bad = // much of this is to retain parity with legacy MessageHeaders + { "HTTP/1.1 200 OK\r\n" + + "Connection:\r\n\r\n", // empty value, no body + + "HTTP/1.1 200 OK\r\n" + + "Connection:\r\n\r\n" + // empty value, with body + "XXXXX", + + "HTTP/1.1 200 OK\r\n" + + ": no header\r\n\r\n", // no/empty header-name, no body, no following header + + "HTTP/1.1 200 OK\r\n" + + ": no; header\r\n" + // no/empty header-name, no body, following header + "Content-Length: 65\r\n\r\n", + + "HTTP/1.1 200 OK\r\n" + + ": no header\r\n" + // no/empty header-name + "Content-Length: 65\r\n\r\n" + + "XXXXX", + + "HTTP/1.1 200 OK\r\n" + + "X-foo: bar\r\n" + + " : no header\r\n" + // fold, not a blank header-name + "Content-Length: 65\r\n\r\n" + + "XXXXX", + + "HTTP/1.1 200 OK\r\n" + + "X-foo: bar\r\n" + + " \t : no header\r\n" + // fold, not a blank header-name + "Content-Length: 65\r\n\r\n" + + "XXXXX", + + "HTTP/1.1 200 OK\r\n" + + ": no header\r\n\r\n" + // no/empty header-name, followed by header + "XXXXX", + + "HTTP/1.1 200 OK\r\n" + + "Conte\r" + + "nt-Length: 9\r\n" + // fold/bad header name ??? without preceding space + "Content-Type: text/html; charset=UTF-8\r\n\r\n" + + "XXXXXYYZZ", + + "HTTP/1.0 404 Not Found\r\n" + + "header-without-colon\r\n\r\n", + + "HTTP/1.0 404 Not Found\r\n" + + "header-without-colon\r\n\r\n" + + "SOMEBODY", + + }; + Arrays.stream(bad).forEach(responses::add); + + return responses.stream().map(p -> new Object[] { p }).toArray(Object[][]::new); + } + + static final AtomicInteger index = new AtomicInteger(); + static final AtomicInteger limit = new AtomicInteger(1); + static final AtomicBoolean useCRLF = new AtomicBoolean(); + // A small method to replace part of the CRLF present in a string + // with simple LF. The method uses a deterministic algorithm based + // on current values of static index/limit/useCRLF counters. + // These counters are used to produce a stream of substitutes that + // looks like this: + // LF CRLF LF LF CRLF CRLF LF LF LF CRLF CRLF CRLF (then repeat from start) + static final String mixedCRLF(String headers) { + int next; + int start = 0; + int last = headers.lastIndexOf("\r\n"); + String prev = ""; + StringBuilder res = new StringBuilder(); + while ((next = headers.indexOf("\r\n", start)) > 0) { + res.append(headers.substring(start, next)); + if ("\n".equals(prev) && next == last) { + // for some reason the legacy MessageHeader parser will + // not consume the final LF if the headers are terminated + // by <LF><CRLF> instead of <CRLF><CRLF>. It consume + // <LF><CR> but leaves the last <LF> in the stream. + // Here we just make sure to avoid using <LF><CRLF> + // as that would cause the legacy parser to consume + // 1 byte less than the Http1HeadersParser - which + // does consume the last <LF>, as it should. + // if this is the last CRLF and the previous one + // was replaced by LF then use LF. + res.append(prev); + } else { + prev = useCRLF.get() ? "\r\n" : "\n"; + res.append(prev); + } + // skip CRLF + start = next + 2; + + // The idea is to substitute some of the CRLF with LF. + // Rather than doing this randomly, always use the following + // sequence: + // LF CRLF LF LF CRLF CRLF LF LF LF CRLF CRLF CRLF + index.incrementAndGet(); + if (index.get() == limit.get()) { + index.set(0); + if (useCRLF.get()) limit.incrementAndGet(); + if (limit.get() > 3) limit.set(1); + useCRLF.set(!useCRLF.get()); + } + } + res.append(headers.substring(start)); + return res.toString(); + } + + + @Test(dataProvider = "responses") + public void verifyHeaders(String respString) throws Exception { + System.out.println("\ntesting:\n\t" + respString + .replace("\r\n", "<CRLF>") + .replace("\r", "<CR>") + .replace("\n","<LF>") + .replace("LF>", "LF>\n\t")); + byte[] bytes = respString.getBytes(ISO_8859_1); + ByteArrayInputStream bais = new ByteArrayInputStream(bytes); + MessageHeader m = new MessageHeader(bais); + Map<String,List<String>> messageHeaderMap = m.getHeaders(); + int availableBytes = bais.available(); + + HttpHeaderParser decoder = new HttpHeaderParser(); + ByteArrayInputStream headerStream = new ByteArrayInputStream(bytes); + int initialBytes = headerStream.available(); + decoder.parse(headerStream); + System.out.printf("HttpHeaderParser parsed %d bytes out of %d%n", initialBytes - headerStream.available(), bytes.length); + Map<String,List<String>> decoderMap1 = decoder.getHeaderMap(); + + + // assert status-line + String statusLine1 = messageHeaderMap.get(null).get(0); + String statusLine2 = decoder.getRequestDetails(); + if (statusLine1.startsWith("HTTP")) {// skip the case where MH's messes up the status-line + assertEquals(statusLine2, statusLine1, "Status-line not equal"); + } else { + assertTrue(statusLine2.startsWith("HTTP/1."), "Status-line not HTTP/1."); + } + + // remove the null'th entry with is the status-line + Map<String,List<String>> map = new HashMap<>(); + for (Map.Entry<String,List<String>> e : messageHeaderMap.entrySet()) { + if (e.getKey() != null) { + map.put(e.getKey(), e.getValue()); + } + } + messageHeaderMap = map; + + assertHeadersEqual(messageHeaderMap, decoderMap1, + "messageHeaderMap not equal to decoderMap1"); + + assertEquals(availableBytes, headerStream.available(), + String.format("stream available (%d) not equal to remaining (%d)", + availableBytes, headerStream.available())); + } + + @DataProvider(name = "errors") + public Object[][] errors() { + List<String> responses = new ArrayList<>(); + + // These responses are parsed, somewhat, by MessageHeaders but give + // nonsensible results. They, correctly, fail with the Http1HeaderParser. + String[] bad = + {// "HTTP/1.1 402 Payment Required\r\n" + + // "Content-Length: 65\r\n\r", // missing trailing LF //TODO: incomplete + + "HTTP/1.1 402 Payment Required\r\n" + + "Content-Length: 65\r\n\rT\r\n\r\nGGGGGG", + + "HTTP/1.1 200OK\r\n\rT", + + "HTTP/1.1 200OK\rT", + + "HTTP/1.0 FOO\r\n", + + "HTTP/1.1 BAR\r\n", + + "HTTP/1.1 +99\r\n", + + "HTTP/1.1 -22\r\n", + + "HTTP/1.1 -20 \r\n", + + "HTTP/1.1 200 OK\r\n" + + "X-fo\u00ffo: foo\r\n" + // invalid char in name + "Content-Length: 5\r\n" + + "Content-Type: text/html; charset=UTF-8\r\n\r\n" + + "XXXXX", + + "HTTP/1.1 200 OK\r\n" + + "HTTP/1.1 200 OK\r\n" + + "X-foo : bar\r\n" + // trim space after name + "Content-Length: 5\r\n" + + "Content-Type: text/html; charset=UTF-8\r\n\r\n" + + "XXXXX", + + "HTTP/1.1 200 OK\r\n" + + " X-foo: bar\r\n" + // trim space before name + "Content-Length: 5\r\n" + + "Content-Type: text/html; charset=UTF-8\r\n\r\n" + + "XXXXX", + + "HTTP/1.1 200 OK\r\n" + + "X foo: bar\r\n" + // invalid space in name + "Content-Length: 5\r\n" + + "Content-Type: text/html; charset=UTF-8\r\n\r\n" + + "XXXXX", + + "HTTP/1.1 200 OK\r\n" + + "Content-Length: 5\r\n" + + "Content Type: text/html; charset=UTF-8\r\n\r\n" + // invalid space in name + "XXXXX", + + "HTTP/1.1 200 OK\r\n" + + "Conte\r" + + " nt-Length: 9\r\n" + // fold results in space in header name + "Content-Type: text/html; charset=UTF-8\r\n\r\n" + + "XXXXX", + + "HTTP/1.1 200 OK\r\n" + + " : no header\r\n" + // all blank header-name (not fold) + "Content-Length: 65\r\n\r\n" + + "XXXXX", + + "HTTP/1.1 200 OK\r\n" + + " \t : no header\r\n" + // all blank header-name (not fold) + "Content-Length: 65\r\n\r\n" + + "XXXXX", + + }; + Arrays.stream(bad).forEach(responses::add); + + return responses.stream().map(p -> new Object[] { p }).toArray(Object[][]::new); + } + + @Test(dataProvider = "errors", expectedExceptions = IOException.class) + public void errors(String respString) throws IOException { + byte[] bytes = respString.getBytes(US_ASCII); + HttpHeaderParser decoder = new HttpHeaderParser(); + ByteArrayInputStream bais = new ByteArrayInputStream(bytes); + decoder.parse(bais); + } + + void assertHeadersEqual(Map<String,List<String>> expected, + Map<String,List<String>> actual, + String msg) { + + if (expected.equals(actual)) + return; + + assertEquals(expected.size(), actual.size(), + format("%s. Expected size %d, actual size %s. %nexpected= %s,%n actual=%s.", + msg, expected.size(), actual.size(), mapToString(expected), mapToString(actual))); + + for (Map.Entry<String,List<String>> e : expected.entrySet()) { + String key = e.getKey(); + List<String> values = e.getValue(); + + boolean found = false; + for (Map.Entry<String,List<String>> other: actual.entrySet()) { + if (key.equalsIgnoreCase(other.getKey())) { + found = true; + List<String> otherValues = other.getValue(); + assertEquals(values.size(), otherValues.size(), + format("%s. Expected list size %d, actual size %s", + msg, values.size(), otherValues.size())); + if (!(values.containsAll(otherValues) && otherValues.containsAll(values))) + assertTrue(false, format("Lists are unequal [%s] [%s]", values, otherValues)); + break; + } + } + assertTrue(found, format("header name, %s, not found in %s", key, actual)); + } + } + + static String mapToString(Map<String,List<String>> map) { + StringBuilder sb = new StringBuilder(); + List<String> sortedKeys = new ArrayList(map.keySet()); + Collections.sort(sortedKeys); + for (String key : sortedKeys) { + List<String> values = map.get(key); + sb.append("\n\t" + key + " | " + values); + } + return sb.toString(); + } +} diff --git a/test/jdk/sun/net/www/protocol/http/NTLMTest.java b/test/jdk/sun/net/www/protocol/http/NTLMTest.java index 73d0cb98603d3e39d5e024f2258b42b59f648333..37282f15b03b99e57c7716982ef926316c61ae51 100644 --- a/test/jdk/sun/net/www/protocol/http/NTLMTest.java +++ b/test/jdk/sun/net/www/protocol/http/NTLMTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 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 @@ -24,7 +24,6 @@ /* * @test * @bug 6520665 6357133 - * @modules java.base/sun.net.www * @library /test/lib * @run main/othervm NTLMTest * @summary 6520665 & 6357133: NTLM authentication issues. @@ -32,7 +31,8 @@ import java.net.*; import java.io.*; -import sun.net.www.MessageHeader; + +import jdk.test.lib.net.HttpHeaderParser; import jdk.test.lib.net.URIBuilder; public class NTLMTest @@ -160,7 +160,7 @@ public class NTLMTest OutputStream os = s.getOutputStream(); for (int i=start; i<end; i++) { - MessageHeader header = new MessageHeader (s.getInputStream()); + HttpHeaderParser httpHeaderParser = new HttpHeaderParser(s.getInputStream()); //System.out.println("Input :" + header); //System.out.println("Output:" + resp[i]); os.write(resp[i].getBytes("ASCII")); diff --git a/test/jdk/sun/net/www/protocol/http/NoNTLM.java b/test/jdk/sun/net/www/protocol/http/NoNTLM.java index 2eaa212bf29b1c63de132922a5b526d367739258..1ae7af670bf71c5983a81c59ae9c8177217074ff 100644 --- a/test/jdk/sun/net/www/protocol/http/NoNTLM.java +++ b/test/jdk/sun/net/www/protocol/http/NoNTLM.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -26,8 +26,7 @@ * @library /test/lib * @summary Sanity check that NTLM will not be selected by the http protocol * handler when running on a profile that does not support NTLM - * @modules java.base/sun.net.www - * java.base/sun.net.www.protocol.http:open + * @modules java.base/sun.net.www.protocol.http:open * @run main/othervm NoNTLM * @run main/othervm -Djava.net.preferIPv6Addresses=true NoNTLM */ @@ -42,8 +41,9 @@ import java.net.Proxy; import java.net.ServerSocket; import java.net.Socket; import java.net.URL; + +import jdk.test.lib.net.HttpHeaderParser; import jdk.test.lib.net.URIBuilder; -import sun.net.www.MessageHeader; public class NoNTLM { @@ -163,7 +163,7 @@ public class NoNTLM { // client ---- GET ---> server // client <--- 401 ---- server try (Socket s = ss.accept()) { - new MessageHeader().parseHeader(s.getInputStream()); + new HttpHeaderParser().parse(s.getInputStream()); s.getOutputStream().write(reply.getBytes("US-ASCII")); } @@ -171,10 +171,10 @@ public class NoNTLM { // client <--- 200 ---- server String auth; try (Socket s = ss.accept()) { - MessageHeader mh = new MessageHeader(); - mh.parseHeader(s.getInputStream()); + HttpHeaderParser mh = new HttpHeaderParser(); + mh.parse(s.getInputStream()); s.getOutputStream().write(OKAY.getBytes("US-ASCII")); - auth = mh.findValue("Authorization"); + auth = mh.getHeaderValue("Authorization").get(0); } // check Authorization header @@ -208,7 +208,7 @@ public class NoNTLM { // client ---- GET ---> server // client <--- 401 ---- client try (Socket s = ss.accept()) { - new MessageHeader().parseHeader(s.getInputStream()); + new HttpHeaderParser().parse(s.getInputStream()); s.getOutputStream().write(reply.getBytes("US-ASCII")); } diff --git a/test/jdk/sun/net/www/protocol/http/RetryUponTimeout.java b/test/jdk/sun/net/www/protocol/http/RetryUponTimeout.java index bfda1663259f61858a1711db21d73975cd020c74..b2214780c2e8d5d00e32b39aaeef4fade201c3ee 100644 --- a/test/jdk/sun/net/www/protocol/http/RetryUponTimeout.java +++ b/test/jdk/sun/net/www/protocol/http/RetryUponTimeout.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -26,13 +26,13 @@ * @bug 4772077 * @library /test/lib * @summary using defaultReadTimeout appear to retry request upon timeout - * @modules java.base/sun.net.www */ import java.net.*; import java.io.*; + +import jdk.test.lib.net.HttpHeaderParser; import jdk.test.lib.net.URIBuilder; -import sun.net.www.*; public class RetryUponTimeout implements Runnable { // run server @@ -42,7 +42,7 @@ public class RetryUponTimeout implements Runnable { for (int i = 0; i < 2; i++) { socket = server.accept(); InputStream is = socket.getInputStream (); - MessageHeader header = new MessageHeader (is); + HttpHeaderParser header = new HttpHeaderParser (is); count++; } } catch (Exception ex) { diff --git a/test/jdk/sun/net/www/protocol/http/UserAgent.java b/test/jdk/sun/net/www/protocol/http/UserAgent.java index 7db848824887af6eec50608cdc3c460ee298d0a4..40ff5d3106fc61d2cee2640d49d20e6a5d87749a 100644 --- a/test/jdk/sun/net/www/protocol/http/UserAgent.java +++ b/test/jdk/sun/net/www/protocol/http/UserAgent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -25,7 +25,6 @@ * @test * @bug 4512200 * @library /test/lib - * @modules java.base/sun.net.www * @run main/othervm -Dhttp.agent=foo UserAgent * @run main/othervm -Dhttp.agent=foo -Djava.net.preferIPv6Addresses=true UserAgent * @summary HTTP header "User-Agent" format incorrect @@ -34,8 +33,9 @@ import java.io.*; import java.util.*; import java.net.*; + +import jdk.test.lib.net.HttpHeaderParser; import jdk.test.lib.net.URIBuilder; -import sun.net.www.MessageHeader; class Server extends Thread { Server (ServerSocket server) { @@ -46,8 +46,8 @@ class Server extends Thread { String version = System.getProperty ("java.version"); String expected = "foo Java/"+version; Socket s = server.accept (); - MessageHeader header = new MessageHeader (s.getInputStream()); - String v = header.findValue ("User-Agent"); + HttpHeaderParser header = new HttpHeaderParser (s.getInputStream()); + String v = header.getHeaderValue ("User-Agent").get(0); if (!expected.equals (v)) { error ("Got unexpected User-Agent: " + v); } else { diff --git a/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/B6226610.java b/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/B6226610.java index ec75bcc3e113adfdbd6e474f3b090b5190dc5fd3..9fca12c995840e194896dc45ff07c9be7fa4f0e5 100644 --- a/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/B6226610.java +++ b/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/B6226610.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -25,7 +25,7 @@ * @test * @bug 6226610 6973030 * @summary HTTP tunnel connections send user headers to proxy - * @modules java.base/sun.net.www + * @library /test/lib * @run main/othervm B6226610 */ @@ -37,7 +37,9 @@ import java.io.*; import java.net.*; -import sun.net.www.MessageHeader; + +import jdk.test.lib.net.HttpHeaderParser; + public class B6226610 { static HeaderCheckerProxyTunnelServer proxy; @@ -138,21 +140,21 @@ class HeaderCheckerProxyTunnelServer extends Thread private void processRequests() throws IOException { InputStream in = clientSocket.getInputStream(); - MessageHeader mheader = new MessageHeader(in); - String statusLine = mheader.getValue(0); + HttpHeaderParser mheader = new HttpHeaderParser(in); + String statusLine = mheader.getRequestDetails(); if (statusLine.startsWith("CONNECT")) { // retrieve the host and port info from the status-line retrieveConnectInfo(statusLine); - if (mheader.findValue("X-TestHeader") != null) { + if (mheader.getHeaderValue("X-TestHeader") != null) { System.out.println("Proxy should not receive user defined headers for tunneled requests"); failed = true; } // 6973030 String value; - if ((value = mheader.findValue("Proxy-Connection")) == null || + if ((value = mheader.getHeaderValue("Proxy-Connection").get(0)) == null || !value.equals("keep-alive")) { System.out.println("Proxy-Connection:keep-alive not being sent"); failed = true; diff --git a/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/TunnelProxy.java b/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/TunnelProxy.java index 9573543fde11946da4126047e670c7e6045addfd..9cec3987d9e0314bd09831bc9697c16d0a3bb294 100644 --- a/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/TunnelProxy.java +++ b/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/TunnelProxy.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -45,7 +45,8 @@ import java.util.HashMap; import java.util.Iterator; import java.util.Set; -import sun.net.www.MessageHeader; +import jdk.test.lib.net.HttpHeaderParser; + public class TunnelProxy { @@ -260,9 +261,9 @@ public class TunnelProxy { boolean res; try { InputStream is = new BufferedInputStream (new NioInputStream (chan)); - String requestline = readLine (is); - MessageHeader mhead = new MessageHeader (is); - String[] req = requestline.split (" "); + HttpHeaderParser mHead = new HttpHeaderParser (is); + String requestLine = mHead.getRequestDetails(); + String[] req = requestLine.split (" "); if (req.length < 2) { /* invalid request line */ return false; diff --git a/test/jdk/sun/nio/cs/TestCharsetMapping.java b/test/jdk/sun/nio/cs/TestCharsetMapping.java index 63eeba1774e56009f2e4a811e04990cfc8d296d4..c7bd101aa425a91d69643a859e70982cf87adf7f 100644 --- a/test/jdk/sun/nio/cs/TestCharsetMapping.java +++ b/test/jdk/sun/nio/cs/TestCharsetMapping.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -569,7 +569,7 @@ public class TestCharsetMapping { public static void main(String args[]) throws Exception { Path dir = Paths.get(System.getProperty("test.src", ".") + - "/../../../../make/data/charsetmapping"); + "/../../../../src/java.base/share/data/charsetmapping"); if (!Files.exists(dir)) { // not inside jdk repo, no mappings, exit silently log.println("Nothing done, not in a jdk repo: "); diff --git a/test/jdk/sun/nio/cs/TestMS950.java b/test/jdk/sun/nio/cs/TestMS950.java index 6d567e077519cd0de790850de8366a2fc10f4f5a..36820f381a04f6efe6052d2d730c9fc59e05ca85 100644 --- a/test/jdk/sun/nio/cs/TestMS950.java +++ b/test/jdk/sun/nio/cs/TestMS950.java @@ -33,7 +33,7 @@ import java.nio.ByteBuffer; import java.util.Arrays; public class TestMS950 { - // Data is listed from make/data/charsetmapping/MS950.map + // Data is listed from src/java.base/share/data/charsetmapping/MS950.map private final static String[] MS950B2C = new String[] { "0xF9FA 0x256D", "0xF9FB 0x256E", diff --git a/test/jdk/sun/security/ec/OidInstance.java b/test/jdk/sun/security/ec/OidInstance.java new file mode 100644 index 0000000000000000000000000000000000000000..972c8e1026a5031588b41785fbc01d76adbaab79 --- /dev/null +++ b/test/jdk/sun/security/ec/OidInstance.java @@ -0,0 +1,45 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8279801 + * @summary EC KeyFactory and KeyPairGenerator do not have aliases for OID format + * @modules java.base/sun.security.util + * jdk.crypto.ec + */ + +import sun.security.util.KnownOIDs; + +import java.security.AlgorithmParameters; +import java.security.KeyFactory; +import java.security.KeyPairGenerator; + +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"); + } +} diff --git a/test/jdk/sun/security/krb5/auto/Context.java b/test/jdk/sun/security/krb5/auto/Context.java index ed8bab0e3d6aee79b117a94fbf7df8ad3a02da77..c18dbe9690fc8690fc5ba86929ddde7a61093016 100644 --- a/test/jdk/sun/security/krb5/auto/Context.java +++ b/test/jdk/sun/security/krb5/auto/Context.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 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 @@ -207,13 +207,26 @@ public class Context { */ public static Context fromUserKtab(Subject s, String user, String ktab, boolean storeKey) throws Exception { + return fromUserKtab(s, user, ktab, false, storeKey); + } + + /** + * Logins with username/keytab as a client. + */ + public static Context fromUserKtabAsClient( + String user, String ktab, boolean storeKey) throws Exception { + return fromUserKtab(new Subject(), user, ktab, true, storeKey); + } + + private static Context fromUserKtab(Subject s, + String user, String ktab, boolean isInitiator, boolean storeKey) throws Exception { Context out = new Context(); out.name = user; out.s = s; Krb5LoginModule krb5 = new Krb5LoginModule(); Map<String, String> map = new HashMap<>(); - map.put("isInitiator", "false"); + map.put("isInitiator", Boolean.toString(isInitiator)); map.put("doNotPrompt", "true"); map.put("useTicketCache", "false"); map.put("useKeyTab", "true"); diff --git a/test/jdk/sun/security/krb5/auto/HttpsCB.java b/test/jdk/sun/security/krb5/auto/HttpsCB.java new file mode 100644 index 0000000000000000000000000000000000000000..1f9f0de33aca6ddf9bf44a27f915375672a0c288 --- /dev/null +++ b/test/jdk/sun/security/krb5/auto/HttpsCB.java @@ -0,0 +1,318 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8279842 8282293 + * @modules java.base/sun.security.util + * java.security.jgss/sun.security.jgss + * java.security.jgss/sun.security.jgss.krb5 + * java.security.jgss/sun.security.jgss.krb5.internal + * java.security.jgss/sun.security.krb5.internal:+open + * java.security.jgss/sun.security.krb5:+open + * java.security.jgss/sun.security.krb5.internal.ccache + * java.security.jgss/sun.security.krb5.internal.crypto + * java.security.jgss/sun.security.krb5.internal.ktab + * jdk.security.auth + * jdk.security.jgss + * jdk.httpserver + * @summary HTTPS Channel Binding support for Java GSS/Kerberos + * @library /test/lib + * @run main jdk.test.lib.FileInstaller TestHosts TestHosts + * @run main/othervm -Djdk.net.hosts.file=TestHosts + * -Djdk.https.negotiate.cbt=always HttpsCB true true + * @run main/othervm -Djdk.net.hosts.file=TestHosts + * -Djdk.https.negotiate.cbt=never HttpsCB false true + * @run main/othervm -Djdk.net.hosts.file=TestHosts + * -Djdk.https.negotiate.cbt=invalid HttpsCB false true + * @run main/othervm -Djdk.net.hosts.file=TestHosts + * HttpsCB false true + * @run main/othervm -Djdk.net.hosts.file=TestHosts + * -Djdk.https.negotiate.cbt=domain:other.com HttpsCB false true + * @run main/othervm -Djdk.net.hosts.file=TestHosts + * -Djdk.https.negotiate.cbt=domain:host.web.domain HttpsCB true true + * @run main/othervm -Djdk.net.hosts.file=TestHosts + * -Djdk.https.negotiate.cbt=domain:HOST.WEB.DOMAIN HttpsCB true true + * @run main/othervm -Djdk.net.hosts.file=TestHosts + * -Djdk.https.negotiate.cbt=domain:*.web.domain HttpsCB true true + * @run main/othervm -Djdk.net.hosts.file=TestHosts + * -Djdk.https.negotiate.cbt=domain:*.WEB.Domain HttpsCB true true + * @run main/othervm -Djdk.net.hosts.file=TestHosts + * -Djdk.https.negotiate.cbt=domain:*.Invalid,*.WEB.Domain HttpsCB true true + */ + +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 com.sun.net.httpserver.HttpPrincipal; +import com.sun.net.httpserver.HttpsConfigurator; +import com.sun.net.httpserver.HttpsExchange; +import com.sun.net.httpserver.HttpsServer; +import com.sun.security.auth.module.Krb5LoginModule; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.InetSocketAddress; +import java.net.PasswordAuthentication; +import java.net.Proxy; +import java.net.Socket; +import java.net.URL; +import java.security.cert.X509Certificate; +import java.util.HashMap; +import java.util.Map; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLEngine; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509ExtendedTrustManager; +import javax.security.auth.Subject; + +import jdk.test.lib.Asserts; +import jdk.test.lib.net.SimpleSSLContext; +import org.ietf.jgss.GSSContext; +import org.ietf.jgss.GSSCredential; +import org.ietf.jgss.GSSManager; +import sun.security.jgss.GSSUtil; +import sun.security.jgss.krb5.internal.TlsChannelBindingImpl; +import sun.security.krb5.Config; +import sun.security.util.TlsChannelBinding; + +import java.util.Base64; +import java.util.concurrent.Callable; + +public class HttpsCB { + + final static String REALM_WEB = "WEB.DOMAIN"; + final static String KRB5_CONF = "web.conf"; + final static String KRB5_TAB = "web.ktab"; + + final static String WEB_USER = "web"; + final static char[] WEB_PASS = "webby".toCharArray(); + final static String WEB_HOST = "host.web.domain"; + final static String CONTENT = "Hello, World!"; + + static int webPort; + static URL cbtURL; + static URL normalURL; + + public static void main(String[] args) + throws Exception { + + boolean expectCBT = Boolean.parseBoolean(args[0]); + boolean expectNoCBT = Boolean.parseBoolean(args[1]); + + System.setProperty("sun.security.krb5.debug", "true"); + + KDC kdcw = KDC.create(REALM_WEB); + kdcw.addPrincipal(WEB_USER, WEB_PASS); + kdcw.addPrincipalRandKey("krbtgt/" + REALM_WEB); + kdcw.addPrincipalRandKey("HTTP/" + WEB_HOST); + + KDC.saveConfig(KRB5_CONF, kdcw, + "default_keytab_name = " + KRB5_TAB, + "[domain_realm]", + "", + ".web.domain="+REALM_WEB); + + System.setProperty("java.security.krb5.conf", KRB5_CONF); + Config.refresh(); + KDC.writeMultiKtab(KRB5_TAB, kdcw); + + // Write a customized JAAS conf file, so that any kinit cache + // will be ignored. + System.setProperty("java.security.auth.login.config", OneKDC.JAAS_CONF); + File f = new File(OneKDC.JAAS_CONF); + FileOutputStream fos = new FileOutputStream(f); + fos.write(( + "com.sun.security.jgss.krb5.initiate {\n" + + " com.sun.security.auth.module.Krb5LoginModule required;\n};\n" + ).getBytes()); + fos.close(); + + HttpServer h1 = httpd("Negotiate", + "HTTP/" + WEB_HOST + "@" + REALM_WEB, KRB5_TAB); + webPort = h1.getAddress().getPort(); + + cbtURL = new URL("https://" + WEB_HOST +":" + webPort + "/cbt"); + normalURL = new URL("https://" + WEB_HOST +":" + webPort + "/normal"); + + java.net.Authenticator.setDefault(new java.net.Authenticator() { + public PasswordAuthentication getPasswordAuthentication () { + return new PasswordAuthentication( + WEB_USER+"@"+REALM_WEB, WEB_PASS); + } + }); + + // Client-side SSLContext needs to ignore hostname mismatch + // and untrusted certificate. + SSLContext sc = SSLContext.getInstance("SSL"); + sc.init(null, new TrustManager[] { + new X509ExtendedTrustManager() { + public X509Certificate[] getAcceptedIssuers() { + return null; + } + public void checkClientTrusted(X509Certificate[] chain, + String authType, Socket socket) { } + public void checkServerTrusted(X509Certificate[] chain, + String authType, Socket socket) { } + public void checkClientTrusted(X509Certificate[] chain, + String authType, SSLEngine engine) { } + public void checkServerTrusted(X509Certificate[] chain, + String authType, SSLEngine engine) { } + public void checkClientTrusted(X509Certificate[] certs, + String authType) { } + public void checkServerTrusted(X509Certificate[] certs, + String authType) { } + } + }, null); + + Asserts.assertEQ(visit(sc, cbtURL), expectCBT); + Asserts.assertEQ(visit(sc, normalURL), expectNoCBT); + } + + static boolean visit(SSLContext sc, URL url) { + try { + HttpsURLConnection conn = (HttpsURLConnection) + url.openConnection(Proxy.NO_PROXY); + conn.setSSLSocketFactory(sc.getSocketFactory()); + BufferedReader reader; + reader = new BufferedReader(new InputStreamReader( + conn.getInputStream())); + return reader.readLine().equals(CONTENT); + } catch (IOException e) { + e.printStackTrace(System.out); + return false; + } + } + + static HttpServer httpd(String scheme, String principal, String ktab) + throws Exception { + MyHttpHandler h = new MyHttpHandler(); + HttpsServer server = HttpsServer.create(new InetSocketAddress(0), 0); + server.setHttpsConfigurator( + new HttpsConfigurator(new SimpleSSLContext().get())); + server.createContext("/", h).setAuthenticator( + new MyServerAuthenticator(scheme, principal, ktab)); + server.start(); + return server; + } + + static class MyHttpHandler implements HttpHandler { + public void handle(HttpExchange t) throws IOException { + t.sendResponseHeaders(200, 0); + t.getResponseBody().write(CONTENT.getBytes()); + t.close(); + } + } + + static class MyServerAuthenticator + extends com.sun.net.httpserver.Authenticator { + Subject s = new Subject(); + GSSManager m; + GSSCredential cred; + String scheme = null; + String reqHdr = "WWW-Authenticate"; + String respHdr = "Authorization"; + int err = HttpURLConnection.HTTP_UNAUTHORIZED; + + public MyServerAuthenticator(String scheme, + String principal, String ktab) throws Exception { + + this.scheme = scheme; + Krb5LoginModule krb5 = new Krb5LoginModule(); + Map<String, String> map = new HashMap<>(); + Map<String, Object> shared = new HashMap<>(); + + map.put("storeKey", "true"); + map.put("isInitiator", "false"); + map.put("useKeyTab", "true"); + map.put("keyTab", ktab); + map.put("principal", principal); + krb5.initialize(s, null, shared, map); + krb5.login(); + krb5.commit(); + m = GSSManager.getInstance(); + cred = Subject.callAs(s, new Callable<GSSCredential>() { + @Override + public GSSCredential call() throws Exception { + System.err.println("Creating GSSCredential"); + return m.createCredential( + null, + GSSCredential.INDEFINITE_LIFETIME, + MyServerAuthenticator.this.scheme + .equalsIgnoreCase("Negotiate") ? + GSSUtil.GSS_SPNEGO_MECH_OID : + GSSUtil.GSS_KRB5_MECH_OID, + GSSCredential.ACCEPT_ONLY); + } + }); + } + + @Override + public Result authenticate(HttpExchange exch) { + // The GSContext is stored in an HttpContext attribute named + // "GSSContext" and is created at the first request. + GSSContext c = null; + String auth = exch.getRequestHeaders().getFirst(respHdr); + try { + c = (GSSContext)exch.getHttpContext() + .getAttributes().get("GSSContext"); + if (auth == null) { // First request + Headers map = exch.getResponseHeaders(); + map.set (reqHdr, scheme); // Challenge! + c = Subject.callAs(s, () -> m.createContext(cred)); + // CBT is required for cbtURL + if (exch instanceof HttpsExchange sexch + && exch.getRequestURI().toString().equals("/cbt")) { + TlsChannelBinding b = TlsChannelBinding.create( + (X509Certificate) sexch.getSSLSession() + .getLocalCertificates()[0]); + c.setChannelBinding( + new TlsChannelBindingImpl(b.getData())); + } + exch.getHttpContext().getAttributes().put("GSSContext", c); + return new com.sun.net.httpserver.Authenticator.Retry(err); + } else { // Later requests + byte[] token = Base64.getMimeDecoder() + .decode(auth.split(" ")[1]); + token = c.acceptSecContext(token, 0, token.length); + Headers map = exch.getResponseHeaders(); + map.set (reqHdr, scheme + " " + Base64.getMimeEncoder() + .encodeToString(token).replaceAll("\\s", "")); + if (c.isEstablished()) { + return new com.sun.net.httpserver.Authenticator.Success( + new HttpPrincipal(c.getSrcName().toString(), "")); + } else { + return new com.sun.net.httpserver.Authenticator.Retry(err); + } + } + } catch (Exception e) { + throw new RuntimeException(e); + } + } + } +} diff --git a/test/jdk/sun/security/krb5/auto/IgnoreChannelBinding.java b/test/jdk/sun/security/krb5/auto/IgnoreChannelBinding.java index a9760dae9ad1bfdf92483fe5ca796628bd83f937..a393c299b70444261f2d507937024f0fd7d1b32c 100644 --- a/test/jdk/sun/security/krb5/auto/IgnoreChannelBinding.java +++ b/test/jdk/sun/security/krb5/auto/IgnoreChannelBinding.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 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 @@ -23,7 +23,7 @@ /* * @test - * @bug 6851973 8194486 + * @bug 6851973 8194486 8279520 * @summary ignore incoming channel binding if acceptor does not set one * @library /test/lib * @run main jdk.test.lib.FileInstaller TestHosts TestHosts @@ -33,6 +33,7 @@ import java.net.InetAddress; import org.ietf.jgss.ChannelBinding; import org.ietf.jgss.GSSException; +import org.ietf.jgss.Oid; import sun.security.jgss.GSSUtil; public class IgnoreChannelBinding { @@ -41,33 +42,38 @@ public class IgnoreChannelBinding { throws Exception { new OneKDC(null).writeJAASConf(); + test(GSSUtil.GSS_KRB5_MECH_OID); + test(GSSUtil.GSS_SPNEGO_MECH_OID); + } + + static void test(Oid mech) throws Exception { Context c = Context.fromJAAS("client"); Context s = Context.fromJAAS("server"); // All silent - c.startAsClient(OneKDC.SERVER, GSSUtil.GSS_KRB5_MECH_OID); - s.startAsServer(GSSUtil.GSS_KRB5_MECH_OID); + c.startAsClient(OneKDC.SERVER, mech); + s.startAsServer(mech); Context.handshake(c, s); // Initiator req, acceptor ignore - c.startAsClient(OneKDC.SERVER, GSSUtil.GSS_KRB5_MECH_OID); + c.startAsClient(OneKDC.SERVER, mech); c.x().setChannelBinding(new ChannelBinding( InetAddress.getByName("client.rabbit.hole"), InetAddress.getByName("host.rabbit.hole"), new byte[0] )); - s.startAsServer(GSSUtil.GSS_KRB5_MECH_OID); + s.startAsServer(mech); Context.handshake(c, s); // Both req, and match - c.startAsClient(OneKDC.SERVER, GSSUtil.GSS_KRB5_MECH_OID); + c.startAsClient(OneKDC.SERVER, mech); c.x().setChannelBinding(new ChannelBinding( InetAddress.getByName("client.rabbit.hole"), InetAddress.getByName("host.rabbit.hole"), new byte[0] )); - s.startAsServer(GSSUtil.GSS_KRB5_MECH_OID); + s.startAsServer(mech); s.x().setChannelBinding(new ChannelBinding( InetAddress.getByName("client.rabbit.hole"), InetAddress.getByName("host.rabbit.hole"), @@ -76,13 +82,13 @@ public class IgnoreChannelBinding { Context.handshake(c, s); // Both req, NOT match - c.startAsClient(OneKDC.SERVER, GSSUtil.GSS_KRB5_MECH_OID); + c.startAsClient(OneKDC.SERVER, mech); c.x().setChannelBinding(new ChannelBinding( InetAddress.getByName("client.rabbit.hole"), InetAddress.getByName("host.rabbit.hole"), new byte[0] )); - s.startAsServer(GSSUtil.GSS_KRB5_MECH_OID); + s.startAsServer(mech); s.x().setChannelBinding(new ChannelBinding( InetAddress.getByName("client.rabbit.hole"), InetAddress.getByName("host.rabbit.hole"), @@ -96,8 +102,8 @@ public class IgnoreChannelBinding { } // Acceptor req, reject - c.startAsClient(OneKDC.SERVER, GSSUtil.GSS_KRB5_MECH_OID); - s.startAsServer(GSSUtil.GSS_KRB5_MECH_OID); + c.startAsClient(OneKDC.SERVER, mech); + s.startAsServer(mech); s.x().setChannelBinding(new ChannelBinding( InetAddress.getByName("client.rabbit.hole"), InetAddress.getByName("host.rabbit.hole"), diff --git a/test/jdk/sun/security/krb5/auto/KDC.java b/test/jdk/sun/security/krb5/auto/KDC.java index aeab113995f93f661f60050b51575091fff5c02b..6e4bfba61f4a843bdb33103723a3ba0ee9b6b3b1 100644 --- a/test/jdk/sun/security/krb5/auto/KDC.java +++ b/test/jdk/sun/security/krb5/auto/KDC.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 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 @@ -29,8 +29,11 @@ import java.lang.reflect.InvocationTargetException; import java.net.*; import java.io.*; import java.lang.reflect.Method; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Paths; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; import java.util.*; import java.util.concurrent.*; import java.util.stream.Collectors; @@ -249,6 +252,14 @@ public class KDC { * If true, will check if TGS-REQ contains a non-null addresses field. */ CHECK_ADDRESSES, + /** + * If true, S4U2self ticket is not set forwardable. + */ + S4U2SELF_NOT_FORWARDABLE, + /** + * If true, allow S4U2self ticket not forwardable. + */ + S4U2SELF_ALLOW_NOT_FORWARDABLE, }; /** @@ -441,12 +452,12 @@ public class KDC { } /** - * Adds a new principal to this realm with a random password + * Adds a new principal to this realm with a generated password * @param user the principal's name. For a service principal, use the * form of host/f.q.d.n */ public void addPrincipalRandKey(String user) { - addPrincipal(user, randomPassword()); + addPrincipal(user, randomPassword(user + "@" + realm)); } /** @@ -607,14 +618,29 @@ public class KDC { startServer(port, asDaemon); } /** - * Generates a 32-char random password + * Generates a 32-char password + * @param user the string to generate from, random is null * @return the password */ - private static char[] randomPassword() { - char[] pass = new char[32]; - Random r = new Random(); - for (int i=0; i<31; i++) - pass[i] = (char)('a' + r.nextInt(26)); + private static char[] randomPassword(String user) { + char[] pass; + if (user == null) { + pass = new char[32]; + Random r = new Random(); + for (int i = 0; i < 31; i++) { + pass[i] = (char) ('a' + r.nextInt(26)); + } + } else { + try { + pass = Base64.getEncoder().encodeToString( + MessageDigest.getInstance("SHA-256").digest((user) + .getBytes(StandardCharsets.UTF_8))) + .substring(0, 32) + .toCharArray(); + } catch (NoSuchAlgorithmException e) { + throw new AssertionError(e); + } + } // The last char cannot be a number, otherwise, keyForUser() // believes it's a sign of kvno pass[31] = 'Z'; @@ -629,7 +655,7 @@ public class KDC { */ private static EncryptionKey generateRandomKey(int eType) throws KrbException { - return genKey0(randomPassword(), "NOTHING", null, eType, null); + return genKey0(randomPassword(null), "NOTHING", null, eType, null); } /** @@ -790,7 +816,7 @@ public class KDC { service.getNameStrings(), service.getRealm()); } try { - System.out.println(realm + "> " + tgsReq.reqBody.cname + + log(tgsReq.reqBody.cname + " sends TGS-REQ for " + service + ", " + tgsReq.reqBody.kdcOptions); KDCReqBody body = tgsReq.reqBody; @@ -810,7 +836,7 @@ public class KDC { boolean allowForwardable = true; boolean isReferral = false; if (body.kdcOptions.get(KDCOptions.CANONICALIZE)) { - System.out.println(realm + "> verifying referral for " + + log("verifying referral for " + body.sname.getNameString()); KDC referral = aliasReferrals.get(body.sname.getNameString()); if (referral != null) { @@ -819,7 +845,7 @@ public class KDC { PrincipalName.NAME_COMPONENT_SEPARATOR_STR + referral.getRealm(), PrincipalName.KRB_NT_SRV_INST, this.getRealm()); - System.out.println(realm + "> referral to " + + log("referral to " + referral.getRealm()); isReferral = true; } @@ -842,14 +868,14 @@ public class KDC { // Finally, cname will be overwritten by PA-FOR-USER // if it exists. cname = etp.cname; - System.out.println(realm + "> presenting a ticket of " + log("presenting a ticket of " + etp.cname + " to " + tkt.sname); } else if (pa.getType() == Krb5.PA_FOR_USER) { if (options.containsKey(Option.ALLOW_S4U2SELF)) { PAForUserEnc p4u = new PAForUserEnc( new DerValue(pa.getValue()), null); forUserCName = p4u.name; - System.out.println(realm + "> See PA_FOR_USER " + log("See PA_FOR_USER " + " in the name of " + p4u.name); } } @@ -862,6 +888,9 @@ public class KDC { // allowed to send S4U2self, do not send an error. // Instead, send a ticket which is useless later. allowForwardable = false; + } else if (options.get(Option.S4U2SELF_NOT_FORWARDABLE) == Boolean.TRUE) { + // Requsted not forwardable + allowForwardable = false; } cname = forUserCName; } @@ -936,15 +965,16 @@ public class KDC { DerInputStream derIn = new DerInputStream(bb); DerValue der = derIn.getDerValue(); EncTicketPart tktEncPart = new EncTicketPart(der.toByteArray()); - if (!tktEncPart.flags.get(Krb5.TKT_OPTS_FORWARDABLE)) { - //throw new KrbException(Krb5.KDC_ERR_BADOPTION); + if (!tktEncPart.flags.get(Krb5.TKT_OPTS_FORWARDABLE) + && options.get(Option.S4U2SELF_ALLOW_NOT_FORWARDABLE) != Boolean.TRUE) { + throw new KrbException(Krb5.KDC_ERR_BADOPTION); } PrincipalName client = tktEncPart.cname; - System.out.println(realm + "> and an additional ticket of " + log("and an additional ticket of " + client + " to " + second.sname); if (map.containsKey(cname.toString())) { if (map.get(cname.toString()).contains(service.toString())) { - System.out.println(realm + "> S4U2proxy OK"); + log("S4U2proxy OK"); } else { throw new KrbException(Krb5.KDC_ERR_BADOPTION); } @@ -1066,7 +1096,7 @@ public class KDC { Realm.getDefault()); } try { - System.out.println(realm + "> " + asReq.reqBody.cname + + log(asReq.reqBody.cname + " sends AS-REQ for " + service + ", " + asReq.reqBody.kdcOptions); @@ -1601,6 +1631,10 @@ public class KDC { return udpConsumerReady && tcpConsumerReady && dispatcherReady; } + void log(String s) { + System.out.println(realm + ":" + port + "> " + s); + } + public void terminate() { if (nativeKdc != null) { System.out.println("Killing kdc..."); diff --git a/test/jdk/sun/security/krb5/auto/S4U2selfNotF.java b/test/jdk/sun/security/krb5/auto/S4U2selfNotF.java new file mode 100644 index 0000000000000000000000000000000000000000..44cf1dd5eddb7f2e9ee2752aebf3c51b940c600a --- /dev/null +++ b/test/jdk/sun/security/krb5/auto/S4U2selfNotF.java @@ -0,0 +1,96 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8272162 + * @summary S4U2Self ticket without forwardable flag + * @library /test/lib + * @compile -XDignore.symbol.file S4U2selfNotF.java + * @run main jdk.test.lib.FileInstaller TestHosts TestHosts + * @run main/othervm -Djdk.net.hosts.file=TestHosts + * -Djdk.security.krb5.s4u2proxy.acceptNonForwardableServiceTicket=true + * S4U2selfNotF + */ + +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; +import java.util.Map; + +import jdk.test.lib.Asserts; +import sun.security.jgss.GSSUtil; +import sun.security.krb5.Config; + +public class S4U2selfNotF { + + public static void main(String[] args) throws Exception { + + // Create 2 KDCs that has almost the same settings + OneKDC[] kdcs = new OneKDC[2]; + boolean[] touched = new boolean[2]; + for (int i = 0; i < 2; i++) { + final int pos = i; + kdcs[i] = new OneKDC(null) { + protected byte[] processTgsReq(byte[] in) throws Exception { + touched[pos] = true; + return super.processTgsReq(in); + } + }; + kdcs[i].setOption(KDC.Option.ALLOW_S4U2SELF, + List.of(OneKDC.USER + "@" + OneKDC.REALM)); + kdcs[i].setOption(KDC.Option.ALLOW_S4U2PROXY, Map.of( + OneKDC.USER + "@" + OneKDC.REALM, + List.of(OneKDC.BACKEND + "@" + OneKDC.REALM))); + } + kdcs[0].writeJAASConf(); + + // except that the 1st issues a non-forwardable S4U2self + // ticket and only the 2nd accepts it + kdcs[0].setOption(KDC.Option.S4U2SELF_NOT_FORWARDABLE, true); + kdcs[1].setOption(KDC.Option.S4U2SELF_ALLOW_NOT_FORWARDABLE, true); + + Files.write(Path.of(OneKDC.KRB5_CONF), String.format(""" + [libdefaults] + default_realm = RABBIT.HOLE + forwardable = true + default_keytab_name = localkdc.ktab + + [realms] + RABBIT.HOLE = { + kdc = kdc.rabbit.hole:%d kdc.rabbit.hole:%d + } + """, kdcs[0].getPort(), kdcs[1].getPort()) + .getBytes(StandardCharsets.UTF_8)); + Config.refresh(); + + Context c = Context.fromJAAS("client"); + c = c.impersonate(OneKDC.USER2); + c.startAsClient(OneKDC.BACKEND, GSSUtil.GSS_KRB5_MECH_OID); + c.take(new byte[0]); + + Asserts.assertTrue(touched[0]); // get S4U2self from 1st one + Asserts.assertTrue(touched[1]); // get S4U2proxy from 2nd one + } +} diff --git a/test/jdk/sun/security/krb5/auto/tools/KtabSalt.java b/test/jdk/sun/security/krb5/auto/tools/KtabSalt.java new file mode 100644 index 0000000000000000000000000000000000000000..af504d5eab74cb81d12fdb5bda78c160ba04c539 --- /dev/null +++ b/test/jdk/sun/security/krb5/auto/tools/KtabSalt.java @@ -0,0 +1,78 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8279064 + * @summary New options for ktab to provide non-default salt + * @requires os.family == "windows" + * @library /test/lib + * @library /sun/security/krb5/auto + * @compile -XDignore.symbol.file KtabSalt.java + * @run main jdk.test.lib.FileInstaller ../TestHosts TestHosts + * @run main/othervm -Djdk.net.hosts.file=TestHosts KtabSalt + */ + +import jdk.test.lib.SecurityTools; +import jdk.test.lib.Utils; +import jdk.test.lib.process.OutputAnalyzer; + +import javax.security.auth.login.LoginException; + +public class KtabSalt { + + public static void main(String[] args) throws Exception { + + OneKDC kdc = new OneKDC(null).writeJAASConf(); + kdc.addPrincipal("u1", "password".toCharArray(), + "this_is_my_salt", null); + + // Using password works + Context.fromUserPass("u1", "password".toCharArray(), true); + + // Using KDC's keytab works + kdc.writeKtab("ktab0"); + Context.fromUserKtabAsClient("u1", "ktab0", true); + + // Self-created keytab with default salt does not work + ktab("-a u1 password -k ktab1"); + Utils.runAndCheckException( + () -> Context.fromUserKtabAsClient("u1", "ktab1", true), + LoginException.class); + + // Self-creating keytab with specified salt works + ktab("-a u1 password -s this_is_my_salt -k ktab2"); + Context.fromUserKtabAsClient("u1", "ktab2", true); + + // Self-creating keytab with salt from KDC works + ktab("-a u1 password -f -k ktab3"); + Context.fromUserKtabAsClient("u1", "ktab3", true); + } + + static OutputAnalyzer ktab(String cmdLine) throws Exception { + String fullCmdLine = String.format( + "-J-Djava.security.krb5.conf=%s -J-Djdk.net.hosts.file=TestHosts %s", + OneKDC.KRB5_CONF, cmdLine); + return SecurityTools.ktab(fullCmdLine).shouldHaveExitValue(0); + } +} diff --git a/test/jdk/sun/security/krb5/tools/KtabCheck.java b/test/jdk/sun/security/krb5/tools/KtabCheck.java index 8924b70ec93cdc07c48f640bde2eb599590349f3..3b9c42ebff1a4e14b8ab1b2e2fc4f5e844258e0d 100644 --- a/test/jdk/sun/security/krb5/tools/KtabCheck.java +++ b/test/jdk/sun/security/krb5/tools/KtabCheck.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 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 @@ -69,31 +69,31 @@ public class KtabCheck { check(3,17,3,18,3,19,4,17,4,18,4,19,5,17,5,18,5,19); ktab("-a me mine -n 6 -append"); check(3,17,3,18,3,19,4,17,4,18,4,19,5,17,5,18,5,19,6,17,6,18,6,19); - ktab("-d me 3"); + ktab("-d me -f 3"); check(4,17,4,18,4,19,5,17,5,18,5,19,6,17,6,18,6,19); - ktab("-d me -e 17 6"); + ktab("-d me -f -e 17 6"); check(4,17,4,18,4,19,5,17,5,18,5,19,6,18,6,19); - ktab("-d me -e 19 6"); + ktab("-d me -f -e 19 6"); check(4,17,4,18,4,19,5,17,5,18,5,19,6,18); - ktab("-d me -e 17 5"); + ktab("-d me -f -e 17 5"); check(4,17,4,18,4,19,5,18,5,19,6,18); - ktab("-d me old"); + ktab("-d me -f old"); check(4,17,5,19,6,18); try { - ktab("-d me old"); + ktab("-d me -f old"); throw new Exception("Should fail"); } catch (Exception e) { // no-op } check(4,17,5,19,6,18); - ktab("-d me"); + ktab("-d me -f"); check(); } static void ktab(String s) throws Exception { File conf = new File(System.getProperty("test.src"), "onlythree.conf"); SecurityTools.ktab("-J-Djava.security.krb5.conf=" + conf - + " -k " + KEYTAB + " -f " + s).shouldHaveExitValue(0); + + " -k " + KEYTAB + " " + s).shouldHaveExitValue(0); } /** diff --git a/test/jdk/sun/security/lib/CheckBlockedCerts.java b/test/jdk/sun/security/lib/CheckBlockedCerts.java index e5561bf15b82898721fde7f637473e7b723a6d99..5afbf4b610b9f58cb9f52422e1e1d3280a933391 100644 --- a/test/jdk/sun/security/lib/CheckBlockedCerts.java +++ b/test/jdk/sun/security/lib/CheckBlockedCerts.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -61,7 +61,7 @@ public class CheckBlockedCerts { // Assumes the full src is available File blockedCertsFile = new File(System.getProperty("test.src"), - "../../../../../make/data/blockedcertsconverter/blocked.certs.pem"); + "../../../../../src/java.base/share/data/blockedcertsconverter/blocked.certs.pem"); CertificateFactory cf = CertificateFactory.getInstance("X.509"); try (FileInputStream fis = new FileInputStream(blockedCertsFile)) { diff --git a/test/jdk/sun/security/lib/cacerts/VerifyCACerts.java b/test/jdk/sun/security/lib/cacerts/VerifyCACerts.java index 884384f2999f57e0e6053f67cbc7890c5f4a968b..00abee8919181623320063ef87f3fd3564421781 100644 --- a/test/jdk/sun/security/lib/cacerts/VerifyCACerts.java +++ b/test/jdk/sun/security/lib/cacerts/VerifyCACerts.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -264,6 +264,8 @@ public class VerifyCACerts { add("luxtrustglobalrootca [jdk]"); // Valid until: Wed Mar 17 11:33:33 PDT 2021 add("quovadisrootca [jdk]"); + // Valid until: Sat May 21 04:00:00 GMT 2022 + add("geotrustglobalca [jdk]"); } }; diff --git a/test/jdk/sun/security/pkcs11/Signature/LargeDSAKey.java b/test/jdk/sun/security/pkcs11/Signature/LargeDSAKey.java new file mode 100644 index 0000000000000000000000000000000000000000..a45a5ca47f544fefe11de334e9dede5dd2575c96 --- /dev/null +++ b/test/jdk/sun/security/pkcs11/Signature/LargeDSAKey.java @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2021, Red Hat, Inc. + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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.security.AlgorithmParameterGenerator; +import java.security.AlgorithmParameters; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.PrivateKey; +import java.security.Provider; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.Signature; +import java.security.spec.DSAGenParameterSpec; +import java.security.spec.DSAParameterSpec; + +/* + * @test + * @bug 8271566 + * @library /test/lib .. + * @modules jdk.crypto.cryptoki + * @run main/othervm/timeout=30 LargeDSAKey + */ + +public final class LargeDSAKey extends PKCS11Test { + + private static final boolean enableDebug = false; + + private static final String knownText = + "Known text known text known text"; + + @Override + public void main(Provider p) throws Exception { + KeyPairGenerator kpg = KeyPairGenerator.getInstance("DSA", p); + AlgorithmParameterGenerator dsaParGen = + AlgorithmParameterGenerator.getInstance("DSA"); + DSAGenParameterSpec dsaParGenSpec = + new DSAGenParameterSpec(2048, 256); + dsaParGen.init(dsaParGenSpec, new SecureRandom()); + AlgorithmParameters params = dsaParGen.generateParameters(); + DSAParameterSpec dsaParams = + params.getParameterSpec(DSAParameterSpec.class); + kpg.initialize(dsaParams); + KeyPair kp = kpg.generateKeyPair(); + doTestSignature(kp, p); + } + + private static void doTestSignature(KeyPair kp, Provider p) + throws Exception { + byte[] knownTextSig = null; + Signature s = Signature.getInstance("SHA1withDSA", p); + PrivateKey privKey = kp.getPrivate(); + PublicKey pubKey = kp.getPublic(); + if (enableDebug) { + System.out.println("Signature algorithm: " + s.getAlgorithm()); + System.out.println("Signature Provider: " + s.getProvider()); + System.out.println("Private key for signature: " + privKey); + System.out.println("Public key for signature: " + pubKey); + } + s.initSign(privKey); + s.update(knownText.getBytes()); + knownTextSig = s.sign(); + s.initVerify(pubKey); + s.update(knownText.getBytes()); + if (s.verify(knownTextSig) == false) { + throw new Exception("Could not verify signature"); + } + if (enableDebug) { + System.out.println("Signature verified"); + } + } + + public static void main(String[] args) throws Throwable { + main(new LargeDSAKey()); + System.out.println("TEST PASS - OK"); + } + +} diff --git a/test/jdk/sun/security/pkcs11/rsa/TestP11KeyFactoryGetRSAKeySpec.java b/test/jdk/sun/security/pkcs11/rsa/TestP11KeyFactoryGetRSAKeySpec.java index 07f07f788122dd3509cd9a0c3287830ff75bbc9a..2babc77e37a92ea55d3d5111bf66d216efa4d78d 100644 --- a/test/jdk/sun/security/pkcs11/rsa/TestP11KeyFactoryGetRSAKeySpec.java +++ b/test/jdk/sun/security/pkcs11/rsa/TestP11KeyFactoryGetRSAKeySpec.java @@ -1,6 +1,6 @@ /* * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2021, Amazon.com, Inc. 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 diff --git a/test/jdk/sun/security/pkcs12/EmptyPassword.java b/test/jdk/sun/security/pkcs12/EmptyPassword.java index 1f5e7ad457e84ac26cbb72b0f258cfa9eb8f943b..5e78003a4850f238bd9dfa4ed7c419be5bdcc1a9 100644 --- a/test/jdk/sun/security/pkcs12/EmptyPassword.java +++ b/test/jdk/sun/security/pkcs12/EmptyPassword.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -23,11 +23,11 @@ /* * @test - * @bug 8202299 + * @bug 8202299 8231107 * @modules java.base/sun.security.tools.keytool * java.base/sun.security.x509 * @library /test/lib - * @summary Java Keystore fails to load PKCS12/PFX certificates created in WindowsServer2016 + * @summary Testing empty (any of null, "", "\0") password behaviors */ import jdk.test.lib.Asserts; @@ -38,6 +38,7 @@ import java.io.File; import java.io.FileOutputStream; import java.security.KeyStore; import java.security.cert.Certificate; +import java.util.Arrays; public class EmptyPassword { @@ -52,13 +53,39 @@ public class EmptyPassword { new Certificate[] { gen.getSelfCertificate(new X500Name("CN=Me"), 100) }); - try (FileOutputStream fos = new FileOutputStream("p12")) { - ks.store(fos, new char[1]); - } + + // 8202299: interop between new char[0] and new char[1] + store(ks, "p12", new char[1]); // It can be loaded with password "". ks = KeyStore.getInstance(new File("p12"), new char[0]); Asserts.assertTrue(ks.getKey("a", new char[0]) != null); Asserts.assertTrue(ks.getCertificate("a") != null); + + ks = KeyStore.getInstance(new File("p12"), new char[1]); + Asserts.assertTrue(ks.getKey("a", new char[1]) != null); + Asserts.assertTrue(ks.getCertificate("a") != null); + + // 8231107: Store with null password makes it password-less + store(ks, "p00", null); + + // Can read cert and key with any password + for (char[] pass: new char[][] { + new char[0], // password actually used before 8202299 + new char[1], // the interoperability before 8202299 + null, // password-less after 8202299 + "whatever".toCharArray() + }) { + System.out.println("with password " + Arrays.toString(pass)); + ks = KeyStore.getInstance(new File("p00"), pass); + Asserts.assertTrue(ks.getKey("a", new char[1]) != null); + Asserts.assertTrue(ks.getCertificate("a") != null); + } + } + + static void store(KeyStore ks, String file, char[] pass) throws Exception { + try (FileOutputStream fos = new FileOutputStream(file)) { + ks.store(fos, pass); + } } } diff --git a/test/jdk/sun/security/pkcs12/GetAttributes.java b/test/jdk/sun/security/pkcs12/GetAttributes.java new file mode 100644 index 0000000000000000000000000000000000000000..6a4f37c97872086a84b9b78503ea13a742c717dc --- /dev/null +++ b/test/jdk/sun/security/pkcs12/GetAttributes.java @@ -0,0 +1,76 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8225181 + * @summary KeyStore should have a getAttributes method + * @library /test/lib + * @modules java.base/sun.security.tools.keytool + * java.base/sun.security.x509 + */ + +import jdk.test.lib.Asserts; +import sun.security.tools.keytool.CertAndKeyGen; +import sun.security.x509.X500Name; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.security.KeyStore; +import java.security.cert.Certificate; + +public class GetAttributes { + + static char[] pass = "changeit".toCharArray(); + + public static void main(String[] args) throws Exception { + + // Create a keystore with one private key entry and one cert entry + CertAndKeyGen cag = new CertAndKeyGen("EC", "SHA256withECDSA"); + KeyStore ks = KeyStore.getInstance("pkcs12"); + ks.load(null, null); + cag.generate("secp256r1"); + ks.setKeyEntry("a", cag.getPrivateKey(), pass, new Certificate[] { + cag.getSelfCertificate(new X500Name("CN=a"), 1000)} ); + cag.generate("secp256r1"); + ks.setCertificateEntry("b", + cag.getSelfCertificate(new X500Name("CN=b"), 1000)); + + // Test + check(ks); + + // Test newly loaded + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + ks.store(bos, pass); + KeyStore ks2 = KeyStore.getInstance("pkcs12"); + ks2.load(new ByteArrayInputStream(bos.toByteArray()), pass); + check(ks2); + } + + static void check(KeyStore ks) throws Exception { + var entry = ks.getEntry("a", new KeyStore.PasswordProtection(pass)); + Asserts.assertEQ(ks.getAttributes("a"), entry.getAttributes()); + entry = ks.getEntry("b", null); + Asserts.assertEQ(ks.getAttributes("b"), entry.getAttributes()); + } +} diff --git a/test/jdk/sun/security/pkcs12/KeytoolOpensslInteropTest.java b/test/jdk/sun/security/pkcs12/KeytoolOpensslInteropTest.java index da655c90a49ac07cb582548da42f864ce56972ed..c35bf47d56db1c8dfbc46794786cd3699d50d59b 100644 --- a/test/jdk/sun/security/pkcs12/KeytoolOpensslInteropTest.java +++ b/test/jdk/sun/security/pkcs12/KeytoolOpensslInteropTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -462,7 +462,7 @@ public class KeytoolOpensslInteropTest { "pkcs12", "-in", "ksnormal", "-passin", "pass:changeit", "-info", "-nokeys", "-nocerts"); output1.shouldHaveExitValue(0) - .shouldContain("MAC: sha256, Iteration 10000") + .shouldMatch("MAC:.*sha256.*Iteration 10000") .shouldContain("Shrouded Keybag: PBES2, PBKDF2, AES-256-CBC," + " Iteration 10000, PRF hmacWithSHA256") .shouldContain("PKCS7 Encrypted data: PBES2, PBKDF2, AES-256-CBC," @@ -505,7 +505,7 @@ public class KeytoolOpensslInteropTest { "ksnewic", "-passin", "pass:changeit", "-info", "-nokeys", "-nocerts"); output1.shouldHaveExitValue(0) - .shouldContain("MAC: sha256, Iteration 5555") + .shouldMatch("MAC:.*sha256.*Iteration 5555") .shouldContain("Shrouded Keybag: PBES2, PBKDF2, AES-256-CBC," + " Iteration 7777, PRF hmacWithSHA256") .shouldContain("Shrouded Keybag: pbeWithSHA1And128BitRC4," diff --git a/test/jdk/sun/security/provider/KeyStore/DksWithEmptyKeystore.java b/test/jdk/sun/security/provider/KeyStore/DksWithEmptyKeystore.java new file mode 100644 index 0000000000000000000000000000000000000000..050c470a3d07519b85d1e53145d881defb3c8a8b --- /dev/null +++ b/test/jdk/sun/security/provider/KeyStore/DksWithEmptyKeystore.java @@ -0,0 +1,125 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8265765 + * @summary Test DomainKeyStore with a collection of keystores that has an empty one in between + * based on the test in the bug report + */ + +import java.io.OutputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.security.DomainLoadStoreParameter; +import java.security.KeyStore; +import java.util.Enumeration; +import java.util.LinkedHashMap; +import java.util.Map; +import javax.crypto.KeyGenerator; + +public class DksWithEmptyKeystore { + private static void write(Path p, KeyStore keystore) throws Exception { + try (OutputStream outputStream = Files.newOutputStream(p)) { + keystore.store(outputStream, new char[] { 'x' }); + } + } + + public static void main(String[] args) throws Exception { + KeyGenerator kg = KeyGenerator.getInstance("AES"); + kg.init(256); + + // Create a keystore with one key + KeyStore nonEmptyKeystore = KeyStore.getInstance("PKCS12"); + nonEmptyKeystore.load(null, null); + + Path nonEmptyPath = Path.of("non_empty.p12"); + nonEmptyKeystore.setKeyEntry("aeskey", kg.generateKey(), new char[] { 'a' }, null); + write(nonEmptyPath, nonEmptyKeystore); + + // Create an empty keystore + KeyStore emptyKeystore = KeyStore.getInstance("PKCS12"); + emptyKeystore.load(null, null); + + Path emptyPath = Path.of("empty.p12"); + write(emptyPath, emptyKeystore); + + // Create a domain keystore with two non-empty keystores + Path dksWithTwoPartsPath = Path.of("two-parts.dks"); + var twoPartsConfiguration = """ + domain Combo { + keystore a keystoreURI="%s"; + keystore b keystoreURI="%s"; + }; + """; + Files.writeString(dksWithTwoPartsPath, String.format(twoPartsConfiguration, + nonEmptyPath.toUri(), nonEmptyPath.toUri())); + Map<String,KeyStore.ProtectionParameter> protectionParameters = new LinkedHashMap<>(); + + KeyStore dksKeystore = KeyStore.getInstance("DKS"); + dksKeystore.load(new DomainLoadStoreParameter(dksWithTwoPartsPath.toUri(), protectionParameters)); + System.out.printf("%s size: %d%n", dksWithTwoPartsPath, dksKeystore.size()); + + int index = 0; + for (Enumeration<String> enumeration = dksKeystore.aliases(); enumeration.hasMoreElements(); ) { + System.out.printf("%d: %s%n", index, enumeration.nextElement()); + index++; + } + + System.out.printf("enumerated aliases from %s: %d%n", dksWithTwoPartsPath, index); + if (index != dksKeystore.size()) { + throw new Exception("Failed to get the number of aliases in the domain keystore " + + "that has two keystores."); + } + + // Create a domain keystore with two non-empty keystores and an empty one in between + Path dksWithThreePartsPath = Path.of("three-parts.dks"); + var threePartsConfiguration = """ + domain Combo { + keystore a keystoreURI="%s"; + keystore b keystoreURI="%s"; + keystore c keystoreURI="%s"; + }; + """; + Files.writeString(dksWithThreePartsPath, String.format(threePartsConfiguration, + nonEmptyPath.toUri(), emptyPath.toUri(), nonEmptyPath.toUri())); + + KeyStore dksKeystore1 = KeyStore.getInstance("DKS"); + dksKeystore1.load(new DomainLoadStoreParameter(dksWithThreePartsPath.toUri(), protectionParameters)); + System.out.printf("%s size: %d%n", dksWithThreePartsPath, dksKeystore1.size()); + + index = 0; + for (Enumeration<String> enumeration = dksKeystore1.aliases(); enumeration.hasMoreElements(); ) { + System.out.printf("%d: %s%n", index, enumeration.nextElement()); + index++; + } + + System.out.printf("enumerated aliases from %s: %d%n", dksWithThreePartsPath, index); + if (index != dksKeystore1.size()) { + throw new Exception("Failed to get the number of aliases in the domain keystore " + + "that has three keystores with an empty one in between."); + } else { + System.out.printf("Test completed successfully"); + } + } +} diff --git a/test/jdk/sun/security/provider/PolicyParser/PrincipalExpansionError.java b/test/jdk/sun/security/provider/PolicyParser/PrincipalExpansionError.java index 8379fce402455bc376983285488c7fa09c386836..54eabc3a228737e5f1d3b6ae3ac1fbb7b0403eb4 100644 --- a/test/jdk/sun/security/provider/PolicyParser/PrincipalExpansionError.java +++ b/test/jdk/sun/security/provider/PolicyParser/PrincipalExpansionError.java @@ -110,7 +110,7 @@ public class PrincipalExpansionError { ("PrincipalExpansionError test failed (file not found)"); java.io.FileNotFoundException fnfe = (java.io.FileNotFoundException)e; - throw new SecurityException("PrincipalExpansionError" + + throw new SecurityException("PrincipalExpansionError " + "test failed (file not found)"); } else { // i don't know??? diff --git a/test/jdk/sun/security/provider/certpath/DisabledAlgorithms/CPBuilder.java b/test/jdk/sun/security/provider/certpath/DisabledAlgorithms/CPBuilder.java index 3edf02d70d7caa1412201b8ec007a6c8f1cdba49..0037ac7bad64f95b78e4451195820c05d003424e 100644 --- a/test/jdk/sun/security/provider/certpath/DisabledAlgorithms/CPBuilder.java +++ b/test/jdk/sun/security/provider/certpath/DisabledAlgorithms/CPBuilder.java @@ -348,7 +348,7 @@ public class CPBuilder { for (String key : certmap.keySet()) { String certStr = certmap.get(key); ByteArrayInputStream is = - new ByteArrayInputStream(certStr.getBytes());; + new ByteArrayInputStream(certStr.getBytes()); Certificate cert = cf.generateCertificate(is); entries.add(cert); } diff --git a/test/jdk/sun/security/provider/certpath/DisabledAlgorithms/CPBuilderWithMD5.java b/test/jdk/sun/security/provider/certpath/DisabledAlgorithms/CPBuilderWithMD5.java index e6a9765037bc9aa851b4186dbb636c219fce7914..9785b2702998e9ebb7b4ed18a9a3973ce3d879a2 100644 --- a/test/jdk/sun/security/provider/certpath/DisabledAlgorithms/CPBuilderWithMD5.java +++ b/test/jdk/sun/security/provider/certpath/DisabledAlgorithms/CPBuilderWithMD5.java @@ -353,7 +353,7 @@ public class CPBuilderWithMD5 { for (String key : certmap.keySet()) { String certStr = certmap.get(key); ByteArrayInputStream is = - new ByteArrayInputStream(certStr.getBytes());; + new ByteArrayInputStream(certStr.getBytes()); Certificate cert = cf.generateCertificate(is); entries.add(cert); } diff --git a/test/jdk/sun/security/ssl/CipherSuite/NoDesRC4CiphSuite.java b/test/jdk/sun/security/ssl/CipherSuite/NoDesRC4DesEdeCiphSuite.java similarity index 92% rename from test/jdk/sun/security/ssl/CipherSuite/NoDesRC4CiphSuite.java rename to test/jdk/sun/security/ssl/CipherSuite/NoDesRC4DesEdeCiphSuite.java index 22238d38e1d5ff05b20e8b5e9b463f258daa7760..c9861324237c16e333b9ce912d79a7ddf6ee3359 100644 --- a/test/jdk/sun/security/ssl/CipherSuite/NoDesRC4CiphSuite.java +++ b/test/jdk/sun/security/ssl/CipherSuite/NoDesRC4DesEdeCiphSuite.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -23,9 +23,9 @@ /* * @test - * @bug 8208350 - * @summary Disable all DES cipher suites - * @run main/othervm NoDesRC4CiphSuite + * @bug 8208350 8163327 + * @summary Disable all DES, RC4, and 3DES/DesEde cipher suites + * @run main/othervm NoDesRC4DesEdeCiphSuite */ /* @@ -43,7 +43,7 @@ import java.util.List; import java.util.ArrayList; import java.util.Arrays; -public class NoDesRC4CiphSuite { +public class NoDesRC4DesEdeCiphSuite { private static final boolean DEBUG = false; @@ -80,6 +80,18 @@ public class NoDesRC4CiphSuite { "SSL_RSA_EXPORT_WITH_RC4_40_MD5", "SSL_DH_anon_EXPORT_WITH_RC4_40_MD5" }; + private static final List<Integer> DESEDE_CS_LIST = Arrays.asList( + 0xC008, 0xC012, 0x0016, 0x0013, 0xC003, 0xC00D, 0x000A + ); + private static final String[] DESEDE_CS_LIST_NAMES = new String[] { + "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA", + "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA", + "SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA", + "SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA", + "TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA", + "TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA", + "SSL_RSA_WITH_3DES_EDE_CBC_SHA" + }; private static final ByteBuffer CLIOUTBUF = ByteBuffer.wrap("Client Side".getBytes()); @@ -99,6 +111,11 @@ public class NoDesRC4CiphSuite { allGood &= testEngAddDisabled(RC4_CS_LIST_NAMES, RC4_CS_LIST); allGood &= testEngOnlyDisabled(RC4_CS_LIST_NAMES); + // Disabled 3DES tests + allGood &= testDefaultCase(DESEDE_CS_LIST); + allGood &= testEngAddDisabled(DESEDE_CS_LIST_NAMES, DESEDE_CS_LIST); + allGood &= testEngOnlyDisabled(DESEDE_CS_LIST_NAMES); + if (allGood) { System.err.println("All tests passed"); } else { diff --git a/test/jdk/sun/security/ssl/InputRecord/ClientHelloRead.java b/test/jdk/sun/security/ssl/InputRecord/ClientHelloRead.java index e08230f325d59fcaa2554119548569ba214e20c3..06cba1091396954204ac1c2391fa7dd48acbef2f 100644 --- a/test/jdk/sun/security/ssl/InputRecord/ClientHelloRead.java +++ b/test/jdk/sun/security/ssl/InputRecord/ClientHelloRead.java @@ -32,12 +32,22 @@ * system properties in samevm/agentvm mode. */ -import java.io.*; -import java.net.*; +import java.io.BufferedReader; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.ServerSocket; +import java.net.URL; import java.security.KeyStore; -import javax.net.*; -import javax.net.ssl.*; -import java.security.cert.*; + +import javax.net.ServerSocketFactory; +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLException; +import javax.net.ssl.SSLServerSocketFactory; +import javax.net.ssl.SSLSession; /* * ClientHelloRead.java -- includes a simple server that can serve diff --git a/test/jdk/sun/security/ssl/SSLSocketImpl/ClientSocketCloseHang.java b/test/jdk/sun/security/ssl/SSLSocketImpl/ClientSocketCloseHang.java new file mode 100644 index 0000000000000000000000000000000000000000..249aab13291bdecad812fb2f5f14920a4bb5d8bb --- /dev/null +++ b/test/jdk/sun/security/ssl/SSLSocketImpl/ClientSocketCloseHang.java @@ -0,0 +1,134 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8274524 + * @summary 8274524: SSLSocket.close() hangs if it is called during the ssl handshake + * @library /javax/net/ssl/templates + * @run main/othervm ClientSocketCloseHang TLSv1.2 + * @run main/othervm ClientSocketCloseHang TLSv1.3 + */ + + +import javax.net.ssl.*; +import java.net.InetAddress; + +public class ClientSocketCloseHang implements SSLContextTemplate { + + public static void main(String[] args) throws Exception { + System.setProperty("jdk.tls.client.protocols", args[0]); + for (int i = 0; i<= 20; i++) { + System.err.println("==================================="); + System.err.println("loop " + i); + System.err.println("==================================="); + new ClientSocketCloseHang().test(); + } + } + + private void test() throws Exception { + SSLServerSocket listenSocket = null; + SSLSocket serverSocket = null; + ClientSocket clientSocket = null; + try { + SSLServerSocketFactory serversocketfactory = + createServerSSLContext().getServerSocketFactory(); + listenSocket = + (SSLServerSocket)serversocketfactory.createServerSocket(0); + listenSocket.setNeedClientAuth(false); + listenSocket.setEnableSessionCreation(true); + listenSocket.setUseClientMode(false); + + + System.err.println("Starting client"); + clientSocket = new ClientSocket(listenSocket.getLocalPort()); + clientSocket.start(); + + System.err.println("Accepting client requests"); + serverSocket = (SSLSocket) listenSocket.accept(); + + serverSocket.startHandshake(); + } finally { + if (clientSocket != null) { + clientSocket.close(); + } + if (listenSocket != null) { + listenSocket.close(); + } + + if (serverSocket != null) { + serverSocket.close(); + } + } + } + + private class ClientSocket extends Thread{ + int serverPort = 0; + SSLSocket clientSocket = null; + + public ClientSocket(int serverPort) { + this.serverPort = serverPort; + } + + @Override + public void run() { + try { + System.err.println( + "Connecting to server at port " + serverPort); + SSLSocketFactory sslSocketFactory = + createClientSSLContext().getSocketFactory(); + clientSocket = (SSLSocket)sslSocketFactory.createSocket( + InetAddress.getLocalHost(), serverPort); + clientSocket.setSoLinger(true, 3); + clientSocket.startHandshake(); + } catch (Exception e) { + } + } + + public void close() { + Thread t = new Thread() { + @Override + public void run() { + try { + if (clientSocket != null) { + clientSocket.close(); + } + } catch (Exception ex) { + } + } + }; + try { + // Close client connection + t.start(); + t.join(2000); // 2 sec + } catch (InterruptedException ex) { + return; + } + + if (t.isAlive()) { + throw new RuntimeException("SSL Client hangs on close"); + } + } + } +} + diff --git a/test/jdk/sun/security/ssl/SSLSocketImpl/SSLSocketShouldThrowSocketException.java b/test/jdk/sun/security/ssl/SSLSocketImpl/SSLSocketShouldThrowSocketException.java index 46cedd8f15ed868fe5b9f5773ff612efcfd43cec..410d0f46a88fed390ac6d9ceee019e0981e2ba1c 100644 --- a/test/jdk/sun/security/ssl/SSLSocketImpl/SSLSocketShouldThrowSocketException.java +++ b/test/jdk/sun/security/ssl/SSLSocketImpl/SSLSocketShouldThrowSocketException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Amazon 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 diff --git a/test/jdk/sun/security/ssl/X509KeyManager/NoGoodKey.java b/test/jdk/sun/security/ssl/X509KeyManager/NoGoodKey.java new file mode 100644 index 0000000000000000000000000000000000000000..71007010d8b83e13306a22f01c111bee7bd15552 --- /dev/null +++ b/test/jdk/sun/security/ssl/X509KeyManager/NoGoodKey.java @@ -0,0 +1,95 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8278560 + * @summary X509KeyManagerImpl::getAliases might return a good key with others + * @library /test/lib + * @modules java.base/sun.security.tools.keytool + * java.base/sun.security.util + * java.base/sun.security.x509 + */ +import jdk.test.lib.Asserts; +import sun.security.tools.keytool.CertAndKeyGen; +import sun.security.util.KnownOIDs; +import sun.security.util.ObjectIdentifier; +import sun.security.x509.CertificateExtensions; +import sun.security.x509.ExtendedKeyUsageExtension; +import sun.security.x509.X500Name; + +import java.io.*; +import java.security.*; +import java.security.cert.Certificate; +import java.util.Date; +import java.util.Vector; +import javax.net.ssl.*; + +public class NoGoodKey { + public static void main(String[] args) throws Exception { + + PrintStream oldErr = System.err; + ByteArrayOutputStream bout = new ByteArrayOutputStream(); + + CertificateExtensions exts = new CertificateExtensions(); + Vector<ObjectIdentifier> xku = new Vector<>(1); + xku.add(ObjectIdentifier.of(KnownOIDs.KP_TimeStamping)); + var ext = new ExtendedKeyUsageExtension(xku); + exts.set(ext.getId(), ext); + + KeyStore ks = KeyStore.getInstance("pkcs12"); + char[] pass = "password".toCharArray(); + ks.load(null, null); + + CertAndKeyGen ckg; + + // This is for the first keyType but wrong extendedKeyUsage + ckg = new CertAndKeyGen("EC", "SHA256withECDSA"); + ckg.generate("secp256r1"); + ks.setKeyEntry("a", ckg.getPrivateKey(), pass, new java.security.cert.Certificate[] + { ckg.getSelfCertificate(new X500Name("CN=user"), new Date(), 10000, exts) }); + + // This is for the 2nd keyType and is perfect + ckg = new CertAndKeyGen("RSA", "SHA256withRSA"); + ckg.generate(2048); + ks.setKeyEntry("b", ckg.getPrivateKey(), pass, new Certificate[] + { ckg.getSelfCertificate(new X500Name("CN=user"), 10000) }); + + try { + System.setProperty("javax.net.debug", "keymanager"); + System.setErr(new PrintStream(bout)); + var kmf = KeyManagerFactory.getInstance("NewSunX509"); + kmf.init(ks, pass); + var km = (X509ExtendedKeyManager) kmf.getKeyManagers()[0]; + + // b will be chosen anyway + Asserts.assertEQ(km.chooseClientAlias(new String[]{"EC", "RSA"}, null, null), "1.0.b"); + } finally { + System.setErr(oldErr); + } + + // make sure it's chosen as good matching key + String log = bout.toString(); + Asserts.assertFalse(log.contains("no good matching key found"), log); + } +} diff --git a/test/jdk/sun/security/ssl/X509TrustManagerImpl/CacertsLimit.java b/test/jdk/sun/security/ssl/X509TrustManagerImpl/CacertsLimit.java index e8a3871c5bb6819ce4d3e0e0fc6ff7791561d3e3..fc70b76735f7a25468038d2f1d3441f3b400e451 100644 --- a/test/jdk/sun/security/ssl/X509TrustManagerImpl/CacertsLimit.java +++ b/test/jdk/sun/security/ssl/X509TrustManagerImpl/CacertsLimit.java @@ -69,7 +69,7 @@ public class CacertsLimit { throw new Exception( "There are too many trusted CAs in cacerts. The " + "certificate_authorities extension cannot be used " + - "for TLS connections. Please rethink about the size" + + "for TLS connections. Please rethink about the size " + "of the cacerts, or have a release note for the " + "impacted behaviors"); } else if (sizeAccount > 0x4000) { diff --git a/test/jdk/sun/security/tools/jarsigner/AltProvider.java b/test/jdk/sun/security/tools/jarsigner/AltProvider.java index c359734b8c770c89339a1ef477a6f5ef76c052d3..d4a57ca55da7442d37c17f77ec190922a11ef7cc 100644 --- a/test/jdk/sun/security/tools/jarsigner/AltProvider.java +++ b/test/jdk/sun/security/tools/jarsigner/AltProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -23,7 +23,7 @@ /* * @test - * @bug 4906940 8130302 8194152 + * @bug 4906940 8130302 8194152 8281175 * @summary -providerPath, -providerClass, -addprovider, and -providerArg * @library /test/lib * @modules java.base/jdk.internal.misc @@ -81,33 +81,28 @@ public class AltProvider { // Without new provider testBoth("", 1, "DUMMYKS not found"); - // legacy use (-providerPath only supported by keytool) - testKeytool("-providerPath mods/test.dummy " + - "-providerClass org.test.dummy.DummyProvider -providerArg full", - 0, "loadProviderByClass: org.test.dummy.DummyProvider"); - // legacy, on classpath - testBoth("-J-cp -Jmods/test.dummy " + + testBoth("-providerpath mods/test.dummy " + "-providerClass org.test.dummy.DummyProvider -providerArg full", 0, "loadProviderByClass: org.test.dummy.DummyProvider"); // Wrong name - testBoth("-J-cp -Jmods/test.dummy " + + testBoth("-providerpath mods/test.dummy " + "-providerClass org.test.dummy.Dummy -providerArg full", 1, "Provider \"org.test.dummy.Dummy\" not found"); // Not a provider name - testBoth("-J-cp -Jmods/test.dummy " + + testBoth("-providerpath mods/test.dummy " + "-providerClass java.lang.Object -providerArg full", 1, "java.lang.Object not a provider"); // without arg - testBoth("-J-cp -Jmods/test.dummy " + + testBoth("-providerpath mods/test.dummy " + "-providerClass org.test.dummy.DummyProvider", 1, "DUMMYKS not found"); // old -provider still works - testBoth("-J-cp -Jmods/test.dummy " + + testBoth("-providerpath mods/test.dummy " + "-provider org.test.dummy.DummyProvider -providerArg full", 0, "loadProviderByClass: org.test.dummy.DummyProvider"); diff --git a/test/jdk/sun/security/tools/jarsigner/AutoKeyStore.java b/test/jdk/sun/security/tools/jarsigner/AutoKeyStore.java new file mode 100644 index 0000000000000000000000000000000000000000..971d9599b6c783b39b0aea07e4e6a78287b37361 --- /dev/null +++ b/test/jdk/sun/security/tools/jarsigner/AutoKeyStore.java @@ -0,0 +1,190 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8281234 + * @summary The -protected option is not always checked in keytool and jarsigner + * @library /test/lib + * @modules java.base/sun.security.tools.keytool + * java.base/sun.security.x509 + */ + +import jdk.test.lib.Asserts; +import jdk.test.lib.SecurityTools; +import jdk.test.lib.util.JarUtils; +import sun.security.tools.keytool.CertAndKeyGen; +import sun.security.x509.X500Name; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.security.*; +import java.security.cert.Certificate; +import java.security.cert.X509Certificate; +import java.util.Collections; +import java.util.Date; +import java.util.Enumeration; +import java.util.List; +import java.util.jar.JarFile; + +public class AutoKeyStore { + + public static void main(String[] args) throws Exception { + + JarUtils.createJarFile(Path.of("unsigned.jar"), Path.of("."), + Files.writeString(Path.of("file"), "hello")); + + SecurityTools.keytool(""" + -J--add-exports -Jjava.base/sun.security.tools.keytool=ALL-UNNAMED + -J--add-exports -Jjava.base/sun.security.x509=ALL-UNNAMED + -providerClass AutoKeyStore$AutoProvider + -providerPath $test.classes + -storetype AUTO -keystore NONE -protected + -list + """).shouldHaveExitValue(0) + .shouldContain("Keystore type: AUTO") + .shouldContain("Keystore provider: AUTO") + .shouldContain("PrivateKeyEntry"); + + SecurityTools.jarsigner(""" + -J--add-exports -Jjava.base/sun.security.tools.keytool=ALL-UNNAMED + -J--add-exports -Jjava.base/sun.security.x509=ALL-UNNAMED + -providerClass AutoKeyStore$AutoProvider + -providerPath $test.classes + -storetype AUTO -keystore NONE -protected + -signedJar signed.jar + unsigned.jar + one + """).shouldHaveExitValue(0) + .shouldContain("jar signed."); + + Asserts.assertTrue(new JarFile("signed.jar") + .getEntry("META-INF/ONE.EC") != null); + } + + public static class AutoProvider extends Provider { + public AutoProvider() { + super("AUTO", "1.1.1", "auto"); + put("KeyStore.AUTO", "AutoKeyStore$KeyStoreImpl"); + } + } + + // This keystore is not based on file. Whenever it's loaded + // a self-sign certificate is generated inside + public static class KeyStoreImpl extends KeyStoreSpi { + + private PrivateKey pri; + private PublicKey pub; + private X509Certificate cert; + + @Override + public Key engineGetKey(String alias, char[] password) { + return pri; + } + + @Override + public Certificate[] engineGetCertificateChain(String alias) { + return new Certificate[] { cert }; + } + + @Override + public Certificate engineGetCertificate(String alias) { + return cert; + } + + @Override + public Date engineGetCreationDate(String alias) { + return new Date(); + } + + @Override + public void engineSetKeyEntry(String alias, Key key, char[] password, Certificate[] chain) throws KeyStoreException { + throw new KeyStoreException("Not supported"); + } + + @Override + public void engineSetKeyEntry(String alias, byte[] key, Certificate[] chain) throws KeyStoreException { + throw new KeyStoreException("Not supported"); + } + + @Override + public void engineSetCertificateEntry(String alias, Certificate cert) throws KeyStoreException { + throw new KeyStoreException("Not supported"); + } + + @Override + public void engineDeleteEntry(String alias) throws KeyStoreException { + throw new KeyStoreException("Not supported"); + } + + @Override + public Enumeration<String> engineAliases() { + return Collections.enumeration(List.of("one")); + } + + @Override + public boolean engineContainsAlias(String alias) { + return alias.equalsIgnoreCase("one"); + } + + @Override + public int engineSize() { + return 1; + } + + @Override + public boolean engineIsKeyEntry(String alias) { + return true; + } + + @Override + public boolean engineIsCertificateEntry(String alias) { + return false; + } + + @Override + public String engineGetCertificateAlias(Certificate cert) { + return "one"; + } + + @Override + public void engineStore(OutputStream stream, char[] password) { + } + + @Override + public void engineLoad(InputStream stream, char[] password) throws IOException { + try { + CertAndKeyGen cag = new CertAndKeyGen("EC", "SHA256withECDSA"); + cag.generate("secp256r1"); + pri = cag.getPrivateKey(); + pub = cag.getPublicKey(); + cert = cag.getSelfCertificate(new X500Name("CN=one"), 3600); + } catch (Exception e) { + throw new IOException("Not loaded"); + } + } + } +} diff --git a/test/jdk/sun/security/tools/jarsigner/CheckAlgParams.java b/test/jdk/sun/security/tools/jarsigner/CheckAlgParams.java new file mode 100644 index 0000000000000000000000000000000000000000..d0a4338fee3b2d1f0299f21ce9c13725403251db --- /dev/null +++ b/test/jdk/sun/security/tools/jarsigner/CheckAlgParams.java @@ -0,0 +1,85 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8277474 + * @summary jarsigner -verify should check if the algorithm parameters of + * its signature algorithm use disabled or legacy algorithms + * @library /test/lib + */ + +import jdk.test.lib.SecurityTools; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.util.JarUtils; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +public class CheckAlgParams { + private static final String JAVA_SECURITY_FILE = "java.security"; + + public static void main(String[] args) throws Exception{ + + SecurityTools.keytool("-keystore ks -storepass changeit " + + "-genkeypair -keyalg RSASSA-PSS -alias ca -dname CN=CA " + + "-ext bc:c") + .shouldHaveExitValue(0); + + JarUtils.createJarFile(Path.of("a.jar"), Path.of("."), Path.of("ks")); + + SecurityTools.jarsigner("-keystore ks -storepass changeit " + + "-signedjar signeda.jar " + + "-verbose" + + " a.jar ca") + .shouldHaveExitValue(0); + + Files.writeString(Files.createFile(Paths.get(JAVA_SECURITY_FILE)), + "jdk.jar.disabledAlgorithms=SHA256\n" + + "jdk.security.legacyAlgorithms=\n"); + + SecurityTools.jarsigner("-verify signeda.jar " + + "-J-Djava.security.properties=" + + JAVA_SECURITY_FILE + + " -keystore ks -storepass changeit -verbose -debug") + .shouldMatch("Digest algorithm: SHA-256.*(disabled)") + .shouldMatch("Signature algorithm: RSASSA-PSS using PSSParameterSpec.*hashAlgorithm=SHA-256.*(disabled)") + .shouldContain("The jar will be treated as unsigned") + .shouldHaveExitValue(0); + + Files.deleteIfExists(Paths.get(JAVA_SECURITY_FILE)); + Files.writeString(Files.createFile(Paths.get(JAVA_SECURITY_FILE)), + "jdk.jar.disabledAlgorithms=\n" + + "jdk.security.legacyAlgorithms=SHA256\n"); + + SecurityTools.jarsigner("-verify signeda.jar " + + "-J-Djava.security.properties=" + + JAVA_SECURITY_FILE + + " -keystore ks -storepass changeit -verbose -debug") + .shouldMatch("Digest algorithm: SHA-256.*(weak)") + .shouldMatch("Signature algorithm: RSASSA-PSS using PSSParameterSpec.*hashAlgorithm=SHA-256.*(weak)") + .shouldNotContain("The jar will be treated as unsigned") + .shouldHaveExitValue(0); + } +} diff --git a/test/jdk/sun/security/tools/jarsigner/DisableCurveTest.java b/test/jdk/sun/security/tools/jarsigner/DisableCurveTest.java new file mode 100644 index 0000000000000000000000000000000000000000..9270899182c8702b04ef78d4e3d7486144c09f8f --- /dev/null +++ b/test/jdk/sun/security/tools/jarsigner/DisableCurveTest.java @@ -0,0 +1,100 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8282633 + * @summary jarsigner should display the named curve to better explain why + * an EC key is disabled or will be disabled. + * @library /test/lib + */ + +import jdk.test.lib.SecurityTools; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.util.JarUtils; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +public class DisableCurveTest { + private static final String JAVA_SECURITY_FILE = "java.security"; + + public static void main(String[] args) throws Exception{ + SecurityTools.keytool("-keystore ks -storepass changeit " + + "-genkeypair -keyalg EC -alias ca -dname CN=CA " + + "-ext bc:c") + .shouldHaveExitValue(0); + + JarUtils.createJarFile(Path.of("a.jar"), Path.of("."), Path.of("ks")); + + Files.writeString(Files.createFile(Paths.get(JAVA_SECURITY_FILE)), + "jdk.jar.disabledAlgorithms=secp256r1\n" + + "jdk.certpath.disabledAlgorithms=secp256r1\n"); + + SecurityTools.jarsigner("-keystore ks -storepass changeit " + + "-signedjar signeda.jar -verbose " + + "-J-Djava.security.properties=" + + JAVA_SECURITY_FILE + + " a.jar ca") + .shouldContain(">>> Signer") + .shouldContain("Signature algorithm: SHA256withECDSA, 256-bit EC (secp256r1) key (disabled)") + .shouldContain("Warning:") + .shouldContain("The EC (secp256r1) signing key has a keysize of 256 which is considered a security risk and is disabled") + .shouldHaveExitValue(0); + + SecurityTools.jarsigner("-verify signeda.jar " + + "-J-Djava.security.properties=" + + JAVA_SECURITY_FILE + + " -keystore ks -storepass changeit -verbose -debug") + .shouldContain("- Signed by") + .shouldContain("Signature algorithm: SHA256withECDSA, 256-bit EC (secp256r1) key (disabled)") + .shouldContain("WARNING: The jar will be treated as unsigned") + .shouldHaveExitValue(0); + + Files.deleteIfExists(Paths.get(JAVA_SECURITY_FILE)); + Files.writeString(Files.createFile(Paths.get(JAVA_SECURITY_FILE)), + "jdk.security.legacyAlgorithms=secp256r1\n"); + + SecurityTools.jarsigner("-keystore ks -storepass changeit " + + "-signedjar signeda.jar -verbose " + + "-J-Djava.security.properties=" + + JAVA_SECURITY_FILE + + " a.jar ca") + .shouldContain(">>> Signer") + .shouldContain("Signature algorithm: SHA256withECDSA, 256-bit EC (secp256r1) key (weak)") + .shouldContain("Warning:") + .shouldContain("The EC (secp256r1) signing key has a keysize of 256 which is considered a security risk. This key size will be disabled in a future update") + .shouldHaveExitValue(0); + + SecurityTools.jarsigner("-verify signeda.jar " + + "-J-Djava.security.properties=" + + JAVA_SECURITY_FILE + + " -keystore ks -storepass changeit -verbose -debug") + .shouldContain("- Signed by") + .shouldContain("Signature algorithm: SHA256withECDSA, 256-bit EC (secp256r1) key (weak)") + .shouldContain("jar verified") + .shouldContain("The EC (secp256r1) signing key has a keysize of 256 which is considered a security risk. This key size will be disabled in a future update") + .shouldHaveExitValue(0); + } +} diff --git a/test/jdk/sun/security/tools/jarsigner/TimestampCheck.java b/test/jdk/sun/security/tools/jarsigner/TimestampCheck.java index 9599e6ac066786c6e1aa309a184beb2e245e85db..e6794550b9097730f39a26c21750f0594ac78d68 100644 --- a/test/jdk/sun/security/tools/jarsigner/TimestampCheck.java +++ b/test/jdk/sun/security/tools/jarsigner/TimestampCheck.java @@ -55,7 +55,7 @@ import sun.security.timestamp.TimestampToken; /* * @test * @bug 6543842 6543440 6939248 8009636 8024302 8163304 8169911 8180289 8172404 - * 8247960 8242068 8269039 + * 8247960 8242068 8269039 8275887 * @summary checking response of timestamp * @modules java.base/sun.security.pkcs * java.base/sun.security.timestamp @@ -340,6 +340,7 @@ public class TimestampCheck { verify("tsdisabled2.jar", "-verbose") .shouldHaveExitValue(16) .shouldContain("treated as unsigned") + .shouldNotMatch("Signature.*(disabled)") .shouldMatch("Timestamp.*512.*(disabled)"); // Algorithm used in signing is disabled @@ -356,6 +357,8 @@ public class TimestampCheck { // sign with RSAkeysize < 1024 signVerbose("normal", "sign1.jar", "sign2.jar", "disabledkeysize") .shouldContain("Algorithm constraints check failed on keysize") + .shouldNotContain("option is considered a security " + + "risk and is disabled") .shouldHaveExitValue(4); checkMultiple("sign2.jar"); @@ -419,6 +422,17 @@ public class TimestampCheck { // sign with RSAkeysize < 2048 signVerbose("normal", "sign1.jar", "sign2.jar", "weakkeysize") .shouldNotContain("Algorithm constraints check failed on keysize") + .shouldNotContain("The SHA-256 algorithm specified " + + "for the -digestalg option is considered a " + + "security risk") + .shouldNotContain("The SHA256withRSA algorithm " + + "specified for the -sigalg option is considered " + + "a security risk") + .shouldNotContain("The SHA-256 algorithm specified " + + "for the -tsadigestalg option is considered a " + + "security risk") + .shouldContain("The RSA signing key has a keysize " + + "of 1024 which is considered a security risk") .shouldHaveExitValue(0); checkMultipleWeak("sign2.jar"); @@ -673,7 +687,7 @@ public class TimestampCheck { .shouldMatch("Timestamp signature algorithm: .*key.*(disabled)"); verify(file, "-J-Djava.security.debug=jar") .shouldHaveExitValue(16) - .shouldMatch("SignatureException:.*keysize"); + .shouldMatch("SignatureException:.*MD5"); // For 8171319: keytool should print out warnings when reading or // generating cert/cert req using disabled algorithms. @@ -845,7 +859,7 @@ public class TimestampCheck { gencert("weakkeysize"); gencert("disabledkeysize"); gencert("badku", "-ext ku:critical=keyAgreement"); - gencert("ts", "-ext eku:critical=ts -validity 500"); + gencert("ts", "-ext eku:critical=ts -ext ku=nonrep -validity 500"); gencert("expired", "-validity 10 -startdate -12d"); gencert("expiring", "-validity 178"); diff --git a/test/jdk/sun/security/tools/keytool/TestSha1Usage.java b/test/jdk/sun/security/tools/keytool/TestSha1Usage.java new file mode 100644 index 0000000000000000000000000000000000000000..0cbece46e147d4ad26c65d829b42a908461ea170 --- /dev/null +++ b/test/jdk/sun/security/tools/keytool/TestSha1Usage.java @@ -0,0 +1,60 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8273236 + * @summary Test SHA1 usage SignedJAR + * @library /test/lib + */ + +import jdk.test.lib.SecurityTools; +import jdk.test.lib.process.OutputAnalyzer; + +public class TestSha1Usage { + + static OutputAnalyzer kt(String cmd, String ks) throws Exception { + return SecurityTools.keytool("-storepass changeit " + cmd + + " -keystore " + ks); + } + + public static void main(String[] args) throws Exception { + + SecurityTools.keytool("-keystore ks -storepass changeit " + + "-genkeypair -keyalg rsa -alias ca -dname CN=CA " + + "-ext eku=codeSigning -sigalg SHA1withRSA") + .shouldContain("Warning:") + .shouldMatch("The generated certificate.*SHA1withRSA.*considered a security risk") + .shouldMatch("cannot be used to sign JARs") + .shouldHaveExitValue(0); + + kt("-genkeypair -keyalg rsa -alias e1 -dname CN=E1", "ks"); + kt("-certreq -alias e1 -file tmp.req", "ks"); + SecurityTools.keytool("-keystore ks -storepass changeit " + + "-gencert -alias ca -infile tmp.req -outfile tmp.cert") + .shouldContain("Warning:") + .shouldMatch("The issuer.*SHA1withRSA.*considered a security risk") + .shouldMatch("cannot be used to sign JARs") + .shouldHaveExitValue(0); + } +} diff --git a/test/jdk/sun/security/tools/keytool/fakegen/jdk.crypto.ec/sun/security/ec/ECKeyPairGenerator.java b/test/jdk/sun/security/tools/keytool/fakegen/jdk.crypto.ec/sun/security/ec/ECKeyPairGenerator.java index f688da1c63572cfdbeac5366d74d607799f8191c..50de12acf0671914eb90fbbcd42ee4ba42df51e8 100644 --- a/test/jdk/sun/security/tools/keytool/fakegen/jdk.crypto.ec/sun/security/ec/ECKeyPairGenerator.java +++ b/test/jdk/sun/security/tools/keytool/fakegen/jdk.crypto.ec/sun/security/ec/ECKeyPairGenerator.java @@ -71,7 +71,7 @@ public final class ECKeyPairGenerator extends KeyPairGeneratorSpi { break; default: throw new AssertionError("SunEC ECKeyPairGenerator" + - "has been patched. Key size " + keySize + + " has been patched. Key size " + keySize + " is not supported"); } ECParameterSpec ecParams = ECUtil.getECParameterSpec(null, keySize); diff --git a/test/jdk/sun/security/util/HostnameMatcher/NullHostnameCheck.java b/test/jdk/sun/security/util/HostnameChecker/NullHostnameCheck.java similarity index 100% rename from test/jdk/sun/security/util/HostnameMatcher/NullHostnameCheck.java rename to test/jdk/sun/security/util/HostnameChecker/NullHostnameCheck.java diff --git a/test/jdk/sun/security/util/HostnameMatcher/TestHostnameChecker.java b/test/jdk/sun/security/util/HostnameChecker/TestHostnameChecker.java similarity index 88% rename from test/jdk/sun/security/util/HostnameMatcher/TestHostnameChecker.java rename to test/jdk/sun/security/util/HostnameChecker/TestHostnameChecker.java index 8d50aa4c29592651755927ddd31a6655f892bbf3..d5c0898d8e658db20936855c1cf390dfffadbf1d 100644 --- a/test/jdk/sun/security/util/HostnameMatcher/TestHostnameChecker.java +++ b/test/jdk/sun/security/util/HostnameChecker/TestHostnameChecker.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 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 @@ -23,16 +23,19 @@ /* * @test - * @bug 4514108 - * @summary Verify host name matching behaves as defined in RFC2818. + * @bug 4514108 7192189 + * @summary Verify host name matching behaves as defined in RFC2818 and RFC6125. * @library /test/lib - * @modules java.base/sun.security.util + * @modules java.base/sun.security.util java.base/sun.security.x509 */ import java.security.cert.*; +import java.util.Collection; +import java.util.List; import jdk.test.lib.security.CertUtils; import sun.security.util.*; +import sun.security.x509.X509CertImpl; /** * Certificate 1: @@ -193,10 +196,17 @@ public class TestHostnameChecker { check(checker, "altfoo2.com", cert3, true); check(checker, "5.6.7.8", cert3, true); check(checker, "foo.bar.com", cert4, true); - check(checker, "altfoo.bar.com", cert4, true); + check(checker, "altfoo.bar.com", cert4, false); check(checker, "2001:db8:3c4d:15::1a2f:1a2b", cert5, true); check(checker, "2001:0db8:3c4d:0015:0000:0000:1a2f:1a2b", cert5, true); check(checker, "2002:db8:3c4d:15::1a2f:1a2b", cert5, false); + check(checker, "foo.bar.example.net", mock("foo.*.example.net"), false); + check(checker, "baz1.example.net", mock("baz*.example.net"), true); + check(checker, "foobaz.example.net", mock("*baz.example.net"), true); + check(checker, "buzz.example.net", mock("b*z.example.net"), true); + check(checker, "公司.example.net", mock("xn--5*.example.net"), false); + check(checker, "公司.江利子.example.net", + mock("*.xn--kcry6tjko.example.net"), true); checker = HostnameChecker.getInstance( HostnameChecker.TYPE_LDAP); @@ -214,6 +224,15 @@ public class TestHostnameChecker { check(checker, "altfoo.bar.com", cert4, false); } + private static X509Certificate mock(String domain) { + return new X509CertImpl() { + @Override + public Collection<List<?>> getSubjectAlternativeNames() { + return List.of(List.of(2, domain)); + } + }; + } + private static void check(HostnameChecker checker, String name, X509Certificate cert, boolean expectedResult) throws Exception { @@ -224,7 +243,7 @@ public class TestHostnameChecker { } } catch (CertificateException e) { if (expectedResult == true) { - throw e; + throw new Exception("Failed valid test: " + name, e); } } System.out.println("OK: " + name); diff --git a/test/jdk/sun/security/util/HostnameMatcher/cert1.crt b/test/jdk/sun/security/util/HostnameChecker/cert1.crt similarity index 100% rename from test/jdk/sun/security/util/HostnameMatcher/cert1.crt rename to test/jdk/sun/security/util/HostnameChecker/cert1.crt diff --git a/test/jdk/sun/security/util/HostnameMatcher/cert2.crt b/test/jdk/sun/security/util/HostnameChecker/cert2.crt similarity index 100% rename from test/jdk/sun/security/util/HostnameMatcher/cert2.crt rename to test/jdk/sun/security/util/HostnameChecker/cert2.crt diff --git a/test/jdk/sun/security/util/HostnameMatcher/cert3.crt b/test/jdk/sun/security/util/HostnameChecker/cert3.crt similarity index 100% rename from test/jdk/sun/security/util/HostnameMatcher/cert3.crt rename to test/jdk/sun/security/util/HostnameChecker/cert3.crt diff --git a/test/jdk/sun/security/util/HostnameMatcher/cert4.crt b/test/jdk/sun/security/util/HostnameChecker/cert4.crt similarity index 100% rename from test/jdk/sun/security/util/HostnameMatcher/cert4.crt rename to test/jdk/sun/security/util/HostnameChecker/cert4.crt diff --git a/test/jdk/sun/security/util/HostnameMatcher/cert5.crt b/test/jdk/sun/security/util/HostnameChecker/cert5.crt similarity index 100% rename from test/jdk/sun/security/util/HostnameMatcher/cert5.crt rename to test/jdk/sun/security/util/HostnameChecker/cert5.crt diff --git a/test/jdk/sun/security/util/Pem/encoding.sh b/test/jdk/sun/security/util/Pem/encoding.sh index 2bc39504218e81e884af8f8ac07feec565a9193d..7f8b142caf898d8b2f11b440c477c66f70f6a85e 100644 --- a/test/jdk/sun/security/util/Pem/encoding.sh +++ b/test/jdk/sun/security/util/Pem/encoding.sh @@ -1,5 +1,5 @@ # -# Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. +# 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 @@ -32,4 +32,4 @@ $TESTJAVA/bin/java $TESTVMOPTS -cp $TESTCLASSES \ -Dfile.encoding=UTF-16 \ - PemEncoding $TESTSRC/../HostnameMatcher/cert5.crt + PemEncoding $TESTSRC/../HostnameChecker/cert5.crt diff --git a/test/jdk/sun/security/util/RegisteredDomain/ParseNames.java b/test/jdk/sun/security/util/RegisteredDomain/ParseNames.java index 7b9433bbac9992bf91f9d57091e658c80ae2a481..69ca9577c687f4b89d6acb4f16a52d50716e391c 100644 --- a/test/jdk/sun/security/util/RegisteredDomain/ParseNames.java +++ b/test/jdk/sun/security/util/RegisteredDomain/ParseNames.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -23,7 +23,7 @@ /* * @test - * @bug 8228969 8244087 + * @bug 8228969 8244087 8255266 * @modules java.base/sun.security.util * @summary unit test for RegisteredDomain */ diff --git a/test/jdk/sun/security/util/RegisteredDomain/tests.dat b/test/jdk/sun/security/util/RegisteredDomain/tests.dat index da9fba064fb34d75bf6297dbb83c340db00e95b0..e4cf659c6341a0df41390888a78d8a73a3e44b17 100644 --- a/test/jdk/sun/security/util/RegisteredDomain/tests.dat +++ b/test/jdk/sun/security/util/RegisteredDomain/tests.dat @@ -56,6 +56,11 @@ biz biz null site.biz biz site.biz w.site.biz biz site.biz +# br +br br null +dev.br dev.br null +x.dev.br dev.br x.dev.br + # cn (unicode) # foo.mil.cn mil.cn foo.mil.cn diff --git a/test/jdk/sun/security/x509/AlgorithmId/NonStandardNames.java b/test/jdk/sun/security/x509/AlgorithmId/NonStandardNames.java index 7823b1eddfa7f0adc9ef91da1a827575530514f2..948cfa47064efa4b631de87218d714b7e29f8667 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, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -23,7 +23,7 @@ /* * @test - * @bug 7180907 + * @bug 7180907 8277224 * @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 @@ -60,8 +60,13 @@ public class NonStandardNames { PKCS9Attributes authed = new PKCS9Attributes(new PKCS9Attribute[]{ new PKCS9Attribute(PKCS9Attribute.CONTENT_TYPE_OID, ContentInfo.DATA_OID), new PKCS9Attribute(PKCS9Attribute.MESSAGE_DIGEST_OID, md.digest(data)), + new PKCS9Attribute(PKCS9Attribute.SIGNATURE_TIMESTAMP_TOKEN_OID, "test".getBytes()) }); + // test PKCS9Attributes.toString(), PKCS9Attributes.getAttributes() + System.out.println(authed); + authed.getAttributes(); + Signature s = Signature.getInstance("SHA256withRSA"); s.initSign(cakg.getPrivateKey()); s.update(authed.getDerEncoding()); diff --git a/test/jdk/sun/security/x509/OtherName/Parse.java b/test/jdk/sun/security/x509/OtherName/Parse.java new file mode 100644 index 0000000000000000000000000000000000000000..7db5ffe56d262126843db076447b263e3a2b3b71 --- /dev/null +++ b/test/jdk/sun/security/x509/OtherName/Parse.java @@ -0,0 +1,102 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8277976 + * @summary Break up SEQUENCE in X509Certificate::getSubjectAlternativeNames + * and X509Certificate::getIssuerAlternativeNames in otherName + * @modules java.base/sun.security.util + * java.base/sun.security.x509 + * java.base/sun.security.tools.keytool + * @library /test/lib + */ + +import jdk.test.lib.Asserts; +import sun.security.tools.keytool.CertAndKeyGen; +import sun.security.util.DerValue; +import sun.security.util.ObjectIdentifier; +import sun.security.x509.CertificateExtensions; +import sun.security.x509.DNSName; +import sun.security.x509.GeneralName; +import sun.security.x509.GeneralNames; +import sun.security.x509.OIDMap; +import sun.security.x509.OtherName; +import sun.security.x509.SubjectAlternativeNameExtension; +import sun.security.x509.X500Name; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.security.cert.X509Certificate; +import java.util.Arrays; +import java.util.Date; + +public class Parse { + + public static class MyDNSName extends DNSName { + public MyDNSName(byte[] in) throws IOException { + super(new String(Arrays.copyOfRange(in, 2, in.length), + StandardCharsets.US_ASCII)); + } + } + + public static void main(String[] args) throws Exception { + OIDMap.addAttribute("n1", "1.2.3.6", MyDNSName.class); + + CertificateExtensions exts = new CertificateExtensions(); + GeneralNames names = new GeneralNames(); + + byte[] d1 = new byte[] { + DerValue.tag_OctetString, 5, 'a', '.', 'c', 'o', 'm' }; + names.add(new GeneralName( + new OtherName(ObjectIdentifier.of("1.2.3.5"), d1))); + + byte[] d2 = new byte[] { + DerValue.tag_UTF8String, 5, 'a', '.', 'c', 'o', 'm' }; + names.add(new GeneralName( + new OtherName(ObjectIdentifier.of("1.2.3.6"), d2))); + + exts.set("x", new SubjectAlternativeNameExtension(names)); + CertAndKeyGen g = new CertAndKeyGen("Ed25519", "Ed25519"); + g.generate(-1); + X509Certificate x = g.getSelfCertificate(new X500Name("CN=ME"), + new Date(), + 100000, + exts); + + int found = 0; + for (var san : x.getSubjectAlternativeNames()) { + if (san.size() >= 4 && san.get(0).equals(0)) { + if (san.get(2).equals("1.2.3.5")) { + Asserts.assertTrue(Arrays.equals((byte[]) san.get(3), d1)); + found++; + } else if (san.get(2).equals("1.2.3.6")) { + Asserts.assertEQ(san.get(3), "a.com"); + found++; + } + } + } + Asserts.assertEQ(found, 2); + } +} + diff --git a/test/jdk/sun/text/resources/LocaleData b/test/jdk/sun/text/resources/LocaleData index ba1760978251d0e3a9fc17a9782eb8e3a6f5eff2..50fa417ae6d188dbea4ca5815fbb080a6d134f97 100644 --- a/test/jdk/sun/text/resources/LocaleData +++ b/test/jdk/sun/text/resources/LocaleData @@ -6448,6 +6448,7 @@ CurrencyNames//rsd=Serbian Dinar CurrencyNames//scr=Seychellois Rupee CurrencyNames//sdd=Sudanese Dinar (1992-2007) CurrencyNames//sit=Slovenian Tolar +CurrencyNames//sle=Sierra Leonean Leone CurrencyNames//sll=Sierra Leonean Leone CurrencyNames//srd=Surinamese Dollar CurrencyNames//srg=Surinamese Guilder diff --git a/test/jdk/sun/text/resources/LocaleDataTest.java b/test/jdk/sun/text/resources/LocaleDataTest.java index 1d2ddd03a8264dcb64977991913aaafb7fb779a6..51e88d72a2bdb348449dd9b037be28f279c12623 100644 --- a/test/jdk/sun/text/resources/LocaleDataTest.java +++ b/test/jdk/sun/text/resources/LocaleDataTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 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 @@ -40,7 +40,7 @@ * 8145136 8145952 8164784 8037111 8081643 7037368 8178872 8185841 8190918 * 8187946 8195478 8181157 8179071 8193552 8202026 8204269 8202537 8208746 * 8209775 8221432 8227127 8230284 8231273 8233579 8234288 8250665 8255086 - * 8251317 8274658 + * 8251317 8274658 8283277 * @summary Verify locale data * @modules java.base/sun.util.resources * @modules jdk.localedata diff --git a/test/jdk/sun/tools/jhsdb/BasicLauncherTest.java b/test/jdk/sun/tools/jhsdb/BasicLauncherTest.java index 401dfe6ca312e8f29c7f7d7553fe32235046cb56..d2ca78f044ac43920e6813dd6e684647f2ca3174 100644 --- a/test/jdk/sun/tools/jhsdb/BasicLauncherTest.java +++ b/test/jdk/sun/tools/jhsdb/BasicLauncherTest.java @@ -134,7 +134,7 @@ public class BasicLauncherTest { launcher.addToolArg("--pid=" + Long.toString(theApp.getPid())); ProcessBuilder processBuilder = SATestUtils.createProcessBuilder(launcher); - OutputAnalyzer output = ProcessTools.executeProcess(processBuilder);; + OutputAnalyzer output = ProcessTools.executeProcess(processBuilder); output.shouldContain("No deadlocks found"); output.shouldNotContain("illegal bci"); output.shouldNotContain("AssertionFailure"); @@ -171,7 +171,7 @@ public class BasicLauncherTest { ProcessBuilder processBuilder = SATestUtils.createProcessBuilder(launcher); processBuilder.redirectError(ProcessBuilder.Redirect.INHERIT); - OutputAnalyzer output = ProcessTools.executeProcess(processBuilder);; + OutputAnalyzer output = ProcessTools.executeProcess(processBuilder); output.shouldContain(expectedMessage); unexpectedMessage.ifPresent(output::shouldNotContain); output.shouldHaveExitValue(0); diff --git a/test/jdk/sun/tools/jhsdb/JShellHeapDumpTest.java b/test/jdk/sun/tools/jhsdb/JShellHeapDumpTest.java index 6c16ec2d29369caf9c5de71afaba1b1b2c96c3dd..5dee1b863dc70fc2ddad99e3694f17ad6667b0d8 100644 --- a/test/jdk/sun/tools/jhsdb/JShellHeapDumpTest.java +++ b/test/jdk/sun/tools/jhsdb/JShellHeapDumpTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -97,21 +97,33 @@ public class JShellHeapDumpTest { launch(expectedMessage, Arrays.asList(toolArgs)); } - public static void printStackTraces(String file) throws IOException { + /* Returns false if the attempt should be retried. */ + public static boolean printStackTraces(String file, boolean allowRetry) throws IOException { try { String output = HprofReader.getStack(file, 0); // We only require JShellToolProvider to be in the output if we did the // short sleep. If we did not, the java process may not have executed far // enough along to even start the main thread. if (doSleep && !output.contains("JShellToolProvider")) { - throw new RuntimeException("'JShellToolProvider' missing from stdout/stderr"); + // This check will very rarely fail due to not be able to get the stack trace + // of the main thread do to it actively executing. See JDK-8269556. We retry once + // if that happens. This failure is so rare that this should be enough to make it + // extremely unlikely that we ever see this test fail again for this reason. + if (!allowRetry) { + throw new RuntimeException("'JShellToolProvider' missing from stdout/stderr"); + } else { + System.out.println("'JShellToolProvider' missing. Allow one retry."); + return true; // Allow one retry + } } } catch (Exception ex) { throw new RuntimeException("Test ERROR " + ex, ex); } + return false; } - public static void testHeapDump() throws IOException { + /* Returns false if the attempt should be retried. */ + public static boolean testHeapDump(boolean allowRetry) throws IOException { File hprofFile = new File("jhsdb.jmap.heap." + System.currentTimeMillis() + ".hprof"); if (hprofFile.exists()) { @@ -124,10 +136,12 @@ public class JShellHeapDumpTest { assertTrue(hprofFile.exists() && hprofFile.isFile(), "Could not create dump file " + hprofFile.getAbsolutePath()); - printStackTraces(hprofFile.getAbsolutePath()); + boolean retry = printStackTraces(hprofFile.getAbsolutePath(), allowRetry); System.out.println("hprof file size: " + hprofFile.length()); hprofFile.delete(); + + return retry; } public static void launchJshell() throws IOException { @@ -149,7 +163,7 @@ public class JShellHeapDumpTest { // Give jshell a chance to fully start up. This makes SA more stable for the jmap dump. try { if (doSleep) { - Thread.sleep(2000); + Thread.sleep(4000); } } catch (Exception e) { } @@ -166,7 +180,12 @@ public class JShellHeapDumpTest { } else if (args.length != 0) { throw new RuntimeException("Too many args: " + args.length); } - testHeapDump(); + + boolean retry = testHeapDump(true); + // In case of rare failure to find 'JShellToolProvider' in the output, allow one retry. + if (retry) { + testHeapDump(false); + } // The test throws RuntimeException on error. // IOException is thrown if Jshell can't start because of some bad diff --git a/test/jdk/sun/tools/jstatd/JstatdTest.java b/test/jdk/sun/tools/jstatd/JstatdTest.java index c603ed1096c471fbb77d99639dd230c222867eb0..9eb1ccb3748cb7d781b93ac058eeb99b46469652 100644 --- a/test/jdk/sun/tools/jstatd/JstatdTest.java +++ b/test/jdk/sun/tools/jstatd/JstatdTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -43,7 +43,7 @@ import jdk.test.lib.thread.ProcessThread; * <pre> * {@code * // start jstatd process - * jstatd -J-XX:+UsePerfData -J-Djava.security.policy=all.policy + * jstatd -J-XX:+UsePerfData * * // run jps and verify its output * jps -J-XX:+UsePerfData hostname @@ -244,21 +244,16 @@ public final class JstatdTest { /** * Depending on test settings command line can look like: * - * jstatd -J-XX:+UsePerfData -J-Djava.security.policy=all.policy - * jstatd -J-XX:+UsePerfData -J-Djava.security.policy=all.policy -p port - * jstatd -J-XX:+UsePerfData -J-Djava.security.policy=all.policy -p port -r rmiport - * jstatd -J-XX:+UsePerfData -J-Djava.security.policy=all.policy -n serverName - * jstatd -J-XX:+UsePerfData -J-Djava.security.policy=all.policy -p port -n serverName + * jstatd -J-XX:+UsePerfData + * jstatd -J-XX:+UsePerfData -p port + * jstatd -J-XX:+UsePerfData -p port -r rmiport + * jstatd -J-XX:+UsePerfData -n serverName + * jstatd -J-XX:+UsePerfData -p port -n serverName */ private String[] getJstatdCmd() throws Exception { JDKToolLauncher launcher = JDKToolLauncher.createUsingTestJDK("jstatd"); launcher.addVMArg("-XX:+UsePerfData"); - launcher.addVMArg("-Djava.security.manager=allow"); String testSrc = System.getProperty("test.src"); - File policy = new File(testSrc, "all.policy"); - assertTrue(policy.exists() && policy.isFile(), - "Security policy " + policy.getAbsolutePath() + " does not exist or not a file"); - launcher.addVMArg("-Djava.security.policy=" + policy.getAbsolutePath()); if (port != null) { addToolArg(launcher,"-p", port); } diff --git a/test/jdk/sun/tools/jstatd/all.policy b/test/jdk/sun/tools/jstatd/all.policy deleted file mode 100644 index e202e4e91b6c49790ef9b726e7cf9ef7eee18fb8..0000000000000000000000000000000000000000 --- a/test/jdk/sun/tools/jstatd/all.policy +++ /dev/null @@ -1,3 +0,0 @@ -grant { - permission java.security.AllPermission; -}; diff --git a/test/jdk/sun/util/calendar/zi/TestZoneInfo310.java b/test/jdk/sun/util/calendar/zi/TestZoneInfo310.java index 7b50c342a0d3c1943ca5b57b9495dbdd55db13a1..ef6405860f5b1c534789acf43e6fe2206844b3ae 100644 --- a/test/jdk/sun/util/calendar/zi/TestZoneInfo310.java +++ b/test/jdk/sun/util/calendar/zi/TestZoneInfo310.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -47,7 +47,7 @@ public class TestZoneInfo310 { String TESTDIR = System.getProperty("test.dir", "."); Path tzdir = Paths.get(System.getProperty("test.root"), - "..", "..", "make", "data", "tzdata"); + "../../src/java.base/share/data/tzdata"); String tzfiles = "africa antarctica asia australasia europe northamerica southamerica backward etcetera gmt"; Path jdk_tzdir = Paths.get(System.getProperty("test.src"), "tzdata_jdk"); String jdk_tzfiles = "jdk11_backward"; diff --git a/test/jdk/sun/util/resources/TimeZone/ChineseTimeZoneNameTest.java b/test/jdk/sun/util/resources/TimeZone/ChineseTimeZoneNameTest.java new file mode 100644 index 0000000000000000000000000000000000000000..c752ec4d63c2591263a2937f1b0d14fed2283553 --- /dev/null +++ b/test/jdk/sun/util/resources/TimeZone/ChineseTimeZoneNameTest.java @@ -0,0 +1,72 @@ +/* + * 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. + */ + + /* + * @test + * @bug 8275721 + * @modules jdk.localedata + * @summary Checks Chinese time zone names for `UTC` using CLDR are consistent + * @run testng/othervm -Djava.locale.providers=CLDR,COMPAT ChineseTimeZoneNameTest + * @run testng/othervm -Djava.locale.providers=CLDR ChineseTimeZoneNameTest + */ + +import java.time.Instant; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.util.Locale; + +import static org.testng.Assert.assertEquals; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +@Test +public class ChineseTimeZoneNameTest { + + private static final Locale SIMPLIFIED_CHINESE = Locale.forLanguageTag("zh-Hans"); + private static final Locale TRADITIONAL_CHINESE = Locale.forLanguageTag("zh-Hant"); + private static final ZonedDateTime EPOCH_UTC = + ZonedDateTime.ofInstant(Instant.ofEpochSecond (0), ZoneId.of ("UTC")); + + @DataProvider(name="locales") + Object[][] data() { + return new Object[][] { + {Locale.CHINESE, SIMPLIFIED_CHINESE}, + {Locale.SIMPLIFIED_CHINESE, SIMPLIFIED_CHINESE}, + {Locale.forLanguageTag("zh-SG"), SIMPLIFIED_CHINESE}, + {Locale.forLanguageTag("zh-Hans-TW"), SIMPLIFIED_CHINESE}, + {Locale.forLanguageTag("zh-HK"), TRADITIONAL_CHINESE}, + {Locale.forLanguageTag("zh-MO"), TRADITIONAL_CHINESE}, + {Locale.TRADITIONAL_CHINESE, TRADITIONAL_CHINESE}, + {Locale.forLanguageTag("zh-Hant-CN"), TRADITIONAL_CHINESE}, + }; + } + + @Test(dataProvider="locales") + public void test_ChineseTimeZoneNames(Locale testLoc, Locale resourceLoc) { + assertEquals(DateTimeFormatter.ofPattern("z", testLoc).format(EPOCH_UTC), + DateTimeFormatter.ofPattern("z", resourceLoc).format(EPOCH_UTC)); + assertEquals(DateTimeFormatter.ofPattern("zzzz", testLoc).format(EPOCH_UTC), + DateTimeFormatter.ofPattern("zzzz", resourceLoc).format(EPOCH_UTC)); + } +} diff --git a/test/jdk/tools/jar/ContentOrder.java b/test/jdk/tools/jar/ContentOrder.java new file mode 100644 index 0000000000000000000000000000000000000000..dc5315efde1be23276f52b6cfefd107ce4149e99 --- /dev/null +++ b/test/jdk/tools/jar/ContentOrder.java @@ -0,0 +1,214 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8276764 + * @summary test that the jar content ordering is sorted + * @library /test/lib + * @modules jdk.jartool + * @build jdk.test.lib.Platform + * jdk.test.lib.util.FileUtils + * @run testng ContentOrder + */ + +import org.testng.Assert; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.io.UncheckedIOException; +import java.io.File; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.spi.ToolProvider; +import java.util.stream.Stream; +import java.util.zip.ZipException; + +import jdk.test.lib.util.FileUtils; + +public class ContentOrder { + 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); + private Runnable onCompletion; + + @BeforeMethod + public void reset() { + onCompletion = null; + } + + @AfterMethod + public void run() { + if (onCompletion != null) { + onCompletion.run(); + } + } + + // Test that the jar content ordering when processing a single directory is sorted + @Test + public void testSingleDir() throws IOException { + mkdir("testjar/Ctest1", "testjar/Btest2/subdir1", "testjar/Atest3"); + touch("testjar/Ctest1/testfile1", "testjar/Ctest1/testfile2", "testjar/Ctest1/testfile3"); + touch("testjar/Btest2/subdir1/testfileC", "testjar/Btest2/subdir1/testfileB", "testjar/Btest2/subdir1/testfileA"); + touch("testjar/Atest3/fileZ", "testjar/Atest3/fileY", "testjar/Atest3/fileX"); + + onCompletion = () -> rm("test.jar", "testjar"); + + jar("cf test.jar testjar"); + jar("tf test.jar"); + System.out.println(new String(baos.toByteArray())); + String output = "META-INF/" + nl + + "META-INF/MANIFEST.MF" + nl + + "testjar/" + nl + + "testjar/Atest3/" + nl + + "testjar/Atest3/fileX" + nl + + "testjar/Atest3/fileY" + nl + + "testjar/Atest3/fileZ" + nl + + "testjar/Btest2/" + nl + + "testjar/Btest2/subdir1/" + nl + + "testjar/Btest2/subdir1/testfileA" + nl + + "testjar/Btest2/subdir1/testfileB" + nl + + "testjar/Btest2/subdir1/testfileC" + nl + + "testjar/Ctest1/" + nl + + "testjar/Ctest1/testfile1" + nl + + "testjar/Ctest1/testfile2" + nl + + "testjar/Ctest1/testfile3" + nl; + Assert.assertEquals(baos.toByteArray(), output.getBytes()); + } + + // Test that when specifying multiple directories or releases that the sort + // ordering is done on each directory and release, reserving the order of + // the directories/releases specified on the command line + @Test + public void testMultiDirWithReleases() throws IOException { + mkdir("testjar/foo/classes", + "testjar/foo11/classes/Zclasses", + "testjar/foo11/classes/Yclasses", + "testjar/foo17/classes/Bclasses", + "testjar/foo17/classes/Aclasses"); + touch("testjar/foo/classes/testfile1", "testjar/foo/classes/testfile2"); + touch("testjar/foo11/classes/Zclasses/testfile1", "testjar/foo11/classes/Zclasses/testfile2"); + touch("testjar/foo11/classes/Yclasses/testfileA", "testjar/foo11/classes/Yclasses/testfileB"); + touch("testjar/foo17/classes/Bclasses/testfile1", "testjar/foo17/classes/Bclasses/testfile2"); + touch("testjar/foo17/classes/Aclasses/testfileA", "testjar/foo17/classes/Aclasses/testfileB"); + + onCompletion = () -> rm("test.jar", "testjar"); + + jar("cf test.jar -C testjar/foo classes " + + "--release 17 -C testjar/foo17 classes/Bclasses -C testjar/foo17 classes/Aclasses " + + "--release 11 -C testjar/foo11 classes/Zclasses -C testjar/foo11 classes/Yclasses"); + jar("tf test.jar"); + System.out.println(new String(baos.toByteArray())); + String output = "META-INF/" + nl + + "META-INF/MANIFEST.MF" + nl + + "classes/" + nl + + "classes/testfile1" + nl + + "classes/testfile2" + nl + + "META-INF/versions/17/classes/Bclasses/" + nl + + "META-INF/versions/17/classes/Bclasses/testfile1" + nl + + "META-INF/versions/17/classes/Bclasses/testfile2" + nl + + "META-INF/versions/17/classes/Aclasses/" + nl + + "META-INF/versions/17/classes/Aclasses/testfileA" + nl + + "META-INF/versions/17/classes/Aclasses/testfileB" + nl + + "META-INF/versions/11/classes/Zclasses/" + nl + + "META-INF/versions/11/classes/Zclasses/testfile1" + nl + + "META-INF/versions/11/classes/Zclasses/testfile2" + nl + + "META-INF/versions/11/classes/Yclasses/" + nl + + "META-INF/versions/11/classes/Yclasses/testfileA" + nl + + "META-INF/versions/11/classes/Yclasses/testfileB" + nl; + Assert.assertEquals(baos.toByteArray(), output.getBytes()); + } + + private Stream<Path> mkpath(String... args) { + return Arrays.stream(args).map(d -> Paths.get(".", d.split("/"))); + } + + private void mkdir(String... dirs) { + System.out.println("mkdir -p " + Arrays.toString(dirs)); + Arrays.stream(dirs).forEach(p -> { + try { + Files.createDirectories((new File(p)).toPath()); + } catch (IOException x) { + throw new UncheckedIOException(x); + } + }); + } + + private void touch(String... files) { + System.out.println("touch " + Arrays.toString(files)); + Arrays.stream(files).forEach(p -> { + try { + Files.createFile((new File(p)).toPath()); + } catch (IOException x) { + throw new UncheckedIOException(x); + } + }); + } + + private void rm(String... files) { + System.out.println("rm -rf " + Arrays.toString(files)); + Arrays.stream(files).forEach(p -> { + try { + Path path = (new File(p)).toPath(); + if (Files.isDirectory(path)) { + FileUtils.deleteFileTreeWithRetry(path); + } else { + FileUtils.deleteFileIfExistsWithRetry(path); + } + } catch (IOException x) { + throw new UncheckedIOException(x); + } + }); + } + + 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); + int rc = JAR_TOOL.run(out, err, cmdline.split(" +")); + System.setErr(saveErr); + if (rc != 0) { + String s = baes.toString(); + if (s.startsWith("java.util.zip.ZipException: duplicate entry: ")) { + throw new ZipException(s); + } + throw new IOException(s); + } + } +} diff --git a/test/jdk/tools/jar/CreateMissingParentDirectories.java b/test/jdk/tools/jar/CreateMissingParentDirectories.java new file mode 100644 index 0000000000000000000000000000000000000000..1f8fa4deb384c36f35f5a6f4cf5a905d4a74fc53 --- /dev/null +++ b/test/jdk/tools/jar/CreateMissingParentDirectories.java @@ -0,0 +1,117 @@ +/* + * 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. + */ + +/** + * @test + * @bug 8281104 + * @modules jdk.jartool + * @summary jar --create --file a/b/test.jar should create directories a/b + */ + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; +import java.util.spi.ToolProvider; +import java.util.stream.Stream; + +public class CreateMissingParentDirectories { + private static final ToolProvider JAR_TOOL = ToolProvider.findFirst("jar") + .orElseThrow(() -> + new RuntimeException("jar tool not found") + ); + + /** + * Remove dirs & files needed for test. + */ + private static void cleanup(Path dir) { + try { + if (Files.isDirectory(dir)) { + try (Stream<Path> s = Files.list(dir)) { + s.forEach(p -> cleanup(p)); + } + } + Files.delete(dir); + } catch (Exception x) { + fail(x.toString()); + } + } + + public static void realMain(String[] args) throws Throwable { + Path topDir = Files.createTempDirectory("delete"); + try { + Path entry = Files.writeString(topDir.resolve("test.txt"), "Some text..."); + + doHappyPathTest(topDir.resolve("test.jar"), entry); + doHappyPathTest(topDir.resolve("a/test.jar"), entry); + doHappyPathTest(topDir.resolve("a/b/test.jar"), entry); + + Path blocker = Files.writeString(topDir.resolve("blocker.txt"), "Blocked!"); + doFailingTest(topDir.resolve("blocker.txt/test.jar").toString(), entry); + } finally { + cleanup(topDir); + } + } + + private static void doHappyPathTest(Path jar, Path entry) throws Throwable { + String[] jarArgs = new String[]{"cf", jar.toString(), entry.toString()}; + if (JAR_TOOL.run(System.out, System.err, jarArgs) != 0) { + fail("Could not create jar file: " + List.of(jarArgs)); + return; + } + jarArgs = new String[]{"--create", "--file", jar.toString(), entry.toString()}; + if (JAR_TOOL.run(System.out, System.err, jarArgs) != 0) { + fail("Could not create jar file: " + List.of(jarArgs)); + return; + } + pass(); + } + + private static void doFailingTest(String jar, Path entry) throws Throwable { + StringWriter out = new StringWriter(); + StringWriter err = new StringWriter(); + String[] jarArgs = new String[]{"cf", jar, entry.toString()}; + + if (JAR_TOOL.run(new PrintWriter(out, true), new PrintWriter(err, true), jarArgs) == 0) { + fail("Should have failed creating jar file: " + jar); + return; + } + pass(); + } + + //--------------------- Infrastructure --------------------------- + static volatile int passed = 0, failed = 0; + static void pass() {passed++;} + static void fail() {failed++; Thread.dumpStack();} + static void fail(String msg) {System.out.println(msg); fail();} + static void unexpected(Throwable t) {failed++; t.printStackTrace();} + static void check(boolean cond) {if (cond) pass(); else fail();} + static void equal(Object x, Object y) { + if (x == null ? y == null : x.equals(y)) pass(); + else fail(x + " not equal to " + y);} + public static void main(String[] args) throws Throwable { + try {realMain(args);} catch (Throwable t) {unexpected(t);} + System.out.println("\nPassed = " + passed + " failed = " + failed); + if (failed > 0) throw new AssertionError("Some tests failed");} +} diff --git a/test/jdk/tools/jar/JarEntryTime.java b/test/jdk/tools/jar/JarEntryTime.java index 80fd65fba5c572cd9a2626f891f8782f9c377a7c..4d84547d07478c0f76daaa659eeb906b36b26e8e 100644 --- a/test/jdk/tools/jar/JarEntryTime.java +++ b/test/jdk/tools/jar/JarEntryTime.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 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 @@ -23,7 +23,7 @@ /** * @test - * @bug 4225317 6969651 + * @bug 4225317 6969651 8277422 * @modules jdk.jartool * @summary Check extracted files have date as per those in the .jar file */ @@ -31,6 +31,7 @@ import java.io.File; import java.io.PrintWriter; import java.nio.file.attribute.FileTime; +import java.time.ZoneId; import java.util.Date; import java.util.TimeZone; import java.util.spi.ToolProvider; @@ -93,6 +94,14 @@ public class JarEntryTime { jarFile.delete(); testFile.delete(); + var date = new Date(); + var defZone = ZoneId.systemDefault(); + if (defZone.getRules().getTransition( + date.toInstant().atZone(defZone).toLocalDateTime()) != null) { + System.out.println("At the offset transition. JarEntryTime test skipped."); + return; + } + /* Create a directory structure * outer/ * inner/ diff --git a/test/jdk/tools/jar/ReproducibleJar.java b/test/jdk/tools/jar/ReproducibleJar.java new file mode 100644 index 0000000000000000000000000000000000000000..ed5e2ed2ae3474af0dbde73cda80d9ba5bce2a53 --- /dev/null +++ b/test/jdk/tools/jar/ReproducibleJar.java @@ -0,0 +1,291 @@ +/* + * 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. + */ + +/* + * @test + * @requires vm.bits == 64 + * @bug 8276766 + * @summary Test jar --date source date of entries and that jars are + * reproducible + * @modules jdk.jartool + * @run testng/othervm ReproducibleJar + */ + +import org.testng.Assert; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; +import org.testng.annotations.DataProvider; + +import java.io.File; +import java.io.IOException; +import java.io.PrintWriter; +import java.nio.file.Files; +import java.nio.file.attribute.FileTime; +import java.util.Date; +import java.util.TimeZone; +import java.util.spi.ToolProvider; +import java.time.LocalDateTime; +import java.time.ZonedDateTime; +import java.time.ZoneId; +import java.time.ZoneOffset; +import java.time.format.DateTimeFormatter; +import java.time.Instant; +import java.util.concurrent.TimeUnit; + +public class ReproducibleJar { + private static final ToolProvider JAR_TOOL = ToolProvider.findFirst("jar") + .orElseThrow(() -> + new RuntimeException("jar tool not found") + ); + + // ZipEntry's mod date has 2 seconds precision: give extra time to + // allow for e.g. rounding/truncation and networked/samba drives. + private static final long PRECISION = 10000L; + + private static final TimeZone TZ = TimeZone.getDefault(); + private static final boolean DST = TZ.inDaylightTime(new Date()); + private static final String UNIX_2038_ROLLOVER_TIME = "2038-01-19T03:14:07Z"; + private static final Instant UNIX_2038_ROLLOVER = Instant.parse(UNIX_2038_ROLLOVER_TIME); + private static final File DIR_OUTER = new File("outer"); + private static final File DIR_INNER = new File(DIR_OUTER, "inner"); + private static final File FILE_INNER = new File(DIR_INNER, "foo.txt"); + private static final File JAR_FILE_SOURCE_DATE1 = new File("JarEntryTimeSourceDate1.jar"); + private static final File JAR_FILE_SOURCE_DATE2 = new File("JarEntryTimeSourceDate2.jar"); + + // Valid --date values for jar + @DataProvider + private Object[][] validSourceDates() { + return new Object[][]{ + {"1980-01-01T00:00:02+00:00"}, + {"1986-06-24T01:02:03+00:00"}, + {"2022-03-15T00:00:00+00:00"}, + {"2022-03-15T00:00:00+06:00"}, + {"2021-12-25T09:30:00-08:00[America/Los_Angeles]"}, + {"2021-12-31T23:59:59Z"}, + {"2024-06-08T14:24Z"}, + {"2026-09-24T16:26-05:00"}, + {"2038-11-26T06:06:06+00:00"}, + {"2098-02-18T00:00:00-08:00"}, + {"2099-12-31T23:59:59+00:00"} + }; + } + + // Invalid --date values for jar + @DataProvider + private Object[][] invalidSourceDates() { + return new Object[][]{ + {"1976-06-24T01:02:03+00:00"}, + {"1980-01-01T00:00:01+00:00"}, + {"2100-01-01T00:00:00+00:00"}, + {"2138-02-18T00:00:00-11:00"}, + {"2006-04-06T12:38:00"}, + {"2012-08-24T16"} + }; + } + + @BeforeMethod + public void runBefore() throws IOException { + runAfter(); + createOuterInnerDirs(); + } + + @AfterMethod + public void runAfter() { + cleanup(DIR_INNER); + cleanup(DIR_OUTER); + JAR_FILE_SOURCE_DATE1.delete(); + JAR_FILE_SOURCE_DATE2.delete(); + TimeZone.setDefault(TZ); + } + + /** + * Test jar tool with various valid --date <timestamps> + */ + @Test(dataProvider = "validSourceDates") + public void testValidSourceDate(String sourceDate) { + if (isInTransition()) return; + + // Test --date source date + Assert.assertEquals(JAR_TOOL.run(System.out, System.err, + "--create", + "--file", JAR_FILE_SOURCE_DATE1.getName(), + "--date", sourceDate, + DIR_OUTER.getName()), 0); + Assert.assertTrue(JAR_FILE_SOURCE_DATE1.exists()); + + // Extract JAR_FILE_SOURCE_DATE1 and check last modified values + Assert.assertEquals(JAR_TOOL.run(System.out, System.err, + "--extract", + "--file", JAR_FILE_SOURCE_DATE1.getName()), 0); + Assert.assertTrue(DIR_OUTER.exists()); + Assert.assertTrue(DIR_INNER.exists()); + Assert.assertTrue(FILE_INNER.exists()); + LocalDateTime expectedLdt = ZonedDateTime.parse(sourceDate, + DateTimeFormatter.ISO_DATE_TIME) + .withZoneSameInstant(ZoneOffset.UTC) + .toLocalDateTime(); + System.out.format("Checking jar entries local date time for --date %s, is %s%n", + sourceDate, expectedLdt); + long sourceDateEpochMillis = TimeUnit.MILLISECONDS.convert( + expectedLdt.toEpochSecond(ZoneId.systemDefault().getRules() + .getOffset(expectedLdt)), TimeUnit.SECONDS); + checkFileTime(DIR_OUTER.lastModified(), sourceDateEpochMillis); + checkFileTime(DIR_INNER.lastModified(), sourceDateEpochMillis); + checkFileTime(FILE_INNER.lastModified(), sourceDateEpochMillis); + } + + /** + * Test jar tool with various invalid --date <timestamps> + */ + @Test(dataProvider = "invalidSourceDates") + public void testInvalidSourceDate(String sourceDate) { + // Negative Tests --date out of range or wrong format source date + Assert.assertNotEquals(JAR_TOOL.run(System.out, System.err, + "--create", + "--file", JAR_FILE_SOURCE_DATE1.getName(), + "--date", sourceDate, + DIR_OUTER.getName()), 0); + } + + /** + * Test jar produces deterministic reproducible output + */ + @Test(dataProvider = "validSourceDates") + public void testJarsReproducible(String sourceDate) throws IOException { + // Test jars are reproducible across timezones + TimeZone tzAsia = TimeZone.getTimeZone("Asia/Shanghai"); + TimeZone tzLA = TimeZone.getTimeZone("America/Los_Angeles"); + TimeZone.setDefault(tzAsia); + Assert.assertEquals(JAR_TOOL.run(System.out, System.err, + "--create", + "--file", JAR_FILE_SOURCE_DATE1.getName(), + "--date", sourceDate, + DIR_OUTER.getName()), 0); + Assert.assertTrue(JAR_FILE_SOURCE_DATE1.exists()); + + try { + // Sleep 5 seconds to ensure jar timestamps might be different if they could be + Thread.sleep(5000); + } catch (InterruptedException ex) { + } + + TimeZone.setDefault(tzLA); + Assert.assertEquals(JAR_TOOL.run(System.out, System.err, + "--create", + "--file", JAR_FILE_SOURCE_DATE2.getName(), + "--date", sourceDate, + DIR_OUTER.getName()), 0); + Assert.assertTrue(JAR_FILE_SOURCE_DATE2.exists()); + + // Check jars are identical + Assert.assertEquals(Files.readAllBytes(JAR_FILE_SOURCE_DATE1.toPath()), + Files.readAllBytes(JAR_FILE_SOURCE_DATE2.toPath())); + } + + /** + * Create the standard directory structure used by the test: + * outer/ + * inner/ + * foo.txt + */ + static void createOuterInnerDirs() throws IOException { + Assert.assertTrue(DIR_OUTER.mkdir()); + Assert.assertTrue(DIR_INNER.mkdir()); + try (PrintWriter pw = new PrintWriter(FILE_INNER)) { + pw.println("hello, world"); + } + Assert.assertTrue(DIR_OUTER.exists()); + Assert.assertTrue(DIR_INNER.exists()); + Assert.assertTrue(FILE_INNER.exists()); + } + + /** + * Check the extracted and original millis since Epoch file times are + * within the zip precision time period. + */ + static void checkFileTime(long now, long original) { + if (isTimeSettingChanged()) { + return; + } + + if (Math.abs(now - original) > PRECISION) { + // If original time is after UNIX 2038 32bit rollover + // and the now time is exactly the rollover time, then assume + // running on a file system that only supports to 2038 (e.g.XFS) and pass test + if (FileTime.fromMillis(original).toInstant().isAfter(UNIX_2038_ROLLOVER) && + FileTime.fromMillis(now).toInstant().equals(UNIX_2038_ROLLOVER)) { + System.out.println("Checking file time after Unix 2038 rollover," + + " and extracted file time is " + UNIX_2038_ROLLOVER_TIME + ", " + + " Assuming restricted file system, pass file time check."); + } else { + throw new AssertionError("checkFileTime failed," + + " extracted to " + FileTime.fromMillis(now) + + ", expected to be close to " + FileTime.fromMillis(original)); + } + } + } + + /** + * Has the timezone or DST changed during the test? + */ + private static boolean isTimeSettingChanged() { + TimeZone currentTZ = TimeZone.getDefault(); + boolean currentDST = currentTZ.inDaylightTime(new Date()); + if (!currentTZ.equals(TZ) || currentDST != DST) { + System.out.println("Timezone or DST has changed during " + + "ReproducibleJar testcase execution. Test skipped"); + return true; + } else { + return false; + } + } + + /** + * Is the Zone currently within the transition change period? + */ + private static boolean isInTransition() { + var inTransition = false; + var date = new Date(); + var defZone = ZoneId.systemDefault(); + if (defZone.getRules().getTransition( + date.toInstant().atZone(defZone).toLocalDateTime()) != null) { + System.out.println("ReproducibleJar testcase being run during Zone offset transition. Test skipped."); + inTransition = true; + } + return inTransition; + } + + /** + * Remove the directory and its contents + */ + static void cleanup(File dir) { + File[] x = dir.listFiles(); + if (x != null) { + for (File f : x) { + f.delete(); + } + } + dir.delete(); + } +} diff --git a/test/jdk/tools/jar/modularJar/Basic.java b/test/jdk/tools/jar/modularJar/Basic.java index f6f95b632079797dcdd0d34e07b096c48ac7e584..177ae2a84534d5476f380ef1d1d927c1de6df6c6 100644 --- a/test/jdk/tools/jar/modularJar/Basic.java +++ b/test/jdk/tools/jar/modularJar/Basic.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -123,7 +123,7 @@ public class Basic { moduleName = mn; mainClass = mc; version = v; message = m; hashes = h; this.requires = requires != null ? requires : Collections.emptySet(); this.exports = exports != null ? exports : Collections.emptySet(); - this.uses = uses != null ? uses : Collections.emptySet();; + this.uses = uses != null ? uses : Collections.emptySet(); this.provides = provides != null ? provides : Collections.emptySet(); this.packages = Stream.concat(this.exports.stream(), contains.stream()) .collect(Collectors.toSet()); @@ -1093,9 +1093,6 @@ public class Basic { { List<String> commands = new ArrayList<>(); - if (!TOOL_VM_OPTIONS.isEmpty()) { - commands.addAll(Arrays.asList(TOOL_VM_OPTIONS.split("\\s+", -1))); - } commands.add("-d"); commands.add(dest.toString()); if (dest.toString().contains("bar")) { diff --git a/test/jdk/tools/jar/modularJar/JarToolModuleDescriptorReproducibilityTest.java b/test/jdk/tools/jar/modularJar/JarToolModuleDescriptorReproducibilityTest.java new file mode 100644 index 0000000000000000000000000000000000000000..376b261799854bfce96686d63add93db790617a3 --- /dev/null +++ b/test/jdk/tools/jar/modularJar/JarToolModuleDescriptorReproducibilityTest.java @@ -0,0 +1,218 @@ +/* + * 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 org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.lang.module.ModuleDescriptor; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.jar.JarEntry; +import java.util.jar.JarInputStream; +import java.util.spi.ToolProvider; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertNotNull; + +/** + * @test + * @bug 8258117 + * @summary Tests that the content generated for module-info.class, using the jar command, is reproducible + * @run testng JarToolModuleDescriptorReproducibilityTest + */ +public class JarToolModuleDescriptorReproducibilityTest { + + private static final String MODULE_NAME = "foo"; + private static final String MODULE_VERSION = "1.2.3"; + private static final String UPDATED_MODULE_VERSION = "1.2.4"; + private static final String MAIN_CLASS = "jdk.test.foo.Foo"; + private static final Path MODULE_CLASSES_DIR = Path.of("8258117-module-classes", MODULE_NAME).toAbsolutePath(); + + private static final ToolProvider JAR_TOOL = ToolProvider.findFirst("jar") + .orElseThrow(() + -> new RuntimeException("jar tool not found") + ); + private static final ToolProvider JAVAC_TOOL = ToolProvider.findFirst("javac") + .orElseThrow(() + -> new RuntimeException("javac tool not found") + ); + + + @BeforeClass + public static void setup() throws Exception { + compileModuleClasses(); + } + + /** + * Launches a "jar --create" command multiple times with a module-info.class. The module-info.class + * is internally updated by the jar tool to add additional data. Expects that each such generated + * jar has the exact same bytes. + */ + @Test + public void testJarCreate() throws Exception { + List<Path> jarFiles = new ArrayList<>(); + for (int i = 0; i < 3; i++) { + Path targetJar = Files.createTempFile(Path.of("."), "8258117-jar-create", ".jar"); + jarFiles.add(targetJar); + if (i > 0) { + // the timestamp that gets embedded in (Zip/Jar)Entry gets narrowed + // down to SECONDS unit. So we make sure that there's at least a second + // gap between the jar file creations, to be sure that the jar file + // was indeed generated at "different times" + Thread.sleep(1000); + } + // create a modular jar + runJarCommand("--create", + "--file=" + targetJar, + "--main-class=" + MAIN_CLASS, + "--module-version=" + MODULE_VERSION, + "--no-manifest", + "-C", MODULE_CLASSES_DIR.toString(), "."); + // verify the module descriptor in the jar + assertExpectedModuleInfo(targetJar, MODULE_VERSION); + } + assertAllFileContentsAreSame(jarFiles); + } + + /** + * Launches a "jar --update" process multiple times to update the module-info.class + * descriptor with the same content and then expects that the modular jar created by + * each of these processes has the exact same bytes. + */ + @Test + public void testJarUpdate() throws Exception { + List<Path> jarFiles = new ArrayList<>(); + for (int i = 0; i < 3; i++) { + Path targetJar = Files.createTempFile(Path.of("."), "8258117-jar-update", ".jar"); + jarFiles.add(targetJar); + if (i > 0) { + // the timestamp that gets embedded in (Zip/Jar)Entry gets narrowed + // down to SECONDS unit. So we make sure that there's at least a second + // gap between the jar file creations, to be sure that the jar file + // was indeed generated at "different times" + Thread.sleep(1000); + } + // first create the modular jar + runJarCommand("--create", + "--file=" + targetJar, + "--module-version=" + MODULE_VERSION, + "--no-manifest", + "-C", MODULE_CLASSES_DIR.toString(), "."); + assertExpectedModuleInfo(targetJar, MODULE_VERSION); + // now update the same modular jar + runJarCommand("--update", + "--file=" + targetJar, + "--module-version=" + UPDATED_MODULE_VERSION, + "--no-manifest", + "-C", MODULE_CLASSES_DIR.toString(), "module-info.class"); + // verify the module descriptor in the jar + assertExpectedModuleInfo(targetJar, UPDATED_MODULE_VERSION); + } + assertAllFileContentsAreSame(jarFiles); + } + + // compiles using javac tool the classes used in the test module + private static void compileModuleClasses() throws Exception { + Path sourcePath = Path.of(System.getProperty("test.src", "."), + "src", MODULE_NAME); + List<String> sourceFiles = new ArrayList<>(); + Files.walkFileTree(sourcePath, new SimpleFileVisitor<>() { + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { + if (file.toString().endsWith(".java")) { + sourceFiles.add(file.toString()); + } + return FileVisitResult.CONTINUE; + } + }); + Path classesDir = Files.createDirectories(MODULE_CLASSES_DIR); + List<String> javacArgs = new ArrayList<>(); + javacArgs.add("-d"); + javacArgs.add(classesDir.toString()); + sourceFiles.forEach((f) -> javacArgs.add(f)); + System.out.println("Launching javac command with args: " + javacArgs); + StringWriter sw = new StringWriter(); + try (PrintWriter pw = new PrintWriter(sw)) { + int exitCode = JAVAC_TOOL.run(pw, pw, javacArgs.toArray(new String[0])); + assertEquals(exitCode, 0, "Module compilation failed: " + sw.toString()); + } + System.out.println("Module classes successfully compiled to directory " + classesDir); + } + + // runs the "jar" command passing it the "jarArgs" and verifying that the command + // execution didn't fail + private static void runJarCommand(String... jarArgs) { + StringWriter sw = new StringWriter(); + System.out.println("Launching jar command with args: " + Arrays.toString(jarArgs)); + try (PrintWriter pw = new PrintWriter(sw)) { + int exitCode = JAR_TOOL.run(pw, pw, jarArgs); + assertEquals(exitCode, 0, "jar command execution failed: " + sw.toString()); + } + } + + // verifies the byte equality of the contents in each of the files + private static void assertAllFileContentsAreSame(List<Path> files) throws Exception { + Path firstFile = files.get(0); + for (int i = 1; i < files.size(); i++) { + assertEquals(Files.mismatch(firstFile, files.get(i)), -1, + "Content in file " + files.get(i) + " isn't the same as in file " + firstFile); + } + } + + // verifies that a module-info.class is present in the jar and the module name and version are the expected + // ones + private static void assertExpectedModuleInfo(Path jar, String expectedModuleVersion) throws Exception { + try (JarInputStream jaris = new JarInputStream(Files.newInputStream(jar))) { + JarEntry moduleInfoEntry = null; + JarEntry entry = null; + while ((entry = jaris.getNextJarEntry()) != null) { + if (entry.getName().equals("module-info.class")) { + moduleInfoEntry = entry; + break; + } + } + assertNotNull(moduleInfoEntry, "module-info.class is missing from jar " + jar); + + ModuleDescriptor md = ModuleDescriptor.read(jaris); + assertEquals(md.name(), MODULE_NAME, "Unexpected module name"); + assertFalse(md.rawVersion().isEmpty(), "Module version missing from descriptor"); + + String actualVersion = md.rawVersion().get(); + assertEquals(actualVersion, expectedModuleVersion, "Unexpected module version"); + + System.out.println(moduleInfoEntry.getName() + " has a timestamp of " + + moduleInfoEntry.getTime() + " for version " + actualVersion); + } + } +} + diff --git a/test/jdk/tools/jar/multiRelease/MRTestBase.java b/test/jdk/tools/jar/multiRelease/MRTestBase.java index 8447b20b368be3d13be0b6dbba5ec7f49b8dcf55..abd5782fdcde204653576a6744b649eb73753c28 100644 --- a/test/jdk/tools/jar/multiRelease/MRTestBase.java +++ b/test/jdk/tools/jar/multiRelease/MRTestBase.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -108,7 +108,6 @@ public class MRTestBase { if (!opts.isEmpty()) { commands.addAll(Arrays.asList(opts.split(" +"))); } - commands.addAll(Utils.getForwardVmOptions()); commands.add("-d"); commands.add(dest.toString()); Stream.of(sourceFiles) diff --git a/test/jdk/tools/jar/multiRelease/data/test13/v10/version/Nested.java b/test/jdk/tools/jar/multiRelease/data/test13/v10/version/Nested.java index 7acd05676b446ac2a309a0b292709f204ca6343b..35f43edcb392077ebb910c7a21430cbfe5046eb5 100644 --- a/test/jdk/tools/jar/multiRelease/data/test13/v10/version/Nested.java +++ b/test/jdk/tools/jar/multiRelease/data/test13/v10/version/Nested.java @@ -12,7 +12,7 @@ public class Nested { int save = getVersion(); class nestnested { - int save = getVersion();; + int save = getVersion(); } } } diff --git a/test/jdk/tools/jimage/JImageNonAsciiNameTest.java b/test/jdk/tools/jimage/JImageNonAsciiNameTest.java new file mode 100644 index 0000000000000000000000000000000000000000..4d1e5ba94ad82532e4b4c2cf291bf26ffe48eb1a --- /dev/null +++ b/test/jdk/tools/jimage/JImageNonAsciiNameTest.java @@ -0,0 +1,98 @@ +/* + * 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 java.nio.file.Path; +import jdk.internal.jimage.BasicImageReader; +import jdk.internal.jimage.ImageLocation; +import jdk.test.lib.compiler.InMemoryJavaCompiler; +import jdk.test.lib.util.JarBuilder; + +import tests.Helper; +import tests.JImageGenerator; +import tests.Result; + +/* + * @test + * @bug 8278185 + * @summary Test non-ASCII path in custom JRE + * @library ../lib + * /test/lib + * @modules java.base/jdk.internal.jimage + * jdk.jdeps/com.sun.tools.classfile + * jdk.jlink/jdk.tools.jimage + * @build tests.* + * @run main/othervm JImageNonAsciiNameTest + */ + +public class JImageNonAsciiNameTest { + private final static String moduleName = "A_module"; + private final static String packageName = "test.\u3042"; //non-ASCII + private final static String className = "A"; + private final static String fullName = packageName + "." + className; + private static Helper helper; + + public static void main(String[] args) throws Exception { + helper = Helper.newHelper(); + if (helper == null) { + System.err.println("Test not run"); + return; + } + + String source = + "package "+packageName+";" + + "public class "+className+" {" + + " public static void main(String[] args) {}" + + "}"; + String moduleInfo = "module " + moduleName + " {}"; + + // Using InMemory features to avoid generating non-ASCII name file + byte[] byteA = InMemoryJavaCompiler.compile(fullName, source); + byte[] byteModule = InMemoryJavaCompiler.compile( + "module-info", moduleInfo); + + Path jarDir = helper.getJarDir(); + JarBuilder jb = new JarBuilder( + jarDir.resolve(moduleName + ".jar").toString()); + jb.addEntry(fullName.replace(".","/") + ".class", byteA); + jb.addEntry("module-info.class", byteModule); + jb.build(); + + Path outDir = helper.createNewImageDir(moduleName); + + Result result = JImageGenerator.getJLinkTask() + .modulePath(helper.defaultModulePath()) + .output(outDir) + .addMods(moduleName) + .call(); + Path testImage = result.assertSuccess(); + + BasicImageReader bir = BasicImageReader.open( + testImage.resolve("lib").resolve("modules")); + ImageLocation loc = bir.findLocation(moduleName, + fullName.replace(".","/") + ".class"); + if (loc == null) { + throw new RuntimeException("Failed to find " + + fullName + " in module " +moduleName); + } + } +} diff --git a/test/jdk/tools/jmod/JmodTest.java b/test/jdk/tools/jmod/JmodTest.java index c32284faee652b4c5ea4898d3f2bc697ff26a982..78f1a89a759ccbd02bd4d3a089c6d4df86545b27 100644 --- a/test/jdk/tools/jmod/JmodTest.java +++ b/test/jdk/tools/jmod/JmodTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -23,7 +23,7 @@ /* * @test - * @bug 8142968 8166568 8166286 8170618 8168149 8240910 + * @bug 8142968 8166568 8166286 8170618 8168149 8240910 8276764 8276766 * @summary Basic test for jmod * @library /test/lib * @modules jdk.compiler @@ -183,13 +183,15 @@ public class JmodTest { @Test public void testList() throws IOException { String cp = EXPLODED_DIR.resolve("foo").resolve("classes").toString(); + Path jmod = MODS_DIR.resolve("foo.jmod"); + FileUtils.deleteFileIfExistsWithRetry(jmod); jmod("create", "--class-path", cp, - MODS_DIR.resolve("foo.jmod").toString()) + jmod.toString()) .assertSuccess(); jmod("list", - MODS_DIR.resolve("foo.jmod").toString()) + jmod.toString()) .assertSuccess() .resultChecker(r -> { // asserts dependent on the exact contents of foo @@ -197,6 +199,75 @@ public class JmodTest { assertContains(r.output, CLASSES_PREFIX + "jdk/test/foo/Foo.class"); assertContains(r.output, CLASSES_PREFIX + "jdk/test/foo/internal/Message.class"); assertContains(r.output, CLASSES_PREFIX + "jdk/test/foo/resources/foo.properties"); + + // JDK-8276764: Ensure the order is sorted for reproducible jmod content + // module-info, followed by <sorted classes> + int mod_info_i = r.output.indexOf(CLASSES_PREFIX + "module-info.class"); + int foo_cls_i = r.output.indexOf(CLASSES_PREFIX + "jdk/test/foo/Foo.class"); + int msg_i = r.output.indexOf(CLASSES_PREFIX + "jdk/test/foo/internal/Message.class"); + int res_i = r.output.indexOf(CLASSES_PREFIX + "jdk/test/foo/resources/foo.properties"); + System.out.println("jmod classes sort order check:\n"+r.output); + assertTrue(mod_info_i < foo_cls_i); + assertTrue(foo_cls_i < msg_i); + assertTrue(msg_i < res_i); + }); + } + + @Test + public void testSourceDateReproducible() throws IOException { + String cp = EXPLODED_DIR.resolve("foo").resolve("classes").toString(); + Path jmod1 = MODS_DIR.resolve("foo1.jmod"); + Path jmod2 = MODS_DIR.resolve("foo2.jmod"); + Path jmod3 = MODS_DIR.resolve("foo3.jmod"); + FileUtils.deleteFileIfExistsWithRetry(jmod1); + FileUtils.deleteFileIfExistsWithRetry(jmod2); + FileUtils.deleteFileIfExistsWithRetry(jmod3); + + // Use source date of 15/03/2022 + String sourceDate = "2022-03-15T00:00:00+00:00"; + + jmod("create", + "--class-path", cp, + "--date", sourceDate, + jmod1.toString()) + .assertSuccess(); + + try { + // Sleep 5 seconds to ensure zip timestamps might be different if they could be + Thread.sleep(5000); + } catch(InterruptedException ex) {} + + jmod("create", + "--class-path", cp, + "--date", sourceDate, + jmod2.toString()) + .assertSuccess(); + + // Compare file byte content to see if they are identical + assertSameContent(jmod1, jmod2); + + // Use a date before 1980 and assert failure error + sourceDate = "1976-03-15T00:00:00+00:00"; + + jmod("create", + "--class-path", cp, + "--date", sourceDate, + jmod3.toString()) + .assertFailure() + .resultChecker(r -> { + assertContains(r.output, "is out of the valid range"); + }); + + // Use a date after 2099 and assert failure error + sourceDate = "2100-03-15T00:00:00+00:00"; + + jmod("create", + "--class-path", cp, + "--date", sourceDate, + jmod3.toString()) + .assertFailure() + .resultChecker(r -> { + assertContains(r.output, "is out of the valid range"); }); } diff --git a/test/jdk/tools/jpackage/apps/Hello.java b/test/jdk/tools/jpackage/apps/Hello.java index dd6f114a421fa06bd341f6daab4952f93c658e0f..000573c933fd1969b19e91d9a4f62db56cd3abbb 100644 --- a/test/jdk/tools/jpackage/apps/Hello.java +++ b/test/jdk/tools/jpackage/apps/Hello.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -37,6 +37,7 @@ import java.util.List; import java.util.ArrayList; import java.util.stream.Stream; import java.util.Collections; +import java.util.Optional; public class Hello implements OpenFilesHandler { @@ -60,6 +61,15 @@ public class Hello implements OpenFilesHandler { var outputFile = getOutputFile(args); trace(String.format("Output file: [%s]", outputFile)); Files.write(outputFile, lines); + + if (Optional.ofNullable(System.getProperty("jpackage.test.noexit")).map( + Boolean::parseBoolean).orElse(false)) { + trace("noexit"); + var lock = new Object(); + synchronized (lock) { + lock.wait(); + } + } } private static List<String> printArgs(String[] args) { @@ -87,7 +97,8 @@ public class Hello implements OpenFilesHandler { } private static Path getOutputFile(String[] args) { - Path outputFilePath = Path.of("appOutput.txt"); + Path outputFilePath = Path.of(Optional.ofNullable(System.getProperty( + "jpackage.test.appOutput")).orElse("appOutput.txt")); // If first arg is a file (most likely from fa), then put output in the same folder as // the file from fa. @@ -101,7 +112,7 @@ public class Hello implements OpenFilesHandler { try { // Try writing in the default output file. Files.write(outputFilePath, Collections.emptyList()); - return outputFilePath; + return outputFilePath.toAbsolutePath(); } catch (IOException ex) { // Log reason of a failure. StringWriter errors = new StringWriter(); @@ -109,7 +120,7 @@ public class Hello implements OpenFilesHandler { Stream.of(errors.toString().split("\\R")).forEachOrdered(Hello::trace); } - return Path.of(System.getProperty("user.home")).resolve(outputFilePath); + return Path.of(System.getProperty("user.home")).resolve(outputFilePath).toAbsolutePath(); } @Override diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/AdditionalLauncher.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/AdditionalLauncher.java index 10033db4802bd57675b56a3ef87d2f9cb3ee2aa9..8c6bbc1fa4314c3228948495965b842fea33cd2d 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/AdditionalLauncher.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/AdditionalLauncher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -29,13 +29,18 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Optional; import java.util.function.BiConsumer; +import java.util.function.Supplier; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; import java.util.stream.Stream; -import jdk.jpackage.internal.ApplicationLayout; import jdk.jpackage.test.Functional.ThrowingBiConsumer; +import static jdk.jpackage.test.Functional.ThrowingFunction.toFunction; -public final class AdditionalLauncher { +public class AdditionalLauncher { public AdditionalLauncher(String name) { this.name = name; @@ -43,12 +48,12 @@ public final class AdditionalLauncher { setPersistenceHandler(null); } - public AdditionalLauncher setDefaultArguments(String... v) { + final public AdditionalLauncher setDefaultArguments(String... v) { defaultArguments = new ArrayList<>(List.of(v)); return this; } - public AdditionalLauncher addDefaultArguments(String... v) { + final public AdditionalLauncher addDefaultArguments(String... v) { if (defaultArguments == null) { return setDefaultArguments(v); } @@ -57,12 +62,12 @@ public final class AdditionalLauncher { return this; } - public AdditionalLauncher setJavaOptions(String... v) { + final public AdditionalLauncher setJavaOptions(String... v) { javaOptions = new ArrayList<>(List.of(v)); return this; } - public AdditionalLauncher addJavaOptions(String... v) { + final public AdditionalLauncher addJavaOptions(String... v) { if (javaOptions == null) { return setJavaOptions(v); } @@ -71,23 +76,36 @@ public final class AdditionalLauncher { return this; } - public AdditionalLauncher addRawProperties(Map.Entry<String, String>... v) { + final public AdditionalLauncher addRawProperties( + Map.Entry<String, String>... v) { return addRawProperties(List.of(v)); } - public AdditionalLauncher addRawProperties( + final public AdditionalLauncher addRawProperties( Collection<Map.Entry<String, String>> v) { rawProperties.addAll(v); return this; } - public AdditionalLauncher setShortcuts(boolean menu, boolean shortcut) { + final public String getRawPropertyValue( + String key, Supplier<String> getDefault) { + return rawProperties.stream() + .filter(item -> item.getKey().equals(key)) + .map(e -> e.getValue()).findAny().orElseGet(getDefault); + } + + private String getDesciption(JPackageCommand cmd) { + return getRawPropertyValue("description", () -> cmd.getArgumentValue( + "--description", unused -> cmd.name())); + } + + final public AdditionalLauncher setShortcuts(boolean menu, boolean shortcut) { withMenuShortcut = menu; withShortcut = shortcut; return this; } - public AdditionalLauncher setIcon(Path iconPath) { + final public AdditionalLauncher setIcon(Path iconPath) { if (iconPath == NO_ICON) { throw new IllegalArgumentException(); } @@ -96,12 +114,12 @@ public final class AdditionalLauncher { return this; } - public AdditionalLauncher setNoIcon() { + final public AdditionalLauncher setNoIcon() { icon = NO_ICON; return this; } - public AdditionalLauncher setPersistenceHandler( + final public AdditionalLauncher setPersistenceHandler( ThrowingBiConsumer<Path, List<Map.Entry<String, String>>> handler) { if (handler != null) { createFileHandler = ThrowingBiConsumer.toBiConsumer(handler); @@ -111,19 +129,53 @@ public final class AdditionalLauncher { return this; } - public void applyTo(JPackageCommand cmd) { + final public void applyTo(JPackageCommand cmd) { cmd.addPrerequisiteAction(this::initialize); cmd.addVerifyAction(this::verify); } - public void applyTo(PackageTest test) { - test.addLauncherName(name); + final public void applyTo(PackageTest test) { test.addInitializer(this::initialize); test.addInstallVerifier(this::verify); } + static void forEachAdditionalLauncher(JPackageCommand cmd, + BiConsumer<String, Path> consumer) { + var argIt = cmd.getAllArguments().iterator(); + while (argIt.hasNext()) { + if ("--add-launcher".equals(argIt.next())) { + // <launcherName>=<propFile> + var arg = argIt.next(); + var items = arg.split("=", 2); + consumer.accept(items[0], Path.of(items[1])); + } + } + } + + static PropertyFile getAdditionalLauncherProperties( + JPackageCommand cmd, String launcherName) { + PropertyFile shell[] = new PropertyFile[1]; + forEachAdditionalLauncher(cmd, (name, propertiesFilePath) -> { + if (name.equals(launcherName)) { + shell[0] = toFunction(PropertyFile::new).apply( + propertiesFilePath); + } + }); + return Optional.of(shell[0]).get(); + } + private void initialize(JPackageCommand cmd) { - final Path propsFile = TKit.workDir().resolve(name + ".properties"); + Path propsFile = TKit.workDir().resolve(name + ".properties"); + if (Files.exists(propsFile)) { + // File with the given name exists, pick another name that + // will not reference existing file. + try { + propsFile = TKit.createTempFile(propsFile); + TKit.deleteIfExists(propsFile); + } catch (IOException ex) { + Functional.rethrowUnchecked(ex); + } + } cmd.addArguments("--add-launcher", String.format("%s=%s", name, propsFile)); @@ -242,9 +294,30 @@ public final class AdditionalLauncher { } } - private void verify(JPackageCommand cmd) throws IOException { + private void verifyDescription(JPackageCommand cmd) throws IOException { + if (TKit.isWindows()) { + String expectedDescription = getDesciption(cmd); + Path launcherPath = cmd.appLauncherPath(name); + String actualDescription = + WindowsHelper.getExecutableDesciption(launcherPath); + TKit.assertEquals(expectedDescription, actualDescription, + String.format("Check file description of [%s]", launcherPath)); + } else if (TKit.isLinux() && !cmd.isImagePackageType()) { + String expectedDescription = getDesciption(cmd); + Path desktopFile = LinuxHelper.getDesktopFile(cmd, name); + if (Files.exists(desktopFile)) { + TKit.assertTextStream("Comment=" + expectedDescription) + .label(String.format("[%s] file", desktopFile)) + .predicate(String::equals) + .apply(Files.readAllLines(desktopFile).stream()); + } + } + } + + protected void verify(JPackageCommand cmd) throws IOException { verifyIcon(cmd); verifyShortcuts(cmd); + verifyDescription(cmd); Path launcherPath = cmd.appLauncherPath(name); @@ -255,14 +328,60 @@ public final class AdditionalLauncher { return; } - HelloApp.assertApp(launcherPath) - .addDefaultArguments(Optional - .ofNullable(defaultArguments) - .orElseGet(() -> List.of(cmd.getAllArgumentValues("--arguments")))) - .addJavaOptions(Optional - .ofNullable(javaOptions) - .orElseGet(() -> List.of(cmd.getAllArgumentValues("--java-options")))) - .executeAndVerifyOutput(); + var appVerifier = HelloApp.assertApp(launcherPath) + .addDefaultArguments(Optional + .ofNullable(defaultArguments) + .orElseGet(() -> List.of(cmd.getAllArgumentValues("--arguments")))) + .addJavaOptions(Optional + .ofNullable(javaOptions) + .orElseGet(() -> List.of(cmd.getAllArgumentValues( + "--java-options"))).stream().map( + str -> resolveVariables(cmd, str)).toList()); + + appVerifier.executeAndVerifyOutput(); + } + + public static final class PropertyFile { + + PropertyFile(Path path) throws IOException { + data = Files.readAllLines(path).stream().map(str -> { + return str.split("=", 2); + }).collect( + Collectors.toMap(tokens -> tokens[0], tokens -> tokens[1], + (oldValue, newValue) -> { + return newValue; + })); + } + + public boolean isPropertySet(String name) { + Objects.requireNonNull(name); + return data.containsKey(name); + } + + public Optional<String> getPropertyValue(String name) { + Objects.requireNonNull(name); + return Optional.of(data.get(name)); + } + + public Optional<Boolean> getPropertyBooleanValue(String name) { + Objects.requireNonNull(name); + return Optional.ofNullable(data.get(name)).map(Boolean::parseBoolean); + } + + private final Map<String, String> data; + } + + private static String resolveVariables(JPackageCommand cmd, String str) { + var map = Map.of( + "$APPDIR", cmd.appLayout().appDirectory(), + "$ROOTDIR", + cmd.isImagePackageType() ? cmd.outputBundle() : cmd.appInstallationDirectory(), + "$BINDIR", cmd.appLayout().launchersDirectory()); + for (var e : map.entrySet()) { + str = str.replaceAll(Pattern.quote(e.getKey()), + Matcher.quoteReplacement(e.getValue().toString())); + } + return str; } private List<String> javaOptions; diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/CfgFile.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/CfgFile.java index e2a380366e8f9e78aafe3c45f95bda05830a9552..31bf0520a315c20c01ed86d6b30e0564c4f31ba1 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/CfgFile.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/CfgFile.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -29,6 +29,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Objects; +import java.util.Optional; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -85,7 +86,8 @@ public final class CfgFile { } if (!currentSection.isEmpty()) { - result.put("", Collections.unmodifiableMap(currentSection)); + result.put(Optional.ofNullable(currentSectionName).orElse(""), + Collections.unmodifiableMap(currentSection)); } return new CfgFile(Collections.unmodifiableMap(result), path.toString()); diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Executor.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Executor.java index d65fe4e667bdeca82aaf0212b0a74ac5197ab7d5..3fed83ddb361ce6c6bf5edad14bd8b5f5a34d8de 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Executor.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Executor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -90,8 +90,10 @@ public final class Executor extends CommandArguments<Executor> { } public Executor setWindowsTmpDir(String tmp) { - TKit.assertTrue(TKit.isWindows(), - "setWindowsTmpDir is only valid on Windows platform"); + if (!TKit.isWindows()) { + throw new UnsupportedOperationException( + "setWindowsTmpDir is only valid on Windows platform"); + } winTmpDir = tmp; return this; } diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/HelloApp.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/HelloApp.java index 71561a51cf3731bfc5b53ad2b957bb4bd8abd76d..2d0d23dae26f30011587049338841b7cdc3ce707 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/HelloApp.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/HelloApp.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -351,6 +351,7 @@ public final class HelloApp { public final static class AppOutputVerifier { AppOutputVerifier(Path helloAppLauncher) { this.launcherPath = helloAppLauncher; + this.outputFilePath = TKit.workDir().resolve(OUTPUT_FILENAME); this.params = new HashMap<>(); this.defaultLauncherArgs = new ArrayList<>(); } @@ -367,6 +368,8 @@ public final class HelloApp { public AppOutputVerifier addParam(String name, String value) { if (name.startsWith("param")) { params.put(name, value); + } else if ("jpackage.test.appOutput".equals(name)) { + outputFilePath = Path.of(value); } return this; } @@ -397,6 +400,18 @@ public final class HelloApp { .collect(Collectors.toList())); } + public void verifyOutput(String... args) { + final List<String> launcherArgs = List.of(args); + final List<String> appArgs; + if (launcherArgs.isEmpty()) { + appArgs = defaultLauncherArgs; + } else { + appArgs = launcherArgs; + } + + verifyOutputFile(outputFilePath, appArgs, params); + } + public void executeAndVerifyOutput(String... args) { executeAndVerifyOutput(false, args); } @@ -408,8 +423,7 @@ public final class HelloApp { getExecutor(launcherArgs.toArray(new String[0])).dumpOutput().setRemovePath( removePath).executeAndRepeatUntilExitCode(0, attempts, waitBetweenAttemptsSeconds); - Path outputFile = TKit.workDir().resolve(OUTPUT_FILENAME); - verifyOutputFile(outputFile, appArgs, params); + verifyOutputFile(outputFilePath, appArgs, params); } public void executeAndVerifyOutput(boolean removePath, String... args) { @@ -453,6 +467,7 @@ public final class HelloApp { } private final Path launcherPath; + private Path outputFilePath; private final List<String> defaultLauncherArgs; private final Map<String, String> params; } 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 3315de374c3888cd3f179bcecbc033c1527f6990..d30f96ff786399b00dea2a9b7b7a827f811204c3 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, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -47,6 +47,7 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import jdk.jpackage.internal.AppImageFile; import jdk.jpackage.internal.ApplicationLayout; +import static jdk.jpackage.test.AdditionalLauncher.forEachAdditionalLauncher; import jdk.jpackage.test.Functional.ThrowingConsumer; import jdk.jpackage.test.Functional.ThrowingFunction; import jdk.jpackage.test.Functional.ThrowingSupplier; @@ -242,6 +243,17 @@ public final class JPackageCommand extends CommandArguments<JPackageCommand> { return this; } + public JPackageCommand setInputToEmptyDirectory() { + if (Files.exists(inputDir())) { + try { + setArgumentValue("--input", TKit.createTempDirectory("input")); + } catch (IOException ex) { + throw new RuntimeException(ex); + } + } + return this; + } + public JPackageCommand setFakeRuntime() { verifyMutable(); @@ -414,6 +426,28 @@ public final class JPackageCommand extends CommandArguments<JPackageCommand> { return unpackDir.resolve(TKit.removeRootFromAbsolutePath(path)); } + /** + * Returns path to package file from the path in unpacked package directory + * or the given path if the package is not unpacked. + */ + public Path pathToPackageFile(Path path) { + Path unpackDir = unpackedPackageDirectory(); + if (unpackDir == null) { + if (!path.isAbsolute()) { + throw new IllegalArgumentException(String.format( + "Path [%s] is not absolute", path)); + } + return path; + } + + if (!path.startsWith(unpackDir)) { + throw new IllegalArgumentException(String.format( + "Path [%s] doesn't start with [%s] path", path, unpackDir)); + } + + return Path.of("/").resolve(unpackDir.relativize(path)); + } + Path unpackedPackageDirectory() { verifyIsOfType(PackageType.NATIVE); return getArgumentValue(UNPACKED_PATH_ARGNAME, () -> null, Path::of); @@ -497,6 +531,18 @@ public final class JPackageCommand extends CommandArguments<JPackageCommand> { return appLauncherPath(null); } + /** + * Returns names of all additional launchers or empty list if none + * configured. + */ + public List<String> addLauncherNames() { + List<String> names = new ArrayList<>(); + forEachAdditionalLauncher(this, (launcherName, propFile) -> { + names.add(launcherName); + }); + return names; + } + private void verifyNotRuntime() { if (isRuntime()) { throw new IllegalArgumentException("Java runtime packaging"); @@ -537,9 +583,9 @@ public final class JPackageCommand extends CommandArguments<JPackageCommand> { throw TKit.throwUnknownPlatformError(); } - if (criticalRuntimeFiles.stream().filter( - v -> runtimeDir.resolve(v).toFile().exists()).findFirst().orElse( - null) == null) { + if (!criticalRuntimeFiles.stream().anyMatch(v -> { + return runtimeDir.resolve(v).toFile().exists(); + })) { // Fake runtime TKit.trace(String.format( "%s because application runtime directory [%s] is incomplete", @@ -738,7 +784,7 @@ public final class JPackageCommand extends CommandArguments<JPackageCommand> { appImageFileName)); } } - } else if (TKit.isOSX()) { + } else if (TKit.isOSX() && !isRuntime()) { TKit.assertFileExists(AppImageFile.getPathInAppImage( appInstallationDirectory())); } else { @@ -763,11 +809,20 @@ public final class JPackageCommand extends CommandArguments<JPackageCommand> { JPackageCommand setUnpackedPackageLocation(Path path) { verifyIsOfType(PackageType.NATIVE); - setArgumentValue(UNPACKED_PATH_ARGNAME, path); + if (path != null) { + setArgumentValue(UNPACKED_PATH_ARGNAME, path); + } else { + removeArgumentWithValue(UNPACKED_PATH_ARGNAME); + } return this; } private JPackageCommand adjustArgumentsBeforeExecution() { + if (!isWithToolProvider()) { + // if jpackage is launched as a process then set the jlink.debug system property + // to allow the jlink process to print exception stacktraces on any failure + addArgument("-J-Djlink.debug=true"); + } if (!hasArgument("--runtime-image") && !hasArgument("--app-image") && DEFAULT_RUNTIME_IMAGE != null && !ignoreDefaultRuntime) { addArguments("--runtime-image", DEFAULT_RUNTIME_IMAGE); } @@ -783,6 +838,11 @@ public final class JPackageCommand extends CommandArguments<JPackageCommand> { return createExecutor().getPrintableCommandLine(); } + @Override + public String toString() { + return getPrintableCommandLine(); + } + public void verifyIsOfType(Collection<PackageType> types) { verifyIsOfType(types.toArray(PackageType[]::new)); } diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JavaTool.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JavaTool.java index de5a4e4d8e4e5c8d7b6b92b17d9bb845bbb67182..7b217b2431ce30ca222ffbe2888d7c97e3b34f9a 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JavaTool.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JavaTool.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -40,7 +40,7 @@ public enum JavaTool { } } - Path getPath() { + public Path getPath() { return path; } @@ -48,7 +48,7 @@ public enum JavaTool { return ToolProvider.findFirst(toolName()).orElse(null); } - Path relativePathInJavaHome() { + private Path relativePathInJavaHome() { Path path = Path.of("bin", toolName()); if (TKit.isWindows()) { path = path.getParent().resolve(path.getFileName().toString() + ".exe"); diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LinuxHelper.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LinuxHelper.java index 5b91b829457015981d0e547e0fd87e9393e662e3..4d096198c9df1e63a162a29241993c74a5001051 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LinuxHelper.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LinuxHelper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -42,8 +42,7 @@ import jdk.jpackage.internal.IOUtils; import jdk.jpackage.test.PackageTest.PackageHandlers; - -public class LinuxHelper { +public final class LinuxHelper { private static String getReleaseSuffix(JPackageCommand cmd) { String value = null; final PackageType packageType = cmd.packageType(); @@ -183,7 +182,10 @@ public class LinuxHelper { }; deb.uninstallHandler = cmd -> { cmd.verifyIsOfType(PackageType.LINUX_DEB); - Executor.of("sudo", "dpkg", "-r", getPackageName(cmd)).execute(); + var packageName = getPackageName(cmd); + String script = String.format("! dpkg -s %s || sudo dpkg -r %s", + packageName, packageName); + Executor.of("sh", "-c", script).execute(); }; deb.unpackHandler = (cmd, destinationDir) -> { cmd.verifyIsOfType(PackageType.LINUX_DEB); @@ -200,13 +202,16 @@ public class LinuxHelper { PackageHandlers rpm = new PackageHandlers(); rpm.installHandler = cmd -> { cmd.verifyIsOfType(PackageType.LINUX_RPM); - Executor.of("sudo", "rpm", "-i") + Executor.of("sudo", "rpm", "-U") .addArgument(cmd.outputBundle()) .execute(); }; rpm.uninstallHandler = cmd -> { cmd.verifyIsOfType(PackageType.LINUX_RPM); - Executor.of("sudo", "rpm", "-e", getPackageName(cmd)).execute(); + var packageName = getPackageName(cmd); + String script = String.format("! rpm -q %s || sudo rpm -e %s", + packageName, packageName); + Executor.of("sh", "-c", script).execute(); }; rpm.unpackHandler = (cmd, destinationDir) -> { cmd.verifyIsOfType(PackageType.LINUX_RPM); @@ -363,10 +368,10 @@ public class LinuxHelper { test.addInstallVerifier(cmd -> { // Verify .desktop files. - try (var files = Files.walk(cmd.appLayout().destktopIntegrationDirectory(), 1)) { + try (var files = Files.list(cmd.appLayout().destktopIntegrationDirectory())) { List<Path> desktopFiles = files .filter(path -> path.getFileName().toString().endsWith(".desktop")) - .collect(Collectors.toList()); + .toList(); if (!integrated) { TKit.assertStringListEquals(List.of(), desktopFiles.stream().map(Path::toString).collect( @@ -470,23 +475,18 @@ public class LinuxHelper { String desktopFileName = queryMimeTypeDefaultHandler(mimeType); - Path desktopFile = getSystemDesktopFilesFolder().resolve( + Path systemDesktopFile = getSystemDesktopFilesFolder().resolve( + desktopFileName); + Path appDesktopFile = cmd.appLayout().destktopIntegrationDirectory().resolve( desktopFileName); - TKit.assertFileExists(desktopFile); - - TKit.trace(String.format("Reading [%s] file...", desktopFile)); - String mimeHandler = Files.readAllLines(desktopFile).stream().peek( - v -> TKit.trace(v)).filter( - v -> v.startsWith("Exec=")).map( - v -> v.split("=", 2)[1]).findFirst().orElseThrow(); - - TKit.trace(String.format("Done")); - - TKit.assertEquals(cmd.appLauncherPath().toString(), - mimeHandler, String.format( - "Check mime type handler is the main application launcher")); + TKit.assertFileExists(systemDesktopFile); + TKit.assertFileExists(appDesktopFile); + TKit.assertStringListEquals(Files.readAllLines(appDesktopFile), + Files.readAllLines(systemDesktopFile), String.format( + "Check [%s] file is a copy of [%s] file", + systemDesktopFile, appDesktopFile)); }); }); 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 9b6457ccc58f7ffc7f308e18f2d2feb25b8c0c9a..7f5887f0ac37dd698894d027d2624f22791891f4 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, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -39,6 +39,7 @@ import javax.xml.parsers.ParserConfigurationException; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathFactory; +import jdk.jpackage.internal.IOUtils; import jdk.jpackage.test.Functional.ThrowingConsumer; import jdk.jpackage.test.Functional.ThrowingSupplier; import jdk.jpackage.test.PackageTest.PackageHandlers; @@ -46,7 +47,7 @@ import jdk.jpackage.internal.RetryExecutor; import org.xml.sax.SAXException; import org.w3c.dom.NodeList; -public class MacHelper { +public final class MacHelper { public static void withExplodedDmg(JPackageCommand cmd, ThrowingConsumer<Path> consumer) { @@ -172,41 +173,62 @@ public class MacHelper { pkg.installHandler = cmd -> { cmd.verifyIsOfType(PackageType.MAC_PKG); Executor.of("sudo", "/usr/sbin/installer", "-allowUntrusted", "-pkg") - .addArgument(cmd.outputBundle()) - .addArguments("-target", "/") - .execute(); + .addArgument(cmd.outputBundle()) + .addArguments("-target", "/") + .execute(); }; pkg.unpackHandler = (cmd, destinationDir) -> { cmd.verifyIsOfType(PackageType.MAC_PKG); + + var dataDir = destinationDir.resolve("data"); + Executor.of("pkgutil", "--expand") - .addArgument(cmd.outputBundle()) - .addArgument(destinationDir.resolve("data")) // We need non-existing folder - .execute(); + .addArgument(cmd.outputBundle()) + .addArgument(dataDir) // We need non-existing folder + .execute(); final Path unpackRoot = destinationDir.resolve("unpacked"); - Path installDir = TKit.removeRootFromAbsolutePath( - getInstallationDirectory(cmd)).getParent(); - final Path unpackDir = unpackRoot.resolve(installDir); - try { - Files.createDirectories(unpackDir); + // Unpack all ".pkg" files from $dataDir folder in $unpackDir folder + try (var dataListing = Files.list(dataDir)) { + dataListing.filter(file -> { + return ".pkg".equals(IOUtils.getSuffix(file.getFileName())); + }).forEach(ThrowingConsumer.toConsumer(pkgDir -> { + // Installation root of the package is stored in + // /pkg-info@install-location attribute in $pkgDir/PackageInfo xml file + var doc = createDocumentBuilder().parse( + new ByteArrayInputStream(Files.readAllBytes( + pkgDir.resolve("PackageInfo")))); + var xPath = XPathFactory.newInstance().newXPath(); + + final String installRoot = (String) xPath.evaluate( + "/pkg-info/@install-location", doc, + XPathConstants.STRING); + + final Path unpackDir = unpackRoot.resolve( + TKit.removeRootFromAbsolutePath(Path.of(installRoot))); + + Files.createDirectories(unpackDir); + + Executor.of("tar", "-C") + .addArgument(unpackDir) + .addArgument("-xvf") + .addArgument(pkgDir.resolve("Payload")) + .execute(); + })); } catch (IOException ex) { throw new RuntimeException(ex); } - Executor.of("tar", "-C") - .addArgument(unpackDir) - .addArgument("-xvf") - .addArgument(Path.of(destinationDir.toString(), "data", - cmd.name() + "-app.pkg", "Payload")) - .execute(); return unpackRoot; }; pkg.uninstallHandler = cmd -> { cmd.verifyIsOfType(PackageType.MAC_PKG); + Executor.of("sudo", "rm", "-rf") - .addArgument(cmd.appInstallationDirectory()) - .execute(); + .addArgument(cmd.appInstallationDirectory()) + .execute(); + }; return pkg; @@ -220,13 +242,13 @@ public class MacHelper { static Path getInstallationDirectory(JPackageCommand cmd) { cmd.verifyIsOfType(PackageType.MAC); - return Path.of(cmd.getArgumentValue("--install-dir", () -> "/Applications")) - .resolve(cmd.name() + (cmd.isRuntime() ? "" : ".app")); + return Path.of(cmd.getArgumentValue("--install-dir", + () -> cmd.isRuntime() ? "/Library/Java/JavaVirtualMachines" : "/Applications")).resolve( + cmd.name() + (cmd.isRuntime() ? "" : ".app")); } private static String getPackageName(JPackageCommand cmd) { - return cmd.getArgumentValue("--mac-package-name", - () -> cmd.installerName()); + return cmd.getArgumentValue("--mac-package-name", cmd::installerName); } public static final class PListWrapper { @@ -274,25 +296,24 @@ public class MacHelper { return values; } - PListWrapper(String xml) throws ParserConfigurationException, + private PListWrapper(String xml) throws ParserConfigurationException, SAXException, IOException { doc = createDocumentBuilder().parse(new ByteArrayInputStream( xml.getBytes(StandardCharsets.UTF_8))); } - private static DocumentBuilder createDocumentBuilder() throws - ParserConfigurationException { - DocumentBuilderFactory dbf = DocumentBuilderFactory.newDefaultInstance(); - dbf.setFeature( - "http://apache.org/xml/features/nonvalidating/load-external-dtd", - false); - return dbf.newDocumentBuilder(); - } - private final org.w3c.dom.Document doc; } + private static DocumentBuilder createDocumentBuilder() throws + ParserConfigurationException { + DocumentBuilderFactory dbf = DocumentBuilderFactory.newDefaultInstance(); + dbf.setFeature( + "http://apache.org/xml/features/nonvalidating/load-external-dtd", + false); + return dbf.newDocumentBuilder(); + } + static final Set<Path> CRITICAL_RUNTIME_FILES = Set.of(Path.of( "Contents/Home/lib/server/libjvm.dylib")); - } 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 f81fb1c170cb51de93a0b1444ddd6855bd4e7849..0884b41dc5530d8efdaf835c52382c8a16549d37 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, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -25,6 +25,7 @@ package jdk.jpackage.test; import java.awt.Desktop; import java.awt.GraphicsEnvironment; import java.io.File; +import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; @@ -36,19 +37,32 @@ import java.util.List; import java.util.ListIterator; import java.util.Map; import java.util.Objects; +import java.util.Optional; import java.util.Set; import java.util.function.BiConsumer; import java.util.function.BiFunction; import java.util.function.Consumer; import java.util.function.Predicate; +import java.util.function.Supplier; import java.util.stream.Collectors; import java.util.stream.Stream; -import jdk.jpackage.internal.AppImageFile; import jdk.jpackage.internal.ApplicationLayout; import jdk.jpackage.test.Functional.ThrowingBiConsumer; +import static jdk.jpackage.test.Functional.ThrowingBiConsumer.toBiConsumer; import jdk.jpackage.test.Functional.ThrowingConsumer; +import static jdk.jpackage.test.Functional.ThrowingConsumer.toConsumer; import jdk.jpackage.test.Functional.ThrowingRunnable; - +import static jdk.jpackage.test.Functional.ThrowingSupplier.toSupplier; +import static jdk.jpackage.test.Functional.rethrowUnchecked; +import static jdk.jpackage.test.PackageType.LINUX; +import static jdk.jpackage.test.PackageType.LINUX_DEB; +import static jdk.jpackage.test.PackageType.LINUX_RPM; +import static jdk.jpackage.test.PackageType.MAC_DMG; +import static jdk.jpackage.test.PackageType.MAC_PKG; +import static jdk.jpackage.test.PackageType.NATIVE; +import static jdk.jpackage.test.PackageType.WINDOWS; +import static jdk.jpackage.test.PackageType.WIN_EXE; +import static jdk.jpackage.test.PackageType.WIN_MSI; /** @@ -82,7 +96,7 @@ public final class PackageTest extends RunnablePackageTest { public PackageTest forTypes(PackageType... types) { Collection<PackageType> newTypes; if (types == null || types.length == 0) { - newTypes = PackageType.NATIVE; + newTypes = NATIVE; } else { newTypes = Stream.of(types).collect(Collectors.toSet()); } @@ -122,7 +136,7 @@ public final class PackageTest extends RunnablePackageTest { namedInitializers.add(id); } currentTypes.forEach(type -> handlers.get(type).addInitializer( - ThrowingConsumer.toConsumer(v))); + toConsumer(v))); return this; } @@ -151,13 +165,12 @@ public final class PackageTest extends RunnablePackageTest { public PackageTest addBundleVerifier( ThrowingBiConsumer<JPackageCommand, Executor.Result> v) { currentTypes.forEach(type -> handlers.get(type).addBundleVerifier( - ThrowingBiConsumer.toBiConsumer(v))); + toBiConsumer(v))); return this; } public PackageTest addBundleVerifier(ThrowingConsumer<JPackageCommand> v) { - return addBundleVerifier( - (cmd, unused) -> ThrowingConsumer.toConsumer(v).accept(cmd)); + return addBundleVerifier((cmd, unused) -> toConsumer(v).accept(cmd)); } public PackageTest addBundlePropertyVerifier(String propertyName, @@ -184,7 +197,7 @@ public final class PackageTest extends RunnablePackageTest { } public PackageTest addBundleDesktopIntegrationVerifier(boolean integrated) { - forTypes(PackageType.LINUX, () -> { + forTypes(LINUX, () -> { LinuxHelper.addBundleDesktopIntegrationVerifier(this, integrated); }); return this; @@ -192,31 +205,25 @@ public final class PackageTest extends RunnablePackageTest { public PackageTest addInstallVerifier(ThrowingConsumer<JPackageCommand> v) { currentTypes.forEach(type -> handlers.get(type).addInstallVerifier( - ThrowingConsumer.toConsumer(v))); + toConsumer(v))); return this; } public PackageTest addUninstallVerifier(ThrowingConsumer<JPackageCommand> v) { currentTypes.forEach(type -> handlers.get(type).addUninstallVerifier( - ThrowingConsumer.toConsumer(v))); + toConsumer(v))); return this; } - public PackageTest setPackageInstaller(Consumer<JPackageCommand> v) { + public PackageTest disablePackageInstaller() { currentTypes.forEach( - type -> packageHandlers.get(type).installHandler = v); - return this; - } - - public PackageTest setPackageUnpacker( - BiFunction<JPackageCommand, Path, Path> v) { - currentTypes.forEach(type -> packageHandlers.get(type).unpackHandler = v); + type -> packageHandlers.get(type).installHandler = cmd -> {}); return this; } - public PackageTest setPackageUninstaller(Consumer<JPackageCommand> v) { + public PackageTest disablePackageUninstaller() { currentTypes.forEach( - type -> packageHandlers.get(type).uninstallHandler = v); + type -> packageHandlers.get(type).uninstallHandler = cmd -> {}); return this; } @@ -238,7 +245,7 @@ public final class PackageTest extends RunnablePackageTest { // running check of type of environment. addHelloAppInitializer(null); - forTypes(PackageType.LINUX, () -> { + forTypes(LINUX, () -> { LinuxHelper.addFileAssociationsVerifier(this, fa); }); @@ -317,11 +324,6 @@ public final class PackageTest extends RunnablePackageTest { return this; } - public PackageTest addLauncherName(String name) { - launcherNames.add(name); - return this; - } - public final static class Group extends RunnablePackageTest { public Group(PackageTest... tests) { handlers = Stream.of(tests) @@ -372,7 +374,7 @@ public final class PackageTest extends RunnablePackageTest { } private List<Consumer<Action>> createPackageTypeHandlers() { - return PackageType.NATIVE.stream() + return NATIVE.stream() .map(type -> { Handler handler = handlers.entrySet().stream() .filter(entry -> !entry.getValue().isVoid()) @@ -393,29 +395,39 @@ public final class PackageTest extends RunnablePackageTest { private Consumer<Action> createPackageTypeHandler( PackageType type, Handler handler) { - return ThrowingConsumer.toConsumer(new ThrowingConsumer<Action>() { + return toConsumer(new ThrowingConsumer<Action>() { @Override public void accept(Action action) throws Throwable { + if (terminated) { + throw new IllegalStateException(); + } + if (action == Action.FINALIZE) { - if (unpackDir != null && Files.isDirectory(unpackDir) - && !unpackDir.startsWith(TKit.workDir())) { - TKit.deleteDirectoryRecursive(unpackDir); + if (unpackDir != null) { + if (Files.isDirectory(unpackDir) + && !unpackDir.startsWith(TKit.workDir())) { + TKit.deleteDirectoryRecursive(unpackDir); + } + unpackDir = null; } + terminated = true; } if (aborted) { return; } - final JPackageCommand curCmd; - if (Set.of(Action.INITIALIZE, Action.CREATE).contains(action)) { - curCmd = cmd; - } else { - curCmd = cmd.createImmutableCopy(); - } + final Supplier<JPackageCommand> curCmd = () -> { + if (Set.of(Action.INITIALIZE, Action.CREATE).contains(action)) { + return cmd; + } else { + return cmd.createImmutableCopy(); + } + }; switch (action) { case UNPACK: { + cmd.setUnpackedPackageLocation(null); var handler = packageHandlers.get(type).unpackHandler; if (!(aborted = (handler == null))) { unpackDir = TKit.createTempDirectory( @@ -428,9 +440,10 @@ public final class PackageTest extends RunnablePackageTest { } case INSTALL: { + cmd.setUnpackedPackageLocation(null); var handler = packageHandlers.get(type).installHandler; if (!(aborted = (handler == null))) { - handler.accept(curCmd); + handler.accept(curCmd.get()); } break; } @@ -438,18 +451,19 @@ public final class PackageTest extends RunnablePackageTest { case UNINSTALL: { var handler = packageHandlers.get(type).uninstallHandler; if (!(aborted = (handler == null))) { - handler.accept(curCmd); + handler.accept(curCmd.get()); } break; } case CREATE: - handler.accept(action, curCmd); + cmd.setUnpackedPackageLocation(null); + handler.accept(action, curCmd.get()); aborted = (expectedJPackageExitCode != 0); return; default: - handler.accept(action, curCmd); + handler.accept(action, curCmd.get()); break; } @@ -462,6 +476,7 @@ public final class PackageTest extends RunnablePackageTest { private Path unpackDir; private boolean aborted; + private boolean terminated; private final JPackageCommand cmd = Functional.identity(() -> { JPackageCommand result = new JPackageCommand(); result.setDefaultInputOutput().setDefaultAppName(); @@ -535,13 +550,23 @@ public final class PackageTest extends RunnablePackageTest { verifyPackageUninstalled(cmd); } break; + + case PURGE: + if (expectedJPackageExitCode == 0) { + var bundle = cmd.outputBundle(); + if (toSupplier(() -> TKit.deleteIfExists(bundle)).get()) { + TKit.trace(String.format("Deleted [%s] package", + bundle)); + } + } + break; } } private void verifyPackageBundle(JPackageCommand cmd, Executor.Result result) { if (expectedJPackageExitCode == 0) { - if (PackageType.LINUX.contains(cmd.packageType())) { + if (LINUX.contains(cmd.packageType())) { LinuxHelper.verifyPackageBundleEssential(cmd); } } @@ -557,35 +582,85 @@ public final class PackageTest extends RunnablePackageTest { } TKit.trace(String.format(formatString, cmd.getPrintableCommandLine())); + Optional.ofNullable(cmd.unpackedPackageDirectory()).ifPresent( + unpackedDir -> { + verifyRootCountInUnpackedPackage(cmd, unpackedDir); + }); + if (!cmd.isRuntime()) { - if (PackageType.WINDOWS.contains(cmd.packageType()) + if (WINDOWS.contains(cmd.packageType()) && !cmd.isPackageUnpacked( "Not verifying desktop integration")) { // Check main launcher - new WindowsHelper.DesktopIntegrationVerifier(cmd, null); + WindowsHelper.verifyDesktopIntegration(cmd, null); // Check additional launchers - launcherNames.forEach(name -> { - new WindowsHelper.DesktopIntegrationVerifier(cmd, name); + cmd.addLauncherNames().forEach(name -> { + WindowsHelper.verifyDesktopIntegration(cmd, name); }); } } + cmd.assertAppLayout(); installVerifiers.forEach(v -> v.accept(cmd)); } + private void verifyRootCountInUnpackedPackage(JPackageCommand cmd, + Path unpackedDir) { + + final long expectedRootCount; + if (WINDOWS.contains(cmd.packageType())) { + // On Windows it is always two entries: + // installation home directory and MSI file + expectedRootCount = 2; + } else if (LINUX.contains(cmd.packageType())) { + Set<Path> roots = new HashSet<>(); + roots.add(Path.of("/").resolve(Path.of(cmd.getArgumentValue( + "--install-dir", () -> "/opt")).getName(0))); + if (cmd.hasArgument("--license-file")) { + switch (cmd.packageType()) { + case LINUX_RPM -> { + // License file is in /usr/share/licenses subtree + roots.add(Path.of("/usr")); + } + + case LINUX_DEB -> { + Path installDir = cmd.appInstallationDirectory(); + if (installDir.equals(Path.of("/")) + || installDir.startsWith("/usr")) { + // License file is in /usr/share/doc subtree + roots.add(Path.of("/usr")); + } + } + } + } + expectedRootCount = roots.size(); + } else { + expectedRootCount = 1; + } + + try ( var files = Files.list(unpackedDir)) { + TKit.assertEquals(expectedRootCount, files.count(), + String.format( + "Check the package has %d top installation directories", + expectedRootCount)); + } catch (IOException ex) { + rethrowUnchecked(ex); + } + } + private void verifyPackageUninstalled(JPackageCommand cmd) { TKit.trace(String.format("Verify uninstalled: %s", cmd.getPrintableCommandLine())); if (!cmd.isRuntime()) { TKit.assertPathExists(cmd.appLauncherPath(), false); - if (PackageType.WINDOWS.contains(cmd.packageType())) { + if (WINDOWS.contains(cmd.packageType())) { // Check main launcher - new WindowsHelper.DesktopIntegrationVerifier(cmd, null); + WindowsHelper.verifyDesktopIntegration(cmd, null); // Check additional launchers - launcherNames.forEach(name -> { - new WindowsHelper.DesktopIntegrationVerifier(cmd, name); + cmd.addLauncherNames().forEach(name -> { + WindowsHelper.verifyDesktopIntegration(cmd, name); }); } } @@ -610,18 +685,18 @@ public final class PackageTest extends RunnablePackageTest { private static Map<PackageType, PackageHandlers> createDefaultPackageHandlers() { HashMap<PackageType, PackageHandlers> handlers = new HashMap<>(); if (TKit.isLinux()) { - handlers.put(PackageType.LINUX_DEB, LinuxHelper.createDebPackageHandlers()); - handlers.put(PackageType.LINUX_RPM, LinuxHelper.createRpmPackageHandlers()); + handlers.put(LINUX_DEB, LinuxHelper.createDebPackageHandlers()); + handlers.put(LINUX_RPM, LinuxHelper.createRpmPackageHandlers()); } if (TKit.isWindows()) { - handlers.put(PackageType.WIN_MSI, WindowsHelper.createMsiPackageHandlers()); - handlers.put(PackageType.WIN_EXE, WindowsHelper.createExePackageHandlers()); + handlers.put(WIN_MSI, WindowsHelper.createMsiPackageHandlers()); + handlers.put(WIN_EXE, WindowsHelper.createExePackageHandlers()); } if (TKit.isOSX()) { - handlers.put(PackageType.MAC_DMG, MacHelper.createDmgPackageHandlers()); - handlers.put(PackageType.MAC_PKG, MacHelper.createPkgPackageHandlers()); + handlers.put(MAC_DMG, MacHelper.createDmgPackageHandlers()); + handlers.put(MAC_PKG, MacHelper.createPkgPackageHandlers()); } return handlers; @@ -633,7 +708,6 @@ public final class PackageTest extends RunnablePackageTest { private Map<PackageType, Handler> handlers; private Set<String> namedInitializers; private Map<PackageType, PackageHandlers> packageHandlers; - private final List<String> launcherNames = new ArrayList(); private final static File BUNDLE_OUTPUT_DIR; diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/RunnablePackageTest.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/RunnablePackageTest.java index 6f98cfc234d94a94f9f54aada3d118415ccfb882..a5cedc5c34ee902237886e896bfc9301a9940388 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/RunnablePackageTest.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/RunnablePackageTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -41,6 +41,12 @@ public abstract class RunnablePackageTest { .filter(Predicate.not(Action.INITIALIZE::equals)) .filter(Predicate.not(Action.FINALIZE::equals)) .collect(Collectors.toList())); + if (hasAction(Action.PURGE) && !actionList.contains(Action.PURGE)) { + // Default action list contains "purge" action meaning + // packages are not needed for further processing. + // Copy this behavior in custom action list. + actionList.add(Action.PURGE); + } } actionList.add(Action.FINALIZE); @@ -51,6 +57,10 @@ public abstract class RunnablePackageTest { runActions(actionGroups); } + public static boolean hasAction(Action a) { + return DEFAULT_ACTIONS.contains(a); + } + protected void runActions(List<Action[]> actions) { actions.forEach(this::runAction); } @@ -89,6 +99,10 @@ public abstract class RunnablePackageTest { * Uninstall package. */ UNINSTALL, + /** + * Purge package. + */ + PURGE, /** * Finalize test. */ 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 fb88d4cd21dc12e73d094f919af14c696934f9dd..1907c074504a3aeea38ad0e3c473918597649327 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, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 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 528973bea2298f29f3dc00595529ccde414229ad..d8bbdf113bce864747a9a02c27ce71e54ea55dfd 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/WindowsHelper.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/WindowsHelper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -58,7 +58,7 @@ public class WindowsHelper { private static Path getInstallationSubDirectory(JPackageCommand cmd) { cmd.verifyIsOfType(PackageType.WINDOWS); - return Path.of(cmd.getArgumentValue("--install-dir", () -> cmd.name())); + return Path.of(cmd.getArgumentValue("--install-dir", cmd::name)); } private static void runMsiexecWithRetries(Executor misexec) { @@ -66,7 +66,13 @@ public class WindowsHelper { for (int attempt = 0; attempt < 8; ++attempt) { result = misexec.executeWithoutExitCodeCheck(); - // The given Executor may either be of an msiexe command or an + if (result.exitCode == 1605) { + // ERROR_UNKNOWN_PRODUCT, attempt to uninstall not installed + // package + return; + } + + // The given Executor may either be of an msiexec command or an // unpack.bat script containing the msiexec command. In the later // case, when misexec returns 1618, the unpack.bat may return 1603 if ((result.exitCode == 1618) || (result.exitCode == 1603)) { @@ -91,16 +97,25 @@ public class WindowsHelper { PackageHandlers msi = new PackageHandlers(); msi.installHandler = cmd -> installMsi.accept(cmd, true); - msi.uninstallHandler = cmd -> installMsi.accept(cmd, false); + msi.uninstallHandler = cmd -> { + if (Files.exists(cmd.outputBundle())) { + installMsi.accept(cmd, false); + } + }; msi.unpackHandler = (cmd, destinationDir) -> { cmd.verifyIsOfType(PackageType.WIN_MSI); final Path unpackBat = destinationDir.resolve("unpack.bat"); final Path unpackDir = destinationDir.resolve( TKit.removeRootFromAbsolutePath( getInstallationRootDirectory(cmd))); + // Put msiexec in .bat file because can't pass value of TARGETDIR // property containing spaces through ProcessBuilder properly. - TKit.createTextFile(unpackBat, List.of(String.join(" ", List.of( + // Set folder permissions to allow msiexec unpack msi bundle. + TKit.createTextFile(unpackBat, List.of( + String.format("icacls \"%s\" /inheritance:e /grant Users:M", + destinationDir), + String.join(" ", List.of( "msiexec", "/a", String.format("\"%s\"", cmd.outputBundle().normalize()), @@ -125,10 +140,19 @@ public class WindowsHelper { PackageHandlers exe = new PackageHandlers(); exe.installHandler = cmd -> installExe.accept(cmd, true); - exe.uninstallHandler = cmd -> installExe.accept(cmd, false); + exe.uninstallHandler = cmd -> { + if (Files.exists(cmd.outputBundle())) { + installExe.accept(cmd, false); + } + }; return exe; } + static void verifyDesktopIntegration(JPackageCommand cmd, + String launcherName) { + new DesktopIntegrationVerifier(cmd, launcherName); + } + public static String getMsiProperty(JPackageCommand cmd, String propertyName) { cmd.verifyIsOfType(PackageType.WIN_MSI); return Executor.of("cscript.exe", "//Nologo") @@ -139,25 +163,72 @@ public class WindowsHelper { .executeAndGetOutput().stream().collect(Collectors.joining("\n")); } + public static String getExecutableDesciption(Path pathToExeFile) { + Executor exec = Executor.of("powershell", + "-NoLogo", + "-NoProfile", + "-Command", + "(Get-Item \\\"" + + pathToExeFile.toAbsolutePath() + + "\\\").VersionInfo | select FileDescription"); + + var lineIt = exec.dumpOutput().executeAndGetOutput().iterator(); + while (lineIt.hasNext()) { + var line = lineIt.next(); + if (line.trim().equals("FileDescription")) { + // Skip "---------------" and move to the description value + lineIt.next(); + return lineIt.next().trim(); + } + } + + throw new RuntimeException(String.format( + "Failed to get file description of [%s]", pathToExeFile)); + } + private static boolean isUserLocalInstall(JPackageCommand cmd) { return cmd.hasArgument("--win-per-user-install"); } - static class DesktopIntegrationVerifier { + private static class DesktopIntegrationVerifier { - DesktopIntegrationVerifier(JPackageCommand cmd, String name) { + DesktopIntegrationVerifier(JPackageCommand cmd, String launcherName) { cmd.verifyIsOfType(PackageType.WINDOWS); - this.cmd = cmd; - this.name = (name == null ? cmd.name() : name); + + name = Optional.ofNullable(launcherName).orElseGet(cmd::name); + + isUserLocalInstall = isUserLocalInstall(cmd); + + appInstalled = cmd.appLauncherPath(launcherName).toFile().exists(); + + desktopShortcutPath = Path.of(name + ".lnk"); + + startMenuShortcutPath = Path.of(cmd.getArgumentValue( + "--win-menu-group", () -> "Unknown"), name + ".lnk"); + + if (name.equals(cmd.name())) { + isWinMenu = cmd.hasArgument("--win-menu"); + isDesktop = cmd.hasArgument("--win-shortcut"); + } else { + var props = AdditionalLauncher.getAdditionalLauncherProperties(cmd, + launcherName); + isWinMenu = props.getPropertyBooleanValue("win-menu").orElseGet( + () -> cmd.hasArgument("--win-menu")); + isDesktop = props.getPropertyBooleanValue("win-shortcut").orElseGet( + () -> cmd.hasArgument("--win-shortcut")); + } + verifyStartMenuShortcut(); + verifyDesktopShortcut(); - verifyFileAssociationsRegistry(); + + Stream.of(cmd.getAllArgumentValues("--file-associations")).map( + Path::of).forEach(this::verifyFileAssociationsRegistry); } private void verifyDesktopShortcut() { - boolean appInstalled = cmd.appLauncherPath(name).toFile().exists(); - if (cmd.hasArgument("--win-shortcut")) { - if (isUserLocalInstall(cmd)) { + if (isDesktop) { + if (isUserLocalInstall) { verifyUserLocalDesktopShortcut(appInstalled); verifySystemDesktopShortcut(false); } else { @@ -170,10 +241,6 @@ public class WindowsHelper { } } - private Path desktopShortcutPath() { - return Path.of(name + ".lnk"); - } - private void verifyShortcut(Path path, boolean exists) { if (exists) { TKit.assertFileExists(path); @@ -185,19 +252,18 @@ public class WindowsHelper { private void verifySystemDesktopShortcut(boolean exists) { Path dir = Path.of(queryRegistryValueCache( SYSTEM_SHELL_FOLDERS_REGKEY, "Common Desktop")); - verifyShortcut(dir.resolve(desktopShortcutPath()), exists); + verifyShortcut(dir.resolve(desktopShortcutPath), exists); } private void verifyUserLocalDesktopShortcut(boolean exists) { Path dir = Path.of( queryRegistryValueCache(USER_SHELL_FOLDERS_REGKEY, "Desktop")); - verifyShortcut(dir.resolve(desktopShortcutPath()), exists); + verifyShortcut(dir.resolve(desktopShortcutPath), exists); } private void verifyStartMenuShortcut() { - boolean appInstalled = cmd.appLauncherPath(name).toFile().exists(); - if (cmd.hasArgument("--win-menu")) { - if (isUserLocalInstall(cmd)) { + if (isWinMenu) { + if (isUserLocalInstall) { verifyUserLocalStartMenuShortcut(appInstalled); verifySystemStartMenuShortcut(false); } else { @@ -210,13 +276,8 @@ public class WindowsHelper { } } - private Path startMenuShortcutPath() { - return Path.of(cmd.getArgumentValue("--win-menu-group", - () -> "Unknown"), name + ".lnk"); - } - private void verifyStartMenuShortcut(Path shortcutsRoot, boolean exists) { - Path shortcutPath = shortcutsRoot.resolve(startMenuShortcutPath()); + Path shortcutPath = shortcutsRoot.resolve(startMenuShortcutPath); verifyShortcut(shortcutPath, exists); if (!exists) { TKit.assertPathNotEmptyDirectory(shortcutPath.getParent()); @@ -234,13 +295,7 @@ public class WindowsHelper { USER_SHELL_FOLDERS_REGKEY, "Programs")), exists); } - private void verifyFileAssociationsRegistry() { - Stream.of(cmd.getAllArgumentValues("--file-associations")).map( - Path::of).forEach(this::verifyFileAssociationsRegistry); - } - private void verifyFileAssociationsRegistry(Path faFile) { - boolean appInstalled = cmd.appLauncherPath(name).toFile().exists(); try { TKit.trace(String.format( "Get file association properties from [%s] file", @@ -290,7 +345,12 @@ public class WindowsHelper { } } - private final JPackageCommand cmd; + private final Path desktopShortcutPath; + private final Path startMenuShortcutPath; + private final boolean isUserLocalInstall; + private final boolean appInstalled; + private final boolean isWinMenu; + private final boolean isDesktop; private final String name; } diff --git a/test/jdk/tools/jpackage/junit/jdk/jpackage/internal/OverridableResourceTest.java b/test/jdk/tools/jpackage/junit/jdk/jpackage/internal/OverridableResourceTest.java index 55a3c22dc9a83a759fd5e13099550abd41989e78..7b00a60acf06ff1cbf35b9ff2b4c92b251ca45e4 100644 --- a/test/jdk/tools/jpackage/junit/jdk/jpackage/internal/OverridableResourceTest.java +++ b/test/jdk/tools/jpackage/junit/jdk/jpackage/internal/OverridableResourceTest.java @@ -136,16 +136,16 @@ public class OverridableResourceTest { } private void testCustomtWithSubstitution(String defaultName) throws IOException { - final List<String> resourceData = List.of("A", "[BB]", "C", "Foo", - "GoodbyeHello"); + final List<String> resourceData = List.of("A", "[BB]", "C", "Foo", "Foo", + "GoodbyeHello", "_B"); final Path customFile = createCustomFile("foo", resourceData); final Map<String, String> substitutionData = new HashMap(Map.of("B", - "Bar", "Foo", "B")); + "Bar", "Foo", "B", "_B", "JJ")); substitutionData.put("Hello", null); final List<String> expectedResourceData = List.of("A", "[BarBar]", "C", - "B", "Goodbye"); + "Bar", "Bar", "Goodbye", "JJ"); final List<String> actualResourceData = convertToStringList(saveToFile( new OverridableResource(defaultName) diff --git a/test/jdk/tools/jpackage/macosx/SigningAppImageTest.java b/test/jdk/tools/jpackage/macosx/SigningAppImageTest.java index cd30b24f350a361a7b8d9cce933e49dc15dbde1e..1ebef43dad8e3ebd04b93b21835f64ed9f334ab2 100644 --- a/test/jdk/tools/jpackage/macosx/SigningAppImageTest.java +++ b/test/jdk/tools/jpackage/macosx/SigningAppImageTest.java @@ -24,6 +24,7 @@ import java.nio.file.Path; import jdk.jpackage.test.JPackageCommand; import jdk.jpackage.test.Annotations.Test; +import jdk.jpackage.test.AdditionalLauncher; /** * Tests generation of app image with --mac-sign and related arguments. Test will @@ -65,11 +66,17 @@ public class SigningAppImageTest { cmd.addArguments("--mac-sign", "--mac-signing-key-user-name", SigningBase.DEV_NAME, "--mac-signing-keychain", SigningBase.KEYCHAIN); + + AdditionalLauncher testAL = new AdditionalLauncher("testAL"); + testAL.applyTo(cmd); cmd.executeAndAssertHelloAppImageCreated(); Path launcherPath = cmd.appLauncherPath(); SigningBase.verifyCodesign(launcherPath, true); + Path testALPath = launcherPath.getParent().resolve("testAL"); + SigningBase.verifyCodesign(testALPath, true); + Path appImage = cmd.outputBundle(); SigningBase.verifyCodesign(appImage, true); SigningBase.verifySpctl(appImage, "exec"); diff --git a/test/jdk/tools/jpackage/macosx/SigningPackageTest.java b/test/jdk/tools/jpackage/macosx/SigningPackageTest.java index 351e354357b725847594c0b83b6ac3dbd304ae07..2fa9e452cfba123e026d9f41ec21bd06c53a8719 100644 --- a/test/jdk/tools/jpackage/macosx/SigningPackageTest.java +++ b/test/jdk/tools/jpackage/macosx/SigningPackageTest.java @@ -76,9 +76,13 @@ public class SigningPackageTest { private static void verifyAppImageInDMG(JPackageCommand cmd) { MacHelper.withExplodedDmg(cmd, dmgImage -> { Path launcherPath = dmgImage.resolve(Path.of("Contents", "MacOS", cmd.name())); - SigningBase.verifyCodesign(launcherPath, true); - SigningBase.verifyCodesign(dmgImage, true); - SigningBase.verifySpctl(dmgImage, "exec"); + // We will be called with all folders in DMG since JDK-8263155, but + // we only need to verify app. + if (dmgImage.endsWith(cmd.name() + ".app")) { + SigningBase.verifyCodesign(launcherPath, true); + SigningBase.verifyCodesign(dmgImage, true); + SigningBase.verifySpctl(dmgImage, "exec"); + } }); } diff --git a/test/jdk/tools/jpackage/run_tests.sh b/test/jdk/tools/jpackage/run_tests.sh index a5cb03fc3aa450d553ca678b6e5ba98f351867fb..2639f38cd681658414b24271ec0739e3ebbec86a 100644 --- a/test/jdk/tools/jpackage/run_tests.sh +++ b/test/jdk/tools/jpackage/run_tests.sh @@ -1,6 +1,6 @@ #!/bin/bash -# Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. +# 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 @@ -78,15 +78,25 @@ help_usage () echo " Optional, for jtreg tests debug purposes only." echo ' -l <logfile> - value for `jpackage.test.logfile` property.' echo " Optional, for jtreg tests debug purposes only." - echo " -m <mode> - mode to run jtreg tests." - echo ' Should be one of `create`, `update` or `print-default-tests`.' - echo ' Optional, default mode is `update`.' + echo " -m <mode> - mode to run jtreg tests. Supported values:" echo ' - `create`' echo ' Remove all package bundles from the output directory before running jtreg tests.' echo ' - `update`' echo ' Run jtreg tests and overrite existing package bundles in the output directory.' echo ' - `print-default-tests`' echo ' Print default list of packaging tests and exit.' + echo ' - `create-small-runtime`' + echo ' Create small Java runtime using <jdk>/bin/jlink command in the output directory.' + echo ' - `create-packages`' + echo ' Create packages.' + echo ' The script will set `jpackage.test.action` property.' + echo ' - `test-packages`' + echo ' Create and fully test packages. Will create, unpack, install, and uninstall packages.' + echo ' The script will set `jpackage.test.action` property.' + echo ' - `do-packages`' + echo " Create, unpack and verify packages." + echo ' The script will not set `jpackage.test.action` property.' + echo ' Optional, defaults are `update` and `create-packages`.' } error () @@ -133,8 +143,6 @@ exec_command () test_jdk= # Path to local copy of open jdk repo with jpackage jtreg tests -# hg clone http://hg.openjdk.java.net/jdk/sandbox -# cd sandbox; hg update -r JDK-8200758-branch open_jdk_with_jpackage_jtreg_tests=$(dirname $0)/../../../../ # Directory where to save artifacts for testing. @@ -152,12 +160,27 @@ mode=update # jtreg extra arguments declare -a jtreg_args -# Create packages only -jtreg_args+=("-Djpackage.test.action=create") - # run all tests run_all_tests= +test_actions= + +set_mode () +{ + case "$1" in + create-packages) test_actions='-Djpackage.test.action=create';; + test-packages) test_actions='-Djpackage.test.action=uninstall,create,unpack,verify-install,install,verify-install,uninstall,verify-uninstall,purge';; + do-packages) test_actions=;; + create-small-runtime) mode=$1;; + print-default-tests) mode=$1;; + create) mode=$1;; + update) mode=$1;; + *) fatal_with_help_usage 'Invalid value of -m option:' [$1];; + esac +} + +set_mode 'create-packages' + mapfile -t tests < <(find_all_packaging_tests) while getopts "vahdct:j:o:r:m:l:" argname; do @@ -171,7 +194,7 @@ while getopts "vahdct:j:o:r:m:l:" argname; do o) output_dir="$OPTARG";; r) runtime_dir="$OPTARG";; l) logfile="$OPTARG";; - m) mode="$OPTARG";; + m) set_mode "$OPTARG";; h) help_usage; exit 0;; ?) help_usage; exit 1;; esac @@ -201,6 +224,11 @@ if [ ! -e "$JAVA_HOME/bin/java" ]; then fatal JAVA_HOME variable is set to [$JAVA_HOME] value, but $JAVA_HOME/bin/java not found. fi +if [ "$mode" = "create-small-runtime" ]; then + exec_command "$test_jdk/bin/jlink" --add-modules java.base,java.datatransfer,java.xml,java.prefs,java.desktop --compress=2 --no-header-files --no-man-pages --strip-debug --output "$output_dir" + exit +fi + if [ -z "$JT_HOME" ]; then if [ -z "$JT_BUNDLE_URL" ]; then fatal 'JT_HOME or JT_BUNDLE_URL environment variable is not set. Link to JTREG bundle can be found at https://openjdk.java.net/jtreg/'. @@ -222,18 +250,12 @@ if [ -n "$logfile" ]; then jtreg_args+=("-Djpackage.test.logfile=$(to_native_path "$logfile")") fi -if [ "$mode" = create ]; then - true -elif [ "$mode" = update ]; then - true -else - fatal_with_help_usage 'Invalid value of -m option:' [$mode] -fi - if [ -z "$run_all_tests" ]; then jtreg_args+=(-Djpackage.test.SQETest=yes) fi +jtreg_args+=("$test_actions") + # Drop arguments separator [ "$1" != "--" ] || shift @@ -249,10 +271,10 @@ installJtreg () if [ ! -f "$jtreg_jar" ]; then exec_command mkdir -p "$workdir" if [[ ${jtreg_bundle: -7} == ".tar.gz" ]]; then - exec_command "(" cd "$workdir" "&&" wget "$jtreg_bundle" "&&" tar -xzf "$(basename $jtreg_bundle)" ";" rm -f "$(basename $jtreg_bundle)" ")" + exec_command "(" cd "$workdir" "&&" wget --no-check-certificate "$jtreg_bundle" "&&" tar -xzf "$(basename $jtreg_bundle)" ";" rm -f "$(basename $jtreg_bundle)" ")" else if [[ ${jtreg_bundle: -4} == ".zip" ]]; then - exec_command "(" cd "$workdir" "&&" wget "$jtreg_bundle" "&&" unzip "$(basename $jtreg_bundle)" ";" rm -f "$(basename $jtreg_bundle)" ")" + exec_command "(" cd "$workdir" "&&" wget --no-check-certificate "$jtreg_bundle" "&&" unzip "$(basename $jtreg_bundle)" ";" rm -f "$(basename $jtreg_bundle)" ")" else fatal 'Unsupported extension of JREG bundle ['$JT_BUNDLE_URL']. Only *.zip or *.tar.gz is supported.' fi diff --git a/test/jdk/tools/jpackage/share/AddLauncherTest.java b/test/jdk/tools/jpackage/share/AddLauncherTest.java index d1eca67b336d464f87994ec3b793cfa595e5c4f4..13d08e015eb9e83d90073aeb8ba33b269cb4879b 100644 --- a/test/jdk/tools/jpackage/share/AddLauncherTest.java +++ b/test/jdk/tools/jpackage/share/AddLauncherTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -40,7 +40,7 @@ import jdk.jpackage.test.CfgFile; * AddLauncherTest*.* installer. The output installer should provide the * same functionality as the default installer (see description of the default * installer in SimplePackageTest.java) plus install three extra application - * launchers. + * launchers with unique description ("LauncherName Description"). */ /* @@ -80,7 +80,8 @@ public class AddLauncherTest { PackageTest packageTest = new PackageTest().configureHelloApp(); packageTest.addInitializer(cmd -> { cmd.addArguments("--arguments", "Duke", "--arguments", "is", - "--arguments", "the", "--arguments", "King"); + "--arguments", "the", "--arguments", "King", + "--description", "AddLauncherTest Description"); }); new FileAssociations( @@ -89,14 +90,17 @@ public class AddLauncherTest { new AdditionalLauncher("Baz2") .setDefaultArguments() + .addRawProperties(Map.entry("description", "Baz2 Description")) .applyTo(packageTest); new AdditionalLauncher("foo") .setDefaultArguments("yep!") + .addRawProperties(Map.entry("description", "foo Description")) .applyTo(packageTest); new AdditionalLauncher("Bar") .setDefaultArguments("one", "two", "three") + .addRawProperties(Map.entry("description", "Bar Description")) .setIcon(GOLDEN_ICON) .applyTo(packageTest); diff --git a/test/jdk/tools/jpackage/share/MultiLauncherTwoPhaseTest.java b/test/jdk/tools/jpackage/share/MultiLauncherTwoPhaseTest.java index 5df3609e3babfdfe016f065588819090440d132d..b048d6db335ca9eedcfb0f48982d16348719da64 100644 --- a/test/jdk/tools/jpackage/share/MultiLauncherTwoPhaseTest.java +++ b/test/jdk/tools/jpackage/share/MultiLauncherTwoPhaseTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -69,8 +69,6 @@ public class MultiLauncherTwoPhaseTest { launcher2.applyTo(appImageCmd); PackageTest packageTest = new PackageTest() - .addLauncherName("bar") // Add launchers name for verification - .addLauncherName("foo") .addRunOnceInitializer(() -> appImageCmd.execute()) .addBundleDesktopIntegrationVerifier(true) .addInitializer(cmd -> { diff --git a/test/jdk/tools/jpackage/test_jpackage.sh b/test/jdk/tools/jpackage/test_jpackage.sh deleted file mode 100644 index c4b28020bc023655e4f76340b3833026ce541cbf..0000000000000000000000000000000000000000 --- a/test/jdk/tools/jpackage/test_jpackage.sh +++ /dev/null @@ -1,100 +0,0 @@ -#!/bin/bash - -# 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. - - -# -# Complete testing of jpackage platform-specific packaging. -# -# The script does the following: -# 1. Create packages. -# 2. Install created packages. -# 3. Verifies packages are installed. -# 4. Uninstall created packages. -# 5. Verifies packages are uninstalled. -# -# For the list of accepted command line arguments see `run_tests.sh` script. -# - -# Fail fast -set -e; set -o pipefail; - -# Script debug -dry_run=${JPACKAGE_TEST_DRY_RUN} - -# Default directory where jpackage should write bundle files -output_dir=~/jpackage_bundles - - -set_args () -{ - args=() - local arg_is_output_dir= - local arg_is_mode= - local output_dir_set= - local with_append_actions=yes - for arg in "$@"; do - if [ "$arg" == "-o" ]; then - arg_is_output_dir=yes - output_dir_set=yes - elif [ "$arg" == "-m" ]; then - arg_is_mode=yes - continue - elif [ "$arg" == '--' ]; then - append_actions - with_append_actions= - continue - elif ! case "$arg" in -Djpackage.test.action=*) false;; esac; then - continue - elif [ -n "$arg_is_output_dir" ]; then - arg_is_output_dir= - output_dir="$arg" - elif [ -n "$arg_is_mode" ]; then - arg_is_mode= - continue - fi - - args+=( "$arg" ) - done - [ -n "$output_dir_set" ] || args=( -o "$output_dir" "${args[@]}" ) - [ -z "$with_append_actions" ] || append_actions -} - - -append_actions () -{ - args+=( '--' '-Djpackage.test.action=create,install,verify-install,uninstall,verify-uninstall' ) -} - - -exec_command () -{ - if [ -n "$dry_run" ]; then - echo "$@" - else - eval "$@" - fi -} - -set_args "$@" -basedir="$(dirname $0)" -exec_command ${SHELL} "$basedir/run_tests.sh" -m create "${args[@]}" diff --git a/test/jdk/tools/jpackage/windows/WinInstallerIconTest.java b/test/jdk/tools/jpackage/windows/WinInstallerIconTest.java index e701b9517f87de0f7e0232d5ab6b22c54442de7f..450a98a40f46fd7d0d0fa3c13991d77d8ffdad3e 100644 --- a/test/jdk/tools/jpackage/windows/WinInstallerIconTest.java +++ b/test/jdk/tools/jpackage/windows/WinInstallerIconTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -21,12 +21,9 @@ * questions. */ -import java.awt.Graphics; -import java.awt.image.BufferedImage; -import java.io.IOException; import java.nio.file.Path; -import javax.swing.Icon; -import javax.swing.filechooser.FileSystemView; +import java.util.Optional; +import java.util.stream.Stream; import jdk.jpackage.test.PackageTest; import jdk.jpackage.test.Annotations.Test; import jdk.jpackage.test.JPackageCommand; @@ -46,43 +43,41 @@ import jdk.jpackage.test.TKit; * @build jdk.jpackage.test.* * @build WinInstallerIconTest * @requires (os.family == "windows") - * @requires !vm.debug * @modules jdk.jpackage/jdk.jpackage.internal * @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.Main * --jpt-run=WinInstallerIconTest */ -/* - * note: AWT can throw assertion from GetDiBits() extracting icon - * bits in fastdebug mode on windows headless systems. That is why - * we have @requires !vm.debug" above. - */ public class WinInstallerIconTest { @Test - public void test() throws IOException { + public void test() { Path customIcon = iconPath("icon"); - BufferedImage[] defaultInstallerIconImg = new BufferedImage[1]; - // Create installer with the default icon - long size1 = createInstaller(null, "WithDefaultIcon"); + var size1 = createInstaller(null, "WithDefaultIcon"); // Create installer with custom icon. - long size2 = createInstaller(customIcon, "WithCustomIcon"); + var size2 = createInstaller(customIcon, "WithCustomIcon"); // Create another installer with custom icon. - long size3 = createInstaller(customIcon, null); + var size3 = createInstaller(customIcon, null); - TKit.assertTrue(size2 < size1, "Installer 2 built with custom icon " + - "should be smaller than Installer 1 built with default icon"); + if (Stream.of(size1, size2, size3).allMatch(Optional::<Long>isEmpty)) { + TKit.trace( + "Not verifying sizes of installers because they were not created"); + return; + } + + TKit.assertTrue(size2.get() < size1.get(), "Check installer 2 built with custom icon " + + "is smaller than Installer 1 built with default icon"); - TKit.assertTrue(size3 < size1, "Installer 3 built with custom icon " + - "should be smaller than Installer 1 built with default icon"); + TKit.assertTrue(size3.get() < size1.get(), "Check installer 3 built with custom icon " + + "is smaller than Installer 1 built with default icon"); } - private long createInstaller(Path icon, String nameSuffix) throws IOException { + private Optional<Long> createInstaller(Path icon, String nameSuffix) { PackageTest test = new PackageTest() .forTypes(PackageType.WIN_EXE) @@ -96,26 +91,24 @@ public class WinInstallerIconTest { test.addInitializer(cmd -> { String name = cmd.name() + nameSuffix; cmd.setArgumentValue("--name", name); + // Create installer bundle in the test work directory, ignore + // value of jpackage.test.output system property. + cmd.setDefaultInputOutput(); }); } - Path installerExePath[] = new Path[1]; + Long installerExeByteCount[] = new Long[1]; test.addBundleVerifier(cmd -> { - installerExePath[0] = cmd.outputBundle(); + Path installerExePath = cmd.outputBundle(); + installerExeByteCount[0] = installerExePath.toFile().length(); + TKit.trace(String.format("Size of [%s] is %d bytes", + installerExePath, installerExeByteCount[0])); }); test.run(CREATE); - long size = 0L; - if (installerExePath[0] != null) { - size = installerExePath[0].toFile().length(); - TKit.trace(" installer: " + installerExePath[0] + " - size: " + size); - if (nameSuffix != null) { - TKit.deleteIfExists(installerExePath[0]); - } - } - return size; + return Optional.ofNullable(installerExeByteCount[0]); } private static Path iconPath(String name) { diff --git a/test/jdk/tools/jpackage/windows/WinL10nTest.java b/test/jdk/tools/jpackage/windows/WinL10nTest.java index 4171da208a46c1990860f36fb5839d8affff5840..4f7e726a3afef2525f7994a9eaa6de2674b88c83 100644 --- a/test/jdk/tools/jpackage/windows/WinL10nTest.java +++ b/test/jdk/tools/jpackage/windows/WinL10nTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -94,8 +94,11 @@ public class WinL10nTest { private final static Stream<String> getLightCommandLine( Executor.Result result) { - return result.getOutput().stream() - .filter(s -> s.trim().startsWith("light.exe")); + return result.getOutput().stream().filter(s -> { + s = s.trim(); + return s.startsWith("light.exe") || ((s.contains("\\light.exe ") + && s.contains(" -out "))); + }); } @Test diff --git a/test/jdk/tools/jpackage/windows/WinShortcutPromptTest.java b/test/jdk/tools/jpackage/windows/WinShortcutPromptTest.java index f64aefe8843d3f18b92d0aefe0477bd4d658ab70..33d9a661ca34cdef10ff8228d5d03287688576ed 100644 --- a/test/jdk/tools/jpackage/windows/WinShortcutPromptTest.java +++ b/test/jdk/tools/jpackage/windows/WinShortcutPromptTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -122,13 +122,13 @@ public class WinShortcutPromptTest { StringBuilder sb = new StringBuilder(cmd.name()); sb.append("With"); if (withShortcutPrompt) { - sb.append("ShortcutPrompt"); + sb.append("P"); } if (withStartMenuShortcut) { - sb.append("StartMenu"); + sb.append("M"); } if (withDesktopShortcut) { - sb.append("Desktop"); + sb.append("D"); } cmd.setArgumentValue("--name", sb.toString()); } diff --git a/test/jdk/tools/jpackage/windows/WinUpgradeUUIDTest.java b/test/jdk/tools/jpackage/windows/WinUpgradeUUIDTest.java index 0c233b0e652a2a5f0abed0a146b90b511d9fc507..968ed94b34570b745c9eb4b9f89093d2c93d2e03 100644 --- a/test/jdk/tools/jpackage/windows/WinUpgradeUUIDTest.java +++ b/test/jdk/tools/jpackage/windows/WinUpgradeUUIDTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -100,7 +100,7 @@ public class WinUpgradeUUIDTest { // It will be uninstalled automatically when the second // package will be installed. // However uninstall verification for the first package will be executed. - PackageTest test1 = init.get().setPackageUninstaller(cmd -> {}); + PackageTest test1 = init.get().disablePackageUninstaller(); PackageTest test2 = init.get().addInitializer(cmd -> { cmd.setArgumentValue("--app-version", "2.0"); diff --git a/test/jdk/tools/launcher/HelpFlagsTest.java b/test/jdk/tools/launcher/HelpFlagsTest.java index 173074ab9055f2ca9b351675cb62f05f1bab91c6..dda649b9f41ba2bc0178dbd5edb98a5286a3116f 100644 --- a/test/jdk/tools/launcher/HelpFlagsTest.java +++ b/test/jdk/tools/launcher/HelpFlagsTest.java @@ -151,6 +151,7 @@ public class HelpFlagsTest extends TestHelper { new ToolHelpSpec("rmiregistry", 0, 0, 0, 0, 0, 0, 1), // none, prints help message anyways. new ToolHelpSpec("serialver", 0, 0, 0, 0, 0, 0, 1), // none, prints help message anyways. new ToolHelpSpec("jpackage", 0, 1, 1, 0, 0, 1, 1), // -h, --help, + new ToolHelpSpec("jwebserver", 1, 1, 1, 0, 0, 1, 1), // -?, -h, --help }; // Returns corresponding object from jdkTools array. diff --git a/test/jdk/tools/launcher/VersionCheck.java b/test/jdk/tools/launcher/VersionCheck.java index 38a61b54198524af8282c490503570ef12089112..8ce636c4af7cffe74792e84302f3b46688fb6625 100644 --- a/test/jdk/tools/launcher/VersionCheck.java +++ b/test/jdk/tools/launcher/VersionCheck.java @@ -23,7 +23,7 @@ /** * @test - * @bug 6545058 6611182 8016209 8139986 8162746 + * @bug 6545058 6611182 8016209 8139986 8162746 8278967 * @summary validate and test -version, -fullversion, and internal, as well as * sanity checks if a tool can be launched. * @modules jdk.compiler @@ -61,7 +61,8 @@ public class VersionCheck extends TestHelper { "jmc.ini", "jweblauncher", "jpackage", - "ssvagent" + "ssvagent", + "jwebserver" }; // tools that do not accept -version @@ -125,9 +126,12 @@ public class VersionCheck extends TestHelper { static String getVersion0(boolean allLines, String... argv) { TestHelper.TestResult tr = doExec(argv); StringBuilder out = new StringBuilder(); - // remove the HotSpot line + // remove the HotSpot line and security manager deprecation warnings for (String x : tr.testOutput) { - if (allLines || !x.matches(".*Client.*VM.*|.*Server.*VM.*")) { + if (allLines || !x.matches(".*Client.*VM.*|" + + ".*Server.*VM.*|" + + "WARNING:.*terminally.*deprecated.*|" + + "WARNING:.*System::setSecurityManager.*")) { out = out.append(x + "\n"); } } diff --git a/test/jtreg-ext/requires/VMProps.java b/test/jtreg-ext/requires/VMProps.java index fac505a4585fc6aef03e8c0fa3b8ef3f573ff836..86a47925b6744d4dd77f157227200e7cc27043c7 100644 --- a/test/jtreg-ext/requires/VMProps.java +++ b/test/jtreg-ext/requires/VMProps.java @@ -102,6 +102,7 @@ public class VMProps implements Callable<Map<String, String>> { // vm.hasJFR is "true" if JFR is included in the build of the VM and // so tests can be executed. map.put("vm.hasJFR", this::vmHasJFR); + map.put("vm.hasDTrace", this::vmHasDTrace); map.put("vm.jvmti", this::vmHasJVMTI); map.put("vm.cpu.features", this::cpuFeatures); map.put("vm.pageSize", this::vmPageSize); @@ -368,6 +369,13 @@ public class VMProps implements Callable<Map<String, String>> { return "" + WB.isJVMTIIncluded(); } + /** + * @return "true" if the VM is compiled with DTrace + */ + protected String vmHasDTrace() { + return "" + WB.isDTraceIncluded(); + } + /** * @return true if compiler in use supports RTM and false otherwise. */ diff --git a/test/langtools/jdk/javadoc/doclet/checkStylesheetClasses/CheckStylesheetClasses.java b/test/langtools/jdk/javadoc/doclet/checkStylesheetClasses/CheckStylesheetClasses.java index 1cc649b2c272e2e6925883be7788dcf6f123518e..ca3d24aed70b77bd2f4b72ac0c2158e4f7e05bc7 100644 --- a/test/langtools/jdk/javadoc/doclet/checkStylesheetClasses/CheckStylesheetClasses.java +++ b/test/langtools/jdk/javadoc/doclet/checkStylesheetClasses/CheckStylesheetClasses.java @@ -139,9 +139,6 @@ public class CheckStylesheetClasses { "search-tag-desc-result", "search-tag-holder-result", "ui-autocomplete", "ui-autocomplete-category", "expanded"); - // snippet-related - removeAll(styleSheetNames, "bold", "highlighted", "italic"); - // very JDK specific styleSheetNames.remove("module-graph"); diff --git a/test/langtools/jdk/javadoc/doclet/testCustomTagletRegistration/ClassCastExceptionTaglet.java b/test/langtools/jdk/javadoc/doclet/testCustomTagletRegistration/ClassCastExceptionTaglet.java new file mode 100644 index 0000000000000000000000000000000000000000..3d6cd7392c93a3a5f9f37d9bfb3779242e894503 --- /dev/null +++ b/test/langtools/jdk/javadoc/doclet/testCustomTagletRegistration/ClassCastExceptionTaglet.java @@ -0,0 +1,50 @@ +/* + * 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 java.util.EnumSet; +import java.util.List; +import java.util.Set; + +import javax.lang.model.element.Element; + +import com.sun.source.doctree.DocTree; +import jdk.javadoc.doclet.Taglet; + +public class ClassCastExceptionTaglet /* does NOT implement jdk.javadoc.doclet.Taglet */ { + + public Set<Taglet.Location> getAllowedLocations() { + return EnumSet.allOf(Taglet.Location.class); + } + + public boolean isInlineTag() { + return false; + } + + public String getName() { + return "ClassCastExceptionTaglet"; + } + + public String toString(List<? extends DocTree> tags, Element element) { + return ""; + } +} diff --git a/test/langtools/jdk/javadoc/doclet/testCustomTagletRegistration/ExceptionInInitializerErrorTaglet.java b/test/langtools/jdk/javadoc/doclet/testCustomTagletRegistration/ExceptionInInitializerErrorTaglet.java new file mode 100644 index 0000000000000000000000000000000000000000..22bd088bbe61821e73e87bd282d83d58093b08af --- /dev/null +++ b/test/langtools/jdk/javadoc/doclet/testCustomTagletRegistration/ExceptionInInitializerErrorTaglet.java @@ -0,0 +1,60 @@ +/* + * 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 java.util.EnumSet; +import java.util.List; +import java.util.Set; + +import javax.lang.model.element.Element; + +import com.sun.source.doctree.DocTree; +import jdk.javadoc.doclet.Taglet; + +public class ExceptionInInitializerErrorTaglet implements Taglet { + + static { + if (true) { + throw new RuntimeException(); + } + } + + @Override + public Set<Taglet.Location> getAllowedLocations() { + return EnumSet.allOf(Taglet.Location.class); + } + + @Override + public boolean isInlineTag() { + return false; + } + + @Override + public String getName() { + return "ExceptionInInitializerErrorTaglet"; + } + + @Override + public String toString(List<? extends DocTree> tags, Element element) { + return ""; + } +} diff --git a/test/langtools/jdk/javadoc/doclet/testCustomTagletRegistration/InstantiationExceptionTaglet.java b/test/langtools/jdk/javadoc/doclet/testCustomTagletRegistration/InstantiationExceptionTaglet.java new file mode 100644 index 0000000000000000000000000000000000000000..b3995a033995757898ba8797f519abf78ff269b6 --- /dev/null +++ b/test/langtools/jdk/javadoc/doclet/testCustomTagletRegistration/InstantiationExceptionTaglet.java @@ -0,0 +1,54 @@ +/* + * 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 java.util.EnumSet; +import java.util.List; +import java.util.Set; + +import javax.lang.model.element.Element; + +import com.sun.source.doctree.DocTree; +import jdk.javadoc.doclet.Taglet; + +public abstract class InstantiationExceptionTaglet implements Taglet { + + @Override + public Set<Taglet.Location> getAllowedLocations() { + return EnumSet.allOf(Taglet.Location.class); + } + + @Override + public boolean isInlineTag() { + return false; + } + + @Override + public String getName() { + return "InstantiationExceptionTaglet"; + } + + @Override + public String toString(List<? extends DocTree> tags, Element element) { + return ""; + } +} diff --git a/test/langtools/jdk/javadoc/doclet/testCustomTagletRegistration/InvocationTargetExceptionTaglet.java b/test/langtools/jdk/javadoc/doclet/testCustomTagletRegistration/InvocationTargetExceptionTaglet.java new file mode 100644 index 0000000000000000000000000000000000000000..37faf0f2ab67c63410fb39d4d3984fff5e310616 --- /dev/null +++ b/test/langtools/jdk/javadoc/doclet/testCustomTagletRegistration/InvocationTargetExceptionTaglet.java @@ -0,0 +1,58 @@ +/* + * 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 java.util.EnumSet; +import java.util.List; +import java.util.Set; + +import javax.lang.model.element.Element; + +import com.sun.source.doctree.DocTree; +import jdk.javadoc.doclet.Taglet; + +public class InvocationTargetExceptionTaglet implements Taglet { + + public InvocationTargetExceptionTaglet() { + throw new RuntimeException(); + } + + @Override + public Set<Location> getAllowedLocations() { + return EnumSet.allOf(Location.class); + } + + @Override + public boolean isInlineTag() { + return false; + } + + @Override + public String getName() { + return "InvocationTargetExceptionTaglet"; + } + + @Override + public String toString(List<? extends DocTree> tags, Element element) { + return ""; + } +} diff --git a/test/langtools/jdk/javadoc/doclet/testCustomTagletRegistration/NoSuchMethodExceptionNoNullaryCtorTaglet.java b/test/langtools/jdk/javadoc/doclet/testCustomTagletRegistration/NoSuchMethodExceptionNoNullaryCtorTaglet.java new file mode 100644 index 0000000000000000000000000000000000000000..5f18ed460c041aa71854331bd16b3b843235f461 --- /dev/null +++ b/test/langtools/jdk/javadoc/doclet/testCustomTagletRegistration/NoSuchMethodExceptionNoNullaryCtorTaglet.java @@ -0,0 +1,56 @@ +/* + * 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 java.util.EnumSet; +import java.util.List; +import java.util.Set; + +import javax.lang.model.element.Element; + +import com.sun.source.doctree.DocTree; +import jdk.javadoc.doclet.Taglet; + +public class NoSuchMethodExceptionNoNullaryCtorTaglet implements Taglet { + + public NoSuchMethodExceptionNoNullaryCtorTaglet(Object obj) {} + + @Override + public Set<Location> getAllowedLocations() { + return EnumSet.allOf(Taglet.Location.class); + } + + @Override + public boolean isInlineTag() { + return false; + } + + @Override + public String getName() { + return "NoSuchMethodExceptionNoNullaryCtorTaglet"; + } + + @Override + public String toString(List<? extends DocTree> tags, Element element) { + return ""; + } +} diff --git a/test/langtools/jdk/javadoc/doclet/testCustomTagletRegistration/NoSuchMethodExceptionPrivateCtorTaglet.java b/test/langtools/jdk/javadoc/doclet/testCustomTagletRegistration/NoSuchMethodExceptionPrivateCtorTaglet.java new file mode 100644 index 0000000000000000000000000000000000000000..cbf71d6021e0a519193f3c8912bbbd0df1afe8db --- /dev/null +++ b/test/langtools/jdk/javadoc/doclet/testCustomTagletRegistration/NoSuchMethodExceptionPrivateCtorTaglet.java @@ -0,0 +1,56 @@ +/* + * 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 java.util.EnumSet; +import java.util.List; +import java.util.Set; + +import javax.lang.model.element.Element; + +import com.sun.source.doctree.DocTree; +import jdk.javadoc.doclet.Taglet; + +public class NoSuchMethodExceptionPrivateCtorTaglet implements Taglet { + + private NoSuchMethodExceptionPrivateCtorTaglet() {} + + @Override + public Set<Taglet.Location> getAllowedLocations() { + return EnumSet.allOf(Taglet.Location.class); + } + + @Override + public boolean isInlineTag() { + return false; + } + + @Override + public String getName() { + return "NoSuchMethodExceptionPrivateCtorTaglet"; + } + + @Override + public String toString(List<? extends DocTree> tags, Element element) { + return ""; + } +} diff --git a/test/langtools/jdk/javadoc/doclet/testCustomTagletRegistration/TestRegistrationErrors.java b/test/langtools/jdk/javadoc/doclet/testCustomTagletRegistration/TestRegistrationErrors.java new file mode 100644 index 0000000000000000000000000000000000000000..8d2d95d6a639e055fbbbd1c8d00fefa65d5173a0 --- /dev/null +++ b/test/langtools/jdk/javadoc/doclet/testCustomTagletRegistration/TestRegistrationErrors.java @@ -0,0 +1,86 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8206181 + * @library ../../lib + * @modules jdk.javadoc/jdk.javadoc.internal.tool + * @build javadoc.tester.* * + * @run main TestRegistrationErrors + */ + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Stream; + +import javadoc.tester.JavadocTester; + +public class TestRegistrationErrors extends JavadocTester { + + public static void main(String... args) throws Exception { + TestRegistrationErrors tester = new TestRegistrationErrors(); + tester.runTests(); + } + + @Test + public void test() throws Exception { + try (Stream<Path> tagletClasses = findTagletClasses()) { + tagletClasses.forEach(p -> { + String tagletName = getTagletName(p); + javadoc("-d", "out-" + tagletName, // a directory per taglet + "-tagletpath", System.getProperty("test.classes"), + "-taglet", tagletName, + testSrc("TestRegistrationErrors.java")); // specify this file + checkExit(Exit.ERROR); + new OutputChecker(Output.OUT).checkUnique(Pattern.compile("thrown while trying to register Taglet")); + checkNoCrashes(); + }); + } + } + + private static Stream<Path> findTagletClasses() throws IOException { + var path = Path.of(System.getProperty("test.classes")); + return Files.find(path, Integer.MAX_VALUE, + (p, a) -> a.isRegularFile() && p.toString().endsWith("Taglet.class")); + } + + private static String getTagletName(Path tagletClass) { + Path fileName = tagletClass.getFileName(); + return fileName.toString().substring(0, fileName.toString().lastIndexOf('.')); + } + + protected void checkNoCrashes() { + checking("check crashes"); + Matcher matcher = Pattern.compile("\\s*at.*\\(.*\\.java:\\d+\\)") + .matcher(getOutput(Output.STDERR)); + if (!matcher.find()) { + passed(""); + } else { + failed("Looks like a stacktrace: " + matcher.group()); + } + } +} diff --git a/test/langtools/jdk/javadoc/doclet/testDateOption/TestDateOption.java b/test/langtools/jdk/javadoc/doclet/testDateOption/TestDateOption.java new file mode 100644 index 0000000000000000000000000000000000000000..411e37efab93de7ecd5d065bbb39797032270928 --- /dev/null +++ b/test/langtools/jdk/javadoc/doclet/testDateOption/TestDateOption.java @@ -0,0 +1,147 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8272984 + * @summary javadoc support for SOURCE_DATE_EPOCH + * @library /tools/lib ../../lib + * @modules jdk.javadoc/jdk.javadoc.internal.tool + * @build toolbox.ToolBox javadoc.tester.* + * @run main TestDateOption + */ + +import java.nio.file.Path; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.util.Date; +import java.util.Locale; + +import javadoc.tester.JavadocTester; +import toolbox.ToolBox; + +public class TestDateOption extends JavadocTester { + + /** + * The entry point of the test. + * + * @param args the array of command line arguments + * @throws Exception if the test fails + */ + public static void main(String... args) throws Exception { + TestDateOption tester = new TestDateOption(); + tester.runTests(m -> new Object[] { Path.of(m.getName()) }); + } + + ToolBox tb = new ToolBox(); + + @Test + public void testDateOption(Path base) throws Exception { + + ZonedDateTime zdt = ZonedDateTime.now(); // uses current date, time, timezone etc + // adjust the calendar to some date before the default used by javadoc (i.e. today/now) + // set a specific time, such as 10 to 3. (Rupert Brooke, Grantchester) + ZonedDateTime testDate = zdt.minusDays(100) + .withHour(14) + .withMinute(50) + .withSecond(0); + + out.println("Test Date: '" + testDate + "'"); + + Path srcDir = base.resolve("src"); + tb.writeJavaFiles(srcDir, """ + package p; + /** Comment. */ + public interface I { } + """); + Path outDir = base.resolve("out"); + + javadoc("-d", outDir.toString(), + "-sourcepath", srcDir.toString(), + "--date", testDate.toString(), + "p"); + checkExit(Exit.OK); + + int featureVersion = Runtime.version().feature(); + + // The following format is as used by javadoc; it is the historical format used by Date.toString() + DateTimeFormatter fmt = + DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss zzz yyyy").withLocale(Locale.US); + String generatedByStamp = testDate.format(fmt); + String generatedBy = String.format("<!-- Generated by javadoc (%d) on %s -->", + featureVersion, generatedByStamp); + + DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd"); + String dcCreatedStamp = testDate.format(dateFormat); + String dcCreated = String.format(""" + <meta name="dc.created" content="%s">""", + dcCreatedStamp); + + // check the timestamps in all generated HTML files + for (Path file : tb.findFiles(".html", outputDir)) { + checkOutput(outputDir.relativize(file).toString(), true, + generatedBy, + dcCreated); + } + } + + @Test + public void testBadDateOption(Path base) throws Exception { + Path srcDir = base.resolve("src"); + tb.writeJavaFiles(srcDir, """ + package p; + /** Comment. */ + public interface I { } + """); + Path outDir = base.resolve("out"); + + javadoc("-d", outDir.toString(), + "-sourcepath", srcDir.toString(), + "--date", "NOT A DATE", + "p"); + checkExit(Exit.CMDERR); + + checkOutput(Output.OUT, true, + "error: value for '--date' not valid: NOT A DATE"); + } + + @Test + public void testInvalidDateOption(Path base) throws Exception { + Path srcDir = base.resolve("src"); + tb.writeJavaFiles(srcDir, """ + package p; + /** Comment. */ + public interface I { } + """); + Path outDir = base.resolve("out"); + + javadoc("-d", outDir.toString(), + "-sourcepath", srcDir.toString(), + "--date", new Date(0).toInstant().toString(), + "p"); + checkExit(Exit.CMDERR); + + checkOutput(Output.OUT, true, + "error: value for '--date' out of range: 1970-01-01T00:00:00Z"); + } +} \ No newline at end of file diff --git a/test/langtools/jdk/javadoc/doclet/testDocletExample/TestDocletExample.java b/test/langtools/jdk/javadoc/doclet/testDocletExample/TestDocletExample.java new file mode 100644 index 0000000000000000000000000000000000000000..80e61d22d48637fc1f055811fd66959daf7ec23d --- /dev/null +++ b/test/langtools/jdk/javadoc/doclet/testDocletExample/TestDocletExample.java @@ -0,0 +1,138 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8272944 + * @summary Use snippets in jdk.javadoc documentation + * @library /tools/lib ../../lib + * @modules jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.main + * jdk.javadoc/jdk.javadoc.internal.tool + * @build snippets.SnippetUtils toolbox.JavacTask toolbox.ToolBox javadoc.tester.* + * @run main TestDocletExample + */ + +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.spi.ToolProvider; +import java.util.stream.Stream; + +import snippets.SnippetUtils; +import toolbox.Task; +import toolbox.TestRunner; +import toolbox.ToolBox; + +import javax.tools.DiagnosticCollector; +import javax.tools.JavaFileObject; + + +public class TestDocletExample extends TestRunner { + public static void main(String... args) throws Exception { + var t = new TestDocletExample(); + t.runTests(m -> new Object[] { Path.of(m.getName()) }); + } + + SnippetUtils snippets = new SnippetUtils("jdk.javadoc"); + ToolBox tb = new ToolBox(); + + TestDocletExample() { + super(System.out); + } + + @Test + public void testEntryPoint(Path base) throws Exception { + var docletPkg = snippets.getElements().getPackageElement("jdk.javadoc.doclet"); + var dc = snippets.getDocTrees().getDocCommentTree(docletPkg); + var entryPointSnippet = snippets.getSnippetById(dc, "entry-point"); + var entryPointCode = entryPointSnippet.getBody().getBody(); + var code = """ + class C { + %s { } + } + """.formatted(entryPointCode); + DiagnosticCollector<JavaFileObject> collector = new DiagnosticCollector<>(); + snippets.parse(code, null, collector); + var diags = collector.getDiagnostics(); + if (diags.isEmpty()) { + out.println("parsed entry point snippet"); + } else { + diags.forEach(out::println); + throw new Exception("parse failed"); + } + } + + @Test + public void testDocletExample(Path base) throws Exception { + + // get source code + var docletPkg = snippets.getElements().getPackageElement("jdk.javadoc.doclet"); + var dc = snippets.getDocTrees().getDocCommentTree(docletPkg); + var exampleSnippet = snippets.getSnippetById(dc, "Example.java"); + var exampleCode = exampleSnippet.getBody().getBody(); + + // compile it + Path src = base.resolve("src"); + Path classes = base.resolve("classes"); + Files.createDirectories(classes); + + tb.writeJavaFiles(src, exampleCode); + new toolbox.JavacTask(tb) + .outdir(classes) + .files(tb.findJavaFiles(src)) + .run(Task.Expect.SUCCESS) + .writeAll(); + + // get demo command + var cmdSnippet = snippets.getSnippetById(dc, "run-doclet"); + var cmd = cmdSnippet.getBody().getBody() + .replaceAll("\\s+//.*", "") // remove markup + .replaceAll("\\\\\n", " ") // join lines + .trim(); + out.println(cmd); + + tb.writeFile(src.resolve("overview.html"), + """ + <!doctype html> + <html><title>Overview + + Overview + + + """); + + var cmdWords = Stream.of(cmd.split("\\s+")) + .map(s -> s.replace("source-location", src.toString())) + .map(s -> s.replace("doclet-classes", classes.toString())) + .toList(); + var toolName = cmdWords.get(0); + var toolArgs = cmdWords.subList(1, cmdWords.size()); + + ToolProvider tool = ToolProvider.findFirst(toolName) + .orElseThrow(() -> new Exception("tool not found: " + toolName)); + int rc = tool.run(System.out, System.err, toolArgs.toArray(new String[0])); + if (rc != 0) { + throw new Exception("ecommand return code: " + rc); + } + } +} diff --git a/test/langtools/jdk/javadoc/doclet/testGenericTypeLink/TestGenericTypeLink.java b/test/langtools/jdk/javadoc/doclet/testGenericTypeLink/TestGenericTypeLink.java index fbfbb5f39782849d97592a3e38e2a48d9379128c..1f0ea233288abb63f76f0b043cb51ba1aa71db61 100644 --- a/test/langtools/jdk/javadoc/doclet/testGenericTypeLink/TestGenericTypeLink.java +++ b/test/langtools/jdk/javadoc/doclet/testGenericTypeLink/TestGenericTypeLink.java @@ -166,18 +166,48 @@ public class TestGenericTypeLink extends JavadocTester { checkExit(Exit.ERROR); checkOutput("pkg2/B.html", true, """ -

          java.util.Foo<String> - Baz<Object> - #b(List<Integer>)
          """, +
          +
          + invalid @link +
          java.util.Foo<String>
          +
          + + \s +
          + invalid @linkplain +
          Baz<Object>
          +
          + + \s +
          + invalid @link +
          #b(List<Integer>)
          +
          +
          """, """
          See Also:
            -
          • java.util.List<Bar>
          • -
          • Baz<Object, String>
          • -
          • B#b(List<Baz>)
          • +
          • +
            + invalid @see +
            java.util.List<Bar>
            +
            +
          • +
          • +
            + invalid @see +
            Baz<Object, String>
            +
            +
          • +
          • +
            + invalid @see +
            B#b(List<Baz>)
            +
            +
          """); diff --git a/test/langtools/jdk/javadoc/doclet/testInherited/TestInherited.java b/test/langtools/jdk/javadoc/doclet/testInherited/TestInherited.java index 21391201a032c6ab86792bfe0b1338c43e294a9e..0806278b43d28d18951255915aa3189f52671191 100644 --- a/test/langtools/jdk/javadoc/doclet/testInherited/TestInherited.java +++ b/test/langtools/jdk/javadoc/doclet/testInherited/TestInherited.java @@ -69,11 +69,11 @@ public class TestInherited extends JavadocTester { checkExit(Exit.OK); checkOutput("BadParam.Base.html", true, """
          Parameters:
          -
          i - a < b
          +
          i - a invalid input: '<' b
          """); checkOutput("BadParam.Sub.html", true, """
          Parameters:
          -
          i - a < b
          +
          i - a invalid input: '<' b
          """); } @@ -101,11 +101,11 @@ public class TestInherited extends JavadocTester { checkExit(Exit.OK); checkOutput("BadReturn.Base.html", true, """
          Returns:
          -
          a < b
          +
          a invalid input: '<' b
          """); checkOutput("BadReturn.Sub.html", true, """
          Returns:
          -
          a < b
          +
          a invalid input: '<' b
          """); } @@ -147,16 +147,36 @@ public class TestInherited extends JavadocTester { src.resolve("BadReference.java").toString()); checkExit(Exit.OK); checkOutput("BadReference.Intf.html", true, """ -
          NonExistingClass
          +
          +
          + invalid @link +
          NonExistingClass
          +
          +
          """); checkOutput("BadReference.Impl1.html", true, """ -
          NonExistingClass
          +
          +
          + invalid @link +
          NonExistingClass
          +
          +
          """); checkOutput("BadReference.Impl2.html", true, """ -
          NonExistingClass
          +
          +
          + invalid @link +
          NonExistingClass
          +
          +
          """); checkOutput("BadReference.Impl3.html", true, """ -
          NonExistingClass
          +
          +
          + invalid @link +
          NonExistingClass
          +
          +
          """); } } diff --git a/test/langtools/jdk/javadoc/doclet/testInterface/TestInterface.java b/test/langtools/jdk/javadoc/doclet/testInterface/TestInterface.java index a435b831e7e33ed00f3a4aaf6252e50049015864..83530f323688a2af7759e5ef0b7811b2cf0ec2bd 100644 --- a/test/langtools/jdk/javadoc/doclet/testInterface/TestInterface.java +++ b/test/langtools/jdk/javadoc/doclet/testInterface/TestInterface.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -45,8 +45,8 @@ * In Child.html * Specified by: method in interface * Overrides: method in class Parent - * In otherwords the TypeParameter in scope should be used ex: Interface, Parent - and Child + * In other words the TypeParameter in scope should be used ex: Interface, Parent + * and Child */ import javadoc.tester.JavadocTester; diff --git a/test/langtools/jdk/javadoc/doclet/testLinkOption/TestLinkOptionWithModule.java b/test/langtools/jdk/javadoc/doclet/testLinkOption/TestLinkOptionWithModule.java index c12432322ff908277d46ff0b455b8a7e7d412baa..4f7602251d8e14cbf0b461ff5f496a297222f914 100644 --- a/test/langtools/jdk/javadoc/doclet/testLinkOption/TestLinkOptionWithModule.java +++ b/test/langtools/jdk/javadoc/doclet/testLinkOption/TestLinkOptionWithModule.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -23,7 +23,7 @@ /* * @test - * @bug 8205593 8240169 + * @bug 8205593 8240169 8274639 * @summary Javadoc -link makes broken links if module name matches package name * @library /tools/lib ../../lib * @modules @@ -71,6 +71,7 @@ public class TestLinkOptionWithModule extends JavadocTester { "--module", "com.ex1"); javadoc("-d", out2.toString(), + "-Werror", "-Xdoclint:-missing", "--module-source-path", moduleSrc.toString(), "--module", "com.ex2", "-link", "../" + out1.getFileName()); @@ -109,13 +110,14 @@ public class TestLinkOptionWithModule extends JavadocTester { "-subpackages", "com.ex1"); javadoc("-d", out2.toString(), + "--link-modularity-mismatch", "warn", "--module-source-path", moduleSrc.toString(), "--module", "com.ex2", "-link", "../" + out1.getFileName()); checkExit(Exit.OK); checkOutput(Output.OUT, true, - "The code being documented uses modules but the packages defined " + "warning: The code being documented uses modules but the packages defined " + "in ../out3a/ are in the unnamed module"); checkOutput("com.ex2/com/ex2/B.html", true, """ @@ -137,13 +139,62 @@ public class TestLinkOptionWithModule extends JavadocTester { checkExit(Exit.OK); checkOutput(Output.OUT, true, - "The code being documented uses packages in the unnamed module, but the packages defined " + "warning: The code being documented uses packages in the unnamed module, but the packages defined " + "in ../out4a/ are in named modules"); checkOutput("com/ex2/B.html", true, """ A"""); } + @Test + public void testModuleLinkedToPackageNoWarning(Path base) throws Exception { + Path out1 = base.resolve("out5a"), out2 = base.resolve("out5b"); + + javadoc("-d", out1.toString(), + "-sourcepath", packageSrc.toString(), + "-subpackages", "com.ex1"); + + javadoc("-d", out2.toString(), + "--link-modularity-mismatch", "info", + "-Werror", "-Xdoclint:-missing", + "--module-source-path", moduleSrc.toString(), + "--module", "com.ex2", + "-link", "../" + out1.getFileName()); + + checkExit(Exit.OK); + checkOutput(Output.OUT, true, + "The code being documented uses modules but the packages defined " + + "in ../out5a/ are in the unnamed module"); + checkOutput("com.ex2/com/ex2/B.html", true, + """ + A"""); + } + + @Test + public void testPackageLinkedToModuleNoWarning(Path base) throws Exception { + Path out1 = base.resolve("out6a"), out2 = base.resolve("out6b"); + + javadoc("-d", out1.toString(), + "--module-source-path", moduleSrc.toString(), + "--module", "com.ex1"); + + javadoc("-d", out2.toString(), + "--link-modularity-mismatch", "info", + "-quiet", // should not print modularity mismatch info + "-Werror", "-Xdoclint:-missing", + "-sourcepath", packageSrc.toString(), + "-subpackages", "com.ex2", + "-link", "../" + out1.getFileName()); + + checkExit(Exit.OK); + // Modularity mismatch diagnostic should not be printed because we're runnning with -quiet option + checkOutput(Output.OUT, false, + "The code being documented uses packages in the unnamed module, but the packages defined " + + "in ../out6a/ are in named modules"); + checkOutput("com/ex2/B.html", true, + """ + A"""); + } void initModulesAndPackages() throws Exception{ new ModuleBuilder(tb, "com.ex1") diff --git a/test/langtools/jdk/javadoc/doclet/testNonInlineHtmlTagRemoval/TestNonInlineHtmlTagRemoval.java b/test/langtools/jdk/javadoc/doclet/testNonInlineHtmlTagRemoval/TestNonInlineHtmlTagRemoval.java index 35a25e29bf26310e930c68274e9521ffbf55dbf9..b0b54bbdd6c2e11d638f59ba83221199bd46ecb9 100644 --- a/test/langtools/jdk/javadoc/doclet/testNonInlineHtmlTagRemoval/TestNonInlineHtmlTagRemoval.java +++ b/test/langtools/jdk/javadoc/doclet/testNonInlineHtmlTagRemoval/TestNonInlineHtmlTagRemoval.java @@ -85,6 +85,6 @@ public class TestNonInlineHtmlTagRemoval extends JavadocTester { checkOutput("Negative.html", true, """ -
          case1: A hanging < : xx<
          """); +
          case1: A hanging < : xxinvalid input: '<'
          """); } } diff --git a/test/langtools/jdk/javadoc/doclet/testOverriddenMethods/TestOverrideMethods.java b/test/langtools/jdk/javadoc/doclet/testOverriddenMethods/TestOverrideMethods.java index 785ddd5072fcbfb6dfbcddb2dcd7450a4c935e74..4e358149669c2fc81cfc75b2e6df36a9d04803f7 100644 --- a/test/langtools/jdk/javadoc/doclet/testOverriddenMethods/TestOverrideMethods.java +++ b/test/langtools/jdk/javadoc/doclet/testOverriddenMethods/TestOverrideMethods.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -23,7 +23,7 @@ /* * @test - * @bug 8157000 8192850 8182765 8223607 8261976 + * @bug 8157000 8192850 8182765 8223607 8261976 8281376 * @summary test the behavior of --override-methods option * @library ../../lib * @modules jdk.javadoc/jdk.javadoc.internal.tool @@ -569,4 +569,93 @@ public class TestOverrideMethods extends JavadocTester {
          something
          """); } + + @Test + public void testPolymorphicDetail() { + javadoc("-d", "out-polymorphic-detail", + "-sourcepath", testSrc, + "--override-methods=detail", + "pkg8"); + + checkExit(Exit.OK); + + checkOutput("pkg8/C.html", true, + """ +
          Overrides:
          +
          m1 in class \ + P
          """); + + checkOutput("pkg8/C.html", true, + """ +
          Overrides:
          +
          m2 in class \ + P
          """); + + checkOutput("pkg8/C.html", true, + """ +
          Overrides:
          +
          m3 in class \ + P
          """); + } + + @Test // results should be the same as that of "detail" + public void testPolymorphicDefault() { + javadoc("-d", "out-polymorphic-default", + "-sourcepath", testSrc, + "pkg8"); + + checkExit(Exit.OK); + + checkOutput("pkg8/C.html", true, + """ +
          Overrides:
          +
          m1 in class \ + P
          """); + + checkOutput("pkg8/C.html", true, + """ +
          Overrides:
          +
          m2 in class \ + P
          """); + + checkOutput("pkg8/C.html", true, + """ +
          Overrides:
          +
          m3 in class \ + P
          """); + } + + @Test + public void testPolymorphicSummary() { + javadoc("-d", "out-polymorphic-summary", + "-sourcepath", testSrc, + "--override-methods=summary", + "pkg8"); + + checkExit(Exit.OK); + + checkOutput("pkg8/C.html", true, + """ +
          Overrides:
          +
          m1 in class \ + GP
          """); + + checkOutput("pkg8/C.html", true, + """ +
          Overrides:
          +
          m2 in class \ + GP
          """); + + checkOutput("pkg8/C.html", true, + """ +
          Overrides:
          +
          m3 in class \ + GP
          """); + + checkOutput("pkg8/C.html", false, + """ +
          Overrides:
          +
          m1 in class \ + P
          """); + } } diff --git a/test/langtools/jdk/javadoc/doclet/testOverriddenMethods/pkg3/I2.java b/test/langtools/jdk/javadoc/doclet/testOverriddenMethods/pkg3/I2.java index 8d1195273469faa5bb30bdad70bd35360f672c08..8c104391d86979b50a9414a93df22664142fce97 100644 --- a/test/langtools/jdk/javadoc/doclet/testOverriddenMethods/pkg3/I2.java +++ b/test/langtools/jdk/javadoc/doclet/testOverriddenMethods/pkg3/I2.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -25,6 +25,6 @@ package pkg3; public interface I2 { - public void foo(); + public void foo(); } diff --git a/test/langtools/jdk/javadoc/doclet/testOverriddenMethods/pkg3/I3.java b/test/langtools/jdk/javadoc/doclet/testOverriddenMethods/pkg3/I3.java index 59015817cd6d1ae841db7c3d989c57dcdbdec46f..5583ea96fc7c85bbd31a9ee4157f7876b2b8d793 100644 --- a/test/langtools/jdk/javadoc/doclet/testOverriddenMethods/pkg3/I3.java +++ b/test/langtools/jdk/javadoc/doclet/testOverriddenMethods/pkg3/I3.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -25,6 +25,6 @@ package pkg3; public interface I3 extends I4 { - public void foo(); + public void foo(); } diff --git a/test/langtools/jdk/javadoc/doclet/testOverriddenMethods/pkg3/I4.java b/test/langtools/jdk/javadoc/doclet/testOverriddenMethods/pkg3/I4.java index b0f52eaa91cb3e72b1b92acd25ed67f43a989835..6633fe1de166e4acdc12e43f4bfed990c466a5eb 100644 --- a/test/langtools/jdk/javadoc/doclet/testOverriddenMethods/pkg3/I4.java +++ b/test/langtools/jdk/javadoc/doclet/testOverriddenMethods/pkg3/I4.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -25,6 +25,6 @@ package pkg3; public interface I4 { - public void foo(); + public void foo(); } diff --git a/test/langtools/jdk/javadoc/doclet/testOverriddenMethods/pkg5/Classes.java b/test/langtools/jdk/javadoc/doclet/testOverriddenMethods/pkg5/Classes.java index 50048688ec3ab1b3f15abd6a686f3463f643900d..dd7b7125bde5443a6817313d0205e399bd4b27c9 100644 --- a/test/langtools/jdk/javadoc/doclet/testOverriddenMethods/pkg5/Classes.java +++ b/test/langtools/jdk/javadoc/doclet/testOverriddenMethods/pkg5/Classes.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -33,108 +33,108 @@ public class Classes { public void m7() {} } - public static class P extends GP { + public static class P extends GP { - /** A nested class in parent */ - public class PN{} + /** A nested class in parent */ + public class PN{} - /** A property in parent */ - private DoubleProperty rate; - public final void setRate(double l){} - public final double getRate(){return 1;} - public DoubleProperty rateProperty() {return null;} + /** A property in parent */ + private DoubleProperty rate; + public final void setRate(double l){} + public final double getRate(){return 1;} + public DoubleProperty rateProperty() {return null;} - /** A ctor in parent */ - public P() {} + /** A ctor in parent */ + public P() {} - /** - * A ctor in parent. - * @param s string - */ - public P(String s) {} + /** + * A ctor in parent. + * @param s string + */ + public P(String s) {} - /** field0 in parent */ - public int field0; + /** field0 in parent */ + public int field0; - /** field1 in parent */ - public int field1; + /** field1 in parent */ + public int field1; - // m0 in parent - public void m0() {} - - /** m1 in parent */ - public void m1() {} - - /** m2 in parent */ - public void m2() {} - - /** m3 in parent */ - public void m3() {} - - /** m4 in parent - @param k a key - @param v a value - */ - public void m4(K k, V v) {} - - // No comment - public void m5() {} - - // No comment - public void m6() {} - - /** {@inheritDoc} */ - public void m7() {} - - } - - public static class C extends P { + // m0 in parent + public void m0() {} - public C(String s) {} + /** m1 in parent */ + public void m1() {} - public int field1; + /** m2 in parent */ + public void m2() {} - /** A modified method */ - public void m1() {} + /** m3 in parent */ + public void m3() {} - /** {@inheritDoc} */ - public void m2() {} + /** m4 in parent + @param k a key + @param v a value + */ + public void m4(K k, V v) {} - // No comment method - public void m3() {} + // No comment + public void m5() {} - public void m4(String k, String v) {} + // No comment + public void m6() {} - // Do something else than the parent - public void m5() {} + /** {@inheritDoc} */ + public void m7() {} - /** A test of links to the methods in this class.

          - * {@link m0}, - * {@link m1}, - * {@link m2}, - * {@link m3}, - * {@link m4}, - * {@link m5}, - * {@link m6}, - * {@link m7}, - * End of links - * - * @see #m0() - * @see #m1() - * @see #m2() - * @see #m3() - * @see #m4(String k, String v) - * @see #m5() - * @see #m6() - * @see #m7() - */ - public void m6() {} + } - /** m7 in Child. */ - public void m7() {} - } + public static class C extends P { + + public C(String s) {} + + public int field1; + + /** A modified method */ + public void m1() {} + + /** {@inheritDoc} */ + public void m2() {} + + // No comment method + public void m3() {} + + public void m4(String k, String v) {} + + // Do something else than the parent + public void m5() {} + + /** A test of links to the methods in this class.

          + * {@link m0}, + * {@link m1}, + * {@link m2}, + * {@link m3}, + * {@link m4}, + * {@link m5}, + * {@link m6}, + * {@link m7}, + * End of links + * + * @see #m0() + * @see #m1() + * @see #m2() + * @see #m3() + * @see #m4(String k, String v) + * @see #m5() + * @see #m6() + * @see #m7() + */ + public void m6() {} + + /** m7 in Child. */ + public void m7() {} + } - /** Tickle this {@link TestEnum#doSomething()} */ - public class DoubleProperty {} + /** Tickle this {@link TestEnum#doSomething()} */ + public class DoubleProperty {} } diff --git a/test/langtools/jdk/javadoc/doclet/testOverriddenMethods/pkg5/Interfaces.java b/test/langtools/jdk/javadoc/doclet/testOverriddenMethods/pkg5/Interfaces.java index dfac98fe4c0ef5e1153b465cda5b9296eb6bc5f2..cf3e5d95d54acdbc0c6e4ad0d8be7c303cdb388c 100644 --- a/test/langtools/jdk/javadoc/doclet/testOverriddenMethods/pkg5/Interfaces.java +++ b/test/langtools/jdk/javadoc/doclet/testOverriddenMethods/pkg5/Interfaces.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -24,67 +24,67 @@ package pkg5; public class Interfaces { - public interface A { + public interface A { - /** field f in A */ - public int f = 0; + /** field f in A */ + public int f = 0; - public static String QUOTE = "Winter is coming"; + public static String QUOTE = "Winter is coming"; - /** a documented static method */ - public static void msd() {} + /** a documented static method */ + public static void msd() {} - /* An undocumented static method */ - public static void msn() {} + /* An undocumented static method */ + public static void msn() {} - /** A property in parent */ - DoubleProperty rate = null; - public void setRate(double l); - public double getRate(); - public DoubleProperty rateProperty(); - // A support class - public interface DoubleProperty {} + /** A property in parent */ + DoubleProperty rate = null; + public void setRate(double l); + public double getRate(); + public DoubleProperty rateProperty(); + // A support class + public interface DoubleProperty {} - /** AA in A */ - public interface AA {} + /** AA in A */ + public interface AA {} - /** m0 in A */ - public void m0(); + /** m0 in A */ + public void m0(); - /** m1 in A */ - public void m1(); + /** m1 in A */ + public void m1(); - /** m2 in A */ - public void m2(); + /** m2 in A */ + public void m2(); - /** m3 in A */ - public void m3(); - } + /** m3 in A */ + public void m3(); + } - public interface B extends A { - // No comment - public void m0(); + public interface B extends A { + // No comment + public void m0(); - /** m1 in B */ - public void m1(); + /** m1 in B */ + public void m1(); - /** {@inheritDoc} */ - public void m2(); + /** {@inheritDoc} */ + public void m2(); - /** @throws Exception e */ - public void m3() throws Exception; + /** @throws Exception e */ + public void m3() throws Exception; - /** n in B */ - public void n(); - } + /** n in B */ + public void n(); + } - public interface C extends A, B { - /** m in C */ - public void m(); + public interface C extends A, B { + /** m in C */ + public void m(); - /** o in C */ - public void o(); - } + /** o in C */ + public void o(); + } /** * The child of all children. @@ -108,13 +108,13 @@ public class Interfaces { * @see #o */ public interface D extends A, B, C { - /** m in D */ - public void m(); + /** m in D */ + public void m(); - /** n in D */ - public void n(); + /** n in D */ + public void n(); - // no comment - public void o(); - } - } + // no comment + public void o(); + } +} diff --git a/test/langtools/jdk/javadoc/doclet/testOverriddenMethods/pkg6/Sub.java b/test/langtools/jdk/javadoc/doclet/testOverriddenMethods/pkg6/Sub.java index 694852f6d5e642e0f862b969c61651797725491c..7b85a4ad3d51e39959dd9d53cfb0297e3b05148a 100644 --- a/test/langtools/jdk/javadoc/doclet/testOverriddenMethods/pkg6/Sub.java +++ b/test/langtools/jdk/javadoc/doclet/testOverriddenMethods/pkg6/Sub.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -52,4 +52,3 @@ public class Sub extends Base { @Override public abstract Object m9(); } - diff --git a/src/hotspot/share/services/mallocTracker.inline.hpp b/test/langtools/jdk/javadoc/doclet/testOverriddenMethods/pkg8/C.java similarity index 70% rename from src/hotspot/share/services/mallocTracker.inline.hpp rename to test/langtools/jdk/javadoc/doclet/testOverriddenMethods/pkg8/C.java index b73e1d42adb2487799e6e0ddf69444ee273fbf7b..0bbfd17986bdba2866be6892ebee87146d77bc03 100644 --- a/src/hotspot/share/services/mallocTracker.inline.hpp +++ b/test/langtools/jdk/javadoc/doclet/testOverriddenMethods/pkg8/C.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -19,18 +19,29 @@ * Please 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_SERVICES_MALLOCTRACKER_INLINE_HPP -#define SHARE_SERVICES_MALLOCTRACKER_INLINE_HPP +package pkg8; -#include "services/mallocTracker.hpp" +public class C extends P { -#include "services/memTracker.hpp" + /** + * Child m1(). + * + * @param Child m1's type + */ + @Override + public void m1() {} -inline void* MallocTracker::get_base(void* memblock){ - return get_base(memblock, MemTracker::tracking_level()); -} + /** + * Child m2(). + */ + @Override + public void m2() {} -#endif // SHARE_SERVICES_MALLOCTRACKER_INLINE_HPP + /** + * Child m3(). + */ + @Override + public void m3() {} +} diff --git a/test/langtools/jdk/javadoc/doclet/testOverriddenMethods/pkg8/GP.java b/test/langtools/jdk/javadoc/doclet/testOverriddenMethods/pkg8/GP.java new file mode 100644 index 0000000000000000000000000000000000000000..393506a269fa4cbb3c466d84ba049620d3f865b4 --- /dev/null +++ b/test/langtools/jdk/javadoc/doclet/testOverriddenMethods/pkg8/GP.java @@ -0,0 +1,48 @@ +/* + * 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. + */ + +package pkg8; + +public class GP { + + /** + * Grandparent m1(). + * + * @param Grandparent m1's type + */ + public void m1() {} + + /** + * Grandparent m2(). + * + * @param Grandparent m2's type + */ + public void m2() {} + + /** + * Grandparent m3(). + * + * @param Grandparent m3's type + */ + public void m3() {} +} diff --git a/src/hotspot/cpu/ppc/register_definitions_ppc.cpp b/test/langtools/jdk/javadoc/doclet/testOverriddenMethods/pkg8/P.java similarity index 68% rename from src/hotspot/cpu/ppc/register_definitions_ppc.cpp rename to test/langtools/jdk/javadoc/doclet/testOverriddenMethods/pkg8/P.java index c0bfd7db95af832e48fb7946c6a8e180993d7371..3f6135454b43648f8503b84fea7280ad6fd392a5 100644 --- a/src/hotspot/cpu/ppc/register_definitions_ppc.cpp +++ b/test/langtools/jdk/javadoc/doclet/testOverriddenMethods/pkg8/P.java @@ -1,6 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2015 SAP SE. All rights reserved. + * 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 @@ -20,18 +19,20 @@ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. - * */ -// Make sure the defines don't screw up the declarations later on in this file. -#define DONT_USE_REGISTER_DEFINES +package pkg8; -#include "asm/register.hpp" +public class P extends GP { -REGISTER_DEFINITION(Register, noreg); + // note that while m1() and m2() are parameterized, m3() is not -REGISTER_DEFINITION(FloatRegister, fnoreg); + @Override + public void m1() {} -REGISTER_DEFINITION(VectorRegister, vnoreg); + @Override + public void m2() {} -REGISTER_DEFINITION(VectorSRegister, vsnoreg); + @Override + public void m3() {} +} diff --git a/test/langtools/jdk/javadoc/doclet/testParamTaglet/TestParamTaglet.java b/test/langtools/jdk/javadoc/doclet/testParamTaglet/TestParamTaglet.java index b6b6a7a78d429e8f5f0e0541726db932fc0b2412..200af37a94838c370e7137b8ba535dd084c9c4b0 100644 --- a/test/langtools/jdk/javadoc/doclet/testParamTaglet/TestParamTaglet.java +++ b/test/langtools/jdk/javadoc/doclet/testParamTaglet/TestParamTaglet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -23,7 +23,7 @@ /* * @test - * @bug 4802275 4967243 8026567 8239804 + * @bug 4802275 4967243 8026567 8239804 8234682 * @summary Make sure param tags are still printed even though they do not * match up with a real parameters. * Make sure inheritDoc cannot be used in an invalid param tag. @@ -48,22 +48,51 @@ public class TestParamTaglet extends JavadocTester { "-sourcepath", testSrc, "pkg"); checkExit(Exit.ERROR); - + checkOutput(Output.OUT, true, + "warning: no @param for param1", + "error: @param name not found", + "warning: @param \"b\" has already been specified"); checkOutput("pkg/C.html", true, - //Regular param tags. + // Regular param tags. """

          Parameters:
          param1 - testing 1 2 3.
          -
          param2 - testing 1 2 3.""", - //Param tags that don't match with any real parameters. +
          param2 - testing 1 2 3.
          + """, + // Param tags that don't match with any real parameters. + // {@inheritDoc} misuse does not cause doclet to throw exception. + // Param is printed with nothing inherited. """
          Parameters:
          p1 - testing 1 2 3.
          -
          p2 - testing 1 2 3.""", - //{@inherit} doc misuse does not cause doclet to throw exception. - // Param is printed with nothing inherited. - //XXX: in the future when Configuration is available during doc inheritence, - //print a warning for this mistake. - "inheritBug -"); +
          p2 - testing 1 2 3.
          +
          inheritBug -
          + """, + """ +
          Parameters:
          +
          i - an int
          +
          d - a double
          +
          b - a boolean
          +
          x - does not exist
          +
          x - duplicate
          +
          b - another duplicate
          + """, + """ +
          Type Parameters:
          +
          T2 - type 2
          +
          Parameters:
          +
          t1 - param 1
          +
          t3 - param 3
          + """); + checkOutput("pkg/C.Point.html", true, + """ +
          Record Components:
          +
          y - the y coordinate
          + """); + checkOutput("pkg/C.Nested.html", true, + """ +
          Type Parameters:
          +
          T1 - type 1
          + """); } } diff --git a/test/langtools/jdk/javadoc/doclet/testParamTaglet/pkg/C.java b/test/langtools/jdk/javadoc/doclet/testParamTaglet/pkg/C.java index a50a8d7c6b9be35ed1e0838d7d49c557539a9ed8..ca5bda9eb6053c8ed2d3fd005aa59c113f3dfcc7 100644 --- a/test/langtools/jdk/javadoc/doclet/testParamTaglet/pkg/C.java +++ b/test/langtools/jdk/javadoc/doclet/testParamTaglet/pkg/C.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -36,6 +36,42 @@ public class C extends Parent { * @param p2 testing 1 2 3. * @param inheritBug {@inheritDoc} */ + @Override public void nonMatchingParams(int param1, int param2) {} + /** + * Overriding method with missing/additional/duplicate param tags in non-declaration order. + * + * @param x does not exist + * @param b a boolean + * @param i an int + * @param x duplicate + * @param b another duplicate + */ + @Override + public void unorderedParams(int i, double d, boolean b) {} + + /** + * Generic method with mixed/missing param tags. + * + * @param t1 param 1 + * @param type 2 + * @param t3 param 3 + */ + public static void genericMethod(T1 t1, T2 t2, T3 t3) {} + + /** + * A partially documented point. + * + * @param y the y coordinate + */ + public static record Point(int x, int y) {} + + /** + * Generic class with missing param tags. + * + * @param type 1 + */ + public static class Nested {} + } diff --git a/test/langtools/jdk/javadoc/doclet/testParamTaglet/pkg/Parent.java b/test/langtools/jdk/javadoc/doclet/testParamTaglet/pkg/Parent.java index f0b380b19bd5ca634c8c690d0f37eadb0d8d8dcd..133c7038cb5ac37d8879f0b83031ac1f7664c498 100644 --- a/test/langtools/jdk/javadoc/doclet/testParamTaglet/pkg/Parent.java +++ b/test/langtools/jdk/javadoc/doclet/testParamTaglet/pkg/Parent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -29,4 +29,11 @@ public class Parent { * Just a dummy method that is here for inheritDoc testing purposes. */ public void nonMatchingParams(int param1, int param2) {} + + /** + * Base method with partially documented params. + * + * @param d a double + */ + public void unorderedParams(int i, double d, boolean b) {} } diff --git a/test/langtools/jdk/javadoc/doclet/testPreview/TestPreview.java b/test/langtools/jdk/javadoc/doclet/testPreview/TestPreview.java index 46035e6eb71edf7323257c854be6f347243325aa..e3618aa1555c30d6c68edbef739a4e44a9f93309 100644 --- a/test/langtools/jdk/javadoc/doclet/testPreview/TestPreview.java +++ b/test/langtools/jdk/javadoc/doclet/testPreview/TestPreview.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -23,7 +23,7 @@ /* * @test - * @bug 8250768 8261976 + * @bug 8250768 8261976 8277300 8282452 * @summary test generated docs for items declared using preview * @library ../../lib * @modules jdk.javadoc/jdk.javadoc.internal.tool @@ -33,8 +33,6 @@ */ import java.nio.file.Paths; -import java.text.MessageFormat; -import java.util.ResourceBundle; import javadoc.tester.JavadocTester; public class TestPreview extends JavadocTester { @@ -101,4 +99,39 @@ public class TestPreview extends JavadocTester { """); } + + @Test + public void test8277300() { + javadoc("-d", "out-8277300", + "--add-exports", "java.base/jdk.internal.javac=api2", + "--source-path", Paths.get(testSrc, "api2").toAbsolutePath().toString(), + "--show-packages=all", + "api2/api"); + checkExit(Exit.OK); + + checkOutput("api2/api/API.html", true, + "

          test()

          ", + "

          testNoPreviewInSig()

          ", + "title=\"class or interface in java.util\" class=\"external-link\">List<APIPREVIEW>"); + checkOutput("api2/api/API2.html", true, + "API.test()PREVIEW", + "API.testNoPreviewInSig()PREVIEW", + "API3.test()PREVIEW"); + checkOutput("api2/api/API3.html", true, + ""); + } + + @Test + public void test8282452() { + javadoc("-d", "out-8282452", + "--patch-module", "java.base=" + Paths.get(testSrc, "api").toAbsolutePath().toString(), + "--add-exports", "java.base/preview=m", + "--source-path", Paths.get(testSrc, "api").toAbsolutePath().toString(), + "--show-packages=all", + "preview"); + checkExit(Exit.OK); + + checkOutput("java.base/preview/NoPreview.html", false, + "refers to one or more preview"); + } } diff --git a/test/langtools/jdk/javadoc/doclet/testPreview/api/preview/NoPreview.java b/test/langtools/jdk/javadoc/doclet/testPreview/api/preview/NoPreview.java new file mode 100644 index 0000000000000000000000000000000000000000..951b557ce6d387884df6e43f75f54bc248d578e2 --- /dev/null +++ b/test/langtools/jdk/javadoc/doclet/testPreview/api/preview/NoPreview.java @@ -0,0 +1,37 @@ +/* + * 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. + */ +package preview; + +import jdk.internal.javac.PreviewFeature; +import jdk.internal.javac.PreviewFeature.Feature; + +public class NoPreview { + + @PreviewFeature(feature=Feature.TEST) + public T get() { + return null; + } + + @PreviewFeature(feature=Feature.TEST) + public static class T {} +} diff --git a/test/langtools/jdk/javadoc/doclet/testPreview/api2/api/API.java b/test/langtools/jdk/javadoc/doclet/testPreview/api2/api/API.java new file mode 100644 index 0000000000000000000000000000000000000000..f8dc37b8addb282ed195da8cf1aaa431f413fe0d --- /dev/null +++ b/test/langtools/jdk/javadoc/doclet/testPreview/api2/api/API.java @@ -0,0 +1,46 @@ +/* + * 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. + */ + +package api; + +import java.util.List; +import jdk.internal.javac.PreviewFeature; +import jdk.internal.javac.PreviewFeature.Feature; + +/** + *

          {@link API#test()}

          + *

          {@link API#testNoPreviewInSig()}

          + */ +@PreviewFeature(feature=Feature.TEST, reflective=false) +public class API { + + public API test() { + return null; + } + + public void testNoPreviewInSig() { + } + + public void typeArgs(List api) { + } +} diff --git a/test/langtools/jdk/javadoc/doclet/testPreview/api2/api/API2.java b/test/langtools/jdk/javadoc/doclet/testPreview/api2/api/API2.java new file mode 100644 index 0000000000000000000000000000000000000000..83c08c7d25856afdf83fc7e7b115b541175b0914 --- /dev/null +++ b/test/langtools/jdk/javadoc/doclet/testPreview/api2/api/API2.java @@ -0,0 +1,33 @@ +/* + * 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. + */ + +package api; + +/** + *

          {@link API#test()} + *

          {@link API#testNoPreviewInSig()} + *

          {@link API3#test()} + */ +public class API2 { + +} diff --git a/test/langtools/jdk/javadoc/doclet/testPreview/api2/api/API3.java b/test/langtools/jdk/javadoc/doclet/testPreview/api2/api/API3.java new file mode 100644 index 0000000000000000000000000000000000000000..26ae586f27ce53d987a1e1488061c11ca39fb3a5 --- /dev/null +++ b/test/langtools/jdk/javadoc/doclet/testPreview/api2/api/API3.java @@ -0,0 +1,39 @@ +/* + * 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. + */ + +package api; + +import jdk.internal.javac.PreviewFeature; +import jdk.internal.javac.PreviewFeature.Feature; + +/** + * {@link API3#test()} + */ +public class API3 { + + @PreviewFeature(feature=Feature.TEST, reflective=false) + public void test() { + return null; + } + +} diff --git a/test/langtools/jdk/javadoc/doclet/testPreview/api2/module-info.java b/test/langtools/jdk/javadoc/doclet/testPreview/api2/module-info.java new file mode 100644 index 0000000000000000000000000000000000000000..0f9e3e5d6efce49cdade957a87c4ced6694cc1da --- /dev/null +++ b/test/langtools/jdk/javadoc/doclet/testPreview/api2/module-info.java @@ -0,0 +1,25 @@ +/* + * 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. + */ +module api2 { + exports api; +} diff --git a/test/langtools/jdk/javadoc/doclet/testPrivateClasses/TestPrivateClasses.java b/test/langtools/jdk/javadoc/doclet/testPrivateClasses/TestPrivateClasses.java index 91917705dd5f624f2915632b933fc9bb069e9e4a..9b23a45a2ddb3e61fe933cb5153e59e0e80c1330 100644 --- a/test/langtools/jdk/javadoc/doclet/testPrivateClasses/TestPrivateClasses.java +++ b/test/langtools/jdk/javadoc/doclet/testPrivateClasses/TestPrivateClasses.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -59,7 +59,7 @@ public class TestPrivateClasses extends JavadocTester { checkExit(Exit.OK); checkOutput("pkg/PublicChild.html", true, - // Field inheritence from non-public superclass. + // Field inheritance from non-public superclass. """ fieldInheritedFromParent""", // Method inheritance from non-public superclass. @@ -156,12 +156,12 @@ public class TestPrivateClasses extends JavadocTester { checkExit(Exit.OK); checkOutput("pkg/PublicChild.html", true, - // Field inheritence from non-public superclass. + // Field inheritance from non-public superclass. """ Fields inherited from class pkg.PrivateParent""", """ fieldInheritedFromParent""", - // Method inheritence from non-public superclass. + // Method inheritance from non-public superclass. """ Methods inherited from class pkg.PrivateParent""", """ @@ -195,7 +195,7 @@ public class TestPrivateClasses extends JavadocTester { ass="element-name type-name-label">PublicChild"""); checkOutput("pkg/PublicInterface.html", true, - // Field inheritence from non-public superinterface. + // Field inheritance from non-public superinterface. """ Fields inherited from interface pkg.PrivateInterface""", """ diff --git a/test/langtools/jdk/javadoc/doclet/testReturnTag/TestReturnTag.java b/test/langtools/jdk/javadoc/doclet/testReturnTag/TestReturnTag.java index 00d5c92c630055614385cceb9c35f8591cf8818a..4974f4e586ea1c91060ae945f9964750ef312c25 100644 --- a/test/langtools/jdk/javadoc/doclet/testReturnTag/TestReturnTag.java +++ b/test/langtools/jdk/javadoc/doclet/testReturnTag/TestReturnTag.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -23,7 +23,7 @@ /* * @test - * @bug 4490068 8075778 + * @bug 4490068 8075778 8283041 * @summary General tests for inline or block at-return tag * @library /tools/lib ../../lib * @modules jdk.javadoc/jdk.javadoc.internal.tool @@ -265,16 +265,30 @@ public class TestReturnTag extends JavadocTester { */ public int m() { return 0; } } + """, + """ + /** Comment. */ + public class X { + /** + * @author Jim + * {@return the result} + */ + public int m() { return 0; } + } """); javadoc("-d", base.resolve("out").toString(), "-sourcepath", src.toString(), - src.resolve("C.java").toString()); + src.resolve("C.java").toString(), + src.resolve("X.java").toString()); checkExit(Exit.OK); checkOutput(Output.OUT, true, "C.java:4: warning: {@return} not at beginning of description"); + checkOutput(Output.OUT, true, + "X.java:5: warning: {@return} not at beginning of description"); + checkOutput("C.html", true, """

          Some text. Returns the result. More text.
          diff --git a/test/langtools/jdk/javadoc/doclet/testSearch/TestSearch.java b/test/langtools/jdk/javadoc/doclet/testSearch/TestSearch.java index d25dba1df220967e5f2d6de6a473215b0b09897e..3d316571811499fe69b6203562affdedd6941ca4 100644 --- a/test/langtools/jdk/javadoc/doclet/testSearch/TestSearch.java +++ b/test/langtools/jdk/javadoc/doclet/testSearch/TestSearch.java @@ -411,7 +411,7 @@ public class TestSearch extends JavadocTester { """, """ - + """, """ """, @@ -684,7 +684,7 @@ public class TestSearch extends JavadocTester { checkFiles(expectedOutput, "search.js", "jquery-ui.overrides.css", - "script-dir/jquery-3.5.1.min.js", + "script-dir/jquery-3.6.0.min.js", "script-dir/jquery-ui.min.js", "script-dir/jquery-ui.min.css", "script-dir/jquery-ui.structure.min.css", diff --git a/test/langtools/jdk/javadoc/doclet/testSeeTag/TestSeeTag.java b/test/langtools/jdk/javadoc/doclet/testSeeTag/TestSeeTag.java index f364cd47ef7c1ea33161bf393c2d1df3f848ea0a..c65b522fd0823e2adcfe47e1ace89afa8e05a7ec 100644 --- a/test/langtools/jdk/javadoc/doclet/testSeeTag/TestSeeTag.java +++ b/test/langtools/jdk/javadoc/doclet/testSeeTag/TestSeeTag.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 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 @@ -23,15 +23,19 @@ /* * @test - * @bug 8017191 8182765 8200432 8239804 8250766 8262992 + * @bug 8017191 8182765 8200432 8239804 8250766 8262992 8281944 * @summary Javadoc is confused by at-link to imported classes outside of the set of generated packages - * @library ../../lib + * @library /tools/lib ../../lib * @modules jdk.javadoc/jdk.javadoc.internal.tool - * @build javadoc.tester.* + * @build toolbox.ToolBox javadoc.tester.* * @run main TestSeeTag */ import javadoc.tester.JavadocTester; +import toolbox.ToolBox; + +import java.io.IOException; +import java.nio.file.Path; public class TestSeeTag extends JavadocTester { @@ -100,9 +104,50 @@ public class TestSeeTag extends JavadocTester {
          • Object
          • -
          • Foo<String>
          • +
          • +
            + invalid @see +
            Foo<String>
            +
            +
          """); } + + ToolBox tb = new ToolBox(); + + @Test + public void testErroneous() throws IOException { + Path src = Path.of("erroneous", "src"); + tb.writeJavaFiles(src, """ + package erroneous; + /** + * Comment. + * @see +
          See Also:
          +
          +
            +
          • invalid input: '<a href="'
          • +
          +
          + + """); + + } } diff --git a/test/langtools/jdk/javadoc/doclet/testSnippetTag/SnippetTester.java b/test/langtools/jdk/javadoc/doclet/testSnippetTag/SnippetTester.java new file mode 100644 index 0000000000000000000000000000000000000000..23d653be00f82f1b5f151170ce8225719f2d1ae9 --- /dev/null +++ b/test/langtools/jdk/javadoc/doclet/testSnippetTag/SnippetTester.java @@ -0,0 +1,169 @@ +/* + * 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 java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.Arrays; +import java.util.List; +import java.util.Optional; +import java.util.function.BiPredicate; +import java.util.function.ObjIntConsumer; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Stream; + +import javadoc.tester.JavadocTester; +import toolbox.ToolBox; + +public class SnippetTester extends JavadocTester { + + protected final ToolBox tb = new ToolBox(); + + protected void checkOrder(Output output, String... strings) { + new OutputChecker(output).setExpectOrdered(true).check(strings); + } + + /* + * When checking for errors, it is important not to confuse one error with + * another. This method checks that there are no crashes (which are also + * errors) by checking for stack traces. We never expect crashes. + */ + protected void checkNoCrashes() { + checking("check crashes"); + Matcher matcher = Pattern.compile("\\s*at.*\\(.*\\.java:\\d+\\)") + .matcher(getOutput(Output.STDERR)); + if (!matcher.find()) { + passed(""); + } else { + failed("Looks like a stacktrace: " + matcher.group()); + } + } + + /* + * This is a convenience method to iterate through a list. + * Unlike List.forEach, this method provides the consumer not only with an + * element but also that element's index. + * + * See JDK-8184707. + */ + protected static void forEachNumbered(List list, ObjIntConsumer action) { + for (var iterator = list.listIterator(); iterator.hasNext(); ) { + action.accept(iterator.next(), iterator.previousIndex()); + } + } + + // TODO: + // Explore the toolbox.ToolBox.writeFile and toolbox.ToolBox.writeJavaFiles methods: + // see if any of them could be used instead of this one + protected static void addSnippetFile(Path srcDir, String packageName, String fileName, String content) + throws UncheckedIOException + { + String[] components = packageName.split("\\."); + Path snippetFiles = Path.of(components[0], Arrays.copyOfRange(components, 1, components.length)).resolve("snippet-files"); + try { + Path p = Files.createDirectories(srcDir.resolve(snippetFiles)); + Files.writeString(p.resolve(fileName), content, StandardOpenOption.CREATE_NEW); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + protected void checkOutputEither(Output out, String first, String... other) { + var strings = Stream.concat(Stream.of(first), Stream.of(other)) + .toArray(String[]::new); + new OutputChecker(out).checkAnyOf(strings); + } + + protected String getSnippetHtmlRepresentation(String pathToHtmlFile, + String content) { + return getSnippetHtmlRepresentation(pathToHtmlFile, content, Optional.empty(), Optional.empty()); + } + + protected String getSnippetHtmlRepresentation(String pathToHtmlFile, + String content, + Optional lang) { + return getSnippetHtmlRepresentation(pathToHtmlFile, content, lang, Optional.empty()); + } + + protected String getSnippetHtmlRepresentation(String pathToHtmlFile, + String content, + Optional lang, + Optional id) { + // the further away from the root, the further to reach to common resources + int nComponents = (int) pathToHtmlFile.chars().filter(c -> c == '/').count(); + var svgString = "../".repeat(nComponents) + "copy.svg"; + var idString = id.isEmpty() ? "" : " id=\"%s\"".formatted(id.get()); + var langString = lang.isEmpty() ? "" : " class=\"language-%s\"".formatted(lang.get()); + return """ + """.formatted(svgString, idString, langString, content); + } + + // There's JavadocTester.diff(), but its semantics is different; hence we + // use this method. + protected void match(Path path1, Path path2, BiPredicate filter) throws IOException { + checking("diff " + path1 + ", " + path2); + try (var paths1 = Files.find(path1, Integer.MAX_VALUE, filter).sorted(); + var paths2 = Files.find(path2, Integer.MAX_VALUE, filter).sorted()) { + var it1 = paths1.iterator(); + var it2 = paths2.iterator(); + while (true) { + if (it1.hasNext() != it2.hasNext()) { + failed(it1.hasNext() ? it1.next() : it2.next(), "missing"); + return; + } + if (!it1.hasNext()) { + passed("match"); + return; + } + Path next1 = it1.next(); + Path next2 = it2.next(); + if (!path1.relativize(next1).equals(path2.relativize(next2))) { + // compare directory tree to see the difference + failed("mismatching names %s %s".formatted(next1, next2)); + return; + } + if (Files.isDirectory(next1) != Files.isDirectory(next2)) { + // it'd be surprising to ever see this + failed("mismatching types %s %s".formatted(next1, next2)); + return; + } + if (Files.isDirectory(next1)) { + continue; + } + if (Files.size(next1) != Files.size(next2) + || Files.mismatch(next1, next2) != -1L) { + failed("mismatching contents: diff %s %s".formatted(next1.toAbsolutePath(), + next2.toAbsolutePath())); + return; + } + } + } + } +} diff --git a/test/langtools/jdk/javadoc/doclet/testSnippetTag/TestLangProperties.java b/test/langtools/jdk/javadoc/doclet/testSnippetTag/TestLangProperties.java new file mode 100644 index 0000000000000000000000000000000000000000..de8ea1b3490766f5ef66d13fbd79ddeb23d2455e --- /dev/null +++ b/test/langtools/jdk/javadoc/doclet/testSnippetTag/TestLangProperties.java @@ -0,0 +1,186 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8266666 + * @summary Implementation for snippets + * @library /tools/lib ../../lib + * @modules jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.main + * jdk.javadoc/jdk.javadoc.internal.tool + * @build javadoc.tester.* toolbox.ToolBox toolbox.ModuleBuilder builder.ClassBuilder + * @run main TestLangProperties + */ + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +public class TestLangProperties extends SnippetTester { + + public static void main(String... args) throws Exception { + new TestLangProperties().runTests(m -> new Object[]{Paths.get(m.getName())}); + } + + @Test + public void testPositiveOuterMarkup(Path base) throws Exception { + var testCases = new ArrayList(); + for (String whitespace1 : List.of("", " ", "\t")) + for (String commentIndicator1 : List.of("#", "!")) + for (String whitespace2 : List.of("", " ", "\t")) { + String markup = whitespace1 + commentIndicator1 + + whitespace2 + "@highlight :"; + var t = new TestSnippetMarkup.TestCase( + """ + %s + coffee=espresso + tea=black + """.formatted(markup), + """ + coffee=espresso + tea=black + """); + testCases.add(t); + } + testPositive(base, testCases); + } + + @Test + public void testPositiveInnerMarkup(Path base) throws Exception { + var testCases = new ArrayList(); + for (String whitespace1 : List.of("", " ", "\t")) + for (String commentIndicator1 : List.of("#", "!")) + for (String whitespace2 : List.of("", " ", "\t")) + for (String unrelatedComment : List.of("a comment")) + for (String whitespace3 : List.of("", " ")) + for (String commentIndicator2 : List.of("#", "!")) { + String payload = whitespace1 + commentIndicator1 + whitespace2 + unrelatedComment; + String markup = payload + whitespace3 + commentIndicator2 + "@highlight :"; + var t = new TestSnippetMarkup.TestCase( + """ + %s + coffee=espresso + tea=black + """.formatted(markup), + """ + %s + coffee=espresso + tea=black + """.formatted(payload)); + testCases.add(t); + } + testPositive(base, testCases); + } + + @Test + public void testPositiveIneffectiveOuterMarkup(Path base) throws Exception { + var testCases = new ArrayList(); + for (String whitespace1 : List.of("", " ", "\t")) + for (String commentIndicator1 : List.of("#", "!")) + for (String whitespace2 : List.of("", " ", "\t")) { + String ineffectiveMarkup = whitespace1 + + commentIndicator1 + whitespace2 + + "@highlight :"; + var t = new TestSnippetMarkup.TestCase( + """ + coffee=espresso%s + tea=black + """.formatted(ineffectiveMarkup), + """ + coffee=espresso%s + tea=black + """.formatted(ineffectiveMarkup)); + testCases.add(t); + } + testPositive(base, testCases); + } + + @Test + public void testPositiveIneffectiveInnerMarkup(Path base) throws Exception { + var testCases = new ArrayList(); + for (String whitespace1 : List.of("", " ", "\t")) + for (String commentIndicator1 : List.of("#", "!")) + for (String whitespace2 : List.of("", " ", "\t")) + for (String unrelatedComment : List.of("a comment")) + for (String whitespace3 : List.of("", " ")) + for (String commentIndicator2 : List.of("#", "!")) { + String ineffectiveMarkup = whitespace1 + + commentIndicator1 + whitespace2 + + unrelatedComment + whitespace3 + + commentIndicator2 + "@highlight :"; + var t = new TestSnippetMarkup.TestCase( + """ + coffee=espresso%s + tea=black + """.formatted(ineffectiveMarkup), + """ + coffee=espresso%s + tea=black + """.formatted(ineffectiveMarkup)); + testCases.add(t); + } + testPositive(base, testCases); + } + + private void testPositive(Path base, List testCases) + throws IOException { + StringBuilder methods = new StringBuilder(); + forEachNumbered(testCases, (i, n) -> { + String r = i.region().isBlank() ? "" : "region=" + i.region(); + var methodDef = """ + + /** + {@snippet lang="properties" %s: + %s}*/ + public void case%s() {} + """.formatted(r, i.input(), n); + methods.append(methodDef); + }); + var classDef = """ + public class A { + %s + } + """.formatted(methods.toString()); + Path src = Files.createDirectories(base.resolve("src")); + tb.writeJavaFiles(src, classDef); + javadoc("-d", base.resolve("out").toString(), + "-sourcepath", src.toString(), + src.resolve("A.java").toString()); + checkExit(Exit.OK); + checkNoCrashes(); + forEachNumbered(testCases, (t, index) -> { + String html = """ + case%s() +
          + %s +
          """.formatted(index, getSnippetHtmlRepresentation("A.html", + t.expectedOutput(), Optional.of("properties"))); + checkOutput("A.html", true, html); + }); + } +} diff --git a/test/langtools/jdk/javadoc/doclet/testSnippetTag/TestSnippetMarkup.java b/test/langtools/jdk/javadoc/doclet/testSnippetTag/TestSnippetMarkup.java new file mode 100644 index 0000000000000000000000000000000000000000..8b5e6b4438dc01c1994094f0cbea193f83c6e683 --- /dev/null +++ b/test/langtools/jdk/javadoc/doclet/testSnippetTag/TestSnippetMarkup.java @@ -0,0 +1,916 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8266666 + * @summary Implementation for snippets + * @library /tools/lib ../../lib + * @modules jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.main + * jdk.javadoc/jdk.javadoc.internal.tool + * @build javadoc.tester.* toolbox.ToolBox toolbox.ModuleBuilder builder.ClassBuilder + * @run main TestSnippetMarkup + */ + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Reader; +import java.io.StringReader; +import java.io.StringWriter; +import java.io.UncheckedIOException; +import java.io.Writer; +import java.net.URI; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.atomic.AtomicLong; +import java.util.function.Function; +import java.util.regex.MatchResult; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.lang.model.element.Modifier; +import javax.lang.model.element.NestingKind; +import javax.tools.FileObject; +import javax.tools.JavaFileObject; +import javax.tools.StandardJavaFileManager; +import javax.tools.ToolProvider; + +import builder.ClassBuilder; +import toolbox.ToolBox; + +import static javax.tools.DocumentationTool.Location.DOCUMENTATION_OUTPUT; + +public class TestSnippetMarkup extends SnippetTester { + + public static void main(String... args) throws Exception { + new TestSnippetMarkup().runTests(m -> new Object[]{Paths.get(m.getName())}); + } + + /* + * The semantics of expectedOutput depends on the test case this record is + * used in. + */ + record TestCase(String region, String input, String expectedOutput) { + TestCase(String input, String expectedOutput) { + this("", input, expectedOutput); + } + } + + // @highlight [region|region=] + // [regex=|substring=] + // [type=bold|italics|highlighted] + // [:] + @Test + public void testHighlight(Path base) throws Exception { + var testCases = List.of( + new TestCase( // FIXME: newline should not be included + """ + First line // @highlight + Second line + """, + """ + First line + Second line + """), + new TestCase( + """ + First line // @highlight regex="\\w" type="bold" + Second line + """, + """ + First line + Second line + """), + new TestCase( // FIXME: newline should not be included + """ + First line // @highlight @highlight regex="\\w" type="bold" + Second line + """, + """ + First line + Second line + """ + )); + testPositive(base, testCases); + } + + // @replace [region|region=] + // [regex=|substring=] + // [replacement=] + // [:] + @Test + public void testReplace(Path base) throws Exception { + var testCases = List.of( + new TestCase( + """ + First line // @replace regex="\\w" replacement="." + Second line + """, + """ + ..... .... + Second line + """), + new TestCase( // "substring" is not treated like "regex" + """ + First line // @replace substring="\\w" replacement="." + Second line + """, + """ + First line + Second line + """ + ), + new TestCase( + """ + First line // @replace substring="i" replacement="." + Second line + """, + """ + F.rst l.ne + Second line + """ + )); + testPositive(base, testCases); + } + + // @link [region|region=] + // [regex=|substring=] + // [target=] + // [type=link|linkplain] + // [:] + @Test + public void testLink(Path base) throws Exception { + var testCases = List.of( + new TestCase( + """ + First line // @link regex="\\w" target="java.lang.Object#Object" + Second line + """, + replace(""" + link(First) link(line) + Second line + """, "link\\((.+?)\\)", r -> link(true, "java.lang.Object#Object", r.group(1))) + )); + testPositive(base, testCases); + } + + @Test + public void testCornerCases(Path base) throws Exception { + var testCases = List.of( + new TestCase( // This is how one might represent a unicode escape sequence uninterpreted, if required. + """ + \\$0041 // @replace substring="$" replacement="u" + """, + """ + \\u0041 + """ + ), + new TestCase( // This is how one might represent `*/` without ending an enclosing comment, if required. + // A non-whitespace character that is also not `*` is needed before `*` so that `*` + // is not confused with the optional doc comment decoration. + // (We cannot use, for example, `**$` or ` *$`.) + """ + a*$ // @replace substring="$" replacement="/" + """, + """ + a*/ + """ + ), + new TestCase( // This is how one might output markup, if required. + // Append a no-op markup since only the rightmost markup is parsed. + """ + // @highlight // @start region=throwaway @end + """, + """ + // @highlight + """ + ) + ); + testPositive(base, testCases); + } + + /* + * For all but the last line of snippet source, next-line markup behaves + * as if that markup without the next-line modifier were put on that + * next line. + */ +// @Test + public void testPositiveInlineExternalTagMarkup_NextLine(Path base) throws Exception { + throw new RuntimeException("Not yet implemented"); + } + + /* + * If next-line markup is put on the last line of a snippet source, + * an error occurs. + */ + @Test + public void testNegativeInlineExternalHybridTagMarkup_NextLinePutOnLastLine(Path base) throws Exception { + Path srcDir = base.resolve("src"); + Path outDir = base.resolve("out"); + var goodFile = "good.txt"; + var badFile = "bad.txt"; + var badFile2 = "bad2.txt"; // to workaround error deduplication + new ClassBuilder(tb, "pkg.A") + .setModifiers("public", "class") + .addMembers( + ClassBuilder.MethodBuilder + .parse("public void inline() { }") + .setComments(""" + {@snippet : + First line // @highlight : + } + """)) + .addMembers( + ClassBuilder.MethodBuilder + .parse("public void external() { }") + .setComments(""" + {@snippet file="%s"} + """.formatted(badFile))) + .addMembers( + ClassBuilder.MethodBuilder + .parse("public void hybrid1() { }") + .setComments(""" + {@snippet file="%s": + First line + } + """.formatted(badFile2))) + .addMembers( + ClassBuilder.MethodBuilder + .parse("public void hybrid2() { }") + .setComments(""" + {@snippet file="%s": + First line // @highlight : + } + """.formatted(goodFile))) + // TODO: these two hybrids are to test what *this* test should not test. + // Add a test that checks that an error in either part + // of a hybrid snippet causes the snippet to fail (property-based testing) + .write(srcDir); + addSnippetFile(srcDir, "pkg", goodFile, """ +First line // @highlight + """); + addSnippetFile(srcDir, "pkg", badFile, """ +First line // @highlight : + """); + addSnippetFile(srcDir, "pkg", badFile2, """ +First line // @highlight : + """); + javadoc("-d", outDir.toString(), + "-sourcepath", srcDir.toString(), + "pkg"); + checkExit(Exit.ERROR); + checkOutput(Output.OUT, true, +""" +A.java:5: error: snippet markup: tag refers to non-existent lines +First line // @highlight : + ^""", +""" +A.java:24: error: snippet markup: tag refers to non-existent lines +First line // @highlight : + ^""", +""" +%s:1: error: snippet markup: tag refers to non-existent lines +First line // @highlight : + ^""".formatted(badFile), +""" +%s:1: error: snippet markup: tag refers to non-existent lines +First line // @highlight : + ^""".formatted(badFile2)); + checkNoCrashes(); + } + + private void testPositive(Path base, List testCases) + throws IOException { + StringBuilder methods = new StringBuilder(); + forEachNumbered(testCases, (i, n) -> { + String r = i.region.isBlank() ? "" : "region=" + i.region; + var methodDef = """ + + /** + {@snippet %s: + %s}*/ + public void case%s() {} + """.formatted(r, i.input, n); + methods.append(methodDef); + }); + var classDef = """ + public class A { + %s + } + """.formatted(methods.toString()); + Path src = Files.createDirectories(base.resolve("src")); + tb.writeJavaFiles(src, classDef); + javadoc("-d", base.resolve("out").toString(), + "-sourcepath", src.toString(), + src.resolve("A.java").toString()); + checkExit(Exit.OK); + checkNoCrashes(); + forEachNumbered(testCases, (t, index) -> { + String html = """ + case%s() +
          + %s +
          """.formatted(index, getSnippetHtmlRepresentation("A.html", t.expectedOutput())); + checkOutput("A.html", true, html); + }); + } + + // FIXME: move error (i.e. negative) tests from TestSnippetTag to here + + // @start region= ... @end [region|region=] + @Test + public void testStart(Path base) throws Exception { + var testCases = new ArrayList(); + for (var variant : generateStartEndVariants()) { + var t = new TestCase(variant.region, + """ + First line + Second line // ###START + Third line + Fourth line // ###END + Fifth line + """.replaceFirst("###START", variant.start) + .replaceFirst("###END", variant.end), + """ + Second line + Third line + Fourth line"""); + testCases.add(t); + } + testPositive(base, testCases); + } + + /* + * These are corner cases. As such they are expected to rarely happen in + * practise. These tests merely capture what the results looked when + * the feature was integrated. This might help when refactoring + * and refreshing the feature, to better understand the impact of + * the proposed changes. + */ + @Test + public void testPositiveInlineTagMarkup_ReplaceOnBlankLine(Path base) throws Exception { + var testCases = List.of( + // the complete line is being replaced + new TestCase("one", + """ + // @start region=one @replace regex=".*" replacement="-----" + one + // @end + """, + """ + -----one + """ + ), + // the contents of the line, but not the line terminator is being replaced + new TestCase("two", + """ + // @start region=two @replace regex=".+" replacement="*****" + two + // @end + """, + """ + *****two + """ + ), + new TestCase( + """ + // @replace regex="duke" replacement="duchess" + """, + """ + """ + ) + ); + testPositive(base, testCases); + } + + @Test + public void testPositiveInlineTagMarkup_BlankLinesRegionEquivalence(Path base) throws Exception { + var testCases = List.of( + new TestCase("example1", + """ + // @start region="example1" + if (v.isPresent()) { + System.out.println("v: " + v.get()); + } // @end + """, + """ + if (v.isPresent()) { + System.out.println("v: " + v.get()); + }"""), + new TestCase("example2", + """ + if (v.isPresent()) { // @start region="example2" + System.out.println("v: " + v.get()); + } // @end + """, + """ + if (v.isPresent()) { + System.out.println("v: " + v.get()); + }"""), + new TestCase("example3", + """ + // @start region="example3" : + if (v.isPresent()) { + System.out.println("v: " + v.get()); + // @end : + } + """, + """ + if (v.isPresent()) { + System.out.println("v: " + v.get()); + }""") + ); + testPositive(base, testCases); + } + + @Test + public void testPositiveInlineTagMarkup_BlankLinesEquivalence(Path base) throws Exception { + var testCases = List.of( + new TestCase( + """ + // @start region="example" + if (v.isPresent()) { + System.out.println("v: " + v.get()); + } + // @end + """, + """ + if (v.isPresent()) { + System.out.println("v: " + v.get()); + } + """), + new TestCase( + """ + if (v.isPresent()) { // @start region="example" + System.out.println("v: " + v.get()); + } // @end + """, + """ + if (v.isPresent()) { + System.out.println("v: " + v.get()); + } + """), + new TestCase( + """ + // @start region="example" : + if (v.isPresent()) { + System.out.println("v: " + v.get()); + // @end : + } + """, + """ + if (v.isPresent()) { + System.out.println("v: " + v.get()); + } + """) + ); + testPositive(base, testCases); + } + + @Test + public void testPositiveInlineTagMarkup_BlankLinesFromStartEnd(Path base) throws Exception { + // A markup line that contains either @start or @end is removed. + var testCases = List.of( + new TestCase(""" + First line + // @start region="a" + Third line + // @end + Fifth line + """, + """ + First line + Third line + Fifth line + """), + new TestCase(""" + First line + // @start region="a" + // @start region="b" + Third line + // @end + Fifth line + // @end + """, + """ + First line + Third line + Fifth line + """), + // note incidental whitespace removal in test cases below + new TestCase("a", """ + First line + // @start region="a" + Third line + // @end + Fifth line + """, + + """ + Third line + """), + new TestCase("b", """ + First line + // @start region="a" + // @start region="b" + Third line + // @end + Fifth line + // @end + """, + """ + Third line + """) + ); + testPositive(base, testCases); + } + + @Test + public void testPositiveInlineTagMarkup_BlankLinesFromNextLineMarkup(Path base) throws Exception { + // A markup line that refers to the next line is removed. + var testCases = List.of( + new TestCase(""" + First line + // @highlight: + Third line + """, + """ + First line + Third line + """), + new TestCase(""" + First line + // @link target="Object#equals(Object)": + Third line + """, + replace(""" + First line + link(Third line) + """, "link\\((.+?)\\)", r -> link(true, "java.lang.Object#equals(Object)", r.group(1))) + ), + new TestCase(""" + First line + // @replace regex=.+ replacement="x": + Third line + """, + """ + First line + x + """), + new TestCase(""" + First line + // @start region=a: + Third line + // @end: + Fifth line + """, + """ + First line + Third line + Fifth line + """) + ); + testPositive(base, testCases); + } + + @Test + public void testPositiveInlineTagMarkup_FalseMarkup(Path base) throws Exception { + var testCases = List.of( + new TestCase( + """ + First line + // @formatter:off + Second Line + Third line + // @formatter:on + Fourth line + """, + """ + First line + // @formatter:off + Second Line + Third line + // @formatter:on + Fourth line + """), + new TestCase("showThis", + """ + First line + // @formatter:off + // @start region=showThis + Second Line + Third line + // @end region + // @formatter:on + Fourth line + """, + """ + Second Line + Third line + """) + ); + testPositive(base, testCases); + } + + @Test + public void testPositiveInlineTagMarkup_NextLineTwoTags(Path base) throws Exception { + var firstTag = new String[]{ + "@highlight string=firstWord", + "@replace string=secondWord replacement=replacedSecondWord", + "@link substring=firstWord target=java.lang.Object"}; + var secondTag = new String[]{ + "@highlight string=secondWord", + "@replace string=firstWord replacement=replacedFirstWord", + "@link substring=secondWord target=java.lang.Thread"}; + List testCases = new ArrayList<>(); + for (var f : firstTag) { + for (var s : secondTag) + for (var separator : List.of("", " ")) { + var t = new TestCase( + """ + first-line // %s %s%s: + firstWord secondWord thirdWord + """.formatted(f, s, separator), + """ + first-line + firstWord secondWord thirdWord // %s %s + """.formatted(f, s)); + testCases.add(t); + } + } + testEquivalence(base, testCases); + } + + record Snippet(String region, String snippet) { } + + private void testEquivalence(Path base, List testCases) throws IOException { + // group all the testcases in just two runs + Path out1 = base.resolve("out1"); + Path out2 = base.resolve("out2"); + run(base.resolve("src1"), out1, testCases.stream().map(t -> new Snippet(t.region(), t.input())).toList()); + run(base.resolve("src2"), out2, testCases.stream().map(t -> new Snippet(t.region(), t.expectedOutput())).toList()); + match(out1, out2, (p, a) -> /* p.toString().endsWith(".html") */ true); + } + + private void run(Path source, Path target, List snippets) throws IOException { + StringBuilder methods = new StringBuilder(); + forEachNumbered(snippets, (i, n) -> { + String r = i.region.isBlank() ? "" : "region=" + i.region; + var methodDef = """ + + /** + {@snippet %s: + %s}*/ + public void case%s() {} + """.formatted(r, i.snippet(), n); + methods.append(methodDef); + }); + var classDef = """ + public class A { + %s + } + """.formatted(methods.toString()); + Path src = Files.createDirectories(source); + tb.writeJavaFiles(src, classDef); + javadoc("-d", target.toString(), + "--limit-modules", "java.base", + "-quiet", "-nohelp", "-noindex", "-nonavbar", "-nosince", + "-notimestamp", "-notree", "-Xdoclint:none", + "-sourcepath", src.toString(), + src.resolve("A.java").toString()); + checkExit(Exit.OK); + checkNoCrashes(); + } + + private static String link(boolean linkPlain, + String targetReference, + String content) + throws UncheckedIOException { + + // The HTML tag generated from the @link snippet markup tag is the + // same as that of the {@link} Standard doclet tag. This is specified + // and can be used for comparison and testing. + + // generate documentation for {@link} to grab its HTML tag; + // generate documentation at low cost and do not interfere with the + // calling test state; for that, do not create file trees, do not write + // to std out/err, and generally try to keep everything in memory + + String source = """ + /** {@link %s %s} */ + public interface A { } + """.formatted(targetReference, content); + + JavaFileObject src = new JavaFileObject() { + @Override + public Kind getKind() {return Kind.SOURCE;} + + @Override + public boolean isNameCompatible(String simpleName, Kind kind) { + return kind == Kind.SOURCE; + } + + @Override + public NestingKind getNestingKind() {return NestingKind.TOP_LEVEL;} + + @Override + public Modifier getAccessLevel() {return Modifier.PUBLIC;} + + @Override + public URI toUri() {throw new UnsupportedOperationException();} + + @Override + public String getName() {return "A.java";} + + @Override + public InputStream openInputStream() { + return new ByteArrayInputStream(source.getBytes(StandardCharsets.UTF_8)); + } + + @Override + public OutputStream openOutputStream() { + throw new UnsupportedOperationException("Read only"); + } + + @Override + public Reader openReader(boolean ignoreEncodingErrors) { + return new StringReader(source); + } + + @Override + public CharSequence getCharContent(boolean ignoreEncodingErrors) { + return source; + } + + @Override + public Writer openWriter() { + throw new UnsupportedOperationException("Read only"); + } + + @Override + public long getLastModified() { + return 0; + } + + @Override + public boolean delete() { + throw new UnsupportedOperationException("Read only"); + } + }; + + var documentationTool = ToolProvider.getSystemDocumentationTool(); + var writer = new StringWriter(); + + // FileManager has to be StandardJavaFileManager; JavaDoc is adamant about it + class InMemoryFileManager extends ToolBox.MemoryFileManager + implements StandardJavaFileManager { + + private final StandardJavaFileManager delegate = documentationTool + .getStandardFileManager(null, null, null); + + @Override + public Iterable getJavaFileObjectsFromFiles(Iterable files) { + return delegate.getJavaFileObjectsFromFiles(files); + } + + @Override + public Iterable getJavaFileObjects(File... files) { + return delegate.getJavaFileObjects(files); + } + + @Override + public Iterable getJavaFileObjectsFromStrings(Iterable names) { + return delegate.getJavaFileObjectsFromStrings(names); + } + + @Override + public Iterable getJavaFileObjects(String... names) { + return delegate.getJavaFileObjects(names); + } + + @Override + public void setLocation(Location location, Iterable files) throws IOException { + delegate.setLocation(location, files); + } + + @Override + public Iterable getLocation(Location location) { + return delegate.getLocation(location); + } + + @Override + public FileObject getFileForOutput(Location location, + String packageName, + String relativeName, + FileObject sibling) { + return getJavaFileForOutput(location, packageName + relativeName, JavaFileObject.Kind.OTHER, null); + } + } + try { + var fileManager = new InMemoryFileManager(); + fileManager.setLocation(DOCUMENTATION_OUTPUT, Collections.singleton(new File("."))); + // exclude extraneous output; we're only after @link + List options = List.of("--limit-modules", "java.base", + "-quiet", "-nohelp", "-noindex", "-nonavbar", "-nosince", + "-notimestamp", "-notree", "-Xdoclint:none"); + var documentationTask = documentationTool.getTask(null, fileManager, + null, null, options, List.of(src)); + if (!documentationTask.call()) { + throw new IOException(writer.toString()); + } + String output = fileManager.getFileString(DOCUMENTATION_OUTPUT, "A.html"); + // use the [^<>] regex to select HTML elements that immediately enclose "content" + Matcher m = Pattern.compile("(?is)]*\" title=\"[^<>]*\" class=\"[^<>]*\">" + + content + "").matcher(output); + if (!m.find()) { + throw new IOException(output); + } + return m.group(0); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + private static String replace(String source, + String regex, + Function replacer) { + return Pattern.compile(regex).matcher(source).replaceAll(replacer); + } + + private static final AtomicLong UNIQUE_INTEGER_NUMBER = new AtomicLong(); + + private static Collection generateStartEndVariants() { + var variants = new ArrayList(); + for (var start : startAttributes()) + for (var end : endAttributes()) { + var region = uniqueValue(); + var v = new StartEndVariant(region, + "@start" + start.apply(region), + "@end" + end.apply(region)); + variants.add(v); + } + return variants; + } + + private static String uniqueValue() { + return "auto_generated_value_" + UNIQUE_INTEGER_NUMBER.incrementAndGet(); + } + + public static Collection> startAttributes() { + return attributes("region"); + } + + private static Collection> endAttributes() { + var variants = new ArrayList>(); + variants.add(value -> ""); + variants.add(value -> " region"); + variants.addAll(attributes("region")); + return variants; + } + + private static Collection> attributes(String name) { + var variants = new ArrayList>(); + for (var whitespace1 : List.of(" ", " ")) + for (var whitespace2 : List.of("", " ")) + for (var quote : List.of("", "'", "\"")) + for (var whitespace3 : List.of("", " ")) { + Function f = value -> + whitespace1 + name + whitespace2 + + "=" + whitespace3 + (quote + value + quote); + variants.add(f); + } + return variants; + } + + record StartEndVariant(String region, String start, String end) {} +} diff --git a/test/langtools/jdk/javadoc/doclet/testSnippetTag/TestSnippetPathOption.java b/test/langtools/jdk/javadoc/doclet/testSnippetTag/TestSnippetPathOption.java new file mode 100644 index 0000000000000000000000000000000000000000..208faa45a4bdf76c650a46608ad435ece9d7e22f --- /dev/null +++ b/test/langtools/jdk/javadoc/doclet/testSnippetTag/TestSnippetPathOption.java @@ -0,0 +1,220 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8266666 + * @summary Implementation for snippets + * @library /tools/lib ../../lib + * @modules jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.main + * jdk.javadoc/jdk.javadoc.internal.tool + * @build javadoc.tester.* toolbox.ToolBox toolbox.ModuleBuilder builder.ClassBuilder + * @run main TestSnippetPathOption + */ + +import java.io.File; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class TestSnippetPathOption extends SnippetTester { + + public static void main(String... args) throws Exception { + new TestSnippetPathOption().runTests(m -> new Object[]{Paths.get(m.getName())}); + } + + /* + # snippet-files snippet-path result + ---+--------------+--------------+--------------------- + 1 + + snippet-files + 2 + invalid snippet-files + 3 - + snippet-path + 4 - invalid error + */ + + @Test + public void test1(Path base) throws Exception { + Path src = Files.createDirectories(base.resolve("src")); + tb.createDirectories(src.resolve("directoryA"), src.resolve("directoryB")); + tb.writeFile(src.resolve("directoryA/mysnippet.txt"), "Hello, directoryA!"); + tb.writeFile(src.resolve("directoryB/mysnippet.txt"), "Hello, directoryB!"); + tb.writeFile(src.resolve("pkg/snippet-files/mysnippet.txt"), "Hello, snippet-files!"); + tb.writeJavaFiles(src, """ + package pkg; + + /** {@snippet file="mysnippet.txt"} */ + public class X { } + """); + String snippetPathValue = Stream.of("directoryA", "directoryB") + .map(src::resolve) + .map(Path::toAbsolutePath) + .map(Path::toString) + .collect(Collectors.joining(File.pathSeparator)); + javadoc("-d", base.resolve("out").toString(), + "--snippet-path", snippetPathValue, + "-sourcepath", src.toString(), + "pkg"); + checkExit(Exit.OK); + checkOutput("pkg/X.html", true, "Hello, snippet-files!"); + checkOutput("pkg/X.html", false, "Hello, directoryA!"); + checkOutput("pkg/X.html", false, "Hello, directoryB!"); + } + + @Test + public void test2(Path base) throws Exception { + Path src = Files.createDirectories(base.resolve("src")); + tb.createDirectories(src.resolve("directoryA"), src.resolve("directoryB")); + tb.writeFile(src.resolve("pkg/snippet-files/mysnippet.txt"), "Hello, snippet-files!"); + tb.writeJavaFiles(src, """ + package pkg; + + /** {@snippet file="mysnippet.txt"} */ + public class X { } + """); + String snippetPathValue = Stream.of("directoryA", "directoryB") + .map(src::resolve) + .map(Path::toAbsolutePath) + .map(Path::toString) + .collect(Collectors.joining(File.pathSeparator)); + javadoc("-d", base.resolve("out").toString(), + "--snippet-path", snippetPathValue, + "-sourcepath", src.toString(), + "pkg"); + checkExit(Exit.OK); + checkOutput("pkg/X.html", true, "Hello, snippet-files!"); + } + + @Test + public void test3(Path base) throws Exception { + Path src = Files.createDirectories(base.resolve("src")); + tb.createDirectories(src.resolve("directoryA"), src.resolve("directoryB")); + tb.writeFile(src.resolve("directoryA/mysnippet.txt"), "Hello, directoryA!"); + tb.writeFile(src.resolve("directoryB/mysnippet.txt"), "Hello, directoryB!"); + tb.writeJavaFiles(src, """ + package pkg; + + /** {@snippet file="mysnippet.txt"} */ + public class X { } + """); + String snippetPathValue = Stream.of("directoryA", "directoryB") + .map(src::resolve) + .map(Path::toAbsolutePath) + .map(Path::toString) + .collect(Collectors.joining(File.pathSeparator)); + javadoc("-d", base.resolve("out").toString(), + "--snippet-path", snippetPathValue, + "-sourcepath", src.toString(), + "pkg"); + checkExit(Exit.OK); + checkOutput("pkg/X.html", true, "Hello, directoryA!"); + checkOutput("pkg/X.html", false, "Hello, directoryB!"); + } + + @Test + public void test4(Path base) throws Exception { + Path src = Files.createDirectories(base.resolve("src")); + tb.writeJavaFiles(src, """ + package pkg; + + /** {@snippet file="mysnippet.txt"} */ + public class X { } + """); + String snippetPathValue = Stream.of("directoryA", "directoryB") + .map(src::resolve) + .map(Path::toAbsolutePath) + .map(Path::toString) + .collect(Collectors.joining(File.pathSeparator)); + javadoc("-d", base.resolve("out").toString(), + "--snippet-path", snippetPathValue, + "-sourcepath", src.toString(), + "pkg"); + checkExit(Exit.ERROR); + } + + /* + * Tests that the elements of the snippet path are iteratively searched + * until the file is found. In particular, tests that if the file is not + * immediately found, the search is not abandoned. + */ + @Test + public void testSearchPath(Path base) throws Exception { + Path src = Files.createDirectories(base.resolve("src")); + tb.createDirectories(src.resolve("directoryA"), src.resolve("directoryB")); + // do not put snippet in directoryA; only put snippet in directoryB + tb.writeFile(src.resolve("directoryB/mysnippet.txt"), "Hello, directoryB!"); + tb.writeJavaFiles(src, """ + package pkg; + + /** {@snippet file="mysnippet.txt"} */ + public class X { } + """); + // directoryA goes first, assuming that paths are searched in + // the same order they are specified in + String snippetPathValue = Stream.of("directoryA", "directoryB") + .map(src::resolve) + .map(Path::toAbsolutePath) + .map(Path::toString) + .collect(Collectors.joining(File.pathSeparator)); + javadoc("-d", base.resolve("out").toString(), + "--snippet-path", snippetPathValue, + "-sourcepath", src.toString(), + "pkg"); + checkExit(Exit.OK); + checkOutput("pkg/X.html", true, "Hello, directoryB!"); + } + + /* + * Tests translation from FQN (the "class" attribute) to file path + * (the "file" attribute). + */ + @Test + public void testClassToFile(Path base) throws Exception { + Path src = Files.createDirectories(base.resolve("src")); + Path directoryA = Files.createDirectories(src.resolve("directoryA")); + tb.writeJavaFiles(directoryA, """ + package com.example.snippet; + + public interface Y { } + """); + tb.writeJavaFiles(src, """ + package pkg; + + /** {@snippet class="com.example.snippet.Y"} */ + public class X { } + """); + String snippetPathValue = Stream.of("directoryA") + .map(src::resolve) + .map(Path::toAbsolutePath) + .map(Path::toString) + .collect(Collectors.joining(File.pathSeparator)); + javadoc("-d", base.resolve("out").toString(), + "--snippet-path", snippetPathValue, + "-sourcepath", src.toString(), + "pkg"); + checkExit(Exit.OK); + checkOutput("pkg/X.html", true, "public interface Y { }"); + } +} diff --git a/test/langtools/jdk/javadoc/doclet/testSnippetTag/TestSnippetTag.java b/test/langtools/jdk/javadoc/doclet/testSnippetTag/TestSnippetTag.java index a13f75ddae6e5c4aa4b0e8c812f74a5200a4f1ed..4b0dd06a2a246adc35c34432829beaf02cea552f 100644 --- a/test/langtools/jdk/javadoc/doclet/testSnippetTag/TestSnippetTag.java +++ b/test/langtools/jdk/javadoc/doclet/testSnippetTag/TestSnippetTag.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8266666 8275788 + * @bug 8266666 8275788 8276964 * @summary Implementation for snippets * @library /tools/lib ../../lib * @modules jdk.compiler/com.sun.tools.javac.api @@ -33,27 +33,21 @@ * @run main TestSnippetTag */ -import builder.ClassBuilder; -import builder.ClassBuilder.MethodBuilder; -import javadoc.tester.JavadocTester; -import toolbox.ModuleBuilder; -import toolbox.ToolBox; - import java.io.IOException; -import java.io.UncheckedIOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardOpenOption; -import java.util.Arrays; +import java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Function; -import java.util.function.ObjIntConsumer; -import java.util.regex.Matcher; import java.util.regex.Pattern; -import java.util.stream.Stream; + +import builder.ClassBuilder; +import builder.ClassBuilder.MethodBuilder; +import toolbox.ModuleBuilder; // FIXME // 0. Add tests for snippets in all types of elements: e.g., fields @@ -63,7 +57,22 @@ import java.util.stream.Stream; // 3. Add tests for hybrid snippets /* - * General notes. + * General notes + * ============= + * + * To simplify maintenance of this test suite, a test name uses a convention. + * By convention, a test name is a concatenation of the following parts: + * + * 1. "test" + * 2. ("Positive", "Negative") + * 3. ("Inline", "External", "Hybrid") + * 4. ("Tag", "Markup") + * 5. + * + * A test can be either positive or negative; it cannot be both or neither. + * A test can exercise inline, external or hybrid variant or any combination + * thereof, including none at all. A test can exercise tag syntax, markup syntax + * or both. * * 1. Some of the below tests could benefit from using a combinatorics library * as they are otherwise very wordy. @@ -73,35 +82,27 @@ import java.util.stream.Stream; * if x is passed to that method additionally N times: JavadocTester.checkOutput(x, x, ..., x). * This is because a single occurrence of x in the output will be matched N times. */ -public class TestSnippetTag extends JavadocTester { - - private final ToolBox tb = new ToolBox(); - - private TestSnippetTag() { } +public class TestSnippetTag extends SnippetTester { public static void main(String... args) throws Exception { new TestSnippetTag().runTests(m -> new Object[]{Paths.get(m.getName())}); } /* - * Make sure the "id" and "lang" attributes defined in JEP 413 are rendered - * properly as recommended by the HTML5 specification. + * Make sure the "id" and "lang" attributes defined in JEP 413 are translated + * to HTML. In particular, verify that the "lang" attribute is translated + * to a value added to the "class" attribute as recommended by the HTML5 specification: + * https://html.spec.whatwg.org/multipage/text-level-semantics.html#the-code-element */ @Test - public void testIdAndLangAttributes(Path base) throws IOException { + public void testPositiveInlineTag_IdAndLangAttributes(Path base) throws IOException { Path srcDir = base.resolve("src"); Path outDir = base.resolve("out"); // A record of a snippet content and matching expected attribute values - record SnippetAttributes(String content, String id, String lang) { - public String idAttribute() { - return id == null ? "" : " id=\"" + id + "\""; - } - public String langAttribute() { - return lang == null ? "" : " class=\"language-" + lang + "\""; - } - } + record SnippetAttributes(String content, String id, String lang) { } + // TODO: use combinatorial methods, e.g. just like in TestSnippetMarkup final var snippets = List.of( new SnippetAttributes(""" {@snippet id="foo1" : @@ -218,29 +219,29 @@ public class TestSnippetTag extends JavadocTester { checkExit(Exit.OK); checkLinks(); for (int j = 0; j < snippets.size(); j++) { - SnippetAttributes snippet = snippets.get(j); + var attr = snippets.get(j); + var snippetHtml = getSnippetHtmlRepresentation("pkg/A.html", " Hello, Snippet!\n", + Optional.ofNullable(attr.lang()), Optional.ofNullable(attr.id())); checkOutput("pkg/A.html", true, """ case%s()
          A method. \s -
          -
              Hello, Snippet!
          -                        
          -
          - """.formatted(j, snippet.idAttribute(), snippet.langAttribute())); + %s + """.formatted(j, snippetHtml)); } } /* - * Make sure the lang attribute is derived correctly from the snippet source file - * for external snippets when it is not defined in the snippet. Defining the lang - * attribute in the snippet should always override this mechanism. + * If the "lang" attribute is absent in the snippet tag for an external snippet, + * then the "class" attribute is derived from the snippet source file extension. + * + * If the "class" attribute can be derived both from the "lang" attribute and + * the file extension, then it is derived from the "lang" attribute. */ + // TODO: restructure this as a list of TestCase records @Test - public void testExternalImplicitAttributes(Path base) throws IOException { + public void testPositiveInlineExternalTagMarkup_ImplicitAttributes(Path base) throws IOException { Path srcDir = base.resolve("src"); Path outDir = base.resolve("out"); @@ -276,60 +277,27 @@ public class TestSnippetTag extends JavadocTester { "com.example"); checkExit(Exit.OK); checkLinks(); + final var javaContent = """ + System.out.println(msg); + """; + final var propertiesContent = """ + user=jane + home=/home/jane + """; checkOutput("com/example/Cls.html", true, - """ -
          
          -                    System.out.println(msg);
          -                    
          """, - """ -
          
          -                    System.out.println(msg);
          -                    
          """, - """ -
          
          -                    System.out.println(msg);
          -                    
          """, - """ -
          
          -                    System.out.println(msg);
          -                    
          """, - """ -
          
          -                    System.out.println(msg);
          -                    
          """, - """ -
          
          -                    System.out.println(msg);
          -                    
          """, - """ -
          user=jane
          -                    home=/home/jane
          -                    
          """, - """ -
          user=jane
          -                    home=/home/jane
          -                    
          """, - """ -
          user=jane
          -                    home=/home/jane
          -                    
          """); - } - - /* - * This is a convenience method to iterate through a list. - * Unlike List.forEach, this method provides the consumer not only with an - * element but also that element's index. - * - * See JDK-8184707. - */ - private static void forEachNumbered(List list, ObjIntConsumer action) { - for (var iterator = list.listIterator(); iterator.hasNext(); ) { - action.accept(iterator.next(), iterator.previousIndex()); - } + getSnippetHtmlRepresentation("com/example/Cls.html", javaContent, Optional.of("java"), Optional.of("snippet1")), + getSnippetHtmlRepresentation("com/example/Cls.html", javaContent, Optional.of("java"), Optional.of("snippet2")), + getSnippetHtmlRepresentation("com/example/Cls.html", javaContent, Optional.of("none"), Optional.of("snippet3")), + getSnippetHtmlRepresentation("com/example/Cls.html", javaContent, Optional.of("none"), Optional.of("snippet4")), + getSnippetHtmlRepresentation("com/example/Cls.html", javaContent, Optional.empty(), Optional.of("snippet5")), + getSnippetHtmlRepresentation("com/example/Cls.html", javaContent, Optional.empty(), Optional.of("snippet6")), + getSnippetHtmlRepresentation("com/example/user.properties", propertiesContent, Optional.of("properties"), Optional.of("snippet7")), + getSnippetHtmlRepresentation("com/example/user.properties", propertiesContent, Optional.of("none"), Optional.of("snippet8")), + getSnippetHtmlRepresentation("com/example/user.properties", propertiesContent, Optional.empty(), Optional.of("snippet9"))); } @Test - public void testBadTagSyntax(Path base) throws IOException { + public void testNegativeInlineTag_BadTagSyntax(Path base) throws IOException { // TODO consider improving diagnostic output by providing more specific // error messages and better positioning the caret (depends on JDK-8273244) @@ -666,50 +634,13 @@ public class TestSnippetTag extends JavadocTester { )); } - // TODO This is a temporary method; it should be removed after JavadocTester has provided similar functionality (JDK-8273154). - private void checkOrder(Output output, String... strings) { - String outputString = getOutput(output); - int prevIndex = -1; - for (String s : strings) { - s = s.replace("\n", NL); // normalize new lines - int currentIndex = outputString.indexOf(s, prevIndex + 1); - checking("output: " + output + ": " + s + " at index " + currentIndex); - if (currentIndex == -1) { - failed(output + ": " + s + " not found."); - continue; - } - if (currentIndex > prevIndex) { - passed(output + ": " + " is in the correct order"); - } else { - failed(output + ": " + " is in the wrong order."); - } - prevIndex = currentIndex; - } - } - - /* - * When checking for errors, it is important not to confuse one error with - * another. This method checks that there are no crashes (which are also - * errors) by checking for stack traces. We never expect crashes. - */ - private void checkNoCrashes() { - checking("check crashes"); - Matcher matcher = Pattern.compile("\s*at.*\\(.*\\.java:\\d+\\)") - .matcher(getOutput(Output.STDERR)); - if (!matcher.find()) { - passed(""); - } else { - failed("Looks like a stacktrace: " + matcher.group()); - } - } - /* * A colon that is not separated from a tag name by whitespace is considered * a part of that name. This behavior is historical. For more context see, * for example, JDK-4750173. */ @Test - public void testUnknownTag(Path base) throws IOException { + public void testNegativeInlineTagUnknownTag(Path base) throws IOException { Path srcDir = base.resolve("src"); Path outDir = base.resolve("out"); final var unknownTags = List.of( @@ -746,7 +677,7 @@ public class TestSnippetTag extends JavadocTester { } @Test - public void testInline(Path base) throws Exception { + public void testPositiveInlineTag(Path base) throws Exception { Path srcDir = base.resolve("src"); Path outDir = base.resolve("out"); @@ -948,16 +879,12 @@ public class TestSnippetTag extends JavadocTester { """ case%s()
          -
          -
          %s
          -
          """.formatted(id, t.expectedOutput())); + %s""".formatted(id, getSnippetHtmlRepresentation("pkg/A.html", t.expectedOutput()))); }); } @Test - public void testExternalFile(Path base) throws Exception { + public void testPositiveExternalTag_File(Path base) throws Exception { Path srcDir = base.resolve("src"); Path outDir = base.resolve("out"); @@ -1044,30 +971,12 @@ public class TestSnippetTag extends JavadocTester { """ case%s()
          -
          -
          %s
          -
          """.formatted(index, expectedOutput)); + %s""".formatted(index, getSnippetHtmlRepresentation("pkg/A.html", expectedOutput))); }); } - // TODO: - // Explore the toolbox.ToolBox.writeFile and toolbox.ToolBox.writeJavaFiles methods: - // see if any of them could be used instead of this one - private void addSnippetFile(Path srcDir, String packageName, String fileName, String content) throws UncheckedIOException { - String[] components = packageName.split("\\."); - Path snippetFiles = Path.of(components[0], Arrays.copyOfRange(components, 1, components.length)).resolve("snippet-files"); - try { - Path p = Files.createDirectories(srcDir.resolve(snippetFiles)); - Files.writeString(p.resolve(fileName), content, StandardOpenOption.CREATE_NEW); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - @Test - public void testInlineSnippetInDocFiles(Path base) throws IOException { + public void testPositiveInlineTag_InDocFiles(Path base) throws IOException { Path srcDir = base.resolve("src"); Path outDir = base.resolve("out"); // If there is no *.java files, javadoc will not create an output @@ -1109,7 +1018,7 @@ public class TestSnippetTag extends JavadocTester { } @Test - public void testExternalSnippetInDocFiles(Path base) throws IOException { + public void testPositiveExternalTag_InDocFiles(Path base) throws IOException { Path srcDir = base.resolve("src"); Path outDir = base.resolve("out"); // If there is no *.java files, javadoc will not create an output @@ -1151,7 +1060,7 @@ public class TestSnippetTag extends JavadocTester { } @Test - public void testExternalFileNotFound(Path base) throws Exception { + public void testNegativeExternalTag_FileNotFound(Path base) throws Exception { Path srcDir = base.resolve("src"); Path outDir = base.resolve("out"); var fileName = "text.txt"; @@ -1171,11 +1080,17 @@ public class TestSnippetTag extends JavadocTester { checkOutput(Output.OUT, true, """ A.java:4: error: File not found: %s""".formatted(fileName)); + checkOutput("pkg/A.html", true, """ +
          + invalid @snippet +
          File not found: text.txt
          +
          + """); checkNoCrashes(); } - @Test // TODO perhaps this could be unified with testExternalFile - public void testExternalFileModuleSourcePath(Path base) throws Exception { + @Test // TODO perhaps this could be unified with testPositiveExternalTagFile + public void testNegativeExternalTag_FileModuleSourcePath(Path base) throws Exception { Path srcDir = base.resolve("src"); Path outDir = base.resolve("out"); var fileName = "snippet.txt"; @@ -1200,8 +1115,8 @@ public class TestSnippetTag extends JavadocTester { checkExit(Exit.OK); } - @Test // TODO perhaps this could be unified with testExternalFileNotFound - public void testExternalFileNotFoundModuleSourcePath(Path base) throws Exception { + @Test // TODO perhaps this could be unified with testNegativeExternalTagFileNotFound + public void testNegativeExternalTag_FileNotFoundModuleSourcePath(Path base) throws Exception { Path srcDir = base.resolve("src"); Path outDir = base.resolve("out"); var fileName = "text.txt"; @@ -1230,7 +1145,7 @@ public class TestSnippetTag extends JavadocTester { } @Test - public void testNoContents(Path base) throws Exception { + public void testNegativeTag_NoContents(Path base) throws Exception { Path srcDir = base.resolve("src"); Path outDir = base.resolve("out"); new ClassBuilder(tb, "pkg.A") @@ -1246,11 +1161,47 @@ public class TestSnippetTag extends JavadocTester { checkOutput(Output.OUT, true, """ A.java:3: error: @snippet does not specify contents"""); + checkOutput("pkg/A.html", true, """ +
          + invalid @snippet +
          @snippet does not specify contents
          +
          + """); checkNoCrashes(); } @Test - public void testConflict20(Path base) throws Exception { + public void testNegativeExternalTagMarkup(Path base) throws Exception { + // External snippet issues are handled similarly to those of internal snippet + Path srcDir = base.resolve("src"); + Path outDir = base.resolve("out"); + addSnippetFile(srcDir, "pkg", "file.txt", """ + // @start + """ + ); + ClassBuilder classBuilder = new ClassBuilder(tb, "pkg.A") + .setModifiers("public", "class") + .addMembers( + MethodBuilder + .parse("public void case0() { }") + .setComments(""" + {@snippet file="file.txt"} + """)); + classBuilder.write(srcDir); + javadoc("-d", outDir.toString(), + "-sourcepath", srcDir.toString(), + "pkg"); + checkExit(Exit.ERROR); + checkOutput(Output.OUT, true, +""" +: error: snippet markup: missing attribute "region" +// @start + ^"""); + checkNoCrashes(); + } + + @Test + public void testNegativeInlineTag_AttributeConflict20(Path base) throws Exception { Path srcDir = base.resolve("src"); Path outDir = base.resolve("out"); new ClassBuilder(tb, "pkg.A") @@ -1272,11 +1223,17 @@ public class TestSnippetTag extends JavadocTester { checkOutput(Output.OUT, true, """ A.java:3: error: @snippet specifies multiple external contents, which is ambiguous"""); + checkOutput("pkg/A.html", true, """ +
          + invalid @snippet +
          @snippet specifies multiple external contents, which is ambiguous
          +
          + """); checkNoCrashes(); } @Test - public void testConflict30(Path base) throws Exception { + public void testNegativeInlineTag_AttributeConflict30(Path base) throws Exception { Path srcDir = base.resolve("src"); Path outDir = base.resolve("out"); new ClassBuilder(tb, "pkg.A") @@ -1297,21 +1254,8 @@ public class TestSnippetTag extends JavadocTester { checkNoCrashes(); } - // TODO: perhaps this method could be added to JavadocTester - private void checkOutputEither(Output out, String first, String... other) { - checking("checkOutputEither"); - String output = getOutput(out); - Stream strings = Stream.concat(Stream.of(first), Stream.of(other)); - Optional any = strings.filter(output::contains).findAny(); - if (any.isPresent()) { - passed(": following text is found:\n" + any.get()); - } else { - failed(": nothing found"); - } - } - @Test - public void testConflict60(Path base) throws Exception { + public void testNegativeInlineTag_AttributeConflict60(Path base) throws Exception { Path srcDir = base.resolve("src"); Path outDir = base.resolve("out"); new ClassBuilder(tb, "pkg.A") @@ -1331,7 +1275,7 @@ public class TestSnippetTag extends JavadocTester { } @Test - public void testConflict70(Path base) throws Exception { + public void testNegativeInlineTag_AttributeConflict70(Path base) throws Exception { Path srcDir = base.resolve("src"); Path outDir = base.resolve("out"); new ClassBuilder(tb, "pkg.A") @@ -1351,7 +1295,7 @@ public class TestSnippetTag extends JavadocTester { } @Test - public void testConflict80(Path base) throws Exception { + public void testNegativeInlineTag_AttributeConflict80(Path base) throws Exception { Path srcDir = base.resolve("src"); Path outDir = base.resolve("out"); new ClassBuilder(tb, "pkg.A") @@ -1375,7 +1319,7 @@ public class TestSnippetTag extends JavadocTester { } @Test - public void testConflict90(Path base) throws Exception { + public void testNegativeInlineTag_AttributeConflict90(Path base) throws Exception { Path srcDir = base.resolve("src"); Path outDir = base.resolve("out"); new ClassBuilder(tb, "pkg.A") @@ -1399,7 +1343,7 @@ public class TestSnippetTag extends JavadocTester { } @Test - public void testErrorPositionResolution(Path base) throws Exception { + public void testNegativeTag_PositionResolution(Path base) throws Exception { Path srcDir = base.resolve("src"); Path outDir = base.resolve("out"); new ClassBuilder(tb, "pkg.A") @@ -1427,7 +1371,7 @@ public class TestSnippetTag extends JavadocTester { } @Test - public void testRegion(Path base) throws Exception { + public void testPositiveInlineTag_AttributeConflictRegion(Path base) throws Exception { record TestCase(Snippet snippet, String expectedOutput) { } final var testCases = List.of( new TestCase(newSnippetBuilder() @@ -1605,11 +1549,7 @@ public class TestSnippetTag extends JavadocTester { """ case%s()
          -
          -
          %s
          -
          """.formatted(index, t.expectedOutput())); + %s""".formatted(index, getSnippetHtmlRepresentation("pkg/A.html", t.expectedOutput()))); }); } @@ -1647,7 +1587,7 @@ public class TestSnippetTag extends JavadocTester { } @Test - public void testAttributeValueSyntaxUnquotedCurly(Path base) throws Exception { + public void testNegativeInlineTagMarkup_AttributeValueSyntaxUnquotedCurly(Path base) throws Exception { Path srcDir = base.resolve("src"); Path outDir = base.resolve("out"); /* @@ -1681,7 +1621,7 @@ public class TestSnippetTag extends JavadocTester { } @Test - public void testAttributeValueSyntaxCurly(Path base) throws Exception { + public void testPositiveInlineTagMarkup_SyntaxCurly(Path base) throws Exception { /* * The snippet has to be external, otherwise its content would * interfere with the test: that internal closing curly would @@ -1722,24 +1662,16 @@ public class TestSnippetTag extends JavadocTester { """ case0()
          -
          -
          -
          """); + """ + getSnippetHtmlRepresentation("pkg/A.html", "")); checkOutput("pkg/A.html", true, """ case1()
          -
          -
          -
          """); + """ + getSnippetHtmlRepresentation("pkg/A.html", "")); } - @Test - public void testAttributeValueSyntax(Path base) throws Exception { + @Test // TODO: use combinatorial methods + public void testPositiveExternalTagMarkup_AttributeValueSyntax(Path base) throws Exception { Path srcDir = base.resolve("src"); Path outDir = base.resolve("out"); // Test most expected use cases for external snippet @@ -1832,17 +1764,13 @@ public class TestSnippetTag extends JavadocTester { """ case%s()
          -
          -
          2
          -
          - """.formatted(j)); + %s + """.formatted(j, getSnippetHtmlRepresentation("pkg/A.html", "2"))); } } @Test - public void testComment(Path base) throws Exception { + public void testPositiveInlineTagMarkup_Comment(Path base) throws Exception { record TestCase(Snippet snippet, String expectedOutput) { } final var testCases = List.of( new TestCase(newSnippetBuilder() @@ -1916,16 +1844,12 @@ public class TestSnippetTag extends JavadocTester { """ case%s()
          -
          -
          %s
          -
          """.formatted(index, t.expectedOutput())); + %s""".formatted(index, getSnippetHtmlRepresentation("pkg/A.html", t.expectedOutput()))); }); } @Test - public void testRedundantFileNotFound(Path base) throws Exception { + public void testNegativeHybridTag_FileNotFound(Path base) throws Exception { Path srcDir = base.resolve("src"); Path outDir = base.resolve("out"); var fileName = "text.txt"; @@ -1950,7 +1874,113 @@ public class TestSnippetTag extends JavadocTester { } @Test - public void testRedundantRegionNotFound(Path base) throws Exception { + public void testNegativeTag_ValuelessAttributes(Path base) throws IOException { + // none of these attributes should ever be valueless + record TestCase(String input, String expectedError) { } + var testCases = new ArrayList(); + for (String attrName : List.of("class", "file", "id", "lang", "region")) { + // special case: valueless region attribute + TestCase t = new TestCase(""" + {@snippet %s: + First line + Second line + } + """.formatted(attrName), + """ + : error: missing value for attribute "%s" + {@snippet %s: + ^""".formatted(attrName, attrName)); + testCases.add(t); + } + + List inputs = testCases.stream().map(s -> s.input).toList(); + StringBuilder methods = new StringBuilder(); + forEachNumbered(inputs, (i, n) -> { + methods.append( + """ + + /** + %s*/ + public void case%s() {} + """.formatted(i, n)); + }); + + String classString = + """ + public class A { + %s + } + """.formatted(methods.toString()); + + Path src = Files.createDirectories(base.resolve("src")); + tb.writeJavaFiles(src, classString); + + javadoc("-d", base.resolve("out").toString(), + "-sourcepath", src.toString(), + src.resolve("A.java").toString()); + checkExit(Exit.ERROR); + // use the facility from JDK-8273154 when it becomes available + checkOutput(Output.OUT, true, testCases.stream().map(TestCase::expectedError).toArray(String[]::new)); + checkNoCrashes(); + } + + @Test + public void testNegativeTag_BlankRegion(Path base) throws Exception { + // If a blank region were allowed, it could not be used without quotes + record TestCase(String input, String expectedError) { } + + var testCases = new ArrayList(); + for (String quote : List.of("", "'", "\"")) + for (String value : List.of("", " ")) { + var t = new TestCase(""" + {@snippet region=%s%s%s: + First line + Second line + } + """.formatted(quote, value, quote), + """ + : error: illegal value for attribute "region": "%s" + {@snippet region=%s%s%s: + ^ + """.formatted( + quote.isEmpty() ? "" : value, // unquoted whitespace translates to empty string + quote, value, quote)); + testCases.add(t); + } + + List inputs = testCases.stream().map(s -> s.input).toList(); + StringBuilder methods = new StringBuilder(); + forEachNumbered(inputs, (i, n) -> { + methods.append( + """ + + /** + %s*/ + public void case%s() {} + """.formatted(i, n)); + }); + + String classString = + """ + public class A { + %s + } + """.formatted(methods.toString()); + + Path src = Files.createDirectories(base.resolve("src")); + tb.writeJavaFiles(src, classString); + + javadoc("-d", base.resolve("out").toString(), + "-sourcepath", src.toString(), + src.resolve("A.java").toString()); + checkExit(Exit.ERROR); + // use the facility from JDK-8273154 when it becomes available + checkOutput(Output.OUT, true, testCases.stream().map(TestCase::expectedError).toArray(String[]::new)); + checkNoCrashes(); + } + + @Test + public void testNegativeHybridTagMarkup_RegionNotFound(Path base) throws Exception { Path srcDir = base.resolve("src"); Path outDir = base.resolve("out"); var fileName = "text.txt"; @@ -1981,7 +2011,7 @@ public class TestSnippetTag extends JavadocTester { } @Test - public void testRedundantMismatch(Path base) throws Exception { + public void testNegativeHybridTag_Mismatch(Path base) throws Exception { Path srcDir = base.resolve("src"); Path outDir = base.resolve("out"); var fileName = "text.txt"; @@ -2006,11 +2036,22 @@ public class TestSnippetTag extends JavadocTester { checkOutput(Output.OUT, true, """ A.java:4: error: contents mismatch"""); + checkOutput("pkg/A.html", true, """ +
          + invalid @snippet +
          contents mismatch:
          +                        ----------------- inline -------------------
          +                        Hello, Snippet!
          +                        ----------------- external -----------------
          +                        Hello, Snippet!...more
          +                        
          +
          + """); checkNoCrashes(); } @Test - public void testRedundantRegionRegionMismatch(Path base) throws Exception { + public void testNegativeHybridTagMarkup_RegionRegionMismatch(Path base) throws Exception { Path srcDir = base.resolve("src"); Path outDir = base.resolve("out"); var fileName = "text.txt"; @@ -2046,11 +2087,24 @@ public class TestSnippetTag extends JavadocTester { checkOutput(Output.OUT, true, """ A.java:4: error: contents mismatch"""); + checkOutput("pkg/A.html", true, """ +
          + invalid @snippet +
          contents mismatch:
          +                        ----------------- inline -------------------
          +                        Hello, Snippet! ...more
          +
          +                        ----------------- external -----------------
          +                        Hello, Snippet!
          +
          +                        
          +
          + """); checkNoCrashes(); } @Test - public void testRedundantRegion1Mismatch(Path base) throws Exception { + public void testNegativeHybridTagMarkup_Region1Mismatch(Path base) throws Exception { Path srcDir = base.resolve("src"); Path outDir = base.resolve("out"); var fileName = "text.txt"; @@ -2084,7 +2138,7 @@ public class TestSnippetTag extends JavadocTester { } @Test - public void testRedundantRegion2Mismatch(Path base) throws Exception { + public void testNegativeHybridTagMarkup_Region2Mismatch(Path base) throws Exception { Path srcDir = base.resolve("src"); Path outDir = base.resolve("out"); var fileName = "text.txt"; @@ -2121,7 +2175,7 @@ public class TestSnippetTag extends JavadocTester { } @Test - public void testRedundant(Path base) throws Exception { + public void testPositiveHybridTagMarkup(Path base) throws Exception { record TestCase(Snippet snippet, String expectedOutput) { } final var testCases = List.of( new TestCase(newSnippetBuilder() @@ -2248,16 +2302,12 @@ public class TestSnippetTag extends JavadocTester { """ case%s()
          -
          -
          %s
          -
          """.formatted(index, t.expectedOutput())); + %s""".formatted(index, getSnippetHtmlRepresentation("pkg/A.html", t.expectedOutput()))); }); } @Test - public void testInvalidRegexDiagnostics(Path base) throws Exception { + public void testNegativeInlineTagMarkup_InvalidRegexDiagnostics(Path base) throws Exception { record TestCase(String input, String expectedError) { } @@ -2273,41 +2323,41 @@ public class TestSnippetTag extends JavadocTester { final var testCases = List.of( new TestCase(""" -{@snippet : -hello there // @highlight regex ="\t**" -}""", + {@snippet : + hello there // @highlight regex ="\t**" + }""", """ -error: snippet markup: invalid regex -hello there // @highlight regex ="\t**" - \t ^ -"""), + error: snippet markup: invalid regex + hello there // @highlight regex ="\t**" + \t ^ + """), new TestCase(""" -{@snippet : -hello there // @highlight regex ="\\t**" -}""", + {@snippet : + hello there // @highlight regex ="\\t**" + }""", """ -error: snippet markup: invalid regex -hello there // @highlight regex ="\\t**" - ^ -"""), + error: snippet markup: invalid regex + hello there // @highlight regex ="\\t**" + ^ + """), new TestCase(""" -{@snippet : -hello there // @highlight regex="\\.\\*\\+\\E" -}""", + {@snippet : + hello there // @highlight regex="\\.\\*\\+\\E" + }""", """ -error: snippet markup: invalid regex -hello there // @highlight regex="\\.\\*\\+\\E" - \s\s\s\s ^ -"""), // use \s to counteract shift introduced by \\ so as to visually align ^ right below E + error: snippet markup: invalid regex + hello there // @highlight regex="\\.\\*\\+\\E" + \s\s\s\s ^ + """), // use \s to counteract shift introduced by \\ so as to visually align ^ right below E new TestCase(""" -{@snippet : -hello there // @highlight type="italics" regex =" [" -}""", + {@snippet : + hello there // @highlight type="italics" regex =" [" + }""", """ -error: snippet markup: invalid regex -hello there // @highlight type="italics" regex =" [" - ^ -""") + error: snippet markup: invalid regex + hello there // @highlight type="italics" regex =" [" + ^ + """) ); List inputs = testCases.stream().map(s -> s.input).toList(); @@ -2337,127 +2387,134 @@ hello there // @highlight type="italics" regex =" [" src.resolve("A.java").toString()); checkExit(Exit.ERROR); checkOrder(Output.OUT, testCases.stream().map(TestCase::expectedError).toArray(String[]::new)); + checkOutput("A.html", true, """ +
          + invalid @snippet +
          invalid regex
          +
          + """); checkNoCrashes(); } @Test - public void testErrorMessages(Path base) throws Exception { + public void testNegativeInlineTagMarkup_ErrorMessages(Path base) throws Exception { record TestCase(String input, String expectedError) { } final var testCases = List.of( new TestCase(""" -{@snippet : - hello // @link -}""", + {@snippet : + hello // @link + }""", """ -error: snippet markup: missing attribute "target" - hello // @link - ^ + error: snippet markup: missing attribute "target" + hello // @link + ^ """), new TestCase(""" -{@snippet : - hello // @start -}""", + {@snippet : + hello // @start + }""", """ -error: snippet markup: missing attribute "region" - hello // @start - ^ + error: snippet markup: missing attribute "region" + hello // @start + ^ """), new TestCase(""" -{@snippet : - hello // @replace -}""", + {@snippet : + hello // @replace + }""", """ -error: snippet markup: missing attribute "replacement" - hello // @replace - ^ + error: snippet markup: missing attribute "replacement" + hello // @replace + ^ """), /* ---------------------- */ new TestCase(""" -{@snippet : - hello // @highlight regex=\\w+ substring=hello -}""", + {@snippet : + hello // @highlight regex=\\w+ substring=hello + }""", """ -error: snippet markup: attributes "substring" and "regex" used simultaneously - hello // @highlight regex=\\w+ substring=hello - ^ + error: snippet markup: attributes "substring" and "regex" used simultaneously + hello // @highlight regex=\\w+ substring=hello + ^ """), new TestCase(""" -{@snippet : - hello // @start region="x" name="here" -}""", + {@snippet : + hello // @start region="x" name="here" + }""", """ -error: snippet markup: unexpected attribute - hello // @start region="x" name="here" - ^ + error: snippet markup: unexpected attribute + hello // @start region="x" name="here" + ^ """), new TestCase(""" -{@snippet : - hello // @start region="" -}""", + {@snippet : + hello // @start region="" + }""", """ -error: snippet markup: invalid attribute value - hello // @start region="" - ^ + error: snippet markup: invalid attribute value + hello // @start region="" + ^ """), new TestCase(""" -{@snippet : - hello // @link target="Object#equals()" type=fluffy -}""", + {@snippet : + hello // @link target="Object#equals()" type=fluffy + }""", """ -error: snippet markup: invalid attribute value - hello // @link target="Object#equals()" type=fluffy - ^ + error: snippet markup: invalid attribute value + hello // @link target="Object#equals()" type=fluffy + ^ """), /* ---------------------- */ new TestCase(""" -{@snippet : - hello // @highlight substring=" -}""", + {@snippet : + hello + there // @highlight substring=" + }""", """ -error: snippet markup: unterminated attribute value - hello // @highlight substring=" - ^ + error: snippet markup: unterminated attribute value + there // @highlight substring=" + ^ """), new TestCase(""" -{@snippet : - hello // @start region="this" - world // @start region="this" - ! // @end -}""", + {@snippet : + hello // @start region="this" + world // @start region="this" + ! // @end + }""", """ -error: snippet markup: duplicated region - world // @start region="this" - ^ + error: snippet markup: duplicated region + world // @start region="this" + ^ """), new TestCase(""" -{@snippet : - hello // @end -}""", + {@snippet : + hello // @end + }""", """ -error: snippet markup: no region to end - hello // @end - ^ + error: snippet markup: no region to end + hello // @end + ^ """), new TestCase(""" -{@snippet : - hello // @start region=this -}""", + {@snippet : + hello // @start region=this + }""", """ -error: snippet markup: unpaired region - hello // @start region=this - ^ + error: snippet markup: unpaired region + hello // @start region=this + ^ """), new TestCase(""" -{@snippet : - hello // @highlight substring="hello" : -}""", + {@snippet : + hello // @highlight substring="hello" : + }""", """ -error: snippet markup: tag refers to non-existent lines - hello // @highlight substring="hello" : - ^ - """) + error: snippet markup: tag refers to non-existent lines + hello // @highlight substring="hello" : + ^ + """) ); List inputs = testCases.stream().map(s -> s.input).toList(); StringBuilder methods = new StringBuilder(); @@ -2487,6 +2544,12 @@ error: snippet markup: tag refers to non-existent lines checkExit(Exit.ERROR); // use the facility from JDK-8273154 when it becomes available checkOutput(Output.OUT, true, testCases.stream().map(TestCase::expectedError).toArray(String[]::new)); + checkOutput("A.html", true, """ +
          + invalid @snippet +
          missing attribute "target"
          +
          + """); checkNoCrashes(); } } diff --git a/test/langtools/jdk/javadoc/doclet/testTagInheritence/TestTagInheritence.java b/test/langtools/jdk/javadoc/doclet/testTagInheritence/TestTagInheritance.java similarity index 86% rename from test/langtools/jdk/javadoc/doclet/testTagInheritence/TestTagInheritence.java rename to test/langtools/jdk/javadoc/doclet/testTagInheritence/TestTagInheritance.java index 59189ff948e3a57784e4213712a19761a6fc8d7d..fece105d6ba2f1f2e735c4f45b3a7f71c1690690 100644 --- a/test/langtools/jdk/javadoc/doclet/testTagInheritence/TestTagInheritence.java +++ b/test/langtools/jdk/javadoc/doclet/testTagInheritence/TestTagInheritance.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 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 @@ -28,16 +28,15 @@ * @library ../../lib * @modules jdk.javadoc/jdk.javadoc.internal.tool * @build javadoc.tester.* - * @run main TestTagInheritence + * @run main TestTagInheritance */ -// TODO: Inheritence should be Inheritance! fix separately as noreg-trivial import javadoc.tester.JavadocTester; -public class TestTagInheritence extends JavadocTester { +public class TestTagInheritance extends JavadocTester { public static void main(String... args) throws Exception { - TestTagInheritence tester = new TestTagInheritence(); + TestTagInheritance tester = new TestTagInheritance(); tester.runTests(); } @@ -56,7 +55,7 @@ public class TestTagInheritence extends JavadocTester { //Test valid usage of inheritDoc tag. for (int i = 1; i < 40; i++) { - checkOutput("pkg/TestTagInheritence.html", true, + checkOutput("pkg/TestTagInheritance.html", true, "Test " + i + " passes"); } diff --git a/test/langtools/jdk/javadoc/doclet/testTagInheritence/pkg/TestTagInheritence.java b/test/langtools/jdk/javadoc/doclet/testTagInheritence/pkg/TestTagInheritance.java similarity index 91% rename from test/langtools/jdk/javadoc/doclet/testTagInheritence/pkg/TestTagInheritence.java rename to test/langtools/jdk/javadoc/doclet/testTagInheritence/pkg/TestTagInheritance.java index c2accc04b8116e3ed9796c40efeefbf37da3105e..60fecf4d09898f6e4878a0f1baaeeb2b887969f6 100644 --- a/test/langtools/jdk/javadoc/doclet/testTagInheritence/pkg/TestTagInheritence.java +++ b/test/langtools/jdk/javadoc/doclet/testTagInheritence/pkg/TestTagInheritance.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2003, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -26,9 +26,9 @@ package pkg; import java.lang.*; import java.io.*; -public class TestTagInheritence extends TestAbstractClass implements TestInterface{ +public class TestTagInheritance extends TestAbstractClass implements TestInterface{ - //This method below tests tag inheritence from a class. + //This method below tests tag inheritance from a class. public String testAbstractClass_method1(int p1, int p2) throws java.io.IOException, @@ -57,7 +57,7 @@ java.lang.NullPointerException } /** - * This method tests @inheritDoc with an inteface. Here is the inherited comment:
          + * This method tests @inheritDoc with an interface. Here is the inherited comment:
          * {@inheritDoc} * @param p1 {@inheritDoc} * @param p2 {@inheritDoc} diff --git a/test/langtools/jdk/javadoc/doclet/testThrowsInheritence/C.java b/test/langtools/jdk/javadoc/doclet/testThrowsInheritance/C.java similarity index 100% rename from test/langtools/jdk/javadoc/doclet/testThrowsInheritence/C.java rename to test/langtools/jdk/javadoc/doclet/testThrowsInheritance/C.java diff --git a/test/langtools/jdk/javadoc/doclet/testThrowsInheritence/Foo.java b/test/langtools/jdk/javadoc/doclet/testThrowsInheritance/Foo.java similarity index 100% rename from test/langtools/jdk/javadoc/doclet/testThrowsInheritence/Foo.java rename to test/langtools/jdk/javadoc/doclet/testThrowsInheritance/Foo.java diff --git a/test/langtools/jdk/javadoc/doclet/testThrowsInheritence/I.java b/test/langtools/jdk/javadoc/doclet/testThrowsInheritance/I.java similarity index 100% rename from test/langtools/jdk/javadoc/doclet/testThrowsInheritence/I.java rename to test/langtools/jdk/javadoc/doclet/testThrowsInheritance/I.java diff --git a/test/langtools/jdk/javadoc/doclet/testThrowsInheritence/Iface.java b/test/langtools/jdk/javadoc/doclet/testThrowsInheritance/Iface.java similarity index 100% rename from test/langtools/jdk/javadoc/doclet/testThrowsInheritence/Iface.java rename to test/langtools/jdk/javadoc/doclet/testThrowsInheritance/Iface.java diff --git a/test/langtools/jdk/javadoc/doclet/testThrowsInheritence/TestThrowsTagInheritence.java b/test/langtools/jdk/javadoc/doclet/testThrowsInheritance/TestThrowsTagInheritance.java similarity index 90% rename from test/langtools/jdk/javadoc/doclet/testThrowsInheritence/TestThrowsTagInheritence.java rename to test/langtools/jdk/javadoc/doclet/testThrowsInheritance/TestThrowsTagInheritance.java index 6409910e85f3b7deda4c3ca29c06b452350fc705..b02ddf1c467ebcb828875250233c7756cf011cc5 100644 --- a/test/langtools/jdk/javadoc/doclet/testThrowsInheritence/TestThrowsTagInheritence.java +++ b/test/langtools/jdk/javadoc/doclet/testThrowsInheritance/TestThrowsTagInheritance.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 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 @@ -30,16 +30,15 @@ * @library ../../lib * @modules jdk.javadoc/jdk.javadoc.internal.tool * @build javadoc.tester.* - * @run main TestThrowsTagInheritence + * @run main TestThrowsTagInheritance */ -// TODO: should be TestThrowsInheritance! import javadoc.tester.JavadocTester; -public class TestThrowsTagInheritence extends JavadocTester { +public class TestThrowsTagInheritance extends JavadocTester { public static void main(String... args) throws Exception { - TestThrowsTagInheritence tester = new TestThrowsTagInheritence(); + TestThrowsTagInheritance tester = new TestThrowsTagInheritance(); tester.runTests(); } diff --git a/test/langtools/jdk/javadoc/doclet/testThrowsInheritence/pkg/Abstract.java b/test/langtools/jdk/javadoc/doclet/testThrowsInheritance/pkg/Abstract.java similarity index 100% rename from test/langtools/jdk/javadoc/doclet/testThrowsInheritence/pkg/Abstract.java rename to test/langtools/jdk/javadoc/doclet/testThrowsInheritance/pkg/Abstract.java diff --git a/test/langtools/jdk/javadoc/doclet/testThrowsInheritence/pkg/Extender.java b/test/langtools/jdk/javadoc/doclet/testThrowsInheritance/pkg/Extender.java similarity index 100% rename from test/langtools/jdk/javadoc/doclet/testThrowsInheritence/pkg/Extender.java rename to test/langtools/jdk/javadoc/doclet/testThrowsInheritance/pkg/Extender.java diff --git a/test/langtools/jdk/javadoc/doclet/testXOption/TestXOption.java b/test/langtools/jdk/javadoc/doclet/testXOption/TestXOption.java index 7d00116fccc674b84d81d718e6740250906e8f60..3c65066419c1835945ab3ada7eb3cb7f7c440f75 100644 --- a/test/langtools/jdk/javadoc/doclet/testXOption/TestXOption.java +++ b/test/langtools/jdk/javadoc/doclet/testXOption/TestXOption.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -98,6 +98,7 @@ public class TestXOption extends JavadocTester { "-Xmaxwarns ", "-Xdocrootparent ", "-Xdoclint ", - "-Xdoclint:"); + "-Xdoclint:", + "--date "); } } diff --git a/test/langtools/jdk/javadoc/lib/javadoc/tester/JavadocTester.java b/test/langtools/jdk/javadoc/lib/javadoc/tester/JavadocTester.java index ff84f37c56bbb9db6d450e8d89b18248b907c3e3..6c6415cf6de349809019912bedfa062623e333b4 100644 --- a/test/langtools/jdk/javadoc/lib/javadoc/tester/JavadocTester.java +++ b/test/langtools/jdk/javadoc/lib/javadoc/tester/JavadocTester.java @@ -58,6 +58,8 @@ import java.util.function.Function; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; +import java.util.stream.Stream; +import javax.tools.StandardJavaFileManager; /** @@ -245,6 +247,7 @@ public abstract class JavadocTester { private boolean automaticCheckLinks = true; private boolean automaticCheckUniqueOUT = true; private boolean useStandardStreams = false; + private StandardJavaFileManager fileManager = null; /** The current subtest number. Incremented when checking(...) is called. */ private int numTestsRun = 0; @@ -264,39 +267,129 @@ public abstract class JavadocTester { /** * Run all methods annotated with @Test, followed by printSummary. - * Typically called on a tester object in main() + * The methods are invoked in the order found using getDeclaredMethods. + * The arguments for the invocation are provided {@link #getTestArgs(Method)}. + * + * Typically called on a tester object in main(). * + * @throws IllegalArgumentException if any test method does not have a recognized signature * @throws Exception if any errors occurred */ public void runTests() throws Exception { - runTests(m -> new Object[0]); + runTests(this::getTestArgs); } /** * Runs all methods annotated with @Test, followed by printSummary. + * The methods are invoked in the order found using getDeclaredMethods. + * The arguments for the invocation are provided by a given function. + * * Typically called on a tester object in main() * * @param f a function which will be used to provide arguments to each * invoked method - * @throws Exception if any errors occurred + * @throws Exception if any errors occurred while executing a test method */ public void runTests(Function f) throws Exception { - for (Method m: getClass().getDeclaredMethods()) { + for (Method m : getClass().getDeclaredMethods()) { Annotation a = m.getAnnotation(Test.class); if (a != null) { - try { - out.println("Running test " + m.getName()); - m.invoke(this, f.apply(m)); - } catch (InvocationTargetException e) { - Throwable cause = e.getCause(); - throw (cause instanceof Exception) ? ((Exception) cause) : e; - } + runTest(m, f); out.println(); } } printSummary(); } + /** + * Run the specified methods annotated with @Test, or all methods annotated + * with @Test if none are specified, followed by printSummary. + * The methods are invoked in the order given in the methodNames argument, + * or the order returned by getDeclaredMethods if no names are provided. + * The arguments for the invocation are provided {@link #getTestArgs(Method)}. + * + * Typically called on a tester object in main(String[] args), perhaps using + * args as the list of method names. + * + * @throws IllegalStateException if any methods annotated with @Test are overloaded + * @throws IllegalArgumentException if any of the method names does not name a suitable method + * @throws NullPointerException if {@code methodNames} is {@code null}, or if any of the names are {@code null} + * @throws Exception if any errors occurred while executing a test method + */ + public void runTests(String... methodNames) throws Exception { + runTests(this::getTestArgs, methodNames); + } + + /** + * Run the specified methods annotated with @Test, or all methods annotated + * with @Test if non are specified, followed by printSummary. + * The methods are invoked in the order given in the methodNames argument, + * or the order returned by getDeclaredMethods if no names are provided. + * The arguments for the invocation are provided {@link #getTestArgs(Method)}. + * + * Typically called on a tester object in main(String[] args), perhaps using + * args as the list of method names. + * + * @throws IllegalStateException if any methods annotated with @Test are overloaded + * @throws IllegalArgumentException if any of the method names does not name a suitable method + * @throws NullPointerException if {@code methodNames} is {@code null}, or if any of the names are {@code null} + * @throws Exception if any errors occurred while executing a test method + */ + public void runTests(Function f, String... methodNames) throws Exception { + if (methodNames.length == 0) { + runTests(f); + } else { + Map testMethods = Stream.of(getClass().getDeclaredMethods()) + .filter(this::isTestMethod) + .collect(Collectors.toMap(Method::getName, Function.identity(), + (o, n) -> { + throw new IllegalStateException("test method " + o.getName() + " is overloaded"); + })); + + List list = new ArrayList<>(); + for (String mn : methodNames) { + Method m = testMethods.get(mn); + if (m == null) { + throw new IllegalArgumentException("test method " + mn + " not found"); + } + list.add(m); + } + + for (Method m : list) { + runTest(m, f); + } + } + } + + protected boolean isTestMethod(Method m) { + return m.getAnnotation(Test.class) != null; + } + + protected Object[] getTestArgs(Method m) throws IllegalArgumentException { + Class[] paramTypes = m.getParameterTypes(); + if (paramTypes.length == 0) { + return new Object[] {}; + } else if (paramTypes.length == 1 && paramTypes[0] == Path.class) { + return new Object[] { Path.of(m.getName())}; + } else { + throw new IllegalArgumentException("unknown signature for method " + + m + Stream.of(paramTypes) + .map(Class::toString) + .collect(Collectors.joining(", ", "(", ")"))) ; + } + } + + protected void runTest(Method m, Function f) throws Exception { + try { + out.println("Running test " + m.getName()); + m.invoke(this, f.apply(m)); + } catch (InvocationTargetException e) { + Throwable cause = e.getCause(); + throw (cause instanceof Exception) ? ((Exception) cause) : e; + } + + } + /** * Runs javadoc. * The output directory used by this call and the final exit code @@ -371,9 +464,17 @@ public abstract class JavadocTester { StreamOutput sysErr = new StreamOutput(System.err, System::setErr); try { - exitCode = useStandardStreams - ? jdk.javadoc.internal.tool.Main.execute(args) // use sysOut, sysErr - : jdk.javadoc.internal.tool.Main.execute(args, outOut.pw); // default + jdk.javadoc.internal.tool.Main main = new jdk.javadoc.internal.tool.Main(); + if (useStandardStreams) { + // use sysOut, sysErr + } else { + // default: use single explicit stream + main.setStreams(outOut.pw, outOut.pw); + } + if (fileManager != null) { + main.setFileManager(fileManager); + } + exitCode = main.run(args).exitCode; } finally { outputMap.put(Output.STDOUT, sysOut.close()); outputMap.put(Output.STDERR, sysErr.close()); @@ -442,6 +543,15 @@ public abstract class JavadocTester { useStandardStreams = b; } + /** + * Sets the file manager to use for subsequent invocations of javadoc. + * If {@code null}, a default file manager will be created and used + * for each invocation. + */ + public void setFileManager(StandardJavaFileManager fm) { + fileManager = fm; + } + /** * The exit codes returned by the javadoc tool. * @see jdk.javadoc.internal.tool.Main.Result diff --git a/test/langtools/jdk/javadoc/lib/javadoc/tester/TestJavaFileManagerBuilder.java b/test/langtools/jdk/javadoc/lib/javadoc/tester/TestJavaFileManagerBuilder.java new file mode 100644 index 0000000000000000000000000000000000000000..69024a48cba45ce988e886bbe0f09ac166541f32 --- /dev/null +++ b/test/langtools/jdk/javadoc/lib/javadoc/tester/TestJavaFileManagerBuilder.java @@ -0,0 +1,306 @@ +/* + * 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. + */ + +package javadoc.tester; + +import javax.tools.FileObject; +import javax.tools.JavaFileManager; +import javax.tools.JavaFileObject; +import javax.tools.StandardJavaFileManager; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.lang.reflect.UndeclaredThrowableException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.WeakHashMap; +import java.util.function.BiFunction; +import java.util.function.Predicate; + +/** + * A builder to create "test file managers" that can return "test file objects". + * All such objects can throw user-provided exceptions when specified methods + * are called. This is done by registering "handlers" to be associated with individual + * methods. + * + * The file objects that are returned as "test file objects" are filtered by a predicate + * on the file object. + * + * Note that "test file objects" passed as arguments to methods on the "test file manager" + * that created them are unwrapped, and replaced by the original file object. + * This ensures that the underlying file manager sees the underlying file objects, + * for cases when the identity of the file objects is important. + * However, it does mean that methods on file objects called internally by a + * file manager will not throw any user-provided exceptions. + * + * For now, the handlers for a file object are simply grouped by predicate and then by + * method, and the group of methods used for a "test file object" is determined by the + * first predicate that matches. + * An alternative, more expensive, implementation would be to group the handlers + * by method and predicate and then dynamically build the set of methods to be used for + * a file object by filtering the methods by their applicable predicate. + */ +public class TestJavaFileManagerBuilder { + private final StandardJavaFileManager fm; + private Map> fileManagerHandlers; + + private record FileObjectHandlers(Predicate filter, + Map> handlers) { } + private final List fileObjectHandlers; + + public TestJavaFileManagerBuilder(StandardJavaFileManager fm) { + this.fm = fm; + fileManagerHandlers = Collections.emptyMap(); + fileObjectHandlers = new ArrayList<>(); + } + + /** + * Provides functions to be called when given file manager methods are called. + * The function should either return an exception to be thrown, or {@code null} + * to indicate that no exception should be thrown. + * + *

          It is an error for any function to return a checked exception that is not + * declared by the method. This error will result in {@link UndeclaredThrowableException} + * being thrown when the method is called. + * + * @param handlers a map giving the function to be called before a file manager method is invoked + * + * @return this object + * + * @throws IllegalArgumentException if any key in the map of handlers is a method that is not + * declared in {@code JavaFileManager} + */ + public TestJavaFileManagerBuilder handle(Map> handlers) { + handlers.forEach((m, h) -> { + if (!JavaFileManager.class.isAssignableFrom(m.getDeclaringClass())) { + throw new IllegalArgumentException(("not a method on JavaFileManager: " + m)); + } + }); + + fileManagerHandlers = handlers; + return this; + } + + /** + * Provides functions to be called when given file object methods are called, + * for file objects that match a given predicate. + * The function should either return an exception to be thrown, or {@code null} + * to indicate that no exception should be thrown. + * + *

          It is an error for the function to return a checked exception that is not + * declared by the method. This error will result in {@link UndeclaredThrowableException} + * being thrown when the method is called. + * + *

          When subsequently finding the handlers to be used for a particular file object, the various + * predicates passed to this method will be tested in the order that they were registered. + * The handlers associated with the first matching predicate will be used. + * + * @apiNote Examples of predicates include: + *

            + *
          • using {@code .equals} or {@link JavaFileObject#isNameCompatible(String, JavaFileObject.Kind)} + * to match a specific file object, + *
          • using string or regular expression operations on the name or URI of the file object, + *
          • using {@code Path} operations on the file object's {@link StandardJavaFileManager#asPath(FileObject) path}. + *
          + * + * @param filter the predicate used to identify file objects for which the handlers are applicable + * @param handlers a map giving the function to be called before a file object method is invoked + * + * @return this object + * + * @throws IllegalArgumentException if any key in the map is a method that is not declared in a class + * that is assignable to {@code FileObject} + */ + public TestJavaFileManagerBuilder handle(Predicate filter, + Map> handlers) { + handlers.forEach((m, h) -> { + if (!FileObject.class.isAssignableFrom(m.getDeclaringClass())) { + throw new IllegalArgumentException(("not a method on FileObject: " + m)); + } + }); + + fileObjectHandlers.add(new FileObjectHandlers(filter, handlers)); + return this; + } + + /** + * {@return a file manager configured with the given handlers} + */ + public StandardJavaFileManager build() { + return (StandardJavaFileManager) Proxy.newProxyInstance(getClass().getClassLoader(), + new Class[] { StandardJavaFileManager.class }, + new JavaFileManager_InvocationHandler()); + } + + /** + * An invocation handler for "test file managers", which provides "test file objects" + * that may be configured to invoke functions to handle selected methods. + */ + private class JavaFileManager_InvocationHandler implements InvocationHandler { + // a cache of "real file object" -> "proxy file object". + Map cache = new WeakHashMap<>(); + + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + Object result = handleMethod(fm, method, unwrap(args)); + + if (result instanceof Iterable iterable) { + // All methods on StandardJavaFileManager that return Iterable for some T + // are such that T is one of ? extends [Java]FileObject, ? extends File, ? extends Path. + // If the result is empty, return it unchanged; otherwise check the first + // element to determine the type of the iterable, and if it is an iterable of + // file objects, post-process the result to use proxy file objects where appropriate. + // Note 1: this assumes that no methods return a mixture of FileObject and JavaFileObject. + // Note 2: all file objects returned by the standard file manager are instances of javaFileObject + Iterator iter = iterable.iterator(); + if (iter.hasNext() && iter.next() instanceof JavaFileObject) { + List list = new ArrayList<>(); + for (JavaFileObject jfo : (Iterable) iterable) { + list.add(wrap(jfo)); + } + return list; + } else { + return result; + } + } else if (result instanceof JavaFileObject jfo) { + return wrap(jfo); + } else { + return result; + } + } + + /** + * Returns a proxy file object that either calls handler functions for specific methods + * or delegates to an underlying file object. + * + * @param jfo the underlying file object + * + * @return the proxy file object + */ + private JavaFileObject wrap(JavaFileObject jfo) { + return fileObjectHandlers.stream() + .filter(e -> e.filter().test(jfo)) + .findFirst() + .map(e -> cache.computeIfAbsent(jfo, jfo_ -> createProxyFileObject(jfo_, e.handlers()))) + .orElse(jfo); + } + + /** + * Creates a proxy file object that either calls handler functions for specific methods + * or delegates to an underlying file object. + * + * @param jfo the underlying file object + * @param handlers the handlers + * + * @return the proxy file object + */ + private JavaFileObject createProxyFileObject(JavaFileObject jfo, + Map> handlers) { + return (JavaFileObject) Proxy.newProxyInstance(getClass().getClassLoader(), + new Class[] { JavaFileObject.class }, + new JavaFileObject_InvocationHandler(jfo, handlers)); + } + + /** + * {@return an array of objects with any proxy file objects replaced by their underlying + * delegate value} + * + * If there are no proxy objects in the array, the original array is returned. + * + * @param args the array of values + */ + private Object[] unwrap(Object[] args) { + if (!containsProxyFileObject(args)) { + return args; + } + + Object[] uArgs = new Object[args.length]; + for (int i = 0; i < args.length; i++) { + Object arg = args[i]; + uArgs[i] = (Proxy.isProxyClass(arg.getClass()) + && Proxy.getInvocationHandler(arg) instanceof JavaFileObject_InvocationHandler ih) + ? ih.jfo + : arg; + } + return uArgs; + } + + /** + * {@return {@code true} if an array of objects contains any proxy file objects, + * and {@code false} otherwise} + * + * @param args the array of objects + */ + private boolean containsProxyFileObject(Object[] args) { + for (Object arg : args) { + if (arg != null && Proxy.isProxyClass(arg.getClass()) + && Proxy.getInvocationHandler(arg) instanceof JavaFileObject_InvocationHandler) { + return true; + } + } + return false; + } + + private Object handleMethod(JavaFileManager fm, Method method, Object[] args) throws Throwable { + var handler = fileManagerHandlers.get(method); + if (handler != null) { + Throwable t = handler.apply(fm, args); + if (t != null) { + throw t; + } + } + + return method.invoke(fm, args); + } + } + + /** + * An invocation handler for "test file objects" which can be configured to call functions + * to handle the calls for individual methods. + * It is expected that a common use case is to throw an exception in circumstances that + * would otherwise be hard to create. + */ + private record JavaFileObject_InvocationHandler(JavaFileObject jfo, + Map> handlers) + implements InvocationHandler { + + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + return handleMethod(jfo, method, args); + } + + private Object handleMethod(JavaFileObject jfo, Method method, Object[] args) throws Throwable { + var handler = handlers.get(method); + if (handler != null) { + Throwable t = handler.apply(jfo, args); + if (t != null) { + throw t; + } + } + return method.invoke(jfo, args); + } + } +} diff --git a/test/langtools/jdk/javadoc/testJavadocTester/TestRunTests.java b/test/langtools/jdk/javadoc/testJavadocTester/TestRunTests.java new file mode 100644 index 0000000000000000000000000000000000000000..ae5c97fd5a6acee11baa5236edef646ad44063e3 --- /dev/null +++ b/test/langtools/jdk/javadoc/testJavadocTester/TestRunTests.java @@ -0,0 +1,272 @@ +/* + * 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. + */ + + +/* + * @test + * @bug 8272853 + * @summary improve `JavadocTester.runTests` + * @library /tools/lib/ ../lib + * @modules jdk.javadoc/jdk.javadoc.internal.tool + * @build toolbox.ToolBox javadoc.tester.* + * @run main TestRunTests + */ + +import javadoc.tester.JavadocTester; + +import java.io.PrintStream; +import java.lang.annotation.Annotation; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.Set; +import java.util.function.Function; + +public class TestRunTests { + @Retention(RetentionPolicy.RUNTIME) + public @interface RunTest { + } + + public static void main(String... args) throws Exception { + TestRunTests t = new TestRunTests(); + t.run(); + } + + PrintStream out = System.out; + + void run() throws Exception { + for (Method m : getClass().getDeclaredMethods()) { + Annotation a = m.getAnnotation(RunTest.class); + if (a != null) { + try { + out.println("Running " + m); + m.invoke(this); + out.println(); + } catch (InvocationTargetException e) { + error("Invocation Target Exception while running " + m + ": " + e.getCause()); + } catch (Exception e) { + error("Exception while running " + m + ": " + e); + } + } + } + out.flush(); + if (errors > 0) { + out.println(errors + " errors occurred"); + throw new Exception(errors + " errors occurred"); + } + } + + int errors; + + @RunTest + public void testNoArgs() throws Exception { + MainGroup g = new MainGroup(); + g.runTests(); + checkEqualUnordered(g.log, Set.of("m1()", "m2(m2)", "m3()", "m4(m4)")); + } + + @RunTest + public void testMethodNames() throws Exception { + MainGroup g = new MainGroup(); + g.runTests("m1", "m4", "m2"); + checkEqualOrdered(g.log, List.of("m1()", "m4(m4)", "m2(m2)")); + } + + @RunTest + public void testFunction() throws Exception { + Function f = m -> + switch (m.getName()) { + case "m1", "m3" -> new Object[]{}; + case "m2", "m4" -> new Object[]{Path.of(m.getName().toUpperCase(Locale.ROOT))}; + default -> throw new IllegalArgumentException(m.toString()); + }; + MainGroup g = new MainGroup(); + g.runTests(f); + checkEqualUnordered(g.log, Set.of("m1()", "m2(M2)", "m3()", "m4(M4)")); + } + + @RunTest + public void testFunctionMethodNames() throws Exception { + Function f = m -> + switch (m.getName()) { + case "m1", "m3" -> new Object[]{}; + case "m2", "m4" -> new Object[]{Path.of(m.getName().toUpperCase(Locale.ROOT))}; + default -> throw new IllegalArgumentException(m.toString()); + }; + MainGroup g = new MainGroup(); + g.runTests(f, "m1", "m4", "m2"); + checkEqualOrdered(g.log, List.of("m1()", "m4(M4)", "m2(M2)")); + } + + @RunTest + public void testMethodNotFound() throws Exception { + MainGroup g = new MainGroup(); + try { + g.runTests("m1", "m2", "mx", "m3", "m4"); + } catch (IllegalArgumentException e) { + g.log.add(e.toString()); + } + // implicit in the following is that the error was detected before any test methods were executed + checkEqualOrdered(g.log, List.of("java.lang.IllegalArgumentException: test method mx not found")); + } + + @RunTest + public void testInvalidSignature() throws Exception { + InvalidSignatureGroup g = new InvalidSignatureGroup(); + try { + g.runTests(); + } catch (IllegalArgumentException e) { + g.log.add(e.toString()); + } + // since the exception comes from the nested use of `getTestArgs`, it will be thrown + // when the test method is being called, and so is not constrained to be thrown + // before any test method is called + checkContainsAll(g.log, List.of("java.lang.IllegalArgumentException: unknown signature for method " + + "public void TestRunTests$InvalidSignatureGroup.invalidSignature(java.lang.Object)(class java.lang.Object)")); + } + + @RunTest + public void testOverloadedMethod() throws Exception { + OverloadGroup g = new OverloadGroup(); + try { + g.runTests("m1"); + } catch (IllegalStateException e) { + g.log.add(e.toString()); + } + // implicit in the following is that the error was detected before any test methods were executed + checkEqualOrdered(g.log, List.of("java.lang.IllegalStateException: test method m1 is overloaded")); + } + + void checkContainsAll(List found, List expect) { + if (!found.containsAll(expect)) { + out.println("Found: " + found); + out.println("Expect: " + expect); + error("Expected results not found"); + } + } + + void checkEqualOrdered(List found, List expect) { + if (!found.equals(expect)) { + out.println("Found: " + found); + out.println("Expect: " + expect); + error("Expected results not found"); + } + } + + void checkEqualUnordered(List found, Set expect) { + if (!(found.containsAll(expect) && expect.containsAll(found))) { + out.println("Found: " + found); + out.println("Expect: " + expect); + error("Expected results not found"); + } + } + + void error(String message) { + out.println("Error: " + message); + errors++; + } + + /** + * A group of tests to be executed by different overloads of {@code runTests}. + */ + public static class MainGroup extends JavadocTester { + List log = new ArrayList<>(); + + @Test + public void m1() { + log.add("m1()"); + checking("m1"); + passed("OK"); + } + + @Test + public void m2(Path p) { + log.add("m2(" + p.getFileName() + ")"); + checking("m2"); + passed("OK"); + } + + @Test + public void m3() { + log.add("m3()"); + checking("m3"); + passed("OK"); + } + + @Test + public void m4(Path p) { + log.add("m4(" + p.getFileName() + ")"); + checking("m4"); + passed("OK"); + } + } + + /** + * A group of tests containing one with an invalid (unrecognized) signature. + * The invalid signature should cause an exception when trying to run that test. + */ + public static class InvalidSignatureGroup extends JavadocTester { + List log = new ArrayList<>(); + + @Test + public void m1() { + log.add("m1()"); + checking("m1"); + passed("OK"); + } + + @Test + public void invalidSignature(Object o) { + log.add("invalidSignature(" + o + ")"); + checking("invalidSignature"); + passed("OK"); + } + } + + /** + * A group of tests including an overloaded test method. + * The overload should cause an exception when trying to run that test by name. + */ + public static class OverloadGroup extends JavadocTester { + List log = new ArrayList<>(); + + @Test + public void m1() { + log.add("m1()"); + checking("m1"); + passed("OK"); + } + + @Test + public void m1(Path p) { + log.add("m1(" + p + ")"); + checking("m1"); + passed("OK"); + } + } +} diff --git a/test/langtools/jdk/javadoc/testTFMBuilder/TestTFMBuilder.java b/test/langtools/jdk/javadoc/testTFMBuilder/TestTFMBuilder.java new file mode 100644 index 0000000000000000000000000000000000000000..1e892df80bbb6264b7846082dc23db30a1317b0e --- /dev/null +++ b/test/langtools/jdk/javadoc/testTFMBuilder/TestTFMBuilder.java @@ -0,0 +1,242 @@ +/* + * 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. + */ + + +/* + * @test + * @bug 8276892 + * @summary Provide a way to emulate exceptional situations in FileManager when using JavadocTester + * @library /tools/lib/ ../lib + * @modules jdk.javadoc/jdk.javadoc.internal.tool + * @build toolbox.ToolBox javadoc.tester.* + * @run main TestTFMBuilder + */ + + +import javax.tools.DocumentationTool; +import javax.tools.JavaFileManager; +import javax.tools.JavaFileObject; +import javax.tools.StandardJavaFileManager; +import javax.tools.StandardLocation; +import javax.tools.ToolProvider; +import java.lang.reflect.Method; +import java.nio.file.Path; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +import javadoc.tester.JavadocTester; +import javadoc.tester.TestJavaFileManagerBuilder; +import toolbox.ToolBox; + +/** + * Tests the {@link TestJavaFileManagerBuilder} class. + * + */ +// The use of the contraction TFMBuilder is deliberate, to avoid using +// the confusing but otherwise logical name of TestTestJavaFileManagerBuilder +public class TestTFMBuilder extends JavadocTester { + public static class TestException extends RuntimeException { + TestException(JavaFileObject jfo) { + this(jfo.getName()); + } + + TestException(String msg) { + super(msg); + } + } + + public static void main(String... args) throws Exception { + TestTFMBuilder tester = new TestTFMBuilder(); + tester.setup().runTests(m -> new Object[] { Path.of(m.getName()) }); + } + + private Path srcDir = Path.of("src"); + private Class thisClass = TestTFMBuilder.class; + private String thisClassName = thisClass.getName(); + + TestTFMBuilder setup() throws Exception { + ToolBox tb = new ToolBox(); + tb.writeJavaFiles(srcDir, """ + package p; + /** Dummy class, to be read by javadoc. {@snippet file="C.properties" } */ + public class C { + private C() { } + }"""); + tb.writeFile(srcDir.resolve("p").resolve("snippet-files").resolve("C.properties"), """ + dummy content + """); + return this; + } + + StandardJavaFileManager getFileManager() { + DocumentationTool dt = ToolProvider.getSystemDocumentationTool(); + return dt.getStandardFileManager(null, null, null); + } + + @Test + public void testSimpleDirectUse(Path base) throws Exception { + try (StandardJavaFileManager fm = getFileManager()) { + fm.setLocation(StandardLocation.SOURCE_PATH, List.of(Path.of(testSrc).toFile())); + + // obtain a normal file object from the standard file manager + JavaFileObject someFileObject = + fm.getJavaFileForInput(StandardLocation.SOURCE_PATH, thisClassName, JavaFileObject.Kind.SOURCE); + + // build a file manager that throws an exception when someFileObject is read + StandardJavaFileManager tfm = new TestJavaFileManagerBuilder(fm) + .handle(jfo -> jfo.equals(someFileObject), + Map.of(JavaFileObject.class.getMethod("getCharContent", boolean.class), + (fo, args) -> new TestException(fo.getName()))) + .build(); + + // access the "same" file object via the test file manager + JavaFileObject someTestFileObject = + tfm.getJavaFileForInput(StandardLocation.SOURCE_PATH, thisClassName, JavaFileObject.Kind.SOURCE); + + checking("non-trapped method"); + try { + out.println("someTestFileObject.getName: " + someTestFileObject.getName()); + passed("method returned normally, as expected"); + } catch (Throwable t) { + failed("method threw unexpected exception: " + t); + } + + checking ("trapped method"); + try { + someTestFileObject.getCharContent(true); + failed("method returned normally, without throwing an exception"); + } catch (TestException e) { + String expect = someFileObject.getName(); + String found = e.getMessage(); + if (found.equals(expect)) { + passed("method threw exception as expected"); + } else { + failed("method throw exception with unexpected message:\n" + + "expected: " + expect + "\n" + + " found: " + found); + } + } catch (Throwable t) { + failed("method threw unexpected exception: " + t); + } + } + } + + @Test + public void testFileManagerAccess(Path base) throws Exception { + try (StandardJavaFileManager fm = getFileManager()) { + + // build a file manager that throws an exception when a specific source file is accessed + Method getFileForInput_method = JavaFileManager.class.getMethod("getFileForInput", + JavaFileManager.Location.class, String.class, String.class); + StandardJavaFileManager tfm = new TestJavaFileManagerBuilder(fm) + .handle(Map.of(getFileForInput_method, + (fm_, args) -> { + var relativeName = (String) args[2]; + return (relativeName.endsWith("C.properties")) + ? new TestException("getFileForInput: " + Arrays.asList(args)) + : null; + })) + .build(); + + try { + setFileManager(tfm); + javadoc("-d", base.resolve("api").toString(), + "-sourcepath", srcDir.toString(), + "p"); + checkExit((Exit.ERROR)); // Ideally, this should be ABNORMAL, but right now, the doclet has no way to indicate that + checkOutput(Output.OUT, true, + """ + error: An internal exception has occurred. + \t(##EXC##: getFileForInput: [SOURCE_PATH, p, snippet-files/C.properties]) + 1 error""" + .replace("##EXC##", TestException.class.getName())); + } finally { + setFileManager(null); + } + } + } + + @Test + public void testFileObjectRead(Path base) throws Exception { + try (StandardJavaFileManager fm = getFileManager()) { + + // build a file manager that throws an exception when any *.java is read + StandardJavaFileManager tfm = new TestJavaFileManagerBuilder(fm) + .handle(jfo -> jfo.getName().endsWith(".java"), + Map.of(JavaFileObject.class.getMethod("getCharContent", boolean.class), + (fo, args) -> new TestException(fo.getName()))) + .build(); + + try { + setFileManager(tfm); + javadoc("-d", base.resolve("api").toString(), + "-sourcepath", srcDir.toString(), + "p"); + checkExit((Exit.ABNORMAL)); + checkOutput(Output.OUT, true, + """ + Loading source files for package p... + error: fatal error encountered: ##EXC##: ##FILE## + error: Please file a bug against the javadoc tool via the Java bug reporting page""" + .replace("##EXC##", TestException.class.getName()) + .replace("##FILE##", srcDir.resolve("p").resolve("C.java").toString())); + } finally { + setFileManager(null); + } + } + } + + @Test + public void testFileObjectWrite(Path base) throws Exception { + try (StandardJavaFileManager fm = getFileManager()) { + Path outDir = base.resolve("api"); + + // build a file manager that throws an exception when any file is generated + StandardJavaFileManager tfm = new TestJavaFileManagerBuilder(fm) + .handle(jfo -> fm.asPath(jfo).startsWith(outDir.toAbsolutePath()) + && jfo.getName().endsWith(".html"), + Map.of(JavaFileObject.class.getMethod("openOutputStream"), + (fo, args) -> new TestException(fo.getName()))) + .build(); + + try { + setFileManager(tfm); + javadoc("-d", outDir.toString(), + "-sourcepath", srcDir.toString(), + "p"); + checkExit((Exit.ERROR)); + checkOutput(Output.OUT, true, + """ + Generating ##FILE##... + error: An internal exception has occurred. + \t(##EXC##: ##FILE##) + 1 error""" + .replace("##EXC##", TestException.class.getName()) + .replace("##FILE##", outDir.resolve("p").resolve("C.html").toString())); + } finally { + setFileManager(null); + } + } + } +} \ No newline at end of file diff --git a/test/langtools/jdk/javadoc/tool/CheckManPageOptions.java b/test/langtools/jdk/javadoc/tool/CheckManPageOptions.java index 437b55da677f4fd05e2e46cc42960b9b3e1f978d..6d49b54559e9bb48fb7cde33c318144cddc48a66 100644 --- a/test/langtools/jdk/javadoc/tool/CheckManPageOptions.java +++ b/test/langtools/jdk/javadoc/tool/CheckManPageOptions.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -23,7 +23,7 @@ /* * @test - * @bug 8274211 + * @bug 8274211 8278538 * @summary Test man page that options are documented * @modules jdk.javadoc/jdk.javadoc.internal.tool:+open * @run main CheckManPageOptions @@ -54,21 +54,19 @@ import java.util.stream.Collectors; * of the javadoc man page against the set of options declared in the source code. */ public class CheckManPageOptions { + static class SourceDirNotFound extends Error { } + public static void main(String... args) throws Exception { - new CheckManPageOptions().run(args); + try { + new CheckManPageOptions().run(args); + } catch (SourceDirNotFound e) { + System.err.println("NOTE: Cannot find src directory; test skipped"); + } } static final PrintStream out = System.err; - // FIXME: JDK-8274295, JDK-8266666 - List MISSING_IN_MAN_PAGE = List.of( - "--add-script", - "--legal-notices", - "--link-platform-properties", - "--no-platform-links", - "--since", - "--since-label", - "--snippet-path"); + List MISSING_IN_MAN_PAGE = List.of("--date"); void run(String... args) throws Exception { var file = args.length == 0 ? findDefaultFile() : Path.of(args[0]); @@ -151,7 +149,7 @@ public class CheckManPageOptions { } dir = dir.getParent(); } - throw new IllegalStateException("cannot find root dir"); + throw new SourceDirNotFound(); } List getToolOptions() throws Error { diff --git a/test/langtools/jdk/javadoc/tool/IgnoreSourceErrors.java b/test/langtools/jdk/javadoc/tool/IgnoreSourceErrors.java index 6c79492db053b124156dbfc1a99028f93bf9a1dd..44e698d7a885e8944fe7d489f3124c8065df86c1 100644 --- a/test/langtools/jdk/javadoc/tool/IgnoreSourceErrors.java +++ b/test/langtools/jdk/javadoc/tool/IgnoreSourceErrors.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -23,7 +23,7 @@ /* * @test - * @bug 8175219 + * @bug 8175219 8268582 * @summary test --ignore-errors works correctly * @modules * jdk.javadoc/jdk.javadoc.internal.api @@ -73,6 +73,12 @@ public class IgnoreSourceErrors extends TestRunner { if (!out.contains("modifier static not allowed here")) { throw new Exception("expected string not found \'modifier static not allowed here\'"); } + if (!out.contains("package invalid.example does not exist")) { + throw new Exception("expected string not found \'package invalid.example does not exist\'"); + } + if (!out.contains("cannot find symbol")) { + throw new Exception("expected string not found \'cannot find symbol\'"); + } } @Test @@ -84,12 +90,19 @@ public class IgnoreSourceErrors extends TestRunner { if (!out.contains("modifier static not allowed here")) { throw new Exception("expected string not found \'modifier static not allowed here\'"); } + if (!out.contains("package invalid.example does not exist")) { + throw new Exception("expected string not found \'package invalid.example does not exist\'"); + } + if (!out.contains("cannot find symbol")) { + throw new Exception("expected string not found \'cannot find symbol\'"); + } } void emitSample(Path file) throws IOException { String[] contents = { "/** A java file with errors */", - "public static class Foo {}" + "import invalid.example.OtherClass;", + "public static class Foo extends OtherClass {}" }; Files.write(file, Arrays.asList(contents), StandardOpenOption.CREATE); } diff --git a/test/langtools/jdk/javadoc/tool/api/basic/APITest.java b/test/langtools/jdk/javadoc/tool/api/basic/APITest.java index a0d68d8540333f72771f2f694823337783a8b4f5..3a5ddda8261824fed9586854f581e523162446fc 100644 --- a/test/langtools/jdk/javadoc/tool/api/basic/APITest.java +++ b/test/langtools/jdk/javadoc/tool/api/basic/APITest.java @@ -201,7 +201,7 @@ class APITest { "help-doc.html", "index-all.html", "index.html", - "script-dir/jquery-3.5.1.min.js", + "script-dir/jquery-3.6.0.min.js", "script-dir/jquery-ui.min.js", "script-dir/jquery-ui.min.css", "script-dir/jquery-ui.structure.min.css", diff --git a/test/langtools/jdk/javadoc/tool/api/basic/JavadocTaskImplTest.java b/test/langtools/jdk/javadoc/tool/api/basic/JavadocTaskImplTest.java index 1a8f1d89f775e1c045b603a28c60595d6fd8d09a..ab84566e827623b4873f210f1cc9c16850389491 100644 --- a/test/langtools/jdk/javadoc/tool/api/basic/JavadocTaskImplTest.java +++ b/test/langtools/jdk/javadoc/tool/api/basic/JavadocTaskImplTest.java @@ -104,7 +104,7 @@ public class JavadocTaskImplTest extends APITest { File outDir = getOutDir(); fm.setLocation(DocumentationTool.Location.DOCUMENTATION_OUTPUT, Arrays.asList(outDir)); try { - DocumentationTask t = new JavadocTaskImpl(c, null, null, files);; + DocumentationTask t = new JavadocTaskImpl(c, null, null, files); error("getTask succeeded, no exception thrown"); } catch (NullPointerException e) { System.err.println("exception caught as expected: " + e); diff --git a/test/langtools/jdk/javadoc/tool/doclint/DocLintReferencesTest.java b/test/langtools/jdk/javadoc/tool/doclint/DocLintReferencesTest.java new file mode 100644 index 0000000000000000000000000000000000000000..ee316135e3730d6c15a4c9128467140a14307a68 --- /dev/null +++ b/test/langtools/jdk/javadoc/tool/doclint/DocLintReferencesTest.java @@ -0,0 +1,255 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8280688 + * @summary doclint reference checks withstand warning suppression + * @library /tools/lib ../../lib + * @modules jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.main + * jdk.javadoc/jdk.javadoc.internal.api + * jdk.javadoc/jdk.javadoc.internal.tool + * @build toolbox.JavacTask toolbox.JavadocTask toolbox.TestRunner toolbox.ToolBox + * @run main DocLintReferencesTest + */ + +import toolbox.JavacTask; +import toolbox.JavadocTask; +import toolbox.Task; +import toolbox.TestRunner; +import toolbox.ToolBox; + +import java.nio.file.Files; +import java.nio.file.Path; + +/** + * Combo test for how javac and javadoc handle {@code @see MODULE/TYPE} + * for different combinations of MODULE and TYPE, with and without + * {@code @SuppressWarnings("doclint") }. + * + * Generally, in javac, references to unknown elements are reported + * as suppressible warnings if the module is not resolved in the module graph. + * Otherwise, in both javac and javadoc, any issues with references + * are reported as errors. + * + * This allows references to other modules to appear in documentation comments + * without causing a hard error if the modules are not available at compile-time. + */ +public class DocLintReferencesTest extends TestRunner { + + public static void main(String... args) throws Exception { + DocLintReferencesTest t = new DocLintReferencesTest(); + t.runTests(); + } + + DocLintReferencesTest() { + super(System.err); + } + + private final ToolBox tb = new ToolBox(); + + enum SuppressKind { NO, YES } + enum ModuleKind { NONE, BAD, NOT_FOUND, GOOD } + enum TypeKind { NONE, BAD, NOT_FOUND, GOOD } + + @Test + public void comboTest () { + for (SuppressKind sk : SuppressKind.values() ) { + for (ModuleKind mk : ModuleKind.values() ) { + for (TypeKind tk: TypeKind.values() ) { + if (mk == ModuleKind.NONE && tk == TypeKind.NONE) { + continue; + } + + try { + test(sk, mk, tk); + } catch (Throwable e) { + error("Exception " + e); + } + } + } + } + } + + void test(SuppressKind sk, ModuleKind mk, TypeKind tk) throws Exception { + out.println(); + out.println("*** Test SuppressKind:" + sk + " ModuleKind: " + mk + " TypeKind: " + tk); + Path base = Path.of(sk + "-" + mk + "-" + tk); + + String sw = switch (sk) { + case NO -> ""; + case YES -> "@SuppressWarnings(\"doclint\")"; + }; + String m = switch (mk) { + case NONE -> ""; + case BAD -> "bad-name/"; + case NOT_FOUND -> "not.found/"; + case GOOD -> "java.base/"; + }; + String t = switch (tk) { + case NONE -> ""; + case BAD -> "bad-name"; + case NOT_FOUND -> "java.lang.NotFound"; + case GOOD -> "java.lang.Object"; + }; + + Path src = base.resolve("src"); + tb.writeJavaFiles(src, """ + package p; + /** + * Comment. + * @see #M##T# + */ + #SW# + public class C { + private C() { } + } + """ + .replace("#M#", m) + .replace("#T#", t) + .replace("#SW#", sw)); + + testJavac(sk, mk, tk, base, src); + testJavadoc(sk, mk, tk, base, src); + } + + void testJavac(SuppressKind sk, ModuleKind mk, TypeKind tk, Path base, Path src) throws Exception { + Files.createDirectories(base.resolve("classes")); + + out.println("javac:"); + try { + String s = predictOutput(sk, mk, tk, false); + Task.Expect e = s.isEmpty() ? Task.Expect.SUCCESS : Task.Expect.FAIL; + + String o = new JavacTask(tb) + .outdir(base.resolve("classes")) + .options("-Xdoclint:all/protected", "-Werror") + .files(tb.findJavaFiles(src)) + .run(e) + .writeAll() + .getOutput(Task.OutputKind.DIRECT); + + checkOutput(s, o); + + } catch (Throwable t) { + error("Error: " + t); + } + out.println(); + } + + void testJavadoc(SuppressKind sk, ModuleKind mk, TypeKind tk, Path base, Path src) throws Exception { + Files.createDirectories(base.resolve("api")); + + out.println("javadoc:"); + try { + String s = predictOutput(sk, mk, tk, true); + Task.Expect e = s.isEmpty() ? Task.Expect.SUCCESS : Task.Expect.FAIL; + + String o = new JavadocTask(tb) + .outdir(base.resolve("api")) + .options("-Xdoclint", "-Werror", "-quiet", "-sourcepath", src.toString(), "p") + .run(e) + .writeAll() + .getOutput(Task.OutputKind.DIRECT); + + checkOutput(s, o); + + } catch (Throwable t) { + error("Error: " + t); + } + out.println(); + } + + private static final String ERROR_UNEXPECTED_TEXT = "error: unexpected text"; + private static final String ERROR_REFERENCE_NOT_FOUND = "error: reference not found"; + private static final String WARNING_MODULE_FOR_REFERENCE_NOT_FOUND = "warning: module for reference not found: not.found"; + private static final String EMPTY = ""; + + /** + * Returns the expected diagnostic, if any, based on the parameters of the test case. + * + * The "interesting" cases are those for which the module name is not found, + * in which case an error for "reference not found" is reduced to warning, + * which may be suppressed. + * + * @param sk whether @SuppressWarnings is present of not + * @param mk the kind of module in the reference + * @param tk the kind of class or interface name in the reference + * @param strict whether all "not found" references are errors, + * or just warnings if the module name is not found + * @return a diagnostic string, or an empty string if no diagnostic should be generated + */ + String predictOutput(SuppressKind sk, ModuleKind mk, TypeKind tk, boolean strict) { + return switch (mk) { + case NONE -> switch(tk) { + case NONE -> throw new Error("should not happen"); // filtered out in combo loops + case BAD -> ERROR_UNEXPECTED_TEXT; + case NOT_FOUND -> ERROR_REFERENCE_NOT_FOUND; + case GOOD -> EMPTY; + }; + + case BAD -> ERROR_UNEXPECTED_TEXT; + + case NOT_FOUND -> switch(tk) { + case BAD -> ERROR_UNEXPECTED_TEXT; + case NONE, NOT_FOUND, GOOD -> strict + ? ERROR_REFERENCE_NOT_FOUND + : sk == SuppressKind.YES + ? EMPTY + : WARNING_MODULE_FOR_REFERENCE_NOT_FOUND; + }; + + case GOOD -> switch(tk) { + case BAD -> ERROR_UNEXPECTED_TEXT; + case NOT_FOUND -> ERROR_REFERENCE_NOT_FOUND; + case GOOD, NONE -> EMPTY; + }; + }; + } + + /** + * Checks the actual output against the expected string, generated by {@code predictError}. + * If the expected string is empty, the output should be empty. + * If the expected string is not empty, it should be present in the output. + * + * @param expect the expected string + * @param found the output + */ + void checkOutput(String expect, String found) { + if (expect.isEmpty()) { + if (found.isEmpty()) { + out.println("Output OK"); + } else { + error("unexpected output"); + } + } else { + if (found.contains(expect)) { + out.println("Output OK"); + } else { + error("expected output not found: " + expect); + } + } + + } +} diff --git a/test/langtools/jdk/jshell/CommandCompletionTest.java b/test/langtools/jdk/jshell/CommandCompletionTest.java index 27746a748b9dff441b9f893726c6c66ead04e007..3a5eb1a46a7ce46d258315ce60b69b9e08793bfe 100644 --- a/test/langtools/jdk/jshell/CommandCompletionTest.java +++ b/test/langtools/jdk/jshell/CommandCompletionTest.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8144095 8164825 8169818 8153402 8165405 8177079 8178013 8167554 8166232 + * @bug 8144095 8164825 8169818 8153402 8165405 8177079 8178013 8167554 8166232 8277328 * @summary Test Command Completion * @modules jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.main @@ -331,6 +331,22 @@ public class CommandCompletionTest extends ReplToolTesting { ); } + @Test + public void testClassPathWithSpace() throws IOException { + Compiler compiler = new Compiler(); + Path outDir = compiler.getPath("testClassPathWithSpace"); + Path dirWithSpace = Files.createDirectories(outDir.resolve("dir with space")); + Files.createDirectories(dirWithSpace.resolve("nested with space")); + String[] pathArray = new String[] {"dir\\ with\\ space/"}; + String[] pathArray2 = new String[] {"nested\\ with\\ space/"}; + testNoStartUp( + a -> assertCompletion(a, "/env -class-path " + outDir + "/|", false, pathArray), + a -> assertCompletion(a, "/env -class-path " + outDir + "/dir|", false, pathArray), + a -> assertCompletion(a, "/env -class-path " + outDir + "/dir\\ with|", false, pathArray), + a -> assertCompletion(a, "/env -class-path " + outDir + "/dir\\ with\\ space/|", false, pathArray2) + ); + } + @Test public void testUserHome() throws IOException { List completions; @@ -338,8 +354,9 @@ public class CommandCompletionTest extends ReplToolTesting { String selectedFile; try (Stream content = Files.list(home)) { selectedFile = content.filter(CLASSPATH_FILTER) + .filter(file -> file.getFileName().toString().contains(" ")) .findAny() - .map(file -> file.getFileName().toString()) + .map(file -> file.getFileName().toString().replace(" ", "\\ ")) .orElse(null); } if (selectedFile == null) { @@ -347,8 +364,8 @@ public class CommandCompletionTest extends ReplToolTesting { } try (Stream content = Files.list(home)) { completions = content.filter(CLASSPATH_FILTER) - .filter(file -> file.getFileName().toString().startsWith(selectedFile)) - .map(file -> file.getFileName().toString() + (Files.isDirectory(file) ? "/" : "")) + .filter(file -> file.getFileName().toString().startsWith(selectedFile.replace("\\ ", " "))) + .map(file -> file.getFileName().toString().replace(" ", "\\ ") + (Files.isDirectory(file) ? "/" : "")) .sorted() .collect(Collectors.toList()); } diff --git a/test/langtools/jdk/jshell/ErrorRecoveryTest.java b/test/langtools/jdk/jshell/ErrorRecoveryTest.java index 0a83fb0e485a511f821bcd061776bb659a0742a0..0dd43fa68cdae90eadc248e76ba6ba5d921e6850 100644 --- a/test/langtools/jdk/jshell/ErrorRecoveryTest.java +++ b/test/langtools/jdk/jshell/ErrorRecoveryTest.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8270139 + * @bug 8270139 8273039 * @summary Verify error recovery in JShell * @modules jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.main @@ -37,6 +37,7 @@ import org.testng.annotations.Test; import static jdk.jshell.Snippet.Status.NONEXISTENT; import static jdk.jshell.Snippet.Status.RECOVERABLE_NOT_DEFINED; +import static jdk.jshell.Snippet.Status.REJECTED; @Test public class ErrorRecoveryTest extends KullaTesting { @@ -49,4 +50,11 @@ public class ErrorRecoveryTest extends KullaTesting { """, ste(MAIN_SNIPPET, NONEXISTENT, RECOVERABLE_NOT_DEFINED, false, null)); } + + public void testBrokenName() { + assertEval("int strictfp = 0;", + DiagCheck.DIAG_ERROR, + DiagCheck.DIAG_IGNORE, + ste(MAIN_SNIPPET, NONEXISTENT, REJECTED, false, null)); + } } diff --git a/test/langtools/jdk/jshell/ToolBasicTest.java b/test/langtools/jdk/jshell/ToolBasicTest.java index 8d8dfc8f9f449cf35f07ae48f18b2b0a4de209f2..a6bb7a075de39c089e6a7acaca3c0a6be427704d 100644 --- a/test/langtools/jdk/jshell/ToolBasicTest.java +++ b/test/langtools/jdk/jshell/ToolBasicTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -553,7 +553,7 @@ public class ToolBasicTest extends ReplToolTesting { } public void testOpenResource() { - test( + test(new String[]{"-R", "-Duser.language=en", "-R", "-Duser.country=US"}, (a) -> assertCommand(a, "/open PRINTING", ""), (a) -> assertCommandOutputContains(a, "/list", "void println", "System.out.printf"), diff --git a/test/langtools/jdk/jshell/ToolEnableNativeAccessTest.java b/test/langtools/jdk/jshell/ToolEnableNativeAccessTest.java new file mode 100644 index 0000000000000000000000000000000000000000..212301c0fd83ef6a49e9ff4279df442e2492b8c6 --- /dev/null +++ b/test/langtools/jdk/jshell/ToolEnableNativeAccessTest.java @@ -0,0 +1,63 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8268725 + * @summary Tests for the --enable-native-access option + * @modules jdk.jshell + * @run testng ToolEnableNativeAccessTest + */ + +import org.testng.annotations.Test; + +import static org.testng.Assert.assertTrue; + +public class ToolEnableNativeAccessTest extends ReplToolTesting { + + @Test + public void testOptionDebug() { + test( + (a) -> assertCommand(a, "/debug b", + "RemoteVM Options: []\n" + + "Compiler options: []"), + (a) -> assertCommand(a, "/env --enable-native-access", + "| Setting new options and restoring state."), + (a) -> assertCommandCheckOutput(a, "/debug b", s -> { + assertTrue(s.contains("RemoteVM Options: [--enable-native-access, ALL-UNNAMED]")); + assertTrue(s.contains("Compiler options: []")); + }) + ); + } + + @Test + public void testCommandLineFlag() { + test(new String[] {"--enable-native-access"}, + (a) -> assertCommandCheckOutput(a, "/debug b", s -> { + assertTrue(s.contains("RemoteVM Options: [--enable-native-access, ALL-UNNAMED]")); + assertTrue(s.contains("Compiler options: []")); + }) + ); + } + +} diff --git a/test/langtools/jdk/jshell/ToolSimpleTest.java b/test/langtools/jdk/jshell/ToolSimpleTest.java index 26a5402564e65560bbc1e84549541801422ede35..6994e3b99f28c710e48bdfb8b2bdad25faaef249 100644 --- a/test/langtools/jdk/jshell/ToolSimpleTest.java +++ b/test/langtools/jdk/jshell/ToolSimpleTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -744,7 +744,8 @@ public class ToolSimpleTest extends ReplToolTesting { @Test public void testCompoundStart() { - test(new String[]{"--startup", "DEFAULT", "--startup", "PRINTING"}, + test(new String[]{"-R", "-Duser.language=en", "-R", "-Duser.country=US", + "--startup", "DEFAULT", "--startup", "PRINTING"}, (a) -> assertCommand(a, "printf(\"%4.2f\", Math.PI)", "", "", null, "3.14", "") ); diff --git a/test/langtools/jdk/jshell/VariablesTest.java b/test/langtools/jdk/jshell/VariablesTest.java index 4224331b331c88f74fd213370defd7214e0a4f56..be957d5065e08a4a7f3963f111a9f32a0cb4b4a0 100644 --- a/test/langtools/jdk/jshell/VariablesTest.java +++ b/test/langtools/jdk/jshell/VariablesTest.java @@ -340,7 +340,7 @@ public class VariablesTest extends KullaTesting { //assertEquals(getState().source(snippet), src); //assertEquals(snippet, undefKey); assertEquals(getState().status(undefKey), RECOVERABLE_NOT_DEFINED); - List unr = getState().unresolvedDependencies((VarSnippet) undefKey).collect(toList());; + List unr = getState().unresolvedDependencies((VarSnippet) undefKey).collect(toList()); assertEquals(unr.size(), 1); assertEquals(unr.get(0), "class undefined"); assertVariables(variable("undefined", "d")); diff --git a/test/langtools/tools/doclint/RunTest.java b/test/langtools/tools/doclint/RunTest.java index 2d287136b479d06fdf7b35677add31e82ee9ad12..aff4b6c855babdd78218626c2a76d3a18e2f7406 100644 --- a/test/langtools/tools/doclint/RunTest.java +++ b/test/langtools/tools/doclint/RunTest.java @@ -59,7 +59,7 @@ public class RunTest { System.err.println("test: " + m.getName()); try { StringWriter sw = new StringWriter(); - PrintWriter pw = new PrintWriter(sw);; + PrintWriter pw = new PrintWriter(sw); m.invoke(this, new Object[] { pw }); String out = sw.toString(); System.err.println(">>> " + out.replace("\n", "\n>>> ")); diff --git a/test/langtools/tools/javac/6521805/T6521805d.java b/test/langtools/tools/javac/6521805/T6521805d.java index 2cdce03c123e47307be2dfebd795783313792fb0..15535509d4478823e96fa11ec6762ab84f17b380 100644 --- a/test/langtools/tools/javac/6521805/T6521805d.java +++ b/test/langtools/tools/javac/6521805/T6521805d.java @@ -7,6 +7,8 @@ * @compile/fail/ref=T6521805d.out T6521805d.java -XDrawDiagnostics */ +import java.util.Objects; + class T6521805 { static class Inner extends T6521805.Outer { @@ -22,6 +24,11 @@ class T6521805 { } } - class Outer {} + class Outer { + { + // access enclosing instance so this$0 field is generated + Objects.requireNonNull(T6521805.this); + } + } } diff --git a/test/langtools/tools/javac/6521805/T6521805d.out b/test/langtools/tools/javac/6521805/T6521805d.out index 1cf1b8e229e6c230652ffb67c7ce33cf4466cd07..92562a1b53596c150e3656238d418bce935c3ac3 100644 --- a/test/langtools/tools/javac/6521805/T6521805d.out +++ b/test/langtools/tools/javac/6521805/T6521805d.out @@ -1,2 +1,2 @@ -T6521805d.java:18:18: compiler.err.cannot.generate.class: T6521805.Inner, (compiler.misc.synthetic.name.conflict: this$0, T6521805.Inner) +T6521805d.java:20:18: compiler.err.cannot.generate.class: T6521805.Inner, (compiler.misc.synthetic.name.conflict: this$0, T6521805.Inner) 1 error diff --git a/test/langtools/tools/javac/6521805/p/Outer.java b/test/langtools/tools/javac/6521805/p/Outer.java index 8a92158426b971717f73c8944b1df0fff8076025..acbbfa0f91f397dc1d6af142ff890b9e55897d76 100644 --- a/test/langtools/tools/javac/6521805/p/Outer.java +++ b/test/langtools/tools/javac/6521805/p/Outer.java @@ -2,6 +2,13 @@ package p; +import java.util.Objects; + class Outer { - class Super {} + class Super { + { + // access enclosing instance so this$0 field is generated + Objects.requireNonNull(Outer.this); + } + } } diff --git a/test/langtools/tools/javac/8074306/TestSyntheticNullChecks.java b/test/langtools/tools/javac/8074306/TestSyntheticNullChecks.java index 137e15c15bfdd238cd8544669f0b20a22306e04b..c4b8843cebc0408eafc55db309429b606c770b0c 100644 --- a/test/langtools/tools/javac/8074306/TestSyntheticNullChecks.java +++ b/test/langtools/tools/javac/8074306/TestSyntheticNullChecks.java @@ -27,7 +27,7 @@ * @summary NULLCHK is emitted as Object.getClass * @compile -source 7 -target 7 TestSyntheticNullChecks.java * @run main TestSyntheticNullChecks 7 - * @clean TestSyntheticNullChecks* + * @clean * * @compile TestSyntheticNullChecks.java * @run main TestSyntheticNullChecks 9 */ diff --git a/test/langtools/tools/javac/8203436/T8203436a.java b/test/langtools/tools/javac/8203436/T8203436a.java index eba0f827c8626865731c112d0afe3c49947d6213..db47a62e67270f3c32266f387139d8eca0f2b838 100644 --- a/test/langtools/tools/javac/8203436/T8203436a.java +++ b/test/langtools/tools/javac/8203436/T8203436a.java @@ -1,6 +1,6 @@ /* * @test /nodynamiccopyright/ - * @bug 8203436 + * @bug 8203436 8211004 * @summary javac should fail early when emitting illegal signature attributes * @compile/fail/ref=T8203436a.out -XDrawDiagnostics T8203436a.java */ diff --git a/test/langtools/tools/javac/8203436/T8203436a.out b/test/langtools/tools/javac/8203436/T8203436a.out index 71b7e6871664f548e7286f68023f60a65c889c40..e076a20a2a84512a63797b05be11af2d1f0c8e89 100644 --- a/test/langtools/tools/javac/8203436/T8203436a.out +++ b/test/langtools/tools/javac/8203436/T8203436a.out @@ -1,2 +1,2 @@ -- compiler.err.cannot.generate.class: compiler.misc.anonymous.class: T8203436a$1, (compiler.misc.illegal.signature: compiler.misc.anonymous.class: T8203436a$1, compiler.misc.type.captureof: 1, ?) +T8203436a.java:12:7: compiler.err.enclosing.class.type.non.denotable: T8203436a 1 error diff --git a/test/langtools/tools/javac/8203436/T8203436b.out b/test/langtools/tools/javac/8203436/T8203436b.out index 979e550fff6c85603ccbff2bc79c0d6ee163770f..48eb947cecf1e5c8f8f91edf73ee018734e18df6 100644 --- a/test/langtools/tools/javac/8203436/T8203436b.out +++ b/test/langtools/tools/javac/8203436/T8203436b.out @@ -1,2 +1,2 @@ -- compiler.err.cannot.generate.class: compiler.misc.anonymous.class: T8203436b$1, (compiler.misc.illegal.signature: compiler.misc.anonymous.class: T8203436b$1, java.lang.Object&T8203436b.A&T8203436b.B) +T8203436b.java:17:10: compiler.err.enclosing.class.type.non.denotable: T8203436b 1 error diff --git a/test/langtools/tools/javac/8278078/InvalidThisAndSuperInConstructorArgTest.java b/test/langtools/tools/javac/8278078/InvalidThisAndSuperInConstructorArgTest.java new file mode 100644 index 0000000000000000000000000000000000000000..eee79e2d5e9895e29db9939d2fe2d7c48052d8df --- /dev/null +++ b/test/langtools/tools/javac/8278078/InvalidThisAndSuperInConstructorArgTest.java @@ -0,0 +1,68 @@ + +import java.util.function.Supplier; + +/** + * @test /nodynamiccopyright/ + * @bug 8278078 + * @summary error: cannot reference super before supertype constructor has been called + * @compile/fail/ref=InvalidThisAndSuperInConstructorArgTest.out -XDrawDiagnostics InvalidThisAndSuperInConstructorArgTest.java + */ +public class InvalidThisAndSuperInConstructorArgTest { + + interface InterfaceWithDefault { + default String get() { + return ""; + } + } + + InvalidThisAndSuperInConstructorArgTest(String s) { + } + + class InnerClass extends AssertionError implements InterfaceWithDefault { + InnerClass() { + super(InnerClass.super.toString()); + } + InnerClass(int i) { + this(InnerClass.super.toString()); + } + InnerClass(boolean b) { + super(InnerClass.this.toString()); + } + InnerClass(double d) { + this(InnerClass.this.toString()); + } + InnerClass(float f) { + super(AssertionError.super.toString()); + } + InnerClass(char ch) { + this(AssertionError.super.toString()); + } + InnerClass(byte b) { + super(AssertionError.this.toString()); + } + InnerClass(Object o) { + this(AssertionError.this.toString()); + } + InnerClass(int[] ii) { + this(InterfaceWithDefault.super.get()); + } + InnerClass(boolean[] bb) { + super(InterfaceWithDefault.this.get()); + } + InnerClass(double[] dd) { + this(InterfaceWithDefault.this.get()); + } + InnerClass(float[] ff) { + super(InterfaceWithDefault.super.get()); + } + InnerClass(char[] chch) { + this(InnerClass.this::toString); + } + InnerClass(String s) { + super(s); + } + InnerClass(Supplier sup) { + super(sup); + } + } +} diff --git a/test/langtools/tools/javac/8278078/InvalidThisAndSuperInConstructorArgTest.out b/test/langtools/tools/javac/8278078/InvalidThisAndSuperInConstructorArgTest.out new file mode 100644 index 0000000000000000000000000000000000000000..1109eb0fdc46bb72be692c2ce7344a5ddc372f75 --- /dev/null +++ b/test/langtools/tools/javac/8278078/InvalidThisAndSuperInConstructorArgTest.out @@ -0,0 +1,14 @@ +InvalidThisAndSuperInConstructorArgTest.java:23:29: compiler.err.cant.ref.before.ctor.called: super +InvalidThisAndSuperInConstructorArgTest.java:26:28: compiler.err.cant.ref.before.ctor.called: super +InvalidThisAndSuperInConstructorArgTest.java:29:29: compiler.err.cant.ref.before.ctor.called: this +InvalidThisAndSuperInConstructorArgTest.java:32:28: compiler.err.cant.ref.before.ctor.called: this +InvalidThisAndSuperInConstructorArgTest.java:35:33: compiler.err.not.encl.class: java.lang.AssertionError +InvalidThisAndSuperInConstructorArgTest.java:38:32: compiler.err.not.encl.class: java.lang.AssertionError +InvalidThisAndSuperInConstructorArgTest.java:41:33: compiler.err.not.encl.class: java.lang.AssertionError +InvalidThisAndSuperInConstructorArgTest.java:44:32: compiler.err.not.encl.class: java.lang.AssertionError +InvalidThisAndSuperInConstructorArgTest.java:47:38: compiler.err.cant.ref.before.ctor.called: super +InvalidThisAndSuperInConstructorArgTest.java:50:39: compiler.err.not.encl.class: InvalidThisAndSuperInConstructorArgTest.InterfaceWithDefault +InvalidThisAndSuperInConstructorArgTest.java:53:38: compiler.err.not.encl.class: InvalidThisAndSuperInConstructorArgTest.InterfaceWithDefault +InvalidThisAndSuperInConstructorArgTest.java:56:39: compiler.err.cant.ref.before.ctor.called: super +InvalidThisAndSuperInConstructorArgTest.java:59:28: compiler.err.cant.ref.before.ctor.called: this +13 errors diff --git a/test/langtools/tools/javac/8278078/ValidThisAndSuperInConstructorArgTest.java b/test/langtools/tools/javac/8278078/ValidThisAndSuperInConstructorArgTest.java new file mode 100644 index 0000000000000000000000000000000000000000..2fe1388420c2690532d31107a993e5cbdaa20a46 --- /dev/null +++ b/test/langtools/tools/javac/8278078/ValidThisAndSuperInConstructorArgTest.java @@ -0,0 +1,78 @@ +/* + * 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. + */ + +/** + * @test + * @bug 8278078 + * @summary error: cannot reference super before supertype constructor has been called + * @compile ValidThisAndSuperInConstructorArgTest.java + * @run main ValidThisAndSuperInConstructorArgTest + */ +public class ValidThisAndSuperInConstructorArgTest { + + static final String SUPER = "unexpected super call"; + static final String THIS = "unexpected this call"; + + public String get() { + return SUPER; + } + + static class StaticSubClass extends ValidThisAndSuperInConstructorArgTest { + @Override + public String get() { + return THIS; + } + + class InnerClass extends AssertionError { + InnerClass() { + super(StaticSubClass.super.get()); + } + InnerClass(int i) { + this(StaticSubClass.super.get()); + } + InnerClass(boolean b) { + super(StaticSubClass.this.get()); + } + InnerClass(double d) { + this(StaticSubClass.this.get()); + } + InnerClass(String s) { + super(s); + } + void assertThis() { + if (!THIS.equals(getMessage())) throw this; + } + void assertSuper() { + if (!SUPER.equals(getMessage())) throw this; + } + } + } + + public static void main(String...args) { + var test = new StaticSubClass(); + test.new InnerClass().assertSuper(); + test.new InnerClass(1).assertSuper(); + test.new InnerClass(true).assertThis(); + test.new InnerClass(1.0).assertThis(); + } +} diff --git a/test/langtools/tools/javac/ClassFileModifiers/MemberModifiers.out b/test/langtools/tools/javac/ClassFileModifiers/MemberModifiers.out index 35b1bc29ca9b38e0cf52db2ca76355cbf3933330..6d26076a57f21fe788fd5cbe8e073b5a77d1b215 100644 --- a/test/langtools/tools/javac/ClassFileModifiers/MemberModifiers.out +++ b/test/langtools/tools/javac/ClassFileModifiers/MemberModifiers.out @@ -1,8 +1,6 @@ CLASSFILE MemberModifiers.c --- SUPER -FIELD this$0 ---- FINAL METHOD --- @@ -20,8 +18,6 @@ METHOD m CLASSFILE MemberModifiersAux.Foo.c --- SUPER -FIELD this$1 ---- FINAL METHOD --- @@ -29,8 +25,6 @@ CLASSFILE MemberModifiersAux.Foo --- FINAL SUPER FIELD f --- -FIELD this$0 ---- FINAL METHOD --- METHOD m diff --git a/test/langtools/tools/javac/StringConcat/StringAppendEvaluatesInOrder.java b/test/langtools/tools/javac/StringConcat/StringAppendEvaluatesInOrder.java new file mode 100644 index 0000000000000000000000000000000000000000..b2bd47acde0003a541d1c4edd2e25ab1995da3c5 --- /dev/null +++ b/test/langtools/tools/javac/StringConcat/StringAppendEvaluatesInOrder.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2021, Google LLC. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8273914 + * @summary Indy string concat changes order of operations + * + * @clean * + * @compile -XDstringConcat=indy StringAppendEvaluatesInOrder.java + * @run main StringAppendEvaluatesInOrder + * + * @clean * + * @compile -XDstringConcat=indyWithConstants StringAppendEvaluatesInOrder.java + * @run main StringAppendEvaluatesInOrder + * + * @clean * + * @compile -XDstringConcat=inline StringAppendEvaluatesInOrder.java + * @run main StringAppendEvaluatesInOrder + */ + +public class StringAppendEvaluatesInOrder { + static String test() { + StringBuilder builder = new StringBuilder("foo"); + int i = 15; + return "Test: " + i + " " + (++i) + builder + builder.append("bar"); + } + + static String compoundAssignment() { + StringBuilder builder2 = new StringBuilder("foo"); + Object oo = builder2; + oo += "" + builder2.append("bar"); + return oo.toString(); + } + + public static void main(String[] args) throws Exception { + assertEquals(test(), "Test: 15 16foofoobar"); + assertEquals(compoundAssignment(), "foofoobar"); + } + + private static void assertEquals(String actual, String expected) { + if (!actual.equals(expected)) { + throw new AssertionError("expected: " + expected + ", actual: " + actual); + } + } +} diff --git a/test/langtools/tools/javac/StringConcat/TestIndyStringConcat.java b/test/langtools/tools/javac/StringConcat/TestIndyStringConcat.java index 7576503efedb33d26c3e020b0bd608b9b4fee78a..1c4d830c6eb7dd82118d0b13d5d2bf159ac07449 100644 --- a/test/langtools/tools/javac/StringConcat/TestIndyStringConcat.java +++ b/test/langtools/tools/javac/StringConcat/TestIndyStringConcat.java @@ -34,23 +34,23 @@ import java.io.File; * @summary Test that StringConcat is working for JDK >= 9 * @modules jdk.jdeps/com.sun.tools.classfile * - * @clean TestIndyStringConcat* + * @clean * * @compile -source 7 -target 7 TestIndyStringConcat.java * @run main TestIndyStringConcat false * - * @clean TestIndyStringConcat* + * @clean * * @compile -source 8 -target 8 TestIndyStringConcat.java * @run main TestIndyStringConcat false * - * @clean TestIndyStringConcat* + * @clean * * @compile -XDstringConcat=inline -source 9 -target 9 TestIndyStringConcat.java * @run main TestIndyStringConcat false * - * @clean TestIndyStringConcat* + * @clean * * @compile -XDstringConcat=indy -source 9 -target 9 TestIndyStringConcat.java * @run main TestIndyStringConcat true * - * @clean TestIndyStringConcat* + * @clean * * @compile -XDstringConcat=indyWithConstants -source 9 -target 9 TestIndyStringConcat.java * @run main TestIndyStringConcat true */ diff --git a/test/langtools/tools/javac/StringConcat/WellKnownTypeSignatures.java b/test/langtools/tools/javac/StringConcat/WellKnownTypeSignatures.java new file mode 100644 index 0000000000000000000000000000000000000000..07cdeef49561535175e4901dd0d51b2d9528c946 --- /dev/null +++ b/test/langtools/tools/javac/StringConcat/WellKnownTypeSignatures.java @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2021, Google LLC. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import com.sun.tools.classfile.*; +import com.sun.tools.classfile.ConstantPool.*; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +/* + * @test + * @bug 8273914 + * @summary Indy string concat changes order of operations + * @modules jdk.jdeps/com.sun.tools.classfile + * + * @clean * + * @compile -XDstringConcat=indy WellKnownTypeSignatures.java + * @run main WellKnownTypeSignatures + * + * @clean * + * @compile -XDstringConcat=indyWithConstants WellKnownTypeSignatures.java + * @run main WellKnownTypeSignatures + */ + +public class WellKnownTypeSignatures { + static List actualTypes; + + static int idx = 0; + + static boolean z = true; + static char c = (char) 42; + static short s = (short) 42; + static byte b = (byte) 42; + static int i = 42; + static long l = 42L; + static float f = 42.0f; + static double d = 42.0; + + public static void main(String[] argv) throws Exception { + readIndyTypes(); + + test("" + WellKnownTypeSignatures.class, idx++, "(Ljava/lang/String;)Ljava/lang/String;"); + test("" + Boolean.valueOf(z), idx++, "(Ljava/lang/Boolean;)Ljava/lang/String;"); + test("" + Character.valueOf(c), idx++, "(Ljava/lang/Character;)Ljava/lang/String;"); + test("" + Byte.valueOf(b), idx++, "(Ljava/lang/Byte;)Ljava/lang/String;"); + test("" + Short.valueOf(s), idx++, "(Ljava/lang/Short;)Ljava/lang/String;"); + test("" + Integer.valueOf(i), idx++, "(Ljava/lang/Integer;)Ljava/lang/String;"); + test("" + Long.valueOf(l), idx++, "(Ljava/lang/Long;)Ljava/lang/String;"); + test("" + Double.valueOf(d), idx++, "(Ljava/lang/Double;)Ljava/lang/String;"); + test("" + Float.valueOf(f), idx++, "(Ljava/lang/Float;)Ljava/lang/String;"); + test("" + z, idx++, "(Z)Ljava/lang/String;"); + test("" + c, idx++, "(C)Ljava/lang/String;"); + test("" + b, idx++, "(B)Ljava/lang/String;"); + test("" + s, idx++, "(S)Ljava/lang/String;"); + test("" + i, idx++, "(I)Ljava/lang/String;"); + test("" + l, idx++, "(J)Ljava/lang/String;"); + test("" + d, idx++, "(D)Ljava/lang/String;"); + test("" + f, idx++, "(F)Ljava/lang/String;"); + } + + public static void test(String actual, int index, String expectedType) { + String actualType = actualTypes.get(index); + if (!actualType.equals(expectedType)) { + throw new IllegalStateException( + index + + " Unexpected type: expected = " + + expectedType + + ", actual = " + + actualType); + } + } + + public static void readIndyTypes() throws Exception { + actualTypes = new ArrayList(); + + ClassFile classFile = + ClassFile.read( + new File( + System.getProperty("test.classes", "."), + WellKnownTypeSignatures.class.getName() + ".class")); + ConstantPool constantPool = classFile.constant_pool; + + for (Method method : classFile.methods) { + if (method.getName(constantPool).equals("main")) { + Code_attribute code = (Code_attribute) method.attributes.get(Attribute.Code); + for (Instruction i : code.getInstructions()) { + if (i.getOpcode() == Opcode.INVOKEDYNAMIC) { + CONSTANT_InvokeDynamic_info indyInfo = + (CONSTANT_InvokeDynamic_info) + constantPool.get(i.getUnsignedShort(1)); + CONSTANT_NameAndType_info natInfo = indyInfo.getNameAndTypeInfo(); + actualTypes.add(natInfo.getType()); + } + } + } + } + } +} diff --git a/test/langtools/tools/javac/StringConcat/WellKnownTypes.java b/test/langtools/tools/javac/StringConcat/WellKnownTypes.java new file mode 100644 index 0000000000000000000000000000000000000000..39150cfc4da42fb02f18f083170d34d49a9cc6da --- /dev/null +++ b/test/langtools/tools/javac/StringConcat/WellKnownTypes.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2021, Google LLC. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import com.sun.tools.classfile.*; +import com.sun.tools.classfile.ConstantPool.*; + +/* + * @test + * @bug 8273914 + * @summary Indy string concat changes order of operations + * @modules jdk.jdeps/com.sun.tools.classfile + * + * @compile -XDstringConcat=indy WellKnownTypes.java + * @run main WellKnownTypes + * + * @compile -XDstringConcat=indyWithConstants WellKnownTypes.java + * @run main WellKnownTypes + * + * @compile -XDstringConcat=inline WellKnownTypes.java + * @run main WellKnownTypes + */ + +public class WellKnownTypes { + static int idx = 0; + + static boolean z = true; + static char c = (char) 42; + static byte b = (byte) 43; + static short s = (short) 44; + static int i = 45; + static long l = 46L; + static float f = 47.0f; + static double d = 48.0; + + public static void main(String[] argv) throws Exception { + test("" + WellKnownTypes.class, idx++, "class WellKnownTypes"); + test("" + Boolean.valueOf(z), idx++, "true"); + test("" + Character.valueOf(c), idx++, "*"); + test("" + Byte.valueOf(b), idx++, "43"); + test("" + Short.valueOf(s), idx++, "44"); + test("" + Integer.valueOf(i), idx++, "45"); + test("" + Long.valueOf(l), idx++, "46"); + test("" + Float.valueOf(f), idx++, "47.0"); + test("" + Double.valueOf(d), idx++, "48.0"); + test("" + z, idx++, "true"); + test("" + c, idx++, "*"); + test("" + b, idx++, "43"); + test("" + s, idx++, "44"); + test("" + i, idx++, "45"); + test("" + l, idx++, "46"); + test("" + f, idx++, "47.0"); + test("" + d, idx++, "48.0"); + } + + public static void test(String actual, int index, String expected) { + if (!actual.equals(expected)) { + throw new IllegalStateException( + index + " Unexpected: expected = " + expected + ", actual = " + actual); + } + } +} diff --git a/test/langtools/tools/javac/StringConcat/access/Test.java b/test/langtools/tools/javac/StringConcat/access/Test.java index 72237e8b4ef7b8d43aaccdbc26979d33bd5956ac..578bbddb1188ca25381d4e4665293b17c3560e78 100644 --- a/test/langtools/tools/javac/StringConcat/access/Test.java +++ b/test/langtools/tools/javac/StringConcat/access/Test.java @@ -56,109 +56,109 @@ public class Test { // ---------------------------------------------------------------------------- // public Private_PublicClass c1 = new Private_PublicClass(); - test("" + holder.c1, idx++, "(Lp1/PublicClass;)Ljava/lang/String;"); + test("" + holder.c1, idx++, "(Ljava/lang/String;)Ljava/lang/String;"); // public Private_PublicInterface c2 = new Private_PublicInterface(); - test("" + holder.c2, idx++, "(Ljava/lang/Object;)Ljava/lang/String;"); + test("" + holder.c2, idx++, "(Ljava/lang/String;)Ljava/lang/String;"); // public Private_PrivateInterface1 c3 = new Private_PrivateInterface1(); - test("" + holder.c3, idx++, "(Ljava/lang/Object;)Ljava/lang/String;"); + test("" + holder.c3, idx++, "(Ljava/lang/String;)Ljava/lang/String;"); // public Private_PrivateInterface2 c4 = new Private_PrivateInterface2(); - test("" + holder.c4, idx++, "(Ljava/lang/Object;)Ljava/lang/String;"); + test("" + holder.c4, idx++, "(Ljava/lang/String;)Ljava/lang/String;"); // public Public_PublicClass c5 = new Public_PublicClass(); - test("" + holder.c5, idx++, "(Lp1/Public_PublicClass;)Ljava/lang/String;"); + test("" + holder.c5, idx++, "(Ljava/lang/String;)Ljava/lang/String;"); // public Public_PublicInterface c6 = new Public_PublicInterface(); - test("" + holder.c6, idx++, "(Lp1/Public_PublicInterface;)Ljava/lang/String;"); + test("" + holder.c6, idx++, "(Ljava/lang/String;)Ljava/lang/String;"); // public Public_PrivateInterface1 c7 = new Public_PrivateInterface1(); - test("" + holder.c7, idx++, "(Lp1/Public_PrivateInterface1;)Ljava/lang/String;"); + test("" + holder.c7, idx++, "(Ljava/lang/String;)Ljava/lang/String;"); // public Public_PrivateInterface2 c8 = new Public_PrivateInterface2(); - test("" + holder.c8, idx++, "(Lp1/Public_PrivateInterface2;)Ljava/lang/String;"); + test("" + holder.c8, idx++, "(Ljava/lang/String;)Ljava/lang/String;"); // ---------------------------------------------------------------------------- // public Private_PublicClass[] ac1 = new Private_PublicClass[0]; - test("" + holder.ac1, idx++, "([Lp1/PublicClass;)Ljava/lang/String;"); + test("" + holder.ac1, idx++, "(Ljava/lang/String;)Ljava/lang/String;"); // public Private_PublicInterface[] ac2 = new Private_PublicInterface[0]; - test("" + holder.ac2, idx++, "([Ljava/lang/Object;)Ljava/lang/String;"); + test("" + holder.ac2, idx++, "(Ljava/lang/String;)Ljava/lang/String;"); // public Private_PrivateInterface1[] ac3 = new Private_PrivateInterface1[0]; - test("" + holder.ac3, idx++, "([Ljava/lang/Object;)Ljava/lang/String;"); + test("" + holder.ac3, idx++, "(Ljava/lang/String;)Ljava/lang/String;"); // public Private_PrivateInterface2[] ac4 = new Private_PrivateInterface2[0]; - test("" + holder.ac4, idx++, "([Ljava/lang/Object;)Ljava/lang/String;"); + test("" + holder.ac4, idx++, "(Ljava/lang/String;)Ljava/lang/String;"); // public Public_PublicClass[] ac5 = new Public_PublicClass[0]; - test("" + holder.ac5, idx++, "([Lp1/Public_PublicClass;)Ljava/lang/String;"); + test("" + holder.ac5, idx++, "(Ljava/lang/String;)Ljava/lang/String;"); // public Public_PublicInterface[] ac6 = new Public_PublicInterface[0]; - test("" + holder.ac6, idx++, "([Lp1/Public_PublicInterface;)Ljava/lang/String;"); + test("" + holder.ac6, idx++, "(Ljava/lang/String;)Ljava/lang/String;"); // public Public_PrivateInterface1[] ac7 = new Public_PrivateInterface1[0]; - test("" + holder.ac7, idx++, "([Lp1/Public_PrivateInterface1;)Ljava/lang/String;"); + test("" + holder.ac7, idx++, "(Ljava/lang/String;)Ljava/lang/String;"); // public Public_PrivateInterface2[] ac8 = new Public_PrivateInterface2[0]; - test("" + holder.ac8, idx++, "([Lp1/Public_PrivateInterface2;)Ljava/lang/String;"); + test("" + holder.ac8, idx++, "(Ljava/lang/String;)Ljava/lang/String;"); // ---------------------------------------------------------------------------- // public Private_PublicClass[][] aac1 = new Private_PublicClass[0][]; - test("" + holder.aac1, idx++, "([[Lp1/PublicClass;)Ljava/lang/String;"); + test("" + holder.aac1, idx++, "(Ljava/lang/String;)Ljava/lang/String;"); // public Private_PublicInterface[][] aac2 = new Private_PublicInterface[0][]; - test("" + holder.aac2, idx++, "([[Ljava/lang/Object;)Ljava/lang/String;"); + test("" + holder.aac2, idx++, "(Ljava/lang/String;)Ljava/lang/String;"); // public Private_PrivateInterface1[][] aac3 = new Private_PrivateInterface1[0][]; - test("" + holder.aac3, idx++, "([[Ljava/lang/Object;)Ljava/lang/String;"); + test("" + holder.aac3, idx++, "(Ljava/lang/String;)Ljava/lang/String;"); // public Private_PrivateInterface2[][] aac4 = new Private_PrivateInterface2[0][]; - test("" + holder.aac4, idx++, "([[Ljava/lang/Object;)Ljava/lang/String;"); + test("" + holder.aac4, idx++, "(Ljava/lang/String;)Ljava/lang/String;"); // public Public_PublicClass[][] aac5 = new Public_PublicClass[0][]; - test("" + holder.aac5, idx++, "([[Lp1/Public_PublicClass;)Ljava/lang/String;"); + test("" + holder.aac5, idx++, "(Ljava/lang/String;)Ljava/lang/String;"); // public Public_PublicInterface[][] aac6 = new Public_PublicInterface[0][]; - test("" + holder.aac6, idx++, "([[Lp1/Public_PublicInterface;)Ljava/lang/String;"); + test("" + holder.aac6, idx++, "(Ljava/lang/String;)Ljava/lang/String;"); // public Public_PrivateInterface1[][] aac7 = new Public_PrivateInterface1[0][]; - test("" + holder.aac7, idx++, "([[Lp1/Public_PrivateInterface1;)Ljava/lang/String;"); + test("" + holder.aac7, idx++, "(Ljava/lang/String;)Ljava/lang/String;"); // public Public_PrivateInterface2[][] aac8 = new Public_PrivateInterface2[0][]; - test("" + holder.aac8, idx++, "([[Lp1/Public_PrivateInterface2;)Ljava/lang/String;"); + test("" + holder.aac8, idx++, "(Ljava/lang/String;)Ljava/lang/String;"); // ---------------------------------------------------------------------------- // public PublicInterface i1 = new Private_PublicInterface(); - test("" + holder.i1, idx++, "(Lp1/PublicInterface;)Ljava/lang/String;"); + test("" + holder.i1, idx++, "(Ljava/lang/String;)Ljava/lang/String;"); // public PrivateInterface1 i2 = new Private_PrivateInterface1(); - test("" + holder.i2, idx++, "(Ljava/lang/Object;)Ljava/lang/String;"); + test("" + holder.i2, idx++, "(Ljava/lang/String;)Ljava/lang/String;"); // public PrivateInterface2 i3 = new Private_PrivateInterface2(); - test("" + holder.i3, idx++, "(Ljava/lang/Object;)Ljava/lang/String;"); + test("" + holder.i3, idx++, "(Ljava/lang/String;)Ljava/lang/String;"); // public PublicInterface[] ai1 = new Private_PublicInterface[0]; - test("" + holder.ai1, idx++, "([Lp1/PublicInterface;)Ljava/lang/String;"); + test("" + holder.ai1, idx++, "(Ljava/lang/String;)Ljava/lang/String;"); // public PrivateInterface1[] ai2 = new Private_PrivateInterface1[0]; - test("" + holder.ai2, idx++, "([Ljava/lang/Object;)Ljava/lang/String;"); + test("" + holder.ai2, idx++, "(Ljava/lang/String;)Ljava/lang/String;"); // public PrivateInterface2[] ai3 = new Private_PrivateInterface2[0]; - test("" + holder.ai3, idx++, "([Ljava/lang/Object;)Ljava/lang/String;"); + test("" + holder.ai3, idx++, "(Ljava/lang/String;)Ljava/lang/String;"); // public PublicInterface[][] aai1 = new Private_PublicInterface[0][]; - test("" + holder.aai1, idx++, "([[Lp1/PublicInterface;)Ljava/lang/String;"); + test("" + holder.aai1, idx++, "(Ljava/lang/String;)Ljava/lang/String;"); // public PrivateInterface1[][] aai2 = new Private_PrivateInterface1[0][]; - test("" + holder.aai2, idx++, "([[Ljava/lang/Object;)Ljava/lang/String;"); + test("" + holder.aai2, idx++, "(Ljava/lang/String;)Ljava/lang/String;"); // public PrivateInterface2[][] aai3 = new Private_PrivateInterface2[0][]; - test("" + holder.aai3, idx++, "([[Ljava/lang/Object;)Ljava/lang/String;"); + test("" + holder.aai3, idx++, "(Ljava/lang/String;)Ljava/lang/String;"); } diff --git a/test/langtools/tools/javac/T8036019.java b/test/langtools/tools/javac/T8036019.java new file mode 100644 index 0000000000000000000000000000000000000000..709b8abba468b025c42725c4e139dbbc5ad49981 --- /dev/null +++ b/test/langtools/tools/javac/T8036019.java @@ -0,0 +1,46 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8036019 + * @summary Insufficient alternatives listed in some errors produced by the parser + * @compile/fail/ref=T8036019.out -XDrawDiagnostics T8036019.java + */ + + +public class T8036019 { + enum E { + E(String value) { } + } + + interface A {} + interface B {} + public class Foo { + Foo foo1 = null; + } + + @SuppressWarnings({,0}) + public class AV { + } +} diff --git a/test/langtools/tools/javac/T8036019.out b/test/langtools/tools/javac/T8036019.out new file mode 100644 index 0000000000000000000000000000000000000000..2c874175793c6034a7eb66727fa9ff7ccdc01d87 --- /dev/null +++ b/test/langtools/tools/javac/T8036019.out @@ -0,0 +1,10 @@ +T8036019.java:34:17: compiler.err.expected2: ')', ',' +T8036019.java:34:23: compiler.err.expected3: ',', '}', ';' +T8036019.java:34:25: compiler.err.enum.constant.expected +T8036019.java:40:24: compiler.err.expected2: >, ',' +T8036019.java:40:26: compiler.err.expected: token.identifier +T8036019.java:40:32: compiler.err.expected: token.identifier +T8036019.java:43:25: compiler.err.annotation.missing.element.value +T8036019.java:43:27: compiler.err.expected4: class, interface, enum, record +T8036019.java:46:1: compiler.err.expected4: class, interface, enum, record +9 errors \ No newline at end of file diff --git a/test/langtools/tools/javac/T8271079.java b/test/langtools/tools/javac/T8271079.java new file mode 100644 index 0000000000000000000000000000000000000000..9b866f618a771c1058fa7d2fbf58fa95192d12dd --- /dev/null +++ b/test/langtools/tools/javac/T8271079.java @@ -0,0 +1,110 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8271079 + * @summary JavaFileObject#toUri in MR-JAR returns real path + * @modules java.compiler + * jdk.compiler + * @run main T8271079 + */ + +import java.io.*; +import java.net.*; +import java.nio.charset.StandardCharsets; +import java.nio.file.*; +import java.util.*; +import java.util.jar.JarEntry; +import javax.tools.*; + +public class T8271079 { + + public static void main(String[] args) throws Exception { + new T8271079().run(); + } + + final PrintStream out; + + T8271079() { + this.out = System.out; + } + + void run() throws Exception { + Path mr = generateMultiReleaseJar(); + try { + testT8271079(mr); + } finally { + Files.deleteIfExists(mr); + } + } + + // $ echo 'module hello {}' > module-info.java + // $ javac -d classes --release 9 module-info.java + // $ jar --create --file mr.jar --release 9 -C classes . + Path generateMultiReleaseJar() throws Exception { + Files.writeString(Path.of("module-info.java"), "module hello {}"); + java.util.spi.ToolProvider.findFirst("javac").orElseThrow() + .run(out, System.err, "-d", "classes", "--release", "9", "module-info.java"); + Path mr = Path.of("mr.jar"); + java.util.spi.ToolProvider.findFirst("jar").orElseThrow() + .run(out, System.err, "--create", "--file", mr.toString(), "--release", "9", "-C", "classes", "."); + out.println("Created: " + mr.toUri()); + out.println(" Exists: " + Files.exists(mr)); + return mr; + } + + void testT8271079(Path path) throws Exception { + StandardJavaFileManager fileManager = + ToolProvider.getSystemJavaCompiler() + .getStandardFileManager(null, Locale.ENGLISH, StandardCharsets.UTF_8); + fileManager.setLocationFromPaths(StandardLocation.CLASS_PATH, List.of(path)); + Iterator options = Arrays.asList("--multi-release", "9").iterator(); + fileManager.handleOption(options.next(), options); + + Iterable list = + fileManager.list( + StandardLocation.CLASS_PATH, "", EnumSet.allOf(JavaFileObject.Kind.class), false); + + for (JavaFileObject f : list) { + out.println("JavaFileObject#getName: " + f.getName()); + out.println("JavaFileObject#toUri: " + f.toUri()); + openUsingUri(f.toUri()); + } + System.gc(); // JDK-8224794 + } + + void openUsingUri(URI uri) throws IOException { + URLConnection connection = uri.toURL().openConnection(); + connection.setUseCaches(false); // JDK-8224794 + if (connection instanceof JarURLConnection jar) { + try { + JarEntry entry = jar.getJarEntry(); + out.println("JarEntry#getName: " + entry.getName()); + connection.getInputStream().close(); // JDK-8224794 + } catch (FileNotFoundException e) { + throw e; + } + } + } +} diff --git a/test/langtools/tools/javac/annotations/typeAnnotations/6967002/T6967002.out b/test/langtools/tools/javac/annotations/typeAnnotations/6967002/T6967002.out index 86480c2bfa8e41bcd1d5aa357574aed7572a9f2a..d9a3545d31deec460f0a1142b0b08ce4996f6cfa 100644 --- a/test/langtools/tools/javac/annotations/typeAnnotations/6967002/T6967002.out +++ b/test/langtools/tools/javac/annotations/typeAnnotations/6967002/T6967002.out @@ -1,2 +1,2 @@ -T6967002.java:10:22: compiler.err.expected: ')' +T6967002.java:10:22: compiler.err.expected2: ')', ',' 1 error diff --git a/test/langtools/tools/javac/annotations/typeAnnotations/classfile/AnnotatedExtendsTest.java b/test/langtools/tools/javac/annotations/typeAnnotations/classfile/AnnotatedExtendsTest.java index 5705219aded0d6349fc1b74a672b2bc9cdadd4f2..3c785debf42cd5d891dd33dd6495b964d6abc33d 100644 --- a/test/langtools/tools/javac/annotations/typeAnnotations/classfile/AnnotatedExtendsTest.java +++ b/test/langtools/tools/javac/annotations/typeAnnotations/classfile/AnnotatedExtendsTest.java @@ -59,7 +59,7 @@ public class AnnotatedExtendsTest { .classes(classPath.toString()) .run() .getOutput(Task.OutputKind.DIRECT); - if (!javapOut.contains("0: #22(): CLASS_EXTENDS, type_index=65535")) + if (!javapOut.contains("0: #20(): CLASS_EXTENDS, type_index=65535")) throw new AssertionError("Expected output missing: " + javapOut); } -} \ No newline at end of file +} diff --git a/test/langtools/tools/javac/annotations/typeAnnotations/classfile/AnonymousExtendsTest.java b/test/langtools/tools/javac/annotations/typeAnnotations/classfile/AnonymousExtendsTest.java index 063afbf43f3712b4e929b1b9d13b9444961ab648..0a99008c643429cd77764b820de6f6805e0ae9dc 100644 --- a/test/langtools/tools/javac/annotations/typeAnnotations/classfile/AnonymousExtendsTest.java +++ b/test/langtools/tools/javac/annotations/typeAnnotations/classfile/AnonymousExtendsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -23,7 +23,7 @@ /* * @test - * @bug 8146167 + * @bug 8146167 8281674 * @summary Anonymous type declarations drop supertype type parameter annotations * @run main AnonymousExtendsTest */ @@ -52,10 +52,10 @@ public class AnonymousExtendsTest { public void testIt() { checkAnnotations(TestClass.class.getAnnotatedSuperclass(), - "[@AnonymousExtendsTest$TA(1)],[@AnonymousExtendsTest$TA(2)]"); + "[@AnonymousExtendsTest.TA(1)],[@AnonymousExtendsTest.TA(2)]"); checkAnnotations(new @TA(3) ArrayList<@TA(4) List>() { }.getClass().getAnnotatedSuperclass(), - "[@AnonymousExtendsTest$TA(3)],[@AnonymousExtendsTest$TA(4)]"); + "[@AnonymousExtendsTest.TA(3)],[@AnonymousExtendsTest.TA(4)]"); } public void checkAnnotations(AnnotatedType type, String expected) { diff --git a/test/langtools/tools/javac/api/TestClientCodeWrapper.java b/test/langtools/tools/javac/api/TestClientCodeWrapper.java index c7f595a451285bba46a8b0f820d10cae22f6c2e0..7c96f29fe5bb91104bde3480457873629233afd7 100644 --- a/test/langtools/tools/javac/api/TestClientCodeWrapper.java +++ b/test/langtools/tools/javac/api/TestClientCodeWrapper.java @@ -62,7 +62,8 @@ public class TestClientCodeWrapper extends JavacTestingAbstractProcessor { defaultFileManager = fm; for (Method m: getMethodsExcept(JavaFileManager.class, - "close", "getJavaFileForInput", "getLocationForModule", "getServiceLoader", "contains")) { + "close", "getJavaFileForInput", "getLocationForModule", "getServiceLoader", + "contains", "getFileForOutput", "siblingFrom")) { test(m); } @@ -370,6 +371,12 @@ public class TestClientCodeWrapper extends JavacTestingAbstractProcessor { return wrap(super.getJavaFileForOutput(location, className, kind, sibling)); } + @Override + public JavaFileObject getJavaFileForOutputForOriginatingFiles(Location location, String className, Kind kind, FileObject... originatingFiles) throws IOException { + throwUserExceptionIfNeeded(fileManagerMethod, "getJavaFileForOutputForOriginatingFiles"); + return wrap(super.getJavaFileForOutputForOriginatingFiles(location, className, kind, originatingFiles)); + } + @Override public FileObject getFileForInput(Location location, String packageName, String relativeName) throws IOException { throwUserExceptionIfNeeded(fileManagerMethod, "getFileForInput"); @@ -382,6 +389,12 @@ public class TestClientCodeWrapper extends JavacTestingAbstractProcessor { return wrap(super.getFileForOutput(location, packageName, relativeName, sibling)); } + @Override + public FileObject getFileForOutputForOriginatingFiles(Location location, String packageName, String relativeName, FileObject... originatingFiles) throws IOException { + throwUserExceptionIfNeeded(fileManagerMethod, "getFileForOutputForOriginatingFiles"); + return wrap(super.getFileForOutputForOriginatingFiles(location, packageName, relativeName, originatingFiles)); + } + @Override public void flush() throws IOException { throwUserExceptionIfNeeded(fileManagerMethod, "flush"); diff --git a/test/langtools/tools/javac/api/TestGetSourceVersions.java b/test/langtools/tools/javac/api/TestGetSourceVersions.java index 9b0ddb9d6733c4eefa5d21b4e815d61d9a659a87..472c4fe97eda00f54ac642cf1199852fe9479fad 100644 --- a/test/langtools/tools/javac/api/TestGetSourceVersions.java +++ b/test/langtools/tools/javac/api/TestGetSourceVersions.java @@ -35,7 +35,7 @@ * @run main TestGetSourceVersions RELEASE_3 RELEASE_4 RELEASE_5 RELEASE_6 RELEASE_7 * RELEASE_8 RELEASE_9 RELEASE_10 RELEASE_11 RELEASE_12 * RELEASE_13 RELEASE_14 RELEASE_15 RELEASE_16 RELEASE_17 - * RELEASE_18 + * RELEASE_18 RELEASE_19 */ import java.util.EnumSet; diff --git a/test/langtools/tools/javac/api/snippets/TestJavaxToolsSnippets.java b/test/langtools/tools/javac/api/snippets/TestJavaxToolsSnippets.java new file mode 100644 index 0000000000000000000000000000000000000000..b9db273bea49a4679de1ef4219af9ac2dbee00b6 --- /dev/null +++ b/test/langtools/tools/javac/api/snippets/TestJavaxToolsSnippets.java @@ -0,0 +1,123 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8272944 + * @summary Use snippets in java.compiler documentation + * @library /tools/lib ../../lib + * @modules jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.main + * @build snippets.SnippetUtils toolbox.JavacTask toolbox.TestRunner toolbox.ToolBox + * @run main TestJavaxToolsSnippets + */ + +import java.io.File; +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Objects; + +import javax.lang.model.element.Element; +import javax.lang.model.element.TypeElement; +import javax.tools.DiagnosticCollector; +import javax.tools.JavaFileObject; + +import com.sun.source.doctree.SnippetTree; + +import snippets.SnippetUtils; +import toolbox.JavacTask; +import toolbox.Task; +import toolbox.TestRunner; +import toolbox.ToolBox; + +/** + * Tests the snippets in the {@code javax.tools} package, by compiling the + * external snippets and parsing the internal Java snippets. + */ +public class TestJavaxToolsSnippets extends TestRunner { + public static void main(String... args) throws Exception { + new TestJavaxToolsSnippets().runTests(m -> new Object[] { Path.of(m.getName()) }); + } + + SnippetUtils snippets = new SnippetUtils("java.compiler"); + ToolBox tb = new ToolBox(); + + TestJavaxToolsSnippets() { + super(System.err); + } + + @Test + public void testExternalSnippets(Path base) throws Exception { + Path snippetFilesDir = snippets.getSourceDir() + .resolve("java.compiler") // module + .resolve("share").resolve("classes") + .resolve("javax.tools".replace(".", File.separator)) // package + .resolve("snippet-files"); + new JavacTask(tb) + .files(tb.findJavaFiles(snippetFilesDir)) + .outdir(Files.createDirectories(base.resolve("classes"))) + .run(Task.Expect.SUCCESS) + .writeAll(); + out.println("Compilation succeeded"); + } + + @Test + public void testJavaCompilerSnippets(Path base) { + TypeElement te = snippets.getElements().getTypeElement("javax.tools.JavaCompiler"); + snippets.scan(te, this::handleSnippet); + } + + @Test + public void testJavaFileManagerSnippets(Path base) { + TypeElement te = snippets.getElements().getTypeElement("javax.tools.JavaFileManager"); + snippets.scan(te, this::handleSnippet); + } + + @Test + public void testStandardJavaFileManagerSnippets(Path base) { + TypeElement te = snippets.getElements().getTypeElement("javax.tools.StandardJavaFileManager"); + snippets.scan(te, this::handleSnippet); + } + + void handleSnippet(Element e, SnippetTree tree) { + String lang = snippets.getAttr(tree, "lang"); + if (Objects.equals(lang, "java")) { + String body = snippets.getBody(tree); + if (body != null) { + String id = snippets.getAttr(tree, "id"); + try { + out.println("parsing snippet " + e + ":" + id); + if (snippets.parse(body, out::println)) { + out.println("parsed snippet"); + } else { + error("parse failed"); + } + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } + } + } + } +} diff --git a/test/langtools/tools/javac/attr/AttrRecoveryTest.java b/test/langtools/tools/javac/attr/AttrRecoveryTest.java new file mode 100644 index 0000000000000000000000000000000000000000..b364cc28001a867c9effc9d1dd7cdc1b93baaa5f --- /dev/null +++ b/test/langtools/tools/javac/attr/AttrRecoveryTest.java @@ -0,0 +1,165 @@ +/* + * 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. + */ + +/** + * @test + * @bug 8273039 + * @summary Verify error recovery in Attr + * @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 + * @run main AttrRecoveryTest +*/ + +import com.sun.source.tree.AnnotationTree; +import com.sun.source.tree.CompilationUnitTree; +import com.sun.source.tree.ErroneousTree; +import com.sun.source.util.TaskEvent; +import com.sun.source.util.TaskListener; +import com.sun.source.util.TreePath; +import com.sun.source.util.TreePathScanner; +import com.sun.source.util.Trees; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; +import javax.lang.model.element.Element; + +import toolbox.TestRunner; +import toolbox.JavacTask; +import toolbox.Task; +import toolbox.ToolBox; + +public class AttrRecoveryTest extends TestRunner { + + ToolBox tb; + + public static void main(String... args) throws Exception { + new AttrRecoveryTest().runTests(); + } + + AttrRecoveryTest() { + super(System.err); + tb = new ToolBox(); + } + + public void runTests() throws Exception { + runTests(m -> new Object[] { Paths.get(m.getName()) }); + } + + @Test + public void testModifiers(Path base) throws Exception { + record TestCase(String name, String source, String expectedAnnotation, String... errors) {} + TestCase[] tests = new TestCase[] { + new TestCase("a", + """ + public class Test { + Object i () { return int strictfp @Deprecated = 0; } + } + """, + "java.lang.Deprecated", + "Test.java:2:30: compiler.err.dot.class.expected", + "Test.java:2:51: compiler.err.expected4: class, interface, enum, record", + "Test.java:2:26: compiler.err.unexpected.type: kindname.value, kindname.class", + "3 errors"), + new TestCase("b", + """ + public class Test { + Object i () { return int strictfp = 0; } + } + """, + null, + "Test.java:2:30: compiler.err.dot.class.expected", + "Test.java:2:39: compiler.err.expected4: class, interface, enum, record", + "Test.java:2:26: compiler.err.unexpected.type: kindname.value, kindname.class", + "3 errors") + }; + for (TestCase test : tests) { + Path current = base.resolve("" + test.name); + Path src = current.resolve("src"); + Path classes = current.resolve("classes"); + tb.writeJavaFiles(src, + test.source); + + Files.createDirectories(classes); + + var log = + new JavacTask(tb) + .options("-XDrawDiagnostics", + "-XDshould-stop.at=FLOW", + "-Xlint:-preview") + .outdir(classes) + .files(tb.findJavaFiles(src)) + .callback(t -> { + t.addTaskListener(new TaskListener() { + CompilationUnitTree parsed; + @Override + public void finished(TaskEvent e) { + switch (e.getKind()) { + case PARSE -> parsed = e.getCompilationUnit(); + case ANALYZE -> + checkAnnotationsValid(t, parsed, test.expectedAnnotation); + } + } + }); + }) + .run(Task.Expect.FAIL, 1) + .writeAll() + .getOutputLines(Task.OutputKind.DIRECT); + if (!List.of(test.errors).equals(log)) { + throw new AssertionError("Incorrect errors, expected: " + List.of(test.errors) + + ", actual: " + log); + } + } + } + + private void checkAnnotationsValid(com.sun.source.util.JavacTask task, + CompilationUnitTree cut, + String expected) { + boolean[] foundAnnotation = new boolean[1]; + Trees trees = Trees.instance(task); + + new TreePathScanner() { + @Override + public Void visitAnnotation(AnnotationTree node, Void p) { + TreePath typePath = new TreePath(getCurrentPath(), node.getAnnotationType()); + Element el = trees.getElement(typePath); + if (el == null || !el.equals(task.getElements().getTypeElement(expected))) { + throw new AssertionError(); + } + foundAnnotation[0] = true; + return super.visitAnnotation(node, p); + } + + @Override + public Void visitErroneous(ErroneousTree node, Void p) { + return scan(node.getErrorTrees(), p); + } + }.scan(cut, null); + if (foundAnnotation[0] ^ (expected != null)) { + throw new AssertionError(); + } + } +} diff --git a/test/langtools/tools/javac/classfiles/ClassVersionChecker.java b/test/langtools/tools/javac/classfiles/ClassVersionChecker.java index 4fcc73031966ac41bf6581899e7ee05410f68a90..4e586c32dcb5b61695a254a284eff0434bd03d33 100644 --- a/test/langtools/tools/javac/classfiles/ClassVersionChecker.java +++ b/test/langtools/tools/javac/classfiles/ClassVersionChecker.java @@ -53,7 +53,8 @@ public class ClassVersionChecker { FIFTEEN("15", 59), SIXTEEN("16", 60), SEVENTEEN("17", 61), - EIGHTEEN("18", 62); + EIGHTEEN("18", 62), + NINETEEN("19", 63); private Version(String release, int classFileVer) { this.release = release; diff --git a/test/langtools/tools/javac/classfiles/attributes/Synthetic/AccessToPrivateInnerClassConstructorsTest.java b/test/langtools/tools/javac/classfiles/attributes/Synthetic/AccessToPrivateInnerClassConstructorsTest.java index 5fba9044c19d69a5dd860e6bfbfff650d4eb294e..d7152de66ba015996314a2d1f4005c9edc776797 100644 --- a/test/langtools/tools/javac/classfiles/attributes/Synthetic/AccessToPrivateInnerClassConstructorsTest.java +++ b/test/langtools/tools/javac/classfiles/attributes/Synthetic/AccessToPrivateInnerClassConstructorsTest.java @@ -44,14 +44,11 @@ "(AccessToPrivateInnerClassConstructorsTest)", "(AccessToPrivateInnerClassConstructorsTest, " + "AccessToPrivateInnerClassConstructorsTest$1)"}, - expectedNumberOfSyntheticFields = 1, expectedNumberOfSyntheticMethods = 0) @ExpectedClass(className = "AccessToPrivateInnerClassConstructorsTest$1Local", - expectedMethods = {"(AccessToPrivateInnerClassConstructorsTest)"}, - expectedNumberOfSyntheticFields = 1) + expectedMethods = {"(AccessToPrivateInnerClassConstructorsTest)"}) @ExpectedClass(className = "AccessToPrivateInnerClassConstructorsTest$2Local", - expectedMethods = {"(AccessToPrivateInnerClassConstructorsTest)"}, - expectedNumberOfSyntheticFields = 1) + expectedMethods = {"(AccessToPrivateInnerClassConstructorsTest)"}) public class AccessToPrivateInnerClassConstructorsTest { public static void main(String... args) { diff --git a/test/langtools/tools/javac/classfiles/attributes/Synthetic/AccessToPrivateInnerClassMembersTest.java b/test/langtools/tools/javac/classfiles/attributes/Synthetic/AccessToPrivateInnerClassMembersTest.java index 79fdf5d7e61dc91869ce5305754ca7d7b08c159b..171a7a5627b038d2cb47200186ac2cf6ac844c29 100644 --- a/test/langtools/tools/javac/classfiles/attributes/Synthetic/AccessToPrivateInnerClassMembersTest.java +++ b/test/langtools/tools/javac/classfiles/attributes/Synthetic/AccessToPrivateInnerClassMembersTest.java @@ -43,15 +43,13 @@ * 3. access method for private method function(). * 4. getter/setter for private field staticVar. * 5. access method for private method staticFunction(). - * 6. field this in Inner1. - * 7. constructor for Inner*. + * 6. constructor for Inner*. */ @ExpectedClass(className = "AccessToPrivateInnerClassMembersTest", expectedMethods = {"()", "()"}) @ExpectedClass(className = "AccessToPrivateInnerClassMembersTest$Inner1", expectedMethods = {"(AccessToPrivateInnerClassMembersTest)", "function()"}, - expectedFields = "var", - expectedNumberOfSyntheticFields = 1) + expectedFields = "var") @ExpectedClass(className = "AccessToPrivateInnerClassMembersTest$Inner2", expectedMethods = {"function()", "staticFunction()", "()"}, expectedFields = {"staticVar", "var"}) diff --git a/test/langtools/tools/javac/classfiles/attributes/Synthetic/AccessToPrivateSiblingsTest.java b/test/langtools/tools/javac/classfiles/attributes/Synthetic/AccessToPrivateSiblingsTest.java index 47269cf8776241508ee5388d105f9c73cb4e71e7..c0e039f83443e6fa14597667db497ad75b990174 100644 --- a/test/langtools/tools/javac/classfiles/attributes/Synthetic/AccessToPrivateSiblingsTest.java +++ b/test/langtools/tools/javac/classfiles/attributes/Synthetic/AccessToPrivateSiblingsTest.java @@ -43,14 +43,12 @@ * 3. access method for private method function(). * 4. getter/setter for private field staticVar. * 5. access method for private method staticFunction(). - * 6. field this in Inner1. - * 7. constructor for Inner*. + * 6. constructor for Inner*. */ @ExpectedClass(className = "AccessToPrivateSiblingsTest", expectedMethods = "()") @ExpectedClass(className = "AccessToPrivateSiblingsTest$Inner1", expectedMethods = {"function()", "(AccessToPrivateSiblingsTest)"}, - expectedFields = "var", - expectedNumberOfSyntheticFields = 1) + expectedFields = "var") @ExpectedClass(className = "AccessToPrivateSiblingsTest$Inner2", expectedMethods = "(AccessToPrivateSiblingsTest)", expectedNumberOfSyntheticFields = 1) diff --git a/test/langtools/tools/javac/classfiles/attributes/Synthetic/BridgeMethodsForLambdaTest.java b/test/langtools/tools/javac/classfiles/attributes/Synthetic/BridgeMethodsForLambdaTest.java index 90d0659d2b3a0c64f1dd2cbc0588d7e93918f8fa..51d9f324e06cbd908e1179e8d794623cc4150d77 100644 --- a/test/langtools/tools/javac/classfiles/attributes/Synthetic/BridgeMethodsForLambdaTest.java +++ b/test/langtools/tools/javac/classfiles/attributes/Synthetic/BridgeMethodsForLambdaTest.java @@ -55,19 +55,16 @@ import java.util.stream.IntStream; @ExpectedClass(className = "BridgeMethodsForLambdaTest$Inner1", expectedMethods = {"(BridgeMethodsForLambdaTest)", "function()", "run()"}, expectedFields = "lambda1", - expectedNumberOfSyntheticMethods = 1, - expectedNumberOfSyntheticFields = 1) + expectedNumberOfSyntheticMethods = 1) @ExpectedClass(className = "BridgeMethodsForLambdaTest$Inner2", expectedMethods = {"()", "staticFunction()"}, expectedFields = "lambda1", expectedNumberOfSyntheticMethods = 1) @ExpectedClass(className = "BridgeMethodsForLambdaTest$Inner3", - expectedMethods = {"(BridgeMethodsForLambdaTest)", "function()"}, - expectedNumberOfSyntheticFields = 1) + expectedMethods = {"(BridgeMethodsForLambdaTest)", "function()"}) @ExpectedClass(className = "BridgeMethodsForLambdaTest$Inner4", expectedMethods = {"(BridgeMethodsForLambdaTest)", "function()"}, - expectedNumberOfSyntheticMethods = 1, - expectedNumberOfSyntheticFields = 1) + expectedNumberOfSyntheticMethods = 1) public class BridgeMethodsForLambdaTest { private class Inner1 implements Runnable { diff --git a/test/langtools/tools/javac/classfiles/attributes/Synthetic/ThisFieldTest.java b/test/langtools/tools/javac/classfiles/attributes/Synthetic/ThisFieldTest.java index 605fb0cc6ded206c89ed3704399b9a7b0b3bc1a8..3ca6e65ef9004538d441a703740e20a0c964f6e6 100644 --- a/test/langtools/tools/javac/classfiles/attributes/Synthetic/ThisFieldTest.java +++ b/test/langtools/tools/javac/classfiles/attributes/Synthetic/ThisFieldTest.java @@ -34,6 +34,8 @@ * @run main SyntheticTestDriver ThisFieldTest */ +import java.util.Objects; + /** * Synthetic members: * 1. fields this$0 for local and anonymous classes. @@ -49,9 +51,17 @@ public class ThisFieldTest { { class Local { + { + // access enclosing instance so this$0 field is generated + Objects.requireNonNull(ThisFieldTest.this); + } } new Local() { + { + // access enclosing instance so this$0 field is generated + Objects.requireNonNull(ThisFieldTest.this); + } }; } } diff --git a/test/langtools/tools/javac/classfiles/attributes/lib/TestResult.java b/test/langtools/tools/javac/classfiles/attributes/lib/TestResult.java index 39b727cecea849f142ee8e98ff86ed49d56ac2d9..4c9662f110ff22a7c544f805f4f617c9915ef794 100644 --- a/test/langtools/tools/javac/classfiles/attributes/lib/TestResult.java +++ b/test/langtools/tools/javac/classfiles/attributes/lib/TestResult.java @@ -26,7 +26,7 @@ import java.io.StringWriter; import java.util.*; /** - * This class accumulates test results. Test results can be checked with method @{code checkStatus}. + * This class accumulates test results. Test results can be checked with method {@code checkStatus}. */ public class TestResult extends TestBase { diff --git a/test/langtools/tools/javac/classwriter/IndyCorrectInvocationName.java b/test/langtools/tools/javac/classwriter/IndyCorrectInvocationName.java new file mode 100644 index 0000000000000000000000000000000000000000..36d7b8c2759852adb93c533a56bf15ed3a491fba --- /dev/null +++ b/test/langtools/tools/javac/classwriter/IndyCorrectInvocationName.java @@ -0,0 +1,271 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8277634 + * @summary Verify the correct constantpool entries are created for invokedynamic instructions using + * the same bootstrap and type, but different name. + * @library /tools/lib + * @modules jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.code + * jdk.compiler/com.sun.tools.javac.comp + * jdk.compiler/com.sun.tools.javac.jvm + * jdk.compiler/com.sun.tools.javac.main + * jdk.compiler/com.sun.tools.javac.tree + * jdk.compiler/com.sun.tools.javac.util + * jdk.jdeps/com.sun.tools.classfile + * jdk.jdeps/com.sun.tools.javap + * @build toolbox.JarTask toolbox.JavacTask toolbox.JavapTask toolbox.ToolBox + * @run main IndyCorrectInvocationName + */ + +import java.net.URL; +import java.net.URLClassLoader; +import java.nio.file.DirectoryStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; + +import com.sun.source.util.JavacTask; +import com.sun.source.util.Plugin; +import com.sun.source.util.TaskEvent; +import com.sun.source.util.TaskListener; + +import com.sun.tools.classfile.Attribute; +import com.sun.tools.classfile.BootstrapMethods_attribute; +import com.sun.tools.classfile.ClassFile; +import com.sun.tools.classfile.Code_attribute; +import com.sun.tools.classfile.ConstantPool.CONSTANT_InvokeDynamic_info; +import com.sun.tools.classfile.ConstantPool.CONSTANT_NameAndType_info; +import com.sun.tools.classfile.Instruction; + +import com.sun.tools.javac.api.BasicJavacTask; +import com.sun.tools.javac.code.Symbol; +import com.sun.tools.javac.code.Symbol.MethodSymbol; +import com.sun.tools.javac.code.Symtab; +import com.sun.tools.javac.code.Type; +import com.sun.tools.javac.jvm.PoolConstant; +import com.sun.tools.javac.tree.JCTree; +import com.sun.tools.javac.tree.JCTree.JCClassDecl; +import com.sun.tools.javac.tree.JCTree.JCCompilationUnit; +import com.sun.tools.javac.tree.JCTree.JCLiteral; +import com.sun.tools.javac.tree.JCTree.JCMethodInvocation; +import com.sun.tools.javac.tree.JCTree.Tag; +import com.sun.tools.javac.tree.TreeMaker; +import com.sun.tools.javac.tree.TreeScanner; +import com.sun.tools.javac.util.Context; +import com.sun.tools.javac.util.Names; + +import toolbox.JarTask; +import toolbox.ToolBox; + + +public class IndyCorrectInvocationName implements Plugin { + private static final String NL = System.lineSeparator(); + + public static void main(String... args) throws Exception { + new IndyCorrectInvocationName().run(); + } + + void run() throws Exception { + ToolBox tb = new ToolBox(); + Path pluginClasses = Path.of("plugin-classes"); + tb.writeFile(pluginClasses.resolve("META-INF").resolve("services").resolve(Plugin.class.getName()), + IndyCorrectInvocationName.class.getName() + System.lineSeparator()); + try (DirectoryStream ds = Files.newDirectoryStream(Path.of(ToolBox.testClasses))) { + for (Path p : ds) { + if (p.getFileName().toString().startsWith("IndyCorrectInvocationName") || + p.getFileName().toString().endsWith(".class")) { + Files.copy(p, pluginClasses.resolve(p.getFileName())); + } + } + } + + Path pluginJar = Path.of("plugin.jar"); + new JarTask(tb, pluginJar) + .baseDir(pluginClasses) + .files(".") + .run(); + + Path src = Path.of("src"); + tb.writeJavaFiles(src, + """ + import java.lang.invoke.CallSite; + import java.lang.invoke.ConstantCallSite; + import java.lang.invoke.MethodHandles; + import java.lang.invoke.MethodHandles.Lookup; + import java.lang.invoke.MethodType; + public class Test{ + private static final String NL = System.lineSeparator(); + private static StringBuilder output = new StringBuilder(); + public static void doRun() { + method("a"); + method("b"); + method("a"); + method("b"); + } + public static String run() { + doRun(); + return output.toString(); + } + public static void method(String name) {} + public static void actualMethod(String name) { + output.append(name).append(NL); + } + public static CallSite bootstrap(Lookup lookup, String name, MethodType type) throws Exception { + return new ConstantCallSite(MethodHandles.lookup() + .findStatic(Test.class, + "actualMethod", + MethodType.methodType(void.class, + String.class)) + .bindTo(name)); + } + } + """); + Path classes = Files.createDirectories(Path.of("classes")); + + new toolbox.JavacTask(tb) + .classpath(pluginJar) + .options("-XDaccessInternalAPI") + .outdir(classes) + .files(tb.findJavaFiles(src)) + .run() + .writeAll(); + + URLClassLoader cl = new URLClassLoader(new URL[] {classes.toUri().toURL()}); + + String actual = (String) cl.loadClass("Test") + .getMethod("run") + .invoke(null); + String expected = "a" + NL + "b" + NL + "a" + NL +"b" + NL; + if (!Objects.equals(actual, expected)) { + throw new AssertionError("expected: " + expected + "; but got: " + actual); + } + + Path testClass = classes.resolve("Test.class"); + ClassFile cf = ClassFile.read(testClass); + BootstrapMethods_attribute bootAttr = + (BootstrapMethods_attribute) cf.attributes.get(Attribute.BootstrapMethods); + if (bootAttr.bootstrap_method_specifiers.length != 1) { + throw new AssertionError("Incorrect number of bootstrap methods: " + + bootAttr.bootstrap_method_specifiers.length); + } + Code_attribute codeAttr = + (Code_attribute) cf.methods[1].attributes.get(Attribute.Code); + Set seenBootstraps = new HashSet<>(); + Set seenNameAndTypes = new HashSet<>(); + Set seenNames = new HashSet<>(); + for (Instruction i : codeAttr.getInstructions()) { + switch (i.getOpcode()) { + case INVOKEDYNAMIC -> { + int idx = i.getUnsignedShort(1); + CONSTANT_InvokeDynamic_info dynamicInfo = + (CONSTANT_InvokeDynamic_info) cf.constant_pool.get(idx); + seenBootstraps.add(dynamicInfo.bootstrap_method_attr_index); + seenNameAndTypes.add(dynamicInfo.name_and_type_index); + CONSTANT_NameAndType_info nameAndTypeInfo = + cf.constant_pool.getNameAndTypeInfo(dynamicInfo.name_and_type_index); + seenNames.add(nameAndTypeInfo.getName()); + } + case RETURN -> {} + default -> throw new AssertionError("Unexpected instruction: " + i.getOpcode()); + } + } + if (seenBootstraps.size() != 1) { + throw new AssertionError("Unexpected bootstraps: " + seenBootstraps); + } + if (seenNameAndTypes.size() != 2) { + throw new AssertionError("Unexpected names and types: " + seenNameAndTypes); + } + if (!seenNames.equals(Set.of("a", "b"))) { + throw new AssertionError("Unexpected names and types: " + seenNames); + } + } + + // Plugin impl... + + @Override + public String getName() { return "IndyCorrectInvocationName"; } + + @Override + public void init(JavacTask task, String... args) { + Context c = ((BasicJavacTask) task).getContext(); + task.addTaskListener(new TaskListener() { + @Override + public void started(TaskEvent e) { + if (e.getKind() == TaskEvent.Kind.GENERATE) { + convert(c, (JCCompilationUnit) e.getCompilationUnit()); + } + } + }); + } + + @Override + public boolean autoStart() { + return true; + } + + private void convert(Context context, JCCompilationUnit toplevel) { + TreeMaker make = TreeMaker.instance(context); + Names names = Names.instance(context); + Symtab syms = Symtab.instance(context); + new TreeScanner() { + MethodSymbol bootstrap; + @Override + public void visitClassDef(JCClassDecl tree) { + bootstrap = (MethodSymbol) tree.sym.members().getSymbolsByName(names.fromString("bootstrap")).iterator().next(); + super.visitClassDef(tree); + } + @Override + public void visitApply(JCMethodInvocation tree) { + if (tree.args.size() == 1 && tree.args.head.hasTag(Tag.LITERAL)) { + String name = (String) ((JCLiteral) tree.args.head).value; + Type.MethodType indyType = new Type.MethodType( + com.sun.tools.javac.util.List.nil(), + syms.voidType, + com.sun.tools.javac.util.List.nil(), + syms.methodClass + ); + Symbol.DynamicMethodSymbol dynSym = new Symbol.DynamicMethodSymbol(names.fromString(name), + syms.noSymbol, + bootstrap.asHandle(), + indyType, + new PoolConstant.LoadableConstant[0]); + + JCTree.JCFieldAccess qualifier = make.Select(make.QualIdent(bootstrap.owner), dynSym.name); + qualifier.sym = dynSym; + qualifier.type = syms.voidType; + tree.meth = qualifier; + tree.args = com.sun.tools.javac.util.List.nil(); + tree.type = syms.voidType; + } + super.visitApply(tree); + } + + }.scan(toplevel); + } + +} diff --git a/test/langtools/tools/javac/code/CharImmediateValue.java b/test/langtools/tools/javac/code/CharImmediateValue.java new file mode 100644 index 0000000000000000000000000000000000000000..38745358be040041300d3d4fdbe8286623227b2e --- /dev/null +++ b/test/langtools/tools/javac/code/CharImmediateValue.java @@ -0,0 +1,185 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8280067 + * @summary Verify constant/immediate char values are correctly enhanced to ints when used in unary + * operators + * @library /tools/lib + * @modules jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.code + * jdk.compiler/com.sun.tools.javac.comp + * jdk.compiler/com.sun.tools.javac.jvm + * jdk.compiler/com.sun.tools.javac.main + * jdk.compiler/com.sun.tools.javac.tree + * jdk.compiler/com.sun.tools.javac.util + * jdk.jdeps/com.sun.tools.classfile + * jdk.jdeps/com.sun.tools.javap + * @build toolbox.JarTask toolbox.JavacTask toolbox.JavapTask toolbox.ToolBox + * @compile CharImmediateValue.java + * @run main CharImmediateValue + */ + +import java.net.URL; +import java.net.URLClassLoader; +import java.nio.file.DirectoryStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Objects; + +import com.sun.source.util.JavacTask; +import com.sun.source.util.Plugin; +import com.sun.source.util.TaskEvent; +import com.sun.source.util.TaskListener; + +import com.sun.tools.classfile.Attribute; +import com.sun.tools.classfile.ClassFile; +import com.sun.tools.classfile.Code_attribute; +import com.sun.tools.classfile.Instruction; +import com.sun.tools.classfile.Opcode; + +import com.sun.tools.javac.tree.JCTree.JCCompilationUnit; +import com.sun.tools.javac.tree.JCTree.JCIdent; +import com.sun.tools.javac.tree.TreeScanner; + +import toolbox.JarTask; +import toolbox.ToolBox; + + +public class CharImmediateValue implements Plugin { + public static void main(String... args) throws Exception { + new CharImmediateValue().runSourceTest(); + new CharImmediateValue().runReplacementTest(); + } + + void runSourceTest() throws Exception { + int param = 0; + Character var = (char) -(false ? (char) param : (char) 2); + } + + void runReplacementTest() throws Exception { + ToolBox tb = new ToolBox(); + Path pluginClasses = Path.of("plugin-classes"); + tb.writeFile(pluginClasses.resolve("META-INF").resolve("services").resolve(Plugin.class.getName()), + CharImmediateValue.class.getName() + System.lineSeparator()); + try (DirectoryStream ds = Files.newDirectoryStream(Path.of(ToolBox.testClasses))) { + for (Path p : ds) { + if (p.getFileName().toString().startsWith("CharImmediateValue") || + p.getFileName().toString().endsWith(".class")) { + Files.copy(p, pluginClasses.resolve(p.getFileName())); + } + } + } + + Path pluginJar = Path.of("plugin.jar"); + new JarTask(tb, pluginJar) + .baseDir(pluginClasses) + .files(".") + .run(); + + Path src = Path.of("src"); + tb.writeJavaFiles(src, + """ + public class Test{ + private static char replace; //this will be replace with a constant "1" after constant folding is done + public static String run() { + char c = (char) - replace; + if (c < 0) { + throw new AssertionError("Incorrect value!"); + } else { + return Integer.toString(c); + } + } + } + """); + Path classes = Files.createDirectories(Path.of("classes")); + + new toolbox.JavacTask(tb) + .classpath(pluginJar) + .options("-XDaccessInternalAPI") + .outdir(classes) + .files(tb.findJavaFiles(src)) + .run() + .writeAll(); + + URLClassLoader cl = new URLClassLoader(new URL[] {classes.toUri().toURL()}); + + String actual = (String) cl.loadClass("Test") + .getMethod("run") + .invoke(null); + String expected = "65535"; + if (!Objects.equals(actual, expected)) { + throw new AssertionError("expected: " + expected + "; but got: " + actual); + } + + Path testClass = classes.resolve("Test.class"); + ClassFile cf = ClassFile.read(testClass); + Code_attribute codeAttr = + (Code_attribute) cf.methods[1].attributes.get(Attribute.Code); + boolean seenCast = false; + for (Instruction i : codeAttr.getInstructions()) { + if (i.getOpcode() == Opcode.I2C) { + seenCast = true; + } + } + if (!seenCast) { + throw new AssertionError("Missing cast!"); + } + } + + // Plugin impl... + + @Override + public String getName() { return "CharImmediateValue"; } + + @Override + public void init(JavacTask task, String... args) { + task.addTaskListener(new TaskListener() { + @Override + public void started(TaskEvent e) { + if (e.getKind() == TaskEvent.Kind.GENERATE) { + convert((JCCompilationUnit) e.getCompilationUnit()); + } + } + }); + } + + @Override + public boolean autoStart() { + return true; + } + + private void convert(JCCompilationUnit toplevel) { + new TreeScanner() { + @Override + public void visitIdent(JCIdent tree) { + if (tree.name.contentEquals("replace")) { + tree.type = tree.type.constType(1); + } + super.visitIdent(tree); + } + }.scan(toplevel); + } + +} diff --git a/test/langtools/tools/javac/diags/examples.not-yet.txt b/test/langtools/tools/javac/diags/examples.not-yet.txt index f257b7df8e09d4ae187c5ed7a14c7f1a32dd3cd2..9f9f8f780144708d7f61108f4708b10c79cd457e 100644 --- a/test/langtools/tools/javac/diags/examples.not-yet.txt +++ b/test/langtools/tools/javac/diags/examples.not-yet.txt @@ -206,3 +206,4 @@ compiler.warn.source.target.conflict compiler.warn.target.default.source.conflict compiler.err.preview.not.latest compiler.err.preview.without.source.or.release +compiler.misc.illegal.signature # the compiler can now detect more non-denotable types before class writing diff --git a/test/langtools/tools/javac/diags/examples/AnnotationMissingElementValue.java b/test/langtools/tools/javac/diags/examples/AnnotationMissingElementValue.java new file mode 100644 index 0000000000000000000000000000000000000000..65f24aad3167d04053f306700151019955e1092c --- /dev/null +++ b/test/langtools/tools/javac/diags/examples/AnnotationMissingElementValue.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +// key: compiler.err.annotation.missing.element.value + +@SuppressWarnings({,0}) +public class AV { +} diff --git a/test/langtools/tools/javac/diags/examples/ErrSyntheticNameConflict.java b/test/langtools/tools/javac/diags/examples/ErrSyntheticNameConflict.java index 45d523dc08a676bf3292a97e75f4d67f143a43fc..d4b3ead499bbfd3515a0e6919c4b1c1136661913 100644 --- a/test/langtools/tools/javac/diags/examples/ErrSyntheticNameConflict.java +++ b/test/langtools/tools/javac/diags/examples/ErrSyntheticNameConflict.java @@ -24,11 +24,18 @@ // key: compiler.err.cannot.generate.class // key: compiler.misc.synthetic.name.conflict +import java.util.Objects; + class ErrSyntheticNameConflict { static class Outer { ErrSyntheticNameConflict this$0 = null; } - public class Inner extends Outer { } + public class Inner extends Outer { + { + // access enclosing instance so this$0 field is generated + Objects.requireNonNull(ErrSyntheticNameConflict.this); + } + } } diff --git a/test/langtools/tools/javac/diags/examples/IllegalSignature.java b/test/langtools/tools/javac/diags/examples/IllegalSignature.java index a9b64b41afa68242acccb45f0aabcd9535f8c88e..96b93b6bdabbdef78199f279fe755c3b934137fb 100644 --- a/test/langtools/tools/javac/diags/examples/IllegalSignature.java +++ b/test/langtools/tools/javac/diags/examples/IllegalSignature.java @@ -21,8 +21,7 @@ * questions. */ -// key: compiler.err.cannot.generate.class -// key: compiler.misc.illegal.signature +// key: compiler.err.enclosing.class.type.non.denotable class IllegalSignature { class Inner { } diff --git a/test/langtools/tools/javac/diags/examples/LambdaDeduplicate.java b/test/langtools/tools/javac/diags/examples/LambdaDeduplicate.java index 8dda7bb2dd9d93e28a5d89211d977db891cbb979..cf39f9ffb758c2e01e5c596bfde12a1bd6943717 100644 --- a/test/langtools/tools/javac/diags/examples/LambdaDeduplicate.java +++ b/test/langtools/tools/javac/diags/examples/LambdaDeduplicate.java @@ -23,7 +23,7 @@ // key: compiler.note.verbose.l2m.deduplicate -// options: --debug=dumpLambdaToMethodDeduplication +// options: -g:none --debug=dumpLambdaToMethodDeduplication import java.util.function.Function; diff --git a/test/langtools/tools/javac/diags/examples/NoJavaLang.java b/test/langtools/tools/javac/diags/examples/NoJavaLang.java index 330243dbc960115331304966a6b5eafea739cc78..7329bbc02b6d4036260ef7a3fa69900ecbf0c12c 100644 --- a/test/langtools/tools/javac/diags/examples/NoJavaLang.java +++ b/test/langtools/tools/javac/diags/examples/NoJavaLang.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 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 @@ -21,7 +21,9 @@ * questions. */ -// key: compiler.misc.fatal.err.no.java.lang +// key: compiler.err.error +// key: compiler.err.no.java.lang +// key: compiler.misc.count.error // options: -source 8 -target 8 -Xbootclasspath: -classpath . // run: backdoor diff --git a/test/langtools/tools/javac/doctree/ReferenceTest.java b/test/langtools/tools/javac/doctree/ReferenceTest.java index 128d3e158b11f1ea90a2f528b83bdf933cd44ae2..eb635650b7678cc3c2a96d3a7beaae4e3c00d91b 100644 --- a/test/langtools/tools/javac/doctree/ReferenceTest.java +++ b/test/langtools/tools/javac/doctree/ReferenceTest.java @@ -23,7 +23,7 @@ /* * @test - * @bug 7021614 + * @bug 7021614 8278373 * @summary extend com.sun.source API to support parsing javadoc comments * @summary check references in at-see and {at-link} tags * @modules jdk.compiler @@ -39,19 +39,23 @@ import com.sun.source.doctree.SeeTree; import com.sun.source.doctree.TextTree; import com.sun.source.util.DocTreePath; import com.sun.source.util.DocTreePathScanner; -import com.sun.source.util.DocTreeScanner; import com.sun.source.util.DocTrees; import com.sun.source.util.TreePath; import java.util.List; import java.util.Set; +import java.util.stream.Collectors; import javax.annotation.processing.AbstractProcessor; import javax.annotation.processing.ProcessingEnvironment; import javax.annotation.processing.RoundEnvironment; import javax.annotation.processing.SupportedAnnotationTypes; import javax.lang.model.SourceVersion; import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.QualifiedNameable; import javax.lang.model.element.TypeElement; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.TypeMirror; import javax.tools.Diagnostic.Kind; /** @@ -174,8 +178,18 @@ public class ReferenceTest extends AbstractProcessor { if (label.size() > 0 && label.get(0) instanceof TextTree) expect = ((TextTree) label.get(0)).getBody(); - if (!expect.equalsIgnoreCase(found == null ? "bad" : found.getKind().name())) { - error(tree, "Unexpected value found: " + found +", expected: " + expect); + if (expect.startsWith("signature:")) { + expect = expect.substring("signature:".length()); + + String signature = found.getKind().name() + ":" + elementSignature(found); + + if (!expect.equalsIgnoreCase(signature)) { + error(tree, "Unexpected value found: " + signature +", expected: " + expect); + } + } else { + if (!expect.equalsIgnoreCase(found == null ? "bad" : found.getKind().name())) { + error(tree, "Unexpected value found: " + found +", expected: " + expect); + } } } @@ -183,6 +197,29 @@ public class ReferenceTest extends AbstractProcessor { trees.printMessage(Kind.ERROR, msg, tree, dc, path.getCompilationUnit()); } } + + String elementSignature(Element el) { + return switch (el.getKind()) { + case METHOD -> elementSignature(el.getEnclosingElement()) + "." + el.getSimpleName() + "(" + executableParamNames((ExecutableElement) el) + ")"; + case CLASS, INTERFACE -> ((QualifiedNameable) el).getQualifiedName().toString(); + default -> throw new AssertionError("Unhandled Element kind: " + el.getKind()); + }; + } + + String executableParamNames(ExecutableElement ee) { + return ee.getParameters() + .stream() + .map(p -> type2Name(p.asType())) + .collect(Collectors.joining(", ")); + } + + String type2Name(TypeMirror type) { + return switch (type.getKind()) { + case DECLARED -> elementSignature(((DeclaredType) type).asElement()); + case INT, LONG -> type.toString(); + default -> throw new AssertionError("Unhandled type kind: " + type.getKind()); + }; + } } /** @@ -199,6 +236,17 @@ public class ReferenceTest extends AbstractProcessor { * @see #varargs(int... args) Method * @see #varargs(int[]) Method * @see #varargs(int[] args) Method + * + * @see #methodSearch(String) signature:METHOD:ReferenceTestExtras.methodSearch(java.lang.String) + * @see #methodSearch(StringBuilder) signature:METHOD:ReferenceTestExtras.methodSearch(java.lang.CharSequence) + * @see #methodSearchPrimitive1(int, int) signature:METHOD:ReferenceTestExtras.methodSearchPrimitive1(int, int) + * @see #methodSearchPrimitive1(long, int) signature:METHOD:ReferenceTestExtras.methodSearchPrimitive1(long, int) + * @see #methodSearchPrimitive1(int, long) signature:METHOD:ReferenceTestExtras.methodSearchPrimitive1(int, long) + * @see #methodSearchPrimitive1(long, long) signature:METHOD:ReferenceTestExtras.methodSearchPrimitive1(long, long) + * @see #methodSearchPrimitive2(int, int) signature:METHOD:ReferenceTestExtras.methodSearchPrimitive2(int, int) + * @see #methodSearchPrimitive2(long, int) signature:METHOD:ReferenceTestExtras.methodSearchPrimitive2(long, int) + * @see #methodSearchPrimitive2(int, long) signature:METHOD:ReferenceTestExtras.methodSearchPrimitive2(int, long) + * @see #methodSearchPrimitive2(long, long) signature:METHOD:ReferenceTestExtras.methodSearchPrimitive2(long, long) */ class ReferenceTestExtras { int ReferenceTestExtras; // field @@ -214,6 +262,20 @@ class ReferenceTestExtras { void m(int i, int j) { } void varargs(int... args) { } + + void methodSearch(Object o) {} + void methodSearch(String s) {} + void methodSearch(CharSequence cs) {} + + void methodSearchPrimitive1(int i, int j) {} + void methodSearchPrimitive1(long i, int j) {} + void methodSearchPrimitive1(int i, long j) {} + void methodSearchPrimitive1(long i, long j) {} + + void methodSearchPrimitive2(long i, long j) {} + void methodSearchPrimitive2(int i, long j) {} + void methodSearchPrimitive2(long i, int j) {} + void methodSearchPrimitive2(int i, int j) {} } diff --git a/test/langtools/tools/javac/enum/EnumMembersOrder.out b/test/langtools/tools/javac/enum/EnumMembersOrder.out index b1e01860f3469d908676f72f2da0528ab2f63adb..94aff47aca8eeffb2bc33165c91273bc20c7965d 100644 --- a/test/langtools/tools/javac/enum/EnumMembersOrder.out +++ b/test/langtools/tools/javac/enum/EnumMembersOrder.out @@ -1,4 +1,4 @@ -EnumMembersOrder.java:11:16: compiler.err.expected: ')' +EnumMembersOrder.java:11:16: compiler.err.expected2: ')', ',' EnumMembersOrder.java:11:18: compiler.err.expected3: ',', '}', ';' EnumMembersOrder.java:11:20: compiler.err.enum.constant.expected 3 errors diff --git a/test/langtools/tools/javac/fatalErrors/NoJavaLangTest.java b/test/langtools/tools/javac/fatalErrors/NoJavaLangTest.java index b200c4c07193c97b485277937934b5bda6c83b26..ea39a0231f0a245624ed38b7dee852d3845fb4c4 100644 --- a/test/langtools/tools/javac/fatalErrors/NoJavaLangTest.java +++ b/test/langtools/tools/javac/fatalErrors/NoJavaLangTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -23,7 +23,7 @@ /* * @test - * @bug 4263768 4785453 + * @bug 4263768 4785453 8205187 * @summary Verify that the compiler does not crash when java.lang is not available * @library /tools/lib * @modules jdk.compiler/com.sun.tools.javac.api @@ -38,7 +38,7 @@ import toolbox.JavacTask; import toolbox.Task; import toolbox.ToolBox; -public class NoJavaLangTest { +public class NoJavaLangTest { private static final String noJavaLangSrc = "public class NoJavaLang {\n" + @@ -50,7 +50,7 @@ public class NoJavaLangTest { "}"; private static final String compilerErrorMessage = - "Fatal Error: Unable to find package java.lang in classpath or bootclasspath"; + "error: Unable to find package java.lang in platform classes"; public static void main(String[] args) throws Exception { new NoJavaLangTest().run(); @@ -90,7 +90,6 @@ public class NoJavaLangTest { Files.delete(Paths.get("modules", "java.base", "java", "lang", "Object.class")); - // ideally we'd have a better message for this case String[] mpOpts = { "--system", "none", "--module-path", "modules" }; test(mpOpts, compilerErrorMessage); } @@ -101,15 +100,13 @@ public class NoJavaLangTest { String out = new JavacTask(tb) .options(options) .sources(noJavaLangSrc) - .run(Task.Expect.FAIL, 3) + .run(Task.Expect.FAIL, 1) .writeAll() .getOutput(Task.OutputKind.DIRECT); - if (!out.trim().equals(expect)) { + if (!out.trim().startsWith(expect)) { throw new AssertionError("javac generated error output is not correct"); } - - System.err.println("OK"); } } diff --git a/test/langtools/tools/javac/generics/diamond/neg/Neg21.out b/test/langtools/tools/javac/generics/diamond/neg/Neg21.out index 35e1a94cc156e4fc83d5edc891ec9a476feecd59..d273f7ae713005ae9ba64a74c19832be76a81759 100644 --- a/test/langtools/tools/javac/generics/diamond/neg/Neg21.out +++ b/test/langtools/tools/javac/generics/diamond/neg/Neg21.out @@ -1,2 +1,3 @@ +Neg21.java:13:9: compiler.err.enclosing.class.type.non.denotable: Neg21 Neg21.java:13:28: compiler.err.cant.apply.diamond.1: (compiler.misc.diamond: Neg21.A), (compiler.misc.diamond.invalid.arg: java.lang.Object&java.io.Serializable&java.lang.Cloneable, (compiler.misc.diamond: Neg21.A)) -1 error +2 errors diff --git a/test/langtools/tools/javac/generics/inference/4954546/T4954546.java b/test/langtools/tools/javac/generics/inference/4954546/T4954546.java index 7ce1dcb5a3a7e9e0fd4d49f8d00b09f08c50cb33..456624b8333a879133c52b1838da227542068e7d 100644 --- a/test/langtools/tools/javac/generics/inference/4954546/T4954546.java +++ b/test/langtools/tools/javac/generics/inference/4954546/T4954546.java @@ -46,7 +46,7 @@ public class T4954546 { f(true, new A(), new B()); } static void f(boolean cond, A a, B b) { - (cond?a:b).f();; - (cond?a:b).g();; + (cond?a:b).f(); + (cond?a:b).g(); } } diff --git a/test/langtools/tools/javac/lambda/CantFindSymbolImplicitLambdaAndDiamondTest.java b/test/langtools/tools/javac/lambda/CantFindSymbolImplicitLambdaAndDiamondTest.java new file mode 100644 index 0000000000000000000000000000000000000000..a053d7f27ab76beb250e4ed2dd1c4a15fb46c631 --- /dev/null +++ b/test/langtools/tools/javac/lambda/CantFindSymbolImplicitLambdaAndDiamondTest.java @@ -0,0 +1,54 @@ +/* + * 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. + */ + +/* + * @test + * @summary symbol not found error, implicit lambdas and diamond constructor invocations + * @compile CantFindSymbolImplicitLambdaAndDiamondTest.java + */ + +import java.util.function.Consumer; + +class CantFindSymbolImplicitLambdaAndDiamondTest { + static class B{} + + static class A1 { + A1(Consumer cons) {} + } + + static class A2 { + A2(Consumer cons) {} + } + + public void mount() { + new A1(inHours -> + new B<>() {{ + System.out.println(inHours); + }}); + + new A2<>(inHours -> + new B<>() {{ + System.out.println(inHours); + }}); + } +} diff --git a/test/langtools/tools/javac/lambda/deduplication/DeduplicationDebugInfo.java b/test/langtools/tools/javac/lambda/deduplication/DeduplicationDebugInfo.java new file mode 100644 index 0000000000000000000000000000000000000000..2302b8f431d3b57d214b6a672016722e4e047b8e --- /dev/null +++ b/test/langtools/tools/javac/lambda/deduplication/DeduplicationDebugInfo.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2021, Google LLC. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test 8275233 + * @summary Incorrect line number reported in exception stack trace thrown from a lambda expression + * @compile/ref=DeduplicationDebugInfo.out -XDrawDiagnostics -XDdebug.dumpLambdaToMethodDeduplication -g:none DeduplicationDebugInfo.java + * @compile/ref=DeduplicationDebugInfo_none.out -XDrawDiagnostics -XDdebug.dumpLambdaToMethodDeduplication DeduplicationDebugInfo.java + * @compile/ref=DeduplicationDebugInfo_none.out -XDrawDiagnostics -XDdebug.dumpLambdaToMethodDeduplication -g:lines DeduplicationDebugInfo.java + * @compile/ref=DeduplicationDebugInfo_none.out -XDrawDiagnostics -XDdebug.dumpLambdaToMethodDeduplication -g:vars DeduplicationDebugInfo.java + * @compile/ref=DeduplicationDebugInfo_none.out -XDrawDiagnostics -XDdebug.dumpLambdaToMethodDeduplication -g:lines,vars DeduplicationDebugInfo.java + */ + +import java.util.function.Function; + +class DeduplicationDebugInfoTest { + void f() { + Function f = x -> x.hashCode(); + Function g = x -> x.hashCode(); + } +} diff --git a/test/langtools/tools/javac/lambda/deduplication/DeduplicationDebugInfo.out b/test/langtools/tools/javac/lambda/deduplication/DeduplicationDebugInfo.out new file mode 100644 index 0000000000000000000000000000000000000000..f428fe28846675bad558eda19e0f18e3d15ca8fd --- /dev/null +++ b/test/langtools/tools/javac/lambda/deduplication/DeduplicationDebugInfo.out @@ -0,0 +1 @@ +DeduplicationDebugInfo.java:39:39: compiler.note.verbose.l2m.deduplicate: lambda$f$0(java.lang.Object) diff --git a/test/langtools/tools/javac/lambda/deduplication/DeduplicationDebugInfo_none.out b/test/langtools/tools/javac/lambda/deduplication/DeduplicationDebugInfo_none.out new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/test/langtools/tools/javac/lambda/deduplication/DeduplicationTest.java b/test/langtools/tools/javac/lambda/deduplication/DeduplicationTest.java index 14d0b88f09e40b525a492ee77f8741ba4ccfc0be..44c200e62261e3cb4069d882d69ba1b1ec4a6e54 100644 --- a/test/langtools/tools/javac/lambda/deduplication/DeduplicationTest.java +++ b/test/langtools/tools/javac/lambda/deduplication/DeduplicationTest.java @@ -93,6 +93,7 @@ public class DeduplicationTest { Arrays.asList( "-d", ".", + "-g:none", "-XDdebug.dumpLambdaToMethodDeduplication", "-XDdebug.dumpLambdaToMethodStats"), null, diff --git a/test/langtools/tools/javac/lambda/lambdaExecution/LambdaTranslationTest1.java b/test/langtools/tools/javac/lambda/lambdaExecution/LambdaTranslationTest1.java index 37033fff8a152acbe987fc355a872798d589179c..b207fd1a7d5e9d6dfa4823c8a78c147225a1d6b7 100644 --- a/test/langtools/tools/javac/lambda/lambdaExecution/LambdaTranslationTest1.java +++ b/test/langtools/tools/javac/lambda/lambdaExecution/LambdaTranslationTest1.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -25,7 +25,7 @@ * @test * @bug 8003639 * @summary convert lambda testng tests to jtreg and add them - * @run testng LambdaTranslationTest1 + * @run testng/othervm -Duser.language=en -Duser.country=US LambdaTranslationTest1 */ import org.testng.annotations.Test; diff --git a/test/langtools/tools/javac/lambda/lambdaExecution/LambdaTranslationTest2.java b/test/langtools/tools/javac/lambda/lambdaExecution/LambdaTranslationTest2.java index fc03a8630361403344cd0b793629f3c9b68eefa0..e7e484730b2117653c766038e3f9dccc06206365 100644 --- a/test/langtools/tools/javac/lambda/lambdaExecution/LambdaTranslationTest2.java +++ b/test/langtools/tools/javac/lambda/lambdaExecution/LambdaTranslationTest2.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -25,7 +25,7 @@ * @test * @bug 8003639 * @summary convert lambda testng tests to jtreg and add them - * @run testng LambdaTranslationTest2 + * @run testng/othervm -Duser.language=en -Duser.country=US LambdaTranslationTest2 */ import org.testng.annotations.Test; diff --git a/test/langtools/tools/javac/launcher/SourceLauncherTest.java b/test/langtools/tools/javac/launcher/SourceLauncherTest.java index 7507a6d9c276bf472dd8f9e0d1c4a807bf050b40..a052f087af6047b9b71d1583b9b1768edf3205b8 100644 --- a/test/langtools/tools/javac/launcher/SourceLauncherTest.java +++ b/test/langtools/tools/javac/launcher/SourceLauncherTest.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8192920 8204588 8246774 8248843 8268869 + * @bug 8192920 8204588 8246774 8248843 8268869 8235876 * @summary Test source launcher * @library /tools/lib * @modules jdk.compiler/com.sun.tools.javac.api @@ -213,48 +213,22 @@ public class SourceLauncherTest extends TestRunner { } @Test - public void testPermissions(Path base) throws IOException { - // does not work on exploded image, because the default policy file assumes jrt:; skip the test - if (Files.exists(Path.of(System.getProperty("java.home")).resolve("modules"))) { - out.println("JDK using exploded modules; test skipped"); - return; - } - - Path policyFile = base.resolve("test.policy"); - Path sourceFile = base.resolve("TestPermissions.java"); - - tb.writeFile(policyFile, - "grant codeBase \"jrt:/jdk.compiler\" {\n" + - " permission java.security.AllPermission;\n" + - "};\n" + - "grant codeBase \"" + sourceFile.toUri().toURL() + "\" {\n" + - " permission java.util.PropertyPermission \"user.dir\", \"read\";\n" + - "};\n"); - + public void testSecurityManager(Path base) throws IOException { + Path sourceFile = base.resolve("HelloWorld.java"); tb.writeJavaFiles(base, - "import java.net.URL;\n" + - "class TestPermissions {\n" + - " public static void main(String... args) {\n" + - " System.out.println(\"user.dir=\" + System.getProperty(\"user.dir\"));\n" + - " try {\n" + - " System.setProperty(\"user.dir\", \"\");\n" + - " System.out.println(\"no exception\");\n" + - " System.exit(1);\n" + - " } catch (SecurityException e) {\n" + - " System.out.println(\"exception: \" + e);\n" + - " }\n" + - " }\n" + - "}"); + "class HelloWorld {\n" + + " public static void main(String... args) {\n" + + " System.out.println(\"Hello World!\");\n" + + " }\n" + + "}"); String log = new JavaTask(tb) - .vmOptions("-Djava.security.manager", "-Djava.security.policy=" + policyFile) + .vmOptions("-Djava.security.manager=default") .className(sourceFile.toString()) - .run(Task.Expect.SUCCESS) - .getOutput(Task.OutputKind.STDOUT); - checkEqual("stdout", log.trim(), - "user.dir=" + System.getProperty("user.dir") + "\n" + - "exception: java.security.AccessControlException: " + - "access denied (\"java.util.PropertyPermission\" \"user.dir\" \"write\")"); + .run(Task.Expect.FAIL) + .getOutput(Task.OutputKind.STDERR); + checkContains("stderr", log, + "error: cannot use source-code launcher with a security manager enabled"); } public void testSystemProperty(Path base) throws IOException { @@ -630,6 +604,20 @@ public class SourceLauncherTest extends TestRunner { } } + @Test + public void testNoOptionsWarnings(Path base) throws IOException { + tb.writeJavaFiles(base, "public class Main { public static void main(String... args) {}}"); + String log = new JavaTask(tb) + .vmOptions("--source", "7") + .className(base.resolve("Main.java").toString()) + .run(Task.Expect.SUCCESS) + .getOutput(Task.OutputKind.STDERR); + + if (log.contains("warning: [options]")) { + error("Unexpected options warning in error output: " + log); + } + } + void testError(Path file, String expectStdErr, String expectFault) throws IOException { Result r = run(file, Collections.emptyList(), List.of("1", "2", "3")); checkEmpty("stdout", r.stdOut); @@ -696,6 +684,14 @@ public class SourceLauncherTest extends TestRunner { } } + void checkContains(String name, String found, String expect) { + expect = expect.replace("\n", tb.lineSeparator); + out.println(name + ": " + found); + if (!found.contains(expect)) { + error("Expected output not found: " + expect); + } + } + void checkEqual(String name, List found, List expect) { out.println(name + ": " + found); tb.checkEqual(expect, found); diff --git a/test/langtools/tools/javac/lib/JavacTestingAbstractProcessor.java b/test/langtools/tools/javac/lib/JavacTestingAbstractProcessor.java index 634a468d5591e29dee8487685035babc857edd31..03e065828961cb412239ce6fd48067ceb7e21d10 100644 --- a/test/langtools/tools/javac/lib/JavacTestingAbstractProcessor.java +++ b/test/langtools/tools/javac/lib/JavacTestingAbstractProcessor.java @@ -112,7 +112,7 @@ public abstract class JavacTestingAbstractProcessor extends AbstractProcessor { * corresponding platform visitor type. */ - @SupportedSourceVersion(RELEASE_18) + @SupportedSourceVersion(RELEASE_19) public static abstract class AbstractAnnotationValueVisitor extends AbstractAnnotationValueVisitor14 { /** @@ -123,7 +123,7 @@ public abstract class JavacTestingAbstractProcessor extends AbstractProcessor { } } - @SupportedSourceVersion(RELEASE_18) + @SupportedSourceVersion(RELEASE_19) public static abstract class AbstractElementVisitor extends AbstractElementVisitor14 { /** * Constructor for concrete subclasses to call. @@ -133,7 +133,7 @@ public abstract class JavacTestingAbstractProcessor extends AbstractProcessor { } } - @SupportedSourceVersion(RELEASE_18) + @SupportedSourceVersion(RELEASE_19) public static abstract class AbstractTypeVisitor extends AbstractTypeVisitor14 { /** * Constructor for concrete subclasses to call. @@ -143,7 +143,7 @@ public abstract class JavacTestingAbstractProcessor extends AbstractProcessor { } } - @SupportedSourceVersion(RELEASE_18) + @SupportedSourceVersion(RELEASE_19) public static class ElementKindVisitor extends ElementKindVisitor14 { /** * Constructor for concrete subclasses; uses {@code null} for the @@ -164,7 +164,7 @@ public abstract class JavacTestingAbstractProcessor extends AbstractProcessor { } } - @SupportedSourceVersion(RELEASE_18) + @SupportedSourceVersion(RELEASE_19) public static class ElementScanner extends ElementScanner14 { /** * Constructor for concrete subclasses; uses {@code null} for the @@ -183,7 +183,7 @@ public abstract class JavacTestingAbstractProcessor extends AbstractProcessor { } } - @SupportedSourceVersion(RELEASE_18) + @SupportedSourceVersion(RELEASE_19) public static class SimpleAnnotationValueVisitor extends SimpleAnnotationValueVisitor14 { /** * Constructor for concrete subclasses; uses {@code null} for the @@ -204,7 +204,7 @@ public abstract class JavacTestingAbstractProcessor extends AbstractProcessor { } } - @SupportedSourceVersion(RELEASE_18) + @SupportedSourceVersion(RELEASE_19) public static class SimpleElementVisitor extends SimpleElementVisitor14 { /** * Constructor for concrete subclasses; uses {@code null} for the @@ -225,7 +225,7 @@ public abstract class JavacTestingAbstractProcessor extends AbstractProcessor { } } - @SupportedSourceVersion(RELEASE_18) + @SupportedSourceVersion(RELEASE_19) public static class SimpleTypeVisitor extends SimpleTypeVisitor14 { /** * Constructor for concrete subclasses; uses {@code null} for the @@ -246,7 +246,7 @@ public abstract class JavacTestingAbstractProcessor extends AbstractProcessor { } } - @SupportedSourceVersion(RELEASE_18) + @SupportedSourceVersion(RELEASE_19) public static class TypeKindVisitor extends TypeKindVisitor14 { /** * Constructor for concrete subclasses to call; uses {@code null} diff --git a/test/langtools/tools/javac/optimizeOuterThis/DontOptimizeOuterThis.java b/test/langtools/tools/javac/optimizeOuterThis/DontOptimizeOuterThis.java new file mode 100644 index 0000000000000000000000000000000000000000..dfba801d256b7c0750f23e2f03ba8d05b798ed1e --- /dev/null +++ b/test/langtools/tools/javac/optimizeOuterThis/DontOptimizeOuterThis.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2021, Google LLC. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.lang.reflect.Field; +import java.util.Arrays; +import java.util.Optional; + +/** + * @test + * @bug 8271623 + * + * @compile --release 17 DontOptimizeOuterThis.java InnerClasses.java + * @run main DontOptimizeOuterThis + */ +public class DontOptimizeOuterThis extends InnerClasses { + + public static void main(String[] args) { + new DontOptimizeOuterThis().test(); + } + + public void test() { + checkInner(localCapturesParameter(0), true); + checkInner(localCapturesLocal(), true); + checkInner(localCapturesEnclosing(), true); + + checkInner(anonCapturesParameter(0), true); + checkInner(anonCapturesLocal(), true); + checkInner(anonCapturesEnclosing(), true); + + checkInner(StaticMemberClass.class, false); // static + checkInner(NonStaticMemberClass.class, true); + checkInner(NonStaticMemberClassCapturesEnclosing.class, true); + + checkInner(N0.class, false); // static + checkInner(N0.N1.class, true); + checkInner(N0.N1.N2.class, true); + checkInner(N0.N1.N2.N3.class, true); + checkInner(N0.N1.N2.N3.N4.class, true); + checkInner(N0.N1.N2.N3.N4.N5.class, true); + + checkInner(SerializableCapture.class, true); + checkInner(SerializableWithSerialVersionUID.class, true); + checkInner(SerializableWithInvalidSerialVersionUIDType.class, true); + checkInner(SerializableWithInvalidSerialVersionUIDNonFinal.class, true); + checkInner(SerializableWithInvalidSerialVersionUIDNonStatic.class, true); + } + + private static void checkInner(Class clazz, boolean expectOuterThis) { + Optional outerThis = Arrays.stream(clazz.getDeclaredFields()) + .filter(f -> f.getName().startsWith("this$")).findFirst(); + if (expectOuterThis) { + if (outerThis.isEmpty()) { + throw new AssertionError( + String.format( + "expected %s to have an enclosing instance", clazz.getName())); + } + } else { + if (outerThis.isPresent()) { + throw new AssertionError( + String.format("%s had an unexpected enclosing instance", clazz.getName())); + } + } + } +} diff --git a/test/langtools/tools/javac/optimizeOuterThis/InnerClasses.java b/test/langtools/tools/javac/optimizeOuterThis/InnerClasses.java new file mode 100644 index 0000000000000000000000000000000000000000..2f4ea1ed615111a748587f0317217b0679354982 --- /dev/null +++ b/test/langtools/tools/javac/optimizeOuterThis/InnerClasses.java @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2021, Google LLC. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.Serializable; + +public class InnerClasses { + + public Class localCapturesParameter(final int x) { + class Local { + public void f() { + System.err.println(x); + } + } + return Local.class; + } + + public Class localCapturesLocal() { + final int x = 0; + class Local { + public void f() { + System.err.println(x); + } + } + return Local.class; + } + + public Class localCapturesEnclosing() { + class Local { + public void f() { + System.err.println(InnerClasses.this); + } + } + return Local.class; + } + + public Class anonCapturesParameter(final int x) { + return new Object() { + public void f() { + System.err.println(x); + } + }.getClass(); + } + + public Class anonCapturesLocal() { + final int x = 0; + return new Object() { + public void f() { + System.err.println(x); + } + }.getClass(); + } + + public Class anonCapturesEnclosing() { + return new Object() { + public void f() { + System.err.println(InnerClasses.this); + } + }.getClass(); + } + + public static class StaticMemberClass {} + + public class NonStaticMemberClass {} + + public class NonStaticMemberClassCapturesEnclosing { + public void f() { + System.err.println(InnerClasses.this); + } + } + + static class N0 { + int x; + + class N1 { + class N2 { + class N3 { + void f() { + System.err.println(x); + } + + class N4 { + class N5 {} + } + } + } + } + } + + class SerializableCapture implements Serializable { + void f() { + System.err.println(InnerClasses.this); + } + } + + class SerializableWithSerialVersionUID implements Serializable { + private static final long serialVersionUID = 0; + } + + class SerializableWithInvalidSerialVersionUIDType implements Serializable { + private static final int serialVersionUID = 0; + } + + class SerializableWithInvalidSerialVersionUIDNonFinal implements Serializable { + private static long serialVersionUID = 0; + } + + class SerializableWithInvalidSerialVersionUIDNonStatic implements Serializable { + private final long serialVersionUID = 0; + } +} diff --git a/test/langtools/tools/javac/optimizeOuterThis/OptimizeOuterThis.java b/test/langtools/tools/javac/optimizeOuterThis/OptimizeOuterThis.java new file mode 100644 index 0000000000000000000000000000000000000000..a42508e2a0a0d39adf5d7274dd96e76a79761400 --- /dev/null +++ b/test/langtools/tools/javac/optimizeOuterThis/OptimizeOuterThis.java @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2021, Google LLC. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.lang.reflect.Field; +import java.util.Arrays; +import java.util.Optional; + +/** + * @test + * @bug 8271623 + * + * @clean * + * @compile OptimizeOuterThis.java InnerClasses.java + * @run main OptimizeOuterThis + * + * @clean * + * @compile -XDoptimizeOuterThis=true --release 17 OptimizeOuterThis.java InnerClasses.java + * @run main OptimizeOuterThis + */ +public class OptimizeOuterThis extends InnerClasses { + + public static void main(String[] args) { + new OptimizeOuterThis().test(); + } + + public void test() { + checkInner(localCapturesParameter(0), false); + checkInner(localCapturesLocal(), false); + checkInner(localCapturesEnclosing(), true); + + checkInner(anonCapturesParameter(0), false); + checkInner(anonCapturesLocal(), false); + checkInner(anonCapturesEnclosing(), true); + + checkInner(StaticMemberClass.class, false); + checkInner(NonStaticMemberClass.class, false); + checkInner(NonStaticMemberClassCapturesEnclosing.class, true); + + checkInner(N0.class, false); + checkInner(N0.N1.class, true); + checkInner(N0.N1.N2.class, true); + checkInner(N0.N1.N2.N3.class, true); + checkInner(N0.N1.N2.N3.N4.class, false); + checkInner(N0.N1.N2.N3.N4.N5.class, false); + + checkInner(SerializableCapture.class, true); + checkInner(SerializableWithSerialVersionUID.class, true); + checkInner(SerializableWithInvalidSerialVersionUIDType.class, true); + checkInner(SerializableWithInvalidSerialVersionUIDNonFinal.class, true); + checkInner(SerializableWithInvalidSerialVersionUIDNonStatic.class, true); + } + + private static void checkInner(Class clazz, boolean expectOuterThis) { + Optional outerThis = Arrays.stream(clazz.getDeclaredFields()) + .filter(f -> f.getName().startsWith("this$")).findFirst(); + if (expectOuterThis) { + if (outerThis.isEmpty()) { + throw new AssertionError( + String.format( + "expected %s to have an enclosing instance", clazz.getName())); + } + } else { + if (outerThis.isPresent()) { + throw new AssertionError( + String.format("%s had an unexpected enclosing instance %s", clazz.getName(), outerThis.get())); + } + } + } +} diff --git a/test/langtools/tools/javac/options/modes/AtFilesTest.java b/test/langtools/tools/javac/options/modes/AtFilesTest.java index 761e20b53021e6f74c468a6465195cccd7272349..5cf5c2acbaf79ddc8a5a4d8982b0c1f1f13d50ab 100644 --- a/test/langtools/tools/javac/options/modes/AtFilesTest.java +++ b/test/langtools/tools/javac/options/modes/AtFilesTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -23,7 +23,7 @@ /* * @test - * @bug 8044859 + * @bug 8044859 8272728 * @summary test support for at-files * @modules jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.file @@ -33,6 +33,7 @@ * @run main AtFilesTest */ +import com.sun.tools.javac.main.Main; import java.io.IOException; public class AtFilesTest extends OptionModesTester { @@ -60,4 +61,16 @@ public class AtFilesTest extends OptionModesTester { runParse(opts, files) .checkIllegalArgumentException(); } + + @Test + void testAtFilesMustNotContainOptionJ() throws IOException { + writeFile("args", "-J-verbose"); + + String[] opts = { "@args", "-version" }; + String[] files = { }; + + runMain(opts, files) + .checkResult(Main.Result.CMDERR.exitCode) + .checkLog(Log.DIRECT, "-J-verbose"); + } } diff --git a/test/langtools/tools/javac/options/modes/InfoOptsTest.java b/test/langtools/tools/javac/options/modes/InfoOptsTest.java index 58391c7d9d623efba72c34aaadb3b2b485d575ae..e6e788adb021a575c2aa02e559c132e3c6161117 100644 --- a/test/langtools/tools/javac/options/modes/InfoOptsTest.java +++ b/test/langtools/tools/javac/options/modes/InfoOptsTest.java @@ -49,7 +49,7 @@ public class InfoOptsTest extends OptionModesTester { String specVersion = System.getProperty("java.specification.version"); testInfoOpt("-version", "javac", specVersion); - testInfoOpt("-fullversion", "javac", specVersion, "+"); + testInfoOpt("-fullversion", "javac", specVersion); } void testInfoOpt(String opt, String... expect) { diff --git a/test/langtools/tools/javac/parser/7157165/T7157165.out b/test/langtools/tools/javac/parser/7157165/T7157165.out index deb580df96c647d06dfffda4887b1d9119d3806b..7552381ba15c13fcef7ad5f97905525e43cd421f 100644 --- a/test/langtools/tools/javac/parser/7157165/T7157165.out +++ b/test/langtools/tools/javac/parser/7157165/T7157165.out @@ -1,4 +1,4 @@ -T7157165.java:11:20: compiler.err.expected: > +T7157165.java:11:20: compiler.err.expected2: >, ',' T7157165.java:11:22: compiler.err.expected: token.identifier T7157165.java:11:28: compiler.err.expected: token.identifier 3 errors diff --git a/test/langtools/tools/javac/parser/SingleCommaAnnotationValueFail.out b/test/langtools/tools/javac/parser/SingleCommaAnnotationValueFail.out index 23d1082361bc9f8c0c7bb80ce5a9cb768f4a0137..05d27bc67df77e508ec2b9dee0fbe96b699fec68 100644 --- a/test/langtools/tools/javac/parser/SingleCommaAnnotationValueFail.out +++ b/test/langtools/tools/javac/parser/SingleCommaAnnotationValueFail.out @@ -1,3 +1,3 @@ -SingleCommaAnnotationValueFail.java:11:12: compiler.err.expected: '}' +SingleCommaAnnotationValueFail.java:11:12: compiler.err.annotation.missing.element.value SingleCommaAnnotationValueFail.java:11:14: compiler.err.expected4: class, interface, enum, record 2 errors diff --git a/test/langtools/tools/javac/patterns/Annotations.java b/test/langtools/tools/javac/patterns/Annotations.java index 8c9062fa427ef229f7bcf853400dd67fa5d8d714..324f07945ddf1e656f8728966f85dc00a4f48cce 100644 --- a/test/langtools/tools/javac/patterns/Annotations.java +++ b/test/langtools/tools/javac/patterns/Annotations.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -23,7 +23,7 @@ /* * @test - * @bug 8256266 + * @bug 8256266 8281238 * @summary Verify annotations work correctly on binding variables * @library /tools/javac/lib * @modules java.compiler @@ -114,11 +114,11 @@ public class Annotations extends JavacTestingAbstractProcessor { } case "dta" -> { expectedDeclAnnos = "@Annotations.DTA"; - expectedType = "@Annotations.DTA java.lang.String"; + expectedType = "java.lang.@Annotations.DTA String"; } case "ta" -> { expectedDeclAnnos = ""; - expectedType = "@Annotations.TA java.lang.String"; + expectedType = "java.lang.@Annotations.TA String"; } default -> { throw new AssertionError("Unexpected variable: " + var); @@ -133,7 +133,7 @@ public class Annotations extends JavacTestingAbstractProcessor { String type = varType.toString(); if (!expectedType.equals(type)) { throw new AssertionError("Unexpected type: " + type + - " for: " + var.getName()); + " for: " + var.getName() + " expected " + expectedType); } return super.visitInstanceOf(node, p); } diff --git a/test/langtools/tools/javac/patterns/BindingsInitializer.java b/test/langtools/tools/javac/patterns/BindingsInitializer.java new file mode 100644 index 0000000000000000000000000000000000000000..eaf550c3dafe004a4c7cd907b9df6568343afaa6 --- /dev/null +++ b/test/langtools/tools/javac/patterns/BindingsInitializer.java @@ -0,0 +1,164 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8278834 + * @summary Verify pattern matching nested inside initializers of classes nested in methods + * works correctly. + * @library /tools/lib /tools/javac/lib + * @modules + * jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.file + * jdk.compiler/com.sun.tools.javac.main + * jdk.compiler/com.sun.tools.javac.util + * @build toolbox.ToolBox toolbox.JavacTask + * @build combo.ComboTestHelper + * @compile BindingsInitializer.java + * @run main BindingsInitializer + */ + +import combo.ComboInstance; +import combo.ComboParameter; +import combo.ComboTask; +import combo.ComboTestHelper; +import java.nio.file.Path; +import java.nio.file.Paths; +import toolbox.ToolBox; + +public class BindingsInitializer extends ComboInstance { + protected ToolBox tb; + + BindingsInitializer() { + super(); + tb = new ToolBox(); + } + + public static void main(String... args) throws Exception { + new ComboTestHelper() + .withDimension("OUTER", (x, outer) -> x.outer = outer, Outer.values()) + .withDimension("MIDDLE", (x, middle) -> x.middle = middle, Middle.values()) + .withDimension("INNER", (x, inner) -> x.inner = inner, Inner.values()) + .withDimension("TEST", (x, test) -> x.test = test, Test.values()) + .run(BindingsInitializer::new); + } + + private Outer outer; + private Middle middle; + private Inner inner; + private Test test; + + private static final String MAIN_TEMPLATE = + """ + public class Test { + private static Object obj = ""; + #{OUTER} + } + """; + + @Override + protected void doWork() throws Throwable { + Path base = Paths.get("."); + + ComboTask task = newCompilationTask() + .withSourceFromTemplate(MAIN_TEMPLATE, pname -> switch (pname) { + case "OUTER" -> outer; + case "MIDDLE" -> middle; + case "INNER" -> inner; + case "TESST" -> test; + default -> throw new UnsupportedOperationException(pname); + }); + + task.generate(result -> { + if (result.hasErrors()) { + throw new AssertionError("Unexpected result: " + result.compilationInfo()); + } + }); + } + + public enum Outer implements ComboParameter { + NONE("#{MIDDLE}"), + STATIC_CLASS("static class Nested { #{MIDDLE} }"), + CLASS("class Inner { #{MIDDLE} }"); + private final String code; + + private Outer(String code) { + this.code = code; + } + + @Override + public String expand(String optParameter) { + return code; + } + } + + public enum Middle implements ComboParameter { + STATIC_INIT("static { #{INNER} }"), + INIT("{ #{INNER} }"), + METHOD("void test() { #{INNER} }"); + private final String code; + + private Middle(String code) { + this.code = code; + } + + @Override + public String expand(String optParameter) { + return code; + } + } + + public enum Inner implements ComboParameter { + DIRECT("#{TEST}"), + CLASS_STATIC_INIT("class C { static { #{TEST} } }"), + CLASS_INIT("class C { { #{TEST} } }"), + CLASS_METHOD("class C { void t() { #{TEST} } }"), + ANNONYMOUS_CLASS_STATIC_INIT("new Object() { static { #{TEST} } };"), + ANNONYMOUS_CLASS_INIT("new Object() { { #{TEST} } };"), + ANNONYMOUS_CLASS_METHOD("new Object() { void t() { #{TEST} } };"); + private final String code; + + private Inner(String code) { + this.code = code; + } + + @Override + public String expand(String optParameter) { + return code; + } + } + + public enum Test implements ComboParameter { + TEST("if (obj instanceof String str) System.err.println(str);"); + private final String code; + + private Test(String code) { + this.code = code; + } + + @Override + public String expand(String optParameter) { + return code; + } + } +} diff --git a/test/langtools/tools/javac/patterns/Domination.java b/test/langtools/tools/javac/patterns/Domination.java index b5283fe31a7ae31aa38bdf7b1ee9a26ef3a563f9..683758c297caf416318c807cdd609af6f25329f3 100644 --- a/test/langtools/tools/javac/patterns/Domination.java +++ b/test/langtools/tools/javac/patterns/Domination.java @@ -68,6 +68,20 @@ public class Domination { } } + int testDominatesStringConstant2(String str) { + switch (str) { + case (String s && s.isEmpty()): return 1; + case "": return -1; + } + } + + int testDominatesStringConstant3(String str) { + switch (str) { + case (String s && !s.isEmpty()): return 1; + case "": return -1; + } + } + int testDominatesIntegerConstant(Integer i) { switch (i) { case Integer j: return 1; @@ -75,6 +89,20 @@ public class Domination { } } + int testDominatesIntegerConstant2(Integer i) { + switch (i) { + case (Integer j && j == 0): return 1; + case 0: return -1; + } + } + + int testDominatesIntegerConstant3(Integer i) { + switch (i) { + case (Integer j && j == 1): return 1; + case 0: return -1; + } + } + int testDominatesEnumConstant() { enum E { A, B; @@ -86,4 +114,26 @@ public class Domination { } } + int testDominatesEnumConstant2() { + enum E { + A, B; + } + E e = E.A; + switch (e) { + case (E d && d == E.A): return 1; + case A: return -1; + } + } + + int testDominatesEnumConstant3() { + enum E { + A, B; + } + E e = E.A; + switch (e) { + case (E d && d == E.B): return 1; + case A: return -1; + } + } + } diff --git a/test/langtools/tools/javac/patterns/Domination.out b/test/langtools/tools/javac/patterns/Domination.out index 3d1aa46bab0fcf060edd8d64312a36c767253756..80b95b8527d84b41cb5cf953da9cf3f717760048 100644 --- a/test/langtools/tools/javac/patterns/Domination.out +++ b/test/langtools/tools/javac/patterns/Domination.out @@ -3,7 +3,13 @@ Domination.java:43:18: compiler.err.pattern.dominated Domination.java:51:18: compiler.err.pattern.dominated Domination.java:67:18: compiler.err.pattern.dominated Domination.java:74:18: compiler.err.pattern.dominated -Domination.java:85:18: compiler.err.pattern.dominated +Domination.java:81:18: compiler.err.pattern.dominated +Domination.java:88:18: compiler.err.pattern.dominated +Domination.java:95:18: compiler.err.pattern.dominated +Domination.java:102:18: compiler.err.pattern.dominated +Domination.java:113:18: compiler.err.pattern.dominated +Domination.java:124:18: compiler.err.pattern.dominated +Domination.java:135:18: compiler.err.pattern.dominated - compiler.note.preview.filename: Domination.java, DEFAULT - compiler.note.preview.recompile -6 errors +12 errors diff --git a/test/langtools/tools/javac/patterns/EnumTypeChanges.java b/test/langtools/tools/javac/patterns/EnumTypeChanges.java index f6a0aafe6e7ef6468ab0ce0f35b72d9027bb3421..8d16efd796551eb01d29e2b538344cf67835d4c6 100644 --- a/test/langtools/tools/javac/patterns/EnumTypeChanges.java +++ b/test/langtools/tools/javac/patterns/EnumTypeChanges.java @@ -52,8 +52,8 @@ public class EnumTypeChanges { String statementEnum(EnumTypeChangesEnum e) { switch (e) { case A -> { return "A"; } - case EnumTypeChangesEnum e1 && false -> throw new AssertionError(); case B -> { return "B"; } + case EnumTypeChangesEnum e1 && false -> throw new AssertionError(); default -> { return "D"; } } } @@ -61,8 +61,8 @@ public class EnumTypeChanges { String expressionEnum(EnumTypeChangesEnum e) { return switch (e) { case A -> "A"; - case EnumTypeChangesEnum e1 && false -> throw new AssertionError(); case B -> "B"; + case EnumTypeChangesEnum e1 && false -> throw new AssertionError(); default -> "D"; }; } diff --git a/test/langtools/tools/javac/patterns/Exhaustiveness.java b/test/langtools/tools/javac/patterns/Exhaustiveness.java index 9728fd83f48b0e2aa677d0d6f79a7a1b2e4ba787..75121a97eca3109eea9aa42a14fde6d469aaffe0 100644 --- a/test/langtools/tools/javac/patterns/Exhaustiveness.java +++ b/test/langtools/tools/javac/patterns/Exhaustiveness.java @@ -23,7 +23,7 @@ /** * @test - * @bug 8262891 8268871 8274363 + * @bug 8262891 8268871 8274363 8281100 * @summary Check exhaustiveness of switches over sealed types. * @library /tools/lib * @modules jdk.compiler/com.sun.tools.javac.api @@ -369,102 +369,6 @@ public class Exhaustiveness extends TestRunner { """); } - @Test - public void testInaccessiblePermitted(Path base) throws IOException { - Path current = base.resolve("."); - Path libSrc = current.resolve("lib-src"); - - tb.writeJavaFiles(libSrc, - """ - package lib; - public sealed interface S permits A, B {} - """, - """ - package lib; - public final class A implements S {} - """, - """ - package lib; - final class B implements S {} - """); - - Path libClasses = current.resolve("libClasses"); - - Files.createDirectories(libClasses); - - new JavacTask(tb) - .options("--enable-preview", - "-source", JAVA_VERSION) - .outdir(libClasses) - .files(tb.findJavaFiles(libSrc)) - .run(); - - Path src = current.resolve("src"); - tb.writeJavaFiles(src, - """ - package test; - import lib.*; - public class Test { - private int test(S obj) { - return switch (obj) { - case A a -> 0; - }; - } - } - """); - - Path classes = current.resolve("libClasses"); - - Files.createDirectories(libClasses); - - var log = - new JavacTask(tb) - .options("--enable-preview", - "-source", JAVA_VERSION, - "-XDrawDiagnostics", - "-Xlint:-preview", - "--class-path", libClasses.toString()) - .outdir(classes) - .files(tb.findJavaFiles(src)) - .run(Task.Expect.FAIL) - .writeAll() - .getOutputLines(Task.OutputKind.DIRECT); - - List expectedErrors = List.of( - "Test.java:5:16: compiler.err.not.exhaustive", - "- compiler.note.preview.filename: Test.java, DEFAULT", - "- compiler.note.preview.recompile", - "1 error"); - - if (!expectedErrors.equals(log)) { - throw new AssertionError("Incorrect errors, expected: " + expectedErrors + - ", actual: " + log); - } - - Path bClass = libClasses.resolve("lib").resolve("B.class"); - - Files.delete(bClass); - - var log2 = - new JavacTask(tb) - .options("--enable-preview", - "-source", JAVA_VERSION, - "-XDrawDiagnostics", - "-Xlint:-preview", - "--class-path", libClasses.toString()) - .outdir(classes) - .files(tb.findJavaFiles(src)) - .run(Task.Expect.FAIL) - .writeAll() - .getOutputLines(Task.OutputKind.DIRECT); - - if (!expectedErrors.equals(log2)) { - throw new AssertionError("Incorrect errors, expected: " + expectedErrors + - ", actual: " + log2); - } - - } - @Test public void testExhaustiveStatement1(Path base) throws Exception { doTest(base, @@ -799,6 +703,170 @@ public class Exhaustiveness extends TestRunner { """); } + @Test + public void testOnlyApplicable(Path base) throws Exception { + record TestCase(String cases, String... errors) {} + TestCase[] subCases = new TestCase[] { + new TestCase(""" + case C3 c -> {} + case C5 c -> {} + case C6 c -> {} + """), //OK + new TestCase(""" + case C5 c -> {} + case C6 c -> {} + """, + "Test.java:11:9: compiler.err.not.exhaustive.statement", + "- compiler.note.preview.filename: Test.java, DEFAULT", + "- compiler.note.preview.recompile", + "1 error"), + new TestCase(""" + case C3 c -> {} + case C6 c -> {} + """, + "Test.java:11:9: compiler.err.not.exhaustive.statement", + "- compiler.note.preview.filename: Test.java, DEFAULT", + "- compiler.note.preview.recompile", + "1 error"), + new TestCase(""" + case C3 c -> {} + case C5 c -> {} + """, + "Test.java:11:9: compiler.err.not.exhaustive.statement", + "- compiler.note.preview.filename: Test.java, DEFAULT", + "- compiler.note.preview.recompile", + "1 error"), + new TestCase(""" + case C1 c -> {} + case C3 c -> {} + case C5 c -> {} + case C6 c -> {} + """, + "Test.java:12:18: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: test.Test.I, test.Test.C1)", + "- compiler.note.preview.filename: Test.java, DEFAULT", + "- compiler.note.preview.recompile", + "1 error"), + new TestCase(""" + case C2 c -> {} + case C3 c -> {} + case C5 c -> {} + case C6 c -> {} + """, + "Test.java:12:18: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: test.Test.I, test.Test.C2)", + "- compiler.note.preview.filename: Test.java, DEFAULT", + "- compiler.note.preview.recompile", + "1 error"), + new TestCase(""" + case C4 c -> {} + case C3 c -> {} + case C5 c -> {} + case C6 c -> {} + """, + "Test.java:12:18: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: test.Test.I, test.Test.C4)", + "- compiler.note.preview.filename: Test.java, DEFAULT", + "- compiler.note.preview.recompile", + "1 error"), + }; + for (TestCase tc : subCases) { + doTest(base, + new String[0], + """ + package test; + public class Test { + sealed interface I {} + final class C1 implements I {} + final class C2 implements I {} + final class C3 implements I {} + final class C4 implements I {} + final class C5 implements I {} + final class C6 implements I {} + void t(I i) { + switch (i) { + ${cases} + } + } + } + """.replace("${cases}", tc.cases), + tc.errors); + } + } + + @Test + public void testDefiniteAssignment(Path base) throws Exception { + doTest(base, + new String[]{""" + package lib; + public sealed interface S permits A, B {} + """, + """ + package lib; + public final class A implements S {} + """, + """ + package lib; + public final class B implements S {} + """}, + """ + package test; + import lib.*; + public class Test { + private void testStatement(S obj) { + int data; + switch (obj) { + case A a -> data = 0; + case B b -> data = 0; + }; + System.err.println(data); + } + private void testExpression(S obj) { + int data; + int v = switch (obj) { + case A a -> data = 0; + case B b -> data = 0; + }; + System.err.println(data); + } + private void testStatementNotExhaustive(S obj) { + int data; + switch (obj) { + case A a -> data = 0; + }; + System.err.println(data); + } + private void testExpressionNotExhaustive(S obj) { + int data; + int v = switch (obj) { + case A a -> data = 0; + }; + System.err.println(data); + } + private void testStatementErrorEnum(E e) { //"E" is intentionally unresolvable + int data; + switch (e) { + case A -> data = 0; + case B -> data = 0; + }; + System.err.println(data); + } + private void testExpressionErrorEnum(E e) { //"E" is intentionally unresolvable + int data; + int v = switch (e) { + case A -> data = 0; + case B -> data = 0; + }; + System.err.println(data); + } + } + """, + "Test.java:34:41: compiler.err.cant.resolve.location: kindname.class, E, , , (compiler.misc.location: kindname.class, test.Test, null)", + "Test.java:42:42: compiler.err.cant.resolve.location: kindname.class, E, , , (compiler.misc.location: kindname.class, test.Test, null)", + "Test.java:22:9: compiler.err.not.exhaustive.statement", + "Test.java:29:17: compiler.err.not.exhaustive", + "- compiler.note.preview.filename: Test.java, DEFAULT", + "- compiler.note.preview.recompile", + "4 errors"); + } + private void doTest(Path base, String[] libraryCode, String testCode, String... expectedErrors) throws IOException { Path current = base.resolve("."); Path libClasses = current.resolve("libClasses"); @@ -833,7 +901,8 @@ public class Exhaustiveness extends TestRunner { "-source", JAVA_VERSION, "-XDrawDiagnostics", "-Xlint:-preview", - "--class-path", libClasses.toString()) + "--class-path", libClasses.toString(), + "-XDshould-stop.at=FLOW") .outdir(classes) .files(tb.findJavaFiles(src)) .run(expectedErrors.length > 0 ? Task.Expect.FAIL : Task.Expect.SUCCESS) diff --git a/test/langtools/tools/javac/patterns/SwitchErrors.java b/test/langtools/tools/javac/patterns/SwitchErrors.java index ddeca570d3aa1a09dda89aec49bcd672bb7d2507..61f544a52c0433c06ba6691131581d4e1837ab15 100644 --- a/test/langtools/tools/javac/patterns/SwitchErrors.java +++ b/test/langtools/tools/javac/patterns/SwitchErrors.java @@ -185,7 +185,16 @@ public class SwitchErrors { default -> null; }; } - void test8269146a(Integer i) { + void test8269146a1(Integer i) { + switch (i) { + //error - illegal combination of pattern and constant: + case 1, Integer o && o != null: + break; + default: + break; + } + } + void test8269146a2(Integer i) { switch (i) { //error - illegal combination of pattern and constant: case Integer o && o != null, 1: @@ -210,7 +219,14 @@ public class SwitchErrors { break; } } - void test8269301(Integer i) { + void test8269301a(Integer i) { + switch (i) { + //error - illegal combination of pattern, constant and default + case 1, Integer o && o != null, default: + break; + } + } + void test8269301b(Integer i) { switch (i) { //error - illegal combination of pattern, constant and default case Integer o && o != null, 1, default: diff --git a/test/langtools/tools/javac/patterns/SwitchErrors.out b/test/langtools/tools/javac/patterns/SwitchErrors.out index 9c4a8ff677f4f5a8888de4723e42dd3e47469506..4679651c800c64e07da8844bb02d9b782c377029 100644 --- a/test/langtools/tools/javac/patterns/SwitchErrors.out +++ b/test/langtools/tools/javac/patterns/SwitchErrors.out @@ -31,12 +31,15 @@ SwitchErrors.java:160:18: compiler.err.pattern.dominated SwitchErrors.java:172:18: compiler.err.pattern.expected SwitchErrors.java:178:76: compiler.err.cant.resolve.location: kindname.variable, n, , , (compiler.misc.location: kindname.class, SwitchErrors, null) SwitchErrors.java:184:71: compiler.err.cant.resolve.location: kindname.variable, n, , , (compiler.misc.location: kindname.class, SwitchErrors, null) -SwitchErrors.java:191:42: compiler.err.flows.through.from.pattern -SwitchErrors.java:200:24: compiler.err.flows.through.to.pattern -SwitchErrors.java:209:29: compiler.err.total.pattern.and.default -SwitchErrors.java:216:42: compiler.err.flows.through.from.pattern -SwitchErrors.java:216:45: compiler.err.flows.through.from.pattern -SwitchErrors.java:228:18: compiler.err.duplicate.total.pattern +SwitchErrors.java:191:21: compiler.err.flows.through.to.pattern +SwitchErrors.java:200:42: compiler.err.pattern.dominated +SwitchErrors.java:209:24: compiler.err.flows.through.to.pattern +SwitchErrors.java:218:29: compiler.err.total.pattern.and.default +SwitchErrors.java:225:21: compiler.err.flows.through.to.pattern +SwitchErrors.java:225:45: compiler.err.flows.through.from.pattern +SwitchErrors.java:232:42: compiler.err.pattern.dominated +SwitchErrors.java:232:45: compiler.err.flows.through.from.pattern +SwitchErrors.java:244:18: compiler.err.duplicate.total.pattern SwitchErrors.java:9:9: compiler.err.not.exhaustive.statement SwitchErrors.java:15:9: compiler.err.not.exhaustive.statement SwitchErrors.java:21:9: compiler.err.not.exhaustive.statement @@ -48,7 +51,7 @@ SwitchErrors.java:91:9: compiler.err.not.exhaustive.statement SwitchErrors.java:97:9: compiler.err.not.exhaustive.statement SwitchErrors.java:104:9: compiler.err.not.exhaustive.statement SwitchErrors.java:164:9: compiler.err.not.exhaustive.statement -SwitchErrors.java:221:9: compiler.err.not.exhaustive.statement +SwitchErrors.java:237:9: compiler.err.not.exhaustive.statement - compiler.note.preview.filename: SwitchErrors.java, DEFAULT - compiler.note.preview.recompile -51 errors +54 errors diff --git a/test/langtools/tools/javac/patterns/Switches.java b/test/langtools/tools/javac/patterns/Switches.java index cf9858e7d0a07ea73db8bd1b9b8412c7b6d8d4c5..e4c1bd6edb452b934e5ac684c248405b9820fe8e 100644 --- a/test/langtools/tools/javac/patterns/Switches.java +++ b/test/langtools/tools/javac/patterns/Switches.java @@ -28,7 +28,7 @@ import java.util.function.Function; /* * @test - * @bug 8262891 8268333 8268896 8269802 8269808 8270151 8269113 + * @bug 8262891 8268333 8268896 8269802 8269808 8270151 8269113 8277864 * @summary Check behavior of pattern switches. * @compile --enable-preview -source ${jdk.version} Switches.java * @run main/othervm --enable-preview Switches @@ -85,6 +85,9 @@ public class Switches { assertEquals(2, switchOverNull1()); assertEquals(2, switchOverNull2()); assertEquals(2, switchOverNull3()); + assertEquals(5, switchOverPrimitiveInt(0)); + assertEquals(7, switchOverPrimitiveInt(1)); + assertEquals(9, switchOverPrimitiveInt(2)); } void run(Function mapper) { @@ -265,8 +268,8 @@ public class Switches { switch (e) { case A: return "a"; case B: return "b"; - case E x && "A".equals(x.name()): return "broken"; case C: return String.valueOf(e); + case E x && "A".equals(x.name()): return "broken"; case null, E x: return String.valueOf(x); } } @@ -275,8 +278,8 @@ public class Switches { return switch (e) { case A -> "a"; case B -> "b"; - case E x && "A".equals(x.name()) -> "broken"; case C -> String.valueOf(e); + case E x && "A".equals(x.name()) -> "broken"; case null, E x -> String.valueOf(x); }; } @@ -286,8 +289,7 @@ public class Switches { case A: return "a"; case B: return "b"; case E x && "C".equals(x.name()): return "C"; - case C: return "broken"; - case null, E x: return String.valueOf(x); + case null, E x: return e == E.C ? "broken" : String.valueOf(x); } } @@ -296,8 +298,7 @@ public class Switches { case A -> "a"; case B -> "b"; case E x && "C".equals(x.name()) -> "C"; - case C -> "broken"; - case null, E x -> String.valueOf(x); + case null, E x -> e == E.C ? "broken" : String.valueOf(x); }; } @@ -306,8 +307,7 @@ public class Switches { case A: return "a"; case B: return "b"; case Object x && "C".equals(x.toString()): return "C"; - case C: return "broken"; - case null, E x: return String.valueOf(x); + case null, E x: return e == E.C ? "broken" : String.valueOf(x); } } @@ -316,8 +316,7 @@ public class Switches { case A -> "a"; case B -> "b"; case Object x && "C".equals(x.toString()) -> "C"; - case C -> "broken"; - case null, E x -> String.valueOf(x); + case null, E x -> e == E.C ? "broken" : String.valueOf(x); }; } @@ -326,8 +325,7 @@ public class Switches { case A: return "a"; case B: return "b"; case Runnable x && "C".equals(x.toString()): return "C"; - case C: return "broken"; - case null, E x: return String.valueOf(x); + case null, E x: return e == E.C ? "broken" : String.valueOf(x); } } @@ -336,8 +334,7 @@ public class Switches { case A -> "a"; case B -> "b"; case Runnable x && "C".equals(x.toString()) -> "C"; - case C -> "broken"; - case null, E x -> String.valueOf(x); + case null, E x -> e == E.C ? "broken" : String.valueOf(x); }; } @@ -346,8 +343,7 @@ public class Switches { case "A": return "a"; case Switches.ConstantClassClash: return "b"; case String x && "C".equals(x): return "C"; - case "C": return "broken"; - case null, String x: return String.valueOf(x); + case null, String x: return "C".equals(x) ? "broken" : String.valueOf(x); } } @@ -356,8 +352,7 @@ public class Switches { case "A" -> "a"; case ConstantClassClash -> "b"; case String x && "C".equals(x) -> "C"; - case "C" -> "broken"; - case null, String x -> String.valueOf(x); + case null, String x -> e == E.C ? "broken" : String.valueOf(x); }; } @@ -366,8 +361,7 @@ public class Switches { case 0: return "a"; case 1: return "b"; case Integer x && x.equals(2): return "C"; - case 2: return "broken"; - case null, Integer x: return String.valueOf(x); + case null, Integer x: return Objects.equals(x, 2) ? "broken" : String.valueOf(x); } } @@ -376,8 +370,7 @@ public class Switches { case 0 -> "a"; case 1 -> "b"; case Integer x && x.equals(2) -> "C"; - case 2 -> "broken"; - case null, Integer x -> String.valueOf(x); + case null, Integer x -> Objects.equals(x, 2) ? "broken" : String.valueOf(x); }; } @@ -412,7 +405,6 @@ public class Switches { switch (i) { case Integer o && o != null: r = 1; - case -1: r = 1; case null, default: r = 2; } @@ -424,7 +416,6 @@ public class Switches { int r = switch (i) { case Integer o && o != null: r = 1; - case -1: r = 1; case null, default: r = 2; yield r; @@ -603,6 +594,14 @@ public class Switches { }; } + private int switchOverPrimitiveInt(Integer i) { + return switch (i) { + case 0 -> 5 + 0; + case Integer j && j == 1 -> 6 + j; + case Integer j -> 7 + j; + }; + } + //verify that for cases like: //case ConstantClassClash -> //ConstantClassClash is interpreted as a field, not as a class diff --git a/test/langtools/tools/javac/platform/CanHandleClassFilesTest.java b/test/langtools/tools/javac/platform/CanHandleClassFilesTest.java index 8afdf54f40d20dcac1fc12bda8397c46d69ef091..ae4f525e4ee125497567bff46e80550e931606f3 100644 --- a/test/langtools/tools/javac/platform/CanHandleClassFilesTest.java +++ b/test/langtools/tools/javac/platform/CanHandleClassFilesTest.java @@ -64,7 +64,7 @@ public class CanHandleClassFilesTest { Path test = d.resolve("make/langtools/src/classes/build/tools/symbolgenerator/CreateSymbols.java"); if (Files.exists(test)) { createSymbols = test; - includeList = d.resolve("make/data/symbols/include.list"); + includeList = d.resolve("src/jdk.compiler/share/data/symbols/include.list"); break; } } diff --git a/test/langtools/tools/javac/platform/NonExportedSuperTypes.java b/test/langtools/tools/javac/platform/NonExportedSuperTypes.java new file mode 100644 index 0000000000000000000000000000000000000000..b3f17fd6e3c45df11a61ac388ee7f0b635b4dfaf --- /dev/null +++ b/test/langtools/tools/javac/platform/NonExportedSuperTypes.java @@ -0,0 +1,41 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8277106 + * @summary Verify no error is when compiling a class whose supertype is not exported. + * @modules jdk.compiler + * jdk.jfr + * @compile --release 17 NonExportedSuperTypes.java + */ + +import jdk.jfr.Event; + +public class NonExportedSuperTypes { + + public void evt(Event evt) { + evt.toString(); + } + +} diff --git a/test/langtools/tools/javac/platform/createsymbols/CreateSymbolsTest.java b/test/langtools/tools/javac/platform/createsymbols/CreateSymbolsTest.java index 2f201fd0067da1d483c0a095ed42ceaf791f44d5..c54c21bfc0d7ad330cddec0cd7b1fd0ef3d110ce 100644 --- a/test/langtools/tools/javac/platform/createsymbols/CreateSymbolsTest.java +++ b/test/langtools/tools/javac/platform/createsymbols/CreateSymbolsTest.java @@ -23,7 +23,7 @@ /** * @test - * @bug 8072480 + * @bug 8072480 8277106 * @summary Unit test for CreateSymbols * @modules java.compiler * jdk.compiler/com.sun.tools.javac.api diff --git a/test/langtools/tools/javac/platform/createsymbols/CreateSymbolsTestImpl.java b/test/langtools/tools/javac/platform/createsymbols/CreateSymbolsTestImpl.java index 42b9649311adebe6caffc6c943bf916842729e44..307c53135a774751778b1594fc6383834bdcb1b3 100644 --- a/test/langtools/tools/javac/platform/createsymbols/CreateSymbolsTestImpl.java +++ b/test/langtools/tools/javac/platform/createsymbols/CreateSymbolsTestImpl.java @@ -28,8 +28,14 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.reflect.Method; import java.util.Arrays; +import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.io.IOException; +import java.io.OutputStream; +import java.nio.charset.StandardCharsets; +import java.nio.file.DirectoryStream; import java.nio.file.FileVisitResult; import java.nio.file.FileVisitor; import java.nio.file.Files; @@ -52,6 +58,14 @@ import build.tools.symbolgenerator.CreateSymbols.ClassDescription; import build.tools.symbolgenerator.CreateSymbols.ClassList; import build.tools.symbolgenerator.CreateSymbols.ExcludeIncludeList; import build.tools.symbolgenerator.CreateSymbols.VersionDescription; +import com.sun.tools.classfile.Attribute; +import com.sun.tools.classfile.Attributes; +import com.sun.tools.classfile.ClassFile; +import com.sun.tools.classfile.ClassWriter; +import com.sun.tools.classfile.ConstantPool; +import com.sun.tools.classfile.ConstantPool.CPInfo; +import com.sun.tools.classfile.ConstantPool.CONSTANT_Utf8_info; +import com.sun.tools.classfile.ModulePackages_attribute; public class CreateSymbolsTestImpl { @@ -641,6 +655,306 @@ public class CreateSymbolsTestImpl { """); } + @Test + void testNonExportedSuperclass() throws Exception { + doTestComplex("api.Api", + """ + package api; + + public class Api extends nonapi.Impl.Nested.Exp { + + public Api(); + } + """, + """ + import api.Api; + public class Test { + private void t(Api api) { + api.run(); + } + } + """, + """ + import api.Api; + public class Test { + private void t(Api api) { + fail + } + } + """, + """ + module m { + exports api; + } + """, + """ + package api; + import nonapi.Impl; + public class Api extends Impl.Nested.Exp { + } + """, + """ + package api; + public @interface Ann { + } + """, + """ + package nonapi; + import api.Ann; + public class Impl { + public static final String C = ""; + public void test() {} + @Ann + public static class Nested { + public static class Exp extends Nested implements Runnable { + public void run() {} + public OtherNested get() { return null; } + } + } + public static class OtherNested {} + } + """); + } + + void doTestComplex(String printClass, + String expected, + String depSuccess, + String depFailure, + String... code) throws Exception { + ToolBox tb = new ToolBox(); + String testClasses = System.getProperty("test.classes"); + Path output = Paths.get(testClasses, "test-data" + i++); + deleteRecursively(output); + Files.createDirectories(output); + Path ver9Jar = output.resolve("9.jar"); + compileAndPack(output, + ver9Jar, + code); + + + Path ctSym = output.resolve("ct.sym"); + + deleteRecursively(ctSym); + + CreateSymbols.ALLOW_NON_EXISTING_CLASSES = true; + CreateSymbols.EXTENSION = ".class"; + + deleteRecursively(ctSym); + + List versions = + Arrays.asList(new VersionDescription(ver9Jar.toAbsolutePath().toString(), "9", null)); + + ExcludeIncludeList acceptAll = new ExcludeIncludeList(null, null) { + @Override public boolean accepts(String className, boolean includePrivateClasses) { + return true; + } + }; + new CreateSymbols().createBaseLine(versions, acceptAll, ctSym, new String[0]); + Path symbolsDesc = ctSym.resolve("symbols"); + Path systemModules = ctSym.resolve("systemModules"); + + Files.newBufferedWriter(systemModules).close(); + + Path classesZip = output.resolve("classes.zip"); + Path classesDir = output.resolve("classes"); + + new CreateSymbols().createSymbols(null, symbolsDesc.toAbsolutePath().toString(), classesZip.toAbsolutePath().toString(), 0, "9", systemModules.toString()); + + try (JarFile jf = new JarFile(classesZip.toFile())) { + Enumeration en = jf.entries(); + + while (en.hasMoreElements()) { + JarEntry je = en.nextElement(); + if (je.isDirectory()) continue; + Path target = classesDir.resolve(je.getName()); + Files.createDirectories(target.getParent()); + Files.copy(jf.getInputStream(je), target); + } + } + + Path classes = classesDir; + Path scratch = output.resolve("scratch"); + + Files.createDirectories(scratch); + + String modulePath; + + try (Stream elements = Files.list(classes)) { + modulePath = elements.filter(el -> el.getFileName().toString().contains("9")) + .map(el -> el.resolve("m")) + .map(el -> el.toAbsolutePath().toString()) + .collect(Collectors.joining(File.pathSeparator)); + } + + { + String out = new JavacTask(tb, Task.Mode.CMDLINE) + .options("-d", scratch.toAbsolutePath().toString(), "--module-path", modulePath, + "--add-modules", "m", "-Xprint", "api.Api") + .run(Expect.SUCCESS) + .getOutput(Task.OutputKind.STDOUT) + .replaceAll("\\R", "\n"); + + if (!out.equals(expected)) { + throw new AssertionError("out=" + out + "; expected=" + expected); + } + } + + { + new JavacTask(tb) + .options("-d", scratch.toAbsolutePath().toString(), "--module-path", modulePath, + "--add-modules", "m") + .sources(depSuccess) + .run(Expect.SUCCESS) + .writeAll(); + } + + { + String expectedFailure = new JavacTask(tb) + .options("-d", scratch.toAbsolutePath().toString(), "--module-path", output.resolve("temp").toString(), + "--add-modules", "m", "-XDrawDiagnostics") + .sources(depFailure) + .run(Expect.FAIL) + .getOutput(Task.OutputKind.DIRECT) + .replaceAll("\\R", "\n"); + + String out = new JavacTask(tb) + .options("-d", scratch.toAbsolutePath().toString(), "--module-path", modulePath, + "--add-modules", "m", "-XDrawDiagnostics") + .sources(depFailure) + .run(Expect.FAIL) + .getOutput(Task.OutputKind.DIRECT) + .replaceAll("\\R", "\n"); + + if (!out.equals(expectedFailure)) { + throw new AssertionError("out=" + out + "; expected=" + expectedFailure); + } + } + } + + @Test + void testExtendsInternalData1() throws Exception { + doTestData(""" + module name m + header exports api,nonapi[java.base] requires name\\u0020;java.base\\u0020;flags\\u0020;8000\\u0020;version\\u0020;0 flags 8000 + + class name api/Ann + header extends java/lang/Object implements java/lang/annotation/Annotation flags 2601 + + class name api/Api + header extends nonapi/Impl$Nested$Exp flags 21 + innerclass innerClass nonapi/Impl$Nested outerClass nonapi/Impl innerClassName Nested flags 9 + innerclass innerClass nonapi/Impl$Nested$Exp outerClass nonapi/Impl$Nested innerClassName Exp flags 9 + method name descriptor ()V flags 1 + + class name nonapi/Impl + header extends java/lang/Object nestMembers nonapi/Impl$Nested,nonapi/Impl$Nested$Exp flags 21 + innerclass innerClass nonapi/Impl$Nested outerClass nonapi/Impl innerClassName Nested flags 9 + innerclass innerClass nonapi/Impl$Nested$Exp outerClass nonapi/Impl$Nested innerClassName Exp flags 9 + field name C descriptor Ljava/lang/String; constantValue flags 19 + method name descriptor ()V flags 1 + method name test descriptor ()V flags 1 + + class name nonapi/Impl$Nested + header extends java/lang/Object nestHost nonapi/Impl flags 21 classAnnotations @Lapi/Ann; + innerclass innerClass nonapi/Impl$Nested outerClass nonapi/Impl innerClassName Nested flags 9 + innerclass innerClass nonapi/Impl$Nested$Exp outerClass nonapi/Impl$Nested innerClassName Exp flags 9 + method name descriptor ()V flags 1 + + class name nonapi/Impl$Nested$Exp + header extends nonapi/Impl$Nested implements java/lang/Runnable nestHost nonapi/Impl flags 21 + innerclass innerClass nonapi/Impl$Nested outerClass nonapi/Impl innerClassName Nested flags 9 + innerclass innerClass nonapi/Impl$Nested$Exp outerClass nonapi/Impl$Nested innerClassName Exp flags 9 + method name descriptor ()V flags 1 + method name run descriptor ()V flags 1 + method name get descriptor ()Lnonapi/Impl$OtherNested; flags 1 + + """, + """ + module m { + exports api; + exports nonapi to java.base; + } + """, + """ + package api; + import nonapi.Impl; + public class Api extends Impl.Nested.Exp { + } + """, + """ + package api; + public @interface Ann { + } + """, + """ + package nonapi; + import api.Ann; + public class Impl { + public static final String C = ""; + public void test() {} + @Ann + public static class Nested { + public static class Exp extends Nested implements Runnable { + public void run() {} + public OtherNested get() { return null; } + } + } + public static class OtherNested {} + } + """); + } + + void doTestData(String data, + String... code) throws Exception { + String testClasses = System.getProperty("test.classes"); + Path output = Paths.get(testClasses, "test-data" + i++); + deleteRecursively(output); + Files.createDirectories(output); + Path ver9Jar = output.resolve("9.jar"); + compileAndPack(output, + ver9Jar, + code); + + Path ctSym = output.resolve("ct.sym"); + + deleteRecursively(ctSym); + + CreateSymbols.ALLOW_NON_EXISTING_CLASSES = true; + CreateSymbols.DO_NOT_MODIFY = ""; + CreateSymbols.EXTENSION = ".class"; + CreateSymbols.INJECTED_VERSION = "0"; + + deleteRecursively(ctSym); + + List versions = + Arrays.asList(new VersionDescription(ver9Jar.toAbsolutePath().toString(), "9", null)); + + ExcludeIncludeList acceptAll = new ExcludeIncludeList(null, null) { + @Override public boolean accepts(String className, boolean includePrivateClasses) { + return true; + } + }; + new CreateSymbols().createBaseLine(versions, acceptAll, ctSym, new String[0]); + + Path symFile = null; + + try (DirectoryStream ds = Files.newDirectoryStream(ctSym)) { + for (Path p : ds) { + if (p.toString().endsWith(".sym.txt")) { + if (symFile != null) { + throw new IllegalStateException("Multiple sym files!"); + } else { + symFile = p; + } + } + } + } + String acutalContent = new String(Files.readAllBytes(symFile), StandardCharsets.UTF_8); + if (!acutalContent.equals(data)) { + throw new AssertionError("out=" + acutalContent + "; expected=" + data); + } + } + void doTestIncluded(String code, String... includedClasses) throws Exception { boolean oldIncludeAll = includeAll; try { @@ -712,7 +1026,7 @@ public class CreateSymbolsTestImpl { new VersionDescription(jar8.toAbsolutePath().toString(), "8", "7")); ExcludeIncludeList acceptAll = new ExcludeIncludeList(null, null) { - @Override public boolean accepts(String className) { + @Override public boolean accepts(String className, boolean includePrivateClasses) { return true; } }; @@ -743,6 +1057,36 @@ public class CreateSymbolsTestImpl { System.err.println(Arrays.asList(code)); new JavacTask(tb).sources(code).options("-d", scratch.toAbsolutePath().toString()).run(Expect.SUCCESS); List classFiles = collectClassFile(scratch); + Path moduleInfo = scratch.resolve("module-info.class"); + if (Files.exists(moduleInfo)) { + Set packages = new HashSet<>(); + for (String cf : classFiles) { + int sep = cf.lastIndexOf(scratch.getFileSystem().getSeparator()); + if (sep != (-1)) { + packages.add(cf.substring(0, sep)); + } + } + ClassFile cf = ClassFile.read(moduleInfo); + List cp = new ArrayList<>(); + cp.add(null); + cf.constant_pool.entries().forEach(cp::add); + Map attrs = new HashMap<>(cf.attributes.map); + int[] encodedPackages = new int[packages.size()]; + int i = 0; + for (String p : packages) { + int nameIndex = cp.size(); + cp.add(new CONSTANT_Utf8_info(p)); + encodedPackages[i++] = cp.size(); + cp.add(new ConstantPool.CONSTANT_Package_info(null, nameIndex)); + } + int attrName = cp.size(); + cp.add(new CONSTANT_Utf8_info(Attribute.ModulePackages)); + attrs.put(Attribute.ModulePackages, new ModulePackages_attribute(attrName, encodedPackages)); + ClassFile newFile = new ClassFile(cf.magic, cf.minor_version, cf.major_version, new ConstantPool(cp.toArray(new CPInfo[0])), cf.access_flags, cf.this_class, cf.super_class, cf.interfaces, cf.fields, cf.methods, new Attributes(attrs)); + try (OutputStream out = Files.newOutputStream(moduleInfo)) { + new ClassWriter().write(newFile, out); + } + } try (Writer out = Files.newBufferedWriter(outputFile)) { for (String classFile : classFiles) { try (InputStream in = Files.newInputStream(scratch.resolve(classFile))) { diff --git a/test/langtools/tools/javac/preview/classReaderTest/Client.nopreview.out b/test/langtools/tools/javac/preview/classReaderTest/Client.nopreview.out index 7c9e532800b01e458680f132a62688e5b9e50ba6..b80a19b27b4865838ae73d13a9c2e4d0cc4b36b0 100644 --- a/test/langtools/tools/javac/preview/classReaderTest/Client.nopreview.out +++ b/test/langtools/tools/javac/preview/classReaderTest/Client.nopreview.out @@ -1,2 +1,2 @@ -- compiler.err.preview.feature.disabled.classfile: Bar.class, 18 +- compiler.err.preview.feature.disabled.classfile: Bar.class, 19 1 error diff --git a/test/langtools/tools/javac/preview/classReaderTest/Client.preview.out b/test/langtools/tools/javac/preview/classReaderTest/Client.preview.out index 6a8ffbd85841acb47d790f6bcae1fdae09e0a367..df31f431c153ac96f4653a0ed6c8da5788fb016a 100644 --- a/test/langtools/tools/javac/preview/classReaderTest/Client.preview.out +++ b/test/langtools/tools/javac/preview/classReaderTest/Client.preview.out @@ -1,4 +1,4 @@ -- compiler.warn.preview.feature.use.classfile: Bar.class, 18 +- compiler.warn.preview.feature.use.classfile: Bar.class, 19 - compiler.err.warnings.and.werror 1 error 1 warning diff --git a/test/langtools/tools/javac/processing/8268575/Processor.java b/test/langtools/tools/javac/processing/8268575/Processor.java new file mode 100644 index 0000000000000000000000000000000000000000..8640c292303f6e912c5934c66daa037897b90a78 --- /dev/null +++ b/test/langtools/tools/javac/processing/8268575/Processor.java @@ -0,0 +1,79 @@ +/* + * 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 java.io.IOException; +import java.io.UncheckedIOException; +import java.io.Writer; +import java.util.Set; +import javax.annotation.processing.AbstractProcessor; +import javax.annotation.processing.RoundEnvironment; +import javax.annotation.processing.SupportedAnnotationTypes; +import javax.lang.model.SourceVersion; +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import javax.tools.Diagnostic.Kind; +import javax.tools.JavaFileObject; +import java.util.List; + +@SupportedAnnotationTypes("*") +public class Processor extends AbstractProcessor { + + @Override + public SourceVersion getSupportedSourceVersion() { + return SourceVersion.latestSupported(); + } + + int round = 1; + + @Override + public boolean process(Set annotations, RoundEnvironment roundEnv) { + processingEnv.getMessager().printMessage(Kind.NOTE, "round " + round); + Element t = processingEnv.getElementUtils().getTypeElement("T8268575"); + for (Element e : t.getEnclosedElements()) { + if (e instanceof ExecutableElement) { + for (VariableElement p : ((ExecutableElement) e).getParameters()) { + List annos = p.getAnnotationMirrors(); + if (annos.size() != 1) { + throw new RuntimeException("Missing annotation in round " + round); + } + } + } + } + if (round == 1) { + String name = "A"; + try { + JavaFileObject jfo = processingEnv.getFiler().createSourceFile(name); + try (Writer w = jfo.openWriter()) { + w.write("@interface " + name + " {}"); + } + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + round++; + return false; + } +} diff --git a/test/langtools/tools/javac/processing/8268575/T8268575.java b/test/langtools/tools/javac/processing/8268575/T8268575.java new file mode 100644 index 0000000000000000000000000000000000000000..9233dbe55d1ad7980ea29fbfbe343c9e0bf50b30 --- /dev/null +++ b/test/langtools/tools/javac/processing/8268575/T8268575.java @@ -0,0 +1,34 @@ +/* + * 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. + */ + +/** + * @test + * @bug 8268575 + * @summary Annotations not visible on model elements before they are generated + * @build Processor + * @compile -processor Processor T8268575.java + */ + +class T8268575 { + void f(@A int x) {} +} diff --git a/test/langtools/tools/javac/processing/filer/TestOriginatingElements.java b/test/langtools/tools/javac/processing/filer/TestOriginatingElements.java new file mode 100644 index 0000000000000000000000000000000000000000..a936c0bb554220eea92129709158a81957e23a52 --- /dev/null +++ b/test/langtools/tools/javac/processing/filer/TestOriginatingElements.java @@ -0,0 +1,486 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8272234 + * @summary Verify proper handling of originating elements in javac's Filer. + * @library /tools/lib + * @modules jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.main + * @build toolbox.TestRunner toolbox.ToolBox TestOriginatingElements + * @run main TestOriginatingElements + */ + +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; +import java.util.Set; + +import javax.annotation.processing.AbstractProcessor; +import javax.annotation.processing.RoundEnvironment; +import javax.annotation.processing.SupportedAnnotationTypes; +import javax.lang.model.SourceVersion; +import javax.lang.model.element.TypeElement; +import javax.tools.JavaCompiler; +import javax.tools.JavaFileObject; +import javax.tools.StandardJavaFileManager; +import javax.tools.ToolProvider; + +import java.io.IOException; +import java.io.OutputStream; +import java.net.URI; +import java.util.ArrayList; +import java.util.Base64; +import java.util.Iterator; +import javax.annotation.processing.Filer; +import javax.annotation.processing.SupportedOptions; +import javax.lang.model.element.Element; +import javax.lang.model.element.ModuleElement; +import javax.lang.model.element.PackageElement; +import javax.lang.model.util.Elements; +import javax.tools.FileObject; +import javax.tools.ForwardingJavaFileManager; +import javax.tools.JavaFileManager; +import javax.tools.SimpleJavaFileObject; +import javax.tools.StandardLocation; +import toolbox.JavacTask; +import toolbox.TestRunner; +import toolbox.TestRunner.Test; +import toolbox.ToolBox; +import toolbox.ToolBox.MemoryFileManager; + +public class TestOriginatingElements extends TestRunner { + + public static void main(String... args) throws Exception { + new TestOriginatingElements().runTests(m -> new Object[] { Paths.get(m.getName()) }); + } + + private static final JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); + private final ToolBox tb = new ToolBox(); + + public TestOriginatingElements() { + super(System.err); + } + + @Test + public void testOriginatingElements(Path outerBase) throws Exception { + Path libSrc = outerBase.resolve("lib-src"); + tb.writeJavaFiles(libSrc, + """ + module lib { exports lib1; exports lib2; } + """, + """ + package lib1; + public @interface A { + } + """, + """ + package lib2; + public class Lib { + } + """); + tb.writeFile(libSrc.resolve("lib1/package-info.java"), "@A package lib1;"); + Path libClasses = outerBase.resolve("lib-classes"); + Path libClassesModule = libClasses.resolve("lib"); + Files.createDirectories(libClassesModule); + + new JavacTask(tb) + .files(tb.findJavaFiles(libSrc)) + .outdir(libClassesModule) + .run(); + + Path src = outerBase.resolve("src"); + tb.writeJavaFiles(src, + """ + module m {} + """, + """ + package t; + public class T1 { + } + """, + """ + package t; + public class T2 { + } + """, + """ + package t; + public class T3 { + } + """); + tb.writeFile(src.resolve("p/package-info.java"), "package p;"); + Path classes = outerBase.resolve("classes"); + Files.createDirectories(classes); + try (StandardJavaFileManager sjfm = compiler.getStandardFileManager(null, null, null)) { + List testOutput = new ArrayList<>(); + JavaFileManager fm = new ForwardingJavaFileManager(sjfm) { + @Override + public JavaFileObject getJavaFileForOutputForOriginatingFiles(Location location, + String className, + JavaFileObject.Kind kind, + FileObject... originatingFiles) throws IOException { + List.of(originatingFiles) + .stream() + .map(fo -> getInfo(fo)) + .forEach(testOutput::add); + return super.getJavaFileForOutputForOriginatingFiles(location, className, kind, originatingFiles); + } + @Override + public FileObject getFileForOutputForOriginatingFiles(Location location, + String packageName, + String relativeName, + FileObject... originatingFiles) throws IOException { + List.of(originatingFiles) + .stream() + .map(fo -> getInfo(fo)) + .forEach(testOutput::add); + return super.getFileForOutputForOriginatingFiles(location, packageName, relativeName, originatingFiles); + } + private String getInfo(FileObject fo) { + try { + JavaFileObject jfo = (JavaFileObject) fo; //the test only expects JavaFileObjects here: + JavaFileManager.Location location = jfo.getKind() == JavaFileObject.Kind.SOURCE + ? StandardLocation.SOURCE_PATH + : sjfm.getLocationForModule(StandardLocation.SYSTEM_MODULES, "java.base"); + String binaryName = inferBinaryName(location, jfo); + return binaryName + "(" + jfo.getKind() + ")"; + } catch (IOException ex) { + throw new AssertionError(ex); + } + } + }; + try { + String generatedData; + try (MemoryFileManager mfm = new MemoryFileManager(sjfm)) { + compiler.getTask(null, mfm, null, null, null, + List.of(new ToolBox.JavaSource("package test; public class Generated2 {}"))) + .call(); + generatedData = + Base64.getEncoder().encodeToString(mfm.getFileBytes(StandardLocation.CLASS_OUTPUT, "test.Generated2")); + } + List options = List.of("-sourcepath", src.toString(), + "-processor", "TestOriginatingElements$P", + "-processorpath", System.getProperty("test.class.path"), + "--module-path", libClasses.toString(), + "--add-modules", "lib", + "-d", classes.toString(), + "-AgeneratedData=" + generatedData); + ToolProvider.getSystemJavaCompiler() + .getTask(null, fm, null, options, null, sjfm.getJavaFileObjects(tb.findJavaFiles(src))) + .call(); + List expectedOriginatingFiles = List.of("t.T1(SOURCE)", + "java.lang.String(CLASS)", + "p.package-info(SOURCE)", + "lib1.package-info(CLASS)", + "module-info(SOURCE)", + "module-info(CLASS)", + "t.T2(SOURCE)", + "java.lang.CharSequence(CLASS)", + "p.package-info(SOURCE)", + "lib1.package-info(CLASS)", + "module-info(SOURCE)", + "module-info(CLASS)", + "t.T3(SOURCE)", + "java.lang.Exception(CLASS)", + "p.package-info(SOURCE)", + "lib1.package-info(CLASS)", + "module-info(SOURCE)", + "module-info(CLASS)"); + assertEquals(expectedOriginatingFiles, testOutput); + } catch (IOException ex) { + throw new IllegalStateException(ex); + } + } + } + + @SupportedAnnotationTypes("*") + @SupportedOptions("generatedData") + public static class P extends AbstractProcessor { + int round; + @Override + public boolean process(Set annotations, RoundEnvironment roundEnv) { + if (round++ == 0) { + Elements elems = processingEnv.getElementUtils(); + ModuleElement mdl = elems.getModuleElement("m"); + ModuleElement java_base = elems.getModuleElement("java.base"); + PackageElement pack = elems.getPackageElement("p"); + PackageElement lib1Pack = elems.getPackageElement("lib1"); + PackageElement lib2Pack = elems.getPackageElement("lib2"); + Filer filer = processingEnv.getFiler(); + try { + filer.createSourceFile("test.Generated1", + element("t.T1"), + element("java.lang.String"), + pack, + lib1Pack, + lib2Pack, + mdl, + java_base).openOutputStream().close(); + try (OutputStream out = filer.createClassFile("test.Generated2", + element("t.T2"), + element("java.lang.CharSequence"), + pack, + lib1Pack, + lib2Pack, + mdl, + java_base).openOutputStream()) { + out.write(Base64.getDecoder().decode(processingEnv.getOptions().get("generatedData"))); + } + filer.createResource(StandardLocation.CLASS_OUTPUT, + "test", + "Generated3.txt", + element("t.T3"), + element("java.lang.Exception"), + pack, + lib1Pack, + lib2Pack, + mdl, + java_base).openOutputStream().close(); + } catch (IOException ex) { + throw new AssertionError(ex); + } + } + return false; + } + + private Element element(String type) { + return processingEnv.getElementUtils().getTypeElement(type); + } + + @Override + public SourceVersion getSupportedSourceVersion() { + return SourceVersion.latest(); + } + } + + @Test + public void testVacuousJavaFileManager(Path outerBase) throws Exception { + List log = new ArrayList<>(); + JavaFileObject expectedOut = new SimpleJavaFileObject(new URI("Out.java"), JavaFileObject.Kind.SOURCE) {}; + JavaFileManager fm = new MinimalJavaFileManager() { + @Override + public JavaFileObject getJavaFileForOutput(JavaFileManager.Location location, String className, JavaFileObject.Kind kind, FileObject sibling) throws IOException { + log.add("getJavaFileForOutput(" + location + ", " + className + ", " + kind + ", " + sibling); + return expectedOut; + } + @Override + public FileObject getFileForOutput(JavaFileManager.Location location, String packageName, String relativeName, FileObject sibling) throws IOException { + log.add("getFileForOutput(" + location + ", " + packageName + ", " + relativeName + ", " + sibling); + return expectedOut; + } + }; + + FileObject fo1 = new SimpleJavaFileObject(new URI("Test1.java"), JavaFileObject.Kind.SOURCE) { + @Override + public String toString() { + return "Test1 - FO"; + } + }; + FileObject fo2 = new SimpleJavaFileObject(new URI("Test2.java"), JavaFileObject.Kind.SOURCE) { + @Override + public String toString() { + return "Test2 - FO"; + } + }; + + assertEquals(expectedOut, + fm.getJavaFileForOutputForOriginatingFiles(StandardLocation.CLASS_OUTPUT, "test.Test", JavaFileObject.Kind.SOURCE, fo1, fo2)); + assertEquals(List.of("getJavaFileForOutput(CLASS_OUTPUT, test.Test, SOURCE, Test1 - FO"), log); log.clear(); + + assertEquals(expectedOut, + fm.getJavaFileForOutputForOriginatingFiles(StandardLocation.CLASS_OUTPUT, "test.Test", JavaFileObject.Kind.SOURCE)); + assertEquals(List.of("getJavaFileForOutput(CLASS_OUTPUT, test.Test, SOURCE, null"), log); log.clear(); + + assertEquals(expectedOut, + fm.getFileForOutputForOriginatingFiles(StandardLocation.CLASS_OUTPUT, "test", "Test.java", fo1, fo2)); + assertEquals(List.of("getFileForOutput(CLASS_OUTPUT, test, Test.java, Test1 - FO"), log); log.clear(); + assertEquals(expectedOut, + fm.getFileForOutputForOriginatingFiles(StandardLocation.CLASS_OUTPUT, "test", "Test.java")); + assertEquals(List.of("getFileForOutput(CLASS_OUTPUT, test, Test.java, null"), log); log.clear(); + } + + @Test + public void testForwardingJavaFileManager(Path outerBase) throws Exception { + List log = new ArrayList<>(); + JavaFileObject expectedOut = new SimpleJavaFileObject(new URI("Out.java"), JavaFileObject.Kind.SOURCE) {}; + + FileObject fo1 = new SimpleJavaFileObject(new URI("Test1.java"), JavaFileObject.Kind.SOURCE) { + @Override + public String toString() { + return "Test1 - FO"; + } + }; + FileObject fo2 = new SimpleJavaFileObject(new URI("Test2.java"), JavaFileObject.Kind.SOURCE) { + @Override + public String toString() { + return "Test2 - FO"; + } + }; + + JavaFileManager forwardingWithOverride = new ForwardingJavaFileManager<>(new MinimalJavaFileManager() { + @Override + public JavaFileObject getJavaFileForOutput(JavaFileManager.Location location, String className, JavaFileObject.Kind kind, FileObject sibling) throws IOException { + log.add("getJavaFileForOutput(" + location + ", " + className + ", " + kind + ", " + sibling); + return expectedOut; + } + @Override + public JavaFileObject getJavaFileForOutputForOriginatingFiles(JavaFileManager.Location location, String className, JavaFileObject.Kind kind, FileObject... originatingFiles) throws IOException { + throw new AssertionError("Should not be called."); + } + @Override + public FileObject getFileForOutput(JavaFileManager.Location location, String packageName, String relativeName, FileObject sibling) throws IOException { + log.add("getFileForOutput(" + location + ", " + packageName + ", " + relativeName + ", " + sibling); + return expectedOut; + } + @Override + public FileObject getFileForOutputForOriginatingFiles(JavaFileManager.Location location, String packageName, String relativeName, FileObject... originatingFiles) throws IOException { + throw new AssertionError("Should not be called."); + } + }) { + @Override + public JavaFileObject getJavaFileForOutput(JavaFileManager.Location location, String className, JavaFileObject.Kind kind, FileObject sibling) throws IOException { + return super.getJavaFileForOutput(location, className, kind, sibling); + } + @Override + public FileObject getFileForOutput(JavaFileManager.Location location, String packageName, String relativeName, FileObject sibling) throws IOException { + return super.getFileForOutput(location, packageName, relativeName, sibling); + } + }; + + assertEquals(expectedOut, + forwardingWithOverride.getJavaFileForOutputForOriginatingFiles(StandardLocation.CLASS_OUTPUT, "test.Test", JavaFileObject.Kind.SOURCE, fo1, fo2)); + assertEquals(List.of("getJavaFileForOutput(CLASS_OUTPUT, test.Test, SOURCE, Test1 - FO"), log); log.clear(); + + assertEquals(expectedOut, + forwardingWithOverride.getJavaFileForOutputForOriginatingFiles(StandardLocation.CLASS_OUTPUT, "test.Test", JavaFileObject.Kind.SOURCE)); + assertEquals(List.of("getJavaFileForOutput(CLASS_OUTPUT, test.Test, SOURCE, null"), log); log.clear(); + + assertEquals(expectedOut, + forwardingWithOverride.getFileForOutputForOriginatingFiles(StandardLocation.CLASS_OUTPUT, "test", "Test.java", fo1, fo2)); + assertEquals(List.of("getFileForOutput(CLASS_OUTPUT, test, Test.java, Test1 - FO"), log); log.clear(); + assertEquals(expectedOut, + forwardingWithOverride.getFileForOutputForOriginatingFiles(StandardLocation.CLASS_OUTPUT, "test", "Test.java")); + assertEquals(List.of("getFileForOutput(CLASS_OUTPUT, test, Test.java, null"), log); log.clear(); + + JavaFileManager forwardingWithOutOverride = new ForwardingJavaFileManager<>(new MinimalJavaFileManager() { + @Override + public JavaFileObject getJavaFileForOutput(JavaFileManager.Location location, String className, JavaFileObject.Kind kind, FileObject sibling) throws IOException { + throw new AssertionError("Should not be called."); + } + @Override + public JavaFileObject getJavaFileForOutputForOriginatingFiles(JavaFileManager.Location location, String className, JavaFileObject.Kind kind, FileObject... originatingFiles) throws IOException { + log.add("getJavaFileForOutputForOriginatingFiles(" + location + ", " + className + ", " + kind + ", " + List.of(originatingFiles)); + return expectedOut; + } + @Override + public FileObject getFileForOutput(JavaFileManager.Location location, String packageName, String relativeName, FileObject sibling) throws IOException { + throw new AssertionError("Should not be called."); + } + @Override + public FileObject getFileForOutputForOriginatingFiles(JavaFileManager.Location location, String packageName, String relativeName, FileObject... originatingFiles) throws IOException { + log.add("getFileForOutputForOriginatingFiles(" + location + ", " + packageName + ", " + relativeName + ", " + List.of(originatingFiles)); + return expectedOut; + } + }) {}; + + assertEquals(expectedOut, + forwardingWithOutOverride.getJavaFileForOutputForOriginatingFiles(StandardLocation.CLASS_OUTPUT, "test.Test", JavaFileObject.Kind.SOURCE, fo1, fo2)); + assertEquals(List.of("getJavaFileForOutputForOriginatingFiles(CLASS_OUTPUT, test.Test, SOURCE, [Test1 - FO, Test2 - FO]"), log); log.clear(); + + assertEquals(expectedOut, + forwardingWithOutOverride.getJavaFileForOutputForOriginatingFiles(StandardLocation.CLASS_OUTPUT, "test.Test", JavaFileObject.Kind.SOURCE)); + assertEquals(List.of("getJavaFileForOutputForOriginatingFiles(CLASS_OUTPUT, test.Test, SOURCE, []"), log); log.clear(); + + assertEquals(expectedOut, + forwardingWithOutOverride.getFileForOutputForOriginatingFiles(StandardLocation.CLASS_OUTPUT, "test", "Test.java", fo1, fo2)); + assertEquals(List.of("getFileForOutputForOriginatingFiles(CLASS_OUTPUT, test, Test.java, [Test1 - FO, Test2 - FO]"), log); log.clear(); + assertEquals(expectedOut, + forwardingWithOutOverride.getFileForOutputForOriginatingFiles(StandardLocation.CLASS_OUTPUT, "test", "Test.java")); + assertEquals(List.of("getFileForOutputForOriginatingFiles(CLASS_OUTPUT, test, Test.java, []"), log); log.clear(); + } + + class MinimalJavaFileManager implements JavaFileManager { + @Override + public ClassLoader getClassLoader(JavaFileManager.Location location) { + throw new UnsupportedOperationException("Not supported."); + } + @Override + public Iterable list(JavaFileManager.Location location, String packageName, Set kinds, boolean recurse) throws IOException { + throw new UnsupportedOperationException("Not supported."); + } + @Override + public String inferBinaryName(JavaFileManager.Location location, JavaFileObject file) { + throw new UnsupportedOperationException("Not supported."); + } + @Override + public boolean isSameFile(FileObject a, FileObject b) { + throw new UnsupportedOperationException("Not supported."); + } + @Override + public boolean handleOption(String current, Iterator remaining) { + throw new UnsupportedOperationException("Not supported."); + } + @Override + public boolean hasLocation(JavaFileManager.Location location) { + throw new UnsupportedOperationException("Not supported."); + } + @Override + public JavaFileObject getJavaFileForInput(JavaFileManager.Location location, String className, JavaFileObject.Kind kind) throws IOException { + throw new UnsupportedOperationException("Not supported."); + } + @Override + public JavaFileObject getJavaFileForOutput(JavaFileManager.Location location, String className, JavaFileObject.Kind kind, FileObject sibling) throws IOException { + throw new UnsupportedOperationException("Not supported."); + } + @Override + public FileObject getFileForInput(JavaFileManager.Location location, String packageName, String relativeName) throws IOException { + throw new UnsupportedOperationException("Not supported."); + } + @Override + public FileObject getFileForOutput(JavaFileManager.Location location, String packageName, String relativeName, FileObject sibling) throws IOException { + throw new UnsupportedOperationException("Not supported."); + } + @Override + public void flush() throws IOException { + throw new UnsupportedOperationException("Not supported."); + } + @Override + public void close() throws IOException { + throw new UnsupportedOperationException("Not supported."); + } + @Override + public int isSupportedOption(String option) { + throw new UnsupportedOperationException("Not supported."); + } + }; + + private void assertEquals(Object expected, Object actual) throws AssertionError { + if (!expected.equals(actual)) { + throw new AssertionError("Unexpected output: " + actual + ", expected: " + expected); + } + } + +} diff --git a/test/langtools/tools/javac/processing/model/element/TestElementKindPredicates.java b/test/langtools/tools/javac/processing/model/element/TestElementKindPredicates.java index 77b31540926b48efdd9858b1346fff9db614a2d5..49b3c72ac39b05d812fd2c142a14f7c635dd279d 100644 --- a/test/langtools/tools/javac/processing/model/element/TestElementKindPredicates.java +++ b/test/langtools/tools/javac/processing/model/element/TestElementKindPredicates.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -23,7 +23,7 @@ /* * @test - * @bug 8222430 + * @bug 8222430 8282411 * @summary Test various predicates of ElementKind. */ @@ -38,24 +38,64 @@ public class TestElementKindPredicates { public static void main(String... args) { Set ALL_KINDS = Set.of(ElementKind.values()); - // isClass: Returns true if this is a kind of class: either CLASS or ENUM. + // isClass: Returns true if this is a kind of class:CLASS, ENUM, or RECORD. test(ALL_KINDS, (ElementKind k) -> Set.of(ElementKind.CLASS, ElementKind.ENUM, ElementKind.RECORD).contains(k), (ElementKind k) -> k.isClass(), "isClass"); - // isField: Returns true if this is a kind of field: either FIELD or ENUM_CONSTANT. + // isField: Returns true if this is a kind of field: one of + // FIELD or ENUM_CONSTANT. test(ALL_KINDS, (ElementKind k) -> Set.of(ElementKind.FIELD, ElementKind.ENUM_CONSTANT).contains(k), (ElementKind k) -> k.isField(), "isField"); - // isInterface: Returns true if this is a kind of interface: either INTERFACE or ANNOTATION_TYPE. + // isInterface: Returns true if this is a kind of interface: + // either INTERFACE or ANNOTATION_TYPE. test(ALL_KINDS, (ElementKind k) -> Set.of(ElementKind.INTERFACE, ElementKind.ANNOTATION_TYPE).contains(k), (ElementKind k) -> k.isInterface(), "isInterface"); + + // isDeclaredType: Returns true if this is a kind of class or interface + test(ALL_KINDS, + (ElementKind k) -> Set.of(ElementKind.CLASS, + ElementKind.ENUM, + ElementKind.RECORD, + ElementKind.INTERFACE, + ElementKind.ANNOTATION_TYPE).contains(k), + (ElementKind k) -> k.isDeclaredType(), "isDeclaredType"); + + // isExecutable: Returns true if this is a kind of executable: one of + // METHOD, CONSTRUCTOR, STATIC_INIT, INSTANCE_INIT + test(ALL_KINDS, + (ElementKind k) -> Set.of(ElementKind.METHOD, + ElementKind.CONSTRUCTOR, + ElementKind.STATIC_INIT, + ElementKind.INSTANCE_INIT).contains(k), + (ElementKind k) -> k.isExecutable(), "isExecutable"); + + // isInitializer: Returns true if this is a kind of initializer: one of + // STATIC_INIT, INSTANCE_INIT + test(ALL_KINDS, + (ElementKind k) -> Set.of(ElementKind.STATIC_INIT, + ElementKind.INSTANCE_INIT).contains(k), + (ElementKind k) -> k.isInitializer(), "isInitializer"); + + // isVariable: Returns true if this is a kind of variable: one of + // ENUM_CONSTANT, FIELD, PARAMETER, LOCAL_VARIABLE, EXCEPTION_PARAMETER + // RESOURCE_VARIABLE, BINDING_VARIABLE + test(ALL_KINDS, + (ElementKind k) -> Set.of(ElementKind.ENUM_CONSTANT, + ElementKind.FIELD, + ElementKind.PARAMETER, + ElementKind.LOCAL_VARIABLE, + ElementKind.EXCEPTION_PARAMETER, + ElementKind.RESOURCE_VARIABLE, + ElementKind.BINDING_VARIABLE).contains(k), + (ElementKind k) -> k.isVariable(), "isVariable"); } private static void test(Set kinds, diff --git a/test/langtools/tools/javac/processing/model/element/TestFileObjectOf.java b/test/langtools/tools/javac/processing/model/element/TestFileObjectOf.java new file mode 100644 index 0000000000000000000000000000000000000000..1957d00ea4a0ed1d1771c6c4efff959be4847c8c --- /dev/null +++ b/test/langtools/tools/javac/processing/model/element/TestFileObjectOf.java @@ -0,0 +1,596 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8224922 + * @summary Verify the behavior of the Elements.getFileObjectOf + * @library /tools/lib + * @modules jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.main + * jdk.jdeps/com.sun.tools.classfile + * @build toolbox.ToolBox toolbox.JavacTask toolbox.TestRunner + * @build TestFileObjectOf + * @run main TestFileObjectOf + */ + +import com.sun.source.tree.VariableTree; +import com.sun.source.util.TreePath; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayDeque; +import java.util.List; +import java.util.Queue; +import java.util.Set; + +import javax.annotation.processing.*; +import javax.lang.model.SourceVersion; +import javax.lang.model.element.*; +import javax.lang.model.util.Elements; + +import com.sun.source.util.TreePathScanner; +import com.sun.source.util.Trees; +import javax.tools.JavaFileObject; +import toolbox.JarTask; +import toolbox.JavacTask; +import toolbox.Task; +import toolbox.TestRunner; +import toolbox.ToolBox; + +public class TestFileObjectOf extends TestRunner { + + private final ToolBox tb; + + TestFileObjectOf() { + super(System.err); + tb = new ToolBox(); + } + + public static void main(String... args) throws Exception { + new TestFileObjectOf().runTests(m -> new Object[] { Paths.get(m.getName()) }); + } + + @Test + public void testSourceFiles(Path base) throws Exception { + Path src = base.resolve("src"); + tb.writeJavaFiles(src, + """ + module m {} + """, + """ + package test; + """, + """ + package test; + public class TestClass { + int fieldTestClass; + TestClass() { } + void methodTestClass(int parameterTestClass) { + int localTestClass; + } + public static class InnerClass { + int fieldInnerClass; + InnerClass() {} + void methodInnerClass(int parameterInnerClass) { + int localInnerClass; + } + } + } + """, + """ + package test; + public enum TestEnum { + CONSTANT; + } + """, + """ + package test2; + public class TestClass2 {} + """); + Path classes = base.resolve("classes").resolve("m"); + tb.createDirectories(classes); + + //from source, implicit: + { + String moduleInfoSource = src.resolve("module-info.java").toUri().toString(); + String packageInfoSource = src.resolve("test").resolve("package-info.java").toUri().toString(); + String testClassSource = src.resolve("test").resolve("TestClass.java").toUri().toString(); + String testEnumSource = src.resolve("test").resolve("TestEnum.java").toUri().toString(); + String testClass2Source = src.resolve("test2").resolve("TestClass2.java").toUri().toString(); + + List log; + + log = new JavacTask(tb) + .options("-Xpkginfo:always", + "-processorpath", System.getProperty("test.classes"), + "-processor", PrintFiles.class.getName(), + "-sourcepath", src.toString()) + .outdir(classes) + .classes("java.lang.Object") + .run() + .writeAll() + .getOutputLines(Task.OutputKind.STDOUT); + + List expected = List.of( + "m: " + moduleInfoSource, + "test: " + packageInfoSource, + "test2: " + "", + "TestClass: " + testClassSource, + "TestEnum: " + testEnumSource, + "TestClass2: " + testClass2Source, + ": " + testClassSource, + "InnerClass: " + testClassSource, + "fieldTestClass: " + testClassSource, + "methodTestClass: " + testClassSource, + "parameterTestClass: " + testClassSource, + "localTestClass: " + testClassSource, + ": " + testEnumSource, + "CONSTANT: " + testEnumSource, + "valueOf: " + testEnumSource, + "values: " + testEnumSource, + ": " + testClass2Source, + ": " + testClassSource, + "fieldInnerClass: " + testClassSource, + "methodInnerClass: " + testClassSource, + "parameterInnerClass: " + testClassSource, + "localInnerClass: " + testClassSource + ); + + if (!expected.equals(log)) + throw new AssertionError("expected output not found: " + log); + } + + tb.cleanDirectory(classes); + + //from source, explicit: + { + String moduleInfoSource = src.resolve("module-info.java").toUri().toString(); + String packageInfoSource = src.resolve("test").resolve("package-info.java").toUri().toString(); + String testClassSource = src.resolve("test").resolve("TestClass.java").toUri().toString(); + String testEnumSource = src.resolve("test").resolve("TestEnum.java").toUri().toString(); + String testClass2Source = src.resolve("test2").resolve("TestClass2.java").toUri().toString(); + + List log; + + log = new JavacTask(tb) + .options("-Xpkginfo:always", + "-processorpath", System.getProperty("test.classes"), + "-processor", PrintFiles.class.getName()) + .outdir(classes) + .files(tb.findJavaFiles(src)) + .run() + .writeAll() + .getOutputLines(Task.OutputKind.STDOUT); + + List expected = List.of( + "m: " + moduleInfoSource, + "test: " + packageInfoSource, + "test2: " + "", + "TestClass: " + testClassSource, + "TestEnum: " + testEnumSource, + "TestClass2: " + testClass2Source, + ": " + testClassSource, + "InnerClass: " + testClassSource, + "fieldTestClass: " + testClassSource, + "methodTestClass: " + testClassSource, + "parameterTestClass: " + testClassSource, + "localTestClass: " + testClassSource, + ": " + testEnumSource, + "CONSTANT: " + testEnumSource, + "valueOf: " + testEnumSource, + "values: " + testEnumSource, + ": " + testClass2Source, + ": " + testClassSource, + "fieldInnerClass: " + testClassSource, + "methodInnerClass: " + testClassSource, + "parameterInnerClass: " + testClassSource, + "localInnerClass: " + testClassSource + ); + + if (!expected.equals(log)) + throw new AssertionError("expected output not found: " + log); + } + + //from class: + { + String moduleInfoSource = classes.resolve("module-info.class").toUri().toString(); + String packageInfoSource = classes.resolve("test").resolve("package-info.class").toUri().toString(); + String testClassSource = classes.resolve("test").resolve("TestClass.class").toUri().toString(); + String testInnerClassSource = classes.resolve("test").resolve("TestClass$InnerClass.class").toUri().toString(); + String testEnumSource = classes.resolve("test").resolve("TestEnum.class").toUri().toString(); + String testClass2Source = classes.resolve("test2").resolve("TestClass2.class").toUri().toString(); + + List log; + + log = new JavacTask(tb) + .options("-processorpath", System.getProperty("test.classes"), + "-processor", PrintFiles.class.getName(), + "--module-path", classes.toString(), + "--add-modules", "m") + .outdir(classes) + .classes("java.lang.Object") + .run() + .writeAll() + .getOutputLines(Task.OutputKind.STDOUT); + + List expected = List.of( + "m: " + moduleInfoSource, + "test: " + packageInfoSource, + "test2: " + "", + "TestClass: " + testClassSource, + "TestEnum: " + testEnumSource, + "TestClass2: " + testClass2Source, + ": " + testClassSource, + "InnerClass: " + testInnerClassSource, + "fieldTestClass: " + testClassSource, + "methodTestClass: " + testClassSource, + ": " + testEnumSource, + ": " + testEnumSource, + "CONSTANT: " + testEnumSource, + "valueOf: " + testEnumSource, + "values: " + testEnumSource, + ": " + testClass2Source, + ": " + testInnerClassSource, + "fieldInnerClass: " + testInnerClassSource, + "methodInnerClass: " + testInnerClassSource + ); + + if (!expected.equals(log)) + throw new AssertionError("expected output not found: " + log); + } + } + + @SupportedAnnotationTypes("*") + @SupportedOptions("fromClass") + public static final class PrintFiles extends AbstractProcessor { + + @Override + public boolean process(Set annotations, RoundEnvironment roundEnv) { + if (!roundEnv.processingOver()) + return false; + + Elements elements = processingEnv.getElementUtils(); + Trees trees = Trees.instance(processingEnv); + Queue q = new ArrayDeque<>(); + q.add(elements.getModuleElement("m")); + + while (!q.isEmpty()) { + Element currentElement = q.remove(); + + handleDeclaration(currentElement); + + switch (currentElement.getKind()) { + case METHOD -> { + ExecutableElement method = (ExecutableElement) currentElement; + TreePath tp = trees.getPath(method); + if (tp != null) { + new TreePathScanner<>() { + @Override + public Object visitVariable(VariableTree node, Object p) { + Element el = trees.getElement(getCurrentPath()); + handleDeclaration(el); + return super.visitVariable(node, p); + } + }.scan(tp, null); + } + } + case MODULE -> { + q.add(elements.getPackageElement("test")); + q.add(elements.getPackageElement("test2")); + } + default -> + currentElement.getEnclosedElements() + .stream() + .sorted((e1, e2) -> e1.getSimpleName().toString().compareTo(e2.getSimpleName().toString())) + .forEach(q::add); + } + } + + return false; + } + + void handleDeclaration(Element el) { + Elements elements = processingEnv.getElementUtils(); + JavaFileObject fileObjects = elements.getFileObjectOf(el); + System.out.println(el.getSimpleName() + ": " + (fileObjects != null ? fileObjects.toUri().toString() : "")); + } + + @Override + public SourceVersion getSupportedSourceVersion() { + return SourceVersion.latestSupported(); + } + + } + + @Test + public void testUnnamed(Path base) throws Exception { + Path src = base.resolve("src"); + tb.writeJavaFiles(src, + """ + public class TestClass { + } + """); + Path classes = base.resolve("classes"); + tb.createDirectories(classes); + + //from source, implicit: + { + String testClassSource = src.resolve("TestClass.java").toUri().toString(); + + List log; + + log = new JavacTask(tb) + .options("-Xpkginfo:always", + "-classpath", "", + "-processorpath", System.getProperty("test.classes"), + "-processor", UnnamedPrintFiles.class.getName(), + "-sourcepath", src.toString()) + .outdir(classes) + .classes("java.lang.Object") + .run() + .writeAll() + .getOutputLines(Task.OutputKind.STDOUT); + + List expected = List.of( + ": " + "", + ": " + "", + "TestClass: " + testClassSource, + ": " + testClassSource + ); + + if (!expected.equals(log)) + throw new AssertionError("expected output not found: " + log); + } + + tb.cleanDirectory(classes); + + //from source, explicit: + { + String testClassSource = src.resolve("TestClass.java").toUri().toString(); + + List log; + + log = new JavacTask(tb) + .options("-Xpkginfo:always", + "-classpath", "", + "-processorpath", System.getProperty("test.classes"), + "-processor", UnnamedPrintFiles.class.getName()) + .outdir(classes) + .files(tb.findJavaFiles(src)) + .run() + .writeAll() + .getOutputLines(Task.OutputKind.STDOUT); + + List expected = List.of( + ": " + "", + ": " + "", + "TestClass: " + testClassSource, + ": " + testClassSource + ); + + if (!expected.equals(log)) + throw new AssertionError("expected output not found: " + log); + } + + //from class: + { + String testClassSource = classes.resolve("TestClass.class").toUri().toString(); + + List log; + + log = new JavacTask(tb) + .options("-processorpath", System.getProperty("test.classes"), + "-processor", UnnamedPrintFiles.class.getName(), + "-classpath", classes.toString()) + .outdir(classes) + .classes("java.lang.Object") + .run() + .writeAll() + .getOutputLines(Task.OutputKind.STDOUT); + + List expected = List.of( + ": " + "", + ": " + "", + "TestClass: " + testClassSource, + ": " + testClassSource + ); + + if (!expected.equals(log)) + throw new AssertionError("expected output not found: " + log); + } + } + + @SupportedAnnotationTypes("*") + @SupportedOptions("fromClass") + public static final class UnnamedPrintFiles extends AbstractProcessor { + + @Override + public boolean process(Set annotations, RoundEnvironment roundEnv) { + if (!roundEnv.processingOver()) + return false; + + Elements elements = processingEnv.getElementUtils(); + Trees trees = Trees.instance(processingEnv); + Queue q = new ArrayDeque<>(); + q.add(elements.getModuleElement("")); + + while (!q.isEmpty()) { + Element currentElement = q.remove(); + + handleDeclaration(currentElement); + + switch (currentElement.getKind()) { + case METHOD -> { + ExecutableElement method = (ExecutableElement) currentElement; + TreePath tp = trees.getPath(method); + if (tp != null) { + new TreePathScanner<>() { + @Override + public Object visitVariable(VariableTree node, Object p) { + Element el = trees.getElement(getCurrentPath()); + handleDeclaration(el); + return super.visitVariable(node, p); + } + }.scan(tp, null); + } + } + case MODULE -> { + q.add(elements.getPackageElement("")); + } + default -> + currentElement.getEnclosedElements() + .stream() + .sorted((e1, e2) -> e1.getSimpleName().toString().compareTo(e2.getSimpleName().toString())) + .forEach(q::add); + } + } + + return false; + } + + void handleDeclaration(Element el) { + Elements elements = processingEnv.getElementUtils(); + JavaFileObject fileObjects = elements.getFileObjectOf(el); + System.out.println(el.getSimpleName() + ": " + (fileObjects != null ? fileObjects.toUri().toString() : "")); + } + + @Override + public SourceVersion getSupportedSourceVersion() { + return SourceVersion.latestSupported(); + } + + } + + @Test + public void testAutomaticModule(Path base) throws Exception { + Path src = base.resolve("src"); + tb.writeJavaFiles(src, + """ + package test; + public class TestClass { + } + """); + Path classes = base.resolve("classes"); + tb.createDirectories(classes); + + Path module = base.resolve("m.jar"); + + new JavacTask(tb) + .options("-classpath", "") + .outdir(classes) + .files(tb.findJavaFiles(src)) + .run() + .writeAll(); + new JarTask(tb, module) + .baseDir(classes) + .files(".") + .run(); + + String testClassSource = "jar:" + module.toUri().toString() + "!/test/TestClass.class"; + + List log; + + log = new JavacTask(tb) + .options("-processorpath", System.getProperty("test.classes"), + "-processor", AutomaticModulePrintFiles.class.getName(), + "--module-path", module.toString(), + "--add-modules", "m") + .outdir(classes) + .classes("java.lang.Object") + .run() + .writeAll() + .getOutputLines(Task.OutputKind.STDOUT); + + List expected = List.of( + "m: " + "", + "test: " + "", + "TestClass: " + testClassSource, + ": " + testClassSource + ); + + if (!expected.equals(log)) + throw new AssertionError("expected output not found: " + log); + } + + @SupportedAnnotationTypes("*") + @SupportedOptions("fromClass") + public static final class AutomaticModulePrintFiles extends AbstractProcessor { + + @Override + public boolean process(Set annotations, RoundEnvironment roundEnv) { + if (!roundEnv.processingOver()) + return false; + + Elements elements = processingEnv.getElementUtils(); + Trees trees = Trees.instance(processingEnv); + Queue q = new ArrayDeque<>(); + q.add(elements.getModuleElement("m")); + + while (!q.isEmpty()) { + Element currentElement = q.remove(); + + handleDeclaration(currentElement); + + switch (currentElement.getKind()) { + case METHOD -> { + ExecutableElement method = (ExecutableElement) currentElement; + TreePath tp = trees.getPath(method); + if (tp != null) { + new TreePathScanner<>() { + @Override + public Object visitVariable(VariableTree node, Object p) { + Element el = trees.getElement(getCurrentPath()); + handleDeclaration(el); + return super.visitVariable(node, p); + } + }.scan(tp, null); + } + } + case MODULE -> { + q.add(elements.getPackageElement("test")); + } + default -> + currentElement.getEnclosedElements() + .stream() + .sorted((e1, e2) -> e1.getSimpleName().toString().compareTo(e2.getSimpleName().toString())) + .forEach(q::add); + } + } + + return false; + } + + void handleDeclaration(Element el) { + Elements elements = processingEnv.getElementUtils(); + JavaFileObject fileObjects = elements.getFileObjectOf(el); + System.out.println(el.getSimpleName() + ": " + (fileObjects != null ? fileObjects.toUri().toString() : "")); + } + + @Override + public SourceVersion getSupportedSourceVersion() { + return SourceVersion.latestSupported(); + } + + } + +} diff --git a/test/langtools/tools/javac/processing/model/element/TestListPackageFromAPI.java b/test/langtools/tools/javac/processing/model/element/TestListPackageFromAPI.java new file mode 100644 index 0000000000000000000000000000000000000000..358be012617062e0884bd0a790a3796672787b21 --- /dev/null +++ b/test/langtools/tools/javac/processing/model/element/TestListPackageFromAPI.java @@ -0,0 +1,149 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8278930 + * @summary Check that when a package has Elements listed from both from classes and sources, + * and then a nested class is completed, it is not first completed from source via + * its enclosing class, and then again for itself. + * @library /tools/javac/lib + * @modules java.compiler + * jdk.compiler + * @run main TestListPackageFromAPI + */ + +import com.sun.source.util.JavacTask; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import javax.lang.model.element.PackageElement; +import javax.tools.DiagnosticListener; +import javax.tools.ForwardingJavaFileManager; +import javax.tools.JavaFileManager; +import javax.tools.JavaFileObject; +import javax.tools.JavaFileObject.Kind; +import javax.tools.SimpleJavaFileObject; +import javax.tools.StandardLocation; +import javax.tools.ToolProvider; + +public class TestListPackageFromAPI { + + public static void main(String... args) throws IOException, URISyntaxException, InterruptedException { + try (JavaFileManager fm = ToolProvider.getSystemJavaCompiler().getStandardFileManager(null, null, null)) { + List testClasses = List.of( + new TestFileObject("Test"), + new TestFileObject("Test$Nested") + ); + List testSources = List.of( + new TestFileObject("Test", + """ + class Test { + public static class Nested {} + } + """) + ); + JavaFileManager testFM = new ForwardingJavaFileManagerImpl(fm, testClasses, testSources); + DiagnosticListener noErrors = d -> { throw new AssertionError("Should not happen: " + d); }; + JavacTask task = (JavacTask) ToolProvider.getSystemJavaCompiler().getTask(null, testFM, noErrors, null, null, List.of(new TestFileObject("Input", ""))); + PackageElement pack = task.getElements().getPackageElement(""); + pack.getEnclosedElements().forEach(e -> System.err.println(e)); + } + } + + private static class TestFileObject extends SimpleJavaFileObject { + + private final String className; + private final String code; + + public TestFileObject(String className) throws URISyntaxException { + super(new URI("mem://" + className + ".class"), Kind.CLASS); + this.className = className; + this.code = null; + } + + public TestFileObject(String className, String code) throws URISyntaxException { + super(new URI("mem://" + className + ".java"), Kind.SOURCE); + this.className = className; + this.code = code; + } + + @Override + public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException { + if (code == null) { + throw new UnsupportedOperationException(); + } + return code; + } + + @Override + public long getLastModified() { + return getKind() == Kind.CLASS ? 0 : 1000; + } + + } + + private static class ForwardingJavaFileManagerImpl extends ForwardingJavaFileManager { + + private final List testClasses; + private final List testSources; + + public ForwardingJavaFileManagerImpl(JavaFileManager fileManager, List testClasses, List testSources) { + super(fileManager); + this.testClasses = testClasses; + this.testSources = testSources; + } + + @Override + public Iterable list(JavaFileManager.Location location, String packageName, Set kinds, boolean recurse) throws IOException { + if (packageName.isEmpty()) { + List result = new ArrayList<>(); + if (location == StandardLocation.CLASS_PATH && kinds.contains(Kind.CLASS)) { + result.addAll(testClasses); + } else if (location == StandardLocation.SOURCE_PATH && kinds.contains(Kind.SOURCE)) { + result.addAll(testSources); + } + return result; + } + return super.list(location, packageName, kinds, recurse); + } + + @Override + public boolean hasLocation(Location location) { + return location == StandardLocation.CLASS_PATH || + location == StandardLocation.SOURCE_PATH || + super.hasLocation(location); + } + + @Override + public String inferBinaryName(JavaFileManager.Location location, JavaFileObject file) { + if (file instanceof TestFileObject testFO) { + return testFO.className; + } + return super.inferBinaryName(location, file); + } + } +} diff --git a/test/langtools/tools/javac/records/BigRecordsToStringTest.java b/test/langtools/tools/javac/records/BigRecordsToStringTest.java new file mode 100644 index 0000000000000000000000000000000000000000..87e269a95324880b17ae99a1910e2cc078825796 --- /dev/null +++ b/test/langtools/tools/javac/records/BigRecordsToStringTest.java @@ -0,0 +1,171 @@ +/* + * 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. + */ + +/** + * @test + * @bug 8261847 + * @summary test the output of the toString method of records with a large number of components + * @run testng BigRecordsToStringTest + */ + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.lang.reflect.Parameter; +import java.util.List; +import java.util.function.Supplier; + +import org.testng.annotations.*; +import static org.testng.Assert.*; + +@Test +public class BigRecordsToStringTest { + record BigInt( + 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,int i55,int i56,int i57,int i58,int i59,int i60, + int i61,int i62,int i63,int i64,int i65,int i66,int i67,int i68,int i69,int i70, + int i71,int i72,int i73,int i74,int i75,int i76,int i77,int i78,int i79,int i80, + int i81,int i82,int i83,int i84,int i85,int i86,int i87,int i88,int i89,int i90, + int i91,int i92,int i93,int i94,int i95,int i96,int i97,int i98,int i99,int i100, + int i101,int i102,int i103,int i104,int i105,int i106,int i107,int i108,int i109,int i110, + int i111,int i112,int i113,int i114,int i115,int i116,int i117,int i118,int i119,int i120, + int i121,int i122,int i123,int i124,int i125,int i126,int i127,int i128,int i129,int i130, + int i131,int i132,int i133,int i134,int i135,int i136,int i137,int i138,int i139,int i140, + int i141,int i142,int i143,int i144,int i145,int i146,int i147,int i148,int i149,int i150, + int i151,int i152,int i153,int i154,int i155,int i156,int i157,int i158,int i159,int i160, + int i161,int i162,int i163,int i164,int i165,int i166,int i167,int i168,int i169,int i170, + int i171,int i172,int i173,int i174,int i175,int i176,int i177,int i178,int i179,int i180, + int i181,int i182,int i183,int i184,int i185,int i186,int i187,int i188,int i189,int i190, + int i191,int i192,int i193,int i194,int i195,int i196,int i197,int i198,int i199, int i200, + int i201,int i202,int i203,int i204,int i205,int i206,int i207,int i208,int i209,int i210, + int i211,int i212,int i213,int i214,int i215,int i216,int i217,int i218,int i219,int i220, + int i221,int i222,int i223,int i224,int i225,int i226,int i227,int i228,int i229,int i230, + int i231,int i232,int i233,int i234,int i235,int i236,int i237,int i238,int i239,int i240, + int i241,int i242,int i243,int i244,int i245,int i246,int i247,int i248,int i249,int i250, + int i251,int i252,int i253,int i254 + ) {} + + BigInt bigInt= new BigInt( + 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,55,56,57,58,59,60, + 61,62,63,64,65,66,67,68,69,70, + 71,72,73,74,75,76,77,78,79,80, + 81,82,83,84,85,86,87,88,89,90, + 91,92,93,94,95,96,97,98,99,100, + 101,102,103,104,105,106,107,108,109,110, + 111,112,113,114,115,116,117,118,119,120, + 121,122,123,124,125,126,127,128,129,130, + 131,132,133,134,135,136,137,138,139,140, + 141,142,143,144,145,146,147,148,149,150, + 151,152,153,154,155,156,157,158,159,160, + 161,162,163,164,165,166,167,168,169,170, + 171,172,173,174,175,176,177,178,179,180, + 181,182,183,184,185,186,187,188,189,190, + 191,192,193,194,195,196,197,198,199, 200, + 201,202,203,204,205,206,207,208,209,210, + 211,212,213,214,215,216,217,218,219,220, + 221,222,223,224,225,226,227,228,229,230, + 231,232,233,234,235,236,237,238,239,240, + 241,242,243,244,245,246,247,248,249,250, + 251,252,253,254 + ); + + record BigLong( + long i1,long i2,long i3,long i4,long i5,long i6,long i7,long i8,long i9,long i10, + long i11,long i12,long i13,long i14,long i15,long i16,long i17,long i18,long i19,long i20, + long i21,long i22,long i23,long i24,long i25,long i26,long i27,long i28,long i29,long i30, + long i31,long i32,long i33,long i34,long i35,long i36,long i37,long i38,long i39,long i40, + long i41,long i42,long i43,long i44,long i45,long i46,long i47,long i48,long i49,long i50, + long i51,long i52,long i53,long i54,long i55,long i56,long i57,long i58,long i59,long i60, + long i61,long i62,long i63,long i64,long i65,long i66,long i67,long i68,long i69,long i70, + long i71,long i72,long i73,long i74,long i75,long i76,long i77,long i78,long i79,long i80, + long i81,long i82,long i83,long i84,long i85,long i86,long i87,long i88,long i89,long i90, + long i91,long i92,long i93,long i94,long i95,long i96,long i97,long i98,long i99,long i100, + long i101,long i102,long i103,long i104,long i105,long i106,long i107,long i108,long i109,long i110, + long i111,long i112,long i113,long i114,long i115,long i116,long i117,long i118,long i119,long i120, + long i121,long i122,long i123,long i124,long i125,long i126,long i127 + ) {} + + BigLong bigLong = new BigLong( + 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,55,56,57,58,59,60, + 61,62,63,64,65,66,67,68,69,70, + 71,72,73,74,75,76,77,78,79,80, + 81,82,83,84,85,86,87,88,89,90, + 91,92,93,94,95,96,97,98,99,100, + 101,102,103,104,105,106,107,108,109,110, + 111,112,113,114,115,116,117,118,119,120, + 121,122,123,124,125,126,127 + ); + + private static final String BIG_INT_TO_STRING_OUTPUT = + "BigInt[i1=1, i2=2, i3=3, i4=4, i5=5, i6=6, i7=7, i8=8, i9=9, i10=10, i11=11, i12=12, i13=13, i14=14, i15=15, i16=16, " + + "i17=17, i18=18, i19=19, i20=20, i21=21, i22=22, i23=23, i24=24, i25=25, i26=26, i27=27, i28=28, i29=29, i30=30, " + + "i31=31, i32=32, i33=33, i34=34, i35=35, i36=36, i37=37, i38=38, i39=39, i40=40, i41=41, i42=42, i43=43, i44=44, " + + "i45=45, i46=46, i47=47, i48=48, i49=49, i50=50, i51=51, i52=52, i53=53, i54=54, i55=55, i56=56, i57=57, i58=58, " + + "i59=59, i60=60, i61=61, i62=62, i63=63, i64=64, i65=65, i66=66, i67=67, i68=68, i69=69, i70=70, i71=71, i72=72, " + + "i73=73, i74=74, i75=75, i76=76, i77=77, i78=78, i79=79, i80=80, i81=81, i82=82, i83=83, i84=84, i85=85, i86=86, " + + "i87=87, i88=88, i89=89, i90=90, i91=91, i92=92, i93=93, i94=94, i95=95, i96=96, i97=97, i98=98, i99=99, i100=100, " + + "i101=101, i102=102, i103=103, i104=104, i105=105, i106=106, i107=107, i108=108, i109=109, i110=110, i111=111, i112=112, " + + "i113=113, i114=114, i115=115, i116=116, i117=117, i118=118, i119=119, i120=120, i121=121, i122=122, i123=123, i124=124, " + + "i125=125, i126=126, i127=127, i128=128, i129=129, i130=130, i131=131, i132=132, i133=133, i134=134, i135=135, i136=136, " + + "i137=137, i138=138, i139=139, i140=140, i141=141, i142=142, i143=143, i144=144, i145=145, i146=146, i147=147, i148=148, " + + "i149=149, i150=150, i151=151, i152=152, i153=153, i154=154, i155=155, i156=156, i157=157, i158=158, i159=159, i160=160, " + + "i161=161, i162=162, i163=163, i164=164, i165=165, i166=166, i167=167, i168=168, i169=169, i170=170, i171=171, i172=172, " + + "i173=173, i174=174, i175=175, i176=176, i177=177, i178=178, i179=179, i180=180, i181=181, i182=182, i183=183, i184=184, " + + "i185=185, i186=186, i187=187, i188=188, i189=189, i190=190, i191=191, i192=192, i193=193, i194=194, i195=195, i196=196, " + + "i197=197, i198=198, i199=199, i200=200, i201=201, i202=202, i203=203, i204=204, i205=205, i206=206, i207=207, i208=208, " + + "i209=209, i210=210, i211=211, i212=212, i213=213, i214=214, i215=215, i216=216, i217=217, i218=218, i219=219, i220=220, " + + "i221=221, i222=222, i223=223, i224=224, i225=225, i226=226, i227=227, i228=228, i229=229, i230=230, i231=231, i232=232, " + + "i233=233, i234=234, i235=235, i236=236, i237=237, i238=238, i239=239, i240=240, i241=241, i242=242, i243=243, i244=244, " + + "i245=245, i246=246, i247=247, i248=248, i249=249, i250=250, i251=251, i252=252, i253=253, i254=254]"; + + private static final String BIG_LONG_TO_STRING_OUTPUT = + "BigLong[i1=1, i2=2, i3=3, i4=4, i5=5, i6=6, i7=7, i8=8, i9=9, i10=10, i11=11, i12=12, i13=13, i14=14, i15=15, i16=16, i17=17, " + + "i18=18, i19=19, i20=20, i21=21, i22=22, i23=23, i24=24, i25=25, i26=26, i27=27, i28=28, i29=29, i30=30, i31=31, i32=32, i33=33, " + + "i34=34, i35=35, i36=36, i37=37, i38=38, i39=39, i40=40, i41=41, i42=42, i43=43, i44=44, i45=45, i46=46, i47=47, i48=48, i49=49, " + + "i50=50, i51=51, i52=52, i53=53, i54=54, i55=55, i56=56, i57=57, i58=58, i59=59, i60=60, i61=61, i62=62, i63=63, i64=64, i65=65, " + + "i66=66, i67=67, i68=68, i69=69, i70=70, i71=71, i72=72, i73=73, i74=74, i75=75, i76=76, i77=77, i78=78, i79=79, i80=80, i81=81, " + + "i82=82, i83=83, i84=84, i85=85, i86=86, i87=87, i88=88, i89=89, i90=90, i91=91, i92=92, i93=93, i94=94, i95=95, i96=96, i97=97, " + + "i98=98, i99=99, i100=100, i101=101, i102=102, i103=103, i104=104, i105=105, i106=106, i107=107, i108=108, i109=109, i110=110, " + + "i111=111, i112=112, i113=113, i114=114, i115=115, i116=116, i117=117, i118=118, i119=119, i120=120, i121=121, i122=122, i123=123, " + + "i124=124, i125=125, i126=126, i127=127]"; + + public void testToStringOutput() { + assertTrue(bigInt.toString().equals(BIG_INT_TO_STRING_OUTPUT)); + assertTrue(bigLong.toString().equals(BIG_LONG_TO_STRING_OUTPUT)); + } +} diff --git a/test/langtools/tools/javac/sealed/MissingPermittedSubtypes.java b/test/langtools/tools/javac/sealed/MissingPermittedSubtypes.java new file mode 100644 index 0000000000000000000000000000000000000000..ba75407099a7f0c08d9d2864f0e1be426c090279 --- /dev/null +++ b/test/langtools/tools/javac/sealed/MissingPermittedSubtypes.java @@ -0,0 +1,199 @@ +/* + * 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. + */ + +/** + * @test + * @bug 8277105 + * @summary Verify missing permitted subtype is handled properly for both casts and pattern switches. + * @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 + * @run main MissingPermittedSubtypes +*/ + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; + +import toolbox.TestRunner; +import toolbox.JavacTask; +import toolbox.Task; +import toolbox.ToolBox; + +public class MissingPermittedSubtypes extends TestRunner { + + private static final String JAVA_VERSION = System.getProperty("java.specification.version"); + + ToolBox tb; + + public static void main(String... args) throws Exception { + new MissingPermittedSubtypes().runTests(); + } + + MissingPermittedSubtypes() { + super(System.err); + tb = new ToolBox(); + } + + public void runTests() throws Exception { + runTests(m -> new Object[] { Paths.get(m.getName()) }); + } + + @Test + public void testInaccessiblePermitted(Path base) throws IOException { + Path current = base.resolve("."); + Path libSrc = current.resolve("lib-src"); + + tb.writeJavaFiles(libSrc, + """ + package lib; + public sealed interface S permits A, B1, B2 {} + """, + """ + package lib; + public final class A implements S {} + """, + """ + package lib; + final class B1 implements S {} + """, + """ + package lib; + final class B2 implements S, Runnable { + public void run() {} + } + """); + + Path libClasses = current.resolve("libClasses"); + + Files.createDirectories(libClasses); + + new JavacTask(tb) + .options("--enable-preview", + "-source", JAVA_VERSION) + .outdir(libClasses) + .files(tb.findJavaFiles(libSrc)) + .run(); + + Path b1Class = libClasses.resolve("lib").resolve("B1.class"); + + Files.delete(b1Class); + + Path b2Class = libClasses.resolve("lib").resolve("B2.class"); + + Files.delete(b2Class); + + { + Path src1 = current.resolve("src1"); + tb.writeJavaFiles(src1, + """ + package test; + import lib.*; + public class Test1 { + private void test(S obj) { + int i = switch (obj) { + case A a -> 0; + }; + Runnable r = () -> {obj = null;}; + } + } + """); + + Path classes1 = current.resolve("classes1"); + + Files.createDirectories(classes1); + + var log = + new JavacTask(tb) + .options("--enable-preview", + "-source", JAVA_VERSION, + "-XDrawDiagnostics", + "-Xlint:-preview", + "--class-path", libClasses.toString()) + .outdir(classes1) + .files(tb.findJavaFiles(src1)) + .run(Task.Expect.FAIL) + .writeAll() + .getOutputLines(Task.OutputKind.DIRECT); + + List expectedErrors = List.of( + "Test1.java:5:24: compiler.err.cant.access: lib.B1, (compiler.misc.class.file.not.found: lib.B1)", + "Test1.java:8:29: compiler.err.cant.ref.non.effectively.final.var: obj, (compiler.misc.lambda)", + "- compiler.note.preview.filename: Test1.java, DEFAULT", + "- compiler.note.preview.recompile", + "2 errors"); + + if (!expectedErrors.equals(log)) { + throw new AssertionError("Incorrect errors, expected: " + expectedErrors + + ", actual: " + log); + } + } + + { + Path src2 = current.resolve("src2"); + tb.writeJavaFiles(src2, + """ + package test; + import lib.*; + public class Test1 { + private void test(S obj) { + Runnable r = (Runnable) obj; + String s = (String) obj; + } + } + """); + + Path classes2 = current.resolve("classes2"); + + Files.createDirectories(classes2); + + var log = + new JavacTask(tb) + .options("--enable-preview", + "-source", JAVA_VERSION, + "-XDrawDiagnostics", + "-Xlint:-preview", + "--class-path", libClasses.toString()) + .outdir(classes2) + .files(tb.findJavaFiles(src2)) + .run(Task.Expect.FAIL) + .writeAll() + .getOutputLines(Task.OutputKind.DIRECT); + + List expectedErrors = List.of( + "Test1.java:5:19: compiler.err.cant.access: lib.B1, (compiler.misc.class.file.not.found: lib.B1)", + "Test1.java:6:26: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: lib.S, java.lang.String)", + "2 errors"); + + if (!expectedErrors.equals(log)) { + throw new AssertionError("Incorrect errors, expected: " + expectedErrors + + ", actual: " + log); + } + } + } + +} diff --git a/test/langtools/tools/javac/sym/ElementStructureTest.java b/test/langtools/tools/javac/sym/ElementStructureTest.java index db5ae5f4582a14dd8de894ddc2544e2e18b1ece3..791785b24521ef5db20b4a858e6405aa872bfaf3 100644 --- a/test/langtools/tools/javac/sym/ElementStructureTest.java +++ b/test/langtools/tools/javac/sym/ElementStructureTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -104,7 +104,7 @@ import toolbox.ToolBox; /**To generate the hash values for version N, invoke this class like: * - * java ElementStructureTest generate-hashes $LANGTOOLS_DIR/make/data/symbols/include.list ( N)+ + * java ElementStructureTest generate-hashes $LANGTOOLS_DIR/src/jdk.compiler/share/data/symbols/include.list ( N)+ * * Where is the file produced by make/src/classes/build/tools/symbolgenerator/Probe.java. * So, to produce hashes for 6, 7 and 8, this command can be used: @@ -113,11 +113,11 @@ import toolbox.ToolBox; * * To inspect differences between the actual and expected output for version N, invoke this class like: * - * java ElementStructureTest generate-output $LANGTOOLS_DIR/make/data/symbols/include.list ( N )+ + * java ElementStructureTest generate-output $LANGTOOLS_DIR/src/jdk.compiler/share/data/symbols/include.list ( N )+ * * For example, to get the actual and expected output for 6 in /tmp/actual and /tmp/expected, respectively: * - * java ElementStructureTest generate-output $LANGTOOLS_DIR/make/data/symbols/include.list classes-6 6 /tmp/actual /tmp/expected + * java ElementStructureTest generate-output $LANGTOOLS_DIR/src/jdk.compiler/share/data/symbols/include.list classes-6 6 /tmp/actual /tmp/expected */ public class ElementStructureTest { diff --git a/test/langtools/tools/javac/tree/ArrayTypeToString.java b/test/langtools/tools/javac/tree/ArrayTypeToString.java index 9d2275ab26fcdfc0ed5ec4abbdd9bc6f73dee534..eac8f345befed036fdbce2ff3bf217dd7e54c645 100644 --- a/test/langtools/tools/javac/tree/ArrayTypeToString.java +++ b/test/langtools/tools/javac/tree/ArrayTypeToString.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -23,7 +23,7 @@ /* * @test - * @bug 8068737 + * @bug 8068737 8281238 * @summary Tests ArrayType.toString with type annotations present * @modules jdk.compiler/com.sun.tools.javac.code * @library /tools/javac/lib @@ -66,7 +66,7 @@ public class ArrayTypeToString extends JavacTestingAbstractProcessor { // Normalize output by removing whitespace s = s.replaceAll("\\s", ""); - // Expected: "@Foo(0)java.lang.String@Foo(3)[]@Foo(2)[]@Foo(1)[]" + // Expected: "java.lang.@Foo(0)String@Foo(1)[]@Foo(2)[]@Foo(3)[]" processingEnv.getMessager().printNote(s); } } diff --git a/test/langtools/tools/javac/tree/ArrayTypeToString.out b/test/langtools/tools/javac/tree/ArrayTypeToString.out index 375a6f28949114bf22850b1b2c3aa5aadf07f88d..ca3db541c2d7c7b4ced5d2aeaab714c9844870db 100644 --- a/test/langtools/tools/javac/tree/ArrayTypeToString.out +++ b/test/langtools/tools/javac/tree/ArrayTypeToString.out @@ -1 +1 @@ -- compiler.note.proc.messager: @Foo(0)java.lang.String@Foo(1)[]@Foo(2)[]@Foo(3)[] +- compiler.note.proc.messager: java.lang.@Foo(0)String@Foo(1)[]@Foo(2)[]@Foo(3)[] diff --git a/test/langtools/tools/javac/tree/NoPrivateTypesExported.java b/test/langtools/tools/javac/tree/NoPrivateTypesExported.java index cd1b305898cd8d1d4e9b1543b96f576bc5248c2a..e723139ef8d727d654781728fc0ca38871e4f75b 100644 --- a/test/langtools/tools/javac/tree/NoPrivateTypesExported.java +++ b/test/langtools/tools/javac/tree/NoPrivateTypesExported.java @@ -89,7 +89,8 @@ public class NoPrivateTypesExported extends JavacTestingAbstractProcessor { "java.text.", "java.util.", "javax.lang.model.", - "javax.annotation.processing.SupportedSourceVersion" + "javax.annotation.processing.SupportedSourceVersion", + "javax.tools.JavaFileObject" )); Set javaxToolsProcessingAcceptableTemp = new HashSet<>(); javaxToolsProcessingAcceptableTemp.addAll(javaxLangModelAcceptable); diff --git a/test/langtools/tools/javac/versions/Versions.java b/test/langtools/tools/javac/versions/Versions.java index 7b75896bab75ee6a77f9b1b1d23f0eccbe30c216..78185eba484b786c0a393ffd6fa0ab3e2bb065fc 100644 --- a/test/langtools/tools/javac/versions/Versions.java +++ b/test/langtools/tools/javac/versions/Versions.java @@ -71,9 +71,9 @@ public class Versions { public static final Set VALID_SOURCES = Set.of("1.7", "1.8", "1.9", "1.10", "11", "12", "13", "14", - "15", "16", "17", "18"); + "15", "16", "17", "18", "19"); - public static final String LATEST_MAJOR_VERSION = "62.0"; + public static final String LATEST_MAJOR_VERSION = "63.0"; static enum SourceTarget { SEVEN(true, "51.0", "7", Versions::checksrc7), @@ -87,7 +87,8 @@ public class Versions { FIFTEEN(false, "59.0", "15", Versions::checksrc15), SIXTEEN(false, "60.0", "16", Versions::checksrc16), SEVENTEEN(false, "61.0", "17", Versions::checksrc17), - EIGHTEEN(false, "62.0", "18", Versions::checksrc18); + EIGHTEEN(false, "62.0", "18", Versions::checksrc18), + NINETEEN(false, "63.0", "19", Versions::checksrc19); private final boolean dotOne; private final String classFileVer; @@ -320,6 +321,13 @@ public class Versions { // Add expectedFail after new language features added in a later release. } + protected void checksrc19(List args) { + printargs("checksrc19", args); + expectedPass(args, List.of("New7.java", "New8.java", "New10.java", "New11.java", + "New14.java", "New15.java", "New16.java", "New17.java")); + // Add expectedFail after new language features added in a later release. + } + protected void expected(List args, List fileNames, Consumer> passOrFail) { ArrayList fullArguments = new ArrayList<>(args); diff --git a/test/langtools/tools/javac/warnings/suppress/SuppressWarningsPackage.java b/test/langtools/tools/javac/warnings/suppress/SuppressWarningsPackage.java new file mode 100644 index 0000000000000000000000000000000000000000..3c6e13fa1fd203d18c01d2df9652eecf714500be --- /dev/null +++ b/test/langtools/tools/javac/warnings/suppress/SuppressWarningsPackage.java @@ -0,0 +1,209 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8280866 + * @summary Verify SuppressWarnings works on package clauses and modules. + * @library /tools/lib + * @modules jdk.compiler/com.sun.tools.javac.api + * @modules jdk.compiler/com.sun.tools.javac.main + * @build toolbox.JavacTask toolbox.TestRunner toolbox.ToolBox + * @run main SuppressWarningsPackage + */ + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; + +import toolbox.JavacTask; +import toolbox.Task.Expect; +import toolbox.Task.OutputKind; +import toolbox.TestRunner; +import toolbox.ToolBox; + +public class SuppressWarningsPackage extends TestRunner { + public static void main(String... args) throws Exception { + SuppressWarningsPackage t = new SuppressWarningsPackage(); + t.runTests(m -> new Object[] { Paths.get(m.getName()) }); + } + + private final ToolBox tb = new ToolBox(); + + public SuppressWarningsPackage() throws IOException { + super(System.err); + } + + @Test + public void testSuppressWarningsOnPackageInfo(Path base) throws IOException { + Path src = base.resolve("src"); + Path classes = Files.createDirectories(base.resolve("classes")); + TestCase[] testCases = new TestCase[] { + new TestCase("", + "package-info.java:1:2: compiler.warn.has.been.deprecated: test.DeprecatedAnn, test", + "package-info.java:1:16: compiler.warn.has.been.deprecated: test.DeprecatedClass, test", + "Use.java:2:2: compiler.warn.has.been.deprecated: test.DeprecatedAnn, test", + "Use.java:2:16: compiler.warn.has.been.deprecated: test.DeprecatedClass, test", + "4 warnings"), + new TestCase("@SuppressWarnings(\"deprecation\")", + "Use.java:2:2: compiler.warn.has.been.deprecated: test.DeprecatedAnn, test", + "Use.java:2:16: compiler.warn.has.been.deprecated: test.DeprecatedClass, test", + "2 warnings") + }; + for (TestCase tc : testCases) { + tb.writeJavaFiles(src, + """ + @DeprecatedAnn(DeprecatedClass.class) + # + package test; + """.replace("#", tc.sw), + """ + package test; + @Deprecated + public @interface DeprecatedAnn { + public Class value(); + } + """, + """ + package test; + @Deprecated + public class DeprecatedClass { + public static class Nested {} + } + """, + """ + package test; + @DeprecatedAnn(DeprecatedClass.class) + public class Use {} + """); + + List log = new JavacTask(tb) + .outdir(classes) + .files(tb.findJavaFiles(src)) + .options("-XDrawDiagnostics", + "-Xlint:deprecation") + .run(Expect.SUCCESS) + .writeAll() + .getOutputLines(OutputKind.DIRECT); + + if (!Objects.equals(log, List.of(tc.expectedOutput))) { + error("Unexpected output, expected:\n" + Arrays.toString(tc.expectedOutput) + + "\nactual:\n" + log); + } + } + } + + @Test + public void testSuppressWarningsOnModuleInfo(Path base) throws IOException { + Path src = base.resolve("src"); + Path classes = Files.createDirectories(base.resolve("classes")); + TestCase[] testCases = new TestCase[] { + new TestCase("", + "module-info.java:3:12: compiler.warn.has.been.deprecated: test.DeprecatedClass, test", + "module-info.java:4:2: compiler.warn.has.been.deprecated: test.DeprecatedAnn, test", + "module-info.java:4:16: compiler.warn.has.been.deprecated: test.DeprecatedClass, test", + "module-info.java:7:14: compiler.warn.has.been.deprecated: test.Service, test", + "module-info.java:8:18: compiler.warn.has.been.deprecated: test.Service, test", + "module-info.java:8:36: compiler.warn.has.been.deprecated: test.ServiceImpl, test", + "package-info.java:1:2: compiler.warn.has.been.deprecated: test.DeprecatedAnn, test", + "package-info.java:1:16: compiler.warn.has.been.deprecated: test.DeprecatedClass, test", + "Use.java:2:2: compiler.warn.has.been.deprecated: test.DeprecatedAnn, test", + "Use.java:2:16: compiler.warn.has.been.deprecated: test.DeprecatedClass, test", + "10 warnings"), + new TestCase("@SuppressWarnings(\"deprecation\")", + "module-info.java:3:12: compiler.warn.has.been.deprecated: test.DeprecatedClass, test", + "package-info.java:1:2: compiler.warn.has.been.deprecated: test.DeprecatedAnn, test", + "package-info.java:1:16: compiler.warn.has.been.deprecated: test.DeprecatedClass, test", + "Use.java:2:2: compiler.warn.has.been.deprecated: test.DeprecatedAnn, test", + "Use.java:2:16: compiler.warn.has.been.deprecated: test.DeprecatedClass, test", + "5 warnings") + }; + for (TestCase tc : testCases) { + tb.writeJavaFiles(src, + """ + import test.DeprecatedAnn; + import test.DeprecatedClass; + import test.DeprecatedClass.Nested; + @DeprecatedAnn(DeprecatedClass.class) + # + module m { + uses test.Service; + provides test.Service with test.ServiceImpl; + } + """.replace("#", tc.sw), + """ + @DeprecatedAnn(DeprecatedClass.class) + package test; + """, + """ + package test; + @Deprecated + public @interface DeprecatedAnn { + public Class value(); + } + """, + """ + package test; + @Deprecated + public class DeprecatedClass { + public static class Nested {} + } + """, + """ + package test; + @Deprecated + public interface Service {} + """, + """ + package test; + @Deprecated + public class ServiceImpl implements Service {} + """, + """ + package test; + @DeprecatedAnn(DeprecatedClass.class) + public class Use {} + """); + + List log = new JavacTask(tb) + .outdir(classes) + .files(tb.findJavaFiles(src)) + .options("-XDrawDiagnostics", + "-Xlint:deprecation") + .run(Expect.SUCCESS) + .writeAll() + .getOutputLines(OutputKind.DIRECT); + + if (!Objects.equals(log, List.of(tc.expectedOutput))) { + error("Unexpected output, expected:\n" + Arrays.toString(tc.expectedOutput) + + "\nactual:\n" + log); + } + } + } + + record TestCase(String sw, String... expectedOutput) {} +} diff --git a/test/langtools/tools/javap/AnnoTest.java b/test/langtools/tools/javap/AnnoTest.java index 7d78d163e296d1ded112ca48dc6307114fdb7b95..649d7e7b38afa9f4e3b25e8c4d4ee954a690c9f7 100644 --- a/test/langtools/tools/javap/AnnoTest.java +++ b/test/langtools/tools/javap/AnnoTest.java @@ -49,50 +49,50 @@ public class AnnoTest { expect(out, "RuntimeVisibleAnnotations:\n" + - " 0: #21(#22=B#23)\n" + + " 0: #17(#18=B#19)\n" + " AnnoTest$ByteAnno(\n" + " value=(byte) 42\n" + " )\n" + - " 1: #24(#22=S#25)\n" + + " 1: #20(#18=S#21)\n" + " AnnoTest$ShortAnno(\n" + " value=(short) 3\n" + " )"); expect(out, "RuntimeInvisibleAnnotations:\n" + - " 0: #27(#22=[J#28,J#30,J#32,J#34,J#36])\n" + + " 0: #23(#18=[J#24,J#26,J#28,J#30,J#32])\n" + " AnnoTest$ArrayAnno(\n" + " value=[1l,2l,3l,4l,5l]\n" + " )\n" + - " 1: #38(#22=Z#39)\n" + + " 1: #34(#18=Z#35)\n" + " AnnoTest$BooleanAnno(\n" + " value=false\n" + " )\n" + - " 2: #40(#41=c#42)\n" + + " 2: #36(#37=c#38)\n" + " AnnoTest$ClassAnno(\n" + " type=class Ljava/lang/Object;\n" + " )\n" + - " 3: #43(#44=e#45.#46)\n" + + " 3: #39(#40=e#41.#42)\n" + " AnnoTest$EnumAnno(\n" + " kind=Ljavax/lang/model/element/ElementKind;.PACKAGE\n" + " )\n" + - " 4: #47(#22=I#48)\n" + + " 4: #43(#18=I#44)\n" + " AnnoTest$IntAnno(\n" + " value=2\n" + " )\n" + - " 5: #49()\n" + + " 5: #45()\n" + " AnnoTest$IntDefaultAnno\n" + - " 6: #50(#51=s#52)\n" + + " 6: #46(#47=s#48)\n" + " AnnoTest$NameAnno(\n" + " name=\"NAME\"\n" + " )\n" + - " 7: #53(#54=D#55,#57=F#58)\n" + + " 7: #49(#50=D#51,#53=F#54)\n" + " AnnoTest$MultiAnno(\n" + " d=3.14159d\n" + " f=2.71828f\n" + " )\n" + - " 8: #59()\n" + + " 8: #55()\n" + " AnnoTest$SimpleAnno\n" + - " 9: #60(#22=@#47(#22=I#61))\n" + + " 9: #56(#18=@#43(#18=I#57))\n" + " AnnoTest$AnnoAnno(\n" + " value=@AnnoTest$IntAnno(\n" + " value=5\n" + @@ -100,7 +100,7 @@ public class AnnoTest { " )"); expect(out, "RuntimeInvisibleTypeAnnotations:\n" + - " 0: #63(): CLASS_EXTENDS, type_index=0\n" + + " 0: #59(): CLASS_EXTENDS, type_index=0\n" + " AnnoTest$TypeAnno"); if (errors > 0) diff --git a/test/langtools/tools/jdeps/Options.java b/test/langtools/tools/jdeps/Options.java index c4a99aa2ca2dddc0ef090064a406c69916f48da4..488dd93f4e1005ee6b150d4fd303c70b0c2aa800 100644 --- a/test/langtools/tools/jdeps/Options.java +++ b/test/langtools/tools/jdeps/Options.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -23,7 +23,7 @@ /* * @test - * @bug 8168386 8205116 + * @bug 8168386 8205116 8281634 * @summary Test option validation * @modules jdk.jdeps * @library lib @@ -48,11 +48,11 @@ public class Options { "-v, -verbose cannot be used with -s, -summary option" }, { - new String[] { "-jdkinternal", "-summary", TEST_CLASSES }, + new String[] { "-jdkinternals", "-summary", TEST_CLASSES }, "-summary or -verbose cannot be used with -jdkinternals option" }, { - new String[] { "-jdkinternal", "-p", "java.lang", TEST_CLASSES }, + new String[] { "-jdkinternals", "-p", "java.lang", TEST_CLASSES }, "--package, --regex, --require cannot be used with -jdkinternals option" }, { @@ -69,7 +69,7 @@ public class Options { }, { new String[] { "--inverse", "-R", TEST_CLASSES }, - "-R cannot be used with --inverse option" + "--recursive and --no-recursive cannot be used with --inverse option" }, { new String[] { "--generate-module-info", "dots", "-cp", TEST_CLASSES }, @@ -77,18 +77,22 @@ public class Options { }, { new String[] { "--list-deps", "-summary", TEST_CLASSES }, - "--list-deps and --list-reduced-deps options are specified" + "-summary or -verbose cannot be used with --list-deps option" }, { new String[] { "--list-deps", "--list-reduced-deps", TEST_CLASSES }, "--list-deps and --list-reduced-deps options are specified" }, + { + new String[] { "--package", "sun.misc", "--require", "java.net.http" }, + "Only one of --package (-p), --regex (-e), --require option can be specified" + } }; } @Test(dataProvider = "errors") public void test(String[] options, String expected) { - jdepsError(options).outputContains(expected); + assertTrue(jdepsError(options).outputContains(expected)); } @@ -109,6 +113,6 @@ public class Options { // invalid path jdeps = new JdepsRunner("--check", "java.base", "--system", "bad"); assertTrue(jdeps.run(true) != 0); - jdeps.outputContains("invalid path: bad"); + assertTrue(jdeps.outputContains("invalid path: bad")); } } diff --git a/test/langtools/tools/jdeps/multiVersion/MultiVersionError.java b/test/langtools/tools/jdeps/multiVersion/MultiVersionError.java new file mode 100644 index 0000000000000000000000000000000000000000..62513406b7139da9c0bce340ba94c7973a896969 --- /dev/null +++ b/test/langtools/tools/jdeps/multiVersion/MultiVersionError.java @@ -0,0 +1,107 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8277165 + * @library ../lib + * @build CompilerUtils + * @run testng MultiVersionError + * @summary Tests multiple versions of the same class file + */ + +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Set; +import java.util.spi.ToolProvider; + +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; + +import static org.testng.Assert.assertTrue; + +public class MultiVersionError { + 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("mods"); + + private static final ToolProvider JAR_TOOL = ToolProvider.findFirst("jar").orElseThrow(); + private static final Set modules = Set.of("m1", "m2"); + + /** + * Compiles classes used by the test + */ + @BeforeTest + public void compileAll() throws Exception { + CompilerUtils.cleanDir(MODS_DIR); + modules.forEach(mn -> + assertTrue(CompilerUtils.compileModule(SRC_DIR, MODS_DIR, mn))); + + // create a modular multi-release m1.jar + Path m1 = MODS_DIR.resolve("m1"); + Path m2 = MODS_DIR.resolve("m2"); + jar("cf", "m1.jar", "-C", m1.toString(), "p/Test.class", + "--release", "9", "-C", m1.toString(), "module-info.class", + "--release", "11", "-C", m1.toString(), "p/internal/P.class"); + jar("cf", "m2.jar", "-C", m2.toString(), "q/Q.class", + "--release", "10", "-C", m2.toString(), "module-info.class"); + + // package private p/internal/P.class in m1 instead + jar("cf", "m3.jar", "-C", m2.toString(), "q/Q.class", + "--release", "12", "-C", m2.toString(), "module-info.class", + "-C", m1.toString(), "p/internal/P.class"); + } + + /* + * multiple module-info.class from different versions should be excluded + * from multiple version check. + */ + @Test + public void noMultiVersionClass() { + // skip parsing p.internal.P to workaround JDK-8277681 + JdepsRunner jdepsRunner = new JdepsRunner("--print-module-deps", "--multi-release", "10", + "--ignore-missing-deps", + "--module-path", "m1.jar", "m2.jar"); + int rc = jdepsRunner.run(true); + assertTrue(rc == 0); + assertTrue(jdepsRunner.outputContains("java.base,m1")); + } + + /* + * Detect multiple versions of p.internal.P class + */ + @Test + public void classInMultiVersions() { + JdepsRunner jdepsRunner = new JdepsRunner("--print-module-deps", "--multi-release", "13", + "--module-path", "m1.jar", "m3.jar"); + int rc = jdepsRunner.run(true); + assertTrue(rc != 0); + assertTrue(jdepsRunner.outputContains("class p.internal.P already associated with version")); + } + + private static void jar(String... options) { + int rc = JAR_TOOL.run(System.out, System.err, options); + assertTrue(rc == 0); + } +} diff --git a/test/langtools/tools/jdeps/multiVersion/src/m1/module-info.java b/test/langtools/tools/jdeps/multiVersion/src/m1/module-info.java new file mode 100644 index 0000000000000000000000000000000000000000..316803466ca7d225332b7329970b95cffa721cb1 --- /dev/null +++ b/test/langtools/tools/jdeps/multiVersion/src/m1/module-info.java @@ -0,0 +1,27 @@ +/* + * 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. + */ + +module m1 { + requires java.management; + exports p; +} diff --git a/test/langtools/tools/jdeps/multiVersion/src/m1/p/Test.java b/test/langtools/tools/jdeps/multiVersion/src/m1/p/Test.java new file mode 100644 index 0000000000000000000000000000000000000000..e3d9139bbddb67e136f29555cc0090757f043121 --- /dev/null +++ b/test/langtools/tools/jdeps/multiVersion/src/m1/p/Test.java @@ -0,0 +1,27 @@ +/* + * 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. + */ + +package p; + +public class Test { +} diff --git a/test/langtools/tools/jdeps/multiVersion/src/m1/p/internal/P.java b/test/langtools/tools/jdeps/multiVersion/src/m1/p/internal/P.java new file mode 100644 index 0000000000000000000000000000000000000000..3a14badd1d07fce83e6b9d08877c222df487f145 --- /dev/null +++ b/test/langtools/tools/jdeps/multiVersion/src/m1/p/internal/P.java @@ -0,0 +1,30 @@ +/* + * 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. + */ + +package p.internal; + +import java.lang.management.*; + +class P { + private static RuntimeMXBean mxbean = ManagementFactory.getRuntimeMXBean(); +} diff --git a/test/langtools/tools/jdeps/multiVersion/src/m2/module-info.java b/test/langtools/tools/jdeps/multiVersion/src/m2/module-info.java new file mode 100644 index 0000000000000000000000000000000000000000..5404ca478674ca3f3c71b7c1cf96968a05a7e11e --- /dev/null +++ b/test/langtools/tools/jdeps/multiVersion/src/m2/module-info.java @@ -0,0 +1,27 @@ +/* + * 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. + */ + +module m2 { + requires m1; + requires java.logging; +} diff --git a/test/langtools/tools/jdeps/multiVersion/src/m2/p/internal/P.java b/test/langtools/tools/jdeps/multiVersion/src/m2/p/internal/P.java new file mode 100644 index 0000000000000000000000000000000000000000..d68265798bda3a774a9ce96b4a3706c671a7768d --- /dev/null +++ b/test/langtools/tools/jdeps/multiVersion/src/m2/p/internal/P.java @@ -0,0 +1,30 @@ +/* + * 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. + */ + +package p.internal; + +import java.util.logging.Logger; + +public class P { + private static final Logger LOGGER = Logger.getLogger("p"); +} diff --git a/test/langtools/tools/jdeps/multiVersion/src/m2/q/Q.java b/test/langtools/tools/jdeps/multiVersion/src/m2/q/Q.java new file mode 100644 index 0000000000000000000000000000000000000000..46cad1cc9d137b522b3c9ac9e06b51828a88db17 --- /dev/null +++ b/test/langtools/tools/jdeps/multiVersion/src/m2/q/Q.java @@ -0,0 +1,32 @@ +/* + * 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. + */ + +package q; + +public class Q { + static p.Test t = new p.Test(); + + public Q() { + Object o = new p.internal.P(); + } +} diff --git a/test/langtools/tools/lib/snippets/SnippetUtils.java b/test/langtools/tools/lib/snippets/SnippetUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..21e8bbabf1800eb8124ee2d17fc1eefa35377a1c --- /dev/null +++ b/test/langtools/tools/lib/snippets/SnippetUtils.java @@ -0,0 +1,543 @@ +/* + * 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. + */ + +package snippets; + +import java.io.File; +import java.io.IOException; +import java.io.PrintWriter; +import java.net.URI; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.function.BiConsumer; +import java.util.function.Consumer; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.Modifier; +import javax.lang.model.element.ModuleElement; +import javax.lang.model.element.PackageElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.util.Elements; +import javax.lang.model.util.SimpleElementVisitor14; +import javax.tools.Diagnostic; +import javax.tools.DiagnosticCollector; +import javax.tools.DiagnosticListener; +import javax.tools.JavaCompiler; +import javax.tools.JavaFileManager; +import javax.tools.JavaFileObject; +import javax.tools.SimpleJavaFileObject; +import javax.tools.StandardJavaFileManager; +import javax.tools.ToolProvider; + +import com.sun.source.doctree.AttributeTree; +import com.sun.source.doctree.DocCommentTree; +import com.sun.source.doctree.DocTree; +import com.sun.source.doctree.SnippetTree; +import com.sun.source.doctree.TextTree; +import com.sun.source.util.DocTreeScanner; +import com.sun.source.util.DocTrees; +import com.sun.source.util.JavacTask; + +/** + * Utilities for analyzing snippets. + * + * Support is provided for the following: + *
            + *
          • creating an instance of {@link JavacTask} suitable for looking up + * elements by name, in order to access any corresponding documentation comment, + *
          • scanning elements to find all associated snippets, + *
          • locating instances of snippets by their {@code id}, + *
          • parsing snippets, and + *
          • accessing the body of snippets, for any additional analysis. + *
          + * + * @apiNote + * The utilities do not provide support for compiling and running snippets, + * because in general, this requires too much additional context. However, + * the utilities do provide support for locating snippets in various ways, + * and accessing the body of those snippets, to simplify the task of writing + * code to compile and run snippets, where that is appropriate. + */ +public class SnippetUtils { + private static final JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); + + private final StandardJavaFileManager fileManager; + private final Path srcDir; + private final JavacTask javacTask; + private final Elements elements; + private final DocTrees docTrees; + + /** + * Creates an instance for analysing snippets in one or more JDK modules. + * + * The source for the modules is derived from the value of the + * {@code test.src} system property. + * + * Any messages, including error messages, will be written to {@code System.err}. + * + * @param modules the modules + * + * @throws IllegalArgumentException if no modules are specified + */ + public SnippetUtils(String... modules) { + this(findSourceDir(), null, null, Set.of(modules)); + } + + /** + * Creates an instance for analysing snippets in one or more modules. + * + * @param srcDir the location for the source of the modules; + * the location for the source of a specific module should be + * in srcDir{@code /}module{@code /share/module} + * + * @param pw a writer for any text messages that may be generated; + * if null, messages will be written to {@code System.err} + * + * @param dl a diagnostic listener for any diagnostic messages that may be generated; + * if null, messages will be written to {@code System.err} + * + * @param modules the modules + * + * @throws IllegalArgumentException if no modules are specified + */ + public SnippetUtils(Path srcDir, PrintWriter pw, DiagnosticListener dl, Set modules) { + if (modules.isEmpty()) { + throw new IllegalArgumentException("no modules specified"); + } + + this.srcDir = srcDir; + fileManager = compiler.getStandardFileManager(dl, null, null); + + List opts = new ArrayList<>(); + opts.addAll(List.of("--add-modules", String.join(",", modules))); // could use CompilationTask.addModules + modules.forEach(m -> opts.addAll(List.of("--patch-module", m + "=" + getModuleSourceDir(m)))); + opts.add("-proc:only"); + + javacTask = (JavacTask) compiler.getTask(pw, fileManager, dl, opts, null, null); + elements = javacTask.getElements(); + elements.getModuleElement("java.base"); // forces module graph to be instantiated, etc + + docTrees = DocTrees.instance(javacTask); + } + + /** + * {@return the source directory for the task used to access snippets} + */ + public Path getSourceDir() { + return srcDir; + } + + /** + * {@return the file manager for the task used to access snippets} + */ + public StandardJavaFileManager getFileManager() { + return fileManager; + } + + /** + * {@return the instance of {@code Elements} for the task used to access snippets} + */ + public Elements getElements() { + return elements; + } + + /** + * {@return the instance of {@code DocTrees} for the task used to access snippets} + */ + public DocTrees getDocTrees() { + return docTrees; + } + + /** + * {@return the doc comment tree for an element} + * + * @param element the element + */ + public DocCommentTree getDocCommentTree(Element element) { + return docTrees.getDocCommentTree(element); + } + + /** + * {@return the snippet with a given id in a doc comment tree} + * + * @param tree the doc comment tree + * @param id the id + */ + public SnippetTree getSnippetById(DocCommentTree tree, String id) { + return new SnippetFinder().scan(tree, id); + } + + /** + * {@return the snippet with a given id in the doc comment tree for an element} + * + * @param element the element + * @param id the id + */ + public SnippetTree getSnippetById(Element element, String id) { + DocCommentTree tree = getDocCommentTree(element); + return new SnippetFinder().scan(tree, id); + } + + /** + * A scanner to locate the tree for a snippet with a given id. + * Note: the scanner is use-once. + */ + private static class SnippetFinder extends DocTreeScanner { + private SnippetTree result; + private SnippetTree inSnippet; + + @Override + public SnippetTree scan(DocTree tree, String id) { + // stop scanning once the result has been found + return result != null ? result : super.scan(tree, id); + } + + @Override + public SnippetTree visitSnippet(SnippetTree tree, String id) { + inSnippet = tree; + try { + return super.visitSnippet(tree, id); + } finally { + inSnippet = null; + } + } + + @Override + public SnippetTree visitAttribute(AttributeTree tree, String id) { + if (tree.getName().contentEquals("id") + && tree.getValue().toString().equals(id)) { + result = inSnippet; + return result; + } else { + return null; + } + } + } + + /** + * Scans an element and appropriate enclosed elements for doc comments, + * and call a handler to handle any snippet trees in those doc comments. + * + * Only the public and protected members of type elements are scanned. + * The enclosed elements of modules and packages are not scanned. + * + * @param element the element + * @param handler the handler + * @throws IllegalArgumentException if any inappropriate element is scanned + */ + public void scan(Element element, BiConsumer handler) { + new ElementScanner(docTrees).scan(element, handler); + } + + private static class ElementScanner extends SimpleElementVisitor14> { + private final DocTrees trees; + + public ElementScanner(DocTrees trees) { + this.trees = trees; + } + + public void scan(Element e, BiConsumer snippetHandler) { + visit(e, new DocTreeScanner<>() { + @Override + public Void visitSnippet(SnippetTree tree, Element e) { + snippetHandler.accept(e, tree); + return null; + } + }); + } + + @Override + public Void visitModule(ModuleElement me, DocTreeScanner treeScanner) { + scanDocComment(me, treeScanner); + return null; + } + + @Override + public Void visitPackage(PackageElement pe, DocTreeScanner treeScanner) { + scanDocComment(pe, treeScanner); + return null; + } + + @Override + public Void visitType(TypeElement te, DocTreeScanner treeScanner) { + scanDocComment(te, treeScanner); + for (Element e : te.getEnclosedElements()) { + Set mods = e.getModifiers(); + if (mods.contains(Modifier.PUBLIC) || mods.contains(Modifier.PROTECTED)) { + e.accept(this, treeScanner); + } + } + return null; + } + + @Override + public Void visitExecutable(ExecutableElement ee, DocTreeScanner treeScanner) { + scanDocComment(ee, treeScanner); + return null; + } + + @Override + public Void visitVariable(VariableElement ve, DocTreeScanner treeScanner) { + switch (ve.getKind()) { + case ENUM_CONSTANT, FIELD -> scanDocComment(ve, treeScanner); + default -> defaultAction(ve, treeScanner); + } + return null; + } + + @Override + public Void defaultAction(Element e, DocTreeScanner treeScanner) { + throw new IllegalArgumentException(e.getKind() + " " + e.getSimpleName()); + } + + private void scanDocComment(Element e, DocTreeScanner treeScanner) { + DocCommentTree dc = trees.getDocCommentTree(e); + if (dc != null) { + treeScanner.scan(dc, e); + } + } + } + + /** + * {@return the string content of an inline or hybrid snippet, or {@code null} for an external snippet} + * + * @param tree the snippet + */ + public String getBody(SnippetTree tree) { + TextTree body = tree.getBody(); + return body == null ? null : body.getBody(); + } + + /** + * {@return the string content of an external or inline snippet} + * + * @param element the element whose documentation contains the snippet + * @param tree the snippet + */ + public String getBody(Element element, SnippetTree tree) throws IOException { + Path externalSnippetPath = getExternalSnippetPath(element, tree); + return externalSnippetPath == null ? getBody(tree) : Files.readString(externalSnippetPath); + } + + /** + * {@return the path for the {@code snippet-files} directory for an element} + * + * @param element the element + * + * @return the path + */ + public Path getSnippetFilesDir(Element element) { + var moduleElem = elements.getModuleOf(element); + var modulePath = getModuleSourceDir(moduleElem); + + var packageElem = elements.getPackageOf(element); // null for a module + var packagePath = packageElem == null + ? modulePath + : modulePath.resolve(packageElem.getQualifiedName().toString().replace(".", File.separator)); + + return packagePath.resolve("snippet-files"); + } + + /** + * {@return the path for an external snippet, or {@code null} if the snippet is inline} + * + * @param element the element whose documentation contains the snippet + * @param tree the snippet + */ + public Path getExternalSnippetPath(Element element, SnippetTree tree) { + var classAttr = getAttr(tree, "class"); + String file = (classAttr != null) + ? classAttr.replace(".", "/") + ".java" + : getAttr(tree, "file"); + return file == null ? null : getSnippetFilesDir(element).resolve(file.replace("/", File.separator)); + } + + /** + * {@return the value of an attribute defined by a snippet} + * + * @param tree the snippet + * @param name the name of the attribute + */ + public String getAttr(SnippetTree tree, String name) { + for (DocTree t : tree.getAttributes()) { + if (t instanceof AttributeTree at && at.getName().contentEquals(name)) { + return at.getValue().toString(); + } + } + return null; + } + + /** + * {@return the primary source directory for a module} + * + * The directory is srcDir/module-name/share/classes. + * + * @param e the module + */ + public Path getModuleSourceDir(ModuleElement e) { + return getModuleSourceDir(e.getQualifiedName().toString()); + } + + /** + * {@return the primary source directory for a module} + * + * The directory is srcDir/moduleName/share/classes. + * + * @param moduleName the module name + */ + public Path getModuleSourceDir(String moduleName) { + return srcDir.resolve(moduleName).resolve("share").resolve("classes"); + } + + /** + * Kinds of fragments of source code. + */ + public enum SourceKind { + /** A module declaration. */ + MODULE_INFO, + /** A package declaration. */ + PACKAGE_INFO, + /** A class or interface declaration. */ + TYPE_DECL, + /** A member declaration for a class or interface. */ + MEMBER_DECL, + /** A statement, expression or other kind of fragment. */ + OTHER + } + + /** + * Parses a fragment of source code, after trying to infer the kind of the fragment. + * + * @param body the string to be parsed + * @param showDiag a function to handle any diagnostics that may be generated + * @return {@code true} if the parse succeeded, and {@code false} otherwise + * + * @throws IOException if an IO exception occurs + */ + public boolean parse(String body, Consumer> showDiag) throws IOException { + DiagnosticCollector collector = new DiagnosticCollector<>(); + parse(body, null, collector); + var diags = collector.getDiagnostics(); + diags.forEach(showDiag); + return diags.isEmpty(); + } + + /** + * Parses a fragment of source code, after trying to infer the kind of the fragment. + * + * @param body the string to be parsed + * @param pw a stream for diagnostics, or {@code null} to use {@code System.err} + * @param dl a diagnostic listener, or {@code null} to report diagnostics to {@code pw} or {@code System.err} + * @throws IOException if an IO exception occurs + */ + public void parse(String body, PrintWriter pw, DiagnosticListener dl) + throws IOException { + parse(inferSourceKind(body), body, pw, dl); + } + + /** + * Parses a fragment of source code of a given kind. + * + * @param kind the kind of code to be parsed + * @param body the string to be parsed + * @param pw a stream for diagnostics, or {@code null} to use {@code System.err} + * @param dl a diagnostic listener, or {@code null} to report diagnostics to {@code pw} or {@code System.err}. + * @throws IOException if an IO exception occurs + */ + public void parse(SourceKind kind, String body, PrintWriter pw, DiagnosticListener dl) + throws IOException { + String fileBase = switch (kind) { + case MODULE_INFO -> "module-info"; + case PACKAGE_INFO -> "package-info"; + default -> "C"; // the exact name doesn't matter if just parsing (the filename check for public types comes later on) + }; + URI uri = URI.create("mem://%s.java".formatted(fileBase)); + + String compUnit = switch (kind) { + case MODULE_INFO, PACKAGE_INFO, TYPE_DECL -> body; + case MEMBER_DECL -> """ + class C { + %s + }""".formatted(body); + case OTHER -> """ + class C { + void m() { + %s + ; + } + }""".formatted(body); + }; + JavaFileObject fo = new SimpleJavaFileObject(uri, JavaFileObject.Kind.SOURCE) { + public CharSequence getCharContent(boolean ignoreEncodingErrors) { + return compUnit; + } + }; + + JavaFileManager fm = compiler.getStandardFileManager(dl, null, null); + + List opts = new ArrayList<>(); + JavacTask javacTask = (JavacTask) compiler.getTask(pw, fm, dl, opts, null, List.of(fo)); + + javacTask.parse(); + } + + public SourceKind inferSourceKind(String s) { + Pattern typeDecl = Pattern.compile("(?s)(^|\\R)([A-Za-z0-9_$ ])*\\b(?module|package|class|interface|record|enum)\\s+(?[A-Za-z0-9_$]+)"); + Matcher m1 = typeDecl.matcher(s); + if (m1.find()) { + return switch (m1.group("kw")) { + case "module" -> SourceKind.MODULE_INFO; + case "package" -> m1.find() ? SourceKind.TYPE_DECL : SourceKind.PACKAGE_INFO; + default -> SourceKind.TYPE_DECL; + }; + } + + Pattern methodDecl = Pattern.compile("(?s)(^|\\R)([A-Za-z0-9<>,]+ )+\\b(?[A-Za-z0-9_$]+)([(;]| +=)"); + Matcher m2 = methodDecl.matcher(s); + if (m2.find()) { + return SourceKind.MEMBER_DECL; + } + + return SourceKind.OTHER; + } + + private static Path findSourceDir() { + String testSrc = System.getProperty("test.src"); + Path p = Path.of(testSrc).toAbsolutePath(); + while (p.getParent() != null) { + Path srcDir = p.resolve("src"); + if (Files.exists(srcDir.resolve("java.base"))) { + return srcDir; + } + p = p.getParent(); + } + throw new IllegalArgumentException("Cannot find src/ from " + testSrc); + } +} \ No newline at end of file diff --git a/test/lib-test/jdk/test/lib/AssertsTest.java b/test/lib-test/jdk/test/lib/AssertsTest.java index 86b1a7fb8c7d5a12864bd027d14067dd1a1524a3..a4c739d64bae8250f587a5b25abd207e46726980 100644 --- a/test/lib-test/jdk/test/lib/AssertsTest.java +++ b/test/lib-test/jdk/test/lib/AssertsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -38,7 +38,7 @@ public class AssertsTest { } public int compareTo(Foo f) { - return new Integer(id).compareTo(new Integer(f.id)); + return Integer.valueOf(id).compareTo(Integer.valueOf(f.id)); } public String toString() { return "Foo(" + Integer.toString(id) + ")"; diff --git a/test/lib-test/jdk/test/lib/TestMutuallyExclusivePlatformPredicates.java b/test/lib-test/jdk/test/lib/TestMutuallyExclusivePlatformPredicates.java index 4be69a6566c8cf0fc3b9879d39f4ef70d8cb7505..3ca1de653a4f7e25112833d39ea693b08d59ea43 100644 --- a/test/lib-test/jdk/test/lib/TestMutuallyExclusivePlatformPredicates.java +++ b/test/lib-test/jdk/test/lib/TestMutuallyExclusivePlatformPredicates.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -53,7 +53,7 @@ public class TestMutuallyExclusivePlatformPredicates { IGNORED("isEmulatedClient", "isDebugBuild", "isFastDebugBuild", "isSlowDebugBuild", "hasSA", "isRoot", "isTieredSupported", "areCustomLoadersSupportedForCDS", "isDefaultCDSArchiveSupported", - "isSignedOSX"); + "isHardenedOSX"); public final List methodNames; diff --git a/test/lib-test/jdk/test/lib/TestPlatformIsTieredSupported.java b/test/lib-test/jdk/test/lib/TestPlatformIsTieredSupported.java index 8f57ab64eaf5b5960eb442a24f35fccfbee627df..8c0c8ea3c189cf807dc973778a128bc838996faf 100644 --- a/test/lib-test/jdk/test/lib/TestPlatformIsTieredSupported.java +++ b/test/lib-test/jdk/test/lib/TestPlatformIsTieredSupported.java @@ -39,6 +39,7 @@ import sun.hotspot.WhiteBox; */ public class TestPlatformIsTieredSupported { public static void main(String args[]) { + @SuppressWarnings("deprecation") WhiteBox whiteBox = WhiteBox.getWhiteBox(); boolean tieredCompilation = whiteBox.getBooleanVMFlag( "TieredCompilation"); diff --git a/test/lib-test/jdk/test/lib/format/ArrayDiffTest.java b/test/lib-test/jdk/test/lib/format/ArrayDiffTest.java index 7b7dfc086f18b033d57d1266146e8d445fbdb6b8..c52fcd78f9324d03daac00fd287cdd6c780e971a 100644 --- a/test/lib-test/jdk/test/lib/format/ArrayDiffTest.java +++ b/test/lib-test/jdk/test/lib/format/ArrayDiffTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -274,6 +274,7 @@ public class ArrayDiffTest { class StrObj { private final String value; public boolean equals(Object another) { return ((StrObj)another).value.equals(value); } + public int hashCode() { return value.hashCode(); } public StrObj(String value) { this.value = value; } public String toString() { return value; } } @@ -363,7 +364,7 @@ public class ArrayDiffTest { } public void assertTwoWay() { - ArrayDiff diff; + ArrayDiff diff; // Direct if (defaultParameters) { diff --git a/test/lib-test/jdk/test/whitebox/OldWhiteBox.java b/test/lib-test/jdk/test/whitebox/OldWhiteBox.java index 677ed210f692bbecf15f63c4cecfc85a8ae18282..41af4698e9843bbd12c8a169d41240b70eab4c9b 100644 --- a/test/lib-test/jdk/test/whitebox/OldWhiteBox.java +++ b/test/lib-test/jdk/test/whitebox/OldWhiteBox.java @@ -43,6 +43,7 @@ import sun.hotspot.WhiteBox; public class OldWhiteBox { public static void main(String[] args) { + @SuppressWarnings("deprecation") WhiteBox wb = WhiteBox.getWhiteBox(); if (wb.getHeapOopSize() < 0) { throw new Error("wb.getHeapOopSize() < 0"); diff --git a/test/lib-test/jdk/test/whitebox/vm_flags/VmFlagTest.java b/test/lib-test/jdk/test/whitebox/vm_flags/VmFlagTest.java index d48aab6cf26f10b59eba71635b817f8aef8bd545..7290cd1096c1534652d55e47cea75322c923f8ee 100644 --- a/test/lib-test/jdk/test/whitebox/vm_flags/VmFlagTest.java +++ b/test/lib-test/jdk/test/whitebox/vm_flags/VmFlagTest.java @@ -72,9 +72,9 @@ public final class VmFlagTest { protected static void runTest(String existentFlag, T[] tests, T[] results, BiConsumer set, Function get) { if (existentFlag != null) { - new VmFlagTest(existentFlag, set, get, true).test(tests, results); + new VmFlagTest(existentFlag, set, get, true).test(tests, results); } - new VmFlagTest(NONEXISTENT_FLAG, set, get, false).test(tests, results); + new VmFlagTest(NONEXISTENT_FLAG, set, get, false).test(tests, results); } public final void test(T[] tests, T[] results) { diff --git a/test/lib/RedefineClassHelper.java b/test/lib/RedefineClassHelper.java index 0fcfc52f0c1b436fde6997a61a9033181ed1ca74..88f31f8ba8fd828685e197ff8b56f847a14c37ba 100644 --- a/test/lib/RedefineClassHelper.java +++ b/test/lib/RedefineClassHelper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -21,7 +21,6 @@ * questions. */ -import java.io.PrintWriter; import java.lang.instrument.Instrumentation; import java.lang.instrument.ClassDefinition; import jdk.test.lib.compiler.InMemoryJavaCompiler; @@ -47,7 +46,7 @@ public class RedefineClassHelper { * @param clazz Class to redefine * @param javacode String with the new java code for the class to be redefined */ - public static void redefineClass(Class clazz, String javacode) throws Exception { + public static void redefineClass(Class clazz, String javacode) throws Exception { byte[] bytecode = InMemoryJavaCompiler.compile(clazz.getName(), javacode); redefineClass(clazz, bytecode); } @@ -58,7 +57,7 @@ public class RedefineClassHelper { * @param clazz Class to redefine * @param bytecode byte[] with the new class */ - public static void redefineClass(Class clazz, byte[] bytecode) throws Exception { + public static void redefineClass(Class clazz, byte[] bytecode) throws Exception { instrumentation.redefineClasses(new ClassDefinition(clazz, bytecode)); } diff --git a/test/lib/jdk/test/lib/NetworkConfiguration.java b/test/lib/jdk/test/lib/NetworkConfiguration.java index 716e2aed3d59bbfd1b3b14041b3dfd932cffa3eb..386a2bf0a6f084ca46ff90e40c9f35fdd5f621d8 100644 --- a/test/lib/jdk/test/lib/NetworkConfiguration.java +++ b/test/lib/jdk/test/lib/NetworkConfiguration.java @@ -451,6 +451,7 @@ public class NetworkConfiguration { } /** Prints all the system interface information to the give stream. */ + @SuppressWarnings("removal") public static void printSystemConfiguration(PrintStream out) { PrivilegedAction pa = () -> { try { diff --git a/test/lib/jdk/test/lib/OSVersion.java b/test/lib/jdk/test/lib/OSVersion.java index 5754fe5ebb9324af5acb393349d9bd1ff4c349e5..bb9f128bda528ae789ba1db912fd7543eb0279ed 100644 --- a/test/lib/jdk/test/lib/OSVersion.java +++ b/test/lib/jdk/test/lib/OSVersion.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -26,13 +26,8 @@ package jdk.test.lib; import java.util.Arrays; -import java.io.BufferedReader; -import java.io.FileReader; import java.util.regex.Pattern; import java.util.stream.Collectors; -import java.security.AccessController; -import java.security.PrivilegedActionException; -import java.security.PrivilegedExceptionAction; public final class OSVersion implements Comparable { public static final OSVersion WINDOWS_95 = new OSVersion(4, 0); diff --git a/test/lib/jdk/test/lib/Platform.java b/test/lib/jdk/test/lib/Platform.java index 7666fdcc459df904770183fdb7ddf71d886ff339..a8405c937226a178dabc5c60cd4a3e53ff427430 100644 --- a/test/lib/jdk/test/lib/Platform.java +++ b/test/lib/jdk/test/lib/Platform.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -23,8 +23,10 @@ package jdk.test.lib; +import java.io.BufferedReader; import java.io.FileNotFoundException; import java.io.IOException; +import java.io.InputStreamReader; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -242,13 +244,13 @@ public class Platform { } /** - * Return true if the test JDK is signed, otherwise false. Only valid on OSX. + * Return true if the test JDK is hardened, otherwise false. Only valid on OSX. */ - public static boolean isSignedOSX() throws IOException { - // We only care about signed binaries for 10.14 and later (actually 10.14.5, but + public static boolean isHardenedOSX() throws IOException { + // We only care about hardened binaries for 10.14 and later (actually 10.14.5, but // for simplicity we'll also include earlier 10.14 versions). if (getOsVersionMajor() == 10 && getOsVersionMinor() < 14) { - return false; // assume not signed + return false; // assume not hardened } // Find the path to the java binary. @@ -260,38 +262,45 @@ public class Platform { } // Run codesign on the java binary. - ProcessBuilder pb = new ProcessBuilder("codesign", "-d", "-v", javaFileName); - pb.redirectError(ProcessBuilder.Redirect.DISCARD); - pb.redirectOutput(ProcessBuilder.Redirect.DISCARD); + ProcessBuilder pb = new ProcessBuilder("codesign", "--display", "--verbose", javaFileName); + pb.redirectErrorStream(true); // redirect stderr to stdout Process codesignProcess = pb.start(); + BufferedReader is = new BufferedReader(new InputStreamReader(codesignProcess.getInputStream())); + String line; + boolean isHardened = false; + boolean hardenedStatusConfirmed = false; // set true when we confirm whether or not hardened + while ((line = is.readLine()) != null) { + System.out.println("STDOUT: " + line); + if (line.indexOf("flags=0x10000(runtime)") != -1 ) { + hardenedStatusConfirmed = true; + isHardened = true; + System.out.println("Target JDK is hardened. Some tests may be skipped."); + } else if (line.indexOf("flags=0x20002(adhoc,linker-signed)") != -1 ) { + hardenedStatusConfirmed = true; + isHardened = false; + System.out.println("Target JDK is adhoc signed, but not hardened."); + } else if (line.indexOf("code object is not signed at all") != -1) { + hardenedStatusConfirmed = true; + isHardened = false; + System.out.println("Target JDK is not signed, therefore not hardened."); + } + } + if (!hardenedStatusConfirmed) { + System.out.println("Could not confirm if TargetJDK is hardened. Assuming not hardened."); + isHardened = false; + } + try { if (codesignProcess.waitFor(10, TimeUnit.SECONDS) == false) { - System.err.println("Timed out waiting for the codesign process to complete. Assuming not signed."); + System.err.println("Timed out waiting for the codesign process to complete. Assuming not hardened."); codesignProcess.destroyForcibly(); - return false; // assume not signed + return false; // assume not hardened } } catch (InterruptedException e) { throw new RuntimeException(e); } - // Check codesign result to see if java binary is signed. Here are the - // exit code meanings: - // 0: signed - // 1: not signed - // 2: invalid arguments - // 3: only has meaning with the -R argument. - // So we should always get 0 or 1 as an exit value. - if (codesignProcess.exitValue() == 0) { - System.out.println("Target JDK is signed. Some tests may be skipped."); - return true; // signed - } else if (codesignProcess.exitValue() == 1) { - System.out.println("Target JDK is not signed."); - return false; // not signed - } else { - System.err.println("Executing codesign failed. Assuming unsigned: " + - codesignProcess.exitValue()); - return false; // not signed - } + return isHardened; } private static boolean isArch(String archnameRE) { diff --git a/test/lib/jdk/test/lib/SA/SATestUtils.java b/test/lib/jdk/test/lib/SA/SATestUtils.java index 0ba91f2a994fff1eb25a697aa617a4b20d04fb3d..2f98cf99357f4dda84f4e4f16b94cd6402254418 100644 --- a/test/lib/jdk/test/lib/SA/SATestUtils.java +++ b/test/lib/jdk/test/lib/SA/SATestUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -63,8 +63,8 @@ public class SATestUtils { throw new SkippedException("SA Attach not expected to work. Ptrace attach not supported."); } } else if (Platform.isOSX()) { - if (Platform.isSignedOSX()) { - throw new SkippedException("SA Attach not expected to work. JDK is signed."); + if (Platform.isHardenedOSX()) { + throw new SkippedException("SA Attach not expected to work. JDK is hardened."); } if (!Platform.isRoot() && !canAddPrivileges()) { throw new SkippedException("SA Attach not expected to work. Insufficient privileges (not root and can't use sudo)."); @@ -159,6 +159,7 @@ public class SATestUtils { * if we are root, so return true. Then return false for an expected denial * if "ptrace_scope" is 1, and true otherwise. */ + @SuppressWarnings("removal") private static boolean canPtraceAttachLinux() throws IOException { // SELinux deny_ptrace: var deny_ptrace = Paths.get("/sys/fs/selinux/booleans/deny_ptrace"); diff --git a/test/lib/jdk/test/lib/SecurityTools.java b/test/lib/jdk/test/lib/SecurityTools.java index 30da87f2d32fb5f528a3c3d1f21ae2db76e09340..36019a00e879b970a4e39ea531b2394c1450d3ff 100644 --- a/test/lib/jdk/test/lib/SecurityTools.java +++ b/test/lib/jdk/test/lib/SecurityTools.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -40,8 +40,8 @@ import jdk.test.lib.process.ProcessTools; * Run security tools (including jarsigner and keytool) in a new process. * The en_US locale is always used so a test can always match output to * English text. {@code /dev/urandom} is used as entropy source so tool will - * not block because of entropy scarcity. {@code -Jvm-options} is supported - * as an argument. + * not block because of entropy scarcity. An argument can be a normal string, + * {@code -Jvm-options}, or {@code $sysProp}. */ public class SecurityTools { @@ -66,6 +66,8 @@ public class SecurityTools { } else if (Platform.isWindows() && arg.isEmpty()) { // JDK-6518827: special handling for empty argument on Windows launcher.addToolArg("\"\""); + } else if (arg.length() > 1 && arg.charAt(0) == '$') { + launcher.addToolArg(System.getProperty(arg.substring(1))); } else { launcher.addToolArg(arg); } diff --git a/test/lib/jdk/test/lib/Utils.java b/test/lib/jdk/test/lib/Utils.java index 30f6e9e14dcb7755d478d1164b16bd42ee401039..4a73eb0a5fe5d3a3429ab8ba53e392a3aec8ed7d 100644 --- a/test/lib/jdk/test/lib/Utils.java +++ b/test/lib/jdk/test/lib/Utils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -52,7 +52,6 @@ import java.util.Map; import java.util.HashMap; import java.util.LinkedList; import java.util.List; -import java.util.Objects; import java.util.Random; import java.util.function.BooleanSupplier; import java.util.concurrent.TimeUnit; diff --git a/test/lib/jdk/test/lib/apps/LingeredApp.java b/test/lib/jdk/test/lib/apps/LingeredApp.java index 732c988ebe7c86a5f23815475b22e73a8d9c9e33..01c15b3562e120cd8bd08cc65dbbc2732f6a9028 100644 --- a/test/lib/jdk/test/lib/apps/LingeredApp.java +++ b/test/lib/jdk/test/lib/apps/LingeredApp.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -37,7 +37,6 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.List; -import java.util.Map; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; import java.util.UUID; diff --git a/test/lib/jdk/test/lib/artifacts/ArtifactManager.java b/test/lib/jdk/test/lib/artifacts/ArtifactManager.java index 31b96229f8ac152293906994f98456cf6efd7899..38a68b6ccd529539158a03216ca84893cbf1921a 100644 --- a/test/lib/jdk/test/lib/artifacts/ArtifactManager.java +++ b/test/lib/jdk/test/lib/artifacts/ArtifactManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -23,7 +23,6 @@ package jdk.test.lib.artifacts; -import java.io.FileNotFoundException; import java.nio.file.Path; public interface ArtifactManager { diff --git a/test/lib/jdk/test/lib/cds/CDSArchiveUtils.java b/test/lib/jdk/test/lib/cds/CDSArchiveUtils.java index 30b919d81c879f62abb5cb5e77e634f9ef912651..f5c504ba1c84e8465d9f5828e1478c6d9a4e27f5 100644 --- a/test/lib/jdk/test/lib/cds/CDSArchiveUtils.java +++ b/test/lib/jdk/test/lib/cds/CDSArchiveUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -45,6 +45,9 @@ import sun.hotspot.WhiteBox; // This class performs operations on shared archive file public class CDSArchiveUtils { + // Minimum supported CDS file header version + private static int genericHeaderMinVersion; // CDS_GENERIC_HEADER_SUPPORTED_MIN_VERSION + private static int currentCDSArchiveVersion; // CURRENT_CDS_ARCHIVE_VERSION // offsets private static int offsetMagic; // offset of GenericCDSFileMapHeader::_magic private static int offsetCrc; // offset of GenericCDSFileMapHeader::_crc @@ -82,6 +85,9 @@ public class CDSArchiveUtils { WhiteBox wb; try { wb = WhiteBox.getWhiteBox(); + // genericHeaderMinVersion + genericHeaderMinVersion = wb.getCDSGenericHeaderMinVersion(); + currentCDSArchiveVersion = wb.getCurrentCDSVersion(); // offsets offsetMagic = wb.getCDSOffsetForName("GenericCDSFileMapHeader::_magic"); offsetCrc = wb.getCDSOffsetForName("GenericCDSFileMapHeader::_crc"); @@ -116,6 +122,10 @@ public class CDSArchiveUtils { } // accessors + // minimum supported file header version + public static int getGenericHeaderMinVersion() { return genericHeaderMinVersion; } + // current CDS version + public static int getCurrentCDSArchiveVersion() { return currentCDSArchiveVersion; } // offsets public static int offsetMagic() { return offsetMagic; } public static int offsetCrc() { return offsetCrc; } @@ -331,6 +341,18 @@ public class CDSArchiveUtils { return newJsaFile; } + public static File createMagicOnlyFile(String fileName, boolean createStatic) throws Exception { + File file = new File(fileName); + if (file.exists()) { + file.delete(); + } + try (FileOutputStream out = new FileOutputStream(file)) { + ByteBuffer buffer = ByteBuffer.allocate(4).putInt(createStatic ? staticMagic: dynamicMagic); + out.write(buffer.array(), 0, 4); + } + return file; + } + private static FileChannel getFileChannel(File file, boolean write) throws Exception { List arry = new ArrayList(); arry.add(READ); diff --git a/test/lib/jdk/test/lib/cds/CDSOptions.java b/test/lib/jdk/test/lib/cds/CDSOptions.java index cbc11db777b1a55d1f34930c122614c0e6657d9c..a60afb90aed29b2b7c2c25e3d182af0aebc1a6e4 100644 --- a/test/lib/jdk/test/lib/cds/CDSOptions.java +++ b/test/lib/jdk/test/lib/cds/CDSOptions.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -56,6 +56,11 @@ public class CDSOptions { return this; } + public CDSOptions addSuffix(ArrayList suffix) { + for (String s : suffix) this.suffix.add(s); + return this; + } + public CDSOptions addSuffix(String... suffix) { for (String s : suffix) this.suffix.add(s); return this; diff --git a/test/lib/jdk/test/lib/cds/CDSTestUtils.java b/test/lib/jdk/test/lib/cds/CDSTestUtils.java index c3ce3a9550470bc4a90fb8fff0498bdb69343a66..f9391c96ee4ece72cdeceeb9024edda6da23a249 100644 --- a/test/lib/jdk/test/lib/cds/CDSTestUtils.java +++ b/test/lib/jdk/test/lib/cds/CDSTestUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -26,6 +26,9 @@ import java.io.IOException; import java.io.File; import java.io.FileOutputStream; import java.io.PrintStream; +import java.nio.file.Files; +import java.nio.file.CopyOption; +import java.nio.file.StandardCopyOption; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; @@ -41,7 +44,7 @@ public class CDSTestUtils { public static final String MSG_RANGE_ALREADT_IN_USE = "Unable to allocate region, java heap range is already in use."; public static final String MSG_DYNAMIC_NOT_SUPPORTED = - "DynamicDumpSharedSpaces is unsupported when base CDS archive is not loaded"; + "-XX:ArchiveClassesAtExit is unsupported when base CDS archive is not loaded"; public static final boolean DYNAMIC_DUMP = Boolean.getBoolean("test.dynamic.cds.archive"); public interface Checker { @@ -326,9 +329,7 @@ public class CDSTestUtils { // Special case -- sometimes Xshare:on fails because it failed to map // at given address. This behavior is platform-specific, machine config-specific // and can be random (see ASLR). - if (isUnableToMap(output)) { - throw new SkippedException(UnableToMapMsg); - } + checkMappingFailure(output); if (e != null) { throw e; @@ -351,19 +352,28 @@ public class CDSTestUtils { // instead of utilizing multiple messages. // These are suggestions to improve testibility of the VM. However, implementing them // could also improve usability in the field. - public static boolean isUnableToMap(OutputAnalyzer output) { + private static String hasUnableToMapMessage(OutputAnalyzer output) { String outStr = output.getOutput(); - if ((output.getExitValue() == 1) && - (outStr.contains(MSG_RANGE_NOT_WITHIN_HEAP) || outStr.contains(MSG_DYNAMIC_NOT_SUPPORTED))) { - return true; + if ((output.getExitValue() == 1)) { + if (outStr.contains(MSG_RANGE_NOT_WITHIN_HEAP)) { + return MSG_RANGE_NOT_WITHIN_HEAP; + } + if (outStr.contains(MSG_DYNAMIC_NOT_SUPPORTED)) { + return MSG_DYNAMIC_NOT_SUPPORTED; + } } - return false; + return null; + } + + public static boolean isUnableToMap(OutputAnalyzer output) { + return hasUnableToMapMessage(output) != null; } public static void checkMappingFailure(OutputAnalyzer out) throws SkippedException { - if (isUnableToMap(out)) { - throw new SkippedException(UnableToMapMsg); + String match = hasUnableToMapMessage(out); + if (match != null) { + throw new SkippedException(UnableToMapMsg + ": " + match); } } @@ -472,10 +482,7 @@ public class CDSTestUtils { public static OutputAnalyzer checkExecExpectError(OutputAnalyzer output, int expectedExitValue, String... extraMatches) throws Exception { - if (isUnableToMap(output)) { - throw new SkippedException(UnableToMapMsg); - } - + checkMappingFailure(output); output.shouldHaveExitValue(expectedExitValue); checkMatches(output, extraMatches); return output; @@ -680,4 +687,78 @@ public class CDSTestUtils { private static boolean isAsciiPrintable(char ch) { return ch >= 32 && ch < 127; } + + // JDK utility + + // Do a cheap clone of the JDK. Most files can be sym-linked. However, $JAVA_HOME/bin/java and $JAVA_HOME/lib/.../libjvm.so" + // must be copied, because the java.home property is derived from the canonicalized paths of these 2 files. + // Set a list of {jvm, "java"} which will be physically copied. If a file needs copied physically, add it to the list. + private static String[] phCopied = {System.mapLibraryName("jvm"), "java"}; + public static void clone(File src, File dst) throws Exception { + if (dst.exists()) { + if (!dst.isDirectory()) { + throw new RuntimeException("Not a directory :" + dst); + } + } else { + if (!dst.mkdir()) { + throw new RuntimeException("Cannot create directory: " + dst); + } + } + // final String jvmLib = System.mapLibraryName("jvm"); + for (String child : src.list()) { + if (child.equals(".") || child.equals("..")) { + continue; + } + + File child_src = new File(src, child); + File child_dst = new File(dst, child); + if (child_dst.exists()) { + throw new RuntimeException("Already exists: " + child_dst); + } + if (child_src.isFile()) { + boolean needPhCopy = false; + for (String target : phCopied) { + if (child.equals(target)) { + needPhCopy = true; + break; + } + } + if (needPhCopy) { + Files.copy(child_src.toPath(), /* copy data to -> */ child_dst.toPath(), + new CopyOption[] { StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.COPY_ATTRIBUTES}); + } else { + Files.createSymbolicLink(child_dst.toPath(), /* link to -> */ child_src.toPath()); + } + } else { + clone(child_src, child_dst); + } + } + } + + // modulesDir, like $JDK/lib + // oldName, module name under modulesDir + // newName, new name for oldName + public static void rename(File fromFile, File toFile) throws Exception { + if (!fromFile.exists()) { + throw new RuntimeException(fromFile.getName() + " does not exist"); + } + + if (toFile.exists()) { + throw new RuntimeException(toFile.getName() + " already exists"); + } + + boolean success = fromFile.renameTo(toFile); + if (!success) { + throw new RuntimeException("rename file " + fromFile.getName()+ " to " + toFile.getName() + " failed"); + } + } + + public static ProcessBuilder makeBuilder(String... args) throws Exception { + System.out.print("["); + for (String s : args) { + System.out.print(" " + s); + } + System.out.println(" ]"); + return new ProcessBuilder(args); + } } diff --git a/test/lib/jdk/test/lib/classloader/ClassUnloadCommon.java b/test/lib/jdk/test/lib/classloader/ClassUnloadCommon.java index ce0e3dadd32c40704e428563b22170870d7c905b..23e8fa62b532ec5c8e400fd74821afe767a5e426 100644 --- a/test/lib/jdk/test/lib/classloader/ClassUnloadCommon.java +++ b/test/lib/jdk/test/lib/classloader/ClassUnloadCommon.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -31,8 +31,6 @@ package jdk.test.lib.classloader; import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; diff --git a/test/lib/jdk/test/lib/compiler/InMemoryJavaCompiler.java b/test/lib/jdk/test/lib/compiler/InMemoryJavaCompiler.java index 9444e4cc97b50f70889f8e9b231e158c7917d12b..3fe7b43a82402ce9374d90b8066b5246fc209975 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, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -36,6 +36,7 @@ import javax.tools.ForwardingJavaFileManager; import javax.tools.FileObject; import javax.tools.JavaCompiler; import javax.tools.JavaCompiler.CompilationTask; +import javax.tools.JavaFileManager; import javax.tools.JavaFileObject; import javax.tools.JavaFileObject.Kind; import javax.tools.SimpleJavaFileObject; @@ -106,7 +107,7 @@ public class InMemoryJavaCompiler { } } - private static class FileManagerWrapper extends ForwardingJavaFileManager { + private static class FileManagerWrapper extends ForwardingJavaFileManager { private static final Location PATCH_LOCATION = new Location() { @Override public String getName() { diff --git a/test/lib/jdk/test/lib/containers/docker/Common.java b/test/lib/jdk/test/lib/containers/docker/Common.java index 4f1d0e0bd73f78e54f68fc878ed7cb60aedd1ea0..4c9cccbc22e90d1beadad0924d49adf2f1893b59 100644 --- a/test/lib/jdk/test/lib/containers/docker/Common.java +++ b/test/lib/jdk/test/lib/containers/docker/Common.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -31,8 +31,6 @@ import java.io.File; import java.nio.file.Files; import java.nio.file.Paths; import java.nio.file.StandardCopyOption; -import jdk.test.lib.containers.docker.DockerRunOptions; -import jdk.test.lib.containers.docker.DockerTestUtils; import jdk.test.lib.Utils; import jdk.test.lib.process.OutputAnalyzer; diff --git a/test/lib/jdk/test/lib/containers/docker/DockerTestUtils.java b/test/lib/jdk/test/lib/containers/docker/DockerTestUtils.java index 8e381180dfbb2fe470f673bcc62510cb92d25933..fa4b11030c19fd5cdc979adcdc32c450857d33e6 100644 --- a/test/lib/jdk/test/lib/containers/docker/DockerTestUtils.java +++ b/test/lib/jdk/test/lib/containers/docker/DockerTestUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -23,7 +23,6 @@ package jdk.test.lib.containers.docker; -import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.nio.file.Files; diff --git a/test/lib/jdk/test/lib/format/ArrayCodec.java b/test/lib/jdk/test/lib/format/ArrayCodec.java index 0e34e7cd811226da3ff0e3754c2cd097932fe9df..b5faf352aa2caa3e484d08d83ef5313d44c5f2ec 100644 --- a/test/lib/jdk/test/lib/format/ArrayCodec.java +++ b/test/lib/jdk/test/lib/format/ArrayCodec.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -25,7 +25,6 @@ package jdk.test.lib.format; import java.util.ArrayList; import java.util.List; -import java.util.Optional; /** * A codec helping representing arrays in a string form. @@ -141,7 +140,7 @@ public class ArrayCodec { * @throws IllegalArgumentException if {@code array}'s component type is not supported * @return an ArrayCodec for the provided array */ - public static ArrayCodec of(Object array) { + public static ArrayCodec of(Object array) { var type = array.getClass().getComponentType(); if (type == byte.class) { return ArrayCodec.of((byte[])array); diff --git a/test/lib/jdk/test/lib/format/ArrayDiff.java b/test/lib/jdk/test/lib/format/ArrayDiff.java index 6755a693b7c8340c01477b7dd9bcd3c98e332182..136827cb0520472749bb8a58f06d72477824d1fd 100644 --- a/test/lib/jdk/test/lib/format/ArrayDiff.java +++ b/test/lib/jdk/test/lib/format/ArrayDiff.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -23,8 +23,6 @@ package jdk.test.lib.format; -import java.util.ArrayList; -import java.util.List; import java.util.Objects; import java.util.Optional; @@ -93,7 +91,7 @@ public class ArrayDiff implements Diff { * @param second the second array * @return an ArrayDiff instance for the two arrays */ - public static ArrayDiff of(Object first, Object second) { + public static ArrayDiff of(Object first, Object second) { return ArrayDiff.of(first, second, Diff.Defaults.WIDTH, Diff.Defaults.CONTEXT_BEFORE); } @@ -109,7 +107,8 @@ public class ArrayDiff implements Diff { * @throws NullPointerException if at least one of the arrays is null * @return an ArrayDiff instance for the two arrays and formatting parameters provided */ - public static ArrayDiff of(Object first, Object second, int width, int contextBefore) { + @SuppressWarnings("rawtypes") + public static ArrayDiff of(Object first, Object second, int width, int contextBefore) { Objects.requireNonNull(first); Objects.requireNonNull(second); @@ -204,4 +203,3 @@ public class ArrayDiff implements Diff { } } - diff --git a/test/lib/jdk/test/lib/helpers/ClassFileInstaller.java b/test/lib/jdk/test/lib/helpers/ClassFileInstaller.java index 3c07469b7f77113884b15d9c06ce8f858b74d276..65660d11ba137f1a3d51037f98fc332775d48f8d 100644 --- a/test/lib/jdk/test/lib/helpers/ClassFileInstaller.java +++ b/test/lib/jdk/test/lib/helpers/ClassFileInstaller.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -27,9 +27,7 @@ import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; -import java.io.FileNotFoundException; import java.io.InputStream; -import java.io.ByteArrayInputStream; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; diff --git a/test/lib/jdk/test/lib/hexdump/ASN1Formatter.java b/test/lib/jdk/test/lib/hexdump/ASN1Formatter.java index 5001978b8603c33dc87e004e13983a7baf1f8b77..ad96466d75f9977da4bcacc83715d5e90f415655 100644 --- a/test/lib/jdk/test/lib/hexdump/ASN1Formatter.java +++ b/test/lib/jdk/test/lib/hexdump/ASN1Formatter.java @@ -626,6 +626,7 @@ public class ASN1Formatter implements HexPrinter.Formatter { * @return the InputStream or the wrapped decoder of Base64Mime. * @throws IOException if an I/O error occurs */ + @SuppressWarnings("deprecation") private static InputStream wrapIfBase64Mime(BufferedInputStream bis) throws IOException { bis.mark(256); DataInputStream dis = new DataInputStream(bis); diff --git a/test/lib/jdk/test/lib/hexdump/ObjectStreamPrinter.java b/test/lib/jdk/test/lib/hexdump/ObjectStreamPrinter.java index 3b52ece6a7420cf3160095a9d1cecf98931f72e6..110840256d3816482088a1add7107247fc16a691 100644 --- a/test/lib/jdk/test/lib/hexdump/ObjectStreamPrinter.java +++ b/test/lib/jdk/test/lib/hexdump/ObjectStreamPrinter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -41,9 +41,6 @@ import java.util.StringJoiner; import java.util.function.BiConsumer; import static java.io.ObjectStreamConstants.STREAM_MAGIC; -import static java.io.ObjectStreamConstants.TC_BLOCKDATA; -import static java.io.ObjectStreamConstants.TC_BLOCKDATALONG; -import static java.io.ObjectStreamConstants.TC_ENDBLOCKDATA; import static java.io.ObjectStreamConstants.TC_MAX; import static java.io.ObjectStreamConstants.TC_NULL; import static java.io.ObjectStreamConstants.baseWireHandle; diff --git a/test/lib/jdk/test/lib/hexdump/StreamDump.java b/test/lib/jdk/test/lib/hexdump/StreamDump.java index 21ad296bca8c413e4bf78d7c395b798b16279f5c..cbdef1f61dc4d6f60fa51edfbb2cf18091242217 100644 --- a/test/lib/jdk/test/lib/hexdump/StreamDump.java +++ b/test/lib/jdk/test/lib/hexdump/StreamDump.java @@ -165,6 +165,7 @@ public class StreamDump { * @return an InputStream, unchanged unless it is Base64 Mime * @throws IOException if an I/O Error occurs */ + @SuppressWarnings("deprecation") static InputStream decodeMaybe(InputStream is) throws IOException { DataInputStream dis = new DataInputStream(is); is.mark(1024); diff --git a/test/lib/jdk/test/lib/hprof/model/JavaObjectArray.java b/test/lib/jdk/test/lib/hprof/model/JavaObjectArray.java index d6bbe853f35cbad8815d6a7826fe7e001f62ede5..232c62794e1b792cb488ba40916562d20b52afb7 100644 --- a/test/lib/jdk/test/lib/hprof/model/JavaObjectArray.java +++ b/test/lib/jdk/test/lib/hprof/model/JavaObjectArray.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -33,7 +33,6 @@ package jdk.test.lib.hprof.model; import java.io.IOException; -import jdk.test.lib.hprof.parser.ReadBuffer; /** * @author Bill Foote diff --git a/test/lib/jdk/test/lib/hprof/model/JavaThing.java b/test/lib/jdk/test/lib/hprof/model/JavaThing.java index f7710390b231c37b00218a65a2d0f801c556ca17..024928ec0191f236cd98f70777ec831c2ffc63cd 100644 --- a/test/lib/jdk/test/lib/hprof/model/JavaThing.java +++ b/test/lib/jdk/test/lib/hprof/model/JavaThing.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -32,10 +32,6 @@ package jdk.test.lib.hprof.model; -import java.util.Enumeration; -import java.util.Hashtable; - - /** * * @author Bill Foote diff --git a/test/lib/jdk/test/lib/hprof/model/JavaValueArray.java b/test/lib/jdk/test/lib/hprof/model/JavaValueArray.java index 12ca34dd39b74bdcb4c0f2c3176752cee53ccc46..8e5ae94f78d412a679aaed5f1b712fe490189d8b 100644 --- a/test/lib/jdk/test/lib/hprof/model/JavaValueArray.java +++ b/test/lib/jdk/test/lib/hprof/model/JavaValueArray.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -32,7 +32,6 @@ package jdk.test.lib.hprof.model; -import jdk.test.lib.hprof.parser.ReadBuffer; import java.io.IOException; import java.util.Objects; diff --git a/test/lib/jdk/test/lib/hprof/model/ReachableExcludesImpl.java b/test/lib/jdk/test/lib/hprof/model/ReachableExcludesImpl.java index 5038f71ddc0f8fd8e1aa843d49d3626936b56a90..af4abbfea9b4b67d03b199cdbe0d2b116821bbb4 100644 --- a/test/lib/jdk/test/lib/hprof/model/ReachableExcludesImpl.java +++ b/test/lib/jdk/test/lib/hprof/model/ReachableExcludesImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -35,7 +35,6 @@ package jdk.test.lib.hprof.model; import java.io.File; import java.io.FileInputStream; import java.io.InputStreamReader; -import java.io.Reader; import java.io.BufferedReader; import java.io.IOException; diff --git a/test/lib/jdk/test/lib/hprof/model/ReachableObjects.java b/test/lib/jdk/test/lib/hprof/model/ReachableObjects.java index 8b96987eaa14f1d46f1618d59f6eeb9678b04248..1ba41e9fe86ce1eeb1910d8f27de130651c2739f 100644 --- a/test/lib/jdk/test/lib/hprof/model/ReachableObjects.java +++ b/test/lib/jdk/test/lib/hprof/model/ReachableObjects.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -32,7 +32,6 @@ package jdk.test.lib.hprof.model; -import java.util.Vector; import java.util.Hashtable; import java.util.Enumeration; diff --git a/test/lib/jdk/test/lib/hprof/util/ArraySorter.java b/test/lib/jdk/test/lib/hprof/util/ArraySorter.java index 04dbad7ff0b3137df6d3fa78378405238b8de1d3..5378528a93ec33b16e1424804ad4cd378c186f33 100644 --- a/test/lib/jdk/test/lib/hprof/util/ArraySorter.java +++ b/test/lib/jdk/test/lib/hprof/util/ArraySorter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -31,7 +31,6 @@ */ package jdk.test.lib.hprof.util; -import java.util.*; /** * A singleton utility class that sorts an array of objects. diff --git a/test/lib/jdk/test/lib/hprof/util/Misc.java b/test/lib/jdk/test/lib/hprof/util/Misc.java index e654d71d4ce1388710527edcc2122b8d75b3c3ab..42e0ce0b46e28b1bf2ca05784993438c6b4bd049 100644 --- a/test/lib/jdk/test/lib/hprof/util/Misc.java +++ b/test/lib/jdk/test/lib/hprof/util/Misc.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -31,7 +31,6 @@ */ package jdk.test.lib.hprof.util; -import java.util.*; /** * Miscellaneous functions I couldn't think of a good place to put. diff --git a/test/lib/jdk/test/lib/jfr/StreamingUtils.java b/test/lib/jdk/test/lib/jfr/StreamingUtils.java index cb95c3d25d89f4be3d4c802af16d031775548842..427a4eb4262fb7790aa81d91106550e81c0331c0 100644 --- a/test/lib/jdk/test/lib/jfr/StreamingUtils.java +++ b/test/lib/jdk/test/lib/jfr/StreamingUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -43,16 +43,18 @@ public class StreamingUtils { public static Path getJfrRepository(Process process) throws Exception { while (true) { if (!process.isAlive()) { - String msg = String.format("Process (pid = %d) is no longer alive, exit value = %d", + String msg = String.format("Process (pid = %d) is no longer alive, exit value = %d\n", process.pid(), process.exitValue()); + msg += "Stderr: " + new String(process.getErrorStream().readAllBytes()) + "\n"; + msg += "Stdout: " + new String(process.getInputStream().readAllBytes()) + "\n"; throw new RuntimeException(msg); } try { VirtualMachine vm = VirtualMachine.attach(String.valueOf(process.pid())); String repo = vm.getSystemProperties().getProperty("jdk.jfr.repository"); + vm.detach(); if (repo != null) { - vm.detach(); System.out.println("JFR repository: " + repo); return Paths.get(repo); } diff --git a/test/lib/jdk/test/lib/net/HttpHeaderParser.java b/test/lib/jdk/test/lib/net/HttpHeaderParser.java new file mode 100644 index 0000000000000000000000000000000000000000..71b3a84fdaa6f453aee35cb9bb53bb34d250a6d6 --- /dev/null +++ b/test/lib/jdk/test/lib/net/HttpHeaderParser.java @@ -0,0 +1,390 @@ +/* + * 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. + */ + +package jdk.test.lib.net; + +import java.io.IOException; +import java.io.InputStream; +import java.net.ProtocolException; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; + +import static java.util.Objects.requireNonNull; + +public class HttpHeaderParser { + private static final char CR = '\r'; + private static final char LF = '\n'; + private static final char HT = '\t'; + private static final char SP = ' '; + // ABNF primitives defined in RFC 7230 + private static boolean[] tchar = new boolean[256]; + private static boolean[] fieldvchar = new boolean[256]; + + static { + char[] allowedTokenChars = + ("!#$%&'*+-.^_`|~0123456789" + + "abcdefghijklmnopqrstuvwxyz" + + "ABCDEFGHIJKLMNOPQRSTUVWXYZ").toCharArray(); + for (char c : allowedTokenChars) { + tchar[c] = true; + } + for (char c = 0x21; c <= 0xFF; c++) { + fieldvchar[c] = true; + } + fieldvchar[0x7F] = false; // a little hole (DEL) in the range + } + + private StringBuilder sb = new StringBuilder(); + + private Map > headerMap = new LinkedHashMap<>(); + private List keyList = new ArrayList<>(); + private String requestOrStatusLine; + private int responseCode; + private boolean eof; + + + + enum State { INITIAL, + STATUS_OR_REQUEST_LINE, + STATUS_OR_REQUEST_LINE_FOUND_CR, + STATUS_OR_REQUEST_LINE_FOUND_LF, + STATUS_OR_REQUEST_LINE_END, + STATUS_OR_REQUEST_LINE_END_CR, + STATUS_OR_REQUEST_LINE_END_LF, + HEADER, + HEADER_FOUND_CR, + HEADER_FOUND_LF, + HEADER_FOUND_CR_LF, + HEADER_FOUND_CR_LF_CR, + FINISHED } + + private HttpHeaderParser.State state = HttpHeaderParser.State.INITIAL; + + public HttpHeaderParser() { + } + + + public HttpHeaderParser(InputStream is) throws IOException, ProtocolException { + parse(is); + } + + public Map> getHeaderMap() { + return headerMap; + } + + public List getHeaderValue(String key) { + if(headerMap.containsKey(key.toLowerCase(Locale.ROOT))) { + return headerMap.get(key.toLowerCase(Locale.ROOT)); + } + return null; + } + public List getValue(int id) { + String key = keyList.get(id); + return headerMap.get(key); + } + + public String getRequestDetails() { + return requestOrStatusLine; + } + + /** + * Parses HTTP/1.X status-line or request-line and headers from the given input stream. + * @param input Containing the input stream of bytes representing request or response header data + * @return true if the end of the headers block has been reached + */ + public boolean parse(InputStream input) throws IOException { + requireNonNull(input, "null input"); + while (canContinueParsing()) { + switch (state) { + case INITIAL -> state = HttpHeaderParser.State.STATUS_OR_REQUEST_LINE; + case STATUS_OR_REQUEST_LINE -> readResumeStatusLine(input); + case STATUS_OR_REQUEST_LINE_FOUND_CR, STATUS_OR_REQUEST_LINE_FOUND_LF -> readStatusLineFeed(input); + case STATUS_OR_REQUEST_LINE_END -> maybeStartHeaders(input); + case STATUS_OR_REQUEST_LINE_END_CR, STATUS_OR_REQUEST_LINE_END_LF -> maybeEndHeaders(input); + case HEADER -> readResumeHeader(input); + case HEADER_FOUND_CR, HEADER_FOUND_LF -> resumeOrLF(input); + case HEADER_FOUND_CR_LF -> resumeOrSecondCR(input); + case HEADER_FOUND_CR_LF_CR -> resumeOrEndHeaders(input); + default -> throw new InternalError("Unexpected state: " + state); + } + } + return state == HttpHeaderParser.State.FINISHED; + } + + private boolean canContinueParsing() { + // some states don't require any input to transition + // to the next state. + return switch (state) { + case FINISHED -> false; + case STATUS_OR_REQUEST_LINE_FOUND_LF, STATUS_OR_REQUEST_LINE_END_LF, HEADER_FOUND_LF -> true; + default -> !eof; + }; + } + + /** + * Returns a character (char) corresponding to the next byte in the + * input, interpreted as an ISO-8859-1 encoded character. + *

          + * The ISO-8859-1 encoding is a 8-bit character coding that + * corresponds to the first 256 Unicode characters - from U+0000 to + * U+00FF. UTF-16 is backward compatible with ISO-8859-1 - which + * means each byte in the input should be interpreted as an unsigned + * value from [0, 255] representing the character code. + * + * @param input a {@code InputStream} containing input stream of Bytes. + * @return the next byte in the input, interpreted as an ISO-8859-1 + * encoded char + * @throws IOException + * if an I/O error occurs. + */ + private char get(InputStream input) throws IOException { + int c = input.read(); + if(c < 0) + eof = true; + return (char)(c & 0xFF); + } + + private void readResumeStatusLine(InputStream input) throws IOException { + char c; + while ((c = get(input)) != CR && !eof) { + if (c == LF) break; + sb.append(c); + } + if (c == CR) { + state = HttpHeaderParser.State.STATUS_OR_REQUEST_LINE_FOUND_CR; + } else if (c == LF) { + state = HttpHeaderParser.State.STATUS_OR_REQUEST_LINE_FOUND_LF; + } + } + + private void readStatusLineFeed(InputStream input) throws IOException { + char c = state == HttpHeaderParser.State.STATUS_OR_REQUEST_LINE_FOUND_LF ? LF : get(input); + if (c != LF) { + throw protocolException("Bad trailing char, \"%s\", when parsing status line, \"%s\"", + c, sb.toString()); + } + requestOrStatusLine = sb.toString(); + sb = new StringBuilder(); + if (!requestOrStatusLine.startsWith("HTTP/1.")) { + if(!requestOrStatusLine.startsWith("GET") && !requestOrStatusLine.startsWith("POST") && + !requestOrStatusLine.startsWith("PUT") && !requestOrStatusLine.startsWith("DELETE") && + !requestOrStatusLine.startsWith("OPTIONS") && !requestOrStatusLine.startsWith("HEAD") && + !requestOrStatusLine.startsWith("PATCH") && !requestOrStatusLine.startsWith("CONNECT")) { + throw protocolException("Invalid request Or Status line: \"%s\"", requestOrStatusLine); + } else { //This is request + System.out.println("Request is :"+requestOrStatusLine); + } + } else { //This is response + if (requestOrStatusLine.length() < 12) { + throw protocolException("Invalid status line: \"%s\"", requestOrStatusLine); + } + try { + responseCode = Integer.parseInt(requestOrStatusLine.substring(9, 12)); + } catch (NumberFormatException nfe) { + throw protocolException("Invalid status line: \"%s\"", requestOrStatusLine); + } + // response code expected to be a 3-digit integer (RFC-2616, section 6.1.1) + if (responseCode < 100) { + throw protocolException("Invalid status line: \"%s\"", requestOrStatusLine); + } + } + state = HttpHeaderParser.State.STATUS_OR_REQUEST_LINE_END; + } + + private void maybeStartHeaders(InputStream input) throws IOException { + assert state == HttpHeaderParser.State.STATUS_OR_REQUEST_LINE_END; + assert sb.length() == 0; + char c = get(input); + if(!eof) { + if (c == CR) { + state = HttpHeaderParser.State.STATUS_OR_REQUEST_LINE_END_CR; + } else if (c == LF) { + state = HttpHeaderParser.State.STATUS_OR_REQUEST_LINE_END_LF; + } else { + sb.append(c); + state = HttpHeaderParser.State.HEADER; + } + } + } + + private void maybeEndHeaders(InputStream input) throws IOException { + assert state == HttpHeaderParser.State.STATUS_OR_REQUEST_LINE_END_CR || state == HttpHeaderParser.State.STATUS_OR_REQUEST_LINE_END_LF; + assert sb.length() == 0; + char c = state == HttpHeaderParser.State.STATUS_OR_REQUEST_LINE_END_LF ? LF : get(input); + if (c == LF) { + state = HttpHeaderParser.State.FINISHED; // no headers + } else { + throw protocolException("Unexpected \"%s\", after status line CR", c); + } + } + + private void readResumeHeader(InputStream input) throws IOException { + assert state == HttpHeaderParser.State.HEADER; + assert !eof; + char c = get(input); + while (!eof) { + if (c == CR) { + state = HttpHeaderParser.State.HEADER_FOUND_CR; + break; + } else if (c == LF) { + state = HttpHeaderParser.State.HEADER_FOUND_LF; + break; + } + if (c == HT) + c = SP; + sb.append(c); + c = get(input); + } + } + + private void addHeaderFromString(String headerString) throws ProtocolException { + assert sb.length() == 0; + int idx = headerString.indexOf(':'); + if (idx == -1) + return; + String name = headerString.substring(0, idx); + + // compatibility with HttpURLConnection; + if (name.isEmpty()) return; + + if (!isValidName(name)) { + throw protocolException("Invalid header name \"%s\"", name); + } + String value = headerString.substring(idx + 1).trim(); + if (!isValidValue(value)) { + throw protocolException("Invalid header value \"%s: %s\"", name, value); + } + + keyList.add(name); + headerMap.computeIfAbsent(name.toLowerCase(Locale.US), + k -> new ArrayList<>()).add(value); + } + + private void resumeOrLF(InputStream input) throws IOException { + assert state == HttpHeaderParser.State.HEADER_FOUND_CR || state == HttpHeaderParser.State.HEADER_FOUND_LF; + char c = state == HttpHeaderParser.State.HEADER_FOUND_LF ? LF : get(input); + if (!eof) { + if (c == LF) { + state = HttpHeaderParser.State.HEADER_FOUND_CR_LF; + } else if (c == SP || c == HT) { + sb.append(SP); // parity with MessageHeaders + state = HttpHeaderParser.State.HEADER; + } else { + sb = new StringBuilder(); + sb.append(c); + state = HttpHeaderParser.State.HEADER; + } + } + } + + private void resumeOrSecondCR(InputStream input) throws IOException { + assert state == HttpHeaderParser.State.HEADER_FOUND_CR_LF; + char c = get(input); + if (!eof) { + if (c == CR || c == LF) { + if (sb.length() > 0) { + // no continuation line - flush + // previous header value. + String headerString = sb.toString(); + sb = new StringBuilder(); + addHeaderFromString(headerString); + } + if (c == CR) { + state = HttpHeaderParser.State.HEADER_FOUND_CR_LF_CR; + } else { + state = HttpHeaderParser.State.FINISHED; + } + } else if (c == SP || c == HT) { + assert sb.length() != 0; + sb.append(SP); // continuation line + state = HttpHeaderParser.State.HEADER; + } else { + if (sb.length() > 0) { + // no continuation line - flush + // previous header value. + String headerString = sb.toString(); + sb = new StringBuilder(); + addHeaderFromString(headerString); + } + sb.append(c); + state = HttpHeaderParser.State.HEADER; + } + } + } + + private void resumeOrEndHeaders(InputStream input) throws IOException { + assert state == HttpHeaderParser.State.HEADER_FOUND_CR_LF_CR; + char c = get(input); + if (!eof) { + if (c == LF) { + state = HttpHeaderParser.State.FINISHED; + } else { + throw protocolException("Unexpected \"%s\", after CR LF CR", c); + } + } + } + + private ProtocolException protocolException(String format, Object ... args) { + return new ProtocolException(String.format(format, args)); + } + + /* + * Validates a RFC 7230 field-name. + */ + public boolean isValidName(String token) { + for (int i = 0; i < token.length(); i++) { + char c = token.charAt(i); + if (c > 255 || !tchar[c]) { + return false; + } + } + return !token.isEmpty(); + } + + /* + * Validates a RFC 7230 field-value. + * + * "Obsolete line folding" rule + * + * obs-fold = CRLF 1*( SP / HTAB ) + * + * is not permitted! + */ + public boolean isValidValue(String token) { + for (int i = 0; i < token.length(); i++) { + char c = token.charAt(i); + if (c > 255) { + return false; + } + if (c == ' ' || c == '\t') { + continue; + } else if (!fieldvchar[c]) { + return false; // forbidden byte + } + } + return true; + } +} diff --git a/test/lib/jdk/test/lib/net/IPSupport.java b/test/lib/jdk/test/lib/net/IPSupport.java index b86354a2503e0d12b1bd9ef89d09c2a915494da7..78efba3a172aafebd7f4b01acd4a277177f31e44 100644 --- a/test/lib/jdk/test/lib/net/IPSupport.java +++ b/test/lib/jdk/test/lib/net/IPSupport.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -71,6 +71,7 @@ public class IPSupport { } } + @SuppressWarnings("removal") private static T runPrivilegedAction(Callable callable) { try { PrivilegedExceptionAction pa = () -> callable.call(); diff --git a/test/lib/jdk/test/lib/net/SimpleSSLContext.java b/test/lib/jdk/test/lib/net/SimpleSSLContext.java index 5660ed048aa64bda61a472785b31ee064b5cccce..e8611fb007f32d75e3fb86e4380cc284aecb0417 100644 --- a/test/lib/jdk/test/lib/net/SimpleSSLContext.java +++ b/test/lib/jdk/test/lib/net/SimpleSSLContext.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -54,6 +54,7 @@ public class SimpleSSLContext { this(() -> "TLS"); } + @SuppressWarnings("removal") private SimpleSSLContext(Supplier protocols) throws IOException { try { final String proto = protocols.get(); diff --git a/test/lib/jdk/test/lib/net/testkeys b/test/lib/jdk/test/lib/net/testkeys index 4673898e0ae15936ac8b83357b802dc425f0c64c..d2818ec9b6c6dd5386a2cabe53b923bf6046e577 100644 Binary files a/test/lib/jdk/test/lib/net/testkeys and b/test/lib/jdk/test/lib/net/testkeys differ diff --git a/test/lib/jdk/test/lib/process/Proc.java b/test/lib/jdk/test/lib/process/Proc.java index def8796fce86a23349b56a7486b16b890d74eaba..3541f34144fe0c09d1331615aece1ee75566a3b6 100644 --- a/test/lib/jdk/test/lib/process/Proc.java +++ b/test/lib/jdk/test/lib/process/Proc.java @@ -113,8 +113,8 @@ public class Proc { private List args = new ArrayList<>(); private Map env = new HashMap<>(); - private Map prop = new HashMap(); - private Map secprop = new HashMap(); + private Map prop = new HashMap<>(); + private Map secprop = new HashMap<>(); private boolean inheritIO = false; private boolean noDump = false; diff --git a/test/lib/jdk/test/lib/process/ProcessTools.java b/test/lib/jdk/test/lib/process/ProcessTools.java index 7998bbbbe8248ef328a1b4d3709313550f3e10a2..19e3bb54785fc66bad837a152e00a4aa20021d80 100644 --- a/test/lib/jdk/test/lib/process/ProcessTools.java +++ b/test/lib/jdk/test/lib/process/ProcessTools.java @@ -432,6 +432,7 @@ public final class ProcessTools { * the default charset. * @return The {@linkplain OutputAnalyzer} instance wrapping the process. */ + @SuppressWarnings("removal") public static OutputAnalyzer executeProcess(ProcessBuilder pb, String input, Charset cs) throws Exception { OutputAnalyzer output = null; @@ -604,6 +605,7 @@ public final class ProcessTools { return pb; } + @SuppressWarnings("removal") private static Process privilegedStart(ProcessBuilder pb) throws IOException { try { return AccessController.doPrivileged( diff --git a/test/lib/jdk/test/lib/security/KeyStoreUtils.java b/test/lib/jdk/test/lib/security/KeyStoreUtils.java index b205de2e7ffc8c5ddc6f4ad3ed45d877da70e519..aa5be6f78a36cd8954f00ff465e5d68eedd96ff0 100644 --- a/test/lib/jdk/test/lib/security/KeyStoreUtils.java +++ b/test/lib/jdk/test/lib/security/KeyStoreUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -31,7 +31,6 @@ import java.security.KeyStore; import java.security.PrivateKey; import java.security.cert.Certificate; import java.security.cert.CertificateFactory; -import java.security.KeyStore; import java.util.ArrayList; import java.util.Base64; import java.util.List; diff --git a/test/lib/jdk/test/lib/security/XMLUtils.java b/test/lib/jdk/test/lib/security/XMLUtils.java index bffab4be405797e4aa142a2c1a6ed71241df95d6..fa93e3f6b003207302f64c8032ddd1035d0be5f5 100644 --- a/test/lib/jdk/test/lib/security/XMLUtils.java +++ b/test/lib/jdk/test/lib/security/XMLUtils.java @@ -92,9 +92,11 @@ public class XMLUtils { Asserts.assertTrue(v2.validate(s3.sign(d))); // can read KeyInfo Asserts.assertTrue(v2.secureValidation(false).validate(s3.sign(p.toUri()))); // can read KeyInfo Asserts.assertTrue(v2.secureValidation(false).baseURI(b).validate( - s3.sign(p.getParent().toUri(), p.getFileName().toUri()))); // can read KeyInfo + s3.sign(p.toAbsolutePath().getParent().toUri(), p.getFileName().toUri()))); // can read KeyInfo Asserts.assertTrue(v1.validate(s1.sign("text"))); // plain text Asserts.assertTrue(v1.validate(s1.sign("binary".getBytes()))); // raw data + Asserts.assertTrue(v1.validate(s1.signEnveloping(d, "x", "#x"))); + Asserts.assertTrue(v1.validate(s1.signEnveloping(d, "x", "#xpointer(id('x'))"))); } //////////// CONVERT //////////// @@ -347,14 +349,14 @@ public class XMLUtils { } // Signs a document in enveloping mode - public Document signEnveloping(Document document) throws Exception { + public Document signEnveloping(Document document, String id, String ref) throws Exception { Document newDocument = DocumentBuilderFactory.newInstance() .newDocumentBuilder().newDocument(); FAC.newXMLSignature( - buildSignedInfo(FAC.newReference("#object", dm)), + buildSignedInfo(FAC.newReference(ref, dm)), buildKeyInfo(), List.of(FAC.newXMLObject(List.of(new DOMStructure(document.getDocumentElement())), - "object", null, null)), + id, null, null)), null, null) .sign(new DOMSignContext(privateKey, newDocument)); @@ -474,7 +476,7 @@ public class XMLUtils { // If key is not null, any key from the signature will be ignored public boolean validate(Document document, PublicKey key) throws Exception { - NodeList nodeList = document.getElementsByTagName("Signature"); + NodeList nodeList = document.getElementsByTagNameNS(XMLSignature.XMLNS, "Signature"); if (nodeList.getLength() == 1) { Node signatureNode = nodeList.item(0); if (signatureNode != null) { diff --git a/test/lib/jdk/test/lib/security/timestamp/DefaultRespInterceptor.java b/test/lib/jdk/test/lib/security/timestamp/DefaultRespInterceptor.java index 8ec9d6fc380fe29859b944a3a9e01bd52db1c9ee..49f93824f85c9e68d54d92553e4c60a5c3ea4fe6 100644 --- a/test/lib/jdk/test/lib/security/timestamp/DefaultRespInterceptor.java +++ b/test/lib/jdk/test/lib/security/timestamp/DefaultRespInterceptor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -23,10 +23,7 @@ package jdk.test.lib.security.timestamp; -import java.math.BigInteger; import java.security.cert.X509Certificate; -import java.time.Instant; -import java.util.Date; import java.util.Objects; /** diff --git a/test/lib/jdk/test/lib/security/timestamp/TsaHandler.java b/test/lib/jdk/test/lib/security/timestamp/TsaHandler.java index b8ec2f2ab9d761d7ac46f91b72b3bd46c3bcbde8..d42d9f031d47e842575d594b7a3f40ddb1139694 100644 --- a/test/lib/jdk/test/lib/security/timestamp/TsaHandler.java +++ b/test/lib/jdk/test/lib/security/timestamp/TsaHandler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -39,8 +39,6 @@ import com.sun.net.httpserver.HttpExchange; import com.sun.net.httpserver.HttpHandler; import sun.security.util.KnownOIDs; -import sun.security.util.SignatureUtil; -import sun.security.x509.AlgorithmId; /** * A {@link HttpHandler} receiving time-stamping request and returning response. diff --git a/test/lib/jdk/test/lib/security/timestamp/TsaServer.java b/test/lib/jdk/test/lib/security/timestamp/TsaServer.java index a4f739d60ae20ca80d4cdab515a4c6355b06ae4d..9bffa1a240ff87be45a056370c4630bdfd8bc414 100644 --- a/test/lib/jdk/test/lib/security/timestamp/TsaServer.java +++ b/test/lib/jdk/test/lib/security/timestamp/TsaServer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -26,7 +26,6 @@ package jdk.test.lib.security.timestamp; import java.io.IOException; import java.net.InetSocketAddress; import java.security.KeyStore; -import java.util.Objects; import com.sun.net.httpserver.HttpServer; diff --git a/test/lib/jdk/test/lib/util/ClassTransformer.java b/test/lib/jdk/test/lib/util/ClassTransformer.java new file mode 100644 index 0000000000000000000000000000000000000000..7ace81df87b6ff7627b4b7108c57a4ee4e292117 --- /dev/null +++ b/test/lib/jdk/test/lib/util/ClassTransformer.java @@ -0,0 +1,163 @@ +/* + * 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 jdk.test.lib.util; + +import jdk.test.lib.compiler.CompilerUtils; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.text.MessageFormat; +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +// ClassTransformer provides functionality to transform java source and compile it. +// We cannot use InMemoryJavaCompiler as test files usually contain 2 classes (the test itself and debuggee) +// and InMemoryJavaCompiler cannot compile them. +public class ClassTransformer { + + private final List lines; + private String fileName; + private String workDir = "ver{0}"; + private static final String LINE_SEPARATOR = System.getProperty("line.separator"); + + private ClassTransformer(List lines) { + this.lines = lines; + } + + public ClassTransformer setFileName(String fileName) { + this.fileName = fileName; + return this; + } + + // workDir is a MessageFormat pattern, id (int) is an {0} arg of the pattern. + // can be relative (relatively "scratch" dir) or absolute. + public ClassTransformer setWorkDir(String dir) { + workDir = dir; + return this; + } + + public static ClassTransformer fromString(String content) { + return new ClassTransformer(Arrays.asList(content.split("\\R"))); + } + + public static ClassTransformer fromFile(Path filePath) { + try { + return new ClassTransformer(Files.readAllLines(filePath)) + .setFileName(filePath.getFileName().toString()); + } catch (IOException e) { + throw new RuntimeException("failed to read " + filePath, e); + } + } + public static ClassTransformer fromFile(String filePath) { + return fromFile(Paths.get(filePath)); + } + + public static ClassTransformer fromTestSource(String fileName) { + return fromFile(Paths.get(System.getProperty("test.src")).resolve(fileName)); + } + + // returns path to the .class file of the transformed class + public String transform(int id, String className, String... compilerOptions) { + Path subdir = Paths.get(".").resolve(MessageFormat.format(workDir, id)); + Path transformedSrc = subdir.resolve(fileName); + try { + Files.createDirectories(subdir); + Files.write(transformedSrc, transform(id).getBytes()); + } catch (IOException e) { + throw new RuntimeException("failed to write transformed " + transformedSrc, e); + } + try { + // need to add extra classpath args + List args = new LinkedList<>(Arrays.asList(compilerOptions)); + args.add("-cp"); + args.add(System.getProperty("java.class.path")); + CompilerUtils.compile(subdir, subdir, false, args.toArray(new String[args.size()])); + } catch (IOException e) { + throw new RuntimeException("failed to compile " + transformedSrc, e); + } + return subdir.resolve(className + ".class").toString(); + } + + /* + * To do RedefineClasses operations, embed @1 tags in the .java + * file to tell this script how to modify it to produce the 2nd + * version of the .class file to be used in the redefine operation. + * Here are examples of each editing tag and what change + * it causes in the new file. Note that blanks are not preserved + * in these editing operations. + * + * @1 uncomment + * orig: // @1 uncomment gus = 89; + * new: gus = 89; + * + * @1 commentout + * orig: gus = 89 // @1 commentout + * new: // gus = 89 // @1 commentout + * + * @1 delete + * orig: gus = 89 // @1 delete + * new: entire line deleted + * + * @1 newline + * orig: gus = 89; // @1 newline gus++; + * new: gus = 89; // + * gus++; + * + * @1 replace + * orig: gus = 89; // @1 replace gus = 90; + * new: gus = 90; + */ + public String transform(int id) { + Pattern delete = Pattern.compile("@" + id + " *delete"); + Pattern uncomment = Pattern.compile("// *@" + id + " *uncomment (.*)"); + Pattern commentout = Pattern.compile(".* @" + id + " *commentout"); + Pattern newline = Pattern.compile("(.*) @" + id + " *newline (.*)"); + Pattern replace = Pattern.compile("@" + id + " *replace (.*)"); + return lines.stream() + .filter(s -> !delete.matcher(s).find()) // @1 delete + .map(s -> { + Matcher m = uncomment.matcher(s); // @1 uncomment + return m.find() ? m.group(1) : s; + }) + .map(s-> { + Matcher m = commentout.matcher(s); // @1 commentout + return m.find() ? "//" + s : s; + }) + .map(s -> { + Matcher m = newline.matcher(s); // @1 newline + return m.find() ? m.group(1) + LINE_SEPARATOR + m.group(2) : s; + }) + .map(s -> { + Matcher m = replace.matcher(s); // @1 replace + return m.find() ? m.group(1) : s; + }) + .collect(Collectors.joining(LINE_SEPARATOR)); + } + +} diff --git a/test/lib/jdk/test/lib/util/CoreUtils.java b/test/lib/jdk/test/lib/util/CoreUtils.java index d7e68e82f427e4819596fbe2d5f2ed2fd01a4e1d..c93357925934cb4dc6475221fac0976441aaeb71 100644 --- a/test/lib/jdk/test/lib/util/CoreUtils.java +++ b/test/lib/jdk/test/lib/util/CoreUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -107,8 +107,10 @@ public class CoreUtils { // Find the core file String coreFileLocation = parseCoreFileLocationFromOutput(crashOutputString); if (coreFileLocation != null) { - System.out.println("Found core file: " + coreFileLocation); - Asserts.assertGT(new File(coreFileLocation).length(), 0L, "Unexpected core size"); + long coreFileSize = new File(coreFileLocation).length(); + System.out.println("Found core file " + coreFileLocation + + ", size = " + coreFileSize / 1024 / 1024 + "mb"); + Asserts.assertGT(coreFileSize, 0L, "Unexpected core size"); // Make sure the core file is moved into the cwd if not already there. Path corePath = Paths.get(coreFileLocation); @@ -136,12 +138,12 @@ public class CoreUtils { if (!coresDir.canWrite()) { throw new SkippedException("Directory \"" + coresDir + "\" is not writable"); } - if (Platform.isSignedOSX()) { + if (Platform.isHardenedOSX()) { if (Platform.getOsVersionMajor() > 10 || (Platform.getOsVersionMajor() == 10 && Platform.getOsVersionMinor() >= 15)) { - // We can't generate cores files with signed binaries on OSX 10.15 and later. - throw new SkippedException("Cannot produce core file with signed binary on OSX 10.15 and later"); + // We can't generate cores files with hardened binaries on OSX 10.15 and later. + throw new SkippedException("Cannot produce core file with hardened binary on OSX 10.15 and later"); } } } else if (Platform.isLinux()) { diff --git a/test/lib/jdk/test/lib/util/JavaAgentBuilder.java b/test/lib/jdk/test/lib/util/JavaAgentBuilder.java index e5fe0cb9bbbabd54307670bc80be6c53ac71929f..d33aa301ca54fd0a2eb4059a5683595d2f835da2 100644 --- a/test/lib/jdk/test/lib/util/JavaAgentBuilder.java +++ b/test/lib/jdk/test/lib/util/JavaAgentBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -27,14 +27,12 @@ import java.io.File; import java.io.IOException; import java.nio.file.Path; import java.nio.file.Paths; -import java.util.Arrays; import java.util.Map; import java.util.HashMap; import java.util.jar.Attributes; import java.util.jar.Manifest; import jdk.test.lib.Utils; -import jdk.test.lib.util.JarUtils; /** * A builder for a common Java agent. diff --git a/test/lib/jdk/test/whitebox/WhiteBox.java b/test/lib/jdk/test/whitebox/WhiteBox.java index 4488559c4709701ecc4fbc9fdad0d8bcd35da4e9..cdd6f6890cb618d0e473b28f7d3799e9a2d5eb19 100644 --- a/test/lib/jdk/test/whitebox/WhiteBox.java +++ b/test/lib/jdk/test/whitebox/WhiteBox.java @@ -225,7 +225,6 @@ public class WhiteBox { public native void NMTReleaseMemory(long addr, long size); public native long NMTMallocWithPseudoStack(long size, int index); public native long NMTMallocWithPseudoStackAndType(long size, int index, int type); - public native boolean NMTChangeTrackingLevel(); public native int NMTGetHashSize(); public native long NMTNewArena(long initSize); public native void NMTFreeArena(long arena); @@ -317,6 +316,36 @@ public class WhiteBox { Objects.requireNonNull(method); return getMethodCompilationLevel0(method, isOsr); } + public int getMethodDecompileCount(Executable method) { + Objects.requireNonNull(method); + return getMethodDecompileCount0(method); + } + private native int getMethodDecompileCount0(Executable method); + // Get the total trap count of a method. If the trap count for a specific reason + // did overflow, this includes the overflow trap count of the method. + public int getMethodTrapCount(Executable method) { + Objects.requireNonNull(method); + return getMethodTrapCount0(method, null); + } + // Get the trap count of a method for a specific reason. If the trap count for + // that reason did overflow, this includes the overflow trap count of the method. + public int getMethodTrapCount(Executable method, String reason) { + Objects.requireNonNull(method); + return getMethodTrapCount0(method, reason); + } + private native int getMethodTrapCount0(Executable method, String reason); + // Get the total deopt count. + public int getDeoptCount() { + return getDeoptCount0(null, null); + } + // Get the deopt count for a specific reason and a specific action. If either + // one of 'reason' or 'action' is null, the method returns the sum of all + // deoptimizations with the specific 'action' or 'reason' respectively. + // If both arguments are null, the method returns the total deopt count. + public int getDeoptCount(String reason, String action) { + return getDeoptCount0(reason, action); + } + private native int getDeoptCount0(String reason, String action); private native boolean testSetDontInlineMethod0(Executable method, boolean value); public boolean testSetDontInlineMethod(Executable method, boolean value) { Objects.requireNonNull(method); @@ -594,6 +623,8 @@ public class WhiteBox { } // Sharing & archiving + public native int getCDSGenericHeaderMinVersion(); + public native int getCurrentCDSVersion(); public native String getDefaultArchivePath(); public native boolean cdsMemoryMappingFailed(); public native boolean isSharingEnabled(); @@ -603,6 +634,7 @@ public class WhiteBox { public native boolean isSharedInternedString(String s); public native boolean isCDSIncluded(); public native boolean isJFRIncluded(); + public native boolean isDTraceIncluded(); public native boolean canWriteJavaHeapArchive(); public native Object getResolvedReferences(Class c); public native void linkClass(Class c); diff --git a/test/lib/sun/hotspot/WhiteBox.java b/test/lib/sun/hotspot/WhiteBox.java index 8db7ec3baafc25825f8dacf9351be9b217f88112..7390cf19704f95961f6a787fc5c6ec5786b8e688 100644 --- a/test/lib/sun/hotspot/WhiteBox.java +++ b/test/lib/sun/hotspot/WhiteBox.java @@ -226,7 +226,6 @@ public class WhiteBox { public native void NMTReleaseMemory(long addr, long size); public native long NMTMallocWithPseudoStack(long size, int index); public native long NMTMallocWithPseudoStackAndType(long size, int index, int type); - public native boolean NMTChangeTrackingLevel(); public native int NMTGetHashSize(); public native long NMTNewArena(long initSize); public native void NMTFreeArena(long arena); @@ -318,6 +317,36 @@ public class WhiteBox { Objects.requireNonNull(method); return getMethodCompilationLevel0(method, isOsr); } + public int getMethodDecompileCount(Executable method) { + Objects.requireNonNull(method); + return getMethodDecompileCount0(method); + } + private native int getMethodDecompileCount0(Executable method); + // Get the total trap count of a method. If the trap count for a specific reason + // did overflow, this includes the overflow trap count of the method. + public int getMethodTrapCount(Executable method) { + Objects.requireNonNull(method); + return getMethodTrapCount0(method, null); + } + // Get the trap count of a method for a specific reason. If the trap count for + // that reason did overflow, this includes the overflow trap count of the method. + public int getMethodTrapCount(Executable method, String reason) { + Objects.requireNonNull(method); + return getMethodTrapCount0(method, reason); + } + private native int getMethodTrapCount0(Executable method, String reason); + // Get the total deopt count. + public int getDeoptCount() { + return getDeoptCount0(null, null); + } + // Get the deopt count for a specific reason and a specific action. If either + // one of 'reason' or 'action' is null, the method returns the sum of all + // deoptimizations with the specific 'action' or 'reason' respectively. + // If both arguments are null, the method returns the total deopt count. + public int getDeoptCount(String reason, String action) { + return getDeoptCount0(reason, action); + } + private native int getDeoptCount0(String reason, String action); private native boolean testSetDontInlineMethod0(Executable method, boolean value); public boolean testSetDontInlineMethod(Executable method, boolean value) { Objects.requireNonNull(method); @@ -595,6 +624,8 @@ public class WhiteBox { } // Sharing & archiving + public native int getCDSGenericHeaderMinVersion(); + public native int getCurrentCDSVersion(); public native String getDefaultArchivePath(); public native boolean cdsMemoryMappingFailed(); public native boolean isSharingEnabled(); @@ -604,6 +635,7 @@ public class WhiteBox { public native boolean isSharedInternedString(String s); public native boolean isCDSIncluded(); public native boolean isJFRIncluded(); + public native boolean isDTraceIncluded(); public native boolean canWriteJavaHeapArchive(); public native Object getResolvedReferences(Class c); public native void linkClass(Class c); diff --git a/test/micro/org/openjdk/bench/java/lang/Integers.java b/test/micro/org/openjdk/bench/java/lang/Integers.java index c238ae5d735a96464303af2bc74c40bd5b01eec8..221dc79ee4c50ba7fde8a8c4e209bb0477c82e9b 100644 --- a/test/micro/org/openjdk/bench/java/lang/Integers.java +++ b/test/micro/org/openjdk/bench/java/lang/Integers.java @@ -53,17 +53,20 @@ public class Integers { private int size; private String[] strings; + private int[] intsTiny; private int[] intsSmall; private int[] intsBig; @Setup public void setup() { - Random r = new Random(0); - strings = new String[size]; + Random r = new Random(0); + strings = new String[size]; + intsTiny = new int[size]; intsSmall = new int[size]; - intsBig = new int[size]; + intsBig = new int[size]; for (int i = 0; i < size; i++) { strings[i] = "" + (r.nextInt(10000) - (5000)); + intsTiny[i] = r.nextInt(99); intsSmall[i] = 100 * i + i + 103; intsBig[i] = ((100 * i + i) << 24) + 4543 + i * 4; } @@ -91,6 +94,14 @@ public class Integers { } } + /** Performs toString on very small values, just one or two digits. */ + @Benchmark + public void toStringTiny(Blackhole bh) { + for (int i : intsTiny) { + bh.consume(Integer.toString(i)); + } + } + /** Performs toString on large values, roughly 10 digits. */ @Benchmark public void toStringBig(Blackhole bh) { diff --git a/test/micro/org/openjdk/bench/java/lang/StringDecode.java b/test/micro/org/openjdk/bench/java/lang/StringDecode.java index ace4252c7a3a310febae96f697c34994be280ef7..ee4f8df7c734f21eb235f1c380843c66ae5dde42 100644 --- a/test/micro/org/openjdk/bench/java/lang/StringDecode.java +++ b/test/micro/org/openjdk/bench/java/lang/StringDecode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -22,17 +22,7 @@ */ package org.openjdk.bench.java.lang; -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.Param; -import org.openjdk.jmh.annotations.Scope; -import org.openjdk.jmh.annotations.Setup; -import org.openjdk.jmh.annotations.State; -import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.annotations.*; import org.openjdk.jmh.infra.Blackhole; import java.nio.charset.Charset; @@ -40,59 +30,177 @@ import java.util.concurrent.TimeUnit; @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.NANOSECONDS) -@Fork(value = 3, jvmArgs = "-Xmx1g") -@Warmup(iterations = 5, time = 2) +@Fork(value = 2) +@Warmup(iterations = 5, time = 3) @Measurement(iterations = 5, time = 3) @State(Scope.Thread) public class StringDecode { - @BenchmarkMode(Mode.AverageTime) - @OutputTimeUnit(TimeUnit.NANOSECONDS) - @Fork(value = 3, jvmArgs = "-Xmx1g") - @Warmup(iterations = 5, time = 2) - @Measurement(iterations = 5, time = 2) - @State(Scope.Thread) - public static class WithCharset { - - @Param({"US-ASCII", "ISO-8859-1", "UTF-8", "MS932", "ISO-8859-6", "ISO-2022-KR"}) - private String charsetName; - - private Charset charset; - private byte[] asciiString; - private byte[] utf16String; - - @Setup - public void setup() { - charset = Charset.forName(charsetName); - asciiString = "ascii string".getBytes(charset); - utf16String = "UTF-\uFF11\uFF16 string".getBytes(charset); - } - - @Benchmark - public void decodeCharsetName(Blackhole bh) throws Exception { - bh.consume(new String(asciiString, charsetName)); - bh.consume(new String(utf16String, charsetName)); - } - - @Benchmark - public void decodeCharset(Blackhole bh) throws Exception { - bh.consume(new String(asciiString, charset)); - bh.consume(new String(utf16String, charset)); - } - } + // Reduced by default to only UTF-8, previous coverage: + // @Param({"US-ASCII", "ISO-8859-1", "UTF-8", "MS932", "ISO-8859-6", "ISO-2022-KR"}) + @Param({"UTF-8"}) + private String charsetName; + + private Charset charset; + private byte[] asciiString; + private byte[] longAsciiString; + private byte[] utf16String; + private byte[] longUtf16EndString; + private byte[] longUtf16StartString; + private byte[] longUtf16OnlyString; + private byte[] latin1String; + private byte[] longLatin1EndString; + private byte[] longLatin1StartString; + private byte[] longLatin1OnlyString; - private byte[] asciiDefaultString; - private byte[] utf16DefaultString; + private static final String LOREM = """ + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam ac sem eu + urna egestas placerat. Etiam finibus ipsum nulla, non mattis dolor cursus a. + Nulla nec nisl consectetur, lacinia neque id, accumsan ante. Curabitur et + sapien in magna porta ultricies. Sed vel pellentesque nibh. Pellentesque dictum + dignissim diam eu ultricies. Class aptent taciti sociosqu ad litora torquent + per conubia nostra, per inceptos himenaeos. Suspendisse erat diam, fringilla + sed massa sed, posuere viverra orci. Suspendisse tempor libero non gravida + efficitur. Vivamus lacinia risus non orci viverra, at consectetur odio laoreet. + Suspendisse potenti."""; + private static final String UTF16_STRING = "\uFF11".repeat(31); + private static final String LATIN1_STRING = "\u00B6".repeat(31); @Setup public void setup() { - asciiDefaultString = "ascii string".getBytes(); - utf16DefaultString = "UTF-\uFF11\uFF16 string".getBytes(); + charset = Charset.forName(charsetName); + asciiString = LOREM.substring(0, 32).getBytes(charset); + longAsciiString = LOREM.repeat(200).getBytes(charset); + utf16String = "UTF-\uFF11\uFF16 string".getBytes(charset); + longUtf16EndString = LOREM.repeat(4).concat(UTF16_STRING).getBytes(charset); + longUtf16StartString = UTF16_STRING.concat(LOREM.repeat(4)).getBytes(charset); + longUtf16OnlyString = UTF16_STRING.repeat(10).getBytes(charset); + latin1String = LATIN1_STRING.getBytes(charset); + longLatin1EndString = LOREM.repeat(4).concat(LATIN1_STRING).getBytes(charset); + longLatin1StartString = LATIN1_STRING.concat(LOREM.repeat(4)).getBytes(charset); + longLatin1OnlyString = LATIN1_STRING.repeat(10).getBytes(charset); + } + + @Benchmark + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + public void decodeAsciiShort(Blackhole bh) throws Exception { + bh.consume(new String(asciiString, charset)); + bh.consume(new String(longAsciiString, 0, 15, charset)); + bh.consume(new String(asciiString, 0, 3, charset)); + bh.consume(new String(longAsciiString, 512, 7, charset)); + } + + @Benchmark + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + public void decodeAsciiLong(Blackhole bh) throws Exception { + bh.consume(new String(longAsciiString, charset)); + bh.consume(new String(longAsciiString, 0, 1024 + 31, charset)); + } + + @Benchmark + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + public void decodeLatin1Short(Blackhole bh) throws Exception { + bh.consume(new String(latin1String, charset)); + bh.consume(new String(latin1String, 0, 15, charset)); + bh.consume(new String(latin1String, 0, 3, charset)); + bh.consume(new String(longLatin1OnlyString, 512, 7, charset)); + } + + @Benchmark + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + public String decodeLatin1LongStart() throws Exception { + return new String(longLatin1StartString, charset); + } + + @Benchmark + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + public String decodeLatin1LongEnd() throws Exception { + return new String(longLatin1EndString, charset); + } + + @Benchmark + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + public String decodeLatin1LongOnly() throws Exception { + return new String(longLatin1OnlyString, charset); + } + + @Benchmark + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + public void decodeLatin1Mixed(Blackhole bh) throws Exception { + bh.consume(new String(longLatin1EndString, charset)); + bh.consume(new String(longLatin1StartString, charset)); + bh.consume(new String(latin1String, charset)); + bh.consume(new String(longLatin1OnlyString, charset)); + } + + @Benchmark + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + public void decodeUTF16Short(Blackhole bh) throws Exception { + bh.consume(new String(utf16String, charset)); + bh.consume(new String(utf16String, 0, 15, charset)); + bh.consume(new String(utf16String, 0, 3, charset)); + bh.consume(new String(utf16String, 0, 7, charset)); + } + + @Benchmark + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + public String decodeUTF16LongEnd() throws Exception { + return new String(longUtf16EndString, charset); + } + + @Benchmark + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + public String decodeUTF16LongStart() throws Exception { + return new String(longUtf16StartString, charset); + } + + @Benchmark + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + public String decodeUTF16LongOnly() throws Exception { + return new String(longUtf16OnlyString, charset); + } + + @Benchmark + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + public void decodeUTF16Mixed(Blackhole bh) throws Exception { + bh.consume(new String(longUtf16StartString, charset)); + bh.consume(new String(longUtf16EndString, charset)); + bh.consume(new String(utf16String, charset)); + bh.consume(new String(longUtf16OnlyString, charset)); + } + + @Benchmark + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + public void decodeAllMixed(Blackhole bh) throws Exception { + bh.consume(new String(utf16String, charset)); + bh.consume(new String(longUtf16EndString, charset)); + bh.consume(new String(utf16String, 0, 15, charset)); + bh.consume(new String(longUtf16StartString, charset)); + bh.consume(new String(asciiString, 0, 3, charset)); + bh.consume(new String(longUtf16OnlyString, charset)); + bh.consume(new String(latin1String, charset)); + bh.consume(new String(longLatin1EndString, charset)); + bh.consume(new String(longLatin1StartString, charset)); + bh.consume(new String(latin1String, 0, 7, charset)); + bh.consume(new String(longLatin1OnlyString, charset)); + bh.consume(new String(asciiString, charset)); + bh.consume(new String(longAsciiString, charset)); } @Benchmark - public void decodeDefault(Blackhole bh) throws Exception { - bh.consume(new String(asciiDefaultString)); - bh.consume(new String(utf16DefaultString)); + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + public void decodeShortMixed(Blackhole bh) throws Exception { + bh.consume(new String(utf16String, 0, 15, charset)); + bh.consume(new String(latin1String, 0, 15, charset)); + bh.consume(new String(asciiString, charset)); + bh.consume(new String(utf16String, charset)); + bh.consume(new String(latin1String, 0, 3, charset)); + bh.consume(new String(asciiString, 0, 3, charset)); + bh.consume(new String(utf16String, 0, 7, charset)); + bh.consume(new String(latin1String, charset)); + bh.consume(new String(asciiString, 0, 7, charset)); + bh.consume(new String(utf16String, 0, 3, charset)); + bh.consume(new String(latin1String, 0, 7, charset)); + bh.consume(new String(asciiString, 0, 15, charset)); } } diff --git a/test/micro/org/openjdk/bench/java/lang/StringEncode.java b/test/micro/org/openjdk/bench/java/lang/StringEncode.java index 4cf5032a0dad39bec490e1db562e0a28a9e55c9d..30f5a18450ee7e89c8dfafbfb333649a326d0df3 100644 --- a/test/micro/org/openjdk/bench/java/lang/StringEncode.java +++ b/test/micro/org/openjdk/bench/java/lang/StringEncode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -30,59 +30,197 @@ import java.util.concurrent.TimeUnit; @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.NANOSECONDS) -@Fork(value = 3, jvmArgs = "-Xmx1g") -@Warmup(iterations = 5, time = 2) +@Fork(value = 2) +@Warmup(iterations = 5, time = 3) @Measurement(iterations = 5, time = 3) @State(Scope.Thread) public class StringEncode { - @BenchmarkMode(Mode.AverageTime) - @OutputTimeUnit(TimeUnit.NANOSECONDS) - @Fork(value = 3, jvmArgs = "-Xmx1g") - @Warmup(iterations = 5, time = 2) - @Measurement(iterations = 5, time = 2) - @State(Scope.Thread) - public static class WithCharset { - - @Param({"US-ASCII", "ISO-8859-1", "UTF-8", "MS932", "ISO-8859-6"}) - private String charsetName; - - private Charset charset; - private String asciiString; - private String utf16String; - - @Setup - public void setup() { - charset = Charset.forName(charsetName); - asciiString = "ascii string"; - utf16String = "UTF-\uFF11\uFF16 string"; - } - - @Benchmark - public void encodeCharsetName(Blackhole bh) throws Exception { - bh.consume(asciiString.getBytes(charsetName)); - bh.consume(utf16String.getBytes(charsetName)); - } - - @Benchmark - public void encodeCharset(Blackhole bh) throws Exception { - bh.consume(asciiString.getBytes(charset)); - bh.consume(utf16String.getBytes(charset)); - } - } + // Reduced by default to only UTF-8, previous coverage: + // @Param({"US-ASCII", "ISO-8859-1", "UTF-8", "MS932", "ISO-8859-6", "ISO-2022-KR"}) + @Param({"UTF-8"}) + private String charsetName; + + private Charset charset; + private String asciiString; + private String asciiString3; + private String asciiString7; + private String asciiString15; + private String longAsciiString; + private String longAsciiString1055; + private String utf16String; + private String utf16String3; + private String utf16String7; + private String utf16String15; + private String longUtf16EndString; + private String longUtf16StartString; + private String longUtf16OnlyString; + private String latin1String; + private String latin1String3; + private String latin1String7; + private String latin1String15; + private String longLatin1EndString; + private String longLatin1StartString; + private String longLatin1OnlyString; - private String asciiDefaultString; - private String utf16DefaultString; + private static final String LOREM = """ + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam ac sem eu + urna egestas placerat. Etiam finibus ipsum nulla, non mattis dolor cursus a. + Nulla nec nisl consectetur, lacinia neque id, accumsan ante. Curabitur et + sapien in magna porta ultricies. Sed vel pellentesque nibh. Pellentesque dictum + dignissim diam eu ultricies. Class aptent taciti sociosqu ad litora torquent + per conubia nostra, per inceptos himenaeos. Suspendisse erat diam, fringilla + sed massa sed, posuere viverra orci. Suspendisse tempor libero non gravida + efficitur. Vivamus lacinia risus non orci viverra, at consectetur odio laoreet. + Suspendisse potenti."""; + private static final String UTF16_STRING = "\uFF11".repeat(31); + private static final String LATIN1_STRING = "\u00B6".repeat(31); @Setup public void setup() { - asciiDefaultString = "ascii string"; - utf16DefaultString = "UTF-\uFF11\uFF16 string"; + charset = Charset.forName(charsetName); + asciiString = LOREM.substring(0, 32); + asciiString3 = LOREM.substring(0, 3); + asciiString7 = LOREM.substring(0, 7); + asciiString15 = LOREM.substring(0, 15); + longAsciiString = LOREM.repeat(200); + longAsciiString1055 = longAsciiString.substring(0, 1055); + utf16String = UTF16_STRING; + utf16String3 = UTF16_STRING.substring(0, 3); + utf16String7 = UTF16_STRING.substring(0, 7); + utf16String15 = UTF16_STRING.substring(0, 15); + longUtf16EndString = LOREM.repeat(4).concat(UTF16_STRING); + longUtf16StartString = UTF16_STRING.concat(LOREM.repeat(4)); + longUtf16OnlyString = UTF16_STRING.repeat(10); + latin1String = LATIN1_STRING; + latin1String3 = LATIN1_STRING.substring(0, 3); + latin1String7 = LATIN1_STRING.substring(0, 7); + latin1String15 = LATIN1_STRING.substring(0, 15); + longLatin1EndString = LOREM.repeat(4).concat(LATIN1_STRING); + longLatin1StartString = LATIN1_STRING.concat(LOREM.repeat(4)); + longLatin1OnlyString = LATIN1_STRING.repeat(10); + } + + @Benchmark + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + public void encodeAsciiShort(Blackhole bh) throws Exception { + bh.consume(asciiString.getBytes(charset)); + bh.consume(asciiString3.getBytes(charset)); + bh.consume(asciiString15.getBytes(charset)); + bh.consume(asciiString7.getBytes(charset)); + } + + @Benchmark + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + public void encodeAsciiLong(Blackhole bh) throws Exception { + bh.consume(longAsciiString.getBytes(charset)); + bh.consume(longAsciiString1055.getBytes(charset)); + } + + @Benchmark + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + public void encodeUTF16Short(Blackhole bh) throws Exception { + bh.consume(utf16String.getBytes(charset)); + bh.consume(utf16String3.getBytes(charset)); + bh.consume(utf16String15.getBytes(charset)); + bh.consume(utf16String7.getBytes(charset)); + } + + @Benchmark + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + public byte[] encodeUTF16LongEnd() throws Exception { + return longUtf16EndString.getBytes(charset); + } + + @Benchmark + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + public byte[] encodeUTF16LongStart() throws Exception { + return longUtf16StartString.getBytes(charset); + } + + @Benchmark + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + public byte[] encodeUTF16LongOnly() throws Exception { + return longUtf16OnlyString.getBytes(charset); + } + + @Benchmark + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + public void encodeUTF16Mixed(Blackhole bh) throws Exception { + bh.consume(utf16String.getBytes(charset)); + bh.consume(longUtf16StartString.getBytes(charset)); + bh.consume(longUtf16EndString.getBytes(charset)); + bh.consume(longUtf16OnlyString.getBytes(charset)); + } + + @Benchmark + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + public void encodeLatin1Short(Blackhole bh) throws Exception { + bh.consume(latin1String.getBytes(charset)); + bh.consume(latin1String3.getBytes(charset)); + bh.consume(latin1String15.getBytes(charset)); + bh.consume(latin1String7.getBytes(charset)); + } + + @Benchmark + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + public byte[] encodeLatin1LongOnly() throws Exception { + return longLatin1OnlyString.getBytes(charset); + } + + @Benchmark + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + public byte[] encodeLatin1LongStart() throws Exception { + return longLatin1StartString.getBytes(charset); + } + + @Benchmark + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + public byte[] encodeLatin1LongEnd() throws Exception { + return longLatin1EndString.getBytes(charset); + } + + @Benchmark + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + public void encodeLatin1Mixed(Blackhole bh) throws Exception { + bh.consume(longLatin1EndString.getBytes(charset)); + bh.consume(longLatin1StartString.getBytes(charset)); + bh.consume(longLatin1OnlyString.getBytes(charset)); + bh.consume(latin1String.getBytes(charset)); + } + + @Benchmark + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + public void encodeAllMixed(Blackhole bh) throws Exception { + bh.consume(utf16String.getBytes(charset)); + bh.consume(longUtf16StartString.getBytes(charset)); + bh.consume(asciiString7.getBytes(charset)); + bh.consume(longUtf16EndString.getBytes(charset)); + bh.consume(latin1String3.getBytes(charset)); + bh.consume(longUtf16OnlyString.getBytes(charset)); + bh.consume(longLatin1EndString.getBytes(charset)); + bh.consume(longLatin1StartString.getBytes(charset)); + bh.consume(utf16String15.getBytes(charset)); + bh.consume(longLatin1OnlyString.getBytes(charset)); + bh.consume(latin1String.getBytes(charset)); + bh.consume(asciiString.getBytes(charset)); + bh.consume(longAsciiString.getBytes(charset)); } @Benchmark - public void encodeDefault(Blackhole bh) throws Exception { - bh.consume(asciiDefaultString.getBytes()); - bh.consume(utf16DefaultString.getBytes()); + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + public void encodeShortMixed(Blackhole bh) throws Exception { + bh.consume(utf16String3.getBytes(charset)); + bh.consume(latin1String7.getBytes(charset)); + bh.consume(asciiString15.getBytes(charset)); + bh.consume(utf16String.getBytes(charset)); + bh.consume(latin1String3.getBytes(charset)); + bh.consume(asciiString7.getBytes(charset)); + bh.consume(utf16String15.getBytes(charset)); + bh.consume(latin1String.getBytes(charset)); + bh.consume(asciiString3.getBytes(charset)); + bh.consume(utf16String7.getBytes(charset)); + bh.consume(latin1String15.getBytes(charset)); + bh.consume(asciiString.getBytes(charset)); } } diff --git a/test/micro/org/openjdk/bench/java/lang/ThreadOnSpinWait.java b/test/micro/org/openjdk/bench/java/lang/ThreadOnSpinWait.java index 72efedb59010614963ffb33e00ec8d945e9379dd..146d34bbd87dd77889077fedde1f0b69fd3f2954 100644 --- a/test/micro/org/openjdk/bench/java/lang/ThreadOnSpinWait.java +++ b/test/micro/org/openjdk/bench/java/lang/ThreadOnSpinWait.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Amazon.com Inc. 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 diff --git a/test/micro/org/openjdk/bench/java/lang/ThreadOnSpinWaitProducerConsumer.java b/test/micro/org/openjdk/bench/java/lang/ThreadOnSpinWaitProducerConsumer.java index e111b77ab5171fc95f5afafcdc563b84fb99c49d..c8662e2984db4369219a8b86fa6adc3e139f2cc0 100644 --- a/test/micro/org/openjdk/bench/java/lang/ThreadOnSpinWaitProducerConsumer.java +++ b/test/micro/org/openjdk/bench/java/lang/ThreadOnSpinWaitProducerConsumer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Amazon.com Inc. 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 @@ -193,6 +193,7 @@ public class ThreadOnSpinWaitProducerConsumer { } } threadConsumer.interrupt(); + threadConsumer.join(); if (producedDataCount != maxNum) { throw new RuntimeException("Produced: " + producedDataCount + ". Expected: " + maxNum); diff --git a/test/micro/org/openjdk/bench/java/lang/runtime/ObjectMethods.java b/test/micro/org/openjdk/bench/java/lang/runtime/ObjectMethods.java new file mode 100644 index 0000000000000000000000000000000000000000..c491141e268382fbe9a98d7b0cb1f047fae6a53a --- /dev/null +++ b/test/micro/org/openjdk/bench/java/lang/runtime/ObjectMethods.java @@ -0,0 +1,158 @@ +/* + * 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. + */ +package org.openjdk.bench.java.lang.runtime; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +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 java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.util.concurrent.TimeUnit; + +/** + * Benchmark assesses Record.toString which is implemented by ObjectMethods::makeToString + */ +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@State(Scope.Thread) +public class ObjectMethods { + record R0() {} + record R1(int i) {} + record R10(int i1,int i2,int i3,int i4,int i5,int i6,int i7,int i8,int i9,int i10) {} + record R100(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,int i55,int i56,int i57,int i58,int i59,int i60, + int i61,int i62,int i63,int i64,int i65,int i66,int i67,int i68,int i69,int i70, + int i71,int i72,int i73,int i74,int i75,int i76,int i77,int i78,int i79,int i80, + int i81,int i82,int i83,int i84,int i85,int i86,int i87,int i88,int i89,int i90, + int i91,int i92,int i93,int i94,int i95,int i96,int i97,int i98,int i99,int i100) {} + record R254(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,int i55,int i56,int i57,int i58,int i59,int i60, + int i61,int i62,int i63,int i64,int i65,int i66,int i67,int i68,int i69,int i70, + int i71,int i72,int i73,int i74,int i75,int i76,int i77,int i78,int i79,int i80, + int i81,int i82,int i83,int i84,int i85,int i86,int i87,int i88,int i89,int i90, + int i91,int i92,int i93,int i94,int i95,int i96,int i97,int i98,int i99,int i100, + int i101,int i102,int i103,int i104,int i105,int i106,int i107,int i108,int i109,int i110, + int i111,int i112,int i113,int i114,int i115,int i116,int i117,int i118,int i119,int i120, + int i121,int i122,int i123,int i124,int i125,int i126,int i127,int i128,int i129,int i130, + int i131,int i132,int i133,int i134,int i135,int i136,int i137,int i138,int i139,int i140, + int i141,int i142,int i143,int i144,int i145,int i146,int i147,int i148,int i149,int i150, + int i151,int i152,int i153,int i154,int i155,int i156,int i157,int i158,int i159,int i160, + int i161,int i162,int i163,int i164,int i165,int i166,int i167,int i168,int i169,int i170, + int i171,int i172,int i173,int i174,int i175,int i176,int i177,int i178,int i179,int i180, + int i181,int i182,int i183,int i184,int i185,int i186,int i187,int i188,int i189,int i190, + int i191,int i192,int i193,int i194,int i195,int i196,int i197,int i198,int i199, int i200, + int i201,int i202,int i203,int i204,int i205,int i206,int i207,int i208,int i209,int i210, + int i211,int i212,int i213,int i214,int i215,int i216,int i217,int i218,int i219,int i220, + int i221,int i222,int i223,int i224,int i225,int i226,int i227,int i228,int i229,int i230, + int i231,int i232,int i233,int i234,int i235,int i236,int i237,int i238,int i239,int i240, + int i241,int i242,int i243,int i244,int i245,int i246,int i247,int i248,int i249,int i250, + int i251,int i252,int i253,int i254) {} + + R0 r0; + R1 r1; + R10 r10; + R100 r100; + R254 r254; + + @Setup + public void prepare() { + r0 = new R0(); + r1 = new R1(1); + r10 = new R10(1,2,3,4,5,6,7,8,9,10); + r100 = new R100(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,55,56,57,58,59,60, + 61,62,63,64,65,66,67,68,69,70, + 71,72,73,74,75,76,77,78,79,80, + 81,82,83,84,85,86,87,88,89,90, + 91,92,93,94,95,96,97,98,99,100); + r254 = new R254(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,55,56,57,58,59,60, + 61,62,63,64,65,66,67,68,69,70, + 71,72,73,74,75,76,77,78,79,80, + 81,82,83,84,85,86,87,88,89,90, + 91,92,93,94,95,96,97,98,99,100, + 101,102,103,104,105,106,107,108,109,110, + 111,112,113,114,115,116,117,118,119,120, + 121,122,123,124,125,126,127,128,129,130, + 131,132,133,134,135,136,137,138,139,140, + 141,142,143,144,145,146,147,148,149,150, + 151,152,153,154,155,156,157,158,159,160, + 161,162,163,164,165,166,167,168,169,170, + 171,172,173,174,175,176,177,178,179,180, + 181,182,183,184,185,186,187,188,189,190, + 191,192,193,194,195,196,197,198,199, 200, + 201,202,203,204,205,206,207,208,209,210, + 211,212,213,214,215,216,217,218,219,220, + 221,222,223,224,225,226,227,228,229,230, + 231,232,233,234,235,236,237,238,239,240, + 241,242,243,244,245,246,247,248,249,250, + 251,252,253,254); + } + + @Benchmark + public String toString0() { + return r0.toString(); + } + + @Benchmark + public String toString1() { + return r1.toString(); + } + + @Benchmark + public String toString10() { + return r10.toString(); + } + + @Benchmark + public String toString100() { + return r100.toString(); + } + + @Benchmark + public String toString254() { + return r254.toString(); + } +} diff --git a/test/micro/org/openjdk/bench/java/math/BigIntegerMersennePrimeMultiply.java b/test/micro/org/openjdk/bench/java/math/BigIntegerMersennePrimeMultiply.java new file mode 100644 index 0000000000000000000000000000000000000000..7ac4cf54dc28e4622242bbb3204f517668dd35f4 --- /dev/null +++ b/test/micro/org/openjdk/bench/java/math/BigIntegerMersennePrimeMultiply.java @@ -0,0 +1,322 @@ +package org.openjdk.bench.java.math; + +import javax.management.MBeanServer; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; +import java.lang.management.ManagementFactory; +import java.lang.management.ThreadMXBean; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.math.BigInteger; +import java.util.Arrays; +import java.util.IdentityHashMap; +import java.util.List; +import java.util.Locale; +import java.util.LongSummaryStatistics; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.ForkJoinWorkerThread; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicLong; +import java.util.function.BinaryOperator; +import java.util.function.LongUnaryOperator; +import java.util.stream.Collectors; + +import static java.util.concurrent.ForkJoinPool.defaultForkJoinWorkerThreadFactory; + +/** + * Benchmark for checking performance difference between sequential and parallel + * multiply of very large Mersenne primes using BigInteger. We want to measure + * real time, user time, system time and the amount of memory allocated. To + * calculate this, we create our own thread factory for the common ForkJoinPool + * and then use that to measure user time, cpu time and bytes allocated. + *

          + * We use reflection to discover all methods that match "*ultiply", and use them + * to multiply two very large Mersenne primes together. + *

          + *

          Results on a 1-6-2 machine running Ubuntu linux

          + *

          + * Memory allocation increased from 83.9GB to 84GB, for both the sequential and + * parallel versions. This is an increase of just 0.1%. On this machine, the + * parallel version was 3.8x faster in latency (real time), but it used 2.7x + * more CPU resources. + *

          + * Testing multiplying Mersenne primes of 2^57885161-1 and 2^82589933-1 + *

          + *

          + * openjdk version "18-internal" 2022-03-15
          + * BigInteger.parallelMultiply()
          + * real  0m6.288s
          + * user  1m3.010s
          + * sys   0m0.027s
          + * mem   84.0GB
          + * BigInteger.multiply()
          + * real  0m23.682s
          + * user  0m23.530s
          + * sys   0m0.004s
          + * mem   84.0GB
          + *
          + * openjdk version "1.8.0_302"
          + * BigInteger.multiply()
          + * real  0m25.657s
          + * user  0m25.390s
          + * sys   0m0.001s
          + * mem   83.9GB
          + *
          + * openjdk version "9.0.7.1"
          + * BigInteger.multiply()
          + * real  0m24.907s
          + * user  0m24.700s
          + * sys   0m0.001s
          + * mem   83.9GB
          + *
          + * openjdk version "10.0.2" 2018-07-17
          + * BigInteger.multiply()
          + * real  0m24.632s
          + * user  0m24.380s
          + * sys   0m0.004s
          + * mem   83.9GB
          + *
          + * openjdk version "11.0.12" 2021-07-20 LTS
          + * BigInteger.multiply()
          + * real  0m22.114s
          + * user  0m21.930s
          + * sys   0m0.001s
          + * mem   83.9GB
          + *
          + * openjdk version "12.0.2" 2019-07-16
          + * BigInteger.multiply()
          + * real  0m23.015s
          + * user  0m22.830s
          + * sys   0m0.000s
          + * mem   83.9GB
          + *
          + * openjdk version "13.0.9" 2021-10-19
          + * BigInteger.multiply()
          + * real  0m23.548s
          + * user  0m23.350s
          + * sys   0m0.005s
          + * mem   83.9GB
          + *
          + * openjdk version "14.0.2" 2020-07-14
          + * BigInteger.multiply()
          + * real  0m22.918s
          + * user  0m22.530s
          + * sys   0m0.131s
          + * mem   83.9GB
          + *
          + * openjdk version "15.0.5" 2021-10-19
          + * BigInteger.multiply()
          + * real  0m22.038s
          + * user  0m21.750s
          + * sys   0m0.003s
          + * mem   83.9GB
          + *
          + * openjdk version "16.0.2" 2021-07-20
          + * BigInteger.multiply()
          + * real  0m23.049s
          + * user  0m22.760s
          + * sys   0m0.006s
          + * mem   83.9GB
          + *
          + * openjdk version "17" 2021-09-14
          + * BigInteger.multiply()
          + * real  0m22.580s
          + * user  0m22.310s
          + * sys   0m0.001s
          + * mem   83.9GB
          + *
          + * + * @author Heinz Kabutz, heinz@javaspecialists.eu + */ +public class BigIntegerMersennePrimeMultiply implements ForkJoinPool.ForkJoinWorkerThreadFactory { + // Large Mersenne prime discovered by Curtis Cooper in 2013 + private static final int EXPONENT_1 = 57885161; + private static final BigInteger MERSENNE_1 = + BigInteger.ONE.shiftLeft(EXPONENT_1).subtract(BigInteger.ONE); + // Largest Mersenne prime number discovered by Patrick Laroche in 2018 + private static final int EXPONENT_2 = 82589933; + private static final BigInteger MERSENNE_2 = + BigInteger.ONE.shiftLeft(EXPONENT_2).subtract(BigInteger.ONE); + private static boolean DEBUG = false; + + public static void main(String... args) { + System.setProperty("java.util.concurrent.ForkJoinPool.common.threadFactory", + BigIntegerMersennePrimeMultiply.class.getName()); + System.out.println("Testing multiplying Mersenne primes of " + + "2^" + EXPONENT_1 + "-1 and 2^" + EXPONENT_2 + "-1"); + addCounters(Thread.currentThread()); + System.out.println("Using the following multiply methods:"); + List methods = Arrays.stream(BigInteger.class.getMethods()) + .filter(method -> method.getName().endsWith("ultiply") && + method.getParameterCount() == 1 && + method.getParameterTypes()[0] == BigInteger.class) + .peek(method -> System.out.println(" " + method)) + .collect(Collectors.toList()); + + for (int i = 0; i < 3; i++) { + System.out.println(); + methods.forEach(BigIntegerMersennePrimeMultiply::test); + } + } + + private static void test(Method method) { + BinaryOperator multiplyOperator = (a, b) -> { + try { + return (BigInteger) method.invoke(a, b); + } catch (IllegalAccessException e) { + throw new AssertionError(e); + } catch (InvocationTargetException e) { + throw new AssertionError(e.getCause()); + } + }; + test(method.getName(), multiplyOperator); + } + + private static void test(String description, + BinaryOperator multiplyOperator) { + System.out.println("BigInteger." + description + "()"); + resetAllCounters(); + long elapsedTimeInNanos = System.nanoTime(); + try { + BigInteger result1 = multiplyOperator.apply(MERSENNE_1, MERSENNE_2); + BigInteger result2 = multiplyOperator.apply(MERSENNE_2, MERSENNE_1); + if (result1.bitLength() != 140475094) + throw new AssertionError("Expected bitLength: 140475094, " + + "but was " + result1.bitLength()); + if (result2.bitLength() != 140475094) + throw new AssertionError("Expected bitLength: 140475094, " + + "but was " + result1.bitLength()); + } finally { + elapsedTimeInNanos = System.nanoTime() - elapsedTimeInNanos; + } + + LongSummaryStatistics userTimeStatistics = getStatistics(userTime); + LongSummaryStatistics cpuTimeStatistics = getStatistics(cpuTime); + LongSummaryStatistics memoryAllocationStatistics = getStatistics(bytes); + System.out.println("real " + formatTime(elapsedTimeInNanos)); + System.out.println("user " + formatTime(userTimeStatistics.getSum())); + System.out.println("sys " + + formatTime(cpuTimeStatistics.getSum() - userTimeStatistics.getSum())); + System.out.println("mem " + formatMemory(memoryAllocationStatistics.getSum(), 1)); + } + + private static LongSummaryStatistics getStatistics(Map timeMap) { + return timeMap.entrySet() + .stream() + .peek(entry -> { + long timeInMs = (counterExtractorMap.get(timeMap) + .applyAsLong(entry.getKey().getId()) + - entry.getValue().get()); + entry.getValue().set(timeInMs); + }) + .peek(BigIntegerMersennePrimeMultiply::printTime) + .map(Map.Entry::getValue) + .mapToLong(AtomicLong::get) + .summaryStatistics(); + } + + private static void printTime(Map.Entry threadCounter) { + if (DEBUG) + System.out.printf("%s %d%n", threadCounter.getKey(), threadCounter.getValue() + .get()); + } + + private static void addCounters(Thread thread) { + counterExtractorMap.forEach((map, timeExtractor) -> add(map, thread, timeExtractor)); + } + + private static void add(Map time, Thread thread, + LongUnaryOperator timeExtractor) { + time.put(thread, new AtomicLong(timeExtractor.applyAsLong(thread.getId()))); + } + + private static void resetAllCounters() { + counterExtractorMap.forEach(BigIntegerMersennePrimeMultiply::resetTimes); + } + + private static void resetTimes(Map timeMap, LongUnaryOperator timeMethod) { + timeMap.forEach((thread, time) -> + time.set(timeMethod.applyAsLong(thread.getId()))); + } + + private static final Map userTime = + new ConcurrentHashMap<>(); + private static final Map cpuTime = + new ConcurrentHashMap<>(); + private static final Map bytes = + new ConcurrentHashMap<>(); + private static final ThreadMXBean tmb = ManagementFactory.getThreadMXBean(); + + private static final Map, LongUnaryOperator> counterExtractorMap = + new IdentityHashMap<>(); + + static { + counterExtractorMap.put(userTime, tmb::getThreadUserTime); + counterExtractorMap.put(cpuTime, tmb::getThreadCpuTime); + counterExtractorMap.put(bytes, BigIntegerMersennePrimeMultiply::threadAllocatedBytes); + } + + public final ForkJoinWorkerThread newThread(ForkJoinPool pool) { + ForkJoinWorkerThread thread = defaultForkJoinWorkerThreadFactory.newThread(pool); + addCounters(thread); + return thread; + } + + private static final String[] SIGNATURE = new String[]{long.class.getName()}; + private static final MBeanServer mBeanServer; + private static final ObjectName name; + + static { + try { + name = new ObjectName(ManagementFactory.THREAD_MXBEAN_NAME); + mBeanServer = ManagementFactory.getPlatformMBeanServer(); + } catch (MalformedObjectNameException e) { + throw new ExceptionInInitializerError(e); + } + } + + public static long threadAllocatedBytes(long threadId) { + try { + return (long) mBeanServer.invoke( + name, + "getThreadAllocatedBytes", + new Object[]{threadId}, + SIGNATURE + ); + } catch (Exception e) { + throw new IllegalArgumentException(e); + } + } + + public static String formatMemory(double bytes, int decimals) { + double val; + String unitStr; + if (bytes < 1024) { + val = bytes; + unitStr = "B"; + } else if (bytes < 1024 * 1024) { + val = bytes / 1024; + unitStr = "KB"; + } else if (bytes < 1024 * 1024 * 1024) { + val = bytes / (1024 * 1024); + unitStr = "MB"; + } else if (bytes < 1024 * 1024 * 1024 * 1024L) { + val = bytes / (1024 * 1024 * 1024L); + unitStr = "GB"; + } else { + val = bytes / (1024 * 1024 * 1024 * 1024L); + unitStr = "TB"; + } + return String.format(Locale.US, "%." + decimals + "f%s", val, unitStr); + } + + public static String formatTime(long nanos) { + if (nanos < 0) nanos = 0; + long timeInMs = TimeUnit.NANOSECONDS.toMillis(nanos); + long minutes = timeInMs / 60_000; + double remainingMs = (timeInMs % 60_000) / 1000.0; + return String.format(Locale.US, "%dm%.3fs", minutes, remainingMs); + } +} \ No newline at end of file diff --git a/test/micro/org/openjdk/bench/java/math/BigIntegerParallelMultiply.java b/test/micro/org/openjdk/bench/java/math/BigIntegerParallelMultiply.java new file mode 100644 index 0000000000000000000000000000000000000000..92a1c5a8237e2607fe0d465eb8f162c2112f313a --- /dev/null +++ b/test/micro/org/openjdk/bench/java/math/BigIntegerParallelMultiply.java @@ -0,0 +1,61 @@ +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.OutputTimeUnit; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; + +import java.math.BigInteger; +import java.util.concurrent.TimeUnit; +import java.util.function.BinaryOperator; + +/** + * Benchmark for checking performance difference between + * sequential and parallel multiply methods in BigInteger, + * using a large Fibonacci calculation of up to n = 100 million. + * + * @author Heinz Kabutz, heinz@javaspecialists.eu + */ +@BenchmarkMode(Mode.SingleShotTime) +@OutputTimeUnit(TimeUnit.MILLISECONDS) +@Fork(value = 2) +@Warmup(iterations = 2) +@Measurement(iterations = 2) // only 2 iterations because each one takes very long +@State(Scope.Thread) +public class BigIntegerParallelMultiply { + private static BigInteger fibonacci(int n, BinaryOperator multiplyOperator) { + if (n == 0) return BigInteger.ZERO; + if (n == 1) return BigInteger.ONE; + + int half = (n + 1) / 2; + BigInteger f0 = fibonacci(half - 1, multiplyOperator); + BigInteger f1 = fibonacci(half, multiplyOperator); + if (n % 2 == 1) { + BigInteger b0 = multiplyOperator.apply(f0, f0); + BigInteger b1 = multiplyOperator.apply(f1, f1); + return b0.add(b1); + } else { + BigInteger b0 = f0.shiftLeft(1).add(f1); + return multiplyOperator.apply(b0, f1); + } + } + + @Param({"1000000", "10000000", "100000000"}) + private int n; + + @Benchmark + public void multiply() { + fibonacci(n, BigInteger::multiply); + } + + @Benchmark + public void parallelMultiply() { + fibonacci(n, BigInteger::parallelMultiply); + } +} \ No newline at end of file diff --git a/test/micro/org/openjdk/bench/java/math/BigIntegers.java b/test/micro/org/openjdk/bench/java/math/BigIntegers.java index e2d563d83065552f255d09611845c37cb61562a4..54056e2c5d41440dae93da1c802f8a76f0ce14ff 100644 --- a/test/micro/org/openjdk/bench/java/math/BigIntegers.java +++ b/test/micro/org/openjdk/bench/java/math/BigIntegers.java @@ -207,4 +207,15 @@ public class BigIntegers { bh.consume(tmp); } } + + /** Invokes the gcd method of BigInteger with different values. */ + @Benchmark + @OperationsPerInvocation(TESTSIZE) + public void testGcd(Blackhole bh) { + for (int i = 0; i < TESTSIZE; i++) { + BigInteger i1 = shiftArray[TESTSIZE - i - 1]; + BigInteger i2 = shiftArray[i]; + bh.consume(i2.gcd(i1)); + } + } } diff --git a/test/micro/org/openjdk/bench/java/nio/CharsetEncodeDecode.java b/test/micro/org/openjdk/bench/java/nio/CharsetEncodeDecode.java index 6e129a5466e895ea2f970e74ecbec48cf31ad226..404bb0583fdc791a1ca015362bb89f9dcfa260a0 100644 --- a/test/micro/org/openjdk/bench/java/nio/CharsetEncodeDecode.java +++ b/test/micro/org/openjdk/bench/java/nio/CharsetEncodeDecode.java @@ -61,7 +61,7 @@ public class CharsetEncodeDecode { private CharsetEncoder encoder; private CharsetDecoder decoder; - @Param({"UTF-8", "BIG5", "ISO-8859-15", "ASCII", "UTF-16"}) + @Param({"UTF-8", "BIG5", "ISO-8859-15", "ISO-8859-1", "ASCII", "UTF-16"}) private String type; @Param("16384") diff --git a/test/micro/org/openjdk/bench/java/text/ZoneStrings.java b/test/micro/org/openjdk/bench/java/text/ZoneStrings.java new file mode 100644 index 0000000000000000000000000000000000000000..383cc8e0b205bd7922dde9e9751ba396be66907d --- /dev/null +++ b/test/micro/org/openjdk/bench/java/text/ZoneStrings.java @@ -0,0 +1,44 @@ +/* + * 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. + */ +package org.openjdk.bench.java.text; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.State; + +import java.text.DateFormatSymbols; +import java.util.Locale; + +@BenchmarkMode(Mode.SingleShotTime) +@State(Scope.Thread) +public class ZoneStrings { + + @Benchmark + public void testZoneStrings() { + for (Locale l : Locale.getAvailableLocales()) { + new DateFormatSymbols(l).getZoneStrings(); + } + } +} diff --git a/test/micro/org/openjdk/bench/java/util/RandomGeneratorNext.java b/test/micro/org/openjdk/bench/java/util/RandomGeneratorNext.java new file mode 100644 index 0000000000000000000000000000000000000000..adb70e195e4233cb0500c44cfc5aae45eb89e178 --- /dev/null +++ b/test/micro/org/openjdk/bench/java/util/RandomGeneratorNext.java @@ -0,0 +1,72 @@ +/* + * 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. + */ +package org.openjdk.bench.java.util; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +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.Param; +import java.util.random.RandomGenerator; +import java.util.random.RandomGeneratorFactory; +import java.util.concurrent.TimeUnit; + +/** + * Tests java.util.random.RandomGenerator's different random number generators which use Math.unsignedMultiplyHigh(). + */ +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@State(Scope.Thread) +public class RandomGeneratorNext { + + RandomGenerator randomGenerator; + + @Param({"L128X128MixRandom", "L128X256MixRandom", "L128X1024MixRandom"}) + String randomGeneratorName; + + long[] buffer; + + @Param("1024") + int size; + + @Setup + public void setup() { + buffer = new long[size]; + randomGenerator = RandomGeneratorFactory.of(randomGeneratorName).create(randomGeneratorName.hashCode()); + } + + @Benchmark + public long testNextLong() { + return randomGenerator.nextLong(); + } + + @Benchmark + public long[] testFillBufferWithNextLong() { + for (int i = 0; i < size; i++) buffer[i] = randomGenerator.nextLong(); + return buffer; + } + +} diff --git a/test/micro/org/openjdk/bench/java/util/TestCRC32C.java b/test/micro/org/openjdk/bench/java/util/TestCRC32C.java new file mode 100644 index 0000000000000000000000000000000000000000..0c3b39fc59a67dd3570ede9f9d27c3b5b0c72498 --- /dev/null +++ b/test/micro/org/openjdk/bench/java/util/TestCRC32C.java @@ -0,0 +1,60 @@ +/* + * 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. + */ +package org.openjdk.bench.java.util; + +import java.util.Random; +import java.util.concurrent.TimeUnit; +import java.util.zip.CRC32C; +import org.openjdk.jmh.annotations.*; + +@BenchmarkMode(Mode.Throughput) +@OutputTimeUnit(TimeUnit.MILLISECONDS) +@State(Scope.Benchmark) +@Fork(value = 2) + +public class TestCRC32C { + + private CRC32C crc32c; + private Random random; + private byte[] bytes; + + @Param({"64", "128", "256", "512", "1024", "2048", "4096", "8192", "16384", "32768", "65536"}) + private int count; + + public TestCRC32C() { + crc32c = new CRC32C(); + random = new Random(2147483648L); + bytes = new byte[1000000]; + random.nextBytes(bytes); + } + + @Setup(Level.Iteration) + public void setupBytes() { + crc32c.reset(); + } + + @Benchmark + public void testCRC32CUpdate() { + crc32c.update(bytes, 0, count); + } +} diff --git a/test/micro/org/openjdk/bench/java/util/regex/FindPattern.java b/test/micro/org/openjdk/bench/java/util/regex/FindPattern.java new file mode 100644 index 0000000000000000000000000000000000000000..907a161688934bdb58c2796238ec175ff8d4f948 --- /dev/null +++ b/test/micro/org/openjdk/bench/java/util/regex/FindPattern.java @@ -0,0 +1,71 @@ +/* + * 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.util.regex; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Level; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; + +import java.util.concurrent.TimeUnit; +import java.util.regex.Pattern; +import java.util.regex.Matcher; + +@State(Scope.Benchmark) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@Fork(value=1, jvmArgs= {"-showversion", "-XX:+UseSerialGC"}) +@Warmup(iterations = 1, time = 10, timeUnit = TimeUnit.SECONDS) +@Measurement(iterations = 3, time = 10, timeUnit = TimeUnit.SECONDS) +public class FindPattern { + @Param({"[^A-Za-z0-9]", "[A-Za-z0-9]"}) + static String patternString; + @Param({"abcdefghijklmnop1234567890ABCDEFGHIJKLMNOP", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"}) + static String text; + static Pattern pattern; + + @Setup(Level.Trial) + public void setupTrial() { + pattern = Pattern.compile(patternString); + } + + @Benchmark + @BenchmarkMode(Mode.AverageTime) + public int testFind() { + int counter = 0; + Matcher m = pattern.matcher(text); + while (m.find()) { + counter++; + } + return counter; + } +} diff --git a/test/micro/org/openjdk/bench/java/util/zip/InflaterInputStreams.java b/test/micro/org/openjdk/bench/java/util/zip/InflaterInputStreams.java new file mode 100644 index 0000000000000000000000000000000000000000..ab6be0e9374e833d6b6597829a72fe286a1c103d --- /dev/null +++ b/test/micro/org/openjdk/bench/java/util/zip/InflaterInputStreams.java @@ -0,0 +1,114 @@ +/* + * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.bench.java.util.zip; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Level; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.Random; +import java.util.concurrent.TimeUnit; +import java.util.zip.Inflater; +import java.util.zip.InflaterInputStream; +import java.util.zip.DeflaterOutputStream; + +/** + * A simple benchmark to measure the performance improvements achieved by avoiding + * unnecessary native calls in InflaterInputStream::read() (see JDK-8281962). + * + * before JDK-8281962 + * ------------------ + * Benchmark (size) Mode Cnt Score Error Units + * InflaterInputStreams.inflaterInputStreamRead 256 avgt 5 2.571 0.120 us/op + * InflaterInputStreams.inflaterInputStreamRead 512 avgt 5 2.861 0.064 us/op + * InflaterInputStreams.inflaterInputStreamRead 4096 avgt 5 5.110 0.278 us/op + * + * after JDK-8281962 + * ----------------- + * Benchmark (size) Mode Cnt Score Error Units + * InflaterInputStreams.inflaterInputStreamRead 256 avgt 5 2.332 0.081 us/op + * InflaterInputStreams.inflaterInputStreamRead 512 avgt 5 2.691 0.293 us/op + * InflaterInputStreams.inflaterInputStreamRead 4096 avgt 5 4.812 1.038 us/op + * + */ +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.MICROSECONDS) +@State(Scope.Thread) +@Warmup(iterations = 3, time = 5, timeUnit = TimeUnit.SECONDS) +@Measurement(iterations = 5, time = 5, timeUnit = TimeUnit.SECONDS) +public class InflaterInputStreams { + + @Param({"256", "512", "4096"}) + private int size; + private byte[] chars; + private byte[] words; + private static byte[] inflated; + ByteArrayInputStream deflated; + + @Setup(Level.Trial) + public void beforeRun() throws IOException { + final int charCount = 64; + final int wordLength = 8; + chars = new byte[charCount]; + Random r = new Random(123456789); + r.nextBytes(chars); + words = new byte[1024]; + for (int i = 0; i < words.length / wordLength; i++) { + System.arraycopy(chars, r.nextInt(charCount - wordLength), words, i * wordLength, wordLength); + } + inflated = new byte[2*size]; + } + + @Setup(Level.Iteration) + public void beforeIteration() throws IOException { + // Maximum deflated size (see https://stackoverflow.com/a/23578269/4146053) + int maxDeflated = size + 5*(size/16383 + 1); + ByteArrayOutputStream baos = new ByteArrayOutputStream(maxDeflated); + DeflaterOutputStream defout = new DeflaterOutputStream(baos); + ByteArrayInputStream bais = new ByteArrayInputStream(words, 0, size); + bais.transferTo(defout); + // We need to close the DeflaterOutputStream in order to flush + // all the compressed data in the Deflater. + defout.close(); + deflated = new ByteArrayInputStream(baos.toByteArray()); + } + + @Benchmark + public void inflaterInputStreamRead() throws IOException { + deflated.reset(); + InflaterInputStream iis = new InflaterInputStream(deflated); + while (iis.read(inflated, 0, inflated.length) != -1); + } +} diff --git a/test/micro/org/openjdk/bench/jdk/incubator/foreign/BulkMismatchAcquire.java b/test/micro/org/openjdk/bench/jdk/incubator/foreign/BulkMismatchAcquire.java index 5d962ee39796e986df28531dc205c6cc67e51dec..c9fc3abd33a5c7748f5d509c0adcf831da944ac9 100644 --- a/test/micro/org/openjdk/bench/jdk/incubator/foreign/BulkMismatchAcquire.java +++ b/test/micro/org/openjdk/bench/jdk/incubator/foreign/BulkMismatchAcquire.java @@ -26,7 +26,6 @@ package org.openjdk.bench.jdk.incubator.foreign; import jdk.incubator.foreign.ResourceScope; -import jdk.incubator.foreign.SegmentAllocator; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Fork; @@ -38,15 +37,12 @@ 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 jdk.incubator.foreign.MemorySegment; import java.nio.ByteBuffer; import java.util.concurrent.TimeUnit; import java.util.function.Supplier; -import static jdk.incubator.foreign.MemoryLayouts.JAVA_INT; - @BenchmarkMode(Mode.AverageTime) @Warmup(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS) @Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS) @@ -71,7 +67,7 @@ public class BulkMismatchAcquire { } } - @Param({"CONFINED", "SHARED", "IMPLICIT"}) + @Param({"CONFINED", "SHARED"}) public ScopeKind scopeKind; // large(ish) segments/buffers with same content, 0, for mismatch, non-multiple-of-8 sized @@ -121,8 +117,7 @@ public class BulkMismatchAcquire { @TearDown public void tearDown() { - if (!scope.isImplicit()) - scope.close(); + scope.close(); } @Benchmark @@ -134,11 +129,9 @@ public class BulkMismatchAcquire { @Benchmark @OutputTimeUnit(TimeUnit.NANOSECONDS) public long mismatch_large_segment_acquire() { - var handle = mismatchSegmentLarge1.scope().acquire(); - try { + try (ResourceScope scope = ResourceScope.newConfinedScope()) { + scope.keepAlive(mismatchSegmentLarge1.scope()); return mismatchSegmentLarge1.mismatch(mismatchSegmentLarge2); - } finally { - mismatchSegmentLarge1.scope().release(handle); } } @@ -157,11 +150,9 @@ public class BulkMismatchAcquire { @Benchmark @OutputTimeUnit(TimeUnit.NANOSECONDS) public long mismatch_small_segment_acquire() { - var handle = mismatchSegmentLarge1.scope().acquire(); - try { + try (ResourceScope scope = ResourceScope.newConfinedScope()) { + scope.keepAlive(mismatchSegmentLarge1.scope()); return mismatchSegmentSmall1.mismatch(mismatchSegmentSmall2); - } finally { - mismatchSegmentLarge1.scope().release(handle); } } diff --git a/test/micro/org/openjdk/bench/jdk/incubator/foreign/BulkOps.java b/test/micro/org/openjdk/bench/jdk/incubator/foreign/BulkOps.java index ac92e9429cae1382dfc49c7dc8f40cdffe1d13f8..25d6cf557b0398c5f0b311acc98baf5bd227bc0b 100644 --- a/test/micro/org/openjdk/bench/jdk/incubator/foreign/BulkOps.java +++ b/test/micro/org/openjdk/bench/jdk/incubator/foreign/BulkOps.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -27,19 +27,23 @@ package org.openjdk.bench.jdk.incubator.foreign; import jdk.incubator.foreign.ResourceScope; 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.Setup; import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.TearDown; import org.openjdk.jmh.annotations.Warmup; import sun.misc.Unsafe; import jdk.incubator.foreign.MemorySegment; import java.nio.ByteBuffer; +import java.nio.IntBuffer; import java.util.concurrent.TimeUnit; -import static jdk.incubator.foreign.MemoryLayouts.JAVA_INT; +import static jdk.incubator.foreign.ValueLayout.JAVA_INT; @BenchmarkMode(Mode.AverageTime) @Warmup(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS) @@ -55,26 +59,31 @@ public class BulkOps { static final int CARRIER_SIZE = (int)JAVA_INT.byteSize(); static final int ALLOC_SIZE = ELEM_SIZE * CARRIER_SIZE; - static final long unsafe_addr = unsafe.allocateMemory(ALLOC_SIZE); - static final MemorySegment segment = MemorySegment.allocateNative(ALLOC_SIZE, ResourceScope.newConfinedScope()); + final ResourceScope scope = ResourceScope.newConfinedScope(); - static final int[] bytes = new int[ELEM_SIZE]; - static final MemorySegment bytesSegment = MemorySegment.ofArray(bytes); - static final int UNSAFE_INT_OFFSET = unsafe.arrayBaseOffset(int[].class); + final long unsafe_addr = unsafe.allocateMemory(ALLOC_SIZE); + final MemorySegment segment = MemorySegment.allocateNative(ALLOC_SIZE, ResourceScope.newConfinedScope()); + final IntBuffer buffer = IntBuffer.allocate(ELEM_SIZE); + + final int[] bytes = new int[ELEM_SIZE]; + final MemorySegment bytesSegment = MemorySegment.ofArray(bytes); + final int UNSAFE_INT_OFFSET = unsafe.arrayBaseOffset(int[].class); // large(ish) segments/buffers with same content, 0, for mismatch, non-multiple-of-8 sized static final int SIZE_WITH_TAIL = (1024 * 1024) + 7; - static final MemorySegment mismatchSegmentLarge1 = MemorySegment.allocateNative(SIZE_WITH_TAIL, ResourceScope.newConfinedScope()); - static final MemorySegment mismatchSegmentLarge2 = MemorySegment.allocateNative(SIZE_WITH_TAIL, ResourceScope.newConfinedScope()); - static final ByteBuffer mismatchBufferLarge1 = ByteBuffer.allocateDirect(SIZE_WITH_TAIL); - static final ByteBuffer mismatchBufferLarge2 = ByteBuffer.allocateDirect(SIZE_WITH_TAIL); + final MemorySegment mismatchSegmentLarge1 = MemorySegment.allocateNative(SIZE_WITH_TAIL, scope); + final MemorySegment mismatchSegmentLarge2 = MemorySegment.allocateNative(SIZE_WITH_TAIL, scope); + final ByteBuffer mismatchBufferLarge1 = ByteBuffer.allocateDirect(SIZE_WITH_TAIL); + final ByteBuffer mismatchBufferLarge2 = ByteBuffer.allocateDirect(SIZE_WITH_TAIL); // mismatch at first byte - static final MemorySegment mismatchSegmentSmall1 = MemorySegment.allocateNative(7, ResourceScope.newConfinedScope()); - static final MemorySegment mismatchSegmentSmall2 = MemorySegment.allocateNative(7, ResourceScope.newConfinedScope()); - static final ByteBuffer mismatchBufferSmall1 = ByteBuffer.allocateDirect(7); - static final ByteBuffer mismatchBufferSmall2 = ByteBuffer.allocateDirect(7); - static { + final MemorySegment mismatchSegmentSmall1 = MemorySegment.allocateNative(7, scope); + final MemorySegment mismatchSegmentSmall2 = MemorySegment.allocateNative(7, scope); + final ByteBuffer mismatchBufferSmall1 = ByteBuffer.allocateDirect(7); + final ByteBuffer mismatchBufferSmall2 = ByteBuffer.allocateDirect(7); + + @Setup + public void setup() { mismatchSegmentSmall1.fill((byte) 0xFF); mismatchBufferSmall1.put((byte) 0xFF).clear(); // verify expected mismatch indices @@ -90,14 +99,17 @@ public class BulkOps { bi = mismatchBufferSmall1.mismatch(mismatchBufferSmall2); if (bi != 0) throw new AssertionError("Unexpected mismatch index:" + bi); - } - static { for (int i = 0 ; i < bytes.length ; i++) { bytes[i] = i; } } + @TearDown + public void tearDown() { + scope.close(); + } + @Benchmark @OutputTimeUnit(TimeUnit.NANOSECONDS) public void unsafe_fill() { @@ -122,6 +134,50 @@ public class BulkOps { segment.copyFrom(bytesSegment); } + @Benchmark + @OutputTimeUnit(TimeUnit.NANOSECONDS) + public void segment_copy_static() { + MemorySegment.copy(bytes, 0, segment, JAVA_INT, 0, bytes.length); + } + + @Benchmark + @OutputTimeUnit(TimeUnit.NANOSECONDS) + public void segment_copy_static_small() { + MemorySegment.copy(bytes, 0, segment, JAVA_INT, 0, 10); + } + + @Benchmark + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + @OutputTimeUnit(TimeUnit.NANOSECONDS) + public void segment_copy_static_small_dontinline() { + MemorySegment.copy(bytes, 0, segment, JAVA_INT, 0, 10); + } + + @Benchmark + @OutputTimeUnit(TimeUnit.NANOSECONDS) + public void unsafe_copy_small() { + unsafe.copyMemory(bytes, UNSAFE_INT_OFFSET, null, unsafe_addr, 10 * CARRIER_SIZE); + } + + @Benchmark + @OutputTimeUnit(TimeUnit.NANOSECONDS) + public void buffer_copy_small() { + buffer.put(0, bytes, 0, 10); + } + + @Benchmark + @OutputTimeUnit(TimeUnit.NANOSECONDS) + public void buffer_copy() { + buffer.put(0, bytes, 0, bytes.length); + } + + @Benchmark + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + @OutputTimeUnit(TimeUnit.NANOSECONDS) + public void segment_copy_static_dontinline() { + MemorySegment.copy(bytes, 0, segment, JAVA_INT, 0, bytes.length); + } + @Benchmark @OutputTimeUnit(TimeUnit.NANOSECONDS) public long mismatch_large_segment() { diff --git a/test/micro/org/openjdk/bench/jdk/incubator/foreign/CLayouts.java b/test/micro/org/openjdk/bench/jdk/incubator/foreign/CLayouts.java new file mode 100644 index 0000000000000000000000000000000000000000..530731e34bfc6221adba5376f490790105d4224c --- /dev/null +++ b/test/micro/org/openjdk/bench/jdk/incubator/foreign/CLayouts.java @@ -0,0 +1,95 @@ +/* + * 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. + */ + +package org.openjdk.bench.jdk.incubator.foreign; + +import jdk.incubator.foreign.Addressable; +import jdk.incubator.foreign.CLinker; +import jdk.incubator.foreign.FunctionDescriptor; +import jdk.incubator.foreign.MemoryAddress; +import jdk.incubator.foreign.ValueLayout; + +import java.lang.invoke.MethodHandle; + +public class CLayouts { + + // the constants below are useful aliases for C types. The type/carrier association is only valid for 64-bit platforms. + + /** + * The layout for the {@code bool} C type + */ + public static final ValueLayout.OfBoolean C_BOOL = ValueLayout.JAVA_BOOLEAN; + /** + * The layout for the {@code char} C type + */ + public static final ValueLayout.OfByte C_CHAR = ValueLayout.JAVA_BYTE; + /** + * The layout for the {@code short} C type + */ + public static final ValueLayout.OfShort C_SHORT = ValueLayout.JAVA_SHORT; + /** + * The layout for the {@code int} C type + */ + public static final ValueLayout.OfInt C_INT = ValueLayout.JAVA_INT; + + /** + * The layout for the {@code long long} C type. + */ + public static final ValueLayout.OfLong C_LONG_LONG = ValueLayout.JAVA_LONG; + /** + * The layout for the {@code float} C type + */ + public static final ValueLayout.OfFloat C_FLOAT = ValueLayout.JAVA_FLOAT; + /** + * The layout for the {@code double} C type + */ + public static final ValueLayout.OfDouble C_DOUBLE = ValueLayout.JAVA_DOUBLE; + /** + * The {@code T*} native type. + */ + public static final ValueLayout.OfAddress C_POINTER = ValueLayout.ADDRESS; + + private static CLinker LINKER = CLinker.systemCLinker(); + + private static final MethodHandle FREE = LINKER.downcallHandle( + LINKER.lookup("free").get(), FunctionDescriptor.ofVoid(ValueLayout.ADDRESS)); + + private static final MethodHandle MALLOC = LINKER.downcallHandle( + LINKER.lookup("malloc").get(), FunctionDescriptor.of(ValueLayout.ADDRESS, ValueLayout.JAVA_LONG)); + + public static void freeMemory(Addressable address) { + try { + FREE.invokeExact(address); + } catch (Throwable ex) { + throw new IllegalStateException(ex); + } + } + + public static MemoryAddress allocateMemory(long size) { + try { + return (MemoryAddress)MALLOC.invokeExact(size); + } catch (Throwable ex) { + throw new IllegalStateException(ex); + } + } +} diff --git a/test/micro/org/openjdk/bench/jdk/incubator/foreign/CallOverheadConstant.java b/test/micro/org/openjdk/bench/jdk/incubator/foreign/CallOverheadConstant.java index bd627646770b9cd2e442569e72c9a7898057bb36..8fe3d1b1ea472d461e61d7517686d42d12839a81 100644 --- a/test/micro/org/openjdk/bench/jdk/incubator/foreign/CallOverheadConstant.java +++ b/test/micro/org/openjdk/bench/jdk/incubator/foreign/CallOverheadConstant.java @@ -22,6 +22,7 @@ */ package org.openjdk.bench.jdk.incubator.foreign; +import jdk.incubator.foreign.Addressable; import jdk.incubator.foreign.MemoryAddress; import jdk.incubator.foreign.MemorySegment; import org.openjdk.jmh.annotations.Benchmark; @@ -55,11 +56,6 @@ public class CallOverheadConstant { func.invokeExact(); } - @Benchmark - public void panama_blank_trivial() throws Throwable { - func_trivial.invokeExact(); - } - @Benchmark public int jni_identity() throws Throwable { return identity(10); @@ -71,18 +67,73 @@ public class CallOverheadConstant { } @Benchmark - public int panama_identity_trivial() throws Throwable { - return (int) identity_trivial.invokeExact(10); + public MemorySegment panama_identity_struct_confined() throws Throwable { + return (MemorySegment) identity_struct.invokeExact(recycling_allocator, confinedPoint); + } + + @Benchmark + public MemorySegment panama_identity_struct_shared() throws Throwable { + return (MemorySegment) identity_struct.invokeExact(recycling_allocator, sharedPoint); + } + + @Benchmark + public MemorySegment panama_identity_struct_confined_3() throws Throwable { + return (MemorySegment) identity_struct_3.invokeExact(recycling_allocator, confinedPoint, confinedPoint, confinedPoint); + } + + @Benchmark + public MemorySegment panama_identity_struct_shared_3() throws Throwable { + return (MemorySegment) identity_struct_3.invokeExact(recycling_allocator, sharedPoint, sharedPoint, sharedPoint); + } + + @Benchmark + public MemoryAddress panama_identity_memory_address_shared() throws Throwable { + return (MemoryAddress) identity_memory_address.invokeExact((Addressable)sharedPoint.address()); + } + + @Benchmark + public MemoryAddress panama_identity_memory_address_confined() throws Throwable { + return (MemoryAddress) identity_memory_address.invokeExact((Addressable)confinedPoint.address()); + } + + @Benchmark + public MemoryAddress panama_identity_memory_address_shared_3() throws Throwable { + return (MemoryAddress) identity_memory_address_3.invokeExact((Addressable)sharedPoint.address(), (Addressable)sharedPoint.address(), (Addressable)sharedPoint.address()); + } + + @Benchmark + public MemoryAddress panama_identity_memory_address_confined_3() throws Throwable { + return (MemoryAddress) identity_memory_address_3.invokeExact((Addressable)confinedPoint.address(), (Addressable)confinedPoint.address(), (Addressable)confinedPoint.address()); + } + + @Benchmark + public MemoryAddress panama_identity_struct_ref_shared() throws Throwable { + return (MemoryAddress) identity_memory_address.invokeExact((Addressable)sharedPoint); + } + + @Benchmark + public MemoryAddress panama_identity_struct_ref_confined() throws Throwable { + return (MemoryAddress) identity_memory_address.invokeExact((Addressable)confinedPoint); + } + + @Benchmark + public MemoryAddress panama_identity_struct_ref_shared_3() throws Throwable { + return (MemoryAddress) identity_memory_address_3.invokeExact((Addressable)sharedPoint, (Addressable)sharedPoint, (Addressable)sharedPoint); + } + + @Benchmark + public MemoryAddress panama_identity_struct_ref_confined_3() throws Throwable { + return (MemoryAddress) identity_memory_address_3.invokeExact((Addressable)confinedPoint, (Addressable)confinedPoint, (Addressable)confinedPoint); } @Benchmark - public MemorySegment panama_identity_struct() throws Throwable { - return (MemorySegment) identity_struct.invokeExact(recycling_allocator, point); + public MemoryAddress panama_identity_memory_address_null() throws Throwable { + return (MemoryAddress) identity_memory_address.invokeExact((Addressable)MemoryAddress.NULL); } @Benchmark - public MemoryAddress panama_identity_memory_address() throws Throwable { - return (MemoryAddress) identity_memory_address.invokeExact(MemoryAddress.NULL); + public MemoryAddress panama_identity_memory_address_null_non_exact() throws Throwable { + return (MemoryAddress) identity_memory_address.invoke(MemoryAddress.NULL); } @Benchmark diff --git a/test/micro/org/openjdk/bench/jdk/incubator/foreign/CallOverheadHelper.java b/test/micro/org/openjdk/bench/jdk/incubator/foreign/CallOverheadHelper.java index 4989f5fa47e5f644f927756d41455c29443d6684..259c4b26bdd6ad2c5fd21f8827fca322a696fe83 100644 --- a/test/micro/org/openjdk/bench/jdk/incubator/foreign/CallOverheadHelper.java +++ b/test/micro/org/openjdk/bench/jdk/incubator/foreign/CallOverheadHelper.java @@ -22,12 +22,11 @@ */ package org.openjdk.bench.jdk.incubator.foreign; -import jdk.incubator.foreign.Addressable; import jdk.incubator.foreign.CLinker; import jdk.incubator.foreign.FunctionDescriptor; -import jdk.incubator.foreign.MemoryAddress; import jdk.incubator.foreign.MemoryLayout; import jdk.incubator.foreign.MemorySegment; +import jdk.incubator.foreign.NativeSymbol; import jdk.incubator.foreign.ResourceScope; import jdk.incubator.foreign.SegmentAllocator; import jdk.incubator.foreign.SymbolLookup; @@ -36,57 +35,58 @@ import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodType; import static java.lang.invoke.MethodHandles.insertArguments; -import static jdk.incubator.foreign.CLinker.C_DOUBLE; -import static jdk.incubator.foreign.CLinker.C_INT; -import static jdk.incubator.foreign.CLinker.C_LONG_LONG; -import static jdk.incubator.foreign.CLinker.C_POINTER; -public class CallOverheadHelper { +public class CallOverheadHelper extends CLayouts { - static final CLinker abi = CLinker.getInstance(); + static final CLinker abi = CLinker.systemCLinker(); static final MethodHandle func; static final MethodHandle func_v; - static Addressable func_addr; + static NativeSymbol func_addr; static final MethodHandle identity; static final MethodHandle identity_v; - static Addressable identity_addr; + static NativeSymbol identity_addr; static final MethodHandle identity_struct; static final MethodHandle identity_struct_v; - static Addressable identity_struct_addr; + static NativeSymbol identity_struct_addr; + static final MethodHandle identity_struct_3; + static final MethodHandle identity_struct_3_v; + static NativeSymbol identity_struct_3_addr; static final MethodHandle identity_memory_address; static final MethodHandle identity_memory_address_v; - static Addressable identity_memory_address_addr; + static NativeSymbol identity_memory_address_addr; + static final MethodHandle identity_memory_address_3; + static final MethodHandle identity_memory_address_3_v; + static NativeSymbol identity_memory_address_3_addr; static final MethodHandle args1; static final MethodHandle args1_v; - static Addressable args1_addr; + static NativeSymbol args1_addr; static final MethodHandle args2; static final MethodHandle args2_v; - static Addressable args2_addr; + static NativeSymbol args2_addr; static final MethodHandle args3; static final MethodHandle args3_v; - static Addressable args3_addr; + static NativeSymbol args3_addr; static final MethodHandle args4; static final MethodHandle args4_v; - static Addressable args4_addr; + static NativeSymbol args4_addr; static final MethodHandle args5; static final MethodHandle args5_v; - static Addressable args5_addr; + static NativeSymbol args5_addr; static final MethodHandle args10; static final MethodHandle args10_v; - static Addressable args10_addr; - static final MethodHandle func_trivial; - static final MethodHandle func_trivial_v; - static final MethodHandle identity_trivial; - static final MethodHandle identity_trivial_v; + static NativeSymbol args10_addr; static final MemoryLayout POINT_LAYOUT = MemoryLayout.structLayout( - C_LONG_LONG, C_LONG_LONG + C_INT, C_INT ); + static final MemorySegment sharedPoint = MemorySegment.allocateNative(POINT_LAYOUT, ResourceScope.newSharedScope()); + static final MemorySegment confinedPoint = MemorySegment.allocateNative(POINT_LAYOUT, ResourceScope.newConfinedScope()); + static final MemorySegment point = MemorySegment.allocateNative(POINT_LAYOUT, ResourceScope.newImplicitScope()); - static final SegmentAllocator recycling_allocator = SegmentAllocator.ofSegment(MemorySegment.allocateNative(POINT_LAYOUT, ResourceScope.newImplicitScope())); + static final SegmentAllocator recycling_allocator = SegmentAllocator.prefixAllocator(MemorySegment.allocateNative(POINT_LAYOUT, ResourceScope.newImplicitScope())); static { System.loadLibrary("CallOverheadJNI"); @@ -97,66 +97,62 @@ public class CallOverheadHelper { func_addr = lookup.lookup("func").orElseThrow(); MethodType mt = MethodType.methodType(void.class); FunctionDescriptor fd = FunctionDescriptor.ofVoid(); - func_v = abi.downcallHandle(mt, fd); + func_v = abi.downcallHandle(fd); func = insertArguments(func_v, 0, func_addr); - func_trivial_v = abi.downcallHandle(mt, fd.withAttribute(FunctionDescriptor.TRIVIAL_ATTRIBUTE_NAME, true)); - func_trivial = insertArguments(func_trivial_v, 0, func_addr); } { identity_addr = lookup.lookup("identity").orElseThrow(); - MethodType mt = MethodType.methodType(int.class, int.class); FunctionDescriptor fd = FunctionDescriptor.of(C_INT, C_INT); - identity_v = abi.downcallHandle(mt, fd); + identity_v = abi.downcallHandle(fd); identity = insertArguments(identity_v, 0, identity_addr); - identity_trivial_v = abi.downcallHandle(mt, fd.withAttribute(FunctionDescriptor.TRIVIAL_ATTRIBUTE_NAME, true)); - identity_trivial = insertArguments(identity_trivial_v, 0, identity_addr); } identity_struct_addr = lookup.lookup("identity_struct").orElseThrow(); identity_struct_v = abi.downcallHandle( - MethodType.methodType(MemorySegment.class, MemorySegment.class), FunctionDescriptor.of(POINT_LAYOUT, POINT_LAYOUT)); identity_struct = insertArguments(identity_struct_v, 0, identity_struct_addr); + identity_struct_3_addr = lookup.lookup("identity_struct_3").orElseThrow(); + identity_struct_3_v = abi.downcallHandle( + FunctionDescriptor.of(POINT_LAYOUT, POINT_LAYOUT, POINT_LAYOUT, POINT_LAYOUT)); + identity_struct_3 = insertArguments(identity_struct_3_v, 0, identity_struct_3_addr); + identity_memory_address_addr = lookup.lookup("identity_memory_address").orElseThrow(); identity_memory_address_v = abi.downcallHandle( - MethodType.methodType(MemoryAddress.class, MemoryAddress.class), FunctionDescriptor.of(C_POINTER, C_POINTER)); identity_memory_address = insertArguments(identity_memory_address_v, 0, identity_memory_address_addr); + identity_memory_address_3_addr = lookup.lookup("identity_memory_address_3").orElseThrow(); + identity_memory_address_3_v = abi.downcallHandle( + FunctionDescriptor.of(C_POINTER, C_POINTER, C_POINTER, C_POINTER)); + identity_memory_address_3 = insertArguments(identity_memory_address_3_v, 0, identity_memory_address_3_addr); + args1_addr = lookup.lookup("args1").orElseThrow(); args1_v = abi.downcallHandle( - MethodType.methodType(void.class, long.class), FunctionDescriptor.ofVoid(C_LONG_LONG)); args1 = insertArguments(args1_v, 0, args1_addr); args2_addr = lookup.lookup("args2").orElseThrow(); args2_v = abi.downcallHandle( - MethodType.methodType(void.class, long.class, double.class), FunctionDescriptor.ofVoid(C_LONG_LONG, C_DOUBLE)); args2 = insertArguments(args2_v, 0, args2_addr); args3_addr = lookup.lookup("args3").orElseThrow(); args3_v = abi.downcallHandle( - MethodType.methodType(void.class, long.class, double.class, long.class), FunctionDescriptor.ofVoid(C_LONG_LONG, C_DOUBLE, C_LONG_LONG)); args3 = insertArguments(args3_v, 0, args3_addr); args4_addr = lookup.lookup("args4").orElseThrow(); args4_v = abi.downcallHandle( - MethodType.methodType(void.class, long.class, double.class, long.class, double.class), FunctionDescriptor.ofVoid(C_LONG_LONG, C_DOUBLE, C_LONG_LONG, C_DOUBLE)); args4 = insertArguments(args4_v, 0, args4_addr); args5_addr = lookup.lookup("args5").orElseThrow(); args5_v = abi.downcallHandle( - MethodType.methodType(void.class, long.class, double.class, long.class, double.class, long.class), FunctionDescriptor.ofVoid(C_LONG_LONG, C_DOUBLE, C_LONG_LONG, C_DOUBLE, C_LONG_LONG)); args5 = insertArguments(args5_v, 0, args5_addr); args10_addr = lookup.lookup("args10").orElseThrow(); args10_v = abi.downcallHandle( - MethodType.methodType(void.class, long.class, double.class, long.class, double.class, long.class, - double.class, long.class, double.class, long.class, double.class), FunctionDescriptor.ofVoid(C_LONG_LONG, C_DOUBLE, C_LONG_LONG, C_DOUBLE, C_LONG_LONG, C_DOUBLE, C_LONG_LONG, C_DOUBLE, C_LONG_LONG, C_DOUBLE)); args10 = insertArguments(args10_v, 0, args10_addr); diff --git a/test/micro/org/openjdk/bench/jdk/incubator/foreign/CallOverheadVirtual.java b/test/micro/org/openjdk/bench/jdk/incubator/foreign/CallOverheadVirtual.java index e1e557bad237866ea82116b488f115787fe01ec7..11152bdd04414acee7c9c1d811f58252f6caf2dd 100644 --- a/test/micro/org/openjdk/bench/jdk/incubator/foreign/CallOverheadVirtual.java +++ b/test/micro/org/openjdk/bench/jdk/incubator/foreign/CallOverheadVirtual.java @@ -22,6 +22,7 @@ */ package org.openjdk.bench.jdk.incubator.foreign; +import jdk.incubator.foreign.Addressable; import jdk.incubator.foreign.MemoryAddress; import jdk.incubator.foreign.MemorySegment; import org.openjdk.jmh.annotations.Benchmark; @@ -56,23 +57,72 @@ public class CallOverheadVirtual { } @Benchmark - public void panama_blank_trivial() throws Throwable { - func_trivial_v.invokeExact(func_addr); + public int jni_identity() throws Throwable { + return identity(10); + } + + public MemorySegment panama_identity_struct_confined() throws Throwable { + return (MemorySegment) identity_struct_v.invokeExact(identity_struct_addr, recycling_allocator, confinedPoint); } @Benchmark - public int jni_identity() throws Throwable { - return identity(10); + public MemorySegment panama_identity_struct_shared() throws Throwable { + return (MemorySegment) identity_struct_v.invokeExact(identity_struct_addr, recycling_allocator, sharedPoint); } @Benchmark - public int panama_identity() throws Throwable { - return (int) identity_v.invokeExact(identity_addr, 10); + public MemorySegment panama_identity_struct_confined_3() throws Throwable { + return (MemorySegment) identity_struct_3_v.invokeExact(identity_struct_3_addr, recycling_allocator, confinedPoint, confinedPoint, confinedPoint); } @Benchmark - public int panama_identity_trivial() throws Throwable { - return (int) identity_trivial_v.invokeExact(identity_addr, 10); + public MemorySegment panama_identity_struct_shared_3() throws Throwable { + return (MemorySegment) identity_struct_3_v.invokeExact(identity_struct_3_addr, recycling_allocator, sharedPoint, sharedPoint, sharedPoint); + } + + @Benchmark + public MemoryAddress panama_identity_memory_address_shared() throws Throwable { + return (MemoryAddress) identity_memory_address_v.invokeExact(identity_memory_address_addr, (Addressable)sharedPoint.address()); + } + + @Benchmark + public MemoryAddress panama_identity_memory_address_confined() throws Throwable { + return (MemoryAddress) identity_memory_address_v.invokeExact(identity_memory_address_addr, (Addressable)confinedPoint.address()); + } + + @Benchmark + public MemoryAddress panama_identity_memory_address_shared_3() throws Throwable { + return (MemoryAddress) identity_memory_address_3_v.invokeExact(identity_memory_address_3_addr, (Addressable)sharedPoint.address(), (Addressable)sharedPoint.address(), (Addressable)sharedPoint.address()); + } + + @Benchmark + public MemoryAddress panama_identity_memory_address_confined_3() throws Throwable { + return (MemoryAddress) identity_memory_address_3_v.invokeExact(identity_memory_address_3_addr, (Addressable)confinedPoint.address(), (Addressable)confinedPoint.address(), (Addressable)confinedPoint.address()); + } + + @Benchmark + public MemoryAddress panama_identity_struct_ref_shared() throws Throwable { + return (MemoryAddress) identity_memory_address_v.invokeExact(identity_struct_addr, (Addressable)sharedPoint); + } + + @Benchmark + public MemoryAddress panama_identity_struct_ref_confined() throws Throwable { + return (MemoryAddress) identity_memory_address_v.invokeExact(identity_struct_addr, (Addressable)confinedPoint); + } + + @Benchmark + public MemoryAddress panama_identity_struct_ref_shared_3() throws Throwable { + return (MemoryAddress) identity_memory_address_3_v.invokeExact(identity_struct_3_addr, (Addressable)sharedPoint, (Addressable)sharedPoint, (Addressable)sharedPoint); + } + + @Benchmark + public MemoryAddress panama_identity_struct_ref_confined_3() throws Throwable { + return (MemoryAddress) identity_memory_address_3_v.invokeExact(identity_struct_3_addr, (Addressable)confinedPoint, (Addressable)confinedPoint, (Addressable)confinedPoint); + } + + @Benchmark + public int panama_identity() throws Throwable { + return (int) identity_v.invokeExact(identity_addr, 10); } @Benchmark @@ -81,8 +131,8 @@ public class CallOverheadVirtual { } @Benchmark - public MemoryAddress panama_identity_memory_address() throws Throwable { - return (MemoryAddress) identity_memory_address_v.invokeExact(identity_memory_address_addr, MemoryAddress.NULL); + public MemoryAddress panama_identity_memory_address_null() throws Throwable { + return (MemoryAddress) identity_memory_address_v.invokeExact(identity_memory_address_addr, (Addressable)MemoryAddress.NULL); } @Benchmark diff --git a/test/micro/org/openjdk/bench/jdk/incubator/foreign/JNICB.h b/test/micro/org/openjdk/bench/jdk/incubator/foreign/JNICB.h new file mode 100644 index 0000000000000000000000000000000000000000..9af5383ead7f4ee5732d47ef9088bf14ce20e99a --- /dev/null +++ b/test/micro/org/openjdk/bench/jdk/incubator/foreign/JNICB.h @@ -0,0 +1,29 @@ +/* + * 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 + +typedef struct { + jclass holder; + jmethodID mid; +} *JNICB; diff --git a/test/micro/org/openjdk/bench/jdk/incubator/foreign/JNICB.java b/test/micro/org/openjdk/bench/jdk/incubator/foreign/JNICB.java new file mode 100644 index 0000000000000000000000000000000000000000..89ead66025e35c16d948a3be89a94cd75d1376aa --- /dev/null +++ b/test/micro/org/openjdk/bench/jdk/incubator/foreign/JNICB.java @@ -0,0 +1,33 @@ +/* + * 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. + */ + +package org.openjdk.bench.jdk.incubator.foreign; + +public class JNICB { + + static { + System.loadLibrary("JNICB"); + } + + public static native long makeCB(String holder, String name, String signature); +} diff --git a/test/micro/org/openjdk/bench/jdk/incubator/foreign/LoopOverConstant.java b/test/micro/org/openjdk/bench/jdk/incubator/foreign/LoopOverConstant.java index 64cc3697687e0628170b71669686bfba3237db14..e1b1b86b61ab7cfe19598b9e88e3600a4bc4ba31 100644 --- a/test/micro/org/openjdk/bench/jdk/incubator/foreign/LoopOverConstant.java +++ b/test/micro/org/openjdk/bench/jdk/incubator/foreign/LoopOverConstant.java @@ -44,7 +44,7 @@ import java.nio.ByteOrder; import java.util.concurrent.TimeUnit; import static jdk.incubator.foreign.MemoryLayout.PathElement.sequenceElement; -import static jdk.incubator.foreign.MemoryLayouts.JAVA_INT; +import static jdk.incubator.foreign.ValueLayout.JAVA_INT; @BenchmarkMode(Mode.AverageTime) @Warmup(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS) @@ -73,7 +73,7 @@ public class LoopOverConstant { //setup native memory segment static final MemorySegment segment = MemorySegment.allocateNative(ALLOC_SIZE, ResourceScope.newImplicitScope()); - static final VarHandle VH_int = MemoryLayout.sequenceLayout(JAVA_INT).varHandle(int.class, sequenceElement()); + static final VarHandle VH_int = MemoryLayout.sequenceLayout(JAVA_INT).varHandle(sequenceElement()); static { for (int i = 0; i < ELEM_SIZE; i++) { diff --git a/test/micro/org/openjdk/bench/jdk/incubator/foreign/LoopOverNew.java b/test/micro/org/openjdk/bench/jdk/incubator/foreign/LoopOverNew.java index 0d59d83488fa6e3f44e67f635d0521d1078b7511..c50148e46e682e631079abe778f0e9d06a99b3d0 100644 --- a/test/micro/org/openjdk/bench/jdk/incubator/foreign/LoopOverNew.java +++ b/test/micro/org/openjdk/bench/jdk/incubator/foreign/LoopOverNew.java @@ -44,7 +44,7 @@ import java.nio.ByteOrder; import java.util.concurrent.TimeUnit; import static jdk.incubator.foreign.MemoryLayout.PathElement.sequenceElement; -import static jdk.incubator.foreign.MemoryLayouts.JAVA_INT; +import static jdk.incubator.foreign.ValueLayout.JAVA_INT; @BenchmarkMode(Mode.AverageTime) @Warmup(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS) @@ -61,10 +61,10 @@ public class LoopOverNew { static final int ALLOC_SIZE = ELEM_SIZE * CARRIER_SIZE; static final MemoryLayout ALLOC_LAYOUT = MemoryLayout.sequenceLayout(ELEM_SIZE, JAVA_INT); - static final VarHandle VH_int = MemoryLayout.sequenceLayout(JAVA_INT).varHandle(int.class, sequenceElement()); + static final VarHandle VH_int = MemoryLayout.sequenceLayout(JAVA_INT).varHandle(sequenceElement()); final ResourceScope scope = ResourceScope.newConfinedScope(); - final SegmentAllocator recyclingAlloc = SegmentAllocator.ofSegment(MemorySegment.allocateNative(ALLOC_LAYOUT, scope)); + final SegmentAllocator recyclingAlloc = SegmentAllocator.prefixAllocator(MemorySegment.allocateNative(ALLOC_LAYOUT, scope)); @TearDown public void tearDown() throws Throwable { diff --git a/test/micro/org/openjdk/bench/jdk/incubator/foreign/LoopOverNewHeap.java b/test/micro/org/openjdk/bench/jdk/incubator/foreign/LoopOverNewHeap.java new file mode 100644 index 0000000000000000000000000000000000000000..62677639f2f400f48142a172d8d9ce8bccf2db21 --- /dev/null +++ b/test/micro/org/openjdk/bench/jdk/incubator/foreign/LoopOverNewHeap.java @@ -0,0 +1,112 @@ +/* + * 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. + */ +package org.openjdk.bench.jdk.incubator.foreign; + +import jdk.incubator.foreign.MemoryLayout; +import jdk.incubator.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.VarHandle; +import java.nio.IntBuffer; +import java.util.concurrent.TimeUnit; + +import static jdk.incubator.foreign.MemoryLayout.PathElement.sequenceElement; +import static jdk.incubator.foreign.ValueLayout.JAVA_INT; + +@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, jvmArgsAppend = { "--add-modules=jdk.incubator.foreign" }) +public class LoopOverNewHeap { + + static final Unsafe unsafe = Utils.unsafe; + + static final int ELEM_SIZE = 1_000_000; + static final int CARRIER_SIZE = (int)JAVA_INT.byteSize(); + + static final VarHandle VH_int = MemoryLayout.sequenceLayout(JAVA_INT).varHandle(sequenceElement()); + + @Param(value = {"false", "true"}) + boolean polluteProfile; + + @Setup + public void setup() { + if (polluteProfile) { + for (int i = 0 ; i < 10000 ; i++) { + MemorySegment intB = MemorySegment.ofArray(new byte[ELEM_SIZE]); + MemorySegment intI = MemorySegment.ofArray(new int[ELEM_SIZE]); + MemorySegment intD = MemorySegment.ofArray(new double[ELEM_SIZE]); + MemorySegment intF = MemorySegment.ofArray(new float[ELEM_SIZE]); + } + } + } + + @Benchmark + public void unsafe_loop() { + int[] elems = new int[ELEM_SIZE]; + for (int i = 0; i < ELEM_SIZE; i++) { + unsafe.putInt(elems, Unsafe.ARRAY_INT_BASE_OFFSET + (i * CARRIER_SIZE) , i); + } + } + + + @Benchmark + public void segment_loop() { + MemorySegment segment = MemorySegment.ofArray(new int[ELEM_SIZE]); + for (int i = 0; i < ELEM_SIZE; i++) { + VH_int.set(segment, (long) i, i); + } + } + + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + @Benchmark + public void segment_loop_dontinline() { + MemorySegment segment = MemorySegment.ofArray(new int[ELEM_SIZE]); + for (int i = 0; i < ELEM_SIZE; i++) { + VH_int.set(segment, (long) i, i); + } + } + + @Benchmark + public void buffer_loop() { + IntBuffer buffer = IntBuffer.wrap(new int[ELEM_SIZE]); + for (int i = 0; i < ELEM_SIZE; i++) { + buffer.put(i , i); + } + } + +} diff --git a/test/micro/org/openjdk/bench/jdk/incubator/foreign/LoopOverNonConstant.java b/test/micro/org/openjdk/bench/jdk/incubator/foreign/LoopOverNonConstant.java index c4af846b6850b7087d8e47db114d089cdfd278ea..1029acf7c2e3fe360a61159e35afb0dd34ee941f 100644 --- a/test/micro/org/openjdk/bench/jdk/incubator/foreign/LoopOverNonConstant.java +++ b/test/micro/org/openjdk/bench/jdk/incubator/foreign/LoopOverNonConstant.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -22,10 +22,11 @@ */ package org.openjdk.bench.jdk.incubator.foreign; -import jdk.incubator.foreign.MemoryAccess; +import jdk.incubator.foreign.MemoryAddress; import jdk.incubator.foreign.MemoryLayout; import jdk.incubator.foreign.MemorySegment; import jdk.incubator.foreign.ResourceScope; +import jdk.incubator.foreign.ValueLayout; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Fork; @@ -44,14 +45,14 @@ import java.nio.ByteOrder; import java.util.concurrent.TimeUnit; import static jdk.incubator.foreign.MemoryLayout.PathElement.sequenceElement; -import static jdk.incubator.foreign.MemoryLayouts.JAVA_INT; +import static jdk.incubator.foreign.ValueLayout.JAVA_INT; @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, jvmArgsAppend = { "--add-modules=jdk.incubator.foreign" }) +@Fork(value = 3, jvmArgsAppend = { "--add-modules=jdk.incubator.foreign", "--enable-native-access=ALL-UNNAMED" }) public class LoopOverNonConstant { static final Unsafe unsafe = Utils.unsafe; @@ -60,7 +61,11 @@ public class LoopOverNonConstant { static final int CARRIER_SIZE = (int)JAVA_INT.byteSize(); static final int ALLOC_SIZE = ELEM_SIZE * CARRIER_SIZE; - static final VarHandle VH_int = MemoryLayout.sequenceLayout(JAVA_INT).varHandle(int.class, sequenceElement()); + static final VarHandle VH_int = MemoryLayout.sequenceLayout(JAVA_INT).varHandle(sequenceElement()); + + static final ValueLayout.OfInt JAVA_INT_ALIGNED = JAVA_INT.withBitAlignment(32); + static final VarHandle VH_int_aligned = MemoryLayout.sequenceLayout(JAVA_INT_ALIGNED).varHandle(sequenceElement()); + MemorySegment segment; long unsafe_addr; @@ -117,19 +122,66 @@ public class LoopOverNonConstant { } @Benchmark - public int segment_loop_static() { + public int segment_loop() { + int sum = 0; + for (int i = 0; i < ELEM_SIZE; i++) { + sum += (int) VH_int.get(segment, (long) i); + } + return sum; + } + + @Benchmark + public int segment_loop_aligned() { + int sum = 0; + for (int i = 0; i < ELEM_SIZE; i++) { + sum += (int) VH_int_aligned.get(segment, (long) i); + } + return sum; + } + + @Benchmark + public int segment_loop_instance() { + int sum = 0; + for (int i = 0; i < ELEM_SIZE; i++) { + sum += segment.get(JAVA_INT, i * CARRIER_SIZE); + + } + return sum; + } + + @Benchmark + public int segment_loop_instance_index() { + int sum = 0; + for (int i = 0; i < ELEM_SIZE; i++) { + sum += segment.getAtIndex(JAVA_INT, i); + + } + return sum; + } + + @Benchmark + public int segment_loop_instance_aligned() { int res = 0; for (int i = 0; i < ELEM_SIZE; i ++) { - res += MemoryAccess.getIntAtIndex(segment, i); + res += segment.get(JAVA_INT_ALIGNED, i * CARRIER_SIZE); } return res; } @Benchmark - public int segment_loop() { + public int segment_loop_instance_address() { int sum = 0; for (int i = 0; i < ELEM_SIZE; i++) { - sum += (int) VH_int.get(segment, (long) i); + sum += segment.address().get(JAVA_INT, i * CARRIER_SIZE); + } + return sum; + } + + @Benchmark + public int segment_loop_instance_address_index() { + int sum = 0; + for (int i = 0; i < ELEM_SIZE; i++) { + sum += segment.address().getAtIndex(JAVA_INT, i); } return sum; } diff --git a/test/micro/org/openjdk/bench/jdk/incubator/foreign/LoopOverNonConstantFP.java b/test/micro/org/openjdk/bench/jdk/incubator/foreign/LoopOverNonConstantFP.java index 17c8cd6b341d20acafea909200182c4b1f78b446..180c12240fa024c607841d0406a5a6abd56fe526 100644 --- a/test/micro/org/openjdk/bench/jdk/incubator/foreign/LoopOverNonConstantFP.java +++ b/test/micro/org/openjdk/bench/jdk/incubator/foreign/LoopOverNonConstantFP.java @@ -22,7 +22,6 @@ */ package org.openjdk.bench.jdk.incubator.foreign; -import jdk.incubator.foreign.MemoryAccess; import jdk.incubator.foreign.MemorySegment; import jdk.incubator.foreign.ResourceScope; import org.openjdk.jmh.annotations.Benchmark; @@ -42,7 +41,7 @@ import java.nio.ByteOrder; import java.util.concurrent.TimeUnit; import static jdk.incubator.foreign.MemoryLayout.PathElement.sequenceElement; -import static jdk.incubator.foreign.MemoryLayouts.JAVA_DOUBLE; +import static jdk.incubator.foreign.ValueLayout.JAVA_DOUBLE; @BenchmarkMode(Mode.AverageTime) @Warmup(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS) @@ -75,10 +74,10 @@ public class LoopOverNonConstantFP { segmentIn = MemorySegment.allocateNative(ALLOC_SIZE, ResourceScope.newConfinedScope()); segmentOut = MemorySegment.allocateNative(ALLOC_SIZE, ResourceScope.newConfinedScope()); for (int i = 0; i < ELEM_SIZE; i++) { - MemoryAccess.setDoubleAtIndex(segmentIn, i, i); + segmentIn.setAtIndex(JAVA_DOUBLE, i, i); } for (int i = 0; i < ELEM_SIZE; i++) { - MemoryAccess.setDoubleAtIndex(segmentOut, i, i); + segmentOut.setAtIndex(JAVA_DOUBLE, i, i); } byteBufferIn = ByteBuffer.allocateDirect(ALLOC_SIZE).order(ByteOrder.nativeOrder()); byteBufferOut = ByteBuffer.allocateDirect(ALLOC_SIZE).order(ByteOrder.nativeOrder()); @@ -112,9 +111,9 @@ public class LoopOverNonConstantFP { @Benchmark public void segment_loop() { for (int i = 0; i < ELEM_SIZE; i ++) { - MemoryAccess.setDoubleAtIndex(segmentOut, i, - MemoryAccess.getDoubleAtIndex(segmentIn, i) + - MemoryAccess.getDoubleAtIndex(segmentOut, i)); + segmentOut.setAtIndex(JAVA_DOUBLE, i, + segmentIn.getAtIndex(JAVA_DOUBLE, i) + + segmentOut.getAtIndex(JAVA_DOUBLE, i)); } } diff --git a/test/micro/org/openjdk/bench/jdk/incubator/foreign/LoopOverNonConstantHeap.java b/test/micro/org/openjdk/bench/jdk/incubator/foreign/LoopOverNonConstantHeap.java index 2b2be067fdcdec08104c65a8f5dc621737c5c448..2d6b605c2c545a5db9f3589b4cf8078cc2734f9a 100644 --- a/test/micro/org/openjdk/bench/jdk/incubator/foreign/LoopOverNonConstantHeap.java +++ b/test/micro/org/openjdk/bench/jdk/incubator/foreign/LoopOverNonConstantHeap.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -22,10 +22,10 @@ */ package org.openjdk.bench.jdk.incubator.foreign; -import jdk.incubator.foreign.MemoryAccess; import jdk.incubator.foreign.MemoryLayout; import jdk.incubator.foreign.MemorySegment; import jdk.incubator.foreign.ResourceScope; +import jdk.incubator.foreign.ValueLayout; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Fork; @@ -46,7 +46,10 @@ import java.nio.ByteOrder; import java.util.concurrent.TimeUnit; import static jdk.incubator.foreign.MemoryLayout.PathElement.sequenceElement; -import static jdk.incubator.foreign.MemoryLayouts.JAVA_INT; +import static jdk.incubator.foreign.ValueLayout.JAVA_BYTE; +import static jdk.incubator.foreign.ValueLayout.JAVA_DOUBLE; +import static jdk.incubator.foreign.ValueLayout.JAVA_FLOAT; +import static jdk.incubator.foreign.ValueLayout.JAVA_INT; @BenchmarkMode(Mode.AverageTime) @Warmup(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS) @@ -63,9 +66,15 @@ public class LoopOverNonConstantHeap { static final int ALLOC_SIZE = ELEM_SIZE * CARRIER_SIZE; static final int UNSAFE_BYTE_BASE = unsafe.arrayBaseOffset(byte[].class); - static final VarHandle VH_int = MemoryLayout.sequenceLayout(JAVA_INT).varHandle(int.class, sequenceElement()); - MemorySegment segment; + static final VarHandle VH_int = MemoryLayout.sequenceLayout(JAVA_INT).varHandle(sequenceElement()); + + static final ValueLayout.OfInt JAVA_INT_ALIGNED = JAVA_INT.withBitAlignment(32); + static final VarHandle VH_int_aligned = MemoryLayout.sequenceLayout(JAVA_INT_ALIGNED).varHandle(sequenceElement()); + static final int UNSAFE_INT_BASE = unsafe.arrayBaseOffset(int[].class); + + MemorySegment segment, alignedSegment; byte[] base; + int[] alignedBase; ByteBuffer byteBuffer; @@ -79,13 +88,13 @@ public class LoopOverNonConstantHeap { MemorySegment intI = MemorySegment.ofArray(new int[ALLOC_SIZE]); MemorySegment intD = MemorySegment.ofArray(new double[ALLOC_SIZE]); MemorySegment intF = MemorySegment.ofArray(new float[ALLOC_SIZE]); - MemorySegment s = MemorySegment.allocateNative(ALLOC_SIZE, 1, ResourceScope.newConfinedScope(Cleaner.create())); + MemorySegment s = MemorySegment.allocateNative(ALLOC_SIZE, 1, ResourceScope.newConfinedScope()); for (int i = 0; i < ALLOC_SIZE; i++) { - MemoryAccess.setByteAtOffset(intB, i, (byte)i); - MemoryAccess.setIntAtIndex(intI, i, i); - MemoryAccess.setDoubleAtIndex(intD, i, i); - MemoryAccess.setFloatAtIndex(intF, i, i); - MemoryAccess.setByteAtOffset(s, i, (byte) i); + intB.set(JAVA_BYTE, i, (byte)i); + intI.setAtIndex(JAVA_INT, i, i); + intD.setAtIndex(JAVA_DOUBLE, i, i); + intF.setAtIndex(JAVA_FLOAT, i, i); + s.set(JAVA_BYTE, i, (byte) i); } } @@ -93,7 +102,12 @@ public class LoopOverNonConstantHeap { for (int i = 0; i < ELEM_SIZE; i++) { unsafe.putInt(base, UNSAFE_BYTE_BASE + (i * CARRIER_SIZE) , i); } + alignedBase = new int[ELEM_SIZE]; + for (int i = 0; i < ELEM_SIZE; i++) { + unsafe.putInt(base, UNSAFE_INT_BASE + (i * CARRIER_SIZE) , i); + } segment = MemorySegment.ofArray(base); + alignedSegment = MemorySegment.ofArray(alignedBase); byteBuffer = ByteBuffer.wrap(base).order(ByteOrder.nativeOrder()); } @@ -134,10 +148,28 @@ public class LoopOverNonConstantHeap { } @Benchmark - public int segment_loop_static() { + public int segment_loop_aligned() { + int sum = 0; + for (int i = 0; i < ELEM_SIZE; i++) { + sum += (int) VH_int_aligned.get(alignedSegment, (long) i); + } + return sum; + } + + @Benchmark + public int segment_loop_instance() { + int res = 0; + for (int i = 0; i < ELEM_SIZE; i ++) { + res += segment.get(JAVA_INT, i * CARRIER_SIZE); + } + return res; + } + + @Benchmark + public int segment_loop_instance_aligned() { int res = 0; for (int i = 0; i < ELEM_SIZE; i ++) { - res += MemoryAccess.getIntAtIndex(segment, i); + res += alignedSegment.get(JAVA_INT_ALIGNED, i * CARRIER_SIZE); } return res; } diff --git a/test/micro/org/openjdk/bench/jdk/incubator/foreign/LoopOverNonConstantMapped.java b/test/micro/org/openjdk/bench/jdk/incubator/foreign/LoopOverNonConstantMapped.java index 11f1c1f061eb246b6c0cdddf537e5b9b3667d809..5e4e22916bf23f06876b69367b09e7c1408511c2 100644 --- a/test/micro/org/openjdk/bench/jdk/incubator/foreign/LoopOverNonConstantMapped.java +++ b/test/micro/org/openjdk/bench/jdk/incubator/foreign/LoopOverNonConstantMapped.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -22,7 +22,6 @@ */ package org.openjdk.bench.jdk.incubator.foreign; -import jdk.incubator.foreign.MemoryAccess; import jdk.incubator.foreign.MemoryLayout; import jdk.incubator.foreign.MemorySegment; import jdk.incubator.foreign.ResourceScope; @@ -51,14 +50,14 @@ import java.nio.file.StandardOpenOption; import java.util.concurrent.TimeUnit; import static jdk.incubator.foreign.MemoryLayout.PathElement.sequenceElement; -import static jdk.incubator.foreign.MemoryLayouts.JAVA_INT; +import static jdk.incubator.foreign.ValueLayout.JAVA_INT; @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, jvmArgsAppend = { "--add-modules=jdk.incubator.foreign" }) +@Fork(value = 3, jvmArgsAppend = { "--add-modules=jdk.incubator.foreign", "--enable-native-access=ALL-UNNAMED" }) public class LoopOverNonConstantMapped { static final Unsafe unsafe = Utils.unsafe; @@ -81,7 +80,7 @@ public class LoopOverNonConstantMapped { } } - static final VarHandle VH_int = MemoryLayout.sequenceLayout(JAVA_INT).varHandle(int.class, sequenceElement()); + static final VarHandle VH_int = MemoryLayout.sequenceLayout(JAVA_INT).varHandle(sequenceElement()); MemorySegment segment; long unsafe_addr; @@ -143,10 +142,19 @@ public class LoopOverNonConstantMapped { } @Benchmark - public int segment_loop_static() { + public int segment_loop_instance() { int res = 0; for (int i = 0; i < ELEM_SIZE; i ++) { - res += MemoryAccess.getIntAtIndex(segment, i); + res += segment.get(JAVA_INT, i * CARRIER_SIZE); + } + return res; + } + + @Benchmark + public int segment_loop_instance_address() { + int res = 0; + for (int i = 0; i < ELEM_SIZE; i ++) { + res += segment.address().get(JAVA_INT, i * CARRIER_SIZE); } return res; } diff --git a/test/micro/org/openjdk/bench/jdk/incubator/foreign/LoopOverNonConstantShared.java b/test/micro/org/openjdk/bench/jdk/incubator/foreign/LoopOverNonConstantShared.java index 06c6310845a728d1916e191b529ae6092006ffc2..75c64a024f9c8aa4e9ff160c1397101aa46cf95d 100644 --- a/test/micro/org/openjdk/bench/jdk/incubator/foreign/LoopOverNonConstantShared.java +++ b/test/micro/org/openjdk/bench/jdk/incubator/foreign/LoopOverNonConstantShared.java @@ -22,7 +22,6 @@ */ package org.openjdk.bench.jdk.incubator.foreign; -import jdk.incubator.foreign.MemoryAccess; import jdk.incubator.foreign.MemoryLayout; import jdk.incubator.foreign.MemorySegment; import jdk.incubator.foreign.ResourceScope; @@ -44,7 +43,7 @@ import java.nio.ByteOrder; import java.util.concurrent.TimeUnit; import static jdk.incubator.foreign.MemoryLayout.PathElement.sequenceElement; -import static jdk.incubator.foreign.MemoryLayouts.JAVA_INT; +import static jdk.incubator.foreign.ValueLayout.JAVA_INT; @BenchmarkMode(Mode.AverageTime) @Warmup(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS) @@ -60,7 +59,7 @@ public class LoopOverNonConstantShared { static final int CARRIER_SIZE = (int)JAVA_INT.byteSize(); static final int ALLOC_SIZE = ELEM_SIZE * CARRIER_SIZE; - static final VarHandle VH_int = MemoryLayout.sequenceLayout(JAVA_INT).varHandle(int.class, sequenceElement()); + static final VarHandle VH_int = MemoryLayout.sequenceLayout(JAVA_INT).varHandle(sequenceElement()); MemorySegment segment; long unsafe_addr; @@ -72,7 +71,7 @@ public class LoopOverNonConstantShared { for (int i = 0; i < ELEM_SIZE; i++) { unsafe.putInt(unsafe_addr + (i * CARRIER_SIZE) , i); } - segment = MemorySegment.allocateNative(ALLOC_SIZE, CARRIER_SIZE, ResourceScope.newSharedScope()); + segment = MemorySegment.allocateNative(ALLOC_SIZE, CARRIER_SIZE, ResourceScope.newConfinedScope()); for (int i = 0; i < ELEM_SIZE; i++) { VH_int.set(segment, (long) i, i); } @@ -117,10 +116,19 @@ public class LoopOverNonConstantShared { } @Benchmark - public int segment_loop_static() { + public int segment_loop_instance() { int res = 0; for (int i = 0; i < ELEM_SIZE; i ++) { - res += MemoryAccess.getIntAtIndex(segment, i); + res += segment.get(JAVA_INT, i * CARRIER_SIZE); + } + return res; + } + + @Benchmark + public int segment_loop_instance_address() { + int res = 0; + for (int i = 0; i < ELEM_SIZE; i ++) { + res += segment.get(JAVA_INT, i * CARRIER_SIZE); } return res; } diff --git a/test/micro/org/openjdk/bench/jdk/incubator/foreign/LoopOverPollutedBuffer.java b/test/micro/org/openjdk/bench/jdk/incubator/foreign/LoopOverPollutedBuffer.java index 3903159c4073f8ff785256ef9187d05281bf2be9..0d1c90cb987fabdf3315de5ee916e019a8110644 100644 --- a/test/micro/org/openjdk/bench/jdk/incubator/foreign/LoopOverPollutedBuffer.java +++ b/test/micro/org/openjdk/bench/jdk/incubator/foreign/LoopOverPollutedBuffer.java @@ -42,7 +42,7 @@ import java.nio.ByteOrder; import java.nio.FloatBuffer; import java.util.concurrent.TimeUnit; -import static jdk.incubator.foreign.MemoryLayouts.JAVA_INT; +import static jdk.incubator.foreign.ValueLayout.JAVA_INT; @BenchmarkMode(Mode.AverageTime) @Warmup(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS) diff --git a/test/micro/org/openjdk/bench/jdk/incubator/foreign/LoopOverPollutedSegments.java b/test/micro/org/openjdk/bench/jdk/incubator/foreign/LoopOverPollutedSegments.java index 65ae252ee322d538ba2176c064c736c333e2f40c..d2803d9d7937bbfbf531caf045f3d9496f714c8c 100644 --- a/test/micro/org/openjdk/bench/jdk/incubator/foreign/LoopOverPollutedSegments.java +++ b/test/micro/org/openjdk/bench/jdk/incubator/foreign/LoopOverPollutedSegments.java @@ -22,7 +22,6 @@ */ package org.openjdk.bench.jdk.incubator.foreign; -import jdk.incubator.foreign.MemoryAccess; import jdk.incubator.foreign.MemoryLayout; import jdk.incubator.foreign.MemorySegment; import jdk.incubator.foreign.ResourceScope; @@ -42,7 +41,8 @@ import java.lang.invoke.VarHandle; import java.util.concurrent.TimeUnit; import static jdk.incubator.foreign.MemoryLayout.PathElement.sequenceElement; -import static jdk.incubator.foreign.MemoryLayouts.JAVA_INT; +import static jdk.incubator.foreign.ValueLayout.JAVA_FLOAT; +import static jdk.incubator.foreign.ValueLayout.JAVA_INT; @BenchmarkMode(Mode.AverageTime) @Warmup(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS) @@ -58,11 +58,11 @@ public class LoopOverPollutedSegments { static final Unsafe unsafe = Utils.unsafe; - MemorySegment nativeSegment, heapSegmentBytes, heapSegmentFloats; + MemorySegment nativeSegment, nativeSharedSegment, heapSegmentBytes, heapSegmentFloats; byte[] arr; long addr; - static final VarHandle intHandle = MemoryLayout.sequenceLayout(JAVA_INT).varHandle(int.class, MemoryLayout.PathElement.sequenceElement()); + static final VarHandle intHandle = MemoryLayout.sequenceLayout(JAVA_INT).varHandle(MemoryLayout.PathElement.sequenceElement()); @Setup @@ -73,20 +73,23 @@ public class LoopOverPollutedSegments { } arr = new byte[ALLOC_SIZE]; nativeSegment = MemorySegment.allocateNative(ALLOC_SIZE, 4, ResourceScope.newConfinedScope()); + nativeSharedSegment = MemorySegment.allocateNative(ALLOC_SIZE, 4, ResourceScope.newSharedScope()); heapSegmentBytes = MemorySegment.ofArray(new byte[ALLOC_SIZE]); heapSegmentFloats = MemorySegment.ofArray(new float[ELEM_SIZE]); for (int rep = 0 ; rep < 5 ; rep++) { for (int i = 0; i < ELEM_SIZE; i++) { unsafe.putInt(arr, Unsafe.ARRAY_BYTE_BASE_OFFSET + (i * 4), i); - MemoryAccess.setIntAtIndex(nativeSegment, i, i); - MemoryAccess.setFloatAtIndex(nativeSegment, i, i); + nativeSegment.setAtIndex(JAVA_INT, i, i); + nativeSegment.setAtIndex(JAVA_FLOAT, i, i); + nativeSharedSegment.setAtIndex(JAVA_INT, i, i); + nativeSharedSegment.setAtIndex(JAVA_FLOAT, i, i); intHandle.set(nativeSegment, (long)i, i); - MemoryAccess.setIntAtIndex(heapSegmentBytes, i, i); - MemoryAccess.setFloatAtIndex(heapSegmentBytes, i, i); + heapSegmentBytes.setAtIndex(JAVA_INT, i, i); + heapSegmentBytes.setAtIndex(JAVA_FLOAT, i, i); intHandle.set(heapSegmentBytes, (long)i, i); - MemoryAccess.setIntAtIndex(heapSegmentFloats, i, i); - MemoryAccess.setFloatAtIndex(heapSegmentFloats, i, i); + heapSegmentFloats.setAtIndex(JAVA_INT, i, i); + heapSegmentFloats.setAtIndex(JAVA_FLOAT, i, i); intHandle.set(heapSegmentFloats, (long)i, i); } } @@ -113,11 +116,11 @@ public class LoopOverPollutedSegments { } @Benchmark - public int native_segment_static() { + public int native_segment_instance() { int sum = 0; for (int k = 0; k < ELEM_SIZE; k++) { - MemoryAccess.setIntAtOffset(nativeSegment, k, k + 1); - int v = MemoryAccess.getIntAtOffset(nativeSegment, k); + nativeSegment.setAtIndex(JAVA_INT, k, k + 1); + int v = nativeSegment.getAtIndex(JAVA_INT, k); sum += v; } return sum; @@ -135,11 +138,11 @@ public class LoopOverPollutedSegments { } @Benchmark - public int heap_segment_ints_static() { + public int heap_segment_ints_instance() { int sum = 0; for (int k = 0; k < ELEM_SIZE; k++) { - MemoryAccess.setIntAtOffset(heapSegmentBytes, k, k + 1); - int v = MemoryAccess.getIntAtOffset(heapSegmentBytes, k); + heapSegmentBytes.setAtIndex(JAVA_INT, k, k + 1); + int v = heapSegmentBytes.getAtIndex(JAVA_INT, k); sum += v; } return sum; @@ -157,11 +160,11 @@ public class LoopOverPollutedSegments { } @Benchmark - public int heap_segment_floats_static() { + public int heap_segment_floats_instance() { int sum = 0; for (int k = 0; k < ELEM_SIZE; k++) { - MemoryAccess.setIntAtOffset(heapSegmentFloats, k, k + 1); - int v = MemoryAccess.getIntAtOffset(heapSegmentFloats, k); + heapSegmentFloats.setAtIndex(JAVA_INT, k, k + 1); + int v = heapSegmentFloats.getAtIndex(JAVA_INT, k); sum += v; } return sum; diff --git a/test/micro/org/openjdk/bench/jdk/incubator/foreign/LoopOverSlice.java b/test/micro/org/openjdk/bench/jdk/incubator/foreign/LoopOverSlice.java new file mode 100644 index 0000000000000000000000000000000000000000..ff5000f89c920d04f2a4f6ba8835b16778d0f369 --- /dev/null +++ b/test/micro/org/openjdk/bench/jdk/incubator/foreign/LoopOverSlice.java @@ -0,0 +1,259 @@ +/* + * 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. + */ +package org.openjdk.bench.jdk.incubator.foreign; + +import jdk.incubator.foreign.MemorySegment; +import jdk.incubator.foreign.ResourceScope; +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.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.TearDown; +import org.openjdk.jmh.annotations.Warmup; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.IntBuffer; +import java.util.Iterator; +import java.util.concurrent.TimeUnit; + +import static jdk.incubator.foreign.MemoryLayout.PathElement.sequenceElement; +import static jdk.incubator.foreign.ValueLayout.JAVA_INT; + +@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, jvmArgsAppend = { "--add-modules=jdk.incubator.foreign", "--enable-native-access=ALL-UNNAMED" }) + +public class LoopOverSlice { + + static final int ELEM_SIZE = 1_000_000; + static final int CARRIER_SIZE = (int)JAVA_INT.byteSize(); + static final int ALLOC_SIZE = ELEM_SIZE * CARRIER_SIZE; + + MemorySegment nativeSegment, heapSegment; + IntBuffer nativeBuffer, heapBuffer; + ResourceScope scope; + + @Setup + public void setup() { + scope = ResourceScope.newConfinedScope(); + nativeSegment = MemorySegment.allocateNative(ALLOC_SIZE, scope); + heapSegment = MemorySegment.ofArray(new int[ELEM_SIZE]); + nativeBuffer = ByteBuffer.allocateDirect(ALLOC_SIZE).order(ByteOrder.LITTLE_ENDIAN).asIntBuffer(); + heapBuffer = IntBuffer.wrap(new int[ELEM_SIZE]); + } + + @TearDown + public void tearDown() { + scope.close(); + } + + @Benchmark + public void native_segment_slice_loop() { + new NativeSegmentWrapper(nativeSegment).forEach(NativeSegmentWrapper.Element::get); + } + + @Benchmark + public void native_buffer_slice_loop() { + new NativeBufferWrapper(nativeBuffer).forEach(NativeBufferWrapper.Element::get); + } + + @Benchmark + public void heap_segment_slice_loop() { + new HeapSegmentWrapper(heapSegment).forEach(HeapSegmentWrapper.Element::get); + } + + @Benchmark + public void heap_buffer_slice_loop() { + new HeapBufferWrapper(heapBuffer).forEach(HeapBufferWrapper.Element::get); + } + + class HeapSegmentWrapper implements Iterable { + final MemorySegment segment; + + public HeapSegmentWrapper(MemorySegment segment) { + this.segment = segment; + } + + @Override + public Iterator iterator() { + return new Iterator() { + + MemorySegment current = segment; + + @Override + public boolean hasNext() { + return current.byteSize() > 4; + } + + @Override + public Element next() { + Element element = new Element(current); + current = current.asSlice(4); + return element; + } + }; + } + + static class Element { + final MemorySegment segment; + + public Element(MemorySegment segment) { + this.segment = segment; + } + + int get() { + return segment.getAtIndex(JAVA_INT, 0); + } + } + } + + class NativeSegmentWrapper implements Iterable { + final MemorySegment segment; + + public NativeSegmentWrapper(MemorySegment segment) { + this.segment = segment; + } + + @Override + public Iterator iterator() { + return new Iterator() { + + MemorySegment current = segment; + + @Override + public boolean hasNext() { + return current.byteSize() > 4; + } + + @Override + public Element next() { + Element element = new Element(current); + current = current.asSlice(4); + return element; + } + }; + } + + static class Element { + final MemorySegment segment; + + public Element(MemorySegment segment) { + this.segment = segment; + } + + int get() { + return segment.getAtIndex(JAVA_INT, 0); + } + } + } + + class NativeBufferWrapper implements Iterable { + final IntBuffer buffer; + + public NativeBufferWrapper(IntBuffer buffer) { + this.buffer = buffer; + } + + @Override + public Iterator iterator() { + return new Iterator() { + + IntBuffer current = buffer; + + @Override + public boolean hasNext() { + return current.position() < current.limit(); + } + + @Override + public Element next() { + Element element = new Element(current); + int lim = current.limit(); + current = current.slice(1, lim - 1); + return element; + } + }; + } + + static class Element { + final IntBuffer buffer; + + public Element(IntBuffer segment) { + this.buffer = segment; + } + + int get() { + return buffer.get( 0); + } + } + } + + class HeapBufferWrapper implements Iterable { + final IntBuffer buffer; + + public HeapBufferWrapper(IntBuffer buffer) { + this.buffer = buffer; + } + + @Override + public Iterator iterator() { + return new Iterator() { + + IntBuffer current = buffer; + + @Override + public boolean hasNext() { + return current.position() < current.limit(); + } + + @Override + public Element next() { + Element element = new Element(current); + int lim = current.limit(); + current = current.slice(1, lim - 1); + return element; + } + }; + } + + static class Element { + final IntBuffer buffer; + + public Element(IntBuffer segment) { + this.buffer = segment; + } + + int get() { + return buffer.get( 0); + } + } + } +} diff --git a/test/micro/org/openjdk/bench/jdk/incubator/foreign/ParallelSum.java b/test/micro/org/openjdk/bench/jdk/incubator/foreign/ParallelSum.java index 231c606103bc0c894c5416a1c46178aff5e99fed..6ec449a1ec0364e9c01606932deb4bddf3cbc761 100644 --- a/test/micro/org/openjdk/bench/jdk/incubator/foreign/ParallelSum.java +++ b/test/micro/org/openjdk/bench/jdk/incubator/foreign/ParallelSum.java @@ -24,9 +24,9 @@ package org.openjdk.bench.jdk.incubator.foreign; import jdk.incubator.foreign.MemoryLayout; -import jdk.incubator.foreign.MemoryLayouts; import jdk.incubator.foreign.ResourceScope; import jdk.incubator.foreign.SequenceLayout; +import jdk.incubator.foreign.ValueLayout; import sun.misc.Unsafe; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; @@ -52,7 +52,7 @@ import java.util.function.Predicate; import java.util.function.ToIntFunction; import static jdk.incubator.foreign.MemoryLayout.PathElement.sequenceElement; -import static jdk.incubator.foreign.MemoryLayouts.JAVA_INT; +import static jdk.incubator.foreign.ValueLayout.JAVA_INT; @BenchmarkMode(Mode.AverageTime) @Warmup(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS) @@ -65,9 +65,9 @@ public class ParallelSum { final static int CARRIER_SIZE = 4; final static int ALLOC_SIZE = CARRIER_SIZE * 1024 * 1024 * 256; final static int ELEM_SIZE = ALLOC_SIZE / CARRIER_SIZE; - static final VarHandle VH_int = MemoryLayout.sequenceLayout(JAVA_INT).varHandle(int.class, sequenceElement()); + static final VarHandle VH_int = MemoryLayout.sequenceLayout(JAVA_INT).varHandle(sequenceElement()); - final static MemoryLayout ELEM_LAYOUT = MemoryLayouts.JAVA_INT; + final static MemoryLayout ELEM_LAYOUT = ValueLayout.JAVA_INT; final static int BULK_FACTOR = 512; final static SequenceLayout ELEM_LAYOUT_BULK = MemoryLayout.sequenceLayout(BULK_FACTOR, ELEM_LAYOUT); diff --git a/test/micro/org/openjdk/bench/jdk/incubator/foreign/QSort.java b/test/micro/org/openjdk/bench/jdk/incubator/foreign/QSort.java new file mode 100644 index 0000000000000000000000000000000000000000..04a10f8ed4e5456f1c5da44fb4066d513f913019 --- /dev/null +++ b/test/micro/org/openjdk/bench/jdk/incubator/foreign/QSort.java @@ -0,0 +1,136 @@ +/* + * 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. + */ +package org.openjdk.bench.jdk.incubator.foreign; + +import jdk.incubator.foreign.Addressable; +import jdk.incubator.foreign.CLinker; +import jdk.incubator.foreign.FunctionDescriptor; +import jdk.incubator.foreign.MemoryAddress; +import jdk.incubator.foreign.MemoryLayout; +import jdk.incubator.foreign.MemorySegment; +import jdk.incubator.foreign.NativeSymbol; +import jdk.incubator.foreign.ResourceScope; +import jdk.incubator.foreign.SymbolLookup; +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.State; +import org.openjdk.jmh.annotations.Warmup; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodType; +import java.util.concurrent.TimeUnit; + +import static java.lang.invoke.MethodHandles.lookup; +import static jdk.incubator.foreign.ValueLayout.JAVA_INT; + +@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 = { "--add-modules=jdk.incubator.foreign", "--enable-native-access=ALL-UNNAMED" }) +public class QSort extends CLayouts { + + static final CLinker abi = CLinker.systemCLinker(); + static final MethodHandle clib_qsort; + static final NativeSymbol native_compar; + static final NativeSymbol panama_upcall_compar; + static final long jni_upcall_compar; + + static final int[] INPUT = { 5, 3, 2, 7, 8, 12, 1, 7 }; + static final MemorySegment INPUT_SEGMENT; + + static NativeSymbol qsort_addr = abi.lookup("qsort").get(); + + static { + INPUT_SEGMENT = MemorySegment.allocateNative(MemoryLayout.sequenceLayout(INPUT.length, JAVA_INT), ResourceScope.globalScope()); + INPUT_SEGMENT.copyFrom(MemorySegment.ofArray(INPUT)); + + System.loadLibrary("QSortJNI"); + jni_upcall_compar = JNICB.makeCB("org/openjdk/bench/jdk/incubator/foreign/QSort", "jni_upcall_compar", "(II)I"); + + try { + clib_qsort = abi.downcallHandle( + qsort_addr, + FunctionDescriptor.ofVoid(C_POINTER, C_LONG_LONG, C_LONG_LONG, C_POINTER) + ); + System.loadLibrary("QSort"); + native_compar = SymbolLookup.loaderLookup().lookup("compar").orElseThrow(); + panama_upcall_compar = abi.upcallStub( + lookup().findStatic(QSort.class, + "panama_upcall_compar", + MethodType.methodType(int.class, MemoryAddress.class, MemoryAddress.class)), + FunctionDescriptor.of(C_INT, C_POINTER, C_POINTER), + ResourceScope.globalScope() + ); + } catch (ReflectiveOperationException e) { + throw new BootstrapMethodError(e); + } + } + + static native void jni_qsort_optimized(int[] array, long cb); + static native void jni_qsort_naive(int[] array); + + @FunctionalInterface + interface JNIComparator { + int cmp(int e0, int e1); + } + + static final JNIComparator COMP = QSort::jni_upcall_compar; + + @Benchmark + public void native_qsort() throws Throwable { + clib_qsort.invokeExact((Addressable)INPUT_SEGMENT, (long) INPUT.length, JAVA_INT.byteSize(), (Addressable)native_compar); + } + + @Benchmark + public void jni_upcall_qsort_optimized() { + jni_qsort_optimized(INPUT, jni_upcall_compar); + } + + @Benchmark + public void jni_upcall_qsort_naive() { + jni_qsort_naive(INPUT); + } + + @Benchmark + public void panama_upcall_qsort() throws Throwable { + clib_qsort.invokeExact((Addressable)INPUT_SEGMENT, (long) INPUT.length, JAVA_INT.byteSize(), (Addressable)panama_upcall_compar); + } + + private static int getIntAbsolute(MemoryAddress addr) { + return addr.get(JAVA_INT, 0); + } + + static int panama_upcall_compar(MemoryAddress e0, MemoryAddress e1) { + return Integer.compare(getIntAbsolute(e0), getIntAbsolute(e1)); + } + + static int jni_upcall_compar(int j0, int j1) { + return Integer.compare(j0, j1); + } +} diff --git a/test/micro/org/openjdk/bench/jdk/incubator/foreign/StrLenTest.java b/test/micro/org/openjdk/bench/jdk/incubator/foreign/StrLenTest.java index ec4da5ffc8875d21a611906786aa16f0ca44f763..ec7d58cf823df27b8b706af1ab2e9b0482bcefe9 100644 --- a/test/micro/org/openjdk/bench/jdk/incubator/foreign/StrLenTest.java +++ b/test/micro/org/openjdk/bench/jdk/incubator/foreign/StrLenTest.java @@ -25,9 +25,9 @@ package org.openjdk.bench.jdk.incubator.foreign; +import jdk.incubator.foreign.Addressable; import jdk.incubator.foreign.CLinker; import jdk.incubator.foreign.FunctionDescriptor; -import jdk.incubator.foreign.MemoryAccess; import jdk.incubator.foreign.MemoryAddress; import jdk.incubator.foreign.MemorySegment; import jdk.incubator.foreign.ResourceScope; @@ -45,10 +45,9 @@ import org.openjdk.jmh.annotations.State; import org.openjdk.jmh.annotations.Warmup; import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodType; import java.util.concurrent.TimeUnit; -import static jdk.incubator.foreign.CLinker.*; +import static jdk.incubator.foreign.ValueLayout.JAVA_BYTE; @BenchmarkMode(Mode.AverageTime) @Warmup(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS) @@ -56,12 +55,12 @@ import static jdk.incubator.foreign.CLinker.*; @State(org.openjdk.jmh.annotations.Scope.Thread) @OutputTimeUnit(TimeUnit.NANOSECONDS) @Fork(value = 3, jvmArgsAppend = { "--add-modules=jdk.incubator.foreign", "--enable-native-access=ALL-UNNAMED" }) -public class StrLenTest { +public class StrLenTest extends CLayouts { - ResourceScope scope = ResourceScope.newConfinedScope(); + ResourceScope scope = ResourceScope.newImplicitScope(); SegmentAllocator segmentAllocator; - SegmentAllocator arenaAllocator = SegmentAllocator.arenaAllocator(scope); + SegmentAllocator arenaAllocator = SegmentAllocator.newNativeArena(scope); @Param({"5", "20", "100"}) public int size; @@ -72,31 +71,17 @@ public class StrLenTest { } static final MethodHandle STRLEN; - static final MethodHandle STRLEN_TRIVIAL; - static final MethodHandle MALLOC_TRIVIAL; - static final MethodHandle FREE_TRIVIAL; static { - CLinker abi = CLinker.getInstance(); - STRLEN = abi.downcallHandle(CLinker.systemLookup().lookup("strlen").get(), - MethodType.methodType(int.class, MemoryAddress.class), + CLinker abi = CLinker.systemCLinker(); + STRLEN = abi.downcallHandle(abi.lookup("strlen").get(), FunctionDescriptor.of(C_INT, C_POINTER)); - STRLEN_TRIVIAL = abi.downcallHandle(CLinker.systemLookup().lookup("strlen").get(), - MethodType.methodType(int.class, MemoryAddress.class), - FunctionDescriptor.of(C_INT, C_POINTER).withAttribute(FunctionDescriptor.TRIVIAL_ATTRIBUTE_NAME, true)); - MALLOC_TRIVIAL = abi.downcallHandle(CLinker.systemLookup().lookup("malloc").get(), - MethodType.methodType(MemoryAddress.class, long.class), - FunctionDescriptor.of(C_POINTER, C_LONG_LONG).withAttribute(FunctionDescriptor.TRIVIAL_ATTRIBUTE_NAME, true)); - - FREE_TRIVIAL = abi.downcallHandle(CLinker.systemLookup().lookup("free").get(), - MethodType.methodType(void.class, MemoryAddress.class), - FunctionDescriptor.ofVoid(C_POINTER).withAttribute(FunctionDescriptor.TRIVIAL_ATTRIBUTE_NAME, true)); } @Setup public void setup() { str = makeString(size); - segmentAllocator = SegmentAllocator.ofSegment(MemorySegment.allocateNative(size + 1, ResourceScope.newImplicitScope())); + segmentAllocator = SegmentAllocator.prefixAllocator(MemorySegment.allocateNative(size + 1, ResourceScope.newConfinedScope())); } @TearDown @@ -112,54 +97,37 @@ public class StrLenTest { @Benchmark public int panama_strlen() throws Throwable { try (ResourceScope scope = ResourceScope.newConfinedScope()) { - MemorySegment segment = CLinker.toCString(str, scope); - return (int)STRLEN.invokeExact(segment.address()); + MemorySegment segment = MemorySegment.allocateNative(str.length() + 1, scope); + segment.setUtf8String(0, str); + return (int)STRLEN.invokeExact((Addressable)segment); } } @Benchmark public int panama_strlen_arena() throws Throwable { - return (int)STRLEN.invokeExact(CLinker.toCString(str, arenaAllocator).address()); + return (int)STRLEN.invokeExact((Addressable)arenaAllocator.allocateUtf8String(str)); } @Benchmark public int panama_strlen_prefix() throws Throwable { - return (int)STRLEN.invokeExact(CLinker.toCString(str, segmentAllocator).address()); + return (int)STRLEN.invokeExact((Addressable)segmentAllocator.allocateUtf8String(str)); } @Benchmark public int panama_strlen_unsafe() throws Throwable { MemoryAddress address = makeStringUnsafe(str); - int res = (int) STRLEN.invokeExact(address); - CLinker.freeMemory(address); - return res; - } - - @Benchmark - public int panama_strlen_unsafe_trivial() throws Throwable { - MemoryAddress address = makeStringUnsafeTrivial(str); - int res = (int) STRLEN_TRIVIAL.invokeExact(address); - FREE_TRIVIAL.invokeExact(address); + int res = (int) STRLEN.invokeExact((Addressable)address); + freeMemory(address); return res; } static MemoryAddress makeStringUnsafe(String s) { byte[] bytes = s.getBytes(); int len = bytes.length; - MemoryAddress address = CLinker.allocateMemory(len + 1); - MemorySegment str = address.asSegment(len + 1, ResourceScope.globalScope()); - str.copyFrom(MemorySegment.ofArray(bytes)); - MemoryAccess.setByteAtOffset(str, len, (byte)0); - return address; - } - - static MemoryAddress makeStringUnsafeTrivial(String s) throws Throwable { - byte[] bytes = s.getBytes(); - int len = bytes.length; - MemoryAddress address = (MemoryAddress)MALLOC_TRIVIAL.invokeExact((long)len + 1); - MemorySegment str = address.asSegment(len + 1, ResourceScope.globalScope()); + MemoryAddress address = allocateMemory(len + 1); + MemorySegment str = MemorySegment.ofAddress(address, len + 1, ResourceScope.globalScope()); str.copyFrom(MemorySegment.ofArray(bytes)); - MemoryAccess.setByteAtOffset(str, len, (byte)0); + str.set(JAVA_BYTE, len, (byte)0); return address; } diff --git a/test/micro/org/openjdk/bench/jdk/incubator/foreign/TestAdaptVarHandles.java b/test/micro/org/openjdk/bench/jdk/incubator/foreign/TestAdaptVarHandles.java index f8f482b3a284879ac2c6bd80dbb82b33be34cd75..4540b5907826b749731774cd691b275aada8165c 100644 --- a/test/micro/org/openjdk/bench/jdk/incubator/foreign/TestAdaptVarHandles.java +++ b/test/micro/org/openjdk/bench/jdk/incubator/foreign/TestAdaptVarHandles.java @@ -26,8 +26,8 @@ package org.openjdk.bench.jdk.incubator.foreign; import jdk.incubator.foreign.MemoryHandles; import jdk.incubator.foreign.MemoryLayout; -import jdk.incubator.foreign.MemoryLayouts; import jdk.incubator.foreign.MemorySegment; +import jdk.incubator.foreign.ValueLayout; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Fork; @@ -85,8 +85,8 @@ public class TestAdaptVarHandles { static final VarHandle VH_box_int = MemoryHandles.filterValue(VH_int, INTBOX_TO_INT, INT_TO_INTBOX); - static final VarHandle VH_addr_int = MemoryLayout.sequenceLayout(MemoryLayouts.JAVA_INT) - .varHandle(int.class, MemoryLayout.PathElement.sequenceElement()); + static final VarHandle VH_addr_int = MemoryLayout.sequenceLayout(ValueLayout.JAVA_INT) + .varHandle(MemoryLayout.PathElement.sequenceElement()); static final VarHandle VH_addr_box_int = MemoryHandles.filterValue(VH_addr_int, INTBOX_TO_INT, INT_TO_INTBOX); diff --git a/test/micro/org/openjdk/bench/jdk/incubator/foreign/TestLoadBytes.java b/test/micro/org/openjdk/bench/jdk/incubator/foreign/TestLoadBytes.java index 45c170b8dd359309488df69088482f3b52b17e09..6288c49cf92af34b925b78b1f93c5d0cd882ed5e 100644 --- a/test/micro/org/openjdk/bench/jdk/incubator/foreign/TestLoadBytes.java +++ b/test/micro/org/openjdk/bench/jdk/incubator/foreign/TestLoadBytes.java @@ -23,14 +23,8 @@ package org.openjdk.bench.jdk.incubator.foreign; -import jdk.incubator.foreign.CLinker; -import jdk.incubator.foreign.MemoryAccess; -import jdk.incubator.foreign.MemoryAddress; import jdk.incubator.foreign.MemorySegment; import jdk.incubator.foreign.ResourceScope; -import jdk.incubator.vector.ByteVector; -import jdk.incubator.vector.IntVector; -import jdk.incubator.vector.VectorSpecies; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.CompilerControl; @@ -44,9 +38,10 @@ import org.openjdk.jmh.annotations.State; import org.openjdk.jmh.annotations.Warmup; import java.nio.ByteBuffer; -import java.nio.ByteOrder; import java.util.concurrent.TimeUnit; +import static jdk.incubator.foreign.ValueLayout.JAVA_BYTE; + @BenchmarkMode(Mode.AverageTime) @Warmup(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS) @Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS) @@ -119,7 +114,7 @@ public class TestLoadBytes { public int segmentNativeScalar() { int size = 0; for (int i = 0; i < srcArray.length; i++) { - var v = MemoryAccess.getByteAtOffset(srcSegmentImplicit, i); + var v = srcSegmentImplicit.get(JAVA_BYTE, i); size += v; } return size; @@ -129,7 +124,7 @@ public class TestLoadBytes { public int segmentNativeScalarConst() { int size = 0; for (int i = 0; i < 1024; i++) { - var v = MemoryAccess.getByteAtOffset(srcSegmentImplicit, i); + var v = srcSegmentImplicit.get(JAVA_BYTE, i); size += v; } return size; diff --git a/test/micro/org/openjdk/bench/jdk/incubator/foreign/UnrolledAccess.java b/test/micro/org/openjdk/bench/jdk/incubator/foreign/UnrolledAccess.java index 614ff42b8f474d2f0305b68e71ce4db3d5f4e2c5..ea72c01f7b941b1fb11d7f0e9009c0fe230e8764 100644 --- a/test/micro/org/openjdk/bench/jdk/incubator/foreign/UnrolledAccess.java +++ b/test/micro/org/openjdk/bench/jdk/incubator/foreign/UnrolledAccess.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -23,7 +23,6 @@ package org.openjdk.bench.jdk.incubator.foreign; -import static jdk.incubator.foreign.MemoryAccess.*; import jdk.incubator.foreign.*; import org.openjdk.jmh.annotations.*; import org.openjdk.jmh.runner.Runner; @@ -34,20 +33,22 @@ import java.util.concurrent.TimeUnit; import java.lang.invoke.VarHandle; +import static jdk.incubator.foreign.ValueLayout.JAVA_LONG; + @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.MICROSECONDS) -@Fork(3) +@Fork(value = 3, jvmArgsAppend = { "--enable-native-access=ALL-UNNAMED" }) public class UnrolledAccess { static final Unsafe U = Utils.unsafe; final static int SIZE = 1024; - static final VarHandle LONG_HANDLE = MemoryLayout.sequenceLayout(SIZE, MemoryLayouts.JAVA_LONG) - .varHandle(long.class, MemoryLayout.PathElement.sequenceElement()); + static final VarHandle LONG_HANDLE = MemoryLayout.sequenceLayout(SIZE, JAVA_LONG) + .varHandle(MemoryLayout.PathElement.sequenceElement()); @State(Scope.Benchmark) public static class Data { @@ -65,8 +66,8 @@ public class UnrolledAccess { this.outputArray = new double[SIZE]; this.inputAddress = U.allocateMemory(8 * SIZE); this.outputAddress = U.allocateMemory(8 * SIZE); - this.inputSegment = MemoryAddress.ofLong(inputAddress).asSegment(8*SIZE, ResourceScope.globalScope()); - this.outputSegment = MemoryAddress.ofLong(outputAddress).asSegment(8*SIZE, ResourceScope.globalScope()); + this.inputSegment = MemorySegment.ofAddress(MemoryAddress.ofLong(inputAddress), 8*SIZE, ResourceScope.globalScope()); + this.outputSegment = MemorySegment.ofAddress(MemoryAddress.ofLong(outputAddress), 8*SIZE, ResourceScope.globalScope()); } } @@ -96,15 +97,15 @@ public class UnrolledAccess { } @Benchmark - public void static_handle_loop(Data state) { + public void handle_loop_instance(Data state) { final MemorySegment is = state.inputSegment; final MemorySegment os = state.outputSegment; for(int i = 0; i < SIZE; i+=4) { - setLongAtIndex(os, i,getLongAtIndex(is, i) + MemoryAccess.getLongAtIndex(os, i)); - setLongAtIndex(os, i+1,getLongAtIndex(is, i+1) + getLongAtIndex(os, i+1)); - setLongAtIndex(os, i+2,getLongAtIndex(is, i+2) + getLongAtIndex(os, i+2)); - setLongAtIndex(os, i+3,getLongAtIndex(is, i+3) + getLongAtIndex(os, i+3)); + os.setAtIndex(JAVA_LONG, i, is.getAtIndex(JAVA_LONG, i) + os.get(JAVA_LONG, i)); + os.setAtIndex(JAVA_LONG, i+1, is.getAtIndex(JAVA_LONG, i+1) + os.get(JAVA_LONG, i+1)); + os.setAtIndex(JAVA_LONG, i+2, is.getAtIndex(JAVA_LONG, i+2) + os.get(JAVA_LONG, i+2)); + os.setAtIndex(JAVA_LONG, i+3, is.getAtIndex(JAVA_LONG, i+3) + os.get(JAVA_LONG, i+3)); } } } diff --git a/test/micro/org/openjdk/bench/jdk/incubator/foreign/Upcalls.java b/test/micro/org/openjdk/bench/jdk/incubator/foreign/Upcalls.java index a25f4f9ae9fed4ade885a7f4ad62f5543bf4829f..06a25c4ab3a0bffc0608906aa578d310bcb14455 100644 --- a/test/micro/org/openjdk/bench/jdk/incubator/foreign/Upcalls.java +++ b/test/micro/org/openjdk/bench/jdk/incubator/foreign/Upcalls.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -22,9 +22,10 @@ */ package org.openjdk.bench.jdk.incubator.foreign; -import jdk.incubator.foreign.FunctionDescriptor; -import jdk.incubator.foreign.MemoryAddress; +import jdk.incubator.foreign.Addressable; import jdk.incubator.foreign.CLinker; +import jdk.incubator.foreign.FunctionDescriptor; +import jdk.incubator.foreign.NativeSymbol; import jdk.incubator.foreign.ResourceScope; import jdk.incubator.foreign.SymbolLookup; import org.openjdk.jmh.annotations.Benchmark; @@ -41,10 +42,6 @@ import java.lang.invoke.MethodType; import java.util.concurrent.TimeUnit; import static java.lang.invoke.MethodHandles.lookup; -import static jdk.incubator.foreign.CLinker.C_DOUBLE; -import static jdk.incubator.foreign.CLinker.C_INT; -import static jdk.incubator.foreign.CLinker.C_LONG_LONG; -import static jdk.incubator.foreign.CLinker.C_POINTER; @BenchmarkMode(Mode.AverageTime) @Warmup(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS) @@ -52,18 +49,18 @@ import static jdk.incubator.foreign.CLinker.C_POINTER; @State(org.openjdk.jmh.annotations.Scope.Thread) @OutputTimeUnit(TimeUnit.NANOSECONDS) @Fork(value = 3, jvmArgsAppend = { "--add-modules=jdk.incubator.foreign", "--enable-native-access=ALL-UNNAMED" }) -public class Upcalls { +public class Upcalls extends CLayouts { - static final CLinker abi = CLinker.getInstance(); + static final CLinker abi = CLinker.systemCLinker(); static final MethodHandle blank; static final MethodHandle identity; static final MethodHandle args5; static final MethodHandle args10; - static final MemoryAddress cb_blank; - static final MemoryAddress cb_identity; - static final MemoryAddress cb_args5; - static final MemoryAddress cb_args10; + static final NativeSymbol cb_blank; + static final NativeSymbol cb_identity; + static final NativeSymbol cb_args5; + static final NativeSymbol cb_args10; static final long cb_blank_jni; static final long cb_identity_jni; @@ -74,10 +71,10 @@ public class Upcalls { System.loadLibrary("UpcallsJNI"); String className = "org/openjdk/bench/jdk/incubator/foreign/Upcalls"; - cb_blank_jni = makeCB(className, "blank", "()V"); - cb_identity_jni = makeCB(className, "identity", "(I)I"); - cb_args5_jni = makeCB(className, "args5", "(JDJDJ)V"); - cb_args10_jni = makeCB(className, "args10", "(JDJDJDJDJD)V"); + cb_blank_jni = JNICB.makeCB(className, "blank", "()V"); + cb_identity_jni = JNICB.makeCB(className, "identity", "(I)I"); + cb_args5_jni = JNICB.makeCB(className, "args5", "(JDJDJ)V"); + cb_args10_jni = JNICB.makeCB(className, "args10", "(JDJDJDJDJD)V"); try { System.loadLibrary("Upcalls"); @@ -86,7 +83,7 @@ public class Upcalls { MethodType mt = MethodType.methodType(void.class); FunctionDescriptor fd = FunctionDescriptor.ofVoid(); - blank = linkFunc(name, mt, fd); + blank = linkFunc(name, fd); cb_blank = makeCB(name, mt, fd); } { @@ -94,7 +91,7 @@ public class Upcalls { MethodType mt = MethodType.methodType(int.class, int.class); FunctionDescriptor fd = FunctionDescriptor.of(C_INT, C_INT); - identity = linkFunc(name, mt, fd); + identity = linkFunc(name, fd); cb_identity = makeCB(name, mt, fd); } { @@ -104,7 +101,7 @@ public class Upcalls { FunctionDescriptor fd = FunctionDescriptor.ofVoid( C_LONG_LONG, C_DOUBLE, C_LONG_LONG, C_DOUBLE, C_LONG_LONG); - args5 = linkFunc(name, mt, fd); + args5 = linkFunc(name, fd); cb_args5 = makeCB(name, mt, fd); } { @@ -116,7 +113,7 @@ public class Upcalls { C_LONG_LONG, C_DOUBLE, C_LONG_LONG, C_DOUBLE, C_LONG_LONG, C_DOUBLE, C_LONG_LONG, C_DOUBLE, C_LONG_LONG, C_DOUBLE); - args10 = linkFunc(name, mt, fd); + args10 = linkFunc(name, fd); cb_args10 = makeCB(name, mt, fd); } } catch (ReflectiveOperationException e) { @@ -124,19 +121,18 @@ public class Upcalls { } } - static MethodHandle linkFunc(String name, MethodType baseType, FunctionDescriptor baseDesc) { + static MethodHandle linkFunc(String name, FunctionDescriptor baseDesc) { return abi.downcallHandle( SymbolLookup.loaderLookup().lookup(name).orElseThrow(), - baseType.insertParameterTypes(baseType.parameterCount(), MemoryAddress.class), - baseDesc.withAppendedArgumentLayouts(C_POINTER) + baseDesc.appendArgumentLayouts(C_POINTER) ); } - static MemoryAddress makeCB(String name, MethodType mt, FunctionDescriptor fd) throws ReflectiveOperationException { + static NativeSymbol makeCB(String name, MethodType mt, FunctionDescriptor fd) throws ReflectiveOperationException { return abi.upcallStub( lookup().findStatic(Upcalls.class, name, mt), fd, ResourceScope.globalScope() - ).address(); + ); } static native void blank(long cb); @@ -144,7 +140,6 @@ public class Upcalls { static native void args5(long a0, double a1, long a2, double a3, long a4, long cb); static native void args10(long a0, double a1, long a2, double a3, long a4, double a5, long a6, double a7, long a8, double a9, long cb); - static native long makeCB(String holder, String name, String signature); @Benchmark public void jni_blank() throws Throwable { @@ -153,7 +148,7 @@ public class Upcalls { @Benchmark public void panama_blank() throws Throwable { - blank.invokeExact(cb_blank); + blank.invokeExact((Addressable)cb_blank); } @Benchmark @@ -173,17 +168,17 @@ public class Upcalls { @Benchmark public int panama_identity() throws Throwable { - return (int) identity.invokeExact(10, cb_identity); + return (int) identity.invokeExact(10, (Addressable)cb_identity); } @Benchmark public void panama_args5() throws Throwable { - args5.invokeExact(1L, 2D, 3L, 4D, 5L, cb_args5); + args5.invokeExact(1L, 2D, 3L, 4D, 5L, (Addressable)cb_args5); } @Benchmark public void panama_args10() throws Throwable { - args10.invokeExact(1L, 2D, 3L, 4D, 5L, 6D, 7L, 8D, 9L, 10D, cb_args10); + args10.invokeExact(1L, 2D, 3L, 4D, 5L, 6D, 7L, 8D, 9L, 10D, (Addressable)cb_args10); } static void blank() {} diff --git a/test/micro/org/openjdk/bench/jdk/incubator/foreign/VaList.java b/test/micro/org/openjdk/bench/jdk/incubator/foreign/VaList.java index 34d74652cadd68cca0e16c31328cc5214c7b5421..d904c79a73401eb393ded730a9c65329ba3b67ed 100644 --- a/test/micro/org/openjdk/bench/jdk/incubator/foreign/VaList.java +++ b/test/micro/org/openjdk/bench/jdk/incubator/foreign/VaList.java @@ -22,8 +22,10 @@ */ package org.openjdk.bench.jdk.incubator.foreign; -import jdk.incubator.foreign.FunctionDescriptor; +import jdk.incubator.foreign.Addressable; import jdk.incubator.foreign.CLinker; +import jdk.incubator.foreign.FunctionDescriptor; +import jdk.incubator.foreign.MemoryAddress; import jdk.incubator.foreign.SymbolLookup; import jdk.incubator.foreign.ResourceScope; import org.openjdk.jmh.annotations.Benchmark; @@ -36,24 +38,17 @@ import org.openjdk.jmh.annotations.State; import org.openjdk.jmh.annotations.Warmup; import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodType; import java.util.concurrent.TimeUnit; -import static jdk.incubator.foreign.CLinker.C_DOUBLE; -import static jdk.incubator.foreign.CLinker.C_INT; -import static jdk.incubator.foreign.CLinker.C_LONG_LONG; -import static jdk.incubator.foreign.CLinker.C_VA_LIST; -import static jdk.incubator.foreign.CLinker.asVarArg; - @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 = { "--add-modules=jdk.incubator.foreign", "--enable-native-access=ALL-UNNAMED" }) -public class VaList { +public class VaList extends CLayouts { - static final CLinker linker = CLinker.getInstance(); + static final CLinker linker = CLinker.systemCLinker(); static { System.loadLibrary("VaList"); } @@ -64,11 +59,9 @@ public class VaList { static { SymbolLookup lookup = SymbolLookup.loaderLookup(); MH_ellipsis = linker.downcallHandle(lookup.lookup("ellipsis").get(), - MethodType.methodType(void.class, int.class, int.class, double.class, long.class), - FunctionDescriptor.ofVoid(C_INT, asVarArg(C_INT), asVarArg(C_DOUBLE), asVarArg(C_LONG_LONG))); + FunctionDescriptor.ofVoid(C_INT).asVariadic(C_INT, C_DOUBLE, C_LONG_LONG)); MH_vaList = linker.downcallHandle(lookup.lookup("vaList").get(), - MethodType.methodType(void.class, int.class, CLinker.VaList.class), - FunctionDescriptor.ofVoid(C_INT, C_VA_LIST)); + FunctionDescriptor.ofVoid(C_INT, C_POINTER)); } @Benchmark @@ -80,12 +73,12 @@ public class VaList { @Benchmark public void vaList() throws Throwable { try (ResourceScope scope = ResourceScope.newConfinedScope()) { - CLinker.VaList vaList = CLinker.VaList.make(b -> - b.vargFromInt(C_INT, 1) - .vargFromDouble(C_DOUBLE, 2D) - .vargFromLong(C_LONG_LONG, 3L), scope); + jdk.incubator.foreign.VaList vaList = jdk.incubator.foreign.VaList.make(b -> + b.addVarg(C_INT, 1) + .addVarg(C_DOUBLE, 2D) + .addVarg(C_LONG_LONG, 3L), scope); MH_vaList.invokeExact(3, - vaList); + (Addressable)vaList); } } } diff --git a/test/micro/org/openjdk/bench/jdk/incubator/foreign/VarHandleExact.java b/test/micro/org/openjdk/bench/jdk/incubator/foreign/VarHandleExact.java index d560765c48c1e5f804c7e848714261f920674f88..0cb783473df67ab6e5ae206fc29ec3fcde7fefa9 100644 --- a/test/micro/org/openjdk/bench/jdk/incubator/foreign/VarHandleExact.java +++ b/test/micro/org/openjdk/bench/jdk/incubator/foreign/VarHandleExact.java @@ -40,7 +40,7 @@ import java.lang.invoke.VarHandle; import java.nio.ByteOrder; import java.util.concurrent.TimeUnit; -import static jdk.incubator.foreign.MemoryLayouts.JAVA_INT; +import static jdk.incubator.foreign.ValueLayout.JAVA_INT; @BenchmarkMode(Mode.AverageTime) @Warmup(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS) @@ -54,7 +54,7 @@ public class VarHandleExact { static final VarHandle generic; static { - generic = MemoryHandles.varHandle(int.class, ByteOrder.nativeOrder()); + generic = MemoryHandles.varHandle(JAVA_INT); exact = generic.withInvokeExactBehavior(); } diff --git a/test/micro/org/openjdk/bench/jdk/incubator/foreign/libCallOverhead.c b/test/micro/org/openjdk/bench/jdk/incubator/foreign/libCallOverhead.c index f42aec0172c4e602e6a12d24ad489f34064826bb..8ad44f58cec4937617ca70f813959af9959d1ea2 100644 --- a/test/micro/org/openjdk/bench/jdk/incubator/foreign/libCallOverhead.c +++ b/test/micro/org/openjdk/bench/jdk/incubator/foreign/libCallOverhead.c @@ -34,18 +34,26 @@ EXPORT int identity(int x) { } typedef struct { - long long x; - long long y; + int x; + int y; } Point; EXPORT Point identity_struct(Point p) { return p; } +EXPORT Point identity_struct_3(Point p1, Point p2, Point p3) { + return p1; +} + EXPORT void* identity_memory_address(void* p) { return p; } +EXPORT void* identity_memory_address_3(void* p1, void* p2, void* p3) { + return p1; +} + EXPORT void args1(long long a0) {} EXPORT void args2(long long a0, double a1) {} EXPORT void args3(long long a0, double a1, long long a2) {} diff --git a/test/micro/org/openjdk/bench/jdk/incubator/foreign/libJNICB.c b/test/micro/org/openjdk/bench/jdk/incubator/foreign/libJNICB.c new file mode 100644 index 0000000000000000000000000000000000000000..617d16d29dd96d62c820c661d20400e2a23f3712 --- /dev/null +++ b/test/micro/org/openjdk/bench/jdk/incubator/foreign/libJNICB.c @@ -0,0 +1,62 @@ +/* + * 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 +#include + +#include "JNICB.h" +#include "jlong.h" + +#define CHECK_NULL(thing, message) \ + if (thing == NULL) { \ + jclass cls = (*env)->FindClass(env, "java/lang/Exception"); \ + (*env)->ThrowNew(env, cls, message); \ + return 0; \ + } + +JNIEXPORT jlong JNICALL Java_org_openjdk_bench_jdk_incubator_foreign_JNICB_makeCB + (JNIEnv *env, jclass cls, jstring holderName, jstring methodName, jstring descriptor) { + + const char* holderNameC = (*env)->GetStringUTFChars(env, holderName, NULL); + const char* methodNameC = (*env)->GetStringUTFChars(env, methodName, NULL); + const char* descriptorC = (*env)->GetStringUTFChars(env, descriptor, NULL); + + JNICB cb = malloc(sizeof *cb); + CHECK_NULL(cb, "Can not allocate cb"); + + jclass holder = (*env)->FindClass(env, holderNameC); + CHECK_NULL(holder, "Can not find class"); + holder = (jclass) (*env)->NewGlobalRef(env, holder); + cb->holder = holder; + + jmethodID methodID = (*env)->GetStaticMethodID(env, holder, methodNameC, descriptorC); + CHECK_NULL(methodID, "Can not find method"); + //methodID = (jmethodID) (*env)->NewGlobalRef(env, methodID); // DON'T DO THIS! -> Crashes GC + cb->mid = methodID; + + (*env)->ReleaseStringUTFChars(env, holderName, holderNameC); + (*env)->ReleaseStringUTFChars(env, methodName, methodNameC); + (*env)->ReleaseStringUTFChars(env, descriptor, descriptorC); + + return ptr_to_jlong(cb); +} diff --git a/test/micro/org/openjdk/bench/jdk/incubator/foreign/libQSort.c b/test/micro/org/openjdk/bench/jdk/incubator/foreign/libQSort.c new file mode 100644 index 0000000000000000000000000000000000000000..cafb83d8708c85fb83f6896aae4bc754afc2211d --- /dev/null +++ b/test/micro/org/openjdk/bench/jdk/incubator/foreign/libQSort.c @@ -0,0 +1,35 @@ +/* + * 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. + */ + +#ifdef _WIN64 +#define EXPORT __declspec(dllexport) +#else +#define EXPORT +#endif + + +EXPORT int compar(const void* e0, const void* e1) { + int i0 = *((int*) e0); + int i1 = *((int*) e1); + return i0 - i1; +} diff --git a/test/micro/org/openjdk/bench/jdk/incubator/foreign/libQSortJNI.c b/test/micro/org/openjdk/bench/jdk/incubator/foreign/libQSortJNI.c new file mode 100644 index 0000000000000000000000000000000000000000..f6fe1b0c5d1a3f02f2a8aba2a49a1c99b3f28850 --- /dev/null +++ b/test/micro/org/openjdk/bench/jdk/incubator/foreign/libQSortJNI.c @@ -0,0 +1,89 @@ +/* + * 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 + +#include + +#include "jlong.h" +#include "JNICB.h" + +#ifdef _WIN64 +#define THREAD_LOCAL __declspec(thread) +#else +#define THREAD_LOCAL __thread +#endif + +THREAD_LOCAL struct { + JNICB cb; + JNIEnv* env; +} ctx_opt; + +static int comparator(const void* e0, const void* e1) { + JNICB jniCb = ctx_opt.cb; + JNIEnv* env = ctx_opt.env; + jint j0 = *((jint*) e0); + jint j1 = *((jint*) e1); + return (*env)->CallStaticIntMethod(env, jniCb->holder, jniCb->mid, j0, j1); +} + +JNIEXPORT void JNICALL Java_org_openjdk_bench_jdk_incubator_foreign_QSort_jni_1qsort_1optimized + (JNIEnv *env, jclass cls, jintArray arr, jlong cb) { + + ctx_opt.cb = jlong_to_ptr(cb); + ctx_opt.env = env; + + jint* ints = (*env)->GetIntArrayElements(env, arr, NULL); + jsize length = (*env)->GetArrayLength(env, arr); + + qsort(ints, length, sizeof(jint), &comparator); + + (*env)->ReleaseIntArrayElements(env, arr, ints, 0); +} + +JavaVM* VM = NULL; + +int java_cmp(const void *a, const void *b) { + int v1 = *((int*)a); + int v2 = *((int*)b); + + JNIEnv* env; + (*VM)->GetEnv(VM, (void**) &env, JNI_VERSION_10); + + jclass qsortClass = (*env)->FindClass(env, "org/openjdk/bench/jdk/incubator/foreign/QSort"); + jmethodID methodId = (*env)->GetStaticMethodID(env, qsortClass, "jni_upcall_compar", "(II)I"); + + return (*env)->CallStaticIntMethod(env, qsortClass, methodId, v1, v2); +} + +JNIEXPORT void JNICALL Java_org_openjdk_bench_jdk_incubator_foreign_QSort_jni_1qsort_1naive + (JNIEnv *env, jclass cls, jintArray arr) { + if (VM == NULL) { + (*env)->GetJavaVM(env, &VM); + } + + jint* carr = (*env)->GetIntArrayElements(env, arr, 0); + jsize length = (*env)->GetArrayLength(env, arr); + qsort(carr, length, sizeof(jint), java_cmp); + (*env)->ReleaseIntArrayElements(env, arr, carr, 0); +} diff --git a/test/micro/org/openjdk/bench/jdk/incubator/foreign/libUpcallsJNI.c b/test/micro/org/openjdk/bench/jdk/incubator/foreign/libUpcallsJNI.c index c44979e3e62f10025b4230f660e70a86bbcf4949..4e8926376213ebe1631a3199c87ca830ded2851e 100644 --- a/test/micro/org/openjdk/bench/jdk/incubator/foreign/libUpcallsJNI.c +++ b/test/micro/org/openjdk/bench/jdk/incubator/foreign/libUpcallsJNI.c @@ -22,46 +22,9 @@ */ #include #include -#include "jlong.h" - -typedef struct { - jclass holder; - jmethodID mid; -} *JNICB; - -#define CHECK_NULL(thing, message) \ - if (thing == NULL) { \ - jclass cls = (*env)->FindClass(env, "java/lang/Exception"); \ - (*env)->ThrowNew(env, cls, message); \ - return 0; \ - } - -JNIEXPORT jlong JNICALL Java_org_openjdk_bench_jdk_incubator_foreign_Upcalls_makeCB - (JNIEnv *env, jclass cls, jstring holderName, jstring methodName, jstring descriptor) { - - const char* holderNameC = (*env)->GetStringUTFChars(env, holderName, NULL); - const char* methodNameC = (*env)->GetStringUTFChars(env, methodName, NULL); - const char* descriptorC = (*env)->GetStringUTFChars(env, descriptor, NULL); - - JNICB cb = malloc(sizeof *cb); - CHECK_NULL(cb, "Can not allocate cb"); - jclass holder = (*env)->FindClass(env, holderNameC); - CHECK_NULL(holder, "Can not find class"); - holder = (jclass) (*env)->NewGlobalRef(env, holder); - cb->holder = holder; - - jmethodID methodID = (*env)->GetStaticMethodID(env, holder, methodNameC, descriptorC); - CHECK_NULL(methodID, "Can not find method"); - //methodID = (jmethodID) (*env)->NewGlobalRef(env, methodID); // DON'T DO THIS! -> Crashes GC - cb->mid = methodID; - - (*env)->ReleaseStringUTFChars(env, holderName, holderNameC); - (*env)->ReleaseStringUTFChars(env, methodName, methodNameC); - (*env)->ReleaseStringUTFChars(env, descriptor, descriptorC); - - return ptr_to_jlong(cb); -} +#include "jlong.h" +#include "JNICB.h" JNIEXPORT void JNICALL Java_org_openjdk_bench_jdk_incubator_foreign_Upcalls_blank (JNIEnv *env, jclass cls, jlong cb) { diff --git a/test/micro/org/openjdk/bench/jdk/incubator/foreign/points/support/PanamaPoint.java b/test/micro/org/openjdk/bench/jdk/incubator/foreign/points/support/PanamaPoint.java index b12d57b20beaddfa5dfcb7284021fddec18e62b0..87c4855771bd4cefb9d92ad1c8f3d9634958bb01 100644 --- a/test/micro/org/openjdk/bench/jdk/incubator/foreign/points/support/PanamaPoint.java +++ b/test/micro/org/openjdk/bench/jdk/incubator/foreign/points/support/PanamaPoint.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -22,46 +22,45 @@ */ package org.openjdk.bench.jdk.incubator.foreign.points.support; +import jdk.incubator.foreign.Addressable; +import jdk.incubator.foreign.CLinker; import jdk.incubator.foreign.FunctionDescriptor; -import jdk.incubator.foreign.SymbolLookup; import jdk.incubator.foreign.MemoryAddress; +import jdk.incubator.foreign.SymbolLookup; import jdk.incubator.foreign.MemoryLayout; import jdk.incubator.foreign.MemorySegment; -import jdk.incubator.foreign.CLinker; import jdk.incubator.foreign.ResourceScope; +import org.openjdk.bench.jdk.incubator.foreign.CLayouts; import java.lang.invoke.MethodHandle; import java.lang.invoke.VarHandle; import static java.lang.invoke.MethodType.methodType; import static jdk.incubator.foreign.MemoryLayout.PathElement.groupElement; -import static jdk.incubator.foreign.CLinker.*; -public class PanamaPoint implements AutoCloseable { +public class PanamaPoint extends CLayouts implements AutoCloseable { public static final MemoryLayout LAYOUT = MemoryLayout.structLayout( C_INT.withName("x"), C_INT.withName("y") ); - private static final VarHandle VH_x = LAYOUT.varHandle(int.class, groupElement("x")); - private static final VarHandle VH_y = LAYOUT.varHandle(int.class, groupElement("y")); + private static final VarHandle VH_x = LAYOUT.varHandle(groupElement("x")); + private static final VarHandle VH_y = LAYOUT.varHandle(groupElement("y")); private static final MethodHandle MH_distance; private static final MethodHandle MH_distance_ptrs; static { - CLinker abi = CLinker.getInstance(); + CLinker abi = CLinker.systemCLinker(); System.loadLibrary("Point"); SymbolLookup lookup = SymbolLookup.loaderLookup(); MH_distance = abi.downcallHandle( lookup.lookup("distance").get(), - methodType(double.class, MemorySegment.class, MemorySegment.class), - FunctionDescriptor.of(C_DOUBLE, LAYOUT, LAYOUT) + FunctionDescriptor.of(C_DOUBLE, LAYOUT, LAYOUT) ); MH_distance_ptrs = abi.downcallHandle( - lookup.lookup("distance_ptrs").get(), - methodType(double.class, MemoryAddress.class, MemoryAddress.class), - FunctionDescriptor.of(C_DOUBLE, C_POINTER, C_POINTER) + lookup.lookup("distance_ptrs").get(), + FunctionDescriptor.of(C_DOUBLE, C_POINTER, C_POINTER) ); } @@ -107,7 +106,7 @@ public class PanamaPoint implements AutoCloseable { public double distanceToPtrs(PanamaPoint other) { try { - return (double) MH_distance_ptrs.invokeExact(segment.address(), other.segment.address()); + return (double) MH_distance_ptrs.invokeExact((Addressable)segment, (Addressable)other.segment); } catch (Throwable throwable) { throw new InternalError(throwable); } diff --git a/test/micro/org/openjdk/bench/jdk/incubator/vector/MaskFromLongBenchmark.java b/test/micro/org/openjdk/bench/jdk/incubator/vector/MaskFromLongBenchmark.java new file mode 100644 index 0000000000000000000000000000000000000000..e929697b57fba1e6b8663a7d0e002c1c906067e7 --- /dev/null +++ b/test/micro/org/openjdk/bench/jdk/incubator/vector/MaskFromLongBenchmark.java @@ -0,0 +1,138 @@ +// +// 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. +// +// +package org.openjdk.bench.jdk.incubator.vector; + +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(jvmArgsPrepend = {"--add-modules=jdk.incubator.vector"}) +public class MaskFromLongBenchmark { + static long val = 0; + + @Setup(Level.Invocation) + public void BmSetup() { + val++; + } + + @Benchmark + public int microMaskFromLong_Byte64() { + VectorMask mask = VectorMask.fromLong(ByteVector.SPECIES_64, val); + return mask.laneIsSet(1) ? 1 : 0; + } + + @Benchmark + public int microMaskFromLong_Byte128() { + VectorMask mask = VectorMask.fromLong(ByteVector.SPECIES_128, val); + return mask.laneIsSet(1) ? 1 : 0; + } + + @Benchmark + public int microMaskFromLong_Byte256() { + VectorMask mask = VectorMask.fromLong(ByteVector.SPECIES_256, val); + return mask.laneIsSet(1) ? 1 : 0; + } + + @Benchmark + public int microMaskFromLong_Byte512() { + VectorMask mask = VectorMask.fromLong(ByteVector.SPECIES_512, val); + return mask.laneIsSet(1) ? 1 : 0; + } + + @Benchmark + public int microMaskFromLong_Short64() { + VectorMask mask = VectorMask.fromLong(ShortVector.SPECIES_64, val); + return mask.laneIsSet(1) ? 1 : 0; + } + + @Benchmark + public int microMaskFromLong_Short128() { + VectorMask mask = VectorMask.fromLong(ShortVector.SPECIES_128, val); + return mask.laneIsSet(1) ? 1 : 0; + } + + @Benchmark + public int microMaskFromLong_Short256() { + VectorMask mask = VectorMask.fromLong(ShortVector.SPECIES_256, val); + return mask.laneIsSet(1) ? 1 : 0; + } + + @Benchmark + public int microMaskFromLong_Short512() { + VectorMask mask = VectorMask.fromLong(ShortVector.SPECIES_512, val); + return mask.laneIsSet(1) ? 1 : 0; + } + + @Benchmark + public int microMaskFromLong_Integer64() { + VectorMask mask = VectorMask.fromLong(IntVector.SPECIES_64, val); + return mask.laneIsSet(1) ? 1 : 0; + } + + @Benchmark + public int microMaskFromLong_Integer128() { + VectorMask mask = VectorMask.fromLong(IntVector.SPECIES_128, val); + return mask.laneIsSet(1) ? 1 : 0; + } + + @Benchmark + public int microMaskFromLong_Integer256() { + VectorMask mask = VectorMask.fromLong(IntVector.SPECIES_256, val); + return mask.laneIsSet(1) ? 1 : 0; + } + + @Benchmark + public int microMaskFromLong_Integer512() { + VectorMask mask = VectorMask.fromLong(IntVector.SPECIES_512, val); + return mask.laneIsSet(1) ? 1 : 0; + } + + @Benchmark + public int microMaskFromLong_Long64() { + VectorMask mask = VectorMask.fromLong(LongVector.SPECIES_64, val); + return mask.laneIsSet(0) ? 1 : 0; + } + + @Benchmark + public int microMaskFromLong_Long128() { + VectorMask mask = VectorMask.fromLong(LongVector.SPECIES_128, val); + return mask.laneIsSet(1) ? 1 : 0; + } + + @Benchmark + public int microMaskFromLong_Long256() { + VectorMask mask = VectorMask.fromLong(LongVector.SPECIES_256, val); + return mask.laneIsSet(1) ? 1 : 0; + } + + @Benchmark + public int microMaskFromLong_Long512() { + VectorMask mask = VectorMask.fromLong(LongVector.SPECIES_512, val); + return mask.laneIsSet(1) ? 1 : 0; + } + +} diff --git a/test/micro/org/openjdk/bench/jdk/incubator/vector/MaskedLogicOpts.java b/test/micro/org/openjdk/bench/jdk/incubator/vector/MaskedLogicOpts.java new file mode 100644 index 0000000000000000000000000000000000000000..97bfc5268086778a3d0ebb51e7c9f572d86b73c1 --- /dev/null +++ b/test/micro/org/openjdk/bench/jdk/incubator/vector/MaskedLogicOpts.java @@ -0,0 +1,331 @@ +/* + * 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. + */ +package org.openjdk.bench.jdk.incubator.vector; + +import org.openjdk.jmh.annotations.*; +import org.openjdk.jmh.infra.*; + +import jdk.incubator.vector.*; +import java.util.concurrent.TimeUnit; +import java.util.Random; + +@BenchmarkMode(Mode.Throughput) +@OutputTimeUnit(TimeUnit.SECONDS) +@State(Scope.Thread) +public class MaskedLogicOpts { + @Param({"256","512","1024"}) + private int ARRAYLEN; + + boolean [] mask_arr = { + false, false, false, true, false, false, false, false, + false, false, false, true, false, false, false, false, + false, false, false, true, false, false, false, false, + true, true, true, true, true, true, true, true, + true, true, true, true, true, true, true, true, + false, false, false, true, false, false, false, false, + false, false, false, true, false, false, false, false, + false, false, false, true, false, false, false, false + }; + + int INVOC_COUNTER = 4096; + + int [] i1 = new int[ARRAYLEN]; + int [] i2 = new int[ARRAYLEN]; + int [] i3 = new int[ARRAYLEN]; + int [] i4 = new int[ARRAYLEN]; + int [] i5 = new int[ARRAYLEN]; + + long [] l1 = new long[ARRAYLEN]; + long [] l2 = new long[ARRAYLEN]; + long [] l3 = new long[ARRAYLEN]; + long [] l4 = new long[ARRAYLEN]; + long [] l5 = new long[ARRAYLEN]; + + Vector iv1; + Vector iv2; + Vector iv3; + Vector iv4; + Vector iv5; + + Vector lv1; + Vector lv2; + Vector lv3; + Vector lv4; + Vector lv5; + + VectorMask imask; + VectorMask lmask; + + VectorSpecies ispecies; + VectorSpecies lspecies; + + int int512_arr_idx; + int int256_arr_idx; + int int128_arr_idx; + int long256_arr_idx; + int long512_arr_idx; + + private Random r = new Random(); + + @Setup(Level.Trial) + public void init() { + int512_arr_idx = 0; + int256_arr_idx = 0; + int128_arr_idx = 0; + long256_arr_idx = 0; + long512_arr_idx = 0; + i1 = new int[ARRAYLEN]; + i2 = new int[ARRAYLEN]; + i3 = new int[ARRAYLEN]; + i4 = new int[ARRAYLEN]; + i5 = new int[ARRAYLEN]; + + l1 = new long[ARRAYLEN]; + l2 = new long[ARRAYLEN]; + l3 = new long[ARRAYLEN]; + l4 = new long[ARRAYLEN]; + l5 = new long[ARRAYLEN]; + + for (int i=0; i SPECIES) { + imask = VectorMask.fromArray(SPECIES, mask_arr, 0); + iv2 = IntVector.fromArray(SPECIES, i2, int512_arr_idx); + iv3 = IntVector.fromArray(SPECIES, i3, int512_arr_idx); + iv4 = IntVector.fromArray(SPECIES, i4, int512_arr_idx); + iv5 = IntVector.fromArray(SPECIES, i5, int512_arr_idx); + for(int i = 0; i < INVOC_COUNTER; i++) { + for(int j = 0 ; j < ARRAYLEN; j+= SPECIES.length()) { + IntVector.fromArray(SPECIES, i1, j) + .lanewise(VectorOperators.AND, iv2, imask) + .lanewise(VectorOperators.OR, iv2, imask) + .lanewise(VectorOperators.AND, iv3, imask) + .lanewise(VectorOperators.OR, iv3, imask) + .lanewise(VectorOperators.AND, iv4, imask) + .lanewise(VectorOperators.OR, iv4, imask) + .lanewise(VectorOperators.AND, iv5, imask) + .lanewise(VectorOperators.XOR, iv5, imask) + .intoArray(i1, j); + } + } + } + + @Benchmark + public void maskedLogicOperationsInt512() { + maskedLogicKernel(IntVector.SPECIES_512); + } + + @Benchmark + public void maskedLogicOperationsInt256() { + maskedLogicKernel(IntVector.SPECIES_256); + } + + @Benchmark + public void maskedLogicOperationsInt128() { + maskedLogicKernel(IntVector.SPECIES_128); + } + + @CompilerControl(CompilerControl.Mode.INLINE) + public void partiallyMaskedLogicOperationsIntKernel(VectorSpecies SPECIES) { + imask = VectorMask.fromArray(SPECIES, mask_arr, 0); + iv2 = IntVector.fromArray(SPECIES, i2, int512_arr_idx); + iv3 = IntVector.fromArray(SPECIES, i3, int512_arr_idx); + iv4 = IntVector.fromArray(SPECIES, i4, int512_arr_idx); + iv5 = IntVector.fromArray(SPECIES, i5, int512_arr_idx); + for(int i = 0; i < INVOC_COUNTER; i++) { + for(int j = 0 ; j < ARRAYLEN; j+= SPECIES.length()) { + IntVector.fromArray(SPECIES, i1, j) + .lanewise(VectorOperators.AND, iv2, imask) + .lanewise(VectorOperators.OR, iv2, imask) + .lanewise(VectorOperators.AND, iv3) + .lanewise(VectorOperators.OR, iv3) + .lanewise(VectorOperators.OR, iv4, imask) + .lanewise(VectorOperators.AND, iv4, imask) + .lanewise(VectorOperators.XOR, iv5, imask) + .intoArray(i1, j); + } + } + } + + @Benchmark + public void partiallyMaskedLogicOperationsInt512() { + partiallyMaskedLogicOperationsIntKernel(IntVector.SPECIES_512); + } + + @Benchmark + public void partiallyMaskedLogicOperationsInt256() { + partiallyMaskedLogicOperationsIntKernel(IntVector.SPECIES_256); + } + + @Benchmark + public void partiallyMaskedLogicOperationsInt128() { + partiallyMaskedLogicOperationsIntKernel(IntVector.SPECIES_128); + } + + @CompilerControl(CompilerControl.Mode.INLINE) + public void bitwiseBlendOperationIntKernel(VectorSpecies SPECIES) { + imask = VectorMask.fromArray(SPECIES, mask_arr, 0); + iv2 = IntVector.fromArray(SPECIES, i2, int512_arr_idx); + iv3 = IntVector.fromArray(SPECIES, i3, int512_arr_idx); + iv4 = IntVector.fromArray(SPECIES, i4, int512_arr_idx); + iv5 = IntVector.fromArray(SPECIES, i5, int512_arr_idx); + for(int i = 0; i < INVOC_COUNTER; i++) { + for(int j = 0 ; j < ARRAYLEN; j+= SPECIES.length()) { + IntVector.fromArray(SPECIES, i1, j) + .lanewise(VectorOperators.BITWISE_BLEND, iv2, iv3, imask) + .lanewise(VectorOperators.BITWISE_BLEND, iv3, iv4, imask) + .lanewise(VectorOperators.BITWISE_BLEND, iv4, iv5, imask) + .intoArray(i1, j); + } + } + } + + @Benchmark + public void bitwiseBlendOperationInt512() { + bitwiseBlendOperationIntKernel(IntVector.SPECIES_512); + } + + @Benchmark + public void bitwiseBlendOperationInt256() { + bitwiseBlendOperationIntKernel(IntVector.SPECIES_256); + } + + @Benchmark + public void bitwiseBlendOperationInt128() { + bitwiseBlendOperationIntKernel(IntVector.SPECIES_128); + } + + @CompilerControl(CompilerControl.Mode.INLINE) + public void maskedLogicOperationsLongKernel(VectorSpecies SPECIES) { + lmask = VectorMask.fromArray(SPECIES, mask_arr, 0); + lv2 = LongVector.fromArray(SPECIES, l2, long256_arr_idx); + lv3 = LongVector.fromArray(SPECIES, l3, long256_arr_idx); + lv4 = LongVector.fromArray(SPECIES, l4, long256_arr_idx); + lv5 = LongVector.fromArray(SPECIES, l5, long256_arr_idx); + for(int i = 0; i < INVOC_COUNTER; i++) { + for(int j = 0 ; j < ARRAYLEN; j+= SPECIES.length()) { + LongVector.fromArray(SPECIES, l1, j) + .lanewise(VectorOperators.AND, lv2, lmask) + .lanewise(VectorOperators.OR, lv3, lmask) + .lanewise(VectorOperators.AND, lv3, lmask) + .lanewise(VectorOperators.OR, lv4, lmask) + .lanewise(VectorOperators.AND, lv4, lmask) + .lanewise(VectorOperators.XOR, lv5, lmask) + .intoArray(l1, j); + } + } + } + + @Benchmark + public void maskedLogicOperationsLong512() { + maskedLogicOperationsLongKernel(LongVector.SPECIES_512); + } + @Benchmark + public void maskedLogicOperationsLong256() { + maskedLogicOperationsLongKernel(LongVector.SPECIES_256); + } + + @CompilerControl(CompilerControl.Mode.INLINE) + public void partiallyMaskedLogicOperationsLongKernel(VectorSpecies SPECIES) { + lmask = VectorMask.fromArray(SPECIES, mask_arr, 0); + lv2 = LongVector.fromArray(SPECIES, l2, long512_arr_idx); + lv3 = LongVector.fromArray(SPECIES, l3, long512_arr_idx); + lv4 = LongVector.fromArray(SPECIES, l4, long512_arr_idx); + lv5 = LongVector.fromArray(SPECIES, l5, long512_arr_idx); + for(int i = 0; i < INVOC_COUNTER; i++) { + for(int j = 0 ; j < ARRAYLEN; j+= SPECIES.length()) { + LongVector.fromArray(SPECIES, l1, j) + .lanewise(VectorOperators.AND, lv2, lmask) + .lanewise(VectorOperators.OR, lv2, lmask) + .lanewise(VectorOperators.AND, lv3) + .lanewise(VectorOperators.OR, lv3) + .lanewise(VectorOperators.AND, lv4) + .lanewise(VectorOperators.OR, lv4, lmask) + .lanewise(VectorOperators.XOR, lv5, lmask) + .intoArray(l1, j); + } + } + } + + @Benchmark + public void partiallyMaskedLogicOperationsLong512() { + partiallyMaskedLogicOperationsLongKernel(LongVector.SPECIES_512); + } + + @Benchmark + public void partiallyMaskedLogicOperationsLong256() { + partiallyMaskedLogicOperationsLongKernel(LongVector.SPECIES_256); + } + + @CompilerControl(CompilerControl.Mode.INLINE) + public void bitwiseBlendOperationLongKernel(VectorSpecies SPECIES) { + lmask = VectorMask.fromArray(SPECIES, mask_arr, 0); + lv2 = LongVector.fromArray(SPECIES, l2, long512_arr_idx); + lv3 = LongVector.fromArray(SPECIES, l3, long512_arr_idx); + lv4 = LongVector.fromArray(SPECIES, l4, long512_arr_idx); + lv5 = LongVector.fromArray(SPECIES, l5, long512_arr_idx); + for(int i = 0; i < INVOC_COUNTER; i++) { + for(int j = 0 ; j < ARRAYLEN; j+= SPECIES.length()) { + LongVector.fromArray(SPECIES, l1, j) + .lanewise(VectorOperators.BITWISE_BLEND, lv2, lv3, lmask) + .lanewise(VectorOperators.BITWISE_BLEND, lv3, lv4, lmask) + .lanewise(VectorOperators.BITWISE_BLEND, lv4, lv5, lmask) + .intoArray(l1, j); + } + } + } + + @Benchmark + public void bitwiseBlendOperationLong512() { + bitwiseBlendOperationLongKernel(LongVector.SPECIES_512); + } + + @Benchmark + public void bitwiseBlendOperationLong256() { + bitwiseBlendOperationLongKernel(LongVector.SPECIES_256); + } +} 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 582a7b4665a0131c8d73e5c07e6f48ccfd86909e..ce0386cb028aec203c6aeedf598a2779ee74833c 100644 --- a/test/micro/org/openjdk/bench/jdk/incubator/vector/TestLoadStoreBytes.java +++ b/test/micro/org/openjdk/bench/jdk/incubator/vector/TestLoadStoreBytes.java @@ -26,8 +26,6 @@ package org.openjdk.bench.jdk.incubator.vector; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.concurrent.TimeUnit; -import jdk.incubator.foreign.CLinker; -import jdk.incubator.foreign.MemoryAccess; import jdk.incubator.foreign.MemoryAddress; import jdk.incubator.foreign.MemorySegment; import jdk.incubator.foreign.ResourceScope; @@ -46,6 +44,8 @@ import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.annotations.State; import org.openjdk.jmh.annotations.Warmup; +import static jdk.incubator.foreign.ValueLayout.JAVA_BYTE; + @BenchmarkMode(Mode.AverageTime) @Warmup(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS) @Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS) @@ -116,8 +116,8 @@ public class TestLoadStoreBytes { dstBufferSegmentImplicit = dstSegmentImplicit.asByteBuffer(); - srcAddress = CLinker.allocateMemory(size); - dstAddress = CLinker.allocateMemory(size); + srcAddress = MemorySegment.allocateNative(size, implicitScope).address(); + dstAddress = MemorySegment.allocateNative(size, implicitScope).address(); a = new byte[size]; b = new byte[size]; @@ -232,16 +232,16 @@ public class TestLoadStoreBytes { @CompilerControl(CompilerControl.Mode.PRINT) public void segmentImplicitScalar() { for (int i = 0; i < SPECIES.loopBound(srcArray.length); i++) { - var v = MemoryAccess.getByteAtOffset(srcSegmentImplicit, i); - MemoryAccess.setByteAtOffset(dstSegmentImplicit, i, v); + var v = srcSegmentImplicit.get(JAVA_BYTE, i); + dstSegmentImplicit.set(JAVA_BYTE, i, v); } } @Benchmark public void bufferSegmentConfined() { try (final var scope = ResourceScope.newConfinedScope()) { - final var srcBufferSegmentConfined = srcAddress.asSegment(size, scope).asByteBuffer(); - final var dstBufferSegmentConfined = dstAddress.asSegment(size, scope).asByteBuffer(); + final var srcBufferSegmentConfined = MemorySegment.ofAddress(srcAddress, size, scope).asByteBuffer(); + final var dstBufferSegmentConfined = MemorySegment.ofAddress(dstAddress, size, scope).asByteBuffer(); for (int i = 0; i < SPECIES.loopBound(srcArray.length); i += SPECIES.length()) { var v = ByteVector.fromByteBuffer(SPECIES, srcBufferSegmentConfined, i, ByteOrder.nativeOrder()); diff --git a/test/micro/org/openjdk/bench/jdk/incubator/vector/TestLoadStoreShort.java b/test/micro/org/openjdk/bench/jdk/incubator/vector/TestLoadStoreShort.java index 6bd9a85143fdf7dd8256c13ed7a3ea4fb3b734f8..881cfad9aa6d54290a8093f835a26cd3644d2da1 100644 --- a/test/micro/org/openjdk/bench/jdk/incubator/vector/TestLoadStoreShort.java +++ b/test/micro/org/openjdk/bench/jdk/incubator/vector/TestLoadStoreShort.java @@ -26,7 +26,7 @@ package org.openjdk.bench.jdk.incubator.vector; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.concurrent.TimeUnit; -import jdk.incubator.foreign.CLinker; + import jdk.incubator.foreign.MemoryAddress; import jdk.incubator.foreign.MemorySegment; import jdk.incubator.foreign.ResourceScope; @@ -112,15 +112,15 @@ public class TestLoadStoreShort { dstBufferNative = ByteBuffer.allocateDirect(size); - implicitScope = ResourceScope.newImplicitScope(); + implicitScope = ResourceScope.newSharedScope(); srcSegmentImplicit = MemorySegment.allocateNative(size, SPECIES.vectorByteSize(), implicitScope); srcBufferSegmentImplicit = srcSegmentImplicit.asByteBuffer(); dstSegmentImplicit = MemorySegment.allocateNative(size, SPECIES.vectorByteSize(), implicitScope); dstBufferSegmentImplicit = dstSegmentImplicit.asByteBuffer(); - srcAddress = CLinker.allocateMemory(size); - dstAddress = CLinker.allocateMemory(size); + srcAddress = MemorySegment.allocateNative(size, implicitScope).address(); + dstAddress = MemorySegment.allocateNative(size, implicitScope).address(); this.longSize = longSize; @@ -130,12 +130,6 @@ public class TestLoadStoreShort { } - @TearDown - public void tearDown() { - CLinker.freeMemory(srcAddress); - CLinker.freeMemory(dstAddress); - } - @Benchmark @CompilerControl(CompilerControl.Mode.PRINT) public void array() { @@ -216,8 +210,8 @@ public class TestLoadStoreShort { @Benchmark public void bufferSegmentConfined() { try (final var scope = ResourceScope.newConfinedScope()) { - final var srcBufferSegmentConfined = srcAddress.asSegment(size, scope).asByteBuffer(); - final var dstBufferSegmentConfined = dstAddress.asSegment(size, scope).asByteBuffer(); + final var srcBufferSegmentConfined = MemorySegment.ofAddress(srcAddress, size, scope).asByteBuffer(); + final var dstBufferSegmentConfined = MemorySegment.ofAddress(dstAddress, size, scope).asByteBuffer(); for (int i = 0; i < SPECIES.loopBound(srcArray.length); i += SPECIES.length()) { var v = ShortVector.fromByteBuffer(SPECIES, srcBufferSegmentConfined, i, ByteOrder.nativeOrder()); diff --git a/test/micro/org/openjdk/bench/vm/compiler/AddIdealNotXPlusC.java b/test/micro/org/openjdk/bench/vm/compiler/AddIdealNotXPlusC.java new file mode 100644 index 0000000000000000000000000000000000000000..057a1dc6104c3c3fa95f23e18edbc0ebc9be61ce --- /dev/null +++ b/test/micro/org/openjdk/bench/vm/compiler/AddIdealNotXPlusC.java @@ -0,0 +1,113 @@ +/* + * 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. + */ + +package org.openjdk.bench.vm.compiler; + +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.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.infra.Blackhole; + +import java.util.concurrent.TimeUnit; + +/** + * Tests transformation that converts "~x + c" into "(c - 1) - x" in + * AddNode::IdealIL and "~(x+c)" into "(-c - 1) - x" in XorINode:Ideal + * and XorLNode::Ideal. + */ +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@State(Scope.Thread) +@Warmup(iterations = 20, time = 1, timeUnit = TimeUnit.SECONDS) +@Measurement(iterations = 20, time = 1, timeUnit = TimeUnit.SECONDS) +@Fork(value = 3) +public class AddIdealNotXPlusC { + + private static final int I_C = 1234567; + + private static final long L_C = 123_456_789_123_456L; + + private int iFld = 4711; + + private long lFld = 4711 * 4711 * 4711; + + private final int SIZE = 10; + + @Benchmark + public void baselineInt(Blackhole bh) { + for (int i = 0; i < SIZE; i++) { + bh.consume(iFld); + } + } + + @Benchmark + public void baselineLong(Blackhole bh) { + for (int i = 0; i < SIZE; i++) { + bh.consume(lFld); + } + } + + // Convert "~x + c" into "(c - 1) - x" for int. + // (c - 1) -x + x is then converted into c - 1. + @Benchmark + public void testInt1(Blackhole bh) { + for (int i = 0; i < SIZE; i++) { + bh.consume(~iFld + I_C + iFld); + } + } + + // Convert "~(x + c)" into "(-c - 1) - x" for int. + // (-c - 1) -x + x is then converted into -c - 1. + @Benchmark + public void testInt2(Blackhole bh) { + for (int i = 0; i < SIZE; i++) { + bh.consume(~(iFld + I_C) + iFld); + } + } + + // Convert "~x + c" into "(c - 1) - x" for long. + // (c - 1) -x + x is then converted into c - 1. + @Benchmark + public void testLong1(Blackhole bh) { + for (int i = 0; i < SIZE; i++) { + bh.consume(~lFld + L_C + lFld); + } + } + + // Convert "~(x + c)" into "(-c - 1) - x" for long. + // (-c - 1) -x + x is then converted into -c - 1. + @Benchmark + public void testLong2(Blackhole bh) { + for (int i = 0; i < SIZE; i++) { + bh.consume(~(lFld + L_C) + lFld); + } + } +} diff --git a/test/micro/org/openjdk/bench/vm/compiler/AutoVectorization2DArray.java b/test/micro/org/openjdk/bench/vm/compiler/AutoVectorization2DArray.java new file mode 100644 index 0000000000000000000000000000000000000000..9155bfbd3de5f3169bc2a6597a583640e70a2bc6 --- /dev/null +++ b/test/micro/org/openjdk/bench/vm/compiler/AutoVectorization2DArray.java @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2022 THL A29 Limited, a Tencent company. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.bench.vm.compiler; + +import org.openjdk.jmh.annotations.*; +import org.openjdk.jmh.infra.*; +import java.util.concurrent.TimeUnit; + +@Warmup(iterations = 3, time = 5, timeUnit = TimeUnit.SECONDS) +@Measurement(iterations = 3, time = 5, timeUnit = TimeUnit.SECONDS) +@BenchmarkMode(Mode.Throughput) +@OutputTimeUnit(TimeUnit.SECONDS) +@State(Scope.Thread) +@Fork(value=1) +public class AutoVectorization2DArray { + @Param({"16", "32", "64"}) + private int LEN; + + private byte[][] a_byte; + private byte[][] b_byte; + private byte[][] c_byte; + + private int[][] a_int; + private int[][] b_int; + private int[][] c_int; + + private double[][] a_double; + private double[][] b_double; + private double[][] c_double; + + @Setup + public void init() { + a_byte = new byte[LEN][LEN]; + b_byte = new byte[LEN][LEN]; + c_byte = new byte[LEN][LEN]; + + a_int = new int[LEN][LEN]; + b_int = new int[LEN][LEN]; + c_int = new int[LEN][LEN]; + + a_double = new double[LEN][LEN]; + b_double = new double[LEN][LEN]; + c_double = new double[LEN][LEN]; + } + + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + private int run_byte(int count, byte[][] a , byte[][] b, byte[][] c) { + for(int i = 0; i < a.length; i++) { + for (int j = 0; j < a[0].length; j++) { + a[i][j] = (byte)(b[i][j] + c[i][j]); + } + } + return a[count][count]; + } + + @Benchmark + public void test_run_byte(Blackhole bh) { + int r = 0; + for(int i = 0 ; i < 100; i++) { + r += run_byte(i % a_byte.length, a_byte, b_byte, c_byte); + } + bh.consume(r); + } + + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + private int run_int(int count, int[][] a, int[][] b, int[][] c) { + for(int i = 0; i < a.length; i++) { + for (int j = 0; j < a[0].length; j++) { + a[i][j] = b[i][j] + c[i][j]; + } + } + return a[count][count]; + } + + @Benchmark + public void test_run_int(Blackhole bh) { + int r = 0; + for(int i = 0 ; i < 100; i++) { + r += run_int(i % a_int.length, a_int, b_int, c_int); + } + bh.consume(r); + } + + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + private double run_double(int count, double[][] a, double[][] b, double[][] c) { + for(int i = 0; i < a.length; i++) { + for (int j = 0; j < a[0].length; j++) { + a[i][j] = b[i][j] + c[i][j]; + } + } + return a[count][count]; + } + + @Benchmark + public void test_run_double(Blackhole bh) { + double r = 0; + for(int i = 0 ; i < 100; i++) { + r += run_double(i % a_double.length, a_double, b_double, c_double); + } + bh.consume(r); + } +} diff --git a/test/micro/org/openjdk/bench/vm/compiler/InterfacePrivateCalls.java b/test/micro/org/openjdk/bench/vm/compiler/InterfacePrivateCalls.java new file mode 100644 index 0000000000000000000000000000000000000000..620b885db366f20049d3a8866dcbb21d27ce3f09 --- /dev/null +++ b/test/micro/org/openjdk/bench/vm/compiler/InterfacePrivateCalls.java @@ -0,0 +1,80 @@ +/* + * 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.vm.compiler; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Level; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; + +import java.util.concurrent.TimeUnit; + +@State(Scope.Benchmark) +public class InterfacePrivateCalls { + interface I { + private int bar() { return 0; } + default int foo() { + return bar(); + } + } + + static class C1 implements I {} + static class C2 implements I {} + static class C3 implements I {} + + private I[] objs; + + @Setup(Level.Trial) + public void setupTrial() { + objs = new I[3]; + objs[0] = new C1(); + objs[1] = new C2(); + objs[2] = new C3(); + } + + @Benchmark + @BenchmarkMode(Mode.AverageTime) + @OutputTimeUnit(TimeUnit.NANOSECONDS) + @Fork(value=1, jvmArgsAppend={"-XX:TieredStopAtLevel=1"}) + public void invokePrivateInterfaceMethodC1() { + for (int i = 0; i < objs.length; ++i) { + objs[i].foo(); + } + } + + @Benchmark + @BenchmarkMode(Mode.AverageTime) + @OutputTimeUnit(TimeUnit.NANOSECONDS) + @Fork(value=1) + public void invokePrivateInterfaceMethodC2() { + for (int i = 0; i < objs.length; ++i) { + objs[i].foo(); + } + } +} diff --git a/test/micro/org/openjdk/bench/vm/compiler/IterativeEA.java b/test/micro/org/openjdk/bench/vm/compiler/IterativeEA.java new file mode 100644 index 0000000000000000000000000000000000000000..26e75f0e05270783bcc677cf7ba7ae2b8b262809 --- /dev/null +++ b/test/micro/org/openjdk/bench/vm/compiler/IterativeEA.java @@ -0,0 +1,105 @@ +/* + * 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. + */ + +package org.openjdk.bench.vm.compiler; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +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 java.util.concurrent.TimeUnit; + +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@State(Scope.Thread) +@Fork(1) + +public class IterativeEA { + + public static int ii = 1; + + static class A { + int i; + + public A(int i) { + this.i = i; + } + } + + static class B { + A a; + + public B(A a) { + this.a = a; + } + } + + static class C { + B b; + + public C(B b) { + this.b = b; + } + } + + @Benchmark + public int test1() { + C c = new C(new B(new A(ii))); + return c.b.a.i; + } + + static class Point { + int x; + int y; + int ax[]; + int ay[]; + } + + @Benchmark + public int test2() { + Point p = new Point(); + p.ax = new int[2]; + p.ay = new int[2]; + int x = 3; + p.ax[0] = x; + p.ay[1] = 3 * x + ii; + return p.ax[0] * p.ay[1]; + } + + public static final Double dbc = Double.valueOf(1.); + + @Benchmark + public double test3() { + Double j1 = Double.valueOf(1.); + Double j2 = Double.valueOf(1.); + for (int i = 0; i< 1000; i++) { + j1 = j1 + 1.; + j2 = j2 + 2.; + } + return j1 + j2; + } +} diff --git a/test/micro/org/openjdk/bench/vm/compiler/LShiftIdeal_XPlusX_LShiftC.java b/test/micro/org/openjdk/bench/vm/compiler/LShiftIdeal_XPlusX_LShiftC.java new file mode 100644 index 0000000000000000000000000000000000000000..d2726706151a634d8ee63bcbc87799b9cc1b1268 --- /dev/null +++ b/test/micro/org/openjdk/bench/vm/compiler/LShiftIdeal_XPlusX_LShiftC.java @@ -0,0 +1,94 @@ +/* + * 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. + */ + +package org.openjdk.bench.vm.compiler; + +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.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.infra.Blackhole; + +import java.util.concurrent.TimeUnit; + +/** + * Tests transformation from "(x + x) << c" to "x << (c + 1)". + *

          + * This benchmark needs to be run with {@code + * JAVA_OPTIONS=-Djmh.blackhole.mode=COMPILER} to force using compiler + * mode blackhole, which is enabled by default and thus not necessary + * since JMH 1.34. + */ +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@State(Scope.Thread) +@Warmup(iterations = 20, time = 1, timeUnit = TimeUnit.SECONDS) +@Measurement(iterations = 20, time = 1, timeUnit = TimeUnit.SECONDS) +@Fork(value = 3) +public class LShiftIdeal_XPlusX_LShiftC { + + private int iFld = 4711; + + private long lFld = 4711 * 4711 * 4711; + + private final int SIZE = 10; + + @Benchmark + public void baselineInt(Blackhole bh) { + for (int i = 0; i < SIZE; i++) { + bh.consume(iFld); + } + } + + @Benchmark + public void baselineLong(Blackhole bh) { + for (int i = 0; i < SIZE; i++) { + bh.consume(lFld); + } + } + + // Convert "(x + x) << 10" into "x << 11" for int. + // (x << 11) >>> 11 is then further converted into zero-extends. + @Benchmark + public void testInt(Blackhole bh) { + for (int i = 0; i < SIZE; i++) { + bh.consume(((iFld + iFld) << 10) >>> 11); + } + } + + // Convert "(x + x) << 40" into "x << 41" for long. + // (x << 41) >>> 41 is then further converted into zero-extends. + @Benchmark + public void testLong(Blackhole bh) { + for (int i = 0; i < SIZE; i++) { + bh.consume(((lFld + lFld) << 40) >>> 41); + } + } +} diff --git a/test/micro/org/openjdk/bench/vm/compiler/LeaInstruction.java b/test/micro/org/openjdk/bench/vm/compiler/LeaInstruction.java new file mode 100644 index 0000000000000000000000000000000000000000..02b10d7ddf71e177a593312e25b7389648f3117f --- /dev/null +++ b/test/micro/org/openjdk/bench/vm/compiler/LeaInstruction.java @@ -0,0 +1,122 @@ +/* + * 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. + */ +package org.openjdk.bench.vm.compiler; + +import org.openjdk.jmh.annotations.*; +import org.openjdk.jmh.infra.Blackhole; + +import java.util.concurrent.TimeUnit; + +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@Fork(value = 1, jvmArgsAppend = {"-XX:LoopUnrollLimit=1"}) +@State(Scope.Thread) +public class LeaInstruction { + static final int ITERATION = 1000; + + int x, y; + + @Benchmark + public void IS_D_int(Blackhole bh) { + int x = this.x; + for (int i = 0; i < ITERATION; i++) { + x = x * 4 + 10; + } + bh.consume(x); + } + + @Benchmark + public void B_I_D_int(Blackhole bh) { + int x = this.x, y = this.y; + for (int i = 0; i < ITERATION; i++) { + x = x + y + 10; + y = x + y + 20; + } + bh.consume(x); + bh.consume(y); + } + + @Benchmark + public void B_IS_int(Blackhole bh) { + int x = this.x, y = this.y; + for (int i = 0; i < ITERATION; i++) { + x = x + y * 4; + y = x + y * 8; + } + bh.consume(x); + bh.consume(y); + } + + @Benchmark + public void B_IS_D_int(Blackhole bh) { + int x = this.x, y = this.y; + for (int i = 0; i < ITERATION; i++) { + x = x + y * 4 + 10; + y = x + y * 8 + 20; + } + bh.consume(x); + bh.consume(y); + } + + @Benchmark + public void IS_D_long(Blackhole bh) { + long x = this.x; + for (int i = 0; i < ITERATION; i++) { + x = x * 4 + 10; + } + bh.consume(x); + } + + @Benchmark + public void B_I_D_long(Blackhole bh) { + long x = this.x, y = this.y; + for (int i = 0; i < ITERATION; i++) { + x = x + y + 10; + y = x + y + 20; + } + bh.consume(x); + bh.consume(y); + } + + @Benchmark + public void B_IS_long(Blackhole bh) { + long x = this.x, y = this.y; + for (int i = 0; i < ITERATION; i++) { + x = x + y * 4; + y = x + y * 8; + } + bh.consume(x); + bh.consume(y); + } + + @Benchmark + public void B_IS_D_long(Blackhole bh) { + long x = this.x, y = this.y; + for (int i = 0; i < ITERATION; i++) { + x = x + y * 4 + 10; + y = x + y * 8 + 20; + } + bh.consume(x); + bh.consume(y); + } +} diff --git a/test/micro/org/openjdk/bench/vm/compiler/MacroLogicOpt.java b/test/micro/org/openjdk/bench/vm/compiler/MacroLogicOpt.java index 58400cadf68280226b16c04c03e4e22772caee82..40c3ba1b2bac1171b977a976dab2d6c9bd9721a5 100644 --- a/test/micro/org/openjdk/bench/vm/compiler/MacroLogicOpt.java +++ b/test/micro/org/openjdk/bench/vm/compiler/MacroLogicOpt.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -32,7 +32,7 @@ import java.util.Random; @OutputTimeUnit(TimeUnit.SECONDS) @State(Scope.Thread) public class MacroLogicOpt { - @Param({"64","128","256","512","1024","2048","4096"}) private int VECLEN; + @Param({"64","128","256","512","1024"}) private int VECLEN; private int [] ai = new int[VECLEN]; private int [] bi = new int[VECLEN]; diff --git a/test/micro/org/openjdk/bench/vm/compiler/PointerBenchmarkFlat.java b/test/micro/org/openjdk/bench/vm/compiler/PointerBenchmarkFlat.java new file mode 100644 index 0000000000000000000000000000000000000000..f83e494b2c96df54c4975a5eab9ec32e75ae3dd3 --- /dev/null +++ b/test/micro/org/openjdk/bench/vm/compiler/PointerBenchmarkFlat.java @@ -0,0 +1,164 @@ +/* + * 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. + */ + +package org.openjdk.bench.vm.compiler; + +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.Warmup; + +import java.util.concurrent.TimeUnit; + +@Fork(value = 3) +@BenchmarkMode(Mode.AverageTime) +@Warmup(iterations = 3, time = 500, timeUnit = TimeUnit.MILLISECONDS) +@Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS) +@OutputTimeUnit(TimeUnit.MILLISECONDS) +@State(Scope.Benchmark) +public class PointerBenchmarkFlat { + + static final int ELEM_SIZE = 1_000_000; + + PointerImpl ptr_ptr; + PointerImplFlat ptr_ptr_flat; + + @Setup + public void setup() { + ptr_ptr = new PointerImpl(new FakeSegment(MemoryAddress.NULL, Long.MAX_VALUE)); + ptr_ptr_flat = new PointerImplFlat(new FakeSegmentFlat(MemoryAddress.NULL, Long.MAX_VALUE)); + } + + static class MemoryAddress { + private long addr; + + public MemoryAddress(long addr) { + this.addr = addr; + } + + long toRawLongValue() { + return addr; + } + + private static final MemoryAddress NULL = new MemoryAddress(0); + + static MemoryAddress ofLong(long val) { + return new MemoryAddress(val); + } + } + + static class PointerImpl { + final FakeSegment segment; + + public PointerImpl(FakeSegment segment) { + this.segment = segment; + } + + MemoryAddress address() { + return segment.address(); + } + + PointerImpl get(long index) { + MemoryAddress address = MemoryAddress.ofLong(index); + FakeSegment holder = new FakeSegment(address, Long.MAX_VALUE); + return new PointerImpl(holder); + } + } + + static class PointerImplFlat { + final FakeSegmentFlat segment; + + public PointerImplFlat(FakeSegmentFlat segment) { + this.segment = segment; + } + + MemoryAddress address() { + return segment.address(); + } + + PointerImplFlat get(long index) { + MemoryAddress address = MemoryAddress.ofLong(index); + FakeSegmentFlat holder = new FakeSegmentFlat(address, Long.MAX_VALUE); + return new PointerImplFlat(holder); + } + } + + static class AbstractFakeSegment { + final long size; + + public AbstractFakeSegment(long size) { + this.size = size; + } + } + + static class FakeSegment extends AbstractFakeSegment { + final MemoryAddress address; + + public FakeSegment(MemoryAddress address, long size) { + super(size); + this.address = address; + } + + MemoryAddress address() { + return address; + } + } + + static class FakeSegmentFlat { + final MemoryAddress address; + final long size; + + public FakeSegmentFlat(MemoryAddress address, long size) { + this.size = size; + this.address = address; + } + + MemoryAddress address() { + return address; + } + } + + @Benchmark + public int test() { + int sum = 0; + for (int i = 0 ; i < ELEM_SIZE ; i++) { + sum += ptr_ptr.get(i).address().toRawLongValue(); + } + return sum; + } + + @Benchmark + public int testFlat() { + int sum = 0; + for (int i = 0 ; i < ELEM_SIZE ; i++) { + sum += ptr_ptr_flat.get(i).address().toRawLongValue(); + } + return sum; + } +} diff --git a/test/micro/org/openjdk/bench/vm/compiler/SharedLoopHeader.java b/test/micro/org/openjdk/bench/vm/compiler/SharedLoopHeader.java new file mode 100644 index 0000000000000000000000000000000000000000..e84ca35ab27658767987aff6506b4e73fd6b5d7f --- /dev/null +++ b/test/micro/org/openjdk/bench/vm/compiler/SharedLoopHeader.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 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. + */ + +package org.openjdk.bench.vm.compiler; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Mode; +import java.util.concurrent.TimeUnit; + +@State(Scope.Thread) +public class SharedLoopHeader { + + private static final int size = 1000; + private static final boolean branch[] = new boolean[size]; + private static final int count[] = new int[size]; + + @Setup + public void setup() { + for (int i = 0; i < branch.length; i++) { + branch[i] = ((i % 10) != 0); + } + } + + @Benchmark + @BenchmarkMode(Mode.AverageTime) + @OutputTimeUnit(TimeUnit.NANOSECONDS) + public void sharedHeader() { + int i = 0; + while (i < branch.length) { + if (branch[i]) { + // common branch + count[i]++; + i++; + continue; + } + i += 2; + } + } + +} diff --git a/test/micro/org/openjdk/bench/vm/compiler/StringConstructorBenchmark.java b/test/micro/org/openjdk/bench/vm/compiler/StringConstructorBenchmark.java new file mode 100644 index 0000000000000000000000000000000000000000..4763c59629c5cd9aa10836fdd90bb830e3a59451 --- /dev/null +++ b/test/micro/org/openjdk/bench/vm/compiler/StringConstructorBenchmark.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 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. + */ + +package org.openjdk.bench.vm.compiler; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.Setup; +import java.util.concurrent.TimeUnit; +import java.nio.charset.StandardCharsets; + +@State(Scope.Thread) +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +public class StringConstructorBenchmark { + private byte[] array; + private String str; + + @Setup + public void setup() { + str = "Quizdeltagerne spiste jordb\u00e6r med fl\u00f8de, mens cirkusklovnen. \u042f";//Latin1 ending with Russian + array = str.getBytes(StandardCharsets.UTF_8); + } + + @Benchmark + public String newString() { + return new String(array, 0, array.length, StandardCharsets.UTF_8); + } + + @Benchmark + public String translateEscapes() { + return str.translateEscapes(); + } +} diff --git a/test/micro/org/openjdk/bench/vm/compiler/SubIdealC0Minus_YPlusC1_.java b/test/micro/org/openjdk/bench/vm/compiler/SubIdealC0Minus_YPlusC1_.java new file mode 100644 index 0000000000000000000000000000000000000000..17728f6bc2589decdacbbe4dead337f4022b40c9 --- /dev/null +++ b/test/micro/org/openjdk/bench/vm/compiler/SubIdealC0Minus_YPlusC1_.java @@ -0,0 +1,110 @@ +/* + * 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. + */ + +package org.openjdk.bench.vm.compiler; + +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.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.infra.Blackhole; + +import java.util.concurrent.TimeUnit; + +/** + * Tests transformation that converts "c0 - (x + c1)" into "(c0 - c1) + * - x" in SubINode::Ideal and SubLNode::Ideal. + */ +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.MILLISECONDS) +@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"}) +public class SubIdealC0Minus_YPlusC1_ { + + private static final int I_C0 = 1234567; + + private static final int I_C1 = 1234567; + + private static final long L_C0 = 123_456_789_123_456L; + + private static final long L_C1 = 123_456_789_123_456L; + + private final int size = 100_000_000; + + private int[] ints_a; + + private long[] longs_a; + + @Setup + public void init() { + ints_a = new int[size]; + longs_a = new long[size]; + for (int i = 0; i < size; i++) { + ints_a[i] = i; + longs_a[i] = i * i; + } + } + + @Benchmark + public void baseline() { + for (int i = 0; i < size; i++) { + sink(ints_a[i]); + sink(longs_a[i]); + } + } + + @Benchmark + public void test() { + for (int i = 0; i < size; i++) { + sink(helper(ints_a[i])); + sink(helper(longs_a[i])); + } + } + + // Convert "c0 - (x + c1)" into "(c0 - c1) - x" for int. + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + private static int helper(int x) { + return I_C0 - (x + I_C1); + } + + // Convert "c0 - (x + c1)" into "(c0 - c1) - x" for long. + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + private static long helper(long x) { + return L_C0 - (x + L_C1); + } + + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + private static void sink(int v) {} + + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + private static void sink(long v) {} +} diff --git a/test/micro/org/openjdk/bench/vm/compiler/TypeVectorOperations.java b/test/micro/org/openjdk/bench/vm/compiler/TypeVectorOperations.java index 0170a1d283299b26fc2d45e5b6090124f4ea7bdd..5e3799c8f3db6af1b72aa815eac400d3d1fef502 100644 --- a/test/micro/org/openjdk/bench/vm/compiler/TypeVectorOperations.java +++ b/test/micro/org/openjdk/bench/vm/compiler/TypeVectorOperations.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -195,6 +195,34 @@ public abstract class TypeVectorOperations { } } + @Benchmark + public void convert_i2f() { + for (int i = 0; i < COUNT; i++) { + resF[i] = (float) ints[i]; + } + } + + @Benchmark + public void convert_f2i() { + for (int i = 0; i < COUNT; i++) { + resI[i] = (int) floats[i]; + } + } + + @Benchmark + public void convert_l2d() { + for (int i = 0; i < COUNT; i++) { + resD[i] = (double) longs[i]; + } + } + + @Benchmark + public void convert_d2l() { + for (int i = 0; i < COUNT; i++) { + resL[i] = (long) doubles[i]; + } + } + @Fork(value = 1, jvmArgsPrepend = { "-XX:+UseSuperWord" }) diff --git a/test/micro/org/openjdk/bench/vm/compiler/UnsignedComparison.java b/test/micro/org/openjdk/bench/vm/compiler/UnsignedComparison.java new file mode 100644 index 0000000000000000000000000000000000000000..a82e1d87c6393436ef411a022a37717993bf4ac4 --- /dev/null +++ b/test/micro/org/openjdk/bench/vm/compiler/UnsignedComparison.java @@ -0,0 +1,138 @@ +/* + * 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. + */ +package org.openjdk.bench.vm.compiler; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Level; +import org.openjdk.jmh.annotations.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.infra.Blackhole; +import java.util.concurrent.TimeUnit; + +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@Fork(2) +@State(Scope.Thread) +public class UnsignedComparison { + private static final int ITERATIONS = 1000; + + private static final int CONST_OPERAND = 4; + private static final int INT_MIN = Integer.MIN_VALUE; + private static final long LONG_MIN = Long.MIN_VALUE; + + int arg0 = 0, arg1 = 4; + + @Setup(Level.Invocation) + public void toggle() { + arg0 = (arg0 + 1) & 7; + } + + @Benchmark + public void intVarDirect(Blackhole bh) { + for (int i = 0; i < ITERATIONS; i++) { + bh.consume(arg0 + INT_MIN < arg1 + INT_MIN); + } + } + + @Benchmark + public void intVarLibLT(Blackhole bh) { + for (int i = 0; i < ITERATIONS; i++) { + bh.consume(Integer.compareUnsigned(arg0, arg1) < 0); + } + } + + @Benchmark + public void intVarLibGT(Blackhole bh) { + for (int i = 0; i < ITERATIONS; i++) { + bh.consume(Integer.compareUnsigned(arg0, arg1) > 0); + } + } + + @Benchmark + public void intConDirect(Blackhole bh) { + for (int i = 0; i < ITERATIONS; i++) { + bh.consume(arg0 + INT_MIN < CONST_OPERAND + INT_MIN); + } + } + + @Benchmark + public void intConLibLT(Blackhole bh) { + for (int i = 0; i < ITERATIONS; i++) { + bh.consume(Integer.compareUnsigned(arg0, CONST_OPERAND) < 0); + } + } + + @Benchmark + public void intConLibGT(Blackhole bh) { + for (int i = 0; i < ITERATIONS; i++) { + bh.consume(Integer.compareUnsigned(arg0, CONST_OPERAND) > 0); + } + } + + @Benchmark + public void longVarDirect(Blackhole bh) { + for (int i = 0; i < ITERATIONS; i++) { + bh.consume(arg0 + LONG_MIN < arg1 + LONG_MIN); + } + } + + @Benchmark + public void longVarLibLT(Blackhole bh) { + for (int i = 0; i < ITERATIONS; i++) { + bh.consume(Long.compareUnsigned(arg0, arg1) < 0); + } + } + + @Benchmark + public void longVarLibGT(Blackhole bh) { + for (int i = 0; i < ITERATIONS; i++) { + bh.consume(Long.compareUnsigned(arg0, arg1) > 0); + } + } + + @Benchmark + public void longConDirect(Blackhole bh) { + for (int i = 0; i < ITERATIONS; i++) { + bh.consume(arg0 + LONG_MIN < CONST_OPERAND + LONG_MIN); + } + } + + @Benchmark + public void longConLibLT(Blackhole bh) { + for (int i = 0; i < ITERATIONS; i++) { + bh.consume(Long.compareUnsigned(arg0, CONST_OPERAND) < 0); + } + } + + @Benchmark + public void longConLibGT(Blackhole bh) { + for (int i = 0; i < ITERATIONS; i++) { + bh.consume(Long.compareUnsigned(arg0, CONST_OPERAND) > 0); + } + } +} diff --git a/test/micro/org/openjdk/bench/vm/compiler/VectorBitCount.java b/test/micro/org/openjdk/bench/vm/compiler/VectorBitCount.java new file mode 100644 index 0000000000000000000000000000000000000000..e16cf422a9df19a668b36567b35da01b22887e37 --- /dev/null +++ b/test/micro/org/openjdk/bench/vm/compiler/VectorBitCount.java @@ -0,0 +1,87 @@ +/* + * 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. + */ +package org.openjdk.bench.vm.compiler; + +import org.openjdk.jmh.annotations.*; +import org.openjdk.jmh.infra.*; +import java.util.concurrent.TimeUnit; +import java.util.random.RandomGenerator; +import java.util.random.RandomGeneratorFactory; + +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@State(Scope.Thread) +public abstract class VectorBitCount { + @Param({"1024"}) + public int SIZE; + + @Param("0") + private int seed; + private RandomGenerator rng = RandomGeneratorFactory.getDefault().create(seed); + private int[] bufferRandInts; + private long[] bufferRandLongs; + private int[] bitCounts; + @Setup + public void init() { + bufferRandInts = new int[SIZE]; + bufferRandLongs = new long[SIZE]; + bitCounts = new int[SIZE]; + + for (int i = 0; i < SIZE; i++) { + bufferRandInts[i] = rng.nextInt(); + bufferRandLongs[i] = rng.nextLong(); + } + } + + @Benchmark + public int[] intBitCount() { + for (int i = 0; i < SIZE; i++) { + bitCounts[i] = Integer.bitCount(bufferRandInts[i]); + } + return bitCounts; + } + + @Benchmark + public int[] longBitCount() { + for (int i = 0; i < SIZE; i++) { + bitCounts[i] = Long.bitCount(bufferRandLongs[i]); + } + return bitCounts; + } + + + @Fork(value = 1, jvmArgsPrepend = { + "-XX:+UseSuperWord" + }) + public static class WithSuperword extends VectorBitCount { + + } + + @Fork(value = 1, jvmArgsPrepend = { + "-XX:-UseSuperWord" + }) + public static class NoSuperword extends VectorBitCount { + } + +} + diff --git a/test/micro/org/openjdk/bench/vm/compiler/VectorShiftRight.java b/test/micro/org/openjdk/bench/vm/compiler/VectorShiftRight.java new file mode 100644 index 0000000000000000000000000000000000000000..068d1bd704dba48363d6e8da111a7223cf2a74b6 --- /dev/null +++ b/test/micro/org/openjdk/bench/vm/compiler/VectorShiftRight.java @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2022, 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. + */ +package org.openjdk.bench.vm.compiler; + +import org.openjdk.jmh.annotations.*; +import org.openjdk.jmh.infra.*; + +import java.util.concurrent.TimeUnit; +import java.util.Random; + +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@State(Scope.Thread) +public class VectorShiftRight { + @Param({"1024"}) + public int SIZE; + + private byte[] bytesA, bytesB; + private short[] shortsA, shortsB; + private char[] charsA, charsB; + private int[] intsA, intsB; + private long[] longsA, longsB; + + @Param("0") + private int seed; + private Random r = new Random(seed); + + @Param("3") + private int shiftCount; + + @Setup + public void init() { + bytesA = new byte[SIZE]; + shortsA = new short[SIZE]; + charsA = new char[SIZE]; + intsA = new int[SIZE]; + longsA = new long[SIZE]; + + bytesB = new byte[SIZE]; + shortsB = new short[SIZE]; + charsB = new char[SIZE]; + intsB = new int[SIZE]; + longsB = new long[SIZE]; + + for (int i = 0; i < SIZE; i++) { + bytesA[i] = (byte) r.nextInt(); + shortsA[i] = (short) r.nextInt(); + charsA[i] = (char) r.nextInt(); + intsA[i] = r.nextInt(); + longsA[i] = r.nextLong(); + } + } + + @Benchmark + public void rShiftByte() { + for (int i = 0; i < SIZE; i++) { + bytesB[i] = (byte) (bytesA[i] >> shiftCount); + } + } + + @Benchmark + public void urShiftByte() { + for (int i = 0; i < SIZE; i++) { + bytesB[i] = (byte) (bytesA[i] >>> shiftCount); + } + } + + @Benchmark + public void rShiftShort() { + for (int i = 0; i < SIZE; i++) { + shortsB[i] = (short) (shortsA[i] >> shiftCount); + } + } + + @Benchmark + public void urShiftChar() { + for (int i = 0; i < SIZE; i++) { + charsB[i] = (char) (charsA[i] >>> shiftCount); + } + } + + @Benchmark + public void rShiftInt() { + for (int i = 0; i < SIZE; i++) { + intsB[i] = intsA[i] >> shiftCount; + } + } + + @Benchmark + public void urShiftInt() { + for (int i = 0; i < SIZE; i++) { + intsB[i] = intsA[i] >>> shiftCount; + } + } + + @Benchmark + public void rShiftLong() { + for (int i = 0; i < SIZE; i++) { + longsB[i] = longsA[i] >> shiftCount; + } + } + + @Benchmark + public void urShiftLong() { + for (int i = 0; i < SIZE; i++) { + longsB[i] = longsA[i] >>> shiftCount; + } + } +} diff --git a/test/micro/org/openjdk/bench/vm/gc/MicroLargePages.java b/test/micro/org/openjdk/bench/vm/gc/MicroLargePages.java new file mode 100644 index 0000000000000000000000000000000000000000..67702cfe607473536bf08316733aed234f2891a1 --- /dev/null +++ b/test/micro/org/openjdk/bench/vm/gc/MicroLargePages.java @@ -0,0 +1,62 @@ +// +// 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. +// + +package org.openjdk.bench.vm.gc; + +import java.util.Arrays; +import java.util.concurrent.TimeUnit; +import org.openjdk.jmh.annotations.*; + +@OutputTimeUnit(TimeUnit.MINUTES) +@State(Scope.Thread) +@Fork(jvmArgsAppend = {"-Xmx256m", "-XX:+UseLargePages", "-XX:LargePageSizeInBytes=1g", "-Xlog:pagesize"}, value = 5) + +public class MicroLargePages { + + @Param({"2097152"}) + public int ARRAYSIZE; + + @Param({"1", "2", "4"}) + public int NUM; + + public long[][] INP; + public long[][] OUT; + + @Setup(Level.Trial) + public void BmSetup() { + INP = new long[NUM][ARRAYSIZE]; + OUT = new long[NUM][ARRAYSIZE]; + for (int i = 0; i < NUM; i++) { + Arrays.fill(INP[i], 10); + } + } + + @Benchmark + public void micro_HOP_DIST_4KB() { + for (int i = 0; i < NUM; i += 1) { + for (int j = 0; j < ARRAYSIZE; j += 512) { + OUT[i][j] = INP[i][j]; + } + } + } +}